一、整体思路
时间点 | A | B | C | D |
发送 | 30 | 60 | 90 | 120 |
接收 | 40 | 90 | 100 | 130 |
延时 | null | 50 | 10 | 30 |
不像视频一帧数据那么大,音频一帧数据包都比较小,UDP的1500个字节完全可以装满一帧。所以音频在发送端的发送时间间隔是按照固定的打包时长节奏发送的。
以上图30ms打包时长为例,ABCD四个报文的发送时间间隔都是30ms。若没有网络影响,接收端的包间间隔也是30ms,音频播放清晰流畅。
但是网络传输各种不可控因素会导致音频报文到达接收端存在丢包、乱序、抖动等异常。接收端若不特殊处理,用户体验会很差。
对于丢包异常传输层可以使用FEC、NACK、交织编码修复。编解码层可以使用PLC(Packet Loss Compensation)等算法修复。
对于乱序、抖动异常,需要使用JitterBuffer做平滑。JitterBuffer实现机制有静态JB和动态JB两种。
静态JB控制算法:缓冲区大小固定,容易实现,网络抖动大时,丢包率高,抖动小时,延迟大。
动态JB控制算法:计算目前最大抖动,调整缓冲区大小,实现复杂,网络抖动大时,丢包率低,抖动小时,延迟小。
DelayManager、BufferLevelFilter模块就是计算动态JB的抖动值。以配置合理的缓冲空间,保证音频平稳播放。这里首先介绍DelayManager模块实现原理。
二、实现原理
DelayManager模块的核心思想是计算target_level_这个参数,通过这个参数在DelayManager::BufferLimits函数中,计算最大最小缓存BUF。
target_level_参数由两个因素决定:IATVector直方图、DelayPeakDetector检测kMaxPeakPeriodMs秒周期内抖动的峰值。
1、IAT直方图介绍
IATVector直方图(Histogram of inter-arrival times)由65成成员变量组成,每个IATVector的成员变量是该延时出现的概率。
IAT(inter arrival times) | 出现概率 |
0 | 72887611 |
1 | 999495224 |
2 | 529939 |
3 | 0 |
4 | 0 |
5 | 0 |
6 | 0 |
7 | 75384 |
。。。。。。 | 0 |
63 | 0 |
64 | 0 |
IATVector直方图里面保存的概率是以1<<30为分母的分子部分。
-
1)iat_packet计算
iat_packet=实际包间间隔 / 打包时长
函数:DelayManager::Update
packet_iat_stopwatch_->ElapsedMs():每收到一包,启动一次定时器,用来计算两次收包实际时间间隔。
packet_len_ms:该报文的打包时长,单位ms。
其中打包时长是根据RTP报文时间戳计算的。我们以G.711A编码10ms打包格式为例,一秒钟的采样率是8000HZ。一包报文的时间戳间隔计算公式为:(8000HZ*10ms打包时长)/1000ms=80个点。
同理,报文的打包时长也可以通过时间戳换算出来。计算公式为packet_len_ms=(1000ms*两包时间戳差值)/采样率。
-
2)更新概率参数
DelayManager::UpdateHistogram函数会根据计算的iat_packet,将该iat_packet插入IATVector直方图对应数组下标内。并更新该直方图的数据下标下概率参数。一共有四步操作:
- 1、用遗忘因子,对历史数据的出现概率进行遗忘。
- 2、增大本次计算到的IAT的概率值。
- 3、更新遗忘因子f,使f为递增趋势。即通话时间越长,包间隔的概率分布越稳定。
- 4、调整本次计算到的IAT的概率,使整个IAT的概率分布之和近似为1。
调整方式为假设当前概率分布之和为tempSum,则:
这四步操作,都在函数DelayManager::UpdateHistogram中实现。
-
3)根据IATVector直方图计算target_level_
DelayManager::CalculateTargetLevel函数在每收到一包音频数据的时候,都会更新一次target_level_的值。
IATVector直方图的更新原理是,从IAT为0开始,累加出现的概率,当概率达到设定的kLimitProbability门限值时,配置target_level_为该直方图的数组下标。
2、DelayPeakDetector峰值检测算法
IATVector直方图的做法的思想是参考从通话启动,到目前为止的平均延时值,但是实时音视频通话中,还要考虑短时延时波动的影响。所以webrtc里面也引入了DelayPeakDetector算法,检测kMaxPeakPeriodMs周期内的延时最大值。作为target_level_的参考值。
实现的原理是,每kMaxPeakPeriodMs秒内,检测IAT延时的异常峰值,若有异常峰值则target_level_参考该异常峰值配置。若没有,使用 IATVector直方图计算的值。
-
1)DelayPeakDetector::Update函数将IAT异常峰值入队
-
2)DelayPeakDetector::CheckPeakConditions判断该峰值是否达到上报条件
-
3)DelayPeakDetector::MaxPeakHeight获取检测周期内异常峰值
-
4)DelayManager::CalculateTargetLevel修订target_level_
至此,完成target_level_的计算。
三、参考
《WebRTC语音引擎中NetEQ技术的研究_吴江锐》