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 @@
-
+
+