Levnější a méně topící PCIe 5.0 SSD: Přichází nové a lepší řadiče pro Gen5 moduly

14. 6. 2024

Sdílet

NVMe modul M.2 Autor: Adata
NVMe modul M.2
Na Computexu 2024 se objevila řada nových řadičů pro SSD využívající rychlosti rozhraní PCIe 5.0 SSD. Zdá se, že by se z nich konečně mohla stát běžná věc.

Po vydání procesorů s podporou PCIe 5.0 nejdřív dost trvalo, než vyšla SSD, která ji dokážou využít, a pak se ukázalo, že moduly založené na prvním řadiči Phison E26 měly vysoké spotřeby a dost se přehřívaly. Spolu s vysokou cenou to vedlo k tomu, že se zatím tato technologie moc neuplatnila. Ale na trh teď míří několik nových řadičů, s nimiž se snad PCIe 5.0 konečně také stanou mainstreamem jak co do ceny, tak spotřeby.

Silicon Motion SM2508: Špičková SSD bez nárůstu spotřeby

Computex 2024 přinesl snůšku řadičů pro PCIe 5.0 SSD a tato konkurence (a výběr mezi různými řešeními) by měla věci vylepšit. Nejdůležitější by asi měl být řadič od americké firmy Silicon Motion, která je na trhu nejzavedenější – s Phisonem tvoří hlavní dvojici dodavatelů, ačkoliv v aplikaci PCIe 4.0 a pak PCIe 5.0 byla firma pomalejší, což dalo Phisonu více prostoru.

Pro PCIe 5.0 SSD má tato firma jako první řadič SM2508, což je highendový čip s rozhraním PCIe 5.0 ×4 podporující osm kanálů pro NAND paměti, takže jde do stejné kategorie jako nyní používaný Phison E26. Výkon tomu odpovídá, SSD s tímto čipem mají dosahovat rychlostí čtení až 14,5 GB/s a rychlostí zápisu až 14,0 GB/s. Ovšem tato novinka by mohla mít navrch v náhodném přístupu, kde má umožňovat až 2,5 milionu IOPS jak ve čtení, tak v zápisu.

Jde o řešení s mezipamětí DRAM (LPDDR4X nebo DDR4), které integruje čtyři jádra ARM Cortex-R8 pro různé výpočetní operace vyžadované při správě NAND (používána je mimochodem 4K LDPC). Na osmi kanálech může být až 32 čipů NAND, což umožňuje 4TB SSD s pamětí typu TLC a 8TB s QLC NAND. Řadič podporuje komunikaci s čipy až rychlostí 3600 MT/s.

Co bude ale řadič nejvíc odlišovat od Phisonu E26, by mohla být spotřeba. Podle výrobce by měl mít špičkové TDP okolo 3,5 W, je totiž vyráběný na pokročilejším výrobním procesu novějším o dvě generace – je použitý 6nm proces TSMC (Phison E26 je 12nm). Také klidová spotřeba může být hodně nízká, jen 2,5 mW s režimu PS4. Možná tak už nastane i čas, kdy PCIe 5.0 ×4 SSD s patřičným výkonem bude moci být i v notebooku.

PCIe 5.0 ×4 SSD řadič Silicon Motion SM2508

PCIe 5.0 ×4 SSD řadič Silicon Motion SM2508

Autor: Silicon

Celé highendové SSD by tak mohlo mít spotřebu okolo 7 W, snad i při těch výkonech nad 14,0 GB/s. To je spotřeba, kterou mají rozumná PCIe 4.0 SSD nebo i starší výkonné PCIe 3.0 moduly, zatímco PCIe 5.0 moduly s Phisonem E26 jdou až na 11 W. Je to rozdíl pár wattů, ale právě to vedlo k onomu častému přehřívání a throttlingu (v horších případech zamrzání a pádům) a právě kvůli tomu se na modulech objevovaly aktivní chladiče.

Moduly se Silicon Motion SM2508 by měly oproti tomu být mnohem nenáročnější a mělo by u nich, doufejme, stačit použít běžný pasiv nebo integrovaný chladič vaší základní desky.

