WebRTC服务质量(07)- 重传机制(04) 接收NACK消息

WebRTC服务质量(01)- Qos概述
WebRTC服务质量(02)- RTP协议
WebRTC服务质量(03)- RTCP协议
WebRTC服务质量(04)- 重传机制(01) RTX NACK概述
WebRTC服务质量(05)- 重传机制(02) NACK判断丢包
WebRTC服务质量(06)- 重传机制(03) NACK找到真正的丢包
WebRTC服务质量(07)- 重传机制(04) 接收NACK消息
WebRTC服务质量(08)- 重传机制(05) RTX机制
WebRTC服务质量(09)- Pacer机制(01) 流程概述
WebRTC服务质量(10)- Pacer机制(02) RoundRobinPacketQueue
WebRTC服务质量(11)- Pacer机制(03) IntervalBudget
WebRTC服务质量(12)- Pacer机制(04) 向Pacer中插入数据

一、前言:

首先我们要明白NACK是一种RTCP包,而RTCP在WebRtc当中是基于UDP的,所以,我们接收数据包的源头肯定是传输层的UDP包,然后,一次经历几个关键的模块到达应用层。

二、收包流程:

在这里插入图片描述

  • PhysicalSocketServer: 这是底层网络的抽象。它负责创建和管理底层网络套接字(通常是 UDP 套接字),为 WebRTC 的其他组件提供网络 I/O 功能。 它处理网络事件,例如数据包到达和发送错误。
  • UDPPort: 这个类代表一个具体的 UDP 端口,用于发送和接收媒体数据和 RTCP 控制信息。它通常由 PhysicalSocketServer 创建和管理。
  • P2PTransportChannel: 这层建立在 UDPPort 之上,它负责在两个 WebRTC 对等体之间可靠地传输数据包。它可能包含重传机制、拥塞控制以及其他优化网络传输的机制。 它负责将数据从应用程序层传递到网络层,反之亦然。
  • PeerConnection: 这是 WebRTC 的核心类。它管理 WebRTC 会话的整个生命周期,包括建立连接、协商编解码器和传输参数,以及处理媒体流的发送和接收。 它负责协调所有其他组件以实现 P2P 通信。
  • Call: 这个类通常在更高级别的应用程序中使用,它代表一个正在进行的 WebRTC 通信会话。 它可能是 PeerConnection 的一个包装器,提供更高级别的 API 来管理通话,例如发起、应答和结束通话。
  • VideoSendStream: 此类专门处理视频数据的发送。它负责编码视频帧,打包数据,并将它们通过 P2PTransportChannel 发送给远程对等体。
  • RTCPReceiver: RTCP (RTP 控制协议) 用于传输媒体流的控制信息,例如丢包率、延迟和带宽估计。RTCPReceiver 负责接收和处理来自远程对等体的 RTCP 数据包,并将这些信息提供给其他 WebRTC 组件。
  • ModuleRtpRtcpImpl: 这是一个更底层的类,它负责处理 RTP (实时传输协议) 数据包的发送和接收。 它处理 RTP 包的封装和解封装,并与 RTCP 紧密集成。

我们发现其实就是:从传输层获取RTP包 —> Call模块分发(RTP或者RTCP包) —> 具体的音视频Stream处理自己的RTCP包 —> 会调用Rtp/Rtcp模块处理。

三、处理收到的RTCP包:

PacketReceiver::DeliveryStatus Call::DeliverPacket(
    MediaType media_type,
    rtc::CopyOnWriteBuffer packet,
    int64_t packet_time_us) {
  RTC_DCHECK_RUN_ON(worker_thread_);
  // 如果是rtcp包
  if (IsRtcp(packet.cdata(), packet.size()))
    return DeliverRtcp(media_type, packet.cdata(), packet.size());
  // 否则就是rtp包
  return DeliverRtp(media_type, std::move(packet), packet_time_us);
}

发现判断是Rtcp包就走DeliverRtcp,那么怎么判断是Rtcp包呢?

其实就是根据RTCP协议头里面的payload type,看看是否属于RTCP包,比如FIR\BYE\NACK这些都有自己的PT值。

