Game as a Service —— 开源云游戏搭载WebRTC_LiveVideoStack_的博客-程序员宅基地

软件即服务,基础架构即服务,平台即服务,通信平台即服务,视频会议即服务,那么,游戏即服务(Game as a Service)如何呢?已经有不少科技公司试水云游戏,最著名的要数Google的Stadia。对WebRTC来说,Stadia已经算是老朋友了,但是其他云游戏也能以同样的方式运用WebRTC吗?

Thanh Nguyen研究了他自己的开源项目CloudRetro在这方面是否可行。CloudRetro基于很受欢迎的WebRTC的pion库。在这篇文章中,Thanh对他如何构建项目进行了框架性的回顾与思考,以及他在此过程中遇到的一些挑战。

loudretro.io中megaman x4的屏幕截图

作者:Thanh Nguyen

翻译:LiveVideoStack

原文链接:https://webrtchacks.com/open-source-cloud-gaming-with-webrtc/

简介

去年,谷歌发布了Stadia,这个想法的独特性和创新性颠覆了我的认知。我一直在质疑当前的技术状态怎么可能支持Stadia。为了揭开Stadia的神秘面纱,我创建了Cloud Gaming的开源版本。我想在接下来的文章中分享有关自己开发Cloud Gaming的一年时间的大冒险。

为什么云游戏才是未来

我相信云游戏不仅将很快成为新一代游戏,而且还将成为新一代的计算机科学甚至其他领域。云游戏是客户端/服务器模型的顶峰。通过将游戏逻辑放在远程服务器上并将图像/音频流传输到客户端,它可以最大化后端控制并最小化前端工作。由此,服务器将负责处理繁重的任务,而客户端将不再受硬件限制。

就Google Stadia而言,它实际上使用户可以在YouTube等界面上玩3A游戏。可以将相同的方法应用于其他繁重的脱机应用程序,例如操作系统或2D / 3D图形设计等,以便我们可以跨平台在低规格设备上一致地运行它们。

可能的未来:你能想象在Chrome浏览器上运行Microsoft Windows 10吗?

云游戏仍然面临技术挑战

游戏是少数需要用户持续且快速反应的应用之一。如果我们单击页面时出现2秒钟的延迟,这是可以接受的。直播视频流通常会延迟很多秒,但仍然具有可用性。但是,如果游戏频繁延迟500毫秒,该游戏将无法播放。


当前的目标是实现极低的延迟,以确保游戏输入与媒体之间的gap尽可能小。因此,传统的视频流传输方法不适用于将图像/音频流传输到客户端的情况。

云游戏运作原理

开源项目CloudRetro

我决定创建一个云游戏的POC,这样我就可以验证在这些严格的网络限制下是否仍有可能实现以上所说的低延迟。我选择了Golang作为我的POC,因为这是我最熟悉的语言,当然也因为它便于运作且开发速度快。当处理并发和流操作时,Go通道也非常有用。

这个项目就是CloudRetro.io:针对怀旧游戏的基于Web的云游戏服务开源项目。我的目标是希望带来最舒适的游戏体验,并将在线多人游戏等网络游戏引入传统的复古游戏。

你可以引用整个项目库:https://github.com/giongto35/cloud-game

CloudRetro的功能性

CloudRetro使用Retro游戏演示了Cloud Gaming的强大功能并带来了许多独特的游戏体验。

  • 便携式游戏体验

  • 即点即玩,无需下载安装

  • 在浏览器上运行,无需任何软件即可启动

  • 游戏会话可以在多个设备之间共享,并存储在云中方便下次游戏

  • 游戏可播可玩,并且多个用户可以加入同一游戏

  • 类似于TwitchPlayPokemon的人群播放,但更实时,更无缝

  • 在线多人游戏,无需网络设置即可进行离线游戏。现在可以在CloudRetro上通过网络与2位玩家一起玩《武士对决》

在不同设备上进行多人线上游戏的demo

架构

要求与技术配置

以下是我在开始这个项目前列出的一些要求。

单人游戏

这项要求听起来并不相关且非常直接,但这是我的主要发现之一,它使云游戏摆脱了传统的流媒体服务。如果我们专注于单人游戏,就可以摆脱集中式服务器或CDN,因为我们不需要将会话流分配给大量用户。该服务不是通过将流上传到摄取服务器或将数据包传递到集中式WebSocket服务器,而是通过WebRTC对等连接直接流向用户。

