浏览代码

feat(api): notify api of mic and camera errors (#4289)

- Use actions to notify the rest of the app that
  a mic or camera error has occurred
- Use middleware to respond to those notifications
  of errors by showing in-app notifications and
  notifying the external api
master
virtuacoplenny 6 年前
父节点
当前提交
251da1861a
没有帐户链接到提交者的电子邮件

+ 10
- 7
conference.js 查看文件

51
 import {
51
 import {
52
     checkAndNotifyForNewDevice,
52
     checkAndNotifyForNewDevice,
53
     getAvailableDevices,
53
     getAvailableDevices,
54
+    notifyCameraError,
55
+    notifyMicError,
54
     setAudioOutputDeviceId,
56
     setAudioOutputDeviceId,
55
     updateDeviceList
57
     updateDeviceList
56
 } from './react/features/base/devices';
58
 } from './react/features/base/devices';
694
                         // If both requests for 'audio' + 'video' and 'audio'
696
                         // If both requests for 'audio' + 'video' and 'audio'
695
                         // only failed, we assume that there are some problems
697
                         // only failed, we assume that there are some problems
696
                         // with user's microphone and show corresponding dialog.
698
                         // with user's microphone and show corresponding dialog.
697
-                        APP.UI.showMicErrorNotification(audioOnlyError);
698
-                        APP.UI.showCameraErrorNotification(videoOnlyError);
699
+                        APP.store.dispatch(notifyMicError(audioOnlyError));
700
+                        APP.store.dispatch(notifyCameraError(videoOnlyError));
699
                     } else {
701
                     } else {
700
                         // If request for 'audio' + 'video' failed, but request
702
                         // If request for 'audio' + 'video' failed, but request
701
                         // for 'audio' only was OK, we assume that we had
703
                         // for 'audio' only was OK, we assume that we had
702
                         // problems with camera and show corresponding dialog.
704
                         // problems with camera and show corresponding dialog.
703
-                        APP.UI.showCameraErrorNotification(audioAndVideoError);
705
+                        APP.store.dispatch(
706
+                            notifyCameraError(audioAndVideoError));
704
                     }
707
                     }
705
                 }
708
                 }
706
 
709
 
839
 
842
 
840
         if (!this.localAudio && !mute) {
843
         if (!this.localAudio && !mute) {
841
             const maybeShowErrorDialog = error => {
844
             const maybeShowErrorDialog = error => {
842
-                showUI && APP.UI.showMicErrorNotification(error);
845
+                showUI && APP.store.dispatch(notifyMicError(error));
843
             };
846
             };
844
 
847
 
845
             createLocalTracksF({ devices: [ 'audio' ] }, false)
848
             createLocalTracksF({ devices: [ 'audio' ] }, false)
902
 
905
 
903
         if (!this.localVideo && !mute) {
906
         if (!this.localVideo && !mute) {
904
             const maybeShowErrorDialog = error => {
907
             const maybeShowErrorDialog = error => {
905
-                showUI && APP.UI.showCameraErrorNotification(error);
908
+                showUI && APP.store.dispatch(notifyCameraError(error));
906
             };
909
             };
907
 
910
 
908
             // Try to create local video if there wasn't any.
911
             // Try to create local video if there wasn't any.
2109
                     this._updateVideoDeviceId();
2112
                     this._updateVideoDeviceId();
2110
                 })
2113
                 })
2111
                 .catch(err => {
2114
                 .catch(err => {
2112
-                    APP.UI.showCameraErrorNotification(err);
2115
+                    APP.store.dispatch(notifyCameraError(err));
2113
                 });
2116
                 });
2114
             }
2117
             }
2115
         );
2118
         );
2142
                     this._updateAudioDeviceId();
2145
                     this._updateAudioDeviceId();
2143
                 })
2146
                 })
2144
                 .catch(err => {
2147
                 .catch(err => {
2145
-                    APP.UI.showMicErrorNotification(err);
2148
+                    APP.store.dispatch(notifyMicError(err));
2146
                 });
2149
                 });
2147
             }
2150
             }
2148
         );
2151
         );

+ 16
- 0
doc/api.md 查看文件

264
 The `listener` parameter is a Function object with one argument that will be notified when the event occurs with data related to the event.
