Source code
Revision control
Copy as Markdown
Other Tools
/*
* 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 <ScreenCaptureKit/ScreenCaptureKit.h>
#include "absl/base/attributes.h"
#include "api/sequence_checker.h"
#include <memory>
#include <optional>
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 {
mutex_.AssertHeld();
return handle_count_ == kMaximumStreamCount;
}
SCContentSharingPicker* GetPicker() const {
return SCContentSharingPicker.sharedPicker;
}
ABSL_MUST_USE_RESULT std::optional<DesktopCapturer::SourceId>
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<SckPickerHandle> Create(SckPickerProxy* proxy) {
std::optional<DesktopCapturer::SourceId> id = proxy->AcquireSourceId();
if (!id) {
return nullptr;
}
return std::unique_ptr<SckPickerHandle>(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<SckPickerHandleInterface> CreateSckPickerHandle() {
return SckPickerHandle::Create(SckPickerProxy::Get());
}
} // namespace webrtc