低延迟媒体流

当我研究Stadia时,有些文章提到了WebRTC的应用。我发现WebRTC是一项非凡的技术,而且非常适合云游戏。

WebRTC是一个通过简单的API为Web浏览器和移动应用程序提供实时通信的项目。它支持对等通信,并针对媒体进行了优化,并具有内置的标准编解码器,例如VP8和H264。

我优先考虑为用户提供最流畅的体验,而不是保留高质量的图形。该算法中有一些损失是可接受的。在Google Stadia上,还有一个步骤来减小服务器上的图像大小,并且图像帧在渲染给对等对象之前被重新缩放为更高的质量。

具有地理路由的分布式架构

无论压缩算法和代码如何优化,网络仍然是导致延迟最关键的因素。该体系结构需要一种将最近的服务器与用户配对的机制,以减少往返时间(RTT)。这样的体系结构包含单个协调器和分布在世界各地的多个流服务器:美国西部,美国东部,欧洲,新加坡,中国。所有流服务器完全被隔离开来了。当服务器加入或离开网络时,系统可以调整其分布。因此,在超高流量下,添加更多服务器可实现水平扩展。

浏览器兼容

在用户需求极少的情况下,云游戏的表现是最好的。这也意味着能够在浏览器上运行。浏览器通过删除软件和硬件安装为用户带来最舒适的游戏体验,同时,它还有助于在移动设备和台式机之间提供跨平台的灵活性。幸运的是,WebRTC在不同的浏览器中都具有出色的支持能力。

明确划分游戏界面及服务

