Handle mid-call output changes

Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com>
This commit is contained in:
Šimon Brandner 2021-06-23 09:56:37 +02:00
parent 9bceb40820
commit 58151d71c5
No known key found for this signature in database
GPG key ID: 9760693FDD98A790
3 changed files with 40 additions and 11 deletions

View file

@ -18,6 +18,7 @@ limitations under the License.
import SettingsStore from "./settings/SettingsStore";
import { SettingLevel } from "./settings/SettingLevel";
import { setMatrixCallAudioInput, setMatrixCallVideoInput } from "matrix-js-sdk/src/matrix";
import EventEmitter from 'events';
interface IMediaDevices {
audioOutput: Array<MediaDeviceInfo>;
@ -25,7 +26,22 @@ interface IMediaDevices {
videoInput: Array<MediaDeviceInfo>;
}
export default class MediaDeviceHandler {
export enum MediaDeviceHandlerEvent {
AudioOutputChanged = "audio_output_changed",
AudioInputChanged = "audio_input_changed",
VideoInputChanged = "video_input_changed",
}
export default class MediaDeviceHandler extends EventEmitter {
private static internalInstance;
public static get instance(): MediaDeviceHandler {
if (!MediaDeviceHandler.internalInstance) {
MediaDeviceHandler.internalInstance = new MediaDeviceHandler();
}
return MediaDeviceHandler.internalInstance;
}
static async hasAnyLabeledDevices(): Promise<boolean> {
const devices = await navigator.mediaDevices.enumerateDevices();
return devices.some(d => Boolean(d.label));
@ -68,18 +84,21 @@ export default class MediaDeviceHandler {
setMatrixCallVideoInput(videoDeviceId);
}
static setAudioOutput(deviceId: string) {
public setAudioOutput(deviceId: string) {
SettingsStore.setValue("webrtc_audiooutput", null, SettingLevel.DEVICE, deviceId);
this.emit(MediaDeviceHandlerEvent.AudioOutputChanged, deviceId);
}
static setAudioInput(deviceId: string) {
public setAudioInput(deviceId: string) {
SettingsStore.setValue("webrtc_audioinput", null, SettingLevel.DEVICE, deviceId);
setMatrixCallAudioInput(deviceId);
this.emit(MediaDeviceHandlerEvent.AudioInputChanged, deviceId);
}
static setVideoInput(deviceId: string) {
public setVideoInput(deviceId: string) {
SettingsStore.setValue("webrtc_videoinput", null, SettingLevel.DEVICE, deviceId);
setMatrixCallVideoInput(deviceId);
this.emit(MediaDeviceHandlerEvent.VideoInputChanged, deviceId);
}
static getAudioOutput(): string {

View file

@ -100,21 +100,21 @@ export default class VoiceUserSettingsTab extends React.Component {
};
_setAudioOutput = (e) => {
MediaDeviceHandler.setAudioOutput(e.target.value);
MediaDeviceHandler.instance.setAudioOutput(e.target.value);
this.setState({
activeAudioOutput: e.target.value,
});
};
_setAudioInput = (e) => {
MediaDeviceHandler.setAudioInput(e.target.value);
MediaDeviceHandler.instance.setAudioInput(e.target.value);
this.setState({
activeAudioInput: e.target.value,
});
};
_setVideoInput = (e) => {
MediaDeviceHandler.setVideoInput(e.target.value);
MediaDeviceHandler.instance.setVideoInput(e.target.value);
this.setState({
activeVideoInput: e.target.value,
});

View file

@ -17,7 +17,7 @@ limitations under the License.
import React, {createRef} from 'react';
import { CallFeed, CallFeedEvent } from 'matrix-js-sdk/src/webrtc/callFeed';
import { logger } from 'matrix-js-sdk/src/logger';
import MediaDeviceHandler from "../../../MediaDeviceHandler";
import MediaDeviceHandler, { MediaDeviceHandlerEvent } from "../../../MediaDeviceHandler";
interface IProps {
feed: CallFeed,
@ -27,19 +27,25 @@ export default class AudioFeed extends React.Component<IProps> {
private element = createRef<HTMLAudioElement>();
componentDidMount() {
MediaDeviceHandler.instance.addListener(
MediaDeviceHandlerEvent.AudioOutputChanged,
this.onAudioOutputChanged,
);
this.props.feed.addListener(CallFeedEvent.NewStream, this.onNewStream);
this.playMedia();
}
componentWillUnmount() {
MediaDeviceHandler.instance.removeListener(
MediaDeviceHandlerEvent.AudioOutputChanged,
this.onAudioOutputChanged,
);
this.props.feed.removeListener(CallFeedEvent.NewStream, this.onNewStream);
this.stopMedia();
}
private playMedia() {
private onAudioOutputChanged = (audioOutput: string) => {
const element = this.element.current;
const audioOutput = MediaDeviceHandler.getAudioOutput();
if (audioOutput) {
try {
// This seems quite unreliable in Chrome, although I haven't yet managed to make a jsfiddle where
@ -52,7 +58,11 @@ export default class AudioFeed extends React.Component<IProps> {
logger.warn("Couldn't set requested audio output device: using default", e);
}
}
}
private playMedia() {
const element = this.element.current;
this.onAudioOutputChanged(MediaDeviceHandler.getAudioOutput());
element.muted = false;
element.srcObject = this.props.feed.stream;
element.autoplay = true;