Bläddra i källkod

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

master
George Politis 8 år sedan
förälder
incheckning
0ff967cbc4
2 ändrade filer med 116 tillägg och 95 borttagningar
  1. 99
    59
      modules/statistics/AvgRTPStatsReporter.js
  2. 17
    36
      modules/statistics/RTPStatsCollector.js

+ 99
- 59
modules/statistics/AvgRTPStatsReporter.js Visa fil

17
  *
17
  *
18
  * {
18
  * {
19
  *   p2p: true,
19
  *   p2p: true,
20
- *   conferenceSize: 1,
21
- *   relayed: true,
20
+ *   conferenceSize: 2,
21
+ *   localCandidateType: "relay",
22
+ *   remoteCandidateType: "relay",
23
+ *   transportType: "udp",
22
  *
24
  *
23
  *   "stat_avg_rtt": {
25
  *   "stat_avg_rtt": {
24
  *     value: 200,
26
  *     value: 200,
92
      * Appends the report to the analytics "data" object. The object will be
94
      * Appends the report to the analytics "data" object. The object will be
93
      * set under <tt>prefix</tt> + {@link this.name} key.
95
      * set under <tt>prefix</tt> + {@link this.name} key.
94
      * @param {Object} report the analytics "data" object
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
             value: this.calculate(),
100
             value: this.calculate(),
101
             samples: this.samples
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
 class ConnectionAvgStats {
121
 class ConnectionAvgStats {
126
     /**
122
     /**
127
      * Creates new <tt>ConnectionAvgStats</tt>
123
      * Creates new <tt>ConnectionAvgStats</tt>
128
-     * @param {JitsiConference} conference
124
+     * @param {AvgRTPStatsReporter} avgRtpStatsReporter
129
      * @param {boolean} isP2P
125
      * @param {boolean} isP2P
130
      * @param {number} n the number of samples, before arithmetic mean is to be
126
      * @param {number} n the number of samples, before arithmetic mean is to be
131
      * calculated and values submitted to the analytics module.
127
      * calculated and values submitted to the analytics module.
132
      */
128
      */
133
-    constructor(conference, isP2P, n) {
129
+    constructor(avgRtpStatsReporter, isP2P, n) {
134
         /**
130
         /**
135
          * Is this instance for JVB or P2P connection ?
131
          * Is this instance for JVB or P2P connection ?
136
          * @type {boolean}
132
          * @type {boolean}
175
          * @type {JitsiConference}
171
          * @type {JitsiConference}
176
          * @private
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
         this._onConnectionStats = (tpc, stats) => {
186
         this._onConnectionStats = (tpc, stats) => {
181
             if (this.isP2P === tpc.isP2P) {
187
             if (this.isP2P === tpc.isP2P) {
182
                 this._calculateAvgStats(stats);
188
                 this._calculateAvgStats(stats);
183
             }
189
             }
184
         };
190
         };
191
+
192
+        const conference = avgRtpStatsReporter._conference;
193
+
185
         conference.statistics.addConnectionStatsListener(
194
         conference.statistics.addConnectionStatsListener(
186
             this._onConnectionStats);
195
             this._onConnectionStats);
187
 
196
 
219
 
228
 
220
         if (this._sampleIdx >= this._n) {
229
         if (this._sampleIdx >= this._n) {
221
             if (RTCBrowserType.supportsRTTStatistics()) {
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
                     p2p: this.isP2P,
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
                         // eslint-disable-next-line dot-notation
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
      *
347
      *
318
      */
348
      */
319
     dispose() {
349
     dispose() {
320
-        this._conference.statistics.removeConnectionStatsListener(
350
+
351
+        const conference = this._avgRtpStatsReporter._conference;
352
+
353
+        conference.statistics.removeConnectionStatsListener(
321
             this._onConnectionStats);
354
             this._onConnectionStats);
322
         if (!this.isP2P) {
355
         if (!this.isP2P) {
323
-            this._conference.off(
356
+            conference.off(
324
                 ConnectionQualityEvents.REMOTE_STATS_UPDATED,
357
                 ConnectionQualityEvents.REMOTE_STATS_UPDATED,
325
                 this._onRemoteStatsUpdated);
358
                 this._onRemoteStatsUpdated);
326
-            this._conference.off(
359
+            conference.off(
327
                 ConferenceEvents.USER_LEFT,
360
                 ConferenceEvents.USER_LEFT,
328
                 this._onUserLeft);
361
                 this._onUserLeft);
329
         }
362
         }
519
             this._onJvb121StatusChanged);
552
             this._onJvb121StatusChanged);
520
 
553
 
521
         this.jvbStatsMonitor
554
         this.jvbStatsMonitor
522
-            = new ConnectionAvgStats(conference, false /* JVB */, n);
555
+            = new ConnectionAvgStats(this, false /* JVB */, n);
523
 
556
 
524
         this.p2pStatsMonitor
557
         this.p2pStatsMonitor
525
-            = new ConnectionAvgStats(conference, true /* P2P */, n);
558
+            = new ConnectionAvgStats(this, true /* P2P */, n);
526
     }
559
     }
527
 
560
 
528
     /**
561
     /**
533
      */
566
      */
534
     _calculateAvgStats(data) {
567
     _calculateAvgStats(data) {
535
 
568
 
569
+        if (!data) {
570
+            logger.error('No stats');
571
+
572
+            return;
573
+        }
574
+
536
         const isP2P = this._conference.isP2PActive();
575
         const isP2P = this._conference.isP2PActive();
537
         const confSize = this._conference.getParticipantCount();
576
         const confSize = this._conference.getParticipantCount();
538
-        const props = {
539
-            relayed: data.relayed,
540
-            p2p: isP2P,
541
-            size: confSize
542
-        };
543
 
577
 
544
         if (!isP2P && confSize < 2) {
578
         if (!isP2P && confSize < 2) {
545
 
579
 
556
             }
590
             }
557
         } */
591
         } */
558
 
592
 
559
-        if (!data) {
560
-            logger.error('No stats');
561
-
562
-            return;
563
-        }
564
-
565
         const bitrate = data.bitrate;
593
         const bitrate = data.bitrate;
566
         const bandwidth = data.bandwidth;
594
         const bandwidth = data.bandwidth;
567
         const packetLoss = data.packetLoss;
595
         const packetLoss = data.packetLoss;
621
         this._sampleIdx += 1;
649
         this._sampleIdx += 1;
622
 
650
 
623
         if (this._sampleIdx >= this._n) {
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
             if (RTCBrowserType.supportsBandwidthStatistics()) {
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
             if (!isNaN(this._avgRemoteScreenFPS.calculate())) {
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
             if (!isNaN(this._avgLocalScreenFPS.calculate())) {
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
             Statistics.analytics.sendEvent(AVG_RTP_STATS_EVENT, batchReport);
691
             Statistics.analytics.sendEvent(AVG_RTP_STATS_EVENT, batchReport);
652
 
692
 

+ 17
- 36
modules/statistics/RTPStatsCollector.js Visa fil

46
     'googFrameRateSent': 'googFrameRateSent',
46
     'googFrameRateSent': 'googFrameRateSent',
47
     'audioInputLevel': 'audioInputLevel',
47
     'audioInputLevel': 'audioInputLevel',
48
     'audioOutputLevel': 'audioOutputLevel',
48
     'audioOutputLevel': 'audioOutputLevel',
49
-    'currentRoundTripTime': 'googRtt'
49
+    'currentRoundTripTime': 'googRtt',
50
+    'remoteCandidateType': 'googRemoteCandidateType',
51
+    'localCandidateType': 'googLocalCandidateType'
50
 };
52
 };
51
 KEYS_BY_BROWSER_TYPE[RTCBrowserType.RTC_BROWSER_EDGE] = {
53
 KEYS_BY_BROWSER_TYPE[RTCBrowserType.RTC_BROWSER_EDGE] = {
52
     'sendBandwidth': 'googAvailableSendBandwidth',
54
     'sendBandwidth': 'googAvailableSendBandwidth',
453
     return Math.max(0, value);
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
 /* eslint-disable no-continue */
458
 /* eslint-disable no-continue */
484
 
459
 
485
 /**
460
 /**
517
         } catch (e) { /* not supported*/ }
492
         } catch (e) { /* not supported*/ }
518
 
493
 
519
         if (now.type === 'googCandidatePair') {
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
             try {
498
             try {
499
+                active = getStatValue(now, 'activeConnection');
500
+                if (!active) {
501
+                    continue;
502
+                }
503
+
524
                 ip = getStatValue(now, 'remoteAddress');
504
                 ip = getStatValue(now, 'remoteAddress');
525
                 type = getStatValue(now, 'transportType');
505
                 type = getStatValue(now, 'transportType');
526
                 localip = getStatValue(now, 'localAddress');
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
                 rtt = this.getNonNegativeStat(now, 'currentRoundTripTime');
509
                 rtt = this.getNonNegativeStat(now, 'currentRoundTripTime');
530
             } catch (e) { /* not supported*/ }
510
             } catch (e) { /* not supported*/ }
531
             if (!ip || !type || !localip || active !== 'true') {
511
             if (!ip || !type || !localip || active !== 'true') {
545
                     type,
525
                     type,
546
                     localip,
526
                     localip,
547
                     p2p: this.peerconnection.isP2P,
527
                     p2p: this.peerconnection.isP2P,
548
-                    relayed,
528
+                    localCandidateType,
529
+                    remoteCandidateType,
549
                     rtt
530
                     rtt
550
                 });
531
                 });
551
             }
532
             }
565
                 ip: `${remote.ipAddress}:${remote.portNumber}`,
546
                 ip: `${remote.ipAddress}:${remote.portNumber}`,
566
                 type: local.transport,
547
                 type: local.transport,
567
                 localip: `${local.ipAddress}:${local.portNumber}`,
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
 

Laddar…
Avbryt
Spara