summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMax Kellermann <max@musicpd.org>2019-06-28 08:55:23 +0200
committerMax Kellermann <max@musicpd.org>2019-06-28 08:55:25 +0200
commit543776d9c94763a6870511ed569df2fd7eda1577 (patch)
tree885fdf053a7049ed292bc78f3771b8f18798ca08 /src
parent8bf3f9b87437e2969b50a8d1bcb380678a5ad58c (diff)
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.
Diffstat (limited to 'src')
-rw-r--r--src/output/plugins/AlsaOutputPlugin.cxx18
1 files changed, 18 insertions, 0 deletions
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;