Skip to content
This repository has been archived by the owner on Sep 11, 2024. It is now read-only.

Commit

Permalink
Add advanced audio settings
Browse files Browse the repository at this point in the history
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 <[email protected]>
  • Loading branch information
MrAnno committed Jun 5, 2022
1 parent d1d4396 commit 6c8dbfc
Show file tree
Hide file tree
Showing 6 changed files with 95 additions and 0 deletions.
42 changes: 42 additions & 0 deletions src/MediaDeviceHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand All @@ -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();
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -113,6 +130,31 @@ export default class MediaDeviceHandler extends EventEmitter {
}
}

public async setAudioAutoGainControl(value: boolean): Promise<void> {
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<void> {
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<void> {
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");
}
Expand Down
26 changes: 26 additions & 0 deletions src/components/views/settings/tabs/user/VoiceUserSettingsTab.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand All @@ -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<Partial<MediaDeviceInfo>>) => {
Expand All @@ -43,6 +45,7 @@ const getDefaultDevice = (devices: Array<Partial<MediaDeviceInfo>>) => {

interface IState extends Record<MediaDeviceKindEnum, string> {
mediaDevices: IMediaDevices;
audioSettings: AudioSettings;
}

export default class VoiceUserSettingsTab extends React.Component<{}, IState> {
Expand All @@ -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(),
};
}

Expand All @@ -79,6 +83,10 @@ export default class VoiceUserSettingsTab extends React.Component<{}, IState> {
}
};

private async refreshAudioSettings(): Promise<void> {
this.setState({ audioSettings: MediaDeviceHandler.instance.getAudioSettings() });
}

private requestMediaPermissions = async (): Promise<void> => {
let constraints;
let stream;
Expand Down Expand Up @@ -197,6 +205,24 @@ export default class VoiceUserSettingsTab extends React.Component<{}, IState> {

<div className="mx_SettingsTab_heading">{ _t("Advanced") }</div>
<div className="mx_SettingsTab_section">
<span className="mx_SettingsTab_subheading">{ _t("Voice processing") }</span>
<div className="mx_SettingsTab_section">
<LabelledToggleSwitch
value={this.state.audioSettings.autoGainControl}
onChange={(v) => { MediaDeviceHandler.instance.setAudioAutoGainControl(v); this.refreshAudioSettings() }}
label={_t("Automatic gain control")}
/>
<LabelledToggleSwitch
value={this.state.audioSettings.echoCancellation}
onChange={(v) => { MediaDeviceHandler.instance.setAudioEchoCancellation(v); this.refreshAudioSettings() }}
label={_t("Echo cancellation")}
/>
<LabelledToggleSwitch
value={this.state.audioSettings.noiseSuppression}
onChange={(v) => { MediaDeviceHandler.instance.setAudioNoiseSuppression(v); this.refreshAudioSettings() }}
label={_t("Noise suppression")}
/>
</div>
<div className="mx_SettingsTab_section">
<span className="mx_SettingsTab_subheading">{ _t("Connection") }</span>
<SettingsFlag
Expand Down
4 changes: 4 additions & 0 deletions src/i18n/strings/en_EN.json
Original file line number Diff line number Diff line change
Expand Up @@ -1552,6 +1552,10 @@
"Voice & Video": "Voice & Video",
"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",
"This room is not accessible by remote Matrix servers": "This room is not accessible by remote Matrix servers",
"<b>Warning</b>: Upgrading a room will <i>not automatically migrate room members to the new version of the room.</i> 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.": "<b>Warning</b>: Upgrading a room will <i>not automatically migrate room members to the new version of the room.</i> 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.",
Expand Down
4 changes: 4 additions & 0 deletions src/i18n/strings/en_US.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
4 changes: 4 additions & 0 deletions src/i18n/strings/hu.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
15 changes: 15 additions & 0 deletions src/settings/Settings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down

0 comments on commit 6c8dbfc

Please sign in to comment.