Appearance
Ease Live Bridge HTML5 SDK
This is a guide for developers to get up and running with the Ease Live Bridge SDK for HTML5.
This library allows you as a web developer to integrate Ease Live with your chosen video streaming player on your web site.
Customers that have their own website and want to integrate it with Ease Live need a convenient way to do so. They may have their own player or a specific player they want to use. The Ease Live UI needs to be in sync with the video player in terms of duration, buffering, timecodes, etc. With the Ease Live Bridge SDK the customer can do this in the easiest and fastest way possible.
Recommended browsers
Ease Live supports browsers with native ES2015 support.
- Chrome 87+
- Edge 88+
- Firefox 78+
- Opera 99+
- Safari 14+
Installation
NPM
The package can be downloaded from Ease Live's private NPM registry. To get access, add the following line to your .npmrc file.
@ease-live:registry=https://easelive.jfrog.io/artifactory/api/npm/npm-public/
Put it in one of these two places:
- per-project config file (/path/to/my/project/.npmrc)
- per-user config file (~/.npmrc)
To learn more about npm config files, head on over to NPM's official docs on the subject.
Once the npm config is in place, install the package:
sh
npm install @ease-live/ease-live-bridge-web
Then in your application you can import/require the library:
js
var EaseLive = require('@ease-live/ease-live-bridge-web')
or use ES6 module syntax:
js
import EaseLive from '@ease-live/ease-live-bridge-web'
Examples
A list of Codesandbox examples can be found here.
The EaseLive
instance
Every Ease Live Bridge application starts by creating a new EaseLive
instance with the EaseLive
function:
js
const easeLive = new EaseLive({
// project and environment to load
accountId: 'tutorials',
// projectId: '0346ae3e-7a91-4760-bcd3-cd84bb6790dd', // optional. it is inferred by program
programId: '2d2711ff-6ff2-41c1-a141-060e9ffa2c38',
env: 'prod',
// optionally override parameters set by the environment.
// they will appear as query string params in the generated URL,
// such as &myQueryParam=value
params: {
myQueryParam: 'value',
},
// DOM element in which the Ease Live overlay will render
viewContainer: '#ease-live-container',
// setup integration with player. See section "Writing a player plugin"
playerPlugin: (easeLive, config) => {
// overlay will load when player ready is emitted
easeLive.emit('player.ready', {});
}
});
easeLive.init();
The values in the code above will load an SDK installation UI that will help verifying your implementation.
Optionally, you can send in an env variable to the configuration. That will allow you to generate multiple target overlay URLs under settings in your program. If not specified, env
defaults to prod
. Other values are staging
and dev
. If the staging
and dev
URLs doesn't exist in project settings, the SDK will make sure to fallback to the prod
URL.
js
const easeLive = new EaseLive({
// ...
env: 'dev'
})
When you create an EaseLive
instance, you pass in an options object. The majority of features in the Ease Live Bridge can be configured to create your desired behavior using options. For reference, you can also browse the full list of options in the API reference. When the instance is created, the lifecycle of a bridge will start.
The initialization of the EaseLive bridge will start when the init()
method is invoked: easeLive.init()
.
To remove the EaseLive bridge, call the destroy()
method. This will make sure that any event handlers are removed, along with the overlay itself.
Lifecycle Diagram
Event dispatcher
- Add a new listener:
easeLive.on(event, listener)
- Remove a listener:
easeLive.off(event, listener)
- Trigger an event:
easeLive.emit(event, payload)
Error handling
Listen for errors emitted from the EaseLive instance and overlay. The error listener should be added before easeLive.init()
.
If the type
is "fatal"
overlay can not continue and the EaseLive instance should be destroyed. For example: the project or main program failed to load.
If the type
is "warning"
something failed, but the overlay can continue with reduced functionality. For example: a custom plugin failed to load.
js
easeLive.on('easelive.error', (e) => {
if (e.type === 'fatal') {
easeLive.destroy();
easeLive = null;
}
});
Status handling
Listen for change in status of the loaded overlay, which can change during runtime.
If the status
is "disabled"
the EaseLive instance can be destroyed.
If the status
is "hidden"
or "disabled"
, when used on TV, the focus should be moved to player controls.
js
easeLive.on('app.status', ({status}) => {
if (status === 'disabled') {
// overlay is disabled
easeLive.destroy();
easeLive = null;
// if on TV, move focus to your player controls
} else if (status === 'hidden') {
// overlay is hidden, but can be enabled later
// if on TV, move focus to your player controls
} else if (status === 'enabled') {
// overlay is enabled
}
});
Plugins
Plugins can add additional functionality to the EaseLive
instance. There is no strictly defined scope for a plugin, however it is usually used for adding extra functionality to the bridge by adding listeners to the lifecycle events.
Writing a plugin
A plugin should expose an install
method. This method will be called with the easeLive
instance as the first argument, along with possible options.
js
MyPlugin.install = function (easeLive, options) {
// 1. add listeners to lifecycle events
easeLive.on('player.time', function (event) {
// some logic using the player timecode ...
})
// 2. add your own lifecycle events
easeLive.emit('myplugin.create', {
// some options ...
)
// 3. add global method or property to the EaseLive instance
easeLive.myGlobalMethod = function () {
// some custom logic ...
}
}
Using a plugin
Use plugins by calling the easeLive.use
global method.
js
easeLive.use(MyPlugin)
You can optionally pass in some options:
js
easeLive.use(MyPlugin, {someOption: true})
easeLive.use
automatically prevents you from using the same plugin more than once.
Writing a player plugin
The main job of a player plugin is to handle the communication between the player and the bridge SDK. Any player events triggered will be received by the web app. As a minimum, the player plugin needs to handle the following events:
- player.time
- player.state
A player plugin is very similar to writing a regular plugin, with a few subtle differences:
- there can only be one player plugin in use at the time (per bridge instance)
- the plugin won't be called immediately, but at the appropriate time after
easeLive.init()
has been called - the plugin should return a player instance
As an example, here's a player plugin for video.js. See API reference for full list of events.
js
function install(easeLive, config) {
// 1. Listen for the overlay requesting the player to change its state
// event from EaseLive to change player controls visibility when the EL background was clicked
easeLive.on('stage.clicked', ({ controls }) => {
player.userActive(controls === 'visible');
}, true);
// event from EaseLive when mouse pointer enters view container, can be used to show controls
easeLive.on('view.mouseenter', () => {
player.userActive(true);
}, true);
// event from EaseLive to change player state
easeLive.on('player.state', ({ state }) => {
if (state === 'playing') player.play();
if (state === 'paused') player.pause();
}, true);
// event from EaseLive to seek to the position of an absolute time
let currentTimecode;
easeLive.on('player.time', ({ timecode }) => {
if (currentTimecode > 0) {
// calculate the timeline position for the absolute time
const diff = (timecode - currentTimecode) / 1000;
const position = player.currentTime() + diff;
player.currentTime(position);
}
}, true);
// 2. Listen for changes in the player's state and notify EaseLive
// notify EaseLive when player controls visibility changes
player.on('useractive', () => {
easeLive.emit('player.controls', { controls: 'visible' });
});
player.on('userinactive', () => {
easeLive.emit('player.controls', { controls: 'hidden' });
});
// notify EaseLive when player state changes
function onPlayerState(state) {
easeLive.emit('player.state', { state });
}
player.on('playing', () => { onPlayerState('playing') });
player.on('pause', () => { onPlayerState('paused'); });
player.on('stalled', () => { onPlayerState('buffering'); });
player.on('seeking', () => { onPlayerState('seeking'); });
player.on('seeked', () => { onPlayerState('playing'); });
// notify EaseLive when the absolute UTC time for the current playback position is read from stream
player.textTracks().addEventListener('addtrack', function (addTrackEvent) {
const track = addTrackEvent.track;
track.addEventListener('cuechange', function (cueChangeEvent) {
if (track.activeCues.length <= 0) return;
for (let cueIdx = 0; cueIdx < track.activeCues.length; cueIdx++) {
// read time from metadata
const cue = track.activeCues[cueIdx];
if (cue.value.dateTimeObject) {
// example: timecode from EXT-X-PROGRAM-DATE-TIME in a HLS stream
const timecode = cue.value.dateTimeObject.getTime()
currentTimecode = timecode;
easeLive.emit('player.time', { timecode });
}
}
}, false);
}, false);
// notify EaseLive when player is ready
player.ready(() => {
easeLive.emit('player.ready', {});
});
}
export default install;
For additional examples, see the src/plugins
folder in the SDK package.
Custom bridge messages
Custom messages can be used to send data from the web page to the Ease Live overlay, and to receive data from the overlay. This can be used for custom functionality in the overlay.
Sending a message to the overlay
js
easeLive.emit('appMessage', {
event: 'myPrefix.myEvent',
metadata: {
myCustomValue: "some data"
}
});
To receive this message in the overlay configure a "Bridge message is received" trigger on the Bridge data source in the Studio project.
Receiving a message from the overlay
A message can be sent from the overlay by configuring a "Send bridge message" trigger in the Studio project.
Such messages can be received in the container web page by listening for it:
js
easeLive.on('myPrefix.myEvent', (event) => {
console.log(event.metadata.myCustomValue)
});