Commit 19e937fc2e22c4dea5dac6a879f697ecb20f7ddb

Ryan C. Gordon 2017-01-08T14:18:03

audio: libsamplerate loading now happens once at init time.

diff --git a/src/audio/SDL_audio.c b/src/audio/SDL_audio.c
index 5773a4f..730a240 100644
--- a/src/audio/SDL_audio.c
+++ b/src/audio/SDL_audio.c
@@ -107,6 +107,72 @@ static const AudioBootStrap *const bootstrap[] = {
     NULL
 };
 
+
+#ifdef HAVE_LIBSAMPLERATE_H
+#ifdef SDL_LIBSAMPLERATE_DYNAMIC
+static void *SRC_lib = NULL;
+#endif
+SDL_bool SRC_available = SDL_FALSE;
+SRC_STATE* (*SRC_src_new)(int converter_type, int channels, int *error) = NULL;
+int (*SRC_src_process)(SRC_STATE *state, SRC_DATA *data) = NULL;
+int (*SRC_src_reset)(SRC_STATE *state) = NULL;
+SRC_STATE* (*SRC_src_delete)(SRC_STATE *state) = NULL;
+const char* (*SRC_src_strerror)(int error) = NULL;
+
+static SDL_bool
+LoadLibSampleRate(void)
+{
+    SRC_available = SDL_FALSE;
+
+    if (!SDL_GetHintBoolean("SDL_AUDIO_ALLOW_LIBRESAMPLE", SDL_TRUE)) {
+        return SDL_FALSE;
+    }
+
+#ifdef SDL_LIBSAMPLERATE_DYNAMIC
+    SDL_assert(SRC_lib == NULL);
+    SRC_lib = SDL_LoadObject(SDL_LIBSAMPLERATE_DYNAMIC);
+    if (!SRC_lib) {
+        return SDL_FALSE;
+    }
+#endif
+
+    SRC_src_new = (SRC_STATE* (*)(int converter_type, int channels, int *error))SDL_LoadFunction(state->SRC_lib, "src_new");
+    SRC_src_process = (int (*)(SRC_STATE *state, SRC_DATA *data))SDL_LoadFunction(state->SRC_lib, "src_process");
+    SRC_src_reset = (int(*)(SRC_STATE *state))SDL_LoadFunction(state->SRC_lib, "src_reset");
+    SRC_src_delete = (SRC_STATE* (*)(SRC_STATE *state))SDL_LoadFunction(state->SRC_lib, "src_delete");
+    SRC_src_strerror = (const char* (*)(int error))SDL_LoadFunction(state->SRC_lib, "src_strerror");
+
+    if (!SRC_src_new || !SRC_src_process || !SRC_src_reset || !SRC_src_delete || !SRC_src_strerror) {
+        #ifdef SDL_LIBSAMPLERATE_DYNAMIC
+        SDL_UnloadObject(SRC_lib);
+        SRC_lib = NULL;
+        #endif
+        return SDL_FALSE;
+    }
+
+    SRC_available = SDL_TRUE;
+    return SDL_TRUE;
+}
+
+static void
+UnloadLibSampleRate(void)
+{
+#ifdef SDL_LIBSAMPLERATE_DYNAMIC
+    if (SRC_lib != NULL) {
+        SDL_UnloadObject(SRC_lib);
+    }
+    SRC_lib = NULL;
+#endif
+
+    SRC_available = SDL_FALSE;
+    SRC_src_new = NULL;
+    SRC_src_process = NULL;
+    SRC_src_reset = NULL;
+    SRC_src_delete = NULL;
+    SRC_src_strerror = NULL;
+}
+#endif
+
 static SDL_AudioDevice *
 get_audio_device(SDL_AudioDeviceID id)
 {
@@ -828,6 +894,10 @@ SDL_AudioInit(const char *driver_name)
     /* Make sure we have a list of devices available at startup. */
     current_audio.impl.DetectDevices();
 
+#ifdef HAVE_LIBSAMPLERATE_H
+    LoadLibSampleRate();
+#endif
+
     return 0;
 }
 
