Kaynağa Gözat

Merge pull request #124 from jitsi/tsareg-handle_create_local_tracks_errors_better

Tsareg handle create local tracks errors better
dev1
lyubomir 9 yıl önce
ebeveyn
işleme
f1dbc9f4e0

+ 8
- 9
JitsiConference.js Dosyayı Görüntüle

@@ -13,6 +13,7 @@ var Statistics = require("./modules/statistics/statistics");
13 13
 var JitsiDTMFManager = require('./modules/DTMF/JitsiDTMFManager');
14 14
 var JitsiTrackEvents = require("./JitsiTrackEvents");
15 15
 var JitsiTrackErrors = require("./JitsiTrackErrors");
16
+var JitsiTrackError = require("./JitsiTrackError");
16 17
 var Settings = require("./modules/settings/Settings");
17 18
 var ComponentsVersions = require("./modules/version/ComponentsVersions");
18 19
 var GlobalOnErrorHandler = require("./modules/util/GlobalOnErrorHandler");
@@ -320,7 +321,7 @@ JitsiConference.prototype.setSubject = function (subject) {
320 321
 JitsiConference.prototype.addTrack = function (track) {
321 322
     if(track.disposed)
322 323
     {
323
-        throw new Error(JitsiTrackErrors.TRACK_IS_DISPOSED);
324
+        throw new JitsiTrackError(JitsiTrackErrors.TRACK_IS_DISPOSED);
324 325
     }
325 326
 
326 327
     if (track.isVideoTrack() && this.rtc.getLocalVideoTrack()) {
@@ -943,8 +944,12 @@ function setupListeners(conference) {
943 944
                         "Failed to accept incoming Jingle session", error);
944 945
                 }
945 946
             );
946
-            conference.statistics.startRemoteStats(
947
-                    jingleSession.peerconnection);
947
+            // Start callstats as soon as peerconnection is initialized,
948
+            // do not wait for XMPPEvents.PEERCONNECTION_READY, as it may never
949
+            // happen in case if user doesn't have or denied permission to
950
+            // both camera and microphone.
951
+            conference.statistics.startCallStats(jingleSession, conference.settings);
952
+            conference.statistics.startRemoteStats(jingleSession.peerconnection);
948 953
         } else {
949 954
             // Error cause this should never happen unless something is wrong!
950 955
             var errmsg
@@ -1295,12 +1300,6 @@ function setupListeners(conference) {
1295 1300
                 conference.statistics.dispose();
1296 1301
             });
1297 1302
 
