13、MCU服务器搭建:基于Janus的MCU部署、视频混流与录制、插件机制
聊到WebRTC的多人通信,大家第一个想到的肯定是SFU。没错,SFU是目前的主流方案。但有些场景,比如大型直播、多人会议需要统一录制、或者客户端性能有限时,MCU方案反而更合适。
今天我们就来聊聊Janus这个开源MCU服务器。我最早接触Janus是在2017年,当时一个项目需要在浏览器端做多方视频通话,还要把所有人的画面合成一路录制下来。嗯,SFU搞不定这个,最后选了Janus。
13.1 Janus是什么?
Janus是一个轻量级的WebRTC网关,由Meetecho团队开发。它本身不只是一个MCU,更像是一个插件化的WebRTC服务器框架。
说白了,Janus的核心就是一个消息路由器和媒体转发引擎。它把各种功能拆成了插件,比如视频会议、流媒体播放、录音桥等。你需要什么功能,就加载什么插件。
核心特点:
- 插件架构,功能可扩展
- 支持MCU和SFU两种模式
- 内置视频混流(VideoRoom插件)
- 支持录制到文件
- RESTful API控制
我个人习惯把Janus比作瑞士军刀。它不追求极致性能,但胜在功能全面、部署简单。很多中小型项目用它做原型验证,非常方便。
13.2 Janus的架构与部署
先看看Janus的整体架构。我画了一张图,帮你快速理解它的工作方式。
部署Janus其实不复杂。我建议用Docker方式,省去编译的麻烦。
# 拉取Janus镜像
docker pull canyan/janus-gateway:latest
# 运行Janus容器
docker run -d --name janus \
-p 8088:8088 \
-p 8188:8188 \
-p 10000-10200:10000-10200/udp \
canyan/janus-gateway:latest
这里要注意端口映射:
- 8088:HTTP管理接口
- 8188:WebSocket接口
- 10000-10200:媒体端口(UDP)
小技巧:我在项目中习惯把媒体端口范围设大一点,比如10000-20000。因为多人会议时端口消耗很快,曾经遇到过端口不够用导致新用户连不上的情况。
13.3 VideoRoom插件:视频混流
VideoRoom是Janus最核心的插件。它实现了MCU模式下的视频混流功能。
什么叫混流?就是把多个人的视频画面合成一路视频流。比如4个人开会,每个人的画面被缩小后拼成一个2x2的格子,然后编码成一路视频发给所有参与者。
这样做的好处很明显:
- 客户端只需要解码一路视频,CPU消耗低
- 录制方便,直接录混流后的画面就行
- 带宽占用小,适合移动端
但缺点也有:
- 服务器压力大,需要做视频解码、合成、再编码
- 灵活性差,不能单独看某一个人的画面
我曾经在一个在线教育项目里用过这个方案。老师端只需要显示一路视频,里面包含了所有学生的画面。嗯,效果还不错,学生端的手机也不发烫。
13.3.1 创建视频房间
通过Janus的REST API创建房间:
POST /janus/<session_id>/<handle_id>
Content-Type: application/json
{
"janus": "message",
"body": {
"request": "create",
"room": 1234,
"description": "我的视频房间",
"publishers": 6,
"bitrate": 512000,
"videocodec": "h264",
"record": true,
"rec_dir": "/opt/janus/recordings"
}
}
参数说明:
| 参数 | 说明 | 我的建议 |
|---|---|---|
| room | 房间ID,唯一标识 | 用数字,方便管理 |
| publishers | 最大发布者数 | 根据服务器性能定,一般6-8人 |
| bitrate | 混流后的码率 | 512kbps够用,画质要求高可以设1M |
| videocodec | 视频编码器 | H.264兼容性最好 |
| record | 是否录制 | 开启后自动录混流视频 |
注意:如果开启录制,一定要确保rec_dir目录存在且有写入权限。我曾经因为忘记创建目录,导致录制功能静默失败,排查了半天才发现是目录问题。
13.3.2 混流布局配置
Janus支持多种混流布局。你可以通过配置来调整:
{
"request": "configure",
"video_orientation": 1,
"video_orientation_force": true,
"videomulticast": false,
"videocodec": "h264",
"bitrate": 512000,
"record": true,
"filename": "meeting_2024"
}
布局模式有几种:
- 自动布局:根据人数自动排列,1人全屏,2人左右分屏,4人2x2
- 固定布局:指定某个人为主画面,其他人缩小在角落
- 自定义布局:通过API动态调整每个画面的位置和大小
我个人比较喜欢自动布局,省心。但如果你做的是直播类应用,固定布局更合适,把主讲人放在大画面。
13.4 视频录制
Janus的录制功能非常实用。它会把混流后的视频直接写入文件。
录制文件格式是.mjr(Janus自己的格式),但你可以用工具转成.mp4:
# 安装转换工具
apt-get install janus-tools
# 转换录制文件
janus-pp-rec input.mjr output.mp4
这里有个坑要提醒你:
我曾经踩过的坑:录制文件默认保存在容器内部。如果容器重启,录制文件就丢了。一定要挂载外部目录到容器里。
docker run -d --name janus \
-v /data/recordings:/opt/janus/recordings \
-p 8088:8088 \
-p 8188:8188 \
-p 10000-10200:10000-10200/udp \
canyan/janus-gateway:latest
13.5 插件机制详解
Janus的插件机制是它的灵魂。说白了,Janus本身只做两件事:建立WebRTC连接和转发媒体数据。具体业务逻辑全交给插件。
常用的插件有:
| 插件名 | 功能 | 适用场景 |
|---|---|---|
| VideoRoom | 视频会议、混流 | 多人视频通话 |
| AudioBridge | 音频混流 | 语音会议、电话会议 |
| Streaming | 流媒体播放 | 直播推流、RTSP转WebRTC |
| RecordPlay | 录制与回放 | 会议录制、回看 |
| SIP | SIP网关 | 对接传统电话系统 |
如果你想开发自己的插件,Janus提供了C语言接口。不过说实话,开发门槛不低。我建议先用现成的插件组合,实在满足不了需求再考虑自定义插件。
13.6 实战:搭建一个简单的MCU会议
最后,我带你走一遍完整的流程。假设我们要搭建一个4人视频会议,开启录制。
第一步:启动Janus
docker run -d --name janus-mcu \
-p 8088:8088 \
-p 8188:8188 \
-p 10000-20000:10000-20000/udp \
-v /data/janus-recordings:/opt/janus/recordings \
canyan/janus-gateway:latest
第二步:创建房间
curl -X POST http://localhost:8088/janus \
-H "Content-Type: application/json" \
-d '{
"janus": "create",
"transaction": "1"
}'
拿到session_id后,再创建房间:
curl -X POST http://localhost:8088/janus/<session_id>/<handle_id> \
-H "Content-Type: application/json" \
-d '{
"janus": "message",
"body": {
"request": "create",
"room": 1001,
"publishers": 4,
"bitrate": 512000,
"record": true,
"rec_dir": "/opt/janus/recordings"
}
}'
第三步:客户端加入
客户端通过WebSocket连接到Janus,加入房间1001,发布自己的音视频流。Janus会自动进行混流,并把合成后的视频分发给所有参与者。
经验之谈:第一次测试时,建议先用两个浏览器窗口模拟两个人加入。确认混流和录制都正常后,再逐步增加人数。这样排查问题会快很多。
好了,关于Janus的MCU部署、视频混流和录制,就聊到这里。这套方案虽然不如SFU灵活,但在特定场景下非常实用。尤其是你需要统一录制、或者客户端性能受限时,Janus的MCU模式能帮你省不少事。