mirror of
https://github.com/fluxerapp/fluxer
synced 2026-10-17 21:15:32 +09:00
feat(voice): ship noise suppression treatment to everyone (#3029)
This commit is contained in:
1 parent
39c72f0fb0
commit
c488906131
88 files changed
+2861
-5837
No files matched your search
@@ -33,7 +33,7 @@ import {useMediaPermission} from '@app/features/user/components/modals/tabs/hook
|
||||
import styles from '@app/features/user/components/modals/tabs/UserVoiceTab.module.css';
|
||||
import * as VoiceSettingsCommands from '@app/features/voice/commands/VoiceSettingsCommands';
|
||||
import MediaEngine from '@app/features/voice/engine/MediaEngineFacade';
|
||||
import VoiceSettings from '@app/features/voice/state/VoiceSettings';
|
||||
import type VoiceSettings from '@app/features/voice/state/VoiceSettings';
|
||||
import {
|
||||
type ExternalAudioProcessorMatch,
|
||||
findExternalProcessorForDevice,
|
||||
@@ -209,10 +209,7 @@ export const VoiceTab: React.FC<VoiceTabProps> = observer(({voiceSettings, autoR
|
||||
inputVolume,
|
||||
outputVolume,
|
||||
echoCancellation,
|
||||
noiseSuppression,
|
||||
autoGainControl,
|
||||
deepFilterNoiseSuppression,
|
||||
deepFilterNoiseSuppressionLevel,
|
||||
vadThreshold,
|
||||
vadAutoSensitivity,
|
||||
} = voiceSettings;
|
||||
@@ -451,9 +448,7 @@ export const VoiceTab: React.FC<VoiceTabProps> = observer(({voiceSettings, autoR
|
||||
label={i18n._(STEREO_MICROPHONE_DESCRIPTOR)}
|
||||
description={i18n._(STEREO_MICROPHONE_DESCRIPTION_DESCRIPTOR)}
|
||||
value={isStereoMicrophoneEnabled()}
|
||||
onChange={(value) => {
|
||||
VoiceSettings.stereoMicrophone = value;
|
||||
}}
|
||||
onChange={(value) => VoiceSettingsCommands.update({stereoMicrophone: value})}
|
||||
ariaLabel={i18n._(STEREO_MICROPHONE_DESCRIPTOR)}
|
||||
data-flx={dataFlx}
|
||||
/>
|
||||
@@ -693,10 +688,7 @@ export const VoiceTab: React.FC<VoiceTabProps> = observer(({voiceSettings, autoR
|
||||
inputVolume,
|
||||
outputVolume,
|
||||
echoCancellation,
|
||||
noiseSuppression,
|
||||
autoGainControl,
|
||||
deepFilterNoiseSuppression,
|
||||
deepFilterNoiseSuppressionLevel,
|
||||
voiceProcessingMode,
|
||||
}}
|
||||
data-flx="user.voice-tab.mic-test-section"
|
||||
|
||||
@@ -31,9 +31,7 @@ interface CreateMicTestAudioGraphOptions {
|
||||
playbackTarget: AudioNode;
|
||||
playbackDelaySeconds: number;
|
||||
deepFilter: boolean;
|
||||
deepFilterNoiseReductionLevel: number;
|
||||
workletBackend: NoiseSuppressionWorkletBackend | null;
|
||||
suppressionStrength: number;
|
||||
}
|
||||
|
||||
export async function createMicTestAudioGraph({
|
||||
@@ -44,9 +42,7 @@ export async function createMicTestAudioGraph({
|
||||
playbackTarget,
|
||||
playbackDelaySeconds,
|
||||
deepFilter,
|
||||
deepFilterNoiseReductionLevel,
|
||||
workletBackend,
|
||||
suppressionStrength,
|
||||
}: CreateMicTestAudioGraphOptions): Promise<MicTestAudioGraph> {
|
||||
const source = audioContext.createMediaStreamSource(new MediaStream([sourceTrack]));
|
||||
const inputGainNode = audioContext.createGain();
|
||||
@@ -59,10 +55,7 @@ export async function createMicTestAudioGraph({
|
||||
let monitorHead: AudioNode = inputGainNode;
|
||||
try {
|
||||
if (deepFilter) {
|
||||
deepFilterChain = await buildDeepFilterAudioChain({
|
||||
audioContext,
|
||||
noiseReductionLevel: deepFilterNoiseReductionLevel,
|
||||
});
|
||||
deepFilterChain = await buildDeepFilterAudioChain(audioContext);
|
||||
inputGainNode.connect(deepFilterChain.inputDestination);
|
||||
suppressedSource = audioContext.createMediaStreamSource(new MediaStream([deepFilterChain.processedTrack]));
|
||||
monitorHead = suppressedSource;
|
||||
@@ -70,7 +63,6 @@ export async function createMicTestAudioGraph({
|
||||
workletChain = await buildNoiseSuppressionWorkletChain({
|
||||
audioContext,
|
||||
backend: workletBackend,
|
||||
suppressionStrength,
|
||||
});
|
||||
inputGainNode.connect(workletChain.inputDestination);
|
||||
suppressedSource = audioContext.createMediaStreamSource(new MediaStream([workletChain.processedTrack]));
|
||||
|
||||
@@ -12,8 +12,7 @@ import {
|
||||
getNoiseSuppressionBackendDescriptor,
|
||||
type VoiceNoiseSuppressionBackend,
|
||||
} from '@app/features/voice/utils/noise_suppression/NoiseSuppressionBackends';
|
||||
import {readEffectiveNoiseSuppression} from '@app/features/voice/utils/noise_suppression/NoiseSuppressionRuntime';
|
||||
import {applyNoiseSuppressionOverride} from '@app/features/voice/utils/noise_suppression/NoiseSuppressionSelection';
|
||||
import {readNoiseSuppressionBackend} from '@app/features/voice/utils/noise_suppression/NoiseSuppressionRuntime';
|
||||
import type {NoiseSuppressionWorkletBackend} from '@app/features/voice/utils/noise_suppression/NoiseSuppressionWorkletTypes';
|
||||
import {
|
||||
applyContentHintToTrack,
|
||||
@@ -41,15 +40,10 @@ export interface MicTestSettings {
|
||||
inputVolume: number;
|
||||
outputVolume: number;
|
||||
echoCancellation: boolean;
|
||||
noiseSuppression: boolean;
|
||||
autoGainControl: boolean;
|
||||
deepFilterNoiseSuppression: boolean;
|
||||
deepFilterNoiseSuppressionLevel: number;
|
||||
voiceProcessingMode: VoiceProcessingMode;
|
||||
}
|
||||
|
||||
const MIC_TEST_PROBE_SAMPLE_RATE = 48000;
|
||||
|
||||
function resolveMicTestWorkletBackend(backend: VoiceNoiseSuppressionBackend): NoiseSuppressionWorkletBackend | null {
|
||||
return getNoiseSuppressionBackendDescriptor(backend).engine === 'worklet'
|
||||
? (backend as NoiseSuppressionWorkletBackend)
|
||||
@@ -77,32 +71,24 @@ export const useMicTest = (settings: MicTestSettings) => {
|
||||
const restartPendingRef = useRef(false);
|
||||
const activeCaptureSignatureRef = useRef<string | null>(null);
|
||||
const micExplicitlyDenied = MediaPermission.microphoneExplicitlyDenied;
|
||||
const activeNoiseSuppression = readEffectiveNoiseSuppression(MIC_TEST_PROBE_SAMPLE_RATE);
|
||||
const noiseSuppressionBackend = readNoiseSuppressionBackend();
|
||||
const captureSignature = useMemo(
|
||||
() =>
|
||||
JSON.stringify({
|
||||
inputDeviceId: settings.inputDeviceId,
|
||||
outputDeviceId: settings.outputDeviceId,
|
||||
echoCancellation: settings.echoCancellation,
|
||||
noiseSuppression: settings.noiseSuppression,
|
||||
autoGainControl: settings.autoGainControl,
|
||||
deepFilterNoiseSuppression: settings.deepFilterNoiseSuppression,
|
||||
deepFilterNoiseSuppressionLevel: settings.deepFilterNoiseSuppressionLevel,
|
||||
voiceProcessingMode: settings.voiceProcessingMode,
|
||||
noiseSuppressionBackend: activeNoiseSuppression.backend,
|
||||
noiseSuppressionStrength: activeNoiseSuppression.suppressionStrength,
|
||||
noiseSuppressionBackend,
|
||||
}),
|
||||
[
|
||||
settings.autoGainControl,
|
||||
settings.deepFilterNoiseSuppression,
|
||||
settings.deepFilterNoiseSuppressionLevel,
|
||||
settings.echoCancellation,
|
||||
settings.inputDeviceId,
|
||||
settings.noiseSuppression,
|
||||
settings.outputDeviceId,
|
||||
settings.voiceProcessingMode,
|
||||
activeNoiseSuppression.backend,
|
||||
activeNoiseSuppression.suppressionStrength,
|
||||
noiseSuppressionBackend,
|
||||
],
|
||||
);
|
||||
const updateLevel = useCallback(() => {
|
||||
@@ -191,8 +177,7 @@ export const useMicTest = (settings: MicTestSettings) => {
|
||||
return exhaustive;
|
||||
}
|
||||
}
|
||||
const effectiveNoiseSuppression = readEffectiveNoiseSuppression(MIC_TEST_PROBE_SAMPLE_RATE);
|
||||
const profile = applyNoiseSuppressionOverride(resolveVoiceProcessing(settings), effectiveNoiseSuppression);
|
||||
const profile = resolveVoiceProcessing(settings, readNoiseSuppressionBackend(), false);
|
||||
const workletBackend = resolveMicTestWorkletBackend(profile.noiseSuppressionBackend);
|
||||
const baseAudioConstraints: MediaTrackConstraints & {voiceIsolation?: boolean} = {
|
||||
echoCancellation: profile.echoCancellation,
|
||||
@@ -240,9 +225,7 @@ export const useMicTest = (settings: MicTestSettings) => {
|
||||
playbackTarget,
|
||||
playbackDelaySeconds: MIC_TEST_MONITOR_DELAY_SECONDS,
|
||||
deepFilter: profile.deepFilter,
|
||||
deepFilterNoiseReductionLevel: profile.deepFilterNoiseReductionLevel,
|
||||
workletBackend,
|
||||
suppressionStrength: effectiveNoiseSuppression.suppressionStrength,
|
||||
});
|
||||
timeDomainDataRef.current = new Float32Array(graphRef.current.analyser.fftSize);
|
||||
const audioElement = new Audio();
|
||||
|
||||
Reference in new issue
Block a user