服务端混音 | WebRTC编风网
1

服务端混音

已有 390 人阅读此文 - - 极Talk - 郝飞(亲加云CTO)

一、背景介绍

最早接触服务端混音这个概念,是几年前一个游戏公司提出的功能需求; 他们要在手机游戏中植入类似YY 那样的实时语音功能,但当一个频道中同时说话的人数过多的时候,手机终端会出现网络和CPU 方面的瓶颈,例如如果三个人同时说话,那么其他的用户就要接收三路语音,同时还要对这三路语音进行解码,再加上游戏本身对网络和CPU 的消耗,这对游戏用户的网络和手机CPU提出了很高的要求; 因此,需要通过服务端混音的方式,使得客户端只接收到一路语音,这样可以保证语音的通讯不影响游戏的质量。

二、服务端混音功能介绍

在具体介绍服务端混音的实现以前,我们先来分析一下混音的业务;在这里我们首先规定一下,在任何一个频道中不管有多少人同时说话,只会取其中三个人的语音进行混音处理;这个假设合理吗? 试想一下,如果一群人在会议室中面对面的开会,当同时超过三个人说话的时候,其他人还能听得清楚吗; 因此,从经验上来看,同时混音三路已经基本上能够还原真实场景了。

那如何从多路中挑选三路呢?在现实场景下,一定是音量大的覆盖音量小的声音; 因此,可以采用类似的策略,计算每一路音频的增益,从而做出选择; 还好增益的算法不复杂,并不会耗费很多时间; 在实际处理中,如果能够增加下平滑的处理就更好了,这样会有效避免声音的断续感。

混音服务器的输出路数是输入路数加1,具体情况如下:

1.如果只有一个人在说话,这种情况不需要任何混音处理,服务端直接进行语音分发就可以了;

2.如果是两个人(A和B)在说话,那么混音服务器需要输出三路数据; 把B 的语音数据给A,A 的语音数据给B,同时AB的混音数据给其他所有用户,如图:

1

a.如果是三个人(A,B和C)在说话,那么混音服务器需要输出四路数据:BC的混音给A,AC 的混音给B,AB 的混音给C,同时ABC的混音数据发送给其他所有用户,如图:

2

三、服务端混音实现描述

通过以上的叙述,相信大家已经了解什么是混音了,接下来开始讨论其具体实现:其整体系统架构图如下:

3

·其中语音服务器主要负责与客户端连接,从客户端收发语音,并与混音服务器进行交互,完成混音功能;

·混音服务器主要进行混音处理;其从语音服务器收取用户语音数据,进行混音后再输出给语音服务器,然后转发给客户端;

·管理服务器对混音服务器分配进行管理。

其中混音服务器内部的实现主要包括三个部分:

·语音接收功能; 即从语音服务器中接收实时语音数据,并存入到缓存中;

·混音功能:混音模块从buffer 中获取数据,然后进行解码,混音以及编码的操作; 然后把相关的数据保存在缓存中;

·语音发送功能:即从buffer 中获取混音数据,并发送给语音服务器。

在实际代码开发中,混音服务器可以考虑使用如下的线程模型,这种模型比较适合混音服务器流程:

4

其中语音数据的收发都可以放在Reactor 中异步完成;而混音功能,可以根据CPU 核数开启一定量的线程负责相关混音工作。

四、服务端混音引入的问题

服务端混音在带来了诸多好处的同时,也存在自身的一些问题:

首先,服务器混音会增加系统延迟; 毕竟混音的流程需要增加解码,混音和编码的过程,而增加的延迟也主要由这三部分组成;具体增加多少延迟,这个与机器的性能,所选择的编解码器的复杂性和优化等都有关系; 一般从需求的角度来说,增加的延迟应该控制在500ms 以内,否则整体延迟如果在一秒以上,用户就有明显的停顿感了。

其次,混音服务也对系统稳定带来了挑战;如果混音服务出现了问题,会导致系统整体不可用;其实可以考虑服务端混音和客户端混音切换的模式; 当服务端混音一切正常的情况下,系统使用服务端混音; 当服务端混音出现问题,系统自动切换到客户端混音,这个时候语音服务器只完成语音转发工作,客户端获取到多路语音数据后,在客户端进行语音叠加后再进行播放。

五、编解码的选择

大家知道,服务端混音引入的延迟与编解码关系非常大,因此如何选择编解码就显得格外重要;以下是我们在一台虚拟机上针对码率在20kbps 以下的常用编解码测试得到的数据:

5

这几种编解码器从主观质量评估(50人参与)来看,质量相差并不大;但从性能来看,opus 的decoder 耗时比其他编解码要低很多,而混音服务器需要解码多路码流然后编码成一路码流,因此解码器的耗时对混音服务器的CPU利用率影响很大,根据以上测试数据,Opus 作为编解码器可以极大的减少服务器消耗; 当然,硬件codec也是一种方案,可以通过扩展板卡实现语音的编解码工作,但此方案不太适合在云主机上部署,不能支持主机的动态扩展需求。

 

2
相关文章!
  1. 匿名 - 2016.12.21

    有没有搞错啊,40ms的语音数据编码要2106ms?