向网络接收器添加 Ad Breaks API 支持

1. 概览

Google Cast 徽标

此 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 插播时间点
  • 如何跳过广告插播片段
  • 如何自定义跳转时的默认插播行为

所需条件

体验

在继续学习本 Codelab 之前,请确保您具备以下经验。

  • 具备一般 Web 开发知识。
  • 构建 Cast Web 接收器应用。

您打算如何使用本教程?

仅阅读教程内容 阅读并完成练习

您如何评价自己在构建 Web 应用方面的经验水平?

新手 中等 熟练

2. 获取示例代码

将所有示例代码下载到您的计算机...

然后解压下载的 zip 文件。

3. 在本地部署接收器

为了能够将网络接收器与 Cast 设备搭配使用,需要将该网络接收器托管在 Cast 设备可以访问的位置。如果您已有一台支持 https 的服务器可供使用,请跳过以下说明并记下其网址,因为下一部分需要用到该网址。

如果您没有可以使用的服务器,则可以使用 Firebase Hostingngrok

运行服务器

设置好所需的服务后,前往 app-start 并启动服务器。

记下托管接收器的网址。您将在下一部分中使用它。

4. 在 Cast Developer Console 中注册应用

您必须注册应用,才能在 Chromecast 设备上运行此 Codelab 内置的自定义接收器。注册应用后,系统会生成一个应用 ID,发送器应用必须配置为启动 Web 接收器应用。

Google Cast SDK Developer Console 的图片,其中显示了“添加新应用”字样按钮处于突出显示状态

点击“添加新应用”

“新建接收器应用”的图片显示“Custom Receiver”的屏幕突出显示的选项

选择“Custom Receiver”,这是我们正在构建的内容。

“新建自定义接收器”屏幕的图片,显示了用户正在向“接收器应用网址”字段中输入的网址

输入新接收器的详细信息。请务必使用指向您计划托管 Web 接收器应用的位置的网址。注册应用后,请记下由控制台生成的应用 ID。在后面的部分中,我们将配置发件人应用以使用该标识符。

您还必须注册 Google Cast 设备,以便该设备可在您发布接收器应用前对其进行访问。接收器应用发布后,即可供所有 Google Cast 设备使用。在此 Codelab 中,建议使用未发布的接收器应用。

Google Cast SDK 开发者控制台的图片,其中突出显示了“添加新设备”按钮

点击“Add new Device”

“Add Cast Receiver Device”(添加投屏接收器设备)对话框的图片

输入印在 Cast 设备背面的序列号,并为其指定一个描述性名称。在访问 Google Cast SDK Developer Console 时将屏幕投射到 Chrome 中,也可以找到此序列号

接收器和设备需要 5-15 分钟才能准备好进行测试。等待 5-15 分钟后,您必须重新启动投放设备。

5. 准备起始项目

在开始此 Codelab 之前,不妨先查看广告开发者指南,其中概述了广告插播时间点 API。

需要在您下载的起始应用中添加对 Google Cast 的支持。以下是此 Codelab 中使用的一些 Google Cast 术语:

  • 发送设备应用是指在移动设备或笔记本电脑上运行的应用;
  • 接收设备应用是指在 Google Cast 设备上运行的应用。

现在,您可以使用自己喜爱的文本编辑器基于起始项目构建应用了:

  1. 从下载的示例代码中选择 文件夹图标app-start 目录。
  2. 打开 js/receiver.js 和 index.html

请注意,在处理此 Codelab 时,您应该根据所做的更改更新所选的网站托管解决方案。在继续验证和测试更改时,请务必将更改推送到托管网站。

应用设计

如前所述,此 Codelab 利用发送器应用启动 Cast 会话,以及一个接收端应用(将修改为使用广告插播时间点 API)。

在此 Codelab 中,Cast and Command Tool 将充当 Web Sender,用于启动接收器应用。首先,在 Chrome 浏览器中打开该工具。输入您在 Cast SDK Developer Console 上获得的接收器应用 ID,然后点击设置以配置发送器应用以进行测试。

注意:如果您发现系统没有显示投放图标,请确保网络接收器和投放设备已在 Cast Developer Console 中正确注册。如果您尚未执行此操作,请重新启动刚刚注册的所有投屏设备。

接收器应用是此 Codelab 的重点,由 index.html 中定义的一个主视图和一个名为 js/receiver.js 的 JavaScript 文件组成。下文对这些方式进行了详细说明。

index.html

此 HTML 文件包含 cast-media-player 元素提供的接收器应用界面。它还会加载 CAF SDK 和 Cast Debug Logger 库。

receiver.js

此脚本管理接收器应用的所有逻辑。现在,它包含一个基本的 CAF 接收器,用于初始化投射上下文并在初始化时加载视频资源。我们还添加了一些调试日志记录器功能,以便向 Cast 和 Command 工具提供日志记录。

6. 向您的内容添加 VMAP

Cast Web Receiver SDK 支持通过数字视频多广告播放列表(也称为 VMAP)指定的广告。XML 结构可指定媒体的广告插播时间点及其关联的插播时间点剪辑元数据。为了插入这些广告,SDK 会在 MediaInformation 对象中提供 vmapAdsRequest 属性。

js/receiver.js 文件中,创建一个 VastAdsRequest 对象。找到 LOAD 请求拦截器函数并将其替换为以下代码。它包含 DoubleClick 中的示例 VMAP 代码网址,并提供随机的相关器值,以确保对同一网址的后续请求会生成包含尚未观看的广告插播的 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 所做的更改,并将文件上传到您的网络服务器。点击“投射”图标,在投射和命令工具上启动投射会话。系统应先播放 VMAP 广告,然后再播放主要内容。

7. 将 VAST 添加到您的内容中

如前所述,Web Receiver SDK 支持多种类型的广告。本部分重点介绍了可用于集成数字视频广告投放模板广告(也称为 VAST)的 API。如果您已实现上一部分中的 VMAP 代码,请将其注释掉。

将以下内容复制到 js/receiver.js 文件中的 load 请求拦截器后面。它包含来自 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,以设置用于中断加载的拦截器。将下面这行代码复制到 js/receiver.js 文件中包含 contextplayerManager 变量的行后面,以获取对实例的引用。

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 所做的更改保存,然后将该文件上传到您的 Web 服务器。点击“投射”图标,在投射和命令工具上启动投射会话。VAST 广告应得到处理。请注意,系统不会播放前贴片广告和第一个中贴片广告(其 position 为 15 秒)。

9. 自定义广告插播跳转行为

在跳过广告插播时,默认实现会获取位置介于跳转操作的 seekFromseekTo 值之间的所有 Break 项。在此插播列表中,SDK 会播放 position 最接近 seekTo 值且 isWatched 属性设置为 falseBreak。然后,系统会将该广告插播时间点的 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 所做的更改,并将文件上传到您的网络服务器。点击“投射”图标,在投射和命令工具上启动投射会话。VAST 广告应得到处理。请注意,系统不会播放前贴片广告和第一个中贴片广告position 为 15 秒)。

等待播放时间达到 30 秒,以跳过由广告插播片段加载拦截器跳过的所有广告插播时间点。到达后,转到媒体控制标签页来调度跳转命令。使用 300 秒填充 Seek Into Media 输入,然后点击 TO 按钮。请注意 Break Seek Interceptor 中输出的日志。现在,应替换默认行为,以便在接近 seekFrom 时间时播放广告插播时间点。

10. 恭喜

您现在已经知道如何使用最新的 Cast 接收器 SDK 向接收器应用添加广告了。

如需了解详情,请参阅广告插播时间点开发者指南。