Browse Source

Show dialog for GUM errors

master
tsareg 9 years ago
parent
commit
448fcf36b6
4 changed files with 211 additions and 31 deletions
  1. 82
    29
      conference.js
  2. 13
    1
      lang/main.json
  3. 94
    1
      modules/UI/UI.js
  4. 22
    0
      modules/UI/side_pannels/settings/SettingsMenu.js

+ 82
- 29
conference.js View File

375
             };
375
             };
376
         }
376
         }
377
 
377
 
378
+        let audioAndVideoError, audioOnlyError;
379
+
378
         return JitsiMeetJS.init(config).then(() => {
380
         return JitsiMeetJS.init(config).then(() => {
379
             return Promise.all([
381
             return Promise.all([
380
                 // try to retrieve audio and video
382
                 // try to retrieve audio and video
381
                 createLocalTracks(['audio', 'video'])
383
                 createLocalTracks(['audio', 'video'])
382
                 // if failed then try to retrieve only audio
384
                 // if failed then try to retrieve only audio
383
-                    .catch(() => createLocalTracks(['audio']))
385
+                    .catch(err => {
386
+                        audioAndVideoError = err;
387
+                        return createLocalTracks(['audio']);
388
+                    })
384
                 // if audio also failed then just return empty array
389
                 // if audio also failed then just return empty array
385
-                    .catch(() => []),
390
+                    .catch(err => {
391
+                        audioOnlyError = err;
392
+                        return [];
393
+                    }),
386
                 connect(options.roomName)
394
                 connect(options.roomName)
387
             ]);
395
             ]);
388
         }).then(([tracks, con]) => {
396
         }).then(([tracks, con]) => {
397
+            if (audioAndVideoError) {
398
+                if (audioOnlyError) {
399
+                    // If both requests for 'audio' + 'video' and 'audio' only
400
+                    // failed, we assume that there is some problems with user's
401
+                    // microphone and show corresponding dialog.
402
+                    APP.UI.showDeviceErrorDialog('microphone', audioOnlyError);
403
+                } else {
404
+                    // If request for 'audio' + 'video' failed, but request for
405
+                    // 'audio' only was OK, we assume that we had problems with
406
+                    // camera and show corresponding dialog.
407
+                    APP.UI.showDeviceErrorDialog('camera', audioAndVideoError);
408
+                }
409
+            }
410
+
389
             console.log('initialized with %s local tracks', tracks.length);
411
             console.log('initialized with %s local tracks', tracks.length);
390
             APP.connection = connection = con;
412
             APP.connection = connection = con;
391
             this._createRoom(tracks);
413
             this._createRoom(tracks);
541
                 }
563
                 }
542
 
564
 
543
                 function createNewTracks(type, cameraDeviceId, micDeviceId) {
565
                 function createNewTracks(type, cameraDeviceId, micDeviceId) {
566
+                    let audioOnlyError, videoOnlyError;
567
+
544
                     return createLocalTracks(type, cameraDeviceId, micDeviceId)
568
                     return createLocalTracks(type, cameraDeviceId, micDeviceId)
545
                         .then(onTracksCreated)
569
                         .then(onTracksCreated)
546
-                        .catch(() => {
570
+                        .catch((err) => {
547
                             // if we tried to create both audio and video tracks
571
                             // if we tried to create both audio and video tracks
548
                             // at once and failed, let's try again only with
572
                             // at once and failed, let's try again only with
549
                             // audio. Such situation may happen in case if we
573
                             // audio. Such situation may happen in case if we
553
                                 && type.indexOf('video') !== -1) {
577
                                 && type.indexOf('video') !== -1) {
554
                                 return createLocalTracks(['audio'], null,
578
                                 return createLocalTracks(['audio'], null,
555
                                     micDeviceId);
579
                                     micDeviceId);
580
+                            } else if (type.indexOf('audio') !== -1) {
581
+                                audioOnlyError = err;
582
+                            } else if (type.indexOf('video') !== -1) {
583
+                                videoOnlyError = err;
556
                             }
584
                             }
557
 
585
 
558
                         })
586
                         })
559
                         .then(onTracksCreated)
587
                         .then(onTracksCreated)
560
-                        .catch(() => {
588
+                        .catch((err) => {
561
                             // if we tried to create both audio and video tracks
589
                             // if we tried to create both audio and video tracks
562
                             // at once and failed, let's try again only with
590
                             // at once and failed, let's try again only with
563
                             // video. Such situation may happen in case if we
591
                             // video. Such situation may happen in case if we
564
                             // granted access only to camera, but not to
592
                             // granted access only to camera, but not to
565
                             // microphone.
593
                             // microphone.
594
+                            audioOnlyError = err;
566
                             if (type.indexOf('audio') !== -1
595
                             if (type.indexOf('audio') !== -1
567
                                 && type.indexOf('video') !== -1) {
596
                                 && type.indexOf('video') !== -1) {
568
                                 return createLocalTracks(['video'],
597
                                 return createLocalTracks(['video'],
571
                             }
600
                             }
572
                         })
601
                         })
573
                         .then(onTracksCreated)
602
                         .then(onTracksCreated)
574
-                        .catch(() => {
575
-                            // can't do anything in this case, so just ignore;
603
+                        .catch((err) => {
604
+                            videoOnlyError = err;
605
+
606
+                            if (videoOnlyError) {
607
+                                APP.UI.showDeviceErrorDialog(
608
+                                    'camera', videoOnlyError);
609
+                            }
610
+
611
+                            if (audioOnlyError) {
612
+                                APP.UI.showDeviceErrorDialog(
613
+                                    'microphone', audioOnlyError);
614
+                            }
576
                         });
615
                         });
577
                 }
616
                 }
578
 
617
 
896
                 this.isSharingScreen = stream.videoType === 'desktop';
935
                 this.isSharingScreen = stream.videoType === 'desktop';
897
 
936
 
898
                 APP.UI.addLocalStream(stream);
937
                 APP.UI.addLocalStream(stream);
938
+
939
+                stream.videoType === 'camera' && APP.UI.enableCameraButton();
899
             } else {
940
             } else {
900
                 this.videoMuted = false;
941
                 this.videoMuted = false;
901
                 this.isSharingScreen = false;
942
                 this.isSharingScreen = false;
902
             }
943
             }
