設定 DAI 專用的 IMA SDK

使用 IMA SDK,即可輕鬆將多媒體廣告整合至網站和應用程式。IMA SDK 可向任何 符合 VAST 規定的廣告伺服器請求廣告,並在應用程式中管理廣告播放。應用程式可透過 IMA DAI SDK,對廣告和內容影片 (隨選影片或直播內容) 提出串流請求。SDK 接著會傳回合併的影片串流,因此您不必在應用程式中管理廣告和內容影片之間的切換。

選取您感興趣的 DAI 解決方案

廣告連播放送 DAI

本指南說明如何使用 IMA DAI HTML5 SDK,透過以 hls.js 播放的影片播放器,播放直播或隨選視訊內容的 DAI 廣告連播放送串流。如要查看或追蹤已完成的整合範例,並支援 HLS.js 和 Safari 播放,請參閱 HLS Pod Serving 範例。如需 DASH.js 支援,請參閱 DASH 廣告連播放送範例。 您可以從 HTML5 DAI GitHub 發布頁面下載這些範例應用程式。

DAI 廣告連播放送總覽

使用 IMA DAI SDK 導入 Pod Serving 時,會用到兩個主要元件,本指南將說明這兩個元件:

  • PodStreamRequest / PodVodStreamRequest:定義向 Google 廣告伺服器發出的串流要求的物件。要求會指定聯播網代碼PodStreamRequest 也需要自訂資產金鑰和選用的 API 金鑰。兩者都包含其他選用參數。

  • StreamManager:這個物件會處理影片串流和 IMA DAI SDK 之間的通訊,例如觸發追蹤 Ping 和將串流事件轉送給發布商。

必要條件

開始之前,請先備妥下列項目:

  • 三個空白檔案:

    • dai.html
    • dai.css
    • dai.js
  • 電腦上安裝的 Python,或是用於測試的網路伺服器或其他代管開發環境

設定開發環境

由於 SDK 會使用與載入網頁相同的通訊協定載入依附元件,因此您需要使用網路伺服器測試應用程式。如要快速啟動本機開發伺服器,可以使用 Python 內建的伺服器。

  1. 透過指令列,從包含 index.html 檔案的目錄執行下列指令:

    python -m http.server 8000
  2. 使用網路瀏覽器前往 http://localhost:8000/

    您也可以使用任何其他代管開發環境或網路伺服器,例如 Apache HTTP Server

建立影片播放器

首先,請修改 dai.html,建立 HTML5 影片元素和 div,供廣告 UI 元素使用。此外,請新增必要標記,載入 dai.cssdai.js 檔案,並匯入 hls.js 影片播放器。

然後修改 dai.css,指定網頁元素的大小和位置。 最後,在 dai.js 中,定義變數來保存串流要求資訊,以及網頁載入時執行的 initPlayer() 函式。

串流要求常數如下:

  • BACKUP_STREAM:備用串流的網址,可在廣告程序發生嚴重錯誤時播放。

  • STREAM_URL僅用於直播。資訊清單操控器或第三方合作夥伴使用廣告連播放送功能提供的影片串流網址。您必須先插入 IMA DAI SDK 提供的串流 ID,才能提出要求。在本例中,串流網址包含預留位置 [[STREAMID]],系統會在提出要求前將其替換為串流 ID。

  • NETWORK_CODE:Ad Manager 360 帳戶的聯播網代碼。

  • CUSTOM_ASSET_KEY僅用於直播。自訂素材資源鍵,用於在 Ad Manager 360 中識別 Pod Serving 事件。這類資訊可由資訊清單操控器或第三方廣告連播放送合作夥伴建立。

  • API_KEY僅用於直播。選用 API 金鑰,可從 IMA DAI SDK 擷取串流 ID。

dai.html

<html>
<head>
  <script src="https://cdn.jsdelivr.net/npm/hls.js@latest"></script>
  <script src="dai.js"></script>
  <link rel="stylesheet" href="dai.css" type="text/css">
</head>
<body onLoad="initPlayer()">
  <h2>IMA DAI SDK Demo (HLS.JS)</h2>
    <video id="video"></video>
    <div id="adUi"></div>
</body>
</html>

dai.css

#video,
#adUi {
  width: 640px;
  height: 360px;
  position: absolute;
  top: 35px;
  left: 0;
}

#adUi {
  cursor: pointer;
}

dai.js

var BACKUP_STREAM =
    'https://storage.googleapis.com/interactive-media-ads/media/bbb.m3u8'

// Stream Config.
const STREAM_URL = "";
const NETWORK_CODE = "";
const CUSTOM_ASSET_KEY = "";
const API_KEY = "";

var hls = new Hls(); // hls.js video player
var videoElement;
var adUiElement;

function initPlayer() {
  videoElement = document.getElementById('video');
  adUiElement = document.getElementById('adUi');
}

