Jeux en nuage open source sur WebRTC : p2p, multijoueur, zéro latence

Jeux en nuage open source sur WebRTC : p2p, multijoueur, zéro latence
Le logiciel en tant que service, l'infrastructure en tant que service, la plateforme en tant que service, la plateforme de communication en tant que service, les vidéoconférences en tant que service, qu'en est-il des jeux en nuage en tant que service ? Plusieurs tentatives pour créer des jeux en nuage (Cloud Gaming) ont déjà été entreprises, par exemple, Stadia, récemment lancée par Google. Stadia n'est pas un novice dans le WebRTC, mais d'autres peuvent-ils utiliser WebRTC de la même manière ?

Thanh Nguyen a décidé d'explorer cette possibilité dans son projet open source CloudRetro. CloudRetro est basé sur Pion, une bibliothèque WebRTC populaire en Go (merci à Sean du groupe de développeurs Pion pour son aide dans la préparation de cet article). Dans cet article, Thanh passe en revue l'architecture de son projet et partage ce qu'il a appris et les défis auxquels il a été confronté pendant son travail. L'année dernière, lorsque Google a annoncé Stadia, j'étais totalement émerveillé. L'idée est tellement unique et innovante que je me suis constamment demandé comment cela était même possible avec les technologies existantes. Le désir de mieux comprendre ce sujet m'a poussé à créer ma propre version de jeu en nuage open source. Le résultat était tout simplement fantastique. Ci-dessous, j'aimerais partager le processus de travail que j'ai mené tout au long de mon année

Introduction

TLDR : version courte avec les points clés le projet.

Pourquoi les jeux en nuage représentent l'avenir

Je crois que le Cloud Gaming va bientôt devenir la nouvelle génération non seulement pour les jeux, mais aussi pour d'autres domaines de l'informatique. Les jeux en nuage représentent le summum du modèle client/serveur. Ce modèle maximise le contrôle du back-end et minimise le travail du front-end en plaçant la logique du jeu sur un serveur distant et en diffusant des images/audio au client. Le serveur effectue le traitement intensif, donc le client n'est plus limité par des contraintes matérielles.

Google Stadia permet fondamentalement de jouer à des

