瀏覽代碼

Merge pull request #201 from jitsi/analytics-move

Analytics move
master
George Politis 9 年之前
父節點
當前提交
d196b8344a

+ 3
- 0
JitsiConference.js 查看文件

@@ -8,6 +8,7 @@ var JitsiConferenceEvents = require("./JitsiConferenceEvents");
8 8
 var JitsiConferenceErrors = require("./JitsiConferenceErrors");
9 9
 var JitsiParticipant = require("./JitsiParticipant");
10 10
 var Statistics = require("./modules/statistics/statistics");
11
+var AnalyticsAdapter = require("./modules/statistics/AnalyticsAdapter");
11 12
 var JitsiDTMFManager = require('./modules/DTMF/JitsiDTMFManager');
12 13
 var JitsiTrackEvents = require("./JitsiTrackEvents");
13 14
 var JitsiTrackErrors = require("./JitsiTrackErrors");
@@ -786,6 +787,8 @@ function (jingleSession, jingleOffer, now) {
786 787
     // Accept incoming call
787 788
     this.room.setJingleSession(jingleSession);
788 789
     this.room.connectionTimes["session.initiate"] = now;
790
+    AnalyticsAdapter.sendEvent("muc.idle",
791
+        (now - this.room.connectionTimes["muc.joined"]));
789 792
     try{
790 793
         jingleSession.initialize(false /* initiator */,this.room);
791 794
     } catch (error) {

+ 24
- 0
JitsiConferenceEventManager.js 查看文件

@@ -8,6 +8,7 @@ var JitsiConferenceErrors = require("./JitsiConferenceErrors");
8 8
 var AuthenticationEvents =
9 9
     require("./service/authentication/AuthenticationEvents");
10 10
 var Statistics = require("./modules/statistics/statistics");
11
+var AnalyticsAdapter = require("./modules/statistics/AnalyticsAdapter");
11 12
 var MediaType = require("./service/RTC/MediaType");
12 13
 
13 14
 /**
@@ -92,6 +93,19 @@ JitsiConferenceEventManager.prototype.setupChatRoomListeners = function () {
92 93
 
93 94
     this.chatRoomForwarder.forward(XMPPEvents.MUC_JOINED,
94 95
         JitsiConferenceEvents.CONFERENCE_JOINED);
96
+    // send some analytics events
97
+    chatRoom.addListener(XMPPEvents.MUC_JOINED,
98
+        function ()
99
+        {
100
+            for (var ckey in chatRoom.connectionTimes){
101
+                var cvalue = chatRoom.connectionTimes[ckey];
102
+                AnalyticsAdapter.sendEvent('conference.' + ckey, cvalue);
103
+            }
104
+            for (var xkey in chatRoom.xmpp.connectionTimes){
105
+                var xvalue = chatRoom.xmpp.connectionTimes[xkey];
106
+                AnalyticsAdapter.sendEvent('xmpp.' + xkey, xvalue);
107
+            }
108
+        });
95 109
 
96 110
     this.chatRoomForwarder.forward(XMPPEvents.ROOM_JOIN_ERROR,
97 111
         JitsiConferenceEvents.CONFERENCE_FAILED,
@@ -116,6 +130,10 @@ JitsiConferenceEventManager.prototype.setupChatRoomListeners = function () {
116 130
     this.chatRoomForwarder.forward(XMPPEvents.BRIDGE_DOWN,
117 131
         JitsiConferenceEvents.CONFERENCE_FAILED,
118 132
         JitsiConferenceErrors.VIDEOBRIDGE_NOT_AVAILABLE);
133
+    chatRoom.addListener(XMPPEvents.BRIDGE_DOWN,
134
+        function (){
135
+            AnalyticsAdapter.sendEvent('conference.bridgeDown');
136
+        });
119 137
 
120 138
     this.chatRoomForwarder.forward(XMPPEvents.RESERVATION_ERROR,
121 139
         JitsiConferenceEvents.CONFERENCE_FAILED,
@@ -153,6 +171,7 @@ JitsiConferenceEventManager.prototype.setupChatRoomListeners = function () {
153 171
 
154 172
     chatRoom.addListener(XMPPEvents.FOCUS_LEFT,
155 173
         function () {
174
+            AnalyticsAdapter.sendEvent('conference.focusLeft');
156 175
             if(!conference.connection._reload())
157 176
                 conference.eventEmitter.emit(
158 177
                     JitsiConferenceEvents.CONFERENCE_FAILED,
@@ -166,6 +185,10 @@ JitsiConferenceEventManager.prototype.setupChatRoomListeners = function () {
166 185
 
167 186
     this.chatRoomForwarder.forward(XMPPEvents.CONNECTION_INTERRUPTED,
168 187
         JitsiConferenceEvents.CONNECTION_INTERRUPTED);
188
+    chatRoom.addListener(XMPPEvents.CONNECTION_INTERRUPTED,
189
+        function () {
190
+            AnalyticsAdapter.sendEvent('connection.interrupted');
191
+        });
169 192
 
170 193
     this.chatRoomForwarder.forward(XMPPEvents.RECORDER_STATE_CHANGED,
171 194
         JitsiConferenceEvents.RECORDER_STATE_CHANGED);
@@ -428,6 +451,7 @@ JitsiConferenceEventManager.prototype.setupRTCListeners = function () {
428 451
         var now = window.performance.now();
429 452
         logger.log("(TIME) data channel opened ", now);
430 453
         conference.room.connectionTimes["data.channel.opened"] = now;
454
+        AnalyticsAdapter.sendEvent('conference.dataChannel.open', now);
431 455
     });
432 456
 
433 457
     this.rtcForwarder.forward(RTCEvents.LASTN_CHANGED,

+ 12
- 0
JitsiConnection.js 查看文件

@@ -2,6 +2,7 @@ var JitsiConference = require("./JitsiConference");
2 2
 var XMPP = require("./modules/xmpp/xmpp");
3 3
 var JitsiConnectionEvents = require("./JitsiConnectionEvents");
4 4
 var JitsiConnectionErrors = require("./JitsiConnectionErrors");
5
+var AnalyticsAdapter = require("./modules/statistics/AnalyticsAdapter");
5 6
 
6 7
 /**
7 8
  * Creates new connection object for the Jitsi Meet server side video conferencing service. Provides access to the
@@ -25,12 +26,22 @@ function JitsiConnection(appID, token, options) {
25 26
 
26 27
     this.addEventListener(JitsiConnectionEvents.CONNECTION_FAILED,
27 28
         function (errType, msg) {
29
+            AnalyticsAdapter.sendEvent('connection.failed.' + errType);
28 30
             if(errType === JitsiConnectionErrors.OTHER_ERROR &&
29 31
                 (msg === "item-not-found" || msg === "host-unknown")) {
30 32
                     // FIXME: don't report the error if we are going to reload
31 33
                     this._reload();
32 34
                 }
33 35
         }.bind(this));
36
+
37
+    this.addEventListener(JitsiConnectionEvents.CONNECTION_DISCONNECTED,
38
+        function (msg) {
39
+            // we can see disconnects from normal tab closing of the browser
40
+            // and then there are no msgs, but we want to log only disconnects
41
+            // when there is real error
42
+            if(msg)
43
+                AnalyticsAdapter.sendEvent('connection.disconnected.' + msg);
44
+        });
34 45
 }
35 46
 
36 47
 /**
@@ -62,6 +73,7 @@ JitsiConnection.prototype.attach = function (options) {
62 73
 JitsiConnection.prototype._reload = function () {
63 74
     if(this.retryOnFail === 0)
64 75
         return false;
76
+    AnalyticsAdapter.sendEvent('connection.reload');
65 77
     this.retryOnFail--;
66 78
     var states = {};
67 79
     for(var name in this.conferences) {

+ 3
- 8
JitsiMeetJS.js 查看文件

@@ -16,6 +16,7 @@ var MediaType = require("./service/RTC/MediaType");
16 16
 var RTC = require("./modules/RTC/RTC");
17 17
 var RTCUIHelper = require("./modules/RTC/RTCUIHelper");
18 18
 var Statistics = require("./modules/statistics/statistics");
19
+var AnalyticsAdapter = require("./modules/statistics/AnalyticsAdapter");
19 20
 var Resolutions = require("./service/RTC/Resolutions");
20 21
 var ScriptUtil = require("./modules/util/ScriptUtil");
21 22
 var GlobalOnErrorHandler = require("./modules/util/GlobalOnErrorHandler");
@@ -66,6 +67,7 @@ var LibJitsiMeet = {
66 67
     },
67 68
     logLevels: Logger.levels,
68 69
     mediaDevices: JitsiMediaDevices,
70
+    analytics: AnalyticsAdapter,
69 71
     init: function (options) {
70 72
         var logObject, attr;
71 73
         Statistics.audioLevelsEnabled = !options.disableAudioLevels;
@@ -137,16 +139,9 @@ var LibJitsiMeet = {
137 139
         if (firePermissionPromptIsShownEvent === true) {
138 140
             window.setTimeout(function () {
139 141
                 if (!promiseFulfilled) {
140
-                    var browser = RTCBrowserType.getBrowserType()
141
-                        .split('rtc_browser.')[1];
142
-
143
-                    if (RTCBrowserType.isAndroid()) {
144
-                        browser = 'android';
145
-                    }
146
-
147 142
                     JitsiMediaDevices.emitEvent(
148 143
                         JitsiMediaDevicesEvents.PERMISSION_PROMPT_IS_SHOWN,
149
-                        browser);
144
+                        RTCBrowserType.getBrowserName());
150 145
                 }
151 146
             }, USER_MEDIA_PERMISSION_PROMPT_TIMEOUT);
152 147
         }

+ 40
- 0
modules/RTC/JitsiRemoteTrack.js 查看文件

@@ -1,5 +1,10 @@
1 1
 var JitsiTrack = require("./JitsiTrack");
2 2
 var JitsiTrackEvents = require("../../JitsiTrackEvents");
3
+var RTCBrowserType = require("./RTCBrowserType");
4
+var AnalyticsAdapter = require("../statistics/AnalyticsAdapter");
5
+
6
+var ttfmTrackerAudioAttached = false;
7
+var ttfmTrackerVideoAttached = false;
3 8
 
4 9
 /**
5 10
  * Represents a single media track (either audio or video).
@@ -84,4 +89,39 @@ JitsiRemoteTrack.prototype._setVideoType = function (type) {
84 89
     this.eventEmitter.emit(JitsiTrackEvents.TRACK_VIDEOTYPE_CHANGED, type);
85 90
 };
86 91
 
92
+/**
93
+ * Attach time to first media tracker only if there is conference and only
94
+ * for the first element.
95
+ * @param container the HTML container which can be 'video' or 'audio' element.
96
+ *        It can also be 'object' element if Temasys plugin is in use and this
97
+ *        method has been called previously on video or audio HTML element.
98
+ * @private
99
+ */
100
+JitsiRemoteTrack.prototype._attachTTFMTracker = function (container) {
101
+    if((ttfmTrackerAudioAttached && this.isAudioTrack())
102
+        || (ttfmTrackerVideoAttached && this.isVideoTrack()))
103
+        return;
104
+
105
+    if (this.isAudioTrack())
106
+        ttfmTrackerAudioAttached = true;
107
+    if (this.isVideoTrack())
108
+        ttfmTrackerVideoAttached = true;
109
+
110
+    // FIXME: this is not working for temasys
111
+    container.addEventListener("canplay", function () {
112
+        var type = (this.isVideoTrack() ? 'video' : 'audio');
113
+
114
+        var now = window.performance.now();
115
+        console.log("(TIME) Render " + type + ":\t", now);
116
+        this.conference.getConnectionTimes()[type + ".render"] = now;
117
+
118
+        var ttfm = now
119
+            - (this.conference.getConnectionTimes()["session.initiate"]
120
+            - this.conference.getConnectionTimes()["muc.joined"]);
121
+        this.conference.getConnectionTimes()[type + ".ttfm"] = ttfm;
122
+        console.log("(TIME) TTFM " + type + ":\t", ttfm);
123
+        AnalyticsAdapter.sendEvent(type +'.ttfm', ttfm);
124
+    }.bind(this));
125
+};
126
+
87 127
 module.exports = JitsiRemoteTrack;

+ 13
- 0
modules/RTC/JitsiTrack.js 查看文件

@@ -189,6 +189,8 @@ JitsiTrack.prototype.attach = function (container) {
189 189
 
190 190
     this._maybeFireTrackAttached(container);
191 191
 
192
+    this._attachTTFMTracker(container);
193
+
192 194
     return container;
193 195
 };
194 196
 
@@ -216,6 +218,17 @@ JitsiTrack.prototype.detach = function (container) {
216 218
     }
217 219
 };
218 220
 
221
+/**
222
+ * Attach time to first media tracker only if there is conference and only
223
+ * for the first element.
224
+ * @param container the HTML container which can be 'video' or 'audio' element.
225
+ *        It can also be 'object' element if Temasys plugin is in use and this
226
+ *        method has been called previously on video or audio HTML element.
227
+ * @private
228
+ */
229
+JitsiTrack.prototype._attachTTFMTracker = function (container) {
230
+};
231
+
219 232
 /**
220 233
  * Removes attached event listeners.
221 234
  *

+ 12
- 0
modules/RTC/RTCBrowserType.js 查看文件

@@ -30,6 +30,18 @@ var RTCBrowserType = {
30 30
         return currentBrowser;
31 31
     },
32 32
 
33
+    /**
34
+     * Gets current browser name, split from the type.
35
+     * @returns {string}
36
+     */
37
+    getBrowserName: function () {
38
+        var browser = currentBrowser.split('rtc_browser.')[1];
39
+        if (RTCBrowserType.isAndroid()) {
40
+            browser = 'android';
41
+        }
42
+        return browser;
43
+    },
44
+
33 45
     /**
34 46
      * Checks if current browser is Chrome.
35 47
      * @returns {boolean}

+ 30
- 0
modules/statistics/AnalyticsAdapter.js 查看文件

@@ -0,0 +1,30 @@
1
+var RTCBrowserType = require("../RTC/RTCBrowserType");
2
+
3
+function NoopAnalytics() {}
4
+NoopAnalytics.prototype.sendEvent = function () {};
5
+
6
+// XXX Since we asynchronously load the integration of the analytics API and the
7
+// analytics API may asynchronously load its implementation (e.g. Google
8
+// Analytics), we cannot make the decision with respect to which analytics
9
+// implementation we will use here and we have to postpone it i.e. we will make
10
+// a lazy decision.
11
+
12
+function AnalyticsAdapter() {
13
+    this.browserActionSuffix = '.' + RTCBrowserType.getBrowserName();
14
+}
15
+
16
+AnalyticsAdapter.prototype.sendEvent = function (action, data)
17
+{
18
+    var a = this.analytics;
19
+
20
+    if (a === null || typeof a === 'undefined') {
21
+        var AnalyticsImpl = window.Analytics || NoopAnalytics;
22
+
23
+        this.analytics = a = new AnalyticsImpl();
24
+    }
25
+    try {
26
+        a.sendEvent(action + this.browserActionSuffix, data);
27
+    } catch (ignored) {}
28
+};
29
+
30
+module.exports = new AnalyticsAdapter();

+ 3
- 0
modules/xmpp/JingleSessionPC.js 查看文件

@@ -12,6 +12,7 @@ var XMPPEvents = require("../../service/xmpp/XMPPEvents");
12 12
 var RTCBrowserType = require("../RTC/RTCBrowserType");
13 13
 var RTC = require("../RTC/RTC");
14 14
 var GlobalOnErrorHandler = require("../util/GlobalOnErrorHandler");
15
+var AnalyticsAdapter = require("../statistics/AnalyticsAdapter");
15 16
 
16 17
 /**
17 18
  * Constant tells how long we're going to wait for IQ response, before timeout
@@ -132,6 +133,8 @@ JingleSessionPC.prototype.doInitialize = function () {
132 133
             self.peerconnection.iceConnectionState] = now;
133 134
         logger.log("(TIME) ICE " + self.peerconnection.iceConnectionState +
134 135
                     ":\t", now);
136
+        AnalyticsAdapter.sendEvent(
137
+            'ice.' + self.peerconnection.iceConnectionState, now);
135 138
         switch (self.peerconnection.iceConnectionState) {
136 139
             case 'connected':
137 140
 

+ 11
- 5
modules/xmpp/strophe.jingle.js 查看文件

@@ -6,7 +6,7 @@ var JingleSession = require("./JingleSessionPC");
6 6
 var XMPPEvents = require("../../service/xmpp/XMPPEvents");
7 7
 var RTCBrowserType = require("../RTC/RTCBrowserType");
8 8
 var GlobalOnErrorHandler = require("../util/GlobalOnErrorHandler");
9
-
9
+var AnalyticsAdapter = require("../statistics/AnalyticsAdapter");
10 10
 
11 11
 module.exports = function(XMPP, eventEmitter) {
12 12
     Strophe.addConnectionPlugin('jingle', {
@@ -101,6 +101,7 @@ module.exports = function(XMPP, eventEmitter) {
101 101
                             .up();
102 102
                         this.terminate(sess.sid);
103 103
                     }
104
+                    AnalyticsAdapter.sendEvent('xmpp.session-initiate', now);
104 105
                     break;
105 106
                 case 'session-terminate':
106 107
                     logger.log('terminating...', sess.sid);
@@ -114,13 +115,18 @@ module.exports = function(XMPP, eventEmitter) {
114 115
                     this.terminate(sess.sid, reasonCondition, reasonText);
115 116
                     break;
116 117
                 case 'transport-replace':
117
-                    logger.info("(TIME) Start transport replace",
118
-                                window.performance.now());
118
+                    var now = window.performance.now();
119
+                    logger.info("(TIME) Start transport replace", now);
120
+                    AnalyticsAdapter.sendEvent(
121
+                        'xmpp.transport-replace.start', now);
122
+
119 123
                     sess.replaceTransport($(iq).find('>jingle'),
120 124
                         function () {
125
+                            var now = window.performance.now();
121 126
                             logger.info(
122
-                                "(TIME) Transport replace success!",
123
-                                window.performance.now());
127
+                                "(TIME) Transport replace success!", now);
128
+                            AnalyticsAdapter.sendEvent(
129
+                                'xmpp.transport-replace.success', now);
124 130
                         },
125 131
                         function(error) {
126 132
                             GlobalOnErrorHandler.callErrorHandler(error);

Loading…
取消
儲存