WEBRTC浅析(五)视频Nack包的发送判断逻辑以及数据流

article/2025/10/6 15:46:39

这篇文章是对webrtc 中Nack包发送机制的梳理,主要包括三个部分:
第一部分,介绍RTCP包中,Nack包的规范。
第二部分,介绍在WEBRTC中,Nack发送机制的数据流程图。
第三部分,介绍在WEBRTC中,Nack处理的一些关键的代码。

一:RTCP Nack报文解析

    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+|V=2|P|   FMT   |       PT      |          length               |+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+|                  SSRC of packet sender                        |+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+|                  SSRC of media source                         |+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+:            Feedback Control Information (FCI)                 ::              Feedback message type (FMT): 5 bits0:    unassigned1:    Generic NACK2-30: unassigned31:   reserved for future expansion of the identifier number spacePayload type (PT): 8 bitsThis is the RTCP packet type that identifies the packet as beingan RTCP FB message.  Two values are defined by the IANA:Name   | Value | Brief Description----------+-------+------------------------------------RTPFB  |  205  | Transport layer FB messagePSFB   |  206  | Payload-specific FB messagessrc packet sender: 构造发送当前消息包的端的SSRCssrc source:  NACK消息部分,也是SSRC值,在此可称为媒体源标识符The Feedback Control Information (FCI) field has the following Syntax0                   1                   2                   30 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+|            PID                |             BLP               |+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

参考链接:rfc4585

  • 如果是一个NACK message
    • PT=RTPFB

    • FMT=1

    • 丢包为10,20,30,40,50。用3个int可以表示清楚,用rfc 4585的通用协议表示如下

        Real-time Transport Control Protocol (Generic RTP Feedback): NACK: 2 frames lost: NACK: 2 frames lost: NACK: 1 frames lost10.. .... = Version: RFC 1889 Version (2)..0. .... = Padding: False...0 0001 = RTCP Feedback message type (FMT): Generic negative acknowledgement (NACK) (1)Packet type: Generic RTP Feedback (205)Length: 5 (24 bytes)Sender SSRC: 0x00123456 (1193046)Media source SSRC: 0x00c0ffed (12648429)RTCP Transport Feedback NACK PID: 10RTCP Transport Feedback NACK BLP: 0x0200 (Frames 20 lost)RTCP Transport Feedback NACK PID: 30RTCP Transport Feedback NACK BLP: 0x0200 (Frames 40 lost)RTCP Transport Feedback NACK PID: 50RTCP Transport Feedback NACK BLP: 0x0000 (No additional frames lost)
      

      PID为10,表示sequence为10的包,BLP的第10位为1,表示10之后第10个包,即sequence num为20的包,所以一个int可以表示17个连续包的丢包情况。

二:Nack包发送流程图

NACK_FLOW.jpg

三:Nack在webrtc中的计算

