news 2026/9/13 11:10:25

Google IMA DAI SDK Roku 集成指南:在 SceneGraph 频道中实现动态广告插入

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Google IMA DAI SDK Roku 集成指南:在 SceneGraph 频道中实现动态广告插入

Google IMA DAI SDK Roku 集成指南:在 SceneGraph 频道中实现动态广告插入

【免费下载链接】skillsAgent Skills for Google products and technologies项目地址: https://gitcode.com/GitHub_Trending/skills29/skills

本指南以本仓库 ima-dai-sdk 技能中的 Roku StreamManager 指南 为核心,系统讲解如何在 Roku SceneGraph 频道中接入 Google IMA DAI(Dynamic Ad Insertion,动态广告插入)SDK,实现直播流(livestream)与点播流(VOD)的广告无缝插播。读完本文,你将掌握从 SDK 导入、初始化、发起流请求、启动播放、定时元数据转发到广告事件监听的完整闭环,并了解如何支持可跳过广告(skippable ads)。

一、总体流程概览

Google full-service DAI 的核心思路是:应用不再直接播放内容源,而是向 Google Ad Manager 请求一条"插播过广告"的流地址(HLS/DASH manifest),SDK 负责在流中注入广告,并通过定时元数据(timed metadata)驱动广告生命周期事件。在 Roku 场景下,这一过程通过StreamManager对象串联:New_IMASDK()初始化 SDK,sdk.createPlayer()创建播放器适配层,CreateLiveStreamRequest/CreateVodStreamRequest构造请求,requestStream()发起请求,最后getStreamManager()拿到流管理器并接管后续播放与事件。

仓库中 SKILL.md 给出了跨平台通用工作流:导入 SDK → 初始化 SDK → 添加流事件监听 → 设置定时元数据转发 → 发起流请求 → 流失败或用户离开时清理 SDK 资源。本文按此骨架展开 Roku 平台的完整实现。

二、导入 IMA DAI SDK

2.1 在 manifest 中声明依赖

在 Roku 应用的manifest文件中声明 SDK 所需的 BrightScript 库:

bs_libs_required=roku_ads_lib,googleima3

roku_ads_lib是 Roku 广告库,googleima3是 Google IMA SDK 的 BrightScript 实现,二者缺一不可。

2.2 创建后台 Task 组件加载库

SDK 的请求与播放协调工作应在后台线程执行,避免阻塞主 UI 线程。创建一个继承自Task的组件components/Sdk.xml,用于加载库并运行 SDK:

<component name="imasdk" extends="Task"> <script type="text/brightscript"> <![CDATA[ Library "Roku_Ads.brs" Library "IMA3.brs" ]]> </script> </component>

这里通过 CDATA 包裹Library指令,确保 XML 解析器不会干扰 BrightScript 代码。Task 组件是 Roku SceneGraph 中在独立线程运行的载体,SDK 的全部逻辑都在这条后台线程中执行。

三、SDK 初始化

在 Task 线程中创建 SDK 实例并初始化。用invalid判空实现单例语义,避免重复初始化:

if m.sdk = invalid m.sdk = New_IMASDK() m.sdk.initSdk() end if

New_IMASDK()返回 SDK 单例对象,initSdk()完成内部状态与网络栈的准备。这一步应在发起任何流请求之前完成,与仓库中其他平台指南(如 Web 指南要求尽早实例化StreamManager)的做法一致,目的是让 SDK 有足够时间建立监听与资源。

四、Video Player 适配层设置

4.1 创建播放器实例

通过sdk.createPlayer()创建播放器适配对象,并将m.top(Task 节点的引用)挂载到 player 上,以便后续回调能访问场景图节点:

m.player = m.sdk.createPlayer() m.player.top = m.top

4.2 定义播放控制回调

m.player是 SDK 与你的Video节点之间的桥梁,需要实现以下回调方法,SDK 会在合适的时机调用它们:

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

各回调的职责:

  • loadUrl(urlData):SDK 拿到流 manifest 后回调,把 manifest 数据通过m.top.urlData暴露给场景;同时临时关闭enableTrickPlay(禁止快进/快退),因为此时尚未进入稳定播放状态。
  • adBreakStarted(adBreakInfo):广告时段开始,置m.top.adPlaying = true并禁用 trick play,防止用户在广告期间拖动进度条。
  • adBreakEnded(adBreakInfo):广告时段结束,恢复adPlaying = false与 trick play。
  • seek(timeSeconds):广告需要跳转(例如可跳过广告的跳过行为)时,以"accurate"模式精确 seek 到目标时间点。

五、发起流请求

Roku 平台支持两种 Google full-service DAI 流:直播流(CreateLiveStreamRequest)与点播流(CreateVodStreamRequest)。

5.1 请求直播流

