From 24927780f10b88315c5e40da98062fc3db88a1b2 Mon Sep 17 00:00:00 2001 From: Salman Malik Date: Thu, 31 Mar 2022 14:32:24 +0000 Subject: [PATCH] wayland: Add a common interface for screencast and remote desktop portal Change adapts the `base_capturer_pipewire` so that a portal can be injected in the capturer. This allows the remoting to inject its own portal for the purpose of capturing desktop stream as long as the injected portal provides implementation of the new interface that is added as part of this change. Additionally, a method has been exposed on the capturer to get details about the portal session so that the remoting implementation can use the same underlying session for controlling inputs on the remote host. Finally, desktop capturer interface is extended with a generic method `GetMetadata` that is used to retrieve session related information by CRD and relay it over to its input injector. Clients provide override for the method and it eventually invokes the underlying `GetSessionDetails` method on the portal instance. Bug: chromium:1291247 Change-Id: I0dbd154eb16d4149f967c4a818eea51e7e6eb9a9 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/257000 Reviewed-by: Mirko Bonadei Reviewed-by: Alexander Cooper Commit-Queue: Salman Malik Cr-Commit-Position: refs/heads/main@{#36399} --- modules/desktop_capture/BUILD.gn | 15 +++++++-- .../desktop_and_cursor_composer.cc | 6 ++++ .../desktop_and_cursor_composer.h | 7 +++- .../desktop_capture_metadata.h | 31 +++++++++++++++++ modules/desktop_capture/desktop_capturer.h | 9 +++++ .../desktop_capturer_differ_wrapper.cc | 6 ++++ .../desktop_capturer_differ_wrapper.h | 8 +++-- .../linux/wayland/base_capturer_pipewire.cc | 22 ++++++++++--- .../linux/wayland/base_capturer_pipewire.h | 11 +++++-- .../wayland/screen_capture_portal_interface.h | 30 +++++++++++++++++ .../linux/wayland/screencast_portal.cc | 4 +++ .../linux/wayland/screencast_portal.h | 7 ++-- .../linux/wayland/xdg_desktop_portal_utils.h | 8 +---- .../linux/wayland/xdg_session_details.h | 33 +++++++++++++++++++ 14 files changed, 176 insertions(+), 21 deletions(-) create mode 100644 modules/desktop_capture/desktop_capture_metadata.h create mode 100644 modules/desktop_capture/linux/wayland/screen_capture_portal_interface.h create mode 100644 modules/desktop_capture/linux/wayland/xdg_session_details.h diff --git a/modules/desktop_capture/BUILD.gn b/modules/desktop_capture/BUILD.gn index 7499c16b09..580a886822 100644 --- a/modules/desktop_capture/BUILD.gn +++ b/modules/desktop_capture/BUILD.gn @@ -6,6 +6,7 @@ # in the file PATENTS. All contributing project authors may # be found in the AUTHORS file in the root of the source tree. +import("//build/config/linux/gtk/gtk.gni") import("//build/config/linux/pkg_config.gni") import("//build/config/ui.gni") import("//tools/generate_stubs/rules.gni") @@ -266,6 +267,13 @@ if (is_linux || is_chromeos) { if (!rtc_link_pipewire) { defines += [ "WEBRTC_DLOPEN_PIPEWIRE" ] } + + # Chromecast build config overrides `WEBRTC_USE_PIPEWIRE` even when + # `rtc_use_pipewire` is not set, which causes pipewire_config to not be + # included in targets. More details in: webrtc:13898 + if (is_linux && !is_chromecast) { + defines += [ "WEBRTC_USE_GIO" ] + } } } } @@ -369,7 +377,9 @@ rtc_library("desktop_capture_generic") { "window_finder.cc", "window_finder.h", ] - + if (is_linux && !is_chromecast && rtc_use_pipewire) { + sources += [ "desktop_capture_metadata.h" ] + } if (is_mac) { sources += [ "mac/desktop_configuration.h", @@ -395,7 +405,6 @@ rtc_library("desktop_capture_generic") { ] } } - if (rtc_use_x11_extensions || rtc_use_pipewire) { sources += [ "mouse_cursor_monitor_linux.cc", @@ -570,6 +579,7 @@ rtc_library("desktop_capture_generic") { "linux/wayland/mouse_cursor_monitor_pipewire.h", "linux/wayland/scoped_glib.cc", "linux/wayland/scoped_glib.h", + "linux/wayland/screen_capture_portal_interface.h", "linux/wayland/screencast_portal.cc", "linux/wayland/screencast_portal.h", "linux/wayland/screencast_stream_utils.cc", @@ -578,6 +588,7 @@ rtc_library("desktop_capture_generic") { "linux/wayland/shared_screencast_stream.h", "linux/wayland/xdg_desktop_portal_utils.cc", "linux/wayland/xdg_desktop_portal_utils.h", + "linux/wayland/xdg_session_details.h", ] configs += [ diff --git a/modules/desktop_capture/desktop_and_cursor_composer.cc b/modules/desktop_capture/desktop_and_cursor_composer.cc index 7ca0af038c..355bfacfbb 100644 --- a/modules/desktop_capture/desktop_and_cursor_composer.cc +++ b/modules/desktop_capture/desktop_and_cursor_composer.cc @@ -203,6 +203,12 @@ bool DesktopAndCursorComposer::IsOccluded(const DesktopVector& pos) { return desktop_capturer_->IsOccluded(pos); } +#if defined(WEBRTC_USE_GIO) +DesktopCaptureMetadata DesktopAndCursorComposer::GetMetadata() { + return desktop_capturer_->GetMetadata(); +} +#endif // defined(WEBRTC_USE_GIO) + void DesktopAndCursorComposer::OnCaptureResult( DesktopCapturer::Result result, std::unique_ptr frame) { diff --git a/modules/desktop_capture/desktop_and_cursor_composer.h b/modules/desktop_capture/desktop_and_cursor_composer.h index edb764d168..a078b3eeef 100644 --- a/modules/desktop_capture/desktop_and_cursor_composer.h +++ b/modules/desktop_capture/desktop_and_cursor_composer.h @@ -12,7 +12,9 @@ #define MODULES_DESKTOP_CAPTURE_DESKTOP_AND_CURSOR_COMPOSER_H_ #include - +#if defined(WEBRTC_USE_GIO) +#include "modules/desktop_capture/desktop_capture_metadata.h" +#endif // defined(WEBRTC_USE_GIO) #include "modules/desktop_capture/desktop_capture_options.h" #include "modules/desktop_capture/desktop_capture_types.h" #include "modules/desktop_capture/desktop_capturer.h" @@ -59,6 +61,9 @@ class RTC_EXPORT DesktopAndCursorComposer bool SelectSource(SourceId id) override; bool FocusOnSelectedSource() override; bool IsOccluded(const DesktopVector& pos) override; +#if defined(WEBRTC_USE_GIO) + DesktopCaptureMetadata GetMetadata() override; +#endif // defined(WEBRTC_USE_GIO) // MouseCursorMonitor::Callback interface. void OnMouseCursor(MouseCursor* cursor) override; diff --git a/modules/desktop_capture/desktop_capture_metadata.h b/modules/desktop_capture/desktop_capture_metadata.h new file mode 100644 index 0000000000..faca156e33 --- /dev/null +++ b/modules/desktop_capture/desktop_capture_metadata.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2022 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef MODULES_DESKTOP_CAPTURE_DESKTOP_CAPTURE_METADATA_H_ +#define MODULES_DESKTOP_CAPTURE_DESKTOP_CAPTURE_METADATA_H_ + +#if defined(WEBRTC_USE_GIO) +#include "modules/desktop_capture/linux/wayland/xdg_session_details.h" +#endif // defined(WEBRTC_USE_GIO) + +namespace webrtc { + +// Container for the metadata associated with a desktop capturer. +struct DesktopCaptureMetadata { +#if defined(WEBRTC_USE_GIO) + // Details about the XDG desktop session handle (used by wayland + // implementation in remoting) + xdg_portal::SessionDetails session_details; +#endif // defined(WEBRTC_USE_GIO) +}; + +} // namespace webrtc + +#endif // MODULES_DESKTOP_CAPTURE_DESKTOP_CAPTURE_METADATA_H_ diff --git a/modules/desktop_capture/desktop_capturer.h b/modules/desktop_capture/desktop_capturer.h index 822a75d947..d3164258ec 100644 --- a/modules/desktop_capture/desktop_capturer.h +++ b/modules/desktop_capture/desktop_capturer.h @@ -19,6 +19,9 @@ #include #include +#if defined(WEBRTC_USE_GIO) +#include "modules/desktop_capture/desktop_capture_metadata.h" +#endif // defined(WEBRTC_USE_GIO) #include "modules/desktop_capture/desktop_capture_types.h" #include "modules/desktop_capture/desktop_frame.h" #include "modules/desktop_capture/shared_memory.h" @@ -143,6 +146,12 @@ class RTC_EXPORT DesktopCapturer { static bool IsRunningUnderWayland(); #endif // defined(WEBRTC_USE_PIPEWIRE) || defined(WEBRTC_USE_X11) +#if defined(WEBRTC_USE_GIO) + // Populates implementation specific metadata into the passed in pointer. + // Classes can choose to override it or use the default no-op implementation. + virtual DesktopCaptureMetadata GetMetadata() { return {}; } +#endif // defined(WEBRTC_USE_GIO) + protected: // CroppingWindowCapturer needs to create raw capturers without wrappers, so // the following two functions are protected. diff --git a/modules/desktop_capture/desktop_capturer_differ_wrapper.cc b/modules/desktop_capture/desktop_capturer_differ_wrapper.cc index 916d76f7ce..77543e4060 100644 --- a/modules/desktop_capture/desktop_capturer_differ_wrapper.cc +++ b/modules/desktop_capture/desktop_capturer_differ_wrapper.cc @@ -186,6 +186,12 @@ bool DesktopCapturerDifferWrapper::IsOccluded(const DesktopVector& pos) { return base_capturer_->IsOccluded(pos); } +#if defined(WEBRTC_USE_GIO) +DesktopCaptureMetadata DesktopCapturerDifferWrapper::GetMetadata() { + return base_capturer_->GetMetadata(); +} +#endif // defined(WEBRTC_USE_GIO) + void DesktopCapturerDifferWrapper::OnCaptureResult( Result result, std::unique_ptr input_frame) { diff --git a/modules/desktop_capture/desktop_capturer_differ_wrapper.h b/modules/desktop_capture/desktop_capturer_differ_wrapper.h index 1f70cef186..6ebb5d7bc3 100644 --- a/modules/desktop_capture/desktop_capturer_differ_wrapper.h +++ b/modules/desktop_capture/desktop_capturer_differ_wrapper.h @@ -12,7 +12,9 @@ #define MODULES_DESKTOP_CAPTURE_DESKTOP_CAPTURER_DIFFER_WRAPPER_H_ #include - +#if defined(WEBRTC_USE_GIO) +#include "modules/desktop_capture/desktop_capture_metadata.h" +#endif // defined(WEBRTC_USE_GIO) #include "modules/desktop_capture/desktop_capture_types.h" #include "modules/desktop_capture/desktop_capturer.h" #include "modules/desktop_capture/desktop_frame.h" @@ -52,7 +54,9 @@ class RTC_EXPORT DesktopCapturerDifferWrapper bool SelectSource(SourceId id) override; bool FocusOnSelectedSource() override; bool IsOccluded(const DesktopVector& pos) override; - +#if defined(WEBRTC_USE_GIO) + DesktopCaptureMetadata GetMetadata() override; +#endif // defined(WEBRTC_USE_GIO) private: // DesktopCapturer::Callback interface. void OnCaptureResult(Result result, diff --git a/modules/desktop_capture/linux/wayland/base_capturer_pipewire.cc b/modules/desktop_capture/linux/wayland/base_capturer_pipewire.cc index ae26570a7c..0fc90e0e8d 100644 --- a/modules/desktop_capture/linux/wayland/base_capturer_pipewire.cc +++ b/modules/desktop_capture/linux/wayland/base_capturer_pipewire.cc @@ -21,14 +21,22 @@ namespace webrtc { namespace { using xdg_portal::RequestResponse; +using xdg_portal::ScreenCapturePortalInterface; +using xdg_portal::SessionDetails; } // namespace BaseCapturerPipeWire::BaseCapturerPipeWire(const DesktopCaptureOptions& options) - : options_(options) { - screencast_portal_ = std::make_unique( - ScreenCastPortal::CaptureSourceType::kAnyScreenContent, this); -} + : BaseCapturerPipeWire( + options, + std::make_unique( + ScreenCastPortal::CaptureSourceType::kAnyScreenContent, + this)) {} + +BaseCapturerPipeWire::BaseCapturerPipeWire( + const DesktopCaptureOptions& options, + std::unique_ptr portal) + : options_(options), portal_(std::move(portal)) {} BaseCapturerPipeWire::~BaseCapturerPipeWire() {} @@ -56,7 +64,7 @@ void BaseCapturerPipeWire::Start(Callback* callback) { callback_ = callback; - screencast_portal_->Start(); + portal_->Start(); } void BaseCapturerPipeWire::CaptureFrame() { @@ -97,4 +105,8 @@ bool BaseCapturerPipeWire::SelectSource(SourceId id) { return true; } +SessionDetails BaseCapturerPipeWire::GetSessionDetails() { + return portal_->GetSessionDetails(); +} + } // namespace webrtc diff --git a/modules/desktop_capture/linux/wayland/base_capturer_pipewire.h b/modules/desktop_capture/linux/wayland/base_capturer_pipewire.h index e9d67d04be..da0ce95a01 100644 --- a/modules/desktop_capture/linux/wayland/base_capturer_pipewire.h +++ b/modules/desktop_capture/linux/wayland/base_capturer_pipewire.h @@ -13,16 +13,21 @@ #include "modules/desktop_capture/desktop_capture_options.h" #include "modules/desktop_capture/desktop_capturer.h" +#include "modules/desktop_capture/linux/wayland/screen_capture_portal_interface.h" #include "modules/desktop_capture/linux/wayland/screencast_portal.h" #include "modules/desktop_capture/linux/wayland/shared_screencast_stream.h" #include "modules/desktop_capture/linux/wayland/xdg_desktop_portal_utils.h" +#include "modules/desktop_capture/linux/wayland/xdg_session_details.h" namespace webrtc { class BaseCapturerPipeWire : public DesktopCapturer, public ScreenCastPortal::PortalNotifier { public: - BaseCapturerPipeWire(const DesktopCaptureOptions& options); + explicit BaseCapturerPipeWire(const DesktopCaptureOptions& options); + BaseCapturerPipeWire( + const DesktopCaptureOptions& options, + std::unique_ptr portal); ~BaseCapturerPipeWire() override; BaseCapturerPipeWire(const BaseCapturerPipeWire&) = delete; @@ -40,11 +45,13 @@ class BaseCapturerPipeWire : public DesktopCapturer, int fd) override; void OnScreenCastSessionClosed() override; + xdg_portal::SessionDetails GetSessionDetails(); + private: DesktopCaptureOptions options_ = {}; Callback* callback_ = nullptr; bool capturer_failed_ = false; - std::unique_ptr screencast_portal_; + std::unique_ptr portal_; }; } // namespace webrtc diff --git a/modules/desktop_capture/linux/wayland/screen_capture_portal_interface.h b/modules/desktop_capture/linux/wayland/screen_capture_portal_interface.h new file mode 100644 index 0000000000..76cbd276c9 --- /dev/null +++ b/modules/desktop_capture/linux/wayland/screen_capture_portal_interface.h @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2022 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef MODULES_DESKTOP_CAPTURE_LINUX_WAYLAND_SCREEN_CAPTURE_PORTAL_INTERFACE_H_ +#define MODULES_DESKTOP_CAPTURE_LINUX_WAYLAND_SCREEN_CAPTURE_PORTAL_INTERFACE_H_ + +#include "modules/desktop_capture/linux/wayland/xdg_session_details.h" + +namespace webrtc { +namespace xdg_portal { + +// An interface for XDG desktop portals that can capture desktop/screen. +class ScreenCapturePortalInterface { + public: + virtual ~ScreenCapturePortalInterface() {} + virtual xdg_portal::SessionDetails GetSessionDetails() = 0; + virtual void Start() = 0; +}; + +} // namespace xdg_portal +} // namespace webrtc + +#endif // MODULES_DESKTOP_CAPTURE_LINUX_WAYLAND_SCREEN_CAPTURE_PORTAL_INTERFACE_H_ diff --git a/modules/desktop_capture/linux/wayland/screencast_portal.cc b/modules/desktop_capture/linux/wayland/screencast_portal.cc index bbf933966b..ab516a7f4d 100644 --- a/modules/desktop_capture/linux/wayland/screencast_portal.cc +++ b/modules/desktop_capture/linux/wayland/screencast_portal.cc @@ -112,6 +112,10 @@ void ScreenCastPortal::Start() { cancellable_, this); } +xdg_portal::SessionDetails ScreenCastPortal::GetSessionDetails() { + return {}; // No-op +} + void ScreenCastPortal::PortalFailed(RequestResponse result) { notifier_->OnScreenCastRequestResult(result, pw_stream_node_id_, pw_fd_); } diff --git a/modules/desktop_capture/linux/wayland/screencast_portal.h b/modules/desktop_capture/linux/wayland/screencast_portal.h index d29f773cb2..3d86006050 100644 --- a/modules/desktop_capture/linux/wayland/screencast_portal.h +++ b/modules/desktop_capture/linux/wayland/screencast_portal.h @@ -15,11 +15,13 @@ #include +#include "modules/desktop_capture/linux/wayland/screen_capture_portal_interface.h" #include "modules/desktop_capture/linux/wayland/xdg_desktop_portal_utils.h" +#include "modules/desktop_capture/linux/wayland/xdg_session_details.h" namespace webrtc { -class ScreenCastPortal { +class ScreenCastPortal : public xdg_portal::ScreenCapturePortalInterface { public: using ProxyRequestResponseHandler = void (*)(GObject* object, GAsyncResult* result, @@ -86,7 +88,8 @@ class ScreenCastPortal { // The observer will return whether the communication with xdg-desktop-portal // was successful and only then you will be able to get all the required // information in order to continue working with PipeWire. - void Start(); + void Start() override; + xdg_portal::SessionDetails GetSessionDetails() override; // Method to notify the reason for failure of a portal request. void PortalFailed(xdg_portal::RequestResponse result); diff --git a/modules/desktop_capture/linux/wayland/xdg_desktop_portal_utils.h b/modules/desktop_capture/linux/wayland/xdg_desktop_portal_utils.h index 4fb058c427..98979c1f40 100644 --- a/modules/desktop_capture/linux/wayland/xdg_desktop_portal_utils.h +++ b/modules/desktop_capture/linux/wayland/xdg_desktop_portal_utils.h @@ -18,6 +18,7 @@ #include #include "modules/desktop_capture/linux/wayland/scoped_glib.h" +#include "modules/desktop_capture/linux/wayland/xdg_session_details.h" #include "rtc_base/checks.h" #include "rtc_base/logging.h" @@ -32,13 +33,6 @@ constexpr char kSessionInterfaceName[] = "org.freedesktop.portal.Session"; constexpr char kRequestInterfaceName[] = "org.freedesktop.portal.Request"; constexpr char kScreenCastInterfaceName[] = "org.freedesktop.portal.ScreenCast"; -struct SessionDetails { - GDBusProxy* proxy; - GCancellable* cancellable; - std::string session_handle; - uint32_t pipewire_stream_node_id; -}; - using ProxyRequestCallback = void (*)(GObject*, GAsyncResult*, gpointer); using SessionRequestCallback = void (*)(GDBusProxy*, GAsyncResult*, gpointer); using SessionRequestResponseSignalHandler = void (*)(GDBusConnection*, diff --git a/modules/desktop_capture/linux/wayland/xdg_session_details.h b/modules/desktop_capture/linux/wayland/xdg_session_details.h new file mode 100644 index 0000000000..b70ac4aa59 --- /dev/null +++ b/modules/desktop_capture/linux/wayland/xdg_session_details.h @@ -0,0 +1,33 @@ +/* + * Copyright 2022 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef MODULES_DESKTOP_CAPTURE_LINUX_WAYLAND_XDG_SESSION_DETAILS_H_ +#define MODULES_DESKTOP_CAPTURE_LINUX_WAYLAND_XDG_SESSION_DETAILS_H_ + +#include + +#include + +namespace webrtc { +namespace xdg_portal { + +// Details of the session associated with XDG desktop portal session. Portal API +// calls can be invoked by utilizing the information here. +struct SessionDetails { + GDBusProxy* proxy = nullptr; + GCancellable* cancellable = nullptr; + std::string session_handle; + uint32_t pipewire_stream_node_id = 0; +}; + +} // namespace xdg_portal +} // namespace webrtc + +#endif // MODULES_DESKTOP_CAPTURE_LINUX_WAYLAND_XDG_SESSION_DETAILS_H_