{"id":89303,"date":"2020-07-22T01:42:30","date_gmt":"2020-07-21T23:42:30","guid":{"rendered":"https:\/\/prohoster.info\/blog\/administrirovanie\/oblachnyj-gejming-s-otkrytym-ishodnym-kodom-na-webrtc-p2p-multipleer-zero-latency"},"modified":"2020-07-22T01:42:30","modified_gmt":"2020-07-21T23:42:30","slug":"oblachnyj-gejming-s-otkrytym-ishodnym-kodom-na-webrtc-p2p-multipleer-zero-latency","status":"publish","type":"post","link":"https:\/\/prohoster.info\/sv\/blog\/administrirovanie\/oblachnyj-gejming-s-otkrytym-ishodnym-kodom-na-webrtc-p2p-multipleer-zero-latency","title":{"rendered":"\u00d6ppen k\u00e4llkod molngaming med WebRTC: p2p, multiplayer, zero latency","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p><noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/Voximplant\/blog\/511626\/\"><img decoding=\"async\" alt=\"\u00d6ppen k\u00e4llkod molngaming med WebRTC: p2p, multiplayer, zero latency\" src=\"\/wp-content\/uploads\/2020\/07\/22dbf7665d7fded15671d98a2afe599b.png\" style=\"display:block;margin: 0 auto;\" \/><\/a><\/noindex><br \/>\nProgramvara som tj\u00e4nst, infrastruktur som tj\u00e4nst, plattform som tj\u00e4nst, kommunikationsplattform som tj\u00e4nst, videokonferenser som tj\u00e4nst, men vad s\u00e4gs om molngaming som tj\u00e4nst? Det har redan gjorts flera f\u00f6rs\u00f6k att skapa molngaming (Cloud Gaming), som till exempel Stadia, nyligen lanserad av Google. Stadia <noindex><a rel=\"nofollow\" href=\"https:\/\/youtu.be\/avtlQeaxd_I?t=440\">\u00e4r inte ny inom WebRTC<\/a><\/noindex>, men kan andra anv\u00e4nda WebRTC p\u00e5 samma s\u00e4tt?<noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><\/p>\n<p>Thanh Nguyen beslutade att unders\u00f6ka denna m\u00f6jlighet i sitt \u00f6ppen k\u00e4llkodsprojekt CloudRetro. CloudRetro \u00e4r baserat p\u00e5 Pion, <noindex><a rel=\"nofollow\" href=\"https:\/\/webrtchacks.com\/webrtc-open-source-most-popular\/\">en popul\u00e4r<\/a><\/noindex> WebRTC-bibliotek byggt p\u00e5 Go (tack <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/Sean-Der\">Sean<\/a><\/noindex> fr\u00e5n Pion-utvecklargruppen f\u00f6r hj\u00e4lpen med att f\u00f6rbereda denna artikel). I denna artikel ger Thanh en \u00f6versikt \u00f6ver arkitekturen av sitt projekt och ber\u00e4ttar vad han har l\u00e4rt sig och vilka utmaningar han har st\u00f6tt p\u00e5 under arbetets g\u00e5ng.<\/p>\n<h2>Inledning<\/h2>\n<p>\nF\u00f6rra \u00e5ret, n\u00e4r Google tillk\u00e4nnagav Stadia, blev jag helt exalterad. Id\u00e9n \u00e4r s\u00e5 unik och innovativ att jag st\u00e4ndigt funderade p\u00e5 hur n\u00e5got s\u00e5dant \u00f6verhuvudtaget \u00e4r m\u00f6jligt med de nuvarande teknologierna. En \u00f6nskan att f\u00f6rst\u00e5 detta b\u00e4ttre ledde mig till att skapa min egen version av molngaming med \u00f6ppen k\u00e4llkod. Resultatet var helt fantastiskt. Nedan vill jag dela med mig av processen bakom mitt ett\u00e5riga <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/giongto35\/cloud-game\">projekt<\/a><\/noindex>.<\/p>\n<p><i>TLDR: kort sammanfattning med huvudpunkterna<\/i><\/p>\n<h3>Varf\u00f6r molngaming \u00e4r framtiden<\/h3>\n<p>\nJag tror att molngaming snart kommer att bli den nya generationen av inte bara spel, utan \u00e4ven inom andra omr\u00e5den av datavetenskap. Molngaming \u00e4r toppen av klient\/server-modellen. Denna modell maximerar backend-hantering och minimerar frontend-arbetet genom att placera spel-logiken p\u00e5 en fj\u00e4rrserver och streama bilder\/ljud till klienten. Servern utf\u00f6r den tunga bearbetningen, s\u00e5 klienten l\u00e4ngre \u00e4r beroende av h\u00e5rdvarubegr\u00e4nsningar.<\/p>\n<p>Google Stadia till\u00e5ter i praktiken att spela <noindex><a rel=\"nofollow\" href=\"https:\/\/ru.wikipedia.org\/wiki\/AAA_(%D0%BA%D0%BE%D0%BC%D0%BF%D1%8C%D1%8E%D1%82%D0%B5%D1%80%D0%BD%D1%8B%D0%B5_%D0%B8%D0%B3%D1%80%D1%8B)\">AAA-spel<\/a><\/noindex> (dvs. h\u00f6gklassiga blockbuster-spel) p\u00e5 en plattform liknande YouTube. Samma metodik kan till\u00e4mpas p\u00e5 andra tunga offline-applikationer, som operativsystem eller 2D\/3D grafikdesign etc., s\u00e5 att vi kan k\u00f6ra dem stabilt p\u00e5 l\u00e5gt specifikationsutrustning p\u00e5 olika plattformar.<\/p>\n<p><img decoding=\"async\" alt=\"\u00d6ppen k\u00e4llkod molngaming med WebRTC: p2p, multiplayer, zero latency\" src=\"\/wp-content\/uploads\/2020\/07\/d6ca3e47db5c8e3d9880b304cc3be33b.png\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nFramtiden f\u00f6r denna teknik: f\u00f6rest\u00e4ll dig att Microsoft Windows 10 skulle fungera i webbl\u00e4saren Chrome?<\/p>\n<h3>Molnspel \u00e4r tekniskt utmanande<\/h3>\n<p>\nGaming \u00e4r ett av de s\u00e4llsynta omr\u00e5dena d\u00e4r konstant snabb respons fr\u00e5n anv\u00e4ndaren kr\u00e4vs. Om vi ibland har en f\u00f6rdr\u00f6jning p\u00e5 2 sekunder n\u00e4r vi klickar p\u00e5 en sida, \u00e4r det acceptabelt. Livestr\u00f6mmar ligger vanligtvis efter med n\u00e5gra sekunder, men erbjuder \u00e4nd\u00e5 tillr\u00e4cklig anv\u00e4ndarv\u00e4nlighet. Men om ett spel ofta laggar med 500 ms, \u00e4r det helt enkelt om\u00f6jligt att spela. V\u00e5rt m\u00e5l \u00e4r att uppn\u00e5 extremt l\u00e5g latens s\u00e5 att skillnaden mellan input och media \u00e4r s\u00e5 liten som m\u00f6jligt. D\u00e4rf\u00f6r \u00e4r den traditionella metoden f\u00f6r videostreaming h\u00e4r inte till\u00e4mplig.<\/p>\n<p><img decoding=\"async\" alt=\"\u00d6ppen k\u00e4llkod molngaming med WebRTC: p2p, multiplayer, zero latency\" src=\"\/wp-content\/uploads\/2020\/07\/d73765a3c9277c026f407883e1091473.png\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nDen \u00f6vergripande mallen f\u00f6r molnspel<\/p>\n<h2>Open source-projektet CloudRetro<\/h2>\n<p>\nJag beslutade att skapa ett testexempel p\u00e5 molnspel f\u00f6r att se om allt detta \u00e4r m\u00f6jligt under s\u00e5dana strikta n\u00e4tverksbegr\u00e4nsningar. F\u00f6r konceptets test valde jag Golang eftersom det \u00e4r det spr\u00e5k jag \u00e4r mest bekant med och passade v\u00e4l f\u00f6r denna implementering av m\u00e5nga andra sk\u00e4l, som senare visade sig. Go \u00e4r enkelt och utvecklas v\u00e4ldigt snabbt; kanaler i Go \u00e4r utm\u00e4rkta f\u00f6r att hantera flertr\u00e5dighet.<\/p>\n<p>Projektet <noindex><a rel=\"nofollow\" href=\"http:\/\/cloudretro.io\/\">CloudRetro.io<\/a><\/noindex> \u2013 en molnbaserad speltj\u00e4nst med \u00f6ppen k\u00e4llkod f\u00f6r retrospel. Projektets m\u00e5l \u00e4r att ge traditionella retrospel en s\u00e5 bekv\u00e4m spelupplevelse som m\u00f6jligt och att l\u00e4gga till flerspelarl\u00e4ge.<br \/>\nDu kan bekanta dig med projektet h\u00e4r: <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/giongto35\/cloud-game\">https:\/\/github.com\/giongto35\/cloud-game<\/a><\/noindex>.<\/p>\n<h3>Funktionalitet f\u00f6r CloudRetro<\/h3>\n<p>\nF\u00f6r att visa hela kraften i molnspel anv\u00e4nds retrospel i CloudRetro. Detta g\u00f6r att man kan f\u00e5 en m\u00e4ngd unika spelupplevelser.<\/p>\n<ul>\n<li>Spelbarhet\n<ul>\n<li>Omedelbar spelstart vid \u00f6ppning av sidan; ingen nedladdning eller installation beh\u00f6vs<\/li>\n<li>Fungerar i mobilwebbl\u00e4sare, s\u00e5 ingen programvara beh\u00f6vs f\u00f6r att k\u00f6ra det<\/li>\n<\/ul>\n<p>\n<\/li>\n<li>Spelsessioner kan delas mellan flera enheter och lagras i molnet f\u00f6r n\u00e4sta inloggning<\/li>\n<li>Spelet kan streamas, och flera anv\u00e4ndare kan spela det direkt:\n<ul>\n<li>Crowdplay \u00e0 la TwitchPlayPokemon, bara mer plattforms\u00f6vergripande och mer realtidsanpassat<\/li>\n<li>Offlinespel online. M\u00e5nga anv\u00e4ndare kan spela utan n\u00e4tverksinst\u00e4llningar. I Samurai Shodown kan nu 2 spelare spela \u00f6ver CloudRetro-n\u00e4tverket<\/li>\n<\/ul>\n<p>\n<img decoding=\"async\" alt=\"\u00d6ppen k\u00e4llkod molngaming med WebRTC: p2p, multiplayer, zero latency\" src=\"\/wp-content\/uploads\/2020\/07\/bdc715971755d669a026f830ce888520.png\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nDemoversion av ett flerspelarl\u00e4ge online-spel p\u00e5 olika enheter<\/p>\n<h2>Infrastruktur<\/h2>\n<p><\/p>\n<h3>Krav och teknologiska stackar<\/h3>\n<p>\nNedanf\u00f6r finns en lista \u00f6ver krav som jag satte innan projektet startade.<\/p>\n<p><b>1. En spelare<\/b><br \/>\nDetta krav kan verka oviktigt och uppenbart h\u00e4r, men det \u00e4r en av mina centrala insikter, det g\u00f6r att molnspel kan h\u00e5lla sig s\u00e5 l\u00e5ngt borta fr\u00e5n traditionella str\u00f6mningstj\u00e4nster som m\u00f6jligt. Om vi fokuserar p\u00e5 enspelarl\u00e4gen kan vi undvika behovet av en centraliserad server eller CDN, eftersom vi inte beh\u00f6ver s\u00e4nda till massorna. Ist\u00e4llet f\u00f6r att ladda upp str\u00f6mmar till en mottagande server eller skicka paket till en centraliserad WebSocket-server, \u00f6verf\u00f6rs tj\u00e4nstestreamar direkt till anv\u00e4ndarna genom en peer-to-peer WeRTC-anslutning.<\/p>\n<p><b>2. L\u00e5g latens mediastreaming<\/b><br \/>\nN\u00e4r jag l\u00e4ser om Stadia st\u00f6ter jag ofta p\u00e5 n\u00e4mningar av WebRTC i vissa artiklar. Jag har f\u00f6rst\u00e5tt att WebRTC \u00e4r en lysande teknologi, och den passar perfekt f\u00f6r anv\u00e4ndning inom molnspel. WebRTC \u00e4r ett projekt som erbjuder webbl\u00e4sare och mobilapplikationer realtidskommunikation via ett enkelt API. Det m\u00f6jligg\u00f6r en peer-to-peer-anslutning, optimerad f\u00f6r media och har inbyggda standardkodekar som VP8 och H264.<\/p>\n<p>Jag prioriterade att s\u00e4kerst\u00e4lla en s\u00e5 bekv\u00e4m anv\u00e4ndarupplevelse som m\u00f6jligt, snarare \u00e4n att bevara h\u00f6g grafik. Vissa f\u00f6rluster \u00e4r acceptabla i algoritmen. Google Stadia har ett extra steg f\u00f6r att minska bildstorleken p\u00e5 servern, och bilderna skalas upp till h\u00f6gre kvalitet innan de \u00f6verf\u00f6rs till peer-noder.<\/p>\n<p><b>3. Distribuerad infrastruktur med geografisk routing<\/b><br \/>\nOavsett hur optimerad komprimeringsalgoritmen och koden \u00e4r, \u00e4r n\u00e4tverket fortfarande den avg\u00f6rande faktorn som mest bidrar till latens. Arkitekturen m\u00e5ste ha en mekanism f\u00f6r att koppla ihop den server som \u00e4r n\u00e4rmast anv\u00e4ndaren f\u00f6r att minska \u00f6verf\u00f6ringstiden (RTT). Arkitekturen b\u00f6r ha en koordinator och flera streamingservrar spridda \u00f6ver hela v\u00e4rlden: v\u00e4stra USA, \u00f6stra USA, Europa, Singapore, Kina. Alla streamingservrar m\u00e5ste vara helt isolerade. Systemet kan justera sin distribution n\u00e4r en server g\u00e5r med i n\u00e4tverket eller l\u00e4mnar det. P\u00e5 s\u00e5 s\u00e4tt, vid h\u00f6g trafik, g\u00f6r ytterligare servrar det m\u00f6jligt att utf\u00f6ra horisontell skalning.<\/p>\n<p><b>4. webbl\u00e4sarkompatibilitet<\/b><br \/>\nMolnspel framtr\u00e4der i b\u00e4sta ljus n\u00e4r de kr\u00e4ver minimalt av anv\u00e4ndarna. Detta betyder att det finns m\u00f6jlighet att spela direkt i webbl\u00e4saren. Webbl\u00e4sare hj\u00e4lper till att g\u00f6ra spelupplevelsen s\u00e5 bekv\u00e4m som m\u00f6jligt f\u00f6r anv\u00e4ndarna, utan att de beh\u00f6ver installera programvara eller h\u00e5rdvara. Webbl\u00e4sare hj\u00e4lper ocks\u00e5 till att s\u00e4kerst\u00e4lla plattformsoberoende f\u00f6r mobila och desktopversioner. Lyckligtvis st\u00f6ds WebRTC utm\u00e4rkt i olika webbl\u00e4sare.<\/p>\n<p><b>5. Tydlig separation av spelgr\u00e4nssnitt och tj\u00e4nst<\/b><br \/>\nJag betraktar molnspeltj\u00e4nsten som en plattform. Varje anv\u00e4ndare ska kunna ansluta vad som helst till plattformen. Just nu har jag integrerat <noindex><a rel=\"nofollow\" href=\"http:\/\/LibRetro\">LibRetro<\/a><\/noindex> med molnspeltj\u00e4nsten, eftersom LibRetro erbjuder ett vackert gr\u00e4nssnitt f\u00f6r spelemulatorer f\u00f6r retrospel som SNES, GBA, PS.<\/p>\n<p><b>6. Rum f\u00f6r flerspelare, crowd play och djup-l\u00e4nkar (deep-link) till spelet<\/b><br \/>\nCloudRetro st\u00f6der m\u00e5nga nya spelupplevelser, s\u00e5som CrowdPlay och Online Multiplayer f\u00f6r retrospel. Om flera anv\u00e4ndare \u00f6ppnar samma djup-l\u00e4nk p\u00e5 olika datorer, kommer de att se samma p\u00e5g\u00e5ende spel och till och med kunna g\u00e5 med i det.<\/p>\n<p>Dessutom lagras spelens tillst\u00e5nd i molnlagring. Detta g\u00f6r att anv\u00e4ndare kan forts\u00e4tta spela n\u00e4r som helst p\u00e5 vilken annan enhet som helst.<\/p>\n<p><b>7. Horisontell skalning<\/b><br \/>\nPrecis som alla SAAS-tj\u00e4nster m\u00e5ste molnspel idag utformas f\u00f6r att vara horisontellt skalbara. Designen \"koordinator-arbetare\" g\u00f6r det m\u00f6jligt att l\u00e4gga till fler arbetare f\u00f6r att hantera h\u00f6gre trafik.<\/p>\n<p><b>8. Ingen bindning till ett enda moln<\/b><br \/>\nInfrastructure CloudRetro finns p\u00e5 olika molnleverant\u00f6rer (Digital Ocean, Alibaba, anpassad leverant\u00f6r) f\u00f6r olika regioner. Jag aktiverar containerdrift med Docker f\u00f6r infrastrukturen och konfigurerar n\u00e4tverksinst\u00e4llningarna med hj\u00e4lp av bash-skript f\u00f6r att undvika beroende av en enda molnleverant\u00f6r. Genom att kombinera detta med NAT Traversal i WebRTC kan vi uppn\u00e5 flexibilitet f\u00f6r att distribuera CloudRetro p\u00e5 vilken molnplattform som helst och till och med p\u00e5 anv\u00e4ndarmaskiner.<\/p>\n<h3>Arkitekturdesign<\/h3>\n<p>\n<b>Arbetare:<\/b> (eller str\u00f6mserver, som n\u00e4mnts ovan) multiplicerar spelen, k\u00f6r den kodande pipeline och \u00f6verf\u00f6r den kodade media till anv\u00e4ndarna. Instanser av arbetaren \u00e4r spridda \u00f6ver hela v\u00e4rlden, och varje arbetare kan hantera flera anv\u00e4ndarsessioner samtidigt.<\/p>\n<p><b>Koordinator:<\/b> ansvarar f\u00f6r att koppla en ny anv\u00e4ndare till den mest l\u00e4mpliga arbetaren f\u00f6r str\u00f6mning. Koordinatorn interagerar med arbetarna via WebSocket.<\/p>\n<p><b>Lagring av speltillst\u00e5nd:<\/b> ett centralt fj\u00e4rrlager f\u00f6r alla spelets tillst\u00e5nd. Detta lager tillhandah\u00e5ller viktiga funktioner, s\u00e5som fj\u00e4rrspara\/ladda.<\/p>\n<p><img decoding=\"async\" alt=\"\u00d6ppen k\u00e4llkod molngaming med WebRTC: p2p, multiplayer, zero latency\" src=\"\/wp-content\/uploads\/2020\/07\/985447b81350a640b0bd1344b5705113.png\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n\u00d6versiktlig arkitektur f\u00f6r CloudRetro<\/p>\n<h3>Anv\u00e4ndarscenario<\/h3>\n<p>\nN\u00e4r en ny anv\u00e4ndare \u00f6ppnar CloudRetro i steg 1 och 2, som visas nedan, beg\u00e4rs koordinatorn tillsammans med en lista \u00f6ver tillg\u00e4ngliga arbetare p\u00e5 f\u00f6rsta sidan. D\u00e4refter, i steg 3, ber\u00e4knar klienten f\u00f6rdr\u00f6jningarna f\u00f6r alla kandidater med hj\u00e4lp av en HTTP ping-f\u00f6rfr\u00e5gan. Denna lista med f\u00f6rdr\u00f6jningar skickas sedan tillbaka till koordinatorn s\u00e5 att denne kan avg\u00f6ra den mest l\u00e4mpliga arbetaren f\u00f6r att betj\u00e4na anv\u00e4ndaren. I steg 4 nedan skapats ett spel. En str\u00f6mf\u00f6rbindelse via WebRTC etableras mellan anv\u00e4ndaren och den tilldelade arbetaren.<br \/>\n<img decoding=\"async\" alt=\"\u00d6ppen k\u00e4llkod molngaming med WebRTC: p2p, multiplayer, zero latency\" src=\"\/wp-content\/uploads\/2020\/07\/00199b5942e3e4314609ec0e70ea7162.png\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nAnv\u00e4ndarscenario efter \u00e5tkomst<\/p>\n<h3>Vad finns inuti arbetaren<\/h3>\n<p>\nSpel- och streamingspipeline lagras isolerat inom workern och utbyter information d\u00e4r genom ett gr\u00e4nssnitt. F\u00f6r n\u00e4rvarande sker denna koppling genom att \u00f6verf\u00f6ra data i minnet via <noindex><a rel=\"nofollow\" href=\"https:\/\/tour.golang.org\/concurrency\/2\">Golang-kanaler<\/a><\/noindex> i samma process. N\u00e4sta m\u00e5l \u00e4r segmentering, dvs. oberoende k\u00f6rning av spelet i en annan process.<\/p>\n<p><img decoding=\"async\" alt=\"\u00d6ppen k\u00e4llkod molngaming med WebRTC: p2p, multiplayer, zero latency\" src=\"\/wp-content\/uploads\/2020\/07\/7a90ec2638344467a34604cd4322165c.png\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nInteraktionen mellan workerkomponenter<\/p>\n<p>Huvudkomponenter:<\/p>\n<ul>\n<li><b>WebRTC:<\/b> klientkomponenten som tar emot anv\u00e4ndarinmatning och skickar kodad media fr\u00e5n servern.\n<\/li>\n<li><b>Spelemuator:<\/b> spelskomponenten. Tack vare biblioteket Libretro kan systemet k\u00f6ra spelet inom samma process och internt f\u00e5nga media och indatafl\u00f6de.\n<\/li>\n<li>In-game frames f\u00e5ngas och skickas till kodaren.\n<\/li>\n<li><b>Bild-\/ljudkodare:<\/b> kodningspipeline som tar emot mediaprogram, kodar dem i bakgrunden och skickar ut kodade bilder\/ljud.\n<\/li>\n<\/ul>\n<p><\/p>\n<h2>Implementering<\/h2>\n<p>\nCloudRetro f\u00f6rlitar sig p\u00e5 WebRTC som en huvudteknologi, s\u00e5 innan jag dyker djupare in i implementeringen i Golang, ville jag ber\u00e4tta om sj\u00e4lva WebRTC. Det \u00e4r en fantastisk teknik som har hj\u00e4lpt mig att uppn\u00e5 en datastreamingf\u00f6rdr\u00f6jning p\u00e5 endast en br\u00e5kdel av en sekund.<\/p>\n<h3>WebRTC<\/h3>\n<p>\nWebRTC \u00e4r designat f\u00f6r att s\u00e4kerst\u00e4lla h\u00f6gkvalitativa peer-to-peer-anslutningar i inbyggda mobilapplikationer och webbl\u00e4sare med hj\u00e4lp av enkla API:er.<\/p>\n<h4>NAT Traversal <\/h4>\n<p>\nWebRTC \u00e4r k\u00e4nt f\u00f6r sin funktionalitet NAT Traversal. WebRTC \u00e4r avsett f\u00f6r peer-to-peer-kommunikation. Dess syfte \u00e4r att hitta den mest l\u00e4mpliga direkta v\u00e4gen, undvika NAT-gateways och brandv\u00e4ggar f\u00f6r peer-to-peer-kommunikation genom en process som kallas <noindex><a rel=\"nofollow\" href=\"https:\/\/webrtchacks.com\/trickle-ice\/\">ICE<\/a><\/noindex>. Inom ramen f\u00f6r denna process hittar WebRTC API din offentliga IP-adress med hj\u00e4lp av STUN-servrar och omdirigerar den till en retransmission server (<noindex><a rel=\"nofollow\" href=\"https:\/\/webrtchacks.com\/?s=turn\">TURN<\/a><\/noindex>), n\u00e4r en direkt anslutning inte kan etableras.<\/p>\n<p>Men CloudRetro utnyttjar inte helt denna funktion. Dess peer-to-peer-anslutningar existerar inte mellan anv\u00e4ndare, utan mellan anv\u00e4ndare och molnservrar. Serverdelen av modellen har f\u00e4rre begr\u00e4nsningar f\u00f6r direkt kommunikation \u00e4n vanliga anv\u00e4ndarenheter. Detta g\u00f6r det m\u00f6jligt att f\u00f6rhands\u00f6ppna inkommande portar eller anv\u00e4nda offentliga IP-adresser direkt, eftersom servern inte ligger bakom NAT.<\/p>\n<p>Tidigare ville jag f\u00f6rvandla projektet till en plattform f\u00f6r spridning av spel f\u00f6r Cloud Gaming. Id\u00e9n var att l\u00e5ta spelutvecklare tillhandah\u00e5lla spel och str\u00f6mresurser. Anv\u00e4ndarna skulle interagera direkt med leverant\u00f6rerna. I ett s\u00e5dant decentraliserat format \u00e4r CloudRetro bara en plattform f\u00f6r att koppla externa str\u00f6mresurser till anv\u00e4ndarna, vilket g\u00f6r det mer skalbart n\u00e4r det inte l\u00e4ngre har hosting p\u00e5 sig. Rollen av WebRTC NAT Traversal \u00e4r mycket viktig f\u00f6r att underl\u00e4tta initieringen av en peer-to-peer-anslutning p\u00e5 externa str\u00f6mresurser, vilket f\u00f6renklar kopplingen av skaparen till n\u00e4tverket.<\/p>\n<h4>Videokomprimering<\/h4>\n<p>\nVideokomprimering \u00e4r en oumb\u00e4rlig del av pipeline som i h\u00f6g grad bidrar till smidigheten i str\u00f6mningen. \u00c4ven om det inte \u00e4r n\u00f6dv\u00e4ndigt att k\u00e4nna till alla detaljer om videokodning i VP8\/H264, s\u00e5 hj\u00e4lper f\u00f6rst\u00e5elsen av konceptet att hantera inst\u00e4llningarna f\u00f6r str\u00f6mmande video, fels\u00f6ka ov\u00e4ntat beteende och justera latens.<\/p>\n<p>Videokomprimering f\u00f6r en str\u00f6mningstj\u00e4nst \u00e4r en komplex uppgift eftersom algoritmen m\u00e5ste garantera att den totala kodningstiden + \u00f6verf\u00f6ringstid + avkodningstid \u00e4r s\u00e5 liten som m\u00f6jligt. Dessutom m\u00e5ste kodningsprocessen vara konsekvent och kontinuerlig. Vissa \u00f6msesidiga uppoffringar vid kodning \u00e4r inte till\u00e4mpliga \u2013 till exempel kan vi inte f\u00f6redra en l\u00e5ng kodningstid framf\u00f6r en mindre filstorlek och avkodningstid, eller anv\u00e4nda inkonsekvent komprimering.<\/p>\n<p>Id\u00e9n med videokomprimering \u00e4r att utesluta on\u00f6diga bitar information och samtidigt beh\u00e5lla en acceptabel noggrannhetsniv\u00e5 f\u00f6r anv\u00e4ndarna. F\u00f6rutom att koda individuella stillbilder, g\u00f6r algoritmen slutsatser f\u00f6r den aktuella bilden baserat p\u00e5 f\u00f6reg\u00e5ende och n\u00e4sta bild, s\u00e5 att endast deras skillnader s\u00e4nds. Som visas i exemplet med Pacman, skickas endast de differenspunkterna.<\/p>\n<p><img decoding=\"async\" alt=\"\u00d6ppen k\u00e4llkod molngaming med WebRTC: p2p, multiplayer, zero latency\" src=\"\/wp-content\/uploads\/2020\/07\/e452c54c53ab7797b610620aefbba8d2.png\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nJ\u00e4mf\u00f6relse av videobilder med Pacman-exemplet<\/p>\n<h4>Ljudkomprimering<\/h4>\n<p>\nP\u00e5 samma s\u00e4tt hoppar ljudkomprimeringsalgoritmen \u00f6ver data som inte kan uppfattas av m\u00e4nniskan. Opus \u00e4r f\u00f6r n\u00e4rvarande ljudkodeken med den b\u00e4sta prestandan. Den \u00e4r utformad f\u00f6r att skicka ljudv\u00e5gor \u00f6ver protokoll f\u00f6r ordnad datagram, s\u00e5som RTP (Real Time Transport Protocol \u2013 protokoll f\u00f6r realtids\u00f6verf\u00f6ring av trafik). Den har l\u00e4gre f\u00f6rdr\u00f6jning \u00e4n mp3 och aac, och kvaliteten \u00e4r h\u00f6gre. F\u00f6rdr\u00f6jningen ligger vanligtvis runt 5~66,5 ms.<\/p>\n<h4>Pion, WebRTC i Golang<\/h4>\n<p>\n<noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/pion\/webrtc\">Pion<\/a><\/noindex> \u00e4r ett open source-projekt som implementerar WebRTC i Golang. Ist\u00e4llet f\u00f6r att vanligtvis kapsla in native C++ WebRTC-bibliotek \u00e4r Pion en nativ Golang-implementation av WebRTC med b\u00e4ttre prestanda, integration med Go och versionskontroll av WebRTC-protokoll.<\/p>\n<p>Biblioteket erbjuder ocks\u00e5 datastreaming med m\u00e5nga utm\u00e4rkta inbyggda moduler med en f\u00f6rdr\u00f6jning p\u00e5 mindre \u00e4n en sekund. Det har sin egen implementation av STUN, DTLS, SCTP, etc., och vissa experiment med QUIC och WebAssembly. Sj\u00e4lva denna open source-bibliotek \u00e4r verkligen en bra l\u00e4randek\u00e4lla med utm\u00e4rkt dokumentation, implementation av n\u00e4tverksprotokoll och intressanta exempel.<\/p>\n<p>Pion-communityt, lett av en mycket passionerad skapare, \u00e4r ganska livligt, och det p\u00e5g\u00e5r m\u00e5nga kvalitativa diskussioner om WebRTC. Om du \u00e4r intresserad av den h\u00e4r teknologin, g\u00e5 med i <noindex><a rel=\"nofollow\" href=\"http:\/\/pion.ly\/slack\">http:\/\/pion.ly\/slack<\/a><\/noindex> \u2013 du kommer att l\u00e4ra dig mycket nytt.<\/p>\n<h3>Att skriva CloudRetro i Golang<\/h3>\n<p>\n<img decoding=\"async\" alt=\"\u00d6ppen k\u00e4llkod molngaming med WebRTC: p2p, multiplayer, zero latency\" src=\"\/wp-content\/uploads\/2020\/07\/f85f7b8ea579fab964d870aad698c7e7.png\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nImplementering av en arbetsprocess i Go<\/p>\n<h4>Go-kanaler i praktiken<\/h4>\n<p>\nMed den eleganta designen av Go-kanaler f\u00f6renklas problem med h\u00e4ndelsestr\u00f6mning och parallellitet avsev\u00e4rt. Som p\u00e5 diagrammet arbetar flera komponenter parallellt i olika GoRoutines. Varje komponent hanterar sitt tillst\u00e5nd och kommunicerar via kanaler. Go:s selektiva p\u00e5st\u00e5ende tvingar varje atom\u00e4r h\u00e4ndelse att hanteras vid varje given tidpunkt i spelet (game tick). Det betyder att en s\u00e5dan design inte kr\u00e4ver l\u00e5sning. Till exempel, n\u00e4r en anv\u00e4ndare sparar, kr\u00e4vs en fullst\u00e4ndig snapshot av spelets tillst\u00e5nd. Detta tillst\u00e5nd m\u00e5ste f\u00f6rbli kontinuerligt under inloggningen tills sparandet \u00e4r slutf\u00f6rt. Under varje game tick kan backend endast bearbeta antingen sparande- eller inloggningsoperationer, vilket g\u00f6r processen tr\u00e5ds\u00e4ker.<\/p>\n<pre><code class=\"go\">func (e *gameEmulator) gameUpdate() {\nfor {\n\tselect {\n\t\tcase &lt;-e.saveOperation:\n\t\t\te.saveGameState()\n\t\tcase key := &lt;-e.input:\n\t\t\te.updateGameState(key)\n\t\tcase &lt;-e.done:\n\t\t\te.close()\n\t\t\treturn\n\t}\n    }\n}<\/code><\/pre>\n<p><\/p>\n<h4>Fan-in \/ Fan-out<\/h4>\n<p>\nDenna Golang-mall passar perfekt f\u00f6r mitt anv\u00e4ndningsfall med CrowdPlay och flera spelare. Genom att f\u00f6lja denna mall samlas all anv\u00e4ndarinmatning i ett rum i en central ing\u00e5ngskanal. Spelmedia distribueras sedan till alla anv\u00e4ndare i rummet. P\u00e5 s\u00e5 s\u00e4tt uppn\u00e5r vi delning av speltillst\u00e5nd mellan flera spel-sessioner av olika anv\u00e4ndare.<\/p>\n<p><img decoding=\"async\" alt=\"\u00d6ppen k\u00e4llkod molngaming med WebRTC: p2p, multiplayer, zero latency\" src=\"\/wp-content\/uploads\/2020\/07\/000a495d7f214246a8a396aab11a3ac5.png\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nSynkronisering mellan olika sessioner<\/p>\n<h4>Nackdelar med Golang<\/h4>\n<p>\nGolang \u00e4r inte perfekt. Kanaler \u00e4r l\u00e5ngsamma. J\u00e4mf\u00f6rt med l\u00e5s \u00e4r Go-kanaler ett enklare s\u00e4tt att hantera parallella och str\u00f6mmade h\u00e4ndelser, men kanalen ger inte den b\u00e4sta prestandan. Under kanalen finns en komplicerad l\u00e5slogik. D\u00e4rf\u00f6r har jag gjort vissa justeringar i implementationen genom att \u00e5teranv\u00e4nda l\u00e5s och atom\u00e4ra v\u00e4rden f\u00f6r att optimera prestanda.<\/p>\n<p>Dessutom \u00e4r garbage collectorn i Golang okontrollerad, vilket ibland leder till misst\u00e4nkt l\u00e5nga pauser. Detta st\u00f6r starkt driften av realtidsapplikationer.<\/p>\n<h4>CGO<\/h4>\n<p>\nProjektet anv\u00e4nder ett befintligt VP8\/H264-bibliotek i Golang med \u00f6ppen k\u00e4llkod f\u00f6r komprimering av media och Libretro f\u00f6r spel-emulatorer. Alla dessa bibliotek \u00e4r helt enkelt omslag av C-biblioteket i Go med anv\u00e4ndning av <noindex><a rel=\"nofollow\" href=\"https:\/\/golang.org\/cmd\/cgo\/\">CGO<\/a><\/noindex>. N\u00e5gra av nackdelarna \u00e4r listade i <noindex><a rel=\"nofollow\" href=\"https:\/\/dave.cheney.net\/2019\/10\/06\/use-internal-packages-to-reduce-your-public-api-surface\">detta inl\u00e4gg av Dave Cheney<\/a><\/noindex>. Problematiken jag st\u00f6tte p\u00e5:<\/p>\n<ul>\n<li>of\u00f6rm\u00e5gan att f\u00e5nga krascher i CGO, \u00e4ven med hj\u00e4lp av Golang RecoveryCrash;<\/li>\n<li>of\u00f6rm\u00e5gan att identifiera flaskhalsar i prestanda n\u00e4r vi inte kan uppt\u00e4cka detaljerade problem i CGO.<\/li>\n<\/ul>\n<p><\/p>\n<h2>Slutsats<\/h2>\n<p>\nJag har n\u00e5tt mitt m\u00e5l \u2013 att f\u00f6rst\u00e5 molnbaserade speltj\u00e4nster och skapa en plattform som hj\u00e4lper mig att spela nostalgiska retrospel med mina v\u00e4nner online. Att skapa detta projekt skulle vara om\u00f6jligt utan Pion-biblioteket och Pion-gemenskapens st\u00f6d. Jag \u00e4r extremt tacksam f\u00f6r dess intensiva utveckling. De enkla API:erna som tillhandah\u00e5lls av WebRTC och Pion m\u00f6jliggjorde en smidig integration. Min f\u00f6rsta konceptbevis lanserades samma vecka, trots att jag p\u00e5 f\u00f6rhand inte k\u00e4nde till peer-to-peer-anslutningar (P2P).<\/p>\n<p>Trots integrations enkelhet \u00e4r P2P-str\u00f6mning verkligen ett mycket komplext omr\u00e5de inom datavetenskap. Det m\u00e5ste hantera komplexiteten i fler\u00e5riga n\u00e4tverksarkitekturer, s\u00e5som IP och NAT, f\u00f6r att skapa en peer-to-peer session. Under arbetet med detta projekt har jag samlat mycket v\u00e4rdefull kunskap om n\u00e4tverk och prestandaoptimering, s\u00e5 jag rekommenderar alla att prova att bygga P2P-produkter med hj\u00e4lp av WebRTC.<\/p>\n<p>CloudRetro hanterar alla anv\u00e4ndningsscenarier som jag f\u00f6rv\u00e4ntade mig, utifr\u00e5n min synvinkel som retro-gamer. Men jag tror att det finns m\u00e5nga omr\u00e5den i projektet som jag kan f\u00f6rb\u00e4ttra, s\u00e5som att g\u00f6ra n\u00e4tverket mer p\u00e5litligt och effektivt, s\u00e4kerst\u00e4lla h\u00f6gre spelgrafik eller m\u00f6jligheten att dela spel mellan anv\u00e4ndare. Jag arbetar h\u00e5rt med detta. V\u00e4nligen f\u00f6lj <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/giongto35\/cloud-game\">projekt<\/a><\/noindex> och st\u00f6d det om du gillar det.<\/li>\n<\/ul>\n<p>K\u00e4lla: <a content=\"nofollow\" rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/Voximplant\/blog\/511626\/\">habr.com<\/a> <\/p>","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"excerpt":{"rendered":"<p>\u041f\u041e \u043a\u0430\u043a \u0443\u0441\u043b\u0443\u0433\u0430, \u0438\u043d\u0444\u0440\u0430\u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u043a\u0430\u043a \u0443\u0441\u043b\u0443\u0433\u0430, \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u0430 \u043a\u0430\u043a \u0443\u0441\u043b\u0443\u0433\u0430, \u043a\u043e\u043c\u043c\u0443\u043d\u0438\u043a\u0430\u0446\u0438\u043e\u043d\u043d\u0430\u044f \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u0430 \u043a\u0430\u043a \u0443\u0441\u043b\u0443\u0433\u0430, \u0432\u0438\u0434\u0435\u043e\u043a\u043e\u043d\u0444\u0435\u0440\u0435\u043d\u0446\u0438\u0438 \u043a\u0430\u043a \u0443\u0441\u043b\u0443\u0433\u0430, \u0430 \u0447\u0442\u043e \u043d\u0430\u0441\u0447\u0435\u0442 \u043e\u0431\u043b\u0430\u0447\u043d\u044b\u0445 \u0438\u0433\u0440 \u043a\u0430\u043a \u0443\u0441\u043b\u0443\u0433\u0438? \u0423\u0436\u0435 \u0431\u044b\u043b\u043e \u043f\u0440\u0435\u0434\u043f\u0440\u0438\u043d\u044f\u0442\u043e \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043f\u043e\u043f\u044b\u0442\u043e\u043a \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u043e\u0431\u043b\u0430\u0447\u043d\u044b\u0445 \u0438\u0433\u0440 (Cloud Gaming), \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, Stadia, \u043d\u0435\u0434\u0430\u0432\u043d\u043e \u0437\u0430\u043f\u0443\u0449\u0435\u043d\u043d\u0430\u044f \u043a\u043e\u043c\u043f\u0430\u043d\u0438\u0435\u0439 Google. Stadia \u043d\u0435 \u043d\u043e\u0432\u0438\u0447\u043e\u043a \u0432 WebRTC, \u043d\u043e \u043c\u043e\u0433\u0443\u0442 \u043b\u0438 \u0434\u0440\u0443\u0433\u0438\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c WebRTC \u0442\u0430\u043a \u0436\u0435? \u0422\u0445\u0430\u043d\u044c \u041d\u0433\u0443\u0435\u043d (Thanh [&hellip;]<\/p>\n","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"author":1,"featured_media":89304,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[688],"tags":[],"class_list":["post-89303","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-administrirovanie"],"aioseo_notices":[],"aioseo_head":"\n\t\t<!-- All in One SEO 5.0.4 - aioseo.com -->\n\t<meta name=\"robots\" content=\"max-image-preview:large\" \/>\n\t<meta name=\"author\" content=\"Yuri Gagarin\"\/>\n\t<link rel=\"canonical\" href=\"https:\/\/prohoster.info\/sv\/blog\/administrirovanie\/oblachnyj-gejming-s-otkrytym-ishodnym-kodom-na-webrtc-p2p-multipleer-zero-latency\" \/>\n\t\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 5.0.4\" \/>\n\t\t<meta property=\"og:locale\" content=\"sv_SE\" \/>\n\t\t<meta property=\"og:site_name\" content=\"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b\" \/>\n\t\t<meta property=\"og:type\" content=\"article\" \/>\n\t\t<meta property=\"og:title\" content=\"\ud83e\udd47\u041e\u0431\u043b\u0430\u0447\u043d\u044b\u0439 \u0433\u0435\u0439\u043c\u0438\u043d\u0433 \u0441 \u043e\u0442\u043a\u0440\u044b\u0442\u044b\u043c \u0438\u0441\u0445\u043e\u0434\u043d\u044b\u043c \u043a\u043e\u0434\u043e\u043c \u043d\u0430 WebRTC: p2p, \u043c\u0443\u043b\u044c\u0442\u0438\u043f\u043b\u0435\u0435\u0440, zero latency | ProHoster\" \/>\n\t\t<meta property=\"og:url\" content=\"https:\/\/prohoster.info\/sv\/blog\/administrirovanie\/oblachnyj-gejming-s-otkrytym-ishodnym-kodom-na-webrtc-p2p-multipleer-zero-latency\" \/>\n\t\t<meta property=\"og:image\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:secure_url\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:width\" content=\"350\" \/>\n\t\t<meta property=\"og:image:height\" content=\"350\" \/>\n\t\t<meta property=\"article:published_time\" content=\"2020-07-21T23:42:30+00:00\" \/>\n\t\t<meta property=\"article:modified_time\" content=\"2020-07-21T23:42:30+00:00\" \/>\n\t\t<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<meta property=\"article:author\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<!-- All in One SEO -->\n\n","aioseo_head_json":{"title":"\ud83e\udd47Molngaming med \u00f6ppen k\u00e4llkod p\u00e5 WebRTC: p2p, multiplayer, zero latency | ProHoster","description":"","canonical_url":"https:\/\/prohoster.info\/sv\/blog\/administrirovanie\/oblachnyj-gejming-s-otkrytym-ishodnym-kodom-na-webrtc-p2p-multipleer-zero-latency","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"sv_SE","og:site_name":"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b","og:type":"article","og:title":"\ud83e\udd47\u041e\u0431\u043b\u0430\u0447\u043d\u044b\u0439 \u0433\u0435\u0439\u043c\u0438\u043d\u0433 \u0441 \u043e\u0442\u043a\u0440\u044b\u0442\u044b\u043c \u0438\u0441\u0445\u043e\u0434\u043d\u044b\u043c \u043a\u043e\u0434\u043e\u043c \u043d\u0430 WebRTC: p2p, \u043c\u0443\u043b\u044c\u0442\u0438\u043f\u043b\u0435\u0435\u0440, zero latency | ProHoster","og:url":"https:\/\/prohoster.info\/sv\/blog\/administrirovanie\/oblachnyj-gejming-s-otkrytym-ishodnym-kodom-na-webrtc-p2p-multipleer-zero-latency","og:image":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:secure_url":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:width":350,"og:image:height":350,"article:published_time":"2020-07-21T23:42:30+00:00","article:modified_time":"2020-07-21T23:42:30+00:00","article:publisher":"https:\/\/www.facebook.com\/prohoster","article:author":"https:\/\/www.facebook.com\/prohoster"},"aioseo_meta_data":{"post_id":"89303","title":null,"description":null,"keywords":null,"keyphrases":null,"primary_term":null,"canonical_url":null,"og_title":null,"og_description":null,"og_object_type":"default","og_image_type":"default","og_image_url":null,"og_image_width":null,"og_image_height":null,"og_image_custom_url":null,"og_image_custom_fields":null,"og_video":null,"og_custom_url":null,"og_article_section":null,"og_article_tags":null,"twitter_use_og":false,"twitter_card":"default","twitter_image_type":"default","twitter_image_url":null,"twitter_image_custom_url":null,"twitter_image_custom_fields":null,"twitter_title":null,"twitter_description":null,"schema":{"blockGraphs":[],"customGraphs":[],"default":{"data":{"Article":[],"Course":[],"Dataset":[],"FAQPage":[],"Movie":[],"Person":[],"Product":[],"ProductReview":[],"Car":[],"Recipe":[],"Service":[],"SoftwareApplication":[],"WebPage":[]},"graphName":"","isEnabled":true},"graphs":[]},"schema_type":null,"schema_type_options":null,"pillar_content":false,"robots_default":true,"robots_noindex":false,"robots_noarchive":false,"robots_nosnippet":false,"robots_nofollow":false,"robots_noimageindex":false,"robots_noodp":false,"robots_notranslate":false,"robots_max_snippet":null,"robots_max_videopreview":null,"robots_max_imagepreview":"large","priority":null,"frequency":null,"local_seo":null,"seo_analyzer_scan_date":null,"breadcrumb_settings":null,"limit_modified_date":false,"reviewed_by":null,"ai":null,"created":"2021-02-28 13:12:27","updated":"2022-09-29 13:03:06","focus_keyword":null,"additional_keywords":null,"truseo_locale":null},"gt_translate_keys":[{"key":"link","format":"url"}],"_links":{"self":[{"href":"https:\/\/prohoster.info\/sv\/wp-json\/wp\/v2\/posts\/89303","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/sv\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/sv\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/sv\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/sv\/wp-json\/wp\/v2\/comments?post=89303"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/sv\/wp-json\/wp\/v2\/posts\/89303\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/prohoster.info\/sv\/wp-json\/wp\/v2\/media\/89304"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/sv\/wp-json\/wp\/v2\/media?parent=89303"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/sv\/wp-json\/wp\/v2\/categories?post=89303"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/sv\/wp-json\/wp\/v2\/tags?post=89303"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}