Licode—基于webrtc的SFU/MCU实现

news2024/12/25 13:33:48

1. webrtc浅析


webrtc的前世今生、编译方法、行业应用、最佳实践等技术与产业类的文章在网上卷帙浩繁,重复的内容我不再赘述。对我来讲,webrtc的概念可以有三个角度去解释:

(1).一个W3C和IETF制定的标准,约定了Web间实时音视频通信机制,通过该标准可开发基于浏览器的、无插件的web多媒体应用(一般是js),该标准仅设定了点对点无中心的实时会话场景,没有强制约束信令协议与内容,没有要求有媒体处理的中心服务器,主要目标是形成开发者与浏览器厂商良好的生态环境,并积极向HTML5靠拢争取被纳入进去;

(2).一群音视频算法和网络适应性算法,这些算法囊括了视频会议几乎所有的核心技术,包括音视频的采集、编解码、网络传输、播放显示、安全等功能,还提供了操作系统系统调用跨平台封装的实现,包含Windows,Linux,Mac,Android,iOS;

(3).一个开源工程,核心由c++实现,可通过修改、封装、提取代码等方式实现一套视频会议系统,客户端可实现为Web js、App或Windows应用程序等多种形式,服务端可实现包括业务外的所有服务,包括媒体服务、信令服务、穿墙服务、中继服务等等,这些服务稍微调整后可轻易支持分布式部署、容器部署、云部署等。

对webrtc的理解与使用,我认为有三个境界:

(1).能搭建一个简易的视频会议系统,其中客户端部分可以这样做: Windows端Mac端Linux(x86)端在自带的peerconnection client或libjingle改一下(取决于信令是http还是sip家族信令);Android/iOS端在apprtc或licodeAndroidClient及Licode-ErizoClientIOS改一下;web端用webrtc 自带js api实现一下。服务端部分可以这样做:信令服务器在apprtc的collider改一下;穿墙服务器用自带的stun server,turn server部署一下;中继服务器在自带的relay server改一下;媒体服务器在kurentos、licode、jitsi、Intel Collaboration Suite for WebRTC或janus改一下;如果需要和传统的SIP体系互通则在webrtc2sip改一下;如果需要关注实时通信过程中的延时、丢包、接通率、掉线率等质量问题,可以部署callstats来进行专业监测;把所有服务都再部署于云平台的多个虚拟主机上或阿里云的容器云服务,完成以上操作就搭建起初级规模的云上视频会议系统原型了。

(2).能提取、理解并使用webrtc的算法模块,即或将算法模块融入到自己的代码中,或将自己的算法添加至webrtc里作为开源贡献或自己产品的差异性优势。值得提取的算法模块包括音视频编解码与处理框架(vp8、vp9、voice engine、video engine),音视频采集呈现封装、音视频预处理(NetEq、NS、AEC、Video Jitter Buffer)、网络适应性(GCC算法、ARQ、FEC)、安全性(Dtls、Srtp/Srtcp)等,自己可添加的有视频编码模块(x265、nvenc、intel qsv、xavs2、以及其他定制化的网络传输策略)。

(3).能够结合基于rtmp-cdn/p2p等直播技术,构建既支持交互互动,又支持海量围观,可商用、能运营、易扩展、全兼容的音视频PaaS服务平台,完成一个多媒体通信的终极产品。

Licode是达到第一境界技术层面所需要了解的开源工程,它从webrtc代码中提取出了SFU/MCU媒体服务所用到的音视频、媒体传输、信令的功能代码,结合libnice与libav实现了ICE与媒体转发功能,并封装成了可被调用的js API,此外还用js实现了包含全局管理服务、数据库服务、业务逻辑服务与信令媒体的调用服务的业务代码。Licode实现了webrtc开源工程没直接实现的中心侧的媒体服务功能,并提供了简单的业务模型与分布式部署方式,从而得到了多媒体通信工程师的广泛关注。但是Licode的相关文档与资料非常少,故本文是在我个人观察运行调试代码后总结所写的,不正确之处希望在留言中能够得以指正。

