Selaa lähdekoodia

ref(iframe-api-devices): Use labels instead of IDs

master
Hristo Terezov 6 vuotta sitten
vanhempi
commit
4967488e56

+ 13
- 13
doc/api.md Näytä tiedosto

51
 var options = {
51
 var options = {
52
     ...
52
     ...
53
     devices: {
53
     devices: {
54
-        'audioInput': '<device_id>',
55
-        'audioOutput': '<device_id>',
56
-        'videoInput': '<device_id>'
54
+        'audioInput': '<deviceLabel>',
55
+        'audioOutput': '<deviceLabel>',
56
+        'videoInput': '<deviceLabel>'
57
     }
57
     }
58
 }
58
 }
59
 var api = new JitsiMeetExternalAPI(domain, options);
59
 var api = new JitsiMeetExternalAPI(domain, options);
109
     ...
109
     ...
110
 });
110
 });
111
 ```
111
 ```
112
-* **getCurrentDevices** - Retrieve a list with the devices that are currently sected.
112
+* **getCurrentDevices** - Retrieve a list with the devices that are currently selected.
113
 
113
 
114
 ```javascript
114
 ```javascript
115
 api.getCurrentDevices().then(function(devices) {
115
 api.getCurrentDevices().then(function(devices) {
116
     // devices = {
116
     // devices = {
117
-    //     'audioInput': 'deviceID',
118
-    //     'audioOutput': 'deviceID',
119
-    //     'videoInput': 'deviceID'
117
+    //     'audioInput': 'deviceLabel',
118
+    //     'audioOutput': 'deviceLabel',
119
+    //     'videoInput': 'deviceLabel'
120
     // }
120
     // }
121
     ...
121
     ...
122
 });
122
 });
143
     ...
143
     ...
144
 });
144
 });
145
 ```
145
 ```
146
-* **setAudioInputDevice** - Sets the audio input device to the one with the id that is passed.
146
+* **setAudioInputDevice** - Sets the audio input device to the one with the label that is passed.
147
 
147
 
148
 ```javascript
148
 ```javascript
149
-api.setAudioInputDevice(deviceId);
149
+api.setAudioInputDevice(deviceLabel);
150
 ```
150
 ```
151
-* **setAudioOutputDevice** - Sets the audio output device to the one with the id that is passed.
151
+* **setAudioOutputDevice** - Sets the audio output device to the one with the label that is passed.
152
 
152
 
153
 ```javascript
153
 ```javascript
154
-api.setAudioOutputDevice(deviceId);
154
+api.setAudioOutputDevice(deviceLabel);
155
 ```
155
 ```
156
-* **setVideoInputDevice** - Sets the video input device to the one with the id that is passed.
156
+* **setVideoInputDevice** - Sets the video input device to the one with the label that is passed.
157
 
157
 
158
 ```javascript
158
 ```javascript
159
-api.setVideoInputDevice(deviceId);
159
+api.setVideoInputDevice(deviceLabel);
160
 ```
160
 ```
161
 
161
 
162
 You can control the embedded Jitsi Meet conference using the `JitsiMeetExternalAPI` object by using `executeCommand`:
162
 You can control the embedded Jitsi Meet conference using the `JitsiMeetExternalAPI` object by using `executeCommand`:

+ 9
- 9
modules/API/external/functions.js Näytä tiedosto

105
  *
105
  *
106
  * @param {Transport} transport - The @code{Transport} instance responsible for
106
  * @param {Transport} transport - The @code{Transport} instance responsible for
107
  * the external communication.
107
  * the external communication.
108
- * @param {string} id - The id of the new device.
108
+ * @param {string} label - The label of the new device.
109
  * @returns {Promise}
109
  * @returns {Promise}
110
  */
110
  */
111
-export function setAudioInputDevice(transport: Object, id: string) {
111
+export function setAudioInputDevice(transport: Object, label: string) {
112
     return _setDevice(transport, {
112
     return _setDevice(transport, {
113
-        id,
113
+        label,
114
         kind: 'audioinput'
114
         kind: 'audioinput'
115
     });
115
     });
116
 }
116
 }
