mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2025-12-21 08:56:56 -05:00
WIP object model change
Work on cleanup
This commit is contained in:
parent
c25ccbb4ba
commit
0d21d633c9
26 changed files with 912 additions and 821 deletions
|
|
@ -31,26 +31,6 @@
|
|||
|
||||
#include "pinos/dbus/org-pinos.h"
|
||||
|
||||
static PinosPort *
|
||||
new_pinos_port (PinosNode *node, PinosDirection direction, uint32_t port)
|
||||
{
|
||||
PinosPort *np;
|
||||
np = calloc (1, sizeof (PinosPort));
|
||||
np->node = node;
|
||||
np->direction = direction;
|
||||
np->port = port;
|
||||
np->links = g_ptr_array_new ();
|
||||
pinos_signal_init (&np->destroy_signal);
|
||||
return np;
|
||||
}
|
||||
|
||||
static void
|
||||
free_node_port (PinosPort *np)
|
||||
{
|
||||
g_ptr_array_free (np->links, TRUE);
|
||||
g_slice_free (PinosPort, np);
|
||||
}
|
||||
|
||||
typedef struct
|
||||
{
|
||||
PinosNode this;
|
||||
|
|
@ -60,31 +40,21 @@ typedef struct
|
|||
|
||||
uint32_t seq;
|
||||
|
||||
gboolean async_init;
|
||||
GList *input_ports;
|
||||
GList *output_ports;
|
||||
guint n_used_output_links;
|
||||
guint n_used_input_links;
|
||||
bool async_init;
|
||||
|
||||
GError *error;
|
||||
guint idle_timeout;
|
||||
|
||||
struct {
|
||||
GPtrArray *links;
|
||||
} rt;
|
||||
} PinosNodeImpl;
|
||||
|
||||
|
||||
static void init_complete (PinosNode *this);
|
||||
|
||||
static void
|
||||
update_port_ids (PinosNode *node, gboolean create)
|
||||
update_port_ids (PinosNode *node, bool create)
|
||||
{
|
||||
PinosNodeImpl *impl = SPA_CONTAINER_OF (node, PinosNodeImpl, this);
|
||||
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;
|
||||
unsigned int n_input_ports, n_output_ports, max_input_ports, max_output_ports;
|
||||
unsigned int i;
|
||||
SpaList *ports;
|
||||
|
||||
if (node->node == NULL)
|
||||
return;
|
||||
|
|
@ -104,80 +74,82 @@ update_port_ids (PinosNode *node, gboolean create)
|
|||
max_output_ports,
|
||||
output_port_ids);
|
||||
|
||||
node->input_port_map = realloc (node->input_port_map, sizeof (PinosPort *) * max_input_ports);
|
||||
node->output_port_map = realloc (node->output_port_map, sizeof (PinosPort *) * max_output_ports);
|
||||
|
||||
pinos_log_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 = impl->input_ports;
|
||||
ports = &node->input_ports;
|
||||
while (true) {
|
||||
PinosPort *p = (ports ? ports->data : NULL);
|
||||
PinosPort *p = (ports == &node->input_ports) ? NULL : SPA_CONTAINER_OF (ports, PinosPort, link);
|
||||
|
||||
if (p && i < n_input_ports && p->port == input_port_ids[i]) {
|
||||
if (p && i < n_input_ports && p->port_id == input_port_ids[i]) {
|
||||
node->input_port_map[p->port_id] = p;
|
||||
pinos_log_debug ("node %p: exiting input port %d", node, input_port_ids[i]);
|
||||
i++;
|
||||
ports = g_list_next (ports);
|
||||
} else if ((p && i < n_input_ports && input_port_ids[i] < p->port) || i < n_input_ports) {
|
||||
ports = ports->next;
|
||||
} else if ((p && i < n_input_ports && input_port_ids[i] < p->port_id) || i < n_input_ports) {
|
||||
PinosPort *np;
|
||||
pinos_log_debug ("node %p: input port added %d", node, input_port_ids[i]);
|
||||
|
||||
np = new_pinos_port (node, PINOS_DIRECTION_INPUT, input_port_ids[i]);
|
||||
impl->input_ports = g_list_insert_before (impl->input_ports, ports, np);
|
||||
np = pinos_port_new (node, PINOS_DIRECTION_INPUT, input_port_ids[i]);
|
||||
spa_list_insert (ports, &np->link);
|
||||
ports = np->link.next;
|
||||
node->input_port_map[np->port_id] = np;
|
||||
|
||||
if (!impl->async_init)
|
||||
pinos_signal_emit (&node->core->port_added, node, np);
|
||||
i++;
|
||||
} else if (p) {
|
||||
GList *next;
|
||||
pinos_log_debug ("node %p: input port removed %d", node, p->port);
|
||||
|
||||
next = g_list_next (ports);
|
||||
impl->input_ports = g_list_delete_link (impl->input_ports, ports);
|
||||
ports = next;
|
||||
|
||||
node->input_port_map[p->port_id] = NULL;
|
||||
ports = ports->next;
|
||||
if (!impl->async_init)
|
||||
pinos_signal_emit (&node->core->port_removed, node, p);
|
||||
|
||||
free_node_port (p);
|
||||
} else
|
||||
pinos_log_debug ("node %p: input port removed %d", node, p->port_id);
|
||||
pinos_port_destroy (p);
|
||||
} else {
|
||||
pinos_log_debug ("node %p: no more input ports", node);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
i = 0;
|
||||
ports = impl->output_ports;
|
||||
ports = &node->output_ports;
|
||||
while (true) {
|
||||
PinosPort *p = (ports ? ports->data : NULL);
|
||||
PinosPort *p = (ports == &node->output_ports) ? NULL : SPA_CONTAINER_OF (ports, PinosPort, link);
|
||||
|
||||
if (p && i < n_output_ports && p->port == output_port_ids[i]) {
|
||||
if (p && i < n_output_ports && p->port_id == output_port_ids[i]) {
|
||||
pinos_log_debug ("node %p: exiting output port %d", node, output_port_ids[i]);
|
||||
i++;
|
||||
ports = g_list_next (ports);
|
||||
} else if ((p && i < n_output_ports && output_port_ids[i] < p->port) || i < n_output_ports) {
|
||||
ports = ports->next;
|
||||
node->output_port_map[p->port_id] = p;
|
||||
} else if ((p && i < n_output_ports && output_port_ids[i] < p->port_id) || i < n_output_ports) {
|
||||
PinosPort *np;
|
||||
pinos_log_debug ("node %p: output port added %d", node, output_port_ids[i]);
|
||||
|
||||
np = new_pinos_port (node, PINOS_DIRECTION_OUTPUT, output_port_ids[i]);
|
||||
impl->output_ports = g_list_insert_before (impl->output_ports, ports, np);
|
||||
np = pinos_port_new (node, PINOS_DIRECTION_OUTPUT, output_port_ids[i]);
|
||||
spa_list_insert (ports, &np->link);
|
||||
ports = np->link.next;
|
||||
node->output_port_map[np->port_id] = np;
|
||||
|
||||
if (!impl->async_init)
|
||||
pinos_signal_emit (&node->core->port_added, node, np);
|
||||
i++;
|
||||
} else if (p) {
|
||||
GList *next;
|
||||
pinos_log_debug ("node %p: output port removed %d", node, p->port);
|
||||
|
||||
next = g_list_next (ports);
|
||||
impl->output_ports = g_list_delete_link (impl->output_ports, ports);
|
||||
ports = next;
|
||||
|
||||
node->output_port_map[p->port_id] = NULL;
|
||||
ports = ports->next;
|
||||
if (!impl->async_init)
|
||||
pinos_signal_emit (&node->core->port_removed, node, p);
|
||||
|
||||
free_node_port (p);
|
||||
} else
|
||||
pinos_log_debug ("node %p: output port removed %d", node, p->port_id);
|
||||
pinos_port_destroy (p);
|
||||
} else {
|
||||
pinos_log_debug ("node %p: no more output ports", node);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
node->have_inputs = n_input_ports > 0;
|
||||
node->have_outputs = n_output_ports > 0;
|
||||
|
||||
node->transport = pinos_transport_new (max_input_ports,
|
||||
max_output_ports);
|
||||
|
||||
|
|
@ -227,31 +199,29 @@ start_node (PinosNode *this)
|
|||
static SpaResult
|
||||
suspend_node (PinosNode *this)
|
||||
{
|
||||
PinosNodeImpl *impl = SPA_CONTAINER_OF (this, PinosNodeImpl, this);
|
||||
SpaResult res = SPA_RESULT_OK;
|
||||
GList *walk;
|
||||
PinosPort *p;
|
||||
|
||||
pinos_log_debug ("node %p: suspend node", this);
|
||||
|
||||
for (walk = impl->input_ports; walk; walk = g_list_next (walk)) {
|
||||
PinosPort *p = walk->data;
|
||||
if ((res = spa_node_port_set_format (this->node, SPA_DIRECTION_INPUT, p->port, 0, NULL)) < 0)
|
||||
pinos_log_warn ("error unset format output: %d", res);
|
||||
spa_list_for_each (p, &this->input_ports, link) {
|
||||
if ((res = spa_node_port_set_format (this->node, SPA_DIRECTION_INPUT, p->port_id, 0, NULL)) < 0)
|
||||
pinos_log_warn ("error unset format input: %d", res);
|
||||
p->buffers = NULL;
|
||||
p->n_buffers = 0;
|
||||
if (p->allocated)
|
||||
pinos_memblock_free (&p->buffer_mem);
|
||||
p->allocated = FALSE;
|
||||
p->allocated = false;
|
||||
}
|
||||
for (walk = impl->output_ports; walk; walk = g_list_next (walk)) {
|
||||
PinosPort *p = walk->data;
|
||||
if ((res = spa_node_port_set_format (this->node, SPA_DIRECTION_OUTPUT, p->port, 0, NULL)) < 0)
|
||||
|
||||
spa_list_for_each (p, &this->output_ports, link) {
|
||||
if ((res = spa_node_port_set_format (this->node, SPA_DIRECTION_OUTPUT, p->port_id, 0, NULL)) < 0)
|
||||
pinos_log_warn ("error unset format output: %d", res);
|
||||
p->buffers = NULL;
|
||||
p->n_buffers = 0;
|
||||
if (p->allocated)
|
||||
pinos_memblock_free (&p->buffer_mem);
|
||||
p->allocated = FALSE;
|
||||
p->allocated = false;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
|
@ -297,19 +267,19 @@ do_read_link (SpaPoll *poll,
|
|||
size_t offset;
|
||||
SpaResult res;
|
||||
|
||||
if (link->input == NULL)
|
||||
if (link->rt.input == NULL)
|
||||
return SPA_RESULT_OK;
|
||||
|
||||
while (link->in_ready > 0 && spa_ringbuffer_get_read_offset (&link->ringbuffer, &offset) > 0) {
|
||||
SpaPortInput *input = &this->transport->inputs[link->input->port];
|
||||
while (link->rt.in_ready > 0 && spa_ringbuffer_get_read_offset (&link->ringbuffer, &offset) > 0) {
|
||||
SpaPortInput *input = &this->transport->inputs[link->rt.input->port_id];
|
||||
|
||||
input->buffer_id = link->queue[offset];
|
||||
|
||||
if ((res = spa_node_process_input (link->input->node->node)) < 0)
|
||||
if ((res = spa_node_process_input (link->rt.input->node->node)) < 0)
|
||||
pinos_log_warn ("node %p: error pushing buffer: %d, %d", this, res, input->status);
|
||||
|
||||
spa_ringbuffer_read_advance (&link->ringbuffer, 1);
|
||||
link->in_ready--;
|
||||
link->rt.in_ready--;
|
||||
}
|
||||
return SPA_RESULT_OK;
|
||||
}
|
||||
|
|
@ -319,7 +289,6 @@ static void
|
|||
on_node_event (SpaNode *node, SpaNodeEvent *event, void *user_data)
|
||||
{
|
||||
PinosNode *this = user_data;
|
||||
PinosNodeImpl *impl = SPA_CONTAINER_OF (this, PinosNodeImpl, this);
|
||||
|
||||
switch (event->type) {
|
||||
case SPA_NODE_EVENT_TYPE_INVALID:
|
||||
|
|
@ -342,21 +311,20 @@ on_node_event (SpaNode *node, SpaNodeEvent *event, void *user_data)
|
|||
case SPA_NODE_EVENT_TYPE_NEED_INPUT:
|
||||
{
|
||||
SpaNodeEventNeedInput *ni = (SpaNodeEventNeedInput *) event;
|
||||
guint i;
|
||||
PinosPort *port = this->input_port_map[ni->port_id];
|
||||
PinosLink *link;
|
||||
|
||||
for (i = 0; i < impl->rt.links->len; i++) {
|
||||
PinosLink *link = g_ptr_array_index (impl->rt.links, i);
|
||||
|
||||
if (link->input == NULL || link->input->port != ni->port_id)
|
||||
spa_list_for_each (link, &port->rt.links, rt.input_link) {
|
||||
if (link->rt.input == NULL || link->rt.output == NULL)
|
||||
continue;
|
||||
|
||||
link->in_ready++;
|
||||
spa_poll_invoke (&link->input->node->data_loop->poll,
|
||||
link->rt.in_ready++;
|
||||
spa_poll_invoke (&link->rt.input->node->data_loop->poll,
|
||||
do_read_link,
|
||||
SPA_ID_INVALID,
|
||||
sizeof (PinosLink *),
|
||||
&link,
|
||||
link->input->node);
|
||||
link->rt.input->node);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
@ -364,36 +332,33 @@ on_node_event (SpaNode *node, SpaNodeEvent *event, void *user_data)
|
|||
{
|
||||
SpaNodeEventHaveOutput *ho = (SpaNodeEventHaveOutput *) event;
|
||||
SpaResult res;
|
||||
guint i;
|
||||
gboolean pushed = FALSE;
|
||||
bool pushed = false;
|
||||
SpaPortOutput *po = &this->transport->outputs[ho->port_id];
|
||||
PinosPort *port = this->output_port_map[ho->port_id];
|
||||
PinosLink *link;
|
||||
|
||||
if ((res = spa_node_process_output (node)) < 0) {
|
||||
pinos_log_warn ("node %p: got pull error %d, %d", this, res, po->status);
|
||||
break;
|
||||
}
|
||||
|
||||
for (i = 0; i < impl->rt.links->len; i++) {
|
||||
PinosLink *link = g_ptr_array_index (impl->rt.links, i);
|
||||
PinosPort *output = link->output;
|
||||
PinosPort *input = link->input;
|
||||
spa_list_for_each (link, &port->rt.links, rt.output_link) {
|
||||
size_t offset;
|
||||
|
||||
if (output == NULL || input == NULL ||
|
||||
output->node->node != node || output->port != ho->port_id)
|
||||
if (link->rt.input == NULL || link->rt.output == NULL)
|
||||
continue;
|
||||
|
||||
if (spa_ringbuffer_get_write_offset (&link->ringbuffer, &offset) > 0) {
|
||||
link->queue[offset] = po->buffer_id;
|
||||
spa_ringbuffer_write_advance (&link->ringbuffer, 1);
|
||||
|
||||
spa_poll_invoke (&link->input->node->data_loop->poll,
|
||||
spa_poll_invoke (&link->rt.input->node->data_loop->poll,
|
||||
do_read_link,
|
||||
SPA_ID_INVALID,
|
||||
sizeof (PinosLink *),
|
||||
&link,
|
||||
link->input->node);
|
||||
pushed = TRUE;
|
||||
link->rt.input->node);
|
||||
pushed = true;
|
||||
}
|
||||
}
|
||||
if (!pushed) {
|
||||
|
|
@ -406,16 +371,15 @@ on_node_event (SpaNode *node, SpaNodeEvent *event, void *user_data)
|
|||
{
|
||||
SpaResult res;
|
||||
SpaNodeEventReuseBuffer *rb = (SpaNodeEventReuseBuffer *) event;
|
||||
guint i;
|
||||
PinosPort *port = this->input_port_map[rb->port_id];
|
||||
PinosLink *link;
|
||||
|
||||
for (i = 0; i < impl->rt.links->len; i++) {
|
||||
PinosLink *link = g_ptr_array_index (impl->rt.links, i);
|
||||
|
||||
if (link->input == NULL || link->input->port != rb->port_id || link->output == NULL)
|
||||
spa_list_for_each (link, &port->rt.links, rt.input_link) {
|
||||
if (link->rt.input == NULL || link->rt.output == NULL)
|
||||
continue;
|
||||
|
||||
if ((res = spa_node_port_reuse_buffer (link->output->node->node,
|
||||
link->output->port,
|
||||
if ((res = spa_node_port_reuse_buffer (link->rt.output->node->node,
|
||||
link->rt.output->port_id,
|
||||
rb->buffer_id)) < 0)
|
||||
pinos_log_warn ("node %p: error reuse buffer: %d", node, res);
|
||||
}
|
||||
|
|
@ -427,7 +391,7 @@ on_node_event (SpaNode *node, SpaNodeEvent *event, void *user_data)
|
|||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
static bool
|
||||
handle_remove (PinosNode1 *interface,
|
||||
GDBusMethodInvocation *invocation,
|
||||
gpointer user_data)
|
||||
|
|
@ -439,7 +403,7 @@ handle_remove (PinosNode1 *interface,
|
|||
|
||||
g_dbus_method_invocation_return_value (invocation,
|
||||
g_variant_new ("()"));
|
||||
return TRUE;
|
||||
return true;
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -503,14 +467,13 @@ pinos_node_new (PinosCore *core,
|
|||
impl->iface = pinos_node1_skeleton_new ();
|
||||
g_signal_connect (impl->iface, "handle-remove",
|
||||
(GCallback) handle_remove,
|
||||
node);
|
||||
this);
|
||||
|
||||
this->state = PINOS_NODE_STATE_CREATING;
|
||||
pinos_node1_set_state (impl->iface, this->state);
|
||||
|
||||
impl->rt.links = g_ptr_array_new_full (256, NULL);
|
||||
|
||||
//g_signal_connect (this, "notify", (GCallback) on_property_notify, this);
|
||||
spa_list_init (&this->input_ports);
|
||||
spa_list_init (&this->output_ports);
|
||||
|
||||
if (this->node->info) {
|
||||
unsigned int i;
|
||||
|
|
@ -527,12 +490,11 @@ pinos_node_new (PinosCore *core,
|
|||
if (this->node->state > SPA_NODE_STATE_INIT) {
|
||||
init_complete (this);
|
||||
} else {
|
||||
impl->async_init = TRUE;
|
||||
impl->async_init = true;
|
||||
pinos_main_loop_defer (this->core->main_loop,
|
||||
this,
|
||||
SPA_RESULT_RETURN_ASYNC (0),
|
||||
(PinosDeferFunc) init_complete,
|
||||
NULL,
|
||||
NULL);
|
||||
}
|
||||
spa_list_insert (core->node_list.prev, &this->list);
|
||||
|
|
@ -547,6 +509,75 @@ pinos_node_new (PinosCore *core,
|
|||
return this;
|
||||
}
|
||||
|
||||
static SpaResult
|
||||
do_node_remove_done (SpaPoll *poll,
|
||||
bool async,
|
||||
uint32_t seq,
|
||||
size_t size,
|
||||
void *data,
|
||||
void *user_data)
|
||||
{
|
||||
PinosNode *this = user_data;
|
||||
PinosNodeImpl *impl = SPA_CONTAINER_OF (this, PinosNodeImpl, this);
|
||||
PinosPort *port, *tmp;
|
||||
|
||||
pinos_main_loop_defer_cancel (this->core->main_loop, this, 0);
|
||||
|
||||
spa_list_for_each_safe (port, tmp, &this->input_ports, link)
|
||||
pinos_port_destroy (port);
|
||||
|
||||
spa_list_for_each_safe (port, tmp, &this->output_ports, link)
|
||||
pinos_port_destroy (port);
|
||||
|
||||
g_clear_object (&impl->iface);
|
||||
free (this->name);
|
||||
free (this->error);
|
||||
if (this->properties)
|
||||
pinos_properties_free (this->properties);
|
||||
free (impl);
|
||||
|
||||
return SPA_RESULT_OK;
|
||||
}
|
||||
|
||||
static SpaResult
|
||||
do_node_remove (SpaPoll *poll,
|
||||
bool async,
|
||||
uint32_t seq,
|
||||
size_t size,
|
||||
void *data,
|
||||
void *user_data)
|
||||
{
|
||||
PinosNode *this = user_data;
|
||||
PinosPort *port, *tmp;
|
||||
SpaResult res;
|
||||
|
||||
pause_node (this);
|
||||
|
||||
spa_list_for_each_safe (port, tmp, &this->input_ports, link) {
|
||||
PinosLink *link, *tlink;
|
||||
spa_list_for_each_safe (link, tlink, &port->rt.links, rt.input_link) {
|
||||
spa_list_remove (&link->rt.input_link);
|
||||
link->rt.input = NULL;
|
||||
}
|
||||
}
|
||||
spa_list_for_each_safe (port, tmp, &this->output_ports, link) {
|
||||
PinosLink *link, *tlink;
|
||||
spa_list_for_each_safe (link, tlink, &port->rt.links, rt.output_link) {
|
||||
spa_list_remove (&link->rt.output_link);
|
||||
link->rt.output = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
res = spa_poll_invoke (this->core->main_loop->poll,
|
||||
do_node_remove_done,
|
||||
seq,
|
||||
0,
|
||||
NULL,
|
||||
this);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* pinos_node_destroy:
|
||||
* @node: a #PinosNode
|
||||
|
|
@ -562,19 +593,15 @@ pinos_node_destroy (PinosNode * this)
|
|||
pinos_log_debug ("node %p: destroy", impl);
|
||||
pinos_signal_emit (&this->destroy_signal, this);
|
||||
|
||||
pinos_node_set_state (this, PINOS_NODE_STATE_SUSPENDED);
|
||||
|
||||
spa_list_remove (&this->list);
|
||||
pinos_core_remove_global (this->core, this->global);
|
||||
|
||||
pinos_main_loop_defer_cancel (this->core->main_loop, this, 0);
|
||||
|
||||
g_clear_object (&impl->iface);
|
||||
free (this->name);
|
||||
g_clear_error (&impl->error);
|
||||
if (this->properties)
|
||||
pinos_properties_free (this->properties);
|
||||
free (impl);
|
||||
spa_poll_invoke (&this->data_loop->poll,
|
||||
do_node_remove,
|
||||
impl->seq++,
|
||||
0,
|
||||
NULL,
|
||||
this);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -605,37 +632,35 @@ PinosPort *
|
|||
pinos_node_get_free_port (PinosNode *node,
|
||||
PinosDirection direction)
|
||||
{
|
||||
PinosNodeImpl *impl = SPA_CONTAINER_OF (node, PinosNodeImpl, this);
|
||||
guint free_port, n_ports, max_ports;
|
||||
GList *ports, *walk;
|
||||
PinosPort *port = NULL;
|
||||
unsigned int free_port, n_ports, max_ports;
|
||||
SpaList *ports;
|
||||
PinosPort *port = NULL, *p;
|
||||
|
||||
g_return_val_if_fail (node, NULL);
|
||||
|
||||
if (direction == PINOS_DIRECTION_INPUT) {
|
||||
max_ports = node->transport->area->max_inputs;
|
||||
n_ports = node->transport->area->n_inputs;
|
||||
ports = impl->input_ports;
|
||||
ports = &node->input_ports;
|
||||
} else {
|
||||
max_ports = node->transport->area->max_outputs;
|
||||
n_ports = node->transport->area->n_outputs;
|
||||
ports = impl->output_ports;
|
||||
ports = &node->output_ports;
|
||||
}
|
||||
free_port = 0;
|
||||
|
||||
pinos_log_debug ("node %p: direction %d max %u, n %u, free_port %u", node, direction, max_ports, n_ports, free_port);
|
||||
|
||||
for (walk = ports; walk; walk = g_list_next (walk)) {
|
||||
PinosPort *p = walk->data;
|
||||
|
||||
if (free_port < p->port) {
|
||||
spa_list_for_each (p, ports, link) {
|
||||
if (free_port < p->port_id) {
|
||||
port = p;
|
||||
break;
|
||||
}
|
||||
free_port = p->port + 1;
|
||||
free_port = p->port_id + 1;
|
||||
}
|
||||
if (free_port >= max_ports && ports) {
|
||||
port = ports->data;
|
||||
|
||||
if (free_port >= max_ports && !spa_list_is_empty (ports)) {
|
||||
port = spa_list_first (ports, PinosPort, link);
|
||||
} else
|
||||
return NULL;
|
||||
|
||||
|
|
@ -643,343 +668,6 @@ pinos_node_get_free_port (PinosNode *node,
|
|||
|
||||
}
|
||||
|
||||
|
||||
static SpaResult
|
||||
do_add_link (SpaPoll *poll,
|
||||
bool async,
|
||||
uint32_t seq,
|
||||
size_t size,
|
||||
void *data,
|
||||
void *user_data)
|
||||
{
|
||||
PinosNode *this = user_data;
|
||||
PinosNodeImpl *impl = SPA_CONTAINER_OF (this, PinosNodeImpl, this);
|
||||
PinosLink *link = ((PinosLink**)data)[0];
|
||||
|
||||
g_ptr_array_add (impl->rt.links, link);
|
||||
|
||||
return SPA_RESULT_OK;
|
||||
}
|
||||
|
||||
static PinosLink *
|
||||
find_link (PinosPort *output_port, PinosPort *input_port)
|
||||
{
|
||||
guint i;
|
||||
|
||||
for (i = 0; i < output_port->links->len; i++) {
|
||||
PinosLink *pl = g_ptr_array_index (output_port->links, i);
|
||||
if (pl->input == input_port) {
|
||||
return pl;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
PinosLink *
|
||||
pinos_port_get_link (PinosPort *output_port,
|
||||
PinosPort *input_port)
|
||||
{
|
||||
g_return_val_if_fail (output_port != NULL, NULL);
|
||||
g_return_val_if_fail (input_port != NULL, NULL);
|
||||
|
||||
return find_link (output_port, input_port);
|
||||
}
|
||||
|
||||
/**
|
||||
* pinos_port_link:
|
||||
* @output_port: an output port
|
||||
* @input_port: an input port
|
||||
* @format_filter: a format filter
|
||||
* @properties: extra properties
|
||||
* @error: an error or %NULL
|
||||
*
|
||||
* Make a link between @output_port and @input_port
|
||||
*
|
||||
* If the ports were already linked, the existing links will be returned.
|
||||
*
|
||||
* Returns: a new #PinosLink or %NULL and @error is set.
|
||||
*/
|
||||
PinosLink *
|
||||
pinos_port_link (PinosPort *output_port,
|
||||
PinosPort *input_port,
|
||||
GPtrArray *format_filter,
|
||||
PinosProperties *properties,
|
||||
GError **error)
|
||||
{
|
||||
PinosNodeImpl *input_impl, *output_impl;
|
||||
PinosNode *input_node, *output_node;
|
||||
PinosLink *link;
|
||||
|
||||
g_return_val_if_fail (output_port != NULL, NULL);
|
||||
g_return_val_if_fail (input_port != NULL, NULL);
|
||||
|
||||
output_node = output_port->node;
|
||||
output_impl = SPA_CONTAINER_OF (output_node, PinosNodeImpl, this);
|
||||
input_node = input_port->node;
|
||||
input_impl = SPA_CONTAINER_OF (input_node, PinosNodeImpl, this);
|
||||
|
||||
pinos_log_debug ("port link %p:%u -> %p:%u", output_node, output_port->port, input_node, input_port->port);
|
||||
|
||||
if (output_node == input_node)
|
||||
goto same_node;
|
||||
|
||||
if (input_port->links->len > 0)
|
||||
goto was_linked;
|
||||
|
||||
link = find_link (output_port, input_port);
|
||||
|
||||
if (link == NULL) {
|
||||
input_node->live = output_node->live;
|
||||
if (output_node->clock)
|
||||
input_node->clock = output_node->clock;
|
||||
pinos_log_debug ("node %p: clock %p, live %d", output_node, output_node->clock, output_node->live);
|
||||
|
||||
link = pinos_link_new (output_node->core,
|
||||
output_port,
|
||||
input_port,
|
||||
format_filter,
|
||||
properties);
|
||||
|
||||
g_ptr_array_add (output_port->links, link);
|
||||
g_ptr_array_add (input_port->links, link);
|
||||
|
||||
output_impl->n_used_output_links++;
|
||||
input_impl->n_used_input_links++;
|
||||
|
||||
spa_poll_invoke (&output_node->data_loop->poll,
|
||||
do_add_link,
|
||||
SPA_ID_INVALID,
|
||||
sizeof (PinosLink *),
|
||||
&link,
|
||||
output_node);
|
||||
spa_poll_invoke (&input_node->data_loop->poll,
|
||||
do_add_link,
|
||||
SPA_ID_INVALID,
|
||||
sizeof (PinosLink *),
|
||||
&link,
|
||||
input_node);
|
||||
}
|
||||
return link;
|
||||
|
||||
same_node:
|
||||
{
|
||||
g_set_error (error,
|
||||
PINOS_ERROR,
|
||||
PINOS_ERROR_NODE_LINK,
|
||||
"can't link a node to itself");
|
||||
return NULL;
|
||||
}
|
||||
was_linked:
|
||||
{
|
||||
g_set_error (error,
|
||||
PINOS_ERROR,
|
||||
PINOS_ERROR_NODE_LINK,
|
||||
"input port was already linked");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static SpaResult
|
||||
pinos_port_pause (PinosPort *port)
|
||||
{
|
||||
SpaNodeCommand cmd;
|
||||
|
||||
cmd.type = SPA_NODE_COMMAND_PAUSE;
|
||||
cmd.size = sizeof (cmd);
|
||||
return spa_node_port_send_command (port->node->node,
|
||||
port->direction,
|
||||
port->port,
|
||||
&cmd);
|
||||
}
|
||||
|
||||
static SpaResult
|
||||
do_remove_link_done (SpaPoll *poll,
|
||||
bool async,
|
||||
uint32_t seq,
|
||||
size_t size,
|
||||
void *data,
|
||||
void *user_data)
|
||||
{
|
||||
PinosPort *port = user_data;
|
||||
PinosNode *this = port->node;
|
||||
PinosNodeImpl *impl = SPA_CONTAINER_OF (this, PinosNodeImpl, this);
|
||||
PinosLink *link = ((PinosLink**)data)[0];
|
||||
|
||||
pinos_log_debug ("port %p: finish unlink", port);
|
||||
if (port->direction == PINOS_DIRECTION_OUTPUT) {
|
||||
if (g_ptr_array_remove_fast (port->links, link))
|
||||
impl->n_used_output_links--;
|
||||
link->output = NULL;
|
||||
} else {
|
||||
if (g_ptr_array_remove_fast (port->links, link))
|
||||
impl->n_used_input_links--;
|
||||
link->input = NULL;
|
||||
}
|
||||
|
||||
if (impl->n_used_output_links == 0 &&
|
||||
impl->n_used_input_links == 0) {
|
||||
pinos_node_report_idle (this);
|
||||
}
|
||||
|
||||
if (!port->allocated) {
|
||||
pinos_log_debug ("port %p: clear buffers on port", port);
|
||||
spa_node_port_use_buffers (port->node->node,
|
||||
port->direction,
|
||||
port->port,
|
||||
NULL, 0);
|
||||
port->buffers = NULL;
|
||||
port->n_buffers = 0;
|
||||
}
|
||||
|
||||
pinos_main_loop_defer_complete (this->core->main_loop,
|
||||
port,
|
||||
seq,
|
||||
SPA_RESULT_OK);
|
||||
g_object_unref (link);
|
||||
g_object_unref (port->node);
|
||||
|
||||
return SPA_RESULT_OK;
|
||||
}
|
||||
|
||||
static SpaResult
|
||||
do_remove_link (SpaPoll *poll,
|
||||
bool async,
|
||||
uint32_t seq,
|
||||
size_t size,
|
||||
void *data,
|
||||
void *user_data)
|
||||
{
|
||||
PinosPort *port = user_data;
|
||||
PinosNode *this = port->node;
|
||||
PinosNodeImpl *impl = SPA_CONTAINER_OF (this, PinosNodeImpl, this);
|
||||
PinosLink *link = ((PinosLink**)data)[0];
|
||||
SpaResult res;
|
||||
|
||||
#if 0
|
||||
/* FIXME we should only pause when all links are gone */
|
||||
pinos_port_pause (port);
|
||||
#endif
|
||||
|
||||
g_ptr_array_remove_fast (impl->rt.links, link);
|
||||
|
||||
res = spa_poll_invoke (this->core->main_loop->poll,
|
||||
do_remove_link_done,
|
||||
seq,
|
||||
sizeof (PinosLink *),
|
||||
&link,
|
||||
port);
|
||||
return res;
|
||||
}
|
||||
|
||||
SpaResult
|
||||
pinos_port_unlink (PinosPort *port, PinosLink *link)
|
||||
{
|
||||
SpaResult res;
|
||||
PinosNodeImpl *impl = SPA_CONTAINER_OF (port->node, PinosNodeImpl, this);
|
||||
|
||||
pinos_log_debug ("port %p: start unlink %p", port, link);
|
||||
|
||||
g_object_ref (link);
|
||||
g_object_ref (port->node);
|
||||
res = spa_poll_invoke (&port->node->data_loop->poll,
|
||||
do_remove_link,
|
||||
impl->seq++,
|
||||
sizeof (PinosLink *),
|
||||
&link,
|
||||
port);
|
||||
return res;
|
||||
}
|
||||
|
||||
static SpaResult
|
||||
do_clear_buffers_done (SpaPoll *poll,
|
||||
bool async,
|
||||
uint32_t seq,
|
||||
size_t size,
|
||||
void *data,
|
||||
void *user_data)
|
||||
{
|
||||
PinosPort *port = user_data;
|
||||
PinosNode *this = port->node;
|
||||
SpaResult res;
|
||||
|
||||
pinos_log_debug ("port %p: clear buffers finish", port);
|
||||
|
||||
res = spa_node_port_use_buffers (port->node->node,
|
||||
port->direction,
|
||||
port->port,
|
||||
NULL, 0);
|
||||
port->buffers = NULL;
|
||||
port->n_buffers = 0;
|
||||
|
||||
pinos_main_loop_defer_complete (this->core->main_loop,
|
||||
port,
|
||||
seq,
|
||||
res);
|
||||
return res;
|
||||
}
|
||||
|
||||
static SpaResult
|
||||
do_clear_buffers (SpaPoll *poll,
|
||||
bool async,
|
||||
uint32_t seq,
|
||||
size_t size,
|
||||
void *data,
|
||||
void *user_data)
|
||||
{
|
||||
PinosPort *port = user_data;
|
||||
PinosNode *this = port->node;
|
||||
SpaResult res;
|
||||
|
||||
pinos_port_pause (port);
|
||||
|
||||
res = spa_poll_invoke (this->core->main_loop->poll,
|
||||
do_clear_buffers_done,
|
||||
seq,
|
||||
0, NULL,
|
||||
port);
|
||||
return res;
|
||||
}
|
||||
|
||||
SpaResult
|
||||
pinos_port_clear_buffers (PinosPort *port)
|
||||
{
|
||||
SpaResult res;
|
||||
PinosNodeImpl *impl = SPA_CONTAINER_OF (port->node, PinosNodeImpl, this);
|
||||
|
||||
pinos_log_debug ("port %p: clear buffers", port);
|
||||
res = spa_poll_invoke (&port->node->data_loop->poll,
|
||||
do_clear_buffers,
|
||||
impl->seq++,
|
||||
0, NULL,
|
||||
port);
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* pinos_node_get_ports:
|
||||
* @node: a #PinosNode
|
||||
* @direction: a #PinosDirection
|
||||
*
|
||||
* Get the port in @node.
|
||||
*
|
||||
* Returns: a #GList of #PinosPort g_list_free after usage.
|
||||
*/
|
||||
GList *
|
||||
pinos_node_get_ports (PinosNode *node, PinosDirection direction)
|
||||
{
|
||||
GList *ports;
|
||||
PinosNodeImpl *impl = SPA_CONTAINER_OF (node, PinosNodeImpl, this);
|
||||
|
||||
g_return_val_if_fail (node, NULL);
|
||||
|
||||
if (direction == PINOS_DIRECTION_INPUT) {
|
||||
ports = impl->input_ports;
|
||||
} else {
|
||||
ports = impl->output_ports;
|
||||
}
|
||||
return ports;
|
||||
}
|
||||
|
||||
static void
|
||||
remove_idle_timeout (PinosNode *node)
|
||||
{
|
||||
|
|
@ -998,12 +686,10 @@ on_state_complete (PinosNode *node,
|
|||
{
|
||||
PinosNodeState state = GPOINTER_TO_INT (data);
|
||||
|
||||
pinos_log_debug ("node %p: state complete %d", node, res);
|
||||
if (SPA_RESULT_IS_ERROR (res)) {
|
||||
GError *error = NULL;
|
||||
g_set_error (&error,
|
||||
PINOS_ERROR,
|
||||
PINOS_ERROR_NODE_STATE,
|
||||
"error changing node state: %d", res);
|
||||
char *error;
|
||||
asprintf (&error, "error changing node state: %d", res);
|
||||
pinos_node_report_error (node, error);
|
||||
} else
|
||||
pinos_node_update_state (node, state);
|
||||
|
|
@ -1060,8 +746,7 @@ pinos_node_set_state (PinosNode *node,
|
|||
node,
|
||||
res,
|
||||
(PinosDeferFunc) on_state_complete,
|
||||
GINT_TO_POINTER (state),
|
||||
NULL);
|
||||
GINT_TO_POINTER (state));
|
||||
|
||||
return res;
|
||||
}
|
||||
|
|
@ -1098,30 +783,30 @@ pinos_node_update_state (PinosNode *node,
|
|||
/**
|
||||
* pinos_node_report_error:
|
||||
* @node: a #PinosNode
|
||||
* @error: a #GError
|
||||
* @error: an error message
|
||||
*
|
||||
* Report an error from within @node.
|
||||
*/
|
||||
void
|
||||
pinos_node_report_error (PinosNode *node,
|
||||
GError *error)
|
||||
char *error)
|
||||
{
|
||||
PinosNodeImpl *impl = SPA_CONTAINER_OF (node, PinosNodeImpl, this);
|
||||
PinosNodeState old;
|
||||
|
||||
g_return_if_fail (node);
|
||||
|
||||
g_clear_error (&impl->error);
|
||||
free (node->error);
|
||||
remove_idle_timeout (node);
|
||||
impl->error = error;
|
||||
node->error = error;
|
||||
old = node->state;
|
||||
node->state = PINOS_NODE_STATE_ERROR;
|
||||
pinos_log_debug ("node %p: got error state %s", node, error->message);
|
||||
pinos_log_debug ("node %p: got error state %s", node, error);
|
||||
pinos_node1_set_state (impl->iface, PINOS_NODE_STATE_ERROR);
|
||||
pinos_signal_emit (&node->core->node_state_changed, node, old, node->state);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
static bool
|
||||
idle_timeout (PinosNode *node)
|
||||
{
|
||||
PinosNodeImpl *impl = SPA_CONTAINER_OF (node, PinosNodeImpl, this);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue