mirror of
https://github.com/electron/electron.git
synced 2026-02-19 03:14:51 -05:00
Compare commits
27 Commits
feat/no-wa
...
sckp-macos
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
589272e065 | ||
|
|
e364a20ba1 | ||
|
|
6b6ef0b9ef | ||
|
|
bb092132be | ||
|
|
0cdf1012bb | ||
|
|
eaa952361c | ||
|
|
8ef66cade3 | ||
|
|
2fb1bfec42 | ||
|
|
65864f6203 | ||
|
|
75eb7aabd6 | ||
|
|
f8aae32c6c | ||
|
|
3e6834099e | ||
|
|
3d5d5f5cb0 | ||
|
|
3268c6ba76 | ||
|
|
50f96692df | ||
|
|
53a7802e95 | ||
|
|
b6c4c727d1 | ||
|
|
4aa9773388 | ||
|
|
7b6b5bf224 | ||
|
|
bd1ed17c02 | ||
|
|
813fc3af58 | ||
|
|
e7675a1a1c | ||
|
|
729ca429b8 | ||
|
|
da56809b62 | ||
|
|
12ca8b30be | ||
|
|
56d4433e46 | ||
|
|
0ee7150832 |
2
.github/workflows/build.yml
vendored
2
.github/workflows/build.yml
vendored
@@ -30,7 +30,7 @@ on:
|
||||
required: false
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- sckp-macos15
|
||||
- '[1-9][0-9]-x-y'
|
||||
pull_request:
|
||||
|
||||
|
||||
@@ -17,7 +17,8 @@ app.whenReady().then(() => {
|
||||
|
||||
session.defaultSession.setDisplayMediaRequestHandler((request, callback) => {
|
||||
desktopCapturer.getSources({ types: ['screen'] }).then((sources) => {
|
||||
// Grant access to the first screen found.
|
||||
// Your app shows some UI, but in this example
|
||||
// grant access to the first screen found.
|
||||
callback({ video: sources[0], audio: 'loopback' })
|
||||
})
|
||||
// If true, use the system picker if available.
|
||||
@@ -42,7 +43,8 @@ startButton.addEventListener('click', () => {
|
||||
video: {
|
||||
width: 320,
|
||||
height: 240,
|
||||
frameRate: 30
|
||||
frameRate: 30,
|
||||
displaySurface: 'monitor'
|
||||
}
|
||||
}).then(stream => {
|
||||
video.srcObject = stream
|
||||
@@ -98,6 +100,16 @@ which can detected by [`systemPreferences.getMediaAccessStatus`][].
|
||||
[`navigator.mediaDevices.getUserMedia`]: https://developer.mozilla.org/en/docs/Web/API/MediaDevices/getUserMedia
|
||||
[`systemPreferences.getMediaAccessStatus`]: system-preferences.md#systempreferencesgetmediaaccessstatusmediatype-windows-macos
|
||||
|
||||
### `desktopCapturer.isDisplayMediaSystemPickerAvailable()` _Experimental_ _macOS_
|
||||
|
||||
Returns `Boolean`, whether or not requesting desktop content via
|
||||
the system picker is supported on this platform.
|
||||
|
||||
Currently this will only return `true` on macOS 14.4 and higher. When
|
||||
true, use the `getNativePickerSource` method to return the system picker's
|
||||
selected media stream. Not doing so may cause a warning dialog to your users
|
||||
on macOS 15 and higher.
|
||||
|
||||
## Caveats
|
||||
|
||||
`navigator.mediaDevices.getUserMedia` does not work on macOS for audio capture due to a fundamental limitation whereby apps that want to access the system's audio require a [signed kernel extension](https://developer.apple.com/library/archive/documentation/Security/Conceptual/System_Integrity_Protection_Guide/KernelExtensions/KernelExtensions.html). Chromium, and by extension Electron, does not provide this.
|
||||
|
||||
@@ -971,6 +971,7 @@ session.fromPartition('some-partition').setPermissionCheckHandler((webContents,
|
||||
* `videoRequested` Boolean - true if the web content requested a video stream.
|
||||
* `audioRequested` Boolean - true if the web content requested an audio stream.
|
||||
* `userGesture` Boolean - Whether a user gesture was active when this request was triggered.
|
||||
* `preferredDisplaySurface` String - The preferred display used for sharing screen in this request.
|
||||
* `callback` Function
|
||||
* `streams` Object
|
||||
* `video` Object | [WebFrameMain](web-frame-main.md) (optional)
|
||||
|
||||
@@ -594,6 +594,8 @@ filenames = {
|
||||
"shell/common/gin_converters/callback_converter.h",
|
||||
"shell/common/gin_converters/content_converter.cc",
|
||||
"shell/common/gin_converters/content_converter.h",
|
||||
"shell/common/gin_converters/display_surface_converter.cc",
|
||||
"shell/common/gin_converters/display_surface_converter.h",
|
||||
"shell/common/gin_converters/file_dialog_converter.cc",
|
||||
"shell/common/gin_converters/file_dialog_converter.h",
|
||||
"shell/common/gin_converters/file_path_converter.h",
|
||||
|
||||
@@ -16,13 +16,13 @@ function isValid (options: Electron.SourcesOptions) {
|
||||
|
||||
export { isDisplayMediaSystemPickerAvailable };
|
||||
|
||||
export async function getSources (args: Electron.SourcesOptions) {
|
||||
export async function getSources (args: Electron.SourcesOptions, useSystemPicker: boolean = false) {
|
||||
if (!isValid(args)) throw new Error('Invalid options');
|
||||
|
||||
const resizableValues = new Map();
|
||||
if (process.platform === 'darwin') {
|
||||
// Fix for bug in ScreenCaptureKit that modifies a window's styleMask the first time
|
||||
// it captures a non-resizable window. We record each non-resizable window's styleMask,
|
||||
// it captures a non-resizable window. We record each non-resizable window's styleMask
|
||||
// and we restore modified styleMasks later, after the screen capture.
|
||||
for (const win of BrowserWindow.getAllWindows()) {
|
||||
resizableValues.set([win.id], win.resizable);
|
||||
@@ -32,14 +32,15 @@ export async function getSources (args: Electron.SourcesOptions) {
|
||||
const captureWindow = args.types.includes('window');
|
||||
const captureScreen = args.types.includes('screen');
|
||||
|
||||
const { thumbnailSize = { width: 150, height: 150 } } = args;
|
||||
const { thumbnailSize = { width: 0, height: 0 } } = args;
|
||||
const { fetchWindowIcons = false } = args;
|
||||
|
||||
const options = {
|
||||
captureWindow,
|
||||
captureScreen,
|
||||
thumbnailSize,
|
||||
fetchWindowIcons
|
||||
fetchWindowIcons,
|
||||
useSystemPicker
|
||||
};
|
||||
|
||||
for (const running of currentlyRunning) {
|
||||
@@ -81,7 +82,7 @@ export async function getSources (args: Electron.SourcesOptions) {
|
||||
resolve(sources);
|
||||
};
|
||||
|
||||
capturer.startHandling(captureWindow, captureScreen, thumbnailSize, fetchWindowIcons);
|
||||
capturer.startHandling(captureWindow, captureScreen, thumbnailSize, fetchWindowIcons, useSystemPicker);
|
||||
});
|
||||
|
||||
currentlyRunning.push({
|
||||
|
||||
@@ -2,25 +2,61 @@ import { fetchWithSession } from '@electron/internal/browser/api/net-fetch';
|
||||
import { addIpcDispatchListeners } from '@electron/internal/browser/ipc-dispatch';
|
||||
import * as deprecate from '@electron/internal/common/deprecate';
|
||||
|
||||
import { net } from 'electron/main';
|
||||
import { desktopCapturer, net } from 'electron/main';
|
||||
|
||||
const { fromPartition, fromPath, Session } = process._linkedBinding('electron_browser_session');
|
||||
const { isDisplayMediaSystemPickerAvailable } = process._linkedBinding('electron_browser_desktop_capturer');
|
||||
|
||||
// Fake video window that activates the native system picker
|
||||
// This is used to get around the need for a screen/window
|
||||
// id in Chrome's desktopCapturer.
|
||||
let fakeVideoWindowId = -1;
|
||||
// See content/public/browser/desktop_media_id.h
|
||||
const kMacOsNativePickerId = -4;
|
||||
const systemPickerVideoSource = Object.create(null);
|
||||
Object.defineProperty(systemPickerVideoSource, 'id', {
|
||||
get () {
|
||||
return `window:${kMacOsNativePickerId}:${fakeVideoWindowId--}`;
|
||||
async function getNativePickerSource (preferredDisplaySurface: string) {
|
||||
console.log('SESSION.TS getNativePickerSource');
|
||||
// Fake video window that activates the native system picker
|
||||
// This is used to get around the need for a screen/window
|
||||
// id in Chrome's desktopCapturer.
|
||||
// let fakeVideoWindowId = -1;
|
||||
// const kMacOsNativePickerId = -4;
|
||||
|
||||
if (process.platform !== 'darwin') {
|
||||
throw new Error('Native system picker option is currently only supported on MacOS');
|
||||
}
|
||||
});
|
||||
systemPickerVideoSource.name = '';
|
||||
Object.freeze(systemPickerVideoSource);
|
||||
|
||||
if (!isDisplayMediaSystemPickerAvailable) {
|
||||
throw new Error(`Native system picker unavailable.
|
||||
Note: This is an experimental API; please check the API documentation for updated restrictions`);
|
||||
}
|
||||
|
||||
let types: Electron.SourcesOptions['types'];
|
||||
switch (preferredDisplaySurface) {
|
||||
case 'no_preference':
|
||||
types = ['screen', 'window'];
|
||||
break;
|
||||
case 'monitor':
|
||||
types = ['screen'];
|
||||
break;
|
||||
case 'window':
|
||||
types = ['window'];
|
||||
break;
|
||||
default:
|
||||
types = ['screen', 'window'];
|
||||
}
|
||||
|
||||
// Pass in the needed options for a more native experience
|
||||
// screen & windows by default, no thumbnails, since the native picker doesn't return them
|
||||
const options: Electron.SourcesOptions = {
|
||||
types,
|
||||
thumbnailSize: { width: 0, height: 0 },
|
||||
fetchWindowIcons: false
|
||||
};
|
||||
|
||||
const mediaStreams = await desktopCapturer.getSources(options);
|
||||
|
||||
if (mediaStreams.length === 0) {
|
||||
throw new Error('No media streams found');
|
||||
}
|
||||
|
||||
// mediaStreams[0].id = `none:${kMacOsNativePickerId}:${fakeVideoWindowId--}`;
|
||||
console.log('SESSION.TS mediaStreams', mediaStreams);
|
||||
return mediaStreams[0];
|
||||
}
|
||||
|
||||
Session.prototype._init = function () {
|
||||
addIpcDispatchListeners(this);
|
||||
@@ -48,12 +84,12 @@ Session.prototype.fetch = function (input: RequestInfo, init?: RequestInit) {
|
||||
Session.prototype.setDisplayMediaRequestHandler = function (handler, opts) {
|
||||
if (!handler) return this._setDisplayMediaRequestHandler(handler, opts);
|
||||
|
||||
this._setDisplayMediaRequestHandler(async (req, callback) => {
|
||||
this._setDisplayMediaRequestHandler(async (request, callback) => {
|
||||
if (opts && opts.useSystemPicker && isDisplayMediaSystemPickerAvailable()) {
|
||||
return callback({ video: systemPickerVideoSource });
|
||||
return callback({ video: await getNativePickerSource(request.preferredDisplaySurface) });
|
||||
}
|
||||
|
||||
return handler(req, callback);
|
||||
// return handler(request, callback);
|
||||
}, opts);
|
||||
};
|
||||
|
||||
|
||||
@@ -128,7 +128,6 @@ chore_remove_reference_to_chrome_browser_themes.patch
|
||||
feat_enable_customizing_symbol_color_in_framecaptionbutton.patch
|
||||
build_allow_electron_mojom_interfaces_to_depend_on_blink.patch
|
||||
osr_shared_texture_remove_keyed_mutex_on_win_dxgi.patch
|
||||
feat_allow_usage_of_sccontentsharingpicker_on_supported_platforms.patch
|
||||
chore_partial_revert_of.patch
|
||||
fix_software_compositing_infinite_loop.patch
|
||||
fix_add_method_which_disables_headless_mode_on_native_widget.patch
|
||||
@@ -143,3 +142,5 @@ fix_win32_synchronous_spellcheck.patch
|
||||
fix_enable_wrap_iter_in_string_view_and_array.patch
|
||||
fix_linter_error.patch
|
||||
fix_take_snapped_status_into_account_when_showing_a_window.patch
|
||||
feat_make_macos_sccontentsharingpicker_work_in_electron_and_return_screen_window_or_both.patch
|
||||
fix_debug_desktop_capturer_picture.patch
|
||||
|
||||
@@ -1,383 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Samuel Attard <marshallofsound@electronjs.org>
|
||||
Date: Thu, 8 Aug 2024 08:39:10 -0700
|
||||
Subject: feat: allow usage of SCContentSharingPicker on supported platforms
|
||||
|
||||
This is implemented as a magic "window id" that instead of pulling an SCStream manually
|
||||
instead farms out to the screen picker.
|
||||
|
||||
diff --git a/content/browser/media/capture/desktop_capture_device_mac.cc b/content/browser/media/capture/desktop_capture_device_mac.cc
|
||||
index afb657b7c9e1ede1273532b16428d37cc5d75c59..16707cf516cd34682c84ea2ccebddaa0f84e01f8 100644
|
||||
--- a/content/browser/media/capture/desktop_capture_device_mac.cc
|
||||
+++ b/content/browser/media/capture/desktop_capture_device_mac.cc
|
||||
@@ -29,7 +29,7 @@ class DesktopCaptureDeviceMac : public IOSurfaceCaptureDeviceBase {
|
||||
~DesktopCaptureDeviceMac() override = default;
|
||||
|
||||
// IOSurfaceCaptureDeviceBase:
|
||||
- void OnStart() override {
|
||||
+ void OnStart(std::optional<bool> use_native_picker) override {
|
||||
requested_format_ = capture_params().requested_format;
|
||||
requested_format_.pixel_format = media::PIXEL_FORMAT_NV12;
|
||||
DCHECK_GT(requested_format_.frame_size.GetArea(), 0);
|
||||
diff --git a/content/browser/media/capture/io_surface_capture_device_base_mac.cc b/content/browser/media/capture/io_surface_capture_device_base_mac.cc
|
||||
index 4ec4c895423151d2c907d97de1461cbde8c8a639..0e59797833b81c07299b8c342f591e192183c6f1 100644
|
||||
--- a/content/browser/media/capture/io_surface_capture_device_base_mac.cc
|
||||
+++ b/content/browser/media/capture/io_surface_capture_device_base_mac.cc
|
||||
@@ -20,7 +20,7 @@ void IOSurfaceCaptureDeviceBase::AllocateAndStart(
|
||||
client_ = std::move(client);
|
||||
capture_params_ = params;
|
||||
|
||||
- OnStart();
|
||||
+ OnStart(params.use_native_picker);
|
||||
}
|
||||
|
||||
void IOSurfaceCaptureDeviceBase::StopAndDeAllocate() {
|
||||
diff --git a/content/browser/media/capture/io_surface_capture_device_base_mac.h b/content/browser/media/capture/io_surface_capture_device_base_mac.h
|
||||
index e2771b7b281274cdcb601a5bc78a948ad592087b..48d116823a28213e50775f378e6ce04ce3af5072 100644
|
||||
--- a/content/browser/media/capture/io_surface_capture_device_base_mac.h
|
||||
+++ b/content/browser/media/capture/io_surface_capture_device_base_mac.h
|
||||
@@ -25,7 +25,7 @@ class CONTENT_EXPORT IOSurfaceCaptureDeviceBase
|
||||
~IOSurfaceCaptureDeviceBase() override;
|
||||
|
||||
// OnStart is called by AllocateAndStart.
|
||||
- virtual void OnStart() = 0;
|
||||
+ virtual void OnStart(std::optional<bool> use_native_picker) = 0;
|
||||
|
||||
// OnStop is called by StopAndDeAllocate.
|
||||
virtual void OnStop() = 0;
|
||||
diff --git a/content/browser/media/capture/screen_capture_kit_device_mac.mm b/content/browser/media/capture/screen_capture_kit_device_mac.mm
|
||||
index 7e17594c30ac3cf8cb484b53563b03fc75bd2e0b..0e4a68f2fd8179640f877cb258b4049610fd49da 100644
|
||||
--- a/content/browser/media/capture/screen_capture_kit_device_mac.mm
|
||||
+++ b/content/browser/media/capture/screen_capture_kit_device_mac.mm
|
||||
@@ -27,6 +27,61 @@
|
||||
std::optional<float>,
|
||||
bool)>;
|
||||
using ErrorCallback = base::RepeatingClosure;
|
||||
+using CancelCallback = base::RepeatingClosure;
|
||||
+
|
||||
+API_AVAILABLE(macos(15.0))
|
||||
+@interface ScreenCaptureKitPickerHelper
|
||||
+ : NSObject <SCContentSharingPickerObserver>
|
||||
+
|
||||
+- (void)contentSharingPicker:(SCContentSharingPicker *)picker
|
||||
+ didCancelForStream:(SCStream *)stream;
|
||||
+
|
||||
+- (void)contentSharingPicker:(SCContentSharingPicker *)picker
|
||||
+ didUpdateWithFilter:(SCContentFilter *)filter
|
||||
+ forStream:(SCStream *)stream;
|
||||
+
|
||||
+- (void)contentSharingPickerStartDidFailWithError:(NSError *)error;
|
||||
+
|
||||
+@end
|
||||
+
|
||||
+@implementation ScreenCaptureKitPickerHelper {
|
||||
+ base::RepeatingCallback<void(SCContentFilter *)> _pickerCallback;
|
||||
+ ErrorCallback _errorCallback;
|
||||
+ CancelCallback _cancelCallback;
|
||||
+}
|
||||
+
|
||||
+- (void)contentSharingPicker:(SCContentSharingPicker *)picker
|
||||
+ didCancelForStream:(SCStream *)stream {
|
||||
+ // TODO: This doesn't appear to be called on Apple's side;
|
||||
+ // implement this logic
|
||||
+ _cancelCallback.Run();
|
||||
+}
|
||||
+
|
||||
+- (void)contentSharingPicker:(SCContentSharingPicker *)picker
|
||||
+ didUpdateWithFilter:(SCContentFilter *)filter
|
||||
+ forStream:(SCStream *)stream {
|
||||
+ if (stream == nil) {
|
||||
+ _pickerCallback.Run(filter);
|
||||
+ [picker removeObserver:self];
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+- (void)contentSharingPickerStartDidFailWithError:(NSError *)error {
|
||||
+ _errorCallback.Run();
|
||||
+}
|
||||
+
|
||||
+- (instancetype)initWithStreamPickCallback:(base::RepeatingCallback<void(SCContentFilter *)>)pickerCallback
|
||||
+ cancelCallback:(CancelCallback)cancelCallback
|
||||
+ errorCallback:(ErrorCallback)errorCallback {
|
||||
+ if (self = [super init]) {
|
||||
+ _pickerCallback = pickerCallback;
|
||||
+ _cancelCallback = cancelCallback;
|
||||
+ _errorCallback = errorCallback;
|
||||
+ }
|
||||
+ return self;
|
||||
+}
|
||||
+
|
||||
+@end
|
||||
|
||||
namespace {
|
||||
API_AVAILABLE(macos(12.3))
|
||||
@@ -123,18 +178,22 @@ @interface ScreenCaptureKitDeviceHelper
|
||||
: NSObject <SCStreamDelegate, SCStreamOutput>
|
||||
|
||||
- (instancetype)initWithSampleCallback:(SampleCallback)sampleCallback
|
||||
+ cancelCallback:(CancelCallback)cancelCallback
|
||||
errorCallback:(ErrorCallback)errorCallback;
|
||||
@end
|
||||
|
||||
@implementation ScreenCaptureKitDeviceHelper {
|
||||
SampleCallback _sampleCallback;
|
||||
+ CancelCallback _cancelCallback;
|
||||
ErrorCallback _errorCallback;
|
||||
}
|
||||
|
||||
- (instancetype)initWithSampleCallback:(SampleCallback)sampleCallback
|
||||
+ cancelCallback:(CancelCallback)cancelCallback
|
||||
errorCallback:(ErrorCallback)errorCallback {
|
||||
if (self = [super init]) {
|
||||
_sampleCallback = sampleCallback;
|
||||
+ _cancelCallback = cancelCallback;
|
||||
_errorCallback = errorCallback;
|
||||
}
|
||||
return self;
|
||||
@@ -211,29 +270,53 @@ + (SCStreamConfiguration*)streamConfigurationWithFrameSize:(gfx::Size)frameSize
|
||||
|
||||
class API_AVAILABLE(macos(12.3)) ScreenCaptureKitDeviceMac
|
||||
: public IOSurfaceCaptureDeviceBase,
|
||||
- public ScreenCaptureKitResetStreamInterface {
|
||||
+ public ScreenCaptureKitResetStreamInterface
|
||||
+ {
|
||||
public:
|
||||
explicit ScreenCaptureKitDeviceMac(const DesktopMediaID& source,
|
||||
- SCContentFilter* filter)
|
||||
+ [[maybe_unused]] SCContentFilter* filter)
|
||||
: source_(source),
|
||||
- filter_(filter),
|
||||
device_task_runner_(base::SingleThreadTaskRunner::GetCurrentDefault()) {
|
||||
SampleCallback sample_callback = base::BindPostTask(
|
||||
device_task_runner_,
|
||||
base::BindRepeating(&ScreenCaptureKitDeviceMac::OnStreamSample,
|
||||
weak_factory_.GetWeakPtr()));
|
||||
+ CancelCallback cancel_callback = base::BindPostTask(
|
||||
+ device_task_runner_,
|
||||
+ base::BindRepeating(&ScreenCaptureKitDeviceMac::OnStreamError,
|
||||
+ weak_factory_.GetWeakPtr()));
|
||||
ErrorCallback error_callback = base::BindPostTask(
|
||||
device_task_runner_,
|
||||
base::BindRepeating(&ScreenCaptureKitDeviceMac::OnStreamError,
|
||||
weak_factory_.GetWeakPtr()));
|
||||
helper_ = [[ScreenCaptureKitDeviceHelper alloc]
|
||||
initWithSampleCallback:sample_callback
|
||||
+ cancelCallback:cancel_callback
|
||||
errorCallback:error_callback];
|
||||
+
|
||||
+ if (@available(macOS 15.0, *)) {
|
||||
+ auto picker_callback = base::BindPostTask(
|
||||
+ device_task_runner_,
|
||||
+ base::BindRepeating(&ScreenCaptureKitDeviceMac::OnContentFilterReady, weak_factory_.GetWeakPtr())
|
||||
+ );
|
||||
+ picker_helper_ = [[ScreenCaptureKitPickerHelper alloc] initWithStreamPickCallback:picker_callback cancelCallback:cancel_callback errorCallback:error_callback];
|
||||
+ [[SCContentSharingPicker sharedPicker] addObserver:picker_helper_];
|
||||
+ }
|
||||
}
|
||||
ScreenCaptureKitDeviceMac(const ScreenCaptureKitDeviceMac&) = delete;
|
||||
ScreenCaptureKitDeviceMac& operator=(const ScreenCaptureKitDeviceMac&) =
|
||||
delete;
|
||||
- ~ScreenCaptureKitDeviceMac() override = default;
|
||||
+ ~ScreenCaptureKitDeviceMac() override {
|
||||
+ if (@available(macOS 15.0, *)) {
|
||||
+ auto* picker = [SCContentSharingPicker sharedPicker];
|
||||
+ ScreenCaptureKitDeviceMac::active_streams_--;
|
||||
+ picker.maximumStreamCount = @(ScreenCaptureKitDeviceMac::active_streams_);
|
||||
+ if (ScreenCaptureKitDeviceMac::active_streams_ == 0 && picker.active) {
|
||||
+ picker.active = false;
|
||||
+ [[SCContentSharingPicker sharedPicker] removeObserver:picker_helper_];
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
|
||||
void OnShareableContentCreated(SCShareableContent* content) {
|
||||
DCHECK(device_task_runner_->RunsTasksInCurrentSequence());
|
||||
@@ -301,7 +384,7 @@ void CreateStream(SCContentFilter* filter) {
|
||||
return;
|
||||
}
|
||||
|
||||
- if (@available(macOS 14.0, *)) {
|
||||
+ if (@available(macOS 15.0, *)) {
|
||||
// Update the content size. This step is neccessary when used together
|
||||
// with SCContentSharingPicker. If the Chrome picker is used, it will
|
||||
// change to retina resolution if applicable.
|
||||
@@ -310,6 +393,9 @@ void CreateStream(SCContentFilter* filter) {
|
||||
filter.contentRect.size.height * filter.pointPixelScale);
|
||||
}
|
||||
|
||||
+ OnContentFilterReady(filter);
|
||||
+ }
|
||||
+ void OnContentFilterReady(SCContentFilter* filter) {
|
||||
gfx::RectF dest_rect_in_frame;
|
||||
actual_capture_format_ = capture_params().requested_format;
|
||||
actual_capture_format_.pixel_format = media::PIXEL_FORMAT_NV12;
|
||||
@@ -323,6 +409,7 @@ void CreateStream(SCContentFilter* filter) {
|
||||
stream_ = [[SCStream alloc] initWithFilter:filter
|
||||
configuration:config
|
||||
delegate:helper_];
|
||||
+
|
||||
{
|
||||
NSError* error = nil;
|
||||
bool add_stream_output_result =
|
||||
@@ -480,7 +567,7 @@ void OnStreamError() {
|
||||
if (fullscreen_module_) {
|
||||
fullscreen_module_->Reset();
|
||||
}
|
||||
- OnStart();
|
||||
+ OnStart(std::nullopt);
|
||||
} else {
|
||||
client()->OnError(media::VideoCaptureError::kScreenCaptureKitStreamError,
|
||||
FROM_HERE, "Stream delegate called didStopWithError");
|
||||
@@ -503,23 +590,41 @@ void OnUpdateConfigurationError() {
|
||||
}
|
||||
|
||||
// IOSurfaceCaptureDeviceBase:
|
||||
- void OnStart() override {
|
||||
+ void OnStart(std::optional<bool> use_native_picker) override {
|
||||
DCHECK(device_task_runner_->RunsTasksInCurrentSequence());
|
||||
- if (filter_) {
|
||||
- // SCContentSharingPicker is used where filter_ is set on creation.
|
||||
- CreateStream(filter_);
|
||||
- } else {
|
||||
- // Chrome picker is used.
|
||||
- auto content_callback = base::BindPostTask(
|
||||
- device_task_runner_,
|
||||
- base::BindRepeating(
|
||||
- &ScreenCaptureKitDeviceMac::OnShareableContentCreated,
|
||||
- weak_factory_.GetWeakPtr()));
|
||||
- auto handler = ^(SCShareableContent* content, NSError* error) {
|
||||
- content_callback.Run(content);
|
||||
- };
|
||||
- [SCShareableContent getShareableContentWithCompletionHandler:handler];
|
||||
+
|
||||
+ if (@available(macOS 15.0, *)) {
|
||||
+ constexpr bool DefaultUseNativePicker = true;
|
||||
+ if (use_native_picker.value_or(DefaultUseNativePicker) &&
|
||||
+ source_.id == DesktopMediaID::kMacOsNativePickerId &&
|
||||
+ source_.window_id < 0) {
|
||||
+ auto* picker = [SCContentSharingPicker sharedPicker];
|
||||
+ ScreenCaptureKitDeviceMac::active_streams_++;
|
||||
+ picker.maximumStreamCount = @(ScreenCaptureKitDeviceMac::active_streams_);
|
||||
+ if (!picker.active) {
|
||||
+ picker.active = true;
|
||||
+ }
|
||||
+ NSMutableArray<NSNumber*>* exclude_ns_windows = [NSMutableArray array];
|
||||
+ [[[[NSApplication sharedApplication] windows] filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(NSWindow* win, NSDictionary *bindings) {
|
||||
+ return [win sharingType] == NSWindowSharingNone;
|
||||
+ }]] enumerateObjectsUsingBlock:^(NSWindow* win, NSUInteger idx, BOOL *stop) {
|
||||
+ [exclude_ns_windows addObject:@([win windowNumber])];
|
||||
+ }];
|
||||
+ picker.defaultConfiguration.excludedWindowIDs = exclude_ns_windows;
|
||||
+ [picker present];
|
||||
+ return;
|
||||
+ }
|
||||
}
|
||||
+
|
||||
+ auto content_callback = base::BindPostTask(
|
||||
+ device_task_runner_,
|
||||
+ base::BindRepeating(
|
||||
+ &ScreenCaptureKitDeviceMac::OnShareableContentCreated,
|
||||
+ weak_factory_.GetWeakPtr()));
|
||||
+ auto handler = ^(SCShareableContent* content, NSError* error) {
|
||||
+ content_callback.Run(content);
|
||||
+ };
|
||||
+ [SCShareableContent getShareableContentWithCompletionHandler:handler];
|
||||
}
|
||||
void OnStop() override {
|
||||
DCHECK(device_task_runner_->RunsTasksInCurrentSequence());
|
||||
@@ -577,8 +682,9 @@ void ResetStreamTo(SCWindow* window) override {
|
||||
}
|
||||
|
||||
private:
|
||||
+ static int active_streams_;
|
||||
+
|
||||
const DesktopMediaID source_;
|
||||
- SCContentFilter* const filter_;
|
||||
const scoped_refptr<base::SingleThreadTaskRunner> device_task_runner_;
|
||||
|
||||
// The actual format of the video frames that are sent to `client`.
|
||||
@@ -594,6 +700,10 @@ void ResetStreamTo(SCWindow* window) override {
|
||||
// Helper class that acts as output and delegate for `stream_`.
|
||||
ScreenCaptureKitDeviceHelper* __strong helper_;
|
||||
|
||||
+ // Helper class that acts as an observer for SCContentSharingPicker
|
||||
+ API_AVAILABLE(macos(15.0))
|
||||
+ ScreenCaptureKitPickerHelper* __strong picker_helper_;
|
||||
+
|
||||
// This is used to detect when a captured presentation enters fullscreen mode.
|
||||
// If this happens, the module will call the ResetStreamTo function.
|
||||
std::unique_ptr<ScreenCaptureKitFullscreenModule> fullscreen_module_;
|
||||
@@ -606,6 +716,8 @@ void ResetStreamTo(SCWindow* window) override {
|
||||
base::WeakPtrFactory<ScreenCaptureKitDeviceMac> weak_factory_{this};
|
||||
};
|
||||
|
||||
+int ScreenCaptureKitDeviceMac::active_streams_ = 0;
|
||||
+
|
||||
} // namespace
|
||||
|
||||
// Although ScreenCaptureKit is available in 12.3 there were some bugs that
|
||||
diff --git a/content/browser/renderer_host/media/in_process_video_capture_device_launcher.cc b/content/browser/renderer_host/media/in_process_video_capture_device_launcher.cc
|
||||
index 0ab684dc8e792359abb90b91917eddae42e6123d..f0f08a834f06c7669da6030640434308a5cbd056 100644
|
||||
--- a/content/browser/renderer_host/media/in_process_video_capture_device_launcher.cc
|
||||
+++ b/content/browser/renderer_host/media/in_process_video_capture_device_launcher.cc
|
||||
@@ -316,8 +316,16 @@ void InProcessVideoCaptureDeviceLauncher::LaunchDeviceAsync(
|
||||
break;
|
||||
}
|
||||
|
||||
+#if defined(USE_AURA)
|
||||
+ bool allow_window_id = false;
|
||||
+#elif BUILDFLAG(IS_MAC)
|
||||
+ bool allow_window_id =
|
||||
+ desktop_id.id == DesktopMediaID::kMacOsNativePickerId;
|
||||
+#endif
|
||||
+
|
||||
#if defined(USE_AURA) || BUILDFLAG(IS_MAC)
|
||||
- if (desktop_id.window_id != DesktopMediaID::kNullId) {
|
||||
+ if (!allow_window_id &&
|
||||
+ desktop_id.window_id != DesktopMediaID::kNullId) {
|
||||
// For the other capturers, when a bug reports the type of capture it's
|
||||
// easy enough to determine which capturer was used, but it's a little
|
||||
// fuzzier with window capture.
|
||||
@@ -333,13 +341,15 @@ void InProcessVideoCaptureDeviceLauncher::LaunchDeviceAsync(
|
||||
}
|
||||
#endif // defined(USE_AURA) || BUILDFLAG(IS_MAC)
|
||||
|
||||
+ media::VideoCaptureParams updated_params = params;
|
||||
+ updated_params.use_native_picker = stream_type != blink::mojom::MediaStreamType::GUM_DESKTOP_VIDEO_CAPTURE;
|
||||
// All cases other than tab capture or Aura desktop/window capture.
|
||||
TRACE_EVENT_INSTANT0(TRACE_DISABLED_BY_DEFAULT("video_and_image_capture"),
|
||||
"UsingDesktopCapturer", TRACE_EVENT_SCOPE_THREAD);
|
||||
start_capture_closure = base::BindOnce(
|
||||
&InProcessVideoCaptureDeviceLauncher::
|
||||
DoStartDesktopCaptureOnDeviceThread,
|
||||
- base::Unretained(this), desktop_id, params,
|
||||
+ base::Unretained(this), desktop_id, updated_params,
|
||||
CreateDeviceClient(media::VideoCaptureBufferType::kSharedMemory,
|
||||
kMaxNumberOfBuffers, std::move(receiver),
|
||||
std::move(receiver_on_io_thread)),
|
||||
diff --git a/content/public/browser/desktop_media_id.h b/content/public/browser/desktop_media_id.h
|
||||
index 415156d403a59bf426cf4561a9d58ecdb27524b4..78aa7b2359c684d5305bf6352751dfbb7ca00d29 100644
|
||||
--- a/content/public/browser/desktop_media_id.h
|
||||
+++ b/content/public/browser/desktop_media_id.h
|
||||
@@ -27,6 +27,8 @@ struct CONTENT_EXPORT DesktopMediaID {
|
||||
static constexpr Id kNullId = 0;
|
||||
// Represents a fake id to create a dummy capturer for autotests.
|
||||
static constexpr Id kFakeId = -3;
|
||||
+ // Represents an id to use native macOS picker for screenshare
|
||||
+ static constexpr Id kMacOsNativePickerId = -4;
|
||||
|
||||
#if defined(USE_AURA) || BUILDFLAG(IS_MAC)
|
||||
// Assigns integer identifier to the |window| and returns its DesktopMediaID.
|
||||
diff --git a/media/capture/video_capture_types.h b/media/capture/video_capture_types.h
|
||||
index 53e8077c9c0b635df0abdeca43fa9a6373c68252..2805e36cc42190d8197d83f5df235094570e3d5d 100644
|
||||
--- a/media/capture/video_capture_types.h
|
||||
+++ b/media/capture/video_capture_types.h
|
||||
@@ -355,6 +355,8 @@ struct CAPTURE_EXPORT VideoCaptureParams {
|
||||
// Flag indicating whether HiDPI mode should be enabled for tab capture
|
||||
// sessions.
|
||||
bool is_high_dpi_enabled = true;
|
||||
+
|
||||
+ std::optional<bool> use_native_picker;
|
||||
};
|
||||
|
||||
CAPTURE_EXPORT std::ostream& operator<<(
|
||||
@@ -0,0 +1,737 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Keeley Hammond <khammond@slack-corp.com>
|
||||
Date: Tue, 14 Jan 2025 15:50:29 -0800
|
||||
Subject: feat: allow desktop capturer to return either screen, window or both
|
||||
and make MacOS SCContentSharingPicker work in Electron
|
||||
|
||||
This patch is a work in progress that contains assorted changes to make the MacOS SCContentSharingPicker upstream implementation work within Electron. If this comment is still in this patch during PR review, it is not ready for prime time
|
||||
|
||||
This patch can be removed after our desktopCapturer is refactored.
|
||||
|
||||
diff --git a/chrome/browser/media/webrtc/capture_policy_utils.cc b/chrome/browser/media/webrtc/capture_policy_utils.cc
|
||||
index 36797f37627d534bd446e0d8270618722ed9a2fa..32222cb526dc047a02cd9382814edd71cca0a378 100644
|
||||
--- a/chrome/browser/media/webrtc/capture_policy_utils.cc
|
||||
+++ b/chrome/browser/media/webrtc/capture_policy_utils.cc
|
||||
@@ -356,7 +356,9 @@ void FilterMediaList(std::vector<DesktopMediaList::Type>& media_types,
|
||||
media_types, [capture_level](const DesktopMediaList::Type& type) {
|
||||
switch (type) {
|
||||
case DesktopMediaList::Type::kNone:
|
||||
- NOTREACHED();
|
||||
+ //TODO(review): are we able to remove this?
|
||||
+ return capture_level < AllowedScreenCaptureLevel::kDesktop;
|
||||
+ // NOTREACHED();
|
||||
// SameOrigin is more restrictive than just Tabs, so as long as
|
||||
// at least SameOrigin is allowed, these entries should stay.
|
||||
// They should be filtered later by the caller.
|
||||
diff --git a/chrome/browser/media/webrtc/desktop_media_list_base.cc b/chrome/browser/media/webrtc/desktop_media_list_base.cc
|
||||
index 08400be4d1bae18502d19beed6b2d9057e55dd4f..4df1a9f44959db1f73d6a8a535d297343f7f0c00 100644
|
||||
--- a/chrome/browser/media/webrtc/desktop_media_list_base.cc
|
||||
+++ b/chrome/browser/media/webrtc/desktop_media_list_base.cc
|
||||
@@ -12,9 +12,11 @@
|
||||
#include <set>
|
||||
#include <utility>
|
||||
|
||||
+#include "base/logging.h"
|
||||
#include "base/functional/bind.h"
|
||||
#include "base/hash/hash.h"
|
||||
#include "chrome/browser/media/webrtc/desktop_media_list.h"
|
||||
+#include "chrome/browser/media/webrtc/thumbnail_capturer_mac.h"
|
||||
#include "content/public/browser/browser_task_traits.h"
|
||||
#include "content/public/browser/browser_thread.h"
|
||||
#include "third_party/skia/include/core/SkBitmap.h"
|
||||
@@ -60,24 +62,34 @@ void DesktopMediaListBase::StartUpdating(DesktopMediaListObserver* observer) {
|
||||
// If there is a delegated source list, it may not have been started yet.
|
||||
if (IsSourceListDelegated())
|
||||
StartDelegatedCapturer();
|
||||
+ LOG(ERROR) << "start delegated capturer";
|
||||
|
||||
// Process sources previously discovered by a call to Update().
|
||||
if (observer_) {
|
||||
for (size_t i = 0; i < sources_.size(); i++) {
|
||||
observer_->OnSourceAdded(i);
|
||||
+ LOG(ERROR) << "OnSourceAdded, i: " << i;
|
||||
}
|
||||
}
|
||||
-
|
||||
+ LOG(INFO)<< "Refresh callback_ is null: " << refresh_callback_.is_null() << ";";
|
||||
DCHECK(!refresh_callback_);
|
||||
+ LOG(INFO) << "dcheck passed";
|
||||
refresh_callback_ = base::BindOnce(&DesktopMediaListBase::ScheduleNextRefresh,
|
||||
weak_factory_.GetWeakPtr());
|
||||
Refresh(true);
|
||||
}
|
||||
|
||||
void DesktopMediaListBase::Update(UpdateCallback callback, bool refresh_thumbnails) {
|
||||
+ LOG(ERROR) << "Update";
|
||||
DCHECK_CURRENTLY_ON(BrowserThread::UI);
|
||||
DCHECK(sources_.empty());
|
||||
- DCHECK(!refresh_callback_);
|
||||
+ #if BUILDFLAG(IS_MAC)
|
||||
+ if (!ShouldUseSCContentSharingPicker()) {
|
||||
+ DCHECK(!refresh_callback_);
|
||||
+ };
|
||||
+ #else
|
||||
+ DCHECK(!refresh_callback_);
|
||||
+ #endif
|
||||
refresh_callback_ = std::move(callback);
|
||||
Refresh(refresh_thumbnails);
|
||||
}
|
||||
diff --git a/chrome/browser/media/webrtc/native_desktop_media_list.cc b/chrome/browser/media/webrtc/native_desktop_media_list.cc
|
||||
index 312882d656f9f6b3d3fd98128131cea63f818e0d..f61697e1717fcfa0500974e8523438389fbab5ae 100644
|
||||
--- a/chrome/browser/media/webrtc/native_desktop_media_list.cc
|
||||
+++ b/chrome/browser/media/webrtc/native_desktop_media_list.cc
|
||||
@@ -45,6 +45,7 @@
|
||||
#endif
|
||||
|
||||
#if BUILDFLAG(IS_MAC)
|
||||
+#include "chrome/browser/media/webrtc/thumbnail_capturer_mac.h"
|
||||
#include "components/remote_cocoa/browser/scoped_cg_window_id.h"
|
||||
#endif
|
||||
|
||||
@@ -162,9 +163,10 @@ content::DesktopMediaID::Type ConvertToDesktopMediaIDType(
|
||||
return content::DesktopMediaID::Type::TYPE_SCREEN;
|
||||
case DesktopMediaList::Type::kWindow:
|
||||
return content::DesktopMediaID::Type::TYPE_WINDOW;
|
||||
+ case DesktopMediaList::Type::kNone:
|
||||
+ return content::DesktopMediaID::Type::TYPE_NONE;
|
||||
case DesktopMediaList::Type::kWebContents:
|
||||
case DesktopMediaList::Type::kCurrentTab:
|
||||
- case DesktopMediaList::Type::kNone:
|
||||
break;
|
||||
}
|
||||
NOTREACHED();
|
||||
@@ -372,7 +374,8 @@ NativeDesktopMediaList::Worker::Worker(
|
||||
nullptr) {
|
||||
DCHECK(capturer_);
|
||||
|
||||
- DCHECK(source_type_ == DesktopMediaID::Type::TYPE_WINDOW ||
|
||||
+ DCHECK(source_type_ == DesktopMediaID::Type::TYPE_WINDOW || source_type_ ==
|
||||
+ DesktopMediaID::Type::TYPE_NONE ||
|
||||
!add_current_process_windows_);
|
||||
}
|
||||
|
||||
@@ -505,11 +508,27 @@ NativeDesktopMediaList::Worker::FormatSources(
|
||||
break;
|
||||
|
||||
case DesktopMediaID::Type::TYPE_WINDOW:
|
||||
+ case DesktopMediaID::Type::TYPE_NONE:
|
||||
+ #if BUILDFLAG(IS_MAC)
|
||||
+ // If using NativeScreenCapturePickerMac,
|
||||
+ // skipping the picker will skip the first window selection.
|
||||
+ if (ShouldUseSCContentSharingPicker()) {
|
||||
+ title = base::UTF8ToUTF16(sources[i].title);
|
||||
+ LOG(ERROR) << "formatting native picker source, id: " << sources[i].id << " title: " << title;
|
||||
+ LOG(ERROR) << "sources size: " << sources.size();
|
||||
+ LOG(ERROR) << "excluded window id: " << excluded_window_id;
|
||||
+ } else if (sources[i].id == excluded_window_id) {
|
||||
+ // Skip the picker dialog window.
|
||||
+ continue;
|
||||
+ }
|
||||
+ title = base::UTF8ToUTF16(sources[i].title);
|
||||
+ #else
|
||||
// Skip the picker dialog window.
|
||||
if (sources[i].id == excluded_window_id) {
|
||||
continue;
|
||||
}
|
||||
title = base::UTF8ToUTF16(sources[i].title);
|
||||
+ #endif
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -775,14 +794,10 @@ NativeDesktopMediaList::NativeDesktopMediaList(
|
||||
is_source_list_delegated_(capturer->GetDelegatedSourceListController() !=
|
||||
nullptr) {
|
||||
type_ = type;
|
||||
-
|
||||
- DCHECK(type_ == DesktopMediaList::Type::kWindow ||
|
||||
+ DCHECK(type_ == DesktopMediaList::Type::kWindow || type_ == DesktopMediaList::Type::kNone ||
|
||||
!add_current_process_windows_);
|
||||
|
||||
#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC)
|
||||
- // webrtc::DesktopCapturer implementations on Windows, MacOS and Fuchsia
|
||||
- // expect to run on a thread with a UI message pump. Under Fuchsia the
|
||||
- // capturer needs an async loop to support FIDL I/O.
|
||||
base::MessagePumpType thread_type = base::MessagePumpType::UI;
|
||||
#else
|
||||
base::MessagePumpType thread_type = base::MessagePumpType::DEFAULT;
|
||||
@@ -794,8 +809,9 @@ NativeDesktopMediaList::NativeDesktopMediaList(
|
||||
std::move(capturer), add_current_process_windows_,
|
||||
auto_show_delegated_source_list);
|
||||
|
||||
- if (!is_source_list_delegated_)
|
||||
+ if (!is_source_list_delegated_) {
|
||||
StartCapturer();
|
||||
+ }
|
||||
}
|
||||
|
||||
NativeDesktopMediaList::~NativeDesktopMediaList() {
|
||||
@@ -903,7 +919,7 @@ void NativeDesktopMediaList::ShowDelegatedList() {
|
||||
}
|
||||
|
||||
void NativeDesktopMediaList::Refresh(bool update_thumbnails) {
|
||||
- DCHECK(can_refresh());
|
||||
+ DCHECK(can_refresh());
|
||||
|
||||
#if defined(USE_AURA)
|
||||
DCHECK_EQ(pending_aura_capture_requests_, 0);
|
||||
diff --git a/chrome/browser/media/webrtc/thumbnail_capturer_mac.h b/chrome/browser/media/webrtc/thumbnail_capturer_mac.h
|
||||
index 12a74f8f32cc00a7f3d7802865ae4b309961341d..acbcfb08ae8c44e24a04b326096289428bc6ff60 100644
|
||||
--- a/chrome/browser/media/webrtc/thumbnail_capturer_mac.h
|
||||
+++ b/chrome/browser/media/webrtc/thumbnail_capturer_mac.h
|
||||
@@ -8,6 +8,9 @@
|
||||
#include "chrome/browser/media/webrtc/desktop_media_list.h"
|
||||
#include "chrome/browser/media/webrtc/thumbnail_capturer.h"
|
||||
|
||||
+// Returns true if the SCK sharing picker is available and enabled.
|
||||
+bool ShouldUseSCContentSharingPicker();
|
||||
+
|
||||
// Returns true if the SCK thumbnail capturer is available and enabled.
|
||||
bool ShouldUseThumbnailCapturerMac(DesktopMediaList::Type type);
|
||||
|
||||
diff --git a/chrome/browser/media/webrtc/thumbnail_capturer_mac.mm b/chrome/browser/media/webrtc/thumbnail_capturer_mac.mm
|
||||
index 744f2447dc2d43c4f6be695bf561474993468705..bb5781b0f0df11422f8355dcc59f5f0f46ebcf89 100644
|
||||
--- a/chrome/browser/media/webrtc/thumbnail_capturer_mac.mm
|
||||
+++ b/chrome/browser/media/webrtc/thumbnail_capturer_mac.mm
|
||||
@@ -13,6 +13,7 @@
|
||||
#include <optional>
|
||||
#include <unordered_map>
|
||||
|
||||
+#include "base/logging.h"
|
||||
#include "base/apple/bridging.h"
|
||||
#include "base/apple/foundation_util.h"
|
||||
#include "base/apple/scoped_cftyperef.h"
|
||||
@@ -71,11 +72,11 @@
|
||||
return content::DesktopMediaID::Type::TYPE_SCREEN;
|
||||
case DesktopMediaList::Type::kWindow:
|
||||
return content::DesktopMediaID::Type::TYPE_WINDOW;
|
||||
+ case DesktopMediaList::Type::kNone:
|
||||
+ return content::DesktopMediaID::Type::TYPE_NONE;
|
||||
case DesktopMediaList::Type::kWebContents:
|
||||
case DesktopMediaList::Type::kCurrentTab:
|
||||
return content::DesktopMediaID::Type::TYPE_WEB_CONTENTS;
|
||||
- case DesktopMediaList::Type::kNone:
|
||||
- break;
|
||||
}
|
||||
NOTREACHED();
|
||||
}
|
||||
@@ -442,7 +443,7 @@ void OnCapturedFrame(base::apple::ScopedCFTypeRef<CGImageRef> image,
|
||||
max_frame_rate_(kThumbnailCapturerMacMaxFrameRate),
|
||||
shareable_windows_([[NSArray<SCWindow*> alloc] init]) {
|
||||
CHECK(type_ == DesktopMediaList::Type::kWindow ||
|
||||
- type_ == DesktopMediaList::Type::kScreen);
|
||||
+ type_ == DesktopMediaList::Type::kScreen || type_ == DesktopMediaList::Type::kNone);
|
||||
}
|
||||
|
||||
ThumbnailCapturerMac::~ThumbnailCapturerMac() {
|
||||
@@ -680,17 +681,15 @@ void OnCapturedFrame(base::apple::ScopedCFTypeRef<CGImageRef> image,
|
||||
source_id);
|
||||
}
|
||||
|
||||
+} // namespace
|
||||
+
|
||||
bool ShouldUseSCContentSharingPicker() {
|
||||
if (@available(macOS 15.0, *)) {
|
||||
- if (base::FeatureList::IsEnabled(media::kUseSCContentSharingPicker)) {
|
||||
- return true;
|
||||
- }
|
||||
+ return base::FeatureList::IsEnabled(media::kUseSCContentSharingPicker);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
-} // namespace
|
||||
-
|
||||
bool ShouldUseThumbnailCapturerMac(DesktopMediaList::Type type) {
|
||||
// There was a bug in ScreenCaptureKit that was fixed in 14.4,
|
||||
// see b/40076027.
|
||||
@@ -704,6 +703,9 @@ bool ShouldUseThumbnailCapturerMac(DesktopMediaList::Type type) {
|
||||
return ShouldUseSCContentSharingPicker() ||
|
||||
base::FeatureList::IsEnabled(kScreenCaptureKitPickerScreen);
|
||||
case DesktopMediaList::Type::kNone:
|
||||
+ return ShouldUseSCContentSharingPicker() ||
|
||||
+ base::FeatureList::IsEnabled(kScreenCaptureKitStreamPickerSonoma) ||
|
||||
+ base::FeatureList::IsEnabled(kScreenCaptureKitPickerScreen);
|
||||
case DesktopMediaList::Type::kCurrentTab:
|
||||
case DesktopMediaList::Type::kWebContents:
|
||||
return false;
|
||||
diff --git a/content/browser/media/capture/desktop_capture_device.cc b/content/browser/media/capture/desktop_capture_device.cc
|
||||
index b4b1e9ee805a8565a04737e0898ad8e46709c4d8..7b856f89028fe8f5594c1ff35900019250865ab5 100644
|
||||
--- a/content/browser/media/capture/desktop_capture_device.cc
|
||||
+++ b/content/browser/media/capture/desktop_capture_device.cc
|
||||
@@ -899,7 +899,6 @@ std::unique_ptr<media::VideoCaptureDevice> DesktopCaptureDevice::Create(
|
||||
result.reset(new DesktopCaptureDevice(std::move(capturer), source.type));
|
||||
return result;
|
||||
}
|
||||
-
|
||||
switch (source.type) {
|
||||
case DesktopMediaID::TYPE_SCREEN: {
|
||||
std::unique_ptr<webrtc::DesktopCapturer> screen_capturer;
|
||||
@@ -920,7 +919,7 @@ std::unique_ptr<media::VideoCaptureDevice> DesktopCaptureDevice::Create(
|
||||
}
|
||||
break;
|
||||
}
|
||||
-
|
||||
+ case DesktopMediaID::TYPE_NONE:
|
||||
case DesktopMediaID::TYPE_WINDOW: {
|
||||
std::unique_ptr<webrtc::DesktopCapturer> window_capturer;
|
||||
if (auto generic_capturer =
|
||||
diff --git a/content/browser/media/capture/native_screen_capture_picker.cc b/content/browser/media/capture/native_screen_capture_picker.cc
|
||||
index 152f3aa78032ee3f8c48fbefe052a2f1d85bed6b..d57df80dff9c6867cddf669efe3f90c43c03a0a7 100644
|
||||
--- a/content/browser/media/capture/native_screen_capture_picker.cc
|
||||
+++ b/content/browser/media/capture/native_screen_capture_picker.cc
|
||||
@@ -7,6 +7,7 @@
|
||||
#if BUILDFLAG(IS_MAC)
|
||||
#include "content/browser/media/capture/native_screen_capture_picker_mac.h"
|
||||
#include "media/base/media_switches.h"
|
||||
+#include "base/logging.h"
|
||||
#endif
|
||||
|
||||
namespace content {
|
||||
diff --git a/content/browser/media/capture/native_screen_capture_picker_mac.mm b/content/browser/media/capture/native_screen_capture_picker_mac.mm
|
||||
index 0dbc7ebc4ba6066eb6b20f8e66f50a1dff4d94f3..17d658ee011b81208b77ee1e65925ae9ad1e68f7 100644
|
||||
--- a/content/browser/media/capture/native_screen_capture_picker_mac.mm
|
||||
+++ b/content/browser/media/capture/native_screen_capture_picker_mac.mm
|
||||
@@ -206,8 +206,12 @@ void Open(DesktopMediaID::Type type,
|
||||
base::OnceClosure cancel_callback,
|
||||
base::OnceClosure error_callback) {
|
||||
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
|
||||
+ LOG(ERROR) << "Open";
|
||||
+ // Chrome doesn't allow both screens & windows in their picker,
|
||||
+ // but Electron does - add a check for TYPE_NONE.
|
||||
CHECK(type == DesktopMediaID::Type::TYPE_SCREEN ||
|
||||
- type == DesktopMediaID::Type::TYPE_WINDOW);
|
||||
+ type == DesktopMediaID::Type::TYPE_WINDOW ||
|
||||
+ type == DesktopMediaID::Type::TYPE_NONE);
|
||||
if (@available(macOS 14.0, *)) {
|
||||
NSNumber* source_id = @(next_id_);
|
||||
PickerObserver* picker_observer = [[PickerObserver alloc]
|
||||
@@ -226,25 +230,32 @@ void Open(DesktopMediaID::Type type,
|
||||
// TODO(https://crbug.com/360781940): Add support for changing selected
|
||||
// content. The problem to solve is how this should interact with stream
|
||||
// restart.
|
||||
- config.allowsChangingSelectedContent = false;
|
||||
+ config.allowsChangingSelectedContent = true;
|
||||
NSNumber* max_stream_count = @(kMaxContentShareCountValue.Get());
|
||||
- if (type == DesktopMediaID::Type::TYPE_SCREEN) {
|
||||
- config.allowedPickerModes = SCContentSharingPickerModeSingleDisplay;
|
||||
- picker.defaultConfiguration = config;
|
||||
- picker.maximumStreamCount = max_stream_count;
|
||||
- [picker presentPickerUsingContentStyle:SCShareableContentStyleDisplay];
|
||||
- VLOG(1) << "NSCPM: Show screen-sharing picker for source_id = "
|
||||
- << source_id.longValue;
|
||||
- LogToUma(SCContentSharingPickerOperation::kPresentScreen_Start);
|
||||
- } else {
|
||||
- config.allowedPickerModes = SCContentSharingPickerModeSingleWindow;
|
||||
- picker.defaultConfiguration = config;
|
||||
- picker.maximumStreamCount = max_stream_count;
|
||||
- [picker presentPickerUsingContentStyle:SCShareableContentStyleWindow];
|
||||
- VLOG(1) << "NSCPM: Show window-sharing picker for source_id = "
|
||||
- << source_id.longValue;
|
||||
- LogToUma(SCContentSharingPickerOperation::kPresentWindow_Start);
|
||||
- }
|
||||
+ // LOG(ERROR) << "Type: " << type;
|
||||
+ // Chrome doesn't allow both screens & windows in their picker,
|
||||
+ // but Electron does; we patch out the MediaID::Type conditional here
|
||||
+ // if (type == DesktopMediaID::Type::TYPE_SCREEN) {
|
||||
+ // config.allowedPickerModes = SCContentSharingPickerModeSingleDisplay;
|
||||
+ // picker.defaultConfiguration = config;
|
||||
+ // picker.maximumStreamCount = max_stream_count;
|
||||
+ // [picker presentPickerUsingContentStyle:SCShareableContentStyleDisplay];
|
||||
+ // } else if (type == DesktopMediaID::Type::TYPE_WINDOW) {
|
||||
+ // config.allowedPickerModes = SCContentSharingPickerModeSingleWindow;
|
||||
+ // picker.defaultConfiguration = config;
|
||||
+ // picker.maximumStreamCount = max_stream_count;
|
||||
+ // [picker presentPickerUsingContentStyle:SCShareableContentStyleWindow];
|
||||
+ // VLOG(1) << "NSCPM: Show screen-sharing picker for source_id = "
|
||||
+ // << source_id.longValue;
|
||||
+ // LogToUma(SCContentSharingPickerOperation::kPresentScreen_Start);
|
||||
+ // } else {
|
||||
+ picker.defaultConfiguration = config;
|
||||
+ picker.maximumStreamCount = max_stream_count;
|
||||
+ [picker present];
|
||||
+ // VLOG(1) << "NSCPM: Show window-sharing picker for source_id = "
|
||||
+ // << source_id.longValue;
|
||||
+ // LogToUma(SCContentSharingPickerOperation::kPresentWindow_Start);
|
||||
+ // }
|
||||
} else {
|
||||
NOTREACHED();
|
||||
}
|
||||
diff --git a/content/browser/media/capture/screen_capture_kit_device_mac.mm b/content/browser/media/capture/screen_capture_kit_device_mac.mm
|
||||
index 7e17594c30ac3cf8cb484b53563b03fc75bd2e0b..fef50841f472bf3e76c171d9e106c689157adaae 100644
|
||||
--- a/content/browser/media/capture/screen_capture_kit_device_mac.mm
|
||||
+++ b/content/browser/media/capture/screen_capture_kit_device_mac.mm
|
||||
@@ -281,6 +281,7 @@ void OnShareableContentCreated(SCShareableContent* content) {
|
||||
if (!fullscreen_module_) {
|
||||
fullscreen_module_ = MaybeCreateScreenCaptureKitFullscreenModule(
|
||||
device_task_runner_, *this, window);
|
||||
+ break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -616,6 +617,7 @@ void ResetStreamTo(SCWindow* window) override {
|
||||
SCContentFilter* filter) {
|
||||
switch (source.type) {
|
||||
case DesktopMediaID::TYPE_SCREEN:
|
||||
+ case DesktopMediaID::TYPE_NONE:
|
||||
// ScreenCaptureKitDeviceMac only supports a single display at a time.
|
||||
// It will not stitch desktops together. If
|
||||
// kScreenCaptureKitFullDesktopFallback is enabled, we will fallback to
|
||||
diff --git a/content/browser/renderer_host/media/in_process_video_capture_device_launcher.cc b/content/browser/renderer_host/media/in_process_video_capture_device_launcher.cc
|
||||
index 0ab684dc8e792359abb90b91917eddae42e6123d..2351919905fbec6c1bfe9ce59d799192a9e2e0e6 100644
|
||||
--- a/content/browser/renderer_host/media/in_process_video_capture_device_launcher.cc
|
||||
+++ b/content/browser/renderer_host/media/in_process_video_capture_device_launcher.cc
|
||||
@@ -177,19 +177,20 @@ DesktopCaptureImplementation CreatePlatformDependentVideoCaptureDevice(
|
||||
#if BUILDFLAG(IS_MAC)
|
||||
// Use ScreenCaptureKit with picker if specified. `desktop_id` for the picker
|
||||
// is not compatible with the other implementations.
|
||||
- if (picker) {
|
||||
- device_out = picker->CreateDevice(desktop_id);
|
||||
- if (device_out) {
|
||||
- return kScreenCaptureKitDeviceMac;
|
||||
- }
|
||||
- return kNoImplementation;
|
||||
- }
|
||||
+ // if (picker) {
|
||||
+ // device_out = picker->CreateDevice(desktop_id);
|
||||
+ // if (device_out) {
|
||||
+ // return kScreenCaptureKitDeviceMac;
|
||||
+ // }
|
||||
+ // return kNoImplementation;
|
||||
+ // }
|
||||
|
||||
// Prefer using ScreenCaptureKit. After that try DesktopCaptureDeviceMac, and
|
||||
// if both fail, use the generic DesktopCaptureDevice.
|
||||
if (desktop_id.type == DesktopMediaID::TYPE_WINDOW ||
|
||||
(desktop_id.type == DesktopMediaID::TYPE_SCREEN &&
|
||||
- base::FeatureList::IsEnabled(kScreenCaptureKitMacScreen))) {
|
||||
+ base::FeatureList::IsEnabled(kScreenCaptureKitMacScreen)) ||
|
||||
+ (desktop_id.type == DesktopMediaID::TYPE_NONE && base::FeatureList::IsEnabled(kScreenCaptureKitMacScreen))) {
|
||||
device_out = CreateScreenCaptureKitDeviceMac(desktop_id);
|
||||
if (device_out) {
|
||||
return kScreenCaptureKitDeviceMac;
|
||||
@@ -237,6 +238,9 @@ void InProcessVideoCaptureDeviceLauncher::LaunchDeviceAsync(
|
||||
DCHECK(state_ == State::READY_TO_LAUNCH);
|
||||
|
||||
if (receiver_on_io_thread) {
|
||||
+ LOG(INFO) << "InProcessVideoCaptureDeviceLauncher::LaunchDeviceAsync: Posting "
|
||||
+ "start request to device thread for device_id = "
|
||||
+ << device_id;
|
||||
std::ostringstream string_stream;
|
||||
string_stream
|
||||
<< "InProcessVideoCaptureDeviceLauncher::LaunchDeviceAsync: Posting "
|
||||
@@ -244,7 +248,7 @@ void InProcessVideoCaptureDeviceLauncher::LaunchDeviceAsync(
|
||||
<< device_id;
|
||||
receiver_on_io_thread->OnLog(string_stream.str());
|
||||
}
|
||||
-
|
||||
+ LOG(ERROR) << "receiver_on_io_thread: ";
|
||||
// Wrap the receiver, to trampoline all its method calls from the device
|
||||
// to the IO thread.
|
||||
auto receiver = std::make_unique<media::VideoFrameReceiverOnTaskRunner>(
|
||||
@@ -257,12 +261,14 @@ void InProcessVideoCaptureDeviceLauncher::LaunchDeviceAsync(
|
||||
base::BindPostTaskToCurrentDefault(base::BindOnce(
|
||||
&InProcessVideoCaptureDeviceLauncher::OnDeviceStarted,
|
||||
base::Unretained(this), callbacks, std::move(done_cb)));
|
||||
-
|
||||
+ LOG(ERROR) << "stream type: " << stream_type;
|
||||
+ LOG(ERROR) << "gum tab video capture: " << blink::mojom::MediaStreamType::GUM_TAB_VIDEO_CAPTURE;
|
||||
switch (stream_type) {
|
||||
- case blink::mojom::MediaStreamType::DEVICE_VIDEO_CAPTURE:
|
||||
- // Only the Service-based device launcher is supported for device capture
|
||||
- // from cameras etc.
|
||||
- NOTREACHED();
|
||||
+ // case blink::mojom::MediaStreamType::DEVICE_VIDEO_CAPTURE:
|
||||
+ // // Only the Service-based device launcher is supported for device capture
|
||||
+ // // from cameras etc.
|
||||
+ // LOG(INFO) << "device video capture not reached";
|
||||
+ // NOTREACHED();
|
||||
#if BUILDFLAG(ENABLE_SCREEN_CAPTURE)
|
||||
case blink::mojom::MediaStreamType::GUM_TAB_VIDEO_CAPTURE:
|
||||
start_capture_closure = base::BindOnce(
|
||||
@@ -274,10 +280,14 @@ void InProcessVideoCaptureDeviceLauncher::LaunchDeviceAsync(
|
||||
case blink::mojom::MediaStreamType::GUM_DESKTOP_VIDEO_CAPTURE:
|
||||
case blink::mojom::MediaStreamType::DISPLAY_VIDEO_CAPTURE:
|
||||
case blink::mojom::MediaStreamType::DISPLAY_VIDEO_CAPTURE_THIS_TAB:
|
||||
+ case blink::mojom::MediaStreamType::DEVICE_VIDEO_CAPTURE:
|
||||
case blink::mojom::MediaStreamType::DISPLAY_VIDEO_CAPTURE_SET: {
|
||||
const DesktopMediaID desktop_id = DesktopMediaID::Parse(device_id);
|
||||
- if (desktop_id.is_null()) {
|
||||
- DLOG(ERROR) << "Desktop media ID is null";
|
||||
+ LOG(ERROR) << "desktop_id.is_null(): " << desktop_id.is_null();
|
||||
+ LOG(ERROR) << "desktop_id.id: " << desktop_id.id;
|
||||
+ LOG(ERROR) << "DesktopMediaID::kMacOsNativePickerId: " << DesktopMediaID::kMacOsNativePickerId;
|
||||
+ if (desktop_id.is_null() && desktop_id.id != DesktopMediaID::kMacOsNativePickerId) {
|
||||
+ LOG(ERROR) << "in null case";
|
||||
start_capture_closure =
|
||||
base::BindOnce(std::move(after_start_capture_callback), nullptr);
|
||||
break;
|
||||
@@ -316,8 +326,21 @@ void InProcessVideoCaptureDeviceLauncher::LaunchDeviceAsync(
|
||||
break;
|
||||
}
|
||||
|
||||
+#if defined(USE_AURA)
|
||||
+ bool allow_window_id = false;
|
||||
+#elif BUILDFLAG(IS_MAC)
|
||||
+
|
||||
+ bool allow_window_id =
|
||||
+ desktop_id.id == DesktopMediaID::kMacOsNativePickerId;
|
||||
+
|
||||
+ LOG(ERROR) << "allow_window_id: " << allow_window_id << " desktop_id.id: " << desktop_id.id;
|
||||
+#endif
|
||||
+
|
||||
#if defined(USE_AURA) || BUILDFLAG(IS_MAC)
|
||||
- if (desktop_id.window_id != DesktopMediaID::kNullId) {
|
||||
+ LOG(ERROR) << "in if block";
|
||||
+ if (!allow_window_id &&
|
||||
+ desktop_id.window_id != DesktopMediaID::kNullId) {
|
||||
+ LOG(ERROR) << "allow_window_id: " << allow_window_id << " desktop_id.window_id: " << desktop_id.window_id;
|
||||
// For the other capturers, when a bug reports the type of capture it's
|
||||
// easy enough to determine which capturer was used, but it's a little
|
||||
// fuzzier with window capture.
|
||||
@@ -344,6 +367,7 @@ void InProcessVideoCaptureDeviceLauncher::LaunchDeviceAsync(
|
||||
kMaxNumberOfBuffers, std::move(receiver),
|
||||
std::move(receiver_on_io_thread)),
|
||||
std::move(after_start_capture_callback));
|
||||
+ LOG(ERROR) << "capture closure";
|
||||
break;
|
||||
}
|
||||
#endif // BUILDFLAG(ENABLE_SCREEN_CAPTURE)
|
||||
@@ -358,6 +382,7 @@ void InProcessVideoCaptureDeviceLauncher::LaunchDeviceAsync(
|
||||
// above are NOTREACHED() then.
|
||||
#if BUILDFLAG(ENABLE_SCREEN_CAPTURE)
|
||||
state_ = State::DEVICE_START_IN_PROGRESS;
|
||||
+ LOG(ERROR) << "start capture closure";
|
||||
device_task_runner_->PostTask(FROM_HERE, std::move(start_capture_closure));
|
||||
#endif
|
||||
}
|
||||
@@ -408,9 +433,11 @@ void InProcessVideoCaptureDeviceLauncher::OnDeviceStarted(
|
||||
base::OnceClosure done_cb,
|
||||
std::unique_ptr<media::VideoCaptureDevice> device) {
|
||||
DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
||||
+ LOG(ERROR) << "on device started";
|
||||
State state_copy = state_;
|
||||
state_ = State::READY_TO_LAUNCH;
|
||||
if (!device) {
|
||||
+ LOG(ERROR) << "device is null";
|
||||
switch (state_copy) {
|
||||
case State::DEVICE_START_IN_PROGRESS:
|
||||
callbacks->OnDeviceLaunchFailed(
|
||||
@@ -429,13 +456,15 @@ void InProcessVideoCaptureDeviceLauncher::OnDeviceStarted(
|
||||
|
||||
auto launched_device = std::make_unique<InProcessLaunchedVideoCaptureDevice>(
|
||||
std::move(device), device_task_runner_);
|
||||
-
|
||||
+ LOG(ERROR) << "launched device";
|
||||
switch (state_copy) {
|
||||
case State::DEVICE_START_IN_PROGRESS:
|
||||
+ LOG(ERROR) << "on device started, case 1";
|
||||
callbacks->OnDeviceLaunched(std::move(launched_device));
|
||||
std::move(done_cb).Run();
|
||||
return;
|
||||
case State::DEVICE_START_ABORTING:
|
||||
+ LOG(ERROR) << "on device started, case 2";
|
||||
launched_device.reset();
|
||||
callbacks->OnDeviceLaunchAborted();
|
||||
std::move(done_cb).Run();
|
||||
@@ -495,7 +524,8 @@ void InProcessVideoCaptureDeviceLauncher::DoStartDesktopCaptureOnDeviceThread(
|
||||
std::unique_ptr<media::VideoCaptureDeviceClient> device_client,
|
||||
ReceiveDeviceCallback result_callback) {
|
||||
DCHECK(device_task_runner_->BelongsToCurrentThread());
|
||||
- DCHECK(!desktop_id.is_null());
|
||||
+ LOG(INFO) << "DO START DESKTOP CAPTURE ON DEVICE THREAD " << desktop_id.id;
|
||||
+ DCHECK(!desktop_id.is_null() || desktop_id.id == DesktopMediaID::kMacOsNativePickerId);
|
||||
|
||||
std::unique_ptr<media::VideoCaptureDevice> video_capture_device;
|
||||
DesktopCaptureImplementation implementation =
|
||||
@@ -504,8 +534,10 @@ void InProcessVideoCaptureDeviceLauncher::DoStartDesktopCaptureOnDeviceThread(
|
||||
DVLOG(1) << __func__ << " implementation " << implementation << " type "
|
||||
<< desktop_id.type;
|
||||
ReportDesktopCaptureImplementationAndType(implementation, desktop_id.type);
|
||||
- if (video_capture_device)
|
||||
+ if (video_capture_device) {
|
||||
+ LOG(ERROR) << "allocate and start capture device";
|
||||
video_capture_device->AllocateAndStart(params, std::move(device_client));
|
||||
+ }
|
||||
std::move(result_callback).Run(std::move(video_capture_device));
|
||||
}
|
||||
|
||||
diff --git a/content/browser/renderer_host/media/in_process_video_capture_provider.cc b/content/browser/renderer_host/media/in_process_video_capture_provider.cc
|
||||
index 4462efa154a2be9cc25f82688fdbc7edf71a7bb1..4207dd1a79c16df5cc972943da32699f414f81fa 100644
|
||||
--- a/content/browser/renderer_host/media/in_process_video_capture_provider.cc
|
||||
+++ b/content/browser/renderer_host/media/in_process_video_capture_provider.cc
|
||||
@@ -9,6 +9,7 @@
|
||||
#include "base/functional/bind.h"
|
||||
#include "base/task/single_thread_task_runner.h"
|
||||
#include "content/browser/renderer_host/media/in_process_video_capture_device_launcher.h"
|
||||
+#include "content/browser/media/capture/native_screen_capture_picker.h"
|
||||
|
||||
namespace content {
|
||||
|
||||
diff --git a/content/browser/renderer_host/media/video_capture_manager.cc b/content/browser/renderer_host/media/video_capture_manager.cc
|
||||
index 2949c2abd5f97e66719ec0f77cb23813865bb701..bd11a0fcdc084da00407c80e4ee229a130fdedc8 100644
|
||||
--- a/content/browser/renderer_host/media/video_capture_manager.cc
|
||||
+++ b/content/browser/renderer_host/media/video_capture_manager.cc
|
||||
@@ -283,6 +283,7 @@ void VideoCaptureManager::QueueStartDevice(
|
||||
mojo::PendingRemote<media::mojom::ReadonlyVideoEffectsManager>
|
||||
readonly_video_effects_manager) {
|
||||
DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
||||
+ LOG(ERROR) << "QueueStartDevice";
|
||||
DCHECK(lock_time_.is_null());
|
||||
device_start_request_queue_.push_back(
|
||||
CaptureDeviceStartRequest(std::move(controller), session_id, params,
|
||||
@@ -297,6 +298,7 @@ void VideoCaptureManager::DoStopDevice(VideoCaptureController* controller) {
|
||||
TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("video_and_image_capture"),
|
||||
"VideoCaptureManager::DoStopDevice");
|
||||
DCHECK(base::Contains(controllers_, controller));
|
||||
+ LOG(ERROR) << "DoStopDevice called for stream type: " << controller->stream_type();
|
||||
|
||||
// If start request has not yet started processing, i.e. if it is not at the
|
||||
// beginning of the queue, remove it from the queue.
|
||||
@@ -327,6 +329,7 @@ void VideoCaptureManager::DoStopDevice(VideoCaptureController* controller) {
|
||||
|
||||
void VideoCaptureManager::ProcessDeviceStartRequestQueue() {
|
||||
DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
||||
+ LOG(ERROR) << "ProcessDeviceStartRequestQueue";
|
||||
TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("video_and_image_capture"),
|
||||
"VideoCaptureManager::ProcessDeviceStartRequestQueue");
|
||||
auto request = device_start_request_queue_.begin();
|
||||
@@ -335,7 +338,7 @@ void VideoCaptureManager::ProcessDeviceStartRequestQueue() {
|
||||
|
||||
scoped_refptr<VideoCaptureController> const controller =
|
||||
request->controller();
|
||||
-
|
||||
+ LOG(ERROR) << "ProcessDeviceStartRequestQueue, controller: " << controller->device_id();
|
||||
EmitLogMessage("VideoCaptureManager::ProcessDeviceStartRequestQueue", 3);
|
||||
// The unit test VideoCaptureManagerTest.OpenNotExisting requires us to fail
|
||||
// synchronously if the stream_type is MEDIA_DEVICE_VIDEO_CAPTURE and no
|
||||
@@ -351,6 +354,7 @@ void VideoCaptureManager::ProcessDeviceStartRequestQueue() {
|
||||
const media::VideoCaptureDeviceInfo* device_info =
|
||||
GetDeviceInfoById(controller->device_id());
|
||||
if (!device_info) {
|
||||
+ LOG(ERROR) << "ProcessDeviceStartRequestQueue, device_info not found";
|
||||
OnDeviceLaunchFailed(
|
||||
controller.get(),
|
||||
media::VideoCaptureError::
|
||||
@@ -381,6 +385,7 @@ void VideoCaptureManager::ProcessDeviceStartRequestQueue() {
|
||||
void VideoCaptureManager::OnDeviceLaunched(VideoCaptureController* controller) {
|
||||
DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
||||
std::ostringstream string_stream;
|
||||
+ LOG(ERROR) << "OnDeviceLaunched";
|
||||
string_stream << "Launching device has succeeded. device_id = "
|
||||
<< controller->device_id();
|
||||
EmitLogMessage(string_stream.str(), 1);
|
||||
@@ -391,7 +396,9 @@ void VideoCaptureManager::OnDeviceLaunched(VideoCaptureController* controller) {
|
||||
if (blink::IsVideoDesktopCaptureMediaType(controller->stream_type())) {
|
||||
const media::VideoCaptureSessionId session_id =
|
||||
device_start_request_queue_.front().session_id();
|
||||
+ LOG(ERROR) << "isvideodesktopcapturemediatype";
|
||||
DCHECK_NE(session_id, FakeSessionId());
|
||||
+ LOG(ERROR) << "maybe post desktop capture window id";
|
||||
MaybePostDesktopCaptureWindowId(session_id);
|
||||
}
|
||||
|
||||
@@ -407,7 +414,9 @@ void VideoCaptureManager::OnDeviceLaunched(VideoCaptureController* controller) {
|
||||
}
|
||||
}
|
||||
|
||||
+ LOG(ERROR) << "OnDeviceLaunched, device_start_request_queue_.pop_front";
|
||||
device_start_request_queue_.pop_front();
|
||||
+ LOG(ERROR) << "OnDeviceLaunched, ProcessDeviceStartRequestQueue";
|
||||
ProcessDeviceStartRequestQueue();
|
||||
}
|
||||
|
||||
@@ -467,6 +476,7 @@ void VideoCaptureManager::ConnectClient(
|
||||
DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
||||
TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("video_and_image_capture"),
|
||||
"VideoCaptureManager::ConnectClient");
|
||||
+ LOG(ERROR) << "ConnectClient";
|
||||
{
|
||||
std::ostringstream string_stream;
|
||||
string_stream << "ConnectClient: session_id = " << session_id
|
||||
@@ -479,6 +489,7 @@ void VideoCaptureManager::ConnectClient(
|
||||
scoped_refptr<VideoCaptureController> controller =
|
||||
GetOrCreateController(session_id, params);
|
||||
if (!controller) {
|
||||
+ LOG(ERROR) << "ConnectClient, controller not found";
|
||||
std::move(done_cb).Run(nullptr);
|
||||
return;
|
||||
}
|
||||
@@ -502,6 +513,7 @@ void VideoCaptureManager::ConnectClient(
|
||||
string_stream
|
||||
<< "VideoCaptureManager queueing device start for device_id = "
|
||||
<< controller->device_id();
|
||||
+ LOG(ERROR) << "ConnectClient, videocapturemanager queueing device start for device_id = " << controller->device_id();
|
||||
EmitLogMessage(string_stream.str(), 1);
|
||||
mojo::PendingRemote<video_effects::mojom::VideoEffectsProcessor>
|
||||
video_effects_processor;
|
||||
@@ -524,6 +536,7 @@ void VideoCaptureManager::ConnectClient(
|
||||
readonly_video_effects_manager.InitWithNewPipeAndPassReceiver());
|
||||
}
|
||||
#endif // BUILDFLAG(ENABLE_VIDEO_EFFECTS)
|
||||
+ LOG(ERROR) << "ConnectClient, videocapturemanager queueing device start for device_id = " << controller->device_id();
|
||||
QueueStartDevice(session_id, controller, params,
|
||||
std::move(video_effects_processor),
|
||||
std::move(readonly_video_effects_manager));
|
||||
diff --git a/content/public/browser/desktop_media_id.cc b/content/public/browser/desktop_media_id.cc
|
||||
index b39b684ff84baaf292eef1a23b7f9fb4585023c5..55507f7a782a9472800221f1e908618a5bad2914 100644
|
||||
--- a/content/public/browser/desktop_media_id.cc
|
||||
+++ b/content/public/browser/desktop_media_id.cc
|
||||
@@ -21,6 +21,7 @@ namespace content {
|
||||
|
||||
const char kScreenPrefix[] = "screen";
|
||||
const char kWindowPrefix[] = "window";
|
||||
+const char kNonePrefix[] = "none";
|
||||
|
||||
#if defined(USE_AURA) || BUILDFLAG(IS_MAC)
|
||||
// static
|
||||
@@ -82,6 +83,8 @@ DesktopMediaID DesktopMediaID::Parse(const std::string& str) {
|
||||
type = TYPE_SCREEN;
|
||||
} else if (parts[0] == kWindowPrefix) {
|
||||
type = TYPE_WINDOW;
|
||||
+ } else if (parts[0] == kNonePrefix) {
|
||||
+ type = TYPE_NONE;
|
||||
} else {
|
||||
return DesktopMediaID();
|
||||
}
|
||||
@@ -104,6 +107,8 @@ std::string DesktopMediaID::ToString() const {
|
||||
std::string prefix;
|
||||
switch (type) {
|
||||
case TYPE_NONE:
|
||||
+ prefix = kNonePrefix;
|
||||
+ break;
|
||||
NOTREACHED();
|
||||
case TYPE_SCREEN:
|
||||
prefix = kScreenPrefix;
|
||||
diff --git a/media/base/media_switches.cc b/media/base/media_switches.cc
|
||||
index c458c1e87dc46cf4f92d5c4423ab837f29067aa0..1749fb96bbd0c69ad5c6377eabb4bbab12e3f7c3 100644
|
||||
--- a/media/base/media_switches.cc
|
||||
+++ b/media/base/media_switches.cc
|
||||
@@ -356,7 +356,7 @@ BASE_FEATURE(kMacLoopbackAudioForScreenShare,
|
||||
// is required to avoid recurring permission dialogs.
|
||||
BASE_FEATURE(kUseSCContentSharingPicker,
|
||||
"UseSCContentSharingPicker",
|
||||
- base::FEATURE_DISABLED_BY_DEFAULT);
|
||||
+ base::FEATURE_ENABLED_BY_DEFAULT);
|
||||
#endif // BUILDFLAG(IS_MAC)
|
||||
|
||||
#if BUILDFLAG(IS_LINUX)
|
||||
diff --git a/media/capture/video/file_video_capture_device.cc b/media/capture/video/file_video_capture_device.cc
|
||||
index 5090aae198e4e0e52212eb502bb4de0475c79b04..c74887a14bcc4249e433d2afd545029d36f744bf 100644
|
||||
--- a/media/capture/video/file_video_capture_device.cc
|
||||
+++ b/media/capture/video/file_video_capture_device.cc
|
||||
@@ -482,6 +482,7 @@ void FileVideoCaptureDevice::AllocateAndStart(
|
||||
CHECK(!capture_thread_.IsRunning());
|
||||
|
||||
capture_thread_.Start();
|
||||
+ LOG(ERROR) << "allocate and start file video capture device";
|
||||
capture_thread_.task_runner()->PostTask(
|
||||
FROM_HERE,
|
||||
base::BindOnce(&FileVideoCaptureDevice::OnAllocateAndStart,
|
||||
@@ -604,6 +605,7 @@ void FileVideoCaptureDevice::TakePhoto(TakePhotoCallback callback) {
|
||||
void FileVideoCaptureDevice::OnAllocateAndStart(
|
||||
const VideoCaptureParams& params,
|
||||
std::unique_ptr<VideoCaptureDevice::Client> client) {
|
||||
+ LOG(ERROR) << "on allocate and start file video capture device";
|
||||
DCHECK(capture_thread_.task_runner()->BelongsToCurrentThread());
|
||||
|
||||
client_ = std::move(client);
|
||||
130
patches/chromium/fix_debug_desktop_capturer_picture.patch
Normal file
130
patches/chromium/fix_debug_desktop_capturer_picture.patch
Normal file
@@ -0,0 +1,130 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Keeley Hammond <khammond@slack-corp.com>
|
||||
Date: Tue, 15 Apr 2025 16:34:52 -0700
|
||||
Subject: fix: debug desktop capturer picture
|
||||
|
||||
|
||||
diff --git a/content/browser/media/capture/screen_capture_kit_device_mac.mm b/content/browser/media/capture/screen_capture_kit_device_mac.mm
|
||||
index fef50841f472bf3e76c171d9e106c689157adaae..1e9ffc1e097439eea731e2cff6193c5f50c984d8 100644
|
||||
--- a/content/browser/media/capture/screen_capture_kit_device_mac.mm
|
||||
+++ b/content/browser/media/capture/screen_capture_kit_device_mac.mm
|
||||
@@ -286,6 +286,25 @@ void OnShareableContentCreated(SCShareableContent* content) {
|
||||
}
|
||||
}
|
||||
break;
|
||||
+ case DesktopMediaID::TYPE_NONE:
|
||||
+ for (SCWindow* window in content.windows) {
|
||||
+ LOG(ERROR) << "Inside TYPE_NONE for loop";
|
||||
+ LOG(ERROR) << "source_.id: " << source_.id;
|
||||
+ LOG(ERROR) << "window.windowID: " << window.windowID;
|
||||
+ if (source_.id == window.windowID) {
|
||||
+ LOG(ERROR) << "window.windowID: " << window.windowID;
|
||||
+ filter = [[SCContentFilter alloc]
|
||||
+ initWithDesktopIndependentWindow:window];
|
||||
+ CGRect frame = window.frame;
|
||||
+ stream_config_content_size_ = gfx::Size(frame.size);
|
||||
+ if (!fullscreen_module_) {
|
||||
+ fullscreen_module_ = MaybeCreateScreenCaptureKitFullscreenModule(
|
||||
+ device_task_runner_, *this, window);
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ break;
|
||||
default:
|
||||
NOTREACHED();
|
||||
}
|
||||
diff --git a/content/browser/renderer_host/media/in_process_video_capture_device_launcher.cc b/content/browser/renderer_host/media/in_process_video_capture_device_launcher.cc
|
||||
index 2351919905fbec6c1bfe9ce59d799192a9e2e0e6..aa97cad0ca0fecc8dfc1ee44760ab1d36086785c 100644
|
||||
--- a/content/browser/renderer_host/media/in_process_video_capture_device_launcher.cc
|
||||
+++ b/content/browser/renderer_host/media/in_process_video_capture_device_launcher.cc
|
||||
@@ -104,6 +104,7 @@ void IncrementDesktopCaptureCounters(const DesktopMediaID& device_id) {
|
||||
: SCREEN_CAPTURER_CREATED_WITHOUT_AUDIO);
|
||||
break;
|
||||
case DesktopMediaID::TYPE_WINDOW:
|
||||
+ case DesktopMediaID::TYPE_NONE:
|
||||
IncrementDesktopCaptureCounter(WINDOW_CAPTURER_CREATED);
|
||||
break;
|
||||
case DesktopMediaID::TYPE_WEB_CONTENTS:
|
||||
@@ -112,8 +113,8 @@ void IncrementDesktopCaptureCounters(const DesktopMediaID& device_id) {
|
||||
device_id.audio_share ? TAB_VIDEO_CAPTURER_CREATED_WITH_AUDIO
|
||||
: TAB_VIDEO_CAPTURER_CREATED_WITHOUT_AUDIO);
|
||||
break;
|
||||
- case DesktopMediaID::TYPE_NONE:
|
||||
- NOTREACHED();
|
||||
+ // case DesktopMediaID::TYPE_NONE:
|
||||
+ // NOTREACHED();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -285,13 +286,15 @@ void InProcessVideoCaptureDeviceLauncher::LaunchDeviceAsync(
|
||||
const DesktopMediaID desktop_id = DesktopMediaID::Parse(device_id);
|
||||
LOG(ERROR) << "desktop_id.is_null(): " << desktop_id.is_null();
|
||||
LOG(ERROR) << "desktop_id.id: " << desktop_id.id;
|
||||
- LOG(ERROR) << "DesktopMediaID::kMacOsNativePickerId: " << DesktopMediaID::kMacOsNativePickerId;
|
||||
- if (desktop_id.is_null() && desktop_id.id != DesktopMediaID::kMacOsNativePickerId) {
|
||||
- LOG(ERROR) << "in null case";
|
||||
- start_capture_closure =
|
||||
- base::BindOnce(std::move(after_start_capture_callback), nullptr);
|
||||
- break;
|
||||
- }
|
||||
+ // TODO(Keeley): kMacOsNativePickerId seems to have been removed upstream.
|
||||
+ // Reconcile this with the upstream changes.
|
||||
+ // LOG(ERROR) << "DesktopMediaID::kMacOsNativePickerId: " << DesktopMediaID::kMacOsNativePickerId;
|
||||
+ // if (desktop_id.is_null() && desktop_id.id != DesktopMediaID::kMacOsNativePickerId) {
|
||||
+ // LOG(ERROR) << "in null case";
|
||||
+ // start_capture_closure =
|
||||
+ // base::BindOnce(std::move(after_start_capture_callback), nullptr);
|
||||
+ // break;
|
||||
+ // }
|
||||
|
||||
if (desktop_id.id == DesktopMediaID::kFakeId) {
|
||||
start_capture_closure = base::BindOnce(
|
||||
@@ -329,18 +332,16 @@ void InProcessVideoCaptureDeviceLauncher::LaunchDeviceAsync(
|
||||
#if defined(USE_AURA)
|
||||
bool allow_window_id = false;
|
||||
#elif BUILDFLAG(IS_MAC)
|
||||
-
|
||||
- bool allow_window_id =
|
||||
- desktop_id.id == DesktopMediaID::kMacOsNativePickerId;
|
||||
-
|
||||
- LOG(ERROR) << "allow_window_id: " << allow_window_id << " desktop_id.id: " << desktop_id.id;
|
||||
+ // bool allow_window_id =
|
||||
+ // desktop_id.id == DesktopMediaID::kMacOsNativePickerId;
|
||||
+ // LOG(ERROR) << "allow_window_id: " << allow_window_id << " desktop_id.id: " << desktop_id.id;
|
||||
#endif
|
||||
|
||||
#if defined(USE_AURA) || BUILDFLAG(IS_MAC)
|
||||
- LOG(ERROR) << "in if block";
|
||||
- if (!allow_window_id &&
|
||||
- desktop_id.window_id != DesktopMediaID::kNullId) {
|
||||
- LOG(ERROR) << "allow_window_id: " << allow_window_id << " desktop_id.window_id: " << desktop_id.window_id;
|
||||
+ // if (!allow_window_id &&
|
||||
+ // desktop_id.window_id != DesktopMediaID::kNullId) {
|
||||
+ if (desktop_id.window_id != DesktopMediaID::kNullId) {
|
||||
+ // LOG(ERROR) << "allow_window_id: " << allow_window_id << " desktop_id.window_id: " << desktop_id.window_id;
|
||||
// For the other capturers, when a bug reports the type of capture it's
|
||||
// easy enough to determine which capturer was used, but it's a little
|
||||
// fuzzier with window capture.
|
||||
@@ -525,7 +526,7 @@ void InProcessVideoCaptureDeviceLauncher::DoStartDesktopCaptureOnDeviceThread(
|
||||
ReceiveDeviceCallback result_callback) {
|
||||
DCHECK(device_task_runner_->BelongsToCurrentThread());
|
||||
LOG(INFO) << "DO START DESKTOP CAPTURE ON DEVICE THREAD " << desktop_id.id;
|
||||
- DCHECK(!desktop_id.is_null() || desktop_id.id == DesktopMediaID::kMacOsNativePickerId);
|
||||
+ // DCHECK(!desktop_id.is_null() || desktop_id.id == DesktopMediaID::kMacOsNativePickerId);
|
||||
|
||||
std::unique_ptr<media::VideoCaptureDevice> video_capture_device;
|
||||
DesktopCaptureImplementation implementation =
|
||||
diff --git a/content/browser/renderer_host/media/video_capture_manager.cc b/content/browser/renderer_host/media/video_capture_manager.cc
|
||||
index bd11a0fcdc084da00407c80e4ee229a130fdedc8..74d9ce9facea9cda90073ca6b70e8c4be3b62f6f 100644
|
||||
--- a/content/browser/renderer_host/media/video_capture_manager.cc
|
||||
+++ b/content/browser/renderer_host/media/video_capture_manager.cc
|
||||
@@ -920,6 +920,8 @@ void VideoCaptureManager::DestroyControllerIfNoClients(
|
||||
// closed.
|
||||
CloseNativeScreenCapturePicker(
|
||||
DesktopMediaID::Parse(controller->device_id()));
|
||||
+ LOG(ERROR) << "Closing native screen capture picker";
|
||||
+ LOG(ERROR) << "VideoCaptureManager: " << string_stream.str();
|
||||
|
||||
// The VideoCaptureController is removed from |controllers_| immediately.
|
||||
// The controller is deleted immediately, and the device is freed
|
||||
@@ -9,6 +9,8 @@
|
||||
#include <vector>
|
||||
|
||||
#include "base/containers/flat_map.h"
|
||||
#include "base/logging.h"
|
||||
#include "base/strings/string_number_conversions.h"
|
||||
#include "base/strings/utf_string_conversions.h"
|
||||
#include "base/threading/thread_restrictions.h"
|
||||
#include "chrome/browser/media/webrtc/desktop_capturer_wrapper.h"
|
||||
@@ -18,6 +20,7 @@
|
||||
#include "content/public/browser/desktop_capture.h"
|
||||
#include "gin/handle.h"
|
||||
#include "gin/object_template_builder.h"
|
||||
#include "media/base/media_switches.h"
|
||||
#include "shell/browser/javascript_environment.h"
|
||||
#include "shell/common/api/electron_api_native_image.h"
|
||||
#include "shell/common/gin_converters/gfx_converter.h"
|
||||
@@ -143,6 +146,21 @@ base::flat_map<int32_t, uint32_t> MonitorAtomIdToDisplayId() {
|
||||
}
|
||||
#endif
|
||||
|
||||
std::unique_ptr<ThumbnailCapturer> MakeScreenAndWindowCapturer() {
|
||||
#if BUILDFLAG(IS_MAC)
|
||||
if (ShouldUseThumbnailCapturerMac(DesktopMediaList::Type::kNone)) {
|
||||
LOG(ERROR) << "creating thumbnail capturer, knone *****";
|
||||
return CreateThumbnailCapturerMac(DesktopMediaList::Type::kNone);
|
||||
}
|
||||
#endif // BUILDFLAG(IS_MAC)
|
||||
LOG(ERROR) << "should not hit this *****";
|
||||
std::unique_ptr<webrtc::DesktopCapturer> window_capturer =
|
||||
content::desktop_capture::CreateWindowCapturer();
|
||||
return window_capturer ? std::make_unique<DesktopCapturerWrapper>(
|
||||
std::move(window_capturer))
|
||||
: nullptr;
|
||||
}
|
||||
|
||||
std::unique_ptr<ThumbnailCapturer> MakeWindowCapturer() {
|
||||
#if BUILDFLAG(IS_MAC)
|
||||
if (ShouldUseThumbnailCapturerMac(DesktopMediaList::Type::kWindow)) {
|
||||
@@ -258,7 +276,8 @@ void DesktopCapturer::DesktopListListener::OnDelegatedSourceListDismissed() {
|
||||
void DesktopCapturer::StartHandling(bool capture_window,
|
||||
bool capture_screen,
|
||||
const gfx::Size& thumbnail_size,
|
||||
bool fetch_window_icons) {
|
||||
bool fetch_window_icons,
|
||||
bool use_system_picker) {
|
||||
fetch_window_icons_ = fetch_window_icons;
|
||||
#if BUILDFLAG(IS_WIN)
|
||||
if (content::desktop_capture::CreateDesktopCaptureOptions()
|
||||
@@ -272,35 +291,76 @@ void DesktopCapturer::StartHandling(bool capture_window,
|
||||
|
||||
// clear any existing captured sources.
|
||||
captured_sources_.clear();
|
||||
|
||||
LOG(ERROR) << "capture_window: " << capture_window << " capture_screen: " << capture_screen;
|
||||
if (capture_window && capture_screen) {
|
||||
// Some capturers like PipeWire support a single capturer for both screens
|
||||
// and windows. Use it if possible, treating both as window capture
|
||||
std::unique_ptr<webrtc::DesktopCapturer> desktop_capturer =
|
||||
webrtc::DesktopCapturer::CreateGenericCapturer(
|
||||
content::desktop_capture::CreateDesktopCaptureOptions());
|
||||
auto capturer = desktop_capturer ? std::make_unique<DesktopCapturerWrapper>(
|
||||
std::move(desktop_capturer))
|
||||
: nullptr;
|
||||
if (capturer && capturer->GetDelegatedSourceListController()) {
|
||||
capture_screen_ = false;
|
||||
if (IsDisplayMediaSystemPickerAvailable()) {
|
||||
auto capturer = MakeScreenAndWindowCapturer();
|
||||
capture_screen_ = capture_screen;
|
||||
capture_window_ = capture_window;
|
||||
window_capturer_ = std::make_unique<NativeDesktopMediaList>(
|
||||
DesktopMediaList::Type::kWindow, std::move(capturer), true, true);
|
||||
window_capturer_->SetThumbnailSize(thumbnail_size);
|
||||
// TODO(review): Maybe just call this a capturer
|
||||
screen_capturer_ = std::make_unique<NativeDesktopMediaList>(
|
||||
DesktopMediaList::Type::kNone, std::move(capturer), true, true);
|
||||
screen_capturer_->SetThumbnailSize(thumbnail_size);
|
||||
screen_capturer_->ShowDelegatedList();
|
||||
#if BUILDFLAG(IS_MAC)
|
||||
screen_capturer_->skip_next_refresh_ =
|
||||
ShouldUseThumbnailCapturerMac(DesktopMediaList::Type::kNone) ? 2 : 0;
|
||||
LOG(ERROR) << "SET SKIP NEXT REFRESH TO 2";
|
||||
#endif
|
||||
|
||||
LOG(ERROR) << "screen_capturer_->skip_next_refresh_ " << screen_capturer_->skip_next_refresh_;
|
||||
OnceCallback update_callback = base::BindOnce(
|
||||
&DesktopCapturer::UpdateSourcesList, weak_ptr_factory_.GetWeakPtr(),
|
||||
window_capturer_.get());
|
||||
OnceCallback failure_callback = base::BindOnce(
|
||||
&DesktopCapturer::HandleFailure, weak_ptr_factory_.GetWeakPtr());
|
||||
screen_capturer_.get());
|
||||
|
||||
window_listener_ = std::make_unique<DesktopListListener>(
|
||||
std::move(update_callback), std::move(failure_callback),
|
||||
thumbnail_size.IsEmpty());
|
||||
window_capturer_->StartUpdating(window_listener_.get());
|
||||
// Needed to force a refresh for the native MacOS Picker
|
||||
OnceCallback wrapped_update_callback = base::BindOnce(
|
||||
&DesktopCapturer::RequestUpdate, weak_ptr_factory_.GetWeakPtr(),
|
||||
screen_capturer_.get(), std::move(update_callback));
|
||||
|
||||
if (screen_capturer_->IsSourceListDelegated()) {
|
||||
OnceCallback failure_callback = base::BindOnce(
|
||||
&DesktopCapturer::HandleFailure, weak_ptr_factory_.GetWeakPtr());
|
||||
screen_listener_ = std::make_unique<DesktopListListener>(
|
||||
std::move(wrapped_update_callback), std::move(failure_callback),
|
||||
thumbnail_size.IsEmpty());
|
||||
screen_capturer_->StartUpdating(screen_listener_.get());
|
||||
} else {
|
||||
screen_capturer_->Update(std::move(update_callback),
|
||||
/* refresh_thumbnails = */ true);
|
||||
}
|
||||
|
||||
return;
|
||||
} else {
|
||||
// Some capturers like PipeWire support a single capturer for both screens
|
||||
// and windows. Use it if possible, treating both as window capture
|
||||
std::unique_ptr<webrtc::DesktopCapturer> desktop_capturer =
|
||||
webrtc::DesktopCapturer::CreateGenericCapturer(
|
||||
content::desktop_capture::CreateDesktopCaptureOptions());
|
||||
auto capturer = desktop_capturer
|
||||
? std::make_unique<DesktopCapturerWrapper>(
|
||||
std::move(desktop_capturer))
|
||||
: nullptr;
|
||||
if (capturer && capturer->GetDelegatedSourceListController()) {
|
||||
capture_screen_ = false;
|
||||
capture_window_ = capture_window;
|
||||
window_capturer_ = std::make_unique<NativeDesktopMediaList>(
|
||||
DesktopMediaList::Type::kWindow, std::move(capturer));
|
||||
window_capturer_->SetThumbnailSize(thumbnail_size);
|
||||
|
||||
OnceCallback update_callback = base::BindOnce(
|
||||
&DesktopCapturer::UpdateSourcesList, weak_ptr_factory_.GetWeakPtr(),
|
||||
window_capturer_.get());
|
||||
OnceCallback failure_callback = base::BindOnce(
|
||||
&DesktopCapturer::HandleFailure, weak_ptr_factory_.GetWeakPtr());
|
||||
|
||||
window_listener_ = std::make_unique<DesktopListListener>(
|
||||
std::move(update_callback), std::move(failure_callback),
|
||||
thumbnail_size.IsEmpty());
|
||||
window_capturer_->StartUpdating(window_listener_.get());
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -319,21 +379,30 @@ void DesktopCapturer::StartHandling(bool capture_window,
|
||||
// Initialize the source list.
|
||||
// Apply the new thumbnail size and restart capture.
|
||||
if (capture_window) {
|
||||
LOG(ERROR) << "WE SHOULDNT BE HERE *****";
|
||||
auto capturer = MakeWindowCapturer();
|
||||
if (capturer) {
|
||||
window_capturer_ = std::make_unique<NativeDesktopMediaList>(
|
||||
DesktopMediaList::Type::kWindow, std::move(capturer), true, true);
|
||||
window_capturer_->SetThumbnailSize(thumbnail_size);
|
||||
#if BUILDFLAG(IS_MAC)
|
||||
window_capturer_->skip_next_refresh_ =
|
||||
ShouldUseThumbnailCapturerMac(DesktopMediaList::Type::kWindow) ? 2
|
||||
: 0;
|
||||
#endif
|
||||
|
||||
OnceCallback update_callback = base::BindOnce(
|
||||
&DesktopCapturer::UpdateSourcesList, weak_ptr_factory_.GetWeakPtr(),
|
||||
window_capturer_.get());
|
||||
|
||||
#if BUILDFLAG(IS_MAC)
|
||||
window_capturer_->skip_next_refresh_ =
|
||||
ShouldUseThumbnailCapturerMac(DesktopMediaList::Type::kWindow) ? 2
|
||||
: 0;
|
||||
|
||||
if (base::FeatureList::IsEnabled(media::kUseSCContentSharingPicker)) {
|
||||
window_capturer_->ShowDelegatedList();
|
||||
// Needed to force a refresh for the native MacOS Picker
|
||||
update_callback = base::BindOnce(
|
||||
&DesktopCapturer::RequestUpdate, weak_ptr_factory_.GetWeakPtr(),
|
||||
window_capturer_.get(), std::move(update_callback));
|
||||
}
|
||||
#endif
|
||||
if (window_capturer_->IsSourceListDelegated()) {
|
||||
OnceCallback failure_callback = base::BindOnce(
|
||||
&DesktopCapturer::HandleFailure, weak_ptr_factory_.GetWeakPtr());
|
||||
@@ -354,16 +423,25 @@ void DesktopCapturer::StartHandling(bool capture_window,
|
||||
screen_capturer_ = std::make_unique<NativeDesktopMediaList>(
|
||||
DesktopMediaList::Type::kScreen, std::move(capturer));
|
||||
screen_capturer_->SetThumbnailSize(thumbnail_size);
|
||||
#if BUILDFLAG(IS_MAC)
|
||||
screen_capturer_->skip_next_refresh_ =
|
||||
ShouldUseThumbnailCapturerMac(DesktopMediaList::Type::kScreen) ? 2
|
||||
: 0;
|
||||
#endif
|
||||
|
||||
OnceCallback update_callback = base::BindOnce(
|
||||
&DesktopCapturer::UpdateSourcesList, weak_ptr_factory_.GetWeakPtr(),
|
||||
screen_capturer_.get());
|
||||
|
||||
#if BUILDFLAG(IS_MAC)
|
||||
screen_capturer_->skip_next_refresh_ =
|
||||
ShouldUseThumbnailCapturerMac(DesktopMediaList::Type::kScreen) ? 2
|
||||
: 0;
|
||||
|
||||
if (base::FeatureList::IsEnabled(media::kUseSCContentSharingPicker)) {
|
||||
screen_capturer_->ShowDelegatedList();
|
||||
// Needed to force a refresh for the native MacOS Picker
|
||||
update_callback = base::BindOnce(
|
||||
&DesktopCapturer::RequestUpdate, weak_ptr_factory_.GetWeakPtr(),
|
||||
screen_capturer_.get(), std::move(update_callback));
|
||||
}
|
||||
#endif
|
||||
|
||||
if (screen_capturer_->IsSourceListDelegated()) {
|
||||
OnceCallback failure_callback = base::BindOnce(
|
||||
&DesktopCapturer::HandleFailure, weak_ptr_factory_.GetWeakPtr());
|
||||
@@ -380,9 +458,15 @@ void DesktopCapturer::StartHandling(bool capture_window,
|
||||
}
|
||||
}
|
||||
|
||||
void DesktopCapturer::RequestUpdate(DesktopMediaList* list,
|
||||
OnceCallback update_callback) {
|
||||
list->Update(std::move(update_callback));
|
||||
}
|
||||
|
||||
void DesktopCapturer::UpdateSourcesList(DesktopMediaList* list) {
|
||||
if (capture_window_ &&
|
||||
list->GetMediaListType() == DesktopMediaList::Type::kWindow) {
|
||||
(list->GetMediaListType() == DesktopMediaList::Type::kWindow ||
|
||||
list->GetMediaListType() == DesktopMediaList::Type::kNone)) {
|
||||
capture_window_ = false;
|
||||
std::vector<DesktopCapturer::Source> window_sources;
|
||||
window_sources.reserve(list->GetSourceCount());
|
||||
@@ -395,7 +479,8 @@ void DesktopCapturer::UpdateSourcesList(DesktopMediaList* list) {
|
||||
}
|
||||
|
||||
if (capture_screen_ &&
|
||||
list->GetMediaListType() == DesktopMediaList::Type::kScreen) {
|
||||
(list->GetMediaListType() == DesktopMediaList::Type::kScreen ||
|
||||
list->GetMediaListType() == DesktopMediaList::Type::kNone)) {
|
||||
capture_screen_ = false;
|
||||
std::vector<DesktopCapturer::Source> screen_sources;
|
||||
screen_sources.reserve(list->GetSourceCount());
|
||||
@@ -465,7 +550,6 @@ void DesktopCapturer::UpdateSourcesList(DesktopMediaList* list) {
|
||||
std::move(screen_sources.begin(), screen_sources.end(),
|
||||
std::back_inserter(captured_sources_));
|
||||
}
|
||||
|
||||
if (!capture_window_ && !capture_screen_)
|
||||
HandleSuccess();
|
||||
}
|
||||
|
||||
@@ -41,7 +41,8 @@ class DesktopCapturer final : public gin::Wrappable<DesktopCapturer>,
|
||||
void StartHandling(bool capture_window,
|
||||
bool capture_screen,
|
||||
const gfx::Size& thumbnail_size,
|
||||
bool fetch_window_icons);
|
||||
bool fetch_window_icons,
|
||||
bool use_system_picker);
|
||||
|
||||
// gin::Wrappable
|
||||
static gin::WrapperInfo kWrapperInfo;
|
||||
@@ -94,6 +95,7 @@ class DesktopCapturer final : public gin::Wrappable<DesktopCapturer>,
|
||||
bool have_thumbnail_ = false;
|
||||
};
|
||||
|
||||
void RequestUpdate(DesktopMediaList* list, OnceCallback update_callback);
|
||||
void UpdateSourcesList(DesktopMediaList* list);
|
||||
void HandleFailure();
|
||||
void HandleSuccess();
|
||||
|
||||
@@ -26,6 +26,27 @@ std::string EnablePlatformSpecificFeatures() {
|
||||
#else
|
||||
return "ScreenCaptureKitPickerScreen,ScreenCaptureKitStreamPickerSonoma,"
|
||||
"ThumbnailCapturerMac:capture_mode/sc_screenshot_manager";
|
||||
#endif
|
||||
}
|
||||
if (@available(macOS 15.0, *)) {
|
||||
// These flags aren't exported so reference them by name directly, they are
|
||||
// used to ensure that screen and window capture exclusive use
|
||||
// ScreenCaptureKit APIs to avoid warning dialogs on macOS 15.0 and higher.
|
||||
// kScreenCaptureKitPickerScreen,
|
||||
// chrome/browser/media/webrtc/thumbnail_capturer_mac.mm
|
||||
// kScreenCaptureKitStreamPickerSonoma,
|
||||
// chrome/browser/media/webrtc/thumbnail_capturer_mac.mm
|
||||
// kThumbnailCapturerMac,
|
||||
// chrome/browser/media/webrtc/thumbnail_capturer_mac.mm
|
||||
// kUseSCContentSharingPicker,
|
||||
// chrome/browser/media/webrtc/thumbnail_capturer_mac.mm
|
||||
#if DCHECK_IS_ON()
|
||||
return "ScreenCaptureKitPickerScreen,ScreenCaptureKitStreamPickerSonoma,"
|
||||
"UseSCContentSharingPicker";
|
||||
#else
|
||||
return "ScreenCaptureKitPickerScreen,ScreenCaptureKitStreamPickerSonoma,"
|
||||
"UseSCContentSharingPicker,"
|
||||
"ThumbnailCapturerMac:capture_mode/sc_screenshot_manager";
|
||||
#endif
|
||||
}
|
||||
return "";
|
||||
|
||||
30
shell/common/gin_converters/display_surface_converter.cc
Normal file
30
shell/common/gin_converters/display_surface_converter.cc
Normal file
@@ -0,0 +1,30 @@
|
||||
// Copyright (c) 2021 Slack Technologies, LLC.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "shell/common/gin_converters/display_surface_converter.h"
|
||||
|
||||
#include "content/public/browser/media_stream_request.h"
|
||||
#include "gin/data_object_builder.h"
|
||||
#include "shell/common/gin_converters/frame_converter.h"
|
||||
#include "shell/common/gin_converters/gurl_converter.h"
|
||||
#include "third_party/blink/public/mojom/mediastream/media_stream.mojom.h"
|
||||
|
||||
namespace gin {
|
||||
|
||||
v8::Local<v8::Value> Converter<blink::mojom::PreferredDisplaySurface>::ToV8(
|
||||
v8::Isolate* isolate,
|
||||
blink::mojom::PreferredDisplaySurface type) {
|
||||
switch (type) {
|
||||
case blink::mojom::PreferredDisplaySurface::NO_PREFERENCE:
|
||||
return StringToV8(isolate, "no_preference");
|
||||
case blink::mojom::PreferredDisplaySurface::MONITOR:
|
||||
return StringToV8(isolate, "monitor");
|
||||
case blink::mojom::PreferredDisplaySurface::WINDOW:
|
||||
return StringToV8(isolate, "window");
|
||||
default:
|
||||
return StringToV8(isolate, "unknown");
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace gin
|
||||
36
shell/common/gin_converters/display_surface_converter.h
Normal file
36
shell/common/gin_converters/display_surface_converter.h
Normal file
@@ -0,0 +1,36 @@
|
||||
// Copyright (c) 2024 Slack, Inc.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef ELECTRON_SHELL_BROWSER_API_DISPLAY_SOURCE_CONVERTER_H_
|
||||
#define ELECTRON_SHELL_BROWSER_API_DISPLAY_SOURCE_CONVERTER_H_
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "gin/converter.h"
|
||||
#include "third_party/blink/public/mojom/mediastream/media_stream.mojom.h"
|
||||
|
||||
namespace electron {
|
||||
|
||||
// cf:
|
||||
// Chrome also allows browser here, but Electron does not.
|
||||
enum PreferredDisplaySurface {
|
||||
NO_PREFERENCE,
|
||||
MONITOR,
|
||||
WINDOW,
|
||||
};
|
||||
|
||||
} // namespace electron
|
||||
|
||||
namespace gin {
|
||||
|
||||
template <>
|
||||
struct Converter<blink::mojom::PreferredDisplaySurface> {
|
||||
static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
|
||||
blink::mojom::PreferredDisplaySurface val);
|
||||
};
|
||||
|
||||
} // namespace gin
|
||||
|
||||
#endif // ELECTRON_SHELL_BROWSER_DISPLAY_SOURCE_CONVERTER_H_
|
||||
@@ -7,6 +7,7 @@
|
||||
#include "content/public/browser/media_stream_request.h"
|
||||
#include "content/public/browser/render_frame_host.h"
|
||||
#include "gin/data_object_builder.h"
|
||||
#include "shell/common/gin_converters/display_surface_converter.h"
|
||||
#include "shell/common/gin_converters/frame_converter.h"
|
||||
#include "shell/common/gin_converters/gurl_converter.h"
|
||||
#include "third_party/blink/public/mojom/mediastream/media_stream.mojom.h"
|
||||
@@ -22,6 +23,7 @@ v8::Local<v8::Value> Converter<content::MediaStreamRequest>::ToV8(
|
||||
.Set("frame", rfh)
|
||||
.Set("securityOrigin", request.security_origin)
|
||||
.Set("userGesture", request.user_gesture)
|
||||
.Set("preferredDisplaySurface", request.preferred_display_surface)
|
||||
.Set("videoRequested",
|
||||
request.video_type != blink::mojom::MediaStreamType::NO_SERVICE)
|
||||
.Set("audioRequested",
|
||||
|
||||
6
typings/internal-electron.d.ts
vendored
6
typings/internal-electron.d.ts
vendored
@@ -149,6 +149,10 @@ declare namespace Electron {
|
||||
_setDisplayMediaRequestHandler: Electron.Session['setDisplayMediaRequestHandler'];
|
||||
}
|
||||
|
||||
interface DisplayMediaRequestHandlerOpts {
|
||||
userSystemPicker: boolean,
|
||||
}
|
||||
|
||||
type CreateWindowFunction = (options: BrowserWindowConstructorOptions) => WebContents;
|
||||
|
||||
interface Menu {
|
||||
@@ -262,7 +266,7 @@ declare namespace Electron {
|
||||
|
||||
declare namespace ElectronInternal {
|
||||
interface DesktopCapturer {
|
||||
startHandling(captureWindow: boolean, captureScreen: boolean, thumbnailSize: Electron.Size, fetchWindowIcons: boolean): void;
|
||||
startHandling(captureWindow: boolean, captureScreen: boolean, thumbnailSize: Electron.Size, fetchWindowIcons: boolean, useSystemPicker: boolean): void;
|
||||
_onerror?: (error: string) => void;
|
||||
_onfinished?: (sources: Electron.DesktopCapturerSource[], fetchWindowIcons: boolean) => void;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user