Molnspelande med öppen källkod på WebRTC: p2p, multiplayer, noll latens

Molnspelande med öppen källkod på WebRTC: p2p, multiplayer, noll latens
Programvara som tjänst, infrastruktur som tjänst, plattform som tjänst, kommunikationsplattform som tjänst, videokonferens som tjänst, hur är det med molnspel som tjänst? Det har redan gjorts flera försök att skapa molnspel (Cloud Gaming), som Stadia, nyligen lanserat av Google. Stadia inte ny för WebRTC, men kan andra använda WebRTC på samma sätt?

Thanh Nguyen bestämde sig för att testa denna möjlighet på sitt open source-projekt CloudRetro. CloudRetro är baserat på Pion, populär WebRTC-bibliotek baserat på Go (tack Visad från Pions utvecklingsteam för deras hjälp med att förbereda denna artikel). I den här artikeln ger Thanh en översikt över sitt projekts arkitektur och berättar också om vilka användbara saker han lärde sig och vilka utmaningar han stötte på under sitt arbete.

Entry

Förra året, när Google tillkännagav Stadia, fick det mig att tänka. Idén är så unik och innovativ att jag hela tiden undrade hur detta ens var möjligt med befintlig teknik. Önskan att bättre förstå detta ämne fick mig att skapa min egen version av ett molnspel med öppen källkod. Resultatet blev helt enkelt fantastiskt. Nedan skulle jag vilja dela processen med att arbeta på mitt år projekt.

TLDR: version med kort bild med höjdpunkter

Varför molnspel är framtiden

Jag tror att Cloud Gaming snart kommer att bli nästa generation av inte bara spel, utan även andra områden inom datavetenskap. Molnspel är toppen av klient/servermodellen. Denna modell maximerar backend-hanteringen och minimerar frontend-arbetet genom att hosta spellogik på en fjärrserver och strömma bilder/ljud till klienten. Servern gör den tunga behandlingen så att klienten inte längre är utlämnad till hårdvarubegränsningar.

Google Stadia låter dig spela AAA-spel (dvs. avancerade blockbuster-spel) på ett gränssnitt som YouTube. Samma metodik kan tillämpas på andra tunga offlineapplikationer som operativsystem eller 2D/3D grafisk design, etc. så att vi kan köra dem konsekvent på lågspecifika enheter på flera plattformar.

Molnspelande med öppen källkod på WebRTC: p2p, multiplayer, noll latens
Framtiden för denna teknik: Tänk om Microsoft Windows 10 kördes på webbläsaren Chrome?

Molnspelande är tekniskt utmanande

Spel är ett av de sällsynta områden där konstant, snabb användarrespons krävs. Om vi ​​ibland stöter på en 2 sekunders fördröjning när vi klickar på en sida, är detta acceptabelt. Livevideoströmmar tenderar att släpa efter några sekunder, men erbjuder fortfarande en rimlig användbarhet. Men om spelet ofta släpar med 500 ms är det helt enkelt ospelbart. Vårt mål är att uppnå extremt låg latens så att gapet mellan input och media blir så litet som möjligt. Därför är den traditionella metoden för videoströmning inte tillämplig här.

Molnspelande med öppen källkod på WebRTC: p2p, multiplayer, noll latens
Allmän molnspelmall

Öppen källkod-projekt CloudRetro

Jag bestämde mig för att skapa ett testprov av ett molnspel för att se om allt detta var möjligt med så snäva nätverksbegränsningar. Jag valde Golang som proof of concept eftersom det var det språk jag var mest bekant med och var väl lämpad för denna implementering av många andra skäl, som jag senare upptäckte. Go är enkelt och utvecklas mycket snabbt; Kanaler i Go är bra för att hantera multithreading.

Projekt CloudRetro.io är en molnspeltjänst med öppen källkod för retrospel. Målet med projektet är att tillföra den mest bekväma spelupplevelsen till traditionella retrospel och lägga till multiplayer.
Du kan lära dig mer om projektet här: https://github.com/giongto35/cloud-game.

CloudRetro-funktionalitet

