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
This commit is contained in:
schakal00783
2026-07-17 00:11:58 +02:00
co-authored by Claude Fable 5
parent 1016eaa095
commit 7391b0ded7
3 changed files with 45 additions and 8 deletions
+18 -2
View File
@@ -75,16 +75,32 @@ pactl set-sink-volume callmix 100% >/dev/null 2>&1
# routes — each loopback tagged so we can set per-stream gain by name # routes — each loopback tagged so we can set per-stream gain by name
pactl load-module module-loopback source="$PCAUD" sink="$HSSINK" latency_msec=60 sink_input_properties=media.name=cr_pc2hs >/dev/null 2>&1 # PC -> headset (monitor) pactl load-module module-loopback source="$PCAUD" sink="$HSSINK" latency_msec=60 sink_input_properties=media.name=cr_pc2hs >/dev/null 2>&1 # PC -> headset (monitor)
pactl load-module module-loopback source="$PCAUD" sink=callmix latency_msec=60 sink_input_properties=media.name=cr_pc2mix >/dev/null 2>&1 # PC -> mix pactl load-module module-loopback source="$PCAUD" sink=callmix latency_msec=60 sink_input_properties=media.name=cr_pc2mix >/dev/null 2>&1 # PC -> mix
pactl load-module module-loopback source="$HSMIC" sink=callmix latency_msec=60 sink_input_properties=media.name=cr_mic2mix >/dev/null 2>&1 # mic -> mix
pactl load-module module-loopback source="$HSMIC" sink="$MIC_OUT" latency_msec=60 sink_input_properties=media.name=cr_mic2pc >/dev/null 2>&1 # mic -> (gate ->) PC pactl load-module module-loopback source="$HSMIC" sink="$MIC_OUT" latency_msec=60 sink_input_properties=media.name=cr_mic2pc >/dev/null 2>&1 # mic -> (gate ->) PC
# mic -> mix: GATED. The old direct HSMIC->callmix loopback put the far end into
# the recording TWICE — digitally (cr_pc2mix) AND ~80 ms later as earcup bleed
# through the always-open mic (cepstral peak 79-80 ms on #71) -> far-end voices
# sounded like a reverberant room AND their smeared embeddings made diarization
# merge two remote speakers into one. Tapping the gate's OUTPUT instead keeps the
# mic out of the mix in the user's speech pauses (same trick as the Teams
# self-echo fix / iPhone uplink). Fallback: no gate -> old direct loopback.
if [ "$MIC_OUT" = micgate ]; then
for i in $(seq 1 10); do
pw-link micgate.out:output_FL callmix:playback_FL >/dev/null 2>&1 && \
pw-link micgate.out:output_FR callmix:playback_FR >/dev/null 2>&1 && break
sleep 1
done
else
pactl load-module module-loopback source="$HSMIC" sink=callmix latency_msec=60 sink_input_properties=media.name=cr_mic2mix >/dev/null 2>&1 # mic -> mix (UNgated fallback)
fi
# GAIN STAGING (clip-safe): PC media hits ~0 dBFS, so knock it down hard in the # GAIN STAGING (clip-safe): PC media hits ~0 dBFS, so knock it down hard in the
# mix; the mic runs near unity. Their sum must never reach 0 dBFS or clipping # mix; the mic runs near unity. Their sum must never reach 0 dBFS or clipping
# corrupts whisper + diarization (over-segments to many speakers). PC monitoring # corrupts whisper + diarization (over-segments to many speakers). PC monitoring
# to the headset (cr_pc2hs) stays at unity — full volume. # to the headset (cr_pc2hs) stays at unity — full volume.
sleep 1 sleep 1
si_vol cr_pc2mix 60% # far side into the recording (~-12 dB) si_vol cr_pc2mix 60% # far side into the recording (~-12 dB)
si_vol cr_mic2mix 100% # near side (user), into the recording mix si_vol cr_mic2mix 100% # near side (user) into the mix — only exists in the UNgated fallback
si_vol cr_mic2pc 65% # near side to the far end (through the gate) si_vol cr_mic2pc 65% # near side to the far end (through the gate)
# NOTE: fine mic/PC balance still wants tuning on a REAL call. If the far end # NOTE: fine mic/PC balance still wants tuning on a REAL call. If the far end
# finds the user too quiet, raise cr_mic2pc / Mic gain -- but watch the gate: # finds the user too quiet, raise cr_mic2pc / Mic gain -- but watch the gate:
+8 -6
View File
@@ -19,20 +19,22 @@ flowchart LR
PCIN -- "cr_pc2hs (100%)" --> HS PCIN -- "cr_pc2hs (100%)" --> HS
PCIN -- "cr_pc2mix (60% ≈ −13 dB)" --> MIX PCIN -- "cr_pc2mix (60% ≈ −13 dB)" --> MIX
MIC -- "cr_mic2mix (100%)" --> MIX MIC -- "cr_mic2pc (65%)" --> GATE
MIC -- "cr_mic2pc (100%)" --> GATE --> GADGET GATE --> GADGET
GATE -- "pw-link (gegatet, 2026-07-17)" --> MIX
MIX -.->|"monitor"| CRMIX --> APP MIX -.->|"monitor"| CRMIX --> APP
``` ```
Vier Loopbacks, jeder per `media.name`-Tag identifizierbar (robust gegen Index-Verschiebung), Gains setzt 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`: `si_vol()` im Setup-Skript `/opt/callrec/aime-usb-audio-setup.sh`:
| Loopback | Weg | Gain | Zweck | | Route | Weg | Gain | Zweck |
|---|---|---|---| |---|---|---|---|
| `cr_pc2hs` | PC → Headset | 100 % | Nutzer hört PC/Teams | | `cr_pc2hs` | PC → Headset | 100 % | Nutzer hört PC/Teams |
| `cr_pc2mix` | PC → callmix | **60 % (≈ −13 dB)** | Gegenseite in die Aufnahme (clip-sicher) | | `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 | 65 % | Gegenseite hört den Nutzer (gegatet) |
| `cr_mic2pc` | Mikro → micgate → Gadget | 100 % | Gegenseite hört den Nutzer | | `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)? ## Warum Noise-Gate (micgate)?
+19
View File
@@ -3,6 +3,25 @@
Chronik der Entwicklungsschritte. **Regel: jede zukünftige Änderung bekommt hier einen Eintrag** (Datum, Chronik der Entwicklungsschritte. **Regel: jede zukünftige Änderung bekommt hier einen Eintrag** (Datum,
Was, Warum, betroffene Dateien/Backups). Was, Warum, betroffene Dateien/Backups).
## 2026-07-17 — Hall auf der Gegenseite + verschmolzene Sprecher: Mikro→Mix jetzt GEGATET (`.bak-gatedmix`)
User: Gegenseite klingt „wie in einem schallenden Raum", Diarization macht aus zwei entfernten Personen
eine. **Diagnose per Cepstral-Analyse** auf #71: Gegenseiten-Segment hat einen felsenstabilen Peak bei
**79–80 ms** (22/26 Frames) = deterministische verzögerte Kopie; User-Segment sauber. Ursache: der direkte
`cr_mic2mix`-Loopback (immer offen) legte die Gegenseite doppelt in den Mix — digital (`cr_pc2mix`) UND als
Kopfhörermuschel-Bleed durchs Mikro (~80 ms Latenz). Der Hall verschmiert zusätzlich die TitaNet-Embeddings
→ zwei Remote-Stimmen (gleicher Kanal + gleicher „Raum") rücken über die 0,5-Kosinus-Schwelle zusammen.
- **Fix** (`aime-usb-audio-setup.sh`): direkter `cr_mic2mix`-Loopback ENTFERNT; stattdessen
`pw-link micgate.out → callmix` — dieselbe Gate-Auskopplung wie beim Teams-Selbstecho-/iPhone-Uplink-Fix.
In Sprechpausen des Nutzers ist das Mikro komplett aus der Aufnahme. Fallback ohne Gate = alter Loopback.
- Verifiziert strukturell (`pw-link -l`: callmix ← cr_pc2mix + micgate.out, kein HSMIC-Direktpfad) und
funktional (4 s callrec_mix bei Stille = RMS 0/Peak 0). **Echter Call steht noch aus.**
- **Nebenbei entdeckt:** OOM-Ereignis 17:47 (die fünf 60-s-READY-Timeout-Retries beim ersten Qwen3-Start
luden je 5,3 GB, NPU-Speicher der gekillten Loads wurde nicht schnell genug frei) riss mariadb, callrec
UND pipewire weg — Audio-Topologie war seitdem TOT. Mit dem 180-s-Timeout (Changelog unten) behoben;
Topologie neu aufgebaut. Lehre: nach OOM immer `pw-link -l` prüfen.
## 2026-07-16 — Glossar: Einträge bearbeitbar (`.bak-gedit`) ## 2026-07-16 — Glossar: Einträge bearbeitbar (`.bak-gedit`)
User-Wunsch: gespeicherte Glossar-Begriffe nachträglich ändern. Neu: `PUT /api/glossary/:id` User-Wunsch: gespeicherte Glossar-Begriffe nachträglich ändern. Neu: `PUT /api/glossary/:id`