{"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\/de\/blog\/administrirovanie\/oblachnyj-gejming-s-otkrytym-ishodnym-kodom-na-webrtc-p2p-multipleer-zero-latency","title":{"rendered":"Cloud-Gaming mit Open Source auf WebRTC: p2p, Mehrspieler, null Latenz","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=\"Cloud-Gaming mit Open Source auf WebRTC: p2p, Mehrspieler, null Latenz\" src=\"\/wp-content\/uploads\/2020\/07\/22dbf7665d7fded15671d98a2afe599b.png\" style=\"display:block;margin: 0 auto;\" \/><\/a><\/noindex><br \/>\nCloud als Dienst, Infrastruktur als Dienst, Plattform als Dienst, Kommunikationsplattform als Dienst, Videokonferenzen als Dienst, und was ist mit Cloud Gaming als Dienst? Es gab bereits mehrere Versuche zur Schaffung von Cloud-Gaming, wie zum Beispiel Stadia, das k\u00fcrzlich von Google lanciert wurde. Stadia <noindex><a rel=\"nofollow\" href=\"https:\/\/youtu.be\/avtlQeaxd_I?t=440\">ist kein Neuling in WebRTC<\/a><\/noindex>, aber k\u00f6nnen andere WebRTC auch so verwenden?<noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><\/p>\n<p>Thanh Nguyen beschloss, diese M\u00f6glichkeit in seinem Open-Source-Projekt CloudRetro zu testen. CloudRetro basiert auf Pion, <noindex><a rel=\"nofollow\" href=\"https:\/\/webrtchacks.com\/webrtc-open-source-most-popular\/\">eine beliebte<\/a><\/noindex> WebRTC-Bibliothek auf Basis von Go (danke <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/Sean-Der\">Sean<\/a><\/noindex> aus dem Pion-Entwicklerteam f\u00fcr die Unterst\u00fctzung bei der Erstellung dieses Artikels). In diesem Artikel gibt Thanh einen \u00dcberblick \u00fcber die Architektur seines Projekts und erz\u00e4hlt, was er dabei gelernt hat und mit welchen Herausforderungen er w\u00e4hrend der Arbeit konfrontiert war.<\/p>\n<h2>Einleitung<\/h2>\n<p>\nAls Google Stadia im letzten Jahr ank\u00fcndigte, war ich einfach \u00fcberw\u00e4ltigt. Die Idee ist so einzigartig und innovativ, dass ich mich st\u00e4ndig fragte, wie so etwas mit bestehenden Technologien \u00fcberhaupt m\u00f6glich sein kann. Der Wunsch, dieses Thema besser zu verstehen, motivierte mich, meine eigene Version eines Open-Source-Cloud-Games zu erstellen. Das Ergebnis war einfach fantastisch. Im Folgenden m\u00f6chte ich den Prozess meiner einj\u00e4hrigen <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/giongto35\/cloud-game\">Projektarbeit<\/a><\/noindex>.<\/p>\n<p><i>TLDR: Kurze Slide-Version mit den wichtigsten Punkten<\/i><\/p>\n<h3>Warum die Zukunft den Cloud-Spielen geh\u00f6rt<\/h3>\n<p>\nIch glaube, dass Cloud Gaming bald eine neue Generation von nicht nur Spielen, sondern auch anderen Bereichen der Informatik darstellen wird. Cloud-Gaming ist der Gipfel des Client\/Server-Modells. Dieses Modell maximiert die Kontrolle \u00fcber das Backend und minimiert die Arbeit des Frontends, indem die Spiel-Logik auf einem entfernten Server ausgef\u00fchrt und Bild-\/Audio-Streams an den Client gesendet werden. Der Server f\u00fchrt die rechenintensive Verarbeitung durch, weshalb der Client nicht mehr von Hardware-Limitierungen abh\u00e4ngig ist.<\/p>\n<p>Google Stadia erm\u00f6glicht es im Grunde, AAA-Spiele <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)\">(d.h. hochwertige Blockbuster-Spiele) \u00fcber eine Benutzeroberfl\u00e4che wie YouTube zu spielen. Dieselbe Methodik kann auch auf andere ressourcenintensive Offline-Anwendungen wie Betriebssysteme oder 2D\/3D Grafikdesign usw. angewendet werden, sodass wir sie stabil auf Ger\u00e4ten mit niedrigen technischen Spezifikationen auf verschiedenen Plattformen ausf\u00fchren k\u00f6nnen.<\/a><\/noindex> Die Zukunft dieser Technologie: Stellen Sie sich vor, Microsoft Windows 10 w\u00fcrde im Browser Chrome laufen.<\/p>\n<p><img decoding=\"async\" alt=\"Cloud-Gaming mit Open Source auf WebRTC: p2p, Mehrspieler, null Latenz\" src=\"\/wp-content\/uploads\/2020\/07\/d6ca3e47db5c8e3d9880b304cc3be33b.png\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nCloud-Gaming ist technisch komplex.<\/p>\n<h3>Cloud-Gaming ist technisch anspruchsvoll.<\/h3>\n<p>\nGaming ist eines der wenigen Bereiche, in denen eine st\u00e4ndige schnelle Reaktion des Benutzers erforderlich ist. Wenn wir gelegentlich eine Verz\u00f6gerung von 2 Sekunden beim Klicken auf der Seite feststellen, ist das akzeptabel. Live-Streaming-Videos hinken in der Regel um einige Sekunden hinterher, bieten aber dennoch gen\u00fcgend Komfort bei der Nutzung. Wenn das Spiel jedoch h\u00e4ufig um 500 ms verz\u00f6gert wird, ist es einfach unm\u00f6glich zu spielen. Unser Ziel ist es, eine extrem niedrige Latenz zu erreichen, sodass der Abstand zwischen Eingabe und Medien so gering wie m\u00f6glich ist. Daher ist der traditionelle Ansatz f\u00fcr Streaming-Videos hier nicht anwendbar.<\/p>\n<p><img decoding=\"async\" alt=\"Cloud-Gaming mit Open Source auf WebRTC: p2p, Mehrspieler, null Latenz\" src=\"\/wp-content\/uploads\/2020\/07\/d73765a3c9277c026f407883e1091473.png\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nAllgemeines Muster des Cloud-Gaming<\/p>\n<h2>Open-Source-Projekt CloudRetro<\/h2>\n<p>\nIch habe beschlossen, ein Testmuster f\u00fcr Cloud-Gaming zu erstellen, um zu \u00fcberpr\u00fcfen, ob all dies unter solch strengen Netzwerkanforderungen m\u00f6glich ist. Zur Konzept\u00fcberpr\u00fcfung habe ich Golang gew\u00e4hlt, da es die mir vertrauteste Sprache ist und sich aus vielen anderen Gr\u00fcnden gut f\u00fcr diese Implementierung eignet, wie sich sp\u00e4ter herausstellte. Go ist einfach und entwickelt sich sehr schnell; die Kan\u00e4le in Go eignen sich hervorragend f\u00fcr die Verwaltung von Nebenl\u00e4ufigkeit.<\/p>\n<p>Projekt <noindex><a rel=\"nofollow\" href=\"http:\/\/cloudretro.io\/\">CloudRetro.io<\/a><\/noindex> \u2013 ein Cloud-Gaming-Dienst mit offenem Quellcode f\u00fcr Retro-Spiele. Das Ziel des Projekts ist es, den traditionellen Retro-Spielen die komfortabelsten Spielerlebnisse zu verleihen und Multiplayer-Funktionen hinzuzuf\u00fcgen.<br \/>\nDetails zum Projekt finden Sie hier: <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/giongto35\/cloud-game\">https:\/\/github.com\/giongto35\/cloud-game<\/a><\/noindex>.<\/p>\n<h3>Funktionalit\u00e4t von CloudRetro<\/h3>\n<p>\nUm die gesamte Power des Cloud-Gamings zu demonstrieren, werden in CloudRetro Retro-Spiele verwendet. Dadurch entstehen viele einzigartige Spielerlebnisse.<\/p>\n<ul>\n<li>Portabilit\u00e4t des Spiels\n<ul>\n<li>Sofortige Wiedergabe beim \u00d6ffnen der Seite; kein Download und keine Installation erforderlich<\/li>\n<li>Funktioniert im mobilen Browser, sodass keine Softwareinstallation erforderlich ist<\/li>\n<\/ul>\n<p>\n<\/li>\n<li>Spielsitzungen k\u00f6nnen auf mehreren Ger\u00e4ten zusammen genutzt und in der Cloud f\u00fcr den n\u00e4chsten Login gespeichert werden<\/li>\n<li>Das Spiel kann gestreamt werden, und gleichzeitig k\u00f6nnen mehrere Benutzer spielen:\n<ul>\n<li>Crowdplay \u00e4hnlich wie TwitchPlayPokemon, nur plattform\u00fcbergreifender und in Echtzeit-gesteuerter<\/li>\n<li>Offline-Spiele online. Viele Benutzer k\u00f6nnen ohne Netzwerksetup spielen. In Samurai Shodown k\u00f6nnen jetzt 2 Spieler \u00fcber das CloudRetro-Netzwerk spielen.<\/li>\n<\/ul>\n<p>\n<img decoding=\"async\" alt=\"Cloud-Gaming mit Open Source auf WebRTC: p2p, Mehrspieler, null Latenz\" src=\"\/wp-content\/uploads\/2020\/07\/bdc715971755d669a026f830ce888520.png\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nDemo-Version eines Mehrspieler-Online-Spiels auf verschiedenen Ger\u00e4ten<\/p>\n<h2>Infrastruktur<\/h2>\n<p><\/p>\n<h3>Anforderungen und Technologie-Stack<\/h3>\n<p>\nIm Folgenden finden Sie eine Liste der Anforderungen, die ich vor Beginn des Projekts festgelegt habe.<\/p>\n<p><b>1. Ein Spieler<\/b><br \/>\nDiese Anforderung mag hier nicht allzu wichtig und offensichtlich erscheinen, aber sie ist einer meiner entscheidenden Erkenntnisse, denn sie erm\u00f6glicht es Cloud-Gaming, sich so weit wie m\u00f6glich von traditionellen Streaming-Diensten zu entfernen. Wenn wir uns auf das Einzelspieler-Spiel konzentrieren, k\u00f6nnen wir auf einen zentralisierten Server oder CDN verzichten, da wir nicht auf Masse streamen m\u00fcssen. Anstatt Streams auf einen datengest\u00fctzten Server hochzuladen oder Pakete an einen zentralen WebSocket-Server zu \u00fcbertragen, werden die Service-Streams direkt \u00fcber eine Peer-to-Peer-Verbindung mit WebRTC an den Benutzer \u00fcbermittelt.<\/p>\n<p><b>2. Niedriglatenz-Mediastream<\/b><br \/>\nBeim Lesen \u00fcber Stadia sto\u00dfe ich in einigen Artikeln h\u00e4ufig auf den Hinweis auf WebRTC. Ich habe erkannt, dass WebRTC eine herausragende Technologie ist und sich hervorragend f\u00fcr den Einsatz in Cloud-Gaming eignet. WebRTC ist ein Projekt, das Echtzeitkommunikation f\u00fcr Webbrowser und mobile Anwendungen \u00fcber eine einfache API bereitstellt. Es bietet eine peer-to-peer Verbindung, die f\u00fcr Medien optimiert ist, und hat integrierte Standardcodecs wie VP8 und H264.<\/p>\n<p>Ich habe es vorgezogen, den Benutzern eine m\u00f6glichst angenehme Arbeit zu erm\u00f6glichen, anstatt eine hohe Grafikqualit\u00e4t aufrechtzuerhalten. Im Algorithmus sind einige Verluste zul\u00e4ssig. Bei Google Stadia gibt es einen zus\u00e4tzlichen Schritt zur Reduzierung der Bildgr\u00f6\u00dfe auf dem Server, und die Frames werden vor der \u00dcbertragung an die Peer-Knoten auf eine h\u00f6here Qualit\u00e4t skaliert.<\/p>\n<p><b>3. Verteilte Infrastruktur mit geografischer Routing<\/b><br \/>\nUnabh\u00e4ngig davon, wie optimiert der Komprimierungsalgorithmus und der Codec sind, ist das Netzwerk nach wie vor ein entscheidender Faktor, der am meisten zur Latenz beitr\u00e4gt. Die Architektur muss einen Mechanismus zur Verbindung des n\u00e4chstgelegenen Servers zum Benutzer haben, um die Rundreisezeit (RTT) zu minimieren. Die Architektur muss einen Koordinator und mehrere Streaming-Server weltweit haben: West-USA, Ost-USA, Europa, Singapur, China. Alle Streaming-Server m\u00fcssen vollst\u00e4ndig isoliert sein. Das System kann seine Verteilung regulieren, wenn ein Server dem Netzwerk beitritt oder es verl\u00e4sst. So erm\u00f6glicht das Hinzuf\u00fcgen zus\u00e4tzlicher Server bei hohem Datenverkehr horizontale Skalierung.<\/p>\n<p><b>4. Browserkompatibilit\u00e4t<\/b><br \/>\nCloud-Gaming kommt am besten zur Geltung, wenn es nur minimale Anforderungen an die Nutzer stellt. Das bedeutet, dass es im Browser gestartet werden kann. Browser helfen, das Spielerlebnis f\u00fcr die Nutzer so komfortabel wie m\u00f6glich zu gestalten, indem sie die Installation von Software und Hardware vermeiden. Au\u00dferdem gew\u00e4hrleisten Browser die Plattform\u00fcbergreifende Kompatibilit\u00e4t f\u00fcr mobile und Desktop-Versionen. Gl\u00fccklicherweise wird WebRTC in verschiedenen Browsern hervorragend unterst\u00fctzt.<\/p>\n<p><b>5. Klare Trennung von Benutzeroberfl\u00e4che und Dienst<\/b><br \/>\nIch betrachte den Cloud-Gaming-Dienst als Plattform. Jeder sollte die M\u00f6glichkeit haben, alles mit der Plattform zu verbinden. Momentan habe ich <noindex><a rel=\"nofollow\" href=\"http:\/\/LibRetro\">LibRetro<\/a><\/noindex> in den Cloud-Gaming-Dienst integriert, weil LibRetro eine ansprechende Benutzeroberfl\u00e4che f\u00fcr Retro-Spiele-Emulatoren wie SNES, GBA und PS bietet.<\/p>\n<p><b>6. R\u00e4ume f\u00fcr Mehrspieler, Crowd Play und Deep-Linking mit dem Spiel<\/b><br \/>\nCloudRetro unterst\u00fctzt zahlreiche neue Spielmodi wie CrowdPlay und Online-Mehrspieler f\u00fcr Retro-Spiele. Wenn mehrere Nutzer denselben Deep-Link auf verschiedenen Computern \u00f6ffnen, sehen sie dasselbe laufende Spiel und k\u00f6nnen sogar daran teilnehmen.<\/p>\n<p>Dar\u00fcber hinaus werden die Spielst\u00e4nde in der Cloud gespeichert. Das erm\u00f6glicht den Nutzern, das Spiel jederzeit auf jedem anderen Ger\u00e4t fortzusetzen.<\/p>\n<p><b>7. Horizontale Skalierbarkeit<\/b><br \/>\nWie jede SAAS-L\u00f6sung m\u00fcssen Cloud-Gaming-Dienste so entworfen werden, dass sie horizontal skalierbar sind. Die Struktur \"Koordinator-Arbeiter\" erm\u00f6glicht es, weitere Arbeiter hinzuzuf\u00fcgen, um einen gr\u00f6\u00dferen Datenverkehr zu bedienen.<\/p>\n<p><b>8. Keine Bindung an eine einzige Cloud<\/b><br \/>\nDie Infrastruktur von CloudRetro wird bei verschiedenen Cloud-Anbietern (Digital Ocean, Alibaba, benutzerdefinierter Anbieter) f\u00fcr verschiedene Regionen gehostet. Ich aktiviere den Start in einem Docker-Container f\u00fcr die Infrastruktur und konfiguriere die Netzwerkeinstellungen mit einem Bash-Skript, um eine Abh\u00e4ngigkeit von einem einzelnen Cloud-Anbieter zu vermeiden. Durch die Kombination mit NAT Traversal in WebRTC erhalten wir die Flexibilit\u00e4t, CloudRetro auf jeder Cloud-Plattform und sogar auf den Maschinen der Nutzer bereitzustellen.<\/p>\n<h3>Architektonisches Design<\/h3>\n<p>\n<b>Arbeiter:<\/b> (oder der oben erw\u00e4hnte Streaming-Server) vervielfacht Spiele, startet eine Codierungs-Pipeline und \u00fcbertr\u00e4gt das codierte Medium an die Benutzer. Die Worker-Instanzen sind weltweit verteilt, und jeder Worker kann mehrere Benutzersitzungen gleichzeitig verarbeiten.<\/p>\n<p><b>Koordinator:<\/b> verantwortlich f\u00fcr die Zuordnung eines neuen Benutzers zu dem am besten geeigneten Worker f\u00fcr das Streaming. Der Koordinator kommuniziert \u00fcber WebSocket mit den Workern.<\/p>\n<p><b>Speicher f\u00fcr Spielzust\u00e4nde:<\/b> zentraler Remote-Speicher f\u00fcr alle Spielst\u00e4nde. Dieses Speicher bietet wichtige Funktionen wie das Remote-Speichern\/Laden.<\/p>\n<p><img decoding=\"async\" alt=\"Cloud-Gaming mit Open Source auf WebRTC: p2p, Mehrspieler, null Latenz\" src=\"\/wp-content\/uploads\/2020\/07\/985447b81350a640b0bd1344b5705113.png\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n\u00dcbergeordnete Architektur von CloudRetro<\/p>\n<h3>Benutzerszenario<\/h3>\n<p>\nWenn ein neuer Benutzer CloudRetro \u00f6ffnet, wird in den Schritten 1 und 2, die in der Abbildung unten dargestellt sind, der Koordinator zusammen mit der Liste der verf\u00fcgbaren Worker zur ersten Seite angefragt. Anschlie\u00dfend berechnet der Client in Schritt 3 die Latenzen f\u00fcr alle Kandidaten durch einen HTTP-Ping-Anruf. Diese Liste von Latenzen wird dann an den Koordinator zur\u00fcckgesendet, damit er den am besten geeigneten Worker zur Betreuung des Benutzers bestimmen kann. In Schritt 4 wird ein Spiel erstellt. Zwischen dem Benutzer und dem zugewiesenen Worker wird eine WebRTC-Streaming-Verbindung hergestellt.<br \/>\n<img decoding=\"async\" alt=\"Cloud-Gaming mit Open Source auf WebRTC: p2p, Mehrspieler, null Latenz\" src=\"\/wp-content\/uploads\/2020\/07\/00199b5942e3e4314609ec0e70ea7162.png\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nBenutzerszenario nach dem Zugriff<\/p>\n<h3>Was sich im Worker befindet<\/h3>\n<p>\nDie Spiel- und Streaming-Pipelines werden innerhalb des Workers isoliert gespeichert und kommunizieren dort \u00fcber eine Schnittstelle. Derzeit erfolgt diese Kommunikation durch den Datenaustausch im Speicher \u00fcber <noindex><a rel=\"nofollow\" href=\"https:\/\/tour.golang.org\/concurrency\/2\">Golang-Kan\u00e4le<\/a><\/noindex> im selben Prozess. Das n\u00e4chste Ziel ist die Segregation, d.h. die unabh\u00e4ngige Ausf\u00fchrung des Spiels in einem anderen Prozess.<\/p>\n<p><img decoding=\"async\" alt=\"Cloud-Gaming mit Open Source auf WebRTC: p2p, Mehrspieler, null Latenz\" src=\"\/wp-content\/uploads\/2020\/07\/7a90ec2638344467a34604cd4322165c.png\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nInteraktion der Komponenten des Workers<\/p>\n<p>Hauptbestandteile:<\/p>\n<ul>\n<li><b>WebRTC:<\/b> Client-Komponente, die Benutzereingaben annimmt und das codierte Medium vom Server ausgibt.\n<\/li>\n<li><b>Spieleemulator:<\/b> Spielkomponente. Dank der Libretro-Bibliothek kann das System das Spiel innerhalb desselben Prozesses ausf\u00fchren und intern Medien und Eingangsstr\u00f6me abfangen.\n<\/li>\n<li>Ingame-Fotos werden erfasst und an den Encoder gesendet.\n<\/li>\n<li><b>Bild-\/Audio-Encoder:<\/b> Codierungs-Pipeline, die Medienbilder annimmt, diese im Hintergrund codiert und die codierten Bilder\/Audios ausgibt.\n<\/li>\n<\/ul>\n<p><\/p>\n<h2>Implementierung<\/h2>\n<p>\nCloudRetro setzt auf WebRTC als Schl\u00fcsseltechnologie. Bevor ich jedoch in die Einzelheiten der Implementierung in Golang eintauche, m\u00f6chte ich \u00fcber WebRTC selbst sprechen. Es ist eine erstaunliche Technologie, die mir geholfen hat, die Latenz bei der Daten\u00fcbertragung auf weniger als eine Sekunde zu reduzieren.<\/p>\n<h3>WebRTC<\/h3>\n<p>\nWebRTC ist darauf ausgelegt, qualitativ hochwertige Peer-to-Peer-Verbindungen auf nativen mobilen Anwendungen und in Browsern durch einfache APIs bereitzustellen.<\/p>\n<h4>NAT Traversal <\/h4>\n<p>\nWebRTC ist bekannt f\u00fcr seine Funktionalit\u00e4t zur Umgehung von NAT. WebRTC ist f\u00fcr die Peer-to-Peer-Kommunikation konzipiert. Ziel ist es, die am besten geeignete direkte Verbindung zu finden und NAT-Gateways sowie Firewalls durch einen Prozess mit dem Namen zu umgehen. <noindex><a rel=\"nofollow\" href=\"https:\/\/webrtchacks.com\/trickle-ice\/\">ICE<\/a><\/noindex>. Im Rahmen dieses Prozesses ermitteln die WebRTC-APIs Ihre \u00f6ffentliche IP-Adresse mithilfe von STUN-Servern und leiten sie an einen Relay-Server weiter (<noindex><a rel=\"nofollow\" href=\"https:\/\/webrtchacks.com\/?s=turn\">TURN<\/a><\/noindex>), wenn keine direkte Verbindung hergestellt werden kann.<\/p>\n<p>CloudRetro nutzt diese M\u00f6glichkeit jedoch nicht vollst\u00e4ndig. Seine Peer-to-Peer-Verbindungen bestehen nicht zwischen Benutzern, sondern zwischen Benutzern und Cloud-Servern. Die Serverseite des Modells hat weniger Einschr\u00e4nkungen hinsichtlich der direkten Kommunikation als ein typisches Benutzerger\u00e4t. Dies erm\u00f6glicht das Voraus\u00f6ffnen von eingehenden Ports oder die direkte Nutzung \u00f6ffentlicher IP-Adressen, da der Server nicht hinter einem NAT steht.<\/p>\n<p>Fr\u00fcher wollte ich das Projekt in eine Plattform zur Bereitstellung von Spielen f\u00fcr Cloud Gaming verwandeln. Die Idee war, es Spielesch\u00f6pfern zu erm\u00f6glichen, Spiele und Streaming-Ressourcen anzubieten. Die Benutzer w\u00fcrden direkt mit den Anbietern interagieren. Auf diese dezentralisierte Weise fungiert CloudRetro nur als Medium, um externe Streaming-Ressourcen mit Benutzern zu verbinden, was es skalierbarer macht, wenn das Hosting nicht mehr daran h\u00e4ngt. Die Rolle von WebRTC NAT Traversal ist hier entscheidend, um die Initiierung der Peer-to-Peer-Verbindung zu externen Streaming-Ressourcen zu erleichtern, was die Verbindung des Sch\u00f6pfers mit dem Netzwerk vereinfacht.<\/p>\n<h4>Videokompression<\/h4>\n<p>\nDie Videokompression ist ein unverzichtbarer Bestandteil der Pipeline, der ma\u00dfgeblich zur Stabilit\u00e4t des Streams beitr\u00e4gt. Obwohl es nicht unbedingt erforderlich ist, alle Details zur Videokodierung in VP8\/H264 zu kennen, hilft das Verst\u00e4ndnis des Konzepts dabei, die Parameter der Streaming-Video-Bitrate zu verstehen, unerwartetes Verhalten zu debuggen und die Latenz zu optimieren.<\/p>\n<p>Die Videokompression f\u00fcr Streaming-Dienste ist eine komplexe Aufgabe, da der Algorithmus sicherstellen muss, dass die Gesamtdauer der Kodierung + die \u00dcbertragungszeit im Netzwerk + die Dekodierungszeit so gering wie m\u00f6glich ist. Au\u00dferdem muss der Kodierungsprozess konsistent und kontinuierlich sein. Einige gegenseitige Kompromisse bei der Kodierung sind nicht anwendbar \u2013 beispielsweise k\u00f6nnen wir nicht eine l\u00e4ngere Kodierzeit einem kleineren Dateiformat und einer k\u00fcrzeren Dekodierungszeit vorziehen oder inkonsistente Kompression verwenden.<\/p>\n<p>Die Idee der Videokompression besteht darin, unn\u00f6tige Informationsbits auszuschlie\u00dfen, w\u00e4hrend ein akzeptables Genauigkeitsniveau f\u00fcr die Benutzer beibehalten wird. Neben der Kodierung einzelner statischer Bildrahmen zieht der Algorithmus seine Schlussfolgerungen f\u00fcr den aktuellen Frame aus dem vorherigen und dem n\u00e4chsten, sodass nur deren Differenz \u00fcbertragen wird. Wie im Beispiel mit Pacman zu sehen ist, werden nur die Differenzpunkte \u00fcbertragen.<\/p>\n<p><img decoding=\"async\" alt=\"Cloud-Gaming mit Open Source auf WebRTC: p2p, Mehrspieler, null Latenz\" src=\"\/wp-content\/uploads\/2020\/07\/e452c54c53ab7797b610620aefbba8d2.png\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nVergleich von Videorahmen am Beispiel von Pacman<\/p>\n<h4>Audiokompression<\/h4>\n<p>\nAnalog dazu l\u00e4sst der Audiokompressionsalgorithmus Daten weg, die vom Menschen nicht wahrgenommen werden k\u00f6nnen. Opus ist derzeit der leistungsf\u00e4higste Audiocodec. Er wurde entwickelt, um Audiowellen \u00fcber ein Protokoll f\u00fcr geordnete Datagramme wie RTP (Real Time Transport Protocol) zu \u00fcbertragen. Seine Latenz ist geringer als die von mp3 und aac, w\u00e4hrend die Qualit\u00e4t h\u00f6her ist. Die Latenz betr\u00e4gt normalerweise etwa 5~66,5 ms.<\/p>\n<h4>Pion, WebRTC in Golang<\/h4>\n<p>\n<noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/pion\/webrtc\">Pion<\/a><\/noindex> ist ein Open-Source-Projekt, das WebRTC nach Golang bringt. Anstatt die nativen C++-Bibliotheken von WebRTC zu umh\u00fcllen, ist Pion eine native Golang-Implementierung von WebRTC mit besserer Leistung, Integration in Go sowie Versionskontrolle f\u00fcr WebRTC-Protokolle.<\/p>\n<p>Die Bibliothek bietet auch das Streaming von Daten mit einer Vielzahl ausgezeichneter integrierter Module mit einer Verz\u00f6gerung von weniger als einer Sekunde. Sie hat ihre eigene Implementierung von STUN, DTLS, SCTP usw. und einige Experimente mit QUIC und WebAssembly. Diese Open-Source-Bibliothek ist eine wirklich gute Lernressource mit hervorragender Dokumentation, Implementierung von Netzwerkprotokollen und tollen Beispielen.<\/p>\n<p>Die Pion-Community, angef\u00fchrt von einem sehr leidenschaftlichen Ersteller, ist recht lebhaft und es gibt viele qualitativ hochwertige Diskussionen \u00fcber WebRTC. Wenn Sie an dieser Technologie interessiert sind, schlie\u00dfen Sie sich an <noindex><a rel=\"nofollow\" href=\"http:\/\/pion.ly\/slack\">http:\/\/pion.ly\/slack<\/a><\/noindex> \u2013 Sie werden viel Neues erfahren.<\/p>\n<h3>CloudRetro in Golang schreiben<\/h3>\n<p>\n<img decoding=\"async\" alt=\"Cloud-Gaming mit Open Source auf WebRTC: p2p, Mehrspieler, null Latenz\" src=\"\/wp-content\/uploads\/2020\/07\/f85f7b8ea579fab964d870aad698c7e7.png\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nImplementierung eines Workers in Go<\/p>\n<h4>Go-Kan\u00e4le in Aktion<\/h4>\n<p>\nDank des eleganten Designs der Go-Kan\u00e4le werden Probleme im Bereich Ereignis-Streaming und Parallelismus erheblich vereinfacht. Wie in der Grafik arbeiten mehrere Komponenten parallel in verschiedenen GoRoutinen. Jede Komponente verwaltet ihren eigenen Zustand und kommuniziert \u00fcber Kan\u00e4le. Die selektive Behauptung von Golang zwingt dazu, in jedem Moment des Spiels (game tick) ein atomarisches Ereignis zu verarbeiten. Das bedeutet, dass f\u00fcr dieses Design keine Sperrung erforderlich ist. Zum Beispiel, wenn der Benutzer speichert, wird ein vollst\u00e4ndiger Snapshot des Spielzustands ben\u00f6tigt. Dieser Zustand muss kontinuierlich bleiben, w\u00e4hrend die Eingabe verarbeitet wird, bis das Speichern abgeschlossen ist. W\u00e4hrend jedes game tick kann das Backend nur die Speicher- oder Eingabeoperation abwickeln, was den Prozess threadsicher macht.<\/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>\nDieses Golang-Muster eignet sich hervorragend f\u00fcr mein Anwendungs-Szenario von CrowdPlay und Multiple Player. Indem alle Benutzereingaben in einem Raum in einen zentralen Eingabekanal integriert werden, werden die Spielmedien an alle Benutzer im Raum verteilt. Auf diese Weise erreichen wir eine Trennung des Spielzustands zwischen mehreren Spielsitzungen verschiedener Benutzer.<\/p>\n<p><img decoding=\"async\" alt=\"Cloud-Gaming mit Open Source auf WebRTC: p2p, Mehrspieler, null Latenz\" src=\"\/wp-content\/uploads\/2020\/07\/000a495d7f214246a8a396aab11a3ac5.png\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nSynchronisation zwischen verschiedenen Sitzungen<\/p>\n<h4>Nachteile von Golang<\/h4>\n<p>\nGolang ist nicht perfekt. Der Kanal ist langsam. Im Vergleich zu Blockierungen ist der Go-Kanal einfach eine einfachere M\u00f6glichkeit, parallele und streamende Ereignisse zu verarbeiten, bietet jedoch nicht die beste Leistung. Unter dem Kanal liegt eine komplexe Blockierungslogik. Daher habe ich einige Anpassungen an der Implementierung vorgenommen, indem ich Blockierungen und atomare Werte bei der Ersetzung von Kan\u00e4len zur Leistungsoptimierung erneut angewendet habe.<\/p>\n<p>Dar\u00fcber hinaus ist der Garbage Collector in Golang unmanaged, was manchmal verd\u00e4chtig lange Pausen verursacht. Dies st\u00f6rt die Funktionalit\u00e4t von Echtzeitanwendungen erheblich.<\/p>\n<h4>CGO<\/h4>\n<p>\nIm Projekt wird eine bestehende VP8\/H264 Golang-Bibliothek mit Open-Source-Code zur Medienkompression und Libretro f\u00fcr Spielemulatoren verwendet. All diese Bibliotheken sind einfach Wrapper um die C-Bibliothek in Go, die verwenden. <noindex><a rel=\"nofollow\" href=\"https:\/\/golang.org\/cmd\/cgo\/\">CGO<\/a><\/noindex>. Einige der Nachteile sind in <noindex><a rel=\"nofollow\" href=\"https:\/\/dave.cheney.net\/2019\/10\/06\/use-internal-packages-to-reduce-your-public-api-surface\">diesem Beitrag von Dave Cheney<\/a><\/noindex>. Die Probleme, mit denen ich konfrontiert war, sind:<\/p>\n<ul>\n<li>die Unm\u00f6glichkeit, einen Crash in CGO zu erfassen, selbst mit Golang RecoveryCrash;<\/li>\n<li>die Unm\u00f6glichkeit, Engp\u00e4sse in der Leistung zu identifizieren, wenn wir keine detaillierten Probleme in CGO erkennen k\u00f6nnen.<\/li>\n<\/ul>\n<p><\/p>\n<h2>Fazit<\/h2>\n<p>\nIch habe mein Ziel erreicht \u2013 ich habe mich in Cloud-Gaming-Dienste eingearbeitet und eine Plattform geschaffen, die es erm\u00f6glicht, nostalgische Retro-Spiele online mit meinen Freunden zu spielen. Die Erstellung dieses Projekts w\u00e4re ohne die Pion-Bibliothek und die Unterst\u00fctzung der Pion-Community unm\u00f6glich gewesen. Ich bin \u00e4u\u00dferst dankbar f\u00fcr dessen intensive Entwicklung. Die einfachen APIs, die von WebRTC und Pion bereitgestellt werden, haben eine reibungslose Integration erm\u00f6glicht. Mein erstes Proof of Concept wurde in demselben Zeitraum ver\u00f6ffentlicht, obwohl ich im Voraus nichts \u00fcber Peer-to-Peer-Verbindungen (P2P) wusste.<\/p>\n<p>Trotz der Einfachheit der Integration ist P2P-Streaming tats\u00e4chlich ein sehr komplexes Gebiet der Informatik. Es muss sich mit der Komplexit\u00e4t jahrzehntelanger Netzwerkarchitekturen, wie IP und NAT, auseinandersetzen, um eine Peer-to-Peer-Session aufzubauen. W\u00e4hrend meiner Arbeit an diesem Projekt habe ich viel wertvolles Wissen \u00fcber Netzwerke und Leistungsoptimierung angeh\u00e4uft, weshalb ich jedem empfehle, P2P-Produkte mit WebRTC auszuprobieren.<\/p>\n<p>CloudRetro bedient alle Nutzungsszenarien, die ich als Retro-Gamer erwartet habe. Ich denke jedoch, dass es viele Bereiche im Projekt gibt, die ich verbessern kann, wie zum Beispiel die Netzwerkstabilit\u00e4t und -leistung, die Verbesserung der Grafikqualit\u00e4t der Spiele oder die M\u00f6glichkeit, Spiele zwischen Nutzern zu teilen. Ich arbeite hart daran. Bitte bleiben Sie dran. <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/giongto35\/cloud-game\">Projektarbeit<\/a><\/noindex> und unterst\u00fctzen Sie es, wenn es Ihnen gef\u00e4llt.<\/li>\n<\/ul>\n<p>Quelle: <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.1.1 - 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\/de\/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.1.1\" \/>\n\t\t<meta property=\"og:locale\" content=\"de_DE\" \/>\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\/de\/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\udd47Cloud Gaming mit offenem Quellcode auf WebRTC: p2p, Mehrspieler, null Latenz | ProHoster","description":"","canonical_url":"https:\/\/prohoster.info\/de\/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":"de_DE","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\/de\/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\/de\/wp-json\/wp\/v2\/posts\/89303","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/comments?post=89303"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/posts\/89303\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/media\/89304"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/media?parent=89303"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/categories?post=89303"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/tags?post=89303"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}