Open source skyspil på WebRTC: p2p, multiplayer, nul latency

Open source skyspil på WebRTC: p2p, multiplayer, nul latency
Software as a Service, Infrastructure as a Service, Platform as a Service, Communications Platform as a Service, Video Conferencing as a Service, og hvad med Cloud Gaming as a Service? Der har allerede været flere forsøg på at skabe cloud-gaming (Cloud Gaming), såsom Stadia, der for nylig blev lanceret af Google. Stadia ikke nyt for WebRTC, men kan andre bruge WebRTC på samme måde?

Thanh Nguyen besluttede at teste denne mulighed på sit open source-projekt CloudRetro. CloudRetro er baseret på Pion, populær WebRTC-bibliotek baseret på Go (tak Vist fra Pion-udviklingsteamet for deres hjælp med denne artikel). I denne artikel giver Thanh et overblik over sit projekts arkitektur og fortæller også om, hvad han lærte nyttigt, og hvilke udfordringer han stødte på, mens han arbejdede.

Indrejse

Sidste år, da Google annoncerede Stadia, blev jeg blæst bagover. Ideen er så unik og innovativ, at jeg hele tiden undrede mig over, hvordan det overhovedet er muligt med eksisterende teknologi. Ønsket om bedre at forstå dette emne fik mig til at lave min egen version af et open source cloud-spil. Resultatet var bare fantastisk. Nedenfor vil jeg gerne dele processen med at arbejde på mit årlige projekt.

TLDR: kort slide version med highlights

Hvorfor cloud-gaming er fremtiden

Jeg tror på, at Cloud Gaming snart vil blive en ny generation af ikke kun spil, men også andre områder inden for datalogi. Cloud-spil er toppen af ​​klient/server-modellen. Denne model maksimerer backend-styring og minimerer frontend-arbejde ved at hoste spillogik på en ekstern server og streame billeder/lyd til klienten. Serveren udfører den tunge behandling, så klienten ikke længere er underlagt hardwarebegrænsninger.

Google Stadia lader dig grundlæggende spille AAA spil (dvs. high-end blockbuster-spil) på en grænseflade som YouTube. Den samme metode kan anvendes til andre tunge offline applikationer såsom operativsystem eller 2D/3D grafisk design osv. så vi kan køre dem stabilt på lavspecifikke enheder på tværs af platforme.

Open source skyspil på WebRTC: p2p, multiplayer, nul latency
Fremtiden for denne teknologi: Forestil dig, hvis Microsoft Windows 10 kørte på Chrome-browseren?

Cloud spil er teknisk udfordrende

Gaming er et af de sjældne områder, hvor der kræves en konstant hurtig reaktion fra brugeren. Hvis vi lejlighedsvis støder på en forsinkelse på 2 sekunder, når vi klikker på en side, er dette acceptabelt. Live videostreams plejer at være et par sekunder bagud, men tilbyder stadig en god portion brugervenlighed. Men hvis spillet ofte er forsinket med 500ms, er det simpelthen ikke muligt at spille. Vores mål er at opnå ekstrem lav latenstid, så afstanden mellem input og medier er så lille som muligt. Derfor er den traditionelle tilgang til streaming af video ikke anvendelig her.

Open source skyspil på WebRTC: p2p, multiplayer, nul latency
Generel sky spil skabelon

Open source-projekt CloudRetro

Jeg besluttede at lave en testprøve af et skyspil for at se, om alt dette er muligt med så strenge netværksbegrænsninger. Jeg valgte Golang som proof of concept, fordi det er det sprog, jeg er mest bekendt med og passer godt til denne implementering af mange andre grunde, som jeg senere fandt ud af. Go er enkel og udvikler sig meget hurtigt; Kanaler i Go er gode til at administrere multithreading.

Projekt CloudRetro.io er en open source cloud-spiltjeneste til retro-spil. Målet med projektet er at bringe den mest komfortable spiloplevelse til traditionelle retrospil og tilføje multiplayer.
Du kan læse mere om projektet her: https://github.com/giongto35/cloud-game.

CloudRetro funktionalitet

