fix(api-devices): Initial device function calls
This commit is contained in:
parent
427f49367b
commit
ed1d3d3df5
16
doc/api.md
16
doc/api.md
|
@ -29,6 +29,7 @@ Its constructor gets a number of options:
|
|||
* **jwt**: (optional) [JWT](https://jwt.io/) token.
|
||||
* **onload**: (optional) handler for the iframe onload event.
|
||||
* **invitees**: (optional) Array of objects containing information about new participants that will be invited in the call.
|
||||
* **devices**: (optional) A map containing information about the initial devices that will be used in the call.
|
||||
|
||||
Example:
|
||||
|
||||
|
@ -43,6 +44,21 @@ var options = {
|
|||
var api = new JitsiMeetExternalAPI(domain, options);
|
||||
```
|
||||
|
||||
You can set the initial media devices for the call:
|
||||
|
||||
```javascript
|
||||
var domain = "meet.jit.si";
|
||||
var options = {
|
||||
...
|
||||
devices: {
|
||||
'audioInput': '<device_id>',
|
||||
'audioOutput': '<device_id>',
|
||||
'videoInput': '<device_id>'
|
||||
}
|
||||
}
|
||||
var api = new JitsiMeetExternalAPI(domain, options);
|
||||
```
|
||||
|
||||
You can overwrite options set in [config.js] and [interface_config.js].
|
||||
For example, to enable the filmstrip-only interface mode, you can use:
|
||||
|
||||
|
|
|
@ -221,6 +221,8 @@ export default class JitsiMeetExternalAPI extends EventEmitter {
|
|||
* for iframe onload event.
|
||||
* @param {Array<Object>} [options.invitees] - Array of objects containing
|
||||
* information about new participants that will be invited in the call.
|
||||
* @param {Array<Object>} [options.devices] - Array of objects containing
|
||||
* information about the initial devices that will be used in the call.
|
||||
*/
|
||||
constructor(domain, ...args) {
|
||||
super();
|
||||
|
@ -234,7 +236,8 @@ export default class JitsiMeetExternalAPI extends EventEmitter {
|
|||
noSSL = false,
|
||||
jwt = undefined,
|
||||
onload = undefined,
|
||||
invitees
|
||||
invitees,
|
||||
devices
|
||||
} = parseArguments(args);
|
||||
|
||||
this._parentNode = parentNode;
|
||||
|
@ -243,7 +246,8 @@ export default class JitsiMeetExternalAPI extends EventEmitter {
|
|||
interfaceConfigOverwrite,
|
||||
jwt,
|
||||
noSSL,
|
||||
roomName
|
||||
roomName,
|
||||
devices
|
||||
});
|
||||
this._createIFrame(height, width, onload);
|
||||
this._transport = new Transport({
|
||||
|
|
|
@ -7,6 +7,8 @@ declare var config: Object;
|
|||
|
||||
const logger = require('jitsi-meet-logger').getLogger(__filename);
|
||||
|
||||
import { configureInitialDevices } from '../devices';
|
||||
|
||||
export {
|
||||
connectionEstablished,
|
||||
connectionFailed,
|
||||
|
@ -25,12 +27,13 @@ export function connect() {
|
|||
|
||||
// XXX For web based version we use conference initialization logic
|
||||
// from the old app (at the moment of writing).
|
||||
return APP.conference.init({
|
||||
roomName: room
|
||||
}).catch(error => {
|
||||
APP.API.notifyConferenceLeft(APP.conference.roomName);
|
||||
logger.error(error);
|
||||
});
|
||||
return dispatch(configureInitialDevices()).then(
|
||||
() => APP.conference.init({
|
||||
roomName: room
|
||||
}).catch(error => {
|
||||
APP.API.notifyConferenceLeft(APP.conference.roomName);
|
||||
logger.error(error);
|
||||
}));
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
import JitsiMeetJS from '../lib-jitsi-meet';
|
||||
import { updateSettings } from '../settings';
|
||||
|
||||
import {
|
||||
SET_AUDIO_INPUT_DEVICE,
|
||||
SET_VIDEO_INPUT_DEVICE,
|
||||
UPDATE_DEVICE_LIST
|
||||
} from './actionTypes';
|
||||
import { getDevicesFromURL } from './functions';
|
||||
|
||||
/**
|
||||
* Queries for connected A/V input and output devices and updates the redux
|
||||
|
@ -77,3 +79,22 @@ export function updateDeviceList(devices) {
|
|||
devices
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures the initial A/V devices before the conference has started.
|
||||
*
|
||||
* @returns {Function}
|
||||
*/
|
||||
export function configureInitialDevices() {
|
||||
return (dispatch, getState) => new Promise(resolve => {
|
||||
const devices = getDevicesFromURL(getState());
|
||||
|
||||
if (devices) {
|
||||
dispatch(updateSettings({
|
||||
...devices
|
||||
}));
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
// @flow
|
||||
|
||||
import { parseURLParams } from '../config';
|
||||
import JitsiMeetJS from '../lib-jitsi-meet';
|
||||
import { updateSettings } from '../settings';
|
||||
|
||||
|
@ -30,3 +31,47 @@ export function setAudioOutputDeviceId(
|
|||
audioOutputDeviceId: newId
|
||||
})));
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts an array of media devices into an object organized by device kind.
|
||||
*
|
||||
* @param {Array<MediaDeviceInfo>} devices - Available media devices.
|
||||
* @private
|
||||
* @returns {Object} An object with the media devices split by type. The keys
|
||||
* are device type and the values are arrays with devices matching the device
|
||||
* type.
|
||||
*/
|
||||
export function groupDevicesByKind(devices: Object[]): Object {
|
||||
return {
|
||||
audioInput: devices.filter(device => device.kind === 'audioinput'),
|
||||
audioOutput: devices.filter(device => device.kind === 'audiooutput'),
|
||||
videoInput: devices.filter(device => device.kind === 'videoinput')
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the devices set in the URL.
|
||||
*
|
||||
* @param {Object} state - The redux state.
|
||||
* @returns {Object|undefined}
|
||||
*/
|
||||
export function getDevicesFromURL(state: Object) {
|
||||
const urlParams
|
||||
= parseURLParams(state['features/base/connection'].locationURL);
|
||||
|
||||
const audioOutputDeviceId = urlParams['devices.audioOutput'];
|
||||
const cameraDeviceId = urlParams['devices.videoInput'];
|
||||
const micDeviceId = urlParams['devices.audioInput'];
|
||||
|
||||
if (!audioOutputDeviceId && !cameraDeviceId && !micDeviceId) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const devices = {};
|
||||
|
||||
audioOutputDeviceId && (devices.audioOutputDeviceId = audioOutputDeviceId);
|
||||
cameraDeviceId && (devices.cameraDeviceId = cameraDeviceId);
|
||||
micDeviceId && (devices.micDeviceId = micDeviceId);
|
||||
|
||||
return devices;
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ import {
|
|||
SET_VIDEO_INPUT_DEVICE,
|
||||
UPDATE_DEVICE_LIST
|
||||
} from './actionTypes';
|
||||
import { groupDevicesByKind } from './functions';
|
||||
|
||||
import { ReducerRegistry } from '../redux';
|
||||
|
||||
|
@ -27,7 +28,7 @@ ReducerRegistry.register(
|
|||
(state = DEFAULT_STATE, action) => {
|
||||
switch (action.type) {
|
||||
case UPDATE_DEVICE_LIST: {
|
||||
const deviceList = _groupDevicesByKind(action.devices);
|
||||
const deviceList = groupDevicesByKind(action.devices);
|
||||
|
||||
return {
|
||||
...deviceList
|
||||
|
@ -44,19 +45,3 @@ ReducerRegistry.register(
|
|||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Converts an array of media devices into an object organized by device kind.
|
||||
*
|
||||
* @param {Array<MediaDeviceInfo>} devices - Available media devices.
|
||||
* @private
|
||||
* @returns {Object} An object with the media devices split by type. The keys
|
||||
* are device type and the values are arrays with devices matching the device
|
||||
* type.
|
||||
*/
|
||||
function _groupDevicesByKind(devices) {
|
||||
return {
|
||||
audioInput: devices.filter(device => device.kind === 'audioinput'),
|
||||
audioOutput: devices.filter(device => device.kind === 'audiooutput'),
|
||||
videoInput: devices.filter(device => device.kind === 'videoinput')
|
||||
};
|
||||
}
|
||||
|
|
|
@ -469,16 +469,16 @@ export function urlObjectToString(o: Object): ?string {
|
|||
|
||||
let { hash } = url;
|
||||
|
||||
for (const configName of [ 'config', 'interfaceConfig' ]) {
|
||||
for (const urlPrefix of [ 'config', 'interfaceConfig', 'devices' ]) {
|
||||
const urlParamsArray
|
||||
= _objectToURLParamsArray(
|
||||
o[`${configName}Overwrite`]
|
||||
|| o[configName]
|
||||
|| o[`${configName}Override`]);
|
||||
o[`${urlPrefix}Overwrite`]
|
||||
|| o[urlPrefix]
|
||||
|| o[`${urlPrefix}Override`]);
|
||||
|
||||
if (urlParamsArray.length) {
|
||||
let urlParamsString
|
||||
= `${configName}.${urlParamsArray.join(`&${configName}.`)}`;
|
||||
= `${urlPrefix}.${urlParamsArray.join(`&${urlPrefix}.`)}`;
|
||||
|
||||
if (hash.length) {
|
||||
urlParamsString = `&${urlParamsString}`;
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
// @flow
|
||||
import {
|
||||
getAudioOutputDeviceId,
|
||||
getAvailableDevices,
|
||||
groupDevicesByKind,
|
||||
setAudioInputDevice,
|
||||
setAudioOutputDeviceId,
|
||||
setVideoInputDevice
|
||||
|
@ -46,7 +48,11 @@ export function getDeviceSelectionDialogProps(stateful: Object | Function) {
|
|||
* response.
|
||||
* @returns {boolean}
|
||||
*/
|
||||
export function processRequest(dispatch: Dispatch<*>, getState: Function, request: Object, responseCallback: Function) { // eslint-disable-line max-len, max-params
|
||||
export function processRequest( // 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'];
|
||||
|
@ -71,7 +77,9 @@ export function processRequest(dispatch: Dispatch<*>, getState: Function, reques
|
|||
});
|
||||
break;
|
||||
case 'getAvailableDevices':
|
||||
responseCallback(getState()['features/base/devices']);
|
||||
dispatch(getAvailableDevices()).then(
|
||||
devices => responseCallback(groupDevicesByKind(devices)));
|
||||
|
||||
break;
|
||||
case 'setDevice': {
|
||||
const { device } = request;
|
||||
|
@ -87,7 +95,7 @@ export function processRequest(dispatch: Dispatch<*>, getState: Function, reques
|
|||
dispatch(setVideoInputDevice(device.id));
|
||||
break;
|
||||
default:
|
||||
|
||||
responseCallback(false);
|
||||
}
|
||||
|
||||
responseCallback(true);
|
||||
|
|
Loading…
Reference in New Issue