Skip to content

Commit 4267c5a

Browse files
committed
ALSA: usb-audio: Work around for XRUN with low latency playback
The recent change for low latency playback works in most of test cases but it turned out still to hit errors on some use cases, most notably with JACK with small buffer sizes. This is because USB-audio driver fills up and submits full URBs at the beginning, while the URBs would return immediately and try to fill more -- that can easily trigger XRUN. It was more or less expected, but in the small buffer size, the problem became pretty obvious. Fixing this behavior properly would require the change of the fundamental driver design, so it's no trivial task, unfortunately. Instead, here we work around the problem just by switching back to the old method when the given configuration is too fragile with the low latency stream handling. As a threshold, we calculate the total buffer bytes in all plus one URBs, and check whether it's beyond the PCM buffer bytes. The one extra URB is needed because XRUN happens at the next submission after the first round. Fixes: 307cc9b ("ALSA: usb-audio: Reduce latency at playback start, take#2") Cc: <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Takashi Iwai <[email protected]>
1 parent f3eef46 commit 4267c5a

File tree

3 files changed

+17
-2
lines changed

3 files changed

+17
-2
lines changed

sound/usb/card.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ struct snd_usb_endpoint {
9494
struct list_head ready_playback_urbs; /* playback URB FIFO for implicit fb */
9595

9696
unsigned int nurbs; /* # urbs */
97+
unsigned int nominal_queue_size; /* total buffer sizes in URBs */
9798
unsigned long active_mask; /* bitmask of active urbs */
9899
unsigned long unlink_mask; /* bitmask of unlinked urbs */
99100
char *syncbuf; /* sync buffer for all sync URBs */
@@ -187,6 +188,7 @@ struct snd_usb_substream {
187188
} dsd_dop;
188189

189190
bool trigger_tstamp_pending_update; /* trigger timestamp being updated from initial estimate */
191+
bool early_playback_start; /* early start needed for playback? */
190192
struct media_ctl *media_ctl;
191193
};
192194

sound/usb/endpoint.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1126,6 +1126,10 @@ static int data_ep_set_params(struct snd_usb_endpoint *ep)
11261126
INIT_LIST_HEAD(&u->ready_list);
11271127
}
11281128

1129+
/* total buffer bytes of all URBs plus the next queue;
1130+
* referred in pcm.c
1131+
*/
1132+
ep->nominal_queue_size = maxsize * urb_packs * (ep->nurbs + 1);
11291133
return 0;
11301134

11311135
out_of_memory:

sound/usb/pcm.c

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -614,6 +614,14 @@ static int snd_usb_pcm_prepare(struct snd_pcm_substream *substream)
614614
subs->period_elapsed_pending = 0;
615615
runtime->delay = 0;
616616

617+
/* check whether early start is needed for playback stream */
618+
subs->early_playback_start =
619+
subs->direction == SNDRV_PCM_STREAM_PLAYBACK &&
620+
subs->data_endpoint->nominal_queue_size >= subs->buffer_bytes;
621+
622+
if (subs->early_playback_start)
623+
ret = start_endpoints(subs);
624+
617625
unlock:
618626
snd_usb_unlock_shutdown(chip);
619627
return ret;
@@ -1394,7 +1402,7 @@ static void prepare_playback_urb(struct snd_usb_substream *subs,
13941402
subs->trigger_tstamp_pending_update = false;
13951403
}
13961404

1397-
if (period_elapsed && !subs->running) {
1405+
if (period_elapsed && !subs->running && !subs->early_playback_start) {
13981406
subs->period_elapsed_pending = 1;
13991407
period_elapsed = 0;
14001408
}
@@ -1448,7 +1456,8 @@ static int snd_usb_substream_playback_trigger(struct snd_pcm_substream *substrea
14481456
prepare_playback_urb,
14491457
retire_playback_urb,
14501458
subs);
1451-
if (cmd == SNDRV_PCM_TRIGGER_START) {
1459+
if (!subs->early_playback_start &&
1460+
cmd == SNDRV_PCM_TRIGGER_START) {
14521461
err = start_endpoints(subs);
14531462
if (err < 0) {
14541463
snd_usb_endpoint_set_callback(subs->data_endpoint,

0 commit comments

Comments
 (0)