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
This commit is contained in:
Wim Taymans 2024-11-15 16:09:36 +01:00
parent 3b51dbba1c
commit 1084cc24b6
4 changed files with 8 additions and 2 deletions

View file

@ -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;

View file

@ -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;

View file

@ -3575,9 +3575,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);
@ -3749,6 +3748,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) {

View file

@ -134,6 +134,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;