From ffc1271f9224ba09ff353709573f83e67d2aa5cc Mon Sep 17 00:00:00 2001 From: Athul Iddya Date: Sat, 15 Jul 2023 09:33:19 -0700 Subject: [PATCH] fix: use generic capturer to list both screens and windows when possible Screensharing with PipeWire via XDG Desktop Portal requires explicit user permission via permission dialogs. Chromium has separate tabs for screens and windows and thus its portal implementation requests permissions separately for each. However, the screencast portal has no such limitation and supports both screens and windows in a single request. WebRTC now supports this type of capture in a new method called called `CreateGenericCapturer`. The `desktopCapturer` implementation has been modified to use it. Additionally, Chromium has been patched to use same generic capturer to ensure that the source IDs remain valid for `getUserMedia`. --- patches/chromium/.patches | 1 + ...ated_generic_capturer_when_available.patch | 54 +++++++++++++++++++ .../api/electron_api_desktop_capturer.cc | 27 ++++++++++ 3 files changed, 82 insertions(+) create mode 100644 patches/chromium/fix_use_delegated_generic_capturer_when_available.patch diff --git a/patches/chromium/.patches b/patches/chromium/.patches index 72c5e85befd87..767054b15cde0 100644 --- a/patches/chromium/.patches +++ b/patches/chromium/.patches @@ -131,3 +131,4 @@ fix_select_the_first_menu_item_when_opened_via_keyboard.patch fix_return_v8_value_from_localframe_requestexecutescript.patch fix_harden_blink_scriptstate_maybefrom.patch chore_add_buildflag_guard_around_new_include.patch +fix_use_delegated_generic_capturer_when_available.patch diff --git a/patches/chromium/fix_use_delegated_generic_capturer_when_available.patch b/patches/chromium/fix_use_delegated_generic_capturer_when_available.patch new file mode 100644 index 0000000000000..79099b2382878 --- /dev/null +++ b/patches/chromium/fix_use_delegated_generic_capturer_when_available.patch @@ -0,0 +1,54 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Athul Iddya +Date: Fri, 14 Jul 2023 08:03:37 -0700 +Subject: fix: use delegated generic capturer when available + +When the generic capturer is used to fetch capture sources, the returned +ID will be arbitrarily prefixed with "screen" or "window" regardless of +the source type. If the window capturer is used to stream video when the +source was a screen or vice-versa, the stream fails to restart in +delegated capturers like PipeWire. + +To fix this, use the generic capturer to fetch the media stream if it's +delegated and available. This does not cause any issues if the original +capturer was window or screen-specific, as the IDs remain valid for +generic capturer as well. + +diff --git a/content/browser/media/capture/desktop_capture_device.cc b/content/browser/media/capture/desktop_capture_device.cc +index b0c4efdd8a6401e09520bdfa96221e5addcfd829..f5b7447938f70dd4623a60fa6a856775b627f3d6 100644 +--- a/content/browser/media/capture/desktop_capture_device.cc ++++ b/content/browser/media/capture/desktop_capture_device.cc +@@ -794,8 +794,14 @@ std::unique_ptr DesktopCaptureDevice::Create( + DesktopCapturerLacros::CaptureType::kScreen, + webrtc::DesktopCaptureOptions()); + #else +- std::unique_ptr screen_capturer( +- webrtc::DesktopCapturer::CreateScreenCapturer(options)); ++ std::unique_ptr screen_capturer; ++ if (auto generic_capturer = ++ webrtc::DesktopCapturer::CreateGenericCapturer(options); ++ generic_capturer && generic_capturer->GetDelegatedSourceListController()) { ++ screen_capturer = std::move(generic_capturer); ++ } else { ++ screen_capturer = webrtc::DesktopCapturer::CreateScreenCapturer(options); ++ } + #endif + if (screen_capturer && screen_capturer->SelectSource(source.id)) { + capturer = std::make_unique( +@@ -814,8 +820,14 @@ std::unique_ptr DesktopCaptureDevice::Create( + new DesktopCapturerLacros(DesktopCapturerLacros::CaptureType::kWindow, + webrtc::DesktopCaptureOptions())); + #else +- std::unique_ptr window_capturer = +- webrtc::DesktopCapturer::CreateWindowCapturer(options); ++ std::unique_ptr window_capturer; ++ if (auto generic_capturer = ++ webrtc::DesktopCapturer::CreateGenericCapturer(options); ++ generic_capturer && generic_capturer->GetDelegatedSourceListController()) { ++ window_capturer = std::move(generic_capturer); ++ } else { ++ window_capturer = webrtc::DesktopCapturer::CreateWindowCapturer(options); ++ } + #endif + if (window_capturer && window_capturer->SelectSource(source.id)) { + capturer = std::make_unique( diff --git a/shell/browser/api/electron_api_desktop_capturer.cc b/shell/browser/api/electron_api_desktop_capturer.cc index 1e908db7c87c8..5cfe0fedb9ef3 100644 --- a/shell/browser/api/electron_api_desktop_capturer.cc +++ b/shell/browser/api/electron_api_desktop_capturer.cc @@ -234,6 +234,33 @@ void DesktopCapturer::StartHandling(bool capture_window, // clear any existing captured sources. captured_sources_.clear(); + if (capture_window && capture_screen) { + // Some capturers like PipeWire suppport a single capturer for both screens + // and windows. Use it if possible, treating both as window capture + if (auto capturer = webrtc::DesktopCapturer::CreateGenericCapturer( + content::desktop_capture::CreateDesktopCaptureOptions()); + capturer && capturer->GetDelegatedSourceListController()) { + capture_screen_ = false; + capture_window_ = capture_window; + window_capturer_ = std::make_unique( + 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( + std::move(update_callback), std::move(failure_callback), + thumbnail_size.IsEmpty()); + window_capturer_->StartUpdating(window_listener_.get()); + + return; + } + } + // Start listening for captured sources. capture_window_ = capture_window; capture_screen_ = capture_screen;