PAF becomes saf/device (history kept), STATE.md dissolves into saf/state.md with the dated era archived, the substrate SAF moves up from souveraine, and every agreement points at saf/INDEX.md and nowhere else. one map, nothing to remember
12 KiB
HANDOFF — Put the Pixel 3 audio to bed (Fable, evening 2026-07-19)
Historical handoff. The current contract is
../../audio.md; this file is retained as dated evidence and may describe work that was later completed.
We are this close. Mic captures nonzero on every boot now, both loudspeakers fire, modem connects. What's left: reinstate PipeWire (the reason it was banned is gone), keep the mic/speaker gains, and make the phone call-ready (two-way call audio). This doc is your orders, not a draft to critique.
⚠️ READ THIS FIRST — the references are ALL local, and they are VAST
Casey's #1 instruction for this handoff: stop and internalize that nearly every fact you could want is already on this drive — every bring-up attempt, every Android LIVE capture, every modem trace, every regmap dump, the full Android vendor mixer map, the pmOS known-good config, the raw partition images. Even the outgoing session (me) barely knew this reference surface existed and wasted hours re-deriving things that were sitting in a file. Do not repeat that. Before you form any theory or run any experiment, grep/read the local references. If you catch yourself reverse-engineering ALSA/UCM/modem internals from scratch, you have already failed — go find the file.
The reference surface (4 repos, ~70 GB, all local)
1. ~/Projects/Pixel3Arch/PAF/ — the then-current base of truth. Doctrine + current state.
audio.md— the entire audio saga. THE ALTERNATION LAW, THE BOOT RACE, speaker routing provenance, mic transport. Read top-to-bottom.audio-2026-07-19-LIVE-reconciliation.md— supersedes the top of audio.md. LIVE Android register captures (recorder vs voice call), the ADM-usecase hypothesis, and the airplane/radio-mode wedge warning (some historical "wedges" were mode toggles, not driver faults — rule mode out before logging any wedge).HANDOFF-mic-unpin.md— the un-pin experiment (corrected header; read audio.md "THE BOOT RACE" first).modem.md,pmos_fix_plan.md,qcril_*_capture.md,modem_dt_rf_analysis_*.md,tz_listener_archaeology.md,secure_load_tz_frontier.md,qrtr_tools_reference.md,tier1_los_vs_mainline_diff.md— the modem bring-up archaeology. Deep. Detailed. Read before touching the modem.evidence/,captures/— raw traces (e.g. glink).
2. ~/Projects/PostMarketOS-Blueline/ — the pmOS port + all Android captures.
android-reference/— the gold.mixer_paths_tavil_b1.xml(the FULL Android vendor route map — every named route:handset,speaker,voice-handset,voice-speaker, all mics), CS35L36 regmaps (idle/playing), tavil PGD dumps,wcd9xxx_core-android-LIVE-*.txt(recording AND voicecall, captured 2026-07-19),wcd934x-android-ground-truth.md.android-capture-2026*— nine per-day Android trace dirs.PAF/— a second full modem-trace tree (android_modem_bringup_capture.md,qcril_full_provisioning.md,qcril_online_sequence.md,modem_consumer_chain_*.md,los-mss-translated.c).HANDOFF.md(80 KB),PROGRESS.md,START-HERE.md,README.md.
3. ~/Projects/pixel3-downstream-audio/ — the Android HAL source.
techpack/audio/ — downstream q6adm.c, q6voice*.c, ASoC machine driver.
This is what the working Android side actually runs; diff mainline behavior
against it when a route/topology question comes up.
4. ~/pixel3-backup/ (in $HOME, not Projects) — raw partition dumps + pmOS config.
modem_a.img, persist.img, vendor_a.img, system_a.img (raw Android),
plus pmos-20260703/ — the known-good pmOS config backup the speaker
routing was lifted from (see the memory note: this is the source of truth for
working modem/cellular + speaker config; restore from here, never guess).
If a route value, a mixer control, a modem sequence, or a UCM verb is in
question — it is decoded in one of the above. Cite file:line. Do not invent.
CURRENT STATE (verified live this session, phone at WiFi 10.10.20.234, USB 172.16.42.1)
Kernel: 7.1.1-sdm845-gcd7758eaeca1 (mic-race-fix, HEAD). Boot-race fix
LIVE and working — MICDBG boot sysclk hold armed fires in dmesg, capture open
joins a live codec (users=2 skip) instead of racing bring-up.
Mic — WORKING. parecord --device=blueline_mic yields nonzero PCM every
boot. Deterministic now (kernel sysclk hold from wcd934x_comp_probe).
Speakers — WORKING. Both CS35L36 amps armed, correct route (measured live):
Left/Right AMP Enable = on, BOOST = on, PCM Volume = 700,
Left Channel Mux = RX1 (top), Right Channel Mux = RX2 (bottom). Matches the
07-12/07-13 known-good. The handset (earpiece) vs speaker distinction is a
single control: Right AMP Enable — Android's handset route runs the top
amp only (R AMP Enable=0, low gain); speaker runs both. Decoded from
mixer_paths_tavil_b1.xml.
Modem — connects. Registered (Fido, MNC 720). Call signaling works. Note:
saw a transient roaming reject (MNC 490, roaming-not-allowed) mid-session —
that's network, not us, and consistent with the reconciliation doc's mode/radio
caveat. Rule mode out before chasing modem "faults."
Calls — NO AUDIO yet. q6voiced is now enabled + running holding
hw:0,2 (the live VoiceMMode1 PCM — NOT device 5 as the staged conf wrongly
said; fixed this session in both /etc/q6voiced.conf on-device and
pkgs/q6voiced/q6voiced.conf). But it logs Failed to open tx/rx: Invalid argument on call-start because nothing applies the VoiceCall route. See below.
THE TWO HOLDS ON THE MIC (know the difference)
- PA loopback pin (
90-blueline-alsa.pa, modules 20/21): null-sink +module-loopback source=blueline_mic ... source_dont_move sink_dont_move. Holds the mic open from boot. Nobody else does this — verified via GitHub code search: no working sdm845 phone (OnePlus 6 enchilada/fajita, holioka) pins the mic. It's a boot-race workaround. - Kernel sysclk hold (today's fix, in
wcd934x_comp_probe): permanent sysclk ref + MICB2 bias from probe. Honest hack — pins the winning-boot state so every boot wins.
With the kernel hold in place, the PA pin is very likely now redundant. The
un-pin test was never run on a race-won boot. Running it de-hacks the daily
driver. See HANDOFF-mic-unpin.md for the exact procedure (unload loopback,
same-map reopen ×2, watch for CHAN_CTRL remove ret=0 + fresh DEF_ACT_CHAN).
If reopen is nonzero → delete the PA pin, keep the kernel hold. If zero → keep
both, root-cause stays open.
PIPEWIRE — the ban is lifted; bring it back
Why it was removed (da53133): the only documented reason was the
premature capture source — wireplumber published the mic before ALSA
capture was nonzero (the boot race). PAF audio.md:516/590. PipeWire playback
was never the problem — 8920c3c had PW playing on glass fine once the sink
was pinned S16LE + RW + no-mmap (the DSP lies about S24/mmap; both play silent).
Why it's safe now: the boot race is fixed in-kernel — capture is nonzero from boot, deterministically. The precondition PipeWire failed on is satisfied. Casey has explicitly cleared reinstating it.
PipeWire task
- Reinstall the full PipeWire + WirePlumber stack. Note the current shims:
pkgs/pipewire-abi-provider,pkgs/pulse-native-provider(they provide the PW ABI without a server — you're replacing that arrangement with a real server, so reconcile/remove the shims cleanly, don't leave a half state). - Re-apply the S16LE playback rule (the wireplumber
51-blueline-audio-s16.confthat8920c3ccreated andda53133deleted — recover it from git:git show 8920c3c). Without it, playback is silent. - Verify on the fixed kernel, in this order, and DO NOT proceed past a failure:
- mic still nonzero via PW (
pw-record) — this is the thing PW broke before; - speakers play via PW (
pw-playa chime) — both top+bottom; - the mic source is NOT published dead at boot (the old failure mode).
- mic still nonzero via PW (
- Keep the new features intact: the QS audio service fix
(
Audio.qml—blueline_micdescription matcher), the mic/speaker gains, the speaker Channel Mux routing.
Ponytail guard: PipeWire is the bigger hammer. Its payoff is that callaudiod can then route calls via UCM — which is the whole reason we want it back. If PW re-breaks the mic despite the race fix, fall back to the raw-PA call hook (below) rather than fighting it — the mic is non-negotiable.
MAKE IT CALL-READY (the actual finish line)
The working sdm845 reference (OnePlus 6, chayleaf/dotfiles
system/hardware/oneplus-enchilada/default.nix, and syntheit/nix
hosts/fajita) routes call audio through UCM (consumed by PipeWire) +
callaudiod + q6voiced tied to ModemManager. Key facts pulled from it:
q6voiced hw:0,6there (per-board PCM number; ours ishw:0,2— always read/proc/asound/pcm, never copy the number).- q6voiced is
After=/wantedBy=ModemManager.service. alsa-ucm-confis shipped andalsa-ucm-meld = true— UCM is the routing layer. callaudiod flips the verb on call state; q6voiced carries the audio.
The call chain we need
gnome-calls → callaudiod → UCM VoiceCall verb → q6voiced carries modem audio
Both middle links are currently broken/absent on our raw-PA setup:
- callaudiod is installed and running but has zero log activity — it routes via PipeWire ports/profiles, which don't exist under raw-PA. PipeWire back gives callaudiod something to route with. This is the clean path and the reason PipeWire is worth the risk.
- UCM VoiceCall verb exists (
Google/blueline/VoiceCall.conf) but has the samehw:0,5bug (PlaybackPCM/CapturePCM "hw:${CardId},5") — fix to,2. Its EnableSequence is the real voice route:SLIMBUS_0_RX Voice Mixer VoiceMMode1=1,VoiceMMode1 Capture Mixer SLIMBUS_0_TX=1. Cross-check the RX/TX and DMIC/DEC selections againstmixer_paths_tavil_b1.xmlvoice-handset/voice-speakerand the downstreamq6voice*.cbefore trusting them. - UCM currently fails to load via
alsaucm -c G3(-2). Under raw-PA this is moot (PA doesn't consume UCM). Once PipeWire+wireplumber drive UCM this must actually resolve — verify wireplumber opens the card's UCM cleanly. (The card driver/id:id=G3, longnameGoogle Pixel 3, ASoC machinemsm-snd-sdm845; conf.d lives inconf.d/sdm845/. If UCM won't match, this driver-name-vs-dir mapping is the first suspect — but let a real UCM client, not the bare CLI, be your test.)
Definition of done — ALL MET 2026-07-29
- PipeWire back, mic + both speakers verified on the fixed kernel. Done 2026-07-19.
- Place a real call (Casey → his wife). Two-way audio. Downlink out the
speaker, uplink from the mic, on the call. Done 2026-07-29 — incoming
call answered, both directions confirmed by ear at both ends. Five defects
had to fall first; see
PAF/audio.md, 2026-07-29. - On hangup, audio reverts to normal HiFi (no stuck voice route). Done — and note the reverse was silently broken: the mic read exact zeros after every call until the outgoing capture leg was unmapped explicitly.
- q6voiced device number correct (
hw:0,2) in every place it's written. Done. - New features + gains preserved. Mic still nonzero every boot. Done — ~90k nonzero frames verified repeatedly across the session.
Not in the original list, completed 2026-08-02: the earpiece/speaker executor
(blueline-callaudio-hook speaker on|off) is driven by the patched
souveraine-callaudiod; see ../../audio.md and TASK-39.
Fallback (if PipeWire re-breaks the mic)
Raw-PA call hook: a small ModemManager call-state trigger that applies the
VoiceCall mixer controls directly via amixer/alsaucm cset on call-start and
reverts on hangup. ~15 lines. No server swap, zero risk to the working mic.
Smaller diff, fewer niceties. Only take this if PipeWire loses the mic.
RULES OF ENGAGEMENT
- Base of truth = PAF. Every reference is local (the 4 repos above). Read
before theorizing. Cite
file:lineor say "not in the code." - Rule out airplane/radio mode before logging any modem/audio "wedge."
- The mic is the crown jewel. Never trade it away for a nicety.
- Verify claims live on the phone; don't assert kernel/route state from memory.
- The doctrine holds: build the finished thing, not a v1. This is the last mile.