264
 The `listener` parameter is a Function object with one argument that will be notified when the event occurs with data related to the event.
265
 
265
 
266
 The following events are currently supported:
266
 The following events are currently supported:
267
+* **cameraError** - event notifications about Jitsi-Meet having failed to access the camera. The listener will receive an object with the following structure:
268
+```javascript
269
+{
270
+    type: string, // A constant representing the overall type of the error.
271
+    message: string // Additional information about the error.
272
+}
273
+```
274
+
267
 * **avatarChanged** - event notifications about avatar
275
 * **avatarChanged** - event notifications about avatar
268
 changes. The listener will receive an object with the following structure:
276
 changes. The listener will receive an object with the following structure:
269
 ```javascript
277
 ```javascript
287
 }
295
 }
288
 ```
296
 ```
289
 
297
 
298
+* **micError** - event notifications about Jitsi-Meet having failed to access the mic. The listener will receive an object with the following structure:
299
+```javascript
300
+{
301
+    type: string, // A constant representing the overall type of the error.
302
+    message: string // Additional information about the error.
303
+}
304
+```
305
+
290
 * **screenSharingStatusChanged** - receives event notifications about turning on/off the local user screen sharing. The listener will receive object with the following structure:
306
 * **screenSharingStatusChanged** - receives event notifications about turning on/off the local user screen sharing. The listener will receive object with the following structure:
291
 ```javascript
307
 ```javascript
292
 {
308
 {

+ 32
- 0
modules/API/API.js 查看文件

559
         });
559
         });
560
     }
560
     }
561
 
561
 
