Usluga kao platforma, infrastruktura kao usluga, platforma kao usluga, komunikacijska platforma kao usluga, videokonferencije kao usluga, a što kažete na oblačne igre kao uslugu? Već je bilo nekoliko pokušaja stvaranja oblačnih igara (Cloud Gaming), poput Stadije, nedavno pokrenute od strane Googlea. Stadia , ali mogu li i drugi koristiti WebRTC na sličan način?
Than Nguyen odlučio je provjeriti ovu mogućnost na svom open-source projektu CloudRetro. CloudRetro se temelji na Pionu, WebRTC biblioteci temeljnoj na Golu (hvala iz Pionovog razvojnog tima na pomoći u pripremi ovog članka). U ovom članku, Than daje pregled arhitekture svog projekta te dijeli korisne informacije i izazove na koje je naišao tijekom rada.
Uvod
Prošle godine, kada je Google najavio Stadiju, jednostavno sam bio oduševljen. Ideja je toliko jedinstvena i inovativna da sam se neprekidno pitao kako je to uopće moguće sa postojećim tehnologijama. Želja da bolje razumijem ovu temu potaknula me je da izradim svoju verziju open-source oblačne igre. Rezultat je bio fantastičan. U nastavku bih volio podijeliti proces rada na mom godišnjem .
TLDR: kratka verzija s najvažnijim točkama
Zašto su oblačne igre budućnost
Vjerujem da će Cloud Gaming uskoro postati nova generacija ne samo igara, već i drugih područja informatike. Oblačne igre predstavljaju vrhunac modela klijent/server. Ovaj model maksimizira upravljanje backendom i minimizira rad frontenda premještanjem logike igre na udaljeni poslužitelj i strujanjem slika/audija klijentu. Poslužitelj provodi tešku obradu, stoga klijent više ne ovisi o hardverskim ograničenjima.
Google Stadia, u suštini, omogućuje igranje u (tj. visokoinvesticijskim blockbuster igrama) putem sučelja sličnog YouTube-u. Ista metodologija može se primijeniti i na druge teške offline aplikacije, poput operativnog sustava ili 2D/3D grafičkog dizajna itd., kako bismo ih stabilno pokretali na uređajima s niskim tehničkim karakteristikama na različitim platformama.

Budućnost ove tehnologije: zamislite da Microsoft Windows 10 radi u pregledniku Chrome?
Oblačne igre su tehnički složene
Igranje je jedno od rijetkih područja gdje je potrebna izuzetno brza reakcija korisnika. Ako se ponekad suočimo s odgodom od 2 sekunde prilikom klika na stranicu, to je prihvatljivo. Video streamovi u stvarnom vremenu obično kasne nekoliko sekundi, ali i dalje pružaju dovoljno udobnosti za korištenje. Međutim, ako igra često ima kašnjenje od 500 ms, jednostavno je nemoguće igrati. Naš cilj je postići izuzetno nisku latenciju, kako bi razlika između unosa i medija bila što manja. Stoga, tradicionalni pristup streamingu videa ovdje nije primjenjiv.

Opći model cloud gaming-a
Open source projekt CloudRetro
Odlučio sam stvoriti testni uzorak cloud gaming-a kako bih provjerio je li to sve moguće pri tako strogim mrežnim ograničenjima. Za provjeru koncepta odabrao sam Golang, jer je to jezik s kojim sam najviše upoznat i koji se pokazao kao vrlo prikladan za ovu implementaciju iz mnogih drugih razloga, kako se kasnije ispostavilo. Go je jednostavan i brzo se razvija; kanali u Go-u savršeno su prikladni za upravljanje višedretvenošću.
Projekt – cloud gaming usluga s otvorenim kodom za retro igre. Cilj projekta je u klasične retro igre uvesti najugodnije igračke doživljaje i dodati multiplayer.
Detaljnije upoznavanje s projektom možete pronaći ovdje: .
Funkcionalnost CloudRetro
Za demonstraciju cijele snage cloud gaming-a, CloudRetro koristi retro igre. To omogućava stjecanje mnoštva jedinstvenih igračkih iskustava.
- Portabilnost igre
- Trenutno reprodukcija prilikom otvaranja stranice; preuzimanje i instalacija nisu potrebni.
- Radi u mobilnom pregledniku, tako da nije potrebno nikakvo softversko rješenje za pokretanje.
- Igračke sesije mogu se dijeliti na više uređaja i pohranjivati u oblaku za sljedeći ulaz.
- Igru je moguće streamati, a može se igrati i odjednom s više korisnika:
- Crowdplay tipa TwitchPlayPokemon, samo više cross-platform i više u stvarnom vremenu.
- Offline igre u online modu. Mnogi korisnici mogu igrati bez postavljanja mreže. U Samurai Shodown sada mogu igrati 2 igrača putem CloudRetro mreže.

