GUI-Titel/Header auf dem Board ebenfalls umgestellt; technische Bezeichner (callrec.service, /opt/callrec, DB, CallRecMix) bleiben. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
80 lines
4.2 KiB
Markdown
80 lines
4.2 KiB
Markdown
# 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_mic2mix (100%)" --> MIX
|
||
MIC -- "cr_mic2pc (100%)" --> GATE --> GADGET
|
||
MIX -.->|"monitor"| CRMIX --> APP
|
||
```
|
||
|
||
Vier Loopbacks, jeder per `media.name`-Tag identifizierbar (robust gegen Index-Verschiebung), Gains setzt
|
||
`si_vol()` im Setup-Skript `/opt/callrec/aime-usb-audio-setup.sh`:
|
||
|
||
| Loopback | 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_mic2mix` | Mikro → callmix | 100 % | Eigene Stimme in die Aufnahme |
|
||
| `cr_mic2pc` | Mikro → micgate → Gadget | 100 % | Gegenseite hört den Nutzer |
|
||
|
||
## 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.
|