Bắt đầu sử dụng SDK IMA DAI

IMA SDK giúp bạn dễ dàng tích hợp quảng cáo đa phương tiện vào trang web và ứng dụng của mình. SDK IMA có thể yêu cầu quảng cáo từ bất kỳ máy chủ quảng cáo tuân thủ VAST nào và quản lý việc phát quảng cáo trong ứng dụng của bạn. Với SDK IMA DAI, các ứng dụng tạo ra một yêu cầu phát trực tuyến cho video quảng cáo và nội dung – VOD hoặc nội dung trực tiếp. Sau đó, SDK sẽ trả về một luồng video kết hợp để bạn không phải quản lý việc chuyển đổi giữa video quảng cáo và video nội dung trong ứng dụng của mình.

Chọn giải pháp DAI mà bạn quan tâm

DAI (Chèn quảng cáo động) phân phát nhóm

Hướng dẫn này minh hoạ cách phát luồng Phân phát nhóm DAI cho nội dung trực tiếp hoặc nội dung VOD, bằng cách sử dụng SDK IMA DAI cho HTML5 với trình phát video dựa trên hls.js để phát lại. Nếu bạn muốn xem hoặc làm theo quy trình tích hợp mẫu hoàn chỉnh, đồng thời hỗ trợ cả HLS.js và Safari Playback, vui lòng xem ví dụ về lựa chọn phân phát nhóm HLS. Để được hỗ trợ cho DASH.js, hãy xem ví dụ về việc phân phát nhóm DASH. Bạn có thể tải các ứng dụng mẫu này xuống từ trang phát hành HTML5 DAI trên GitHub.

Tổng quan về việc phân phát nhóm DAI

Việc triển khai hoạt động phân phát nhóm bằng SDK IMA DAI gồm hai thành phần chính, được minh hoạ trong hướng dẫn này:

  • PodStreamRequest / PodVodStreamRequest: Đối tượng xác định yêu cầu truyền đến các máy chủ quảng cáo của Google. Các yêu cầu chỉ định Mã mạngPodStreamRequest cũng đòi hỏi một Khoá thành phần tuỳ chỉnh và một khoá API không bắt buộc. Cả hai đều bao gồm các tham số không bắt buộc khác.

  • StreamManager: Một đối tượng xử lý hoạt động giao tiếp giữa luồng video và SDK IMA DAI, chẳng hạn như kích hoạt ping theo dõi và chuyển tiếp các sự kiện luồng đến nhà xuất bản.

Điều kiện tiên quyết

Trước khi bắt đầu, bạn cần có:

  • Ba tệp trống:

    • dai.html
    • dai.css
    • dai.js
  • Python được cài đặt trên máy tính của bạn hoặc một máy chủ web hay môi trường phát triển được lưu trữ khác để dùng cho mục đích kiểm thử

Định cấu hình môi trường phát triển

Vì SDK tải các phần phụ thuộc bằng cùng một giao thức với trang mà từ đó SDK được tải, bạn cần sử dụng một máy chủ web để kiểm thử ứng dụng của mình. Cách đơn giản nhất để khởi động một máy chủ phát triển cục bộ là sử dụng máy chủ tích hợp sẵn của Python.

  1. Sử dụng một dòng lệnh từ thư mục chứa tệp index.html chạy:

    python -m http.server 8000
    
  2. Trong trình duyệt web, hãy truy cập vào http://localhost:8000/

    Bạn cũng có thể sử dụng bất kỳ môi trường phát triển hoặc máy chủ web nào khác được lưu trữ, chẳng hạn như Máy chủ HTTP Apache.

Tạo một trình phát video đơn giản

Trước tiên, hãy sửa đổi dai.html để tạo một phần tử video HTML5 đơn giản và một div để sử dụng cho các phần tử Giao diện người dùng quảng cáo. Ngoài ra, hãy thêm các thẻ cần thiết để tải tệp dai.cssdai.js, cũng như để nhập trình phát video hls.js.

Sau đó, hãy sửa đổi dai.css để chỉ định kích thước và vị trí của các phần tử trang. Cuối cùng, trong dai.js, hãy xác định các biến để lưu giữ thông tin về yêu cầu luồng và một hàm initPlayer() để chạy khi trang tải.

