From b733adb503407efffe249bfad86624fb7bdb25be Mon Sep 17 00:00:00 2001
From: "Ryan C. Gordon" <[EMAIL REDACTED]>
Date: Mon, 16 Oct 2023 20:17:04 -0400
Subject: [PATCH] audio: Fix device refcounting vs ProvidesOwnCallbackThread
backends.
---
src/audio/SDL_audio.c | 8 ++++----
src/audio/SDL_sysaudio.h | 3 +++
src/audio/emscripten/SDL_emscriptenaudio.c | 2 ++
src/audio/haiku/SDL_haikuaudio.cc | 2 ++
src/audio/jack/SDL_jackaudio.c | 2 ++
5 files changed, 13 insertions(+), 4 deletions(-)
diff --git a/src/audio/SDL_audio.c b/src/audio/SDL_audio.c
index 18b5f533f283..331e57c7ee8b 100644
--- a/src/audio/SDL_audio.c
+++ b/src/audio/SDL_audio.c
@@ -352,7 +352,7 @@ static void DestroyPhysicalAudioDevice(SDL_AudioDevice *device)
}
// Don't hold the device lock when calling this, as we may destroy the device!
-static void UnrefPhysicalAudioDevice(SDL_AudioDevice *device)
+void UnrefPhysicalAudioDevice(SDL_AudioDevice *device)
{
if (SDL_AtomicDecRef(&device->refcount)) {
// take it out of the device list.
@@ -365,7 +365,7 @@ static void UnrefPhysicalAudioDevice(SDL_AudioDevice *device)
}
}
-static void RefPhysicalAudioDevice(SDL_AudioDevice *device)
+void RefPhysicalAudioDevice(SDL_AudioDevice *device)
{
SDL_AtomicIncRef(&device->refcount);
}
@@ -861,6 +861,7 @@ static void MixFloat32Audio(float *dst, const float *src, const int buffer_size)
void SDL_OutputAudioThreadSetup(SDL_AudioDevice *device)
{
SDL_assert(!device->iscapture);
+ RefPhysicalAudioDevice(device); // unref'd when the audio thread terminates (ProvidesOwnCallbackThread implementations should call SDL_AudioThreadFinalize appropriately).
current_audio.impl.ThreadInit(device);
}
@@ -1010,6 +1011,7 @@ static int SDLCALL OutputAudioThread(void *devicep) // thread entry point
void SDL_CaptureAudioThreadSetup(SDL_AudioDevice *device)
{
SDL_assert(device->iscapture);
+ RefPhysicalAudioDevice(device); // unref'd when the audio thread terminates (ProvidesOwnCallbackThread implementations should call SDL_AudioThreadFinalize appropriately).
current_audio.impl.ThreadInit(device);
}
@@ -1495,8 +1497,6 @@ static int OpenPhysicalAudioDevice(SDL_AudioDevice *device, const SDL_AudioSpec
}
}
- RefPhysicalAudioDevice(device); // unref'd when the audio thread terminates (ProvidesOwnCallbackThread implementations should call SDL_AudioThreadFinalize appropriately).
-
return 0;
}
diff --git a/src/audio/SDL_sysaudio.h b/src/audio/SDL_sysaudio.h
index 6dd7a9f2b72f..c33ac9ce08dc 100644
--- a/src/audio/SDL_sysaudio.h
+++ b/src/audio/SDL_sysaudio.h
@@ -106,6 +106,9 @@ extern void SDL_UpdatedAudioDeviceFormat(SDL_AudioDevice *device);
// Backends can call this to get a standardized name for a thread to power a specific audio device.
extern char *SDL_GetAudioThreadName(SDL_AudioDevice *device, char *buf, size_t buflen);
+// Backends can call these to change a device's refcount.
+extern void RefPhysicalAudioDevice(SDL_AudioDevice *device);
+extern void UnrefPhysicalAudioDevice(SDL_AudioDevice *device);
// These functions are the heart of the audio threads. Backends can call them directly if they aren't using the SDL-provided thread.
extern void SDL_OutputAudioThreadSetup(SDL_AudioDevice *device);
diff --git a/src/audio/emscripten/SDL_emscriptenaudio.c b/src/audio/emscripten/SDL_emscriptenaudio.c
index b8740a887529..d2ee78b9dd9f 100644
--- a/src/audio/emscripten/SDL_emscriptenaudio.c
+++ b/src/audio/emscripten/SDL_emscriptenaudio.c
@@ -181,6 +181,8 @@ static int EMSCRIPTENAUDIO_OpenDevice(SDL_AudioDevice *device)
return SDL_OutOfMemory();
}
+ RefPhysicalAudioDevice(device); // CloseDevice will always unref this through SDL_AudioThreadFinalize, even if we failed to start the thread.
+
// limit to native freq
device->spec.freq = EM_ASM_INT({ return Module['SDL3'].audioContext.sampleRate; });
diff --git a/src/audio/haiku/SDL_haikuaudio.cc b/src/audio/haiku/SDL_haikuaudio.cc
index 15204362d6be..5d74462672b2 100644
--- a/src/audio/haiku/SDL_haikuaudio.cc
+++ b/src/audio/haiku/SDL_haikuaudio.cc
@@ -112,6 +112,8 @@ static int HAIKUAUDIO_OpenDevice(SDL_AudioDevice *device)
}
SDL_zerop(device->hidden);
+ RefPhysicalAudioDevice(device); // CloseDevice will always unref this through SDL_AudioThreadFinalize, even if we failed to start the thread.
+
// Parse the audio format and fill the Be raw audio format
media_raw_audio_format format;
SDL_zero(format);
diff --git a/src/audio/jack/SDL_jackaudio.c b/src/audio/jack/SDL_jackaudio.c
index ba19621ef586..4f0691bc3dde 100644
--- a/src/audio/jack/SDL_jackaudio.c
+++ b/src/audio/jack/SDL_jackaudio.c
@@ -300,6 +300,8 @@ static int JACK_OpenDevice(SDL_AudioDevice *device)
return SDL_OutOfMemory();
}
+ RefPhysicalAudioDevice(device); // CloseDevice will always unref this through SDL_AudioThreadFinalize, even if we failed to start the thread.
+
client = JACK_jack_client_open(GetJackAppName(), JackNoStartServer, &status, NULL);
device->hidden->client = client;
if (client == NULL) {