WebRTC Simulcast 大小流介绍与优化实践

server/2024/12/15 0:21:11/

Simulcast 是 WebRTC 中的一种标准化技术 ,简称大小流。通过 Simulcast,客户端可以同时发送同一视频的多个版本。每个版本都以不同的分辨率和帧率独立编码,带宽较多的拉流端可以接收较高质量的视频流,带宽有限的拉流端则可以接收较低质量版本的视频流,从而保障每个参会者都能有流畅的观看体验。在我们的视频会议产品中,支持参会者启用大小流功能,以提高整体会议质量。

1

2cfc34474ed6d6d90d3ea31f95ddf988.gif

为什么选择大小流

在网络条件较差的情况下,参会者难以获得稳定的连接来接收其他人发布的高质量视频流。实际场景中,很难确保每位参会者始终处于良好的网络环境。我们观察到,网络状况最差的参会者可能显著影响整个会议的流畅性,带来以下问题:

  1. 视频质量下降:慢速用户的下行链路(接收方向)可能出现大量数据包丢失,导致视频画质不稳定、出现黑屏或空白帧, 甚至造成严重的卡顿、延迟和画面不连贯。

  2. 网络拥塞加剧:下行带宽饱和会导致网络拥塞,进而影响用户上行发送自己视频画面的能力。这不仅影响该用户,还会降低其他参会者的使用体验。

  3. 关键帧带宽放大效应:在基于WebRTC协议的实时传输系统中,当客户端因数据包丢失无法渲染帧时, 会频繁向发布视频流的用户(通过SFU)发送PLI(图片丢失指示)消息。接收PLI的客户端会生成新的关键帧作为响应,这些关键帧需广播给所有参会者,显著增加会话的带宽需求。当总带宽需求超过其他参会者的网络承受能力时,这种增加可能引发级联效应,进一步恶化会议体验。

175b9aba6eb91b337095b4dee99d56f8.png

随着会议规模的扩大,网络状况较差的参会者出现的可能性也随之增加。为了保障大规模会议的流畅性,优化慢速网络环境下的媒体传输已成为会议架构的基本要求。会议系统需要能够快速调整视频流质量,以适应不同参会者的网络条件。

目前,业界主要采用三种方法来解决这一问题:转码、SVC(可伸缩视频编码)和 Simulcast(联播,大小流)。它们各有优缺点:

  1. 转码:转码通过实时生成适合下行链路的备用视频流,能够以近乎最佳的方式适配不同网络条件。但转码会显著增加服务器的计算负担,尤其在大规模会议中,其高成本使其性价比不佳。

  2. SVC:SVC允许单个视频流适配多种码率,避免了额外生成备用流的需求。然而,其主要问题在于编解码器的兼容性。SVC要求所有参会设备支持可扩展的编解码器, 但许多移动设备依赖的H.264硬件编解码并不支持SVC,导致广泛兼容性难以实现。

  3. Simulcast:通过客户端对同一视频源以多种码率编码,并将这些视频流并行发送至 SFU(选择性转发单元)。SFU 根据参会者的网络条件切换和转发合适的视频流。虽然 Simulcast 对服务器的压力较小,但是会略微增加客户端的编码负担及其上行带宽消耗(在下文的优化实践中会提到如何尽可能的抵消这个副作用)。

4dab6c07f7739eb1e4ce746c12bc2cd7.png

综合考虑,Simulcast 更具可扩展性和成本效益,因为它不需要服务器上的媒体编解码,也不需要视频编解码器中的专门功能。

2

8520662f9da4b64d7596663298dd28f7.gif

SFU如何支持大小流

我们可以回顾一下推流端只推一路流的时候,在 SFU 中的数据收发模型(我们在之前的文章 [视频云:级联SFU的设计与实现] 中详细介绍了我们自主研发的 SFU 如何实现和设计,欢迎再次回顾~),