PacketReceiver::DeliveryStatus Call::DeliverRtcp(MediaType media_type,
                                                 const uint8_t* packet,
                                                 size_t length) {
  // ...
  bool rtcp_delivered = false;
  if (media_type == MediaType::ANY || media_type == MediaType::VIDEO) {
    for (VideoReceiveStream2* stream : video_receive_streams_) {
      if (stream->DeliverRtcp(packet, length))
        rtcp_delivered = true;
    }
  }
  // ...

  return rtcp_delivered ? DELIVERY_OK : DELIVERY_PACKET_ERROR;
}

发现Call是将RTCP包转给了对应Stream,我们这儿就是ReceiveStream。

bool VideoReceiveStream2::DeliverRtcp(const uint8_t* packet, size_t length) {
  return rtp_video_stream_receiver_.DeliverRtcp(packet, length);
}

进去看看:

bool RtpVideoStreamReceiver2::DeliverRtcp(const uint8_t* rtcp_packet,
                                          size_t rtcp_packet_length) {
  // ...
  // 将RTP/RTCP包传给 ModuleRtpRtcpImpl2 处理
  rtp_rtcp_->IncomingRtcpPacket(rtcp_packet, rtcp_packet_length);
  // ...
}

发现转给了ModuleRtpRtcpImpl2模块:

void ModuleRtpRtcpImpl::IncomingRtcpPacket(const uint8_t* rtcp_packet,
                                           const size_t length) {
  rtcp_receiver_.IncomingPacket(rtcp_packet, length);
}

注意,对上上面的收包流程图,始终记住自己在哪儿:

void RTCPReceiver::IncomingPacket(rtc::ArrayView<const uint8_t> packet) {
  // ... 
  PacketInformation packet_information;
  // 解析网络包,因为发送端是将多个包串成一个包发送的。
  // 因此,解析过程中,就是先解析RTCP头,再通过RTCP头里面的长度解析数据。以此类推
  if (!ParseCompoundPacket(packet, &packet_information))
    return;
  // 将上面解析包得到的 packet_information 作为参数,传给下一步继续处理
  TriggerCallbacksFromRtcpPacket(packet_information);
}

其实我注释写了很多,其实就是解析CompoundPacket,这种包我前面讲过,就是RTCP包比较小,就将多个一次发过来了。

bool RTCPReceiver::ParseCompoundPacket(rtc::ArrayView<const uint8_t> packet,
                                       PacketInformation* packet_information) {
  MutexLock lock(&rtcp_receiver_lock_);

  CommonHeader rtcp_block;
  // 先获取每个rtcp包的header,然后,解析
  for (const uint8_t* next_block = packet.begin(); next_block != packet.end();
       next_block = rtcp_block.NextPacket()) { // 读取一个RTCP包
    // remaining_blocks_size 不为0说明后面还有数据,继续解析;
    ptrdiff_t remaining_blocks_size = packet.end() - next_block;
    RTC_DCHECK_GT(remaining_blocks_size, 0);
    // 开始解析
    if (!rtcp_block.Parse(next_block, remaining_blocks_size)) {
      if (next_block == packet.begin()) {
        // Failed to parse 1st header, nothing was extracted from this packet.
        RTC_LOG(LS_WARNING) << "Incoming invalid RTCP packet";
        return false;
      }
      ++num_skipped_packets_;
      break;
    }
    // 。。。
    // 根据 RTCP 包的类型 (rtcp_block.type()) 调用相应的处理函数
    switch (rtcp_block.type()) {
      case rtcp::SenderReport::kPacketType:
        HandleSenderReport(rtcp_block, packet_information);
        break;
      case rtcp::ReceiverReport::kPacketType:
        HandleReceiverReport(rtcp_block, packet_information);
        break;
      // 。。。
    }
  }

  return true;
}

总而言之,这个函数是一个 RTCP 包解析器,它高效地处理复合 RTCP 数据包,并根据包类型进行分发,处理各种 RTCP 消息。

四、总结:

