From 02c332bb7836ac6d5235accc85f29e698a9a5950 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 15 Nov 2024 16:09:36 +0100 Subject: [PATCH] alsa: handle the case where the driver is destroyed When the driver node is destroyed (like when unplugging the cable) it will drop/pause all of the follower ALSA nodes. This is something that happens internally because of how the ALSA nodes work together, on the PipeWire level, the nodes are still running and they will just be moved to another driver. The problem is that nothing will then start the nodes again after moving it to the new driver. Fix this by keeping track of the desired target state of the ALSA node and restoring that state when we detect that we are paused when moved to a new driver. Fixes #4401 --- spa/plugins/alsa/alsa-pcm-sink.c | 2 ++ spa/plugins/alsa/alsa-pcm-source.c | 2 ++ spa/plugins/alsa/alsa-pcm.c | 5 +++-- spa/plugins/alsa/alsa-pcm.h | 1 + 4 files changed, 8 insertions(+), 2 deletions(-) diff --git a/spa/plugins/alsa/alsa-pcm-sink.c b/spa/plugins/alsa/alsa-pcm-sink.c index 2d5951227..49e6ee557 100644 --- a/spa/plugins/alsa/alsa-pcm-sink.c +++ b/spa/plugins/alsa/alsa-pcm-sink.c @@ -326,11 +326,13 @@ static int impl_node_send_command(void *object, const struct spa_command *comman if (this->n_buffers == 0) return -EIO; + this->want_started = true; if ((res = spa_alsa_start(this)) < 0) return res; break; case SPA_NODE_COMMAND_Suspend: case SPA_NODE_COMMAND_Pause: + this->want_started = false; if ((res = spa_alsa_pause(this)) < 0) return res; break; diff --git a/spa/plugins/alsa/alsa-pcm-source.c b/spa/plugins/alsa/alsa-pcm-source.c index 0a8ffec49..5ee9a4c99 100644 --- a/spa/plugins/alsa/alsa-pcm-source.c +++ b/spa/plugins/alsa/alsa-pcm-source.c @@ -292,11 +292,13 @@ static int impl_node_send_command(void *object, const struct spa_command *comman if (this->n_buffers == 0) return -EIO; + this->want_started = true; if ((res = spa_alsa_start(this)) < 0) return res; break; case SPA_NODE_COMMAND_Pause: case SPA_NODE_COMMAND_Suspend: + this->want_started = false; if ((res = spa_alsa_pause(this)) < 0) return res; break; diff --git a/spa/plugins/alsa/alsa-pcm.c b/spa/plugins/alsa/alsa-pcm.c index eb3972042..fbd700512 100644 --- a/spa/plugins/alsa/alsa-pcm.c +++ b/spa/plugins/alsa/alsa-pcm.c @@ -3505,9 +3505,8 @@ static int do_state_sync(struct spa_loop *loop, bool async, uint32_t seq, rt->driver = state->driver; spa_log_debug(state->log, "state:%p -> driver:%p", state, state->driver); - if(state->linked && state->matching) { + if(state->linked && state->matching) try_unlink(state); - } } if (state->following) { remove_sources(state); @@ -3679,6 +3678,8 @@ int spa_alsa_reassign_follower(struct state *state) setup_matching(state); if (state->started) spa_loop_invoke(state->data_loop, do_state_sync, 0, NULL, 0, true, state); + else if (state->want_started) + spa_alsa_start(state); freewheel = pos != NULL && SPA_FLAG_IS_SET(pos->clock.flags, SPA_IO_CLOCK_FLAG_FREEWHEEL); if (state->freewheel != freewheel) { diff --git a/spa/plugins/alsa/alsa-pcm.h b/spa/plugins/alsa/alsa-pcm.h index bca62ece8..3dc1ec9d1 100644 --- a/spa/plugins/alsa/alsa-pcm.h +++ b/spa/plugins/alsa/alsa-pcm.h @@ -133,6 +133,7 @@ struct state { unsigned int opened:1; unsigned int prepared:1; unsigned int started:1; + unsigned int want_started:1; snd_pcm_t *hndl; bool have_format;