Browse Source

Merge pull request #114 from jitsi/remove-stats-repetitions

Remove repetitions
master
Paweł Domas 9 years ago
parent
commit
803dd95c19
2 changed files with 222 additions and 167 deletions
  1. 174
    115
      modules/statistics/RTPStatsCollector.js
  2. 48
    52
      modules/statistics/statistics.js

+ 174
- 115
modules/statistics/RTPStatsCollector.js View File

@@ -9,8 +9,12 @@ var StatisticsEvents = require("../../service/statistics/Events");
9 9
 var browserSupported = RTCBrowserType.isChrome() ||
10 10
         RTCBrowserType.isOpera() || RTCBrowserType.isFirefox();
11 11
 
12
-var keyMap = {};
13
-keyMap[RTCBrowserType.RTC_BROWSER_FIREFOX] = {
12
+/**
13
+ * The LibJitsiMeet browser-agnostic names of the browser-specific keys reported
14
+ * by RTCPeerConnection#getStats mapped by RTCBrowserType.
15
+ */
16
+var KEYS_BY_BROWSER_TYPE = {};
17
+KEYS_BY_BROWSER_TYPE[RTCBrowserType.RTC_BROWSER_FIREFOX] = {
14 18
     "ssrc": "ssrc",
15 19
     "packetsReceived": "packetsReceived",
16 20
     "packetsLost": "packetsLost",
@@ -18,7 +22,7 @@ keyMap[RTCBrowserType.RTC_BROWSER_FIREFOX] = {
18 22
     "bytesReceived": "bytesReceived",
19 23
     "bytesSent": "bytesSent"
20 24
 };
21
-keyMap[RTCBrowserType.RTC_BROWSER_CHROME] = {
25
+KEYS_BY_BROWSER_TYPE[RTCBrowserType.RTC_BROWSER_CHROME] = {
22 26
     "receiveBandwidth": "googAvailableReceiveBandwidth",
23 27
     "sendBandwidth": "googAvailableSendBandwidth",
24 28
     "remoteAddress": "googRemoteAddress",
@@ -38,12 +42,12 @@ keyMap[RTCBrowserType.RTC_BROWSER_CHROME] = {
38 42
     "audioInputLevel": "audioInputLevel",
39 43
     "audioOutputLevel": "audioOutputLevel"
40 44
 };
41
-keyMap[RTCBrowserType.RTC_BROWSER_OPERA] =
42
-    keyMap[RTCBrowserType.RTC_BROWSER_CHROME];
43
-keyMap[RTCBrowserType.RTC_BROWSER_IEXPLORER] =
44
-    keyMap[RTCBrowserType.RTC_BROWSER_CHROME];
45
-keyMap[RTCBrowserType.RTC_BROWSER_SAFARI] =
46
-    keyMap[RTCBrowserType.RTC_BROWSER_CHROME];
45
+KEYS_BY_BROWSER_TYPE[RTCBrowserType.RTC_BROWSER_OPERA] =
46
+    KEYS_BY_BROWSER_TYPE[RTCBrowserType.RTC_BROWSER_CHROME];
47
+KEYS_BY_BROWSER_TYPE[RTCBrowserType.RTC_BROWSER_IEXPLORER] =
48
+    KEYS_BY_BROWSER_TYPE[RTCBrowserType.RTC_BROWSER_CHROME];
49
+KEYS_BY_BROWSER_TYPE[RTCBrowserType.RTC_BROWSER_SAFARI] =
50
+    KEYS_BY_BROWSER_TYPE[RTCBrowserType.RTC_BROWSER_CHROME];
47 51
 /**
48 52
  * Calculates packet lost percent using the number of lost packets and the
49 53
  * number of all packet.
@@ -57,15 +61,6 @@ function calculatePacketLoss(lostPackets, totalPackets) {
57 61
     return Math.round((lostPackets/totalPackets)*100);
58 62
 }
59 63
 
60
-function getStatValue(item, name) {
61
-    var browserType = RTCBrowserType.getBrowserType();
62
-    if (!keyMap[browserType][name])
63
-        throw "The property isn't supported!";
64
-    var key = keyMap[browserType][name];
65
-    return (RTCBrowserType.isChrome() || RTCBrowserType.isOpera()) ?
66
-        item.stat(key) : item[key];
67
-}
68
-
69 64
 function formatAudioLevel(audioLevel) {
70 65
     return Math.min(Math.max(audioLevel, 0), 1);
71 66
 }
@@ -74,10 +69,11 @@ function formatAudioLevel(audioLevel) {
74 69
  * Checks whether a certain record should be included in the logged statistics.
75 70
  */
76 71
 function acceptStat(reportId, reportType, statName) {
77
-    if (reportType == "googCandidatePair" && statName == "googChannelId")
78
-        return false;
72
+    if (reportType == "googCandidatePair") {
73
+        if (statName == "googChannelId")
74
+            return false;
79 75
 
80
-    if (reportType == "ssrc") {
76
+    } else if (reportType == "ssrc") {
81 77
         if (statName == "googTrackId" ||
82 78
             statName == "transportId" ||
83 79
             statName == "ssrc")
@@ -91,14 +87,14 @@ function acceptStat(reportId, reportType, statName) {
91 87
  * Checks whether a certain record should be included in the logged statistics.
92 88
  */
93 89
 function acceptReport(id, type) {
90
+    if (type == "googComponent")
91
+        return false;
92
+
94 93
     if (id.substring(0, 15) == "googCertificate" ||
95 94
         id.substring(0, 9) == "googTrack" ||
96 95
         id.substring(0, 20) == "googLibjingleSession")
97 96
         return false;
98 97
 
99
-    if (type == "googComponent")
100
-        return false;
101
-
102 98
     return true;
103 99
 }
104 100
 
@@ -106,8 +102,7 @@ function acceptReport(id, type) {
106 102
  * Peer statistics data holder.
107 103
  * @constructor
108 104
  */
109
-function PeerStats()
110
-{
105
+function PeerStats() {
111 106
     this.ssrc2Loss = {};
112 107
     this.ssrc2AudioLevel = {};
113 108
     this.ssrc2bitrate = {
@@ -167,7 +162,6 @@ PeerStats.prototype.setSsrcAudioLevel = function (audioLevel) {
167 162
 
168 163
 function ConferenceStats() {
169 164
 
170
-
171 165
     /**
172 166
      * The bandwidth
173 167
      * @type {{}}
@@ -186,7 +180,6 @@ function ConferenceStats() {
186 180
      */
187 181
     this.packetLoss = null;
188 182
 
189
-
190 183
     /**
191 184
      * Array with the transport information.
192 185
      * @type {Array}
@@ -201,15 +194,48 @@ function ConferenceStats() {
201 194
  * is done <tt>audioLevelsUpdateCallback</tt> is called with <tt>this</tt>
202 195
  * instance as an event source.
203 196
  *
204
- * @param peerconnection webRTC peer connection object.
205
- * @param interval stats refresh interval given in ms.
206
- * @param {function(StatsCollector)} audioLevelsUpdateCallback the callback
207
- * called on stats update.
208
- * @param config {object} supports the following properties - disableAudioLevels, disableStats, logStats
197
+ * @param peerconnection WebRTC PeerConnection object.
198
+ * @param audioLevelsInterval
199
+ * @param statsInterval stats refresh interval given in ms.
200
+ * @param eventEmitter
201
+ * @param config {object} supports the following properties: disableAudioLevels,
202
+ * disableStats, logStats
209 203
  * @constructor
210 204
  */
211
-function StatsCollector(peerconnection, audioLevelsInterval, statsInterval, eventEmitter, config)
212
-{
205
+function StatsCollector(
206
+        peerconnection,
207
+        audioLevelsInterval,
208
+        statsInterval,
209
+        eventEmitter,
210
+        config) {
211
+    // StatsCollector depends entirely on the format of the reports returned by
212
+    // RTCPeerConnection#getStats. Given that the value of
213
+    // RTCBrowserType#getBrowserType() is very unlikely to change at runtime, it
214
+    // makes sense to discover whether StatsCollector supports the executing
215
+    // browser as soon as possible. Otherwise, (1) getStatValue would have to
216
+    // needlessly check a "static" condition multiple times very very often and
217
+    // (2) the lack of support for the executing browser would be discovered and
218
+    // reported multiple times very very often too late in the execution in some
219
+    // totally unrelated callback.
220
+    /**
221
+     * The RTCBrowserType supported by this StatsCollector. In other words, the
222
+     * RTCBrowserType of the browser which initialized this StatsCollector
223
+     * instance.
224
+     * @private
225
+     */
226
+    this._browserType = RTCBrowserType.getBrowserType();
227
+    var keys = KEYS_BY_BROWSER_TYPE[this._browserType];
228
+    if (!keys)
229
+        throw "The browser type '" + this._browserType + "' isn't supported!";
230
+    /**
231
+     * The function which is to be used to retrieve the value associated in a
232
+     * report returned by RTCPeerConnection#getStats with a LibJitsiMeet
233
+     * browser-agnostic name/key.
234
+     * @function
235
+     * @private
236
+     */
237
+    this._getStatValue = this._defineGetStatValueMethod(keys);
238
+
213 239
     this.peerconnection = peerconnection;
214 240
     this.baselineAudioLevelsReport = null;
215 241
     this.currentAudioLevelsReport = null;
@@ -233,8 +259,7 @@ function StatsCollector(peerconnection, audioLevelsInterval, statsInterval, even
233 259
     /**
234 260
      * Stores the statistics which will be send to the focus to be logged.
235 261
      */
236
-    this.statsToBeLogged =
237
-    {
262
+    this.statsToBeLogged = {
238 263
         timestamps: [],
239 264
         stats: {}
240 265
     };
@@ -259,14 +284,12 @@ StatsCollector.prototype.stop = function () {
259 284
         this.audioLevelsIntervalId = null;
260 285
     }
261 286
 
262
-    if (this.statsIntervalId)
263
-    {
287
+    if (this.statsIntervalId) {
264 288
         clearInterval(this.statsIntervalId);
265 289
         this.statsIntervalId = null;
266 290
     }
267 291
 
268
-    if(this.gatherStatsIntervalId)
269
-    {
292
+    if (this.gatherStatsIntervalId) {
270 293
         clearInterval(this.gatherStatsIntervalId);
271 294
         this.gatherStatsIntervalId = null;
272 295
     }
@@ -276,8 +299,7 @@ StatsCollector.prototype.stop = function () {
276 299
  * Callback passed to <tt>getStats</tt> method.
277 300
  * @param error an error that occurred on <tt>getStats</tt> call.
278 301
  */
279
-StatsCollector.prototype.errorCallback = function (error)
280
-{
302
+StatsCollector.prototype.errorCallback = function (error) {
281 303
     logger.error("Get stats error", error);
282 304
     this.stop();
283 305
 };
@@ -285,8 +307,7 @@ StatsCollector.prototype.errorCallback = function (error)
285 307
 /**
286 308
  * Starts stats updates.
287 309
  */
288
-StatsCollector.prototype.start = function ()
289
-{
310
+StatsCollector.prototype.start = function () {
290 311
     var self = this;
291 312
     this.audioLevelsIntervalId = setInterval(
292 313
         function () {
@@ -347,8 +368,10 @@ StatsCollector.prototype.start = function ()
347 368
         );
348 369
     }
349 370
 
350
-    // logging statistics does not support firefox
351
-    if (this.config.logStats && (browserSupported && !RTCBrowserType.isFirefox())) {
371
+    if (this.config.logStats
372
+            && browserSupported
373
+            // logging statistics does not support firefox
374
+            && this._browserType !== RTCBrowserType.RTC_BROWSER_FIREFOX) {
352 375
         this.gatherStatsIntervalId = setInterval(
353 376
             function () {
354 377
                 self.peerconnection.getStats(
@@ -406,6 +429,53 @@ StatsCollector.prototype.clearCollectedStats = function () {
406 429
    this.statsToBeLogged.timestamps = [];
407 430
 };
408 431
 
432
+/**
433
+ * Defines a function which (1) is to be used as a StatsCollector method and (2)
434
+ * gets the value from a specific report returned by RTCPeerConnection#getStats
435
+ * associated with a LibJitsiMeet browser-agnostic name.
436
+ *
437
+ * @param {Object.<string,string>} keys the map of LibJitsi browser-agnostic
438
+ * names to RTCPeerConnection#getStats browser-specific keys
439
+ */
440
+StatsCollector.prototype._defineGetStatValueMethod = function (keys) {
441
+    // Define the function which converts a LibJitsiMeet browser-asnostic name
442
+    // to a browser-specific key of a report returned by
443
+    // RTCPeerConnection#getStats.
444
+    var keyFromName = function (name) {
445
+        var key = keys[name];
446
+        if (key)
447
+            return key;
448
+        else
449
+            throw "The property '" + name + "' isn't supported!";
450
+    };
451
+
452
+    // Define the function which retrieves the value from a specific report
453
+    // returned by RTCPeerConnection#getStats associated with a given
454
+    // browser-specific key.
455
+    var itemStatByKey;
456
+    switch (this._browserType) {
457
+    case RTCBrowserType.RTC_BROWSER_CHROME:
458
+    case RTCBrowserType.RTC_BROWSER_OPERA:
459
+        // TODO What about other types of browser which are based on Chrome such
460
+        // as NW.js? Every time we want to support a new type browser we have to
461
+        // go and add more conditions (here and in multiple other places).
462
+        // Cannot we do a feature detection instead of a browser type check? For
463
+        // example, if item has a stat property of type function, then it's very
464
+        // likely that whoever defined it wanted you to call it in order to
465
+        // retrieve the value associated with a specific key.
466
+        itemStatByKey = function (item, key) { return item.stat(key) };
467
+        break;
468
+    default:
469
+        itemStatByKey = function (item, key) { return item[key] };
470
+    }
471
+
472
+    // Compose the 2 functions defined above to get a function which retrieves
473
+    // the value from a specific report returned by RTCPeerConnection#getStats
474
+    // associated with a specific LibJitsiMeet browser-agnostic name.
475
+    return function (item, name) {
476
+        return itemStatByKey(item, keyFromName(name))
477
+    };
478
+};
409 479
 
410 480
 /**
411 481
  * Stats processing logic.
@@ -415,16 +485,17 @@ StatsCollector.prototype.processStatsReport = function () {
415 485
         return;
416 486
     }
417 487
 
488
+    var getStatValue = this._getStatValue;
489
+
418 490
     for (var idx in this.currentStatsReport) {
419 491
         var now = this.currentStatsReport[idx];
420 492
         try {
421
-            if (getStatValue(now, 'receiveBandwidth') ||
422
-                getStatValue(now, 'sendBandwidth')) {
493
+            var receiveBandwidth = getStatValue(now, 'receiveBandwidth');
494
+            var sendBandwidth = getStatValue(now, 'sendBandwidth');
495
+            if (receiveBandwidth || sendBandwidth) {
423 496
                 this.conferenceStats.bandwidth = {
424
-                    "download": Math.round(
425
-                            (getStatValue(now, 'receiveBandwidth')) / 1000),
426
-                    "upload": Math.round(
427
-                            (getStatValue(now, 'sendBandwidth')) / 1000)
497
+                    "download": Math.round(receiveBandwidth / 1000),
498
+                    "upload": Math.round(sendBandwidth / 1000)
428 499
                 };
429 500
             }
430 501
         }
@@ -432,42 +503,38 @@ StatsCollector.prototype.processStatsReport = function () {
432 503
 
433 504
         if(now.type == 'googCandidatePair')
434 505
         {
435
-            var ip, type, localIP, active;
506
+            var ip, type, localip, active;
436 507
             try {
437 508
                 ip = getStatValue(now, 'remoteAddress');
438 509
                 type = getStatValue(now, "transportType");
439
-                localIP = getStatValue(now, "localAddress");
510
+                localip = getStatValue(now, "localAddress");
440 511
                 active = getStatValue(now, "activeConnection");
441 512
             }
442 513
             catch(e){/*not supported*/}
443
-            if(!ip || !type || !localIP || active != "true")
514
+            if(!ip || !type || !localip || active != "true")
444 515
                 continue;
445
-            var addressSaved = false;
446
-            for(var i = 0; i < this.conferenceStats.transport.length; i++)
447
-            {
448
-                if(this.conferenceStats.transport[i].ip == ip &&
449
-                    this.conferenceStats.transport[i].type == type &&
450
-                    this.conferenceStats.transport[i].localip == localIP)
451
-                {
452
-                    addressSaved = true;
453
-                }
516
+            // Save the address unless it has been saved already.
517
+            var conferenceStatsTransport = this.conferenceStats.transport;
518
+            if(!conferenceStatsTransport.some(function (t) { return (
519
+                        t.ip == ip && t.type == type && t.localip == localip
520
+                    )})) {
521
+                conferenceStatsTransport.push(
522
+                    {ip: ip, type: type, localip: localip});
454 523
             }
455
-            if(addressSaved)
456
-                continue;
457
-            this.conferenceStats.transport.push({localip: localIP, ip: ip, type: type});
458 524
             continue;
459 525
         }
460 526
 
461
-        if(now.type == "candidatepair")
462
-        {
527
+        if(now.type == "candidatepair") {
463 528
             if(now.state == "succeeded")
464 529
                 continue;
465 530
 
466 531
             var local = this.currentStatsReport[now.localCandidateId];
467 532
             var remote = this.currentStatsReport[now.remoteCandidateId];
468
-            this.conferenceStats.transport.push({localip: local.ipAddress + ":" + local.portNumber,
469
-                ip: remote.ipAddress + ":" + remote.portNumber, type: local.transport});
470
-
533
+            this.conferenceStats.transport.push({
534
+                ip: remote.ipAddress + ":" + remote.portNumber,
535
+                type: local.transport,
536
+                localip: local.ipAddress + ":" + local.portNumber
537
+            });
471 538
         }
472 539
 
473 540
         if (now.type != 'ssrc' && now.type != "outboundrtp" &&
@@ -476,21 +543,17 @@ StatsCollector.prototype.processStatsReport = function () {
476 543
         }
477 544
 
478 545
         var before = this.baselineStatsReport[idx];
546
+        var ssrc = getStatValue(now, 'ssrc');
479 547
         if (!before) {
480
-            logger.warn(getStatValue(now, 'ssrc') + ' not enough data');
548
+            logger.warn(ssrc + ' not enough data');
481 549
             continue;
482 550
         }
483 551
 
484
-        var ssrc = getStatValue(now, 'ssrc');
485 552
         if(!ssrc)
486 553
             continue;
487 554
 
488
-        var ssrcStats = this.ssrc2stats[ssrc];
489
-        if (!ssrcStats) {
490
-            ssrcStats = new PeerStats();
491
-            this.ssrc2stats[ssrc] = ssrcStats;
492
-        }
493
-
555
+        var ssrcStats
556
+          = this.ssrc2stats[ssrc] || (this.ssrc2stats[ssrc] = new PeerStats());
494 557
 
495 558
         var isDownloadStream = true;
496 559
         var key = 'packetsReceived';
@@ -531,16 +594,15 @@ StatsCollector.prototype.processStatsReport = function () {
531 594
             isDownloadStream: isDownloadStream
532 595
         });
533 596
 
534
-
535 597
         var bytesReceived = 0, bytesSent = 0;
536
-        if(getStatValue(now, "bytesReceived")) {
537
-            bytesReceived = getStatValue(now, "bytesReceived") -
538
-                getStatValue(before, "bytesReceived");
598
+        var nowBytesTransmitted = getStatValue(now, "bytesReceived");
599
+        if(nowBytesTransmitted) {
600
+            bytesReceived
601
+                = nowBytesTransmitted - getStatValue(before, "bytesReceived");
539 602
         }
540
-
541
-        if (getStatValue(now, "bytesSent")) {
542
-            bytesSent = getStatValue(now, "bytesSent") -
543
-                getStatValue(before, "bytesSent");
603
+        nowBytesTransmitted = getStatValue(now, "bytesSent");
604
+        if (nowBytesTransmitted) {
605
+            bytesSent = nowBytesTransmitted - getStatValue(before, "bytesSent");
544 606
         }
545 607
 
546 608
         var time = Math.round((now.timestamp - before.timestamp) / 1000);
@@ -563,16 +625,16 @@ StatsCollector.prototype.processStatsReport = function () {
563 625
 
564 626
         var resolution = {height: null, width: null};
565 627
         try {
566
-            if (getStatValue(now, "googFrameHeightReceived") &&
567
-                getStatValue(now, "googFrameWidthReceived")) {
568
-                resolution.height =
569
-                    getStatValue(now, "googFrameHeightReceived");
570
-                resolution.width = getStatValue(now, "googFrameWidthReceived");
628
+            var height, width;
629
+            if ((height = getStatValue(now, "googFrameHeightReceived")) &&
630
+                (width = getStatValue(now, "googFrameWidthReceived"))) {
631
+                resolution.height = height;
632
+                resolution.width = width;
571 633
             }
572
-            else if (getStatValue(now, "googFrameHeightSent") &&
573
-                getStatValue(now, "googFrameWidthSent")) {
574
-                resolution.height = getStatValue(now, "googFrameHeightSent");
575
-                resolution.width = getStatValue(now, "googFrameWidthSent");
634
+            else if ((height = getStatValue(now, "googFrameHeightSent")) &&
635
+                (width = getStatValue(now, "googFrameWidthSent"))) {
636
+                resolution.height = height;
637
+                resolution.width = width;
576 638
             }
577 639
         }
578 640
         catch(e){/*not supported*/}
@@ -619,7 +681,8 @@ StatsCollector.prototype.processStatsReport = function () {
619 681
         this
620 682
     );
621 683
 
622
-    this.conferenceStats.bitrate = {"upload": bitrateUpload, "download": bitrateDownload};
684
+    this.conferenceStats.bitrate
685
+      = {"upload": bitrateUpload, "download": bitrateDownload};
623 686
 
624 687
     this.conferenceStats.packetLoss = {
625 688
         total:
@@ -630,8 +693,7 @@ StatsCollector.prototype.processStatsReport = function () {
630 693
         upload:
631 694
             calculatePacketLoss(lostPackets.upload, totalPackets.upload)
632 695
     };
633
-    this.eventEmitter.emit(StatisticsEvents.CONNECTION_STATS,
634
-        {
696
+    this.eventEmitter.emit(StatisticsEvents.CONNECTION_STATS, {
635 697
             "bitrate": this.conferenceStats.bitrate,
636 698
             "packetLoss": this.conferenceStats.packetLoss,
637 699
             "bandwidth": this.conferenceStats.bandwidth,
@@ -639,7 +701,6 @@ StatsCollector.prototype.processStatsReport = function () {
639 701
             "transport": this.conferenceStats.transport
640 702
         });
641 703
     this.conferenceStats.transport = [];
642
-
643 704
 };
644 705
 
645 706
 /**
@@ -650,6 +711,8 @@ StatsCollector.prototype.processAudioLevelReport = function () {
650 711
         return;
651 712
     }
652 713
 
714
+    var getStatValue = this._getStatValue;
715
+
653 716
     for (var idx in this.currentAudioLevelsReport) {
654 717
         var now = this.currentAudioLevelsReport[idx];
655 718
 
@@ -659,31 +722,27 @@ StatsCollector.prototype.processAudioLevelReport = function () {
659 722
         }
660 723
 
661 724
         var before = this.baselineAudioLevelsReport[idx];
725
+        var ssrc = getStatValue(now, 'ssrc');
662 726
         if (!before) {
663
-            logger.warn(getStatValue(now, 'ssrc') + ' not enough data');
727
+            logger.warn(ssrc + ' not enough data');
664 728
             continue;
665 729
         }
666 730
 
667
-        var ssrc = getStatValue(now, 'ssrc');
668 731
         if (!ssrc) {
669
-            if((Date.now() - now.timestamp) < 3000)
732
+            if ((Date.now() - now.timestamp) < 3000)
670 733
                 logger.warn("No ssrc: ");
671 734
             continue;
672 735
         }
673 736
 
674
-        var ssrcStats = this.ssrc2stats[ssrc];
675
-        if (!ssrcStats) {
676
-            ssrcStats = new PeerStats();
677
-            this.ssrc2stats[ssrc] = ssrcStats;
678
-        }
737
+        var ssrcStats
738
+            = this.ssrc2stats[ssrc]
739
+                || (this.ssrc2stats[ssrc] = new PeerStats());
679 740
 
680 741
         // Audio level
681
-        var audioLevel = null;
682
-
683 742
         try {
684
-            audioLevel = getStatValue(now, 'audioInputLevel');
685
-            if (!audioLevel)
686
-                audioLevel = getStatValue(now, 'audioOutputLevel');
743
+            var audioLevel
744
+                = getStatValue(now, 'audioInputLevel')
745
+                    || getStatValue(now, 'audioOutputLevel');
687 746
         }
688 747
         catch(e) {/*not supported*/
689 748
             logger.warn("Audio Levels are not available in the statistics.");

+ 48
- 52
modules/statistics/statistics.js View File

@@ -1,18 +1,19 @@
1 1
 /* global require */
2 2
 var LocalStats = require("./LocalStatsCollector.js");
3
+var logger = require("jitsi-meet-logger").getLogger(__filename);
3 4
 var RTPStats = require("./RTPStatsCollector.js");
4 5
 var EventEmitter = require("events");
5 6
 var StatisticsEvents = require("../../service/statistics/Events");
6 7
 var CallStats = require("./CallStats");
7 8
 var ScriptUtil = require('../util/ScriptUtil');
8 9
 
9
-// Since callstats.io is a third party, we cannot guarantee the quality of
10
-// their service. More specifically, their server may take noticeably long
11
-// time to respond. Consequently, it is in our best interest (in the sense
12
-// that the intergration of callstats.io is pretty important to us but not
13
-// enough to allow it to prevent people from joining a conference) to (1)
14
-// start downloading their API as soon as possible and (2) do the
15
-// downloading asynchronously.
10
+// Since callstats.io is a third party, we cannot guarantee the quality of their
11
+// service. More specifically, their server may take noticeably long time to
12
+// respond. Consequently, it is in our best interest (in the sense that the
13
+// intergration of callstats.io is pretty important to us but not enough to
14
+// allow it to prevent people from joining a conference) to (1) start
15
+// downloading their API as soon as possible and (2) do the downloading
16
+// asynchronously.
16 17
 function loadCallStatsAPI() {
17 18
     ScriptUtil.loadScript(
18 19
             'https://api.callstats.io/static/callstats.min.js',
@@ -22,14 +23,11 @@ function loadCallStatsAPI() {
22 23
     // have loaded by the time we needed it (i.e. CallStats.init is invoked).
23 24
 }
24 25
 
25
-
26 26
 /**
27 27
  * Log stats via the focus once every this many milliseconds.
28 28
  */
29 29
 var LOG_INTERVAL = 60000;
30 30
 
31
-var eventEmitter = new EventEmitter();
32
-
33 31
 function Statistics(xmpp, options) {
34 32
     this.rtpStats = null;
35 33
     this.eventEmitter = new EventEmitter();
@@ -37,17 +35,16 @@ function Statistics(xmpp, options) {
37 35
     this.options = options || {};
38 36
     this.callStatsIntegrationEnabled
39 37
         = this.options.callStatsID && this.options.callStatsSecret
40
-        // Even though AppID and AppSecret may be specified, the integration of
41
-        // callstats.io may be disabled because of globally-disallowed requests
42
-        // to any third parties.
43
-        && (this.options.disableThirdPartyRequests !== true);
38
+            // Even though AppID and AppSecret may be specified, the integration
39
+            // of callstats.io may be disabled because of globally-disallowed
40
+            // requests to any third parties.
41
+            && (this.options.disableThirdPartyRequests !== true);
44 42
     if(this.callStatsIntegrationEnabled)
45 43
         loadCallStatsAPI();
46 44
     this.callStats = null;
47 45
 
48 46
     /**
49
-     * Send the stats already saved in rtpStats to be logged via
50
-     * the focus.
47
+     * Send the stats already saved in rtpStats to be logged via the focus.
51 48
      */
52 49
     this.logStatsIntervalId = null;
53 50
 }
@@ -59,15 +56,22 @@ Statistics.prototype.startRemoteStats = function (peerconnection) {
59 56
 
60 57
     this.stopRemoteStats();
61 58
 
62
-    this.rtpStats = new RTPStats(peerconnection, 200, 2000, this.eventEmitter);
63
-    this.rtpStats.start();
64
-
65
-    this.logStatsIntervalId = setInterval(function () {
66
-        var stats = this.rtpStats.getCollectedStats();
67
-        if (this.xmpp.sendLogs(stats)) {
68
-            this.rtpStats.clearCollectedStats();
69
-        }
70
-    }.bind(this), LOG_INTERVAL);
59
+    try {
60
+        this.rtpStats
61
+            = new RTPStats(peerconnection, 200, 2000, this.eventEmitter);
62
+        this.rtpStats.start();
63
+    } catch (e) {
64
+        this.rtpStats = null;
65
+        logger.error('Failed to start collecting remote statistics: ' + e);
66
+    }
67
+    if (this.rtpStats) {
68
+        this.logStatsIntervalId = setInterval(function () {
69
+            var stats = this.rtpStats.getCollectedStats();
70
+            if (this.xmpp.sendLogs(stats)) {
71
+                this.rtpStats.clearCollectedStats();
72
+            }
73
+        }.bind(this), LOG_INTERVAL);
74
+    }
71 75
 };
72 76
 
73 77
 Statistics.localStats = [];
@@ -80,15 +84,13 @@ Statistics.startLocalStats = function (stream, callback) {
80 84
     localStats.start();
81 85
 };
82 86
 
83
-Statistics.prototype.addAudioLevelListener = function(listener)
84
-{
87
+Statistics.prototype.addAudioLevelListener = function(listener) {
85 88
     if(!Statistics.audioLevelsEnabled)
86 89
         return;
87 90
     this.eventEmitter.on(StatisticsEvents.AUDIO_LEVEL, listener);
88 91
 };
89 92
 
90
-Statistics.prototype.removeAudioLevelListener = function(listener)
91
-{
93
+Statistics.prototype.removeAudioLevelListener = function(listener) {
92 94
     if(!Statistics.audioLevelsEnabled)
93 95
         return;
94 96
     this.eventEmitter.removeListener(StatisticsEvents.AUDIO_LEVEL, listener);
@@ -108,13 +110,9 @@ Statistics.prototype.dispose = function () {
108 110
         this.stopRemoteStats();
109 111
         if(this.eventEmitter)
110 112
             this.eventEmitter.removeAllListeners();
111
-
112
-        if(eventEmitter)
113
-            eventEmitter.removeAllListeners();
114 113
     }
115 114
 };
116 115
 
117
-
118 116
 Statistics.stopAllLocalStats = function () {
119 117
     if(!Statistics.audioLevelsEnabled)
120 118
         return;
@@ -180,7 +178,7 @@ Statistics.prototype.isCallstatsEnabled = function () {
180 178
  * @param {RTCPeerConnection} pc connection on which failure occured.
181 179
  */
182 180
 Statistics.prototype.sendIceConnectionFailedEvent = function (pc) {
183
-    if(this.callStatsIntegrationEnabled && this.callstats)
181
+    if(this.callstats)
184 182
         this.callstats.sendIceConnectionFailedEvent(pc, this.callstats);
185 183
 };
186 184
 
@@ -190,7 +188,7 @@ Statistics.prototype.sendIceConnectionFailedEvent = function (pc) {
190 188
  * @param type {String} "audio"/"video"
191 189
  */
192 190
 Statistics.prototype.sendMuteEvent = function (muted, type) {
193
-    if(this.callStatsIntegrationEnabled)
191
+    if(this.callstats)
194 192
         CallStats.sendMuteEvent(muted, type, this.callstats);
195 193
 };
196 194
 
@@ -200,7 +198,7 @@ Statistics.prototype.sendMuteEvent = function (muted, type) {
200 198
  * false for not stopping
201 199
  */
202 200
 Statistics.prototype.sendScreenSharingEvent = function (start) {
203
-    if(this.callStatsIntegrationEnabled)
201
+    if(this.callstats)
204 202
         CallStats.sendScreenSharingEvent(start, this.callstats);
205 203
 };
206 204
 
@@ -209,7 +207,7 @@ Statistics.prototype.sendScreenSharingEvent = function (start) {
209 207
  * conference.
210 208
  */
211 209
 Statistics.prototype.sendDominantSpeakerEvent = function () {
212
-    if(this.callStatsIntegrationEnabled)
210
+    if(this.callstats)
213 211
         CallStats.sendDominantSpeakerEvent(this.callstats);
214 212
 };
215 213
 
@@ -226,7 +224,7 @@ Statistics.prototype.sendDominantSpeakerEvent = function () {
226 224
  */
227 225
 Statistics.prototype.associateStreamWithVideoTag =
228 226
 function (ssrc, isLocal, usageLabel, containerId) {
229
-    if(this.callStatsIntegrationEnabled && this.callstats) {
227
+    if(this.callstats) {
230 228
         this.callstats.associateStreamWithVideoTag(
231 229
             ssrc, isLocal, usageLabel, containerId);
232 230
     }
@@ -238,7 +236,7 @@ function (ssrc, isLocal, usageLabel, containerId) {
238 236
  * @param {Error} e error to send
239 237
  */
240 238
 Statistics.prototype.sendGetUserMediaFailed = function (e) {
241
-    if(this.callStatsIntegrationEnabled)
239
+    if(this.callstats)
242 240
         CallStats.sendGetUserMediaFailed(e, this.callstats);
243 241
 };
244 242
 
@@ -258,7 +256,7 @@ Statistics.sendGetUserMediaFailed = function (e) {
258 256
  * @param {RTCPeerConnection} pc connection on which failure occured.
259 257
  */
260 258
 Statistics.prototype.sendCreateOfferFailed = function (e, pc) {
261
-    if(this.callStatsIntegrationEnabled)
259
+    if(this.callstats)
262 260
         CallStats.sendCreateOfferFailed(e, pc, this.callstats);
263 261
 };
264 262
 
@@ -269,7 +267,7 @@ Statistics.prototype.sendCreateOfferFailed = function (e, pc) {
269 267
  * @param {RTCPeerConnection} pc connection on which failure occured.
270 268
  */
271 269
 Statistics.prototype.sendCreateAnswerFailed = function (e, pc) {
272
-    if(this.callStatsIntegrationEnabled)
270
+    if(this.callstats)
273 271
         CallStats.sendCreateAnswerFailed(e, pc, this.callstats);
274 272
 };
275 273
 
@@ -280,7 +278,7 @@ Statistics.prototype.sendCreateAnswerFailed = function (e, pc) {
280 278
  * @param {RTCPeerConnection} pc connection on which failure occured.
281 279
  */
282 280
 Statistics.prototype.sendSetLocalDescFailed = function (e, pc) {
283
-    if(this.callStatsIntegrationEnabled)
281
+    if(this.callstats)
284 282
         CallStats.sendSetLocalDescFailed(e, pc, this.callstats);
285 283
 };
286 284
 
@@ -291,7 +289,7 @@ Statistics.prototype.sendSetLocalDescFailed = function (e, pc) {
291 289
  * @param {RTCPeerConnection} pc connection on which failure occured.
292 290
  */
293 291
 Statistics.prototype.sendSetRemoteDescFailed = function (e, pc) {
294
-    if(this.callStatsIntegrationEnabled)
292
+    if(this.callstats)
295 293
         CallStats.sendSetRemoteDescFailed(e, pc, this.callstats);
296 294
 };
297 295
 
@@ -302,7 +300,7 @@ Statistics.prototype.sendSetRemoteDescFailed = function (e, pc) {
302 300
  * @param {RTCPeerConnection} pc connection on which failure occured.
303 301
  */
304 302
 Statistics.prototype.sendAddIceCandidateFailed = function (e, pc) {
305
-    if(this.callStatsIntegrationEnabled)
303
+    if(this.callstats)
306 304
         CallStats.sendAddIceCandidateFailed(e, pc, this.callstats);
307 305
 };
308 306
 
@@ -313,7 +311,7 @@ Statistics.prototype.sendAddIceCandidateFailed = function (e, pc) {
313 311
  * @param {RTCPeerConnection} pc connection on which failure occured.
314 312
  */
315 313
 Statistics.prototype.sendUnhandledError = function (e) {
316
-    if(this.callStatsIntegrationEnabled)
314
+    if(this.callstats)
317 315
         CallStats.sendUnhandledError(e, this.callstats);
318 316
 };
319 317
 
@@ -329,14 +327,12 @@ Statistics.sendUnhandledError = function (e) {
329 327
 /**
330 328
  * Sends the given feedback through CallStats.
331 329
  *
332
- * @param overallFeedback an integer between 1 and 5 indicating the
333
- * user feedback
334
- * @param detailedFeedback detailed feedback from the user. Not yet used
330
+ * @param overall an integer between 1 and 5 indicating the user feedback
331
+ * @param detailed detailed feedback from the user. Not yet used
335 332
  */
336
-Statistics.prototype.sendFeedback =
337
-function(overallFeedback, detailedFeedback){
338
-    if(this.callStatsIntegrationEnabled && this.callstats)
339
-        this.callstats.sendFeedback(overallFeedback, detailedFeedback);
333
+Statistics.prototype.sendFeedback = function(overall, detailed) {
334
+    if(this.callstats)
335
+        this.callstats.sendFeedback(overall, detailed);
340 336
 };
341 337
 
342 338
 Statistics.LOCAL_JID = require("../../service/statistics/constants").LOCAL_JID;

Loading…
Cancel
Save