Browse Source

Merge pull request #259 from jitsi/participant_conn_status

Adds participant connection status notifications
dev1
hristoterezov 9 years ago
parent
commit
be57f0368f

+ 11
- 0
JitsiConference.js View File

@@ -18,6 +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 23
 
22 24
 /**
23 25
  * Creates a JitsiConference object with the given name and properties.
@@ -92,6 +94,10 @@ JitsiConference.prototype._init = function (options) {
92 94
         this.eventManager.setupRTCListeners();
93 95
     }
94 96
 
97
+    this.participantConnectionStatus
98
+        = new ParticipantConnectionStatus(this.rtc, this);
99
+    this.participantConnectionStatus.init();
100
+
95 101
     if(!this.statistics) {
96 102
         this.statistics = new Statistics(this.xmpp, {
97 103
             callStatsID: this.options.config.callStatsID,
@@ -151,6 +157,11 @@ JitsiConference.prototype._leaveRoomAndRemoveParticipants = function () {
151 157
 JitsiConference.prototype.leave = function () {
152 158
     var conference = this;
153 159
 
160
+    if (this.participantConnectionStatus) {
161
+        this.participantConnectionStatus.dispose();
162
+        this.participantConnectionStatus = null;
163
+    }
164
+
154 165
     this.statistics.stopCallStats();
155 166
     this.rtc.closeAllDataChannels();
156 167
 

+ 10
- 0
JitsiConferenceEvents.js View File

@@ -81,6 +81,16 @@ export const LOCK_STATE_CHANGED = "conference.lock_state_changed";
81 81
  * New text message was received.
82 82
  */
83 83
 export const MESSAGE_RECEIVED = "conference.messageReceived";
84
+/**
85
+ * Event fired when JVB sends notification about interrupted/restored user's
86
+ * ICE connection status. First argument is the ID of the participant and
87
+ * the seconds is a boolean indicating if the connection is currently
88
+ * active(true = active, false = interrupted).
89
+ * The current status value can be obtained by calling
90
+ * JitsiParticipant.isConnectionActive().
91
+ */
92
+export const PARTICIPANT_CONN_STATUS_CHANGED
93
+    = "conference.participant_conn_status_changed";
84 94
 /**
85 95
  * Indicates that a the value of a specific property of a specific participant
86 96
  * has changed.

+ 21
- 0
JitsiParticipant.js View File

@@ -30,6 +30,7 @@ export default class JitsiParticipant {
30 30
             video: undefined
31 31
         };
32 32
         this._hidden = hidden;
33
+        this._isConnectionActive = true;
33 34
         this._properties = {};
34 35
     }
35 36
 
@@ -48,6 +49,26 @@ export default class JitsiParticipant {
48 49
         return this._properties[name];
49 50
     }
50 51
 
52
+    /**
53
+     * Updates participant's connection status.
54
+     * @param {boolean} isActive true if the user's connection is fine or false
55
+     * when the user is having connectivity issues.
56
+     * @private
57
+     */
58
+    _setIsConnectionActive(isActive) {
59
+        this._isConnectionActive = isActive;
60
+    }
61
+
62
+    /**
63
+     * Checks participant's connectivity status.
64
+     *
65
+     * @returns {boolean} true if the connection is currently ok or false when
66
+     * the user is having connectivity issues.
67
+     */
68
+    isConnectionActive() {
69
+        return this._isConnectionActive;
70
+    }
71
+
51 72
     /**
52 73
      * Sets the value of a property of this participant, and fires an event if
53 74
      * the value has changed.

+ 8
- 0
modules/RTC/DataChannels.js View File

@@ -143,6 +143,14 @@ DataChannels.prototype.onDataChannel = function (event) {
143 143
                     RTCEvents.ENDPOINT_MESSAGE_RECEIVED, obj.from,
144 144
                     obj.msgPayload);
145 145
             }
146
+            else if ("EndpointConnectivityStatusChangeEvent" === colibriClass) {
147
+                var endpoint = obj.endpoint;
148
+                var isActive = obj.active === "true";
149
+                logger.info("Endpoint connection status changed: " + endpoint
150
+                           + " active ? " + isActive);
151
+                self.eventEmitter.emit(RTCEvents.ENDPOINT_CONN_STATUS_CHANGED,
152
+                    endpoint, isActive);
153
+            }
146 154
             else {
147 155
                 logger.debug("Data channel JSON-formatted message: ", obj);
148 156
                 // The received message appears to be appropriately formatted

+ 1
- 1
modules/RTC/JitsiLocalTrack.js View File

@@ -340,7 +340,7 @@ JitsiLocalTrack.prototype._setMute = function (mute) {
340 340
             return self._sendMuteStatus(mute);
341 341
         })
342 342
         .then(function() {
343
-            self.eventEmitter.emit(JitsiTrackEvents.TRACK_MUTE_CHANGED);
343
+            self.eventEmitter.emit(JitsiTrackEvents.TRACK_MUTE_CHANGED, this);
344 344
         });
345 345
 };
346 346
 

+ 38
- 4
modules/RTC/JitsiRemoteTrack.js View File

@@ -1,6 +1,10 @@
1
+/* global __filename, module */
2
+var logger = require("jitsi-meet-logger").getLogger(__filename);
3
+
1 4
 var JitsiTrack = require("./JitsiTrack");