120
  *
120
  *
121
  * @param {Transport} transport - The @code{Transport} instance responsible for
121
  * @param {Transport} transport - The @code{Transport} instance responsible for
122
  * the external communication.
122
  * the external communication.
123
- * @param {string} id - The id of the new device.
123
+ * @param {string} label - The label of the new device.
124
  * @returns {Promise}
124
  * @returns {Promise}
125
  */
125
  */
126
-export function setAudioOutputDevice(transport: Object, id: string) {
126
+export function setAudioOutputDevice(transport: Object, label: string) {
127
     return _setDevice(transport, {
127
     return _setDevice(transport, {
128
-        id,
128
+        label,
129
         kind: 'audiooutput'
129
         kind: 'audiooutput'
130
     });
130
     });
131
 }
131
 }
151
  *
151
  *
152
  * @param {Transport} transport - The @code{Transport} instance responsible for
152
  * @param {Transport} transport - The @code{Transport} instance responsible for
153
  * the external communication.
153
  * the external communication.
154
- * @param {string} id - The id of the new device.
154
+ * @param {string} label - The label of the new device.
155
  * @returns {Promise}
155
  * @returns {Promise}
156
  */
156
  */
157
-export function setVideoInputDevice(transport: Object, id: string) {
157
+export function setVideoInputDevice(transport: Object, label: string) {
158
     return _setDevice(transport, {
158
     return _setDevice(transport, {
159
-        id,
159
+        label,
160
         kind: 'videoinput'
160
         kind: 'videoinput'
161
     });
161
     });
162
 }
162
 }

+ 21
- 0
react/features/base/devices/actionTypes.js Näytä tiedosto

30
  * }
30
  * }
31
  */
31
  */
32
 export const UPDATE_DEVICE_LIST = 'UPDATE_DEVICE_LIST';
32
 export const UPDATE_DEVICE_LIST = 'UPDATE_DEVICE_LIST';
33
+
34
+/**
35
+ * The type of Redux action which will add a pending device requests that will
36
+ * be executed later when it is possible (when the conference is joined).
37
+ *
38
+ * {
39
+ *     type: ADD_PENDING_DEVICE_REQUEST,
40
+ *     request: Object
41
+ * }
42
+ */
43
+export const ADD_PENDING_DEVICE_REQUEST = 'ADD_PENDING_DEVICE_REQUEST';
44
+
45
+/**
46
+ * The type of Redux action which will remove all pending device requests.
47
+ *
48
+ * {
49
+ *     type: REMOVE_PENDING_DEVICE_REQUESTS,
50
+ *     request: Object
51
+ * }
52
+ */
53
+export const REMOVE_PENDING_DEVICE_REQUESTS = 'REMOVE_PENDING_DEVICE_REQUESTS';

+ 96
- 19
react/features/base/devices/actions.js Näytä tiedosto

2
 import { updateSettings } from '../settings';
2
 import { updateSettings } from '../settings';
3
 
3
 
4
 import {
4
 import {
5
+    ADD_PENDING_DEVICE_REQUEST,
6
+    REMOVE_PENDING_DEVICE_REQUESTS,
5
     SET_AUDIO_INPUT_DEVICE,
7
     SET_AUDIO_INPUT_DEVICE,
6
     SET_VIDEO_INPUT_DEVICE,
8
     SET_VIDEO_INPUT_DEVICE,
7
     UPDATE_DEVICE_LIST
9
     UPDATE_DEVICE_LIST
8
 } from './actionTypes';
10
 } from './actionTypes';
