Gioco cloud open source su WebRTC: p2p, multiplayer, latenza zero

Gioco cloud open source su WebRTC: p2p, multiplayer, latenza zero
Software come servizio, infrastruttura come servizio, piattaforma come servizio, piattaforma di comunicazione come servizio, videoconferenza come servizio, che dire del cloud gaming come servizio? Ci sono già stati diversi tentativi di creare cloud gaming (Cloud Gaming), come Stadia, recentemente lanciato da Google. Stadi non è nuovo a WebRTC, ma altri possono utilizzare WebRTC allo stesso modo?

Thanh Nguyen ha deciso di testare questa opportunità sul suo progetto open source CloudRetro. CloudRetro è basato su Pion, popolare Libreria WebRTC basata su Go (grazie Shownu dal team di sviluppo di Pion per la loro assistenza nella preparazione di questo articolo). In questo articolo, Thanh fornisce una panoramica dell'architettura del suo progetto e parla anche delle cose utili che ha imparato e delle sfide che ha incontrato durante il suo lavoro.

Iscrizione

L'anno scorso, quando Google ha annunciato Stadia, sono rimasto senza parole. L'idea è così unica e innovativa che mi sono costantemente chiesto come ciò fosse possibile anche con la tecnologia esistente. Il desiderio di comprendere meglio questo argomento mi ha spinto a creare la mia versione di un gioco cloud open source. Il risultato è stato semplicemente fantastico. Di seguito vorrei condividere il processo di lavoro sul mio anno progetto.

TLDR: versione diapositiva breve con evidenziazioni

Perché il cloud gaming è il futuro

Credo che il Cloud Gaming diventerà presto la prossima generazione non solo dei giochi, ma anche di altre aree dell'informatica. Il cloud gaming è l’apice del modello client/server. Questo modello massimizza la gestione del backend e riduce al minimo il lavoro del frontend ospitando la logica di gioco su un server remoto e trasmettendo immagini/audio al client. Il server esegue l'elaborazione pesante, quindi il client non è più in balia delle limitazioni hardware.

Google Stadia ti consente essenzialmente di giocare Giochi AAA (ovvero giochi di successo di fascia alta) su un'interfaccia come YouTube. La stessa metodologia può essere applicata ad altre applicazioni offline pesanti come il sistema operativo o la progettazione grafica 2D/3D, ecc. in modo da poterli eseguire in modo coerente su dispositivi con specifiche basse su più piattaforme.

Gioco cloud open source su WebRTC: p2p, multiplayer, latenza zero
Il futuro di questa tecnologia: immagina se Microsoft Windows 10 funzionasse sul browser Chrome?

Il cloud gaming è tecnicamente impegnativo

Il gaming è una di quelle rare aree in cui è richiesta una risposta costante e veloce da parte dell'utente. Se occasionalmente riscontriamo un ritardo di 2 secondi quando si fa clic su una pagina, ciò è accettabile. I flussi video live tendono a ritardare di qualche secondo, ma offrono comunque un'usabilità ragionevole. Tuttavia, se il gioco rallenta spesso di 500 ms, è semplicemente ingiocabile. Il nostro obiettivo è raggiungere una latenza estremamente bassa in modo che il divario tra input e media sia il più piccolo possibile. Pertanto, l’approccio tradizionale allo streaming video non è applicabile in questo caso.

Gioco cloud open source su WebRTC: p2p, multiplayer, latenza zero
Modello generale di gioco cloud

Progetto open source CloudRetro

Ho deciso di creare un campione di prova di un gioco cloud per vedere se tutto ciò fosse possibile con restrizioni di rete così rigide. Ho scelto Golang per la prova di concetto perché era il linguaggio con cui avevo più familiarità ed era adatto a questa implementazione per molti altri motivi, come ho scoperto in seguito. Go è semplice e si sviluppa molto velocemente; I canali in Go sono ottimi per la gestione del multithreading.

Progetto CloudRetro.io è un servizio di cloud gaming open source per giochi retrò. L'obiettivo del progetto è portare l'esperienza di gioco più confortevole ai tradizionali giochi retrò e aggiungere il multiplayer.
Puoi saperne di più sul progetto qui: https://github.com/giongto35/cloud-game.

Funzionalità CloudRetro