CloudRetro använder retrospel för att demonstrera kraften i molnspel. Vilket gör att du kan få många unika spelupplevelser.

  • Portabilitet av spelet
    • Omedelbar uppspelning när du öppnar sidan; ingen nedladdning eller installation behövs
    • Fungerar i en mobil webbläsare, så ingen programvara behövs för att köra den

  • Spelsessioner kan delas på flera enheter och lagras i molnet för nästa gång du loggar in
  • Spelet kan streamas eller spelas av flera användare samtidigt:
    • Crowdplay som TwitchPlayPokemon, bara mer plattformsoberoende och mer i realtid
    • Offlinespel online. Många användare kan spela utan att konfigurera ett nätverk. Samurai Shodown kan nu spelas av 2 spelare över CloudRetro-nätverket

    Molnspelande med öppen källkod på WebRTC: p2p, multiplayer, noll latens
    Demoversion av online multiplayer-spel på olika enheter

    Infrastruktur

    Krav och teknikstapel

    Nedan följer en lista med krav som jag ställer innan jag startar projektet.

    1. En spelare
    Detta krav kanske inte verkar så viktigt eller självklart här, men det är en av mina viktigaste takeaways, det tillåter molnspel att hålla sig så långt borta från traditionella streamingtjänster som möjligt. Om vi ​​fokuserar på ett enspelarspel kan vi bli av med en centraliserad server eller CDN eftersom vi inte behöver streama till massorna. Istället för att ladda upp strömmar till en sink-server eller skicka paket till en centraliserad WebSocket-server, levereras tjänstströmmar direkt till användaren via en peer-to-peer WebRTC-anslutning.

    2. Mediaström med låg latens
    När jag läser om Stadia ser jag ofta att WebRTC nämns i vissa artiklar. Jag insåg att WebRTC är en enastående teknik och är perfekt för användning i molnspel. WebRTC är ett projekt som förser webbläsare och mobilapplikationer med kommunikation i realtid genom ett enkelt API. Den ger peer-to-peer-anslutning, är optimerad för media och har inbyggda standardcodecs som VP8 och H264.

    Jag prioriterade att säkerställa bästa möjliga användarupplevelse framför att upprätthålla grafik av hög kvalitet. Vissa förluster är acceptabla i algoritmen. Google Stadia har ett extra steg för att minska bildstorleken på servern, och ramar skalas upp till en högre kvalitet innan de överförs till kamrater.

    3. Distribuerad infrastruktur med geografisk routing
    Oavsett hur optimerad komprimeringsalgoritmen och koden är, är nätverket fortfarande den avgörande faktorn som bidrar mest till latensen. Arkitekturen måste ha en mekanism för att para ihop servern närmast användaren för att minska tur och returtid (RTT). Arkitekturen måste ha 1 samordnare och flera streamingservrar distribuerade över hela världen: västra USA, östra USA, Europa, Singapore, Kina. Alla streamingservrar måste vara helt isolerade. Systemet kan justera sin distribution när en server ansluter till eller lämnar nätverket. Således, med stor trafik, kan lägga till ytterligare servrar för horisontell skalning.

    4. Webbläsarkompatibilitet
    Molnspel är som bäst när det kräver minst av användarna. Det betyder att det går att köra i en webbläsare. Webbläsare hjälper till att göra spelupplevelsen så bekväm som möjligt för användarna och räddar dem från att installera mjukvara och hårdvara. Webbläsare hjälper också till att tillhandahålla plattformsoberoende funktionalitet mellan mobila och stationära versioner. Lyckligtvis stöds WebRTC väl i en mängd olika webbläsare.

    5. Tydlig separation av spelgränssnittet och tjänsten
    Jag ser molnspeltjänsten som en plattform. Alla ska kunna koppla vad som helst till plattformen. Nu har jag integrerat LibRetro med molnspeltjänst eftersom LibRetro erbjuder ett vackert spelemulatorgränssnitt för retrospel som SNES, GBA, PS.

    6. Rum för multiplayer, publikspel och extern länkning (djuplänk) med spelet
    CloudRetro stöder många nya spel som CrowdPlay och Online MultiPlayer för retrospel. Om flera användare öppnar samma djuplänk på olika datorer kommer de att se samma pågående spel och till och med kunna gå med i det.

    Dessutom lagras speltillstånd i molnlagring. Detta tillåter användare att fortsätta spela när som helst på vilken annan enhet som helst.

    7. Horisontell skalning
    Som alla SAAS nuförtiden måste molnspel utformas för att vara horisontellt skalbara. Koordinator-arbetardesignen gör att du kan lägga till fler arbetare för att betjäna mer trafik.

    8. Ingen anslutning till ett moln
    CloudRetros infrastruktur finns hos olika molnleverantörer (Digital Ocean, Alibaba, anpassad leverantör) för olika regioner. Jag möjliggör körning i en Docker-behållare för infrastrukturen och konfigurerar nätverksinställningar med ett bash-skript för att undvika att bli låst till en enda molnleverantör. Genom att kombinera detta med NAT Traversal i WebRTC kan vi ha flexibiliteten att distribuera CloudRetro på vilken molnplattform som helst och till och med på alla användares maskiner.

    Arkitektonisk design

    Arbetstagare: (eller streamingservern som nämns ovan) multiplicerar spelen, kör kodningspipelinen och strömmar det kodade mediet till användarna. Arbetarinstanser är distribuerade över hela världen och varje arbetare kan hantera flera användarsessioner samtidigt.

    Samordnare: är ansvarig för att para ihop den nya användaren med den mest lämpliga arbetaren för streaming. Koordinatorn interagerar med arbetare via WebSocket.

    Lagring av spelstatus: central fjärrlagring för alla spellägen. Denna lagring tillhandahåller viktiga funktioner såsom fjärrspara/ladda.

    Molnspelande med öppen källkod på WebRTC: p2p, multiplayer, noll latens
    Toppnivåarkitektur för CloudRetro

    Anpassat skript

    När en ny användare öppnar CloudRetro i steg 1 och 2 som visas i figuren nedan, uppmanas koordinatorn tillsammans med listan över tillgängliga arbetare till första sidan. Efter detta, i steg 3, beräknar klienten fördröjningarna för alla kandidater med hjälp av en HTTP-ping-begäran. Denna lista över förseningar skickas sedan tillbaka till samordnaren så att han kan bestämma den mest lämpliga arbetaren för att betjäna användaren. Steg 4 nedan skapar spelet. En WebRTC-strömningsanslutning upprättas mellan användaren och den tilldelade arbetaren.
    Molnspelande med öppen källkod på WebRTC: p2p, multiplayer, noll latens
    Användarskript efter att ha fått åtkomst

    Vad som finns inuti arbetaren

    Spel- och streamingpipelines lagras inuti arbetaren isolerat och utbyter information där genom gränssnittet. För närvarande sker denna kommunikation genom att överföra data i minnet via Golang-kanaler i samma process. Nästa mål är segregation, d.v.s. oberoende lansering av spelet i en annan process.

    Molnspelande med öppen källkod på WebRTC: p2p, multiplayer, noll latens
    Interaktion mellan arbetarkomponenter

    Huvudkomponenter:

    • WebRTC: en klientkomponent som accepterar användarinmatning och matar ut kodade media från servern.
    • Spelemulator: spelkomponent. Tack vare Libretro-biblioteket kan systemet köra spelet i samma process och internt fånga upp media och indataström.
    • Ramar i spelet fångas och skickas till kodaren.
    • Bild-/ljudkodare: en kodningspipeline som tar mediaramar, kodar dem i bakgrunden och matar ut kodade bilder/ljud.

    genomförande

    CloudRetro förlitar sig på WebRTC som sin ryggradsteknik, så innan jag dyker in i detaljerna i Golang-implementeringen bestämde jag mig för att prata om själva WebRTC. Det här är fantastisk teknik som har hjälpt mig mycket med att uppnå en fördröjning på under sekunder för streaming av data.

    WebRTC

    WebRTC är designat för att tillhandahålla högkvalitativa peer-to-peer-anslutningar på inbyggda mobilappar och webbläsare med enkla API:er.

    NAT Traversal

    WebRTC är känt för sin NAT Traversal-funktionalitet. WebRTC är designad för peer-to-peer-kommunikation. Dess mål är att hitta den mest lämpliga direktvägen och undvika NAT-gateways och brandväggar för peer-to-peer-kommunikation genom en process som kallas IS. Som en del av denna process hittar WebRTC API:erna din offentliga IP-adress med hjälp av STUN-servrar och vidarebefordrar den till reläservern (SVÄNG) när en direkt anslutning inte kan upprättas.

    CloudRetro utnyttjar dock inte den här funktionen fullt ut. Dess peer-to-peer-förbindelser existerar inte mellan användare, utan mellan användare och molnservrar. Serversidan av modellen har färre direktkommunikationsbegränsningar än en vanlig användarenhet. Detta gör att du kan föröppna inkommande portar eller använda offentliga IP-adresser direkt, eftersom servern inte ligger bakom NAT.

    Tidigare har jag velat förvandla projektet till en speldistributionsplattform för Cloud Gaming. Tanken var att tillåta spelskapare att tillhandahålla spel och streamingresurser. Och användare skulle interagera med leverantörer direkt. På detta decentraliserade sätt är CloudRetro bara ett ramverk för att koppla strömningsresurser från tredje part till användare, vilket gör det mer skalbart när det inte längre är värd. WebRTC NAT Traversals roll här är mycket viktig för att underlätta initiering av peer-to-peer-anslutningar på strömningsresurser från tredje part, vilket gör det lättare för skaparen att ansluta till nätverket.

    Videokomprimering

    Videokomprimering är en oumbärlig del av pipelinen och bidrar i hög grad till ett jämnt flöde. Även om det inte är nödvändigt att känna till varje detalj av VP8/H264-videokodning, kan en förståelse av koncepten hjälpa dig att förstå hastighetsalternativ för streaming av video, felsöka oväntat beteende och justera latens.

    Att komprimera video för en streamingtjänst är utmanande eftersom algoritmen måste säkerställa att den totala kodningstiden + nätverkets överföringstid + avkodningstiden är så låg som möjligt. Dessutom måste kodningsprocessen vara konsekvent och kontinuerlig. Vissa avvägningar för kodning gäller inte – till exempel kan vi inte gynna långa kodningstider framför mindre filstorlekar och avkodningstider, eller använda inkonsekvent komprimering.

    Tanken bakom videokomprimering är att eliminera onödiga informationsbitar samtidigt som en acceptabel nivå av noggrannhet för användarna bibehålls. Förutom att koda enskilda statiska bildramar, sluter algoritmen den aktuella bildrutan från de föregående och nästa, så endast deras skillnad skickas. Som framgår av exemplet med Pacman sänds endast differentialpunkter.

    Molnspelande med öppen källkod på WebRTC: p2p, multiplayer, noll latens
    Jämförelse av videoramar med Pacman som exempel

    Ljudkomprimering

    På samma sätt utelämnar ljudkomprimeringsalgoritmen data som inte kan uppfattas av människor. Opus är för närvarande den bäst presterande ljud-codec. Den är utformad för att sända en ljudvåg över ett beställt datagramprotokoll som RTP (Real Time Transport Protocol). Dess latens är lägre än mp3 och aac, och kvaliteten är högre. Latensen är vanligtvis runt 5~66,5ms.

    Pion, WebRTC i Golang

    pion är ett projekt med öppen källkod som tar WebRTC till Golang. Istället för den vanliga inpackningen av inbyggda C++ WebRTC-bibliotek, är Pion en inbyggd Golang-implementering av WebRTC med bättre prestanda, Go-integrering och versionskontroll på WebRTC-protokoll.

    Biblioteket möjliggör också streaming med många fantastiska inbyggda funktioner med latens på under sekunder. Den har sin egen implementering av STUN, DTLS, SCTP, etc. och några experiment med QUIC och WebAssembly. Detta bibliotek med öppen källkod i sig är en riktigt bra inlärningsresurs med utmärkt dokumentation, implementeringar av nätverksprotokoll och coola exempel.

    Pion-communityt, som leds av en mycket passionerad skapare, är ganska livligt, med många kvalitetsdiskussioner som pågår om WebRTC. Om du är intresserad av denna teknik, gå med http://pion.ly/slack – du kommer att lära dig mycket nytt.

    Skriver CloudRetro i Golang

    Molnspelande med öppen källkod på WebRTC: p2p, multiplayer, noll latens
    Implementering av en arbetare i Go

    Gå Channels in Action

    Tack vare Gos vackra kanaldesign förenklas problemen med händelseströmning och samtidighet avsevärt. Som i diagrammet har olika GoRoutines flera komponenter som körs parallellt. Varje komponent hanterar sitt tillstånd och kommunicerar via kanaler. Golangs selektiva påstående tvingar en atomhändelse att bearbetas varje gång i spelet (game tick). Detta innebär att ingen låsning behövs för denna design. Till exempel, när en användare sparar, krävs en fullständig ögonblicksbild av spelets tillstånd. Detta tillstånd bör förbli kontinuerligt, logga in tills lagringen är klar. Under varje speltick kan backend endast hantera en spara eller inmatning, vilket gör processtråden säker.

    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

    Denna Golang-mall passar min CrowdPlay och Multiple Player-användning perfekt. Efter detta mönster är alla användaringångar i ett rum inbyggda i den centrala entrékanalen. Spelmedia distribueras sedan till alla användare i samma rum. På så sätt uppnår vi uppdelningen av speltillståndet mellan flera spelsessioner för olika användare.

    Molnspelande med öppen källkod på WebRTC: p2p, multiplayer, noll latens
    Synkronisering mellan olika sessioner

    Nackdelar med Golang

    Golang är inte perfekt. Kanalen är långsam. Jämfört med blockering är Go-kanalen helt enkelt ett enklare sätt att hantera samtidiga och trådade händelser, men kanalen ger inte den bästa prestandan. Det finns komplex blockeringslogik under kanalen. Så jag gjorde några justeringar av implementeringen, genom att återanvända lås och atomvärden när jag bytte kanaler för att optimera prestandan.

    Dessutom är sophämtaren i Golang ohanterad, vilket ibland orsakar misstänkt långa pauser. Detta stör avsevärt realtidsströmningsapplikationen.

    KUGGE

    Projektet använder det befintliga Golang VP8/H264-biblioteket med öppen källkod för mediakomprimering och Libretro för spelemulatorer. Alla dessa bibliotek är helt enkelt omslag av C-biblioteket i Go KUGGE. Några av nackdelarna är listade i detta inlägg av Dave Cheney. Problem jag stötte på:

    • oförmåga att fånga en krasch i CGO, även med Golang RecoveryCrash;
    • misslyckande med att identifiera prestandaflaskhalsar när vi inte kan upptäcka detaljerade problem i CGO.

    Slutsats

    Jag uppnådde mitt mål att förstå molnspeltjänster och skapa en plattform som hjälper mig att spela nostalgiska retrospel med mina vänner online. Detta projekt hade inte varit möjligt utan Pion-biblioteket och stödet från Pion-gemenskapen. Jag är oerhört tacksam för dess intensiva utveckling. De enkla API:erna från WebRTC och Pion säkerställde sömlös integration. Mitt första proof of concept släpptes samma vecka, även om jag inte hade några förkunskaper om peer-to-peer (P2P) kommunikation.

    Trots den enkla integrationen är P2P-streaming verkligen ett mycket komplext område inom datavetenskap. Hon måste hantera komplexiteten hos långvariga nätverksarkitekturer som IP och NAT för att skapa en peer-to-peer-session. Under arbetet med det här projektet fick jag mycket värdefull kunskap om nätverk och prestandaoptimering, så jag uppmuntrar alla att prova att bygga P2P-produkter med WebRTC.

    CloudRetro tillgodoser alla användningsfall jag förväntade mig ur mitt perspektiv som retrospelare. Jag tror dock att det finns många områden i projektet som jag kan förbättra, som att göra nätverket mer pålitligt och prestanda, tillhandahålla spelgrafik av högre kvalitet eller möjligheten att dela spel mellan användare. Jag jobbar hårt på det här. Var vänlig följ projekt och stödja det om du gillar det.

Källa: will.com

Lägg en kommentar