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),當超過最大重試次數時,不再請求此序號