2 5
 import * as JitsiTrackEvents from "../../JitsiTrackEvents";
3 6
 var RTCBrowserType = require("./RTCBrowserType");
7
+var RTCEvents = require("../../service/RTC/RTCEvents");
4 8
 var Statistics = require("../statistics/statistics");
5 9
 var AdapterJS = require("./adapter.screenshare");
6 10
 
@@ -9,7 +13,7 @@ var ttfmTrackerVideoAttached = false;
9 13
 
10 14
 /**
11 15
  * Represents a single media track (either audio or video).
12
- * @param RTC the rtc instance.
16
+ * @param rtc {RTC} the RTC service instance.
13 17
  * @param ownerJid the MUC JID of the track owner
14 18
  * @param stream WebRTC MediaStream, parent of the track
15 19
  * @param track underlying WebRTC MediaStreamTrack for new JitsiRemoteTrack
@@ -19,22 +23,52 @@ var ttfmTrackerVideoAttached = false;
19 23
  * @param muted intial muted state of the JitsiRemoteTrack
20 24
  * @constructor
21 25
  */
22
-function JitsiRemoteTrack(conference, ownerJid, stream, track, mediaType, videoType,
26
+function JitsiRemoteTrack(rtc, conference, ownerJid, stream, track, mediaType, videoType,
23 27
                           ssrc, muted) {
24 28
     JitsiTrack.call(
25 29
         this, conference, stream, track, function () {}, mediaType, videoType, ssrc);
26
-    this.conference = conference;
30
+    this.rtc = rtc;
27 31
     this.peerjid = ownerJid;
28 32
     this.muted = muted;
29 33
     // we want to mark whether the track has been ever muted
30 34
     // to detect ttfm events for startmuted conferences, as it can significantly
31 35
     // increase ttfm values
32 36
     this.hasBeenMuted = muted;
37
+    // Bind 'onmute' and 'onunmute' event handlers
38
+    if (this.rtc && this.track)
39
+        this._bindMuteHandlers();
33 40
 }
34 41
 
35 42
 JitsiRemoteTrack.prototype = Object.create(JitsiTrack.prototype);
36 43
 JitsiRemoteTrack.prototype.constructor = JitsiRemoteTrack;
37 44
 
45
+JitsiRemoteTrack.prototype._bindMuteHandlers = function() {
46
+    // Bind 'onmute'
47
+    // FIXME it would be better to use recently added '_setHandler' method, but
48
+    // 1. It does not allow to set more than one handler to the event
49
+    // 2. It does mix MediaStream('inactive') with MediaStreamTrack events
50
+    // 3. Allowing to bind more than one event handler requires too much
51
+    //    refactoring around camera issues detection.
52
+    this.track.addEventListener('mute', function () {
53
+
54
+        logger.debug(
55
+            '"onmute" event(' + Date.now() + '): ',
56
+            this.getParticipantId(), this.getType(), this.getSSRC());
57
+
58
+        this.rtc.eventEmitter.emit(RTCEvents.REMOTE_TRACK_MUTE, this);
59
+    }.bind(this));
60
+
61
+    // Bind 'onunmute'
62
+    this.track.addEventListener('unmute', function () {
63
+
64
+        logger.debug(
65
+            '"onunmute" event(' + Date.now() + '): ',
66
+            this.getParticipantId(), this.getType(), this.getSSRC());
67
+
68
+        this.rtc.eventEmitter.emit(RTCEvents.REMOTE_TRACK_UNMUTE, this);
69
+    }.bind(this));
70
+};
71
+
38 72
 /**
39 73
  * Sets current muted status and fires an events for the change.
40 74
  * @param value the muted status.
@@ -51,7 +85,7 @@ JitsiRemoteTrack.prototype.setMute = function (value) {
51 85
         this.stream.muted = value;
52 86
 
53 87
     this.muted = value;
54
-    this.eventEmitter.emit(JitsiTrackEvents.TRACK_MUTE_CHANGED);
88
+    this.eventEmitter.emit(JitsiTrackEvents.TRACK_MUTE_CHANGED, this);
55 89
 };
56 90
 
57 91
 /**

+ 9
- 0
modules/RTC/JitsiTrack.js View File

@@ -149,6 +149,15 @@ JitsiTrack.prototype.isVideoTrack = function () {
149 149
     return this.getType() === MediaType.VIDEO;
150 150
 };
151 151
 
152
+/**
153
+ * Checks whether this is a local track.
154
+ * @abstract
155
+ * @return {boolean} 'true' if it's a local track or 'false' otherwise.
156
+ */
157
+JitsiTrack.prototype.isLocal = function () {
158
+    throw new Error("Not implemented by subclass");
159
+};
160
+
152 161
 /**
153 162
  * Returns the WebRTC MediaStream instance.
154 163
  */

+ 1
- 1
modules/RTC/RTC.js View File

@@ -301,7 +301,7 @@ RTC.prototype.removeLocalTrack = function (track) {
301 301
 RTC.prototype.createRemoteTrack = function (event) {
302 302
     var ownerJid = event.owner;
303 303
     var remoteTrack = new JitsiRemoteTrack(
304
-        this.conference,  ownerJid, event.stream,    event.track,
304
+        this, this.conference, ownerJid, event.stream, event.track,
305 305
         event.mediaType, event.videoType, event.ssrc, event.muted);
306 306
     var resource = Strophe.getResourceFromJid(ownerJid);
307 307
     var remoteTracks

+ 10
- 0
modules/RTC/RTCBrowserType.js View File

@@ -106,6 +106,16 @@ var RTCBrowserType = {
106 106
         return RTCBrowserType.isIExplorer() || RTCBrowserType.isSafari();
107 107
     },
108 108
 
109
+    /**
110
+     * Checks if the current browser triggers 'onmute'/'onunmute' events when
111
+     * user's connection is interrupted and the video stops playback.
112
+     * @returns {*|boolean} 'true' if the event is supported or 'false'
113
+     * otherwise.
114
+     */
115
+    isVideoMuteOnConnInterruptedSupported: function () {
116
+        return RTCBrowserType.isChrome();
117
+    },
118
+
109 119
     /**
110 120
      * Returns Firefox version.
111 121
      * @returns {number|null}

+ 306
- 0
modules/connectivity/ParticipantConnectionStatus.js View File

@@ -0,0 +1,306 @@
1
+/* global __filename, module, require */
2
+var logger = require('jitsi-meet-logger').getLogger(__filename);
3
+var MediaType = require('../../service/RTC/MediaType');
4
+var RTCBrowserType = require('../RTC/RTCBrowserType');
5
+var RTCEvents = require('../../service/RTC/RTCEvents');
6
+
7
+import * as JitsiConferenceEvents from '../../JitsiConferenceEvents';
8
+import * as JitsiTrackEvents from '../../JitsiTrackEvents';
9
+
10
+/**
11
+ * How long we're going to wait after the RTC video track muted event for
12
+ * the corresponding signalling mute event, before the connection interrupted
13
+ * is fired.
14
+ *
15
+ * @type {number} amount of time in milliseconds
16
+ */
17
+const RTC_MUTE_TIMEOUT = 1000;
18
+
19
+/**
20
+ * Class is responsible for emitting
21
+ * JitsiConferenceEvents.PARTICIPANT_CONN_STATUS_CHANGED events.
22
+ *
23
+ * @constructor
24
+ * @param rtc {RTC} the RTC service instance
25
+ * @param conference {JitsiConference} parent conference instance
26
+ */
27
+function ParticipantConnectionStatus(rtc, conference) {
28
+    this.rtc = rtc;
29
+    this.conference = conference;
30
+    /**
31
+     * A map of the "endpoint ID"(which corresponds to the resource part of MUC
32
+     * JID(nickname)) to the timeout callback IDs scheduled using
33
+     * window.setTimeout.
34
+     * @type {Object.<string, number>}
35
+     */
36
+    this.trackTimers = {};
37
+}
38
+
39
+/**
40
+ * Initializes <tt>ParticipantConnectionStatus</tt> and bind required event
41
+ * listeners.
42
+ */
43
+ParticipantConnectionStatus.prototype.init = function() {
44
+
45
+    this._onEndpointConnStatusChanged
46
+        = this.onEndpointConnStatusChanged.bind(this);
47
+
48
+    this.rtc.addListener(
49
+        RTCEvents.ENDPOINT_CONN_STATUS_CHANGED,
50
+        this._onEndpointConnStatusChanged);
51
+
52
+    // On some browsers MediaStreamTrack trigger "onmute"/"onunmute"
53
+    // events for video type tracks when they stop receiving data which is
54
+    // often a sign that remote user is having connectivity issues
55
+    if (RTCBrowserType.isVideoMuteOnConnInterruptedSupported()) {
56
+
57
+        this._onTrackRtcMuted = this.onTrackRtcMuted.bind(this);
58
+        this.rtc.addListener(
59
+            RTCEvents.REMOTE_TRACK_MUTE, this._onTrackRtcMuted);
60
+
61
+        this._onTrackRtcUnmuted = this.onTrackRtcUnmuted.bind(this);
62
+        this.rtc.addListener(
63
+            RTCEvents.REMOTE_TRACK_UNMUTE, this._onTrackRtcUnmuted);
64
+
65
+        // Track added/removed listeners are used to bind "mute"/"unmute"
66
+        // event handlers
67
+        this._onRemoteTrackAdded = this.onRemoteTrackAdded.bind(this);
68
+        this.conference.on(
69
+            JitsiConferenceEvents.TRACK_ADDED, this._onRemoteTrackAdded);
70
+        this._onRemoteTrackRemoved = this.onRemoteTrackRemoved.bind(this);
71
+        this.conference.on(
72
+            JitsiConferenceEvents.TRACK_REMOVED, this._onRemoteTrackRemoved);
73
+
74
+        // Listened which will be bound to JitsiRemoteTrack to listen for
75
+        // signalling mute/unmute events.
76
+        this._onSignallingMuteChanged = this.onSignallingMuteChanged.bind(this);
77
+    }
78
+};
79
+
80
+/**
81
+ * Removes all event listeners and disposes of all resources held by this
82
+ * instance.
83
+ */
84
+ParticipantConnectionStatus.prototype.dispose = function () {
85
+
86
+    this.rtc.removeListener(
87
+        RTCEvents.ENDPOINT_CONN_STATUS_CHANGED,
88
+        this._onEndpointConnStatusChanged);
89
+
90
+    if (RTCBrowserType.isVideoMuteOnConnInterruptedSupported()) {
91
+        this.rtc.removeListener(
92
+            RTCEvents.REMOTE_TRACK_MUTE, this._onTrackRtcMuted);
93
+        this.rtc.removeListener(
94
+            RTCEvents.REMOTE_TRACK_UNMUTE, this._onTrackRtcUnmuted);
95
+        this.conference.off(
96
+            JitsiConferenceEvents.TRACK_ADDED, this._onRemoteTrackAdded);
97
+        this.conference.off(
98
+            JitsiConferenceEvents.TRACK_REMOVED, this._onRemoteTrackRemoved);
99
+    }
100
+
101
+    Object.keys(this.trackTimers).forEach(function (participantId) {
102
+        this.clearTimeout(participantId);
103
+    }.bind(this));
104
+};
105
+
106
+/**
107
+ * Checks whether given <tt>JitsiParticipant</tt> has any muted video
108
+ * <tt>MediaStreamTrack</tt>s.
109
+ *
110
+ * @param {JitsiParticipant} participant to be checked for muted video tracks
111
+ *
112
+ * @return {boolean} <tt>true</tt> if given <tt>participant</tt> contains any
113
+ * video <tt>MediaStreamTrack</tt>s muted according to their 'muted' field.
114
+ */
115
+var hasRtcMutedVideoTrack = function (participant) {
116
+    return participant.getTracks().some(function(jitsiTrack) {
117
+        var rtcTrack = jitsiTrack.getTrack();
118
+        return jitsiTrack.getType() === MediaType.VIDEO
119
+            && rtcTrack && rtcTrack.muted === true;
120
+    });
121
+};
122
+
123
+/**
124
+ * Handles RTCEvents.ENDPOINT_CONN_STATUS_CHANGED triggered when we receive
125
+ * notification over the data channel from the bridge about endpoint's
126
+ * connection status update.
127
+ * @param endpointId {string} the endpoint ID(MUC nickname/resource JID)
128
+ * @param isActive {boolean} true if the connection is OK or false otherwise
129
+ */
130
+ParticipantConnectionStatus.prototype.onEndpointConnStatusChanged
131
+= function(endpointId, isActive) {
132
+
133
+    logger.debug(
134
+        'Detector RTCEvents.ENDPOINT_CONN_STATUS_CHANGED('
135
+            + Date.now() +'): ' + endpointId + ': ' + isActive);
136
+
137
+    // Filter out events for the local JID for now
138
+    if (endpointId !== this.conference.myUserId()) {
139
+        var participant = this.conference.getParticipantById(endpointId);
140
+        // Delay the 'active' event until the video track gets RTC unmuted event
141
+        if (isActive
142
+                && RTCBrowserType.isVideoMuteOnConnInterruptedSupported()
143
+                && participant
144
+                && hasRtcMutedVideoTrack(participant)
145
+                && !participant.isVideoMuted()) {
146
+            logger.debug(
147
+                'Ignoring RTCEvents.ENDPOINT_CONN_STATUS_CHANGED -'
148
+                    + ' will wait for unmute event');
149
+        } else {
150
+            this._changeConnectionStatus(endpointId, isActive);
151
+        }
152
+    }
153
+};
154
+
155
+ParticipantConnectionStatus.prototype._changeConnectionStatus
156
+= function (endpointId, newStatus) {
157
+    var participant = this.conference.getParticipantById(endpointId);
158
+    if (!participant) {
159
+        // This will happen when participant exits the conference with broken
160
+        // ICE connection and we join after that. The bridge keeps sending
161
+        // that notification until the conference does not expire.
162
+        logger.warn(
163
+            'Missed participant connection status update - ' +
164
+                'no participant for endpoint: ' + endpointId);
165
+        return;
166
+    }
167
+    if (participant.isConnectionActive() !== newStatus) {
168
+        participant._setIsConnectionActive(newStatus);
169
+        logger.debug(
170
+            'Emit endpoint conn status(' + Date.now() + '): ',
171
+            endpointId, newStatus);
172
+        this.conference.eventEmitter.emit(
173
+            JitsiConferenceEvents.PARTICIPANT_CONN_STATUS_CHANGED,
174
+            endpointId, newStatus);
175
+    }
176
+};
177
+
178
+/**
179
+ * Reset the postponed "connection interrupted" event which was previously
180
+ * scheduled as a timeout on RTC 'onmute' event.
181
+ *
182
+ * @param participantId the participant for which the "connection interrupted"
183
+ * timeout was scheduled
184
+ */
185
+ParticipantConnectionStatus.prototype.clearTimeout = function (participantId) {
186
+    if (this.trackTimers[participantId]) {
187
+        window.clearTimeout(this.trackTimers[participantId]);
188
+        this.trackTimers[participantId] = null;
189
+    }
190
+};
191
+
192
+/**
193
+ * Bind signalling mute event listeners for video {JitsiRemoteTrack} when
194
+ * a new one is added to the conference.
195
+ *
196
+ * @param {JitsiTrack} remoteTrack the {JitsiTrack} which is being added to
197
+ * the conference.
198
+ */
199
+ParticipantConnectionStatus.prototype.onRemoteTrackAdded
200
+= function(remoteTrack) {
201
+    if (!remoteTrack.isLocal() && remoteTrack.getType() === MediaType.VIDEO) {
202
+
203
+        logger.debug(
204
+            'Detector on remote track added: ', remoteTrack.getParticipantId());
205
+
206
+        remoteTrack.on(
207
+            JitsiTrackEvents.TRACK_MUTE_CHANGED,
208
+            this._onSignallingMuteChanged);
209
+    }
210
+};
211
+
212
+/**
213
+ * Removes all event listeners bound to the remote video track and clears any
214
+ * related timeouts.
215
+ *
216
+ * @param {JitsiRemoteTrack} remoteTrack the remote track which is being removed
217
+ * from the conference.
218
+ */
219
+ParticipantConnectionStatus.prototype.onRemoteTrackRemoved
220
+= function(remoteTrack) {
221
+    if (!remoteTrack.isLocal() && remoteTrack.getType() === MediaType.VIDEO) {
222
+        logger.debug(
223
+            'Detector on remote track removed: ',
224
+            remoteTrack.getParticipantId());
225
+        remoteTrack.off(
226
+            JitsiTrackEvents.TRACK_MUTE_CHANGED,
227
+            this._onSignallingMuteChanged);
228
+        this.clearTimeout(remoteTrack.getParticipantId());
229
+    }
230
+};
231
+
232
+/**
233
+ * Handles RTC 'onmute' event for the video track.
234
+ *
235
+ * @param track {JitsiRemoteTrack} the video track for which 'onmute' event will
236
+ * be processed.
237
+ */
238
+ParticipantConnectionStatus.prototype.onTrackRtcMuted = function(track) {
239
+    var participantId = track.getParticipantId();
240
+    var participant = this.conference.getParticipantById(participantId);
241
+    logger.debug('Detector track RTC muted: ', participantId);
242
+    if (!participant) {
243
+        logger.error('No participant for id: ' + participantId);
244
+        return;
245
+    }
246
+    if (!participant.isVideoMuted()) {
247
+        // If the user is not muted according to the signalling we'll give it
248
+        // some time, before the connection interrupted event is triggered.
249
+        this.trackTimers[participantId] = window.setTimeout(function () {
250
+            if (!track.isMuted() && participant.isConnectionActive()) {
251
+                logger.info(
252
+                    'Connection interrupted through the RTC mute: '
253
+                        + participantId, Date.now());
254
+                this._changeConnectionStatus(participantId, false);
255
+            }
256
+            this.clearTimeout(participantId);
257
+        }.bind(this), RTC_MUTE_TIMEOUT);
258
+    }
259
+};
260
+
261
+/**
262
+ * Handles RTC 'onunmute' event for the video track.
263
+ *
264
+ * @param track {JitsiRemoteTrack} the video track for which 'onunmute' event
265
+ * will be processed.
266
+ */
267
+ParticipantConnectionStatus.prototype.onTrackRtcUnmuted = function(track) {
268
+    logger.debug('Detector track RTC unmuted: ', track);
269
+    var participantId = track.getParticipantId();
270
+    if (!track.isMuted() &&
271
+        !this.conference.getParticipantById(participantId)
272
+            .isConnectionActive()) {
273
+        logger.info(
274
+            'Detector connection restored through the RTC unmute: '
275
+                + participantId, Date.now());
276
+        this._changeConnectionStatus(participantId, true);
277
+    }
278
+    this.clearTimeout(participantId);
279
+};
280
+
281
+/**
282
+ * Here the signalling "mute"/"unmute" events are processed.
283
+ *
284
+ * @param track {JitsiRemoteTrack} the remote video track for which
285
+ * the signalling mute/unmute event will be processed.
286
+ */
287
+ParticipantConnectionStatus.prototype.onSignallingMuteChanged
288
+= function (track) {
289
+    logger.debug(
290
+        'Detector on track signalling mute changed: ', track, track.isMuted());
291
+    var isMuted = track.isMuted();
292
+    var participantId = track.getParticipantId();
293
+    var participant = this.conference.getParticipantById(participantId);
294
+    if (!participant) {
295
+        logger.error('No participant for id: ' + participantId);
296
+        return;
297
+    }
298
+    var isConnectionActive = participant.isConnectionActive();
299
+    if (isMuted && isConnectionActive && this.trackTimers[participantId]) {
300
+        logger.debug(
301
+            'Signalling got in sync - cancelling task for: ' + participantId);
302
+        this.clearTimeout(participantId);
303
+    }
304
+};
305
+
306
+module.exports = ParticipantConnectionStatus;

+ 3
- 0
service/RTC/RTCEvents.js View File

@@ -1,11 +1,14 @@
1 1
 var RTCEvents = {
2 2
     RTC_READY: "rtc.ready",
3 3
     DATA_CHANNEL_OPEN: "rtc.data_channel_open",
4
+    ENDPOINT_CONN_STATUS_CHANGED: "rtc.endpoint_conn_status_changed",
4 5
     LASTN_CHANGED: "rtc.lastn_changed",
5 6
     DOMINANTSPEAKER_CHANGED: "rtc.dominantspeaker_changed",
6 7
     LASTN_ENDPOINT_CHANGED: "rtc.lastn_endpoint_changed",
7 8
     AVAILABLE_DEVICES_CHANGED: "rtc.available_devices_changed",
8 9
     TRACK_ATTACHED: "rtc.track_attached",
10
+    REMOTE_TRACK_MUTE: "rtc.remote_track_mute",
11
+    REMOTE_TRACK_UNMUTE: "rtc.remote_track_unmute",
9 12
     AUDIO_OUTPUT_DEVICE_CHANGED: "rtc.audio_output_device_changed",
10 13
     DEVICE_LIST_CHANGED: "rtc.device_list_changed",
11 14
     DEVICE_LIST_AVAILABLE: "rtc.device_list_available",

Loading…
Cancel
Save