@@ -1427,6 +1497,10 @@ SDL_AudioQuit(void)
 
     SDL_zero(current_audio);
     SDL_zero(open_devices);
+
+#ifdef HAVE_LIBSAMPLERATE_H
+    UnloadLibSampleRate();
+#endif
 }
 
 #define NUM_FORMATS 10
diff --git a/src/audio/SDL_audio_c.h b/src/audio/SDL_audio_c.h
index 62467cf..2736fe4 100644
--- a/src/audio/SDL_audio_c.h
+++ b/src/audio/SDL_audio_c.h
@@ -36,6 +36,16 @@
 
 /* Functions and variables exported from SDL_audio.c for SDL_sysaudio.c */
 
+#ifdef HAVE_LIBSAMPLERATE_H
+extern SDL_bool SRC_available;
+typedef struct SRC_STATE SRC_STATE;
+extern SRC_STATE* (*SRC_src_new)(int converter_type, int channels, int *error);
+extern int (*SRC_src_process)(SRC_STATE *state, SRC_DATA *data);
+extern int (*SRC_src_reset)(SRC_STATE *state);
+extern SRC_STATE* (*SRC_src_delete)(SRC_STATE *state);
+extern const char* (*SRC_src_strerror)(int error);
+#endif
+
 /* Functions to get a list of "close" audio formats */
 extern SDL_AudioFormat SDL_FirstAudioFormat(SDL_AudioFormat format);
 extern SDL_AudioFormat SDL_NextAudioFormat(void);
diff --git a/src/audio/SDL_audiocvt.c b/src/audio/SDL_audiocvt.c
index a9d4fce..1d9f027 100644
--- a/src/audio/SDL_audiocvt.c
+++ b/src/audio/SDL_audiocvt.c
@@ -634,45 +634,10 @@ struct SDL_AudioStream
 };
 
 #ifdef HAVE_LIBSAMPLERATE_H
