Merge pull request #420 from fryshorts/v4l2-obs-signals

linux-v4l2: Replace custom udev callbacks
master
Jim 2015-04-23 17:59:57 -07:00
commit cd4d79075d
3 changed files with 65 additions and 111 deletions

View File

@ -80,7 +80,6 @@ struct v4l2_data {
obs_source_t *source; obs_source_t *source;
pthread_t thread; pthread_t thread;
os_event_t *event; os_event_t *event;
void *udev;
int_fast32_t dev; int_fast32_t dev;
int width; 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 * If everything went fine we can start capturing again when the device is
* reconnected * reconnected
*/ */
static void device_added(const char *dev, void *vptr) static void device_added(void *vptr, calldata_t *calldata)
{ {
V4L2_DATA(vptr); V4L2_DATA(vptr);
obs_source_update_properties(data->source); obs_source_update_properties(data->source);
const char *dev;
calldata_get_string(calldata, "device", &dev);
if (strcmp(data->device_id, dev)) if (strcmp(data->device_id, dev))
return; 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 * 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); V4L2_DATA(vptr);
obs_source_update_properties(data->source); obs_source_update_properties(data->source);
const char *dev;
calldata_get_string(calldata, "device", &dev);
if (strcmp(data->device_id, dev)) if (strcmp(data->device_id, dev))
return; return;
@ -790,7 +795,12 @@ static void v4l2_destroy(void *vptr)
bfree(data->device_id); bfree(data->device_id);
#if HAVE_UDEV #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 #endif
bfree(data); bfree(data);
@ -946,9 +956,11 @@ static void *v4l2_create(obs_data_t *settings, obs_source_t *source)
v4l2_update(data, settings); v4l2_update(data, settings);
#if HAVE_UDEV #if HAVE_UDEV
data->udev = v4l2_init_udev(); v4l2_init_udev();
v4l2_set_device_added_callback(data->udev, &device_added, data); signal_handler_t *sh = v4l2_get_udev_signalhandler();
v4l2_set_device_removed_callback(data->udev, &device_removed, data);
signal_handler_connect(sh, "device_added", &device_added, data);
signal_handler_connect(sh, "device_removed", &device_removed, data);
#endif #endif
return data; return data;

View File

@ -23,9 +23,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "v4l2-udev.h" #include "v4l2-udev.h"
#define UDEV_DATA(voidptr) struct v4l2_udev_mon_t *m \
= (struct v4l2_udev_mon_t *) voidptr;
/** udev action enum */ /** udev action enum */
enum udev_action { enum udev_action {
UDEV_ACTION_ADDED, UDEV_ACTION_ADDED,
@ -33,14 +30,10 @@ enum udev_action {
UDEV_ACTION_UNKNOWN UDEV_ACTION_UNKNOWN
}; };
/** monitor object holding the callbacks */ static const char *udev_signals[] = {
struct v4l2_udev_mon_t { "void device_added(string device)",
/* data for the device added callback */ "void device_removed(string device)",
void *dev_added_userdata; NULL
v4l2_device_added_cb dev_added_cb;
/* data for the device removed callback */
void *dev_removed_userdata;
v4l2_device_removed_cb dev_removed_cb;
}; };
/* global data */ /* global data */
@ -50,7 +43,7 @@ static pthread_mutex_t udev_mutex = PTHREAD_MUTEX_INITIALIZER;
static pthread_t udev_thread; static pthread_t udev_thread;
static os_event_t *udev_event; 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 ... * udev gives us the device action as string, so we convert it here ...
@ -76,34 +69,35 @@ static enum udev_action udev_action_to_enum(const char *action)
* *
* @param dev udev device that had an event occuring * @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; const char *node;
enum udev_action action; enum udev_action action;
struct calldata data;
pthread_mutex_lock(&udev_mutex); pthread_mutex_lock(&udev_mutex);
node = udev_device_get_devnode(dev); node = udev_device_get_devnode(dev);
action = udev_action_to_enum(udev_device_get_action(dev)); action = udev_action_to_enum(udev_device_get_action(dev));
for (size_t idx = 0; idx < udev_clients.num; idx++) { calldata_init(&data);
struct v4l2_udev_mon_t *c = &udev_clients.array[idx];
calldata_set_string(&data, "device", node);
switch (action) { switch (action) {
case UDEV_ACTION_ADDED: case UDEV_ACTION_ADDED:
if (!c->dev_added_cb) signal_handler_signal(udev_signalhandler,
continue; "device_added", &data);
c->dev_added_cb(node, c->dev_added_userdata);
break; break;
case UDEV_ACTION_REMOVED: case UDEV_ACTION_REMOVED:
if (!c->dev_removed_cb) signal_handler_signal(udev_signalhandler,
continue; "device_removed", &data);
c->dev_removed_cb(node, c->dev_removed_userdata);
break; break;
default: default:
break; break;
} }
}
calldata_free(&data);
pthread_mutex_unlock(&udev_mutex); pthread_mutex_unlock(&udev_mutex);
} }
@ -146,7 +140,7 @@ static void *udev_event_thread(void *vptr)
if (!dev) if (!dev)
continue; continue;
udev_call_callbacks(dev); udev_signal_event(dev);
udev_device_unref(dev); udev_device_unref(dev);
} }
@ -157,10 +151,8 @@ static void *udev_event_thread(void *vptr)
return NULL; return NULL;
} }
void *v4l2_init_udev(void) void v4l2_init_udev(void)
{ {
struct v4l2_udev_mon_t *ret = NULL;
pthread_mutex_lock(&udev_mutex); pthread_mutex_lock(&udev_mutex);
/* set up udev */ /* set up udev */
@ -170,55 +162,38 @@ void *v4l2_init_udev(void)
if (pthread_create(&udev_thread, NULL, udev_event_thread, if (pthread_create(&udev_thread, NULL, udev_event_thread,
NULL) != 0) NULL) != 0)
goto fail; 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++; udev_refs++;
/* create monitor object */
ret = da_push_back_new(udev_clients);
fail: fail:
pthread_mutex_unlock(&udev_mutex); 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); pthread_mutex_lock(&udev_mutex);
/* clean up monitor object */
da_erase_item(udev_clients, m);
/* unref udev monitor */ /* unref udev monitor */
udev_refs--; if (udev_refs && --udev_refs == 0) {
if (udev_refs == 0) {
os_event_signal(udev_event); os_event_signal(udev_event);
pthread_join(udev_thread, NULL); pthread_join(udev_thread, NULL);
os_event_destroy(udev_event); 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); pthread_mutex_unlock(&udev_mutex);
} }
void v4l2_set_device_added_callback(void *monitor, v4l2_device_added_cb cb, signal_handler_t *v4l2_get_udev_signalhandler(void)
void *userdata)
{ {
UDEV_DATA(monitor); return udev_signalhandler;
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;
} }

View File

@ -19,61 +19,28 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include <inttypes.h> #include <inttypes.h>
#include <callback/signal.h>
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
/** /**
* Initialize udev system to watch for device events * 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 * 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 * @return signal handler for udev events
* @param userdata pointer to userdata specified when registered
*/ */
typedef void (*v4l2_device_added_cb)(const char *dev, void *userdata); signal_handler_t *v4l2_get_udev_signalhandler(void);
/**
* 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);
#ifdef __cplusplus #ifdef __cplusplus
} }