Browse Source

Merge pull request #201 from jitsi/analytics-move

Analytics move
master
George Politis 9 years ago
parent
commit
d196b8344a

+ 3
- 0
JitsiConference.js View File

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

+ 24
- 0
JitsiConferenceEventManager.js View File

8
 var AuthenticationEvents =
8
 var AuthenticationEvents =
9
     require("./service/authentication/AuthenticationEvents");
9
     require("./service/authentication/AuthenticationEvents");
10
 var Statistics = require("./modules/statistics/statistics");
10
 var Statistics = require("./modules/statistics/statistics");
11
+var AnalyticsAdapter = require("./modules/statistics/AnalyticsAdapter");
11
 var MediaType = require("./service/RTC/MediaType");
12
 var MediaType = require("./service/RTC/MediaType");
12
 
13
 
13
 /**
14
 /**
92
 
93
 
93
     this.chatRoomForwarder.forward(XMPPEvents.MUC_JOINED,
94
     this.chatRoomForwarder.forward(XMPPEvents.MUC_JOINED,
94
         JitsiConferenceEvents.CONFERENCE_JOINED);
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
     this.chatRoomForwarder.forward(XMPPEvents.ROOM_JOIN_ERROR,
110
     this.chatRoomForwarder.forward(XMPPEvents.ROOM_JOIN_ERROR,
97
         JitsiConferenceEvents.CONFERENCE_FAILED,
111
         JitsiConferenceEvents.CONFERENCE_FAILED,
116
     this.chatRoomForwarder.forward(XMPPEvents.BRIDGE_DOWN,
130
     this.chatRoomForwarder.forward(XMPPEvents.BRIDGE_DOWN,
117
         JitsiConferenceEvents.CONFERENCE_FAILED,
131
         JitsiConferenceEvents.CONFERENCE_FAILED,
118
         JitsiConferenceErrors.VIDEOBRIDGE_NOT_AVAILABLE);
132
         JitsiConferenceErrors.VIDEOBRIDGE_NOT_AVAILABLE);
133
+    chatRoom.addListener(XMPPEvents.BRIDGE_DOWN,
134
+        function (){
135
+            AnalyticsAdapter.sendEvent('conference.bridgeDown');
136
+        });
119
 
137
 
120
     this.chatRoomForwarder.forward(XMPPEvents.RESERVATION_ERROR,
138
     this.chatRoomForwarder.forward(XMPPEvents.RESERVATION_ERROR,
121
         JitsiConferenceEvents.CONFERENCE_FAILED,
139
         JitsiConferenceEvents.CONFERENCE_FAILED,
153
 
171
 
154
     chatRoom.addListener(XMPPEvents.FOCUS_LEFT,
172
     chatRoom.addListener(XMPPEvents.FOCUS_LEFT,
155
         function () {
173
         function () {
174
+            AnalyticsAdapter.sendEvent('conference.focusLeft');
156
             if(!conference.connection._reload())
175
             if(!conference.connection._reload())
157
                 conference.eventEmitter.emit(
176
                 conference.eventEmitter.emit(
158
                     JitsiConferenceEvents.CONFERENCE_FAILED,
177
                     JitsiConferenceEvents.CONFERENCE_FAILED,
166
 
185
 
167
     this.chatRoomForwarder.forward(XMPPEvents.CONNECTION_INTERRUPTED,
186
     this.chatRoomForwarder.forward(XMPPEvents.CONNECTION_INTERRUPTED,
168
         JitsiConferenceEvents.CONNECTION_INTERRUPTED);
187
         JitsiConferenceEvents.CONNECTION_INTERRUPTED);
188
+    chatRoom.addListener(XMPPEvents.CONNECTION_INTERRUPTED,
189
+        function () {
190
+            AnalyticsAdapter.sendEvent('connection.interrupted');
191
+        });
169
 
192
 
170
     this.chatRoomForwarder.forward(XMPPEvents.RECORDER_STATE_CHANGED,
193
     this.chatRoomForwarder.forward(XMPPEvents.RECORDER_STATE_CHANGED,
171
         JitsiConferenceEvents.RECORDER_STATE_CHANGED);
194
         JitsiConferenceEvents.RECORDER_STATE_CHANGED);
428
         var now = window.performance.now();
451
         var now = window.performance.now();
429
         logger.log("(TIME) data channel opened ", now);
452
         logger.log("(TIME) data channel opened ", now);
430
         conference.room.connectionTimes["data.channel.opened"] = now;
453
         conference.room.connectionTimes["data.channel.opened"] = now;
454
+        AnalyticsAdapter.sendEvent('conference.dataChannel.open', now);
431
     });
455
     });
432
 
456
 
433
     this.rtcForwarder.forward(RTCEvents.LASTN_CHANGED,
457
     this.rtcForwarder.forward(RTCEvents.LASTN_CHANGED,

+ 12
- 0
JitsiConnection.js View File

2
 var XMPP = require("./modules/xmpp/xmpp");
2
 var XMPP = require("./modules/xmpp/xmpp");
3
 var JitsiConnectionEvents = require("./JitsiConnectionEvents");
3
 var JitsiConnectionEvents = require("./JitsiConnectionEvents");
4
 var JitsiConnectionErrors = require("./JitsiConnectionErrors");
4
 var JitsiConnectionErrors = require("./JitsiConnectionErrors");
5
+var AnalyticsAdapter = require("./modules/statistics/AnalyticsAdapter");
5
 
6
 
6
 /**
7
 /**
7
  * Creates new connection object for the Jitsi Meet server side video conferencing service. Provides access to the
8
  * Creates new connection object for the Jitsi Meet server side video conferencing service. Provides access to the
25
 
26
 
26
     this.addEventListener(JitsiConnectionEvents.CONNECTION_FAILED,
27
     this.addEventListener(JitsiConnectionEvents.CONNECTION_FAILED,
27
         function (errType, msg) {
28
         function (errType, msg) {
29
+            AnalyticsAdapter.sendEvent('connection.failed.' + errType);
28
             if(errType === JitsiConnectionErrors.OTHER_ERROR &&
30
             if(errType === JitsiConnectionErrors.OTHER_ERROR &&
29
                 (msg === "item-not-found" || msg === "host-unknown")) {
31
                 (msg === "item-not-found" || msg === "host-unknown")) {
30
                     // FIXME: don't report the error if we are going to reload
32
                     // FIXME: don't report the error if we are going to reload
31
                     this._reload();
33
                     this._reload();
32
                 }
34
                 }
33
         }.bind(this));
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
 JitsiConnection.prototype._reload = function () {
73
 JitsiConnection.prototype._reload = function () {
63
     if(this.retryOnFail === 0)
74
     if(this.retryOnFail === 0)
64
         return false;
75
         return false;
76
+    AnalyticsAdapter.sendEvent('connection.reload');
65
     this.retryOnFail--;
77
     this.retryOnFail--;
66
     var states = {};
78
     var states = {};
67
     for(var name in this.conferences) {
79
     for(var name in this.conferences) {

+ 3
- 8
JitsiMeetJS.js View File

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

+ 40
- 0
modules/RTC/JitsiRemoteTrack.js View File

1
 var JitsiTrack = require("./JitsiTrack");
1
 var JitsiTrack = require("./JitsiTrack");
2
 var JitsiTrackEvents = require("../../JitsiTrackEvents");
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
  * Represents a single media track (either audio or video).
10
  * Represents a single media track (either audio or video).
84
     this.eventEmitter.emit(JitsiTrackEvents.TRACK_VIDEOTYPE_CHANGED, type);
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
 module.exports = JitsiRemoteTrack;
127
 module.exports = JitsiRemoteTrack;

+ 13
- 0
modules/RTC/JitsiTrack.js View File

189
 
189
 
190
     this._maybeFireTrackAttached(container);
190
     this._maybeFireTrackAttached(container);
191
 
191
 
192
+    this._attachTTFMTracker(container);
193
+
192
     return container;
194
     return container;
193
 };
195
 };
194
 
196
 
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
  * Removes attached event listeners.
233
  * Removes attached event listeners.
221
  *
234
  *

+ 12
- 0
modules/RTC/RTCBrowserType.js View File

30
         return currentBrowser;
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
      * Checks if current browser is Chrome.
46
      * Checks if current browser is Chrome.
35
      * @returns {boolean}
47
      * @returns {boolean}

+ 30
- 0
modules/statistics/AnalyticsAdapter.js View File

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 View File

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

+ 11
- 5
modules/xmpp/strophe.jingle.js View File

6
 var XMPPEvents = require("../../service/xmpp/XMPPEvents");
6
 var XMPPEvents = require("../../service/xmpp/XMPPEvents");
7
 var RTCBrowserType = require("../RTC/RTCBrowserType");
7
 var RTCBrowserType = require("../RTC/RTCBrowserType");
8
 var GlobalOnErrorHandler = require("../util/GlobalOnErrorHandler");
8
 var GlobalOnErrorHandler = require("../util/GlobalOnErrorHandler");
9
-
9
+var AnalyticsAdapter = require("../statistics/AnalyticsAdapter");
10
 
10
 
11
 module.exports = function(XMPP, eventEmitter) {
11
 module.exports = function(XMPP, eventEmitter) {
12
     Strophe.addConnectionPlugin('jingle', {
12
     Strophe.addConnectionPlugin('jingle', {
101
                             .up();
101
                             .up();
102
                         this.terminate(sess.sid);
102
                         this.terminate(sess.sid);
103
                     }
103
                     }
104
+                    AnalyticsAdapter.sendEvent('xmpp.session-initiate', now);
104
                     break;
105
                     break;
105
                 case 'session-terminate':
106
                 case 'session-terminate':
106
                     logger.log('terminating...', sess.sid);
107
                     logger.log('terminating...', sess.sid);
114
                     this.terminate(sess.sid, reasonCondition, reasonText);
115
                     this.terminate(sess.sid, reasonCondition, reasonText);
115
                     break;
116
                     break;
116
                 case 'transport-replace':
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
                     sess.replaceTransport($(iq).find('>jingle'),
123
                     sess.replaceTransport($(iq).find('>jingle'),
120
                         function () {
124
                         function () {
125
+                            var now = window.performance.now();
121
                             logger.info(
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
                         function(error) {
131
                         function(error) {
126
                             GlobalOnErrorHandler.callErrorHandler(error);
132
                             GlobalOnErrorHandler.callErrorHandler(error);

Loading…
Cancel
Save