如何在嵌入式Linux上开发一个语音通讯解决方案

开发一个语音通讯解决方案是一个软件项目。既然是软件项目,就要有相应的计划:有多少功能,安排多少软件工程师去作,这些工程师在这一领域的经验如何,是否须要培训,要多长时间作完,中间有几个主要的milestone等。咱们曾经四我的花了近一年时间开发了一个语音解决方案,成功经过验收,各项关键指标(语音质量、单向时延)均达到运营商要求。当时是在芯片公司,在公司本身的芯片上作语音解决方案,增长芯片的卖点,加强芯片竞争力。咱们作语音数据面实现,同时提供API。用户在上层控制协议(例如SIP)中调用API,从而实现语音通讯功能。下面聊聊咱们当时是怎么一步步作出来的。算法

 

1,讨论需求和软件架构网络

第一步是讨论需求,看要实现哪些功能,并对功能排一个优先级。讨论下来前处理(回声消除、噪声抑制、增益控制)、tone generation、重采样、codec(g.7十一、g.72二、g.729)、RTP、RTCP 、jitter buffer等是第一优先级功能,VAD、CNG、SID、PLC等是第二优先级功能。同时制定了几个关键的milestone点:讨论需求和软件架构、成功打通第一个basic call、完成第一优先级功能产品基本能用、完成第二优先级功能攻克关键指标、全面测试经过验收。需求讨论后就要看用一个什么样的软件架构去实现这个解决方案。因为在Linux上开发,Linux上关于声音的架构是ALSA,讨论下来咱们基于ALSA来作,这样能够缩短开发周期,在driver上仅仅是调试,在user space里用好ALSA-Lib等。同时肯定了须要三个thread。Capture thread每隔10ms运行一次,靠ALSA获取采集到的语音PCM数据,而后作前处理编码打包等发到网络上。Play thread也是每隔10ms运行一次,从jitter buffer中获取10ms的码流,而后解码成PCM等再经由ALSA送给audio device播放出来。Packet receive thread用来从网络上收包,收到后解析并放进jitter buffer中。因为jitter buffer会被两个thread访问,须要加保护。这样语音数据面的软件架构图以下:架构

                                             

这些都肯定后咱们就开始向第一个Milestone进军了。框架

 

2,成功打通第一个basic callless

这一阶段的目标就是成功打通第一个basic call。在每一个阶段的开始咱们都讨论一下你们的分工。共四我的,一个同窗负责搭软件框架以及作API给上层协议调用。一个同窗对ALSA比较熟悉,由他负责调ALSA,分两个阶段:第一阶段是把从ALSA获得的MIC的PCM数据再经由ALSA送给speaker播放出来,即在PCM侧造成Loopback。若是从MIC讲的话到speaker正确播放出来,ALSA的调试就完成了。第二阶段是加上最简单的codec G.711,造成codec loopback,即从ALSA获得的MIC的PCM数据用G.711编码获得码流,而后用G.711解码获得PCM数据再经由ALSA送给speaker播放出来。我主要负责网络侧,包括RTP的实现以及UDP收发包的实现等。也是经过loopback的方式调试,即将特殊字符(如全’a’)做为RTP的payload打包(codec用G.711),而后经过UDP socket发给目标地址,在目标地址板子上用UDP socket收包,收到后解析RTP获得payload,这个payload与发送端的payload 相比较,若是彻底相同则说明RTP的实现UDP收发包的实现是正确的。因为jitter buffer相对比较复杂,这一阶段暂时不用jitter buffer,用固定的缓冲buffer来替代,可是jitter buffer的设计开始作起来。一个同窗负责上层协议,也就是SIP,用一个开源的实现(上层协议不是咱们的重点,主要是配合底层实现的),把基本功能调试好就能够了。socket

 

通过你们的努力,这一阶段的目标如期实现。当成功打通第一个basic call的时刻,你们别提多高兴啦。毕竟这几乎是从零开始作方案,这种经历仍是可贵的。咱们还特意出去吃了一顿大餐,庆祝basic call成功打通。oop

 

