设置 IMA SDK for DAI

选择您感兴趣的 DAI 解决方案

Pod Serving DAI

IMA SDK 可简化将多媒体广告集成到网站和应用中的过程。

IMA SDK 可从任何符合 VAST 标准的广告服务器请求广告,并在您的应用中管理广告播放。

借助 IMA DAI SDK,应用可以针对 VOD 或直播内容发出广告和内容视频的视频流请求。然后,SDK 会返回一个组合的视频流,这样您就不必在应用中管理广告视频和内容视频之间的切换。

本指南演示了如何使用 IMA DAI SDK for CAF 播放 DAI Pod Serving 流。

在使用本指南之前,请先熟悉 Chromecast 应用框架的 Web 接收器协议。本指南假定您对 CAF 接收器概念(例如消息拦截器mediaInformation 对象)有基本的了解,并且熟悉如何使用 Cast 命令和控制工具来模拟 CAF 发送器。

如需使用 IMA DAI Pod Serving,您必须与 Pod Serving 合作伙伴合作,并且必须拥有 Ad Manager 360 高级版账号。如果您有 Ad Manager 账号,请与您的客户经理联系以了解详情。如需了解如何注册 Ad Manager,请访问 Ad Manager 帮助中心

如需了解如何与其他平台集成或使用 IMA 客户端 SDK,请参阅互动式媒体广告 SDK

IMA DAI Pod Serving 概览

使用 IMA CAF DAI SDK 实现 Pod 服务涉及两个主要组件,本指南将对此进行演示:

  • StreamRequest:用于定义向 Google 广告服务器发出的流式请求的对象。 请求会指定广告资源网代码、自定义广告资源键和可选的 API 密钥,以及其他可选参数。
  • StreamManager:用于处理视频流与 IMA DAI SDK 之间通信的对象,例如触发跟踪 ping 和将流事件转发给发布商。

前提条件

配置发送者的 MediaInfo 对象

首先,配置发送方应用的 MediaInfo 对象,以包含以下字段:

字段 目录
contentId 相应媒体内容的唯一标识符。

CONTENT_ID

contentUrl 可选。如果 DAI 视频流无法加载,则播放的备用视频流网址。

BACKUP_STREAM_URL

contentType 可选。内容备份流的 MIME 类型。仅需用于 DASH 流

CONTENT_STREAM_MIMETYPE

streamType 用于此值的字符串字面量或常量因发送方平台而异。
customData customData 字段包含其他必需字段的键值存储区。在此示例中,它包含您的 DAI 流参数。在正式版应用中,您可能会改为传递一个标识符,Cast 接收器应用会使用该标识符通过服务器端请求检索这些参数。
字段 目录
daiStreamType DAI 视频流的类型。可以是 "LIVE""VOD"

DAI_STREAM_TYPE

networkCode 您的 Google Ad Manager 360 账号的广告资源网代码。

NETWORK_CODE

customAssetKey 此字段仅适用于直播。用于在 Google Ad Manager 360 中标识 Pod 投放事件的自定义素材资源键。

CUSTOM_ASSET_KEY

apiKey 用于从 IMA DAI SDK 检索视频流 ID 的可选 API 密钥。

API_KEY

以下是一些代码示例,可帮助您快速入门:

Web

如需在 Cast Web 发送器中配置这些值,请先创建一个包含所需数据的 MediaInfo 对象,然后向 Web 接收器发出 load 请求

// Create mediaInfo object
const mediaInfo = new chrome.cast.media.MediaInfo("CONTENT_ID");
mediaInfo.contentUrl = "BACKUP_STREAM_URL";
mediaInfo.contentType = "CONTENT_STREAM_MIMETYPE";
mediaInfo.streamType = chrome.cast.media.StreamType.LIVE;
mediaInfo.customData = {
  daiStreamType: "DAI_STREAM_TYPE",
  networkCode: "NETWORK-CODE",
  customAssetKey: "CUSTOM_ASSET_KEY",
  apiKey: "API_KEY"
};

// Make load request to cast web receiver
const castSession = cast.framework.CastContext.getInstance().getCurrentSession();
const request = new chrome.cast.media.LoadRequest(mediaInfo);
castSession.loadMedia(request).then(
  () => { console.log('Load succeed'); },
  (errorCode) => { console.log('Error code: ' + errorCode); });

Android

如需在 Cast Web 发送器中配置这些值,请先创建包含所需数据的 MediaInfo 对象,然后向 Web 接收器发出加载请求

JSONObject customData = new JSONObject()?
  .put("daiStreamType", "DAI_STREAM_TYPE")
  .put("networkCode", "NETWORK-CODE")
  .put("customAssetKey", "CUSTOM_ASSET_KEY")
  .put("apiKey", "API_KEY");
MediaInfo mediaInfo = MediaInfo.Builder("CONTENT_ID")
  .setContentUrl("BACKUP_STREAM_URL")
  .setContentType("CONTENT_STREAM_MIMETYPE")
  .setStreamType(MediaInfo.STREAM_TYPE_LIVE)
  .setCustomData(customData)
  .build();

