移动通信最先进的音频编解码器EVS及用好要做的工作_音频幻线通讯业务-程序员宅基地

技术标签: 传统音频  音频  

语音通信从最初的只有有线通信变成后来的有线通信与无线通信(移动通信)的竞争,当移动语音通信价格下来后有线语音通信明显处于逆势。如今移动语音通信的竞争对手是OTT(On The Top)语音,OTT语音是互联网厂商提供的服务,一般免费,如微信语音。目前语音通信技术上就分成了两大阵营:传统通信阵营和互联网阵营,互相竞争,推动着语音通信技术的发展。具体到编解码器上互联网阵营提出了涵盖语音和音乐的音频编解码器OPUS(OPUS是由非盈利的Xiph.org 基金会、Skype 和Mozilla 等共同主导开发的,全频段(8kHZ到48kHZ),支持语音和音乐(语音用SILK, 音乐用CELT),已被IETF接纳成为网络上的声音编解码标准(RFC6716)),绝大多数OTT语音的APP都支持,有一统互联网阵营的趋势。移动通信标准组织3GPP为了应对互联网阵营的竞争,也提出了涵盖语音和音乐的音频编解码器EVS(Enhanced Voice Service)。我曾经给我做的手机平台上成功的加上了EVS,并且通过了中国移动的实网环境下的测试。下面就讲讲这个codec以及用好要做的工作。

 

3GPP在2014年9月将EVS编解码器标准化,由3GPP R12版本定义,主要适用于VoLTE, 但也同时适用于VoWiFi和固定网络电话VoIP。EVS编解码器由运营商、终端设备、基础设施和芯片提供商以及语音与音频编码方面的专家联合开发,其中包括爱立信、Fraunhofer集成电路研究所、华为技术有限公司、诺基亚公司、日本电信电话公司(NTT)、日本NTT DOCOMO公司、法国电信(ORANGE)、日本松下公司、高通公司、三星电子公司、VoiceAge公司及中兴通讯股份有限公司等。它是3GPP迄今为止性能和质量最好的语音频编码器,它是全频段(8kHZ到48kHZ),可以在5.9kbps至128kbps的码率范围内工作,不仅对于语音和音乐信号都能够提供非常高的音频质量,而且还具有很强的抗丢帧和抗延时抖动的能力,可以为用户带来全新的体验。

 

下图是3GPP EVS相关的SPEC,从TS26.441到TS26.451。

我已将关键的几个用红框标出,其中TS26.441是总览,TS26.442是用C语言写的定点实现(reference code),这也是后面用好EVS工作中的重中之重。TS26.444是测试序列,优化reference code过程中几乎每天都要保存一个优化的版本,每天都要用测试序列跑一跑优化的版本,如发现不一样了,说明优化的有问题,要退到上一个版本,并检查出哪一步优化出问题了。TS26.445是EVS算法的具体描述,近700页,说实话看的头疼,如果不是做算法的,算法部分看个大概就可以了,但是对特性描述相关的一定要细看。

 

EVS对语音信号和音乐信号采用不同的编码器。语音编码器是改进型代数码激励线性预测(ACELP),还采用了适合不同语音类别的线性预测模式。对于音乐信号编码,则采用频域(MDCT)编码方式, 并特别关注低延迟/低比特率情况下的频域编码效率,从而在语音处理器和音频处理器之间实现无缝可靠的切换。下图是EVS编解码器的框图:

编码时先对输入的PCM信号做预处理,同时确定是语音信号还是音频信号。如是语音信号就用语音编码器编码得到比特流,如是音频信号就用感知编码器进行编码得到比特流。解码时根据比特流中的信息确定是语音信号还是音频信号,如是语音信号就用语音解码器解码得到PCM数据,然后做语音带宽扩展。如是音频信号就用感知解码器解码得到PCM数据,然后做频率带宽扩展。最后再做后处理作为EVS解码器的输出。

 

下面说说EVS的各个关键特性。

1,EVS支持全频段(8kHZ--48kHZ),码率范围是5.9kbps至128kbps。每帧是20Ms时长。下图是音频带宽的分布:

窄带(Narrow Band, NB)范围是300HZ-3400HZ,对应的采样率是8kHZ,AMR-NB用的就是这种采样率。宽带(Wide Band, WB)范围是50HZ-7000HZ,对应的采样率是16kHZ,AMR-WB用的就是这种采样率。超宽带(Super Wide Band, SWB)范围是20HZ-14000HZ,对应的采样率是32kHZ。全带(Full Band, FB)范围是20HZ-2000HZ,对应的采样率是48kHZ。EVS支持全频段,所以它支持四种采样率:8kHZ、16kHZ、32kHZ和48kHZ。

下图是在各种采样率下支持的码率:

从上图看出只有在WB下支持全码率,其他采样率下只支持部分码率。需要注意的是EVS向前兼容AMR-WB,所以它也支持AMR-WB的所有码率。

 

2,EVS支持DTX/VAD/CNG/SID,这同AMR-WB一样。在通话过程中通常有一半左右时间讲话,其余时间处于聆听状态。在聆听状态时没必要发语音包给对方,于是就有了DTX(非连续传输)。要用VAD(静音检测)算法去判断是语音还是静音,是语音包时就发语音包,是静音时就发静音包(SID包)。对方收到SID包后就去用CNG(舒适噪声生成)算法去生成舒适噪声。EVS中有两种CNG算法:基于线性预测的CNG(linear prediction-domain based CNG)和基于频域的CNG(frequency-domain based CNG)。在SID包的发送机制上EVS跟AMR-WB不同,在AMR-WB中VAD检测到是静音时就发送一个SID包,然后40Ms后发送第二个SID包,随后每隔160Ms发送一个SID包,不过VAD一检测到是语音就立刻发送语音包。EVS中SID包的发送机制可配,可以固定每隔一段时间(几帧,范围是3--100)发送一个SID包,也可以根据SNR自适应的发送SID包,发送周期范围是8—50帧。EVS SID包的payload大小也与AMR-WB不同,AMR-WB的是40个字节(50*40=2000bps),EVS是48个字节(50*48=2400bps)。从上可以看出DTX有两个好处,一是可以节省带宽,增加容量,二是因为不编解码减少了运算量,从而降低功耗增加续航时长。

 

3,EVS也支持PLC(丢包补偿),这也同AMR-WB一样。不过EVS把Jitter Buffer Module(JBM)也包含了进来,这在以前的codec中是从来没有过的。我在使用中没有用到JBM,由于时间比较紧,也就没有时间去研究。后面有时间了定要好好研究一下,JB可是语音通信的难点之一同时也是语音质量的瓶颈之一呀。

 

EVS的算法时延根据采样率不同而不同。当采样率为WB/SWB/FB时总时延为32ms,包括一帧20ms的时延,编码侧输入重采样的0.9375ms时延以及8.75ms的前向时延,解码侧时域带宽扩展的2.3125ms时延。当采样率为NB时总时延减小为30.9375ms,相对WB/SWB/FB减小了1.0625ms, 这1.0625ms主要是在解码侧减少的。

 

EVS的语音质量(MOS值)相对于AMR-NB/AMR-WB有了明显的提升。下图是这几种codec的MOS值比较:

从上图看出,当采样率为NB时在各种码率下EVS-NB的MOS值比AMR-NB的MOS值显著提升;当采样率为WB时在各种码率下EVS-WB的MOS值同样比AMR-WB的MOS值显著提升;当采样率为SWB并且码率大于15kbps时EVS-SWB的MOS值接近了不编码的PCM的MOS值。可见EVS的语音质量是相当不错的。

 

用好EVS要做的工作在不同的平台上会有所不同,我是用在手机平台audio DSP上,用于语音通信。下面就说说为了手机支持EVS我做了哪些工作。

1,学习EVS相关的SPEC。要把前面我列的SPEC都看一遍,因为不是做算法,算法相关的可以看的粗,但是对特性描述相关的一定要看的细,这关系到后面的使用。

 

2,在PC上生成encoder/decoder的应用程序。我是在Ubuntu上做的,把PCM文件作为encoder的输入,根据不同的配置生成相应的码流文件,再把码流文件作为decoder的输入,解码还原成PCM文件。如果解码后的PCM文件听下来跟原始PCM文件无异样,说明算法实现是可信的(权威组织出来的算法实现都是可信的,如果有异样说明应用程序没做好)。做应用程序是为了后面的优化,也方便理解外围实现,如怎么把编码后的值变成码流。编码后的值放在indices(最多有1953个indices)中, 每个indices有两个成员变量,一个是nb_bits,表示这个indices有多少位,另一个是value,表示这个indices的值。Indices有两种存储方式:G192(ITU-T G.192)和MIME(Multipurpose Internet Mail Extensions)。先看G192,每一帧的G192的存储格式见下图:

第一个Word是同步值,分good frame(值为0x6B21)和bad frame(值为0x6B20)两种,第二个Word是长度,后面是每个值(1用0x0081表示, 0用0x007F表示)。Indices里的value用二进制表示,位上的值为1就存为0x0081,为0 就存为0x007F。下图是一个例子,采样率为16000HZ, 码率为8000bps,因此一帧有160位(160 = 8000/50),保存成G192格式就是160个Word。下图中头是0x6B21, 表示good frame,length是0x00A0, 后面160个Word是内容。

