SDL: Recover from -EPIPE in snd_pcm_avail()

From ba65ef5ce7bba8a7cf7b639fe63aba990c403ce0 Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Thu, 28 Sep 2023 20:16:59 -0700
Subject: [PATCH] Recover from -EPIPE in snd_pcm_avail()

---
 src/audio/alsa/SDL_alsa_audio.c | 16 ++++++++++------
 1 file changed, 10 insertions(+), 6 deletions(-)

diff --git a/src/audio/alsa/SDL_alsa_audio.c b/src/audio/alsa/SDL_alsa_audio.c
index a8b9abfa93c9..0d63213b36f8 100644
--- a/src/audio/alsa/SDL_alsa_audio.c
+++ b/src/audio/alsa/SDL_alsa_audio.c
@@ -336,11 +336,16 @@ static void ALSA_WaitDevice(SDL_AudioDevice *device)
     const snd_pcm_sframes_t needed = (snd_pcm_sframes_t)device->sample_frames;
     while (!SDL_AtomicGet(&device->shutdown)) {
         const snd_pcm_sframes_t rc = ALSA_snd_pcm_avail(device->hidden->pcm_handle);
-        if ((rc < 0) && (rc != -EAGAIN)) {
-            /* Hmm, not much we can do - abort */
-            fprintf(stderr, "ALSA snd_pcm_avail failed (unrecoverable): %s\n",
-                    ALSA_snd_strerror(rc));
-            SDL_AudioDeviceDisconnected(device);
+        if (rc < 0 && rc != -EAGAIN) {
+            int status = rc;
+
+            status = ALSA_snd_pcm_recover(device->hidden->pcm_handle, status, 0);
+            if (status < 0) {
+                /* Hmm, not much we can do - abort */
+                fprintf(stderr, "ALSA snd_pcm_avail failed (unrecoverable): %s\n",
+                        ALSA_snd_strerror(rc));
+                SDL_AudioDeviceDisconnected(device);
+            }
             return;
         } else if (rc < needed) {
             const Uint32 delay = ((needed - (SDL_max(rc, 0))) * 1000) / device->spec.freq;
@@ -363,7 +368,6 @@ static int ALSA_PlayDevice(SDL_AudioDevice *device, const Uint8 *buffer, int buf
     while ((frames_left > 0) && !SDL_AtomicGet(&device->shutdown)) {
         int status = ALSA_snd_pcm_writei(device->hidden->pcm_handle,
                                          sample_buf, frames_left);
-
         if (status < 0) {
             if (status == -EAGAIN) {
                 /* Apparently snd_pcm_recover() doesn't handle this case -