mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2026-03-08 05:34:03 -04:00
impl-port: support mode port.passive values
Add a port.passive = follow mode and the node.passive equivalents out-follow, in-follow, follow. This makes it possible to control how a port influences the state of the peer and how the peer influences the state of the node independently. In passive mode, the port will not make the peer runnable and will also not become runnable when the peer activates. In the follow mode, the port will not make the peer runnable but it will become runnable when the peer is active. This makes it possible to do new things like (f for follow): Source -> (f)loopback1-in|loopback1-out(f) -> Sink It will not make the source and sink run but when one of them start, all will become runnable. Or you can now better do the leak node hack that was previously used: Source -> (f)pw-record That will only start running when the source is activated by something else. With port.passive = true|false|follow there is a potential 4th case which would activate the peer but not be activated by the peer, which is not something that makes sense.
This commit is contained in:
parent
437a8d32f2
commit
118d8574c8
6 changed files with 90 additions and 28 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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 ||
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue