 介绍)
NackTracker 是 WebRTC NetEq 模块中用于跟踪丢失的 RTP 数据包并生成 NACKNegative Acknowledgement列表的核心类。它的主要目的是在网络状况不佳导致丢包时通过请求发送端重传丢失的数据包来恢复音频质量同时避免请求那些已经“过时”即播放时间已过或即将到达重传来不及的数据包。NackTracker 是一个智能的丢包跟踪器。它不仅仅是记录哪些包没收到更重要的是基于时间的决策引擎。它通过实时估算每个丢失包的“剩余寿命”距离播放还有多久结合网络 RTT动态决定哪些包值得重传Missing哪些包应该放弃Late 或过期从而在恢复音频质量和控制延迟/带宽之间取得平衡。一、核心概念Missing vs. LateNackTracker将未到达的数据包分为两类• Late (迟到): 数据包虽然还没到但预计在其播放时间之前还有可能到达。此时不请求重传继续等待。• Missing (丢失): 数据包不仅没到而且根据当前的网络往返时间RTT估计即使现在请求重传在播放时刻之前也大概率无法到达或者该包已经严重滞后不再有价值。此时将其标记为 Missing并加入 NACK 列表请求重传。二 关键成员2.1 nack_list_ (NackList):• 一个 std::mapKey 是 RTP 序列号Value 是 NackElement。• NackElement 包含• time_to_play_ms: 估计该包还需要多少毫秒才被播放。• estimated_timestamp: 估计该包的 RTP 时间戳。• is_missing: 标记该包是“丢失”还是“迟到”。2.2 nack_threshold_packets_:• 阈值。如果当前收到的最新包序列号为 那么序列号小于 且未收到的包被视为 Missing。序列号在 之间的未收到包被视为 Late。2.3 max_nack_list_size_:• NACK 列表的最大长度限制。防止内存无限增长只保留最近的丢失包。2.4 samples_per_packet_ sample_rate_khz_:• 用于计算每个包的持续时间从而估算 time_to_play。三主要工作流程函数3.1 初始化与重置1 Create(int nack_threshold_packets): 工厂方法创建实例。2 Reset(): 清空 NACK 列表。通常在切换编解码器或采样率变化时调用因为旧的包重传已无意义。3 UpdateSampleRate(int sample_rate_hz): 更新采样率以便正确计算播放时间。3.2 状态更新1 UpdateLastReceivedPacket(seq, ts):• 当一个新的 RTP 包从网络到达并插入 NetEq/ACM 时调用。• 核心逻辑:a. 检测序列号跳跃识别中间缺失的包。b. 调用 AddToList 将缺失包加入 nack_list_。c. 调用 ChangeFromLateToMissing检查之前的 Late 包如果它们现在的序列号距离最新包超过了 nack_threshold则转为 Missing。d. 调用 LimitNackListSize移除过旧的包。2 UpdateLastDecodedPacket(seq, ts):• 当 NetEq 成功解码并输出 10ms 音频时调用。• 核心逻辑:a. 更新最后解码包的序列号和时间戳。b. 调用 UpdateEstimatedPlayoutTimeBy10ms将 nack_list_ 中所有包的 time_to_play_ms 减去 10ms。因为时间流逝了剩余等待播放的时间变短了。3.3获取 NACK 列表1 GetNackList(int64_t round_trip_time_ms):• 这是上层如 RtpRtcp 模块调用的接口用于获取需要请求重传的序列号列表。• 筛选逻辑:a. 遍历 nack_list_。b. 只选择 is_missing true 的包。c. 进一步筛选只有当 time_to_play_ms round_trip_time_ms 时才加入列表。• 原因: 如果剩余播放时间小于 RTT说明即使现在立刻请求重传包也会在播放时刻之后才到达因此请求重传是无效的甚至浪费带宽。四辅助函数1 EstimateTimestamp(seq):根据已知包的时间戳和序列号差值线性推算丢失包的时间戳。2 TimeToPlay(timestamp):根据当前解码进度和包的时间戳计算该包距离被播放还有多少毫秒。