SDL: pipewire: Fix possible deadlock when opening a device

From 945da099ae631edae12ddbe7b590b0bf0eb8c56c Mon Sep 17 00:00:00 2001
From: Cameron Gutman <[EMAIL REDACTED]>
Date: Sat, 22 Feb 2025 12:33:19 -0600
Subject: [PATCH] pipewire: Fix possible deadlock when opening a device

If the pipewire thread invokes output_callback() while we're still
waiting inside PIPEWIRE_OpenDevice(), we will deadlock. The pipewire
thread owns the loop lock and is blocked on the audio device lock,
which cannot be released because pw_thread_loop_wait() needs to
reacquire the loop lock before it can return and allow
PIPEWIRE_OpenDevice() to complete and release the device lock.
---
 src/audio/pipewire/SDL_pipewire.c | 9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/src/audio/pipewire/SDL_pipewire.c b/src/audio/pipewire/SDL_pipewire.c
index 40324f4f18292..e3f9439f73fed 100644
--- a/src/audio/pipewire/SDL_pipewire.c
+++ b/src/audio/pipewire/SDL_pipewire.c
@@ -44,7 +44,9 @@ enum PW_READY_FLAGS
 {
     PW_READY_FLAG_BUFFER_ADDED = 0x1,
     PW_READY_FLAG_STREAM_READY = 0x2,
-    PW_READY_FLAG_ALL_BITS = 0x3
+    PW_READY_FLAG_ALL_PREOPEN_BITS = 0x3,
+    PW_READY_FLAG_OPEN_COMPLETE = 0x4,
+    PW_READY_FLAG_ALL_BITS = 0x7
 };
 
 #define PW_ID_TO_HANDLE(x) (void *)((uintptr_t)x)
@@ -1215,12 +1217,13 @@ static bool PIPEWIRE_OpenDevice(SDL_AudioDevice *device)
         return SDL_SetError("Pipewire: Failed to start stream loop");
     }
 
-    // Wait until all init flags are set or the stream has failed.
+    // Wait until all pre-open init flags are set or the stream has failed.
     PIPEWIRE_pw_thread_loop_lock(priv->loop);
-    while (priv->stream_init_status != PW_READY_FLAG_ALL_BITS &&
+    while (priv->stream_init_status != PW_READY_FLAG_ALL_PREOPEN_BITS &&
            PIPEWIRE_pw_stream_get_state(priv->stream, NULL) != PW_STREAM_STATE_ERROR) {
         PIPEWIRE_pw_thread_loop_wait(priv->loop);
     }
+    priv->stream_init_status |= PW_READY_FLAG_OPEN_COMPLETE;
     PIPEWIRE_pw_thread_loop_unlock(priv->loop);
 
     if (PIPEWIRE_pw_stream_get_state(priv->stream, &error) == PW_STREAM_STATE_ERROR) {