【流媒体服务器Mediasoup】 源码中重要类基本概念 、上层代码作用详解、底层C++类关系详解(四)_gjy_it的博客-程序员宅基地

技术标签: webrtc  源码分析  流媒体  mediasoup  

目录

 

前言     

MediaSoup的特性 

特性一

特性二

特性三

 

MediaSoup SFU简单的架构说明

MediaSoup库中Lib目录下的JS作用

MediaSoup-JS类的关系图

MediaSoup js部分起到的作用

MediaSoup C++ 库类关系图

核心类图

C++类图

小结


前言
     

      上篇文章对MediaSoup源码的调试方法  以及运行时分析、调试、查看核心信息   【流媒体服务器Mediasoup】调试源码以及运行时分析、调试、查看核心信息(三),本章节主要对MediaSoup的源码中重要类基本概念 、上层代码作用详解、底层C++类关系详解

      在下一篇文章中将继续对MediaSoup的源码进行分析和架构的讲解。

MediaSoup的特性 

特性一

  •       支持IPV6
  •       ICE/DTLS/RTP/RTCP    既可以在TCP协议上运行也可以在UDP协议上运行
  •       支持Simulcast(多流发送) 和 SVC(分层接收) 

特性二

  •        支持拥塞控制
  •        带宽评估  (Remb前几个章节有提到)
  •        支持STCP协议(非音视频数据 如文件,文本数据)

特性三

  •         多留使用同一个 ICE + DTLS 传输通道 (减少端口的占用)
  •         拥有强大的性能(底层是C++ 使用进程+LIBUV  异步I/O实践处理机制)

 

MediaSoup SFU简单的架构说明

              å¨è¿éæå¥å¾çæè¿°

Worker

  •       一个Worker代表着一个运行在单核CPU上并处理Router实例的mediasoup C++子进程;

Router

  •        Router用于注入、选择和转发通过Transport实例创建的媒体流;

Transport

  •        Transport将终端与MediaSoup Router连接起来,并通过在其上创建的Producer和Consumer实例实现双向媒体传输,实         现了下面3种Transport:WebRtcTransport,PlainRtpTransport,PipeTransport.
  1.       每个Client创建两个Peerconnection分别用于发送和接受媒体流,发送端用于发送承载本地videoTrack和audioTrack的      localStream,接收端接受来自其他Client的remoteStream;
  2.       同时Room会为每个Client创建一个Peer,Peer管理两个Transport用于接受Client的媒体流和向Client发送媒体流;
  3.      Peer为对应的Client发送的videoTrack和audioTrack分别创建一个Producer(共2个);
  4.      Peer为其他两个Client发送的videoTrack和audioTrack分别创建2个Consumer(共2个);
  5.      Producer将媒体数据发送给每一个订阅者Consumer
  6.     Consumer代表着一个被MediaSoup Router转发到终端的音频或视频源。它是在定义媒体数据包传送方式的Transport之上创建的。

 

MediaSoup库中Lib目录下的JS作用

               

        lib库需要先npm install   编译过后才会出现详细请参阅

                  【流媒体服务器Mediasoup】环境部署与demo搭建(二)

        npm install后 lib 库的路径为

                    server\node_modules\mediasoup\lib

                                                                  

AudioLevelObserver.js  

          用于检测声音的大小, 通过C++检测音频声音返回应用层,通过Observer接收并展示音频大小

Channel.js

          主要用于与C++部分信令通讯

Consume.js

      消费媒体数据,音频或视频

EnhancedEventEmitter.js

      EventEmitter的封装,C++底层向上层发送事件

Logger.js

      用于写日志

PipeTransport.js

      Router之间的转发

PlainRtpTransport.js

      普通的rtp传输通道,如FFmpeg等不经过浏览器rtp协议的数据传输

Producer.js

     生产媒体数据,音频或视频

Routers.js

     代表一个房间或者一个路由器

RtpObserver.js

     Rtp数据的观察者 回调用的

Transport.js

     所有传输的的基类(父类)

WebRtcRtpTransport.js

  浏览器使用的传输

Worker.js

    一个节点或者一个进程,实际应该是进程,代码中根据CPU核数启动相对   应的Worker数量;一个房间只能在一个Worker里。

