Prerequisites
Before you begin, you'll need to:
- Read through our compatibility page to make sure your intended use case is supported.
- Obtain our Roku sample player code.
- Deploy the above sample player code to a Roku device to verify that your development set up is working.
Play your video
The sample video player provided will play a content video out of the box. Deploy the sample player to your Roku player to ensure your development environment is set up properly.
Turn your video player into an IMA Dynamic Ad Insertion stream player
Create Sdk.xml
Add a new file to your project alongside MainScene.xml
called Sdk.xml
,
and add the following boilerplate:
Sdk.xml
<?xml version = "1.0" encoding = "utf-8" ?> <component name = "imasdk" extends = "Task"> <interface> </interface> <script type = "text/brightscript"> <![CDATA[ ' Your code will go here. ]]> </script> </component>
You'll be editing both of these files throughout this guide. A heading above each code snippet will indicate in which file you need to add that snippet.
Load the Roku Advertising Framework
The IMA SDK depends on the Roku Advertising Framework. To load the framework, add the following
to manifest
and Sdk.xml
:
manifest
bs_libs_required=roku_ads_lib,googleima3
Sdk.xml
Library "Roku_Ads.brs" Library "IMA3.brs"
Load the IMA SDK
The first step to loading your IMA Dynamic Ad Insertion stream is to load and initialize the IMA SDK. The following loads the IMA SDK script.
Sdk.xml
<interface> <field id="sdkLoaded" type="Boolean" /> <field id="errors" type="stringarray" /> </interface>
sub init() m.top.functionName = "runThread" End Sub sub runThread() if not m.top.sdkLoaded loadSdk() End If End Sub sub loadSdk() If m.sdk = invalid m.sdk = New_IMASDK() End If m.top.sdkLoaded = true End Sub
Now start this task in MainScene.xml
and remove the call to load the content
stream.
MainScene.xml
function init() m.video = m.top.findNode("myVideo") m.video.notificationinterval = 1 loadImaSdk() end function function loadImaSdk() as void m.sdkTask = createObject("roSGNode", "imasdk") m.sdkTask.observeField("sdkLoaded", "onSdkLoaded") m.sdkTask.observeField("errors", "onSdkLoadedError") m.sdkTask.control = "RUN" end function Sub onSdkLoaded(message as Object) print "----- onSdkLoaded --- control ";message End Sub Sub onSdkLoadedError(message as Object) print "----- errors in the sdk loading process --- ";message End Sub
Create an IMA Stream Player
Next, you'll need to use your existing roVideoScreen
to create an IMA stream player.
This stream player implements three callback methods: loadUrl
,
adBreakStarted
, and adBreakEnded
. Also note that we disable trick play
when the stream is loaded. This prevents users from skipping a pre-roll in the instant that it
starts, before the ad break started event is fired.
Sdk.xml
<interface> <field id="sdkLoaded" type="Boolean" /> <field id="errors" type="stringarray" /> <field id="urlData" type="assocarray" /> <field id="adPlaying" type="Boolean" /> <field id="video" type="Node" /> </interface> ... sub setupVideoPlayer() sdk = m.sdk m.player = sdk.createPlayer() m.player.top = m.top m.player.loadUrl = Function(urlData) m.top.video.enableTrickPlay = false m.top.urlData = urlData End Function m.player.adBreakStarted = Function(adBreakInfo as Object) print "---- Ad Break Started ---- " m.top.adPlaying = True m.top.video.enableTrickPlay = false End Function m.player.adBreakEnded = Function(adBreakInfo as Object) print "---- Ad Break Ended ---- " m.top.adPlaying = False m.top.video.enableTrickPlay = true End Function End Sub
Create and execute a stream request
Now that you have a stream player, you can create and execute a stream request.
Here we have data for a live stream and a VOD stream. Currently the VOD stream is being used.
To use live instead of VOD, change selectedStream
from m.testVodStream
to
m.testLiveStream
.
MainScene.xml
function init() m.video = m.top.findNode("myVideo") m.video.notificationinterval = 1 m.testLiveStream = { title: "Live Stream", assetKey: "sN_IYUG8STe1ZzhIIE_ksA", apiKey: "", type: "live" } m.testVodStream = { title: "VOD stream" contentSourceId: "19463", videoId: "tears-of-steel", apiKey: "", type: "vod" } loadImaSdk() end function function loadImaSdk() as void m.sdkTask = createObject("roSGNode", "imasdk") m.sdkTask.observeField("sdkLoaded", "onSdkLoaded") m.sdkTask.observeField("errors", "onSdkLoadedError") selectedStream = m.testVodStream m.videoTitle = selectedStream.title m.sdkTask.streamData = selectedStream m.sdkTask.video = m.video m.sdkTask.control = "RUN" end function
Sdk.xml
<interface> <field id="sdkLoaded" type="Boolean" /> <field id="errors" type="stringarray" /> <field id="urlData" type="assocarray" /> <field id="adPlaying" type="Boolean" /> <field id="video" type="Node" /> <field id="streamData" type="assocarray" /> <field id="streamManagerReady" type="Boolean" /> </interface>
sub runThread() if not m.top.sdkLoaded loadSdk() End If if not m.top.streamManagerReady loadStream() End If End Sub Sub loadStream() sdk = m.sdk sdk.initSdk() setupVideoPlayer() request = sdk.CreateStreamRequest() if m.top.streamData.type = "live" request.assetKey = m.top.streamData.assetKey else request.contentSourceId = m.top.streamData.contentSourceId request.videoId = m.top.streamData.videoId end if request.apiKey = m.top.streamData.apiKey request.player = m.player requestResult = sdk.requestStream(request) If requestResult <> Invalid print "Error requesting stream ";requestResult Else m.streamManager = Invalid While m.streamManager = Invalid sleep(50) m.streamManager = sdk.getStreamManager() End While If m.streamManager = Invalid or m.streamManager["type"] <> Invalid or 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.top.streamManagerReady = True addCallbacks() m.streamManager.start() End If End If End Sub
Add event listeners and start the stream
After requesting your stream, there are only a few things left to do: add event listeners to track ad progress, start your stream, and forward Roku messages to the SDK. It is extremely important that you forward all messages to the SDK to ensure correct ad playback.
MainScene.xml
function loadImaSdk() as void m.sdkTask = createObject("roSGNode", "imasdk") m.sdkTask.observeField("sdkLoaded", "onSdkLoaded") m.sdkTask.observeField("errors", "onSdkLoadedError") selectedStream = m.testVodStream m.videoTitle = selectedStream.title m.sdkTask.streamData = selectedStream m.sdkTask.observeField("urlData", "urlLoadRequested") m.sdkTask.video = m.video m.sdkTask.control = "RUN" end function Sub urlLoadRequested(message as Object) print "Url Load Requested ";message data = message.getData() playStream(data.manifest) End Sub Sub playStream(url as Object) vidContent = createObject("RoSGNode", "ContentNode") vidContent.url = url vidContent.title = m.videoTitle vidContent.streamformat = "hls" m.video.content = vidContent m.video.setFocus(true) m.video.visible = true m.video.control = "play" m.video.EnableCookies() End Sub
Sdk.xml
sub runThread() if not m.top.sdkLoaded loadSdk() End If if not m.top.streamManagerReady loadStream() End If If m.top.streamManagerReady runLoop() End If End Sub Sub runLoop() m.top.video.timedMetaDataSelectionKeys = ["*"] m.port = CreateObject("roMessagePort") ' Listen to all fields. ' IMPORTANT: Failure to listen to the position and timedmetadata fields ' could result in ad impressions not being reported. 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 print "exiting" 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 End Sub Function addCallbacks() as Void 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) End Function Function startCallback(ad as Object) as Void print "Callback from SDK -- Start called - " End Function Function firstQuartileCallback(ad as Object) as Void print "Callback from SDK -- First quartile called - " End Function Function midpointCallback(ad as Object) as Void print "Callback from SDK -- Midpoint called - " End Function Function thirdQuartileCallback(ad as Object) as Void print "Callback from SDK -- Third quartile called - " End Function Function completeCallback(ad as Object) as Void print "Callback from SDK -- Complete called - " End Function Function errorCallback(error as Object) as Void print "Callback from SDK -- Error called - "; error m.errorState = True End Function