再来看MIME格式。要把indices的value值pack成serial值,具体怎么pack,见pack_bit()函数。MIME的格式是第一个Word是header(低4位表示码率index, 在用WB_IO时第5和6位要置1,EVS 时不需要),后面是比特流。还是上面采样率为16000HZ码率为8000bps的例子,但存成MIME格式,一帧有160位,需要20byte(20 = 160/8),如下图:

上图中头16个字节是reference code自带的,第17个字节是header,0x2表示以EVS 编码,码率是8kbps(8kbps index为2),后面的20个字节表示pack后的payload。

在语音通信中,要把indices的value值pack成serial值,然后作为payload发送给对方。对方收到后先unpack再解码得到PCM值。

 

3,原始reference code通常是不能直接使用的,需要优化。至于怎么优化,请看我前面写过的一篇文章(音频的编解码及其优化方法和经验),文章写的是比较通用的方法。我现在要在DSP上用,DSP的频率较低,只有三百多MHZ,不用汇编优化时搞不定的。我之前没用过DSP汇编,要在短时间内优化的很好有很大难度。老板权衡后决定用DSP IP厂商提供的优化好的库,汇编方面它们更专业一点。

 

4,对reference code的应用程序改造,方便后面调试验证时当工具使用。原始reference code保存成文件时是以字节为单位的,而DSP是以Word(两个字节)为单位,所以要对reference code里的pack/unpack函数改造,以适应DSP。

 

5,要想打电话时codec是EVS,Audio DSP 和CP上都要加相应的代码,先写各自的代码自调,然后联调。我自调时用AMR-WB的壳(因为EVS和AMR-WB的一帧都是20ms时长),即流程上用AMR-WB的,但codec从AMR-WB换成EVS。主要验证encoder、pack、unpack、decoder是否ok,其中encoder和pack是上行的,unpack和decoder是下行的。它们的先后关系如下图:

先调上行,把encode后的保存成G192格式,用decoder工具解码成PCM数据用CoolEdit听,跟自己说的话是一样的,说明encoder是OK的。再调pack,把pack后的码流保存成MIME格式,同样用decoder工具解码成PCM数据用CoolEdit听,跟自己说的话是一样的,说明pack是OK的。再调下行。由于CP还没有正确的EVS码流发给Audio DSP,就用loopback的方式来调试,具体是把pack后的码流作为unpack的输入,unpack后得到的保存成G192格式,用decoder工具解码成PCM数据用CoolEdit听,跟自己说的话是一样的,说明unapck是OK的。最后调decoder,把decoder后的PCM数据用CoolEdit听,跟自己说的话是一样的,说明decoder是OK的。这样自调就结束了。

 

6,与CP联调。由于前面自调时各关键模块都是调好的,联调起来相对比较顺利,没几天就调好了。这样打电话时就能享受EVS带来的高音质了。

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

智能推荐

android 代码 截取屏幕,如何以编程方式在Android上截取屏幕截图?-程序员宅基地