Errors.js

     错误信息的定义

Index.js

     Mediasoup的库,上层引入Mediasoup最先导入的库,也为库的索引。

Ortc.js

     其与SDP相对应,以对象的形式标识SDP,如编解码参数,编解码器,帧   率等,以对象方式去存储。

ScalabilityModes.js

  一般不关心,略过

SupportedRtpCapabilities.js

  对通讯能力的支持,实际上是媒体协商相关的东西,如你支持的帧率, 码率,编解码器是什么等

Utils.js

       一些常见的工具函数

 

MediaSoup-JS类的关系图

 

                            

  • 每个Worker里有多个Router
  • 每个Worker里都有一个Channel(管道) 通过其与C++进行通讯
  • 每个用户的Transport可能会有多个Produces或者 Consume
  • ransoprt为WebRtcTransport(浏览器加密数据使用的传输)、PlainRtpTransport(自定义Rtp数据,如FFmpeg推流使用的传输)、PipeTransport(不同Router之间的通信传输)的基类

MediaSoup js部分起到的作用

  • 起到管理作用,通过上图可以看出各个模块之间的关系
  • 生成JSON字符串,传给C++; 作为承上启下的作用,即是应用层调用的接口层,又是C++层的适配层或者桥梁层,上层应用与C++的一个桥梁。

例如

 createRouter({ mediaCodecs, appData = {} } = {}) {
           ....            
            yield this._channel.request('worker.createRouter', internal);
            const data = { rtpCapabilities };
            const router = new Router_1.Router({
                internal,
                data,
                channel: this._channel,
                appData
            });
          .....
    }

 ..channel.request()最后会构造json字符串通过channel 传给C++层,C++层则做它自己相对应的逻辑操作.

 

MediaSoup C++ 库类关系图

   对于C++库来说是整个MediaSoup库中最核心的部分,包括了基本的一些管理,这些管理或者关系相对于JS来说要少一些,但最主要的是流的传输,首先对于WebRtc 要先进行数据加密再传到服务端之后要对这些数据进行解密操作。另外包括整个数据的安全,它的验证机制是由C++部分进行验证的,包括流的流转,数据的流转,带宽的评估,发生丢包之后的通知客户端进行重传等操作都是有C++部分完成这些工作。

核心类图

                 

SimpleConsumer

        普通RTP数据的消费者,比如有音频流和视频流每个都是SimpleConsumer,没有按类型区分,音视频流都是一样的,最简单的consumer

PipeConsumer

        不同Worker之间Router之间的数据流转,则其为接收或者消费从另外一个Worker中的Router传过来的数据

SvcConsumer

        传输时一般分为3层(核心层、拓展层、边缘层)进行传输,则其处理消费多层数据

SimulcastConsumer

        当共享者使用的是多路流时,则使用其来接收

Consumer

        为上述模块的基类(父类)

WebRtcTransport

        主要用于浏览器之间的或者浏览器与其他终端进行通讯的,这种传输数据一般是进行加密的,为了保证数据安全,它有很多安全机制,安全机制较为复杂。

PlainRtpTransport

用于普通或者自定义的rtp数据传输

PipeTransport

不同Worker之间Router之间的数据传输

TransportTuple

包括了本地的Socket,远端的Soucket ,使用的是TCP还是UDP , 传输协议等信息存储地方

Transport

        各种传输的基类(父类)

 

C++类图

                 

RtpPack的起作用为对rtp数据包的一个分析,如Rtp包中有包头,拓展头,数据,对于数据协议或者解析都是它的工作

SeqManager对传输的数据重新进行排序和处理,相当于WebRtc客户端与服务端之间进行传输数据的时候 服务端要新产生一个流推送给客户端,整个顺序都是重新排的,某个SSRC所对应的起始位置是多少,后面的包都是以这个起始包基础上进行传输和排序递增

所有Consumer都包含了RtpStreamSend对象, 从服务端角度来说,消费数据等于把数据发送给其他客户端