2. Licode系统分析


2.1 系统架构


Licode的系统架构如下,有客户端和服务端,客户端包括ErizoClient和NuveClient,分别用来进行信令与音视频交互和业务操作,类似于终端和会控集成在一起;服务端包括Nuve、ErizoController、ErizoAgent和MessageBus,分别用来实现业务服务与全局管理服务、信令服务、媒体服务和服务通信,其中ErizoController类似于MC、ErizoAgent类似于MP。

图1 系统架构图

2.2 客户端与服务端交互流程


客户端与服务端的交互流程如下图所示,其中客户端代码集中在N.API.js与Client.js上,服务端代码集中在nuve.js与erizoController.js上。

图2 信令交互图

3. 系统组成与模块划分


3.1 系统组成


本系统组成仅指服务端的系统组成,包括Nuve业务管理服务,ErizoController信令服务,ErizoAgent媒体服务,ErizoJS媒体转发实体。个人觉得代码在文件命名与文件组织结构上比较乱,初学者不易理解,如erizo_controller文件夹包括了除nuve以及webrtc的js api之外的所有js代码,不仅仅是erizoController,此外webrtc核心部分命名为erizo,也让人与整个系统相混淆。系统组成如下图所示,一个Nuve管理多个ErizoController(以下简称EC),一个EC管理多个ErizoAgent(以下简称EA),一个EA管理多个ErizoJS(以下简称EJ),一个EJ就是一个SFU,封装了C++实现的webrtc、libav与libnice。

图3 服务端系统组成图

3.2 Nuve业务管理服务


图4 Nuve业务管理服务

图5 Nuve各模块用途及对应文件

此外,这篇文章Licode(二):Nuve源码分析 - CSDN博客 对Nuve做了更详细的分析。

3.3 ErizoController信令服务


图6 ErizoController信令服务

图7 ErizoController各模块用途及对应文件

3.4 ErizoAgent媒体服务


图8 ErizoAgent媒体服务

图9 ErizoAgent各模块用途及对应文件

3.5 ErizoJS媒体转发实体


图10 ErizoJS媒体转发实体

图11 ErizoJS各模块用途及对应文件

3.6 webrtc


由于webrtc工程代码本身非常庞大,编译工具也很独特,Licode并未全部引入,仅仅抽取了webrtc的部分代码,如下图所示

图12 webrtc各组件用途及对应目录

由此可见,所抽取的代码没有webrtc自带的音视频处理框架(voice engine/video engine/media engine),这是由于SFC只在RTP层进行转发并不解码,只需要check一下媒体流属性(如I帧头)即可。抽取代码的亮点在于将webrtc强大的抵抗网络时延和丢包的网络适应性算法和协议都提炼出来了,可以供广大研究视频传输的网络适应方向的开发者们单独学习、实验并快速集成到自己非webrtc-based的产品中来。

webrtc的网络适应性手段包括丢包重传(ARQ)、前向纠错(FEC)和拥塞控制(GCC),其中自动码率(ARC)在GCC中。对网络适应性有兴趣的朋友可对照代码看如下几篇博文:

(1). 丢包重传 (ARQ)

RFC4585 RTP/AVPF 传输层反馈;

RFC4588 4585补充 重传包格式;

RFC5104 4585补充 负载层反馈;

RFC5124 RTP/SAVPF

RFC5450 4585补充 Jitter报告

(2). 前向纠错 (FEC)

RFC2198 WebRTC中的前向纠错编码 - Red Packet

RFC5109 WebRTC 的前向纠错编码 - XOR FEC

(3). 带宽检测 (BWE)

传统的基于RTCP RR报文中丢包数来进行带宽检测的算法目前被认为是最low的了,因为属于事后处理;先进的算法是需要事前感知的(突发情况除外),假定带宽是逐渐变窄的,根据信号估计理论可以在网络链路发生丢包以前就监测到网络拥塞,

GCC草案

REMB草案

