mirror of
https://github.com/mackron/miniaudio.git
synced 2026-04-22 00:06:59 +02:00
WASAPI: Rework the data discontinuity recovery logic.
Public issue https://github.com/mackron/miniaudio/issues/572
This commit is contained in:
+46
-21
@@ -22223,12 +22223,17 @@ static ma_result ma_device_read__wasapi(ma_device* pDevice, void* pFrames, ma_ui
|
||||
} else {
|
||||
/* We don't have any cached data pointer, so grab another one. */
|
||||
HRESULT hr;
|
||||
DWORD flags;
|
||||
DWORD flags = 0;
|
||||
|
||||
/* First just ask WASAPI for a data buffer. If it's not available, we'll wait for more. */
|
||||
hr = ma_IAudioCaptureClient_GetBuffer((ma_IAudioCaptureClient*)pDevice->wasapi.pCaptureClient, (BYTE**)&pDevice->wasapi.pMappedBufferCapture, &pDevice->wasapi.mappedBufferCaptureCap, &flags, NULL, NULL);
|
||||
if (hr == S_OK) {
|
||||
/* We got a data buffer. Continue to the next loop iteration which will then read from the mapped pointer. */
|
||||
pDevice->wasapi.mappedBufferCaptureLen = pDevice->wasapi.mappedBufferCaptureCap;
|
||||
|
||||
if (flags != 0) {
|
||||
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[WASAPI] Capture Flags: %ld\n", flags);
|
||||
}
|
||||
|
||||
/* Overrun detection. */
|
||||
if ((flags & MA_AUDCLNT_BUFFERFLAGS_DATA_DISCONTINUITY) != 0) {
|
||||
@@ -22236,13 +22241,29 @@ static ma_result ma_device_read__wasapi(ma_device* pDevice, void* pFrames, ma_ui
|
||||
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[WASAPI] Data discontinuity (possible overrun). Attempting recovery. mappedBufferCaptureCap=%d\n", pDevice->wasapi.mappedBufferCaptureCap);
|
||||
|
||||
/*
|
||||
If we got an overrun it probably means we're straddling the end of the buffer. In order to prevent
|
||||
a never-ending sequence of glitches we're going to recover by completely clearing out the capture
|
||||
buffer.
|
||||
If we got an overrun it probably means we're straddling the end of the buffer. In normal capture
|
||||
mode this is the fault of the client application because they're responsible for ensuring data is
|
||||
processed fast enough. In duplex mode, however, the processing of audio is tied to the playback
|
||||
device, so this can possibly be the result of a timing de-sync.
|
||||
|
||||
In capture mode we're not going to do any kind of recovery because the real fix is for the client
|
||||
application to process faster. In duplex mode, we'll treat this as a desync and reset the buffers
|
||||
to prevent a never-ending sequence of glitches due to straddling the end of the buffer.
|
||||
*/
|
||||
{
|
||||
ma_uint32 iterationCount = 4; /* Safety to prevent an infinite loop. */
|
||||
if (pDevice->type == ma_device_type_duplex) {
|
||||
/*
|
||||
Experiment:
|
||||
|
||||
If we empty out the *entire* buffer we may end up putting ourselves into an underrun position
|
||||
which isn't really any better than the overrun we're probably in right now. Instead we'll just
|
||||
empty out about half.
|
||||
*/
|
||||
ma_uint32 i;
|
||||
ma_uint32 periodCount = (pDevice->wasapi.actualBufferSizeInFramesCapture / pDevice->wasapi.periodSizeInFramesCapture);
|
||||
ma_uint32 iterationCount = periodCount / 2;
|
||||
if ((periodCount % 2) > 0) {
|
||||
iterationCount += 1;
|
||||
}
|
||||
|
||||
for (i = 0; i < iterationCount; i += 1) {
|
||||
hr = ma_IAudioCaptureClient_ReleaseBuffer((ma_IAudioCaptureClient*)pDevice->wasapi.pCaptureClient, pDevice->wasapi.mappedBufferCaptureCap);
|
||||
@@ -22251,11 +22272,26 @@ static ma_result ma_device_read__wasapi(ma_device* pDevice, void* pFrames, ma_ui
|
||||
break;
|
||||
}
|
||||
|
||||
flags = 0;
|
||||
hr = ma_IAudioCaptureClient_GetBuffer((ma_IAudioCaptureClient*)pDevice->wasapi.pCaptureClient, (BYTE**)&pDevice->wasapi.pMappedBufferCapture, &pDevice->wasapi.mappedBufferCaptureCap, &flags, NULL, NULL);
|
||||
if (hr == MA_AUDCLNT_S_BUFFER_EMPTY || FAILED(hr)) {
|
||||
/*
|
||||
The buffer has been completely emptied or an error occurred. In this case we'll need
|
||||
to reset the state of the mapped buffer which will trigger the next iteration to get
|
||||
a fresh buffer from WASAPI.
|
||||
*/
|
||||
pDevice->wasapi.pMappedBufferCapture = NULL;
|
||||
pDevice->wasapi.mappedBufferCaptureCap = 0;
|
||||
pDevice->wasapi.mappedBufferCaptureLen = 0;
|
||||
|
||||
if (hr == MA_AUDCLNT_S_BUFFER_EMPTY) {
|
||||
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[WASAPI] Data discontinuity recovery: Buffer emptied.\n");
|
||||
if ((flags & MA_AUDCLNT_BUFFERFLAGS_DATA_DISCONTINUITY) != 0) {
|
||||
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[WASAPI] Data discontinuity recovery: Buffer emptied, and data discontinuity still reported.\n");
|
||||
} else {
|
||||
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[WASAPI] Data discontinuity recovery: Buffer emptied.\n");
|
||||
}
|
||||
}
|
||||
|
||||
if (FAILED(hr)) {
|
||||
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[WASAPI] Data discontinuity recovery: IAudioCaptureClient_GetBuffer() failed with %d.\n", hr);
|
||||
}
|
||||
@@ -22264,22 +22300,11 @@ static ma_result ma_device_read__wasapi(ma_device* pDevice, void* pFrames, ma_ui
|
||||
}
|
||||
}
|
||||
|
||||
if (i == iterationCount) {
|
||||
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[WASAPI] Data discontinuity recovery: Iteration limit reached.\n");
|
||||
/* If at this point we have a valid buffer mapped, make sure the buffer length is set appropriately. */
|
||||
if (pDevice->wasapi.pMappedBufferCapture != NULL) {
|
||||
pDevice->wasapi.mappedBufferCaptureLen = pDevice->wasapi.mappedBufferCaptureCap;
|
||||
}
|
||||
}
|
||||
|
||||
/* We should not have a valid buffer at this point so make sure everything is empty. */
|
||||
pDevice->wasapi.pMappedBufferCapture = NULL;
|
||||
pDevice->wasapi.mappedBufferCaptureCap = 0;
|
||||
pDevice->wasapi.mappedBufferCaptureLen = 0;
|
||||
} else {
|
||||
/* The data is clean. */
|
||||
pDevice->wasapi.mappedBufferCaptureLen = pDevice->wasapi.mappedBufferCaptureCap;
|
||||
|
||||
if (flags != 0) {
|
||||
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[WASAPI] Capture Flags: %ld\n", flags);
|
||||
}
|
||||
}
|
||||
|
||||
continue;
|
||||
|
||||
Reference in New Issue
Block a user