Fix a potential bug with context configs.

This issue is related to how strings for select backends are not deeply
copied, but rather only have their pointers copied. This results in a
situation where the client may delete the strings they passed to the
context config assuming miniaudio makes a copy of it when in fact it
hasn't.
This commit is contained in:
David Reid
2019-03-30 12:25:01 +10:00
parent 26466bf28f
commit e915a82764
+138 -55
View File
@@ -1,6 +1,6 @@
/*
Audio playback and capture library. Choice of public domain or MIT-0. See license statements at the end of this file.
miniaudio (formerly mini_al) - v0.9.1 - 2019-03-17
miniaudio (formerly mini_al) - v0.9.2-dev - 2019-xx-xx
David Reid - davidreidsoftware@gmail.com
*/
@@ -1882,7 +1882,9 @@ typedef ma_bool32 (* ma_enum_devices_callback_proc)(ma_context* pContext, ma_dev
struct ma_context
{
ma_backend backend; // DirectSound, ALSA, etc.
ma_context_config config;
ma_log_proc logCallback;
ma_thread_priority threadPriority;
void* pUserData;
ma_mutex deviceEnumLock; // Used to make ma_context_get_devices() thread safe.
ma_mutex deviceInfoLock; // Used to make ma_context_get_device_info() thread safe.
ma_uint32 deviceInfoCapacity; // Total capacity of pDeviceInfos.
@@ -2005,6 +2007,7 @@ struct ma_context
ma_proc snd_config_update_free_global;
ma_mutex internalDeviceEnumLock;
ma_bool32 useVerboseDeviceEnumeration;
} alsa;
#endif
#ifdef MA_SUPPORT_PULSEAUDIO
@@ -2055,6 +2058,10 @@ struct ma_context
ma_proc pa_stream_drop;
ma_proc pa_stream_writable_size;
ma_proc pa_stream_readable_size;
char* pApplicationName;
char* pServerName;
ma_bool32 tryAutoSpawn;
} pulse;
#endif
#ifdef MA_SUPPORT_JACK
@@ -2077,6 +2084,9 @@ struct ma_context
ma_proc jack_port_name;
ma_proc jack_port_get_buffer;
ma_proc jack_free;
char* pClientName;
ma_bool32 tryStartServer;
} jack;
#endif
#ifdef MA_SUPPORT_COREAUDIO
@@ -3701,6 +3711,19 @@ int ma_strcmp(const char* str1, const char* str2)
return ((unsigned char*)str1)[0] - ((unsigned char*)str2)[0];
}
char* ma_copy_string(const char* src)
{
size_t sz = strlen(src)+1;
char* dst = (char*)ma_malloc(sz);
if (dst == NULL) {
return NULL;
}
ma_strcpy_s(dst, sz, src);
return dst;
}
// Thanks to good old Bit Twiddling Hacks for this one: http://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2
static MA_INLINE unsigned int ma_next_power_of_2(unsigned int x)
@@ -4299,7 +4322,7 @@ ma_result ma_thread_create__win32(ma_context* pContext, ma_thread* pThread, ma_t
return MA_FAILED_TO_CREATE_THREAD;
}
SetThreadPriority((HANDLE)pThread->win32.hThread, ma_thread_priority_to_win32(pContext->config.threadPriority));
SetThreadPriority((HANDLE)pThread->win32.hThread, ma_thread_priority_to_win32(pContext->threadPriority));
return MA_SUCCESS;
}
@@ -4400,13 +4423,13 @@ ma_bool32 ma_thread_create__posix(ma_context* pContext, ma_thread* pThread, ma_t
pthread_attr_t attr;
if (((ma_pthread_attr_init_proc)pContext->posix.pthread_attr_init)(&attr) == 0) {
int scheduler = -1;
if (pContext->config.threadPriority == ma_thread_priority_idle) {
if (pContext->threadPriority == ma_thread_priority_idle) {
#ifdef SCHED_IDLE
if (((ma_pthread_attr_setschedpolicy_proc)pContext->posix.pthread_attr_setschedpolicy)(&attr, SCHED_IDLE) == 0) {
scheduler = SCHED_IDLE;
}
#endif
} else if (pContext->config.threadPriority == ma_thread_priority_realtime) {
} else if (pContext->threadPriority == ma_thread_priority_realtime) {
#ifdef SCHED_FIFO
if (((ma_pthread_attr_setschedpolicy_proc)pContext->posix.pthread_attr_setschedpolicy)(&attr, SCHED_FIFO) == 0) {
scheduler = SCHED_FIFO;
@@ -4425,12 +4448,12 @@ ma_bool32 ma_thread_create__posix(ma_context* pContext, ma_thread* pThread, ma_t
struct sched_param sched;
if (((ma_pthread_attr_getschedparam_proc)pContext->posix.pthread_attr_getschedparam)(&attr, &sched) == 0) {
if (pContext->config.threadPriority == ma_thread_priority_idle) {
if (pContext->threadPriority == ma_thread_priority_idle) {
sched.sched_priority = priorityMin;
} else if (pContext->config.threadPriority == ma_thread_priority_realtime) {
} else if (pContext->threadPriority == ma_thread_priority_realtime) {
sched.sched_priority = priorityMax;
} else {
sched.sched_priority += ((int)pContext->config.threadPriority + 5) * priorityStep; // +5 because the lowest priority is -5.
sched.sched_priority += ((int)pContext->threadPriority + 5) * priorityStep; // +5 because the lowest priority is -5.
if (sched.sched_priority < priorityMin) {
sched.sched_priority = priorityMin;
}
@@ -4821,7 +4844,7 @@ void ma_log(ma_context* pContext, ma_device* pDevice, ma_uint32 logLevel, const
}
#endif
ma_log_proc onLog = pContext->config.logCallback;
ma_log_proc onLog = pContext->logCallback;
if (onLog) {
onLog(pContext, pDevice, logLevel, message);
}
@@ -5598,10 +5621,12 @@ ma_result ma_context_uninit__null(ma_context* pContext)
return MA_SUCCESS;
}
ma_result ma_context_init__null(ma_context* pContext)
ma_result ma_context_init__null(const ma_context_config* pConfig, ma_context* pContext)
{
ma_assert(pContext != NULL);
(void)pConfig;
pContext->onUninit = ma_context_uninit__null;
pContext->onDeviceIDEqual = ma_context_is_device_id_equal__null;
pContext->onEnumDevices = ma_context_enumerate_devices__null;
@@ -8343,10 +8368,12 @@ ma_result ma_context_uninit__wasapi(ma_context* pContext)
return MA_SUCCESS;
}
ma_result ma_context_init__wasapi(ma_context* pContext)
ma_result ma_context_init__wasapi(const ma_context_config* pConfig, ma_context* pContext)
{
ma_assert(pContext != NULL);
(void)pContext;
(void)pConfig;
ma_result result = MA_SUCCESS;
@@ -9981,10 +10008,12 @@ ma_result ma_context_uninit__dsound(ma_context* pContext)
return MA_SUCCESS;
}
ma_result ma_context_init__dsound(ma_context* pContext)
ma_result ma_context_init__dsound(const ma_context_config* pConfig, ma_context* pContext)
{
ma_assert(pContext != NULL);
(void)pConfig;
pContext->dsound.hDSoundDLL = ma_dlopen("dsound.dll");
if (pContext->dsound.hDSoundDLL == NULL) {
return MA_API_NOT_FOUND;
@@ -10944,10 +10973,12 @@ ma_result ma_context_uninit__winmm(ma_context* pContext)
return MA_SUCCESS;
}
ma_result ma_context_init__winmm(ma_context* pContext)
ma_result ma_context_init__winmm(const ma_context_config* pConfig, ma_context* pContext)
{
ma_assert(pContext != NULL);
(void)pConfig;
pContext->winmm.hWinMM = ma_dlopen("winmm.dll");
if (pContext->winmm.hWinMM == NULL) {
return MA_NO_BACKEND;
@@ -11729,7 +11760,7 @@ ma_result ma_context_enumerate_devices__alsa(ma_context* pContext, ma_enum_devic
char hwid[sizeof(pUniqueIDs->alsa)];
if (NAME != NULL) {
if (pContext->config.alsa.useVerboseDeviceEnumeration) {
if (pContext->alsa.useVerboseDeviceEnumeration) {
// Verbose mode. Use the name exactly as-is.
ma_strncpy_s(hwid, sizeof(hwid), NAME, (size_t)-1);
} else {
@@ -11784,7 +11815,7 @@ ma_result ma_context_enumerate_devices__alsa(ma_context* pContext, ma_enum_devic
if (line2 != NULL) {
line2 += 1; // Skip past the new-line character.
if (pContext->config.alsa.useVerboseDeviceEnumeration) {
if (pContext->alsa.useVerboseDeviceEnumeration) {
// Verbose mode. Put the second line in brackets.
ma_strncpy_s(deviceInfo.name, sizeof(deviceInfo.name), DESC, lfPos);
ma_strcat_s (deviceInfo.name, sizeof(deviceInfo.name), " (");
@@ -12822,7 +12853,7 @@ ma_result ma_context_uninit__alsa(ma_context* pContext)
return MA_SUCCESS;
}
ma_result ma_context_init__alsa(ma_context* pContext)
ma_result ma_context_init__alsa(const ma_context_config* pConfig, ma_context* pContext)
{
ma_assert(pContext != NULL);
@@ -13014,6 +13045,8 @@ ma_result ma_context_init__alsa(ma_context* pContext)
pContext->alsa.snd_config_update_free_global = (ma_proc)_snd_config_update_free_global;
#endif
pContext->alsa.useVerboseDeviceEnumeration = pConfig->alsa.useVerboseDeviceEnumeration;
if (ma_mutex_init(pContext, &pContext->alsa.internalDeviceEnumLock) != MA_SUCCESS) {
ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[ALSA] WARNING: Failed to initialize mutex for internal device enumeration.", MA_ERROR);
}
@@ -13872,13 +13905,13 @@ ma_result ma_context_enumerate_devices__pulse(ma_context* pContext, ma_enum_devi
return MA_FAILED_TO_INIT_BACKEND;
}
ma_pa_context* pPulseContext = ((ma_pa_context_new_proc)pContext->pulse.pa_context_new)(pAPI, pContext->config.pulse.pApplicationName);
ma_pa_context* pPulseContext = ((ma_pa_context_new_proc)pContext->pulse.pa_context_new)(pAPI, pContext->pulse.pApplicationName);
if (pPulseContext == NULL) {
((ma_pa_mainloop_free_proc)pContext->pulse.pa_mainloop_free)(pMainLoop);
return MA_FAILED_TO_INIT_BACKEND;
}
int error = ((ma_pa_context_connect_proc)pContext->pulse.pa_context_connect)(pPulseContext, pContext->config.pulse.pServerName, 0, NULL);
int error = ((ma_pa_context_connect_proc)pContext->pulse.pa_context_connect)(pPulseContext, pContext->pulse.pServerName, 0, NULL);
if (error != MA_PA_OK) {
((ma_pa_context_unref_proc)pContext->pulse.pa_context_unref)(pPulseContext);
((ma_pa_mainloop_free_proc)pContext->pulse.pa_mainloop_free)(pMainLoop);
@@ -14019,13 +14052,13 @@ ma_result ma_context_get_device_info__pulse(ma_context* pContext, ma_device_type
return MA_FAILED_TO_INIT_BACKEND;
}
ma_pa_context* pPulseContext = ((ma_pa_context_new_proc)pContext->pulse.pa_context_new)(pAPI, pContext->config.pulse.pApplicationName);
ma_pa_context* pPulseContext = ((ma_pa_context_new_proc)pContext->pulse.pa_context_new)(pAPI, pContext->pulse.pApplicationName);
if (pPulseContext == NULL) {
((ma_pa_mainloop_free_proc)pContext->pulse.pa_mainloop_free)(pMainLoop);
return MA_FAILED_TO_INIT_BACKEND;
}
int error = ((ma_pa_context_connect_proc)pContext->pulse.pa_context_connect)(pPulseContext, pContext->config.pulse.pServerName, 0, NULL);
int error = ((ma_pa_context_connect_proc)pContext->pulse.pa_context_connect)(pPulseContext, pContext->pulse.pServerName, 0, NULL);
if (error != MA_PA_OK) {
((ma_pa_context_unref_proc)pContext->pulse.pa_context_unref)(pPulseContext);
((ma_pa_mainloop_free_proc)pContext->pulse.pa_mainloop_free)(pMainLoop);
@@ -14232,13 +14265,13 @@ ma_result ma_device_init__pulse(ma_context* pContext, const ma_device_config* pC
goto on_error1;
}
pDevice->pulse.pPulseContext = ((ma_pa_context_new_proc)pContext->pulse.pa_context_new)((ma_pa_mainloop_api*)pDevice->pulse.pAPI, pContext->config.pulse.pApplicationName);
pDevice->pulse.pPulseContext = ((ma_pa_context_new_proc)pContext->pulse.pa_context_new)((ma_pa_mainloop_api*)pDevice->pulse.pAPI, pContext->pulse.pApplicationName);
if (pDevice->pulse.pPulseContext == NULL) {
result = ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to create PulseAudio context for device.", MA_FAILED_TO_INIT_BACKEND);
goto on_error1;
}
error = ((ma_pa_context_connect_proc)pContext->pulse.pa_context_connect)((ma_pa_context*)pDevice->pulse.pPulseContext, pContext->config.pulse.pServerName, (pContext->config.pulse.tryAutoSpawn) ? 0 : MA_PA_CONTEXT_NOAUTOSPAWN, NULL);
error = ((ma_pa_context_connect_proc)pContext->pulse.pa_context_connect)((ma_pa_context*)pDevice->pulse.pPulseContext, pContext->pulse.pServerName, (pContext->pulse.tryAutoSpawn) ? 0 : MA_PA_CONTEXT_NOAUTOSPAWN, NULL);
if (error != MA_PA_OK) {
result = ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to connect PulseAudio context.", ma_result_from_pulse(error));
goto on_error2;
@@ -14796,6 +14829,12 @@ ma_result ma_context_uninit__pulse(ma_context* pContext)
ma_assert(pContext != NULL);
ma_assert(pContext->backend == ma_backend_pulseaudio);
ma_free(pContext->pulse.pServerName);
pContext->pulse.pServerName = NULL;
ma_free(pContext->pulse.pApplicationName);
pContext->pulse.pApplicationName = NULL;
#ifndef MA_NO_RUNTIME_LINKING
ma_dlclose(pContext->pulse.pulseSO);
#endif
@@ -14803,7 +14842,7 @@ ma_result ma_context_uninit__pulse(ma_context* pContext)
return MA_SUCCESS;
}
ma_result ma_context_init__pulse(ma_context* pContext)
ma_result ma_context_init__pulse(const ma_context_config* pConfig, ma_context* pContext)
{
ma_assert(pContext != NULL);
@@ -14973,28 +15012,43 @@ ma_result ma_context_init__pulse(ma_context* pContext)
pContext->onDeviceWrite = ma_device_write__pulse;
pContext->onDeviceRead = ma_device_read__pulse;
if (pConfig->pulse.pApplicationName) {
pContext->pulse.pApplicationName = ma_copy_string(pConfig->pulse.pApplicationName);
}
if (pConfig->pulse.pServerName) {
pContext->pulse.pServerName = ma_copy_string(pConfig->pulse.pServerName);
}
pContext->pulse.tryAutoSpawn = pConfig->pulse.tryAutoSpawn;
// Although we have found the libpulse library, it doesn't necessarily mean PulseAudio is useable. We need to initialize
// and connect a dummy PulseAudio context to test PulseAudio's usability.
ma_pa_mainloop* pMainLoop = ((ma_pa_mainloop_new_proc)pContext->pulse.pa_mainloop_new)();
if (pMainLoop == NULL) {
ma_free(pContext->pulse.pServerName);
ma_free(pContext->pulse.pApplicationName);
return MA_NO_BACKEND;
}
ma_pa_mainloop_api* pAPI = ((ma_pa_mainloop_get_api_proc)pContext->pulse.pa_mainloop_get_api)(pMainLoop);
if (pAPI == NULL) {
ma_free(pContext->pulse.pServerName);
ma_free(pContext->pulse.pApplicationName);
((ma_pa_mainloop_free_proc)pContext->pulse.pa_mainloop_free)(pMainLoop);
return MA_NO_BACKEND;
}
ma_pa_context* pPulseContext = ((ma_pa_context_new_proc)pContext->pulse.pa_context_new)(pAPI, pContext->config.pulse.pApplicationName);
ma_pa_context* pPulseContext = ((ma_pa_context_new_proc)pContext->pulse.pa_context_new)(pAPI, pContext->pulse.pApplicationName);
if (pPulseContext == NULL) {
ma_free(pContext->pulse.pServerName);
ma_free(pContext->pulse.pApplicationName);
((ma_pa_mainloop_free_proc)pContext->pulse.pa_mainloop_free)(pMainLoop);
return MA_NO_BACKEND;
}
int error = ((ma_pa_context_connect_proc)pContext->pulse.pa_context_connect)(pPulseContext, pContext->config.pulse.pServerName, 0, NULL);
int error = ((ma_pa_context_connect_proc)pContext->pulse.pa_context_connect)(pPulseContext, pContext->pulse.pServerName, 0, NULL);
if (error != MA_PA_OK) {
ma_free(pContext->pulse.pServerName);
ma_free(pContext->pulse.pApplicationName);
((ma_pa_context_unref_proc)pContext->pulse.pa_context_unref)(pPulseContext);
((ma_pa_mainloop_free_proc)pContext->pulse.pa_mainloop_free)(pMainLoop);
return MA_NO_BACKEND;
@@ -15077,10 +15131,10 @@ ma_result ma_context_open_client__jack(ma_context* pContext, ma_jack_client_t**
size_t maxClientNameSize = ((ma_jack_client_name_size_proc)pContext->jack.jack_client_name_size)(); // Includes null terminator.
char clientName[256];
ma_strncpy_s(clientName, ma_min(sizeof(clientName), maxClientNameSize), (pContext->config.jack.pClientName != NULL) ? pContext->config.jack.pClientName : "miniaudio", (size_t)-1);
ma_strncpy_s(clientName, ma_min(sizeof(clientName), maxClientNameSize), (pContext->jack.pClientName != NULL) ? pContext->jack.pClientName : "miniaudio", (size_t)-1);
ma_jack_status_t status;
ma_jack_client_t* pClient = ((ma_jack_client_open_proc)pContext->jack.jack_client_open)(clientName, (pContext->config.jack.tryStartServer) ? 0 : ma_JackNoStartServer, &status, NULL);
ma_jack_client_t* pClient = ((ma_jack_client_open_proc)pContext->jack.jack_client_open)(clientName, (pContext->jack.tryStartServer) ? 0 : ma_JackNoStartServer, &status, NULL);
if (pClient == NULL) {
return MA_FAILED_TO_OPEN_BACKEND_DEVICE;
}
@@ -15519,6 +15573,9 @@ ma_result ma_context_uninit__jack(ma_context* pContext)
ma_assert(pContext != NULL);
ma_assert(pContext->backend == ma_backend_jack);
ma_free(pContext->jack.pClientName);
pContext->jack.pClientName = NULL;
#ifndef MA_NO_RUNTIME_LINKING
ma_dlclose(pContext->jack.jackSO);
#endif
@@ -15526,7 +15583,7 @@ ma_result ma_context_uninit__jack(ma_context* pContext)
return MA_SUCCESS;
}
ma_result ma_context_init__jack(ma_context* pContext)
ma_result ma_context_init__jack(const ma_context_config* pConfig, ma_context* pContext)
{
ma_assert(pContext != NULL);
@@ -15617,12 +15674,17 @@ ma_result ma_context_init__jack(ma_context* pContext)
pContext->onDeviceStart = ma_device_start__jack;
pContext->onDeviceStop = ma_device_stop__jack;
if (pConfig->jack.pClientName != NULL) {
pContext->jack.pClientName = ma_copy_string(pConfig->jack.pClientName);
}
pContext->jack.tryStartServer = pConfig->jack.tryStartServer;
// Getting here means the JACK library is installed, but it doesn't necessarily mean it's usable. We need to quickly test this by connecting
// a temporary client.
ma_jack_client_t* pDummyClient;
ma_result result = ma_context_open_client__jack(pContext, &pDummyClient);
if (result != MA_SUCCESS) {
ma_free(pContext->jack.pClientName);
return MA_NO_BACKEND;
}
@@ -17905,10 +17967,12 @@ ma_result ma_context_uninit__coreaudio(ma_context* pContext)
return MA_SUCCESS;
}
ma_result ma_context_init__coreaudio(ma_context* pContext)
ma_result ma_context_init__coreaudio(const ma_context_config* pConfig, ma_context* pContext)
{
ma_assert(pContext != NULL);
(void)pConfig;
#if defined(MA_APPLE_MOBILE)
@autoreleasepool {
AVAudioSession* pAudioSession = [AVAudioSession sharedInstance];
@@ -18764,10 +18828,12 @@ ma_result ma_context_uninit__sndio(ma_context* pContext)
return MA_SUCCESS;
}
ma_result ma_context_init__sndio(ma_context* pContext)
ma_result ma_context_init__sndio(const ma_context_config* pConfig, ma_context* pContext)
{
ma_assert(pContext != NULL);
(void)pConfig;
#ifndef MA_NO_RUNTIME_LINKING
// libpulse.so
const char* libsndioNames[] = {
@@ -19515,10 +19581,12 @@ ma_result ma_context_uninit__audio4(ma_context* pContext)
return MA_SUCCESS;
}
ma_result ma_context_init__audio4(ma_context* pContext)
ma_result ma_context_init__audio4(const ma_context_config* pConfig, ma_context* pContext)
{
ma_assert(pContext != NULL);
(void)pConfig;
pContext->onUninit = ma_context_uninit__audio4;
pContext->onDeviceIDEqual = ma_context_is_device_id_equal__audio4;
pContext->onEnumDevices = ma_context_enumerate_devices__audio4;
@@ -20027,10 +20095,12 @@ ma_result ma_context_uninit__oss(ma_context* pContext)
return MA_SUCCESS;
}
ma_result ma_context_init__oss(ma_context* pContext)
ma_result ma_context_init__oss(const ma_context_config* pConfig, ma_context* pContext)
{
ma_assert(pContext != NULL);
(void)pConfig;
/* Try opening a temporary device first so we can get version information. This is closed at the end. */
int fd = ma_open_temp_device__oss();
if (fd == -1) {
@@ -20610,10 +20680,11 @@ ma_result ma_context_uninit__aaudio(ma_context* pContext)
return MA_SUCCESS;
}
ma_result ma_context_init__aaudio(ma_context* pContext)
ma_result ma_context_init__aaudio(const ma_context_config* pConfig, ma_context* pContext)
{
ma_assert(pContext != NULL);
(void)pContext;
(void)pConfig;
const char* libNames[] = {
"libaaudio.so"
@@ -21561,10 +21632,11 @@ ma_result ma_context_uninit__opensl(ma_context* pContext)
return MA_SUCCESS;
}
ma_result ma_context_init__opensl(ma_context* pContext)
ma_result ma_context_init__opensl(const ma_context_config* pConfig, ma_context* pContext)
{
ma_assert(pContext != NULL);
(void)pContext;
(void)pConfig;
/* Initialize global data first if applicable. */
if (ma_atomic_increment_32(&g_maOpenSLInitCounter) == 1) {
@@ -22100,9 +22172,11 @@ ma_result ma_context_uninit__webaudio(ma_context* pContext)
return MA_SUCCESS;
}
ma_result ma_context_init__webaudio(ma_context* pContext)
ma_result ma_context_init__webaudio(const ma_context_config* pConfig, ma_context* pContext)
{
ma_assert(pContext != NULL);
(void)pConfig;
/* Here is where our global JavaScript object is initialized. */
int resultFromJS = EM_ASM_INT({
@@ -22680,12 +22754,17 @@ ma_result ma_context_init(const ma_backend backends[], ma_uint32 backendCount, c
ma_zero_object(pContext);
// Always make sure the config is set first to ensure properties are available as soon as possible.
ma_context_config config;
if (pConfig != NULL) {
pContext->config = *pConfig;
config = *pConfig;
} else {
pContext->config = ma_context_config_init();
config = ma_context_config_init();
}
pContext->logCallback = config.logCallback;
pContext->threadPriority = config.threadPriority;
pContext->pUserData = config.pUserData;
// Backend APIs need to be initialized first. This is where external libraries will be loaded and linked.
ma_result result = ma_context_init_backend_apis(pContext);
if (result != MA_SUCCESS) {
@@ -22714,85 +22793,85 @@ ma_result ma_context_init(const ma_backend backends[], ma_uint32 backendCount, c
#ifdef MA_HAS_WASAPI
case ma_backend_wasapi:
{
result = ma_context_init__wasapi(pContext);
result = ma_context_init__wasapi(&config, pContext);
} break;
#endif
#ifdef MA_HAS_DSOUND
case ma_backend_dsound:
{
result = ma_context_init__dsound(pContext);
result = ma_context_init__dsound(&config, pContext);
} break;
#endif
#ifdef MA_HAS_WINMM
case ma_backend_winmm:
{
result = ma_context_init__winmm(pContext);
result = ma_context_init__winmm(&config, pContext);
} break;
#endif
#ifdef MA_HAS_ALSA
case ma_backend_alsa:
{
result = ma_context_init__alsa(pContext);
result = ma_context_init__alsa(&config, pContext);
} break;
#endif
#ifdef MA_HAS_PULSEAUDIO
case ma_backend_pulseaudio:
{
result = ma_context_init__pulse(pContext);
result = ma_context_init__pulse(&config, pContext);
} break;
#endif
#ifdef MA_HAS_JACK
case ma_backend_jack:
{
result = ma_context_init__jack(pContext);
result = ma_context_init__jack(&config, pContext);
} break;
#endif
#ifdef MA_HAS_COREAUDIO
case ma_backend_coreaudio:
{
result = ma_context_init__coreaudio(pContext);
result = ma_context_init__coreaudio(&config, pContext);
} break;
#endif
#ifdef MA_HAS_SNDIO
case ma_backend_sndio:
{
result = ma_context_init__sndio(pContext);
result = ma_context_init__sndio(&config, pContext);
} break;
#endif
#ifdef MA_HAS_AUDIO4
case ma_backend_audio4:
{
result = ma_context_init__audio4(pContext);
result = ma_context_init__audio4(&config, pContext);
} break;
#endif
#ifdef MA_HAS_OSS
case ma_backend_oss:
{
result = ma_context_init__oss(pContext);
result = ma_context_init__oss(&config, pContext);
} break;
#endif
#ifdef MA_HAS_AAUDIO
case ma_backend_aaudio:
{
result = ma_context_init__aaudio(pContext);
result = ma_context_init__aaudio(&config, pContext);
} break;
#endif
#ifdef MA_HAS_OPENSL
case ma_backend_opensl:
{
result = ma_context_init__opensl(pContext);
result = ma_context_init__opensl(&config, pContext);
} break;
#endif
#ifdef MA_HAS_WEBAUDIO
case ma_backend_webaudio:
{
result = ma_context_init__webaudio(pContext);
result = ma_context_init__webaudio(&config, pContext);
} break;
#endif
#ifdef MA_HAS_NULL
case ma_backend_null:
{
result = ma_context_init__null(pContext);
result = ma_context_init__null(&config, pContext);
} break;
#endif
@@ -23038,8 +23117,8 @@ ma_result ma_device_init(ma_context* pContext, const ma_device_config* pConfig,
pDevice->onStop = config.stopCallback;
if (((ma_uintptr)pDevice % sizeof(pDevice)) != 0) {
if (pContext->config.logCallback) {
pContext->config.logCallback(pContext, pDevice, MA_LOG_LEVEL_WARNING, "WARNING: ma_device_init() called for a device that is not properly aligned. Thread safety is not supported.");
if (pContext->logCallback) {
pContext->logCallback(pContext, pDevice, MA_LOG_LEVEL_WARNING, "WARNING: ma_device_init() called for a device that is not properly aligned. Thread safety is not supported.");
}
}
@@ -31390,6 +31469,10 @@ Device
REVISION HISTORY
================
v0.9.2-dev - 2019-xx-xx
- Add support for per-context user data.
- Fix a potential bug with context configs.
v0.9.1 - 2019-03-17
- Fix a bug where the output buffer is not getting zeroed out before calling the data callback. This happens when
the device is running in passthrough mode (not doing any data conversion).