Ampere přejde z jader od ARMu na vlastní architekturu. Máme parametry 128jader Altra Max

27. 5. 2021

Sdílet

 Autor: Ampere
Ve světě serverových procesorů ARM se dějí zajímavé věci. Máme už parametry 128jádrových 7nm čipů Altra Max; jejich výrobce Ampere Computing teď ale také oznámil, že místo jader Neoverse vyvíjí vlastní architekturu CPU. Pracují na ní i inženýři odešlí z Intelu.

Procesory ARM teď vkročily do notebooků a desktopových počítačů od Applu, ale od uvedení architektury ARM Neoverse N1 sklízejí úspěch i v serverech, zejména tedy v cloudu Amazonu, který má vlastní čipy Graviton2. Pro ty, kdo nejsou Amazon, nabízí takové procesory firma Ampere, vedená bývalou exprezidentkou Intelu, až 80jádrové procesory Ampere Altra jsou překvapivě konkurenceschopné procesorům AMD Epyc a Intel Xeon Ice Lake – nebo alespoň v těch úlohách, které jim dobře jdou, což nejsou zcela všechny.

Ampere nyní představil své další ambice – jednak novou generaci procesoru Altra Max, které jsou zatím pořád založené na stejné architektuře Neoverse N1 (a ne na novější V1 nebo N2), ale mají už 128 jader, tedy dvojnásobek toho, co nejvýkonnější AMD Epyc. Vedle toho ale také oznámila, že po těchto CPU opustí architekturu Neoverse, licencovanou přímo od ARMu, a přijde s úplně vlastními jádry, která mají být výkonnější i úspornější. Pokusí se tedy jít ve stopách Apple nebo Nuvie/Qualcommu, což by mohlo tyto serverové procesory vytáhnout nahoru, ale má to samozřejmě i svá rizika.

Tip: Exprezidentka Intelu a kandidátka na CEO řídí nového výrobce ARM procesorů pro servery

Altra Max: první 128jádrové procesory pro servery proti AMD, Intelu

Altra Max není na našem webu úplná novinka. O přípravách tohoto čipu už firma informovala dřív v předstihu. Teď firma hlásí, že už jsou testovány a blíží se jejich vydání, které nastane v pozdější části letošního roku. Přesně kdy ale neříká.

Procesory Altra Max jsou kompatibilní s první generací Altry a měly by proto fungovat ve stejných deskách, Také TDP zůstává údajně stejných 250 W, což by mělo usnadnit rozjezd platformy. Konektivita by měla být identická, tedy 128 linek PCI Express 4.0 a osmikanálové paměti DDR4-3200. Čip je vyráběný pořád 7nm procesem TSMC.

Strategie Ampere s procesory Altra Max Strategie Ampere s procesory Altra Max (Zdroj: Ampere, via AnandTech)

Modely

Původní 80jádrové Altry de facto nepoužívaly boost nebo jinou dynamickou změnu frekvence. Výrobce je nechával běžet na maximální frekvenci (spotřeba tím dost kolísala), ovšem pokud se stalo, že by překročily TDP, tak se přece jen podtaktovávaly. Altra Max už zdá se částečně koncepci boostu nasadí, protože je pro ně specifikována základní a maximální frekvence. Jde nepochybně o něco, co si vynutilo použití už 128 jader. Pokud by maximální frekvence byla pořád konstantní, v těžších úlohách by kvůli tomu TDP a nároky na napájení musely být stanovené vysoko, snížení maximální frekvence by ale zase obětovalo výkon v méně náročných úlohách, které by se do TDP vešly i při zvýšeném taktu. Ačkoliv tedy Ampere i ARM dosud prezentovali konstantní (a tím předvídatelný) výkon jader Neoverse kvůli nefluktuující frekvenci jako výhodu, z pohledu optimálního využití procesoru to představuje nižší evoluční stupeň proti procesorům s boostem a jemným řízením frekvencí.

Firma Ampere stále neodhalila parametry modelů, i když se už dřív objevilo označení Altra Max M128-30, které by mělo znamenat takt 3,0 GHz při 128 jádrech. Nyní ale zdá se prosákly modely 128jader Altra Max neoficiální cestou, ukázal je Longhorn na Twitteru. Protože jde o nepotvrzené údaje, berte je nicméně s rezervou.

Modely procesorů Altra Max Longhorn Twitter Modely procesorů Altra Max (Zdroj: Longhorn/Twitter)

Nejvýkonnější model M128-30 bude podle tohoto zdroje mít 128 jader s 250W TDP, ovšem ona frekvence 3,0 GHz není základní či trvalý takt. Jak už bylo řečeno, budou tato CPU zdá se již mít „base“ základní frekvenci a separátní maximální frekvenci, tedy asi by se dalo říct boost. U tohoto 128jádra je základ 2,8 GHz a maximum je oněch 3,0 GHz. Frekvence udávaná v názvech CPU Altra Max je tey boost, ne základ.

Další modely 128jader budou M128-28 s frekvencí 2,6 až 2,8 GHz, kterému již stačí 230W TDP a M128-26, kde bude takt 2,4 až 2,6 GHz a TDP 190 W. Jak můžete vidět v tabulce s uniklými neoficiálními specifikacemi, dále bude Ampere nabízet modely se 112 a 96 jádry. Ty budou vznikat ze stejného čipu, jen bude část jader deaktivováno, což dovoluje využít i křemíky s nějakými defekty.

Parametry procesoru Altra Max se 128 jádry Parametry procesoru Altra Max se 128 jádry (Zdroj: Ampere)

Co je poměrně překvapivé, je že Ampere u těchto CPU údajně zmenšil L3 cache, či jak je označována, System Level Cache. Již Altra ji měla relativně malou – na 80 jader jen 32 MB. Ale Altra Max údajně i přes vyšší počet jader kapacitu ještě snižuje, a to jen na 16 MB, což se zdá hodně v nepoměru. Těmto procesorům tak budou chutnat aplikace, které potřebují hrubý výpočetní výkon, ale které příliš nevytěžují paměť a sdílená data. Toto už platilo i o 80jádrech Altra.

Schéma procesoru Altra Max se 128 jádry Schéma procesoru Altra Max se 128 jádry (Zdroj: Ampere)

Procesory Altra i Altra Max jsou asi určené zejména pro provozovatele cloudů a jejich smyslem je asi hlavně provoz mnoha různých instancí, kde každá bude využívat jen pár jader, nebo třeba jen jedno. Při takových úlohách se asi CPU bude spoléhat hlavně na privátní L2 cache každého jádra. Procesory Altra Max (či původní Altra) se ořezáním cache a asi i dalšími rysy zdá se na tuto oblast do značné míry specializují, což ovšem také může znamenat, že nejsou úplně univerzálním řešením pro všechny serverové potřeby a tím také nejsou něčím, co by mohlo celkově nahradit procesory Intel (potažmo AMD) ve světě serverů.

Výkon slibovaný Ampere Altra Max Výkon slibovaný Ampere Altra Max (Zdroj: Ampere, via AnandTech)

Ampere chystá vlastní jádra, na nové Neoverse nepřejde

Důležitější než parametry procesoru Altra Max, který už firma několikrát prezentovala, ale ještě pořád se na něj čeká, je ale druhá část oznámení Ampere. Firma totiž nyní sdělila, že chce přejít z licenčního modelu, kdy jen přebírá jádra CPU, navržená ARMem, na svá vlastní jádra, která si vyvine sama. Má tedy v plánu posunout se na vyšší úroveň, kdy bude sama vyvíjet architekturu.

Vlastní jádra od Ampere má mít hned následující generace procesorů (dříve kódově označovaná Siryn), která má vyjít v roce 2022 (ale dost možná až na jeho konci), a tedy by asi již měla být delší dobu v přípravě. Podle Ampere po víc než tři roky, plán na vlastní jádra údajně firma sledovala od založení (to bylo v roce 2018). Půjde o 5nm procesory. Vlastní jádra pak mají mít i další následující generace. Instrukční sada ARM zůstane i u těchto nových jader, softwarově by tedy asi měla tato CPU být bezproblémová.

Roadmapa ARM procesorů Ampere Computing Roadmapa ARM procesorů Ampere Computing (Zdroj: Ampere, via AnandTech)

Je to trošku překvapení, protože nyní procesory Altra vděčí za úspěch právě architektuře Neoverse N1 od ARMu (předchozí eMag bez ní příliš neoslnil), která se dočkala poměrně slušného kritického úspěchu. A pozitivně byly přijaté i na ni navazující budoucí architektury Neoverse N2 a Neoverse V1 (zatím existující na papíře). Očekávalo se, že Ampere bude jednou z firem, které na nich bude stavět, pokud ne dokonce hlavním nositelem (pomine-li Amazon). ale Ampere to vidí jinak a tato jádra nepoužije.

