|
@@ -73,6 +73,12 @@ function JitsiLocalTrack(stream, track, mediaType, videoType, resolution,
|
73
|
73
|
// called.
|
74
|
74
|
this._realDeviceId = this.deviceId === '' ? undefined : this.deviceId;
|
75
|
75
|
|
|
76
|
+ /**
|
|
77
|
+ * Indicates that we have called RTCUtils.stopMediaStream for the
|
|
78
|
+ * MediaStream related to this JitsiTrack object.
|
|
79
|
+ */
|
|
80
|
+ this.stopStreamInProgress = false;
|
|
81
|
+
|
76
|
82
|
this._onDeviceListChanged = function (devices) {
|
77
|
83
|
self._setRealDeviceIdFromDeviceList(devices);
|
78
|
84
|
|
|
@@ -101,6 +107,19 @@ function JitsiLocalTrack(stream, track, mediaType, videoType, resolution,
|
101
|
107
|
|
102
|
108
|
RTCUtils.addListener(RTCEvents.DEVICE_LIST_CHANGED,
|
103
|
109
|
this._onDeviceListChanged);
|
|
110
|
+
|
|
111
|
+ if(this.isVideoTrack() && this.videoType === VideoType.CAMERA) {
|
|
112
|
+ this._setHandler("track_mute", function () {
|
|
113
|
+ if(!this._checkForCameraIssues())
|
|
114
|
+ return;
|
|
115
|
+ this.eventEmitter.emit(JitsiTrackEvents.NO_DATA_FROM_SOURCE);
|
|
116
|
+ }.bind(this));
|
|
117
|
+ this._setHandler("track_ended", function () {
|
|
118
|
+ if(!this._checkForCameraIssues())
|
|
119
|
+ return;
|
|
120
|
+ this.eventEmitter.emit(JitsiTrackEvents.NO_DATA_FROM_SOURCE);
|
|
121
|
+ }.bind(this));
|
|
122
|
+ }
|
104
|
123
|
}
|
105
|
124
|
|
106
|
125
|
JitsiLocalTrack.prototype = Object.create(JitsiTrack.prototype);
|
|
@@ -215,7 +234,7 @@ JitsiLocalTrack.prototype._setMute = function (mute) {
|
215
|
234
|
this._removeStreamFromConferenceAsMute(() => {
|
216
|
235
|
//FIXME: Maybe here we should set the SRC for the containers
|
217
|
236
|
// to something
|
218
|
|
- RTCUtils.stopMediaStream(this.stream);
|
|
237
|
+ this._stopMediaStream();
|
219
|
238
|
this._setStream(null);
|
220
|
239
|
resolve();
|
221
|
240
|
}, (err) => {
|
|
@@ -363,7 +382,7 @@ JitsiLocalTrack.prototype.dispose = function () {
|
363
|
382
|
}
|
364
|
383
|
|
365
|
384
|
if (this.stream) {
|
366
|
|
- RTCUtils.stopMediaStream(this.stream);
|
|
385
|
+ this._stopMediaStream();
|
367
|
386
|
this.detach();
|
368
|
387
|
}
|
369
|
388
|
|
|
@@ -468,7 +487,7 @@ JitsiLocalTrack.prototype._setByteSent = function (bytesSent) {
|
468
|
487
|
setTimeout(function () {
|
469
|
488
|
if(this._bytesSent <= 0){
|
470
|
489
|
//we are not receiving anything from the microphone
|
471
|
|
- this.eventEmitter.emit(JitsiTrackEvents.TRACK_AUDIO_NOT_WORKING);
|
|
490
|
+ this.eventEmitter.emit(JitsiTrackEvents.NO_DATA_FROM_SOURCE);
|
472
|
491
|
}
|
473
|
492
|
}.bind(this), 3000);
|
474
|
493
|
this._testByteSent = false;
|
|
@@ -516,5 +535,57 @@ JitsiLocalTrack.prototype.getCameraFacingMode = function () {
|
516
|
535
|
return undefined;
|
517
|
536
|
};
|
518
|
537
|
|
|
538
|
+/**
|
|
539
|
+ * Stops the associated MediaStream.
|
|
540
|
+ */
|
|
541
|
+JitsiLocalTrack.prototype._stopMediaStream = function () {
|
|
542
|
+ this.stopStreamInProgress = true;
|
|
543
|
+ RTCUtils.stopMediaStream(this.stream);
|
|
544
|
+ this.stopStreamInProgress = false;
|
|
545
|
+}
|
|
546
|
+
|
|
547
|
+/**
|
|
548
|
+ * Detects camera issues on ended and mute events from MediaStreamTrack.
|
|
549
|
+ * @returns {boolean} true if an issue is detected and false otherwise
|
|
550
|
+ */
|
|
551
|
+JitsiLocalTrack.prototype._checkForCameraIssues = function () {
|
|
552
|
+ if(!this.isVideoTrack() || this.stopStreamInProgress ||
|
|
553
|
+ this.videoType === VideoType.DESKTOP)
|
|
554
|
+ return false;
|
|
555
|
+
|
|
556
|
+ return !this._isReceivingData();
|
|
557
|
+}
|
|
558
|
+
|
|
559
|
+/**
|
|
560
|
+ * Checks whether the attached MediaStream is reveiving data from source or
|
|
561
|
+ * not. If the stream property is null(because of mute or another reason) this
|
|
562
|
+ * method will return false.
|
|
563
|
+ * NOTE: This method doesn't indicate problem with the streams directly.
|
|
564
|
+ * For example in case of video mute the method will return false or if the
|
|
565
|
+ * user has disposed the track.
|
|
566
|
+ * @returns {boolean} true if the stream is receiving data and false otherwise.
|
|
567
|
+ */
|
|
568
|
+JitsiLocalTrack.prototype._isReceivingData = function () {
|
|
569
|
+ if(!this.stream)
|
|
570
|
+ return false;
|
|
571
|
+ var isReceivingData = false;
|
|
572
|
+ var tracks = this.stream.getTracks();
|
|
573
|
+ tracks.some(function (track) {
|
|
574
|
+ // In older version of the spec there is no muted property and
|
|
575
|
+ // readyState can have value muted. In the latest versions
|
|
576
|
+ // readyState can have values "live" and "ended" and there is
|
|
577
|
+ // muted boolean property. If the stream is muted that means that
|
|
578
|
+ // we aren't receiving any data from the source. We want to notify
|
|
579
|
+ // the users for error if the stream is muted or ended on it's
|
|
580
|
+ // creation.
|
|
581
|
+ if((!("readyState" in track) || track.readyState === "live")
|
|
582
|
+ && (!("muted" in track) || track.muted === false)) {
|
|
583
|
+ isReceivingData = true;
|
|
584
|
+ return true;
|
|
585
|
+ }
|
|
586
|
+ return false;
|
|
587
|
+ });
|
|
588
|
+ return isReceivingData;
|
|
589
|
+}
|
519
|
590
|
|
520
|
591
|
module.exports = JitsiLocalTrack;
|