GCC算法与函数调用 WebRTC基于GCC的拥塞控制(上) - 算法分析 WebRTC基于GCC的拥塞控制(下) - 实现分析

带宽估计 WebRTC之带宽控制部分学习(1) ------基本demo的介绍

带宽检测 WebRTC 中的带宽侦测 - CSDN博客

接收缓冲区延迟估计 WebRTC视频接收缓冲区基于KalmanFilter的延迟模型

3.7 libav、libnice、libsrtp


libav是从ffmpeg分离出的开发者发布的开源工程,与早期ffmpeg有很大相似性,对于仅调用api的开发者来说就简单看成是代码量更小、第三方依赖库更少、编译更简单的轻量级ffmpeg吧。这个库在Licode编译过程中有处问题,Licode使用版本较旧的libav的接口,其中avcodec_alloc_frame和avcodec_free_frame都已经遗弃,改为av_frame_alloc/av_frame_free才可编译通过。

libnice库基于ICE协议实现的网络层库,Licode使用libnice库来实现端到端的ICE连接和数据流发送接收,以及candidates(候选地址)和SDP(媒体描述文件)的相互交换。

libsrtp库主要是是用来加密rtp/rtcp的。

4. 关键技术


4.1 网络收发流水线架构技术


网络收发或一个SFU实现,并非简单的从一个源地址收到若干个数据包再复制多份发送给多个目的地址,正如3.6所描述,除了需要堆栈式的ICE地址转换、DTLS/SRTP的解密,还需要流水线式的RTP/RTCP的丢包检测与重传、FEC处理、带宽检测与估计、包缓冲区调整以及平滑发送等若干个复杂步骤,这个流程在Licode代码中是通过Pipeline-Handler这样的架构实现的,由于webrtc仅提供底层算法并未提供SFU架构,所以我认为这种架构是Licode最重要的关键技术,可供未来想成为软件架构师的开发者参考学习。日后我也再详细分析这个架构,看看是否能抽象出一个新的设计模式来。

整个网络收发的层级模型图如下图所示,其中每一层右侧标注出了关键类。

图13 网络收发层级模型

Pipeline的类图如下图

图14 Pipeline相关类图

对Pipeline来说,需要全局管理、长时处理或非逐个包处理的流程,实现对象叫Service,包括Handler的管理、RTCP的计算与处理、当前状态的处理、网络质量的管理以及包缓冲的管理都是Service;而需要每次逐包处理的流程,实现对象叫Handler,包括19项Handler,其代码都位于erizo\src\erizo\rtp目录下

//新增全局处理的Service

pipeline_->addService(handler_manager_);

pipeline_->addService(rtcp_processor_);

pipeline_->addService(stats_);

pipeline_->addService(quality_manager_);

pipeline_->addService(packet_buffer_);

//新增单次处理的Handler

pipeline_->addFront(std::make_shared<RtcpProcessorHandler>());

pipeline_->addFront(std::make_shared<FecReceiverHandler>());

pipeline_->addFront(std::make_shared<LayerBitrateCalculationHandler>());

pipeline_->addFront(std::make_shared<QualityFilterHandler>());

pipeline_->addFront(std::make_shared<IncomingStatsHandler>());

pipeline_->addFront(std::make_shared<RtpTrackMuteHandler>());

pipeline_->addFront(std::make_shared<RtpSlideShowHandler>());

pipeline_->addFront(std::make_shared<RtpPaddingGeneratorHandler>());

pipeline_->addFront(std::make_shared<PliPacerHandler>());

pipeline_->addFront(std::make_shared<BandwidthEstimationHandler>());

pipeline_->addFront(std::make_shared<RtpPaddingRemovalHandler>());

pipeline_->addFront(std::make_shared<RtcpFeedbackGenerationHandler>());

pipeline_->addFront(std::make_shared<RtpRetransmissionHandler>());

pipeline_->addFront(std::make_shared<SRPacketHandler>());

pipeline_->addFront(std::make_shared<SenderBandwidthEstimationHandler>());

pipeline_->addFront(std::make_shared<LayerDetectorHandler>());

pipeline_->addFront(std::make_shared<OutgoingStatsHandler>());

pipeline_->addFront(std::make_shared<PacketCodecParser>());

pipeline_->addFront(std::make_shared<PacketWriter>(this));

4.2 分布式保活技术


Licode的系统设计如3.1所述,Nuve管理多个EC,EC管理多个EA,EA启动多个EJ进程;在资源上,Nuve负责EC的负载均摊,EC负责EA和EJ的负载均摊(毕竟EJ在EA内,EA除了监控OS性能并未太多其他工作),故Nuve需要EC分布式保活,EC需要EA分布式保活。Licode实现比较简单,代码可参考CloudHandler.js与ecCloudHandler.js。

例如Nuve每启动一个EC立刻分配id,并加入到ECList中,并在DB中写入id作为key,且在该key对应的value上进行累加,此后Nuve的秒级循环中不断check这个value并继续累加,如果超过阈值,则认为该EC失效,将此EC从list中删除。Nuve同时提供keepalive接口,EC通过RPC调用此接口不断对数据库中本id的value清零,从而实现了分布式保活。EC与EA间方法一样。

4.3 资源管理技术


这里定义的资源有三个含义:设备资源(设备简单分为发布设备、接收设备、收发设备)、内容资源(某地的实时视频或已录制视频)以及server处理能力余量(例如还能转发的路数,还能容纳的新成员)。

Licode的publish-subscribe模型将信令交互、内容管理(源站管理)、媒体分发三者分开,从而可实现多维度的资源管理。

Client 1 发的第一个信令仅起到了一个资源注册的作用,即room中存在Client 1的id了;

Client 1 发的第二个信令表明该id可以发布新内容了,内容为Stream 1;

Client 2 同理,room记录了Client 2的id与Stream 2;

Client 1发的第三个信令表明对Client 2的Stream 2内容感兴趣开始订阅了,于是启动了SFU过程;

Client 3加入room后,可以发布资源(Stream3),可以订阅资源(Stream1、Stream2),也可以什么都不做,因为任何在该room中注册的设备都可以pubilsh内容资源或subscirbe已publish的内容资源。完全解耦带来的好处是内容资源同设备资源一样也可以轻易管理了,在启动SFU过程中,server处理能力余量也能得到较好的管理。

H.323是紧耦合的,信令交互后必须开启媒体交互(电路交换的思维,信道容量有限,申请资源赶紧用,用完赶紧释放),对内容管理过于依赖于会议逻辑的实现,为了实现更灵活的互听互看,其逻辑会堆砌的很复杂。

然而好的方法也不是万能的,publish-subscribe的完全解耦虽带来极大的可扩展性,但对于某些传统业务更复杂了。比如MCU两个终端互看,就需要启动两个erizoJS,互相订阅发布,根据负载均摊的算法,可能两个erizoJS都不在一个erizoAgent里(不在同一台物理机或虚拟机上)。MCU轮询模式也稍复杂,轮询者需要不断的subscribe room中的发布者,发布者也要不断的去remove、add,切换速度比接收所有流+I Frame Check的传统方式要慢的多。

5. 总结


本文先介绍了自己对webrtc的概念理解与使用参考,接下来从系统架构、交互流程、系统组成与模块划分几个角度对Licode进行概要设计级别的分析,最后对自己觉得Licode比较有特色的三大技术,即网络收发流水线架构技术、分布式保活技术与资源管理技术进行了浅层次的解释。文中表述内容可能会有不准确之处,希望能与读者们交流并及时改正。

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

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

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

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

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

相关文章

项目成本管理中的常见误区及解决方案

做过项目的人都明白&#xff0c;项目实施时间一般很长&#xff0c;在实施期间总有很多项目结果不尽人意的问题。要使一个项目取得成功&#xff0c;就要结合很多因素一起才能作用&#xff0c;其中做好项目成本的管理就是最重要的步骤之一&#xff0c;下面列出了常见的项目成本管…

Python进阶-----高阶函数map() 简介和使用

目录 简介&#xff1a; ​编辑 示例&#xff1a; 示例&#xff08;1&#xff09;&#xff1a;输出map()函数返回值&#xff08;迭代器&#xff09;结果 示例&#xff08;2&#xff09;&#xff1a;与循环对比 示例&#xff08;3&#xff09;&#xff1a;字符串转列表 示…

第九届蓝桥杯省赛——7缩位求和

题目&#xff1a;在电子计算机普及以前&#xff0c;人们经常用一个粗略的方法来验算四则运算是否正确。比如&#xff1a;248 * 15 3720把乘数和被乘数分别逐位求和&#xff0c;如果是多位数再逐位求和&#xff0c;直到是1位数&#xff0c;得2 4 8 14 > 1 4 5;1 5 65…

【C++】类与对象(一)

文章目录1、面向过程和面向对象初步认识2、类的引入3、类的定义4、类的访问限定符5、类的作用域6、类的实例化7、计算类对象的大小8、this指针9、 C语言和C实现Stack的对比1、面向过程和面向对象初步认识 C语言是面向过程的&#xff0c;关注的是过程&#xff0c;分析出求解问题…

算法练习-排序(一)

算法练习-排序(一) 文章目录算法练习-排序(一)1 排序算法1.1 冒泡排序1.1.1代码1.2插入排序1.2.1代码1.3 选择排序1.3.1代码1.4归并排序1.4.1代码1.5 快速排序1.5.1 思路1.5.2 代码2 题目2.1 特殊排序2.1.1 题目2.1.2 题解2.2 数组中的第k个最大元素2.2.1 题目2.2.2 题解2.3 对…

【Linux学习】基础IO——系统调用 | 文件描述符fd | 重定向

&#x1f431;作者&#xff1a;一只大喵咪1201 &#x1f431;专栏&#xff1a;《Linux学习》 &#x1f525;格言&#xff1a;你只管努力&#xff0c;剩下的交给时间&#xff01; 基础IO&#x1f34e;文件操作&#x1f349;使用C接口进行文件操作&#x1f349;文件操作的系统调…

Ingress

Ingres 目录 文章目录Ingres目录本节实战1、Ingress是什么2、定义1.rules2.Resource3.pathType4.IngressClass5.TLS3、Ingress-controller1.什么是Ingress-controller2.其他ingress-controller控制器FAQ零碎ingress就是借用service实现服务发现机制关于我最后本节实战 无 1、…

MySQL基础(一)SQL分类、导入、SELECT语句,运算符

目录 MySQL安装以及相关工具 SQL分类 导入数据 最基本的SELECT语句 SELECT FROM 列的别名 去除重复行 着重号 查询常数 描述表结构 过滤数据&#xff08;重要&#xff09; 运算符 算数运算符 比较运算符 符号运算符 非符号运算符 逻辑运算符 位运算符 MySQL安…

【C++】继承与多态

目录前言1. 继承1.1 继承的概念1.2 继承的定义1.3 切片赋值1.4 继承中的作用域1.5 派生类的默认成员函数1.6 继承与友元、静态成员1.7 多继承、菱形继承、菱形虚拟继承1.7.1 区分单继承与多继承1.7.2 菱形继承1.7.3 菱形虚拟继承1.7.4 菱形虚拟继承的原理2. 多态2.1 概念2.2 多…

Elasticsearch实战之(商品搜索API实现)

Elasticsearch实战之&#xff08;商品搜索API实现&#xff09; 1、案例介绍 某医药电商H5商城基于Elasticsearch实现商品搜索 2、案例分析 2.1、数据来源 商品库 - 平台运营维护商品库 - 供应商维护 2.2、数据同步 2.2.1、同步双写 写入 MySQL&#xff0c;直接也同步往…

如何使用C2concealer生成随机化的C2 Malleable配置文件

关于C2concealer C2concealer是一款功能强大的命令行工具&#xff0c;在该工具的帮助下&#xff0c;广大研究人员可以轻松生成随机化的C2 Malleable配置文件&#xff0c;以便在Cobalt Strike中使用。 工具运行机制 开发人员对Cobalt Strike文档进行了详细的研究&#xff0c;…

【转载】2020融云:基于WebRTC的低延迟视频直播

原文直接访问本文是读书笔记。基于WebRTC的低延迟视频直播 需要学习rtp包的缓存设计,于是找到了这一篇文章rtp包缓存 如何适应直播需求?直播与实时通信的区别 流量更少: RTMP或者HLS主要基于TCP传输,WebRTC是基于UDP的传输, **UDP协议的头小。**TCP为了保证传输质量,因…

Zotero设置毕业论文/中文期刊参考文献格式

大家在使用zotero时很容易遇到的问题&#xff1a; 英文参考文献中有多个作者时出现“等”&#xff0c;而不是用"et al"引文最后面有不需要的DOI号&#xff0c;或者论文链接对于一些期刊分类上会出现OL字样&#xff0c;即[J/OL]作者名为全大写 本文主要解决以上几个…

string函数以及string常用接口

本文介绍的是C关键字string中一些重要用法&#xff0c;以及各种字符串序列的处理操作 ——飘飘何所似&#xff0c;天地一沙鸥 文章目录前言一、string&#xff08;字符串类&#xff09;二、string类对象的容量操作2.1 size/length2.2 capacity2.3 empty/clear2.4 resize/reser…

教你如何搭建设备-保养管理系统,demo可分享

1、简介1.1、案例简介本文将介绍&#xff0c;如何搭建设备-保养管理。1.2、应用场景设备管理员进行制定设备保养计划、记录设备保养信息、可以查看设备保养日历。2、设置方法2.1、表单搭建1&#xff09;新建表单【设备档案-履历表】&#xff0c;字段设置如下&#xff1a;名称类…

SSM SpringBoot vue 在线教学质量评价系统

SSM SpringBoot vue 在线教学质量评价系统 SSM 在线教学质量评价系统 功能介绍 首页 图片轮播展示 登录 学生注册 教师注册 督导注册 教师展示 教师详情 学生评价 课程信息 课程详情 提交选修该课 学生选课 学生留言 个人中心 后台管理 管理员或学生或教师或督导登录 个人中…

项目经理处理团队冲突 5大注意事项

1、在时间、场景、体验矩阵中的5种处理方式 第一种方式&#xff1a;强迫命令&#xff0c;即职位高的一方在不考虑对方感受的情况下&#xff0c;强迫职位低的一方接受自己的意见。这种处理方式的适用场景为重要且紧急&#xff0c;这种方式团队成员的体验感低。 第二种方式&#…

Linux 学习笔记(一):终端 和 Shell 的区别和联系

一、Linux 介绍 1、什么是 Linux Linux 就是一个操作系统&#xff0c;全称 GNU/Linux&#xff0c;是一种类 Unix 操作系统Linux 一开始是没有图形界面的&#xff0c;所有操作都靠 命令 完成。如 磁盘操作、文件存取、目录操作、进程管理、文件权限 等等&#xff0c;可以说 Li…

Android Handler机制(二) Handler 实现原理

一. 前言 接上一篇文章为什么设计Handler , 我们来继续讲解一下Handler的实现原理, 俗话说一个好汉三个帮, 接下来一步一步引入各个主角,并说明它们在Handler机制中扮演的角色和作用. 二. Handler实现原理 首先我们先确定一个结论: 使用 Handler 是希望它被实例化在哪个线程&a…

不同序列模型的输入和输出总结

不同序列模型的输入和输出总结 文章目录不同序列模型的输入和输出总结RNNLSTMGRURNN RNN 是迭代输出&#xff1a; 输入第一个 -> 输出第二个&#xff0c; 输入第二个 -> 输出第三个&#xff0c; 输出倒数第二个 -> 输出最后一个。 LSTM LSTM 也是迭代输出&#xff…