RemoteMediaClient remoteMediaClient = mCastSession.getRemoteMediaClient();
remoteMediaClient.load(new MediaLoadRequestData.Builder().setMediaInfo(mediaInfo).build());

iOS (Obj-C)

如需在 Cast Web 发送器中配置这些值,请先创建一个包含所需数据的 GCKMediaInformation 对象,然后向 Web 接收器发出 load 请求

NSURL url = [NSURL URLWithString:@"BACKUP_STREAM_URL"];
NSDictionary *customData = @{
  @"daiStreamType": @"DAI_STREAM_TYPE",
  @"networkCode": @"NETWORK-CODE",
  @"customAssetKey": @"CUSTOM_ASSET_KEY",
  @"apiKey": @"API_KEY"};
mediaInfoBuilder.customData = customData;

GCKMediaInformationBuilder *mediaInfoBuilder =
  [[GCKMediaInformationBuilder alloc] initWithContentID: @"CONTENT_ID"];
mediaInfoBuilder.contentURL = url;
mediaInfoBuilder.contentType = @"CONTENT_STREAM_MIMETYPE";
mediaInfoBuilder.streamType = GCKMediaStreamTypeLive;
mediaInfoBuilder.customData = customData;
self.mediaInformation = [mediaInfoBuilder build];

GCKRequest *request = [self.sessionManager.currentSession.remoteMediaClient loadMedia:self.mediaInformation];
if (request != nil) {
  request.delegate = self;
}

iOS (Swift)

如需在 Cast Web 发送器中配置这些值,请先创建一个包含所需数据的 GCKMediaInformation 对象,然后向 Web 接收器发出 load 请求

let url = URL.init(string: "BACKUP_STREAM_URL")
guard let mediaURL = url else {
  print("invalid mediaURL")
  return
}

let customData = [
  "daiStreamType": "DAI_STREAM_TYPE",
  "networkCode": "NETWORK-CODE",
  "customAssetKey": "CUSTOM_ASSET_KEY",
  "region": "API_KEY"
]

let mediaInfoBuilder = GCKMediaInformationBuilder.init(contentId: "CONTENT_ID")
mediaInfoBuilder.contentURL = mediaUrl
mediaInfoBuilder.contentType = @"CONTENT_STREAM_MIMETYPE"
mediaInfoBuilder.streamType = GCKMediaStreamType.Live
mediaInfoBuilder.customData = customData
mediaInformation = mediaInfoBuilder.build()

guard let mediaInfo = mediaInformation else {
  print("invalid mediaInformation")
  return
}

if let request = sessionManager.currentSession?.remoteMediaClient?.loadMedia
(mediaInfo) {
  request.delegate = self
}

CAC 工具

如需在 Cast Command and Control 工具中配置这些值,请点击“Load Media”标签页,并将自定义加载请求类型设置为 LOAD。然后,将文本区域中的 JSON 数据替换为以下 JSON:

{
  "media": {
    "contentId": "CONTENT_ID",
    "contentUrl": "BACKUP_STREAM_URL",
    "contentType": ""CONTENT_STREAM_MIMETYPE"",
    "streamType": "LIVE",
    "customData": {
      "daiStreamType": "DAI_STREAM_TYPE",
      "networkCode": "NETWORK-CODE",
      "customAssetKey": "CUSTOM_ASSET_KEY",
      "oAuthToken": "API_KEY"
    }
  }
}

此自定义负载请求可以发送到接收器,以测试其余步骤。

创建基本 CAF 接收器

创建自定义 Web 接收器,如 CAF SDK 自定义 Web 接收器指南中所述。

接收器的代码应如下所示:

<html>
<head>
  <script
      src="//www.gstatic.com/cast/sdk/libs/caf_receiver/v3/cast_receiver_framework.js">
  </script>
</head>
<body>
  <cast-media-player></cast-media-player>
  <script>
    // ...
  </script>
</body>
</html>

导入 IMA DAI SDK 并获取播放器管理器

在加载 CAF 的脚本之后,添加一个脚本标记,以将 IMA DAI SDK for CAF 导入到您的 Web 接收器。在脚本标记中,将接收器上下文和播放器管理器存储为常量,然后再启动接收器。

<html>
<head>
  <script
      src="//www.gstatic.com/cast/sdk/libs/caf_receiver/v3/cast_receiver_framework.js"></script>
  <script src="//imasdk.googleapis.com/js/sdkloader/cast_dai.js"></script>
</head>
<body>
  <cast-media-player></cast-media-player>
  <script>
    const castContext = cast.framework.CastReceiverContext.getInstance();
    const playerManager = castContext.getPlayerManager();

    castContext.start();
  </script>
</body>
</html>

初始化 IMA Stream Manager

初始化 IMA StreamManager。

<html>
<head>
  <script type="text/javascript"
      src="//www.gstatic.com/cast/sdk/libs/caf_receiver/v3/cast_receiver_framework.js"></script>
  <script src="//imasdk.googleapis.com/js/sdkloader/cast_dai.js"></script>
