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

1. 概览

Google Cast 徽标

此 Codelab 概述了如何构建使用 Cast Ad Breaks API 的自定义 Web 接收器应用。

什么是 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. 在本地部署接收器

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

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

运行服务器

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

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

4. 在 Cast Developer Console 中注册应用

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

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

点击“Add new application”

“新建接收器应用”界面的图片,其中突出显示了“自定义接收器”选项

选择“Custom Receiver”,这是我们将构建的应用类型。

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

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

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

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

点击“Add new Device”

“添加投屏接收器设备”对话框的图片

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

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

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 和 Command 工具将充当 Web 发送方来启动接收器应用。首先,在 Chrome 浏览器中打开该工具。输入您在 Cast SDK Developer Console 中获得的接收器应用 ID,然后点击 Set 以配置发送方应用以进行测试。

注意:如果您发现投放图标未显示,请确保 Web 接收器和投放设备已在 Cast 开发者控制台中正确注册。如果您尚未这样做,请重新启动刚刚注册的所有投屏设备。

接收器应用是此 Codelab 的主要重点,包含一个在 index.html 中定义的主视图和一个名为 js/receiver.js 的 JavaScript 文件。下面将对此进行详细说明。

index.html

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

receiver.js

此脚本负责管理接收器应用的所有逻辑。目前,它包含一个基本的 CAF 接收器,用于初始化 Cast 上下文并在初始化时加载视频资源。此外,还添加了一些调试记录器功能,以将日志记录回 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,然后将该文件上传到您的 Web 服务器。点击投放图标,在投放和命令工具上发起投放会话。VMAP 广告应先播放,然后播放主要内容。

7. 向内容中添加 VAST

如前所述,Web 接收器 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 秒处),以及 1 个后贴片广告插播时间点。完成上述步骤后,系统只会跳过位置为 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,然后将该文件上传到您的 Web 服务器。点击投放图标,在投放和命令工具上发起投放会话。应处理 VAST 广告。请注意,前贴片广告和第一个中贴片广告(其 position 为 15 秒)不会播放。

等待播放时间达到 30 秒,以跳过中断剪辑加载拦截器跳过的所有中断。到达该位置后,前往媒体控制标签页,调度搜索命令。在 Seek Into Media 输入源中填充 300 秒,然后点击 TO 按钮。请注意在 Break Seek Interceptor 中打印的日志。现在,应替换默认行为,以便在更接近 seekFrom 时间时播放插播广告。

10. 恭喜

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

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