前言
MediaSoup的特性
特性一
特性二
特性三
MediaSoup SFU简单的架构说明
MediaSoup库中Lib目录下的JS作用
MediaSoup-JS类的关系图
MediaSoup js部分起到的作用
MediaSoup C++ 库类关系图
核心类图
C++类图
小结
上篇文章对MediaSoup源码的调试方法 以及运行时分析、调试、查看核心信息 【流媒体服务器Mediasoup】调试源码以及运行时分析、调试、查看核心信息(三),本章节主要对MediaSoup的源码中重要类基本概念 、上层代码作用详解、底层C++类关系详解
在下一篇文章中将继续对MediaSoup的源码进行分析和架构的讲解。
Worker
Router
Transport
- 每个Client创建两个Peerconnection分别用于发送和接受媒体流,发送端用于发送承载本地videoTrack和audioTrack的 localStream,接收端接受来自其他Client的remoteStream;
- 同时Room会为每个Client创建一个Peer,Peer管理两个Transport用于接受Client的媒体流和向Client发送媒体流;
- Peer为对应的Client发送的videoTrack和audioTrack分别创建一个Producer(共2个);
- Peer为其他两个Client发送的videoTrack和audioTrack分别创建2个Consumer(共2个);
- Producer将媒体数据发送给每一个订阅者Consumer
- Consumer代表着一个被MediaSoup Router转发到终端的音频或视频源。它是在定义媒体数据包传送方式的Transport之上创建的。
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
一些常见的工具函数
例如
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++层则做它自己相对应的逻辑操作.
对于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
各种传输的基类(父类)
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 的充分利用。