SDL_mixer: let Mix_Quit() unload libsndfile

From 1d268c880f757a05e5e887cc53a68fdf268101e4 Mon Sep 17 00:00:00 2001
From: Fabian Greffrath <[EMAIL REDACTED]>
Date: Tue, 28 Feb 2023 17:26:20 +0100
Subject: [PATCH] let Mix_Quit() unload libsndfile

---
 src/codecs/load_sndfile.c | 33 +++++++++++++++++++++++++++------
 src/codecs/load_sndfile.h |  2 ++
 src/mixer.c               |  1 +
 3 files changed, 30 insertions(+), 6 deletions(-)

diff --git a/src/codecs/load_sndfile.c b/src/codecs/load_sndfile.c
index 0b53d453..d4dfed2f 100644
--- a/src/codecs/load_sndfile.c
+++ b/src/codecs/load_sndfile.c
@@ -40,15 +40,14 @@ static int (*SF_sf_close) (SNDFILE *sndfile);
 static sf_count_t (*SF_sf_readf_short) (SNDFILE *sndfile, short *ptr, sf_count_t frames);
 static const char* (*SF_sf_strerror) (SNDFILE *sndfile);
 
+static int SNDFILE_loaded;
+static void *SNDFILE_lib;
+
 static int SNDFILE_init (void)
 {
-    static int SNDFILE_loaded;
-
     if (SNDFILE_loaded == 0)
     {
 #ifdef SNDFILE_DYNAMIC
-        static void *SNDFILE_lib;
-
         SNDFILE_lib = SDL_LoadObject(SNDFILE_DYNAMIC);
         if (SNDFILE_lib == NULL) {
             return -1;
@@ -80,6 +79,21 @@ static int SNDFILE_init (void)
     return 0;
 }
 
+void SNDFILE_uninit (void)
+{
+    if (SNDFILE_lib != NULL) {
+        SDL_UnloadObject(SNDFILE_lib);
+        SNDFILE_lib = NULL;
+
+        SF_sf_open_virtual = NULL;
+        SF_sf_close = NULL;
+        SF_sf_readf_short = NULL;
+        SF_sf_strerror = NULL;
+
+        SNDFILE_loaded = 0;
+    }
+}
+
 static sf_count_t sfvio_size(void *user_data)
 {
     SDL_RWops *RWops = user_data;
@@ -135,8 +149,10 @@ SDL_AudioSpec *Mix_LoadSndFile_RW (SDL_RWops *src, int freesrc,
     *audio_len = 0;
     SDL_memset(spec, 0, sizeof(*spec));
 
-    if (SNDFILE_init() != 0) {
-        goto done;
+    if (SNDFILE_loaded == 0) {
+        if (SNDFILE_init() != 0) {
+            goto done;
+        }
     }
 
     SDL_memset(&sfinfo, 0, sizeof(sfinfo));
@@ -205,6 +221,11 @@ SDL_AudioSpec *Mix_LoadSndFile_RW (SDL_RWops *src, int freesrc,
     return NULL;
 }
 
+void SNDFILE_uninit (void)
+{
+    // no-op
+}
+
 #endif
 
 /* vi: set ts=4 sw=4 expandtab: */
diff --git a/src/codecs/load_sndfile.h b/src/codecs/load_sndfile.h
index 6f5e6020..2f12e53e 100644
--- a/src/codecs/load_sndfile.h
+++ b/src/codecs/load_sndfile.h
@@ -34,6 +34,8 @@
 SDL_AudioSpec *Mix_LoadSndFile_RW (SDL_RWops *src, int freesrc,
         SDL_AudioSpec *spec, Uint8 **audio_buf, Uint32 *audio_len);
 
+void SNDFILE_uninit (void);
+
 #endif
 
 /* vi: set ts=4 sw=4 expandtab: */
diff --git a/src/mixer.c b/src/mixer.c
index 0af6ed7a..d11377f8 100644
--- a/src/mixer.c
+++ b/src/mixer.c
@@ -282,6 +282,7 @@ int Mix_Init(int flags)
 void Mix_Quit(void)
 {
     unload_music();
+    SNDFILE_uninit();
 }
 
 static int _Mix_remove_all_effects(int channel, effect_info **e);