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

Commit 6c8dbfc

Browse files
committed
Add advanced audio settings
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]>
1 parent d1d4396 commit 6c8dbfc

File tree

6 files changed

+95
-0
lines changed

6 files changed

+95
-0
lines changed

src/MediaDeviceHandler.ts

+42
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ limitations under the License.
1717

1818
import EventEmitter from 'events';
1919
import { logger } from "matrix-js-sdk/src/logger";
20+
import { AudioSettings } from "matrix-js-sdk/src/webrtc/mediaHandler";
2021

2122
import SettingsStore from "./settings/SettingsStore";
2223
import { SettingLevel } from "./settings/SettingLevel";
@@ -38,6 +39,8 @@ export enum MediaDeviceHandlerEvent {
3839
export default class MediaDeviceHandler extends EventEmitter {
3940
private static internalInstance;
4041

42+
private audioSettings: AudioSettings;
43+
4144
public static get instance(): MediaDeviceHandler {
4245
if (!MediaDeviceHandler.internalInstance) {
4346
MediaDeviceHandler.internalInstance = new MediaDeviceHandler();
@@ -78,6 +81,20 @@ export default class MediaDeviceHandler extends EventEmitter {
7881

7982
await MatrixClientPeg.get().getMediaHandler().setAudioInput(audioDeviceId);
8083
await MatrixClientPeg.get().getMediaHandler().setVideoInput(videoDeviceId);
84+
await MatrixClientPeg.get().getMediaHandler().setAudioSettings(MediaDeviceHandler.loadAudioSettings());
85+
}
86+
87+
private static loadAudioSettings(): AudioSettings {
88+
return {
89+
autoGainControl: SettingsStore.getValue("webRtcAudio_autoGainControl"),
90+
echoCancellation: SettingsStore.getValue("webRtcAudio_echoCancellation"),
91+
noiseSuppression: SettingsStore.getValue("webRtcAudio_noiseSuppression"),
92+
};
93+
}
94+
95+
public constructor() {
96+
super();
97+
this.audioSettings = MediaDeviceHandler.loadAudioSettings();
8198
}
8299

83100
public setAudioOutput(deviceId: string): void {
@@ -113,6 +130,31 @@ export default class MediaDeviceHandler extends EventEmitter {
113130
}
114131
}
115132

133+
public async setAudioAutoGainControl(value: boolean): Promise<void> {
134+
this.audioSettings.autoGainControl = value;
135+
SettingsStore.setValue("webRtcAudio_autoGainControl", null, SettingLevel.DEVICE, value);
136+
137+
await MatrixClientPeg.get().getMediaHandler().setAudioSettings(this.audioSettings);
138+
}
139+
140+
public async setAudioEchoCancellation(value: boolean): Promise<void> {
141+
this.audioSettings.echoCancellation = value;
142+
SettingsStore.setValue("webRtcAudio_echoCancellation", null, SettingLevel.DEVICE, value);
143+
144+
await MatrixClientPeg.get().getMediaHandler().setAudioSettings(this.audioSettings);
145+
}
146+
147+
public async setAudioNoiseSuppression(value: boolean): Promise<void> {
148+
this.audioSettings.noiseSuppression = value;
149+
SettingsStore.setValue("webRtcAudio_noiseSuppression", null, SettingLevel.DEVICE, value);
150+
151+
await MatrixClientPeg.get().getMediaHandler().setAudioSettings(this.audioSettings);
152+
}
153+
154+
public getAudioSettings(): AudioSettings {
155+
return this.audioSettings;
156+
}
157+
116158
public static getAudioOutput(): string {
117159
return SettingsStore.getValueAt(SettingLevel.DEVICE, "webrtc_audiooutput");
118160
}

src/components/views/settings/tabs/user/VoiceUserSettingsTab.tsx

+26
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ limitations under the License.
1717

1818
import React from 'react';
1919
import { logger } from "matrix-js-sdk/src/logger";
20+
import { AudioSettings } from "matrix-js-sdk/src/webrtc/mediaHandler";
2021

2122
import { _t } from "../../../../../languageHandler";
2223
import SdkConfig from "../../../../../SdkConfig";
@@ -27,6 +28,7 @@ import { MatrixClientPeg } from "../../../../../MatrixClientPeg";
2728
import Modal from "../../../../../Modal";
2829
import { SettingLevel } from "../../../../../settings/SettingLevel";
2930
import SettingsFlag from '../../../elements/SettingsFlag';
31+
import LabelledToggleSwitch from "../../../elements/LabelledToggleSwitch";
3032
import ErrorDialog from '../../../dialogs/ErrorDialog';
3133

3234
const getDefaultDevice = (devices: Array<Partial<MediaDeviceInfo>>) => {
@@ -43,6 +45,7 @@ const getDefaultDevice = (devices: Array<Partial<MediaDeviceInfo>>) => {
4345

4446
interface IState extends Record<MediaDeviceKindEnum, string> {
4547
mediaDevices: IMediaDevices;
48+
audioSettings: AudioSettings;
4649
}
4750

4851
export default class VoiceUserSettingsTab extends React.Component<{}, IState> {
@@ -54,6 +57,7 @@ export default class VoiceUserSettingsTab extends React.Component<{}, IState> {
5457
[MediaDeviceKindEnum.AudioOutput]: null,
5558
[MediaDeviceKindEnum.AudioInput]: null,
5659
[MediaDeviceKindEnum.VideoInput]: null,
60+
audioSettings: MediaDeviceHandler.instance.getAudioSettings(),
5761
};
5862
}
5963

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

86+
private async refreshAudioSettings(): Promise<void> {
87+
this.setState({ audioSettings: MediaDeviceHandler.instance.getAudioSettings() });
88+
}
89+
8290
private requestMediaPermissions = async (): Promise<void> => {
8391
let constraints;
8492
let stream;
@@ -197,6 +205,24 @@ export default class VoiceUserSettingsTab extends React.Component<{}, IState> {
197205

198206
<div className="mx_SettingsTab_heading">{ _t("Advanced") }</div>
199207
<div className="mx_SettingsTab_section">
208+
<span className="mx_SettingsTab_subheading">{ _t("Voice processing") }</span>
209+
<div className="mx_SettingsTab_section">
210+
<LabelledToggleSwitch
211+
value={this.state.audioSettings.autoGainControl}
212+
onChange={(v) => { MediaDeviceHandler.instance.setAudioAutoGainControl(v); this.refreshAudioSettings() }}
213+
label={_t("Automatic gain control")}
214+
/>
215+
<LabelledToggleSwitch
216+
value={this.state.audioSettings.echoCancellation}
217+
onChange={(v) => { MediaDeviceHandler.instance.setAudioEchoCancellation(v); this.refreshAudioSettings() }}
218+
label={_t("Echo cancellation")}
219+
/>
220+
<LabelledToggleSwitch
221+
value={this.state.audioSettings.noiseSuppression}
222+
onChange={(v) => { MediaDeviceHandler.instance.setAudioNoiseSuppression(v); this.refreshAudioSettings() }}
223+
label={_t("Noise suppression")}
224+
/>
225+
</div>
200226
<div className="mx_SettingsTab_section">
201227
<span className="mx_SettingsTab_subheading">{ _t("Connection") }</span>
202228
<SettingsFlag

src/i18n/strings/en_EN.json

+4
Original file line numberDiff line numberDiff line change
@@ -1552,6 +1552,10 @@
15521552
"Voice & Video": "Voice & Video",
15531553
"Voice settings": "Voice settings",
15541554
"Video settings": "Video settings",
1555+
"Voice processing": "Voice processing",
1556+
"Automatic gain control": "Automatic gain control",
1557+
"Echo cancellation": "Echo cancellation",
1558+
"Noise suppression": "Noise suppression",
15551559
"Connection": "Connection",
15561560
"This room is not accessible by remote Matrix servers": "This room is not accessible by remote Matrix servers",
15571561
"<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.",

src/i18n/strings/en_US.json

+4
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,10 @@
1313
"Advanced": "Advanced",
1414
"Voice settings": "Voice settings",
1515
"Video settings": "Video settings",
16+
"Voice processing": "Voice processing",
17+
"Automatic gain control": "Automatic gain control",
18+
"Echo cancellation": "Echo cancellation",
19+
"Noise suppression": "Noise suppression",
1620
"Connection": "Connection",
1721
"Always show message timestamps": "Always show message timestamps",
1822
"Authentication": "Authentication",

src/i18n/strings/hu.json

+4
Original file line numberDiff line numberDiff line change
@@ -706,6 +706,10 @@
706706
"Voice & Video": "Hang és videó",
707707
"Voice settings": "Hangbeállítások",
708708
"Video settings": "Videóbeállítások",
709+
"Voice processing": "Hangfeldolgozás",
710+
"Automatic gain control": "Automatikus erősségszabályozás",
711+
"Echo cancellation": "Visszhangcsökkentés",
712+
"Noise suppression": "Zajcsökkentés",
709713
"Connection": "Kapcsolat",
710714
"Main address": "Fő cím",
711715
"Room avatar": "Szoba képe",

src/settings/Settings.tsx

+15
Original file line numberDiff line numberDiff line change
@@ -645,6 +645,21 @@ export const SETTINGS: {[setting: string]: ISetting} = {
645645
supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS,
646646
default: "default",
647647
},
648+
"webRtcAudio_autoGainControl": {
649+
supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS,
650+
displayName: _td("Automatic gain control"),
651+
default: true,
652+
},
653+
"webRtcAudio_echoCancellation": {
654+
supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS,
655+
displayName: _td("Echo cancellation"),
656+
default: true,
657+
},
658+
"webRtcAudio_noiseSuppression": {
659+
supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS,
660+
displayName: _td("Noise suppression"),
661+
default: true,
662+
},
648663
"language": {
649664
supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS_WITH_CONFIG,
650665
default: "en",

0 commit comments

Comments
 (0)