2017-11-16 18:26:14 +00:00
|
|
|
/* global JitsiMeetJS */
|
|
|
|
|
2018-03-13 04:45:00 +00:00
|
|
|
import { AtlasKitThemeProvider } from '@atlaskit/theme';
|
2017-06-04 03:12:04 +00:00
|
|
|
import React from 'react';
|
|
|
|
import ReactDOM from 'react-dom';
|
|
|
|
import { I18nextProvider } from 'react-i18next';
|
|
|
|
|
2019-03-21 12:33:40 +00:00
|
|
|
import {
|
|
|
|
getAvailableDevices,
|
|
|
|
getCurrentDevices,
|
|
|
|
isDeviceChangeAvailable,
|
|
|
|
isDeviceListAvailable,
|
|
|
|
isMultipleAudioInputSupported,
|
|
|
|
setAudioInputDevice,
|
|
|
|
setAudioOutputDevice,
|
|
|
|
setVideoInputDevice
|
2019-03-28 13:08:00 +00:00
|
|
|
} from '../../../../../modules/API/external/functions';
|
2020-05-20 10:57:03 +00:00
|
|
|
import {
|
|
|
|
PostMessageTransportBackend,
|
|
|
|
Transport
|
|
|
|
} from '../../../../../modules/transport';
|
2019-09-13 13:03:40 +00:00
|
|
|
import DialogWithTabs from '../../../base/dialog/components/web/DialogWithTabs';
|
2020-05-07 22:26:37 +00:00
|
|
|
import { parseURLParams } from '../../../base/util/parseURLParams';
|
2019-09-13 13:03:40 +00:00
|
|
|
import DeviceSelection from '../../../device-selection/components/DeviceSelection';
|
2017-06-04 03:12:04 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Implements a class that renders the React components for the device selection
|
|
|
|
* popup page and handles the communication between the components and Jitsi
|
|
|
|
* Meet.
|
|
|
|
*/
|
|
|
|
export default class DeviceSelectionPopup {
|
|
|
|
/**
|
|
|
|
* Initializes a new DeviceSelectionPopup instance.
|
|
|
|
*
|
|
|
|
* @param {Object} i18next - The i18next instance used for translation.
|
|
|
|
*/
|
|
|
|
constructor(i18next) {
|
|
|
|
this.close = this.close.bind(this);
|
|
|
|
this._i18next = i18next;
|
2018-06-20 20:19:53 +00:00
|
|
|
this._onSubmit = this._onSubmit.bind(this);
|
|
|
|
|
2017-06-04 03:12:04 +00:00
|
|
|
const { scope } = parseURLParams(window.location);
|
|
|
|
|
|
|
|
this._transport = new Transport({
|
|
|
|
backend: new PostMessageTransportBackend({
|
|
|
|
postisOptions: {
|
|
|
|
scope,
|
|
|
|
window: window.opener
|
|
|
|
}
|
|
|
|
})
|
|
|
|
});
|
|
|
|
|
|
|
|
this._transport.on('event', event => {
|
|
|
|
if (event.name === 'deviceListChanged') {
|
|
|
|
this._updateAvailableDevices();
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
});
|
|
|
|
|
|
|
|
this._dialogProps = {
|
|
|
|
availableDevices: {},
|
2018-06-20 20:19:53 +00:00
|
|
|
selectedAudioInputId: '',
|
|
|
|
selectedAudioOutputId: '',
|
|
|
|
selectedVideoInputId: '',
|
2017-06-04 03:12:04 +00:00
|
|
|
disableAudioInputChange: true,
|
2018-06-20 20:19:53 +00:00
|
|
|
disableBlanketClickDismiss: true,
|
2017-06-04 03:12:04 +00:00
|
|
|
disableDeviceChange: true,
|
|
|
|
hideAudioInputPreview: !JitsiMeetJS.isCollectingLocalStats(),
|
|
|
|
hideAudioOutputSelect: true
|
2018-06-20 20:19:53 +00:00
|
|
|
|
2017-06-04 03:12:04 +00:00
|
|
|
};
|
|
|
|
this._initState();
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Sends event to Jitsi Meet to close the popup dialog.
|
|
|
|
*
|
|
|
|
* @returns {void}
|
|
|
|
*/
|
|
|
|
close() {
|
|
|
|
this._transport.sendEvent({
|
|
|
|
type: 'devices-dialog',
|
|
|
|
name: 'close'
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Changes the properties of the react component and re-renders it.
|
|
|
|
*
|
|
|
|
* @param {Object} newProps - The new properties that will be assigned to
|
|
|
|
* the current ones.
|
|
|
|
* @returns {void}
|
|
|
|
*/
|
|
|
|
_changeDialogProps(newProps) {
|
|
|
|
this._dialogProps = {
|
|
|
|
...this._dialogProps,
|
|
|
|
...newProps
|
|
|
|
};
|
|
|
|
this._render();
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns Promise that resolves with result an list of available devices.
|
|
|
|
*
|
|
|
|
* @returns {Promise}
|
|
|
|
*/
|
|
|
|
_getAvailableDevices() {
|
2019-03-21 12:33:40 +00:00
|
|
|
return getAvailableDevices(this._transport);
|
2017-06-04 03:12:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns Promise that resolves with current selected devices.
|
|
|
|
*
|
|
|
|
* @returns {Promise}
|
|
|
|
*/
|
|
|
|
_getCurrentDevices() {
|
2019-03-28 13:08:00 +00:00
|
|
|
return getCurrentDevices(this._transport).then(currentDevices => {
|
|
|
|
const {
|
|
|
|
audioInput = {},
|
|
|
|
audioOutput = {},
|
|
|
|
videoInput = {}
|
|
|
|
} = currentDevices;
|
|
|
|
|
|
|
|
return {
|
|
|
|
audioInput: audioInput.deviceId,
|
|
|
|
audioOutput: audioOutput.deviceId,
|
|
|
|
videoInput: videoInput.deviceId
|
|
|
|
};
|
|
|
|
});
|
2017-06-04 03:12:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Initializes the state.
|
|
|
|
*
|
|
|
|
* @returns {void}
|
|
|
|
*/
|
|
|
|
_initState() {
|
|
|
|
return Promise.all([
|
|
|
|
this._getAvailableDevices(),
|
|
|
|
this._isDeviceListAvailable(),
|
|
|
|
this._isDeviceChangeAvailable(),
|
2017-06-13 00:12:29 +00:00
|
|
|
this._isDeviceChangeAvailable('output'),
|
2017-06-04 03:12:04 +00:00
|
|
|
this._getCurrentDevices(),
|
|
|
|
this._isMultipleAudioInputSupported()
|
|
|
|
]).then(([
|
|
|
|
availableDevices,
|
|
|
|
listAvailable,
|
|
|
|
changeAvailable,
|
2017-06-13 00:12:29 +00:00
|
|
|
changeOutputAvailable,
|
2017-06-04 03:12:04 +00:00
|
|
|
currentDevices,
|
|
|
|
multiAudioInputSupported
|
|
|
|
]) => {
|
|
|
|
this._changeDialogProps({
|
|
|
|
availableDevices,
|
2018-06-20 20:19:53 +00:00
|
|
|
selectedAudioInputId: currentDevices.audioInput,
|
|
|
|
selectedAudioOutputId: currentDevices.audioOutput,
|
|
|
|
selectedVideoInputId: currentDevices.videoInput,
|
2017-06-04 03:12:04 +00:00
|
|
|
disableAudioInputChange: !multiAudioInputSupported,
|
|
|
|
disableDeviceChange: !listAvailable || !changeAvailable,
|
2017-06-13 00:12:29 +00:00
|
|
|
hideAudioOutputSelect: !changeOutputAvailable
|
2017-06-04 03:12:04 +00:00
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns Promise that resolves with true if the device change is available
|
|
|
|
* and with false if not.
|
|
|
|
*
|
2017-06-13 00:12:29 +00:00
|
|
|
* @param {string} [deviceType] - Values - 'output', 'input' or undefined.
|
|
|
|
* Default - 'input'.
|
2017-06-04 03:12:04 +00:00
|
|
|
* @returns {Promise}
|
|
|
|
*/
|
2017-06-13 00:12:29 +00:00
|
|
|
_isDeviceChangeAvailable(deviceType) {
|
2019-03-28 16:29:30 +00:00
|
|
|
return isDeviceChangeAvailable(this._transport, deviceType).catch(() => false);
|
2017-06-04 03:12:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns Promise that resolves with true if the device list is available
|
|
|
|
* and with false if not.
|
|
|
|
*
|
|
|
|
* @returns {Promise}
|
|
|
|
*/
|
|
|
|
_isDeviceListAvailable() {
|
2019-03-28 16:29:30 +00:00
|
|
|
return isDeviceListAvailable(this._transport).catch(() => false);
|
2017-06-04 03:12:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2019-03-28 16:29:30 +00:00
|
|
|
* Returns Promise that resolves with true if multiple audio input is supported
|
2017-06-04 03:12:04 +00:00
|
|
|
* and with false if not.
|
|
|
|
*
|
|
|
|
* @returns {Promise}
|
|
|
|
*/
|
|
|
|
_isMultipleAudioInputSupported() {
|
2019-03-28 16:29:30 +00:00
|
|
|
return isMultipleAudioInputSupported(this._transport).catch(() => false);
|
2017-06-04 03:12:04 +00:00
|
|
|
}
|
|
|
|
|
2018-06-20 20:19:53 +00:00
|
|
|
/**
|
|
|
|
* Callback invoked to save changes to selected devices and close the
|
|
|
|
* dialog.
|
|
|
|
*
|
|
|
|
* @param {Object} newSettings - The chosen device IDs.
|
|
|
|
* @private
|
|
|
|
* @returns {void}
|
|
|
|
*/
|
|
|
|
_onSubmit(newSettings) {
|
|
|
|
const promises = [];
|
|
|
|
|
|
|
|
if (newSettings.selectedVideoInputId
|
|
|
|
!== this._dialogProps.selectedVideoInputId) {
|
|
|
|
promises.push(
|
|
|
|
this._setVideoInputDevice(newSettings.selectedVideoInputId));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (newSettings.selectedAudioInputId
|
|
|
|
!== this._dialogProps.selectedAudioInputId) {
|
|
|
|
promises.push(
|
|
|
|
this._setAudioInputDevice(newSettings.selectedAudioInputId));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (newSettings.selectedAudioOutputId
|
|
|
|
!== this._dialogProps.selectedAudioOutputId) {
|
|
|
|
promises.push(
|
|
|
|
this._setAudioOutputDevice(newSettings.selectedAudioOutputId));
|
|
|
|
}
|
|
|
|
|
|
|
|
Promise.all(promises).then(this.close, this.close);
|
|
|
|
}
|
|
|
|
|
2017-06-04 03:12:04 +00:00
|
|
|
/**
|
|
|
|
* Renders the React components for the popup page.
|
|
|
|
*
|
|
|
|
* @returns {void}
|
|
|
|
*/
|
|
|
|
_render() {
|
2018-06-20 20:19:53 +00:00
|
|
|
const onSubmit = this.close;
|
2017-06-04 03:12:04 +00:00
|
|
|
|
|
|
|
ReactDOM.render(
|
2018-06-20 20:19:53 +00:00
|
|
|
<I18nextProvider i18n = { this._i18next }>
|
2018-03-13 04:45:00 +00:00
|
|
|
<AtlasKitThemeProvider mode = 'dark'>
|
2018-06-20 20:19:53 +00:00
|
|
|
<DialogWithTabs
|
|
|
|
closeDialog = { this.close }
|
2018-11-24 11:50:09 +00:00
|
|
|
cssClassName = 'settings-dialog'
|
2018-06-20 20:19:53 +00:00
|
|
|
onSubmit = { onSubmit }
|
|
|
|
tabs = { [ {
|
|
|
|
component: DeviceSelection,
|
|
|
|
label: 'settings.devices',
|
|
|
|
props: this._dialogProps,
|
|
|
|
submit: this._onSubmit
|
2018-11-24 11:50:09 +00:00
|
|
|
} ] }
|
|
|
|
titleKey = 'settings.title' />
|
2018-03-13 04:45:00 +00:00
|
|
|
</AtlasKitThemeProvider>
|
2017-06-04 03:12:04 +00:00
|
|
|
</I18nextProvider>,
|
|
|
|
document.getElementById('react'));
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Sets the audio input device to the one with the id that is passed.
|
|
|
|
*
|
|
|
|
* @param {string} id - The id of the new device.
|
|
|
|
* @returns {Promise}
|
|
|
|
*/
|
|
|
|
_setAudioInputDevice(id) {
|
2019-03-28 13:08:00 +00:00
|
|
|
return setAudioInputDevice(this._transport, undefined, id);
|
2017-06-04 03:12:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Sets the audio output device to the one with the id that is passed.
|
|
|
|
*
|
|
|
|
* @param {string} id - The id of the new device.
|
|
|
|
* @returns {Promise}
|
|
|
|
*/
|
|
|
|
_setAudioOutputDevice(id) {
|
2019-03-28 13:08:00 +00:00
|
|
|
return setAudioOutputDevice(this._transport, undefined, id);
|
2017-06-04 03:12:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Sets the video input device to the one with the id that is passed.
|
|
|
|
*
|
|
|
|
* @param {string} id - The id of the new device.
|
|
|
|
* @returns {Promise}
|
|
|
|
*/
|
|
|
|
_setVideoInputDevice(id) {
|
2019-03-28 13:08:00 +00:00
|
|
|
return setVideoInputDevice(this._transport, undefined, id);
|
2017-06-04 03:12:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Updates the available devices.
|
|
|
|
*
|
|
|
|
* @returns {void}
|
|
|
|
*/
|
|
|
|
_updateAvailableDevices() {
|
|
|
|
this._getAvailableDevices().then(devices =>
|
|
|
|
this._changeDialogProps({ availableDevices: devices })
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|