9
-import { getDevicesFromURL } from './functions';
11
+import {
12
+    areDeviceLabelsInitialized,
13
+    getDeviceIdByLabel,
14
+    getDevicesFromURL
15
+} from './functions';
16
+
17
+/**
18
+ * Adds a pending device request.
19
+ *
20
+ * @param {Object} request - The request to be added.
21
+ * @returns {{
22
+ *      type: ADD_PENDING_DEVICE_REQUEST,
23
+ *      request: Object
24
+ * }}
25
+ */
26
+export function addPendingDeviceRequest(request) {
27
+    return {
28
+        type: ADD_PENDING_DEVICE_REQUEST,
29
+        request
30
+    };
31
+}
32
+
33
+/**
34
+ * Configures the initial A/V devices before the conference has started.
35
+ *
36
+ * @returns {Function}
37
+ */
38
+export function configureInitialDevices() {
39
+    return (dispatch, getState) => new Promise(resolve => {
40
+        const deviceLabels = getDevicesFromURL(getState());
41
+
42
+        if (deviceLabels) {
43
+            dispatch(getAvailableDevices()).then(() => {
44
+                const state = getState();
45
+
46
+                if (!areDeviceLabelsInitialized(state)) {
47
+                    // The labels are not available if the A/V permissions are
48
+                    // not yet granted.
49
+
50
+                    Object.keys(deviceLabels).forEach(key => {
51
+                        dispatch(addPendingDeviceRequest({
52
+                            type: 'devices',
53
+                            name: 'setDevice',
54
+                            device: {
55
+                                kind: key.toLowerCase(),
56
+                                label: deviceLabels[key]
57
+                            },
58
+                            // eslint-disable-next-line no-empty-function
59
+                            responseCallback() {}
60
+                        }));
61
+                    });
62
+                    resolve();
63
+
64
+                    return;
65
+                }
66
+                const newSettings = {};
67
+                const devicesKeysToSettingsKeys = {
68
+                    audioInput: 'micDeviceId',
69
+                    audioOutput: 'audioOutputDeviceId',
70
+                    videoInput: 'cameraDeviceId'
71
+                };
72
+
73
+                Object.keys(deviceLabels).forEach(key => {
74
+                    const label = deviceLabels[key];
75
+                    const deviceId = getDeviceIdByLabel(state, label);
76
+
77
+                    if (deviceId) {
78
+                        newSettings[devicesKeysToSettingsKeys[key]] = deviceId;
79
+                    }
80
+                });
81
+
82
+                dispatch(updateSettings(newSettings));
83
+                resolve();
84
+            });
85
+
86
+        } else {
87
+            resolve();
88
+        }
89
+    });
90
+}
10
 
91
 
11
 /**
92
 /**
12
  * Queries for connected A/V input and output devices and updates the redux
93
  * Queries for connected A/V input and output devices and updates the redux
31
     });
112
     });
32
 }
113
 }
33
 
114
 
115
+
116
+/**
117
+ * Remove all pending device requests.
118
+ *
119
+ * @returns {{
120
+ *      type: REMOVE_PENDING_DEVICE_REQUESTS
121
+ * }}
122
+ */
123
+export function removePendingDeviceRequests() {
124
+    return {
125
+        type: REMOVE_PENDING_DEVICE_REQUESTS
126
+    };
127
+}
128
+
34
 /**
129
 /**
35
  * Signals to update the currently used audio input device.
130
  * Signals to update the currently used audio input device.
36
  *
131
  *
80
     };
175
     };
81
 }
176
 }
82
 
177
 
83
-/**
84
- * Configures the initial A/V devices before the conference has started.
85
- *
86
- * @returns {Function}
87
- */
88
-export function configureInitialDevices() {
89
-    return (dispatch, getState) => new Promise(resolve => {
90
-        const devices = getDevicesFromURL(getState());
91
-
92
-        if (devices) {
93
-            dispatch(updateSettings({
94
-                ...devices
95
-            }));
96
-            resolve();
97
-        }
98
-    });
99
-}
100
-

+ 79
- 35
react/features/base/devices/functions.js Näytä tiedosto

4
 import JitsiMeetJS from '../lib-jitsi-meet';
4
 import JitsiMeetJS from '../lib-jitsi-meet';
5
 import { updateSettings } from '../settings';
5
 import { updateSettings } from '../settings';
