ovenplayer
Version:
OvenPlayer is Open-Source HTML5 Player. OvenPlayer supports WebRTC Signaling from OvenMediaEngine for Sub-Second Latency Streaming.
384 lines (322 loc) • 15.1 kB
JavaScript
/**
* Created by hoho on 08/04/2019.
*/
import AdsEventsListener from "api/ads/ima/Listener";
import {TEMP_VIDEO_URL} from "api/ads/utils";
import LA$ from "utils/likeA$.js";
import {errorTrigger} from "api/provider/utils";
import {
ERROR,
CONTENT_VOLUME,
STATE_LOADING,
INIT_ADS_ERROR,
STATE_AD_ERROR,
PLAYER_WARNING,
CONTENT_META,
WARN_MSG_MUTEDPLAY,
STATE_AD_LOADING,
PROVIDER_DASH,
UI_ICONS
} from "api/constants";
const Ad = function(elVideo, provider, playerConfig, adTagUrl, errorCallback){
//Todo : move createAdContainer to MediaManager
const AUTOPLAY_NOT_ALLOWED = "autoplayNotAllowed";
const ADMANGER_LOADING_ERROR = "admanagerLoadingTimeout";
let ADS_MANAGER_LOADED = "";
let AD_ERROR = "";
let that = {};
let adsManagerLoaded = false;
let adsErrorOccurred = false;
let spec = {
started: false, //player started
active : false, //on Ad
isVideoEnded : false
};
let OnManagerLoaded = null;
let OnAdError = null;
let adDisplayContainer = null;
let adsLoader = null;
let adsManager = null;
let listener = null;
let adsRequest = null;
let autoplayAllowed = false, autoplayRequiresMuted = false;
let browser = playerConfig.getBrowser();
let isMobile = browser.os === "Android" || browser.os === "iOS";
let adDisplayContainerInitialized = false;
// google.ima.settings.setAutoPlayAdBreaks(false);
//google.ima.settings.setVpaidMode(google.ima.ImaSdkSettings.VpaidMode.ENABLED);
//google.ima.settings.setVpaidMode(google.ima.ImaSdkSettings.VpaidMode.ENABLED);
//google.ima.settings.setDisableCustomPlaybackForIOS10Plus(true);
const sendWarningMessageForMutedPlay = function(){
provider.trigger(PLAYER_WARNING, {
message : WARN_MSG_MUTEDPLAY,
timer : 10 * 1000,
iconClass : UI_ICONS.volume_mute,
onClickCallback : function(){
provider.setMute(false);
}
});
};
OvenPlayerConsole.log("IMA : started ", "isMobile : ", isMobile, adTagUrl);
try{
ADS_MANAGER_LOADED = google.ima.AdsManagerLoadedEvent.Type.ADS_MANAGER_LOADED;
AD_ERROR = google.ima.AdErrorEvent.Type.AD_ERROR;
google.ima.settings.setLocale(playerConfig.getLanguage());
google.ima.settings.setDisableCustomPlaybackForIOS10Plus(true);
const createAdContainer = () => {
let adContainer = document.createElement('div');
adContainer.setAttribute('class', 'op-ads');
adContainer.setAttribute('id', 'op-ads');
playerConfig.getContainer().append(adContainer);
return adContainer;
};
OnAdError = function(adErrorEvent){
//note : adErrorEvent.getError().getInnerError().getErrorCode() === 1205 & adErrorEvent.getError().getVastErrorCode() === 400 is Browser User Interactive error.
//Do not triggering ERROR. becuase It just AD!
console.log(adErrorEvent.getError().getVastErrorCode(), adErrorEvent.getError().getMessage());
adsErrorOccurred = true;
let innerError = adErrorEvent.getError().getInnerError();
if(innerError){
try {
console.log(innerError.getErrorCode(), innerError.getMessage());
} catch (error) { }
}
/*if (adsManager) {
adsManager.destroy();
}*/
provider.trigger(STATE_AD_ERROR, {code : adErrorEvent.getError().getVastErrorCode() , message : adErrorEvent.getError().getMessage()});
spec.active = false;
spec.started = true;
provider.play();
/*if(innerError && innerError.getErrorCode() === 1205){
}else{
}*/
};
OnManagerLoaded = function(adsManagerLoadedEvent){
OvenPlayerConsole.log("IMA : OnManagerLoaded ");
let adsRenderingSettings = new google.ima.AdsRenderingSettings();
adsRenderingSettings.restoreCustomPlaybackStateOnAdBreakComplete = true;
//adsRenderingSettings.useStyledNonLinearAds = true;
if(adsManager){
OvenPlayerConsole.log("IMA : destroy adsManager----");
listener.destroy();
listener = null;
adsManager.destroy();
adsManager = null;
}
adsManager = adsManagerLoadedEvent.getAdsManager(elVideo, adsRenderingSettings);
listener = AdsEventsListener(adsManager, provider, spec, OnAdError);
OvenPlayerConsole.log("IMA : created admanager and listner ");
adsManagerLoaded = true;
};
let adConatinerElment = createAdContainer();
adDisplayContainer = new google.ima.AdDisplayContainer(adConatinerElment, elVideo);
adsLoader = new google.ima.AdsLoader(adDisplayContainer);
adsLoader.addEventListener(ADS_MANAGER_LOADED, OnManagerLoaded, false);
adsLoader.addEventListener(AD_ERROR, OnAdError, false);
OvenPlayerConsole.log("IMA : adDisplayContainer initialized");
provider.on(CONTENT_VOLUME, function(data) {
if(adsManager){
if(data.mute){
adsManager.setVolume(0);
}else{
adsManager.setVolume(data.volume/100);
}
}
}, that);
const setAutoPlayToAdsRequest = function (){
if(adsRequest){
OvenPlayerConsole.log("IMA : setADWillAutoPlay ", "autoplayAllowed",autoplayAllowed, "autoplayRequiresMuted",autoplayRequiresMuted);
adsRequest.setAdWillAutoPlay(autoplayAllowed);
adsRequest.setAdWillPlayMuted(autoplayRequiresMuted);
if(autoplayRequiresMuted){
sendWarningMessageForMutedPlay();
}
}
};
const initRequest = function(){
adsManagerLoaded = false;
OvenPlayerConsole.log("IMA : initRequest() AutoPlay Support : ", "autoplayAllowed",autoplayAllowed, "autoplayRequiresMuted",autoplayRequiresMuted);
/*if(adsRequest){
return false;
}*/
adsRequest = new google.ima.AdsRequest();
adsRequest.forceNonLinearFullSlot = false;
/*if(playerConfig.getBrowser().browser === "Safari" && playerConfig.getBrowser().os === "iOS" ){
autoplayAllowed = false;
autoplayRequiresMuted = false;
}*/
setAutoPlayToAdsRequest();
adsRequest.adTagUrl = adTagUrl;
adsLoader.requestAds(adsRequest);
OvenPlayerConsole.log("IMA : requestAds Complete");
//two way what ad starts.
//adsLoader.requestAds(adsRequest); or adsManager.start();
//what? why?? wth??
};
const checkAutoplaySupport = function () {
OvenPlayerConsole.log("IMA : checkAutoplaySupport() ");
let temporarySupportCheckVideo = document.createElement('video');
temporarySupportCheckVideo.setAttribute('playsinline', 'true');
temporarySupportCheckVideo.src = TEMP_VIDEO_URL;
temporarySupportCheckVideo.load();
//Dash has already loaded when triggered provider.play() always.
if(isMobile && provider.getName() !== PROVIDER_DASH ){
//Main video sets user gesture when temporarySupportCheckVideo triggered checking.
elVideo.load();
}
/* Different browser-specific ways to delivery UI to other elements. My Guess. 2019-06-19
* (temporarySupportCheckVideo's User Interaction delivery to elVideo.)
* Mobile Chrome WebView :
* You have to run elVideo.load() when temporarySupportCheckVideo issues within 5 seconds of user interaction.
*
* Mobile ios safari :
* You have to run elVideo.load() before temporarySupportCheckVideo run play().
* */
const clearAndReport = function(_autoplayAllowed, _autoplayRequiresMuted){
autoplayAllowed = _autoplayAllowed;
autoplayRequiresMuted = _autoplayRequiresMuted;
temporarySupportCheckVideo.pause();
temporarySupportCheckVideo.remove();
setAutoPlayToAdsRequest();
};
return new Promise(function(resolve, reject){
if(!temporarySupportCheckVideo.play){
//I can't remember this case...
OvenPlayerConsole.log("IMA : !temporarySupportCheckVideo.play");
clearAndReport(true, false);
resolve();
}else{
let playPromise = temporarySupportCheckVideo.play();
if (playPromise !== undefined) {
playPromise.then(function(){
OvenPlayerConsole.log("IMA : auto play allowed.");
// If we make it here, unmuted autoplay works.
clearAndReport(true, false);
resolve();
}).catch(function(error){
OvenPlayerConsole.log("IMA : auto play failed", error.message);
clearAndReport(false, false);
resolve();
//Disable Muted Play
/*temporarySupportCheckVideo.muted = true;
temporarySupportCheckVideo.volume = 0;
playPromise = temporarySupportCheckVideo.play();
playPromise.then(function () {
// If we make it here, muted autoplay works but unmuted autoplay does not.
OvenPlayerConsole.log("ADS : muted auto play success.");
provider.setMute(true);
clearAndReport(true, true);
resolve();
}).catch(function (error) {
OvenPlayerConsole.log("ADS : muted auto play failed", error.message);
clearAndReport(false, false);
resolve();
});*/
});
}else{
OvenPlayerConsole.log("IMA : promise not support");
//Maybe this is IE11....
clearAndReport(true, false);
resolve();
}
}
});
}
that.isActive = () => {
return spec.active;
};
that.started = () => {
return spec.started;
};
that.play = () => {
if(spec.started){
return new Promise(function (resolve, reject) {
try{
adsManager.resume();
resolve();
} catch (error){
reject(error);
}
});
}else{
adDisplayContainer.initialize();
return new Promise(function (resolve, reject) {
let retryCount = 0;
const checkAdsManagerIsReady = function(){
retryCount ++;
if(adsManagerLoaded){
OvenPlayerConsole.log("IMA : ad start!");
adsManager.init("100%", "100%", google.ima.ViewMode.NORMAL);
adsManager.start();
spec.started = true;
resolve();
}else{
if(adsErrorOccurred){
reject(new Error(ADMANGER_LOADING_ERROR));
}else{
if(retryCount < 150){
setTimeout(checkAdsManagerIsReady, 100);
}else{
reject(new Error(ADMANGER_LOADING_ERROR));
}
}
}
};
checkAutoplaySupport().then(function () {
if( (playerConfig.isAutoStart() && !autoplayAllowed) ){
OvenPlayerConsole.log("IMA : autoplayAllowed : false");
spec.started = false;
reject(new Error(AUTOPLAY_NOT_ALLOWED));
}else{
initRequest();
checkAdsManagerIsReady();
}
});
});
}
};
that.pause = () => {
adsManager.pause();
};
that.videoEndedCallback = (completeContentCallback) => {
//listener.isLinearAd : get current ad's status whether linear ad or not.
if(listener && (listener.isAllAdComplete() || !listener.isLinearAd())){
completeContentCallback();
}else if(adsErrorOccurred){
completeContentCallback();
}else{
//If you need play the post-roll, you have to call to adsLoader when contents was completed.
spec.isVideoEnded = true;
adsLoader.contentComplete();
}
};
that.destroy = () => {
if(adsLoader){
adsLoader.removeEventListener(ADS_MANAGER_LOADED, OnManagerLoaded);
adsLoader.removeEventListener(AD_ERROR, OnAdError);
}
if(adsManager){
adsManager.destroy();
}
if(adDisplayContainer){
adDisplayContainer.destroy();
}
if(listener){
listener.destroy();
}
let $ads = LA$(playerConfig.getContainer()).find(".op-ads");
if($ads){
$ads.remove();
}
provider.off(CONTENT_VOLUME, null, that);
};
return that;
}catch (error){
//let tempError = ERRORS[INIT_ADS_ERROR];
//tempError.error = error;
//errorCallback(tempError);
return null;
}
};
export default Ad;