Commit ba906aee authored by David Reid's avatar David Reid

WASAPI: Add some overrun detection for ma_device_type_capture.

This is derived from the ma_device_type_duplex case. It basically
detects a possible overrun and drops some periods. The idea is to
prevent the buffer from indefinitely straddling the end of the buffer
and causing persistent glitching.

Public issue https://github.com/dr-soft/miniaudio/issues/81
parent aedd1169
...@@ -12884,7 +12884,58 @@ static ma_result ma_device_main_loop__wasapi(ma_device* pDevice) ...@@ -12884,7 +12884,58 @@ static ma_result ma_device_main_loop__wasapi(ma_device* pDevice)
break; break;
} }
/* We should have a buffer at this point. */ /* Overrun detection. */
if ((flagsCapture & MA_AUDCLNT_BUFFERFLAGS_DATA_DISCONTINUITY) != 0) {
/* Glitched. Probably due to an overrun. */
#ifdef MA_DEBUG_OUTPUT
printf("[WASAPI] Data discontinuity (possible overrun). framesAvailableCapture=%d, mappedBufferSizeInFramesCapture=%d\n", framesAvailableCapture, mappedDeviceBufferSizeInFramesCapture);
#endif
/*
Exeriment: If we get an overrun it probably means we're straddling the end of the buffer. In order to prevent a never-ending sequence of glitches let's experiment
by dropping every frame until we're left with only a single period. To do this we just keep retrieving and immediately releasing buffers until we're down to the
last period.
*/
if (framesAvailableCapture >= pDevice->wasapi.actualPeriodSizeInFramesCapture) {
#ifdef MA_DEBUG_OUTPUT
printf("[WASAPI] Synchronizing capture stream. ");
#endif
do
{
hr = ma_IAudioCaptureClient_ReleaseBuffer((ma_IAudioCaptureClient*)pDevice->wasapi.pCaptureClient, mappedDeviceBufferSizeInFramesCapture);
if (FAILED(hr)) {
break;
}
framesAvailableCapture -= mappedDeviceBufferSizeInFramesCapture;
if (framesAvailableCapture > 0) {
mappedDeviceBufferSizeInFramesCapture = ma_min(framesAvailableCapture, periodSizeInFramesCapture);
hr = ma_IAudioCaptureClient_GetBuffer((ma_IAudioCaptureClient*)pDevice->wasapi.pCaptureClient, (BYTE**)&pMappedDeviceBufferCapture, &mappedDeviceBufferSizeInFramesCapture, &flagsCapture, NULL, NULL);
if (FAILED(hr)) {
ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to retrieve internal buffer from capture device in preparation for writing to the device.", ma_result_from_HRESULT(hr));
exitLoop = MA_TRUE;
break;
}
} else {
pMappedDeviceBufferCapture = NULL;
mappedDeviceBufferSizeInFramesCapture = 0;
}
} while (framesAvailableCapture > periodSizeInFramesCapture);
#ifdef MA_DEBUG_OUTPUT
printf("framesAvailableCapture=%d, mappedBufferSizeInFramesCapture=%d\n", framesAvailableCapture, mappedDeviceBufferSizeInFramesCapture);
#endif
}
} else {
#ifdef MA_DEBUG_OUTPUT
if (flagsCapture != 0) {
printf("[WASAPI] Capture Flags: %d\n", flagsCapture);
}
#endif
}
/* We should have a buffer at this point, but let's just do a sanity check anyway. */
if (mappedDeviceBufferSizeInFramesCapture > 0 && pMappedDeviceBufferCapture != NULL) {
ma_device__send_frames_to_client(pDevice, mappedDeviceBufferSizeInFramesCapture, pMappedDeviceBufferCapture); ma_device__send_frames_to_client(pDevice, mappedDeviceBufferSizeInFramesCapture, pMappedDeviceBufferCapture);
/* At this point we're done with the buffer. */ /* At this point we're done with the buffer. */
...@@ -12896,6 +12947,7 @@ static ma_result ma_device_main_loop__wasapi(ma_device* pDevice) ...@@ -12896,6 +12947,7 @@ static ma_result ma_device_main_loop__wasapi(ma_device* pDevice)
exitLoop = MA_TRUE; exitLoop = MA_TRUE;
break; break;
} }
}
} break; } 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