From 543776d9c94763a6870511ed569df2fd7eda1577 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Fri, 28 Jun 2019 08:55:23 +0200 Subject: [PATCH] output/alsa: check PCM state before calling snd_pcm_drain() Apparently, if snd_pcm_drain() returns EAGAIN, it does not actually want to be called again; the next call will snd_pcm_drain() will also return EAGAIN, forever, even though the PCM state has meanwhile switched to SND_PCM_STATE_SETUP. This causes a busy loop; to fix this, we should always check snd_pcm_state() to see if draining is really required. --- NEWS | 1 + src/output/plugins/AlsaOutputPlugin.cxx | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+) diff --git a/NEWS b/NEWS index b0657d4a9..1d066d290 100644 --- a/NEWS +++ b/NEWS @@ -4,6 +4,7 @@ ver 0.21.11 (not yet released) * decoder - wildmidi: log error if library initialization fails * output + - alsa: fix busy loop while draining - alsa, osx: fix distortions with DSD_U32 and DoP on 32 bit CPUs * protocol - fix "list" with multiple "group" levels diff --git a/src/output/plugins/AlsaOutputPlugin.cxx b/src/output/plugins/AlsaOutputPlugin.cxx index 8f32cf8d7..eefb7f467 100644 --- a/src/output/plugins/AlsaOutputPlugin.cxx +++ b/src/output/plugins/AlsaOutputPlugin.cxx @@ -774,6 +774,24 @@ AlsaOutput::DrainInternal() don't need to drain it */ return true; + switch (snd_pcm_state(pcm)) { + case SND_PCM_STATE_PREPARED: + case SND_PCM_STATE_RUNNING: + /* these states require a call to snd_pcm_drain() */ + break; + + case SND_PCM_STATE_DRAINING: + /* already draining, but not yet finished; this is + probably a spurious epoll event, and we should wait + for the next one */ + return false; + + default: + /* all other states cannot be drained, and we're + done */ + return true; + } + /* .. and finally drain the ALSA hardware buffer */ int result;