תחילת העבודה עם IMA DAI SDK

ערכות ה-SDK של IMA מאפשרות לשלב בקלות מודעות מולטימדיה באתרים ובאפליקציות שלכם. ערכות ה-SDK של IMA יכולות לבקש מודעות מכל שרת מודעות שתואם ל-VAST ולנהל את ההפעלה של המודעות באפליקציות. באמצעות ערכות ה-SDK של IMA DAI, האפליקציות שולחות בקשה לשידור של מודעת וידאו ותוכן וידאו – VOD או תוכן בשידור חי. לאחר מכן, ה-SDK מחזיר שידור וידאו משולב, כך שלא תצטרכו לנהל את המעבר בין סרטון המודעה לסרטון התוכן באפליקציה.

בחירת פתרון ה-DAI הרצוי

Pod Serving DAI

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

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

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

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

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

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

  • CUSTOM_ASSET_KEY: משמש רק לשידורים חיים. מפתח הנכס המותאם אישית שמזהה את אירוע הצגת המודעות ב-Pod ב-Ad Manager 360. אפשר ליצור אותו באמצעות הכלי לעיבוד המניפסט או באמצעות שותף צד שלישי להצגת מודעות ב-Pod.

  • 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="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 באמצעות תג סקריפט ב-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 מקבלים אלמנט וידאו, ובמכונה שנוצרת מקבלים אלמנט של ממשק המשתמש של המודעה כדי לטפל באינטראקציות עם המודעה.

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

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

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

בשלב הבא, מטמיעים מאזינים לאירועים של סרטונים חשובים. בדוגמה הזו מתבצעת קריאה לפונקציה onStreamEvent() כדי לטפל באירועים STREAM_INITIALIZED, ERROR, AD_BREAK_STARTED ו-AD_BREAK_ENDED. הפונקציה הזו מטפלת בחיוב ובשגיאות של הסטרימינג, וגם משביתה את אמצעי הבקרה של הנגן בזמן שהמודעה פועלת, כפי שנדרש על ידי ה-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

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

בנוסף, כדי להפעיל את ההעברה של רצפי הווידאו ב-VOD, צריך להפעיל את 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);
}

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

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

טיפול באירועי שחקנים

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