This guide demonstrates how to use the IMA DAI SDK for CAF Web Receivers to request and play a live stream for an event registered with the Google Cloud Video Stitcher API, and insert an ad break during playback.
This guide expands on the basic example from the Get started guide, adding support for streams registered with the Google Cloud Video Stitcher API. For a complete understanding of the IMA SDK, refer to that guide.
Ensure your streaming format is supported by CAF web receivers before continuing.
For information on integrating with other platforms or on using the IMA client-side SDKs, see Interactive Media Ads SDKs.
Background
Before using this guide, familiarize yourself with the Chromecast Application Framework's Web Receiver protocol.
This guide assumes a basic level of familiarity with CAF receiver concepts,
such as message interceptors,
[MediaInformation](/cast/docs/reference/web_receiver/cast.framework.messages.MediaInformation)
objects, and using theCast Command and Control tool to emulate a CAF sender.
App components and architecture
Implementing live stream playback with the Google Cloud Video Stitcher API with the IMA CAF DAI SDK involves two main components, which are demonstrated in this guide:
VideoStitcherLiveStreamRequest
: An object that defines a stream request to Google's servers. The request specifies an instance of the Cloud Video Stitcher API, a live config ID, and other optional parameters.[StreamManager] (/interactive-media-ads/docs/sdks/caf-dai/reference/js/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
You need to have a live stream event registered with the Google Cloud Video Stitcher API. Here's how to register one:
- Set up a Google Cloud project, and configure service accounts to access the project.
- Create a configuration for a live stream event using your own content live stream, or a test live stream.
You need the following variables for the IMA SDK:
Live Config ID - This is the live config ID you specified when creating your Video Stitcher API live config.
LIVE_CONFIG_ID
Region - The Google Cloud region where your Live Config was created.
REGION
Project Number - The Google Cloud project number using the Video Stitcher API.
PROJECT_NUMBER
OAuth Token - A service account's short lived OAuth Token with the Video Stitcher user role. Read more about creating short-lived credentials for service accounts.
OAUTH_TOKEN
Network Code - Google Ad Manager network code for requesting ads
NETWORK_CODE
Custom Asset Key - Google Ad Manager custom asset key generated during the process of creating a configuration for a live stream event with the Video Stitcher API.
CUSTOM_ASSET_KEY
You need the following for a custom Cast receiver:
A Cast Developer Console account with allowlisted test devices.
A hosted web receiver app that is registered with your Cast Developer Console, and which can be modified to host the code provided by this guide.
A sending app configured to use your web receiver app. For the purposes of this example, this guide uses the Cast Command and Control tool as the sender.
Prepare a sender to pass stream data to the receiver
First, configure your sender app to make a load request to your web receiver,
containing the following fields in your platform's [MediaInformation]
(/cast/docs/reference/web_receiver/cast.framework.messages.MediaInformation)
object.
Field | Contents | ||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
contentId
|
A unique identifier for this media item, as defined in the Cast reference documentation. This ID shouldn't be reused for multiple items in the same media queue.
|
||||||||||||||
contentUrl
|
Optional Backup stream URL to play if the DAI stream fails to load.
|
||||||||||||||
contentType
|
Optional Mimetype of the backup stream URL to play if the DAI stream fails to load.
|
||||||||||||||
streamType
|
The string literal or constant used for this value varies by sender platform. See the examples below for specific values.
|
||||||||||||||
customData
|
The customData field contains a key-value store of additional required fields. In this case, customData contains the DAI stream data that you collected.
|
Here are some code samples to help you get started:
Web
To configure these values in a Cast web sender, first create a MediaInfo object with the required data, then make a load request to the web receiver.
// ... // create mediaInfo object const mediaInfo = new chrome.cast.media.MediaInfo("CONTENT_ID"); mediaInfo.contentUrl = "BACKUP_STREAM_URL"; mediaInfo.contentType = "BACKUP_STREAM_MIMETYPE"; mediaInfo.streamType = chrome.cast.media.StreamType.LIVE; mediaInfo.customData = { liveConfigID: "LIVE_CONFIG_ID", region: "REGION", projectNumber: "PROJECT_NUMBER", oAuthToken: "OAUTH_TOKEN", networkCode: "NETWORK_CODE", customAssetKey: "CUSTOM_ASSET_KEY" }; // Make load request to cast web receiver const castSession = cast.framework.CastContext.getInstance().getCurrentSession(); const request = new chrome.cast.media.LoadRequest(mediaInfo); castSession.loadMedia(request).then( () => { console.log('Load succeed'); }, (errorCode) => { console.log('Error code: ' + errorCode); }); // ...
Android
To configure these values in a Cast web sender, first create a MediaInfo object with the required data, then make a load request to the web receiver.
// ... JSONObject customData = new JSONObject() .put("liveConfigID", "LIVE_CONFIG_ID") .put("region", "REGION") .put("projectNumber", "PROJECT_NUMBER") .put("oAuthToken", "OAUTH_TOKEN") .put("networkCode", "NETWORK_CODE") .put("customAssetKey", "CUSTOM_ASSET_KEY"); MediaInfo mediaInfo = MediaInfo.Builder("CONTENT_ID") .setContentUrl("BACKUP_STREAM_URL") .setContentType("BACKUP_STREAM_MIMETYPE") .setStreamType(MediaInfo.STREAM_TYPE_LIVE) .setCustomData(customData) .build(); RemoteMediaClient remoteMediaClient = mCastSession.getRemoteMediaClient(); remoteMediaClient.load(new MediaLoadRequestData.Builder().setMediaInfo(mediaInfo).build()); // ...
iOS Objective-C
To configure these values in a Cast web sender, first create a GCKMediaInformation object with the required data, then make a load request to the web receiver.
// ... NSURL url = [NSURL URLWithString:@"BACKUP_STREAM_URL"]; NSDictionary *customData = @{ @"liveConfigID": @"LIVE_CONFIG_ID", @"region": @"REGION", @"projectNumber": @"PROJECT_NUMBER", @"oAuthToken": @"OAUTH_TOKEN", @"networkCode": @"NETWORK_CODE", @"customAssetKey": @"CUSTOM_ASSET_KEY" }; GCKMediaInformationBuilder *mediaInfoBuilder = [[GCKMediaInformationBuilder alloc] initWithContentID: @"CONTENT_ID"]; mediaInfoBuilder.contentURL = url; mediaInfoBuilder.contentType = @"BACKUP_STREAM_MIMETYPE"; mediaInfoBuilder.streamType = GCKMediaStreamTypeLive; mediaInfoBuilder.customData = customData; self.mediaInformation = [mediaInfoBuilder build]; GCKRequest *request = [self.sessionManager.currentSession.remoteMediaClient loadMedia:self.mediaInformation]; if (request != nil) { request.delegate = self; } // ...
iOS Swift
To configure these values in a Cast web sender, first create a GCKMediaInformation object with the required data, then make a load request to the web receiver.
// ... let url = URL.init(string: "BACKUP_STREAM_URL") guard let mediaURL = url else { print("invalid mediaURL") return } let customData = [ "liveConfigID": "LIVE_CONFIG_ID", "region": "REGION", "projectNumber": "PROJECT_NUMBER", "oAuthToken": "OAUTH_TOKEN", "networkCode": "NETWORK_CODE", "customAssetKey": "CUSTOM_ASSET_KEY" ] let mediaInfoBuilder = GCKMediaInformationBuilder.init(contentId: "CONTENT_ID") mediaInfoBuilder.contentURL = mediaUrl mediaInfoBuilder.contentType = "BACKUP_STREAM_MIMETYPE" mediaInfoBuilder.streamType = GCKMediaStreamType.Live mediaInfoBuilder.customData = customData mediaInformation = mediaInfoBuilder.build() guard let mediaInfo = mediaInformation else { print("invalid mediaInformation") return } if let request = sessionManager.currentSession?.remoteMediaClient?.loadMedia(mediaInfo) { request.delegate = self } // ...
CAC tool
To configure these values in the Cast Command and Control tool, click the Load Media tab, and set the custom load request type to LOAD. Then replace the JSON data in the text area with this JSON:
{ "media": { "contentId": "CONTENT_ID", "contentUrl": "BACKUP_STREAM_URL", "contentType": "BACKUP_STREAM_MIMETYPE", "streamType": "LIVE", "customData": { "liveConfigID": "LIVE_CONFIG_ID", "region": "REGION", "projectNumber": "PROJECT_NUMBER", "oAuthToken": "OAUTH_TOKEN", "networkCode": "NETWORK_CODE", "customAssetKey": "CUSTOM_ASSET_KEY" } } }
This custom load request can be sent to the receiver to test the rest of the steps.
Create a custom CAF web receiver
Create a custom web receiver, as seen in the CAF SDK Custom Web Receiver Guide.
Your receiver's code should look like the following:
<html>
<head>
<script
src="//www.gstatic.com/cast/sdk/libs/caf_receiver/v3/cast_receiver_framework.js">
</script>
</head>
<body>
<cast-media-player></cast-media-player>
<script>
const castContext = cast.framework.CastReceiverContext.getInstance()
castContext.start();
</script>
</body>
</html>
Import the IMA DAI SDK and get the Player Manager
Add a script tag to import the IMA DAI SDK for CAF to your web receiver, just after the script loading CAF. Then, in the script tag below store the receiver context and player manager as constants before starting the receiver.
<html>
<head>
<script
src="//www.gstatic.com/cast/sdk/libs/caf_receiver/v3/cast_receiver_framework.js"></script>
<script src="//imasdk.googleapis.com/js/sdkloader/cast_dai.js"></script>
</head>
<body>
<cast-media-player></cast-media-player>
<script>
const castContext = cast.framework.CastReceiverContext.getInstance();
const playerManager = castContext.getPlayerManager();
castContext.start();
</script>
</body>
</html>
Initialize the IMA Stream Manager
Initialize the IMA Stream Manager.
<html>
<head>
<script type="text/javascript"
src="//www.gstatic.com/cast/sdk/libs/caf_receiver/v3/cast_receiver_framework.js"></script>
<script src="//imasdk.googleapis.com/js/sdkloader/cast_dai.js"></script>
</head>
<body>
<cast-media-player></cast-media-player>
<script>
const castContext = cast.framework.CastReceiverContext.getInstance();
const playerManager = castContext.getPlayerManager();
const streamManager = new google.ima.cast.dai.api.StreamManager();
castContext.start();
</script>
</body>
</html>
Create the Stream Manager Load Interceptor
Before your media items are passed to CAF, create your stream request in a LOAD message interceptor.
// ...
const castContext = cast.framework.CastReceiverContext.getInstance();
const playerManager = castContext.getPlayerManager();
const streamManager = new google.ima.cast.dai.api.StreamManager();
/**
* Creates a live stream request object for the Video Stitcher API.
* @param {!LoadRequestData} castRequest The request object from the cast sender
* @return {StreamRequest} an IMA stream request
*/
const createStreamRequest = (castRequest) => { /* ... */};
/**
* Initates a DAI stream request for the final stream manifest.
* @param {!LoadRequestData} castRequest The request object from the cast sender
* @return {Promise<LoadRequestData>} a promise that resolves to an updated castRequest, containing the DAI stream manifest
*/
const createDAICastRequest = (castRequest) => {
return streamManager.requestStream(castRequest, createStreamRequest(castRequest))
.then((castRequestWithStreamData) => {
console.log('Successfully made DAI stream request.');
return castRequestWithStreamData;
})
.catch((error) => {
console.log('Failed to make DAI stream request.');
// CAF will automatically fallback to the content URL
// that it can read from the castRequest object.
return castRequest;
});
};
playerManager.setMessageInterceptor(
cast.framework.messages.MessageType.LOAD, createDAICastRequest);
castContext.start();
// ...
Create the stream request
Complete the createStreamRequest
function to create a Video Stitcher API live
stream request, based on the CAF load request.
// ...
/**
* Creates a live stream request object for the Video Stitcher API.
* @param {!LoadRequestData} castRequest The request object from the cast sender
* @return {StreamRequest} an IMA stream request
*/
const createStreamRequest = (castRequest) => {
const streamRequest = new google.ima.cast.dai.api.VideoStitcherLiveStreamRequest();
const customData = castRequest.media.customData;
streamRequest.liveStreamEventId = customData.liveConfigID;
streamRequest.region = customData.region;
streamRequest.projectNumber = customData.projectNumber;
streamRequest.oAuthToken = customData.oAuthToken;
streamRequest.networkCode = customData.networkCode;
streamRequest.customAssetKey = customData.customAssetKey;
return streamRequest;
};
// ...