6
 
6
 
7
+declare var APP: Object;
8
+
9
+/**
10
+ * Detects the use case when the labels are not available if the A/V permissions
11
+ * are not yet granted.
12
+ *
13
+ * @param {Object} state - The redux state.
14
+ * @returns {boolean} - True if the labels are already initialized and false
15
+ * otherwise.
16
+ */
17
+export function areDeviceLabelsInitialized(state: Object) {
18
+    if (APP.conference._localTracksInitialized) {
19
+        return true;
20
+    }
21
+
22
+    for (const type of [ 'audioInput', 'audioOutput', 'videoInput' ]) {
23
+        if (state['features/base/devices'][type].find(d => Boolean(d.label))) {
24
+            return true;
25
+        }
26
+    }
27
+
28
+    return false;
29
+}
30
+
7
 /**
31
 /**
8
  * Get device id of the audio output device which is currently in use.
32
  * Get device id of the audio output device which is currently in use.
9
  * Empty string stands for default device.
33
  * Empty string stands for default device.
15
 }
39
 }
16
 
40
 
17
 /**
41
 /**
18
- * Set device id of the audio output device which is currently in use.
19
- * Empty string stands for default device.
42
+ * Finds a device with a label that matches the passed label and returns its id.
20
  *
43
  *
21
- * @param {string} newId - New audio output device id.
22
- * @param {Function} dispatch - The Redux dispatch function.
23
- * @returns {Promise}
44
+ * @param {Object} state - The redux state.
45
+ * @param {string} label - The label.
46
+ * @returns {string|undefined}
24
  */
47
  */
25
-export function setAudioOutputDeviceId(
26
-        newId: string = 'default',
27
-        dispatch: Function): Promise<*> {
28
-    return JitsiMeetJS.mediaDevices.setAudioOutputDevice(newId)
29
-        .then(() =>
30
-            dispatch(updateSettings({
31
-                audioOutputDeviceId: newId
32
-            })));
48
+export function getDeviceIdByLabel(state: Object, label: string) {
49
+    const types = [ 'audioInput', 'audioOutput', 'videoInput' ];
50
+
51
+    for (const type of types) {
52
+        const device
53
+            = state['features/base/devices'][type].find(d => d.label === label);
54
+
55
+        if (device) {
56
+            return device.deviceId;
57
+        }
58
+    }
59
+}
60
+
61
+/**
62
+ * Returns the devices set in the URL.
63
+ *
64
+ * @param {Object} state - The redux state.
65
+ * @returns {Object|undefined}
66
+ */
67
+export function getDevicesFromURL(state: Object) {
68
+    const urlParams
69
+        = parseURLParams(state['features/base/connection'].locationURL);
70
+
71
+    const audioOutput = urlParams['devices.audioOutput'];
72
+    const videoInput = urlParams['devices.videoInput'];
73
+    const audioInput = urlParams['devices.audioInput'];
74
+
75
+    if (!audioOutput && !videoInput && !audioInput) {
76
+        return undefined;
77
+    }
78
+
79
+    const devices = {};
80
+
81
+    audioOutput && (devices.audioOutput = audioOutput);
82
+    videoInput && (devices.videoInput = videoInput);
83
+    audioInput && (devices.audioInput = audioInput);
84
+
85
+    return devices;
33
 }
86
 }
34
 
87
 
35
 /**
88
 /**
50
 }
103
 }
51
 
104
 
52
 /**
105
 /**
53
- * Returns the devices set in the URL.
106
+ * Set device id of the audio output device which is currently in use.
107
+ * Empty string stands for default device.
54
  *
108
  *
55
- * @param {Object} state - The redux state.
56
- * @returns {Object|undefined}
109
+ * @param {string} newId - New audio output device id.
110
+ * @param {Function} dispatch - The Redux dispatch function.
111
+ * @returns {Promise}
57
  */
112
  */