903
 
944
 
904
-            stream.videoType === 'camera' && APP.UI.enableCameraButton();
905
-
906
             APP.UI.setVideoMuted(this.localId, this.videoMuted);
945
             APP.UI.setVideoMuted(this.localId, this.videoMuted);
907
 
946
 
908
             APP.UI.updateDesktopSharingButtons();
947
             APP.UI.updateDesktopSharingButtons();
990
                     return;
1029
                     return;
991
                 }
1030
                 }
992
 
1031
 
993
-                // TODO: handle Permission error
994
-
995
                 // Handling:
1032
                 // Handling:
1033
+                // TrackErrors.PERMISSION_DENIED
996
                 // TrackErrors.CHROME_EXTENSION_INSTALLATION_ERROR
1034
                 // TrackErrors.CHROME_EXTENSION_INSTALLATION_ERROR
997
                 // TrackErrors.GENERAL
1035
                 // TrackErrors.GENERAL
998
                 // and any other
1036
                 // and any other
999
-                let dialogTxt = APP.translation
1000
-                    .generateTranslationHTML("dialog.failtoinstall");
1001
-                let dialogTitle = APP.translation
1002
-                    .generateTranslationHTML("dialog.error");
1003
-                APP.UI.messageHandler.openDialog(
1004
-                    dialogTitle,
1005
-                    dialogTxt,
1006
-                    false
1007
-                );
1037
+                let dialogTxt = APP.translation.generateTranslationHTML(
1038
+                    err.name === TrackErrors.PERMISSION_DENIED
1039
+                        ? "dialog.screenSharingPermissionDeniedError"
1040
+                        : "dialog.failtoinstall");
1041
+
1042
+                let dialogTitle = APP.translation.generateTranslationHTML(
1043
+                    err.name === TrackErrors.PERMISSION_DENIED
1044
+                        ? "dialog.permissionDenied"
1045
+                        : "dialog.error");
1046
+
1047
+                APP.UI.messageHandler.openDialog(dialogTitle, dialogTxt, false);
1008
             });
