Noise suppression, noise gate and compressor for microphone audio

(#1052) Feature Shipped voice

Feature Contribution

I've implemented three new audio processing features for the voice system and would like to offer them upstream. The implementation is complete and tested on my self-hosted instance. Branch: cproudlock:echowire-refactor (diff)
I wasn't able to create a PR directly — if fork PRs are enabled, I'm happy to resubmit as a proper PR.
---

Summary

Adds three new audio processing features using @sapphi-red/web-noise-suppressor and the Web Audio API:
  • ML Noise Suppression (RNNoise) — WASM-based neural network that filters background noise (fans, typing, traffic). Uses AudioWorklet for off-main-thread processing at 48kHz with ~13ms latency.
  • Noise Gate — Mutes the microphone when audio falls below a configurable dB threshold (-100 to 0). Uses hysteresis (separate open/close thresholds) to prevent rapid toggling.
  • Compressor — DynamicsCompressorNode that evens out loud and quiet audio for more consistent voice levels.

Processing Chain

Raw mic → RNNoise (if enabled) → Noise Gate (if enabled) → Compressor (if enabled) → LiveKit
When all three are disabled, no processor is attached — zero overhead.

Why not @livekit/krisp-noise-filter?

Krisp requires LiveKit Cloud and doesn't work with self-hosted LiveKit. @sapphi-red/web-noise-suppressor provides ready-made AudioWorklet nodes for RNNoise with WASM SIMD auto-detection, making it a drop-in solution for any deployment.

Files Changed

FileDescription
pnpm-workspace.yamlAdd @sapphi-red/web-noise-suppressor to catalog
fluxer_app/package.jsonAdd dependency
fluxer_app/rspack.config.mjsCopy worklet/WASM files to dist/audio-worklets/
fluxer_app/src/utils/AudioProcessor.tsxNew — TrackProcessor<Track.Kind.Audio> implementation
fluxer_app/src/stores/VoiceSettingsStore.tsx4 new persisted settings
fluxer_app/src/stores/voice/VoiceMediaManager.tsxapplyAudioProcessor() method
fluxer_app/src/stores/voice/MediaEngineFacade.tsxExpose applyAudioProcessor()
fluxer_app/src/actions/VoiceSettingsActionCreators.tsxTrigger processor rebuild on setting change
fluxer_app/src/components/modals/tabs/VoiceTab.tsx"Advanced Audio Processing" UI section

Settings Added

SettingTypeDefaultDescription
advancedNoiseSuppressionbooleanfalseML noise suppression (RNNoise)
noiseGateEnabledbooleanfalseNoise gate toggle
noiseGateThresholdnumber-50Gate threshold in dB (-100 to 0)
compressorEnabledbooleanfalseDynamic compressor toggle

Implementation Details

  • Uses LiveKit's TrackProcessor<Track.Kind.Audio> interface for clean integration
  • AudioWorklet files + WASM binaries copied to dist/audio-worklets/ via rspack CopyPlugin
  • Settings persisted via MobX persistence (IndexedDB), changes apply immediately mid-call
  • Processor rebuilds graph on settings change; fully tears down when all processing disabled
  • RNNoise uses SIMD auto-detection for best performance where available
  • Noise gate uses 90ms hold time and -10dB hysteresis gap to prevent chatter

3 comments

Sign in with Fluxer to comment and vote.
Comment by @nstgeorge
RexSystem 1 vote originally by @nstgeorge on GitHub
Double check your branch. You may have leaked root passwords for some of your servers in your docs (even though the IPs look private).
Comment by @cproudlock
RexSystem 1 vote originally by @cproudlock on GitHub OP
Thanks for the heads up! Removed the password and scrubbed it from git history. Changing the passwords on the affected servers now.
Comment by @hoptional
RexSystem 1 vote originally by @hoptional on GitHub
Thanks a lot for your work on this! The lack of a noise gate is what is keeping me from switching over from Teamspeak. I hope it will be merged.