9befe74310df9cd4f7b4f9db1f38183f.png

基于一路流的收发模型,我们进一步设计扩展出多路流的收发:

  1. 接收多路视频流:复用同一条推流 PC 上的轨道接收器,通过多次 OnTrack 事件的触发,构建多个 UpTrack,并利用每层视频流的不同 SSRC 分别构造与其一一对应的 Buffer, 来缓存不同视频层的 RTP 数据包。

  2. 区分不同层视频流进行下发:可以为 Downtrack 引入当前层、下发目标层、是否正在切层中等状态,使 SFU 能够准确地将不同视频层的数据包下发给拉流端,以及通过切层进行时状态等待新流的关键帧再进行切层,保障端上的流畅播放。

    62f93c81f7964db5d22cae1350108ea3.png

RTP包序列号和时间戳的重写

在 Simulcast 大小流模式下,发送端将其视频源的不同版本作为单独的 RTP 流传输给 SFU,每个流都具有唯一的同步源 (SSRC) 标识符。但是对于接收端来说,如果 SFU 直接切换流数据转发,接收端可能因不连续的时间戳或序列号丢弃包或解码失败。因此,实现大小流的无缝切换(如低、中、高质量流),SFU 需要对发往下行 RTP 数据包中的 SSRC、RTP 序列号和 RTP 时间戳字段进行改写,确保接收端能够连续解码和播放,避免因切换而导致丢包或解码失败。

以下是在 SFU 中实现的关键流程:

  1. 改写下发流 RTP 包的 SSRC、序列号与时间戳,并维护序列号和时间戳的连续性,保证接收端观察到的序列号和时间戳是逻辑上连续的,使接收端对流切换过程完全无感知:

    1. RTP SSRC:标识一组连续的 RTP 数据包流,在 SFU 中,传入的每一层 Simulcast 视频流(高/中/低) 都有唯一的 SSRC。如果需要将多个层(例如层 1、层 2 和层 3)在传出时当作一个层下发给拉流端,则必须将这些下发包的 SSRC 重写为相同的值。

    2. RTP 序列号:RTP 序列号用于为共享同一 SSRC 的 RTP 包排序。由于 Simulcast 每个传入层的包数量和序列号不同,无法直接转发多个层的包而不调整序列号。

      911bb36ab91091cec992c91cf3c06fa2.png

    3. RTP 时间戳:RTP 时间戳用于表示视频帧相对于基准时间的渲染时间。由于 WebRTC 为每一层分配了独立的基准时间,导致各层的时间戳不兼容。为合并多层数据,必须将传入层的时间戳重写为与传出层的基准时间一致。

  2. 切换新流下发时,SFU 必须等待接收到新流的关键帧后再开始转发,避免解码器因缺少参考帧而解码失败。

  3. 缓存改写后的包信息和源包信息(序列号、时间戳)之间的映射关系,便于在丢包时提供准确的重传支持,保障切换后的流畅性。

3

095ea2c62170a790733f4f651154cf8b.gif

在大小流模式下优化实践

3.1 拥塞检测/带宽估计

拉流端的网络一旦发生拥塞,会导致更高的丢包率,从而引发画面卡顿和音视频失真等问题。为了避免拥塞,我们必须确保 SFU 下发的数据保持在拉流端允许的带宽范围内。在我们自主研发的SFU中,目前主要采用TWCC策略进行拥塞控制和带宽估计(我们在之前的文章 [视频云服务质量(Qos)之抗丢包策略] 中详细介绍了TWCC的原理,欢迎再次回顾~)。

