关于运维:WebRTC-音频抗弱网技术下

3次阅读

共计 8971 个字符,预计需要花费 23 分钟才能阅读完成。

上周,咱们针对音频弱网反抗技术中的前向纠错技术、后向纠错技术及 OPUS 编解码抗弱网个性进行了分享。文本分享 WebRTC 应用的抗抖动模块 NetEQ。关注【融云寰球互联网通信云】理解更多

抖动的定义和打消原理

抖动是指因为网络起因,达到接收端的数据在不同时间段,体现出的不平衡;或者说接收端接管数据包的工夫距离有大有小。

WebRTC 通过包达到工夫距离的变动来评估抖动,公式如下:

Ji 定义为时刻 i 时测量的抖动,E(T) 示意包达到工夫的距离均值,Ti 示意时刻 i 收到的包距上一次收包的工夫距离。

Ji > 0 阐明数据包提前到了,这样抖动缓存区数据将会呈现沉积,容易造成缓冲区数据溢出,导致端到端时间延迟增大;Ji < 0 阐明数据包晚到或失落,会增大延时;不论早到还是晚到,都可能造成丢包,减少时延。

NetEQ 通过测量包达到工夫距离,来预测包在网络中的传输工夫延时;依据收到的包但还未播放的缓冲语音数据的大小来评估抖动的大小。

原则上通过对网络延时的测量,以其最大延时来设置抖动缓冲区的大小,而后使每个包在网络中的延时加上该包在抖动缓冲区的延时之和放弃相等,这样能够打消抖动,就能够管制语音包从抖动缓冲区以一个绝对安稳的速度播放音频数据。

下图 [1] 阐明了抖动打消的核心思想:

(抖动打消的外围思路)

A、B、C、D 包在发送端别离以 30ms 距离发送,即别离在 30ms、60ms、90ms、120ms 处发送;接收端接管到这些包对应的工夫为 40ms、90ms、100ms、130ms;这样它们在网络中的延时别离是 10ms、30ms、10ms、10ms;包达到的距离别离为 50ms、10ms、30ms,即抖动。

因而能够使包 A、C、D 在抖动缓存中的延时 20ms 再播放,即 A、B、C、D 的播放工夫为 60ms、90ms、120ms、150ms,这样能够放弃一个安稳的距离进行播放。

NetEQ 通过估算网络传输延时,依据网络传输延时 95% 分位来调整抖动缓冲区;这使得 NetEQ 在打消抖动缓冲影响时,兼顾最小延时。

下图 [2] 是官网对 NetEQ 和其它技术在打消抖动带来的延时比照,能够看出 NetEQ 在打消抖动时,能够放弃很低的工夫延时。

(NetEQ 与其它技术打消抖动延时比照)


NetEQ 及其相干模块

下图 [1] 概要形容了 WebRTC 的语音引擎架构。红色区域为 NetEQ 局部,能够看出 NetEQ 位于接收端,蕴含了 jitter buffer 和解码器、PLC 等相干模块。接收端从网络收到语音包后,语音包将先进入 NetEQ 模块进行抖动打消、丢包暗藏、解码等操作,最初将音频数据输入到声卡播放。

(WebRTC 的语音引擎架构图)

NetEQ 蕴含的模块见下图[1]:

(NetEQ 模块)

NetEQ 外围模块有 MCU 模块 DSP 模块,MCU 模块负责往 jitter buffer 缓存中插入数据和取数据,以及给 DSP 的操作;DSP 模块负责语音信息号的解决,包含解码、减速、加速、交融、PLC 等。

同时 MCU 模块从 jitter buffer 中取包受到 DSP 模块相干反馈影响。
MCU 模块 包含音频包进入到 buffer,音频包从 buffer 中取出,通过语音包达到距离评估网络传输工夫延时,以及对 DSP 模块执行何种操作(减速、加速、PLC、merge)等。

DSP 模块 包含解码,对解码后的语音 PCM 数据进行相干操作,评估网络抖动 level,向 play buffer 传递可播放的数据等等。上面详细分析 MCU 和 DSP 各相干模块。

MCU

将收到的包插入 packet_buffer_
从网络收到音频包后,将其插入到抖动缓存 packet_buffer_中,最多缓存 200 个包;当缓存满了,会刷新缓存中所有的包,同时该缓存最多缓存近 5 秒的音频数据,太早的会被定时革除。

若收到的包是 red 包,会将 red 包中的每个独⽴包解析进去存入到缓存队列中,包在缓存队列中依照 timestamp 的升序进行存储,即最近的音频包存储在队列前面,老的包存储在队列后面。

收到音频包后,还会更新 NackTracker 模块,该模块次要是通过包的序列号来判断是否存在丢包,若存在丢包且重传申请开启,须要向发送端发动 nack 申请,申请发送端重发失落音频包。

估算网络传输延时

在将包插入到抖动缓存中时,依据包达到工夫距离对网络延时进行估算。这里将 WebRTC 中依据包达到工夫距离来计算网络延时,WebRTC 计算音频网络延时,次要思考如下几点:

统计音频包达到工夫距离,取其 95% 分为作为网络时延预计。

以上公式通过计算以后包和上一个包的时间差,以及 seqnum 的差值,来计算每个 seq 包占有的工夫戳范畴,即 packet_per_time,而后通过以后包和上一个包收包距离 iat_ms,来计算收包工夫距离延时,用包的个数来度量。

当失常包达到时 iat = 1,iat = 0 示意提前到了,iat = 2,示意延时一个包,最终用包个数来掂量延迟时间。

每算出一个 iat 后,会将其插入到对应的直方图,直方图记录 0-64 个包,即记录 0-64 个包的提早概率分布状况。所有提早概率和为 1。

计算出以后包的达到距离 iat,将其插入到直方图,并更新直方图每个提早的概率,每个提早散布乘以一个忘记因子 f,f 小于 1,更新过程如下:

下面公式的意义是保障每次计算出一个包达到距离提早后,对应减少其概率,同时对其它延时散布的概率进行忘记,使整个和放弃为 1。最初取其 95% 分为的提早作为指标延时,即有 95% 的提早都小于这个指标延时。

统计包达到工夫距离最大峰值

统计多个包达到距离峰值,最多 8 个,在肯定状况下,以峰值作为网络延时预计。每次计算到包达到工夫距离 iat 和按 95% 分位计算到的指标延时(记为 target_level)后,来判断峰值。

认为该 iat 是⼀个延时峰值的条件是:

iat > target_level + threshold, 或 iat > 2 * target_level,这里的 threshold 为 3
援用
且距上次峰值工夫距离小于阈值 5s

当判断该 iat 为延时峰值时,将其增加到峰值容器中,峰值容器中每个元素记录两个值,一个是峰值 iat 值,另一个是以后峰值间隔上一次峰值的工夫距离(即为 period_ms);

当峰值容器超过了两个,且以后工夫间隔上一次发现峰值时已流逝的工夫(记为 eplase_time)小于峰值容器元素中记录的最大 period_ms 的两倍时,认为该峰值是无效的,须要从峰值容器取最大的 iat(记为 max_iat),则指标时延取值:

当 target_level 取值是 max_iat 时,该峰值的实践无效工夫可达到 40s 以上,此处存在优化空间。

最小延时限度

依据设置最低时延,调整指标延时预计,保障指标延时预计不低于最小时延;最小时延是音视频同步计算的进去的后果。指标延时小于该最小延时,会导致音视频不同步。

指标延时不能超过 0.75 * 最大抖动缓冲区大小

WebRTC 中默认最大抖动缓冲区为 200,所以指标延时为:

即 target_level 不大于 150 个包,也就是指标延时不大于 3s 延时。

从 packet_buffer_中取包

播放线程尝试每次获取 10ms 数据来播放,要是抖动缓冲中没有数据,则播放静音数据。

从 packet_buffer_ 中获取的数据首先须要通过解码器解码,而后再依据反馈的操作进行对应的 DSP 操作(减速、加速、丢包暗藏、PLC、交融等)。最初将 DSP 解决完的数据填入到 sync_buffer_ 中待扬声器播放,并从 sync_buffer_ 中取 10ms 音频数据进行播放。

计算抖动延时

依据抖动缓冲区 packet_buffer_ 和 sync_buffer_ 中未播放完的音频数据总延时 total_dealy,来更新计算抖动缓存延时 filtered_level

若通过加加速操作,须要从 filtered_level 中打消加加速操作后引入的延时变动,如下所示:

获取对应的操作

下图中的 packet_buffer_ 和 sync_buffer_ 中未播放的数据大小能够了解为抖动缓冲区大小,从图中可看出数据从 packet_buffer_ 取出后,经解码器解码、DSP 解决,最初进入 sync_buffer_中待播放。

