2018-08-06 15:24:59 +00:00
|
|
|
import JitsiMeetJS from '../lib-jitsi-meet';
|
2019-05-07 08:53:01 +00:00
|
|
|
import {
|
|
|
|
getUserSelectedOutputDeviceId,
|
|
|
|
updateSettings
|
|
|
|
} from '../settings';
|
2018-08-06 15:24:59 +00:00
|
|
|
|
2017-03-29 17:43:30 +00:00
|
|
|
import {
|
2019-03-27 17:30:56 +00:00
|
|
|
ADD_PENDING_DEVICE_REQUEST,
|
2019-05-03 17:25:33 +00:00
|
|
|
CHECK_AND_NOTIFY_FOR_NEW_DEVICE,
|
2019-05-29 21:17:07 +00:00
|
|
|
NOTIFY_CAMERA_ERROR,
|
|
|
|
NOTIFY_MIC_ERROR,
|
2019-03-27 17:30:56 +00:00
|
|
|
REMOVE_PENDING_DEVICE_REQUESTS,
|
2017-03-29 17:43:30 +00:00
|
|
|
SET_AUDIO_INPUT_DEVICE,
|
|
|
|
SET_VIDEO_INPUT_DEVICE,
|
|
|
|
UPDATE_DEVICE_LIST
|
|
|
|
} from './actionTypes';
|
2019-03-27 17:30:56 +00:00
|
|
|
import {
|
|
|
|
areDeviceLabelsInitialized,
|
|
|
|
getDeviceIdByLabel,
|
2020-04-14 06:53:04 +00:00
|
|
|
getDeviceLabelById,
|
2019-04-04 15:10:01 +00:00
|
|
|
getDevicesFromURL,
|
|
|
|
setAudioOutputDeviceId
|
2019-03-27 17:30:56 +00:00
|
|
|
} from './functions';
|
2019-08-21 14:50:00 +00:00
|
|
|
import logger from './logger';
|
2019-04-04 15:10:01 +00:00
|
|
|
|
2019-05-16 21:00:55 +00:00
|
|
|
/**
|
|
|
|
* Maps the WebRTC string for device type to the keys used to store configure,
|
|
|
|
* within redux, which devices should be used by default.
|
|
|
|
*/
|
|
|
|
const DEVICE_TYPE_TO_SETTINGS_KEYS = {
|
|
|
|
audioInput: {
|
|
|
|
currentDeviceId: 'micDeviceId',
|
|
|
|
userSelectedDeviceId: 'userSelectedMicDeviceId',
|
|
|
|
userSelectedDeviceLabel: 'userSelectedMicDeviceLabel'
|
|
|
|
},
|
|
|
|
audioOutput: {
|
|
|
|
currentDeviceId: 'audioOutputDeviceId',
|
|
|
|
userSelectedDeviceId: 'userSelectedAudioOutputDeviceId',
|
|
|
|
userSelectedDeviceLabel: 'userSelectedAudioOutputDeviceLabel'
|
|
|
|
},
|
|
|
|
videoInput: {
|
|
|
|
currentDeviceId: 'audioOutputDeviceId',
|
|
|
|
userSelectedDeviceId: 'userSelectedCameraDeviceId',
|
|
|
|
userSelectedDeviceLabel: 'userSelectedCameraDeviceLabel'
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2019-03-27 17:30:56 +00:00
|
|
|
/**
|
|
|
|
* Adds a pending device request.
|
|
|
|
*
|
|
|
|
* @param {Object} request - The request to be added.
|
|
|
|
* @returns {{
|
|
|
|
* type: ADD_PENDING_DEVICE_REQUEST,
|
|
|
|
* request: Object
|
|
|
|
* }}
|
|
|
|
*/
|
|
|
|
export function addPendingDeviceRequest(request) {
|
|
|
|
return {
|
|
|
|
type: ADD_PENDING_DEVICE_REQUEST,
|
|
|
|
request
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Configures the initial A/V devices before the conference has started.
|
|
|
|
*
|
|
|
|
* @returns {Function}
|
|
|
|
*/
|
|
|
|
export function configureInitialDevices() {
|
2019-04-04 15:10:01 +00:00
|
|
|
return (dispatch, getState) => {
|
2019-03-27 17:30:56 +00:00
|
|
|
const deviceLabels = getDevicesFromURL(getState());
|
2019-04-04 15:10:01 +00:00
|
|
|
let updateSettingsPromise;
|
2019-03-27 17:30:56 +00:00
|
|
|
|
|
|
|
if (deviceLabels) {
|
2019-04-04 15:10:01 +00:00
|
|
|
updateSettingsPromise = dispatch(getAvailableDevices()).then(() => {
|
2019-03-27 17:30:56 +00:00
|
|
|
const state = getState();
|
|
|
|
|
|
|
|
if (!areDeviceLabelsInitialized(state)) {
|
|
|
|
// The labels are not available if the A/V permissions are
|
|
|
|
// not yet granted.
|
|
|
|
|
|
|
|
Object.keys(deviceLabels).forEach(key => {
|
|
|
|
dispatch(addPendingDeviceRequest({
|
|
|
|
type: 'devices',
|
|
|
|
name: 'setDevice',
|
|
|
|
device: {
|
|
|
|
kind: key.toLowerCase(),
|
|
|
|
label: deviceLabels[key]
|
|
|
|
},
|
|
|
|
// eslint-disable-next-line no-empty-function
|
|
|
|
responseCallback() {}
|
|
|
|
}));
|
|
|
|
});
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
2019-05-16 21:00:55 +00:00
|
|
|
|
2019-03-27 17:30:56 +00:00
|
|
|
const newSettings = {};
|
|
|
|
|
|
|
|
Object.keys(deviceLabels).forEach(key => {
|
|
|
|
const label = deviceLabels[key];
|
2019-04-08 17:03:45 +00:00
|
|
|
const deviceId = getDeviceIdByLabel(state, label, key);
|
2019-03-27 17:30:56 +00:00
|
|
|
|
|
|
|
if (deviceId) {
|
2019-05-16 21:00:55 +00:00
|
|
|
const settingsTranslationMap = DEVICE_TYPE_TO_SETTINGS_KEYS[key];
|
|
|
|
|
|
|
|
newSettings[settingsTranslationMap.currentDeviceId] = deviceId;
|
|
|
|
newSettings[settingsTranslationMap.userSelectedDeviceId] = deviceId;
|
|
|
|
newSettings[settingsTranslationMap.userSelectedDeviceLabel] = label;
|
2019-03-27 17:30:56 +00:00
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
dispatch(updateSettings(newSettings));
|
|
|
|
});
|
|
|
|
} else {
|
2019-04-04 15:10:01 +00:00
|
|
|
updateSettingsPromise = Promise.resolve();
|
2019-03-27 17:30:56 +00:00
|
|
|
}
|
2019-04-04 15:10:01 +00:00
|
|
|
|
|
|
|
return updateSettingsPromise
|
|
|
|
.then(() => {
|
2019-05-07 08:53:01 +00:00
|
|
|
const userSelectedAudioOutputDeviceId = getUserSelectedOutputDeviceId(getState());
|
2019-04-04 15:10:01 +00:00
|
|
|
|
2019-05-01 14:13:25 +00:00
|
|
|
return setAudioOutputDeviceId(userSelectedAudioOutputDeviceId, dispatch)
|
2019-04-04 15:10:01 +00:00
|
|
|
.catch(ex => logger.warn(`Failed to set audio output device.
|
|
|
|
Default audio output device will be used instead ${ex}`));
|
|
|
|
});
|
|
|
|
};
|
2019-03-27 17:30:56 +00:00
|
|
|
}
|
2017-03-29 17:43:30 +00:00
|
|
|
|
|
|
|
/**
|
2018-08-06 15:24:59 +00:00
|
|
|
* Queries for connected A/V input and output devices and updates the redux
|
|
|
|
* state of known devices.
|
2017-03-29 17:43:30 +00:00
|
|
|
*
|
2018-08-06 15:24:59 +00:00
|
|
|
* @returns {Function}
|
2017-03-29 17:43:30 +00:00
|
|
|
*/
|
2018-08-06 15:24:59 +00:00
|
|
|
export function getAvailableDevices() {
|
|
|
|
return dispatch => new Promise(resolve => {
|
|
|
|
const { mediaDevices } = JitsiMeetJS;
|
|
|
|
|
|
|
|
if (mediaDevices.isDeviceListAvailable()
|
|
|
|
&& mediaDevices.isDeviceChangeAvailable()) {
|
|
|
|
mediaDevices.enumerateDevices(devices => {
|
|
|
|
dispatch(updateDeviceList(devices));
|
|
|
|
|
|
|
|
resolve(devices);
|
|
|
|
});
|
|
|
|
} else {
|
|
|
|
resolve([]);
|
|
|
|
}
|
|
|
|
});
|
2017-03-29 17:43:30 +00:00
|
|
|
}
|
|
|
|
|
2019-05-29 21:17:07 +00:00
|
|
|
/**
|
|
|
|
* Signals that an error occurred while trying to obtain a track from a camera.
|
|
|
|
*
|
|
|
|
* @param {Object} error - The device error, as provided by lib-jitsi-meet.
|
|
|
|
* @param {string} error.name - The constant for the type of the error.
|
|
|
|
* @param {string} error.message - Optional additional information about the
|
|
|
|
* error.
|
|
|
|
* @returns {{
|
|
|
|
* type: NOTIFY_CAMERA_ERROR,
|
|
|
|
* error: Object
|
|
|
|
* }}
|
|
|
|
*/
|
|
|
|
export function notifyCameraError(error) {
|
|
|
|
return {
|
|
|
|
type: NOTIFY_CAMERA_ERROR,
|
|
|
|
error
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Signals that an error occurred while trying to obtain a track from a mic.
|
|
|
|
*
|
|
|
|
* @param {Object} error - The device error, as provided by lib-jitsi-meet.
|
|
|
|
* @param {Object} error.name - The constant for the type of the error.
|
|
|
|
* @param {string} error.message - Optional additional information about the
|
|
|
|
* error.
|
|
|
|
* @returns {{
|
|
|
|
* type: NOTIFY_MIC_ERROR,
|
|
|
|
* error: Object
|
|
|
|
* }}
|
|
|
|
*/
|
|
|
|
export function notifyMicError(error) {
|
|
|
|
return {
|
|
|
|
type: NOTIFY_MIC_ERROR,
|
|
|
|
error
|
|
|
|
};
|
|
|
|
}
|
2019-03-27 17:30:56 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Remove all pending device requests.
|
|
|
|
*
|
|
|
|
* @returns {{
|
|
|
|
* type: REMOVE_PENDING_DEVICE_REQUESTS
|
|
|
|
* }}
|
|
|
|
*/
|
|
|
|
export function removePendingDeviceRequests() {
|
|
|
|
return {
|
|
|
|
type: REMOVE_PENDING_DEVICE_REQUESTS
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2017-03-29 17:43:30 +00:00
|
|
|
/**
|
2018-08-06 15:24:59 +00:00
|
|
|
* Signals to update the currently used audio input device.
|
2017-03-29 17:43:30 +00:00
|
|
|
*
|
2018-08-06 15:24:59 +00:00
|
|
|
* @param {string} deviceId - The id of the new audio input device.
|
2017-03-29 17:43:30 +00:00
|
|
|
* @returns {{
|
2018-08-06 15:24:59 +00:00
|
|
|
* type: SET_AUDIO_INPUT_DEVICE,
|
2017-03-29 17:43:30 +00:00
|
|
|
* deviceId: string
|
|
|
|
* }}
|
|
|
|
*/
|
2018-08-06 15:24:59 +00:00
|
|
|
export function setAudioInputDevice(deviceId) {
|
2017-03-29 17:43:30 +00:00
|
|
|
return {
|
2018-08-06 15:24:59 +00:00
|
|
|
type: SET_AUDIO_INPUT_DEVICE,
|
2017-03-29 17:43:30 +00:00
|
|
|
deviceId
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2020-04-14 06:53:04 +00:00
|
|
|
/**
|
|
|
|
* Sets the audio input device id and updates the settings
|
|
|
|
* so they are persisted across sessions.
|
|
|
|
*
|
|
|
|
* @param {string} deviceId - The id of the new audio input device.
|
|
|
|
* @returns {Function}
|
|
|
|
*/
|
|
|
|
export function setAudioInputDeviceAndUpdateSettings(deviceId) {
|
|
|
|
return function(dispatch, getState) {
|
|
|
|
const deviceLabel = getDeviceLabelById(getState(), deviceId, 'audioInput');
|
|
|
|
|
|
|
|
dispatch(setAudioInputDevice(deviceId));
|
|
|
|
dispatch(updateSettings({
|
|
|
|
userSelectedMicDeviceId: deviceId,
|
|
|
|
userSelectedMicDeviceLabel: deviceLabel
|
|
|
|
}));
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2020-03-30 14:17:18 +00:00
|
|
|
/**
|
|
|
|
* Updates the output device id.
|
|
|
|
*
|
|
|
|
* @param {string} deviceId - The id of the new output device.
|
|
|
|
* @returns {Function}
|
|
|
|
*/
|
|
|
|
export function setAudioOutputDevice(deviceId) {
|
2020-06-03 21:52:29 +00:00
|
|
|
return function(dispatch, getState) {
|
|
|
|
const deviceLabel = getDeviceLabelById(getState(), deviceId, 'audioOutput');
|
|
|
|
|
|
|
|
return setAudioOutputDeviceId(deviceId, dispatch, true, deviceLabel);
|
2020-03-30 14:17:18 +00:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2017-03-29 17:43:30 +00:00
|
|
|
/**
|
|
|
|
* Signals to update the currently used video input device.
|
|
|
|
*
|
|
|
|
* @param {string} deviceId - The id of the new video input device.
|
|
|
|
* @returns {{
|
|
|
|
* type: SET_VIDEO_INPUT_DEVICE,
|
|
|
|
* deviceId: string
|
|
|
|
* }}
|
|
|
|
*/
|
|
|
|
export function setVideoInputDevice(deviceId) {
|
|
|
|
return {
|
|
|
|
type: SET_VIDEO_INPUT_DEVICE,
|
|
|
|
deviceId
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2020-04-14 06:53:04 +00:00
|
|
|
/**
|
|
|
|
* Sets the video input device id and updates the settings
|
|
|
|
* so they are persisted across sessions.
|
|
|
|
*
|
|
|
|
* @param {string} deviceId - The id of the new video input device.
|
|
|
|
* @returns {Function}
|
|
|
|
*/
|
|
|
|
export function setVideoInputDeviceAndUpdateSettings(deviceId) {
|
|
|
|
return function(dispatch, getState) {
|
|
|
|
const deviceLabel = getDeviceLabelById(getState(), deviceId, 'videoInput');
|
|
|
|
|
|
|
|
dispatch(setVideoInputDevice(deviceId));
|
|
|
|
dispatch(updateSettings({
|
|
|
|
userSelectedCameraDeviceId: deviceId,
|
|
|
|
userSelectedCameraDeviceLabel: deviceLabel
|
|
|
|
}));
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2017-03-29 17:43:30 +00:00
|
|
|
/**
|
|
|
|
* Signals to update the list of known audio and video devices.
|
|
|
|
*
|
|
|
|
* @param {Array<MediaDeviceInfo>} devices - All known available audio input,
|
|
|
|
* audio output, and video input devices.
|
|
|
|
* @returns {{
|
|
|
|
* type: UPDATE_DEVICE_LIST,
|
|
|
|
* devices: Array<MediaDeviceInfo>
|
|
|
|
* }}
|
|
|
|
*/
|
|
|
|
export function updateDeviceList(devices) {
|
|
|
|
return {
|
|
|
|
type: UPDATE_DEVICE_LIST,
|
|
|
|
devices
|
|
|
|
};
|
|
|
|
}
|
2019-03-25 11:33:41 +00:00
|
|
|
|
2019-05-03 17:25:33 +00:00
|
|
|
/**
|
|
|
|
* Signals to check new and old devices for newly added devices and notify.
|
|
|
|
*
|
|
|
|
* @param {Array<MediaDeviceInfo>} newDevices - Array of the new devices.
|
|
|
|
* @param {Array<MediaDeviceInfo>} oldDevices - Array of the old devices.
|
|
|
|
* @returns {{
|
|
|
|
* type: CHECK_AND_NOTIFY_FOR_NEW_DEVICE,
|
|
|
|
* newDevices: Array<MediaDeviceInfo>,
|
|
|
|
* oldDevices: Array<MediaDeviceInfo>
|
|
|
|
* }}
|
|
|
|
*/
|
|
|
|
export function checkAndNotifyForNewDevice(newDevices, oldDevices) {
|
|
|
|
return {
|
|
|
|
type: CHECK_AND_NOTIFY_FOR_NEW_DEVICE,
|
|
|
|
newDevices,
|
|
|
|
oldDevices
|
|
|
|
};
|
|
|
|
}
|