SRS WebRTC Signaling 信令服务实战:Docker 部署、源码构建与 HTTPS/WSS 反向代理指南
2026/9/25 1:04:56 网站建设 项目流程

SRS WebRTC Signaling 信令服务实战:Docker 部署、源码构建与 HTTPS/WSS 反向代理指南

【免费下载链接】srsSRS is a simple, high-performance, AI-driven real-time media server supporting RTMP, WebRTC, HLS, HTTP-FLV, HTTP-TS, SRT, MPEG-DASH, and GB28181, with codec support for H.264, H.265, AV1, VP9, AAC, Opus, and G.711.项目地址: https://gitcode.com/GitHub_Trending/sr/srs

SRS(Simple Realtime Server)采用「信令面与媒体面分离」的架构:媒体面由 SRS 的 RTC 模块负责(WHIP/WHEP、SRTP/SRTCP、ICE/DTLS),而信令面需要一个轻量级服务来协调浏览器之间的房间加入、发布状态与呼叫控制。trunk/3rdparty/signaling正是 SRS 官方随仓库发布的demo WebRTC signaling——一个基于 Go + WebSocket 的极简信令服务。本文将以 signaling/README.md 为骨架,完整讲解如何用 Docker 一键跑通 SRS + signaling 的 WebRTC 通话演示、如何从源码构建运行,并结合 main.go 与前端 SDK 源码剖析其信令协议与房间模型,最后给出通过 httpx-static 将演示服务升级为 HTTPS/WSS 的完整方案。读完本文,你可以独立搭建一套可演示、可学习、可二次开发的一对一/多人 WebRTC 信令系统。

一、signaling 是什么:SRS WebRTC 架构中的信令面

在 SRS 的 WebRTC 解决方案中,浏览器之间的媒体流通过 SRS 的 SFU(Selective Forwarding Unit)进行转发,这一过程使用标准化的 WHIP(WebRTC-HTTP Ingestion Protocol,推流)与 WHEP(WebRTC-HTTP Egress Protocol,拉流)完成 SDP 交换;而「谁在哪个房间、谁开始发布、谁要离开、互相发送控制消息」这类协调工作,则需要信令服务来完成。signaling 正是承担这一角色的官方 demo 实现。

该组件位于仓库trunk/3rdparty/signaling/目录,核心构成如下:

文件/目录作用
README.md使用与构建文档(本文主体)
main.goGo 实现的服务端,提供 WebSocket 信令与静态页面服务
Makefile构建脚本,产出objs/signaling二进制
Dockerfile基于 Ubuntu 的两阶段镜像构建
go.modGo 模块定义,依赖go-oryx-libgolang.org/x/net
auto/pub.sh打 tag 发布脚本
www/demos/一对一会话、多人房间等 H5 演示页面与前端 SDK

从 go.mod 可以看到,服务端基于 Go 1.16,仅依赖两个模块:github.com/ossrs/go-oryx-lib(日志、错误处理等基础库)与golang.org/x/net(其中提供websocket包)。整个服务端核心逻辑集中在单个 main.go(约 350 行)中,非常适合作为学习与二次开发的起点。

二、快速体验:Docker 一键跑通 SRS + signaling

2.1 启动 SRS(RTC 配置)

首先在 Docker 中启动 SRS,使用 RTC 专用配置 trunk/conf/rtc.conf,并通过环境变量CANDIDATE指定本机公网/局域网 IP(用于 ICE candidate 协商):

docker run --rm --env CANDIDATE=$(ifconfig en0 inet| grep 'inet '|awk '{print $2}') \ -p 1935:1935 -p 8080:8080 -p 1985:1985 -p 8000:8000/udp \ registry.cn-hangzhou.aliyuncs.com/ossrs/srs:4 \ objs/srs -c conf/rtc.conf

说明:CANDIDATE应替换为实际可达的 IP(如ifconfig输出中的 en0 地址,或云主机公网 IP)。更多镜像与版本可参考镜像仓库页面。

各端口在 SRS 中的作用:

端口协议用途
1935TCPRTMP 推拉流
8080TCPSRS HTTP 服务(HLS、HTTP-FLV 等)
1985TCPSRS HTTP API(HTTP API、WHIP/WHEP SDP 交换)
8000UDPWebRTC 媒体流(SRTP/SRTCP)

2.2 启动 signaling 服务

在另一个终端启动 signaling,监听 1989 端口:

docker run --rm -p 1989:1989 registry.cn-hangzhou.aliyuncs.com/ossrs/signaling:1

