desktop_capturer: Extract helpers from screencast portal
Extract helper methods from screencast portal that can be reused for remote desktop portal client. Bug: chromium:1291247 Change-Id: I66d09c75f0c34d81c7ceff8998720fbbd1902ac8 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/249860 Reviewed-by: Alexander Cooper <alcooper@chromium.org> Commit-Queue: Salman Malik <salmanmalik@google.com> Cr-Commit-Position: refs/heads/main@{#36256}
This commit is contained in:

committed by
WebRTC LUCI CQ

parent
29ad53e466
commit
76dd735a14
@ -574,6 +574,8 @@ rtc_library("desktop_capture_generic") {
|
|||||||
"linux/wayland/screencast_portal.h",
|
"linux/wayland/screencast_portal.h",
|
||||||
"linux/wayland/shared_screencast_stream.cc",
|
"linux/wayland/shared_screencast_stream.cc",
|
||||||
"linux/wayland/shared_screencast_stream.h",
|
"linux/wayland/shared_screencast_stream.h",
|
||||||
|
"linux/wayland/xdg_desktop_portal_utils.cc",
|
||||||
|
"linux/wayland/xdg_desktop_portal_utils.h",
|
||||||
]
|
]
|
||||||
|
|
||||||
configs += [
|
configs += [
|
||||||
|
@ -12,11 +12,18 @@
|
|||||||
|
|
||||||
#include "modules/desktop_capture/desktop_capture_options.h"
|
#include "modules/desktop_capture/desktop_capture_options.h"
|
||||||
#include "modules/desktop_capture/desktop_capturer.h"
|
#include "modules/desktop_capture/desktop_capturer.h"
|
||||||
|
#include "modules/desktop_capture/linux/wayland/xdg_desktop_portal_utils.h"
|
||||||
#include "rtc_base/checks.h"
|
#include "rtc_base/checks.h"
|
||||||
#include "rtc_base/logging.h"
|
#include "rtc_base/logging.h"
|
||||||
|
|
||||||
namespace webrtc {
|
namespace webrtc {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
using xdg_portal::RequestResponse;
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
BaseCapturerPipeWire::BaseCapturerPipeWire(const DesktopCaptureOptions& options)
|
BaseCapturerPipeWire::BaseCapturerPipeWire(const DesktopCaptureOptions& options)
|
||||||
: options_(options) {
|
: options_(options) {
|
||||||
screencast_portal_ = std::make_unique<ScreenCastPortal>(
|
screencast_portal_ = std::make_unique<ScreenCastPortal>(
|
||||||
@ -25,11 +32,10 @@ BaseCapturerPipeWire::BaseCapturerPipeWire(const DesktopCaptureOptions& options)
|
|||||||
|
|
||||||
BaseCapturerPipeWire::~BaseCapturerPipeWire() {}
|
BaseCapturerPipeWire::~BaseCapturerPipeWire() {}
|
||||||
|
|
||||||
void BaseCapturerPipeWire::OnScreenCastRequestResult(
|
void BaseCapturerPipeWire::OnScreenCastRequestResult(RequestResponse result,
|
||||||
ScreenCastPortal::RequestResponse result,
|
|
||||||
uint32_t stream_node_id,
|
uint32_t stream_node_id,
|
||||||
int fd) {
|
int fd) {
|
||||||
if (result != ScreenCastPortal::RequestResponse::kSuccess ||
|
if (result != RequestResponse::kSuccess ||
|
||||||
!options_.screencast_stream()->StartScreenCastStream(stream_node_id,
|
!options_.screencast_stream()->StartScreenCastStream(stream_node_id,
|
||||||
fd)) {
|
fd)) {
|
||||||
capturer_failed_ = true;
|
capturer_failed_ = true;
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
#include "modules/desktop_capture/desktop_capturer.h"
|
#include "modules/desktop_capture/desktop_capturer.h"
|
||||||
#include "modules/desktop_capture/linux/wayland/screencast_portal.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/shared_screencast_stream.h"
|
||||||
|
#include "modules/desktop_capture/linux/wayland/xdg_desktop_portal_utils.h"
|
||||||
|
|
||||||
namespace webrtc {
|
namespace webrtc {
|
||||||
|
|
||||||
@ -34,7 +35,7 @@ class BaseCapturerPipeWire : public DesktopCapturer,
|
|||||||
bool SelectSource(SourceId id) override;
|
bool SelectSource(SourceId id) override;
|
||||||
|
|
||||||
// ScreenCastPortal::PortalNotifier interface.
|
// ScreenCastPortal::PortalNotifier interface.
|
||||||
void OnScreenCastRequestResult(ScreenCastPortal::RequestResponse result,
|
void OnScreenCastRequestResult(xdg_portal::RequestResponse result,
|
||||||
uint32_t stream_node_id,
|
uint32_t stream_node_id,
|
||||||
int fd) override;
|
int fd) override;
|
||||||
void OnScreenCastSessionClosed() override;
|
void OnScreenCastSessionClosed() override;
|
||||||
|
@ -14,73 +14,67 @@
|
|||||||
#include <glib-object.h>
|
#include <glib-object.h>
|
||||||
|
|
||||||
#include "modules/desktop_capture/linux/wayland/scoped_glib.h"
|
#include "modules/desktop_capture/linux/wayland/scoped_glib.h"
|
||||||
|
#include "modules/desktop_capture/linux/wayland/xdg_desktop_portal_utils.h"
|
||||||
#include "rtc_base/checks.h"
|
#include "rtc_base/checks.h"
|
||||||
#include "rtc_base/logging.h"
|
#include "rtc_base/logging.h"
|
||||||
|
|
||||||
namespace webrtc {
|
namespace webrtc {
|
||||||
|
namespace {
|
||||||
|
|
||||||
const char kDesktopBusName[] = "org.freedesktop.portal.Desktop";
|
using xdg_portal::kScreenCastInterfaceName;
|
||||||
const char kDesktopObjectPath[] = "/org/freedesktop/portal/desktop";
|
using xdg_portal::PrepareSignalHandle;
|
||||||
const char kDesktopRequestObjectPath[] =
|
using xdg_portal::RequestResponse;
|
||||||
"/org/freedesktop/portal/desktop/request";
|
using xdg_portal::RequestSessionProxy;
|
||||||
const char kSessionInterfaceName[] = "org.freedesktop.portal.Session";
|
using xdg_portal::RequestSessionUsingProxy;
|
||||||
const char kRequestInterfaceName[] = "org.freedesktop.portal.Request";
|
using xdg_portal::SessionRequestHandler;
|
||||||
const char kScreenCastInterfaceName[] = "org.freedesktop.portal.ScreenCast";
|
using xdg_portal::SessionRequestResponseSignalHelper;
|
||||||
|
using xdg_portal::SetupRequestResponseSignal;
|
||||||
|
using xdg_portal::SetupSessionRequestHandlers;
|
||||||
|
using xdg_portal::StartRequestedHandler;
|
||||||
|
using xdg_portal::StartSessionRequest;
|
||||||
|
using xdg_portal::TearDownSession;
|
||||||
|
|
||||||
ScreenCastPortal::ScreenCastPortal(CaptureSourceType source_type,
|
} // namespace
|
||||||
|
|
||||||
|
ScreenCastPortal::ScreenCastPortal(
|
||||||
|
ScreenCastPortal::CaptureSourceType source_type,
|
||||||
PortalNotifier* notifier)
|
PortalNotifier* notifier)
|
||||||
: notifier_(notifier), capture_source_type_(source_type) {}
|
: notifier_(notifier), capture_source_type_(source_type) {}
|
||||||
|
|
||||||
ScreenCastPortal::~ScreenCastPortal() {
|
ScreenCastPortal::~ScreenCastPortal() {
|
||||||
if (start_request_signal_id_) {
|
UnsubscribeSignalHandlers();
|
||||||
g_dbus_connection_signal_unsubscribe(connection_, start_request_signal_id_);
|
TearDownSession(std::move(session_handle_), proxy_, cancellable_,
|
||||||
}
|
connection_);
|
||||||
if (sources_request_signal_id_) {
|
|
||||||
g_dbus_connection_signal_unsubscribe(connection_,
|
|
||||||
sources_request_signal_id_);
|
|
||||||
}
|
|
||||||
if (session_request_signal_id_) {
|
|
||||||
g_dbus_connection_signal_unsubscribe(connection_,
|
|
||||||
session_request_signal_id_);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!session_handle_.empty()) {
|
|
||||||
Scoped<GDBusMessage> message(
|
|
||||||
g_dbus_message_new_method_call(kDesktopBusName, session_handle_.c_str(),
|
|
||||||
kSessionInterfaceName, "Close"));
|
|
||||||
if (message.get()) {
|
|
||||||
Scoped<GError> error;
|
|
||||||
g_dbus_connection_send_message(connection_, message.get(),
|
|
||||||
G_DBUS_SEND_MESSAGE_FLAGS_NONE,
|
|
||||||
/*out_serial=*/nullptr, error.receive());
|
|
||||||
if (error.get()) {
|
|
||||||
RTC_LOG(LS_ERROR) << "Failed to close the session: " << error->message;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cancellable_) {
|
|
||||||
g_cancellable_cancel(cancellable_);
|
|
||||||
g_object_unref(cancellable_);
|
|
||||||
cancellable_ = nullptr;
|
cancellable_ = nullptr;
|
||||||
}
|
|
||||||
|
|
||||||
if (proxy_) {
|
|
||||||
g_object_unref(proxy_);
|
|
||||||
proxy_ = nullptr;
|
proxy_ = nullptr;
|
||||||
}
|
|
||||||
|
|
||||||
if (pw_fd_ != -1) {
|
if (pw_fd_ != -1) {
|
||||||
close(pw_fd_);
|
close(pw_fd_);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ScreenCastPortal::UnsubscribeSignalHandlers() {
|
||||||
|
if (start_request_signal_id_) {
|
||||||
|
g_dbus_connection_signal_unsubscribe(connection_, start_request_signal_id_);
|
||||||
|
start_request_signal_id_ = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sources_request_signal_id_) {
|
||||||
|
g_dbus_connection_signal_unsubscribe(connection_,
|
||||||
|
sources_request_signal_id_);
|
||||||
|
sources_request_signal_id_ = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (session_request_signal_id_) {
|
||||||
|
g_dbus_connection_signal_unsubscribe(connection_,
|
||||||
|
session_request_signal_id_);
|
||||||
|
session_request_signal_id_ = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void ScreenCastPortal::Start() {
|
void ScreenCastPortal::Start() {
|
||||||
cancellable_ = g_cancellable_new();
|
cancellable_ = g_cancellable_new();
|
||||||
g_dbus_proxy_new_for_bus(
|
RequestSessionProxy(kScreenCastInterfaceName, OnProxyRequested, cancellable_,
|
||||||
G_BUS_TYPE_SESSION, G_DBUS_PROXY_FLAGS_NONE, /*info=*/nullptr,
|
|
||||||
kDesktopBusName, kDesktopObjectPath, kScreenCastInterfaceName,
|
|
||||||
cancellable_, reinterpret_cast<GAsyncReadyCallback>(OnProxyRequested),
|
|
||||||
this);
|
this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -88,115 +82,28 @@ void ScreenCastPortal::PortalFailed(RequestResponse result) {
|
|||||||
notifier_->OnScreenCastRequestResult(result, pw_stream_node_id_, pw_fd_);
|
notifier_->OnScreenCastRequestResult(result, pw_stream_node_id_, pw_fd_);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t ScreenCastPortal::SetupRequestResponseSignal(
|
|
||||||
const char* object_path,
|
|
||||||
GDBusSignalCallback callback) {
|
|
||||||
return g_dbus_connection_signal_subscribe(
|
|
||||||
connection_, kDesktopBusName, kRequestInterfaceName, "Response",
|
|
||||||
object_path, /*arg0=*/nullptr, G_DBUS_SIGNAL_FLAGS_NO_MATCH_RULE,
|
|
||||||
callback, this, /*user_data_free_func=*/nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
// static
|
// static
|
||||||
void ScreenCastPortal::OnProxyRequested(GObject* /*object*/,
|
void ScreenCastPortal::OnProxyRequested(GObject* gobject,
|
||||||
GAsyncResult* result,
|
GAsyncResult* result,
|
||||||
gpointer user_data) {
|
gpointer user_data) {
|
||||||
ScreenCastPortal* that = static_cast<ScreenCastPortal*>(user_data);
|
RequestSessionUsingProxy<ScreenCastPortal>(
|
||||||
RTC_DCHECK(that);
|
static_cast<ScreenCastPortal*>(user_data), gobject, result);
|
||||||
|
|
||||||
Scoped<GError> error;
|
|
||||||
GDBusProxy* proxy = g_dbus_proxy_new_finish(result, error.receive());
|
|
||||||
if (!proxy) {
|
|
||||||
if (g_error_matches(error.get(), G_IO_ERROR, G_IO_ERROR_CANCELLED))
|
|
||||||
return;
|
|
||||||
RTC_LOG(LS_ERROR) << "Failed to create a proxy for the screen cast portal: "
|
|
||||||
<< error->message;
|
|
||||||
that->PortalFailed(RequestResponse::kError);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
that->proxy_ = proxy;
|
|
||||||
that->connection_ = g_dbus_proxy_get_connection(that->proxy_);
|
|
||||||
|
|
||||||
RTC_LOG(LS_INFO) << "Created proxy for the screen cast portal.";
|
|
||||||
|
|
||||||
that->SessionRequest();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// static
|
void ScreenCastPortal::SessionRequest(GDBusProxy* proxy) {
|
||||||
std::string ScreenCastPortal::PrepareSignalHandle(GDBusConnection* connection,
|
proxy_ = proxy;
|
||||||
const char* token) {
|
connection_ = g_dbus_proxy_get_connection(proxy_);
|
||||||
Scoped<char> sender(
|
SetupSessionRequestHandlers(
|
||||||
g_strdup(g_dbus_connection_get_unique_name(connection) + 1));
|
"webrtc", OnSessionRequested, OnSessionRequestResponseSignal, connection_,
|
||||||
for (int i = 0; sender.get()[i]; ++i) {
|
proxy_, cancellable_, portal_handle_, session_request_signal_id_, this);
|
||||||
if (sender.get()[i] == '.') {
|
|
||||||
sender.get()[i] = '_';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const char* handle = g_strconcat(kDesktopRequestObjectPath, "/", sender.get(),
|
|
||||||
"/", token, /*end of varargs*/ nullptr);
|
|
||||||
|
|
||||||
return handle;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ScreenCastPortal::SessionRequest() {
|
|
||||||
GVariantBuilder builder;
|
|
||||||
Scoped<char> variant_string;
|
|
||||||
|
|
||||||
g_variant_builder_init(&builder, G_VARIANT_TYPE_VARDICT);
|
|
||||||
variant_string =
|
|
||||||
g_strdup_printf("webrtc_session%d", g_random_int_range(0, G_MAXINT));
|
|
||||||
g_variant_builder_add(&builder, "{sv}", "session_handle_token",
|
|
||||||
g_variant_new_string(variant_string.get()));
|
|
||||||
variant_string = g_strdup_printf("webrtc%d", g_random_int_range(0, G_MAXINT));
|
|
||||||
g_variant_builder_add(&builder, "{sv}", "handle_token",
|
|
||||||
g_variant_new_string(variant_string.get()));
|
|
||||||
|
|
||||||
portal_handle_ = PrepareSignalHandle(connection_, variant_string.get());
|
|
||||||
session_request_signal_id_ = SetupRequestResponseSignal(
|
|
||||||
portal_handle_.c_str(), OnSessionRequestResponseSignal);
|
|
||||||
|
|
||||||
RTC_LOG(LS_INFO) << "Screen cast session requested.";
|
|
||||||
g_dbus_proxy_call(proxy_, "CreateSession", g_variant_new("(a{sv})", &builder),
|
|
||||||
G_DBUS_CALL_FLAGS_NONE, /*timeout=*/-1, cancellable_,
|
|
||||||
reinterpret_cast<GAsyncReadyCallback>(OnSessionRequested),
|
|
||||||
this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// static
|
// static
|
||||||
void ScreenCastPortal::OnSessionRequested(GDBusProxy* proxy,
|
void ScreenCastPortal::OnSessionRequested(GDBusProxy* proxy,
|
||||||
GAsyncResult* result,
|
GAsyncResult* result,
|
||||||
gpointer user_data) {
|
gpointer user_data) {
|
||||||
ScreenCastPortal* that = static_cast<ScreenCastPortal*>(user_data);
|
SessionRequestHandler(static_cast<ScreenCastPortal*>(user_data), proxy,
|
||||||
RTC_DCHECK(that);
|
result, user_data);
|
||||||
|
|
||||||
Scoped<GError> error;
|
|
||||||
Scoped<GVariant> variant(
|
|
||||||
g_dbus_proxy_call_finish(proxy, result, error.receive()));
|
|
||||||
if (!variant) {
|
|
||||||
if (g_error_matches(error.get(), G_IO_ERROR, G_IO_ERROR_CANCELLED))
|
|
||||||
return;
|
|
||||||
RTC_LOG(LS_ERROR) << "Failed to create a screen cast session: "
|
|
||||||
<< error->message;
|
|
||||||
that->PortalFailed(RequestResponse::kError);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
RTC_LOG(LS_INFO) << "Initializing the screen cast session.";
|
|
||||||
|
|
||||||
Scoped<char> handle;
|
|
||||||
g_variant_get_child(variant.get(), 0, "o", &handle);
|
|
||||||
if (!handle) {
|
|
||||||
RTC_LOG(LS_ERROR) << "Failed to initialize the screen cast session.";
|
|
||||||
if (that->session_request_signal_id_) {
|
|
||||||
g_dbus_connection_signal_unsubscribe(that->connection_,
|
|
||||||
that->session_request_signal_id_);
|
|
||||||
that->session_request_signal_id_ = 0;
|
|
||||||
}
|
|
||||||
that->PortalFailed(RequestResponse::kError);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
RTC_LOG(LS_INFO) << "Subscribing to the screen cast session.";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// static
|
// static
|
||||||
@ -210,30 +117,9 @@ void ScreenCastPortal::OnSessionRequestResponseSignal(
|
|||||||
gpointer user_data) {
|
gpointer user_data) {
|
||||||
ScreenCastPortal* that = static_cast<ScreenCastPortal*>(user_data);
|
ScreenCastPortal* that = static_cast<ScreenCastPortal*>(user_data);
|
||||||
RTC_DCHECK(that);
|
RTC_DCHECK(that);
|
||||||
|
SessionRequestResponseSignalHelper(
|
||||||
RTC_LOG(LS_INFO)
|
OnSessionClosedSignal, that, that->connection_, that->session_handle_,
|
||||||
<< "Received response for the screen cast session subscription.";
|
parameters, that->session_closed_signal_id_);
|
||||||
|
|
||||||
uint32_t portal_response;
|
|
||||||
Scoped<GVariant> response_data;
|
|
||||||
g_variant_get(parameters, "(u@a{sv})", &portal_response,
|
|
||||||
response_data.receive());
|
|
||||||
Scoped<GVariant> session_handle(
|
|
||||||
g_variant_lookup_value(response_data.get(), "session_handle", nullptr));
|
|
||||||
that->session_handle_ = g_variant_dup_string(session_handle.get(), nullptr);
|
|
||||||
|
|
||||||
if (that->session_handle_.empty() || portal_response) {
|
|
||||||
RTC_LOG(LS_ERROR)
|
|
||||||
<< "Failed to request the screen cast session subscription.";
|
|
||||||
that->PortalFailed(RequestResponse::kError);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
that->session_closed_signal_id_ = g_dbus_connection_signal_subscribe(
|
|
||||||
that->connection_, kDesktopBusName, kSessionInterfaceName, "Closed",
|
|
||||||
that->session_handle_.c_str(), /*arg0=*/nullptr, G_DBUS_SIGNAL_FLAGS_NONE,
|
|
||||||
OnSessionClosedSignal, that, /*user_data_free_func=*/nullptr);
|
|
||||||
|
|
||||||
that->SourcesRequest();
|
that->SourcesRequest();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -289,9 +175,10 @@ void ScreenCastPortal::SourcesRequest() {
|
|||||||
g_variant_builder_add(&builder, "{sv}", "handle_token",
|
g_variant_builder_add(&builder, "{sv}", "handle_token",
|
||||||
g_variant_new_string(variant_string.get()));
|
g_variant_new_string(variant_string.get()));
|
||||||
|
|
||||||
sources_handle_ = PrepareSignalHandle(connection_, variant_string.get());
|
sources_handle_ = PrepareSignalHandle(variant_string.get(), connection_);
|
||||||
sources_request_signal_id_ = SetupRequestResponseSignal(
|
sources_request_signal_id_ = SetupRequestResponseSignal(
|
||||||
sources_handle_.c_str(), OnSourcesRequestResponseSignal);
|
sources_handle_.c_str(), OnSourcesRequestResponseSignal, this,
|
||||||
|
connection_);
|
||||||
|
|
||||||
RTC_LOG(LS_INFO) << "Requesting sources from the screen cast session.";
|
RTC_LOG(LS_INFO) << "Requesting sources from the screen cast session.";
|
||||||
g_dbus_proxy_call(
|
g_dbus_proxy_call(
|
||||||
@ -364,66 +251,17 @@ void ScreenCastPortal::OnSourcesRequestResponseSignal(
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ScreenCastPortal::StartRequest() {
|
void ScreenCastPortal::StartRequest() {
|
||||||
GVariantBuilder builder;
|
StartSessionRequest("webrtc", session_handle_, OnStartRequestResponseSignal,
|
||||||
Scoped<char> variant_string;
|
OnStartRequested, proxy_, connection_, cancellable_,
|
||||||
|
start_request_signal_id_, start_handle_, this);
|
||||||
g_variant_builder_init(&builder, G_VARIANT_TYPE_VARDICT);
|
|
||||||
variant_string = g_strdup_printf("webrtc%d", g_random_int_range(0, G_MAXINT));
|
|
||||||
g_variant_builder_add(&builder, "{sv}", "handle_token",
|
|
||||||
g_variant_new_string(variant_string.get()));
|
|
||||||
|
|
||||||
start_handle_ = PrepareSignalHandle(connection_, variant_string.get());
|
|
||||||
start_request_signal_id_ = SetupRequestResponseSignal(
|
|
||||||
start_handle_.c_str(), OnStartRequestResponseSignal);
|
|
||||||
|
|
||||||
// "Identifier for the application window", this is Wayland, so not "x11:...".
|
|
||||||
const char parent_window[] = "";
|
|
||||||
|
|
||||||
RTC_LOG(LS_INFO) << "Starting the screen cast session.";
|
|
||||||
g_dbus_proxy_call(proxy_, "Start",
|
|
||||||
g_variant_new("(osa{sv})", session_handle_.c_str(),
|
|
||||||
parent_window, &builder),
|
|
||||||
G_DBUS_CALL_FLAGS_NONE, /*timeout=*/-1, cancellable_,
|
|
||||||
reinterpret_cast<GAsyncReadyCallback>(OnStartRequested),
|
|
||||||
this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// static
|
// static
|
||||||
void ScreenCastPortal::OnStartRequested(GDBusProxy* proxy,
|
void ScreenCastPortal::OnStartRequested(GDBusProxy* proxy,
|
||||||
GAsyncResult* result,
|
GAsyncResult* result,
|
||||||
gpointer user_data) {
|
gpointer user_data) {
|
||||||
ScreenCastPortal* that = static_cast<ScreenCastPortal*>(user_data);
|
StartRequestedHandler(static_cast<ScreenCastPortal*>(user_data), proxy,
|
||||||
RTC_DCHECK(that);
|
result);
|
||||||
|
|
||||||
Scoped<GError> error;
|
|
||||||
Scoped<GVariant> variant(
|
|
||||||
g_dbus_proxy_call_finish(proxy, result, error.receive()));
|
|
||||||
if (!variant) {
|
|
||||||
if (g_error_matches(error.get(), G_IO_ERROR, G_IO_ERROR_CANCELLED))
|
|
||||||
return;
|
|
||||||
RTC_LOG(LS_ERROR) << "Failed to start the screen cast session: "
|
|
||||||
<< error->message;
|
|
||||||
that->PortalFailed(RequestResponse::kError);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
RTC_LOG(LS_INFO) << "Initializing the start of the screen cast session.";
|
|
||||||
|
|
||||||
Scoped<char> handle;
|
|
||||||
g_variant_get_child(variant.get(), 0, "o", handle.receive());
|
|
||||||
if (!handle) {
|
|
||||||
RTC_LOG(LS_ERROR)
|
|
||||||
<< "Failed to initialize the start of the screen cast session.";
|
|
||||||
if (that->start_request_signal_id_) {
|
|
||||||
g_dbus_connection_signal_unsubscribe(that->connection_,
|
|
||||||
that->start_request_signal_id_);
|
|
||||||
that->start_request_signal_id_ = 0;
|
|
||||||
}
|
|
||||||
that->PortalFailed(RequestResponse::kError);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
RTC_LOG(LS_INFO) << "Subscribed to the start signal.";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// static
|
// static
|
||||||
@ -525,8 +363,7 @@ void ScreenCastPortal::OnOpenPipeWireRemoteRequested(GDBusProxy* proxy,
|
|||||||
}
|
}
|
||||||
|
|
||||||
that->notifier_->OnScreenCastRequestResult(
|
that->notifier_->OnScreenCastRequestResult(
|
||||||
ScreenCastPortal::RequestResponse::kSuccess, that->pw_stream_node_id_,
|
RequestResponse::kSuccess, that->pw_stream_node_id_, that->pw_fd_);
|
||||||
that->pw_fd_);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace webrtc
|
} // namespace webrtc
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include "absl/types/optional.h"
|
#include "modules/desktop_capture/linux/wayland/xdg_desktop_portal_utils.h"
|
||||||
|
|
||||||
namespace webrtc {
|
namespace webrtc {
|
||||||
|
|
||||||
@ -43,20 +43,9 @@ class ScreenCastPortal {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Interface that must be implemented by the ScreenCastPortal consumers.
|
// Interface that must be implemented by the ScreenCastPortal consumers.
|
||||||
enum class RequestResponse {
|
|
||||||
// Success, the request is carried out.
|
|
||||||
kSuccess,
|
|
||||||
// The user cancelled the interaction.
|
|
||||||
kUserCancelled,
|
|
||||||
// The user interaction was ended in some other way.
|
|
||||||
kError,
|
|
||||||
|
|
||||||
kMaxValue = kError
|
|
||||||
};
|
|
||||||
|
|
||||||
class PortalNotifier {
|
class PortalNotifier {
|
||||||
public:
|
public:
|
||||||
virtual void OnScreenCastRequestResult(RequestResponse result,
|
virtual void OnScreenCastRequestResult(xdg_portal::RequestResponse result,
|
||||||
uint32_t stream_node_id,
|
uint32_t stream_node_id,
|
||||||
int fd) = 0;
|
int fd) = 0;
|
||||||
virtual void OnScreenCastSessionClosed() = 0;
|
virtual void OnScreenCastSessionClosed() = 0;
|
||||||
@ -66,7 +55,7 @@ class ScreenCastPortal {
|
|||||||
virtual ~PortalNotifier() = default;
|
virtual ~PortalNotifier() = default;
|
||||||
};
|
};
|
||||||
|
|
||||||
explicit ScreenCastPortal(CaptureSourceType source_type,
|
explicit ScreenCastPortal(ScreenCastPortal::CaptureSourceType source_type,
|
||||||
PortalNotifier* notifier);
|
PortalNotifier* notifier);
|
||||||
~ScreenCastPortal();
|
~ScreenCastPortal();
|
||||||
|
|
||||||
@ -79,6 +68,14 @@ class ScreenCastPortal {
|
|||||||
// information in order to continue working with PipeWire.
|
// information in order to continue working with PipeWire.
|
||||||
void Start();
|
void Start();
|
||||||
|
|
||||||
|
// Method to notify the reason for failure of a portal request.
|
||||||
|
void PortalFailed(xdg_portal::RequestResponse result);
|
||||||
|
|
||||||
|
// Sends a create session request to the portal.
|
||||||
|
void SessionRequest(GDBusProxy* proxy);
|
||||||
|
|
||||||
|
void UnsubscribeSignalHandlers();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
PortalNotifier* notifier_;
|
PortalNotifier* notifier_;
|
||||||
|
|
||||||
@ -104,19 +101,9 @@ class ScreenCastPortal {
|
|||||||
guint start_request_signal_id_ = 0;
|
guint start_request_signal_id_ = 0;
|
||||||
guint session_closed_signal_id_ = 0;
|
guint session_closed_signal_id_ = 0;
|
||||||
|
|
||||||
void PortalFailed(RequestResponse result);
|
|
||||||
|
|
||||||
uint32_t SetupRequestResponseSignal(const char* object_path,
|
|
||||||
GDBusSignalCallback callback);
|
|
||||||
|
|
||||||
static void OnProxyRequested(GObject* object,
|
static void OnProxyRequested(GObject* object,
|
||||||
GAsyncResult* result,
|
GAsyncResult* result,
|
||||||
gpointer user_data);
|
gpointer user_data);
|
||||||
|
|
||||||
static std::string PrepareSignalHandle(GDBusConnection* connection,
|
|
||||||
const char* token);
|
|
||||||
|
|
||||||
void SessionRequest();
|
|
||||||
static void OnSessionRequested(GDBusProxy* proxy,
|
static void OnSessionRequested(GDBusProxy* proxy,
|
||||||
GAsyncResult* result,
|
GAsyncResult* result,
|
||||||
gpointer user_data);
|
gpointer user_data);
|
||||||
|
@ -0,0 +1,169 @@
|
|||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
#include "modules/desktop_capture/linux/wayland/xdg_desktop_portal_utils.h"
|
||||||
|
|
||||||
|
#include "modules/desktop_capture/linux/wayland/scoped_glib.h"
|
||||||
|
#include "rtc_base/logging.h"
|
||||||
|
|
||||||
|
namespace webrtc {
|
||||||
|
namespace xdg_portal {
|
||||||
|
|
||||||
|
std::string RequestResponseToString(RequestResponse request) {
|
||||||
|
switch (request) {
|
||||||
|
case RequestResponse::kSuccess:
|
||||||
|
return "kSuccess";
|
||||||
|
case RequestResponse::kUserCancelled:
|
||||||
|
return "kUserCancelled";
|
||||||
|
case RequestResponse::kError:
|
||||||
|
return "kError";
|
||||||
|
default:
|
||||||
|
return "Uknown";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string PrepareSignalHandle(const char* token,
|
||||||
|
GDBusConnection* connection) {
|
||||||
|
Scoped<char> sender(
|
||||||
|
g_strdup(g_dbus_connection_get_unique_name(connection) + 1));
|
||||||
|
for (int i = 0; sender.get()[i]; ++i) {
|
||||||
|
if (sender.get()[i] == '.') {
|
||||||
|
sender.get()[i] = '_';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const char* handle = g_strconcat(kDesktopRequestObjectPath, "/", sender.get(),
|
||||||
|
"/", token, /*end of varargs*/ nullptr);
|
||||||
|
return handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t SetupRequestResponseSignal(const char* object_path,
|
||||||
|
const GDBusSignalCallback callback,
|
||||||
|
gpointer user_data,
|
||||||
|
GDBusConnection* connection) {
|
||||||
|
return g_dbus_connection_signal_subscribe(
|
||||||
|
connection, kDesktopBusName, kRequestInterfaceName, "Response",
|
||||||
|
object_path, /*arg0=*/nullptr, G_DBUS_SIGNAL_FLAGS_NO_MATCH_RULE,
|
||||||
|
callback, user_data, /*user_data_free_func=*/nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RequestSessionProxy(const char* interface_name,
|
||||||
|
const ProxyRequestCallback proxy_request_callback,
|
||||||
|
GCancellable* cancellable,
|
||||||
|
gpointer user_data) {
|
||||||
|
g_dbus_proxy_new_for_bus(
|
||||||
|
G_BUS_TYPE_SESSION, G_DBUS_PROXY_FLAGS_NONE, /*info=*/nullptr,
|
||||||
|
kDesktopBusName, kDesktopObjectPath, interface_name, cancellable,
|
||||||
|
reinterpret_cast<GAsyncReadyCallback>(proxy_request_callback), user_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetupSessionRequestHandlers(
|
||||||
|
const std::string& portal_prefix,
|
||||||
|
const SessionRequestCallback session_request_callback,
|
||||||
|
const SessionRequestResponseSignalHandler request_response_signale_handler,
|
||||||
|
GDBusConnection* connection,
|
||||||
|
GDBusProxy* proxy,
|
||||||
|
GCancellable* cancellable,
|
||||||
|
std::string& portal_handle,
|
||||||
|
guint& session_request_signal_id,
|
||||||
|
gpointer user_data) {
|
||||||
|
GVariantBuilder builder;
|
||||||
|
Scoped<char> variant_string;
|
||||||
|
|
||||||
|
g_variant_builder_init(&builder, G_VARIANT_TYPE_VARDICT);
|
||||||
|
variant_string = g_strdup_printf("%s_session%d", portal_prefix.c_str(),
|
||||||
|
g_random_int_range(0, G_MAXINT));
|
||||||
|
g_variant_builder_add(&builder, "{sv}", "session_handle_token",
|
||||||
|
g_variant_new_string(variant_string.get()));
|
||||||
|
|
||||||
|
variant_string = g_strdup_printf("%s_%d", portal_prefix.c_str(),
|
||||||
|
g_random_int_range(0, G_MAXINT));
|
||||||
|
g_variant_builder_add(&builder, "{sv}", "handle_token",
|
||||||
|
g_variant_new_string(variant_string.get()));
|
||||||
|
|
||||||
|
portal_handle = PrepareSignalHandle(variant_string.get(), connection);
|
||||||
|
session_request_signal_id = SetupRequestResponseSignal(
|
||||||
|
portal_handle.c_str(), request_response_signale_handler, user_data,
|
||||||
|
connection);
|
||||||
|
|
||||||
|
RTC_LOG(LS_INFO) << "Desktop session requested.";
|
||||||
|
g_dbus_proxy_call(
|
||||||
|
proxy, "CreateSession", g_variant_new("(a{sv})", &builder),
|
||||||
|
G_DBUS_CALL_FLAGS_NONE, /*timeout=*/-1, cancellable,
|
||||||
|
reinterpret_cast<GAsyncReadyCallback>(session_request_callback),
|
||||||
|
user_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
void StartSessionRequest(
|
||||||
|
const std::string& prefix,
|
||||||
|
const std::string session_handle,
|
||||||
|
const StartRequestResponseSignalHandler signal_handler,
|
||||||
|
const SessionStartRequestedHandler session_started_handler,
|
||||||
|
GDBusProxy* proxy,
|
||||||
|
GDBusConnection* connection,
|
||||||
|
GCancellable* cancellable,
|
||||||
|
guint& start_request_signal_id,
|
||||||
|
std::string& start_handle,
|
||||||
|
gpointer user_data) {
|
||||||
|
GVariantBuilder builder;
|
||||||
|
Scoped<char> variant_string;
|
||||||
|
|
||||||
|
g_variant_builder_init(&builder, G_VARIANT_TYPE_VARDICT);
|
||||||
|
variant_string =
|
||||||
|
g_strdup_printf("%s%d", prefix.c_str(), g_random_int_range(0, G_MAXINT));
|
||||||
|
g_variant_builder_add(&builder, "{sv}", "handle_token",
|
||||||
|
g_variant_new_string(variant_string.get()));
|
||||||
|
|
||||||
|
start_handle = PrepareSignalHandle(variant_string.get(), connection);
|
||||||
|
start_request_signal_id = SetupRequestResponseSignal(
|
||||||
|
start_handle.c_str(), signal_handler, user_data, connection);
|
||||||
|
|
||||||
|
// "Identifier for the application window", this is Wayland, so not "x11:...".
|
||||||
|
const char parent_window[] = "";
|
||||||
|
|
||||||
|
RTC_LOG(LS_INFO) << "Starting the portal session.";
|
||||||
|
g_dbus_proxy_call(
|
||||||
|
proxy, "Start",
|
||||||
|
g_variant_new("(osa{sv})", session_handle.c_str(), parent_window,
|
||||||
|
&builder),
|
||||||
|
G_DBUS_CALL_FLAGS_NONE, /*timeout=*/-1, cancellable,
|
||||||
|
reinterpret_cast<GAsyncReadyCallback>(session_started_handler),
|
||||||
|
user_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TearDownSession(std::string session_handle,
|
||||||
|
GDBusProxy* proxy,
|
||||||
|
GCancellable* cancellable,
|
||||||
|
GDBusConnection* connection) {
|
||||||
|
if (!session_handle.empty()) {
|
||||||
|
Scoped<GDBusMessage> message(
|
||||||
|
g_dbus_message_new_method_call(kDesktopBusName, session_handle.c_str(),
|
||||||
|
kSessionInterfaceName, "Close"));
|
||||||
|
if (message.get()) {
|
||||||
|
Scoped<GError> error;
|
||||||
|
g_dbus_connection_send_message(connection, message.get(),
|
||||||
|
G_DBUS_SEND_MESSAGE_FLAGS_NONE,
|
||||||
|
/*out_serial=*/nullptr, error.receive());
|
||||||
|
if (error.get()) {
|
||||||
|
RTC_LOG(LS_ERROR) << "Failed to close the session: " << error->message;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cancellable) {
|
||||||
|
g_cancellable_cancel(cancellable);
|
||||||
|
g_object_unref(cancellable);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (proxy) {
|
||||||
|
g_object_unref(proxy);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace xdg_portal
|
||||||
|
} // namespace webrtc
|
234
modules/desktop_capture/linux/wayland/xdg_desktop_portal_utils.h
Normal file
234
modules/desktop_capture/linux/wayland/xdg_desktop_portal_utils.h
Normal file
@ -0,0 +1,234 @@
|
|||||||
|
/*
|
||||||
|
* 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_DESKTOP_PORTAL_UTILS_H_
|
||||||
|
#define MODULES_DESKTOP_CAPTURE_LINUX_WAYLAND_XDG_DESKTOP_PORTAL_UTILS_H_
|
||||||
|
|
||||||
|
#include <gio/gio.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "modules/desktop_capture/linux/wayland/scoped_glib.h"
|
||||||
|
#include "rtc_base/checks.h"
|
||||||
|
#include "rtc_base/logging.h"
|
||||||
|
|
||||||
|
namespace webrtc {
|
||||||
|
namespace xdg_portal {
|
||||||
|
|
||||||
|
constexpr char kDesktopBusName[] = "org.freedesktop.portal.Desktop";
|
||||||
|
constexpr char kDesktopObjectPath[] = "/org/freedesktop/portal/desktop";
|
||||||
|
constexpr char kDesktopRequestObjectPath[] =
|
||||||
|
"/org/freedesktop/portal/desktop/request";
|
||||||
|
constexpr char kSessionInterfaceName[] = "org.freedesktop.portal.Session";
|
||||||
|
constexpr char kRequestInterfaceName[] = "org.freedesktop.portal.Request";
|
||||||
|
constexpr char kScreenCastInterfaceName[] = "org.freedesktop.portal.ScreenCast";
|
||||||
|
|
||||||
|
using ProxyRequestCallback = void (*)(GObject*, GAsyncResult*, gpointer);
|
||||||
|
using SessionRequestCallback = void (*)(GDBusProxy*, GAsyncResult*, gpointer);
|
||||||
|
using SessionRequestResponseSignalHandler = void (*)(GDBusConnection*,
|
||||||
|
const char*,
|
||||||
|
const char*,
|
||||||
|
const char*,
|
||||||
|
const char*,
|
||||||
|
GVariant*,
|
||||||
|
gpointer);
|
||||||
|
using SessionRequestResponseSignalCallback = void (*)(std::string);
|
||||||
|
using SessionClosedSignalHandler = void (*)(GDBusConnection*,
|
||||||
|
const char*,
|
||||||
|
const char*,
|
||||||
|
const char*,
|
||||||
|
const char*,
|
||||||
|
GVariant*,
|
||||||
|
gpointer);
|
||||||
|
using StartRequestResponseSignalHandler = void (*)(GDBusConnection*,
|
||||||
|
const char*,
|
||||||
|
const char*,
|
||||||
|
const char*,
|
||||||
|
const char*,
|
||||||
|
GVariant*,
|
||||||
|
gpointer);
|
||||||
|
using SessionStartRequestedHandler = void (*)(GDBusProxy*,
|
||||||
|
GAsyncResult*,
|
||||||
|
gpointer);
|
||||||
|
|
||||||
|
// Contains type of responses that can be observed when making a request to
|
||||||
|
// a desktop portal interface.
|
||||||
|
enum class RequestResponse {
|
||||||
|
// Success, the request is carried out.
|
||||||
|
kSuccess,
|
||||||
|
// The user cancelled the interaction.
|
||||||
|
kUserCancelled,
|
||||||
|
// The user interaction was ended in some other way.
|
||||||
|
kError,
|
||||||
|
|
||||||
|
kMaxValue = kError,
|
||||||
|
};
|
||||||
|
|
||||||
|
std::string RequestResponseToString(RequestResponse request);
|
||||||
|
|
||||||
|
// Returns a string path for signal handle based on the provided connection and
|
||||||
|
// token.
|
||||||
|
std::string PrepareSignalHandle(const char* token, GDBusConnection* connection);
|
||||||
|
|
||||||
|
// Sets up the callback to execute when a response signal is received for the
|
||||||
|
// given object.
|
||||||
|
uint32_t SetupRequestResponseSignal(const char* object_path,
|
||||||
|
const GDBusSignalCallback callback,
|
||||||
|
gpointer user_data,
|
||||||
|
GDBusConnection* connection);
|
||||||
|
|
||||||
|
void RequestSessionProxy(const char* interface_name,
|
||||||
|
const ProxyRequestCallback proxy_request_callback,
|
||||||
|
GCancellable* cancellable,
|
||||||
|
gpointer user_data);
|
||||||
|
|
||||||
|
void SetupSessionRequestHandlers(
|
||||||
|
const std::string& portal_prefix,
|
||||||
|
const SessionRequestCallback session_request_callback,
|
||||||
|
const SessionRequestResponseSignalHandler request_response_signale_handler,
|
||||||
|
GDBusConnection* connection,
|
||||||
|
GDBusProxy* proxy,
|
||||||
|
GCancellable* cancellable,
|
||||||
|
std::string& portal_handle,
|
||||||
|
guint& session_request_signal_id,
|
||||||
|
gpointer user_data);
|
||||||
|
|
||||||
|
void StartSessionRequest(
|
||||||
|
const std::string& prefix,
|
||||||
|
const std::string session_handle,
|
||||||
|
const StartRequestResponseSignalHandler signal_handler,
|
||||||
|
const SessionStartRequestedHandler session_started_handler,
|
||||||
|
GDBusProxy* proxy,
|
||||||
|
GDBusConnection* connection,
|
||||||
|
GCancellable* cancellable,
|
||||||
|
guint& start_request_signal_id,
|
||||||
|
std::string& start_handle,
|
||||||
|
gpointer user_data);
|
||||||
|
|
||||||
|
// Tears down the portal session and cleans up related objects.
|
||||||
|
void TearDownSession(std::string session_handle,
|
||||||
|
GDBusProxy* proxy,
|
||||||
|
GCancellable* cancellable,
|
||||||
|
GDBusConnection* connection);
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void RequestSessionUsingProxy(T* portal,
|
||||||
|
GObject* gobject,
|
||||||
|
GAsyncResult* result) {
|
||||||
|
RTC_DCHECK(portal);
|
||||||
|
Scoped<GError> error;
|
||||||
|
GDBusProxy* proxy = g_dbus_proxy_new_finish(result, error.receive());
|
||||||
|
if (!proxy) {
|
||||||
|
if (g_error_matches(error.get(), G_IO_ERROR, G_IO_ERROR_CANCELLED))
|
||||||
|
return;
|
||||||
|
RTC_LOG(LS_ERROR) << "Failed to get a proxy for the portal: "
|
||||||
|
<< error->message;
|
||||||
|
portal->PortalFailed(RequestResponse::kError);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
RTC_LOG(LS_INFO) << "Successfully created proxy for the portal.";
|
||||||
|
portal->SessionRequest(proxy);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void SessionRequestHandler(T* portal,
|
||||||
|
GDBusProxy* proxy,
|
||||||
|
GAsyncResult* result,
|
||||||
|
gpointer user_data) {
|
||||||
|
RTC_DCHECK(portal);
|
||||||
|
|
||||||
|
Scoped<GError> error;
|
||||||
|
Scoped<GVariant> variant(
|
||||||
|
g_dbus_proxy_call_finish(proxy, result, error.receive()));
|
||||||
|
if (!variant) {
|
||||||
|
if (g_error_matches(error.get(), G_IO_ERROR, G_IO_ERROR_CANCELLED))
|
||||||
|
return;
|
||||||
|
RTC_LOG(LS_ERROR) << "Failed to session: " << error->message;
|
||||||
|
portal->PortalFailed(RequestResponse::kError);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
RTC_LOG(LS_INFO) << "Initializing the session.";
|
||||||
|
|
||||||
|
Scoped<char> handle;
|
||||||
|
g_variant_get_child(variant.get(), /*index=*/0, /*format_string=*/"o",
|
||||||
|
&handle);
|
||||||
|
if (!handle) {
|
||||||
|
RTC_LOG(LS_ERROR) << "Failed to initialize the session.";
|
||||||
|
portal->UnsubscribeSignalHandlers();
|
||||||
|
portal->PortalFailed(RequestResponse::kError);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void SessionRequestResponseSignalHelper(
|
||||||
|
const SessionClosedSignalHandler session_close_signal_handler,
|
||||||
|
T* portal,
|
||||||
|
GDBusConnection* connection,
|
||||||
|
std::string& session_handle,
|
||||||
|
GVariant* parameters,
|
||||||
|
guint& session_closed_signal_id) {
|
||||||
|
uint32_t portal_response;
|
||||||
|
Scoped<GVariant> response_data;
|
||||||
|
g_variant_get(parameters, /*format_string=*/"(u@a{sv})", &portal_response,
|
||||||
|
response_data.receive());
|
||||||
|
Scoped<GVariant> g_session_handle(
|
||||||
|
g_variant_lookup_value(response_data.get(), /*key=*/"session_handle",
|
||||||
|
/*expected_type=*/nullptr));
|
||||||
|
session_handle = g_variant_dup_string(
|
||||||
|
/*value=*/g_session_handle.get(), /*length=*/nullptr);
|
||||||
|
|
||||||
|
if (session_handle.empty() || portal_response) {
|
||||||
|
RTC_LOG(LS_ERROR) << "Failed to request the session subscription.";
|
||||||
|
portal->PortalFailed(RequestResponse::kError);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
session_closed_signal_id = g_dbus_connection_signal_subscribe(
|
||||||
|
connection, kDesktopBusName, kSessionInterfaceName, /*member=*/"Closed",
|
||||||
|
session_handle.c_str(), /*arg0=*/nullptr, G_DBUS_SIGNAL_FLAGS_NONE,
|
||||||
|
session_close_signal_handler, portal, /*user_data_free_func=*/nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void StartRequestedHandler(T* portal, GDBusProxy* proxy, GAsyncResult* result) {
|
||||||
|
RTC_DCHECK(portal);
|
||||||
|
Scoped<GError> error;
|
||||||
|
Scoped<GVariant> variant(
|
||||||
|
g_dbus_proxy_call_finish(proxy, result, error.receive()));
|
||||||
|
if (!variant) {
|
||||||
|
if (g_error_matches(error.get(), G_IO_ERROR, G_IO_ERROR_CANCELLED))
|
||||||
|
return;
|
||||||
|
RTC_LOG(LS_ERROR) << "Failed to start the portal session: "
|
||||||
|
<< error->message;
|
||||||
|
portal->PortalFailed(RequestResponse::kError);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Scoped<char> handle;
|
||||||
|
g_variant_get_child(variant.get(), 0, "o", handle.receive());
|
||||||
|
if (!handle) {
|
||||||
|
RTC_LOG(LS_ERROR) << "Failed to initialize the start portal session.";
|
||||||
|
portal->UnsubscribeSignalHandlers();
|
||||||
|
portal->PortalFailed(RequestResponse::kError);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
RTC_LOG(LS_INFO) << "Subscribed to the start signal.";
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace xdg_portal
|
||||||
|
} // namespace webrtc
|
||||||
|
|
||||||
|
#endif // MODULES_DESKTOP_CAPTURE_LINUX_WAYLAND_XDG_DESKTOP_PORTAL_UTILS_H_
|
Reference in New Issue
Block a user