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:
co-authored by
Claude Fable 5
parent
1016eaa095
commit
7391b0ded7
@@ -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:
|
||||||
|
|||||||
@@ -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)?
|
||||||
|
|
||||||
|
|||||||
@@ -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`
|
||||||
|
|||||||
Reference in New Issue
Block a user