[BUG] snd-usb-audio: Behringer Flow 8 (1397:050c)
Gordon Chen <[email protected]>
| Newsgroups | org.alsa-project.alsa-devel |
|---|---|
| Message-ID | <CAJxk+sBq4QaqgQF5KjwbLgiSDs0ab8PBrBrErOz7TDX9rWOasQ@mail.gmail.com> |
implicit-feedback playback EP starves permanently after capture packet
errors
Hi Takashi,
I would like to report what looks like a long-standing silent-stall path
in sound/usb/endpoint.c that triggers reliably on the Behringer Flow 8
USB mixer (idVendor=0x1397 idProduct=0x050c, UAC 2.0, high-speed).
Symptom
=======
After 5-35 minutes of continuous playback at 48 kHz, the playback PCM
hw_ptr stops advancing while substream state remains
SNDRV_PCM_STATE_RUNNING. No XRUN reported, no recovery; only a full USB
device-level unbind/bind clears it (jackd / pipewire restart alone is
not sufficient).
The Flow 8 declares an OUT EP 0x01 with implicit feedback from capture
EP 0x81 (Sync EP Interface=2 Altset=1, Implicit Feedback Mode: Yes per
/proc/asound/F8/stream0). The chip currently has no quirk_flags entry in
sound/usb/quirks.c. Tried setting
- QUIRK_FLAG_SKIP_IMPLICIT_FB (no effect; the UAC2 endpoint
companion descriptor explicitly
references the sync EP, so IFB is
wired up by the standard parser
regardless of the quirk)
- QUIRK_FLAG_PLAYBACK_FIRST | QUIRK_FLAG_GENERIC_IMPLICIT_FB
(same as UMC202/204/404HD; no effect)
- QUIRK_FLAG_FORCE_IFACE_RESET (no effect)
None of them addresses the stall.
Evidence (three independent ftrace captures with func_stack_trace)
==================================================================
Each capture covers ~70 ms ending at a STALL_MARKER timestamp written
once a userspace watchdog noticed hw_ptr frozen. In all three captures:
- 60-70 capture URB completion cycles in the 70 ms window
- 0 retire_playback_urb / prepare_outbound_urb /
snd_usb_queue_pending_output_urbs /
snd_usb_endpoint_implicit_feedback_sink calls
- every usb_submit_urb in the window comes from
snd_complete_urb+0x64e (the capture self-resubmit at line 594);
none from snd_usb_queue_pending_output_urbs
Concurrent dmesg shows recurring (rate-limited) lines from pcm.c
around iso frame status reporting:
usb 3-1: frame N active: -18 (iso_frame_desc[N].status = -EXDEV)
In some cases two consecutive frames within a single URB hit -EXDEV in
the same millisecond. dev_dbg_ratelimited hides the true rate, but
ftrace confirms the IFB sink is never being called.
Suspected root cause
====================
In snd_usb_handle_sync_urb(), sound/usb/endpoint.c around line 1784:
for (i = 0; i < in_ctx->packets; i++)
if (urb->iso_frame_desc[i].status == 0)
bytes += urb->iso_frame_desc[i].actual_length;
/*
* skip empty packets. At least M-Audio's Fast Track Ultra stops
* streaming once it received a 0-byte OUT URB
*/
if (bytes == 0)
return;
When Flow 8 returns a capture URB whose every packet has a non-zero
status (recurrent -EXDEV episodes), bytes stays 0 and we return without
calling snd_usb_queue_pending_output_urbs(). The OUT ring loses its
sole IFB-driven feeder and starves forever, while the IN ring keeps
self-resubmitting through snd_complete_urb()'s pipein branch.
So the "skip empty" path that protects M-Audio Fast Track Ultra is, for
Flow 8 -class devices, an unconditional kill switch.
Proposed fix
============
Add an opt-in quirk QUIRK_FLAG_IFB_SILENCE_ON_EMPTY that, when set,
skips the early return and falls through to the existing
next_packet_fifo_enqueue path. The loop already maps each
iso_frame_desc[i].status != 0 to packet_size[i] = 0, so falling through
naturally produces a silence packet, prepare_outbound_urb keeps the OUT
ring alive, and the device rides through the glitch.
Default behaviour is preserved for every existing device including
M-Audio Fast Track Ultra (no quirk -> early return as today). Only
Flow 8 opts in.
Patch attached (0001-...patch).
Tested
======
On CachyOS kernel 7.0.9-1-cachyos (mainline 6.10-derived). The patched
driver has been running on the Flow 8 for [N] hours of continuous
playback. Will report longer soak results once available.
Anything else useful I can provide:
- full lsusb -v 1397:050c
- the three raw ftrace files (~140 KB each around STALL_MARKER)
- usbmon pcap during a stall episode (200 MB segment, can trim)
- /proc/asound/F8/stream0, pcm0p, pcm0c snapshots
Happy to spin the patch differently if you'd prefer a different name,
or default-on with M-Audio opting out, or something else.
Thanks for taking a look.
Best,
Gordon
0001-snd-usb-audio-add-IFB-silence-on-empty-quirk-for-Beh.patch
(text/x-patch, 5.2 KB)
From: Gordon <[email protected]> Date: Sat, 23 May 2026 03:10:00 +0800 Subject: [PATCH] ALSA: usb-audio: add IFB_SILENCE_ON_EMPTY quirk for Behringer Flow 8 The Behringer Flow 8 (1397:050c) is an 8-channel USB mixer that declares OUT EP 0x01 with implicit feedback from capture EP 0x81 via its UAC2 endpoint companion descriptor. After 5-35 minutes of continuous playback, the device occasionally returns a capture URB in which every iso_frame_desc has a non-zero status (-EXDEV bursts, visible as rate-limited "frame N active: -18" lines in dmesg from pcm.c). In that case snd_usb_handle_sync_urb() at endpoint.c counts bytes==0 and falls into the early "skip empty packets" return originally added for M-Audio Fast Track Ultra. As a result the playback EP loses its sole IFB-driven feeder and the OUT ring starves permanently: hw_ptr stops advancing while substream state remains RUNNING. Only USB re-enumeration recovers. Three independent ftrace captures (taken at the moment of stall via a userspace watchdog) consistently show: - 60-70 capture URB completions in the 70ms window before the marker - 0 retire_playback_urb / queue_pending_output_urbs / snd_usb_endpoint_implicit_feedback_sink calls - every usb_submit_urb in the window comes from snd_complete_urb+0x64e (capture self-resubmit), none from the queue_pending_output_urbs path Add a new opt-in quirk QUIRK_FLAG_IFB_SILENCE_ON_EMPTY: when set, the early return is skipped and we fall through to enqueue a packet_info whose packet_size[i] are all 0 (the existing loop already maps status!=0 packets to size 0). prepare_outbound_urb then emits a silence packet, the OUT ring keeps moving, and the device rides through the glitch. The default behaviour (early return) is preserved for all existing devices including M-Audio Fast Track Ultra. Only Flow 8 opts in here. Signed-off-by: Gordon <[email protected]> --- sound/usb/endpoint.c | 12 ++++++++++-- sound/usb/quirks.c | 3 +++ sound/usb/usbaudio.h | 9 +++++++++ 3 files changed, 22 insertions(+), 2 deletions(-) diff --git a/sound/usb/endpoint.c b/sound/usb/endpoint.c index XXXXXXX..XXXXXXX 100644 --- a/sound/usb/endpoint.c +++ b/sound/usb/endpoint.c @@ -1781,8 +1781,16 @@ static void snd_usb_handle_sync_urb(struct snd_usb_endpoint *ep, /* * skip empty packets. At least M-Audio's Fast Track Ultra stops * streaming once it received a 0-byte OUT URB + * + * However, on devices where bytes==0 means every sync-source + * packet errored (e.g. Behringer Flow 8 returning -EXDEV bursts + * for entire capture URBs), an unconditional return starves the + * IFB-fed OUT ring permanently. Such devices set + * QUIRK_FLAG_IFB_SILENCE_ON_EMPTY to fall through and enqueue a + * packet_info with size 0 packets, so playback emits silence + * and the OUT ring keeps moving. */ - if (bytes == 0) + if (bytes == 0 && !(ep->chip->quirk_flags & QUIRK_FLAG_IFB_SILENCE_ON_EMPTY)) return; spin_lock_irqsave(&ep->lock, flags); diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c index XXXXXXX..XXXXXXX 100644 --- a/sound/usb/quirks.c +++ b/sound/usb/quirks.c @@ -2127,6 +2127,8 @@ static const struct usb_audio_quirk_flags_table quirk_flags_table[] = { QUIRK_FLAG_PLAYBACK_FIRST | QUIRK_FLAG_GENERIC_IMPLICIT_FB), DEVICE_FLG(0x1397, 0x0509, /* Behringer UMC404HD */ QUIRK_FLAG_PLAYBACK_FIRST | QUIRK_FLAG_GENERIC_IMPLICIT_FB), + DEVICE_FLG(0x1397, 0x050c, /* Behringer Flow 8 */ + QUIRK_FLAG_IFB_SILENCE_ON_EMPTY), DEVICE_FLG(0x13e5, 0x0001, /* Serato Phono */ QUIRK_FLAG_IGNORE_CTL_ERROR), @@ -2280,6 +2282,7 @@ static const char *const snd_usb_audio_quirk_flag_names[] = { QUIRK_STRING_ENTRY(SKIP_IFACE_SETUP), QUIRK_STRING_ENTRY(MIXER_PLAYBACK_LINEAR_VOL), QUIRK_STRING_ENTRY(MIXER_CAPTURE_LINEAR_VOL), + QUIRK_STRING_ENTRY(IFB_SILENCE_ON_EMPTY), NULL }; diff --git a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h index XXXXXXX..XXXXXXX 100644 --- a/sound/usb/usbaudio.h +++ b/sound/usb/usbaudio.h @@ -195,6 +195,12 @@ extern bool snd_usb_skip_validation; * Set linear volume mapping for devices where the playback volume control * range and value are reported in linear amplitude scale instead of dB. * Overrides QUIRK_FLAG_MIXER_PLAYBACK_MIN_MUTE + * QUIRK_FLAG_IFB_SILENCE_ON_EMPTY + * In implicit feedback mode, when an entire capture URB returns with + * all iso_frame_desc[i].status != 0 (bytes==0), do not silently return + * from snd_usb_handle_sync_urb. Instead fall through and enqueue a + * packet_info containing only size-0 packets, so the OUT ring keeps + * moving (emits silence). Needed by Behringer Flow 8 (1397:050c). */ enum { @@ -227,6 +233,8 @@ enum { QUIRK_TYPE_SKIP_IFACE_SETUP = 26, QUIRK_TYPE_MIXER_PLAYBACK_LINEAR_VOL = 27, QUIRK_TYPE_MIXER_CAPTURE_LINEAR_VOL = 28, + QUIRK_TYPE_IFB_SILENCE_ON_EMPTY = 29, +/* Please also edit snd_usb_audio_quirk_flag_names */ }; #define QUIRK_FLAG(x) BIT_U32(QUIRK_TYPE_ ## x) @@ -259,5 +267,6 @@ enum { #define QUIRK_FLAG_SKIP_IFACE_SETUP QUIRK_FLAG(SKIP_IFACE_SETUP) #define QUIRK_FLAG_MIXER_PLAYBACK_LINEAR_VOL QUIRK_FLAG(MIXER_PLAYBACK_LINEAR_VOL) #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) #endif /* __USBAUDIO_H */ -- 2.45.0