載入 IMA DAI SDK

接著,在 dai.html 中,於 dai.js 的標記之前,使用指令碼標記加入 DAI 架構。

dai.html

<html>
<head>
  <script src="https://cdn.jsdelivr.net/npm/hls.js@latest"></script>
  <script type="text/javascript" src="//imasdk.googleapis.com/js/sdkloader/ima3_dai.js"></script>
  <script src="dai.js"></script>
  <link rel="stylesheet" href="dai.css" type="text/css">
</head>
...

初始化 StreamManager,並發出直播或隨選影片串流要求

直播 Pod 放送

如要要求一組廣告,請建立 ima.dai.api.StreamManager,負責要求及管理 DAI 串流。建構函式會採用影片元素,產生的執行個體則會採用廣告 UI 元素來處理廣告互動。

接著,定義要求 Pod Serving 直播的函式。這個函式會先建立 PodStreamRequest,然後使用步驟 2 中提供的 streamRequest 參數設定該函式,最後使用該要求物件呼叫 streamManager.requestStream()

dai.js

function initPlayer() {
  videoElement = document.getElementById('video');
  adUiElement = document.getElementById('adUi');
  streamManager = new google.ima.dai.api.StreamManager(videoElement, adUiElement)

  requestLivePodStream(NETWORK_CODE, CUSTOM_ASSET_KEY, API_KEY);
}

function requestLivePodStream(networkCode, customAssetKey, apiKey) {
  // clear HLS.js instance, if in use
  if (hls) {
    hls.destroy();
  }

  // Generate a Pod Serving live Stream Request
  const streamRequest = new google.ima.dai.api.PodStreamRequest();
  streamRequest.networkCode = networkCode;
  streamRequest.customAssetKey = customAssetKey;
  streamRequest.apiKey = apiKey;
  streamRequest.format = 'hls';
  streamManager.requestStream(streamRequest);
}

隨選影片廣告連播放送

如要要求一組廣告,請建立 ima.dai.api.StreamManager,負責要求及管理 DAI 串流。建構函式會採用影片元素,產生的執行個體則會採用廣告 UI 元素來處理廣告互動。

接著,定義函式來要求 Pod Serving VOD 串流。這個函式會先建立 PodVodStreamRequest,然後使用步驟 2 中提供的 streamRequest 參數設定該函式,最後使用該要求物件呼叫 streamManager.requestStream()

dai.js

function initPlayer() {
  videoElement = document.getElementById('video');
  adUiElement = document.getElementById('adUi');
  streamManager = new google.ima.dai.api.StreamManager(videoElement, adUiElement)

  requestVodPodStream(NETWORK_CODE);
}

function requestVodPodStream(networkCode) {
  // clear HLS.js instance, if in use
  if (hls) {
    hls.destroy();
  }

  // Generate a Pod Serving VOD Stream Request
  const streamRequest = new google.ima.dai.api.PodVodStreamRequest();
  streamRequest.networkCode = networkCode;
  streamRequest.format = 'hls';
  streamManager.requestStream(streamRequest);
}

處理串流事件

直播 Pod 放送

接著,為主要影片事件實作事件監聽器。這個範例會呼叫 onStreamEvent() 函式,處理 STREAM_INITIALIZEDERRORAD_BREAK_STARTEDAD_BREAK_ENDED 事件。這個函式會處理串流載入和錯誤,並在播放廣告時停用播放器控制項,這是 SDK 的必要功能。載入串流時,影片播放程式會使用 loadStream() 函式載入並播放提供的網址。

dai.js

var isAdBreak;

