ALSA: pcm: Improved XRUN handling for indirect PCM helpers
authorTakashi Iwai <tiwai@suse.de>
Thu, 23 Mar 2023 06:52:35 +0000 (07:52 +0100)
committerTakashi Iwai <tiwai@suse.de>
Fri, 24 Mar 2023 13:52:58 +0000 (14:52 +0100)
As PCM ack callback may handle the XRUN situation gracefully now,
change the indirect PCM helpers to give a proper error (-EPIPE).
Also, change the pointer callback helpers to deal with the XRUN error
properly, too.

This requires the PCM core change by the commit 8c721c53dda5
("ALSA: usb-audio: Fix recursive locking at XRUN during syncing").

Link: https://lore.kernel.org/r/20230323065237.5062-2-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
include/sound/pcm-indirect.h

index 0412768..98e06ea 100644 (file)
@@ -44,7 +44,7 @@ snd_pcm_indirect_playback_transfer(struct snd_pcm_substream *substream,
                if (diff < -(snd_pcm_sframes_t) (runtime->boundary / 2))
                        diff += runtime->boundary;
                if (diff < 0)
-                       return -EINVAL;
+                       return -EPIPE;
                rec->sw_ready += (int)frames_to_bytes(runtime, diff);
                rec->appl_ptr = appl_ptr;
        }
@@ -83,6 +83,8 @@ snd_pcm_indirect_playback_pointer(struct snd_pcm_substream *substream,
                                  struct snd_pcm_indirect *rec, unsigned int ptr)
 {
        int bytes = ptr - rec->hw_io;
+       int err;
+
        if (bytes < 0)
                bytes += rec->hw_buffer_size;
        rec->hw_io = ptr;
@@ -90,8 +92,11 @@ snd_pcm_indirect_playback_pointer(struct snd_pcm_substream *substream,
        rec->sw_io += bytes;
        if (rec->sw_io >= rec->sw_buffer_size)
                rec->sw_io -= rec->sw_buffer_size;
-       if (substream->ops->ack)
-               substream->ops->ack(substream);
+       if (substream->ops->ack) {
+               err = substream->ops->ack(substream);
+               if (err == -EPIPE)
+                       return SNDRV_PCM_POS_XRUN;
+       }
        return bytes_to_frames(substream->runtime, rec->sw_io);
 }
 
@@ -112,7 +117,7 @@ snd_pcm_indirect_capture_transfer(struct snd_pcm_substream *substream,
                if (diff < -(snd_pcm_sframes_t) (runtime->boundary / 2))
                        diff += runtime->boundary;
                if (diff < 0)
-                       return -EINVAL;
+                       return -EPIPE;
                rec->sw_ready -= frames_to_bytes(runtime, diff);
                rec->appl_ptr = appl_ptr;
        }
@@ -152,6 +157,8 @@ snd_pcm_indirect_capture_pointer(struct snd_pcm_substream *substream,
 {
        int qsize;
        int bytes = ptr - rec->hw_io;
+       int err;
+
        if (bytes < 0)
                bytes += rec->hw_buffer_size;
        rec->hw_io = ptr;
@@ -162,8 +169,11 @@ snd_pcm_indirect_capture_pointer(struct snd_pcm_substream *substream,
        rec->sw_io += bytes;
        if (rec->sw_io >= rec->sw_buffer_size)
                rec->sw_io -= rec->sw_buffer_size;
-       if (substream->ops->ack)
-               substream->ops->ack(substream);
+       if (substream->ops->ack) {
+               err = substream->ops->ack(substream);
+               if (err == -EPIPE)
+                       return SNDRV_PCM_POS_XRUN;
+       }
        return bytes_to_frames(substream->runtime, rec->sw_io);
 }