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 }} 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/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/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/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 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)