• 聊聊音频类开源代码这点事


    我工作的头几年是在通信设备商做通信设备上的语音软件开发,主要是follow ITU-T/3GPP/RFC等SPEC写代码,相对封闭,没怎么接触开源代码。后来到芯片公司做终端上的voice engine,开始接触音频类的开源代码,先是ITU-T/3GPP的各种codec,后来是各种完整的解决方案。刚开始做voice engine的时候,GIPS还没被Google收购,更加没有webRTC的开源,那时腾讯QQ上的语音方案还没自研(用的是GIPS的方案)。到现在用过的音频类开源代码个数虽然没具体统计过,至少也有十几个吧,例如webRTC/PJSIP/FFMPEG。今天我们就聊聊音频类开源代码这点事。

    音频类开源代码众多,我根据自己的使用以及理解将它们分成三类,如下表:

    算法类主要有ITU-T/3GPP codec reference code等,音频的算法主要是数字信号处理,技术门槛是很高的,ITU-T/3GPP等组织为了普及自己制定的codec,就开源了codec的软件实现方便大家使用,大家用时的主要工作就是优化代码,使其在具体的平台上流畅运行。解决方案类主要有webRTC/PJSIP等,包括了从采集、编解码、传输到播放的整个过程,并且对不同平台(Linux/Android/iOS)进行了适配。好多公司(尤其互联网公司)基于这样的开源实现做二次开发,形成自己的产品。这类开源实现中也用其他的开源代码,主要是算法类的,比如用ITU-T/3GPP各种codec的reference code,再比如PJSIP就用了webRTC里的AEC的开源实现。介于算法和解决方案之间的既不是单纯的算法,也没有形成一套完整的解决方案,比如FFMPEG,它除了各种算法之外,还有各种音频格式的封装和解封装等,但它没有形成完整的解决方案,而是提供API给其他模块用。

    音频类代码的开源,不管是对行业对公司还是对从业的个人都是受益颇多。对行业而言,主要是降低了技术的门槛,促进了技术的普及,大家都来做了,也促进了行业的繁荣。要是没有webRTC的开源,短时间内肯定不会有音视频直播APP的集中涌现,更加不会有2016年全民玩直播的热潮。

    对公司而言,主要有以下益处:

    1,基于解决方案类的开源实现做产品,极大地缩短了产品的开发周期,让产品尽早的投放市场,获得先机和较好的市场份额。

    2,音频处理中复杂的算法,比如AEC,都是有很高的技术门槛的,一般不可能在短时间内做出一个性能很好的软件实现。以前只有大公司或者专业的算法公司才做这些算法,一般公司都是去买算法库用到自己的产品里。现在这些算法开源了,可以拿来用,节省了一笔开支。

    3,基于解决方案类开源实现做产品,就要对里面的机制技巧等搞清楚吃透,然后才能做二次开发。这样就逐渐的提高了整个团队的技术能力和竞争力。

    对个人而言,主要有以下益处:

    1,一些算法实现,如果只有文档,可能理解的不是很深刻,有了代码实现后就可以去调试,更好的理解算法。

    2,著名的解决方案类开源实现都是技术大牛写出来的,里面有很多的技巧和设计的思想,把这些都理解了后就无形中提高了自己的编程架构等能力。大家做东西一般都不是从零开始的,而是先学习他人的,理解消化后再根据自己开发产品的需要做改进。以我自己为例,以前对jitter buffer只有一个基本的概念,并不知道如何实现,后来学习了开源里的实现,理解消化后并做了一定的改进用到了自己开发的产品里。

    音频类开源代码也有自己的一些特点:

    1,对算法类开源实现而言,尤其是各种codec的reference code,一般都不能直接使用(主要是因为CPU load 高),而是优化后才能使用。

    2,对解决方案类开源实现而言,一般会适配各种平台各种协议,因而是包罗万象的,有的还增加了适配层,这些处理增加了代码的复杂度,加大了代码走读的难度。同时这些代码都是大牛写的,技巧性很强,也加大了代码走读的难度。我记得刚开始读PJSIP代码时特别晕,好多抽象出的适配层,到处是callback函数,而且这些callback函数的名称都一样,只有加log才知道这个函数在哪调的。后来代码熟悉了知道这些callback函数在哪调才好很多。

    就我自己而言,既在产品开发中用过算法类开源实现,也有基于解决方案类开源实现开发产品。我的看法是算法和模块可以用开源的,但是整个解决方案最好不要用开源的,即使刚开始为了赶进度用开源的,后面有时间了也要自己重写。因为解决方案类开源是保罗万象的,而我们自己开发的产品平台和协议等都是明确的,这样可以减少代码的复杂度冗余度,也有利于后期的维护(我看到一些基于解决方案类开源做的产品越到后面越难维护,不得不重写)。同时开源实现中好多会用非常复杂的数据结构,有时还有多层的封装,代码走读性不够友好。我喜欢的代码风格是简洁明了,能用简单的数据结构就不用复杂的,即使是刚毕业的学生也能很快看懂,也有利于后期的维护。记得在开发过的一款产品里前人用双向链表(buffer动态分配不固定)来存储从网络上收到的语音包,通常情况下都没有问题,但是网络状况多变,好多场景是设计时想不到的,只有出问题了才意识到。而且出问题基本上都是指针飞了crash,如果没有很好的定位crash的手段,再加上log又不是实时的,不知道crash在什么地方,会很痛苦。当时就填了好多这样的坑。后来我们用循环数组替换了双向链表,存放语音包的buffer是一块连续的空间,代码好理解,也很少出crash的问题,即使出crash问题也能很快定位解决。所以我觉得能用数组解决问题的就不要用链表,数组(循环数组/ring  buffer)是我这么多年用的最多的数据结构,而链表是很少用的。

  • 相关阅读:
    Nginx安装与运行配置总结
    不知道为什么随笔分类出不来
    springboot打war包
    python爬取网站页面时,部分标签无指定属性而报错
    python爬取某站新闻,并分析最近新闻关键词
    插了带蠕虫的U盘后,文件不见了怎么快速恢复
    CompTIA Security+ 常见知识点
    JAVA学习--集合的遍历
    JAVA学习--ArrayList使用方法:List的主要实现类
    JAVA学习--异常Exception的处理
  • 原文地址:https://www.cnblogs.com/talkaudiodev/p/8545533.html
Copyright © 2020-2023  润新知