Skip to content

Commit

Permalink
Improve screen sharing with PipeWire on Wayland
Browse files Browse the repository at this point in the history
Currently, sharing a screen or a window on Wayland opens unnecessary
preview dialog on Chromium side, which is then followed by a similar
dialog on xdg-desktop-portal side. The Chromium dialog is useless on
Wayland, as it doesn't show anything. This is because Chromium doesn't
have access to screen content as in case of X11 session. To fix this, we
want to avoid showing the preview dialog in case we find that we run on
Wayland and only pick a screen or a window from the dialog that comes
from xdg-desktop-portal.

This patch splits BaseCapturerPipeWire class, moving portal related code
into XdgPortalBase, which does all the DBus communication and which is
supposed to be reused by BaseCapturerPipeWire when the user confirms
the dialog from xdg-desktop-portal. The XdgPortalBase is extended to
support multiple calls at once, where each call is identified by Id.

Relevant change on Chromium side will be in a different review.

Bug: chromium:682122
Change-Id: If8afd36da66231eb154cdc00114908ac897ee4cf
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/160649
Commit-Queue: Tommi <[email protected]>
Reviewed-by: Tommi <[email protected]>
Reviewed-by: Erik Språng <[email protected]>
Cr-Commit-Position: refs/heads/master@{#32342}
  • Loading branch information
grulja authored and Commit Bot committed Oct 7, 2020
1 parent ff9f646 commit 9b87037
Show file tree
Hide file tree
Showing 16 changed files with 1,818 additions and 1,075 deletions.
39 changes: 35 additions & 4 deletions modules/desktop_capture/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,21 @@ if (rtc_include_tests) {
"window_finder_unittest.cc",
]
public_configs = [ ":x11_config" ]
if (is_linux) {
public_configs += [ ":pipewire_config" ]
if (rtc_use_pipewire) {
configs += [
":pipewire_config",
":gio",
]

if (rtc_link_pipewire) {
configs += [ ":pipewire" ]
} else {
deps += [ ":pipewire_stubs" ]
}
}
}
if (is_win) {
deps += [ "../../rtc_base:win32" ]
}
Expand Down Expand Up @@ -132,6 +147,21 @@ if (rtc_include_tests) {
}
deps += [ ":desktop_capture_mock" ]
public_configs = [ ":x11_config" ]
if (is_linux) {
public_configs += [ ":pipewire_config" ]
if (rtc_use_pipewire) {
configs += [
":pipewire_config",
":gio",
]

if (rtc_link_pipewire) {
configs += [ ":pipewire" ]
} else {
deps += [ ":pipewire_stubs" ]
}
}
}
}
}

