Merge pull request #6247 from SimonBrandner/feature/media-device-handler
This commit is contained in:
commit
1fe1288427
7 changed files with 153 additions and 108 deletions
|
@ -1,85 +0,0 @@
|
||||||
/*
|
|
||||||
Copyright 2017 Michael Telatynski <7t3chguy@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";
|
|
||||||
|
|
||||||
export default {
|
|
||||||
hasAnyLabeledDevices: async function() {
|
|
||||||
const devices = await navigator.mediaDevices.enumerateDevices();
|
|
||||||
return devices.some(d => !!d.label);
|
|
||||||
},
|
|
||||||
|
|
||||||
getDevices: function() {
|
|
||||||
// Only needed for Electron atm, though should work in modern browsers
|
|
||||||
// once permission has been granted to the webapp
|
|
||||||
return navigator.mediaDevices.enumerateDevices().then(function(devices) {
|
|
||||||
const audiooutput = [];
|
|
||||||
const audioinput = [];
|
|
||||||
const videoinput = [];
|
|
||||||
|
|
||||||
devices.forEach((device) => {
|
|
||||||
switch (device.kind) {
|
|
||||||
case 'audiooutput': audiooutput.push(device); break;
|
|
||||||
case 'audioinput': audioinput.push(device); break;
|
|
||||||
case 'videoinput': videoinput.push(device); break;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// console.log("Loaded WebRTC Devices", mediaDevices);
|
|
||||||
return {
|
|
||||||
audiooutput,
|
|
||||||
audioinput,
|
|
||||||
videoinput,
|
|
||||||
};
|
|
||||||
}, (error) => { console.log('Unable to refresh WebRTC Devices: ', error); });
|
|
||||||
},
|
|
||||||
|
|
||||||
loadDevices: function() {
|
|
||||||
const audioDeviceId = SettingsStore.getValue("webrtc_audioinput");
|
|
||||||
const videoDeviceId = SettingsStore.getValue("webrtc_videoinput");
|
|
||||||
|
|
||||||
setMatrixCallAudioInput(audioDeviceId);
|
|
||||||
setMatrixCallVideoInput(videoDeviceId);
|
|
||||||
},
|
|
||||||
|
|
||||||
setAudioOutput: function(deviceId) {
|
|
||||||
SettingsStore.setValue("webrtc_audiooutput", null, SettingLevel.DEVICE, deviceId);
|
|
||||||
},
|
|
||||||
|
|
||||||
setAudioInput: function(deviceId) {
|
|
||||||
SettingsStore.setValue("webrtc_audioinput", null, SettingLevel.DEVICE, deviceId);
|
|
||||||
setMatrixCallAudioInput(deviceId);
|
|
||||||
},
|
|
||||||
|
|
||||||
setVideoInput: function(deviceId) {
|
|
||||||
SettingsStore.setValue("webrtc_videoinput", null, SettingLevel.DEVICE, deviceId);
|
|
||||||
setMatrixCallVideoInput(deviceId);
|
|
||||||
},
|
|
||||||
|
|
||||||
getAudioOutput: function() {
|
|
||||||
return SettingsStore.getValueAt(SettingLevel.DEVICE, "webrtc_audiooutput");
|
|
||||||
},
|
|
||||||
|
|
||||||
getAudioInput: function() {
|
|
||||||
return SettingsStore.getValueAt(SettingLevel.DEVICE, "webrtc_audioinput");
|
|
||||||
},
|
|
||||||
|
|
||||||
getVideoInput: function() {
|
|
||||||
return SettingsStore.getValueAt(SettingLevel.DEVICE, "webrtc_videoinput");
|
|
||||||
},
|
|
||||||
};
|
|
120
src/MediaDeviceHandler.ts
Normal file
120
src/MediaDeviceHandler.ts
Normal file
|
@ -0,0 +1,120 @@
|
||||||
|
/*
|
||||||
|
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";
|
||||||
|
import EventEmitter from 'events';
|
||||||
|
|
||||||
|
interface IMediaDevices {
|
||||||
|
audioOutput: Array<MediaDeviceInfo>;
|
||||||
|
audioInput: Array<MediaDeviceInfo>;
|
||||||
|
videoInput: Array<MediaDeviceInfo>;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async hasAnyLabeledDevices(): Promise<boolean> {
|
||||||
|
const devices = await navigator.mediaDevices.enumerateDevices();
|
||||||
|
return devices.some(d => Boolean(d.label));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async getDevices(): Promise<IMediaDevices> {
|
||||||
|
// 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();
|
||||||
|
|
||||||
|
const audioOutput = [];
|
||||||
|
const audioInput = [];
|
||||||
|
const videoInput = [];
|
||||||
|
|
||||||
|
devices.forEach((device) => {
|
||||||
|
switch (device.kind) {
|
||||||
|
case 'audiooutput': audioOutput.push(device); break;
|
||||||
|
case 'audioinput': audioInput.push(device); break;
|
||||||
|
case 'videoinput': videoInput.push(device); break;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return { audioOutput, audioInput, videoInput };
|
||||||
|
} catch (error) {
|
||||||
|
console.warn('Unable to refresh WebRTC Devices: ', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves devices from the SettingsStore and tells the js-sdk to use them
|
||||||
|
*/
|
||||||
|
public static loadDevices(): void {
|
||||||
|
const audioDeviceId = SettingsStore.getValue("webrtc_audioinput");
|
||||||
|
const videoDeviceId = SettingsStore.getValue("webrtc_videoinput");
|
||||||
|
|
||||||
|
setMatrixCallAudioInput(audioDeviceId);
|
||||||
|
setMatrixCallVideoInput(videoDeviceId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public setAudioOutput(deviceId: string): void {
|
||||||
|
SettingsStore.setValue("webrtc_audiooutput", null, SettingLevel.DEVICE, deviceId);
|
||||||
|
this.emit(MediaDeviceHandlerEvent.AudioOutputChanged, deviceId);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
public setAudioInput(deviceId: string): void {
|
||||||
|
SettingsStore.setValue("webrtc_audioinput", null, SettingLevel.DEVICE, deviceId);
|
||||||
|
setMatrixCallAudioInput(deviceId);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
public setVideoInput(deviceId: string): void {
|
||||||
|
SettingsStore.setValue("webrtc_videoinput", null, SettingLevel.DEVICE, deviceId);
|
||||||
|
setMatrixCallVideoInput(deviceId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static getAudioOutput(): string {
|
||||||
|
return SettingsStore.getValueAt(SettingLevel.DEVICE, "webrtc_audiooutput");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static getAudioInput(): string {
|
||||||
|
return SettingsStore.getValueAt(SettingLevel.DEVICE, "webrtc_audioinput");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static getVideoInput(): string {
|
||||||
|
return SettingsStore.getValueAt(SettingLevel.DEVICE, "webrtc_videoinput");
|
||||||
|
}
|
||||||
|
}
|
|
@ -22,7 +22,7 @@ import { MatrixClient } from 'matrix-js-sdk/src/client';
|
||||||
|
|
||||||
import {Key} from '../../Keyboard';
|
import {Key} from '../../Keyboard';
|
||||||
import PageTypes from '../../PageTypes';
|
import PageTypes from '../../PageTypes';
|
||||||
import CallMediaHandler from '../../CallMediaHandler';
|
import MediaDeviceHandler from '../../MediaDeviceHandler';
|
||||||
import { fixupColorFonts } from '../../utils/FontManager';
|
import { fixupColorFonts } from '../../utils/FontManager';
|
||||||
import * as sdk from '../../index';
|
import * as sdk from '../../index';
|
||||||
import dis from '../../dispatcher/dispatcher';
|
import dis from '../../dispatcher/dispatcher';
|
||||||
|
@ -167,7 +167,7 @@ class LoggedInView extends React.Component<IProps, IState> {
|
||||||
// stash the MatrixClient in case we log out before we are unmounted
|
// stash the MatrixClient in case we log out before we are unmounted
|
||||||
this._matrixClient = this.props.matrixClient;
|
this._matrixClient = this.props.matrixClient;
|
||||||
|
|
||||||
CallMediaHandler.loadDevices();
|
MediaDeviceHandler.loadDevices();
|
||||||
|
|
||||||
fixupColorFonts();
|
fixupColorFonts();
|
||||||
|
|
||||||
|
|
|
@ -30,7 +30,7 @@ import RecordingPlayback from "../voice_messages/RecordingPlayback";
|
||||||
import {MsgType} from "matrix-js-sdk/src/@types/event";
|
import {MsgType} from "matrix-js-sdk/src/@types/event";
|
||||||
import Modal from "../../../Modal";
|
import Modal from "../../../Modal";
|
||||||
import ErrorDialog from "../dialogs/ErrorDialog";
|
import ErrorDialog from "../dialogs/ErrorDialog";
|
||||||
import CallMediaHandler from "../../../CallMediaHandler";
|
import MediaDeviceHandler from "../../../MediaDeviceHandler";
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
room: Room;
|
room: Room;
|
||||||
|
@ -129,8 +129,8 @@ export default class VoiceRecordComposerTile extends React.PureComponent<IProps,
|
||||||
// Do a sanity test to ensure we're about to grab a valid microphone reference. Things might
|
// Do a sanity test to ensure we're about to grab a valid microphone reference. Things might
|
||||||
// change between this and recording, but at least we will have tried.
|
// change between this and recording, but at least we will have tried.
|
||||||
try {
|
try {
|
||||||
const devices = await CallMediaHandler.getDevices();
|
const devices = await MediaDeviceHandler.getDevices();
|
||||||
if (!devices?.['audioinput']?.length) {
|
if (!devices?.['audioInput']?.length) {
|
||||||
Modal.createTrackedDialog('No Microphone Error', '', ErrorDialog, {
|
Modal.createTrackedDialog('No Microphone Error', '', ErrorDialog, {
|
||||||
title: _t("No microphone found"),
|
title: _t("No microphone found"),
|
||||||
description: <>
|
description: <>
|
||||||
|
|
|
@ -18,7 +18,7 @@ limitations under the License.
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import {_t} from "../../../../../languageHandler";
|
import {_t} from "../../../../../languageHandler";
|
||||||
import SdkConfig from "../../../../../SdkConfig";
|
import SdkConfig from "../../../../../SdkConfig";
|
||||||
import CallMediaHandler from "../../../../../CallMediaHandler";
|
import MediaDeviceHandler from "../../../../../MediaDeviceHandler";
|
||||||
import Field from "../../../elements/Field";
|
import Field from "../../../elements/Field";
|
||||||
import AccessibleButton from "../../../elements/AccessibleButton";
|
import AccessibleButton from "../../../elements/AccessibleButton";
|
||||||
import {MatrixClientPeg} from "../../../../../MatrixClientPeg";
|
import {MatrixClientPeg} from "../../../../../MatrixClientPeg";
|
||||||
|
@ -41,7 +41,7 @@ export default class VoiceUserSettingsTab extends React.Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
async componentDidMount() {
|
async componentDidMount() {
|
||||||
const canSeeDeviceLabels = await CallMediaHandler.hasAnyLabeledDevices();
|
const canSeeDeviceLabels = await MediaDeviceHandler.hasAnyLabeledDevices();
|
||||||
if (canSeeDeviceLabels) {
|
if (canSeeDeviceLabels) {
|
||||||
this._refreshMediaDevices();
|
this._refreshMediaDevices();
|
||||||
}
|
}
|
||||||
|
@ -49,10 +49,10 @@ export default class VoiceUserSettingsTab extends React.Component {
|
||||||
|
|
||||||
_refreshMediaDevices = async (stream) => {
|
_refreshMediaDevices = async (stream) => {
|
||||||
this.setState({
|
this.setState({
|
||||||
mediaDevices: await CallMediaHandler.getDevices(),
|
mediaDevices: await MediaDeviceHandler.getDevices(),
|
||||||
activeAudioOutput: CallMediaHandler.getAudioOutput(),
|
activeAudioOutput: MediaDeviceHandler.getAudioOutput(),
|
||||||
activeAudioInput: CallMediaHandler.getAudioInput(),
|
activeAudioInput: MediaDeviceHandler.getAudioInput(),
|
||||||
activeVideoInput: CallMediaHandler.getVideoInput(),
|
activeVideoInput: MediaDeviceHandler.getVideoInput(),
|
||||||
});
|
});
|
||||||
if (stream) {
|
if (stream) {
|
||||||
// kill stream (after we've enumerated the devices, otherwise we'd get empty labels again)
|
// kill stream (after we've enumerated the devices, otherwise we'd get empty labels again)
|
||||||
|
@ -100,21 +100,21 @@ export default class VoiceUserSettingsTab extends React.Component {
|
||||||
};
|
};
|
||||||
|
|
||||||
_setAudioOutput = (e) => {
|
_setAudioOutput = (e) => {
|
||||||
CallMediaHandler.setAudioOutput(e.target.value);
|
MediaDeviceHandler.instance.setAudioOutput(e.target.value);
|
||||||
this.setState({
|
this.setState({
|
||||||
activeAudioOutput: e.target.value,
|
activeAudioOutput: e.target.value,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
_setAudioInput = (e) => {
|
_setAudioInput = (e) => {
|
||||||
CallMediaHandler.setAudioInput(e.target.value);
|
MediaDeviceHandler.instance.setAudioInput(e.target.value);
|
||||||
this.setState({
|
this.setState({
|
||||||
activeAudioInput: e.target.value,
|
activeAudioInput: e.target.value,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
_setVideoInput = (e) => {
|
_setVideoInput = (e) => {
|
||||||
CallMediaHandler.setVideoInput(e.target.value);
|
MediaDeviceHandler.instance.setVideoInput(e.target.value);
|
||||||
this.setState({
|
this.setState({
|
||||||
activeVideoInput: e.target.value,
|
activeVideoInput: e.target.value,
|
||||||
});
|
});
|
||||||
|
@ -171,7 +171,7 @@ export default class VoiceUserSettingsTab extends React.Component {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const audioOutputs = this.state.mediaDevices.audiooutput.slice(0);
|
const audioOutputs = this.state.mediaDevices.audioOutput.slice(0);
|
||||||
if (audioOutputs.length > 0) {
|
if (audioOutputs.length > 0) {
|
||||||
const defaultDevice = getDefaultDevice(audioOutputs);
|
const defaultDevice = getDefaultDevice(audioOutputs);
|
||||||
speakerDropdown = (
|
speakerDropdown = (
|
||||||
|
@ -183,7 +183,7 @@ export default class VoiceUserSettingsTab extends React.Component {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const audioInputs = this.state.mediaDevices.audioinput.slice(0);
|
const audioInputs = this.state.mediaDevices.audioInput.slice(0);
|
||||||
if (audioInputs.length > 0) {
|
if (audioInputs.length > 0) {
|
||||||
const defaultDevice = getDefaultDevice(audioInputs);
|
const defaultDevice = getDefaultDevice(audioInputs);
|
||||||
microphoneDropdown = (
|
microphoneDropdown = (
|
||||||
|
@ -195,7 +195,7 @@ export default class VoiceUserSettingsTab extends React.Component {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const videoInputs = this.state.mediaDevices.videoinput.slice(0);
|
const videoInputs = this.state.mediaDevices.videoInput.slice(0);
|
||||||
if (videoInputs.length > 0) {
|
if (videoInputs.length > 0) {
|
||||||
const defaultDevice = getDefaultDevice(videoInputs);
|
const defaultDevice = getDefaultDevice(videoInputs);
|
||||||
webcamDropdown = (
|
webcamDropdown = (
|
||||||
|
|
|
@ -17,7 +17,7 @@ limitations under the License.
|
||||||
import React, {createRef} from 'react';
|
import React, {createRef} from 'react';
|
||||||
import { CallFeed, CallFeedEvent } from 'matrix-js-sdk/src/webrtc/callFeed';
|
import { CallFeed, CallFeedEvent } from 'matrix-js-sdk/src/webrtc/callFeed';
|
||||||
import { logger } from 'matrix-js-sdk/src/logger';
|
import { logger } from 'matrix-js-sdk/src/logger';
|
||||||
import CallMediaHandler from "../../../CallMediaHandler";
|
import MediaDeviceHandler, { MediaDeviceHandlerEvent } from "../../../MediaDeviceHandler";
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
feed: CallFeed,
|
feed: CallFeed,
|
||||||
|
@ -27,19 +27,25 @@ export default class AudioFeed extends React.Component<IProps> {
|
||||||
private element = createRef<HTMLAudioElement>();
|
private element = createRef<HTMLAudioElement>();
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
|
MediaDeviceHandler.instance.addListener(
|
||||||
|
MediaDeviceHandlerEvent.AudioOutputChanged,
|
||||||
|
this.onAudioOutputChanged,
|
||||||
|
);
|
||||||
this.props.feed.addListener(CallFeedEvent.NewStream, this.onNewStream);
|
this.props.feed.addListener(CallFeedEvent.NewStream, this.onNewStream);
|
||||||
this.playMedia();
|
this.playMedia();
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillUnmount() {
|
componentWillUnmount() {
|
||||||
|
MediaDeviceHandler.instance.removeListener(
|
||||||
|
MediaDeviceHandlerEvent.AudioOutputChanged,
|
||||||
|
this.onAudioOutputChanged,
|
||||||
|
);
|
||||||
this.props.feed.removeListener(CallFeedEvent.NewStream, this.onNewStream);
|
this.props.feed.removeListener(CallFeedEvent.NewStream, this.onNewStream);
|
||||||
this.stopMedia();
|
this.stopMedia();
|
||||||
}
|
}
|
||||||
|
|
||||||
private playMedia() {
|
private onAudioOutputChanged = (audioOutput: string) => {
|
||||||
const element = this.element.current;
|
const element = this.element.current;
|
||||||
const audioOutput = CallMediaHandler.getAudioOutput();
|
|
||||||
|
|
||||||
if (audioOutput) {
|
if (audioOutput) {
|
||||||
try {
|
try {
|
||||||
// This seems quite unreliable in Chrome, although I haven't yet managed to make a jsfiddle where
|
// 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);
|
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.muted = false;
|
||||||
element.srcObject = this.props.feed.stream;
|
element.srcObject = this.props.feed.stream;
|
||||||
element.autoplay = true;
|
element.autoplay = true;
|
||||||
|
|
|
@ -17,7 +17,7 @@ limitations under the License.
|
||||||
import * as Recorder from 'opus-recorder';
|
import * as Recorder from 'opus-recorder';
|
||||||
import encoderPath from 'opus-recorder/dist/encoderWorker.min.js';
|
import encoderPath from 'opus-recorder/dist/encoderWorker.min.js';
|
||||||
import {MatrixClient} from "matrix-js-sdk/src/client";
|
import {MatrixClient} from "matrix-js-sdk/src/client";
|
||||||
import CallMediaHandler from "../CallMediaHandler";
|
import MediaDeviceHandler from "../MediaDeviceHandler";
|
||||||
import {SimpleObservable} from "matrix-widget-api";
|
import {SimpleObservable} from "matrix-widget-api";
|
||||||
import {clamp, percentageOf, percentageWithin} from "../utils/numbers";
|
import {clamp, percentageOf, percentageWithin} from "../utils/numbers";
|
||||||
import EventEmitter from "events";
|
import EventEmitter from "events";
|
||||||
|
@ -97,7 +97,7 @@ export class VoiceRecording extends EventEmitter implements IDestroyable {
|
||||||
audio: {
|
audio: {
|
||||||
channelCount: CHANNELS,
|
channelCount: CHANNELS,
|
||||||
noiseSuppression: true, // browsers ignore constraints they can't honour
|
noiseSuppression: true, // browsers ignore constraints they can't honour
|
||||||
deviceId: CallMediaHandler.getAudioInput(),
|
deviceId: MediaDeviceHandler.getAudioInput(),
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
this.recorderContext = createAudioContext({
|
this.recorderContext = createAudioContext({
|
||||||
|
|
Loading…
Reference in a new issue