使用Shaka Player与IMA Ads SDK切换播放不同广告的问题
问题描述
搭建了一个包含两个按钮和一个<video>元素的页面,使用Shaka Player播放自适应DASH文件,结合Google IMA Ads SDK实现广告与视频的联动播放。预期效果为:点击按钮1时先播放前置广告1,随后播放视频1;点击按钮2时先播放前置广告2,随后播放视频2。但实际测试发现,点击任意按钮后广告仅能播放一次,切换按钮后广告不再播放。
现有代码
HTML代码
<html> <head> <meta content="text/html; charset=utf-8" http-equiv="Content-type"/> <title id="sample_app_page_title">Ad Ping</title> <!--for UI builds: --> <script src="https://cdnjs.cloudflare.com/ajax/libs/shaka-player/4.3.0/shaka-player.ui.min.js"></script> <link href="https://cdnjs.cloudflare.com/ajax/libs/shaka-player/4.3.0/controls.min.css" rel="stylesheet"> <!-- IMA HTML5 SDK (for serving Client Side ads): --> <script src="https://imasdk.googleapis.com/js/sdkloader/ima3.js" type="text/javascript"></script> </head> <body> <button onclick="playAd1()">Play Video with Ad1</button> <button onclick="playAd2()">Play Video with Ad2</button> <div> <div data-shaka-player-cast-receiver-id="8D8C71A7" data-shaka-player-container> <video data-shaka-player controls autoplay id="video" style="width:400px; height:200px" /> </div> </div> </body> </html>
JavaScript代码
const adUrl1 = "https://pubads.g.doubleclick.net/gampad/ads?iu=/21775744923/external/vmap_ad_samples&sz=640x480&cust_params=sample_ar%3Dpreonly&ciu_szs=300x250%2C728x90&gdfp_req=1&ad_rule=1&output=vmap&unviewed_position_start=1&env=vp&impl=s&correlator="; const adUrl2 = "https://pubads.g.doubleclick.net/gampad/ads?iu=/21775744923/external/vmap_ad_samples&sz=640x480&cust_params=sample_ar%3Dpremidpost&ciu_szs=300x250&gdfp_req=1&ad_rule=1&output=vmap&unviewed_position_start=1&env=vp&impl=s&cmsid=496&vid=short_onecue&correlator="; const manifestUrl1 = "https://storage.googleapis.com/wvmedia/clear/h264/tears/tears.mpd"; const manifestUrl2 = "https://storage.googleapis.com/shaka-demo-assets/angel-one/dash.mpd"; let player, ui, video, controls, adManager; async function initApp() { shaka.polyfill.installAll(); if (shaka.Player.isBrowserSupported()) { // When using the UI, the player is made automatically by the UI object. video = document.getElementById('video'); ui = video['ui']; controls = ui.getControls(); player = controls.getPlayer(); // Listen for error events. player.addEventListener('error', onPlayerErrorEvent); // controls.addEventListener('error', onUIErrorEvent); adManager = player.getAdManager(); // Attach player and ui to the window to make it easy to access in the JS console. window.player = player; window.ui = ui; window.video = video; window.controls = controls; window.adManager = adManager; } else { console.error("Browser not supported"); } } function initializeAdManager() { const container = ui.getControls().getClientSideAdContainer(); adManager.initClientSide(container, video); } function onError(error) { // Log the error. console.error('Error code', error.code, 'object', error); } async function playAd1() { console.log('playing Video with ads 1'); initializeAdManager(); fetchAd(adUrl1); await playVideo(manifestUrl1); } async function playAd2() { console.log('playing video with ads 2'); initializeAdManager(); fetchAd(adUrl2); await playVideo(manifestUrl2); } async function playVideo(url) { try { await player.load(url); } catch (e) { onError(e); } } function fetchAd(url) { const adRequest = new google.ima.AdsRequest(); adRequest.adTagUrl = url; adManager.requestClientSideAds(adRequest); } function onPlayerErrorEvent(errorEvent) { // Extract the shaka.util.Error object from the event. onPlayerError(errorEvent.detail); } function onPlayerError(error) { // Handle player error console.error('Error code', error.code, 'object', error); } function onUIErrorEvent(errorEvent) { // Extract the shaka.util.Error object from the event. onPlayerError(errorEvent.detail); } document.addEventListener('shaka-ui-loaded', initApp);
解决方案
广告仅能播放一次的核心原因有两个:
- 重复初始化AdManager:每次点击按钮都调用
initializeAdManager(),但Shaka的AdManager重复初始化会导致内部状态混乱。 - 未同步广告与视频的生命周期:当前直接在请求广告后立即加载视频,会打断广告流程;且切换时未清理旧广告状态,新广告请求无法正确绑定到新流程。
修改步骤:
- 全局初始化AdManager:仅在
initApp()中初始化一次AdManager,避免重复初始化。 - 切换时清理广告状态:每次发起新广告请求前,调用
adManager.destroyClientSide()清理旧实例,再重新初始化。 - 等待广告结束后加载视频:监听
adBreakEnded事件,确保广告播放完成后再加载主视频,避免流程冲突。
修改后的关键代码:
调整initApp()提前初始化AdManager
async function initApp() { shaka.polyfill.installAll(); if (shaka.Player.isBrowserSupported()) { video = document.getElementById('video'); ui = video['ui']; controls = ui.getControls(); player = controls.getPlayer(); player.addEventListener('error', onPlayerErrorEvent); adManager = player.getAdManager(); // 仅初始化一次AdManager const container = ui.getControls().getClientSideAdContainer(); adManager.initClientSide(container, video); window.player = player; window.ui = ui; window.video = video; window.controls = controls; window.adManager = adManager; } else { console.error("Browser not supported"); } }
修改播放函数,同步广告与视频流程
async function playAd1() { console.log('playing Video with ads 1'); // 清理旧广告状态 adManager.destroyClientSide(); // 重新初始化AdManager const container = ui.getControls().getClientSideAdContainer(); adManager.initClientSide(container, video); // 等待广告播放完成 await new Promise((resolve) => { const onAdBreakEnded = () => { adManager.removeEventListener('adBreakEnded', onAdBreakEnded); resolve(); }; adManager.addEventListener('adBreakEnded', onAdBreakEnded); fetchAd(adUrl1); }); await playVideo(manifestUrl1); } async function playAd2() { console.log('playing video with ads 2'); // 清理旧广告状态 adManager.destroyClientSide(); // 重新初始化AdManager const container = ui.getControls().getClientSideAdContainer(); adManager.initClientSide(container, video); // 等待广告播放完成 await new Promise((resolve) => { const onAdBreakEnded = () => { adManager.removeEventListener('adBreakEnded', onAdBreakEnded); resolve(); }; adManager.addEventListener('adBreakEnded', onAdBreakEnded); fetchAd(adUrl2); }); await playVideo(manifestUrl2); }
移除原initializeAdManager()函数
该函数的逻辑已整合到全局初始化和播放函数中,无需保留。
内容的提问来源于stack exchange,提问作者chochim
相关产品推荐
相关产品推荐