-
-typedef struct
-{
-    void *SRC_lib;
-
-    SRC_STATE* (*src_new)(int converter_type, int channels, int *error);
-    int (*src_process)(SRC_STATE *state, SRC_DATA *data);
-    int (*src_reset)(SRC_STATE *state);
-    SRC_STATE* (*src_delete)(SRC_STATE *state);
-    const char* (*src_strerror)(int error);
-
-    SRC_STATE *SRC_state;
-} SDL_AudioStreamResamplerState_SRC;
-
-static SDL_bool
-LoadLibSampleRate(SDL_AudioStreamResamplerState_SRC *state)
-{
-#ifdef SDL_LIBSAMPLERATE_DYNAMIC
-    state->SRC_lib = SDL_LoadObject(SDL_LIBSAMPLERATE_DYNAMIC);
-    if (!state->SRC_lib) {
-        return SDL_FALSE;
-    }
-#endif
-
-    state->src_new = (SRC_STATE* (*)(int converter_type, int channels, int *error))SDL_LoadFunction(state->SRC_lib, "src_new");
-    state->src_process = (int (*)(SRC_STATE *state, SRC_DATA *data))SDL_LoadFunction(state->SRC_lib, "src_process");
-    state->src_reset = (int(*)(SRC_STATE *state))SDL_LoadFunction(state->SRC_lib, "src_reset");
-    state->src_delete = (SRC_STATE* (*)(SRC_STATE *state))SDL_LoadFunction(state->SRC_lib, "src_delete");
-    state->src_strerror = (const char* (*)(int error))SDL_LoadFunction(state->SRC_lib, "src_strerror");
-    if (!state->src_new || !state->src_process || !state->src_reset || !state->src_delete || !state->src_strerror) {
-        return SDL_FALSE;
-    }
-    return SDL_TRUE;
-}
-
 static int
 SDL_ResampleAudioStream_SRC(SDL_AudioStream *stream, const float *inbuf, const int inbuflen, float *outbuf, const int outbuflen)
 {
-    SDL_AudioStreamResamplerState_SRC *state = (SDL_AudioStreamResamplerState_SRC*)stream->resampler_state;
+    SRC_STATE *state = (SRC_STATE *)stream->resampler_state;
     SRC_DATA data;
     int result;
 
@@ -686,9 +651,9 @@ SDL_ResampleAudioStream_SRC(SDL_AudioStream *stream, const float *inbuf, const i
     data.end_of_input = 0;
     data.src_ratio = stream->rate_incr;
 
-    result = state->src_process(state->SRC_state, &data);
+    result = SRC_src_process(state, &data);
     if (result != 0) {
-        SDL_SetError("src_process() failed: %s", state->src_strerror(result));
+        SDL_SetError("src_process() failed: %s", SRC_src_strerror(result));
         return 0;
     }
 
@@ -701,20 +666,15 @@ SDL_ResampleAudioStream_SRC(SDL_AudioStream *stream, const float *inbuf, const i
 static void
 SDL_ResetAudioStreamResampler_SRC(SDL_AudioStream *stream)
 {
-    SDL_AudioStreamResamplerState_SRC *state = (SDL_AudioStreamResamplerState_SRC*)stream->resampler_state;
-    state->src_reset(state->SRC_state);
+    SRC_src_reset((SRC_STATE *)stream->resampler_state);
 }
 
 static void
 SDL_CleanupAudioStreamResampler_SRC(SDL_AudioStream *stream)
 {
-    SDL_AudioStreamResamplerState_SRC *state = (SDL_AudioStreamResamplerState_SRC*)stream->resampler_state;
+    SRC_STATE *state = (SRC_STATE *)stream->resampler_state;
     if (state) {
-        if (state->SRC_lib) {
-            SDL_UnloadObject(state->SRC_lib);
-        }
-        state->src_delete(state->SRC_state);
-        SDL_free(state);
+        SRC_src_delete(state);
     }
 
     stream->resampler_state = NULL;
@@ -726,15 +686,18 @@ SDL_CleanupAudioStreamResampler_SRC(SDL_AudioStream *stream)
 static SDL_bool
 SetupLibSampleRateResampling(SDL_AudioStream *stream)
 {
-    int result;
+    int result = 0;
+    SRC_STATE *state = NULL;
 
-    SDL_AudioStreamResamplerState_SRC *state = (SDL_AudioStreamResamplerState_SRC *)SDL_calloc(1, sizeof(*state));
-    if (!state) {
-        return SDL_FALSE;
+    if (SRC_available) {
+        state = SRC_src_new(SRC_SINC_FASTEST, stream->pre_resample_channels, &result);
+        if (!state) {
+            SDL_SetError("src_new() failed: %s", SRC_src_strerror(result));
+        }
     }
 
-    if (!LoadLibSampleRate(state)) {
-        SDL_free(state);
+    if (!state) {
+        SDL_CleanupAudioStreamResampler_SRC(stream);
         return SDL_FALSE;
     }
 
@@ -743,17 +706,11 @@ SetupLibSampleRateResampling(SDL_AudioStream *stream)
     stream->reset_resampler_func = SDL_ResetAudioStreamResampler_SRC;
     stream->cleanup_resampler_func = SDL_CleanupAudioStreamResampler_SRC;
 
-    state->SRC_state = state->src_new(SRC_SINC_FASTEST, stream->pre_resample_channels, &result);
-    if (!state->SRC_state) {
-        SDL_SetError("src_new() failed: %s", state->src_strerror(result));
-        SDL_CleanupAudioStreamResampler_SRC(stream);
-        return SDL_FALSE;
-    }
     return SDL_TRUE;
 }
-
 #endif /* HAVE_LIBSAMPLERATE_H */
 
+
 typedef struct
 {
     SDL_bool resampler_seeded;