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 <alcooper@chromium.org>
Reviewed-by: Mark Foltz <mfoltz@chromium.org>
Commit-Queue: Alexander Cooper <alcooper@chromium.org>
Cr-Commit-Position: refs/heads/main@{#38474}
This commit is contained in:
Alex Cooper 2022-10-25 11:34:45 -07:00 committed by WebRTC LUCI CQ
parent 3282747466
commit e25e98b906
9 changed files with 102 additions and 53 deletions

View file

@ -644,6 +644,8 @@ rtc_library("desktop_capture") {
"linux/wayland/egl_dmabuf.h", "linux/wayland/egl_dmabuf.h",
"linux/wayland/mouse_cursor_monitor_pipewire.cc", "linux/wayland/mouse_cursor_monitor_pipewire.cc",
"linux/wayland/mouse_cursor_monitor_pipewire.h", "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/portal_request_response.h",
"linux/wayland/restore_token_manager.cc", "linux/wayland/restore_token_manager.cc",
"linux/wayland/restore_token_manager.h", "linux/wayland/restore_token_manager.h",

View file

@ -12,11 +12,11 @@
#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/pipewire_utils.h"
#include "modules/desktop_capture/linux/wayland/restore_token_manager.h" #include "modules/desktop_capture/linux/wayland/restore_token_manager.h"
#include "modules/desktop_capture/linux/wayland/xdg_desktop_portal_utils.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"
#include "screencast_portal.h"
namespace webrtc { namespace webrtc {
@ -28,6 +28,18 @@ using xdg_portal::SessionDetails;
} // namespace } // 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, BaseCapturerPipeWire::BaseCapturerPipeWire(const DesktopCaptureOptions& options,
CaptureType type) CaptureType type)
: BaseCapturerPipeWire(options, : BaseCapturerPipeWire(options,

View file

@ -27,6 +27,12 @@ class BaseCapturerPipeWire : public DesktopCapturer,
public DelegatedSourceListController, public DelegatedSourceListController,
public ScreenCastPortal::PortalNotifier { public ScreenCastPortal::PortalNotifier {
public: 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, CaptureType type);
BaseCapturerPipeWire( BaseCapturerPipeWire(
const DesktopCaptureOptions& options, const DesktopCaptureOptions& options,

View file

@ -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

View file

@ -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_

View file

@ -20,28 +20,18 @@
#include "absl/memory/memory.h" #include "absl/memory/memory.h"
#include "modules/desktop_capture/linux/wayland/egl_dmabuf.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 "modules/desktop_capture/linux/wayland/screencast_stream_utils.h"
#include "rtc_base/checks.h" #include "rtc_base/checks.h"
#include "rtc_base/logging.h" #include "rtc_base/logging.h"
#include "rtc_base/sanitizer.h" #include "rtc_base/sanitizer.h"
#include "rtc_base/synchronization/mutex.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 { namespace webrtc {
const int kBytesPerPixel = 4; const int kBytesPerPixel = 4;
const int kVideoDamageRegionCount = 16; const int kVideoDamageRegionCount = 16;
#if defined(WEBRTC_DLOPEN_PIPEWIRE)
const char kPipeWireLib[] = "libpipewire-0.3.so.0";
#endif
constexpr int kCursorBpp = 4; constexpr int kCursorBpp = 4;
constexpr int CursorMetaSize(int w, int h) { constexpr int CursorMetaSize(int w, int h) {
return (sizeof(struct spa_meta_cursor) + sizeof(struct spa_meta_bitmap) + return (sizeof(struct spa_meta_cursor) + sizeof(struct spa_meta_bitmap) +
@ -389,19 +379,10 @@ bool SharedScreenCastStreamPrivate::StartScreenCastStream(
uint32_t height) { uint32_t height) {
width_ = width; width_ = width;
height_ = height; height_ = height;
#if defined(WEBRTC_DLOPEN_PIPEWIRE) if (!InitializePipeWire()) {
StubPathMap paths; RTC_LOG(LS_ERROR) << "Unable to open PipeWire library";
// 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";
return false; return false;
} }
#endif // defined(WEBRTC_DLOPEN_PIPEWIRE)
egl_dmabuf_ = std::make_unique<EglDmaBuf>(); egl_dmabuf_ = std::make_unique<EglDmaBuf>();
pw_stream_node_id_ = stream_node_id; pw_stream_node_id_ = stream_node_id;

View file

@ -20,40 +20,21 @@
#include <utility> #include <utility>
#include <vector> #include <vector>
#include "modules/desktop_capture/linux/wayland/pipewire_utils.h"
#include "rtc_base/logging.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 { namespace webrtc {
#if defined(WEBRTC_DLOPEN_PIPEWIRE)
const char kPipeWireLib[] = "libpipewire-0.3.so.0";
#endif
constexpr int kBytesPerPixel = 4; constexpr int kBytesPerPixel = 4;
TestScreenCastStreamProvider::TestScreenCastStreamProvider(Observer* observer, TestScreenCastStreamProvider::TestScreenCastStreamProvider(Observer* observer,
uint32_t width, uint32_t width,
uint32_t height) uint32_t height)
: observer_(observer), width_(width), height_(height) { : observer_(observer), width_(width), height_(height) {
#if defined(WEBRTC_DLOPEN_PIPEWIRE) if (!InitializePipeWire()) {
StubPathMap paths; RTC_LOG(LS_ERROR) << "Unable to open PipeWire";
// 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";
return; return;
} }
#endif // defined(WEBRTC_DLOPEN_PIPEWIRE)
pw_init(/*argc=*/nullptr, /*argc=*/nullptr); pw_init(/*argc=*/nullptr, /*argc=*/nullptr);

View file

@ -27,17 +27,18 @@ namespace webrtc {
std::unique_ptr<DesktopCapturer> DesktopCapturer::CreateRawScreenCapturer( std::unique_ptr<DesktopCapturer> DesktopCapturer::CreateRawScreenCapturer(
const DesktopCaptureOptions& options) { const DesktopCaptureOptions& options) {
#if defined(WEBRTC_USE_PIPEWIRE) #if defined(WEBRTC_USE_PIPEWIRE)
if (options.allow_pipewire() && DesktopCapturer::IsRunningUnderWayland()) { if (options.allow_pipewire() && BaseCapturerPipeWire::IsSupported()) {
return std::make_unique<BaseCapturerPipeWire>(options, return std::make_unique<BaseCapturerPipeWire>(options,
CaptureType::kScreen); CaptureType::kScreen);
} }
#endif // defined(WEBRTC_USE_PIPEWIRE) #endif // defined(WEBRTC_USE_PIPEWIRE)
#if defined(WEBRTC_USE_X11) #if defined(WEBRTC_USE_X11)
if (!DesktopCapturer::IsRunningUnderWayland())
return ScreenCapturerX11::CreateRawScreenCapturer(options); return ScreenCapturerX11::CreateRawScreenCapturer(options);
#else
return nullptr;
#endif // defined(WEBRTC_USE_X11) #endif // defined(WEBRTC_USE_X11)
return nullptr;
} }
} // namespace webrtc } // namespace webrtc

View file

@ -27,17 +27,18 @@ namespace webrtc {
std::unique_ptr<DesktopCapturer> DesktopCapturer::CreateRawWindowCapturer( std::unique_ptr<DesktopCapturer> DesktopCapturer::CreateRawWindowCapturer(
const DesktopCaptureOptions& options) { const DesktopCaptureOptions& options) {
#if defined(WEBRTC_USE_PIPEWIRE) #if defined(WEBRTC_USE_PIPEWIRE)
if (options.allow_pipewire() && DesktopCapturer::IsRunningUnderWayland()) { if (options.allow_pipewire() && BaseCapturerPipeWire::IsSupported()) {
return std::make_unique<BaseCapturerPipeWire>(options, return std::make_unique<BaseCapturerPipeWire>(options,
CaptureType::kWindow); CaptureType::kWindow);
} }
#endif // defined(WEBRTC_USE_PIPEWIRE) #endif // defined(WEBRTC_USE_PIPEWIRE)
#if defined(WEBRTC_USE_X11) #if defined(WEBRTC_USE_X11)
if (!DesktopCapturer::IsRunningUnderWayland())
return WindowCapturerX11::CreateRawWindowCapturer(options); return WindowCapturerX11::CreateRawWindowCapturer(options);
#else
return nullptr;
#endif // defined(WEBRTC_USE_X11) #endif // defined(WEBRTC_USE_X11)
return nullptr;
} }
} // namespace webrtc } // namespace webrtc