Преглед изворни кода

feat: report avg end to end RTT

Average end to end RTT calculated as a sum of local RTT towards the JVB
and an average of towards JVB RTTs reported by other participants.
Will be reported under 'stat.avg.end2endrtt' analytics event name.
master
paweldomas пре 8 година
родитељ
комит
49568f75d7
2 измењених фајлова са 96 додато и 16 уклоњено
  1. 7
    2
      modules/connectivity/ConnectionQuality.js
  2. 89
    14
      modules/statistics/AvgRTPStatsReporter.js

+ 7
- 2
modules/connectivity/ConnectionQuality.js Прегледај датотеку

@@ -396,7 +396,11 @@ export default class ConnectionQuality {
396 396
         const data = {
397 397
             bitrate: this._localStats.bitrate,
398 398
             packetLoss: this._localStats.packetLoss,
399
-            connectionQuality: this._localStats.connectionQuality
399
+            connectionQuality: this._localStats.connectionQuality,
400
+            jvbRTT: this._localStats.transport
401
+                    && this._localStats.transport.length
402
+                    && !this._localStats.transport[0].p2p
403
+                        ? this._localStats.transport[0].rtt : undefined
400 404
         };
401 405
 
402 406
         // TODO: It looks like the remote participants don't really "care"
@@ -477,7 +481,8 @@ export default class ConnectionQuality {
477 481
         this._remoteStats[id] = {
478 482
             bitrate: data.bitrate,
479 483
             packetLoss: data.packetLoss,
480
-            connectionQuality: data.connectionQuality
484
+            connectionQuality: data.connectionQuality,
485
+            jvbRTT: data.jvbRTT
481 486
         };
482 487
 
483 488
         this.eventEmitter.emit(

+ 89
- 14
modules/statistics/AvgRTPStatsReporter.js Прегледај датотеку

@@ -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
 }

Loading…
Откажи
Сачувај