WebRTC QoS方法之Pacer实现

news2024/9/20 1:01:17

本文将解读WebRTC中Pacer算法的实现。

WebRTC有两套Pacer算法:TaskQueuePacedSender、PacedSender。本文仅介绍PacedSender的实现。(文章中引用的WebRTC代码基于master,commit:3f412945f05ce1ac372a7dad77d85498d23deaae源码分析)

1、背景介绍


若仅仅发送音频数据,不需要Pacer模块。

  • 一帧音频数据本身不大,不会超过以太网的最大报文长度。一个RTP报文可以搞定,按照打包时长的节奏发送就可以。但视频数据不能按照音频数据的思路发送,一帧视频可能很大,远大于以太网的1500byte,需要分别封装在几个RTP报文中,若这些视频帧RTP报文一起发送到网络上,必然会导致网络瞬间拥塞。产生丢包抖动等异常。

  • 大多数编解码格式下,一帧音频数据长度固定,音频码率持续平稳。码率不会出现忽高忽低现象。但是一帧视频数据长度受内容影响严重。I、P、B帧间的长度相差非常大。直接发送网络波动幅度很大。尤其是WIFI环境下,受限WIFI的调度机制,媒体数据能否平稳发送,对弱网的WiFi环境对通话质量影响很大。

Pacer的目的就是让视频数据按照评估码率均匀的在各个时间片发送出去。如下图所示:

实现原理

2、设计PACER模块主要解决三个问题:怎么发送报文、什么时候发报文、每次发多少数据量。


2.1怎么发送报文

音频、视频、NACK、FEC、Padding报文都要统一从Pacer模块发送。若不区分报文优先级,势必会对系统延时产生很大影响。

所以音视频编码数据RTP切分打包后,首先将RTP报文存在pace queue队列,并将报文元数据(packet id, size, timestamp, 重传标示)送到pacer queue进行排队等待发送,插入队列的元数据会进行优先级排序。

pace queue是一个基于优先级排序的多维链表,它并不是一个先进先出的fifo,而是一个按优先级排序的list。报文优先级规则是:

  • 优先级高的报文排在fifo的前面,低的排在后面;

  • 首先判断报文的priority等级,等级越小的优先级越高(priority等级根据报文类型进行分类);

  • 然后判断重发标示,重发的报文比普通报文的优先级更高;

  • 最后是判断视频帧timestamp,越早的视频帧优先级更高。

Pacer每次触发发送事件时先从queue的最前面取出优先级最高的报文进行发送,这样做的目的是让视频在传输的过程中延迟尽量小,重传的报文尽快能到达防止等待卡顿。pace queue还可以设置最大延迟,如果超过最大延迟,会计算queue中数据发送所需要的码率,并且会把这个码率替代target bitrate作为budget参考码率来加速发送。(最大延时详细处理流程会在后文中介绍)

根据报文类型确定数据优先级处理函数如下:

int GetPriorityForType(RtpPacketMediaType type) { // Lower number takes priority over higher. switch (type) { case RtpPacketMediaType::kAudio: // Audio is always prioritized over other packet types. return kFirstPriority + 1; case RtpPacketMediaType::kRetransmission: // Send retransmissions before new media. return kFirstPriority + 2; case RtpPacketMediaType::kVideo: case RtpPacketMediaType::kForwardErrorCorrection: // Video has "normal" priority, in the old speak. // Send redundancy concurrently to video. If it is delayed it might have a // lower chance of being useful. return kFirstPriority + 3; case RtpPacketMediaType::kPadding: // Packets that are in themselves likely useless, only sent to keep the // BWE high. return kFirstPriority + 4; } RTC_CHECK_NOTREACHED();}

按照优先级POP数据处理函数如下:

bool RoundRobinPacketQueue::QueuedPacket::operator<( const RoundRobinPacketQueue::QueuedPacket& other) const { if (priority_ != other.priority_) return priority_ > other.priority_; if (is_retransmission_ != other.is_retransmission_) return other.is_retransmission_;

return enqueue_order_ > other.enqueue_order_;}

2.2 什么时候发报文

PacingController::ProcessPackets按照PacingController::NextSendTime控制的节奏周期调用。完成PACER平滑发送功能。

PacingController::NextSendTime在控制发送节奏上,有两种模式kPeriodic、kDynamic。这里先介绍kPeriodic实现方式。kPeriodic模式下,固定每隔5ms调用一次发送报文任务。

constexpr TimeDelta kDefaultMinPacketLimit = TimeDelta::Millis(5);

2.3每次发多少数据量

PacingController::ProcessPackets被定时触发后,会计算当前时间和上次被调用时间的时间差,然后将时间差参数传入media_budget,media_budget算出当前时间片网络可以发送多少数据,然后从pacer queue当中取出报文元数据进行网络发送。

media_budget_根据评估出来的参考码率计算这次定时事件能发送多少字节的公式如下:

delta time:上次检查时间点和这次检查时间点的时间差。

target bitrate:pacer的参考码率,是由probe模块根据网络探测带宽评估出来的。

remain_bytes:每次触发发包时会减去发送报文的长度size,如果remain_bytes > 0,继续从pace queue中取下一个报文进行发送,直到remain_bytes <=0 或者 pace queue没有更多的报文。

如果pacer queue没有更多待发送的报文,但media_budget_计算出还可以发送更多的数据,这个时候pacer会进行padding报文补充

3、Pacer模块引入延时规避方法max_pacing_delay:


Pacer模块定量计算发送网络报文数据量,相当于cache等待发送,必然会引起延迟。为了保证实时性,Pacer模块有个max_pacing_delay全局变量,配置最大缓冲发送延时时间上限,若最大缓冲延时大于该值,就要重新调整Pacer模块的目标码率,保证当前数据都能及时发送出去。

max_pacing_delay生效流程如下:

VideoSendStreamImpl::VideoSendStreamImpl配置到transport->SetQueueTimeLimit

void PacingController::SetQueueTimeLimit(TimeDelta limit) { queue_time_limit = limit;}

PacingController::ProcessPackets会实时计算当前处理方式会引入的系统延时,当延时大于设定目标上限值,需要及时调整Pacer目标码率,保证Pacer模块引入延时时间可控。

很明显这仅仅是一个迫不得己的规避方法,实际应用中,这种方法会出现码率梯度上升现象。

编码算法码控模块配合:

Pacer模块实现不复杂,但是要想真正做好Pacer功能,仅仅靠一个Pacer模块是玩不转的,需要与视频编码器的码控模块配合:

  • 首先探测模块配置码率给编码器,编码器一定要保证在可控周期内码率收敛到配置的码率参数值以内,否则会给Pacer模块造成的累计延时越来越大压力;

  • 另外IP帧rate也要在合理范围内。若I帧超大,势必导致关键帧传输延时变大,影响端到端系统延时。

这些参数都要根据自己的实际应用场景进行调优。

原文https://zhuanlan.zhihu.com/p/484689876

★文末名片可以免费领取音视频开发学习资料,内容包括(FFmpeg ,webRTC ,rtmp ,hls ,rtsp ,ffplay ,srs)以及音视频学习路线图等等。

见下方!↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

算法练习(八)区域搜索

一、腐烂的橘子 1、题目描述&#xff1a; 在给定的 m x n 网格 grid 中&#xff0c;每个单元格可以有以下三个值之一&#xff1a; 值 0 代表空单元格&#xff1b; 值 1 代表新鲜橘子&#xff1b; 值 2 代表腐烂的橘子。 每分钟&#xff0c;腐烂的橘子 周围 4 个方向上相邻 的…

从零开始:学习使用 Hugo 构建自己的静态网站

1、什么是 Hugo 1.1、简介 Hugo 是一个由 Go 语言编写的静态网站生成器。它可以帮助用户快速构建高性能的静态网站&#xff0c;特别是博客、文档和个人网站等。与其他静态网站生成器相比&#xff0c;Hugo 的特点是速度快、易于使用、可扩展性强等。Hugo 使用简单的 Markdown …

【项目】游戏-我在万科转生成了一只狗

文章目录学习unity一些基操..位置坐标系父子关系常用工具导入游戏模型资源商店创建地形为地形化妆--纹理绘制脚本组件脚本的生命周期脚本执行顺序标签和图层的作用向量的运算和意义欧拉角和四元数-常用C#预制体-类与对象Debug的使用C#物体属性使用游戏时间使用-C#计时器的设置路…

无需手动编码的XGBoost中的分类特征

无需手动编码的XGBoost中的分类特征 XGBoost 是一种基于梯度提升的基于决策树的集成机器学习算法。 然而&#xff0c;直到最近&#xff0c;它还没有原生支持分类数据。 在将分类特征用于训练或推理之前&#xff0c;必须对其进行手动编码。 在序数类别的情况下&#xff0c;例如…

视觉SLAM十四讲ch4 李群和李代数笔记

视觉SLAM十四讲ch4 李群和李代数视觉SLAM十四讲ch4 李群和李代数李群和李代数基础指数映射与对数映射李代数求导与扰动模型视觉SLAM十四讲ch4 李群和李代数 李群和李代数基础 可以将SO3看成旋转矩阵集合&#xff0c;SE3看成变换矩阵集合 李代数是6个自由度的向量空间…

qsort函数的应用以及模拟实现

前言 &#x1f388;个人主页:&#x1f388; :✨✨✨初阶牛✨✨✨ &#x1f43b;推荐专栏: &#x1f354;&#x1f35f;&#x1f32f; c语言进阶 &#x1f511;个人信条: &#x1f335;知行合一 &#x1f349;本篇简介:>:介绍库函数qsort函数的模拟实现和应用 金句分享: ✨追…

Docker之部署Mysql

通过docker对Mysql进行部署。 如果没有部署过docker&#xff0c;看我之前写的目录拉取镜像运行容器开放端口拉取镜像 前往dockerHub官网地址&#xff0c;搜索mysql。 找到要拉取的镜像版本&#xff0c;在tag下找到版本。 拉取mysql镜像&#xff0c;不指定版本数&#xff0c…

04 Android基础--RelativeLayout

04 Android基础--RelativeLayout什么是RelativeLayout&#xff1f;RelativeLayout的常见用法&#xff1a;什么是RelativeLayout&#xff1f; 相对布局&#xff08;RelativeLayout&#xff09;是一种根据父容器和兄弟控件作为参照来确定控件位置的布局方式。 根据父容器定位 在相…

JavaWeb--RequestResponse

Request&Response1 Request和Response的概述2 Request对象2.1 Request继承体系2.2 Request获取请求数据2.2.1 获取请求行数据2.2.2 获取请求头数据2.2.3 获取请求体数据2.2.4 小结2.2.5 获取请求参数的通用方式2.3 IDEA快速创建Servlet2.4 请求参数中文乱码问题2.4.1 POST请…

智能家居Homekit系列一智能通断开关

智能通断器&#xff0c;也叫开关模块&#xff0c;可以非常方便地接入家中原有开关、插座、灯具、电器的线路中&#xff0c;通过手机App或者语音即可控制电路通断&#xff0c;轻松实现原有家居设备的智能化改造。 随着智能家居概念的普及&#xff0c;越来越多的人想将自己的家改…

WebRTC系列分享 | WebRTC视频QoS全局技术栈

概述目前总结出WebRTC用于提升QoS的方法有&#xff1a;NACK、FEC、SVC、JitterBuffer、IDR Request、Pacer、Sender Side BWE、Probe、VFR&#xff08;动态帧率调整策略&#xff09;、AVSync&#xff08;音视频同步&#xff09;、动态分辨率调整。这几种方法在WebRTC架构分布如…

上海亚商投顾:沪指窄幅震荡 ChatGPT概念再度走高

上海亚商投顾前言&#xff1a;无惧大盘涨跌&#xff0c;解密龙虎榜资金&#xff0c;跟踪一线游资和机构资金动向&#xff0c;识别短期热点和强势个股。市场情绪沪指今日窄幅震荡&#xff0c;创业板指低开低走&#xff0c;午后跌幅扩大至1%&#xff0c;宁德时代一度跌近4%。6G概…

【架构师】零基础到精通——微服务治理

博客昵称&#xff1a;架构师Cool 最喜欢的座右铭&#xff1a;一以贯之的努力&#xff0c;不得懈怠的人生。 作者简介&#xff1a;一名Coder&#xff0c;软件设计师/鸿蒙高级工程师认证&#xff0c;在备战高级架构师/系统分析师&#xff0c;欢迎关注小弟&#xff01; 博主小留言…

【java基础】一篇文章彻底搞懂lambda表达式

文章目录lambda表达式是什么lambda表达式的语法函数式接口初次使用深入理解方法引用 :: 用法快速入门不同形式的::情况1 object::instanceMethod情况2 Class::instanceMethod情况3 Class::staticMethod对于 :: 的一些示例及其注意事项构造器引用变量作用域使用外部变量定义内部…

web自动化 基于python+Selenium+PHP+Ftp实现的轻量级web自动化测试框架

1、 开发环境 win7 64 PyCharm 4.0.5 setuptools-29.0.1.zip 下载地址&#xff1a;setuptools-29.0.1.zip_免费高速下载|百度网盘-分享无限制 官方下载地址&#xff1a;setuptools PyPI python 3.3.2 mysql-connector-python-2.1.4-py3.3-win64 下载地址&#xff1a;mysq…

企业 Active Directory 自助服务

您的企业是否正在寻找一个全面的 Active Directory 自助服务解决方案&#xff0c;使用户能够在没有帮助台帮助的情况下满足自己的 Active Directory 需求&#xff1f;ADSelfService Plus 了解您的安全问题&#xff0c;并提供基于审批的自助服务工作流功能&#xff0c;使管理员能…

内网vCenter部署教程一

PS&#xff1a;因为交换机链路为trunk&#xff0c;安装先登录ESXI&#xff0c;将端口组改为管理vlan ID&#xff08;1021&#xff09; 一、双击镜像&#xff0c;打开文件夹&#xff0c;目录为F:\vcsa-ui-installer\win32&#xff0c;双击installer.exe 二、先设置语言为中文 三…

机器学习笔记之狄利克雷过程(三)随机测度的生成过程(折棍子过程)

机器学习笔记之狄利克雷过程——随机测度的生成过程[折棍子过程]引言回顾&#xff1a;狄利克雷过程——定义随机测度的生成过程从随机测度的生成过程观察标签参数α\alphaα与随机测度离散程度之间的关系引言 上一节使用公式推导的方式介绍了狄利克雷过程中标量参数α\alphaα…

云服务器ECS 什么是云服务器ECS?

云服务器ECS&#xff08;Elastic Compute Service&#xff09;是阿里云提供的性能卓越、稳定可靠、弹性扩展的IaaS&#xff08;Infrastructure as a Service&#xff09;级别云计算服务。 云服务器ECS免去了您采购IT硬件的前期准备&#xff0c;让您像使用水、电、天然气等公共…

【线性DP】猴子与香蕉

可恶&#xff0c;就差一点就能独立写出这道题了&#xff01;4548. 猴子和香蕉 - AcWing题库题意&#xff1a;思路&#xff1a;设计状态的时候一开始不知道怎么设&#xff0c;后来试了一下发现这样设很合理因此在设状态的时候很多时候都要试一试当时间或空间吃不消时&#xff0c…