Procházet zdrojové kódy

Merge pull request #292 from jitsi/fix_peer_conn_status_with_dev_switch

Fix participant connection status stuck after device switch
dev1
hristoterezov před 9 roky
rodič
revize
1707315c0e

+ 2
- 2
JitsiConference.js Zobrazit soubor

@@ -18,8 +18,8 @@ var GlobalOnErrorHandler = require("./modules/util/GlobalOnErrorHandler");
18 18
 var JitsiConferenceEventManager = require("./JitsiConferenceEventManager");
19 19
 var VideoType = require('./service/RTC/VideoType');
20 20
 var Transcriber = require("./modules/transcription/transcriber");
21
-var ParticipantConnectionStatus
22
-    = require("./modules/connectivity/ParticipantConnectionStatus");
21
+import ParticipantConnectionStatus
22
+    from "./modules/connectivity/ParticipantConnectionStatus";
23 23
 import TalkMutedDetection from "./modules/TalkMutedDetection";
24 24
 
25 25
 /**

+ 15
- 0
JitsiParticipant.js Zobrazit soubor

@@ -49,6 +49,21 @@ export default class JitsiParticipant {
49 49
         return this._properties[name];
50 50
     }
51 51
 
52
+    /**
53
+     * Checks whether this <tt>JitsiParticipant</tt> has any video tracks which
54
+     * are muted according to their underlying WebRTC <tt>MediaStreamTrack</tt>
55
+     * muted status.
56
+     * @return {boolean} <tt>true</tt> if this <tt>participant</tt> contains any
57
+     * video <tt>JitsiTrack</tt>s which are muted as defined in
58
+     * {@link JitsiTrack.isWebRTCTrackMuted}.
59
+     */
60
+    hasAnyVideoTrackWebRTCMuted() {
61
+        return this.getTracks().some(function(jitsiTrack) {
62
+            return jitsiTrack.getType() === MediaType.VIDEO
63
+                && jitsiTrack.isWebRTCTrackMuted();
64
+        });
65
+    }
66
+
52 67
     /**
53 68
      * Updates participant's connection status.
54 69
      * @param {boolean} isActive true if the user's connection is fine or false

+ 10
- 0
modules/RTC/JitsiTrack.js Zobrazit soubor

@@ -141,6 +141,16 @@ JitsiTrack.prototype.isAudioTrack = function () {
141 141
     return this.getType() === MediaType.AUDIO;
142 142
 };
143 143
 
144
+/**
145
+ * Checks whether the underlying WebRTC <tt>MediaStreamTrack</tt> is muted
146
+ * according to it's 'muted' field status.
147
+ * @return {boolean} <tt>true</tt> if the underlying <tt>MediaStreamTrack</tt>
148
+ * is muted or <tt>false</tt> otherwise.
149
+ */
150
+JitsiTrack.prototype.isWebRTCTrackMuted = function () {
151
+    return this.track && this.track.muted;
152
+};
153
+
144 154
 /**
145 155
  * Check if this is videotrack.
146 156
  */

+ 347
- 273
modules/connectivity/ParticipantConnectionStatus.js Zobrazit soubor

@@ -19,317 +19,391 @@ const DEFAULT_RTC_MUTE_TIMEOUT = 2000;
19 19
 /**
20 20
  * Class is responsible for emitting
21 21
  * JitsiConferenceEvents.PARTICIPANT_CONN_STATUS_CHANGED events.
22
- *
23
- * @constructor
24
- * @param {RTC} rtc the RTC service instance
25
- * @param {JitsiConference} conference parent conference instance
26
- * @param {number} rtcMuteTimeout (optional) custom value for
27
- * {@link ParticipantConnectionStatus.rtcMuteTimeout}.
28 22
  */
