# Google IMA DAI SDK Roku - StreamManager Guide For Google full-service DAI, use `CreateLiveStreamRequest` to request a livestream and `CreateVodStreamRequest` to request a VOD stream. ## Table of Contents * [Import the IMA DAI SDK](#import-the-ima-dai-sdk) (Line 21) * [SDK Initialization](#sdk-initialization) (Line 43) * [Video Player Setup](#video-player-setup) (Line 54) * [Make Stream Requests](#make-stream-requests) (Line 87) * [Request a livestream](#request-a-livestream) (Line 89) * [Request a VOD stream](#request-a-vod-stream) (Line 105) * [Execute stream request](#execute-stream-request) (Line 126) * [Start Stream Playback](#start-stream-playback) (Line 153) * [Timed Metadata Forwarding](#timed-metadata-forwarding) (Line 177) * [Listen to Ad Events](#listen-to-ad-events) (Line 205) * [Skippable Ads Support](#skippable-ads-support) (Line 244) * [Reference Implementation](#reference-implementation) (Line 256) ## Import the IMA DAI SDK Add the required libraries to `manifest`: ``` bs_libs_required=roku_ads_lib,googleima3 ``` Create a Task component `components/Sdk.xml` to load libraries and run the SDK on a background thread: ```xml ``` ## SDK Initialization Initialize the IMA SDK instance using `New_IMASDK()`: ```brightscript if m.sdk = invalid m.sdk = New_IMASDK() m.sdk.initSdk() end if ``` ## Video Player Setup Create the player instance with `sdk.createPlayer()`. ```brightscript m.player = m.sdk.createPlayer() m.player.top = m.top ``` Create ad break callbacks: ```brightscript m.player.loadUrl = Function(urlData) m.top.video.enableTrickPlay = false m.top.urlData = urlData End Function m.player.adBreakStarted = Function(adBreakInfo as Object) m.top.adPlaying = true m.top.video.enableTrickPlay = false End Function m.player.adBreakEnded = Function(adBreakInfo as Object) m.top.adPlaying = false m.top.video.enableTrickPlay = true End Function m.player.seek = Function(timeSeconds as Double) m.top.video.seekMode = "accurate" m.top.video.seek = timeSeconds End Function ``` ## Make Stream Requests ### Request a livestream ```brightscript streamRequest = m.sdk.CreateLiveStreamRequest( , "", // Replace the empty string with a Google DAI API key if the app use one ) ``` Provide the following parameters: * ****: The Google Ad Manager network code. * ****: The livestream asset key configured in Google Ad Manager. ### Request a VOD stream ```brightscript streamRequest = m.sdk.CreateVodStreamRequest( , , "", // Replace the empty string with a Google DAI API key if the app use one ) ``` Provide the following parameters: * ****: The Google Ad Manager network code. * ****: The content source ID (CMS ID) in Google Ad Manager. * ****: The video ID in the CMS. For testing purposes, use values of DAI sample streams from https://developers.google.com/ad-manager/dynamic-ad-insertion/streams.md.txt?utm_source=agent-skills&utm_medium=content&utm_campaign=adr-ss-ai&utm_content=ima-dai-sdk ### Execute stream request Pass the player object and video node reference (`adUiNode`) to the request. ```brightscript streamRequest.player = m.player streamRequest.adUiNode = m.top.findNode("myVideo") requestResult = m.sdk.requestStream(streamRequest) If requestResult <> Invalid print "Error requesting stream ";requestResult Else m.streamManager = Invalid While m.streamManager = Invalid sleep(50) m.streamManager = m.sdk.getStreamManager() End While If m.streamManager = Invalid or (m.streamManager["type"] <> Invalid and m.streamManager["type"] = "error") errors = CreateObject("roArray", 1, True) print "error ";m.streamManager["info"] errors.push(m.streamManager["info"]) m.top.errors = errors Else m.streamManager.start() End If ``` ## Start Stream Playback Listen for the stream manifest data in `MainScene.xml` and pass it to the `Video` node: ```brightscript m.sdkTask.observeField("urlData", "urlLoadRequested") ' Setting control to run starts the task thread. m.sdkTask.control = "RUN" Sub urlLoadRequested(message as Object) data = message.getData() vidContent = createObject("RoSGNode", "ContentNode") vidContent.url = data.manifest vidContent.title = m.videoTitle vidContent.streamformat = data.format m.video.content = vidContent m.video.setFocus(true) m.video.visible = true m.video.control = "play" m.video.EnableCookies() End Sub ``` ## Timed Metadata Forwarding Forward all timed metadata and video node events to `StreamManager.onMessage(msg)` during stream playback: ```brightscript m.top.video.timedMetaDataSelectionKeys = ["*"] m.port = CreateObject("roMessagePort") fields = m.top.video.getFields() for each field in fields m.top.video.observeField(field, m.port) end for while true msg = wait(1000, m.port) if m.top.video = invalid exit while end if m.streamManager.onMessage(msg) currentTime = m.top.video.position if currentTime > 3 and not m.top.adPlaying m.top.video.enableTrickPlay = true end if end while ``` ## Listen to Ad Events Register event listeners on `m.streamManager` to monitor ad lifecycle and error events: ```brightscript m.streamManager.addEventListener(m.sdk.AdEvent.ERROR, errorCallback) m.streamManager.addEventListener(m.sdk.AdEvent.START, startCallback) m.streamManager.addEventListener(m.sdk.AdEvent.FIRST_QUARTILE, firstQuartileCallback) m.streamManager.addEventListener(m.sdk.AdEvent.MIDPOINT, midpointCallback) m.streamManager.addEventListener(m.sdk.AdEvent.THIRD_QUARTILE, thirdQuartileCallback) m.streamManager.addEventListener(m.sdk.AdEvent.COMPLETE, completeCallback) Function startCallback(ad as Object) as Void print "Ad event: START" End Function Function firstQuartileCallback(ad as Object) as Void print "Ad event: FIRST_QUARTILE" End Function Function midpointCallback(ad as Object) as Void print "Ad event: MIDPOINT" End Function Function thirdQuartileCallback(ad as Object) as Void print "Ad event: THIRD_QUARTILE" End Function Function completeCallback(ad as Object) as Void print "Ad event: COMPLETE" End Function Function errorCallback(error as Object) as Void print "Ad event: ERROR - "; error m.errorState = true End Function ``` ### Skippable Ads Support To support skippable ads, implement the `seek` callback method on `m.player` and ensure `streamRequest.adUiNode` is set to the video node in the stream request: ```brightscript m.player.seek = Function(timeSeconds as Double) m.top.video.seekMode = "accurate" m.top.video.seek = timeSeconds End Function ``` ## Reference Implementation BasicExample: * [Sdk.xml](https://raw.githubusercontent.com/googleads/googleads-ima-roku-dai/refs/heads/main/basic_example/components/Sdk.xml) * [MainScene.xml](https://raw.githubusercontent.com/googleads/googleads-ima-roku-dai/refs/heads/main/basic_example/components/MainScene.xml)