diff --git a/plugins/linux-v4l2/v4l2-input.c b/plugins/linux-v4l2/v4l2-input.c index f9e3d8d06..422306262 100644 --- a/plugins/linux-v4l2/v4l2-input.c +++ b/plugins/linux-v4l2/v4l2-input.c @@ -80,7 +80,6 @@ struct v4l2_data { obs_source_t *source; pthread_t thread; os_event_t *event; - void *udev; int_fast32_t dev; int width; @@ -674,12 +673,15 @@ static bool resolution_selected(obs_properties_t *props, obs_property_t *p, * If everything went fine we can start capturing again when the device is * reconnected */ -static void device_added(const char *dev, void *vptr) +static void device_added(void *vptr, calldata_t *calldata) { V4L2_DATA(vptr); obs_source_update_properties(data->source); + const char *dev; + calldata_get_string(calldata, "device", &dev); + if (strcmp(data->device_id, dev)) return; @@ -692,12 +694,15 @@ static void device_added(const char *dev, void *vptr) * * We stop recording here so we don't block the device node */ -static void device_removed(const char *dev, void *vptr) +static void device_removed(void *vptr, calldata_t *calldata) { V4L2_DATA(vptr); obs_source_update_properties(data->source); + const char *dev; + calldata_get_string(calldata, "device", &dev); + if (strcmp(data->device_id, dev)) return; @@ -790,7 +795,12 @@ static void v4l2_destroy(void *vptr) bfree(data->device_id); #if HAVE_UDEV - v4l2_unref_udev(data->udev); + signal_handler_t *sh = v4l2_get_udev_signalhandler(); + + signal_handler_disconnect(sh, "device_added", device_added, data); + signal_handler_disconnect(sh, "device_removed", device_removed, data); + + v4l2_unref_udev(); #endif bfree(data); @@ -946,9 +956,11 @@ static void *v4l2_create(obs_data_t *settings, obs_source_t *source) v4l2_update(data, settings); #if HAVE_UDEV - data->udev = v4l2_init_udev(); - v4l2_set_device_added_callback(data->udev, &device_added, data); - v4l2_set_device_removed_callback(data->udev, &device_removed, data); + v4l2_init_udev(); + signal_handler_t *sh = v4l2_get_udev_signalhandler(); + + signal_handler_connect(sh, "device_added", &device_added, data); + signal_handler_connect(sh, "device_removed", &device_removed, data); #endif return data; diff --git a/plugins/linux-v4l2/v4l2-udev.c b/plugins/linux-v4l2/v4l2-udev.c index 8538197e5..44a32d5f2 100644 --- a/plugins/linux-v4l2/v4l2-udev.c +++ b/plugins/linux-v4l2/v4l2-udev.c @@ -23,9 +23,6 @@ along with this program. If not, see . #include "v4l2-udev.h" -#define UDEV_DATA(voidptr) struct v4l2_udev_mon_t *m \ - = (struct v4l2_udev_mon_t *) voidptr; - /** udev action enum */ enum udev_action { UDEV_ACTION_ADDED, @@ -33,14 +30,10 @@ enum udev_action { UDEV_ACTION_UNKNOWN }; -/** monitor object holding the callbacks */ -struct v4l2_udev_mon_t { - /* data for the device added callback */ - void *dev_added_userdata; - v4l2_device_added_cb dev_added_cb; - /* data for the device removed callback */ - void *dev_removed_userdata; - v4l2_device_removed_cb dev_removed_cb; +static const char *udev_signals[] = { + "void device_added(string device)", + "void device_removed(string device)", + NULL }; /* global data */ @@ -50,7 +43,7 @@ static pthread_mutex_t udev_mutex = PTHREAD_MUTEX_INITIALIZER; static pthread_t udev_thread; static os_event_t *udev_event; -static DARRAY(struct v4l2_udev_mon_t) udev_clients; +static signal_handler_t *udev_signalhandler = NULL; /** * udev gives us the device action as string, so we convert it here ... @@ -76,35 +69,36 @@ static enum udev_action udev_action_to_enum(const char *action) * * @param dev udev device that had an event occuring */ -static inline void udev_call_callbacks(struct udev_device *dev) +static inline void udev_signal_event(struct udev_device *dev) { const char *node; enum udev_action action; + struct calldata data; pthread_mutex_lock(&udev_mutex); node = udev_device_get_devnode(dev); action = udev_action_to_enum(udev_device_get_action(dev)); - for (size_t idx = 0; idx < udev_clients.num; idx++) { - struct v4l2_udev_mon_t *c = &udev_clients.array[idx]; + calldata_init(&data); - switch (action) { - case UDEV_ACTION_ADDED: - if (!c->dev_added_cb) - continue; - c->dev_added_cb(node, c->dev_added_userdata); - break; - case UDEV_ACTION_REMOVED: - if (!c->dev_removed_cb) - continue; - c->dev_removed_cb(node, c->dev_removed_userdata); - break; - default: - break; - } + calldata_set_string(&data, "device", node); + + switch (action) { + case UDEV_ACTION_ADDED: + signal_handler_signal(udev_signalhandler, + "device_added", &data); + break; + case UDEV_ACTION_REMOVED: + signal_handler_signal(udev_signalhandler, + "device_removed", &data); + break; + default: + break; } + calldata_free(&data); + pthread_mutex_unlock(&udev_mutex); } @@ -146,7 +140,7 @@ static void *udev_event_thread(void *vptr) if (!dev) continue; - udev_call_callbacks(dev); + udev_signal_event(dev); udev_device_unref(dev); } @@ -157,10 +151,8 @@ static void *udev_event_thread(void *vptr) return NULL; } -void *v4l2_init_udev(void) +void v4l2_init_udev(void) { - struct v4l2_udev_mon_t *ret = NULL; - pthread_mutex_lock(&udev_mutex); /* set up udev */ @@ -170,55 +162,38 @@ void *v4l2_init_udev(void) if (pthread_create(&udev_thread, NULL, udev_event_thread, NULL) != 0) goto fail; - da_init(udev_clients); + + udev_signalhandler = signal_handler_create(); + if (!udev_signalhandler) + goto fail; + signal_handler_add_array(udev_signalhandler, udev_signals); + } udev_refs++; - /* create monitor object */ - ret = da_push_back_new(udev_clients); fail: pthread_mutex_unlock(&udev_mutex); - return ret; } -void v4l2_unref_udev(void *monitor) +void v4l2_unref_udev(void) { - UDEV_DATA(monitor); pthread_mutex_lock(&udev_mutex); - /* clean up monitor object */ - da_erase_item(udev_clients, m); - /* unref udev monitor */ - udev_refs--; - if (udev_refs == 0) { + if (udev_refs && --udev_refs == 0) { os_event_signal(udev_event); pthread_join(udev_thread, NULL); os_event_destroy(udev_event); - da_free(udev_clients); + + if (udev_signalhandler) + signal_handler_destroy(udev_signalhandler); + udev_signalhandler = NULL; } pthread_mutex_unlock(&udev_mutex); } -void v4l2_set_device_added_callback(void *monitor, v4l2_device_added_cb cb, - void *userdata) +signal_handler_t *v4l2_get_udev_signalhandler(void) { - UDEV_DATA(monitor); - if (!m) - return; - - m->dev_added_cb = cb; - m->dev_added_userdata = userdata; -} - -void v4l2_set_device_removed_callback(void *monitor, v4l2_device_removed_cb cb, - void *userdata) -{ - UDEV_DATA(monitor); - if (!m) - return; - - m->dev_removed_cb = cb; - m->dev_removed_userdata = userdata; + return udev_signalhandler; } diff --git a/plugins/linux-v4l2/v4l2-udev.h b/plugins/linux-v4l2/v4l2-udev.h index f95966ca1..9242fab14 100644 --- a/plugins/linux-v4l2/v4l2-udev.h +++ b/plugins/linux-v4l2/v4l2-udev.h @@ -19,61 +19,28 @@ along with this program. If not, see . #include +#include + #ifdef __cplusplus extern "C" { #endif /** * Initialize udev system to watch for device events - * - * @return monitor object, or NULL on error */ -void *v4l2_init_udev(void); +void v4l2_init_udev(void); /** * Unref the udev system - * - * This will also remove any registered callbacks if there are any - * - * @param monitor monitor object */ -void v4l2_unref_udev(void *monitor); +void v4l2_unref_udev(void); /** - * Callback when a device was added. + * Get signal handler * - * @param dev device node of the device that was added - * @param userdata pointer to userdata specified when registered + * @return signal handler for udev events */ -typedef void (*v4l2_device_added_cb)(const char *dev, void *userdata); - -/** - * Callback when a device was removed. - * - * @param dev device node of the device that was removed - * @param userdata pointer to userdata specified when registered - */ -typedef void (*v4l2_device_removed_cb)(const char *dev, void *userdata); - -/** - * Register the device added callback - * - * @param monitor monitor object - * @param cb the function that should be called - * @param userdata pointer to userdata that should be passed to the callback - */ -void v4l2_set_device_added_callback(void *monitor, v4l2_device_added_cb cb, - void *userdata); - -/** - * Register the device remove callback - * - * @param monitor monitor object - * @param cb the function that should be called - * @param userdata pointer to userdata that should be passed to the callback - */ -void v4l2_set_device_removed_callback(void *monitor, v4l2_device_removed_cb cb, - void *userdata); +signal_handler_t *v4l2_get_udev_signalhandler(void); #ifdef __cplusplus }