From nobody Mon Jun 8 12:04:11 2026 X-Original-To: bugs@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 4gYrLM5Xdvz6fwHq for ; Mon, 08 Jun 2026 12:04:11 +0000 (UTC) (envelope-from bugzilla-noreply@freebsd.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "R13" (not verified)) by mx1.freebsd.org (Postfix) with ESMTPS id 4gYrLM4xF4z41QR for ; Mon, 08 Jun 2026 12:04:11 +0000 (UTC) (envelope-from bugzilla-noreply@freebsd.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1780920251; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=8xfMFZHYxMKbEbp28XX1iSIziZi2du8r8fnYTQQs8N0=; b=XGp6aUYrNYCzpGCR4ldcbZ3gFQemeSZbkm4UzeWeX8B/uRwAGEPmGiOwKRNO7FFt5Ggr8+ m3RjDWLQl7mEeEsIwTqet7CavHFROFIeT8AfV5SZaBr3fiY9Ber3skQtftYQx8oNxCHR/A OVllLxstucPjkyfe5sgssOheQONcYLCORrP4HaUj69Da2/4/ZqktV7x9+c/xkZ77zzH03g 0RuZcGO3esswdcEGUl+T5ZO9qjbsKOpZCBpAhMHlaJhKLNaIQPPCs8xX9Xiesm4Cg90O3g s8ZLE/hnNJksaYX8PvRwKIL+town29m6Kzd1x15wLa/FIIHFok8sqg8gKjzI0g== ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1780920251; a=rsa-sha256; cv=none; b=g6/cAAmepU+ONBGiJAo/q5+8jksVbMnEaRQrizaJMYcr68TJMSF7SnxylBPvRN5+NEJvo+ 8ZVuhsrxzYtE4kUzVK5nyEyFbz6dOjPKAFnYfUf1Kttci762G8E5/Ai40V7op2WGsWP6o4 +pC0spLi775A7vCNTIfhCu0nJz3NL2eFEM6YHYHxeUm+O+3MO1rDOPI4elokwsqv20VqmG XYXwbCGUZFkk5RNUk+E5NeDx8pFdNx4iTgiw7RlRxzAMnR7e3V40vXbSKWqj9sbWMEiEaX WCljoSHgXrbpfFRi27dgdpE2bFpYY73r326R9EFhlDRul563wiqXp/bvL7WAnQ== ARC-Authentication-Results: i=1; mx1.freebsd.org; none ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1780920251; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=8xfMFZHYxMKbEbp28XX1iSIziZi2du8r8fnYTQQs8N0=; b=tYazjYOvl/2UiVR8aY4Gyr30I5YPS5/xxzx803vCs6dtswFbczW4U7nc9S+P6zg0ry5CDe zVok+PjLqB7MxsMk+geNF0K9Spqg41GHFJthmNjgsOwVTa58RHxejCwuy7tjRtdIjZOmhx TEl9nlMFm50Xdhs8PPTYXGHEPMf8yqr82Kl6bbiA9SeKxk4Qdxh/fRYfx9Rr0b6oy4kJth 62yivBEzvTUXXPGQOaLB7gkEiabnF8FHn07l8u2gOhvZ29caRRXHIYguUbi//pNXW6k7ev NI6ij/VFb0PeUQYYOPAN84P0LEHDL7ggZg/wo4iDj2p480l8c1/kPAWSJiX/MQ== Received: from kenobi.freebsd.org (kenobi.freebsd.org [IPv6:2610:1c1:1:606c::50:1d]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 4gYrLM4Vdlzms1 for ; Mon, 08 Jun 2026 12:04:11 +0000 (UTC) (envelope-from bugzilla-noreply@freebsd.org) Received: from kenobi.freebsd.org ([127.0.1.5]) by kenobi.freebsd.org (8.15.2/8.15.2) with ESMTP id 658C4BHh008563 for ; Mon, 8 Jun 2026 12:04:11 GMT (envelope-from bugzilla-noreply@freebsd.org) Received: (from www@localhost) by kenobi.freebsd.org (8.15.2/8.15.2/Submit) id 658C4BGR008562 for bugs@FreeBSD.org; Mon, 8 Jun 2026 12:04:11 GMT (envelope-from bugzilla-noreply@freebsd.org) X-Authentication-Warning: kenobi.freebsd.org: www set sender to bugzilla-noreply@freebsd.org using -f From: bugzilla-noreply@freebsd.org To: bugs@FreeBSD.org Subject: [Bug 295933] uaudio(4): idle capture stream clobbers active playback sample rate on devices with a shared UAC2 Clock Source - device unusable Date: Mon, 08 Jun 2026 12:04:11 +0000 X-Bugzilla-Reason: AssignedTo X-Bugzilla-Type: new X-Bugzilla-Watch-Reason: None X-Bugzilla-Product: Base System X-Bugzilla-Component: kern X-Bugzilla-Version: 15.0-RELEASE X-Bugzilla-Keywords: X-Bugzilla-Severity: Affects Only Me X-Bugzilla-Who: delleceste@gmail.com X-Bugzilla-Status: New X-Bugzilla-Resolution: X-Bugzilla-Priority: --- X-Bugzilla-Assigned-To: bugs@FreeBSD.org X-Bugzilla-Flags: X-Bugzilla-Changed-Fields: bug_id short_desc product version rep_platform op_sys bug_status bug_severity priority component assigned_to reporter Message-ID: Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="UTF-8" X-Bugzilla-URL: https://bugs.freebsd.org/bugzilla/ Auto-Submitted: auto-generated List-Id: Bug reports List-Archive: https://lists.freebsd.org/archives/freebsd-bugs List-Help: List-Post: List-Subscribe: List-Unsubscribe: Sender: owner-freebsd-bugs@FreeBSD.org List-Id: List-Post: List-Help: List-Subscribe: List-Unsubscribe: List-Owner: Precedence: list MIME-Version: 1.0 https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=3D295933 Bug ID: 295933 Summary: uaudio(4): idle capture stream clobbers active playback sample rate on devices with a shared UAC2 Clock Source - device unusable Product: Base System Version: 15.0-RELEASE Hardware: Any OS: Any Status: New Severity: Affects Only Me Priority: --- Component: kern Assignee: bugs@FreeBSD.org Reporter: delleceste@gmail.com ## TL;DR On a UAC2 device that exposes **one Clock Source entity shared between its playback and capture interfaces**, `uaudio(4)` programs that clock for *bot= h* directions. When playback uses a sample rate from the **44.1 kHz family** (44100 / 88200 / 176400 / 352800 Hz) and the (idle, non=E2=80=91streaming) = capture channel is configured for a **48 kHz=E2=80=91family** default, the capture = channel's `SET_CUR(CUR_SAM_FREQ)` is issued **after** the playback one and **overwrit= es it on the shared clock**. The device's converter then runs at ~48 kHz while= the host streams 44.1 kHz data =E2=86=92 continuous input=E2=80=91FIFO underrun= inside the device =E2=86=92 the DAC repeatedly drops and re=E2=80=91acquires USB streaming lock (audibl= e dropouts; front=E2=80=91panel "play/idle" flicker several times per second). * The **48 kHz family is unaffected** =E2=80=94 both directions then reques= t 48000, so there is no conflict on the shared clock. * The **same device works perfectly under Linux** (`snd-usb-audio`), which = does not let an idle capture stream reprogram the clock used by active playbac= k. * A device with **no capture interface** (Cambridge Audio DacMagic 100) nev= er shows the problem on the same FreeBSD host. The host side is verifiably healthy throughout (`underruns 0`, channel stays `RUNNING`); the fault is the **wrong clock rate programmed into the device*= *, not data starvation. --- ## Affected component and environment | Item | Value | |------|-------| | Driver | `sys/dev/sound/usb/uaudio.c` (`uaudio(4)` / `snd_uaudio.ko`) | | OS (reproduced on) | FreeBSD **15.1=E2=80=91RC1**, amd64, `GENERIC` (`releng/15.1-n283533`) | | Expected to affect | All branches; the code paths below are long=E2=80=91= standing | | Host controller | Intel Sunrise Point=E2=80=91LP xHCI, USB High=E2=80=91S= peed (480 Mbps) | | Reference player | MPD 0.24.12, OSS output to `/dev/dsp0`, `dev.pcm.0.bitperfect=3D1` | ### Device used to reproduce | Item | Value | |------|-------| | Device | OKTO RESEARCH **DAC8 STEREO** (D/A only =E2=80=94 no analog inpu= ts) | | USB IDs | idVendor `0x152a`, idProduct `0x88c5`, bcdDevice `0x0160` | | Firmware | Thesycon UAC2 (`bInterfaceProtocol 0x20`), `bcdUSB 0x0200` | | Link | USB High=E2=80=91Speed | > Note: although the DAC8 has **no physical inputs**, its USB descriptor st= ill > advertises a UAC2 **capture interface** (Interface 2) =E2=80=94 common bo= ilerplate in > Thesycon/XMOS reference firmware. It is this *vestigial, never=E2=80=91st= reaming* > capture interface that triggers the bug. ## Root cause =E2=80=94 measured ### 1. Two `SET_CUR` calls to the shared clock, capture wins With `sysctl hw.usb.uaudio.debug=3D15` (GENERIC builds `options USB_DEBUG`)= , at the start of 44.1 kHz playback: ``` uaudio_chan_set_param_speed: Selecting alt 6 uaudio_chan_set_param_speed: Selecting alt 7 uaudio20_set_speed: ifaceno=3D0 clockid=3D41 speed=3D44100 <-- playback= sets shared clock to 44100 uaudio20_set_speed: ifaceno=3D0 clockid=3D41 speed=3D48000 <-- capture = default 48000 then overwrites it ``` Same `clockid=3D41`. The second call wins; the device clock ends at 48 kHz. ### 2. The capture channel is idle, yet it owns the clock `cat /dev/sndstat` with `hw.snd.verbose=3D2`, during 44.1 kHz playback: ``` [dsp0.play.0]: spd 44100, fmt 0x00201000, flags ... interrupts , underruns 0, feed , ready [dsp0.record.0]: spd 48000, fmt 0x00200010/0x00201000, flags 0x00000000 <= -- NOT running, but holds 48000 ``` The record channel has flags `0x00000000` (not `RUNNING`) =E2=80=94 it is n= ot streaming a single byte =E2=80=94 yet its 48000 Hz configuration is what sits on the = shared clock. ### 3. The device confirms it is running at 48 kHz, not 44.1 kHz The playback OUT endpoint is asynchronous with an explicit feedback IN endp= oint (`0x81`, Q16.16 at High=E2=80=91Speed). While the host streams 44100: ``` uaudio_chan_play_sync_callback: Value =3D 0x0006000a uaudio_chan_play_sync_callback: Comparing 48001 Hz :: 44100 Hz ``` `0x0006000a` in 16.16 =3D 6.0001 samples/microframe =C3=97 8000 =3D **~4800= 1 Hz**. The device's converter is clocked at 48 kHz while being fed 44.1 kHz frames =E2= =86=92 it drains ~3900 samples/s faster than it is filled =E2=86=92 underrun/mute/rel= ock cycle. ### 4. It is a host/driver problem, not the device firmware * The **same device, cable and host play the 44.1 kHz family perfectly under Linux** (`snd-usb-audio`). Linux programs the shared clock from the active playback stream and does not let the idle capture stream override it. * A DAC with **no capture interface** (DacMagic 100) is stable at every rat= e on the same FreeBSD host. --- ## Relevant code paths Line numbers are approximate, from FreeBSD **15.1=E2=80=91RC1** `sys/dev/sound/usb/uaudio.c`. 1. **`uaudio_configure_msg()` (~line 1539)** =E2=80=94 runs on the USB expl= ore task and unconditionally reconfigures *both* directions of every child: ```c for (i =3D 0; i !=3D UAUDIO_MAX_CHILD; i++) { uaudio_configure_msg_sub(sc, &sc->sc_play_chan[i], PCMDIR_PLAY); uaudio_configure_msg_sub(sc, &sc->sc_rec_chan[i], PCMDIR_REC); } ``` 2. **`uaudio_configure_msg_sub()` (~line 1352)** =E2=80=94 on `CHAN_OP_STAR= T` it selects the alt setting and then, for UAC2, programs the sample rate by iterating every clock id flagged for the channel's direction and calling `uaudio20_set_speed()` (~line 1449): ```c } else if (sc->sc_audio_rev >=3D UAUDIO_VERSION_20) { for (x =3D 0; x !=3D 256; x++) { if (dir =3D=3D PCMDIR_PLAY) { if (!(sc->sc_mixer_clocks.bit_output[x/8] & (1u << (x%8)))) continue; } else { if (!(sc->sc_mixer_clocks.bit_input[x/8] & (1u << (x%8)))) continue; } if (uaudio20_set_speed(sc->sc_udev, sc->sc_mixer_iface_no, x, chan_alt->sample_rate)) DPRINTF("setting of sample rate failed! (continuing anyway)\= n"); } } ``` Because clock id 41 is set in **both** `bit_output` and `bit_input` (shared clock =E2=80=94 see `uaudio20_mixer_find_clocks_sub()` ~line 485= 8), the REC pass reprograms the very clock the PLAY pass just set. 3. **Asynchronous feedback handling =E2=80=94 secondary issue.** In `uaudio_chan_play_sync_callback()` (~line 2255) the explicit feedback endpoint value is only turned into a rate correction when there is **no** capture channel (`if (ch->priv_sc->sc_rec_chan[i].num_alt =3D=3D 0)`, ~line 2306= ), and the feedback transfer is not even submitted when a capture channel exists (~line 2332). For a device whose capture interface never streams, this m= eans the explicit feedback endpoint is ignored, so there is no closed=E2=80= =91loop correction to mask a mis=E2=80=91programmed clock either. --- ## Proposed fix (direction) **Primary =E2=80=94 do not let an idle/secondary direction reprogram a cloc= k that is shared with the active streaming direction.** The active stream must own the shared Clock Source. Concretely, in the UAC2 rate=E2=80=91setting loop of `uaudio_configure_msg_sub()`, before issuing `SET_CUR` to a clock id, skip = it if that clock id is also referenced by the *other* direction's channel that is currently `RUNNING` at a different rate. Equivalently: only program a clock= for a channel that is the one actually transitioning to `RUNNING`, and never let a non=E2=80=91running channel push its default rate onto a clock another runn= ing channel depends on. UAC2 constraint to respect: a single Clock Source physically cannot serve t= wo different rates simultaneously, so when both directions stream concurrently they must already agree on one rate; that concurrent case needs its own coherent handling (e.g. the second stream adopts the first's rate). The common failu= re mode here, however, is purely an **idle** capture stream forcing its defaul= t =E2=80=94 which should never override active playback. **Secondary (optional, matches Linux behaviour).** Consider honouring the device's explicit asynchronous feedback endpoint even when a capture interf= ace is present, rather than only when `sc_rec_chan[i].num_alt =3D=3D 0`. Not re= quired if the clock is programmed correctly, but it brings `uaudio` in line with `snd-usb-audio` for async devices. ### Diagnostic stopgap used to confirm the hypothesis (NOT proposed for upstream) To verify the diagnosis, the reporter dropped the capture channels for this= one device, right after `uaudio_chan_fill_info()` in `uaudio_attach()`: ```c /* local diagnostic only =E2=80=94 confirms the shared-clock hypothesis */ if (uaa->info.idVendor =3D=3D 0x152a && uaa->info.idProduct =3D=3D 0x88c5) { for (i =3D 0; i !=3D UAUDIO_MAX_CHILD; i++) sc->sc_rec_chan[i].num_alt =3D 0; } ``` Result: the OKTO then enumerates play=E2=80=91only, the shared clock follow= s playback, and **44.1 kHz locks cleanly and bit=E2=80=91perfect** (`underruns 0`, gap= =E2=80=91free, stable front panel). This is offered only as confirmation of the root cause; the r= eal fix should be the general clock=E2=80=91ownership change above, which prese= rves capture for devices that genuinely record. --- ## Reproduction 1. FreeBSD 15.1=E2=80=91RC1, `uaudio(4)`, a UAC2 device whose playback and = capture interfaces share one Clock Source, on a High=E2=80=91Speed port. 2. Play bit=E2=80=91perfect audio at any **44.1 kHz=E2=80=91family** rate t= o `/dev/dsp0` (e.g. MPD OSS output, `dev.pcm.0.bitperfect=3D1`, no rate enforcement). =E2=86=92 device drops/re=E2=80=91acquires lock continuously; `sndstat` = shows the play channel `RUNNING` with `underruns 0`, and the record channel idle at a 48 kHz=E2=80=91family rate. 3. Play any **48 kHz=E2=80=91family** rate =E2=86=92 stable. 4. Same machine/cable/port under Linux (`snd-usb-audio`) =E2=86=92 44.1 kHz= plays perfectly. --- --=20 You are receiving this mail because: You are the assignee for the bug.=