jeux AAA (c'est-à-dire des jeux de haut niveau) sur une interface semblable à YouTube. La même méthodologie peut être appliquée à d'autres applications hors ligne lourdes, telles que le système d'exploitation ou le design graphique 2D/3D, afin de pouvoir les exécuter de manière stable sur des appareils aux caractéristiques techniques faibles sur différentes plateformes. L'avenir de cette technologie : imaginez si Microsoft Windows 10 fonctionnait dans le navigateur Chrome ?

Jeux en nuage open source sur WebRTC : p2p, multijoueur, zéro latence
Les jeux en nuage sont techniquement complexes

Облачные игры технически сложны

Le jeu est l'un de ces rares domaines où une réaction rapide et constante de l'utilisateur est requise. Si occasionnellement nous faisons face à un retard de 2 secondes lors d'un clic sur une page, cela est acceptable. Les flux vidéo en direct semblent généralement avoir quelques secondes de retard, mais ils offrent néanmoins un confort d'utilisation suffisant. Cependant, si un jeu a souvent un retard de 500 ms, il devient tout simplement injouable. Notre objectif est d'atteindre une latence extrêmement basse pour que le décalage entre l'entrée et le média soit le plus court possible. Par conséquent, l'approche traditionnelle du streaming vidéo n'est pas applicable ici.

Jeux en nuage open source sur WebRTC : p2p, multijoueur, zéro latence
Modèle général de jeu dans le cloud

Projet open source CloudRetro

J'ai décidé de créer un prototype de jeu dans le cloud pour tester si tout cela est possible avec de telles restrictions réseau strictes. Pour vérifier ce concept, j'ai choisi Golang, car c'est le langage que je connais le mieux et qui est bien adapté à cette mise en œuvre pour de nombreuses autres raisons, comme je l'ai découvert plus tard. Go est simple et évolue très rapidement ; les canaux en Go sont parfaits pour la gestion de la concurrence.

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

Fonctionnalités de CloudRetro

Pour démontrer toute la puissance du jeu dans le cloud, CloudRetro utilise des jeux rétro. Cela permet d'obtenir de nombreuses expériences de jeu uniques.

  • Portabilité du jeu
    • Lecture instantanée à l'ouverture de la page ; aucun téléchargement ni installation nécessaires
    • Fonctionne dans le navigateur mobile, donc aucun logiciel n'est requis pour démarrer

  • 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é, et peut également être joué simultanément par plusieurs utilisateurs :
    • Crowdplay de type TwitchPlayPokemon, mais plus multiplateforme et en temps réel
    • Jeux hors ligne en ligne. De nombreux utilisateurs peuvent jouer sans configuration réseau. Dans Samurai Shodown, 2 joueurs peuvent maintenant jouer en réseau via CloudRetro

    Jeux en nuage open source sur WebRTC : p2p, multijoueur, zéro latence
    Démonstration d'un jeu en ligne multijoueur sur différents appareils

    Infrastructure

    Exigences et stack technologique

    Voici une liste des exigences que j'ai établies avant de commencer le projet.

    1. Un joueur
    Cette exigence peut sembler peu importante et évidente ici, mais c'est l'une de mes principales conclusions, elle permet aux jeux en cloud de se distancier des services de streaming traditionnels. Si nous nous concentrons sur les jeux solo, nous pouvons nous passer d'un serveur centralisé ou d'un CDN, car il n'est pas nécessaire de diffuser massivement. Au lieu de télécharger des flux sur un serveur de digestion ou de transmettre des paquets à un serveur WebSocket centralisé, les flux de services sont transmis directement à l'utilisateur via une connexion pair-à-pair WebRTC.

    2. Flux multimédia à faible latence
    En lisant sur Stadia, je rencontre souvent dans certains articles la mention de WebRTC. J'ai compris que WebRTC est une technologie remarquable et qu'elle est parfaitement adaptée à l'utilisation dans les jeux en cloud. WebRTC est un projet qui fournit aux navigateurs web et aux applications mobiles une communication en temps réel via une API simple. Il offre une connexion pair-à-pair, optimisée pour les médias, et dispose de codecs standards intégrés comme VP8 et H264.

    J'ai privilégié le confort maximal des utilisateurs plutôt que de maintenir une qualité graphique élevée. Certaines pertes sont acceptables dans l'algorithme. Google Stadia a une étape supplémentaire pour réduire la taille de l'image sur le serveur, et les frames sont redimensionnées à une qualité supérieure avant d'être transmises aux nœuds pair-à-pair.

    3. Infrastructure distribuée avec routage géographique
    Peu importe à quel point l'algorithme de compression et le code sont optimisés, le réseau reste un facteur décisif qui contribue le plus à la latence. L'architecture doit avoir un mécanisme pour associer le serveur le plus proche de l'utilisateur afin de réduire le temps de transmission aller-retour (RTT). L'architecture doit avoir 1 coordinateur et plusieurs serveurs de streaming, répartis dans le monde : Ouest des États-Unis, Est des États-Unis, Europe, Singapour, Chine. Tous les serveurs de streaming doivent être complètement isolés. Le système peut réguler sa distribution lorsque le serveur rejoint ou quitte le réseau. Ainsi, lors d'un fort trafic, l'ajout de serveurs supplémentaires permet une montée en charge horizontale.

    4. Compatibilité du navigateur
    Les jeux en nuage se présentent sous leur meilleur jour lorsqu'ils exigent un minimum d'interaction de la part des utilisateurs. Cela signifie qu'il est possible de les lancer dans un navigateur. Les navigateurs facilitent une expérience de jeu optimale pour les utilisateurs, en les dispensant d'installer des logiciels et du matériel. Ils aident également à garantir la compatibilité entre les versions mobiles et de bureau. Heureusement, WebRTC est parfaitement pris en charge dans divers navigateurs.

    5. Séparation claire de l'interface de jeu et du service
    Je considère le service de jeux en nuage comme une plateforme. Chacun doit avoir la possibilité de connecter tout ce qu'il souhaite à la plateforme. À l'heure actuelle, j'ai intégré LibRetro au service de jeux en nuage, car LibRetro offre une belle interface d'émulateur de jeux rétro comme SNES, GBA, PS.

    6. Chambres pour le multijoueur, crowd play et lien profond avec le jeu
    CloudRetro prend en charge de nouvelles mécaniques de jeu telles que le CrowdPlay et le multijoueur en ligne pour les jeux rétro. Si plusieurs utilisateurs ouvrent le même lien profond sur des ordinateurs différents, ils pourront voir le même jeu en cours d'exécution et même y rejoindre.

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

    7. Scalabilité horizontale
    Comme tout SAAS de nos jours, les jeux en nuage doivent être conçus pour être évolutifs horizontalement. La structure « coordonnateur-travailleur » permet d'ajouter plus de travailleurs pour gérer un trafic plus important.

    8. Pas de dépendance à un seul cloud
    L'infrastructure de CloudRetro est hébergée sur différents fournisseurs de cloud (Digital Ocean, Alibaba, fournisseur personnalisé) pour diverses régions. J'active le démarrage dans un conteneur Docker pour l'infrastructure et configure les paramètres réseau à l'aide d'un script bash, afin d'éviter de dépendre d'un seul fournisseur de cloud. En combinant cela avec le NAT Traversal dans WebRTC, nous pouvons obtenir la flexibilité de déployer CloudRetro sur n'importe quelle plateforme cloud et même sur les machines de n'importe quel utilisateur.

    Conception architecturale

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

    Coordinateur : responsable de l'association d'un nouvel utilisateur avec le travailleur le plus approprié pour le streaming. Le coordinateur interagit avec les travailleurs via WebSocket.

    Stockage des états de jeu : un stockage décentralisé central pour tous les états du jeu. Ce stockage offre des fonctionnalités essentielles telles que la sauvegarde et le chargement à distance.

    Jeux en nuage open source sur WebRTC : p2p, multijoueur, zéro latence
    Architecture CloudRetro de haut niveau

    Scénario utilisateur

    Lorsqu'un nouvel utilisateur ouvre CloudRetro aux étapes 1 et 2 présentées ci-dessous, le coordinateur est consulté avec la liste des travailleurs disponibles sur la première page. Ensuite, à l'étape 3, le client calcule les latences pour tous les candidats à l'aide d'une requête HTTP ping. Cette liste de latences est ensuite renvoyée au coordinateur, qui peut déterminer le travailleur le plus adapté pour servir l'utilisateur. À l'étape 4 ci-dessous, le jeu est créé. Une connexion de streaming WebRTC est établie entre l'utilisateur et le travailleur désigné.
    Jeux en nuage open source sur WebRTC : p2p, multijoueur, zéro latence
    Scénario utilisateur après accès

    Que contient le travailleur

    Les pipelines de jeux et de streaming sont stockés de manière isolée à l'intérieur du travailleur et échangent des informations via une interface. Actuellement, cette liaison se fait par le biais de la transmission de données en mémoire via les canaux Golang dans le même processus. L’objectif suivant est la segmentation, c’est-à-dire l'exécution indépendante du jeu dans un autre processus.

    Jeux en nuage open source sur WebRTC : p2p, multijoueur, zéro latence
    Interaction des composants du travailleur

    Principales composantes :

    • WebRTC : composant client qui reçoit les entrées de l'utilisateur et restitue les médias encodés 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 de capturer intérieurement les médias et les flux d'entrée.
    • Les images/vidéos du jeu sont capturées et envoyées à l'encodeur.
    • Encodeur image/son : pipeline d'encodage qui prend les images/vidéos, les encode en arrière-plan et restitue les images/vidéos encodées.

    Mise en œuvre

    CloudRetro s'appuie sur WebRTC comme technologie clé, donc avant de plonger dans les détails de l'implémentation en Golang, j'ai décidé de parler un peu de WebRTC lui-même. C'est une technologie incroyable qui m'a beaucoup aidé à atteindre une latence de transmission de données d'à peine quelques millisecondes.

    WebRTC

    WebRTC est conçu pour fournir des connexions de pair à pair de haute qualité sur des applications mobiles natives et dans les navigateurs via des API simples.

    NAT Traversal

    WebRTC est connu pour sa fonctionnalité de traversée NAT. WebRTC est conçu pour la communication entre pairs. Son objectif est de trouver le chemin direct le plus approprié, en évitant les passerelles NAT et les pare-feu pour la communication entre pairs via un processus appelé ICE. Dans le cadre de ce processus, les API WebRTC trouvent votre adresse IP publique via des serveurs STUN et la redirigent vers un serveur de relais (TURN), lorsque la connexion directe ne peut pas être établie.

    Cependant, CloudRetro n'exploite pas pleinement cette capacité. Ses connexions entre pairs n'existent pas entre les utilisateurs, mais entre les utilisateurs et les serveurs cloud. La partie serveur du modèle a moins de restrictions sur la connexion directe que les appareils utilisateur ordinaires. Cela permet une ouverture préalable des ports entrants ou l'utilisation directe d'adresses IP publiques, car le serveur n'est pas derrière un NAT.

    Autrefois, je voulais 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 fournir des jeux et des ressources de streaming. Les utilisateurs interagiraient directement avec les fournisseurs. De cette manière décentralisée, CloudRetro n'est qu'un environnement pour connecter des ressources de streaming tierces aux utilisateurs, le rendant plus évolutif, maintenant qu'il n'est plus chargé de l'hébergement. Le rôle de la traversée NAT de WebRTC est ici très important pour faciliter l'initialisation de la connexion entre pairs sur des ressources de streaming tierces, ce qui simplifie la connexion du créateur au réseau.

    Compression vidéo

    La compression vidéo est une partie indispensable du pipeline, contribuant largement à la fluidité du flux. Bien qu'il ne soit pas nécessaire de connaître tous les détails de l'encodage vidéo en VP8/H264, comprendre le concept aide à appréhender les paramètres de débit vidéo en streaming, à déboguer un comportement inattendu et à régler la latence.

    La compression vidéo pour les services de streaming est une tâche complexe, car l'algorithme doit garantir que le temps total d'encodage + le temps de transmission réseau + le temps de décodage est aussi réduit que possible. De plus, le processus d'encodage doit être constant et ininterrompu. Certaines concessions dans l'encodage ne sont pas applicables – par exemple, nous ne pouvons pas préférer un temps d'encodage prolongé à une taille de fichier plus petite et à un temps de décodage, ou utiliser une compression non cohérente.

    L'idée de la compression vidéo consiste à éliminer les bits d'information superflus tout en maintenant un niveau de précision acceptable pour les utilisateurs. En plus de l'encodage des images individuelles, l'algorithme tire les conclusions pour le cadre actuel à partir des précédents et suivants, donc seule leur différence est transmise. Comme le montre l'exemple de Pacman, seules les points différentiels sont envoyés.

    Jeux en nuage open source sur WebRTC : p2p, multijoueur, zéro latence
    Comparaison de cadres vidéo avec l'exemple de Pacman

    Compression audio

    De la même manière, l'algorithme de compression audio omet les données qui ne peuvent pas être perçues par l'homme. Actuellement, Opus est le codec audio avec les meilleures performances. Il a été conçu pour transmettre des ondes audio via un protocole de datagramme ordonné, tel que RTP (Real Time Transport Protocol). Sa latence est inférieure à celle de mp3 et aac, avec une qualité supérieure. La latence est généralement d'environ 5 à 66,5 ms.

    Pion, WebRTC en Golang

    Pion est un projet open source qui intègre WebRTC dans Golang. Au lieu d'envelopper les bibliothèques C++ natives de WebRTC, Pion est une implémentation native de WebRTC en Golang offrant de meilleures performances, une intégration avec Go, ainsi qu'un contrôle des versions sur les protocoles WebRTC.

    La bibliothèque offre également un streaming avec de nombreux excellents modules intégrés avec un retard de moins d'une seconde. Elle possède sa propre implémentation de STUN, DTLS, SCTP, etc., et expérimente avec QUIC et WebAssembly. En soi, cette bibliothèque open-source est vraiment une bonne source d'apprentissage avec une excellente documentation, mise en œuvre des protocoles réseau et de superbes exemples.

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

    Écriture de CloudRetro en Golang

    Jeux en nuage open source sur WebRTC : p2p, multijoueur, zéro latence
    Mise en œuvre d'un worker en Go

    Canaux Go en action

    Grâce à la belle conception des canaux Go, les problèmes de streaming d'événements et de parallélisme sont considérablement simplifiés. Comme indiqué dans le diagramme, plusieurs composants fonctionnent parallèlement dans différentes GoRoutines. Chaque composant gère son état et communique via des canaux. L'instruction sélective de Golang force à traiter un événement atomique à la fois à chaque moment dans le jeu (game tick). Cela signifie qu'aucun verrou n'est nécessaire pour ce design. Par exemple, lorsque l'utilisateur se sauvegarde, un snapshot complet de l'état du jeu est requis. Cet état doit rester cohérent, effectuant des entrées jusqu'à ce que la sauvegarde soit terminée. Lors de chaque game tick, le backend ne peut traiter qu'une seule opération de sauvegarde ou d'entrée, ce qui rend le processus sécurisé par rapport aux threads.

    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

    Ce modèle Golang convient parfaitement à mon cas d'utilisation de CrowdPlay et de plusieurs joueurs. En suivant ce modèle, toutes les entrées utilisateur dans une salle sont intégrées dans un canal d'entrée central. Les médias de jeu sont ensuite diffusés à tous les utilisateurs dans cette salle. Ainsi, nous atteignons une séparation de l'état du jeu entre plusieurs sessions de jeu de différents utilisateurs.

    Jeux en nuage open source sur WebRTC : p2p, multijoueur, zéro latence
    Synchronisation entre différentes sessions

    Inconvénients de Golang

    Golang n'est pas parfait. Le canal est lent. Comparé à un blocage, le canal Go est simplement une manière plus simple de gérer des événements parallèles et des flux, mais il ne fournit pas la meilleure performance. Sous le canal, il y a une logique de blocage complexe. C'est pourquoi j'ai apporté quelques modifications à l'implémentation, en réutilisant des verrous et des valeurs atomiques à la place des canaux pour optimiser la performance.

    De plus, le ramasse-miettes dans Golang est incontrôlable, ce qui entraîne parfois des pauses suspectes et prolongées. Cela perturbe considérablement le fonctionnement des applications en temps réel.

    CGO

    Le projet utilise la bibliothèque VP8/H264 existante en open source de Golang pour la compression média et Libretro pour les émulateurs de jeux. Toutes ces bibliothèques ne sont que des wrappers de la bibliothèque C en Go utilisant CGO. Certains des inconvénients sont énumérés dans ce post de Dave Cheney. Les problèmes auxquels j'ai été confronté :

    • impossibilité de capturer un crash dans CGO, même avec l'aide de Golang RecoveryCrash ;
    • impossibilité de déterminer le goulet d'étranglement en performance, lorsque nous ne pouvons pas détecter les problèmes détaillés dans CGO.

    Conclusion

    J'ai atteint mon objectif – je me suis plongé dans les services de jeux dans le cloud et j'ai créé une plateforme qui permet de jouer à des jeux rétro nostalgiques avec mes amis en ligne. La création de 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 permis une intégration fluide. Ma première preuve de concept a été lancée la même semaine, même si je n'avais pas à l'avance connaissance de la connexion peer-to-peer (P2P).

    Malgré la simplicité d'intégration, le streaming P2P est en réalité un domaine très complexe en informatique. Il doit faire face à la complexité des architectures réseau établies depuis des années, telles que l'IP et le NAT pour établir une session peer-to-peer. Au cours de ce projet, j'ai acquis de nombreuses connaissances précieuses sur le réseau et l'optimisation de la performance, par conséquent, je recommande à tous d'essayer de construire des produits P2P en utilisant WebRTC.

    CloudRetro gère tous les scénarios d'utilisation que j'attendais, de mon point de vue en tant que passionné de rétro-gaming. Cependant, je pense qu'il y a de nombreux domaines dans le projet que je peux améliorer, comme rendre le réseau plus fiable et performant, assurer une meilleure qualité graphique des jeux, ou permettre le partage de jeux entre utilisateurs. Je travaille dur là-dessus. Veuillez suivre le projet et le soutenir si cela vous plaît.

Source : habr.com

Acheter un hébergement fiable pour les sites avec protection DDoS, serveurs VPS VDS 🔥 Acheter un hébergement fiable pour les sites avec protection DDoS, serveurs VPS VDS | ProHoster