Demo verzija višekorisničke online igre na različitim uređajima.Infrastruktura
Zahtjevi i tehnologije
U nastavku je popis zahtjeva koje sam postavio prije početka projekta.
1. Jedan igrač
Ovaj zahtjev se može činiti manje važnim i očitim, ali to je jedan od mojih ključnih zaključaka, omogućava oblak igrama da se drže što dalje od tradicionalnih streaming usluga. Ako se fokusiramo na igrača s jednim igračem, možemo se osloboditi centraliziranih servera ili CDN-a, jer ne trebamo prenositi sadržaj masama. Umjesto da učitavamo streamove na prenapučeni server ili šaljemo pakete na centralizirani WebSocket server, usluge streama se izravno prenosu korisniku putem peer-to-peer WebRTC veze.2. Medijski tok s niskom latencijom
Čitajući o Stadiji, često susrećem spominjanje WebRTC-a u nekim člancima. Shvatio sam da je WebRTC izvanredna tehnologija i da savršeno odgovara za korištenje u oblačnim igrama. WebRTC je projekt koji web preglednicima i mobilnim aplikacijama omogućuje komunikaciju u stvarnom vremenu kroz jednostavan API. Osigurava peer-to-peer vezu optimiziranu za medije i ima ugrađene standardne kodeke kao što su VP8 i H264.Davao sam prioritet osiguravanju maksimalne udobnosti za korisnike, a ne očuvanju visokog kvaliteta grafike. U algoritmu su dopušteni određeni gubici. U Google Stadiji postoji dodatni korak za smanjenje veličine slike na serveru, a okviri se skaliraju na višu kvalitetu prije nego što se prenesu peer-to-peer čvorovima.
3. Distribuirana infrastruktura s geografskom usmjeravanjem
Bez obzira na to koliko je algoritam kompresije optimiziran i kod, mreža ostaje odlučujući faktor koji najviše pridonosi latenciji. Arhitektura mora imati mehanizam za povezivanje najbližeg servera korisniku kako bi se smanjilo vrijeme prijenosa (RTT). Arhitektura bi trebala imati 1 koordinatora i više streaming servera raspoređenih širom svijeta: Zapad SAD-a, Istok SAD-a, Europa, Singapur, Kina. Svi streaming serveri moraju biti potpuno izolirani. Sustav može regulirati svoje raspodjele kada server pristupi mreži ili se povuče. Također, tijekom velikog prometa, dodavanje dodatnih servera omogućuje horizontalno skaliranje.4. Kompatibilnost preglednika
Cloud gaming shines when it requires minimal effort from users. This means that it can be launched in a browser. Browsers help make the gaming experience as comfortable as possible for users by eliminating the need to install software and hardware. Browsers also help ensure cross-platform compatibility for both mobile and desktop versions. Fortunately, WebRTC is well supported across different browsers.5. Clear separation of the gaming interface and service
I view the cloud gaming service as a platform. Everyone should have the ability to connect anything to the platform. Currently, I have integrated with the cloud gaming service because LibRetro offers a beautiful emulator interface for retro games such as SNES, GBA, and PS.6. Rooms for multiplayer, crowd play, and deep linking to games
CloudRetro supports many new gameplay modes, such as CrowdPlay and Online MultiPlayer for retro games. If multiple users open the same deep link on different computers, they will see the same running game and even be able to join it.Moreover, game states are stored in cloud storage. This allows users to continue playing at any time on any other device.
7. Horizontal scaling
Like any SAAS today, cloud gaming must be designed to be horizontally scalable. The coordinator-worker architecture allows for adding more workers to handle greater traffic.8. No dependency on a single cloud
The CloudRetro infrastructure is hosted on various cloud providers (Digital Ocean, Alibaba, custom provider) for different regions. I activate launching in a Docker container for the infrastructure and configure the network settings using a bash script to avoid reliance on a single cloud provider. By combining this with NAT Traversal in WebRTC, we can gain flexibility to deploy CloudRetro on any cloud platform and even on users' machines.Architectural design
Worker: (ili striming poslužitelj, spomenut ranije) multiplicira igre, pokreće kodirajući pipeline i prenosi kodirani medij korisnicima. Instance radnika su raspoređene širom svijeta, a svaki radnik može obraditi nekoliko korisničkih sesija istovremeno.
Koordinator: odgovara za spajanje novog korisnika s najprikladnijim radnikom za striming. Koordinator komunicira s radnicima putem WebSocket-a.
Skladište stanja igara: centralno udaljeno skladište za sve statuse igre. Ovo skladište omogućava važne funkcije kao što su udaljeno spremanje/učitavanje.