streamRequest = m.sdk.CreateLiveStreamRequest( <ASSET_KEY_PLACEHOLDER>, "", // Replace the empty string with a Google DAI API key if the app use one <NETWORK_CODE_PLACEHOLDER> )

参数说明:

参数含义
<ASSET_KEY_PLACEHOLDER>在 Google Ad Manager 中为直播事件配置的 asset key(素材键),用于唯一标识一条直播流
第二参数Google DAI API key;如果应用使用 API key 则填入,否则传空字符串""
<NETWORK_CODE_PLACEHOLDER>Google Ad Manager 的 network code(网络代码)

5.2 请求 VOD 流

streamRequest = m.sdk.CreateVodStreamRequest( <CONTENT_SOURCE_ID_PLACEHOLDER>, <VIDEO_ID_PLACEHOLDER>, "", // Replace the empty string with a Google DAI API key if the app use one <NETWORK_CODE_PLACEHOLDER> )

参数说明:

参数含义
<CONTENT_SOURCE_ID_PLACEHOLDER>Google Ad Manager 中的 content source ID(CMS ID),标识内容来源
<VIDEO_ID_PLACEHOLDER>该内容在 CMS 中的 video ID
第三参数Google DAI API key,无则传空字符串""
<NETWORK_CODE_PLACEHOLDER>Google Ad Manager 的 network code

测试阶段可以直接使用 Google 官方提供的 DAI 示例流(sample streams)参数值,快速验证整条链路是否打通。

5.3 执行流请求

请求对象需要绑定两个关键引用后调用requestStream()

  • player:即上一步创建的m.player适配对象;
  • adUiNode:场景中的Video节点引用,SDK 依赖它定位广告 UI 与视频节点。
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 End If

这段代码的要点:

  1. requestStream()返回非Invalid表示请求立即失败(例如参数缺失),直接打印错误。
  2. 请求成功后,getStreamManager()可能尚未就绪,因此用sleep(50)循环轮询(最多 50 毫秒间隔)直到拿到流管理器。
  3. 若流管理器类型为"error",把m.streamManager["info"]中的错误信息收集进数组并推送到m.top.errors,交由 UI 层展示。
  4. 一切正常则调用m.streamManager.start()正式启动流会话。

六、启动流播放

SDK 在后台线程解析流 manifest 后,会通过loadUrl回调把数据放到m.top.urlData。在MainScene.xml中观察该字段并驱动Video节点播放:

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

说明:

  • observeField("urlData", "urlLoadRequested")注册字段观察者;将 Task 的control设为"RUN"启动后台线程。
  • 回调中data.manifest是 SDK 重写后的流地址,data.format是流格式(HLS 等)。
  • 将二者写入ContentNode后赋给m.video.content,随后control = "play"开始播放。
  • 调用m.video.EnableCookies()确保播放器在请求流时携带必要的 Cookie(对需要鉴权的流尤为重要)。

七、定时元数据转发(Timed Metadata Forwarding)

DAI 的广告事件完全依赖流中内嵌的定时元数据(HLS 的 ID3 帧或 DASH 的自定义事件)。Roku 上Video节点默认会解析这些元数据,但必须主动把它们转发给StreamManager.onMessage(msg),SDK 才能据此触发广告事件回调。

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

关键点:

  • timedMetaDataSelectionKeys = ["*"]:通配所有定时元数据键,让Video节点产生相应的事件通知。
  • 创建roMessagePort,遍历Video节点所有字段逐一observeField,把事件统一投递到该端口。
  • 事件循环内wait(1000, m.port)阻塞等待事件;把每一条消息交给m.streamManager.onMessage(msg)处理。
  • 播放位置超过 3 秒且当前不在广告时段时恢复enableTrickPlay = true,允许用户操作播放控制。
  • m.top.video = invalid时退出循环,避免节点销毁后继续访问。

八、监听广告事件

m.streamManager上注册事件监听器,即可跟踪广告生命周期与错误。仓库指南提供了从广告开始到结束的完整事件族:

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

事件语义一览:

事件含义典型用途
START广告开始播放记录广告曝光、上报监测
FIRST_QUARTILE广告播放至 25%进度监测/结算
MIDPOINT广告播放至 50%进度监测
THIRD_QUARTILE广告播放至 75%进度监测
COMPLETE广告播放完成上报广告完成、恢复内容
ERROR广告或流发生错误m.errorState、触发降级策略

这些事件对应 Web/HTML5 指南中的STARTED / FIRST_QUARTILE / MIDPOINT / THIRD_QUARTILE / COMPLETE语义(见 web-StreamManager-guide),跨平台命名一致,便于维护多端逻辑。

8.1 可跳过广告支持

要支持可跳过广告(skippable ads),需要满足两个条件:

  1. 实现seek回调:跳过动作本质是一次精确跳转,m.player.seek必须以"accurate"模式驱动Video节点:
  2. 在流请求中设置adUiNode:确保streamRequest.adUiNode = m.top.findNode("myVideo")指向视频节点,SDK 才能把跳过 UI 挂载到正确的节点上。
m.player.seek = Function(timeSeconds as Double) m.top.video.seekMode = "accurate" m.top.video.seek = timeSeconds End Function

其中seekMode = "accurate"让跳转更精确(默认的 fast seek 可能跳过关键帧导致广告切点不准)。

九、错误处理与资源清理

从本文的请求与播放流程可以看到,错误处理贯穿始终:

  • 请求阶段requestStream()立即返回错误对象(非Invalid),直接打印并终止。
  • 流创建阶段getStreamManager()返回类型为"error"的流管理器时,读取m.streamManager["info"]收集错误信息。
  • 播放阶段AdEvent.ERROR事件回调中置m.errorState = true,应用可据此切换备用流(backup stream)。

这与仓库中其他平台指南的策略一致:Web 指南在ERROR事件中读取errorMessage并切换回退流,iOS 指南在failedWith回调中调用playBackupStream()。Roku 实现同样建议在致命错误时展示错误提示或切换到备用内容源,并在用户离开流或流结束时按 SKILL.md 中的通用步骤清理 SDK 资源(释放监听、终止事件循环、置空流管理器引用),避免内存泄漏与重复初始化。

十、参考实现与其他平台对照

原指南指向的参考实现(BasicExample)包含两个核心文件:components/Sdk.xml(即本文第二节创建的 Task 组件,负责加载库与运行 SDK)与components/MainScene.xml(负责观察urlData、装配Video节点、转发元数据与注册广告事件)。你可以在自己的 Roku 工程中按本节给出的完整流程复刻这两个文件的结构。

本仓库的 ima-dai-sdk 技能还收录了其他平台的同类指南,便于多端开发时对照实现:

  • Web/HTML5 StreamManager 指南:浏览器端 HLS.js / DASH.js 集成;
  • Cast(CAF)StreamManager 指南:Chromecast Web Receiver 集成;
  • iOS/tvOS IMAStreamRequest 指南:AVPlayer集成;
  • Android ExoPlayer IMA 扩展指南:Media3ImaServerSideAdInsertionMediaSource集成。

它们共享同一套 Google full-service DAI 概念:asset key(直播)、content source ID+video ID(点播)、network coderequestStream()发起请求、定时元数据转发与广告事件监听。Roku 平台的特殊性在于:必须借助 SceneGraphTask在后台线程运行 SDK,用roMessagePort观察Video节点字段来桥接定时元数据,并通过m.player回调适配层把 SDK 的播放控制指令转译成Video节点操作。

总结

在 Roku 频道中接入 Google IMA DAI SDK 的完整链路可概括为:manifest声明库 → Task 组件加载 SDK →New_IMASDK()初始化 →createPlayer()建立适配层 → 按直播/点播构造CreateLiveStreamRequest/CreateVodStreamRequestrequestStream()发起请求 → 轮询getStreamManager()start()→ 观察urlData驱动Video播放 → 用roMessagePort转发定时元数据 → 注册广告事件与错误处理。掌握这套流程,你就能在 Roku 上实现与 Web、iOS、Android、Cast 平台行为一致的动态广告插入体验。

【免费下载链接】skillsAgent Skills for Google products and technologies项目地址: https://gitcode.com/GitHub_Trending/skills29/skills

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/13 11:09:56

LLM与Jaccard算法在智能运维中的实践

1. 项目概述&#xff1a;当大模型遇见Jaccard算法去年处理某金融系统故障时&#xff0c;我花了整整6小时才定位到根因。而今年引入LLMJaccard方案后&#xff0c;同样量级的故障平均定位时间缩短到47秒——这正是智能运维革命的缩影。传统运维依赖人工经验匹配日志特征&#xff…

作者头像 李华
网站建设 2026/9/13 11:09:51

MATLAB数模竞赛实战:从赛题分析到预测与优化代码实现

简介&#xff1a;中国大学生数学建模竞赛多个经典赛题的MATLAB实现&#xff0c;面向备赛学生与建模爱好者&#xff0c;涵盖捕鱼策略、节水洗衣机、零件参数设计、截断切割、风险投资模型、灾情巡视路线及自动化车床模型等十余个赛题程序。压缩包共21个文件&#xff0c;以19个.m…

作者头像 李华
网站建设 2026/9/13 11:08:34

米哈游游戏构建开发工程师面试复盘:从Unity构建管线到CI/CD

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/13 11:07:44

VS Code安全扩展:可解释性代码复核与契约驱动开发实践

1. 项目背景与核心价值在当今快速迭代的软件开发环境中&#xff0c;安全复核&#xff08;Security Review&#xff09;已成为代码交付流程中不可或缺的环节。然而传统安全工具往往存在两个显著痛点&#xff1a;一是检查结果缺乏可解释性&#xff0c;工程师难以理解"为什么…

作者头像 李华