3,完成第一优先级功能,产品基本能用测试

这一阶段的目标就是完成第一优先级功能,产品基本能用。依旧先分好工。先前作框架和API的作重采样、tone generation和codec(G.722/G.729)。先前调试ALSA的负责前处理(回声消除、噪声抑制、增益控制)。他们主要是先验证算法再调试算法使其在咱们的方案里能很好的运行,先保证能用,后面再优化。我仍是负责网络侧,完成jitter buffer和RTCP。作SIP的同窗在这一阶段使功能更完善。这一阶段相对于上一阶段难度加大了,咱们每一个人在作的过程当中都或多或少的遇到了一些困难。以我本身为例,在作jitter buffer的过程当中就遇到了很多困难,主要是在一些细节上设计时想的不全,致使在良好网络下音质有时也很差。这些问题后来都一一被解决,同时也更新了设计文档。在你们的努力下,这一阶段也如期完工。老板来验收后对目标完成表示满意,又带着你们出去吃了一顿大餐。优化

 

4,完成第二优先级功能,攻克关键指标编码

这一阶段的目标就是完成第二优先级功能,攻克关键指标。关键指标有各类场景下的打电话时CPU load、各类网络环境下的语音质量(MOS值)、单向时延(one way delay)、连续打多少通电话不出错(bulk call)、单通电话最大能持续多长时间(long call)等。先前作重采样等的同窗作第二优先级功能(VAD、CNG、SID、PLC等)。先前作前处理的作CPU load优化,使打电话时所有模块所占的CPU load控制在一个合理的范围内,固然是越小越好,作的很好就是咱们方案的一个卖点。我主要负责语音质量、bulk call、long call等。作SIP的同窗依旧完善SIP的功能。这一阶段使愈来愈难愈来愈有挑战了。优化算法load的同窗须要测出各个算法的load,而后一一优化,尽量降到最小。语音质量把我折腾的够呛。单向时延也是,仪器测出来的是一个总的值,我要找到各个模块引入的delay是多少,而后看怎么减少。bulk call和long call都是作起来很是头疼伤脑细胞的,通常都是晚上或者周末测,次日早上或者下周一早上看结果,若是有问题就分析看怎么解决。

 

在这一阶段很多问题都是你们一块儿讨论看怎么解决的,毕竟这些问题都是很难的。 咱们没被困难打趴,仍是在规定时间内搞定了。咱们离最终目标愈来愈近了!

 

5,全面测试,经过验收

在前面几个阶段中,把一个功能作完后会对这个功能相关的进行测试,确保功能无缺,可是因为赶进度,并无作全面性的测试。如今各项功能所有完备,关键指标也已所有达标,是时候全面测试确保产品质量了。首先是由咱们开发人员本身测,咱们以为质量能够了再交由测试人员测。咱们本身测时先由一我的写测试用例,而后你们一块儿review讨论,确保尽可能全的覆盖,还有就是异常case要尽可能多的考虑。测试用例review后你们分工测,发现了些问题,因为代码除了算法全是咱们本身写的,对代码机制很是熟悉,发现的问题很快就解决了(算法都是很是成熟的,通常不会出问题)。交给测试人员后共测试了三轮,也发现了一些问题(测试人员的测试用例会更多一些,他们的测试也会更专业一些,必定要由他们把关产品质量),也都很快解决了。最终顺利的经过了验收。老板和咱们都特别高兴,虽然咱们的方案是免费提供给客户,可是这加强了咱们芯片的竞争力,能够提升芯片的出货量。对咱们我的而言也是一次很可贵的一个方案从无到成功完成的经历,毕竟工做中这种经历太少了。

 

最后咱们也进行了总结,有哪些lesson learnt,哪些作的不错,哪些还能够作的更好。

相关文章
相关标签/搜索