dash.js: How to use DASH events

HTTP Live Streaming (HLS) and Dynamic Adaptive Streaming over HTTP (MPEG-DASH) are the two main formats for adaptive streaming. While HLS is natively supported on most of its target platforms, (iOS and MacOSX), MPEG-DASH requires external players. For browser-based environments, there are two great open-source options, namely shaka-player and dash.js.  Both are written in JavaScript and use the MediaSourceExtensions (MSE) and EncryptedMediaExtensions (EME) to enable playback directly in the browser without the need for external plugins. Both offer a wide set of features and have an active community. Shaka-player is maintained and developed by Google, dash.js is the official reference player of the DASH Industry Forum

In this series of blog posts, we will focus on dash.js. I will explain how certain features are implemented and how they can be used within applications. To start off, we will focus on DASH events and how they can be used for features like metadata signaling and ad-insertion. But first, we need to clarify what DASH events are and how they work.

What are DASH events?

You can think of DASH events as a means for signalling additional information to the DASH client or the underlying application. Events are timed and therefore have a start time and duration. They can be a part of the manifest file or be embedded in the ISOBMFF-based media files, such as an EMSG box. For means of simplicity, we focus on the manifest variant. Let’s take a closer look at event-specific parts of such a manifest file:

<EventStream schemeIdUri="urn:custom-data" value="1">
  <Event presentationTime="5" duration="1" id="1">
      Hello world
   </Event>
  <Event presentationTime="10" duration="1" id="2">
      Hello world 2
   </Event>
</EventStream>

We introduce two new tags in our manifest file: the <EventStream> and <Event> element. Think of EventStreams as a container for a specific type of event. Each container has a @schemeIdUri which identifies the type of event and an optional @value to distinguish between events of the same type. Certain DASH-specific events with a reserved @schemeIdUri are directly processed by the DASH client and not dispatched to the underlying application.
Inside the <Eventstream> container, we can specify multiple events. In the example above, we defined two events. Each <Event> has a @presentationTime and a @duration. The presentation time is relative to the start of the parent <Period> element. Both @presentationTime and @duration should to be divided by the @timescale attribute in order to get their respective values in seconds. In our case, no @timescale is defined, so we can assume a default value of 1.  The event payload is wrapped within the <Event> tags.

DASH events in dash.js

In order to handle DASH events within the player, dash.js has a separate controller called EventController.js. Without going into too much detail, we can take a closer look at the part in which the events are actually dispatched:

if (curr.eventStream.schemeIdUri == MPD_RELOAD_SCHEME && curr.eventStream.value == MPD_RELOAD_VALUE) {
   if (curr.duration !== 0 || curr.presentationTimeDelta !== 0) { 
      refreshManifest();
   }
 } else {                           
   eventBus.trigger(curr.eventStream.schemeIdUri, {event: curr});
  }

DASH events with a schemeIdUri set to “urn:mpeg:dash:event:2012” (MPD_RELOAD_SCHEME) and a value of “1” (MPD_RELOAD_VALUE) are directly processed by dash.js. In that case, an aperiodic MPD reload is triggered. In any other case, the event is dispatched to the underlying application using the internal event bus.

How to use DASH events in an application

Now that we know what DASH events are and how they are handled within dash.js, we can start using them. Let’s create a small application which shows the payload of our events in a <div> container below our video element. The corresponding index.html is very straight forward and looks like the following:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8"/>
    <title>DASH events example</title>
        
    <style>
        video {
            width: 640px;
            height: 360px;
        }
    </style>
</head>
<body>
<div class="code">
    <video controls="true">
    </video>
</div>
<div >
   Event output: <span id="event-output"></span>   
</div>
<script>
    document.addEventListener("DOMContentLoaded", function () {
        var app = new App();
        app.init();
    });
</script>
<script src="dash.all.debug.js"></script>
<script src="main.js"></script>
</body>
</html>

We simply add all of our dependencies and initialize our sample application. For the latter, we only need a few lines of code:

var CUSTOM_EVENT_SCHEME = 'urn:custom-data';

var MPD_URL = 'events.mpd';

var App = function () {
 this.outputDiv = document.getElementById('event-output');
};

App.prototype.init = function () {
    this.video = document.querySelector("video");
    this.player = dashjs.MediaPlayer().create();
    this.player.initialize(this.video, MPD_URL, true);
    this.player.on(
     CUSTOM_EVENT_SCHEME, this.customEventHandler.bind(this));
};

App.prototype.customEventHandler = function (payload) {
    this.outputDiv.innerText = payload.event.messageData;
};

The crucial part is the last line of the init function in which we register for our custom events. The dash.js player will dispatch the events at the appropriate time and we output the content of the messageData attribute in the index.html.

This concludes our small example on DASH events and how they are handled within dash.js Obviously, there are much more sophisticated use cases for those types of events. For example, a switch to an advertisement could be signaled. Morever, DASH events are great in providing additional information about current objects like buildings or an actor/actress for the viewer.

If you want to find out more about us and DASH, feel free to check out our website https://www.fokus.fraunhofer.de/go/dash

Leave a Reply

Your email address will not be published. Required fields are marked *