From a2f5f56bb366f52c5fec1d37d28e20d46c255889 Mon Sep 17 00:00:00 2001 From: SendableMetatype <263203301+SendableMetatype@users.noreply.github.com> Date: Sun, 6 Sep 2026 14:57:10 +0200 Subject: [PATCH 1/3] fix: load libudev at runtime instead of linking it The Linux natives linked libudev, so they failed to load on any host without it, although only the V4L2 device manager uses it. The manager now opens libudev.so.1 on construction and binds the symbols it needs, the same way the PulseAudio device manager handles libpulse. A host without libudev gets an exception when it enumerates cameras instead of a load failure. --- webrtc-jni/src/main/cpp/CMakeLists.txt | 2 +- .../include/media/video/linux/UdevLoader.h | 151 ++++++++++++++++++ .../video/linux/V4l2VideoDeviceManager.cpp | 59 ++++--- 3 files changed, 187 insertions(+), 25 deletions(-) create mode 100644 webrtc-jni/src/main/cpp/include/media/video/linux/UdevLoader.h diff --git a/webrtc-jni/src/main/cpp/CMakeLists.txt b/webrtc-jni/src/main/cpp/CMakeLists.txt index 3a6fea1a..e129958a 100644 --- a/webrtc-jni/src/main/cpp/CMakeLists.txt +++ b/webrtc-jni/src/main/cpp/CMakeLists.txt @@ -113,7 +113,7 @@ if(APPLE) elseif(LINUX) set(CXX_LIBS "-static-libgcc -stdlib=libc++ -lc++ -lc++abi") - target_link_libraries(${PROJECT_NAME} ${CXX_LIBS} udev) + target_link_libraries(${PROJECT_NAME} ${CXX_LIBS}) target_link_libraries(${PROJECT_NAME} dl) elseif(WIN32) target_link_libraries(${PROJECT_NAME} dwmapi.lib mf.lib mfreadwrite.lib mfplat.lib mfuuid.lib shcore.lib) diff --git a/webrtc-jni/src/main/cpp/include/media/video/linux/UdevLoader.h b/webrtc-jni/src/main/cpp/include/media/video/linux/UdevLoader.h new file mode 100644 index 00000000..a959d9c5 --- /dev/null +++ b/webrtc-jni/src/main/cpp/include/media/video/linux/UdevLoader.h @@ -0,0 +1,151 @@ +/* + * Copyright 2019 Alex Andres + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#ifndef JNI_WEBRTC_MEDIA_V4L2_UDEV_LOADER_H_ +#define JNI_WEBRTC_MEDIA_V4L2_UDEV_LOADER_H_ + +#include + +#include + +namespace jni +{ + namespace avdev + { + typedef struct udev * (*udev_new_t)(); + typedef struct udev * (*udev_unref_t)(struct udev * udev); + typedef struct udev_enumerate * (*udev_enumerate_new_t)(struct udev * udev); + typedef struct udev_enumerate * (*udev_enumerate_unref_t)(struct udev_enumerate * enumerate); + typedef int (*udev_enumerate_add_match_subsystem_t)(struct udev_enumerate * enumerate, const char * subsystem); + typedef int (*udev_enumerate_scan_devices_t)(struct udev_enumerate * enumerate); + typedef struct udev_list_entry * (*udev_enumerate_get_list_entry_t)(struct udev_enumerate * enumerate); + typedef struct udev_list_entry * (*udev_list_entry_get_next_t)(struct udev_list_entry * entry); + typedef const char * (*udev_list_entry_get_name_t)(struct udev_list_entry * entry); + typedef struct udev_device * (*udev_device_new_from_syspath_t)(struct udev * udev, const char * syspath); + typedef struct udev_device * (*udev_device_unref_t)(struct udev_device * device); + typedef const char * (*udev_device_get_devnode_t)(struct udev_device * device); + typedef const char * (*udev_device_get_subsystem_t)(struct udev_device * device); + typedef const char * (*udev_device_get_action_t)(struct udev_device * device); + typedef const char * (*udev_device_get_property_value_t)(struct udev_device * device, const char * key); + typedef struct udev_monitor * (*udev_monitor_new_from_netlink_t)(struct udev * udev, const char * name); + typedef struct udev_monitor * (*udev_monitor_unref_t)(struct udev_monitor * monitor); + typedef int (*udev_monitor_filter_add_match_subsystem_devtype_t)(struct udev_monitor * monitor, const char * subsystem, const char * devtype); + typedef int (*udev_monitor_enable_receiving_t)(struct udev_monitor * monitor); + typedef int (*udev_monitor_get_fd_t)(struct udev_monitor * monitor); + typedef struct udev_device * (*udev_monitor_receive_device_t)(struct udev_monitor * monitor); + + class UdevLoader + { + public: + static UdevLoader & instance() + { + static UdevLoader instance; + return instance; + } + + bool load() + { + if (loaded) { + return true; + } + + handle = dlopen("libudev.so.1", RTLD_NOW); + + if (!handle) { + return false; + } + + #define UDEV_LOAD_SYM(name) \ + name = (name##_t) dlsym(handle, #name); \ + if (!name) { close(); return false; } + + UDEV_LOAD_SYM(udev_new); + UDEV_LOAD_SYM(udev_unref); + UDEV_LOAD_SYM(udev_enumerate_new); + UDEV_LOAD_SYM(udev_enumerate_unref); + UDEV_LOAD_SYM(udev_enumerate_add_match_subsystem); + UDEV_LOAD_SYM(udev_enumerate_scan_devices); + UDEV_LOAD_SYM(udev_enumerate_get_list_entry); + UDEV_LOAD_SYM(udev_list_entry_get_next); + UDEV_LOAD_SYM(udev_list_entry_get_name); + UDEV_LOAD_SYM(udev_device_new_from_syspath); + UDEV_LOAD_SYM(udev_device_unref); + UDEV_LOAD_SYM(udev_device_get_devnode); + UDEV_LOAD_SYM(udev_device_get_subsystem); + UDEV_LOAD_SYM(udev_device_get_action); + UDEV_LOAD_SYM(udev_device_get_property_value); + UDEV_LOAD_SYM(udev_monitor_new_from_netlink); + UDEV_LOAD_SYM(udev_monitor_unref); + UDEV_LOAD_SYM(udev_monitor_filter_add_match_subsystem_devtype); + UDEV_LOAD_SYM(udev_monitor_enable_receiving); + UDEV_LOAD_SYM(udev_monitor_get_fd); + UDEV_LOAD_SYM(udev_monitor_receive_device); + + #undef UDEV_LOAD_SYM + + loaded = true; + + return true; + } + + void close() + { + if (handle) { + dlclose(handle); + handle = nullptr; + } + + loaded = false; + } + + bool isLoaded() const + { + return loaded; + } + + udev_new_t udev_new; + udev_unref_t udev_unref; + udev_enumerate_new_t udev_enumerate_new; + udev_enumerate_unref_t udev_enumerate_unref; + udev_enumerate_add_match_subsystem_t udev_enumerate_add_match_subsystem; + udev_enumerate_scan_devices_t udev_enumerate_scan_devices; + udev_enumerate_get_list_entry_t udev_enumerate_get_list_entry; + udev_list_entry_get_next_t udev_list_entry_get_next; + udev_list_entry_get_name_t udev_list_entry_get_name; + udev_device_new_from_syspath_t udev_device_new_from_syspath; + udev_device_unref_t udev_device_unref; + udev_device_get_devnode_t udev_device_get_devnode; + udev_device_get_subsystem_t udev_device_get_subsystem; + udev_device_get_action_t udev_device_get_action; + udev_device_get_property_value_t udev_device_get_property_value; + udev_monitor_new_from_netlink_t udev_monitor_new_from_netlink; + udev_monitor_unref_t udev_monitor_unref; + udev_monitor_filter_add_match_subsystem_devtype_t udev_monitor_filter_add_match_subsystem_devtype; + udev_monitor_enable_receiving_t udev_monitor_enable_receiving; + udev_monitor_get_fd_t udev_monitor_get_fd; + udev_monitor_receive_device_t udev_monitor_receive_device; + + private: + UdevLoader() : loaded(false), handle(nullptr) {} + + bool loaded; + void * handle; + }; + } +} + +#endif diff --git a/webrtc-jni/src/main/cpp/src/media/video/linux/V4l2VideoDeviceManager.cpp b/webrtc-jni/src/main/cpp/src/media/video/linux/V4l2VideoDeviceManager.cpp index e7f0e5f4..b8d9f29f 100644 --- a/webrtc-jni/src/main/cpp/src/media/video/linux/V4l2VideoDeviceManager.cpp +++ b/webrtc-jni/src/main/cpp/src/media/video/linux/V4l2VideoDeviceManager.cpp @@ -15,6 +15,7 @@ */ #include "media/video/linux/V4l2VideoDeviceManager.h" +#include "media/video/linux/UdevLoader.h" #include "Exception.h" #include "rtc_base/logging.h" @@ -36,7 +37,13 @@ namespace jni { V4l2VideoDeviceManager::V4l2VideoDeviceManager() { - udev = udev_new(); + if (!UdevLoader::instance().load()) { + throw Exception("V4l2: libudev not found on system."); + } + + auto & lib = UdevLoader::instance(); + + udev = lib.udev_new(); if (!udev) { throw Exception("V4l2: Create udev failed"); @@ -62,7 +69,7 @@ namespace jni } } - udev_unref(udev); + UdevLoader::instance().udev_unref(udev); } std::set V4l2VideoDeviceManager::getVideoCaptureDevices() @@ -71,30 +78,32 @@ namespace jni return captureDevices.devices(); } - udev_enumerate * enumerate = udev_enumerate_new(udev); - udev_enumerate_add_match_subsystem(enumerate, UDEV_SUBSYSTEM); - udev_enumerate_scan_devices(enumerate); + auto & lib = UdevLoader::instance(); - udev_list_entry * udev_devices = udev_enumerate_get_list_entry(enumerate); + udev_enumerate * enumerate = lib.udev_enumerate_new(udev); + lib.udev_enumerate_add_match_subsystem(enumerate, UDEV_SUBSYSTEM); + lib.udev_enumerate_scan_devices(enumerate); + + udev_list_entry * udev_devices = lib.udev_enumerate_get_list_entry(enumerate); udev_list_entry * dev_list_entry; v4l2_capability vcap; - udev_list_entry_foreach(dev_list_entry, udev_devices) { - const char * path = udev_list_entry_get_name(dev_list_entry); + for (dev_list_entry = udev_devices; dev_list_entry != nullptr; dev_list_entry = lib.udev_list_entry_get_next(dev_list_entry)) { + const char * path = lib.udev_list_entry_get_name(dev_list_entry); if (!path) { RTC_LOG(LS_ERROR) << "V4l2: Failed to get device sys path"; continue; } - udev_device * dev = udev_device_new_from_syspath(udev, path); + udev_device * dev = lib.udev_device_new_from_syspath(udev, path); if (!dev) { RTC_LOG(LS_ERROR) << "V4l2: Failed to get device from sys path: " << path; continue; } - const char * node = udev_device_get_devnode(dev); + const char * node = lib.udev_device_get_devnode(dev); bool error = false; int v4l2_fd = open(node, O_RDONLY); @@ -126,10 +135,10 @@ namespace jni addDevice(name, node); } - udev_device_unref(dev); + lib.udev_device_unref(dev); } - udev_enumerate_unref(enumerate); + lib.udev_enumerate_unref(enumerate); return captureDevices.devices(); } @@ -203,39 +212,41 @@ namespace jni void V4l2VideoDeviceManager::run() { - udev_monitor * mon = udev_monitor_new_from_netlink(udev, "udev"); + auto & lib = UdevLoader::instance(); + + udev_monitor * mon = lib.udev_monitor_new_from_netlink(udev, "udev"); if (!mon) { RTC_LOG(LS_ERROR) << "V4l2: Failed to init udev monitor"; return; } - udev_monitor_filter_add_match_subsystem_devtype(mon, UDEV_SUBSYSTEM, NULL); - udev_monitor_enable_receiving(mon); + lib.udev_monitor_filter_add_match_subsystem_devtype(mon, UDEV_SUBSYSTEM, NULL); + lib.udev_monitor_enable_receiving(mon); pollfd items[1]; - items[0].fd = udev_monitor_get_fd(mon); + items[0].fd = lib.udev_monitor_get_fd(mon); items[0].events = POLLIN; while (running) { while (poll(items, 1, -1) > 0) { - udev_device * dev = udev_monitor_receive_device(mon); + udev_device * dev = lib.udev_monitor_receive_device(mon); if (!dev) { RTC_LOG(LS_ERROR) << "V4l2: No device received from udev monitor"; continue; } - const char * subsystem = udev_device_get_subsystem(dev); + const char * subsystem = lib.udev_device_get_subsystem(dev); if (strcmp(subsystem, UDEV_SUBSYSTEM) != 0) { - udev_device_unref(dev); + lib.udev_device_unref(dev); continue; } - const char * action = udev_device_get_action(dev); - const char * node = udev_device_get_devnode(dev); - const char * name = udev_device_get_property_value(dev, "ID_V4L_PRODUCT"); + const char * action = lib.udev_device_get_action(dev); + const char * node = lib.udev_device_get_devnode(dev); + const char * name = lib.udev_device_get_property_value(dev, "ID_V4L_PRODUCT"); if (strcmp(action, UDEV_ADD) == 0 && checkDevice(node)) { addDevice(name, node); @@ -244,11 +255,11 @@ namespace jni removeDevice(name, node); } - udev_device_unref(dev); + lib.udev_device_unref(dev); } } - udev_monitor_unref(mon); + lib.udev_monitor_unref(mon); } void V4l2VideoDeviceManager::addDevice(const std::string & name, const std::string & descriptor) From 7238c4e6f5c81b128a1624885e32e7987145a837 Mon Sep 17 00:00:00 2001 From: SendableMetatype <263203301+SendableMetatype@users.noreply.github.com> Date: Sun, 6 Sep 2026 14:57:11 +0200 Subject: [PATCH 2/3] fix: load libdbus at runtime instead of linking it Only the Linux power management uses libdbus, to ask the screen saver not to start during desktop capture. It now opens libdbus-1.so.3 on first use and binds the symbols it needs. A host without libdbus logs a warning and skips the inhibition instead of failing to load the natives. The dbus headers are still required at build time. --- .../cpp/dependencies/webrtc/CMakeLists.txt | 4 +- .../media/video/desktop/linux/DBusLoader.h | 124 ++++++++++++++++++ .../desktop/linux/LinuxPowerManagement.cpp | 73 +++++++---- 3 files changed, 170 insertions(+), 31 deletions(-) create mode 100644 webrtc-jni/src/main/cpp/include/media/video/desktop/linux/DBusLoader.h diff --git a/webrtc-jni/src/main/cpp/dependencies/webrtc/CMakeLists.txt b/webrtc-jni/src/main/cpp/dependencies/webrtc/CMakeLists.txt index d1341a4e..333669d8 100644 --- a/webrtc-jni/src/main/cpp/dependencies/webrtc/CMakeLists.txt +++ b/webrtc-jni/src/main/cpp/dependencies/webrtc/CMakeLists.txt @@ -206,7 +206,7 @@ if(APPLE) target_compile_definitions(${PROJECT_NAME} PUBLIC WEBRTC_MAC WEBRTC_POSIX WEBRTC_USE_H264) target_link_libraries(${PROJECT_NAME} "-framework Foundation" "-framework AVFoundation" "-framework CoreGraphics" "-framework CoreAudio" "-framework CoreVideo" "-framework ScreenCaptureKit" "-framework AudioToolbox" "-framework IOSurface" "-framework ApplicationServices" "-framework AppKit") elseif(LINUX) - # Find DBus + # Find DBus (headers only: the JNI code opens libdbus at runtime) find_package(PkgConfig QUIET REQUIRED) # Include functions provided by PkgConfig module. pkg_check_modules(DBUS REQUIRED dbus-1) # Wayland/PipeWire desktop capture: libwebrtc.a references gio, gbm and libdrm @@ -226,7 +226,7 @@ elseif(LINUX) # 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}) + target_link_libraries(${PROJECT_NAME} X11 Xext Xfixes Xdamage Xtst Xrandr Xcomposite ${GIO_LIBRARIES} ${GBM_LIBRARIES} ${DRM_LIBRARIES}) elseif(WIN32) # RTC_ENABLE_WIN_WGC must match the gn build: webrtc.lib is compiled with gn's # default rtc_enable_win_wgc=true (webrtc.gni: "rtc_enable_win_wgc = is_win"), diff --git a/webrtc-jni/src/main/cpp/include/media/video/desktop/linux/DBusLoader.h b/webrtc-jni/src/main/cpp/include/media/video/desktop/linux/DBusLoader.h new file mode 100644 index 00000000..2375d370 --- /dev/null +++ b/webrtc-jni/src/main/cpp/include/media/video/desktop/linux/DBusLoader.h @@ -0,0 +1,124 @@ +/* + * Copyright 2019 Alex Andres + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#ifndef JNI_WEBRTC_MEDIA_DESKTOP_LINUX_DBUS_LOADER_H_ +#define JNI_WEBRTC_MEDIA_DESKTOP_LINUX_DBUS_LOADER_H_ + +#include + +#include + +namespace jni +{ + namespace avdev + { + typedef void (*dbus_error_init_t)(DBusError * error); + typedef void (*dbus_error_free_t)(DBusError * error); + typedef dbus_bool_t (*dbus_error_is_set_t)(const DBusError * error); + typedef DBusConnection * (*dbus_bus_get_t)(DBusBusType type, DBusError * error); + typedef dbus_bool_t (*dbus_bus_name_has_owner_t)(DBusConnection * connection, const char * name, DBusError * error); + typedef void (*dbus_connection_unref_t)(DBusConnection * connection); + typedef DBusMessage * (*dbus_connection_send_with_reply_and_block_t)(DBusConnection * connection, DBusMessage * message, int timeout, DBusError * error); + typedef DBusMessage * (*dbus_message_new_method_call_t)(const char * destination, const char * path, const char * iface, const char * method); + typedef dbus_bool_t (*dbus_message_append_args_t)(DBusMessage * message, int firstArgType, ...); + typedef void (*dbus_message_unref_t)(DBusMessage * message); + typedef dbus_bool_t (*dbus_message_iter_init_t)(DBusMessage * message, DBusMessageIter * iter); + typedef void (*dbus_message_iter_get_basic_t)(DBusMessageIter * iter, void * value); + + class DBusLoader + { + public: + static DBusLoader & instance() + { + static DBusLoader instance; + return instance; + } + + bool load() + { + if (loaded) { + return true; + } + + handle = dlopen("libdbus-1.so.3", RTLD_NOW); + + if (!handle) { + return false; + } + + #define DBUS_LOAD_SYM(name) \ + name = (name##_t) dlsym(handle, #name); \ + if (!name) { close(); return false; } + + DBUS_LOAD_SYM(dbus_error_init); + DBUS_LOAD_SYM(dbus_error_free); + DBUS_LOAD_SYM(dbus_error_is_set); + DBUS_LOAD_SYM(dbus_bus_get); + DBUS_LOAD_SYM(dbus_bus_name_has_owner); + DBUS_LOAD_SYM(dbus_connection_unref); + DBUS_LOAD_SYM(dbus_connection_send_with_reply_and_block); + DBUS_LOAD_SYM(dbus_message_new_method_call); + DBUS_LOAD_SYM(dbus_message_append_args); + DBUS_LOAD_SYM(dbus_message_unref); + DBUS_LOAD_SYM(dbus_message_iter_init); + DBUS_LOAD_SYM(dbus_message_iter_get_basic); + + #undef DBUS_LOAD_SYM + + loaded = true; + + return true; + } + + void close() + { + if (handle) { + dlclose(handle); + handle = nullptr; + } + + loaded = false; + } + + bool isLoaded() const + { + return loaded; + } + + dbus_error_init_t dbus_error_init; + dbus_error_free_t dbus_error_free; + dbus_error_is_set_t dbus_error_is_set; + dbus_bus_get_t dbus_bus_get; + dbus_bus_name_has_owner_t dbus_bus_name_has_owner; + dbus_connection_unref_t dbus_connection_unref; + dbus_connection_send_with_reply_and_block_t dbus_connection_send_with_reply_and_block; + dbus_message_new_method_call_t dbus_message_new_method_call; + dbus_message_append_args_t dbus_message_append_args; + dbus_message_unref_t dbus_message_unref; + dbus_message_iter_init_t dbus_message_iter_init; + dbus_message_iter_get_basic_t dbus_message_iter_get_basic; + + private: + DBusLoader() : loaded(false), handle(nullptr) {} + + bool loaded; + void * handle; + }; + } +} + +#endif diff --git a/webrtc-jni/src/main/cpp/src/media/video/desktop/linux/LinuxPowerManagement.cpp b/webrtc-jni/src/main/cpp/src/media/video/desktop/linux/LinuxPowerManagement.cpp index 05611a8e..2aa06191 100644 --- a/webrtc-jni/src/main/cpp/src/media/video/desktop/linux/LinuxPowerManagement.cpp +++ b/webrtc-jni/src/main/cpp/src/media/video/desktop/linux/LinuxPowerManagement.cpp @@ -15,6 +15,7 @@ */ #include "media/video/desktop/linux/LinuxPowerManagement.h" +#include "media/video/desktop/linux/DBusLoader.h" #include #include @@ -31,19 +32,26 @@ namespace jni void LinuxPowerManagement::enableUserActivity() { + if (!DBusLoader::instance().load()) { + RTC_LOG(LS_WARNING) << "[PowerManagement] libdbus not found on system"; + return; + } + + auto & dbus = DBusLoader::instance(); + DBusError error; - dbus_error_init(&error); + dbus.dbus_error_init(&error); - DBusConnection * dbusConnection = dbus_bus_get(DBUS_BUS_SESSION, &error); + DBusConnection * dbusConnection = dbus.dbus_bus_get(DBUS_BUS_SESSION, &error); - if (dbus_error_is_set(&error)) { + if (dbus.dbus_error_is_set(&error)) { // throw RTC_LOG(LS_ERROR) << "[PowerManagement] Cannot connect to session bus: " << error.message; - dbus_error_free(&error); + dbus.dbus_error_free(&error); return; } - if (dbus_bus_name_has_owner(dbusConnection, BUS_SERVICE_NAME, NULL)) { + if (dbus.dbus_bus_name_has_owner(dbusConnection, BUS_SERVICE_NAME, NULL)) { RTC_LOG(LS_INFO) << "[PowerManagement] Found service: " << BUS_SERVICE_NAME; } else { @@ -52,7 +60,7 @@ namespace jni return; } - DBusMessage * message = dbus_message_new_method_call(BUS_SERVICE_NAME, BUS_SERVICE_PATH, BUS_INTERFACE, + DBusMessage * message = dbus.dbus_message_new_method_call(BUS_SERVICE_NAME, BUS_SERVICE_PATH, BUS_INTERFACE, "Inhibit"); if (message == nullptr) { @@ -60,44 +68,51 @@ namespace jni return; } - dbus_message_append_args(message, DBUS_TYPE_STRING, &appName, DBUS_TYPE_STRING, &reason, DBUS_TYPE_INVALID); + dbus.dbus_message_append_args(message, DBUS_TYPE_STRING, &appName, DBUS_TYPE_STRING, &reason, DBUS_TYPE_INVALID); - DBusMessage * reply = dbus_connection_send_with_reply_and_block(dbusConnection, message, 50, &error); - dbus_message_unref(message); + DBusMessage * reply = dbus.dbus_connection_send_with_reply_and_block(dbusConnection, message, 50, &error); + dbus.dbus_message_unref(message); - if (dbus_error_is_set(&error)) { - dbus_error_free(&error); - dbus_connection_unref(dbusConnection); + if (dbus.dbus_error_is_set(&error)) { + dbus.dbus_error_free(&error); + dbus.dbus_connection_unref(dbusConnection); // throw RTC_LOG(LS_ERROR) << "[PowerManagement] Cannot retrieve cookie"; return; } DBusMessageIter reply_iter; - dbus_message_iter_init(reply, &reply_iter); - dbus_message_iter_get_basic(&reply_iter, &dbusCookie); + dbus.dbus_message_iter_init(reply, &reply_iter); + dbus.dbus_message_iter_get_basic(&reply_iter, &dbusCookie); RTC_LOG(LS_INFO) << "[PowerManagement] Acquired screensaver inhibition cookie"; - dbus_message_unref(reply); - dbus_connection_unref(dbusConnection); + dbus.dbus_message_unref(reply); + dbus.dbus_connection_unref(dbusConnection); } void LinuxPowerManagement::disableUserActivity() { + if (!DBusLoader::instance().load()) { + RTC_LOG(LS_WARNING) << "[PowerManagement] libdbus not found on system"; + return; + } + + auto & dbus = DBusLoader::instance(); + DBusError error; - dbus_error_init(&error); + dbus.dbus_error_init(&error); - DBusConnection * dbusConnection = dbus_bus_get(DBUS_BUS_SESSION, &error); + DBusConnection * dbusConnection = dbus.dbus_bus_get(DBUS_BUS_SESSION, &error); - if (dbus_error_is_set(&error)) { + if (dbus.dbus_error_is_set(&error)) { // throw RTC_LOG(LS_ERROR) << "[PowerManagement] Cannot connect to session bus: " << error.message; - dbus_error_free(&error); + dbus.dbus_error_free(&error); return; } - DBusMessage * message = dbus_message_new_method_call(BUS_SERVICE_NAME, BUS_SERVICE_PATH, BUS_INTERFACE, + DBusMessage * message = dbus.dbus_message_new_method_call(BUS_SERVICE_NAME, BUS_SERVICE_PATH, BUS_INTERFACE, "UnInhibit"); if (message == nullptr) { @@ -105,24 +120,24 @@ namespace jni return; } - dbus_message_append_args(message, DBUS_TYPE_UINT32, &dbusCookie, DBUS_TYPE_INVALID); + dbus.dbus_message_append_args(message, DBUS_TYPE_UINT32, &dbusCookie, DBUS_TYPE_INVALID); - DBusMessage * reply = dbus_connection_send_with_reply_and_block(dbusConnection, message, 50, &error); - dbus_message_unref(message); + DBusMessage * reply = dbus.dbus_connection_send_with_reply_and_block(dbusConnection, message, 50, &error); + dbus.dbus_message_unref(message); - if (dbus_error_is_set(&error)) { + if (dbus.dbus_error_is_set(&error)) { // throw RTC_LOG(LS_ERROR) << "[PowerManagement] Cannot release cookie"; - dbus_error_free(&error); - dbus_connection_unref(dbusConnection); + dbus.dbus_error_free(&error); + dbus.dbus_connection_unref(dbusConnection); return; } RTC_LOG(LS_INFO) << "[PowerManagement] Released screensaver inhibition cookie"; - dbus_message_unref(reply); - dbus_connection_unref(dbusConnection); + dbus.dbus_message_unref(reply); + dbus.dbus_connection_unref(dbusConnection); } } } \ No newline at end of file From 0cf2f0a14a1eb339abfca30e4234683f8bc3107f Mon Sep 17 00:00:00 2001 From: SendableMetatype <263203301+SendableMetatype@users.noreply.github.com> Date: Sun, 6 Sep 2026 14:57:11 +0200 Subject: [PATCH 3/3] ci: run the native tests without libudev and libdbus The test runners no longer install the two libraries, so the lanes verify that the natives load without them. --- .github/actions/test-natives/action.yml | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/.github/actions/test-natives/action.yml b/.github/actions/test-natives/action.yml index 9fbd44e5..3866de00 100644 --- a/.github/actions/test-natives/action.yml +++ b/.github/actions/test-natives/action.yml @@ -39,21 +39,22 @@ runs: name: natives-${{ inputs.platform-name }} path: natives - # PulseAudio is deliberately absent on the test runners: the natives open - # it at runtime, and the tests prove that they load without it. + # PulseAudio, libudev and libdbus are deliberately not installed here: the + # natives open them at runtime, and the armhf lane, whose image has none of + # them, proves that they load without them. - name: Install 32-bit runtime libraries if: runner.os == 'Linux' && inputs.java-architecture == 'armv7' run: | sudo dpkg --add-architecture armhf sudo apt-get update - sudo apt-get install -y libc6:armhf libstdc++6:armhf zlib1g:armhf libx11-6:armhf libxext6:armhf libxfixes3:armhf libxdamage1:armhf libxtst6:armhf libxrandr2:armhf libxcomposite1:armhf libglib2.0-0:armhf libgbm1:armhf libdrm2:armhf libdbus-1-3:armhf libudev1:armhf + sudo apt-get install -y libc6:armhf libstdc++6:armhf zlib1g:armhf libx11-6:armhf libxext6:armhf libxfixes3:armhf libxdamage1:armhf libxtst6:armhf libxrandr2:armhf libxcomposite1:armhf libglib2.0-0:armhf libgbm1:armhf libdrm2:armhf shell: bash - name: Install runtime libraries if: runner.os == 'Linux' && inputs.java-architecture != 'armv7' run: | sudo apt-get update - sudo apt-get install -y libx11-6 libxext6 libxfixes3 libxdamage1 libxtst6 libxrandr2 libxcomposite1 libglib2.0-0 libgbm1 libdrm2 libdbus-1-3 libudev1 + sudo apt-get install -y libx11-6 libxext6 libxfixes3 libxdamage1 libxtst6 libxrandr2 libxcomposite1 libglib2.0-0 libgbm1 libdrm2 shell: bash - name: Set up JDK ${{ inputs.java-version }}