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;