Как настроить показ пакетов с динамической вставкой объявлений

Выберите платформу: HTML5 Android iOS tvOS Cast Roku

В этом руководстве рассказывается, как воспроизводить трансляции с пакетной передачей объявлений при динамической вставке в прямом эфире или в видео по запросу. Для этого используется IMA DAI SDK для HTML5 и видеопроигрыватель, в котором воспроизведение выполняется с помощью hls.js. Чтобы посмотреть или использовать готовый пример интеграции с поддержкой HLS.js и воспроизведения в Safari, ознакомьтесь с примером показа пакета HLS. Информацию о поддержке DASH.js можно найти в примере показа пакетов с динамической вставкой объявлений в DASH. Скачать эти примеры приложений можно на странице выпуска HTML5 DAI на GitHub.

Общие сведения о показе пакетов с динамической вставкой объявлений

Реализация показа пакетов с помощью 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, чтобы создать элемент видео HTML5 и элемент div для элементов интерфейса объявлений. Также добавьте теги, необходимые для загрузки файлов dai.css и dai.js и импорта видеопроигрывателя hls.js.

Затем измените файл dai.css, чтобы задать размер и положение элементов страницы. Наконец, в файле dai.js определите переменные, которые будут содержать информацию о запросе потока, и функцию initPlayer(), которая будет выполняться при загрузке страницы.

Константы запроса потока:

  • BACKUP_STREAM – URL резервного потока, который будет воспроизводиться, если при обработке объявлений возникнет критическая ошибка.

  • STREAM_URL: используется только для прямых трансляций. URL видеопотока, предоставленный вашим инструментом управления манифестом или внешним партнером, который использует показ пакетов. Перед отправкой запроса вам потребуется указать идентификатор трансляции, предоставленный IMA DAI SDK. В этом случае URL потока содержит плейсхолдер [[STREAMID]], который перед отправкой запроса заменяется идентификатором потока.

  • NETWORK_CODE – код сети вашего аккаунта Менеджера рекламы 360.

  • CUSTOM_ASSET_KEY: используется только для прямых трансляций. Специальный ключ объекта, который идентифицирует событие пакетной передачи объявлений в Менеджере рекламы 360. Его может создать ваш инструмент управления манифестом или сторонний партнер по пакетной передаче объявлений.

  • API_KEY: используется только для прямых трансляций. Необязательный ключ API, который может потребоваться для получения идентификатора потока из IMA DAI SDK.

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

Затем добавьте фреймворк динамической вставки объявлений с помощью тега script в файле dai.html перед тегом для 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, который отвечает за запрос потоков с динамической вставкой объявлений и управление ими. Конструктор принимает элемент видео, а полученный экземпляр – элемент интерфейса объявления для обработки взаимодействий с объявлением.

Затем определите функцию для запроса трансляции с показом пакетов. Эта функция сначала создает объект PodStreamRequest, настраивает его с помощью параметров streamRequest, указанных на шаге 2, а затем вызывает 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, который отвечает за запрос потоков с динамической вставкой объявлений и управление ими. Конструктор принимает элемент видео, а полученный экземпляр – элемент интерфейса объявления для обработки взаимодействий с объявлением.

Затем определите функцию для запроса потока видео по запросу с показом пакетов. Эта функция сначала создает объект PodVodStreamRequest, настраивает его с помощью параметров streamRequest, указанных на шаге 2, а затем вызывает 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);
}

Обработка событий потока

Показ пакетов в трансляциях

Затем реализуйте прослушиватели основных событий видео. В этом примере события STREAM_INITIALIZED, ERROR, AD_BREAK_STARTED и AD_BREAK_ENDED обрабатываются путем вызова функции onStreamEvent(). Эта функция обрабатывает загрузку потока и ошибки, а также отключает элементы управления проигрывателем во время воспроизведения объявления, как того требует SDK. Когда поток загружен, видеопроигрыватель загружает и воспроизводит предоставленный URL с помощью функции 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);
}

Показ пакетов в видео по запросу

Затем реализуйте прослушиватели основных событий видео. В этом примере события STREAM_INITIALIZED, LOADED, ERROR, AD_BREAK_STARTED и AD_BREAK_ENDED обрабатываются путем вызова функции onStreamEvent(). Эта функция обрабатывает загрузку потока и ошибки, а также отключает элементы управления проигрывателем во время показа объявления, как того требует SDK.

Кроме того, для трансляций с пакетной передачей видео по запросу необходимо вызывать StreamManager.loadStreamMetadata() в ответ на событие STREAM_INITIALIZED. Вам также нужно запросить URL потока у партнера по видеотехнологиям. После успешного вызова loadStreamMetadata() активируется событие LOADED, в котором нужно вызвать функцию loadStream() с URL трансляции, чтобы загрузить и воспроизвести ее.

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), ее типа (прямая трансляция или видео по запросу), типа проигрывателя и типа используемого бэкенда динамической вставки объявлений. Подробную информацию вы найдете в руководстве по временным метаданным.

Формат потока HLS (прямые трансляции и видео по запросу, проигрыватель HLS.js)

Если вы используете проигрыватель HLS.js, отслеживайте событие FRAG_PARSING_METADATA, чтобы получать метаданные ID3 и передавать их в SDK с помощью StreamManager.processMetadata().

Чтобы видео автоматически воспроизводилось после загрузки и подготовки всех элементов, настройте отслеживание события MANIFEST_PARSED в HLS.js.

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, тип потоков Live и VOD)

Если вы используете проигрыватель DASH.js, то для прослушивания метаданных ID3 в прямых трансляциях и видео по запросу вам нужно использовать разные строки:

  • Трансляции: 'https://developer.apple.com/streaming/emsg-id3'
  • Потоки видео по запросу: 'urn:google:dai:2018'

Передайте метаданные ID3 в SDK с помощью StreamManager.processMetadata().

Чтобы элементы управления видео автоматически показывались после того, как все загрузится и будет готово, отслеживайте событие 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 Player для воспроизведения прямых трансляций, используйте строку '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 с видео по запросу (формат DASH)

Если вы используете Shaka Player для воспроизведения видео по запросу, используйте строку '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);
       }
}

Обработка событий проигрывателя

Добавьте прослушиватели событий к событиям pause и start элемента видео, чтобы пользователь мог возобновить воспроизведение, когда 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, мы рекомендуем удалить все ресурсы, которые использовались во время сеанса пакетной передачи. Вызовите StreamManager.destroy(), чтобы остановить воспроизведение потока, прекратить отслеживание рекламы и освободить все загруженные объекты потока.

Чтобы узнать больше о расширенных функциях SDK, ознакомьтесь с другими руководствами или примерами на GitHub.