Åpen kildekode-skyspilling på WebRTC: p2p, flerspiller, null ventetid

Åpen kildekode-skyspilling på WebRTC: p2p, flerspiller, null ventetid
Programvare som tjeneste, infrastruktur som tjeneste, plattform som tjeneste, kommunikasjonsplattform som tjeneste, videokonferanse som tjeneste, hva med skyspill som tjeneste? Det har allerede vært flere forsøk på å lage skyspill (Cloud Gaming), som Stadia, nylig lansert av Google. Stadia ikke ny for WebRTC, men kan andre bruke WebRTC på samme måte?

Thanh Nguyen bestemte seg for å teste denne muligheten på sitt åpen kildekodeprosjekt CloudRetro. CloudRetro er basert på Pion, populær WebRTC-bibliotek basert på Go (takk Vist fra Pion-utviklingsteamet for deres hjelp med å utarbeide denne artikkelen). I denne artikkelen gir Thanh en oversikt over arkitekturen i prosjektet sitt, og forteller også om hvilke nyttige ting han lærte og hvilke utfordringer han møtte under arbeidet.

Entry

I fjor, da Google kunngjorde Stadia, ble det helt galt. Ideen er så unik og nyskapende at jeg hele tiden lurte på hvordan dette i det hele tatt var mulig med eksisterende teknologi. Ønsket om å forstå dette emnet bedre fikk meg til å lage min egen versjon av et åpen kildekode-skyspill. Resultatet ble rett og slett fantastisk. Nedenfor vil jeg dele prosessen med å jobbe med året mitt prosjekt.

TLDR: kort lysbildeversjon med høydepunkter

Hvorfor skyspill er fremtiden

Jeg tror at Cloud Gaming snart vil bli neste generasjon av ikke bare spill, men også andre områder innen informatikk. Cloud gaming er toppen av klient/server-modellen. Denne modellen maksimerer backend-administrasjonen og minimerer frontend-arbeid ved å hoste spilllogikk på en ekstern server og streame bilder/lyd til klienten. Serveren gjør den tunge behandlingen slik at klienten ikke lenger er prisgitt maskinvarebegrensninger.

Google Stadia lar deg egentlig spille AAA-spill (dvs. high-end blockbuster-spill) på et grensesnitt som YouTube. Den samme metodikken kan brukes på andre tunge offline-applikasjoner som operativsystem eller 2D/3D grafisk design, etc. slik at vi kan kjøre dem konsekvent på lavspesifiserte enheter på tvers av flere plattformer.

Åpen kildekode-skyspilling på WebRTC: p2p, flerspiller, null ventetid
Fremtiden til denne teknologien: Tenk om Microsoft Windows 10 kjørte på Chrome-nettleseren?

Skyspilling er teknisk utfordrende

Gaming er et av de sjeldne områdene der konstant, rask brukerrespons kreves. Hvis vi av og til møter en forsinkelse på 2 sekunder når vi klikker på en side, er dette akseptabelt. Live videostrømmer har en tendens til å ligge noen sekunder, men tilbyr fortsatt en rimelig brukervennlighet. Men hvis spillet ofte henger med 500 ms, er det rett og slett uspillbart. Målet vårt er å oppnå ekstremt lav latens slik at gapet mellom input og media blir så lite som mulig. Derfor er den tradisjonelle tilnærmingen til videostreaming ikke aktuelt her.

Åpen kildekode-skyspilling på WebRTC: p2p, flerspiller, null ventetid
Generell skyspillmal

Åpen kildekode-prosjekt CloudRetro

Jeg bestemte meg for å lage en testprøve av et skyspill for å se om alt dette var mulig med så stramme nettverksbegrensninger. Jeg valgte Golang som proof of concept fordi det var språket jeg var mest kjent med og var godt egnet for denne implementeringen av mange andre grunner, som jeg senere oppdaget. Go er enkelt og utvikler seg veldig raskt; Kanaler i Go er flotte for å administrere multithreading.

Prosjekt CloudRetro.io er en åpen kildekode skyspilltjeneste for retrospilling. Målet med prosjektet er å bringe den mest komfortable spillopplevelsen til tradisjonelle retrospill og legge til flerspiller.
Du kan lære mer om prosjektet her: https://github.com/giongto35/cloud-game.

CloudRetro-funksjonalitet