29
-function ParticipantConnectionStatus(rtc, conference, rtcMuteTimeout) {
30
-    this.rtc = rtc;
31
-    this.conference = conference;
32
-    /**
33
-     * A map of the "endpoint ID"(which corresponds to the resource part of MUC
34
-     * JID(nickname)) to the timeout callback IDs scheduled using
35
-     * window.setTimeout.
36
-     * @type {Object.<string, number>}
37
-     */
38
-    this.trackTimers = {};
23
+export default class ParticipantConnectionStatus {
39 24
     /**
40
-     * How long we're going to wait after the RTC video track muted event for
41
-     * the corresponding signalling mute event, before the connection
42
-     * interrupted is fired. The default value is
43
-     * {@link DEFAULT_RTC_MUTE_TIMEOUT}.
25
+     * Creates new instance of <tt>ParticipantConnectionStatus</tt>.
44 26
      *
45
-     * @type {number} amount of time in milliseconds
27
+     * @constructor
28
+     * @param {RTC} rtc the RTC service instance
29
+     * @param {JitsiConference} conference parent conference instance
30
+     * @param {number} rtcMuteTimeout (optional) custom value for
31
+     * {@link ParticipantConnectionStatus.rtcMuteTimeout}.
46 32
      */
47
-    this.rtcMuteTimeout
48
-        = typeof rtcMuteTimeout === 'number'
49
-            ? rtcMuteTimeout : DEFAULT_RTC_MUTE_TIMEOUT;
50
-    logger.info("RtcMuteTimeout set to: " + this.rtcMuteTimeout);
51
-}
52
-
53
-/**
54
- * Initializes <tt>ParticipantConnectionStatus</tt> and bind required event
55
- * listeners.
56
- */
57
-ParticipantConnectionStatus.prototype.init = function() {
58
-
59
-    this._onEndpointConnStatusChanged
60
-        = this.onEndpointConnStatusChanged.bind(this);
61
-
62
-    this.rtc.addListener(
63
-        RTCEvents.ENDPOINT_CONN_STATUS_CHANGED,
64
-        this._onEndpointConnStatusChanged);
33
+    constructor(rtc, conference, rtcMuteTimeout) {
34
+        this.rtc = rtc;
35
+        this.conference = conference;
36
+        /**
37
+         * A map of the "endpoint ID"(which corresponds to the resource part
38
+         * of MUC JID(nickname)) to the timeout callback IDs scheduled using
39
+         * window.setTimeout.
40
+         * @type {Object.<string, number>}
41
+         */
42
+        this.trackTimers = {};
43
+        /**
44
+         * This map holds the endpoint connection status received from the JVB
45
+         * (as it might be different than the one stored in JitsiParticipant).
46
+         * Required for getting back in sync when remote video track is removed.
47
+         * @type {Object.<string, boolean>}
48
+         */
49
+        this.rtcConnStatusCache = { };
50
+        /**
51
+         * How long we're going to wait after the RTC video track muted event
52
+         * for the corresponding signalling mute event, before the connection
53
+         * interrupted is fired. The default value is
54
+         * {@link DEFAULT_RTC_MUTE_TIMEOUT}.
55
+         *
56
+         * @type {number} amount of time in milliseconds
57
+         */
58
+        this.rtcMuteTimeout
59
+            = typeof rtcMuteTimeout === 'number'
60
+                ? rtcMuteTimeout : DEFAULT_RTC_MUTE_TIMEOUT;
61
+        logger.info("RtcMuteTimeout set to: " + this.rtcMuteTimeout);
62
+    }
65 63
 
66
-    // On some browsers MediaStreamTrack trigger "onmute"/"onunmute"
67
-    // events for video type tracks when they stop receiving data which is
68
-    // often a sign that remote user is having connectivity issues
69
-    if (RTCBrowserType.isVideoMuteOnConnInterruptedSupported()) {
64
+    /**
65
+     * Initializes <tt>ParticipantConnectionStatus</tt> and bind required event
66
+     * listeners.
67
+     */
68
+    init() {
70 69
 
71
-        this._onTrackRtcMuted = this.onTrackRtcMuted.bind(this);
72
-        this.rtc.addListener(
73
-            RTCEvents.REMOTE_TRACK_MUTE, this._onTrackRtcMuted);
70
+        this._onEndpointConnStatusChanged
71
+            = this.onEndpointConnStatusChanged.bind(this);
74 72
 
75
-        this._onTrackRtcUnmuted = this.onTrackRtcUnmuted.bind(this);
76 73
         this.rtc.addListener(
77
-            RTCEvents.REMOTE_TRACK_UNMUTE, this._onTrackRtcUnmuted);
78
-
79
-        // Track added/removed listeners are used to bind "mute"/"unmute"
80
-        // event handlers
81
-        this._onRemoteTrackAdded = this.onRemoteTrackAdded.bind(this);
82
-        this.conference.on(
83
-            JitsiConferenceEvents.TRACK_ADDED, this._onRemoteTrackAdded);
84
-        this._onRemoteTrackRemoved = this.onRemoteTrackRemoved.bind(this);
85
-        this.conference.on(
86
-            JitsiConferenceEvents.TRACK_REMOVED, this._onRemoteTrackRemoved);
87
-
88
-        // Listened which will be bound to JitsiRemoteTrack to listen for
89
-        // signalling mute/unmute events.
90
-        this._onSignallingMuteChanged = this.onSignallingMuteChanged.bind(this);
74
+            RTCEvents.ENDPOINT_CONN_STATUS_CHANGED,
75
+            this._onEndpointConnStatusChanged);
76
+
77
+        // On some browsers MediaStreamTrack trigger "onmute"/"onunmute"
78
+        // events for video type tracks when they stop receiving data which is
79
+        // often a sign that remote user is having connectivity issues
80
+        if (RTCBrowserType.isVideoMuteOnConnInterruptedSupported()) {
81
+
82
+            this._onTrackRtcMuted = this.onTrackRtcMuted.bind(this);
83
+            this.rtc.addListener(
84
+                RTCEvents.REMOTE_TRACK_MUTE, this._onTrackRtcMuted);
85
+
86
+            this._onTrackRtcUnmuted = this.onTrackRtcUnmuted.bind(this);
87
+            this.rtc.addListener(
88
+                RTCEvents.REMOTE_TRACK_UNMUTE, this._onTrackRtcUnmuted);
89
+
90
+            // Track added/removed listeners are used to bind "mute"/"unmute"
91
+            // event handlers
92
+            this._onRemoteTrackAdded = this.onRemoteTrackAdded.bind(this);
93
+            this.conference.on(
94
+                JitsiConferenceEvents.TRACK_ADDED,
95
+                this._onRemoteTrackAdded);
96
+
97
+            this._onRemoteTrackRemoved = this.onRemoteTrackRemoved.bind(this);
98
+            this.conference.on(
99
+                JitsiConferenceEvents.TRACK_REMOVED,
100
+                this._onRemoteTrackRemoved);
101
+
102
+            // Listened which will be bound to JitsiRemoteTrack to listen for
103
+            // signalling mute/unmute events.
104
+            this._onSignallingMuteChanged
105
+                = this.onSignallingMuteChanged.bind(this);
106
+        }
91 107
     }
92
-};
93 108
 
94
-/**
95
- * Removes all event listeners and disposes of all resources held by this
96
- * instance.
97
- */
98
-ParticipantConnectionStatus.prototype.dispose = function () {
99
-
100
-    this.rtc.removeListener(
101
-        RTCEvents.ENDPOINT_CONN_STATUS_CHANGED,
102
-        this._onEndpointConnStatusChanged);
109
+    /**
110
+     * Removes all event listeners and disposes of all resources held by this
111
+     * instance.
112
+     */
113
+    dispose() {
103 114
 
104
-    if (RTCBrowserType.isVideoMuteOnConnInterruptedSupported()) {
105
-        this.rtc.removeListener(
106
-            RTCEvents.REMOTE_TRACK_MUTE, this._onTrackRtcMuted);
107 115
         this.rtc.removeListener(
108
-            RTCEvents.REMOTE_TRACK_UNMUTE, this._onTrackRtcUnmuted);
109
-        this.conference.off(
110
-            JitsiConferenceEvents.TRACK_ADDED, this._onRemoteTrackAdded);
111
-        this.conference.off(
112
-            JitsiConferenceEvents.TRACK_REMOVED, this._onRemoteTrackRemoved);
113
-    }
116
+            RTCEvents.ENDPOINT_CONN_STATUS_CHANGED,
117
+            this._onEndpointConnStatusChanged);
118
+
119
+        if (RTCBrowserType.isVideoMuteOnConnInterruptedSupported()) {
120
+            this.rtc.removeListener(
121
+                RTCEvents.REMOTE_TRACK_MUTE,
122
+                this._onTrackRtcMuted);
123
+            this.rtc.removeListener(
124
+                RTCEvents.REMOTE_TRACK_UNMUTE,
125
+                this._onTrackRtcUnmuted);
126
+
127
+            this.conference.off(
128
+                JitsiConferenceEvents.TRACK_ADDED,
129
+                this._onRemoteTrackAdded);
130
+            this.conference.off(
131
+                JitsiConferenceEvents.TRACK_REMOVED,
132
+                this._onRemoteTrackRemoved);
133
+        }
114 134
 
115
-    Object.keys(this.trackTimers).forEach(function (participantId) {
116
-        this.clearTimeout(participantId);
117
-    }.bind(this));
118
-};
135
+        Object.keys(this.trackTimers).forEach(function (participantId) {
136
+            this.clearTimeout(participantId);
137
+        }.bind(this));
119 138
 
120
-/**
121
- * Checks whether given <tt>JitsiParticipant</tt> has any muted video
122
- * <tt>MediaStreamTrack</tt>s.
123
- *
124
- * @param {JitsiParticipant} participant to be checked for muted video tracks
125
- *
126
- * @return {boolean} <tt>true</tt> if given <tt>participant</tt> contains any
127
- * video <tt>MediaStreamTrack</tt>s muted according to their 'muted' field.
128
- */
129
-var hasRtcMutedVideoTrack = function (participant) {
130
-    return participant.getTracks().some(function(jitsiTrack) {
131
-        var rtcTrack = jitsiTrack.getTrack();
132
-        return jitsiTrack.getType() === MediaType.VIDEO
133
-            && rtcTrack && rtcTrack.muted === true;
134
-    });
135
-};
139
+        // Clear RTC connection status cache
140
+        this.rtcConnStatusCache = {};
141
+    }
136 142
 
