diff --git a/src/audio/SDL_audio.c b/src/audio/SDL_audio.c index 5773a4f5d..730a2408f 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 62467cfb5..2736fe4fa 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 a9d4fce81..1d9f02708 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;