本文系作者原创。如转载,请注明出处。 谢谢!
音频软件开发同其他软件开发一样,都需要去调试。音频软件调试同其他软件调试方法有相同的地方,也有不同的地方,同时调试时还需要借助一些专门的工具,有了这些方法和工具,就能快速的定位问题和解决问题。下面我们就谈谈这些方法和工具。
1,方法
1)log
这是软件调试中最常用的方法,音频调试也不例外。在写代码时加上一定的log, 在出问题时就打开这些log,通过log分析问题出在什么地方。一个好的log体现在如下几点:
a) 要有时间和日期,有时候时间戳对分析问题很重要。
b) 函数入口处和出口处要加上log,有了这就能很快看出函数调用流程。
c) 发生问题时的相关变量值要打印出来,这对分析问题至关重要。
d) log要分级别,常见级别有error/warning/debug/info等。有时候log打印太多会导致load大从而出现不同的结果影响分析。
2)二分法
当前版本有问题,而以前的某个版本没问题,这说明是近期的某个改动引起的。这时我们就需要用二分法快速找出哪个版本开始出问题的。先把当前版本和那个好的版本中间一分为二,取中间那个版本,看有没有问题,有的话说明这个中间版本之前就有问题了,没有的话说明是这个中间版本后面的改动引入的。这样的话就把范围缩小一半了。在这样继续二分下去,直到最后找到最初出问题的版本。找到版本后再看这个版本加入了几个改动,分析哪个改动最可能引起这个问题,直到最后找到根本原因解决问题。
3)crash的分析方法
写代码crash是难免的,关键是crash后能快速找到原因并最好后面不犯这个错误。通常crash主要有这几种原因:空指针,除零,越界,死循环,当然还有其他的原因。在Linux下有好的工具,很容易查。有些小众的OS没什么工具查crash问题,如果是做底层的可以借助JTAG工具,不然的话还得靠log。Log是实时的还好办,多加点打印总能找出crash的地方。就怕log非实时,这时只能具体问题具体分析了。记得在一个OS下log非实时,一个模块相对独立,只能把函数调用关系和输入参数值都保存在文件里,在Linux下做一个应用程序去读这个保存的文件从而模拟当时的过程,再借助Linux的工具找到crash的地方,最终这个应用程序成了一个工具,以后再遇到类似的问题就能很快解决了。
4)最小系统法
做一个软件系统时刚开始是一个最小系统,即缺了任何一个模块,系统不能用。后来加上一个个功能使系统完备。在写代码时我们可以加上一些标志位使这些后加的功能enable或者disable。这有助于后面出现问题时排查。下图是语音通信的软件框图,最小系统是采集播放编解码网络发送接收等,没有这些不能通话。而前处理的一些模块(AEC/ANS/AGC等)则不是最小系统里面的,它们是后来一步步加上去的。假设系统出问题了,我们先disable前处理的诸多模块,形成最小系统,看有没有问题,有说明问题在最小系统里,再继续调查。没有的话先把AEC使能看有没有问题,有说明问题在AEC里,没有说明问题在ANS或者AGC里。如没有问题继续使能ANS看是否有问题,有说明问题在ANS里,没有说明问题在AGC里。经过这几步基本定位问题在哪个模块里,后面再结合其他方法直到找到根本原因。
音频开发时不管是voice还是music好多问题是音频听下来不对,这时就要用音频特有的debug方法了。
5)dump音频数据
Dump音频数据就是把音频数据dump出来用工具(比如CoolEdit, 后面讲工具时会具体讲)播放,或者看波形,或者看频谱,看是否正确。一般是找几个可能的dump点,进模块前一个dump点, 出模块后一个dump点。如果进模块前dump出来的数据是好的,而出模块后的音频数据是坏的,那么问题就出在这个模块了,再一步步排查,最终找到把音频数据写坏的地方。还是以上面的语音通信软件框图为例,在AEC前设一个dump点,AEC后再设一个dump点,如果AEC前的音频数据是好的,AEC后的音频数据不好了,问题肯定出在AEC里。
Dump音频数据也有几种不同的方法,在不同的场合用不同的方法。
a)把音频数据写进指定的文件里,问题复现后把这个文件导出来用工具分析。
b)把音频数据放进RTP包里发送到指定的IP地址上,用抓包工具(比如wireshark, 后面讲工具时具体讲)抓到这些包。由于是PCM数据,在wireshark上可以直接听或者看波形。这多用于语音通信场景。
c)有时候有些模块对自己是黑盒的,比如在linux下kernel space的音频驱动对做use space的来说就是黑盒。在use space里调查下来音频数据没问题,但是最终从扬声器或者耳机出来的音频是有问题的,这时可以用一根音频线一头连着出问题的设备的耳机,另一头连着电脑,复现问题,用CoolEdit把出问题时的音频录下来,先听确认问题出在这个黑盒模块里,然后看波形,是否有规律,如果有规律,好查一些,没规律再具体问题具体分析。
6)loopback音频数据
loopback音频数据就是形成回环,从而来排查问题。还是以上面的语音通信软件框图为例,有几种不同层次的loopback,见下图:
1) 把采集和播放形成loopback,即把采集到的音频数据立刻payback出来,听下来是好的说明音频驱动没问题,不好说明问题在音频驱动里面。
2) 把前处理后的数据和播放形成loopback,即把ANS后的PCM数据直接播放出来,听下来是好的说明前处理没问题,不好说明问题在前处理里面。
3) 把编码和解码形成loopback,即把编码后的码流立刻放进解码器得到pcm数据再playback出来,听下来是好的说明问题出在网络侧,不好说明问题出在编解码里面。
通过上面几个loopback基本上可以定位问题出在哪个模块里,再在这个模块里仔细调查直到找到根本原因。
2,工具
上面讲方法时提到了几个工具,如CoolEdit,下面具体讲。
1)CoolEdit / Audition
这应该算是做音频开发的必备工具了。以前叫CoolEdit,后来被Adobe收购重新包装后形成了Audition。我个人还是习惯于用CoolEdit,原因一是用习惯了,二是CoolEdit可以保存成PCM文件,而Audition却不可以,做音频开发的保存成PCM文件最方便。
用CoolEdit可以听音频是否正常,也可以看波形,在出问题时看波形是否有规律,还可以看频谱。同时还可以生成一些特定的音频文件用于去调试。比如调试音频算法时用一个时间相对较长的(> 1秒)的音频文件会很不方便,主要是因为log多,不便于分析。算法通常一帧为10ms或者20ms,需要几帧就可以调试算法了。这时用CoolEdit做一个几十ms的PCM文件给算法调试用。再比如用CoolEdit做一个20HZ到20000HZ的扫频文件作为某个算法或者某个系统的输入,看这个算法或者系统的频响如何。
CoolEdit的具体使用可以看help文件,或者看网上的文章,这里就不详细讲了。
2)Wireshark
Wireshark主要用于语音通信场景,抓网络上的语音包。当然它也可以抓其他类型的包,在做音频开发时就是抓语音相关的RTP/RTCP包了。抓到包后可以看某个具体包的RTP/RTCP属性,比如sequence number/time stamp等,从而去分析定位问题等。Wireshark也可以分析丢包率等,还可以播放codec 为g711的语音包,当然还有其他用途,这里就不一一说了,有需求的可以到网上看具体的文章。
3)mediainfo
Mediainfo主要用于音乐场景,用它可以看到一个音乐文件(例如MP3)的属性,有采样率/声道数/codec类型/码率等。如果在log中看到的打印值和mediainfo中显示的值对不上,说明读取音乐文件属性的代码有问题。
4)GoldWave
GoldWave也主要用于音乐场景,用它来做采样率/codec/码率等的转换。支持的采样率、codec、码率都特别多,对调试有不少帮助。例如某个系统要支持采样率为11025HZ的音乐文件,但是市面上的音乐文件一般为44.1KHZ或者48KHZ的,这就需要专门的工具去做转换,从而得到想要的文件。然后拿这个文件去调试测试看系统是否支持采样率为11025HZ的音乐文件。
关于音频debug的方法和工具暂时就先谈这么多,以后想到了被遗忘的以及有新的会及时补充。也欢迎大家补充,形成一个好的debug方法和工具集,对大家都是益处多多。谢谢!