-
Notifications
You must be signed in to change notification settings - Fork 1.1k
/
JitsiTrackError.js
162 lines (150 loc) · 6.13 KB
/
JitsiTrackError.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
import * as JitsiTrackErrors from './JitsiTrackErrors';
const TRACK_ERROR_TO_MESSAGE_MAP = {};
TRACK_ERROR_TO_MESSAGE_MAP[JitsiTrackErrors.UNSUPPORTED_RESOLUTION]
= 'Video resolution is not supported: ';
TRACK_ERROR_TO_MESSAGE_MAP[JitsiTrackErrors.SCREENSHARING_USER_CANCELED]
= 'User canceled screen sharing prompt';
TRACK_ERROR_TO_MESSAGE_MAP[JitsiTrackErrors.SCREENSHARING_GENERIC_ERROR]
= 'Unknown error from screensharing';
TRACK_ERROR_TO_MESSAGE_MAP[JitsiTrackErrors.ELECTRON_DESKTOP_PICKER_ERROR]
= 'Unkown error from desktop picker';
TRACK_ERROR_TO_MESSAGE_MAP[JitsiTrackErrors.ELECTRON_DESKTOP_PICKER_NOT_FOUND]
= 'Failed to detect desktop picker';
TRACK_ERROR_TO_MESSAGE_MAP[JitsiTrackErrors.GENERAL]
= 'Generic getUserMedia error';
TRACK_ERROR_TO_MESSAGE_MAP[JitsiTrackErrors.PERMISSION_DENIED]
= 'User denied permission to use device(s): ';
TRACK_ERROR_TO_MESSAGE_MAP[JitsiTrackErrors.NOT_FOUND]
= 'Requested device(s) was/were not found: ';
TRACK_ERROR_TO_MESSAGE_MAP[JitsiTrackErrors.CONSTRAINT_FAILED]
= 'Constraint could not be satisfied: ';
TRACK_ERROR_TO_MESSAGE_MAP[JitsiTrackErrors.TIMEOUT]
= 'Could not start media source. Timeout occured!';
TRACK_ERROR_TO_MESSAGE_MAP[JitsiTrackErrors.TRACK_IS_DISPOSED]
= 'Track has been already disposed';
TRACK_ERROR_TO_MESSAGE_MAP[JitsiTrackErrors.TRACK_NO_STREAM_FOUND]
= 'Track does not have an associated Media Stream';
// FIXME: Using prototype inheritance because otherwise instanceof is not
// working properly (see https://github.com/babel/babel/issues/3083)
/**
*
* Represents an error that occurred to a JitsiTrack. Can represent various
* types of errors. For error descriptions (@see JitsiTrackErrors).
*
* @extends Error
*
*
* @constructor
* @param {Object|string} error - error object or error name
* @param {Object|string} (options) - getUserMedia constraints object or
* error message
* @param {('audio'|'video'|'desktop'|'screen'|'audiooutput')[]} (devices) -
* list of getUserMedia requested devices
*/
function JitsiTrackError(error, options, devices) {
if (typeof error === 'object' && typeof error.name !== 'undefined') {
/**
* Additional information about original getUserMedia error
* and constraints.
* @type {{
* error: Object,
* constraints: Object,
* devices: Array.<'audio'|'video'|'desktop'|'screen'>
* }}
*/
this.gum = {
error,
constraints: options,
devices: devices && Array.isArray(devices)
? devices.slice(0)
: undefined
};
switch (error.name) {
case 'NotAllowedError':
case 'PermissionDeniedError':
case 'SecurityError':
this.name = JitsiTrackErrors.PERMISSION_DENIED;
this.message
= TRACK_ERROR_TO_MESSAGE_MAP[this.name]
+ (this.gum.devices || []).join(', ');
break;
case 'DevicesNotFoundError':
case 'NotFoundError':
this.name = JitsiTrackErrors.NOT_FOUND;
this.message
= TRACK_ERROR_TO_MESSAGE_MAP[this.name]
+ (this.gum.devices || []).join(', ');
break;
case 'ConstraintNotSatisfiedError':
case 'OverconstrainedError': {
const constraintName = error.constraintName || error.constraint;
// we treat deviceId as unsupported resolution, as we want to
// retry and finally if everything fails to remove deviceId from
// mandatory constraints
if (options
&& options.video
&& (!devices || devices.indexOf('video') > -1)
&& (constraintName === 'minWidth'
|| constraintName === 'maxWidth'
|| constraintName === 'minHeight'
|| constraintName === 'maxHeight'
|| constraintName === 'width'
|| constraintName === 'height'
|| constraintName === 'deviceId')) {
this.name = JitsiTrackErrors.UNSUPPORTED_RESOLUTION;
this.message
= TRACK_ERROR_TO_MESSAGE_MAP[this.name]
+ getResolutionFromFailedConstraint(
constraintName,
options);
} else {
this.name = JitsiTrackErrors.CONSTRAINT_FAILED;
this.message
= TRACK_ERROR_TO_MESSAGE_MAP[this.name]
+ error.constraintName;
}
break;
}
default:
this.name = JitsiTrackErrors.GENERAL;
this.message
= error.message || TRACK_ERROR_TO_MESSAGE_MAP[this.name];
break;
}
} else if (typeof error === 'string') {
if (TRACK_ERROR_TO_MESSAGE_MAP[error]) {
this.name = error;
this.message = options || TRACK_ERROR_TO_MESSAGE_MAP[error];
} else {
// this is some generic error that do not fit any of our
// pre-defined errors, so don't give it any specific name, just
// store message
this.message = error;
}
} else {
throw new Error('Invalid arguments');
}
this.stack = error.stack || new Error().stack;
}
JitsiTrackError.prototype = Object.create(Error.prototype);
JitsiTrackError.prototype.constructor = JitsiTrackError;
/**
* Gets failed resolution constraint from corresponding object.
* @param {string} failedConstraintName
* @param {Object} constraints
* @returns {string|number}
*/
function getResolutionFromFailedConstraint(failedConstraintName, constraints) {
if (constraints && constraints.video && constraints.video.mandatory) {
switch (failedConstraintName) {
case 'width':
return constraints.video.mandatory.minWidth;
case 'height':
return constraints.video.mandatory.minHeight;
default:
return constraints.video.mandatory[failedConstraintName] || '';
}
}
return '';
}
export default JitsiTrackError;