diff options
Diffstat (limited to 'third_party/libwebrtc/modules/portal')
13 files changed, 922 insertions, 0 deletions
diff --git a/third_party/libwebrtc/modules/portal/BUILD.gn b/third_party/libwebrtc/modules/portal/BUILD.gn new file mode 100644 index 0000000000..d7768b2323 --- /dev/null +++ b/third_party/libwebrtc/modules/portal/BUILD.gn @@ -0,0 +1,148 @@ +# 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. + +import("//build/config/linux/pkg_config.gni") +import("//tools/generate_stubs/rules.gni") +import("../../webrtc.gni") + +if ((is_linux || is_chromeos) && rtc_use_pipewire) { +if (!build_with_mozilla) { + pkg_config("gio") { + packages = [ + "gio-2.0", + "gio-unix-2.0", + ] + } + + pkg_config("pipewire") { + packages = [ "libpipewire-0.3" ] + if (!rtc_link_pipewire) { + ignore_libs = true + } + } + + pkg_config("gbm") { + packages = [ "gbm" ] + } + pkg_config("egl") { + packages = [ "egl" ] + } + pkg_config("epoxy") { + packages = [ "epoxy" ] + ignore_libs = true + } + pkg_config("libdrm") { + packages = [ "libdrm" ] + } + + if (!rtc_link_pipewire) { + # When libpipewire is not directly linked, use stubs to allow for dlopening of + # the binary. + generate_stubs("pipewire_stubs") { + configs = [ + "../../:common_config", + ":pipewire", + ] + deps = [ "../../rtc_base:logging" ] + extra_header = "pipewire_stub_header.fragment" + logging_function = "RTC_LOG(LS_VERBOSE)" + logging_include = "rtc_base/logging.h" + output_name = "pipewire_stubs" + path_from_source = "modules/portal" + sigs = [ "pipewire.sigs" ] + if (!build_with_chromium) { + macro_include = "rtc_base/system/no_cfi_icall.h" + macro_deps = [ "../../rtc_base/system:no_cfi_icall" ] + } + } + } + + config("pipewire_base") { + configs = [ + ":gio", + ":pipewire", + ] + } + + config("pipewire_all") { + configs = [ + ":pipewire_base", + ":gbm", + ":egl", + ":epoxy", + ":libdrm", + ] + } + + config("pipewire_config") { + defines = [ "WEBRTC_USE_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_castos) { + defines += [ "WEBRTC_USE_GIO" ] + } + } +} else { + config("pipewire_all") { + } + config("pipewire_config") { + } +} + + rtc_library("portal") { + sources = [ + "pipewire_utils.cc", + "pipewire_utils.h", + "portal_request_response.h", + "scoped_glib.cc", + "scoped_glib.h", + "xdg_desktop_portal_utils.cc", + "xdg_desktop_portal_utils.h", + "xdg_session_details.h", + ] + + configs += [ + ":gio", + ":pipewire", + ":pipewire_config", + ] + + deps = [ + "../../rtc_base:checks", + "../../rtc_base:logging", + "../../rtc_base:sanitizer", + "../../rtc_base/system:rtc_export", + ] + absl_deps = [ "//third_party/abseil-cpp/absl/strings" ] + + if (!rtc_link_pipewire) { + defines = [ "WEBRTC_DLOPEN_PIPEWIRE" ] + + deps += [ ":pipewire_stubs" ] + } + + if (build_with_mozilla) { + configs -= [ + ":gio", + ":pipewire", + ":pipewire_config", + ] + deps -= [ ":pipewire_stubs" ] + defines -= [ "WEBRTC_DLOPEN_PIPEWIRE" ] + public_deps = [ + "//third_party/pipewire", + "//third_party/drm", + "//third_party/gbm", + "//third_party/libepoxy" + ] + } + } +} + diff --git a/third_party/libwebrtc/modules/portal/OWNERS b/third_party/libwebrtc/modules/portal/OWNERS new file mode 100644 index 0000000000..e3bc32ee5c --- /dev/null +++ b/third_party/libwebrtc/modules/portal/OWNERS @@ -0,0 +1,2 @@ +alcooper@chromium.org +mfoltz@chromium.org diff --git a/third_party/libwebrtc/modules/portal/pipewire.sigs b/third_party/libwebrtc/modules/portal/pipewire.sigs new file mode 100644 index 0000000000..139a8c37a5 --- /dev/null +++ b/third_party/libwebrtc/modules/portal/pipewire.sigs @@ -0,0 +1,52 @@ +// Copyright 2018 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. + +//------------------------------------------------ +// Functions from PipeWire used in capturer code. +//------------------------------------------------ + +// core.h +int pw_core_disconnect(pw_core *core); + +// loop.h +void pw_loop_destroy(pw_loop *loop); +pw_loop * pw_loop_new(const spa_dict *props); + + +// pipewire.h +void pw_init(int *argc, char **argv[]); +const char* pw_get_library_version(); + +// properties.h +pw_properties * pw_properties_new_string(const char *args); + +// stream.h +void pw_stream_add_listener(pw_stream *stream, spa_hook *listener, const pw_stream_events *events, void *data); +int pw_stream_connect(pw_stream *stream, enum pw_direction direction, uint32_t target_id, enum pw_stream_flags flags, const spa_pod **params, uint32_t n_params); +int pw_stream_disconnect(pw_stream *stream); +pw_buffer *pw_stream_dequeue_buffer(pw_stream *stream); +void pw_stream_destroy(pw_stream *stream); +pw_stream * pw_stream_new(pw_core *core, const char *name, pw_properties *props); +int pw_stream_queue_buffer(pw_stream *stream, pw_buffer *buffer); +int pw_stream_set_active(pw_stream *stream, bool active); +int pw_stream_update_params(pw_stream *stream, const spa_pod **params, uint32_t n_params); +uint32_t pw_stream_get_node_id(pw_stream *stream); +pw_stream_state pw_stream_get_state(pw_stream *stream, const char **error); + +// thread-loop.h +void pw_thread_loop_destroy(pw_thread_loop *loop); +pw_thread_loop * pw_thread_loop_new(const char *name, const spa_dict *props); +int pw_thread_loop_start(pw_thread_loop *loop); +void pw_thread_loop_stop(pw_thread_loop *loop); +void pw_thread_loop_lock(pw_thread_loop *loop); +void pw_thread_loop_unlock(pw_thread_loop *loop); +pw_loop * pw_thread_loop_get_loop(pw_thread_loop *loop); +void pw_thread_loop_signal(pw_thread_loop *loop, bool wait_for_accept); +void pw_thread_loop_wait(pw_thread_loop *loop); + +// context.h +void pw_context_destroy(pw_context *context); +pw_context *pw_context_new(pw_loop *main_loop, pw_properties *props, size_t user_data_size); +pw_core * pw_context_connect(pw_context *context, pw_properties *properties, size_t user_data_size); +pw_core * pw_context_connect_fd(pw_context *context, int fd, pw_properties *properties, size_t user_data_size); diff --git a/third_party/libwebrtc/modules/portal/pipewire_stub_header.fragment b/third_party/libwebrtc/modules/portal/pipewire_stub_header.fragment new file mode 100644 index 0000000000..9d7dbd27c5 --- /dev/null +++ b/third_party/libwebrtc/modules/portal/pipewire_stub_header.fragment @@ -0,0 +1,8 @@ +// The extra include header needed in the generated stub file for defining +// various PipeWire types. + +extern "C" { + +#include <pipewire/pipewire.h> + +} diff --git a/third_party/libwebrtc/modules/portal/pipewire_utils.cc b/third_party/libwebrtc/modules/portal/pipewire_utils.cc new file mode 100644 index 0000000000..fd96b4a4db --- /dev/null +++ b/third_party/libwebrtc/modules/portal/pipewire_utils.cc @@ -0,0 +1,53 @@ +/* + * 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/portal/pipewire_utils.h" + +#include <pipewire/pipewire.h> + +#include "rtc_base/sanitizer.h" + +#if defined(WEBRTC_DLOPEN_PIPEWIRE) +#include "modules/portal/pipewire_stubs.h" +#endif // defined(WEBRTC_DLOPEN_PIPEWIRE) + +namespace webrtc { + +RTC_NO_SANITIZE("cfi-icall") +bool InitializePipeWire() { +#if defined(WEBRTC_DLOPEN_PIPEWIRE) + static constexpr char kPipeWireLib[] = "libpipewire-0.3.so.0"; + + using modules_portal::InitializeStubs; + using modules_portal::kModulePipewire; + + modules_portal::StubPathMap paths; + + // Check if the PipeWire library is available. + paths[kModulePipewire].push_back(kPipeWireLib); + + static bool result = InitializeStubs(paths); + + return result; +#else + return true; +#endif // defined(WEBRTC_DLOPEN_PIPEWIRE) +} + +PipeWireThreadLoopLock::PipeWireThreadLoopLock(pw_thread_loop* loop) + : loop_(loop) { + pw_thread_loop_lock(loop_); +} + +PipeWireThreadLoopLock::~PipeWireThreadLoopLock() { + pw_thread_loop_unlock(loop_); +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/modules/portal/pipewire_utils.h b/third_party/libwebrtc/modules/portal/pipewire_utils.h new file mode 100644 index 0000000000..0f5ccf3292 --- /dev/null +++ b/third_party/libwebrtc/modules/portal/pipewire_utils.h @@ -0,0 +1,35 @@ +/* + * 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_PORTAL_PIPEWIRE_UTILS_H_ +#define MODULES_PORTAL_PIPEWIRE_UTILS_H_ + +struct pw_thread_loop; + +namespace webrtc { + +// Prepare PipeWire so that it is ready to be used. If it needs to be dlopen'd +// this will do so. Note that this does not guarantee a PipeWire server is +// running nor does it establish a connection to one. +bool InitializePipeWire(); + +// Locks pw_thread_loop in the current scope +class PipeWireThreadLoopLock { + public: + explicit PipeWireThreadLoopLock(pw_thread_loop* loop); + ~PipeWireThreadLoopLock(); + + private: + pw_thread_loop* const loop_; +}; + +} // namespace webrtc + +#endif // MODULES_PORTAL_PIPEWIRE_UTILS_H_ diff --git a/third_party/libwebrtc/modules/portal/portal_gn/moz.build b/third_party/libwebrtc/modules/portal/portal_gn/moz.build new file mode 100644 index 0000000000..77603c780b --- /dev/null +++ b/third_party/libwebrtc/modules/portal/portal_gn/moz.build @@ -0,0 +1,109 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + + + ### This moz.build was AUTOMATICALLY GENERATED from a GN config, ### + ### DO NOT edit it by hand. ### +if CONFIG["MOZ_WIDGET_TOOLKIT"] == "gtk": + CXXFLAGS += CONFIG["MOZ_GTK3_CFLAGS"] + +COMPILE_FLAGS["OS_INCLUDES"] = [] +AllowCompilerWarnings() + +DEFINES["ABSL_ALLOCATOR_NOTHROW"] = "1" +DEFINES["RTC_DAV1D_IN_INTERNAL_DECODER_FACTORY"] = True +DEFINES["RTC_ENABLE_VP9"] = True +DEFINES["USE_AURA"] = "1" +DEFINES["USE_GLIB"] = "1" +DEFINES["USE_NSS_CERTS"] = "1" +DEFINES["USE_OZONE"] = "1" +DEFINES["USE_UDEV"] = True +DEFINES["WEBRTC_ENABLE_PROTOBUF"] = "0" +DEFINES["WEBRTC_LIBRARY_IMPL"] = True +DEFINES["WEBRTC_LINUX"] = True +DEFINES["WEBRTC_MOZILLA_BUILD"] = True +DEFINES["WEBRTC_NON_STATIC_TRACE_EVENT_HANDLERS"] = "0" +DEFINES["WEBRTC_POSIX"] = True +DEFINES["WEBRTC_STRICT_FIELD_TRIALS"] = "0" +DEFINES["WEBRTC_USE_PIPEWIRE"] = True +DEFINES["_FILE_OFFSET_BITS"] = "64" +DEFINES["_GNU_SOURCE"] = True +DEFINES["_LARGEFILE64_SOURCE"] = True +DEFINES["_LARGEFILE_SOURCE"] = True +DEFINES["__STDC_CONSTANT_MACROS"] = True +DEFINES["__STDC_FORMAT_MACROS"] = True + +FINAL_LIBRARY = "webrtc" + + +LOCAL_INCLUDES += [ + "!/ipc/ipdl/_ipdlheaders", + "!/third_party/libwebrtc/gen", + "/gfx/angle/checkout/include/", + "/ipc/chromium/src", + "/third_party/drm/drm/", + "/third_party/drm/drm/include/", + "/third_party/drm/drm/include/libdrm/", + "/third_party/gbm/gbm/", + "/third_party/libepoxy/libepoxy/include/", + "/third_party/libwebrtc/", + "/third_party/libwebrtc/third_party/abseil-cpp/", + "/third_party/pipewire/", + "/tools/profiler/public" +] + +UNIFIED_SOURCES += [ + "/third_party/libwebrtc/modules/portal/pipewire_utils.cc", + "/third_party/libwebrtc/modules/portal/scoped_glib.cc", + "/third_party/libwebrtc/modules/portal/xdg_desktop_portal_utils.cc" +] + +if not CONFIG["MOZ_DEBUG"]: + + DEFINES["DYNAMIC_ANNOTATIONS_ENABLED"] = "0" + DEFINES["NDEBUG"] = True + DEFINES["NVALGRIND"] = True + +if CONFIG["MOZ_DEBUG"] == "1": + + DEFINES["DYNAMIC_ANNOTATIONS_ENABLED"] = "1" + DEFINES["_DEBUG"] = True + +if CONFIG["CPU_ARCH"] == "aarch64": + + DEFINES["WEBRTC_ARCH_ARM64"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["CPU_ARCH"] == "arm": + + CXXFLAGS += [ + "-mfpu=neon" + ] + + DEFINES["WEBRTC_ARCH_ARM"] = True + DEFINES["WEBRTC_ARCH_ARM_V7"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["CPU_ARCH"] == "mips32": + + DEFINES["MIPS32_LE"] = True + DEFINES["MIPS_FPU_LE"] = True + +if CONFIG["CPU_ARCH"] == "x86": + + CXXFLAGS += [ + "-msse2" + ] + + DEFINES["WEBRTC_ENABLE_AVX2"] = True + +if CONFIG["CPU_ARCH"] == "x86_64": + + DEFINES["WEBRTC_ENABLE_AVX2"] = True + +if CONFIG["MOZ_X11"] == "1" and CONFIG["OS_TARGET"] == "Linux": + + DEFINES["USE_X11"] = "1" + +Library("portal_gn") diff --git a/third_party/libwebrtc/modules/portal/portal_request_response.h b/third_party/libwebrtc/modules/portal/portal_request_response.h new file mode 100644 index 0000000000..5fac4eb137 --- /dev/null +++ b/third_party/libwebrtc/modules/portal/portal_request_response.h @@ -0,0 +1,34 @@ +/* + * 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_PORTAL_PORTAL_REQUEST_RESPONSE_H_ +#define MODULES_PORTAL_PORTAL_REQUEST_RESPONSE_H_ + +namespace webrtc { +namespace xdg_portal { + +// Contains type of responses that can be observed when making a request to +// a desktop portal interface. +enum class RequestResponse { + // Unknown, the initialized status. + kUnknown, + // 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, +}; + +} // namespace xdg_portal +} // namespace webrtc +#endif // MODULES_PORTAL_PORTAL_REQUEST_RESPONSE_H_ diff --git a/third_party/libwebrtc/modules/portal/scoped_glib.cc b/third_party/libwebrtc/modules/portal/scoped_glib.cc new file mode 100644 index 0000000000..31ba8cb77a --- /dev/null +++ b/third_party/libwebrtc/modules/portal/scoped_glib.cc @@ -0,0 +1,64 @@ +/* + * 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/portal/scoped_glib.h" + +namespace webrtc { + +template class RTC_EXPORT_TEMPLATE_DEFINE(RTC_EXPORT) Scoped<GError>; +template class RTC_EXPORT_TEMPLATE_DEFINE(RTC_EXPORT) Scoped<char>; +template class RTC_EXPORT_TEMPLATE_DEFINE(RTC_EXPORT) Scoped<GVariant>; +template class RTC_EXPORT_TEMPLATE_DEFINE(RTC_EXPORT) Scoped<GVariantIter>; +template class RTC_EXPORT_TEMPLATE_DEFINE(RTC_EXPORT) Scoped<GDBusMessage>; +template class RTC_EXPORT_TEMPLATE_DEFINE(RTC_EXPORT) Scoped<GUnixFDList>; + +template <> +Scoped<GError>::~Scoped() { + if (ptr_) { + g_error_free(ptr_); + } +} + +template <> +Scoped<char>::~Scoped() { + if (ptr_) { + g_free(ptr_); + } +} + +template <> +Scoped<GVariant>::~Scoped() { + if (ptr_) { + g_variant_unref(ptr_); + } +} + +template <> +Scoped<GVariantIter>::~Scoped() { + if (ptr_) { + g_variant_iter_free(ptr_); + } +} + +template <> +Scoped<GDBusMessage>::~Scoped() { + if (ptr_) { + g_object_unref(ptr_); + } +} + +template <> +Scoped<GUnixFDList>::~Scoped() { + if (ptr_) { + g_object_unref(ptr_); + } +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/modules/portal/scoped_glib.h b/third_party/libwebrtc/modules/portal/scoped_glib.h new file mode 100644 index 0000000000..d97e47ae1f --- /dev/null +++ b/third_party/libwebrtc/modules/portal/scoped_glib.h @@ -0,0 +1,76 @@ +/* + * 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_PORTAL_SCOPED_GLIB_H_ +#define MODULES_PORTAL_SCOPED_GLIB_H_ + +#include <gio/gio.h> + +#include "rtc_base/checks.h" +#include "rtc_base/system/rtc_export_template.h" + +namespace webrtc { + +template <class T> +class Scoped { + public: + Scoped() {} + explicit Scoped(T* val) { ptr_ = val; } + ~Scoped() { RTC_DCHECK_NOTREACHED(); } + + T* operator->() const { return ptr_; } + + explicit operator bool() const { return ptr_ != nullptr; } + + bool operator!() const { return ptr_ == nullptr; } + + T* get() const { return ptr_; } + + T** receive() { + RTC_CHECK(!ptr_); + return &ptr_; + } + + Scoped& operator=(T* val) { + RTC_DCHECK(val); + ptr_ = val; + return *this; + } + + protected: + T* ptr_ = nullptr; +}; + +template <> +Scoped<GError>::~Scoped(); +template <> +Scoped<char>::~Scoped(); +template <> +Scoped<GVariant>::~Scoped(); +template <> +Scoped<GVariantIter>::~Scoped(); +template <> +Scoped<GDBusMessage>::~Scoped(); +template <> +Scoped<GUnixFDList>::~Scoped(); + +extern template class RTC_EXPORT_TEMPLATE_DECLARE(RTC_EXPORT) Scoped<GError>; +extern template class RTC_EXPORT_TEMPLATE_DECLARE(RTC_EXPORT) Scoped<char>; +extern template class RTC_EXPORT_TEMPLATE_DECLARE(RTC_EXPORT) Scoped<GVariant>; +extern template class RTC_EXPORT_TEMPLATE_DECLARE( + RTC_EXPORT) Scoped<GVariantIter>; +extern template class RTC_EXPORT_TEMPLATE_DECLARE( + RTC_EXPORT) Scoped<GDBusMessage>; +extern template class RTC_EXPORT_TEMPLATE_DECLARE( + RTC_EXPORT) Scoped<GUnixFDList>; + +} // namespace webrtc + +#endif // MODULES_PORTAL_SCOPED_GLIB_H_ diff --git a/third_party/libwebrtc/modules/portal/xdg_desktop_portal_utils.cc b/third_party/libwebrtc/modules/portal/xdg_desktop_portal_utils.cc new file mode 100644 index 0000000000..271e084463 --- /dev/null +++ b/third_party/libwebrtc/modules/portal/xdg_desktop_portal_utils.cc @@ -0,0 +1,195 @@ +/* + * 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/portal/xdg_desktop_portal_utils.h" + +#include <string> + +#include "absl/strings/string_view.h" +#include "modules/portal/scoped_glib.h" +#include "rtc_base/logging.h" + +namespace webrtc { +namespace xdg_portal { + +std::string RequestResponseToString(RequestResponse request) { + switch (request) { + case RequestResponse::kUnknown: + return "kUnknown"; + case RequestResponse::kSuccess: + return "kSuccess"; + case RequestResponse::kUserCancelled: + return "kUserCancelled"; + case RequestResponse::kError: + return "kError"; + default: + return "Uknown"; + } +} + +RequestResponse RequestResponseFromPortalResponse(uint32_t portal_response) { + // See: + // https://docs.flatpak.org/en/latest/portal-api-reference.html#gdbus-signal-org-freedesktop-portal-Request.Response + switch (portal_response) { + case 0: + return RequestResponse::kSuccess; + case 1: + return RequestResponse::kUserCancelled; + case 2: + return RequestResponse::kError; + default: + return RequestResponse::kUnknown; + } +} + +std::string PrepareSignalHandle(absl::string_view 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(), "/", + std::string(token).c_str(), /*end of varargs*/ nullptr); + return handle; +} + +uint32_t SetupRequestResponseSignal(absl::string_view object_path, + const GDBusSignalCallback callback, + gpointer user_data, + GDBusConnection* connection) { + return g_dbus_connection_signal_subscribe( + connection, kDesktopBusName, kRequestInterfaceName, "Response", + std::string(object_path).c_str(), /*arg0=*/nullptr, + G_DBUS_SIGNAL_FLAGS_NO_MATCH_RULE, callback, user_data, + /*user_data_free_func=*/nullptr); +} + +void RequestSessionProxy(absl::string_view 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, std::string(interface_name).c_str(), + cancellable, + reinterpret_cast<GAsyncReadyCallback>(proxy_request_callback), user_data); +} + +void SetupSessionRequestHandlers( + absl::string_view 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", static_cast<int>(portal_prefix.size()), + portal_prefix.data(), 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", static_cast<int>(portal_prefix.size()), + portal_prefix.data(), 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( + absl::string_view prefix, + absl::string_view 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", static_cast<int>(prefix.size()), prefix.data(), + 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})", std::string(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(absl::string_view session_handle, + GDBusProxy* proxy, + GCancellable* cancellable, + GDBusConnection* connection) { + if (!session_handle.empty()) { + Scoped<GDBusMessage> message(g_dbus_message_new_method_call( + kDesktopBusName, std::string(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 diff --git a/third_party/libwebrtc/modules/portal/xdg_desktop_portal_utils.h b/third_party/libwebrtc/modules/portal/xdg_desktop_portal_utils.h new file mode 100644 index 0000000000..eff46a01ab --- /dev/null +++ b/third_party/libwebrtc/modules/portal/xdg_desktop_portal_utils.h @@ -0,0 +1,113 @@ +/* + * 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_PORTAL_XDG_DESKTOP_PORTAL_UTILS_H_ +#define MODULES_PORTAL_XDG_DESKTOP_PORTAL_UTILS_H_ + +#include <gio/gio.h> +#include <stdint.h> + +#include <string> +#include <vector> + +#include "absl/strings/string_view.h" +#include "modules/portal/portal_request_response.h" +#include "modules/portal/scoped_glib.h" +#include "modules/portal/xdg_session_details.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 StartRequestResponseSignalHandler = void (*)(GDBusConnection*, + const char*, + const char*, + const char*, + const char*, + GVariant*, + gpointer); +using SessionStartRequestedHandler = void (*)(GDBusProxy*, + GAsyncResult*, + gpointer); + +RTC_EXPORT std::string RequestResponseToString(RequestResponse request); + +RequestResponse RequestResponseFromPortalResponse(uint32_t portal_response); + +// Returns a string path for signal handle based on the provided connection and +// token. +RTC_EXPORT std::string PrepareSignalHandle(absl::string_view token, + GDBusConnection* connection); + +// Sets up the callback to execute when a response signal is received for the +// given object. +RTC_EXPORT uint32_t +SetupRequestResponseSignal(absl::string_view object_path, + const GDBusSignalCallback callback, + gpointer user_data, + GDBusConnection* connection); + +RTC_EXPORT void RequestSessionProxy( + absl::string_view interface_name, + const ProxyRequestCallback proxy_request_callback, + GCancellable* cancellable, + gpointer user_data); + +RTC_EXPORT void SetupSessionRequestHandlers( + absl::string_view 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); + +RTC_EXPORT void StartSessionRequest( + absl::string_view prefix, + absl::string_view 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. +RTC_EXPORT void TearDownSession(absl::string_view session_handle, + GDBusProxy* proxy, + GCancellable* cancellable, + GDBusConnection* connection); + +} // namespace xdg_portal +} // namespace webrtc + +#endif // MODULES_PORTAL_XDG_DESKTOP_PORTAL_UTILS_H_ diff --git a/third_party/libwebrtc/modules/portal/xdg_session_details.h b/third_party/libwebrtc/modules/portal/xdg_session_details.h new file mode 100644 index 0000000000..ab52508c2f --- /dev/null +++ b/third_party/libwebrtc/modules/portal/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_PORTAL_XDG_SESSION_DETAILS_H_ +#define MODULES_PORTAL_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_PORTAL_XDG_SESSION_DETAILS_H_ |