From 32e4553a053a674352bef3af088ecc322002eb92 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 18 Jul 2024 13:34:59 +0200 Subject: [PATCH] impl-node: always INACTIVATE when stopping A remote node is prepared when the Start command sync reply has been received. If we however quickly switch from active to inactive, the pending reply is cancelled but the remote node will have set the FINISHED status and will be ready to be scheduled. Make it so that we always set the INACTIVE status when the node is canceled and unprepared, even if we didn't get the reply and the node was not prepared. Fixes #4122 --- src/pipewire/impl-node.c | 16 +++++++++------- src/pipewire/private.h | 2 ++ 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/pipewire/impl-node.c b/src/pipewire/impl-node.c index 5845aa71c..9df27ab75 100644 --- a/src/pipewire/impl-node.c +++ b/src/pipewire/impl-node.c @@ -177,7 +177,8 @@ do_node_prepare(struct spa_loop *loop, bool async, uint32_t seq, uint64_t dummy; int res; - pw_log_trace("%p: prepare %d remote:%d", this, this->rt.prepared, this->remote); + pw_log_trace("%p: prepare %d remote:%d exported:%d", this, this->rt.prepared, + this->remote, this->exported); if (this->rt.prepared) return 0; @@ -216,10 +217,8 @@ do_node_unprepare(struct spa_loop *loop, bool async, uint32_t seq, int old_state; uint64_t trigger = 0; - pw_log_trace("%p: unprepare %d remote:%d", this, this->rt.prepared, this->remote); - - if (!this->rt.prepared) - return 0; + pw_log_trace("%p: unprepare %d remote:%d exported:%d", this, this->rt.prepared, + this->remote, this->exported); if (!this->exported) { /* We mark ourself as finished now, this will avoid going further into the process loop @@ -227,9 +226,12 @@ do_node_unprepare(struct spa_loop *loop, bool async, uint32_t seq, * If we were supposed to be scheduled make sure we continue the graph for the peers we * were supposed to trigger */ old_state = SPA_ATOMIC_XCHG(this->rt.target.activation->status, PW_NODE_ACTIVATION_INACTIVE); - if (old_state != PW_NODE_ACTIVATION_FINISHED) + if (PW_NODE_ACTIVATION_PENDING_TRIGGER(old_state)) trigger = get_time_ns(this->rt.target.system); } + if (!this->rt.prepared) + return 0; + if (!this->remote) spa_loop_remove_source(loop, &this->source); @@ -861,7 +863,7 @@ do_remove_target(struct spa_loop *loop, if (node->rt.prepared) { int old_state = SPA_ATOMIC_LOAD(node->rt.target.activation->status); uint64_t trigger = 0; - if (old_state != PW_NODE_ACTIVATION_FINISHED) + if (PW_NODE_ACTIVATION_PENDING_TRIGGER(old_state)) trigger = get_time_ns(node->rt.target.system); deactivate_target(node, t, trigger); } diff --git a/src/pipewire/private.h b/src/pipewire/private.h index dd8200649..d40c3994e 100644 --- a/src/pipewire/private.h +++ b/src/pipewire/private.h @@ -563,6 +563,8 @@ static inline void copy_target(struct pw_node_target *dst, const struct pw_node_ */ #define PW_VERSION_NODE_ACTIVATION 1 +#define PW_NODE_ACTIVATION_PENDING_TRIGGER(status) ((status) <= PW_NODE_ACTIVATION_AWAKE) + /* nodes start as INACTIVE, when they are ready to be scheduled, they add their * fd to the loop and change status to FINISHED. When the node shuts down, the * status is set back to INACTIVE.