From 1e2427f5f78fb873183e9224edfaef5c289f982a Mon Sep 17 00:00:00 2001 From: David Reid Date: Wed, 4 Feb 2026 14:20:42 +1000 Subject: [PATCH] Tighten up the audio thread. This should close a hole that could possibly result in the audio thread getting stuck if the `MA_DEVICE_OP_UNINIT` operation posted from `ma_device_uninit()` fails. --- miniaudio.h | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/miniaudio.h b/miniaudio.h index 0de51ccb..25deeb6f 100644 --- a/miniaudio.h +++ b/miniaudio.h @@ -48126,16 +48126,32 @@ static ma_thread_result MA_THREADCALL ma_audio_thread(void* pData) goto end_audio_thread; } - for (;;) { - result = ma_device_op_queue_next(&pDevice->opQueue, MA_BLOCKING_MODE_BLOCKING, &pOp); + ma_blocking_mode blockingMode = MA_BLOCKING_MODE_BLOCKING; + + /* If the device has put into an uninitialized state we will make sure the thread is always terminated. */ + if (ma_device_get_status(pDevice) == ma_device_status_uninitialized) { + blockingMode = MA_BLOCKING_MODE_NON_BLOCKING; + } + + result = ma_device_op_queue_next(&pDevice->opQueue, blockingMode, &pOp); if (result != MA_SUCCESS) { break; } + /* + This is a safety mechanism to avoid an infinite loop. If the device has been marked as uninitialized, but we haven't + got anything in the queue, we'll get out of the loop to make sure we don't get stuck. This can *technically* happen + if pushing the MA_DEVICE_OP_UNINIT in `ma_device_uninit()` fails, although it'll be exceptionally rare. + */ + if (result == MA_NO_DATA_AVAILABLE) { + if (ma_device_get_status(pDevice) == ma_device_status_uninitialized) { + break; + } + } + /* */ if (pOp->type == MA_DEVICE_OP_UNINIT) { - ma_device_op_do_uninit(pDevice, pOp->pCompletionEvent); - break; + break; /* Breaking from the loop will trigger an uninit. */ } else if (pOp->type == MA_DEVICE_OP_START) { /* We should never be attempting to start the device unless it's in a stopped state. */ MA_ASSERT(ma_device_get_status(pDevice) == ma_device_status_starting); @@ -48160,7 +48176,6 @@ static ma_thread_result MA_THREADCALL ma_audio_thread(void* pData) if (result == MA_SUCCESS) { if (pOp->type == MA_DEVICE_OP_UNINIT) { ma_device_op_do_stop(pDevice, NULL); - ma_device_op_do_uninit(pDevice, pOp->pCompletionEvent); break; /* <-- This gets out of the op queue loop and terminates the audio thread. */ } else if (pOp->type == MA_DEVICE_OP_STOP) { ma_device_op_do_stop(pDevice, pOp->pCompletionEvent); @@ -48195,6 +48210,9 @@ static ma_thread_result MA_THREADCALL ma_audio_thread(void* pData) } } + /* When we leave the loop we always need to uninitialize the backend. */ + ma_device_op_do_uninit(pDevice, pOp->pCompletionEvent); + end_audio_thread: #ifdef MA_WIN32 {