文章浏览阅读346次。这是允许我的屏幕截图存储在SD卡上的代码,以后用于满足您的任何需求:首先,您需要添加适当的权限来保存文件:这是代码(在Activity中运行):privatevoidtakeScreenshot(){Datenow=newDate();android.text.format.DateFormat.format("yyyy-MM-dd_hh:mm:ss",now);try{//i..._屏幕部分截图android代码

注册表禁用计算机管理,Win7注册表编辑器被管理员禁用的解除方法-程序员宅基地

文章浏览阅读2.7k次。熟悉Win7系统的朋友都知道,注册表编辑器是更改Win7系统设置的好工具。在注册表中可以完成控制面板中不能修改的设置。但是有些用户打开注册表编辑器的时候却被提示,注册表编辑器已被管理员禁用,这是怎么回事呢?如何解除Win7对注册表编辑器的限制呢?一、Win7打开注册表的方法1 Win+R键打开Win7系统的运行,在运行数输入regedit点击确定。二、注册表被禁用解除方法Win7注册表编辑器被管理..._注册表编辑器禁用和解除原因

mysql innodb 源码_【InnoDB源码分析】Redo log-程序员宅基地

文章浏览阅读502次。【版本:mysql-8.0.12】1. Mini Transaction(mtr)InnoDB会将事务执行过程拆分为若干个Mini Transaction(mtr),每个mtr包含一系列如加锁,写数据,写redo,放锁等操作。举个例子:void btr_truncate(const dict_index_t *index) {... ...page_size_t page_size(space-&..._mysql innodb 源代码 解读

matlab背景设置_preferences: path: c:\users\administrator\appdata\-程序员宅基地

文章浏览阅读515次。打开C:\Users\Administrator\AppData\Roaming\MathWorks\MATLAB\R2015b\matlab.prf修改为#MATLAB Preferences#Sat Jul 11 15:54:49 CST 2020Editor.VariableHighlighting.Color=C-6931898EditorMRUSize=I8ReplaceSearchText19=SReplaceSearchText18=SReplaceSearchText17=S_preferences: path: c:\users\administrator\appdata\roaming\mathworks\matlab\c

谁说技术男不浪漫!90后程序员2天做出情绪...-程序员宅基地

文章浏览阅读75次。点击上方[全栈开发者社区]→右上角[...]→[设为星标]点击领取全栈资料:全栈资料9月1日,一则关于#程序员2天做出猫咪情绪识别软件#的话题登上微博热搜,参与阅读的人数达到了82..._程序员自研

解决SpringBoot整合redis下的键值序列化的问题_spring boot redis 查询序列化key-程序员宅基地

文章浏览阅读1.3k次。文章目录思考redis实现键值序列化自定义一个序列化转换器编写redis配置文件编写application.properties编写User类编写controller编写service测试思考为什么键值要序序列化呢?​ 不同平台之间的数据传输,深拷贝,浅拷贝,如果不采用序列化,很容易在传输过程中出现各种错误,无法正常使用Redis的序列化到底是什么?​ 简单的是说 就是 key ..._spring boot redis 查询序列化key

随便推点

JavaSE基础知识(十三)--Java的数组以及数组的初始化_int a1=a[rand.nextint(a.length)];-程序员宅基地

文章浏览阅读1.1k次。Java SE 是什么,包括哪些内容(十三)?本文内容参考自Java8标准数组是相同类型的,用一个标识符名称封装到一起的一个对象引用序列或基本数据类型序列,数组是通过方括号下标操作符[ ]来定义和使用的,要定义一个数组,只需要在类型后面加上一个[ ],并取一个合适的标识符名称即可。上面的内容总共体现在三个方面:⑴、数组内的数据类型必须是同一类型,也就是说在一个数组内不能同时存储不同数据类型..._int a1=a[rand.nextint(a.length)];

计算机专业2016高考录取分数线,华南师范大学计算机类专业2016年在广东理科高考录取最低分数线...-程序员宅基地

文章浏览阅读129次。类似问题答案华南师范大学计算机类专业2015年在广东理科高考录取最低分数线学校 地 区 专业 年份 批次 类型 分数 华南师范大学 广东 计算机类 2015 一批 理科 612 学校 地 区 专业 年份 批次 类型 分数 华南师范大学 广东 计算机类 2016 一批 理科 563 华南师范大学 广东 计算机类 2016 一批 理科 563 华南师范大学 广东 计算机类 2015 一批 理科 612..._华南师范大学广东2016各专业分数线

arm-linux-gnueabihf opencv,opencv3.4.9 + armv7 + arm-linux-gnueabihf交叉编译-程序员宅基地

文章浏览阅读249次。mac上编译 arm linux gnueabi交叉编译工具链toolchaincrosstool-ng 编译和安装 交叉编译工具下载: git clone [email protected]:secularbird/crosstool-ng.git 切换到mac编译分支 git ...Windows平台交叉编译Arm Linux平台的QT5.7库1.准备交叉编译环境 环境说..._gcc-arm-linux-gnueabihf armv7l

mysql数据库dao模式_mysql中DAO模式-程序员宅基地

文章浏览阅读591次。JDBC封装优点:隔离细节降低代码间耦合性提高代码可扩展性和维护性附注:DAO模式提供了访问关系型数据系统所需操作的接口,将数据访问和业务逻辑分开,对上层提供面向对象的数据访问接口.DAO模式实现两层分离:代码间分工明确,数据访问层代码不影响业务逻辑层代码,这也符合单一职能原则,降低了耦合度,提高了代码的可复用性。。隔离了不同的数据库的实现,采用面向接口编程,如果底层数据变化了,如mysql变成了..._mysqldao

Android对数据按照时间排序,Android实现数据按照时间排序-程序员宅基地

文章浏览阅读748次。经常遇见一个列表,两个接口的情况,两个接口属于两个不同的表数据,那么数据拼接回来之后,并不是按照时间排序的,看起来就相当混乱,所以记录一下如何对数据按照时间排序。步骤一:格式化日期public static Date stringToDate(String dateString) {ParsePosition position = new ParsePosition(0);SimpleDateFo..._安卓代码实现聊天记录根据时间排序

华硕固件默认ip,新路由3 newifi d2刷机刷华硕固件教程-程序员宅基地

文章浏览阅读4.9k次。新路由3默认的功能非常的少,所以不刷个好固件简直就是浪费硬件性能,恢复出厂后默认的路由器IP就是192.168.99.1。准备下面几个工具和固件上面工具准备好以后,下面开始刷机:一. 开启固件 SSH1、开启路由器,进入管理界面 (假设路由器 IP 地址是 192.168.99.1)2、 在浏览器中输入 http://192.168.99.1/newifi/ifiwen_hss.html 并进入3..._路由器刷华硕固件之后默认ip