開始使用 IMA DAI SDK

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

選取感興趣的動態廣告解決方案

DAI 廣告連播放送

本指南將說明如何使用 HTML5 專用的 IMA DAI SDK,搭配仰賴 hls.js 播放的影片播放器,播放直播或隨選內容的 DAI 廣告連播放送串流。如要查看或瞭解完整的整合範例,並支援 HLS.js 和 Safari 播放功能,請參閱 HLS Pod 服務範例。如需 DASH.js 支援資訊,請參閱 DASH 廣告連播放送示例。您可以前往 HTML5 DAI GitHub 發布頁面下載這些範例應用程式。

DAI 廣告連播放送功能總覽

使用 IMA DAI SDK 實作 Pod 服務,需要兩個主要元件,本指南會說明如下:

  • PodStreamRequest / PodVodStreamRequest:定義傳送至 Google 廣告伺服器的串流要求的物件。要求會指定 Network Code,而 PodStreamRequest 也需要 Custom Asset Key,以及選用的 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 放送事件的自訂素材資源鍵。這可以由資訊清單操控工具或第三方廣告連播放送合作夥伴建立。

  • 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="ad-ui"></div>
</body>
</html>

dai.css

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

#ad-ui {
  cursor: pointer;
}

dai.js

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

// Stream Config.
const STREAM_URL = "https://encodersim.sandbox.google.com/masterPlaylist/...&stream_id=[[STREAMID]]";
const NETWORK_CODE = "51636543";
const CUSTOM_ASSET_KEY = "google-sample";
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 架構,並放在 dai.js 的標記前面。

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,並提出直播或 VOD 串流要求

直播 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);
}

VOD 廣告連播放送

如要要求一組廣告,請建立 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);
}

VOD 廣告連播放送

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

此外,VOD Pod 服務串流必須呼叫 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。您可以根據串流格式 (HLS 或 DASH)、串流類型 (直播或 VOD 串流)、播放器類型,以及使用的 DAI 後端類型,來判斷是否要監聽串流中繼資料事件。詳情請參閱時間設定的結構化資料指南。

HLS 串流格式 (直播和 VOD 串流、HLS.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 播放器,則必須使用不同的字串來收聽直播或 VOD 串流的 ID3 中繼資料:

  • 直播:'https://developer.apple.com/streaming/emsg-id3'
  • VOD 串流:'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});
}

搭配 VOD 串流的 Shaka Player (DASH 串流格式)

如果您使用 Shaka player 播放 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 放送串流中成功完成廣告請求和顯示作業後,建議您在 Pod 放送工作階段結束後清理所有資源。呼叫 StreamManager.destroy() 即可停止串流播放、停止所有廣告追蹤,並釋放所有已載入的串流資產。

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