SSD s tímto řadičem asi nejsou bezprostředně za dveřmi. Čip samotný by asi měl být hotový, ale stále je finalizován firmware a nyní platforma prochází validací pro čipy NAND od různých výrobců. Podporuje TLC i QLC, ale výkonná SSD budou pravděpodobně vždy nebo téměř vždy jen s TLC.

Silicon Motion na Computexu 2024 předváděl prototyp (v CrystalDiskMarku dosahoval čtení až 14 903 MB/s) a několik výrobců ukazovalo vzorky SSD s tímto řadičem, tak by snad reálná dostupnost na trhu neměla být ani vyloženě daleko, možná by se mohla tato SSD objevit už do konce letošního roku.

Adata Project NeonStorm se zvláštním ozdobným vodním chladičem bude také založené na SM2508

Adata Project NeonStorm se zvláštním ozdobným vodním chladičem bude také založené na SM2508

Autor: Adata

Realtek má také řadiče pro „Gen5 SSD“

Do této oblasti se hrne i Realtek, který už pár řadičů pro SSD vyvinul a zatím sice nejsou moc široce zastoupené, ale protože nejde o vyloženě malou firmu nebo startup, asi má na to, aby získal nějaký díl trhu. Pro highendová SSD chystá Realtek čip RTS5781DL s rozhraním PCIe 5.0 ×4. Ten má také osm kanálů s podporou čipů na rychlosti až 3600 MT/s a také používá 4K LDPC.

Realtek slibuje dosažení sekvenčních rychlostí až 14 GB/s při čtení a 12 GB/s při zápisu a také 2,5 milionu IOPS při náhodném čtení i náhodném zápisu, jde o řadič používající DRAM (DDR4 nebo LPDDR4/4X).

Firma chystá také další řadič s rozhraním PCIe 5.0 ×4, RTS5781DL. To už bude úspornější a levnější řešení se čtyřmi kanály (také s rychlostí komunikace 3600 MT/s a 4K LDPC), které má dosahovat rychlosti čtení a zápisu 10 GB/s v sekvenčním čtení a 10 GB/s i v sekvenčním zápisu. V náhodném čtení a zápisu má dávat až 1,4 milionu IOPS.

V praxi se tato SSD objeví až později, vzorky řadičů mají být u druhého levnějšího v Q1 2025, takže první SSD nejspíš budou koncem roku 2025 až začátkem roku 2026, může to trvat i déle k relativně méně častému používání řadičů tohoto výrobce. U prvního výkonnějšího řadiče zatím nic o termínu dostupnosti vzorků není sděleno a ještě je asi rozpracovaný. SSD s ním tak asi budou až zadlouho.

Maxio: Levná SSD s výkonem špičky?

Menším hráčem v řadičích je Maxio Technology (či MaxioTek), který už ale také chystá podporu PCIe 5.0. Na Computexu byla tato technologie vidět už i v hotovém SSD – Patriot Viper PD573 (pozor, nezaměňovat s PV573, který má Phison E26 a aktivní chladič, viz obrázek).

Patriot Viper PV573 (s řadičem Phison E26)

Patriot Viper PV573 (s řadičem Phison E26)

Autor: Patriot

To bude dost zajímavý modul. Patriot je americká firma a vzdor významu jejího jména má SSD jak čínský řadič, tak čínskou NAND (i když sestavení bude na Tchaj-wanu). Paměti jsou od YMTC, tedy Yangtze Memory Technologies. Řadič pak je zajímavá novinka, Maxio MAP1802. I Maxio Technology je čínská společnost.

Maxio MAP1802 má rozhraní PCIe 5.0 ×4 a je to DRAMless řadič, navíc jen čtyřkanálový, tedy ne highendové, ale mainstreamové řešení. Tím pádem by ale také mohl být poměrně úsporný na spotřebu a celé SSD by mohlo být z levnějších.

