From 4c434f1591b0e43a860833f2e1dc993574d47950 Mon Sep 17 00:00:00 2001 From: David Reid Date: Tue, 7 Nov 2017 19:39:47 +1000 Subject: [PATCH] ALSA: Another attempt at fixing mmap mode. --- mini_al.h | 56 ++++++++++++++++++++++++++++--------------------------- 1 file changed, 29 insertions(+), 27 deletions(-) diff --git a/mini_al.h b/mini_al.h index 3011a336..68e29b63 100644 --- a/mini_al.h +++ b/mini_al.h @@ -5102,27 +5102,9 @@ static mal_uint32 mal_device__wait_for_frames__alsa(mal_device* pDevice, mal_boo mal_uint32 periodSizeInFrames = pDevice->bufferSizeInFrames / pDevice->periods; while (!pDevice->alsa.breakFromMainLoop) { - snd_pcm_sframes_t framesAvailable = ((mal_snd_pcm_avail_update_proc)pDevice->pContext->alsa.snd_pcm_avail_update)((snd_pcm_t*)pDevice->alsa.pPCM); - - // Keep the returned number of samples consistent and based on the period size. - if (framesAvailable >= periodSizeInFrames) { - return periodSizeInFrames; - } - - if (framesAvailable < 0) { - if (framesAvailable == -EPIPE) { - if (((mal_snd_pcm_recover_proc)pDevice->pContext->alsa.snd_pcm_recover)((snd_pcm_t*)pDevice->alsa.pPCM, framesAvailable, MAL_TRUE) < 0) { - return 0; - } - - framesAvailable = ((mal_snd_pcm_avail_update_proc)pDevice->pContext->alsa.snd_pcm_avail_update)((snd_pcm_t*)pDevice->alsa.pPCM); - if (framesAvailable < 0) { - return 0; - } - } - } - - const int timeoutInMilliseconds = 1; // <-- The larger this value, the longer it'll take to stop the device! + // Wait for something to become available. The timeout should not affect latency - it's only used to break from the wait + // so we can check whether or not the device has been stopped. + const int timeoutInMilliseconds = 10; int waitResult = ((mal_snd_pcm_wait_proc)pDevice->pContext->alsa.snd_pcm_wait)((snd_pcm_t*)pDevice->alsa.pPCM, timeoutInMilliseconds); if (waitResult < 0) { if (waitResult == -EPIPE) { @@ -5130,15 +5112,35 @@ static mal_uint32 mal_device__wait_for_frames__alsa(mal_device* pDevice, mal_boo return 0; } - if (pRequiresRestart) { - *pRequiresRestart = MAL_TRUE; + if (pRequiresRestart) *pRequiresRestart = MAL_TRUE; // A device recovery means a restart for mmap mode. + } + } + + if (pDevice->alsa.breakFromMainLoop) { + return 0; + } + + snd_pcm_sframes_t framesAvailable = ((mal_snd_pcm_avail_update_proc)pDevice->pContext->alsa.snd_pcm_avail_update)((snd_pcm_t*)pDevice->alsa.pPCM); + if (framesAvailable < 0) { + if (framesAvailable == -EPIPE) { + if (((mal_snd_pcm_recover_proc)pDevice->pContext->alsa.snd_pcm_recover)((snd_pcm_t*)pDevice->alsa.pPCM, framesAvailable, MAL_TRUE) < 0) { + return 0; } - return pDevice->bufferSizeInFrames; - } else { - return 0; + if (pRequiresRestart) *pRequiresRestart = MAL_TRUE; // A device recovery means a restart for mmap mode. + + // Try again, but if it fails this time just return an error. + framesAvailable = ((mal_snd_pcm_avail_update_proc)pDevice->pContext->alsa.snd_pcm_avail_update)((snd_pcm_t*)pDevice->alsa.pPCM); + if (framesAvailable < 0) { + return 0; + } } } + + // Keep the returned number of samples consistent and based on the period size. + if (framesAvailable >= periodSizeInFrames) { + return periodSizeInFrames; + } } // We'll get here if the loop was terminated. Just return whatever's available. @@ -5161,7 +5163,7 @@ static mal_bool32 mal_device_write__alsa(mal_device* pDevice) } - if (pDevice->alsa.pIntermediaryBuffer == NULL) { + if (pDevice->alsa.isUsingMMap) { // mmap. mal_bool32 requiresRestart; mal_uint32 framesAvailable = mal_device__wait_for_frames__alsa(pDevice, &requiresRestart);