说明:signaling 镜像会同时托管静态演示页面(www目录),因此 1989 端口既是 WebSocket 信令端口,也是 H5 演示页面的 HTTP 端口。

2.3 打开 H5 演示

浏览器访问即可进入一对一通话演示(带autostart=true自动开始):

  • WebRTC: One to One over SFU(SRS)

这是 README 给出的最小验证路径:两个浏览器分别打开上述地址,加入同一房间后即可互通音视频。整套环境仅需两个容器,无需任何代码。

三、从源码构建与运行

如果希望调试、修改或深入学习,可以从源码构建。

3.1 构建并运行 SRS

在已就绪的 SRS 仓库中,进入trunk目录执行配置与编译(rtc.conf位于 trunk/conf/rtc.conf):

cd ~/git/srs/trunk && ./configure && make && ./objs/srs -c conf/rtc.conf

3.2 构建并运行 signaling

在 signaling 目录执行make,产物为objs/signaling

cd ~/git/srs/trunk/3rdparty/signaling && make && ./objs/signaling

从 Makefile 可以看到构建细节:make会先执行gofmt -w .统一格式(生成.format.txt标记),然后以go build -mod=vendor -o objs/signaling .进行编译。目标文件仅一个二进制 +www静态目录,非常轻量。

运行后浏览器打开演示列表:http://localhost:1989/demos

3.3 服务端启动参数

从 main.go 可以看到,signaling 支持两个命令行参数:

参数默认值说明
-listen1989TCP 监听端口(信令 WebSocket + 静态页面共用)
-root./www静态页面根目录;若为相对路径且可执行文件路径为绝对路径,则自动拼接到可执行文件所在目录

启动日志会输出Signaling ok, root=..., home page is ...,其中 home page 即演示首页地址。

四、信令协议与核心源码剖析

4.1 两个 HTTP 端点

signaling 在同一个端口上提供了三个路由(见 main.go):

  • /—— 静态文件服务(http.FileServer),托管www演示页面;
  • /sig/v1/versions—— 返回字符串1.0,用于版本探活;
  • /sig/v1/rtc—— WebSocket 信令端点,核心逻辑所在。

4.2 WebSocket 消息帧格式

客户端通过ws://host:1989/sig/v1/rtc?room=<房间名>&display=<昵称>建立连接(见 srs.sig.js)。消息为 JSON 文本帧,外层带事务 IDtid

{ "tid": "a1b2c3d", "msg": { "action": "join", "room": "live", "display": "alice" } }

服务端响应同样携带tid回包;而服务端主动广播的通知(notify)则不带tid,通过event字段区分事件类型。

4.3 三种 Action:join / publish / control

从 main.go 可以完整还原服务端对三类消息的处理:

join(加入房间):解析msg.roommsg.display,通过sync.MapLoadOrStore获取/创建房间,创建Participant并调用Room.Add加入。Add会做同名检查(main.go),若房间内已存在相同display则返回错误。成功后向本人返回{action, room, self, participants}(房间当前成员列表),并向其他成员广播event: "join"

publish(宣布发布):找到房间内对应display的参与者,将其Publishing置为true,随后向其他成员广播event: "publish"。收到该事件的成员即可知道「有人开始推流了」,从而发起 WHEP 拉流。

control(控制消息):携带calldata两个透传字段(如call: "refresh"call: "alert"+ 任意data),服务端将其原样广播给房间内其他成员,实现演示中的「刷新对方页面」「给对方弹窗」等自定义控制。

4.4 服务端数据模型:Room 与 Participant

服务端的数据模型非常清晰(main.go):

  • ParticipantDisplay(昵称)、Publishing(是否推流中)、Out(该连接的消息发送通道chan []byte);
  • RoomName(房间名)、Participants(成员切片),并以sync.RWMutex保护并发读写;
  • 全局rooms sync.Map:以房间名为 key 持有所有房间。

连接的读写模型采用双 goroutine + 通道:读取 goroutine 循环Read消息并送入inMessages,处理 goroutine 逐个处理并回包,写入 goroutine 循环从outMessages取数据Write回客户端。连接断开时(main.go),服务端会先向房间内其他成员广播event: "leave",再将自身从房间移除——这正是「有人离开」通知的来源,前端收到leave事件后会隐藏播放器(见 one2one.html)。

4.5 广播通知的完整结构

Room.Notify(main.go)在加锁快照成员列表后,向除发送者外的每个成员投递以下结构:

{ "action": "notify", "event": "join | publish | leave | control", "param": "", "data": "", "room": "房间名", "self": { "display": "接收者", "publishing": false }, "peer": { "display": "发送者", "publishing": false }, "participants": [ "房间内全部成员" ] }

其中control事件的param对应call字段、data对应data字段。该结构同时覆盖了self(自己)、peer(对方)与participants(全量成员),足以支撑一对一与多人的房间状态同步。

4.6 前端 SDK:srs.sig.js

演示页面的信令客户端封装在 srs.sig.js 中,提供三个核心 API:

  • connect(schema, host, room, display):建立ws(s)://host/sig/v1/rtc?room=..&display=..连接,返回 Promise;
  • send(message):为消息生成 7 位十六进制tid,将{resolve, reject}存入_internals.msgs后发送;收到同tid响应即 resolve(srs.sig.js);
  • onmessage(msg):回调,用于接收服务端主动广播的 notify 事件。

此外SrsRtcSignalingParse(srs.sig.js)负责从 URL 解析wsswshwsphostroomdisplayautostart等参数,并把与信令无关的查询参数原样透传给媒体层(如 WHIP/WHEP 的 token)。

五、H5 演示与 WHIP/WHEP 媒体流打通

5.1 演示页面

www/demos/下提供两个核心演示(入口见 index.html):

  • one2one.html:一对一视频通话;
  • room.html:多人视频房间(Video Room)。

两个页面都支持autostart=true自动启动,便于直接粘贴 URL 分享。

5.2 一对一流程拆解

以 one2one.html 为例,完整流程为:

  1. sig.connect(...)建立信令连接;
  2. sig.send({action:'join', room, display})加入房间,返回成员列表;
  3. startPublish:将webrtc://地址转换为 WHIP URL(http(s)://host:1985|443/rtc/v1/whip/?app=<room>&stream=<display>)并调用SrsRtcWhipWhepAsync.publish()推流(见 srs.sdk.js);
  4. sig.send({action:'publish', room, display})广播「我在推流」;
  5. 对房间内已存在的publishing成员调用startPlay,使用 WHEP URL(/rtc/v1/whep/?app=<room>&stream=<display>)拉流播放(srs.sdk.js);
  6. 之后新成员加入或推流时,通过 notify 事件(publishjoinleave)触发对应的开始/停止播放。

媒体 URL 的端口规则(one2one.html 中convertToWhipUrl/convertToWhepUrl):HTTP 场景走 1985,HTTPS 场景走 443。而信令端口默认 1989;当演示页面通过 SRS 的 8080 HTTP 服务打开时,index.html会自动追加&wsp=1989让信令连接到 1989 端口(见 index.html)。

5.3 演示 URL 参数一览

