2017-06-04 03:12:04 +00:00
|
|
|
/* globals APP, interfaceConfig */
|
2017-04-09 21:20:37 +00:00
|
|
|
|
|
|
|
import { openDialog } from '../base/dialog';
|
|
|
|
import JitsiMeetJS from '../base/lib-jitsi-meet';
|
2017-06-04 03:12:04 +00:00
|
|
|
import { API_ID } from '../../../modules/API/constants';
|
|
|
|
import {
|
|
|
|
setAudioInputDevice,
|
|
|
|
setAudioOutputDevice,
|
|
|
|
setVideoInputDevice
|
|
|
|
} from '../base/devices';
|
|
|
|
import { i18next } from '../base/i18n';
|
|
|
|
import {
|
|
|
|
PostMessageTransportBackend,
|
|
|
|
Transport
|
|
|
|
} from '../../../modules/transport';
|
2017-04-09 21:20:37 +00:00
|
|
|
|
2017-06-04 03:12:04 +00:00
|
|
|
import { SET_DEVICE_SELECTION_POPUP_DATA } from './actionTypes';
|
2017-04-09 21:20:37 +00:00
|
|
|
import { DeviceSelectionDialog } from './components';
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Open DeviceSelectionDialog with a configuration based on the environment's
|
|
|
|
* supported abilities.
|
|
|
|
*
|
|
|
|
* @returns {Function}
|
|
|
|
*/
|
|
|
|
export function openDeviceSelectionDialog() {
|
2017-04-26 02:15:19 +00:00
|
|
|
return dispatch => {
|
2017-06-04 03:12:04 +00:00
|
|
|
if (interfaceConfig.filmStripOnly) {
|
|
|
|
dispatch(_openDeviceSelectionDialogInPopup());
|
|
|
|
} else {
|
|
|
|
dispatch(_openDeviceSelectionDialogHere());
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Opens the DeviceSelectionDialog in the same window.
|
|
|
|
*
|
|
|
|
* @returns {Function}
|
|
|
|
*/
|
|
|
|
function _openDeviceSelectionDialogHere() {
|
|
|
|
return dispatch =>
|
2017-04-09 21:20:37 +00:00
|
|
|
JitsiMeetJS.mediaDevices.isDeviceListAvailable()
|
|
|
|
.then(isDeviceListAvailable => {
|
|
|
|
dispatch(openDialog(DeviceSelectionDialog, {
|
2017-04-26 02:15:19 +00:00
|
|
|
currentAudioInputId: APP.settings.getMicDeviceId(),
|
2017-04-09 21:20:37 +00:00
|
|
|
currentAudioOutputId: APP.settings.getAudioOutputDeviceId(),
|
2017-04-26 02:15:19 +00:00
|
|
|
currentVideoInputId: APP.settings.getCameraDeviceId(),
|
2017-04-09 21:20:37 +00:00
|
|
|
disableAudioInputChange:
|
|
|
|
!JitsiMeetJS.isMultipleAudioInputSupported(),
|
|
|
|
disableDeviceChange: !isDeviceListAvailable
|
|
|
|
|| !JitsiMeetJS.mediaDevices.isDeviceChangeAvailable(),
|
|
|
|
hasAudioPermission: JitsiMeetJS.mediaDevices
|
2017-06-13 00:12:29 +00:00
|
|
|
.isDevicePermissionGranted.bind(null, 'audio'),
|
2017-04-09 21:20:37 +00:00
|
|
|
hasVideoPermission: JitsiMeetJS.mediaDevices
|
2017-06-13 00:12:29 +00:00
|
|
|
.isDevicePermissionGranted.bind(null, 'video'),
|
2017-04-09 21:20:37 +00:00
|
|
|
hideAudioInputPreview:
|
|
|
|
!JitsiMeetJS.isCollectingLocalStats(),
|
|
|
|
hideAudioOutputSelect: !JitsiMeetJS.mediaDevices
|
|
|
|
.isDeviceChangeAvailable('output')
|
|
|
|
}));
|
|
|
|
});
|
2017-06-04 03:12:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Opens a popup window with the device selection dialog in it.
|
|
|
|
*
|
|
|
|
* @returns {Function}
|
|
|
|
*/
|
|
|
|
function _openDeviceSelectionDialogInPopup() {
|
|
|
|
return (dispatch, getState) => {
|
|
|
|
const { popupDialogData } = getState()['features/device-selection'];
|
|
|
|
|
|
|
|
if (popupDialogData) {
|
|
|
|
popupDialogData.popup.focus();
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// API_ID will always be defined because the iframe api is enabled
|
|
|
|
const scope = `dialog_${API_ID}`;
|
2017-06-09 18:16:03 +00:00
|
|
|
const url = `${
|
|
|
|
window.location.origin}/static/deviceSelectionPopup.html#scope=${
|
|
|
|
encodeURIComponent(JSON.stringify(scope))}`;
|
2017-06-04 03:12:04 +00:00
|
|
|
const popup
|
|
|
|
= window.open(
|
|
|
|
url,
|
|
|
|
'device-selection-popup',
|
|
|
|
'toolbar=no,scrollbars=no,resizable=no,width=720,height=458');
|
|
|
|
|
|
|
|
popup.addEventListener('DOMContentLoaded', () => {
|
|
|
|
popup.init(i18next);
|
|
|
|
});
|
|
|
|
|
|
|
|
const transport = new Transport({
|
|
|
|
backend: new PostMessageTransportBackend({
|
|
|
|
postisOptions: {
|
|
|
|
scope,
|
|
|
|
window: popup
|
|
|
|
}
|
|
|
|
})
|
|
|
|
});
|
|
|
|
|
|
|
|
transport.on('request',
|
|
|
|
_processRequest.bind(undefined, dispatch, getState));
|
|
|
|
transport.on('event', event => {
|
|
|
|
if (event.type === 'devices-dialog' && event.name === 'close') {
|
|
|
|
popup.close();
|
|
|
|
transport.dispose();
|
|
|
|
dispatch(_setDeviceSelectionPopupData());
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
});
|
|
|
|
|
|
|
|
dispatch(_setDeviceSelectionPopupData({
|
|
|
|
popup,
|
|
|
|
transport
|
|
|
|
}));
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Processes device requests from external applications.
|
|
|
|
*
|
|
|
|
* @param {Dispatch} dispatch - The redux {@code dispatch} function.
|
|
|
|
* @param {Function} getState - The redux function that gets/retrieves the redux
|
|
|
|
* state.
|
|
|
|
* @param {Object} request - The request to be processed.
|
|
|
|
* @param {Function} responseCallback - The callback that will send the
|
|
|
|
* response.
|
|
|
|
* @returns {boolean}
|
|
|
|
*/ // eslint-disable-next-line max-params
|
|
|
|
function _processRequest(dispatch, getState, request, responseCallback) {
|
|
|
|
if (request.type === 'devices') {
|
|
|
|
switch (request.name) {
|
|
|
|
case 'isDeviceListAvailable':
|
|
|
|
JitsiMeetJS.mediaDevices.isDeviceListAvailable()
|
|
|
|
.then(isDeviceListAvailable =>
|
|
|
|
responseCallback(isDeviceListAvailable))
|
|
|
|
.catch(e => responseCallback(null, e));
|
|
|
|
break;
|
|
|
|
case 'isDeviceChangeAvailable':
|
|
|
|
responseCallback(
|
2017-06-13 00:12:29 +00:00
|
|
|
JitsiMeetJS.mediaDevices.isDeviceChangeAvailable(
|
|
|
|
request.deviceType));
|
2017-06-04 03:12:04 +00:00
|
|
|
break;
|
|
|
|
case 'isMultipleAudioInputSupported':
|
|
|
|
responseCallback(JitsiMeetJS.isMultipleAudioInputSupported());
|
|
|
|
break;
|
|
|
|
case 'getCurrentDevices':
|
|
|
|
responseCallback({
|
|
|
|
audioInput: APP.settings.getMicDeviceId(),
|
|
|
|
audioOutput: APP.settings.getAudioOutputDeviceId(),
|
|
|
|
videoInput: APP.settings.getCameraDeviceId()
|
|
|
|
});
|
|
|
|
break;
|
|
|
|
case 'getAvailableDevices':
|
|
|
|
responseCallback(getState()['features/base/devices']);
|
|
|
|
break;
|
|
|
|
case 'setDevice': {
|
|
|
|
let action;
|
|
|
|
const { device } = request;
|
|
|
|
|
|
|
|
switch (device.kind) {
|
|
|
|
case 'audioinput':
|
|
|
|
action = setAudioInputDevice;
|
|
|
|
break;
|
|
|
|
case 'audiooutput':
|
|
|
|
action = setAudioOutputDevice;
|
|
|
|
break;
|
|
|
|
case 'videoinput':
|
|
|
|
action = setVideoInputDevice;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
|
|
|
|
}
|
|
|
|
dispatch(action(device.id));
|
|
|
|
responseCallback(true);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Sets information about device selection popup in the store.
|
|
|
|
*
|
|
|
|
* @param {Object} popupDialogData - Information about the popup.
|
|
|
|
* @param {Object} popupDialog.popup - The popup object returned from
|
|
|
|
* window.open.
|
|
|
|
* @param {Object} popupDialogData.transport - The transport instance used for
|
|
|
|
* communication with the popup window.
|
|
|
|
* @returns {{
|
|
|
|
* type: SET_DEVICE_SELECTION_POPUP_DATA,
|
|
|
|
* popupDialogData: Object
|
|
|
|
* }}
|
|
|
|
*/
|
|
|
|
function _setDeviceSelectionPopupData(popupDialogData) {
|
|
|
|
return {
|
|
|
|
type: SET_DEVICE_SELECTION_POPUP_DATA,
|
|
|
|
popupDialogData
|
2017-04-09 21:20:37 +00:00
|
|
|
};
|
|
|
|
}
|