NetEQ是WebRTC的音频处理模块,主要包含MCU和DSP两大处理单元,包含自适应缓冲区、语音解码器、抖动控制和丢包隐藏模块及播放四大部分。MCU的主要作用的安排数据包的插入和控制数据包的输出。插入的关注点是插入的位置,输出的关注点是输出的时间。抖动消除的算法思路在MCU控制模块中得以体现。DSP模块主要负责对从MCU中提取PCM进行数字信号处理,包括解码,信号处理,数据输出等部分。丢包隐藏操作在DSP模块中完成。个人的理解,MCU和DSP其实就对应两个线程,MCU对应audio rtp数据网络读取线程,DSP对应audio rtp从缓冲区读取,解码并显示的线程。
一、自适应缓冲区(audio jitter buffer)
抖动是指接收端某个数据包到达间隔与平均数据包到达间隔之差。这个差值不管大于0还是小于0,均增大了端到端的丢包概率。抖动通常可以使用抖动缓冲区解决。在接收方开辟一个缓冲区,语音包首先进入缓冲区,随后再以稳定平滑的速率提取并播放。
二、丢包隐藏(Packet Loss Concealment, PLC)
分为基于发送端补偿和基于接收端补偿。发送端补偿就是FEC前向纠错和重传;接收端补偿是指错误隐藏算法。接收端补偿一般是指通过插值的技术得到与原来丢包相似的包,起到替代作用。
三、命令机制
分为以下几种情况:
1. 过去帧、当前帧都接收正确:normal模式
2. 仅当前帧发生丢包或延迟:PLC重建丢包帧
3. 连续多帧发生丢失:多次进入PLC单元,注意越靠后面丢失的帧,越难以精确重建补偿包,因此补偿增益应该逐帧递减,以避免引入更大失真。
4. 前一帧丢失、当前帧正常播放:说明上一帧是经过PLC产生的。
四、NetEQ四个缓冲区
packet_buffer_:抖动缓冲区
decoded_buffer_:解码缓冲区,最大长度5760(120ms @ 48KHz)
algorithm_buffer_:DSP算法缓冲区,就是一个AudioMultiVector对象
sync_buffer_:语音播放缓冲区,分为两块,一块是已经播放的数据,一块是未播放的数据,curPosition变量作为分界点。看下这个缓冲区多大,及内部结构。
end_timestamp_用于记录最后一个样本的时间戳,并报告给MCU。MCU根据packet_buffer_中的timestamp来决定是否能够继续取出音频包。
五、一点反思
5.1 关于代码
WebRTC代码目录是webrtc\modules\audio_coding\neteq\。网上找了很多文档,大部分都在说NetEQ的结构(包括本文),很少走读NetEQ代码。结构脉络还是比较清晰的,就是原始RTP数据包依次经过几个buffer,最终输出的过程。但是内部实现,比如decision_logic, delay_manager_, expand.cc, merge.cc等,需要较强的理论基础才能分析清楚。
5.2 关于移植
如果不修改NetEQ核心逻辑,只是添加读写线程。个人认为移植还算方便。