From 6497c82a7de3e4c3f90b33fc6f4f476f29a4cdec Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 15 Sep 2016 17:51:34 +0200 Subject: [PATCH] Use v4l2 monitor Use the v4l2 monitor to dynamically add and remove nodes. Use the info from the monitor as parameter for the factory init and use it to configure the new node. Add info to the node. Use info from the factory as properties on the PinosNode --- pinos/Makefile.am | 2 +- pinos/modules/spa/module.c | 4 +- pinos/modules/spa/spa-v4l2-monitor.c | 389 ++++++++++++++++++++++++ pinos/modules/spa/spa-v4l2-monitor.h | 58 ++++ pinos/modules/spa/spa-v4l2-source.c | 207 ------------- pinos/modules/spa/spa-v4l2-source.h | 61 ---- pinos/server/daemon.c | 7 +- pinos/server/link.c | 17 +- pinos/server/node.c | 54 ++-- spa/include/spa/monitor.h | 1 - spa/include/spa/node.h | 6 + spa/include/spa/plugin.h | 6 +- spa/plugins/alsa/alsa-sink.c | 3 +- spa/plugins/audiomixer/audiomixer.c | 3 +- spa/plugins/audiotestsrc/audiotestsrc.c | 3 +- spa/plugins/ffmpeg/ffmpeg-dec.c | 1 + spa/plugins/ffmpeg/ffmpeg-enc.c | 1 + spa/plugins/ffmpeg/ffmpeg.c | 4 +- spa/plugins/remote/proxy.c | 3 +- spa/plugins/v4l2/v4l2-monitor.c | 10 +- spa/plugins/v4l2/v4l2-source.c | 11 +- spa/plugins/volume/volume.c | 3 +- spa/plugins/xv/xv-sink.c | 3 +- 23 files changed, 542 insertions(+), 315 deletions(-) create mode 100644 pinos/modules/spa/spa-v4l2-monitor.c create mode 100644 pinos/modules/spa/spa-v4l2-monitor.h delete mode 100644 pinos/modules/spa/spa-v4l2-source.c delete mode 100644 pinos/modules/spa/spa-v4l2-source.h diff --git a/pinos/Makefile.am b/pinos/Makefile.am index ee0eb4e9d..359fb7402 100644 --- a/pinos/Makefile.am +++ b/pinos/Makefile.am @@ -247,7 +247,7 @@ module_LTLIBRARIES += module-spa.la module_spa_la_SOURCES = \ modules/spa/spa-audiotestsrc.c \ modules/spa/spa-alsa-sink.c \ - modules/spa/spa-v4l2-source.c \ + modules/spa/spa-v4l2-monitor.c \ modules/spa/module.c module_spa_la_CFLAGS = $(AM_CFLAGS) module_spa_la_LDFLAGS = $(MODULE_LDFLAGS) diff --git a/pinos/modules/spa/module.c b/pinos/modules/spa/module.c index 0ccc1929f..7722262e4 100644 --- a/pinos/modules/spa/module.c +++ b/pinos/modules/spa/module.c @@ -22,7 +22,7 @@ #include #include "spa-alsa-sink.h" -#include "spa-v4l2-source.h" +#include "spa-v4l2-monitor.h" #include "spa-audiotestsrc.h" gboolean pinos__module_init (PinosModule *module, const gchar * args); @@ -31,7 +31,7 @@ G_MODULE_EXPORT gboolean pinos__module_init (PinosModule * module, G_GNUC_UNUSED const gchar * args) { pinos_spa_alsa_sink_new (module->daemon, "alsa-sink", NULL); - pinos_spa_v4l2_source_new (module->daemon, "v4l2-source", NULL); + pinos_spa_v4l2_monitor_new (module->daemon); pinos_spa_audiotestsrc_new (module->daemon, "audiotestsrc", NULL); return TRUE; diff --git a/pinos/modules/spa/spa-v4l2-monitor.c b/pinos/modules/spa/spa-v4l2-monitor.c new file mode 100644 index 000000000..794633f45 --- /dev/null +++ b/pinos/modules/spa/spa-v4l2-monitor.c @@ -0,0 +1,389 @@ +/* Pinos + * Copyright (C) 2015 Wim Taymans + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#define _GNU_SOURCE + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include "spa-v4l2-monitor.h" + +#define PINOS_SPA_V4L2_MONITOR_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((obj), PINOS_TYPE_SPA_V4L2_MONITOR, PinosSpaV4l2MonitorPrivate)) + +struct _PinosSpaV4l2MonitorPrivate +{ + PinosDaemon *daemon; + + SpaHandle *handle; + SpaMonitor *monitor; + + GSource *watch_source; + + unsigned int n_poll; + SpaPollItem poll[16]; + + GHashTable *nodes; +}; + +enum +{ + PROP_0, + PROP_DAEMON, + PROP_MONITOR, +}; + +G_DEFINE_TYPE (PinosSpaV4l2Monitor, pinos_spa_v4l2_monitor, G_TYPE_OBJECT); + +static SpaResult +make_handle (SpaHandle **handle, const char *lib, const char *name, const SpaDict *info) +{ + SpaResult res; + void *hnd, *state = NULL; + SpaEnumHandleFactoryFunc enum_func; + + if ((hnd = dlopen (lib, RTLD_NOW)) == NULL) { + g_error ("can't load %s: %s", lib, dlerror()); + return SPA_RESULT_ERROR; + } + if ((enum_func = dlsym (hnd, "spa_enum_handle_factory")) == NULL) { + g_error ("can't find enum function"); + return SPA_RESULT_ERROR; + } + + while (true) { + const SpaHandleFactory *factory; + + if ((res = enum_func (&factory, &state)) < 0) { + if (res != SPA_RESULT_ENUM_END) + g_error ("can't enumerate factories: %d", res); + break; + } + if (strcmp (factory->name, name)) + continue; + + *handle = g_malloc0 (factory->size); + if ((res = spa_handle_factory_init (factory, *handle, info)) < 0) { + g_error ("can't make factory instance: %d", res); + return res; + } + return SPA_RESULT_OK; + } + return SPA_RESULT_ERROR; +} + +static void +add_item (PinosSpaV4l2Monitor *this, SpaMonitorItem *item) +{ + PinosSpaV4l2MonitorPrivate *priv = this->priv; + SpaResult res; + SpaHandle *handle; + PinosNode *node; + void *iface; + PinosProperties *props = NULL; + + g_debug ("v4l2-monitor %p: add: \"%s\" (%s)", this, item->name, item->id); + + handle = calloc (1, item->factory->size); + if ((res = spa_handle_factory_init (item->factory, handle, item->info)) < 0) { + g_error ("can't make factory instance: %d", res); + return; + } + if ((res = spa_handle_get_interface (handle, SPA_INTERFACE_ID_NODE, &iface)) < 0) { + g_error ("can't get MONITOR interface: %d", res); + return; + } + + if (item->info) { + unsigned int i; + + props = pinos_properties_new (NULL, NULL); + + for (i = 0; i < item->info->n_items; i++) + pinos_properties_set (props, + item->info->items[i].key, + item->info->items[i].value); + } + + node = g_object_new (PINOS_TYPE_NODE, + "daemon", priv->daemon, + "name", item->factory->name, + "node", iface, + "properties", props, + NULL); + + g_hash_table_insert (priv->nodes, g_strdup (item->id), node); +} + +static void +remove_item (PinosSpaV4l2Monitor *this, SpaMonitorItem *item) +{ + PinosSpaV4l2MonitorPrivate *priv = this->priv; + PinosNode *node; + + g_debug ("v4l2-monitor %p: remove: \"%s\" (%s)", this, item->name, item->id); + + node = g_hash_table_lookup (priv->nodes, item->id); + if (node) { + pinos_node_remove (node); + g_hash_table_remove (priv->nodes, item->id); + } +} + +static gboolean +poll_event (GIOChannel *source, + GIOCondition condition, + gpointer user_data) +{ + PinosSpaV4l2Monitor *this = user_data; + PinosSpaV4l2MonitorPrivate *priv = this->priv; + SpaPollNotifyData data; + + data.user_data = priv->poll[0].user_data; + data.fds = priv->poll[0].fds; + data.n_fds = priv->poll[0].n_fds; + priv->poll[0].after_cb (&data); + + return TRUE; +} + +static void +on_monitor_event (SpaMonitor *monitor, + SpaMonitorEvent *event, + void *user_data) +{ + PinosSpaV4l2Monitor *this = user_data; + PinosSpaV4l2MonitorPrivate *priv = this->priv; + + switch (event->type) { + case SPA_MONITOR_EVENT_TYPE_ADDED: + { + SpaMonitorItem *item = event->data; + add_item (this, item); + break; + } + case SPA_MONITOR_EVENT_TYPE_REMOVED: + { + SpaMonitorItem *item = event->data; + remove_item (this, item); + } + case SPA_MONITOR_EVENT_TYPE_CHANGED: + { + SpaMonitorItem *item = event->data; + g_debug ("v4l2-monitor %p: changed: \"%s\"", this, item->name); + break; + } + case SPA_MONITOR_EVENT_TYPE_ADD_POLL: + { + SpaPollItem *item = event->data; + GIOChannel *channel; + + priv->poll[priv->n_poll] = *item; + priv->n_poll++; + + channel = g_io_channel_unix_new (item->fds[0].fd); + priv->watch_source = g_io_create_watch (channel, G_IO_IN); + g_io_channel_unref (channel); + g_source_set_callback (priv->watch_source, (GSourceFunc) poll_event, this, NULL); + g_source_attach (priv->watch_source, g_main_context_get_thread_default ()); + g_source_unref (priv->watch_source); + break; + } + case SPA_MONITOR_EVENT_TYPE_UPDATE_POLL: + break; + case SPA_MONITOR_EVENT_TYPE_REMOVE_POLL: + { + priv->n_poll--; + g_source_destroy (priv->watch_source); + priv->watch_source = NULL; + break; + } + default: + break; + } +} + +static void +monitor_constructed (GObject * object) +{ + PinosSpaV4l2Monitor *this = PINOS_SPA_V4L2_MONITOR (object); + PinosSpaV4l2MonitorPrivate *priv = this->priv; + SpaResult res; + void *state = NULL; + + g_debug ("spa-monitor %p: constructed", this); + + G_OBJECT_CLASS (pinos_spa_v4l2_monitor_parent_class)->constructed (object); + + while (TRUE) { + SpaMonitorItem *item; + + if ((res = spa_monitor_enum_items (priv->monitor, &item, &state)) < 0) { + if (res != SPA_RESULT_ENUM_END) + g_debug ("spa_monitor_enum_items: got error %d\n", res); + break; + } + add_item (this, item); + } + spa_monitor_set_event_callback (priv->monitor, on_monitor_event, this); +} + +static void +monitor_get_property (GObject *_object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + PinosSpaV4l2Monitor *this = PINOS_SPA_V4L2_MONITOR (_object); + PinosSpaV4l2MonitorPrivate *priv = this->priv; + + switch (prop_id) { + case PROP_DAEMON: + g_value_set_object (value, priv->daemon); + break; + + case PROP_MONITOR: + g_value_set_pointer (value, priv->monitor); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (this, prop_id, pspec); + break; + } +} + +static void +monitor_set_property (GObject *_object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + PinosSpaV4l2Monitor *this = PINOS_SPA_V4L2_MONITOR (_object); + PinosSpaV4l2MonitorPrivate *priv = this->priv; + + switch (prop_id) { + case PROP_DAEMON: + priv->daemon = g_value_dup_object (value); + break; + + case PROP_MONITOR: + priv->monitor = g_value_get_pointer (value); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (this, prop_id, pspec); + break; + } +} + +static void +monitor_finalize (GObject * object) +{ + PinosSpaV4l2Monitor *this = PINOS_SPA_V4L2_MONITOR (object); + PinosSpaV4l2MonitorPrivate *priv = this->priv; + + g_debug ("spa-monitor %p: dispose", this); + spa_handle_clear (priv->handle); + g_free (priv->handle); + g_hash_table_unref (priv->nodes); + + G_OBJECT_CLASS (pinos_spa_v4l2_monitor_parent_class)->finalize (object); +} + +static void +pinos_spa_v4l2_monitor_class_init (PinosSpaV4l2MonitorClass * klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + + g_type_class_add_private (klass, sizeof (PinosSpaV4l2MonitorPrivate)); + + gobject_class->constructed = monitor_constructed; + gobject_class->finalize = monitor_finalize; + gobject_class->set_property = monitor_set_property; + gobject_class->get_property = monitor_get_property; + + g_object_class_install_property (gobject_class, + PROP_DAEMON, + g_param_spec_object ("daemon", + "Daemon", + "The Daemon", + PINOS_TYPE_DAEMON, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, + PROP_MONITOR, + g_param_spec_pointer ("monitor", + "Monitor", + "The SPA monitor", + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS)); +} + +static void +pinos_spa_v4l2_monitor_init (PinosSpaV4l2Monitor * this) +{ + PinosSpaV4l2MonitorPrivate *priv = this->priv = PINOS_SPA_V4L2_MONITOR_GET_PRIVATE (this); + + priv->nodes = g_hash_table_new_full (g_str_hash, + g_str_equal, + g_free, + g_object_unref); +} + +GObject * +pinos_spa_v4l2_monitor_new (PinosDaemon *daemon) +{ + GObject *monitor; + SpaHandle *handle; + SpaResult res; + void *iface; + + if ((res = make_handle (&handle, + "spa/build/plugins/v4l2/libspa-v4l2.so", + "v4l2-monitor", + NULL)) < 0) { + g_error ("can't create v4l2-monitor: %d", res); + return NULL; + } + + if ((res = spa_handle_get_interface (handle, SPA_INTERFACE_ID_MONITOR, &iface)) < 0) { + g_free (handle); + g_error ("can't get MONITOR interface: %d", res); + return NULL; + } + + monitor = g_object_new (PINOS_TYPE_SPA_V4L2_MONITOR, + "daemon", daemon, + "monitor", iface, + NULL); + return monitor; +} diff --git a/pinos/modules/spa/spa-v4l2-monitor.h b/pinos/modules/spa/spa-v4l2-monitor.h new file mode 100644 index 000000000..008ed39c3 --- /dev/null +++ b/pinos/modules/spa/spa-v4l2-monitor.h @@ -0,0 +1,58 @@ +/* Pinos + * Copyright (C) 2015 Wim Taymans + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __PINOS_SPA_V4L2_MONITOR_H__ +#define __PINOS_SPA_V4L2_MONITOR_H__ + +#include + +#include + +G_BEGIN_DECLS + +#define PINOS_TYPE_SPA_V4L2_MONITOR (pinos_spa_v4l2_monitor_get_type ()) +#define PINOS_IS_SPA_V4L2_MONITOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PINOS_TYPE_SPA_V4L2_MONITOR)) +#define PINOS_IS_SPA_V4L2_MONITOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PINOS_TYPE_SPA_V4L2_MONITOR)) +#define PINOS_SPA_V4L2_MONITOR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PINOS_TYPE_SPA_V4L2_MONITOR, PinosSpaV4l2MonitorClass)) +#define PINOS_SPA_V4L2_MONITOR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PINOS_TYPE_SPA_V4L2_MONITOR, PinosSpaV4l2Monitor)) +#define PINOS_SPA_V4L2_MONITOR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PINOS_TYPE_SPA_V4L2_MONITOR, PinosSpaV4l2MonitorClass)) +#define PINOS_SPA_V4L2_MONITOR_CAST(obj) ((PinosSpaV4l2Monitor*)(obj)) +#define PINOS_SPA_V4L2_MONITOR_CLASS_CAST(klass) ((PinosSpaV4l2MonitorClass*)(klass)) + +typedef struct _PinosSpaV4l2Monitor PinosSpaV4l2Monitor; +typedef struct _PinosSpaV4l2MonitorClass PinosSpaV4l2MonitorClass; +typedef struct _PinosSpaV4l2MonitorPrivate PinosSpaV4l2MonitorPrivate; + +struct _PinosSpaV4l2Monitor { + GObject object; + + PinosSpaV4l2MonitorPrivate *priv; +}; + +struct _PinosSpaV4l2MonitorClass { + GObjectClass parent_class; +}; + +GType pinos_spa_v4l2_monitor_get_type (void); + +GObject * pinos_spa_v4l2_monitor_new (PinosDaemon *daemon); + +G_END_DECLS + +#endif /* __PINOS_SPA_V4L2_MONITOR_H__ */ diff --git a/pinos/modules/spa/spa-v4l2-source.c b/pinos/modules/spa/spa-v4l2-source.c deleted file mode 100644 index 94cbcd863..000000000 --- a/pinos/modules/spa/spa-v4l2-source.c +++ /dev/null @@ -1,207 +0,0 @@ -/* Pinos - * Copyright (C) 2015 Wim Taymans - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, - * Boston, MA 02110-1301, USA. - */ - -#define _GNU_SOURCE - -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include -#include - -#include "spa-v4l2-source.h" - -#define PINOS_SPA_V4L2_SOURCE_GET_PRIVATE(obj) \ - (G_TYPE_INSTANCE_GET_PRIVATE ((obj), PINOS_TYPE_SPA_V4L2_SOURCE, PinosSpaV4l2SourcePrivate)) - -struct _PinosSpaV4l2SourcePrivate -{ - gint dummy; -}; - -enum { - PROP_0, -}; - -G_DEFINE_TYPE (PinosSpaV4l2Source, pinos_spa_v4l2_source, PINOS_TYPE_NODE); - -static SpaResult -make_node (SpaNode **node, const char *lib, const char *name) -{ - SpaHandle *handle; - SpaResult res; - void *hnd, *state = NULL; - SpaEnumHandleFactoryFunc enum_func; - - if ((hnd = dlopen (lib, RTLD_NOW)) == NULL) { - g_error ("can't load %s: %s", lib, dlerror()); - return SPA_RESULT_ERROR; - } - if ((enum_func = dlsym (hnd, "spa_enum_handle_factory")) == NULL) { - g_error ("can't find enum function"); - return SPA_RESULT_ERROR; - } - - while (true) { - const SpaHandleFactory *factory; - void *iface; - - if ((res = enum_func (&factory, &state)) < 0) { - if (res != SPA_RESULT_ENUM_END) - g_error ("can't enumerate factories: %d", res); - break; - } - if (strcmp (factory->name, name)) - continue; - - handle = calloc (1, factory->size); - if ((res = spa_handle_factory_init (factory, handle, NULL)) < 0) { - g_error ("can't make factory instance: %d", res); - return res; - } - if ((res = spa_handle_get_interface (handle, SPA_INTERFACE_ID_NODE, &iface)) < 0) { - g_error ("can't get interface %d", res); - return res; - } - *node = iface; - return SPA_RESULT_OK; - } - return SPA_RESULT_ERROR; -} - -static void -setup_node (PinosSpaV4l2Source *this) -{ - PinosNode *node = PINOS_NODE (this); - SpaResult res; - SpaProps *props; - SpaPropValue value; - - if ((res = spa_node_get_props (node->node, &props)) < 0) - g_debug ("got get_props error %d", res); - - value.value = "/dev/video1"; - value.size = strlen (value.value)+1; - spa_props_set_prop (props, spa_props_index_for_name (props, "device"), &value); - - if ((res = spa_node_set_props (node->node, props)) < 0) - g_debug ("got set_props error %d", res); -} - -static void -get_property (GObject *object, - guint prop_id, - GValue *value, - GParamSpec *pspec) -{ - switch (prop_id) { - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -set_property (GObject *object, - guint prop_id, - const GValue *value, - GParamSpec *pspec) -{ - switch (prop_id) { - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -source_constructed (GObject * object) -{ - PinosSpaV4l2Source *source = PINOS_SPA_V4L2_SOURCE (object); - - G_OBJECT_CLASS (pinos_spa_v4l2_source_parent_class)->constructed (object); - - setup_node (source); -} - -static void -source_finalize (GObject * object) -{ - PinosNode *node = PINOS_NODE (object); - PinosSpaV4l2Source *source = PINOS_SPA_V4L2_SOURCE (object); - - g_debug ("spa-source %p: dispose", source); - spa_handle_clear (node->node->handle); - g_free (node->node->handle); - - G_OBJECT_CLASS (pinos_spa_v4l2_source_parent_class)->finalize (object); -} - -static void -pinos_spa_v4l2_source_class_init (PinosSpaV4l2SourceClass * klass) -{ - GObjectClass *gobject_class = G_OBJECT_CLASS (klass); - - g_type_class_add_private (klass, sizeof (PinosSpaV4l2SourcePrivate)); - - gobject_class->constructed = source_constructed; - gobject_class->finalize = source_finalize; - gobject_class->get_property = get_property; - gobject_class->set_property = set_property; -} - -static void -pinos_spa_v4l2_source_init (PinosSpaV4l2Source * source) -{ - source->priv = PINOS_SPA_V4L2_SOURCE_GET_PRIVATE (source); -} - -PinosNode * -pinos_spa_v4l2_source_new (PinosDaemon *daemon, - const gchar *name, - PinosProperties *properties) -{ - PinosNode *node; - SpaNode *n; - SpaResult res; - - if ((res = make_node (&n, - "spa/build/plugins/v4l2/libspa-v4l2.so", - "v4l2-source")) < 0) { - g_error ("can't create v4l2-source: %d", res); - return NULL; - } - - node = g_object_new (PINOS_TYPE_SPA_V4L2_SOURCE, - "daemon", daemon, - "name", name, - "properties", properties, - "node", n, - NULL); - - return node; -} diff --git a/pinos/modules/spa/spa-v4l2-source.h b/pinos/modules/spa/spa-v4l2-source.h deleted file mode 100644 index efc5df962..000000000 --- a/pinos/modules/spa/spa-v4l2-source.h +++ /dev/null @@ -1,61 +0,0 @@ -/* Pinos - * Copyright (C) 2015 Wim Taymans - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, - * Boston, MA 02110-1301, USA. - */ - -#ifndef __PINOS_SPA_V4L2_SOURCE_H__ -#define __PINOS_SPA_V4L2_SOURCE_H__ - -#include - -#include -#include - -G_BEGIN_DECLS - -#define PINOS_TYPE_SPA_V4L2_SOURCE (pinos_spa_v4l2_source_get_type ()) -#define PINOS_IS_SPA_V4L2_SOURCE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PINOS_TYPE_SPA_V4L2_SOURCE)) -#define PINOS_IS_SPA_V4L2_SOURCE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PINOS_TYPE_SPA_V4L2_SOURCE)) -#define PINOS_SPA_V4L2_SOURCE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PINOS_TYPE_SPA_V4L2_SOURCE, PinosSpaV4l2SourceClass)) -#define PINOS_SPA_V4L2_SOURCE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PINOS_TYPE_SPA_V4L2_SOURCE, PinosSpaV4l2Source)) -#define PINOS_SPA_V4L2_SOURCE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PINOS_TYPE_SPA_V4L2_SOURCE, PinosSpaV4l2SourceClass)) -#define PINOS_SPA_V4L2_SOURCE_CAST(obj) ((PinosSpaV4l2Source*)(obj)) -#define PINOS_SPA_V4L2_SOURCE_CLASS_CAST(klass) ((PinosSpaV4l2SourceClass*)(klass)) - -typedef struct _PinosSpaV4l2Source PinosSpaV4l2Source; -typedef struct _PinosSpaV4l2SourceClass PinosSpaV4l2SourceClass; -typedef struct _PinosSpaV4l2SourcePrivate PinosSpaV4l2SourcePrivate; - -struct _PinosSpaV4l2Source { - PinosNode object; - - PinosSpaV4l2SourcePrivate *priv; -}; - -struct _PinosSpaV4l2SourceClass { - PinosNodeClass parent_class; -}; - -GType pinos_spa_v4l2_source_get_type (void); - -PinosNode * pinos_spa_v4l2_source_new (PinosDaemon *daemon, - const gchar *name, - PinosProperties *properties); - -G_END_DECLS - -#endif /* __PINOS_SPA_V4L2_SOURCE_H__ */ diff --git a/pinos/server/daemon.c b/pinos/server/daemon.c index 564a4f433..adb8a0019 100644 --- a/pinos/server/daemon.c +++ b/pinos/server/daemon.c @@ -525,8 +525,7 @@ pinos_daemon_remove_node (PinosDaemon *daemon, * * Find the best port in @daemon that matches the given parameters. * - * Returns: a #PinosPort or %NULL when no port could be found. unref the port - * after usage. + * Returns: a #PinosPort or %NULL when no port could be found. */ PinosNode * pinos_daemon_find_node (PinosDaemon *daemon, @@ -566,9 +565,7 @@ pinos_daemon_find_node (PinosDaemon *daemon, G_IO_ERROR, G_IO_ERROR_NOT_FOUND, "No matching Node found"); - } else - g_object_ref (best); - + } return best; } diff --git a/pinos/server/link.c b/pinos/server/link.c index 1517dd45a..20779466e 100644 --- a/pinos/server/link.c +++ b/pinos/server/link.c @@ -479,12 +479,23 @@ on_property_notify (GObject *obj, } } +static void +on_node_remove (PinosNode *node, PinosLink *this) +{ + g_signal_handlers_disconnect_by_data (node, this); + if (node == this->input_node) + g_clear_object (&this->input_node); + else + g_clear_object (&this->output_node); +} static void pinos_link_constructed (GObject * object) { PinosLink *this = PINOS_LINK (object); + g_signal_connect (this->input_node, "remove", (GCallback) on_node_remove, this); + g_signal_connect (this->output_node, "remove", (GCallback) on_node_remove, this); g_signal_connect (this->input_node, "notify::node-state", (GCallback) on_node_state_notify, this); g_signal_connect (this->output_node, "notify::node-state", (GCallback) on_node_state_notify, this); @@ -508,8 +519,10 @@ pinos_link_dispose (GObject * object) g_debug ("link %p: dispose", this); - g_signal_handlers_disconnect_by_data (this->input_node, this); - g_signal_handlers_disconnect_by_data (this->output_node, this); + if (this->input_node) + g_signal_handlers_disconnect_by_data (this->input_node, this); + if (this->output_node) + g_signal_handlers_disconnect_by_data (this->output_node, this); g_signal_emit (this, signals[SIGNAL_REMOVE], 0, NULL); diff --git a/pinos/server/node.c b/pinos/server/node.c index e7cbfeafe..e59273201 100644 --- a/pinos/server/node.c +++ b/pinos/server/node.c @@ -81,7 +81,7 @@ struct _PinosNodePrivate SpaClock *clock; }; -G_DEFINE_ABSTRACT_TYPE (PinosNode, pinos_node, G_TYPE_OBJECT); +G_DEFINE_TYPE (PinosNode, pinos_node, G_TYPE_OBJECT); enum { @@ -735,14 +735,26 @@ pinos_node_constructed (GObject * obj) priv->fds[0].revents = 0; priv->n_fds = 1; + if (this->node->info) { + unsigned int i; + + if (priv->properties == NULL) + priv->properties = pinos_properties_new (NULL, NULL); + + for (i = 0; i < this->node->info->n_items; i++) + pinos_properties_set (priv->properties, + this->node->info->items[i].key, + this->node->info->items[i].value); + } + if ((res = spa_node_set_event_callback (this->node, on_node_event, this)) < 0) g_warning ("node %p: error setting callback", this); update_port_ids (this, TRUE); - if (priv->sender == NULL) { + if (priv->sender == NULL) priv->sender = g_strdup (pinos_daemon_get_sender (priv->daemon)); - } + on_property_notify (G_OBJECT (this), NULL, this); node_register_object (this); @@ -1165,24 +1177,28 @@ do_remove_link (PinosLink *link, PinosNode *node) guint i, n_links; GArray *links; - links = link->output_node->priv->output_links; - n_links = links->len; - for (i = 0; i < n_links; i++) { - NodeLink *l = &g_array_index (links, NodeLink, i); - if (l->link == link) { - l->link = NULL; - if (--link->output_node->priv->n_used_output_links == 0) - pinos_node_report_idle (link->output_node); + if (link->output_node) { + links = link->output_node->priv->output_links; + n_links = links->len; + for (i = 0; i < n_links; i++) { + NodeLink *l = &g_array_index (links, NodeLink, i); + if (l->link == link) { + l->link = NULL; + if (--link->output_node->priv->n_used_output_links == 0) + pinos_node_report_idle (link->output_node); + } } } - links = link->input_node->priv->input_links; - n_links = links->len; - for (i = 0; i < n_links; i++) { - NodeLink *l = &g_array_index (links, NodeLink, i); - if (l->link == link) { - l->link = NULL; - if (--link->input_node->priv->n_used_input_links == 0) - pinos_node_report_idle (link->input_node); + if (link->input_node) { + links = link->input_node->priv->input_links; + n_links = links->len; + for (i = 0; i < n_links; i++) { + NodeLink *l = &g_array_index (links, NodeLink, i); + if (l->link == link) { + l->link = NULL; + if (--link->input_node->priv->n_used_input_links == 0) + pinos_node_report_idle (link->input_node); + } } } } diff --git a/spa/include/spa/monitor.h b/spa/include/spa/monitor.h index 1d2f3669d..a24952102 100644 --- a/spa/include/spa/monitor.h +++ b/spa/include/spa/monitor.h @@ -54,7 +54,6 @@ typedef struct { const char *klass; const SpaDict *info; const SpaHandleFactory *factory; - const void *config; } SpaMonitorItem; /** diff --git a/spa/include/spa/node.h b/spa/include/spa/node.h index 58f35380a..332d93105 100644 --- a/spa/include/spa/node.h +++ b/spa/include/spa/node.h @@ -154,6 +154,12 @@ struct _SpaNode { /* the total size of this node. This can be used to expand this * structure in the future */ size_t size; + /** + * SpaNode::info + * + * Extra information about the node + */ + const SpaDict * info; /** * SpaNode::state: * diff --git a/spa/include/spa/plugin.h b/spa/include/spa/plugin.h index c529feefc..51c0a619f 100644 --- a/spa/include/spa/plugin.h +++ b/spa/include/spa/plugin.h @@ -102,8 +102,8 @@ struct _SpaHandleFactory { * SpaHandleFactory::init * @factory: a #SpaHandleFactory * @handle: a pointer to memory - * @config: extra handle specific config information, usually obtained from - * a #SpaMonitor. + * @info: extra handle specific information, usually obtained + * from a #SpaMonitor. This can be used to configure the handle. * * Initialize an instance of this factory. The caller should allocate * memory at least SpaHandleFactory::size bytes and pass this as @handle. @@ -114,7 +114,7 @@ struct _SpaHandleFactory { */ SpaResult (*init) (const SpaHandleFactory *factory, SpaHandle *handle, - const void *config); + const SpaDict *info); /** * SpaHandle::enum_interface_info: diff --git a/spa/plugins/alsa/alsa-sink.c b/spa/plugins/alsa/alsa-sink.c index 941d6b795..e991885d6 100644 --- a/spa/plugins/alsa/alsa-sink.c +++ b/spa/plugins/alsa/alsa-sink.c @@ -649,6 +649,7 @@ spa_alsa_sink_node_port_pull_output (SpaNode *node, static const SpaNode alsasink_node = { NULL, sizeof (SpaNode), + NULL, SPA_NODE_STATE_INIT, spa_alsa_sink_node_get_props, spa_alsa_sink_node_set_props, @@ -703,7 +704,7 @@ alsa_sink_clear (SpaHandle *handle) static SpaResult alsa_sink_init (const SpaHandleFactory *factory, SpaHandle *handle, - const void *config) + const SpaDict *info) { SpaALSASink *this; diff --git a/spa/plugins/audiomixer/audiomixer.c b/spa/plugins/audiomixer/audiomixer.c index 3804cdcbf..a905e6f1d 100644 --- a/spa/plugins/audiomixer/audiomixer.c +++ b/spa/plugins/audiomixer/audiomixer.c @@ -726,6 +726,7 @@ spa_audiomixer_node_port_push_event (SpaNode *node, static const SpaNode audiomixer_node = { NULL, sizeof (SpaNode), + NULL, SPA_NODE_STATE_INIT, spa_audiomixer_node_get_props, spa_audiomixer_node_set_props, @@ -781,7 +782,7 @@ spa_audiomixer_clear (SpaHandle *handle) static SpaResult spa_audiomixer_init (const SpaHandleFactory *factory, SpaHandle *handle, - const void *config) + const SpaDict *info) { SpaAudioMixer *this; diff --git a/spa/plugins/audiotestsrc/audiotestsrc.c b/spa/plugins/audiotestsrc/audiotestsrc.c index aa08f4a0e..a184b9853 100644 --- a/spa/plugins/audiotestsrc/audiotestsrc.c +++ b/spa/plugins/audiotestsrc/audiotestsrc.c @@ -787,6 +787,7 @@ spa_audiotestsrc_node_port_push_event (SpaNode *node, static const SpaNode audiotestsrc_node = { NULL, sizeof (SpaNode), + NULL, SPA_NODE_STATE_INIT, spa_audiotestsrc_node_get_props, spa_audiotestsrc_node_set_props, @@ -842,7 +843,7 @@ audiotestsrc_clear (SpaHandle *handle) static SpaResult audiotestsrc_init (const SpaHandleFactory *factory, SpaHandle *handle, - const void *config) + const SpaDict *info) { SpaAudioTestSrc *this; diff --git a/spa/plugins/ffmpeg/ffmpeg-dec.c b/spa/plugins/ffmpeg/ffmpeg-dec.c index 584ee937e..7012fefce 100644 --- a/spa/plugins/ffmpeg/ffmpeg-dec.c +++ b/spa/plugins/ffmpeg/ffmpeg-dec.c @@ -503,6 +503,7 @@ spa_ffmpeg_dec_node_port_push_event (SpaNode *node, static const SpaNode ffmpeg_dec_node = { NULL, sizeof (SpaNode), + NULL, SPA_NODE_STATE_INIT, spa_ffmpeg_dec_node_get_props, spa_ffmpeg_dec_node_set_props, diff --git a/spa/plugins/ffmpeg/ffmpeg-enc.c b/spa/plugins/ffmpeg/ffmpeg-enc.c index 8250e2b81..2d97eb943 100644 --- a/spa/plugins/ffmpeg/ffmpeg-enc.c +++ b/spa/plugins/ffmpeg/ffmpeg-enc.c @@ -506,6 +506,7 @@ spa_ffmpeg_enc_node_port_push_event (SpaNode *node, static const SpaNode ffmpeg_enc_node = { NULL, sizeof (SpaNode), + NULL, SPA_NODE_STATE_INIT, spa_ffmpeg_enc_node_get_props, spa_ffmpeg_enc_node_set_props, diff --git a/spa/plugins/ffmpeg/ffmpeg.c b/spa/plugins/ffmpeg/ffmpeg.c index 33b56e5a4..ec87d5fb5 100644 --- a/spa/plugins/ffmpeg/ffmpeg.c +++ b/spa/plugins/ffmpeg/ffmpeg.c @@ -31,7 +31,7 @@ SpaResult spa_ffmpeg_enc_init (SpaHandle *handle); static SpaResult ffmpeg_dec_init (const SpaHandleFactory *factory, SpaHandle *handle, - const void *config) + const SpaDict *info) { if (factory == NULL || handle == NULL) return SPA_RESULT_INVALID_ARGUMENTS; @@ -42,7 +42,7 @@ ffmpeg_dec_init (const SpaHandleFactory *factory, static SpaResult ffmpeg_enc_init (const SpaHandleFactory *factory, SpaHandle *handle, - const void *config) + const SpaDict *info) { if (factory == NULL || handle == NULL) return SPA_RESULT_INVALID_ARGUMENTS; diff --git a/spa/plugins/remote/proxy.c b/spa/plugins/remote/proxy.c index 2a3451270..ae4b26cf7 100644 --- a/spa/plugins/remote/proxy.c +++ b/spa/plugins/remote/proxy.c @@ -1099,6 +1099,7 @@ proxy_on_fd_events (SpaPollNotifyData *data) static const SpaNode proxy_node = { NULL, sizeof (SpaNode), + NULL, SPA_NODE_STATE_INIT, spa_proxy_node_get_props, spa_proxy_node_set_props, @@ -1153,7 +1154,7 @@ proxy_clear (SpaHandle *handle) static SpaResult proxy_init (const SpaHandleFactory *factory, SpaHandle *handle, - const void *config) + const SpaDict *info) { SpaProxy *this; diff --git a/spa/plugins/v4l2/v4l2-monitor.c b/spa/plugins/v4l2/v4l2-monitor.c index 95b155ebd..5b73ef3b0 100644 --- a/spa/plugins/v4l2/v4l2-monitor.c +++ b/spa/plugins/v4l2/v4l2-monitor.c @@ -31,6 +31,8 @@ #include #include +extern const SpaHandleFactory spa_v4l2_source_factory; + typedef struct _SpaV4l2Monitor SpaV4l2Monitor; typedef struct { @@ -81,16 +83,14 @@ fill_item (V4l2Item *item, struct udev_device *udevice) if (udevice == NULL) return; - item->item.id = udev_device_get_devnode (item->udevice); + item->item.id = udev_device_get_syspath (item->udevice); item->item.flags = 0; item->item.state = SPA_MONITOR_ITEM_STATE_AVAILABLE; item->item.klass = "Video/Source"; item->item.info = &item->info; - item->item.factory = NULL; - item->item.config = NULL; + item->item.factory = &spa_v4l2_source_factory; item->info.items = item->info_items; - i = 0; item->info_items[i].key = "udev-probed"; item->info_items[i++].value = "1"; @@ -351,7 +351,7 @@ v4l2_monitor_clear (SpaHandle *handle) static SpaResult v4l2_monitor_init (const SpaHandleFactory *factory, SpaHandle *handle, - const void *config) + const SpaDict *info) { SpaV4l2Monitor *this; diff --git a/spa/plugins/v4l2/v4l2-source.c b/spa/plugins/v4l2/v4l2-source.c index 8aa4e455d..7c82d349f 100644 --- a/spa/plugins/v4l2/v4l2-source.c +++ b/spa/plugins/v4l2/v4l2-source.c @@ -728,6 +728,7 @@ spa_v4l2_source_node_port_push_event (SpaNode *node, static const SpaNode v4l2source_node = { NULL, sizeof (SpaNode), + NULL, SPA_NODE_STATE_INIT, spa_v4l2_source_node_get_props, spa_v4l2_source_node_set_props, @@ -835,9 +836,10 @@ v4l2_source_clear (SpaHandle *handle) static SpaResult v4l2_source_init (const SpaHandleFactory *factory, SpaHandle *handle, - const void *config) + const SpaDict *info) { SpaV4l2Source *this; + unsigned int i; if (factory == NULL || handle == NULL) return SPA_RESULT_INVALID_ARGUMENTS; @@ -859,6 +861,13 @@ v4l2_source_init (const SpaHandleFactory *factory, this->state[0].export_buf = true; + for (i = 0; info && i < info->n_items; i ++) { + if (!strcmp (info->items[i].key, "device.path")) { + strncpy (this->props[1].device, info->items[i].value, 63); + this->props[1].props.unset_mask &= ~1; + } + } + return SPA_RESULT_OK; } diff --git a/spa/plugins/volume/volume.c b/spa/plugins/volume/volume.c index b6f3c56cb..7bbe3d271 100644 --- a/spa/plugins/volume/volume.c +++ b/spa/plugins/volume/volume.c @@ -621,6 +621,7 @@ spa_volume_node_port_push_event (SpaNode *node, static const SpaNode volume_node = { NULL, sizeof (SpaNode), + NULL, SPA_NODE_STATE_INIT, spa_volume_node_get_props, spa_volume_node_set_props, @@ -677,7 +678,7 @@ volume_clear (SpaHandle *handle) static SpaResult volume_init (const SpaHandleFactory *factory, SpaHandle *handle, - const void *config) + const SpaDict *info) { SpaVolume *this; diff --git a/spa/plugins/xv/xv-sink.c b/spa/plugins/xv/xv-sink.c index b12155842..fe30dc130 100644 --- a/spa/plugins/xv/xv-sink.c +++ b/spa/plugins/xv/xv-sink.c @@ -501,6 +501,7 @@ spa_xv_sink_node_port_push_event (SpaNode *node, static const SpaNode xvsink_node = { NULL, sizeof (SpaNode), + NULL, SPA_NODE_STATE_INIT, spa_xv_sink_node_get_props, spa_xv_sink_node_set_props, @@ -556,7 +557,7 @@ xv_sink_clear (SpaHandle *handle) static SpaResult xv_sink_init (const SpaHandleFactory *factory, SpaHandle *handle, - const void *config) + const SpaDict *info) { SpaXvSink *this;