diff --git a/src/MediaDeviceHandler.ts b/src/MediaDeviceHandler.ts index 59f624f08087..3c6c5f5051e9 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("webrtc_audio_autoGainControl"), + echoCancellation: SettingsStore.getValue("webrtc_audio_echoCancellation"), + noiseSuppression: SettingsStore.getValue("webrtc_audio_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("webrtc_audio_autoGainControl", null, SettingLevel.DEVICE, value); + + await MatrixClientPeg.get().getMediaHandler().setAudioSettings(this.audioSettings); + } + + public async setAudioEchoCancellation(value: boolean): Promise { + this.audioSettings.echoCancellation = value; + SettingsStore.setValue("webrtc_audio_echoCancellation", null, SettingLevel.DEVICE, value); + + await MatrixClientPeg.get().getMediaHandler().setAudioSettings(this.audioSettings); + } + + public async setAudioNoiseSuppression(value: boolean): Promise { + this.audioSettings.noiseSuppression = value; + SettingsStore.setValue("webrtc_audio_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..5c876e3b575c 100644 --- a/src/components/views/settings/tabs/user/VoiceUserSettingsTab.tsx +++ b/src/components/views/settings/tabs/user/VoiceUserSettingsTab.tsx @@ -27,6 +27,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,17 +44,24 @@ const getDefaultDevice = (devices: Array>) => { interface IState extends Record { mediaDevices: IMediaDevices; + audioAutoGainControl: boolean; + audioEchoCancellation: boolean; + audioNoiseSuppression: boolean; } export default class VoiceUserSettingsTab extends React.Component<{}, IState> { constructor(props: {}) { super(props); + const audioSettings = MediaDeviceHandler.instance.getAudioSettings(); this.state = { mediaDevices: null, [MediaDeviceKindEnum.AudioOutput]: null, [MediaDeviceKindEnum.AudioInput]: null, [MediaDeviceKindEnum.VideoInput]: null, + audioAutoGainControl: audioSettings.autoGainControl, + audioEchoCancellation: audioSettings.echoCancellation, + audioNoiseSuppression: audioSettings.noiseSuppression, }; } @@ -79,6 +87,16 @@ export default class VoiceUserSettingsTab extends React.Component<{}, IState> { } }; + private async refreshAudioSettings(): Promise { + const audioSettings = MediaDeviceHandler.instance.getAudioSettings(); + + this.setState({ + audioAutoGainControl: audioSettings.autoGainControl, + audioEchoCancellation: audioSettings.echoCancellation, + audioNoiseSuppression: audioSettings.noiseSuppression, + }); + } + private requestMediaPermissions = async (): Promise => { let constraints; let stream; @@ -197,6 +215,33 @@ 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/settings/Settings.tsx b/src/settings/Settings.tsx index 09987c438610..980d2064afce 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", }, + "webrtc_audio_autoGainControl": { + supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS, + displayName: _td("Automatic gain control"), + default: true, + }, + "webrtc_audio_echoCancellation": { + supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS, + displayName: _td("Echo cancellation"), + default: true, + }, + "webrtc_audio_noiseSuppression": { + supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS, + displayName: _td("Noise suppression"), + default: true, + }, "language": { supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS_WITH_CONFIG, default: "en",