1048
             });
1009
         } else {
1049
         } else {
1010
             createLocalTracks(['video']).then(
1050
             createLocalTracks(['video']).then(
1016
                 this.useVideoStream(null);
1056
                 this.useVideoStream(null);
1017
                 this.videoSwitchInProgress = false;
1057
                 this.videoSwitchInProgress = false;
1018
                 console.error('failed to share local video', err);
1058
                 console.error('failed to share local video', err);
1059
+
1060
+                APP.UI.showDeviceErrorDialog('camera', err);
1019
             });
1061
             });
1020
         }
1062
         }
1021
     },
1063
     },
1357
         APP.UI.addListener(
1399
         APP.UI.addListener(
1358
             UIEvents.VIDEO_DEVICE_CHANGED,
1400
             UIEvents.VIDEO_DEVICE_CHANGED,
1359
             (cameraDeviceId) => {
1401
             (cameraDeviceId) => {
1360
-                APP.settings.setCameraDeviceId(cameraDeviceId);
1361
-                createLocalTracks(['video']).then(([stream]) => {
1362
-                    this.useVideoStream(stream);
1363
-                    console.log('switched local video device');
1364
-                });
1402
+                createLocalTracks(['video'])
1403
+                    .then(([stream]) => {
1404
+                        this.useVideoStream(stream);
1405
+                        console.log('switched local video device');
1406
+                        APP.settings.setCameraDeviceId(cameraDeviceId);
1407
+                    })
1408
+                    .catch((err) => {
1409
+                        APP.UI.showDeviceErrorDialog('camera', err);
1410
+                        APP.UI.setSelectedCameraFromSettings();
1411
+                    });
1365
             }
1412
             }
1366
         );
1413
         );
1367
 
1414
 
1368
         APP.UI.addListener(
1415
         APP.UI.addListener(
1369
             UIEvents.AUDIO_DEVICE_CHANGED,
1416
             UIEvents.AUDIO_DEVICE_CHANGED,
1370
             (micDeviceId) => {
1417
             (micDeviceId) => {
1371
-                APP.settings.setMicDeviceId(micDeviceId);
1372
-                createLocalTracks(['audio']).then(([stream]) => {
1373
-                    this.useAudioStream(stream);
1374
-                    console.log('switched local audio device');
1375
-                });
1418
+                createLocalTracks(['audio'])
1419
+                    .then(([stream]) => {
1420
+                        this.useAudioStream(stream);
1421
+                        console.log('switched local audio device');
1422
+                        APP.settings.setMicDeviceId(micDeviceId);
1423
+                    })
1424
+                    .catch((err) => {
1425
+                        APP.UI.showDeviceErrorDialog('microphone', err);
1426
+                        APP.UI.setSelectedMicFromSettings();
1427
+                    });
1376
             }
1428
             }
1377
         );
1429
         );
1378
 
1430
 
1383
                     .then(() => console.log('changed audio output device'))
1435
                     .then(() => console.log('changed audio output device'))
1384
                     .catch((err) => {
1436
                     .catch((err) => {
1385
                         console.error('failed to set audio output device', err);
1437
                         console.error('failed to set audio output device', err);
1438
+                        APP.UI.setSelectedAudioOutputFromSettings();
1386
                     });
1439
                     });
1387
             }
1440
             }
1388
         );
1441
         );

+ 13
- 1
lang/main.json View File

222
         "stopStreamingWarning": "Are you sure you would like to stop the live streaming?",
222
         "stopStreamingWarning": "Are you sure you would like to stop the live streaming?",
223
         "stopRecordingWarning": "Are you sure you would like to stop the recording?",
223
         "stopRecordingWarning": "Are you sure you would like to stop the recording?",
224
         "stopLiveStreaming": "Stop live streaming",
224
         "stopLiveStreaming": "Stop live streaming",