VideoStream接收端的处理

  • 添加Nack 包到nack_list_中去

      	void NackModule::AddPacketsToNack(uint16_t seq_num_start,uint16_t seq_num_end) {// Remove old packets.auto it = nack_list_.lower_bound(seq_num_end - kMaxPacketAge);nack_list_.erase(nack_list_.begin(), it);// If the nack list is too large, remove packets from the nack list until// the latest first packet of a keyframe. If the list is still too large,// clear it and request a keyframe.uint16_t num_new_nacks = ForwardDiff(seq_num_start, seq_num_end);if (nack_list_.size() + num_new_nacks > kMaxNackPackets) {while (RemovePacketsUntilKeyFrame() &&nack_list_.size() + num_new_nacks > kMaxNackPackets) {}if (nack_list_.size() + num_new_nacks > kMaxNackPackets) {nack_list_.clear();LOG(LS_WARNING) << "NACK list full, clearing NACK"" list and requesting keyframe.";keyframe_request_sender_->RequestKeyFrame();return;}}//在Start 和 End之间的RTP包,就是需要发Nack的包。for (uint16_t seq_num = seq_num_start; seq_num != seq_num_end; ++seq_num) {NackInfo nack_info(seq_num, seq_num + WaitNumberOfPackets(0.5));RTC_DCHECK(nack_list_.find(seq_num) == nack_list_.end());nack_list_[seq_num] = nack_info;}}
    
  • 根据不同的kSeqNumOnly, kTimeOnly模式,来选择需要重发的包

      std::vector<uint16_t> NackModule::GetNackBatch(NackFilterOptions options) {bool consider_seq_num = options != kTimeOnly;bool consider_timestamp = options != kSeqNumOnly;int64_t now_ms = clock_->TimeInMilliseconds();std::vector<uint16_t> nack_batch;auto it = nack_list_.begin();while (it != nack_list_.end()) {if (consider_seq_num && it->second.sent_at_time == -1 &&AheadOrAt(newest_seq_num_, it->second.send_at_seq_num)) {nack_batch.emplace_back(it->second.seq_num);++it->second.retries;it->second.sent_at_time = now_ms;if (it->second.retries >= kMaxNackRetries) {LOG(LS_VERBOSE) << "Sequence number " << it->second.seq_num<< " removed from NACK list due to max retries."<< " newest_seq_num " << newest_seq_num_<< " it->second.send_at_seq_num " << it->second.send_at_seq_num;it = nack_list_.erase(it);} else {++it;}continue;}if (consider_timestamp && it->second.sent_at_time + rtt_ms_ <= now_ms) {nack_batch.emplace_back(it->second.seq_num);++it->second.retries;it->second.sent_at_time = now_ms;if (it->second.retries >= kMaxNackRetries) {LOG(LS_VERBOSE) << "Sequence number " << it->second.seq_num<< " removed from NACK list due to max retries."<< " rtt_ms " << rtt_ms_;it = nack_list_.erase(it);} else {++it;}continue;}++it;}return nack_batch;}
    

VideoSendStream端的处理

  • 收到OnReceivedNack事件

      int32_t RTPSender::ReSendPacket(uint16_t packet_id, int64_t min_resend_time) {// 根据RTT,去从队列里找到还能发送的RTP包std::unique_ptr<RtpPacketToSend> packet =packet_history_.GetPacketAndSetSendTime(packet_id, min_resend_time, true);if (!packet) {// Packet not found.LOG(LS_VERBOSE) << "ResendPacket packet not found "<< " pktid " << packet_id<< " min_resend_time " << min_resend_time;return 0;}。。。。。。if (paced_sender_) {// Convert from TickTime to Clock since capture_time_ms is based on// TickTime.int64_t corrected_capture_tims_ms =packet->capture_time_ms() + clock_delta_ms_;// 添加到Pace Sender里去发送    paced_sender_->InsertPacket(RtpPacketSender::kNormalPriority,packet->Ssrc(), packet->SequenceNumber(),corrected_capture_tims_ms,packet->payload_size(), true);。。。。。。
    

http://chatgpt.dhexx.cn/article/4ZPbPTU0.shtml

相关文章

RabbitMQ的ack和nack机制

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、ACK机制二、主动ACK三、手动ACK四、Nack机制五、MQ unack的影响总结 前言 本文主要讨论RabbitMQ消费者的ack和nack机制&#xff0c;并且关注ack和nack使用…

RTCP 协议的 NACK 报文

接收方定时把所有未收到的包序号通过反馈报文通知到发送方进行重传。 相对 ARQ带来的改进&#xff1a;减少的反馈包的频率和带宽占用&#xff0c;同时也能比较及时地通知发送方进行丢包重传。 NACK 报文的定义在 [rfc4585] 文档中定义。 RTCP 的反馈报文包头定义如下&#x…

webrtc nack实现原理

1.nack 简介 webrtc 中nack是最基本的QOS策略&#xff0c;与ack机制不同的地方是nack是接收端检测到丢包时&#xff0c;告知发送端具体丢包的序号&#xff0c;接收端收到nack后从缓存中找到对应的包并发送出去。 2. nack实现 nack rtcp报文格式如上图所示&#xff0c;pt205。P…

webrtc QOS方法一(NACK实现)

一&#xff1a;概述 NACK则在接收端检测到数据丢包后&#xff0c;发送NACK报文到发送端&#xff1b;发送端根据NACK报文中的序列号&#xff0c;在发送缓冲区找到对应的数据包&#xff0c;重新发送到接收端。NACK需要发送端发送缓冲区的支持&#xff0c;RFC5104[2]定义NACK数据包…

认识网络通信中的 ACK、NACK 和 REX

ACK、NACK、 REX在面试或者网络通信的时候&#xff0c;我们可能经常听到和遇到。今天就来详细介绍一下ACK、NACK、 REX。 认识ACK、NACK、 REX ACK&#xff1a;Acknowledgement&#xff0c;它是一种正向反馈&#xff0c;接收方收到数据后回复消息告知发送方。NACK&#xff1a…

WebRTC之NACK、RTX 在什么时机判断丢包发送NACK请求和RTX丢包重传

WebRTC之NACK、RTX 在什么时机判断丢包发送NACK请求和RTX丢包重传 WebRTC之NACK、RTX 在什么时机判断丢包发送NACK请求和RTX丢包重传 WebRTC之NACK、RTX 在什么时机判断丢包发送NACK请求和RTX丢包重传前言一、NACK与RTX的作用1、NACK/RTX的工作机制的流程图2、NACK/RTX涉及到的…

WebRTC 的音频弱网对抗之 NACK

本文梳理 WebRTC 的音频弱网对抗中的 NACK 机制的实现。音频的 NACK 机制在 WebRTC 中默认是关闭的&#xff0c;本文会介绍开启 NACK 机制的方法。 在网络数据传输中&#xff0c;NACK (NAK&#xff0c;negative acknowledgment&#xff0c;not acknowledged) 是数据接收端主动…

流媒体弱网优化之路(NACK)——纯NACK方案的优化探索

流媒体弱网优化之路(NACK)——纯NACK方案的优化探索 —— 我正在的github给大家开发一个用于做实验的项目 —— github.com/qw225967/Bifrost目标&#xff1a;可以让大家熟悉各类Qos能力、带宽估计能力&#xff0c;提供每个环节关键参数调节接口并实现一个json全配置&#xff…

WebRTC源码分析 nack详解

1、Nack过程 1.1 nack是什么 丢包重传(NACK)是抵抗网络错误的重要手段。NACK在接收端检测到数据丢包后&#xff0c;发送NACK报文到发送端&#xff1b;发送端根据NACK报文中的序列号&#xff0c;在发送缓冲区找到对应的数据包&#xff0c;重新发送到接收端。NACK需要发送端&am…

谈谈网络通信中的 ACK、NACK 和 REX

目录 名词解释 问题 1&#xff1a; 接收方如何判断数据包是否丢失&#xff1f; 问题 2&#xff1a;发送方如何确认数据包已经丢失&#xff1f; 问题 3&#xff1a;重传超时的计算规则&#xff1f; 问题 4&#xff1a;发送方的数据包要缓存多久&#xff1f; 问题 5&#x…

费马定理_高数_1元微积分

定理 设 f(x) 在 x0 点处满足&#xff1a;1、可导 2、取得极值&#xff0c;则有 f ’ (x0)0 证明 不妨假设 f(x) 在点 x0 处取得极大值&#xff0c;则存在 x0 的邻域 U( x0 )&#xff0c;对任意的 x属于U( x0 )&#xff0c;都有 根据导数定义与极限的保号性有 又 f(x) 在点…

老猿Python博客文章目录索引

本目录提供老猿Python所有相关博文的一级目录汇总&#xff0c;带星号的为付费专栏&#xff1a; 一、专栏列表 本部分为老猿所有专栏的列表&#xff0c;每个专栏都有该专栏置顶的博文目录&#xff1a; Python基础教程目录PyQt入门学习* 使用PyQt开发图形界面Python应用PyQtmo…

(组合数+快速幂+lucas+费马小引理)acwing 887. 求组合数 III

887. 求组合数 III 题目链接https://www.acwing.com/problem/content/889/ 题目&#xff1a; 思路&#xff1a; #include<iostream> #include<cstdio> using namespace std; typedef long long LL; int n; int qmi(LL a,int k,int p){int res1;while(k){if(k&…

(组合数 +快速幂+逆元+费马小引理)acwing 886. 求组合数 II

886. 求组合数 II 题目链接https://www.acwing.com/problem/content/888/ 题目&#xff1a; 思路&#xff1a; #include<iostream> #include<cstdio> using namespace std; typedef long long LL; const int mod1e97;//mod为质数 int a,b,n; int fact[100010],…

Leetcode-数学费马平方和定理-633. 平方数之和

题目633. 平方数之和&#xff1a; 题解&#xff1a; 1&#xff0c;暴力枚举sqrt class Solution { public:bool judgeSquareSum(int c) {if(c < 2 ){return true;}for(long a 0; a*a < c; a){double b sqrt(c - a * a);if((int)b b){return true;}}return false;} …

费马定理、罗尔中值定理、零点存在定理、拉格朗日中值定理、

介值定理 介值定理如果AB,则开区间&#xff08;a,b&#xff09;内可能取不到端点值A,B 即介值定理如果C不等于端点值&#xff0c;那么 ξ ξ ξ可以是属于开区间&#xff0c;如果C等于端点值&#xff0c;那么 ξ ξ ξ必须属于闭区间。 零点存在定理 假设函数f(x)在闭区间[a,…

费马引理的证明

设 f(x)在 ξ处最大&#xff0c;故不论Δx是正或负&#xff0c;总有 设 &#xff0c; 则 。 故由极限的保号性有 &#xff08;1&#xff09; 而当 时&#xff0c; &#xff0c; 故 &#xff08;2&#xff09; 由(1)&#xff0c;(2)两式及 存在知&#xff0c;必有 设 f(x)在 ξ处…

费马引理

转载于:https://www.cnblogs.com/fuhang/p/7976329.html