From a328dacc509cc4e575f940cef62f01246e9910e0 Mon Sep 17 00:00:00 2001 From: Thore Cimbal Date: Sat, 15 Aug 2026 12:00:00 +0000 Subject: [PATCH] docs: supersede ADR-0006, open #0054 on client-side AI noise suppression MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- STATUS.md | 7 +- .../0006-wikis-konsolidieren-docusaurus.md | 4 +- ...ki-geraeuschunterdrueckung-element-call.md | 94 +++++++++++++++++++ 3 files changed, 100 insertions(+), 5 deletions(-) create mode 100644 docs/issues/0054-ki-geraeuschunterdrueckung-element-call.md diff --git a/STATUS.md b/STATUS.md index bcb9a32..f242b74 100644 --- a/STATUS.md +++ b/STATUS.md @@ -2,9 +2,9 @@ -## Issues (20 open, 27 closed) +## Issues (21 open, 27 closed) -Verteilung: M1 5 · M2 12 · M4 2 · M5 1 +Verteilung: M1 5 · M2 12 · M4 3 · M5 1 | Issue | Status | Meilenstein | Priorität | Title | |---|---|---|---|---| @@ -28,6 +28,7 @@ Verteilung: M1 5 · M2 12 · M4 2 · M5 1 | [0042](docs/issues/0042-migration-in-betrieb-nehmen-push-spiegel-schedule.md) | open | M2 | high | Migration in Betrieb nehmen: Push, erster Spiegel-Lauf, CI-Schedule | | [0051](docs/issues/0051-cve-remediation-pass.md) | open | M5 | high | CVE-Remediation-Pass: Schwachstellen-Report abarbeiten | | [0053](docs/issues/0053-historien-durchgang-nicht-kanonische-commits.md) | open | M2 | low | Historien-Durchgang: acht nicht-kanonische Commits mitziehen | +| [0054](docs/issues/0054-ki-geraeuschunterdrueckung-element-call.md) | open | M4 | medium | Tastaturgeräusche in Calls: quelloffene KI-Geräuschunterdrückung im Client prüfen | ## Active design docs (0) @@ -42,7 +43,7 @@ _none active_ | [0003](docs/adr/0003-cve-meldeweg-aggregiert.md) | accepted | 0003 — CVE-Meldeweg: aggregierte Alarme, eigener Security-Raum, gleicher Bot | | [0004](docs/adr/0004-site-to-site-vpn-hetzner-lab.md) | accepted | 0004 — Site-to-Site-VPN Hetzner-Projektnetz ↔ Lab, schaltbar über die UDM | | [0005](docs/adr/0005-pm-framework-kanban.md) | accepted | 0005 — Projektmanagement: Kanban-Rückgrat mit leichten Scrum-Elementen | -| [0006](docs/adr/0006-wikis-konsolidieren-docusaurus.md) | accepted | 0006 — Wikis ins Lab konsolidieren, Docusaurus als gemeinsame Lesefläche | +| [0006](docs/adr/0006-wikis-konsolidieren-docusaurus.md) | superseded | 0006 — Wikis ins Lab konsolidieren, Docusaurus als gemeinsame Lesefläche | | [0007](docs/adr/0007-wiki-oberflaeche-docusaurus-vs-bookstack.md) | superseded | 0007 — Wiki-Oberfläche: Docusaurus läuft, BookStack als Gegenentwurf | | [0008](docs/adr/0008-agenten-sessions-root-aequivalent.md) | accepted | 0008 — Agenten-Sessions auf CFGMON laufen root-äquivalent über die docker-Gruppe | | [0009](docs/adr/0009-commit-konventionen-und-historien-anonymisierung.md) | accepted | 0009 — Commit-Konventionen und rückwirkende Anonymisierung der Historie | diff --git a/docs/adr/0006-wikis-konsolidieren-docusaurus.md b/docs/adr/0006-wikis-konsolidieren-docusaurus.md index fdb1517..850cbdd 100644 --- a/docs/adr/0006-wikis-konsolidieren-docusaurus.md +++ b/docs/adr/0006-wikis-konsolidieren-docusaurus.md @@ -1,10 +1,10 @@ --- type: adr id: "0006" -status: accepted +status: superseded date: 2026-08-02 supersedes: null -superseded_by: null +superseded_by: docs/adr/0014-wikijs-loest-docusaurus-ab.md related: [] --- diff --git a/docs/issues/0054-ki-geraeuschunterdrueckung-element-call.md b/docs/issues/0054-ki-geraeuschunterdrueckung-element-call.md new file mode 100644 index 0000000..8ab68d2 --- /dev/null +++ b/docs/issues/0054-ki-geraeuschunterdrueckung-element-call.md @@ -0,0 +1,94 @@ +--- +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.5–4.34": die untere DFN3-Grenze läge unter RNNoise. Werte aus verschiedenen Testsets, + nicht vergleichbar. +4. **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. +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.