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 <mbonadei@webrtc.org>
Reviewed-by: Alexander Cooper <alcooper@chromium.org>
Commit-Queue: Salman Malik <salmanmalik@google.com>
Cr-Commit-Position: refs/heads/main@{#36399}
This commit is contained in:
Salman Malik 2022-03-31 14:32:24 +00:00 committed by WebRTC LUCI CQ
parent 3455481554
commit 24927780f1
14 changed files with 176 additions and 21 deletions

View file

@ -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 += [

View file

@ -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<DesktopFrame> frame) {

View file

@ -12,7 +12,9 @@
#define MODULES_DESKTOP_CAPTURE_DESKTOP_AND_CURSOR_COMPOSER_H_
#include <memory>
#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;

View file

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

View file

@ -19,6 +19,9 @@
#include <type_traits>
#include <vector>
#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.

View file

@ -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<DesktopFrame> input_frame) {

View file

@ -12,7 +12,9 @@
#define MODULES_DESKTOP_CAPTURE_DESKTOP_CAPTURER_DIFFER_WRAPPER_H_
#include <memory>
#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,

View file

@ -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>(
ScreenCastPortal::CaptureSourceType::kAnyScreenContent, this);
}
: BaseCapturerPipeWire(
options,
std::make_unique<ScreenCastPortal>(
ScreenCastPortal::CaptureSourceType::kAnyScreenContent,
this)) {}
BaseCapturerPipeWire::BaseCapturerPipeWire(
const DesktopCaptureOptions& options,
std::unique_ptr<ScreenCapturePortalInterface> 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

View file

@ -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<xdg_portal::ScreenCapturePortalInterface> 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<ScreenCastPortal> screencast_portal_;
std::unique_ptr<xdg_portal::ScreenCapturePortalInterface> portal_;
};
} // namespace webrtc

View file

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

View file

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

View file

@ -15,11 +15,13 @@
#include <string>
#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);

View file

@ -18,6 +18,7 @@
#include <vector>
#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*,

View file

@ -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 <gio/gio.h>
#include <string>
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_