The Linux Kernel Mailing List
 help / color / mirror / Atom feed
* [PATCH v3] ALSA: usb-audio: Fix boot-time audio stuttering for USB Audio device
@ 2026-07-28 11:13 Zhang Heng
  2026-07-28 16:32 ` Takashi Iwai
  2026-08-16 16:01 ` Michal Pecio
  0 siblings, 2 replies; 3+ messages in thread
From: Zhang Heng @ 2026-07-28 11:13 UTC (permalink / raw)
  To: perex, tiwai, kees, chengordon326, jussi, hulianqin, i, g,
	cryolitia, pav
  Cc: linux-sound, linux-kernel, Zhang Heng

This USB Audio device (0x1e0b:0xd01e) exhibits audio stuttering
during boot when playing audio. Once the system is fully booted,
playback is normal.

The device reports its isochronous endpoints with the Asynchronous
sync type (bmAttributes = 0x03), which causes the driver to
calculate nurbs = min(max_urbs, ...) = 3, providing only ~16ms
of buffering. During boot, the higher system scheduling jitter
(e.g., from init scripts, device enumeration, and driver probing)
can exceed this buffer depth, causing audible stuttering.

This patch adds a device-specific quirk (QUIRK_FLAG_PLAYBACK_URB_FIXUP)
that applies two changes for this device:
1. Forces nurbs to MAX_URBS (12), providing sufficient buffering
2. Sets URB_ISO_ASAP flag for more consistent xHCI scheduling

Both changes are required together for stable boot-time playback:
- The larger buffer absorbs scheduling jitter during boot
- URB_ISO_ASAP ensures consistent URB submission timing, preventing
  the xHCI scheduler from introducing variable delays

Test methodology:
- Without patch: reboot and play audio → stuttering audible in all
  tests (reproduced consistently across multiple attempts)
- With nurbs=8 only: occasional minor stuttering observed after
  multiple tests (insufficient buffer depth)
- With full patch (nurbs=12 + URB_ISO_ASAP): reboot and play audio
  → no stuttering observed (tested in 10+ reboot cycles without
  reproducing the issue)

Signed-off-by: Zhang Heng <zhangheng@kylinos.cn>
---
 sound/usb/endpoint.c | 7 ++++++-
 sound/usb/quirks.c   | 3 +++
 sound/usb/usbaudio.h | 8 ++++++++
 3 files changed, 17 insertions(+), 1 deletion(-)

diff --git a/sound/usb/endpoint.c b/sound/usb/endpoint.c
index 24cd7692bd01..54aeac7d087b 100644
--- a/sound/usb/endpoint.c
+++ b/sound/usb/endpoint.c
@@ -1232,7 +1232,10 @@ static int data_ep_set_params(struct snd_usb_endpoint *ep)
 		/* try to use enough URBs to contain an entire ALSA buffer */
 		max_urbs = min((unsigned) MAX_URBS,
 				MAX_QUEUE * packs_per_ms / urb_packs);
-		ep->nurbs = min(max_urbs, urbs_per_period * ep->cur_buffer_periods);
+		if (chip->quirk_flags & QUIRK_FLAG_PLAYBACK_URB_FIXUP)
+			ep->nurbs = MAX_URBS;
+		else
+			ep->nurbs = min(max_urbs, urbs_per_period * ep->cur_buffer_periods);
 	}
 
 	/* allocate and initialize data urbs */
@@ -1256,6 +1259,8 @@ static int data_ep_set_params(struct snd_usb_endpoint *ep)
 			goto out_of_memory;
 		u->urb->pipe = ep->pipe;
 		u->urb->transfer_flags = URB_NO_TRANSFER_DMA_MAP;
+		if (chip->quirk_flags & QUIRK_FLAG_PLAYBACK_URB_FIXUP)
+			u->urb->transfer_flags |= URB_ISO_ASAP;
 		u->urb->interval = 1 << ep->datainterval;
 		u->urb->context = u;
 		u->urb->complete = snd_complete_urb;
diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c
index 40aa40fccb46..2b4e665564d2 100644
--- a/sound/usb/quirks.c
+++ b/sound/usb/quirks.c
@@ -2422,6 +2422,8 @@ static const struct usb_audio_quirk_flags_table quirk_flags_table[] = {
 		   QUIRK_FLAG_GET_SAMPLE_RATE | QUIRK_FLAG_MIC_RES_16),
 	DEVICE_FLG(0x1bcf, 0x2283, /* NexiGo N930AF FHD Webcam */
 		   QUIRK_FLAG_GET_SAMPLE_RATE | QUIRK_FLAG_MIC_RES_16),
+	DEVICE_FLG(0x1e0b, 0xd01e, /* Generic USB Audio Device */
+		   QUIRK_FLAG_PLAYBACK_URB_FIXUP),
 	DEVICE_FLG(0x1ff7, 0x0f81, /* SC13A Webcam */
 		   QUIRK_FLAG_GET_SAMPLE_RATE),
 	DEVICE_FLG(0x2040, 0x7200, /* Hauppauge HVR-950Q */
@@ -2631,6 +2633,7 @@ static const char *const snd_usb_audio_quirk_flag_names[] = {
 	QUIRK_STRING_ENTRY(MIXER_CAPTURE_LINEAR_VOL),
 	QUIRK_STRING_ENTRY(IFB_SILENCE_ON_EMPTY),
 	QUIRK_STRING_ENTRY(MIXER_GET_CUR_BROKEN),
+	QUIRK_STRING_ENTRY(PLAYBACK_URB_FIXUP),
 	NULL
 };
 
diff --git a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h
index e26f9092417e..dc1d0c8c9c80 100644
--- a/sound/usb/usbaudio.h
+++ b/sound/usb/usbaudio.h
@@ -254,6 +254,12 @@ extern bool snd_usb_skip_validation;
  *  check being non-fatal and only disabling GET_CUR instead of the whole mixer.
  *  The current volume will then be provided by the internal cache that stores
  *  the last set volume
+ * QUIRK_FLAG_PLAYBACK_URB_FIXUP
+ *  Set URB_ISO_ASAP flag for isochronous URBs and force nurbs to MAX_URBS.
+ *  This is needed for devices that exhibit boot-time audio stuttering due
+ *  to insufficient buffer depth combined with xHCI scheduling variability.
+ *  The larger buffer (MAX_URBS = 12, ~64ms) absorbs system scheduling
+ *  jitter during boot, while URB_ISO_ASAP ensures consistent xHCI scheduling.
  */
 
 enum {
@@ -288,6 +294,7 @@ enum {
 	QUIRK_TYPE_MIXER_CAPTURE_LINEAR_VOL	= 28,
 	QUIRK_TYPE_IFB_SILENCE_ON_EMPTY		= 29,
 	QUIRK_TYPE_MIXER_GET_CUR_BROKEN		= 30,
+	QUIRK_TYPE_PLAYBACK_URB_FIXUP		= 31,
 /* Please also edit snd_usb_audio_quirk_flag_names */
 };
 
@@ -324,5 +331,6 @@ enum {
 #define QUIRK_FLAG_MIXER_CAPTURE_LINEAR_VOL	QUIRK_FLAG(MIXER_CAPTURE_LINEAR_VOL)
 #define QUIRK_FLAG_IFB_SILENCE_ON_EMPTY		QUIRK_FLAG(IFB_SILENCE_ON_EMPTY)
 #define QUIRK_FLAG_MIXER_GET_CUR_BROKEN		QUIRK_FLAG(MIXER_GET_CUR_BROKEN)
+#define QUIRK_FLAG_PLAYBACK_URB_FIXUP		QUIRK_FLAG(PLAYBACK_URB_FIXUP)
 
 #endif /* __USBAUDIO_H */
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 3+ messages in thread

* Re: [PATCH v3] ALSA: usb-audio: Fix boot-time audio stuttering for USB Audio device
  2026-07-28 11:13 [PATCH v3] ALSA: usb-audio: Fix boot-time audio stuttering for USB Audio device Zhang Heng
@ 2026-07-28 16:32 ` Takashi Iwai
  2026-08-16 16:01 ` Michal Pecio
  1 sibling, 0 replies; 3+ messages in thread
From: Takashi Iwai @ 2026-07-28 16:32 UTC (permalink / raw)
  To: Zhang Heng
  Cc: perex, tiwai, kees, chengordon326, jussi, hulianqin, i, g,
	cryolitia, pav, linux-sound, linux-kernel

On Tue, 28 Jul 2026 13:13:09 +0200,
Zhang Heng wrote:
> 
> This USB Audio device (0x1e0b:0xd01e) exhibits audio stuttering
> during boot when playing audio. Once the system is fully booted,
> playback is normal.
> 
> The device reports its isochronous endpoints with the Asynchronous
> sync type (bmAttributes = 0x03), which causes the driver to
> calculate nurbs = min(max_urbs, ...) = 3, providing only ~16ms
> of buffering. During boot, the higher system scheduling jitter
> (e.g., from init scripts, device enumeration, and driver probing)
> can exceed this buffer depth, causing audible stuttering.
> 
> This patch adds a device-specific quirk (QUIRK_FLAG_PLAYBACK_URB_FIXUP)
> that applies two changes for this device:
> 1. Forces nurbs to MAX_URBS (12), providing sufficient buffering
> 2. Sets URB_ISO_ASAP flag for more consistent xHCI scheduling
> 
> Both changes are required together for stable boot-time playback:
> - The larger buffer absorbs scheduling jitter during boot
> - URB_ISO_ASAP ensures consistent URB submission timing, preventing
>   the xHCI scheduler from introducing variable delays
> 
> Test methodology:
> - Without patch: reboot and play audio → stuttering audible in all
>   tests (reproduced consistently across multiple attempts)
> - With nurbs=8 only: occasional minor stuttering observed after
>   multiple tests (insufficient buffer depth)
> - With full patch (nurbs=12 + URB_ISO_ASAP): reboot and play audio
>   → no stuttering observed (tested in 10+ reboot cycles without
>   reproducing the issue)
> 
> Signed-off-by: Zhang Heng <zhangheng@kylinos.cn>

Looks a bit like voodoo, but better than vanilla, as it seems.
Applied to for-next branch now.


thanks,

Takashi


^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [PATCH v3] ALSA: usb-audio: Fix boot-time audio stuttering for USB Audio device
  2026-07-28 11:13 [PATCH v3] ALSA: usb-audio: Fix boot-time audio stuttering for USB Audio device Zhang Heng
  2026-07-28 16:32 ` Takashi Iwai
@ 2026-08-16 16:01 ` Michal Pecio
  1 sibling, 0 replies; 3+ messages in thread
From: Michal Pecio @ 2026-08-16 16:01 UTC (permalink / raw)
  To: Zhang Heng
  Cc: perex, tiwai, kees, chengordon326, jussi, hulianqin, i, g,
	cryolitia, pav, linux-sound, linux-kernel, linux-usb

Hi,

Adding linux-usb.

On Tue, 28 Jul 2026 19:13:09 +0800, Zhang Heng wrote:
> This USB Audio device (0x1e0b:0xd01e) exhibits audio stuttering
> during boot when playing audio. Once the system is fully booted,
> playback is normal.

Weird, your thread runs horribly slowly (preempted by something despite
spin_lock_irqsave held by xhci-hcd?) during those URB submissions. It's
first time I actually see this warning:

[    9.654586] xhci_hcd 0000:03:00.3: Frame ID 644 (reg 5154, index 13) beyond range (645, 1539)
[    9.654589] xhci_hcd 0000:03:00.3: Ignore frame ID field, use SIA bit instead
[    9.655053] xhci_hcd 0000:03:00.3: Frame ID 644 (reg 5158, index 14) beyond range (645, 1539)
[    9.655055] xhci_hcd 0000:03:00.3: Ignore frame ID field, use SIA bit instead

If packet 14 was scheduled for frame 644, packet 0 must have been
frame 643 i.e. uframe 5144 (should be frame aligned). So packet 14 was
uframe 5158 - it was only being written to HW while it was already
due for execution, some 2ms after usb_submit_urb() began. ???

URB execution won't even start until all packets are written - we do
take care to queue URBs atomically. Initial part of this URB (before
the warnings) will complete with -EXDEV status due to blatant isoc
scheduling threshold violation, but the rest (with SIA bits) will be
delayed by HW and completed normally after submission finishes.

The same may happen to the next URB if the condition which caused this
persists, and moreover, the next URB may be scheduled with a gap after
the previous one.

IDK how snd-usb-audio would react to such a mess. It is believed, at
least by the USB subsystem, that drivers expect contiguously submitted
URBs to execute in contiguous service intervals, without gaps.

FYI, a lot of this xhci-hcd logic is considered broken and goes out
the window in v7.3. I'm curious if you could test how things work on
usb-next without (and maybe also with) your workaround code.

https://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb.git/log/?h=usb-next

This removes the automatic conversion to SIA/ASAP and insertion of gaps
between URBs, so that the initial URB will likely wholly complete with
-EXDEV and the next one will be scheduled immediately after it.

Again, what snd-usb-audio will think about it IDK, but usb-next mostly
works for me in my test (one remaining exception I'm trying to fix).

> The device reports its isochronous endpoints with the Asynchronous
> sync type (bmAttributes = 0x03), which causes the driver to
> calculate nurbs = min(max_urbs, ...) = 3, providing only ~16ms
> of buffering. During boot, the higher system scheduling jitter
> (e.g., from init scripts, device enumeration, and driver probing)
> can exceed this buffer depth, causing audible stuttering.

Not sure what causes it, xhci-hcd holds a spin_lock_irqsave() during
the whole submission, so I think it shouldn't get preempted.

> This patch adds a device-specific quirk (QUIRK_FLAG_PLAYBACK_URB_FIXUP)
> that applies two changes for this device:
> 1. Forces nurbs to MAX_URBS (12), providing sufficient buffering

I actually wonder why snd-usb-audio seems to allocate only one URB per
period and then submit URBs shorter than a period. Doesn't this mean
that all URBs may be busy without covering the whole playback buffer,
and then newly written samples have nowhere to go until one completes?

This seems to increase risk of URB queue underrun, though TBH I tried
increasing 'nurbs' and I haven't seen much practical difference running
with very low latency like 2x250us or 2x500us.

Note: on USB 3.1 and newer such settings may only work on usb-next.

> 2. Sets URB_ISO_ASAP flag for more consistent xHCI scheduling

URB_ISO_ASAP or xHCI SIA do the opposite of consistency - they cause
execution to be delayed until the URB is written to the HW and the HW
reaches it.

Non-ASAP submissions are scheduled contiguously and possibly complete
with -EXDEV if submitted too late. Only after the last completion of
the last remaining URB returns, will the next URB be scheduled
separately and discontiguously, to execute in some (near) future.
Again, this is documented usb_submit_urb() rule and it's believed that
drivers expect it. It's how OHCI/UHCI/EHCI drivers work.

Using ASAP is a known workaround for the old xhci-hcd bugs, similar
patches have been sent to linux-usb, that's why it's being fixed. But
IDK if usb-next will solve your bizarre edge case out of the box.

Regards,
Michal

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2026-08-16 15:59 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-28 11:13 [PATCH v3] ALSA: usb-audio: Fix boot-time audio stuttering for USB Audio device Zhang Heng
2026-07-28 16:32 ` Takashi Iwai
2026-08-16 16:01 ` Michal Pecio

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox