|
|
@@ -184,6 +184,14 @@ export default class AvgRTPStatsReporter {
|
|
184
|
184
|
*/
|
|
185
|
185
|
this._avgRemoteFPS = new AverageStatReport('stat.avg.framerate.remote');
|
|
186
|
186
|
|
|
|
187
|
+ /**
|
|
|
188
|
+ * Map stores average RTT to the JVB reported by remote participants.
|
|
|
189
|
+ * Mapped per participant id {@link JitsiParticipant.getId}.
|
|
|
190
|
+ * @type {Map<string,AverageStatReport>}
|
|
|
191
|
+ * @private
|
|
|
192
|
+ */
|
|
|
193
|
+ this._avgRemoteRTTMap = new Map();
|
|
|
194
|
+
|
|
187
|
195
|
/**
|
|
188
|
196
|
* Average round trip time reported by the ICE candidate pair.
|
|
189
|
197
|
* FIXME currently reported only for P2P
|
|
|
@@ -212,6 +220,12 @@ export default class AvgRTPStatsReporter {
|
|
212
|
220
|
ConnectionQualityEvents.LOCAL_STATS_UPDATED,
|
|
213
|
221
|
this._onLocalStatsUpdated);
|
|
214
|
222
|
|
|
|
223
|
+ this._onRemoteStatsUpdated
|
|
|
224
|
+ = (id, data) => this._processRemoteStats(id, data);
|
|
|
225
|
+ conference.on(
|
|
|
226
|
+ ConnectionQualityEvents.REMOTE_STATS_UPDATED,
|
|
|
227
|
+ this._onRemoteStatsUpdated);
|
|
|
228
|
+
|
|
215
|
229
|
this._onP2PStatusChanged = () => {
|
|
216
|
230
|
logger.debug('Resetting average stats calculation');
|
|
217
|
231
|
this._resetAvgStats();
|
|
|
@@ -219,6 +233,33 @@ export default class AvgRTPStatsReporter {
|
|
219
|
233
|
conference.on(
|
|
220
|
234
|
ConferenceEvents.P2P_STATUS,
|
|
221
|
235
|
this._onP2PStatusChanged);
|
|
|
236
|
+
|
|
|
237
|
+ this._onUserLeft = id => this._avgRemoteRTTMap.delete(id);
|
|
|
238
|
+ conference.on(ConferenceEvents.USER_LEFT, this._onUserLeft);
|
|
|
239
|
+ }
|
|
|
240
|
+
|
|
|
241
|
+ /**
|
|
|
242
|
+ * Calculates arithmetic mean of all RTTs towards the JVB reported by
|
|
|
243
|
+ * participants.
|
|
|
244
|
+ * @return {number|NaN} NaN if not available (not enough data)
|
|
|
245
|
+ * @private
|
|
|
246
|
+ */
|
|
|
247
|
+ _calculateAvgRemoteRTT() {
|
|
|
248
|
+ let count = 0, sum = 0;
|
|
|
249
|
+
|
|
|
250
|
+ // FIXME should we ignore RTT for participant
|
|
|
251
|
+ // who "is having connectivity issues" ?
|
|
|
252
|
+ for (const remoteAvg of this._avgRemoteRTTMap.values()) {
|
|
|
253
|
+ const avg = remoteAvg.calculate();
|
|
|
254
|
+
|
|
|
255
|
+ if (!isNaN(avg)) {
|
|
|
256
|
+ sum += avg;
|
|
|
257
|
+ count += 1;
|
|
|
258
|
+ remoteAvg.reset();
|
|
|
259
|
+ }
|
|
|
260
|
+ }
|
|
|
261
|
+
|
|
|
262
|
+ return sum / count;
|
|
222
|
263
|
}
|
|
223
|
264
|
|
|
224
|
265
|
/**
|
|
|
@@ -290,8 +331,7 @@ export default class AvgRTPStatsReporter {
|
|
290
|
331
|
this._avgCQ.addNext(data.connectionQuality);
|
|
291
|
332
|
|
|
292
|
333
|
if (RTCBrowserType.supportsRTTStatistics()) {
|
|
293
|
|
- // FIXME implement JVB end-to-end RTT
|
|
294
|
|
- if (isP2P && data.transport && data.transport.length) {
|
|
|
334
|
+ if (data.transport && data.transport.length) {
|
|
295
|
335
|
this._avgRTT.addNext(data.transport[0].rtt);
|
|
296
|
336
|
} else {
|
|
297
|
337
|
this._avgRTT.reset();
|
|
|
@@ -321,9 +361,18 @@ export default class AvgRTPStatsReporter {
|
|
321
|
361
|
this._avgLocalFPS.report(isP2P);
|
|
322
|
362
|
this._avgCQ.report(isP2P);
|
|
323
|
363
|
|
|
324
|
|
- // FIXME implement JVB end-to-end RTT
|
|
325
|
|
- if (isP2P && RTCBrowserType.supportsRTTStatistics()) {
|
|
|
364
|
+ if (RTCBrowserType.supportsRTTStatistics()) {
|
|
326
|
365
|
this._avgRTT.report(isP2P);
|
|
|
366
|
+ if (!isP2P) {
|
|
|
367
|
+ const avgRemoteRTT = this._calculateAvgRemoteRTT();
|
|
|
368
|
+ const avgLocalRTT = this._avgRTT.calculate();
|
|
|
369
|
+
|
|
|
370
|
+ if (!isNaN(avgLocalRTT) && !isNaN(avgRemoteRTT)) {
|
|
|
371
|
+ Statistics.analytics.sendEvent(
|
|
|
372
|
+ 'stat.avg.end2endrtt',
|
|
|
373
|
+ avgLocalRTT + avgRemoteRTT);
|
|
|
374
|
+ }
|
|
|
375
|
+ }
|
|
327
|
376
|
}
|
|
328
|
377
|
|
|
329
|
378
|
this._resetAvgStats();
|
|
|
@@ -366,6 +415,29 @@ export default class AvgRTPStatsReporter {
|
|
366
|
415
|
return subFrameAvg / peerCount;
|
|
367
|
416
|
}
|
|
368
|
417
|
|
|
|
418
|
+ /**
|
|
|
419
|
+ * Processes {@link ConnectionQualityEvents.REMOTE_STATS_UPDATED} to analyse
|
|
|
420
|
+ * RTT towards the JVB reported by each participant.
|
|
|
421
|
+ * @param {string} id {@link JitsiParticipant.getId}
|
|
|
422
|
+ * @param {go figure in ConnectionQuality.js} data
|
|
|
423
|
+ * @private
|
|
|
424
|
+ */
|
|
|
425
|
+ _processRemoteStats(id, data) {
|
|
|
426
|
+ const validData = typeof data.jvbRTT === 'number';
|
|
|
427
|
+ let rttAvg = this._avgRemoteRTTMap.get(id);
|
|
|
428
|
+
|
|
|
429
|
+ if (!rttAvg && validData) {
|
|
|
430
|
+ rttAvg = new AverageStatReport(`${id}.stat.rtt`);
|
|
|
431
|
+ this._avgRemoteRTTMap.set(id, rttAvg);
|
|
|
432
|
+ }
|
|
|
433
|
+
|
|
|
434
|
+ if (validData) {
|
|
|
435
|
+ rttAvg.addNext(data.jvbRTT);
|
|
|
436
|
+ } else if (rttAvg) {
|
|
|
437
|
+ this._avgRemoteRTTMap.delete(id);
|
|
|
438
|
+ }
|
|
|
439
|
+ }
|
|
|
440
|
+
|
|
369
|
441
|
/**
|
|
370
|
442
|
* Reset cache of all averages and {@link _sampleIdx}.
|
|
371
|
443
|
* @private
|
|
|
@@ -381,6 +453,7 @@ export default class AvgRTPStatsReporter {
|
|
381
|
453
|
this._avgLocalFPS.reset();
|
|
382
|
454
|
this._avgCQ.reset();
|
|
383
|
455
|
this._avgRTT.reset();
|
|
|
456
|
+ this._avgRemoteRTTMap.clear();
|
|
384
|
457
|
this._sampleIdx = 0;
|
|
385
|
458
|
}
|
|
386
|
459
|
|
|
|
@@ -388,15 +461,17 @@ export default class AvgRTPStatsReporter {
|
|
388
|
461
|
* Unregisters all event listeners and stops working.
|
|
389
|
462
|
*/
|
|
390
|
463
|
dispose() {
|
|
391
|
|
- if (this._onP2PStatusChanged) {
|
|
392
|
|
- this._conference.off(
|
|
393
|
|
- ConferenceEvents.P2P_STATUS,
|
|
394
|
|
- this._onP2PStatusChanged);
|
|
395
|
|
- }
|
|
396
|
|
- if (this._onLocalStatsUpdated) {
|
|
397
|
|
- this._conference.off(
|
|
398
|
|
- ConnectionQualityEvents.LOCAL_STATS_UPDATED,
|
|
399
|
|
- this._onLocalStatsUpdated);
|
|
400
|
|
- }
|
|
|
464
|
+ this._conference.off(
|
|
|
465
|
+ ConferenceEvents.P2P_STATUS,
|
|
|
466
|
+ this._onP2PStatusChanged);
|
|
|
467
|
+ this._conference.off(
|
|
|
468
|
+ ConnectionQualityEvents.LOCAL_STATS_UPDATED,
|
|
|
469
|
+ this._onLocalStatsUpdated);
|
|
|
470
|
+ this._conference.off(
|
|
|
471
|
+ ConnectionQualityEvents.REMOTE_STATS_UPDATED,
|
|
|
472
|
+ this._onRemoteStatsUpdated);
|
|
|
473
|
+ this._conference.off(
|
|
|
474
|
+ ConferenceEvents.USER_LEFT,
|
|
|
475
|
+ this._onUserLeft);
|
|
401
|
476
|
}
|
|
402
|
477
|
}
|