From e34ef88dacbeaa2c659ff2a35d8d78dc48e65c6d Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Mon, 12 Sep 2016 18:29:59 +0200 Subject: [PATCH] node: add port_id Decouple the SPA port ids from the pinos port ids, this allows us to more easily link and relink things and do dynamic connection later. Implement multiple output ports on a pinos node. --- pinos/server/daemon.c | 8 +- pinos/server/link.c | 60 ++++++++++-- pinos/server/link.h | 6 +- pinos/server/node.c | 222 +++++++++++++++++++++++++++--------------- pinos/server/node.h | 6 +- 5 files changed, 213 insertions(+), 89 deletions(-) diff --git a/pinos/server/daemon.c b/pinos/server/daemon.c index 7fd8728e4..0e8df9547 100644 --- a/pinos/server/daemon.c +++ b/pinos/server/daemon.c @@ -214,12 +214,16 @@ on_port_added (PinosNode *node, PinosDirection direction, guint port_id, PinosCl return; } - new_port = pinos_node_get_free_port_id (target, pinos_direction_reverse (direction)); + new_port = pinos_node_get_free_port (target, pinos_direction_reverse (direction)); if (new_port == SPA_ID_INVALID) { g_debug ("daemon %p: can't create free port", this); return; } - link = pinos_node_link (node, port_id, target, new_port, NULL, NULL); + if (direction == PINOS_DIRECTION_OUTPUT) + link = pinos_node_link (node, port_id, target, new_port, NULL, NULL); + else + link = pinos_node_link (target, new_port, node, port_id, NULL, NULL); + pinos_client_add_object (client, G_OBJECT (link)); g_object_unref (link); } diff --git a/pinos/server/link.c b/pinos/server/link.c index dee31497b..83cc3cf6e 100644 --- a/pinos/server/link.c +++ b/pinos/server/link.c @@ -57,8 +57,10 @@ enum PROP_DAEMON, PROP_OBJECT_PATH, PROP_OUTPUT_NODE, + PROP_OUTPUT_ID, PROP_OUTPUT_PORT, PROP_INPUT_NODE, + PROP_INPUT_ID, PROP_INPUT_PORT, PROP_FORMAT_FILTER, PROP_PROPERTIES, @@ -94,6 +96,10 @@ pinos_link_get_property (GObject *_object, g_value_set_object (value, this->output_node); break; + case PROP_OUTPUT_ID: + g_value_set_uint (value, this->output_id); + break; + case PROP_OUTPUT_PORT: g_value_set_uint (value, this->output_port); break; @@ -102,6 +108,10 @@ pinos_link_get_property (GObject *_object, g_value_set_object (value, this->input_node); break; + case PROP_INPUT_ID: + g_value_set_uint (value, this->input_id); + break; + case PROP_INPUT_PORT: g_value_set_uint (value, this->input_port); break; @@ -142,6 +152,10 @@ pinos_link_set_property (GObject *_object, this->output_node = g_value_dup_object (value); break; + case PROP_OUTPUT_ID: + this->output_id = g_value_get_uint (value); + break; + case PROP_OUTPUT_PORT: this->output_port = g_value_get_uint (value); break; @@ -150,6 +164,10 @@ pinos_link_set_property (GObject *_object, this->input_node = g_value_dup_object (value); break; + case PROP_INPUT_ID: + this->input_id = g_value_get_uint (value); + break; + case PROP_INPUT_PORT: this->input_port = g_value_get_uint (value); break; @@ -279,7 +297,7 @@ do_allocation (PinosLink *this, SpaNodeState in_state, SpaNodeState out_state) const SpaPortInfo *iinfo, *oinfo; SpaPortInfoFlags in_flags, out_flags; - if (in_state != SPA_NODE_STATE_READY || out_state != SPA_NODE_STATE_READY) + if (in_state < SPA_NODE_STATE_READY || out_state < SPA_NODE_STATE_READY) return SPA_RESULT_OK; g_debug ("link %p: doing alloc buffers %p %p", this, this->output_node, this->input_node); @@ -296,9 +314,6 @@ do_allocation (PinosLink *this, SpaNodeState in_state, SpaNodeState out_state) spa_debug_port_info (oinfo); spa_debug_port_info (iinfo); - priv->n_in_buffers = 16; - priv->n_out_buffers = 16; - if ((oinfo->flags & SPA_PORT_INFO_FLAG_CAN_ALLOC_BUFFERS) && (iinfo->flags & SPA_PORT_INFO_FLAG_CAN_USE_BUFFERS)) { out_flags = SPA_PORT_INFO_FLAG_CAN_ALLOC_BUFFERS; @@ -309,6 +324,7 @@ do_allocation (PinosLink *this, SpaNodeState in_state, SpaNodeState out_state) in_flags = SPA_PORT_INFO_FLAG_CAN_ALLOC_BUFFERS; } else if ((oinfo->flags & SPA_PORT_INFO_FLAG_CAN_USE_BUFFERS) && (iinfo->flags & SPA_PORT_INFO_FLAG_CAN_USE_BUFFERS)) { + priv->n_in_buffers = 16; out_flags = SPA_PORT_INFO_FLAG_CAN_USE_BUFFERS; in_flags = SPA_PORT_INFO_FLAG_CAN_USE_BUFFERS; @@ -330,7 +346,13 @@ do_allocation (PinosLink *this, SpaNodeState in_state, SpaNodeState out_state) goto error; } + if (in_state > SPA_NODE_STATE_READY) + in_flags &= ~SPA_PORT_INFO_FLAG_CAN_USE_BUFFERS; + if (out_state > SPA_NODE_STATE_READY) + out_flags &= ~SPA_PORT_INFO_FLAG_CAN_USE_BUFFERS; + if (in_flags & SPA_PORT_INFO_FLAG_CAN_ALLOC_BUFFERS) { + priv->n_in_buffers = 16; if ((res = spa_node_port_alloc_buffers (this->input_node->node, this->input_port, oinfo->params, oinfo->n_params, priv->in_buffers, &priv->n_in_buffers)) < 0) { @@ -339,6 +361,7 @@ do_allocation (PinosLink *this, SpaNodeState in_state, SpaNodeState out_state) } } if (out_flags & SPA_PORT_INFO_FLAG_CAN_ALLOC_BUFFERS) { + priv->n_out_buffers = 16; if ((res = spa_node_port_alloc_buffers (this->output_node->node, this->output_port, iinfo->params, iinfo->n_params, priv->out_buffers, &priv->n_out_buffers)) < 0) { @@ -460,8 +483,9 @@ pinos_link_constructed (GObject * object) G_OBJECT_CLASS (pinos_link_parent_class)->constructed (object); on_property_notify (G_OBJECT (this), NULL, this); - g_debug ("link %p: constructed %p:%d -> %p:%d", this, this->output_node, this->output_port, - this->input_node, this->input_port); + g_debug ("link %p: constructed %p:%d:%d -> %p:%d:%d", this, + this->output_node, this->output_id, this->output_port, + this->input_node, this->input_id, this->input_port); link_register_object (this); check_states (this); @@ -535,6 +559,18 @@ pinos_link_class_init (PinosLinkClass * klass) G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, + PROP_OUTPUT_ID, + g_param_spec_uint ("output-id", + "Output Id", + "The output id", + 0, + G_MAXUINT, + -1, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT | + G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_OUTPUT_PORT, g_param_spec_uint ("output-port", @@ -557,6 +593,18 @@ pinos_link_class_init (PinosLinkClass * klass) G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, + PROP_INPUT_ID, + g_param_spec_uint ("input-id", + "Input Id", + "The input id", + 0, + G_MAXUINT, + -1, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT | + G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_INPUT_PORT, g_param_spec_uint ("input-port", diff --git a/pinos/server/link.h b/pinos/server/link.h index f71956c42..f2c5ebeac 100644 --- a/pinos/server/link.h +++ b/pinos/server/link.h @@ -48,9 +48,11 @@ struct _PinosLink { GObject object; PinosNode *output_node; - guint output_port; + guint output_id; + uint32_t output_port; PinosNode *input_node; - guint input_port; + guint input_id; + uint32_t input_port; PinosLinkPrivate *priv; }; diff --git a/pinos/server/node.c b/pinos/server/node.c index eea592e3f..27976e657 100644 --- a/pinos/server/node.c +++ b/pinos/server/node.c @@ -37,6 +37,10 @@ #define PINOS_NODE_GET_PRIVATE(node) \ (G_TYPE_INSTANCE_GET_PRIVATE ((node), PINOS_TYPE_NODE, PinosNodePrivate)) +typedef struct { + PinosLink *link; +} NodeLink; + struct _PinosNodePrivate { PinosDaemon *daemon; @@ -69,7 +73,10 @@ struct _PinosNodePrivate gboolean running; pthread_t thread; - GHashTable *links; + GArray *output_links; + guint n_used_output_links; + GArray *input_links; + guint n_used_input_links; SpaClock *clock; }; @@ -469,38 +476,47 @@ on_node_event (SpaNode *node, SpaNodeEvent *event, void *user_data) } case SPA_NODE_EVENT_TYPE_HAVE_OUTPUT: { - PinosLink *link; SpaPortOutputInfo oinfo[1] = { 0, }; SpaResult res; + guint i; if ((res = spa_node_port_pull_output (node, 1, oinfo)) < 0) { g_warning ("node %p: got pull error %d, %d", this, res, oinfo[0].status); break; } - link = g_hash_table_lookup (priv->links, GUINT_TO_POINTER (oinfo[0].port_id)); - if (link) { + for (i = 0; i < priv->output_links->len; i++) { + NodeLink *link = &g_array_index (priv->output_links, NodeLink, i); + PinosLink *pl = link->link; SpaPortInputInfo iinfo[1]; - iinfo[0].port_id = link->input_port; + if (pl == NULL || pl->output_node->node != node || pl->output_port != oinfo[0].port_id) + continue; + + iinfo[0].port_id = pl->input_port; iinfo[0].buffer_id = oinfo[0].buffer_id; iinfo[0].flags = SPA_PORT_INPUT_FLAG_NONE; - if ((res = spa_node_port_push_input (link->input_node->node, 1, iinfo)) < 0) + if ((res = spa_node_port_push_input (pl->input_node->node, 1, iinfo)) < 0) g_warning ("node %p: error pushing buffer: %d, %d", this, res, iinfo[0].status); } break; } case SPA_NODE_EVENT_TYPE_REUSE_BUFFER: { - PinosLink *link; SpaResult res; SpaNodeEventReuseBuffer *rb = event->data; + guint i; - link = g_hash_table_lookup (priv->links, GUINT_TO_POINTER (rb->port_id)); - if (link) { - if ((res = spa_node_port_reuse_buffer (link->output_node->node, - link->output_port, + for (i = 0; i < priv->input_links->len; i++) { + NodeLink *link = &g_array_index (priv->input_links, NodeLink, i); + PinosLink *pl = link->link; + + if (pl == NULL || pl->input_node->node != node || pl->input_port != rb->port_id) + continue; + + if ((res = spa_node_port_reuse_buffer (pl->output_node->node, + pl->output_port, rb->buffer_id)) < 0) g_warning ("node %p: error reuse buffer: %d", node, res); } @@ -715,7 +731,8 @@ pinos_node_dispose (GObject * obj) node_unregister_object (node); - g_hash_table_unref (priv->links); + g_array_free (priv->input_links, TRUE); + g_array_free (priv->output_links, TRUE); G_OBJECT_CLASS (pinos_node_parent_class)->dispose (obj); } @@ -881,7 +898,8 @@ pinos_node_init (PinosNode * node) priv->state = PINOS_NODE_STATE_SUSPENDED; pinos_node1_set_state (priv->iface, PINOS_NODE_STATE_SUSPENDED); - priv->links = g_hash_table_new (g_direct_hash, g_direct_equal); + priv->input_links = g_array_new (FALSE, TRUE, sizeof (NodeLink)); + priv->output_links = g_array_new (FALSE, TRUE, sizeof (NodeLink)); } /** @@ -1042,63 +1060,102 @@ pinos_node_remove (PinosNode *node) g_signal_emit (node, signals[SIGNAL_REMOVE], 0, NULL); } -/** - * pinos_node_get_free_port_id: - * @node: a #PinosNode - * @direction: a #PinosDirection - * - * Find a new unused port id in @node with @direction - * - * Returns: the new port id of %SPA_INVALID_ID on error - */ -guint -pinos_node_get_free_port_id (PinosNode *node, - PinosDirection direction) +static uint32_t +get_free_node_port (PinosNode *node, + PinosDirection direction) { - PinosNodePrivate *priv; - guint i, free_port = 0, n_ports, max_ports; + PinosNodePrivate *priv = node->priv; + guint i, free_port, n_ports, max_ports; uint32_t *ports; - g_return_val_if_fail (PINOS_IS_NODE (node), -1); - priv = node->priv; - if (direction == PINOS_DIRECTION_INPUT) { max_ports = priv->max_input_ports; n_ports = priv->n_input_ports; ports = priv->input_port_ids; + free_port = 0; } else { max_ports = priv->max_output_ports; n_ports = priv->n_output_ports; ports = priv->output_port_ids; + free_port = priv->max_input_ports; } + if (max_ports == n_ports) + return SPA_ID_INVALID; g_debug ("node %p: direction %d max %u, n %u", node, direction, max_ports, n_ports); for (i = 0; i < n_ports; i++) { if (free_port < ports[i]) break; - - if (g_hash_table_lookup (priv->links, GUINT_TO_POINTER (free_port)) == NULL && free_port < max_ports) - return free_port; - free_port = ports[i] + 1; } if (free_port >= max_ports) - return -1; + return SPA_ID_INVALID; return free_port; } +/** + * pinos_node_get_free_port: + * @node: a #PinosNode + * @direction: a #PinosDirection + * + * Find a new unused port id in @node with @direction + * + * Returns: the new port id or %SPA_ID_INVALID on error + */ +guint +pinos_node_get_free_port (PinosNode *node, + PinosDirection direction) +{ + PinosNodePrivate *priv; + guint i, n_ports; + NodeLink *links; + + g_return_val_if_fail (PINOS_IS_NODE (node), SPA_ID_INVALID); + priv = node->priv; + + if (direction == PINOS_DIRECTION_INPUT) { + n_ports = priv->input_links->len; + links = (NodeLink *)priv->input_links->data; + } else { + n_ports = priv->output_links->len; + links = (NodeLink *)priv->output_links->data; + } + + for (i = 0; i < n_ports; i++) { + if (!links[i].link) + return i; + } + return n_ports; +} + static void do_remove_link (PinosLink *link, PinosNode *node) { - g_hash_table_remove (link->output_node->priv->links, GUINT_TO_POINTER (link->output_port)); - if (g_hash_table_size (link->output_node->priv->links) == 0) - pinos_node_report_idle (link->output_node); + guint i, n_links; + GArray *links; - g_hash_table_remove (link->input_node->priv->links, GUINT_TO_POINTER (link->input_port)); - if (g_hash_table_size (link->input_node->priv->links) == 0) - pinos_node_report_idle (link->input_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); + } + } } /** @@ -1121,61 +1178,74 @@ do_remove_link (PinosLink *link, PinosNode *node) */ PinosLink * pinos_node_link (PinosNode *output_node, - guint output_port, + guint output_id, PinosNode *input_node, - guint input_port, + guint input_id, GPtrArray *format_filter, PinosProperties *properties) { PinosNodePrivate *priv; - PinosLink *link; + NodeLink *olink, *ilink; + PinosLink *pl; g_return_val_if_fail (PINOS_IS_NODE (output_node), NULL); g_return_val_if_fail (PINOS_IS_NODE (input_node), NULL); - if (get_port_direction (output_node, output_port) != PINOS_DIRECTION_OUTPUT) { - PinosNode *tmp; - guint tmp_port; - - tmp = output_node; - output_node = input_node; - input_node = tmp; - - tmp_port = output_port; - output_port = input_port; - input_port = tmp_port; - } - priv = output_node->priv; - link = g_hash_table_lookup (priv->links, GUINT_TO_POINTER (output_port)); - if (link) { - link->input_node = input_node; - link->input_port = input_port; - g_object_ref (link); + g_debug ("node %p: link %u %p:%u", output_node, output_id, input_node, input_id); + + if (output_id >= priv->output_links->len) + g_array_set_size (priv->output_links, output_id + 1); + if (input_id >= input_node->priv->input_links->len) + g_array_set_size (input_node->priv->input_links, input_id + 1); + + olink = &g_array_index (priv->output_links, NodeLink, output_id); + ilink = &g_array_index (input_node->priv->input_links, NodeLink, input_id); + pl = olink->link; + + if (pl) { + /* FIXME */ + pl->input_node = input_node; + pl->input_id = input_id; + g_object_ref (pl); } else { + uint32_t input_port, output_port; + if (output_node->priv->clock) input_node->priv->clock = output_node->priv->clock; - link = g_object_new (PINOS_TYPE_LINK, - "daemon", priv->daemon, - "output-node", output_node, - "output-port", output_port, - "input-node", input_node, - "input-port", input_port, - "format-filter", format_filter, - "properties", properties, - NULL); + output_port = get_free_node_port (output_node, PINOS_DIRECTION_OUTPUT); + if (output_port == SPA_ID_INVALID) + output_port = output_node->priv->output_port_ids[0]; - g_signal_connect (link, + input_port = get_free_node_port (input_node, PINOS_DIRECTION_INPUT); + if (input_port == SPA_ID_INVALID) + input_port = input_node->priv->input_port_ids[0]; + + pl = g_object_new (PINOS_TYPE_LINK, + "daemon", priv->daemon, + "output-node", output_node, + "output-id", output_id, + "output-port", output_port, + "input-node", input_node, + "input-id", input_id, + "input-port", input_port, + "format-filter", format_filter, + "properties", properties, + NULL); + + g_signal_connect (pl, "remove", (GCallback) do_remove_link, output_node); - g_hash_table_insert (priv->links, GUINT_TO_POINTER (output_port), link); - g_hash_table_insert (input_node->priv->links, GUINT_TO_POINTER (input_port), link); + output_node->priv->n_used_output_links++; + input_node->priv->n_used_input_links++; + olink->link = pl; + ilink->link = pl; } - return link; + return pl; } /** @@ -1194,7 +1264,7 @@ pinos_node_get_links (PinosNode *node) g_return_val_if_fail (PINOS_IS_NODE (node), NULL); priv = node->priv; - return g_hash_table_get_values (priv->links); + return NULL; } static void diff --git a/pinos/server/node.h b/pinos/server/node.h index 3f19f5f60..51be8fdde 100644 --- a/pinos/server/node.h +++ b/pinos/server/node.h @@ -86,13 +86,13 @@ PinosDaemon * pinos_node_get_daemon (PinosNode *node); const gchar * pinos_node_get_sender (PinosNode *node); const gchar * pinos_node_get_object_path (PinosNode *node); -guint pinos_node_get_free_port_id (PinosNode *node, +guint pinos_node_get_free_port (PinosNode *node, PinosDirection direction); PinosLink * pinos_node_link (PinosNode *output_node, - guint output_port, + guint output_id, PinosNode *input_node, - guint input_port, + guint input_id, GPtrArray *format_filter, PinosProperties *properties); GList * pinos_node_get_links (PinosNode *node);