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 commit 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 <laszlo.varady@protonmail.com>
  • Loading branch information
MrAnno committed Jun 6, 2022
1 parent e896acb commit 34ca8e2
Show file tree
Hide file tree
Showing 4 changed files with 106 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("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 {
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("webrtc_audio_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("webrtc_audio_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("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");
}
Expand Down
45 changes: 45 additions & 0 deletions src/components/views/settings/tabs/user/VoiceUserSettingsTab.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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<Partial<MediaDeviceInfo>>) => {
Expand All @@ -43,17 +44,24 @@ const getDefaultDevice = (devices: Array<Partial<MediaDeviceInfo>>) => {

interface IState extends Record<MediaDeviceKindEnum, string> {
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,
};
}

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

private async refreshAudioSettings(): Promise<void> {
const audioSettings = MediaDeviceHandler.instance.getAudioSettings();

this.setState({
audioAutoGainControl: audioSettings.autoGainControl,
audioEchoCancellation: audioSettings.echoCancellation,
audioNoiseSuppression: audioSettings.noiseSuppression,
});
}

private requestMediaPermissions = async (): Promise<void> => {
let constraints;
let stream;
Expand Down Expand Up @@ -197,6 +215,33 @@ 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.audioAutoGainControl}
onChange={(v) => {
MediaDeviceHandler.instance.setAudioAutoGainControl(v);
this.refreshAudioSettings();
}}
label={_t("Automatic gain control")}
/>
<LabelledToggleSwitch
value={this.state.audioEchoCancellation}
onChange={(v) => {
MediaDeviceHandler.instance.setAudioEchoCancellation(v);
this.refreshAudioSettings();
}}
label={_t("Echo cancellation")}
/>
<LabelledToggleSwitch
value={this.state.audioNoiseSuppression}
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 @@ -944,6 +944,9 @@
"Use a system font": "Use a system font",
"System font name": "System font name",
"Allow Peer-to-Peer for 1:1 calls (if you enable this, the other party might be able to see your IP address)": "Allow Peer-to-Peer for 1:1 calls (if you enable this, the other party might be able to see your IP address)",
"Automatic gain control": "Automatic gain control",
"Echo cancellation": "Echo cancellation",
"Noise suppression": "Noise suppression",
"Send analytics data": "Send analytics data",
"Never send encrypted messages to unverified sessions from this session": "Never send encrypted messages to unverified sessions from this session",
"Never send encrypted messages to unverified sessions in this room from this session": "Never send encrypted messages to unverified sessions in this room from this session",
Expand Down Expand Up @@ -1552,6 +1555,7 @@
"Voice & Video": "Voice & Video",
"Voice settings": "Voice settings",
"Video settings": "Video settings",
"Voice processing": "Voice processing",
"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
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",
},
"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",
Expand Down

0 comments on commit 34ca8e2

Please sign in to comment.