Commit a74385a2 authored by David Reid's avatar David Reid

WASAPI: Try fixing a deadlock in exclusive mode.

Public issue https://github.com/mackron/miniaudio/issues/265
parent 1ceecebb
......@@ -15165,6 +15165,10 @@ static ma_result ma_device_stop__wasapi(ma_device* pDevice)
}
#ifndef MA_WASAPI_WAIT_TIMEOUT_MILLISECONDS
#define MA_WASAPI_WAIT_TIMEOUT_MILLISECONDS 5000
#endif
static ma_result ma_device_audio_thread__wasapi(ma_device* pDevice)
{
ma_result result;
......@@ -15231,7 +15235,7 @@ static ma_result ma_device_audio_thread__wasapi(ma_device* pDevice)
if (pMappedDeviceBufferPlayback == NULL) {
/* WASAPI is weird with exclusive mode. You need to wait on the event _before_ querying the available frames. */
if (pDevice->playback.shareMode == ma_share_mode_exclusive) {
if (WaitForSingleObject(pDevice->wasapi.hEventPlayback, INFINITE) != WAIT_OBJECT_0) {
if (WaitForSingleObject(pDevice->wasapi.hEventPlayback, MA_WASAPI_WAIT_TIMEOUT_MILLISECONDS) != WAIT_OBJECT_0) {
return MA_ERROR; /* Wait failed. */
}
}
......@@ -15255,7 +15259,7 @@ static ma_result ma_device_audio_thread__wasapi(ma_device* pDevice)
if (framesAvailablePlayback == 0) {
/* In exclusive mode we waited at the top. */
if (pDevice->playback.shareMode != ma_share_mode_exclusive) {
if (WaitForSingleObject(pDevice->wasapi.hEventPlayback, INFINITE) != WAIT_OBJECT_0) {
if (WaitForSingleObject(pDevice->wasapi.hEventPlayback, MA_WASAPI_WAIT_TIMEOUT_MILLISECONDS) != WAIT_OBJECT_0) {
return MA_ERROR; /* Wait failed. */
}
}
......@@ -15280,7 +15284,7 @@ static ma_result ma_device_audio_thread__wasapi(ma_device* pDevice)
/* Try grabbing some captured data if we haven't already got a mapped buffer. */
if (pMappedDeviceBufferCapture == NULL) {
if (pDevice->capture.shareMode == ma_share_mode_shared) {
if (WaitForSingleObject(pDevice->wasapi.hEventCapture, INFINITE) != WAIT_OBJECT_0) {
if (WaitForSingleObject(pDevice->wasapi.hEventCapture, MA_WASAPI_WAIT_TIMEOUT_MILLISECONDS) != WAIT_OBJECT_0) {
return MA_ERROR; /* Wait failed. */
}
}
......@@ -15297,7 +15301,7 @@ static ma_result ma_device_audio_thread__wasapi(ma_device* pDevice)
if (framesAvailableCapture == 0) {
/* In exclusive mode we waited at the top. */
if (pDevice->capture.shareMode != ma_share_mode_shared) {
if (WaitForSingleObject(pDevice->wasapi.hEventCapture, INFINITE) != WAIT_OBJECT_0) {
if (WaitForSingleObject(pDevice->wasapi.hEventCapture, MA_WASAPI_WAIT_TIMEOUT_MILLISECONDS) != WAIT_OBJECT_0) {
return MA_ERROR; /* Wait failed. */
}
}
......@@ -15540,7 +15544,7 @@ static ma_result ma_device_audio_thread__wasapi(ma_device* pDevice)
DWORD flagsCapture; /* Passed to IAudioCaptureClient_GetBuffer(). */
/* Wait for data to become available first. */
if (WaitForSingleObject(pDevice->wasapi.hEventCapture, INFINITE) != WAIT_OBJECT_0) {
if (WaitForSingleObject(pDevice->wasapi.hEventCapture, MA_WASAPI_WAIT_TIMEOUT_MILLISECONDS) != WAIT_OBJECT_0) {
exitLoop = MA_TRUE;
break; /* Wait failed. */
}
......@@ -15637,12 +15641,6 @@ static ma_result ma_device_audio_thread__wasapi(ma_device* pDevice)
{
ma_uint32 framesAvailablePlayback;
/* Wait for space to become available first. */
if (WaitForSingleObject(pDevice->wasapi.hEventPlayback, INFINITE) != WAIT_OBJECT_0) {
exitLoop = MA_TRUE;
break; /* Wait failed. */
}
/* Check how much space is available. If this returns 0 we just keep waiting. */
result = ma_device__get_available_frames__wasapi(pDevice, (ma_IAudioClient*)pDevice->wasapi.pAudioClientPlayback, &framesAvailablePlayback);
if (result != MA_SUCCESS) {
......@@ -15677,16 +15675,21 @@ static ma_result ma_device_audio_thread__wasapi(ma_device* pDevice)
}
framesWrittenToPlaybackDevice += framesAvailablePlayback;
if (!c89atomic_load_8(&pDevice->wasapi.isStartedPlayback)) {
if (pDevice->playback.shareMode == ma_share_mode_exclusive || framesWrittenToPlaybackDevice >= pDevice->playback.internalPeriodSizeInFrames*1) {
hr = ma_IAudioClient_Start((ma_IAudioClient*)pDevice->wasapi.pAudioClientPlayback);
if (FAILED(hr)) {
ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to start internal playback device.", ma_result_from_HRESULT(hr));
exitLoop = MA_TRUE;
break;
}
c89atomic_exchange_8(&pDevice->wasapi.isStartedPlayback, MA_TRUE);
hr = ma_IAudioClient_Start((ma_IAudioClient*)pDevice->wasapi.pAudioClientPlayback);
if (FAILED(hr)) {
ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to start internal playback device.", ma_result_from_HRESULT(hr));
exitLoop = MA_TRUE;
break;
}
c89atomic_exchange_8(&pDevice->wasapi.isStartedPlayback, MA_TRUE);
}
/* Make sure we don't wait on the event before we've started the device or we may end up deadlocking. */
if (WaitForSingleObject(pDevice->wasapi.hEventPlayback, MA_WASAPI_WAIT_TIMEOUT_MILLISECONDS) != WAIT_OBJECT_0) {
exitLoop = MA_TRUE;
break; /* Wait failed. Probably timed out. */
}
} break;
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