Get started with the IMA DAI SDK

IMA SDKs make it easy to integrate multimedia ads into your websites and apps. IMA SDKs can request ads from any VAST-compliant ad server and manage ad playback in your apps. With IMA DAI SDKs, apps make a stream request for ad and content video—either VOD or live content. The SDK then returns a combined video stream, so that you don't have to manage switching between ad and content video within your app.

Select the DAI solution you're interested in

Pod Serving DAI

This guide demonstrates how to play a DAI Pod Serving stream for live or VOD content, using the IMA DAI SDK for HTML5 with a video player that relies on hls.js for playback. To view or follow a completed sample integration, with support for both HLS.js and Safari Playback, see the HLS Pod Serving example. For DASH.js support, see the DASH Pod Serving example. You can download these sample apps from the HTML5 DAI GitHub release page.

DAI Pod Serving overview

Implementing Pod Serving using the IMA DAI SDK involves two main components, which are demonstrated in this guide:

  • PodStreamRequest / PodVodStreamRequest: An object that defines a stream request to Google's advertising servers. Requests specify a Network Code, and the PodStreamRequest also requires a Custom Asset Key, and an optional API key. Both include other optional parameters.

  • StreamManager: An object that handles communication between the video stream and the IMA DAI SDK, such as firing tracking pings and forwarding stream events to the publisher.

Prerequisites

Before you begin, you need the following:

  • Three empty files:

    • dai.html
    • dai.css
    • dai.js
  • Python installed on your computer, or a web server or other hosted development environment to use for testing

Configure a development environment

Since the SDK loads dependencies using the same protocol as the page from which it's loaded, you need to use a web server to test your app. A quick way to start a local development server is to use Python's built-in server.

  1. Using a command line, from the directory that contains your index.html file run:

    python -m http.server 8000
  2. In a web browser, go to http://localhost:8000/

    You can also use any other hosted development environment or web server, such as the Apache HTTP Server.

Create a video player

First, modify dai.html to create a HTML5 video element and a div to use for Ad UI elements. Also add the necessary tags to load the dai.css and dai.js files, as well as to import the hls.js video player.

Then, modify dai.css to specify the size and position of the page elements. Finally, in dai.js, define variables to hold the stream request information and an initPlayer() function to run when the page loads.

The stream request constants are as follows:

  • BACKUP_STREAM: A URL for a backup stream to play in case the ads process encounters a fatal error.

  • STREAM_URL: Only used for livestreams. The video stream URL provided by your manifest manipulator or third-party partner using Pod Serving. It should require you to insert the stream ID provided by the IMA DAI SDK, before you make a request. In this case, the stream URL includes a placeholder, [[STREAMID]], which is replaced with the stream ID before making a request.

  • NETWORK_CODE: The network code for your Ad Manager 360 account.

  • CUSTOM_ASSET_KEY: Only used for livestreams. The custom asset key that identifies your Pod Serving event in Ad Manager 360. This can be created by your manifest manipulator or third-party Pod Serving partner.

  • API_KEY: Only used for livestreams. An optional API key that can be required to retrieve a stream ID from the IMA DAI SDK.

dai.html

<html>
<head>
  <script src="https://cdn.jsdelivr.net/npm/hls.js@latest"></script>
  <script src="dai.js"></script>
  <link rel="stylesheet" href="dai.css" type="text/css">
</head>
<body onLoad="initPlayer()">
  <h2>IMA DAI SDK Demo (HLS.JS)</h2>
    <video id="video"></video>
    <div id="ad-ui"></div>
</body>
</html>

dai.css

#video,
#ad-ui {
  width: 640px;
  height: 360px;
  position: absolute;
  top: 35px;
  left: 0;
}

#ad-ui {
  cursor: pointer;
}

dai.js

var BACKUP_STREAM =
    'https://storage.googleapis.com/interactive-media-ads/media/bbb.m3u8'

// Stream Config.
const STREAM_URL = "https://encodersim.sandbox.google.com/masterPlaylist/...&stream_id=[[STREAMID]]";
const NETWORK_CODE = "51636543";
const CUSTOM_ASSET_KEY = "google-sample";
const API_KEY = "";

var hls = new Hls(); // hls.js video player
var videoElement;
var adUiElement;

function initPlayer() {
  videoElement = document.getElementById('video');
  adUiElement = document.getElementById('adUi');
}

Load the IMA DAI SDK

Next, add the DAI framework using a script tag in dai.html, before the tag for dai.js.