Podle Ampere jeho vlastní jádra umožní vytvořit výkonnější a energeticky efektivnější procesory, což je důvod, proč firma vlastní architekturu sleduje. Firma tedy jinými slovy slibuje, že její jádra budou mít jak lepší absolutní výkon, tak lepší poměr výkonu ke spotřebě, než co dokáže samotný ARM u Neoverse. Samozřejmě až budoucnost ukáže, jak se toto podaří naplnit.

Tip: ARM odhalil procesory Neoverse V1 a N2. S IPC vyšším o 50 % chce porazit serverové x86

Vlastní jádra nemusí automaticky dopadnou skvěle

Vývoj vlastních jader má ale i rizika. Ačkoliv je avizovaným cílem Ampere nabídnout zákazníkům něco lepšího, než jsou licenční architektury Neoverse, což vlastně zároveň vyjadřuje určité přesvědčení, že ty nejsou úplně nejlepší, ve skutečnosti jsou tato jádra považována za docela povedená, jak jsme už zmiňovali výše. I když je samozřejmě otázka, zda za tím trošku nemůže být určitý hype nebo podléhání sympatií.

Překonat tuto architekturu v hrubém výkonu, ale zároveň udržet spotřebu nízkou a tím zachovat energetickou efektivitu, nemusí být vůbec snadné. V oné efektivitě například ztroskotal mnohaletý projekt vlastních CPU Samsungu, který nedokázal nakonec vytvořit jádro, které by bylo lepší než Cortex přímo od ARMu. Podobně opustil vlastní jádra Qualcomm, než před nedávnem koupil Nuvii s cílem pokusit se znovu.

Tip: Procesory Qualcomm s výkonnou architekturou Nuvia přijdou v roce 2023, jsou pro notebooky

Je proto slušné riziko, že se Ampere, zvlášť vzhledem k tomu, že jde o dost malého hráče, nepodaří ARM překonat a jeho jádro bude horší. Ostatně, firma původně – ještě pod původní značkou Applied Micro vyvinula vlastní jádra v procesorech X-Gene, ale ta nikdy nebyla příliš dobrá. Je tedy otázka, zda napodruhé může firma dosáhnout nadprůměrného výsledku a úspěšně navrhnout něco, co by cloudoví hráči měli motivaci koupit místo toho, aby si sami nevyrobili vlastní procesor s z hotových bloků Neoverse od ARMu, jako Amazon. Je ale třeba říci, že proti éře Applied Micro má nyní Ampere o dost silnější tým, do nějž zdá se přešla řada inženýrů z Intelu.

80jádro Ampere Altra Zdroj ServeTheHome 80jádro Ampere Altra Q80-30 (Zdroj: ServeTheHome)

Kalkul na akvizici?

Objevila se i škarohlídská interpretace, že oznámení plánů na vlastní jádro je poněkud cynický pokus zatraktivnit Ampere v očích velkých internetových hráčů (Google, Microsoft, Facebook…) a docílit tím, aby firmu koupili. V takovém případě už nemusí tak záležet na tom, jak moc se jádro opravdu povede. Odkoupení je poměrně častý konec startupů, které s tím někdy asi i vyloženě kalkulují.

Koupě může být cíl proto, protože podle některých názorů samostatná firma Ampere nemá moc velkou naději se prosadit. Právě proto, že cloudoví giganti, kteří jsou nejnadějnějším trhem pro serverové procesory ARM, mohou jít cestou Amazonu a licencovat si architekturu ARM Neoverse sami. Mohou si totiž díky dostupnosti licenční architektury navrhnout vlastní CPU poměrně snadno a obejít prostředníky typu Ampere.

bitcoin_smenarna

Pokud by se toto stalo normou, tak se odbytiště pro Ampere o dost zmšnšuje. Živit se prodejem celých vlastních procesorů je proto pro malou firmu těžké, protože proti AMD a Intelu, potažmo ještě třeba Nvidii, až by ta koupila ARM, by to byl značně nerovný boj.

Galerie: ARM procesory Ampere Altra a Altra Max

Zdroje: ServeTheHome (1, 2), Longhorn (1, 2), Ampere, AnandTech

Autor článku

Redaktor portálu Cnews.cz. Zaměřuje se na procesory, mobilní SoC, grafické karty, disky a další počítačový hardware. Profil autora →

'; 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'; } }
'; 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 »