diff --git a/modules/desktop_capture/mac/screen_capturer_mac.mm b/modules/desktop_capture/mac/screen_capturer_mac.mm index df18777226..6a1e3da6ab 100644 --- a/modules/desktop_capture/mac/screen_capturer_mac.mm +++ b/modules/desktop_capture/mac/screen_capturer_mac.mm @@ -16,6 +16,7 @@ #include "rtc_base/checks.h" #include "rtc_base/constructormagic.h" #include "rtc_base/logging.h" +#include "rtc_base/synchronization/rw_lock_wrapper.h" #include "rtc_base/timeutils.h" #include "sdk/objc/Framework/Classes/Common/scoped_cftyperef.h" @@ -28,18 +29,31 @@ namespace webrtc { // destroy itself once it's done. class DisplayStreamManager { public: - int GetUniqueId() { return ++unique_id_generator_; } - void DestroyStream(int unique_id) { - auto it = display_stream_wrappers_.find(unique_id); - RTC_CHECK(it != display_stream_wrappers_.end()); - RTC_CHECK(!it->second.active); - CFRelease(it->second.stream); - display_stream_wrappers_.erase(it); + DisplayStreamManager() : rw_lock_(RWLockWrapper::CreateRWLock()) {} + RWLockWrapper* GetLock() {return rw_lock_.get();}; - if (ready_for_self_destruction_ && display_stream_wrappers_.empty()) delete this; + int GetUniqueId() { + WriteLockScoped scoped_display_stream_manager_lock(*rw_lock_); + return ++unique_id_generator_; + } + void DestroyStream(int unique_id) { + bool finalize; + { + WriteLockScoped scoped_display_stream_manager_lock(*rw_lock_); + auto it = display_stream_wrappers_.find(unique_id); + RTC_CHECK(it != display_stream_wrappers_.end()); + RTC_CHECK(!it->second.active); + CFRelease(it->second.stream); + display_stream_wrappers_.erase(it); + finalize = ready_for_self_destruction_ && display_stream_wrappers_.empty(); + } + if (finalize) { + delete this; + } } void SaveStream(int unique_id, CGDisplayStreamRef stream) { + WriteLockScoped scoped_display_stream_manager_lock(*rw_lock_); RTC_CHECK(unique_id <= unique_id_generator_); DisplayStreamWrapper wrapper; wrapper.stream = stream; @@ -47,6 +61,7 @@ class DisplayStreamManager { } void UnregisterActiveStreams() { + WriteLockScoped scoped_display_stream_manager_lock(*rw_lock_); for (auto& pair : display_stream_wrappers_) { DisplayStreamWrapper& wrapper = pair.second; if (wrapper.active) { @@ -61,12 +76,23 @@ class DisplayStreamManager { void PrepareForSelfDestruction() { ready_for_self_destruction_ = true; - if (display_stream_wrappers_.empty()) delete this; + bool finalize; + { + WriteLockScoped scoped_display_stream_manager_lock(*rw_lock_); + ready_for_self_destruction_ = true; + finalize = display_stream_wrappers_.empty(); + } + if (finalize) { + delete this; + } } // Once the DisplayStreamManager is ready for destruction, the // ScreenCapturerMac is no longer present. Any updates should be ignored. - bool ShouldIgnoreUpdates() { return ready_for_self_destruction_; } + // Note: not thread-safe! Acquire and release a lock manually. + bool ShouldIgnoreUpdates() { + return ready_for_self_destruction_; + } private: struct DisplayStreamWrapper { @@ -81,6 +107,7 @@ class DisplayStreamManager { std::map display_stream_wrappers_; int unique_id_generator_ = 0; bool ready_for_self_destruction_ = false; + std::unique_ptr rw_lock_; }; namespace { @@ -507,8 +534,6 @@ bool ScreenCapturerMac::RegisterRefreshAndMoveHandlers() { return; } - if (manager->ShouldIgnoreUpdates()) return; - // Only pay attention to frame updates. if (status != kCGDisplayStreamFrameStatusFrameComplete) return; @@ -518,7 +543,12 @@ bool ScreenCapturerMac::RegisterRefreshAndMoveHandlers() { if (count != 0) { // According to CGDisplayStream.h, it's safe to call // CGDisplayStreamStop() from within the callback. - ScreenRefresh(count, rects, display_origin); + manager->GetLock()->AcquireLockShared(); + bool screen_capturer_mac_invalidated = manager->ShouldIgnoreUpdates(); + if (!screen_capturer_mac_invalidated) { + ScreenRefresh(count, rects, display_origin); + } + manager->GetLock()->ReleaseLockShared(); } };