feat: RNNoise WASM AudioWorklet for ML-based noise suppression (Phase 3)
Inject @sapphi-red/web-noise-suppressor into AudioManager's input pipeline as a toggleable AudioWorkletNode. The worklet is loaded lazily on first enable, then kept alive — toggling bypasses by rewiring the graph without destroying the WASM instance. Browser NS is forced off when RNNoise is active to avoid double-processing. InputGain forced to stereo up-mix to prevent mono-left-only output from the worklet. Also wires Phase 2 output device routing (setSinkId) into AppLayout/ChannelSidebar.
This commit is contained in:
@@ -105,6 +105,7 @@ export function useLiveKit() {
|
||||
const echoCancellation = useVoiceStore((s) => s.echoCancellation);
|
||||
const noiseSuppression = useVoiceStore((s) => s.noiseSuppression);
|
||||
const autoGainControl = useVoiceStore((s) => s.autoGainControl);
|
||||
const rnnoiseEnabled = useVoiceStore((s) => s.rnnoiseEnabled);
|
||||
const lastMicGenRef = useRef(0);
|
||||
const updateParticipants = useCallback(() => {
|
||||
const r = roomRef.current;
|
||||
@@ -199,6 +200,7 @@ export function useLiveKit() {
|
||||
try {
|
||||
const audioManager = AudioManager.getInstance();
|
||||
audioManager.setVoiceProcessing({ echoCancellation, noiseSuppression, autoGainControl });
|
||||
await audioManager.setRnnoiseEnabled(rnnoiseEnabled);
|
||||
audioManager.setScreenShareActive(isScreenSharing);
|
||||
const micPub = r.localParticipant.getTrackPublications()
|
||||
.find(p => p.source === Track.Source.Microphone);
|
||||
@@ -247,7 +249,7 @@ export function useLiveKit() {
|
||||
return () => {
|
||||
unsubscribe();
|
||||
};
|
||||
}, [isMuted, isDeafened, inputDeviceId, inputVolume, isConnected, echoCancellation, noiseSuppression, autoGainControl, isScreenSharing]);
|
||||
}, [isMuted, isDeafened, inputDeviceId, inputVolume, isConnected, echoCancellation, noiseSuppression, autoGainControl, rnnoiseEnabled, isScreenSharing]);
|
||||
const connect = useCallback(async (channelId) => {
|
||||
if (connectedChannelRef.current === channelId && roomRef.current?.state === ConnectionState.Connected)
|
||||
return;
|
||||
|
||||
@@ -161,6 +161,7 @@ export function useLiveKit() {
|
||||
const echoCancellation = useVoiceStore((s) => s.echoCancellation);
|
||||
const noiseSuppression = useVoiceStore((s) => s.noiseSuppression);
|
||||
const autoGainControl = useVoiceStore((s) => s.autoGainControl);
|
||||
const rnnoiseEnabled = useVoiceStore((s) => s.rnnoiseEnabled);
|
||||
|
||||
const lastMicGenRef = useRef(0);
|
||||
|
||||
@@ -254,6 +255,7 @@ export function useLiveKit() {
|
||||
|
||||
// Sync voice processing settings to AudioManager
|
||||
audioManager.setVoiceProcessing({ echoCancellation, noiseSuppression, autoGainControl });
|
||||
await audioManager.setRnnoiseEnabled(rnnoiseEnabled);
|
||||
// Keep screen share state in sync (handles edge cases like remounts)
|
||||
audioManager.setScreenShareActive(isScreenSharing);
|
||||
|
||||
@@ -313,7 +315,7 @@ export function useLiveKit() {
|
||||
return () => {
|
||||
unsubscribe();
|
||||
};
|
||||
}, [isMuted, isDeafened, inputDeviceId, inputVolume, isConnected, echoCancellation, noiseSuppression, autoGainControl, isScreenSharing]);
|
||||
}, [isMuted, isDeafened, inputDeviceId, inputVolume, isConnected, echoCancellation, noiseSuppression, autoGainControl, rnnoiseEnabled, isScreenSharing]);
|
||||
|
||||
const connect = useCallback(async (channelId: string) => {
|
||||
if (connectedChannelRef.current === channelId && roomRef.current?.state === ConnectionState.Connected) return;
|
||||
|
||||
Reference in New Issue
Block a user