Producer对于服务端来说,他要生产流数据则就是接受客户端传输来的数据,因此每个Producer会对应多个RtpStreamRecv,为什么会有多个接收流?有可能是丢包了,丢包重传的数据也是单独的一路流。RtpStreamRecv使用了NackGenerator(丢包的一个产生器),对于接受者来说,发送者发了100个包,那么接受者是知道丢了哪些包(通过SeqManager知道丢的哪些包), 如果短时间内可以通过NackGenerator对客户端通知 进行补包。

WebRtcTransport

可以使用UDP或者TCP来传输数据,这两种传输都用PortManager进行端口管理,Mediasoup的默认端口为4000~4999(不同woker[进程]可复用),管理如关口是否被占用等一些策略。具体的传输工作还是 handle目录下的::UdpSocket和 ::TcpServer来完成。UdpSocket和TcpServer只是做了一层封装。

使用了上述的数据连接之后,对于上层传输来说,DtlsTransport 使用了dtls协议对rtp数据包进行加密的传输,在DtlsTransport 会用到SrtpSession的 收与发。RembClient和RembServer主要用于带宽的评估,对于共享者来说MediaSoup它的WebRtcTransport就是一个Clinet端,对于消费者来说,它就是Server端。Remb只是其中一种带宽评估方法,还有其他,这里不做重点讲解。

TransportTuple很多可选项存储在IceServer里,一对多的关系,TransportTuple如果是Tcp连接那么里面还包含了::TcpConnection,  其与 ::TcpServer又有关系,它包含了多个::TcpConnection

 

小结

有很多人对 Nodejs 比较诟病,认为 Nodejs 提拱不了高性能的流媒体服务器。实际上,如果按照传输的 Nodejs 应用开发出的流媒体服务器肯定是不能胜任这项工作的。但对于 Mediasoup 来讲,它只不过使用 Nodejs 做 信令处理 及 业务的管理 工作,所以它的负担并不重。对性能要求高的是媒体数据流的转发工作,而这部分工作是由 Mediasoup(C++)部分实现的。Nodejs 与 Mediasoup之间通过管道进行通信。

严格意义上来说,Mediasoup是单进程的。但这不影响了它的性能。实际上,它是使用单进程的方式将服务器上CPU某个 充分利用好,然后在业务层控制进程的个数。比如说你的服务器是个 8 核的CPU,那么在业务层你就该启动 8 个Mediasoup进程。通过这种方式来达到对 CPU 的充分利用。

 

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/gjy_it/article/details/104474095

智能推荐

作业帮云原生降本增效实践之路_阿里巴巴中间件的博客-程序员宅基地

本文整理自作业帮基础架构负责人董晓聪在云原生实战峰会上的分享,讲解作业帮降本增效实践的道路上遇到的问题及经验,主要分为三个方面。一是作业帮的业务和现状,以及为什么要做降本增效。第二,如何和...

报错:ImportError: libmysqlclient.so.20: cannot open shared object file: No such file or director(亲测可用)_lxw1844912514的博客-程序员宅基地

启动jumpserver报错 ImportError: libmysqlclient.so.20: cannot open shared object file: No such file or directory。查找这个libmysqlclient.so.20库文件,由于本机之前部署了mysql,所以可以查到这个文件(如果没有的话,可以安装mysql来获取这个文件)(py3) [[email protected] jumpserver]# find / -name libmysqlclient.so.

oj系统java返回非零_你好,请教个java问题,返回非零问题_韭菜实验室的博客-程序员宅基地

你好,我在网上做一个pat的测试题,问题是转换百位数的格式输出,用字母B来表示“百”、字母S表示“十”,用“12...n”来表示个位数字n(<10),例如234应该被输出为BBSSS1234,因为它...你好,我在网上做一个pat的测试题,问题是转换百位数的格式输出,用字母B来表示“百”、字母S表示“十”,用“12...n”来表示个位数字n(<10),例如234应该被输出为BBSSS1...

在万米高空享受高速网络,霍尼韦尔与天地互联提供机上高速互联解决方案_美通社的博客-程序员宅基地

上海2021年8月17日 /美通社/ -- 霍尼韦尔(纳斯达克代码:HON)宣布与天地互联科技(广州)有限公司(天地互联)签署机上高速互联合作框架协议。霍尼韦尔先进的MCS-8420型号J...

【Node.js】 简介,入门案例,启动服务器、操作数据库功能的实现_Zhou_LC的博客-程序员宅基地

什么是Node.js介绍简单的说 Node.js 就是运行在服务端的 JavaScript。Node.js 是一个基于Chrome JavaScript 运行时建立的一个平台。Node.js是一个事件驱动I/O服务端 JavaScript 环境,基于Google的V8引擎,V8引擎执行Javascript的速度非常快,性能非常好。两部分使用者【前端程序员】:不懂得像PHP、Python或Ruby等动态编程语言,但又想创建自己的服务,那么可用 Node.js 。由于 Node.

如何在 PyFlink 1.10 中自定义 Python UDF?_阿里云云栖号的博客-程序员宅基地

我们知道 PyFlink 是在 Apache Flink 1.9 版新增的,那么在 Apache Flink 1.10 中 Python UDF 功能支持的速度是否能够满足用户的急切需求呢?Python UDF 的发展趋势直观的判断,PyFlink Python UDF 的功能也可以如上图一样能够迅速从幼苗变成大树,为啥有此判断,请继续往下看…Flink on Beam我们都知...

随便推点

一起来读书51- 计算机操作系统:第四章 存储器管理_狍子科技-贺汉景的博客-程序员宅基地

第四章 存储器管理存储器分层:cpu: 寄存器; 主存:高速缓存,主存,磁盘缓存; 辅存:磁盘,可移动介质;程序处理:编译->链接->装入链接方式:SL<静态链接>:事先进行链接...

linux拦截终端输入,Linux 终端输入控制_weixin_39777019的博客-程序员宅基地

涉及头文件:termios.h涉及结构:termios主要特性:行编辑:选择是否允许Backspace。缓冲:是立即读取还是缓冲读取Echo:比如读取密码的时候是否允许控制echo。struct termios {tcflag_t c_iflag;// 输入模式tcflag_t c_oflag; // 输出模式tcflag_t c_cflag; // 控制模式tcflag_t c_lflag; /...

金融法重点复习(整理)_-爱拼才会赢-的博客-程序员宅基地

结合《中国人民银行法》和《银行业监督管理法》对中国人民银行与银监会职责分工的规定,论述我国的银行监管体制。

ThreadLocal学习与使用_我是小佣兵的博客-程序员宅基地

1:什么是ThreadLocalThreadLoal 变量,线程局部变量,同一个 ThreadLocal 所包含的对象,在不同的 Thread 中有不同的副本。这里有几点需要注意:因为每个 Thread 内有自己的实例副本,且该副本只能由当前 Thread 使用。这是也是 ThreadLocal 命名的由来。 既然每个 Thread 有自己的实例副本,且其它 Thread 不可访问,那就...

2020.11.28【NOIP提高B组】模拟 总结_2020linweitong的博客-程序员宅基地

2020.11.28【NOIP提高B组】模拟 总结T1【2020.11.28提高组模拟】树(tree)不会做。竟然考构造题,一看就是结论。然而不知道subtask这么多有啥用,暴力都不会打。Update after contestlinli来讲的题,奆啊。kkk可以被表示为∏i=1nai!\prod_{i=1}^{n}{a_i!}i=1∏n​ai​!然后就构造了。T2【2020.11.28提高组模拟】签到题(signin)暴力。正解是啥?推了一波公式,发现越推越乱,呵呵呵。U

Go语言中slice在函数传递中的问题_nohysiwe的博客-程序员宅基地_golang slice引用传递

问题描述最初想这个问题是因为官方称 slice, map, 函数, 结构体为引用类型…当时就在想 引用类型 是指C++中 变量引用 一样的意思么,如果一样, 那不就是slice作为函数参数传递时就是像C++中的引用传递一样么, 和Python 也是一样的传递概念么。结果,经过试验,搜索相关的信息, 我发现, 官方的说什么引用类型简直就是坑知道C++的人, 而且我想吐槽下 Go 的设计者在设计这门语言时是不是满脑子想着我一定要与C/C++与众不同!!!!ε=(´ο`*)))唉, 学Go给我一种奇怪的感觉

推荐文章

热门文章

相关标签