参数含义默认值
hostSRS 媒体服务器地址当前页面 hostname
room加入的房间名随机生成
display用户昵称随机生成
wssWebSocket 协议(ws/wss依页面协议推断
wshWebSocket 服务器地址当前页面 hostname
wspWebSocket 端口当前页面端口
autostart页面加载后自动开始关闭

5.4 双人以上时的 FFmpeg 合流提示

participants.length >= 2时,one2one 页面会展开「FFmpeg 合流转直播」面板(见 one2one.html),给出将两路 RTMP 流用-filter_complex overlay合成为一路并推流到rtmp://host/<room>/merge的完整命令,并支持一键将输出对接视频号推流地址(填写推流地址与密钥后点击「应用」)。这一功能演示了 WebRTC 通话与 RTMP 直播体系的互转能力。

六、HTTPS/WSS 生产化:httpx-static 反向代理

WebRTC 的getUserMedia在非 localhost 环境强制要求 HTTPS(浏览器安全策略,见 srs.sdk.js 中HttpsRequiredError的抛出逻辑),因此将信令升级为 WSS 是实际部署的必经之路。SRS 仓库提供了 httpx-static 组件,一个 Go 实现的「HTTP/HTTPS 静态服务器 + API 反向代理」,可一站完成证书终止与多后端代理。

6.1 构建并运行 httpx-static

cd ~/git/srs/trunk/3rdparty/httpx-static && make && ./objs/httpx-static -http 80 -https 443 -ssk server.key -ssc server.crt \ -proxy http://127.0.0.1:1989/sig -proxy http://127.0.0.1:1985/rtc \ -proxy http://127.0.0.1:8080/

其中server.key/server.crt为自签或正式证书;若需要生成自签证书,httpx-static 的用法说明中给出了openssl genrsa+openssl req -x509的标准命令。

6.2 参数说明

从 httpx-static/main.go 可确认各参数语义:

参数(短/长)说明
-t/-httpHTTP 监听端口,0表示禁用
-s/-httpsHTTPS 监听端口,如443
-r/-root静态文件根目录,默认./html(相对可执行文件路径)
-k/-ssk自签或文件型证书的私钥文件
-c/-ssc自签或文件型证书的证书文件
-p/-proxy反向代理规则,可重复指定多个,按路径前缀匹配转发到后端
-d/-domainsHTTPS 允许的域名(配合 Let's Encrypt 时用于校验,留空允许所有)
-l/-lets是否使用 Let's Encrypt CA(否则使用自签证书)

代理规则的匹配是按路径前缀进行的,因此上面三条规则分别把/sig(signaling 信令)、/rtc(SRS 的 WHIP/WHEP API)、/(SRS 的 HTTP 服务与静态资源)分发到对应后端。README 中的另一条典型规则-proxy http://127.0.0.1:8888/api/webrtc也印证了这一「路径前缀 → 后端」的模型。此外-proxy还支持?trimPrefix=/x?addPrefix=/y?keepUpsreamServer=true?modifyRequestHost=false等高级修饰参数(见 main.go)。

6.3 通过 HTTPS/IP 访问演示

部署完成后,以下地址均可访问演示:

  • http://localhost/demos/
  • https://localhost/demos/
  • https://192.168.3.6/demos/

此时浏览器页面为 HTTPS(wss=自动推断为wss),媒体 API 走 443(443 上/rtc被代理到 SRS 1985),信令走wss://.../sig(被代理到 signaling 1989),三者通过同一域名 + 端口即可统一访问,规避了混合内容与getUserMedia安全限制。

七、从 demo 走向自研:源码结构给出的启示

需要明确的是,signaling 官方定位为demo(README 第一句即声明 "A demo WebRTC signaling"),从源码结构可以推断其面向演示与教学的设计取舍:

  • 单进程内存态:房间数据存于进程内sync.Map,无持久化、无水平扩展能力;多实例部署时需要自行引入共享状态(如 Redis)与一致性方案;
  • 无鉴权与配额join/control不校验身份与权限,任何人可加入任意房间;生产环境需在信令层或上层网关补充 Token 校验;
  • 媒体面完全交由 SRS:signaling 本身不处理 SDP/ICE,仅做事件转发,媒体质量、NAT 穿透(STUN/TURN)能力取决于 SRS 的 RTC 配置;
  • 协议简洁可扩展join/publish/control+notify的四事件模型足够通用,新增动作(如踢人、举手、录制开关)只需在 main.go 的消息分发处仿照现有分支扩展,并在 srs.sig.js 的send/onmessage上对接即可。

如果需要更完整的多方音视频能力,SRS 仓库的trunk/researchsrs-bench等目录也提供了压力测试与协议验证的参考实现,可作为扩展阅读。

总结

本文完整走通了 SRS WebRTC signaling 的三种使用形态:Docker 一键体验(两个容器 + 一个 URL 即可看到一对一通话)、源码构建make产出单二进制,-listen/-root两个参数即可运行)、HTTPS/WSS 生产化(httpx-static 按路径前缀反代/sig/rtc/三路后端)。同时结合 main.go 与 srs.sig.js 剖析了信令协议:/sig/v1/rtcWebSocket 端点、tid事务帧、join/publish/control三种动作、Room/Participant内存模型与join/publish/leave/control四类广播事件。无论你是要快速验证 SRS 的 WebRTC 能力,还是要在此 demo 基础上构建自己的房间信令服务,本文提供的部署命令、协议字段与源码定位都可以直接作为起点。

进一步阅读:

  • 信令服务完整源码:trunk/3rdparty/signaling/main.go
  • 前端信令 SDK:trunk/3rdparty/signaling/www/demos/js/srs.sig.js
  • WHIP/WHEP 媒体 SDK:trunk/3rdparty/signaling/www/demos/js/srs.sdk.js
  • 演示页面源码:trunk/3rdparty/signaling/www/demos/one2one.html
  • HTTPS/WSS 反代组件:trunk/3rdparty/httpx-static/main.go
  • SRS RTC 配置示例:trunk/conf/rtc.conf

【免费下载链接】srsSRS is a simple, high-performance, AI-driven real-time media server supporting RTMP, WebRTC, HLS, HTTP-FLV, HTTP-TS, SRT, MPEG-DASH, and GB28181, with codec support for H.264, H.265, AV1, VP9, AAC, Opus, and G.711.项目地址: https://gitcode.com/GitHub_Trending/sr/srs

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

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询