From 88f20a7011fb4236a564930878f6630b2781e78a Mon Sep 17 00:00:00 2001 From: Misaki Kasumi Date: Mon, 6 May 2024 20:25:53 +0800 Subject: [PATCH] ao_pipewire: wait for draining finishes before restart ao When the stream is draining, setting stream to active has no effect. --- audio/out/ao_pipewire.c | 37 +++++++++++++++++++++++++------------ 1 file changed, 25 insertions(+), 12 deletions(-) diff --git a/audio/out/ao_pipewire.c b/audio/out/ao_pipewire.c index 7b094b3f65..1cb4b6459b 100644 --- a/audio/out/ao_pipewire.c +++ b/audio/out/ao_pipewire.c @@ -56,10 +56,11 @@ static uint64_t pw_stream_get_nsec(struct pw_stream *stream) } #endif -enum init_state { - INIT_STATE_NONE, - INIT_STATE_SUCCESS, - INIT_STATE_ERROR, +enum state { + STATE_UNINITIALIZED, + STATE_READY, + STATE_ERROR, + STATE_DRAINING, }; enum { @@ -73,7 +74,7 @@ struct priv { struct pw_core *core; struct spa_hook stream_listener; struct spa_hook core_listener; - enum init_state init_state; + enum state state; bool muted; float volume; @@ -221,6 +222,7 @@ static void on_process(void *userdata) if (eof) { pw_stream_flush(p->stream, true); ao_stop_streaming(ao); + p->state = STATE_DRAINING; } MP_TRACE(ao, "queued %d of %d samples\n", samples, nframes); @@ -238,7 +240,7 @@ static void on_param_changed(void *userdata, uint32_t id, const struct spa_pod * * As there is no proper callback for this we use the Latency param for this */ if (id == SPA_PARAM_Latency) { - p->init_state = INIT_STATE_SUCCESS; + p->state = STATE_READY; pw_thread_loop_signal(p->loop, false); } @@ -273,7 +275,7 @@ static void on_state_changed(void *userdata, enum pw_stream_state old, enum pw_s if (state == PW_STREAM_STATE_ERROR) { MP_WARN(ao, "Stream in error state, trying to reload...\n"); - p->init_state = INIT_STATE_ERROR; + p->state = STATE_ERROR; pw_thread_loop_signal(p->loop, false); ao_request_reload(ao); } @@ -328,12 +330,22 @@ static void on_control_info(void *userdata, uint32_t id, } } +static void on_drained(void *userdata) +{ + struct ao *ao = userdata; + struct priv *p = ao->priv; + + p->state = STATE_READY; + pw_thread_loop_signal(p->loop, false); +} + static const struct pw_stream_events stream_events = { .version = PW_VERSION_STREAM_EVENTS, .param_changed = on_param_changed, .process = on_process, .state_changed = on_state_changed, .control_info = on_control_info, + .drained = on_drained, }; static void uninit(struct ao *ao) @@ -559,7 +571,7 @@ error: return -1; } -static void wait_for_init_done(struct ao *ao) +static void wait_for_state_ready(struct ao *ao) { struct priv *p = ao->priv; struct timespec abstime; @@ -571,7 +583,7 @@ static void wait_for_init_done(struct ao *ao) return; } - while (p->init_state == INIT_STATE_NONE) { + while (p->state != STATE_READY && p->state != STATE_ERROR) { r = pw_thread_loop_timed_wait_full(p->loop, &abstime); if (r < 0) { MP_WARN(ao, "Could not wait for initialization: %s\n", spa_strerror(r)); @@ -679,11 +691,11 @@ static int init(struct ao *ao) goto error; } - wait_for_init_done(ao); + wait_for_state_ready(ao); pw_thread_loop_unlock(p->loop); - if (p->init_state == INIT_STATE_ERROR) + if (p->state == STATE_ERROR) goto error; return 0; @@ -708,6 +720,7 @@ static void start(struct ao *ao) { struct priv *p = ao->priv; pw_thread_loop_lock(p->loop); + wait_for_state_ready(ao); pw_stream_set_active(p->stream, true); pw_thread_loop_unlock(p->loop); } @@ -924,7 +937,7 @@ const struct ao_driver audio_out_pipewire = { { .loop = NULL, .stream = NULL, - .init_state = INIT_STATE_NONE, + .state = STATE_UNINITIALIZED, .options.buffer_msec = 0, .options.volume_mode = VOLUME_MODE_CHANNEL, },