Arhitektura CloudRetro na visokom nivouKorisnički scenarij
Kada novi korisnik otvori CloudRetro na koracima 1 i 2, prikazanim na slici ispod, koordinator zajedno s popisom dostupnih radnika traži prvu stranicu. Nakon toga, u koraku 3, klijent izračunava latencije za sve kandidate putem HTTP zahtjeva ping. Ovaj popis latencija se zatim šalje natrag koordinatoru kako bi mogao odrediti najprikladnijeg radnika za usluživanje korisnika. U koraku 4 ispod se stvara igra. Između korisnika i dodijeljenog radnika uspostavlja se streaming veza WebRTC.

Korisnički scenarij nakon pristupaŠto se nalazi unutar radnika
Igrački i striming pipelini su pohranjeni unutar radnika izolirano i razmjenjuju informacije putem sučelja. Trenutno se ova veza ostvaruje putem prijenosa podataka u memoriji preko u istom procesu. Sljedeći cilj je segregacija, tj. neovisno pokretanje igre u drugom procesu.

Interakcija komponenata radnikaGlavne komponente:
- WebRTC: klijentska komponenta koja prihvaća korisnički unos i isporučuje kodirani medij s poslužitelja.
- Igrački emulator: igračka komponenta. Zahvaljujući biblioteci Libretro, sustav je sposoban pokrenuti igru unutar istog procesa i interno presretati medije i tok unosa.
- Unutarnji okviri igre se snimaju i šalju u kodirač.
- Slika/audio kodirač: kodirajući pipeline koji prihvaća medijske okvire, kodira ih u pozadini i isporučuje kodirane slike/audio.
Implementacija
CloudRetro se oslanja na WebRTC kao ključnu tehnologiju, stoga sam, prije nego što se duboko posvetim detaljima implementacije u Golangu, odlučio govoriti o samom WebRTC-u. Ovo je nevjerojatna tehnologija koja mi je jako pomogla u postizanju kašnjenja prijenosa podataka od samo dijela sekunde.
WebRTC
WebRTC je namijenjen osiguravanju visokokvalitetnih peer-to-peer povezivanja na nativnim mobilnim aplikacijama i u preglednicima pomoću jednostavnih API-ja.
NAT Traversal
WebRTC je poznat po svojoj funkcionalnosti NAT Traversal. WebRTC je namijenjen peer-to-peer komunikaciji. Njegov cilj je pronaći najprikladniji izravni put, izbjegavajući NAT usmjerivače i vatrozidove za peer-to-peer komunikaciju putem procesa nazvanog . U okviru ovog procesa API WebRTC pronalazi vašu javnu IP adresu pomoću STUN poslužitelja i prosljeđuje je na poslužitelj za preusmjeravanje (), kada izravna veza ne može biti uspostavljena.
Međutim, CloudRetro ne koristi potpuno ovu mogućnost. Njegove peer-to-peer veze ne postoje između korisnika, već između korisnika i cloud poslužitelja. Serverska strana modela ima manje ograničenja na izravnu komunikaciju od običnog korisničkog uređaja. Ovo omogućava prethodno otvaranje dolaznih portova ili izravnu upotrebu javnih IP adresa, budući da poslužitelj nije iza NAT-a.
Nekada sam želio pretvoriti projekt u platformu za distribuciju igara za Cloud Gaming. Ideja je bila omogućiti kreatorima igara da pružaju igre i resurse za streaming, dok bi korisnici izravno komunicirali s pružateljima. Na takav decentralizirani način, CloudRetro je samo okruženje za povezivanje vanjskih resursa streaminga s korisnicima, čime postaje skalabilniji jer više ne ovisi o hostingu. Uloga WebRTC NAT Traversala ovdje je vrlo važna za olakšavanje inicijalizacije peer-to-peer veze na vanjskim resursima streaminga, što pojednostavljuje povezivanje kreatora s mrežom.
Kompresija videa
Kompresija videa je neizostavan deo radnog toka koji u velikoj meri doprinosi fluidnosti strimovanja. Iako nije neophodno znati sve detalje kodiranja videa u VP8/H264, razumevanje koncepcije pomaže u razumevanju parametara brzine strimovanja, rešavanju neočekivanog ponašanja i podešavanju latencije.
Kompresija videa za streaming servis predstavlja složen zadatak, jer algoritam mora osigurati da je ukupno vreme kodiranja + vreme prenosa preko mreže + vreme dekodiranja što je moguće manje. Pored toga, proces kodiranja mora biti dosledan i neprestan. Neki međusobni ustupci tokom kodiranja nisu primenjivi – na primer, ne možemo dati prednost dužem vremenu kodiranja ispred manjeg veličine datoteke i vremena dekodiranja, niti koristiti nedoslednu kompresiju.
Ideja kompresije videa je da isključi nepotrebne bitove informacija, dok zadržava prihvatljiv nivo tačnosti za korisnike. Osim kodiranja pojedinačnih statičnih okvira slike, algoritam izvodi trenutno okvir iz prethodnog i sledećeg, tako da se šalje samo njihova razlika. Kao što se može videti u primeru sa Pacman-om, šalju se samo diferencijalne tačke.

