NackModule
一个包的最大请求次数是kMaxNackRetries(10)次,最大请求时间是10*rtt,在这个时间内还没有获取到丢失的包则不再请求
对外提供的接口如下,源码
const int kDefaultRttMs = 100;
const int kMaxNackRetries = 10;
const int kProcessFrequency = 50;
const int kProcessIntervalMs = 1000 / kProcessFrequency;
int OnReceivedPacket(const VCMPacket& packet);
void ClearUpTo(uint16_t seq_num);
void UpdateRtt(int64_t rtt_ms);
void Clear();
int64_t TimeUntilNextProcess() override;
void Process() override;
- OnReceivedPacket
数据走向:RtpReceiverImpl::IncomingRtpPacket
->RTPReceiverVideo::ParseRtpPacket
->RtpVideoStreamReceiver::OnReceivedPayloadData
->NackModule::OnReceivedPacket
- IncomingRtpPacket
数据从网卡过来,经过上一层的分发(每个ssrc会对应一个RtpReceiver实例),这里会根据payloadType得到对应的视频编解码类型 - ParseRtpPacket
根据视频编解码类型调用对应的RtpDepacketizer解析此包,得到帧类型(FrameType
)和帧信息(RTPTypeHeader
->RTPVideoHeader
)等信息 - OnReceivedPayloadData
添加ntp时间直接交付给nack模块
- IncomingRtpPacket
- 所以到了nack模块是可以知道此包是否是关键帧的包,是否是一帧的第一个包,包序号等信息。
- 例如收到
1 2 3 6 7 4 5
等包,那么在收到序号为6的包的时候就认为4和5这两个包丢失了,具体可以阅读AddPacketsToNack
这个函数,然后把4和5两个包加入到nack列表中(nack_list_),当收到5这个包的时候从nack列表中移除 - 调用
GetNackBatch(kSeqNumOnly)
找到缺失的包序号,kSeqNumOnly选项触发第一次nack请求,所以nack请求是非常及时的
-
ClearUpTo
此函数最终是由帧缓触发的FrameBuffer::InsertFrame
,帧缓冲只保留kMaxFramesBuffered
帧,并且当帧是乱序的时候也不要此帧。清除到此序号的nack列表和关键帧列表 -
UpdateRtt
更新rtt时间,rtt是根据sr包的信息计算得到的,第一个包的nack触发以后,后面的9次触发都是依据rtt时间而定的。也就是说nack请求的间隔是nack1 rtt nack2 rtt nack3 ...
-
Clear
清空nack列表和关键帧列表 -
TimeUntilNextProcess
获取下一次执行Processc
的时间,每隔kProcessIntervalMs(20ms)检查一次 -
Process
依据rtt找到当前需要发送的nack序号,并递增nack的重试次数(retries),当超过最大重试次数时,不再请求此序号
网友评论