本文主要介绍了接收Nack包的流程,其实也就是接收一般RTCP包的流程,并且从Call模块开始走读了一下代码,走读代码过程中千万要记住自己大概处于流程的什么位置,要么会lost yourself!!!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/943437.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Cadence学习笔记 11 PCB中器件放置

基于Cadence 17.4&#xff0c;四层板4路HDMI电路 更多Cadence学习笔记&#xff1a;Cadence学习笔记 1 原理图库绘制Cadence学习笔记 2 PCB封装绘制Cadence学习笔记 3 MCU主控原理图绘制Cadence学习笔记 4 单片机原理图绘制Cadence学习笔记 5 四路HDMI原理图绘制Cadence学习笔记…

Docker 入门:如何使用 Docker 容器化 AI 项目(二)

四、将 AI 项目容器化&#xff1a;示例实践 - 完整的图像分类与 API 服务 让我们通过一个更完整的 AI 项目示例&#xff0c;展示如何将 AI 项目容器化。我们以一个基于 TensorFlow 的图像分类模型为例&#xff0c;演示如何将训练、推理、以及 API 服务过程容器化。 4.1 创建 …

三层交换机配置

一&#xff0c;三层交换 概念&#xff1a;三层交换技术就是&#xff1a;二层交换技术三层转发技术(路由器功能)。它解决了局域网中网段划分之后&#xff0c;网段中子网必须依赖路由器进行管理的局面&#xff0c;解决了传统路由器低速&#xff0c;复杂所造成的网络瓶颈问题。 …

LabVIEW应用在工业车间

LabVIEW作为一种图形化编程语言&#xff0c;以其强大的数据采集和硬件集成功能广泛应用于工业自动化领域。在工业车间中&#xff0c;LabVIEW不仅能够实现快速开发&#xff0c;还能通过灵活的硬件接口和直观的用户界面提升生产效率和设备管理水平。尽管其高成本和初期学习门槛可…

【CSS in Depth 2 精译_094】16.2:CSS 变换在动效中的应用(下)——导航菜单的文本标签“飞入”特效与交错渲染效果的实现

当前内容所在位置&#xff08;可进入专栏查看其他译好的章节内容&#xff09; 第五部分 添加动效 ✔️【第 16 章 变换】 ✔️ 16.1 旋转、平移、缩放与倾斜 16.1.1 变换原点的更改16.1.2 多重变换的设置16.1.3 单个变换属性的设置 16.2 变换在动效中的应用 16.2.1 放大图标&am…

Qt使用QZipWriter和QZipReader来解压、压缩文件

首先感谢这位博主的无私奉献&#xff1a;Qt - 实现压缩文件、文件夹和解压缩操作 - [BORUTO] - 博客园 多文件和目录压缩时&#xff0c;不改变原始文件和目录的相对位置结构&#xff0c;需要在addFile和addDirectory时&#xff0c;需要带上相对路径&#xff0c;如下&#xff1…

PH热榜 | 2024-12-23

1. Websparks 标语&#xff1a;让你的创意变为现实的AI软件工程师 介绍&#xff1a;现在&#xff0c;构建网页应用从未如此简单快捷&#xff01;WebSparks是一个基于人工智能的平台&#xff0c;它能让开发者、设计师&#xff0c;甚至不懂编程的人&#xff0c;都能在很短的时间…

Opencv之对图片的处理和运算