225
-        "stopRecording": "Stop recording"
225
+        "stopRecording": "Stop recording",
226
+        "doNotShowWarningAgain": "Don't show this warning again",
227
+        "permissionDenied": "Permission Denied",
228
+        "screenSharingPermissionDeniedError": "You have not granted permission to share your screen.",
229
+        "cameraUnsupportedResolutionError": "Your camera does not support required video resolution.",
230
+        "cameraUnknownError": "Cannot use camera for a unknown reason.",
231
+        "cameraPermissionDeniedError": "You have not granted permission to use your camera.",
232
+        "cameraNotFoundError": "Requested camera was not found.",
233
+        "cameraConstraintFailedError": "Yor camera does not satisfy some of required constraints.",
234
+        "micUnknownError": "Cannot use microphone for a unknown reason.",
235
+        "micPermissionDeniedError": "You have not granted permission to use your microphone.",
236
+        "micNotFoundError": "Requested microphone was not found.",
237
+        "micConstraintFailedError": "Yor microphone does not satisfy some of required constraints."
226
     },
238
     },
227
     "email":
239
     "email":
228
     {
240
     {

+ 94
- 1
modules/UI/UI.js View File

1
-/* global APP, $, config, interfaceConfig, toastr */
1
+/* global APP, JitsiMeetJS, $, config, interfaceConfig, toastr */
2
 /* jshint -W101 */
2
 /* jshint -W101 */
3
 var UI = {};
3
 var UI = {};
4
 
4
 
38
 
38
 
39
 let followMeHandler;
39
 let followMeHandler;
40
 
40
 
41
+const TrackErrors = JitsiMeetJS.errors.track;
42
+
43
+const JITSI_TRACK_ERROR_TO_MESSAGE_KEY_MAP = {
44
+    microphone: {},
45
+    camera: {}
46
+};
47
+
48
+JITSI_TRACK_ERROR_TO_MESSAGE_KEY_MAP.camera[TrackErrors.UNSUPPORTED_RESOLUTION]
49
+    = "dialog.cameraUnsupportedResolutionError";
50
+JITSI_TRACK_ERROR_TO_MESSAGE_KEY_MAP.camera[TrackErrors.GENERAL]
51
+    = "dialog.cameraUnknownError";
52
+JITSI_TRACK_ERROR_TO_MESSAGE_KEY_MAP.camera[TrackErrors.PERMISSION_DENIED]
53
+    = "dialog.cameraPermissionDeniedError";
54
+JITSI_TRACK_ERROR_TO_MESSAGE_KEY_MAP.camera[TrackErrors.NOT_FOUND]
55
+    = "dialog.cameraNotFoundError";
56
+JITSI_TRACK_ERROR_TO_MESSAGE_KEY_MAP.camera[TrackErrors.CONSTRAINT_FAILED]
57
+    = "dialog.cameraConstraintFailedError";
58
+JITSI_TRACK_ERROR_TO_MESSAGE_KEY_MAP.microphone[TrackErrors.GENERAL]
59
+    = "dialog.micUnknownError";
60
+JITSI_TRACK_ERROR_TO_MESSAGE_KEY_MAP.microphone[TrackErrors.PERMISSION_DENIED]
61
+    = "dialog.micPermissionDeniedError";
62
+JITSI_TRACK_ERROR_TO_MESSAGE_KEY_MAP.microphone[TrackErrors.NOT_FOUND]
63
+    = "dialog.micNotFoundError";
64
+JITSI_TRACK_ERROR_TO_MESSAGE_KEY_MAP.microphone[TrackErrors.CONSTRAINT_FAILED]
65
+    = "dialog.micConstraintFailedError";
66
+
41
 /**
67
 /**
42
  * Prompt user for nickname.
68
  * Prompt user for nickname.
43
  */
69
  */
1078
     SettingsMenu.changeDevicesList(devices);
1104
     SettingsMenu.changeDevicesList(devices);
1079
 };
1105
 };
1080
 
1106
 