Các hằng số yêu cầu luồng như sau:

  • BACKUP_STREAM: URL của một luồng dự phòng sẽ phát trong trường hợp quá trình quảng cáo gặp lỗi nghiêm trọng.

  • STREAM_URL: Chỉ dùng cho sự kiện phát trực tiếp. URL luồng video do người xử lý tệp kê khai hoặc đối tác bên thứ ba cung cấp bằng tính năng phân phát nhóm. Bạn nên chèn mã luồng do SDK IMA DAI cung cấp trước khi đưa ra yêu cầu. Trong trường hợp này, URL luồng bao gồm phần giữ chỗ, [[STREAMID]], được thay thế bằng mã luồng trước khi đưa ra yêu cầu.

  • NETWORK_CODE: Mã mạng cho tài khoản Ad Manager 360 của bạn.

  • CUSTOM_ASSET_KEY: Chỉ dùng cho sự kiện phát trực tiếp. Khoá thành phần tuỳ chỉnh xác định sự kiện phân phát nhóm của bạn trong Ad Manager 360. Trình này có thể được tạo bởi người chỉnh sửa tệp kê khai hoặc đối tác phân phát nhóm của bên thứ ba.

  • API_KEY: Chỉ dùng cho sự kiện phát trực tiếp. Bạn có thể cần một khoá API không bắt buộc để truy xuất mã luồng từ SDK IMA DAI.

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');
}

Tải SDK IMA DAI

Tiếp theo, hãy thêm khung DAI bằng cách sử dụng thẻ tập lệnh trong dai.html, trước thẻ cho 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>
...

Khởi động StreamManager và gửi yêu cầu phát trực tiếp hoặc video theo yêu cầu (VOD)

Phân phát nhóm trong sự kiện phát trực tiếp

Để yêu cầu một nhóm quảng cáo, hãy tạo một ima.dai.api.StreamManager. Lớp này chịu trách nhiệm yêu cầu và quản lý các luồng quảng cáo DAI. Hàm khởi tạo sẽ lấy một phần tử video và thực thể thu được sẽ lấy một phần tử trên giao diện người dùng của quảng cáo để xử lý các lượt tương tác với quảng cáo.

Sau đó, xác định một hàm để yêu cầu nhóm phân phát sự kiện phát trực tiếp. Hàm này trước tiên sẽ tạo một PodStreamRequest, định cấu hình hàm này bằng các tham số streamRequest được cung cấp ở bước 2, sau đó gọi streamManager.requestStream() bằng đối tượng yêu cầu đó.

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

Phân phát nhóm VOD

Để yêu cầu một nhóm quảng cáo, hãy tạo một ima.dai.api.StreamManager. Lớp này chịu trách nhiệm yêu cầu và quản lý các luồng quảng cáo DAI. Hàm khởi tạo sẽ lấy một phần tử video và thực thể thu được sẽ lấy một phần tử trên giao diện người dùng của quảng cáo để xử lý các lượt tương tác với quảng cáo.

Sau đó, xác định một hàm để yêu cầu luồng VOD phân phát nhóm. Hàm này trước tiên sẽ tạo một PodVodStreamRequest, định cấu hình hàm này bằng các tham số streamRequest được cung cấp ở bước 2, sau đó gọi streamManager.requestStream() bằng đối tượng yêu cầu đó.

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

Xử lý sự kiện phát trực tiếp

Phân phát nhóm trong sự kiện phát trực tiếp

Tiếp theo, hãy triển khai trình nghe sự kiện cho các sự kiện video lớn. Ví dụ này xử lý các sự kiện STREAM_INITIALIZED, ERROR, AD_BREAK_STARTEDAD_BREAK_ENDED bằng cách gọi một hàm onStreamEvent(). Hàm này xử lý các lỗi và lỗi trong quá trình tải luồng, cũng như tắt các nút điều khiển trình phát trong khi quảng cáo đang phát (theo yêu cầu của SDK). Khi luồng được tải, trình phát video sẽ tải và phát URL được cung cấp bằng hàm 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);
}

Phân phát nhóm VOD

Tiếp theo, hãy triển khai trình nghe sự kiện cho các sự kiện video lớn. Ví dụ này xử lý các sự kiện STREAM_INITIALIZED, LOADED, ERROR, AD_BREAK_STARTEDAD_BREAK_ENDED bằng cách gọi hàm onStreamEvent(). Hàm này xử lý các lỗi và lỗi trong luồng phát, cũng như tắt các nút điều khiển trình phát trong khi quảng cáo đang phát (theo yêu cầu của SDK).

Ngoài ra, luồng phân phát nhóm VOD yêu cầu gọi StreamManager.loadStreamMetadata() để phản hồi sự kiện STREAM_INITIALIZED. Bạn cũng cần yêu cầu URL phát trực tuyến từ đối tác công nghệ video (VTP) của mình. Sau khi thành công, lệnh gọi loadStreamMetadata() sẽ kích hoạt một sự kiện LOADED, trong đó bạn nên gọi hàm loadStream() bằng URL luồng để tải và phát luồng.

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

Xử lý siêu dữ liệu của sự kiện phát trực tiếp

Ở bước này, bạn triển khai trình nghe sự kiện cho siêu dữ liệu để thông báo cho SDK khi sự kiện quảng cáo xảy ra. Việc theo dõi các sự kiện siêu dữ liệu trong luồng có thể thay đổi, tuỳ thuộc vào định dạng luồng (HLS hoặc DASH), loại luồng (luồng trực tiếp hoặc VOD), loại trình phát và loại phần phụ trợ DAI đang được sử dụng. Xem hướng dẫn về Siêu dữ liệu có thời gian của chúng tôi để biết thêm thông tin.

Định dạng luồng HLS (luồng trực tiếp và VOD, trình phát HLS.js)

Nếu bạn đang sử dụng trình phát HLS.js, hãy theo dõi sự kiện HLS.js FRAG_PARSING_METADATA để lấy siêu dữ liệu ID3 và truyền siêu dữ liệu đó đến SDK bằng StreamManager.processMetadata().

Để tự động phát video sau khi mọi thứ được tải và sẵn sàng, hãy theo dõi sự kiện MANIFEST_PARSED HLS.js để kích hoạt tính năng phát.

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 (định dạng luồng DASH, loại luồng trực tiếp và VOD)

Nếu đang sử dụng trình phát DASH.js, bạn phải sử dụng các chuỗi khác nhau để nghe siêu dữ liệu ID3 cho sự kiện phát trực tiếp hoặc VOD:

  • Sự kiện phát trực tiếp: 'https://developer.apple.com/streaming/emsg-id3'
  • Luồng VOD: 'urn:google:dai:2018'

Truyền siêu dữ liệu ID3 cho SDK bằng StreamManager.processMetadata().

Để tự động hiển thị các nút điều khiển video sau khi mọi thứ được tải và sẵn sàng, hãy theo dõi sự kiện MANIFEST_LOADED DASH.js.

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 với sự kiện phát trực tiếp (định dạng luồng DASH)

Nếu bạn đang dùng trình phát Shaka để phát sự kiện phát trực tiếp, hãy dùng chuỗi 'emsg' để theo dõi các sự kiện siêu dữ liệu. Sau đó, hãy sử dụng dữ liệu tin nhắn sự kiện trong cuộc gọi đến 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 với luồng VOD (định dạng luồng DASH)

Nếu bạn đang dùng trình phát Shaaka để phát luồng VOD, hãy sử dụng chuỗi 'timelineregionenter' để theo dõi các sự kiện siêu dữ liệu. Sau đó, hãy sử dụng dữ liệu thông báo sự kiện trong lệnh gọi đến StreamManager.processMetadata() bằng chuỗi '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);
       }
}

Xử lý sự kiện của người chơi

Thêm trình nghe sự kiện vào các sự kiện pausestart của phần tử video để cho phép người dùng tiếp tục phát khi SDK tạm dừng trong thời điểm chèn quảng cáo.

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';
  }
}

Vậy là xong! Bạn hiện đang yêu cầu và hiển thị quảng cáo trong luồng phân phát nhóm bằng SDK IMA DAI cho HTML5. Để tìm hiểu về các tính năng SDK nâng cao khác, hãy xem hướng dẫn khác hoặc mẫu trên GitHub.