58
-export function getDevicesFromURL(state: Object) {
59
-    const urlParams
60
-        = parseURLParams(state['features/base/connection'].locationURL);
61
-
62
-    const audioOutputDeviceId = urlParams['devices.audioOutput'];
63
-    const cameraDeviceId = urlParams['devices.videoInput'];
64
-    const micDeviceId = urlParams['devices.audioInput'];
65
-
66
-    if (!audioOutputDeviceId && !cameraDeviceId && !micDeviceId) {
67
-        return undefined;
68
-    }
69
-
70
-    const devices = {};
71
-
72
-    audioOutputDeviceId && (devices.audioOutputDeviceId = audioOutputDeviceId);
73
-    cameraDeviceId && (devices.cameraDeviceId = cameraDeviceId);
74
-    micDeviceId && (devices.micDeviceId = micDeviceId);
75
-
76
-    return devices;
113
+export function setAudioOutputDeviceId(
114
+        newId: string = 'default',
115
+        dispatch: Function): Promise<*> {
116
+    return JitsiMeetJS.mediaDevices.setAudioOutputDevice(newId)
117
+        .then(() =>
118
+            dispatch(updateSettings({
119
+                audioOutputDeviceId: newId
120
+            })));
77
 }
121
 }

+ 37
- 2
react/features/base/devices/middleware.js Näytä tiedosto

1
 /* global APP */
1
 /* global APP */
2
 
2
 
3
-import UIEvents from '../../../../service/UI/UIEvents';
4
-
3
+import { CONFERENCE_JOINED } from '../conference';
4
+import { processRequest } from '../../device-selection';
5
 import { MiddlewareRegistry } from '../redux';
5
 import { MiddlewareRegistry } from '../redux';
6
+import UIEvents from '../../../../service/UI/UIEvents';
6
 
7
 
