From 9a1b551658360c473eac9382ef447fc54333e40d Mon Sep 17 00:00:00 2001 From: David Reid Date: Mon, 12 Jan 2026 10:57:09 +1000 Subject: [PATCH] WASAPI: Fix an error with rerouting. When WASAPI reports `AUDCLNT_E_DEVICE_INVALIDATED` miniaudio will attempt to reinitialize the device and continue processing. Prior to this commit the reinit process would use NULL as the device ID which is incorrect when an explicit device was requested. With this commit the reinit process will correctly pass in the ID of the device that it was initialized with. In practice, this will mean the device will be put into an errored state if it is unplugged. --- miniaudio.h | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/miniaudio.h b/miniaudio.h index 2280c068..cf272088 100644 --- a/miniaudio.h +++ b/miniaudio.h @@ -23836,6 +23836,7 @@ static ma_result ma_device_reinit__wasapi(ma_device* pDevice, ma_device_type dev ma_device_state_wasapi* pDeviceStateWASAPI = ma_device_get_backend_state__wasapi(pDevice); ma_device_init_internal_data__wasapi data; ma_result result; + const ma_device_id* pDeviceID = NULL; MA_ASSERT(pDevice != NULL); @@ -23872,11 +23873,13 @@ static ma_result ma_device_reinit__wasapi(ma_device* pDevice, ma_device_type dev if (deviceType == ma_device_type_playback) { + pDeviceID = pDevice->playback.pID; data.formatIn = pDevice->playback.format; data.channelsIn = pDevice->playback.channels; MA_COPY_MEMORY(data.channelMapIn, pDevice->playback.channelMap, sizeof(pDevice->playback.channelMap)); data.shareMode = pDevice->playback.shareMode; } else { + pDeviceID = pDevice->playback.pID; data.formatIn = pDevice->capture.format; data.channelsIn = pDevice->capture.channels; MA_COPY_MEMORY(data.channelMapIn, pDevice->capture.channelMap, sizeof(pDevice->capture.channelMap)); @@ -23892,7 +23895,7 @@ static ma_result ma_device_reinit__wasapi(ma_device* pDevice, ma_device_type dev data.noHardwareOffloading = pDeviceStateWASAPI->noHardwareOffloading; data.loopbackProcessID = pDeviceStateWASAPI->loopbackProcessID; data.loopbackProcessExclude = pDeviceStateWASAPI->loopbackProcessExclude; - result = ma_device_init_internal__wasapi(pDevice->pContext, deviceType, NULL, &data); + result = ma_device_init_internal__wasapi(pDevice->pContext, deviceType, pDeviceID, &data); if (result != MA_SUCCESS) { return result; } @@ -24251,7 +24254,7 @@ static ma_result ma_device__get_available_frames__wasapi(ma_device* pDevice, ma_ *pFrameCount = 0; - if (pAudioClient != pDeviceStateWASAPI->pAudioClientPlayback && pAudioClient != pDeviceStateWASAPI->pAudioClientCapture) { + if (pAudioClient == NULL || (pAudioClient != pDeviceStateWASAPI->pAudioClientPlayback && pAudioClient != pDeviceStateWASAPI->pAudioClientCapture)) { return MA_INVALID_OPERATION; } @@ -24377,7 +24380,7 @@ static ma_result ma_device_stop_client_by_type__wasapi(ma_device* pDevice, ma_de MA_ASSERT(deviceType != ma_device_type_duplex); MA_ASSERT(deviceType != ma_device_type_loopback); - if (deviceType == ma_device_type_capture) { + if (deviceType == ma_device_type_capture && pDeviceStateWASAPI->pAudioClientCapture != NULL) { hr = ma_IAudioClient_Stop(pDeviceStateWASAPI->pAudioClientCapture); if (FAILED(hr)) { ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to stop internal capture device."); @@ -24392,7 +24395,7 @@ static ma_result ma_device_stop_client_by_type__wasapi(ma_device* pDevice, ma_de } } - if (deviceType == ma_device_type_playback) { + if (deviceType == ma_device_type_playback && pDeviceStateWASAPI->pAudioClientPlayback != NULL) { /* The buffer needs to be drained before stopping the device. Not doing this will result in the last few frames not getting output to the speakers. This is a problem for very short sounds because it'll result in a significant portion of it not getting played.