|
|
@@ -37,7 +37,7 @@ export function createDesiredLocalTracks(...desiredTypes) {
|
|
37
|
37
|
const { audio, video } = state['features/base/media'];
|
|
38
|
38
|
|
|
39
|
39
|
audio.muted || desiredTypes.push(MEDIA_TYPE.AUDIO);
|
|
40
|
|
- Boolean(video.muted) || desiredTypes.push(MEDIA_TYPE.VIDEO);
|
|
|
40
|
+ video.muted || desiredTypes.push(MEDIA_TYPE.VIDEO);
|
|
41
|
41
|
}
|
|
42
|
42
|
|
|
43
|
43
|
const availableTypes
|
|
|
@@ -85,44 +85,52 @@ export function createLocalTracksA(options = {}) {
|
|
85
|
85
|
.find(t => t.local && t.mediaType === device)) {
|
|
86
|
86
|
throw new Error(`Local track for ${device} already exists`);
|
|
87
|
87
|
}
|
|
88
|
|
- const gumProcess = createLocalTracksF(
|
|
89
|
|
- {
|
|
90
|
|
- cameraDeviceId: options.cameraDeviceId,
|
|
91
|
|
- devices: [ device ],
|
|
92
|
|
- facingMode: options.facingMode || CAMERA_FACING_MODE.USER,
|
|
93
|
|
- micDeviceId: options.micDeviceId
|
|
94
|
|
- },
|
|
95
|
|
- /* firePermissionPromptIsShownEvent */ false,
|
|
96
|
|
- store)
|
|
97
|
|
- .then(
|
|
98
|
|
- localTracks => {
|
|
99
|
|
- // Because GUM is called for 1 device (which is actually
|
|
100
|
|
- // a media type 'audio','video', 'screen' etc.) we should
|
|
101
|
|
- // not get more than one JitsiTrack.
|
|
102
|
|
- if (localTracks.length !== 1) {
|
|
103
|
|
- throw new Error(
|
|
104
|
|
- 'Expected exactly 1 track, but was '
|
|
105
|
|
- + `given ${localTracks.length} tracks`
|
|
106
|
|
- + `for device: ${device}.`);
|
|
107
|
|
- }
|
|
108
|
88
|
|
|
109
|
|
- if (gumProcess.canceled) {
|
|
110
|
|
- return _disposeTracks(localTracks)
|
|
111
|
|
- .then(
|
|
112
|
|
- () =>
|
|
113
|
|
- dispatch(
|
|
114
|
|
- _trackCreateCanceled(device)));
|
|
115
|
|
- }
|
|
|
89
|
+ const gumProcess
|
|
|
90
|
+ = createLocalTracksF(
|
|
|
91
|
+ {
|
|
|
92
|
+ cameraDeviceId: options.cameraDeviceId,
|
|
|
93
|
+ devices: [ device ],
|
|
|
94
|
+ facingMode:
|
|
|
95
|
+ options.facingMode || CAMERA_FACING_MODE.USER,
|
|
|
96
|
+ micDeviceId: options.micDeviceId
|
|
|
97
|
+ },
|
|
|
98
|
+ /* firePermissionPromptIsShownEvent */ false,
|
|
|
99
|
+ store)
|
|
|
100
|
+ .then(
|
|
|
101
|
+ localTracks => {
|
|
|
102
|
+ // Because GUM is called for 1 device (which is actually
|
|
|
103
|
+ // a media type 'audio', 'video', 'screen', etc.) we
|
|
|
104
|
+ // should not get more than one JitsiTrack.
|
|
|
105
|
+ if (localTracks.length !== 1) {
|
|
|
106
|
+ throw new Error(
|
|
|
107
|
+ `Expected exactly 1 track, but was given ${
|
|
|
108
|
+ localTracks.length} tracks for device: ${
|
|
|
109
|
+ device}.`);
|
|
|
110
|
+ }
|
|
116
|
111
|
|
|
117
|
|
- return dispatch(trackAdded(localTracks[0]));
|
|
118
|
|
- },
|
|
119
|
|
- // eslint-disable-next-line no-confusing-arrow
|
|
120
|
|
- reason =>
|
|
121
|
|
- dispatch(
|
|
122
|
|
- gumProcess.canceled
|
|
123
|
|
- ? _trackCreateCanceled(device)
|
|
124
|
|
- : _onCreateLocalTracksRejected(reason, device)));
|
|
|
112
|
+ if (gumProcess.canceled) {
|
|
|
113
|
+ return _disposeTracks(localTracks)
|
|
|
114
|
+ .then(() =>
|
|
|
115
|
+ dispatch(_trackCreateCanceled(device)));
|
|
|
116
|
+ }
|
|
125
|
117
|
|
|
|
118
|
+ return dispatch(trackAdded(localTracks[0]));
|
|
|
119
|
+ },
|
|
|
120
|
+ reason =>
|
|
|
121
|
+ dispatch(
|
|
|
122
|
+ gumProcess.canceled
|
|
|
123
|
+ ? _trackCreateCanceled(device)
|
|
|
124
|
+ : _onCreateLocalTracksRejected(
|
|
|
125
|
+ reason,
|
|
|
126
|
+ device)));
|
|
|
127
|
+
|
|
|
128
|
+ /**
|
|
|
129
|
+ * Cancels the {@code getUserMedia} process represented by this
|
|
|
130
|
+ * {@code Promise}.
|
|
|
131
|
+ *
|
|
|
132
|
+ * @returns {Promise} This {@code Promise} i.e. {@code gumProcess}.
|
|
|
133
|
+ */
|
|
126
|
134
|
gumProcess.cancel = () => {
|
|
127
|
135
|
gumProcess.canceled = true;
|
|
128
|
136
|
|
|
|
@@ -132,8 +140,8 @@ export function createLocalTracksA(options = {}) {
|
|
132
|
140
|
dispatch({
|
|
133
|
141
|
type: TRACK_BEING_CREATED,
|
|
134
|
142
|
track: {
|
|
135
|
|
- local: true,
|
|
136
|
143
|
gumProcess,
|
|
|
144
|
+ local: true,
|
|
137
|
145
|
mediaType: device
|
|
138
|
146
|
}
|
|
139
|
147
|
});
|
|
|
@@ -151,9 +159,9 @@ export function destroyLocalTracks() {
|
|
151
|
159
|
return (dispatch, getState) => {
|
|
152
|
160
|
// First wait until any getUserMedia in progress is settled and then get
|
|
153
|
161
|
// rid of all local tracks.
|
|
154
|
|
- _cancelAllGumInProgress(getState)
|
|
155
|
|
- .then(
|
|
156
|
|
- () => dispatch(
|
|
|
162
|
+ _cancelGUMProcesses(getState)
|
|
|
163
|
+ .then(() =>
|
|
|
164
|
+ dispatch(
|
|
157
|
165
|
_disposeAndRemoveTracks(
|
|
158
|
166
|
getState()['features/base/tracks']
|
|
159
|
167
|
.filter(t => t.local)
|
|
|
@@ -366,49 +374,27 @@ function _addTracks(tracks) {
|
|
366
|
374
|
}
|
|
367
|
375
|
|
|
368
|
376
|
/**
|
|
369
|
|
- * Signals that track create operation for given media track has been canceled.
|
|
370
|
|
- * Will clean up local track stub from the Redux state which holds the
|
|
371
|
|
- * 'gumProcess' reference.
|
|
372
|
|
- *
|
|
373
|
|
- * @param {MEDIA_TYPE} mediaType - The type of the media for which the track was
|
|
374
|
|
- * being created.
|
|
375
|
|
- * @returns {{
|
|
376
|
|
- * type,
|
|
377
|
|
- * trackType: MEDIA_TYPE
|
|
378
|
|
- * }}
|
|
379
|
|
- * @private
|
|
380
|
|
- */
|
|
381
|
|
-function _trackCreateCanceled(mediaType) {
|
|
382
|
|
- return {
|
|
383
|
|
- type: TRACK_CREATE_CANCELED,
|
|
384
|
|
- trackType: mediaType
|
|
385
|
|
- };
|
|
386
|
|
-}
|
|
387
|
|
-
|
|
388
|
|
-/**
|
|
389
|
|
- * Cancels and waits for any get user media operations currently in progress to
|
|
390
|
|
- * complete.
|
|
|
377
|
+ * Cancels and waits for any {@code getUserMedia} process/currently in progress
|
|
|
378
|
+ * to complete/settle.
|
|
391
|
379
|
*
|
|
392
|
|
- * @param {Function} getState - The Redux store {@code getState} method used to
|
|
393
|
|
- * obtain the state.
|
|
394
|
|
- * @returns {Promise} - A Promise resolved once all {@code gumProcess.cancel}
|
|
395
|
|
- * Promises are settled. That is when they are either resolved or rejected,
|
|
396
|
|
- * because all we care about here is to be sure that get user media callbacks
|
|
397
|
|
- * have completed (returned from the native side).
|
|
|
380
|
+ * @param {Function} getState - The redux store {@code getState} function used
|
|
|
381
|
+ * to obtain the state.
|
|
398
|
382
|
* @private
|
|
|
383
|
+ * @returns {Promise} - A {@code Promise} resolved once all
|
|
|
384
|
+ * {@code gumProcess.cancel()} {@code Promise}s are settled because all we care
|
|
|
385
|
+ * about here is to be sure that the {@code getUserMedia} callbacks have
|
|
|
386
|
+ * completed (i.e. returned from the native side).
|
|
399
|
387
|
*/
|
|
400
|
|
-function _cancelAllGumInProgress(getState) {
|
|
401
|
|
- // FIXME use logger
|
|
|
388
|
+function _cancelGUMProcesses(getState) {
|
|
402
|
389
|
const logError
|
|
403
|
390
|
= error =>
|
|
404
|
|
- console.error('gumProcess.cancel failed', JSON.stringify(error));
|
|
|
391
|
+ logger.error('gumProcess.cancel failed', JSON.stringify(error));
|
|
405
|
392
|
|
|
406
|
393
|
return Promise.all(
|
|
407
|
394
|
getState()['features/base/tracks']
|
|
408
|
395
|
.filter(t => t.local)
|
|
409
|
|
- .map(
|
|
410
|
|
- t => t.gumProcess
|
|
411
|
|
- && t.gumProcess.cancel().catch(logError)));
|
|
|
396
|
+ .map(({ gumProcess }) =>
|
|
|
397
|
+ gumProcess && gumProcess.cancel().catch(logError)));
|
|
412
|
398
|
}
|
|
413
|
399
|
|
|
414
|
400
|
/**
|
|
|
@@ -421,15 +407,15 @@ function _cancelAllGumInProgress(getState) {
|
|
421
|
407
|
export function _disposeAndRemoveTracks(tracks) {
|
|
422
|
408
|
return dispatch =>
|
|
423
|
409
|
_disposeTracks(tracks)
|
|
424
|
|
- .then(
|
|
425
|
|
- () => Promise.all(tracks.map(t => dispatch(trackRemoved(t)))));
|
|
|
410
|
+ .then(() =>
|
|
|
411
|
+ Promise.all(tracks.map(t => dispatch(trackRemoved(t)))));
|
|
426
|
412
|
}
|
|
427
|
413
|
|
|
428
|
414
|
/**
|
|
429
|
415
|
* Disposes passed tracks.
|
|
430
|
416
|
*
|
|
431
|
417
|
* @param {(JitsiLocalTrack|JitsiRemoteTrack)[]} tracks - List of tracks.
|
|
432
|
|
- * @protected
|
|
|
418
|
+ * @private
|
|
433
|
419
|
* @returns {Promise} - A Promise resolved once {@link JitsiTrack.dispose()} is
|
|
434
|
420
|
* done for every track from the list.
|
|
435
|
421
|
*/
|
|
|
@@ -438,13 +424,12 @@ function _disposeTracks(tracks) {
|
|
438
|
424
|
tracks.map(t =>
|
|
439
|
425
|
t.dispose()
|
|
440
|
426
|
.catch(err => {
|
|
441
|
|
- // Track might be already disposed so ignore such an
|
|
442
|
|
- // error. Of course, re-throw any other error(s).
|
|
|
427
|
+ // Track might be already disposed so ignore such an error.
|
|
|
428
|
+ // Of course, re-throw any other error(s).
|
|
443
|
429
|
if (err.name !== JitsiTrackErrors.TRACK_IS_DISPOSED) {
|
|
444
|
430
|
throw err;
|
|
445
|
431
|
}
|
|
446
|
|
- })
|
|
447
|
|
- ));
|
|
|
432
|
+ })));
|
|
448
|
433
|
}
|
|
449
|
434
|
|
|
450
|
435
|
/**
|
|
|
@@ -496,7 +481,8 @@ function _onCreateLocalTracksRejected({ gum }, device) {
|
|
496
|
481
|
}
|
|
497
|
482
|
|
|
498
|
483
|
/**
|
|
499
|
|
- * Returns true if the provided JitsiTrack should be rendered as a mirror.
|
|
|
484
|
+ * Returns true if the provided {@code JitsiTrack} should be rendered as a
|
|
|
485
|
+ * mirror.
|
|
500
|
486
|
*
|
|
501
|
487
|
* We only want to show a video in mirrored mode when:
|
|
502
|
488
|
* 1) The video source is local, and not remote.
|
|
|
@@ -524,3 +510,23 @@ function _shouldMirror(track) {
|
|
524
|
510
|
// but that may not be the case tomorrow.
|
|
525
|
511
|
&& track.getCameraFacingMode() === CAMERA_FACING_MODE.USER);
|
|
526
|
512
|
}
|
|
|
513
|
+
|
|
|
514
|
+/**
|
|
|
515
|
+ * Signals that track create operation for given media track has been canceled.
|
|
|
516
|
+ * Will clean up local track stub from the redux state which holds the
|
|
|
517
|
+ * {@code gumProcess} reference.
|
|
|
518
|
+ *
|
|
|
519
|
+ * @param {MEDIA_TYPE} mediaType - The type of the media for which the track was
|
|
|
520
|
+ * being created.
|
|
|
521
|
+ * @private
|
|
|
522
|
+ * @returns {{
|
|
|
523
|
+ * type,
|
|
|
524
|
+ * trackType: MEDIA_TYPE
|
|
|
525
|
+ * }}
|
|
|
526
|
+ */
|
|
|
527
|
+function _trackCreateCanceled(mediaType) {
|
|
|
528
|
+ return {
|
|
|
529
|
+ type: TRACK_CREATE_CANCELED,
|
|
|
530
|
+ trackType: mediaType
|
|
|
531
|
+ };
|
|
|
532
|
+}
|