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..92c3b3c56c75 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,24 @@ 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",