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>
5.5 KiB
type, id, status, created, milestone, priority, area, related
| type | id | status | created | milestone | priority | area | related | |
|---|---|---|---|---|---|---|---|---|
| issue | 0054 | open | 2026-08-15 | M4 | medium | element |
|
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
- ⚠️ 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. - 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.
- Die Zahlen taugen nicht als Entscheidungsgrundlage. PESQ „RNNoise ~3.88" gegen „DFN3 3.5–4.34": die untere DFN3-Grenze läge unter RNNoise. Werte aus verschiedenen Testsets, nicht vergleichbar.
- Bundle-Größe geschätzt, nicht gemessen („15–25 MB"). Für eine Browser-App, die beim Call-Start lädt, ist das der kritische Wert überhaupt — muss gemessen werden.
- 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. - Mobil fehlt. Element Call läuft auf Telefonen; DFN3 auf einem Mittelklasse-Android ist offen und wird mit „läuft auf modernen Prozessoren" abgetan.
getUserMedia-Constraints fehlen im Code. Wer selbst filtert, muss die Browser-eigenenoiseSuppressionabschalten (sonst arbeiten zwei Filter gegeneinander) undechoCancellationerhalten. Im Gespräch erwähnt, im finalen Code verschwunden.- Erzwungene 48 kHz ohne Fallback — Geräte mit 44,1 kHz brauchen einen Pfad.
- ⚠️ Der größte Posten fehlt ganz: Fork-Wartung. Das wäre eine erhebliche
Eigenentwicklung in
threadnet-call, die bei jedem Upstream-Rebase mitgeschleppt und inaxion1337-fork.mdgepflegt werden muss. Die Spec erwähnt das mit keinem Wort. - 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)
- 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".
- 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.
- Regler über den Modellparameter, nicht über Dry/Wet. Falls doch Dry/Wet: Delay-Node zur Latenzkompensation ist Pflicht.
- Dann erst Integration als
TrackProcessorund Eintrag inaxion1337-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.