low_limit = 3/4 *target_level
high_limit = max(target_level, low_limit + window_20ms


(抖动缓冲区)

但进行何种 DSP 操作解决呢?

NetEQ 将依据 packet_buffer_和 sync_buffer_中未播放的音频数据总延时(记为 total_delay),以及 sync_buffer_ 中最初待播放的音频数据的工夫(记为 endtimestamp),和 packet_buffer_首包的工夫(记为 avaibleTimestamp),以及 target_level 和 filtered_level 的关系,来综合判断接下来执行何种 DSP 操作。

上面将对 几种外围的 DSP 解决操作条件 进行简要阐明:

norml 操作

满足以下条件之一,将执行 normal 操作

  1. 若本来要做 expand 操作,然而 sync_buffer_ 待播放的数据量大于 10ms。
    援用
  2. 间断 expand 操作次数超过阈值。
    援用
    3. 以后帧和前一帧都失常达到,且 fitlered_level 在 low_limit 和 higth_limit 之间。
    援用
  3. 上一次操作是 PLC,以后帧失常,但以后帧来得太早,执行 normal 操作。
    援用
  4. 以后帧和前一帧都失常达到, 本来通过 filtered_level > high_limit 判断,要减速操作,然而 sync_buffer_ 待播放的音频数据大于小于 30ms。

expand 操作条件

以后数据包失落或者还未达到时,同时在 sync_buffer_ 待播放的音频数据小于 10ms 时,则满足上面 4 个条件中任何一个,都将执行 expand 操作。

  1. packet_buffer_ 没有可获取的音频数据。
    援用
    2. 上一次是 expand 操作,且以后 total_delay < 0.5* target_level。
    援用
  2. 上一次是 expand 操作,且以后包(即 availbeTimestamp – endtimestamp 大于肯定阈值)来的太早,同时以后 filtered_level 小于 target_level。
    援用
  3. 上一次包非 expand(减速、加速或 normal),且 availbeTimestamp – endtimestamp >0,即两头存在丢包。

减速操作

上一个包和以后包都失常达到,filtered_level 大于 hight_limit,且 sync_buffer_ 中待播放的数据量大于 30ms。

加速操作

上一个包和以后包都失常达到,filtered_level 小于 low_limit。

merge 操作

上一次为 expand 操作,以后包失常达到。

DSP

基音[3]

基音是指发浊音时声带振动所引起的周期性对应的信号根本谐波,基音周期等于声带振动频率的倒数。个别的声音都是由发音体收回的一系列频率、振幅各不相同的振动复合而成的。这些振动中有一个频率最低的振动,由它收回的音就是基音,其余为泛音。基音携带了大部分能量,决定了音高。

基音的周期提取,个别应用短时自相干函数,因为自相干函数个别在基于周期上体现出有极大值的特点。在 NetEQ 的 DSP 信号处理中,基音的提取是一个至关重要的步骤。

语音的拉伸[4]

对语音的拉伸变速,有时域办法和频域办法。时域办法 计算量绝对频域办法少,适宜 VoIP 这种场景;频域办法适宜频率强烈变动的场景,如音乐。

NetEQ 中对语音的拉伸(减速或加速)应用的是 WSOLA 算法,即通过波形类似叠加的办法来变速;该算法在拉伸语音时可能保障 变速不变调。同时该算法是时域算法,对语音有比拟好的成果,下图是其大抵原理和流程:

(WSOLA 算法原理)

WSOLA 算法大抵流程:

解码

从 packet_buffer_ 中获取数据,失常解码,解码数据存储到 decoded_buffer_ 中。

减速

NetEQ 中,当 sync_buffer_ 和 packet_buffer_ 中的待播放数据总延时沉积过多,且前一帧和以后帧都失常时,须要通过减速播放操作,来升高抖动缓冲区待播放的数据量,以达到升高时延的目标,否则容易导致抖动缓冲区溢出,呈现丢包。而减速是要求变速不变调的,WSOLA 算法通过寻找类似波形并对类似波形进行叠加来实现变速目标。

这里对 NetEQ 中的减速过程做简要形容:

⾸先做减速要求起码须要 30ms 数据,数据个别来源于从 decoder_buffer_, 当 decoded_buffer_中得的数据有余 30ms,须要从 sync_buffer_中借一部分数据,凑满 30ms。

30ms 数据对应 240 个样本,将这 240 个样本下采样到 110 个样本;将下采样 110 个样本分成两局部 seq1 和 seq2,seq2 为固定开端 50 个样本,即[60,110]; seq1 也为 50 个样本,滑动范畴[0,100],计算 seq1 和 seq2 的自相关性。

依据计算出来的自相关性后果,以抛物线拟合来找到自相关性峰值和地位,极大值呈现的地位,即为上图中的 offset,即 seq1 窗口向左滑动的间隔,所以基音周期 T = offset + 10。

在要减速的 30ms 样本中,取 15ms 和 15ms – T 这两个基音周期信号,别离记为 XY 计算这两个基音周期信号的匹配度。

当 best_correlation 大于 0.9 时,则执行将两个基音周期信号合并为⼀个基音周期信号,起到减速作用

减速完的数据,如下图的 output 将存储到 algorithm_buffer_中,要是之前因为 decoded_buffer_中的数据量不够,从 sync_buffer_中借了局部数据,则须要从 algorithm_buffer_中将借的数据 copu 回 sync_buffer_对应的地位(目标是保障音频的平滑过渡),同时将 algorithm_buffer_中剩下的数据 copy 到 sync_buffer_开端,如下图所示:


加速

当 NetEQ 抖动缓冲中待播放的数据延时程度小于指标延时上限时,阐明待播放的数据量小,为了达到播放端的最佳音质体验,须要将现有数据拉伸,适当减少播放数据量;这和减速是相同的操作,底层技术雷同。同样上面对其做简要剖析:

前 4 步和减速基本上是一样的,这里不再赘述

最初一步,是将 15ms – T 和 15ms 两个基音周期穿插突变合并的混合基音插入到 15ms 后一个周期前。达到减少一个基音周期数据的目标,以此来减少播放数据量,同时须要从算法缓冲区中将借的数据返还给 sync_buffer_。

具体如下图所示:


丢包弥补

以后包失落时,在 NetEQ 中会触发丢包弥补来预测失落的包;丢包弥补有两种形式,一种是通过编解码器来预测重构失落的包,另一种是通过 NetEQ 模块来预测重构失落的包;对应别离是 kModeCodecPlc 和 kModeExpand。

不论是何种模式,前提要求是 sync_buffer_ 中待播放的音频数据量小于以后申请要播放的数据量,能力执行该操作;丢包弥补通过最近的历史数据,来重构 PLC 相干参数,而后通过历史数据和 PLC 相干参数进行线性预测,复原失落的包,最初再叠加肯定的噪声。

当间断屡次 PLC 操作时,失真将会加大,所以屡次操作后,将会升高 PLC 语音能量值。

下图是 NetEQ expand 操作的外围步骤。

(构建 PLC 参数步骤,点击查看大图)


(构建 PLC 包,点击查看大图)

PLC 操作中,首要任务是计算基音周期,这里应用了 自相干计算 信号失真计算 两种形式来计算基音周期,可通过下图简要阐明。

A 为末端 60 个样本信号

B 为滑动窗口,窗口蕴含 60 个样本信号,窗口起始地位滑动范畴[0, 54]

通过计算 A 和 B 的自相关系数,失去 54 个自相干后果,对这 54 个自相干后果应用抛物线拟合找到三个最大值的地位 peak1_idx1、peak_idx2、peak_idx3 为三个自相关系数最大的值的地位

认为基音是周期信号,极值呈现的地位为周期上

故基音周期 T
T1 = peak_idx3 + 10
T2 = peak_idx2 + 10
T3 = peak_idx1 + 10


依据下面通过自相干及抛物线拟合找到的三个极值,失去了三个基音周期

取末端 20 个信号作为 A,滑动窗口 B 也是 20 个样本 (2.5ms),B 在距 A 一个基音周期前后 4 个样本范畴内(0.5ms) 滑动

故有三个窗口滑动范畴,计算三个范畴内的窗口 A 和窗口 B 的失真度

取最小失真度三个极值,这三个极值作为通过失真最小计算的基音周期 T’

1, T’2, T’3
最小失真的掂量是以 A 和 B 对应元素差值绝对值之和最小为根据的

在失去基于自相干计算出来的三个基⾳周期 T1,T2,T3 和基于失真度最小失去的三个基⾳周期 T’1,T’2,T’3

通过比拟这三对的 ratio = 自相值 / 失真度,当 ratio 最大时,则认为这对基音周期最佳

PLC 操作中,expand_vector0 和 expand_vector1 的计算细节如下图:


(从历史数据中结构 expand_vector0、expand_vector1)

结构 AR 滤波器参数,通过获取一组(7 个)自相干值,对这组自相干值通过 LevinsonDurbin 算法计算,预测出 AR 滤波器参数。

AR 滤波器是线性预测器,通过历史数据来预测以后数据;在构建 PLC 包时,通过对历史数据进行 AR 滤波,来预测失落的包信息。

下图是对这个过程的简要阐明:

AR 滤波器公式如下所示:

这里 k = 7;e(n)为预测值和理论值的误差;AR 滤波就是通过应用最近的历史数据来预测以后时刻数据;LevinsonDurbin 算法通过自相性值的计算来预测 ck,使得 e(n) 最小。

自相关性越大,阐明 e(n) 越小;

LevinsonbDurbin 算法通过应用自相关性值来预测 AR 滤波器参数,能够了解为使⽤ e(n)来预测。

交融

交融操作个别是上一帧失落了,但以后帧失常;

上一帧是通过预测生成的 PLC 包,和以后帧须要做平滑解决,避免两种连接呈现显著变动;

交融就是实现该性能,交融的组要过程有:

须要 202 个扩大样本信号,次要是向 sync_buffer_ 未播放的信号借用 sync_buffer_ 未播放的信号有余 202,通过生成足够 PLC 数据来凑满

通过扩大样本信号和输出信号,计算期它们的自相关性值,及通过抛物线拟合来获取基音周期

对 input 数据进行 Ramp 信号变换
对扩大信号和 input 信号局部段进行混合
从缓存算法取偿还借用的信号数据到 sync_buffer_
将算法缓冲区残余的平滑解决的信号追加到 sync_buffer_

下图对 NetEQ 中交融过程的简要阐明:


(基音周期和 mute_factor,点击查看大图)


(混合 expand 和 input 信号,点击查看大图)

normal

以后帧能够失常播放,也就是能够间接将这段信号送⼊到 sync_buffer_ 中, 然而因为上一帧可能是 expand 等,须要进行相干的平滑操作。

次要步骤如下:

将输出信号拷贝到算法缓冲区生成一段 PLC 数据包

依据背景噪声和输出语音信号的能量比值,计算 mute_factor

依据 mute_factor 对算法缓冲区数据依照能量从弱到强的趋势修改

将 expand 和算法缓冲区的头 1ms 音频数据进行平滑混合,后果存在算法缓冲区;

相干混合平滑公式如下:

将最终的算法缓冲区数据最加到 sync_buffer_ 后

下图对 normal 的操作流程做补充阐明:

(normal 操作流程,点击查看大图)

NetEQ 相干 buffer

NetEQ 为了打消抖动、解码音频数据、对解码数据进行 DSP 解决(加加速、PLC、交融、平滑数据),以及平滑播放等,应用了多个缓存 buffer,上面是对这些 buffer 的简要阐明:

packet_buffer_: 用来接管网络中收到的音频包数据,也可称为抖动缓存,会定时删除以后工夫 5 秒前的包,同时最多缓存 200 个包,即 4 秒 (这⾥以每个包 20ms 计算)。
援用
decoded_buffer_: 当播放线程每次获取音频数据来播放时,会依据指标延时和抖动缓存延时来判断是否须要从 packet_buffer_中获取音频数据进行解码,解码后的数据寄存到 decoded_buffer_中。最多可缓存 120ms 数据。

algorithm_buffer_: decoded_buffer_中的数据通过 DSP 解决后,将寄存到该缓存,个别每解决一次会清空一次。

sync_buffer_: 个别是从算法缓存拷贝过去的数据,是待播放的数据;sync_buffer_中有两个变量,一个是 next_index,示意以后播放的地位,next_index 前的数据表示曾经播放,前面的数据表示待播放;另一个是 endtimestamp,示意 sync_buffer_中最初一个待播放的数据,也就是最近的音频数据量。

该 buffer 可最多缓存 180ms 数据,是一个循环缓存;播放线程每次会从 sync_buffer_中取 10ms 数据进行播放。

对于何时从 packet_buffer_中取数据解码阐明:

个别状况下每次从 packet_buffer_中取 10ms 数据进行解码。

当要执行 expand 操作时,但 sync_buffer_中有 10ms 以上数据,不从 packet_buffer_中取数据解码。

当做减速操作时,若 sync_buffer_中有 30ms 以上数据,不从 packet_buffer_中取数据;或若 sync_buffer_中有 10ms 以上待播放数据,同时上次解码了 30ms 数据,则不从 packet_buffer_中获取。

当减速操作,若 sync_buffer_待播放数据小于 20ms,同时上次解码的数据小于 30ms,从 packet_buffer_中获取 20ms 数据待解码。

当要做加速操作时,若 sync_buffer_中待播放的数据大于 30ms;或待播放的数据小于 10ms,但上一次解码的数据多余 30ms,则不从 packet_buffer_中获取数据。

当要做加速操作,sycn_buffer_中待播放的数据量小于 20ms,且上次解码的数据量少于 30ms,获取 20ms 数据进行解码。


NetEQ 能很好地跟踪网络抖动,同时在打消抖动时保障延时尽量小,对音频体验晋升显著;联合上一篇对于弱网反抗的一些技术,可显著晋升音频在弱网环境下的体验。

参考资料:

正文完
 0