feat(denoise): browser-native default, quality-ordered model picker, wire native-NS
CI / Build & Quality Checks (push) Successful in 11m15s
CI / Trigger Desktop Build (push) Successful in 18s

- Model dropdown is now ordered by quality/CPU, best first (DeepFilterNet 3 →
  DTLN → RNNoise → Speex); fix RNNoise's inaccurate "High" voice-quality label.
- When a user opts into the ML tier, default to the highest-quality model
  (DeepFilterNet 3). The tier default stays browser-native (known-good, best
  perceived in testing so far).
- Wire the "Series Suppression" (native-NS-before-ML) toggle into the real call
  path — it was applied only in the settings tester, so the tester could sound
  better than the actual call. Default it OFF (a single NS stage is best
  practice; it's an opt-in test aid).
- isMLDenoiseSupported now also requires WebAssembly, so ML isn't offered on
  strict-CSP shells where it would silently fall back to the raw mic.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-30 23:02:41 -04:00
parent 7939dc92d4
commit ebc782b16c
4 changed files with 61 additions and 43 deletions
+11 -7
View File
@@ -138,9 +138,9 @@ export class CallEmbed {
themeKind: ElementCallThemeKind,
denoiseMode: NoiseSuppressionMode = 'browser',
denoiseModel: string = 'rnnoise',
// [lotus] no longer used by the in-source denoise path; kept positionally
// for callers. Prefixed with _ to satisfy no-unused-vars.
_denoiseNativeNS: boolean = true,
// [lotus] "Series suppression": also run EC's built-in WebRTC NS before the
// in-source ML model (opt-in test aid for stacking browser NS + ML).
denoiseNativeNS: boolean = false,
denoiseGate: boolean = false,
denoiseGateThreshold: number = -45,
initialAudio = true,
@@ -166,10 +166,14 @@ export class CallEmbed {
perParticipantE2EE: room.hasEncryptionStateEvent().toString(),
lang: 'en-EN',
theme: themeKind,
// EC's built-in WebRTC suppressor: on only for 'browser' tier. For 'ml'
// we disable it so EC captures a raw mic and the fork's in-source denoise
// TrackProcessor (lotusDenoiseSource) handles the pipeline.
noiseSuppression: (denoiseMode === 'browser').toString(),
// EC's built-in WebRTC suppressor: on for the 'browser' tier, and for the
// 'ml' tier only when "series suppression" is opted into (stack browser NS
// before the fork's in-source ML model). Plain 'ml' keeps it OFF so the
// fork's TrackProcessor (lotusDenoiseSource) gets a raw mic.
noiseSuppression: (
denoiseMode === 'browser' ||
(denoiseMode === 'ml' && denoiseNativeNS)
).toString(),
audio: initialAudio.toString(),
video: initialVideo.toString(),
header: 'none',