借助 IMA SDK,您可以轻松地将多媒体广告集成到您的网站和应用中。IMA SDK 可以从任何 符合 VAST 标准的广告服务器请求广告,并在您的应用中管理广告播放。借助 IMA DAI SDK,应用可针对广告和内容视频(VOD 或直播内容)发出视频流请求。然后,SDK 会返回合并的视频流,因此您无需在应用中管理广告和内容视频之间的切换。
本指南演示了如何将 IMA SDK 集成到简单的视频播放器应用中。如果您想查看或遵循已完成的示例集成,请从 GitHub 下载基本示例。
IMA DAI 概览
实现 IMA DAI 涉及两个主要 SDK 组件,本指南对此进行了演示:
StreamRequest
:一个定义流请求的对象。流请求可以是视频点播请求,也可以是直播请求。请求会指定内容 ID、API 密钥或身份验证令牌和其他参数。StreamManager
:用于处理动态广告插播流以及与 DAI 后端的互动的对象。视频流管理器还会处理对 ping 的跟踪,并将视频流和广告事件转发给发布商。
前提条件
在开始之前,您需要:
- 仔细阅读我们的兼容性页面,确保您的预期用例受支持。
- 下载我们的 Roku 示例播放器代码。
- 将上面的示例播放器代码部署到 Roku 设备,以验证您的开发设置是否正常运行。
播放视频
所提供的示例视频播放器可直接播放内容视频。将示例播放器部署到 Roku 播放器,以确保正确设置您的开发环境。
将您的视频播放器转换为 IMA 动态广告插播流式播放器
创建 Sdk.xml
将 MainScene.xml
与名为 Sdk.xml
的新文件一起添加到您的项目中,并添加以下样板:
Sdk.xml
<?xml version = "1.0" encoding = "utf-8" ?> <component name = "imasdk" extends = "Task"> <interface> </interface> <script type = "text/brightscript"> <![CDATA[ ' Your code goes here. ]]> </script> </component>
在本指南中,您需要修改这两个文件。每个代码段上方的标题会指示您需要将该代码段添加到哪个文件中。
加载 Roku 广告框架
IMA SDK 依赖于 Roku 广告框架。如需加载框架,请将以下代码添加到 manifest
和 Sdk.xml
:
清单
bs_libs_required=roku_ads_lib,googleima3
Sdk.xml
Library "Roku_Ads.brs" Library "IMA3.brs"
加载 IMA SDK
加载 IMA 动态广告插播数据流的第一步是加载并初始化 IMA SDK。以下代码会加载 IMA SDK 脚本。
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
现在,在 MainScene.xml
中启动此任务,并移除加载内容流的调用。
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
创建 IMA 流媒体播放器
接下来,您需要使用现有的 roVideoScreen
创建 IMA 流媒体播放器。此流播放器实现了三种回调方法:loadUrl
、adBreakStarted
和 adBreakEnded
。此外,还要在视频流加载时停用特技播放。这样可以防止用户在前贴片广告开始播放的那一刻,在广告插播开始事件触发之前跳过前贴片广告。
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
创建和执行数据流请求
现在您已经有了流播放器,接下来您可以创建和执行流请求了。此示例包含直播和点播视频流的数据。目前正在使用 VOD 视频流。
如需使用直播而非 VOD,请将 selectedStream
从 m.testVodStream
更改为 m.testLiveStream
。
为了能够支持 AdUI(例如 adChoices 图标),您还必须在请求中传递对包含内容视频的节点的引用。
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: "2528370", 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 = {} streamData = m.top.streamData if streamData.type = "live" request = sdk.CreateLiveStreamRequest(streamData.assetKey, streamData.apiKey) else if streamData.type = "vod" request = sdk.CreateVodStreamRequest(streamData.contentSourceId, streamData.videoId, streamData.apiKey) else request = sdk.CreateStreamRequest() end if request.player = m.player request.videoObject = m.top.video ' Required to support UI elements for 'Why This Ad?' and skippability request.adUiNode = m.top.video 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
添加事件监听器并启动数据流
请求视频流后,只需添加事件监听器即可跟踪广告进度、启动视频流,以及将 Roku 消息转发到 SDK。请务必向 SDK 转发所有消息,以确保广告正常播放。
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
添加对可跳过广告的支持(可选)
为了支持可跳过式广告,您需要向 IMA SDK 的 player 对象添加一个 seek
方法,该方法会以程序化方式将视频定位到指定位置(以浮点数秒为单位)。
Sdk.xml
... m.player.loadUrl = Function(urlData) m.top.video.enableTrickPlay = false m.top.urlData = urlData End Function m.player.seek = Function(timeSeconds as Float) print "---- SDK requested seek to ----" ; timeSeconds m.top.video.seekMode = "accurate" m.top.video.seek = timeSeconds End Function m.player.adBreakStarted = Function(adBreakInfo as Object) print "---- Ad Break Started ---- " m.top.adPlaying = True m.top.video.enableTrickPlay = false End Function ...