Compare commits

...

26 Commits

Author SHA1 Message Date
George Xu
e364a20ba1 intense debug session with not many results... 2025-04-09 17:40:57 -07:00
George Xu
6b6ef0b9ef chore: update patch: 2025-03-28 15:29:14 -07:00
George Xu
bb092132be kick ci 2025-03-19 14:32:44 -07:00
George Xu
0cdf1012bb remove old patch and lint 2025-03-19 14:32:44 -07:00
George Xu
eaa952361c wrap macos code in buildflag 2025-03-19 14:32:44 -07:00
George Xu
8ef66cade3 remove log statements 2025-03-19 14:32:43 -07:00
George Xu
2fb1bfec42 cleaning up 2025-03-19 14:32:43 -07:00
George Xu
65864f6203 test 2025-03-19 14:32:43 -07:00
George Xu
75eb7aabd6 add more logging 2025-03-19 14:32:43 -07:00
George Xu
f8aae32c6c some linting and fixing 2025-03-19 14:32:43 -07:00
George Xu
3e6834099e make things work with type none 2025-03-19 14:32:43 -07:00
George Xu
3d5d5f5cb0 happy path share window: 2025-03-19 14:32:43 -07:00
George Xu
3268c6ba76 new changes 2025-03-19 14:32:43 -07:00
George Xu
50f96692df add more logging, picker works on macos 2025-03-19 14:32:43 -07:00
George Xu
53a7802e95 update patches 2025-03-19 14:32:43 -07:00
George Xu
b6c4c727d1 UNDO ME- onpush for ci 2025-03-19 14:32:43 -07:00
Keeley Hammond
4aa9773388 feat: allow screen or window to return depending on preferredDisplaySurface set 2025-03-19 14:32:43 -07:00
Keeley Hammond
7b6b5bf224 chore: skip skip_refresh_callback if ShouldUseSCContentSharingPicker is false 2025-03-19 14:32:43 -07:00
Keeley Hammond
bd1ed17c02 feat: modify API to use useSystemPicker option 2025-03-19 14:32:43 -07:00
Keeley Hammond
813fc3af58 docs: add documentation 2025-03-19 14:32:43 -07:00
Keeley Hammond
e7675a1a1c chore: remove OnSourceAdded (re-add in the future) 2025-03-19 14:32:43 -07:00
Keeley Hammond
729ca429b8 feat: add getNativePickerSource() API option 2025-03-19 14:32:43 -07:00
Keeley Hammond
da56809b62 fix: make capturer work on both screens and windows 2025-03-19 14:32:43 -07:00
Keeley Hammond
12ca8b30be fix: make window capturer work, still issue with first refresh 2025-03-19 14:32:43 -07:00
Keeley Hammond
56d4433e46 feat: use upstream MacOS SCContentSharingPicker implementation pt. 1 2025-03-19 14:32:43 -07:00
Keeley Hammond
0ee7150832 feat: partially implement IsDisplayMediaSystemPickerAvailable 2025-03-19 14:32:43 -07:00
15 changed files with 1027 additions and 62 deletions

View File

@@ -30,7 +30,7 @@ on:
required: false
push:
branches:
- main
- sckp-macos15
- '[1-9][0-9]-x-y'
pull_request:

View File

@@ -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.

View File

@@ -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)

View File

@@ -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",

View File

@@ -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({

View File

@@ -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);
};

View File

@@ -143,3 +143,4 @@ 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

View File

@@ -0,0 +1,733 @@
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 0e4a68f2fd8179640f877cb258b4049610fd49da..0fb8d036b7696e5303fbcd463114114aa3227a08 100644
--- a/content/browser/media/capture/screen_capture_kit_device_mac.mm
+++ b/content/browser/media/capture/screen_capture_kit_device_mac.mm
@@ -364,6 +364,7 @@ void OnShareableContentCreated(SCShareableContent* content) {
if (!fullscreen_module_) {
fullscreen_module_ = MaybeCreateScreenCaptureKitFullscreenModule(
device_task_runner_, *this, window);
+ break;
}
}
}
@@ -728,6 +729,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 f0f08a834f06c7669da6030640434308a5cbd056..a34dcdbad1c3d32de59a1574de485bd831599aa1 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;
@@ -319,13 +329,18 @@ 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;
#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;
// 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.
@@ -354,6 +369,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)
@@ -368,6 +384,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
}
@@ -418,9 +435,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(
@@ -439,13 +458,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();
@@ -505,7 +526,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 =
@@ -514,8 +536,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);

View File

@@ -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();
}

View File

@@ -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();

View File

@@ -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 "";

View 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

View 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_

View File

@@ -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",

View File

@@ -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;
}