浏览代码

feat(stats): Treats local/remote relayed addresses differently.

master
George Politis 8 年前
父节点
当前提交
0ff967cbc4
共有 2 个文件被更改,包括 116 次插入95 次删除
  1. 99
    59
      modules/statistics/AvgRTPStatsReporter.js
  2. 17
    36
      modules/statistics/RTPStatsCollector.js

+ 99
- 59
modules/statistics/AvgRTPStatsReporter.js 查看文件

@@ -17,8 +17,10 @@ import * as VideoType from '../../service/RTC/VideoType';
17 17
  *
18 18
  * {
19 19
  *   p2p: true,
20
- *   conferenceSize: 1,
21
- *   relayed: true,
20
+ *   conferenceSize: 2,
21
+ *   localCandidateType: "relay",
22
+ *   remoteCandidateType: "relay",
23
+ *   transportType: "udp",
22 24
  *
23 25
  *   "stat_avg_rtt": {
24 26
  *     value: 200,
@@ -92,18 +94,12 @@ class AverageStatReport {
92 94
      * Appends the report to the analytics "data" object. The object will be
93 95
      * set under <tt>prefix</tt> + {@link this.name} key.
94 96
      * @param {Object} report the analytics "data" object
95
-     * @param {Object} extra properties to append to the analytics "data" object
96 97
      */
97
-    appendReport(report, props) {
98
-
99
-        const reportValue = {
98
+    appendReport(report) {
99
+        report[this.name] = {
100 100
             value: this.calculate(),
101 101
             samples: this.samples
102 102
         };
103
-
104
-        Object.assign(reportValue, props);
105
-
106
-        report[this.name] = reportValue;
107 103
     }
108 104
 
109 105
     /**
@@ -125,12 +121,12 @@ class AverageStatReport {
125 121
 class ConnectionAvgStats {
126 122
     /**
127 123
      * Creates new <tt>ConnectionAvgStats</tt>
128
-     * @param {JitsiConference} conference
124
+     * @param {AvgRTPStatsReporter} avgRtpStatsReporter
129 125
      * @param {boolean} isP2P
130 126
      * @param {number} n the number of samples, before arithmetic mean is to be
131 127
      * calculated and values submitted to the analytics module.
132 128
      */
133
-    constructor(conference, isP2P, n) {
129
+    constructor(avgRtpStatsReporter, isP2P, n) {
134 130
         /**
135 131
          * Is this instance for JVB or P2P connection ?
136 132
          * @type {boolean}
@@ -175,13 +171,26 @@ class ConnectionAvgStats {
175 171
          * @type {JitsiConference}
176 172
          * @private
177 173
          */
178
-        this._conference = conference;
174
+        this._avgRtpStatsReporter = avgRtpStatsReporter;
175
+
176
+        /**
177
+         * The latest average E2E RTT for the JVB connection only.
178
+         *
179
+         * This is used only when {@link ConnectionAvgStats.isP2P} equals to
180
+         * <tt>false</tt>.
181
+         *
182
+         * @type {number}
183
+         */
184
+        this._avgEnd2EndRTT = undefined;
179 185
 
180 186
         this._onConnectionStats = (tpc, stats) => {
181 187
             if (this.isP2P === tpc.isP2P) {
182 188
                 this._calculateAvgStats(stats);
183 189
             }
184 190
         };
191
+
192
+        const conference = avgRtpStatsReporter._conference;
193
+
185 194
         conference.statistics.addConnectionStatsListener(
186 195
             this._onConnectionStats);
187 196
 
@@ -219,30 +228,51 @@ class ConnectionAvgStats {
219 228
 
220 229
         if (this._sampleIdx >= this._n) {
221 230
             if (RTCBrowserType.supportsRTTStatistics()) {
222
-                const batchReport = { };
223
-                const props = {
224
-                    relayed: data.relayed,
231
+                const conference = this._avgRtpStatsReporter._conference;
232
+
233
+                const batchReport = {
225 234
                     p2p: this.isP2P,
226
-                    size: this._conference.getParticipantCount()
235
+                    size: conference.getParticipantCount()
227 236
                 };
228 237
 
229
-                this._avgRTT.appendReport(batchReport, props);
238
+                if (data.transport && data.transport.length) {
239
+                    Object.assign(batchReport, {
240
+                        localCandidateType:
241
+                            data.transport[0].localCandidateType,
242
+                        remoteCandidateType:
243
+                            data.transport[0].remoteCandidateType,
244
+                        transportType: data.transport[0].type
245
+                    });
246
+                }
230 247
 
231
-                // Report end to end RTT only for JVB
232
-                if (!this.isP2P) {
233
-                    const avgRemoteRTT = this._calculateAvgRemoteRTT();
234
-                    const avgLocalRTT = this._avgRTT.calculate();
248
+                this._avgRTT.appendReport(batchReport);
235 249
 
236
-                    if (!isNaN(avgLocalRTT) && !isNaN(avgRemoteRTT)) {
237
-                        // eslint-disable-next-line camelcase
238
-                        const reportValue = {
239
-                            value: avgLocalRTT + avgRemoteRTT
250
+                if (this.isP2P) {
251
+                    // Report RTT diff only for P2P.
252
+                    const jvbEnd2EndRTT = this
253
+                        ._avgRtpStatsReporter.jvbStatsMonitor._avgEnd2EndRTT;
254
+
255
+                    if (!isNaN(jvbEnd2EndRTT)) {
256
+                        const avgRTTDiff
257
+                            = this._avgRTT.calculate() - jvbEnd2EndRTT;
258
+
259
+                        // eslint-disable-next-line dot-notation
260
+                        batchReport['stat_avg_rtt_diff'] = {
261
+                            value: avgRTTDiff
240 262
                         };
263
+                    }
264
+                } else {
265
+                    // Report end to end RTT only for JVB.
266
+                    const avgRemoteRTT = this._calculateAvgRemoteRTT();
267
+                    const avgLocalRTT = this._avgRTT.calculate();
241 268
 
242
-                        Object.assign(reportValue, props);
269
+                    this._avgEnd2EndRTT = avgLocalRTT + avgRemoteRTT;
243 270
 
271
+                    if (!isNaN(avgLocalRTT) && !isNaN(avgRemoteRTT)) {
244 272
                         // eslint-disable-next-line dot-notation
245
-                        batchReport['stat_avg_end2endrtt'] = reportValue;
273
+                        batchReport['stat_avg_end2endrtt'] = {
274
+                            value: this._avgEnd2EndRTT
275
+                        };
246 276
                     }
247 277
                 }
248 278
 
@@ -317,13 +347,16 @@ class ConnectionAvgStats {
317 347
      *
318 348
      */
319 349
     dispose() {
320
-        this._conference.statistics.removeConnectionStatsListener(
350
+
351
+        const conference = this._avgRtpStatsReporter._conference;
352
+
353
+        conference.statistics.removeConnectionStatsListener(
321 354
             this._onConnectionStats);
322 355
         if (!this.isP2P) {
323
-            this._conference.off(
356
+            conference.off(
324 357
                 ConnectionQualityEvents.REMOTE_STATS_UPDATED,
325 358
                 this._onRemoteStatsUpdated);
326
-            this._conference.off(
359
+            conference.off(
327 360
                 ConferenceEvents.USER_LEFT,
328 361
                 this._onUserLeft);
329 362
         }
@@ -519,10 +552,10 @@ export default class AvgRTPStatsReporter {
519 552
             this._onJvb121StatusChanged);
520 553
 
521 554
         this.jvbStatsMonitor
522
-            = new ConnectionAvgStats(conference, false /* JVB */, n);
555
+            = new ConnectionAvgStats(this, false /* JVB */, n);
523 556
 
524 557
         this.p2pStatsMonitor
525
-            = new ConnectionAvgStats(conference, true /* P2P */, n);
558
+            = new ConnectionAvgStats(this, true /* P2P */, n);
526 559
     }
527 560
 
528 561
     /**
@@ -533,13 +566,14 @@ export default class AvgRTPStatsReporter {
533 566
      */
534 567
     _calculateAvgStats(data) {
535 568
 
569
+        if (!data) {
570
+            logger.error('No stats');
571
+
572
+            return;
573
+        }
574
+
536 575
         const isP2P = this._conference.isP2PActive();
537 576
         const confSize = this._conference.getParticipantCount();
538
-        const props = {
539
-            relayed: data.relayed,
540
-            p2p: isP2P,
541
-            size: confSize
542
-        };
543 577
 
544 578
         if (!isP2P && confSize < 2) {
545 579
 
@@ -556,12 +590,6 @@ export default class AvgRTPStatsReporter {
556 590
             }
557 591
         } */
558 592
 
559
-        if (!data) {
560
-            logger.error('No stats');
561
-
562
-            return;
563
-        }
564
-
565 593
         const bitrate = data.bitrate;
566 594
         const bandwidth = data.bandwidth;
567 595
         const packetLoss = data.packetLoss;
@@ -621,32 +649,44 @@ export default class AvgRTPStatsReporter {
621 649
         this._sampleIdx += 1;
622 650
 
623 651
         if (this._sampleIdx >= this._n) {
624
-            const batchReport = { };
625 652
 
626
-            this._avgAudioBitrateUp.appendReport(batchReport, props);
627
-            this._avgAudioBitrateDown.appendReport(batchReport, props);
653
+            const batchReport = {
654
+                p2p: isP2P,
655
+                size: confSize
656
+            };
657
+
658
+            if (data.transport && data.transport.length) {
659
+                Object.assign(batchReport, {
660
+                    localCandidateType: data.transport[0].localCandidateType,
661
+                    remoteCandidateType: data.transport[0].remoteCandidateType,
662
+                    transportType: data.transport[0].type
663
+                });
664
+            }
665
+
666
+            this._avgAudioBitrateUp.appendReport(batchReport);
667
+            this._avgAudioBitrateDown.appendReport(batchReport);
628 668
 
629
-            this._avgVideoBitrateUp.appendReport(batchReport, props);
630
-            this._avgVideoBitrateDown.appendReport(batchReport, props);
669
+            this._avgVideoBitrateUp.appendReport(batchReport);
670
+            this._avgVideoBitrateDown.appendReport(batchReport);
631 671
 
632 672
             if (RTCBrowserType.supportsBandwidthStatistics()) {
633
-                this._avgBandwidthUp.appendReport(batchReport, props);
634
-                this._avgBandwidthDown.appendReport(batchReport, props);
673
+                this._avgBandwidthUp.appendReport(batchReport);
674
+                this._avgBandwidthDown.appendReport(batchReport);
635 675
             }
636
-            this._avgPacketLossUp.appendReport(batchReport, props);
637
-            this._avgPacketLossDown.appendReport(batchReport, props);
638
-            this._avgPacketLossTotal.appendReport(batchReport, props);
676
+            this._avgPacketLossUp.appendReport(batchReport);
677
+            this._avgPacketLossDown.appendReport(batchReport);
678
+            this._avgPacketLossTotal.appendReport(batchReport);
639 679
 
640
-            this._avgRemoteFPS.appendReport(batchReport, props);
680
+            this._avgRemoteFPS.appendReport(batchReport);
641 681
             if (!isNaN(this._avgRemoteScreenFPS.calculate())) {
642
-                this._avgRemoteScreenFPS.appendReport(batchReport, props);
682
+                this._avgRemoteScreenFPS.appendReport(batchReport);
643 683
             }
644
-            this._avgLocalFPS.appendReport(batchReport, props);
684
+            this._avgLocalFPS.appendReport(batchReport);
645 685
             if (!isNaN(this._avgLocalScreenFPS.calculate())) {
646
-                this._avgLocalScreenFPS.appendReport(batchReport, props);
686
+                this._avgLocalScreenFPS.appendReport(batchReport);
647 687
             }
648 688
 
649
-            this._avgCQ.appendReport(batchReport, props);
689
+            this._avgCQ.appendReport(batchReport);
650 690
 
651 691
             Statistics.analytics.sendEvent(AVG_RTP_STATS_EVENT, batchReport);
652 692
 

+ 17
- 36
modules/statistics/RTPStatsCollector.js 查看文件

@@ -46,7 +46,9 @@ KEYS_BY_BROWSER_TYPE[RTCBrowserType.RTC_BROWSER_CHROME] = {
46 46
     'googFrameRateSent': 'googFrameRateSent',
47 47
     'audioInputLevel': 'audioInputLevel',
48 48
     'audioOutputLevel': 'audioOutputLevel',
49
-    'currentRoundTripTime': 'googRtt'
49
+    'currentRoundTripTime': 'googRtt',
50
+    'remoteCandidateType': 'googRemoteCandidateType',
51
+    'localCandidateType': 'googLocalCandidateType'
50 52
 };
51 53
 KEYS_BY_BROWSER_TYPE[RTCBrowserType.RTC_BROWSER_EDGE] = {
52 54
     'sendBandwidth': 'googAvailableSendBandwidth',
@@ -453,33 +455,6 @@ StatsCollector.prototype.getNonNegativeStat = function(report, name) {
453 455
     return Math.max(0, value);
454 456
 };
455 457
 
456
-/**
457
- * Determines whether the local ICE candidate address is a relayed one.
458
- *
459
- * @param {TraceablePeerConnection} rtcPeerConnection the peer connection that
460
- * has the local ICE candidate address.
461
- * @param {Array} localAddressArray an array in the form
462
- * [ ip address, port ].
463
- * @return {boolean} true if the local ICE candidate is a relayed one, otherwise
464
- * false.
465
- */
466
-function isRelayed(rtcPeerConnection, localAddressArray) {
467
-    const localSdpLines
468
-        = rtcPeerConnection.localDescription.sdp.match(/[^\r\n]+/g);
469
-
470
-    for (const idx in localSdpLines) {
471
-        if (localSdpLines[idx].indexOf(localAddressArray[0])
472
-            && localSdpLines[idx].indexOf(localAddressArray[1])) {
473
-            return localSdpLines[idx].indexOf('relay') !== -1;
474
-        }
475
-    }
476
-
477
-    logger
478
-        .warn('The candidate address was not found in the local description.');
479
-
480
-    return false;
481
-}
482
-
483 458
 /* eslint-disable no-continue */
484 459
 
485 460
 /**
@@ -517,15 +492,20 @@ StatsCollector.prototype.processStatsReport = function() {
517 492
         } catch (e) { /* not supported*/ }
518 493
 
519 494
         if (now.type === 'googCandidatePair') {
520
-            let active, ip, localip, rtt, type;
521
-            let relayed = false;
495
+            let active, ip, localCandidateType, localip,
496
+                remoteCandidateType, rtt, type;
522 497
 
523 498
             try {
499
+                active = getStatValue(now, 'activeConnection');
500
+                if (!active) {
501
+                    continue;
502
+                }
503
+
524 504
                 ip = getStatValue(now, 'remoteAddress');
525 505
                 type = getStatValue(now, 'transportType');
526 506
                 localip = getStatValue(now, 'localAddress');
527
-                relayed = isRelayed(this.peerconnection, localip.split(':'));
528
-                active = getStatValue(now, 'activeConnection');
507
+                localCandidateType = getStatValue(now, 'localCandidateType');
508
+                remoteCandidateType = getStatValue(now, 'remoteCandidateType');
529 509
                 rtt = this.getNonNegativeStat(now, 'currentRoundTripTime');
530 510
             } catch (e) { /* not supported*/ }
531 511
             if (!ip || !type || !localip || active !== 'true') {
@@ -545,7 +525,8 @@ StatsCollector.prototype.processStatsReport = function() {
545 525
                     type,
546 526
                     localip,
547 527
                     p2p: this.peerconnection.isP2P,
548
-                    relayed,
528
+                    localCandidateType,
529
+                    remoteCandidateType,
549 530
                     rtt
550 531
                 });
551 532
             }
@@ -565,9 +546,9 @@ StatsCollector.prototype.processStatsReport = function() {
565 546
                 ip: `${remote.ipAddress}:${remote.portNumber}`,
566 547
                 type: local.transport,
567 548
                 localip: `${local.ipAddress}:${local.portNumber}`,
568
-                relayed: isRelayed(
569
-                    this.peerconnection, [ local.ipAddress, local.portNumber ]),
570
-                p2p: this.peerconnection.isP2P
549
+                p2p: this.peerconnection.isP2P,
550
+                localCandidateType: local.candidateType,
551
+                remoteCandidateType: remote.candidateType
571 552
             });
572 553
         }
573 554
 

正在加载...
取消
保存