diff --git a/doc/dox/config/pipewire-props.7.md b/doc/dox/config/pipewire-props.7.md index 5555e3408..a215c6f21 100644 --- a/doc/dox/config/pipewire-props.7.md +++ b/doc/dox/config/pipewire-props.7.md @@ -450,11 +450,25 @@ Whether the node target may be changed using metadata. @PAR@ node-prop node.passive = false \parblock -This is a passive node and so it should not keep sinks/sources busy. This property makes the session manager create passive links to the sink/sources. If the node is not otherwise linked (via a non-passive link), the node and the sink it is linked to are idle (and eventually suspended). +This can be used to configure the port.passive property for all ports of this node. + +Possible values are: + + * "out": output ports are passive, They will not make the peers active and active peers will + not make this node active. + * "in": input ports are passive, They will not make the peers active and active peers will + not make this node active. + * "true": A combination in "in" and "out", both input and output ports are passive. + * "out-follow": output ports will not make the peer active but when the peer is activated via + some other way, this node will also become active. + * "in-follow": input ports will not make the peer active but when the peer is activated via + some other way, this node will also become active. + * "follow": A combination of "in-follow" and "out-follow". This is used for filter nodes that sit in front of sinks/sources and need to suspend together with the sink/source. \endparblock + @PAR@ node-prop node.link-group = ID Add the node to a certain link group. Nodes from the same link group are not automatically linked to each other by the session manager. And example is a coupled stream where you don't want the output to link to the input streams, making a useless loop. @@ -1420,6 +1434,11 @@ them. Below are some port properties may interesting for users: \copydoc PW_KEY_PORT_ALIAS \endparblock +@PAR@ port-prop port.passive # string +\parblock +\copydoc PW_KEY_PORT_PASSIVE +\endparblock + \see pw_keys in the API documentation for a full list. # LINK PROPERTIES @IDX@ props diff --git a/src/modules/module-scheduler-v1.c b/src/modules/module-scheduler-v1.c index 80a797cfa..9eb8f3467 100644 --- a/src/modules/module-scheduler-v1.c +++ b/src/modules/module-scheduler-v1.c @@ -108,10 +108,10 @@ static int ensure_state(struct pw_impl_node *node, bool running) /* make a node runnable. This will automatically also make all non-passive peer nodes * runnable and the nodes that belong to the same groups or link_groups. We stop when - * we reach a passive port. + * we reach a passive_into port. * * We have 4 cases for the links: - * (p) marks a passive port. we don't follow the peer from this port. + * (p) marks a passive_into port. we don't follow the peer from this port. * * A -> B ==> B can also be runnable * A p-> B ==> B can also be runnable @@ -145,8 +145,8 @@ static void make_runnable(struct pw_context *context, struct pw_impl_node *node) spa_list_for_each(l, &p->links, output_link) { n = l->input->node; pw_log_trace(" out-port %p: link %p passive:%d prepared:%d active:%d runn:%d", p, - l, l->input->passive, l->prepared, n->active, n->runnable); - if (!n->active || l->input->passive) + l, l->input->passive_into, l->prepared, n->active, n->runnable); + if (!n->active || l->input->passive_into) continue; pw_impl_link_prepare(l); if (!l->prepared) @@ -159,8 +159,8 @@ static void make_runnable(struct pw_context *context, struct pw_impl_node *node) spa_list_for_each(l, &p->links, input_link) { n = l->output->node; pw_log_trace(" in-port %p: link %p passive:%d prepared:%d active:%d runn:%d", p, - l, l->output->passive, l->prepared, n->active, n->runnable); - if (!n->active || l->output->passive) + l, l->output->passive_into, l->prepared, n->active, n->runnable); + if (!n->active || l->output->passive_into) continue; pw_impl_link_prepare(l); if (!l->prepared) @@ -193,7 +193,7 @@ static void make_runnable(struct pw_context *context, struct pw_impl_node *node) * * There are 4 cases: * - * (p) marks a passive port. we don't follow the peer from this port. + * (p) marks a passive_away port. we don't follow the peer from this port. * A can not be a driver * * A -> B ==> both nodes can run @@ -223,8 +223,8 @@ static void check_runnable(struct pw_context *context, struct pw_impl_node *node /* the peer needs to be active and we are linked to it * with a non-passive link */ pw_log_trace(" out-port %p: link %p passive:%d prepared:%d active:%d", p, - l, p->passive, l->prepared, n->active); - if (!n->active || p->passive) + l, p->passive_away, l->prepared, n->active); + if (!n->active || p->passive_away) continue; /* explicitly prepare the link in case it was suspended */ pw_impl_link_prepare(l); @@ -238,8 +238,8 @@ static void check_runnable(struct pw_context *context, struct pw_impl_node *node spa_list_for_each(l, &p->links, input_link) { n = l->output->node; pw_log_trace(" in-port %p: link %p passive:%d prepared:%d active:%d", p, - l, p->passive, l->prepared, n->active); - if (!n->active || p->passive) + l, p->passive_away, l->prepared, n->active); + if (!n->active || p->passive_away) continue; pw_impl_link_prepare(l); if (!l->prepared) diff --git a/src/pipewire/impl-node.c b/src/pipewire/impl-node.c index f5dd7c96b..c7591afd2 100644 --- a/src/pipewire/impl-node.c +++ b/src/pipewire/impl-node.c @@ -1269,12 +1269,35 @@ static void check_properties(struct pw_impl_node *node) } if ((str = pw_properties_get(node->properties, PW_KEY_NODE_PASSIVE)) == NULL) str = "false"; - if (spa_streq(str, "out")) - node->out_passive = true; - else if (spa_streq(str, "in")) - node->in_passive = true; - else - node->in_passive = node->out_passive = spa_atob(str); + + if (spa_streq(str, "out")) { + node->passive_away[SPA_DIRECTION_OUTPUT] = true; + node->passive_into[SPA_DIRECTION_OUTPUT]= true; + } + if (spa_streq(str, "out-follow")) { + node->passive_away[SPA_DIRECTION_OUTPUT] = true; + node->passive_into[SPA_DIRECTION_OUTPUT] = false; + } + else if (spa_streq(str, "in")) { + node->passive_away[SPA_DIRECTION_INPUT] = true; + node->passive_into[SPA_DIRECTION_INPUT]= true; + } + else if (spa_streq(str, "in-follow")) { + node->passive_away[SPA_DIRECTION_INPUT] = true; + node->passive_into[SPA_DIRECTION_INPUT] = false; + } + else if (spa_streq(str, "follow")) { + node->passive_away[SPA_DIRECTION_INPUT] = true; + node->passive_into[SPA_DIRECTION_INPUT] = false; + node->passive_away[SPA_DIRECTION_OUTPUT] = true; + node->passive_into[SPA_DIRECTION_OUTPUT] = false; + } + else { + node->passive_away[SPA_DIRECTION_OUTPUT] = + node->passive_into[SPA_DIRECTION_OUTPUT] = + node->passive_away[SPA_DIRECTION_INPUT] = + node->passive_into[SPA_DIRECTION_INPUT] = spa_atob(str); + } node->want_driver = pw_properties_get_bool(node->properties, PW_KEY_NODE_WANT_DRIVER, false); node->always_process = pw_properties_get_bool(node->properties, PW_KEY_NODE_ALWAYS_PROCESS, false); diff --git a/src/pipewire/impl-port.c b/src/pipewire/impl-port.c index ed6fe9f1e..3b87c8c0b 100644 --- a/src/pipewire/impl-port.c +++ b/src/pipewire/impl-port.c @@ -537,10 +537,25 @@ static int check_properties(struct pw_impl_port *port) &schedule_tee_node; } - /* inherit passive state from parent node */ - port->passive = pw_properties_get_bool(port->properties, PW_KEY_PORT_PASSIVE, - port->direction == PW_DIRECTION_INPUT ? - node->in_passive : node->out_passive); + + if ((str = pw_properties_get(port->properties, PW_KEY_PORT_PASSIVE)) == NULL) { + /* inherit passive state from parent node */ + port->passive_into = node->passive_into[port->direction]; + port->passive_away = node->passive_away[port->direction]; + } else { + if (spa_streq(str, "true")) { + port->passive_into = true; + port->passive_away = true; + } + else if (spa_streq(str, "follow")) { + port->passive_into = false; + port->passive_away = true; + } else { + port->passive_into = false; + port->passive_away = false; + } + + } if (media_class != NULL && (strstr(media_class, "Sink") != NULL || diff --git a/src/pipewire/keys.h b/src/pipewire/keys.h index 13694bc29..a7afd398e 100644 --- a/src/pipewire/keys.h +++ b/src/pipewire/keys.h @@ -213,7 +213,8 @@ extern "C" { * object */ #define PW_KEY_NODE_PASSIVE "node.passive" /**< indicate that a node wants passive links * on output/input/all ports when the value is - * "out"/"in"/"true" respectively */ + * "out"/"out-follow"/"in"/"in-follow"/ + * "true"/"follow" */ #define PW_KEY_NODE_LINK_GROUP "node.link-group" /**< the node is internally linked to * nodes with the same link-group. Can be an * array of group names. */ @@ -247,7 +248,8 @@ extern "C" { #define PW_KEY_PORT_CACHE_PARAMS "port.cache-params" /**< cache the node port params */ #define PW_KEY_PORT_EXTRA "port.extra" /**< api specific extra port info, API name * should be prefixed. "jack:flags:56" */ -#define PW_KEY_PORT_PASSIVE "port.passive" /**< the ports wants passive links, since 0.3.67 */ +#define PW_KEY_PORT_PASSIVE "port.passive" /**< the ports wants passive links. Values + * can be "true" or "follow". Since 0.3.67 */ #define PW_KEY_PORT_IGNORE_LATENCY "port.ignore-latency" /**< latency ignored by peers, since 0.3.71 */ #define PW_KEY_PORT_GROUP "port.group" /**< the port group of the port 1.2.0 */ #define PW_KEY_PORT_EXCLUSIVE "port.exclusive" /**< link port only once 1.6.0 */ @@ -261,7 +263,8 @@ extern "C" { #define PW_KEY_LINK_OUTPUT_PORT "link.output.port" /**< output port id of a link */ #define PW_KEY_LINK_PASSIVE "link.passive" /**< indicate that a link is passive and * does not cause the graph to be - * runnable. */ + * runnable. Deprecated look at + * port.passive properties. */ #define PW_KEY_LINK_FEEDBACK "link.feedback" /**< indicate that a link is a feedback * link and the target will receive data * in the next cycle */ diff --git a/src/pipewire/private.h b/src/pipewire/private.h index 25a2928fe..58801bc27 100644 --- a/src/pipewire/private.h +++ b/src/pipewire/private.h @@ -762,8 +762,6 @@ struct pw_impl_node { * 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 */ - unsigned int in_passive:1; /**< node input links should be passive */ - unsigned int out_passive:1; /**< node output links should be passive */ unsigned int runnable:1; /**< node is runnable */ unsigned int freewheel:1; /**< if this is the freewheel driver */ unsigned int loopchecked:1; /**< for feedback loop checking */ @@ -788,6 +786,9 @@ struct pw_impl_node { unsigned int exclusive:1; /**< ports can only be linked once */ unsigned int reliable:1; /**< ports need reliable tee */ + bool passive_away[2]; /**< node input links should be passive */ + bool passive_into[2]; /**< node input links should be passive */ + uint32_t transport; /**< latest transport request */ uint32_t port_user_data_size; /**< extra size for port user data */ @@ -962,7 +963,8 @@ struct pw_impl_port { bool added; } rt; /**< data only accessed from the data thread */ unsigned int destroying:1; - unsigned int passive:1; + unsigned int passive_into:1; + unsigned int passive_away:1; unsigned int auto_path:1; /* path was automatically generated */ unsigned int auto_name:1; /* name was automatically generated */ unsigned int auto_alias:1; /* alias was automatically generated */