{"id":89303,"date":"2020-07-22T01:42:30","date_gmt":"2020-07-21T23:42:30","guid":{"rendered":"https:\/\/prohoster.info\/blog\/administrirovanie\/oblachnyj-gejming-s-otkrytym-ishodnym-kodom-na-webrtc-p2p-multipleer-zero-latency"},"modified":"2020-07-22T01:42:30","modified_gmt":"2020-07-21T23:42:30","slug":"oblachnyj-gejming-s-otkrytym-ishodnym-kodom-na-webrtc-p2p-multipleer-zero-latency","status":"publish","type":"post","link":"https:\/\/prohoster.info\/fr\/blog\/administrirovanie\/oblachnyj-gejming-s-otkrytym-ishodnym-kodom-na-webrtc-p2p-multipleer-zero-latency","title":{"rendered":"Jeux en nuage open source sur WebRTC : p2p, multijoueur, z\u00e9ro latence","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p><noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/Voximplant\/blog\/511626\/\"><img decoding=\"async\" alt=\"Jeux en nuage open source sur WebRTC : p2p, multijoueur, z\u00e9ro latence\" src=\"\/wp-content\/uploads\/2020\/07\/22dbf7665d7fded15671d98a2afe599b.png\" style=\"display:block;margin: 0 auto;\" \/><\/a><\/noindex><br \/>\nLe 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\u00e9oconf\u00e9rences en tant que service, qu'en est-il des jeux en nuage en tant que service ? Plusieurs tentatives pour cr\u00e9er des jeux en nuage (Cloud Gaming) ont d\u00e9j\u00e0 \u00e9t\u00e9 entreprises, par exemple, Stadia, r\u00e9cemment lanc\u00e9e par Google. Stadia <noindex><a rel=\"nofollow\" href=\"https:\/\/youtu.be\/avtlQeaxd_I?t=440\">n'est pas un novice dans le WebRTC<\/a><\/noindex>, mais d'autres peuvent-ils utiliser WebRTC de la m\u00eame mani\u00e8re ?<noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><\/p>\n<p>Thanh Nguyen a d\u00e9cid\u00e9 d'explorer cette possibilit\u00e9 dans son projet open source CloudRetro. CloudRetro est bas\u00e9 sur Pion, <noindex><a rel=\"nofollow\" href=\"https:\/\/webrtchacks.com\/webrtc-open-source-most-popular\/\">une biblioth\u00e8que WebRTC populaire en Go (merci<\/a><\/noindex> \u00e0 Sean <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/Sean-Der\">du groupe de d\u00e9veloppeurs Pion pour son aide dans la pr\u00e9paration 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\u00e9fis auxquels il a \u00e9t\u00e9 confront\u00e9 pendant son travail.<\/a><\/noindex> L'ann\u00e9e derni\u00e8re, lorsque Google a annonc\u00e9 Stadia, j'\u00e9tais totalement \u00e9merveill\u00e9. L'id\u00e9e est tellement unique et innovante que je me suis constamment demand\u00e9 comment cela \u00e9tait m\u00eame possible avec les technologies existantes. Le d\u00e9sir de mieux comprendre ce sujet m'a pouss\u00e9 \u00e0 cr\u00e9er ma propre version de jeu en nuage open source. Le r\u00e9sultat \u00e9tait tout simplement fantastique. Ci-dessous, j'aimerais partager le processus de travail que j'ai men\u00e9 tout au long de mon ann\u00e9e<\/p>\n<h2>Introduction<\/h2>\n<p>\nTLDR : version courte avec les points cl\u00e9s <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/giongto35\/cloud-game\">le projet<\/a><\/noindex>.<\/p>\n<p><i>Pourquoi les jeux en nuage repr\u00e9sentent l'avenir<\/i><\/p>\n<h3>Je crois que le Cloud Gaming va bient\u00f4t devenir la nouvelle g\u00e9n\u00e9ration non seulement pour les jeux, mais aussi pour d'autres domaines de l'informatique. Les jeux en nuage repr\u00e9sentent le summum du mod\u00e8le client\/serveur. Ce mod\u00e8le maximise le contr\u00f4le du back-end et minimise le travail du front-end en pla\u00e7ant 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\u00e9 par des contraintes mat\u00e9rielles.<\/h3>\n<p>\nGoogle Stadia permet fondamentalement de jouer \u00e0 des<\/p>\n<p>jeux AAA <noindex><a rel=\"nofollow\" href=\"https:\/\/ru.wikipedia.org\/wiki\/AAA_(%D0%BA%D0%BE%D0%BC%D0%BF%D1%8C%D1%8E%D1%82%D0%B5%D1%80%D0%BD%D1%8B%D0%B5_%D0%B8%D0%B3%D1%80%D1%8B)\">(c'est-\u00e0-dire des jeux de haut niveau) sur une interface semblable \u00e0 YouTube. La m\u00eame m\u00e9thodologie peut \u00eatre appliqu\u00e9e \u00e0 d'autres applications hors ligne lourdes, telles que le syst\u00e8me d'exploitation ou le design graphique 2D\/3D, afin de pouvoir les ex\u00e9cuter de mani\u00e8re stable sur des appareils aux caract\u00e9ristiques techniques faibles sur diff\u00e9rentes plateformes.<\/a><\/noindex> L'avenir de cette technologie : imaginez si Microsoft Windows 10 fonctionnait dans le navigateur Chrome ?<\/p>\n<p><img decoding=\"async\" alt=\"Jeux en nuage open source sur WebRTC : p2p, multijoueur, z\u00e9ro latence\" src=\"\/wp-content\/uploads\/2020\/07\/d6ca3e47db5c8e3d9880b304cc3be33b.png\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nLes jeux en nuage sont techniquement complexes<\/p>\n<h3>Les jeux en nuage sont techniquement complexes<\/h3>\n<p>\nLe jeu est l'un de ces rares domaines o\u00f9 une r\u00e9action rapide et constante de l'utilisateur est requise. Si occasionnellement nous faisons face \u00e0 un retard de 2 secondes lors d'un clic sur une page, cela est acceptable. Les flux vid\u00e9o en direct semblent g\u00e9n\u00e9ralement avoir quelques secondes de retard, mais ils offrent n\u00e9anmoins 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\u00eamement basse pour que le d\u00e9calage entre l'entr\u00e9e et le m\u00e9dia soit le plus court possible. Par cons\u00e9quent, l'approche traditionnelle du streaming vid\u00e9o n'est pas applicable ici.<\/p>\n<p><img decoding=\"async\" alt=\"Jeux en nuage open source sur WebRTC : p2p, multijoueur, z\u00e9ro latence\" src=\"\/wp-content\/uploads\/2020\/07\/d73765a3c9277c026f407883e1091473.png\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nMod\u00e8le g\u00e9n\u00e9ral de jeu dans le cloud<\/p>\n<h2>Projet open source CloudRetro<\/h2>\n<p>\nJ'ai d\u00e9cid\u00e9 de cr\u00e9er un prototype de jeu dans le cloud pour tester si tout cela est possible avec de telles restrictions r\u00e9seau strictes. Pour v\u00e9rifier ce concept, j'ai choisi Golang, car c'est le langage que je connais le mieux et qui est bien adapt\u00e9 \u00e0 cette mise en \u0153uvre pour de nombreuses autres raisons, comme je l'ai d\u00e9couvert plus tard. Go est simple et \u00e9volue tr\u00e8s rapidement ; les canaux en Go sont parfaits pour la gestion de la concurrence.<\/p>\n<p>Projet <noindex><a rel=\"nofollow\" href=\"http:\/\/cloudretro.io\/\">CloudRetro.io<\/a><\/noindex> \u2013 service de jeu cloud open source pour le jeu r\u00e9tro. L'objectif du projet est d'apporter aux jeux r\u00e9tro traditionnels une exp\u00e9rience de jeu la plus confortable possible et d'ajouter un mode multijoueur.<br \/>\nPour en savoir plus sur le projet, cliquez ici : <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/giongto35\/cloud-game\">https:\/\/github.com\/giongto35\/cloud-game<\/a><\/noindex>.<\/p>\n<h3>Fonctionnalit\u00e9s de CloudRetro<\/h3>\n<p>\nPour d\u00e9montrer toute la puissance du jeu dans le cloud, CloudRetro utilise des jeux r\u00e9tro. Cela permet d'obtenir de nombreuses exp\u00e9riences de jeu uniques.<\/p>\n<ul>\n<li>Portabilit\u00e9 du jeu\n<ul>\n<li>Lecture instantan\u00e9e \u00e0 l'ouverture de la page ; aucun t\u00e9l\u00e9chargement ni installation n\u00e9cessaires<\/li>\n<li>Fonctionne dans le navigateur mobile, donc aucun logiciel n'est requis pour d\u00e9marrer<\/li>\n<\/ul>\n<p>\n<\/li>\n<li>Les sessions de jeu peuvent \u00eatre partag\u00e9es sur plusieurs appareils et stock\u00e9es dans le cloud pour la prochaine connexion<\/li>\n<li>Le jeu peut \u00eatre diffus\u00e9, et peut \u00e9galement \u00eatre jou\u00e9 simultan\u00e9ment par plusieurs utilisateurs :\n<ul>\n<li>Crowdplay de type TwitchPlayPokemon, mais plus multiplateforme et en temps r\u00e9el<\/li>\n<li>Jeux hors ligne en ligne. De nombreux utilisateurs peuvent jouer sans configuration r\u00e9seau. Dans Samurai Shodown, 2 joueurs peuvent maintenant jouer en r\u00e9seau via CloudRetro<\/li>\n<\/ul>\n<p>\n<img decoding=\"async\" alt=\"Jeux en nuage open source sur WebRTC : p2p, multijoueur, z\u00e9ro latence\" src=\"\/wp-content\/uploads\/2020\/07\/bdc715971755d669a026f830ce888520.png\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nD\u00e9monstration d'un jeu en ligne multijoueur sur diff\u00e9rents appareils<\/p>\n<h2>Infrastructure<\/h2>\n<p><\/p>\n<h3>Exigences et stack technologique<\/h3>\n<p>\nVoici une liste des exigences que j'ai \u00e9tablies avant de commencer le projet.<\/p>\n<p><b>1. Un joueur<\/b><br \/>\nCette exigence peut sembler peu importante et \u00e9vidente 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\u00e9 ou d'un CDN, car il n'est pas n\u00e9cessaire de diffuser massivement. Au lieu de t\u00e9l\u00e9charger des flux sur un serveur de digestion ou de transmettre des paquets \u00e0 un serveur WebSocket centralis\u00e9, les flux de services sont transmis directement \u00e0 l'utilisateur via une connexion pair-\u00e0-pair WebRTC.<\/p>\n<p><b>2. Flux multim\u00e9dia \u00e0 faible latence<\/b><br \/>\nEn 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\u00e9e \u00e0 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\u00e9el via une API simple. Il offre une connexion pair-\u00e0-pair, optimis\u00e9e pour les m\u00e9dias, et dispose de codecs standards int\u00e9gr\u00e9s comme VP8 et H264.<\/p>\n<p>J'ai privil\u00e9gi\u00e9 le confort maximal des utilisateurs plut\u00f4t que de maintenir une qualit\u00e9 graphique \u00e9lev\u00e9e. Certaines pertes sont acceptables dans l'algorithme. Google Stadia a une \u00e9tape suppl\u00e9mentaire pour r\u00e9duire la taille de l'image sur le serveur, et les frames sont redimensionn\u00e9es \u00e0 une qualit\u00e9 sup\u00e9rieure avant d'\u00eatre transmises aux n\u0153uds pair-\u00e0-pair.<\/p>\n<p><b>3. Infrastructure distribu\u00e9e avec routage g\u00e9ographique<\/b><br \/>\nPeu importe \u00e0 quel point l'algorithme de compression et le code sont optimis\u00e9s, le r\u00e9seau reste un facteur d\u00e9cisif qui contribue le plus \u00e0 la latence. L'architecture doit avoir un m\u00e9canisme pour associer le serveur le plus proche de l'utilisateur afin de r\u00e9duire le temps de transmission aller-retour (RTT). L'architecture doit avoir 1 coordinateur et plusieurs serveurs de streaming, r\u00e9partis dans le monde : Ouest des \u00c9tats-Unis, Est des \u00c9tats-Unis, Europe, Singapour, Chine. Tous les serveurs de streaming doivent \u00eatre compl\u00e8tement isol\u00e9s. Le syst\u00e8me peut r\u00e9guler sa distribution lorsque le serveur rejoint ou quitte le r\u00e9seau. Ainsi, lors d'un fort trafic, l'ajout de serveurs suppl\u00e9mentaires permet une mont\u00e9e en charge horizontale.<\/p>\n<p><b>4. Compatibilit\u00e9 du navigateur<\/b><br \/>\nLes jeux en nuage se pr\u00e9sentent 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\u00e9rience de jeu optimale pour les utilisateurs, en les dispensant d'installer des logiciels et du mat\u00e9riel. Ils aident \u00e9galement \u00e0 garantir la compatibilit\u00e9 entre les versions mobiles et de bureau. Heureusement, WebRTC est parfaitement pris en charge dans divers navigateurs.<\/p>\n<p><b>5. S\u00e9paration claire de l'interface de jeu et du service<\/b><br \/>\nJe consid\u00e8re le service de jeux en nuage comme une plateforme. Chacun doit avoir la possibilit\u00e9 de connecter tout ce qu'il souhaite \u00e0 la plateforme. \u00c0 l'heure actuelle, j'ai int\u00e9gr\u00e9 <noindex><a rel=\"nofollow\" href=\"http:\/\/LibRetro\">LibRetro<\/a><\/noindex> au service de jeux en nuage, car LibRetro offre une belle interface d'\u00e9mulateur de jeux r\u00e9tro comme SNES, GBA, PS.<\/p>\n<p><b>6. Chambres pour le multijoueur, crowd play et lien profond avec le jeu<\/b><br \/>\nCloudRetro prend en charge de nouvelles m\u00e9caniques de jeu telles que le CrowdPlay et le multijoueur en ligne pour les jeux r\u00e9tro. Si plusieurs utilisateurs ouvrent le m\u00eame lien profond sur des ordinateurs diff\u00e9rents, ils pourront voir le m\u00eame jeu en cours d'ex\u00e9cution et m\u00eame y rejoindre.<\/p>\n<p>De plus, les \u00e9tats de jeu sont stock\u00e9s dans le cloud. Cela permet aux utilisateurs de reprendre leur partie \u00e0 tout moment sur n'importe quel autre appareil.<\/p>\n<p><b>7. Scalabilit\u00e9 horizontale<\/b><br \/>\nComme tout SAAS de nos jours, les jeux en nuage doivent \u00eatre con\u00e7us pour \u00eatre \u00e9volutifs horizontalement. La structure \u00ab coordonnateur-travailleur \u00bb permet d'ajouter plus de travailleurs pour g\u00e9rer un trafic plus important.<\/p>\n<p><b>8. Pas de d\u00e9pendance \u00e0 un seul cloud<\/b><br \/>\nL'infrastructure de CloudRetro est h\u00e9berg\u00e9e sur diff\u00e9rents fournisseurs de cloud (Digital Ocean, Alibaba, fournisseur personnalis\u00e9) pour diverses r\u00e9gions. J'active le d\u00e9marrage dans un conteneur Docker pour l'infrastructure et configure les param\u00e8tres r\u00e9seau \u00e0 l'aide d'un script bash, afin d'\u00e9viter de d\u00e9pendre d'un seul fournisseur de cloud. En combinant cela avec le NAT Traversal dans WebRTC, nous pouvons obtenir la flexibilit\u00e9 de d\u00e9ployer CloudRetro sur n'importe quelle plateforme cloud et m\u00eame sur les machines de n'importe quel utilisateur.<\/p>\n<h3>Conception architecturale<\/h3>\n<p>\n<b>Travailleur:<\/b> (ou le serveur de streaming mentionn\u00e9 ci-dessus) multiplie les jeux, ex\u00e9cute le pipeline d'encodage et transmet les m\u00e9dias encod\u00e9s aux utilisateurs. Les instances de travailleur sont r\u00e9parties dans le monde entier, et chaque travailleur peut traiter plusieurs sessions utilisateur simultan\u00e9ment.<\/p>\n<p><b>Coordinateur :<\/b> responsable de l'association d'un nouvel utilisateur avec le travailleur le plus appropri\u00e9 pour le streaming. Le coordinateur interagit avec les travailleurs via WebSocket.<\/p>\n<p><b>Stockage des \u00e9tats de jeu :<\/b> un stockage d\u00e9centralis\u00e9 central pour tous les \u00e9tats du jeu. Ce stockage offre des fonctionnalit\u00e9s essentielles telles que la sauvegarde et le chargement \u00e0 distance.<\/p>\n<p><img decoding=\"async\" alt=\"Jeux en nuage open source sur WebRTC : p2p, multijoueur, z\u00e9ro latence\" src=\"\/wp-content\/uploads\/2020\/07\/985447b81350a640b0bd1344b5705113.png\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nArchitecture CloudRetro de haut niveau<\/p>\n<h3>Sc\u00e9nario utilisateur<\/h3>\n<p>\nLorsqu'un nouvel utilisateur ouvre CloudRetro aux \u00e9tapes 1 et 2 pr\u00e9sent\u00e9es ci-dessous, le coordinateur est consult\u00e9 avec la liste des travailleurs disponibles sur la premi\u00e8re page. Ensuite, \u00e0 l'\u00e9tape 3, le client calcule les latences pour tous les candidats \u00e0 l'aide d'une requ\u00eate HTTP ping. Cette liste de latences est ensuite renvoy\u00e9e au coordinateur, qui peut d\u00e9terminer le travailleur le plus adapt\u00e9 pour servir l'utilisateur. \u00c0 l'\u00e9tape 4 ci-dessous, le jeu est cr\u00e9\u00e9. Une connexion de streaming WebRTC est \u00e9tablie entre l'utilisateur et le travailleur d\u00e9sign\u00e9.<br \/>\n<img decoding=\"async\" alt=\"Jeux en nuage open source sur WebRTC : p2p, multijoueur, z\u00e9ro latence\" src=\"\/wp-content\/uploads\/2020\/07\/00199b5942e3e4314609ec0e70ea7162.png\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nSc\u00e9nario utilisateur apr\u00e8s acc\u00e8s<\/p>\n<h3>Que contient le travailleur<\/h3>\n<p>\nLes pipelines de jeux et de streaming sont stock\u00e9s de mani\u00e8re isol\u00e9e \u00e0 l'int\u00e9rieur du travailleur et \u00e9changent des informations via une interface. Actuellement, cette liaison se fait par le biais de la transmission de donn\u00e9es en m\u00e9moire via <noindex><a rel=\"nofollow\" href=\"https:\/\/tour.golang.org\/concurrency\/2\">les canaux Golang<\/a><\/noindex> dans le m\u00eame processus. L\u2019objectif suivant est la segmentation, c\u2019est-\u00e0-dire l'ex\u00e9cution ind\u00e9pendante du jeu dans un autre processus.<\/p>\n<p><img decoding=\"async\" alt=\"Jeux en nuage open source sur WebRTC : p2p, multijoueur, z\u00e9ro latence\" src=\"\/wp-content\/uploads\/2020\/07\/7a90ec2638344467a34604cd4322165c.png\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nInteraction des composants du travailleur<\/p>\n<p>Principales composantes :<\/p>\n<ul>\n<li><b>WebRTC :<\/b> composant client qui re\u00e7oit les entr\u00e9es de l'utilisateur et restitue les m\u00e9dias encod\u00e9s du serveur.\n<\/li>\n<li><b>\u00c9mulateur de jeu :<\/b> composant de jeu. Gr\u00e2ce \u00e0 la biblioth\u00e8que Libretro, le syst\u00e8me est capable d'ex\u00e9cuter le jeu dans le m\u00eame processus et de capturer int\u00e9rieurement les m\u00e9dias et les flux d'entr\u00e9e.\n<\/li>\n<li>Les images\/vid\u00e9os du jeu sont captur\u00e9es et envoy\u00e9es \u00e0 l'encodeur.\n<\/li>\n<li><b>Encodeur image\/son :<\/b> pipeline d'encodage qui prend les images\/vid\u00e9os, les encode en arri\u00e8re-plan et restitue les images\/vid\u00e9os encod\u00e9es.\n<\/li>\n<\/ul>\n<p><\/p>\n<h2>Mise en \u0153uvre<\/h2>\n<p>\nCloudRetro s'appuie sur WebRTC comme technologie cl\u00e9, donc avant de plonger dans les d\u00e9tails de l'impl\u00e9mentation en Golang, j'ai d\u00e9cid\u00e9 de parler un peu de WebRTC lui-m\u00eame. C'est une technologie incroyable qui m'a beaucoup aid\u00e9 \u00e0 atteindre une latence de transmission de donn\u00e9es d'\u00e0 peine quelques millisecondes.<\/p>\n<h3>WebRTC<\/h3>\n<p>\nWebRTC est con\u00e7u pour fournir des connexions de pair \u00e0 pair de haute qualit\u00e9 sur des applications mobiles natives et dans les navigateurs via des API simples.<\/p>\n<h4>NAT Traversal <\/h4>\n<p>\nWebRTC est connu pour sa fonctionnalit\u00e9 de travers\u00e9e NAT. WebRTC est con\u00e7u pour la communication entre pairs. Son objectif est de trouver le chemin direct le plus appropri\u00e9, en \u00e9vitant les passerelles NAT et les pare-feu pour la communication entre pairs via un processus appel\u00e9 <noindex><a rel=\"nofollow\" href=\"https:\/\/webrtchacks.com\/trickle-ice\/\">ICE<\/a><\/noindex>. 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 (<noindex><a rel=\"nofollow\" href=\"https:\/\/webrtchacks.com\/?s=turn\">TURN<\/a><\/noindex>), lorsque la connexion directe ne peut pas \u00eatre \u00e9tablie.<\/p>\n<p>Cependant, CloudRetro n'exploite pas pleinement cette capacit\u00e9. Ses connexions entre pairs n'existent pas entre les utilisateurs, mais entre les utilisateurs et les serveurs cloud. La partie serveur du mod\u00e8le a moins de restrictions sur la connexion directe que les appareils utilisateur ordinaires. Cela permet une ouverture pr\u00e9alable des ports entrants ou l'utilisation directe d'adresses IP publiques, car le serveur n'est pas derri\u00e8re un NAT.<\/p>\n<p>Autrefois, je voulais transformer le projet en une plateforme de distribution de jeux pour le Cloud Gaming. L'id\u00e9e \u00e9tait de permettre aux cr\u00e9ateurs de jeux de fournir des jeux et des ressources de streaming. Les utilisateurs interagiraient directement avec les fournisseurs. De cette mani\u00e8re d\u00e9centralis\u00e9e, CloudRetro n'est qu'un environnement pour connecter des ressources de streaming tierces aux utilisateurs, le rendant plus \u00e9volutif, maintenant qu'il n'est plus charg\u00e9 de l'h\u00e9bergement. Le r\u00f4le de la travers\u00e9e NAT de WebRTC est ici tr\u00e8s important pour faciliter l'initialisation de la connexion entre pairs sur des ressources de streaming tierces, ce qui simplifie la connexion du cr\u00e9ateur au r\u00e9seau.<\/p>\n<h4>Compression vid\u00e9o<\/h4>\n<p>\nLa compression vid\u00e9o est une partie indispensable du pipeline, contribuant largement \u00e0 la fluidit\u00e9 du flux. Bien qu'il ne soit pas n\u00e9cessaire de conna\u00eetre tous les d\u00e9tails de l'encodage vid\u00e9o en VP8\/H264, comprendre le concept aide \u00e0 appr\u00e9hender les param\u00e8tres de d\u00e9bit vid\u00e9o en streaming, \u00e0 d\u00e9boguer un comportement inattendu et \u00e0 r\u00e9gler la latence.<\/p>\n<p>La compression vid\u00e9o pour les services de streaming est une t\u00e2che complexe, car l'algorithme doit garantir que le temps total d'encodage + le temps de transmission r\u00e9seau + le temps de d\u00e9codage est aussi r\u00e9duit que possible. De plus, le processus d'encodage doit \u00eatre constant et ininterrompu. Certaines concessions dans l'encodage ne sont pas applicables \u2013 par exemple, nous ne pouvons pas pr\u00e9f\u00e9rer un temps d'encodage prolong\u00e9 \u00e0 une taille de fichier plus petite et \u00e0 un temps de d\u00e9codage, ou utiliser une compression non coh\u00e9rente.<\/p>\n<p>L'id\u00e9e de la compression vid\u00e9o consiste \u00e0 \u00e9liminer les bits d'information superflus tout en maintenant un niveau de pr\u00e9cision acceptable pour les utilisateurs. En plus de l'encodage des images individuelles, l'algorithme tire les conclusions pour le cadre actuel \u00e0 partir des pr\u00e9c\u00e9dents et suivants, donc seule leur diff\u00e9rence est transmise. Comme le montre l'exemple de Pacman, seules les points diff\u00e9rentiels sont envoy\u00e9s.<\/p>\n<p><img decoding=\"async\" alt=\"Jeux en nuage open source sur WebRTC : p2p, multijoueur, z\u00e9ro latence\" src=\"\/wp-content\/uploads\/2020\/07\/e452c54c53ab7797b610620aefbba8d2.png\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nComparaison de cadres vid\u00e9o avec l'exemple de Pacman<\/p>\n<h4>Compression audio<\/h4>\n<p>\nDe la m\u00eame mani\u00e8re, l'algorithme de compression audio omet les donn\u00e9es qui ne peuvent pas \u00eatre per\u00e7ues par l'homme. Actuellement, Opus est le codec audio avec les meilleures performances. Il a \u00e9t\u00e9 con\u00e7u pour transmettre des ondes audio via un protocole de datagramme ordonn\u00e9, tel que RTP (Real Time Transport Protocol). Sa latence est inf\u00e9rieure \u00e0 celle de mp3 et aac, avec une qualit\u00e9 sup\u00e9rieure. La latence est g\u00e9n\u00e9ralement d'environ 5 \u00e0 66,5 ms.<\/p>\n<h4>Pion, WebRTC en Golang<\/h4>\n<p>\n<noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/pion\/webrtc\">Pion<\/a><\/noindex> est un projet open source qui int\u00e8gre WebRTC dans Golang. Au lieu d'envelopper les biblioth\u00e8ques C++ natives de WebRTC, Pion est une impl\u00e9mentation native de WebRTC en Golang offrant de meilleures performances, une int\u00e9gration avec Go, ainsi qu'un contr\u00f4le des versions sur les protocoles WebRTC.<\/p>\n<p>La biblioth\u00e8que offre \u00e9galement un streaming avec de nombreux excellents modules int\u00e9gr\u00e9s avec un retard de moins d'une seconde. Elle poss\u00e8de sa propre impl\u00e9mentation de STUN, DTLS, SCTP, etc., et exp\u00e9rimente avec QUIC et WebAssembly. En soi, cette biblioth\u00e8que open-source est vraiment une bonne source d'apprentissage avec une excellente documentation, mise en \u0153uvre des protocoles r\u00e9seau et de superbes exemples.<\/p>\n<p>La communaut\u00e9 Pion, dirig\u00e9e par un cr\u00e9ateur tr\u00e8s passionn\u00e9, est assez anim\u00e9e, avec de nombreuses discussions de qualit\u00e9 sur WebRTC. Si vous \u00eates int\u00e9ress\u00e9 par cette technologie, rejoignez <noindex><a rel=\"nofollow\" href=\"http:\/\/pion.ly\/slack\">http:\/\/pion.ly\/slack<\/a><\/noindex> \u2013 vous apprendrez beaucoup de nouvelles choses.<\/p>\n<h3>\u00c9criture de CloudRetro en Golang<\/h3>\n<p>\n<img decoding=\"async\" alt=\"Jeux en nuage open source sur WebRTC : p2p, multijoueur, z\u00e9ro latence\" src=\"\/wp-content\/uploads\/2020\/07\/f85f7b8ea579fab964d870aad698c7e7.png\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nMise en \u0153uvre d'un worker en Go<\/p>\n<h4>Canaux Go en action<\/h4>\n<p>\nGr\u00e2ce \u00e0 la belle conception des canaux Go, les probl\u00e8mes de streaming d'\u00e9v\u00e9nements et de parall\u00e9lisme sont consid\u00e9rablement simplifi\u00e9s. Comme indiqu\u00e9 dans le diagramme, plusieurs composants fonctionnent parall\u00e8lement dans diff\u00e9rentes GoRoutines. Chaque composant g\u00e8re son \u00e9tat et communique via des canaux. L'instruction s\u00e9lective de Golang force \u00e0 traiter un \u00e9v\u00e9nement atomique \u00e0 la fois \u00e0 chaque moment dans le jeu (game tick). Cela signifie qu'aucun verrou n'est n\u00e9cessaire pour ce design. Par exemple, lorsque l'utilisateur se sauvegarde, un snapshot complet de l'\u00e9tat du jeu est requis. Cet \u00e9tat doit rester coh\u00e9rent, effectuant des entr\u00e9es jusqu'\u00e0 ce que la sauvegarde soit termin\u00e9e. Lors de chaque game tick, le backend ne peut traiter qu'une seule op\u00e9ration de sauvegarde ou d'entr\u00e9e, ce qui rend le processus s\u00e9curis\u00e9 par rapport aux threads.<\/p>\n<pre><code class=\"go\">func (e *gameEmulator) gameUpdate() {\nfor {\n\tselect {\n\t\tcase &lt;-e.saveOperation:\n\t\t\te.saveGameState()\n\t\tcase key := &lt;-e.input:\n\t\t\te.updateGameState(key)\n\t\tcase &lt;-e.done:\n\t\t\te.close()\n\t\t\treturn\n\t}\n    }\n}<\/code><\/pre>\n<p><\/p>\n<h4>Fan-in \/ Fan-out<\/h4>\n<p>\nCe mod\u00e8le Golang convient parfaitement \u00e0 mon cas d'utilisation de CrowdPlay et de plusieurs joueurs. En suivant ce mod\u00e8le, toutes les entr\u00e9es utilisateur dans une salle sont int\u00e9gr\u00e9es dans un canal d'entr\u00e9e central. Les m\u00e9dias de jeu sont ensuite diffus\u00e9s \u00e0 tous les utilisateurs dans cette salle. Ainsi, nous atteignons une s\u00e9paration de l'\u00e9tat du jeu entre plusieurs sessions de jeu de diff\u00e9rents utilisateurs.<\/p>\n<p><img decoding=\"async\" alt=\"Jeux en nuage open source sur WebRTC : p2p, multijoueur, z\u00e9ro latence\" src=\"\/wp-content\/uploads\/2020\/07\/000a495d7f214246a8a396aab11a3ac5.png\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nSynchronisation entre diff\u00e9rentes sessions<\/p>\n<h4>Inconv\u00e9nients de Golang<\/h4>\n<p>\nGolang n'est pas parfait. Le canal est lent. Compar\u00e9 \u00e0 un blocage, le canal Go est simplement une mani\u00e8re plus simple de g\u00e9rer des \u00e9v\u00e9nements parall\u00e8les 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\u00e9 quelques modifications \u00e0 l'impl\u00e9mentation, en r\u00e9utilisant des verrous et des valeurs atomiques \u00e0 la place des canaux pour optimiser la performance.<\/p>\n<p>De plus, le ramasse-miettes dans Golang est incontr\u00f4lable, ce qui entra\u00eene parfois des pauses suspectes et prolong\u00e9es. Cela perturbe consid\u00e9rablement le fonctionnement des applications en temps r\u00e9el.<\/p>\n<h4>CGO<\/h4>\n<p>\nLe projet utilise la biblioth\u00e8que VP8\/H264 existante en open source de Golang pour la compression m\u00e9dia et Libretro pour les \u00e9mulateurs de jeux. Toutes ces biblioth\u00e8ques ne sont que des wrappers de la biblioth\u00e8que C en Go utilisant <noindex><a rel=\"nofollow\" href=\"https:\/\/golang.org\/cmd\/cgo\/\">CGO<\/a><\/noindex>. Certains des inconv\u00e9nients sont \u00e9num\u00e9r\u00e9s dans <noindex><a rel=\"nofollow\" href=\"https:\/\/dave.cheney.net\/2019\/10\/06\/use-internal-packages-to-reduce-your-public-api-surface\">ce post de Dave Cheney<\/a><\/noindex>. Les probl\u00e8mes auxquels j'ai \u00e9t\u00e9 confront\u00e9 :<\/p>\n<ul>\n<li>impossibilit\u00e9 de capturer un crash dans CGO, m\u00eame avec l'aide de Golang RecoveryCrash ;<\/li>\n<li>impossibilit\u00e9 de d\u00e9terminer le goulet d'\u00e9tranglement en performance, lorsque nous ne pouvons pas d\u00e9tecter les probl\u00e8mes d\u00e9taill\u00e9s dans CGO.<\/li>\n<\/ul>\n<p><\/p>\n<h2>Conclusion<\/h2>\n<p>\nJ'ai atteint mon objectif \u2013 je me suis plong\u00e9 dans les services de jeux dans le cloud et j'ai cr\u00e9\u00e9 une plateforme qui permet de jouer \u00e0 des jeux r\u00e9tro nostalgiques avec mes amis en ligne. La cr\u00e9ation de ce projet n'aurait pas \u00e9t\u00e9 possible sans la biblioth\u00e8que Pion et le soutien de la communaut\u00e9 Pion. Je suis extr\u00eamement reconnaissant pour son d\u00e9veloppement intensif. Les API simples fournies par WebRTC et Pion ont permis une int\u00e9gration fluide. Ma premi\u00e8re preuve de concept a \u00e9t\u00e9 lanc\u00e9e la m\u00eame semaine, m\u00eame si je n'avais pas \u00e0 l'avance connaissance de la connexion peer-to-peer (P2P).<\/p>\n<p>Malgr\u00e9 la simplicit\u00e9 d'int\u00e9gration, le streaming P2P est en r\u00e9alit\u00e9 un domaine tr\u00e8s complexe en informatique. Il doit faire face \u00e0 la complexit\u00e9 des architectures r\u00e9seau \u00e9tablies depuis des ann\u00e9es, telles que l'IP et le NAT pour \u00e9tablir une session peer-to-peer. Au cours de ce projet, j'ai acquis de nombreuses connaissances pr\u00e9cieuses sur le r\u00e9seau et l'optimisation de la performance, par cons\u00e9quent, je recommande \u00e0 tous d'essayer de construire des produits P2P en utilisant WebRTC.<\/p>\n<p>CloudRetro g\u00e8re tous les sc\u00e9narios d'utilisation que j'attendais, de mon point de vue en tant que passionn\u00e9 de r\u00e9tro-gaming. Cependant, je pense qu'il y a de nombreux domaines dans le projet que je peux am\u00e9liorer, comme rendre le r\u00e9seau plus fiable et performant, assurer une meilleure qualit\u00e9 graphique des jeux, ou permettre le partage de jeux entre utilisateurs. Je travaille dur l\u00e0-dessus. Veuillez suivre <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/giongto35\/cloud-game\">le projet<\/a><\/noindex> et le soutenir si cela vous pla\u00eet.<\/li>\n<\/ul>\n<p>Source : <a content=\"nofollow\" rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/Voximplant\/blog\/511626\/\">habr.com<\/a> <\/p>","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"excerpt":{"rendered":"<p>\u041f\u041e \u043a\u0430\u043a \u0443\u0441\u043b\u0443\u0433\u0430, \u0438\u043d\u0444\u0440\u0430\u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u043a\u0430\u043a \u0443\u0441\u043b\u0443\u0433\u0430, \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u0430 \u043a\u0430\u043a \u0443\u0441\u043b\u0443\u0433\u0430, \u043a\u043e\u043c\u043c\u0443\u043d\u0438\u043a\u0430\u0446\u0438\u043e\u043d\u043d\u0430\u044f \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u0430 \u043a\u0430\u043a \u0443\u0441\u043b\u0443\u0433\u0430, \u0432\u0438\u0434\u0435\u043e\u043a\u043e\u043d\u0444\u0435\u0440\u0435\u043d\u0446\u0438\u0438 \u043a\u0430\u043a \u0443\u0441\u043b\u0443\u0433\u0430, \u0430 \u0447\u0442\u043e \u043d\u0430\u0441\u0447\u0435\u0442 \u043e\u0431\u043b\u0430\u0447\u043d\u044b\u0445 \u0438\u0433\u0440 \u043a\u0430\u043a \u0443\u0441\u043b\u0443\u0433\u0438? \u0423\u0436\u0435 \u0431\u044b\u043b\u043e \u043f\u0440\u0435\u0434\u043f\u0440\u0438\u043d\u044f\u0442\u043e \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043f\u043e\u043f\u044b\u0442\u043e\u043a \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u043e\u0431\u043b\u0430\u0447\u043d\u044b\u0445 \u0438\u0433\u0440 (Cloud Gaming), \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, Stadia, \u043d\u0435\u0434\u0430\u0432\u043d\u043e \u0437\u0430\u043f\u0443\u0449\u0435\u043d\u043d\u0430\u044f \u043a\u043e\u043c\u043f\u0430\u043d\u0438\u0435\u0439 Google. Stadia \u043d\u0435 \u043d\u043e\u0432\u0438\u0447\u043e\u043a \u0432 WebRTC, \u043d\u043e \u043c\u043e\u0433\u0443\u0442 \u043b\u0438 \u0434\u0440\u0443\u0433\u0438\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c WebRTC \u0442\u0430\u043a \u0436\u0435? \u0422\u0445\u0430\u043d\u044c \u041d\u0433\u0443\u0435\u043d (Thanh [&hellip;]<\/p>\n","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"author":1,"featured_media":89304,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[688],"tags":[],"class_list":["post-89303","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-administrirovanie"],"aioseo_notices":[],"aioseo_head":"\n\t\t<!-- All in One SEO 5.0.2 - aioseo.com -->\n\t<meta name=\"robots\" content=\"max-image-preview:large\" \/>\n\t<meta name=\"author\" content=\"Yuri Gagarin\"\/>\n\t<link rel=\"canonical\" href=\"https:\/\/prohoster.info\/fr\/blog\/administrirovanie\/oblachnyj-gejming-s-otkrytym-ishodnym-kodom-na-webrtc-p2p-multipleer-zero-latency\" \/>\n\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 5.0.2\" \/>\n\t\t<meta property=\"og:locale\" content=\"fr_FR\" \/>\n\t\t<meta property=\"og:site_name\" content=\"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b\" \/>\n\t\t<meta property=\"og:type\" content=\"article\" \/>\n\t\t<meta property=\"og:title\" content=\"\ud83e\udd47\u041e\u0431\u043b\u0430\u0447\u043d\u044b\u0439 \u0433\u0435\u0439\u043c\u0438\u043d\u0433 \u0441 \u043e\u0442\u043a\u0440\u044b\u0442\u044b\u043c \u0438\u0441\u0445\u043e\u0434\u043d\u044b\u043c \u043a\u043e\u0434\u043e\u043c \u043d\u0430 WebRTC: p2p, \u043c\u0443\u043b\u044c\u0442\u0438\u043f\u043b\u0435\u0435\u0440, zero latency | ProHoster\" \/>\n\t\t<meta property=\"og:url\" content=\"https:\/\/prohoster.info\/fr\/blog\/administrirovanie\/oblachnyj-gejming-s-otkrytym-ishodnym-kodom-na-webrtc-p2p-multipleer-zero-latency\" \/>\n\t\t<meta property=\"og:image\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:secure_url\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:width\" content=\"350\" \/>\n\t\t<meta property=\"og:image:height\" content=\"350\" \/>\n\t\t<meta property=\"article:published_time\" content=\"2020-07-21T23:42:30+00:00\" \/>\n\t\t<meta property=\"article:modified_time\" content=\"2020-07-21T23:42:30+00:00\" \/>\n\t\t<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<meta property=\"article:author\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<!-- All in One SEO -->\n\n","aioseo_head_json":{"title":"\ud83e\udd47 Jeu cloud open source sur WebRTC : p2p, multijoueur, z\u00e9ro latence | ProHoster","description":"","canonical_url":"https:\/\/prohoster.info\/fr\/blog\/administrirovanie\/oblachnyj-gejming-s-otkrytym-ishodnym-kodom-na-webrtc-p2p-multipleer-zero-latency","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"fr_FR","og:site_name":"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b","og:type":"article","og:title":"\ud83e\udd47\u041e\u0431\u043b\u0430\u0447\u043d\u044b\u0439 \u0433\u0435\u0439\u043c\u0438\u043d\u0433 \u0441 \u043e\u0442\u043a\u0440\u044b\u0442\u044b\u043c \u0438\u0441\u0445\u043e\u0434\u043d\u044b\u043c \u043a\u043e\u0434\u043e\u043c \u043d\u0430 WebRTC: p2p, \u043c\u0443\u043b\u044c\u0442\u0438\u043f\u043b\u0435\u0435\u0440, zero latency | ProHoster","og:url":"https:\/\/prohoster.info\/fr\/blog\/administrirovanie\/oblachnyj-gejming-s-otkrytym-ishodnym-kodom-na-webrtc-p2p-multipleer-zero-latency","og:image":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:secure_url":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:width":350,"og:image:height":350,"article:published_time":"2020-07-21T23:42:30+00:00","article:modified_time":"2020-07-21T23:42:30+00:00","article:publisher":"https:\/\/www.facebook.com\/prohoster","article:author":"https:\/\/www.facebook.com\/prohoster"},"aioseo_meta_data":{"post_id":"89303","title":null,"description":null,"keywords":null,"keyphrases":null,"primary_term":null,"canonical_url":null,"og_title":null,"og_description":null,"og_object_type":"default","og_image_type":"default","og_image_url":null,"og_image_width":null,"og_image_height":null,"og_image_custom_url":null,"og_image_custom_fields":null,"og_video":null,"og_custom_url":null,"og_article_section":null,"og_article_tags":null,"twitter_use_og":false,"twitter_card":"default","twitter_image_type":"default","twitter_image_url":null,"twitter_image_custom_url":null,"twitter_image_custom_fields":null,"twitter_title":null,"twitter_description":null,"schema":{"blockGraphs":[],"customGraphs":[],"default":{"data":{"Article":[],"Course":[],"Dataset":[],"FAQPage":[],"Movie":[],"Person":[],"Product":[],"ProductReview":[],"Car":[],"Recipe":[],"Service":[],"SoftwareApplication":[],"WebPage":[]},"graphName":"","isEnabled":true},"graphs":[]},"schema_type":null,"schema_type_options":null,"pillar_content":false,"robots_default":true,"robots_noindex":false,"robots_noarchive":false,"robots_nosnippet":false,"robots_nofollow":false,"robots_noimageindex":false,"robots_noodp":false,"robots_notranslate":false,"robots_max_snippet":null,"robots_max_videopreview":null,"robots_max_imagepreview":"large","priority":null,"frequency":null,"local_seo":null,"seo_analyzer_scan_date":null,"breadcrumb_settings":null,"limit_modified_date":false,"reviewed_by":null,"ai":null,"created":"2021-02-28 13:12:27","updated":"2022-09-29 13:03:06","focus_keyword":null,"additional_keywords":null,"truseo_locale":null},"gt_translate_keys":[{"key":"link","format":"url"}],"_links":{"self":[{"href":"https:\/\/prohoster.info\/fr\/wp-json\/wp\/v2\/posts\/89303","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/fr\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/fr\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/fr\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/fr\/wp-json\/wp\/v2\/comments?post=89303"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/fr\/wp-json\/wp\/v2\/posts\/89303\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/prohoster.info\/fr\/wp-json\/wp\/v2\/media\/89304"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/fr\/wp-json\/wp\/v2\/media?parent=89303"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/fr\/wp-json\/wp\/v2\/categories?post=89303"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/fr\/wp-json\/wp\/v2\/tags?post=89303"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}