Watch
1
0
Fork
You've already forked SouveraineOS
0

task-39: retract the HiFi-capture-is-dead finding

HiFi captures fine - 204136 nonzero, peak 32726 - once the channel map is
clean. The zeros were stale SLIM map state, which PAF/audio.md already
documents as the alternation law and the post-call unmapped-leg bug, and the
TX7 poke used to "test the decimator" recreated that bug on all three AIFs.
Device is back on HiFi; the Voice Call workaround is reverted.
This commit is contained in:
Fimeg 2026-08-02 08:35:03 -04:00
commit a711ce48cd

View file

@ -136,81 +136,40 @@ pipewire, pipewire-audio and wireplumber — while the device is in fact running
pipewire, pipewire-pulse and wireplumber. Reconcile which is true before
building policy on either.
## The HiFi profile captures pure silence (measured 2026-08-02)
## RETRACTED — "HiFi capture is dead" was wrong (2026-08-02)
**`HiFi` capture is dead, and not subtly: 92133 frames, peak `0`.** Exactly
zero, not a low level — the stream runs and the ADC delivers nothing. This is
why STT on the keyboard has no microphone.
**This section previously concluded that `HiFi` capture is structurally silent
and that the DMIC needs the Q6 voice session. Both claims are false.** With the
channel map cleaned up, HiFi capture reads **235520 frames, 204136 nonzero,
peak 32726** through its normal `DMIC4 -> DEC5 -> TX5 -> SLIMBUS_0_TX ->
hw:0,1` route. Speaker and mic both work on `HiFi`; the
`Voice Call (Mic, Speaker)` workaround is not needed and was reverted.
The codec routing in `HiFi` is *correct*, which is what makes it a real bug
rather than a missing mixer line:
**What actually happened, and it is already documented in `PAF/audio.md`:**
DMIC MUX5 = DMIC4 CDC_IF TX5 MUX = DEC5 ADC MUX5 = DMIC
DEC5 Volume = 84 AIF1_CAP Mixer SLIM TX5 = on
MultiMedia2 Mixer SLIMBUS_0_TX = on (front end, on in both profiles)
- The zeros were **stale SLIM channel-map state**, not a missing route. audio.md
names both mechanisms: the *alternation law* ("a SLIM TX capture produces
samples only when its channel map differs from the previous capture session's
map; re-opening with the identical map always reads zeros") and the
post-call leak where "TX5 and TX7 both stayed mapped into `AIF1_CAP`,
SLIM_0_TX carried two channels into a mono front-end, and capture read exact
zeros."
- **The diagnosis then made it worse.** Enabling `AIF1_CAP Mixer SLIM TX7`
alongside TX5 to "test the decimator" recreated that exact two-channel
condition — on all three AIFs — and **no UCM DisableSequence ever unmaps
TX7**, so it persisted. Clearing TX7 and cycling the verb restored capture.
- The "11-control diff" reasoning was therefore measuring my own contamination,
and the elimination of TX5/TX7 as a cause is void.
Forcing the capture onto the **TX7** decimator — the exact chain the call
profile uses (`DMIC MUX7=5`, `CDC_IF TX7 MUX=2`, `DEC7 Volume=124`,
`AIF1_CAP Mixer SLIM TX7=on`) — still yields peak `0`. So it is **not** the
decimator, and not the front-end mixer.
**Method lesson, which is the repo's own standing warning:** this was derived by
diffing mixer state instead of reading `PAF/audio.md`, which had the answer
written down since 2026-07-19. Read the doc first; a confident architecture
built from `amixer` diffs is exactly the failure mode `CLAUDE.md` warns about.
Only **11** mixer controls differ between `HiFi` and `Voice Call (Mic, Speaker)`.
After eliminating the TX5/TX7 pairs, what remains is
`QUAT_TDM_RX_0 Voice Mixer VoiceMMode1` and
`VoiceMMode1 Capture Mixer SLIMBUS_0_TX` — i.e. the DMIC only produces data
while the **Q6 voice session** is up. That is the thing to chase; do not
re-litigate the decimator, it is measured and ruled out.
**Working configuration today: `Voice Call (Mic, Speaker)`.** It carries the
`Both CS35L36 amps, speakerphone` output *and* a live DMIC4 capture, and it
survives a wireplumber restart. That is a workaround, not the answer — it holds
the modem voice path open (`VoiceMMode1`) for ordinary media use, whose power
and call-interaction cost is unmeasured.
**Capture gain belongs in the UCM.** The voice verb sets `DEC7 Volume=124`,
which gives a flat noise floor at rms ~14000 with no speech variation at all;
84 drops it to ~6200. A runtime `amixer cset` does **not** persist — activating
the profile reapplies the UCM value, verified. Whatever gain STT wants has to
land in `souveraine-ucm-blueline`.
## The in-call speaker button routes to a headset (root cause, 2026-08-02)
Casey, observed: an inbound call **defaulted to speakerphone**, and tapping the
speaker button (to *turn on* speakerphone) **switched to headset mode**.
Not mysterious once the ownership is traced:
- `gnome-calls` is the dialer, and its speaker button calls the D-Bus name
`org.mobian_project.CallAudio`.
- That name is owned by upstream **`callaudiod`**
(`/usr/share/dbus-1/services/org.mobian_project.CallAudio.service`,
`Exec=/usr/bin/callaudiod`), which is D-Bus activated on demand.
- **callaudiod cannot route this card.** It switches a sink *port* and needs a
speaker port and an earpiece port on one sink; ACP models UCM devices as one
profile per combination — `Voice Call (Earpiece, Mic)` and
`Voice Call (Mic, Speaker)` — so no sink carries both. `blueline-callaudio-hook`
already says this in a comment; the consequence was never written down.
- So the button asks for a port that does not exist and lands on a headset
route. **The working toggle already exists and nothing in the UI calls it:**
`blueline-callaudio-hook speaker on|off` does direct mixer writes and is
verified working (`speaker: on` / `speaker: off (earpiece)`).
`souveraine-callaudio` ships only the hook — it does **not** contest the D-Bus
name, so callaudiod always wins.
**The fix is a shim that claims `org.mobian_project.CallAudio`** and translates
`EnableSpeaker`/`SelectMode` into the hook's `speaker on|off`. It must be tested
against a real inbound call before it is enabled: this path is phone calls, and
a broken shim loses them entirely.
Until then the manual escape is `sudo blueline-callaudio-hook speaker on`.
Note the default-to-speakerphone half is a *separate* symptom: `apply()` forces
Earpiece deliberately ("enabling Speaker here is what made every call come out
of the loudspeaker with no way back"), and the hook is enabled, active and
unshadowed (`FragmentPath=/usr/lib/systemd/system/...`). So something else put
the card in a speaker profile before or during that call — unreproduced, and it
needs a call to chase.
**Still genuinely open** (unchanged by the above): capture gain lives in the UCM
(`DEC5 Volume 84` for HiFi), runtime `amixer` does not survive profile
activation, and nothing re-arms a stale map automatically — a verb switch that
leaves a leg mapped still costs you the microphone.
### Prior art: this has been attacked before — read the branches first