Make PinosPort struct

Keep track of the ports, their links and the allocated buffers in a
small struct managed by the node.
This commit is contained in:
Wim Taymans 2016-09-28 10:42:36 +02:00
parent c6861845a7
commit fe37e2bc1b
4 changed files with 364 additions and 417 deletions

View file

@ -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;
}

View file

@ -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,

View file

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

View file

@ -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:
{