Files
management/docs/issues/0054-ki-geraeuschunterdrueckung-element-call.md
T
Thore CimbalandClaude Opus 4.8 a328dacc50 docs: supersede ADR-0006, open #0054 on client-side AI noise suppression
ADR-0006 (Docusaurus as the shared reading surface) is superseded by ADR-0014,
which ADR-0014 had only recorded for ADR-0007. The schema has no 'deprecated', so
superseded with a pointer is the fitting lifecycle state, same shape as ADR-0007.

#0054 evaluates an external architecture spec for filtering keyboard noise with a
WebAssembly model in the client. It holds up on diagnosis, placement and the
awkward parts (128-vs-480 sample buffering, the Chromium worklet leak, SIMD), and
it does not contradict the fork's earlier rejection of ML denoising — that one was
about the server side, for a reason that does not apply here.

It does not hold up on: a missing delay node, which would make the dry/wet mix comb
filter audibly; the premise behind dry/wet at all, since DeepFilterNet can limit
attenuation natively and mixing raw signal back in returns the very keystrokes we
want gone; PESQ figures compared across different test sets; unmeasured bundle size;
throwaway npm packages; and no mention of the standing cost of carrying this through
every upstream rebase.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-15 12:00:00 +00:00

95 lines
5.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.
---
type: issue
id: "0054"
status: open
created: 2026-08-15
milestone: M4
priority: medium
area: element
related:
- "docs/issues/0029-ui-harmonisieren-gleiche-farben-und-formen.md"
---
# Tastaturgeräusche in Calls: quelloffene KI-Geräuschunterdrückung im Client prüfen
## Problem
Der WebRTC-Standardfilter (`noiseSuppression`) ist auf **stationäres** Rauschen ausgelegt
(Lüfter, Netzbrummen). **Transiente** Geräusche — Tastaturanschläge — rutschen durch: sie
haben eine sehr schnelle Anstiegszeit und ein unvorhersehbares Spektrum, sodass die
laufende Rauschprofil-Schätzung sie nicht als Störung erkennt. Betroffen sind ausdrücklich
**auch leise Chiclet-Tastaturen** (MacBook), nicht nur mechanische.
Grundlage ist eine externe Architekturspezifikation (Gemini Deep Research, 2026-07-29):
client-seitige KI-Filterung via WebAssembly, eingehängt über das LiveKit-`TrackProcessor`-
Interface, mit Intensitätsregler in den Audio-Einstellungen.
## Bewertung der Spezifikation
### Trägt
- **Diagnose stimmt.** Stationär vs. transient ist die richtige Erklärung dafür, warum die
vorhandenen Toggles nicht helfen.
- **Client-seitig ist der richtige Ort — und kein Widerspruch zur bisherigen Linie.**
`threadnet-call:docs/axion1337-fork.md` §5 verwirft ML-Rauschunterdrückung **server-seitig**
(LiveKit Agents), weil es dort keinen unterstützten Weg gibt, bereinigtes Audio an andere
Teilnehmer weiterzureichen. Genau dieser Einwand greift client-seitig **nicht**. Die
Spezifikation setzt die alte Entscheidung fort, statt ihr zu widersprechen.
- **AudioWorklet statt ScriptProcessor**, eigener hochpriorer Audio-Thread: richtig und
nicht verhandelbar.
- **Der 128-vs-480-Sample-Mismatch** (Web Audio liefert 128er-Blöcke, die Modelle brauchen
480) und der nötige Ringpuffer sind sauber benannt — daran scheitern naive Umsetzungen.
- **Chromium-AudioWorklet-Leak** und die Gegenmaßnahme (eigener `AudioContext`, hart
schließen) sind real und richtig adressiert.
- **Wasm SIMD** ist tatsächlich Voraussetzung, nicht Optimierung.
### Trägt nicht
1. ⚠️ **Konkreter Fehler: die Latenzkompensation fehlt.** Der finale Dry/Wet-Code mischt das
**unverzögerte** Original mit dem ~40 ms verzögerten KI-Signal. Das erzeugt Kammfilter und
Phasenauslöschung — hörbar als blechernes Echo, also genau das Gegenteil des Ziels. Ein
früherer Entwurf im selben Gespräch hatte dafür einen `DelayNode`; in der Endfassung ist er
verschwunden. Das ist kein Detail.
2. **Der Dry/Wet-Ansatz ist konzeptionell fragwürdig.** Die Begründung („neuronale Netze
kennen nur An/Aus") ist für DeepFilterNet **falsch** — es hat einen nativen Parameter zur
**Begrenzung der Dämpfung**. „Weniger aggressiv" heißt richtig: das Modell weniger dämpfen
lassen. Dry/Wet mischt stattdessen ungefiltertes Signal zurück — **inklusive der
Tastaturanschläge**, die man loswerden wollte.
3. **Die Zahlen taugen nicht als Entscheidungsgrundlage.** PESQ „RNNoise ~3.88" gegen „DFN3
3.54.34": die untere DFN3-Grenze läge unter RNNoise. Werte aus verschiedenen Testsets,
nicht vergleichbar.
4. **Bundle-Größe geschätzt, nicht gemessen** („1525 MB"). Für eine Browser-App, die beim
Call-Start lädt, ist das der kritische Wert überhaupt — muss gemessen werden.
5. **Die genannten NPM-Pakete sind Experimente** (`deepfilternet3-worker-test`,
`…-noise-filter-trong`). Die Spec empfiehlt selbst, aus dem Rust-Quellcode zu bauen — dann
gehört ehrlich dazu: wir übernehmen eine **Rust/wasm-Toolchain in die Build-Kette**.
6. **Mobil fehlt.** Element Call läuft auf Telefonen; DFN3 auf einem Mittelklasse-Android ist
offen und wird mit „läuft auf modernen Prozessoren" abgetan.
7. **`getUserMedia`-Constraints fehlen im Code.** Wer selbst filtert, muss die Browser-eigene
`noiseSuppression` **abschalten** (sonst arbeiten zwei Filter gegeneinander) und
`echoCancellation` erhalten. Im Gespräch erwähnt, im finalen Code verschwunden.
8. **Erzwungene 48 kHz** ohne Fallback — Geräte mit 44,1 kHz brauchen einen Pfad.
9. ⚠️ **Der größte Posten fehlt ganz: Fork-Wartung.** Das wäre eine erhebliche
Eigenentwicklung in `threadnet-call`, die bei **jedem** Upstream-Rebase mitgeschleppt und
in `axion1337-fork.md` gepflegt werden muss. Die Spec erwähnt das mit keinem Wort.
10. **Lizenz nur behauptet.** DeepFilterNet-Code ist MIT/Apache-2.0 — die **Modellgewichte**
sind separat zu prüfen, bevor „null Lizenzkosten" behauptet wird.
## Vorgeschlagenes Vorgehen (vor jeder Zeile Produktivcode)
1. **Messen statt annehmen.** Reproduzierbarer A/B-Test mit mechanischer *und* Chiclet-Tastatur
gegen die heutigen Toggles — belegt das Problem und liefert die Referenz für „besser".
2. **Wegwerf-Prototyp außerhalb des Forks.** DFN3 als Wasm auf einer eigenen Testseite:
**Bundle-Größe, CPU und Latenz auf echten Geräten messen** (inkl. Telefon). Erst diese
Zahlen entscheiden über Modell und Machbarkeit.
3. **Regler über den Modellparameter**, nicht über Dry/Wet. Falls doch Dry/Wet: Delay-Node zur
Latenzkompensation ist Pflicht.
4. **Dann erst** Integration als `TrackProcessor` und Eintrag in `axion1337-fork.md`.
## Offen (Entscheidung sorb)
Ob der Aufwand lohnt. Die Plattform hat derzeit einen sehr kleinen Nutzerkreis; dem steht
eine dauerhaft zu pflegende Fork-Anpassung mit Rust/wasm-Build gegenüber. Die Alternative —
Tastaturgeräusche als hinnehmbar erklären und stattdessen Push-to-Talk bzw. bewusstes
Stummschalten dokumentieren — ist billiger und sollte bewusst verworfen werden, nicht
übersehen.