Research
Security News
Quasar RAT Disguised as an npm Package for Detecting Vulnerabilities in Ethereum Smart Contracts
Socket researchers uncover a malicious npm package posing as a tool for detecting vulnerabilities in Etherium smart contracts.
empanalytics
Advanced tools
This component collects playback events and sends them every 3s to EMP Exposure backend.
Analytics is now served as a standalone service and you can integrate this component into any javascript-based project other than the empPlayer. Android/iOS libraries already send analytics by themselves. Also, for the empPlayer, analytics are sent automatically aswell. If your project is using an old analytics setup: for instance via plugin or calling the method setAnalytics, you can remove that code from your project as it is no longer necessary. Being a standalone component, EMPAnalytics can now be integrated with more products other than EMPPlayer. This tutorial will show you how to use EMP Analytics. When using the new component, please do not forget to remove the old video.js analytics plugin from your setup, otherwise the EMPPlayer might send duplicated analytics events. The new analytics service is delivered with some important bug fixes. We will no longer deliver new features or bug fixes to the old video.js analytics plugin.
This component collects playback events and sends them every 3s to EMP Exposure backend. In case no event has been generated and a playback is taking place, a Heartbeat event is sent every 60 seconds.
npm install empanalytics
// ES modules
import EMPAnalytics from 'EMPAnalytics';
// CommonJS
var EMPAnalytics = require('EMPAnalytics');
The following configuration values are required when the plugin is created:
If you use the EntitlmentEngine provided by EMP, in order to have analytics, all you have to do is pass these values in as options when instantiating the player:
var exposureOptions = {
'customer': customer.customer,
'businessUnit': customer.businessUnit,
'sessionToken': session.sessionToken,
'exposureApiURL': apiUrl
};
var options = {
'ericssonexposure': exposureOptions,
//...
}
If you use your own entitlment engine, just include these properties directly as options in your entitlement engine:
yourEMPPlayerObjec.entitlementEngine_.options_ = {
'customer': customer.customer,
'businessUnit': customer.businessUnit,
'sessionToken': session.sessionToken,
'exposureApiURL': apiUrl
}
var deviceInfoData = {
deviceModel: DEVICE_MODEL_STRING, // default: DESKTOP
userAgent: USER_AGENT_STRING, // default: window.navigator.userAgent
screenHeight: SCREEN_HEIGHT, // default: window.screen.height
screenWidth: SCREEN_WIDTH, // default: window.screen.width
deviceName: DEVICE_NAME_STRING, // default: window.navigator.product
deviceOS: DEVICE_OS_STRING, // default: platform.os.family
deviceOSVersion: DEVICE_OS_VERSION_STRING, // default: platform.os.version
type: DEVICE_TYPE_STRING, // default: WEB
deviceManufacturer: DEVICE_MANUFACTURER_STRING,
deviceId: DEVICE_ID_STRING,
};
var properties = {
disableWebWorkers: DISABLE_BOOLEAN // default: false
}
constructor(serverURL, customer, businessUnit, sessionToken, userId, deviceInfoData, properties)
// This method is called to initialize the component.
init();
// This method is called to clear all pending analytics events.
clear();
// This property is called to enable/disable debug.
debug = true | false;
// This method is called to add an event for a new plackback
// Event: Playback.Created
var params = {
autoplay: true
techName: TECH_NAME,
version: TECH_VERSION,
player: PLAYER_IDENTIFIER,
deviceAppInfo: APP_INFO_STRING, // optional
playMode: PLAY_MODE_STRING // optional
};
created(sessionId, params);
// This method is called when a 'play' command occurs (automatic or user triggered)
// Event: Playback.PlayerReady
var params = {
techName: TECH_NAME,
version: TECH_VERSION,
deviceAppInfo: APP_INFO_STRING, // optional
playMode: PLAY_MODE_STRING // optional
};
play(sessionId, startTime, params);
// This method is called when the media is actually playing
// Event: Playback.Started
var params = {
bitrate: BITRATE_IN_BYTES,
duration: DURATION_IN_SECONDS,
mediaLocator: MEDIA_URL // optional (.mpd URL p.e.)
referenceTime: UNIX_TIME_OF_THE_BEGINNING_OF_STREAM_IN_MS, // optional
playMode: PLAY_MODE_STRING // optional
};
playing(sessionId, currentTime, params);
// This method is called when the playback is paused.
// Event: Playback.Paused
paused(sessionId, currentTime);
// This method is called when a seek occurs.
// Event: Playback.ScrubbedTo
seek(sessionId, seekTime);
// This method is called when the player starts casting to an external device (chromecast p.e.).
// Event: Playback.StartCasting
startCasting(sessionId, nowTime);
// This method is called when the player stops casting to an external device.
// Event: Playback.StopCasting
stopCasting(sessionId, nowTime);
// This method should be called regularly to update the playback current time.
setCurrentTime(sessionId, nowTime);
// This method is called when a new asset is loaded.
// Event: Playback.HandshakeStarted
var params = {
assetId: EMP_ASSET_ID,
programId: EMP_PROGRAM_ID // optional
};
handshake(sessionId, params);
// This method is called when the playback is resumed from a paused state.
// Event: Playback.Resumed
resume(sessionId, startTime, params);
// This method is called when there is a change in the playback bitrate.
// Event: Playback.BitrateChanged
var params = {
bitrate: BITRATE_IN_BYTES
};
bitrateChanged(sessionId, nowTime, params);
// Method for when DRM Session Update
// Event: Playback.DRM
var params = {
message: [WIDEVINE_CERTIFICATE_REQUEST, FAIRPLAY_CERTIFICATE_REQUEST
WIDEVINE_CERTIFICATE_RESPONS, FAIRPLAY_CERTIFICATE_RESPONSE
WIDEVINE_LICENSE_REQUEST, PLAYREADY_LICENSE_REQUEST, FAIRPLAY_LICENSE_REQUEST
WIDEVINE_LICENSE_RESPONS, PLAYREADY_LICENSE_RESPONSE, FAIRPLAY_LICENSE_RESPONSE
WIDEVINE_LICENSE_ERROR, PLAYREADY_LICENSE_ERROR, FAIRPLAY_LICENSE_ERROR]
code: 0,
info: 'info',
};
drmSessionUpdate(sessionId, params);
// This method is called when the playback plays all the media to the end.
// Event: Playback.Completed
endOfStream(sessionId, params = {});
// This method is called when an error occurs during a playback.
// Event: Playback.Error
var params = {
errorCode: ERROR_CODE, // default: N/A
errorMessage: ERROR_MESSAGE // default: Unknown Error
};
error(sessionId, nowTime, params = {});
// This method is called when a user exits/disposes a playback before it reaches the end of the stream.
// Event: Playback.Aborted
dispose(sessionId, nowTime, params = {});
// This method is called when the player enters goest into a waiting/buffering/loading state.
// Event: Playback.BufferingStarted
waiting(sessionId, nowTime, params = {});
// This method is called when the player leaves a waiting/buffering/loading state.
// Event: Playback.BufferingEnded
waitingEnded(sessionId, nowTime, params = {});
// This getter returns the current state of an analytics session (IDLE, PLAYING, DIRTY, FINISHED).
getSessionState(sessionId);
// This method immediately dispatches all events waiting to be sent to the backend.
dispatchNow(asyncCall = true);
// This method automatically disposes ongoing analytics session
exitOngoingSession(nowTime);
// This method allows you to register a custom attribute that will be sent on every Playback.Started event
setCustomAttribute(key, value);
// This method allows you to clear all custom events previously registered
clearCustomAttributes();
index.html
<html>
<head>
<script src="emp-analytics.min.js"></script>
<script src="html5player-analytics-connector.js"></script>
</head>
<body>
<video id="sample-video" autoplay>
<source src=http://techslides.com/demos/sample-videos/small.webm type=video/webm>
<source src=http://techslides.com/demos/sample-videos/small.ogv type=video/ogg>
<source src=http://techslides.com/demos/sample-videos/small.mp4 type=video/mp4>
<source src=http://techslides.com/demos/sample-videos/small.3gp type=video/3gp>
</video>
<script>
// Global variables
var SERVER_URL = 'YOUR_ANALYTICS_SERVER_URL';
var CUSTOMER = 'YOUR_CUSTOMER';
var BUSINESS_UNIT = 'YOUR_BUSINESS_UNIT';
var SESSION_TOKEN = 'YOUR_SESSION_TOKEN';
// Video element to connect analytics to
var html5player = document.getElementById('sample-video');
// Creating and initiating the analytics service
var analytics = new empAnalytics (SERVER_URL, CUSTOMER, BUSINESS_UNIT, SESSION_TOKEN);
analytics.init();
// Creating and initiating the connector - the constructor receives the html5 player element and the analytics component
var connector = new HTML5PlayerAnalyticsConnector(html5player, analytics);
connector.init();
</script>
</body>
</html>
html5player-analytics-connector.js
var HTML5PlayerAnalyticsConnector = function(html5player, analytics) {
this.player_ = html5player;
this.analytics_ = analytics;
this.onLoadStartBind = this.onLoadStart.bind(this);
this.onCanPlayBind = this.onCanPlay.bind(this);
this.onPlayingBind = this.onPlaying.bind(this);
this.onEndedBind = this.onEnded.bind(this);
this.onPauseBind = this.onPause.bind(this);
this.onSeekedBind = this.onSeeked.bind(this);
this.onErrorBind = this.onError.bind(this);
this.onAbortBind = this.onAbort.bind(this);
this.onWindowUnloadBind = this.onWindowUnload.bind(this);
this.init();
};
// Initialization function - adds events to the provided player
HTML5PlayerAnalyticsConnector.prototype.init = function() {
this.dispose();
this.rnd_ = Math.random();
this.player_.addEventListener('loadstart', this.onLoadStartBind);
this.player_.addEventListener('canplay', this.onCanPlayBind);
this.player_.addEventListener('playing', this.onPlayingBind);
this.player_.addEventListener('ended', this.onEndedBind);
this.player_.addEventListener('pause', this.onPauseBind);
this.player_.addEventListener('seeked', this.onSeekedBind);
this.player_.addEventListener('error', this.onErrorBind);
this.player_.addEventListener('abort', this.onAbortBind);
window.addEventListener('beforeunload', this.onWindowUnloadBind);
};
// Returns the session ID being currently analysed
HTML5PlayerAnalyticsConnector.prototype.getSessionId = function() {
return 'ANALYTICS-DEMO-' + this.rnd_;
};
// Function triggered when player starts to load new source
HTML5PlayerAnalyticsConnector.prototype.onLoadStart = function() {
this.onGeneric('HandShake', this.analytics_.handshake, function() {
var params = {
'assetId': 'YOUR_ASSET_ID',
'programId': 'YOUR_PROGRAM_ID'
};
this.analytics_.handshake(this.getSessionId(), params);
}.bind(this), false);
};
// Sends playback current time to the analytics engine
HTML5PlayerAnalyticsConnector.prototype.sendCurrentTime = function() {
var sessionId = this.getSessionId();
if (this.analytics_.getSessionState &&
this.analytics_.getSessionState(sessionId) === 'PLAYING') {
// This is important for the heartbeats to reflect accurate playback currentTime
this.analytics_.setCurrentTime(sessionId, this.player_.currentTime);
}
};
// Clears all timers bound to the analytics session
HTML5PlayerAnalyticsConnector.prototype.clearTimers = function() {
if(this.currentTimeTimer_) {
clearInterval(this.currentTimeTimer_);
}
this.currentTimeTimer_ = null;
};
// Registers a timer to send to the analytics engine regular currentTime updates
HTML5PlayerAnalyticsConnector.prototype.registerCurrentTimeTimer = function() {
this.clearTimers();
this.currentTimeTimer_ = setInterval(function() { this.sendCurrentTime(); }.bind(this), 1000);
};
// Function triggered when player is able to start playing media
HTML5PlayerAnalyticsConnector.prototype.onCanPlay = function() {
var currentSessionId = this.getSessionId();
this.onGeneric('Created', this.analytics_.created, function() {
var params = {
'autoplay': true
};
this.analytics_.created(currentSessionId, params);
this.onStartPlay();
}.bind(this), false);
};
// Function triggered when player receives a command to start playing media
HTML5PlayerAnalyticsConnector.prototype.onStartPlay = function() {
this.onGeneric('Play', this.analytics_.play, function() {
var params = {
'techName' : 'NativeHTML5',
'version' : '1.0',
'techVersion': '1.0'
};
this.analytics_.play(this.getSessionId(), 0.0, params);
this.registerCurrentTimeTimer();
}.bind(this), false);
};
// Function triggered when the playback is paused
HTML5PlayerAnalyticsConnector.prototype.onPause = function() {
this.onGeneric('Pause', this.analytics_.paused, function() {
this.analytics_.paused(this.getSessionId(), this.player_.currentTime);
}.bind(this), true);
};
// Function triggered when player actually displays the first media elements on the screen
HTML5PlayerAnalyticsConnector.prototype.onPlaying = function() {
this.onGeneric('Playing', this.analytics_.playing, function() {
let params = {
'bitrate': 'YOUR_BITRATE',
'duration': this.player_.duration,
'mediaLocator': 'MEDIA_URL'
};
this.analytics_.playing(this.getSessionId(), this.player_.currentTime, params);
}.bind(this), false);
};
// Function triggered when the playback reaches the end of the stream
HTML5PlayerAnalyticsConnector.prototype.onEnded = function() {
var currentSessionId = this.getSessionId();
this.onGeneric('End of Stream', this.analytics_.endOfStream, function() {
this.analytics_.endOfStream(currentSessionId);
}.bind(this), true, true);
};
// Function triggered when the media is seeked
HTML5PlayerAnalyticsConnector.prototype.onSeeked = function() {
this.onGeneric('Seeked', this.analytics_.seek, function() {
this.analytics_.seek(this.getSessionId(), this.player_.currentTime);
}.bind(this), true);
};
// Function triggered when an error occurs within the player's playback session
HTML5PlayerAnalyticsConnector.prototype.onError = function() {
this.onGeneric('Error', this.analytics_.error, function() {
const params = {
'code': 'YOUR_ERROR_CODE',
'errorMessage': 'YOUR_MESSAGE'
};
this.analytics_.error(this.getSessionId(), this.player_.currentTime, params);
}.bind(this), false);
};
// Function triggered when the playback session is interruped
HTML5PlayerAnalyticsConnector.prototype.onAbort = function() {
this.onGeneric('Dispose', this.analytics_.dispose, function() {
this.analytics_.dispose(this.getSessionId());
}.bind(this), true, true);
};
// Function triggered when the browser window is unloaded/closed
HTML5PlayerAnalyticsConnector.prototype.onWindowUnload = function() {
this.onGeneric('WindowClose', this.analytics_.dispose, function() {
this.analytics_.dispose(this.getSessionId(), this.player_.currentTime);
this.analytics_.dispatchNow(false);
}.bind(this), true);
};
HTML5PlayerAnalyticsConnector.prototype.onGeneric = function(eventName, eventFnc, callback) {
if (eventFnc && callback) {
callback();
}
else {
console.log('\'' + eventName + '\' was discarded.');
}
};
// Function used to unregister callbacks for player events and clear timers
HTML5PlayerAnalyticsConnector.prototype.dispose = function() {
this.clearTimers();
this.player_.removeEventListener('loadstart', this.onLoadStartBind);
this.player_.removeEventListener('canplay', this.onCanPlayBind);
this.player_.removeEventListener('playing', this.onPlayingBind);
this.player_.removeEventListener('ended', this.onEndedBind);
this.player_.removeEventListener('pause', this.onPauseBind);
this.player_.removeEventListener('seeked', this.onSeekedBind);
this.player_.removeEventListener('error', this.onErrorBind);
this.player_.removeEventListener('abort', this.onAbortBind);
window.removeEventListener('beforeunload', this.onWindowUnloadBind);
};
FAQs
This component collects playback events and sends them every 3s to EMP Exposure backend.
We found that empanalytics demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Research
Security News
Socket researchers uncover a malicious npm package posing as a tool for detecting vulnerabilities in Etherium smart contracts.
Security News
Research
A supply chain attack on Rspack's npm packages injected cryptomining malware, potentially impacting thousands of developers.
Research
Security News
Socket researchers discovered a malware campaign on npm delivering the Skuld infostealer via typosquatted packages, exposing sensitive data.