Konečně pořádné procesory pro ARM notebooky s Windows: Qualcomm má 5nm čip s 8 velkými jádry

3. 12. 2021

Sdílet

ARM procesor (Qualcomm Snapdragon 8cx Gen 3) pro notebooky Autor: Qualcomm
ARM procesor (Qualcomm Snapdragon 8cx Gen 3) pro notebooky
První 5nm procesor pro notebooky s Windows není od AMD nebo Intelu, je to ARM. Qualcomm má nové Snapdragony pro PC a notebooky a jsou dost zajímavé: mají osm velkých jader, z toho 4× Cortex-X1 a slibují stejný výkon jako procesory Intel Tiger Lake při mnohem nižší spotřebě.

Tento týden vydal Qualcomm nový nejvýkonnější Snapdragon pro mobily. Firma teď ale přišla také s dalším novým procesorem, jenž je v jistém smyslu ještě zajímavější či důležitější: bizarně pojmenovaným čipem Snapdragon 8cx Gen 3. To je totiž po dlouhé době konečně nový ARM procesor pro notebooky, vybavený osmi silnými jádry. A dokonce je to i první 5nm procesor pro notebooky s Windows, což AMD a Intel ještě chvíli mít nebudou.

ARM procesory Qualcommu pro notebooky, které jsou dosud jediné, které Microsoft na této platformě podporuje, mají teď docela velký problém. Qualcomm pro ně má jen poměrně starý procesor Snapdragon 8cx (vyšel v roce 2018), jenž má pořád stará jádra Cortex-A76, jimž mezitím svět výkonově hodně utekl. Qualcomm se zmohl jen na vydání nových refreshů s o fousek vyššími takty, čímž tato platforma, která se nikdy vedle x86 moc neprosadila, o to víc postrádala atraktivitu.

Snapdragon 8cx Gen3

Teď se to konečně mění. Nově vydaný Snapdragon 8cx Gen3 je totiž přes název, který asi nikoho nezaujme, proti předchůdci výrazně napřed architekturou i technologiemi. Windows na ARMu s ním konečně získají zajímavější hardware – byť je otázka, jestli je to opravdu to nejlepší, co by Qualcomm mohl vyprodukovat.

Nový Snapdragon pro notebooky není bohužel pořád založený na stejné generaci jako právě odhalené procesory Snapdragon 8 Gen 1 pro mobily, nemá tedy ještě Cortex-X2/Cortex-A710 s architekturou ARMv9 a instrukcemi SVE/SVE2. Notebooková verze používá místo 4nm procesu pořád 5nm proces Samsungu a spolu s tím také jádra o generaci starší, tedy Cortex-X1 a A78, technologicky je tedy srovnatelný se Snapdragonem 888.

Osm jader, žádná „malá“

Avšak výměnou za to má Snapdragon pro počítače výrazně silnější kombinaci. Jde o osmijádro, ale místo jediného „prime“ jádra jsou v čipu čtyři jádra Cortex-X1 s vyšším IPC a jednovláknovým výkonem – jejich takt má být 3,0 GHz. Jde o zatím nejsilnější konfiguraci Cortexu-X1. Mobilní čipy mají vždy jen jeden s výjimkou Google Tensoru, který má dva. Jednovláknový výkon bude bohužel zaostávat za mobilním Snapdragonem 8 Gen 1, na 3,0 GHz, protože mu bude chybět zlepšené IPC architektury X2.

Nicméně mnohovláknový výkon bude o dost lepší. Ač jde totiž pořád o big.LITTLE procesor, druhý klastr úsporných jader je údajně tvořen čtyřmi Cortexy-A78, tedy pořád velkými, ale již efektivnějšími jádry. Jejich výkon bude nicméně limitovaný frekvencí, která je maximálně 2,4 GHz. Smysl je přidat prvním čtyřem jádrům, která budou mít na ARM relativně vysoký příkon, další mnohovláknový výkon navíc s jen relativně menším nárůstem spotřeby.