Expand Down Expand Up @@ -496,6 +526,7 @@ rtc_library("desktop_capture_generic") {
absl_deps = [
"//third_party/abseil-cpp/absl/memory",
"//third_party/abseil-cpp/absl/strings",
"//third_party/abseil-cpp/absl/types:optional",
]

if (rtc_use_x11_extensions) {
Expand All @@ -516,10 +547,10 @@ rtc_library("desktop_capture_generic") {
sources += [
"linux/base_capturer_pipewire.cc",
"linux/base_capturer_pipewire.h",
"linux/screen_capturer_pipewire.cc",
"linux/screen_capturer_pipewire.h",
"linux/window_capturer_pipewire.cc",
"linux/window_capturer_pipewire.h",
"linux/pipewire_base.cc",
"linux/pipewire_base.h",
"linux/xdg_desktop_portal_base.cc",
"linux/xdg_desktop_portal_base.h",
]

configs += [
Expand Down
3 changes: 3 additions & 0 deletions modules/desktop_capture/desktop_capture_options.cc
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ DesktopCaptureOptions DesktopCaptureOptions::CreateDefault() {
#if defined(WEBRTC_USE_X11)
result.set_x_display(SharedXDisplay::CreateDefault());
#endif
#if defined(WEBRTC_USE_PIPEWIRE)
result.set_xdp_base(XdgDesktopPortalBase::CreateDefault());
#endif
#if defined(WEBRTC_MAC) && !defined(WEBRTC_IOS)
result.set_configuration_monitor(new DesktopConfigurationMonitor());
result.set_full_screen_window_detector(
Expand Down
62 changes: 61 additions & 1 deletion modules/desktop_capture/desktop_capture_options.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#ifndef MODULES_DESKTOP_CAPTURE_DESKTOP_CAPTURE_OPTIONS_H_
#define MODULES_DESKTOP_CAPTURE_DESKTOP_CAPTURE_OPTIONS_H_

#include "absl/types/optional.h"
#include "api/scoped_refptr.h"
#include "rtc_base/system/rtc_export.h"

Expand All @@ -23,6 +24,10 @@

#include "modules/desktop_capture/full_screen_window_detector.h"

#if defined(WEBRTC_USE_PIPEWIRE)
#include "modules/desktop_capture/linux/xdg_desktop_portal_base.h"
#endif

namespace webrtc {

// An object that stores initialization parameters for screen and window
Expand Down Expand Up @@ -131,13 +136,68 @@ class RTC_EXPORT DesktopCaptureOptions {
#if defined(WEBRTC_USE_PIPEWIRE)
bool allow_pipewire() const { return allow_pipewire_; }
void set_allow_pipewire(bool allow) { allow_pipewire_ = allow; }

// Provides a way how to identify portal call for a sharing request
// made by the client. This allows to go through the preview dialog
// and to the web page itself with just one xdg-desktop-portal call.
// Client is supposed to:
// 1) Call start_request(id) to tell us an identificator for the current
// request
// 2) Call close_request(id) in case the preview dialog was cancelled
// or user picked a web page to be shared
// Note: In case the current request is not finalized, we will close it for
// safety reasons and client will need to ask the portal again
// This was done primarily for chromium support as there was no way how to
// identify a portal call made for the preview and later on continue with the
// same content on the web page itself.

void start_request(int32_t request_id) {
// In case we get a duplicit start_request call, which might happen when a
// browser requests both screen and window sharing, we don't want to do
// anything.
if (request_id == xdp_base_->CurrentConnectionId()) {
return;
}

// In case we are about to start a new request and the previous one is not
// finalized and not stream to the web page itself we will just close it.
if (!xdp_base_->IsConnectionStreamingOnWeb(absl::nullopt) &&
xdp_base_->IsConnectionInitialized(absl::nullopt)) {
xdp_base_->CloseConnection(absl::nullopt);
}

xdp_base_->SetCurrentConnectionId(request_id);
}

void close_request(int32_t request_id) {
xdp_base_->CloseConnection(request_id);
xdp_base_->SetCurrentConnectionId(absl::nullopt);
}

absl::optional<int32_t> request_id() {
// Reset request_id in case the connection is in final state, which means it
// is streaming content to the web page itself and nobody should be asking
// again for this ID.
if (xdp_base_->IsConnectionStreamingOnWeb(absl::nullopt)) {
xdp_base_->SetCurrentConnectionId(absl::nullopt);
}

return xdp_base_->CurrentConnectionId();
}

XdgDesktopPortalBase* xdp_base() const { return xdp_base_; }
void set_xdp_base(rtc::scoped_refptr<XdgDesktopPortalBase> xdp_base) {
xdp_base_ = std::move(xdp_base);
}
#endif

private:
#if defined(WEBRTC_USE_X11)
rtc::scoped_refptr<SharedXDisplay> x_display_;
#endif

#if defined(WEBRTC_USE_PIPEWIRE)
rtc::scoped_refptr<XdgDesktopPortalBase> xdp_base_;
#endif
#if defined(WEBRTC_MAC) && !defined(WEBRTC_IOS)
rtc::scoped_refptr<DesktopConfigurationMonitor> configuration_monitor_;
bool allow_iosurface_ = false;
Expand Down
Loading

0 comments on commit 9b87037

Please sign in to comment.