diff --git a/locales/de/app.json b/locales/de/app.json index bb6328e7..38116fb5 100644 --- a/locales/de/app.json +++ b/locales/de/app.json @@ -177,6 +177,12 @@ "background_blur_header": "Hintergrund", "background_blur_label": "Unschärfeeffekt für den Hintergrund aktivieren", "blur_not_supported_by_browser": "(Hintergrundunschärfe wird von diesem Gerät nicht unterstützt.)", + "noise_suppression_header": "Audioverarbeitung", + "noise_suppression_label": "Störgeräuschreduktion", + "noise_suppression_description": "Reduziert Hintergrundgeräusche von Ihrem Mikrofon", + "noise_suppression_level_label": "Niveau der Störgeräuschreduktion", + "noise_suppression_level_description": "Höhere Werte unterdrücken mehr Rauschen, können aber die Sprachklarheit beeinflussen", + "noise_suppression_level_value": "Niveau: {{level}}", "developer_tab_title": "Entwickler", "devices": { "camera": "Kamera", diff --git a/locales/en/app.json b/locales/en/app.json index f5749cf7..79cd6ae4 100644 --- a/locales/en/app.json +++ b/locales/en/app.json @@ -201,6 +201,12 @@ "background_blur_header": "Background", "background_blur_label": "Blur the background of the video", "blur_not_supported_by_browser": "(Background blur is not supported by this device.)", + "noise_suppression_header": "Audio Processing", + "noise_suppression_label": "Noise suppression", + "noise_suppression_description": "Reduces background noise from your microphone", + "noise_suppression_level_label": "Noise suppression level", + "noise_suppression_level_description": "Higher levels suppress more noise but may affect speech clarity", + "noise_suppression_level_value": "Level: {{level}}", "developer_tab_title": "Developer", "devices": { "camera": "Camera", diff --git a/src/UrlParams.ts b/src/UrlParams.ts index 31101197..8cd72fa5 100644 --- a/src/UrlParams.ts +++ b/src/UrlParams.ts @@ -245,6 +245,19 @@ export interface UrlConfiguration { */ noiseSuppression?: boolean; + /** + * Whether to enable the advanced noise suppression filter (DeepFilterNet3). + * This can be used to override the user's noise suppression setting via URL parameter. + */ + noiseSuppressionEnabled?: boolean; + + /** + * The noise suppression level (30-80) when using the advanced DeepFilterNet3 filter. + * This can be used to override the user's setting via URL parameter. + * Defaults to 75 if not specified. + */ + noiseSuppressionLevel?: number; + callIntent?: RTCCallIntent; } @@ -504,6 +517,11 @@ export const computeUrlParams = (search = "", hash = ""): UrlParams => { autoLeaveWhenOthersLeft: parser.getFlag("autoLeave"), noiseSuppression: parser.getFlagParam("noiseSuppression", true), echoCancellation: parser.getFlagParam("echoCancellation", true), + noiseSuppressionEnabled: parser.getFlagParam("noiseSuppressionEnabled"), + noiseSuppressionLevel: (() => { + const val = parseInt(parser.getParam("noiseSuppressionLevel") ?? "", 10); + return isNaN(val) ? undefined : val / 100; + })(), }; // Log the final configuration for debugging purposes. diff --git a/src/settings/SettingsModal.tsx b/src/settings/SettingsModal.tsx index 30ac3618..53e43a5a 100644 --- a/src/settings/SettingsModal.tsx +++ b/src/settings/SettingsModal.tsx @@ -23,6 +23,8 @@ import { useSetting, soundEffectVolume as soundEffectVolumeSetting, backgroundBlur as backgroundBlurSetting, + noiseSuppressionEnabled, + noiseSuppressionLevel, developerMode, } from "./settings"; import { PreferencesSettingsTab } from "./PreferencesSettingsTab"; @@ -98,6 +100,67 @@ export const SettingsModal: FC = ({ ); }; + // Generate controls for noise suppression. + const NoiseSuppressionControls: React.FC = (): ReactNode => { + const [noiseEnabled, setNoiseEnabled] = useSetting(noiseSuppressionEnabled); + const [noiseLevel, setNoiseLevel] = useSetting(noiseSuppressionLevel); + const displayLevel = Math.round(noiseLevel * 100); + const [noiseLevelRaw, setNoiseLevelRaw] = useState(noiseLevel); + + useEffect(() => { + setNoiseLevelRaw(noiseLevel); + }, [noiseLevel]); + + useEffect(() => { + if (noiseLevel < 0 || noiseLevel > 1) { + setNoiseLevel(Math.max(0, Math.min(1, noiseLevel))); + } + }, [noiseLevel, setNoiseLevel]); + + return ( + <> +

{t("settings.noise_suppression_header")}

+ + + setNoiseEnabled(b.target.checked)} + /> + + + {noiseEnabled && ( +
+ +

{t("settings.noise_suppression_level_description")}

+ { + if (!isNaN(value)) { + setNoiseLevelRaw(value); + } + }} + onValueCommit={(value): void => { + if (!isNaN(value)) { + setNoiseLevel(value); + } + }} + min={0} + max={1} + step={0.05} + /> +
+ )} + + ); + }; + const devices = useMediaDevices(); useEffect(() => { if (open) devices.requestDeviceNames(); @@ -164,6 +227,10 @@ export const SettingsModal: FC = ({ step={0.01} /> + + + + ), diff --git a/src/settings/settings.ts b/src/settings/settings.ts index 917c79f1..9e27186d 100644 --- a/src/settings/settings.ts +++ b/src/settings/settings.ts @@ -122,6 +122,16 @@ export const soundEffectVolume = new Setting( export const muteAllAudio = new Setting("mute-all-audio", false); +export const noiseSuppressionEnabled = new Setting( + "noise-suppression-enabled", + true, +); + +export const noiseSuppressionLevel = new Setting( + "noise-suppression-level", + 0.75, +); + export const alwaysShowSelf = new Setting("always-show-self", true); export const alwaysShowIphoneEarpiece = new Setting(