CloudRetro utilizza giochi retrò per dimostrare la potenza del cloud gaming. Ciò ti consente di ottenere molte esperienze di gioco uniche.

  • Portabilità del gioco
    • Riproduzione istantanea all'apertura della pagina; nessun download o installazione necessaria
    • Funziona in un browser mobile, quindi non è necessario alcun software per eseguirlo

  • Le sessioni di gioco possono essere condivise su più dispositivi e archiviate nel cloud per il successivo accesso
  • Il gioco può essere trasmesso in streaming oppure può essere giocato da più utenti contemporaneamente:
    • Crowdplay come TwitchPlayPokemon, solo più multipiattaforma e più in tempo reale
    • Giochi offline online. Molti utenti possono giocare senza configurare una rete. Samurai Shodown ora può essere giocato da 2 giocatori sulla rete CloudRetro

    Gioco cloud open source su WebRTC: p2p, multiplayer, latenza zero
    Versione demo del gioco multiplayer online su diversi dispositivi

    infrastruttura

    Requisiti e stack tecnologico

    Di seguito è riportato un elenco di requisiti che ho impostato prima di iniziare il progetto.

    1. Un giocatore
    Questo requisito potrebbe non sembrare troppo importante o ovvio qui, ma è uno dei miei punti chiave, consente al cloud gaming di stare il più lontano possibile dai tradizionali servizi di streaming. Se ci concentriamo su un gioco per giocatore singolo, possiamo sbarazzarci di un server centralizzato o CDN perché non dobbiamo trasmettere in streaming alle masse. Invece di caricare flussi su un server sink o passare pacchetti a un server WebSocket centralizzato, i flussi di servizio vengono consegnati direttamente all'utente tramite una connessione WebRTC peer-to-peer.

    2. Flusso multimediale a bassa latenza
    Leggendo di Stadia, vedo spesso menzionato WebRTC in alcuni articoli. Mi sono reso conto che WebRTC è una tecnologia eccezionale ed è perfetta per l'uso nel cloud gaming. WebRTC è un progetto che fornisce ai browser Web e alle applicazioni mobili comunicazioni in tempo reale tramite una semplice API. Fornisce connettività peer-to-peer, è ottimizzato per i contenuti multimediali e dispone di codec standard integrati come VP8 e H264.

    Ho dato priorità alla garanzia della migliore esperienza utente possibile piuttosto che al mantenimento di una grafica di alta qualità. Alcune perdite sono accettabili nell'algoritmo. Google Stadia prevede un ulteriore passaggio per ridurre le dimensioni dell'immagine sul server e i frame vengono convertiti in una qualità superiore prima di essere trasmessi ai peer.

    3. Infrastruttura distribuita con routing geografico
    Non importa quanto siano ottimizzati l’algoritmo di compressione e il codice, la rete è ancora il fattore decisivo che contribuisce maggiormente alla latenza. L'architettura deve disporre di un meccanismo per accoppiare il server più vicino all'utente per ridurre il tempo di andata e ritorno (RTT). L'architettura dovrebbe avere 1 coordinatore e diversi server di streaming distribuiti in tutto il mondo: Stati Uniti occidentali, Stati Uniti orientali, Europa, Singapore, Cina. Tutti i server di streaming devono essere completamente isolati. Il sistema può modificare la propria distribuzione quando un server si unisce o lascia la rete. Pertanto, con un traffico elevato, l'aggiunta di server aggiuntivi consente il ridimensionamento orizzontale.

    4. Compatibilità del browser
    Il cloud gaming dà il meglio di sé quando richiede il minimo dagli utenti. Ciò significa che è possibile eseguirlo in un browser. I browser aiutano a rendere l'esperienza di gioco il più confortevole possibile per gli utenti, evitando loro l'installazione di software e hardware. I browser aiutano anche a fornire funzionalità multipiattaforma tra le versioni mobile e desktop. Fortunatamente, WebRTC è ben supportato su una varietà di browser.

    5. Chiara separazione dell'interfaccia di gioco e del servizio
    Considero il servizio di cloud gaming come una piattaforma. Tutti dovrebbero essere in grado di connettere qualsiasi cosa alla piattaforma. Ora mi sono integrato LibRetro con il servizio di cloud gaming perché LibRetro offre una bellissima interfaccia di emulazione di giochi per giochi retrò come SNES, GBA, PS.

    6. Stanze per multiplayer, crowd play e collegamento esterno (deep-link) con il gioco
    CloudRetro supporta molti nuovi gameplay come CrowdPlay e MultiPlayer online per giochi retrò. Se più utenti aprono lo stesso deep-link su computer diversi, vedranno lo stesso gioco in esecuzione e potranno anche parteciparvi.

    Inoltre, gli stati del gioco vengono archiviati nel cloud storage. Ciò consente agli utenti di continuare a giocare in qualsiasi momento su qualsiasi altro dispositivo.

    7. Ridimensionamento orizzontale
    Come ogni SAAS al giorno d’oggi, il cloud gaming deve essere progettato per essere scalabile orizzontalmente. La progettazione coordinatore-lavoratore consente di aggiungere più lavoratori per servire più traffico.

    8. Nessuna connessione a un cloud
    L'infrastruttura di CloudRetro è ospitata su diversi provider cloud (Digital Ocean, Alibaba, provider personalizzato) per diverse regioni. Abilito l'esecuzione in un contenitore Docker per l'infrastruttura e configuro le impostazioni di rete utilizzando uno script bash per evitare di essere bloccato in un unico provider cloud. Combinando questo con NAT Traversal in WebRTC, possiamo avere la flessibilità di distribuire CloudRetro su qualsiasi piattaforma cloud e persino sui computer di qualsiasi utente.

    Progettazione architettonica

    Lavoratore: (o il server di streaming menzionato sopra) moltiplica i giochi, esegue la pipeline di codifica e trasmette in streaming i contenuti multimediali codificati agli utenti. Le istanze di lavoro sono distribuite in tutto il mondo e ogni lavoratore può gestire più sessioni utente contemporaneamente.

    Coordinatore: è responsabile di accoppiare il nuovo utente con il lavoratore più adatto per lo streaming. Il coordinatore interagisce con i lavoratori tramite WebSocket.

    Memorizzazione dello stato del gioco: archiviazione remota centrale per tutti gli stati del gioco. Questa memoria fornisce funzioni importanti come il salvataggio/caricamento remoto.

    Gioco cloud open source su WebRTC: p2p, multiplayer, latenza zero
    Architettura di primo livello di CloudRetro

    Scrittura personalizzata

    Quando un nuovo utente apre CloudRetro nei passaggi 1 e 2 mostrati nella figura seguente, il coordinatore insieme all'elenco dei lavoratori disponibili viene richiesto alla prima pagina. Successivamente, nel passaggio 3 il client calcola i ritardi per tutti i candidati utilizzando una richiesta ping HTTP. Questo elenco di ritardi viene poi rinviato al coordinatore affinché possa determinare il lavoratore più adatto a servire l'utente. Il passaggio 4 di seguito crea il gioco. Viene stabilita una connessione di streaming WebRTC tra l'utente e il lavoratore assegnato.
    Gioco cloud open source su WebRTC: p2p, multiplayer, latenza zero
    Script utente dopo aver ottenuto l'accesso

    Cosa c'è dentro il lavoratore

    Le pipeline di gioco e di streaming vengono archiviate all'interno del lavoratore in modo isolato e lì scambiano informazioni attraverso l'interfaccia. Attualmente questa comunicazione viene effettuata trasferendo i dati in memoria tramite Canali Golang nello stesso processo. Il prossimo obiettivo è la segregazione, vale a dire lancio indipendente del gioco in un altro processo.

    Gioco cloud open source su WebRTC: p2p, multiplayer, latenza zero
    Interazione dei componenti del lavoratore

    Componenti principali:

    • WebRTC: un componente client che accetta l'input dell'utente e restituisce contenuti multimediali codificati dal server.
    • Emulatore di gioco: componente di gioco. Grazie alla libreria Libretro, il sistema è in grado di eseguire il gioco all'interno dello stesso processo e intercettare internamente media e flusso di input.
    • I fotogrammi del gioco vengono catturati e inviati al codificatore.
    • Codificatore immagine/audio: una pipeline di codifica che accetta fotogrammi multimediali, li codifica in background e restituisce immagini/audio codificati.

    implementazione

    CloudRetro si basa su WebRTC come tecnologia portante, quindi prima di immergermi nei dettagli dell'implementazione Golang, ho deciso di parlare di WebRTC stesso. Questa è una tecnologia straordinaria che mi ha aiutato molto a raggiungere una latenza inferiore al secondo per lo streaming di dati.

    WebRTC

    WebRTC è progettato per fornire connessioni peer-to-peer di alta qualità su browser e app mobili nativi utilizzando API semplici.

    NAT Attraversamento

    WebRTC è noto per la sua funzionalità NAT Traversal. WebRTC è progettato per la comunicazione peer-to-peer. Il suo obiettivo è trovare il percorso diretto più adatto, evitando gateway NAT e firewall per la comunicazione peer-to-peer attraverso un processo chiamato ICE. Come parte di questo processo, le API WebRTC trovano il tuo indirizzo IP pubblico utilizzando i server STUN e lo inoltrano al server di inoltro (TURNO) quando non è possibile stabilire una connessione diretta.

    Tuttavia, CloudRetro non sfrutta appieno questa funzionalità. Le sue connessioni peer-to-peer non esistono tra utenti, ma tra utenti e server cloud. Il lato server del modello presenta meno restrizioni di comunicazione diretta rispetto a un tipico dispositivo utente. Ciò consente di pre-aprire le porte in entrata o di utilizzare direttamente gli indirizzi IP pubblici, poiché il server non è dietro NAT.

    In precedenza, volevo trasformare il progetto in una piattaforma di distribuzione di giochi per Cloud Gaming. L'idea era quella di consentire ai creatori di giochi di fornire giochi e risorse di streaming. E gli utenti interagirebbero direttamente con i fornitori. In questo modo decentralizzato, CloudRetro è solo un framework per connettere risorse di streaming di terze parti agli utenti, rendendolo più scalabile quando non è più ospitato. Il ruolo di WebRTC NAT Traversal qui è molto importante per facilitare l'inizializzazione della connessione peer-to-peer su risorse di streaming di terze parti, rendendo più semplice per il creatore connettersi alla rete.

    Compressione video

    La compressione video è una parte indispensabile della pipeline e contribuisce notevolmente a un flusso fluido. Sebbene non sia necessario conoscere ogni dettaglio della codifica video VP8/H264, la comprensione dei concetti può aiutarti a comprendere le opzioni di velocità del video in streaming, eseguire il debug di comportamenti imprevisti e regolare la latenza.

    La compressione di video per un servizio di streaming è impegnativa perché l'algoritmo deve garantire che il tempo totale di codifica + tempo di trasmissione in rete + tempo di decodifica sia il più basso possibile. Inoltre, il processo di codifica deve essere coerente e continuo. Alcuni compromessi di codifica non sono applicabili: ad esempio, non possiamo favorire tempi di codifica lunghi rispetto a dimensioni di file e tempi di decodifica inferiori oppure utilizzare una compressione incoerente.

    L'idea alla base della compressione video è eliminare le informazioni non necessarie mantenendo un livello accettabile di precisione per gli utenti. Oltre a codificare i singoli fotogrammi di immagini statiche, l'algoritmo deduce il fotogramma corrente da quelli precedenti e successivi, quindi viene inviata solo la loro differenza. Come si può vedere dall'esempio con Pacman, vengono trasmessi solo i punti differenziali.

    Gioco cloud open source su WebRTC: p2p, multiplayer, latenza zero
    Confronto di fotogrammi video utilizzando Pacman come esempio

    Compressione audio

    Allo stesso modo, l'algoritmo di compressione audio omette i dati che non possono essere percepiti dagli esseri umani. Opus è attualmente il codec audio più performante. È progettato per trasmettere un'onda audio su un protocollo di datagramma ordinato come RTP (Real Time Transport Protocol). La sua latenza è inferiore a quella di mp3 e aac e la qualità è superiore. La latenza è solitamente di circa 5~66,5 ms.

    Pion, WebRTC a Golang

    pion è un progetto open source che porta WebRTC a Golang. Invece del solito avvolgimento di librerie C++ WebRTC native, Pion è un'implementazione Golang nativa di WebRTC con prestazioni migliori, integrazione Go e controllo della versione sui protocolli WebRTC.

    La libreria consente anche lo streaming con molti ottimi integrati con una latenza inferiore al secondo. Ha la propria implementazione di STUN, DTLS, SCTP, ecc. e alcuni esperimenti con QUIC e WebAssembly. Questa stessa libreria open source è un'ottima risorsa di apprendimento con un'eccellente documentazione, implementazioni di protocolli di rete ed esempi interessanti.

    La community di Pion, guidata da un creatore molto appassionato, è piuttosto vivace, con molte discussioni di qualità in corso su WebRTC. Se sei interessato a questa tecnologia, iscriviti http://pion.ly/slack – imparerai molte cose nuove.

    Scrivere CloudRetro in Golang

    Gioco cloud open source su WebRTC: p2p, multiplayer, latenza zero
    Implementazione di un lavoratore in Go

    Vai a Canali in azione

    Grazie al bellissimo design dei canali di Go, i problemi di streaming e concorrenza degli eventi sono notevolmente semplificati. Come nel diagramma, diverse GoRoutine hanno più componenti che funzionano in parallelo. Ogni componente gestisce il proprio stato e comunica attraverso canali. L'asserzione selettiva di Golang forza l'elaborazione di un evento atomico ogni volta nel gioco (tick del gioco). Ciò significa che per questo modello non è necessario alcun bloccaggio. Ad esempio, quando un utente salva, è necessaria un'istantanea completa dello stato del gioco. Questo stato dovrebbe rimanere continuo, accedendo fino al completamento del salvataggio. Durante ogni tick del gioco, il backend può gestire solo un'operazione di salvataggio o di input, rendendo il thread del processo sicuro.

    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

    Questo modello Golang si adatta perfettamente al mio caso d'uso CrowdPlay e Multiple Player. Seguendo questo schema, tutti gli ingressi degli utenti in una stanza vengono integrati nel canale d'ingresso centrale. Il supporto di gioco viene quindi distribuito a tutti gli utenti nella stessa stanza. In questo modo otteniamo la suddivisione dello stato del gioco tra più sessioni di gioco di diversi utenti.

    Gioco cloud open source su WebRTC: p2p, multiplayer, latenza zero
    Sincronizzazione tra diverse sessioni

    Svantaggi di Golang

    Golang non è perfetto. Il canale è lento. Rispetto al blocco, il canale Go è semplicemente un modo più semplice per gestire eventi simultanei e concatenati, ma il canale non offre le prestazioni migliori. Sotto il canale è presente una complessa logica di blocco. Quindi ho apportato alcune modifiche all'implementazione, riapplicando blocchi e valori atomici durante la sostituzione dei canali per ottimizzare le prestazioni.

    Inoltre, il garbage collector di Golang non è gestito, il che a volte causa pause sospettosamente lunghe. Ciò interferisce notevolmente con l'applicazione di streaming in tempo reale.

    COG

    Il progetto utilizza la libreria open source esistente Golang VP8/H264 per la compressione multimediale e Libretro per gli emulatori di giochi. Tutte queste librerie sono semplicemente wrapper della libreria C in Go COG. Alcuni degli svantaggi sono elencati in questo post di Dave Cheney. Problemi che ho riscontrato:

    • incapacità di rilevare un arresto anomalo in CGO, anche con Golang RecoveryCrash;
    • incapacità di identificare i colli di bottiglia delle prestazioni quando non siamo in grado di rilevare problemi dettagliati in CGO.

    conclusione

    Ho raggiunto il mio obiettivo di comprendere i servizi di cloud gaming e di creare una piattaforma che mi aiuti a giocare a giochi retrò nostalgici con i miei amici online. Questo progetto non sarebbe stato possibile senza la biblioteca Pion e il supporto della comunità Pion. Sono estremamente grato per il suo intenso sviluppo. Le semplici API fornite da WebRTC e Pion hanno garantito un'integrazione perfetta. La mia prima prova di concetto è stata rilasciata quella stessa settimana, anche se non avevo alcuna conoscenza preliminare della comunicazione peer-to-peer (P2P).

    Nonostante la facilità di integrazione, lo streaming P2P è davvero un’area molto complessa dell’informatica. Deve affrontare la complessità delle architetture di rete di lunga data come IP e NAT per creare una sessione peer-to-peer. Mentre lavoravo a questo progetto, ho acquisito molte preziose conoscenze sul networking e sull'ottimizzazione delle prestazioni, quindi incoraggio tutti a provare a creare prodotti P2P utilizzando WebRTC.

    CloudRetro soddisfa tutti i casi d'uso che mi aspettavo dal mio punto di vista di giocatore retrò. Tuttavia, penso che ci siano molte aree del progetto che posso migliorare, come rendere la rete più affidabile e performante, fornire grafica di gioco di qualità superiore o la possibilità di condividere giochi tra utenti. Ci sto lavorando duro. Per favore Segui progetto e sostienilo se ti piace.

Fonte: habr.com

Aggiungi un commento