Commit 4afeda4b authored by David Reid's avatar David Reid

Remove the OpenAL backend.

parent 2e6c6e66
......@@ -174,10 +174,6 @@ Web Audio / Emscripten
of user input. See here for details: https://developers.google.com/web/updates/2017/09/autoplay-policy-changes. Starting
the device may fail if you try to start playback without first handling some kind of user input.
OpenAL
------
- Capture is not supported on iOS with OpenAL. Use the Core Audio backend instead.
OPTIONS
=======
......@@ -222,9 +218,6 @@ OPTIONS
#define MAL_NO_WEBAUDIO
Disables the Web Audio backend.
#define MAL_NO_OPENAL
Disables the OpenAL backend.
#define MAL_NO_NULL
Disables the null backend.
......@@ -1233,9 +1226,8 @@ void mal_interleave_pcm_frames(mal_format format, mal_uint32 channels, mal_uint6
#define MAL_SUPPORT_WEBAUDIO
#endif
// Explicitly disable OpenAL and Null backends for Emscripten because they both use a background thread which is not properly supported right now.
// Explicitly disable the Null backend for Emscripten because it uses a background thread which is not properly supported right now.
#if !defined(MAL_EMSCRIPTEN)
#define MAL_SUPPORT_OPENAL
#define MAL_SUPPORT_NULL
#endif
......@@ -1279,9 +1271,6 @@ void mal_interleave_pcm_frames(mal_format format, mal_uint32 channels, mal_uint6
#if !defined(MAL_NO_WEBAUDIO) && defined(MAL_SUPPORT_WEBAUDIO)
#define MAL_ENABLE_WEBAUDIO
#endif
#if !defined(MAL_NO_OPENAL) && defined(MAL_SUPPORT_OPENAL)
#define MAL_ENABLE_OPENAL
#endif
#if !defined(MAL_NO_NULL) && defined(MAL_SUPPORT_NULL)
#define MAL_ENABLE_NULL
#endif
......@@ -1312,7 +1301,6 @@ typedef enum
mal_backend_aaudio,
mal_backend_opensl,
mal_backend_webaudio,
mal_backend_openal,
mal_backend_null /* <-- Must always be the last item. Lowest priority, and used as the terminator for backend enumeration. */
} mal_backend;
......@@ -1398,8 +1386,7 @@ typedef struct
} mal_event;
#define MAL_MAX_PERIODS_DSOUND 4
#define MAL_MAX_PERIODS_OPENAL 4
#define MAL_MAX_PERIODS_DSOUND 4
typedef void (* mal_log_proc) (mal_context* pContext, mal_device* pDevice, mal_uint32 logLevel, const char* message);
typedef void (* mal_recv_proc)(mal_device* pDevice, mal_uint32 frameCount, const void* pSamples);
......@@ -1459,9 +1446,6 @@ typedef union
#ifdef MAL_SUPPORT_WEBAUDIO
char webaudio[32]; // Web Audio always uses default devices for now, but if this changes it'll be a GUID.
#endif
#ifdef MAL_SUPPORT_OPENAL
char openal[256]; // OpenAL seems to use human-readable device names as the ID.
#endif
#ifdef MAL_SUPPORT_NULL
int nullbackend; // The null backend uses an integer for device IDs.
#endif
......@@ -1841,93 +1825,6 @@ struct mal_context
int _unused;
} webaudio;
#endif
#ifdef MAL_SUPPORT_OPENAL
struct
{
/*HMODULE*/ mal_handle hOpenAL; // OpenAL32.dll, etc.
mal_proc alcCreateContext;
mal_proc alcMakeContextCurrent;
mal_proc alcProcessContext;
mal_proc alcSuspendContext;
mal_proc alcDestroyContext;
mal_proc alcGetCurrentContext;
mal_proc alcGetContextsDevice;
mal_proc alcOpenDevice;
mal_proc alcCloseDevice;
mal_proc alcGetError;
mal_proc alcIsExtensionPresent;
mal_proc alcGetProcAddress;
mal_proc alcGetEnumValue;
mal_proc alcGetString;
mal_proc alcGetIntegerv;
mal_proc alcCaptureOpenDevice;
mal_proc alcCaptureCloseDevice;
mal_proc alcCaptureStart;
mal_proc alcCaptureStop;
mal_proc alcCaptureSamples;
mal_proc alEnable;
mal_proc alDisable;
mal_proc alIsEnabled;
mal_proc alGetString;
mal_proc alGetBooleanv;
mal_proc alGetIntegerv;
mal_proc alGetFloatv;
mal_proc alGetDoublev;
mal_proc alGetBoolean;
mal_proc alGetInteger;
mal_proc alGetFloat;
mal_proc alGetDouble;
mal_proc alGetError;
mal_proc alIsExtensionPresent;
mal_proc alGetProcAddress;
mal_proc alGetEnumValue;
mal_proc alGenSources;
mal_proc alDeleteSources;
mal_proc alIsSource;
mal_proc alSourcef;
mal_proc alSource3f;
mal_proc alSourcefv;
mal_proc alSourcei;
mal_proc alSource3i;
mal_proc alSourceiv;
mal_proc alGetSourcef;
mal_proc alGetSource3f;
mal_proc alGetSourcefv;
mal_proc alGetSourcei;
mal_proc alGetSource3i;
mal_proc alGetSourceiv;
mal_proc alSourcePlayv;
mal_proc alSourceStopv;
mal_proc alSourceRewindv;
mal_proc alSourcePausev;
mal_proc alSourcePlay;
mal_proc alSourceStop;
mal_proc alSourceRewind;
mal_proc alSourcePause;
mal_proc alSourceQueueBuffers;
mal_proc alSourceUnqueueBuffers;
mal_proc alGenBuffers;
mal_proc alDeleteBuffers;
mal_proc alIsBuffer;
mal_proc alBufferData;
mal_proc alBufferf;
mal_proc alBuffer3f;
mal_proc alBufferfv;
mal_proc alBufferi;
mal_proc alBuffer3i;
mal_proc alBufferiv;
mal_proc alGetBufferf;
mal_proc alGetBuffer3f;
mal_proc alGetBufferfv;
mal_proc alGetBufferi;
mal_proc alGetBuffer3i;
mal_proc alGetBufferiv;
mal_bool32 isEnumerationSupported : 1;
mal_bool32 isFloat32Supported : 1;
mal_bool32 isMCFormatsSupported : 1;
} openal;
#endif
#ifdef MAL_SUPPORT_NULL
struct
{
......@@ -2164,20 +2061,6 @@ MAL_ALIGNED_STRUCT(MAL_SIMD_ALIGNMENT) mal_device
int index; /* We use a factory on the JavaScript side to manage devices and use an index for JS/C interop. */
} webaudio;
#endif
#ifdef MAL_SUPPORT_OPENAL
struct
{
/*ALCcontext**/ mal_ptr pContextALC;
/*ALCdevice**/ mal_ptr pDeviceALC;
/*ALuint*/ mal_uint32 sourceAL;
/*ALuint*/ mal_uint32 buffersAL[MAL_MAX_PERIODS_OPENAL];
/*ALenum*/ mal_uint32 formatAL;
mal_uint32 subBufferSizeInFrames; // This is the size of each of the OpenAL buffers (buffersAL).
mal_uint8* pIntermediaryBuffer; // This is malloc()'d and is used as the destination for reading from the client. Typed as mal_uint8 for easy offsetting.
mal_uint32 iNextBuffer; // The next buffer to unenqueue and then re-enqueue as new data is read.
mal_bool32 breakFromMainLoop;
} openal;
#endif
#ifdef MAL_SUPPORT_NULL
struct
{
......@@ -3787,16 +3670,6 @@ mal_uint32 mal_get_standard_sample_rate_priority_index(mal_uint32 sampleRate)
#ifdef MAL_ENABLE_WEBAUDIO
#define MAL_HAS_WEBAUDIO
#endif
#ifdef MAL_ENABLE_OPENAL
#define MAL_HAS_OPENAL
#ifdef MAL_NO_RUNTIME_LINKING
#ifdef __has_include
#if !__has_include(<AL/al.h>)
#undef MAL_HAS_OPENAL
#endif
#endif
#endif
#endif
#ifdef MAL_ENABLE_NULL
#define MAL_HAS_NULL // Everything supports the null backend.
#endif
......@@ -3818,7 +3691,6 @@ const char* mal_get_backend_name(mal_backend backend)
case mal_backend_aaudio: return "AAudio";
case mal_backend_opensl: return "OpenSL|ES";
case mal_backend_webaudio: return "Web Audio";
case mal_backend_openal: return "OpenAL";
case mal_backend_null: return "Null";
default: return "Unknown";
}
......@@ -19627,981 +19499,6 @@ mal_result mal_context_init__webaudio(mal_context* pContext)
#endif // Web Audio
///////////////////////////////////////////////////////////////////////////////
//
// OpenAL Backend
//
///////////////////////////////////////////////////////////////////////////////
#ifdef MAL_HAS_OPENAL
#ifdef MAL_WIN32
#define MAL_AL_APIENTRY __cdecl
#else
#define MAL_AL_APIENTRY
#endif
#ifdef MAL_NO_RUNTIME_LINKING
#if defined(MAL_APPLE)
#include <OpenAL/al.h>
#include <OpenAL/alc.h>
#else
#include <AL/al.h>
#include <AL/alc.h>
#endif
#endif
typedef struct mal_ALCdevice_struct mal_ALCdevice;
typedef struct mal_ALCcontext_struct mal_ALCcontext;
typedef char mal_ALCboolean;
typedef char mal_ALCchar;
typedef signed char mal_ALCbyte;
typedef unsigned char mal_ALCubyte;
typedef short mal_ALCshort;
typedef unsigned short mal_ALCushort;
typedef int mal_ALCint;
typedef unsigned int mal_ALCuint;
typedef int mal_ALCsizei;
typedef int mal_ALCenum;
typedef float mal_ALCfloat;
typedef double mal_ALCdouble;
typedef void mal_ALCvoid;
typedef mal_ALCboolean mal_ALboolean;
typedef mal_ALCchar mal_ALchar;
typedef mal_ALCbyte mal_ALbyte;
typedef mal_ALCubyte mal_ALubyte;
typedef mal_ALCshort mal_ALshort;
typedef mal_ALCushort mal_ALushort;
typedef mal_ALCint mal_ALint;
typedef mal_ALCuint mal_ALuint;
typedef mal_ALCsizei mal_ALsizei;
typedef mal_ALCenum mal_ALenum;
typedef mal_ALCfloat mal_ALfloat;
typedef mal_ALCdouble mal_ALdouble;
typedef mal_ALCvoid mal_ALvoid;
#define MAL_ALC_DEVICE_SPECIFIER 0x1005
#define MAL_ALC_CAPTURE_DEVICE_SPECIFIER 0x310
#define MAL_ALC_CAPTURE_SAMPLES 0x312
#define MAL_AL_SOURCE_STATE 0x1010
#define MAL_AL_INITIAL 0x1011
#define MAL_AL_PLAYING 0x1012
#define MAL_AL_PAUSED 0x1013
#define MAL_AL_STOPPED 0x1014
#define MAL_AL_BUFFERS_PROCESSED 0x1016
#define MAL_AL_FORMAT_MONO8 0x1100
#define MAL_AL_FORMAT_MONO16 0x1101
#define MAL_AL_FORMAT_STEREO8 0x1102
#define MAL_AL_FORMAT_STEREO16 0x1103
#define MAL_AL_FORMAT_MONO_FLOAT32 0x10010
#define MAL_AL_FORMAT_STEREO_FLOAT32 0x10011
#define MAL_AL_FORMAT_51CHN16 0x120B
#define MAL_AL_FORMAT_51CHN32 0x120C
#define MAL_AL_FORMAT_51CHN8 0x120A
#define MAL_AL_FORMAT_61CHN16 0x120E
#define MAL_AL_FORMAT_61CHN32 0x120F
#define MAL_AL_FORMAT_61CHN8 0x120D
#define MAL_AL_FORMAT_71CHN16 0x1211
#define MAL_AL_FORMAT_71CHN32 0x1212
#define MAL_AL_FORMAT_71CHN8 0x1210
#define MAL_AL_FORMAT_QUAD16 0x1205
#define MAL_AL_FORMAT_QUAD32 0x1206
#define MAL_AL_FORMAT_QUAD8 0x1204
#define MAL_AL_FORMAT_REAR16 0x1208
#define MAL_AL_FORMAT_REAR32 0x1209
#define MAL_AL_FORMAT_REAR8 0x1207
typedef mal_ALCcontext* (MAL_AL_APIENTRY * MAL_LPALCCREATECONTEXT) (mal_ALCdevice *device, const mal_ALCint *attrlist);
typedef mal_ALCboolean (MAL_AL_APIENTRY * MAL_LPALCMAKECONTEXTCURRENT) (mal_ALCcontext *context);
typedef void (MAL_AL_APIENTRY * MAL_LPALCPROCESSCONTEXT) (mal_ALCcontext *context);
typedef void (MAL_AL_APIENTRY * MAL_LPALCSUSPENDCONTEXT) (mal_ALCcontext *context);
typedef void (MAL_AL_APIENTRY * MAL_LPALCDESTROYCONTEXT) (mal_ALCcontext *context);
typedef mal_ALCcontext* (MAL_AL_APIENTRY * MAL_LPALCGETCURRENTCONTEXT) (void);
typedef mal_ALCdevice* (MAL_AL_APIENTRY * MAL_LPALCGETCONTEXTSDEVICE) (mal_ALCcontext *context);
typedef mal_ALCdevice* (MAL_AL_APIENTRY * MAL_LPALCOPENDEVICE) (const mal_ALCchar *devicename);
typedef mal_ALCboolean (MAL_AL_APIENTRY * MAL_LPALCCLOSEDEVICE) (mal_ALCdevice *device);
typedef mal_ALCenum (MAL_AL_APIENTRY * MAL_LPALCGETERROR) (mal_ALCdevice *device);
typedef mal_ALCboolean (MAL_AL_APIENTRY * MAL_LPALCISEXTENSIONPRESENT) (mal_ALCdevice *device, const mal_ALCchar *extname);
typedef void* (MAL_AL_APIENTRY * MAL_LPALCGETPROCADDRESS) (mal_ALCdevice *device, const mal_ALCchar *funcname);
typedef mal_ALCenum (MAL_AL_APIENTRY * MAL_LPALCGETENUMVALUE) (mal_ALCdevice *device, const mal_ALCchar *enumname);
typedef const mal_ALCchar* (MAL_AL_APIENTRY * MAL_LPALCGETSTRING) (mal_ALCdevice *device, mal_ALCenum param);
typedef void (MAL_AL_APIENTRY * MAL_LPALCGETINTEGERV) (mal_ALCdevice *device, mal_ALCenum param, mal_ALCsizei size, mal_ALCint *values);
typedef mal_ALCdevice* (MAL_AL_APIENTRY * MAL_LPALCCAPTUREOPENDEVICE) (const mal_ALCchar *devicename, mal_ALCuint frequency, mal_ALCenum format, mal_ALCsizei buffersize);
typedef mal_ALCboolean (MAL_AL_APIENTRY * MAL_LPALCCAPTURECLOSEDEVICE) (mal_ALCdevice *device);
typedef void (MAL_AL_APIENTRY * MAL_LPALCCAPTURESTART) (mal_ALCdevice *device);
typedef void (MAL_AL_APIENTRY * MAL_LPALCCAPTURESTOP) (mal_ALCdevice *device);
typedef void (MAL_AL_APIENTRY * MAL_LPALCCAPTURESAMPLES) (mal_ALCdevice *device, mal_ALCvoid *buffer, mal_ALCsizei samples);
typedef void (MAL_AL_APIENTRY * MAL_LPALENABLE) (mal_ALenum capability);
typedef void (MAL_AL_APIENTRY * MAL_LPALDISABLE) (mal_ALenum capability);
typedef mal_ALboolean (MAL_AL_APIENTRY * MAL_LPALISENABLED) (mal_ALenum capability);
typedef const mal_ALchar* (MAL_AL_APIENTRY * MAL_LPALGETSTRING) (mal_ALenum param);
typedef void (MAL_AL_APIENTRY * MAL_LPALGETBOOLEANV) (mal_ALenum param, mal_ALboolean *values);
typedef void (MAL_AL_APIENTRY * MAL_LPALGETINTEGERV) (mal_ALenum param, mal_ALint *values);
typedef void (MAL_AL_APIENTRY * MAL_LPALGETFLOATV) (mal_ALenum param, mal_ALfloat *values);
typedef void (MAL_AL_APIENTRY * MAL_LPALGETDOUBLEV) (mal_ALenum param, mal_ALdouble *values);
typedef mal_ALboolean (MAL_AL_APIENTRY * MAL_LPALGETBOOLEAN) (mal_ALenum param);
typedef mal_ALint (MAL_AL_APIENTRY * MAL_LPALGETINTEGER) (mal_ALenum param);
typedef mal_ALfloat (MAL_AL_APIENTRY * MAL_LPALGETFLOAT) (mal_ALenum param);
typedef mal_ALdouble (MAL_AL_APIENTRY * MAL_LPALGETDOUBLE) (mal_ALenum param);
typedef mal_ALenum (MAL_AL_APIENTRY * MAL_LPALGETERROR) (void);
typedef mal_ALboolean (MAL_AL_APIENTRY * MAL_LPALISEXTENSIONPRESENT) (const mal_ALchar *extname);
typedef void* (MAL_AL_APIENTRY * MAL_LPALGETPROCADDRESS) (const mal_ALchar *fname);
typedef mal_ALenum (MAL_AL_APIENTRY * MAL_LPALGETENUMVALUE) (const mal_ALchar *ename);
typedef void (MAL_AL_APIENTRY * MAL_LPALGENSOURCES) (mal_ALsizei n, mal_ALuint *sources);
typedef void (MAL_AL_APIENTRY * MAL_LPALDELETESOURCES) (mal_ALsizei n, const mal_ALuint *sources);
typedef mal_ALboolean (MAL_AL_APIENTRY * MAL_LPALISSOURCE) (mal_ALuint source);
typedef void (MAL_AL_APIENTRY * MAL_LPALSOURCEF) (mal_ALuint source, mal_ALenum param, mal_ALfloat value);
typedef void (MAL_AL_APIENTRY * MAL_LPALSOURCE3F) (mal_ALuint source, mal_ALenum param, mal_ALfloat value1, mal_ALfloat value2, mal_ALfloat value3);
typedef void (MAL_AL_APIENTRY * MAL_LPALSOURCEFV) (mal_ALuint source, mal_ALenum param, const mal_ALfloat *values);
typedef void (MAL_AL_APIENTRY * MAL_LPALSOURCEI) (mal_ALuint source, mal_ALenum param, mal_ALint value);
typedef void (MAL_AL_APIENTRY * MAL_LPALSOURCE3I) (mal_ALuint source, mal_ALenum param, mal_ALint value1, mal_ALint value2, mal_ALint value3);
typedef void (MAL_AL_APIENTRY * MAL_LPALSOURCEIV) (mal_ALuint source, mal_ALenum param, const mal_ALint *values);
typedef void (MAL_AL_APIENTRY * MAL_LPALGETSOURCEF) (mal_ALuint source, mal_ALenum param, mal_ALfloat *value);
typedef void (MAL_AL_APIENTRY * MAL_LPALGETSOURCE3F) (mal_ALuint source, mal_ALenum param, mal_ALfloat *value1, mal_ALfloat *value2, mal_ALfloat *value3);
typedef void (MAL_AL_APIENTRY * MAL_LPALGETSOURCEFV) (mal_ALuint source, mal_ALenum param, mal_ALfloat *values);
typedef void (MAL_AL_APIENTRY * MAL_LPALGETSOURCEI) (mal_ALuint source, mal_ALenum param, mal_ALint *value);
typedef void (MAL_AL_APIENTRY * MAL_LPALGETSOURCE3I) (mal_ALuint source, mal_ALenum param, mal_ALint *value1, mal_ALint *value2, mal_ALint *value3);
typedef void (MAL_AL_APIENTRY * MAL_LPALGETSOURCEIV) (mal_ALuint source, mal_ALenum param, mal_ALint *values);
typedef void (MAL_AL_APIENTRY * MAL_LPALSOURCEPLAYV) (mal_ALsizei n, const mal_ALuint *sources);
typedef void (MAL_AL_APIENTRY * MAL_LPALSOURCESTOPV) (mal_ALsizei n, const mal_ALuint *sources);
typedef void (MAL_AL_APIENTRY * MAL_LPALSOURCEREWINDV) (mal_ALsizei n, const mal_ALuint *sources);
typedef void (MAL_AL_APIENTRY * MAL_LPALSOURCEPAUSEV) (mal_ALsizei n, const mal_ALuint *sources);
typedef void (MAL_AL_APIENTRY * MAL_LPALSOURCEPLAY) (mal_ALuint source);
typedef void (MAL_AL_APIENTRY * MAL_LPALSOURCESTOP) (mal_ALuint source);
typedef void (MAL_AL_APIENTRY * MAL_LPALSOURCEREWIND) (mal_ALuint source);
typedef void (MAL_AL_APIENTRY * MAL_LPALSOURCEPAUSE) (mal_ALuint source);
typedef void (MAL_AL_APIENTRY * MAL_LPALSOURCEQUEUEBUFFERS) (mal_ALuint source, mal_ALsizei nb, const mal_ALuint *buffers);
typedef void (MAL_AL_APIENTRY * MAL_LPALSOURCEUNQUEUEBUFFERS)(mal_ALuint source, mal_ALsizei nb, mal_ALuint *buffers);
typedef void (MAL_AL_APIENTRY * MAL_LPALGENBUFFERS) (mal_ALsizei n, mal_ALuint *buffers);
typedef void (MAL_AL_APIENTRY * MAL_LPALDELETEBUFFERS) (mal_ALsizei n, const mal_ALuint *buffers);
typedef mal_ALboolean (MAL_AL_APIENTRY * MAL_LPALISBUFFER) (mal_ALuint buffer);
typedef void (MAL_AL_APIENTRY * MAL_LPALBUFFERDATA) (mal_ALuint buffer, mal_ALenum format, const mal_ALvoid *data, mal_ALsizei size, mal_ALsizei freq);
typedef void (MAL_AL_APIENTRY * MAL_LPALBUFFERF) (mal_ALuint buffer, mal_ALenum param, mal_ALfloat value);
typedef void (MAL_AL_APIENTRY * MAL_LPALBUFFER3F) (mal_ALuint buffer, mal_ALenum param, mal_ALfloat value1, mal_ALfloat value2, mal_ALfloat value3);
typedef void (MAL_AL_APIENTRY * MAL_LPALBUFFERFV) (mal_ALuint buffer, mal_ALenum param, const mal_ALfloat *values);
typedef void (MAL_AL_APIENTRY * MAL_LPALBUFFERI) (mal_ALuint buffer, mal_ALenum param, mal_ALint value);
typedef void (MAL_AL_APIENTRY * MAL_LPALBUFFER3I) (mal_ALuint buffer, mal_ALenum param, mal_ALint value1, mal_ALint value2, mal_ALint value3);
typedef void (MAL_AL_APIENTRY * MAL_LPALBUFFERIV) (mal_ALuint buffer, mal_ALenum param, const mal_ALint *values);
typedef void (MAL_AL_APIENTRY * MAL_LPALGETBUFFERF) (mal_ALuint buffer, mal_ALenum param, mal_ALfloat *value);
typedef void (MAL_AL_APIENTRY * MAL_LPALGETBUFFER3F) (mal_ALuint buffer, mal_ALenum param, mal_ALfloat *value1, mal_ALfloat *value2, mal_ALfloat *value3);
typedef void (MAL_AL_APIENTRY * MAL_LPALGETBUFFERFV) (mal_ALuint buffer, mal_ALenum param, mal_ALfloat *values);
typedef void (MAL_AL_APIENTRY * MAL_LPALGETBUFFERI) (mal_ALuint buffer, mal_ALenum param, mal_ALint *value);
typedef void (MAL_AL_APIENTRY * MAL_LPALGETBUFFER3I) (mal_ALuint buffer, mal_ALenum param, mal_ALint *value1, mal_ALint *value2, mal_ALint *value3);
typedef void (MAL_AL_APIENTRY * MAL_LPALGETBUFFERIV) (mal_ALuint buffer, mal_ALenum param, mal_ALint *values);
mal_bool32 mal_context_is_device_id_equal__openal(mal_context* pContext, const mal_device_id* pID0, const mal_device_id* pID1)
{
mal_assert(pContext != NULL);
mal_assert(pID0 != NULL);
mal_assert(pID1 != NULL);
(void)pContext;
return mal_strcmp(pID0->openal, pID1->openal) == 0;
}
mal_result mal_context_enumerate_devices__openal(mal_context* pContext, mal_enum_devices_callback_proc callback, void* pUserData)
{
mal_assert(pContext != NULL);
mal_assert(callback != NULL);
if (pContext->openal.isEnumerationSupported) {
mal_bool32 isTerminated = MAL_FALSE;
// Playback
if (!isTerminated) {
const mal_ALCchar* pPlaybackDeviceNames = ((MAL_LPALCGETSTRING)pContext->openal.alcGetString)(NULL, MAL_ALC_DEVICE_SPECIFIER);
if (pPlaybackDeviceNames == NULL) {
return MAL_NO_DEVICE;
}
// Each device is stored in pDeviceNames, separated by a null-terminator. The string itself is double-null-terminated.
const mal_ALCchar* pNextPlaybackDeviceName = pPlaybackDeviceNames;
while (pNextPlaybackDeviceName[0] != '\0') {
mal_device_info deviceInfo;
mal_zero_object(&deviceInfo);
mal_strncpy_s(deviceInfo.id.openal, sizeof(deviceInfo.id.openal), (const char*)pNextPlaybackDeviceName, (size_t)-1);
mal_strncpy_s(deviceInfo.name, sizeof(deviceInfo.name), (const char*)pNextPlaybackDeviceName, (size_t)-1);
mal_bool32 cbResult = callback(pContext, mal_device_type_playback, &deviceInfo, pUserData);
if (cbResult == MAL_FALSE) {
isTerminated = MAL_TRUE;
break;
}
// Move to the next device name.
while (*pNextPlaybackDeviceName != '\0') {
pNextPlaybackDeviceName += 1;
}
// Skip past the null terminator.
pNextPlaybackDeviceName += 1;
};
}
// Capture
if (!isTerminated) {
const mal_ALCchar* pCaptureDeviceNames = ((MAL_LPALCGETSTRING)pContext->openal.alcGetString)(NULL, MAL_ALC_CAPTURE_DEVICE_SPECIFIER);
if (pCaptureDeviceNames == NULL) {
return MAL_NO_DEVICE;
}
const mal_ALCchar* pNextCaptureDeviceName = pCaptureDeviceNames;
while (pNextCaptureDeviceName[0] != '\0') {
mal_device_info deviceInfo;
mal_zero_object(&deviceInfo);
mal_strncpy_s(deviceInfo.id.openal, sizeof(deviceInfo.id.openal), (const char*)pNextCaptureDeviceName, (size_t)-1);
mal_strncpy_s(deviceInfo.name, sizeof(deviceInfo.name), (const char*)pNextCaptureDeviceName, (size_t)-1);
mal_bool32 cbResult = callback(pContext, mal_device_type_capture, &deviceInfo, pUserData);
if (cbResult == MAL_FALSE) {
isTerminated = MAL_TRUE;
break;
}
// Move to the next device name.
while (*pNextCaptureDeviceName != '\0') {
pNextCaptureDeviceName += 1;
}
// Skip past the null terminator.
pNextCaptureDeviceName += 1;
};
}
} else {
// Enumeration is not supported. Use default devices.
mal_bool32 cbResult = MAL_TRUE;
// Playback.
if (cbResult) {
mal_device_info deviceInfo;
mal_zero_object(&deviceInfo);
mal_strncpy_s(deviceInfo.name, sizeof(deviceInfo.name), MAL_DEFAULT_PLAYBACK_DEVICE_NAME, (size_t)-1);
cbResult = callback(pContext, mal_device_type_playback, &deviceInfo, pUserData);
}
// Capture.
if (cbResult) {
mal_device_info deviceInfo;
mal_zero_object(&deviceInfo);
mal_strncpy_s(deviceInfo.name, sizeof(deviceInfo.name), MAL_DEFAULT_CAPTURE_DEVICE_NAME, (size_t)-1);
cbResult = callback(pContext, mal_device_type_capture, &deviceInfo, pUserData);
}
}
return MAL_SUCCESS;
}
typedef struct
{
mal_device_type deviceType;
const mal_device_id* pDeviceID;
mal_share_mode shareMode;
mal_device_info* pDeviceInfo;
mal_bool32 foundDevice;
} mal_context_get_device_info_enum_callback_data__openal;
mal_bool32 mal_context_get_device_info_enum_callback__openal(mal_context* pContext, mal_device_type deviceType, const mal_device_info* pDeviceInfo, void* pUserData)
{
mal_context_get_device_info_enum_callback_data__openal* pData = (mal_context_get_device_info_enum_callback_data__openal*)pUserData;
mal_assert(pData != NULL);
if (pData->deviceType == deviceType && mal_context_is_device_id_equal__openal(pContext, pData->pDeviceID, &pDeviceInfo->id)) {
mal_strncpy_s(pData->pDeviceInfo->name, sizeof(pData->pDeviceInfo->name), pDeviceInfo->name, (size_t)-1);
pData->foundDevice = MAL_TRUE;
}
// Keep enumerating until we have found the device.
return !pData->foundDevice;
}
mal_result mal_context_get_device_info__openal(mal_context* pContext, mal_device_type deviceType, const mal_device_id* pDeviceID, mal_share_mode shareMode, mal_device_info* pDeviceInfo)
{
mal_assert(pContext != NULL);
(void)shareMode;
// Name / Description
if (pDeviceID == NULL) {
if (deviceType == mal_device_type_playback) {
mal_strncpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), MAL_DEFAULT_PLAYBACK_DEVICE_NAME, (size_t)-1);
} else {
mal_strncpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), MAL_DEFAULT_CAPTURE_DEVICE_NAME, (size_t)-1);
}
return MAL_SUCCESS;
} else {
mal_context_get_device_info_enum_callback_data__openal data;
data.deviceType = deviceType;
data.pDeviceID = pDeviceID;
data.shareMode = shareMode;
data.pDeviceInfo = pDeviceInfo;
data.foundDevice = MAL_FALSE;
mal_result result = mal_context_enumerate_devices__openal(pContext, mal_context_get_device_info_enum_callback__openal, &data);
if (result != MAL_SUCCESS) {
return result;
}
if (!data.foundDevice) {
return MAL_NO_DEVICE;
}
}
// mini_al's OpenAL backend only supports:
// - mono and stereo
// - u8, s16 and f32
// - All standard sample rates
pDeviceInfo->minChannels = 1;
pDeviceInfo->maxChannels = 2;
pDeviceInfo->minSampleRate = MAL_MIN_SAMPLE_RATE;
pDeviceInfo->maxSampleRate = MAL_MAX_SAMPLE_RATE;
pDeviceInfo->formatCount = 2;
pDeviceInfo->formats[0] = mal_format_u8;
pDeviceInfo->formats[1] = mal_format_s16;
if (pContext->openal.isFloat32Supported) {
pDeviceInfo->formats[pDeviceInfo->formatCount] = mal_format_f32;
pDeviceInfo->formatCount += 1;
}
return MAL_SUCCESS;
}
void mal_device_uninit__openal(mal_device* pDevice)
{
mal_assert(pDevice != NULL);
// Delete buffers and source first.
((MAL_LPALCMAKECONTEXTCURRENT)pDevice->pContext->openal.alcMakeContextCurrent)((mal_ALCcontext*)pDevice->openal.pContextALC);
if (pDevice->openal.sourceAL != 0) {
((MAL_LPALDELETESOURCES)pDevice->pContext->openal.alDeleteSources)(1, (const mal_ALuint*)&pDevice->openal.sourceAL);
}
if (pDevice->periods > 0 && pDevice->openal.buffersAL[0] != 0) {
((MAL_LPALDELETEBUFFERS)pDevice->pContext->openal.alDeleteBuffers)(pDevice->periods, (const mal_ALuint*)pDevice->openal.buffersAL);
}
// Now that resources have been deleted we can destroy the OpenAL context and close the device.
((MAL_LPALCMAKECONTEXTCURRENT)pDevice->pContext->openal.alcMakeContextCurrent)(NULL);
((MAL_LPALCDESTROYCONTEXT)pDevice->pContext->openal.alcDestroyContext)((mal_ALCcontext*)pDevice->openal.pContextALC);
if (pDevice->type == mal_device_type_playback) {
((MAL_LPALCCLOSEDEVICE)pDevice->pContext->openal.alcCloseDevice)((mal_ALCdevice*)pDevice->openal.pDeviceALC);
} else {
((MAL_LPALCCAPTURECLOSEDEVICE)pDevice->pContext->openal.alcCaptureCloseDevice)((mal_ALCdevice*)pDevice->openal.pDeviceALC);
}
mal_free(pDevice->openal.pIntermediaryBuffer);
}
mal_result mal_device_init__openal(mal_context* pContext, mal_device_type type, const 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;
}
// Try calculating an appropriate default buffer size.
if (pDevice->bufferSizeInFrames == 0) {
pDevice->bufferSizeInFrames = mal_calculate_buffer_size_in_frames_from_milliseconds(pDevice->bufferSizeInMilliseconds, pDevice->sampleRate);
if (pDevice->usingDefaultBufferSize) {
float bufferSizeScaleFactor = 3;
pDevice->bufferSizeInFrames = mal_scale_buffer_size(pDevice->bufferSizeInFrames, bufferSizeScaleFactor);
}
}
mal_ALCsizei bufferSizeInSamplesAL = pDevice->bufferSizeInFrames;
mal_ALCuint frequencyAL = pConfig->sampleRate;
mal_uint32 channelsAL = 0;
// OpenAL currently only supports only mono and stereo. TODO: Check for the AL_EXT_MCFORMATS extension and use one of those formats for quad, 5.1, etc.
mal_ALCenum formatAL = 0;
if (pConfig->channels == 1) {
// Mono.
channelsAL = 1;
if (pConfig->format == mal_format_f32) {
if (pContext->openal.isFloat32Supported) {
formatAL = MAL_AL_FORMAT_MONO_FLOAT32;
} else {
formatAL = MAL_AL_FORMAT_MONO16;
}
} else if (pConfig->format == mal_format_s32) {
formatAL = MAL_AL_FORMAT_MONO16;
} else if (pConfig->format == mal_format_s24) {
formatAL = MAL_AL_FORMAT_MONO16;
} else if (pConfig->format == mal_format_s16) {
formatAL = MAL_AL_FORMAT_MONO16;
} else if (pConfig->format == mal_format_u8) {
formatAL = MAL_AL_FORMAT_MONO8;
}
} else {
// Stereo.
channelsAL = 2;
if (pConfig->format == mal_format_f32) {
if (pContext->openal.isFloat32Supported) {
formatAL = MAL_AL_FORMAT_STEREO_FLOAT32;
} else {
formatAL = MAL_AL_FORMAT_STEREO16;
}
} else if (pConfig->format == mal_format_s32) {
formatAL = MAL_AL_FORMAT_STEREO16;
} else if (pConfig->format == mal_format_s24) {
formatAL = MAL_AL_FORMAT_STEREO16;
} else if (pConfig->format == mal_format_s16) {
formatAL = MAL_AL_FORMAT_STEREO16;
} else if (pConfig->format == mal_format_u8) {
formatAL = MAL_AL_FORMAT_STEREO8;
}
}
if (formatAL == 0) {
return mal_context_post_error(pContext, NULL, MAL_LOG_LEVEL_ERROR, "[OpenAL] Format not supported.", MAL_FORMAT_NOT_SUPPORTED);
}
bufferSizeInSamplesAL *= channelsAL;
// OpenAL feels a bit unintuitive to me... The global object is a device, and it would appear that each device can have
// many context's...
mal_ALCdevice* pDeviceALC = NULL;
if (type == mal_device_type_playback) {
pDeviceALC = ((MAL_LPALCOPENDEVICE)pContext->openal.alcOpenDevice)((pDeviceID == NULL) ? NULL : pDeviceID->openal);
} else {
pDeviceALC = ((MAL_LPALCCAPTUREOPENDEVICE)pContext->openal.alcCaptureOpenDevice)((pDeviceID == NULL) ? NULL : pDeviceID->openal, frequencyAL, formatAL, bufferSizeInSamplesAL);
}
if (pDeviceALC == NULL) {
return mal_context_post_error(pContext, NULL, MAL_LOG_LEVEL_ERROR, "[OpenAL] Failed to open device.", MAL_FAILED_TO_INIT_BACKEND);
}
// A context is only required for playback.
mal_ALCcontext* pContextALC = NULL;
if (pDevice->type == mal_device_type_playback) {
pContextALC = ((MAL_LPALCCREATECONTEXT)pContext->openal.alcCreateContext)(pDeviceALC, NULL);
if (pContextALC == NULL) {
((MAL_LPALCCLOSEDEVICE)pDevice->pContext->openal.alcCloseDevice)(pDeviceALC);
return mal_context_post_error(pContext, NULL, MAL_LOG_LEVEL_ERROR, "[OpenAL] Failed to open OpenAL context.", MAL_FAILED_TO_INIT_BACKEND);
}
((MAL_LPALCMAKECONTEXTCURRENT)pDevice->pContext->openal.alcMakeContextCurrent)(pContextALC);
mal_ALuint sourceAL;
((MAL_LPALGENSOURCES)pDevice->pContext->openal.alGenSources)(1, &sourceAL);
pDevice->openal.sourceAL = sourceAL;
// We create the buffers, but only fill and queue them when the device is started.
mal_ALuint buffersAL[MAL_MAX_PERIODS_OPENAL];
((MAL_LPALGENBUFFERS)pDevice->pContext->openal.alGenBuffers)(pDevice->periods, buffersAL);
for (mal_uint32 i = 0; i < pDevice->periods; ++i) {
pDevice->openal.buffersAL[i] = buffersAL[i];
}
}
pDevice->internalChannels = channelsAL;
pDevice->internalSampleRate = frequencyAL;
switch (formatAL)
{
case MAL_AL_FORMAT_MONO8:
case MAL_AL_FORMAT_STEREO8:
case MAL_AL_FORMAT_REAR8:
case MAL_AL_FORMAT_QUAD8:
case MAL_AL_FORMAT_51CHN8:
case MAL_AL_FORMAT_61CHN8:
case MAL_AL_FORMAT_71CHN8:
{
pDevice->internalFormat = mal_format_u8;
} break;
case MAL_AL_FORMAT_MONO16:
case MAL_AL_FORMAT_STEREO16:
case MAL_AL_FORMAT_REAR16:
case MAL_AL_FORMAT_QUAD16:
case MAL_AL_FORMAT_51CHN16:
case MAL_AL_FORMAT_61CHN16:
case MAL_AL_FORMAT_71CHN16:
{
pDevice->internalFormat = mal_format_s16;
} break;
case MAL_AL_FORMAT_REAR32:
case MAL_AL_FORMAT_QUAD32:
case MAL_AL_FORMAT_51CHN32:
case MAL_AL_FORMAT_61CHN32:
case MAL_AL_FORMAT_71CHN32:
{
pDevice->internalFormat = mal_format_s32;
} break;
case MAL_AL_FORMAT_MONO_FLOAT32:
case MAL_AL_FORMAT_STEREO_FLOAT32:
{
pDevice->internalFormat = mal_format_f32;
} break;
}
// From what I can tell, the ordering of channels is fixed for OpenAL.
switch (formatAL)
{
case MAL_AL_FORMAT_MONO8:
case MAL_AL_FORMAT_MONO16:
case MAL_AL_FORMAT_MONO_FLOAT32:
{
pDevice->internalChannelMap[0] = MAL_CHANNEL_FRONT_CENTER;
} break;
case MAL_AL_FORMAT_STEREO8:
case MAL_AL_FORMAT_STEREO16:
case MAL_AL_FORMAT_STEREO_FLOAT32:
{
pDevice->internalChannelMap[0] = MAL_CHANNEL_FRONT_LEFT;
pDevice->internalChannelMap[1] = MAL_CHANNEL_FRONT_RIGHT;
} break;
case MAL_AL_FORMAT_REAR8:
case MAL_AL_FORMAT_REAR16:
case MAL_AL_FORMAT_REAR32:
{
pDevice->internalChannelMap[0] = MAL_CHANNEL_BACK_LEFT;
pDevice->internalChannelMap[1] = MAL_CHANNEL_BACK_RIGHT;
} break;
case MAL_AL_FORMAT_QUAD8:
case MAL_AL_FORMAT_QUAD16:
case MAL_AL_FORMAT_QUAD32:
{
pDevice->internalChannelMap[0] = MAL_CHANNEL_FRONT_LEFT;
pDevice->internalChannelMap[1] = MAL_CHANNEL_FRONT_RIGHT;
pDevice->internalChannelMap[2] = MAL_CHANNEL_BACK_LEFT;
pDevice->internalChannelMap[3] = MAL_CHANNEL_BACK_RIGHT;
} break;
case MAL_AL_FORMAT_51CHN8:
case MAL_AL_FORMAT_51CHN16:
case MAL_AL_FORMAT_51CHN32:
{
pDevice->internalChannelMap[0] = MAL_CHANNEL_FRONT_LEFT;
pDevice->internalChannelMap[1] = MAL_CHANNEL_FRONT_RIGHT;
pDevice->internalChannelMap[2] = MAL_CHANNEL_FRONT_CENTER;
pDevice->internalChannelMap[3] = MAL_CHANNEL_LFE;
pDevice->internalChannelMap[4] = MAL_CHANNEL_BACK_LEFT;
pDevice->internalChannelMap[5] = MAL_CHANNEL_BACK_RIGHT;
} break;
case MAL_AL_FORMAT_61CHN8:
case MAL_AL_FORMAT_61CHN16:
case MAL_AL_FORMAT_61CHN32:
{
pDevice->internalChannelMap[0] = MAL_CHANNEL_FRONT_LEFT;
pDevice->internalChannelMap[1] = MAL_CHANNEL_FRONT_RIGHT;
pDevice->internalChannelMap[2] = MAL_CHANNEL_FRONT_CENTER;
pDevice->internalChannelMap[3] = MAL_CHANNEL_LFE;
pDevice->internalChannelMap[4] = MAL_CHANNEL_BACK_CENTER;
pDevice->internalChannelMap[5] = MAL_CHANNEL_SIDE_LEFT;
pDevice->internalChannelMap[6] = MAL_CHANNEL_SIDE_RIGHT;
} break;
case MAL_AL_FORMAT_71CHN8:
case MAL_AL_FORMAT_71CHN16:
case MAL_AL_FORMAT_71CHN32:
{
pDevice->internalChannelMap[0] = MAL_CHANNEL_FRONT_LEFT;
pDevice->internalChannelMap[1] = MAL_CHANNEL_FRONT_RIGHT;
pDevice->internalChannelMap[2] = MAL_CHANNEL_FRONT_CENTER;
pDevice->internalChannelMap[3] = MAL_CHANNEL_LFE;
pDevice->internalChannelMap[4] = MAL_CHANNEL_BACK_LEFT;
pDevice->internalChannelMap[5] = MAL_CHANNEL_BACK_RIGHT;
pDevice->internalChannelMap[6] = MAL_CHANNEL_SIDE_LEFT;
pDevice->internalChannelMap[7] = MAL_CHANNEL_SIDE_RIGHT;
} break;
default: break;
}
pDevice->openal.pDeviceALC = pDeviceALC;
pDevice->openal.pContextALC = pContextALC;
pDevice->openal.formatAL = formatAL;
pDevice->openal.subBufferSizeInFrames = pDevice->bufferSizeInFrames / pDevice->periods;
pDevice->openal.pIntermediaryBuffer = (mal_uint8*)mal_malloc(pDevice->openal.subBufferSizeInFrames * channelsAL * mal_get_bytes_per_sample(pDevice->internalFormat));
if (pDevice->openal.pIntermediaryBuffer == NULL) {
mal_device_uninit__openal(pDevice);
return mal_context_post_error(pContext, NULL, MAL_LOG_LEVEL_ERROR, "[OpenAL] Failed to allocate memory for intermediary buffer.", MAL_OUT_OF_MEMORY);
}
return MAL_SUCCESS;
}
mal_result mal_device_start__openal(mal_device* pDevice)
{
mal_assert(pDevice != NULL);
if (pDevice->type == mal_device_type_playback) {
// Playback.
//
// When starting playback we want to ensure each buffer is filled and queued before playing the source.
pDevice->openal.iNextBuffer = 0;
((MAL_LPALCMAKECONTEXTCURRENT)pDevice->pContext->openal.alcMakeContextCurrent)((mal_ALCcontext*)pDevice->openal.pContextALC);
for (mal_uint32 i = 0; i < pDevice->periods; ++i) {
mal_device__read_frames_from_client(pDevice, pDevice->openal.subBufferSizeInFrames, pDevice->openal.pIntermediaryBuffer);
mal_ALuint bufferAL = pDevice->openal.buffersAL[i];
((MAL_LPALBUFFERDATA)pDevice->pContext->openal.alBufferData)(bufferAL, pDevice->openal.formatAL, pDevice->openal.pIntermediaryBuffer, pDevice->openal.subBufferSizeInFrames * pDevice->internalChannels * mal_get_bytes_per_sample(pDevice->internalFormat), pDevice->internalSampleRate);
((MAL_LPALSOURCEQUEUEBUFFERS)pDevice->pContext->openal.alSourceQueueBuffers)(pDevice->openal.sourceAL, 1, &bufferAL);
}
// Start the source only after filling and queueing each buffer.
((MAL_LPALSOURCEPLAY)pDevice->pContext->openal.alSourcePlay)(pDevice->openal.sourceAL);
} else {
// Capture.
((MAL_LPALCCAPTURESTART)pDevice->pContext->openal.alcCaptureStart)((mal_ALCdevice*)pDevice->openal.pDeviceALC);
}
return MAL_SUCCESS;
}
mal_result mal_device_stop__openal(mal_device* pDevice)
{
mal_assert(pDevice != NULL);
if (pDevice->type == mal_device_type_playback) {
((MAL_LPALCMAKECONTEXTCURRENT)pDevice->pContext->openal.alcMakeContextCurrent)((mal_ALCcontext*)pDevice->openal.pContextALC);
((MAL_LPALSOURCESTOP)pDevice->pContext->openal.alSourceStop)(pDevice->openal.sourceAL);
} else {
((MAL_LPALCCAPTURESTOP)pDevice->pContext->openal.alcCaptureStop)((mal_ALCdevice*)pDevice->openal.pDeviceALC);
}
return MAL_SUCCESS;
}
mal_result mal_device_break_main_loop__openal(mal_device* pDevice)
{
mal_assert(pDevice != NULL);
pDevice->openal.breakFromMainLoop = MAL_TRUE;
return MAL_SUCCESS;
}
mal_uint32 mal_device__get_available_frames__openal(mal_device* pDevice)
{
mal_assert(pDevice != NULL);
if (pDevice->type == mal_device_type_playback) {
((MAL_LPALCMAKECONTEXTCURRENT)pDevice->pContext->openal.alcMakeContextCurrent)((mal_ALCcontext*)pDevice->openal.pContextALC);
mal_ALint processedBufferCount = 0;
((MAL_LPALGETSOURCEI)pDevice->pContext->openal.alGetSourcei)(pDevice->openal.sourceAL, MAL_AL_BUFFERS_PROCESSED, &processedBufferCount);
return processedBufferCount * pDevice->openal.subBufferSizeInFrames;
} else {
mal_ALint samplesAvailable = 0;
((MAL_LPALCGETINTEGERV)pDevice->pContext->openal.alcGetIntegerv)((mal_ALCdevice*)pDevice->openal.pDeviceALC, MAL_ALC_CAPTURE_SAMPLES, 1, &samplesAvailable);
return samplesAvailable / pDevice->channels;
}
}
mal_uint32 mal_device__wait_for_frames__openal(mal_device* pDevice)
{
mal_assert(pDevice != NULL);
while (!pDevice->openal.breakFromMainLoop) {
mal_uint32 framesAvailable = mal_device__get_available_frames__openal(pDevice);
if (framesAvailable > 0) {
return framesAvailable;
}
mal_sleep(1);
}
// We'll get here if the loop was terminated. When capturing we want to return whatever is available. For playback we just drop it.
if (pDevice->type == mal_device_type_playback) {
return 0;
} else {
return mal_device__get_available_frames__openal(pDevice);
}
}
mal_result mal_device_main_loop__openal(mal_device* pDevice)
{
mal_assert(pDevice != NULL);
pDevice->openal.breakFromMainLoop = MAL_FALSE;
while (!pDevice->openal.breakFromMainLoop) {
mal_uint32 framesAvailable = mal_device__wait_for_frames__openal(pDevice);
if (framesAvailable == 0) {
continue;
}
// If it's a playback device, don't bother grabbing more data if the device is being stopped.
if (pDevice->openal.breakFromMainLoop && pDevice->type == mal_device_type_playback) {
return MAL_FALSE;
}
if (pDevice->type == mal_device_type_playback) {
while (framesAvailable > 0) {
mal_uint32 framesToRead = (framesAvailable > pDevice->openal.subBufferSizeInFrames) ? pDevice->openal.subBufferSizeInFrames : framesAvailable;
mal_ALuint bufferAL = pDevice->openal.buffersAL[pDevice->openal.iNextBuffer];
pDevice->openal.iNextBuffer = (pDevice->openal.iNextBuffer + 1) % pDevice->periods;
mal_device__read_frames_from_client(pDevice, framesToRead, pDevice->openal.pIntermediaryBuffer);
((MAL_LPALCMAKECONTEXTCURRENT)pDevice->pContext->openal.alcMakeContextCurrent)((mal_ALCcontext*)pDevice->openal.pContextALC);
((MAL_LPALSOURCEUNQUEUEBUFFERS)pDevice->pContext->openal.alSourceUnqueueBuffers)(pDevice->openal.sourceAL, 1, &bufferAL);
((MAL_LPALBUFFERDATA)pDevice->pContext->openal.alBufferData)(bufferAL, pDevice->openal.formatAL, pDevice->openal.pIntermediaryBuffer, pDevice->openal.subBufferSizeInFrames * pDevice->internalChannels * mal_get_bytes_per_sample(pDevice->internalFormat), pDevice->internalSampleRate);
((MAL_LPALSOURCEQUEUEBUFFERS)pDevice->pContext->openal.alSourceQueueBuffers)(pDevice->openal.sourceAL, 1, &bufferAL);
framesAvailable -= framesToRead;
}
// There's a chance the source has stopped playing due to there not being any buffer's queue. Make sure it's restarted.
mal_ALenum state;
((MAL_LPALGETSOURCEI)pDevice->pContext->openal.alGetSourcei)(pDevice->openal.sourceAL, MAL_AL_SOURCE_STATE, &state);
if (state != MAL_AL_PLAYING) {
((MAL_LPALSOURCEPLAY)pDevice->pContext->openal.alSourcePlay)(pDevice->openal.sourceAL);
}
} else {
while (framesAvailable > 0) {
mal_uint32 framesToSend = (framesAvailable > pDevice->openal.subBufferSizeInFrames) ? pDevice->openal.subBufferSizeInFrames : framesAvailable;
((MAL_LPALCCAPTURESAMPLES)pDevice->pContext->openal.alcCaptureSamples)((mal_ALCdevice*)pDevice->openal.pDeviceALC, pDevice->openal.pIntermediaryBuffer, framesToSend);
mal_device__send_frames_to_client(pDevice, framesToSend, pDevice->openal.pIntermediaryBuffer);
framesAvailable -= framesToSend;
}
}
}
return MAL_SUCCESS;
}
mal_result mal_context_uninit__openal(mal_context* pContext)
{
mal_assert(pContext != NULL);
mal_assert(pContext->backend == mal_backend_openal);
#ifndef MAL_NO_RUNTIME_LINKING
mal_dlclose(pContext->openal.hOpenAL);
#endif
return MAL_SUCCESS;
}
mal_result mal_context_init__openal(mal_context* pContext)
{
mal_assert(pContext != NULL);
#ifndef MAL_NO_RUNTIME_LINKING
const char* libNames[] = {
#if defined(MAL_WIN32)
"OpenAL32.dll",
"soft_oal.dll"
#endif
#if defined(MAL_UNIX) && !defined(MAL_APPLE)
"libopenal.so",
"libopenal.so.1"
#endif
#if defined(MAL_APPLE)
"OpenAL.framework/OpenAL"
#endif
};
for (size_t i = 0; i < mal_countof(libNames); ++i) {
pContext->openal.hOpenAL = mal_dlopen(libNames[i]);
if (pContext->openal.hOpenAL != NULL) {
break;
}
}
if (pContext->openal.hOpenAL == NULL) {
return MAL_FAILED_TO_INIT_BACKEND;
}
pContext->openal.alcCreateContext = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alcCreateContext");
pContext->openal.alcMakeContextCurrent = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alcMakeContextCurrent");
pContext->openal.alcProcessContext = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alcProcessContext");
pContext->openal.alcSuspendContext = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alcSuspendContext");
pContext->openal.alcDestroyContext = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alcDestroyContext");
pContext->openal.alcGetCurrentContext = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alcGetCurrentContext");
pContext->openal.alcGetContextsDevice = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alcGetContextsDevice");
pContext->openal.alcOpenDevice = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alcOpenDevice");
pContext->openal.alcCloseDevice = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alcCloseDevice");
pContext->openal.alcGetError = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alcGetError");
pContext->openal.alcIsExtensionPresent = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alcIsExtensionPresent");
pContext->openal.alcGetProcAddress = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alcGetProcAddress");
pContext->openal.alcGetEnumValue = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alcGetEnumValue");
pContext->openal.alcGetString = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alcGetString");
pContext->openal.alcGetIntegerv = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alcGetIntegerv");
pContext->openal.alcCaptureOpenDevice = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alcCaptureOpenDevice");
pContext->openal.alcCaptureCloseDevice = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alcCaptureCloseDevice");
pContext->openal.alcCaptureStart = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alcCaptureStart");
pContext->openal.alcCaptureStop = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alcCaptureStop");
pContext->openal.alcCaptureSamples = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alcCaptureSamples");
pContext->openal.alEnable = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alEnable");
pContext->openal.alDisable = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alDisable");
pContext->openal.alIsEnabled = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alIsEnabled");
pContext->openal.alGetString = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alGetString");
pContext->openal.alGetBooleanv = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alGetBooleanv");
pContext->openal.alGetIntegerv = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alGetIntegerv");
pContext->openal.alGetFloatv = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alGetFloatv");
pContext->openal.alGetDoublev = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alGetDoublev");
pContext->openal.alGetBoolean = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alGetBoolean");
pContext->openal.alGetInteger = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alGetInteger");
pContext->openal.alGetFloat = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alGetFloat");
pContext->openal.alGetDouble = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alGetDouble");
pContext->openal.alGetError = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alGetError");
pContext->openal.alIsExtensionPresent = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alIsExtensionPresent");
pContext->openal.alGetProcAddress = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alGetProcAddress");
pContext->openal.alGetEnumValue = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alGetEnumValue");
pContext->openal.alGenSources = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alGenSources");
pContext->openal.alDeleteSources = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alDeleteSources");
pContext->openal.alIsSource = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alIsSource");
pContext->openal.alSourcef = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alSourcef");
pContext->openal.alSource3f = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alSource3f");
pContext->openal.alSourcefv = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alSourcefv");
pContext->openal.alSourcei = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alSourcei");
pContext->openal.alSource3i = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alSource3i");
pContext->openal.alSourceiv = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alSourceiv");
pContext->openal.alGetSourcef = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alGetSourcef");
pContext->openal.alGetSource3f = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alGetSource3f");
pContext->openal.alGetSourcefv = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alGetSourcefv");
pContext->openal.alGetSourcei = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alGetSourcei");
pContext->openal.alGetSource3i = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alGetSource3i");
pContext->openal.alGetSourceiv = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alGetSourceiv");
pContext->openal.alSourcePlayv = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alSourcePlayv");
pContext->openal.alSourceStopv = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alSourceStopv");
pContext->openal.alSourceRewindv = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alSourceRewindv");
pContext->openal.alSourcePausev = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alSourcePausev");
pContext->openal.alSourcePlay = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alSourcePlay");
pContext->openal.alSourceStop = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alSourceStop");
pContext->openal.alSourceRewind = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alSourceRewind");
pContext->openal.alSourcePause = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alSourcePause");
pContext->openal.alSourceQueueBuffers = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alSourceQueueBuffers");
pContext->openal.alSourceUnqueueBuffers = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alSourceUnqueueBuffers");
pContext->openal.alGenBuffers = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alGenBuffers");
pContext->openal.alDeleteBuffers = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alDeleteBuffers");
pContext->openal.alIsBuffer = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alIsBuffer");
pContext->openal.alBufferData = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alBufferData");
pContext->openal.alBufferf = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alBufferf");
pContext->openal.alBuffer3f = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alBuffer3f");
pContext->openal.alBufferfv = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alBufferfv");
pContext->openal.alBufferi = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alBufferi");
pContext->openal.alBuffer3i = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alBuffer3i");
pContext->openal.alBufferiv = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alBufferiv");
pContext->openal.alGetBufferf = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alGetBufferf");
pContext->openal.alGetBuffer3f = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alGetBuffer3f");
pContext->openal.alGetBufferfv = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alGetBufferfv");
pContext->openal.alGetBufferi = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alGetBufferi");
pContext->openal.alGetBuffer3i = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alGetBuffer3i");
pContext->openal.alGetBufferiv = (mal_proc)mal_dlsym(pContext->openal.hOpenAL, "alGetBufferiv");
#else
pContext->openal.alcCreateContext = (mal_proc)alcCreateContext;
pContext->openal.alcMakeContextCurrent = (mal_proc)alcMakeContextCurrent;
pContext->openal.alcProcessContext = (mal_proc)alcProcessContext;
pContext->openal.alcSuspendContext = (mal_proc)alcSuspendContext;
pContext->openal.alcDestroyContext = (mal_proc)alcDestroyContext;
pContext->openal.alcGetCurrentContext = (mal_proc)alcGetCurrentContext;
pContext->openal.alcGetContextsDevice = (mal_proc)alcGetContextsDevice;
pContext->openal.alcOpenDevice = (mal_proc)alcOpenDevice;
pContext->openal.alcCloseDevice = (mal_proc)alcCloseDevice;
pContext->openal.alcGetError = (mal_proc)alcGetError;
pContext->openal.alcIsExtensionPresent = (mal_proc)alcIsExtensionPresent;
pContext->openal.alcGetProcAddress = (mal_proc)alcGetProcAddress;
pContext->openal.alcGetEnumValue = (mal_proc)alcGetEnumValue;
pContext->openal.alcGetString = (mal_proc)alcGetString;
pContext->openal.alcGetIntegerv = (mal_proc)alcGetIntegerv;
pContext->openal.alcCaptureOpenDevice = (mal_proc)alcCaptureOpenDevice;
pContext->openal.alcCaptureCloseDevice = (mal_proc)alcCaptureCloseDevice;
pContext->openal.alcCaptureStart = (mal_proc)alcCaptureStart;
pContext->openal.alcCaptureStop = (mal_proc)alcCaptureStop;
pContext->openal.alcCaptureSamples = (mal_proc)alcCaptureSamples;
pContext->openal.alEnable = (mal_proc)alEnable;
pContext->openal.alDisable = (mal_proc)alDisable;
pContext->openal.alIsEnabled = (mal_proc)alIsEnabled;
pContext->openal.alGetString = (mal_proc)alGetString;
pContext->openal.alGetBooleanv = (mal_proc)alGetBooleanv;
pContext->openal.alGetIntegerv = (mal_proc)alGetIntegerv;
pContext->openal.alGetFloatv = (mal_proc)alGetFloatv;
pContext->openal.alGetDoublev = (mal_proc)alGetDoublev;
pContext->openal.alGetBoolean = (mal_proc)alGetBoolean;
pContext->openal.alGetInteger = (mal_proc)alGetInteger;
pContext->openal.alGetFloat = (mal_proc)alGetFloat;
pContext->openal.alGetDouble = (mal_proc)alGetDouble;
pContext->openal.alGetError = (mal_proc)alGetError;
pContext->openal.alIsExtensionPresent = (mal_proc)alIsExtensionPresent;
pContext->openal.alGetProcAddress = (mal_proc)alGetProcAddress;
pContext->openal.alGetEnumValue = (mal_proc)alGetEnumValue;
pContext->openal.alGenSources = (mal_proc)alGenSources;
pContext->openal.alDeleteSources = (mal_proc)alDeleteSources;
pContext->openal.alIsSource = (mal_proc)alIsSource;
pContext->openal.alSourcef = (mal_proc)alSourcef;
pContext->openal.alSource3f = (mal_proc)alSource3f;
pContext->openal.alSourcefv = (mal_proc)alSourcefv;
pContext->openal.alSourcei = (mal_proc)alSourcei;
pContext->openal.alSource3i = (mal_proc)alSource3i;
pContext->openal.alSourceiv = (mal_proc)alSourceiv;
pContext->openal.alGetSourcef = (mal_proc)alGetSourcef;
pContext->openal.alGetSource3f = (mal_proc)alGetSource3f;
pContext->openal.alGetSourcefv = (mal_proc)alGetSourcefv;
pContext->openal.alGetSourcei = (mal_proc)alGetSourcei;
pContext->openal.alGetSource3i = (mal_proc)alGetSource3i;
pContext->openal.alGetSourceiv = (mal_proc)alGetSourceiv;
pContext->openal.alSourcePlayv = (mal_proc)alSourcePlayv;
pContext->openal.alSourceStopv = (mal_proc)alSourceStopv;
pContext->openal.alSourceRewindv = (mal_proc)alSourceRewindv;
pContext->openal.alSourcePausev = (mal_proc)alSourcePausev;
pContext->openal.alSourcePlay = (mal_proc)alSourcePlay;
pContext->openal.alSourceStop = (mal_proc)alSourceStop;
pContext->openal.alSourceRewind = (mal_proc)alSourceRewind;
pContext->openal.alSourcePause = (mal_proc)alSourcePause;
pContext->openal.alSourceQueueBuffers = (mal_proc)alSourceQueueBuffers;
pContext->openal.alSourceUnqueueBuffers = (mal_proc)alSourceUnqueueBuffers;
pContext->openal.alGenBuffers = (mal_proc)alGenBuffers;
pContext->openal.alDeleteBuffers = (mal_proc)alDeleteBuffers;
pContext->openal.alIsBuffer = (mal_proc)alIsBuffer;
pContext->openal.alBufferData = (mal_proc)alBufferData;
pContext->openal.alBufferf = (mal_proc)alBufferf;
pContext->openal.alBuffer3f = (mal_proc)alBuffer3f;
pContext->openal.alBufferfv = (mal_proc)alBufferfv;
pContext->openal.alBufferi = (mal_proc)alBufferi;
pContext->openal.alBuffer3i = (mal_proc)alBuffer3i;
pContext->openal.alBufferiv = (mal_proc)alBufferiv;
pContext->openal.alGetBufferf = (mal_proc)alGetBufferf;
pContext->openal.alGetBuffer3f = (mal_proc)alGetBuffer3f;
pContext->openal.alGetBufferfv = (mal_proc)alGetBufferfv;
pContext->openal.alGetBufferi = (mal_proc)alGetBufferi;
pContext->openal.alGetBuffer3i = (mal_proc)alGetBuffer3i;
pContext->openal.alGetBufferiv = (mal_proc)alGetBufferiv;
#endif
// We depend on the ALC_ENUMERATION_EXT extension for enumeration. If this is not supported we fall back to default devices.
pContext->openal.isEnumerationSupported = ((MAL_LPALCISEXTENSIONPRESENT)pContext->openal.alcIsExtensionPresent)(NULL, "ALC_ENUMERATION_EXT");
pContext->openal.isFloat32Supported = ((MAL_LPALISEXTENSIONPRESENT)pContext->openal.alIsExtensionPresent)("AL_EXT_float32");
pContext->openal.isMCFormatsSupported = ((MAL_LPALISEXTENSIONPRESENT)pContext->openal.alIsExtensionPresent)("AL_EXT_MCFORMATS");
pContext->onUninit = mal_context_uninit__openal;
pContext->onDeviceIDEqual = mal_context_is_device_id_equal__openal;
pContext->onEnumDevices = mal_context_enumerate_devices__openal;
pContext->onGetDeviceInfo = mal_context_get_device_info__openal;
pContext->onDeviceInit = mal_device_init__openal;
pContext->onDeviceUninit = mal_device_uninit__openal;
pContext->onDeviceStart = mal_device_start__openal;
pContext->onDeviceStop = mal_device_stop__openal;
pContext->onDeviceBreakMainLoop = mal_device_break_main_loop__openal;
pContext->onDeviceMainLoop = mal_device_main_loop__openal;
return MAL_SUCCESS;
}
#endif // OpenAL
mal_bool32 mal__is_channel_map_valid(const mal_channel* channelMap, mal_uint32 channels)
{
......@@ -21075,12 +19972,6 @@ mal_result mal_context_init(const mal_backend backends[], mal_uint32 backendCoun
result = mal_context_init__webaudio(pContext);
} break;
#endif
#ifdef MAL_HAS_OPENAL
case mal_backend_openal:
{
result = mal_context_init__openal(pContext);
} break;
#endif
#ifdef MAL_HAS_NULL
case mal_backend_null:
{
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment