From 66b5ccb5771ed3807b48a62a503c88bf51bee898 Mon Sep 17 00:00:00 2001 From: David Reid Date: Thu, 8 Jul 2021 20:44:50 +1000 Subject: [PATCH 01/10] Update issue template. --- .github/ISSUE_TEMPLATE/general-issue.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE/general-issue.md b/.github/ISSUE_TEMPLATE/general-issue.md index 6e1d259a..25b70645 100644 --- a/.github/ISSUE_TEMPLATE/general-issue.md +++ b/.github/ISSUE_TEMPLATE/general-issue.md @@ -9,4 +9,6 @@ assignees: '' **DELETE ALL OF THIS TEXT BEFORE SUBMITTING** -If you have a question about how to use the library, please read the documentation at the top of miniaudio.h and take a look at the examples. Otherwise, feel free to post your issue and we'll get to it as soon as possible! +If you have a question about how to use the library, please read the documentation at the top of miniaudio.h and take a look at the examples. If that still doesn't answer your question, please post it in the Discussions section instead. Otherwise, feel free to post your issue and we'll get to it as soon as possible! + +If you have an issue with playback, please run the simple_playback_sine example first and check whether or not that is working. Likewise for capture, please run the simple_capture example. If these examples work, it probably (but not always) means you're doing something wrong and a question in the Discussions section is more appropriate. From 655c08765144891a4dddf4c3fb36b9edff948fb5 Mon Sep 17 00:00:00 2001 From: David Reid Date: Sun, 11 Jul 2021 17:00:56 +1000 Subject: [PATCH 02/10] Avoid some superfluous decoder backend initialization. --- miniaudio.h | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/miniaudio.h b/miniaudio.h index 80fd15bc..93c9a468 100644 --- a/miniaudio.h +++ b/miniaudio.h @@ -50291,6 +50291,14 @@ static ma_result ma_decoder_init__internal(ma_decoder_read_proc onRead, ma_decod } } + /* + If we get to this point and we still haven't found a decoder, and the caller has requested a + specific encoding format, there's no hope for it. Abort. + */ + if (pConfig->encodingFormat != ma_encoding_format_unknown) { + return MA_NO_BACKEND; + } + #ifdef MA_HAS_WAV if (result != MA_SUCCESS) { result = ma_decoder_init_wav__internal(pConfig, pDecoder); @@ -50808,6 +50816,26 @@ MA_API ma_result ma_decoder_init_vfs(ma_vfs* pVFS, const char* pFilePath, const if (result != MA_SUCCESS) { /* Getting here means we weren't able to initialize a decoder of a specific encoding format. */ + + /* + We use trial and error to open a decoder. We prioritize custom decoders so that if they + implement the same encoding format they take priority over the built-in decoders. + */ + if (result != MA_SUCCESS) { + result = ma_decoder_init_custom__internal(pConfig, pDecoder); + if (result != MA_SUCCESS) { + ma_decoder__on_seek_vfs(pDecoder, 0, ma_seek_origin_start); + } + } + + /* + If we get to this point and we still haven't found a decoder, and the caller has requested a + specific encoding format, there's no hope for it. Abort. + */ + if (pConfig->encodingFormat != ma_encoding_format_unknown) { + return MA_NO_BACKEND; + } + #ifdef MA_HAS_WAV if (result != MA_SUCCESS && ma_path_extension_equal(pFilePath, "wav")) { result = ma_decoder_init_wav__internal(&config, pDecoder); @@ -50994,6 +51022,26 @@ MA_API ma_result ma_decoder_init_vfs_w(ma_vfs* pVFS, const wchar_t* pFilePath, c if (result != MA_SUCCESS) { /* Getting here means we weren't able to initialize a decoder of a specific encoding format. */ + + /* + We use trial and error to open a decoder. We prioritize custom decoders so that if they + implement the same encoding format they take priority over the built-in decoders. + */ + if (result != MA_SUCCESS) { + result = ma_decoder_init_custom__internal(pConfig, pDecoder); + if (result != MA_SUCCESS) { + ma_decoder__on_seek_vfs(pDecoder, 0, ma_seek_origin_start); + } + } + + /* + If we get to this point and we still haven't found a decoder, and the caller has requested a + specific encoding format, there's no hope for it. Abort. + */ + if (pConfig->encodingFormat != ma_encoding_format_unknown) { + return MA_NO_BACKEND; + } + #ifdef MA_HAS_WAV if (result != MA_SUCCESS && ma_path_extension_equal_w(pFilePath, L"wav")) { result = ma_decoder_init_wav__internal(&config, pDecoder); From 7bb96d8a3c125c64b5c868361a2b76499989b843 Mon Sep 17 00:00:00 2001 From: David Reid Date: Sun, 11 Jul 2021 17:04:07 +1000 Subject: [PATCH 03/10] Fix a crash when initializing a decoder without a config. --- miniaudio.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/miniaudio.h b/miniaudio.h index 93c9a468..4048d2be 100644 --- a/miniaudio.h +++ b/miniaudio.h @@ -50822,7 +50822,7 @@ MA_API ma_result ma_decoder_init_vfs(ma_vfs* pVFS, const char* pFilePath, const implement the same encoding format they take priority over the built-in decoders. */ if (result != MA_SUCCESS) { - result = ma_decoder_init_custom__internal(pConfig, pDecoder); + result = ma_decoder_init_custom__internal(&config, pDecoder); if (result != MA_SUCCESS) { ma_decoder__on_seek_vfs(pDecoder, 0, ma_seek_origin_start); } @@ -50832,7 +50832,7 @@ MA_API ma_result ma_decoder_init_vfs(ma_vfs* pVFS, const char* pFilePath, const If we get to this point and we still haven't found a decoder, and the caller has requested a specific encoding format, there's no hope for it. Abort. */ - if (pConfig->encodingFormat != ma_encoding_format_unknown) { + if (config.encodingFormat != ma_encoding_format_unknown) { return MA_NO_BACKEND; } @@ -51028,7 +51028,7 @@ MA_API ma_result ma_decoder_init_vfs_w(ma_vfs* pVFS, const wchar_t* pFilePath, c implement the same encoding format they take priority over the built-in decoders. */ if (result != MA_SUCCESS) { - result = ma_decoder_init_custom__internal(pConfig, pDecoder); + result = ma_decoder_init_custom__internal(&config, pDecoder); if (result != MA_SUCCESS) { ma_decoder__on_seek_vfs(pDecoder, 0, ma_seek_origin_start); } @@ -51038,7 +51038,7 @@ MA_API ma_result ma_decoder_init_vfs_w(ma_vfs* pVFS, const wchar_t* pFilePath, c If we get to this point and we still haven't found a decoder, and the caller has requested a specific encoding format, there's no hope for it. Abort. */ - if (pConfig->encodingFormat != ma_encoding_format_unknown) { + if (config.encodingFormat != ma_encoding_format_unknown) { return MA_NO_BACKEND; } From b65a117132a91ad74e0d16a481b12bc8cedc26fa Mon Sep 17 00:00:00 2001 From: Clownacy Date: Tue, 13 Jul 2021 23:33:15 +0100 Subject: [PATCH 04/10] Fix function not returning anything MSVC 6 was printing a warning about this. --- miniaudio.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/miniaudio.h b/miniaudio.h index 4048d2be..789a797f 100644 --- a/miniaudio.h +++ b/miniaudio.h @@ -8811,6 +8811,8 @@ MA_API ma_result ma_log_postv(ma_log* pLog, ma_uint32 level, const char* pFormat ma_free(pFormattedMessage, &pLog->allocationCallbacks); return result; + } else { + return MA_OUT_OF_MEMORY; } } else { return MA_INVALID_OPERATION; From f56ea2047044a8f2a673e834c675c035b419d649 Mon Sep 17 00:00:00 2001 From: Clownacy Date: Tue, 13 Jul 2021 23:35:41 +0100 Subject: [PATCH 05/10] Restructure `ma_log_postv` to be more consistent The `__STDC_VERSION__ >= 199901L` and the `_MSC_VER >= 1200` code had different styles for handling errors, so I've made them match. --- miniaudio.h | 52 ++++++++++++++++++++++++++-------------------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/miniaudio.h b/miniaudio.h index 789a797f..e3de1979 100644 --- a/miniaudio.h +++ b/miniaudio.h @@ -8789,34 +8789,34 @@ MA_API ma_result ma_log_postv(ma_log* pLog, ma_uint32 level, const char* pFormat formattedLen = ma_vscprintf(&pLog->allocationCallbacks, pFormat, args2); va_end(args2); - if (formattedLen > 0) { - char* pFormattedMessage = NULL; - - pFormattedMessage = (char*)ma_malloc(formattedLen + 1, &pLog->allocationCallbacks); - if (pFormattedMessage != NULL) { - ma_result result; - - /* We'll get errors on newer versions of Visual Studio if we try to use vsprintf(). */ - #if _MSC_VER >= 1400 /* 1400 = Visual Studio 2005 */ - { - vsprintf_s(pFormattedMessage, formattedLen + 1, pFormat, args); - } - #else - { - vsprintf(pFormattedMessage, pFormat, args); - } - #endif - - result = ma_log_post(pLog, level, pFormattedMessage); - ma_free(pFormattedMessage, &pLog->allocationCallbacks); - - return result; - } else { - return MA_OUT_OF_MEMORY; - } - } else { + if (formattedLen <= 0) { return MA_INVALID_OPERATION; } + + char* pFormattedMessage = NULL; + + pFormattedMessage = (char*)ma_malloc(formattedLen + 1, &pLog->allocationCallbacks); + if (pFormattedMessage == NULL) { + return MA_OUT_OF_MEMORY; + } + + ma_result result; + + /* We'll get errors on newer versions of Visual Studio if we try to use vsprintf(). */ + #if _MSC_VER >= 1400 /* 1400 = Visual Studio 2005 */ + { + vsprintf_s(pFormattedMessage, formattedLen + 1, pFormat, args); + } + #else + { + vsprintf(pFormattedMessage, pFormat, args); + } + #endif + + result = ma_log_post(pLog, level, pFormattedMessage); + ma_free(pFormattedMessage, &pLog->allocationCallbacks); + + return result; } #else { From 3a5bfa9f9bc8239bb81973ffbaa1a81e8b757ccc Mon Sep 17 00:00:00 2001 From: David Reid Date: Wed, 14 Jul 2021 17:20:49 +1000 Subject: [PATCH 06/10] Fix some strict C89 issues. --- miniaudio.h | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/miniaudio.h b/miniaudio.h index e3de1979..4e2bb8ee 100644 --- a/miniaudio.h +++ b/miniaudio.h @@ -8773,7 +8773,9 @@ MA_API ma_result ma_log_postv(ma_log* pLog, ma_uint32 level, const char* pFormat */ #if defined(_MSC_VER) && _MSC_VER >= 1200 /* 1200 = VC6 */ { + ma_result result; int formattedLen; + char* pFormattedMessage = NULL; va_list args2; #if _MSC_VER >= 1800 @@ -8793,15 +8795,11 @@ MA_API ma_result ma_log_postv(ma_log* pLog, ma_uint32 level, const char* pFormat return MA_INVALID_OPERATION; } - char* pFormattedMessage = NULL; - pFormattedMessage = (char*)ma_malloc(formattedLen + 1, &pLog->allocationCallbacks); if (pFormattedMessage == NULL) { return MA_OUT_OF_MEMORY; } - ma_result result; - /* We'll get errors on newer versions of Visual Studio if we try to use vsprintf(). */ #if _MSC_VER >= 1400 /* 1400 = Visual Studio 2005 */ { From 60409562557204adcb67df7d9cdbf5bae3d5c179 Mon Sep 17 00:00:00 2001 From: David Reid Date: Wed, 14 Jul 2021 17:26:30 +1000 Subject: [PATCH 07/10] Fix an error where ma_log_level_to_string() is sometimes not compiled. This was happening because ma_log_level_to_string() was only being included when MA_DEBUG_OUTPUT is enabled. --- miniaudio.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/miniaudio.h b/miniaudio.h index 4e2bb8ee..83f7621b 100644 --- a/miniaudio.h +++ b/miniaudio.h @@ -8477,8 +8477,6 @@ static ma_result ma_allocation_callbacks_init_copy(ma_allocation_callbacks* pDst Logging **************************************************************************************************************************************************************/ -#if defined(MA_DEBUG_OUTPUT) - MA_API const char* ma_log_level_to_string(ma_uint32 logLevel) { switch (logLevel) @@ -8491,6 +8489,8 @@ MA_API const char* ma_log_level_to_string(ma_uint32 logLevel) } } +#if defined(MA_DEBUG_OUTPUT) + /* Customize this to use a specific tag in __android_log_print() for debug output messages. */ #ifndef MA_ANDROID_LOG_TAG #define MA_ANDROID_LOG_TAG "miniaudio" From 2d63e2347a11ca9bdb9552cd21b3147deb7e928a Mon Sep 17 00:00:00 2001 From: David Reid Date: Wed, 14 Jul 2021 17:33:03 +1000 Subject: [PATCH 08/10] Update revision history. --- miniaudio.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/miniaudio.h b/miniaudio.h index 83f7621b..eceea931 100644 --- a/miniaudio.h +++ b/miniaudio.h @@ -69347,6 +69347,8 @@ The following miscellaneous changes have also been made. REVISION HISTORY ================ v0.10.38 - TBD + - Fix a linking error when MA_DEBUG_OUTPUT is not enabled. + - Fix an error where ma_log_postv() does not return a value. - OpenSL: Fix a bug with setting of stream types and recording presets. 0.10.37 - 2021-07-06 From 922c95997e2108cd1988d3879f9a57692853452e Mon Sep 17 00:00:00 2001 From: David Reid Date: Wed, 14 Jul 2021 18:49:17 +1000 Subject: [PATCH 09/10] PulseAudio: Experimental work on improving the stop callback. Public issue https://github.com/mackron/miniaudio/issues/341 --- miniaudio.h | 47 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/miniaudio.h b/miniaudio.h index eceea931..ed247eba 100644 --- a/miniaudio.h +++ b/miniaudio.h @@ -3862,6 +3862,8 @@ struct ma_context ma_proc pa_stream_get_device_name; ma_proc pa_stream_set_write_callback; ma_proc pa_stream_set_read_callback; + ma_proc pa_stream_set_suspended_callback; + ma_proc pa_stream_is_suspended; ma_proc pa_stream_flush; ma_proc pa_stream_drain; ma_proc pa_stream_is_corked; @@ -21737,6 +21739,7 @@ to check for type safety. We cannot do this when linking at run time because the #define MA_PA_ERR_ACCESS PA_ERR_ACCESS #define MA_PA_ERR_INVALID PA_ERR_INVALID #define MA_PA_ERR_NOENTITY PA_ERR_NOENTITY +#define MA_PA_ERR_NOTSUPPORTED PA_ERR_NOTSUPPORTED #define MA_PA_CHANNELS_MAX PA_CHANNELS_MAX #define MA_PA_RATE_MAX PA_RATE_MAX @@ -21932,12 +21935,14 @@ typedef pa_sink_info_cb_t ma_pa_sink_info_cb_t; typedef pa_source_info_cb_t ma_pa_source_info_cb_t; typedef pa_stream_success_cb_t ma_pa_stream_success_cb_t; typedef pa_stream_request_cb_t ma_pa_stream_request_cb_t; +typedef pa_stream_notify_cb_t ma_pa_stream_notify_cb_t; typedef pa_free_cb_t ma_pa_free_cb_t; #else #define MA_PA_OK 0 #define MA_PA_ERR_ACCESS 1 #define MA_PA_ERR_INVALID 2 #define MA_PA_ERR_NOENTITY 5 +#define MA_PA_ERR_NOTSUPPORTED 19 #define MA_PA_CHANNELS_MAX 32 #define MA_PA_RATE_MAX 384000 @@ -22211,6 +22216,7 @@ typedef void (* ma_pa_sink_info_cb_t) (ma_pa_context* c, const ma_pa_sink_in typedef void (* ma_pa_source_info_cb_t) (ma_pa_context* c, const ma_pa_source_info* i, int eol, void* userdata); typedef void (* ma_pa_stream_success_cb_t)(ma_pa_stream* s, int success, void* userdata); typedef void (* ma_pa_stream_request_cb_t)(ma_pa_stream* s, size_t nbytes, void* userdata); +typedef void (* ma_pa_stream_notify_cb_t) (ma_pa_stream* s, void* userdata); typedef void (* ma_pa_free_cb_t) (void* p); #endif @@ -22262,6 +22268,8 @@ typedef ma_pa_operation* (* ma_pa_stream_set_buffer_attr_proc) ( typedef const char* (* ma_pa_stream_get_device_name_proc) (ma_pa_stream* s); typedef void (* ma_pa_stream_set_write_callback_proc) (ma_pa_stream* s, ma_pa_stream_request_cb_t cb, void* userdata); typedef void (* ma_pa_stream_set_read_callback_proc) (ma_pa_stream* s, ma_pa_stream_request_cb_t cb, void* userdata); +typedef void (* ma_pa_stream_set_suspended_callback_proc) (ma_pa_stream* s, ma_pa_stream_notify_cb_t cb, void* userdata); +typedef int (* ma_pa_stream_is_suspended_proc) (const ma_pa_stream* s); typedef ma_pa_operation* (* ma_pa_stream_flush_proc) (ma_pa_stream* s, ma_pa_stream_success_cb_t cb, void* userdata); typedef ma_pa_operation* (* ma_pa_stream_drain_proc) (ma_pa_stream* s, ma_pa_stream_success_cb_t cb, void* userdata); typedef int (* ma_pa_stream_is_corked_proc) (ma_pa_stream* s); @@ -23134,6 +23142,36 @@ static void ma_device_on_write__pulse(ma_pa_stream* pStream, size_t byteCount, v } } +static void ma_device_on_suspended__pulse(ma_pa_stream* pStream, void* pUserData) +{ + ma_device* pDevice = (ma_device*)pUserData; + int suspended; + + (void)pStream; + + suspended = ((ma_pa_stream_is_suspended_proc)pDevice->pContext->pulse.pa_stream_is_suspended)(pStream); + ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[Pulse] Device suspended state changed. pa_stream_is_suspended() returned %d.\n", suspended); + + if (suspended < 0) { + return; + } + + if (suspended == 1) { + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[Pulse] Device suspended state changed. Suspended.\n"); + + /* Locking this behind MA_DEBUG_OUTPUT for the moment while this is still in an experimental state. */ + #if defined(MA_DEBUG_OUTPUT) + { + if (pDevice->onStop) { + pDevice->onStop(pDevice); + } + } + #endif + } else { + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[Pulse] Device suspended state changed. Resumed.\n"); + } +} + static ma_result ma_device_init__pulse(ma_device* pDevice, const ma_device_config* pConfig, ma_device_descriptor* pDescriptorPlayback, ma_device_descriptor* pDescriptorCapture) { /* @@ -23353,6 +23391,9 @@ static ma_result ma_device_init__pulse(ma_device* pDevice, const ma_device_confi */ ((ma_pa_stream_set_write_callback_proc)pDevice->pContext->pulse.pa_stream_set_write_callback)((ma_pa_stream*)pDevice->pulse.pStreamPlayback, ma_device_on_write__pulse, pDevice); + /* State callback for checking when the device has been corked. */ + ((ma_pa_stream_set_suspended_callback_proc)pDevice->pContext->pulse.pa_stream_set_suspended_callback)((ma_pa_stream*)pDevice->pulse.pStreamPlayback, ma_device_on_suspended__pulse, pDevice); + /* Connect after we've got all of our internal state set up. */ streamFlags = MA_PA_STREAM_START_CORKED | MA_PA_STREAM_ADJUST_LATENCY | MA_PA_STREAM_FIX_FORMAT | MA_PA_STREAM_FIX_RATE | MA_PA_STREAM_FIX_CHANNELS; @@ -23673,6 +23714,8 @@ static ma_result ma_context_init__pulse(ma_context* pContext, const ma_context_c pContext->pulse.pa_stream_get_device_name = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_get_device_name"); pContext->pulse.pa_stream_set_write_callback = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_set_write_callback"); pContext->pulse.pa_stream_set_read_callback = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_set_read_callback"); + pContext->pulse.pa_stream_set_suspended_callback = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_set_suspended_callback"); + pContext->pulse.pa_stream_is_suspended = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_is_suspended"); pContext->pulse.pa_stream_flush = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_flush"); pContext->pulse.pa_stream_drain = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_drain"); pContext->pulse.pa_stream_is_corked = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_is_corked"); @@ -23733,6 +23776,8 @@ static ma_result ma_context_init__pulse(ma_context* pContext, const ma_context_c ma_pa_stream_get_device_name_proc _pa_stream_get_device_name = pa_stream_get_device_name; ma_pa_stream_set_write_callback_proc _pa_stream_set_write_callback = pa_stream_set_write_callback; ma_pa_stream_set_read_callback_proc _pa_stream_set_read_callback = pa_stream_set_read_callback; + ma_pa_stream_set_suspended_callback_proc _pa_stream_set_suspended_callback = pa_stream_set_suspended_callback; + ma_pa_stream_is_suspended_proc _pa_stream_is_suspended = pa_stream_is_suspended; ma_pa_stream_flush_proc _pa_stream_flush = pa_stream_flush; ma_pa_stream_drain_proc _pa_stream_drain = pa_stream_drain; ma_pa_stream_is_corked_proc _pa_stream_is_corked = pa_stream_is_corked; @@ -23792,6 +23837,8 @@ static ma_result ma_context_init__pulse(ma_context* pContext, const ma_context_c pContext->pulse.pa_stream_get_device_name = (ma_proc)_pa_stream_get_device_name; pContext->pulse.pa_stream_set_write_callback = (ma_proc)_pa_stream_set_write_callback; pContext->pulse.pa_stream_set_read_callback = (ma_proc)_pa_stream_set_read_callback; + pContext->pulse.pa_stream_set_suspended_callback = (ma_proc)_pa_stream_set_suspended_callback; + pContext->pulse.pa_stream_is_suspended = (ma_proc)_pa_stream_is_suspended; pContext->pulse.pa_stream_flush = (ma_proc)_pa_stream_flush; pContext->pulse.pa_stream_drain = (ma_proc)_pa_stream_drain; pContext->pulse.pa_stream_is_corked = (ma_proc)_pa_stream_is_corked; From 0f5cb7829d4f6fe0201449b5ad1947bef0468ea8 Mon Sep 17 00:00:00 2001 From: David Reid Date: Wed, 14 Jul 2021 20:46:38 +1000 Subject: [PATCH 10/10] Version 0.10.38 --- extras/miniaudio_split/miniaudio.c | 165 +++++++++++++++++++++++------ extras/miniaudio_split/miniaudio.h | 6 +- miniaudio.h | 4 +- 3 files changed, 137 insertions(+), 38 deletions(-) diff --git a/extras/miniaudio_split/miniaudio.c b/extras/miniaudio_split/miniaudio.c index e6595b44..00d1fc1b 100644 --- a/extras/miniaudio_split/miniaudio.c +++ b/extras/miniaudio_split/miniaudio.c @@ -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 - v0.10.37 - 2021-07-06 +miniaudio - v0.10.38 - 2021-07-14 David Reid - mackron@gmail.com @@ -1950,8 +1950,6 @@ static ma_result ma_allocation_callbacks_init_copy(ma_allocation_callbacks* pDst Logging **************************************************************************************************************************************************************/ -#if defined(MA_DEBUG_OUTPUT) - MA_API const char* ma_log_level_to_string(ma_uint32 logLevel) { switch (logLevel) @@ -1964,6 +1962,8 @@ MA_API const char* ma_log_level_to_string(ma_uint32 logLevel) } } +#if defined(MA_DEBUG_OUTPUT) + /* Customize this to use a specific tag in __android_log_print() for debug output messages. */ #ifndef MA_ANDROID_LOG_TAG #define MA_ANDROID_LOG_TAG "miniaudio" @@ -2246,7 +2246,9 @@ MA_API ma_result ma_log_postv(ma_log* pLog, ma_uint32 level, const char* pFormat */ #if defined(_MSC_VER) && _MSC_VER >= 1200 /* 1200 = VC6 */ { + ma_result result; int formattedLen; + char* pFormattedMessage = NULL; va_list args2; #if _MSC_VER >= 1800 @@ -2262,32 +2264,30 @@ MA_API ma_result ma_log_postv(ma_log* pLog, ma_uint32 level, const char* pFormat formattedLen = ma_vscprintf(&pLog->allocationCallbacks, pFormat, args2); va_end(args2); - if (formattedLen > 0) { - char* pFormattedMessage = NULL; - - pFormattedMessage = (char*)ma_malloc(formattedLen + 1, &pLog->allocationCallbacks); - if (pFormattedMessage != NULL) { - ma_result result; - - /* We'll get errors on newer versions of Visual Studio if we try to use vsprintf(). */ - #if _MSC_VER >= 1400 /* 1400 = Visual Studio 2005 */ - { - vsprintf_s(pFormattedMessage, formattedLen + 1, pFormat, args); - } - #else - { - vsprintf(pFormattedMessage, pFormat, args); - } - #endif - - result = ma_log_post(pLog, level, pFormattedMessage); - ma_free(pFormattedMessage, &pLog->allocationCallbacks); - - return result; - } - } else { + if (formattedLen <= 0) { return MA_INVALID_OPERATION; } + + pFormattedMessage = (char*)ma_malloc(formattedLen + 1, &pLog->allocationCallbacks); + if (pFormattedMessage == NULL) { + return MA_OUT_OF_MEMORY; + } + + /* We'll get errors on newer versions of Visual Studio if we try to use vsprintf(). */ + #if _MSC_VER >= 1400 /* 1400 = Visual Studio 2005 */ + { + vsprintf_s(pFormattedMessage, formattedLen + 1, pFormat, args); + } + #else + { + vsprintf(pFormattedMessage, pFormat, args); + } + #endif + + result = ma_log_post(pLog, level, pFormattedMessage); + ma_free(pFormattedMessage, &pLog->allocationCallbacks); + + return result; } #else { @@ -15210,6 +15210,7 @@ to check for type safety. We cannot do this when linking at run time because the #define MA_PA_ERR_ACCESS PA_ERR_ACCESS #define MA_PA_ERR_INVALID PA_ERR_INVALID #define MA_PA_ERR_NOENTITY PA_ERR_NOENTITY +#define MA_PA_ERR_NOTSUPPORTED PA_ERR_NOTSUPPORTED #define MA_PA_CHANNELS_MAX PA_CHANNELS_MAX #define MA_PA_RATE_MAX PA_RATE_MAX @@ -15405,12 +15406,14 @@ typedef pa_sink_info_cb_t ma_pa_sink_info_cb_t; typedef pa_source_info_cb_t ma_pa_source_info_cb_t; typedef pa_stream_success_cb_t ma_pa_stream_success_cb_t; typedef pa_stream_request_cb_t ma_pa_stream_request_cb_t; +typedef pa_stream_notify_cb_t ma_pa_stream_notify_cb_t; typedef pa_free_cb_t ma_pa_free_cb_t; #else #define MA_PA_OK 0 #define MA_PA_ERR_ACCESS 1 #define MA_PA_ERR_INVALID 2 #define MA_PA_ERR_NOENTITY 5 +#define MA_PA_ERR_NOTSUPPORTED 19 #define MA_PA_CHANNELS_MAX 32 #define MA_PA_RATE_MAX 384000 @@ -15684,6 +15687,7 @@ typedef void (* ma_pa_sink_info_cb_t) (ma_pa_context* c, const ma_pa_sink_in typedef void (* ma_pa_source_info_cb_t) (ma_pa_context* c, const ma_pa_source_info* i, int eol, void* userdata); typedef void (* ma_pa_stream_success_cb_t)(ma_pa_stream* s, int success, void* userdata); typedef void (* ma_pa_stream_request_cb_t)(ma_pa_stream* s, size_t nbytes, void* userdata); +typedef void (* ma_pa_stream_notify_cb_t) (ma_pa_stream* s, void* userdata); typedef void (* ma_pa_free_cb_t) (void* p); #endif @@ -15735,6 +15739,8 @@ typedef ma_pa_operation* (* ma_pa_stream_set_buffer_attr_proc) ( typedef const char* (* ma_pa_stream_get_device_name_proc) (ma_pa_stream* s); typedef void (* ma_pa_stream_set_write_callback_proc) (ma_pa_stream* s, ma_pa_stream_request_cb_t cb, void* userdata); typedef void (* ma_pa_stream_set_read_callback_proc) (ma_pa_stream* s, ma_pa_stream_request_cb_t cb, void* userdata); +typedef void (* ma_pa_stream_set_suspended_callback_proc) (ma_pa_stream* s, ma_pa_stream_notify_cb_t cb, void* userdata); +typedef int (* ma_pa_stream_is_suspended_proc) (const ma_pa_stream* s); typedef ma_pa_operation* (* ma_pa_stream_flush_proc) (ma_pa_stream* s, ma_pa_stream_success_cb_t cb, void* userdata); typedef ma_pa_operation* (* ma_pa_stream_drain_proc) (ma_pa_stream* s, ma_pa_stream_success_cb_t cb, void* userdata); typedef int (* ma_pa_stream_is_corked_proc) (ma_pa_stream* s); @@ -16607,6 +16613,36 @@ static void ma_device_on_write__pulse(ma_pa_stream* pStream, size_t byteCount, v } } +static void ma_device_on_suspended__pulse(ma_pa_stream* pStream, void* pUserData) +{ + ma_device* pDevice = (ma_device*)pUserData; + int suspended; + + (void)pStream; + + suspended = ((ma_pa_stream_is_suspended_proc)pDevice->pContext->pulse.pa_stream_is_suspended)(pStream); + ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[Pulse] Device suspended state changed. pa_stream_is_suspended() returned %d.\n", suspended); + + if (suspended < 0) { + return; + } + + if (suspended == 1) { + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[Pulse] Device suspended state changed. Suspended.\n"); + + /* Locking this behind MA_DEBUG_OUTPUT for the moment while this is still in an experimental state. */ + #if defined(MA_DEBUG_OUTPUT) + { + if (pDevice->onStop) { + pDevice->onStop(pDevice); + } + } + #endif + } else { + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[Pulse] Device suspended state changed. Resumed.\n"); + } +} + static ma_result ma_device_init__pulse(ma_device* pDevice, const ma_device_config* pConfig, ma_device_descriptor* pDescriptorPlayback, ma_device_descriptor* pDescriptorCapture) { /* @@ -16826,6 +16862,9 @@ static ma_result ma_device_init__pulse(ma_device* pDevice, const ma_device_confi */ ((ma_pa_stream_set_write_callback_proc)pDevice->pContext->pulse.pa_stream_set_write_callback)((ma_pa_stream*)pDevice->pulse.pStreamPlayback, ma_device_on_write__pulse, pDevice); + /* State callback for checking when the device has been corked. */ + ((ma_pa_stream_set_suspended_callback_proc)pDevice->pContext->pulse.pa_stream_set_suspended_callback)((ma_pa_stream*)pDevice->pulse.pStreamPlayback, ma_device_on_suspended__pulse, pDevice); + /* Connect after we've got all of our internal state set up. */ streamFlags = MA_PA_STREAM_START_CORKED | MA_PA_STREAM_ADJUST_LATENCY | MA_PA_STREAM_FIX_FORMAT | MA_PA_STREAM_FIX_RATE | MA_PA_STREAM_FIX_CHANNELS; @@ -17146,6 +17185,8 @@ static ma_result ma_context_init__pulse(ma_context* pContext, const ma_context_c pContext->pulse.pa_stream_get_device_name = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_get_device_name"); pContext->pulse.pa_stream_set_write_callback = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_set_write_callback"); pContext->pulse.pa_stream_set_read_callback = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_set_read_callback"); + pContext->pulse.pa_stream_set_suspended_callback = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_set_suspended_callback"); + pContext->pulse.pa_stream_is_suspended = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_is_suspended"); pContext->pulse.pa_stream_flush = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_flush"); pContext->pulse.pa_stream_drain = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_drain"); pContext->pulse.pa_stream_is_corked = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_is_corked"); @@ -17206,6 +17247,8 @@ static ma_result ma_context_init__pulse(ma_context* pContext, const ma_context_c ma_pa_stream_get_device_name_proc _pa_stream_get_device_name = pa_stream_get_device_name; ma_pa_stream_set_write_callback_proc _pa_stream_set_write_callback = pa_stream_set_write_callback; ma_pa_stream_set_read_callback_proc _pa_stream_set_read_callback = pa_stream_set_read_callback; + ma_pa_stream_set_suspended_callback_proc _pa_stream_set_suspended_callback = pa_stream_set_suspended_callback; + ma_pa_stream_is_suspended_proc _pa_stream_is_suspended = pa_stream_is_suspended; ma_pa_stream_flush_proc _pa_stream_flush = pa_stream_flush; ma_pa_stream_drain_proc _pa_stream_drain = pa_stream_drain; ma_pa_stream_is_corked_proc _pa_stream_is_corked = pa_stream_is_corked; @@ -17265,6 +17308,8 @@ static ma_result ma_context_init__pulse(ma_context* pContext, const ma_context_c pContext->pulse.pa_stream_get_device_name = (ma_proc)_pa_stream_get_device_name; pContext->pulse.pa_stream_set_write_callback = (ma_proc)_pa_stream_set_write_callback; pContext->pulse.pa_stream_set_read_callback = (ma_proc)_pa_stream_set_read_callback; + pContext->pulse.pa_stream_set_suspended_callback = (ma_proc)_pa_stream_set_suspended_callback; + pContext->pulse.pa_stream_is_suspended = (ma_proc)_pa_stream_is_suspended; pContext->pulse.pa_stream_flush = (ma_proc)_pa_stream_flush; pContext->pulse.pa_stream_drain = (ma_proc)_pa_stream_drain; pContext->pulse.pa_stream_is_corked = (ma_proc)_pa_stream_is_corked; @@ -24901,8 +24946,11 @@ static ma_result ma_device_init__opensl(ma_device* pDevice, const ma_device_conf SLDataLocator_AndroidSimpleBufferQueue queue; SLresult resultSL; size_t bufferSizeInBytes; - SLInterfaceID itfIDs1[1]; - const SLboolean itfIDsRequired1[] = {SL_BOOLEAN_TRUE}; + SLInterfaceID itfIDs[2]; + const SLboolean itfIDsRequired[] = { + SL_BOOLEAN_TRUE, /* SL_IID_ANDROIDSIMPLEBUFFERQUEUE */ + SL_BOOLEAN_FALSE /* SL_IID_ANDROIDCONFIGURATION */ + }; #endif MA_ASSERT(g_maOpenSLInitCounter > 0); /* <-- If you trigger this it means you've either not initialized the context, or you've uninitialized it and then attempted to initialize a new device. */ @@ -24920,7 +24968,8 @@ static ma_result ma_device_init__opensl(ma_device* pDevice, const ma_device_conf queues). */ #ifdef MA_ANDROID - itfIDs1[0] = (SLInterfaceID)pDevice->pContext->opensl.SL_IID_ANDROIDSIMPLEBUFFERQUEUE; + itfIDs[0] = (SLInterfaceID)pDevice->pContext->opensl.SL_IID_ANDROIDSIMPLEBUFFERQUEUE; + itfIDs[1] = (SLInterfaceID)pDevice->pContext->opensl.SL_IID_ANDROIDCONFIGURATION; /* No exclusive mode with OpenSL|ES. */ if (((pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) && pDescriptorPlayback->shareMode == ma_share_mode_exclusive) || @@ -24956,7 +25005,7 @@ static ma_result ma_device_init__opensl(ma_device* pDevice, const ma_device_conf sink.pLocator = &queue; sink.pFormat = (SLDataFormat_PCM*)&pcm; - resultSL = (*g_maEngineSL)->CreateAudioRecorder(g_maEngineSL, (SLObjectItf*)&pDevice->opensl.pAudioRecorderObj, &source, &sink, 1, itfIDs1, itfIDsRequired1); + resultSL = (*g_maEngineSL)->CreateAudioRecorder(g_maEngineSL, (SLObjectItf*)&pDevice->opensl.pAudioRecorderObj, &source, &sink, ma_countof(itfIDs), itfIDs, itfIDsRequired); if (resultSL == SL_RESULT_CONTENT_UNSUPPORTED) { /* Unsupported format. Fall back to something safer and try again. If this fails, just abort. */ pcm.formatType = SL_DATAFORMAT_PCM; @@ -24965,7 +25014,7 @@ static ma_result ma_device_init__opensl(ma_device* pDevice, const ma_device_conf pcm.bitsPerSample = 16; pcm.containerSize = pcm.bitsPerSample; /* Always tightly packed for now. */ pcm.channelMask = SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT; - resultSL = (*g_maEngineSL)->CreateAudioRecorder(g_maEngineSL, (SLObjectItf*)&pDevice->opensl.pAudioRecorderObj, &source, &sink, 1, itfIDs1, itfIDsRequired1); + resultSL = (*g_maEngineSL)->CreateAudioRecorder(g_maEngineSL, (SLObjectItf*)&pDevice->opensl.pAudioRecorderObj, &source, &sink, ma_countof(itfIDs), itfIDs, itfIDsRequired); } if (resultSL != SL_RESULT_SUCCESS) { @@ -25070,7 +25119,7 @@ static ma_result ma_device_init__opensl(ma_device* pDevice, const ma_device_conf sink.pLocator = &outmixLocator; sink.pFormat = NULL; - resultSL = (*g_maEngineSL)->CreateAudioPlayer(g_maEngineSL, (SLObjectItf*)&pDevice->opensl.pAudioPlayerObj, &source, &sink, 1, itfIDs1, itfIDsRequired1); + resultSL = (*g_maEngineSL)->CreateAudioPlayer(g_maEngineSL, (SLObjectItf*)&pDevice->opensl.pAudioPlayerObj, &source, &sink, ma_countof(itfIDs), itfIDs, itfIDsRequired); if (resultSL == SL_RESULT_CONTENT_UNSUPPORTED) { /* Unsupported format. Fall back to something safer and try again. If this fails, just abort. */ pcm.formatType = SL_DATAFORMAT_PCM; @@ -25079,7 +25128,7 @@ static ma_result ma_device_init__opensl(ma_device* pDevice, const ma_device_conf pcm.bitsPerSample = 16; pcm.containerSize = pcm.bitsPerSample; /* Always tightly packed for now. */ pcm.channelMask = SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT; - resultSL = (*g_maEngineSL)->CreateAudioPlayer(g_maEngineSL, (SLObjectItf*)&pDevice->opensl.pAudioPlayerObj, &source, &sink, 1, itfIDs1, itfIDsRequired1); + resultSL = (*g_maEngineSL)->CreateAudioPlayer(g_maEngineSL, (SLObjectItf*)&pDevice->opensl.pAudioPlayerObj, &source, &sink, ma_countof(itfIDs), itfIDs, itfIDsRequired); } if (resultSL != SL_RESULT_SUCCESS) { @@ -43760,6 +43809,14 @@ static ma_result ma_decoder_init__internal(ma_decoder_read_proc onRead, ma_decod } } + /* + If we get to this point and we still haven't found a decoder, and the caller has requested a + specific encoding format, there's no hope for it. Abort. + */ + if (pConfig->encodingFormat != ma_encoding_format_unknown) { + return MA_NO_BACKEND; + } + #ifdef MA_HAS_WAV if (result != MA_SUCCESS) { result = ma_decoder_init_wav__internal(pConfig, pDecoder); @@ -44277,6 +44334,26 @@ MA_API ma_result ma_decoder_init_vfs(ma_vfs* pVFS, const char* pFilePath, const if (result != MA_SUCCESS) { /* Getting here means we weren't able to initialize a decoder of a specific encoding format. */ + + /* + We use trial and error to open a decoder. We prioritize custom decoders so that if they + implement the same encoding format they take priority over the built-in decoders. + */ + if (result != MA_SUCCESS) { + result = ma_decoder_init_custom__internal(&config, pDecoder); + if (result != MA_SUCCESS) { + ma_decoder__on_seek_vfs(pDecoder, 0, ma_seek_origin_start); + } + } + + /* + If we get to this point and we still haven't found a decoder, and the caller has requested a + specific encoding format, there's no hope for it. Abort. + */ + if (config.encodingFormat != ma_encoding_format_unknown) { + return MA_NO_BACKEND; + } + #ifdef MA_HAS_WAV if (result != MA_SUCCESS && ma_path_extension_equal(pFilePath, "wav")) { result = ma_decoder_init_wav__internal(&config, pDecoder); @@ -44463,6 +44540,26 @@ MA_API ma_result ma_decoder_init_vfs_w(ma_vfs* pVFS, const wchar_t* pFilePath, c if (result != MA_SUCCESS) { /* Getting here means we weren't able to initialize a decoder of a specific encoding format. */ + + /* + We use trial and error to open a decoder. We prioritize custom decoders so that if they + implement the same encoding format they take priority over the built-in decoders. + */ + if (result != MA_SUCCESS) { + result = ma_decoder_init_custom__internal(&config, pDecoder); + if (result != MA_SUCCESS) { + ma_decoder__on_seek_vfs(pDecoder, 0, ma_seek_origin_start); + } + } + + /* + If we get to this point and we still haven't found a decoder, and the caller has requested a + specific encoding format, there's no hope for it. Abort. + */ + if (config.encodingFormat != ma_encoding_format_unknown) { + return MA_NO_BACKEND; + } + #ifdef MA_HAS_WAV if (result != MA_SUCCESS && ma_path_extension_equal_w(pFilePath, L"wav")) { result = ma_decoder_init_wav__internal(&config, pDecoder); diff --git a/extras/miniaudio_split/miniaudio.h b/extras/miniaudio_split/miniaudio.h index ef6e4b92..1c145d5d 100644 --- a/extras/miniaudio_split/miniaudio.h +++ b/extras/miniaudio_split/miniaudio.h @@ -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 - v0.10.37 - 2021-07-06 +miniaudio - v0.10.38 - 2021-07-14 David Reid - mackron@gmail.com @@ -20,7 +20,7 @@ extern "C" { #define MA_VERSION_MAJOR 0 #define MA_VERSION_MINOR 10 -#define MA_VERSION_REVISION 37 +#define MA_VERSION_REVISION 38 #define MA_VERSION_STRING MA_XSTRINGIFY(MA_VERSION_MAJOR) "." MA_XSTRINGIFY(MA_VERSION_MINOR) "." MA_XSTRINGIFY(MA_VERSION_REVISION) #if defined(_MSC_VER) && !defined(__clang__) @@ -2384,6 +2384,8 @@ struct ma_context ma_proc pa_stream_get_device_name; ma_proc pa_stream_set_write_callback; ma_proc pa_stream_set_read_callback; + ma_proc pa_stream_set_suspended_callback; + ma_proc pa_stream_is_suspended; ma_proc pa_stream_flush; ma_proc pa_stream_drain; ma_proc pa_stream_is_corked; diff --git a/miniaudio.h b/miniaudio.h index ed247eba..182f4144 100644 --- a/miniaudio.h +++ b/miniaudio.h @@ -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 - v0.10.38 - TBD +miniaudio - v0.10.38 - 2021-07-14 David Reid - mackron@gmail.com @@ -69393,7 +69393,7 @@ The following miscellaneous changes have also been made. /* REVISION HISTORY ================ -v0.10.38 - TBD +v0.10.38 - 2021-07-14 - Fix a linking error when MA_DEBUG_OUTPUT is not enabled. - Fix an error where ma_log_postv() does not return a value. - OpenSL: Fix a bug with setting of stream types and recording presets.