diff --git a/modules/transport/Transport.js b/modules/transport/Transport.js index 678ad3277f..9f6cebbcaa 100644 --- a/modules/transport/Transport.js +++ b/modules/transport/Transport.js @@ -233,9 +233,11 @@ export default class Transport { return new Promise((resolve, reject) => { this._responseHandlers.set(id, ({ error, result }) => { - if (result) { + if (typeof result !== 'undefined') { resolve(result); - } else if (error) { + + // eslint-disable-next-line no-negated-condition + } else if (typeof error !== 'undefined') { reject(error); } else { // no response reject(new Error('Unexpected response format!')); diff --git a/react/features/device-selection/DeviceSelectionPopup.js b/react/features/device-selection/DeviceSelectionPopup.js index 778c637f21..6c91e590c1 100644 --- a/react/features/device-selection/DeviceSelectionPopup.js +++ b/react/features/device-selection/DeviceSelectionPopup.js @@ -61,9 +61,9 @@ export default class DeviceSelectionPopup { disableAudioInputChange: true, disableDeviceChange: true, hasAudioPermission: JitsiMeetJS.mediaDevices - .isDevicePermissionGranted('audio'), + .isDevicePermissionGranted.bind(null, 'audio'), hasVideoPermission: JitsiMeetJS.mediaDevices - .isDevicePermissionGranted('video'), + .isDevicePermissionGranted.bind(null, 'video'), hideAudioInputPreview: !JitsiMeetJS.isCollectingLocalStats(), hideAudioOutputSelect: true }; @@ -139,12 +139,14 @@ export default class DeviceSelectionPopup { this._getAvailableDevices(), this._isDeviceListAvailable(), this._isDeviceChangeAvailable(), + this._isDeviceChangeAvailable('output'), this._getCurrentDevices(), this._isMultipleAudioInputSupported() ]).then(([ availableDevices, listAvailable, changeAvailable, + changeOutputAvailable, currentDevices, multiAudioInputSupported ]) => { @@ -155,7 +157,7 @@ export default class DeviceSelectionPopup { currentVideoInputId: currentDevices.videoInput, disableAudioInputChange: !multiAudioInputSupported, disableDeviceChange: !listAvailable || !changeAvailable, - hideAudioOutputSelect: !changeAvailable + hideAudioOutputSelect: !changeOutputAvailable }); }); } @@ -164,10 +166,13 @@ export default class DeviceSelectionPopup { * Returns Promise that resolves with true if the device change is available * and with false if not. * + * @param {string} [deviceType] - Values - 'output', 'input' or undefined. + * Default - 'input'. * @returns {Promise} */ - _isDeviceChangeAvailable() { + _isDeviceChangeAvailable(deviceType) { return this._transport.sendRequest({ + deviceType, type: 'devices', name: 'isDeviceChangeAvailable' }).catch(e => { diff --git a/react/features/device-selection/actions.js b/react/features/device-selection/actions.js index ade0678c62..550966e8e4 100644 --- a/react/features/device-selection/actions.js +++ b/react/features/device-selection/actions.js @@ -51,9 +51,9 @@ function _openDeviceSelectionDialogHere() { disableDeviceChange: !isDeviceListAvailable || !JitsiMeetJS.mediaDevices.isDeviceChangeAvailable(), hasAudioPermission: JitsiMeetJS.mediaDevices - .isDevicePermissionGranted('audio'), + .isDevicePermissionGranted.bind(null, 'audio'), hasVideoPermission: JitsiMeetJS.mediaDevices - .isDevicePermissionGranted('video'), + .isDevicePermissionGranted.bind(null, 'video'), hideAudioInputPreview: !JitsiMeetJS.isCollectingLocalStats(), hideAudioOutputSelect: !JitsiMeetJS.mediaDevices @@ -144,7 +144,8 @@ function _processRequest(dispatch, getState, request, responseCallback) { break; case 'isDeviceChangeAvailable': responseCallback( - JitsiMeetJS.mediaDevices.isDeviceChangeAvailable()); + JitsiMeetJS.mediaDevices.isDeviceChangeAvailable( + request.deviceType)); break; case 'isMultipleAudioInputSupported': responseCallback(JitsiMeetJS.isMultipleAudioInputSupported()); diff --git a/react/features/device-selection/components/DeviceSelectionDialog.js b/react/features/device-selection/components/DeviceSelectionDialog.js index d7cb8eae24..c2e8ef30de 100644 --- a/react/features/device-selection/components/DeviceSelectionDialog.js +++ b/react/features/device-selection/components/DeviceSelectionDialog.js @@ -66,14 +66,16 @@ class DeviceSelectionDialog extends Component { dispatch: React.PropTypes.func, /** - * Whether or not a new audio input source can be selected. + * Function that checks whether or not a new audio input source can be + * selected. */ - hasAudioPermission: React.PropTypes.bool, + hasAudioPermission: React.PropTypes.func, /** - * Whether or not a new video input sources can be selected. + * Function that checks whether or not a new video input sources can be + * selected. */ - hasVideoPermission: React.PropTypes.bool, + hasVideoPermission: React.PropTypes.func, /** * If true, the audio meter will not display. Necessary for browsers or diff --git a/react/features/device-selection/components/DeviceSelectionDialogBase.js b/react/features/device-selection/components/DeviceSelectionDialogBase.js index f12901243e..9994b58bfa 100644 --- a/react/features/device-selection/components/DeviceSelectionDialogBase.js +++ b/react/features/device-selection/components/DeviceSelectionDialogBase.js @@ -71,14 +71,16 @@ class DeviceSelectionDialogBase extends Component { disableDeviceChange: React.PropTypes.bool, /** - * Whether or not a new audio input source can be selected. + * Function that checks whether or not a new audio input source can be + * selected. */ - hasAudioPermission: React.PropTypes.bool, + hasAudioPermission: React.PropTypes.func, /** - * Whether or not a new video input sources can be selected. + * Function that checks whether or not a new video input sources can be + * selected. */ - hasVideoPermission: React.PropTypes.bool, + hasVideoPermission: React.PropTypes.func, /** * If true, the audio meter will not display. Necessary for browsers or @@ -381,7 +383,7 @@ class DeviceSelectionDialogBase extends Component { const configurations = [ { devices: availableDevices.videoInput, - hasPermission: this.props.hasVideoPermission, + hasPermission: this.props.hasVideoPermission(), icon: 'icon-camera', isDisabled: this.props.disableDeviceChange, key: 'videoInput', @@ -391,7 +393,7 @@ class DeviceSelectionDialogBase extends Component { }, { devices: availableDevices.audioInput, - hasPermission: this.props.hasAudioPermission, + hasPermission: this.props.hasAudioPermission(), icon: 'icon-microphone', isDisabled: this.props.disableAudioInputChange || this.props.disableDeviceChange, @@ -405,8 +407,8 @@ class DeviceSelectionDialogBase extends Component { if (!this.props.hideAudioOutputSelect) { configurations.push({ devices: availableDevices.audioOutput, - hasPermission: this.props.hasAudioPermission - || this.props.hasVideoPermission, + hasPermission: this.props.hasAudioPermission() + || this.props.hasVideoPermission(), icon: 'icon-volume', isDisabled: this.props.disableDeviceChange, key: 'audioOutput', diff --git a/react/features/device-selection/popup.js b/react/features/device-selection/popup.js index bfefe882eb..09d8729c37 100644 --- a/react/features/device-selection/popup.js +++ b/react/features/device-selection/popup.js @@ -3,10 +3,14 @@ import 'aui-experimental-css'; import DeviceSelectionPopup from './DeviceSelectionPopup'; +declare var JitsiMeetJS: Object; + let deviceSelectionPopup; window.init = function(i18next) { - deviceSelectionPopup = new DeviceSelectionPopup(i18next); + JitsiMeetJS.init({}).then(() => { + deviceSelectionPopup = new DeviceSelectionPopup(i18next); + }); }; window.addEventListener('beforeunload', () => diff --git a/static/deviceSelectionPopup.html b/static/deviceSelectionPopup.html index ebce7cf5a4..8650a809c2 100644 --- a/static/deviceSelectionPopup.html +++ b/static/deviceSelectionPopup.html @@ -8,9 +8,9 @@ - + +