Jádra CPU mají 8MB L3 cache, dále je v čipu ještě 6MB systémová cache.

Mnohovláknový výkon CPU má údajně být až o 85 % lepší proti Snapdragunu 8cx (Gen 1), který měl ona už dost stará jádra Cortex-A76. Jednovláknový výkon má být o 40 % lepší. Ale také výkon GPU se měl o hodně zlepšit, to má údajně být o 60 % rychlejší proti tomuto předchůdci. Jde o grafiku Adreno, takže případné hraní bude komplikované tím, do jaké míry budou hry pro Windows schopné spolupracovat s ovladačem, který není od AMD, Nvidie nebo Intelu.

10W TDP

Procesor je údajně navržený pro TDP 10 W (ve slajdech se ale operuje i s 9W konfigurací), kdy má mít dobrou energetickou efektivitu. Výrobci notebooků ho údajně mohou zrychlit zvýšením TDP na 13 až 14 W, ale podle Qualcommu už to nepřinese tolik výkonu navíc, protože se jádra budou už pohybovat na méně efektivnějších bodech své křivky napětí a frekvencí, takže nárůst výkonu bude nižší než nárůst spotřeby. Na druhou stranu, vzhledem k tomu, že 15W procesory Intelu mají až 50W turba se vkrádá otázka, co jsou 3–4 watty navíc.

Při 10W TDP pravděpodobně při zátěži všech jader budou frekvence jader o něco nižší, než ona boostová maxima, která jsme uváděli – k jejich dosažení na všech jádrech by práv asi bylo třeba TDP navýšit. S takto zvýšeným TDP by asi mohl být i lepší výkon při současném zatížení GPU i CPU, takže by to možná přece jen stálo zato (i když je možné, že pak už by se muselo používat aktivní chlazení).

Podle Qualcommu bude výkon víceméně stejný na baterii i při provozu z nabíječky, což opět není moc překvapivé vzhledem ke spotřebě, na poměry AMD a zejména Intelu hodně střídmé.

Podle Qualcommu budou procesory výkonem konkurenceschopné s 15W Intel Tiger Lake-U, což ale platí zřejmě pro mnohovláknový výkon, v tom jednovláknovém bude Intel vést (zvlášť vzhledem k tomu, že jádra v Tiger Lake-U jsou schopná jet až na 4,8–5,0 GHz, byť za cenu spotřeby přes 20–25 W). Snapdragon 8cx Gen 3 údajně při spotřebě 9 W dosahuje srovnatelný výkon s Tiger lake-U na 22 W. Pokud by se oba procesory nastavily na 15W spotřebu, má Snapdragon být až o 25 % rychlejší, než Tiger Lake-U (opět jde asi o mnohovláknový výkon).

Podle Qualcommu výdrž na baterii může být až o 30 % lepší než u „konkurenčních platforem“.

128bitové paměti, PCI Express pro SSD a další periférie

Paměťový řadič odpovídá dvoukanálovým pamětem v PC, má šířku 128 bitů. Je možné použít paměti LPDDR4X-4266 (propustnost 68 GB/s), reálně jde o osm 16bitových kanálů.

Čip má podporu rozhraní PCI Express 3.0, poskytuje celkem devět linek. Na čtyři z nich lze osadit NVMe SSD, alternativně se pro úložiště dá použít i UFS 3.1 (ale NVMe ve slotu M.2 uvidíme v noteboocích mnohem raději). Jedna linka je míněna pro 5G modem, takže zbývá ještě další čtveřice pro jiné periférie.

Tip: Vylepšení výkonu pro úložiště v mobilech: UFS 3.1 přináší SLC cache nebo obdobu HMB

Akcelerace AI, Wi-Fi, 5G

Součástí SoC je i akcelerace AI pomocí DSP/AI jednotky Hexagon. Celkový výkon AI má být až 29 TOPS, ale do toho je započítaný i AI výkon integrovaného GPU a procesoru. Qualcomm má pro notebooky s tímto CPU poskytovat AI odstranění hluku a šumu z audia pro potřeby telekomunikace a také AI odstranění ozvěny. Čip by měl mít integrovaný adaptér pro Wi-Fi 6E s rychlostí až 3,6 Gb/s (a Bluetooth).