8
+import { removePendingDeviceRequests } from './actions';
7
 import {
9
 import {
8
     SET_AUDIO_INPUT_DEVICE,
10
     SET_AUDIO_INPUT_DEVICE,
9
     SET_VIDEO_INPUT_DEVICE
11
     SET_VIDEO_INPUT_DEVICE
18
 // eslint-disable-next-line no-unused-vars
20
 // eslint-disable-next-line no-unused-vars
19
 MiddlewareRegistry.register(store => next => action => {
21
 MiddlewareRegistry.register(store => next => action => {
20
     switch (action.type) {
22
     switch (action.type) {
23
+    case CONFERENCE_JOINED:
24
+        return _conferenceJoined(store, next, action);
21
     case SET_AUDIO_INPUT_DEVICE:
25
     case SET_AUDIO_INPUT_DEVICE:
22
         APP.UI.emitEvent(UIEvents.AUDIO_DEVICE_CHANGED, action.deviceId);
26
         APP.UI.emitEvent(UIEvents.AUDIO_DEVICE_CHANGED, action.deviceId);
23
         break;
27
         break;
28
 
32
 
29
     return next(action);
33
     return next(action);
30
 });
34
 });
35
+
36
+
37
+/**
38
+ * Does extra sync up on properties that may need to be updated after the
39
+ * conference was joined.
40
+ *
41
+ * @param {Store} store - The redux store in which the specified {@code action}
42
+ * is being dispatched.
43
+ * @param {Dispatch} next - The redux {@code dispatch} function to dispatch the
44
+ * specified {@code action} to the specified {@code store}.
45
+ * @param {Action} action - The redux action {@code CONFERENCE_JOINED} which is
46
+ * being dispatched in the specified {@code store}.
47
+ * @private
48
+ * @returns {Object} The value returned by {@code next(action)}.
49
+ */
50
+function _conferenceJoined({ dispatch, getState }, next, action) {
51
+    const result = next(action);
52
+    const state = getState();
53
+    const { pendingRequests } = state['features/base/devices'];
54
+
55
+    pendingRequests.forEach(request => {
56
+        processRequest(
57
+            dispatch,
58
+            getState,
59
+            request,
60
+            request.responseCallback);
61
+    });
62
+    dispatch(removePendingDeviceRequests());
63
+
64
+    return result;
65
+}

+ 20
- 1
react/features/base/devices/reducer.js Näytä tiedosto

1
 import {
1
 import {
2
+    ADD_PENDING_DEVICE_REQUEST,
3
+    REMOVE_PENDING_DEVICE_REQUESTS,
2
     SET_AUDIO_INPUT_DEVICE,
4
     SET_AUDIO_INPUT_DEVICE,
3
     SET_VIDEO_INPUT_DEVICE,
5
     SET_VIDEO_INPUT_DEVICE,
4
     UPDATE_DEVICE_LIST
6
     UPDATE_DEVICE_LIST
10
 const DEFAULT_STATE = {
12
 const DEFAULT_STATE = {
11
     audioInput: [],
13
     audioInput: [],
12
     audioOutput: [],
14
     audioOutput: [],
13
-    videoInput: []
15
+    videoInput: [],
16
+    pendingRequests: []
14
 };
17
 };
15
 
18
 
16
 /**
19
 /**
31
             const deviceList = groupDevicesByKind(action.devices);
34
             const deviceList = groupDevicesByKind(action.devices);
32
 
35
 
33
             return {
36
             return {
37
+                pendingRequests: state.pendingRequests,
34
                 ...deviceList
38
                 ...deviceList
35
             };
39
             };
36
         }
40
         }
37
 
41
 
42
+        case ADD_PENDING_DEVICE_REQUEST:
43
+            return {
44
+                ...state,
45
+                pendingRequests: [
46
+                    ...state.pendingRequests,
47
+                    action.request
48
+                ]
49
+            };
50
+
51
+        case REMOVE_PENDING_DEVICE_REQUESTS:
52
+            return {
53
+                ...state,
54
+                pendingRequests: [ ]
55
+            };
56
+
38
         // TODO: Changing of current audio and video device id is currently
57
         // TODO: Changing of current audio and video device id is currently
39
         // handled outside of react/redux. Fall through to default logic for
58
         // handled outside of react/redux. Fall through to default logic for
40
         // now.
59
         // now.

+ 88
- 20
react/features/device-selection/functions.js Näytä tiedosto

1
 // @flow
1
 // @flow
2
+
3
+import type { Dispatch } from 'redux';
4
+
2
 import {
5
 import {
6
+    addPendingDeviceRequest,
7
+    areDeviceLabelsInitialized,
3
     getAudioOutputDeviceId,
8
     getAudioOutputDeviceId,
4
     getAvailableDevices,
9
     getAvailableDevices,
10
+    getDeviceIdByLabel,
5
     groupDevicesByKind,
11
     groupDevicesByKind,
6
     setAudioInputDevice,
12
     setAudioInputDevice,
7
     setAudioOutputDeviceId,
13
     setAudioOutputDeviceId,
49
  * @returns {boolean}
55
  * @returns {boolean}
50
  */
56
  */
51
 export function processRequest( // eslint-disable-line max-params
57
 export function processRequest( // eslint-disable-line max-params
52
-        dispatch: Dispatch<*>,
58
+        dispatch: Dispatch<any>,
53
         getState: Function,
59
         getState: Function,
54
         request: Object,
60
         request: Object,
55
         responseCallback: Function) {
61
         responseCallback: Function) {
56
     if (request.type === 'devices') {
62
     if (request.type === 'devices') {
57
         const state = getState();
63
         const state = getState();
58
         const settings = state['features/base/settings'];
64
         const settings = state['features/base/settings'];
65
+        const { conference } = state['features/base/conference'];
66
+        let result = true;
59
 
67
 
60
         switch (request.name) {
68
         switch (request.name) {
61
         case 'isDeviceListAvailable':
69
         case 'isDeviceListAvailable':
70
             responseCallback(JitsiMeetJS.isMultipleAudioInputSupported());
78
             responseCallback(JitsiMeetJS.isMultipleAudioInputSupported());
71
             break;
79
             break;
72
         case 'getCurrentDevices':
80
         case 'getCurrentDevices':
73
-            responseCallback({
74
-                audioInput: settings.micDeviceId,
75
-                audioOutput: getAudioOutputDeviceId(),
76
-                videoInput: settings.cameraDeviceId
81
+            dispatch(getAvailableDevices()).then(devices => {
82
+                if (areDeviceLabelsInitialized(state)) {
83
+                    let audioInput, audioOutput, videoInput;
84
+                    const audioOutputDeviceId = getAudioOutputDeviceId();
85
+                    const { cameraDeviceId, micDeviceId } = settings;
86
+
87
+                    devices.forEach(({ deviceId, label }) => {
88
+                        switch (deviceId) {
89
+                        case micDeviceId:
90
+                            audioInput = label;
91
+                            break;
92
+                        case audioOutputDeviceId:
93
+                            audioOutput = label;
94
+                            break;
95
+                        case cameraDeviceId:
96
+                            videoInput = label;
97
+                            break;
98
+                        }
99
+                    });
100
+
101
+                    responseCallback({
102
+                        audioInput,
103
+                        audioOutput,
104
+                        videoInput
105
+                    });
106
+                } else {
107
+                    // The labels are not available if the A/V permissions are
108
+                    // not yet granted.
109
+                    dispatch(addPendingDeviceRequest({
110
+                        type: 'devices',
111
+                        name: 'getCurrentDevices',
112
+                        responseCallback
113
+                    }));
114
+                }
77
             });
115
             });
116
+
78
             break;
117
             break;
79
         case 'getAvailableDevices':
118
         case 'getAvailableDevices':
80
-            dispatch(getAvailableDevices()).then(
81
-                devices => responseCallback(groupDevicesByKind(devices)));
119
+            dispatch(getAvailableDevices()).then(devices => {
120
+                if (areDeviceLabelsInitialized(state)) {
121
+                    responseCallback(groupDevicesByKind(devices));
122
+                } else {
123
+                    // The labels are not available if the A/V permissions are
124
+                    // not yet granted.
125
+                    dispatch(addPendingDeviceRequest({
126
+                        type: 'devices',
127
+                        name: 'getAvailableDevices',
128
+                        responseCallback
129
+                    }));
130
+                }
131
+            });
82
 
132
 
83
             break;
133
             break;
84
         case 'setDevice': {
134
         case 'setDevice': {
85
             const { device } = request;
135
             const { device } = request;
86
 
136
 
87
-            switch (device.kind) {
88
-            case 'audioinput':
89
-                dispatch(setAudioInputDevice(device.id));
90
-                break;
91
-            case 'audiooutput':
92
-                setAudioOutputDeviceId(device.id, dispatch);
93
-                break;
94
-            case 'videoinput':
95
-                dispatch(setVideoInputDevice(device.id));
96
-                break;
97
-            default:
98
-                responseCallback(false);
137
+            if (!conference) {
138
+                dispatch(addPendingDeviceRequest({
139
+                    type: 'devices',
140
+                    name: 'setDevice',
141
+                    device,
142
+                    responseCallback
143
+                }));
144
+
145
+                return true;
146
+            }
147
+
148
+            const deviceId = getDeviceIdByLabel(state, device.label);
149
+
150
+            if (deviceId) {
151
+                switch (device.kind) {
152
+                case 'audioinput': {
153
+                    dispatch(setAudioInputDevice(deviceId));
154
+                    break;
155
+                }
156
+                case 'audiooutput':
157
+                    setAudioOutputDeviceId(deviceId, dispatch);
158
+                    break;
159
+                case 'videoinput':
160
+                    dispatch(setVideoInputDevice(deviceId));
161
+                    break;
162
+                default:
163
+                    result = false;
164
+                }
165
+            } else {
166
+                result = false;
99
             }
167
             }
100
 
168
 
101
-            responseCallback(true);
169
+            responseCallback(result);
102
             break;
170
             break;
103
         }
171
         }
104
         default:
172
         default:

Loading…
Peruuta
Tallenna