Issue point that pipewire itself may apply a workaround for mpv, so this may or may not be necessary for future pipewire versions. Albeit the actual issue seems to be in mpv, so let's backport the fix which appears to work properly for old 0.35.1 as well. Note that (unrelated to this issue), 0.35.1 is still a bit flaky with pipewire. If have other issues with ao=pipewire you may want to consider mpv-9999 until next release, or use ao=pulse/alsa/jack to use through pipewire meanwhile. https://gitlab.freedesktop.org/pipewire/pipewire/-/issues/3374 https://github.com/mpv-player/mpv/issues/11995 https://github.com/mpv-player/mpv/pull/11996 https://github.com/mpv-player/mpv/commit/007019a303a09b098a387f607ae149705b57dc1c From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Sun, 23 Jul 2023 09:10:55 +0200 Subject: [PATCH] ao_pipewire: for_each_sink: properly check termination condition Doing a pw_thread_loop_wait() without checking conditions is invalid. The thread loop could be signalled for other reasons and in this case the wait needs to continue. PipeWire added such additional signaling in commit 33be898130f0 ("thread-loop: signal when started"). This meant that for_each_sink would return before the callbacks have fired and session_has_sink() would incorrectly return "false", failing the initialization of ao_pipewire. Fixes #11995 --- a/audio/out/ao_pipewire.c +++ b/audio/out/ao_pipewire.c @@ -337,6 +337,11 @@ } +struct for_each_done_ctx { + struct pw_thread_loop *loop; + bool done; +}; + static const struct pw_registry_events for_each_sink_registry_events = { .version = PW_VERSION_REGISTRY_EVENTS, .global = for_each_sink_registry_event_global, @@ -344,8 +349,9 @@ static void for_each_sink_done(void *data, uint32_t it, int seq) { - struct pw_thread_loop *loop = data; - pw_thread_loop_signal(loop, false); + struct for_each_done_ctx *ctx = data; + ctx->done = true; + pw_thread_loop_signal(ctx->loop, false); } static const struct pw_core_events for_each_sink_core_events = { @@ -359,12 +365,16 @@ struct priv *priv = ao->priv; struct pw_registry *registry; struct spa_hook core_listener; + struct for_each_done_ctx done_ctx = { + .loop = priv->loop, + .done = false, + }; int ret = -1; pw_thread_loop_lock(priv->loop); spa_zero(core_listener); - if (pw_core_add_listener(priv->core, &core_listener, &for_each_sink_core_events, priv->loop) < 0) + if (pw_core_add_listener(priv->core, &core_listener, &for_each_sink_core_events, &done_ctx) < 0) goto unlock_loop; registry = pw_core_get_registry(priv->core, PW_VERSION_REGISTRY, 0); @@ -383,7 +393,8 @@ if (pw_registry_add_listener(registry, ®istry_listener, &for_each_sink_registry_events, &revents_ctx) < 0) goto destroy_registry; - pw_thread_loop_wait(priv->loop); + while (!done_ctx.done) + pw_thread_loop_wait(priv->loop); spa_hook_remove(®istry_listener);