【流媒体服务器Mediasoup】 源码中重要类基本概念 、上层代码作用详解、底层C++类关系详解(四)

目录

 

前言     

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 的充分利用。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章