mirror of
https://github.com/torvalds/linux.git
synced 2026-09-23 05:04:02 +02:00
ALSA: usb-audio: Fix boot-time audio stuttering for USB Audio device
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> Link: https://patch.msgid.link/20260728111309.1271834-1-zhangheng@kylinos.cn Signed-off-by: Takashi Iwai <tiwai@suse.de>
This commit is contained in:
parent
46a6393e96
commit
b7adaa94e3
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -2415,6 +2415,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 */
|
||||
|
|
@ -2624,6 +2626,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
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user