Explorar el Código

Reduce browser type checks in statistics

dev1
Lyubomir Marinov hace 9 años
padre
commit
7ea29f14fb
Se han modificado 2 ficheros con 125 adiciones y 36 borrados
  1. 108
    27
      modules/statistics/RTPStatsCollector.js
  2. 17
    9
      modules/statistics/statistics.js

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

9
 var browserSupported = RTCBrowserType.isChrome() ||
9
 var browserSupported = RTCBrowserType.isChrome() ||
10
         RTCBrowserType.isOpera() || RTCBrowserType.isFirefox();
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
     "ssrc": "ssrc",
18
     "ssrc": "ssrc",
15
     "packetsReceived": "packetsReceived",
19
     "packetsReceived": "packetsReceived",
16
     "packetsLost": "packetsLost",
20
     "packetsLost": "packetsLost",
18
     "bytesReceived": "bytesReceived",
22
     "bytesReceived": "bytesReceived",
19
     "bytesSent": "bytesSent"
23
     "bytesSent": "bytesSent"
20
 };
24
 };
21
-keyMap[RTCBrowserType.RTC_BROWSER_CHROME] = {
25
+KEYS_BY_BROWSER_TYPE[RTCBrowserType.RTC_BROWSER_CHROME] = {
22
     "receiveBandwidth": "googAvailableReceiveBandwidth",
26
     "receiveBandwidth": "googAvailableReceiveBandwidth",
23
     "sendBandwidth": "googAvailableSendBandwidth",
27
     "sendBandwidth": "googAvailableSendBandwidth",
24
     "remoteAddress": "googRemoteAddress",
28
     "remoteAddress": "googRemoteAddress",
38
     "audioInputLevel": "audioInputLevel",
42
     "audioInputLevel": "audioInputLevel",
39
     "audioOutputLevel": "audioOutputLevel"
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
  * Calculates packet lost percent using the number of lost packets and the
52
  * Calculates packet lost percent using the number of lost packets and the
49
  * number of all packet.
53
  * number of all packet.
57
     return Math.round((lostPackets/totalPackets)*100);
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
 function formatAudioLevel(audioLevel) {
64
 function formatAudioLevel(audioLevel) {
70
     return Math.min(Math.max(audioLevel, 0), 1);
65
     return Math.min(Math.max(audioLevel, 0), 1);
71
 }
66
 }
198
  * is done <tt>audioLevelsUpdateCallback</tt> is called with <tt>this</tt>
193
  * is done <tt>audioLevelsUpdateCallback</tt> is called with <tt>this</tt>
199
  * instance as an event source.
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
  * @constructor
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
     this.peerconnection = peerconnection;
238
     this.peerconnection = peerconnection;
211
     this.baselineAudioLevelsReport = null;
239
     this.baselineAudioLevelsReport = null;
212
     this.currentAudioLevelsReport = null;
240
     this.currentAudioLevelsReport = null;
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
         this.gatherStatsIntervalId = setInterval(
374
         this.gatherStatsIntervalId = setInterval(
345
             function () {
375
             function () {
346
                 self.peerconnection.getStats(
376
                 self.peerconnection.getStats(
398
    this.statsToBeLogged.timestamps = [];
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
  * Stats processing logic.
480
  * Stats processing logic.
407
         return;
484
         return;
408
     }
485
     }
409
 
486
 
487
+    var getStatValue = this._getStatValue;
488
+
410
     for (var idx in this.currentStatsReport) {
489
     for (var idx in this.currentStatsReport) {
411
         var now = this.currentStatsReport[idx];
490
         var now = this.currentStatsReport[idx];
412
         try {
491
         try {
642
         return;
721
         return;
643
     }
722
     }
644
 
723
 
724
+    var getStatValue = this._getStatValue;
725
+
645
     for (var idx in this.currentAudioLevelsReport) {
726
     for (var idx in this.currentAudioLevelsReport) {
646
         var now = this.currentAudioLevelsReport[idx];
727
         var now = this.currentAudioLevelsReport[idx];
647
 
728
 

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

1
 /* global require */
1
 /* global require */
2
 var LocalStats = require("./LocalStatsCollector.js");
2
 var LocalStats = require("./LocalStatsCollector.js");
3
+var logger = require("jitsi-meet-logger").getLogger(__filename);
3
 var RTPStats = require("./RTPStatsCollector.js");
4
 var RTPStats = require("./RTPStatsCollector.js");
4
 var EventEmitter = require("events");
5
 var EventEmitter = require("events");
5
 var StatisticsEvents = require("../../service/statistics/Events");
6
 var StatisticsEvents = require("../../service/statistics/Events");
55
 
56
 
56
     this.stopRemoteStats();
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
 Statistics.localStats = [];
77
 Statistics.localStats = [];

Loading…
Cancelar
Guardar