1. 概览
此 Codelab 概述了如何构建使用 Cast Ad Breaks API 的自定义网络接收器应用。
什么是 Google Cast?
Google Cast 可让用户将移动设备上的内容投射到电视上。然后,用户可以将其移动设备用作遥控器,来控制电视上的媒体播放。
借助 Google Cast SDK,您可以扩展应用以控制电视或音响系统。借助 Cast SDK,您可以根据 Google Cast 设计核对清单添加必需的界面组件。
Google Cast 设计核对清单旨在规范 Cast 实现,以便在所有受支持的平台上提供直观的用户体验。
构建目标
完成此 Codelab 后,您就构建了一个利用 Break API 的 Cast 接收器。
学习内容
- 如何在 Cast 内容中添加 VMAP 和 VAST 广告插播时间点
- 如何跳过广告插播片段
- 如何自定义跳转时的默认中断行为
所需条件
- 最新版本的 Google Chrome 浏览器。
- HTTPS 托管服务,例如 Firebase Hosting 或 ngrok。
- 一台可连接到互联网的 Google Cast 设备,例如 Chromecast 或 Android TV。
- 配有 HDMI 输入接口的电视或显示器,或 Google Home Hub
体验
在继续学习本 Codelab 之前,请确保您具备以下经验。
- 一般 Web 开发知识。
- 构建 Cast Web 接收器应用。
您打算如何使用本教程?
您如何评价自己在构建 Web 应用方面的经验水平?
2. 获取示例代码
将所有示例代码下载到计算机上…
然后解压下载的 zip 文件。
3. 在本地部署接收器
为了能够将网络接收器与 Cast 设备搭配使用,需要将该网络接收器托管在 Cast 设备可以访问的位置。如果您拥有支持 https 的服务器,请跳过以下说明并记下网址,因为下一部分需要用到该网址。
如果您没有可用的服务器,可以使用 Firebase Hosting 或 ngrok。
运行服务器
设置好所需的服务后,前往 app-start
并启动服务器。
记下托管接收器的网址。您将在下一部分中使用它。
4. 在 Cast Developer Console 中注册应用
您必须注册应用,才能在 Chromecast 设备上运行此 Codelab 中构建的这种自定义接收器。注册应用后,系统会生成一个应用 ID,发送器应用必须配置为启动 Web 接收器应用。
点击“Add new application”
选择“Custom Receiver”,这是我们将构建的应用类型。
输入新收款方的详细信息。请务必使用指向您计划托管 Web 接收器应用的网址。注册应用后,记下控制台生成的应用 ID。在后面的部分中,我们将配置发件人应用以使用该标识符。
此外,您还必须注册 Google Cast 设备,以便该设备可以在您发布接收器应用之前对其进行访问。接收器应用发布后,便可供所有 Google Cast 设备使用。在此 Codelab 中,建议使用未发布的接收器应用。
点击“添加新设备”
输入 Cast 设备背面印刷的序列号,并为其指定一个描述性名称。在访问 Google Cast SDK Developer Console 时将屏幕投射到 Chrome 中,也可以找到此序列号
接收器和设备需要 5-15 分钟才能准备好进行测试。等待 5-15 分钟后,您必须重新启动 Cast 设备。
5. 准备起始项目
在开始此 Codelab 之前,不妨先查看广告开发者指南,其中概述了广告插播时间点 API。
需要在您下载的起始应用中添加 Google Cast 支持。下面是此 Codelab 中使用的部分 Google Cast 术语:
- 发送设备应用是指在移动设备或笔记本电脑上运行的应用;
- 接收设备应用是指在 Google Cast 设备上运行的应用。
现在,您可以使用自己喜爱的文本编辑器基于起始项目构建应用了:
- 从下载的示例代码中选择
app-start
目录。 - 打开
js/receiver.js
和 index.html
请注意,在处理此 Codelab 时,您应该根据所做的更改更新所选的网站托管解决方案。在继续验证和测试更改时,请确保将更改推送到托管网站。
应用设计
如前所述,此 Codelab 利用发送器应用启动 Cast 会话,以及一个接收端应用(将修改为使用广告插播时间点 API)。
在此 Codelab 中,投放和命令工具将充当 Web 发送器来启动接收器应用。首先,在 Chrome 浏览器中打开该工具。输入您在 Cast SDK 开发者控制台中获得的接收器应用 ID,然后点击设置以配置要进行测试的发送器应用。
注意:如果您发现投放图标未显示,请确保 Web 接收器和投放设备已在 Cast 开发者控制台中正确注册。如果您尚未执行此操作,请重新启动刚刚注册的所有投屏设备。
接收器应用是本 Codelab 的主要重点,它包含一个在 index.html
中定义的主视图和一个名为 js/receiver.js
的 JavaScript 文件。下面将对这些进行进一步说明。
index.html
此 HTML 文件包含 cast-media-player
元素提供的接收器应用界面。它还会加载 CAF SDK 和 Cast 调试日志记录器库。
receiver.js
此脚本管理接收器应用的所有逻辑。现在,它包含一个基本的 CAF 接收器,用于初始化投射上下文并在初始化时加载视频资源。我们还添加了一些调试日志记录器功能,以便向 Cast 和 Command 工具提供日志记录。
6. 向您的内容添加 VMAP
Cast Web Receiver SDK 支持通过数字视频多广告播放列表(也称为 VMAP)指定的广告。XML 结构指定媒体的广告插播时间点及其关联的插播片段元数据。为了插入这些广告,SDK 在 MediaInformation
对象中提供了 vmapAdsRequest
属性。
在 js/receiver.js
文件中,创建一个 VastAdsRequest
对象。找到 LOAD 请求拦截器函数,并将其替换为以下代码。其中包含一个来自 DoubleClick 的 VMAP 代码网址示例,并提供一个随机 Correlator 值,以确保针对同一网址的后续请求会生成包含尚未观看的广告插播时间点的 XML 模板。
playerManager.setMessageInterceptor(
cast.framework.messages.MessageType.LOAD, (loadRequestData) => {
castDebugLogger.info('MyAPP.LOG', 'Intercepting LOAD request');
// Create the VMAP Ads request data and append it to the MediaInformation.
const vmapUrl =
'https://pubads.g.doubleclick.net/gampad/ads?sz=640x480&iu=/124319096/external/ad_rule_samples&ciu_szs=300x250&ad_rule=1&impl=s&gdfp_req=1&env=vp&output=vmap&unviewed_position_start=1&cust_params=deployment%3Ddevsite%26sample_ar%3Dpremidpost&cmsid=496&vid=short_onecue&correlator=' +
Math.floor(Math.random() * Math.pow(10, 10));
let vmapRequest = new cast.framework.messages.VastAdsRequest();
vmapRequest.adTagUrl = vmapUrl;
loadRequestData.media.vmapAdsRequest = vmapRequest;
castDebugLogger.warn(
'MyAPP.LOG', 'Playable URL: ' + loadRequestData.media.contentId);
return loadRequestData;
});
将对 js/receiver.js
所做的更改保存,然后将该文件上传到您的 Web 服务器。点击投放和控制工具中的投放图标,在该工具中发起投放会话。系统应先播放 VMAP 广告,然后再播放主要内容。
7. 将 VAST 添加到您的内容
如前所述,Web Receiver SDK 支持多种类型的广告。本部分重点介绍了可用于集成数字视频广告投放模板广告(也称为 VAST)的 API。如果您已实现上一部分中的 VMAP 代码,请将其注释掉。
将以下代码复制到加载请求拦截器后面的 js/receiver.js
文件中。它包含来自 DoubleClick 的六个 VAST 广告插播片段和一个随机的相关器值。系统会将这些广告插播剪辑分配到 5 个广告插播时间点。每个广告插播时间点的 position
均设置为相对于主要内容的秒数,包括前贴片广告插播时间点(将 position
设置为 0
)和后贴片广告插播时间点(将 position
设置为 -1
)。
const addVASTBreaksToMedia = (mediaInformation) => {
mediaInformation.breakClips = [
{
id: 'bc1',
title: 'bc1 (Pre-roll)',
vastAdsRequest: {
adTagUrl: generateVastUrl('preroll')
}
},
{
id: 'bc2',
title: 'bc2 (Mid-roll)',
vastAdsRequest: {
adTagUrl: generateVastUrl('midroll')
}
},
{
id: 'bc3',
title: 'bc3 (Mid-roll)',
vastAdsRequest: {
adTagUrl: generateVastUrl('midroll')
}
},
{
id: 'bc4',
title: 'bc4 (Mid-roll)',
vastAdsRequest: {
adTagUrl: generateVastUrl('midroll')
}
},
{
id: 'bc5',
title: 'bc5 (Mid-roll)',
vastAdsRequest: {
adTagUrl: generateVastUrl('midroll')
}
},
{
id: 'bc6',
title: 'bc6 (Post-roll)',
vastAdsRequest: {
adTagUrl: generateVastUrl('postroll')
}
}
];
mediaInformation.breaks = [
{id: 'b1', breakClipIds: ['bc1'], position: 0},
{id: 'b2', breakClipIds: ['bc2'], position: 15},
{id: 'b3', breakClipIds: ['bc3', 'bc4'], position: 60},
{id: 'b4', breakClipIds: ['bc5'], position: 100},
{id: 'b5', breakClipIds: ['bc6'], position: -1}
];
};
注意:广告插播时间点的 breakClipIds
属性是一个数组,这意味着可以为每个广告插播时间点分配多个广告插播剪辑。
在 js/receiver.js file
中,找到 LOAD 消息拦截器,并将其替换为以下代码。请注意,VMAP 工作已注释掉,以展示 VAST 类型的广告。
playerManager.setMessageInterceptor(
cast.framework.messages.MessageType.LOAD, (loadRequestData) => {
castDebugLogger.info('MyAPP.LOG', 'Intercepting LOAD request');
// Create the VMAP Ads request data and append it to the MediaInformation.
// const vmapUrl =
// 'https://pubads.g.doubleclick.net/gampad/ads?sz=640x480&iu=/124319096/external/ad_rule_samples&ciu_szs=300x250&ad_rule=1&impl=s&gdfp_req=1&env=vp&output=vmap&unviewed_position_start=1&cust_params=deployment%3Ddevsite%26sample_ar%3Dpremidpost&cmsid=496&vid=short_onecue&correlator=' +
// Math.floor(Math.random() * Math.pow(10, 10));
// let vmapRequest = new cast.framework.messages.VastAdsRequest();
// vmapRequest.adTagUrl = vmapUrl;
// loadRequestData.media.vmapAdsRequest = vmapRequest;
// Append VAST ad breaks to the MediaInformation.
addVASTBreaksToMedia(loadRequestData.media);
castDebugLogger.warn(
'MyAPP.LOG', 'Playable URL: ' + loadRequestData.media.contentId);
return loadRequestData;
});
将对 js/receiver.js
所做的更改保存,然后将该文件上传到您的 Web 服务器。点击投放和控制工具中的投放图标,在该工具中发起投放会话。VAST 广告应在播放主要内容之后播放。
8. 广告插播时间点跳过
CAF 有一个名为 BreakManager
的类,可帮助您为广告行为实现自定义业务规则。其中一项功能可让应用根据某些条件以编程方式跳过插播时间点和插播片段。此示例展示了如何跳过在内容前 30 秒内(但不包括后贴片广告)的广告插播时间点。使用上一部分中配置的 VAST 广告时,系统会定义 5 个插播时间点:1 个前贴片广告插播时间点、3 个中贴片广告插播时间点(分别在 15、60 和 100 秒时刻),最后一个是后贴片广告插播时间点。完成上述步骤后,系统只会跳过位置为 15 秒的前贴片广告和中贴片广告。
为此,应用应调用通过 BreakManager
提供的 API 来设置用于断点加载的拦截器。将以下代码行复制到包含 context
和 playerManager
变量的代码行后面,以获取对实例的引用。js/receiver.js
const breakManager = playerManager.getBreakManager();
应用应设置一个拦截器并设置规则,以忽略 30 秒前发生的所有广告插播时间点,同时记住所有后贴片广告插播时间点(因为它们的 position
值为 -1
)。此拦截器的运作方式与 PlayerManager
上的 LOAD 拦截器类似,但它专门用于加载广告插播片段。将此值设置在 LOAD 请求拦截器之后、addVASTBreaksToMedia
函数声明之前。
将以下内容复制到 js/receiver.js
文件中。
breakManager.setBreakClipLoadInterceptor((breakClip, breakContext) => {
/**
* The code will skip playback of break clips if the break position is within
* the first 30 seconds.
*/
let breakObj = breakContext.break;
if (breakObj.position >= 0 && breakObj.position < 30) {
castDebugLogger.debug(
'MyAPP.LOG',
'Break Clip Load Interceptor skipping break with ID: ' + breakObj.id);
return null;
} else {
return breakClip;
}
});
注意:在此处返回 null
会跳过正在处理的 BreakClip
。如果 Break
未定义任何广告插播片段,则系统会跳过广告插播本身。
保存对 js/receiver.js
所做的更改,并将文件上传到您的网络服务器。点击“投射”图标,在投射和命令工具上启动投射会话。系统应处理 VAST 广告。请注意,系统不会播放前贴片广告和第一个中贴片广告(其 position
为 15 秒)。
9. 自定义广告插播跳转行为
在跳过广告插播时,默认实现会获取位置介于跳转操作的 seekFrom
和 seekTo
值之间的所有 Break
项。在此插播列表中,SDK 会播放 position
最接近 seekTo
值且 isWatched
属性设置为 false
的 Break
。然后,系统会将该广告插播的 isWatched
属性设为 true
,并让播放器开始播放广告插播的剪辑。看完插播广告后,主要内容会从 seekTo
位置继续播放。如果不存在此类广告插播,则不会播放广告插播,主内容会从 seekTo
位置继续播放。
为了自定义在跳转时播放的具体中断,Cast SDK 在 BreakManager
中提供了 setBreakSeekInterceptor
API。当应用通过该 API 提供其自定义逻辑时,每当在一个或多个广告插播点执行跳转操作时,SDK 都会调用该逻辑。系统会向回调函数传递一个对象,其中包含 seekFrom
位置和 seekTo
位置之间的所有换行。然后,应用需要修改并返回 BreakSeekData
。
为了演示其用法,以下示例通过获取已跳过的所有广告插播时间点,并仅播放时间轴中显示的第一个广告插播时间点,来替换默认行为。
将以下内容复制到 js/receiver.js
文件中 setBreakClipLoadInterceptor
的定义下。
breakManager.setBreakSeekInterceptor((breakSeekData) => {
/**
* The code will play an unwatched break between the seekFrom and seekTo
* position. Note: If the position of a break is less than 30 then it will be
* skipped due to the setBreakClipLoadInterceptor code.
*/
castDebugLogger.debug(
'MyAPP.LOG',
'Break Seek Interceptor processing break ids ' +
JSON.stringify(breakSeekData.breaks.map(adBreak => adBreak.id)));
// Remove all other breaks except for the first one.
breakSeekData.breaks.splice(1,breakSeekData.breaks.length);
return breakSeekData;
});
注意:如果该函数未返回值或返回 null
,则不会播放任何休息时刻。
将对 js/receiver.js
所做的更改保存,然后将该文件上传到您的 Web 服务器。点击投放和控制工具中的投放图标,在该工具中发起投放会话。系统应处理 VAST 广告。请注意,系统不会播放前贴片广告和第一个中贴片广告(position
为 15 秒)。
等待播放时间达到 30 秒,以跳过广告插播片段加载拦截器跳过的所有广告插播。达到该位置后,前往媒体控制标签页,发出跳转命令。在 Seek Into Media 输入框中填入 300
秒,然后点击 TO 按钮。请注意 Break Seek Interceptor 中输出的日志。现在,应替换默认行为,以便在更接近 seekFrom
时间播放广告插播。
10. 恭喜
现在,您已经知道如何使用最新的 Cast 接收器 SDK 向接收器应用添加广告。
如需了解详情,请参阅广告插播开发者指南。