L4-WHIP-WHEP低延迟直播
把 WebRTC 用作直播协议。WHIP 标准化推流(OBS → 服务端),WHEP 标准化拉流(服务端 → 浏览器播放器)。延迟可降到 500ms 以内,对 CDN 友好。
1. 为什么用 WHIP/WHEP
| 维度 | RTMP + HLS | WHIP + WHEP |
|---|---|---|
| 推流协议 | RTMP(已被浏览器淘汰) | WebRTC over HTTP |
| 拉流协议 | HLS(6~30s 延迟) | WebRTC(< 1s) |
| 浏览器原生 | ❌ 拉流要播放器 | ✅ |
| CDN 兼容 | 成熟 | 还在演进 |
| 信令复杂度 | 推流需 RTMP,拉流单 HTTP | 双侧单 HTTP |
| 加密 | RTMPS / HTTPS | 强制 DTLS-SRTP |
2. 学习目标
- 理解 WHIP 推流流程(HTTP POST SDP Offer,回 Answer)。
- 实现 WHEP 拉流端点。
- 把信令简化成 1 个 HTTP 请求。
- 用 OBS 31+ 直接 WHIP 推到自研服务端。
3. 架构
4. WHIP 协议交互
# 推流端(OBS / 浏览器)→ 服务端
POST /whip/{streamKey} HTTP/1.1
Host: ingest.example.com
Content-Type: application/sdp
Authorization: Bearer xxxxx
v=0
o=- 1 2 IN IP4 0.0.0.0
...(推流端的 Offer SDP)
# 服务端响应
HTTP/1.1 201 Created
Location: /whip/{streamKey}/resource/abc
Content-Type: application/sdp
v=0
...(服务端的 Answer SDP)
发起后用 PATCH 推 Trickle ICE 候选;DELETE 释放资源。
PATCH /whip/{streamKey}/resource/abc HTTP/1.1
Content-Type: application/trickle-ice-sdpfrag
a=candidate:1 1 UDP 2122252543 ...
5. 客户端代码(浏览器侧)
async function whipPublish(stream, endpoint, token) {
const pc = new RTCPeerConnection({iceServers});
for (const t of stream.getTracks()) pc.addTransceiver(t, {direction: 'sendonly'});
const offer = await pc.createOffer();
await pc.setLocalDescription(offer);
const res = await fetch(endpoint, {
method: 'POST',
headers: {'Content-Type': 'application/sdp', 'Authorization': `Bearer ${token}`},
body: offer.sdp,
});
const answer = await res.text();
const resourceUrl = res.headers.get('Location');
await pc.setRemoteDescription({type: 'answer', sdp: answer});
// Trickle ICE 走 PATCH(可选,多数实现也接受 SDP 一次给齐)
pc.onicecandidate = ({candidate}) => {
if (candidate) fetch(resourceUrl, {
method: 'PATCH',
headers: {'Content-Type': 'application/trickle-ice-sdpfrag'},
body: `a=${candidate.candidate}`,
});
};
return { pc, resourceUrl };
}
async function whipUnpublish(resourceUrl) {
await fetch(resourceUrl, {method: 'DELETE'});
}
WHEP 与 WHIP 对称,把 transceiver direction 改成 recvonly 即可。
6. 服务端选型
| 选型 | 语言 | 适合 |
|---|---|---|
| Pion WHIP server 示例 | Go | 自研轻量服务 |
| LiveKit Ingress | Go | 已用 LiveKit 的项目 |
| GStreamer + webrtcsink | C/Rust | 视频后端栈 |
| Janus VideoRoom + WHIP plugin | C | 已用 Janus 的项目 |
7. 推流端
| 客户端 | WHIP 支持 | 备注 |
|---|---|---|
| OBS Studio 31+ | ✅ 原生 | "服务"选 WHIP |
| ffmpeg ≥ 7.1 | ✅ | -f whip |
| 浏览器 | ✅ 自己写 | 上面那段 30 行 JS |
| 移动端原生 | 通过 libwebrtc 实现 | — |
8. 与 CDN / 大规模分发的边界
WHIP/WHEP 单实例上限大约同 SFU 一档。要做"百万直播 + 低延迟",仍需要边缘 SFU 集群 + CDN 智能路由。
经验值:单台 c7.2xlarge 跑 Pion WHEP 大概 1k 路同时观看,超过要做级联。
9. 验收 Checklist
- OBS 推流端到端延迟 < 1s
- 浏览器播放器单 HTTP 请求即开播
- 关闭 OBS 后服务端在 5s 内回收资源
- 弱网(200ms RTT)画面不抖动
- 与 RTMP/HLS 主路并存(同源双协议)
10. 参考资料
- IETF RFC 9725 WHIP: https://www.rfc-editor.org/rfc/rfc9725
- IETF draft WHEP: https://datatracker.ietf.org/doc/draft-ietf-wish-whep/
- Pion WHIP demo: https://github.com/pion/webrtc/tree/master/examples/whip-whep
- LiveKit Ingress: https://docs.livekit.io/home/ingress/overview/
- OBS Studio WHIP 配置: https://obsproject.com/wiki/WebRTC-Output
- 上一级 实战项目总览