语音voip(Gvoice千万在语音输入的那些事)
语音voip(Gvoice千万在语音输入的那些事)GVoice是腾讯专门为游戏打造的语音通话SDK。在谈到语音通信的时候,大家可能最先想到的是语音聊天等场景,但在游戏中对于语音通话有一些特殊要求,接下来我们看一下GVoice在游戏场景中有哪些要求。游戏实时语音系统中最常见的场景有两种,一种是“王者荣耀”类游戏可以五人组队,这就是小队语音形态,每个队伍不超过10或20个人,但是会高频率地交流;另一种场景是“御龙在天”类游戏,游戏中的国战一个房间可以同时在线几千甚至上万人。在处理这两种语音场景时解决的问题不同,需要分别进行讨论处理。今天的分享主要包括5个部分:第一部分是GVoice的产品形态以及在研发过程中的目标;第二部分是针对产品需求介绍GVoice的整体架构设计;第三部分是拆分架构中的每一个模块以及讨论容灾和扩缩容的方案;第四部分会详细地展开介绍传输算法并分享一些在GVoice语音传输中用到的调优方案及效果;第五部分对整个分享作总结以及思
GVoice为腾讯旗下的主流游戏提供低延迟语音通话服务,其特点是高并发、覆盖全球。本次分享的嘉宾许路平是GVoice后台负责人,他会详细介绍游戏业务的特点,以及GVoice针对性的架构与协议的设计原则和方法,高可用保障与成本控制,重点性能突破和未来展望等。
文 | 许路平
整理 | LiveVideoStack
许路平 公开课
今天的分享主要包括5个部分:第一部分是GVoice的产品形态以及在研发过程中的目标;第二部分是针对产品需求介绍GVoice的整体架构设计;第三部分是拆分架构中的每一个模块以及讨论容灾和扩缩容的方案;第四部分会详细地展开介绍传输算法并分享一些在GVoice语音传输中用到的调优方案及效果;第五部分对整个分享作总结以及思考有哪些可以改进的地方。
01
游戏语音系统的需求和特点
游戏实时语音系统中最常见的场景有两种,一种是“王者荣耀”类游戏可以五人组队,这就是小队语音形态,每个队伍不超过10或20个人,但是会高频率地交流;另一种场景是“御龙在天”类游戏,游戏中的国战一个房间可以同时在线几千甚至上万人。在处理这两种语音场景时解决的问题不同,需要分别进行讨论处理。
GVoice是腾讯专门为游戏打造的语音通话SDK。在谈到语音通信的时候,大家可能最先想到的是语音聊天等场景,但在游戏中对于语音通话有一些特殊要求,接下来我们看一下GVoice在游戏场景中有哪些要求。
因为我们不是做终端产品而是做SDK,那必然涉及到开发接入的问题,在长期做SDK的过程中我们摸索出了两个关键点:第一是尽量少的人接SDK;第二是SDK的接口尽量少,因为多一个接口就要多写许多声明或是解释许多问题,另外多出错率也会越大。所以GVoice的产品要求只需两点,一个是只需要客户端SDK接入即可,另一个是只需要编写五行代码即可接入GVoice语音服务。
为什么只需要编写五行代码?为了实现五行代码接入语音服务,GVoice的后台需要做哪些配合呢?看似简单的操作背后其实有着很复杂的设计。
游戏语音是一个非常单纯的场景,就是基于房间的转发和通信(如右图最后一行代码所示),所以最重要的是让客户端知道房间位于的服务器位置,剩下的就是客户端和服务器之间进行语音数据传输的问题。这些都是在做VoIP系统或是语音传输系统中大家非常熟悉的领域。
游戏语音系统的需求包括四点:
首先需要高性能系统,因为游戏都是大规模在线且业务成本敏感,实现高性能可以在极低的成本下为游戏中的大部分用户提供语音服务;
第二点是系统可伸缩,游戏存在生命周期,从研发到玩家不断增长再到衰退期,整个生命周期中对服务器的伸缩和快速扩容要求非常高,比如扩容的速度赶不上游戏会造成事故,缩容的速度赶不上游戏会造成成本浪费;
第三点是高可用,游戏中做到高性能、可伸缩的同时,如果还要求极高的高可用性就会大大增加整个系统的复杂度从而影响实际运维的效率,所以高可用性排在第三位。我们会拆解系统中的服务,针对关键服务做高可用,其他非关键服务或实现起来比较困难的服务尽量做到故障隔离,其次是做到柔性可用(比如有几千台服务器,挂掉一两台只会影响百分之零点几的玩家),要想办法在这上面找到平衡点;
第四点是易使用,GVoice在全球四五十个国家部署,也就是说如果做了一套非常庞大或是复杂的系统,那么在海外的运营环境(海外的设备配置、网络配置等)会参差不齐。如果系统非常庞大且依赖第三方主件会导致整个GVoice的部署困难,使业务出海受到影响。
综上,我们会始终以实现这四个需求为目标来设计整套系统。
02
GVoice架构设计
这不仅是游戏语音系统,更是一个典型的语音通话系统的设计架构图。
举个例子向大家解释将信令和数据服务拆分开的原因,当你拿起手机准备拨号,这就是信令通信的过程,可能就持续几秒钟,但建立完整个数据连接后,数据服务持续时间可能是半小时甚至更久。所以整个语音通话过程中,信令和数据传输流量占比严重不对等,它们的传输需求如可靠性、可用性、成本占用方面也各不相同。因此要拆分信令及数据服务,再根据它们的特征和需求分别做设计。打电话第一步是请求信令服务,比如要到某个房间通话,信令服务就会返回数据服务地址,客户端根据数据服务建立连接,这个连接是长期存在的,信令服务可能一个来回就解决了,但是语音通信每秒都有几十个包,所以将它们拆开分别做设计。
信令服务需要具备高可用性,因为如果一开始无法拨通电话,对用户来说体验感会很差。其次是可伸缩,我们的服务在外网运营的时候可能会受到各种攻击,或者业务迅速扩张或缩小,这都需要信令服务具备可伸缩性以快速满足业务的各种需求。
数据服务首先要具备良好的性能,一个客户端连入服务器时每秒交互的包可能达到二三十个或更多,这对数据服务的性能是非常大的考验。第二是可伸缩,这对互联网类的产品是必备的特征,做任意类型的服务时都要保证根据业务规模的变化,迅速扩容或缩容。第三是低成本,多媒体通话的很大一块成本都集中在带宽,所以在做传输的过程中需要考虑如何节省带宽并且提高传输效率。
上文已经将GVoice拆分为了两大块,分别是信令服务和数据传输服务,接下来要针对不同模块分配相应的职责。在处理不同业务逻辑的时候,可能对每一个业务的转台有不同要求,所以我们把整个服务分为了有状态或无状态,这也是一个互联网后台设计通用的思想。
无状态服务有一个特征,只要均匀或随机分布请求,那么整个伸缩性和容灾性都会非常好。所以根据请求是否有状态,比如无状态逻辑包括鉴权、限流、路由、计费,将它们放在第一层的信令集群处理,这叫做信令接入服务器。将有状态的服务比如房间信息管理(给每个房间分配转发服务器)、集群管理(如何扩容缩容、每个集群的存活状态)放在中间层的转发管理集群处理。这样做是因为前面的接入集群直接面向官网客户端,那么接受的请求不一定来自合法的客户端,也有可能来自攻击和异常流量,通过将前面的信令服务设置为无状态并大规模部署能够抵御异常攻击,过滤异常流量后,再放到真正的转发管理集群中处理房间逻辑,整个转发管理集群的规模就可以得到有效控制而且中间有状态的服务规模可以限制到很少。有状态的服务是不可靠的,因此大规模有状态服务会非常难管理。我们通过以上策略尽量缩小有状态服务,尽量扩大无状态服务能处理的逻辑,这就可以缩小有状态集群从而方便后续运维管理。
最底层是专门负责转发服务的集群,因为转发服务的总量占整个集群规模的95%以上,这是非常大规模的服务器管理,管理方法同部队管理,分为班长、排长、连长等。我们不可能实时知道每一台服务器的状态,那就把它们分组编队,一组一组管理,所以在整个转发集群按分组方案来管理时,每组可能是很小的集群,每次扩容缩容都以最小集群进行操作,从而确保操作的集群数量有限,不会出现一个集群中有一万台机器,每次都要观察每台机器的状态的情况,也就是说把1w台机器分为100台机器一队,那么只要管理100个集群的状态。这样做的好处就体现在刚才提到的“国战”大房间场景,首先单机传输难以满足大房间场景的需求,我们预估游戏最大的房间不超过100w同时在线,于是就把100w作为一个集群部署,也就是只需要一个集群就可以满足“国战”游戏的需求。
03
GVoice架构设计要点
3.1.信令服务设计要点
信令服务器内部有多个模块包括客户端接入,专门负责处理客户端上行的各种请求,解决加密,处理异常数据包,统计监控(防止业务请求量加大或突发请求暴涨影响到其他业务)等。GVoice是面向全行业的语音引擎,所以内部有一套自成体系的业务账号管理系统,在接入服务器就有账号信息的缓存,每个业务请求过来时都可以直接在接入服务器上完成鉴权操作,避免了所有请求都直接透传到最末端的数据库中,这是最常见的提高处理性能的方法。此外,还有一些业务配置的管理,比如客户端上来用的传输算法、逻辑和参数都可以在接入服务器一次性取回,不用多次访问服务器。还要对后面依赖的服务进行存活探测和容灾,比如发现请求下游的服务器出现故障就要屏蔽这台服务器并生成相应的告警信息。
接入服务器的设计重点是首先坚持一个原则——接入服务器无状态,所谓的无状态是指任何客户端任何时刻连接到任何一台服务器,只要能够连接且网络通畅,那么返回的结果都是有效的,除非后续业务出错否则都能够正确处理逻辑。第二是高性能,作为接入服务器,经常需要接受外网各种突发流量的考验,首先接入服务器自身不能卡死,在受到攻击后,如果自身的信令服务器第一层就出现故障那么整个系统的可用性就会变得很差。第三是可平行扩展,只要在实现无状态的前提下,可平行扩展就会非常容易,只要不断往集群中加机器就可以。第四是高容错,这是内部实现的特有逻辑或是说需要坚持的方法,代码要在服务或整个系统出现任一错误的情况下,依然可以保证基础服务如语音通话服务的正常,GVoice中有许多语音服务包括离线语音、语音翻译、语音转文字、语音消息,这些其他的周边服务出现故障都要隔离开以保证语音通话服务的逻辑正常,因为只要玩家通话正常至少不会出现很严重的问题。
信令服务的扩容流程如图,首先是拉起新部署的信令服务进程,然后测试程序拨测,通过后修改域名配置加入服务了,这是一个非常简单的方案。缩容流程相比更加简单,因为大家都没有状态,想删掉的机器就直接在域名配置中摘掉,等待机器上流量掉0后停止服务进程,最后回收机器,就完成了信令服务的扩缩容。
容灾方案分为两块,一块是信令服务故障时的处理方法,另一块是后端服务(依赖的其他服务)故障时的处理方法。
信令服务出现故障时依靠客户端的自动轮询重试,客户端每次发生信令失败都会将数据上报到监控服务器,监控服务器根据请求失败率分析出最近一天的高失败率的信令服务器,引发告警从而人工介入检查问题。通过重试手段可以保证信令请求的成功率。
后端服务出现故障时,我们使用的是一个简单的容灾探测逻辑,可用的原因是客户端会主动发起重试,而在信令服务中没有重试逻辑,因为如果加了重试逻辑,和客户端的重试逻辑一起可能会引发错误请求的放大。也就是如果客户端出错重试之后这边又重试,那后面的服务器已经过载的情况下,大家都在重试反而会压垮其他服务。所以整个重试链条完全是由客户端主动出发的,信令请求服务中不会对错误请求进行重试。我们会采用一个简单地容灾逻辑,如果单台机器出现连续10次的请求超时,就将这个机器标记为故障机,但后续会每秒放一个请求,观察它是否能正常处理,因为后端服务的有些故障是可恢复的,可能只是因为临时过载或是网络闪断。每秒给故障机放一个请求后,如果连续3次请求成功,就将其标记为有效。这样可以防止出现网络闪断时所有服务都被标记为不可用,这会影响请求的成功率。
对这块内容做一个小总结,整个信令服务器是无状态服务器,因为它的设计要点是高性能,易处理,写代码时要注意尽量隔离各个模块之间的故障,能缓存的数据尽量缓存,这样就可以在外部系统出现故障时保证信令服务的正常,从而保证语音的基本服务功能。
3.2.转发管理服务的设计要点
转发管理服务的职责首先是负责处理客户端上行的加入房间请求,再根据房间名分配不同的转发集群,这里出现的问题是请求是有状态的,比如来到A房间,要保证每次来A房间的都分配到同一个转发集群中,解决方法是在转发管理服务器做了Hash处理,在服务器上分配了127个桶,每来一个请求就往桶里放,每个桶里都会挂一个转发集群,这样就可以把请求按Hash规则均匀地分发到不同的转发集群。另外,在转发管理服务上需要对转发集群进行存活探测和容灾保护,在Hash的时候如果后面有一个集群的服务全挂了是非常麻烦的,为此要做的有两步,首先在转发集群内部做异地容灾,每个转发集群内部有三台信令接入器,每台都会在转发管理服务上进行注册,这样比如发现有一台信令接入器挂了就可以迅速的切换到其他两台接入器上进行服务,确保服务过程中在转发集群的信令服务挂掉时仍然可以正常提供服务。
站在转发管理服务的角度来说,它也是没有状态的服务,只不过有一个强制要求是保证所有转发管理服务的配置是一致的,才能够做好对后面转发集群的管理。
扩容的流程就是部署新的转发管理集群并做好拨测,测试好后修改信令接入服务配置,添加新的转发管理服务,再继续观察新的集群的流量是否正常即可。
缩容很简单,在前端的信令请求服务中把想删掉的机器在域名配置中摘掉,等待机器上流量掉0后再处理。
如果是转发管理服务自身出问题,这是不影响的,因为所有转发管理服务都是对等的,从信令接入服务角度来说只要按照自己的容灾处理策略把出问题的转发管理服务删除即可。整个转发管理集群的容灾都是通过信令接入服务来保证的。
3.3.转发服务的设计要点
在整个语音通信中,转发集群是占用服务器数量最大的集群,大概占据80%以上的机器,所以要对这些机器进行分组管理,目前设计的是每个集群管理50台机器,单个集群支持50w的同时在线人数。
每一个集群里面会部署三台完全相同对等的集群管理服务器叫做RoomManager,它负责管理这个集群中房间和机器的位置关系及机器上的IP。在部署的时候,一个集群有三个RoomManager,也就是说三台机器上的信息完全一致。所有的VoiceServer一个集群里大概有50台语音服务器都会和这些RoomManager定时同步状态,可以理解为这整个集群可以满足游戏高可用的要求。为了防止出现一个或三个RoomManager同时挂掉的情况。对外暴露的三个RoomManager是分开部署的,确保它们不在同一个机架上。首先保证它们的可用性,然后所有的VoiceServer都向这三台RoomManager同步信息,这个转发集群的可靠性就是有保障且符合设计要求的。
转发集群管理服务看每个集群都是三台RoomManager,所以就算集群中有一两台RoomManager挂掉也不会影响整个业务服务。
每个集群有3套完全相同的RoomManager,所以RoomManager出现故障不会影响整个游戏语音服务。如果是VoiceServer出现故障,首先客户端有重试机制,每次RoomManager会给客户下发多个接入IP,客户端在发现一个IP超时的时候会重试其他IP,就算整个集群的VoiceServer全部重启,我们还可以依赖客户端的心跳来恢复整个房间的信息,恢复之后所有信息都会在RoomManager的内存重建,所以整个转发集群可以理解为不依赖数据库,但是具有高可用性信息恢复功能的集群。
可以看到在VoiceServer出现故障时,客户端可以通过重新加房间或者重试的方式来恢复。在RoomManager出现故障时,VoiceServer会定时上报每个人有几个房间给RoomManager来解决问题。
04
系统迭代优化方案
前面仅仅是将GVoice的系统搭建起来,只是实现了一个能用的系统,在后续的开发过程中就需要进行迭代优化,这也是大家在业务过程中经常碰到的问题。通常会有这样的大循环(右图所示),业务上线之后会有统计监控、发现问题、制定方案、客户端发版本、服务器发版本,再看数据。整个GVoice上线之后就是不断在这个迭代循环中跑。因为做监控或者一个项目肯定要提取三到五个关键指标,每天观察指标是否出现问题,接下来就是根据监控数据分析问题,再决定要做的优化,然后在服务器中开启新特性进行验证,最后在统计监控分析是否符合预期效果。
GVoice服务有四大重点观察指标:
第一是PCU,在做项目或服务时,PCU可以反映当时有多少人在使用服务,同时它也是最容易反馈业务故障或是集群故障的指标,某个地方出现故障时PCU肯定会掉下来。此外,还可以根据PCU来做扩缩容的决策,比如集群容量使用率是否达到了扩容或缩绒的条件。最后GVoice的一个特征是计费根据PCU来制定的,所以PCU是关键的观察指标。
第二是丢包率,这是一个基础的指标,直接衡量某个地区的网络质量好坏,这通常是受网络影响的,因为服务器和客户端版本稳定后,网络活动会引起丢包率的变化。
第三是延迟,从A说话到B听见的整个过程其实包括很多段,GVoice会监控每一段的延迟包括数据处理延迟,甚至是采集播放的延迟,形成完整的延迟监控数据。
第四是卡顿,这也是大家经常遇到的问题。其实只要是软件就会卡顿,但我们要想办法监控卡顿并进一步分析其原因是网络传输引起还是程序BUG引起的,再根据原因做细分并解决。
GVoice优化过程中最典型案例的是语音传输丢包率的优化,这也是做传输的过程中大家比较关心的问题。站在应用层角度,除了对网络延迟做一些调度的处理,在算法方面没有较好的解决方法,但在丢包率方面却可以做较多的优化。整个游戏语音通话的卡顿是排除程序BUG之后由丢包率和延迟综合影响的。
首先引入一个语音传输经常用到的算法——FEC算法。举个例子,对1、2、3进行异或得出A,发送第四个包的时候带上A,如果传输过程中4号包丢了,在收到5、6、7时就可以把5、6、B三个数联合起来算出4号包的内容,这就是大家常说的“3 1策略”。
实际应用中,不止可以实现“3 1”,因为根据RSCode算法可以实现任意“M N”的冗余方式。理论上“M N”取得越大,抗丢包越强,但要考虑的是延迟问题,帧间隔为40MS,恢复一个包至少要收到“M N”个包之后才可以进行恢复,所以我们选择“M N”最大值为5,其次还要考虑带宽利用率,最严重的突发情况是发1带上2和3,发3带上1和2,发4带上2和3,这样就是三倍冗余策略,虽然对整个延迟和分布算法来说很简单,但带宽利用率不够高。所以在考虑带宽利用率的前提下,我们选择的是“3 1”、“3 2”以及“2 2”三种冗余方式。语音有一个好处是冗余度大的时候可以降低码率,这就是语音相比游戏中的传输更为灵活的地方。
FEC是被动恢复丢包的方式,那么在做可靠传输时,更常见的其实是主动恢复丢包的方式——ARQ。比如发1、2、3,3在传输过程中丢了,那在收到4的时候马上可以知道3丢了,就发一个请求3,再传输一次3,这类似于TCP中的ACK,细分下来还有ACK和NACK,所谓NACK是没有收到的时候再请求,ACK是每次收到都会说明收到了。
在语音传输中,一般两个人不会同时说话,所以使用更多的是ARQ,没收到的时候再发起请求。通过分析ARQ的处理流程可以发现它请求重传一个包需要再等一个RTT才能回来,也就是说有一个RTT的延迟,然后发现丢一个包至少要等一个帧间隔才可以知道,甚至丢包过多的时候要等好几个帧间隔,可以理解为ARQ算法对延迟敏感。举个例子,发现丢包后请求一次ARQ,但此时网络延迟很大,需要等待1s才可以回来,这时ARQ就没有意义了,因为语音可能已经播放到1s之后的位置了。
总结一下,要根据ARQ和FEC特征进行选择,FEC的优点在于只要收到“M N”个包就可以恢复满足条件的丢包内容。而ARQ对网络延迟敏感,如果网络延迟太大,收到丢掉的包后再发ARQ就没有意义。
通常我们会混合使用FEC/ARQ,具体使用时根据客户端当前丢包率和网络传输RTT进行选择,方案有很多种,因为眼前至少有三个可调参数,首先是否用ARQ、选择何等级的FEC、码率也可调。在低延迟低丢包率的情况下,偏向于使用ARQ,高延迟高丢包率的情况下,偏向于使用FEC,而且其级别随着延迟增加而增加,FEC级别增加之后增大带宽消耗,举个例子“3 3”大概有两倍冗余,方法是加FEC冗余的同时降低码率,这时用户可以收到语音但是音质有一些细节的失帧,总体上是流畅的,听语音和音乐的要求不同,语音的要求是在保证流畅的前提下再追求细节。
随着业务不断发展变化,举个例子用户在玩和平精英的时候会发现他可以在多个房间里通话,除了自身小队的语音还可以听到周围其他用户的声音。最简单的方法是一个客户端进入两个房间,说话可以同时被两个房间听到,同时也可以听到两个房间的声音,这样会出现的问题是客户端在游戏对局里要和服务器建立多条连接,导致客户端状态管理非常复杂。其次在服务器看来相当于一位用户在服务器中有两个实例,也是较复杂的情况。
在针对多房间的场景时,我们的实现优化方案是引入传输代理,客户端和服务器之间走传输代理,传输代理再和各个房间进行通信。升级架构后,优势在于首先可以实现玩家逻辑和数据的集中管理,从而简化客户端所做的逻辑。其次能够聚合客户端公网流量,包括在传输层的优化上,如果客户端是单点接入,那我们可以做很多优化并且不引入额外的成本,客户端和服务器可以同时通过4G和WIFI进行通信,可以确保语音传输在单挑链路出现故障和丢包时始终保持流畅。第三是能够聚合客户端的逻辑,因为每一个客户端在服务器上都有一个类似镜像的实例,在做翻译、反外挂或其他方案时就有非常好的接入点,因为可以直接找到另一个客户端的位置,为消息路由带来很大的便利。
05
总结/展望
在服务海量用户时,GVoice在全球的PCU是过千万级别的,那么如何低成本高效率地服务海量用户呢?
首先要分模块,不能想着只做一个程序、一个架构或是只依赖一个第三方的简单模块就实现整个集群,大系统一定要拆分为小模块并且每个子系统一定要分工明确,功能清晰。因为实现不同要求的程序对编程及开发技巧不同、对人员的要求也不相同,那么将大系统拆分后每个人在自己擅长的领域工作就很容易提高开发效率。
第二是分层次,分完模块之后,每个模块该做的事情、如何做及每位员工擅长的模块也要细分清楚,这样可以更容易且高效地搭建系统。
第三是分集群,所有的鸡蛋不要放在一个篮子里,需要强调异地部署、集群隔离、集群之间要实现灵活调度,这也是做互联网的基本思路,把全球各个IDC都部上服务器,非必要不要融合通信以保证单个集群故障时不会扩张到所有服务器。
最后是优化闭环(PCDA工作方法),搭起工作流后,大家要不断地丰富监控数据、查看监控数据、寻找问题、给出解决方案,不断迭代。GVoice在服务海量用户的本质是在进行数据驱动优化的过程,也就是搭建架子后,在数据上挖掘每个环节的问题比如某些服务成功率低、丢包率高,某个地区的玩家丢包率高等,再针对这些问题做优化,最后把数据分布完全后会发现已经做好了全链路的监控系统,所有问题都可以通过查看监控数据的方法进行定位。
以上是本次的分享,谢谢!
Q&A:
1.老师的方案更强调卡顿,在网络各种制约条件下优先保证的是流畅度,牺牲一部分延迟是吗?
在语音通信下,要看参照物,如果是和游戏比,确实是要优先保证不卡顿,举个例子:整个语音通信延迟的容忍在300MS左右,但在游戏对战系统,只要延迟超过120MS,就会影响玩家体验,所以需要优先保证流畅度,再保证延迟。
2.没有用TRTC吗?自建的?
没有使用。因为我们需要在打游戏的时候同时语音通信,所以较大的挑战是对带宽的占用有很高的要求,不能因为语音流畅导致游戏卡顿,这样也是不可取的。
3.冗余大时会降低码率?这个不太懂,可否更进一步介绍下?
其实是丢包率高的时候会引起冗余大,而冗余大的同时每个包会变大,占用的带宽随之增加,在网络传输中,本来网络就出现了卡顿,此时带宽再增加就相当于在抢带宽,这是不允许的,会严重影响用户的体验。所以我们选择在冗余增加的时候降低码率,这样发出去的包不变,只不过从原来收到的包播放1s语音变成一个包播放2s语音,相当于优先保证流畅,虽然会导致一些高频的细节声音损失,但也是在追求流畅的过程中允许发生的。
4.根据不同的丢包率和rtt,采用重传方案时,重传的次数是如何定义的?根据rtt动态计算吗?
两位用户聊天时,不存在一定要重传完的概念。比如上一秒,用户A说的话丢了,1s后再重传回来,这句话已经没有意义了,所以不存在一定可达的问题,这需要区别于游戏传输。游戏传输是严格的逻辑帧,少了一个输入会影响表现,但是语音传输是“尽量可达”,不同于游戏中丢失的包必须补回,否则游戏逻辑会混乱导致两个客户端不同步。重传次数可以理解为在有限的时间内尽量可达,比如超过1s丢了就算了。
5.传输协议采用的是rtp吗?请问,应用层和传输层分别是什么协议?
传输层用的协议是UDP,应用层用的是GVoice自定义的协议,可以认为是私有的协议。
6.能方便介绍一下,是如何监控语音质量的吗?
可以理解为我们在接收端进行监控,因为接收端有抗抖动缓冲区,这里会缓存一部分包,语音播放时可以知道是否连续,比如发现要播放3号包时它还没到,那么就刷一次卡顿,这是监控卡顿的方法。监控丢包只需要有序列号、收发端就可以很快算出。
7.带宽波动大的场景下,如何平衡游戏自身和声音占用的带宽?会优先保音频吗?
这种情况肯定是优先保证游戏的带宽。我们所做的是非必要不发包的网络处理,大家可以测一下整个GVoice其实在游戏中占用的带宽非常低。
8.转发服务有就近接入吗?如果是大房间场景下,是不是需要在不同转发集群之间进行传输?
转发服务是有就近接入的,在每一个省都有接入点,这些数据会就近接入。大房间场景下,我们不会做跨集群传输,举个例子来说在游戏中的大房间不像广播系统,游戏房间规模可以认为不会超过100w,这就只需要一个集群的机器就可以覆盖。避免跨集群传输也是为了整个部署隔离的需求。
9.连续丢包是如何处理的,使用类似于NetEQ的技术么?
我们没有使用NetEQ。对连续丢包的处理也是类似前面说的,有一个最高级别优先级,因为语音传输的优点在于Best Effort,尽量做好就可以,实在丢了就是丢了,比如开到最高级别3 3、16K后还是丢包了,那就丢了,毕竟这种丢包的情况下可能游戏也无法进行。
10.编码码率配置有最佳实践吗?
根据目前对码率的测试所得,大量的普通用户能够听出差别的时候码率大概在12k左右,游戏场景下且码率大于12k时,一般用户听不出差别。我们尽量用32k的目的是使小孩的声音听起来更加丰富。
11.如何平衡语音音量和游戏音效音量的关系?
这也是游戏语音场景下的一个经典问题。在用户玩游戏时,要播放游戏音效,同时会播放语音,我们平衡这两者关系的方案是在游戏的配合下,用户收到语音后会降低一些游戏音效。
12.面对面开黑时,经常有啸叫产生,体验比较差,这块有什么经验吗?如果要缩容的转发服务的任务一直存在,怎么办?
啸叫是一个长回路反馈的问题。大家会经常对比视频会议系统和游戏系统,疑惑为什么前者不会啸叫,但是游戏就会。这是因为在玩游戏的时候,用户的手部可能会遮挡麦克风、扬声器,导致啸叫传输路径不稳定,滤波器很难实时跟踪变化,所以目前的解决方案是用户面对面开黑的时候尽量关闭一个麦克风。
13.如果要缩容的转发服务的任务一直存在,怎么办?
这个问题确实存在。用户进入游戏后大多数时间在对局中,而对局时长是有限的,比如一局2h。举个例子,一个人一直不走,店铺也不会一直不关门,类似的我们会给缩容一个时限,比如可以先观察3天,3天后还有流量就可以停掉,这对用户来说只是重新加载或是重新加入房间就可以恢复服务。
14.如果没有跨集群传输,那么集群会跨地域部署吗?否则不同地域用户怎么保证就近接入?
这要分国内和国外各种场景进行讨论,我们在部分区域做了跨集群传输。实现方案是(倒数第三张ppt中的)传输代理层,一个集群肯定有一个主要目标用户区域,比如海外东南亚的用户尽量接入新加坡,如果实在接入网络太差,我们会搭一个代理,从香港接入,然后代理到新加坡。
15.请问,多链路传输是指WIFI/4G同时使用吗?它是怎么决策用哪一个网络的呢?
两个网络两条链路是同时开着的,它们之间是主备的关系,通常认为优先走WIFI,但随着4G包月流量越来越多,用户对流量的使用不是很敏感,我们就会逐步放开在WIFI/4G同时传输。
16.请问GVoice有考虑WebRTC中的模块吗?
这是完全不同的架构,我们在整个引擎里已经把经典语音通话模块比如信号处理相关的采集、3A处理等已经完全融合在一起了,这样做的原因是做语音通信的主件来说开启手机的目的就是语音聊天,但是GVoice不同,此时开启手机是为了打游戏,聊天是附加功能,所以我们会把所有跟信号处理相关的在WebRTC中分模块的东西融合在一起,尽量重用计算资源。
17.使用的是通用音频处理器吗,没有用后处理,在极端情况下比如连续丢包,丢掉半秒语音后无法重传,是否会在接收端做一些算法,通过深度学习恢复语音?
这主要关系到CPU成本问题,我们虽然有这种算法,但是会偏向于用在降噪及其他方面。对游戏来说更敏感的是采集端的噪声,比如用户玩游戏时手指敲击屏幕的声音,我们会集中算力做前处理而不太关注后处理。当然这是针对游戏场景的特性说的操作。
18.Roommanager对于多个VoiceServer一个room只会分配到一个VoiceServer吗?这里有什么分配策略么?
尽量分配到一个。集群内跨机转发是允许的。
扫描图中二维码或点击阅读原文
了解大会更多信息