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.
This commit is contained in:
borine 2023-11-30 11:25:43 +00:00
parent e9c40dead8
commit 50e6950fa8

View File

@ -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