English | 简体中文
这是一个围绕上游 mediasoup-worker 构建的 C++17 SFU 控制平面。
本项目使用原生的 C++ 服务器取代了 mediasoup 通常的 Node.js 控制层,同时仍然依赖经过实战检验的 mediasoup-worker 进程进行媒体处理。最终呈现的是一个原生的 C++ 信令技术栈,具备房间/会话管理、多节点房间路由、录制以及 QoS 聚合等功能。
立即体验: http://47.99.237.234:3000
在两个浏览器标签页或两台设备中打开,即可开始带有实时 QoS 监控的 1v1 通话。
录制回放: http://47.99.237.234:3000/playback.html
mediasoup 得到了广泛应用,但其默认的控制平面是 Node.js。本项目保留了上游的 C++ 媒体 worker,并将控制平面替换为 C++17,以实现:
- 更低的信令开销
- 单二进制文件(single-binary)的控制平面部署
- 对线程、故障恢复以及与原生系统集成的更精细控制
媒体平面仍然由 mediasoup-worker 处理,通过 Unix 管道(Unix pipes)和 FlatBuffers IPC 进行连接。
本项目包含:
- 一个 WebSocket/HTTP 信令服务器
- 一个房间 / 节点 (peer) / 会话 (session) 管理层
- 一个 Transport / Producer / Consumer 编排层
- 一个基于 Redis 的多节点房间路由层
- 一个录制器 / QoS 集成层
本项目不是:
- 对 mediasoup 媒体内部机制的重写
mediasoup-worker的替代品
本项目不是重写 mediasoup 的媒体 worker,而是把外围控制面和原生客户端集成面收敛到一套可部署、可验证、可排障的 C++ 工程里。
- C++17 控制面: 使用
uWebSockets处理 HTTP/WebSocket,媒体面继续复用上游mediasoup-worker。 - 房间串行执行:
WorkerThread绑定房间生命周期,减少房间状态跨线程共享和锁竞争。 - FlatBuffers IPC: 控制面通过 Unix pipe + FlatBuffers 与
mediasoup-worker通信,协议边界清晰。
- 外围最小化: push/play 客户端只保留 WebSocket 信令和 UDP Socket I/O。
- 媒体 QoS 下沉: add track、编码、packetize、pacer、GoogCC、NACK/PLI、统计和 QoE 观测交给
webrtc_qos_sdk;FEC/RTX 不计入当前推拉流客户端验收范围。 - PlainTransport 对接: 客户端复用
plainPublish/plainSubscribe,用于验证 mediasoup PlainTransport 和 SDK 推拉流闭环。
- 浏览器 uplink 矩阵: 保留浏览器/Node harness,用于验证上行 QoS 状态机和服务端聚合链路。
- native push/play 弱网短测: P2 主报告覆盖 baseline、delay、loss、bandwidth、drop/recover,并记录 RTP/RTCP、TWCC、target bitrate、native decode QoE 和恢复首帧。
- 环境 SKIP 规则: browser H264 capability、V4L2 设备、netem 权限等环境前置不足时只允许记录
SKIP/PARTIAL,不能计入 PASS。
Browser
│
│ WebSocket / HTTP
▼
uWS Main Thread
│
├─ SignalingServer 主线程粘合层
├─ SignalingServerWs 请求/会话处理
├─ SignalingServerHttp 路由处理
├─ 绑定 roomId -> WorkerThread
└─ 发送响应 / 通知
│
▼
WorkerThread Pool (N)
│
├─ 每个 WorkerThread 拥有一个串行事件循环
├─ 拥有 mediasoup worker 进程的子集
├─ 拥有已分配房间的 RoomManager + RoomService
├─ 通过 epoll 驱动 Channel IPC
└─ 单线程运行房间业务逻辑
│
▼
RoomService Facade
│
├─ 生命周期切面 (lifecycle slice)
├─ 媒体切面 (media slice)
├─ 统计 / QoS 切面
└─ 下行调度规划切面 (downlink planning slice)
│
▼
Router / Transport / Producer / Consumer
│
▼
Channel (基于 Unix pipe 的 FlatBuffers)
│
▼
mediasoup-worker 进程
│
▼
RTP / SRTP / ICE / DTLS
除了浏览器路径,本仓库提供一套基于 webrtc_qos_sdk 的原生推拉流客户端,用于打通服务端信令、UDP RTP/RTCP 收发和 SDK 媒体 QoS。
这个客户端只负责最小外围集成:
- WebSocket 信令:
join、plainPublish、plainSubscribe - UDP Socket:连接 mediasoup RTP/RTCP 收发口
- WebRTC 接口:通过 SDK 完成 add track、编码、packetize、pacer、GoogCC、NACK/PLI、统计和 QoE 观测;FEC/RTX 不计入当前验收范围
当前实现和验收文档:
- docs/dependencies_cn.md
- docs/webrtc-qos-push-play-client-design_cn.md
- docs/webrtc-qos-push-play-client-p2-design_cn.md
- docs/webrtc-qos-push-play-client-thread-model-design_cn.md
- docs/webrtc-qos-push-play-client-implementation-checklist_cn.md
- docs/architecture_cn.md
SignalingServer
│
├─ WorkerThread Pool
│
└─ Registry Worker Thread
│
└─ RoomRegistry
├─ Redis 命令连接
├─ 本地房间缓存
├─ 本地节点缓存
├─ 房间所有权声明 / 刷新 / 注销
└─ resolveRoom(roomId, remoteIp)
│
└─ GeoRouter (可选)
├─ ip2region 查找
├─ 国家隔离
└─ 基于 ISP / 距离的打分
此外,还有一个专用的 Redis 订阅者线程(subscriber thread),负责监听节点和房间更新,并刷新本地缓存状态。
- 以房间为中心的设计:当一个 peer 开始发布媒体流时,房间内的其他 peer 会被自动订阅。
- 基于 WorkerThread 的信令:房间控制逻辑在 uWS 主循环之外运行。
- 会话身份标识:重连会替换旧连接,过时的请求会被
sessionId拒绝。 - 基于 Redis 的房间路由:房间所有权、缓存、pub/sub 同步、降级为本地模式。
- 感知地理位置的路由:基于 ip2region 的国家 / ISP / 距离打分。
- H264 / VP8 录制:通过 FFmpeg 进行 RTP 解包和 WebM 封装。
- QoS 监控:服务器统计数据 + 客户端统计数据的聚合及定期推送。
- Worker 崩溃恢复:带有速率限制的子进程重生(respawn)。
- 守护进程模式 (daemon mode):支持 fork、PID 文件、结构化日志。
本仓库目前包含:
- 完整的上行 (Uplink) QoS 链路,覆盖:
- 客户端 Publisher QoS 状态机和阶梯控制
- 服务端对
clientStats的接收、校验、聚合以及自动 Override 生成 - 针对推流、陈旧序列号 (stale-seq)、策略更新、自动 Override、手动清除的浏览器/Node 测试套件
- 浏览器回环弱网矩阵 (weak-network matrix) 执行及逐 Case 的结果报告
- 完整的下行 (Downlink) QoS 链路,覆盖:
- 订阅者侧对
downlinkClientStats的接收、校验、存储以及控制器执行 - 服务端基于隐藏 (hidden) / 驻留 (pinned) / 尺寸的带宽分配、基于健康度的降级/恢复,以及优先级处理
- 针对持续全隐藏 (all-hidden) 场景,协调 Producer 侧的零需求
pauseUpstream/resumeUpstream控制 - 针对消费者控制、下行自动暂停/恢复,以及在受限下行网络下优先级竞争的浏览器测试套件
- 订阅者侧对
当前的下行范围主要是:接收端控制加上对零需求的发布端自动暂停/恢复协调。
dynacast 以及房间级别的全局比特率预算划分仍然是后续的工作内容。
当前仓库文档和生成的制品显示:
- 浏览器上行矩阵:原
43 / 43 PASS主 gate (2026-04-13) +GD1-GD12targeted PASS,当前总口径为55 case - WebRTC QoS P2 当前主报告:
sourceMode=copy,enableNetem=true,decodeQoe=true;baseline、delay_100ms、loss_2pct、loss_5pct、bandwidth_600k、drop_recover为6 / 6 PASS,failedChecks=0 - P2 主报告 gate:
qosMainline=PASS,sdkRuntimeObservability=PASS,nativeDecodeQoe=PASS,weakNetworkCoverage=PASS,recoveryFirstFrame=PASS;encoderRuntime=SKIP,因为 copy 输入不经过实时 x264 encoder - P2 弱网 QoS 数据:100ms delay RTT avg/max 为
86.3/247ms,600kbps bandwidth targetBps min/avg/max 为300000/1237333/1994666,drop_recovertargetBps min/avg/max 为300000/632260.23/1994666 - P2 恢复首帧已列为独立门禁:主报告中
drop_recover清网后120ms看到 native QoEdecodedFrames增长,decoded delta=241;专项恢复报告drop_recover=PASS、failedChecks=0,清网后2122ms看到首帧,decoded delta=416 - WebRTC QoS P2 MP4 decode-loop baseline:
qosMainline=PASS,sdkRuntimeObservability=PASS,encoderRuntime=PASS,nativeDecodeQoe=PASS;baselinepushedAu=359、decodedFrames=359、decodeErrors=0 - WebRTC QoS P2 browser receiver smoke:push 发布链路
PASS;当前 headless Chromium 只暴露 VP8/VP9、不暴露 H264 packetization-mode=1,浏览器收流 case 按环境能力记为SKIP,overall 为PARTIAL - WebRTC QoS P2 V4L2 source:V4L2 CLI/source/smoke SKIP gate 已落地;当前机器无
/dev/video0,baseline 按环境能力SKIP,overall 为PARTIAL - WebRTC QoS P2 聚合验收:
scripts/run_qos_tests.sh p2-acceptance会执行构建、plain client 单测、ORTC/TWCC targeted test、PlainPublish 集成测试、边界检查和报告复核;正式刷新报告用scripts/run_webrtc_qos_plain_p2_acceptance.sh --run-smoke --enable-netem,会重跑主弱网、恢复首帧、MP4 decode-loop 和 V4L2 报告;scripts/run_qos_tests.sh p2-report只做离线边界/报告复核 - WebRTC QoS P3 线程模型自动化验收:
scripts/run_qos_tests.sh p3-thread-model-report会执行静态 owner/队列/日志边界检查,并运行两路 synthetic、两路 MP4 decode-loop、慢编码注入、慢 sink 注入、弱网 two-track、per-track play QoE 和 V4L2 capability 的动态 smoke;V4L2 capture/raw/encode split 代码和静态边界已落地。生产签收入口是scripts/run_qos_tests.sh p3-thread-model-acceptance,它要求 netem 弱网和真实双 camera V4L2 全部 PASS,不能用 SKIP/PARTIAL 代替;当前 weak-network strict 已 PASS,V4L2 strict 因缺/dev/video0和/dev/video1仍不能签生产。
当前范围提示:
- 上行 QoS 主链路在浏览器和 WebRTC QoS P2 客户端上均已闭环
- 下行目前覆盖接收端控制以及零需求发布端暂停/恢复协调
- WebRTC QoS P2 已签收 native push/play copy 输入弱网短测和 MP4 decode-loop baseline;browser receiver 与 V4L2 已有自动化入口,但本机浏览器缺 H264 能力、当前机器无
/dev/video0,对应真实画面/摄像头运行结果仍只能记录SKIP/PARTIAL - 推拉流多线程 runtime 已有 P3 自动化验收入口,覆盖 two-track synthetic/decode-loop、慢编码/慢 sink 注入、弱网 two-track、per-track play QoE、per-track V4L2 device capability;生产签收必须另跑
p3-thread-model-acceptance,当前开发机仍缺真实双 camera 硬件 PASS。 dynacast和房间级全局比特率预算划分是后续工作
事实来源链接 (Source-of-truth links):
- QoS 整体状态:docs/qos-status.md
- 最终总结:docs/uplink-qos-final-report.md
- 结果总结:docs/uplink-qos-test-results-summary.md
- 逐 Case 最终结果:docs/uplink-qos-case-results.md
- WebRTC QoS P2 smoke 报告:docs/generated/webrtc-qos-plain-p2-smoke-report.md
- WebRTC QoS P2 设计和验收门禁:docs/webrtc-qos-push-play-client-p2-design_cn.md
- WebRTC QoS 推拉流线程模型升级设计:docs/webrtc-qos-push-play-client-thread-model-design_cn.md
- WebRTC QoS P2 恢复首帧专项报告:docs/generated/webrtc-qos-plain-p2-recovery-first-frame-report.md
- WebRTC QoS P2 MP4 decode-loop baseline 报告:docs/generated/webrtc-qos-plain-p2-mp4-decode-loop-report.md
- WebRTC QoS P2 browser receiver 报告:docs/generated/webrtc-qos-plain-p2-browser-receiver-report.md
- WebRTC QoS P2 V4L2 source 报告:docs/generated/webrtc-qos-plain-p2-v4l2-report.md
- WebRTC QoS P3 线程模型边界报告:docs/generated/webrtc-qos-plain-thread-model-boundary-report.md
- WebRTC QoS P3 two-track synthetic smoke 报告:docs/generated/webrtc-qos-plain-p3-thread-model-smoke-report.md
- WebRTC QoS P3 two-track MP4 decode-loop 报告:docs/generated/webrtc-qos-plain-p3-thread-model-decode-loop-report.md
- WebRTC QoS P3 slow encoder 注入报告:docs/generated/webrtc-qos-plain-p3-thread-model-slow-encoder-report.md
- WebRTC QoS P3 slow sink 注入报告:docs/generated/webrtc-qos-plain-p3-thread-model-slow-sink-report.md
- WebRTC QoS P3 weak-network two-track 报告:docs/generated/webrtc-qos-plain-p3-thread-model-weak-network-report.md
- WebRTC QoS P3 V4L2 capability 报告:docs/generated/webrtc-qos-plain-p3-thread-model-v4l2-report.md
- WebRTC QoS P2 聚合验收脚本:scripts/run_webrtc_qos_plain_p2_acceptance.sh
- WebRTC QoS P2 报告验收脚本:scripts/verify_webrtc_qos_plain_p2_reports.py
- WebRTC QoS plain client 边界验收脚本:scripts/verify_webrtc_qos_plain_client_boundaries.py
- WebRTC QoS P3 线程模型 smoke 脚本:scripts/run_webrtc_qos_plain_p3_thread_model_smoke.sh
- 下行当前状态:docs/downlink-qos-status.md
- 测试覆盖地图:docs/qos-test-coverage_cn.md
- 生成的矩阵制品:docs/generated/uplink-qos-matrix-report.json
主线程负责:
- WebSocket 的接收 / 关闭 / 消息处理
- HTTP 接口端点
- 房间到线程的分配 (room-to-thread dispatch)
- Socket/Session 的所有权
- 向客户端事件循环的延迟发送 (deferred sends)
重要不变量 (Important invariant):
- 同一个房间 -> 同一个 WorkerThread
在执行业务任务之前,第一次成功的加入(join)就会在主线程中将 roomId 绑定到一个特定的 WorkerThread。
每个 WorkerThread 是一个串行事件循环,拥有:
- 零个或多个 mediasoup worker 子进程
- 一个
RoomManager - 一个
RoomService - 一个任务队列
- worker 管道文件描述符的 epoll 注册
- 健康检查 / 垃圾回收 (GC) 定时器
在 WorkerThread 内部,房间逻辑被刻意设计为单线程的。这样可以在没有普遍的细粒度锁的情况下保持房间状态的一致性。
每个 WorkerThread 拥有一个 mediasoup worker 子进程的子集。
这些子进程:
- 创建路由器 (routers)
- 创建传输通道 (transports)
- 协商媒体
- 转发 RTP 数据
- 通过 IPC 暴露统计信息
Redis 的“阅后即焚” (fire-and-forget) 维护任务不会内联执行在房间控制路径上。一个专用的注册中心工作线程负责处理:
- 房间 TTL 刷新
- 房间注销
- 节点心跳 / 负载更新
这使得稳态房间控制路径对 Redis 延迟不那么敏感。
| Thread | Count | Role |
|---|---|---|
| uWS main | 1 | WebSocket, HTTP, timers, room dispatch |
| WorkerThread | N | serial room logic + epoll-driven worker IPC |
| Registry worker | 1 | async Redis maintenance tasks |
| Redis subscriber | 1 | pub/sub cache updates |
| Worker waiter | per worker | child process wait / death handling |
| Recorder | per active recorder | UDP RTP receive + muxing |
Typical small deployment:
- 1 uWS main thread
- 1 registry worker
- 1 Redis subscriber
- 1 WorkerThread
- 1 mediasoup worker process
- 0..M recorder threads
All critical modules are initialized before the server begins accepting traffic:
RoomRegistry: Redis connect,syncAll(), subscriber threadWorkerThread::start(): create worker processeswaitReady(): block until WorkerThreads report initialization completeuWS::App().listen(): only then begin accepting WebSocket / HTTP connections
本项目区分了以下两种身份:
- 业务身份:
peerId - 连接身份:
sessionId
这在处理重连(reconnect)时非常重要:
- 当同一个
peerId发起新的 join 请求时,会替换旧的 session - 旧的 socket 会被立即失效
Peer对象会被打上新的sessionId标记- 那些来自被替换连接的过时请求,会在试图修改房间状态前被拒绝
client -> WebSocket join
-> uWS 主线程 (main thread)
-> 分配 roomId -> 绑定到某个 WorkerThread
-> WorkerThread 执行 RoomService::join()
-> 如果需要,RoomManager 创建房间
-> 将响应结果 deferred 传回主循环
-> socket 被绑定 roomId / peerId / sessionId
client -> produce
-> uWS 主线程
-> 分发给该房间绑定的 WorkerThread
-> 校验 session
-> RoomService::produce()
-> Transport::produce()
-> Channel::requestWait()
-> mediasoup-worker 创建 Producer
-> 自动给其他 peer 订阅 (auto-subscribe)
-> (可选) 启动录制链路
-> 响应结果 deferred 传回客户端
定时器 (timer) -> 主线程
-> 往每个 WorkerThread 投递 stats 任务
-> WorkerThread 遍历名下的 rooms / peers
-> 收集 transport / producer / consumer 级别的 stats
-> 合并 clientStats
-> 广播 statsReport
-> 录制器 (recorder) 可能会追加写入 QoS snapshot
webrtc-qos-plain-push-client / webrtc-qos-plain-play-client
-> WebSocket join / plainPublish / plainSubscribe
-> 绑定 mediasoup UDP RTP/RTCP
-> 通过 webrtc_qos_sdk add track / receive track
-> SDK 负责 GoogCC / pacer / NACK / PLI / stats / QoE
-> 导出 SDK stats / QoE / clientStats snapshots
The media plane does not pass through the signaling logic after setup:
Browser A ──SRTP/UDP──→ WebRtcTransport → Producer
├──→ Consumer (SIMPLE) → WebRtcTransport → Browser B
└──→ Consumer (PIPE) → PlainTransport
│ localhost UDP RTP
▼
PeerRecorder → .webm
A room owns:
- a
Router - a peer map
- room activity timestamps
A peer owns:
peerIddisplayNamesessionId- RTP capabilities
- send transport
- recv transport
- producers
- consumers
The room model is room-first rather than explicit per-subscription signaling.
When one peer produces:
- all other peers with a recv transport are auto-subscribed
- they receive
newConsumernotifications
RoomRegistry is responsible for:
- node registration
- node load publication
- room ownership claim
- room ownership refresh
- room lookup / resolution
- room and node cache maintenance
Important behavior:
- room ownership is stored in Redis
- room and node info are cached locally
- pub/sub keeps cache warm
resolveRoom()can fall back to a Redis-backed node refresh if local cache is missing fresh node data- when Redis is unavailable, the system degrades to local-only mode
If GeoRouter is enabled:
- client IP is mapped via
ip2region - same-country routing can be enforced
- candidate nodes are ranked by:
- country isolation
- ISP affinity
- geographic distance
- current load
This logic lives under RoomRegistry, not directly under RoomService.
Enabled by default.
- Chinese IP -> Chinese nodes only
- US IP -> US nodes only
Disable with --noCountryIsolation or "countryIsolation": false.
# Hangzhou node (China Telecom)
./build/mediasoup-sfu \
--nodaemon \
--port=3000 \
--announcedIp=<public-ip> \
--lat=30.27 \
--lng=120.15 \
--isp=电信 \
--country=中国
# US West node
./build/mediasoup-sfu \
--nodaemon \
--port=3001 \
--announcedIp=<public-ip> \
--lat=37.39 \
--lng=-122.08 \
--isp=Amazon \
--country="United States"Recording is implemented as a side path:
Producer
-> PIPE Consumer
-> PlainTransport
-> localhost UDP RTP
-> PeerRecorder
-> FFmpeg / WebM output
Recorder responsibilities include:
- RTP receive
- H264 / VP8 packet handling
- muxing
- QoS timeline sidecar output
Dependency reference:
-
Linux
-
CMake 3.16+
-
GCC 10+ or Clang 12+
-
OpenSSL
-
zlib
-
FFmpeg
libavformatlibavcodeclibavutillibswscalelibavdevice
-
hiredis
-
curl与tar(被setup.sh用于下载和解压mediasoup-worker)
备注:
- 对于单节点、仅本地路由(local-only)的模式,Redis 在运行时是可选的,但目前的默认构建依然会链接
hiredis。 - WebRTC QoS P2 的 V4L2 输入源需要
libavdevice;没有/dev/video0的机器会把摄像头 smoke 记为环境SKIP。
git clone --recursive https://github.com/user/mediasoup-cpp.git
cd mediasoup-cpp
./setup.sh
mkdir -p build
cd build
cmake .. -DCMAKE_BUILD_TYPE=Release
cmake --build . -j$(nproc)请始终在项目根目录下运行。
最简运行:
./build/mediasoup-sfu --nodaemon --port=3000 --listenIp=0.0.0.0推荐的生产环境启动参数:
./build/mediasoup-sfu \
--nodaemon \
--port=3000 \
--workers=1 \
--workerThreads=1 \
--listenIp=0.0.0.0 \
--announcedIp=<public-ip> \
--workerBin=./mediasoup-worker \
--redisHost=127.0.0.1 \
--redisPort=6379 \
--nodeId=<unique-node-id>使用配置文件:
cat > config.json <<'EOF'
{
"port": 3000,
"workers": 1,
"workerThreads": 1,
"workerBin": "./mediasoup-worker",
"listenIp": "0.0.0.0",
"announcedIp": "<public-ip>",
"redisHost": "127.0.0.1",
"redisPort": 6379,
"recordDir": "./recordings",
"logDir": "/var/log/mediasoup",
"logPrefix": "mediasoup-sfu",
"logRotateHours": 3
}
EOF
./build/mediasoup-sfu --nodaemon --config=config.json打开浏览器访问 http://<server-ip>:3000。
| 选项 (Option) | 默认值 (Default) | 描述 (Description) |
|---|---|---|
--port |
3000 |
信令 + HTTP 端口 |
--workers |
基于 CPU 自动计算 | mediasoup worker 子进程数量 |
--workerThreads |
自动计算 | WorkerThread 事件循环数量 |
--listenIp |
0.0.0.0 |
传输层 (transport) 监听 IP |
--announcedIp |
自动检测 | 用于 ICE 候选者 (candidates) 的公网 IP |
--workerBin |
./mediasoup-worker |
worker 可执行文件路径 |
--recordDir |
./recordings |
录制文件输出目录 |
--logDir |
/var/log/mediasoup |
守护进程日志目录 |
--logPrefix |
mediasoup-sfu |
守护进程日志文件前缀 |
--logLevel |
info |
日志详细级别 |
--logRotateHours |
3 |
每 N 小时轮转守护进程日志,生成如 mediasoup-sfu_2026041306_<pid>.log 的文件 (0 为禁用轮转) |
--nodaemon |
flag | 在前台运行 (不作为守护进程) |
--redisHost |
127.0.0.1 |
Redis 主机地址 |
--redisPort |
6379 |
Redis 端口 |
--nodeId |
自动生成 | 节点唯一标识 |
--nodeAddress |
自动生成 | 对外公布的 WS 地址 |
--lat |
自动检测 | 节点纬度 |
--lng |
自动检测 | 节点经度 |
--isp |
自动检测 | 节点所属运营商 (ISP) |
--country |
自动检测 | 节点所在国家 |
--countryIsolation |
on | 仅限同国家路由 |
--noCountryIsolation |
flag | 禁用国家隔离 |
--geoDb |
./ip2region.xdb |
ip2region 数据库路径 (回退路径为 ./third_party/ip2region/ip2region.xdb) |
如果当前目录下不存在 ./ip2region.xdb,服务器还会检查打包的源码副本路径 ./third_party/ip2region/ip2region.xdb 以及可执行文件构建目录下的副本。
代码具备尽力而为的自动检测能力,但生产环境部署不应依赖于此。
请明确设置:
--announcedIp- 可选设置
--nodeId - 如果你的环境具有特殊的路由或代理拓扑,可选设置
--nodeAddress
集成测试依赖于在 ./build 目录下使用相对路径来生成并启动二进制文件。
如果启用了基于 Redis 的多节点路由,每个节点都必须发布一个能够被客户端或上游代理层访问到的 ws:// 地址。
所有的测试必须在项目的根目录执行。
# 全仓库回归测试
./scripts/run_all_tests.sh
# QoS JS / 测试套件 / 矩阵回归
./scripts/run_qos_tests.sh
# 单独的二进制测试文件
./build/mediasoup_tests
./build/mediasoup_qos_unit_tests
./build/mediasoup_review_fix_tests
./build/mediasoup_stability_integration_tests
./build/mediasoup_multinode_tests
./build/mediasoup_topology_tests
./build/mediasoup_integration_tests
./build/mediasoup_qos_integration_tests
./build/mediasoup_e2e_tests
./build/mediasoup_benchmediasoup_review_fix_tests、mediasoup_multinode_tests 以及 mediasoup_topology_tests 会自动启动一个隔离的 redis-server。这需要环境变量 PATH 中有 redis-server 可执行文件,但它们并不依赖 127.0.0.1:6379 上共享的 Redis。
./scripts/run_all_tests.sh 和 ./scripts/run_qos_tests.sh 都在有测试失败后继续运行剩余被选定的测试组,只有在打印最终的失败总结后才返回非零状态码。
./scripts/run_all_tests.sh 还会覆写最新的全量回归测试报告:
docs/full-regression-test-results.md
对于无人值守的夜间执行,可以使用仓库本地的包装脚本:
cp .nightly-full-regression.env.example .nightly-full-regression.env
./scripts/nightly_full_regression.py run
./scripts/install_nightly_full_regression_cron.sh夜间包装脚本会在 artifacts/nightly-full-regression/ 下保存带有时间戳的运行目录,默认情况下刷新 /var/log/run_all_tests.log,并通过邮件发送通过率/失败用例总结以及精选的 Markdown 报告附件。
详见 docs/nightly-full-regression.md。
当运行范围包含 qos 时,该切面会被委托给 ./scripts/run_qos_tests.sh,因此该脚本所负责的特定 QoS 总结和矩阵制品也会作为运行的一部分被刷新。
目前回归重载套件涵盖:
- 重连语义 (reconnect semantics)
- 过时请求拒绝 (stale request rejection)
- restartIce 正确性
- 非阻塞统计路径 (non-blocking stats path)
- 录制路径稳定性
- 地理位置路由 (geo routing)
- 国家隔离 (country isolation)
- Redis 降级模式 (Redis degrade mode)
- 缓存传播 (cache propagation)
- full-node 重定向行为
供 Review 前本地验证使用:
# 配置并构建
cmake -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build -j$(nproc)
# 全仓库回归测试
./scripts/run_all_tests.sh
# 快速基线 (核心单元测试)
./build/mediasoup_tests
# QoS 单元测试基线
./build/mediasoup_qos_unit_tests对于 QoS 特定的验证,请使用统一脚本:
cd /root/mediasoup-cpp
# 全量 QoS 运行
./scripts/run_qos_tests.sh
# 仅从上一次失败的任务继续
./scripts/run_qos_tests.sh --resume
# 跳过依赖浏览器的部分
./scripts/run_qos_tests.sh --skip-browser
# 运行指定的组
./scripts/run_qos_tests.sh client-js cpp-unit
# 默认浏览器矩阵关卡
node tests/qos_harness/run_matrix.mjs
# 扩展的浏览器矩阵 (追加剩余的基线用例)
node tests/qos_harness/run_matrix.mjs --include-extended
# 针对性重跑盲点
node tests/qos_harness/run_matrix.mjs --cases=T9,T10,T11
# 多房间容量压力测试:
# 每个房间有刚好 2 个 peer:1 个 publisher 发送 1080p,1 个 subscriber 接收
node tests/qos_harness/browser_capacity_rooms.mjs --workers=1 --step=5 --max-rooms=50行为表现:
- 默认模式会运行所有默认 QoS 组,包括 browser/downlink 矩阵、WebRTC QoS P2 聚合验收和 P3 线程模型自动化报告;即使某个组失败也会继续执行
- 失败会记录到
tests/qos_harness/artifacts/last-failures.txt --resume仅会重新运行上一次失败的精确任务- 只想复核 WebRTC QoS P2/P3 时使用
./scripts/run_qos_tests.sh p2-report、./scripts/run_qos_tests.sh p2-acceptance、./scripts/run_qos_tests.sh p3-thread-model-report或显式生产签收入口./scripts/run_qos_tests.sh p3-thread-model-acceptance;这些入口不会刷新 downlink summary,且 P3 生产签收不包含在默认或all中 - 如果执行了
matrix,脚本还会重新生成逐 Case 的报告: docs/uplink-qos-case-results.md - 默认矩阵现在包含盲点过渡用例
T9/T10/T11;剩余的extended集合是目前更高带宽的基线校准用例,可以通过--include-extended追加,或者通过--cases=...明确指定运行
Cannot find source file ... third_party/ip2region/binding/c/xdb_searcher.c
确保你在最新的分支上,并且捆绑的third_party/ip2region目录存在。Could NOT find ... avformat/avcodec/avutil
安装 FFmpeg 开发包(比如在 Debian/Ubuntu 上安装libavformat-dev libavcodec-dev libavutil-dev libswscale-dev libavdevice-dev),或者参阅 docs/dependencies_cn.md。hiredis not found或 Redis 符号的链接错误
安装 hiredis 开发包 (libhiredis-dev/hiredis-devel),或者参阅 docs/dependencies_cn.md。
生产环境的监控位于 deploy/monitoring 下。
cd deploy/monitoring
docker compose up -d| 服务 (Service) | URL |
|---|---|
| Grafana | http://<server-ip>:3001 |
| Prometheus | http://<server-ip>:9090 |
| Alertmanager | http://<server-ip>:9093 |
在线演示 Grafana: http://47.99.237.234:3001
在 Intel Xeon Platinum 2.5GHz, 2 vCPU 上的测试结果:
| 指标 (Metric) | 本地回环 (Loopback) | 真实网络 (Real Network) |
|---|---|---|
| 峰值房间数 (每个含 1推 + 2拉) | 240 | 80 |
| Worker CPU | 82% | 23% |
| RSS (内存驻留) | 180 MB | 67 MB |
| PPS (包速率 in -> out) | 72k -> 144k | 24k -> 48k |
真实环境预估:对于典型的音视频 WebRTC 流量,每个 mediasoup worker 大约能承载 30-40 个 1v1 房间。
src/
├── main.cpp # 瘦进程入口 + 信号接线
├── MainBootstrap.* # 运行时选项、geo/初始化、worker 线程池创建
├── RuntimeDaemon.* # 守护进程化 + 启动通知管道
├── Constants.h # 运行时常量
├── SignalingServer.h # 信令服务器外观 (facade)
├── SignalingServerWs.* # WebSocket 请求/会话分发
├── SignalingServerHttp.* # HTTP 路由、指标、文件服务
├── SignalingServerRuntime.cpp # 运行时快照、注册中心 worker、房间分配助手
├── SignalingSocketState.h # WS 会话 / 速率限制助手
├── SignalingRequestDispatcher.h # method -> RoomService 分发粘合
├── StaticFileResponder.h # 静态文件路径解析 + 流式传输
├── WorkerThread.* # 每个信令 worker 线程一个 epoll 事件循环
├── RoomService.h # 房间服务外观 (facade)
├── RoomServiceLifecycle.cpp # join/leave/健康/清理
├── RoomServiceMedia.cpp # transport / produce / consume 流程
├── RoomServiceStats.cpp # stats / QoS / 房间状态广播
├── RoomServiceDownlink.cpp # 下行规划 + 发布端供应
├── RoomRecordingHelpers.* # 录制器创建 / 清理助手
├── RoomMediaHelpers.h # 媒体侧辅助例程
├── RoomDownlinkHelpers.h # 下行辅助例程
├── RoomStatsQosHelpers.h # 统计/QoS 辅助例程
├── RoomManager.h # 房间容器与生命周期
├── RoomRegistry.* # Redis 路由、缓存、pub/sub 同步
├── GeoRouter.h # 地理位置解析和打分
├── WorkerManager.h # worker 选取 / 容量辅助
├── Worker.* # mediasoup-worker 子进程包装器
├── Channel.* # 基于 Unix 管道的 FlatBuffers IPC
├── Router.* # 路由器包装器
├── Transport.* # 传输通道包装器
├── WebRtcTransport.* # ICE / DTLS 传输通道
├── PlainTransport.h # 用于录制路径的 plain RTP 传输通道
├── Producer.* # producer 包装器
├── Consumer.* # consumer 包装器
├── Peer.h # peer + session 状态
├── Recorder.h # RTP -> WebM 录制与 QoS 时间线
├── EventEmitter.h # 轻量级事件系统
└── Logger.h # spdlog 包装器
MIT — 详见 LICENSE.