dai.html

<html>
<head>
  <script src="https://cdn.jsdelivr.net/npm/hls.js@latest"></script>
  <script type="text/javascript" src="//imasdk.googleapis.com/js/sdkloader/ima3_dai.js"></script>
  <script src="dai.js"></script>
  <link rel="stylesheet" href="dai.css" type="text/css">
</head>
...

Initialize the StreamManager and make a live or VOD stream request

Livestream Pod Serving

In order to request a set of ads, create an ima.dai.api.StreamManager, which is responsible for requesting and managing DAI streams. The constructor takes a video element and the resulting instance takes an ad UI element to handle ad interactions.

Then, define a function to request the Pod Serving livestream. This function first creates a PodStreamRequest, configures it with the streamRequest parameters provided in step 2, and then calls streamManager.requestStream() with that request object.

dai.js

function initPlayer() {
  videoElement = document.getElementById('video');
  adUiElement = document.getElementById('adUi');
  streamManager = new google.ima.dai.api.StreamManager(videoElement, adUiElement)

  requestLivePodStream(NETWORK_CODE, CUSTOM_ASSET_KEY, API_KEY);
}

function requestLivePodStream(networkCode, customAssetKey, apiKey) {
  // clear HLS.js instance, if in use
  if (hls) {
    hls.destroy();
  }

  // Generate a Pod Serving live Stream Request
  const streamRequest = new google.ima.dai.api.PodStreamRequest();
  streamRequest.networkCode = networkCode;
  streamRequest.customAssetKey = customAssetKey;
  streamRequest.apiKey = apiKey;
  streamRequest.format = 'hls';
  streamManager.requestStream(streamRequest);
}

VOD Pod Serving

In order to request a set of ads, create an ima.dai.api.StreamManager, which is responsible for requesting and managing DAI streams. The constructor takes a video element and the resulting instance takes an ad UI element to handle ad interactions.

Then, define a function to request the Pod Serving VOD stream. This function first creates a PodVodStreamRequest, configures it with the streamRequest parameters provided in step 2, and then calls streamManager.requestStream() with that request object.

dai.js

function initPlayer() {
  videoElement = document.getElementById('video');
  adUiElement = document.getElementById('adUi');
  streamManager = new google.ima.dai.api.StreamManager(videoElement, adUiElement)

  requestVodPodStream(NETWORK_CODE);
}

function requestVodPodStream(networkCode) {
  // clear HLS.js instance, if in use
  if (hls) {
    hls.destroy();
  }

  // Generate a Pod Serving VOD Stream Request
  const streamRequest = new google.ima.dai.api.PodVodStreamRequest();
  streamRequest.networkCode = networkCode;
  streamRequest.format = 'hls';
  streamManager.requestStream(streamRequest);
}

Handle stream events

Livestream Pod Serving

Next, implement event listeners for major video events. This example handles the STREAM_INITIALIZED, ERROR, AD_BREAK_STARTED and AD_BREAK_ENDED events by calling an onStreamEvent() function. This function handles stream loading and errors, as well as disabling the player controls while an ad is playing, which is required by the SDK. When the stream is loaded, the video player loads and plays the provided URL using a loadStream() function.

dai.js

var isAdBreak;

