影 响 观 看 体 验 的 主 观 因 素 { 卡 顿 延 迟 马 赛 克 绿 屏 + 花 屏 爆 音 变 频 音 . . . 影响观看体验的主观因素 \begin{cases} 卡顿 \\ 延迟 \\ 马赛克 \\ 绿屏+花屏 \\ 爆音 \\ 变频音 \\ ... \end{cases} 影响观看体验的主观因素⎩⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎨⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎧卡顿延迟马赛克绿屏+花屏爆音变频音...
一般出现这种情况,我们就认为网络差。
网 络 差 的 具 体 表 现 { 抖 动 大 丢 包 高 网络差的具体表现 \begin{cases} 抖动大 \\ 丢包高 \\ \end{cases} 网络差的具体表现{抖动大丢包高
网络抖动大,往往是发生了拥塞,包在路由中的排队延时随着拥塞程度呈现波动变化。
丢包高,往往和网络模型相关。
弱 网 网 络 模 型 { 带 宽 受 限 型 { 固 定 带 宽 拥 塞 信 道 差 错 型 { w i f i 移 动 网 络 设 置 主 动 丢 包 策 略 网 络 弱网网络模型 \begin{cases} 带宽受限型 \begin{cases} 固定带宽 \\ 拥塞 \end{cases} \\ 信道差错型 \begin{cases} wifi \\ 移动网络 \\ 设置主动丢包策略网络 \end{cases} \\ \end{cases} 弱网网络模型⎩⎪⎪⎪⎪⎪⎪⎨⎪⎪⎪⎪⎪⎪⎧带宽受限型{固定带宽拥塞信道差错型⎩⎪⎨⎪⎧wifi移动网络设置主动丢包策略网络
这种网络的丢包率会随着网络过载的严重度增长。越是过载,丢包越严重。
对 策 { s i m u l c a s t s v c b u f f e r 对策 \begin{cases} simulcast \\ svc \\ buffer \\ \end{cases} 对策⎩⎪⎨⎪⎧simulcastsvcbuffer
在带宽允许范围内,这种网络的丢包率是信道的一个属性,与网络流量无关。
对 策 { n a c k f e c b u f f e r 对策 \begin{cases} nack \\ fec \\ buffer \\ \end{cases} 对策⎩⎪⎨⎪⎧nackfecbuffer
当接收端检测到丢包,他会向发送端发出nack,请求重传丢失的数据包。这就意味着nack对rtt十分敏感。在rtt较大的情况下,nack能起到的作用与jitter buffer的策略息息相关,最差的情况下,nack的作用微乎其微。
class FrameBuffer{
VCMJitterEstimator* const jitter_estimator_ ;
std::map frames_;
int num_frames_history_
int num_frames_buffered_
FrameMap::iterator last_decoded_frame_it_;
FrameMap::iterator last_continuous_frame_it_;
};
/*
num_frames_history_:
Decoded frame holes[without video frame] that remains in frames_ that can be used as a reference by incoming frames to know whether they can be decoded [e.g.:their dependencies can be found in frames_].
num_frames_buffered_:
Holes in frames_ that have a video frame reside in.
*/
InsertFrame:
NextFrame:
在webrtc中,jitter buffer攒齐一个可以解码的帧之后,会将其送去渲染,它会等待一个std::max(jitter delay, av sync delay),然后被解码显示。解码之后的帧的序列号会反馈到数据包的接收模块,接收模块接着就会清除jitter buffer中的"old stuff"。所以,如果rtt很大,nack反馈触发的重传会大量的失效,因为默认情况下,jitter buffer耐不住性子等待重传的包,所以你就看到了卡顿和跳帧。
从这里可以知道,如果不改变接收端jitter buffer的策略,单独改变发送端的缓存队列大小是起不到多大作用的,一般保证100ms的队列大小就行了。如果网络的jitter较大,可以适当的增大发动端的缓存队列大小。
webrtc的拥塞控制算法基于GCC,它的特点是带宽估计由两个大的算法模块组成:
G C C { d e l a y − b a s e d l o s s − b a s e d GCC \begin{cases} delay-based \\ loss-based \\ \end{cases} GCC{delay−basedloss−based
一个基于延迟模型,一个基于丢包模型,然后取一个最小的估算值。
这么看来,GCC算法对信道差错型网络很不友好,总是给它一个过低的带宽估计值。
上面提到的nack和gcc的问题,我们发现FEC可以很好的解决。
FEC,即前向纠错编码,利用亦或(xor)运算获得,可以调节冗余度和mask来应对不同程度以及不同模型的丢包[主要是随机丢包和突发的连续丢包]。
我们总是能够通过增大buffer来极大地改善卡顿情况,但它会带来延迟。可以考虑在不同的场景下使用它:
场 景 { 连 麦 互 动 低延迟,默认jitter buffer算法 无 互 动 观 看 修改默认jitter buffer算法,适当地增大buffer 场景 \begin{cases} 连麦互动 &\text{低延迟,默认jitter buffer算法}\\ 无互动观看 &\text{修改默认jitter buffer算法,适当地增大buffer} \\ \end{cases} 场景{连麦互动无互动观看低延迟,默认jitter buffer算法修改默认jitter buffer算法,适当地增大buffer
点我