目錄
前言
上篇文章對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.
- 每個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之上創建的。
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 的充分利用。