fix: use generic capturer to list both screens and windows when possible (#39111)

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`.
This commit is contained in:
Athul Iddya 2023-07-21 16:03:01 -07:00 committed by GitHub
parent a83f9c06d7
commit 9cd5de7588
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 82 additions and 0 deletions

View file

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

View file

@ -0,0 +1,54 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Athul Iddya <athul@iddya.com>
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<media::VideoCaptureDevice> DesktopCaptureDevice::Create(
DesktopCapturerLacros::CaptureType::kScreen,
webrtc::DesktopCaptureOptions());
#else
- std::unique_ptr<webrtc::DesktopCapturer> screen_capturer(
- webrtc::DesktopCapturer::CreateScreenCapturer(options));
+ std::unique_ptr<webrtc::DesktopCapturer> 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<webrtc::DesktopAndCursorComposer>(
@@ -814,8 +820,14 @@ std::unique_ptr<media::VideoCaptureDevice> DesktopCaptureDevice::Create(
new DesktopCapturerLacros(DesktopCapturerLacros::CaptureType::kWindow,
webrtc::DesktopCaptureOptions()));
#else
- std::unique_ptr<webrtc::DesktopCapturer> window_capturer =
- webrtc::DesktopCapturer::CreateWindowCapturer(options);
+ std::unique_ptr<webrtc::DesktopCapturer> 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<webrtc::DesktopAndCursorComposer>(

View file

@ -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<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;
}
}
// Start listening for captured sources.
capture_window_ = capture_window;
capture_screen_ = capture_screen;