news 2026/10/2 12:06:53

ZLMediaKit WebRTC 使用指南:SFU(WHIP/WHEP) 与 P2P 双信令架构、HTTP API 与 [rtc] 配置全解

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
ZLMediaKit WebRTC 使用指南:SFU(WHIP/WHEP) 与 P2P 双信令架构、HTTP API 与 [rtc] 配置全解
  • 音视频
  • 直播
  • 后端

【免费下载链接】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

项目地址:https://gitcode.com/GitHub_Trending/zl/ZLMediaKit
点击查看免费下载

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=0

2. 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_protocols0WHIP/WHEP 模式(默认)基于 HTTP 的标准 WebRTC 信令;SFU 场景,适合广播与多人会议
signaling_protocols1WebSocket 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
urlWebRTC 源 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_urlWebRTC 目标推流 URL

约定中的 WebRTC 推流 URL 格式与拉流一致:

  1. WHIP 模式(SFU)——推流到支持 WHIP 的服务器:

    # HTTP webrtc://target_server:port/app/stream_id?signaling_protocols=0 # HTTPS(暂未实现) webrtcs://target_server:port/app/stream_id?signaling_protocols=0
  2. WebSocket 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

各配置项说明与源码对应

配置项说明源码默认值
signalingPortWebRTC 信令服务器(WebSocket)监听端口0(源码默认关闭,见 WebRtcTransport.cpp)
icePortSTUN/TURN 服务器 UDP 端口0(默认关闭)
enableTurnSTUN/TURN 端口是否使能 TURN 服务;1开启1
portRangeTURN 服务分配端口池仓库config.ini中为port_range=49152-65535
iceTransportPolicyICE 传输策略:0不限制(默认)、1仅 Relay 转发、2仅 P2P 直连0
iceSessionTimeoutSecUDP ICE 会话空闲超时(秒),0关闭60
iceUfrag/icePwdSTUN/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 端口,部署时务必在防火墙/安全组中放行:

  1. 信令端口:3000(默认,对应signalingPort),供 WebSocket 信令连接;
  2. STUN/TURN 端口:3478(默认,对应icePort),供 STUN 打洞探测与 TURN 分配请求;
  3. 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

项目地址:https://gitcode.com/GitHub_Trending/zl/ZLMediaKit
点击查看免费下载

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/2 12:06:43

Vector工具链的闭环:从向量表偏移到CANoe刷写验证

做嵌入式、汽车电子这行的人&#xff0c;几乎绕不开三个词&#xff1a;CANoe、HexView&#xff0c;以及GD32/STM32工程里那个让人又爱又恨的vector table base offset。这几天Vector官方接连放出来的更新&#xff0c;我所在的几个技术群里都在刷一句话&#xff1a;等了30年&…

作者头像 李华
网站建设 2026/10/2 12:05:44

高频与交流:从低频思维到高频电路设计的实战避坑指南

1. 从“1.5 高频与交流”这个标题说起第一次看到“1.5 高频与交流”这个标题&#xff0c;很多人会一头雾水。它不像“手把手教你写爬虫”那样直白&#xff0c;也不像“XX框架源码解析”那样有明确的指向。但恰恰是这种看似模糊的标题&#xff0c;往往藏着最值得深挖的内容。我个…

作者头像 李华
网站建设 2026/10/2 12:04:22

全AI编程体验-TraeCN 上位机开发实战:用Qt打通AI编程全流程

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/2 12:03:20

毫米波雷达感知链路全解析:从ADC采样到目标跟踪

第一次在实验室里把毫米波雷达的感知链路完整调通时&#xff0c;我盯着屏幕上的目标列表愣了好几秒——一个被标记为ID 3的目标&#xff0c;距离、速度、角度都在稳稳地刷新&#xff0c;而它的位置坐标在几帧之前还是一团只有我能看懂的复数频点。很多人拿到车载雷达或工业毫米…

作者头像 李华
网站建设 2026/10/2 12:02:39

HSTU在Dynamo-Triton中的AOTI与KV缓存验收方法

NVIDIA在9月30日公布HSTU生成式推荐的端到端部署流程&#xff1a;PyTorch提前编译、FlexKV缓存、原生C回放&#xff0c;再由Dynamo-Triton服务。最吸睛的是八层模型在批量8、GPU缓存100%命中时最高5.93倍的延迟改善&#xff0c;但真正决定你能否拿到收益的&#xff0c;是线上用…

作者头像 李华