CloudRetro bruger retro-spil til at demonstrere styrken af ​​cloud-spil. Hvilket giver dig mulighed for at få mange unikke spiloplevelser.

  • Spilportabilitet
    • Øjeblikkelig afspilning, når du åbner en side; ingen download og installation påkrævet
    • Kører på en mobilbrowser, så ingen software er nødvendig for at køre

  • Spilsessioner kan deles på tværs af flere enheder og gemmes i skyen til næste gang, du logger på
  • Spillet kan streames, eller det kan spilles af flere brugere på én gang:
    • Crowdplay som TwitchPlayPokemon, kun mere på tværs af platforme og mere i realtid
    • Offline spil online. Mange brugere kan spille uden netværksopsætning. Samurai Shodown kan nu spilles med 2 spillere over CloudRetro-netværket

    Open source skyspil på WebRTC: p2p, multiplayer, nul latency
    Demoversion af online multiplayer-spil på forskellige enheder

    Infrastruktur

    Krav og teknologistak

    Nedenfor er en liste over krav, som jeg stiller inden jeg starter projektet.

    1. En spiller
    Dette krav virker måske ikke alt for vigtigt og indlysende her, men det er en af ​​mine vigtigste takeaways, det holder skyspil så langt væk fra traditionelle streamingtjenester som muligt. Hvis vi fokuserer på singleplayer-spillet, kan vi slippe af med den centraliserede server eller CDN, fordi vi ikke behøver at streame til masserne. I stedet for at uploade streams til en indtagelsesserver eller sende pakker til en centraliseret WebSocket-server, streames servicestreams direkte til brugeren via en WebRTC peer-forbindelse.

    2. Mediestrøm med lav latenstid
    Når jeg læser om Stadia, ser jeg ofte WebRTC nævnt i nogle artikler. Jeg indså, at WebRTC er en fremragende teknologi, og den er fantastisk til brug i skyspil. WebRTC er et projekt, der giver webbrowsere og mobilapplikationer kommunikation i realtid gennem en simpel API. Det giver peer-to-peer-forbindelse, er optimeret til medier og har indbyggede standard-codecs såsom VP8 og H264.

    Jeg prioriterede at give den bedst mulige brugeroplevelse frem for at opretholde grafik af høj kvalitet. Nogle tab er tilladt i algoritmen. Google Stadia har et ekstra trin til at reducere billedstørrelsen på serveren, og rammerne opskaleres til en højere kvalitet, før de videregives til peers.

    3. Distribueret infrastruktur med geografisk routing
    Uanset hvor optimeret komprimeringsalgoritmen og koden er, er netværket stadig den afgørende faktor, der bidrager mest til latency. Arkitekturen bør have en mekanisme til at parre den server, der er tættest på brugeren for at reducere rundturstid (RTT). Arkitekturen skal have 1 koordinator og flere streamingservere fordelt rundt om i verden: USA Vest, USA Øst, Europa, Singapore, Kina. Alle streamingservere skal være fuldstændigt isolerede. Systemet kan justere sin distribution, når serveren tilslutter sig eller forlader netværket. Med høj trafik giver tilføjelse af yderligere servere mulighed for horisontal skalering.

    4. Browserkompatibilitet
    Cloud-spil er bedst, når det kræver det absolutte minimum fra brugerne. Det betyder, at det er muligt at køre i en browser. Browsere hjælper med at gøre spiloplevelsen så behagelig som muligt for brugerne ved at spare dem fra at installere software og hardware. Browsere hjælper også med at levere tværplatforme til mobil- og desktopversioner. Heldigvis er WebRTC godt understøttet på tværs af en række browsere.

    5. Klar adskillelse af spilgrænsefladen og tjenesten
    Jeg ser cloud gaming service som en platform. Alle skal kunne forbinde hvad som helst til platformen. Jeg har nu integreret LibRetro med cloud-spiltjeneste, fordi LibRetro tilbyder smuk spilemulatorgrænseflade til retrospil som SNES, GBA, PS.

    6. Rum til multiplayer, crowdplay og ekstern linking (deep-link) med spillet
    CloudRetro understøtter mange nye gameplays såsom CrowdPlay og Online MultiPlayer til retro-spil. Hvis flere brugere åbner det samme dybe link på forskellige computere, vil de se det samme spil køre og endda være i stand til at deltage i det.

    Desuden gemmes spiltilstande i skylager. Dette giver brugerne mulighed for at fortsætte med at spille til enhver tid på en hvilken som helst anden enhed.

    7. Vandret skalering
    Som enhver SAAS i dag skal cloud-gaming være designet til at være horisontalt skalerbar. Koordinator-arbejder-designet giver dig mulighed for at tilføje flere arbejdere for at betjene mere trafik.

    8. Ikke bundet til én sky
    CloudRetro-infrastrukturen hostes af forskellige cloud-udbydere (Digital Ocean, Alibaba, brugerdefineret udbyder) for forskellige regioner. Jeg aktiverer kørsel i en infrastruktur Docker-container og konfigurerer netværksindstillinger med et bash-script for at undgå at være afhængig af en enkelt cloud-udbyder. Ved at kombinere dette med NAT Traversal i WebRTC kan vi have fleksibiliteten til at implementere CloudRetro på enhver cloud-platform og endda enhver brugers maskine.

    Arkitektonisk design

    Arbejder: (eller streamingserveren nævnt ovenfor) multiplicerer spillene, kører encoding pipeline og streamer det kodede medie til brugerne. Arbejderforekomster er distribueret over hele verden, og hver medarbejder kan håndtere flere brugersessioner på samme tid.

    Koordinator: er ansvarlig for at parre den nye bruger med den bedst egnede streamingmedarbejder. Koordinatoren kommunikerer med arbejderne via WebSocket.

    Lagring af spiltilstand: central fjernlager til alle spiltilstande. Dette lager giver vigtige funktioner såsom fjernlagring/indlæsning.

    Open source skyspil på WebRTC: p2p, multiplayer, nul latency
    CloudRetro arkitektur på topniveau

    Brugerdefineret script

    Når en ny bruger åbner CloudRetro i trin 1 og 2 vist i figuren nedenfor, anmodes koordinatoren sammen med en liste over tilgængelige arbejdere til den første side. Derefter, i trin 3, beregner klienten forsinkelser for alle kandidater ved hjælp af en HTTP-ping-anmodning. Denne liste over forsinkelser sendes derefter tilbage til koordinatoren, så han kan finde den mest passende medarbejder til at betjene brugeren. Trin 4 nedenfor opretter et spil. Der etableres en WebRTC-streamingforbindelse mellem brugeren og den tildelte arbejder.
    Open source skyspil på WebRTC: p2p, multiplayer, nul latency
    Brugerdefineret script efter at have fået adgang

    Hvad er der inde i arbejderen

    Spil- og streaming-pipelines lagres isoleret inde i arbejderen og udveksler oplysninger der gennem grænsefladen. I øjeblikket udføres denne kommunikation ved at overføre data i hukommelsen over golang kanaler i samme proces. Næste mål er segregation, dvs. uafhængig lancering af spillet i en anden proces.

    Open source skyspil på WebRTC: p2p, multiplayer, nul latency
    Interaktion mellem arbejderkomponenter

    Hovedkomponenter:

    • WebRTC: en klientkomponent, der accepterer brugerinput og udsender det kodede medie fra serveren.
    • Spil emulator: spil komponent. Takket være Libretro-biblioteket er systemet i stand til at køre spillet inde i den samme proces og opsnappe medierne og inputstrømmen internt.
    • Rammer i spillet fanges og sendes til encoderen.
    • Billed-/lydkoder: en kodningspipeline, der modtager medieframes, koder dem i baggrunden og udsender kodede billeder/lyd.

    implementering

    CloudRetro er afhængig af WebRTC som en backbone-teknologi, så før jeg dykkede ned i detaljerne i Golang-implementeringen, besluttede jeg at tale om selve WebRTC. Det er et fantastisk stykke teknologi, der har hjulpet mig utroligt meget med at opnå streaming med forsinkelse på under sekunder.

    WebRTC

    WebRTC er designet til at levere peer-to-peer-forbindelser af høj kvalitet på native mobilapps og browsere ved hjælp af simple API'er.

    NAT Traversal

    WebRTC er kendt for sin NAT Traversal-funktionalitet. WebRTC er designet til peer-to-peer kommunikation. Dens mål er at finde den bedst egnede direkte rute og undgå NAT-gateways og firewalls til peer-to-peer-kommunikation gennem en proces kaldet ICE. Som en del af denne proces finder WebRTC API'erne din offentlige IP-adresse ved hjælp af STUN-servere og videresender den til relæserveren (TUR), når en direkte forbindelse ikke kan etableres.

    CloudRetro udnytter dog ikke denne mulighed fuldt ud. Dens peer-to-peer-forbindelser eksisterer ikke mellem brugere, men mellem brugere og cloud-servere. Serversiden af ​​modellen har færre begrænsninger på direkte kommunikation end en typisk brugerenhed. Dette giver dig mulighed for at åbne indgående porte på forhånd eller bruge offentlige IP-adresser direkte, da serveren ikke er bag NAT.

    Tidligere har jeg ønsket at gøre projektet til en spildistributionsplatform til Cloud Gaming. Ideen var at give spilskabere mulighed for at levere spil og streamingressourcer. Og brugere ville interagere med udbydere direkte. På denne decentraliserede måde er CloudRetro blot et medie til at forbinde tredjeparts streamingressourcer til brugere, hvilket gør det mere skalerbart, når hosting ikke længere hænger på det. Rollen som WebRTC NAT Traversal er meget vigtig her for at lette initialisering af en peer-to-peer-forbindelse på tredjeparts streamingressourcer, hvilket gør det nemmere for skaberen at oprette forbindelse til netværket.

    Videokomprimering

    Videokomprimering er en uundværlig del af rørledningen og bidrager i høj grad til strømmens jævnhed. Selvom det ikke er nødvendigt at kende alle detaljerne i VP8/H264-videokodning, hjælper forståelsen af ​​konceptet med at forstå videostreaminghastighedsparametre, fejlfinde uventet adfærd og justere latens.

    At komprimere video til en streamingtjeneste er udfordrende, fordi algoritmen skal sikre, at den samlede indkodningstid + netværksoverførselstid + afkodningstid er så lille som muligt. Derudover skal kodningsprocessen være konsistent og kontinuerlig. Nogle afvejninger i kodning gælder ikke - for eksempel kan vi ikke foretrække en lang kodningstid frem for en mindre filstørrelse og afkodningstid, eller bruge inkonsekvent komprimering.

    Ideen bag videokomprimering er at eliminere unødvendige bidder af information og samtidig opretholde et acceptabelt niveau af nøjagtighed for brugerne. Ud over at kode individuelle statiske billedrammer, udleder algoritmen den aktuelle frame fra den forrige og næste, så kun deres forskel sendes. Som det fremgår af eksemplet med Pacman, transmitteres kun differentialpunkter.

    Open source skyspil på WebRTC: p2p, multiplayer, nul latency
    Sammenligning af videorammer med Pacman som eksempel

    Lydkomprimering

    På samme måde udelader lydkomprimeringsalgoritmen data, som ikke kan opfattes af mennesker. Opus er i øjeblikket den bedste lyd-codec. Den er designet til at transmittere en lydbølge over en bestilt datagramprotokol, såsom RTP (Real Time Transport Protocol). Dens latency er lavere end mp3 og aac, og kvaliteten er højere. Latensen er normalt omkring 5~66,5ms.

    Pion, WebRTC i Golang

    Bonde er et open source-projekt, der bringer WebRTC til Golang. I stedet for den sædvanlige indpakning af native C++ WebRTC-biblioteker, er Pion en native Golang-implementering af WebRTC med bedre ydeevne, Go-integration og versionskontrol på WebRTC-protokoller.

    Biblioteket leverer også streaming af data med en masse flotte indbyggede moduler med en forsinkelse på mindre end et sekund. Det har sin egen implementering af STUN, DTLS, SCTP osv. og nogle eksperimenter med QUIC og WebAssembly. I sig selv er dette open source-bibliotek en rigtig god kilde til læring med fantastisk dokumentation, implementeringer af netværksprotokol og fede eksempler.

    Pion-fællesskabet, ledet af en meget passioneret skaber, er ret livlig og har en masse kvalitetsdiskussion om WebRTC. Hvis du er interesseret i denne teknologi, så deltag http://pion.ly/slack - du vil lære en masse nye ting.

    Skriver CloudRetro i Golang

    Open source skyspil på WebRTC: p2p, multiplayer, nul latency
    Arbejderimplementering i Go

    Gå kanaler i aktion

    Med det smukke design af Go's kanaler er problemerne med begivenhedsstreaming og samtidighed meget forenklet. Som i diagrammet er der flere komponenter, der kører parallelt i forskellige GoRoutines. Hver komponent styrer sin egen tilstand og kommunikerer gennem kanaler. Golangs selektive påstand bevirker, at én atomær hændelse behandles hver gang i spillet (game tick). Det betyder, at der ikke er behov for blokering til dette design. For eksempel, når en bruger er gemt, kræves et øjebliksbillede af fuld tilstand af spillet. Denne tilstand skal forblive uafbrudt og logge på, indtil lagringen er fuldført. Under hvert spilkryds kan backend kun behandle en save- eller enter-operation, hvilket gør processen trådsikker.

    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

    Denne Golang-skabelon er fantastisk til min CrowdPlay og Multiple Player-brug. Efter dette mønster er alle brugerindgange i samme rum indbygget i den midterste inputkanal. Spilmediet distribueres derefter til alle brugere i samme rum. På denne måde opnår vi opdelingen af ​​spiltilstanden mellem flere spilsessioner af forskellige brugere.

    Open source skyspil på WebRTC: p2p, multiplayer, nul latency
    Synkronisering mellem forskellige sessioner

    Ulemper ved Golang

    Golang er ikke perfekt. Kanalen er langsom. Sammenlignet med blokering er en Go-kanal simpelthen en nemmere måde at håndtere samtidige begivenheder og streamingbegivenheder på, men en kanal giver ikke den bedste ydeevne. Der er kompleks blokeringslogik under kanalen. Derfor foretog jeg nogle justeringer af implementeringen ved at genanvende låse og atomværdier ved udskiftning af kanaler for at optimere ydeevnen.

    Derudover er Golangs skraldemand uoverskuelig, hvilket nogle gange forårsager mistænkeligt lange pauser. Dette forstyrrer i høj grad streamingapplikationen i realtid.

    COG

    Projektet bruger det eksisterende VP8/H264 open source Golang-bibliotek til mediekomprimering og Libretro til spilemulatorer. Alle disse biblioteker er simpelthen indpakninger af C-biblioteket i Go-brug COG. Nogle af ulemperne er nævnt i dette indlæg Dave Cheney. Problemer jeg stødte på:

    • manglende evne til at fange et nedbrud i CGO, selv med Golang RecoveryCrash;
    • manglende evne til at identificere en præstationsflaskehals, når vi ikke kan opdage granulære problemer i CGO.

    Konklusion

    Jeg nåede mit mål om at forstå cloud-spiltjenester og skabe en platform, der hjælper mig med at spille nostalgiske retrospil med mine venner online. Dette projekt ville ikke have været muligt uden Pion-biblioteket og støtten fra Pion-fællesskabet. Jeg er meget taknemmelig for dens intensive udvikling. De enkle API'er leveret af WebRTC og Pion sikrede problemfri integration. Mit første proof of concept blev udgivet samme uge, selvom jeg ikke havde nogen forudgående viden om peer-to-peer (P2P) kommunikation.

    På trods af den lette integration er P2P-streaming faktisk et meget komplekst område inden for datalogi. Det skal håndtere kompleksiteten af ​​flerårige netværksarkitekturer såsom IP og NAT for at skabe en peer-to-peer session. Mens jeg arbejdede på dette projekt, har jeg oparbejdet en masse værdifuld viden om netværk og ydeevneoptimering, så jeg anbefaler, at alle prøver at bygge P2P-produkter ved hjælp af WebRTC.

    CloudRetro henvender sig til alle de use cases, jeg forventede fra mit synspunkt som retro gamer. Jeg tror dog, at der er mange områder i projektet, som jeg kan forbedre, såsom at gøre netværket mere pålideligt og ydende, levere spilgrafik af højere kvalitet eller muligheden for at dele spil mellem brugere. Jeg arbejder hårdt på det her. Følg venligst projekt og støt ham, hvis du kan lide ham.

Kilde: www.habr.com

Tilføj en kommentar