Skip to content

Commit 198dde0

Browse files
committed
ALSA: usb-audio: Workaround for XRUN at prepare
Under certain situations (typically in the implicit feedback mode), USB-audio driver starts a playback stream already at PCM prepare call even before the actual PCM trigger-START call. For implicit feedback mode, this effectively starts two streams for data and sync endpoints, and if a coupled sync stream gets XRUN at this point, it results in an error -EPIPE. The problem is that currently we return -EPIPE error as is from the prepare. Then application tries to recover again via the prepare call, but it'll fail again because the sync-stop is missing. The sync-stop is missing because it's an internal trigger call (hence the PCM core isn't involved). Since we'll need to re-issue the prepare in anyway when trapped into this pitfall, this patch attempts to address it in a bit different way; namely, the driver tries to prepare once again after syncing the stop manually by itself -- so applications don't see the internal error. At the second failure, we report the error as is, but this shouldn't happen in normal situations. Reported-and-tested-by: Carl Hetherington <[email protected]> Cc: <[email protected]> Link: https://lore.kernel.org/r/[email protected] Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Takashi Iwai <[email protected]>
1 parent e661c48 commit 198dde0

File tree

1 file changed

+11
-2
lines changed

1 file changed

+11
-2
lines changed

sound/usb/pcm.c

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -604,6 +604,7 @@ static int snd_usb_pcm_prepare(struct snd_pcm_substream *substream)
604604
struct snd_pcm_runtime *runtime = substream->runtime;
605605
struct snd_usb_substream *subs = runtime->private_data;
606606
struct snd_usb_audio *chip = subs->stream->chip;
607+
int retry = 0;
607608
int ret;
608609

609610
ret = snd_usb_lock_shutdown(chip);
@@ -614,6 +615,7 @@ static int snd_usb_pcm_prepare(struct snd_pcm_substream *substream)
614615
goto unlock;
615616
}
616617

618+
again:
617619
if (subs->sync_endpoint) {
618620
ret = snd_usb_endpoint_prepare(chip, subs->sync_endpoint);
619621
if (ret < 0)
@@ -638,9 +640,16 @@ static int snd_usb_pcm_prepare(struct snd_pcm_substream *substream)
638640

639641
subs->lowlatency_playback = lowlatency_playback_available(runtime, subs);
640642
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
641-
!subs->lowlatency_playback)
643+
!subs->lowlatency_playback) {
642644
ret = start_endpoints(subs);
643-
645+
/* if XRUN happens at starting streams (possibly with implicit
646+
* fb case), restart again, but only try once.
647+
*/
648+
if (ret == -EPIPE && !retry++) {
649+
sync_pending_stops(subs);
650+
goto again;
651+
}
652+
}
644653
unlock:
645654
snd_usb_unlock_shutdown(chip);
646655
return ret;

0 commit comments

Comments
 (0)