Opencv实现对图片的处理和修改 目录 Opencv实现对图片的处理和修改灰度图读取灰度图转换灰度图 RBG图单通道图方法一方法二 单通道图显色合并单通道图 图片截取图片打码图片组合缩放格式1格式2 图像运算图像ma[m:n,x:y]b[m1:n1,x1:y1] add加权运算 灰度图 读取灰度图 imread(‘…

OpenLinkSaas使用手册-Git工具

在OpenLinkSaas的工具箱里面&#xff0c;最基础的一个就是Git仓库管理。Git仓库功能让git使用更加简单和强大&#xff0c;不仅可以使用常规的commit/pull/push/branch等功能外&#xff0c;还连接了Git仓库供应商的能力。 OpenLinkSass支持使用国内主流的Git仓库供应商的账号登录…

WebRTC服务质量(12)- Pacer机制(04) 向Pacer中插入数据

WebRTC服务质量&#xff08;01&#xff09;- Qos概述 WebRTC服务质量&#xff08;02&#xff09;- RTP协议 WebRTC服务质量&#xff08;03&#xff09;- RTCP协议 WebRTC服务质量&#xff08;04&#xff09;- 重传机制&#xff08;01) RTX NACK概述 WebRTC服务质量&#xff08;…

protobuf学习使用

1、概述 protobuf是Google开发的一种语言中立、平台无关、可扩展的序列化结构数据格式。允许定义一次数据结构&#xff0c;然后可以使用各种支持的语言来生成代码&#xff0c;以轻松地读写这些结构到一个二进制流中&#xff0c;如网络传输或文件&#xff0c;Protobuf支持多种编…

CTFHUB-web进阶-php

我们用蚁剑中的这个插件来做这些关卡 一.LD_PRELOAD 发现这里有一句话木马&#xff0c;并且把ant给了我们&#xff0c;我们直接连接蚁剑 右键 选择模式&#xff0c;都可以试一下&#xff0c;这里第一个就可以 点击开始 我们进入到目录&#xff0c;刷新一下&#xff0c;会有一个…

相机、镜头参数详解以及相关计算公式

一、工业相机参数 1、分辨率 相机每次采集图像的像素点数&#xff0c;也是指这个相机总共有多少个感光晶片。在采集图像时&#xff0c;相机的分辨率对检测精度有很大的影响&#xff0c;在对同样打的视场成像时&#xff0c;分辨率越高&#xff0c;对细节的展示越明显。 相机像素…

取多个集合的交集

1.我们取多个集合的交集&#xff0c;先把各个集合放入list中 List < Set < String > > listnew ArrayList<>();HashSet<String> set1new HashSet<>();set1.add( "A" );set1.add("B" );set1.add("C" );HashSet<…

leetcode之hot100---206环形链表(C++)

思路一&#xff1a;哈希表 遍历链表&#xff0c;同时借助哈希表判断当前遍历到的节点是否已经被访问过&#xff0c;如果当前节点已被访问过&#xff0c;则说明存在环 /*** Definition for singly-linked list.* struct ListNode {* int val;* ListNode *next;* L…

文档解析丨高效准确的PDF解析工具,赋能企业非结构化数据治理

在数据为王的时代浪潮中&#xff0c;企业数据治理已成为组织优化运营、提高竞争力的关键。随着数字化进程的加速&#xff0c;企业所积累的数据量呈爆炸式增长&#xff0c;数据类型也愈发多样化&#xff0c;这些数据构成了现代企业数据资产的重要组成部分。 然而&#xff0c;传…

优化 invite_codes 表的 SQL 创建语句

-- auto-generated definition create table invite_codes (id int auto_incrementprimary key,invite_code varchar(6) not null comment 邀请码&#xff0c;6位整数&#xff0c;确保在有效期内…

C语言基础:指针(数组指针与指针数组)

数组指针与指针数组 数组指针 概念&#xff1a;数组指针是指向数组的指针&#xff0c;本质上还是指针 特点&#xff1a; 先有数组&#xff0c;后有指针 它指向的是一个完整的数组 一维数组指针&#xff1a; 语法&#xff1a; 数据类型 (*指针变量名)[行容量][列容量]; 案…

进阶篇(1)

一.存储引擎: <1>MySQL体系结构: 1.连接层: 主要接收客户端的连接,完成一些连接的处理、认证授权、及相关操作安全方案、检测是否超过最大连接数等等;也会为安全接入的每个客户端验证它所具有的操作权限。 例如:在连接MySQL服务器时,我们需要输入用户名和密码,输…

电脑提示报错NetLoad.dll文件丢失或损坏?是什么原因?

一、NetLoad.dll文件丢失或损坏的根源 程序安装不完整&#xff1a;某些程序在安装过程中可能因为磁盘错误、网络中断或安装程序本身的缺陷&#xff0c;导致NetLoad.dll文件未能正确安装或复制。 恶意软件攻击&#xff1a;病毒、木马等恶意软件可能会篡改或删除系统文件&#x…