開始使用 IMA DAI SDK

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

選取所需的 DAI 解決方案

廣告連播放送 DAI

本指南說明如何針對直播或 VOD 內容,使用適用於 HTML5 的 IMA DAI SDK,以及採用 hls.js 播放的影片播放器,播放 DAI Pod 放送串流。如要查看或執行已完成的整合範例 (同時支援 HLS.js 和 Safari 播放),請參閱 HLS pod 提供範例。如需 DASH.js 支援,請參閱 DASH Pod 服務範例。 您可以從 HTML5 DAI GitHub 版本頁面下載這些範例應用程式。

DAI 廣告連播放送總覽

使用 IMA DAI SDK 導入廣告連播放送時,必須涵蓋兩個主要元件,詳情請參閱本指南:

  • 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,建立用於廣告 UI 元素的簡易 HTML5 影片元素和 div。此外,請新增必要的標記來載入 dai.cssdai.js 檔案,以及匯入 hls.js 影片播放器。

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

串流要求常數如下:

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

  • STREAM_URL僅適用於直播。由資訊清單操縱器或第三方合作夥伴使用 Pod 放送功能提供的影片串流網址。在發出請求之前,您應該先插入 IMA DAI SDK 提供的串流 ID。在這種情況下,串流網址包含預留位置 [[STREAMID]],在提出要求前會替換為串流 ID。

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

  • CUSTOM_ASSET_KEY僅適用於直播。自訂素材資源鍵,可用來在 Ad Manager 360 中識別廣告連播放送事件。您可以由資訊清單操縱器或第三方 Pod 服務合作夥伴建立這個檔案。

  • API_KEY僅適用於直播。從 IMA DAI SDK 擷取串流 ID 時所需的選用 API 金鑰。

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

直播廣告連播放送

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

接著,定義函式來要求 Pod 放送直播。這個函式會先建立 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 提供 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);
}

處理串流事件

直播廣告連播放送

接下來,實作主要影片事件的事件監聽器。這個範例會透過呼叫 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 廣告連播放送串流需要呼叫 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)、串流類型 (直播或隨選影片串流)、播放器類型,以及使用的 DAI 後端類型而異。詳情請參閱時效中繼資料指南。

HTTP 即時串流格式 (直播和隨選影片串流、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 播放器 (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 播放器 (DASH 串流格式)

如果您使用Shaaka 播放器進行 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';
  }
}

大功告成!現在,您透過適用於 HTML5 的 IMA DAI SDK 請求及顯示廣告的廣告連播放送串流中。如要進一步瞭解其他進階 SDK 功能,請參閱其他指南或 GitHub 範例