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