Files
Aime/docs/02-audio-topologie.md
T
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

82 lines
4.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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
```mermaid
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).
```mermaid
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.