webrtc c++中nack由sdp协商自动启用,c++层通过video/audiosendstream配置影响重传窗口与缓冲区行为;重传缓冲区默认1000包、超时默认50ms(弱网可调至80~120ms),fec需sdp协商a=rtcp-fb: fec并设fec_rate(如5表示每5包发1个fec包),且须与bwe协同避免码流压缩;jitterbuffer的target_delay_ms应略大于rtt而非仅看抖动,max_late_time_ms过小会导致nack无包可重传。

WebRTC C++中NACK重传怎么启用和调参
WebRTC的NACK不是靠手动开启开关,而是由SDP协商自动激活——只要发送端在a=rtcp-fb行里声明了nack能力,接收端就会在RTCP反馈中发出NACK请求。C++层真正能干预的是重传缓冲区行为和超时策略。
关键点在于:VideoSendStream或AudioSendStream创建时传入的EncoderSettings和RtpConfig会影响重传窗口大小与重传次数;而底层ModuleRtpRtcpImpl维护的retransmission_buffer_决定哪些包可被重发。
- 重传缓冲区默认大小是1000个RTP包(约2秒视频),可通过
SetRetransmitFrequencyMs()间接影响保留时长,但不能直接设为“无限”——否则内存暴涨且旧包重传已无意义 -
rtx_time(重传超时)实际由PacketRouter内部的retransmission_delay_ms_控制,默认值是50ms,弱网下可调至80~120ms,但超过150ms后重传基本失效(播放窗口已过) - NACK报文本身有容量限制:单个RTCP FB包最多携带256个丢失序列号,连续丢包超过这个数就会截断,需依赖后续PLI/FIR关键帧请求兜底
FEC在C++ WebRTC里如何配置才不白开
FEC不是“开了就稳”,它和NACK存在带宽博弈关系。C++ SDK中FEC启用路径很隐蔽:必须在创建VideoEncoderConfig时显式设置fec_rate,且仅对VP8/VP9生效(AV1暂不支持FEC)。
更关键的是,FEC冗余包本身也走RTP传输,会占用码率预算。如果BWE(带宽估计)没把FEC带宽算进去,就会导致主码流被压缩得面目全非。
- VP8 FEC使用
FlexFEC(而非旧版ULPFEC),需在SDP中协商a=rtcp-fb: <payload> fec</payload>,否则即使C++侧配了fec_rate=10也无效 -
fec_rate不是百分比,而是“每N个原始包配1个FEC包”的倒数。设为5表示每5个包发1个FEC包(即20%冗余);设为0表示禁用,设为-1表示让WebRTC根据丢包率动态调整(推荐) - FEC只对帧内包(I帧)和部分P帧有效,对B帧几乎无恢复能力——所以高GOP结构下FEC收益骤降,此时应优先调低GOP长度而非堆FEC
抖动缓冲(JitterBuffer)和NACK/FEC的协同陷阱
很多人以为开了NACK+FEC就能关掉抖动缓冲,这是危险误区。JitterBuffer不是只为抗抖动而存在,它还承担着包排序、NACK响应时机判定、FEC解码窗口同步三大任务。
C++中VideoReceiveStream的JitterBuffer实例由Call::CreateVideoReceiveStream()内部构造,其max_packets和max_late_time_ms参数直接影响NACK效果:
-
max_late_time_ms设太小(如10),会导致刚进缓冲区的包被立刻丢弃,NACK还没发出去就没了重传依据 -
max_packets设太大(如>2000),会让JitterBuffer缓存大量旧包,NACK请求可能指向早已过期的序列号,触发假阳性重传 - 真正要调的是
target_delay_ms——它决定缓冲区“期望填充量”。该值应略大于网络RTT(比如RTT=60ms时设为80ms),而非单纯看抖动值。抖动大但RTT稳定时,宁可扩大缓冲也不乱启NACK
为什么你的NACK日志里全是“no packet to retransmit”
这个错误不是丢包没检测到,而是发送端根本没把对应包留在重传队列里。常见于以下三种C++工程场景:
- 编码器输出速率突增(如屏幕共享切到高动态画面),
RtpSender来不及把所有包塞进retransmission_buffer_,部分包被绕过直发,自然无法重传 - 启用了RTX(重传流)但没正确配置SSRC映射,导致NACK请求发到了主SSRC,而重传包却从RTX SSRC发出,两端对不上
- 自定义
FrameTransformerInterface或EncodedImageCallback中修改了RTP时间戳或序列号,破坏了NACK依赖的连续性假设
最隐蔽的问题是:WebRTC的NACK重传队列只保留“未被确认送达”的包,而确认信号来自RTCP Receiver Report(RR)。如果RR发送被阻塞(比如网络卡在发大包),重传队列就会提前清空——这在移动端后台进程被系统限频时特别常见。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











