/* * Copyright (c) 2024 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "sck_picker_handle.h" #import #include "absl/base/attributes.h" #include "api/sequence_checker.h" #include #include namespace webrtc { class SckPickerProxy; class API_AVAILABLE(macos(14.0)) SckPickerProxy { public: static SckPickerProxy* Get() { static SckPickerProxy* g_picker = new SckPickerProxy(); return g_picker; } bool AtCapacityLocked() const RTC_EXCLUSIVE_LOCKS_REQUIRED(mutex_) { return handle_count_ == kMaximumStreamCount; } SCContentSharingPicker* GetPicker() const { return SCContentSharingPicker.sharedPicker; } ABSL_MUST_USE_RESULT std::optional AcquireSourceId() { MutexLock lock(&mutex_); if (AtCapacityLocked()) { return std::nullopt; } if (handle_count_ == 0) { auto* picker = GetPicker(); picker.maximumStreamCount = [NSNumber numberWithUnsignedInt:kMaximumStreamCount]; picker.active = YES; } handle_count_ += 1; unique_source_id_ += 1; return unique_source_id_; } void RelinquishSourceId(DesktopCapturer::SourceId source) { MutexLock lock(&mutex_); handle_count_ -= 1; if (handle_count_ > 0) { return; } GetPicker().active = NO; } private: // SckPickerProxy is a process-wide singleton. ScreenCapturerSck and // SckPickerHandle are largely single-threaded but may be used on different // threads. For instance some clients use a capturer on one thread for // enumeration and on another for frame capture. Since all those capturers // share the same SckPickerProxy instance, it must be thread-safe. Mutex mutex_; // 100 is an arbitrary number that seems high enough to never get reached, // while still providing a reasonably low upper bound. static constexpr size_t kMaximumStreamCount = 100; size_t handle_count_ RTC_GUARDED_BY(mutex_) = 0; DesktopCapturer::SourceId unique_source_id_ RTC_GUARDED_BY(mutex_) = 0; }; class API_AVAILABLE(macos(14.0)) SckPickerHandle : public SckPickerHandleInterface { public: static std::unique_ptr Create(SckPickerProxy* proxy) { std::optional id = proxy->AcquireSourceId(); if (!id) { return nullptr; } return std::unique_ptr(new SckPickerHandle(proxy, *id)); } ~SckPickerHandle() { RTC_DCHECK_RUN_ON(&thread_checker_); proxy_->RelinquishSourceId(source_); } SCContentSharingPicker* GetPicker() const override { return proxy_->GetPicker(); } DesktopCapturer::SourceId Source() const override { return source_; } private: SckPickerHandle(SckPickerProxy* proxy, DesktopCapturer::SourceId source) : proxy_(proxy), source_(source) { RTC_DCHECK_RUN_ON(&thread_checker_); } webrtc::SequenceChecker thread_checker_; SckPickerProxy* const proxy_; const DesktopCapturer::SourceId source_; }; std::unique_ptr CreateSckPickerHandle() { return SckPickerHandle::Create(SckPickerProxy::Get()); } } // namespace webrtc