[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
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.