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)