From e25e98b906cade4abb2078e31cedb00b95b5c40a Mon Sep 17 00:00:00 2001 From: Alex Cooper Date: Tue, 25 Oct 2022 11:34:45 -0700 Subject: [PATCH] Improve Capturer Selection on Wayland It doesn't really make sense to try to create the X11 capturer if we are running under Wayland; nor does it make sense to create the PipeWire capturer if we are going to fail to actually start a stream with it. This change addresses both of these issues by exposing an IsSupported method on BaseCapturerPipeWire and checking that we are not running under Wayland before creating the X11 capturer. Bug: chromium:1374436 Change-Id: Ieb291307376010e084824124ea8fde065545337c Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/279163 Auto-Submit: Alexander Cooper Reviewed-by: Mark Foltz Commit-Queue: Alexander Cooper Cr-Commit-Position: refs/heads/main@{#38474} --- modules/desktop_capture/BUILD.gn | 2 + .../linux/wayland/base_capturer_pipewire.cc | 14 ++++++- .../linux/wayland/base_capturer_pipewire.h | 6 +++ .../linux/wayland/pipewire_utils.cc | 42 +++++++++++++++++++ .../linux/wayland/pipewire_utils.h | 23 ++++++++++ .../linux/wayland/shared_screencast_stream.cc | 25 ++--------- .../test/test_screencast_stream_provider.cc | 25 ++--------- .../desktop_capture/screen_capturer_linux.cc | 9 ++-- .../desktop_capture/window_capturer_linux.cc | 9 ++-- 9 files changed, 102 insertions(+), 53 deletions(-) create mode 100644 modules/desktop_capture/linux/wayland/pipewire_utils.cc create mode 100644 modules/desktop_capture/linux/wayland/pipewire_utils.h diff --git a/modules/desktop_capture/BUILD.gn b/modules/desktop_capture/BUILD.gn index 482b03c958..34a5704b40 100644 --- a/modules/desktop_capture/BUILD.gn +++ b/modules/desktop_capture/BUILD.gn @@ -644,6 +644,8 @@ rtc_library("desktop_capture") { "linux/wayland/egl_dmabuf.h", "linux/wayland/mouse_cursor_monitor_pipewire.cc", "linux/wayland/mouse_cursor_monitor_pipewire.h", + "linux/wayland/pipewire_utils.cc", + "linux/wayland/pipewire_utils.h", "linux/wayland/portal_request_response.h", "linux/wayland/restore_token_manager.cc", "linux/wayland/restore_token_manager.h", diff --git a/modules/desktop_capture/linux/wayland/base_capturer_pipewire.cc b/modules/desktop_capture/linux/wayland/base_capturer_pipewire.cc index 3d006c5f6c..a0af638d00 100644 --- a/modules/desktop_capture/linux/wayland/base_capturer_pipewire.cc +++ b/modules/desktop_capture/linux/wayland/base_capturer_pipewire.cc @@ -12,11 +12,11 @@ #include "modules/desktop_capture/desktop_capture_options.h" #include "modules/desktop_capture/desktop_capturer.h" +#include "modules/desktop_capture/linux/wayland/pipewire_utils.h" #include "modules/desktop_capture/linux/wayland/restore_token_manager.h" #include "modules/desktop_capture/linux/wayland/xdg_desktop_portal_utils.h" #include "rtc_base/checks.h" #include "rtc_base/logging.h" -#include "screencast_portal.h" namespace webrtc { @@ -28,6 +28,18 @@ using xdg_portal::SessionDetails; } // namespace +// static +bool BaseCapturerPipeWire::IsSupported() { + // Unfortunately, the best way we have to check if PipeWire is available is + // to try to initialize it. + // InitializePipeWire should prevent us from repeatedly initializing PipeWire, + // but we also don't really expect support to change without the application + // restarting. + static bool supported = + DesktopCapturer::IsRunningUnderWayland() && InitializePipeWire(); + return supported; +} + BaseCapturerPipeWire::BaseCapturerPipeWire(const DesktopCaptureOptions& options, CaptureType type) : BaseCapturerPipeWire(options, diff --git a/modules/desktop_capture/linux/wayland/base_capturer_pipewire.h b/modules/desktop_capture/linux/wayland/base_capturer_pipewire.h index a852f44ade..d84718aea4 100644 --- a/modules/desktop_capture/linux/wayland/base_capturer_pipewire.h +++ b/modules/desktop_capture/linux/wayland/base_capturer_pipewire.h @@ -27,6 +27,12 @@ class BaseCapturerPipeWire : public DesktopCapturer, public DelegatedSourceListController, public ScreenCastPortal::PortalNotifier { public: + // Returns whether or not the current system can support capture via PipeWire. + // This will only be true on Wayland systems that also have PipeWire + // available, and thus may require dlopening PipeWire to determine if it is + // available. + static bool IsSupported(); + BaseCapturerPipeWire(const DesktopCaptureOptions& options, CaptureType type); BaseCapturerPipeWire( const DesktopCaptureOptions& options, diff --git a/modules/desktop_capture/linux/wayland/pipewire_utils.cc b/modules/desktop_capture/linux/wayland/pipewire_utils.cc new file mode 100644 index 0000000000..878e459681 --- /dev/null +++ b/modules/desktop_capture/linux/wayland/pipewire_utils.cc @@ -0,0 +1,42 @@ +/* + * 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/pipewire_utils.h" + +#include "rtc_base/sanitizer.h" + +#if defined(WEBRTC_DLOPEN_PIPEWIRE) +#include "modules/desktop_capture/linux/wayland/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_desktop_capture_linux_wayland::InitializeStubs; + using modules_desktop_capture_linux_wayland::kModulePipewire; + + modules_desktop_capture_linux_wayland::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) +} + +} // namespace webrtc diff --git a/modules/desktop_capture/linux/wayland/pipewire_utils.h b/modules/desktop_capture/linux/wayland/pipewire_utils.h new file mode 100644 index 0000000000..b785d395bd --- /dev/null +++ b/modules/desktop_capture/linux/wayland/pipewire_utils.h @@ -0,0 +1,23 @@ +/* + * 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_PIPEWIRE_UTILS_H_ +#define MODULES_DESKTOP_CAPTURE_LINUX_WAYLAND_PIPEWIRE_UTILS_H_ + +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(); + +} // namespace webrtc + +#endif // MODULES_DESKTOP_CAPTURE_LINUX_WAYLAND_PIPEWIRE_UTILS_H_ diff --git a/modules/desktop_capture/linux/wayland/shared_screencast_stream.cc b/modules/desktop_capture/linux/wayland/shared_screencast_stream.cc index 615d42e2ee..4651486223 100644 --- a/modules/desktop_capture/linux/wayland/shared_screencast_stream.cc +++ b/modules/desktop_capture/linux/wayland/shared_screencast_stream.cc @@ -20,28 +20,18 @@ #include "absl/memory/memory.h" #include "modules/desktop_capture/linux/wayland/egl_dmabuf.h" +#include "modules/desktop_capture/linux/wayland/pipewire_utils.h" #include "modules/desktop_capture/linux/wayland/screencast_stream_utils.h" #include "rtc_base/checks.h" #include "rtc_base/logging.h" #include "rtc_base/sanitizer.h" #include "rtc_base/synchronization/mutex.h" -#if defined(WEBRTC_DLOPEN_PIPEWIRE) -#include "modules/desktop_capture/linux/wayland/pipewire_stubs.h" -using modules_desktop_capture_linux_wayland::InitializeStubs; -using modules_desktop_capture_linux_wayland::kModulePipewire; -using modules_desktop_capture_linux_wayland::StubPathMap; -#endif // defined(WEBRTC_DLOPEN_PIPEWIRE) - namespace webrtc { const int kBytesPerPixel = 4; const int kVideoDamageRegionCount = 16; -#if defined(WEBRTC_DLOPEN_PIPEWIRE) -const char kPipeWireLib[] = "libpipewire-0.3.so.0"; -#endif - constexpr int kCursorBpp = 4; constexpr int CursorMetaSize(int w, int h) { return (sizeof(struct spa_meta_cursor) + sizeof(struct spa_meta_bitmap) + @@ -389,19 +379,10 @@ bool SharedScreenCastStreamPrivate::StartScreenCastStream( uint32_t height) { width_ = width; height_ = height; -#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) - << "One of following libraries is missing on your system:\n" - << " - PipeWire (" << kPipeWireLib << ")\n"; + if (!InitializePipeWire()) { + RTC_LOG(LS_ERROR) << "Unable to open PipeWire library"; return false; } -#endif // defined(WEBRTC_DLOPEN_PIPEWIRE) egl_dmabuf_ = std::make_unique(); pw_stream_node_id_ = stream_node_id; diff --git a/modules/desktop_capture/linux/wayland/test/test_screencast_stream_provider.cc b/modules/desktop_capture/linux/wayland/test/test_screencast_stream_provider.cc index c49823d510..bf212d0650 100644 --- a/modules/desktop_capture/linux/wayland/test/test_screencast_stream_provider.cc +++ b/modules/desktop_capture/linux/wayland/test/test_screencast_stream_provider.cc @@ -20,40 +20,21 @@ #include #include +#include "modules/desktop_capture/linux/wayland/pipewire_utils.h" #include "rtc_base/logging.h" -#if defined(WEBRTC_DLOPEN_PIPEWIRE) -#include "modules/desktop_capture/linux/wayland/pipewire_stubs.h" -using modules_desktop_capture_linux_wayland::InitializeStubs; -using modules_desktop_capture_linux_wayland::kModulePipewire; -using modules_desktop_capture_linux_wayland::StubPathMap; -#endif // defined(WEBRTC_DLOPEN_PIPEWIRE) - namespace webrtc { -#if defined(WEBRTC_DLOPEN_PIPEWIRE) -const char kPipeWireLib[] = "libpipewire-0.3.so.0"; -#endif - constexpr int kBytesPerPixel = 4; TestScreenCastStreamProvider::TestScreenCastStreamProvider(Observer* observer, uint32_t width, uint32_t height) : observer_(observer), width_(width), height_(height) { -#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) - << "One of following libraries is missing on your system:\n" - << " - PipeWire (" << kPipeWireLib << ")\n"; + if (!InitializePipeWire()) { + RTC_LOG(LS_ERROR) << "Unable to open PipeWire"; return; } -#endif // defined(WEBRTC_DLOPEN_PIPEWIRE) pw_init(/*argc=*/nullptr, /*argc=*/nullptr); diff --git a/modules/desktop_capture/screen_capturer_linux.cc b/modules/desktop_capture/screen_capturer_linux.cc index 80f6da679a..44993837e8 100644 --- a/modules/desktop_capture/screen_capturer_linux.cc +++ b/modules/desktop_capture/screen_capturer_linux.cc @@ -27,17 +27,18 @@ namespace webrtc { std::unique_ptr DesktopCapturer::CreateRawScreenCapturer( const DesktopCaptureOptions& options) { #if defined(WEBRTC_USE_PIPEWIRE) - if (options.allow_pipewire() && DesktopCapturer::IsRunningUnderWayland()) { + if (options.allow_pipewire() && BaseCapturerPipeWire::IsSupported()) { return std::make_unique(options, CaptureType::kScreen); } #endif // defined(WEBRTC_USE_PIPEWIRE) #if defined(WEBRTC_USE_X11) - return ScreenCapturerX11::CreateRawScreenCapturer(options); -#else - return nullptr; + if (!DesktopCapturer::IsRunningUnderWayland()) + return ScreenCapturerX11::CreateRawScreenCapturer(options); #endif // defined(WEBRTC_USE_X11) + + return nullptr; } } // namespace webrtc diff --git a/modules/desktop_capture/window_capturer_linux.cc b/modules/desktop_capture/window_capturer_linux.cc index 20d93d0b33..4205bf9bc0 100644 --- a/modules/desktop_capture/window_capturer_linux.cc +++ b/modules/desktop_capture/window_capturer_linux.cc @@ -27,17 +27,18 @@ namespace webrtc { std::unique_ptr DesktopCapturer::CreateRawWindowCapturer( const DesktopCaptureOptions& options) { #if defined(WEBRTC_USE_PIPEWIRE) - if (options.allow_pipewire() && DesktopCapturer::IsRunningUnderWayland()) { + if (options.allow_pipewire() && BaseCapturerPipeWire::IsSupported()) { return std::make_unique(options, CaptureType::kWindow); } #endif // defined(WEBRTC_USE_PIPEWIRE) #if defined(WEBRTC_USE_X11) - return WindowCapturerX11::CreateRawWindowCapturer(options); -#else - return nullptr; + if (!DesktopCapturer::IsRunningUnderWayland()) + return WindowCapturerX11::CreateRawWindowCapturer(options); #endif // defined(WEBRTC_USE_X11) + + return nullptr; } } // namespace webrtc