Update mini_al with experimental support for SDL/Emscripten.
This commit is contained in:
parent
f9144ac5b0
commit
84ef860443
288
src/external/mini_al.h
vendored
288
src/external/mini_al.h
vendored
@ -233,8 +233,14 @@ extern "C" {
|
||||
#define MAL_SUPPORT_OSS
|
||||
#endif
|
||||
#endif
|
||||
#define MAL_SUPPORT_OPENAL // All platforms support OpenAL (at least for now).
|
||||
#define MAL_SUPPORT_NULL // All platforms support the null device.
|
||||
|
||||
// Explicitly disable OpenAL for Emscripten - prefer SDL for this.
|
||||
#if !defined(MAL_EMSCRIPTEN)
|
||||
#define MAL_SUPPORT_OPENAL
|
||||
#endif
|
||||
|
||||
#define MAL_SUPPORT_SDL // All platforms support SDL.
|
||||
#define MAL_SUPPORT_NULL // All platforms support the null backend.
|
||||
|
||||
|
||||
#if !defined(MAL_NO_WASAPI) && defined(MAL_SUPPORT_WASAPI)
|
||||
@ -261,6 +267,9 @@ extern "C" {
|
||||
#if !defined(MAL_NO_OPENAL) && defined(MAL_SUPPORT_OPENAL)
|
||||
#define MAL_ENABLE_OPENAL
|
||||
#endif
|
||||
#if !defined(MAL_NO_SDL) && defined(MAL_SUPPORT_SDL)
|
||||
#define MAL_ENABLE_SDL
|
||||
#endif
|
||||
#if !defined(MAL_NO_NULL) && defined(MAL_SUPPORT_NULL)
|
||||
#define MAL_ENABLE_NULL
|
||||
#endif
|
||||
@ -469,7 +478,8 @@ typedef enum
|
||||
mal_backend_alsa,
|
||||
mal_backend_oss,
|
||||
mal_backend_opensl,
|
||||
mal_backend_openal
|
||||
mal_backend_openal,
|
||||
mal_backend_sdl
|
||||
} mal_backend;
|
||||
|
||||
typedef enum
|
||||
@ -522,6 +532,9 @@ typedef union
|
||||
#ifdef MAL_SUPPORT_OPENAL
|
||||
char openal[256]; // OpenAL seems to use human-readable device names as the ID.
|
||||
#endif
|
||||
#ifdef MAL_SUPPORT_SDL
|
||||
int sdl; //
|
||||
#endif
|
||||
#ifdef MAL_SUPPORT_NULL
|
||||
int nullbackend; // Always 0.
|
||||
#endif
|
||||
@ -844,11 +857,17 @@ struct mal_context
|
||||
mal_uint32 isMCFormatsSupported : 1;
|
||||
} openal;
|
||||
#endif
|
||||
#ifdef MAL_SUPPORT_SDL
|
||||
struct
|
||||
{
|
||||
int _unused;
|
||||
} sdl;
|
||||
#endif
|
||||
#ifdef MAL_SUPPORT_NULL
|
||||
struct
|
||||
{
|
||||
int _unused;
|
||||
} null_device;
|
||||
} null_backend;
|
||||
#endif
|
||||
};
|
||||
|
||||
@ -1017,6 +1036,12 @@ struct mal_device
|
||||
mal_bool32 breakFromMainLoop;
|
||||
} openal;
|
||||
#endif
|
||||
#ifdef MAL_SUPPORT_SDL
|
||||
struct
|
||||
{
|
||||
mal_uint32 deviceID;
|
||||
} sdl;
|
||||
#endif
|
||||
#ifdef MAL_SUPPORT_NULL
|
||||
struct
|
||||
{
|
||||
@ -1575,12 +1600,26 @@ void mal_pcm_convert(void* pOut, mal_format formatOut, const void* pIn, mal_form
|
||||
#ifdef MAL_ENABLE_OPENAL
|
||||
#define MAL_HAS_OPENAL // mini_al inlines the necessary OpenAL stuff.
|
||||
#endif
|
||||
#ifdef MAL_ENABLE_SDL
|
||||
#define MAL_HAS_SDL
|
||||
#ifdef __has_include
|
||||
#ifdef MAL_EMSCRIPTEN
|
||||
#if !__has_include(<SDL/SDL_audio.h>)
|
||||
#undef MAL_HAS_SDL
|
||||
#endif
|
||||
#else
|
||||
#if !__has_include(<SDL2/SDL_audio.h>)
|
||||
#undef MAL_HAS_SDL
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
#ifdef MAL_ENABLE_NULL
|
||||
#define MAL_HAS_NULL // Everything supports the null backend.
|
||||
#endif
|
||||
|
||||
// Disable run-time linking on certain backends.
|
||||
#if defined(MAL_ANDROID) || defined(MAL_EMSCRIPTED)
|
||||
#if defined(MAL_ANDROID) || defined(MAL_EMSCRIPTEN)
|
||||
#define MAL_NO_RUNTIME_LINKING
|
||||
#endif
|
||||
|
||||
@ -7768,7 +7807,7 @@ mal_result mal_enumerate_devices__openal(mal_context* pContext, mal_device_type
|
||||
return MAL_SUCCESS;
|
||||
}
|
||||
|
||||
static void mal_device_uninit__openal(mal_device* pDevice)
|
||||
void mal_device_uninit__openal(mal_device* pDevice)
|
||||
{
|
||||
mal_assert(pDevice != NULL);
|
||||
|
||||
@ -7784,7 +7823,7 @@ static void mal_device_uninit__openal(mal_device* pDevice)
|
||||
mal_free(pDevice->openal.pIntermediaryBuffer);
|
||||
}
|
||||
|
||||
static mal_result mal_device_init__openal(mal_context* pContext, mal_device_type type, mal_device_id* pDeviceID, const mal_device_config* pConfig, mal_device* pDevice)
|
||||
mal_result mal_device_init__openal(mal_context* pContext, mal_device_type type, mal_device_id* pDeviceID, const mal_device_config* pConfig, mal_device* pDevice)
|
||||
{
|
||||
if (pDevice->periods > MAL_MAX_PERIODS_OPENAL) {
|
||||
pDevice->periods = MAL_MAX_PERIODS_OPENAL;
|
||||
@ -8167,6 +8206,196 @@ static mal_result mal_device__main_loop__openal(mal_device* pDevice)
|
||||
#endif // OpenAL
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// SDL Backend
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#ifdef MAL_HAS_SDL
|
||||
#define SDL_MAIN_HANDLED
|
||||
#ifdef MAL_EMSCRIPTEN
|
||||
#include <SDL/SDL.h>
|
||||
#else
|
||||
#include <SDL2/SDL.h>
|
||||
#endif
|
||||
|
||||
SDL_AudioFormat mal_format_to_sdl(mal_format format)
|
||||
{
|
||||
switch (format)
|
||||
{
|
||||
case mal_format_unknown: return 0;
|
||||
case mal_format_u8: return AUDIO_U8;
|
||||
case mal_format_s16: return AUDIO_S16;
|
||||
case mal_format_s24: return AUDIO_S32; // Closest match.
|
||||
case mal_format_s32: return AUDIO_S32;
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
|
||||
mal_format mal_format_from_sdl(SDL_AudioFormat format)
|
||||
{
|
||||
switch (format)
|
||||
{
|
||||
case AUDIO_U8: return mal_format_u8;
|
||||
case AUDIO_S16: return mal_format_s16;
|
||||
case AUDIO_S32: return mal_format_s32;
|
||||
case AUDIO_F32: return mal_format_f32;
|
||||
default: return mal_format_unknown;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
mal_result mal_context_init__sdl(mal_context* pContext)
|
||||
{
|
||||
mal_assert(pContext != NULL);
|
||||
|
||||
int resultSDL = SDL_InitSubSystem(SDL_INIT_AUDIO);
|
||||
if (resultSDL != 0) {
|
||||
return MAL_ERROR;
|
||||
}
|
||||
|
||||
return MAL_SUCCESS;
|
||||
}
|
||||
|
||||
mal_result mal_context_uninit__sdl(mal_context* pContext)
|
||||
{
|
||||
mal_assert(pContext != NULL);
|
||||
mal_assert(pContext->backend == mal_backend_sdl);
|
||||
|
||||
SDL_QuitSubSystem(SDL_INIT_AUDIO);
|
||||
return MAL_SUCCESS;
|
||||
}
|
||||
|
||||
mal_result mal_enumerate_devices__sdl(mal_context* pContext, mal_device_type type, mal_uint32* pCount, mal_device_info* pInfo)
|
||||
{
|
||||
(void)pContext;
|
||||
|
||||
|
||||
mal_uint32 infoSize = *pCount;
|
||||
*pCount = 0;
|
||||
|
||||
// For now I'm restricting the SDL backend to default devices.
|
||||
if (pInfo != NULL) {
|
||||
if (infoSize > 0) {
|
||||
if (type == mal_device_type_playback) {
|
||||
pInfo->id.sdl = 0;
|
||||
mal_strncpy_s(pInfo->name, sizeof(pInfo->name), "Default Playback Device", (size_t)-1);
|
||||
} else {
|
||||
pInfo->id.sdl = 0;
|
||||
mal_strncpy_s(pInfo->name, sizeof(pInfo->name), "Default Capture Device", (size_t)-1);
|
||||
}
|
||||
|
||||
pInfo += 1;
|
||||
*pCount += 1;
|
||||
}
|
||||
} else {
|
||||
*pCount += 1;
|
||||
}
|
||||
|
||||
return MAL_SUCCESS;
|
||||
}
|
||||
|
||||
void mal_device_uninit__sdl(mal_device* pDevice)
|
||||
{
|
||||
mal_assert(pDevice != NULL);
|
||||
|
||||
#if 1
|
||||
SDL_CloseAudioDevice(pDevice->sdl.deviceID);
|
||||
#else
|
||||
SDL_CloseAudio();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
static void mal_audio_callback__sdl(void *pUserData, Uint8 *pBuffer, int bufferSizeInBytes)
|
||||
{
|
||||
mal_device* pDevice = (mal_device*)pUserData;
|
||||
mal_assert(pDevice != NULL);
|
||||
|
||||
mal_uint32 bufferSizeInFrames = (mal_uint32)bufferSizeInBytes / mal_get_sample_size_in_bytes(pDevice->format) / pDevice->channels;
|
||||
|
||||
if (pDevice->type == mal_device_type_playback) {
|
||||
mal_device__read_frames_from_client(pDevice, bufferSizeInFrames, pBuffer);
|
||||
} else {
|
||||
mal_device__send_frames_to_client(pDevice, bufferSizeInFrames, pBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
mal_result mal_device_init__sdl(mal_context* pContext, mal_device_type type, mal_device_id* pDeviceID, const mal_device_config* pConfig, mal_device* pDevice)
|
||||
{
|
||||
mal_assert(pContext != NULL);
|
||||
mal_assert(pConfig != NULL);
|
||||
mal_assert(pDevice != NULL);
|
||||
|
||||
SDL_AudioSpec desiredSpec, obtainedSpec;
|
||||
mal_zero_memory(&desiredSpec, sizeof(desiredSpec));
|
||||
desiredSpec.freq = (int)pConfig->sampleRate;
|
||||
desiredSpec.format = mal_format_to_sdl(pConfig->format);
|
||||
desiredSpec.channels = (Uint8)pConfig->channels;
|
||||
desiredSpec.samples = (Uint16)mal_next_power_of_2(pConfig->bufferSizeInFrames * pConfig->periods * pConfig->channels);
|
||||
desiredSpec.callback = mal_audio_callback__sdl;
|
||||
desiredSpec.userdata = pDevice;
|
||||
|
||||
// Fall back to f32 if we don't have an appropriate mapping between mini_al and SDL.
|
||||
if (desiredSpec.format == 0) {
|
||||
desiredSpec.format = AUDIO_F32;
|
||||
}
|
||||
|
||||
// For now, only using the default device.
|
||||
(void)pDeviceID;
|
||||
|
||||
#if 1
|
||||
pDevice->sdl.deviceID = SDL_OpenAudioDevice(NULL, (type == mal_device_type_playback) ? 0 : 1, &desiredSpec, &obtainedSpec, 0);
|
||||
if (pDevice->sdl.deviceID == 0) {
|
||||
return mal_post_error(pDevice, "Failed to open SDL device.", MAL_FAILED_TO_OPEN_BACKEND_DEVICE);
|
||||
}
|
||||
#else
|
||||
pDevice->sdl.deviceID = SDL_OpenAudio(&desiredSpec, &obtainedSpec);
|
||||
if (pDevice->sdl.deviceID != 0) {
|
||||
return mal_post_error(pDevice, "Failed to open SDL device.", MAL_FAILED_TO_OPEN_BACKEND_DEVICE);
|
||||
}
|
||||
#endif
|
||||
|
||||
pDevice->internalFormat = mal_format_from_sdl(obtainedSpec.format);
|
||||
pDevice->internalChannels = obtainedSpec.channels;
|
||||
pDevice->internalSampleRate = (mal_uint32)obtainedSpec.freq;
|
||||
pDevice->bufferSizeInFrames = obtainedSpec.samples / obtainedSpec.channels;
|
||||
pDevice->periods = 1; // SDL doesn't seem to tell us what the period count is. Just set this 1.
|
||||
|
||||
return MAL_SUCCESS;
|
||||
}
|
||||
|
||||
static mal_result mal_device__start_backend__sdl(mal_device* pDevice)
|
||||
{
|
||||
mal_assert(pDevice != NULL);
|
||||
|
||||
#if 1
|
||||
SDL_PauseAudioDevice(pDevice->sdl.deviceID, 0);
|
||||
#else
|
||||
SDL_PauseAudio(0);
|
||||
#endif
|
||||
|
||||
return MAL_SUCCESS;
|
||||
}
|
||||
|
||||
static mal_result mal_device__stop_backend__sdl(mal_device* pDevice)
|
||||
{
|
||||
mal_assert(pDevice != NULL);
|
||||
|
||||
#if 1
|
||||
SDL_PauseAudioDevice(pDevice->sdl.deviceID, 1);
|
||||
#else
|
||||
SDL_PauseAudio(1);
|
||||
#endif
|
||||
|
||||
return MAL_SUCCESS;
|
||||
}
|
||||
#endif // SDL
|
||||
|
||||
|
||||
|
||||
|
||||
mal_bool32 mal__is_channel_map_valid(const mal_channel* channelMap, mal_uint32 channels)
|
||||
{
|
||||
mal_assert(channels > 0);
|
||||
@ -8585,6 +8814,7 @@ mal_result mal_context_init(mal_backend backends[], mal_uint32 backendCount, con
|
||||
mal_backend_oss,
|
||||
mal_backend_opensl,
|
||||
mal_backend_openal,
|
||||
mal_backend_sdl,
|
||||
mal_backend_null
|
||||
};
|
||||
|
||||
@ -8642,6 +8872,12 @@ mal_result mal_context_init(mal_backend backends[], mal_uint32 backendCount, con
|
||||
result = mal_context_init__openal(pContext);
|
||||
} break;
|
||||
#endif
|
||||
#ifdef MAL_HAS_SDL
|
||||
case mal_backend_sdl:
|
||||
{
|
||||
result = mal_context_init__sdl(pContext);
|
||||
} break;
|
||||
#endif
|
||||
#ifdef MAL_HAS_NULL
|
||||
case mal_backend_null:
|
||||
{
|
||||
@ -8710,6 +8946,12 @@ mal_result mal_context_uninit(mal_context* pContext)
|
||||
return mal_context_uninit__openal(pContext);
|
||||
} break;
|
||||
#endif
|
||||
#ifdef MAL_HAS_SDL
|
||||
case mal_backend_sdl:
|
||||
{
|
||||
return mal_context_uninit__sdl(pContext);
|
||||
} break;
|
||||
#endif
|
||||
#ifdef MAL_HAS_NULL
|
||||
case mal_backend_null:
|
||||
{
|
||||
@ -8775,6 +9017,12 @@ mal_result mal_enumerate_devices(mal_context* pContext, mal_device_type type, ma
|
||||
return mal_enumerate_devices__openal(pContext, type, pCount, pInfo);
|
||||
} break;
|
||||
#endif
|
||||
#ifdef MAL_HAS_SDL
|
||||
case mal_backend_sdl:
|
||||
{
|
||||
return mal_enumerate_devices__sdl(pContext, type, pCount, pInfo);
|
||||
} break;
|
||||
#endif
|
||||
#ifdef MAL_HAS_NULL
|
||||
case mal_backend_null:
|
||||
{
|
||||
@ -8934,6 +9182,12 @@ mal_result mal_device_init(mal_context* pContext, mal_device_type type, mal_devi
|
||||
result = mal_device_init__openal(pContext, type, pDeviceID, &config, pDevice);
|
||||
} break;
|
||||
#endif
|
||||
#ifdef MAL_HAS_SDL
|
||||
case mal_backend_sdl:
|
||||
{
|
||||
result = mal_device_init__sdl(pContext, type, pDeviceID, &config, pDevice);
|
||||
} break;
|
||||
#endif
|
||||
#ifdef MAL_HAS_NULL
|
||||
case mal_backend_null:
|
||||
{
|
||||
@ -8979,7 +9233,7 @@ mal_result mal_device_init(mal_context* pContext, mal_device_type type, mal_devi
|
||||
|
||||
|
||||
// Some backends don't require the worker thread.
|
||||
if (pContext->backend != mal_backend_opensl) {
|
||||
if (pContext->backend != mal_backend_opensl && pContext->backend != mal_backend_sdl) {
|
||||
// The worker thread.
|
||||
if (mal_thread_create(pContext, &pDevice->thread, mal_worker_thread, pDevice) != MAL_SUCCESS) {
|
||||
mal_device_uninit(pDevice);
|
||||
@ -9012,7 +9266,7 @@ void mal_device_uninit(mal_device* pDevice)
|
||||
mal_device__set_state(pDevice, MAL_STATE_UNINITIALIZED);
|
||||
|
||||
// Wake up the worker thread and wait for it to properly terminate.
|
||||
if (pDevice->pContext->backend != mal_backend_opensl) {
|
||||
if (pDevice->pContext->backend != mal_backend_opensl && pDevice->pContext->backend != mal_backend_sdl) {
|
||||
mal_event_signal(&pDevice->wakeupEvent);
|
||||
mal_thread_wait(&pDevice->thread);
|
||||
}
|
||||
@ -9057,6 +9311,11 @@ void mal_device_uninit(mal_device* pDevice)
|
||||
mal_device_uninit__openal(pDevice);
|
||||
}
|
||||
#endif
|
||||
#ifdef MAL_HAS_SDL
|
||||
if (pDevice->pContext->backend == mal_backend_sdl) {
|
||||
mal_device_uninit__sdl(pDevice);
|
||||
}
|
||||
#endif
|
||||
#ifdef MAL_HAS_NULL
|
||||
if (pDevice->pContext->backend == mal_backend_null) {
|
||||
mal_device_uninit__null(pDevice);
|
||||
@ -9117,6 +9376,12 @@ mal_result mal_device_start(mal_device* pDevice)
|
||||
mal_device__start_backend__opensl(pDevice);
|
||||
mal_device__set_state(pDevice, MAL_STATE_STARTED);
|
||||
} else
|
||||
#endif
|
||||
#ifdef MAL_HAS_SDL
|
||||
if (pDevice->pContext->backend == mal_backend_sdl) {
|
||||
mal_device__start_backend__sdl(pDevice);
|
||||
mal_device__set_state(pDevice, MAL_STATE_STARTED);
|
||||
} else
|
||||
#endif
|
||||
// Synchronous backends.
|
||||
{
|
||||
@ -9167,6 +9432,11 @@ mal_result mal_device_stop(mal_device* pDevice)
|
||||
if (pDevice->pContext->backend == mal_backend_opensl) {
|
||||
mal_device__stop_backend__opensl(pDevice);
|
||||
} else
|
||||
#endif
|
||||
#ifdef MAL_HAS_SDL
|
||||
if (pDevice->pContext->backend == mal_backend_sdl) {
|
||||
mal_device__stop_backend__sdl(pDevice);
|
||||
} else
|
||||
#endif
|
||||
// Synchronous backends.
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user