function initPlayer() {
  videoElement = document.getElementById('video');
  adUiElement = document.getElementById('adUi');
  streamManager = new google.ima.dai.api.StreamManager(videoElement, adUiElement);
  
  streamManager.addEventListener(
    [google.ima.dai.api.StreamEvent.Type.STREAM_INITIALIZED,
    google.ima.dai.api.StreamEvent.Type.ERROR,
    google.ima.dai.api.StreamEvent.Type.AD_BREAK_STARTED,
    google.ima.dai.api.StreamEvent.Type.AD_BREAK_ENDED],
    onStreamEvent,
    false);
...
function onStreamEvent(e) {
  switch (e.type) {
    case google.ima.dai.api.StreamEvent.Type.STREAM_INITIALIZED:
      console.log('Stream initialized');
      loadStream(e.getStreamData().streamId);
      break;
    case google.ima.dai.api.StreamEvent.Type.ERROR:
      console.log('Error loading stream, playing backup stream.' + e);
      loadStream('');
      break;
    case google.ima.dai.api.StreamEvent.Type.AD_BREAK_STARTED:
      console.log('Ad Break Started');
      isAdBreak = true;
      videoElement.controls = false;
      adUiElement.style.display = 'block';
      break;
    case google.ima.dai.api.StreamEvent.Type.AD_BREAK_ENDED:
      console.log('Ad Break Ended');
      isAdBreak = false;
      videoElement.controls = true;
      adUiElement.style.display = 'none';
      break;
    default:
      break;
  }
}

function loadStream(streamID) {
  var url;
  if(streamID) {
    url = STREAM_URL.replace('[[STREAMID]]', streamID);
  } else {
    console.log('Stream Initialization Failed');
    url = BACKUP_STREAM;
  }
  console.log('Loading:' + url);
  hls.loadSource(url);
  hls.attachMedia(videoElement);
}

隨選影片廣告連播放送

接著,為主要影片事件實作事件監聽器。這個範例會呼叫 onStreamEvent() 函式,處理 STREAM_INITIALIZEDLOADEDERRORAD_BREAK_STARTEDAD_BREAK_ENDED 事件。這個函式會處理串流載入和錯誤,並在播放廣告時停用播放器控制項,這是 SDK 的必要功能。

此外,VOD Pod Serving 串流需要呼叫 StreamManager.loadStreamMetadata(),以回應 STREAM_INITIALIZED 事件。此外,您也需要向影片技術合作夥伴 (VTP) 索取串流網址。loadStreamMetadata() 呼叫成功後,系統會觸發 LOADED 事件,您應使用串流網址呼叫 loadStream() 函式,載入及播放串流。

var isAdBreak;

function initPlayer() {
  videoElement = document.getElementById('video');
  adUiElement = document.getElementById('adUi');
  streamManager = new google.ima.dai.api.StreamManager(videoElement, adUiElement);
  
  streamManager.addEventListener(
    [google.ima.dai.api.StreamEvent.Type.STREAM_INITIALIZED,
    google.ima.dai.api.StreamEvent.Type.ERROR,
    google.ima.dai.api.StreamEvent.Type.AD_BREAK_STARTED,
    google.ima.dai.api.StreamEvent.Type.AD_BREAK_ENDED],
    onStreamEvent,
    false);
...
function onStreamEvent(e) {
  switch (e.type) {
    case google.ima.dai.api.StreamEvent.Type.STREAM_INITIALIZED:
      const streamId = e.getStreamData().streamId;
      // 'vtpInterface' is a place holder for your own video technology
      //  partner (VTP) API calls.
      vtpInterface.requestStreamURL({
        'streamId': streamId,
      })
      .then( (vtpStreamUrl) => {
        streamUrl = vtpStreamUrl;
        streamManager.loadStreamMetadata();
      }, (error) => {
        // Handle the error.
      });
      break;
    case google.ima.dai.api.StreamEvent.Type.LOADED:
      loadStream(streamUrl);
      break;
    case google.ima.dai.api.StreamEvent.Type.ERROR:
      console.log('Error loading stream, playing backup stream.' + e);
      loadStream();
      break;
    case google.ima.dai.api.StreamEvent.Type.AD_BREAK_STARTED:
      console.log('Ad Break Started');
      isAdBreak = true;
      videoElement.controls = false;
      adUiElement.style.display = 'block';
      break;
    case google.ima.dai.api.StreamEvent.Type.AD_BREAK_ENDED:
      console.log('Ad Break Ended');
      isAdBreak = false;
      videoElement.controls = true;
      adUiElement.style.display = 'none';
      break;
    default:
      break;
  }
}

function loadStream(url) {
  if(url) {
    console.log('Loading:' + url);
    hls.loadSource(url);
  } else {
    console.log('Stream Initialization Failed');
    hls.loadSource(BACKUP_STREAM);
  }
  hls.attachMedia(videoElement);
}

處理串流中繼資料

在這個步驟中,您將實作中繼資料的事件監聽器,在廣告事件發生時通知 SDK。視串流格式 (HTTP 即時串流或 DASH)、串流類型 (直播或隨選視訊串流)、播放器類型和使用的 DAI 後端類型而定,監聽串流中繼資料事件的方式可能有所不同。詳情請參閱時間碼中繼資料指南。

HTTP 即時串流格式 (直播和隨選影片串流,HTTP 即時串流.js 播放器)

如果您使用 HLS.js 播放器,請監聽 HLS.js FRAG_PARSING_METADATA 事件,取得 ID3 中繼資料,並透過 StreamManager.processMetadata() 傳遞至 SDK。

如要在所有內容載入完畢後自動播放影片,請監聽 HLS.js MANIFEST_PARSED 事件來觸發播放。

function loadStream(streamID) {
  hls.loadSource(url);
  hls.attachMedia(videoElement);
  
  // Timed metadata is passed HLS stream events to the streamManager.
  hls.on(Hls.Events.FRAG_PARSING_METADATA, parseID3Events);
  hls.on(Hls.Events.MANIFEST_PARSED, startPlayback);
}

function parseID3Events(event, data) {
  if (streamManager && data) {
    // For each ID3 tag in the metadata, pass in the type - ID3, the
    // tag data (a byte array), and the presentation timestamp (PTS).
    data.samples.forEach((sample) => {
      streamManager.processMetadata('ID3', sample.data, sample.pts);
    });
  }
}

function startPlayback() {
  console.log('Video Play');
  videoElement.play();
}

DASH.js (DASH 串流格式、直播和 VOD 串流類型)

如果您使用 DASH.js 播放器,必須使用不同的字串,才能監聽直播或隨選視訊串流的 ID3 中繼資料:

  • 直播:'https://developer.apple.com/streaming/emsg-id3'
  • 隨選影片串流:'urn:google:dai:2018'

使用 StreamManager.processMetadata() 將 ID3 中繼資料傳遞至 SDK。

如要在所有內容載入完畢並準備就緒後自動顯示影片控制項,請監聽 DASH.js MANIFEST_LOADED 事件。

const googleLiveSchema = 'https://developer.apple.com/streaming/emsg-id3';
const googleVodSchema = 'urn:google:dai:2018';
dashPlayer.on(googleLiveSchema, processMetadata);
dashPlayer.on(googleVodSchema, processMetadata);
dashPlayer.on(dashjs.MediaPlayer.events.MANIFEST_LOADED, loadlistener);

function processMetadata(metadataEvent) {
  const messageData = metadataEvent.event.messageData;
  const timestamp = metadataEvent.event.calculatedPresentationTime;

  // Use StreamManager.processMetadata() if your video player provides raw
  // ID3 tags, as with dash.js.
  streamManager.processMetadata('ID3', messageData, timestamp);
}

function loadlistener() {
  showControls();

  // This listener must be removed, otherwise it triggers as addional
  // manifests are loaded. The manifest is loaded once for the content,
  // but additional manifests are loaded for upcoming ad breaks.
  dashPlayer.off(dashjs.MediaPlayer.events.MANIFEST_LOADED, loadlistener);
}

Shaka Player (直播,DASH 串流格式)

如果您使用 Shaka 播放器播放直播,請使用字串 'emsg' 監聽中繼資料事件。然後在對 StreamManager.onTimedMetadata() 的呼叫中使用事件訊息資料。

shakaPlayer.addEventListener('emsg', (event) => onEmsgEvent(event));

function onEmsgEvent(metadataEvent) {
  // Use StreamManager.onTimedMetadata() if your video player provides
  // processed metadata, as with Shaka player livestreams.
  streamManager.onTimedMetadata({'TXXX': metadataEvent.detail.messageData});
}

使用 Shaka Player 播放 VOD 串流 (DASH 串流格式)

如果您使用 Shaka 播放器播放 VOD 串流,請使用字串 'timelineregionenter' 監聽中繼資料事件。然後在呼叫中使用事件訊息資料,StreamManager.processMetadata() 字串為 'urn:google:dai:2018'

shakaPlayer.addEventListener('timelineregionenter', (event) => onTimelineEvent(event));

function onTimelineEvent(metadataEvent) {
  const detail = metadataEvent.detail;
  if ( detail.eventElement.attributes &&
       detail.eventElement.attributes['messageData'] &&
       detail.eventElement.attributes['messageData'].value ) {
        const mediaId = detail.eventElement.attributes['messageData'].value;
        const pts = detail.startTime;
        // Use StreamManager.processMetadata() if your video player provides raw
        // ID3 tags, as with Shaka player VOD streams.
        streamManager.processMetadata('urn:google:dai:2018', mediaId, pts);
       }
}

處理播放器事件

在影片元素的 pausestart 事件中新增事件監聽器,讓使用者在 SDK 於廣告插播期間暫停時,可以繼續播放影片。

function loadStream(streamUrl) {
  ...
  
  videoElement.addEventListener('pause', onStreamPause);
  videoElement.addEventListener('play', onStreamPlay);
}

function onStreamPause() {
  console.log('paused');
  if (isAdBreak) {
    videoElement.controls = true;
    adUiElement.style.display = 'none';
  }
}

function onStreamPlay() {
  console.log('played');
  if (isAdBreak) {
    videoElement.controls = false;
    adUiElement.style.display = 'block';
  }
}

清理 IMA DAI 資產

使用 IMA DAI SDK 成功在 Pod Serving 串流中請求及顯示廣告後,建議您在 Pod Serving 工作階段完成後清除所有資源。呼叫 StreamManager.destroy() 可停止串流播放、停止所有廣告追蹤,並釋出所有已載入的串流資產。

如要瞭解更多進階 SDK 功能,請參閱其他指南或 GitHub 上的範例