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. If you would like to view or follow along with 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 thePodStreamRequest
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.
Using a command line, from the directory that contains your
index.html
file run:python -m http.server 8000
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 simple video player
First, modify dai.html to create a simple 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';
}
}
That's it! You're now requesting and displaying ads in a pod serving stream with the IMA DAI SDK for HTML5. To learn about more advanced SDK features, see the other guides or the samples on GitHub.