2021-06-23 07:26:33 +00:00
|
|
|
/*
|
|
|
|
Copyright 2017 Michael Telatynski <7t3chguy@gmail.com>
|
|
|
|
Copyright 2021 Šimon Brandner <simon.bra.ag@gmail.com>
|
|
|
|
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
you may not use this file except in compliance with the License.
|
|
|
|
You may obtain a copy of the License at
|
|
|
|
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
See the License for the specific language governing permissions and
|
|
|
|
limitations under the License.
|
|
|
|
*/
|
|
|
|
|
|
|
|
import SettingsStore from "./settings/SettingsStore";
|
|
|
|
import { SettingLevel } from "./settings/SettingLevel";
|
|
|
|
import { setMatrixCallAudioInput, setMatrixCallVideoInput } from "matrix-js-sdk/src/matrix";
|
2021-06-23 07:56:37 +00:00
|
|
|
import EventEmitter from 'events';
|
2021-06-23 07:26:33 +00:00
|
|
|
|
2021-07-09 11:08:39 +00:00
|
|
|
// XXX: MediaDeviceKind is a union type, so we make our own enum
|
|
|
|
export enum MediaDeviceKindEnum {
|
|
|
|
AudioOutput = "audiooutput",
|
|
|
|
AudioInput = "audioinput",
|
|
|
|
VideoInput = "videoinput",
|
2021-06-23 07:26:33 +00:00
|
|
|
}
|
|
|
|
|
2021-07-09 11:08:39 +00:00
|
|
|
export type IMediaDevices = Record<MediaDeviceKindEnum, Array<MediaDeviceInfo>>;
|
|
|
|
|
2021-06-23 07:56:37 +00:00
|
|
|
export enum MediaDeviceHandlerEvent {
|
|
|
|
AudioOutputChanged = "audio_output_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;
|
|
|
|
}
|
|
|
|
|
2021-06-23 08:27:51 +00:00
|
|
|
public static async hasAnyLabeledDevices(): Promise<boolean> {
|
2021-06-23 07:26:33 +00:00
|
|
|
const devices = await navigator.mediaDevices.enumerateDevices();
|
|
|
|
return devices.some(d => Boolean(d.label));
|
|
|
|
}
|
|
|
|
|
2021-06-23 08:27:51 +00:00
|
|
|
public static async getDevices(): Promise<IMediaDevices> {
|
2021-06-23 07:26:33 +00:00
|
|
|
// Only needed for Electron atm, though should work in modern browsers
|
|
|
|
// once permission has been granted to the webapp
|
|
|
|
|
|
|
|
try {
|
|
|
|
const devices = await navigator.mediaDevices.enumerateDevices();
|
2021-07-09 11:08:39 +00:00
|
|
|
const output = {
|
|
|
|
[MediaDeviceKindEnum.AudioOutput]: [],
|
|
|
|
[MediaDeviceKindEnum.AudioInput]: [],
|
|
|
|
[MediaDeviceKindEnum.VideoInput]: [],
|
|
|
|
};
|
|
|
|
|
|
|
|
devices.forEach((device) => output[device.kind].push(device));
|
|
|
|
return output;
|
2021-06-23 07:26:33 +00:00
|
|
|
} catch (error) {
|
2021-06-23 08:43:49 +00:00
|
|
|
console.warn('Unable to refresh WebRTC Devices: ', error);
|
2021-06-23 07:26:33 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-06-23 08:37:15 +00:00
|
|
|
/**
|
|
|
|
* Retrieves devices from the SettingsStore and tells the js-sdk to use them
|
|
|
|
*/
|
2021-06-23 08:27:51 +00:00
|
|
|
public static loadDevices(): void {
|
2021-06-23 07:26:33 +00:00
|
|
|
const audioDeviceId = SettingsStore.getValue("webrtc_audioinput");
|
|
|
|
const videoDeviceId = SettingsStore.getValue("webrtc_videoinput");
|
|
|
|
|
|
|
|
setMatrixCallAudioInput(audioDeviceId);
|
|
|
|
setMatrixCallVideoInput(videoDeviceId);
|
|
|
|
}
|
|
|
|
|
2021-06-23 08:27:51 +00:00
|
|
|
public setAudioOutput(deviceId: string): void {
|
2021-06-23 07:26:33 +00:00
|
|
|
SettingsStore.setValue("webrtc_audiooutput", null, SettingLevel.DEVICE, deviceId);
|
2021-06-23 07:56:37 +00:00
|
|
|
this.emit(MediaDeviceHandlerEvent.AudioOutputChanged, deviceId);
|
2021-06-23 07:26:33 +00:00
|
|
|
}
|
|
|
|
|
2021-06-23 08:37:15 +00:00
|
|
|
/**
|
|
|
|
* This will not change the device that a potential call uses. The call will
|
|
|
|
* need to be ended and started again for this change to take effect
|
|
|
|
* @param {string} deviceId
|
|
|
|
*/
|
2021-06-23 08:27:51 +00:00
|
|
|
public setAudioInput(deviceId: string): void {
|
2021-06-23 07:26:33 +00:00
|
|
|
SettingsStore.setValue("webrtc_audioinput", null, SettingLevel.DEVICE, deviceId);
|
|
|
|
setMatrixCallAudioInput(deviceId);
|
|
|
|
}
|
|
|
|
|
2021-06-23 08:37:15 +00:00
|
|
|
/**
|
|
|
|
* This will not change the device that a potential call uses. The call will
|
|
|
|
* need to be ended and started again for this change to take effect
|
|
|
|
* @param {string} deviceId
|
|
|
|
*/
|
2021-06-23 08:27:51 +00:00
|
|
|
public setVideoInput(deviceId: string): void {
|
2021-06-23 07:26:33 +00:00
|
|
|
SettingsStore.setValue("webrtc_videoinput", null, SettingLevel.DEVICE, deviceId);
|
|
|
|
setMatrixCallVideoInput(deviceId);
|
|
|
|
}
|
|
|
|
|
2021-07-09 12:13:31 +00:00
|
|
|
public setDevice(deviceId: string, kind: MediaDeviceKindEnum): void {
|
|
|
|
switch (kind) {
|
|
|
|
case MediaDeviceKindEnum.AudioOutput: this.setAudioOutput(deviceId); break;
|
|
|
|
case MediaDeviceKindEnum.AudioInput: this.setAudioInput(deviceId); break;
|
|
|
|
case MediaDeviceKindEnum.VideoInput: this.setVideoInput(deviceId); break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-06-23 08:27:51 +00:00
|
|
|
public static getAudioOutput(): string {
|
2021-06-23 07:26:33 +00:00
|
|
|
return SettingsStore.getValueAt(SettingLevel.DEVICE, "webrtc_audiooutput");
|
|
|
|
}
|
|
|
|
|
2021-06-23 08:27:51 +00:00
|
|
|
public static getAudioInput(): string {
|
2021-06-23 07:26:33 +00:00
|
|
|
return SettingsStore.getValueAt(SettingLevel.DEVICE, "webrtc_audioinput");
|
|
|
|
}
|
|
|
|
|
2021-06-23 08:27:51 +00:00
|
|
|
public static getVideoInput(): string {
|
2021-06-23 07:26:33 +00:00
|
|
|
return SettingsStore.getValueAt(SettingLevel.DEVICE, "webrtc_videoinput");
|
|
|
|
}
|
|
|
|
}
|