From 829e5597d5854e30f7658b4395f9d3fc10c21bab Mon Sep 17 00:00:00 2001 From: Hristo Terezov Date: Thu, 28 Mar 2019 16:29:30 +0000 Subject: [PATCH] fix(iframe-api-devices): Misc small issues. --- conference.js | 4 +- doc/api.md | 4 +- modules/API/API.js | 4 +- modules/API/external/external_api.js | 28 ++- modules/API/external/functions.js | 14 +- react/features/base/devices/actionTypes.js | 3 +- react/features/base/devices/functions.js | 5 +- react/features/base/devices/middleware.js | 4 +- react/features/base/devices/reducer.js | 4 +- react/features/device-selection/actions.js | 4 +- react/features/device-selection/functions.js | 215 +++++++++--------- react/features/device-selection/middleware.js | 6 +- .../components/web/DeviceSelectionPopup.js | 8 +- 13 files changed, 148 insertions(+), 155 deletions(-) diff --git a/conference.js b/conference.js index a7274bdcd..c1b999566 100644 --- a/conference.js +++ b/conference.js @@ -2417,7 +2417,7 @@ export default { */ updateAudioIconEnabled() { const audioMediaDevices - = APP.store.getState()['features/base/devices'].devices.audioInput; + = APP.store.getState()['features/base/devices'].availableDevices.audioInput; const audioDeviceCount = audioMediaDevices ? audioMediaDevices.length : 0; @@ -2440,7 +2440,7 @@ export default { */ updateVideoIconEnabled() { const videoMediaDevices - = APP.store.getState()['features/base/devices'].devices.videoInput; + = APP.store.getState()['features/base/devices'].availableDevices.videoInput; const videoDeviceCount = videoMediaDevices ? videoMediaDevices.length : 0; diff --git a/doc/api.md b/doc/api.md index cdf01a5d4..67fa51ea4 100644 --- a/doc/api.md +++ b/doc/api.md @@ -81,7 +81,7 @@ var api = new JitsiMeetExternalAPI(domain, options); ### Controlling the embedded Jitsi Meet Conference -You can control the available devices with the following methods of `JitsiMeetExternalAPI` instance: +Device management `JitsiMeetExternalAPI` methods: * **getAvailableDevices** - Retrieve a list of available devices. ```javascript @@ -151,7 +151,7 @@ api.isDeviceListAvailable().then(function(isDeviceListAvailable) { ... }); ``` -* **isMultipleAudioInputSupported** - Resolves with true if the device list is available and with false if not. +* **isMultipleAudioInputSupported** - Resolves with true if multiple audio input is supported and with false if not. ```javascript api.isMultipleAudioInputSupported().then(function(isMultipleAudioInputSupported) { diff --git a/modules/API/API.js b/modules/API/API.js index e41062540..b6c25bdc6 100644 --- a/modules/API/API.js +++ b/modules/API/API.js @@ -12,7 +12,7 @@ import { getJitsiMeetTransport } from '../transport'; import { API_ID } from './constants'; import { - processRequest + processExternalDeviceRequest } from '../../react/features/device-selection/functions'; const logger = require('jitsi-meet-logger').getLogger(__filename); @@ -122,7 +122,7 @@ function initCommands() { transport.on('request', (request, callback) => { const { dispatch, getState } = APP.store; - if (processRequest(dispatch, getState, request, callback)) { + if (processExternalDeviceRequest(dispatch, getState, request, callback)) { return true; } diff --git a/modules/API/external/external_api.js b/modules/API/external/external_api.js index e7a62f2ce..6b00879da 100644 --- a/modules/API/external/external_api.js +++ b/modules/API/external/external_api.js @@ -609,7 +609,7 @@ export default class JitsiMeetExternalAPI extends EventEmitter { } /** - * Returns Promise that resolves with result an list of available devices. + * Returns Promise that resolves with a list of available devices. * * @returns {Promise} */ @@ -661,7 +661,7 @@ export default class JitsiMeetExternalAPI extends EventEmitter { } /** - * Returns Promise that resolves with true if the device list is available + * Returns Promise that resolves with true if multiple audio input is supported * and with false if not. * * @returns {Promise} @@ -837,33 +837,39 @@ export default class JitsiMeetExternalAPI extends EventEmitter { } /** - * Sets the audio input device to the one with the id that is passed. + * Sets the audio input device to the one with the label or id that is + * passed. * + * @param {string} label - The label of the new device. * @param {string} deviceId - The id of the new device. * @returns {Promise} */ - setAudioInputDevice(deviceId) { - return setAudioInputDevice(this._transport, deviceId); + setAudioInputDevice(label, deviceId) { + return setAudioInputDevice(this._transport, label, deviceId); } /** - * Sets the audio output device to the one with the id that is passed. + * Sets the audio output device to the one with the label or id that is + * passed. * + * @param {string} label - The label of the new device. * @param {string} deviceId - The id of the new device. * @returns {Promise} */ - setAudioOutputDevice(deviceId) { - return setAudioOutputDevice(this._transport, deviceId); + setAudioOutputDevice(label, deviceId) { + return setAudioOutputDevice(this._transport, label, deviceId); } /** - * Sets the video input device to the one with the id that is passed. + * Sets the video input device to the one with the label or id that is + * passed. * + * @param {string} label - The label of the new device. * @param {string} deviceId - The id of the new device. * @returns {Promise} */ - setVideoInputDevice(deviceId) { - return setVideoInputDevice(this._transport, deviceId); + setVideoInputDevice(label, deviceId) { + return setVideoInputDevice(this._transport, label, deviceId); } /** diff --git a/modules/API/external/functions.js b/modules/API/external/functions.js index df8d9cc88..ebbb2a1e0 100644 --- a/modules/API/external/functions.js +++ b/modules/API/external/functions.js @@ -55,10 +55,6 @@ export function isDeviceChangeAvailable(transport: Object, deviceType: string) { deviceType, type: 'devices', name: 'isDeviceChangeAvailable' - }).catch(e => { - logger.error(e); - - return false; }); } @@ -74,15 +70,11 @@ export function isDeviceListAvailable(transport: Object) { return transport.sendRequest({ type: 'devices', name: 'isDeviceListAvailable' - }).catch(e => { - logger.error(e); - - return false; }); } /** - * Returns Promise that resolves with true if the device list is available + * Returns Promise that resolves with true if multiple audio input is supported * and with false if not. * * @param {Transport} transport - The @code{Transport} instance responsible for @@ -93,10 +85,6 @@ export function isMultipleAudioInputSupported(transport: Object) { return transport.sendRequest({ type: 'devices', name: 'isMultipleAudioInputSupported' - }).catch(e => { - logger.error(e); - - return false; }); } diff --git a/react/features/base/devices/actionTypes.js b/react/features/base/devices/actionTypes.js index 753d5e00c..2928afab5 100644 --- a/react/features/base/devices/actionTypes.js +++ b/react/features/base/devices/actionTypes.js @@ -46,8 +46,7 @@ export const ADD_PENDING_DEVICE_REQUEST = 'ADD_PENDING_DEVICE_REQUEST'; * The type of Redux action which will remove all pending device requests. * * { - * type: REMOVE_PENDING_DEVICE_REQUESTS, - * request: Object + * type: REMOVE_PENDING_DEVICE_REQUESTS * } */ export const REMOVE_PENDING_DEVICE_REQUESTS = 'REMOVE_PENDING_DEVICE_REQUESTS'; diff --git a/react/features/base/devices/functions.js b/react/features/base/devices/functions.js index 90f35a089..247cfaee0 100644 --- a/react/features/base/devices/functions.js +++ b/react/features/base/devices/functions.js @@ -15,12 +15,13 @@ declare var APP: Object; * otherwise. */ export function areDeviceLabelsInitialized(state: Object) { + // TODO: Replace with something that doesn't use APP when the conference.js logic is reactified. if (APP.conference._localTracksInitialized) { return true; } for (const type of [ 'audioInput', 'audioOutput', 'videoInput' ]) { - if (state['features/base/devices'].devices[type].find(d => Boolean(d.label))) { + if ((state['features/base/devices'].availableDevices[type] || []).find(d => Boolean(d.label))) { return true; } } @@ -50,7 +51,7 @@ export function getDeviceIdByLabel(state: Object, label: string) { for (const type of types) { const device - = state['features/base/devices'].devices[type] + = (state['features/base/devices'].availableDevices[type] || []) .find(d => d.label === label); if (device) { diff --git a/react/features/base/devices/middleware.js b/react/features/base/devices/middleware.js index f6562e17f..decb73bea 100644 --- a/react/features/base/devices/middleware.js +++ b/react/features/base/devices/middleware.js @@ -1,7 +1,7 @@ /* global APP */ import { CONFERENCE_JOINED } from '../conference'; -import { processRequest } from '../../device-selection'; +import { processExternalDeviceRequest } from '../../device-selection'; import { MiddlewareRegistry } from '../redux'; import UIEvents from '../../../../service/UI/UIEvents'; @@ -53,7 +53,7 @@ function _conferenceJoined({ dispatch, getState }, next, action) { const { pendingRequests } = state['features/base/devices']; pendingRequests.forEach(request => { - processRequest( + processExternalDeviceRequest( dispatch, getState, request, diff --git a/react/features/base/devices/reducer.js b/react/features/base/devices/reducer.js index 49d68931d..7d16f27b0 100644 --- a/react/features/base/devices/reducer.js +++ b/react/features/base/devices/reducer.js @@ -10,7 +10,7 @@ import { groupDevicesByKind } from './functions'; import { ReducerRegistry } from '../redux'; const DEFAULT_STATE = { - devices: { + availableDevices: { audioInput: [], audioOutput: [], videoInput: [] @@ -37,7 +37,7 @@ ReducerRegistry.register( return { ...state, - devices: deviceList + availableDevices: deviceList }; } diff --git a/react/features/device-selection/actions.js b/react/features/device-selection/actions.js index f87138fdb..fce22675f 100644 --- a/react/features/device-selection/actions.js +++ b/react/features/device-selection/actions.js @@ -14,7 +14,7 @@ import { i18next } from '../base/i18n'; import { updateSettings } from '../base/settings'; import { SET_DEVICE_SELECTION_POPUP_DATA } from './actionTypes'; -import { getDeviceSelectionDialogProps, processRequest } from './functions'; +import { getDeviceSelectionDialogProps, processExternalDeviceRequest } from './functions'; const logger = require('jitsi-meet-logger').getLogger(__filename); @@ -58,7 +58,7 @@ export function openDeviceSelectionPopup() { }); transport.on('request', - processRequest.bind(undefined, dispatch, getState)); + processExternalDeviceRequest.bind(undefined, dispatch, getState)); transport.on('event', event => { if (event.type === 'devices-dialog' && event.name === 'close') { popup.close(); diff --git a/react/features/device-selection/functions.js b/react/features/device-selection/functions.js index 2dd18f402..21b537e03 100644 --- a/react/features/device-selection/functions.js +++ b/react/features/device-selection/functions.js @@ -28,7 +28,7 @@ export function getDeviceSelectionDialogProps(stateful: Object | Function) { const settings = state['features/base/settings']; return { - availableDevices: state['features/base/devices'].devices, + availableDevices: state['features/base/devices'].availableDevices, disableAudioInputChange: !JitsiMeetJS.isMultipleAudioInputSupported(), disableDeviceChange: @@ -52,133 +52,132 @@ export function getDeviceSelectionDialogProps(stateful: Object | Function) { * @param {Object} request - The request to be processed. * @param {Function} responseCallback - The callback that will send the * response. - * @returns {boolean} + * @returns {boolean} - True if the request has been processed and false otherwise. */ -export function processRequest( // eslint-disable-line max-params +export function processExternalDeviceRequest( // eslint-disable-line max-params dispatch: Dispatch, getState: Function, request: Object, responseCallback: Function) { - if (request.type === 'devices') { - const state = getState(); - const settings = state['features/base/settings']; - const { conference } = state['features/base/conference']; - let result = true; + if (request.type !== 'devices') { + return false; + } + const state = getState(); + const settings = state['features/base/settings']; + const { conference } = state['features/base/conference']; + let result = true; - switch (request.name) { - case 'isDeviceListAvailable': - responseCallback(JitsiMeetJS.mediaDevices.isDeviceListAvailable()); - break; - case 'isDeviceChangeAvailable': - responseCallback( - JitsiMeetJS.mediaDevices.isDeviceChangeAvailable( - request.deviceType)); - break; - case 'isMultipleAudioInputSupported': - responseCallback(JitsiMeetJS.isMultipleAudioInputSupported()); - break; - case 'getCurrentDevices': - dispatch(getAvailableDevices()).then(devices => { - if (areDeviceLabelsInitialized(state)) { - let audioInput, audioOutput, videoInput; - const audioOutputDeviceId = getAudioOutputDeviceId(); - const { cameraDeviceId, micDeviceId } = settings; + switch (request.name) { + case 'isDeviceListAvailable': + responseCallback(JitsiMeetJS.mediaDevices.isDeviceListAvailable()); + break; + case 'isDeviceChangeAvailable': + responseCallback( + JitsiMeetJS.mediaDevices.isDeviceChangeAvailable( + request.deviceType)); + break; + case 'isMultipleAudioInputSupported': + responseCallback(JitsiMeetJS.isMultipleAudioInputSupported()); + break; + case 'getCurrentDevices': + dispatch(getAvailableDevices()).then(devices => { + if (areDeviceLabelsInitialized(state)) { + let audioInput, audioOutput, videoInput; + const audioOutputDeviceId = getAudioOutputDeviceId(); + const { cameraDeviceId, micDeviceId } = settings; - devices.forEach(device => { - const { deviceId } = device; + devices.forEach(device => { + const { deviceId } = device; - switch (deviceId) { - case micDeviceId: - audioInput = device; - break; - case audioOutputDeviceId: - audioOutput = device; - break; - case cameraDeviceId: - videoInput = device; - break; - } - }); + switch (deviceId) { + case micDeviceId: + audioInput = device; + break; + case audioOutputDeviceId: + audioOutput = device; + break; + case cameraDeviceId: + videoInput = device; + break; + } + }); - responseCallback({ - audioInput, - audioOutput, - videoInput - }); - } else { - // The labels are not available if the A/V permissions are - // not yet granted. - dispatch(addPendingDeviceRequest({ - type: 'devices', - name: 'getCurrentDevices', - responseCallback - })); - } - }); - - break; - case 'getAvailableDevices': - dispatch(getAvailableDevices()).then(devices => { - if (areDeviceLabelsInitialized(state)) { - responseCallback(groupDevicesByKind(devices)); - } else { - // The labels are not available if the A/V permissions are - // not yet granted. - dispatch(addPendingDeviceRequest({ - type: 'devices', - name: 'getAvailableDevices', - responseCallback - })); - } - }); - - break; - case 'setDevice': { - const { device } = request; - - if (!conference) { + responseCallback({ + audioInput, + audioOutput, + videoInput + }); + } else { + // The labels are not available if the A/V permissions are + // not yet granted. dispatch(addPendingDeviceRequest({ type: 'devices', - name: 'setDevice', - device, + name: 'getCurrentDevices', responseCallback })); - - return true; } + }); - const { label, id } = device; - const deviceId = label ? getDeviceIdByLabel(state, device.label) : id; - - if (deviceId) { - switch (device.kind) { - case 'audioinput': { - dispatch(setAudioInputDevice(deviceId)); - break; - } - case 'audiooutput': - setAudioOutputDeviceId(deviceId, dispatch); - break; - case 'videoinput': - dispatch(setVideoInputDevice(deviceId)); - break; - default: - result = false; - } + break; + case 'getAvailableDevices': + dispatch(getAvailableDevices()).then(devices => { + if (areDeviceLabelsInitialized(state)) { + responseCallback(groupDevicesByKind(devices)); } else { + // The labels are not available if the A/V permissions are + // not yet granted. + dispatch(addPendingDeviceRequest({ + type: 'devices', + name: 'getAvailableDevices', + responseCallback + })); + } + }); + + break; + case 'setDevice': { + const { device } = request; + + if (!conference) { + dispatch(addPendingDeviceRequest({ + type: 'devices', + name: 'setDevice', + device, + responseCallback + })); + + return true; + } + + const { label, id } = device; + const deviceId = label ? getDeviceIdByLabel(state, device.label) : id; + + if (deviceId) { + switch (device.kind) { + case 'audioinput': { + dispatch(setAudioInputDevice(deviceId)); + break; + } + case 'audiooutput': + setAudioOutputDeviceId(deviceId, dispatch); + break; + case 'videoinput': + dispatch(setVideoInputDevice(deviceId)); + break; + default: result = false; } - - responseCallback(result); - break; - } - default: - - return false; + } else { + result = false; } - return true; + responseCallback(result); + break; + } + default: + return false; } - return false; + return true; } + diff --git a/react/features/device-selection/middleware.js b/react/features/device-selection/middleware.js index c2451e0d8..d1d9e5d98 100644 --- a/react/features/device-selection/middleware.js +++ b/react/features/device-selection/middleware.js @@ -18,17 +18,17 @@ MiddlewareRegistry.register(store => next => action => { if (action.type === UPDATE_DEVICE_LIST) { const state = store.getState(); const { popupDialogData } = state['features/device-selection']; - const { devices } = state['features/base/devices']; + const { availableDevices } = state['features/base/devices']; if (popupDialogData) { popupDialogData.transport.sendEvent({ name: 'deviceListChanged', - devices + devices: availableDevices }); } if (typeof APP !== 'undefined') { - APP.API.notifyDeviceListChanged(devices); + APP.API.notifyDeviceListChanged(availableDevices); } } diff --git a/react/features/settings/components/web/DeviceSelectionPopup.js b/react/features/settings/components/web/DeviceSelectionPopup.js index 4510e59ad..a7b184cb3 100644 --- a/react/features/settings/components/web/DeviceSelectionPopup.js +++ b/react/features/settings/components/web/DeviceSelectionPopup.js @@ -175,7 +175,7 @@ export default class DeviceSelectionPopup { * @returns {Promise} */ _isDeviceChangeAvailable(deviceType) { - return isDeviceChangeAvailable(this._transport, deviceType); + return isDeviceChangeAvailable(this._transport, deviceType).catch(() => false); } /** @@ -185,17 +185,17 @@ export default class DeviceSelectionPopup { * @returns {Promise} */ _isDeviceListAvailable() { - return isDeviceListAvailable(this._transport); + return isDeviceListAvailable(this._transport).catch(() => false); } /** - * Returns Promise that resolves with true if the device list is available + * Returns Promise that resolves with true if multiple audio input is supported * and with false if not. * * @returns {Promise} */ _isMultipleAudioInputSupported() { - return isMultipleAudioInputSupported(this._transport); + return isMultipleAudioInputSupported(this._transport).catch(() => false); } /**