此外,我们的 SFU 还基于 TWCC 反馈报告指出的数据包延迟状态和丢包率,实现了通过拥塞信号的有限状态机,通过不同的网络拥塞状态,进一步调整视频轨道大小流的分配,以适应不同的网络情况。

  1. 引入 5 种状态表示当前网络拥塞情况:

    1. 无拥塞状态:正常网络。

    2. 预拥塞状态:表示可能即将发生拥塞。

    3. 拥塞状态:表明网络已发生拥塞。

    4. 预拥塞恢复中:拥塞的"预警"消失,用于短暂的状态过渡从而避免频繁状态切换。

    5. 拥塞恢复中:拥塞的"滞后"状态,用于短暂的状态过渡从而避免频繁状态切换。

  2. 拥塞检测时机,基于事件触发和时间触发:

    1. 事件触发:TWCC 组包反馈报告

    2. 时间触发:定时器

  3. 状态转移条件,基于拥塞信号和状态超时:

    1. 拥塞信号

      * numGroups 为包组数

      * duration 为所有包组里的发送时间跨度, 即 maxSendTime (最晚发送时间) - minSendTime (最早发送时间)

      * loss 丢包率

      e335c7a9436642e0932ddab80530fa31.png

    2. 状态超时

      1. 预拥塞恢复中状态:500ms 超时,转移到正常网络状态;

      2. 拥塞恢复中状态:3s 超时,转移到正常网络状态;

  4. 状态切换完整逻辑:

    6ee91ea70b07492e08fdbda12277ae4f.png

  5. 用一个例子来说明该状态机如何变化:

    1. 正常网络:TWCC 反馈报告显示数据包延迟正常,无丢包。

    2. 拥塞预警:TWCC 反馈报告延迟轻微升高或偶现丢包且超过阈值,触发 [可能拥塞] 信号,网络状态切换到 {预拥塞} 状态。

    3. 拥塞发生:TWCC 反馈报告延迟持续升高且丢包率持续变大且超过阈值,触发 [确定拥塞] 信号,网络状态切换到 {拥塞} 状态。

    4. 拥塞恢复阶段:延迟和丢包率下降,不再触发 [确定拥塞] 信号,但仍不完全稳定,进入 {拥塞恢复} 状态。

    5. 网络完全恢复:TWCC 反馈报告所有指标恢复正常,返回到正常网络。

3.2 大小流自动化编排

我们通过上面的方法在 SFU 中准确地的捕捉到了拉流端网络是否拥塞,在大小流模式下,SFU 可以利用拥塞状态迅速对拉流端进行轨道分配的调整,从而有效缓解带宽拥塞,提高观看体验和会议质量。

  1. 视频流自动化分配的核心挑战和解决思路

    1. 挑战 1:带宽变化的不可预测性

      解决思路:结合实时反馈动态调整轨道分配,既不能超出带宽,又不能过分保守。

    2. 挑战 2:轨道分配优先级冲突

      解决思路:结合不同产品形态,会议场景下,优先保障屏幕共享、主讲人视频画面,再公平分配其他普通参会者。

    3. 挑战 3:用户体验和带宽限制的平衡

      解决思路:在用户订阅带宽不足时,保证在画面连续性的同时,最大化流质量。

  2. 拥塞网络下视频流的主要分配策略

a. 策略1:拥塞状态下统一降层策略

分配原则:迅速降层,逐步提升。

核心流程:

  1. 优先将带宽分配给屏幕共享及其他高优先级(如主讲人等),如果剩余可用带宽为0或不足以分给其他任意一条小流,则暂停下发流,避免造成进一步的拥塞;

  2. 从最小流开始分配,优先保障小流的视频流畅性;

  3. 小流分配完毕后,如果仍有多余带宽,遍历小流逐一升层直至无可用带宽,以提高用户体验;

进一步优化实践:

  1. 当网络状态刚切换到拥塞时,带宽估计可能不够准确,导致流的分配方案也可能不是最优的,进而不足以减少拥塞。这个时候,我们通过持续监控 rtp 包收发速率变化且进行采样,并利用 Kendall's Tau 计算方法来分析数据包收发率的样本,可以得到网络传输效率的变化趋势呈「上升」还是「下降」 ,以确保即使在持续在拥塞状态下的带宽分配也和最新带宽估计一致,可以进一步调整分配从而缓解拥塞。

  2. 数据包收发速率可以被计算为 send delta / (recv delta + loss penalty),各参数具体解释为:

