WebRTC通过NackTracker类实现丢包重传,下面是该类的源码。源码中包含公共变量和方法,也包含私有变量和方法,公共变量和方法可以被看作是对外部提供的接口。
class NackTracker {
public:
// 重传列表的上限为500个包(20ms,10s)
static const size_t kNackListSizeLimit = 500;
// 创建
static NackTracker* Create(int nack_threshold_packets);
~NackTracker();
// 设置重传列表的最大尺寸,上限为 kNackListSizeLimit,值保存在 max_nack_list_size_
void SetMaxNackListSize(size_t max_nack_list_size);
// 更新采样率,保存到 sample_rate_khz_
void UpdateSampleRate(int sample_rate_hz);
// 更新上一个解码完成的数据包的序列号和时间戳
void UpdateLastDecodedPacket(uint16_t sequence_number, uint32_t timestamp);
// 更新上一个接收到的数据包的序列号和时间戳
void UpdateLastReceivedPacket(uint16_t sequence_number, uint32_t timestamp);
// 获取重传列表
std::vector<uint16_t> GetNackList(int64_t round_trip_time_ms) const;
// 状态重置
void Reset();
private:
FRIEND_TEST_ALL_PREFIXES(NackTrackerTest, EstimateTimestampAndTimeToPlay);
struct NackElement {
NackElement(int64_t initial_time_to_play_ms,
uint32_t initial_timestamp,
bool missing)
: time_to_play_ms(initial_time_to_play_ms),
estimated_timestamp(initial_timestamp),
is_missing(missing) {}
int64_t time_to_play_ms;
uint32_t estimated_timestamp;
bool is_missing;
};
class NackListCompare {
public:
bool operator()(uint16_t sequence_number_old,
uint16_t sequence_number_new) const {
return IsNewerSequenceNumber(sequence_number_new, sequence_number_old);
}
};
// 重传列表的宏定义
typedef std::map<uint16_t, NackElement, NackListCompare> NackList;
// 显示定义构造函数
explicit NackTracker(int nack_threshold_packets);
// 得到重传列表(重传列表中是丢失数据包的序列号)
NackList GetNackList() const;
// 根据当前时间戳,将丢失的数据包添加到重传列表中
void AddToList(uint16_t sequence_number_current_received_rtp);
void UpdateEstimatedPlayoutTimeBy10ms();
// 更新每一个数据包包含的样本数
void UpdateSamplesPerPacket(uint16_t sequence_number_current_received_rtp,
uint32_t timestamp_current_received_rtp);
// 更新重传列表
void UpdateList(uint16_t sequence_number_current_received_rtp);
// 将延时包设置为丢包
void ChangeFromLateToMissing(uint16_t sequence_number_current_received_rtp);
// 将超出重传列表上限的多余数据包清除
void LimitNackListSize();
uint32_t EstimateTimestamp(uint16_t sequence_number);
int64_t TimeToPlay(uint32_t timestamp) const;
// 设置延迟阈值,阈值以内为延迟,阈值以外为丢包
const int nack_threshold_packets_;
// 上一个接收到的数据包的序列号
uint16_t sequence_num_last_received_rtp_;
// 上一个接收到的数据包的时间戳
uint32_t timestamp_last_received_rtp_;
// 是否接收到过数据包
bool any_rtp_received_;
// 上一个解码后的数据包的序列号
uint16_t sequence_num_last_decoded_rtp_;
// 上一个解码后的数据包的时间戳
uint32_t timestamp_last_decoded_rtp_;
// 是否解码过数据包
bool any_rtp_decoded_;
// 采样率(单位kHz)
int sample_rate_khz_;
// 单个数据包包含的样本数
int samples_per_packet_;
// 重传列表
NackList nack_list_;
// 重传列表的最大上限
size_t max_nack_list_size_;
};
从公共方法来看,丢包重传的功能主要围绕 UpdateLastDecodedPacket、UpdateLastReceivedPacket 和 GetNackList 来实现。
Create:用来创建 NackTracker 的实例
Reset:用于状态重置
UpdateSampleRate:用于更新采样率,接收端采样率的变化通常意味着通讯媒体协商的改变,会清空所有缓冲区,相当于重新建立了一个会话。
GetNackList:得到重传列表,用来构造成一个丢失重传报文,发送给对端。
UpdateLastReceivedPacket:接收端每接收一个数据包就要调用此方法,更新单个包中的样本数量,更新列表(将nack_threshold_packets_范围之外的包划定为丢包,接着当前收到数据包的时间戳和序列号和上一个收到的时间戳和序列号相比,判断是否有丢失的数据包并且计算丢包的序列号和时间戳,并将其存入重传列表)。将当前收到的RTP数据包保存为上一个收到的数据包,为下一个数据包提供参考。删除超出重传列表上限的数据包。