diff --git a/app/aime-usb-audio-setup.sh b/app/aime-usb-audio-setup.sh index 5bec1d5..c39365a 100644 --- a/app/aime-usb-audio-setup.sh +++ b/app/aime-usb-audio-setup.sh @@ -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 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="$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 +# 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 # 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 # to the headset (cr_pc2hs) stays at unity — full volume. sleep 1 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) # 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: diff --git a/docs/02-audio-topologie.md b/docs/02-audio-topologie.md index 0c67f5b..a2fbbbd 100644 --- a/docs/02-audio-topologie.md +++ b/docs/02-audio-topologie.md @@ -19,20 +19,22 @@ flowchart LR PCIN -- "cr_pc2hs (100%)" --> HS PCIN -- "cr_pc2mix (60% ≈ −13 dB)" --> MIX - MIC -- "cr_mic2mix (100%)" --> MIX - MIC -- "cr_mic2pc (100%)" --> GATE --> GADGET + MIC -- "cr_mic2pc (65%)" --> GATE + GATE --> GADGET + GATE -- "pw-link (gegatet, 2026-07-17)" --> MIX 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`: -| Loopback | Weg | Gain | Zweck | +| 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_mic2mix` | Mikro → callmix | 100 % | Eigene Stimme in die Aufnahme | -| `cr_mic2pc` | Mikro → micgate → Gadget | 100 % | Gegenseite hört den Nutzer | +| `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)? diff --git a/docs/08-changelog.md b/docs/08-changelog.md index 828b6db..ba8c325 100644 --- a/docs/08-changelog.md +++ b/docs/08-changelog.md @@ -3,6 +3,25 @@ Chronik der Entwicklungsschritte. **Regel: jede zukünftige Änderung bekommt hier einen Eintrag** (Datum, 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`) User-Wunsch: gespeicherte Glossar-Begriffe nachträglich ändern. Neu: `PUT /api/glossary/:id`