562
+    /**
563
+     * Notify external application of an unexpected camera-related error having
564
+     * occurred.
565
+     *
566
+     * @param {string} type - The type of the camera error.
567
+     * @param {string} message - Additional information about the error.
568
+     * @returns {void}
569
+     */
570
+    notifyOnCameraError(type: string, message: string) {
571
+        this._sendEvent({
572
+            name: 'camera-error',
573
+            type,
574
+            message
575
+        });
576
+    }
577
+
578
+    /**
579
+     * Notify external application of an unexpected mic-related error having
580
+     * occurred.
581
+     *
582
+     * @param {string} type - The type of the mic error.
583
+     * @param {string} message - Additional information about the error.
584
+     * @returns {void}
585
+     */
586
+    notifyOnMicError(type: string, message: string) {
587
+        this._sendEvent({
588
+            name: 'mic-error',
589
+            type,
590
+            message
591
+        });
592
+    }
593
+
562
     /**
594
     /**
563
      * Notify external application (if API is enabled) that conference feedback
595
      * Notify external application (if API is enabled) that conference feedback
564
      * has been submitted. Intended to be used in conjunction with the
596
      * has been submitted. Intended to be used in conjunction with the

+ 2
- 0
modules/API/external/external_api.js 查看文件

51
     'avatar-changed': 'avatarChanged',
51
     'avatar-changed': 'avatarChanged',
52
     'audio-availability-changed': 'audioAvailabilityChanged',
52
     'audio-availability-changed': 'audioAvailabilityChanged',
53
     'audio-mute-status-changed': 'audioMuteStatusChanged',
53
     'audio-mute-status-changed': 'audioMuteStatusChanged',
54
+    'camera-error': 'cameraError',
54
     'device-list-changed': 'deviceListChanged',
55
     'device-list-changed': 'deviceListChanged',
55
     'display-name-change': 'displayNameChange',
56
     'display-name-change': 'displayNameChange',
56
     'email-change': 'emailChange',
57
     'email-change': 'emailChange',
58
     'feedback-prompt-displayed': 'feedbackPromptDisplayed',
59
     'feedback-prompt-displayed': 'feedbackPromptDisplayed',
59
     'filmstrip-display-changed': 'filmstripDisplayChanged',
60
     'filmstrip-display-changed': 'filmstripDisplayChanged',
60
     'incoming-message': 'incomingMessage',
61
     'incoming-message': 'incomingMessage',
62
+    'mic-error': 'micError',
61
     'outgoing-message': 'outgoingMessage',
63
     'outgoing-message': 'outgoingMessage',
62
     'participant-joined': 'participantJoined',
64
     'participant-joined': 'participantJoined',
63
     'participant-left': 'participantLeft',
65
     'participant-left': 'participantLeft',

+ 1
- 97
modules/UI/UI.js 查看文件

13
 import VideoLayout from './videolayout/VideoLayout';
13
 import VideoLayout from './videolayout/VideoLayout';
14
 import Filmstrip from './videolayout/Filmstrip';
14
 import Filmstrip from './videolayout/Filmstrip';
15
 
15
 
16
-import { JitsiTrackErrors } from '../../react/features/base/lib-jitsi-meet';
17
 import { getLocalParticipant } from '../../react/features/base/participants';
16
 import { getLocalParticipant } from '../../react/features/base/participants';
18
 import { toggleChat } from '../../react/features/chat';
17
 import { toggleChat } from '../../react/features/chat';
19
 import { openDisplayNamePrompt } from '../../react/features/display-name';
18
 import { openDisplayNamePrompt } from '../../react/features/display-name';
20
 import { setEtherpadHasInitialzied } from '../../react/features/etherpad';
19
 import { setEtherpadHasInitialzied } from '../../react/features/etherpad';
21
 import { setFilmstripVisible } from '../../react/features/filmstrip';
20
 import { setFilmstripVisible } from '../../react/features/filmstrip';
22
-import {
23
-    setNotificationsEnabled,
24
-    showWarningNotification
25
-} from '../../react/features/notifications';
21
+import { setNotificationsEnabled } from '../../react/features/notifications';
26
 import {
22
 import {
27
     dockToolbox,
23
     dockToolbox,
28
     setToolboxEnabled,
24
     setToolboxEnabled,
40
 let etherpadManager;
36
 let etherpadManager;
41
 let sharedVideoManager;
37
 let sharedVideoManager;
42
 
38
 
43
-const JITSI_TRACK_ERROR_TO_MESSAGE_KEY_MAP = {
44
-    microphone: {},
45
-    camera: {}
46
-};
47
-
48
-JITSI_TRACK_ERROR_TO_MESSAGE_KEY_MAP
49
-    .camera[JitsiTrackErrors.UNSUPPORTED_RESOLUTION]
50
-        = 'dialog.cameraUnsupportedResolutionError';
51
-JITSI_TRACK_ERROR_TO_MESSAGE_KEY_MAP.camera[JitsiTrackErrors.GENERAL]
52
-    = 'dialog.cameraUnknownError';
53
-JITSI_TRACK_ERROR_TO_MESSAGE_KEY_MAP.camera[JitsiTrackErrors.PERMISSION_DENIED]
54
-    = 'dialog.cameraPermissionDeniedError';
55
-JITSI_TRACK_ERROR_TO_MESSAGE_KEY_MAP.camera[JitsiTrackErrors.NOT_FOUND]
56
-    = 'dialog.cameraNotFoundError';
57
-JITSI_TRACK_ERROR_TO_MESSAGE_KEY_MAP.camera[JitsiTrackErrors.CONSTRAINT_FAILED]
58
-    = 'dialog.cameraConstraintFailedError';
59
-JITSI_TRACK_ERROR_TO_MESSAGE_KEY_MAP
60
-    .camera[JitsiTrackErrors.NO_DATA_FROM_SOURCE]
61
-        = 'dialog.cameraNotSendingData';
62
-JITSI_TRACK_ERROR_TO_MESSAGE_KEY_MAP.microphone[JitsiTrackErrors.GENERAL]
63
-    = 'dialog.micUnknownError';
64
-JITSI_TRACK_ERROR_TO_MESSAGE_KEY_MAP
65
-    .microphone[JitsiTrackErrors.PERMISSION_DENIED]
66
-        = 'dialog.micPermissionDeniedError';
67
-JITSI_TRACK_ERROR_TO_MESSAGE_KEY_MAP.microphone[JitsiTrackErrors.NOT_FOUND]
68
-    = 'dialog.micNotFoundError';
69
-JITSI_TRACK_ERROR_TO_MESSAGE_KEY_MAP
70
-    .microphone[JitsiTrackErrors.CONSTRAINT_FAILED]
71
-        = 'dialog.micConstraintFailedError';
72
-JITSI_TRACK_ERROR_TO_MESSAGE_KEY_MAP
73
-    .microphone[JitsiTrackErrors.NO_DATA_FROM_SOURCE]
74
-        = 'dialog.micNotSendingData';
75
-
76
 const UIListeners = new Map([
39
 const UIListeners = new Map([
77
     [
40
     [
78
         UIEvents.ETHERPAD_CLICKED,
41
         UIEvents.ETHERPAD_CLICKED,
774
     });
737
     });
775
 };
738
 };
776
 
739
 
777
-/**
778
- * Shows a notifications about the passed in microphone error.
779
- *
780
- * @param {JitsiTrackError} micError - An error object related to using or
781
- * acquiring an audio stream.
782
- * @returns {void}
783
- */
784
-UI.showMicErrorNotification = function(micError) {
785
-    if (!micError) {
786
-        return;
787
-    }
788
-
789
-    const { message, name } = micError;
790
-
791
-    const micJitsiTrackErrorMsg
792
-        = JITSI_TRACK_ERROR_TO_MESSAGE_KEY_MAP.microphone[name];
793
-    const micErrorMsg = micJitsiTrackErrorMsg
794
-        || JITSI_TRACK_ERROR_TO_MESSAGE_KEY_MAP
795
-            .microphone[JitsiTrackErrors.GENERAL];
796
-    const additionalMicErrorMsg = micJitsiTrackErrorMsg ? null : message;
797
-
798
-    APP.store.dispatch(showWarningNotification({
799
-        description: additionalMicErrorMsg,
800
-        descriptionKey: micErrorMsg,
801
-        titleKey: name === JitsiTrackErrors.PERMISSION_DENIED
802
-            ? 'deviceError.microphonePermission'
803
-            : 'deviceError.microphoneError'
804
-    }));
805
-};
806
-
807
-/**
808
- * Shows a notifications about the passed in camera error.
809
- *
810
- * @param {JitsiTrackError} cameraError - An error object related to using or
811
- * acquiring a video stream.
812
- * @returns {void}
813
- */
814
-UI.showCameraErrorNotification = function(cameraError) {
815
-    if (!cameraError) {
816
-        return;
817
-    }
818
-
819
-    const { message, name } = cameraError;
820
-
821
-    const cameraJitsiTrackErrorMsg
822
-        = JITSI_TRACK_ERROR_TO_MESSAGE_KEY_MAP.camera[name];
823
-    const cameraErrorMsg = cameraJitsiTrackErrorMsg
824
-        || JITSI_TRACK_ERROR_TO_MESSAGE_KEY_MAP
825
-            .camera[JitsiTrackErrors.GENERAL];
826
-    const additionalCameraErrorMsg = cameraJitsiTrackErrorMsg ? null : message;
827
-
828
-    APP.store.dispatch(showWarningNotification({
829
-        description: additionalCameraErrorMsg,
830
-        descriptionKey: cameraErrorMsg,
831
-        titleKey: name === JitsiTrackErrors.PERMISSION_DENIED
832
-            ? 'deviceError.cameraPermission' : 'deviceError.cameraError'
833
-    }));
834
-};
835
-
836
 /**
740
 /**
837
  * Shows error dialog that informs the user that no data is received from the
741
  * Shows error dialog that informs the user that no data is received from the
838
  * device.
742
  * device.

+ 9
- 5
modules/devices/mediaDeviceHelper.js 查看文件

1
 /* global APP, JitsiMeetJS */