1.send delta:发送端相邻 rtp 包发送的时间间隔增量

2.recv delta:TWCC反馈报告接收端相邻 rtp 包接收的时间间隔增量

3.loss penalty:丢包惩罚加权,模拟丢失的数据包在队列中堆积时可能带来的排队延迟

rtp 包收发速率的趋势方向判定条件和阈值表以及相应动作,如下:

578f6353b80bf276409cea05ca59b662.png

b.策略2:拥塞状态下定期尝试升层策略

分配原则:一次尝试只提升一个轨道,优先级从远到近,确保资源分配的稳健和公平。

85a937ce19905058a4e56d7ca4176fca.png

核心流程:

  1. 计算当前通道的剩余带宽,如果没有,直接退出;

  2. 获取缺乏带宽分配的视频轨道, 按它们距离最大目标层的距离从远到近排序;

  3. 遍历排序后轨道尝试为其分配下一个更高的层

  4. 只要当前带宽满足一个轨道升层,则退出遍历,以免导致加剧拥塞;

c. 策略3:新增订阅轨道面临拥塞状态下带宽重分配策略

分配原则:合作性让渡,优先级从近到远。

d142a1c976c99824d176cf73b08a819c.png

核心流程:

  1. 计算不计入当前新增订阅轨道时的可用带宽余量,如果有余量,尝试提升轨道到最高层(遍历比当前层更高的层),直至找到满足条件的层级;

  2. 如果没有足够余量,尝试通过降低其他轨道层级释放带宽;

  3. 获取已分配带宽的视频轨道(屏幕共享除外),按它们距离最大目标层从近到远排序;

  4. 遍历轨道,计算可以通过降层释放的带宽;

  5. 如果累计释放的带宽满足当前新增订阅轨道的需求,对需要释放带宽的轨道进行降层,并将释放的带宽分配至新增订阅轨道;

  6. 如果可释放的带宽不足以分配给新增订阅轨道,则暂停下发该轨道的流;

4

e107a7000388f7a15da17c803f006b52.gif

端上的进一步优化

推流端(上行链路)

  • 推流端省流

    SFU 可以实时通过信令通道,每当订阅情况发生变化,则实时告知推流端,端上依据订阅情况,动态开启/暂停相关层级视频的编码,从而节省推流端上行带宽,减小大小流模式带来的副作用。

    d986cbfe80a55c98376105222af5838f.png

拉流端(下行链路)

  • 拉流端省流

    我们以常见的宫格式翻页的视频会议布局为例:

    对于当前页可见的视频轨道,端上实时追踪这些轨道所附加的视频元素大小,通过与 SFU 的实时信令通道进行反馈,从而获得 SFU 进行分析后认为质量更加合适的视频层(因为渲染轨道的视频元素的大小可能会有所不同,有时甚至会隐藏,总是获取高分辨率视频但仅将其渲染在比较小的框中将是极其浪费的)。而对于其他页不可见的视频轨道,端上可以通知 SFU 暂停下发不可见层的视频流数据。结合实际场景,交互式的实现拉流端获得自适应流的方式,从而节约拉流端的带宽,也一定程度上缓解了 SFU 的压力。

    95a99e7037f1d090d51c815193213752.png

  • 弱网场景下动态增加延迟,抵御频繁卡顿

    拉流端通过RTCRtpReceiver.jitterBufferTarget方法,可以支持动态调整jitterBufferTarget的大小(最大4000ms, 值越大,网络抖动的时候越不容易卡顿、延迟越大;反之缓冲器越小,网络抖动的时候越容易卡顿、延迟越低)。基于这种方式,端上可以依据 SFU 评估出来的网络质量评分,在网络情况越来越差的时候,动态增加延迟来降低卡顿的发生。


    推荐阅读:

     视频云服务质量(Qos)之抗丢包策略

     视频云:级联SFU的设计与实现

