- 音视频
- 直播
- 后端
【免费下载链接】ZLMediaKit
WebRTC/RTSP/RTMP/HTTP/HLS/HTTP-FLV/WebSocket-FLV/HTTP-TS/HTTP-fMP4/WebSocket-TS/WebSocket-fMP4/GB28181/SRT/STUN/TURN server and client framework based on C++11
ZLMediaKit 内置完整的 WebRTC 服务端框架,既支持基于 HTTP 标准信令的 WHIP/WHEP(SFU 中继)模式,也支持基于 WebSocket 自定义信令的 P2P 房间直连模式。本文以 webrtc/USAGE.md 为骨架,结合 server/WebApi.cpp、server/main.cpp、webrtc/WebRtcTransport.cpp、conf/config.ini 等源码,完整讲解两种模式的架构、信令 URL 格式、房间管理 API、流代理 API 以及[rtc]配置段,读完即可独立完成 WebRTC 拉流代理、房间管理和相关服务端调优。
一、WebRTC 双模式架构总览
ZLMediaKit 的 WebRTC 模块同时支持两种截然不同的信令与媒体转发模型,二者由 URL 参数signaling_protocols区分(0或1):
- SFU 模式(WHIP/WHEP):媒体流全部经服务器中继,天然支持多路复用与转码,适合广播、多人会议等场景;
- P2P 模式(WebSocket 信令):信令仍经过服务器(WebSocket + STUN + TURN 辅助),但媒体面由两端直接建立连接,降低服务器带宽压力,适合低延迟通话与私人通信。
在服务端实现上,两类连接由不同的 Session 承载:信令由WebRtcWebcosktSignalingSession(WebSocket 信令服务器)处理,媒体面统一由WebRtcSession(UDP/TCP)承载,STUN/TURN 由IceSession提供。对应启动逻辑见 server/main.cpp:
// webrtc udp服务器 if (rtcPort) { rtcSrv_udp->start<WebRtcSession>(rtcPort, listen_ip); } if (rtcTcpPort) { rtcSrv_tcp->start<WebRtcSession>(rtcTcpPort, listen_ip); } // webrtc 信令服务器 if (signalingPort) { signaleSrv->start<WebRtcWebcosktSignalingSession>(signalingPort); } if (signalSslPort) { signalsSrv->start<WebRtcWebcosktSignalSslSession>(signalSslPort); } // STUN/TURN服务 if (icePort) { iceSrv->start<IceSession>(icePort); } if (iceTcpPort) { iceTcpSrv->start<IceSession>(iceTcpPort); }注意:以上所有服务均遵循“端口为 0 则不开机”的约定(详见 server/main.cpp 对signalingPort、icePort等配置的读取),因此默认conf/config.ini中这些端口为0时 WebRTC 相关服务不会启动。
1. SFU 模式(WHIP/WHEP)架构
WHIP(WebRTC-HTTP Ingestion Protocol)与 WHEP(WebRTC-HTTP Egress Protocol)是 IETF 标准化的 HTTP 信令协议,一个用于推流(ingest),一个用于拉流(playback)。ZLMediaKit 将其作为 SFU 模式的信令实现:
WebRTC SFU 模式 (WHIP/WHEP) 推流端 (WHIP) 拉流端 (WHEP) +----------------+ +-----------------+ | Encoder | | Player | | (Browser/ZLM) | | (Browser/ZLM) | +----------------+ +-----------------+ | | | WHIP Protocol | WHEP Protocol | (WebRTC ingest) | (WebRTC playback) | | v v +-------------------------------------------------------------------+ | ZLMediaKit Server | +-------------------------------------------------------------------+ - WHIP: WebRTC-HTTP Ingestion Protocol (推流) - WHEP: WebRTC-HTTP Egress Protocol (拉流)媒体流统一汇聚到 ZLMediaKit 的流媒体管道(MultiMediaSourceMuxer多协议复用),因此 WHIP 推入的流可以同时被 RTSP、RTMP、HLS 等其他协议拉取,这是 SFU 模式下“多路复用”的直接体现。
2. P2P 模式(WebSocket 信令)架构
P2P 模式基于 ZLMediaKit 自定义的 WebSocket 信令协议。客户端 A/B 与服务器之间通过 WebSocket 交换 SDP Offer/Answer 与 ICE Candidate,最终媒体直接点对点传输:
WebRTC P2P 模式 客户端 A 客户端 B +------------+ +-------------+ | Browser/ZLM| | Browser/ZLM | +------------+ +-------------+ | | | 1. 信令交换 (SDP Offer/Answer) | | 2. ICE Candidate 交换 | +---------------- -----+-----------------------+ | | | | +-----------------------+ | | | ZLMediaKit Server | | | | 信令服务器 (WebSocket) | | | | STUN 服务器 | | | | TURN 服务器 | | | +-----------------------+ | | | +-----------------------------------------------+ 直接P2P连接在 P2P 模式下,服务器承担三份职责:WebSocket 信令转发、STUN(打洞探测公网地址)、TURN(Relay 兜底转发)。当两端无法建立直连(对称 NAT 等)时,ICE 会回落到 TURN Relay,此时portRange端口池(conf/config.ini中为port_range=49152-65535)开始生效。
从源码看,P2P 模式的房间归属由WebRtcSignalingPeer管理:客户端通过checkIn(peer_room_id, ...)登记到目标房间并触发呼叫请求(sendCallRequest),离开时调用checkOut(peer_room_id)发送 Bye 通知,相关逻辑见 webrtc/WebRtcSignalingPeer.cpp 与 webrtc/WebRtcClient.cpp。
二、WebRTC URL 格式与信令协议参数
无论是拉流代理还是推流代理,WebRTC 源/目标 URL 都遵循统一格式,并通过 query 参数选择信令模式。
1. WHIP/WHEP 模式(SFU)——signaling_protocols=0
标准 HTTP 信令协议,为默认模式(WebRtcClient.h中_signaling_protocols默认值即WHEP_WHIP):
# HTTP webrtc://server_host:server_port/app/stream_id?signaling_protocols=0 # HTTPS(暂未实现) webrtcs://server_host:server_port/app/stream_id?signaling_protocols=02. WebSocket P2P 模式——signaling_protocols=1
基于 WebSocket 的自定义信令协议,需额外指定目标房间:
# WebSocket webrtc://signaling_server_host:signaling_server_port/app/stream_id?signaling_protocols=1&peer_room_id=target_room_id # WebSocket Secure(暂未实现) webrtcs://signaling_server_host:signaling_server_port/app/stream_id?signaling_protocols=1&peer_room_id=target_room_id注意:在curl -d表单提交中,&必须做 URL 编码(%26),否则会被 shell 或表单解析器误认为多个参数,详见下文请求示例。
3. 参数对照表
| 参数 | 取值 | 含义 | 说明 |
|---|---|---|---|
signaling_protocols | 0 | WHIP/WHEP 模式(默认) | 基于 HTTP 的标准 WebRTC 信令;SFU 场景,适合广播与多人会议 |
signaling_protocols | 1 | WebSocket P2P 模式 | 基于 WebSocket 的自定义信令;点对点直连,适合低延迟通话与私人通信 |
peer_room_id | 任意字符串 | P2P 目标房间 ID | 仅 P2P 模式需要,对应WebRtcSignalingPeer::checkIn的peer_room_id入参 |
从源码角度印证:URL 解析位于 webrtc/WebRtcClient.cpp,客户端读取peer_room_id与signaling_protocols后,在 webrtc/WebRtcClient.cpp 中按协议类型分发到WEBSOCKET或WHEP_WHIP分支,未识别的协议值直接抛出not support signaling_protocols异常。
三、WebRTC 房间管理 HTTP API
P2P 模式依赖“房间保持器(Room Keeper)”把本地房间注册到远端信令服务器。相关 API 统一挂在 ZLMediaKit 的 HTTP API 体系下(实现在 server/WebApi.cpp,均要求secret鉴权,即CHECK_SECRET())。
1. 添加房间保持器
POST /index/api/addWebrtcRoomKeeper在指定信令服务器上维持一个房间连接,注册后信令服务器会对room_id做唯一性检查。请求参数:
| 参数 | 说明 |
|---|---|
secret | 接口访问密钥 |
server_host | 信令服务器主机地址 |
server_port | 信令服务器端口 |
room_id | 房间 ID,信令服务器对该 ID 进行唯一性检查 |
调用链:addWebrtcRoomKeeper(server_host, server_port, room_id, ssl)→ 通过WebRtcSignalingPeer建立 WebSocket 连接并注册房间。成功返回data.room_key(房间保持器唯一标识),该值在删除接口中要用到。
2. 删除房间保持器
POST /index/api/delWebrtcRoomKeeper删除指定信令服务器上的房间保持器。请求参数:
| 参数 | 说明 |
|---|---|
secret | 接口访问密钥 |
room_key | 房间保持器的唯一标识符(由添加接口返回) |
3. 列出所有房间保持器
POST /index/api/listWebrtcRoomKeepers请求参数仅secret。返回每个房间保持器对应WebRtcSignalingPeer的 JSON 序列化信息(ToJson(p)),并附加room_key字段。
4. 列出活跃的 WebRTC 房间会话
POST /index/api/listWebrtcRooms请求参数仅secret。枚举当前所有活跃的WebRtcSignalingSessionPeer 会话,返回项附加room_id字段。会话对象维护于WebRtcSignalingSession的全局注册表中(见 webrtc/WebRtcSignalingSession.cpp)。
5. 查询 WebRTC 代理播放器信息
POST /index/api/getWebrtcProxyPlayerInfo获取 WebRTC 代理播放器的连接信息和状态。请求参数:
| 参数 | 说明 |
|---|---|
secret | 接口访问密钥 |
key | 代理播放器标识符 |
实现要点(server/WebApi.cpp):通过key找到WebRtcProxyPlayerImp并取其WebRtcTransport,异步调用getTransportInfo返回 ICE 候选、连接状态等传输信息;若 key 不存在返回NotFound,若代理不是 WebRTC 类型返回OtherFailed。
四、WebRTC 拉流与推流代理 API
ZLMediaKit 复用标准的流代理接口(addStreamProxy/addStreamPusherProxy)创建 WebRTC 拉流与推流,两种信令模式均可通过 URL 参数切换。
1. 创建 WebRTC 拉流代理
POST /index/api/addStreamProxy| 参数 | 说明 |
|---|---|
secret | 接口访问密钥 |
vhost | 虚拟主机名,默认为__defaultVhost__ |
app | 应用名 |
stream | 流 ID |
url | WebRTC 源 URL(支持上述两种格式) |
WHIP/WHEP 模式拉流示例:
curl -X POST "http://127.0.0.1/index/api/addStreamProxy" \ -d "secret=your_secret" \ -d "vhost=__defaultVhost__" \ -d "app=live" \ -d "stream=test" \ -d "url=webrtc://source.server.com:80/live/source_stream?signaling_protocols=0"P2P 模式拉流示例(注意&编码为%26):
curl -X POST "http://127.0.0.1/index/api/addStreamProxy" \ -d "secret=your_secret" \ -d "vhost=__defaultVhost__" \ -d "app=live" \ -d "stream=test" \ -d "url=webrtc://signaling.server.com:3000/live/source_stream??signaling_protocols=1%26peer_room_id=target_room_id"拉流代理在服务端对应WebRtcProxyPlayer(继承PlayerProxy体系),通过WebRtcPlayer内部创建WebRtcTransport并完成信令握手,最终把 WebRTC 流接入本地媒体管道。
2. 创建 WebRTC 推流代理(暂未实现)
POST /index/api/addStreamPusherProxy注意:该接口当前尚未实现(USAGE.md明确标注“暂未实现”,也列入文末未实现功能清单),此处仅给出约定中的接口契约与参数,供后续版本参考:
| 参数 | 说明 |
|---|---|
secret | 接口访问密钥 |
schema | 源流协议(如 rtmp、rtsp、hls 等) |
vhost | 虚拟主机名 |
app | 应用名 |
stream | 源流 ID |
dst_url | WebRTC 目标推流 URL |
约定中的 WebRTC 推流 URL 格式与拉流一致:
WHIP 模式(SFU)——推流到支持 WHIP 的服务器:
# HTTP webrtc://target_server:port/app/stream_id?signaling_protocols=0 # HTTPS(暂未实现) webrtcs://target_server:port/app/stream_id?signaling_protocols=0WebSocket P2P 模式——推流到 P2P 房间:
# WebSocket webrtc://signaling_server:port/app/stream_id?signaling_protocols=1&peer_room_id=target_room # WebSocket Secure webrtcs://signaling_server:port/app/stream_id?signaling_protocols=1&peer_room_id=target_room
约定的请求示例:
# 将RTSP流推送到WHIP服务器 curl -X POST "http://127.0.0.1/index/api/addStreamPusherProxy" \ -d "secret=your_secret" \ -d "schema=rtsp" \ -d "vhost=__defaultVhost__" \ -d "app=live" \ -d "stream=test" \ -d "dst_url=webrtc://target.server.com:80/live/target_stream?signaling_protocols=0" # 将RTSP流推送到P2P房间 curl -X POST "http://127.0.0.1/index/api/addStreamPusherProxy" \ -d "secret=your_secret" \ -d "schema=rtsp" \ -d "vhost=__defaultVhost__" \ -d "app=live" \ -d "stream=test" \ -d "dst_url=webrtc://signaling.server.com:3000/live/room_stream?signaling_protocols=1%26peer_room_id=target_room_id"五、[rtc]配置段详解
WebRTC 相关配置全部位于config.ini的[rtc]段。以下配置来自 conf/config.ini,并交叉核对 webrtc/WebRtcTransport.cpp 中Rtc命名空间的默认值与字段定义:
[rtc] #webrtc 信令服务器端口 signalingPort=3000 #STUN/TURN服务器端口 icePort=3478 #STUN/TURN端口是否使能TURN服务 enableTurn=1 #TURN服务分配端口池 portRange=50000-65000 #ICE传输策略:0=不限制(默认),1=仅支持Relay转发,2=仅支持P2P直连 iceTransportPolicy=0 #UDP ICE会话空闲超时时间,单位秒,0为关闭 iceSessionTimeoutSec=60 #STUN/TURN 服务Ice密码 iceUfrag=ZLMediaKit icePwd=ZLMediaKit各配置项说明与源码对应
| 配置项 | 说明 | 源码默认值 |
|---|---|---|
signalingPort | WebRTC 信令服务器(WebSocket)监听端口 | 0(源码默认关闭,见 WebRtcTransport.cpp) |
icePort | STUN/TURN 服务器 UDP 端口 | 0(默认关闭) |
enableTurn | STUN/TURN 端口是否使能 TURN 服务;1开启 | 1 |
portRange | TURN 服务分配端口池 | 仓库config.ini中为port_range=49152-65535 |
iceTransportPolicy | ICE 传输策略:0不限制(默认)、1仅 Relay 转发、2仅 P2P 直连 | 0 |
iceSessionTimeoutSec | UDP ICE 会话空闲超时(秒),0关闭 | 60 |
iceUfrag/icePwd | STUN/TURN 服务 ICE 凭证 | ZLMediaKit/ZLMediaKit |
源码层面的深层解读
- 配置注册与默认值:
Rtc命名空间在 webrtc/WebRtcTransport.cpp 通过onceToken统一注册上述所有字段的默认值,例如kSignalingPort = 0、kIcePort = 0、kEnableTurn = 1、kIceTransportPolicy = 0、kIceSessionTimeoutSec = 60、kIceUfrag = kIcePwd = "ZLMediaKit"。这意味着即使config.ini未显式配置,进程内也有一套可用的兜底值。 - 端口 0 即关闭:服务端读取
signalingPort、icePort后仅在非 0 时启动对应服务(server/main.cpp)。因此生产环境必须显式把端口配为非 0,否则 WebRTC 信令与 STUN/TURN 服务不会监听。 - ICE 凭证的下发:
WebRtcSignalingSession在生成ice_servers(STUN/TURN 服务器列表)时读取icePort、iceUfrag、icePwd,并拼接turn://或stun://URL 下发给客户端(webrtc/WebRtcSignalingSession.cpp);IceSession则用同一份 ufrag/pwd 校验入站 STUN 请求(webrtc/IceSession.cpp)。修改凭证时务必保持两端一致。 - 其它相关配置:
[rtc]段还有port(WebRTC 单端口 UDP 服务器,默认 8000)、tcpPort、signalingSslPort、iceTcpPort、timeoutSec(RTP/RTCP 接收超时,默认 15 秒)、externIP(服务器外网 IP,用于生成正确的 ICE 候选)等,均可在 conf/config.ini 与 webrtc/WebRtcTransport.cpp 中查阅。
六、防火墙与部署注意事项
WebRTC 依赖大量 UDP 端口,部署时务必在防火墙/安全组中放行:
- 信令端口:3000(默认,对应
signalingPort),供 WebSocket 信令连接; - STUN/TURN 端口:3478(默认,对应
icePort),供 STUN 打洞探测与 TURN 分配请求; - TURN Alloc 端口范围:50000-65000(默认,对应
portRange),TURN Relay 实际转发媒体所用的动态端口池;仓库 conf/config.ini 中该项名为port_range=49152-65535,以当前仓库实际配置为准。
此外还应注意:
- 媒体端口:WebRTC 媒体默认由
[rtc] port(UDP,默认 8000)与tcpPort承载,需一并放行; - 外网部署:服务器在 NAT 后时需配置
externIP,否则 ICE 候选中的地址是内网地址,客户端无法连通; - P2P 打洞失败兜底:若双方 NAT 类型无法打洞成功,媒体会经 TURN Relay 转发,此时 TURN 端口池的容量直接决定并发上限。
七、参考示例与未实现功能清单
官方参考示例
USAGE.md提供了一个基于 libwebrtc 实现的 P2P 代理拉流简单示例(zlm_peerconnection),可用于快速验证 P2P 模式的信令流程与房间机制。仓库内的webrtc/目录还包含WebRtcPlayer、WebRtcPusher、WebRtcProxyPlayer、WebRtcProxyPusher、WebRtcTalk、WebRtcEchoTest等完整客户端/服务端实现,www/webrtc/ZLMRTCClient.js提供了浏览器端 JavaScript 客户端,可作为二次开发的起点。
暂未实现的功能
当前版本(以仓库实际代码为准)以下功能尚不支持,请勿在文档中当作可用能力:
- WebRTC 信令服务的安全校验(WebSocket 信令缺少鉴权);
- 自定义外部 STUN/TURN 服务器的配置(当前 STUN/TURN 由 ZLMediaKit 内置提供);
- WebRTC 代理推流(
addStreamPusherProxy接口尚未实现); - HTTPS/WSS 信令(URL 中的
webrtcs://标记为“暂未实现”)。
八、总结
ZLMediaKit 的 WebRTC 能力围绕“双信令模式”展开:signaling_protocols=0走标准 WHIP/WHEP HTTP 信令实现 SFU 中继,signaling_protocols=1走 WebSocket 自定义信令实现 P2P 房间直连;通过addStreamProxy、房间管理系列 API 与[rtc]配置段,可以组合出广播、会议、点对点通话等多种拓扑。部署时牢记三点:信令端口、STUN/TURN 端口与 TURN 端口池必须放行;端口为 0 的服务不会启动;外网环境务必配置externIP。如需深入源码,建议从 server/main.cpp(服务启动)、webrtc/WebRtcSignalingPeer.cpp(房间信令)、webrtc/WebRtcClient.cpp(URL 解析与协议分发)三个文件入手。
- 音视频
- 直播
- 后端
【免费下载链接】ZLMediaKit
WebRTC/RTSP/RTMP/HTTP/HLS/HTTP-FLV/WebSocket-FLV/HTTP-TS/HTTP-fMP4/WebSocket-TS/WebSocket-fMP4/GB28181/SRT/STUN/TURN server and client framework based on C++11
相关推荐
SRS WebRTC 实战指南:WHIP/WHEP 推拉流、Candidate 配置与 SFU 架构详解
SRS WebRTC 实战指南:WHIP/WHEP 推拉流、Candidate 配置与 SFU 架构详解 导读 WebRTC 是 Google 开源的浏览器实时
音视频后端直播DLSS Swapper 上手指南:不等游戏更新也能换 DLSS 版本
DLSS Swapper 上手指南:不等游戏更新也能换 DLSS 版本 DLSS Swapper 是一款免费开源的 Windows 工具,能把游戏里的 DLSS
桌面应用RT-Thread RTC 设备驱动框架详解:时间设置、date 命令与 Soft RTC 使用指南
RT Thread RTC 设备驱动框架详解:时间设置、date 命令与 Soft RTC 使用指南 RT Thread 的 RTC(实时时钟)设备为操作系统的
操作系统嵌入式物联网嵌入式OSRTOS
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考