impl-node: activate links immediately

Don't wait for the node to be added to the graph before we activate
the links to it.

We don't do the reverse for shutdown and the activation counters won't
actually be updated until the node is added.

Waiting can cause race conditions in some specific cases (see in
screen sharing unit test) because the driver node can start
pushing buffers before the link has sent the Buffer io area to the
ports.

With this fix, the receiver (input stream) will first trigger
the input link activation, then the Start command and then it will be
added to the graph.

This does not entirely fix the race conditions when starting. Ideally,
the driver node should wait until all pending Start commands of the
nodes in the graph have completed.
This commit is contained in:
Wim Taymans 2022-12-03 20:03:00 +01:00
parent 90d00551b7
commit a5f23224d1
2 changed files with 4 additions and 13 deletions

View file

@ -622,8 +622,8 @@ int pw_impl_link_activate(struct pw_impl_link *this)
pw_log_debug("%p: activate activated:%d state:%s", this, impl->activated, pw_log_debug("%p: activate activated:%d state:%s", this, impl->activated,
pw_link_state_as_string(this->info.state)); pw_link_state_as_string(this->info.state));
if (impl->activated || !this->prepared || !impl->inode->active || if (impl->activated || !this->prepared ||
!impl->inode->added || !impl->onode->active) !impl->inode->active || !impl->onode->active)
return 0; return 0;
if (!impl->io_set) { if (!impl->io_set) {

View file

@ -239,7 +239,7 @@ static int idle_node(struct pw_impl_node *this)
return res; return res;
} }
static void node_activate_outputs(struct pw_impl_node *this) static void node_activate(struct pw_impl_node *this)
{ {
struct pw_impl_port *port; struct pw_impl_port *port;
@ -249,13 +249,6 @@ static void node_activate_outputs(struct pw_impl_node *this)
spa_list_for_each(link, &port->links, output_link) spa_list_for_each(link, &port->links, output_link)
pw_impl_link_activate(link); pw_impl_link_activate(link);
} }
}
static void node_activate_inputs(struct pw_impl_node *this)
{
struct pw_impl_port *port;
pw_log_debug("%p: activate", this);
spa_list_for_each(port, &this->input_ports, link) { spa_list_for_each(port, &this->input_ports, link) {
struct pw_impl_link *link; struct pw_impl_link *link;
spa_list_for_each(link, &port->links, input_link) spa_list_for_each(link, &port->links, input_link)
@ -268,9 +261,7 @@ static int start_node(struct pw_impl_node *this)
struct impl *impl = SPA_CONTAINER_OF(this, struct impl, this); struct impl *impl = SPA_CONTAINER_OF(this, struct impl, this);
int res = 0; int res = 0;
/* First activate the outputs so that when the node starts pushing, node_activate(this);
* we can process the outputs */
node_activate_outputs(this);
if (impl->pending_state >= PW_NODE_STATE_RUNNING) if (impl->pending_state >= PW_NODE_STATE_RUNNING)
return 0; return 0;