1
 /* global APP, JitsiMeetJS */
2
 
2
 
3
-import { getAudioOutputDeviceId } from '../../react/features/base/devices';
3
+import {
4
+    getAudioOutputDeviceId,
5
+    notifyCameraError,
6
+    notifyMicError
7
+} from '../../react/features/base/devices';
4
 import {
8
 import {
5
     getUserSelectedCameraDeviceId,
9
     getUserSelectedCameraDeviceId,
6
     getUserSelectedMicDeviceId,
10
     getUserSelectedMicDeviceId,
176
                 ]))
180
                 ]))
177
                 .then(tracks => {
181
                 .then(tracks => {
178
                     if (audioTrackError) {
182
                     if (audioTrackError) {
179
-                        APP.UI.showMicErrorNotification(audioTrackError);
183
+                        APP.store.dispatch(notifyMicError(audioTrackError));
180
                     }
184
                     }
181
 
185
 
182
                     if (videoTrackError) {
186
                     if (videoTrackError) {
183
-                        APP.UI.showCameraErrorNotification(videoTrackError);
187
+                        APP.store.dispatch(notifyCameraError(videoTrackError));
184
                     }
188
                     }
185
 
189
 
186
                     return tracks.filter(t => typeof t !== 'undefined');
190
                     return tracks.filter(t => typeof t !== 'undefined');
205
                 })
209
                 })
