|
@@ -81,8 +81,6 @@ export default class JitsiTrack extends EventEmitter {
|
81
|
81
|
this._setStream(stream);
|
82
|
82
|
}
|
83
|
83
|
|
84
|
|
- /* eslint-enable max-params */
|
85
|
|
-
|
86
|
84
|
/**
|
87
|
85
|
* Adds onended/oninactive handler to a MediaStream or a MediaStreamTrack.
|
88
|
86
|
* Firefox doesn't fire a inactive event on the MediaStream, instead it fires
|
|
@@ -97,6 +95,52 @@ export default class JitsiTrack extends EventEmitter {
|
97
|
95
|
}
|
98
|
96
|
}
|
99
|
97
|
|
|
98
|
+ /**
|
|
99
|
+ * Attach time to first media tracker only if there is conference and only
|
|
100
|
+ * for the first element.
|
|
101
|
+ *
|
|
102
|
+ * @param {HTMLElement} container the HTML container which can be 'video' or
|
|
103
|
+ * 'audio' element.
|
|
104
|
+ * @private
|
|
105
|
+ */
|
|
106
|
+ _attachTTFMTracker(container) { // eslint-disable-line no-unused-vars
|
|
107
|
+ // Should be defined by the classes that are extending JitsiTrack
|
|
108
|
+ }
|
|
109
|
+
|
|
110
|
+ /**
|
|
111
|
+ * Eventually will trigger RTCEvents.TRACK_ATTACHED event.
|
|
112
|
+ * @param container the video/audio container to which this stream is
|
|
113
|
+ * attached and for which event will be fired.
|
|
114
|
+ * @private
|
|
115
|
+ */
|
|
116
|
+ _maybeFireTrackAttached(container) {
|
|
117
|
+ if (this.conference && container) {
|
|
118
|
+ this.conference._onTrackAttach(this, container);
|
|
119
|
+ }
|
|
120
|
+ }
|
|
121
|
+
|
|
122
|
+ /**
|
|
123
|
+ * Called when the track has been attached to a new container.
|
|
124
|
+ *
|
|
125
|
+ * @param {HTMLElement} container the HTML container which can be 'video' or
|
|
126
|
+ * 'audio' element.
|
|
127
|
+ * @private
|
|
128
|
+ */
|
|
129
|
+ _onTrackAttach(container) { // eslint-disable-line no-unused-vars
|
|
130
|
+ // Should be defined by the classes that are extending JitsiTrack
|
|
131
|
+ }
|
|
132
|
+
|
|
133
|
+ /**
|
|
134
|
+ * Called when the track has been detached from a container.
|
|
135
|
+ *
|
|
136
|
+ * @param {HTMLElement} container the HTML container which can be 'video' or
|
|
137
|
+ * 'audio' element.
|
|
138
|
+ * @private
|
|
139
|
+ */
|
|
140
|
+ _onTrackDetach(container) { // eslint-disable-line no-unused-vars
|
|
141
|
+ // Should be defined by the classes that are extending JitsiTrack
|
|
142
|
+ }
|
|
143
|
+
|
100
|
144
|
/**
|
101
|
145
|
* Sets handler to the WebRTC MediaStream or MediaStreamTrack object
|
102
|
146
|
* depending on the passed type.
|
|
@@ -122,29 +166,6 @@ export default class JitsiTrack extends EventEmitter {
|
122
|
166
|
}
|
123
|
167
|
}
|
124
|
168
|
|
125
|
|
- /**
|
126
|
|
- * Unregisters all event handlers bound to the underlying media stream/track
|
127
|
|
- * @private
|
128
|
|
- */
|
129
|
|
- _unregisterHandlers() {
|
130
|
|
- if (!this.stream) {
|
131
|
|
- logger.warn(
|
132
|
|
- `${this}: unable to unregister handlers - no stream object`);
|
133
|
|
-
|
134
|
|
- return;
|
135
|
|
- }
|
136
|
|
-
|
137
|
|
- for (const type of this.handlers.keys()) {
|
138
|
|
- // FIXME Why only video tracks?
|
139
|
|
- for (const videoTrack of this.stream.getVideoTracks()) {
|
140
|
|
- videoTrack[trackHandler2Prop[type]] = undefined;
|
141
|
|
- }
|
142
|
|
- }
|
143
|
|
- if (this._streamInactiveHandler) {
|
144
|
|
- this._addMediaStreamInactiveHandler(undefined);
|
145
|
|
- }
|
146
|
|
- }
|
147
|
|
-
|
148
|
169
|
/**
|
149
|
170
|
* Sets the stream property of JitsiTrack object and sets all stored
|
150
|
171
|
* handlers to it.
|
|
@@ -174,59 +195,105 @@ export default class JitsiTrack extends EventEmitter {
|
174
|
195
|
}
|
175
|
196
|
|
176
|
197
|
/**
|
177
|
|
- * Returns the video type (camera or desktop) of this track.
|
|
198
|
+ * Unregisters all event handlers bound to the underlying media stream/track
|
|
199
|
+ * @private
|
178
|
200
|
*/
|
179
|
|
- getVideoType() {
|
180
|
|
- return this.videoType;
|
181
|
|
- }
|
|
201
|
+ _unregisterHandlers() {
|
|
202
|
+ if (!this.stream) {
|
|
203
|
+ logger.warn(
|
|
204
|
+ `${this}: unable to unregister handlers - no stream object`);
|
182
|
205
|
|
183
|
|
- /**
|
184
|
|
- * Returns the type (audio or video) of this track.
|
185
|
|
- */
|
186
|
|
- getType() {
|
187
|
|
- return this.type;
|
|
206
|
+ return;
|
|
207
|
+ }
|
|
208
|
+
|
|
209
|
+ for (const type of this.handlers.keys()) {
|
|
210
|
+ // FIXME Why only video tracks?
|
|
211
|
+ for (const videoTrack of this.stream.getVideoTracks()) {
|
|
212
|
+ videoTrack[trackHandler2Prop[type]] = undefined;
|
|
213
|
+ }
|
|
214
|
+ }
|
|
215
|
+ if (this._streamInactiveHandler) {
|
|
216
|
+ this._addMediaStreamInactiveHandler(undefined);
|
|
217
|
+ }
|
188
|
218
|
}
|
189
|
219
|
|
190
|
220
|
/**
|
191
|
|
- * Check if this is an audio track.
|
|
221
|
+ * Attaches the MediaStream of this track to an HTML container.
|
|
222
|
+ * Adds the container to the list of containers that are displaying the
|
|
223
|
+ * track.
|
|
224
|
+ *
|
|
225
|
+ * @param container the HTML container which can be 'video' or 'audio'
|
|
226
|
+ * element.
|
|
227
|
+ *
|
|
228
|
+ * @returns {void}
|
192
|
229
|
*/
|
193
|
|
- isAudioTrack() {
|
194
|
|
- return this.getType() === MediaType.AUDIO;
|
|
230
|
+ attach(container) {
|
|
231
|
+ if (this.stream) {
|
|
232
|
+ this._onTrackAttach(container);
|
|
233
|
+ RTCUtils.attachMediaStream(container, this.stream);
|
|
234
|
+ }
|
|
235
|
+ this.containers.push(container);
|
|
236
|
+ this._maybeFireTrackAttached(container);
|
|
237
|
+ this._attachTTFMTracker(container);
|
195
|
238
|
}
|
196
|
239
|
|
197
|
240
|
/**
|
198
|
|
- * Checks whether the underlying WebRTC <tt>MediaStreamTrack</tt> is muted
|
199
|
|
- * according to it's 'muted' field status.
|
200
|
|
- * @return {boolean} <tt>true</tt> if the underlying
|
201
|
|
- * <tt>MediaStreamTrack</tt> is muted or <tt>false</tt> otherwise.
|
|
241
|
+ * Removes this JitsiTrack from the passed HTML container.
|
|
242
|
+ *
|
|
243
|
+ * @param container the HTML container to detach from this JitsiTrack. If
|
|
244
|
+ * <tt>null</tt> or <tt>undefined</tt>, all containers are removed. A
|
|
245
|
+ * container can be a 'video', 'audio' or 'object' HTML element instance to
|
|
246
|
+ * which this JitsiTrack is currently attached.
|
202
|
247
|
*/
|
203
|
|
- isWebRTCTrackMuted() {
|
204
|
|
- return this.track && this.track.muted;
|
|
248
|
+ detach(container) {
|
|
249
|
+ for (let cs = this.containers, i = cs.length - 1; i >= 0; --i) {
|
|
250
|
+ const c = cs[i];
|
|
251
|
+
|
|
252
|
+ if (!container) {
|
|
253
|
+ this._onTrackDetach(c);
|
|
254
|
+ RTCUtils.attachMediaStream(c, null);
|
|
255
|
+ }
|
|
256
|
+ if (!container || c === container) {
|
|
257
|
+ cs.splice(i, 1);
|
|
258
|
+ }
|
|
259
|
+ }
|
|
260
|
+
|
|
261
|
+ if (container) {
|
|
262
|
+ this._onTrackDetach(container);
|
|
263
|
+ RTCUtils.attachMediaStream(container, null);
|
|
264
|
+ }
|
205
|
265
|
}
|
206
|
266
|
|
207
|
267
|
/**
|
208
|
|
- * Check if this is a video track.
|
|
268
|
+ * Removes attached event listeners.
|
|
269
|
+ *
|
|
270
|
+ * @returns {Promise}
|
209
|
271
|
*/
|
210
|
|
- isVideoTrack() {
|
211
|
|
- return this.getType() === MediaType.VIDEO;
|
|
272
|
+ dispose() {
|
|
273
|
+ this.removeAllListeners();
|
|
274
|
+
|
|
275
|
+ this.disposed = true;
|
|
276
|
+
|
|
277
|
+ return Promise.resolve();
|
212
|
278
|
}
|
213
|
279
|
|
214
|
280
|
/**
|
215
|
|
- * Checks whether this is a local track.
|
216
|
|
- * @abstract
|
217
|
|
- * @return {boolean} 'true' if it's a local track or 'false' otherwise.
|
|
281
|
+ * Returns id of the track.
|
|
282
|
+ * @returns {string|null} id of the track or null if this is fake track.
|
218
|
283
|
*/
|
219
|
|
- isLocal() {
|
220
|
|
- throw new Error('Not implemented by subclass');
|
|
284
|
+ getId() {
|
|
285
|
+ return this.getStreamId();
|
221
|
286
|
}
|
222
|
287
|
|
223
|
288
|
/**
|
224
|
|
- * Check whether this is a local audio track.
|
225
|
|
- *
|
226
|
|
- * @return {boolean} - true if track represents a local audio track, false otherwise.
|
|
289
|
+ * Returns the msid of the stream attached to the JitsiTrack object or null
|
|
290
|
+ * if no stream is attached.
|
227
|
291
|
*/
|
228
|
|
- isLocalAudioTrack() {
|
229
|
|
- return this.isAudioTrack() && this.isLocal();
|
|
292
|
+ getMSID() {
|
|
293
|
+ const streamId = this.getStreamId();
|
|
294
|
+ const trackId = this.getTrackId();
|
|
295
|
+
|
|
296
|
+ return streamId && trackId ? `${streamId} ${trackId}` : null;
|
230
|
297
|
}
|
231
|
298
|
|
232
|
299
|
/**
|
|
@@ -268,6 +335,13 @@ export default class JitsiTrack extends EventEmitter {
|
268
|
335
|
return this.track ? this.track.id : null;
|
269
|
336
|
}
|
270
|
337
|
|
|
338
|
+ /**
|
|
339
|
+ * Returns the type (audio or video) of this track.
|
|
340
|
+ */
|
|
341
|
+ getType() {
|
|
342
|
+ return this.type;
|
|
343
|
+ }
|
|
344
|
+
|
271
|
345
|
/**
|
272
|
346
|
* Return meaningful usage label for this track depending on it's media and
|
273
|
347
|
* eventual video type.
|
|
@@ -282,131 +356,66 @@ export default class JitsiTrack extends EventEmitter {
|
282
|
356
|
}
|
283
|
357
|
|
284
|
358
|
/**
|
285
|
|
- * Eventually will trigger RTCEvents.TRACK_ATTACHED event.
|
286
|
|
- * @param container the video/audio container to which this stream is
|
287
|
|
- * attached and for which event will be fired.
|
288
|
|
- * @private
|
289
|
|
- */
|
290
|
|
- _maybeFireTrackAttached(container) {
|
291
|
|
- if (this.conference && container) {
|
292
|
|
- this.conference._onTrackAttach(this, container);
|
293
|
|
- }
|
294
|
|
- }
|
295
|
|
-
|
296
|
|
- /**
|
297
|
|
- * Attaches the MediaStream of this track to an HTML container.
|
298
|
|
- * Adds the container to the list of containers that are displaying the
|
299
|
|
- * track.
|
300
|
|
- *
|
301
|
|
- * @param container the HTML container which can be 'video' or 'audio'
|
302
|
|
- * element.
|
303
|
|
- *
|
304
|
|
- * @returns {void}
|
|
359
|
+ * Returns the video type (camera or desktop) of this track.
|
305
|
360
|
*/
|
306
|
|
- attach(container) {
|
307
|
|
- if (this.stream) {
|
308
|
|
- this._onTrackAttach(container);
|
309
|
|
- RTCUtils.attachMediaStream(container, this.stream);
|
310
|
|
- }
|
311
|
|
- this.containers.push(container);
|
312
|
|
- this._maybeFireTrackAttached(container);
|
313
|
|
- this._attachTTFMTracker(container);
|
|
361
|
+ getVideoType() {
|
|
362
|
+ return this.videoType;
|
314
|
363
|
}
|
315
|
364
|
|
316
|
365
|
/**
|
317
|
|
- * Removes this JitsiTrack from the passed HTML container.
|
318
|
|
- *
|
319
|
|
- * @param container the HTML container to detach from this JitsiTrack. If
|
320
|
|
- * <tt>null</tt> or <tt>undefined</tt>, all containers are removed. A
|
321
|
|
- * container can be a 'video', 'audio' or 'object' HTML element instance to
|
322
|
|
- * which this JitsiTrack is currently attached.
|
|
366
|
+ * Checks whether the MediaStream is active/not ended.
|
|
367
|
+ * When there is no check for active we don't have information and so
|
|
368
|
+ * will return that stream is active (in case of FF).
|
|
369
|
+ * @returns {boolean} whether MediaStream is active.
|
323
|
370
|
*/
|
324
|
|
- detach(container) {
|
325
|
|
- for (let cs = this.containers, i = cs.length - 1; i >= 0; --i) {
|
326
|
|
- const c = cs[i];
|
327
|
|
-
|
328
|
|
- if (!container) {
|
329
|
|
- this._onTrackDetach(c);
|
330
|
|
- RTCUtils.attachMediaStream(c, null);
|
331
|
|
- }
|
332
|
|
- if (!container || c === container) {
|
333
|
|
- cs.splice(i, 1);
|
334
|
|
- }
|
335
|
|
- }
|
336
|
|
-
|
337
|
|
- if (container) {
|
338
|
|
- this._onTrackDetach(container);
|
339
|
|
- RTCUtils.attachMediaStream(container, null);
|
|
371
|
+ isActive() {
|
|
372
|
+ if (typeof this.stream.active !== 'undefined') {
|
|
373
|
+ return this.stream.active;
|
340
|
374
|
}
|
341
|
|
- }
|
342
|
375
|
|
343
|
|
- /**
|
344
|
|
- * Called when the track has been attached to a new container.
|
345
|
|
- *
|
346
|
|
- * @param {HTMLElement} container the HTML container which can be 'video' or
|
347
|
|
- * 'audio' element.
|
348
|
|
- * @private
|
349
|
|
- */
|
350
|
|
- _onTrackAttach(container) { // eslint-disable-line no-unused-vars
|
351
|
|
- // Should be defined by the classes that are extending JitsiTrack
|
|
376
|
+ return true;
|
352
|
377
|
}
|
353
|
378
|
|
354
|
379
|
/**
|
355
|
|
- * Called when the track has been detached from a container.
|
356
|
|
- *
|
357
|
|
- * @param {HTMLElement} container the HTML container which can be 'video' or
|
358
|
|
- * 'audio' element.
|
359
|
|
- * @private
|
|
380
|
+ * Check if this is an audio track.
|
360
|
381
|
*/
|
361
|
|
- _onTrackDetach(container) { // eslint-disable-line no-unused-vars
|
362
|
|
- // Should be defined by the classes that are extending JitsiTrack
|
|
382
|
+ isAudioTrack() {
|
|
383
|
+ return this.getType() === MediaType.AUDIO;
|
363
|
384
|
}
|
364
|
385
|
|
365
|
386
|
/**
|
366
|
|
- * Attach time to first media tracker only if there is conference and only
|
367
|
|
- * for the first element.
|
368
|
|
- *
|
369
|
|
- * @param {HTMLElement} container the HTML container which can be 'video' or
|
370
|
|
- * 'audio' element.
|
371
|
|
- * @private
|
|
387
|
+ * Checks whether this is a local track.
|
|
388
|
+ * @abstract
|
|
389
|
+ * @return {boolean} 'true' if it's a local track or 'false' otherwise.
|
372
|
390
|
*/
|
373
|
|
- _attachTTFMTracker(container) { // eslint-disable-line no-unused-vars
|
374
|
|
- // Should be defined by the classes that are extending JitsiTrack
|
|
391
|
+ isLocal() {
|
|
392
|
+ throw new Error('Not implemented by subclass');
|
375
|
393
|
}
|
376
|
394
|
|
377
|
395
|
/**
|
378
|
|
- * Removes attached event listeners.
|
|
396
|
+ * Check whether this is a local audio track.
|
379
|
397
|
*
|
380
|
|
- * @returns {Promise}
|
|
398
|
+ * @return {boolean} - true if track represents a local audio track, false otherwise.
|
381
|
399
|
*/
|
382
|
|
- dispose() {
|
383
|
|
- this.removeAllListeners();
|
384
|
|
-
|
385
|
|
- this.disposed = true;
|
386
|
|
-
|
387
|
|
- return Promise.resolve();
|
|
400
|
+ isLocalAudioTrack() {
|
|
401
|
+ return this.isAudioTrack() && this.isLocal();
|
388
|
402
|
}
|
389
|
403
|
|
390
|
404
|
/**
|
391
|
|
- * Returns id of the track.
|
392
|
|
- * @returns {string|null} id of the track or null if this is fake track.
|
|
405
|
+ * Check if this is a video track.
|
393
|
406
|
*/
|
394
|
|
- getId() {
|
395
|
|
- return this.getStreamId();
|
|
407
|
+ isVideoTrack() {
|
|
408
|
+ return this.getType() === MediaType.VIDEO;
|
396
|
409
|
}
|
397
|
410
|
|
398
|
411
|
/**
|
399
|
|
- * Checks whether the MediaStream is active/not ended.
|
400
|
|
- * When there is no check for active we don't have information and so
|
401
|
|
- * will return that stream is active (in case of FF).
|
402
|
|
- * @returns {boolean} whether MediaStream is active.
|
|
412
|
+ * Checks whether the underlying WebRTC <tt>MediaStreamTrack</tt> is muted
|
|
413
|
+ * according to it's 'muted' field status.
|
|
414
|
+ * @return {boolean} <tt>true</tt> if the underlying
|
|
415
|
+ * <tt>MediaStreamTrack</tt> is muted or <tt>false</tt> otherwise.
|
403
|
416
|
*/
|
404
|
|
- isActive() {
|
405
|
|
- if (typeof this.stream.active !== 'undefined') {
|
406
|
|
- return this.stream.active;
|
407
|
|
- }
|
408
|
|
-
|
409
|
|
- return true;
|
|
417
|
+ isWebRTCTrackMuted() {
|
|
418
|
+ return this.track && this.track.muted;
|
410
|
419
|
}
|
411
|
420
|
|
412
|
421
|
/**
|
|
@@ -447,17 +456,6 @@ export default class JitsiTrack extends EventEmitter {
|
447
|
456
|
}
|
448
|
457
|
}
|
449
|
458
|
|
450
|
|
- /**
|
451
|
|
- * Returns the msid of the stream attached to the JitsiTrack object or null
|
452
|
|
- * if no stream is attached.
|
453
|
|
- */
|
454
|
|
- getMSID() {
|
455
|
|
- const streamId = this.getStreamId();
|
456
|
|
- const trackId = this.getTrackId();
|
457
|
|
-
|
458
|
|
- return streamId && trackId ? `${streamId} ${trackId}` : null;
|
459
|
|
- }
|
460
|
|
-
|
461
|
459
|
/**
|
462
|
460
|
* Sets new audio output device for track's DOM elements. Video tracks are
|
463
|
461
|
* ignored.
|