|
@@ -11,6 +11,7 @@ import { getLogger } from 'jitsi-meet-logger';
|
11
|
11
|
import clonedeep from 'lodash.clonedeep';
|
12
|
12
|
|
13
|
13
|
import JitsiTrackError from '../../JitsiTrackError';
|
|
14
|
+import * as JitsiTrackErrors from '../../JitsiTrackErrors';
|
14
|
15
|
import CameraFacingMode from '../../service/RTC/CameraFacingMode';
|
15
|
16
|
import * as MediaType from '../../service/RTC/MediaType';
|
16
|
17
|
import RTCEvents from '../../service/RTC/RTCEvents';
|
|
@@ -911,27 +912,20 @@ class RTCUtils extends Listenable {
|
911
|
912
|
* @param {Object} options.frameRate.max - Maximum fps
|
912
|
913
|
* @param {bool} options.screenShareAudio - Used by electron clients to
|
913
|
914
|
* enable system audio screen sharing.
|
|
915
|
+ * @param {number} options.timeout - The timeout in ms for GUM.
|
914
|
916
|
* @returns {Promise} Returns a media stream on success or a JitsiTrackError
|
915
|
917
|
* on failure.
|
916
|
918
|
**/
|
917
|
919
|
getUserMediaWithConstraints(um, options = {}) {
|
918
|
|
- const constraints = getConstraints(um, options);
|
|
920
|
+ const {
|
|
921
|
+ timeout,
|
|
922
|
+ ...otherOptions
|
|
923
|
+ } = options;
|
|
924
|
+ const constraints = getConstraints(um, otherOptions);
|
919
|
925
|
|
920
|
926
|
logger.info('Get media constraints', JSON.stringify(constraints));
|
921
|
927
|
|
922
|
|
- return new Promise((resolve, reject) => {
|
923
|
|
- navigator.mediaDevices.getUserMedia(constraints)
|
924
|
|
- .then(stream => {
|
925
|
|
- logger.log('onUserMediaSuccess');
|
926
|
|
- updateGrantedPermissions(um, stream);
|
927
|
|
- resolve(stream);
|
928
|
|
- })
|
929
|
|
- .catch(error => {
|
930
|
|
- logger.warn(`Failed to get access to local media. ${error} ${JSON.stringify(constraints)}`);
|
931
|
|
- updateGrantedPermissions(um, undefined);
|
932
|
|
- reject(new JitsiTrackError(error, constraints, um));
|
933
|
|
- });
|
934
|
|
- });
|
|
928
|
+ return this._getUserMedia(um, constraints, timeout);
|
935
|
929
|
}
|
936
|
930
|
|
937
|
931
|
/**
|
|
@@ -940,20 +934,41 @@ class RTCUtils extends Listenable {
|
940
|
934
|
*
|
941
|
935
|
* @param {array} umDevices which devices to acquire (e.g. audio, video)
|
942
|
936
|
* @param {Object} constraints - Stream specifications to use.
|
|
937
|
+ * @param {number} timeout - The timeout in ms for GUM.
|
943
|
938
|
* @returns {Promise}
|
944
|
939
|
*/
|
945
|
|
- _newGetUserMediaWithConstraints(umDevices, constraints = {}) {
|
|
940
|
+ _getUserMedia(umDevices, constraints = {}, timeout = 0) {
|
946
|
941
|
return new Promise((resolve, reject) => {
|
|
942
|
+ let gumTimeout, timeoutExpired = false;
|
|
943
|
+
|
|
944
|
+ if (typeof timeout === 'number' && !isNaN(timeout) && timeout > 0) {
|
|
945
|
+ gumTimeout = setTimeout(() => {
|
|
946
|
+ timeoutExpired = true;
|
|
947
|
+ gumTimeout = undefined;
|
|
948
|
+ reject(new JitsiTrackError(JitsiTrackErrors.TIMEOUT));
|
|
949
|
+ }, timeout);
|
|
950
|
+ }
|
|
951
|
+
|
947
|
952
|
navigator.mediaDevices.getUserMedia(constraints)
|
948
|
953
|
.then(stream => {
|
949
|
954
|
logger.log('onUserMediaSuccess');
|
950
|
955
|
updateGrantedPermissions(umDevices, stream);
|
951
|
|
- resolve(stream);
|
|
956
|
+ if (!timeoutExpired) {
|
|
957
|
+ if (typeof gumTimeout !== 'undefined') {
|
|
958
|
+ clearTimeout(gumTimeout);
|
|
959
|
+ }
|
|
960
|
+ resolve(stream);
|
|
961
|
+ }
|
952
|
962
|
})
|
953
|
963
|
.catch(error => {
|
954
|
964
|
logger.warn(`Failed to get access to local media. ${error} ${JSON.stringify(constraints)}`);
|
955
|
965
|
updateGrantedPermissions(umDevices, undefined);
|
956
|
|
- reject(new JitsiTrackError(error, constraints, umDevices));
|
|
966
|
+ if (!timeoutExpired) {
|
|
967
|
+ if (typeof gumTimeout !== 'undefined') {
|
|
968
|
+ clearTimeout(gumTimeout);
|
|
969
|
+ }
|
|
970
|
+ reject(new JitsiTrackError(error, constraints, umDevices));
|
|
971
|
+ }
|
957
|
972
|
});
|
958
|
973
|
});
|
959
|
974
|
}
|
|
@@ -961,7 +976,7 @@ class RTCUtils extends Listenable {
|
961
|
976
|
/**
|
962
|
977
|
* Acquire a display stream via the screenObtainer. This requires extra
|
963
|
978
|
* logic compared to use screenObtainer versus normal device capture logic
|
964
|
|
- * in RTCUtils#_newGetUserMediaWithConstraints.
|
|
979
|
+ * in RTCUtils#_getUserMedia.
|
965
|
980
|
*
|
966
|
981
|
* @param {Object} options
|
967
|
982
|
* @param {string[]} options.desktopSharingSources
|
|
@@ -1162,6 +1177,11 @@ class RTCUtils extends Listenable {
|
1162
|
1177
|
newObtainAudioAndVideoPermissions(options) {
|
1163
|
1178
|
logger.info('Using the new gUM flow');
|
1164
|
1179
|
|
|
1180
|
+ const {
|
|
1181
|
+ timeout,
|
|
1182
|
+ ...otherOptions
|
|
1183
|
+ } = options;
|
|
1184
|
+
|
1165
|
1185
|
const mediaStreamsMetaData = [];
|
1166
|
1186
|
|
1167
|
1187
|
// Declare private functions to be used in the promise chain below.
|
|
@@ -1175,7 +1195,7 @@ class RTCUtils extends Listenable {
|
1175
|
1195
|
* @returns {Promise}
|
1176
|
1196
|
*/
|
1177
|
1197
|
const maybeRequestDesktopDevice = function() {
|
1178
|
|
- const umDevices = options.devices || [];
|
|
1198
|
+ const umDevices = otherOptions.devices || [];
|
1179
|
1199
|
const isDesktopDeviceRequested
|
1180
|
1200
|
= umDevices.indexOf('desktop') !== -1;
|
1181
|
1201
|
|
|
@@ -1187,7 +1207,7 @@ class RTCUtils extends Listenable {
|
1187
|
1207
|
desktopSharingSourceDevice,
|
1188
|
1208
|
desktopSharingSources,
|
1189
|
1209
|
desktopSharingFrameRate
|
1190
|
|
- } = options;
|
|
1210
|
+ } = otherOptions;
|
1191
|
1211
|
|
1192
|
1212
|
// Attempt to use a video input device as a screenshare source if
|
1193
|
1213
|
// the option is defined.
|
|
@@ -1211,7 +1231,7 @@ class RTCUtils extends Listenable {
|
1211
|
1231
|
// Leverage the helper used by {@link _newGetDesktopMedia} to
|
1212
|
1232
|
// get constraints for the desktop stream.
|
1213
|
1233
|
const { gumOptions, trackOptions }
|
1214
|
|
- = this._parseDesktopSharingOptions(options);
|
|
1234
|
+ = this._parseDesktopSharingOptions(otherOptions);
|
1215
|
1235
|
|
1216
|
1236
|
const constraints = {
|
1217
|
1237
|
video: {
|
|
@@ -1220,8 +1240,7 @@ class RTCUtils extends Listenable {
|
1220
|
1240
|
}
|
1221
|
1241
|
};
|
1222
|
1242
|
|
1223
|
|
- return this._newGetUserMediaWithConstraints(
|
1224
|
|
- requestedDevices, constraints)
|
|
1243
|
+ return this._getUserMedia(requestedDevices, constraints, timeout)
|
1225
|
1244
|
.then(stream => {
|
1226
|
1245
|
const track = stream && stream.getTracks()[0];
|
1227
|
1246
|
const applyConstrainsPromise
|
|
@@ -1297,7 +1316,7 @@ class RTCUtils extends Listenable {
|
1297
|
1316
|
* @returns {Promise}
|
1298
|
1317
|
*/
|
1299
|
1318
|
const maybeRequestCaptureDevices = function() {
|
1300
|
|
- const umDevices = options.devices || [ 'audio', 'video' ];
|
|
1319
|
+ const umDevices = otherOptions.devices || [ 'audio', 'video' ];
|
1301
|
1320
|
const requestedCaptureDevices = umDevices.filter(device => device === 'audio' || device === 'video');
|
1302
|
1321
|
|
1303
|
1322
|
if (!requestedCaptureDevices.length) {
|
|
@@ -1305,12 +1324,11 @@ class RTCUtils extends Listenable {
|
1305
|
1324
|
}
|
1306
|
1325
|
|
1307
|
1326
|
const constraints = newGetConstraints(
|
1308
|
|
- requestedCaptureDevices, options);
|
|
1327
|
+ requestedCaptureDevices, otherOptions);
|
1309
|
1328
|
|
1310
|
1329
|
logger.info('Got media constraints: ', JSON.stringify(constraints));
|
1311
|
1330
|
|
1312
|
|
- return this._newGetUserMediaWithConstraints(
|
1313
|
|
- requestedCaptureDevices, constraints);
|
|
1331
|
+ return this._getUserMedia(requestedCaptureDevices, constraints, timeout);
|
1314
|
1332
|
}.bind(this);
|
1315
|
1333
|
|
1316
|
1334
|
/**
|
|
@@ -1335,7 +1353,7 @@ class RTCUtils extends Listenable {
|
1335
|
1353
|
mediaStreamsMetaData.push({
|
1336
|
1354
|
stream: audioStream,
|
1337
|
1355
|
track: audioStream.getAudioTracks()[0],
|
1338
|
|
- effects: options.effects
|
|
1356
|
+ effects: otherOptions.effects
|
1339
|
1357
|
});
|
1340
|
1358
|
}
|
1341
|
1359
|
|
|
@@ -1348,7 +1366,7 @@ class RTCUtils extends Listenable {
|
1348
|
1366
|
stream: videoStream,
|
1349
|
1367
|
track: videoStream.getVideoTracks()[0],
|
1350
|
1368
|
videoType: VideoType.CAMERA,
|
1351
|
|
- effects: options.effects
|
|
1369
|
+ effects: otherOptions.effects
|
1352
|
1370
|
});
|
1353
|
1371
|
}
|
1354
|
1372
|
};
|