From fe37e2bc1ba655e283457f93e82feb3350fa4966 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 28 Sep 2016 10:42:36 +0200 Subject: [PATCH] Make PinosPort struct Keep track of the ports, their links and the allocated buffers in a small struct managed by the node. --- pinos/server/daemon.c | 8 +- pinos/server/link.c | 274 +++++++++--------------- pinos/server/link.h | 16 +- pinos/server/node.c | 483 ++++++++++++++++++++++-------------------- 4 files changed, 364 insertions(+), 417 deletions(-) diff --git a/pinos/server/daemon.c b/pinos/server/daemon.c index b8a87d3c4..447d4977f 100644 --- a/pinos/server/daemon.c +++ b/pinos/server/daemon.c @@ -204,11 +204,11 @@ on_link_state_notify (GObject *obj, { g_warning ("daemon %p: link %p: state error: %s", daemon, link, error->message); - if (link->input_node) { - pinos_node_report_error (link->input_node, g_error_copy (error)); + if (link->input->node) { + pinos_node_report_error (link->input->node, g_error_copy (error)); } - if (link->output_node) { - pinos_node_report_error (link->output_node, g_error_copy (error)); + if (link->output->node) { + pinos_node_report_error (link->output->node, g_error_copy (error)); } break; } diff --git a/pinos/server/link.c b/pinos/server/link.c index 2622abea4..ec63a6271 100644 --- a/pinos/server/link.c +++ b/pinos/server/link.c @@ -50,10 +50,9 @@ struct _PinosLinkPrivate uint32_t async_busy; - SpaBuffer *in_buffers[MAX_BUFFERS]; - unsigned int n_in_buffers; - SpaBuffer *out_buffers[MAX_BUFFERS]; - unsigned int n_out_buffers; + gboolean allocated; + SpaBuffer *buffers[MAX_BUFFERS]; + unsigned int n_buffers; }; G_DEFINE_TYPE (PinosLink, pinos_link, G_TYPE_OBJECT); @@ -63,11 +62,7 @@ enum PROP_0, 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, @@ -100,28 +95,12 @@ pinos_link_get_property (GObject *_object, g_value_set_string (value, priv->object_path); break; - case PROP_OUTPUT_NODE: - 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; - - case PROP_INPUT_NODE: - g_value_set_object (value, this->input_node); - break; - - case PROP_INPUT_ID: - g_value_set_uint (value, this->input_id); + g_value_set_pointer (value, this->output); break; case PROP_INPUT_PORT: - g_value_set_uint (value, this->input_port); + g_value_set_pointer (value, this->input); break; case PROP_FORMAT_FILTER: @@ -160,28 +139,12 @@ pinos_link_set_property (GObject *_object, priv->object_path = g_value_dup_string (value); break; - case PROP_OUTPUT_NODE: - 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; - - case PROP_INPUT_NODE: - this->input_node = g_value_dup_object (value); - break; - - case PROP_INPUT_ID: - this->input_id = g_value_get_uint (value); + this->output = g_value_get_pointer (value); break; case PROP_INPUT_PORT: - this->input_port = g_value_get_uint (value); + this->input = g_value_get_pointer (value); break; case PROP_FORMAT_FILTER: @@ -271,8 +234,8 @@ do_negotiate (PinosLink *this, SpaNodeState in_state, SpaNodeState out_state) if (in_state == SPA_NODE_STATE_CONFIGURE && out_state == SPA_NODE_STATE_CONFIGURE) { g_debug ("link %p: doing negotiate format", this); again: - if ((res = spa_node_port_enum_formats (this->input_node->node, - this->input_port, + if ((res = spa_node_port_enum_formats (this->input->node->node, + this->input->port, &filter, NULL, &istate)) < 0) { @@ -287,8 +250,8 @@ again: g_debug ("Try filter:"); spa_debug_format (filter); - if ((res = spa_node_port_enum_formats (this->output_node->node, - this->output_port, + if ((res = spa_node_port_enum_formats (this->output->node->node, + this->output->port, &format, filter, &ostate)) < 0) { @@ -307,8 +270,8 @@ again: spa_format_fixate (format); } else if (in_state == SPA_NODE_STATE_CONFIGURE && out_state > SPA_NODE_STATE_CONFIGURE) { /* only input needs format */ - if ((res = spa_node_port_get_format (this->output_node->node, - this->output_port, + if ((res = spa_node_port_get_format (this->output->node->node, + this->output->port, (const SpaFormat **)&format)) < 0) { g_set_error (&error, PINOS_ERROR, @@ -318,8 +281,8 @@ again: } } else if (out_state == SPA_NODE_STATE_CONFIGURE && in_state > SPA_NODE_STATE_CONFIGURE) { /* only output needs format */ - if ((res = spa_node_port_get_format (this->input_node->node, - this->input_port, + if ((res = spa_node_port_get_format (this->input->node->node, + this->input->port, (const SpaFormat **)&format)) < 0) { g_set_error (&error, PINOS_ERROR, @@ -335,8 +298,8 @@ again: if (out_state == SPA_NODE_STATE_CONFIGURE) { g_debug ("link %p: doing set format on output", this); - if ((res = spa_node_port_set_format (this->output_node->node, - this->output_port, + if ((res = spa_node_port_set_format (this->output->node->node, + this->output->port, SPA_PORT_FORMAT_FLAG_NEAREST, format)) < 0) { g_set_error (&error, @@ -347,8 +310,8 @@ again: } } else if (in_state == SPA_NODE_STATE_CONFIGURE) { g_debug ("link %p: doing set format on input", this); - if ((res = spa_node_port_set_format (this->input_node->node, - this->input_port, + if ((res = spa_node_port_set_format (this->input->node->node, + this->input->port, SPA_PORT_FORMAT_FLAG_NEAREST, format)) < 0) { g_set_error (&error, @@ -395,16 +358,16 @@ do_allocation (PinosLink *this, SpaNodeState in_state, SpaNodeState out_state) pinos_link_update_state (this, PINOS_LINK_STATE_ALLOCATING); - g_debug ("link %p: doing alloc buffers %p %p", this, this->output_node, this->input_node); + g_debug ("link %p: doing alloc buffers %p %p", this, this->output->node, this->input->node); /* find out what's possible */ - if ((res = spa_node_port_get_info (this->output_node->node, this->output_port, &oinfo)) < 0) { + if ((res = spa_node_port_get_info (this->output->node->node, this->output->port, &oinfo)) < 0) { g_set_error (&error, PINOS_ERROR, PINOS_ERROR_BUFFER_ALLOCATION, "error get output port info: %d", res); goto error; } - if ((res = spa_node_port_get_info (this->input_node->node, this->input_port, &iinfo)) < 0) { + if ((res = spa_node_port_get_info (this->input->node->node, this->input->port, &iinfo)) < 0) { g_set_error (&error, PINOS_ERROR, PINOS_ERROR_BUFFER_ALLOCATION, @@ -423,8 +386,8 @@ do_allocation (PinosLink *this, SpaNodeState in_state, SpaNodeState out_state) max_buffers = out_alloc->max_buffers == 0 ? max_buffers : SPA_MIN (out_alloc->max_buffers, max_buffers); if (out_flags & SPA_PORT_INFO_FLAG_LIVE) { - this->output_node->live = true; - this->input_node->live = true; + this->output->node->live = true; + this->input->node->live = true; } if (in_state == SPA_NODE_STATE_READY && out_state == SPA_NODE_STATE_READY) { @@ -438,22 +401,27 @@ do_allocation (PinosLink *this, SpaNodeState in_state, SpaNodeState out_state) in_flags = SPA_PORT_INFO_FLAG_CAN_ALLOC_BUFFERS; } else if ((out_flags & SPA_PORT_INFO_FLAG_CAN_USE_BUFFERS) && (in_flags & SPA_PORT_INFO_FLAG_CAN_USE_BUFFERS)) { - priv->n_in_buffers = max_buffers; + priv->n_buffers = max_buffers; out_flags = SPA_PORT_INFO_FLAG_CAN_USE_BUFFERS; in_flags = SPA_PORT_INFO_FLAG_CAN_USE_BUFFERS; if ((res = spa_buffer_alloc (oinfo->params, oinfo->n_params, - priv->in_buffers, - &priv->n_in_buffers)) < 0) { + priv->buffers, + &priv->n_buffers)) < 0) { g_set_error (&error, PINOS_ERROR, PINOS_ERROR_BUFFER_ALLOCATION, "error buffer alloc: %d", res); goto error; } - memcpy (priv->out_buffers, priv->in_buffers, priv->n_in_buffers * sizeof (SpaBuffer*)); - priv->n_out_buffers = priv->n_in_buffers; - g_debug ("allocated out_buffers %p, in_buffers %p", priv->out_buffers, priv->in_buffers); + priv->allocated = TRUE; + memcpy (this->output->buffers, priv->buffers, priv->n_buffers * sizeof (SpaBuffer*)); + memcpy (this->input->buffers, priv->buffers, priv->n_buffers * sizeof (SpaBuffer*)); + this->output->n_buffers = priv->n_buffers; + this->input->n_buffers = priv->n_buffers; + this->output->allocated = FALSE; + this->input->allocated = FALSE; + g_debug ("allocated %d buffers %p", priv->n_buffers, priv->buffers); } else if ((out_flags & SPA_PORT_INFO_FLAG_CAN_ALLOC_BUFFERS) && (in_flags & SPA_PORT_INFO_FLAG_CAN_ALLOC_BUFFERS)) { out_flags = SPA_PORT_INFO_FLAG_CAN_ALLOC_BUFFERS; @@ -478,59 +446,65 @@ do_allocation (PinosLink *this, SpaNodeState in_state, SpaNodeState out_state) spa_debug_port_info (oinfo); spa_debug_port_info (iinfo); - if (in_flags & SPA_PORT_INFO_FLAG_CAN_ALLOC_BUFFERS && priv->n_in_buffers == 0) { - priv->n_in_buffers = max_buffers; - if ((res = spa_node_port_alloc_buffers (this->input_node->node, this->input_port, + if (in_flags & SPA_PORT_INFO_FLAG_CAN_ALLOC_BUFFERS && this->input->n_buffers == 0) { + this->input->n_buffers = max_buffers; + 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) { + this->input->buffers, &this->input->n_buffers)) < 0) { g_set_error (&error, PINOS_ERROR, PINOS_ERROR_BUFFER_ALLOCATION, "error alloc input buffers: %d", res); goto error; } - g_debug ("allocated in_buffers %p from input port", priv->in_buffers); + this->input->allocated = TRUE; + g_debug ("allocated %d buffers %p from input port", this->input->n_buffers, this->input->buffers); } - else if (out_flags & SPA_PORT_INFO_FLAG_CAN_ALLOC_BUFFERS && priv->n_out_buffers == 0) { - priv->n_out_buffers = max_buffers; - if ((res = spa_node_port_alloc_buffers (this->output_node->node, this->output_port, + else if (out_flags & SPA_PORT_INFO_FLAG_CAN_ALLOC_BUFFERS && this->output->n_buffers == 0) { + this->output->n_buffers = max_buffers; + 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) { + this->output->buffers, &this->output->n_buffers)) < 0) { g_set_error (&error, PINOS_ERROR, PINOS_ERROR_BUFFER_ALLOCATION, "error alloc output buffers: %d", res); goto error; } - g_debug ("allocated out_buffers %p from output port", priv->out_buffers); + this->output->allocated = TRUE; + g_debug ("allocated %d buffers %p from output port", this->output->n_buffers, this->output->buffers); } if (in_flags & SPA_PORT_INFO_FLAG_CAN_USE_BUFFERS) { - g_debug ("using out_buffers %p on input port", priv->out_buffers); - if ((res = spa_node_port_use_buffers (this->input_node->node, this->input_port, - priv->out_buffers, priv->n_out_buffers)) < 0) { + g_debug ("using output buffers %p on input port", this->output->buffers); + if ((res = spa_node_port_use_buffers (this->input->node->node, this->input->port, + this->output->buffers, this->output->n_buffers)) < 0) { g_set_error (&error, PINOS_ERROR, PINOS_ERROR_BUFFER_ALLOCATION, "error use input buffers: %d", res); goto error; } + this->input->allocated = FALSE; } else if (out_flags & SPA_PORT_INFO_FLAG_CAN_USE_BUFFERS) { - g_debug ("using in_buffers %p on output port", priv->in_buffers); - if ((res = spa_node_port_use_buffers (this->output_node->node, this->output_port, - priv->in_buffers, priv->n_in_buffers)) < 0) { + g_debug ("using %d in_buffers %p on output port", this->input->n_buffers, this->input->buffers); + if ((res = spa_node_port_use_buffers (this->output->node->node, this->output->port, + this->input->buffers, this->input->n_buffers)) < 0) { g_set_error (&error, PINOS_ERROR, PINOS_ERROR_BUFFER_ALLOCATION, "error use output buffers: %d", res); goto error; } + this->output->allocated = FALSE; } else { g_set_error (&error, PINOS_ERROR, PINOS_ERROR_BUFFER_ALLOCATION, "no common buffer alloc found"); goto error; + this->input->allocated = FALSE; + this->output->allocated = FALSE; } return res; @@ -555,14 +529,14 @@ do_start (PinosLink *this, SpaNodeState in_state, SpaNodeState out_state) pinos_link_update_state (this, PINOS_LINK_STATE_PAUSED); if (in_state == SPA_NODE_STATE_PAUSED) { - pinos_node_set_state (this->input_node, PINOS_NODE_STATE_RUNNING); - if (pinos_node_get_state (this->input_node) != PINOS_NODE_STATE_RUNNING) + pinos_node_set_state (this->input->node, PINOS_NODE_STATE_RUNNING); + if (pinos_node_get_state (this->input->node) != PINOS_NODE_STATE_RUNNING) res = SPA_RESULT_RETURN_ASYNC (0); } if (out_state == SPA_NODE_STATE_PAUSED) { - pinos_node_set_state (this->output_node, PINOS_NODE_STATE_RUNNING); - if (pinos_node_get_state (this->output_node) != PINOS_NODE_STATE_RUNNING) + pinos_node_set_state (this->output->node, PINOS_NODE_STATE_RUNNING); + if (pinos_node_get_state (this->output->node) != PINOS_NODE_STATE_RUNNING) res = SPA_RESULT_RETURN_ASYNC (0); } } @@ -580,8 +554,8 @@ again: if (priv->async_busy != SPA_ID_INVALID) return SPA_RESULT_OK; - in_state = this->input_node->node->state; - out_state = this->output_node->node->state; + in_state = this->input->node->node->state; + out_state = this->output->node->node->state; g_debug ("link %p: input state %d, output state %d", this, in_state, out_state); @@ -594,9 +568,9 @@ again: if ((res = do_start (this, in_state, out_state)) != SPA_RESULT_OK) goto exit; - if (this->input_node->node->state != in_state) + if (this->input->node->node->state != in_state) goto again; - if (this->output_node->node->state != out_state) + if (this->output->node->node->state != out_state) goto again; return SPA_RESULT_OK; @@ -636,17 +610,13 @@ on_property_notify (GObject *obj, PinosLink *this = user_data; PinosLinkPrivate *priv = this->priv; - if (pspec == NULL || strcmp (g_param_spec_get_name (pspec), "output-node") == 0) { - pinos_link1_set_output_node (priv->iface, pinos_node_get_object_path (this->output_node)); - } if (pspec == NULL || strcmp (g_param_spec_get_name (pspec), "output-port") == 0) { - pinos_link1_set_output_port (priv->iface, this->output_port); - } - if (pspec == NULL || strcmp (g_param_spec_get_name (pspec), "input-node") == 0) { - pinos_link1_set_input_node (priv->iface, pinos_node_get_object_path (this->input_node)); + pinos_link1_set_output_node (priv->iface, pinos_node_get_object_path (this->output->node)); + pinos_link1_set_output_port (priv->iface, this->output->port); } if (pspec == NULL || strcmp (g_param_spec_get_name (pspec), "input-port") == 0) { - pinos_link1_set_input_port (priv->iface, this->input_port); + pinos_link1_set_input_node (priv->iface, pinos_node_get_object_path (this->input->node)); + pinos_link1_set_input_port (priv->iface, this->input->port); } } @@ -654,10 +624,10 @@ 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); + if (node == this->input->node) + this->input = NULL; else - g_clear_object (&this->output_node); + this->output = NULL; pinos_link_update_state (this, PINOS_LINK_STATE_UNLINKED); } @@ -667,20 +637,20 @@ 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, "remove", (GCallback) on_node_remove, this); + g_signal_connect (this->output->node, "remove", (GCallback) on_node_remove, this); - g_signal_connect (this->input_node, "async-complete", (GCallback) on_async_complete_notify, this); - g_signal_connect (this->output_node, "async-complete", (GCallback) on_async_complete_notify, this); + g_signal_connect (this->input->node, "async-complete", (GCallback) on_async_complete_notify, this); + g_signal_connect (this->output->node, "async-complete", (GCallback) on_async_complete_notify, this); g_signal_connect (this, "notify", (GCallback) on_property_notify, this); G_OBJECT_CLASS (pinos_link_parent_class)->constructed (object); on_property_notify (G_OBJECT (this), NULL, this); - 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); + g_debug ("link %p: constructed %p:%d -> %p:%d", this, + this->output->node, this->output->port, + this->input->node, this->input->port); link_register_object (this); } @@ -691,15 +661,15 @@ pinos_link_dispose (GObject * object) g_debug ("link %p: dispose", 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); + 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); - g_clear_object (&this->input_node); - g_clear_object (&this->output_node); + this->input = NULL; + this->output = NULL; link_unregister_object (this); @@ -744,73 +714,23 @@ pinos_link_class_init (PinosLinkClass * klass) G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); - g_object_class_install_property (gobject_class, - PROP_OUTPUT_NODE, - g_param_spec_object ("output-node", - "Output Node", - "The output node", - PINOS_TYPE_NODE, - G_PARAM_READWRITE | - 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", - "Output Port", - "The output port", - 0, - G_MAXUINT, - -1, - G_PARAM_READWRITE | - G_PARAM_CONSTRUCT | - G_PARAM_STATIC_STRINGS)); - - g_object_class_install_property (gobject_class, - PROP_INPUT_NODE, - g_param_spec_object ("input-node", - "Input Node", - "The input node", - PINOS_TYPE_NODE, - G_PARAM_READWRITE | - 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_param_spec_pointer ("output-port", + "Output Port", + "The output port", + 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", - "Input Port", - "The input port", - 0, - G_MAXUINT, - -1, - G_PARAM_READWRITE | - G_PARAM_CONSTRUCT | - G_PARAM_STATIC_STRINGS)); + g_param_spec_pointer ("input-port", + "Input Port", + "The input port", + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT | + G_PARAM_STATIC_STRINGS)); g_object_class_install_property (gobject_class, PROP_FORMAT_FILTER, diff --git a/pinos/server/link.h b/pinos/server/link.h index 9ed6a8f10..28d811123 100644 --- a/pinos/server/link.h +++ b/pinos/server/link.h @@ -40,6 +40,14 @@ typedef struct _PinosLinkPrivate PinosLinkPrivate; #define PINOS_LINK_CAST(obj) ((PinosLink*)(obj)) #define PINOS_LINK_CLASS_CAST(klass)((PinosLinkClass*)(klass)) +typedef struct { + PinosNode *node; + uint32_t port; + gboolean allocated; + SpaBuffer *buffers[16]; + guint n_buffers; +} PinosPort; + /** * PinosLink: * @@ -48,12 +56,8 @@ typedef struct _PinosLinkPrivate PinosLinkPrivate; struct _PinosLink { GObject object; - PinosNode *output_node; - guint output_id; - uint32_t output_port; - PinosNode *input_node; - guint input_id; - uint32_t input_port; + PinosPort *output; + PinosPort *input; uint32_t queue[16]; SpaRingbuffer ringbuffer; diff --git a/pinos/server/node.c b/pinos/server/node.c index 7d4dcd03a..64dda0c1b 100644 --- a/pinos/server/node.c +++ b/pinos/server/node.c @@ -34,8 +34,40 @@ (G_TYPE_INSTANCE_GET_PRIVATE ((node), PINOS_TYPE_NODE, PinosNodePrivate)) typedef struct { - PinosLink *link; -} NodeLink; + PinosPort port; + GPtrArray *links; +} NodePort; + +static NodePort * +new_node_port (PinosNode *node, uint32_t port) +{ + NodePort *np; + np = g_slice_new0 (NodePort); + np->port.node = node; + np->port.port = port; + np->links = g_ptr_array_new (); + return np; +} + +static void +free_node_port (NodePort *np) +{ + g_ptr_array_free (np->links, TRUE); + g_slice_free (NodePort, np); +} + +static NodePort * +find_node_port (GList *ports, PinosNode *node, uint32_t port) +{ + GList *walk; + for (walk = ports; walk; walk = g_list_next (walk)) { + NodePort *np = walk->data; + g_debug ("%p %d <-> %p %d", np->port.node, np->port.port, node, port); + if (np->port.node == node && np->port.port == port) + return np; + } + return NULL; +} struct _PinosNodePrivate { @@ -51,8 +83,10 @@ struct _PinosNodePrivate unsigned int max_output_ports; unsigned int n_input_ports; unsigned int n_output_ports; - uint32_t *input_port_ids; - uint32_t *output_port_ids; + GList *input_ports; + GList *output_ports; + guint n_used_output_links; + guint n_used_input_links; PinosNodeState state; GError *error; @@ -62,11 +96,6 @@ struct _PinosNodePrivate PinosRTLoop *loop; - GArray *output_links; - guint n_used_output_links; - GArray *input_links; - guint n_used_input_links; - SpaNodeEventAsyncComplete ac; uint32_t pending_state_seq; PinosNodeState pending_state; @@ -104,80 +133,108 @@ static void update_port_ids (PinosNode *node, gboolean create) { PinosNodePrivate *priv = node->priv; - uint32_t *in_ports, *out_ports; - guint n_input_ports, n_output_ports; - guint i, j; + uint32_t *input_port_ids, *output_port_ids; + guint n_input_ports, n_output_ports, max_input_ports, max_output_ports; + guint i; + GList *ports; if (node->node == NULL) return; - n_input_ports = priv->n_input_ports; - n_output_ports = priv->n_output_ports; - - in_ports = g_alloca (sizeof (uint32_t) * n_input_ports); - out_ports = g_alloca (sizeof (uint32_t) * n_output_ports); - memcpy (in_ports, priv->input_port_ids, sizeof (uint32_t) * n_input_ports); - memcpy (out_ports, priv->output_port_ids, sizeof (uint32_t) * n_output_ports); - spa_node_get_n_ports (node->node, - &priv->n_input_ports, - &priv->max_input_ports, - &priv->n_output_ports, - &priv->max_output_ports); + &n_input_ports, + &max_input_ports, + &n_output_ports, + &max_output_ports); + + input_port_ids = g_alloca (sizeof (uint32_t) * n_input_ports); + output_port_ids = g_alloca (sizeof (uint32_t) * n_output_ports); + + spa_node_get_port_ids (node->node, + max_input_ports, + input_port_ids, + max_output_ports, + output_port_ids); + + g_debug ("node %p: update_port ids %u/%u, %u/%u", node, + n_input_ports, max_input_ports, n_output_ports, max_output_ports); + + i = 0; + ports = priv->input_ports; + while (true) { + NodePort *p = (ports ? ports->data : NULL); + + if (p && i < n_input_ports && p->port.port == input_port_ids[i]) { + i++; + ports = g_list_next (ports); + } else if ((p && i < n_input_ports && input_port_ids[i] < p->port.port) || i < n_input_ports) { + NodePort *np; + g_debug ("node %p: input port added %d", node, input_port_ids[i]); + + np = new_node_port (node, input_port_ids[i]); + priv->input_ports = g_list_insert_before (priv->input_ports, ports, np); + + if (!priv->async_init) + g_signal_emit (node, signals[SIGNAL_PORT_ADDED], 0, PINOS_DIRECTION_INPUT); + i++; + } else if (p) { + GList *next; + g_debug ("node %p: input port removed %d", node, p->port.port); + + next = g_list_next (ports); + priv->input_ports = g_list_delete_link (priv->input_ports, ports); + ports = next; + + free_node_port (p); + + if (!priv->async_init) + g_signal_emit (node, signals[SIGNAL_PORT_REMOVED], 0, PINOS_DIRECTION_INPUT); + } else + break; + } + + i = 0; + ports = priv->output_ports; + while (true) { + NodePort *p = (ports ? ports->data : NULL); + + if (p && i < n_output_ports && p->port.port == output_port_ids[i]) { + i++; + ports = g_list_next (ports); + } else if ((p && i < n_output_ports && output_port_ids[i] < p->port.port) || i < n_output_ports) { + NodePort *np; + g_debug ("node %p: output port added %d", node, output_port_ids[i]); + + np = new_node_port (node, output_port_ids[i]); + priv->output_ports = g_list_insert_before (priv->output_ports, ports, np); + + if (!priv->async_init) + g_signal_emit (node, signals[SIGNAL_PORT_ADDED], 0, PINOS_DIRECTION_INPUT); + i++; + } else if (p) { + GList *next; + g_debug ("node %p: output port removed %d", node, p->port.port); + + next = g_list_next (ports); + priv->output_ports = g_list_delete_link (priv->output_ports, ports); + ports = next; + + free_node_port (p); + + if (!priv->async_init) + g_signal_emit (node, signals[SIGNAL_PORT_REMOVED], 0, PINOS_DIRECTION_INPUT); + } else + break; + } + + priv->max_input_ports = max_input_ports; + priv->max_output_ports = max_output_ports; + priv->n_input_ports = n_input_ports; + priv->n_output_ports = n_output_ports; node->have_inputs = priv->n_input_ports > 0; node->have_outputs = priv->n_output_ports > 0; - g_debug ("node %p: update_port ids %u/%u, %u/%u", node, - priv->n_input_ports, priv->max_input_ports, priv->n_output_ports, priv->max_output_ports); - - priv->input_port_ids = g_realloc_n (priv->input_port_ids, priv->max_input_ports, sizeof (uint32_t)); - priv->output_port_ids = g_realloc_n (priv->output_port_ids, priv->max_output_ports, sizeof (uint32_t)); - - spa_node_get_port_ids (node->node, - priv->max_input_ports, - priv->input_port_ids, - priv->max_output_ports, - priv->output_port_ids); - - i = j = 0; - while (true) { - if (i < priv->n_input_ports && j < n_input_ports && priv->input_port_ids[i] == in_ports[j]) { - i++; - j++; - } else if ((i < priv->n_input_ports && j < n_input_ports && - priv->input_port_ids[i] < in_ports[j]) || i < priv->n_input_ports) { - g_debug ("node %p: input port added %d", node, priv->input_port_ids[i]); - if (!priv->async_init) - g_signal_emit (node, signals[SIGNAL_PORT_ADDED], 0, PINOS_DIRECTION_INPUT); - i++; - } else if (j < n_input_ports) { - g_debug ("node %p: input port removed %d", node, in_ports[j]); - if (!priv->async_init) - g_signal_emit (node, signals[SIGNAL_PORT_REMOVED], 0, PINOS_DIRECTION_INPUT); - j++; - } else - break; - } - i = j = 0; - while (true) { - if (i < priv->n_output_ports && j < n_output_ports && priv->output_port_ids[i] == out_ports[j]) { - i++; - j++; - } else if ((i < priv->n_output_ports && j < n_output_ports && - priv->output_port_ids[i] < out_ports[j]) || i < priv->n_output_ports) { - g_debug ("node %p: output port added %d", node, priv->output_port_ids[i]); - if (!priv->async_init) - g_signal_emit (node, signals[SIGNAL_PORT_ADDED], 0, PINOS_DIRECTION_OUTPUT); - i++; - } else if (j < n_output_ports) { - g_debug ("node %p: output port removed %d", node, out_ports[j]); - if (!priv->async_init) - g_signal_emit (node, signals[SIGNAL_PORT_REMOVED], 0, PINOS_DIRECTION_OUTPUT); - j++; - } else - break; - } } static SpaResult @@ -219,17 +276,23 @@ suspend_node (PinosNode *this) { PinosNodePrivate *priv = this->priv; SpaResult res = SPA_RESULT_OK; - guint i; + GList *walk; g_debug ("node %p: suspend node", this); - for (i = 0; i < priv->n_input_ports; i++) { - if ((res = spa_node_port_set_format (this->node, priv->input_port_ids[i], 0, NULL)) < 0) + for (walk = priv->input_ports; walk; walk = g_list_next (walk)) { + NodePort *p = walk->data; + if ((res = spa_node_port_set_format (this->node, p->port.port, 0, NULL)) < 0) g_warning ("error unset format output: %d", res); + p->port.allocated = FALSE; + p->port.n_buffers = 0; } - for (i = 0; i < priv->n_output_ports; i++) { - if ((res = spa_node_port_set_format (this->node, priv->output_port_ids[i], 0, NULL)) < 0) + for (walk = priv->output_ports; walk; walk = g_list_next (walk)) { + NodePort *p = walk->data; + if ((res = spa_node_port_set_format (this->node, p->port.port, 0, NULL)) < 0) g_warning ("error unset format output: %d", res); + p->port.allocated = FALSE; + p->port.n_buffers = 0; } return res; } @@ -327,11 +390,11 @@ do_read_link (PinosNode *this, PinosLink *link) link->in_ready--; - iinfo[0].port_id = link->input_port; + iinfo[0].port_id = link->input->port; iinfo[0].buffer_id = link->queue[areas[0].offset]; 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 (link->input->node->node, 1, iinfo)) < 0) g_warning ("node %p: error pushing buffer: %d, %d", this, res, iinfo[0].status); else pushed = TRUE; @@ -405,18 +468,18 @@ on_node_event (SpaNode *node, SpaNodeEvent *event, void *user_data) } case SPA_NODE_EVENT_TYPE_NEED_INPUT: { - guint i; SpaNodeEventNeedInput *ni = event->data; + NodePort *p; + guint i; - for (i = 0; i < priv->input_links->len; i++) { - NodeLink *link = &g_array_index (priv->input_links, NodeLink, i); - PinosLink *pl = link->link; + if (!(p = find_node_port (priv->input_ports, this, ni->port_id))) + break; - if (pl == NULL || pl->input_node->node != node || pl->input_port != ni->port_id) - continue; + for (i = 0; i < p->links->len; i++) { + PinosLink *link = g_ptr_array_index (p->links, i); - pl->in_ready++; - do_read_link (this, pl); + link->in_ready++; + do_read_link (this, link); } break; } @@ -425,8 +488,9 @@ on_node_event (SpaNode *node, SpaNodeEvent *event, void *user_data) SpaNodeEventHaveOutput *ho = event->data; SpaPortOutputInfo oinfo[1] = { 0, }; SpaResult res; - guint i; gboolean pushed = FALSE; + NodePort *p; + guint i; oinfo[0].port_id = ho->port_id; @@ -435,20 +499,19 @@ on_node_event (SpaNode *node, SpaNodeEvent *event, void *user_data) break; } - for (i = 0; i < priv->output_links->len; i++) { - NodeLink *link = &g_array_index (priv->output_links, NodeLink, i); - PinosLink *pl = link->link; + if (!(p = find_node_port (priv->output_ports, this, oinfo[0].port_id))) + break; + + for (i = 0; i < p->links->len; i++) { + PinosLink *link = g_ptr_array_index (p->links, i); SpaRingbufferArea areas[2]; - if (pl == NULL || pl->output_node->node != node || pl->output_port != oinfo[0].port_id) - continue; - - spa_ringbuffer_get_write_areas (&pl->ringbuffer, areas); + spa_ringbuffer_get_write_areas (&link->ringbuffer, areas); if (areas[0].len > 0) { - pl->queue[areas[0].offset] = oinfo[0].buffer_id; - spa_ringbuffer_write_advance (&pl->ringbuffer, 1); + link->queue[areas[0].offset] = oinfo[0].buffer_id; + spa_ringbuffer_write_advance (&link->ringbuffer, 1); - pushed = do_read_link (this, pl); + pushed = do_read_link (this, link); } } if (!pushed) { @@ -462,17 +525,17 @@ on_node_event (SpaNode *node, SpaNodeEvent *event, void *user_data) { SpaResult res; SpaNodeEventReuseBuffer *rb = event->data; + NodePort *p; guint i; - for (i = 0; i < priv->input_links->len; i++) { - NodeLink *link = &g_array_index (priv->input_links, NodeLink, i); - PinosLink *pl = link->link; + if (!(p = find_node_port (priv->input_ports, this, rb->port_id))) + break; - if (pl == NULL || pl->input_node->node != node || pl->input_port != rb->port_id) - continue; + for (i = 0; i < p->links->len; i++) { + PinosLink *link = g_ptr_array_index (p->links, i); - if ((res = spa_node_port_reuse_buffer (pl->output_node->node, - pl->output_port, + if ((res = spa_node_port_reuse_buffer (link->output->node->node, + link->output->port, rb->buffer_id)) < 0) g_warning ("node %p: error reuse buffer: %d", node, res); } @@ -702,16 +765,13 @@ static void pinos_node_dispose (GObject * obj) { PinosNode *node = PINOS_NODE (obj); - PinosNodePrivate *priv = node->priv; + //PinosNodePrivate *priv = node->priv; g_debug ("node %p: dispose", node); pinos_node_set_state (node, PINOS_NODE_STATE_SUSPENDED); node_unregister_object (node); - g_array_free (priv->input_links, TRUE); - g_array_free (priv->output_links, TRUE); - G_OBJECT_CLASS (pinos_node_parent_class)->dispose (obj); } @@ -729,8 +789,6 @@ pinos_node_finalize (GObject * obj) g_clear_error (&priv->error); if (priv->properties) pinos_properties_free (priv->properties); - g_free (priv->input_port_ids); - g_free (priv->output_port_ids); G_OBJECT_CLASS (pinos_node_parent_class)->finalize (obj); } @@ -885,9 +943,6 @@ pinos_node_init (PinosNode * node) priv->state = PINOS_NODE_STATE_CREATING; priv->pending_state_seq = SPA_ID_INVALID; pinos_node1_set_state (priv->iface, priv->state); - - priv->input_links = g_array_new (FALSE, TRUE, sizeof (NodeLink)); - priv->output_links = g_array_new (FALSE, TRUE, sizeof (NodeLink)); } /** @@ -1048,41 +1103,6 @@ pinos_node_remove (PinosNode *node) g_signal_emit (node, signals[SIGNAL_REMOVE], 0, NULL); } -static uint32_t -get_free_node_port (PinosNode *node, - PinosDirection direction) -{ - PinosNodePrivate *priv = node->priv; - guint i, free_port, n_ports, max_ports; - uint32_t *ports; - - 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; - free_port = ports[i] + 1; - } - if (free_port >= max_ports) - return SPA_ID_INVALID; - - return free_port; -} - /** * pinos_node_get_free_port: * @node: a #PinosNode @@ -1097,65 +1117,79 @@ pinos_node_get_free_port (PinosNode *node, PinosDirection direction) { PinosNodePrivate *priv; - guint i, n_ports; - NodeLink *links; + guint free_port, n_ports, max_ports; + GList *ports, *walk; 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; + max_ports = priv->max_input_ports; + n_ports = priv->n_input_ports; + ports = priv->input_ports; + free_port = 0; } else { - n_ports = priv->output_links->len; - links = (NodeLink *)priv->output_links->data; + max_ports = priv->max_output_ports; + n_ports = priv->n_output_ports; + ports = priv->output_ports; + free_port = priv->max_input_ports; } - for (i = 0; i < n_ports; i++) { - if (!links[i].link) - return i; + g_debug ("node %p: direction %d max %u, n %u", node, direction, max_ports, n_ports); + + for (walk = ports; walk; walk = g_list_next (walk)) { + PinosPort *p = walk->data; + + if (free_port < p->port) + break; + + free_port = p->port + 1; } - return n_ports; + if (free_port >= max_ports && ports) { + PinosPort *p = ports->data; + + free_port = p->port; + } else + return SPA_ID_INVALID; + + return free_port; + } static void do_remove_link (PinosLink *link, PinosNode *node) { - guint i, n_links; - GArray *links; + NodePort *p; + PinosNode *n; - 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); - } - } + if (link->output) { + n = link->output->node; + if ((p = find_node_port (n->priv->output_ports, n, link->output->port))) + if (g_ptr_array_remove_fast (p->links, link)) + n->priv->n_used_output_links--; + + if (n->priv->n_used_output_links == 0 && + n->priv->n_used_input_links == 0) + pinos_node_report_idle (n); } - 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); - } - } + if (link->input->node) { + n = link->input->node; + if ((p = find_node_port (n->priv->input_ports, n, link->input->port))) + if (g_ptr_array_remove_fast (p->links, link)) + n->priv->n_used_input_links--; + + if (n->priv->n_used_output_links == 0 && + n->priv->n_used_input_links == 0) + pinos_node_report_idle (n); } } /** * pinos_node_link: * @output_node: a #PinosNode - * @output_id: an output link id + * @output_port: an output port * @input_node: a #PinosNode - * @input_id: an input link id + * @input_port: an input port * @format_filter: a format filter * @properties: extra properties * @error: an error or %NULL @@ -1171,85 +1205,74 @@ do_remove_link (PinosLink *link, PinosNode *node) */ PinosLink * pinos_node_link (PinosNode *output_node, - guint output_id, + guint output_port, PinosNode *input_node, - guint input_id, + guint input_port, GPtrArray *format_filter, PinosProperties *properties, GError **error) { PinosNodePrivate *priv; - NodeLink *olink, *ilink; - PinosLink *pl; + NodePort *onp, *inp; + PinosLink *link = NULL; + guint i; g_return_val_if_fail (PINOS_IS_NODE (output_node), NULL); g_return_val_if_fail (PINOS_IS_NODE (input_node), NULL); priv = output_node->priv; - g_debug ("node %p: link %u %p:%u", output_node, output_id, input_node, input_id); + g_debug ("node %p: link %u %p:%u", output_node, output_port, input_node, input_port); if (output_node == input_node) goto same_node; - 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; - - output_port = get_free_node_port (output_node, PINOS_DIRECTION_OUTPUT); - if (output_port == SPA_ID_INVALID && output_node->priv->n_output_ports > 0) - output_port = output_node->priv->output_port_ids[0]; - else + onp = find_node_port (priv->output_ports, output_node, output_port); + if (onp == NULL) goto no_output_ports; - input_port = get_free_node_port (input_node, PINOS_DIRECTION_INPUT); - g_debug ("node %p: port %u, %u", input_node, input_port, input_node->priv->n_input_ports); - if (input_port == SPA_ID_INVALID && input_node->priv->n_input_ports > 0) - input_port = input_node->priv->input_port_ids[0]; - else + for (i = 0; i < onp->links->len; i++) { + PinosLink *pl = g_ptr_array_index (onp->links, i); + if (pl->input->node == input_node && pl->input->port == input_port) { + link = pl; + break; + } + } + inp = find_node_port (input_node->priv->input_ports, input_node, input_port); + if (inp == NULL) goto no_input_ports; + if (link) { + /* FIXME */ + link->input->node = input_node; + link->input->port = input_port; + g_object_ref (link); + } else { input_node->live = output_node->live; if (output_node->clock) input_node->clock = output_node->clock; - g_debug ("node %p: clock %p", output_node, output_node->clock); - pl = g_object_new (PINOS_TYPE_LINK, + + link = 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, + "output-port", &onp->port, + "input-port", &inp->port, "format-filter", format_filter, "properties", properties, NULL); - g_signal_connect (pl, + g_ptr_array_add (onp->links, link); + g_ptr_array_add (inp->links, link); + + g_signal_connect (link, "remove", (GCallback) do_remove_link, output_node); output_node->priv->n_used_output_links++; input_node->priv->n_used_input_links++; - olink->link = pl; - ilink->link = pl; } - return pl; + return link; same_node: {