diff --git a/analytics.js b/analytics.js index 54c7ee1ae..03a178393 100644 --- a/analytics.js +++ b/analytics.js @@ -11,7 +11,10 @@ } Analytics.prototype.sendEvent = function (action, data) { - ga('send', 'event', 'jit.si', action); + // empty label and add the value, the value should be integer or null + var value = parseInt(data); + + ga('send', 'event', 'jit.si', action, "", value ? value : null); }; ctx.Analytics = Analytics; diff --git a/modules/UI/recording/Recording.js b/modules/UI/recording/Recording.js index 13a28e7b5..7341bd1a3 100644 --- a/modules/UI/recording/Recording.js +++ b/modules/UI/recording/Recording.js @@ -20,6 +20,7 @@ import VideoLayout from '../videolayout/VideoLayout'; import Feedback from '../Feedback.js'; import Toolbar from '../toolbars/Toolbar'; import BottomToolbar from '../toolbars/BottomToolbar'; +import AnalyticsAdapter from '../../statistics/AnalyticsAdapter'; /** * The dialog for user input. @@ -306,13 +307,16 @@ var Recording = { selector.click(function () { if (dialog) return; - + AnalyticsAdapter.sendEvent('recording.clicked'); switch (self.currentState) { case Status.ON: case Status.RETRYING: case Status.PENDING: { - _showStopRecordingPrompt(recordingType).then(() => - self.eventEmitter.emit(UIEvents.RECORDING_TOGGLED), + _showStopRecordingPrompt(recordingType).then( + () => { + self.eventEmitter.emit(UIEvents.RECORDING_TOGGLED); + AnalyticsAdapter.sendEvent('recording.stopped'); + }, () => {}); break; } @@ -322,26 +326,35 @@ var Recording = { _requestLiveStreamId().then((streamId) => { self.eventEmitter.emit( UIEvents.RECORDING_TOGGLED, {streamId: streamId}); + AnalyticsAdapter.sendEvent('recording.started'); }).catch( reason => { if (reason !== APP.UI.messageHandler.CANCEL) console.error(reason); + else + AnalyticsAdapter.sendEvent( + 'recording.canceled'); } ); else { if (self.predefinedToken) { self.eventEmitter.emit( UIEvents.RECORDING_TOGGLED, {token: self.predefinedToken}); + AnalyticsAdapter.sendEvent('recording.started'); return; } _requestRecordingToken().then((token) => { self.eventEmitter.emit( UIEvents.RECORDING_TOGGLED, {token: token}); + AnalyticsAdapter.sendEvent('recording.started'); }).catch( reason => { if (reason !== APP.UI.messageHandler.CANCEL) console.error(reason); + else + AnalyticsAdapter.sendEvent( + 'recording.canceled'); } ); } diff --git a/modules/UI/shared_video/SharedVideo.js b/modules/UI/shared_video/SharedVideo.js index 52a3d8fcd..761ed33d5 100644 --- a/modules/UI/shared_video/SharedVideo.js +++ b/modules/UI/shared_video/SharedVideo.js @@ -8,6 +8,7 @@ import LargeContainer from '../videolayout/LargeContainer'; import SmallVideo from '../videolayout/SmallVideo'; import FilmStrip from '../videolayout/FilmStrip'; import ToolbarToggler from "../toolbars/ToolbarToggler"; +import AnalyticsAdapter from '../../statistics/AnalyticsAdapter'; export const SHARED_VIDEO_CONTAINER_TYPE = "sharedvideo"; @@ -68,17 +69,25 @@ export default class SharedVideoManager { if(!this.isSharedVideoShown) { requestVideoLink().then( - url => this.emitter.emit( - UIEvents.UPDATE_SHARED_VIDEO, url, 'start'), - err => console.log('SHARED VIDEO CANCELED', err) + url => { + this.emitter.emit( + UIEvents.UPDATE_SHARED_VIDEO, url, 'start'); + AnalyticsAdapter.sendEvent('sharedvideo.started'); + }, + err => { + console.log('SHARED VIDEO CANCELED', err); + AnalyticsAdapter.sendEvent('sharedvideo.canceled'); + } ); return; } if(APP.conference.isLocalId(this.from)) { - showStopVideoPropmpt().then(() => - this.emitter.emit( - UIEvents.UPDATE_SHARED_VIDEO, this.url, 'stop'), + showStopVideoPropmpt().then(() => { + this.emitter.emit( + UIEvents.UPDATE_SHARED_VIDEO, this.url, 'stop'); + AnalyticsAdapter.sendEvent('sharedvideo.stoped'); + }, () => {}); } else { dialog = APP.UI.messageHandler.openMessageDialog( @@ -89,6 +98,7 @@ export default class SharedVideoManager { dialog = null; } ); + AnalyticsAdapter.sendEvent('sharedvideo.alreadyshared'); } } @@ -192,6 +202,7 @@ export default class SharedVideoManager { self.smartAudioMute(); } else if (event.data == YT.PlayerState.PAUSED) { self.smartAudioUnmute(); + AnalyticsAdapter.sendEvent('sharedvideo.paused'); } self.fireSharedVideoEvent(event.data == YT.PlayerState.PAUSED); }; @@ -221,6 +232,7 @@ export default class SharedVideoManager { else if (event.data.volume <=0 || event.data.muted) { self.smartAudioUnmute(); } + AnalyticsAdapter.sendEvent('sharedvideo.volumechanged'); }; window.onPlayerReady = function(event) { diff --git a/modules/UI/toolbars/Toolbar.js b/modules/UI/toolbars/Toolbar.js index 61812fdbe..e25641089 100644 --- a/modules/UI/toolbars/Toolbar.js +++ b/modules/UI/toolbars/Toolbar.js @@ -82,6 +82,7 @@ const buttonHandlers = { } }, "toolbar_button_security": function () { + AnalyticsAdapter.sendEvent('toolbar.lock.clicked'); emitter.emit(UIEvents.ROOM_LOCK_CLICKED); }, "toolbar_button_link": function () { diff --git a/modules/UI/videolayout/SmallVideo.js b/modules/UI/videolayout/SmallVideo.js index 723aaefba..27279cb75 100644 --- a/modules/UI/videolayout/SmallVideo.js +++ b/modules/UI/videolayout/SmallVideo.js @@ -160,25 +160,6 @@ SmallVideo.createStreamElement = function (stream) { element.id = SmallVideo.getStreamElementID(stream); - element.onplay = function () { - var type = (isVideo ? 'video' : 'audio'); - var now = APP.connectionTimes[type + ".render"] - = window.performance.now(); - console.log("(TIME) Render " + type + ":\t", - now); - AnalyticsAdapter.sendEvent('render.' + type, now); - - // Time to first media, a number that can be used for comparision of - // time fot rendering media. It can be used for the first and - // the rest participants. It subtracts the period of waiting for the - // second participant to join (time between join and first - // session initiate). - var ttfm = now - APP.connectionTimes["document.ready"] - - (APP.conference.getConnectionTimes()["session.initiate"] - - APP.conference.getConnectionTimes()["muc.joined"]); - console.log("(TIME) TTFM " + type + ":\t", ttfm); - AnalyticsAdapter.sendEvent('ttfm.' + type, ttfm); - }; return element; }; diff --git a/modules/keyboardshortcut/keyboardshortcut.js b/modules/keyboardshortcut/keyboardshortcut.js index 2677d3065..19ef767fe 100644 --- a/modules/keyboardshortcut/keyboardshortcut.js +++ b/modules/keyboardshortcut/keyboardshortcut.js @@ -1,4 +1,5 @@ /* global APP, $ */ +import AnalyticsAdapter from '../statistics/AnalyticsAdapter'; //maps keycode to character, id of popover for given function and function var shortcuts = {}; function initShortcutHandlers() { @@ -13,6 +14,7 @@ function initShortcutHandlers() { character: "C", id: "toggleChatPopover", function: function() { + AnalyticsAdapter.sendEvent('shortcut.chat.toggled'); APP.UI.toggleChat(); } }, @@ -20,6 +22,7 @@ function initShortcutHandlers() { character: "D", id: "toggleDesktopSharingPopover", function: function () { + AnalyticsAdapter.sendEvent('shortcut.screen.toggled'); APP.conference.toggleScreenSharing(); } }, @@ -27,6 +30,7 @@ function initShortcutHandlers() { character: "F", id: "filmstripPopover", function: function() { + AnalyticsAdapter.sendEvent('shortcut.film.toggled'); APP.UI.toggleFilmStrip(); } }, @@ -34,12 +38,14 @@ function initShortcutHandlers() { character: "M", id: "mutePopover", function: function() { + AnalyticsAdapter.sendEvent('shortcut.audiomute.toggled'); APP.conference.toggleAudioMuted(); } }, "R": { character: "R", function: function() { + AnalyticsAdapter.sendEvent('shortcut.raisedhand.toggled'); APP.conference.maybeToggleRaisedHand(); } @@ -47,6 +53,7 @@ function initShortcutHandlers() { "T": { character: "T", function: function() { + AnalyticsAdapter.sendEvent('shortcut.talk.clicked'); APP.conference.muteAudio(true); } }, @@ -54,12 +61,14 @@ function initShortcutHandlers() { character: "V", id: "toggleVideoPopover", function: function() { + AnalyticsAdapter.sendEvent('shortcut.videomute.toggled'); APP.conference.toggleVideoMuted(); } }, "?": { character: "?", function: function(e) { + AnalyticsAdapter.sendEvent('shortcut.shortcut.help'); APP.UI.toggleKeyboardShortcutsPanel(); } } diff --git a/modules/statistics/AnalyticsAdapter.js b/modules/statistics/AnalyticsAdapter.js index ec5cfce10..29a62f018 100644 --- a/modules/statistics/AnalyticsAdapter.js +++ b/modules/statistics/AnalyticsAdapter.js @@ -15,32 +15,4 @@ if (config.disableThirdPartyRequests !== true) { /* prepend */ false); } -class NoopAnalytics { - sendEvent () {} -} - -// XXX Since we asynchronously load the integration of the analytics API and the -// analytics API may asynchronously load its implementation (e.g. Google -// Analytics), we cannot make the decision with respect to which analytics -// implementation we will use here and we have to postpone it i.e. we will make -// a lazy decision. - -class AnalyticsAdapter { - constructor () { - } - - sendEvent (...args) { - var a = this.analytics; - - if (a === null || typeof a === 'undefined') { - var AnalyticsImpl = window.Analytics || NoopAnalytics; - - this.analytics = a = new AnalyticsImpl(); - } - try { - a.sendEvent(...args); - } catch (ignored) {} - } -} - -export default new AnalyticsAdapter(); +export default JitsiMeetJS.analytics;