1298
-        conference.room.addListener(XMPPEvents.PEERCONNECTION_READY,
1299
-            function (session) {
1300
-                conference.statistics.startCallStats(
1301
-                    session, conference.settings);
1302
-            });
1303
-
1304 1303
         conference.room.addListener(XMPPEvents.CONNECTION_ICE_FAILED,
1305 1304
             function (pc) {
1306 1305
                 conference.statistics.sendIceConnectionFailedEvent(pc);

+ 19
- 5
JitsiMeetJS.js Dosyayı Görüntüle

@@ -8,6 +8,7 @@ var JitsiConnectionErrors = require("./JitsiConnectionErrors");
8 8
 var JitsiConferenceErrors = require("./JitsiConferenceErrors");
9 9
 var JitsiTrackEvents = require("./JitsiTrackEvents");
10 10
 var JitsiTrackErrors = require("./JitsiTrackErrors");
11
+var JitsiTrackError = require("./JitsiTrackError");
11 12
 var JitsiRecorderErrors = require("./JitsiRecorderErrors");
12 13
 var Logger = require("jitsi-meet-logger");
13 14
 var MediaType = require("./service/RTC/MediaType");
@@ -116,18 +117,27 @@ var LibJitsiMeet = {
116 117
                 this._gumFailedHandler.forEach(function (handler) {
117 118
                     handler(error);
118 119
                 });
119
-                if(!this._gumFailedHandler.length)
120
+
121
+                if(!this._gumFailedHandler.length) {
120 122
                     Statistics.sendGetUserMediaFailed(error);
121
-                if(error === JitsiTrackErrors.UNSUPPORTED_RESOLUTION) {
122
-                    var oldResolution = options.resolution || '360';
123
-                    var newResolution = getLowerResolution(oldResolution);
124
-                    if(newResolution === null)
123
+                }
124
+
125
+                if(error.name === JitsiTrackErrors.UNSUPPORTED_RESOLUTION) {
126
+                    var oldResolution = options.resolution || '360',
127
+                        newResolution = getLowerResolution(oldResolution);
128
+
129
+                    if (newResolution === null) {
125 130
                         return Promise.reject(error);
131
+                    }
132
+
126 133
                     options.resolution = newResolution;
134
+
127 135
                     logger.debug("Retry createLocalTracks with resolution",
128 136
                                 newResolution);
137
+
129 138
                     return LibJitsiMeet.createLocalTracks(options);
130 139
                 }
140
+
131 141
                 return Promise.reject(error);
132 142
             }.bind(this));
133 143
     },
@@ -210,6 +220,10 @@ var LibJitsiMeet = {
210 220
 // JitsiConnection.
211 221
 LibJitsiMeet.JitsiConnection = JitsiConnection.bind(null, LibJitsiMeet);
212 222
 
223
+// expose JitsiTrackError this way to give library consumers to do checks like
224
+// if (error instanceof JitsiMeetJS.JitsiTrackError) { }
225
+LibJitsiMeet.JitsiTrackError = JitsiTrackError;
226
+
213 227
 //Setups the promise object.
214 228
 window.Promise = window.Promise || require("es6-promise").Promise;
215 229
 

+ 142
- 0
JitsiTrackError.js Dosyayı Görüntüle

@@ -0,0 +1,142 @@
1
+var JitsiTrackErrors = require("./JitsiTrackErrors");
2
+
3
+var TRACK_ERROR_TO_MESSAGE_MAP = {};
4
+
5
+TRACK_ERROR_TO_MESSAGE_MAP[JitsiTrackErrors.UNSUPPORTED_RESOLUTION]
6
+    = "Video resolution is not supported: ";
7
+TRACK_ERROR_TO_MESSAGE_MAP[JitsiTrackErrors.FIREFOX_EXTENSION_NEEDED]
8
+    = "Firefox extension is not installed";
9
+TRACK_ERROR_TO_MESSAGE_MAP[JitsiTrackErrors.CHROME_EXTENSION_INSTALLATION_ERROR]
10
+    = "Failed to install Chrome extension";
11
+TRACK_ERROR_TO_MESSAGE_MAP[JitsiTrackErrors.CHROME_EXTENSION_USER_CANCELED]
12
+    = "User canceled Chrome's screen sharing prompt";
13
+TRACK_ERROR_TO_MESSAGE_MAP[JitsiTrackErrors.CHROME_EXTENSION_GENERIC_ERROR]
14
+    = "Unknown error from Chrome extension";
15
+TRACK_ERROR_TO_MESSAGE_MAP[JitsiTrackErrors.GENERAL]
16
+    = "Generic getUserMedia error";
17
+TRACK_ERROR_TO_MESSAGE_MAP[JitsiTrackErrors.PERMISSION_DENIED]
18
+    = "User denied permission to use device(s): ";
19
+TRACK_ERROR_TO_MESSAGE_MAP[JitsiTrackErrors.NOT_FOUND]
20
+    = "Requested device(s) was/were not found: ";
21
+TRACK_ERROR_TO_MESSAGE_MAP[JitsiTrackErrors.CONSTRAINT_FAILED]
22
+    = "Constraint could not be satisfied: ";
23
+TRACK_ERROR_TO_MESSAGE_MAP[JitsiTrackErrors.TRACK_IS_DISPOSED]
24
+    = "Track has been already disposed";
25
+TRACK_ERROR_TO_MESSAGE_MAP[JitsiTrackErrors.TRACK_MUTE_UNMUTE_IN_PROGRESS]
26
+    = "Track mute/unmute process is currently in progress";
27
+
28
+/**
29
+ * Object representing error that happened to a JitsiTrack. Can represent
30
+ * various types of errors. For error descriptions (@see JitsiTrackErrors).
31
+ * @constructor
32
+ * @extends Error
33
+ * @param {Object|string} error - error object or error name
34
+ * @param {Object|string} (options) - getUserMedia constraints object or error
35
+ *      message
36
+ * @param {('audio'|'video'|'desktop'|'screen')[]} (devices) - list of
37
+ *      getUserMedia requested devices
38
+ */
39
+function JitsiTrackError(error, options, devices) {
40
+    if (typeof error === "object" && typeof error.name !== "undefined") {
41
+        /**
42
+         * Additional information about original getUserMedia error
43
+         * and constraints.
44
+         * @type {{
45
+         *          error: Object,
46
+         *          constraints: Object,
47
+         *          devices: Array.<'audio'|'video'|'desktop'|'screen'>
48
+         *      }}
49
+         */
50
+        this.gum = {
51
+            error: error,
52
+            constraints: options,
53
+            devices: devices && Array.isArray(devices)
54
+                ? devices.slice(0)
55
+                : undefined
56
+        };
57
+
58
+        switch (error.name) {
59
+            case "PermissionDeniedError":
60
+            case "SecurityError":
61
+                this.name = JitsiTrackErrors.PERMISSION_DENIED;
62
+                this.message = TRACK_ERROR_TO_MESSAGE_MAP[
63
+                        JitsiTrackErrors.PERMISSION_DENIED]
64
+                        + (this.gum.devices || []).join(", ");
65
+                break;
66
+            case "NotFoundError":
67
+                this.name = JitsiTrackErrors.NOT_FOUND;
68
+                this.message = TRACK_ERROR_TO_MESSAGE_MAP[
69
+                        JitsiTrackErrors.NOT_FOUND]
70
+                        + (this.gum.devices || []).join(", ");
71
+                break;
72
+            case "ConstraintNotSatisfiedError":
73
+            case "OverconstrainedError":
74
+                var constraintName = error.constraintName;
75
+
76
+                if (options && options.video
77
+                    && (devices || []).indexOf('video') > -1
78
+                    &&
79
+                    (constraintName === "minWidth" ||
80
+                        constraintName === "maxWidth" ||
81
+                        constraintName === "minHeight" ||
82
+                        constraintName === "maxHeight" ||
83
+                        constraintName === "width" ||
84
+                        constraintName === "height")) {
85
+                    this.name = JitsiTrackErrors.UNSUPPORTED_RESOLUTION;
86
+                    this.message = TRACK_ERROR_TO_MESSAGE_MAP[
87
+                            JitsiTrackErrors.UNSUPPORTED_RESOLUTION] +
88
+                        getResolutionFromFailedConstraint(constraintName,
89
+                            options);
90
+                } else {
91
+                    this.name = JitsiTrackErrors.CONSTRAINT_FAILED;
92
+                    this.message = TRACK_ERROR_TO_MESSAGE_MAP[
93
+                            JitsiTrackErrors.CONSTRAINT_FAILED] +
94
+                        error.constraintName;
95
+                }
96
+                break;
97
+            default:
98
+                this.name = JitsiTrackErrors.GENERAL;
99
+                this.message = error.message ||
100
+                    TRACK_ERROR_TO_MESSAGE_MAP[JitsiTrackErrors.GENERAL];
101
+                break;
102
+        }
103
+    } else if (typeof error === "string") {
104
+        if (TRACK_ERROR_TO_MESSAGE_MAP[error]) {
105
+            this.name = error;
106
+            this.message = options || TRACK_ERROR_TO_MESSAGE_MAP[error];
107
+        } else {
108
+            // this is some generic error that do not fit any of our pre-defined
109
+            // errors, so don't give it any specific name, just store message
110
+            this.message = error;
111
+        }
112
+    } else {
113
+        throw new Error("Invalid arguments");
114
+    }
115
+
116
+    this.stack = error.stack || (new Error()).stack;
117
+}
118
+
119
+JitsiTrackError.prototype = Object.create(Error.prototype);
120
+JitsiTrackError.prototype.constructor = JitsiTrackError;
121
+
122
+/**
123
+ * Gets failed resolution constraint from corresponding object.
124
+ * @param {string} failedConstraintName
125
+ * @param {Object} constraints
126
+ * @returns {string|number}
127
+ */
128
+function getResolutionFromFailedConstraint(failedConstraintName, constraints) {
129
+    if (constraints && constraints.video && constraints.video.mandatory) {
130
+        if (failedConstraintName === "width") {
131
+            return constraints.video.mandatory.minWidth;
132
+        } else if (failedConstraintName === "height") {
133
+            return constraints.video.mandatory.minHeight;
134
+        } else {
135
+            return constraints.video.mandatory[failedConstraintName] || "";
136
+        }
137
+    }
138
+
139
+    return "";
140
+}
141
+
142
+module.exports = JitsiTrackError;

+ 46
- 34
JitsiTrackErrors.js Dosyayı Görüntüle

@@ -1,49 +1,61 @@
1
-var logger = require("jitsi-meet-logger").getLogger(__filename);
2
-
1
+/**
2
+ * Enumeration with the errors for the JitsiTrack objects.
3
+ * @type {{string: string}}
4
+ */
3 5
 module.exports = {
4 6
     /**
5
-     * Returns JitsiTrackErrors based on the error object passed by GUM
6
-     * @param error the error
7
-     * @param {Array} devices Array with the requested devices
8
-     */
9
-    parseError: function (error, devices) {
10
-        if (typeof error === "object") {
11
-          var constraintName = error.constraintName;
12
-          var name;
13
-          if (constraintName
14
-                  && (name = error.name)
15
-                  && (name == "ConstraintNotSatisfiedError"
16
-                      || name == "OverconstrainedError")
17
-                  && (constraintName == "minWidth"
18
-                      || constraintName == "maxWidth"
19
-                      || constraintName == "minHeight"
20
-                      || constraintName == "maxHeight"
21
-                      || constraintName == "width"
22
-                      || constraintName == "height")
23
-                  && (devices || []).indexOf("video") !== -1) {
24
-              return this.UNSUPPORTED_RESOLUTION;
25
-          }
26
-          if (error.type === "jitsiError") {
27
-              return error.errorObject;
28
-          }
29
-        }
30
-        // XXX We're about to lose the details represented by error and devices
31
-        // (because we're about to generalize them to GENERAL). At the very
32
-        // least log the details.
33
-        logger.error('Parsing error into ' + this.GENERAL + ': ' + error);
34
-        return this.GENERAL;
35
-    },
7
+     * An error which indicates that requested video resolution is not supported
8
+     * by a webcam.
9
+     */
36 10
     UNSUPPORTED_RESOLUTION: "gum.unsupported_resolution",
37 11
     /**
38
-     * An event which indicates that the jidesha extension for Firefox is
12
+     * An error which indicates that the jidesha extension for Firefox is
39 13
      * needed to proceed with screen sharing, and that it is not installed.
40 14
      */
41 15
     FIREFOX_EXTENSION_NEEDED: "gum.firefox_extension_needed",
16
+    /**
17
+     * An error which indicates that the jidesha extension for Chrome is
18
+     * failed to install.
19
+     */
42 20
     CHROME_EXTENSION_INSTALLATION_ERROR:
43 21
         "gum.chrome_extension_installation_error",
22
+    /**
23
+     * An error which indicates that user canceled screen sharing window
24
+     * selection dialog in jidesha extension for Chrome.
25
+     */
44 26
     CHROME_EXTENSION_USER_CANCELED:
45 27
         "gum.chrome_extension_user_canceled",
28
+    /**
29
+     * Generic error for jidesha extension for Chrome.
30
+     */
31
+    CHROME_EXTENSION_GENERIC_ERROR:
32
+        "gum.chrome_extension_generic_error",
33
+    /**
34
+     * Generic getUserMedia error.
35
+     */
46 36
     GENERAL: "gum.general",
37
+    /**
38
+     * An error which indicates that user denied permission to share requested
39
+     * device.
40
+     */
41
+    PERMISSION_DENIED: "gum.permission_denied",
42
+    /**
43
+     * An error which indicates that requested device was not found.
44
+     */
45
+    NOT_FOUND: "gum.not_found",
46
+    /**
47
+     * An error which indicates that some of requested constraints in
48
+     * getUserMedia call were not satisfied.
49
+     */
50
+    CONSTRAINT_FAILED: "gum.constraint_failed",
51
+    /**
52
+     * An error which indicates that track has been already disposed and cannot
53
+     * be longer used.
54
+     */
47 55
     TRACK_IS_DISPOSED: "track.track_is_disposed",
56
+    /**
57
+     * An error which indicates that track is currently in progress of muting or
58
+     * unmuting itself.
59
+     */
48 60
     TRACK_MUTE_UNMUTE_IN_PROGRESS: "track.mute_unmute_inprogress"
49 61
 };

+ 25
- 2
doc/API.md Dosyayı Görüntüle

@@ -27,6 +27,8 @@ Jitsi Meet API has the following components:
27 27
 
28 28
 * JitsiTrack
29 29
 
30
+* JitsiTrackError
31
+
30 32
 Usage
31 33
 ======
32 34
 JitsiMeetJS
@@ -56,7 +58,7 @@ The ```options``` parameter is JS object with the following properties:
56 58
 JitsiMeetJS.setLogLevel(JitsiMeetJS.logLevels.ERROR);
57 59
 ```
58 60
 
59
-* ```JitsiMeetJS.createLocalTracks(options)``` - Creates the media tracks and returns them trough ```Promise``` object.
61
+* ```JitsiMeetJS.createLocalTracks(options)``` - Creates the media tracks and returns them trough ```Promise``` object. If rejected, passes ```JitsiTrackError``` instance to catch block.
60 62
     - options - JS object with configuration options for the local media tracks. You can change the following properties there:
61 63
         1. devices - array with the devices - "desktop", "video" and "audio" that will be passed to GUM. If that property is not set GUM will try to get all available devices.
62 64
         2. resolution - the prefered resolution for the local video.
@@ -132,7 +134,7 @@ JitsiMeetJS.setLogLevel(JitsiMeetJS.logLevels.ERROR);
132 134
 
133 135
 
134 136
 * ```JitsiMeetJS.errors``` - JS object that contains all errors used by the API. You can use that object to check the reported errors from the API
135
-    We have two error types - connection and conference. You can access the events with the following code ```JitsiMeetJS.errors.<error_type>.<error_name>```.
137
+    We have three error types - connection, conference and track. You can access the events with the following code ```JitsiMeetJS.errors.<error_type>.<error_name>```.
136 138
     For example if you want to use the conference event that is fired when somebody leave conference you can use the following code - ```JitsiMeetJS.errors.conference.PASSWORD_REQUIRED```.
137 139
     We support the following errors:
138 140
     1. conference
@@ -154,6 +156,19 @@ JitsiMeetJS.setLogLevel(JitsiMeetJS.logLevels.ERROR);
154 156
         - PASSWORD_REQUIRED - passed when the connection to the server failed. You should try to authenticate with password.
155 157
         - CONNECTION_ERROR - indicates connection failures.
156 158
         - OTHER_ERROR - all other errors
159
+    3. track
160
+        - GENERAL - generic getUserMedia-related error.
161
+        - UNSUPPORTED_RESOLUTION - getUserMedia-related error, indicates that requested video resolution is not supported by camera.
162
+        - PERMISSION_DENIED - getUserMedia-related error, indicates that user denied permission to share requested device.
163
+        - NOT_FOUND - getUserMedia-related error, indicates that requested device was not found.
164
+        - CONSTRAINT_FAILED - getUserMedia-related error, indicates that some of requested constraints in getUserMedia call were not satisfied.
165
+        - TRACK_IS_DISPOSED - an error which indicates that track has been already disposed and cannot be longer used.
166
+        - TRACK_MUTE_UNMUTE_IN_PROGRESS - an error which indicates that track is currently in progress of muting or unmuting itself.
167
+        - CHROME_EXTENSION_GENERIC_ERROR - generic error for jidesha extension for Chrome.
168
+        - CHROME_EXTENSION_USER_CANCELED - an error which indicates that user canceled screen sharing window selection dialog in jidesha extension for Chrome.
169
+        - CHROME_EXTENSION_INSTALLATION_ERROR - an error which indicates that the jidesha extension for Chrome is failed to install.
170
+        - FIREFOX_EXTENSION_NEEDED - An error which indicates that the jidesha extension for Firefox is needed to proceed with screen sharing, and that it is not installed.
171
+        
157 172
 * ```JitsiMeetJS.logLevels``` - object with the log levels:
158 173
     1. TRACE
159 174
     2. DEBUG
@@ -359,6 +374,14 @@ We have the following methods for controling the tracks:
359 374
 
360 375
 12. isEnded() - returns true if track is ended
361 376
 
377
+JitsiTrackError
378
+======
379
+The object represents error that happened to a JitsiTrack. Is inherited from JavaScript base ```Error``` object, 
380
+so ```"name"```, ```"message"``` and ```"stack"``` properties are available. For GUM-related errors,
381
+exposes additional ```"gum"``` property, which is an object with following properties:
382
+ - error - original GUM error
383
+ - constraints - GUM constraints object used for the call
384
+ - devices - array of devices requested in GUM call (possible values - "audio", "video", "screen", "desktop")
362 385
 
363 386
 Getting Started
364 387
 ==============

+ 3
- 1
modules/RTC/JitsiLocalTrack.js Dosyayı Görüntüle

@@ -4,6 +4,7 @@ var JitsiTrack = require("./JitsiTrack");
4 4
 var RTCBrowserType = require("./RTCBrowserType");
5 5
 var JitsiTrackEvents = require('../../JitsiTrackEvents');
6 6
 var JitsiTrackErrors = require("../../JitsiTrackErrors");
7
+var JitsiTrackError = require("../../JitsiTrackError");
7 8
 var RTCEvents = require("../../service/RTC/RTCEvents");
8 9
 var RTCUtils = require("./RTCUtils");
9 10
 var VideoType = require('../../service/RTC/VideoType');
@@ -141,7 +142,8 @@ function createMuteUnmutePromise(track, mute)
141 142
     return new Promise(function (resolve, reject) {
142 143
 
143 144
         if(this.inMuteOrUnmuteProgress) {
144
-            reject(new Error(JitsiTrackErrors.TRACK_MUTE_UNMUTE_IN_PROGRESS));
145
+            reject(new JitsiTrackError(
146
+                JitsiTrackErrors.TRACK_MUTE_UNMUTE_IN_PROGRESS));
145 147
             return;
146 148
         }
147 149
         this.inMuteOrUnmuteProgress = true;

+ 40
- 19
modules/RTC/RTCUtils.js Dosyayı Görüntüle

@@ -14,6 +14,7 @@ var SDPUtil = require("../xmpp/SDPUtil");
14 14
 var EventEmitter = require("events");
15 15
 var screenObtainer = require("./ScreenObtainer");
16 16
 var JitsiTrackErrors = require("../../JitsiTrackErrors");
17
+var JitsiTrackError = require("../../JitsiTrackError");
17 18
 var MediaType = require("../../service/RTC/MediaType");
18 19
 var VideoType = require("../../service/RTC/VideoType");
19 20
 var GlobalOnErrorHandler = require("../util/GlobalOnErrorHandler");
@@ -473,7 +474,8 @@ function obtainDevices(options) {
473 474
             });
474 475
             logger.error(
475 476
                 "failed to obtain " + device + " stream - stop", error);
476
-            options.errorCallback(JitsiTrackErrors.parseError(error, devices));
477
+
478
+            options.errorCallback(error);
477 479
         });
478 480
 }
479 481
 
@@ -802,14 +804,17 @@ var RTCUtils = {
802 804
                     setAvailableDevices(um, false);
803 805
                     logger.warn('Failed to get access to local media. Error ',
804 806
                         error, constraints);
807
+
805 808
                     if (failure_callback) {
806
-                        failure_callback(error, resolution);
809
+                        failure_callback(
810
+                            new JitsiTrackError(error, constraints, um));
807 811
                     }
808 812
                 });
809 813
         } catch (e) {
810 814
             logger.error('GUM failed: ', e);
815
+
811 816
             if (failure_callback) {
812
-                failure_callback(e);
817
+                failure_callback(new JitsiTrackError(e, constraints, um));
813 818
             }
814 819
         }
815 820
     },
@@ -880,16 +885,36 @@ var RTCUtils = {
880 885
                     this.getUserMediaWithConstraints(
881 886
                         options.devices,
882 887
                         function (stream) {
883
-                            if((options.devices.indexOf("audio") !== -1 &&
884
-                                !stream.getAudioTracks().length) ||
885
-                                (options.devices.indexOf("video") !== -1 &&
886
-                                !stream.getVideoTracks().length))
888
+                            var audioDeviceRequested = options.devices.indexOf("audio") !== -1;
889
+                            var videoDeviceRequested = options.devices.indexOf("video") !== -1;
890
+                            var audioTracksReceived = !!stream.getAudioTracks().length;
891
+                            var videoTracksReceived = !!stream.getVideoTracks().length;
892
+
893
+                            if((audioDeviceRequested && !audioTracksReceived) ||
894
+                                (videoDeviceRequested && !videoTracksReceived))
887 895
                             {
888 896
                                 self.stopMediaStream(stream);
889
-                                reject(JitsiTrackErrors.parseError(
890
-                                    new Error("Unable to get the audio and " +
891
-                                        "video tracks."),
892
-                                    options.devices));
897
+
898
+                                // We are getting here in case if we requested
899
+                                // 'audio' or 'video' devices or both, but
900
+                                // didn't get corresponding MediaStreamTrack in
901
+                                // response stream. We don't know the reason why
902
+                                // this happened, so reject with general error.
903
+                                var devices = [];
904
+
905
+                                if (audioDeviceRequested && !audioTracksReceived) {
906
+                                    devices.push("audio");
907
+                                }
908
+
909
+                                if (videoDeviceRequested && !videoTracksReceived) {
910
+                                    devices.push("video");
911
+                                }
912
+
913
+                                reject(new JitsiTrackError(
914
+                                    { name: "UnknownError" },
915
+                                    getConstraints(options.devices, options),
916
+                                    devices)
917
+                                );
893 918
                                 return;
894 919
                             }
895 920
                             if(hasDesktop) {
@@ -899,17 +924,15 @@ var RTCUtils = {
899 924
                                             desktopStream: desktopStream});
900 925
                                     }, function (error) {
901 926
                                         self.stopMediaStream(stream);
902
-                                        reject(
903
-                                            JitsiTrackErrors.parseError(error,
904
-                                                options.devices));
927
+
928
+                                        reject(error);
905 929
                                     });
906 930
                             } else {
907 931
                                 successCallback({audioVideo: stream});
908 932
                             }
909 933
                         },
910 934
                         function (error) {
911
-                            reject(JitsiTrackErrors.parseError(error,
912
-                                options.devices));
935
+                            reject(error);
913 936
                         },
914 937
                         options);
915 938
                 } else if (hasDesktop) {
@@ -917,9 +940,7 @@ var RTCUtils = {
917 940
                         function (stream) {
918 941
                             successCallback({desktopStream: stream});
919 942
                         }, function (error) {
920
-                            reject(
921
-                                JitsiTrackErrors.parseError(error,
922
-                                    ["desktop"]));
943
+                            reject(error);
923 944
                         });
924 945
                 }
925 946
             }

+ 34
- 28
modules/RTC/ScreenObtainer.js Dosyayı Görüntüle

@@ -4,6 +4,7 @@ var logger = require("jitsi-meet-logger").getLogger(__filename);
4 4
 var RTCBrowserType = require("./RTCBrowserType");
5 5
 var AdapterJS = require("./adapter.screenshare");
6 6
 var JitsiTrackErrors = require("../../JitsiTrackErrors");
7
+var JitsiTrackError = require("../../JitsiTrackError");
7 8
 var GlobalOnErrorHandler = require("../util/GlobalOnErrorHandler");
8 9
 
9 10
 /**
@@ -66,7 +67,11 @@ var ScreenObtainer = {
66 67
 
67 68
         if (RTCBrowserType.isNWJS()) {
68 69
             obtainDesktopStream = function (onSuccess, onFailure) {
69
-                window.JitsiMeetNW.obtainDesktopStream (onSuccess, onFailure);
70
+                window.JitsiMeetNW.obtainDesktopStream (
71
+                    onSuccess, function (error, constraints) {
72
+                        onFailure && onFailure(new JitsiTrackError(
73
+                            error, constraints, ["desktop"]));
74
+                    });
70 75
             };
71 76
         } else if (RTCBrowserType.isTemasysPluginUsed()) {
72 77
             if (!AdapterJS.WebRTCPlugin.plugin.HasScreensharingFeature) {
@@ -174,10 +179,8 @@ var ScreenObtainer = {
174 179
 
175 180
         // Make sure desktopsharing knows that we failed, so that it doesn't get
176 181
         // stuck in 'switching' mode.
177
-        errorCallback({
178
-            type: "jitsiError",
179
-            errorObject: JitsiTrackErrors.FIREFOX_EXTENSION_NEEDED
180
-        });
182
+        errorCallback(
183
+            new JitsiTrackError(JitsiTrackErrors.FIREFOX_EXTENSION_NEEDED));
181 184
     },
182 185
     /**
183 186
      * Asks Chrome extension to call chooseDesktopMedia and gets chrome
@@ -208,26 +211,24 @@ var ScreenObtainer = {
208 211
                                 streamCallback, failCallback);
209 212
                         }, 500);
210 213
                     },
211
-                    function (arg) {
212
-                        logger.log("Failed to install the extension from:"
213
-                            + getWebStoreInstallUrl(self.options), arg);
214
-                        failCallback({
215
-                            type: "jitsiError",
216
-                            errorObject: JitsiTrackErrors
217
-                                .CHROME_EXTENSION_INSTALLATION_ERROR
218
-                        });
219
-                    }
214
+                    handleExtensionInstallationError
220 215
                 );
221 216
             } catch(e) {
222
-                logger.log("Failed to install the extension from:"
223
-                    + self.getWebStoreInstallUrl(this.options), e);
224
-                failCallback({
225
-                    type: "jitsiError",
226
-                    errorObject:
227
-                        JitsiTrackErrors.CHROME_EXTENSION_INSTALLATION_ERROR
228
-                });
217
+                handleExtensionInstallationError(e);
229 218
             }
230 219
         }
220
+
221
+        function handleExtensionInstallationError(e) {
222
+            var msg = "Failed to install the extension from "
223
+                + getWebStoreInstallUrl(self.options);
224
+
225
+            logger.log(msg, e);
226
+
227
+            failCallback(new JitsiTrackError(
228
+                JitsiTrackErrors.CHROME_EXTENSION_INSTALLATION_ERROR,
229
+                msg
230
+            ));
231
+        }
231 232
     }
232 233
 };
233 234
 
@@ -348,7 +349,13 @@ function doGetStreamFromExtension(options, streamCallback, failCallback) {
348 349
         },
349 350
         function (response) {
350 351
             if (!response) {
351
-                failCallback(chrome.runtime.lastError);
352
+                // possibly re-wraping error message to make code consistent
353
+                var lastError = chrome.runtime.lastError;
354
+                failCallback(lastError instanceof Error
355
+                    ? lastError
356
+                    : new JitsiTrackError(
357
+                        JitsiTrackErrors.CHROME_EXTENSION_GENERIC_ERROR,
358
+                        lastError));
352 359
                 return;
353 360
             }
354 361
             logger.log("Response from extension: ", response);
@@ -366,15 +373,14 @@ function doGetStreamFromExtension(options, streamCallback, failCallback) {
366 373
                 // then the callback is called with an empty streamId.
367 374
                 if(response.streamId === "")
368 375
                 {
369
-                    failCallback({
370
-                        type: "jitsiError",
371
-                        errorObject:
372
-                            JitsiTrackErrors.CHROME_EXTENSION_USER_CANCELED
373
-                    });
376
+                    failCallback(new JitsiTrackError(
377
+                        JitsiTrackErrors.CHROME_EXTENSION_USER_CANCELED));
374 378
                     return;
375 379
                 }
376 380
 
377
-                failCallback("Extension failed to get the stream");
381
+                failCallback(new JitsiTrackError(
382
+                    JitsiTrackErrors.CHROME_EXTENSION_GENERIC_ERROR,
383
+                    response.error));
378 384
             }
379 385
         }
380 386
     );

+ 42
- 3
modules/statistics/statistics.js Dosyayı Görüntüle

@@ -6,6 +6,7 @@ var EventEmitter = require("events");
6 6
 var StatisticsEvents = require("../../service/statistics/Events");
7 7
 var CallStats = require("./CallStats");
8 8
 var ScriptUtil = require('../util/ScriptUtil');
9
+var JitsiTrackError = require("../../JitsiTrackError");
9 10
 
10 11
 // Since callstats.io is a third party, we cannot guarantee the quality of their
11 12
 // service. More specifically, their server may take noticeably long time to
@@ -28,6 +29,35 @@ function loadCallStatsAPI() {
28 29
  */
29 30
 var LOG_INTERVAL = 60000;
30 31
 
32
+/**
33
+ * callstats strips any additional fields from Error except for "name", "stack",
34
+ * "message" and "constraintName". So we need to bundle additional information
35
+ * from JitsiTrackError into error passed to callstats to preserve valuable
36
+ * information about error.
37
+ * @param {JitsiTrackError} error
38
+ */
39
+function formatJitsiTrackErrorForCallStats(error) {
40
+    var err = new Error();
41
+
42
+    // Just copy original stack from error
43
+    err.stack = error.stack;
44
+
45
+    // Combine name from error's name plus (possibly) name of original GUM error
46
+    err.name = (error.name || "Unknown error") + (error.gum && error.gum.error
47
+        && error.gum.error.name ? " - " + error.gum.error.name : "");
48
+
49
+    // Put all constraints into this field. For constraint failed errors we will
50
+    // still know which exactly constraint failed as it will be a part of
51
+    // message.
52
+    err.constraintName = error.gum && error.gum.constraints
53
+        ? JSON.stringify(error.gum.constraints) : "";
54
+
55
+    // Just copy error's message.
56
+    err.message = error.message;
57
+
58
+    return err;
59
+}
60
+
31 61
 function Statistics(xmpp, options) {
32 62
     this.rtpStats = null;
33 63
     this.eventEmitter = new EventEmitter();
@@ -236,8 +266,13 @@ function (ssrc, isLocal, usageLabel, containerId) {
236 266
  * @param {Error} e error to send
237 267
  */
238 268
 Statistics.prototype.sendGetUserMediaFailed = function (e) {
239
-    if(this.callstats)
240
-        CallStats.sendGetUserMediaFailed(e, this.callstats);
269
+    if(this.callstats) {
270
+        CallStats.sendGetUserMediaFailed(
271
+            e instanceof JitsiTrackError
272
+                ? formatJitsiTrackErrorForCallStats(e)
273
+                : e,
274
+            this.callstats);
275
+    }
241 276
 };
242 277
 
243 278
 /**
@@ -246,7 +281,11 @@ Statistics.prototype.sendGetUserMediaFailed = function (e) {
246 281
  * @param {Error} e error to send
247 282
  */
248 283
 Statistics.sendGetUserMediaFailed = function (e) {
249
-    CallStats.sendGetUserMediaFailed(e, null);
284
+    CallStats.sendGetUserMediaFailed(
285
+        e instanceof JitsiTrackError
286
+            ? formatJitsiTrackErrorForCallStats(e)
287
+            : e,
288
+        null);
250 289
 };
251 290
 
252 291
 /**

Loading…
İptal
Kaydet