diff --git a/spa/include/spa/node/node.h b/spa/include/spa/node/node.h index 70a0b8b2b..f35c27bfe 100644 --- a/spa/include/spa/node/node.h +++ b/spa/include/spa/node/node.h @@ -653,8 +653,11 @@ struct spa_node_methods { /** node keys */ #define SPA_KEY_NODE_NAME "node.name" /**< a node name */ -#define SPA_KEY_NODE_DRIVER "node.driver" /**< the node can be a driver */ #define SPA_KEY_NODE_LATENCY "node.latency" /**< the requested node latency */ + +#define SPA_KEY_NODE_DRIVER "node.driver" /**< the node can be a driver */ +#define SPA_KEY_NODE_ALWAYS_PROCESS "node.always-process" /**< call the process function even if + * not linked. */ #define SPA_KEY_NODE_PAUSE_ON_IDLE "node.pause-on-idle" /**< if the node should be paused * immediately when idle. */ diff --git a/src/pipewire/core.c b/src/pipewire/core.c index cdae50c0a..faac66a35 100644 --- a/src/pipewire/core.c +++ b/src/pipewire/core.c @@ -1101,22 +1101,63 @@ static int collect_nodes(struct pw_node *driver) int pw_core_recalc_graph(struct pw_core *core) { - struct pw_node *n, *s; + struct pw_node *n, *s, *target; + /* start from all drivers and group all nodes that are linked + * to it. Some nodes are not (yet) linked to anything and they + * will end up 'unassigned' to a master. Other nodes are master + * and if they have active slaves, we can use them to schedule + * the unassigned nodes. */ + target = NULL; spa_list_for_each(n, &core->driver_list, driver_link) { - if (!n->visited) + uint32_t active_slaves; + + if (n->active && !n->visited) collect_nodes(n); + + /* from now on we are only interested in nodes that are + * a master. We're going to count the number of slaves it + * has. */ + if (!n->master) + continue; + + active_slaves = 0; + spa_list_for_each(s, &n->slave_list, slave_link) { + pw_log_info(NAME" %p: driver %p: slave %p %s: %d", + core, n, s, s->name, s->active); + if (s != n && s->active) + active_slaves++; + } + pw_log_info(NAME" %p: driver %p active slaves %d", + core, n, active_slaves); + + /* if the master has active slaves, it is a target for our + * unassigned nodes */ + if (active_slaves > 0) { + if (target == NULL) + target = n; + } } + /* now go through all available nodes. The ones we didn't visit + * in collect_nodes() are not linked to any master. We assign them + * to an active master */ spa_list_for_each(n, &core->node_list, link) { if (!n->visited) { pw_log_info(NAME" %p: unassigned node %p: '%s' %d", core, n, n->name, n->active); - pw_node_set_driver(n, NULL); + if (!n->want_driver) + pw_node_set_driver(n, NULL); + else { + pw_node_set_driver(n, target); + pw_node_set_state(n, target && n->active ? + PW_NODE_STATE_RUNNING : PW_NODE_STATE_IDLE); + } } n->visited = false; } + /* debug only here to list all masters and their slaves */ spa_list_for_each(n, &core->driver_list, driver_link) { if (!n->master) continue; diff --git a/src/pipewire/keys.h b/src/pipewire/keys.h index d5864d907..8600bd316 100644 --- a/src/pipewire/keys.h +++ b/src/pipewire/keys.h @@ -121,6 +121,7 @@ extern "C" { #define PW_KEY_NODE_LATENCY "node.latency" /**< the requested latency of the node as * a fraction. Ex: 128/48000 */ #define PW_KEY_NODE_DONT_RECONNECT "node.dont-reconnect" /**< don't reconnect this node */ +#define PW_KEY_NODE_ALWAYS_PROCESS "node.always-process" /**< process even when unlinked */ #define PW_KEY_NODE_PAUSE_ON_IDLE "node.pause-on-idle" /**< pause the node when idle */ #define PW_KEY_NODE_DRIVER "node.driver" /**< node can drive the graph */ #define PW_KEY_NODE_STREAM "node.stream" /**< node is a stream, the server side should diff --git a/src/pipewire/node.c b/src/pipewire/node.c index f21d53e57..2e0446b27 100644 --- a/src/pipewire/node.c +++ b/src/pipewire/node.c @@ -601,6 +601,8 @@ int pw_node_register(struct pw_node *this, spa_list_for_each(port, &this->output_ports, link) pw_port_register(port, NULL); + pw_core_recalc_graph(core); + return 0; error_existed: @@ -706,6 +708,11 @@ static void check_properties(struct pw_node *node) else driver = false; + if ((str = pw_properties_get(node->properties, PW_KEY_NODE_ALWAYS_PROCESS))) + node->want_driver = pw_properties_parse_bool(str); + else + node->want_driver = false; + if (node->driver != driver) { pw_log_info(NAME" %p: driver %d -> %d", node, node->driver, driver); node->driver = driver; diff --git a/src/pipewire/private.h b/src/pipewire/private.h index 0f314b8b3..132206794 100644 --- a/src/pipewire/private.h +++ b/src/pipewire/private.h @@ -419,6 +419,7 @@ struct pw_node { unsigned int master:1; /**< a master node is one of the driver nodes that * is selected to drive the graph */ unsigned int visited:1; /**< for sorting */ + unsigned int want_driver:1; /**< this node wants to be assigned to a driver */ uint32_t port_user_data_size; /**< extra size for port user data */