Files
Aime/docs/02-audio-topologie.md
schakal00783andClaude Fable 5 7391b0ded7 Mikro->Mix gegatet: Doppelweg-Hall der Gegenseite beseitigt
Cepstral-Beweis auf #71: stabiler 80ms-Peak nur auf Gegenseiten-Segmenten
= Muschel-Bleed durchs offene Mikro zusaetzlich zum digitalen Pfad.
cr_mic2mix-Loopback entfernt, stattdessen pw-link micgate.out -> callmix
(Fallback ohne Gate bleibt). Verschmierte Embeddings (verschmolzene
Remote-Sprecher) sollten damit ebenfalls weg sein - echter Call offen.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0113vDKdSNtD3Dwcw4QMu9yV
2026-07-17 00:11:58 +02:00

4.5 KiB
Raw Permalink Blame History

02 — Audio-Topologie (PipeWire)

Herzstück: virtueller Misch-Bus callmix (Null-Sink). Alles, was aufgenommen werden soll, wird per Loopback dorthin geroutet; der Monitor von callmix wird als echte Quelle callrec_mix („CallRecMix“) re-mappt — die wählt die Web-GUI als Aufnahmequelle.

Gesamtgraph

flowchart LR
    PCIN["PC-Audio (Capture des UAC2-Gadgets)<br/>alsa_input.platform-fc000000.usb"]
    MIC["Headset-Mikrofon H390<br/>alsa_input.usb-Logi...mono-fallback"]
    HS["Headset-Hörer H390<br/>alsa_output.usb-Logi...analog-stereo"]
    GADGET["Gadget-Sink (Board→PC)<br/>alsa_output.platform-fc000000.usb"]
    GATE["micgate<br/>LADSPA Noise-Gate<br/>(swh gate_1410, Thr −45 dB)"]
    MIX[("callmix<br/>Null-Sink")]
    CRMIX["callrec_mix ('CallRecMix')<br/>remap von callmix.monitor"]
    APP["Aime-App<br/>Aufnahme"]

    PCIN -- "cr_pc2hs (100%)" --> HS
    PCIN -- "cr_pc2mix (60% ≈ −13 dB)" --> MIX
    MIC -- "cr_mic2pc (65%)" --> GATE
    GATE --> GADGET
    GATE -- "pw-link (gegatet, 2026-07-17)" --> MIX
    MIX -.->|"monitor"| CRMIX --> APP

Drei Loopbacks (per media.name-Tag identifizierbar) + ein statischer pw-link; Gains setzt si_vol() im Setup-Skript /opt/callrec/aime-usb-audio-setup.sh:

Route Weg Gain Zweck
cr_pc2hs PC → Headset 100 % Nutzer hört PC/Teams
cr_pc2mix PC → callmix 60 % (≈ −13 dB) Gegenseite in die Aufnahme (clip-sicher)
cr_mic2pc Mikro → micgate → Gadget 65 % Gegenseite hört den Nutzer (gegatet)
pw-link micgate.out → callmix GEGATETES Mikro → callmix unity Eigene Stimme in die Aufnahme
cr_mic2mix Mikro → callmix direkt — ENTFERNT 2026-07-17 (nur noch Fallback ohne Gate): der offene Mikro-Pfad legte die Gegenseite ZWEIMAL in den Mix — digital + ~80 ms später als Muschel-Bleed (Cepstral-Peak 79–80 ms, #71) → Hall auf der Gegenseite + Diarization verschmolz zwei entfernte Sprecher

Warum Noise-Gate (micgate)?

Teams-Gegenseite hörte sich selbst verzögert (Selbst-Echo). Nachgewiesen: akustisches Übersprechen ins Mikrofon (nicht elektrisch, nicht Ohrmuschel — Mute-Tests), und Teams-AGC renormalisiert jede Pegelabsenkung. Lösung: LADSPA-Gate im Mikro→PC-Pfad schließt in Sprechpausen → Gegenseite bekommt Stille → kein Echo. AEC wurde getestet und verworfen (Knistern, kein Nutzen).

flowchart LR
    M["Mikrofon<br/>HW-Gain fest Stufe 12 (+1,4 dB)"] --> G{"Pegel > −45 dB?"}
    G -- "ja (Sprache)" --> OPEN["Gate offen → Signal zum PC"]
    G -- "nein (Pause)" --> CLOSED["Gate zu → Stille zum PC<br/>= kein Selbst-Echo"]

Gotchas (teuer bezahlt):

  • Filter-Chain ist ein Core-Modul, kein Pulse-Modul → nicht per pactl load-module, sondern Drop-in filter-chain.conf.d/micgate.conf + eigener Dienst aime-micgate.service.
  • PipeWire liefert einen eigenen preset-aktivierten filter-chain.service mit → doppeltes micgate → systemctl --user mask filter-chain.service.
  • Mikro-HW-Gain nur über pactl set-source-volume $HSMIC 62% setzen (= HW-Stufe 12). amixer direkt wird von WirePlumber überschrieben; 100 % = +11 dB → Grundrauschen öffnet das Gate wieder.
  • 2-Mono-Node-Stereo-Graph im Filter-Chain = kein Audio → 1 Mono-Node verwenden.
  • pkill -f "pipewire -c filter-chain.conf" killt die eigene SSH-Session (exit 128) → setsid nutzen.

Merksätze

  • PC-Audio = die Quelle alsa_input.platform-fc000000.usb..., NICHT deren .monitor (der ist stumm — hat einmal eine Stunde gekostet). Quellen vor Verwendung mit parecord + ffmpeg astats auf Signal prüfen.
  • Die GUI filtert alle *.monitor-Quellen aus → deshalb der Remap auf callrec_mix.
  • Gain-Staging ist clip-kritisch: Übersteuerung (0 dBFS) hat einmal die Diarization-Embeddings zerstört → 14 „Sprecher“ bei einem 2-Personen-Gespräch (Aufnahme #41, bleibt dauerhaft geclippt).

Persistenz

Einheit Aufgabe
aime-usb-audio.service (user) baut die komplette Topologie beim Boot (aime-usb-audio-setup.sh); wartet auf micgate, Fallback direkt auf Gadget-Sink
aime-micgate.service (user, enabled) startet die micgate-Filter-Chain
aime-volume-headset.service (user) Windows-Volume-Bridge (UAC2 numid=7 → Headset-Sink)
aime-headset-keys.service (root) H390-Inline-Tasten → Lautstärke
alte aime-audio-out / aime-volume ES8323-Ära, disabled

Kaltstart 2× verifiziert: Topologie, Gate, Volume-Bridge und WLAN kommen ohne Eingriff hoch.