1. 信号是信息的物理表现形式 / 携带信息的自变量函数.
信息是信号的具体内容 .
2. 信号的类别 : 电的, 声的, 光的 , 磁的, 机械的. 热的 . 生物医学.
根据产生源: 单通道 和 多通道 . 单声道音频/双声道音频/五通道环绕声音频.
信号表现 : 任意时刻都可以确定信号取值的确定信号. 任意时刻取值不能确定的不确定信号.
自变量可以为: 时间 频率 空间 可以有一维 (时间与频率) 二维 (黑白图像信号的x,y坐标) 黑白视频信号的 x,y,t . 彩色视频信号的红绿蓝三原色三个三微信号组成的三通道信号.
还有其他划分方法,例如周期信号与非周期信号,功率信号与能量信号等。
声音就是先由物体振动产生的声波,声波再通过介质(空气或固体、液体)传播并能被人或动物听觉器官所感知的波动现象。最初发出振动的物体叫声源。振动引起的气压变化的大小称为声压,声压是决定声强即响度的主要因素。气压具有一定的频率,即声波每秒变化的次数,以Hz(赫兹)表示。它决定了声音的高低。声压的测量单位是帕(斯卡)
16Hz至20000Hz的声波,低于16Hz的叫次声波,高于20000Hz的叫超声波。
人耳对2000Hz至5000HZ的声波感受力最强,但人说话声音频率一般在300Hz至700HZ。
音频信号、Audio Signal
音频信号是指声波的频率、幅度变化信息载体。
信号分类
连续时间连续幅值信号是指在以时间为自变量的一维信号中,除个别不连续点外,信号在所讨论的时间段内的任意时间点都有确定的振幅值,且振幅值在取值范围内也有任意种取值。该信号也叫模拟信号。
连续时间离散幅值信号是指在以时间为自变量的一维信号中,除个别不连续点外,信号在所讨论的时间段内的任意时间点都有确定的振幅值,但振幅值在取值范围内只有特定种取值。该信号也叫量化信号。
连续时间连续幅值信号和连续时间离散幅值信号都称为连续时间信号。
例如:信号 的时间和幅值都是连续的,即为模拟信号。
离散时间连续幅值信号是指在以时间为自变量的一维信号中,只在离散时间瞬间才有幅值,在其它时间没有,但振幅值在取值范围内有任意种取值。该信号也叫采样信号、抽样信号、取样信号、脉冲信号。
散时间离散幅值信号是指在以时间为自变量的一维信号中,只在离散时间瞬间才有幅值,在其它时间没有,且振幅值在取值范围内也只有特定种取值。该信号也叫数字信号。
离散时间连续幅值信号和离散时间离散幅值信号都称为离散时间信号,也常称为序列。
确定信号是指能用确定的数学函数表示的信号,任意时刻都有确定的幅值,预先可以知道该信号的变化规律。
随机信号是指不能数学函数表示的信号,不能预先可以知道该信号的变化规律。
周期信号是指按照一定的时间间隔周而复始,并且无始无终的信号。
他们的表达式可以写作:
,
(任意整数)
其中
称为
的周期,而满足关系式的最小
值则称为是信号的基本周期。
连续时间信号和离散时间信号与周期信号和非周期信号彼此包含,即连续时间信号和离散时间信号中有周期信号和非周期信号,同理,周期信号和非周期信号中也包含连续时间信号和离散时间信号。
模拟信号是指用连续变化的物理量所表达的信息,其信号的幅度,或频率,或相位随时间作连续变化,如温度、湿度、压力、长度、电流、电压等等,我们通常又把模拟信号称为连续信号,它在一定的时间范围内可以有无限多个不同的取值。而数字信号是指在取值上是离散的、不连续的信号。
数字信号处理利用计算机的信号处理设备,采用数值计算的方法对信号进行处理的一门学科,包括滤波、变换、压缩、扩展、增强、复原、估计、识别、分析、综合等加工处理,已达到提取有用信息、便于应用的目的。
在数字信号处理领域,量化是指将信号的连续取值(或者大量可能的离散取值)近似为有限多个(或较少的)离散值的过程。量化主要应用于从连续信号到数字信号的转换中。连续信号经过采样成为离散信号,离散信号经过量化即成为数字信号。注意离散信号通常情况下并不需要经过量化的过程,但可能在值域上并不离散,还是需要经过量化的过程。信号的采样和量化通常都是由模数转换器实现的。
模拟信号转换成数字信号的过程叫做模数转换,简写成A/D,完成这种功能的电路叫做模数转换器,简称ADC。模数转换器的框图如图所示:
输入端输入的模拟信号,经采样、保持、量化和编码四个过程的处理,转换成对应的二进制数码输出。采样就是利用模拟开关将连续变化的模拟量变成离散的数字量,如上图中波形③所示。由于经采样后形成的数字量宽度较窄,经过保持电路可将窄脉冲展宽,形成梯形波,如波形④所示。量化就是将阶梯形模拟信号中各个值转化为某个最小单位的整数倍,便于用数字量来表示。编码就是将量化的结果(即整数倍值)用二进制数码来表示。这个过程就实现了模数转换。目前集成模数转换器种类较多,有8位、10位模数转换器。
采样频率、采样率、Sampling Frequency、Sampling Rate
采样频率就是每秒对音频模拟信号的采样次数,常见音频采样频率有8000Hz、16000Hz、22050Hz、32000Hz、44100Hz、48000Hz、96000Hz等。
采样频率越高,音频数字信号就越接近之前的音频模拟信号,音质也就越好,硬件成本也就越高,存储空间占用也就越大。
如果采样位数为8位,则有256个级别的采样数据,其动态范围为20×log(256)分贝,大约是48db。
采样数据帧、Sampling Data Frame
采样数据帧就是将多个连续的采样数据分为一组,主要是为了便于处理采样数据。
采样数据帧一般是以时间为单位进行分组,例如:将8000hz的音频数据流按20ms为一个单位划分为一帧,则每帧包含160个采样数据。
音频数据帧的大小计算公式:(采样频率×采样位数×声道数×时间)/ 8
目前我们Dueros 采样频率 16k 采样位数 16位 声道 1 那么20ms 的数据帧的大小为
16000 * 16 * 1 * 0.0.2 / 8 = 640字节
1. 采样数据帧长度、Sampling Data Frame Size
采样数据帧长度就是每个采样数据帧包含多少个采样数据。
采样数据帧的长度计算公式:采样频率×时间 16k * 0.02 = 320个数据
1. 脉冲编码调制、脉码调制、Pulse Code Modulation、PCM
我们采样到的最原始的音频数字信号的那一串数列就是脉冲编码调制格式的,也叫PCM格式。具体格式如下:
声道数 |
采样位数 |
字节1 |
字节2 |
字节3 |
字节4 |
字节5 |
字节6 |
字节7 |
字节8 |
单声道 |
8位 |
FRONT 前声道 采样数据 |
FRONT 前声道 采样数据 |
FRONT 前声道 采样数据 |
FRONT 前声道 采样数据 |
FRONT 前声道 采样数据 |
FRONT 前声道 采样数据 |
FRONT 前声道 采样数据 |
FRONT 前声道 采样数据 |
单声道 |
16位 |
FRONT 前声道 采样数据 |
FRONT 前声道 采样数据 |
FRONT 前声道 采样数据 |
FRONT 前声道 采样数据 |
||||
双声道 |
8位 |
LEFT 左声道 采样数据 |
RIGHT 右声道 采样数据 |
LEFT 左声道 采样数据 |
RIGHT 右声道 采样数据 |
LEFT 左声道 采样数据 |
RIGHT 右声道 采样数据 |
LEFT 左声道 采样数据 |
RIGHT 右声道 采样数据 |
双声道 |
16位 |
LEFT 左声道 采样数据 |
RIGHT 右声道 采样数据 |
LEFT 左声道 采样数据 |
RIGHT 右声道 采样数据 |
1 网络传输、Transport
发送方依次将各个音频数据帧通过网络发送给通话的对方。由于语音对讲对实时性要求比较高,所以低延迟和平稳连续是非常重要的,这样语音对讲才能顺畅。
网络传输必须要注意的问题就是,一个是乱序到达,一个是丢包。
一般常用的网络传输协议是实时传输协议(Real-time Transport Protocol、RTP),也有用TCP协议的
音频数字信号还原、回放、播放、Playback、Play
音频数字信号还原是指,将得到的PCM格式音频数据帧提交给声卡,声卡会把音频数字信号再转换为音频模拟信号,并输出到扬声器,扬声器就会根据音频模拟信号而振动起来,然后就会产生声波,最后我们就能听还原后的声音了。
音频数字信号处理、Audio Digital Signal Processing、Audio DSP
仅仅只是实现网络电话,那就只需要进行采样、传输、播放就好了,但是实际使用过程中我们会发现语音对讲中的各种问题会严重影响我们的对讲体验,正是有很多现实的因素给我们带来了众多挑战,使得网络电话系统的实现不是那么简单,其中涉及到很多专业技术。
我觉得"效果良好"的网络电话系统应该达到如下几点:
语音延迟低,实时感很强。
声音流畅,没有卡顿的感觉。
音量适中,没有忽大忽小的感觉。
环境背景噪音要小。
没有声学回音。
网络流量要小。
编码、Encode
简介
如果我们将采样到的PCM格式音频数据直接发送或者存储,那么每秒需要占用的带宽就是16000Hz×16bit=31.25 KB/S,这就要占用很大的带宽了。那么我们就需要对PCM格式进行压缩了,将压缩后的音频数据再进行发送或者存储,当需要播放的时候,再解压缩成PCM格式进行播放。我们把音频数据压缩的过程称之为编码,把音频数据解压缩的过程称之为解码。
音频编码分为两大类,一类是无损压缩,一类是有损压缩。无损压缩是指编码前的PCM格式音频数据和解码后的PCM格式音频数据是完全一样的,音频信号没有任何的损失。有损压缩是指解码后的PCM格式音频数据只是近似于编码前的PCM格式音频数据,并不完全一样。所以无损压缩的音质是最好的,压缩率也是最低的,有损压缩的音质会受压缩率的高低影响好坏。
音频编码算法一般有三种方式:固定比特率、可变比特率、平均比特率。不同的编码方式的区别主要在于压缩率不一样。
目前常用的无损音频编码格式有:AAL、APE、FLAC、等等,
有损音频编码格式有:G.729、iLBC、AAC、Speex、Opus、等等。
固定比特率、静态比特率、固定码率、Constant Bit Rate、CBR
CBR编码指的是编码器每秒钟的输出码数据量(或者解码器的输入码率)应该是固定制(常数)。
。对于音频压缩来说,比如MP3,比特率是最重要的因素,它用来表示每秒钟的音频数据占用了多少个比特,这个值越高,音质就越好。CBR使用固定比特率编码音频,一首MP3从头至尾为某固定值,如128 kbps进行编码。
可变比特率、动态比特率、可变码率、Variable Bit Rate、VBR Vorbis
可变比特率可以随着图像的复杂程度的不同而变化,因此其编码效率比较高,快速运动画面的马赛克就很少。编码软件在压缩时,根据视频数据,即时确定使用什么比特率,这样既保证了质量,又兼顾了文件大小。使用这种方式时,编码程序可以选择从最差音视频质量(一般此时压缩比最高)到最好音视频质量(一般此时压缩比最低)之间的各种视频质量。在视频文件编码的时候,编码程序会尝试保持所选定的整个文件的品质,对视频文件的不同部分选择不同的比特率来编码。例如,使用MP3格式的音频编解码器,音频文件可以以8~320kbps的可变码率进行压缩,得到相对小的文件来节约存储空间。MP3格式的文件格式是*.mp3。
当形容编解码器的时候,VBR编码指的是编码器的输出码率(或者解码器的输入码率)可以根据编码器的输入源信号的复杂度自适应的调整,目的是达到保持输出质量保持不变而不是保持输出码率保持不变。VBR适用于存储(不太适用于流式传输),可以更好的利用有限的存储空间:用比较多的码字对复杂度高的段进行编码,用比较少的码字对复杂度低的段进行编码。
像Vorbis这样的编解码器和几乎所有的视频编解码器内在的都是VBR的。*.mp3文件也可以以VBR的方式进行编码。
例如:有一段采样频率8000Hz的PCM格式音频数据,一共10帧,每帧20ms,可能其中5帧声音变化较大,其他5帧声音变化较小,那么用VBR来编码时,就会把声音变化较大的那5帧用较高的采样频率编码,编码后体积也较大,另外那声音变化较小的那5帧就用较低的采样频率编码,编码后体积也较小。
平均比特率、平衡比特率、平均码率、Average Bitrate Rate、ABR
平均比特率是VBR的一种插值参数。它针对CBR不佳的文件体积比和VBR生成文件大小不定的特点独创了这种编码模式。ABR在指定的文件大小内,例如以每50帧(30帧约1秒)为一段,低频和不敏感频率使用相对低的流量,高频和大动态表现时使用高流量,可以做为VBR和CBR的一种折衷选择
当对方接收到编码后的音频数据帧后,需要对其进行解码,以恢复成为可供声卡直接播放的PCM格式音频数据。如果是直接发送PCM格式的音频数据帧,对方就不需要解码,直接就可以播放。
通常情况下没有解码的音频数据是不能播放的,但也有些操作系统可以直接播放某些常用编码格式的音频数据,其实就是操作系统帮我们做了解码。
声学回音消除、Acoustic Echo Cancellation、AEC
大家在语音通话时都会用到电脑的扬声器外放功能,或者手机的免提功能。这是一个很方便的功能,但这个小小的功能曾经音频技术提出了很大挑战。当使用外放功能时,扬声器播放的声音会被麦克风再次采集,然后在传给对方时,对方就会听到自己的声音,俗称声学回音。这个声学回音在被循环很多次之后,还有可能会变成啸叫。所以,我们需要将这个声学回音消除掉。
声学回音消除必须注意的问题:
做声学回音消除时,首先要尽量保证音频输入帧和音频输出帧是同步的,时间差越小,声学回音消除效果就越好,时间差越大,声学回音消除效果也就越差,因为声学回音消除算法是需要同时传入音频输入帧和音频输出帧的。
声学回音消除一般都是在一个音频输入数据帧刚采样完毕和一个音频输出数据帧刚播放完毕后,就立刻做,不要在做了其他处理之后再做,这样会降低效果。
声学回音必须在远端语音出现之后,因为必须是先播放出来,然后麦克风才能采样到,否则声学回音消除算法会认为这是近端语音,而不是声学回音。
声学回音与远端语音会有一段时间间隔,有些声学回音消除算法可以自动适应这个时间间隔,但有些声学回音消除算法无法自动适应这个时间间隔,需要手动设置,这个时间间隔设置是否精准,将直接导致声学回音消除效果的好坏,设置不好可能会导致声学回音无法消除,或者近端语音被误消除掉。
声学回音一般都比远端语音的音量要小,但也有些扬声器的音量较大,会将远端语音的音量放大很多,导致声学回音的音量要比远端语音的音量大很多,这种情况下有些声学回音消除算法可能无法正确识别声学回音,这就需要更换较好的声学回音消除算法。
如果说话双方同时说话,那么声学回音与近端语音就会重叠,这种情况下有些声学回音消除算法可能无法正确识别声学回音,这就需要更换较好的声学回音消除算法。
测试声学回音消除算法的时候,如果对讲的两个设备在同一个房间,那么两个设备会相互采样到对方扬声器播放出来的声音,会导致产生啸叫,所以测试时必须要在不同的房间。
声学回音消除算法一般有这几种:时域算法,频域算法,子带算法。
声学回音消除算法分为两大类:基于DSP等实时平台的回音消除,基于Windows等非实时平台的回音消除。两者的技术难度和重点是不一样的。
各个操作系统是否自带声学回音消除功能:
Windows、UNIX、Linux操作系统没有自带声学回音消除功能,需要调用第三方库实现。
Android操作系统虽然自带有声学回音消除功能,但是需要设备厂商自己实现,由于很多厂商都实现不了该功能,所以大部分的手机都不自带该功能,仍然需要调用第三方库实现。
IOS操作系统自带有声学回音消除功能,而且效果非常好,可以放心调用,当然也可以调用第三方库实现。
音频输入输出数据帧同步的方法
第一种:调用第三方修改的jni层的Android版的PortAudio的OpenSLES库实现同步,本方法可以完美同步,但是有些手机对OpenSLES库支持并不好,导致播放或录音有很高的延迟,所以本方法兼容性较差。下载地址:https://github.com/Gundersanne/portaudio_opensles
第二种:在单线程中,先初始化AudioRecord类和AudioTrack类,并先调用AudioRecord.startRecording()函数再调用AudioTrack.play()函数,然后进入循环体,先调用AudioTrack.write()函数阻塞播放音频输出数据帧,然后再调用AudioRecord.read()函数获取音频输入数据帧,循环体完毕。理论上这样做出来的音频输入输出数据帧就是同步的,但是由于Android操作系统Java代码的函数调用是有延迟的,不同的手机延迟会不一样,最终就会导致大部分的手机不能同步,所以本方法兼容性和稳定性都很差。
第三种:先在主线程中,初始化AudioRecord类和AudioTrack类,并先调用AudioRecord.startRecording()函数再调用AudioTrack.play()函数,然后再启动两个线程,一个音频输入线程负责调用AudioRecord.read()函数获取音频输入数据帧,并依次存放到已录音的音频输入数据帧链表,一个音频输出线程负责调用AudioTrack.write()函数播放音频输出数据帧,并依次存放到已播放的音频输出数据帧链表。先启动音频输入线程,再启动音频输出线程,这样已录音的音频输入数据帧链表和已播放的音频输出数据帧链表里的数据帧就是一一对应同步的,本方法在大部分情况下可以差不多完美同步,但是极少数情况下如果系统出现突然卡顿,就可能会不同步了,所以本方法兼容性和稳定性都很好。
Android操作系统:
第一种:调用第三方修改的jni层的Android版的PortAudio的OpenSLES库实现同步,本方法可以完美同步,但是有些手机对OpenSLES库支持并不好,导致播放或录音有很高的延迟,所以本方法兼容性较差。下载地址:https://github.com/Gundersanne/portaudio_opensles
第二种:在单线程中,先初始化AudioRecord类和AudioTrack类,并先调用AudioRecord.startRecording()函数再调用AudioTrack.play()函数,然后进入循环体,先调用AudioTrack.write()函数阻塞播放音频输出数据帧,然后再调用AudioRecord.read()函数获取音频输入数据帧,循环体完毕。理论上这样做出来的音频输入输出数据帧就是同步的,但是由于Android操作系统Java代码的函数调用是有延迟的,不同的手机延迟会不一样,最终就会导致大部分的手机不能同步,所以本方法兼容性和稳定性都很差。
第三种:先在主线程中,初始化AudioRecord类和AudioTrack类,并先调用AudioRecord.startRecording()函数再调用AudioTrack.play()函数,然后再启动两个线程,一个音频输入线程负责调用AudioRecord.read()函数获取音频输入数据帧,并依次存放到已录音的音频输入数据帧链表,一个音频输出线程负责调用AudioTrack.write()函数播放音频输出数据帧,并依次存放到已播放的音频输出数据帧链表。先启动音频输入线程,再启动音频输出线程,这样已录音的音频输入数据帧链表和已播放的音频输出数据帧链表里的数据帧就是一一对应同步的,本方法在大部分情况下可以差不多完美同步,但是极少数情况下如果系统出现突然卡顿,就可能会不同步了,所以本方法兼容性和稳定性都很好。
第四种:本人后来发现,有些手机在调用AudioRecord.startRecording()函数后,居然并没有真正开始录音,而是要在调用AudioRecord.read()函数过程中时才会真正开始,那么这样就有可能会导致播放线程走在前面了,所以在第三种方法中,改为在音频输入线程调用一次AudioRecord.read()函数并丢弃掉后,再在音频输入线程中启动音频输出线程。这样本方法在绝大部分情况下可以差不多完美同步。
第五种:本人后来又发现,有些手机在调用AudioRecord.read()函数后,居然并没有真正开始录音,而是要在调用好几次AudioRecord.read()函数后才会真正开始,那么这样就有可能会导致播放线程走在前面了,所以在第四种方法中,改为在音频输入线程调用多次AudioRecord.read()函数,直到读取到的音频数据不是全0了并全部丢弃掉后,再在音频输入线程中启动音频输出线程。这样本方法在所有手机上可以差不多完美同步。
二、回声消除原理
从通讯回音产生的原因看,可以分为声学回音(Acoustic Echo)和线路回音(Line Echo),相应的回声消除技术就叫声学回声消除(Acoustic Echo Cancellation,AEC)和线路回声消除(Line Echo Cancellation, LEC)。声学回音是由于在免提或者会议应用中,扬声器的声音多次反馈到麦克风引起的(比较好理解);线路回音是由于物理电子线路的二四线匹配耦合引起的(比较难理解)。
1. 由于空间声学反射产生的声学回音(见下图):
图中的男子说话,语音信号(speech1)传到女士所在的房间,由于空间的反射,形成回音speech1(Echo)重新从麦克风输入,同时叠加了女士的语音信号(speech2)。此时男子将会听到女士的声音叠加了自己的声音,影响了正常的通话质量。此时在女士所在房间应用回音抵消模块,可以抵消掉男子的回音,让男子只听到女士的声音。