1107
+/**
1108
+ * Sets microphone's <select> element to select microphone ID from settings.
1109
+ */
1110
+UI.setSelectedMicFromSettings = function () {
1111
+    SettingsMenu.setSelectedMicFromSettings();
1112
+};
1113
+
1114
+/**
1115
+ * Sets camera's <select> element to select camera ID from settings.
1116
+ */
1117
+UI.setSelectedCameraFromSettings = function () {
1118
+    SettingsMenu.setSelectedCameraFromSettings();
1119
+};
1120
+
1121
+/**
1122
+ * Sets audio outputs's <select> element to select audio output ID from
1123
+ * settings.
1124
+ */
1125
+UI.setSelectedAudioOutputFromSettings = function () {
1126
+    SettingsMenu.setSelectedAudioOutputFromSettings();
1127
+};
1128
+
1081
 /**
1129
 /**
1082
  * Returns the id of the current video shown on large.
1130
  * Returns the id of the current video shown on large.
1083
  * Currently used by tests (torture).
1131
  * Currently used by tests (torture).
1106
             "dialog.firefoxExtensionPrompt", {url: url}));
1154
             "dialog.firefoxExtensionPrompt", {url: url}));
1107
 };
1155
 };
1108
 
1156
 
1157
+/**
1158
+ * Shows dialog with information about camera or microphone error.
1159
+ * @param {'microphone'|'camera'} type
1160
+ * @param {JitsiTrackError} error
1161
+ */
1162
+UI.showDeviceErrorDialog = function (type, error) {
1163
+    if (type !== "microphone" && type !== "camera") {
1164
+        throw new Error("Invalid device type");
1165
+    }
1166
+
1167
+    if (window.localStorage[type + "DoNotShowErrorAgain-" + error.name]
1168
+        === "true") {
1169
+        return;
1170
+    }
1171
+
1172
+    let titleKey = error.name === TrackErrors.PERMISSION_DENIED
1173
+            ? "dialog.permissionDenied"
1174
+            : "dialog.error",
1175
+        errorMsg = JITSI_TRACK_ERROR_TO_MESSAGE_KEY_MAP[type][error.name],
1176
+        doNotShowAgainMsg = "dialog.doNotShowWarningAgain",
1177
+        title = `<span data-i18n="${titleKey}"></span>`,
1178
+        message = `
1179
+            <h4 data-i18n="${errorMsg}"></h4>
1180
+            <label>
1181
+                <input type="checkbox" id="doNotShowWarningAgain">
1182
+                <span data-i18n="${doNotShowAgainMsg}"></span>
1183
+            </label>`;
1184
+
1185
+    messageHandler.openDialog(
1186
+        title,
1187
+        message,
1188
+        false,
1189
+        {Ok: true},
1190
+        function () {
1191
+            let form  = $.prompt.getPrompt(),
1192
+                input = form.find("#doNotShowWarningAgain");
1193
+
1194
+            window.localStorage[type + "DoNotShowErrorAgain-" + error.name]
1195
+                = input.prop("checked");
1196
+        }
1197
+    );
1198
+
1199
+    APP.translation.translateElement($(".jqibox"));
1200
+};
1201
+
1109
 UI.updateDevicesAvailability = function (id, devices) {
1202
 UI.updateDevicesAvailability = function (id, devices) {
1110
     VideoLayout.setDeviceAvailabilityIcons(id, devices);
1203
     VideoLayout.setDeviceAvailabilityIcons(id, devices);
1111
 };
1204
 };

+ 22
- 0
modules/UI/side_pannels/settings/SettingsMenu.js View File

203
         $('#avatar').attr('src', avatarUrl);
203
         $('#avatar').attr('src', avatarUrl);
204
     },
204
     },
205
 
205
 
206
+    /**
207
+     * Sets microphone's <select> element to select microphone ID from settings.
208
+     */
209
+    setSelectedMicFromSettings () {
210
+        $('#selectMic').val(Settings.getMicDeviceId());
211
+    },
212
+
213
+    /**
214
+     * Sets camera's <select> element to select camera ID from settings.
215
+     */
216
+    setSelectedCameraFromSettings () {
217
+        $('#selectCamera').val(Settings.getCameraDeviceId());
218
+    },
219
+
220
+    /**
221
+     * Sets audio outputs's <select> element to select audio output ID from
222
+     * settings.
223
+     */
224
+    setSelectedAudioOutputFromSettings () {
225
+        $('#selectAudioOutput').val(Settings.getAudioOutputDeviceId());
226
+    },
227
+
206
     /**
228
     /**
207
      * Change available cameras/microphones or hide selects completely if
229
      * Change available cameras/microphones or hide selects completely if
208
      * no devices available.
230
      * no devices available.

Loading…
Cancel
Save