137
-/**
138
- * Handles RTCEvents.ENDPOINT_CONN_STATUS_CHANGED triggered when we receive
139
- * notification over the data channel from the bridge about endpoint's
140
- * connection status update.
141
- * @param endpointId {string} the endpoint ID(MUC nickname/resource JID)
142
- * @param isActive {boolean} true if the connection is OK or false otherwise
143
- */
144
-ParticipantConnectionStatus.prototype.onEndpointConnStatusChanged
145
-= function(endpointId, isActive) {
143
+    /**
144
+     * Handles RTCEvents.ENDPOINT_CONN_STATUS_CHANGED triggered when we receive
145
+     * notification over the data channel from the bridge about endpoint's
146
+     * connection status update.
147
+     * @param endpointId {string} the endpoint ID(MUC nickname/resource JID)
148
+     * @param isActive {boolean} true if the connection is OK or false otherwise
149
+     */
150
+    onEndpointConnStatusChanged(endpointId, isActive) {
146 151
 
147
-    logger.debug(
148
-        'Detector RTCEvents.ENDPOINT_CONN_STATUS_CHANGED('
149
-            + Date.now() +'): ' + endpointId + ': ' + isActive);
152
+        logger.debug(
153
+            'Detector RTCEvents.ENDPOINT_CONN_STATUS_CHANGED('
154
+                + Date.now() +'): ' + endpointId + ': ' + isActive);
155
+
156
+        // Filter out events for the local JID for now
157
+        if (endpointId !== this.conference.myUserId()) {
158
+
159
+            // Cache the status received received over the data channels, as
160
+            // it will be needed to verify for out of sync when the remote video
161
+            // track is being removed.
162
+            this.rtcConnStatusCache[endpointId] = isActive;
163
+
164
+            var participant = this.conference.getParticipantById(endpointId);
165
+            // Delay the 'active' event until the video track gets
166
+            // the RTC unmuted event
167
+            if (isActive
168
+                    && RTCBrowserType.isVideoMuteOnConnInterruptedSupported()
169
+                    && participant
170
+                    && participant.hasAnyVideoTrackWebRTCMuted()
171
+                    && !participant.isVideoMuted()) {
172
+                logger.debug(
173
+                    'Ignoring RTCEvents.ENDPOINT_CONN_STATUS_CHANGED -'
174
+                        + ' will wait for unmute event');
175
+            } else {
176
+                this._changeConnectionStatus(endpointId, isActive);
177
+            }
178
+        }
179
+    }
150 180
 
151
-    // Filter out events for the local JID for now
152
-    if (endpointId !== this.conference.myUserId()) {
181
+    _changeConnectionStatus(endpointId, newStatus) {
153 182
         var participant = this.conference.getParticipantById(endpointId);
154
-        // Delay the 'active' event until the video track gets RTC unmuted event
155
-        if (isActive
156
-                && RTCBrowserType.isVideoMuteOnConnInterruptedSupported()
157
-                && participant
158
-                && hasRtcMutedVideoTrack(participant)
159
-                && !participant.isVideoMuted()) {
183
+        if (!participant) {
184
+            // This will happen when participant exits the conference with
185
+            // broken ICE connection and we join after that. The bridge keeps
186
+            // sending that notification until the conference does not expire.
187
+            logger.warn(
188
+                'Missed participant connection status update - ' +
189
+                    'no participant for endpoint: ' + endpointId);
190
+            return;
191
+        }
192
+        if (participant.isConnectionActive() !== newStatus) {
193
+
194
+            participant._setIsConnectionActive(newStatus);
195
+
160 196
             logger.debug(
161
-                'Ignoring RTCEvents.ENDPOINT_CONN_STATUS_CHANGED -'
162
-                    + ' will wait for unmute event');
163
-        } else {
164
-            this._changeConnectionStatus(endpointId, isActive);
197
+                'Emit endpoint conn status(' + Date.now() + ') '
198
+                    + endpointId + ": " + newStatus);
199
+
200
+            // Log the event on CallStats
201
+            Statistics.sendLog(
202
+                JSON.stringify({
203
+                    id: 'peer.conn.status',
204
+                    participant: endpointId,
205
+                    status: newStatus
206
+                }));
207
+
208
+            // and analytics
209
+            Statistics.analytics.sendEvent('peer.conn.status',
210
+                {label: newStatus});
211
+
212
+            this.conference.eventEmitter.emit(
213
+                JitsiConferenceEvents.PARTICIPANT_CONN_STATUS_CHANGED,
214
+                endpointId, newStatus);
165 215
         }
166 216
     }
167
-};
168
-
169
-ParticipantConnectionStatus.prototype._changeConnectionStatus
170
-= function (endpointId, newStatus) {
171
-    var participant = this.conference.getParticipantById(endpointId);
172
-    if (!participant) {
173
-        // This will happen when participant exits the conference with broken
174
-        // ICE connection and we join after that. The bridge keeps sending
175
-        // that notification until the conference does not expire.
176
-        logger.warn(
177
-            'Missed participant connection status update - ' +
178
-                'no participant for endpoint: ' + endpointId);
179
-        return;
217
+
218
+    /**
219
+     * Reset the postponed "connection interrupted" event which was previously
220
+     * scheduled as a timeout on RTC 'onmute' event.
221
+     *
222
+     * @param participantId the participant for which the "connection
223
+     * interrupted" timeout was scheduled
224
+     */
225
+    clearTimeout(participantId) {
226
+        if (this.trackTimers[participantId]) {
227
+            window.clearTimeout(this.trackTimers[participantId]);
228
+            this.trackTimers[participantId] = null;
229
+        }
180 230
     }
181
-    if (participant.isConnectionActive() !== newStatus) {
182 231
 
183
-        participant._setIsConnectionActive(newStatus);
232
+    /**
233
+     * Bind signalling mute event listeners for video {JitsiRemoteTrack} when
234
+     * a new one is added to the conference.
235
+     *
236
+     * @param {JitsiTrack} remoteTrack the {JitsiTrack} which is being added to
237
+     * the conference.
238
+     */
239
+    onRemoteTrackAdded(remoteTrack) {
240
+        if (!remoteTrack.isLocal()
241
+                && remoteTrack.getType() === MediaType.VIDEO) {
184 242
 
185
-        logger.debug(
186
-            'Emit endpoint conn status(' + Date.now() + '): ',
187
-            endpointId, newStatus);
188
-
189
-        // Log the event on CallStats
190
-        Statistics.sendLog(
191
-            JSON.stringify({
192
-                id: 'peer.conn.status',
193
-                participant: endpointId,
194
-                status: newStatus
195
-            }));
196
-
197
-        // and analytics
198
-        Statistics.analytics.sendEvent('peer.conn.status',
199
-            {label: newStatus});
200
-
201
-        this.conference.eventEmitter.emit(
202
-            JitsiConferenceEvents.PARTICIPANT_CONN_STATUS_CHANGED,
203
-            endpointId, newStatus);
204
-    }
205
-};
243
+            logger.debug(
244
+                'Detector on remote track added for: '
245
+                    + remoteTrack.getParticipantId());
206 246
 
207
-/**
208
- * Reset the postponed "connection interrupted" event which was previously
209
- * scheduled as a timeout on RTC 'onmute' event.
210
- *
211
- * @param participantId the participant for which the "connection interrupted"
212
- * timeout was scheduled
213
- */
214
-ParticipantConnectionStatus.prototype.clearTimeout = function (participantId) {
215
-    if (this.trackTimers[participantId]) {
216
-        window.clearTimeout(this.trackTimers[participantId]);
217
-        this.trackTimers[participantId] = null;
247
+            remoteTrack.on(
248
+                JitsiTrackEvents.TRACK_MUTE_CHANGED,
249
+                this._onSignallingMuteChanged);
250
+        }
218 251
     }
219
-};
220 252
 
221
-/**
222
- * Bind signalling mute event listeners for video {JitsiRemoteTrack} when
223
- * a new one is added to the conference.
224
- *
225
- * @param {JitsiTrack} remoteTrack the {JitsiTrack} which is being added to
226
- * the conference.
227
- */
228
-ParticipantConnectionStatus.prototype.onRemoteTrackAdded
229
-= function(remoteTrack) {
230
-    if (!remoteTrack.isLocal() && remoteTrack.getType() === MediaType.VIDEO) {
253
+    /**
254
+     * Removes all event listeners bound to the remote video track and clears
255
+     * any related timeouts.
256
+     *
257
+     * @param {JitsiRemoteTrack} remoteTrack the remote track which is being
258
+     * removed from the conference.
259
+     */
260
+    onRemoteTrackRemoved(remoteTrack) {
261
+        if (!remoteTrack.isLocal()
262
+                && remoteTrack.getType() === MediaType.VIDEO) {
231 263
 
232
-        logger.debug(
233
-            'Detector on remote track added: ', remoteTrack.getParticipantId());
264
+            const endpointId = remoteTrack.getParticipantId();
234 265
 
235
-        remoteTrack.on(
236
-            JitsiTrackEvents.TRACK_MUTE_CHANGED,
237
-            this._onSignallingMuteChanged);
266
+            logger.debug(
267
+                'Detector on remote track removed: ' + endpointId);
268
+
269
+            remoteTrack.off(
270
+                JitsiTrackEvents.TRACK_MUTE_CHANGED,
271
+                this._onSignallingMuteChanged);
272
+
273
+            this.clearTimeout(endpointId);
274
+
275
+            // Only if we're using video muted events - check if the JVB status
276
+            // should be restored from cache.
277
+            if (RTCBrowserType.isVideoMuteOnConnInterruptedSupported())
278
+            {
279
+                this.maybeRestoreCachedStatus(endpointId);
280
+            }
281
+        }
238 282
     }
239
-};
240 283
 
241
-/**
242
- * Removes all event listeners bound to the remote video track and clears any
243
- * related timeouts.
244
- *
245
- * @param {JitsiRemoteTrack} remoteTrack the remote track which is being removed
246
- * from the conference.
247
- */
248
-ParticipantConnectionStatus.prototype.onRemoteTrackRemoved
249
-= function(remoteTrack) {
250
-    if (!remoteTrack.isLocal() && remoteTrack.getType() === MediaType.VIDEO) {
284
+    /**
285
+     * When RTC video track muted events are taken into account,
286
+     * at the point when the track is being removed we have to update
287
+     * to the current connectivity status according to the JVB. That's
288
+     * because if the current track is muted then the new one which
289
+     * replaces it is always added as unmuted and there may be no
290
+     * 'muted'/'unmuted' event sequence if the connection restores in
291
+     * the meantime.
292
+     *
293
+     * XXX See onEndpointConnStatusChanged method where the update is
294
+     * postponed and which is the cause for this workaround. If we
295
+     * decide to not wait for video unmuted event and accept the JVB
296
+     * status immediately then it's fine to remove the code below.
297
+     */
298
+    maybeRestoreCachedStatus(endpointId) {
299
+        var participant = this.conference.getParticipantById(endpointId);
300
+        if (!participant) {
301
+            // Probably the participant is no longer in the conference
302
+            // (at the time of writing this code, participant is
303
+            // detached from the conference and TRACK_REMOVED events are
304
+            // fired),
305
+            // so we don't care, but let's print the warning for
306
+            // debugging purpose
307
+            logger.warn(
308
+                'maybeRestoreCachedStatus - ' +
309
+                'no participant for endpoint: ' + endpointId);
310
+            return;
311
+        }
312
+
313
+        const isConnectionActive = participant.isConnectionActive();
314
+        const hasAnyVideoRTCMuted = participant.hasAnyVideoTrackWebRTCMuted();
315
+        const isConnActiveByJvb = this.rtcConnStatusCache[endpointId];
316
+
251 317
         logger.debug(
252
-            'Detector on remote track removed: ',
253
-            remoteTrack.getParticipantId());
254
-        remoteTrack.off(
255
-            JitsiTrackEvents.TRACK_MUTE_CHANGED,
256
-            this._onSignallingMuteChanged);
257
-        this.clearTimeout(remoteTrack.getParticipantId());
318
+            "Remote track removed, is active: " + isConnectionActive
319
+            + " is active(jvb):" + isConnActiveByJvb
320
+            + " video RTC muted:" + hasAnyVideoRTCMuted);
321
+
322
+        if (!isConnectionActive && isConnActiveByJvb && !hasAnyVideoRTCMuted) {
323
+            // FIXME adjust the log level or remove the message completely once
324
+            // the feature gets mature enough.
325
+            logger.info(
326
+                "Remote track removed for disconnected" +
327
+                " participant, when the status according to" +
328
+                " the JVB is connected. Adjusting to the JVB value.");
329
+            this._changeConnectionStatus(endpointId, isConnActiveByJvb);
330
+        }
258 331
     }
259
-};
260 332
 
261
-/**
262
- * Handles RTC 'onmute' event for the video track.
263
- *
264
- * @param {JitsiRemoteTrack} track the video track for which 'onmute' event will
265
- * be processed.
266
- */
267
-ParticipantConnectionStatus.prototype.onTrackRtcMuted = function(track) {
268
-    var participantId = track.getParticipantId();
269
-    var participant = this.conference.getParticipantById(participantId);
270
-    logger.debug('Detector track RTC muted: ', participantId);
271
-    if (!participant) {
272
-        logger.error('No participant for id: ' + participantId);
273
-        return;
274
-    }
275
-    if (!participant.isVideoMuted()) {
276
-        // If the user is not muted according to the signalling we'll give it
277
-        // some time, before the connection interrupted event is triggered.
278
-        this.trackTimers[participantId] = window.setTimeout(function () {
279
-            if (!track.isMuted() && participant.isConnectionActive()) {
280
-                logger.info(
281
-                    'Connection interrupted through the RTC mute: '
282
-                        + participantId, Date.now());
283
-                this._changeConnectionStatus(participantId, false);
284
-            }
285
-            this.clearTimeout(participantId);
286
-        }.bind(this), this.rtcMuteTimeout);
333
+    /**
334
+     * Handles RTC 'onmute' event for the video track.
335
+     *
336
+     * @param {JitsiRemoteTrack} track the video track for which 'onmute' event
337
+     * will be processed.
338
+     */
339
+    onTrackRtcMuted(track) {
340
+        var participantId = track.getParticipantId();
341
+        var participant = this.conference.getParticipantById(participantId);
342
+        logger.debug('Detector track RTC muted: ' + participantId);
343
+        if (!participant) {
344
+            logger.error('No participant for id: ' + participantId);
345
+            return;
346
+        }
347
+        if (!participant.isVideoMuted()) {
348
+            // If the user is not muted according to the signalling we'll give
349
+            // it some time, before the connection interrupted event is
350
+            // triggered.
351
+            this.trackTimers[participantId] = window.setTimeout(function () {
352
+                if (!track.isMuted() && participant.isConnectionActive()) {
353
+                    logger.info(
354
+                        'Connection interrupted through the RTC mute: '
355
+                            + participantId, Date.now());
356
+                    this._changeConnectionStatus(participantId, false);
357
+                }
358
+                this.clearTimeout(participantId);
359
+            }.bind(this), this.rtcMuteTimeout);
360
+        }
287 361
     }
288
-};
289 362
 
290
-/**
291
- * Handles RTC 'onunmute' event for the video track.
292
- *
293
- * @param {JitsiRemoteTrack} track the video track for which 'onunmute' event
294
- * will be processed.
295
- */
296
-ParticipantConnectionStatus.prototype.onTrackRtcUnmuted = function(track) {
297
-    logger.debug('Detector track RTC unmuted: ', track);
298
-    var participantId = track.getParticipantId();
299
-    if (!track.isMuted() &&
300
-        !this.conference.getParticipantById(participantId)
301
-            .isConnectionActive()) {
302
-        logger.info(
303
-            'Detector connection restored through the RTC unmute: '
304
-                + participantId, Date.now());
305
-        this._changeConnectionStatus(participantId, true);
363
+    /**
364
+     * Handles RTC 'onunmute' event for the video track.
365
+     *
366
+     * @param {JitsiRemoteTrack} track the video track for which 'onunmute'
367
+     * event will be processed.
368
+     */
369
+    onTrackRtcUnmuted(track) {
370
+        logger.debug('Detector track RTC unmuted: ', track);
371
+        var participantId = track.getParticipantId();
372
+        if (!track.isMuted() &&
373
+            !this.conference.getParticipantById(participantId)
374
+                .isConnectionActive()) {
375
+            logger.info(
376
+                'Detector connection restored through the RTC unmute: '
377
+                    + participantId, Date.now());
378
+            this._changeConnectionStatus(participantId, true);
379
+        }
380
+        this.clearTimeout(participantId);
306 381
     }
307
-    this.clearTimeout(participantId);
308
-};
309 382
 
310
-/**
311
- * Here the signalling "mute"/"unmute" events are processed.
312
- *
313
- * @param {JitsiRemoteTrack} track the remote video track for which
314
- * the signalling mute/unmute event will be processed.
315
- */
316
-ParticipantConnectionStatus.prototype.onSignallingMuteChanged
317
-= function (track) {
318
-    logger.debug(
319
-        'Detector on track signalling mute changed: ', track, track.isMuted());
320
-    var isMuted = track.isMuted();
321
-    var participantId = track.getParticipantId();
322
-    var participant = this.conference.getParticipantById(participantId);
323
-    if (!participant) {
324
-        logger.error('No participant for id: ' + participantId);
325
-        return;
326
-    }
327
-    var isConnectionActive = participant.isConnectionActive();
328
-    if (isMuted && isConnectionActive && this.trackTimers[participantId]) {
383
+    /**
384
+     * Here the signalling "mute"/"unmute" events are processed.
385
+     *
386
+     * @param {JitsiRemoteTrack} track the remote video track for which
387
+     * the signalling mute/unmute event will be processed.
388
+     */
389
+    onSignallingMuteChanged (track) {
329 390
         logger.debug(
330
-            'Signalling got in sync - cancelling task for: ' + participantId);
331
-        this.clearTimeout(participantId);
391
+            'Detector on track signalling mute changed: ',
392
+            track, track.isMuted());
393
+        var isMuted = track.isMuted();
394
+        var participantId = track.getParticipantId();
395
+        var participant = this.conference.getParticipantById(participantId);
396
+        if (!participant) {
397
+            logger.error('No participant for id: ' + participantId);
398
+            return;
399
+        }
400
+        var isConnectionActive = participant.isConnectionActive();
401
+        if (isMuted && isConnectionActive && this.trackTimers[participantId]) {
402
+            logger.debug(
403
+                'Signalling got in sync - cancelling task for: '
404
+                    + participantId);
405
+            this.clearTimeout(participantId);
406
+        }
332 407
     }
333
-};
334 408
 
335
-module.exports = ParticipantConnectionStatus;
409
+}

Načítá se…
Zrušit
Uložit