Poređenje video okvira na primeru PacmanKompresija zvuka
Na sličan način, algoritam za kompresiju zvuka izostavlja podatke koji ne mogu biti percipirani od strane čoveka. Opus je trenutno audio kodek sa najboljom performansom. On je dizajniran za prenos audio talasa preko protokola uređenih datagrama, kao što je RTP (Real Time Transport Protocol – protokol za prenos podataka u realnom vremenu). Njegova latencija je manja od mp3 i aac, a kvalitet je viši. Latencija obično iznosi oko 5~66,5 ms.
Pion, WebRTC u Golangu
je projekat otvorenog koda koji donosi WebRTC u Golang. Umesto uobičajenog omotavanja nativnih C++ biblioteka WebRTC, Pion je nativna Golang implementacija WebRTC sa boljim performansama, integracijom sa Go, kao i kontrolom verzija na protokolima WebRTC.
Biblioteka također omogućuje streamanje podataka s brojnim odličnim ugrađenim modulima s latencijom manjom od sekunde. Ima svoju vlastitu implementaciju STUN, DTLS, SCTP i tako dalje, kao i neka eksperimentalna rješenja s QUIC-om i WebAssembly-om. Sama po sebi, ova open-source biblioteka je zaista dobar izvor za učenje s odličnom dokumentacijom, implementacijom mrežnih protokola i odličnim primjerima.
Pion zajednica, vođena veoma strastvenim tvorcem, prilično je aktivna i vodi se mnogo kvalitetnih rasprava o WebRTC-u. Ako vas zanima ova tehnologija, pridružite se – saznat ćete mnogo novog.
Pisanje CloudRetro-a na Golangu

