Merge pull request #420 from fryshorts/v4l2-obs-signals
linux-v4l2: Replace custom udev callbacksmaster
commit
cd4d79075d
|
@ -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;
|
||||||
|
|
|
@ -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;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue