Na jaké televizní vysílání ještě platí zákony?

23. 3. 2007
Doba čtení: 6 minut

Sdílet

Autor: 118483
Desetimilionová pokuta. Taková hrozba je připravena na každého, kdo se pokusí neoprávněně provozovat televizní vysílání. Ale co je ještě televize, a kde už začíná internet? Pro první svět platí regulace podle mediálního zákona, zatímco druhý si užívá nevázané svobody. Hranici mezi nimi prověří správní řízení Rady pro rozhlasové a televizní vysílání (RRTV) s frýdeckou-místeckou firmou Mattes AD, poskytovatelem televize přes internetový protokol (IPTV).

Zemská, satelitní ani kabelová televize nenechávají diváky ani české zákony na pochybách, že jsou skutečně televizí a platí pro ně pravidla daná mediální legislativou. U programů šířených přes internetový protokol už ale není situace tak jednoznačná. Za rozhlasové a televizní vysílání se nepovažuje vysílání prostřednictvím dálkového přístupu (Internetu), uvádí § 2, odstavec 2 bod e) zákona o provozování rozhlasového a televizního vysílání 231/2001 Sb. [PDF, 286 kB].

Ve stejném zákoně je ale v § 26 pasáž o registraci převzatého vysílání: Registrace provozovatele převzatého vysílání prostřednictvím sítě elektronických komunikací opravňuje provozovatele k provozování převzatého vysílání prostřednictvím příslušné sítě elektronických komunikací s výjimkou vysílání šířeného prostřednictvím zemských vysílacích rádiových zařízení.

Pokud si obě ustanovení dáme dohromady, dojdeme k zajímavému spojení. Registrovat se dá cokoli kromě zemského vysílání. A internetové vysílání není vysíláním. Co z toho plyne pro provozovatele IPTV? Těžko říct. Na jednu stranu má jejich způsob televizní distribuce velmi blízko k internetu, na stranu druhou je to privátní IP síť, kterou není možné s internetem ztotožňovat. Každopádně kdokoli se rozhodne pro registraci, musí se přihlásit k nějaké síti elektronických komunikací, přes niž bude svoji nabídku zprostředkovávat.

802.cz

Selský rozum říká, že když někdo provozuje vysílání IPTV, měl by se registrovat jako provozovatel převzatého vysílání přes internetový protokol. Rada pro rozhlasové a televizní vysílání se ale rozhodla pro jiný přístup a poradila všem zájemcům o IPTV, aby se registrovali jako kabeloví operátoři. Velcí hráči jako Telefónica O2 nebo Czech On Line (Volný) na nápad přistoupili a z doporučení se stal úzus. Ale firma Mattes AD provozující IPTV pod značkou 802.tv ve vlastní optické síti ve Frýdku-Místku, Frýdlantu nad Ostravicí a Frenštátě pod Radhoštěm se rozhodla jako jediná zvyklosti odporovat.

V jaké fázi je správní řízení a proč k němu došlo?

Mediální rada nenechala odbojný přístup frýdecko-místecké společnosti být a na konci února s ní zahájila správní řízení. Na jeho výsledek si ale budeme muset ještě počkat. Správní řízení běží. Zpracováváme analýzu a na jejím základě firmu Mattes AD vyzveme k jednání. Předpokládám, že to bude zhruba za měsíc, řekl serveru DigiZone.cz předseda RRTV Václav Žák a dodal: Analýza má prokázat, zda Mattes AD porušil zákon nevědomky, nebo se ho cíleně snažil obejít.

Václav Žák

Žák nemá pro slezský přístup k provozování IPTV příliš pochopení: My jsme s nimi byli v kontaktu někdy před rokem a to jsme se dozvěděli, že pracují na internetové aplikaci. Pak jsme se ale na vašem serveru dočetli, a za to vám děkuji, že provozují IPTV. Předseda RRTV si myslí, že porušení mediální legislativy je v tomto případě velmi pravděpodobné. Nemůžou si myslet, že ve Frýdku-Místku zákony neplatí, uvedl pro server DigiZone.cz na adresu firmy ve správním řízení.

Jednatel společnosti Mattes AD Petr Pobořil má na kauzu jiný pohled. Radě jsme během dvou let posílali už dvě přihlášky na službu 802.cz. Při jejich formulaci jsem vycházeli z principů IPTV. Dotyčný úředník na RRTV si s něčím takovým ale neuměl poradit, žaluje na mediální radu Pobořil. Podle něj je mezi vysíláním přes kabel a prostřednictvím internetového protokolu zásadní rozdíl. Registrace prvního probíhá na základě katastrálních území, u druhého jsou klíčové routery a switche.

Telefónica O2, Volný a další operátoři na IP povahu svého převzatého vysílání z hlediska zákona rezignovali a svoje registrace provedli na základě území, ve kterých je jejich služba dostupná. Firma Petra Pobořila by mohla udělat totéž. Ačkoli se její jednatel ohání termíny z branže počítačových sítí, faktem zůstává, že diváci 802.tv musí být připojeni k optické infrastruktuře Mattesu AD. A optická vlákna společnosti vedou jen ve třech slezských městech. Pro ně by kabelová registrace nebyla problém. Ve skutečnosti ale jde spíš o princip a otázku, co všechno se dá regulovat.

Nabídka 802.tv s problematickým StounLive

Služba 802.tv nabízí dvě možnosti, jak sledovat televizi. První je televizor s připojeným set-top-boxem (který si zákazník musí od firmy koupit za 4900 korun), druhou je počítačový program VLC media player. Diváci mají na výběr ze tří balíčku. V testovací variantě jsou stanice ČT 1 a ČT 2, které se zájemci mohou vyzkoušet přes internet zdarma. Nejdříve jsem si myslel, že se takhle Mattes AD dostává do dalších potíží, když po celosvětové sítí šíří programy, které mají práva omezená na Českou republiku a nikde na internetu nevysílání. Praktický test mi ale ukázal, že si programy České televize naladí jen lidé připojení na internet v síti 802.cz. A ta nikam do světa nesahá.

Dvě placené nabídky se liší programovou nabídkou a měsíčním paušálem. 802.tv základ obsahuje české (ČT 1, ČT 2, ČT 24, ČT 4 Sport, Nova, Prima, TV Noe, Meteo TV) a slovenské stanice, Mattes AD si za něj účtuje 106 korun měsíčně. Nabídka 802.tv standard rozšiřuje programovou skladbu o CS Film, 24cz, Galaxii sport, Sport 1, Óčko, Minimax/A+, Reality TV, Romantica, Discovery, Animal Planet, TV Paprika, TV Deko a StounLive. Měsíční paušál je v tomto případě 475 korun.

Poslední ze jmenovaných programů je živým vysíláním z místního klubu Stoun, ve kterém se střídá obraz osmi webových kamer. Právě StounLive je dalším možným jablkem sváru mezi mediální radou a firmou Mattes AD. Internetové stránky služby 802.tv ho uvádějí jako regulérní součást programové nabídky, „stanice“ ale není ani licencovaná, ani nemá registraci. Ačkoli se jedná o sled vysílání z webových kamer, kterých je plný internet, mohl by se StounLive dostat do problémů. Jeho vysílání se totiž odehrává na platformě, která internetem není.

Chce RRTV zabránit šíření pornografie?

IPTV je mnohotvará záležitost. Václav Žák uvedl současnou regulaci vysílání na příkladu Telefóniky O2: Na IPTV pohlížíme jako vysílání přes kabel, to už jsme si vyjasnili s ‚Ó dvojkou‘. (Její) IPTV má tři složky. Je to video on demand a televizní archiv, které se za vysílání podle zákona nepovažují, a pak je to přenos televizních programů k divákovi, což už vysílání je.