Implementacija radnika u Go-uGo kanali u akciji
Zbog lijepog dizajna Go kanala, problemi streamanja događaja i paralelizma se značajno pojednostavljuju. Kao što je prikazano na dijagramu, u različitim GoRutinama istovremeno radi nekoliko komponenti. Svaka komponenta upravlja svojim stanjem i komunicira preko kanala. Izborna izjava Golanga osigurava da se obrađuje samo jedno atomarno stanje u svakom trenutku u igri (game tick). To znači da za takav dizajn nije potrebna blokada. Na primjer, kada se korisnik sprema, potreban je puni snapshot stanja igre. Ovo stanje mora ostati neprekidno, obavljajući ulaz sve dok spremanje nije završeno. Tijekom svakog game tick-a, backend može obrađivati samo operaciju spremanja ili ulaza, što proces čini sigurnim za rad u višekorisničkom okruženju.
func (e *gameEmulator) gameUpdate() { for { select { case <-e.saveOperation: e.saveGameState() case key := <-e.input: e.updateGameState(key) case <-e.done: e.close() return } } }Fan-in / Fan-out
Ova Golang šablona je savršena za moj scenarij korištenja CrowdPlay-a i Multiple Player-a. Slijedeći ovu šablonu, svi korisnički unosi u jednoj sobi se integriraju u centralni ulazni kanal. Igračka sredstva se tada distribuiraju svim korisnicima u toj sobi. Na taj način postižemo dijeljenje stanja igre između nekoliko igraćih sesija različitih korisnika.

Sinkronizacija između različitih sesijaNedostaci Golanga
Golang nije savršen. Kanal je spor. U usporedbi sa blokiranjem, kanal Go je jednostavniji način obrade paralelnih i strimskih događaja, no kanal ne pruža najbolju izvedbu. ispod kanala postoji složena logika blokiranja. Stoga sam uveo neke izmjene u implementaciju ponovnim korištenjem blokada i atomski vrijednosti umjesto kanala za optimizaciju performansi.
Osim toga, garbage collector u Golangu je neuređen, što ponekad dovodi do sumnjivih dugih pauza. To značajno ometa rad strim aplikacije u stvarnom vremenu.
CGO
U projektu se koristi postojeća VP8/H264 Golang biblioteka otvorenog koda za kompresiju medija i Libretro za igre emulatora. Sve te biblioteke su zapravo omote C biblioteke u Go koristeći . Neki od nedostataka navedeni su u . Problemi s kojima sam se suočio su:
- nemogućnost hvatanja padova u CGO-u, čak i uz pomoć Golang RecoveryCrash;
- nemogućnost identifikacije uskog grla u performansama kada ne možemo otkriti detaljne probleme u CGO-u.
Zaključak
Postigao sam svoj cilj – razumio sam usluge oblaka igara i stvorio platformu koja pomaže igrati nostalgične retro igre s mojim prijateljima online. Izrada ovog projekta ne bi bila moguća bez Pion biblioteke i podrške zajednice Pion. Izuzetno sam zahvalan na njegovoj intenzivnoj podršci. Jednostavna API-ja koje pružaju WebRTC i Pion omogućila su glatku integraciju. Moj prvi dokaz koncepta objavljen je u istom tjednu, iako nisam unaprijed znao o peer-to-peer vezi (P2P).
Iako je integracija jednostavna, P2P strimovanje je zapravo vrlo složno područje računalnih znanosti. Mora se nositi sa složenošću dugogodišnjih mrežnih arhitektura poput IP-a i NAT-a za uspostavljanje peer-to-peer sesije. Tijekom rada na ovom projektu stekao sam mnogo vrijednih znanja o mreži i optimizaciji performansi, pa preporučujem svima da pokušaju izgraditi P2P proizvode pomoću WebRTC-a.
CloudRetro podržava sve scenarije korištenja koje sam očekivao s mog stajališta kao retro igrača. Međutim, mislim da postoji mnogo područja u projektu koja mogu poboljšati, poput povećanja pouzdanosti i performansi mreže, osiguravanja boljeg kvaliteta grafike igara ili mogućnosti dijeljenja igara među korisnicima. Naporno radim na tome. Molim vas, pratite i podržite ga ako vam se sviđa.
Izvor: habr.com







