Cloud gaming open source sur WebRTC : p2p, multijoueur, zéro latence

Cloud gaming open source sur WebRTC : p2p, multijoueur, zéro latence
Logiciel en tant que service, infrastructure en tant que service, plateforme en tant que service, plateforme de communication en tant que service, vidéoconférence en tant que service, qu'en est-il du cloud gaming en tant que service ? Il y a déjà eu plusieurs tentatives de création de cloud gaming (Cloud Gaming), comme Stadia, récemment lancé par Google. Stades pas nouveau sur WebRTC, mais d'autres peuvent-ils utiliser WebRTC de la même manière ?

Thanh Nguyen a décidé de tester cette opportunité sur son projet open source CloudRetro. CloudRetro est basé sur Pion, populaire Bibliothèque WebRTC basée sur Go (merci Affichernu de l'équipe de développement de Pion pour son aide dans la préparation de cet article). Dans cet article, Thanh donne un aperçu de l'architecture de son projet, et parle également des choses utiles qu'il a apprises et des défis qu'il a rencontrés au cours de son travail.

Entrée

L’année dernière, lorsque Google a annoncé Stadia, cela m’a époustouflé. L’idée est si unique et innovante que je me demandais constamment comment cela était possible avec la technologie existante. Le désir de mieux comprendre ce sujet m'a incité à créer ma propre version d'un jeu cloud open source. Le résultat était tout simplement fantastique. Ci-dessous, j'aimerais partager le processus de travail sur mon année projet.

TLDR : version courte de diapositives avec faits saillants

Pourquoi le cloud gaming est l'avenir

Je pense que le Cloud Gaming deviendra bientôt la prochaine génération non seulement du jeu, mais aussi d'autres domaines de l'informatique. Le cloud gaming est le summum du modèle client/serveur. Ce modèle maximise la gestion du back-end et minimise le travail du front-end en hébergeant la logique du jeu sur un serveur distant et en diffusant des images/audio vers le client. Le serveur effectue le traitement lourd afin que le client ne soit plus à la merci des limitations matérielles.

Google Stadia vous permet essentiellement de jouer Jeux AAA (c'est-à-dire des jeux à succès haut de gamme) sur une interface comme YouTube. La même méthodologie peut être appliquée à d’autres applications lourdes hors ligne telles que le système d’exploitation ou la conception graphique 2D/3D, etc. afin que nous puissions les exécuter de manière cohérente sur des appareils peu performants sur plusieurs plates-formes.

Cloud gaming open source sur WebRTC : p2p, multijoueur, zéro latence
L'avenir de cette technologie : imaginez si Microsoft Windows 10 fonctionnait sur le navigateur Chrome ?

Le cloud gaming est un défi technique

Le jeu est l’un des rares domaines où une réponse constante et rapide de l’utilisateur est requise. Si occasionnellement nous rencontrons un délai de 2 secondes en cliquant sur une page, cela est acceptable. Les flux vidéo en direct ont tendance à prendre quelques secondes, mais offrent toujours une convivialité raisonnable. Cependant, si le jeu est souvent en retard de 500 ms, il est tout simplement injouable. Notre objectif est d'obtenir une latence extrêmement faible afin que l'écart entre l'entrée et le média soit aussi réduit que possible. Par conséquent, l’approche traditionnelle du streaming vidéo n’est pas applicable ici.

Cloud gaming open source sur WebRTC : p2p, multijoueur, zéro latence
Modèle de jeu cloud général

Projet open source CloudRetro

J'ai décidé de créer un échantillon test d'un jeu cloud pour voir si tout cela était possible avec des restrictions de réseau aussi strictes. J'ai choisi Golang pour la preuve de concept car c'était le langage que je connaissais le mieux et qui était bien adapté à cette implémentation pour de nombreuses autres raisons, comme je l'ai découvert plus tard. Go est simple et se développe très rapidement ; Les canaux dans Go sont parfaits pour gérer le multithreading.

Projet CloudRetro.io est un service de jeu cloud open source pour les jeux rétro. L'objectif du projet est d'apporter l'expérience de jeu la plus confortable aux jeux rétro traditionnels et d'ajouter le mode multijoueur.
Vous pouvez en savoir plus sur le projet ici : https://github.com/giongto35/cloud-game.

Fonctionnalité CloudRetro

CloudRetro utilise des jeux rétro pour démontrer la puissance du cloud gaming. Ce qui vous permet de vivre de nombreuses expériences de jeu uniques.

  • Portabilité du jeu
    • Lecture instantanée à l'ouverture de la page ; aucun téléchargement ou installation nécessaire
    • Fonctionne dans un navigateur mobile, aucun logiciel n'est donc nécessaire pour l'exécuter

  • Les sessions de jeu peuvent être partagées sur plusieurs appareils et stockées dans le cloud pour la prochaine connexion
  • Le jeu peut être diffusé en streaming ou joué par plusieurs utilisateurs à la fois :
    • Crowdplay comme TwitchPlayPokemon, mais en plus multiplateforme et plus en temps réel
    • Jeux hors ligne en ligne. De nombreux utilisateurs peuvent jouer sans configurer de réseau. Samurai Shodown peut désormais être joué à 2 joueurs sur le réseau CloudRetro

    Cloud gaming open source sur WebRTC : p2p, multijoueur, zéro latence
    Version démo du jeu multijoueur en ligne sur différents appareils

    Infrastructure

    Exigences et pile technologique

    Vous trouverez ci-dessous une liste d'exigences que j'ai définies avant de démarrer le projet.

    1. Un joueur
    Cette exigence ne semble peut-être pas trop importante ou évidente ici, mais c'est l'un de mes principaux points à retenir : elle permet au cloud gaming de rester aussi éloigné que possible des services de streaming traditionnels. Si nous nous concentrons sur un jeu solo, nous pouvons nous débarrasser d'un serveur centralisé ou d'un CDN car nous n'avons pas besoin de diffuser en masse. Au lieu de télécharger des flux vers un serveur récepteur ou de transmettre des paquets à un serveur WebSocket centralisé, les flux de service sont fournis directement à l'utilisateur via une connexion WebRTC peer-to-peer.

    2. Flux multimédia à faible latence
    En lisant sur Stadia, je vois souvent WebRTC mentionné dans certains articles. J'ai réalisé que WebRTC est une technologie exceptionnelle et parfaite pour une utilisation dans le cloud gaming. WebRTC est un projet qui fournit aux navigateurs Web et aux applications mobiles une communication en temps réel via une simple API. Il offre une connectivité peer-to-peer, est optimisé pour les médias et intègre des codecs standard tels que VP8 et H264.

    J'ai donné la priorité à la garantie de la meilleure expérience utilisateur possible plutôt qu'au maintien de graphiques de haute qualité. Certaines pertes sont acceptables dans l'algorithme. Google Stadia comporte une étape supplémentaire consistant à réduire la taille de l'image sur le serveur, et les images sont mises à l'échelle vers une qualité supérieure avant d'être transmises aux pairs.

    3. Infrastructure distribuée avec routage géographique
    Quelle que soit l’optimisation de l’algorithme et du code de compression, le réseau reste le facteur décisif qui contribue le plus à la latence. L'architecture doit disposer d'un mécanisme permettant de coupler le serveur le plus proche de l'utilisateur afin de réduire le temps d'aller-retour (RTT). L'architecture doit avoir 1 coordinateur et plusieurs serveurs de streaming répartis dans le monde : USA Ouest, USA Est, Europe, Singapour, Chine. Tous les serveurs de streaming doivent être complètement isolés. Le système peut ajuster sa distribution lorsqu'un serveur rejoint ou quitte le réseau. Ainsi, en cas de trafic important, l’ajout de serveurs supplémentaires permet une mise à l’échelle horizontale.

    4. Compatibilité du navigateur
    Le cloud gaming est à son meilleur lorsqu'il exige le moins des utilisateurs. Cela signifie qu'il est possible de l'exécuter dans un navigateur. Les navigateurs contribuent à rendre l'expérience de jeu aussi confortable que possible pour les utilisateurs, en leur évitant d'installer des logiciels et du matériel. Les navigateurs contribuent également à fournir des fonctionnalités multiplateformes entre les versions mobiles et de bureau. Heureusement, WebRTC est bien pris en charge sur une variété de navigateurs.

    5. Séparation claire de l'interface de jeu et du service
    Je considère le service de cloud gaming comme une plateforme. Tout le monde devrait pouvoir connecter n’importe quoi à la plateforme. Maintenant j'ai intégré LibRetro avec le service de jeu en nuage car LibRetro offre une belle interface d'émulation de jeu pour les jeux rétro tels que SNES, GBA, PS.

    6. Salles pour le multijoueur, le jeu en foule et les liens externes (lien profond) avec le jeu
    CloudRetro prend en charge de nombreux nouveaux gameplays tels que CrowdPlay et Online MultiPlayer pour les jeux rétro. Si plusieurs utilisateurs ouvrent le même lien profond sur des ordinateurs différents, ils verront le même jeu tourner et pourront même le rejoindre.

    De plus, les états du jeu sont stockés dans le stockage cloud. Cela permet aux utilisateurs de continuer à jouer à tout moment sur n'importe quel autre appareil.

    7. Mise à l'échelle horizontale
    Comme tout SAAS de nos jours, le cloud gaming doit être conçu pour être évolutif horizontalement. La conception coordinateur-travailleur vous permet d’ajouter plus de travailleurs pour desservir plus de trafic.

    8. Aucune connexion à un seul cloud
    L'infrastructure de CloudRetro est hébergée sur différents fournisseurs de cloud (Digital Ocean, Alibaba, fournisseur personnalisé) pour différentes régions. J'active l'exécution dans un conteneur Docker pour l'infrastructure et configure les paramètres réseau à l'aide d'un script bash pour éviter d'être enfermé dans un seul fournisseur de cloud. En combinant cela avec NAT Traversal dans WebRTC, nous pouvons avoir la flexibilité de déployer CloudRetro sur n'importe quelle plate-forme cloud et même sur les machines de n'importe quel utilisateur.

    Conception architecturale

    Ouvrier: (ou le serveur de streaming mentionné ci-dessus) multiplie les jeux, exécute le pipeline d'encodage et diffuse les médias encodés aux utilisateurs. Les instances de travailleur sont réparties dans le monde entier et chaque travailleur peut gérer plusieurs sessions utilisateur simultanément.

    Coordinateur: est responsable de jumeler le nouvel utilisateur avec le travailleur le plus approprié pour le streaming. Le coordinateur interagit avec les travailleurs via WebSocket.

    Stockage de l'état du jeu : stockage central à distance pour tous les états du jeu. Ce stockage fournit des fonctions importantes telles que la sauvegarde/le chargement à distance.

    Cloud gaming open source sur WebRTC : p2p, multijoueur, zéro latence
    Architecture de haut niveau de CloudRetro

    Script personnalisé

    Lorsqu'un nouvel utilisateur ouvre CloudRetro aux étapes 1 et 2 illustrées dans la figure ci-dessous, le coordinateur ainsi que la liste des travailleurs disponibles sont invités à accéder à la première page. Après cela, à l'étape 3, le client calcule les délais pour tous les candidats à l'aide d'une requête ping HTTP. Cette liste de délais est ensuite renvoyée au coordonnateur afin qu'il puisse déterminer l'intervenant le plus apte à servir l'usager. L'étape 4 ci-dessous crée le jeu. Une connexion de streaming WebRTC est établie entre l'utilisateur et le travailleur affecté.
    Cloud gaming open source sur WebRTC : p2p, multijoueur, zéro latence
    Script utilisateur après avoir obtenu l'accès

    Qu'y a-t-il à l'intérieur du travailleur

    Les pipelines de jeux et de streaming sont stockés à l'intérieur du travailleur de manière isolée et y échangent des informations via l'interface. Actuellement, cette communication s'effectue en transférant des données en mémoire via Chaînes Golang dans le même processus. Le prochain objectif est la ségrégation, c'est-à-dire lancement indépendant du jeu dans un autre processus.

    Cloud gaming open source sur WebRTC : p2p, multijoueur, zéro latence
    Interaction des composants du travailleur

    Composants principaux:

    • WebRTC: un composant client qui accepte les entrées de l'utilisateur et génère des médias codés à partir du serveur.
    • Émulateur de jeu : composant de jeu. Grâce à la bibliothèque Libretro, le système est capable d'exécuter le jeu dans le même processus et d'intercepter en interne les médias et le flux d'entrée.
    • Les images du jeu sont capturées et envoyées à l'encodeur.
    • Encodeur image/audio : un pipeline d'encodage qui prend les images multimédias, les encode en arrière-plan et génère des images/audio encodés.

    exécution

    CloudRetro s'appuie sur WebRTC comme technologie de base, donc avant de plonger dans les détails de l'implémentation de Golang, j'ai décidé de parler de WebRTC lui-même. Il s’agit d’une technologie étonnante qui m’a grandement aidé à atteindre une latence inférieure à la seconde pour le streaming de données.

    WebRTC

    WebRTC est conçu pour fournir des connexions peer-to-peer de haute qualité sur des applications mobiles et des navigateurs natifs à l'aide d'API simples.

    Traversée NAT

    WebRTC est connu pour sa fonctionnalité NAT Traversal. WebRTC est conçu pour la communication peer-to-peer. Son objectif est de trouver la route directe la plus appropriée, en évitant les passerelles NAT et les pare-feu pour la communication peer-to-peer via un processus appelé VÉLO. Dans le cadre de ce processus, les API WebRTC trouvent votre adresse IP publique à l'aide des serveurs STUN et la transmettent au serveur relais (TOUR) lorsqu'une connexion directe ne peut pas être établie.

    Cependant, CloudRetro n'exploite pas pleinement cette fonctionnalité. Ses connexions peer-to-peer n'existent pas entre utilisateurs, mais entre utilisateurs et serveurs cloud. Le côté serveur du modèle a moins de restrictions sur la communication directe qu'un appareil utilisateur typique. Cela vous permet de pré-ouvrir les ports entrants ou d'utiliser directement les adresses IP publiques, puisque le serveur n'est pas derrière NAT.

    Auparavant, je souhaitais transformer le projet en une plateforme de distribution de jeux pour le Cloud Gaming. L’idée était de permettre aux créateurs de jeux de proposer des jeux et des ressources de streaming. Et les utilisateurs interagiraient directement avec les fournisseurs. De cette manière décentralisée, CloudRetro n'est qu'un cadre permettant de connecter des ressources de streaming tierces aux utilisateurs, le rendant plus évolutif lorsqu'il n'est plus hébergé. Le rôle de WebRTC NAT Traversal est ici très important pour faciliter l'initialisation de la connexion peer-to-peer sur des ressources de streaming tierces, facilitant ainsi la connexion du créateur au réseau.

    Compression de vidéo

    La compression vidéo est un élément indispensable du pipeline et contribue grandement à un flux fluide. Bien qu'il ne soit pas nécessaire de connaître tous les détails de l'encodage vidéo VP8/H264, comprendre les concepts peut vous aider à comprendre les options de vitesse de streaming vidéo, à déboguer les comportements inattendus et à ajuster la latence.

    La compression de vidéo pour un service de streaming est un défi car l'algorithme doit garantir que le temps total d'encodage + le temps de transmission réseau + le temps de décodage sont aussi courts que possible. De plus, le processus de codage doit être cohérent et continu. Certains compromis d'encodage ne s'appliquent pas : par exemple, nous ne pouvons pas privilégier des temps d'encodage longs par rapport à des tailles de fichiers et des temps de décodage plus petits, ni utiliser une compression incohérente.

    L'idée derrière la compression vidéo est d'éliminer les éléments d'information inutiles tout en maintenant un niveau de précision acceptable pour les utilisateurs. En plus de coder les images statiques individuelles, l'algorithme déduit l'image actuelle à partir des images précédentes et suivantes, de sorte que seule leur différence est envoyée. Comme le montre l'exemple avec Pacman, seuls les points différentiels sont transmis.

    Cloud gaming open source sur WebRTC : p2p, multijoueur, zéro latence
    Comparaison des images vidéo en utilisant Pacman comme exemple

    Compression audio

    De même, l’algorithme de compression audio omet les données qui ne peuvent pas être perçues par les humains. Opus est actuellement le codec audio le plus performant. Il est conçu pour transmettre une onde audio via un protocole de datagramme ordonné tel que RTP (Real Time Transport Protocol). Sa latence est inférieure à celle du mp3 et de l'aac, et la qualité est supérieure. La latence est généralement d'environ 5 à 66,5 ms.

    Pion, WebRTC à Golang

    Pion est un projet open source qui apporte WebRTC à Golang. Au lieu de l'encapsulation habituelle des bibliothèques WebRTC C++ natives, Pion est une implémentation Golang native de WebRTC avec de meilleures performances, une intégration Go et un contrôle de version sur les protocoles WebRTC.

    La bibliothèque permet également le streaming avec de nombreux éléments intégrés intéressants avec une latence inférieure à la seconde. Il possède sa propre implémentation de STUN, DTLS, SCTP, etc. et quelques expériences avec QUIC et WebAssembly. Cette bibliothèque open source elle-même est une très bonne ressource d'apprentissage avec une excellente documentation, des implémentations de protocoles réseau et des exemples intéressants.

    La communauté Pion, dirigée par un créateur très passionné, est assez vivante, avec de nombreuses discussions de qualité autour du WebRTC. Si cette technologie vous intéresse, rejoignez http://pion.ly/slack – vous apprendrez beaucoup de nouvelles choses.

    Écrire CloudRetro en Golang

    Cloud gaming open source sur WebRTC : p2p, multijoueur, zéro latence
    Implémentation d'un travailleur en Go

    Aller aux chaînes en action

    Grâce à la superbe conception des canaux de Go, les problèmes de diffusion d'événements et de simultanéité sont grandement simplifiés. Comme dans le diagramme, différentes GoRoutines ont plusieurs composants exécutés en parallèle. Chaque composant gère son état et communique via des canaux. L'assertion sélective de Golang force le traitement d'un événement atomique à chaque fois dans le jeu (ticket de jeu). Cela signifie qu'aucun verrouillage n'est nécessaire pour cette conception. Par exemple, lorsqu'un utilisateur enregistre, un instantané complet de l'état du jeu est requis. Cet état doit rester continu, en vous connectant jusqu'à ce que la sauvegarde soit terminée. Au cours de chaque tick de jeu, le backend ne peut gérer qu'une opération de sauvegarde ou de saisie, ce qui sécurise le thread de processus.

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

    Entrée/sortie

    Ce modèle Golang correspond parfaitement à mon cas d'utilisation CrowdPlay et Multiple Player. Suivant ce modèle, toutes les entrées utilisateur dans une pièce sont intégrées dans le canal d'entrée central. Le support du jeu est ensuite déployé auprès de tous les utilisateurs présents dans la même pièce. De cette manière, nous parvenons à diviser l’état du jeu entre plusieurs sessions de jeu d’utilisateurs différents.

    Cloud gaming open source sur WebRTC : p2p, multijoueur, zéro latence
    Synchronisation entre différentes sessions

    Inconvénients du Golang

    Golang n'est pas parfait. La chaîne est lente. Comparé au blocage, le canal Go est simplement un moyen plus simple de gérer les événements simultanés et threadés, mais le canal n'offre pas les meilleures performances. Il existe une logique de blocage complexe sous le canal. J'ai donc apporté quelques ajustements à l'implémentation, en réappliquant les verrous et les valeurs atomiques lors du remplacement des canaux pour optimiser les performances.

    De plus, le garbage collector de Golang n'est pas géré, ce qui provoque parfois des pauses étrangement longues. Cela interfère grandement avec l'application de streaming en temps réel.

    DENT

    Le projet utilise la bibliothèque open source Golang VP8/H264 existante pour la compression multimédia et Libretro pour les émulateurs de jeux. Toutes ces bibliothèques sont simplement des wrappers de la bibliothèque C dans Go utilisant DENT. Certains des inconvénients sont répertoriés dans ce message de Dave Cheney. Problèmes que j'ai rencontrés :

    • incapacité à détecter un crash dans CGO, même avec Golang RecoveryCrash ;
    • incapacité à identifier les goulots d'étranglement des performances lorsque nous ne parvenons pas à détecter des problèmes détaillés dans CGO.

    Conclusion

    J'ai atteint mon objectif de comprendre les services de jeux en nuage et de créer une plate-forme qui m'aide à jouer à des jeux rétro nostalgiques avec mes amis en ligne. Ce projet n'aurait pas été possible sans la bibliothèque Pion et le soutien de la communauté Pion. Je suis extrêmement reconnaissant pour son développement intensif. Les API simples fournies par WebRTC et Pion ont assuré une intégration transparente. Ma première preuve de concept a été publiée la même semaine, même si je n'avais aucune connaissance préalable de la communication peer-to-peer (P2P).

    Malgré la facilité d’intégration, le streaming P2P est en effet un domaine très complexe en informatique. Elle doit faire face à la complexité des architectures réseau de longue date telles que IP et NAT pour créer une session peer-to-peer. En travaillant sur ce projet, j'ai acquis de nombreuses connaissances précieuses sur les réseaux et l'optimisation des performances. J'encourage donc tout le monde à essayer de créer des produits P2P à l'aide de WebRTC.

    CloudRetro répond à tous les cas d'utilisation que j'attendais de mon point de vue de joueur rétro. Cependant, je pense qu'il y a de nombreux domaines du projet que je peux améliorer, comme rendre le réseau plus fiable et plus performant, fournir des graphismes de jeu de meilleure qualité ou la possibilité de partager des jeux entre utilisateurs. Je travaille dur là-dessus. Veuillez suivre projet et soutenez-le si vous l’aimez.

Source: habr.com

Ajouter un commentaire