sdl12-compat: first shot at fixing the SDL_OpenAudio and SDL_LoadWAV_RW FIXME()s:

From 3895550264a1c82b398cb4f04072adf884fa4bd5 Mon Sep 17 00:00:00 2001
From: Ozkan Sezer <[EMAIL REDACTED]>
Date: Wed, 3 Mar 2021 23:00:10 +0300
Subject: [PATCH] first shot at fixing the SDL_OpenAudio and SDL_LoadWAV_RW
 FIXME()s:

* SDL1.2 doesn't support AUDIO_S32 or AUDIO_F32 formats:
  - SDL_LoadWAV_RW: Reject WAV files with such formats.
  - Always pass NULL as the 'obtained' pointer to SDL_OpenAudio().
    If a field of the spec is 0, assign some reasonable default to
    it.
* Library is leaking AudioCallbackWrapper data:
  - Store the data in a global var, change SDL_CloseAudio to not
    be a passthrough, free the data from SDL_CloseAudio.
---
 src/SDL12_compat.c | 48 ++++++++++++++++++++++++++++++++--------------
 src/SDL20_syms.h   |  4 +---
 2 files changed, 35 insertions(+), 17 deletions(-)

diff --git a/src/SDL12_compat.c b/src/SDL12_compat.c
index ab09646..6be21d2 100644
--- a/src/SDL12_compat.c
+++ b/src/SDL12_compat.c
@@ -4441,7 +4441,12 @@ SDL_LoadWAV_RW(SDL12_RWops *rwops12, int freerwops12,
 {
     SDL_RWops *rwops20 = RWops12to20(rwops12);
     SDL_AudioSpec *retval = SDL20_LoadWAV_RW(rwops20, freerwops12, spec, buf, len);
-    FIXME("deal with non-1.2 formats, like float32");
+    if (retval && retval->format & 0x20) {
+        SDL20_SetError("Unsupported 32-bit PCM data format");
+        SDL20_FreeWAV(*buf);
+        *buf = NULL;
+        retval = NULL;
+    }
     if (!freerwops12)  /* free our wrapper if SDL2 didn't close it. */
         SDL20_FreeRW(rwops20);
     return retval;
@@ -4454,11 +4459,13 @@ typedef struct
     Uint8 silence;
 } AudioCallbackWrapperData;
 
+static AudioCallbackWrapperData *audio_cbdata = NULL;
+
 static void SDLCALL
 AudioCallbackWrapper(void *userdata, Uint8 *stream, int len)
 {
     AudioCallbackWrapperData *data = (AudioCallbackWrapperData *) userdata;
-    SDL_memset(stream, data->silence, len);  // SDL2 doesn't clear the stream before calling in here, but 1.2 expects it.
+    SDL_memset(stream, data->silence, len);  /* SDL2 doesn't clear the stream before calling in here, but 1.2 expects it. */
     data->app_callback(data->app_userdata, stream, len);
 }
 
@@ -4469,7 +4476,7 @@ SDL_OpenAudio(SDL_AudioSpec *want, SDL_AudioSpec *obtained)
     AudioCallbackWrapperData *data;
     int retval;
 
-    // SDL2 uses a NULL callback to mean "we play to use SDL_QueueAudio()"
+    /* SDL2 uses a NULL callback to mean "we play to use SDL_QueueAudio()" */
     if (want && (want->callback == NULL)) {
         return SDL20_SetError("Callback can't be NULL");
     }
@@ -4482,28 +4489,41 @@ SDL_OpenAudio(SDL_AudioSpec *want, SDL_AudioSpec *obtained)
     data->app_userdata = want->userdata;
     want->callback = AudioCallbackWrapper;
     want->userdata = data;
-
-    FIXME("Don't allow int32 or float32");
-    FIXME("clamp output to mono/stereo");
-    retval = SDL20_OpenAudio(want, obtained);
+    /* to avoid receiving a possible incompatible configuration
+     * from SDL2, always pass NULL as the 'obtained' pointer.  */
+    if (!want->format) {
+        want->format = AUDIO_S16SYS;
+    }
+    if (!want->freq) {
+        want->freq = 22050;
+    }
+    if (!want->channels) {
+        want->channels = 2;
+    }
+    retval = SDL20_OpenAudio(want, NULL);
     want->callback = data->app_callback;
     want->userdata = data->app_userdata;
     if (retval < 0) {
         SDL20_free(data);
     } else {
-        FIXME("memory leak on callback data");
-        if (!obtained) {
-            data->silence = want->silence;
-        } else {
-            data->silence = obtained->silence;
-            obtained->callback = data->app_callback;
-            obtained->userdata = data->app_userdata;
+        data->silence = want->silence;
+        audio_cbdata = data;
+        if (obtained) {
+            SDL_memcpy(obtained, want, sizeof (SDL_AudioSpec));
         }
     }
 
     return retval;
 }
 
+DECLSPEC void SDLCALL
+SDL_CloseAudio(void)
+{
+    SDL20_CloseAudio();
+    SDL20_free(audio_cbdata);
+    audio_cbdata = NULL;
+}
+
 /* !!! FIXME: these are just stubs for now, but Sam thinks that maybe these
 were added at Loki for Heavy Gear 2's UI. They just make GL calls. */
 DECLSPEC void SDLCALL
diff --git a/src/SDL20_syms.h b/src/SDL20_syms.h
index 1f1359a..8204724 100644
--- a/src/SDL20_syms.h
+++ b/src/SDL20_syms.h
@@ -149,10 +149,8 @@ SDL20_SYM(SDL_Thread *,CreateThread,(SDL_ThreadFunction a, const char *b, void *
 #else
 SDL20_SYM(SDL_Thread *,CreateThread,(SDL_ThreadFunction a, const char *b, void *c),(a,b,c),return)
 #endif
-
 SDL20_SYM(unsigned long,GetThreadID,(SDL_Thread *a),(a),return)
 SDL20_SYM(unsigned long,ThreadID,(void),(),return)
-
 SDL20_SYM_PASSTHROUGH(void,WaitThread,(SDL_Thread *a, int *b),(a,b),)
 SDL20_SYM_PASSTHROUGH(SDL_mutex*,CreateMutex,(void),(),return)
 SDL20_SYM(int,LockMutex,(SDL_mutex *a),(a),return)
@@ -174,6 +172,7 @@ SDL20_SYM_PASSTHROUGH(int,CondWaitTimeout,(SDL_cond *a, SDL_mutex *b, Uint32 c),
 
 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),(),)
 SDL20_SYM_PASSTHROUGH(SDL_AudioStatus,GetAudioStatus,(void),(),return)
 SDL20_SYM_PASSTHROUGH(void,PauseAudio,(int a),(a),)
 SDL20_SYM_PASSTHROUGH(void,FreeWAV,(Uint8 *a),(a),)
@@ -182,7 +181,6 @@ SDL20_SYM_PASSTHROUGH(int,ConvertAudio,(SDL_AudioCVT *a),(a),return)
 SDL20_SYM_PASSTHROUGH(void,MixAudio,(Uint8 *a, const Uint8 *b, Uint32 c, int d),(a,b,c,d),)
 SDL20_SYM_PASSTHROUGH(void,LockAudio,(void),(),)
 SDL20_SYM_PASSTHROUGH(void,UnlockAudio,(void),(),)
-SDL20_SYM_PASSTHROUGH(void,CloseAudio,(void),(),)
 
 SDL20_SYM_PASSTHROUGH(void*,LoadObject,(const char *a),(a),return)
 SDL20_SYM_PASSTHROUGH(void*,LoadFunction,(void *a, const char *b),(a,b),return)