diff --git a/BUILD.gn b/BUILD.gn index a45bea091f..860382e9ad 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -131,6 +131,14 @@ config("common_inherited_config") { # Allow includes to be prefixed with webrtc/ in case it is not an # immediate subdirectory of the top-level. ".", + + # Just like the root WebRTC directory is added to include path, the + # corresponding directory tree with generated files needs to be added too. + # Note: this path does not change depending on the current target, e.g. + # it is always "//gen/third_party/webrtc" when building with Chromium. + # See also: http://cs.chromium.org/?q=%5C"default_include_dirs + # https://gn.googlesource.com/gn/+/master/docs/reference.md#target_gen_dir + target_gen_dir, ] } if (is_posix || is_fuchsia) { diff --git a/modules/desktop_capture/BUILD.gn b/modules/desktop_capture/BUILD.gn index 390fc0a051..0677a79ff5 100644 --- a/modules/desktop_capture/BUILD.gn +++ b/modules/desktop_capture/BUILD.gn @@ -8,6 +8,7 @@ import("//build/config/linux/pkg_config.gni") import("//build/config/ui.gni") +import("//tools/generate_stubs/rules.gni") import("../../webrtc.gni") use_desktop_capture_differ_sse2 = current_cpu == "x86" || current_cpu == "x64" @@ -166,18 +167,40 @@ if (rtc_include_tests) { if (is_linux) { if (rtc_use_pipewire) { - pkg_config("pipewire") { - packages = [ "libpipewire-0.2" ] - - defines = [ "WEBRTC_USE_PIPEWIRE" ] - } - pkg_config("gio") { packages = [ "gio-2.0", "gio-unix-2.0", ] } + + if (rtc_link_pipewire) { + pkg_config("pipewire") { + packages = [ "libpipewire-0.2" ] + } + } else { + # When libpipewire is not directly linked, use stubs to allow for dlopening of + # the binary. + generate_stubs("pipewire_stubs") { + configs = [ "../../:common_config" ] + deps = [ + "../../rtc_base", + ] + extra_header = "linux/pipewire_stub_header.fragment" + logging_function = "RTC_LOG(LS_VERBOSE)" + logging_include = "rtc_base/logging.h" + output_name = "linux/pipewire_stubs" + path_from_source = "modules/desktop_capture/linux" + sigs = [ "linux/pipewire.sigs" ] + } + } + + config("pipewire_config") { + defines = [ "WEBRTC_USE_PIPEWIRE" ] + if (!rtc_link_pipewire) { + defines += [ "WEBRTC_DLOPEN_PIPEWIRE" ] + } + } } } @@ -384,22 +407,6 @@ rtc_static_library("desktop_capture_generic") { } } - if (rtc_use_pipewire) { - sources += [ - "linux/base_capturer_pipewire.cc", - "linux/base_capturer_pipewire.h", - "linux/screen_capturer_pipewire.cc", - "linux/screen_capturer_pipewire.h", - "linux/window_capturer_pipewire.cc", - "linux/window_capturer_pipewire.h", - ] - - configs += [ - ":gio", - ":pipewire", - ] - } - if (!is_win && !is_mac && !rtc_use_x11 && !rtc_use_pipewire) { sources += [ "mouse_cursor_monitor_null.cc", @@ -438,6 +445,28 @@ rtc_static_library("desktop_capture_generic") { if (use_desktop_capture_differ_sse2) { deps += [ ":desktop_capture_differ_sse2" ] } + + if (rtc_use_pipewire) { + sources += [ + "linux/base_capturer_pipewire.cc", + "linux/base_capturer_pipewire.h", + "linux/screen_capturer_pipewire.cc", + "linux/screen_capturer_pipewire.h", + "linux/window_capturer_pipewire.cc", + "linux/window_capturer_pipewire.h", + ] + + configs += [ + ":pipewire_config", + ":gio", + ] + + if (rtc_link_pipewire) { + configs += [ ":pipewire" ] + } else { + deps += [ ":pipewire_stubs" ] + } + } } if (use_desktop_capture_differ_sse2) { diff --git a/modules/desktop_capture/linux/base_capturer_pipewire.cc b/modules/desktop_capture/linux/base_capturer_pipewire.cc index 62d9994d32..05ad86f762 100644 --- a/modules/desktop_capture/linux/base_capturer_pipewire.cc +++ b/modules/desktop_capture/linux/base_capturer_pipewire.cc @@ -27,6 +27,14 @@ #include "rtc_base/checks.h" #include "rtc_base/logging.h" +#if defined(WEBRTC_DLOPEN_PIPEWIRE) +#include "modules/desktop_capture/linux/pipewire_stubs.h" + +using modules_desktop_capture_linux::InitializeStubs; +using modules_desktop_capture_linux::kModulePipewire; +using modules_desktop_capture_linux::StubPathMap; +#endif // defined(WEBRTC_DLOPEN_PIPEWIRE) + namespace webrtc { const char kDesktopBusName[] = "org.freedesktop.portal.Desktop"; @@ -39,6 +47,10 @@ const char kScreenCastInterfaceName[] = "org.freedesktop.portal.ScreenCast"; const int kBytesPerPixel = 4; +#if defined(WEBRTC_DLOPEN_PIPEWIRE) +const char kPipeWireLib[] = "libpipewire-0.2.so.1"; +#endif + // static void BaseCapturerPipeWire::OnStateChanged(void* data, pw_remote_state old_state, @@ -251,6 +263,18 @@ void BaseCapturerPipeWire::InitPortal() { } void BaseCapturerPipeWire::InitPipeWire() { +#if defined(WEBRTC_DLOPEN_PIPEWIRE) + StubPathMap paths; + + // Check if the PipeWire library is available. + paths[kModulePipewire].push_back(kPipeWireLib); + if (!InitializeStubs(paths)) { + RTC_LOG(LS_ERROR) << "Failed to load the PipeWire library and symbols."; + portal_init_failed_ = true; + return; + } +#endif // defined(WEBRTC_DLOPEN_PIPEWIRE) + pw_init(/*argc=*/nullptr, /*argc=*/nullptr); pw_loop_ = pw_loop_new(/*properties=*/nullptr); @@ -279,6 +303,8 @@ void BaseCapturerPipeWire::InitPipeWire() { RTC_LOG(LS_ERROR) << "Failed to start main PipeWire loop"; portal_init_failed_ = true; } + + RTC_LOG(LS_INFO) << "PipeWire remote opened."; } void BaseCapturerPipeWire::InitPipeWireTypes() { @@ -300,8 +326,8 @@ void BaseCapturerPipeWire::CreateReceivingStream() { spa_fraction pwFrameRateMin = spa_fraction{0, 1}; spa_fraction pwFrameRateMax = spa_fraction{60, 1}; - pw_properties* reuseProps = pw_properties_new("pipewire.client.reuse", "1", - /*end of varargs*/ nullptr); + pw_properties* reuseProps = + pw_properties_new_string("pipewire.client.reuse=1"); pw_stream_ = pw_stream_new(pw_remote_, "webrtc-consume-stream", reuseProps); uint8_t buffer[1024] = {}; @@ -793,7 +819,6 @@ void BaseCapturerPipeWire::OnOpenPipeWireRemoteRequested( g_object_unref(outlist); that->InitPipeWire(); - RTC_LOG(LS_INFO) << "PipeWire remote opened."; } void BaseCapturerPipeWire::Start(Callback* callback) { diff --git a/modules/desktop_capture/linux/pipewire.sigs b/modules/desktop_capture/linux/pipewire.sigs new file mode 100644 index 0000000000..3e21e9dc07 --- /dev/null +++ b/modules/desktop_capture/linux/pipewire.sigs @@ -0,0 +1,44 @@ +// 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 +void pw_core_destroy(pw_core *core); +pw_type *pw_core_get_type(pw_core *core); +pw_core * pw_core_new(pw_loop *main_loop, pw_properties *props); + +// loop.h +void pw_loop_destroy(pw_loop *loop); +pw_loop * pw_loop_new(pw_properties *properties); + +// pipewire.h +void pw_init(int *argc, char **argv[]); + +// properties.h +pw_properties * pw_properties_new_string(const char *args); + +// remote.h +void pw_remote_add_listener(pw_remote *remote, spa_hook *listener, const pw_remote_events *events, void *data); +int pw_remote_connect_fd(pw_remote *remote, int fd); +void pw_remote_destroy(pw_remote *remote); +pw_remote * pw_remote_new(pw_core *core, pw_properties *properties, size_t user_data_size); + +// 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, const char *port_path, enum pw_stream_flags flags, const spa_pod **params, uint32_t n_params); +pw_buffer *pw_stream_dequeue_buffer(pw_stream *stream); +void pw_stream_destroy(pw_stream *stream); +void pw_stream_finish_format(pw_stream *stream, int res, const spa_pod **params, uint32_t n_params); +pw_stream * pw_stream_new(pw_remote *remote, 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); + +// thread-loop.h +void pw_thread_loop_destroy(pw_thread_loop *loop); +pw_thread_loop * pw_thread_loop_new(pw_loop *loop, const char *name); +int pw_thread_loop_start(pw_thread_loop *loop); +void pw_thread_loop_stop(pw_thread_loop *loop); diff --git a/modules/desktop_capture/linux/pipewire_stub_header.fragment b/modules/desktop_capture/linux/pipewire_stub_header.fragment new file mode 100644 index 0000000000..9d7dbd27c5 --- /dev/null +++ b/modules/desktop_capture/linux/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 + +} diff --git a/webrtc.gni b/webrtc.gni index 7c24c79c75..5c0c107c0a 100644 --- a/webrtc.gni +++ b/webrtc.gni @@ -109,7 +109,10 @@ declare_args() { rtc_use_x11 = use_x11 # Set this to use PipeWire on the Wayland display server. - rtc_use_pipewire = false + rtc_use_pipewire = is_linux && use_sysroot + + # Set this to link PipeWire directly instead of using the dlopen. + rtc_link_pipewire = false # Enable to use the Mozilla internal settings. build_with_mozilla = false