From 9f9fc2333eceb17d8dbbd79218c3f59147c7579b Mon Sep 17 00:00:00 2001 From: znakeeye Date: Thu, 20 Feb 2025 02:17:13 +0100 Subject: [PATCH 1/9] Improved synchronization for AAudio rerouting. This should fix the crash observed in ma_device_init__aaudio (when re-routing). --- miniaudio.h | 81 +++++++++++++++++++++++++++++++++++------------------ 1 file changed, 54 insertions(+), 27 deletions(-) diff --git a/miniaudio.h b/miniaudio.h index e1d2a13c..0a145a53 100644 --- a/miniaudio.h +++ b/miniaudio.h @@ -7985,7 +7985,7 @@ struct ma_device { /*AAudioStream**/ ma_ptr pStreamPlayback; /*AAudioStream**/ ma_ptr pStreamCapture; - ma_mutex closeLock; + ma_mutex rerouteLock; ma_aaudio_usage usage; ma_aaudio_content_type contentType; ma_aaudio_input_preset inputPreset; @@ -38162,19 +38162,15 @@ static ma_result ma_close_streams__aaudio(ma_device* pDevice) { MA_ASSERT(pDevice != NULL); - ma_mutex_lock(&pDevice->aaudio.closeLock); - { - /* When re-routing, streams may have been closed and never re-opened. Hence the extra checks below. */ - if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) { - ma_close_stream__aaudio(pDevice->pContext, (ma_AAudioStream*)pDevice->aaudio.pStreamCapture); - pDevice->aaudio.pStreamCapture = NULL; - } - if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) { - ma_close_stream__aaudio(pDevice->pContext, (ma_AAudioStream*)pDevice->aaudio.pStreamPlayback); - pDevice->aaudio.pStreamPlayback = NULL; - } + /* When re-routing, streams may have been closed and never re-opened. Hence the extra checks below. */ + if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) { + ma_close_stream__aaudio(pDevice->pContext, (ma_AAudioStream*)pDevice->aaudio.pStreamCapture); + pDevice->aaudio.pStreamCapture = NULL; + } + if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) { + ma_close_stream__aaudio(pDevice->pContext, (ma_AAudioStream*)pDevice->aaudio.pStreamPlayback); + pDevice->aaudio.pStreamPlayback = NULL; } - ma_mutex_unlock(&pDevice->aaudio.closeLock); return MA_SUCCESS; } @@ -38183,8 +38179,15 @@ static ma_result ma_device_uninit__aaudio(ma_device* pDevice) { MA_ASSERT(pDevice != NULL); - ma_close_streams__aaudio(pDevice); - ma_mutex_uninit(&pDevice->aaudio.closeLock); + /* Wait for any rerouting to finish before attempting to close the streams. */ + ma_mutex_lock(&pDevice->aaudio.rerouteLock); + { + ma_close_streams__aaudio(pDevice); + } + ma_mutex_unlock(&pDevice->aaudio.rerouteLock); + + /* Destroy re-routing lock. */ + ma_mutex_uninit(&pDevice->aaudio.rerouteLock); return MA_SUCCESS; } @@ -38236,7 +38239,7 @@ static ma_result ma_device_init_by_type__aaudio(ma_device* pDevice, const ma_dev return MA_SUCCESS; } -static ma_result ma_device_init__aaudio(ma_device* pDevice, const ma_device_config* pConfig, ma_device_descriptor* pDescriptorPlayback, ma_device_descriptor* pDescriptorCapture) +static ma_result ma_device_init_streams__aaudio(ma_device* pDevice, const ma_device_config* pConfig, ma_device_descriptor* pDescriptorPlayback, ma_device_descriptor* pDescriptorCapture) { ma_result result; @@ -38266,7 +38269,21 @@ static ma_result ma_device_init__aaudio(ma_device* pDevice, const ma_device_conf } } - result = ma_mutex_init(&pDevice->aaudio.closeLock); + return MA_SUCCESS; +} + +static ma_result ma_device_init__aaudio(ma_device* pDevice, const ma_device_config* pConfig, ma_device_descriptor* pDescriptorPlayback, ma_device_descriptor* pDescriptorCapture) +{ + ma_result result; + + MA_ASSERT(pDevice != NULL); + + result = ma_device_init_streams__aaudio(pDevice, pConfig, pDescriptorPlayback, pDescriptorCapture); + if (result != MA_SUCCESS) { + return result; + } + + result = ma_mutex_init(&pDevice->aaudio.rerouteLock); if (result != MA_SUCCESS) { return result; } @@ -38410,12 +38427,16 @@ static ma_result ma_device_reinit__aaudio(ma_device* pDevice, ma_device_type dev MA_ASSERT(pDevice != NULL); -error_disconnected: - /* The first thing to do is close the streams. */ - ma_close_streams__aaudio(pDevice); - - /* Now we need to reinitialize each streams. The hardest part with this is just filling output the config and descriptors. */ + /* + TODO: Stop retrying if main thread is about to uninit device. + */ + ma_mutex_lock(&pDevice->aaudio.rerouteLock); { +error_disconnected: + /* The first thing to do is close the streams. */ + ma_close_streams__aaudio(pDevice); + + /* Now we need to reinitialize each streams. The hardest part with this is just filling output the config and descriptors. */ ma_device_config deviceConfig; ma_device_descriptor descriptorPlayback; ma_device_descriptor descriptorCapture; @@ -38464,17 +38485,17 @@ error_disconnected: descriptorPlayback.periodCount = deviceConfig.periods; } - result = ma_device_init__aaudio(pDevice, &deviceConfig, &descriptorPlayback, &descriptorCapture); + result = ma_device_init_streams__aaudio(pDevice, &deviceConfig, &descriptorPlayback, &descriptorCapture); if (result != MA_SUCCESS) { ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_WARNING, "[AAudio] Failed to create stream after route change."); - return result; + goto done; } result = ma_device_post_init(pDevice, deviceType, &descriptorPlayback, &descriptorCapture); if (result != MA_SUCCESS) { ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_WARNING, "[AAudio] Failed to initialize device after route change."); ma_close_streams__aaudio(pDevice); - return result; + goto done; } /* We'll only ever do this in response to a reroute. */ @@ -38492,15 +38513,21 @@ error_disconnected: goto error_disconnected; } ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, "[AAudio] Failed to start stream after route change."); - return result; + goto done; } } else { ma_device_stop(pDevice); /* Do a full device stop so we set internal state correctly. */ } } + + result = MA_SUCCESS; - return MA_SUCCESS; +done: + /* Re-routing done */ } + ma_mutex_unlock(&pDevice->aaudio.rerouteLock); + + return result; } static ma_result ma_device_get_info__aaudio(ma_device* pDevice, ma_device_type type, ma_device_info* pDeviceInfo) From 7a1135d448a8b767760b170fca7770ce050e03da Mon Sep 17 00:00:00 2001 From: znakeeye Date: Thu, 20 Feb 2025 22:12:56 +0100 Subject: [PATCH 2/9] Goto label placed outside braces for C compliance. --- miniaudio.h | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/miniaudio.h b/miniaudio.h index 0a145a53..f2ab25cf 100644 --- a/miniaudio.h +++ b/miniaudio.h @@ -38521,10 +38521,9 @@ error_disconnected: } result = MA_SUCCESS; - -done: - /* Re-routing done */ } +done: + /* Re-routing done */ ma_mutex_unlock(&pDevice->aaudio.rerouteLock); return result; From b5f1ff125e85c6ce1ab919138a3c0fb019f033ee Mon Sep 17 00:00:00 2001 From: David Reid Date: Sun, 23 Feb 2025 09:31:52 +1000 Subject: [PATCH 3/9] Update documentation for ma_context_get_devices(). --- miniaudio.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/miniaudio.h b/miniaudio.h index f2ab25cf..7872c88c 100644 --- a/miniaudio.h +++ b/miniaudio.h @@ -8409,6 +8409,10 @@ Retrieves basic information about every active playback and/or capture device. This function will allocate memory internally for the device lists and return a pointer to them through the `ppPlaybackDeviceInfos` and `ppCaptureDeviceInfos` parameters. If you do not want to incur the overhead of these allocations consider using `ma_context_enumerate_devices()` which will instead use a callback. +Note that this only retrieves the ID and name/description of the device. The reason for only retrieving basic information is that it would otherwise require +opening the backend device in order to probe it for more detailed information which can be inefficient. Consider using `ma_context_get_device_info()` for this, +but don't call it from within the enumeration callback. + Parameters ---------- From 01302b97150b9f8a8cd1200adc137b93568b4001 Mon Sep 17 00:00:00 2001 From: David Reid Date: Sun, 23 Feb 2025 09:34:48 +1000 Subject: [PATCH 4/9] Fix a parameter order error. This did not affect functionality at all because the implementation of the relevant function is just a simple bitwise OR. --- miniaudio.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/miniaudio.h b/miniaudio.h index 7872c88c..118fba05 100644 --- a/miniaudio.h +++ b/miniaudio.h @@ -56734,7 +56734,7 @@ MA_API ma_result ma_rb_commit_read(ma_rb* pRB, size_t sizeInBytes) newReadOffsetLoopFlag ^= 0x80000000; } - ma_atomic_exchange_32(&pRB->encodedReadOffset, ma_rb__construct_offset(newReadOffsetLoopFlag, newReadOffsetInBytes)); + ma_atomic_exchange_32(&pRB->encodedReadOffset, ma_rb__construct_offset(newReadOffsetInBytes, newReadOffsetLoopFlag)); return MA_SUCCESS; } @@ -56816,7 +56816,7 @@ MA_API ma_result ma_rb_commit_write(ma_rb* pRB, size_t sizeInBytes) newWriteOffsetLoopFlag ^= 0x80000000; } - ma_atomic_exchange_32(&pRB->encodedWriteOffset, ma_rb__construct_offset(newWriteOffsetLoopFlag, newWriteOffsetInBytes)); + ma_atomic_exchange_32(&pRB->encodedWriteOffset, ma_rb__construct_offset(newWriteOffsetInBytes, newWriteOffsetLoopFlag)); return MA_SUCCESS; } From c74c90f68603ba7a4a3bb46b59cd2789d1fd8fd0 Mon Sep 17 00:00:00 2001 From: David Reid Date: Sun, 23 Feb 2025 11:35:26 +1000 Subject: [PATCH 5/9] Minor comment changes. --- miniaudio.h | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/miniaudio.h b/miniaudio.h index 118fba05..994cc166 100644 --- a/miniaudio.h +++ b/miniaudio.h @@ -17501,7 +17501,7 @@ static ma_job_proc g_jobVTable[MA_JOB_TYPE_COUNT] = /* Device. */ #if !defined(MA_NO_DEVICE_IO) - ma_job_process__device__aaudio_reroute /*MA_JOB_TYPE_DEVICE_AAUDIO_REROUTE*/ + ma_job_process__device__aaudio_reroute /* MA_JOB_TYPE_DEVICE_AAUDIO_REROUTE */ #endif }; @@ -28778,7 +28778,7 @@ static ma_result ma_context_init__alsa(ma_context* pContext, const ma_context_co return MA_SUCCESS; } -#endif /* ALSA */ +#endif /* MA_HAS_ALSA */ @@ -31973,7 +31973,7 @@ static ma_result ma_context_init__jack(ma_context* pContext, const ma_context_co return MA_SUCCESS; } -#endif /* JACK */ +#endif /* MA_HAS_JACK */ @@ -35218,7 +35218,7 @@ static ma_result ma_context_init__coreaudio(ma_context* pContext, const ma_conte return MA_SUCCESS; } -#endif /* Core Audio */ +#endif /* MA_HAS_COREAUDIO */ @@ -36065,7 +36065,7 @@ static ma_result ma_context_init__sndio(ma_context* pContext, const ma_context_c (void)pConfig; return MA_SUCCESS; } -#endif /* sndio */ +#endif /* MA_HAS_SNDIO */ @@ -36963,7 +36963,7 @@ static ma_result ma_context_init__audio4(ma_context* pContext, const ma_context_ return MA_SUCCESS; } -#endif /* audio4 */ +#endif /* MA_HAS_AUDIO4 */ /****************************************************************************** @@ -37594,7 +37594,7 @@ static ma_result ma_context_init__oss(ma_context* pContext, const ma_context_con return MA_SUCCESS; } -#endif /* OSS */ +#endif /* MA_HAS_OSS */ @@ -40918,7 +40918,7 @@ static ma_result ma_context_init__webaudio(ma_context* pContext, const ma_contex return MA_SUCCESS; } -#endif /* Web Audio */ +#endif /* MA_HAS_WEBAUDIO */ From 54373128ee896b662ec19183bbe7f92fcb9b6993 Mon Sep 17 00:00:00 2001 From: David Reid Date: Sun, 23 Feb 2025 11:49:31 +1000 Subject: [PATCH 6/9] Fix a subtle undefined behaviour error. --- miniaudio.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/miniaudio.h b/miniaudio.h index 994cc166..33098b5a 100644 --- a/miniaudio.h +++ b/miniaudio.h @@ -13932,7 +13932,7 @@ static ma_uint32 ma_ffs_32(ma_uint32 x) /* Just a naive implementation just to get things working for now. Will optimize this later. */ for (i = 0; i < 32; i += 1) { - if ((x & (1 << i)) != 0) { + if ((x & (1U << i)) != 0) { return i; } } From 166fd6dfc7c851dd27c2cb23eb39a2d81ec1f730 Mon Sep 17 00:00:00 2001 From: David Reid Date: Sun, 23 Feb 2025 12:03:22 +1000 Subject: [PATCH 7/9] Silence some static analysis warnings. --- miniaudio.h | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/miniaudio.h b/miniaudio.h index 33098b5a..6cc626df 100644 --- a/miniaudio.h +++ b/miniaudio.h @@ -19043,9 +19043,7 @@ static void ma_device__read_frames_from_client(ma_device* pDevice, ma_uint32 fra framesToReadThisIterationIn = requiredInputFrameCount; } - if (framesToReadThisIterationIn > 0) { - ma_device__handle_data_callback(pDevice, pIntermediaryBuffer, NULL, (ma_uint32)framesToReadThisIterationIn); - } + ma_device__handle_data_callback(pDevice, pIntermediaryBuffer, NULL, (ma_uint32)framesToReadThisIterationIn); /* At this point we have our decoded data in input format and now we need to convert to output format. Note that even if we didn't read any @@ -65764,6 +65762,7 @@ MA_API ma_result ma_decoder_read_pcm_frames(ma_decoder* pDecoder, void* pFramesO result = ma_data_source_read_pcm_frames(pDecoder->pBackend, pIntermediaryBuffer, framesToReadThisIterationIn, &framesReadThisIterationIn); } else { framesReadThisIterationIn = 0; + pIntermediaryBuffer[0] = 0; /* <-- This is just to silence a static analysis warning. */ } /* From b6184fa2a04b2a136c8a0be994ff2420cbb622c4 Mon Sep 17 00:00:00 2001 From: David Reid Date: Sun, 23 Feb 2025 12:11:29 +1000 Subject: [PATCH 8/9] Fix some Wnewline-eof warnings. --- .../ma_channel_separator_node_example.c | 2 +- extras/nodes/ma_ltrim_node/ma_ltrim_node_example.c | 2 +- extras/nodes/ma_reverb_node/ma_reverb_node_example.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/extras/nodes/ma_channel_separator_node/ma_channel_separator_node_example.c b/extras/nodes/ma_channel_separator_node/ma_channel_separator_node_example.c index 00953275..04456392 100644 --- a/extras/nodes/ma_channel_separator_node/ma_channel_separator_node_example.c +++ b/extras/nodes/ma_channel_separator_node/ma_channel_separator_node_example.c @@ -145,4 +145,4 @@ done0: ma_device_uninit(&device); (void)argv; return 0; -} \ No newline at end of file +} diff --git a/extras/nodes/ma_ltrim_node/ma_ltrim_node_example.c b/extras/nodes/ma_ltrim_node/ma_ltrim_node_example.c index 81b9ca87..f6a2d05b 100644 --- a/extras/nodes/ma_ltrim_node/ma_ltrim_node_example.c +++ b/extras/nodes/ma_ltrim_node/ma_ltrim_node_example.c @@ -111,4 +111,4 @@ done1: ma_node_graph_uninit(&g_nodeGraph, NULL); done0: ma_device_uninit(&device); return 0; -} \ No newline at end of file +} 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 5827641f..beb9ac57 100644 --- a/extras/nodes/ma_reverb_node/ma_reverb_node_example.c +++ b/extras/nodes/ma_reverb_node/ma_reverb_node_example.c @@ -119,4 +119,4 @@ done0: ma_device_uninit(&device); (void)argv; return 0; -} \ No newline at end of file +} From 8c52072f430c21c1f13c8b09d191fb7cb2014e2e Mon Sep 17 00:00:00 2001 From: David Reid Date: Sun, 23 Feb 2025 12:54:19 +1000 Subject: [PATCH 9/9] Remove const qualifiers from decoding backend vtable arrays. --- examples/custom_decoder.c | 2 +- examples/custom_decoder_engine.c | 2 +- extras/decoders/libopus/miniaudio_libopus.c | 4 ++-- extras/decoders/libopus/miniaudio_libopus.h | 2 +- extras/decoders/libvorbis/miniaudio_libvorbis.c | 4 ++-- extras/decoders/libvorbis/miniaudio_libvorbis.h | 2 +- miniaudio.h | 4 ++-- 7 files changed, 10 insertions(+), 10 deletions(-) diff --git a/examples/custom_decoder.c b/examples/custom_decoder.c index e218945a..d73576b6 100644 --- a/examples/custom_decoder.c +++ b/examples/custom_decoder.c @@ -54,7 +54,7 @@ int main(int argc, char** argv) Add your custom backend vtables here. The order in the array defines the order of priority. The vtables will be passed in via the decoder config. */ - const ma_decoding_backend_vtable* pCustomBackendVTables[] = + ma_decoding_backend_vtable* pCustomBackendVTables[] = { ma_decoding_backend_libvorbis, ma_decoding_backend_libopus diff --git a/examples/custom_decoder_engine.c b/examples/custom_decoder_engine.c index df452cc1..5938c76e 100644 --- a/examples/custom_decoder_engine.c +++ b/examples/custom_decoder_engine.c @@ -29,7 +29,7 @@ int main(int argc, char** argv) Add your custom backend vtables here. The order in the array defines the order of priority. The vtables will be passed in to the resource manager config. */ - const ma_decoding_backend_vtable* pCustomBackendVTables[] = + ma_decoding_backend_vtable* pCustomBackendVTables[] = { ma_decoding_backend_libvorbis, ma_decoding_backend_libopus diff --git a/extras/decoders/libopus/miniaudio_libopus.c b/extras/decoders/libopus/miniaudio_libopus.c index 61c1d19b..ae7887ff 100644 --- a/extras/decoders/libopus/miniaudio_libopus.c +++ b/extras/decoders/libopus/miniaudio_libopus.c @@ -528,9 +528,9 @@ static ma_decoding_backend_vtable ma_gDecodingBackendVTable_libopus = NULL, /* onInitMemory() */ ma_decoding_backend_uninit__libopus }; -const ma_decoding_backend_vtable* ma_decoding_backend_libopus = &ma_gDecodingBackendVTable_libopus; +ma_decoding_backend_vtable* ma_decoding_backend_libopus = &ma_gDecodingBackendVTable_libopus; #else -const ma_decoding_backend_vtable* ma_decoding_backend_libopus = NULL; +ma_decoding_backend_vtable* ma_decoding_backend_libopus = NULL; #endif #endif /* miniaudio_libopus_c */ diff --git a/extras/decoders/libopus/miniaudio_libopus.h b/extras/decoders/libopus/miniaudio_libopus.h index f8d005c5..80dce280 100644 --- a/extras/decoders/libopus/miniaudio_libopus.h +++ b/extras/decoders/libopus/miniaudio_libopus.h @@ -34,7 +34,7 @@ MA_API ma_result ma_libopus_get_cursor_in_pcm_frames(ma_libopus* pOpus, ma_uint6 MA_API ma_result ma_libopus_get_length_in_pcm_frames(ma_libopus* pOpus, ma_uint64* pLength); /* Decoding backend vtable. This is what you'll plug into ma_decoder_config.pBackendVTables. No user data required. */ -extern const ma_decoding_backend_vtable* ma_decoding_backend_libopus; +extern ma_decoding_backend_vtable* ma_decoding_backend_libopus; #ifdef __cplusplus } diff --git a/extras/decoders/libvorbis/miniaudio_libvorbis.c b/extras/decoders/libvorbis/miniaudio_libvorbis.c index 8535b9e7..653b4879 100644 --- a/extras/decoders/libvorbis/miniaudio_libvorbis.c +++ b/extras/decoders/libvorbis/miniaudio_libvorbis.c @@ -566,9 +566,9 @@ static ma_decoding_backend_vtable ma_gDecodingBackendVTable_libvorbis = NULL, /* onInitMemory() */ ma_decoding_backend_uninit__libvorbis }; -const ma_decoding_backend_vtable* ma_decoding_backend_libvorbis = &ma_gDecodingBackendVTable_libvorbis; +ma_decoding_backend_vtable* ma_decoding_backend_libvorbis = &ma_gDecodingBackendVTable_libvorbis; #else -const ma_decoding_backend_vtable* ma_decoding_backend_libvorbis = NULL; +ma_decoding_backend_vtable* ma_decoding_backend_libvorbis = NULL; #endif #endif /* miniaudio_libvorbis_c */ diff --git a/extras/decoders/libvorbis/miniaudio_libvorbis.h b/extras/decoders/libvorbis/miniaudio_libvorbis.h index 24994fbf..6699266c 100644 --- a/extras/decoders/libvorbis/miniaudio_libvorbis.h +++ b/extras/decoders/libvorbis/miniaudio_libvorbis.h @@ -34,7 +34,7 @@ MA_API ma_result ma_libvorbis_get_cursor_in_pcm_frames(ma_libvorbis* pVorbis, ma MA_API ma_result ma_libvorbis_get_length_in_pcm_frames(ma_libvorbis* pVorbis, ma_uint64* pLength); /* Decoding backend vtable. This is what you'll plug into ma_decoder_config.pBackendVTables. No user data required. */ -extern const ma_decoding_backend_vtable* ma_decoding_backend_libvorbis; +extern ma_decoding_backend_vtable* ma_decoding_backend_libvorbis; #ifdef __cplusplus } diff --git a/miniaudio.h b/miniaudio.h index 6cc626df..a31d9df8 100644 --- a/miniaudio.h +++ b/miniaudio.h @@ -9959,7 +9959,7 @@ typedef struct ma_allocation_callbacks allocationCallbacks; ma_encoding_format encodingFormat; ma_uint32 seekPointCount; /* When set to > 0, specifies the number of seek points to use for the generation of a seek table. Not all decoding backends support this. */ - const ma_decoding_backend_vtable* const* ppCustomBackendVTables; + ma_decoding_backend_vtable** ppCustomBackendVTables; ma_uint32 customBackendCount; void* pCustomBackendUserData; } ma_decoder_config; @@ -10486,7 +10486,7 @@ typedef struct ma_uint32 jobQueueCapacity; /* The maximum number of jobs that can fit in the queue at a time. Defaults to MA_JOB_TYPE_RESOURCE_MANAGER_QUEUE_CAPACITY. Cannot be zero. */ ma_uint32 flags; ma_vfs* pVFS; /* Can be NULL in which case defaults will be used. */ - const ma_decoding_backend_vtable* const* ppCustomDecodingBackendVTables; + ma_decoding_backend_vtable** ppCustomDecodingBackendVTables; ma_uint32 customDecodingBackendCount; void* pCustomDecodingBackendUserData; } ma_resource_manager_config;