From 7e38fa0e7ea34f60b61e436919ed36226244c8ea Mon Sep 17 00:00:00 2001 From: David Reid Date: Sat, 2 Dec 2023 07:42:39 +1000 Subject: [PATCH 01/20] Update dr_wav. --- miniaudio.h | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/miniaudio.h b/miniaudio.h index 5dfb4465..9a53a01b 100644 --- a/miniaudio.h +++ b/miniaudio.h @@ -59779,7 +59779,7 @@ extern "C" { #define MA_DR_WAV_XSTRINGIFY(x) MA_DR_WAV_STRINGIFY(x) #define MA_DR_WAV_VERSION_MAJOR 0 #define MA_DR_WAV_VERSION_MINOR 13 -#define MA_DR_WAV_VERSION_REVISION 13 +#define MA_DR_WAV_VERSION_REVISION 14 #define MA_DR_WAV_VERSION_STRING MA_DR_WAV_XSTRINGIFY(MA_DR_WAV_VERSION_MAJOR) "." MA_DR_WAV_XSTRINGIFY(MA_DR_WAV_VERSION_MINOR) "." MA_DR_WAV_XSTRINGIFY(MA_DR_WAV_VERSION_REVISION) #include #define MA_DR_WAVE_FORMAT_PCM 0x1 @@ -78903,9 +78903,7 @@ MA_PRIVATE ma_bool32 ma_dr_wav_init__internal(ma_dr_wav* pWav, ma_dr_wav_chunk_p } } if (isProcessingMetadata) { - ma_uint64 metadataBytesRead; - metadataBytesRead = ma_dr_wav__metadata_process_chunk(&metadataParser, &header, ma_dr_wav_metadata_type_all_including_unknown); - MA_DR_WAV_ASSERT(metadataBytesRead <= header.sizeInBytes); + ma_dr_wav__metadata_process_chunk(&metadataParser, &header, ma_dr_wav_metadata_type_all_including_unknown); if (ma_dr_wav__seek_from_start(pWav->onSeek, cursor, pWav->pUserData) == MA_FALSE) { break; } From 4f426f6db08dc5b111475b124627b6c92eb147a3 Mon Sep 17 00:00:00 2001 From: David Reid Date: Wed, 6 Dec 2023 07:59:52 +1000 Subject: [PATCH 02/20] Update change history. --- CHANGES.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGES.md b/CHANGES.md index 2d0211b6..9e9b218d 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -3,6 +3,7 @@ v0.11.22 - TBD * ALSA: Fix some warnings relating to unhandled return value of `read()`. * DirectSound: Add support for specifying an explicit window handle for SetCooperativeLevel(). * Web: Fix ScriptProcessorNode path when compiling with `--closure=1`. Note that the Audio Worklets path is not currently working due to the callback specified in `emscripten_create_wasm_audio_worklet_processor_async` never getting fired. +* Web: Fix an error with the unlocked notification when compiling as C++. v0.11.21 - 2023-11-15 From 6099e6f41ce8de668c38b44780b813e401e55c14 Mon Sep 17 00:00:00 2001 From: David Reid Date: Wed, 6 Dec 2023 08:12:21 +1000 Subject: [PATCH 03/20] Add support for customizing the min SDK version for AAudio. Define MA_AAUDIO_MIN_ANDROID_SDK_VERSION to specify the minimum required SDK version for enabling the AAudio backend. --- miniaudio.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/miniaudio.h b/miniaudio.h index 9a53a01b..6d4b7a30 100644 --- a/miniaudio.h +++ b/miniaudio.h @@ -17944,6 +17944,10 @@ DEVICE I/O #endif #endif +/* This must be set to at least 26. */ +#ifndef MA_AAUDIO_MIN_ANDROID_SDK_VERSION +#define MA_AAUDIO_MIN_ANDROID_SDK_VERSION 26 +#endif MA_API void ma_device_info_add_native_data_format(ma_device_info* pDeviceInfo, ma_format format, ma_uint32 channels, ma_uint32 sampleRate, ma_uint32 flags) @@ -18090,7 +18094,7 @@ MA_API ma_bool32 ma_is_backend_enabled(ma_backend backend) #if defined(MA_HAS_AAUDIO) #if defined(MA_ANDROID) { - return ma_android_sdk_version() >= 26; + return ma_android_sdk_version() >= MA_AAUDIO_MIN_ANDROID_SDK_VERSION; } #else return MA_FALSE; From ed204e4b72b7c996489dbd028accafee15b2284d Mon Sep 17 00:00:00 2001 From: xielock <1812822378@qq.com> Date: Thu, 30 Nov 2023 22:29:59 +0800 Subject: [PATCH 04/20] Fix bug in ma_node_detach_full(...) --- miniaudio.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/miniaudio.h b/miniaudio.h index 6d4b7a30..f482075d 100644 --- a/miniaudio.h +++ b/miniaudio.h @@ -72300,7 +72300,7 @@ static ma_result ma_node_detach_full(ma_node* pNode) linked list logic. We don't need to worry about the audio thread referencing these because the step above severed the connection to the graph. */ - for (pOutputBus = (ma_node_output_bus*)ma_atomic_load_ptr(&pInputBus->head.pNext); pOutputBus != NULL; pOutputBus = (ma_node_output_bus*)ma_atomic_load_ptr(&pOutputBus->pNext)) { + for (pOutputBus = (ma_node_output_bus*)ma_atomic_load_ptr(&pInputBus->head.pNext); pOutputBus != NULL; pOutputBus = (ma_node_output_bus*)ma_atomic_load_ptr(&pInputBus->head.pNext)) { ma_node_detach_output_bus(pOutputBus->pNode, pOutputBus->outputBusIndex); /* This won't do any waiting in practice and should be efficient. */ } } From 1325ac397bd99dd1f852f91525a798dd0ca9c8c8 Mon Sep 17 00:00:00 2001 From: David Reid Date: Fri, 8 Dec 2023 19:13:51 +1000 Subject: [PATCH 05/20] AAudio: Increase default min SDK version from 26 to 27. Use `#define MA_AAUDIO_MIN_ANDROID_SDK_VERSION 26` if you need to support SDK version 26. --- miniaudio.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/miniaudio.h b/miniaudio.h index f482075d..1f4822c5 100644 --- a/miniaudio.h +++ b/miniaudio.h @@ -17946,7 +17946,7 @@ DEVICE I/O /* This must be set to at least 26. */ #ifndef MA_AAUDIO_MIN_ANDROID_SDK_VERSION -#define MA_AAUDIO_MIN_ANDROID_SDK_VERSION 26 +#define MA_AAUDIO_MIN_ANDROID_SDK_VERSION 27 #endif From ee3b7df66aeb404e82571f58c10b9d524025d1ee Mon Sep 17 00:00:00 2001 From: David Reid Date: Sun, 10 Dec 2023 13:50:40 +1000 Subject: [PATCH 06/20] Update change history. --- CHANGES.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGES.md b/CHANGES.md index 9e9b218d..00ea97c7 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,9 +1,11 @@ v0.11.22 - TBD ===================== +* Fix a bug relating to node detachment. * ALSA: Fix some warnings relating to unhandled return value of `read()`. * DirectSound: Add support for specifying an explicit window handle for SetCooperativeLevel(). * Web: Fix ScriptProcessorNode path when compiling with `--closure=1`. Note that the Audio Worklets path is not currently working due to the callback specified in `emscripten_create_wasm_audio_worklet_processor_async` never getting fired. * Web: Fix an error with the unlocked notification when compiling as C++. +* AAudio: The default minimum SDK version has been increased from 26 to 27 when enabling AAudio. If you need to support version 26, you can use `#define MA_AAUDIO_MIN_ANDROID_SDK_VERSION 26`. v0.11.21 - 2023-11-15 From c29c001840b5de7740655fee0e3845d49ecd58e7 Mon Sep 17 00:00:00 2001 From: David Reid Date: Wed, 13 Dec 2023 08:36:03 +1000 Subject: [PATCH 07/20] Fix an error where the pthread priority is not being set correctly. --- miniaudio.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/miniaudio.h b/miniaudio.h index 1f4822c5..70040735 100644 --- a/miniaudio.h +++ b/miniaudio.h @@ -16158,8 +16158,10 @@ static ma_result ma_thread_create__posix(ma_thread* pThread, ma_thread_priority } } - /* I'm not treating a failure of setting the priority as a critical error so not checking the return value here. */ - pthread_attr_setschedparam(&attr, &sched); + /* I'm not treating a failure of setting the priority as a critical error so not aborting on failure here. */ + if (pthread_attr_setschedparam(&attr, &sched) == 0) { + pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED); + } } } } From 766a155fb3170e1e86b87612abb08bf5f1f8bd96 Mon Sep 17 00:00:00 2001 From: David Reid Date: Sun, 17 Dec 2023 08:42:19 +1000 Subject: [PATCH 08/20] Stop using MA_ASSERT in examples. This is useful because MA_ASSERT is only defined in the implementation section of miniaudio.h which can cause issues when people copy/paste the code and use it in a file that does not have visibility of the implementation. Note that there are still more references to implementation-defined macros, but these have been moved to the public section in the dev-0.12 branch so I'm not bothering to change those just yet. Public issue https://github.com/mackron/miniaudio/issues/787 --- examples/custom_backend.c | 33 +------------------ examples/data_source_chaining.c | 4 ++- examples/duplex_effect.c | 11 +++++-- examples/node_graph.c | 2 -- examples/resource_manager.c | 1 - examples/resource_manager_advanced.c | 15 ++++----- examples/simple_capture.c | 5 +-- examples/simple_duplex.c | 6 ++-- examples/simple_loopback.c | 5 +-- examples/simple_mixing.c | 4 +-- examples/simple_playback_sine.c | 9 +---- .../ma_delay_node/ma_delay_node_example.c | 9 +++-- .../ma_reverb_node/ma_reverb_node_example.c | 9 +++-- .../ma_vocoder_node/ma_vocoder_node_example.c | 9 +++-- 14 files changed, 48 insertions(+), 74 deletions(-) diff --git a/examples/custom_backend.c b/examples/custom_backend.c index e30cd463..5c0b4d71 100644 --- a/examples/custom_backend.c +++ b/examples/custom_backend.c @@ -180,9 +180,6 @@ static ma_result ma_context_enumerate_devices__sdl(ma_context* pContext, ma_enum ma_bool32 cbResult; int iDevice; - MA_ASSERT(pContext != NULL); - MA_ASSERT(callback != NULL); - /* Playback */ if (!isTerminated) { int deviceCount = ((MA_PFN_SDL_GetNumAudioDevices)pContextEx->sdl.SDL_GetNumAudioDevices)(0); @@ -241,8 +238,6 @@ static ma_result ma_context_get_device_info__sdl(ma_context* pContext, ma_device const char* pDeviceName; #endif - MA_ASSERT(pContext != NULL); - if (pDeviceID == NULL) { if (deviceType == ma_device_type_playback) { pDeviceInfo->id.custom.i = 0; @@ -322,8 +317,6 @@ void ma_audio_callback_capture__sdl(void* pUserData, ma_uint8* pBuffer, int buff { ma_device_ex* pDeviceEx = (ma_device_ex*)pUserData; - MA_ASSERT(pDeviceEx != NULL); - ma_device_handle_backend_data_callback((ma_device*)pDeviceEx, NULL, pBuffer, (ma_uint32)bufferSizeInBytes / ma_get_bytes_per_frame(pDeviceEx->device.capture.internalFormat, pDeviceEx->device.capture.internalChannels)); } @@ -331,8 +324,6 @@ void ma_audio_callback_playback__sdl(void* pUserData, ma_uint8* pBuffer, int buf { ma_device_ex* pDeviceEx = (ma_device_ex*)pUserData; - MA_ASSERT(pDeviceEx != NULL); - ma_device_handle_backend_data_callback((ma_device*)pDeviceEx, pBuffer, NULL, (ma_uint32)bufferSizeInBytes / ma_get_bytes_per_frame(pDeviceEx->device.playback.internalFormat, pDeviceEx->device.playback.internalChannels)); } @@ -344,9 +335,6 @@ static ma_result ma_device_init_internal__sdl(ma_device_ex* pDeviceEx, const ma_ const char* pDeviceName; int deviceID; - MA_ASSERT(pDeviceEx != NULL); - MA_ASSERT(pDescriptor != NULL); - /* SDL is a little bit awkward with specifying the buffer size, You need to specify the size of the buffer in frames, but since we may have requested a period size in milliseconds we'll need to convert, which depends on the sample rate. But there's a possibility that @@ -430,8 +418,6 @@ static ma_result ma_device_init__sdl(ma_device* pDevice, const ma_device_config* ma_context_ex* pContextEx = (ma_context_ex*)pDevice->pContext; ma_result result; - MA_ASSERT(pDevice != NULL); - /* SDL does not support loopback mode, so must return MA_DEVICE_TYPE_NOT_SUPPORTED if it's requested. */ if (pConfig->deviceType == ma_device_type_loopback) { return MA_DEVICE_TYPE_NOT_SUPPORTED; @@ -463,8 +449,6 @@ static ma_result ma_device_uninit__sdl(ma_device* pDevice) ma_device_ex* pDeviceEx = (ma_device_ex*)pDevice; ma_context_ex* pContextEx = (ma_context_ex*)pDevice->pContext; - MA_ASSERT(pDevice != NULL); - if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) { ((MA_PFN_SDL_CloseAudioDevice)pContextEx->sdl.SDL_CloseAudioDevice)(pDeviceEx->sdl.deviceIDCapture); } @@ -481,8 +465,6 @@ static ma_result ma_device_start__sdl(ma_device* pDevice) ma_device_ex* pDeviceEx = (ma_device_ex*)pDevice; ma_context_ex* pContextEx = (ma_context_ex*)pDevice->pContext; - MA_ASSERT(pDevice != NULL); - if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) { ((MA_PFN_SDL_PauseAudioDevice)pContextEx->sdl.SDL_PauseAudioDevice)(pDeviceEx->sdl.deviceIDCapture, 0); } @@ -499,8 +481,6 @@ static ma_result ma_device_stop__sdl(ma_device* pDevice) ma_device_ex* pDeviceEx = (ma_device_ex*)pDevice; ma_context_ex* pContextEx = (ma_context_ex*)pDevice->pContext; - MA_ASSERT(pDevice != NULL); - if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) { ((MA_PFN_SDL_PauseAudioDevice)pContextEx->sdl.SDL_PauseAudioDevice)(pDeviceEx->sdl.deviceIDCapture, 1); } @@ -516,8 +496,6 @@ static ma_result ma_context_uninit__sdl(ma_context* pContext) { ma_context_ex* pContextEx = (ma_context_ex*)pContext; - MA_ASSERT(pContext != NULL); - ((MA_PFN_SDL_QuitSubSystem)pContextEx->sdl.SDL_QuitSubSystem)(MA_SDL_INIT_AUDIO); /* Close the handle to the SDL shared object last. */ @@ -545,8 +523,6 @@ static ma_result ma_context_init__sdl(ma_context* pContext, const ma_context_con #endif }; - MA_ASSERT(pContext != NULL); - (void)pConfig; /* Check if we have SDL2 installed somewhere. If not it's not usable and we need to abort. */ @@ -641,15 +617,8 @@ Main program starts here. void data_callback(ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount) { - MA_ASSERT(pDevice->playback.channels == DEVICE_CHANNELS); - if (pDevice->type == ma_device_type_playback) { - ma_waveform* pSineWave; - - pSineWave = (ma_waveform*)pDevice->pUserData; - MA_ASSERT(pSineWave != NULL); - - ma_waveform_read_pcm_frames(pSineWave, pOutput, frameCount, NULL); + ma_waveform_read_pcm_frames((ma_waveform*)pDevice->pUserData, pOutput, frameCount, NULL); } if (pDevice->type == ma_device_type_duplex) { diff --git a/examples/data_source_chaining.c b/examples/data_source_chaining.c index 6d019903..c04b4534 100644 --- a/examples/data_source_chaining.c +++ b/examples/data_source_chaining.c @@ -49,7 +49,9 @@ ma_decoder* g_pDecoders; static ma_data_source* next_callback_tail(ma_data_source* pDataSource) { - MA_ASSERT(g_decoderCount > 0); /* <-- We check for this in main() so should never happen. */ + if (g_decoderCount > 0) { /* <-- We check for this in main() so should never happen. */ + return NULL; + } /* This will be fired when the last item in the chain has reached the end. In this example we want diff --git a/examples/duplex_effect.c b/examples/duplex_effect.c index 2c2a5459..6a07fd25 100644 --- a/examples/duplex_effect.c +++ b/examples/duplex_effect.c @@ -12,7 +12,7 @@ effect. #include -#define DEVICE_FORMAT ma_format_f32; /* Must always be f32 for this example because the node graph system only works with this. */ +#define DEVICE_FORMAT ma_format_f32 /* Must always be f32 for this example because the node graph system only works with this. */ #define DEVICE_CHANNELS 1 /* For this example, always set to 1. */ static ma_waveform g_sourceData; /* The underlying data source of the source node. */ @@ -24,8 +24,13 @@ static ma_node_graph g_nodeGraph; void data_callback(ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount) { - MA_ASSERT(pDevice->capture.format == pDevice->playback.format); - MA_ASSERT(pDevice->capture.channels == pDevice->playback.channels); + /* + This example assumes the playback and capture sides use the same format and channel count. The + format must be f32. + */ + if (pDevice->capture.format != DEVICE_FORMAT || pDevice->playback.format != DEVICE_FORMAT || pDevice->capture.channels != pDevice->playback.channels) { + return; + } /* The node graph system is a pulling style of API. At the lowest level of the chain will be a diff --git a/examples/node_graph.c b/examples/node_graph.c index aecccfe7..83aa8945 100644 --- a/examples/node_graph.c +++ b/examples/node_graph.c @@ -81,8 +81,6 @@ static int g_soundNodeCount; void data_callback(ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount) { - MA_ASSERT(pDevice->playback.channels == CHANNELS); - /* Hearing the output of the node graph is as easy as reading straight into the output buffer. You just need to make sure you use a consistent data format or else you'll need to do your own conversion. diff --git a/examples/resource_manager.c b/examples/resource_manager.c index d9a9697f..27d7fd51 100644 --- a/examples/resource_manager.c +++ b/examples/resource_manager.c @@ -33,7 +33,6 @@ set, each sound will have their own formats and you'll need to do the necessary void main_loop__em(void* pUserData) { ma_resource_manager* pResourceManager = (ma_resource_manager*)pUserData; - MA_ASSERT(pResourceManager != NULL); /* The Emscripten build does not support threading which means we need to process jobs manually. If diff --git a/examples/resource_manager_advanced.c b/examples/resource_manager_advanced.c index 19236c33..d757b027 100644 --- a/examples/resource_manager_advanced.c +++ b/examples/resource_manager_advanced.c @@ -32,8 +32,6 @@ static ma_result ma_data_source_read_pcm_frames_f32_ex(ma_data_source* pDataSour This function is intended to be used when the format and channel count of the data source is known beforehand. The idea is to avoid overhead due to redundant calls to ma_data_source_get_data_format(). */ - MA_ASSERT(pDataSource != NULL); - if (dataSourceFormat == ma_format_f32) { /* Fast path. No conversion necessary. */ return ma_data_source_read_pcm_frames(pDataSource, pFramesOut, frameCount, pFramesRead); @@ -136,10 +134,6 @@ void data_callback(ma_device* pDevice, void* pOutput, const void* pInput, ma_uin */ ma_uint32 iDataSource; - MA_ASSERT(pDevice->playback.format == ma_format_f32); - - (void)pInput; /* Unused. */ - /* If the device was configured with noPreSilencedOutputBuffer then you would need to silence the buffer here, or make sure the first data source to be mixed is copied rather than mixed. @@ -150,12 +144,15 @@ void data_callback(ma_device* pDevice, void* pOutput, const void* pInput, ma_uin for (iDataSource = 0; iDataSource < g_dataSourceCount; iDataSource += 1) { ma_data_source_read_pcm_frames_and_mix_f32(&g_dataSources[iDataSource], (float*)pOutput, frameCount, NULL, /* volume = */1); } + + /* Unused. */ + (void)pInput; + (void)pDevice; } static ma_thread_result MA_THREADCALL custom_job_thread(void* pUserData) { ma_resource_manager* pResourceManager = (ma_resource_manager*)pUserData; - MA_ASSERT(pResourceManager != NULL); for (;;) { ma_result result; @@ -191,8 +188,8 @@ static ma_thread_result MA_THREADCALL custom_job_thread(void* pUserData) event is received which means the `result != MA_SUCCESS` logic above will catch it. If you do not check the return value of ma_resource_manager_next_job() you will want to check for MA_RESOURCE_MANAGER_JOB_QUIT like the code below. */ - if (job.toc.breakup.code == MA_RESOURCE_MANAGER_JOB_QUIT) { - printf("CUSTOM JOB THREAD TERMINATING VIA MA_RESOURCE_MANAGER_JOB_QUIT... "); + if (job.toc.breakup.code == MA_JOB_TYPE_QUIT) { + printf("CUSTOM JOB THREAD TERMINATING VIA MA_JOB_TYPE_QUIT... "); break; } diff --git a/examples/simple_capture.c b/examples/simple_capture.c index e3b18248..6c08dc15 100644 --- a/examples/simple_capture.c +++ b/examples/simple_capture.c @@ -16,10 +16,7 @@ data received by the microphone straight to a WAV file. void data_callback(ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount) { - ma_encoder* pEncoder = (ma_encoder*)pDevice->pUserData; - MA_ASSERT(pEncoder != NULL); - - ma_encoder_write_pcm_frames(pEncoder, pInput, frameCount, NULL); + ma_encoder_write_pcm_frames((ma_encoder*)pDevice->pUserData, pInput, frameCount, NULL); (void)pOutput; } diff --git a/examples/simple_duplex.c b/examples/simple_duplex.c index c604db51..69cc6d84 100644 --- a/examples/simple_duplex.c +++ b/examples/simple_duplex.c @@ -23,8 +23,10 @@ void main_loop__em() void data_callback(ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount) { - MA_ASSERT(pDevice->capture.format == pDevice->playback.format); - MA_ASSERT(pDevice->capture.channels == pDevice->playback.channels); + /* This example assumes the playback and capture sides use the same format and channel count. */ + if (pDevice->capture.format != pDevice->playback.format || pDevice->capture.channels != pDevice->playback.channels) { + return; + } /* In this example the format and channel count are the same for both input and output which means we can just memcpy(). */ MA_COPY_MEMORY(pOutput, pInput, frameCount * ma_get_bytes_per_frame(pDevice->capture.format, pDevice->capture.channels)); diff --git a/examples/simple_loopback.c b/examples/simple_loopback.c index c8318d6d..df5fb0ab 100644 --- a/examples/simple_loopback.c +++ b/examples/simple_loopback.c @@ -18,10 +18,7 @@ properties. The output buffer in the callback will be null whereas the input buf void data_callback(ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount) { - ma_encoder* pEncoder = (ma_encoder*)pDevice->pUserData; - MA_ASSERT(pEncoder != NULL); - - ma_encoder_write_pcm_frames(pEncoder, pInput, frameCount, NULL); + ma_encoder_write_pcm_frames((ma_encoder*)pDevice->pUserData, pInput, frameCount, NULL); (void)pOutput; } diff --git a/examples/simple_mixing.c b/examples/simple_mixing.c index e4c81b05..30e906e6 100644 --- a/examples/simple_mixing.c +++ b/examples/simple_mixing.c @@ -87,8 +87,7 @@ void data_callback(ma_device* pDevice, void* pOutput, const void* pInput, ma_uin float* pOutputF32 = (float*)pOutput; ma_uint32 iDecoder; - MA_ASSERT(pDevice->playback.format == SAMPLE_FORMAT); /* <-- Important for this example. */ - + /* This example assumes the device was configured to use ma_format_f32. */ for (iDecoder = 0; iDecoder < g_decoderCount; ++iDecoder) { if (!g_pDecodersAtEnd[iDecoder]) { ma_uint32 framesRead = read_and_mix_pcm_frames_f32(&g_pDecoders[iDecoder], pOutputF32, frameCount); @@ -107,6 +106,7 @@ void data_callback(ma_device* pDevice, void* pOutput, const void* pInput, ma_uin } (void)pInput; + (void)pDevice; } int main(int argc, char** argv) diff --git a/examples/simple_playback_sine.c b/examples/simple_playback_sine.c index ab1f25fb..d053f5a0 100644 --- a/examples/simple_playback_sine.c +++ b/examples/simple_playback_sine.c @@ -33,14 +33,7 @@ void main_loop__em() void data_callback(ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount) { - ma_waveform* pSineWave; - - MA_ASSERT(pDevice->playback.channels == DEVICE_CHANNELS); - - pSineWave = (ma_waveform*)pDevice->pUserData; - MA_ASSERT(pSineWave != NULL); - - ma_waveform_read_pcm_frames(pSineWave, pOutput, frameCount, NULL); + ma_waveform_read_pcm_frames((ma_waveform*)pDevice->pUserData, pOutput, frameCount, NULL); (void)pInput; /* Unused. */ } diff --git a/extras/nodes/ma_delay_node/ma_delay_node_example.c b/extras/nodes/ma_delay_node/ma_delay_node_example.c index 3fcb4aa3..6f102c81 100644 --- a/extras/nodes/ma_delay_node/ma_delay_node_example.c +++ b/extras/nodes/ma_delay_node/ma_delay_node_example.c @@ -15,8 +15,13 @@ static ma_node_graph g_nodeGraph; /* The main node graph that we'l void data_callback(ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount) { - MA_ASSERT(pDevice->capture.format == pDevice->playback.format && pDevice->capture.format == ma_format_f32); - MA_ASSERT(pDevice->capture.channels == pDevice->playback.channels); + /* + This example assumes the playback and capture sides use the same format and channel count. The + format must be f32. + */ + if (pDevice->capture.format != DEVICE_FORMAT || pDevice->playback.format != DEVICE_FORMAT || pDevice->capture.channels != pDevice->playback.channels) { + return; + } /* The node graph system is a pulling style of API. At the lowest level of the chain will be a diff --git a/extras/nodes/ma_reverb_node/ma_reverb_node_example.c b/extras/nodes/ma_reverb_node/ma_reverb_node_example.c index 55ec444f..5102ab07 100644 --- a/extras/nodes/ma_reverb_node/ma_reverb_node_example.c +++ b/extras/nodes/ma_reverb_node/ma_reverb_node_example.c @@ -15,8 +15,13 @@ static ma_node_graph g_nodeGraph; /* The main node graph that we'l void data_callback(ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount) { - MA_ASSERT(pDevice->capture.format == pDevice->playback.format && pDevice->capture.format == ma_format_f32); - MA_ASSERT(pDevice->capture.channels == pDevice->playback.channels); + /* + This example assumes the playback and capture sides use the same format and channel count. The + format must be f32. + */ + if (pDevice->capture.format != DEVICE_FORMAT || pDevice->playback.format != DEVICE_FORMAT || pDevice->capture.channels != pDevice->playback.channels) { + return; + } /* The node graph system is a pulling style of API. At the lowest level of the chain will be a diff --git a/extras/nodes/ma_vocoder_node/ma_vocoder_node_example.c b/extras/nodes/ma_vocoder_node/ma_vocoder_node_example.c index 57700982..9e501005 100644 --- a/extras/nodes/ma_vocoder_node/ma_vocoder_node_example.c +++ b/extras/nodes/ma_vocoder_node/ma_vocoder_node_example.c @@ -24,8 +24,13 @@ static ma_node_graph g_nodeGraph; void data_callback(ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount) { - MA_ASSERT(pDevice->capture.format == pDevice->playback.format); - MA_ASSERT(pDevice->capture.channels == pDevice->playback.channels); + /* + This example assumes the playback and capture sides use the same format and channel count. The + format must be f32. + */ + if (pDevice->capture.format != DEVICE_FORMAT || pDevice->playback.format != DEVICE_FORMAT || pDevice->capture.channels != pDevice->playback.channels) { + return; + } /* The node graph system is a pulling style of API. At the lowest level of the chain will be a From fde3a27d930113a7035a09857055601b53bcd203 Mon Sep 17 00:00:00 2001 From: David Reid Date: Sat, 23 Dec 2023 09:21:13 +1000 Subject: [PATCH 09/20] Add support for customizing pthread priorities at compile time. Use the MA_PTHREAD_REALTTIME_THREAD_PRIORITY define. --- miniaudio.h | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/miniaudio.h b/miniaudio.h index 70040735..d0293e6a 100644 --- a/miniaudio.h +++ b/miniaudio.h @@ -16147,15 +16147,24 @@ static ma_result ma_thread_create__posix(ma_thread* pThread, ma_thread_priority if (priority == ma_thread_priority_idle) { sched.sched_priority = priorityMin; } else if (priority == ma_thread_priority_realtime) { - sched.sched_priority = priorityMax; - } else { - sched.sched_priority += ((int)priority + 5) * priorityStep; /* +5 because the lowest priority is -5. */ - if (sched.sched_priority < priorityMin) { - sched.sched_priority = priorityMin; + #if defined(MA_PTHREAD_REALTTIME_THREAD_PRIORITY) + { + sched.sched_priority = MA_PTHREAD_REALTTIME_THREAD_PRIORITY; } - if (sched.sched_priority > priorityMax) { + #else + { sched.sched_priority = priorityMax; } + #endif + } else { + sched.sched_priority += ((int)priority + 5) * priorityStep; /* +5 because the lowest priority is -5. */ + } + + if (sched.sched_priority < priorityMin) { + sched.sched_priority = priorityMin; + } + if (sched.sched_priority > priorityMax) { + sched.sched_priority = priorityMax; } /* I'm not treating a failure of setting the priority as a critical error so not aborting on failure here. */ From 9c73849f3b2c92d7ea8d9a1645ec33b63f618fd8 Mon Sep 17 00:00:00 2001 From: David Reid Date: Sat, 23 Dec 2023 09:30:08 +1000 Subject: [PATCH 10/20] Fix a typo. --- miniaudio.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/miniaudio.h b/miniaudio.h index d0293e6a..24ce3941 100644 --- a/miniaudio.h +++ b/miniaudio.h @@ -16147,9 +16147,9 @@ static ma_result ma_thread_create__posix(ma_thread* pThread, ma_thread_priority if (priority == ma_thread_priority_idle) { sched.sched_priority = priorityMin; } else if (priority == ma_thread_priority_realtime) { - #if defined(MA_PTHREAD_REALTTIME_THREAD_PRIORITY) + #if defined(MA_PTHREAD_REALTIME_THREAD_PRIORITY) { - sched.sched_priority = MA_PTHREAD_REALTTIME_THREAD_PRIORITY; + sched.sched_priority = MA_PTHREAD_REALTIME_THREAD_PRIORITY; } #else { From bdab2fc3e0454b0fb7c28900b30534ad881f2e5d Mon Sep 17 00:00:00 2001 From: David Reid Date: Mon, 8 Jan 2024 12:30:04 +1000 Subject: [PATCH 11/20] Remove an accidental change to the deviceio test. --- tests/test_deviceio/ma_test_deviceio.c | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/test_deviceio/ma_test_deviceio.c b/tests/test_deviceio/ma_test_deviceio.c index 6c8ceaf5..f7b049b6 100644 --- a/tests/test_deviceio/ma_test_deviceio.c +++ b/tests/test_deviceio/ma_test_deviceio.c @@ -41,7 +41,6 @@ will receive the captured audio. If multiple backends are specified, the priority will be based on the order in which you specify them. If multiple waveform or noise types are specified the last one on the command line will have priority. */ -#define MA_FORCE_UWP #include "../test_common/ma_test_common.c" typedef enum From 10f9ef05a2a9c888308ca95b135e5a2952872bd7 Mon Sep 17 00:00:00 2001 From: David Reid Date: Mon, 8 Jan 2024 12:50:20 +1000 Subject: [PATCH 12/20] DirectSound: Attempted fix for an error when switching devices. Public issue https://github.com/mackron/miniaudio/issues/779 --- miniaudio.h | 35 +++++++++++++++++++++++++++++------ 1 file changed, 29 insertions(+), 6 deletions(-) diff --git a/miniaudio.h b/miniaudio.h index 24ce3941..a2885721 100644 --- a/miniaudio.h +++ b/miniaudio.h @@ -11211,12 +11211,12 @@ MA_API ma_engine_config ma_engine_config_init(void); struct ma_engine { - ma_node_graph nodeGraph; /* An engine is a node graph. It should be able to be plugged into any ma_node_graph API (with a cast) which means this must be the first member of this struct. */ + ma_node_graph nodeGraph; /* An engine is a node graph. It should be able to be plugged into any ma_node_graph API (with a cast) which means this must be the first member of this struct. */ #if !defined(MA_NO_RESOURCE_MANAGER) ma_resource_manager* pResourceManager; #endif #if !defined(MA_NO_DEVICE_IO) - ma_device* pDevice; /* Optionally set via the config, otherwise allocated by the engine in ma_engine_init(). */ + ma_device* pDevice; /* Optionally set via the config, otherwise allocated by the engine in ma_engine_init(). */ #endif ma_log* pLog; ma_uint32 sampleRate; @@ -11225,10 +11225,10 @@ struct ma_engine ma_allocation_callbacks allocationCallbacks; ma_bool8 ownsResourceManager; ma_bool8 ownsDevice; - ma_spinlock inlinedSoundLock; /* For synchronizing access so the inlined sound list. */ - ma_sound_inlined* pInlinedSoundHead; /* The first inlined sound. Inlined sounds are tracked in a linked list. */ - MA_ATOMIC(4, ma_uint32) inlinedSoundCount; /* The total number of allocated inlined sound objects. Used for debugging. */ - ma_uint32 gainSmoothTimeInFrames; /* The number of frames to interpolate the gain of spatialized sounds across. */ + ma_spinlock inlinedSoundLock; /* For synchronizing access so the inlined sound list. */ + ma_sound_inlined* pInlinedSoundHead; /* The first inlined sound. Inlined sounds are tracked in a linked list. */ + MA_ATOMIC(4, ma_uint32) inlinedSoundCount; /* The total number of allocated inlined sound objects. Used for debugging. */ + ma_uint32 gainSmoothTimeInFrames; /* The number of frames to interpolate the gain of spatialized sounds across. */ ma_uint32 defaultVolumeSmoothTimeInPCMFrames; ma_mono_expansion_mode monoExpansionMode; ma_engine_process_proc onProcess; @@ -23680,6 +23680,13 @@ DirectSound Backend #define MA_DSBPLAY_TERMINATEBY_DISTANCE 0x00000010 #define MA_DSBPLAY_TERMINATEBY_PRIORITY 0x00000020 +#define MA_DSBSTATUS_PLAYING 0x00000001 +#define MA_DSBSTATUS_BUFFERLOST 0x00000002 +#define MA_DSBSTATUS_LOOPING 0x00000004 +#define MA_DSBSTATUS_LOCHARDWARE 0x00000008 +#define MA_DSBSTATUS_LOCSOFTWARE 0x00000010 +#define MA_DSBSTATUS_TERMINATED 0x00000020 + #define MA_DSCBSTART_LOOPING 0x00000001 typedef struct @@ -24842,6 +24849,7 @@ static ma_result ma_device_data_loop__dsound(ma_device* pDevice) ma_bool32 isPlaybackDeviceStarted = MA_FALSE; ma_uint32 framesWrittenToPlaybackDevice = 0; /* For knowing whether or not the playback device needs to be started. */ ma_uint32 waitTimeInMilliseconds = 1; + DWORD playbackBufferStatus = 0; MA_ASSERT(pDevice != NULL); @@ -25170,6 +25178,21 @@ static ma_result ma_device_data_loop__dsound(ma_device* pDevice) break; } + hr = ma_IDirectSoundBuffer_GetStatus((ma_IDirectSoundBuffer*)pDevice->dsound.pPlaybackBuffer, &playbackBufferStatus); + if (SUCCEEDED(hr) && (playbackBufferStatus & MA_DSBSTATUS_PLAYING) == 0 && isPlaybackDeviceStarted) + { + ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, "[DirectSound] Attempting to resume audio due to state: %d.", (int)playbackBufferStatus); + hr = ma_IDirectSoundBuffer_Play((ma_IDirectSoundBuffer*)pDevice->dsound.pPlaybackBuffer, 0, 0, MA_DSBPLAY_LOOPING); + if (FAILED(hr)) { + ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[DirectSound] IDirectSoundBuffer_Play() failed after attempting to resume from state %d.", (int)playbackBufferStatus); + return ma_result_from_HRESULT(hr); + } + + isPlaybackDeviceStarted = MA_TRUE; + ma_sleep(waitTimeInMilliseconds); + continue; + } + if (physicalPlayCursorInBytes < prevPlayCursorInBytesPlayback) { physicalPlayCursorLoopFlagPlayback = !physicalPlayCursorLoopFlagPlayback; } From fd3c1b0af094d7870f6f5d9d5db10ea4dea7430f Mon Sep 17 00:00:00 2001 From: David Reid Date: Wed, 10 Jan 2024 18:19:24 +1000 Subject: [PATCH 13/20] Formatting. --- miniaudio.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/miniaudio.h b/miniaudio.h index a2885721..e9baee6d 100644 --- a/miniaudio.h +++ b/miniaudio.h @@ -25179,8 +25179,7 @@ static ma_result ma_device_data_loop__dsound(ma_device* pDevice) } hr = ma_IDirectSoundBuffer_GetStatus((ma_IDirectSoundBuffer*)pDevice->dsound.pPlaybackBuffer, &playbackBufferStatus); - if (SUCCEEDED(hr) && (playbackBufferStatus & MA_DSBSTATUS_PLAYING) == 0 && isPlaybackDeviceStarted) - { + if (SUCCEEDED(hr) && (playbackBufferStatus & MA_DSBSTATUS_PLAYING) == 0 && isPlaybackDeviceStarted) { ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, "[DirectSound] Attempting to resume audio due to state: %d.", (int)playbackBufferStatus); hr = ma_IDirectSoundBuffer_Play((ma_IDirectSoundBuffer*)pDevice->dsound.pPlaybackBuffer, 0, 0, MA_DSBPLAY_LOOPING); if (FAILED(hr)) { From a4aa0dc404c1ddd6418a730c15c3c9dcf5f829b9 Mon Sep 17 00:00:00 2001 From: David Reid Date: Fri, 12 Jan 2024 08:10:53 +1000 Subject: [PATCH 14/20] Fix amplification with `ma_device_set_master_volume()`. Public issue https://github.com/mackron/miniaudio/discussions/800 --- CHANGES.md | 1 + miniaudio.h | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 00ea97c7..b823da39 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,6 +1,7 @@ v0.11.22 - TBD ===================== * Fix a bug relating to node detachment. +* Fix a bug where amplification with `ma_device_set_master_volume()` does not work. * ALSA: Fix some warnings relating to unhandled return value of `read()`. * DirectSound: Add support for specifying an explicit window handle for SetCooperativeLevel(). * Web: Fix ScriptProcessorNode path when compiling with `--closure=1`. Note that the Audio Worklets path is not currently working due to the callback specified in `emscripten_create_wasm_audio_worklet_processor_async` never getting fired. diff --git a/miniaudio.h b/miniaudio.h index e9baee6d..c1621aee 100644 --- a/miniaudio.h +++ b/miniaudio.h @@ -18827,7 +18827,7 @@ static void ma_device__handle_data_callback(ma_device* pDevice, void* pFramesOut unsigned int prevDenormalState = ma_device_disable_denormals(pDevice); { /* Volume control of input makes things a bit awkward because the input buffer is read-only. We'll need to use a temp buffer and loop in this case. */ - if (pFramesIn != NULL && masterVolumeFactor < 1) { + if (pFramesIn != NULL && masterVolumeFactor != 1) { ma_uint8 tempFramesIn[MA_DATA_CONVERTER_STACK_BUFFER_SIZE]; ma_uint32 bpfCapture = ma_get_bytes_per_frame(pDevice->capture.format, pDevice->capture.channels); ma_uint32 bpfPlayback = ma_get_bytes_per_frame(pDevice->playback.format, pDevice->playback.channels); @@ -18850,7 +18850,7 @@ static void ma_device__handle_data_callback(ma_device* pDevice, void* pFramesOut /* Volume control and clipping for playback devices. */ if (pFramesOut != NULL) { - if (masterVolumeFactor < 1) { + if (masterVolumeFactor != 1) { if (pFramesIn == NULL) { /* <-- In full-duplex situations, the volume will have been applied to the input samples before the data callback. Applying it again post-callback will incorrectly compound it. */ ma_apply_volume_factor_pcm_frames(pFramesOut, frameCount, pDevice->playback.format, pDevice->playback.channels, masterVolumeFactor); } From 3ed9d05c38dc9751cefbbee078f2847117573000 Mon Sep 17 00:00:00 2001 From: David Reid Date: Mon, 22 Jan 2024 07:26:38 +1000 Subject: [PATCH 15/20] Fix compilation error on Android. Public issue https://github.com/mackron/miniaudio/issues/805 --- miniaudio.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/miniaudio.h b/miniaudio.h index c1621aee..1cf6ad86 100644 --- a/miniaudio.h +++ b/miniaudio.h @@ -16169,7 +16169,11 @@ static ma_result ma_thread_create__posix(ma_thread* pThread, ma_thread_priority /* I'm not treating a failure of setting the priority as a critical error so not aborting on failure here. */ if (pthread_attr_setschedparam(&attr, &sched) == 0) { - pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED); + #if !defined(MA_ANDROID) || (defined(__ANDROID_API__) && __ANDROID_API__ >= 28) + { + pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED); + } + #endif } } } From bde517a166887bb8afcf61a63f8b77027f9cbec7 Mon Sep 17 00:00:00 2001 From: David Reid Date: Tue, 23 Jan 2024 16:34:34 +1000 Subject: [PATCH 16/20] Update dr_wav. --- miniaudio.h | 1 - 1 file changed, 1 deletion(-) diff --git a/miniaudio.h b/miniaudio.h index 1cf6ad86..e4ded2b8 100644 --- a/miniaudio.h +++ b/miniaudio.h @@ -78617,7 +78617,6 @@ MA_PRIVATE ma_bool32 ma_dr_wav_init__internal(ma_dr_wav* pWav, ma_dr_wav_chunk_p } if (pWav->container == ma_dr_wav_container_riff || pWav->container == ma_dr_wav_container_rifx) { if (ma_dr_wav_bytes_to_u32_ex(chunkSizeBytes, pWav->container) < 36) { - return MA_FALSE; } } else if (pWav->container == ma_dr_wav_container_rf64) { if (ma_dr_wav_bytes_to_u32_le(chunkSizeBytes) != 0xFFFFFFFF) { From c0afa7e621f9abd7ea32caec6d67cbdc58287789 Mon Sep 17 00:00:00 2001 From: David Reid Date: Sun, 28 Jan 2024 08:46:56 +1000 Subject: [PATCH 17/20] Web: Fix a possible JS error. Public issue https://github.com/mackron/miniaudio/issues/810 --- miniaudio.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/miniaudio.h b/miniaudio.h index e4ded2b8..d16bb820 100644 --- a/miniaudio.h +++ b/miniaudio.h @@ -40454,6 +40454,10 @@ static ma_result ma_context_uninit__webaudio(ma_context* pContext) /* Remove the global miniaudio object from window if there are no more references to it. */ EM_ASM({ if (typeof(window.miniaudio) !== 'undefined') { + miniaudio.unlock_event_types.map(function(event_type) { + document.removeEventListener(event_type, miniaudio.unlock, true); + }); + window.miniaudio.referenceCount -= 1; if (window.miniaudio.referenceCount === 0) { delete window.miniaudio; From aa57d052da2f63e07ada293e18f43a19fc9b9e23 Mon Sep 17 00:00:00 2001 From: Chris Genova Date: Mon, 29 Jan 2024 19:26:59 -0500 Subject: [PATCH 18/20] Fix out of range check in ma_default_vfs_seek__win32 --- miniaudio.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/miniaudio.h b/miniaudio.h index d16bb820..d4038afc 100644 --- a/miniaudio.h +++ b/miniaudio.h @@ -59221,7 +59221,7 @@ static ma_result ma_default_vfs_seek__win32(ma_vfs* pVFS, ma_vfs_file file, ma_i result = ma_SetFilePointerEx((HANDLE)file, liDistanceToMove, NULL, dwMoveMethod); } else if (ma_SetFilePointer != NULL) { /* No SetFilePointerEx() so restrict to 31 bits. */ - if (origin > 0x7FFFFFFF) { + if (offset > 0x7FFFFFFF) { return MA_OUT_OF_RANGE; } From f20ab8a9eecfccec37234a89e86e2fe37fabc580 Mon Sep 17 00:00:00 2001 From: David Reid Date: Thu, 8 Feb 2024 15:26:41 +1000 Subject: [PATCH 19/20] Web: Increase the default stack size for the AudioWorklets thread. --- miniaudio.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/miniaudio.h b/miniaudio.h index d4038afc..9ed870e3 100644 --- a/miniaudio.h +++ b/miniaudio.h @@ -39711,7 +39711,7 @@ TODO: Version 0.12: Swap this logic around so that AudioWorklets are used by def /* The thread stack size must be a multiple of 16. */ #ifndef MA_AUDIO_WORKLETS_THREAD_STACK_SIZE -#define MA_AUDIO_WORKLETS_THREAD_STACK_SIZE 16384 +#define MA_AUDIO_WORKLETS_THREAD_STACK_SIZE 131072 #endif #if defined(MA_USE_AUDIO_WORKLETS) From f4e5cf99dca8ac85884385197732a5199393d08e Mon Sep 17 00:00:00 2001 From: David Reid Date: Thu, 8 Feb 2024 15:26:55 +1000 Subject: [PATCH 20/20] Update change history. --- CHANGES.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGES.md b/CHANGES.md index b823da39..90fc1a42 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -6,6 +6,7 @@ v0.11.22 - TBD * DirectSound: Add support for specifying an explicit window handle for SetCooperativeLevel(). * Web: Fix ScriptProcessorNode path when compiling with `--closure=1`. Note that the Audio Worklets path is not currently working due to the callback specified in `emscripten_create_wasm_audio_worklet_processor_async` never getting fired. * Web: Fix an error with the unlocked notification when compiling as C++. +* Web: Fix a JavaScript error when initializing and then uninitializing a context before any interactivity. * AAudio: The default minimum SDK version has been increased from 26 to 27 when enabling AAudio. If you need to support version 26, you can use `#define MA_AAUDIO_MIN_ANDROID_SDK_VERSION 26`.