diff --git a/examples/custom_decoder.c b/examples/custom_decoder.c index f94158c6..d4642686 100644 --- a/examples/custom_decoder.c +++ b/examples/custom_decoder.c @@ -68,7 +68,7 @@ int main(int argc, char** argv) decoders. If you want to prioritize the stock decoders over the custom decoders, you would simply change the order. */ - const ma_decoding_backend_vtable* pBackendVTables[] = + ma_decoding_backend_vtable* pBackendVTables[] = { ma_decoding_backend_libvorbis, ma_decoding_backend_libopus, diff --git a/examples/custom_decoder_engine.c b/examples/custom_decoder_engine.c index e67a67da..36557f9c 100644 --- a/examples/custom_decoder_engine.c +++ b/examples/custom_decoder_engine.c @@ -34,7 +34,7 @@ int main(int argc, char** argv) decoders. If you want to prioritize the stock decoders over the custom decoders, you would simply change the order. */ - const ma_decoding_backend_vtable* pBackendVTables[] = + ma_decoding_backend_vtable* pBackendVTables[] = { 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 d85eea10..b52a4f23 100644 --- a/extras/decoders/libopus/miniaudio_libopus.c +++ b/extras/decoders/libopus/miniaudio_libopus.c @@ -549,9 +549,9 @@ static ma_decoding_backend_vtable ma_gDecodingBackendVTable_libopus = ma_decoding_backend_uninit__libopus, ma_decoding_backend_get_encoding_format__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 78135b1f..d50357ea 100644 --- a/extras/decoders/libvorbis/miniaudio_libvorbis.c +++ b/extras/decoders/libvorbis/miniaudio_libvorbis.c @@ -586,9 +586,9 @@ static ma_decoding_backend_vtable ma_gDecodingBackendVTable_libvorbis = ma_decoding_backend_uninit__libvorbis, ma_decoding_backend_get_encoding_format__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/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 +} diff --git a/miniaudio.h b/miniaudio.h index f9069d67..7ef1c55a 100644 --- a/miniaudio.h +++ b/miniaudio.h @@ -8097,7 +8097,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; @@ -8534,6 +8534,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 ---------- @@ -10096,7 +10100,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* ppBackendVTables; + ma_decoding_backend_vtable** ppBackendVTables; void** ppBackendUserData; ma_uint32 backendCount; } ma_decoder_config; @@ -10615,7 +10619,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* ppDecodingBackendVTables; + ma_decoding_backend_vtable** ppDecodingBackendVTables; ma_uint32 decodingBackendCount; void** ppDecodingBackendUserData; } ma_resource_manager_config; @@ -14018,7 +14022,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; } } @@ -17587,7 +17591,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 }; @@ -19334,9 +19338,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 @@ -29067,7 +29069,7 @@ static ma_result ma_context_init__alsa(ma_context* pContext, const ma_context_co return MA_SUCCESS; } -#endif /* ALSA */ +#endif /* MA_HAS_ALSA */ @@ -32229,7 +32231,7 @@ static ma_result ma_context_init__jack(ma_context* pContext, const ma_context_co return MA_SUCCESS; } -#endif /* JACK */ +#endif /* MA_HAS_JACK */ @@ -35474,7 +35476,7 @@ static ma_result ma_context_init__coreaudio(ma_context* pContext, const ma_conte return MA_SUCCESS; } -#endif /* Core Audio */ +#endif /* MA_HAS_COREAUDIO */ @@ -36321,7 +36323,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 */ @@ -37219,7 +37221,7 @@ static ma_result ma_context_init__audio4(ma_context* pContext, const ma_context_ return MA_SUCCESS; } -#endif /* audio4 */ +#endif /* MA_HAS_AUDIO4 */ /****************************************************************************** @@ -37850,7 +37852,7 @@ static ma_result ma_context_init__oss(ma_context* pContext, const ma_context_con return MA_SUCCESS; } -#endif /* OSS */ +#endif /* MA_HAS_OSS */ @@ -38422,19 +38424,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; } @@ -38443,8 +38441,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; } @@ -38496,7 +38501,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; @@ -38526,7 +38531,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; } @@ -38670,12 +38689,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; @@ -38724,17 +38747,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. */ @@ -38752,15 +38775,20 @@ 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. */ } } - - return MA_SUCCESS; + + result = 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) @@ -41148,7 +41176,7 @@ static ma_result ma_context_init__webaudio(ma_context* pContext, const ma_contex return MA_SUCCESS; } -#endif /* Web Audio */ +#endif /* MA_HAS_WEBAUDIO */ @@ -56893,7 +56921,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; } @@ -56975,7 +57003,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; } @@ -65391,6 +65419,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. */ } /*