Ver código fonte

Reduce browser type checks in statistics

dev1
Lyubomir Marinov 9 anos atrás
pai
commit
7ea29f14fb
2 arquivos alterados com 125 adições e 36 exclusões
  1. 108
    27
      modules/statistics/RTPStatsCollector.js
  2. 17
    9
      modules/statistics/statistics.js

+ 108
- 27
modules/statistics/RTPStatsCollector.js Ver arquivo

@@ -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
 }
@@ -198,15 +193,48 @@ function ConferenceStats() {
198 193
  * is done <tt>audioLevelsUpdateCallback</tt> is called with <tt>this</tt>
199 194
  * instance as an event source.
200 195
  *
201
- * @param peerconnection webRTC peer connection object.
202
- * @param interval stats refresh interval given in ms.
203
- * @param {function(StatsCollector)} audioLevelsUpdateCallback the callback
204
- * called on stats update.
205
- * @param config {object} supports the following properties - disableAudioLevels, disableStats, logStats
196
+ * @param peerconnection WebRTC PeerConnection object.
197
+ * @param audioLevelsInterval
198
+ * @param statsInterval stats refresh interval given in ms.
199
+ * @param eventEmitter
200
+ * @param config {object} supports the following properties: disableAudioLevels,
201
+ * disableStats, logStats
206 202
  * @constructor
207 203
  */
208
-function StatsCollector(peerconnection, audioLevelsInterval, statsInterval, eventEmitter, config)
209
-{
204
+function StatsCollector(
205
+        peerconnection,
206
+        audioLevelsInterval,
207
+        statsInterval,
208
+        eventEmitter,
209
+        config) {
210
+    // StatsCollector depends entirely on the format of the reports returned by
211
+    // RTCPeerConnection#getStats. Given that the value of
212
+    // RTCBrowserType#getBrowserType() is very unlikely to change at runtime, it
213
+    // makes sense to discover whether StatsCollector supports the executing
214
+    // browser as soon as possible. Otherwise, (1) getStatValue would have to
215
+    // needlessly check a "static" condition multiple times very very often and
216
+    // (2) the lack of support for the executing browser would be discovered and
217
+    // reported multiple times very very often too late in the execution in some
218
+    // totally unrelated callback.
219
+    /**
220
+     * The RTCBrowserType supported by this StatsCollector. In other words, the
221
+     * RTCBrowserType of the browser which initialized this StatsCollector
222
+     * instance.
223
+     * @private
224
+     */
225
+    this._browserType = RTCBrowserType.getBrowserType();
226
+    var keys = KEYS_BY_BROWSER_TYPE[this._browserType];
227
+    if (!keys)
228
+        throw "The browser type '" + this._browserType + "' isn't supported!";
229
+    /**
230
+     * The function which is to be used to retrieve the value associated in a
231
+     * report returned by RTCPeerConnection#getStats with a LibJitsiMeet
232
+     * browser-agnostic name/key.
233
+     * @function
234
+     * @private
235
+     */
236
+    this._getStatValue = this._defineGetStatValueMethod(keys);
237
+
210 238
     this.peerconnection = peerconnection;
211 239
     this.baselineAudioLevelsReport = null;
212 240
     this.currentAudioLevelsReport = null;
@@ -339,8 +367,10 @@ StatsCollector.prototype.start = function () {
339 367
         );
340 368
     }
341 369
 
342
-    // logging statistics does not support firefox
343
-    if (this.config.logStats && (browserSupported && !RTCBrowserType.isFirefox())) {
370
+    if (this.config.logStats
371
+            && browserSupported
372
+            // logging statistics does not support firefox
373
+            && this._browserType !== RTCBrowserType.RTC_BROWSER_FIREFOX) {
344 374
         this.gatherStatsIntervalId = setInterval(
345 375
             function () {
346 376
                 self.peerconnection.getStats(
@@ -398,6 +428,53 @@ StatsCollector.prototype.clearCollectedStats = function () {
398 428
    this.statsToBeLogged.timestamps = [];
399 429
 };
400 430
 
431
+/**
432
+ * Defines a function which (1) is to be used as a StatsCollector method and (2)
433
+ * gets the value from a specific report returned by RTCPeerConnection#getStats
434
+ * associated with a LibJitsiMeet browser-agnostic name.
435
+ *
436
+ * @param {Object.<string,string>} keys the map of LibJitsi browser-agnostic
437
+ * names to RTCPeerConnection#getStats browser-specific keys
438
+ */
439
+StatsCollector.prototype._defineGetStatValueMethod = function (keys) {
440
+    // Define the function which converts a LibJitsiMeet browser-asnostic name
441
+    // to a browser-specific key of a report returned by
442
+    // RTCPeerConnection#getStats.
443
+    var keyFromName = function (name) {
444
+        var key = keys[name];
445
+        if (key)
446
+            return key;
447
+        else
448
+            throw "The property '" + name + "' isn't supported!";
449
+    };
450
+
451
+    // Define the function which retrieves the value from a specific report
452
+    // returned by RTCPeerConnection#getStats associated with a given
453
+    // browser-specific key.
454
+    var itemStatByKey;
455
+    switch (this._browserType) {
456
+    case RTCBrowserType.RTC_BROWSER_CHROME:
457
+    case RTCBrowserType.RTC_BROWSER_OPERA:
458
+        // TODO What about other types of browser which are based on Chrome such
459
+        // as NW.js? Every time we want to support a new type browser we have to
460
+        // go and add more conditions (here and in multiple other places).
461
+        // Cannot we do a feature detection instead of a browser type check? For
462
+        // example, if item has a stat property of type function, then it's very
463
+        // likely that whoever defined it wanted you to call it in order to
464
+        // retrieve the value associated with a specific key.
465
+        itemStatByKey = function (item, key) { return item.stat(key) };
466
+        break;
467
+    default:
468
+        itemStatByKey = function (item, key) { return item[key] };
469
+    }
470
+
471
+    // Compose the 2 functions defined above to get a function which retrieves
472
+    // the value from a specific report returned by RTCPeerConnection#getStats
473
+    // associated with a specific LibJitsiMeet browser-agnostic name.
474
+    return function (item, name) {
475
+        return itemStatByKey(item, keyFromName(name))
476
+    };
477
+};
401 478
 
402 479
 /**
403 480
  * Stats processing logic.
@@ -407,6 +484,8 @@ StatsCollector.prototype.processStatsReport = function () {
407 484
         return;
408 485
     }
409 486
 
487
+    var getStatValue = this._getStatValue;
488
+
410 489
     for (var idx in this.currentStatsReport) {
411 490
         var now = this.currentStatsReport[idx];
412 491
         try {
@@ -642,6 +721,8 @@ StatsCollector.prototype.processAudioLevelReport = function () {
642 721
         return;
643 722
     }
644 723
 
724
+    var getStatValue = this._getStatValue;
725
+
645 726
     for (var idx in this.currentAudioLevelsReport) {
646 727
         var now = this.currentAudioLevelsReport[idx];
647 728
 

+ 17
- 9
modules/statistics/statistics.js Ver arquivo

@@ -1,5 +1,6 @@
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");
@@ -55,15 +56,22 @@ Statistics.prototype.startRemoteStats = function (peerconnection) {
55 56
 
56 57
     this.stopRemoteStats();
57 58
 
58
-    this.rtpStats = new RTPStats(peerconnection, 200, 2000, this.eventEmitter);
59
-    this.rtpStats.start();
60
-
61
-    this.logStatsIntervalId = setInterval(function () {
62
-        var stats = this.rtpStats.getCollectedStats();
63
-        if (this.xmpp.sendLogs(stats)) {
64
-            this.rtpStats.clearCollectedStats();
65
-        }
66
-    }.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
+    }
67 75
 };
68 76
 
69 77
 Statistics.localStats = [];

Carregando…
Cancelar
Salvar