From 50e6950fa8bc2bda92698e399bab082383ec2804 Mon Sep 17 00:00:00 2001 From: borine <32966433+borine@users.noreply.github.com> Date: Thu, 30 Nov 2023 11:25:43 +0000 Subject: [PATCH] output/alsa: handle recoverable errors in DrainInternal() It is possible that an underrun may occur in the ALSA output device while MPD is draining its own internal buffer. If this happens then MPD stops playback, reporting the error EPIPE. This commit attempts to recover the ALSA device instead of stopping playback, so that the drain can complete and the next song in the play queue is played. --- src/output/plugins/AlsaOutputPlugin.cxx | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/output/plugins/AlsaOutputPlugin.cxx b/src/output/plugins/AlsaOutputPlugin.cxx index 257f1cd5a..c37428855 100644 --- a/src/output/plugins/AlsaOutputPlugin.cxx +++ b/src/output/plugins/AlsaOutputPlugin.cxx @@ -1002,14 +1002,19 @@ AlsaOutput::DrainInternal() period_buffer.FillWithSilence(silence, out_frame_size); /* drain period_buffer */ - if (!period_buffer.IsDrained()) { + unsigned int retry_count = 0; + while (!period_buffer.IsDrained() && retry_count <= 1) { auto frames_written = WriteFromPeriodBuffer(); if (frames_written < 0) { - if (frames_written == -EAGAIN) + if (frames_written == -EAGAIN || frames_written == -EINTR) return false; - throw Alsa::MakeError(frames_written, - "snd_pcm_writei() failed"); + if (Recover(frames_written) < 0) + throw Alsa::MakeError(frames_written, + "snd_pcm_writei() failed"); + + retry_count++; + continue; } /* need to call CopyRingToPeriodBuffer() and