From 797832efa55f1a9904bba1ea946c473c91d621bb Mon Sep 17 00:00:00 2001 From: WilliamSolari <118758182+B077AS@users.noreply.github.com> Date: Sun, 23 Aug 2026 21:45:20 +0200 Subject: [PATCH 1/2] Add Wayland/PipeWire desktop capture support WebRTC's PipeWire/xdg-desktop-portal screen capture backend is never enabled: rtc_use_pipewire stays false and WEBRTC_USE_PIPEWIRE/WEBRTC_USE_GIO are never defined for the JNI wrapper, so DesktopCapturer::CreateScreenCapturer() returns null under Wayland. Since the recent null-check fix that fails gracefully with a log message instead of crashing, but capture still doesn't work. - CMakeLists.txt: WEBRTC_USE_PIPEWIRE/WEBRTC_USE_GIO defines, GIO/GBM/DRM linking, rtc_use_pipewire=true, and a fix for a PKG_CONFIG_SYSROOT_DIR/ PATH leak from the JNI configure step into gn/ninja that broke portal capturer header discovery. Also links Xext/Xdamage/Xtst, needed by the existing X11 capturer path but not previously linked. - VideoTrackDesktopSource.cpp / DesktopCapturer.cpp: set_allow_pipewire(true) + set_prefer_cursor_embedded(true), gated behind WEBRTC_USE_PIPEWIRE. - patches/linux/pipewire_force_shm.patch: forces SHM buffers over DMA-BUF in screencast_stream_utils.cc's BuildFullFormat(). Several GPU/driver combinations deliver DMA-BUF frames flagged SPA_META_HEADER_FLAG_CORRUPTED, which OnStreamProcess drops, producing an empty screen share. Verified building and linking cleanly on all three Linux architectures against branch-heads/7977. --- .../cpp/dependencies/webrtc/CMakeLists.txt | 40 +++++++++++++++++-- .../patches/linux/pipewire_force_shm.patch | 16 ++++++++ .../media/video/VideoTrackDesktopSource.cpp | 8 ++++ .../media/video/desktop/DesktopCapturer.cpp | 8 ++++ 4 files changed, 68 insertions(+), 4 deletions(-) create mode 100644 webrtc-jni/src/main/cpp/dependencies/webrtc/patches/linux/pipewire_force_shm.patch diff --git a/webrtc-jni/src/main/cpp/dependencies/webrtc/CMakeLists.txt b/webrtc-jni/src/main/cpp/dependencies/webrtc/CMakeLists.txt index de31914e..02151ab5 100644 --- a/webrtc-jni/src/main/cpp/dependencies/webrtc/CMakeLists.txt +++ b/webrtc-jni/src/main/cpp/dependencies/webrtc/CMakeLists.txt @@ -209,10 +209,24 @@ elseif(LINUX) # Find DBus find_package(PkgConfig QUIET REQUIRED) # Include functions provided by PkgConfig module. pkg_check_modules(DBUS REQUIRED dbus-1) - - target_include_directories(${PROJECT_NAME} PUBLIC ${DBUS_INCLUDE_DIRS}) - target_compile_definitions(${PROJECT_NAME} PUBLIC WEBRTC_LINUX WEBRTC_POSIX WEBRTC_USE_H264 WEBRTC_USE_X11) - target_link_libraries(${PROJECT_NAME} X11 Xfixes Xrandr Xcomposite dbus-1) + # Wayland/PipeWire desktop capture: libwebrtc.a references gio, gbm and libdrm + # symbols directly (libpipewire, libEGL and libGL are dlopen'd at runtime, so + # they are NOT link dependencies). WEBRTC_USE_PIPEWIRE / WEBRTC_USE_GIO must + # match the gn build (rtc_use_pipewire=true) — DesktopCaptureOptions has + # members guarded by WEBRTC_USE_PIPEWIRE, so compiling the JNI wrapper without + # it would change the struct layout and crash (same ABI bug WEBRTC_USE_X11 fixed). + pkg_check_modules(GIO REQUIRED gio-2.0 gio-unix-2.0) + pkg_check_modules(GBM REQUIRED gbm) + pkg_check_modules(DRM REQUIRED libdrm) + + # GIO include dirs: with WEBRTC_USE_PIPEWIRE defined, desktop_capturer.h -> + # desktop_capture_metadata.h -> xdg_session_details.h includes , + # so the JNI wrapper compile needs the glib headers too. (No pipewire headers + # are needed — nothing the JNI includes reaches them, and the runner has no + # libpipewire dev package.) + target_include_directories(${PROJECT_NAME} PUBLIC ${DBUS_INCLUDE_DIRS} ${GIO_INCLUDE_DIRS}) + target_compile_definitions(${PROJECT_NAME} PUBLIC WEBRTC_LINUX WEBRTC_POSIX WEBRTC_USE_H264 WEBRTC_USE_X11 WEBRTC_USE_PIPEWIRE WEBRTC_USE_GIO) + target_link_libraries(${PROJECT_NAME} X11 Xext Xfixes Xdamage Xtst Xrandr Xcomposite dbus-1 ${GIO_LIBRARIES} ${GBM_LIBRARIES} ${DRM_LIBRARIES}) elseif(WIN32) target_compile_definitions(${PROJECT_NAME} PUBLIC WEBRTC_WIN WEBRTC_USE_H264 NOMINMAX WIN32_LEAN_AND_MEAN NDEBUG) target_link_libraries(${PROJECT_NAME} D3D11 DXGI user32 gdi32 iphlpapi dmoguids msdmo secur32 strmiids winmm wmcodecdspuuid ws2_32) @@ -311,6 +325,12 @@ symbol_level=0") if(APPLE) set(COMPILE_ARGS "${COMPILE_ARGS} mac_deployment_target=\"${CMAKE_OSX_DEPLOYMENT_TARGET}\"") elseif(LINUX) + # Build the PipeWire/xdg-desktop-portal capturer for Wayland sessions. The + # X11 capturer stays in as well; WebRTC picks PipeWire at runtime only when + # IsRunningUnderWayland() is true. rtc_link_pipewire stays false (default), + # so libpipewire is dlopen'd and X11-only systems gain no hard dependency. + string(REPLACE "rtc_use_pipewire=false" "rtc_use_pipewire=true" COMPILE_ARGS "${COMPILE_ARGS}") + if(${TARGET_CPU} STREQUAL "arm") set(COMPILE_ARGS "${COMPILE_ARGS} custom_toolchain=\"//build/toolchain/linux:clang_arm\"") elseif(${TARGET_CPU} STREQUAL "arm64") @@ -318,6 +338,18 @@ elseif(LINUX) endif() endif() +if(LINUX) + # The sysroot pkg-config environment exported for the JNI configure step + # (PKG_CONFIG_SYSROOT_DIR/PKG_CONFIG_PATH in cpp/CMakeLists.txt) must not + # leak into gn/ninja: Chromium's pkg-config wrapper applies the gn sysroot + # itself, so a leaked PKG_CONFIG_SYSROOT_DIR double-prefixes every include + # path (build/linux//opt/sysroot//usr/include/...) and + # the gio/pipewire headers of the portal capturer are not found. All + # pkg_check_modules() calls above have already run at this point. + unset(ENV{PKG_CONFIG_SYSROOT_DIR}) + unset(ENV{PKG_CONFIG_PATH}) +endif() + execute_command( COMMAND gn gen ${WEBRTC_BUILD} --args=${COMPILE_ARGS} WORKING_DIRECTORY "${WEBRTC_SRC}" diff --git a/webrtc-jni/src/main/cpp/dependencies/webrtc/patches/linux/pipewire_force_shm.patch b/webrtc-jni/src/main/cpp/dependencies/webrtc/patches/linux/pipewire_force_shm.patch new file mode 100644 index 00000000..4a18d676 --- /dev/null +++ b/webrtc-jni/src/main/cpp/dependencies/webrtc/patches/linux/pipewire_force_shm.patch @@ -0,0 +1,16 @@ +--- a/modules/desktop_capture/linux/wayland/screencast_stream_utils.cc ++++ b/modules/desktop_capture/linux/wayland/screencast_stream_utils.cc +@@ -113,5 +113,13 @@ + if (render_device) { + auto modifiers = render_device->QueryDmaBufModifiers(format); + ++ // Force SHM (shared-memory) buffers instead of DMA-BUF. On several ++ // GPU/driver combos under Wayland the compositor delivers every screen ++ // frame as a DMA-BUF flagged SPA_META_HEADER_FLAG_CORRUPTED, which WebRTC ++ // drops (see SharedScreenCastStreamPrivate::OnStreamProcess), leaving the ++ // screen share entirely empty. Clearing modifiers advertises SHM-only, ++ // and the CPU copy path always works. ++ modifiers.clear(); ++ + if (modifiers.size()) { + if (modifiers.size() == 1 && modifiers[0] == DRM_FORMAT_MOD_INVALID) { diff --git a/webrtc-jni/src/main/cpp/src/media/video/VideoTrackDesktopSource.cpp b/webrtc-jni/src/main/cpp/src/media/video/VideoTrackDesktopSource.cpp index 6192d6d3..2b93a3aa 100644 --- a/webrtc-jni/src/main/cpp/src/media/video/VideoTrackDesktopSource.cpp +++ b/webrtc-jni/src/main/cpp/src/media/video/VideoTrackDesktopSource.cpp @@ -251,6 +251,14 @@ namespace jni #if defined(WEBRTC_WIN) options.set_allow_directx_capturer(true); #endif +#if defined(WEBRTC_USE_PIPEWIRE) + // Wayland: route capture through the PipeWire/xdg-desktop-portal backend. + // Only takes effect when IsRunningUnderWayland(); X11 sessions keep the + // X11 capturer. The portal delivers frames with the cursor already + // composited, so prefer it over DesktopAndCursorComposer's software cursor. + options.set_allow_pipewire(true); + options.set_prefer_cursor_embedded(true); +#endif std::unique_ptr capturer; diff --git a/webrtc-jni/src/main/cpp/src/media/video/desktop/DesktopCapturer.cpp b/webrtc-jni/src/main/cpp/src/media/video/desktop/DesktopCapturer.cpp index 9d559ec3..9262e75f 100644 --- a/webrtc-jni/src/main/cpp/src/media/video/desktop/DesktopCapturer.cpp +++ b/webrtc-jni/src/main/cpp/src/media/video/desktop/DesktopCapturer.cpp @@ -36,6 +36,14 @@ namespace jni #if defined(WEBRTC_WIN) options.set_allow_directx_capturer(true); #endif +#if defined(WEBRTC_USE_PIPEWIRE) + // Wayland: route capture through the PipeWire/xdg-desktop-portal backend. + // Only takes effect when IsRunningUnderWayland(); X11 sessions keep the + // X11 capturer. The portal delivers frames with the cursor already + // composited, so prefer it over DesktopAndCursorComposer's software cursor. + options.set_allow_pipewire(true); + options.set_prefer_cursor_embedded(true); +#endif std::unique_ptr inner = screenCapturer ? webrtc::DesktopCapturer::CreateScreenCapturer(options) From 8169cc533b7e7cadf4267dc574218fde5278f018 Mon Sep 17 00:00:00 2001 From: B077AS <118758182+B077AS@users.noreply.github.com> Date: Mon, 24 Aug 2026 08:32:48 +0200 Subject: [PATCH 2/2] Retrigger CI