</head>
<body>
  <cast-media-player></cast-media-player>
  <script>
    const castContext = cast.framework.CastReceiverContext.getInstance();
    const playerManager = castContext.getPlayerManager();
    const streamManager = new google.ima.cast.dai.api.StreamManager();

    castContext.start();
  </script>
</body>
</html>

创建 Stream Manager Load Interceptor

在将媒体项传递给 CAF 之前,请在 LOAD 消息拦截器中创建您的流请求。

    const castContext = cast.framework.CastReceiverContext.getInstance();
    const playerManager = castContext.getPlayerManager();
    const streamManager = new google.ima.cast.dai.api.StreamManager();

    /**
     * Creates a livestream request object for a Pod Serving stream.
     * @param {!LoadRequestData} castRequest The request object from the cast sender
     * @return {StreamRequest} an IMA stream request
     */
    const createStreamRequest = (castRequest) => { /* ... */};

    /**
     * Initates a DAI stream request for the final stream manifest.
     * @param {!LoadRequestData} castRequest The request object from the cast sender
     * @return {Promise<LoadRequestData>} a promise that resolves to an updated castRequest, containing the DAI stream manifest
     */
    const createDAICastRequest = (castRequest) => {
        return streamManager.requestStream(castRequest, createStreamRequest(castRequest))
          .then((castRequestWithPodStreamData) => {
            console.log('Successfully made DAI stream request.');
            // ...
            return castRequestWithPodStreamData;
          })
          .catch((error) => {
            console.log('Failed to make DAI stream request.');
            // CAF will automatically fallback to the content URL
            // that it can read from the castRequest object.
            return castRequest;
          });
    };

    playerManager.setMessageInterceptor(
        cast.framework.messages.MessageType.LOAD, createDAICastRequest);

    castContext.start();

创建流式请求

完成 createStreamRequest 函数,以基于 CAF 加载请求创建 Pod Serving 流。

    /**
     * Creates a livestream request object for a Pod Serving stream.
     * @param {!LoadRequestData} castRequest The request object from the cast sender
     * @return {StreamRequest} an IMA stream request
     */
    const createStreamRequest = (castRequest) => {
      const customData = castRequest.media.customData;
      let streamRequest;
      if (customData.daiStreamType == "LIVE") {
        streamRequest = new google.ima.cast.dai.api.PodStreamRequest();
        streamRequest.customAssetKey = customData.customAssetKey;
        streamRequest.networkCode = customData.networkCode;
        streamRequest.apiKey = customData.apiKey;
      } else if (customData.daiStreamType == "VOD") {
        streamRequest = new google.ima.cast.dai.api.PodVodStreamRequest();
        streamRequest.networkCode = customData.networkCode;
        streamRequest.apiKey = customData.apiKey;
      }
      return streamRequest;
    };

从 VTP 中检索拼接后的清单

如果您的直播请求成功,请使用 streamManager.getStreamId() 检索直播的 ID。您的视频技术合作伙伴 (VTP) 或自定义清单操纵器将提供有关如何使用此视频流 ID 检索清单网址的说明。

检索到清单网址后,请将现有的 contentUrl 替换为新的 manifestUrl

最后,在返回修改后的视频流清单之前,请对 streamManager 调用 loadStreamMetadata 方法,以告知 IMA SDK 可以安全地请求视频流元数据。此调用仅适用于 VOD 流。

    /**
     * Initates a DAI stream request for the final stream manifest.
     * @param {!LoadRequestData} castRequest The request object from the cast sender
     * @return {Promise<LoadRequestData>} a promise that resolves to an updated castRequest, containing the DAI stream manifest
     */
    const createDAICastRequest = (castRequest) => {
        return streamManager.requestStream(castRequest, createStreamRequest(castRequest))
          .then((castRequestWithPodStreamData) => {
            console.log('Successfully made DAI stream request.');

            // This is a sample VTP integration. Consult your VTP documentation
            // for how to retrieve an ad-stitched stream manifest URL.
            const manifestTemplate = "https://.../manifest.m3u8?gam_stream_id=[[STREAMID]]";
            const streamId = streamManager.getStreamId();
            const manifestUrl = manifestTemplate.replace('[[STREAMID]]', streamId)
            // Assign your manifestUrl to the request's content URL.
            castRequestWithPodStreamData.media.contentUrl = manifestUrl;

            // After generating the manifest URL, VOD streams must notify the
            // IMA SDK that it is safe to request ad pod metadata.
            // This is only necessary for VOD streams. It is a no-op for
            // livestreams, so no conditional is needed.
            streamManager.loadStreamMetadata();

            return castRequestWithPodStreamData;
          })
          .catch((error) => {
            console.log('Failed to make DAI stream request.');
            // CAF will automatically fallback to the content URL
            // that it can read from the castRequest object.
            return castRequest;
          });
    };

清理 IMA DAI 资产

当您使用 IMA DAI SDK 成功完成在 Pod Serving 视频流中请求和展示广告后,建议您在 Pod Serving 会话结束后清理所有资源。调用 StreamManager.destroy() 可停止视频流播放、停止所有广告跟踪并释放所有已加载的视频流素材资源。