CloudRetro bruker retrospill for å demonstrere kraften i skyspilling. Noe som lar deg få mange unike spillopplevelser.

  • Portabilitet av spillet
    • Øyeblikkelig avspilling når du åpner en side; ingen nedlasting eller installasjon nødvendig
    • Fungerer i en mobil nettleser, så det trengs ingen programvare for å kjøre den

  • Spilløkter kan deles på flere enheter og lagres i skyen til neste gang du logger på
  • Spillet kan streames, eller det kan spilles av flere brukere samtidig:
    • Crowdplay som TwitchPlayPokemon, bare mer på tvers av plattformer og mer sanntid
    • Offline spill online. Mange brukere kan spille uten å sette opp et nettverk. Samurai Shodown kan nå spilles av 2 spillere over CloudRetro-nettverket

    Åpen kildekode-skyspilling på WebRTC: p2p, flerspiller, null ventetid
    Demoversjon av online flerspillerspill på forskjellige enheter

    infrastruktur

    Krav og teknologistabel

    Nedenfor er en liste over krav som jeg stiller før jeg starter prosjektet.

    1. Én spiller
    Dette kravet virker kanskje ikke for viktig eller åpenbart her, men det er en av mine viktigste takeaways, det lar skyspilling holde seg så langt unna tradisjonelle strømmetjenester som mulig. Hvis vi fokuserer på et enkeltspillerspill, kan vi kvitte oss med en sentralisert server eller CDN fordi vi ikke trenger å streame til massene. I stedet for å laste opp strømmer til en sink-server eller sende pakker til en sentralisert WebSocket-server, leveres tjenestestrømmer direkte til brukeren via en peer-to-peer WebRTC-forbindelse.

    2. Mediestrøm med lav ventetid
    Når jeg leser om Stadia, ser jeg ofte WebRTC nevnt i noen artikler. Jeg innså at WebRTC er en enestående teknologi og er perfekt for bruk i skyspill. WebRTC er et prosjekt som gir nettlesere og mobilapplikasjoner sanntidskommunikasjon gjennom et enkelt API. Den gir peer-to-peer-tilkobling, er optimert for media, og har standard kodeker innebygd som VP8 og H264.

    Jeg prioriterte å sikre best mulig brukeropplevelse fremfor å opprettholde grafikk av høy kvalitet. Noen tap er akseptable i algoritmen. Google Stadia har et ekstra trinn med å redusere bildestørrelsen på serveren, og rammer oppskaleres til en høyere kvalitet før de overføres til jevnaldrende.

    3. Distribuert infrastruktur med geografisk ruting
    Uansett hvor optimalisert komprimeringsalgoritmen og koden er, er nettverket fortsatt den avgjørende faktoren som bidrar mest til ventetiden. Arkitekturen må ha en mekanisme for å pare serveren nærmest brukeren for å redusere rundturstid (RTT). Arkitekturen må ha 1 koordinator og flere strømmeservere distribuert over hele verden: USA vest, USA øst, Europa, Singapore, Kina. Alle strømmeservere må være fullstendig isolert. Systemet kan justere distribusjonen når en server blir med eller forlater nettverket. Dermed, med stor trafikk, kan legge til flere servere for horisontal skalering.

    4. Nettleserkompatibilitet
    Cloud gaming er på sitt beste når det krever minst av brukerne. Dette betyr at det er mulig å kjøre i en nettleser. Nettlesere bidrar til å gjøre spillopplevelsen så komfortabel som mulig for brukerne, og sparer dem fra å installere programvare og maskinvare. Nettlesere bidrar også til å tilby funksjonalitet på tvers av plattformer mellom mobil- og desktopversjoner. Heldigvis støttes WebRTC godt på tvers av en rekke nettlesere.

    5. Tydelig skille mellom spillgrensesnittet og tjenesten
    Jeg ser på skyspilltjenesten som en plattform. Alle skal kunne koble hva som helst til plattformen. Nå har jeg integrert LibRetro med skyspilltjeneste fordi LibRetro tilbyr et vakkert spillemulatorgrensesnitt for retrospill som SNES, GBA, PS.

    6. Rom for flerspiller, publikumsspill og ekstern kobling (dyplink) med spillet
    CloudRetro støtter mange nye spill som CrowdPlay og Online MultiPlayer for retrospill. Hvis flere brukere åpner den samme dyplenken på forskjellige datamaskiner, vil de se det samme spillet kjøre og til og med kunne bli med i det.

    Dessuten lagres spilltilstander i skylagring. Dette lar brukere fortsette å spille når som helst på en hvilken som helst annen enhet.

    7. Horisontal skalering
    Som alle SAAS i dag, må skyspill være designet for å være horisontalt skalerbart. Koordinator-arbeider-designet lar deg legge til flere arbeidere for å betjene mer trafikk.

    8. Ingen tilkobling til én sky
    CloudRetros infrastruktur er vert for forskjellige skyleverandører (Digital Ocean, Alibaba, tilpasset leverandør) for forskjellige regioner. Jeg aktiverer kjøring i en Docker-beholder for infrastrukturen og konfigurerer nettverksinnstillinger ved hjelp av et bash-skript for å unngå å bli låst til en enkelt skyleverandør. Ved å kombinere dette med NAT Traversal i WebRTC, kan vi ha fleksibiliteten til å distribuere CloudRetro på hvilken som helst skyplattform og til og med på alle brukeres maskiner.

    Arkitektonisk design

    Arbeider: (eller strømmeserveren nevnt ovenfor) multipliserer spillene, kjører kodingspipelinen og strømmer det kodede mediet til brukerne. Arbeiderforekomster er distribuert over hele verden, og hver arbeider kan håndtere flere brukerøkter samtidig.

    Koordinator: er ansvarlig for å sammenkoble den nye brukeren med den best egnede arbeideren for strømming. Koordinatoren samhandler med arbeidere via WebSocket.

    Lagring av spilltilstand: sentral fjernlagring for alle spillstater. Denne lagringen gir viktige funksjoner som ekstern lagring/last.

    Åpen kildekode-skyspilling på WebRTC: p2p, flerspiller, null ventetid
    Toppnivåarkitektur til CloudRetro

    Egendefinert skript

    Når en ny bruker åpner CloudRetro i trinn 1 og 2 vist i figuren nedenfor, blir koordinatoren sammen med listen over tilgjengelige arbeidere bedt om til første side. Etter dette, i trinn 3, beregner klienten forsinkelsene for alle kandidater ved å bruke en HTTP-pingforespørsel. Denne listen over forsinkelser sendes deretter tilbake til koordinatoren slik at han kan finne den best egnede arbeideren til å betjene brukeren. Trinn 4 nedenfor lager spillet. En WebRTC-streamingforbindelse opprettes mellom brukeren og den tilordnede arbeideren.
    Åpen kildekode-skyspilling på WebRTC: p2p, flerspiller, null ventetid
    Brukerskript etter å ha fått tilgang

    Hva er inne i arbeideren

    Spill- og strømmingsrørledninger lagres isolert inne i arbeideren og utveksler informasjon der gjennom grensesnittet. Foreløpig utføres denne kommunikasjonen ved å overføre data i minnet via Golang-kanaler i samme prosess. Neste mål er segregering, d.v.s. uavhengig lansering av spillet i en annen prosess.

    Åpen kildekode-skyspilling på WebRTC: p2p, flerspiller, null ventetid
    Samspill mellom arbeiderkomponenter

    Hovedkomponenter:

    • WebRTC: en klientkomponent som aksepterer brukerinndata og sender ut kodede medier fra serveren.
    • Spillemulator: spillkomponent. Takket være Libretro-biblioteket er systemet i stand til å kjøre spillet i samme prosess og internt avskjære media og inputstrøm.
    • Rammer i spillet fanges opp og sendes til koderen.
    • Bilde-/lydkoder: en kodingspipeline som tar mediarammer, koder dem i bakgrunnen og sender ut kodede bilder/lyd.

    implementering

    CloudRetro er avhengig av WebRTC som ryggradsteknologi, så før jeg dykket inn i detaljene i Golang-implementeringen, bestemte jeg meg for å snakke om selve WebRTC. Dette er fantastisk teknologi som har hjulpet meg veldig med å oppnå forsinkelser på under sekunder for streaming av data.

    WebRTC

    WebRTC er designet for å gi høykvalitets peer-to-peer-tilkoblinger på innfødte mobilapper og nettlesere ved hjelp av enkle APIer.

    NAT Traversal

    WebRTC er kjent for sin NAT Traversal-funksjonalitet. WebRTC er designet for peer-to-peer kommunikasjon. Målet er å finne den mest passende direkte ruten, og unngå NAT-gatewayer og brannmurer for peer-to-peer-kommunikasjon gjennom en prosess som kalles ICE. Som en del av denne prosessen finner WebRTC API-ene din offentlige IP-adresse ved hjelp av STUN-servere og videresender den til reléserveren (SVING) når en direkte forbindelse ikke kan opprettes.

    CloudRetro utnytter imidlertid ikke denne funksjonen fullt ut. Dens peer-to-peer-forbindelser eksisterer ikke mellom brukere, men mellom brukere og skyservere. Serversiden av modellen har færre direkte kommunikasjonsbegrensninger enn en typisk brukerenhet. Dette lar deg forhåndsåpne innkommende porter eller bruke offentlige IP-adresser direkte, siden serveren ikke er bak NAT.

    Tidligere ønsket jeg å gjøre prosjektet om til en spilldistribusjonsplattform for Cloud Gaming. Tanken var å la spillskapere tilby spill og strømmeressurser. Og brukere ville samhandle med leverandører direkte. På denne desentraliserte måten er CloudRetro bare et rammeverk for å koble tredjeparts strømmeressurser til brukere, noe som gjør det mer skalerbart når det ikke lenger er vert. Rollen til WebRTC NAT Traversal her er veldig viktig for å lette initialisering av node-til-node-tilkobling på tredjeparts strømmeressurser, noe som gjør det enklere for skaperen å koble til nettverket.

    Videokomprimering

    Videokomprimering er en uunnværlig del av rørledningen og bidrar sterkt til en jevn flyt. Selv om det ikke er nødvendig å kjenne til alle detaljer i VP8/H264-videokoding, kan forståelsen av konseptene hjelpe deg med å forstå hastighetsalternativer for streaming av video, feilsøke uventet oppførsel og justere ventetiden.

    Å komprimere video for en strømmetjeneste er utfordrende fordi algoritmen skal sørge for at den totale kodetiden + nettverksoverføringstid + dekodingstid er så lav som mulig. I tillegg må kodeprosessen være konsistent og kontinuerlig. Noen avveininger for koding gjelder ikke – for eksempel kan vi ikke favorisere lange kodingstider fremfor mindre filstørrelser og dekodingstider, eller bruke inkonsekvent komprimering.

    Ideen bak videokomprimering er å eliminere unødvendige biter av informasjon og samtidig opprettholde et akseptabelt nivå av nøyaktighet for brukerne. I tillegg til å kode individuelle statiske bilderammer, utleder algoritmen gjeldende ramme fra de forrige og neste, så bare forskjellen deres sendes. Som man kan se fra eksempelet med Pacman, overføres kun differensialpunkter.

    Åpen kildekode-skyspilling på WebRTC: p2p, flerspiller, null ventetid
    Sammenligning av videorammer med Pacman som eksempel

    Lydkomprimering

    På samme måte utelater lydkomprimeringsalgoritmen data som ikke kan oppfattes av mennesker. Opus er for tiden den beste lydkodeken. Den er designet for å overføre en lydbølge over en bestilt datagramprotokoll som RTP (Real Time Transport Protocol). Latenstiden er lavere enn mp3 og aac, og kvaliteten er høyere. Latensen er vanligvis rundt 5~66,5ms.

    Pion, WebRTC i Golang

    Pant er et åpen kildekode-prosjekt som bringer WebRTC til Golang. I stedet for den vanlige innpakningen av native C++ WebRTC-biblioteker, er Pion en native Golang-implementering av WebRTC med bedre ytelse, Go-integrasjon og versjonskontroll på WebRTC-protokoller.

    Biblioteket muliggjør også streaming med mange flotte innebygde elementer med forsinkelse på under sekunder. Den har sin egen implementering av STUN, DTLS, SCTP, etc. og noen eksperimenter med QUIC og WebAssembly. Dette åpen kildekodebiblioteket i seg selv er en veldig god læringsressurs med utmerket dokumentasjon, nettverksprotokollimplementeringer og kule eksempler.

    Pion-fellesskapet, ledet av en veldig lidenskapelig skaper, er ganske livlig, med mange kvalitetsdiskusjoner om WebRTC. Hvis du er interessert i denne teknologien, bli med http://pion.ly/slack – du vil lære mye nytt.

    Skriver CloudRetro på Golang

    Åpen kildekode-skyspilling på WebRTC: p2p, flerspiller, null ventetid
    Implementering av en arbeider i Go

    Gå til Channels in Action

    Takket være Gos vakre kanaldesign, forenkles problemene med hendelsesstrømming og samtidighet betydelig. Som i diagrammet har forskjellige GoRoutines flere komponenter som kjører parallelt. Hver komponent styrer sin tilstand og kommuniserer gjennom kanaler. Golangs selektive påstand tvinger én atomhendelse til å bli behandlet hver gang i spillet (spilltikk). Dette betyr at ingen låsing er nødvendig for denne utformingen. For eksempel, når en bruker lagrer, kreves et fullstendig øyeblikksbilde av spilltilstanden. Denne tilstanden skal forbli kontinuerlig, logge inn til lagringen er fullført. Under hver spillhake kan backend bare håndtere en lagrings- eller inndataoperasjon, noe som gjør prosesstråden trygg.

    func (e *gameEmulator) gameUpdate() {
    for {
    	select {
    		case <-e.saveOperation:
    			e.saveGameState()
    		case key := <-e.input:
    			e.updateGameState(key)
    		case <-e.done:
    			e.close()
    			return
    	}
        }
    }

    Vifte inn/vifte ut

    Denne Golang-malen passer perfekt til min CrowdPlay- og Multiple Player-brukersak. Etter dette mønsteret er alle brukerinnganger i ett rom innebygd i den sentrale inngangskanalen. Spillmedier distribueres deretter til alle brukere i samme rom. På denne måten oppnår vi delingen av spilltilstanden mellom flere spilløkter til forskjellige brukere.

    Åpen kildekode-skyspilling på WebRTC: p2p, flerspiller, null ventetid
    Synkronisering mellom ulike økter

    Ulemper med Golang

    Golang er ikke perfekt. Kanalen er treg. Sammenlignet med blokkering er Go-kanalen ganske enkelt en enklere måte å håndtere samtidige og gjengede hendelser på, men kanalen gir ikke den beste ytelsen. Det er kompleks blokkeringslogikk under kanalen. Så jeg gjorde noen justeringer av implementeringen, og brukte låser og atomverdier på nytt når jeg byttet ut kanaler for å optimalisere ytelsen.

    I tillegg er søppelsamleren i Golang ustyrt, noe som noen ganger forårsaker mistenkelig lange pauser. Dette forstyrrer i stor grad streaming-applikasjonen i sanntid.

    COG

    Prosjektet bruker det eksisterende open source Golang VP8/H264-biblioteket for mediekomprimering og Libretro for spillemulatorer. Alle disse bibliotekene er ganske enkelt innpakninger av C-biblioteket i Go-bruk COG. Noen av ulempene er oppført i dette innlegget av Dave Cheney. Problemer jeg møtte:

    • manglende evne til å fange et krasj i CGO, selv med Golang RecoveryCrash;
    • unnlatelse av å identifisere ytelsesflaskehalser når vi ikke er i stand til å oppdage detaljerte problemer i CGO.

    Konklusjon

    Jeg nådde målet mitt om å forstå skyspilltjenester og lage en plattform som hjelper meg å spille nostalgiske retrospill med vennene mine på nettet. Dette prosjektet hadde ikke vært mulig uten Pion-biblioteket og støtten fra Pion-fellesskapet. Jeg er ekstremt takknemlig for den intensive utviklingen. De enkle API-ene levert av WebRTC og Pion sørget for sømløs integrasjon. Mitt første proof of concept ble utgitt samme uke, selv om jeg ikke hadde noen forkunnskaper om peer-to-peer (P2P) kommunikasjon.

    Til tross for den enkle integrasjonen, er P2P-streaming virkelig et veldig komplekst område innen informatikk. Hun må forholde seg til kompleksiteten til langvarige nettverksarkitekturer som IP og NAT for å skape en peer-to-peer-sesjon. Mens jeg jobbet med dette prosjektet, fikk jeg mye verdifull kunnskap om nettverk og ytelsesoptimalisering, så jeg oppfordrer alle til å prøve å bygge P2P-produkter ved hjelp av WebRTC.

    CloudRetro imøtekommer alle brukstilfellene jeg forventet fra mitt perspektiv som retrospiller. Imidlertid tror jeg det er mange områder i prosjektet som jeg kan forbedre, for eksempel å gjøre nettverket mer pålitelig og ytelsesdyktig, gi spillgrafikk av høyere kvalitet, eller muligheten til å dele spill mellom brukere. Jeg jobber hardt med dette. Vennligst følg prosjekt og støtt det hvis du liker det.

Kilde: www.habr.com

Legg til en kommentar