When building a HTML5 web video player, it tends to need a user interface, quality of service tracking, user interaction tracking, and sometimes ad tracking. To achieve this, the HTML5 Media Event standard needs to be interpreted.
After building multiple web video players, and having worked on more than one iteration of an event interpreter, something didn't feel right. Things weren't kept DRY.
When repetition strikes, it's usually a good idea to do something about it.
Creating a Media Event Filter
Enter @eyevinn/media-event-filter, a filter that interprets HTML5 media events in a way that makes sense.
This filter aims to provide a single source of truth that can be used across player engines and native browser playback.
Whether using one or multiple player engines, like Shaka Player, HLS.js, or dash.js, the filter will output a standardised event sequence. It does so without relying on events output by the player engine, giving applications a single, player agnostic, source of truth for video playback state updates.
Example Implementation
import {
getMediaEventFilter,
FilteredMediaEvent,
} from "@eyevinn/media-event-filter";
const videoElement = document.createElement("video");
const mediaEventFilter = getMediaEventFilter({
videoElement,
callback: (event: FilteredMediaEvent) => {
switch (event) {
case FilteredMediaEvent.LOADED:
// handle loaded
break;
case FilteredMediaEvent.BUFFERING:
// handle buffering
break;
case FilteredMediaEvent.BUFFERED:
// handle buffered
// ...
default:
break;
}
},
});
// Create a player, using your engine of choice
const player = createPlayer(videoElement);
// Load a manifest and play
player.load(url).then(player.play);
// Call when done
mediaEventFilter.teardown();
Live Example
See a barebones React + Shaka + Media Event Filter example over at codepen.
Production Readiness
While making the filter open source is recent, it has been battle tested for years. With millions of playback sessions, multiple third party tracking systems have been validated using the filter.
Event Sequence
The sequence follows the Eyevinn Player Analytics Specification, which maps directly to many popular tracking service provider SDKs.
Sample event sequence comparison, using <video autoplay>
with Shaka Player in Firefox, excluding timeupdate
:
Native | Filtered | Comment |
---|---|---|
ratechange | — | Shaka sets playback rate to 0 to control buffering |
progress | — | |
durationchange | — | |
resize | — | |
loadedmetadata | — | |
ratechange | — | |
progress | — | |
loadeddata | — | |
canplay | — | |
play | — | |
playing | — | |
canplaythrough | loaded | video is ready to start playing |
— | playing | video is playing, play event missing due to autoplay |
progress | — | |
... | — | |
progress | — | |
pause | pause | manual pause |
progress | — | |
seeking | seeking | seeking while paused |
ratechange | — | Shaka sets playback rate to 0 to control buffering |
play | play | Play requested during a seek |
waiting | — | |
progress | — | |
progress | — | |
progress | — | |
seeked | — | |
canplay | — | |
playing | — | |
canplaythrough | — | video element thinks it can start playing, but playback rate is 0 |
progress | — | |
ratechange | seeked | shaka returns playback rate to normal |
— | playing | video is playing again after previous pause |
progress | — | |
progress | — | |
pause | pause | |
progress | — | |
play | play | |
playing | playing | |
progress | — | |
progress | — | |
seeking | seeking | seeking while playing |
waiting | — | |
ratechange | — | |
progress | — | |
progress | — | |
seeked | — | |
canplay | — | |
playing | — | |
progress | — | |
canplaythrough | — | |
progress | — | |
ratechange | seeked | seek finished, video is rolling |
progress | — | |
progress | — | |
progress | — | |
progress | — | |
ratechange | buffering | buffer empty, shaka sets playbackrate to 0 |
progress | — | |
progress | — | |
progress | — | |
canplaythrough | — | video element thinks it can start playing, but playback rate is 0 |
progress | — | |
ratechange | buffered | shaka returns playback rate to normal |
progress | — | |
... | — | |
progress | — | |
seeking | seeking | |
waiting | — | |
ratechange | — | |
progress | — | |
... | — | |
progress | — | |
seeked | — | |
canplay | — | |
playing | — | |
canplaythrough | — | |
progress | — | |
ratechange | seeked | |
progress | — | |
progress | — | |
progress | — | |
durationchange | — | |
progress | — | |
seeking | seeking | seeking within buffer, no ratechange |
waiting | — | |
seeked | seeked | seek finished |
canplay | — | |
playing | — | |
canplaythrough | — | |
pause | pause | |
ended | ended | end of stream reached |
emptied | — |
Download it at npm.
Contribute at github.
Top comments (0)