diff --git a/webrtc/modules/desktop_capture/desktop_capturer.h b/webrtc/modules/desktop_capture/desktop_capturer.h index 47f78dc3ff..c6c3c7bea0 100644 --- a/webrtc/modules/desktop_capture/desktop_capturer.h +++ b/webrtc/modules/desktop_capture/desktop_capturer.h @@ -33,6 +33,9 @@ class DesktopCapturer { // from chromium. virtual SharedMemory* CreateSharedMemory(size_t size) { return nullptr; } + // Called to notify that the capturer has failed to initialize. + virtual void OnInitializationFailed() {}; + // Called after a frame has been captured. Handler must take ownership of // |frame|. If capture has failed for any reason |frame| is set to NULL // (e.g. the window has been closed). diff --git a/webrtc/modules/desktop_capture/screen_capturer_mac.mm b/webrtc/modules/desktop_capture/screen_capturer_mac.mm index c41dc4d7a3..2c22ee5e46 100644 --- a/webrtc/modules/desktop_capture/screen_capturer_mac.mm +++ b/webrtc/modules/desktop_capture/screen_capturer_mac.mm @@ -22,7 +22,9 @@ #include #include +#include "webrtc/base/checks.h" #include "webrtc/base/macutils.h" +#include "webrtc/base/thread_checker.h" #include "webrtc/modules/desktop_capture/desktop_capture_options.h" #include "webrtc/modules/desktop_capture/desktop_frame.h" #include "webrtc/modules/desktop_capture/desktop_geometry.h" @@ -188,8 +190,6 @@ class ScreenCapturerMac : public ScreenCapturer { rtc::scoped_refptr desktop_config_monitor); virtual ~ScreenCapturerMac(); - bool Init(); - // Overridden from ScreenCapturer: void Start(Callback* callback) override; void Capture(const DesktopRegion& region) override; @@ -198,6 +198,8 @@ class ScreenCapturerMac : public ScreenCapturer { bool SelectScreen(ScreenId id) override; private: + bool Initialize(); + void GlBlitFast(const DesktopFrame& frame, const DesktopRegion& region); void GlBlitSlow(const DesktopFrame& frame); @@ -228,9 +230,11 @@ class ScreenCapturerMac : public ScreenCapturer { DesktopFrame* CreateFrame(); - Callback* callback_; + rtc::ThreadChecker thread_checker_; - CGLContextObj cgl_context_; + Callback* callback_ = nullptr; + + CGLContextObj cgl_context_ = nullptr; ScopedPixelBufferObject pixel_buffer_object_; // Queue of the frames buffers. @@ -241,13 +245,13 @@ class ScreenCapturerMac : public ScreenCapturer { // Currently selected display, or 0 if the full desktop is selected. On OS X // 10.6 and before, this is always 0. - CGDirectDisplayID current_display_; + CGDirectDisplayID current_display_ = 0; // The physical pixel bounds of the current screen. DesktopRect screen_pixel_bounds_; // The dip to physical pixel scale of the current screen. - float dip_to_pixel_scale_; + float dip_to_pixel_scale_ = 1.0f; // A thread-safe list of invalid rectangles, and the size of the most // recently captured screen. @@ -260,20 +264,20 @@ class ScreenCapturerMac : public ScreenCapturer { rtc::scoped_refptr desktop_config_monitor_; // Power management assertion to prevent the screen from sleeping. - IOPMAssertionID power_assertion_id_display_; + IOPMAssertionID power_assertion_id_display_ = kIOPMNullAssertionID; // Power management assertion to indicate that the user is active. - IOPMAssertionID power_assertion_id_user_; + IOPMAssertionID power_assertion_id_user_ = kIOPMNullAssertionID; // Dynamically link to deprecated APIs for Mac OS X 10.6 support. - void* app_services_library_; - CGDisplayBaseAddressFunc cg_display_base_address_; - CGDisplayBytesPerRowFunc cg_display_bytes_per_row_; - CGDisplayBitsPerPixelFunc cg_display_bits_per_pixel_; - void* opengl_library_; - CGLSetFullScreenFunc cgl_set_full_screen_; + void* app_services_library_ = nullptr; + CGDisplayBaseAddressFunc cg_display_base_address_ = nullptr; + CGDisplayBytesPerRowFunc cg_display_bytes_per_row_ = nullptr; + CGDisplayBitsPerPixelFunc cg_display_bits_per_pixel_ = nullptr; + void* opengl_library_ = nullptr; + CGLSetFullScreenFunc cgl_set_full_screen_ = nullptr; - CGWindowID excluded_window_; + CGWindowID excluded_window_ = 0; RTC_DISALLOW_COPY_AND_ASSIGN(ScreenCapturerMac); }; @@ -303,23 +307,15 @@ class InvertedDesktopFrame : public DesktopFrame { ScreenCapturerMac::ScreenCapturerMac( rtc::scoped_refptr desktop_config_monitor) - : callback_(NULL), - cgl_context_(NULL), - current_display_(0), - dip_to_pixel_scale_(1.0f), - desktop_config_monitor_(desktop_config_monitor), - power_assertion_id_display_(kIOPMNullAssertionID), - power_assertion_id_user_(kIOPMNullAssertionID), - app_services_library_(NULL), - cg_display_base_address_(NULL), - cg_display_bytes_per_row_(NULL), - cg_display_bits_per_pixel_(NULL), - opengl_library_(NULL), - cgl_set_full_screen_(NULL), - excluded_window_(0) { + : desktop_config_monitor_(desktop_config_monitor) { + // ScreenCapturer can be used on a thread different from the thread on which + // it's created. + thread_checker_.DetachFromThread(); } ScreenCapturerMac::~ScreenCapturerMac() { + RTC_DCHECK(thread_checker_.CalledOnValidThread()); + if (power_assertion_id_display_ != kIOPMNullAssertionID) { IOPMAssertionRelease(power_assertion_id_display_); power_assertion_id_display_ = kIOPMNullAssertionID; @@ -335,7 +331,7 @@ ScreenCapturerMac::~ScreenCapturerMac() { dlclose(opengl_library_); } -bool ScreenCapturerMac::Init() { +bool ScreenCapturerMac::Initialize() { if (!RegisterRefreshAndMoveHandlers()) { return false; } @@ -359,11 +355,17 @@ void ScreenCapturerMac::ReleaseBuffers() { } void ScreenCapturerMac::Start(Callback* callback) { - assert(!callback_); - assert(callback); + RTC_DCHECK(thread_checker_.CalledOnValidThread()); + RTC_DCHECK(!callback_); + RTC_DCHECK(callback); callback_ = callback; + if (!Initialize()) { + callback_->OnInitializationFailed(); + return; + } + // Create power management assertions to wake the display and prevent it from // going to sleep on user idle. // TODO(jamiewalch): Use IOPMAssertionDeclareUserActivity on 10.7.3 and above @@ -381,6 +383,8 @@ void ScreenCapturerMac::Start(Callback* callback) { } void ScreenCapturerMac::Capture(const DesktopRegion& region_to_capture) { + RTC_DCHECK(thread_checker_.CalledOnValidThread()); + TickTime capture_start_time = TickTime::Now(); queue_.MoveToNextFrame(); @@ -449,11 +453,14 @@ void ScreenCapturerMac::Capture(const DesktopRegion& region_to_capture) { } void ScreenCapturerMac::SetExcludedWindow(WindowId window) { + RTC_DCHECK(thread_checker_.CalledOnValidThread()); excluded_window_ = window; } bool ScreenCapturerMac::GetScreenList(ScreenList* screens) { - assert(screens->size() == 0); + RTC_DCHECK(thread_checker_.CalledOnValidThread()); + RTC_DCHECK(screens->size() == 0); + if (rtc::GetOSVersionName() < rtc::kMacOSLion) { // Single monitor cast is not supported on pre OS X 10.7. Screen screen; @@ -472,6 +479,8 @@ bool ScreenCapturerMac::GetScreenList(ScreenList* screens) { } bool ScreenCapturerMac::SelectScreen(ScreenId id) { + RTC_DCHECK(thread_checker_.CalledOnValidThread()); + if (rtc::GetOSVersionName() < rtc::kMacOSLion) { // Ignore the screen selection on unsupported OS. assert(!current_display_); @@ -980,11 +989,7 @@ ScreenCapturer* ScreenCapturer::Create(const DesktopCaptureOptions& options) { if (!options.configuration_monitor()) return NULL; - std::unique_ptr capturer( - new ScreenCapturerMac(options.configuration_monitor())); - if (!capturer->Init()) - capturer.reset(); - return capturer.release(); + return new ScreenCapturerMac(options.configuration_monitor()); } } // namespace webrtc diff --git a/webrtc/modules/desktop_capture/screen_capturer_x11.cc b/webrtc/modules/desktop_capture/screen_capturer_x11.cc index 65e682b6f8..986fe2155f 100644 --- a/webrtc/modules/desktop_capture/screen_capturer_x11.cc +++ b/webrtc/modules/desktop_capture/screen_capturer_x11.cc @@ -21,6 +21,7 @@ #include #include "webrtc/base/checks.h" +#include "webrtc/base/thread_checker.h" #include "webrtc/modules/desktop_capture/desktop_capture_options.h" #include "webrtc/modules/desktop_capture/desktop_frame.h" #include "webrtc/modules/desktop_capture/differ.h" @@ -37,12 +38,9 @@ namespace { class ScreenCapturerLinux : public ScreenCapturer, public SharedXDisplay::XEventHandler { public: - ScreenCapturerLinux(); + explicit ScreenCapturerLinux(const DesktopCaptureOptions& options); virtual ~ScreenCapturerLinux(); - // TODO(ajwong): Do we really want this to be synchronous? - bool Init(const DesktopCaptureOptions& options); - // DesktopCapturer interface. void Start(Callback* delegate) override; void Capture(const DesktopRegion& region) override; @@ -54,11 +52,13 @@ class ScreenCapturerLinux : public ScreenCapturer, private: Display* display() { return options_.x_display()->display(); } - // SharedXDisplay::XEventHandler interface. - bool HandleXEvent(const XEvent& event) override; + bool Initialize(); void InitXDamage(); + // SharedXDisplay::XEventHandler interface. + bool HandleXEvent(const XEvent& event) override; + // Capture screen pixels to the current buffer in the queue. In the DAMAGE // case, the ScreenCapturerHelper already holds the list of invalid rectangles // from HandleXEvent(). In the non-DAMAGE case, this captures the @@ -78,25 +78,27 @@ class ScreenCapturerLinux : public ScreenCapturer, void DeinitXlib(); + rtc::ThreadChecker thread_checker_; + DesktopCaptureOptions options_; - Callback* callback_; + Callback* callback_ = nullptr; // X11 graphics context. - GC gc_; - Window root_window_; + GC gc_ = nullptr; + Window root_window_ = BadValue; // XFixes. - bool has_xfixes_; - int xfixes_event_base_; - int xfixes_error_base_; + bool has_xfixes_ = false; + int xfixes_event_base_ = -1; + int xfixes_error_base_ = -1; // XDamage information. - bool use_damage_; - Damage damage_handle_; - int damage_event_base_; - int damage_error_base_; - XserverRegion damage_region_; + bool use_damage_ = false; + Damage damage_handle_ = 0; + int damage_event_base_ = -1; + int damage_error_base_ = -1; + XserverRegion damage_region_ = 0; // Access to the X Server's pixel buffer. XServerPixelBuffer x_server_pixel_buffer_; @@ -118,22 +120,16 @@ class ScreenCapturerLinux : public ScreenCapturer, RTC_DISALLOW_COPY_AND_ASSIGN(ScreenCapturerLinux); }; -ScreenCapturerLinux::ScreenCapturerLinux() - : callback_(NULL), - gc_(NULL), - root_window_(BadValue), - has_xfixes_(false), - xfixes_event_base_(-1), - xfixes_error_base_(-1), - use_damage_(false), - damage_handle_(0), - damage_event_base_(-1), - damage_error_base_(-1), - damage_region_(0) { - helper_.SetLogGridSize(4); +ScreenCapturerLinux::ScreenCapturerLinux(const DesktopCaptureOptions& options) + : options_(options) { + // ScreenCapturer can be used on a thread different from the thread on which + // it's created. + thread_checker_.DetachFromThread(); } ScreenCapturerLinux::~ScreenCapturerLinux() { + RTC_DCHECK(thread_checker_.CalledOnValidThread()); + options_.x_display()->RemoveEventHandler(ConfigureNotify, this); if (use_damage_) { options_.x_display()->RemoveEventHandler( @@ -142,8 +138,8 @@ ScreenCapturerLinux::~ScreenCapturerLinux() { DeinitXlib(); } -bool ScreenCapturerLinux::Init(const DesktopCaptureOptions& options) { - options_ = options; +bool ScreenCapturerLinux::Initialize() { + helper_.SetLogGridSize(4); root_window_ = RootWindow(display(), DefaultScreen(display())); if (root_window_ == BadValue) { @@ -198,11 +194,6 @@ void ScreenCapturerLinux::InitXDamage() { return; } - // TODO(lambroslambrou): Disable DAMAGE in situations where it is known - // to fail, such as when Desktop Effects are enabled, with graphics - // drivers (nVidia, ATI) that fail to report DAMAGE notifications - // properly. - // Request notifications every time the screen becomes damaged. damage_handle_ = XDamageCreate(display(), root_window_, XDamageReportNonEmpty); @@ -227,13 +218,20 @@ void ScreenCapturerLinux::InitXDamage() { } void ScreenCapturerLinux::Start(Callback* callback) { + RTC_DCHECK(thread_checker_.CalledOnValidThread()); RTC_DCHECK(!callback_); RTC_DCHECK(callback); callback_ = callback; + + if (!Initialize()) { + callback_->OnInitializationFailed(); + } } void ScreenCapturerLinux::Capture(const DesktopRegion& region) { + RTC_DCHECK(thread_checker_.CalledOnValidThread()); + TickTime capture_start_time = TickTime::Now(); queue_.MoveToNextFrame(); @@ -279,7 +277,9 @@ void ScreenCapturerLinux::Capture(const DesktopRegion& region) { } bool ScreenCapturerLinux::GetScreenList(ScreenList* screens) { + RTC_DCHECK(thread_checker_.CalledOnValidThread()); RTC_DCHECK(screens->size() == 0); + // TODO(jiayl): implement screen enumeration. Screen default_screen; default_screen.id = 0; @@ -288,11 +288,14 @@ bool ScreenCapturerLinux::GetScreenList(ScreenList* screens) { } bool ScreenCapturerLinux::SelectScreen(ScreenId id) { + RTC_DCHECK(thread_checker_.CalledOnValidThread()); // TODO(jiayl): implement screen selection. return true; } bool ScreenCapturerLinux::HandleXEvent(const XEvent& event) { + RTC_DCHECK(thread_checker_.CalledOnValidThread()); + if (use_damage_ && (event.type == damage_event_base_ + XDamageNotify)) { const XDamageNotifyEvent* damage_event = reinterpret_cast(&event); @@ -309,7 +312,7 @@ bool ScreenCapturerLinux::HandleXEvent(const XEvent& event) { DesktopFrame* ScreenCapturerLinux::CaptureScreen() { DesktopFrame* frame = queue_.current_frame()->Share(); - assert(x_server_pixel_buffer_.window_size().equals(frame->size())); + RTC_DCHECK(x_server_pixel_buffer_.window_size().equals(frame->size())); // Pass the screen size to the helper, so it can clip the invalid region if it // expands that region to a grid. @@ -436,10 +439,7 @@ ScreenCapturer* ScreenCapturer::Create(const DesktopCaptureOptions& options) { if (!options.x_display()) return NULL; - std::unique_ptr capturer(new ScreenCapturerLinux()); - if (!capturer->Init(options)) - capturer.reset(); - return capturer.release(); + return new ScreenCapturerLinux(options); } } // namespace webrtc