Player adapters

Available adapters

Implementing adapter

If current plug-ins do not meet your requirements, or you require more control over what events are tracked and synchronized with emotions, you may want to write your own plug-in. This would be the best option particularly if we do not support the type of video player you have on your website pages, or if you want to thoroughly integrate our services into your applications. In this case you have three options:

  • Writing a unified player interface implementation to support new video players.
  • Writing your own plug-in to change the way the players on the page are added to the tracking list.
  • Writing your own plug-in/application code to track players’ events and push them to us.

Communicate with our SDK from your plugin.

Sending commands or subscribing to events can be done via the previously mentioned rubac function. However, the name “rubac” is not fix, it can be easily changed in the injection script, so it is better if you get the function reference in this way:

var rubac = rubac || window[window["RealeyesitUBACore"]];

Writing a unified player interface implementation to support new video players

Most modern video players based on html5 video tag or flash include a Javascript API to control them and detect their state. Those APIs differ from player to player. That’s why we introduced a unified player interface that our built-in tracking application (keyname application) can consume regardless of the player’s native API implementation. To support a new player you would need to create a player adapter object that implements this interface according to the specification below:

{
  // required properties
  getPlayerState: function(){...},
  getCurrentTime: function(){...},
  getVideoInfo: function(){...},

  // optional properties
  pollTimeout: number,
  allowAutoControl: boolean,
  ready: boolean // or function(){...},
  equals: function(compareTo){...},

  // optional properties (overlay related)
  pauseVideo: function(){...},
  playVideo: function(){...},
  getDisplayArea: function(){...},
}

getPlayerState - returns current player state as a number according to enumeration

ERROR: -1, UNKNOWN_STATE_CHANGE: 0, PLAY: 1, PAUSE: 2, BUFFERING: 3, ENDED: 4, CUED: 5, PLAYER_INITIALIZED: 7

The only required states to work with our API are PLAY and PAUSE because they indicate whether the video is playing. If your player’s native API support SEEK events you can use a sequence of PAUSE, PLAY states.

All other states are merely recommended and allow for more accurate synchronization of emotions and behaviour to the content itself. When any of these states are available by your player API we do however strongly recommend you use them.

getCurrentTime - returns current player time position in milliseconds.

getVideoInfo - returns the information object describing the current media being played {name: string, url: string, duration: number, extId: string}. Duration is represented in milliseconds. “extId” parameter is optional, but it should be used in case when there is no fixed media uri to prevent duplicate medias in the database.

pollTimeout - property returns desired state change polling interval in milliseconds. It should be less than or equal to 1000 ms. See “State polling and event models” paragraph for details.

allowAutoControl - if true or undefined, player won’t be able to control the collection (i.e. use the start/stop commands). In this case, our SDK will do this by itself.

ready - determines if player is ready. You can use this property to tell us not to track player state changes or events if the player is in an inconsistent state, or if you just don’t want us to track it. It can be a boolean value or a function that returns such a value.

equals - compares current player interface instance to another interface instance (compareTo parameter). This method returns boolean and is used inside our tracking applications, for instanca to prevent attaching to the same player twice, or removing a player from being tracked etc. If this method is not implemented then comparison by reference is used instead.

State polling and event models

To sync the behaviour to the media, we need to know its playback position. For the widest compatibility with different video players we use a continuous polling model. Every N milliseconds (this is configurable by pollTimeout interface property) we are checking if the player state or time position have changed since the last check. This way we are able to determine state change events and also implicit seeking/lagging events. This model can be complemented by an event-based one, in which case we make this check as soon as any state change event is fired by the player, allowing for more accurate synchronization. To implement it you should add the following code snippet to your player interface class event raising method: this.onStateChange && this.onStateChange();. It will try to do a callback that we dynamically assign to player objects onStateChange property.

Controlling the collection from the player

Players are given the possibility to control the collection’s state, ie. starting it, stopping it and also releasing the camera. To enable this feature, set the allowAutoControl property to false on your player object.

Sending start and stop commands to control the collection:

Before you use any of these commands, you have to be sure that your player is registered correctly. You know this from the onReady callback of the ‘application.addPlayer’ command.

rubac('application.addPlayer', { player: playerObject, onReady: function(playerObject) { /* player is added successfully */ } } )

(Remember: before using rubac read the section “Communicate with our SDK from your plugin.”)

The callback should receive the result of the addPlayer operation as parameter result. In case you receive your playerObject, you can safely continue with start/stop. In any other case you should not proceed with any further commands and consider that our application (for whatever reason) is not ready. In this case the player should function as if our application wouldn’t exists.

rubac('start', { sender: player, callback: fn }); where player is a reference to the player interface rubac('stop', { sender: player, releaseWebcam: true|false, callback: fn}); if webcam is released a restart of the collection implies a new camera access request

For both of theses commands a callback may be defined that receives true|false depending on the success of the operation.

There are also some events that players may find useful

  1. application.ready Triggered when the application has been fully loaded and ready to work. One can subscribe to this event by the following command:

     `rubac('addListener', { filter: 'application.ready', callback: fn })` where fn can be a function reference or an anonyme function, the callback does not get any arguments
    
     Please note that this event should only be relied upon once the environment check has succeeded,
     ie you should first subscribe the the `application.environmentChecked` event and only subscribe to `application.ready`
     once this first was fired and returned with true result.
     Ex.:
    
     rubac('addListener', { filter: 'application.environmentChecked', callback: function(data) {
         if(data && data.result) {
             rubac('addListener', { filter: 'application.ready', callback: fn });
         }}
     });
    
  2. application.webcamAccess

     Triggered when the application gets the result of the webcam access request.
     One can subscribe to it by:
    
     `rubac('addListener', { filter: 'application.webcamAccess', callback: fn };` // where fn can be a function reference or an anonyme function, the function gets an object as arguments
    
     The result object has the following structure: `{ type: numeric, name: string } ` where type and name can be the following
    
     * 205 : Allowed
     * 206 : Denied
     * 207 : Timeout
    
  1. application.collectionStarted & application.collectionStopped

     Triggered when the collection has been successfully started of stopped (regardless off the success or failure in this later case!).
     One can subscribe to this event by the following command:
    
     `rubac('addListener', { filter: 'application.collectionStarted', callback: fn })`
     `rubac('addListener', { filter: 'application.collectionStopped', callback: fn })`
    

where fn can be a function reference or an anonyme function, the callback does not get any arguments