ソースを参照

feat(GUM): timeout.

dev1
Hristo Terezov 4年前
コミット
054fbdf45f
3個のファイルの変更55行の追加29行の削除
  1. 2
    0
      JitsiTrackError.js
  2. 6
    0
      JitsiTrackErrors.js
  3. 47
    29
      modules/RTC/RTCUtils.js

+ 2
- 0
JitsiTrackError.js ファイルの表示

20
     = 'Requested device(s) was/were not found: ';
20
     = 'Requested device(s) was/were not found: ';
21
 TRACK_ERROR_TO_MESSAGE_MAP[JitsiTrackErrors.CONSTRAINT_FAILED]
21
 TRACK_ERROR_TO_MESSAGE_MAP[JitsiTrackErrors.CONSTRAINT_FAILED]
22
     = 'Constraint could not be satisfied: ';
22
     = 'Constraint could not be satisfied: ';
23
+TRACK_ERROR_TO_MESSAGE_MAP[JitsiTrackErrors.TIMEOUT]
24
+    = 'Could not start media source. Timeout occured!';
23
 TRACK_ERROR_TO_MESSAGE_MAP[JitsiTrackErrors.TRACK_IS_DISPOSED]
25
 TRACK_ERROR_TO_MESSAGE_MAP[JitsiTrackErrors.TRACK_IS_DISPOSED]
24
     = 'Track has been already disposed';
26
     = 'Track has been already disposed';
25
 TRACK_ERROR_TO_MESSAGE_MAP[JitsiTrackErrors.TRACK_NO_STREAM_FOUND]
27
 TRACK_ERROR_TO_MESSAGE_MAP[JitsiTrackErrors.TRACK_NO_STREAM_FOUND]

+ 6
- 0
JitsiTrackErrors.js ファイルの表示

51
 export const SCREENSHARING_USER_CANCELED
51
 export const SCREENSHARING_USER_CANCELED
52
     = 'gum.screensharing_user_canceled';
52
     = 'gum.screensharing_user_canceled';
53
 
53
 
54
+
55
+/**
56
+ * Indicates that the timeout passed to the obtainAudioAndVideoPermissions has expired without GUM resolving.
57
+ */
58
+export const TIMEOUT = 'gum.timeout';
59
+
54
 /**
60
 /**
55
  * An error which indicates that track has been already disposed and cannot
61
  * An error which indicates that track has been already disposed and cannot
56
  * be longer used.
62
  * be longer used.

+ 47
- 29
modules/RTC/RTCUtils.js ファイルの表示

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

読み込み中…
キャンセル
保存