我将云游戏服务看作是一个平台,一个能够将任何插件插入的平台。目前,我将LibRetro(https://www.libretro.com/)与云游服务集成在一起,因为LibRetro为SNES,GBA,PS等复古游戏提供了美观的游戏。                                                                                                               

为多人、群体游戏和深层游戏链接服务的基于房间的机制

CloudRetro支持许多新颖的游戏玩法,例如用于复古游戏的CrowdPlay和线上多人游戏。如果多个用户在不同计算机上打开相同的深层链接,他们将看到的正在运行的游戏与视频流相同,而且他们可以像视频中任何一个玩家一样加入游戏。

此外,游戏状态存储在云中使用户可以随时在任何其他设备上继续他们的游戏。

水平缩放

像今天的每一个SAAS一样,云游戏必须被设计为可水平扩展。协调器-工作器的设计允许增加更多的工作器以服务更多的流量。

不可知的云

CloudRetro的基础架构托管在各种云提供商(Digital Ocean,阿里巴巴,定制提供商)上,以对标不同的区域。我通过bash脚本对基础架构进行了dockerize和配置网络设置,以避免依赖任何一个云提供商。结合使用WebRTC的NAT遍历,我们可以灵活地将CloudRetro部署在任何云平台甚至任何用户的计算机上。

架构设计

worker:(或者是上面提到的流服务器)生成游戏、运行编码管道、并将编码的媒体流传输给用户。Worker分布在世界各地,每一个都可以同时处理多个用户会话。

Coordinator:负责将新用户与最适合的Worker配对并进行流传输,通过WebSocket与worker进行交互。

Game state storage:所有游戏状态的中央远程存储。该存储实现了一些基本功能,例如远程保存/加载。

CloudRetro高级架构

用户流

当新用户在下图所示的步骤1和2中打开CloudRetro时,协调器将被要求提供前端页面以及可用Worker列表。之后,在第3步,客户端使用HTTP ping请求计算所有候选者的延迟。此延迟列表随后发送回协调器,以便它可以确定最适合为用户服务的worker。在下面的步骤4中,游戏生成。WebRTC流连接是在用户和指定worker之间建立的。

CloudRetro 在获得后的用户流

Inside the worker

在worker内部,游戏和流管道保持隔离状态,并通过接口交换信息。当前,该通信是通过Golang通道上的内存传输过程完成的。下一个目标是进一步隔离–即以不同的过程独立运行游戏。

Worker中各组件之间如何交互

主要部分是:

WebRTC:面向客户端的组件,用户输入进入,服务器的编码媒体输出。

游戏模拟器:游戏组件。借助Libretro库,该系统能够在同一进程内运行游戏,并在内部挂钩媒体和输入流。游戏中的帧被捕获并被发送到编码器。

图像/音频编码器:编码管道,它在其中接收媒体帧、在后台进行编码并输出编码的图像/音频。

应用

CloudRetro依靠WebRTC作为骨干,因此在详细介绍我在Golang中的实现之前,第一部分要专门介绍WebRTC技术。这是一项很棒的技术,可以极大地帮助我实现亚秒级的延迟流。

WebRTC

WebRTC旨在通过简单的API在本机移动设备和浏览器上实现高质量的对等连接。

NAT Traversal

WebRTC以其NAT Traversal功能而闻名,它被设计用于对等通信,旨在找到最合适的直接路由,避免NAT网关和防火墙通过名为ICE的进程进行对等通信。作为此过程的一部分,WebRTC API使用STUN服务器找到您的公共IP地址,并在无法建立直接通信时回退到中继服务器(TURN)。

但是,CloudRetro没有充分利用此功能。它的对等连接不是在用户与用户之间,而是在用户与云服务器之间。与典型的用户设备相比,该模型的服务器端对直接通信的限制较少。服务器不在NAT之后,可以进行预打开入站端口或直接使用公共IP地址等操作。

以前,我曾经有让这个项目成为云游戏分发平台的野心。这个想法是想让游戏创作者贡献游戏和流媒体资源,用户将直接与游戏创作者的提供者配对。以这种分散的方式,CloudRetro只是将第三方流资源与用户连接的一种媒介。

因此当托管的负担不再依赖CloudRetro时,它会具有更高的可扩展性。WebRTC NAT Traversal在简化第三方流资源上的对等连接初始化时将发挥重要作用,进而使创建者毫不费力地加入网络。

视频压缩

视频压缩是管道中必不可少的部分,它极大地有助于流畅的流媒体体验。尽管不一定要完全了解VP8 / H264的所有视频编码细节,但了解其概念有助于阐明流速度参数、调试意外行为并调整延迟。

用于流服务的视频压缩具有挑战性,因为该算法需要确保总编码时间+网络传输+解码时间的总和尽可能短。另外,编码过程需要是连续并有次序的。某些传统的编码折衷方法并不适用–例如用较长的编码时间换取较小的文件大小和解码时间,或者是无序压缩。

视频压缩需要忽略不必要的信息,同时将保真度控制在保持用户可以理解和接受的范围。除了对单个静态图像帧进行编码之外,该算法还根据先前和将来的帧对当前帧进行了推断,因此仅发送差异。如同在下面的Pacman示例中看到的,仅有差分点被传输。

 

以Pacman为例的视频帧比对

音频压缩

同样,音频压缩算法会忽略人类无法感知的数据。目前性能最佳的音频编解码器是Opus。Opus旨在通过有序数据报协议(例如RTP实时传输协议)传输音频波。它比(mp3,aac)具有更高的质量、产生更低的延迟(通常约为5〜66.5 ms)

Pion是一个将WebRTC引入Golang的开源项目。Pion不是简单地包装本机C ++ WebRTC库,而是一种本机Golang实现,可以实现更好的性能、更好的Golang集成以及对基本WebRTC协议的版本控制。

该库还提供具有许多出色内置功能的亚秒级延迟流。它具有自己的STUN,DTLS,SCTP等实现,以及QUIC和WebAssembly的一些实验。这个开源库本身是一个很好的学习资源,其中包含出色的文档、网络协议实现和示例。

由非常热情的创建者领导的Pion社区非常活跃,并且对WebRTC进行了许多高质量的讨论。

如果你对此技术感兴趣,请加入http://pion.ly/slack –你将学到许多新东西。

Write CloudRetro in Golang

Go在worker内的实施

Go Channel In Action

由于Go的通道设计精美,事件流和并发问题得到了极大的简化。如图所示,在不同的GoRoutine中有多个并行运行的组件,每个组件管理自己的状态并通过通道进行通信。 

Golang的select语句强制每个game tick都处理一个原子事件,这意味着此设计不需要锁定。例如,当用户保存时,需要一个完整的游戏状态快照。该状态需要通过运行输入保持不间断,直到保存完成。在每个game tick中,后端只能处理保存操作或输入操作,因此它也是同时安全的。

Fan-in / Fan-out

这个Golang模式与我的CrowdPlay和Multiple Player用例完全匹配。按照这种模式,同一房间中的所有用户输入都扇入一个中央输入通道,然后将游戏媒体分发给同一房间中的所有用户。因此,我们实现了来自不同用户的多个游戏会话之间的游戏状态共享。

不同会话之间的同步

Golang的劣势

Golang并不完美,它的通道缓慢。与锁定相比,Go通道只是处理并发和流事件的更简单方法,但是通道并不能提供最佳性能。通道下有一个复杂的锁定逻辑。因此,我通过在替换通道时重新应用锁定和原子值来对性能进行一些调整,以优化性能。

此外,Golang垃圾收集器是无法控制的,因此有时会有一些可疑的长时间停顿。这极大地损害了该应用程序流的实时性。

CGO

该项目使用一些现有的Golang开源VP8 / H264库进行媒体压缩,并使用Libretro作为游戏模拟器。所有这些库都只是使用CGO在Go中对C库的包装。你可以参考Dave的这篇博客文章(https://dave.cheney.net/2019/10/06/use-internal-packages-to-reduce-your-public-api-surface)。我现在面临的问题是:

  • 即使使用Golang Recovery,也无法捕获CGO的崩溃

  • 无法确定CGO下的细粒度问题就无法定义性能瓶颈

总结

我实现了揭开云游戏服务神秘面纱的目标,并创建了一个平台,可以帮助我和朋友们在线玩怀旧的复古游戏。没有Pion库和Pion社区的支持,这个项目是不可能实现的。

我非常感谢Pion及其密集的开发,WebRTC和Pion提供的简单API也可以实现平稳的集成。

尽管集成起来很简单,但是P2P流媒体的确是计算机科学中一个非常具有挑战性的领域。它必须处理IP和NAT等常年网络架构的复杂性才能创建对等会话。在从事此项目的过程中,我积累了许多有关网络和性能优化的宝贵知识,因此,我建议所有人尝试使用WebRTC构建一些P2P产品。

CloudRetro可满足我作为复古游戏玩家的所有用例。但是,我认为我可以改进项目中的许多方面,例如使网络更可靠、性能更高、提供更高图形质量的游戏或在用户之间共享游戏。我正在为此而努力。

相关文章:

爱奇艺广告变游戏——视频流媒体如何加入云游戏战局


LiveVideoStackCon 2020首届音视频线上峰会

2020.6.20-2020.6.21 

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/vn9PLgZvnPs1522s82g/article/details/106030214

智能推荐

运用狭义相对论各推论和洛伦兹变换解题_洛伦兹变换 静止系各处时间不变_HGGshiwo的博客-程序员宅基地

讲真的,相对论一开始学真的不好理解。亏我之前高中学了近代物理,但是那时候没好好听,现在啥都不知道了。一道题用洛伦兹变换和钟缓算出来答案一直不一样,后来才知道怎么错了…对于时间流逝的理解:一共四维空间,三维空间和一个ct轴,ct轴代表的是时间流逝速度。不变量是一个四维球。时间流逝和光速是相关的,当速度越快,在三维坐标系里投影就大,在ct轴上投影就小,时间流逝就慢。这是我的理解,可能有问题,但是没关系因为这些和解题没啥关系。下面是和解题有关系的:两个参考系相对速度是不会变的,你对我v,我对你_洛伦兹变换 静止系各处时间不变

事务、存储过程和触发器和函数_一个存储过程中多个事务_yutiannanjingjiangsu的博客-程序员宅基地

1、事务Begin Trans用于开始一个事物;Rollback Trans用于回滚事务;Commit Trans用于提交所有的事务处理结果,即确认事务的处理。事务处理可以将一组操作视为一个整体,只有全部语句都成功执行后,事务处理才算成功;若其中有一个语句执行失败,则整个处理就算失败,并恢复到处里前的状态。 BeginTrans和CommitTrans用于标记事务的开始和结_一个存储过程中多个事务

如何通过一个域名部署项目_域名 部署_Steven--Lee的博客-程序员宅基地

效果演示域名示例https://stevenlee.club描述域名可使人更方便更人性化的访问互联网,之前我买的云服务器时顺带买了两个(1元/年),用于我自己服务器项目更便利的被访问。在我的云服务器过期后,当时觉得域名也就没什么用了,直到有天我突发奇想,能否将我自己的项目找一个免费平台部署,再使用我自己的域名~踩坑无数,后来总算实现了域名准备1. 购买一个域名..._域名 部署

oracle安装缺少,安装oracle11g R2 缺少依赖包_weixin_39657249的博客-程序员宅基地

最近我在RHEL6.1上安装oracle11gR2时总是碰见如题说示的错误,在网上查了很多资料但都未能解决。网上都说是gcc版本问题或者gcc的包没有装全,但没有给出正确的gcc安装方法。这里转载别人的安装gcc的rpm包的顺序及方法,供各位参考:转载文章如下:最近在折腾RedHat,我安装的版本是rhel-server-6.1-x86_64。RHEL 6.1默认是没有gcc和gcc-c++环境的..._安装oracle时出现依赖包没有安装怎么办

前置变换后置变换OpenCV源代码 转自https://github.com/kipr/opencv/blob/master/modules/legacy/src/lines.cpp_cristinaSophia的博客-程序员宅基地

/*M/////////////////////////////////////////////////////////////////////////////////////// // // IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. //

android第三方今日头条、仿知乎日报、录音文字动画、多种跑马灯效果等源码_chuangzhi9350的博客-程序员宅基地

Android精选源码MVP+Retrofit+RxJava 实例源码android图片加滤镜特效源码自定义支付密码弹窗,可拓展性高,界面友好,注释详细android 自定义录音、播放动画View效果实现一个完整的复杂列表布局源码Android实现仿QQ、微信头像剪切效果..._php+android仿今日头条

随便推点

ASP.Net 拉姆达表达式_LJR-557的博客-程序员宅基地

1.Lambda‘ =>’是什么意思? 是lambda表达式,表示一个匿名函数,=>前面的是参数,后面的是函数体。图中P是任意标识符 可以用任意字符串来代表2.删除3.修改4.跨越表 用Add()添加5.两个表联合将stu marks两个表信息一并显示 ...

关于jsessionid_技术专家的博客-程序员宅基地

jsessionid=CA72488F94BC8A3E92FEEDA8CC736FDC这个jsessionid是session的一个标识。我在这里转贴jdbc老大的部分讲解session机制是一种服务器端的机制,服务器使用一种类似于散列表的结构(也可能就是使用散列表)来保存信息。当程序需要为某个客户端的请

设计模式 之 单例 模式_吕冲的博客-程序员宅基地

设计模式是开发中很重要的一种思想,今天记录一下单例模式,备忘,哈哈。

卷积神经网络物体检测---边框回归(Bounding Box Regression)详解_bounding box神经网络_终结大笨狗的博客-程序员宅基地

Bounding-Box regression最近一直看检测有关的Paper, 从rcnn, fast rcnn, faster rcnn, yolo, r-fcn, ssd,到今年cvpr最新的yolo9000。这些paper中损失函数都包含了边框回归,除了rcnn详细介绍了,其他的paper都是一笔带过,或者直接引用rcnn就把损失函数写出来了。前三条网上解释比较多,后面的两条我看了很多pap..._bounding box神经网络

freeswitch笔记2:呼叫中心坐席转接_freeswitch outbound_aphero的博客-程序员宅基地

1.设置呼叫中心拨号计划<extension name="Call-Center-9999" continue="" uuid="c3500cca-9d04-4e18-a857-9d54c7490038"> <condition field="destination_number" expression="^([^#]+#)(.*)$" break="never"> <action application="set" data="caller_id_name=$2"/&_freeswitch outbound

tcp服务器往客户端发消息,tcp服务器往客户端发消息_霜曦的博客-程序员宅基地

tcp服务器往客户端发消息 内容精选换一换华为云帮助中心,为用户提供产品简介、价格说明、购买指南、用户指南、API参考、最佳实践、常见问题、视频帮助等技术文档,帮助您快速上手使用华为云服务。本节定义了VR云渲游平台上报云监控的监控指标的命名空间、监控指标列表和维度定义,用户可以通过云监控检索VR云渲游平台产生的监控指标和告警信息。SYS.CVR表1 监控指标说明指标指标名称含义取值范围测量对象监控..._tcp服务端往客户端发东西

推荐文章

热门文章

相关标签