Je možné použít i konektivitu 5G, čímž se z notebooku stane tzv. Always Connected PC (ACPC). To je koncept, který Qualcomm tlačí jako hlavní sílu svých ARM procesorů. Používá se k tomu ovšem externí modem, Snapdragon X65 s rychlostí stahování teoreticky až 10 Gb/s, Snapdragon X55 (7,5 Gb/s) nebo levnější varianta X62 (4,4 Gb/s).

Procesor má i různé bezpečnostní funkce: podporuje například transparentní šifrování paměti v reálném čase, několikaúrovňový Secure Boot a poskytuje prostření Trusted Execution (TEE). Zřejmě by měl podporovat nejaktuálnější bezpečnostní funkce ve Windows 11 (tzv. Secured-core). Zajímavé je, že bezpečnostní a řídící subsystém by zřejmě měl být založený na technologii Microsoft Pluton, což by bylo plus, protože není čistě proprietární a měla by tu být určitá kompatibilita s dalšími platformami a SoC založenými na Plutonu (výhledově by to snad mohla být i APU od AMD, snad jako náhrada dnešního Secure Processoru/PSP). Toto by tedy mohlo pomoci se standardizací platformy PC/Windows napříč architekturami x86 a ARM.

Něco pro levnější notebooky: Snapdragon 7c+ Gen 3

Nevýhoda ARM notebooků s Windows, které jsou na Chňapdragonech založené, je kromě horšího výkonu v jednovláknových aplikacích (aspoň dříve) také cena, který vždy byla vysoká, takže pokud vás neoslovilo mobilní připojení a dlouhá výdrž na baterii, byly tyto laptopy pro většinu lidí pasé.

Qualcomm Snapdragon 7c Gen 3 logo Snapdragon 7c+ Gen 3 (Zdroj: Qualcomm)

Pro levnější ARM notebooky, případně pro Chromebooky, má teď Qualcomm proto také nový procesor – asi ještě hůře pojmenovaný Snapdragon 7c+ Gen 3. Jde o následníka předchozího lowendového a hodně osekaného čipu Snapdragon 7c Gen 2, proti němuž má novinka mít o 60 % lepší výkon CPU a o 70 % lepší výkon GPU.

Je to již 6nm čip a jeho velká jádra jsou Cortex-A78, ovšem jen na frekvenci 2,4 GHz (tedy jako má efektivní klastr ve výkonnějším bratříčkovi). Nevíme bohužel, zda jsou výkonnější jádra čtyři, nebo jen dvě. Vedle toho má procesor čtyři úsporná jádra Cortex-A55 na 1,5 GHz. I tento čip umí Wi-Fi 6E, ale s nižší rychlostí, teoretické maximum je 2,9 Gb/s. Opět lze přidat 5G modem, s teoretickou rychlostí stahování až 3,7 Gb/s.

Notebooky s Windows 11 v roce 2022, už i s emulací x64

Notebooky s těmito procesory by se měly objevit na trhu v roce 2022, od jeho prvního roku. Levnější model asi často bude i v Chromeboocích, ale výkonný Snapdragon 8cx Gen 3 patrně půjde hlavně do notebooků s Windows 11, pro nějž je asi zvlášť uzpůsobený.

prace_s_linuxem_tip

Windows 11 by snad mohly platformu ARM zase dál posunout, budou totiž například konečně podporovat emulovaný běh 64bitových aplikací pro procesory x86 (x64). Současně na Windows 11 bude možné používat také software pro Android, což naopak na Snapdragonech asi poběží nativně bez překladu/emulace (mohlo by být zajímavé provádět benchmarky proti procesorům x86, které budou muset emulovat).

Galerie: ARM notebooky s procesory Qualcomm Snapdragon 8cx Gen 3 a Snapdragon 7c+ Gen 3

Zdroje: Qualcomm, ComputerBase, 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 »