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);