一. 介绍
在这篇博客我们介绍了如何使用 mediasoup-demo 搭建多人音视频聊天室,本文将介绍 mediasoup-demo 的启动流程以及信令交互流程。
mediasoup-demo 项目组成主要包括两部分:app,server。
app 目录存放客户端代码,主要包含了前端页面以及加入房间、退出房间、闭麦等与服务端的信令交互处理。
server 目录存放了服务端代码,主要负责启动 mediasoup 媒体进程、创建 websocket 监听信令消息并处理。
二. 启动流程
async function run()
{
// Open the interactive server.
await interactiveServer();
// Open the interactive client.
if (process.env.INTERACTIVE === 'true' || process.env.INTERACTIVE === '1')
await interactiveClient();
// Run a mediasoup Worker.
await runMediasoupWorkers();
// Create Express app.
await createExpressApp();
// Run HTTPS server.
await runHttpsServer();
// Run a protoo WebSocketServer.
await runProtooWebSocketServer();
// Log rooms status every X seconds.
setInterval(() =>
{
for (const room of rooms.values())
{
room.logStatus();
}
}, 120000);
}
interactiveServer
初始化与命令行交互的服务处理逻辑,mediasoup-demo server 启动后,用户可以通过命令行执行 node connect.js 与 server 进行交互。输入 help 可以查看用法,输入 usage 可以查看每个 mediasoup worker 进程的信息(例如 CPU 使用率,内存占用等),输入 dr 可以查看 worker 上的 router 信息等。
runMediasoupWorkers
mediasoup-demo server 启动时会拉起 mediasoup worker 子进程,worker 进程负责流媒体转发,启动的 worker 子进程数由配置文件的 numWorkers 决定,一般设置为 CPU 核数。
createExpressApp / runHttpsServer
启动 HTTPS 服务,并通过 express 注册一系列请求路径对应的处理逻辑,该服务主要是为了接收应用推流。
路径 | 方法 | 作用 |
/rooms/:roomId | GET | 获取 RTP 能力 |
/rooms/:roomId/broadcasters | POST | 创建一个广播实例 |
/rooms/:roomId/broadcasters/:broadcasterId | DELETE | 删除broadcasterId的广播实例 |
/rooms/:roomId/broadcasters/:broadcasterId/transports | POST | 创建transport通道连接 |
/rooms/:roomId/broadcasters/:broadcasterId/transports/:transportId/connect | POST | 与通道连接,主要是进行证书校验 |
/rooms/:roomId/broadcasters/:broadcasterId/transports/:transportId/producers | POST | 创建流生产者 |
/rooms/:roomId/broadcasters/:broadcasterId/transports/:transportId/consume | POST | 创建流消费者 |
/rooms/:roomId/broadcasters/:broadcasterId/transports/:transportId/produce/data | POST | 创建数据消费者 |
/rooms/:roomId/broadcasters/:broadcasterId/transports/:transportId/consume/data | POST | 创建数据生产者 |
runProtooWebSocketServer
启动 Websocket 服务,接收来自浏览器 Websocket 连接的消息。收到 Websocket 连接请求时会回调 protoo.WebSocketServer.on('connectionrequest') 注册的回调函数,请求信息包含 roomId 和 peerId。
mediasoup-demo server 首先创建 roomId 对应的房间管理结构信息,并通知 Worker 子进程创建相应的 router 进行流媒体路由管理。同时创建 peerId 管理该连接用户信息(例如存放 displayName, producers, consumers 等信息),并注册该用户请求相应的回调,所有 peer 的请求都会交给 Room.js 文件 _handleProtooRequest 进行处理。
三. 信令交互流程
Room.js 的 _handleProtooRequest 有许多 request.method 类型的请求处理,mediasoup-demo 支持的信令如下所示。
getRouterRtpCapabilities | 获取媒体能力 |
join | 加入房间 |
createWebRtcTransport | 创建WebRtc连接通道 |
connectWebRtcTransport | 与WebRtc通道建立连接关系 |
restartIce | 重启ICE |
produce / closeProducer | 创建/关闭生产者 |
pauseProducer / resumeProducer | 暂停/恢复生产者 |
pauseConsumer / resumeConsumer | 暂停/恢复消费者 |
setConsumerPreferredLayers | 设置更倾向的媒体层 |
requestConsumerKeyFrame | 请求关键帧 |
produceData | 生产数据 |
changeDisplayName | 更改显示用户名 |
getTransportStats | 获取传输通道统计 |
getProducerStats | 获取生产者统计 |
getDataProducerStats | 获取数据生产者统计 |
getDataConsumerStats | 获取数据消费者统计 |
applyNetworkThrottle | 设置网络限制 |
resetNetworkThrottle | 重置网络限制 |
用户加入房间过程涉及的信令交互流程如下所示:
getRouterRtpCapabilities
获取 RTC 媒体能力,主要包含 {kind, mimeType, preferredPayload, clockRate, channels, parameters, rtcpFeedback},含义为 {媒体类别,编码类别,倾向的 RTP 负载类型,时钟频率,通道数,一些编码类型的参数信息,RTCP 反馈报文}。
{
kind: 'audio',
mimeType: 'audio/opus',
clockRate: 48000,
channels: 2,
rtcpFeedback: [Array],
parameters: {},
preferredPayloadType: 100
}, {
kind: 'video',
mimeType: 'video/VP8',
clockRate: 90000,
rtcpFeedback: [Array],
parameters: {'x-google-start-bitrate' : 1000},
preferredPayloadType: 101
} ...
createWebRtcTransport
请求创建 WebRTC 传输通道。服务端将创建一个与该客户端的 WebRTC 通道连接,用户可以指定 forceTcp, producing, consuming, sctpCapabilities 等信息,成功创建后将返回给客户端 { id, iceParameters, iceCandidates, dtlsParameters, sctpParameters }。
字段 | 含义 |
id | 传输通道id |
iceParameters | ICE类型,ICE用户名,密码 |
iceCandidates | ICE候选者信息,包括ip,端口,协议类型,优先级等信息 |
dtlsParameters | 用于DTLS握手的证书指纹信息 |
sctpParameters | SCTP 配置信息 |
示例:{ id: ‘c0fe3f31-a764-40ff-88ff-69c14b83afda’,
iceParameters: { iceLite: true, password: ‘o9cg0zd0rp2sqgjgp2l5dga94qjlj1s1’, usernameFragment: '3cbvni43i0lr53in' },
iceCandidates: { foundation: ‘udpcandidate’, ip: '192.168.0.102', port: 43299, priority: 1076302079, protocol: 'udp', type: 'host' },
dtlsParameters: { fingerprints: [ {algorithm: 'sha-1', value: 'B6:B2:B3:DF:0B:EC:E5:3C:37:67:50:52:DA:B3:AD:4A:56:94:4D:84'}... ], role: 'auto' },
sctpParameters: { MIS: 1024, OS: 1024, isDataChannel: true, maxMessageSize: 262144, port: 5000, sctpBufferedAmount: 0, sendBufferSize: 262144 } }
join
加入指定房间,并携带用户名,设备,RTP,SCTP 能力信息。加入房间一方面是为了加入者获取已在房间内其他用户的信息,并成为房间已有流/数据生产者的消费者,另一方面是为了通知已在房间的用户该用户加入房间了。
connectWebRtcTransport
客户端上传通道 id 与 dtls 证书指纹与服务器该通道建立起连接关系。
produce
发送 produce 通知,设置房间内存在的用户订阅消费该 producer。