更多技术和产品文章,请关注👆

如果您对哪个产品感兴趣,欢迎留言给我们,我们会定向邀文~

360智汇云是以"汇聚数据价值,助力智能未来"为目标的企业应用开放服务平台,融合360丰富的产品、技术力量,为客户提供平台服务。
目前,智汇云提供数据库、中间件、存储、大数据、人工智能、计算、网络、视联物联与通信等多种产品服务以及一站式解决方案,助力客户降本增效,累计服务业务1000+。
智汇云致力于为各行各业的业务及应用提供强有力的产品、技术服务,帮助企业和业务实现更大的商业价值。
官网:https://zyun.360.cn 或搜索“360智汇云”
客服电话:4000052360
欢迎使用我们的产品!😊

http://www.ppmy.cn/server/150221.html

相关文章

【GitHub分享】you-get项目

【GitHub分享】you-get 一、介绍二、安装教程三、使用教程四、配置ffmpeg五,卸载 如果大家想要更具体地操作可去开源网站查看手册,这里只是一些简单介绍,但是也够用一般,有什么问题,也可以留言。 一、介绍 you-get是一…

go语言使用zlib压缩[]byte

在Go语言中,可以使用compress/flate和compress/zlib包来实现对[]byte数据的Zlib压缩。下面是一个简单的示例,展示如何使用这些包来压缩一个字节切片: go package main import ( "bytes" "compress/zlib" "fmt"…

财务数据分析优化 | 实战应用小浣熊

前言 随着大数据时代的到来,数据分析已经成为企业决策和战略规划的重要依据。作为数据分析师,每天都需要面对海量的原始数据,进行数据清洗、数据运算、趋势分析、预测性分析、比较分析、关联性分析和数据可视化等一系列复杂工作。为了提升工作…

Socket编程UDP

Socket–UDP 我们先认识udp接口&#xff0c;做一个小实验&#xff0c;实现udp通信 1. version1-udp通信 代码链接&#xff1a;gitee main.cc #include"udpserver.hpp" #include"log.hpp" #include<memory> void usage(std::string str) {std::cou…

前端成长之路:CSS字体、文本属性和引入方式

本文主要介绍CSS的字体属性和文本属性&#xff0c;最后再介绍CSS在HTML中的引入方式。 CSS字体属性 CSS Fonts&#xff08;字体&#xff09;属性能用于定义字体系列属性&#xff0c;包括但不限于字体大小、粗细、字体样式等。 字体系列 在CSS中使用font-family属性定义文本…

Qt多项目管理动态库使用(QMake)

要管理大型项目和对代码可以进行复用,可以在同一项目之中创建不同的模块&#xff0c;提供调用库的形式进行调用&#xff0c;实现各模块的分块编写和处理&#xff0c;下面介绍我自己写的一个demo&#xff0c;结合之前编写的一些组件实现。一共创建了两个项目&#xff0c;一个项目…

FPGA实现GTP光口数据回环传输,基于Aurora 8b/10b编解码架构,提供2套工程源码和技术支持

目录 1、前言工程概述免责声明 2、相关方案推荐我已有的所有工程源码总目录----方便你快速找到自己喜欢的项目我这里已有的 GT 高速接口解决方案 3、工程详细设计方案工程设计原理框图用户数据发送模块基于GTP高速接口的数据回环传输架构GTP IP 简介GTP 基本结构GTP 发送和接收…

安装 PostgreSQL

1.安装 PostgreSQL sudo yum install -y postgresql postgresql-serverrootlocalhost ~]# systemctl status postgresql.service ● postgresql.service - PostgreSQL database serverLoaded: loaded (/usr/lib/systemd/system/postgresql.service; disabled; vendor preset:…