คู่มือนี้แสดงวิธีเล่นสตรีม DAI Pod Serving สำหรับเนื้อหาสดหรือ VOD โดยใช้ IMA DAI SDK สำหรับ HTML5 กับวิดีโอเพลเยอร์ที่ใช้ hls.js สำหรับการเล่น หากต้องการดูหรือทำตามการผสานรวมตัวอย่างที่เสร็จสมบูรณ์ซึ่งรองรับทั้ง HLS.js และการเล่น Safari โปรดดูตัวอย่างการแสดงพ็อด HLS สำหรับการรองรับ DASH.js โปรดดูตัวอย่างการแสดงพ็อด DASH คุณดาวน์โหลดแอปตัวอย่างเหล่านี้ได้จากหน้าเผยแพร่ HTML5 DAI GitHub
ภาพรวมของ DAI Pod Serving
การใช้ Pod Serving โดยใช้ IMA DAI SDK มีองค์ประกอบหลัก 2 อย่าง ซึ่งจะอธิบายไว้ในคู่มือนี้
PodStreamRequest/PodVodStreamRequest: ออบเจ็กต์ที่กำหนดคำขอสตรีมไปยังเซิร์ฟเวอร์โฆษณาของ Google คำขอจะระบุรหัสเครือข่าย และPodStreamRequestยังต้องใช้คีย์เนื้อหาที่กำหนดเองและคีย์ API ที่ไม่บังคับด้วย ทั้ง 2 รายการมีพารามิเตอร์อื่นๆ ที่ไม่บังคับStreamManager: ออบเจ็กต์ที่จัดการการสื่อสารระหว่างสตรีมวิดีโอกับ IMA DAI SDK เช่น การเริ่มส่งคําสั่ง ping ติดตามและการส่งต่อเหตุการณ์สตรีมไปยังผู้เผยแพร่โฆษณา
ข้อกำหนดเบื้องต้น
ก่อนเริ่มต้น คุณต้องมีสิ่งต่อไปนี้
ไฟล์ว่างเปล่า 3 ไฟล์:
- dai.html
- dai.css
- dai.js
Python ที่ติดตั้งในคอมพิวเตอร์ หรือเว็บเซิร์ฟเวอร์ หรือสภาพแวดล้อมในการพัฒนาซอฟต์แวร์ที่โฮสต์อื่นๆ เพื่อใช้ในการทดสอบ
กำหนดค่าสภาพแวดล้อมในการพัฒนาซอฟต์แวร์
เนื่องจาก SDK โหลดทรัพยากร Dependency โดยใช้โปรโตคอลเดียวกับหน้าเว็บที่โหลด คุณจึงต้องใช้เว็บเซิร์ฟเวอร์เพื่อทดสอบแอป วิธีที่รวดเร็วในการเริ่มเซิร์ฟเวอร์การพัฒนาในเครื่องคือการใช้เซิร์ฟเวอร์ในตัวของ Python
ใช้บรรทัดคำสั่งจากไดเรกทอรีที่มีไฟล์
index.htmlเพื่อเรียกใช้คำสั่งต่อไปนี้python -m http.server 8000ในเว็บเบราว์เซอร์ ให้ไปที่
http://localhost:8000/นอกจากนี้ คุณยังใช้สภาพแวดล้อมในการพัฒนาซอฟต์แวร์หรือเว็บเซิร์ฟเวอร์อื่นๆ ที่โฮสต์ได้ เช่น Apache HTTP Server
สร้างวิดีโอเพลเยอร์
ก่อนอื่น ให้แก้ไข dai.html เพื่อสร้างองค์ประกอบวิดีโอ HTML5 และ div เพื่อใช้สำหรับองค์ประกอบ UI ของโฆษณา นอกจากนี้ ให้เพิ่มแท็กที่จำเป็นเพื่อโหลดไฟล์ dai.css และ dai.js รวมถึงนำเข้าวิดีโอเพลเยอร์ hls.js ด้วย
จากนั้นแก้ไข dai.css เพื่อระบุขนาดและตำแหน่งขององค์ประกอบของหน้า
สุดท้าย ใน dai.js ให้กำหนดตัวแปรเพื่อเก็บข้อมูลคำขอสตรีมและฟังก์ชัน initPlayer() เพื่อเรียกใช้เมื่อการโหลดหน้าเว็บ
ค่าคงที่ของคำขอสตรีมมีดังนี้
BACKUP_STREAM: URL สำหรับสตรีมสำรองที่จะเล่นในกรณีที่กระบวนการโฆษณาพบข้อผิดพลาดร้ายแรงSTREAM_URL: ใช้สำหรับไลฟ์สดเท่านั้น URL ของสตรีมวิดีโอที่ได้จากโปรแกรมจัดการไฟล์ Manifest หรือพาร์ทเนอร์บุคคลที่สามที่ใช้ Pod Serving โดยคุณจะต้องใส่รหัสสตรีมที่ IMA DAI SDK ระบุไว้ก่อนส่งคำขอ ในกรณีนี้ URL ของสตรีมจะมีตัวยึดตำแหน่ง[[STREAMID]]ซึ่งจะแทนที่ด้วยรหัสสตรีมก่อนส่งคำขอNETWORK_CODE: รหัสเครือข่ายสำหรับบัญชี Ad Manager 360CUSTOM_ASSET_KEY: ใช้สำหรับไลฟ์สดเท่านั้น คีย์ชิ้นงานที่กำหนดเองซึ่งระบุเหตุการณ์การแสดงโฆษณาแบบพ็อดใน Ad Manager 360 ซึ่งอาจสร้างโดยโปรแกรมจัดการไฟล์ Manifest หรือพาร์ทเนอร์ Pod Serving บุคคลที่สาม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 ตัวสร้างจะรับองค์ประกอบวิดีโอ และอินสแตนซ์ที่ได้จะรับองค์ประกอบ UI ของโฆษณาเพื่อจัดการการโต้ตอบกับโฆษณา
จากนั้นกำหนดฟังก์ชันเพื่อขอไลฟ์สดที่ใช้ 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
หากต้องการขอชุดโฆษณา ให้สร้าง ima.dai.api.StreamManager ซึ่งมีหน้าที่ขอและจัดการสตรีม DAI ตัวสร้างจะรับองค์ประกอบวิดีโอ และอินสแตนซ์ที่ได้จะรับองค์ประกอบ UI ของโฆษณาเพื่อจัดการการโต้ตอบกับโฆษณา
จากนั้นกำหนดฟังก์ชันเพื่อขอสตรีม 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);
}
จัดการเหตุการณ์สตรีม
การแสดงพ็อดไลฟ์สด
จากนั้นใช้ 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
จากนั้นใช้ Listener เหตุการณ์สำหรับเหตุการณ์วิดีโอที่สำคัญ ตัวอย่างนี้จะจัดการเหตุการณ์ 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);
}
จัดการข้อมูลเมตาของสตรีม
ในขั้นตอนนี้ คุณจะติดตั้งใช้งาน Listener เหตุการณ์สำหรับข้อมูลเมตาเพื่อแจ้ง SDK เมื่อเกิดเหตุการณ์โฆษณา การฟังเหตุการณ์ข้อมูลเมตาในสตรีมอาจแตกต่างกันไป โดยขึ้นอยู่กับรูปแบบสตรีม (HLS หรือ DASH), ประเภทสตรีม (สตรีมแบบสดหรือ VOD), ประเภทโปรแกรมเล่น และประเภทแบ็กเอนด์ DAI ที่ใช้ ดูข้อมูลเพิ่มเติมได้ที่คู่มือข้อมูลเมตาที่กำหนดเวลา
รูปแบบสตรีม HLS (สตรีมแบบสดและ VOD, เพลเยอร์ HLS.js)
หากคุณใช้โปรแกรมเล่น HLS.js ให้ฟังเหตุการณ์ FRAG_PARSING_METADATA ของ HLS.js เพื่อรับข้อมูลเมตา ID3 และส่งไปยัง SDK ด้วย StreamManager.processMetadata()
หากต้องการเล่นวิดีโอโดยอัตโนมัติหลังจากโหลดทุกอย่างและพร้อมแล้ว ให้ฟังเหตุการณ์ 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 คุณต้องใช้สตริงที่แตกต่างกันเพื่อฟังข้อมูลเมตา ID3 สำหรับสตรีมแบบสดหรือ VOD ดังนี้
- ไลฟ์สด:
'https://developer.apple.com/streaming/emsg-id3' - สตรีม VOD:
'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 ที่มีสตรีม 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);
}
}
จัดการกิจกรรมของผู้เล่น
เพิ่ม 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