--- type: adr id: "0018" status: accepted date: 2026-08-15 supersedes: null superseded_by: null related: - "docs/issues/0054-ki-geraeuschunterdrueckung-element-call.md" --- # 0018 — KI-Geräuschunterdrückung in threadnet-call: client-seitig, opt-in, selbst ausgeliefert **Status:** akzeptiert · **Datum:** 2026-08-15 · **Entscheider:** sorb ## Kontext Der WebRTC-Standardfilter (`noiseSuppression`) schätzt ein laufendes Rauschprofil und ist damit auf **stationäre** Störungen ausgelegt. **Transiente** Geräusche — Tastaturanschläge — erkennt er nicht als Störung; sie werden mitübertragen. Betroffen sind ausdrücklich auch leise Chiclet-Tastaturen, nicht nur mechanische. Push-to-Talk als Ausweg wurde verworfen („inakzeptabel", sorb). `threadnet-call:docs/axion1337-fork.md` §5 hatte ML-Rauschunterdrückung bereits einmal verworfen — allerdings **server-seitig** (LiveKit Agents), weil es dort keinen unterstützten Weg gibt, bereinigtes Audio an andere Teilnehmer weiterzureichen. Client-seitig greift dieser Einwand nicht; diese ADR widerspricht der damaligen Entscheidung also nicht, sondern setzt sie fort. Eine externe Architekturspezifikation empfahl DeepFilterNet3 via WebAssembly. Statt sie zu übernehmen, wurde ein **Wegwerf-Prototyp** gebaut und gemessen (#0054). Das hat drei ihrer Kernannahmen korrigiert und die Entscheidungsgrundlage von Schätzung auf Messung gestellt. ## Entscheidung **DeepFilterNet3 wird client-seitig integriert — opt-in, nachgeladen, selbst ausgeliefert.** 1. **Modell:** DeepFilterNet3 über `deepfilternet3-noise-filter` (Apache-2.0 ODER MIT) als LiveKit-`TrackProcessor`. Nicht RNNoise: es ist zwar zehnmal kleiner, aber bei Transienten deutlich schwächer — genau dem Fall, um den es hier geht. 2. **Opt-in mit Nachladen.** Standard **AUS**. Die Assets (23,3 MB) werden **erst beim Einschalten** geladen. Damit zahlt nur, wer profitiert — das Größenargument entfällt für alle anderen. 3. **Bedienung:** Checkbox zum Aktivieren **plus Regler** für die Stärke. 4. **Standardwert 35 %**, nicht 100 %. Gemessen reicht gut ein Drittel für „Tastatur weg und Stimme natürlich"; weniger Dämpfung heißt weniger Artefaktrisiko. 5. **Regelung über den Modellparameter** (`setSuppressionLevel` / `atten_lim`), **nicht** über einen Dry/Wet-Mix. 6. **Assets werden selbst ausgeliefert.** Der Default-Pfad des Pakets lädt sie von `cdn.mezon.ai`; `assetConfig.cdnUrl` wird auf das eigene Deployment gezeigt. 7. **`getUserMedia`:** `noiseSuppression: false` (sonst arbeiten Browser-Filter und Modell gegeneinander), `echoCancellation: true`. ## Gemessene Grundlage (Prototyp 2026-08-15) | | | |---|---| | Wirkung | Tastatur weg, Stimme natürlich — **bei 35 %** | | Download je Client | **23,27 MB** (15,66 MB wasm + 7,61 MB Modell) | | Vergleich RNNoise | 2,0–4,6 MB, also ~ein Zehntel | | Paketpflege | 20 Versionen, 4 Maintainer, ~20k Downloads/Monat | | CDN-freier Betrieb | im Prototyp nachgewiesen | ## Konsequenzen - **Kein Rust/wasm-Build.** Die Spezifikation hielt ihn für nötig; das fertige Paket macht ihn entbehrlich. Die Fork-Anpassung bleibt dadurch klein: Abhängigkeit, `TrackProcessor`, Bedienelement, Assets in der Auslieferung. - **Kein Dry/Wet-Mixer, kein Delay-Node.** Da über den Modellparameter geregelt wird, gibt es keinen zweiten Signalpfad — und damit weder Phasenauslöschung noch Latenzkompensation. - **23,3 MB gehören ins Deployment.** Sie müssen mit ausgeliefert werden (Image/Ingress) und wachsen bei einem Modell-Update mit. - **Dauerhafte Fork-Anpassung.** Sie muss jeden Upstream-Rebase überleben und gehört in `axion1337-fork.md` samt Portier-Hinweis. - ⚠️ **Mobil ist ungeprüft.** Der Telefontest wurde bewusst ausgesetzt. Weil der Filter opt-in ist, ist das vertretbar: Auf schwachen Geräten bleibt er schlicht aus. Zeigt sich später, dass er dort unbrauchbar ist, ist das ein Folge-Issue, kein Widerruf dieser Entscheidung. - **Neue Lieferkette.** Ein npm-Paket eines Drittanbieters liefert Code, der WebAssembly lädt. Die **Assets** kontrollieren wir (selbst gehostet); der 23-KB-Wrapper bleibt Fremdcode. Vendoring wäre möglich und wurde bewusst nicht gewählt — dann müssten wir Updates selbst nachziehen. ## Verworfene Alternativen - **Push-to-Talk / bewusstes Stummschalten dokumentieren:** billigste Lösung, aber ein Rückschritt gegenüber dem, was Konferenzsysteme heute leisten. Ausdrücklich verworfen. - **RNNoise** statt DFN3: ein Zehntel der Größe, aber konzeptionell schwach bei genau den transienten Geräuschen, die das Problem sind. - **Server-seitige ML-Filterung:** bereits in `axion1337-fork.md` §5 verworfen — LiveKit bietet keinen unterstützten Weg, bereinigtes Audio an andere Teilnehmer weiterzugeben. - **Standardmäßig AN:** beste Wirkung ohne Zutun, aber jeder Client lädt 23 MB — auch auf Telefonen, die ungetestet sind. - **Dry/Wet-Mix als Regler** (Vorschlag der Spezifikation): mischt ungefiltertes Signal zurück, **inklusive der Tastaturanschläge**, und braucht eine Latenzkompensation, die im Spec-Entwurf fehlte. Der native Modellparameter leistet dasselbe ohne diese Nachteile. - **Assets vom Anbieter-CDN laden:** würde bei jedem Call-Start die IP jedes Teilnehmers an einen Dritten melden und die Verfügbarkeit an fremde Infrastruktur hängen.