From ca91b368c1b23df6c97fab66def75a07f7d47786 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 12 Mar 2026 14:40:04 +0100 Subject: [PATCH] impl-port: make a follow-suspend port mode It's like the follow mode but when you link 2 follow-suspend ports together, they will activate eachother. This is to make Source -> Sink links work. --- src/modules/module-scheduler-v1.c | 27 ++++++++++++++++++++------- src/pipewire/impl-node.c | 6 +++++- src/pipewire/impl-port.c | 1 - src/pipewire/private.h | 9 +++++---- 4 files changed, 30 insertions(+), 13 deletions(-) diff --git a/src/modules/module-scheduler-v1.c b/src/modules/module-scheduler-v1.c index f8575f718..9a8fc13a0 100644 --- a/src/modules/module-scheduler-v1.c +++ b/src/modules/module-scheduler-v1.c @@ -188,12 +188,25 @@ static void make_runnable(struct pw_context *context, struct pw_impl_node *node) * Only consider ports that have a PASSIVE_MODE_FALSE link. * All other port modes don't make A and B runnable. * - * A -> B A + B both set to running - * A -> (p) B A + B both set to running - * A -> (f) B A + B both set to running - * A (p) -> (*) B A + B no change - * A (f) -> (*) B A + B no change + * A -> B A + B both set to running + * A -> (p) B A + B both set to running + * A -> (f) B A + B both set to running + * A (p) -> (*) B A + B no change + * A (f) -> (*) B A + B no change + * A (fs) -> (*) B A + B no change + * A (fs) -> (fs) B A + B both set to running */ +static inline bool may_follow(struct pw_impl_port *p, struct pw_impl_port *other) +{ + pw_log_warn("%s %s %d %d", p->node->name, other->node->name, + p->passive_mode, other->passive_mode); + if (p->passive_mode == PASSIVE_MODE_FALSE) + return true; + if (p->passive_mode == PASSIVE_MODE_FOLLOW_SUSPEND && + other->passive_mode == PASSIVE_MODE_FOLLOW_SUSPEND) + return true; + return false; +} static void check_runnable(struct pw_context *context, struct pw_impl_node *node) { struct pw_impl_port *p; @@ -213,7 +226,7 @@ static void check_runnable(struct pw_context *context, struct pw_impl_node *node * with a non-passive link */ pw_log_trace(" out-port %p: link %p passive:%d prepared:%d active:%d", p, l, p->passive_mode, l->prepared, n->active); - if (!n->active || p->passive_mode != PASSIVE_MODE_FALSE) + if (!n->active || !may_follow(p, l->input)) continue; /* explicitly prepare the link in case it was suspended */ pw_impl_link_prepare(l); @@ -228,7 +241,7 @@ static void check_runnable(struct pw_context *context, struct pw_impl_node *node n = l->output->node; pw_log_trace(" in-port %p: link %p passive:%d prepared:%d active:%d", p, l, p->passive_mode, l->prepared, n->active); - if (!n->active || p->passive_mode != PASSIVE_MODE_FALSE) + if (!n->active || !may_follow(p, l->output)) continue; pw_impl_link_prepare(l); if (!l->prepared) diff --git a/src/pipewire/impl-node.c b/src/pipewire/impl-node.c index 91b0295d4..ac362cc68 100644 --- a/src/pipewire/impl-node.c +++ b/src/pipewire/impl-node.c @@ -1264,7 +1264,7 @@ static void check_properties(struct pw_impl_node *node) if ((str = pw_properties_get(node->properties, PW_KEY_NODE_PASSIVE)) == NULL) { if ((str = pw_properties_get(node->properties, PW_KEY_MEDIA_CLASS)) != NULL && (strstr(str, "/Sink") != NULL || strstr(str, "/Source") != NULL)) - str = "follow"; + str = "follow-suspend"; else str = "false"; } @@ -1285,6 +1285,10 @@ static void check_properties(struct pw_impl_node *node) node->passive_mode[SPA_DIRECTION_INPUT] = PASSIVE_MODE_FOLLOW; node->passive_mode[SPA_DIRECTION_OUTPUT] = PASSIVE_MODE_FOLLOW; } + else if (spa_streq(str, "follow-suspend")) { + node->passive_mode[SPA_DIRECTION_INPUT] = PASSIVE_MODE_FOLLOW_SUSPEND; + node->passive_mode[SPA_DIRECTION_OUTPUT] = PASSIVE_MODE_FOLLOW_SUSPEND; + } else { node->passive_mode[SPA_DIRECTION_OUTPUT] = node->passive_mode[SPA_DIRECTION_INPUT] = diff --git a/src/pipewire/impl-port.c b/src/pipewire/impl-port.c index 074a93d12..1e1d023b9 100644 --- a/src/pipewire/impl-port.c +++ b/src/pipewire/impl-port.c @@ -537,7 +537,6 @@ static int check_properties(struct pw_impl_port *port) &schedule_tee_node; } - if ((str = pw_properties_get(port->properties, PW_KEY_PORT_PASSIVE)) == NULL) { /* inherit passive state from parent node */ port->passive_mode = node->passive_mode[port->direction]; diff --git a/src/pipewire/private.h b/src/pipewire/private.h index 897f990d9..27eaaeb96 100644 --- a/src/pipewire/private.h +++ b/src/pipewire/private.h @@ -785,10 +785,11 @@ struct pw_impl_node { unsigned int exclusive:1; /**< ports can only be linked once */ unsigned int reliable:1; /**< ports need reliable tee */ -#define PASSIVE_MODE_FALSE 0 -#define PASSIVE_MODE_TRUE 1 -#define PASSIVE_MODE_FOLLOW 2 - bool passive_mode[2]; /**< node input links should be passive */ +#define PASSIVE_MODE_FALSE 0 +#define PASSIVE_MODE_TRUE 1 +#define PASSIVE_MODE_FOLLOW 2 +#define PASSIVE_MODE_FOLLOW_SUSPEND 3 + int passive_mode[2]; /**< node input links should be passive */ uint32_t transport; /**< latest transport request */