Podle Patriotu moduly Viper PD573 i přes použití řadiče této nižší váhové kategorie mají dosahovat rychlosti čtení až 14 000 MB/s a rychlosti zápisu až 12 000 MB/s, takže moduly by se z velké části vyrovnaly oněm highendovým modelům s osmikanálovými řadiči a mezipamětí DRAM. Nicméně asi k tomu budou potřeba velmi rychlé čipy NAND, což zase bude ze začátku nevýhoda (ovšem později mohou takové čipy zlevnit na úrovně, kde jsou dnes ty pomalejší).

Na udávaných 14 000 MB/s možná Viper PD573 bude dokonce potřebovat čipy, jaké ještě nejsou na trhu (rychlost 4800 MT/s), takže je možné, že tyto moduly jsou ještě dost daleko od vydání, ačkoliv je již Patriot ukazuje.

Řadič Maxio MAP1802 samotný má podle výrobce limity ještě o trošku výš. Když se spáruje s NAND s rychlostí komunikace 4800 MT/s, má dosáhnout až 14,4 GB/s a výkon v náhodném přístupu má být až 3,4 milionu IOPS při čtení a 3,5 milionu IOPS zápisu. Zde ale asi bude dobré si počkat na reálné testy reálných SSD, je možné, že výrobce udává optimistická čísla pro nereálné scénáře a jeho IOPS nelze úplně srovnávat s tím, co slibuje Silicon Motion nebo Phison.

První SSD s řadičem Phison E31T

I Phison samotný jinak má na cestě nový řadič, který by měl být chladnější a úpornější. Není to nicméně highendový řadič, ale mainstreamový čtyřkanálový Phison E31T vyráběný 7nm procesem pro DRAMless SSD. Ten již byl oznámený dříve, ale není s ním už patrně přichází první SSD.

MSI Spatium M560

MSI Spatium M560

Autor: MSI

MSI předvádělo na Computexu první moduly s tímto řadičem, pojmenované MSI Spatium M560. Ač používají jen takovýto úspornější řadič, mají dosahovat rychlosti čtení a zápisu až 10 GB/s. Tyto moduly budou nabízené v kapacitě 1 TB a 2 TB a mohlo by jít o výhodnou volbu, kdy rychlosti budou vyšší než u SSD založených na PCIe 4.0 ×4, ale snad by to nemělo být za nějaký velký příplatek.

Phison E31T přinese úsporná a levná PCIe 5.0 SSD. Přitom budou rychlejší než dnešní highend Přečtěte si také:

Phison E31T přinese úsporná a levná PCIe 5.0 SSD. Přitom budou rychlejší než dnešní highend

S InnoGritem už pět značek

Dalším kandidátem do sbírky PCIe 5.0 řadičů je pak už delší dobu InnoGrit IG5666. O tom už se ví delší dobu, nějaké větší rozšíření mu ale také, zdá se, trvá. Má být například v modulu Adata Legend 970 Pro také oznámeném na Computexu 2024.

bitcoin_smenarna

Navíc firmy jako Samsung, Hynix a Western Digital budou mít řadiče vlastní, takže do roka by mohl trh PCIe 5.0 SSD být nesrovnatelně pestřejší a celkově by tato SSD měla nabízet dostupnější a také více kultivované modely.

Do PCIe 5.0 SSD přichází nový řadič InnoGrit, rychlost modulů dosáhne až na 14,3 GB/s Přečtěte si také:

Do PCIe 5.0 SSD přichází nový řadič InnoGrit, rychlost modulů dosáhne až na 14,3 GB/s

První PCIe 5.0 disk od Samsungu: SSD 990 Evo umí hybridně PCIe 5.0 ×2 nebo 4.0 ×4 (update) Přečtěte si také:

První PCIe 5.0 disk od Samsungu: SSD 990 Evo umí hybridně PCIe 5.0 ×2 nebo 4.0 ×4 (update)

Konečně PCIe 5.0 SSD, které nepeče? Hynix Platinum P51 má nový, zcela vlastní řadič a dá až 13,5 GB/s Přečtěte si také:

Konečně PCIe 5.0 SSD, které nepeče? Hynix Platinum P51 má nový, zcela vlastní řadič a dá až 13,5 GB/s

Zdroje: AnandTech (1, 2), Tom’s Hardware, Silicon Motion

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 »