sck_picker_handle.mm (3512B)
1 /* 2 * Copyright (c) 2024 The WebRTC project authors. All Rights Reserved. 3 * 4 * Use of this source code is governed by a BSD-style license 5 * that can be found in the LICENSE file in the root of the source 6 * tree. An additional intellectual property rights grant can be found 7 * in the file PATENTS. All contributing project authors may 8 * be found in the AUTHORS file in the root of the source tree. 9 */ 10 11 #include "sck_picker_handle.h" 12 13 #import <ScreenCaptureKit/ScreenCaptureKit.h> 14 15 #include "absl/base/attributes.h" 16 #include "api/sequence_checker.h" 17 18 #include <memory> 19 #include <optional> 20 21 namespace webrtc { 22 23 class SckPickerProxy; 24 25 class API_AVAILABLE(macos(14.0)) SckPickerProxy { 26 public: 27 static SckPickerProxy* Get() { 28 static SckPickerProxy* g_picker = new SckPickerProxy(); 29 return g_picker; 30 } 31 32 bool AtCapacityLocked() const RTC_EXCLUSIVE_LOCKS_REQUIRED(mutex_) { 33 return handle_count_ == kMaximumStreamCount; 34 } 35 36 SCContentSharingPicker* GetPicker() const { 37 return SCContentSharingPicker.sharedPicker; 38 } 39 40 ABSL_MUST_USE_RESULT std::optional<DesktopCapturer::SourceId> 41 AcquireSourceId() { 42 MutexLock lock(&mutex_); 43 if (AtCapacityLocked()) { 44 return std::nullopt; 45 } 46 if (handle_count_ == 0) { 47 auto* picker = GetPicker(); 48 picker.maximumStreamCount = 49 [NSNumber numberWithUnsignedInt:kMaximumStreamCount]; 50 picker.active = YES; 51 } 52 handle_count_ += 1; 53 unique_source_id_ += 1; 54 return unique_source_id_; 55 } 56 57 void RelinquishSourceId(DesktopCapturer::SourceId source) { 58 MutexLock lock(&mutex_); 59 handle_count_ -= 1; 60 if (handle_count_ > 0) { 61 return; 62 } 63 GetPicker().active = NO; 64 } 65 66 private: 67 // SckPickerProxy is a process-wide singleton. ScreenCapturerSck and 68 // SckPickerHandle are largely single-threaded but may be used on different 69 // threads. For instance some clients use a capturer on one thread for 70 // enumeration and on another for frame capture. Since all those capturers 71 // share the same SckPickerProxy instance, it must be thread-safe. 72 Mutex mutex_; 73 // 100 is an arbitrary number that seems high enough to never get reached, 74 // while still providing a reasonably low upper bound. 75 static constexpr size_t kMaximumStreamCount = 100; 76 size_t handle_count_ RTC_GUARDED_BY(mutex_) = 0; 77 DesktopCapturer::SourceId unique_source_id_ RTC_GUARDED_BY(mutex_) = 0; 78 }; 79 80 class API_AVAILABLE(macos(14.0)) SckPickerHandle 81 : public SckPickerHandleInterface { 82 public: 83 static std::unique_ptr<SckPickerHandle> Create(SckPickerProxy* proxy) { 84 std::optional<DesktopCapturer::SourceId> id = proxy->AcquireSourceId(); 85 if (!id) { 86 return nullptr; 87 } 88 return std::unique_ptr<SckPickerHandle>(new SckPickerHandle(proxy, *id)); 89 } 90 91 ~SckPickerHandle() { 92 RTC_DCHECK_RUN_ON(&thread_checker_); 93 proxy_->RelinquishSourceId(source_); 94 } 95 96 SCContentSharingPicker* GetPicker() const override { 97 return proxy_->GetPicker(); 98 } 99 100 DesktopCapturer::SourceId Source() const override { return source_; } 101 102 private: 103 SckPickerHandle(SckPickerProxy* proxy, DesktopCapturer::SourceId source) 104 : proxy_(proxy), source_(source) { 105 RTC_DCHECK_RUN_ON(&thread_checker_); 106 } 107 108 webrtc::SequenceChecker thread_checker_; 109 SckPickerProxy* const proxy_; 110 const DesktopCapturer::SourceId source_; 111 }; 112 113 std::unique_ptr<SckPickerHandleInterface> CreateSckPickerHandle() { 114 return SckPickerHandle::Create(SckPickerProxy::Get()); 115 } 116 117 } // namespace webrtc