From ea08a24b3f5eba381c0ce962914c76106116eeaa Mon Sep 17 00:00:00 2001
From: David Gow <[EMAIL REDACTED]>
Date: Tue, 22 Jun 2021 20:53:03 +0800
Subject: [PATCH] SDL_PauseAudio should work within the callback
In SDL 1.2, SDL_PauseAudio() works from within the audio callback,
whereas currently in sdl12-compat, it deadlocks due to SDL_LockAudio()
being called.
Move the callback paused state out of the callback structure (whose
allocation is protected by SDL_LockAudio()) and into a separate atomic
variable. SDL_PauseAudio() can then simply set that value.
This fixes some SDL 1.2 Ren'py games, which will deadlock somewhat
randomly either at startup or when a new piece of music plays, due to
SDL_PauseAudio() being called from within the callback.
---
src/SDL12_compat.c | 15 +++++----------
src/SDL20_syms.h | 3 +++
2 files changed, 8 insertions(+), 10 deletions(-)
diff --git a/src/SDL12_compat.c b/src/SDL12_compat.c
index 8daf96e..f13f26d 100644
--- a/src/SDL12_compat.c
+++ b/src/SDL12_compat.c
@@ -6086,7 +6086,6 @@ typedef struct
SDL_AudioSpec device_format;
SDL_bool app_callback_opened;
- SDL_bool app_callback_paused;
SDL_AudioSpec app_callback_format;
SDL_AudioStream *app_callback_stream;
@@ -6107,7 +6106,7 @@ typedef struct
} AudioCallbackWrapperData;
static AudioCallbackWrapperData *audio_cbdata = NULL;
-
+static SDL_atomic_t audio_callback_paused;
static void
@@ -6721,7 +6720,7 @@ AudioCallbackWrapper(void *userdata, Uint8 *stream, int len)
AudioCallbackWrapperData *data = (AudioCallbackWrapperData *) userdata;
SDL_bool must_mix = SDL_FALSE;
- if (data->app_callback_opened && !data->app_callback_paused) {
+ if (data->app_callback_opened && !SDL20_AtomicGet(&audio_callback_paused)) {
while (SDL20_AudioStreamAvailable(data->app_callback_stream) < len) {
SDL20_memset(data->mix_buffer, data->app_callback_format.silence, data->app_callback_format.size); /* SDL2 doesn't clear the stream before calling in here, but 1.2 expects it. */
data->app_callback_format.callback(data->app_callback_format.userdata, data->mix_buffer, data->app_callback_format.size);
@@ -6903,7 +6902,7 @@ SDL_OpenAudio(SDL_AudioSpec *want, SDL_AudioSpec *obtained)
SDL20_memcpy(&audio_cbdata->app_callback_format, want, sizeof (SDL_AudioSpec));
audio_cbdata->app_callback_opened = SDL_TRUE;
- audio_cbdata->app_callback_paused = SDL_TRUE; /* app callback always starts paused after open. */
+ SDL20_AtomicSet(&audio_callback_paused, SDL_TRUE); /* app callback always starts paused after open. */
FIXME("Cleanup from failures in here");
SDL_assert(audio_cbdata->app_callback_stream == NULL);
@@ -6921,11 +6920,7 @@ SDL_OpenAudio(SDL_AudioSpec *want, SDL_AudioSpec *obtained)
DECLSPEC void SDLCALL
SDL_PauseAudio(int pause_on)
{
- SDL20_LockAudio();
- if (audio_cbdata && audio_cbdata->app_callback_opened) {
- audio_cbdata->app_callback_paused = pause_on ? SDL_TRUE : SDL_FALSE;
- }
- SDL20_UnlockAudio();
+ SDL20_AtomicSet(&audio_callback_paused, pause_on ? SDL_TRUE : SDL_FALSE);
}
DECLSPEC SDL_AudioStatus SDLCALL
@@ -6934,7 +6929,7 @@ SDL_GetAudioStatus(void)
SDL_AudioStatus retval = SDL_AUDIO_STOPPED;
SDL20_LockAudio();
if (audio_cbdata && audio_cbdata->app_callback_opened) {
- retval = audio_cbdata->app_callback_paused ? SDL_AUDIO_PAUSED : SDL_AUDIO_PLAYING;
+ retval = SDL20_AtomicGet(&audio_callback_paused) ? SDL_AUDIO_PAUSED : SDL_AUDIO_PLAYING;
}
SDL20_UnlockAudio();
return retval;
diff --git a/src/SDL20_syms.h b/src/SDL20_syms.h
index baf6a02..0937d8a 100644
--- a/src/SDL20_syms.h
+++ b/src/SDL20_syms.h
@@ -188,6 +188,9 @@ SDL20_SYM_PASSTHROUGH(int,CondBroadcast,(SDL_cond *a),(a),return)
SDL20_SYM_PASSTHROUGH(int,CondWait,(SDL_cond *a, SDL_mutex *b),(a,b),return)
SDL20_SYM_PASSTHROUGH(int,CondWaitTimeout,(SDL_cond *a, SDL_mutex *b, Uint32 c),(a,b,c),return)
+SDL20_SYM(int,AtomicGet,(SDL_atomic_t *a),(a),return)
+SDL20_SYM(void,AtomicSet,(SDL_atomic_t *a, int b),(a,b),)
+
SDL20_SYM(SDL_AudioSpec *,LoadWAV_RW,(SDL_RWops *a, int b, SDL_AudioSpec *c, Uint8 **d, Uint32 *e),(a,b,c,d,e),return)
SDL20_SYM(int,OpenAudio,(SDL_AudioSpec *a, SDL_AudioSpec *b),(a,b),return)
SDL20_SYM(void,CloseAudio,(void),(),)