Předseda RRTV vidí současnost vysílání jako klíč k tomu, co je a není televizí. V rukou má silný argument evropského soudního dvora. Ten ve svém rozsudku proti firmě Mediakabel [PDF, 276 kB] ze 2. června 2005 zpřesňuje definici vysílání. Služba spadá pod pojem ‚televizní vysílání‘…, pokud sestává z prvotního vysílání televizních programů určených veřejnosti, tedy neomezenému počtu možných televizních diváků, u nichž je současně přenášen tentýž obraz. Technika přenosu obrazu není při tomto posouzení určujícím prvkem. Je samozřejmě otázkou, nakolik je přenos z hudebního klubu televizním programem. Ale když se do StounLive střihově skládají záběry z několika kamer, má na takovou kvalifikaci velkou šanci.

Možná se ptáte, proč se kolem jednoho frýdecko-místeckého provozovatele dělá takový povyk. Hrozba až desetimilionové pokuty, jejíž výši RRTV navíc ještě nestanovila, není hlavním důvodem. Nechceme pokutami nahánět peníze pro státní rozpočet. Jde nám o to, aby na trhu panovaly stejné podmínky pro každého, řekl DigiZone.cz Václav Žák.

CIF25_SE_terc

Pokud by v Česku existovali poskytovatelé televize, kteří by unikli registrační povinnosti, byla by na ně mediální rada krátká. To v praxi znamená, že na jejich stanice by se například nevztahovaly žádné povinnosti z paragrafů 31 a 32 zákona o provozování rozhlasového a televizního vysílání. Zákon kupříkladu přikazuje nezařazovat v době od 06.00 hodin do 22.00 hodin pořady a upoutávky, které by mohly ohrozit fyzický, psychický nebo mravní vývoj dětí a mladistvých. Ve vysílání neregulovaného operátora by nic takového platit nemuselo.

Když jsem se Václava Žáka ptal, čemu chce jeho rada zabránit, uvedl mi příklad. Podívejte se na FreeTV.cz, možná budete překvapený, co tam vysílají. Pornografie dostupná i v bezplatné verzi (kde je ale omezena na shluk černo-oranžových kostek) je tady na programu 24 hodin denně. Pokud by se ukázalo, že se Mattes AD registrovat nemusí a jeho StounLive je mimo zákon, teoreticky mu nic nebrání zařadit do programové nabídky i stanici á la FreeTV. Ne, že by měl jednatel společnosti Petr Pobořil něco takového v úmyslu. Uvidíme, co ukáže připravovaná analýza od RRTV a jak ve věci rozhodnou právníci.

Komu ve sporu RRTV a firmy Mattes AD fandíte?

Autor článku

Autor pracoval do ledna 2011 ve zpravodajství TV Z1. V redakci DigiZone.cz působil od startu v říjnu 2005 do dubna 2008 jako redaktor, pak i zástupce šéfredaktora.
'; document.getElementById('preroll-iframe').onload = function () { setupIframe(); } prerollContainer = document.getElementsByClassName('preroll-container-iframe')[0]; } function setupIframe() { prerollDocument = document.getElementById('preroll-iframe').contentWindow.document; let el = prerollDocument.createElement('style'); prerollDocument.head.appendChild(el); el.innerText = "#adContainer>div:nth-of-type(1),#adContainer>div:nth-of-type(1) > iframe { width: 99% !important;height: 99% !important;max-width: 100%;}#videoContent,body{ width:100vw;height:100vh}body{ font-family:'Helvetica Neue',Arial,sans-serif}#videoContent{ overflow:hidden;background:#000}#adMuteBtn{ width:35px;height:35px;border:0;background:0 0;display:none;position:absolute;fill:rgba(230,230,230,1);bottom:20px;right:25px}"; videoContent = prerollDocument.getElementById('contentElement'); videoContent.style.display = 'none'; videoContent.volume = 1; videoContent.muted = false; const playPromise = videoContent.play(); if (playPromise !== undefined) { playPromise.then(function () { console.log('PREROLL sound allowed'); // setUpIMA(true); videoContent.volume = 1; videoContent.muted = false; setUpIMA(); }).catch(function () { console.log('PREROLL sound forbidden'); videoContent.volume = 0; videoContent.muted = true; setUpIMA(); }); } } function setupDimensions() { prerollWidth = Math.min(iinfoPrerollPosition.offsetWidth, 480); prerollHeight = Math.min(iinfoPrerollPosition.offsetHeight, 320); } function setUpIMA() { google.ima.settings.setDisableCustomPlaybackForIOS10Plus(true); google.ima.settings.setLocale('cs'); google.ima.settings.setNumRedirects(10); // Create the ad display container. createAdDisplayContainer(); // Create ads loader. adsLoader = new google.ima.AdsLoader(adDisplayContainer); // Listen and respond to ads loaded and error events. adsLoader.addEventListener( google.ima.AdsManagerLoadedEvent.Type.ADS_MANAGER_LOADED, onAdsManagerLoaded, false); adsLoader.addEventListener( google.ima.AdErrorEvent.Type.AD_ERROR, onAdError, false); // An event listener to tell the SDK that our content video // is completed so the SDK can play any post-roll ads. const contentEndedListener = function () { adsLoader.contentComplete(); }; videoContent.onended = contentEndedListener; // Request video ads. const adsRequest = new google.ima.AdsRequest(); adsRequest.adTagUrl = iinfoVastUrls[iinfoVastUrlIndex]; console.log('Preroll advert: ' + iinfoVastUrls[iinfoVastUrlIndex]); videoContent.muted = false; videoContent.volume = 1; // Specify the linear and nonlinear slot sizes. This helps the SDK to // select the correct creative if multiple are returned. // adsRequest.linearAdSlotWidth = prerollWidth; // adsRequest.linearAdSlotHeight = prerollHeight; adsRequest.nonLinearAdSlotWidth = 0; adsRequest.nonLinearAdSlotHeight = 0; adsLoader.requestAds(adsRequest); } function createAdDisplayContainer() { // We assume the adContainer is the DOM id of the element that will house // the ads. prerollDocument.getElementById('videoContent').style.display = 'none'; adDisplayContainer = new google.ima.AdDisplayContainer( prerollDocument.getElementById('adContainer'), videoContent); } function unmutePrerollAdvert() { adVolume = !adVolume; if (adVolume) { adsManager.setVolume(0.3); prerollDocument.getElementById('adMuteBtn').innerHTML = ''; } else { adsManager.setVolume(0); prerollDocument.getElementById('adMuteBtn').innerHTML = ''; } } function onAdsManagerLoaded(adsManagerLoadedEvent) { // Get the ads manager. const adsRenderingSettings = new google.ima.AdsRenderingSettings(); adsRenderingSettings.restoreCustomPlaybackStateOnAdBreakComplete = true; adsRenderingSettings.loadVideoTimeout = 12000; // videoContent should be set to the content video element. adsManager = adsManagerLoadedEvent.getAdsManager(videoContent, adsRenderingSettings); // Add listeners to the required events. adsManager.addEventListener(google.ima.AdErrorEvent.Type.AD_ERROR, onAdError); adsManager.addEventListener( google.ima.AdEvent.Type.CONTENT_PAUSE_REQUESTED, onContentPauseRequested); adsManager.addEventListener( google.ima.AdEvent.Type.CONTENT_RESUME_REQUESTED, onContentResumeRequested); adsManager.addEventListener( google.ima.AdEvent.Type.ALL_ADS_COMPLETED, onAdEvent); // Listen to any additional events, if necessary. adsManager.addEventListener(google.ima.AdEvent.Type.LOADED, onAdEvent); adsManager.addEventListener(google.ima.AdEvent.Type.STARTED, onAdEvent); adsManager.addEventListener(google.ima.AdEvent.Type.COMPLETE, onAdEvent); playAds(); } function playAds() { // Initialize the container. Must be done through a user action on mobile // devices. videoContent.load(); adDisplayContainer.initialize(); // setupDimensions(); try { // Initialize the ads manager. Ad rules playlist will start at this time. adsManager.init(1920, 1080, google.ima.ViewMode.NORMAL); // Call play to start showing the ad. Single video and overlay ads will // start at this time; the call will be ignored for ad rules. adsManager.start(); // window.addEventListener('resize', function (event) { // if (adsManager) { // setupDimensions(); // adsManager.resize(prerollWidth, prerollHeight, google.ima.ViewMode.NORMAL); // } // }); } catch (adError) { // An error may be thrown if there was a problem with the VAST response. // videoContent.play(); } } function onAdEvent(adEvent) { const ad = adEvent.getAd(); console.log('Preroll event: ' + adEvent.type); switch (adEvent.type) { case google.ima.AdEvent.Type.LOADED: if (!ad.isLinear()) { videoContent.play(); } prerollDocument.getElementById('adContainer').style.width = '100%'; prerollDocument.getElementById('adContainer').style.maxWidth = '640px'; prerollDocument.getElementById('adContainer').style.height = '360px'; break; case google.ima.AdEvent.Type.STARTED: window.addEventListener('scroll', onActiveView); if (ad.isLinear()) { intervalTimer = setInterval( function () { // Example: const remainingTime = adsManager.getRemainingTime(); // adsManager.pause(); }, 300); // every 300ms } prerollDocument.getElementById('adMuteBtn').style.display = 'block'; break; case google.ima.AdEvent.Type.ALL_ADS_COMPLETED: if (ad.isLinear()) { clearInterval(intervalTimer); } if (prerollLastError === 303) { playYtVideo(); } break; case google.ima.AdEvent.Type.COMPLETE: if (ad.isLinear()) { clearInterval(intervalTimer); } playYtVideo(); break; } } function onAdError(adErrorEvent) { console.log(adErrorEvent.getError()); prerollLastError = adErrorEvent.getError().getErrorCode(); if (!loadNext()) { playYtVideo(); } } function loadNext() { iinfoVastUrlIndex++; if (iinfoVastUrlIndex < iinfoVastUrls.length) { iinfoPrerollPosition.remove(); playPrerollAd(); } else { return false; } adVolume = 1; return true; } function onContentPauseRequested() { videoContent.pause(); } function onContentResumeRequested() { videoContent.play(); } function onActiveView() { if (prerollContainer) { const containerOffset = prerollContainer.getBoundingClientRect(); const windowHeight = window.innerHeight; if (containerOffset.top < windowHeight/1 && containerOffset.bottom > 0.0) { if (prerollPaused) { adsManager.resume(); prerollPaused = false; } return true; } else { if (!prerollPaused) { adsManager.pause(); prerollPaused = true; } } } return false; } function playYtVideo() { iinfoPrerollPosition.remove(); youtubeIframe.style.display = 'block'; youtubeIframe.src += '&autoplay=1&mute=1'; } }
Upozorníme vás na články, které by vám neměly uniknout (maximálně 2x týdně).
'; document.getElementById('outstream-iframe').onload = function () { setupIframe(); } replayScreen = document.getElementById('iinfoOutstreamReplay'); iinfoOutstreamPosition = document.getElementById('iinfoOutstreamPosition'); outstreamContainer = document.getElementsByClassName('outstream-container')[0]; setupReplayScreen(); } function setupIframe() { outstreamDocument = document.getElementById('outstream-iframe').contentWindow.document; let el = outstreamDocument.createElement('style'); outstreamDocument.head.appendChild(el); el.innerText = "#adContainer>div:nth-of-type(1),#adContainer>div:nth-of-type(1) > iframe { width: 99% !important;height: 99% !important;max-width: 100%;}#videoContent,body{ width:100vw;height:100vh}body{ font-family:'Helvetica Neue',Arial,sans-serif}#videoContent{ overflow:hidden;background:#000}#adMuteBtn{ width:35px;height:35px;border:0;background:0 0;display:none;position:absolute;fill:rgba(230,230,230,1);bottom:-5px;right:25px}"; videoContent = outstreamDocument.getElementById('contentElement'); videoContent.style.display = 'none'; videoContent.volume = 1; videoContent.muted = false; if ( location.href.indexOf('rejstriky.finance.cz') !== -1 || location.href.indexOf('finance-rejstrik') !== -1 || location.href.indexOf('firmy.euro.cz') !== -1 || location.href.indexOf('euro-rejstrik') !== -1 || location.href.indexOf('/rejstrik/') !== -1 || location.href.indexOf('/rejstrik-firem/') !== -1) { outstreamDirectPlayed = true; soundAllowed = true; iinfoVastUrlIndex = 0; } if (!outstreamDirectPlayed) { console.log('OUTSTREAM direct'); setUpIMA(true); } else { if (soundAllowed) { const playPromise = videoContent.play(); if (playPromise !== undefined) { playPromise.then(function () { console.log('OUTSTREAM sound allowed'); setUpIMA(false); }).catch(function () { console.log('OUTSTREAM sound forbidden'); renderBanner(); }); } } else { renderBanner(); } } } function getWrapper() { let articleWrapper = document.querySelector('.rs-outstream-placeholder'); // Outstream Placeholder from RedSys manipulation if (articleWrapper && articleWrapper.style.display !== 'block') { articleWrapper.innerHTML = ""; articleWrapper.style.display = 'block'; } // Don't render OutStream on homepages if (articleWrapper === null) { if (document.querySelector('body.p-index')) { return null; } } if (articleWrapper === null) { articleWrapper = document.getElementById('iinfo-outstream'); } if (articleWrapper === null) { articleWrapper = document.querySelector('.layout-main__content .detail__article p:nth-of-type(6)'); } if (articleWrapper === null) { // Euro, Autobible, Zdravi articleWrapper = document.querySelector('.o-article .o-article__text p:nth-of-type(6)'); } if (articleWrapper === null) { articleWrapper = document.getElementById('sidebar'); } if (!articleWrapper) { console.error("Outstream wrapper of article was not found."); } return articleWrapper; } function setupDimensions() { outstreamWidth = Math.min(iinfoOutstreamPosition.offsetWidth, 480); outstreamHeight = Math.min(iinfoOutstreamPosition.offsetHeight, 320); } /** * Sets up IMA ad display container, ads loader, and makes an ad request. */ function setUpIMA(direct) { google.ima.settings.setDisableCustomPlaybackForIOS10Plus(true); google.ima.settings.setLocale('cs'); google.ima.settings.setNumRedirects(10); // Create the ad display container. createAdDisplayContainer(); // Create ads loader. adsLoader = new google.ima.AdsLoader(adDisplayContainer); // Listen and respond to ads loaded and error events. adsLoader.addEventListener( google.ima.AdsManagerLoadedEvent.Type.ADS_MANAGER_LOADED, onAdsManagerLoaded, false); adsLoader.addEventListener( google.ima.AdErrorEvent.Type.AD_ERROR, onAdError, false); // An event listener to tell the SDK that our content video // is completed so the SDK can play any post-roll ads. const contentEndedListener = function () { adsLoader.contentComplete(); }; videoContent.onended = contentEndedListener; // Request video ads. const adsRequest = new google.ima.AdsRequest(); if (direct) { adsRequest.adTagUrl = directVast; console.log('Outstream DIRECT CAMPAING advert: ' + directVast); videoContent.muted = true; videoContent.volume = 0; outstreamDirectPlayed = true; } else { adsRequest.adTagUrl = iinfoVastUrls[iinfoVastUrlIndex]; console.log('Outstream advert: ' + iinfoVastUrls[iinfoVastUrlIndex]); videoContent.muted = false; videoContent.volume = 1; } // Specify the linear and nonlinear slot sizes. This helps the SDK to // select the correct creative if multiple are returned. // adsRequest.linearAdSlotWidth = outstreamWidth; // adsRequest.linearAdSlotHeight = outstreamHeight; adsRequest.nonLinearAdSlotWidth = 0; adsRequest.nonLinearAdSlotHeight = 0; adsLoader.requestAds(adsRequest); } function setupReplayScreen() { replayScreen.addEventListener('click', function () { iinfoOutstreamPosition.remove(); iinfoVastUrlIndex = 0; outstreamInit(); }); } /** * Sets the 'adContainer' div as the IMA ad display container. */ function createAdDisplayContainer() { // We assume the adContainer is the DOM id of the element that will house // the ads. outstreamDocument.getElementById('videoContent').style.display = 'none'; adDisplayContainer = new google.ima.AdDisplayContainer( outstreamDocument.getElementById('adContainer'), videoContent); } function unmuteAdvert() { adVolume = !adVolume; if (adVolume) { adsManager.setVolume(0.3); outstreamDocument.getElementById('adMuteBtn').innerHTML = ''; } else { adsManager.setVolume(0); outstreamDocument.getElementById('adMuteBtn').innerHTML = ''; } } /** * Loads the video content and initializes IMA ad playback. */ function playAds() { // Initialize the container. Must be done through a user action on mobile // devices. videoContent.load(); adDisplayContainer.initialize(); // setupDimensions(); try { // Initialize the ads manager. Ad rules playlist will start at this time. adsManager.init(1920, 1080, google.ima.ViewMode.NORMAL); // Call play to start showing the ad. Single video and overlay ads will // start at this time; the call will be ignored for ad rules. adsManager.start(); // window.addEventListener('resize', function (event) { // if (adsManager) { // setupDimensions(); // adsManager.resize(outstreamWidth, outstreamHeight, google.ima.ViewMode.NORMAL); // } // }); } catch (adError) { // An error may be thrown if there was a problem with the VAST response. // videoContent.play(); } } /** * Handles the ad manager loading and sets ad event listeners. * @param { !google.ima.AdsManagerLoadedEvent } adsManagerLoadedEvent */ function onAdsManagerLoaded(adsManagerLoadedEvent) { // Get the ads manager. const adsRenderingSettings = new google.ima.AdsRenderingSettings(); adsRenderingSettings.restoreCustomPlaybackStateOnAdBreakComplete = true; adsRenderingSettings.loadVideoTimeout = 12000; // videoContent should be set to the content video element. adsManager = adsManagerLoadedEvent.getAdsManager(videoContent, adsRenderingSettings); // Add listeners to the required events. adsManager.addEventListener(google.ima.AdErrorEvent.Type.AD_ERROR, onAdError); adsManager.addEventListener( google.ima.AdEvent.Type.CONTENT_PAUSE_REQUESTED, onContentPauseRequested); adsManager.addEventListener( google.ima.AdEvent.Type.CONTENT_RESUME_REQUESTED, onContentResumeRequested); adsManager.addEventListener( google.ima.AdEvent.Type.ALL_ADS_COMPLETED, onAdEvent); // Listen to any additional events, if necessary. adsManager.addEventListener(google.ima.AdEvent.Type.LOADED, onAdEvent); adsManager.addEventListener(google.ima.AdEvent.Type.STARTED, onAdEvent); adsManager.addEventListener(google.ima.AdEvent.Type.COMPLETE, onAdEvent); playAds(); } /** * Handles actions taken in response to ad events. * @param { !google.ima.AdEvent } adEvent */ function onAdEvent(adEvent) { // Retrieve the ad from the event. Some events (for example, // ALL_ADS_COMPLETED) don't have ad object associated. const ad = adEvent.getAd(); console.log('Outstream event: ' + adEvent.type); switch (adEvent.type) { case google.ima.AdEvent.Type.LOADED: // This is the first event sent for an ad - it is possible to // determine whether the ad is a video ad or an overlay. if (!ad.isLinear()) { // Position AdDisplayContainer correctly for overlay. // Use ad.width and ad.height. videoContent.play(); } outstreamDocument.getElementById('adContainer').style.width = '100%'; outstreamDocument.getElementById('adContainer').style.maxWidth = '640px'; outstreamDocument.getElementById('adContainer').style.height = '360px'; break; case google.ima.AdEvent.Type.STARTED: window.addEventListener('scroll', onActiveView); // This event indicates the ad has started - the video player // can adjust the UI, for example display a pause button and // remaining time. if (ad.isLinear()) { // For a linear ad, a timer can be started to poll for // the remaining time. intervalTimer = setInterval( function () { // Example: const remainingTime = adsManager.getRemainingTime(); // adsManager.pause(); }, 300); // every 300ms } outstreamDocument.getElementById('adMuteBtn').style.display = 'block'; break; case google.ima.AdEvent.Type.ALL_ADS_COMPLETED: if (ad.isLinear()) { clearInterval(intervalTimer); } if (outstreamLastError === 303) { if (isBanner) { renderBanner(); } else { replayScreen.style.display = 'flex'; } } break; case google.ima.AdEvent.Type.COMPLETE: // This event indicates the ad has finished - the video player // can perform appropriate UI actions, such as removing the timer for // remaining time detection. if (ad.isLinear()) { clearInterval(intervalTimer); } if (isBanner) { renderBanner(); } else { replayScreen.style.display = 'flex'; } break; } } /** * Handles ad errors. * @param { !google.ima.AdErrorEvent } adErrorEvent */ function onAdError(adErrorEvent) { // Handle the error logging. console.log(adErrorEvent.getError()); outstreamLastError = adErrorEvent.getError().getErrorCode(); if (!loadNext()) { renderBanner(); } } function renderBanner() { if (isBanner) { console.log('Outstream: Render Banner'); iinfoOutstreamPosition.innerHTML = ""; iinfoOutstreamPosition.style.height = "330px"; iinfoOutstreamPosition.appendChild(bannerDiv); } else { console.log('Outstream: Banner is not set'); } } function loadNext() { iinfoVastUrlIndex++; if (iinfoVastUrlIndex < iinfoVastUrls.length) { iinfoOutstreamPosition.remove(); outstreamInit(); } else { return false; } adVolume = 1; return true; } /** * Pauses video content and sets up ad UI. */ function onContentPauseRequested() { videoContent.pause(); // This function is where you should setup UI for showing ads (for example, // display ad timer countdown, disable seeking and more.) // setupUIForAds(); } /** * Resumes video content and removes ad UI. */ function onContentResumeRequested() { videoContent.play(); // This function is where you should ensure that your UI is ready // to play content. It is the responsibility of the Publisher to // implement this function when necessary. // setupUIForContent(); } function onActiveView() { if (outstreamContainer) { const containerOffset = outstreamContainer.getBoundingClientRect(); const windowHeight = window.innerHeight; if (containerOffset.top < windowHeight/1 && containerOffset.bottom > 0.0) { if (outstreamPaused) { adsManager.resume(); outstreamPaused = false; } return true; } else { if (!outstreamPaused) { adsManager.pause(); outstreamPaused = true; } } } return false; } let outstreamInitInterval; if (typeof cpexPackage !== "undefined") { outstreamInitInterval = setInterval(tryToInitializeOutstream, 100); } else { const wrapper = getWrapper(); if (wrapper) { let outstreamInitialized = false; window.addEventListener('scroll', () => { if (!outstreamInitialized) { const containerOffset = wrapper.getBoundingClientRect(); const windowHeight = window.innerHeight; if (containerOffset.top < windowHeight / 1 && containerOffset.bottom > 0.0) { outstreamInit(); outstreamInitialized = true; } } }); } } function tryToInitializeOutstream() { const wrapper = getWrapper(); if (wrapper) { const containerOffset = wrapper.getBoundingClientRect(); const windowHeight = window.innerHeight; if (containerOffset.top < windowHeight / 1 && containerOffset.bottom > 0.0) { if (cpexPackage.adserver.displayed) { clearInterval(outstreamInitInterval); outstreamInit(); } } } else { clearInterval(outstreamInitInterval); } } }
OSZAR »