function initPlayer() {
  videoElement = document.getElementById('video');
  adUiElement = document.getElementById('adUi');
  streamManager = new google.ima.dai.api.StreamManager(videoElement, adUiElement);
  
  streamManager.addEventListener(
    [google.ima.dai.api.StreamEvent.Type.STREAM_INITIALIZED,
    google.ima.dai.api.StreamEvent.Type.ERROR,
    google.ima.dai.api.StreamEvent.Type.AD_BREAK_STARTED,
    google.ima.dai.api.StreamEvent.Type.AD_BREAK_ENDED],
    onStreamEvent,
    false);
...
function onStreamEvent(e) {
  switch (e.type) {
    case google.ima.dai.api.StreamEvent.Type.STREAM_INITIALIZED:
      console.log('Stream initialized');
      loadStream(e.getStreamData().streamId);
      break;
    case google.ima.dai.api.StreamEvent.Type.ERROR:
      console.log('Error loading stream, playing backup stream.' + e);
      loadStream('');
      break;
    case google.ima.dai.api.StreamEvent.Type.AD_BREAK_STARTED:
      console.log('Ad Break Started');
      isAdBreak = true;
      videoElement.controls = false;
      adUiElement.style.display = 'block';
      break;
    case google.ima.dai.api.StreamEvent.Type.AD_BREAK_ENDED:
      console.log('Ad Break Ended');
      isAdBreak = false;
      videoElement.controls = true;
      adUiElement.style.display = 'none';
      break;
    default:
      break;
  }
}

function loadStream(streamID) {
  var url;
  if(streamID) {
    url = STREAM_URL.replace('[[STREAMID]]', streamID);
  } else {
    console.log('Stream Initialization Failed');
    url = BACKUP_STREAM;
  }
  console.log('Loading:' + url);
  hls.loadSource(url);
  hls.attachMedia(videoElement);
}

VOD Pod Serving

Next, implement event listeners for major video events. This example handles the STREAM_INITIALIZED, LOADED, ERROR, AD_BREAK_STARTED and AD_BREAK_ENDED events by calling an onStreamEvent() function. This function handles stream loading and errors, as well as disabling the player controls while an ad is playing, which is required by the SDK.

In addition, VOD Pod Serving streams require calling StreamManager.loadStreamMetadata() in response to the to the STREAM_INITIALIZED event. You also need to request a stream URL from your, video technology partner (VTP). Once the loadStreamMetadata() call succeeds it triggers a LOADED event, where you should call a loadStream() function with your stream URL to load and play the stream.

var isAdBreak;

function initPlayer() {
  videoElement = document.getElementById('video');
  adUiElement = document.getElementById('adUi');
  streamManager = new google.ima.dai.api.StreamManager(videoElement, adUiElement);
  
  streamManager.addEventListener(
    [google.ima.dai.api.StreamEvent.Type.STREAM_INITIALIZED,
    google.ima.dai.api.StreamEvent.Type.ERROR,
    google.ima.dai.api.StreamEvent.Type.AD_BREAK_STARTED,
    google.ima.dai.api.StreamEvent.Type.AD_BREAK_ENDED],
    onStreamEvent,
    false);
...
function onStreamEvent(e) {
  switch (e.type) {
    case google.ima.dai.api.StreamEvent.Type.STREAM_INITIALIZED:
      const streamId = e.getStreamData().streamId;
      // 'vtpInterface' is a place holder for your own video technology
      //  partner (VTP) API calls.
      vtpInterface.requestStreamURL({
        'streamId': streamId,
      })
      .then( (vtpStreamUrl) => {
        streamUrl = vtpStreamUrl;
        streamManager.loadStreamMetadata();
      }, (error) => {
        // Handle the error.
      });
      break;
    case google.ima.dai.api.StreamEvent.Type.LOADED:
      loadStream(streamUrl);
      break;
    case google.ima.dai.api.StreamEvent.Type.ERROR:
      console.log('Error loading stream, playing backup stream.' + e);
      loadStream();
      break;
    case google.ima.dai.api.StreamEvent.Type.AD_BREAK_STARTED:
      console.log('Ad Break Started');
      isAdBreak = true;
      videoElement.controls = false;
      adUiElement.style.display = 'block';
      break;
    case google.ima.dai.api.StreamEvent.Type.AD_BREAK_ENDED:
      console.log('Ad Break Ended');
      isAdBreak = false;
      videoElement.controls = true;
      adUiElement.style.display = 'none';
      break;
    default:
      break;
  }
}

function loadStream(url) {
  if(url) {
    console.log('Loading:' + url);
    hls.loadSource(url);
  } else {
    console.log('Stream Initialization Failed');
    hls.loadSource(BACKUP_STREAM);
  }
  hls.attachMedia(videoElement);
}

Handle stream metadata

In this step you implement event listeners for metadata to notify the SDK when ad events occur. Listening for in-stream metadata events can vary, depending on the stream format (HLS or DASH), the stream type (Live or VOD stream), your player type, and the type of DAI backend being used. See our Timed Metadata guide for more information.

HLS stream format (Live and VOD streams, HLS.js player)

If you are using an HLS.js player, listen to the HLS.js FRAG_PARSING_METADATA event to get ID3 metadata and pass it to the SDK with StreamManager.processMetadata().

To automatically play the video after everything is loaded and ready, listen to the HLS.js MANIFEST_PARSED event to trigger playback.

function loadStream(streamID) {
  hls.loadSource(url);
  hls.attachMedia(videoElement);
  
  // Timed metadata is passed HLS stream events to the streamManager.
  hls.on(Hls.Events.FRAG_PARSING_METADATA, parseID3Events);
  hls.on(Hls.Events.MANIFEST_PARSED, startPlayback);
}

function parseID3Events(event, data) {
  if (streamManager && data) {
    // For each ID3 tag in the metadata, pass in the type - ID3, the
    // tag data (a byte array), and the presentation timestamp (PTS).
    data.samples.forEach((sample) => {
      streamManager.processMetadata('ID3', sample.data, sample.pts);
    });
  }
}

function startPlayback() {
  console.log('Video Play');
  videoElement.play();
}

DASH.js (DASH streams format, Live and VOD stream type)

If you are using a DASH.js player, you have to use different strings to listen for ID3 metadata for Live or VOD streams:

  • Livestreams: 'https://developer.apple.com/streaming/emsg-id3'
  • VOD streams: 'urn:google:dai:2018'

Pass the ID3 metadata to the SDK with StreamManager.processMetadata().

To automatically show the video controls after everything is loaded and ready, listen to the DASH.js MANIFEST_LOADED event.

const googleLiveSchema = 'https://developer.apple.com/streaming/emsg-id3';
const googleVodSchema = 'urn:google:dai:2018';
dashPlayer.on(googleLiveSchema, processMetadata);
dashPlayer.on(googleVodSchema, processMetadata);
dashPlayer.on(dashjs.MediaPlayer.events.MANIFEST_LOADED, loadlistener);

function processMetadata(metadataEvent) {
  const messageData = metadataEvent.event.messageData;
  const timestamp = metadataEvent.event.calculatedPresentationTime;

  // Use StreamManager.processMetadata() if your video player provides raw
  // ID3 tags, as with dash.js.
  streamManager.processMetadata('ID3', messageData, timestamp);
}

function loadlistener() {
  showControls();

  // This listener must be removed, otherwise it triggers as addional
  // manifests are loaded. The manifest is loaded once for the content,
  // but additional manifests are loaded for upcoming ad breaks.
  dashPlayer.off(dashjs.MediaPlayer.events.MANIFEST_LOADED, loadlistener);
}

Shaka Player with livestreams (DASH streams format)

If you are using Shaka player for livestream playback, use the string 'emsg' to listen for metadata events. Then, use the event message data in your call to StreamManager.onTimedMetadata().

shakaPlayer.addEventListener('emsg', (event) => onEmsgEvent(event));

function onEmsgEvent(metadataEvent) {
  // Use StreamManager.onTimedMetadata() if your video player provides
  // processed metadata, as with Shaka player livestreams.
  streamManager.onTimedMetadata({'TXXX': metadataEvent.detail.messageData});
}

Shaka Player with VOD streams (DASH streams format)

If you are using Shaka player for VOD stream playback, use the string 'timelineregionenter' to listen for metadata events. Then, use the event message data in your call to StreamManager.processMetadata() with the string 'urn:google:dai:2018'.

shakaPlayer.addEventListener('timelineregionenter', (event) => onTimelineEvent(event));

function onTimelineEvent(metadataEvent) {
  const detail = metadataEvent.detail;
  if ( detail.eventElement.attributes &&
       detail.eventElement.attributes['messageData'] &&
       detail.eventElement.attributes['messageData'].value ) {
        const mediaId = detail.eventElement.attributes['messageData'].value;
        const pts = detail.startTime;
        // Use StreamManager.processMetadata() if your video player provides raw
        // ID3 tags, as with Shaka player VOD streams.
        streamManager.processMetadata('urn:google:dai:2018', mediaId, pts);
       }
}

Handle player events

Add event listeners to the video element's pause and start events to allow the user to resume playback when the SDK pauses during ad breaks.

function loadStream(streamUrl) {
  ...
  
  videoElement.addEventListener('pause', onStreamPause);
  videoElement.addEventListener('play', onStreamPlay);
}

function onStreamPause() {
  console.log('paused');
  if (isAdBreak) {
    videoElement.controls = true;
    adUiElement.style.display = 'none';
  }
}

function onStreamPlay() {
  console.log('played');
  if (isAdBreak) {
    videoElement.controls = false;
    adUiElement.style.display = 'block';
  }
}

Clean up IMA DAI assets

When you have successfully finished requesting and displaying ads in a Pod Serving stream with IMA DAI SDK, we suggest you clean up any resources after the Pod Serving session is complete. Call StreamManager.destroy() to stop stream playback, stop all ad tracking, and release all of the loaded stream assets.

To learn about more advanced SDK features, see the other guides or the samples on GitHub.