From afc256aebebe34d2ce7016388927765e7aeb7286 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A1szl=C3=B3=20V=C3=A1rady?= Date: Sun, 5 Jun 2022 12:05:43 +0200 Subject: [PATCH] Add advanced audio settings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit autoGainControl, echoCancellation, and noiseSuppression are audio processing options that are usually enabled by default on WebRTC input tracks. This commits adds the possibility to enable/disable them, as they can be undesirable in some cases (audiophile use cases). For example, one might want to stream electronic dance music, which is basically noise, so it should not be suppressed in that specific case. Signed-off-by: László Várady --- src/MediaDeviceHandler.ts | 42 +++++++++++++++++++ .../tabs/user/VoiceUserSettingsTab.tsx | 32 ++++++++++++++ src/i18n/strings/en_EN.json | 4 ++ src/i18n/strings/en_US.json | 4 ++ src/i18n/strings/hu.json | 4 ++ src/settings/Settings.tsx | 15 +++++++ 6 files changed, 101 insertions(+) diff --git a/src/MediaDeviceHandler.ts b/src/MediaDeviceHandler.ts index 59f624f08087..c455c6661927 100644 --- a/src/MediaDeviceHandler.ts +++ b/src/MediaDeviceHandler.ts @@ -17,6 +17,7 @@ limitations under the License. import EventEmitter from 'events'; import { logger } from "matrix-js-sdk/src/logger"; +import { AudioSettings } from "matrix-js-sdk/src/webrtc/mediaHandler"; import SettingsStore from "./settings/SettingsStore"; import { SettingLevel } from "./settings/SettingLevel"; @@ -38,6 +39,8 @@ export enum MediaDeviceHandlerEvent { export default class MediaDeviceHandler extends EventEmitter { private static internalInstance; + private audioSettings: AudioSettings; + public static get instance(): MediaDeviceHandler { if (!MediaDeviceHandler.internalInstance) { MediaDeviceHandler.internalInstance = new MediaDeviceHandler(); @@ -78,6 +81,20 @@ export default class MediaDeviceHandler extends EventEmitter { await MatrixClientPeg.get().getMediaHandler().setAudioInput(audioDeviceId); await MatrixClientPeg.get().getMediaHandler().setVideoInput(videoDeviceId); + await MatrixClientPeg.get().getMediaHandler().setAudioSettings(MediaDeviceHandler.loadAudioSettings()); + } + + private static loadAudioSettings(): AudioSettings { + return { + autoGainControl: SettingsStore.getValue("webRtcAudio_autoGainControl"), + echoCancellation: SettingsStore.getValue("webRtcAudio_echoCancellation"), + noiseSuppression: SettingsStore.getValue("webRtcAudio_noiseSuppression"), + }; + } + + public constructor() { + super(); + this.audioSettings = MediaDeviceHandler.loadAudioSettings(); } public setAudioOutput(deviceId: string): void { @@ -113,6 +130,31 @@ export default class MediaDeviceHandler extends EventEmitter { } } + public async setAudioAutoGainControl(value: boolean): Promise { + this.audioSettings.autoGainControl = value; + SettingsStore.setValue("webRtcAudio_autoGainControl", null, SettingLevel.DEVICE, value); + + await MatrixClientPeg.get().getMediaHandler().setAudioSettings(this.audioSettings); + } + + public async setAudioEchoCancellation(value: boolean): Promise { + this.audioSettings.echoCancellation = value; + SettingsStore.setValue("webRtcAudio_echoCancellation", null, SettingLevel.DEVICE, value); + + await MatrixClientPeg.get().getMediaHandler().setAudioSettings(this.audioSettings); + } + + public async setAudioNoiseSuppression(value: boolean): Promise { + this.audioSettings.noiseSuppression = value; + SettingsStore.setValue("webRtcAudio_noiseSuppression", null, SettingLevel.DEVICE, value); + + await MatrixClientPeg.get().getMediaHandler().setAudioSettings(this.audioSettings); + } + + public getAudioSettings(): AudioSettings { + return this.audioSettings; + } + public static getAudioOutput(): string { return SettingsStore.getValueAt(SettingLevel.DEVICE, "webrtc_audiooutput"); } diff --git a/src/components/views/settings/tabs/user/VoiceUserSettingsTab.tsx b/src/components/views/settings/tabs/user/VoiceUserSettingsTab.tsx index e027853e140e..07427bec2b30 100644 --- a/src/components/views/settings/tabs/user/VoiceUserSettingsTab.tsx +++ b/src/components/views/settings/tabs/user/VoiceUserSettingsTab.tsx @@ -17,6 +17,7 @@ limitations under the License. import React from 'react'; import { logger } from "matrix-js-sdk/src/logger"; +import { AudioSettings } from "matrix-js-sdk/src/webrtc/mediaHandler"; import { _t } from "../../../../../languageHandler"; import SdkConfig from "../../../../../SdkConfig"; @@ -27,6 +28,7 @@ import { MatrixClientPeg } from "../../../../../MatrixClientPeg"; import Modal from "../../../../../Modal"; import { SettingLevel } from "../../../../../settings/SettingLevel"; import SettingsFlag from '../../../elements/SettingsFlag'; +import LabelledToggleSwitch from "../../../elements/LabelledToggleSwitch"; import ErrorDialog from '../../../dialogs/ErrorDialog'; const getDefaultDevice = (devices: Array>) => { @@ -43,6 +45,7 @@ const getDefaultDevice = (devices: Array>) => { interface IState extends Record { mediaDevices: IMediaDevices; + audioSettings: AudioSettings; } export default class VoiceUserSettingsTab extends React.Component<{}, IState> { @@ -54,6 +57,7 @@ export default class VoiceUserSettingsTab extends React.Component<{}, IState> { [MediaDeviceKindEnum.AudioOutput]: null, [MediaDeviceKindEnum.AudioInput]: null, [MediaDeviceKindEnum.VideoInput]: null, + audioSettings: MediaDeviceHandler.instance.getAudioSettings(), }; } @@ -79,6 +83,10 @@ export default class VoiceUserSettingsTab extends React.Component<{}, IState> { } }; + private async refreshAudioSettings(): Promise { + this.setState({ audioSettings: MediaDeviceHandler.instance.getAudioSettings() }); + } + private requestMediaPermissions = async (): Promise => { let constraints; let stream; @@ -197,6 +205,30 @@ export default class VoiceUserSettingsTab extends React.Component<{}, IState> {
{ _t("Advanced") }
+ { _t("Voice processing") } +
+ { + MediaDeviceHandler.instance.setAudioAutoGainControl(v); this.refreshAudioSettings(); + }} + label={_t("Automatic gain control")} + /> + { + MediaDeviceHandler.instance.setAudioEchoCancellation(v); this.refreshAudioSettings(); + }} + label={_t("Echo cancellation")} + /> + { + MediaDeviceHandler.instance.setAudioNoiseSuppression(v); this.refreshAudioSettings(); + }} + label={_t("Noise suppression")} + /> +
{ _t("Connection") } Warning: Upgrading a room will not automatically migrate room members to the new version of the room. We'll post a link to the new room in the old version of the room - room members will have to click this link to join the new room.": "Warning: Upgrading a room will not automatically migrate room members to the new version of the room. We'll post a link to the new room in the old version of the room - room members will have to click this link to join the new room.", diff --git a/src/i18n/strings/en_US.json b/src/i18n/strings/en_US.json index 2e24f3e76afc..1802e1da4c80 100644 --- a/src/i18n/strings/en_US.json +++ b/src/i18n/strings/en_US.json @@ -13,6 +13,10 @@ "Advanced": "Advanced", "Voice settings": "Voice settings", "Video settings": "Video settings", + "Voice processing": "Voice processing", + "Automatic gain control": "Automatic gain control", + "Echo cancellation": "Echo cancellation", + "Noise suppression": "Noise suppression", "Connection": "Connection", "Always show message timestamps": "Always show message timestamps", "Authentication": "Authentication", diff --git a/src/i18n/strings/hu.json b/src/i18n/strings/hu.json index fd5374e1bb28..07091d9b193a 100644 --- a/src/i18n/strings/hu.json +++ b/src/i18n/strings/hu.json @@ -706,6 +706,10 @@ "Voice & Video": "Hang és videó", "Voice settings": "Hangbeállítások", "Video settings": "Videóbeállítások", + "Voice processing": "Hangfeldolgozás", + "Automatic gain control": "Automatikus erősségszabályozás", + "Echo cancellation": "Visszhangcsökkentés", + "Noise suppression": "Zajcsökkentés", "Connection": "Kapcsolat", "Main address": "Fő cím", "Room avatar": "Szoba képe", diff --git a/src/settings/Settings.tsx b/src/settings/Settings.tsx index 09987c438610..af440d5817e8 100644 --- a/src/settings/Settings.tsx +++ b/src/settings/Settings.tsx @@ -645,6 +645,21 @@ export const SETTINGS: {[setting: string]: ISetting} = { supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS, default: "default", }, + "webRtcAudio_autoGainControl": { + supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS, + displayName: _td("Automatic gain control"), + default: true, + }, + "webRtcAudio_echoCancellation": { + supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS, + displayName: _td("Echo cancellation"), + default: true, + }, + "webRtcAudio_noiseSuppression": { + supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS, + displayName: _td("Noise suppression"), + default: true, + }, "language": { supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS_WITH_CONFIG, default: "en",