206
                 .catch(err => {
210
                 .catch(err => {
207
                     audioTrackError = err;
211
                     audioTrackError = err;
208
-                    showError && APP.UI.showMicErrorNotification(err);
212
+                    showError && APP.store.disptach(notifyMicError(err));
209
 
213
 
210
                     return [];
214
                     return [];
211
                 }));
215
                 }));
223
                 })
227
                 })
224
                 .catch(err => {
228
                 .catch(err => {
225
                     videoTrackError = err;
229
                     videoTrackError = err;
226
-                    showError && APP.UI.showCameraErrorNotification(err);
230
+                    showError && APP.store.dispatch(notifyCameraError(err));
227
 
231
 
228
                     return [];
232
                     return [];
229
                 }));
233
                 }));

+ 1
- 0
react/features/app/components/App.web.js 查看文件

6
 import { DialogContainer } from '../../base/dialog';
6
 import { DialogContainer } from '../../base/dialog';
7
 import '../../base/responsive-ui';
7
 import '../../base/responsive-ui';
8
 import '../../chat';
8
 import '../../chat';
9
+import '../../external-api';
9
 import '../../room-lock';
10
 import '../../room-lock';
10
 import '../../video-layout';
11
 import '../../video-layout';
11
 
12
 

+ 22
- 0
react/features/base/devices/actionTypes.js 查看文件

1
+/**
2
+ * The type of Redux action which signals that an error occurred while obtaining
3
+ * a camera.
4
+ *
5
+ * {
6
+ *     type: NOTIFY_CAMERA_ERROR,
7
+ *     error: Object
8
+ * }
9
+ */
10
+export const NOTIFY_CAMERA_ERROR = 'NOTIFY_CAMERA_ERROR';
11
+
12
+/**
13
+ * The type of Redux action which signals that an error occurred while obtaining
14
+ * a microphone.
15
+ *
16
+ * {
17
+ *     type: NOTIFY_MIC_ERROR,
18
+ *     error: Object
19
+ * }
20
+ */
21
+export const NOTIFY_MIC_ERROR = 'NOTIFY_MIC_ERROR';
22
+
1
 /**
23
 /**
2
  * The type of Redux action which signals that the currently used audio
24
  * The type of Redux action which signals that the currently used audio
3
  * input device should be changed.
25
  * input device should be changed.

+ 39
- 0
react/features/base/devices/actions.js 查看文件

7
 import {
7
 import {
8
     ADD_PENDING_DEVICE_REQUEST,
8
     ADD_PENDING_DEVICE_REQUEST,
9
     CHECK_AND_NOTIFY_FOR_NEW_DEVICE,
9
     CHECK_AND_NOTIFY_FOR_NEW_DEVICE,
10
+    NOTIFY_CAMERA_ERROR,
11
+    NOTIFY_MIC_ERROR,
10
     REMOVE_PENDING_DEVICE_REQUESTS,
12
     REMOVE_PENDING_DEVICE_REQUESTS,
11
     SET_AUDIO_INPUT_DEVICE,
13
     SET_AUDIO_INPUT_DEVICE,
12
     SET_VIDEO_INPUT_DEVICE,
14
     SET_VIDEO_INPUT_DEVICE,
148
     });
150
     });
149
 }
151
 }
150
 
152
 
153
+/**
154
+ * Signals that an error occurred while trying to obtain a track from a camera.
155
+ *
156
+ * @param {Object} error - The device error, as provided by lib-jitsi-meet.
157
+ * @param {string} error.name - The constant for the type of the error.
158
+ * @param {string} error.message - Optional additional information about the
159
+ * error.
160
+ * @returns {{
161
+ *     type: NOTIFY_CAMERA_ERROR,
162
+ *     error: Object
163
+ * }}
164
+ */
165
+export function notifyCameraError(error) {
166
+    return {
167
+        type: NOTIFY_CAMERA_ERROR,
168
+        error
169
+    };
170
+}
171
+
172
+/**
173
+ * Signals that an error occurred while trying to obtain a track from a mic.
174
+ *
175
+ * @param {Object} error - The device error, as provided by lib-jitsi-meet.
176
+ * @param {Object} error.name - The constant for the type of the error.
177
+ * @param {string} error.message - Optional additional information about the
178
+ * error.
179
+ * @returns {{
180
+ *     type: NOTIFY_MIC_ERROR,
181
+ *     error: Object
182
+ * }}
183
+ */
184
+export function notifyMicError(error) {
185
+    return {
186
+        type: NOTIFY_MIC_ERROR,
187
+        error
188
+    };
189
+}
151
 
