Janus WebRTC Gateway -- 从零搭建完整指南

本文档面向新手,手把手指导你在 Ubuntu 22.04 上从源码编译、配置并运行 Janus WebRTC 服务器。

所有编译产物安装在项目目录下的 local/,不污染系统目录,无需 root 权限即可运行。


目录

  1. [什么是 Janus](#什么是 Janus)
  2. 整体架构
  3. 环境准备
  4. 编译安装
  5. 项目结构
  6. 启动与停止
  7. 验证服务
  8. 配置详解
  9. 插件介绍
  10. [Janus API 入门](#Janus API 入门)
  11. 常见问题排查
  12. 进阶:生产环境部署
  13. 参考资料

1. 什么是 Janus

Janus 是由 Meetecho 开发的开源 WebRTC 服务器(Gateway) 。它本身不提供具体的音视频业务逻辑,而是充当一个通用的 WebRTC 信令和媒体中转框架,通过插件机制实现各种场景:

  • 多人视频会议(VideoRoom,SFU 模式)
  • 一对一视频通话(VideoCall)
  • 流媒体分发(Streaming)
  • 音频混音会议(AudioBridge,MCU 模式)
  • SIP 网关(对接传统电话网络)
  • 录制与回放(RecordPlay)

为什么选择 Janus:

  • C 语言编写,性能优秀,资源占用低
  • 插件架构灵活,可只加载需要的功能
  • 同时支持 HTTP REST 和 WebSocket 两种信令通道
  • 社区活跃,文档完善

2. 整体架构

复制代码
浏览器 / App
    │
    │  WebSocket (ws://localhost:8188)
    │  或 HTTP REST (http://localhost:8088/janus)
    │
    ▼
┌─────────────────────────────────────────┐
│            Janus Gateway                │
│                                         │
│  ┌──────────┐  ┌──────────┐            │
│  │ Transport │  │ Transport │  信令层    │
│  │  HTTP     │  │ WebSocket│            │
│  └────┬─────┘  └────┬─────┘            │
│       └──────┬───────┘                  │
│              ▼                          │
│  ┌─────────────────────────────┐        │
│  │       Janus Core            │  核心   │
│  │  (ICE / DTLS / SRTP / SDP) │        │
│  └──────┬──────────────────────┘        │
│         ▼                               │
│  ┌──────────┐ ┌──────────┐ ┌────────┐  │
│  │VideoRoom │ │EchoTest  │ │Streaming│  │  插件层
│  │(SFU 会议)│ │(回显测试)│ │(流转发) │  │
│  └──────────┘ └──────────┘ └────────┘  │
└─────────────────────────────────────────┘
    │
    │  RTP / RTCP (UDP)
    │
    ▼
  WebRTC 媒体流

关键概念:

概念 说明
Session 浏览器与 Janus 之间的一个会话,通过 session_id 标识
Handle (Plugin Handle) 在 session 内 attach 到某个插件后得到的句柄,通过 handle_id 标识
Transport 信令传输方式(HTTP / WebSocket / Unix Socket 等)
Plugin 实际业务逻辑模块(VideoRoom / EchoTest 等)
ICE WebRTC 连接建立协议,负责 NAT 穿透
DTLS-SRTP WebRTC 媒体加密机制

3. 环境准备

3.1 系统要求

  • Ubuntu 22.04 LTS(其他 Debian 系发行版类似)
  • GCC / G++ 编译器
  • 至少 2GB 可用磁盘空间
  • 网络通畅(需要从 GitHub / GitLab 下载源码)

3.2 安装系统依赖

以下包是编译 Janus 及其依赖所必须的,只需运行一次

bash 复制代码
# 方式一:使用项目提供的脚本(推荐)
./install_deps.sh

# 方式二:手动安装
sudo apt-get update
sudo apt-get install -y \
  build-essential cmake pkg-config gengetopt libtool automake autoconf git \
  meson ninja-build gtk-doc-tools wget ca-certificates \
  libglib2.0-dev libjansson-dev libconfig-dev libssl-dev \
  libcurl4-openssl-dev libopus-dev libogg-dev \
  libavutil-dev libavcodec-dev libavformat-dev \
  libsofia-sip-ua-dev libmicrohttpd-dev \
  libgnutls28-dev zlib1g-dev \
  lua5.3 liblua5.3-dev

各依赖包的作用:

包名 用途
build-essential GCC 编译器、make 等基础编译工具
cmake / meson / ninja-build 构建系统(不同依赖库使用不同构建系统)
libglib2.0-dev GLib 基础库,Janus 核心依赖
libjansson-dev JSON 解析库
libconfig-dev 配置文件解析库
libssl-dev OpenSSL,DTLS/SRTP 加密
libopus-dev Opus 音频编解码器
libsofia-sip-ua-dev SIP 协议栈(SIP 插件需要)
libmicrohttpd-dev 轻量 HTTP 服务器(HTTP transport 需要)
gengetopt 命令行参数解析代码生成器

4. 编译安装

Janus 依赖 3 个需要从源码编译的库(Ubuntu 仓库版本太旧):

组件 版本 为什么需要源码编译
libnice 0.1.22 ICE 协议库,Ubuntu 22.04 自带版本不满足 Janus 要求
libsrtp 2.6.0 SRTP 加密库,需要 2.x 版本
libwebsockets 4.3.3 WebSocket 支持,系统版本不兼容
Janus Gateway 1.2.4 最新稳定版

4.1 一键编译(推荐)

bash 复制代码
# 编译所有依赖 + Janus,约 2-5 分钟(取决于 CPU 核数)
bash build_janus.sh

脚本会自动下载源码、编译并安装到 ./local/ 目录下。

4.2 手动分步编译

如果你想了解每一步在做什么,可以按以下顺序手动执行。

第 1 步:设置环境变量
bash 复制代码
export PREFIX="$(pwd)/local"
export PKG_CONFIG_PATH="$PREFIX/lib/pkgconfig:$PREFIX/lib/x86_64-linux-gnu/pkgconfig"
export LD_LIBRARY_PATH="$PREFIX/lib:$PREFIX/lib/x86_64-linux-gnu"
export CFLAGS="-I$PREFIX/include"
export LDFLAGS="-L$PREFIX/lib -L$PREFIX/lib/x86_64-linux-gnu"
第 2 步:编译 libnice
bash 复制代码
wget https://gitlab.freedesktop.org/libnice/libnice/-/archive/0.1.22/libnice-0.1.22.tar.gz
tar xf libnice-0.1.22.tar.gz && cd libnice-0.1.22
meson setup builddir --prefix="$PREFIX" -Dexamples=disabled -Dtests=disabled -Dgstreamer=disabled
ninja -C builddir -j$(nproc) && ninja -C builddir install
第 3 步:编译 libsrtp
bash 复制代码
wget https://github.com/cisco/libsrtp/archive/refs/tags/v2.6.0.tar.gz -O libsrtp-2.6.0.tar.gz
tar xf libsrtp-2.6.0.tar.gz && cd libsrtp-2.6.0
./configure --prefix="$PREFIX" --enable-openssl
make -j$(nproc) && make install
第 4 步:编译 libwebsockets
bash 复制代码
wget https://github.com/warmcat/libwebsockets/archive/refs/tags/v4.3.3.tar.gz -O lws-4.3.3.tar.gz
tar xf lws-4.3.3.tar.gz && cd libwebsockets-4.3.3 && mkdir build && cd build
cmake -DCMAKE_INSTALL_PREFIX="$PREFIX" -DCMAKE_C_FLAGS="-fpic" \
      -DLWS_MAX_SMP=1 -DLWS_WITHOUT_EXTENSIONS=0 \
      -DLWS_WITHOUT_TESTAPPS=ON -DLWS_WITH_STATIC=OFF ..
make -j$(nproc) && make install
第 5 步:编译 Janus
bash 复制代码
wget https://github.com/meetecho/janus-gateway/archive/refs/tags/v1.2.4.tar.gz -O janus-1.2.4.tar.gz
tar xf janus-1.2.4.tar.gz && cd janus-gateway-1.2.4
sh autogen.sh
./configure --prefix="$PREFIX/janus" \
    --enable-websockets --enable-rest \
    --enable-plugin-echotest --enable-plugin-videoroom \
    --enable-plugin-streaming --enable-plugin-videocall \
    --enable-plugin-audiobridge --enable-plugin-sip \
    --enable-plugin-textroom --enable-plugin-recordplay
make -j$(nproc) && make install && make configs

5. 项目结构

复制代码
LibjanusLearn/
├── install_deps.sh             # [第一步] 安装系统依赖(需 sudo,仅运行一次)
├── build_janus.sh              # [第二步] 一键编译 Janus 及依赖
├── start_janus.sh              # 启动 Janus
├── stop_janus.sh               # 停止 Janus
├── html/
│   └── echotest.html           # Echo Test 前端测试页面
├── local/                      # 编译产物(自动生成)
│   ├── lib/                    #   libnice / libsrtp / libwebsockets 动态库
│   ├── include/                #   头文件
│   └── janus/                  #   Janus Gateway
│       ├── bin/janus           #     可执行文件
│       ├── etc/janus/          #     配置文件
│       ├── lib/janus/
│       │   ├── plugins/        #     插件 (.so)
│       │   └── transports/     #     Transport (.so)
│       └── share/janus/
│           └── html/           #     Janus 自带 Demo 页面
└── README.md                   # 本文档

6. 启动与停止

启动

bash 复制代码
./start_janus.sh

启动后终端会输出 Janus 日志,你会看到类似以下关键行:

复制代码
Websockets server started (port 8188)...
HTTP webserver started (port 8088, /janus path listener)...

这表明两个 transport 都已就绪。

停止

新开一个终端:

bash 复制代码
./stop_janus.sh

或者直接在运行 Janus 的终端按 Ctrl+C

后台运行

bash 复制代码
nohup ./start_janus.sh > janus.log 2>&1 &
echo $!    # 记录 PID

7. 验证服务

7.1 API 验证

bash 复制代码
# 查看服务器信息
curl -s http://localhost:8088/janus/info | python3 -m json.tool

正常返回中会包含:

json 复制代码
{
    "janus": "server_info",
    "version_string": "1.2.4",
    "plugins": {
        "janus.plugin.echotest": { ... },
        "janus.plugin.videoroom": { ... },
        ...
    }
}

7.2 Echo Test 页面测试

Echo Test 是最简单的 WebRTC 功能验证------你发出去的音视频会被服务器原样回传给你。

bash 复制代码
# 在 html 目录启动一个静态文件服务器
cd html && python3 -m http.server 8080

浏览器打开 http://localhost:8080/echotest.html

页面支持三种模式:

模式 说明 适用场景
摄像头 使用真实摄像头和麦克风 有物理摄像头的本地机器
模拟视频 Canvas 生成动态画面 无摄像头 / 远程服务器 / 摄像头被占用
纯音频 只使用麦克风 无摄像头但有麦克风

如果摄像头被占用,页面会自动检测并在 3 秒后切换到模拟视频模式。

7.3 测试流程

  1. 选择一种模式,点击「开始测试」
  2. 等待状态变为 "WebRTC 连接已建立 - Echo 测试运行中"
  3. 左侧显示你的本地画面,右侧显示服务器回传的画面
  4. 如果两边都有画面/声音,恭喜,Janus 工作正常!

8. 配置详解

配置文件位于 local/janus/etc/janus/,采用 JCFG 格式(类似 JSON 的 libconfig 语法)。

8.1 核心配置 janus.jcfg

复制代码
general: {
    debug_level = 4          # 日志级别 0(关闭) ~ 7(最详细)
    admin_secret = "janusoverlord"  # Admin API 密钥
    server_name = "MyJanusInstance"
}

nat: {
    stun_server = "stun.l.google.com"   # STUN 服务器
    stun_port = 19302
    nice_debug = false
    ice_lite = false         # true=Lite模式(服务端不主动探测)
    full_trickle = true      # true=完整trickle ICE
    # nat_1_1_mapping = "公网IP"   # 云服务器必须设置
}

media: {
    max_nack_queue = 500     # NACK 队列长度(ms)
    no_media_timer = 1       # 无媒体超时(s)
}

8.2 HTTP Transport janus.transport.http.jcfg

复制代码
general: {
    base_path = "/janus"     # API 路径前缀
    http = true              # 启用 HTTP
    port = 8088              # HTTP 端口
}

admin: {
    admin_base_path = "/admin"
    admin_http = true
    admin_port = 7088
}

8.3 WebSocket Transport janus.transport.websockets.jcfg

复制代码
general: {
    ws = true                # 启用 WebSocket
    ws_port = 8188           # WebSocket 端口
    # wss = true             # 启用 WSS (加密 WebSocket)
    # wss_port = 8989
}

8.4 VideoRoom 插件 janus.plugin.videoroom.jcfg

复制代码
general: {
    admin_key = "supersecret"
}

# 预配置房间
room-1234: {
    description = "Demo Room"
    publishers = 6           # 最大同时发布者
    bitrate = 512000         # 最大比特率 (bps)
    audiocodec = "opus"
    videocodec = "vp8,h264"
    record = false
}

9. 插件介绍

插件 文件名 说明 典型场景
EchoTest libjanus_echotest.so 回显音视频,用于调试 验证 WebRTC 链路是否正常
VideoRoom libjanus_videoroom.so SFU 多人视频会议 视频会议、在线课堂
VideoCall libjanus_videocall.so 一对一视频/音频通话 点对点通信
AudioBridge libjanus_audiobridge.so MCU 音频混音会议 语音会议、播客
Streaming libjanus_streaming.so 将 RTP 流转为 WebRTC 监控、直播、IPTV
SIP libjanus_sip.so SIP 协议网关 对接 IP 电话/PSTN
RecordPlay libjanus_recordplay.so 录制 WebRTC 并回放 课程录制、取证

10. Janus API 入门

Janus 的 API 基于 JSON 消息,无论 HTTP 还是 WebSocket 格式相同。完整交互流程如下:

10.1 创建 Session

bash 复制代码
curl -s -X POST http://localhost:8088/janus \
  -H "Content-Type: application/json" \
  -d '{"janus":"create","transaction":"abc123"}' | python3 -m json.tool

返回:

json 复制代码
{
    "janus": "success",
    "data": { "id": 1234567890 }    // 这就是 session_id
}

10.2 Attach 到插件

bash 复制代码
curl -s -X POST http://localhost:8088/janus/1234567890 \
  -H "Content-Type: application/json" \
  -d '{"janus":"attach","plugin":"janus.plugin.echotest","transaction":"def456"}'

返回 handle_id

10.3 发送消息 + SDP Offer

bash 复制代码
curl -s -X POST http://localhost:8088/janus/1234567890/9876543210 \
  -H "Content-Type: application/json" \
  -d '{
    "janus": "message",
    "transaction": "ghi789",
    "body": {"audio": true, "video": true},
    "jsep": {"type": "offer", "sdp": "v=0\r\n..."}
  }'

10.4 Long Poll 获取事件

bash 复制代码
curl -s http://localhost:8088/janus/1234567890?maxev=5

提示: 生产环境推荐使用 WebSocket,可以实时收到事件推送,不需要 long poll。

10.5 WebSocket 交互示例

javascript 复制代码
const ws = new WebSocket('ws://localhost:8188', 'janus-protocol');

// 创建 session
ws.send(JSON.stringify({
    janus: 'create',
    transaction: 'txn_001'
}));

// 收到回复后 attach 插件
ws.onmessage = (evt) => {
    const msg = JSON.parse(evt.data);
    console.log(msg);
};

11. 常见问题排查

Q: 启动报 "error while loading shared libraries"

原因: 找不到编译的动态库。
解决: 使用 ./start_janus.sh 启动(脚本自动设置 LD_LIBRARY_PATH),不要直接调用 janus 二进制。

Q: 浏览器提示 "Could not start video source"

可能原因:

  • 摄像头被其他程序占用(微信/Zoom/OBS 等)→ 关闭占用程序,或使用「模拟视频」模式
  • 通过 HTTP 远程访问 → 浏览器要求 HTTPS 才能调用 getUserMedia
  • 没有物理摄像头 → 选择「模拟视频」模式
bash 复制代码
# 查看谁在占用摄像头
lsof /dev/video0
fuser /dev/video0

Q: 页面提示 "WebSocket 连接失败" 或 "连接已关闭"

原因: Janus 没有运行,或端口被防火墙拦截。

bash 复制代码
# 检查 Janus 是否运行
pgrep -a janus

# 检查端口是否监听
ss -tlnp | grep -E '8088|8188'

# 测试 API
curl http://localhost:8088/janus/info

Q: ICE 连接失败(WebRTC 建立不了)

原因: NAT 穿透失败。

  • 本机测试:通常不会遇到此问题
  • 云服务器:必须在 janus.jcfg 中设置 nat_1_1_mapping 为公网 IP
  • 复杂网络:需要配置 TURN 服务器

Q: 如何查看详细日志?

bash 复制代码
# 启动时设置更高日志级别
./start_janus.sh --debug-level=7

12. 进阶:生产环境部署

12.1 启用 HTTPS / WSS

WebRTC 在生产环境必须使用加密连接。使用 Let's Encrypt 获取免费证书后:

编辑 janus.transport.http.jcfg

复制代码
general: {
    https = true
    secure_port = 8089
}
certificates: {
    cert_pem = "/etc/letsencrypt/live/your-domain/fullchain.pem"
    cert_key = "/etc/letsencrypt/live/your-domain/privkey.pem"
}

编辑 janus.transport.websockets.jcfg

复制代码
general: {
    wss = true
    wss_port = 8989
}
certificates: {
    cert_pem = "/etc/letsencrypt/live/your-domain/fullchain.pem"
    cert_key = "/etc/letsencrypt/live/your-domain/privkey.pem"
}

12.2 配置 TURN 服务器

推荐使用 coturn

bash 复制代码
sudo apt-get install coturn

janus.jcfg 中配置:

复制代码
nat: {
    stun_server = "your-server.com"
    stun_port = 3478
    turn_server = "your-server.com"
    turn_port = 3478
    turn_type = "udp"
    turn_user = "janususer"
    turn_pwd = "januspassword"
    nat_1_1_mapping = "公网IP"
}

12.3 Nginx 反向代理

nginx 复制代码
upstream janus_http {
    server 127.0.0.1:8088;
}
upstream janus_ws {
    server 127.0.0.1:8188;
}

server {
    listen 443 ssl;
    server_name your-domain.com;

    ssl_certificate     /etc/letsencrypt/live/your-domain/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/your-domain/privkey.pem;

    location /janus {
        proxy_pass http://janus_http;
    }

    location /janus-ws {
        proxy_pass http://janus_ws;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_read_timeout 86400;
    }
}

12.4 性能调优

复制代码
# janus.jcfg
general: {
    debug_level = 1          # 生产环境降低日志级别
    session_timeout = 60
    no_media_timer = 1
}

media: {
    max_nack_queue = 1000    # 增大 NACK 队列应对丢包
    slowlink_threshold = 4
}

操作系统层面:

bash 复制代码
# 增大文件描述符限制
ulimit -n 65536

# 增大 UDP 缓冲区
sudo sysctl -w net.core.rmem_max=26214400
sudo sysctl -w net.core.rmem_default=26214400

13. 参考资料

相关推荐
xiejiashu2 天前
EasyRTC三种工作模式发布,全终端覆盖音视频RTC实时通信99%应用场景
webrtc·webrtc原生sdk·webrtc c sdk·webrtc c++ sdk·webrtc安卓sdk
换个昵称都难2 天前
webrtc 音频模块FEC模块
网络·音视频·webrtc
JJJennie7772 天前
从苹果 2026 落地场景,看系统级 Agent 时代的隐私边界与 MAI Gateway 的企业Token治理
人工智能·gateway·apple
换个昵称都难2 天前
webrtc RTP config
webrtc
kakawzw2 天前
微服务组件源码6——Spring Gateway
spring·gateway
换个昵称都难2 天前
WebRTC 视频RTP 优化模块
音视频·webrtc
白露与泡影2 天前
Java 8老系统旁路接入AI Gateway:不升级JDK也能用AI
java·人工智能·gateway
换个昵称都难3 天前
webrtc PeerConnection 模块介绍
音视频·webrtc
换个昵称都难3 天前
webrtc neteq Nack_tracker重发(ARQ 的nack技术) 介绍
webrtc
简简单单lym3 天前
WebRTC进阶--red+ulpfec深度解析3-FEC--冗余控制机制深度解析
开发语言·webrtc