我使用 IMA 在我的 Video.js 播放器中播放广告。我已经这样设置了几个月,直到最近一切都很好。问题是视频和广告同时播放。我在播放广告之前暂停视频,但它仍在播放。我只能在 Android 上的 Chrome 上复制此问题,但其他用户声称在不同的情况下遇到此问题。在生产中,这种情况经常发生,但在我的 CodePen 示例中很少发生。
我正在做的事情:我有两个用于 VAST 响应的端点 - 一个内部源(通常为空)和一个外部源,当内部源失败时我使用该外部源。我需要从我的域请求它们,因此我手动获取此端点并将响应放入 IMA。
事情是这样的:
我尝试手动检查广告是否正在播放并暂停视频(如果是),但这并不能解决问题并会中断 iOS 上的播放。
这里是示例:https://codepen.io/davlasq/pen/RwOpJJV
<html>
<head>
<link href="https://unpkg.com/[email protected]/dist/video-js.css" rel="stylesheet">
<link href="https://unpkg.com/[email protected]/dist/videojs.ima.css" rel="stylesheet">
<meta charset="utf-8">
<title>Video.js Starter Template</title>
</head>
<body>
<video id="my_video" class="video-js" controls width="300">
<source src="https://test-streams.mux.dev/x36xhzz/x36xhzz.m3u8" type="application/x-mpegURL">
</video>
<script src="//imasdk.googleapis.com/js/sdkloader/ima3.js"></script>
<script src="https://unpkg.com/[email protected]/dist/video.js"></script>
<script src="https://unpkg.com/[email protected]/dist/videojs.ads.js"></script>
<script src="https://unpkg.com/[email protected]/dist/videojs.ima.js"></script>
</body>
</html>
const Plugin = videojs.getPlugin("plugin");
// without initializing plugins in setTimeout they don't work for some reason
// so I created this wrapper
class Delay extends Plugin {
constructor(player, options) {
super(player, options);
setTimeout(() => {
Object.keys(options).forEach((pluginName) => {
if (pluginName === "ima" && typeof google === "undefined") {
return;
}
player[pluginName](options[pluginName]);
});
});
}
}
videojs.registerPlugin("delay", Delay);
class MyPlugin extends Plugin {
constructor(player, options) {
super(player, options);
this.options = options;
this.setAds();
}
setAds() {
if (
!this.options.ads?.vast ||
!this.player.ima ||
typeof google === "undefined" ||
!google?.ima
) {
return;
}
this.player.one("play", () => {
this.playAds(this.options.ads.vast, () => {
if (this.options.ads.vast_programmatic) {
this.playAds(this.options.ads.vast_programmatic);
}
});
});
}
async playAds(url, onError) {
this.player.pause();
const handleError = () => {
if (typeof onError === "function") {
onError();
} else {
this.player.play();
}
};
try {
const vast = await (await fetch(url, { mode: "cors" })).text();
if (!vast) {
handleError();
return;
}
this.player.ima.controller.settings.adsResponse = vast;
this.player.ima.controller.settings.adsManagerLoadedCallback = () => {
this.player.ima.addEventListener(
google.ima.AdEvent.Type.CONTENT_RESUME_REQUESTED,
() => {
this.player.play();
}
);
};
this.player.one("adserror", handleError);
this.player.ima.requestAds();
} catch (error) {
handleError();
}
}
}
videojs.registerPlugin("myplugin", MyPlugin);
const config = {
plugins: {
delay: {
ima: {},
myplugin: {
ads: {
vast: "https://some.failing.url/", // internal ads (often empty)
vast_programmatic:
"https://cdnzone.nuevodevel.com/pub/5.0/e-v-1/vmap_ad_sample.xml" // external ads (used when no internal ads)
}
}
}
}
};
document.addEventListener("DOMContentLoaded", () => {
const video = document.querySelector("video");
videojs(video, config);
});
IMA 的问题:https://github.com/googleads/videojs-ima/issues/1098 这是我的解决方法:
let tempVolume;
player.ima.addEventListener(google.ima.AdEvent.Type.STARTED, () => {
const adVideoEl = player.el().querySelector(".ima-ad-container video[src]");
tempVolume = player.volume();
player.volume(0);
adVideoEl.volume = tempVolume;
});
player.ima.addEventListener(google.ima.AdEvent.Type.CONTENT_RESUME_REQUESTED, () => {
player.currentTime(0);
player.volume(tempVolume);
player.src(player.src());
player.play();
}
);
所以基本上我在广告开始时将视频静音,然后在广告结束时取消静音并重新加载。