190
 
152
 /**
191
 /**
153
  * Remove all pending device requests.
192
  * Remove all pending device requests.

+ 69
- 1
react/features/base/devices/middleware.js 查看文件

4
 import { processExternalDeviceRequest } from '../../device-selection';
4
 import { processExternalDeviceRequest } from '../../device-selection';
5
 import { MiddlewareRegistry } from '../redux';
5
 import { MiddlewareRegistry } from '../redux';
6
 import UIEvents from '../../../../service/UI/UIEvents';
6
 import UIEvents from '../../../../service/UI/UIEvents';
7
+import { JitsiTrackErrors } from '../lib-jitsi-meet';
7
 
8
 
8
 import {
9
 import {
9
     removePendingDeviceRequests,
10
     removePendingDeviceRequests,
12
 } from './actions';
13
 } from './actions';
13
 import {
14
 import {
14
     CHECK_AND_NOTIFY_FOR_NEW_DEVICE,
15
     CHECK_AND_NOTIFY_FOR_NEW_DEVICE,
16
+    NOTIFY_CAMERA_ERROR,
17
+    NOTIFY_MIC_ERROR,
15
     SET_AUDIO_INPUT_DEVICE,
18
     SET_AUDIO_INPUT_DEVICE,
16
     SET_VIDEO_INPUT_DEVICE
19
     SET_VIDEO_INPUT_DEVICE
17
 } from './actionTypes';
20
 } from './actionTypes';
18
-import { showNotification } from '../../notifications';
21
+import { showNotification, showWarningNotification } from '../../notifications';
19
 import { updateSettings } from '../settings';
22
 import { updateSettings } from '../settings';
20
 import { setAudioOutputDeviceId } from './functions';
23
 import { setAudioOutputDeviceId } from './functions';
21
 
24
 
22
 const logger = require('jitsi-meet-logger').getLogger(__filename);
25
 const logger = require('jitsi-meet-logger').getLogger(__filename);
23
 
26
 
27
+const JITSI_TRACK_ERROR_TO_MESSAGE_KEY_MAP = {
28
+    microphone: {
29
+        [JitsiTrackErrors.CONSTRAINT_FAILED]: 'dialog.micConstraintFailedError',
30
+        [JitsiTrackErrors.GENERAL]: 'dialog.micUnknownError',
31
+        [JitsiTrackErrors.NO_DATA_FROM_SOURCE]: 'dialog.micNotSendingData',
32
+        [JitsiTrackErrors.NOT_FOUND]: 'dialog.micNotFoundError',
33
+        [JitsiTrackErrors.PERMISSION_DENIED]: 'dialog.micPermissionDeniedError'
34
+    },
35
+    camera: {
36
+        [JitsiTrackErrors.CONSTRAINT_FAILED]: 'dialog.cameraConstraintFailedError',
37
+        [JitsiTrackErrors.GENERAL]: 'dialog.cameraUnknownError',
38
+        [JitsiTrackErrors.NO_DATA_FROM_SOURCE]: 'dialog.cameraNotSendingData',
39
+        [JitsiTrackErrors.NOT_FOUND]: 'dialog.cameraNotFoundError',
40
+        [JitsiTrackErrors.PERMISSION_DENIED]: 'dialog.cameraPermissionDeniedError',
41
+        [JitsiTrackErrors.UNSUPPORTED_RESOLUTION]: 'dialog.cameraUnsupportedResolutionError'
42
+    }
43
+};
44
+
24
 /**
45
 /**
25
  * Implements the middleware of the feature base/devices.
46
  * Implements the middleware of the feature base/devices.
26
  *
47
  *
32
     switch (action.type) {
53
     switch (action.type) {
33
     case CONFERENCE_JOINED:
54
     case CONFERENCE_JOINED:
34
         return _conferenceJoined(store, next, action);
55
         return _conferenceJoined(store, next, action);
56
+    case NOTIFY_CAMERA_ERROR: {
57
+        if (typeof APP !== 'object' || !action.error) {
58
+            break;
59
+        }
60
+
61
+        const { message, name } = action.error;
62
+
63
+        const cameraJitsiTrackErrorMsg
64
+            = JITSI_TRACK_ERROR_TO_MESSAGE_KEY_MAP.camera[name];
65
+        const cameraErrorMsg = cameraJitsiTrackErrorMsg
66
+            || JITSI_TRACK_ERROR_TO_MESSAGE_KEY_MAP
67
+                .camera[JitsiTrackErrors.GENERAL];
68
+        const additionalCameraErrorMsg = cameraJitsiTrackErrorMsg ? null : message;
69
+
70
+        store.dispatch(showWarningNotification({
71
+            description: additionalCameraErrorMsg,
72
+            descriptionKey: cameraErrorMsg,
73
+            titleKey: name === JitsiTrackErrors.PERMISSION_DENIED
74
+                ? 'deviceError.cameraPermission' : 'deviceError.cameraError'
75
+        }));
76
+
77
+        break;
78
+    }
79
+    case NOTIFY_MIC_ERROR: {
80
+        if (typeof APP !== 'object' || !action.error) {
81
+            break;
82
+        }
83
+
84
+        const { message, name } = action.error;
85
+
86
+        const micJitsiTrackErrorMsg
87
+            = JITSI_TRACK_ERROR_TO_MESSAGE_KEY_MAP.microphone[name];
88
+        const micErrorMsg = micJitsiTrackErrorMsg
89
+            || JITSI_TRACK_ERROR_TO_MESSAGE_KEY_MAP
90
+                .microphone[JitsiTrackErrors.GENERAL];
91
+        const additionalMicErrorMsg = micJitsiTrackErrorMsg ? null : message;
92
+
93
+        store.dispatch(showWarningNotification({
94
+            description: additionalMicErrorMsg,
95
+            descriptionKey: micErrorMsg,
96
+            titleKey: name === JitsiTrackErrors.PERMISSION_DENIED
97
+                ? 'deviceError.microphonePermission'
98
+                : 'deviceError.microphoneError'
99
+        }));
100
+
101
+        break;
102
+    }
35
     case SET_AUDIO_INPUT_DEVICE:
103
     case SET_AUDIO_INPUT_DEVICE:
36
         APP.UI.emitEvent(UIEvents.AUDIO_DEVICE_CHANGED, action.deviceId);
104
         APP.UI.emitEvent(UIEvents.AUDIO_DEVICE_CHANGED, action.deviceId);
37
         break;
105
         break;

+ 1
- 0
react/features/external-api/index.js 查看文件

1
+import './middleware';

+ 30
- 0
react/features/external-api/middleware.js 查看文件

1
+// @flow
2
+
3
+import { NOTIFY_CAMERA_ERROR, NOTIFY_MIC_ERROR } from '../base/devices';
4
+import { MiddlewareRegistry } from '../base/redux';
5
+
6
+declare var APP: Object;
7
+
8
+/**
9
+ * The middleware of the feature {@code external-api}.
10
+ *
11
+ * @returns {Function}
12
+ */
13
+MiddlewareRegistry.register((/* store */) => next => action => {
14
+    switch (action.type) {
15
+    case NOTIFY_CAMERA_ERROR:
16
+        if (action.error) {
17
+            APP.API.notifyOnCameraError(
18
+              action.error.name, action.error.message);
19
+        }
20
+        break;
21
+
22
+    case NOTIFY_MIC_ERROR:
23
+        if (action.error) {
24
+            APP.API.notifyOnMicError(action.error.name, action.error.message);
25
+        }
26
+        break;
27
+    }
28
+
29
+    return next(action);
30
+});

正在加载...
取消
保存