設定廣告連播服務 DAI

選取平台: HTML5 Android iOS tvOS Cast Roku

IMA SDK 可簡化將多媒體廣告整合至網站和應用程式的程序。

IMA SDK 可向任何符合 VAST 規範的廣告伺服器請求廣告,並管理應用程式中的廣告播放。

使用 IMA DAI SDK 時,應用程式會針對隨選影片或直播內容,提出廣告和內容影片的串流請求。接著,SDK 會傳回合併的影片串流,您就不必在應用程式中管理廣告和內容影片之間的切換。

本指南說明如何使用 IMA DAI SDK for CAF 播放 DAI 廣告連播放送串流。

使用本指南前,請先熟悉 Chromecast 應用程式架構的 Web 接收端通訊協定。本指南假設您已基本瞭解 CAF 接收端概念,例如訊息攔截器和 mediaInformation 物件,並熟悉如何使用 Cast 指揮與控制工具模擬 CAF 傳送端。

如要使用 IMA DAI 廣告連播放送功能,您必須與廣告連播放送合作夥伴合作,且須擁有 Ad Manager 360 Advanced 帳戶。如果您有 Ad Manager 帳戶,請洽詢客戶經理瞭解詳情。如要瞭解如何註冊 Ad Manager,請前往 Ad Manager 說明中心。

如要瞭解如何與其他平台整合,或使用 IMA 用戶端 SDK,請參閱「互動式媒體廣告 SDK」。

IMA DAI 廣告連播放送總覽

使用 IMA CAF DAI SDK 導入 Pod 廣告放送功能,主要涉及兩個元件,本指南將示範這兩個元件:

  • StreamRequest: 這個物件定義了向 Google 廣告伺服器發出的串流請求。 請求會指定聯播網代碼、自訂素材資源金鑰、選用的 API 金鑰,以及其他選用參數。
  • StreamManager: 這個物件會處理影片串流和 IMA DAI SDK 之間的通訊,例如觸發追蹤連線偵測 (ping),以及將串流事件轉送給發布商。

必要條件

設定傳送端的 MediaInfo 物件

首先,請設定傳送端應用程式的 MediaInfo 物件,加入下列欄位:

欄位 目錄
contentId 這個媒體項目的專屬 ID。

CONTENT_ID

contentUrl (選用步驟) 如果 DAI 串流無法載入,則播放備用串流網址。

BACKUP_STREAM_URL

contentType (選用步驟) 內容備份串流的 Mime 類型。僅適用於 DASH 串流。

CONTENT_STREAM_MIMETYPE

streamType 這個值使用的字串常值或常數會因傳送端平台而異。
customData customData 欄位包含其他必填欄位的鍵/值儲存區。在這個範例中,它包含 DAI 串流參數。在正式版應用程式中,您可能會改為傳遞 ID,讓 Cast 接收端應用程式使用伺服器端要求擷取這些參數。
欄位 目錄
daiStreamType DAI 串流類型,可以是 "LIVE" 或 "VOD"

DAI_STREAM_TYPE

networkCode Google Ad Manager 360 帳戶的聯播網代碼。

NETWORK_CODE

customAssetKey 這個欄位僅適用於直播。用於在 Google Ad Manager 360 中識別廣告連播放送事件的自訂素材資源金鑰。

CUSTOM_ASSET_KEY

apiKey 選用的 API 金鑰,用於從 IMA DAI SDK 擷取串流 ID。

API_KEY

以下提供一些程式碼範例,協助您快速上手:

網頁

如要在 Cast 網頁傳送端中設定這些值,請先使用必要資料建立 MediaInfo 物件,然後向網頁接收端發出載入要求。

// 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 網頁傳送端中設定這些值,請先建立包含必要資料的 MediaInfo 物件,然後向網頁接收端發出載入要求。

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 網頁傳送端中設定這些值,請先使用必要資料建立 GCKMediaInformation 物件,然後向網頁接收端發出載入要求。

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 網頁傳送端中設定這些值,請先使用必要資料建立 GCKMediaInformation 物件,然後向網頁接收端發出載入要求。

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 指揮與控制工具中設定這些值,請按一下「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 接收端

建立自訂網路接收器,如 CAF SDK 自訂網路接收器指南所示。

接收器的程式碼應如下所示:

<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 的指令碼後方,新增指令碼標記,將 CAF 專用 IMA DAI SDK 匯入網路接收器。在指令碼標記中,先將接收端內容和播放器管理工具儲存為常數,再啟動接收端。

<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 串流管理工具。

<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 載入攔截器

在將媒體項目傳遞至 CAF 之前,請在載入訊息攔截器中建立串流要求。

    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 成功請求並顯示廣告連播放送串流中的廣告後,建議您在廣告連播放送工作階段結束後,清除所有資源。呼叫 StreamManager.destroy() 即可停止串流播放、停止所有廣告追蹤,並釋出所有已載入的串流素材資源。