diff --git a/src/audio/pipewire/SDL_pipewire.c b/src/audio/pipewire/SDL_pipewire.c index d803c8d736..775c558d97 100644 --- a/src/audio/pipewire/SDL_pipewire.c +++ b/src/audio/pipewire/SDL_pipewire.c @@ -939,7 +939,21 @@ static bool PIPEWIRE_PlayDevice(SDL_AudioDevice *device, const Uint8 *buffer, in static void output_callback(void *data) { - SDL_PlaybackAudioThreadIterate((SDL_AudioDevice *)data); + SDL_AudioDevice *device = (SDL_AudioDevice *) data; + + // this callback can fire in a background thread during OpenDevice, while we're still blocking + // _with the device lock_ until the stream is ready, causing a deadlock. Write silence in this case. + if (device->hidden->stream_init_status != PW_READY_FLAG_ALL_BITS) { + int bufsize = 0; + Uint8 *buf = PIPEWIRE_GetDeviceBuf(device, &bufsize); + if (buf && bufsize) { + SDL_memset(buf, device->silence_value, bufsize); + } + PIPEWIRE_PlayDevice(device, buf, bufsize); + return; + } + + SDL_PlaybackAudioThreadIterate(device); } static void PIPEWIRE_FlushRecording(SDL_AudioDevice *device) @@ -980,7 +994,16 @@ static int PIPEWIRE_RecordDevice(SDL_AudioDevice *device, void *buffer, int bufl static void input_callback(void *data) { - SDL_RecordingAudioThreadIterate((SDL_AudioDevice *)data); + SDL_AudioDevice *device = (SDL_AudioDevice *) data; + + // this callback can fire in a background thread during OpenDevice, while we're still blocking + // _with the device lock_ until the stream is ready, causing a deadlock. Drop data in this case. + if (device->hidden->stream_init_status != PW_READY_FLAG_ALL_BITS) { + PIPEWIRE_FlushRecording(device); + return; + } + + SDL_RecordingAudioThreadIterate(device); } static void stream_add_buffer_callback(void *data, struct pw_buffer *buffer)