借助 IMA SDK,您可以轻松将多媒体广告集成到您的网站和应用中。IMA SDK 可从任何 符合 VAST 标准的广告服务器请求广告,并管理您应用中的广告播放。借助 IMA DAI SDK,应用可以针对广告和内容视频(VOD 或直播内容)发出流式传输请求。然后,SDK 会返回一个合并的视频串流,这样您就不必在应用中管理广告视频和内容视频之间的切换。
选择您感兴趣的 DAI 解决方案
全方位 DAI
本指南演示了如何将 IMA DAI SDK 集成到简单的视频播放器应用中。如果您想要查看已完成的示例集成或了解已完成的示例集成,请从 GitHub 下载基本示例。
IMA DAI 概览
实现 IMA DAI 涉及两个主要 SDK 组件,如本指南中所示:
StreamRequest
:用于定义数据流请求的对象。流式传输请求可以是视频点播或直播。请求中会指定内容 ID,以及 API 密钥或身份验证令牌和其他参数。StreamManager
:一种对象,用于处理动态广告插播数据流以及与 DAI 后端的互动。直播管理器还会处理跟踪 ping,并将直播和广告事件转发给发布商。
前提条件
- 请仔细阅读我们的兼容性页面,确保您的预期用例受支持。
- 下载我们的 Roku 示例播放器代码
- 将示例播放器代码部署到 Roku 设备,以验证您的开发设置是否有效。
播放视频
提供的示例视频播放器会直接播放内容视频。将示例播放器部署到 Roku 播放器,以确保您的开发环境设置正确无误。
将视频播放器转换为 IMA DAI 流式播放器
请按照以下步骤实现流式播放器。
创建 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 DAI SDK 依赖于 Roku 广告框架。如需加载框架,请将以下代码添加到 manifest
和 Sdk.xml
:
清单
bs_libs_required=roku_ads_lib,googleima3
Sdk.xml
Library "Roku_Ads.brs"
Library "IMA3.brs"
加载 IMA DAI SDK
加载 IMA 动态广告插播流的第一步是加载并初始化 IMA DAI SDK。以下代码会加载 IMA DAI 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(例如“广告选项”图标),您还必须在请求中传递指向包含内容视频的节点的引用。
MainScene.xml
function init()
m.video = m.top.findNode("myVideo")
m.video.notificationinterval = 1
m.testLiveStream = {
title: "Livestream",
assetKey: "sN_IYUG8STe1ZzhIIE_ksA",
apiKey: "",
type: "live"
}
m.testVodStream = {
title: "VOD stream"
contentSourceId: "2548831",
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。
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 DAI SDK 的player 对象添加 seek
方法,以便以浮点秒数的形式以编程方式将视频跳转到指定位置。
如需支持可跳过的广告,您还必须确保在请求中设置 adUiNode
。
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