直播板块构建之路
直播板块构建之路:从 Screego 到 MediaMTX
本站在 /live 下集成了一个完整的低延迟直播系统。回头看这个过程,踩了不少坑才找到正确的路。
第一阶段:Screego(失败)
一开始想着屏幕共享,选了 Screego——一个 WebRTC 的点对点屏幕共享工具。把它跑起来不难,Screego 自带 TURN 服务器,浏览器之间通过 WebSocket 信令建连。
问题很快暴露:
- WebRTC 是 P2P 架构,需要 TURN 中继做 NAT 穿透
- TURN relay 每个观众分配一个随机端口
- 通过 SakuraFrp 对外暴露时,frpc 只能转发一个固定端口
- 手机流量有运营商级 NAT,P2P 打不通
- Screego 内置 TURN 要求在服务器上开放至少 40 个连续 UDP 端口
结论:P2P 不适合单主播多观众的直播场景。 Screego 适合"两个人互相看对方屏幕",不适合"一个人播一群人看"。
第二阶段:重新理解需求
退回一步重新想。我的需求本质上是:
- 一台电脑推画面(OBS)
- 多个观众浏览器看
- 永远只有一个主播
这是标准的广播模型,不是视频会议。广播模型的核心是"主播推流 → 服务器中转 → 观众拉流",所有人走同一条数据流,不存在 P2P 的 NAT 问题。
第三阶段:选型
调研了几个方案:
| 项目 | 语言 | Windows | 延迟 | 结论 |
|------|------|:--:|------|------|
| SRS | C++ | ❌ Linux only | 1-3s | 不支持 Windows |
| ZLMediaKit | C++ | ⚠️ 需编译 | <500ms | 部署复杂度高 |
| MediaMTX | Go | ✅ 官方 exe | ~1s | 最简方案 |
MediaMTX 胜在:一个 exe、零依赖、官方 Windows 编译、LL-HLS 低延迟、配置一个 YAML 就够。
第四阶段:落地架构
OBS (Arc A750 QSV H.264 1080p60)
│ RTMP push
▼
MediaMTX (localhost:1935 → LL-HLS localhost:8888)
│ HLS over TLS (Let's Encrypt)
▼
frpc 国内节点 TCP 隧道 (8888)
│ sc.w-en.cc:27098
▼
观众浏览器 (hls.js 播放)
延迟 ~7s (LL-HLS 协议天花板)
关键踩坑
1. LL-HLS 最少 7 段
Apple 规范要求 Low-Latency HLS 至少 7 个 segment。每段 1 秒就是最低 7 秒延迟。曾经想降到 3 段,MediaMTX 直接报错 Low-Latency HLS requires at least 7 segments。
如果一定要亚秒延迟只能上 WebRTC,但 WebRTC 又绕回 TURN 的问题。权衡之后 7 秒够了——Twitch 也差不多这个数。
2. 韩国节点 vs 国内节点
页面(HTML/JS)走韩国 frpc 节点因为 HTTPS 域名绑定需要备案。但 HLS 视频流是纯 TCP,不需要备案,走国内节点延迟低得多。用 sc.w-en.cc 的备用域名走国内隧道,页面和视频走不同路径。
3. hls.js 的状态管理
MANIFEST_PARSED 才算真正连上流。之前用 Hls.Events.ERROR 做销毁重建会导致"加载-播放-离线"的闪烁。改成让 hls.js 自己重试,只在不可恢复的错误才标记离线。
4. 主播没开播时的体验
加了一个状态机:进入页面立即开始拉流,m3u8 不存在就显示"主播未开播,等待中",hls.js 自动后台重试。开播瞬间 MANIFEST_PARSED 触发,无缝切到播放状态。
最终配置
MediaMTX (mediamtx.yml):
rtmp: yes
rtmpAddress: :1935
hls: yes
hlsAddress: :8888
hlsVariant: lowLatency
hlsEncryption: yes
hlsSegmentDuration: 1s
hlsPartDuration: 200ms
前端 (page.tsx):
const hls = new Hls({
lowLatencyMode: true,
liveSyncDurationCount: 2,
maxBufferLength: 20,
testBandwidth: true,
});
OBS 设置速查
| 设置 | 值 |
|------|-----|
| 服务器 | rtmp://127.0.0.1:1935/live |
| 串流密钥 | stream |
| 编码器 | QuickSync H.264 |
| 输出 | 1920×1080, 60fps, 6000 Kbps CBR |
总结
一句话:直播就是直播,不是视频会议。 用广播模型(推流 → 中转 → 拉流)替代 P2P 模型后,所有 TURN/NAT/端口范围的问题都消失了。现在一条 TCP 隧道解决全部问题,不需要任何云服务器。