הגדרה באמצעות שירות Pod DAI

בחירת פלטפורמה: HTML5 Android iOS tvOS Cast Roku

במדריך הזה נסביר איך להפעיל שידור של הצגת מודעות Pod ב-DAI לתוכן בשידור חי או לתוכן וידאו על פי דרישה (VOD), באמצעות IMA DAI SDK ל-HTML5 עם נגן וידאו שמסתמך על hls.js להפעלה. כדי לראות או לעקוב אחרי דוגמה לשילוב מלא, עם תמיכה גם ב-HLS.js וגם בהפעלה ב-Safari, אפשר לעיין בדוגמה להצגת Pod ב-HLS. לתמיכה ב-DASH.js, אפשר לעיין בדוגמה להצגת Pod ב-DASH. אפשר להוריד את האפליקציות לדוגמה האלה מדף הגרסאות של HTML5 DAI ב-GitHub.

סקירה כללית על הצגת מודעות ברצף ב-DAI

הטמעת Pod Serving באמצעות IMA DAI SDK כוללת שני רכיבים עיקריים, שמוצגים במדריך הזה:

  • ‫PodStreamRequest / PodVodStreamRequest: אובייקט שמגדיר בקשה לשידור לשרתי הפרסום של Google. בבקשות צריך לציין קוד רשת, וב-PodStreamRequest צריך לציין גם מפתח נכס בהתאמה אישית ומפתח API (אופציונלי). שניהם כוללים פרמטרים אופציונליים אחרים.

  • ‫StreamManager: אובייקט שמטפל בתקשורת בין שידור הווידאו לבין IMA DAI SDK, למשל הפעלת פינגים למעקב והעברת אירועי שידור לבעל האפליקציה.

דרישות מוקדמות

לפני שמתחילים, צריך:

  • שלושה קבצים ריקים:

    • 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 של שידור הווידאו שסופקה על ידי הכלי לשינוי המניפסט או שותף צד שלישי שמשתמש ב-Pod Serving. לפני ששולחים בקשה, צריך להזין את מזהה השידור שסופק על ידי IMA DAI SDK. במקרה הזה, כתובת ה-URL של השידור כוללת פלייסהולדר, [[STREAMID]], שמוחלף במזהה השידור לפני שליחת הבקשה.

  • ‫NETWORK_CODE: קוד הרשת של החשבון שלכם ב-Ad Manager 360.

  • ‫CUSTOM_ASSET_KEY: משמש רק לשידורים חיים. מפתח הנכס בהתאמה אישית שמזהה את האירוע של Pod Serving ב-Ad Manager 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

בשלב הבא, מוסיפים את מסגרת ה-DAI באמצעות תג סקריפט ב-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 ושולחים בקשה לשידור חי או לשידור VOD

הצגת מודעות ברצף בשידור חי

כדי לבקש קבוצה של מודעות, יוצרים ima.dai.api.StreamManager, שאחראי לבקשה ולניהול של שידורי DAI. ה-constructor מקבל רכיב וידאו, והמופע שנוצר מקבל רכיב בממשק המשתמש של מודעה כדי לטפל באינטראקציות עם המודעה.

לאחר מכן, מגדירים פונקציה כדי לבקש את השידור החי של הצגת המודעות בקבוצות. הפונקציה הזו יוצרת קודם 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);
}

הצגת מודעות ב-VOD Pod

כדי לבקש קבוצה של מודעות, יוצרים ima.dai.api.StreamManager, שאחראי לבקשה ולניהול של שידורי DAI. ה-constructor מקבל רכיב וידאו, והמופע שנוצר מקבל רכיב בממשק המשתמש של מודעה כדי לטפל באינטראקציות עם המודעה.

לאחר מכן, מגדירים פונקציה לבקשת שידור VOD עם הצגת מודעות ברצף. הפונקציה הזו יוצרת קודם 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);
}

טיפול באירועי סטרימינג

הצגת מודעות ברצף בשידור חי

בשלב הבא, מטמיעים רכיבי event listener לאירועי וידאו מרכזיים. בדוגמה הזו, האירועים 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);
}

הצגת מודעות ב-VOD Pod

בשלב הבא, מטמיעים רכיבי event listener לאירועי וידאו מרכזיים. בדוגמה הזו, האירועים STREAM_INITIALIZED,‏ LOADED,‏ ERROR,‏ AD_BREAK_STARTED ו-AD_BREAK_ENDED מטופלים באמצעות קריאה לפונקציה onStreamEvent(). הפונקציה הזו מטפלת בטעינת השידור ובשגיאות, וגם משביתה את כפתורי הנגן בזמן שהמודעה מוצגת, כפי שנדרש על ידי ה-SDK.

בנוסף, בסטרימינג של VOD Pod Serving צריך להפעיל את StreamManager.loadStreamMetadata() בתגובה לאירוע STREAM_INITIALIZED. אתם צריכים גם לבקש כתובת URL של סטרימינג משותף טכנולוגיית הווידאו (VTP) שלכם. אחרי שהקריאה ל-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);
}

טיפול במטא-נתונים של שידור

בשלב הזה מטמיעים רכיבי event listener למטא-נתונים כדי להודיע ל-SDK כשמתרחשים אירועי מודעות. האזנה לאירועי מטא-נתונים ב-In-stream יכולה להשתנות בהתאם לפורמט השידור (HLS או DASH), לסוג השידור (שידור חי או וידאו על פי דרישה), לסוג הנגן ולסוג של הקצה העורפי של DAI שבו משתמשים. מידע נוסף זמין במדריך בנושא מטא-נתונים מתוזמנים.

פורמט סטרימינג HLS (שידורים חיים ושידורי VOD, נגן HLS.js)

אם אתם משתמשים בנגן HLS.js, האזינו לאירוע FRAG_PARSING_METADATA של HLS.js כדי לקבל מטא-נתונים של 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, סוג סטרימינג: שידור חי ו-VOD)

אם אתם משתמשים בנגן DASH.js, אתם צריכים להשתמש במחרוזות שונות כדי להאזין למטא-נתונים של ID3 בשידורים חיים או בשידורי VOD:

  • שידורים חיים: 'https://developer.apple.com/streaming/emsg-id3'
  • שידורי VOD: ‏'urn:google:dai:2018'

מעבירים את המטא-נתונים של ID3 ל-SDK באמצעות StreamManager.processMetadata().

כדי להציג באופן אוטומטי את פקדי הווידאו אחרי שהכול נטען ומוכן, צריך להאזין לאירוע 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 עם שידורים חיים (פורמט סטרימינג 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 עם שידורי VOD (פורמט שידורי 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);
       }
}

טיפול בפעולות במשחק

מוסיפים פונקציות event listener לאירועים 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.