From 543776d9c94763a6870511ed569df2fd7eda1577 Mon Sep 17 00:00:00 2001
From: Max Kellermann <max@musicpd.org>
Date: Fri, 28 Jun 2019 08:55:23 +0200
Subject: [PATCH 1/2] 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;

From c926021599c77b3011beec856cad535a5bedb1af Mon Sep 17 00:00:00 2001
From: Max Kellermann <max@musicpd.org>
Date: Fri, 28 Jun 2019 08:27:48 +0200
Subject: [PATCH 2/2] output/alsa: always redo DrainInternal() after writing

Draining isn't finished just because the period_buffer has run empty.
It is only finished after snd_pcm_drain() has succeeded.
---
 NEWS                                    | 1 +
 src/output/plugins/AlsaOutputPlugin.cxx | 2 +-
 2 files changed, 2 insertions(+), 1 deletion(-)

diff --git a/NEWS b/NEWS
index 1d066d290..542cd5d04 100644
--- a/NEWS
+++ b/NEWS
@@ -5,6 +5,7 @@ ver 0.21.11 (not yet released)
   - wildmidi: log error if library initialization fails
 * output
   - alsa: fix busy loop while draining
+  - alsa: fix missing drain call
   - 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 eefb7f467..16832a1bc 100644
--- a/src/output/plugins/AlsaOutputPlugin.cxx
+++ b/src/output/plugins/AlsaOutputPlugin.cxx
@@ -766,7 +766,7 @@ AlsaOutput::DrainInternal()
 		/* need to call CopyRingToPeriodBuffer() and
 		   WriteFromPeriodBuffer() again in the next
 		   iteration, so don't finish the drain just yet */
-		return period_buffer.IsEmpty();
+		return false;
 	}
 
 	if (!written)