Commit 57101f61 authored by David Reid's avatar David Reid

WASAPI and WinMM: Stop the device an internal error occurs.

parent 21e15a4c
...@@ -512,6 +512,7 @@ typedef int mal_result; ...@@ -512,6 +512,7 @@ typedef int mal_result;
#define MAL_INVALID_DEVICE_CONFIG -31 #define MAL_INVALID_DEVICE_CONFIG -31
#define MAL_ACCESS_DENIED -32 #define MAL_ACCESS_DENIED -32
#define MAL_TOO_LARGE -33 #define MAL_TOO_LARGE -33
#define MAL_DEVICE_UNAVAILABLE -34
// Standard sample rates. // Standard sample rates.
#define MAL_SAMPLE_RATE_8000 8000 #define MAL_SAMPLE_RATE_8000 8000
...@@ -6467,56 +6468,66 @@ mal_result mal_device__break_main_loop__wasapi(mal_device* pDevice) ...@@ -6467,56 +6468,66 @@ mal_result mal_device__break_main_loop__wasapi(mal_device* pDevice)
return MAL_SUCCESS; return MAL_SUCCESS;
} }
mal_uint32 mal_device__get_available_frames__wasapi(mal_device* pDevice) mal_result mal_device__get_available_frames__wasapi(mal_device* pDevice, mal_uint32* pFrameCount)
{ {
mal_assert(pDevice != NULL); mal_assert(pDevice != NULL);
mal_assert(pFrameCount != NULL);
*pFrameCount = 0;
#if 0 #if 0
if (pDevice->type == mal_device_type_playback) { if (pDevice->type == mal_device_type_playback) {
mal_uint32 paddingFramesCount; mal_uint32 paddingFramesCount;
HRESULT hr = mal_IAudioClient_GetCurrentPadding((mal_IAudioClient*)pDevice->wasapi.pAudioClient, &paddingFramesCount); HRESULT hr = mal_IAudioClient_GetCurrentPadding((mal_IAudioClient*)pDevice->wasapi.pAudioClient, &paddingFramesCount);
if (FAILED(hr)) { if (FAILED(hr)) {
return 0; return MAL_ERROR;
} }
if (pDevice->exclusiveMode) { if (pDevice->exclusiveMode) {
return paddingFramesCount; *pFrameCount = paddingFramesCount;
return MAL_SUCCESS;
} else { } else {
return pDevice->bufferSizeInFrames - paddingFramesCount; *pFrameCount = pDevice->bufferSizeInFrames - paddingFramesCount;
return MAL_SUCCESS;
} }
} else { } else {
mal_uint32 framesAvailable; mal_uint32 framesAvailable;
HRESULT hr = mal_IAudioCaptureClient_GetNextPacketSize((mal_IAudioCaptureClient*)pDevice->wasapi.pCaptureClient, &framesAvailable); HRESULT hr = mal_IAudioCaptureClient_GetNextPacketSize((mal_IAudioCaptureClient*)pDevice->wasapi.pCaptureClient, &framesAvailable);
if (FAILED(hr)) { if (FAILED(hr)) {
return 0; return MAL_ERROR;
} }
return framesAvailable; *pFrameCount = framesAvailable;
return MAL_SUCCESS;
} }
#else #else
mal_uint32 paddingFramesCount; mal_uint32 paddingFramesCount;
HRESULT hr = mal_IAudioClient_GetCurrentPadding((mal_IAudioClient*)pDevice->wasapi.pAudioClient, &paddingFramesCount); HRESULT hr = mal_IAudioClient_GetCurrentPadding((mal_IAudioClient*)pDevice->wasapi.pAudioClient, &paddingFramesCount);
if (FAILED(hr)) { if (FAILED(hr)) {
return 0; return MAL_DEVICE_UNAVAILABLE;
} }
// Slightly different rules for exclusive and shared modes. // Slightly different rules for exclusive and shared modes.
if (pDevice->exclusiveMode) { if (pDevice->exclusiveMode) {
return paddingFramesCount; *pFrameCount = paddingFramesCount;
} else { } else {
if (pDevice->type == mal_device_type_playback) { if (pDevice->type == mal_device_type_playback) {
return pDevice->bufferSizeInFrames - paddingFramesCount; *pFrameCount = pDevice->bufferSizeInFrames - paddingFramesCount;
} else { } else {
return paddingFramesCount; *pFrameCount = paddingFramesCount;
} }
} }
return MAL_SUCCESS;
#endif #endif
} }
mal_uint32 mal_device__wait_for_frames__wasapi(mal_device* pDevice) mal_result mal_device__wait_for_frames__wasapi(mal_device* pDevice, mal_uint32* pFrameCount)
{ {
mal_assert(pDevice != NULL); mal_assert(pDevice != NULL);
mal_result result;
while (!pDevice->wasapi.breakFromMainLoop) { while (!pDevice->wasapi.breakFromMainLoop) {
// Wait for a buffer to become available or for the stop event to be signalled. // Wait for a buffer to become available or for the stop event to be signalled.
HANDLE hEvents[2]; HANDLE hEvents[2];
...@@ -6532,14 +6543,18 @@ mal_uint32 mal_device__wait_for_frames__wasapi(mal_device* pDevice) ...@@ -6532,14 +6543,18 @@ mal_uint32 mal_device__wait_for_frames__wasapi(mal_device* pDevice)
break; break;
} }
mal_uint32 framesAvailable = mal_device__get_available_frames__wasapi(pDevice); result = mal_device__get_available_frames__wasapi(pDevice, pFrameCount);
if (framesAvailable > 0) { if (result != MAL_SUCCESS) {
return framesAvailable; return result;
}
if (*pFrameCount > 0) {
return MAL_SUCCESS;
} }
} }
// We'll get here if the loop was terminated. Just return whatever's available. // We'll get here if the loop was terminated. Just return whatever's available.
return mal_device__get_available_frames__wasapi(pDevice); return mal_device__get_available_frames__wasapi(pDevice, pFrameCount);
} }
mal_result mal_device__main_loop__wasapi(mal_device* pDevice) mal_result mal_device__main_loop__wasapi(mal_device* pDevice)
...@@ -6551,14 +6566,19 @@ mal_result mal_device__main_loop__wasapi(mal_device* pDevice) ...@@ -6551,14 +6566,19 @@ mal_result mal_device__main_loop__wasapi(mal_device* pDevice)
pDevice->wasapi.breakFromMainLoop = MAL_FALSE; pDevice->wasapi.breakFromMainLoop = MAL_FALSE;
while (!pDevice->wasapi.breakFromMainLoop) { while (!pDevice->wasapi.breakFromMainLoop) {
mal_uint32 framesAvailable = mal_device__wait_for_frames__wasapi(pDevice); mal_uint32 framesAvailable;
mal_result result = mal_device__wait_for_frames__wasapi(pDevice, &framesAvailable);
if (result != MAL_SUCCESS) {
return result;
}
if (framesAvailable == 0) { if (framesAvailable == 0) {
continue; continue;
} }
// If it's a playback device, don't bother grabbing more data if the device is being stopped. // If it's a playback device, don't bother grabbing more data if the device is being stopped.
if (pDevice->wasapi.breakFromMainLoop && pDevice->type == mal_device_type_playback) { if (pDevice->wasapi.breakFromMainLoop && pDevice->type == mal_device_type_playback) {
return MAL_FALSE; return MAL_SUCCESS;
} }
if (pDevice->type == mal_device_type_playback) { if (pDevice->type == mal_device_type_playback) {
...@@ -8732,7 +8752,7 @@ mal_result mal_device__main_loop__winmm(mal_device* pDevice) ...@@ -8732,7 +8752,7 @@ mal_result mal_device__main_loop__winmm(mal_device* pDevice)
MMRESULT resultMM = ((MAL_PFN_waveOutUnprepareHeader)pDevice->pContext->winmm.waveOutUnprepareHeader)((HWAVEOUT)pDevice->winmm.hDevice, &((LPWAVEHDR)pDevice->winmm.pWAVEHDR)[i], sizeof(WAVEHDR)); MMRESULT resultMM = ((MAL_PFN_waveOutUnprepareHeader)pDevice->pContext->winmm.waveOutUnprepareHeader)((HWAVEOUT)pDevice->winmm.hDevice, &((LPWAVEHDR)pDevice->winmm.pWAVEHDR)[i], sizeof(WAVEHDR));
if (resultMM != MMSYSERR_NOERROR) { if (resultMM != MMSYSERR_NOERROR) {
mal_post_error(pDevice, MAL_LOG_LEVEL_ERROR, "[WinMM] Failed to unprepare header for playback device in preparation for sending a new block of data to the device for playback.", mal_result_from_MMRESULT(resultMM)); mal_post_error(pDevice, MAL_LOG_LEVEL_ERROR, "[WinMM] Failed to unprepare header for playback device in preparation for sending a new block of data to the device for playback.", mal_result_from_MMRESULT(resultMM));
break; return MAL_DEVICE_UNAVAILABLE;
} }
mal_zero_object(&((LPWAVEHDR)pDevice->winmm.pWAVEHDR)[i]); mal_zero_object(&((LPWAVEHDR)pDevice->winmm.pWAVEHDR)[i]);
...@@ -8746,7 +8766,7 @@ mal_result mal_device__main_loop__winmm(mal_device* pDevice) ...@@ -8746,7 +8766,7 @@ mal_result mal_device__main_loop__winmm(mal_device* pDevice)
resultMM = ((MAL_PFN_waveOutPrepareHeader)pDevice->pContext->winmm.waveOutPrepareHeader)((HWAVEOUT)pDevice->winmm.hDevice, &((LPWAVEHDR)pDevice->winmm.pWAVEHDR)[i], sizeof(WAVEHDR)); resultMM = ((MAL_PFN_waveOutPrepareHeader)pDevice->pContext->winmm.waveOutPrepareHeader)((HWAVEOUT)pDevice->winmm.hDevice, &((LPWAVEHDR)pDevice->winmm.pWAVEHDR)[i], sizeof(WAVEHDR));
if (resultMM != MMSYSERR_NOERROR) { if (resultMM != MMSYSERR_NOERROR) {
mal_post_error(pDevice, MAL_LOG_LEVEL_ERROR, "[WinMM] Failed to prepare header for playback device in preparation for sending a new block of data to the device for playback.", mal_result_from_MMRESULT(resultMM)); mal_post_error(pDevice, MAL_LOG_LEVEL_ERROR, "[WinMM] Failed to prepare header for playback device in preparation for sending a new block of data to the device for playback.", mal_result_from_MMRESULT(resultMM));
break; return MAL_DEVICE_UNAVAILABLE;
} }
} else { } else {
// Capture. // Capture.
...@@ -8758,7 +8778,7 @@ mal_result mal_device__main_loop__winmm(mal_device* pDevice) ...@@ -8758,7 +8778,7 @@ mal_result mal_device__main_loop__winmm(mal_device* pDevice)
MMRESULT resultMM = ((MAL_PFN_waveInUnprepareHeader)pDevice->pContext->winmm.waveInUnprepareHeader)((HWAVEIN)pDevice->winmm.hDevice, &((LPWAVEHDR)pDevice->winmm.pWAVEHDR)[i], sizeof(WAVEHDR)); MMRESULT resultMM = ((MAL_PFN_waveInUnprepareHeader)pDevice->pContext->winmm.waveInUnprepareHeader)((HWAVEIN)pDevice->winmm.hDevice, &((LPWAVEHDR)pDevice->winmm.pWAVEHDR)[i], sizeof(WAVEHDR));
if (resultMM != MMSYSERR_NOERROR) { if (resultMM != MMSYSERR_NOERROR) {
mal_post_error(pDevice, MAL_LOG_LEVEL_ERROR, "[WinMM] Failed to unprepare header for capture device in preparation for adding a new capture buffer for the device.", mal_result_from_MMRESULT(resultMM)); mal_post_error(pDevice, MAL_LOG_LEVEL_ERROR, "[WinMM] Failed to unprepare header for capture device in preparation for adding a new capture buffer for the device.", mal_result_from_MMRESULT(resultMM));
break; return MAL_DEVICE_UNAVAILABLE;
} }
mal_zero_object(&((LPWAVEHDR)pDevice->winmm.pWAVEHDR)[i]); mal_zero_object(&((LPWAVEHDR)pDevice->winmm.pWAVEHDR)[i]);
...@@ -8771,7 +8791,7 @@ mal_result mal_device__main_loop__winmm(mal_device* pDevice) ...@@ -8771,7 +8791,7 @@ mal_result mal_device__main_loop__winmm(mal_device* pDevice)
resultMM = ((MAL_PFN_waveInPrepareHeader)pDevice->pContext->winmm.waveInPrepareHeader)((HWAVEIN)pDevice->winmm.hDevice, &((LPWAVEHDR)pDevice->winmm.pWAVEHDR)[i], sizeof(WAVEHDR)); resultMM = ((MAL_PFN_waveInPrepareHeader)pDevice->pContext->winmm.waveInPrepareHeader)((HWAVEIN)pDevice->winmm.hDevice, &((LPWAVEHDR)pDevice->winmm.pWAVEHDR)[i], sizeof(WAVEHDR));
if (resultMM != MMSYSERR_NOERROR) { if (resultMM != MMSYSERR_NOERROR) {
mal_post_error(pDevice, MAL_LOG_LEVEL_ERROR, "[WinMM] Failed to prepare header for capture device in preparation for adding a new capture buffer for the device.", mal_result_from_MMRESULT(resultMM)); mal_post_error(pDevice, MAL_LOG_LEVEL_ERROR, "[WinMM] Failed to prepare header for capture device in preparation for adding a new capture buffer for the device.", mal_result_from_MMRESULT(resultMM));
break; return MAL_DEVICE_UNAVAILABLE;
} }
} }
...@@ -8791,14 +8811,14 @@ mal_result mal_device__main_loop__winmm(mal_device* pDevice) ...@@ -8791,14 +8811,14 @@ mal_result mal_device__main_loop__winmm(mal_device* pDevice)
MMRESULT resultMM = ((MAL_PFN_waveOutWrite)pDevice->pContext->winmm.waveOutWrite)((HWAVEOUT)pDevice->winmm.hDevice, &((LPWAVEHDR)pDevice->winmm.pWAVEHDR)[i], sizeof(WAVEHDR)); MMRESULT resultMM = ((MAL_PFN_waveOutWrite)pDevice->pContext->winmm.waveOutWrite)((HWAVEOUT)pDevice->winmm.hDevice, &((LPWAVEHDR)pDevice->winmm.pWAVEHDR)[i], sizeof(WAVEHDR));
if (resultMM != MMSYSERR_NOERROR) { if (resultMM != MMSYSERR_NOERROR) {
mal_post_error(pDevice, MAL_LOG_LEVEL_ERROR, "[WinMM] Failed to write data to the internal playback device.", mal_result_from_MMRESULT(resultMM)); mal_post_error(pDevice, MAL_LOG_LEVEL_ERROR, "[WinMM] Failed to write data to the internal playback device.", mal_result_from_MMRESULT(resultMM));
break; return MAL_DEVICE_UNAVAILABLE;
} }
} else { } else {
// Capture. // Capture.
MMRESULT resultMM = ((MAL_PFN_waveInAddBuffer)pDevice->pContext->winmm.waveInAddBuffer)((HWAVEIN)pDevice->winmm.hDevice, &((LPWAVEHDR)pDevice->winmm.pWAVEHDR)[i], sizeof(WAVEHDR)); MMRESULT resultMM = ((MAL_PFN_waveInAddBuffer)pDevice->pContext->winmm.waveInAddBuffer)((HWAVEIN)pDevice->winmm.hDevice, &((LPWAVEHDR)pDevice->winmm.pWAVEHDR)[i], sizeof(WAVEHDR));
if (resultMM != MMSYSERR_NOERROR) { if (resultMM != MMSYSERR_NOERROR) {
mal_post_error(pDevice, MAL_LOG_LEVEL_ERROR, "[WinMM] Failed to add new capture buffer to the internal capture device.", mal_result_from_MMRESULT(resultMM)); mal_post_error(pDevice, MAL_LOG_LEVEL_ERROR, "[WinMM] Failed to add new capture buffer to the internal capture device.", mal_result_from_MMRESULT(resultMM));
break; return MAL_DEVICE_UNAVAILABLE;
} }
} }
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment