概念
mediasoup 是完全兼容webrtc的高性能sfu服务器, 它由ts语言实现的master端和基于libuv的c++语言实现的work模块组成.
严格意义上来说,Mediasoup是单进程的。但这不影响了它的性能。实际上,它是使用单进程的方式将服务器上CPU某个核充分利用好,然后在业务层控制进程的个数。比如说你的服务器是个 8 核的CPU,那么在业务层你就可以启动 8 个Mediasoup进程。通过这种方式来达到对 CPU 的充分利用。
特性
- 支持IPV6
- ICE/DTLS/RTP/RTCP 既可以使用TCP协议,也可以使用UDP协议
- 支持simulcast(多流发送)和SVC(分层编码)
- 支持拥塞控制
- 带宽评估
- 支持STCP协议(非音视频数据)
- 多路复用同一个通道,减少端口的占用
- 性能优越(底层C++, 使用进程libuv 异步I/O处理机制)
架构说明
worker
一个worker代表一个运行在单核CPU上并处理Router实例的mediasoup C++子进程.
Router
router用于注入、选择和转发通过transport实例创建的媒体流.
Transport
transport将终端与mediasoup连接起来, 并通过在其上创建producer和consumer实例实现双向媒体流传输.
transport分三种: WebRtcTransport、PlainRtpTranspo、PipeTransport.
-
WebRtcTransport : 主要用于客户端(浏览器或其他客户端)之间通信, 为了保证安全, 这种传输数据一般是加密的, 安全机制较为复杂.
-
PlainRtpTransport : 用于普通的或自定义的rtp数据传输, 例如 与基于gstreamer实现的混流服务器 或者kurento服务器通信.
-
PipeTransport : 用于不同worker下的router进行通信, 应用场景为房间之间的互联.
Producer
一个Producer代表着一个被注入到MediaSoup Router的音频或视频源.它是在定义媒体数据包传送方式的Transport之上创建的.
Consumer
一个Consumer代表着一个被MediaSoup Router转发到终端的音频或视频源.它是在定义媒体数据包传送方式的Transport之上创建的.
-
每个worker里有多个router
-
每个worker里都有一个channel与C++进行通信
-
每个用户的transport可能会有多个producer和consumer
-
每个client创建两个peer connection分别用于发送和接收媒体流, 发送端用于发送承载本地videotrack 和audiotrack的localStream. 接收端接收来自其他client的remote Stream.
-
同时room会给每个client创建一个peer, peer管理两个transport用于接收和发送媒体流 peer.data.transports.set(transport.id, transport).
-
consumer通过producer ID订阅媒体数据.
JS目录
AudioLevelObserver.js
用于检测声音的大小, 通过c++检测音频声音返回给应用层, 通过observer接收并展示.
Channel.js
用于与C++ 部分通信, 外部调用ts的命令, 例如: 创建router, 最后通过channel把命令发送给worker并执行.
Consumer.js
媒体数据消费者, 消费音频/视频数据
DataConsumer.js
非媒体数据消费者, 可用于文本/文件传输
EnhancedEventEmitter.js
EventEmitter的封装, C++底层向上层发送事件.
PipeTransport.js
用于router之间的数据传输.
PlainTransport.js
普通的rtp传输通道, 例如 ffmpeg等不经过浏览器rtp协议的数据传输.
Router.js
代表一个房间或者一个路由器, 管理着各种transport.
RtpObserver.js
RTP数据的观察者.
Transport.js
各种transport的基类.
WebRtcTransport.js
浏览器/native客户端使用的传输.
Worker.js
一个节点或者一个进程, 实际应该是进程, 代码中根据CPU核数启动相对应地worker数量, 一个房间只能在一个房间里, 但是可以通过pipeTransport进行跨worker的通信.
ortc.js
其与SDP相对应, 以对象的形式标识sdp, 如 编解码参数、编解码器、帧率等, 以对象方式存储.
supportedRtpCapabilities.js
对通信能力的支持, 也是媒体协商相关的内容, 例如 支持的编解码器的种类、格式、各种参数.
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端。
TransportTuple很多可选项存储在IceServer里,一对多的关系,TransportTuple如果是Tcp连接那么里面还包含了::TcpConnection, 其与 ::TcpServer又有关系,它包含了多个::TcpConnection.