Commit 997d8a8d authored by David Reid's avatar David Reid

WASAPI/ALSA: Fix automatic playback starting in full-duplex mode.

The new rule is to start playback when the entire buffer is filled
rather than when the first period is filled in duplex mode. Normal
playback mode will still start the device when the first period is
filled.
parent 1b957471
...@@ -2188,6 +2188,8 @@ MAL_ALIGNED_STRUCT(MAL_SIMD_ALIGNMENT) mal_device ...@@ -2188,6 +2188,8 @@ MAL_ALIGNED_STRUCT(MAL_SIMD_ALIGNMENT) mal_device
mal_uint32 deviceBufferFramesCapacityCapture; mal_uint32 deviceBufferFramesCapacityCapture;
mal_uint32 periodSizeInFramesPlayback; mal_uint32 periodSizeInFramesPlayback;
mal_uint32 periodSizeInFramesCapture; mal_uint32 periodSizeInFramesCapture;
mal_uint32 actualBufferSizeInFramesPlayback; /* Value from GetBufferSize(). internalBufferSizeInFrames is not set to the _actual_ buffer size when low-latency shared mode is being used due to the way the IAudioClient3 API works. */
mal_uint32 actualBufferSizeInFramesCapture;
mal_uint32 originalBufferSizeInFrames; mal_uint32 originalBufferSizeInFrames;
mal_uint32 originalBufferSizeInMilliseconds; mal_uint32 originalBufferSizeInMilliseconds;
mal_uint32 originalPeriods; mal_uint32 originalPeriods;
...@@ -7259,9 +7261,7 @@ mal_result mal_device_init_internal__wasapi(mal_context* pContext, mal_device_ty ...@@ -7259,9 +7261,7 @@ mal_result mal_device_init_internal__wasapi(mal_context* pContext, mal_device_ty
errorMsg = "[WASAPI] Failed to get audio client's actual buffer size.", result = MAL_FAILED_TO_OPEN_BACKEND_DEVICE; errorMsg = "[WASAPI] Failed to get audio client's actual buffer size.", result = MAL_FAILED_TO_OPEN_BACKEND_DEVICE;
goto done; goto done;
} }
}
if (!wasInitializedUsingIAudioClient3) {
pData->periodSizeInFramesOut = pData->bufferSizeInFramesOut / pData->periodsOut; pData->periodSizeInFramesOut = pData->bufferSizeInFramesOut / pData->periodsOut;
} }
...@@ -7390,6 +7390,7 @@ mal_result mal_device_reinit__wasapi(mal_device* pDevice, mal_device_type device ...@@ -7390,6 +7390,7 @@ mal_result mal_device_reinit__wasapi(mal_device* pDevice, mal_device_type device
mal_IAudioClient_SetEventHandle((mal_IAudioClient*)pDevice->wasapi.pAudioClientCapture, pDevice->wasapi.hEventCapture); mal_IAudioClient_SetEventHandle((mal_IAudioClient*)pDevice->wasapi.pAudioClientCapture, pDevice->wasapi.hEventCapture);
pDevice->wasapi.periodSizeInFramesCapture = data.periodSizeInFramesOut; pDevice->wasapi.periodSizeInFramesCapture = data.periodSizeInFramesOut;
mal_IAudioClient_GetBufferSize((mal_IAudioClient*)pDevice->wasapi.pAudioClientCapture, &pDevice->wasapi.actualBufferSizeInFramesCapture);
} }
if (deviceType == mal_device_type_playback) { if (deviceType == mal_device_type_playback) {
...@@ -7417,6 +7418,7 @@ mal_result mal_device_reinit__wasapi(mal_device* pDevice, mal_device_type device ...@@ -7417,6 +7418,7 @@ mal_result mal_device_reinit__wasapi(mal_device* pDevice, mal_device_type device
mal_IAudioClient_SetEventHandle((mal_IAudioClient*)pDevice->wasapi.pAudioClientPlayback, pDevice->wasapi.hEventPlayback); mal_IAudioClient_SetEventHandle((mal_IAudioClient*)pDevice->wasapi.pAudioClientPlayback, pDevice->wasapi.hEventPlayback);
pDevice->wasapi.periodSizeInFramesPlayback = data.periodSizeInFramesOut; pDevice->wasapi.periodSizeInFramesPlayback = data.periodSizeInFramesOut;
mal_IAudioClient_GetBufferSize((mal_IAudioClient*)pDevice->wasapi.pAudioClientPlayback, &pDevice->wasapi.actualBufferSizeInFramesPlayback);
} }
mal_atomic_exchange_32(&pDevice->wasapi.isStarted, MAL_FALSE); mal_atomic_exchange_32(&pDevice->wasapi.isStarted, MAL_FALSE);
...@@ -7490,6 +7492,7 @@ mal_result mal_device_init__wasapi(mal_context* pContext, const mal_device_confi ...@@ -7490,6 +7492,7 @@ mal_result mal_device_init__wasapi(mal_context* pContext, const mal_device_confi
mal_IAudioClient_SetEventHandle((mal_IAudioClient*)pDevice->wasapi.pAudioClientCapture, pDevice->wasapi.hEventCapture); mal_IAudioClient_SetEventHandle((mal_IAudioClient*)pDevice->wasapi.pAudioClientCapture, pDevice->wasapi.hEventCapture);
pDevice->wasapi.periodSizeInFramesCapture = data.periodSizeInFramesOut; pDevice->wasapi.periodSizeInFramesCapture = data.periodSizeInFramesOut;
mal_IAudioClient_GetBufferSize((mal_IAudioClient*)pDevice->wasapi.pAudioClientCapture, &pDevice->wasapi.actualBufferSizeInFramesCapture);
} }
if (pConfig->deviceType == mal_device_type_playback || pConfig->deviceType == mal_device_type_duplex) { if (pConfig->deviceType == mal_device_type_playback || pConfig->deviceType == mal_device_type_duplex) {
...@@ -7573,6 +7576,7 @@ mal_result mal_device_init__wasapi(mal_context* pContext, const mal_device_confi ...@@ -7573,6 +7576,7 @@ mal_result mal_device_init__wasapi(mal_context* pContext, const mal_device_confi
mal_IAudioClient_SetEventHandle((mal_IAudioClient*)pDevice->wasapi.pAudioClientPlayback, pDevice->wasapi.hEventPlayback); mal_IAudioClient_SetEventHandle((mal_IAudioClient*)pDevice->wasapi.pAudioClientPlayback, pDevice->wasapi.hEventPlayback);
pDevice->wasapi.periodSizeInFramesPlayback = data.periodSizeInFramesOut; pDevice->wasapi.periodSizeInFramesPlayback = data.periodSizeInFramesOut;
mal_IAudioClient_GetBufferSize((mal_IAudioClient*)pDevice->wasapi.pAudioClientPlayback, &pDevice->wasapi.actualBufferSizeInFramesPlayback);
} }
...@@ -7709,7 +7713,7 @@ mal_result mal_device__get_available_frames__wasapi(mal_device* pDevice, mal_IAu ...@@ -7709,7 +7713,7 @@ mal_result mal_device__get_available_frames__wasapi(mal_device* pDevice, mal_IAu
*pFrameCount = paddingFramesCount; *pFrameCount = paddingFramesCount;
} else { } else {
if ((mal_ptr)pAudioClient == pDevice->wasapi.pAudioClientPlayback) { if ((mal_ptr)pAudioClient == pDevice->wasapi.pAudioClientPlayback) {
*pFrameCount = pDevice->playback.internalBufferSizeInFrames - paddingFramesCount; *pFrameCount = pDevice->wasapi.actualBufferSizeInFramesPlayback - paddingFramesCount;
} else { } else {
*pFrameCount = paddingFramesCount; *pFrameCount = paddingFramesCount;
} }
...@@ -7857,8 +7861,10 @@ mal_result mal_device_write__wasapi(mal_device* pDevice, const void* pPCMFrames, ...@@ -7857,8 +7861,10 @@ mal_result mal_device_write__wasapi(mal_device* pDevice, const void* pPCMFrames,
/* In exclusive mode, the frame count needs to exactly match the value returned by GetCurrentPadding(). */ /* In exclusive mode, the frame count needs to exactly match the value returned by GetCurrentPadding(). */
if (pDevice->playback.shareMode != mal_share_mode_exclusive) { if (pDevice->playback.shareMode != mal_share_mode_exclusive) {
if (pDevice->wasapi.deviceBufferFramesCapacityPlayback > pDevice->wasapi.periodSizeInFramesPlayback) { if (pDevice->type != mal_device_type_duplex) { /* Full-duplex mode should also require the whole buffer be mapped at a time. */
pDevice->wasapi.deviceBufferFramesCapacityPlayback = pDevice->wasapi.periodSizeInFramesPlayback; if (pDevice->wasapi.deviceBufferFramesCapacityPlayback > pDevice->wasapi.periodSizeInFramesPlayback) {
pDevice->wasapi.deviceBufferFramesCapacityPlayback = pDevice->wasapi.periodSizeInFramesPlayback;
}
} }
} }
...@@ -11978,7 +11984,7 @@ mal_result mal_device_init_by_type__alsa(mal_context* pContext, const mal_device ...@@ -11978,7 +11984,7 @@ mal_result mal_device_init_by_type__alsa(mal_context* pContext, const mal_device
Subtle detail here with the start threshold. When in playback-only mode (no full-duplex) we can set the start threshold to Subtle detail here with the start threshold. When in playback-only mode (no full-duplex) we can set the start threshold to
the size of a period. But for full-duplex we need to set it such that it is at least two periods. the size of a period. But for full-duplex we need to set it such that it is at least two periods.
*/ */
if (((mal_snd_pcm_sw_params_set_start_threshold_proc)pContext->alsa.snd_pcm_sw_params_set_start_threshold)(pPCM, pSWParams, (internalBufferSizeInFrames / internalPeriods) * 2 /*internalBufferSizeInFrames*/) != 0) { if (((mal_snd_pcm_sw_params_set_start_threshold_proc)pContext->alsa.snd_pcm_sw_params_set_start_threshold)(pPCM, pSWParams, internalBufferSizeInFrames) != 0) {
((mal_snd_pcm_close_proc)pDevice->pContext->alsa.snd_pcm_close)(pPCM); ((mal_snd_pcm_close_proc)pDevice->pContext->alsa.snd_pcm_close)(pPCM);
return mal_post_error(pDevice, MAL_LOG_LEVEL_ERROR, "[ALSA] Failed to set start threshold for playback device. snd_pcm_sw_params_set_start_threshold() failed.", MAL_FAILED_TO_CONFIGURE_BACKEND_DEVICE); return mal_post_error(pDevice, MAL_LOG_LEVEL_ERROR, "[ALSA] Failed to set start threshold for playback device. snd_pcm_sw_params_set_start_threshold() failed.", MAL_FAILED_TO_CONFIGURE_BACKEND_DEVICE);
} }
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