# iMac19,2 internal mic: silent capture despite maxed gain## TL;DRThe internal mic shows up normally in PipeWire/ALSA/Discord, with fullyadjustable gain controls, but captures almost nothing regardless of how highany gain is pushed. Root cause: the CS8409 codec driver's HDA auto-configbinds the exposed capture PCM stream to the wrong ADC node, orphaning thereal internal-mic ADC entirely — its mixer controls work, but nothing isever routed through them. A fix for this exact bug, confirmed on a siblingMac model, is packaged into this repo's build (`patches/snd-hda-codec-cs8409/`)but **not yet verified on this exact iMac19,2 hardware** — see[Current verification status](#current-verification-status).## Hardware / software identification- Model: Apple iMac19,2 (2019, 21.5")- Distro: Aurora (uBlue/Fedora Kinoite bootc image), Kinoite variant`44.20260908.1`- Kernel: `7.1.8-200.fc44.x86_64`- Audio codec: Cirrus Logic CS8409, HDA vendor id `0x10138409`, subsystem id`0x106b0f00` (confirmed via `/proc/asound/card0/codec#0`)- Secure Boot: unsupported/disabled on this hardware (`mokutil --sb-state`)— a documented non-goal of this fix; see [Open risks](#open-risks--unknowns).## SymptomMic appears as a normal PipeWire source (`Built-in Audio Analog Stereo`) andALSA capture device (`CS8409 Analog`, card 0). All of the following wereconfirmed at 100% (or higher) with no effect on captured level:- ALSA `Internal Mic` capture volume: 100% (63/63), unmuted- ALSA `Internal Mic Boost`: 100% (2/2)- PipeWire source software volume: tested at 1.0, 4.0, and 8.0 (up to +18dB)- Discord's own in-app input-volume slider: maxedDirect measurement, bypassing Discord and any GUI entirely, via`pw-record --target <mic source>` / `arecord`, analyzed with`ffmpeg -af volumedetect`:| Gain setting | mean_volume | max_volume ||---|---|---|| PipeWire source @ 1.0x (100%, all ALSA gain also maxed) | -80.8 dB | -71.2 dB || PipeWire source @ 4.0x | -59.7 dB | -50.3 dB || PipeWire source @ 8.0x | -59.7 dB | -50.3 dB (uncontrolled re-test, not a true ceiling — see note below) |The 1x → 4x jump is real, reproducible signal (matches the expectedamplification). The identical 4x/8x reading is *not* evidence of a hardceiling — it came from two takes that weren't spoken into with controlled,identical volume/distance, so it's not a clean A/B. Even at its bestmeasured point (-50dB max), this is far too quiet for usable speech (normalspeech should peak around -12 to -6dB) — consistent with "gain is working,but there's very little real signal to amplify in the first place."## Ruled out, with evidence- **Wrong/muted output device** — a real but separate issue found early on:the *output* sink was muted at 0% (unrelated to the mic). Fixedindependently (`wpctl set-mute @DEFAULT_AUDIO_SINK@ 0`).- **PipeWire/ALSA mute or wrong default device** — `wpctl status`,`pactl list sources`, and `amixer` all independently agreed the mic sourcewas unmuted and at 100%+ from three different vantage points.- **Discord-side gain/config** — Discord's own input-volume slider wasalready at maximum; its `settings.json` doesn't store per-accountvoice/mic settings in plaintext (those sync via Discord's own accountstorage), so this was ruled out by the maxed-slider observation ratherthan a config file.- **The camera providing the audio instead of the codec** — `arecord -l`shows exactly **one** ALSA capture device (`CS8409 Analog`, card 0); theFaceTime HD Camera (USB `05ac:8511`) exposes no audio interface to Linuxat all (checked via `lsusb` + absence from `arecord -l`/`arecord -L`).- **Apple T2 chip audio routing** — ruled out: no Apple PCI bridge/T2 devicepresent (`lspci -nn`), and iMac19,2 (2019 21.5") predates T2's presence inMacs' internal-mic path regardless.- **Missing Flatpak/portal permission for Discord's mic access** —`wpctl status` showed Discord's own `WEBRTC VoiceEngine` client (verifiedby cross-referencing the sandboxed PID against the host process list) withan *active* capture stream connected to the real hardware node — apermission denial would show no connected stream at all, not merely lowlevel.## Root causeTraced to a specific, very recent (2026-08-19) upstream bug report and fixon a sibling Mac model:- **Issue**: [`egorenar/snd-hda-codec-cs8409` #5, "mic input"](https://github.com/egorenar/snd-hda-codec-cs8409/issues/5)- **Diagnostic dead-end + panic warning + D3 discovery** (2026-08-17):https://github.com/egorenar/snd-hda-codec-cs8409/issues/5#issuecomment-5314393975- **Root cause + fix, confirmed working** (2026-08-19):https://github.com/egorenar/snd-hda-codec-cs8409/issues/5#issuecomment-5338459155- **Fork/PR carrying Linux 6.17+ HDA API compatibility**:[PR #30](https://github.com/egorenar/snd-hda-codec-cs8409/pull/30),`daviddoll/snd-hda-codec-cs8409@kernel-6.17-hda-compat`, open/unmerged.In `patch_cirrus_apple.h`, function `cs_8409_apple_boot_init()`, the`SNDRV_PCM_STREAM_CAPTURE` branch only handles two cases for the capturestream's `hinfo->nid`:- `hinfo->nid == spec->intmike_adc_nid` — the real internal-mic ADC, set upcorrectly.- `hinfo->nid == 0x1a` — the headset-mic node, set up correctly.There's no fallback for when HDA auto-config lands the exposed capture PCMstream on **neither** — e.g. landing on node `0x12`, wired to an unconfiguredexternal Line-In pin (`0x34`) with no physical signal path at all. When thishappens, the real internal-mic ADC (`spec->intmike_adc_nid`, `0x23` for oursubsystem-id group) has all its mixer/gain/switch controls correctly presentand adjustable — which is exactly why raising every gain control had noeffect — but is never attached to any PCM stream, so it's completelyorphaned. Confirmed on the sibling model via `journalctl -kf` during a live`arecord` test: the internal-mic-specific prepare hook was never called,only the generic default path ran.Our subsystem id (`0x106b0f00`) is grouped together with the sibling model'sfamily (`0x106b1000`, `0x106b0f00`, `0x106b0e00`) in this same file's`intmike_adc_nid` assignment logic — all three get `intmike_nid = 0x45`,`intmike_adc_nid = 0x23` — matching our own kernel log(`snd_hda_codec_cs8409 hdaudioC0D0: ... Internal Mic=0x45`). So this is aplausible direct match, though **confirmed only on iMac18,1, not this exactiMac19,2** — see [Open risks](#open-risks--unknowns).On the sibling model, applying the fix took capture from -91dB pure digitalsilence to a real -16.9dB mean / -0.0dB max signal.## The fixSee [`patches/snd-hda-codec-cs8409/0001-imac19-2-force-intmike-adc-nid-fallback.patch`](../patches/snd-hda-codec-cs8409/0001-imac19-2-force-intmike-adc-nid-fallback.patch)for the actual diff (source of truth — not duplicated here). In short: ifthe capture stream's `hinfo->nid` matches neither the internal-mic ADC northe headset-mic node, force it onto the internal-mic ADC before the existingsetup code runs.### A second, related issue (defensive, unconfirmed on this model)On the sibling model, the internal-mic ADC node also came up in HDA powerstate D3 (suspended) after cold boot, failing capture with an I/O erroruntil forced to D0 via `hda-verb ... 0x23 SET_POWER_STATE 0x0` — notpersistent across reboots. This repo includes a defensive systemd unit(`cs8409-intmike-power-fixup.service`, running`overlay/usr/libexec/quine-linux/cs8409-intmike-power-fixup.sh`) that logsthe power state and retries forcing D0 a few seconds after boot. **WhetheriMac19,2 actually hits this at all is unconfirmed** — its own journal outputafter the real test boot is the evidence that will settle it.## Packaging approachThe fix is built into this repo's own bootc image rather than hand-patchedlive on the running system, specifically to avoid a documented panic risk(see [Open risks](#open-risks--unknowns)) and to get free, cheap rollback via`bootc rollback`/`rpm-ostree rollback` if anything goes wrong.- `patches/snd-hda-codec-cs8409/vendor/` — a verbatim copy of the 16 filesfrom the pinned upstream commit (`daviddoll/snd-hda-codec-cs8409` @`14e00de4290e090afd7632bc6d5c724131a19e7b`), vendored rather than fetchedat build time because this is an unmerged personal-fork branch that couldbe force-pushed or deleted with no notice. See[`PROVENANCE.md`](../patches/snd-hda-codec-cs8409/PROVENANCE.md) for thefull origin/license/rationale writeup (license: `GPL-2.0-or-later`, onefile `GPL-2.0-only`, per each file's own original SPDX header).- `patches/snd-hda-codec-cs8409/0001-imac19-2-force-intmike-adc-nid-fallback.patch` —the actual functional change, kept separate from the vendored copy so it'seasy to re-diff if/when PR #30 lands upstream and this vendoring can bedropped.- `Containerfile` — a new `kmod-builder` stage installs kernel headersmatching the exact kernel shipped in the `aurora:stable` base image(pinned by digest, shared between both stages via a single `ARG`, so theycan't drift apart), applies the patch, and builds the module with thevendored `Makefile`. The final stage copies the resulting `.ko` into`/usr/lib/modules/<kernel-version>/extra/` (the same convention Fedora'sown `kmod-*` subpackages use to override an in-tree module of the samename/modalias — no blacklisting or renaming needed) and re-runs `depmod`against the final image's own module tree.- DKMS was deliberately **not** used: it exists to rebuild modules atboot/install time when a kernel updates later on a mutable host. On thisbootc image, a new kernel only ever arrives bundled inside a freshly builtimage, at which point the `kmod-builder` stage reruns from scratch anyway— DKMS's rebuild-on-boot machinery is redundant weight here.## Current verification status**Not yet tested on real hardware as of 2026-09-26.** The patch has beenverified to apply cleanly (`git apply --check`) and produce the intendeddiff against the vendored source. The Containerfile has been written and alocal `podman build` sanity check (module compiles, `vermagic` matches thetarget kernel) is the next step. Actually switching this machine to boot thebuilt image (`bootc switch`/`rpm-ostree rebase` + reboot) is a separate,explicitly confirmed step, not yet taken, given this hardware/kernel/fixcombination is entirely unverified. This section will be updated with realresults (measured dB, Discord input-meter behavior, and whether the D3power-state unit actually fired) once that test happens.## Open risks / unknowns- **Kernel API mismatch risk**: the vendored fork targets Linux 6.17+ HDAAPI; our kernel is 7.1.8. Untested whether it compiles cleanly withoutfurther porting — but this fails safely at `podman build` time, beforeever touching the running system.- **Unconfirmed on this exact model**: the fix is confirmed only oniMac18,1, not this iMac19,2/subsystem-id combination, even though the`intmike_adc_nid` code path is shared across both per direct sourceinspection.- **D3 power-state issue unconfirmed on this model** — only confirmed on thesibling; the defensive unit's journal is the intended way to settle this.- **Module search-path precedence** (`extra/` overriding in-tree`kernel/...`) is asserted from documented Fedora/kmod convention, not yetverified on this image — check `modinfo -F filenamesnd_hda_codec_cs8409` after the real test boot.- **Live-unbind panic risk**: a live `unbind`/`rmmod`/`modprobe`/`bind` cycleof this module while PipeWire has the sink active caused an unrecoverablefreeze on the sibling model. This is exactly why all testing here goesthrough a full image build + reboot, never a live module reload.- **Secure Boot non-goal**: this approach assumes Secure Boot staysdisabled on this hardware. If it's ever enabled, this entire approachbreaks (an unsigned out-of-tree `.ko` gets rejected at load) and wouldneed MOK enrollment + module signing added to the builder stage.- **Personal-fork provenance risk**: the ultimate origin of the 6.17+compatibility work is an unmerged personal-fork PR (#30). Vendoringmitigates the "it could disappear" risk but doesn't change that thishasn't gone through upstream review.- `quine-linux`'s own `rpm-ostree-cleanup.timer` prunes the rollbackdeployment weekly — worth being aware of before testing an unverifiedchange on this hardware, though no action has been taken on this yet.## References- https://github.com/egorenar/snd-hda-codec-cs8409/issues/5- https://github.com/egorenar/snd-hda-codec-cs8409/issues/5#issuecomment-5314393975- https://github.com/egorenar/snd-hda-codec-cs8409/issues/5#issuecomment-5338459155- https://github.com/egorenar/snd-hda-codec-cs8409/pull/30- https://github.com/daviddoll/snd-hda-codec-cs8409/tree/kernel-6.17-hda-compat- https://github.com/rojoxstar/imac19-2-cs8409-linux (iMac19,2-specificproject; primarily speaker/playback and Apple-DSP research, explicitlydoes not claim mic-capture support — investigated and set aside in favorof the fix above, which directly targets the observed symptom)