1. 基本知识
1.1 webrtc
一、WebRTC的本质:实时通信的“网络协议栈”类比
将WebRTC类比为Linux网络协议栈极具洞察力,二者在架构设计和功能定位上高度相似:
-
分层协议栈架构
- Linux网络协议栈:从底层物理层到应用层(如TCP/IP、UDP),负责数据的封装、传输、路由及解析,是操作系统网络能力的核心。
- WebRTC协议栈:
- 传输层:基于UDP实现自定义数据通道(DataChannel)和音视频流传输,内置RTCPeerConnection处理连接建立、NAT穿越(STUN/TURN)和带宽管理。
- 媒体处理层:集成音视频编解码模块(VP8/VP9/H.264、Opus)、前向纠错(FEC)、降噪算法等,实现低延迟媒体流的实时处理。
- 应用层接口:通过浏览器API(如
getUserMedia
、RTCPeerConnection
)暴露功能,类似Linux通过Socket接口供应用调用。
-
原生性与系统整合
- Linux协议栈是操作系统内核的原生组件,WebRTC则是浏览器内核的原生模块(如Chrome的Blink引擎),直接调用操作系统的硬件接口(摄像头、麦克风、网络驱动),避免中间层性能损耗。
二、浏览器中的WebRTC:API接口的技术全景
WebRTC在浏览器中的实现,本质是将协议栈能力通过标准化API开放给开发者,其核心接口体系包括:
- 媒体采集与设备控制
getUserMedia
:直接调用设备传感器,获取音视频流,支持参数配置(如分辨率、帧率、摄像头方向)。navigator.mediaDevices.getUserMedia({ video: { facingMode: "user" }, audio: true })
MediaRecorder
:基于WebRTC流实现客户端录制(如录制会议内容)。
- 点对点连接建立
RTCPeerConnection
:核心接口,负责创建连接、交换SDP信令、管理ICE候选(网络地址),并通过addTrack
/ontrack
处理媒体流传输。- 信令解耦设计:浏览器仅处理媒体通道,信令通道需开发者自建(如WebSocket),这种分离模式与Linux协议栈“内核处理传输,用户态处理应用逻辑”的设计一致。
1.2 sfu模式
SFU模式(Selective Forwarding Unit)深度解析:架构、原理与应用场景
一、SFU模式的核心定义与定位
SFU(选择性转发单元)是流媒体服务器的一种转发模式,其核心功能是接收多个客户端的媒体流,根据订阅关系选择性地将流转发给其他客户端,而非对媒体流进行解码、混流或重新编码。
- 类比说明:
- 若将媒体流视为“快递包裹”,SFU相当于快递分拣中心:
- 包裹(原始流)到达分拣中心后,仅根据收件地址(订阅关系)重新分拣投递,不拆包(不解码)、不合并包裹(不混流)。
- 优势在于低延迟、低计算消耗,适合实时性要求高的场景(如互动直播、视频会议)。
- 若将媒体流视为“快递包裹”,SFU相当于快递分拣中心:
二、SFU的技术架构与工作流程
1. 核心组件与网络模型
(典型SFU架构示意图:客户端A/B/C发布流至SFU,SFU根据订阅关系将流转发给订阅者)
-
关键角色:
- 发布者(Publisher):客户端向SFU发送媒体流(如摄像头采集的视频流)。
- 订阅者(Subscriber):客户端向SFU请求订阅特定流,接收转发的流数据。
- SFU服务器:
- 维护流路由表(记录每个流的发布者与订阅者列表)。
- 通过传输层协议(如UDP、WebRTC DataChannel)接收和转发流数据,不涉及媒体层处理。
-
数据流向:
- 发布者通过RTMP/WebRTC等协议将流推至SFU。
- SFU解析流元数据(如流ID),存储到路由表。
- 订阅者向SFU请求订阅某个流ID。
- SFU根据路由表,将该流的数据包复制并转发给所有订阅者。
2. 与MCU模式的本质区别
维度 | SFU模式 | MCU模式(Multipoint Control Unit) |
---|---|---|
媒体处理 | 不解码、不混流,仅转发原始数据包 | 解码所有流,混合成单一流(如将多路视频合成画中画) |
延迟 | 极低(仅网络传输延迟+转发处理时间) | 高(需解码、混流、重新编码,引入处理延迟) |
带宽消耗 | 发布者推1路流,订阅者接收N路流(总带宽≈发布带宽×N) | 发布者推N路流,服务器混流后推1路流(总带宽≈发布带宽×N + 混流带宽) |
计算资源 | 几乎无媒体处理消耗,适合高并发 | 需大量CPU/GPU资源,并发量受限 |
典型场景 | 实时互动直播、多人视频会议(如Zoom) | 低并发、需要画面合成的场景(如传统视频会议) |
三、SFU模式的技术优势与适用场景
1. 核心优势
-
低延迟特性:
- 无解码-编码环节,延迟通常控制在100ms-500ms级别,满足实时互动需求(如连麦、弹幕互动)。
- 对比:传统CDN直播延迟约2-3秒,MCU模式延迟约500ms-1秒。
-
高扩展性与低资源消耗:
- 服务器仅负责转发,单台SFU可支持数万路流并发转发(取决于网络带宽)。
- 节省计算资源,适合构建大规模实时通信系统(如在线教育平台、电商直播)。
-
灵活性与兼容性:
- 支持多协议接入(WebRTC、RTMP、SRT等),通过转协议网关实现跨终端互通(如浏览器WebRTC流转发给RTMP推流的手机端)。
- 支持动态路由:可根据订阅者网络质量动态选择转发策略(如丢弃高延迟订阅者的流,或启用FEC增强可靠性)。
2. 典型应用场景
-
实时互动直播:
- 场景:主播与观众连麦、多人PK直播。
- 实现:主播推流至SFU,观众订阅主播流;连麦者推流至SFU,SFU将连麦者流转发给主播和其他观众。
- 案例:Twitch的低延迟直播、B站“直播连麦”功能。
-
视频会议系统:
- 场景:百人以上的远程会议,需支持动态加入/退出。
- 实现:每个参会者发布自己的流至SFU,根据会议布局(如“发言人模式”),SFU将主讲人流转发给所有参会者。
- 案例:Zoom的“分组讨论”功能基于SFU实现动态流转发。
-
物联网与实时监控:
- 场景:多个摄像头实时回传画面至监控中心,支持多用户实时查看。
- 实现:摄像头通过RTSP推流至SFU,监控客户端订阅指定摄像头流,SFU按需转发。
2 srs流媒体服务器
2.1 SFU转发单位
- 流接收与注册:
- 协议适配:支持 WebRTC 协议,接收客户端(发布者)通过 WebRTC 推来的音视频流 ,也可处理 RTMP 等其他协议转 WebRTC 后的流,通过如
/rtc/v1/publish/
接口逻辑,解析流的元数据(如流 ID、编码格式、分辨率等) 。 - 流注册:将接收的流信息(流 ID、发布者标识等)记录到内部“流路由表”,建立“流 - 发布者”映射关系,为后续转发做准备 。
- 协议适配:支持 WebRTC 协议,接收客户端(发布者)通过 WebRTC 推来的音视频流 ,也可处理 RTMP 等其他协议转 WebRTC 后的流,通过如
- 订阅与转发决策:
- 订阅请求处理:当其他客户端(订阅者)通过
/rtc/v1/play
或 WebRTC 协议发起订阅请求时,SRS 依据请求中的流 ID,查询“流路由表”,确定对应的发布者流 。 - 转发策略:
- 选择性转发:作为 SFU,不解码、不混流原始媒体流(或仅做轻量级处理,如适配编码格式),直接复制流数据,根据订阅关系转发给订阅者 。比如多人会议场景,把发言人的单路流,转发给所有参会订阅者,实现“一对多”高效分发 。
- 智能适配:结合客户端网络状况(如带宽、延迟)、终端能力(支持编码格式),动态调整转发的流参数。若订阅者网络差,可转发低分辨率、低码率流;若终端不支持 VP8 编码,转换为 H.264 再转发 。
- 订阅请求处理:当其他客户端(订阅者)通过
- 媒体传输与优化:
- 传输协议:基于 UDP 传输媒体数据包(WebRTC 常用方式),利用其低延迟特性;也适配 TCP,应对复杂网络环境 。
- 网络优化:
- NAT 穿透:配合 STUN/TURN 服务器,或通过配置
candidate
(候选地址),解决客户端处于 NAT 环境下的互联互通问题,让流顺利收发 。 - 拥塞控制:支持 NACK(丢包重传)、TWCC(传输带宽估计与拥塞控制反馈),检测到丢包时重传关键数据,根据网络带宽动态调整发送码率,保障流传输稳定 。
- FEC(前向纠错):添加冗余数据,订阅者收到数据后,可通过冗余数据恢复丢失的数据包,降低重传依赖,减少延迟 。
- NAT 穿透:配合 STUN/TURN 服务器,或通过配置
- 管理与协同:
- 控制台管理:提供
srs 1985 控制台
(对应 URL 可查看),可视化展示 SRS 服务状态、流信息、客户端连接情况,方便运维人员监控流转发状态、排查问题 。 - 信令协同:与信令服务器(如
signal1989
)配合,通过/sig/v1/rtc
等接口,处理房间创建、加入、流订阅/取消等信令逻辑,协同完成“发布 - 订阅”全流程 。比如信令通知 SRS 有新订阅者加入,SRS 即刻启动对应流的转发 。
- 控制台管理:提供
- 协议转换与兼容(可选拓展):除纯 WebRTC 流转发,还支持协议转换。如把 WebRTC 流转为 RTMP/FLV ,供不支持 WebRTC 的终端(如老旧播放器通过
srs_player.html
播放)使用;也能将 RTMP 流转为 WebRTC 流输出,打通不同协议终端的实时通信 。
2.2 信令服务器
信令的本质:
信令服务器核心职责是 处理设备 / 客户端之间的 “协商逻辑”,比如 WebRTC 里的 SDP 交换(协商编解码、媒体能力)、房间管理(加入 / 退出、流订阅关系)、ICE 候选交换(网络地址协商)等,让终端知道 “和谁连、怎么连、发什么流” 。
SRS 对信令的支持方式:
- SRS 可通过 集成简易信令逻辑 或 对接独立信令服务器,辅助流媒体业务:
内置轻量信令功能:
支持 WHIP(WebRTC HTTP 推流协议 )、WHEP(WebRTC HTTP 拉流协议 )等,可在协议层面处理部分 “推流 - 拉流” 的信令交互(如 SDP 协商、流标识绑定 )。
例如,客户端通过 WHIP 协议向 SRS 推流时,SRS 会解析请求里的 SDP 信息,完成媒体能力协商,这一步涉及 “信令式” 的交互,但仅围绕流媒体传输本身,并非完整的 “房间管理、多终端协同” 信令逻辑。 - 对接独立信令服务器:
实际复杂场景(如多人会议)中,SRS 通常搭配 独立信令服务器(如开源的 Janus 信令模块、或业务自定义的信令服务 )。
信令服务器负责处理 “房间创建、用户加入 / 退出、流订阅关系同步” 等高层逻辑,再将 “谁需要推流、谁需要拉流” 的指令告知 SRS,由 SRS 执行实际的媒体转发。
2.3 综合示例
背景设定
- 信令服务器:负责房间管理、状态同步,提供
join
/publish
/subscribe
等信令接口。 - SRS(SFU):负责媒体流转发,提供
publish
(推流)和play
(拉流)的媒体接口。 - 用户角色:
- CWR:先加入房间的用户,发布自己的流。
- CZ:后加入房间的用户,订阅 CWR 的流,同时发布自己的流让 CWR 订阅。
流程拆解(Step by Step)
1. CWR 加入房间(join
信令)
-
CWR 操作:
调用信令服务器的join
接口,参数:roomId=1001
,userId=CWR
。// CWR 发送给信令服务器的 join 请求 { "action": "join", "roomId": "1001", "userId": "CWR" }
-
信令服务器逻辑:
- 检查房间
1001
是否存在,若不存在则创建。 - 记录 CWR 为房间
1001
的参与者,维护“房间 - 参与者列表”:{"1001": ["CWR"]}
。 - 返回房间当前状态给 CWR:
// 信令服务器返回给 CWR 的响应 { "code": 0, "roomId": "1001", "participants": ["CWR"], // 目前只有自己 "streams": [] // 暂时没有流发布 }
- 检查房间
2. CWR 发布流(publish
信令 + SRS 推流)
-
CWR 操作:
- 调用信令服务器的
publish
接口,告知“要发布流”:{ "action": "publish", "roomId": "1001", "userId": "CWR", "streamId": "CWR_stream" // 自定义流标识 }
- 通过 WebRTC 协议,将本地摄像头/麦克风采集的流,推送到 SRS 的
publish
地址(如webrtc://srs.server/1001/CWR_stream
)。
- 调用信令服务器的
-
信令服务器逻辑:
- 记录“CWR 发布了流
CWR_stream
”,更新房间流列表:{"1001": {"streams": ["CWR_stream"]}}
。 - 向房间内所有参与者(目前只有 CWR 自己)推送流发布事件:
{ "action": "stream_published", "roomId": "1001", "userId": "CWR", "streamId": "CWR_stream", "streamUrl": "webrtc://srs.server/1001/CWR_stream" // SRS 流地址 }
- 记录“CWR 发布了流
-
SRS(SFU)逻辑:
- 接收 CWR 推来的 WebRTC 流,解析流元数据(编码、分辨率等)。
- 建立“流标识(
CWR_stream
)- 发布者(CWR)”的映射,等待订阅者。
3. CZ 加入房间(join
信令)
-
CZ 操作:
调用信令服务器的join
接口,参数:roomId=1001
,userId=CZ
。{ "action": "join", "roomId": "1001", "userId": "CZ" }
-
信令服务器逻辑:
- 检查房间
1001
已存在,将 CZ 加入参与者列表:{"1001": ["CWR", "CZ"]}
。 - 返回房间当前状态给 CZ,包含已存在的参与者和流:
{ "code": 0, "roomId": "1001", "participants": ["CWR", "CZ"], "streams": [ { "userId": "CWR", "streamId": "CWR_stream", "streamUrl": "webrtc://srs.server/1001/CWR_stream" } ] }
- 向房间内其他参与者(CWR) 推送新成员加入事件:
{ "action": "participant_joined", "roomId": "1001", "userId": "CZ" }
- 检查房间
4. CZ 订阅 CWR 的流(subscribe
信令 + SRS 拉流)
-
CZ 操作:
从信令服务器返回的streams
中,拿到 CWR 的流地址webrtc://srs.server/1001/CWR_stream
,调用信令服务器的subscribe
接口(或直接通过 WebRTC 发起play
请求 ):{ "action": "subscribe", "roomId": "1001", "userId": "CZ", "streamUrl": "webrtc://srs.server/1001/CWR_stream" }
-
信令服务器逻辑:
记录“CZ 订阅了 CWR 的流”,并通知 SRS 处理转发。 -
SRS(SFU)逻辑:
- 收到 CZ 的
play
请求(对应webrtc://srs.server/1001/CWR_stream
)。 - 找到 CWR 发布的流,直接转发给 CZ(不解码、不混流,仅做网络优化 )。
- 收到 CZ 的
5. CZ 发布自己的流(publish
信令 + SRS 推流)
-
CZ 操作:
- 调用信令服务器的
publish
接口,告知“要发布流”:{ "action": "publish", "roomId": "1001", "userId": "CZ", "streamId": "CZ_stream" }
- 通过 WebRTC 协议,将本地流推送到 SRS 的
publish
地址(如webrtc://srs.server/1001/CZ_stream
)。
- 调用信令服务器的
-
信令服务器逻辑:
- 记录“CZ 发布了流
CZ_stream
”,更新房间流列表。 - 向房间内所有参与者(CWR、CZ) 推送流发布事件:
{ "action": "stream_published", "roomId": "1001", "userId": "CZ", "streamId": "CZ_stream", "streamUrl": "webrtc://srs.server/1001/CZ_stream" }
- 记录“CZ 发布了流
-
SRS(SFU)逻辑:
接收 CZ 推来的流,建立“流标识(CZ_stream
)- 发布者(CZ)”的映射,等待订阅者(如 CWR 会触发订阅 )。
6. CWR 订阅 CZ 的流(自动触发或信令驱动)
-
CWR 操作:
收到信令服务器推送的“CZ 发布流”事件后,自动调用subscribe
接口(或直接play
),订阅webrtc://srs.server/1001/CZ_stream
。 -
SRS(SFU)逻辑:
将 CZ 的流转发给 CWR,此时 CWR 和 CZ 实现双向音视频互通(CWR 看/听 CZ,CZ 看/听 CWR )。
关键协同总结
角色 | 核心动作 | 数据/信令流向 | 作用 |
---|---|---|---|
CWR(发布者) | join → publish → 推流到 SRS | 信令服务器 ←→ CWR;SRS ← CWR(媒体流) | 初始化房间、发布本地流 |
CZ(订阅者) | join → 订阅 CWR 流 → publish → 推流 | 信令服务器 ←→ CZ;SRS ←→ CZ(媒体流) | 加入房间、订阅他人流、发布自己流 |
信令服务器 | 管理房间、同步状态、转发事件 | 信令服务器 ←→ CWR/CZ | 指挥“谁连谁、什么时候连”,不碰媒体数据 |
SRS(SFU) | 接收流、转发流(publish /play 接口) | SRS ← 发布者(媒体流);SRS → 订阅者 | 只负责“搬流媒体数据”,依赖信令调度 |
3 实战
3.1 srs 流媒体服务器分析
运行命令:./objs/srs -c ./conf/rtc.conf
# WebRTC streaming config for SRS.
# @see full.conf for detail config.
listen 1935;
max_connections 1000;
daemon off;
srs_log_tank console;
http_server {
enabled on;
listen 8080;
dir ./objs/nginx/html;
}
http_api {
enabled on;
listen 1985;
}
stats {
network 0;
}
rtc_server {
enabled on;
listen 8000; # UDP port
# @see https://ossrs.net/lts/zh-cn/docs/v4/doc/webrtc#config-candidate
candidate $CANDIDATE;
}
vhost __defaultVhost__ {
rtc {
enabled on;
# @see https://ossrs.net/lts/zh-cn/docs/v4/doc/webrtc#rtmp-to-rtc
rtmp_to_rtc off;
# @see https://ossrs.net/lts/zh-cn/docs/v4/doc/webrtc#rtc-to-rtmp
rtc_to_rtmp off;
}
http_remux {
enabled on;
mount [vhost]/[app]/[stream].flv;
}
}
整体功能概述
该配置文件实现了一个基础的WebRTC流媒体服务,主要包含以下核心功能:
- RTMP协议支持(端口1935)
- HTTP文件服务(端口8080)
- HTTP API管理接口(端口1985)
- WebRTC服务(UDP端口8000)
- HTTP-FLV直播流输出
核心配置项解析
- 基础服务配置
listen 1935;
max_connections 1000;
daemon off;
srs_log_tank console;
listen 1935
:启用RTMP协议监听,用于接收传统RTMP推流max_connections 1000
:限制最大客户端连接数为1000daemon off
:不以守护进程方式运行,便于调试srs_log_tank console
:日志输出到控制台
- HTTP服务配置
http_server {
enabled on;
listen 8080;
dir ./objs/nginx/html;
}
- 启用HTTP文件服务,端口8080
- 静态文件目录指向
./objs/nginx/html
,可用于存放播放器页面等静态资源
- HTTP API配置
http_api {
enabled on;
listen 1985;
}
- 启用HTTP管理API,端口1985
- 通过该API可以查询服务器状态、流信息等,支持RESTful风格
RESTful 不是 “强制标准”,而是一套让 API 更简洁、规范的设计风格,核心通过 “资源 URI + HTTP 方法” 定义接口,让系统交互清晰、易维护。像你之前提到的 SRS 的 HTTP API,若遵循 RESTful 设计,就能用GET /api/streams查列表、POST /api/streams创建流,比自定义复杂参数的接口好理解得多~
HTTPAPI:
HTTP API 虽然不直接参与媒体流的传输(由 SFU 模块负责),但它为 WebRTC 服务提供了 控制平面 的能力:
动态配置 WebRTC 参数:通过 HTTP API 修改 rtc_server 的配置(如端口、候选地址),无需重启服务。
监控 WebRTC 连接质量:实时查看 WebRTC 客户端的连接数、丢包率、带宽使用情况。
管理 WebRTC 房间 / 会话:结合业务逻辑,通过 HTTP API 创建 / 销毁 WebRTC 会话(如多人会议房间)
- WebRTC核心配置
rtc_server {
enabled on;
listen 8000; # UDP port
candidate $CANDIDATE;
}
enabled on
:启用WebRTC服务listen 8000
:使用UDP端口8000进行WebRTC数据传输(UDP更适合低延迟实时通信)candidate $CANDIDATE
:配置ICE候选地址,$CANDIDATE
通常会在启动时被替换为服务器的公网IP或域名,用于NAT穿透
- 虚拟主机配置
vhost __defaultVhost__ {
rtc {
enabled on;
rtmp_to_rtc off;
rtc_to_rtmp off;
}
http_remux {
enabled on;
mount [vhost]/[app]/[stream].flv;
}
}
-
WebRTC相关配置:
rtc.enabled on
:在默认虚拟主机上启用WebRTC功能rtmp_to_rtc off
:关闭RTMP到WebRTC的转换(不将RTMP流转换为WebRTC流)rtc_to_rtmp off
:关闭WebRTC到RTMP的转换(不将WebRTC流转换为RTMP流)
-
HTTP-FLV配置:
http_remux.enabled on
:启用HTTP-FLV流输出mount [vhost]/[app]/[stream].flv
:定义HTTP-FLV流的访问路径格式,例如:http://server:8080/live/stream.flv
3.2 信令服务器分析
SRS 中第三方库的信令服务器是一个用 Go 语言开发的组件,位于 SRS 的3rdparty/signaling目录下,默认监听 1989 端口。它在 SRS 的 WebRTC 功能中扮演着重要角色,主要负责以下任务:
- 房间管理:处理与房间相关的操作,包括创建房间、加入房间、离开房间等。例如,当用户想要加入一个特定的视频通话房间时,信令服务器会对该请求进行处理,确保用户能够正确地加入到指定房间。
- 用户信息管理:负责管理参与 WebRTC 会话的用户信息,如用户的昵称、状态等。它可以跟踪房间内的用户列表,当有新用户加入或现有用户离开时,及时更新相关信息并通知其他用户。
- 信令交互:作为客户端之间信令消息的中转站,处理 WebRTC 客户端之间的信令交互,包括协商媒体能力、交换会话描述协议(SDP)信息、处理 ICE(Interactive Connectivity Establishment)候选等。比如,在多人视频通话中,信令服务器会将一个用户的媒体流信息转发给其他用户,使得各方能够建立起正确的媒体连接。
cd ~/git/srs/trunk/3rdparty/signaling && make && ./objs/signaling
3.3 http-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/
httpx-static 是一个基于 C++ 开发的高性能 HTTP/HTTPS 反向代理服务器,主要用于将客户端的 HTTP/HTTPS 请求转发到后端的多个目标服务(如 API 接口、其他服务器等)
一、按请求类型拆分:HTTP vs WebSocket
httpx-static
同时支持 HTTP 请求 和 WebSocket 请求 的转发,对应不同的业务场景:
1. HTTP 请求转发(常规接口、静态文件)
-
请求示例:
/rtc/v1/publish/
→ 转发到srs 1985 http api
/console/ng_index.html
→ 转发到srs 1985 控制台
/players/srs_player.html
→ 转发到srs 8080 播放器
-
作用:
- 静态文件托管:像
srs_player.html
这类播放器页面,通过httpx-static
直接代理到 SRS 的静态文件服务器(8080 端口),客户端访问http://your-domain/players/srs_player.html
就能加载页面。 - API 调用:
/rtc/v1/publish
是 SRS 的 HTTP API(1985 端口),用于触发流发布逻辑(如推流到 SRS)。 - 控制台访问:
/console/ng_index.html
是 SRS 的 Web 管理界面,通过代理统一入口,方便运维人员访问。
- 静态文件托管:像
2. WebSocket 请求转发(信令交互)
-
请求示例:
/sig/v1/rtc
→ 转发到signal1989 信令服务器
(WebSocket 协议)
-
作用:
WebRTC 信令交互(如房间创建、SDP 交换、ICE 候选协商)依赖 WebSocket 长连接,httpx-static
作为代理,将客户端的 WebSocket 请求(ws://your-domain/sig/v1/rtc
)转发到信令服务器(1989 端口),确保实时信令能稳定传输。
二、路由逻辑:“流量分发规则”
httpx-static
通过 路径匹配 决定请求转发到哪个后端:
请求路径 | 协议 | 转发目标 | 作用 |
---|---|---|---|
/rtc/v1/publish/ | HTTP | srs 1985 http api | 调用 SRS 的流发布 API |
/console/ng_index.html | HTTP | srs 1985 控制台 | 访问 SRS 管理界面 |
/players/srs_player.html | HTTP | srs 8080 播放器 | 加载 SRS 播放器静态页面 |
/sig/v1/rtc | WebSocket | signal1989 信令服务器 | WebRTC 信令交互(房间、流协商) |
三、业务价值:为什么需要这个“中枢”?
1. 统一入口,简化客户端配置
- 客户端只需记住
httpx-static
的地址(如http://your-domain
),无需关心后端多个服务的具体端口(1985、8080、1989 等)。 - 示例:
- 播放器页面地址统一为
http://your-domain/players/srs_player.html
,无需拼接:8080
端口。 - 信令连接地址统一为
ws://your-domain/sig/v1/rtc
,无需关心信令服务器的 1989 端口。
- 播放器页面地址统一为
2. 协议转换与兼容
httpx-static
可以将 外部 HTTPS 请求 转换为内部 HTTP 请求,反之亦然。- 示例:
- 客户端用
https://your-domain
访问(更安全),httpx-static
内部转发到 SRS 的 HTTP 服务(1985、8080 等),无需后端服务单独配置 HTTPS。
- 客户端用
3. 隐藏后端细节,提升安全性
- 后端服务(如信令服务器 1989 端口)无需暴露到公网,只需在内部网络与
httpx-static
通信。 - 减少公网暴露的端口数量,降低被攻击的风险(如 1989 端口不直接对外,仅通过
httpx-static
代理)。
4. 支持复杂业务流程
- 比如 WebRTC 推流流程:
- 客户端通过 HTTP 请求
/rtc/v1/publish
告诉 SRS “我要推流”。 - 通过 WebSocket 连接
/sig/v1/rtc
与信令服务器协商推流参数。 - 最终音视频流通过 SRS 的 SFU 模块传输,但所有“控制面”请求都由
httpx-static
统一路由。
- 客户端通过 HTTP 请求
四、类比理解:把 httpx-static
当“小区门卫”
- 客户端 = 小区居民,想访问小区内的不同设施(健身房、物业、快递柜)。
httpx-static
= 小区门卫,负责登记居民需求,然后帮居民把请求转发到对应的设施:- 居民说“我要去健身房” → 门卫指引到健身房(转发到
srs 8080 播放器
)。 - 居民说“我要找物业开证明” → 门卫指引到物业办公室(转发到
srs 1985 控制台
)。 - 居民说“我要收发快递” → 门卫指引到快递柜(转发到
signal1989 信令服务器
)。
- 居民说“我要去健身房” → 门卫指引到健身房(转发到
这样,居民(客户端)无需记住每个设施的具体位置(端口),只需找门卫(httpx-static
)即可~
3.4 交互流程
以下结合 httpx-static
代理、SRS(SFU)、信令服务器 与这张前端交互流程图,完整拆解 “用户 → 前端 → 后端服务” 的交互逻辑,理解从“进入网页”到“音视频互通”的全流程:
一、核心角色回顾
-
前端侧:
one2one.html
:前端页面(用户入口)。srs.sig.js
:信令交互工具库(处理 WebSocket 连接、收发信令)。srs.sdk.js
:WebRTC 工具库(处理音视频采集、发布、订阅)。
-
后端侧:
httpx-static
:反向代理(统一入口,转发 HTTP/WebSocket 请求)。- SRS(SFU):流媒体服务器(处理音视频流的发布、订阅、转发)。
- 信令服务器:处理房间管理、SDP 协商、ICE 候选交换等信令逻辑。
二、流程拆解(从“用户进入网页”到“音视频互通”)
1. 初始化阶段:前端加载与配置
- 用户操作:用户 1 访问
one2one.html
页面(进入网页)。 - 前端逻辑:
one2one.html
加载后,调用srs.sig.js
的SrsRtcSignalingParse
方法,解析配置:- 返回
wsHost
(WebSocket 信令地址,如ws://your-domain/sig/v1/rtc
,实际由httpx-static
代理)。 - 返回
room
(房间 ID,如1234
)、display
(用户标识,如user1
)等参数。
- 返回
2. 信令连接阶段:建立 WebSocket 通道
- 前端逻辑:
- 调用
srs.sig.js
的SrsRtcSignalingAsync
方法,基于wsHost
创建 WebSocket 连接:- 返回
sig
对象(封装了 WebSocket 收发信令的能力)。
- 返回
- 通过
sig.connect()
发起 WebSocket 连接,请求到达httpx-static
。
- 调用
httpx-static
转发:- 识别路径
/sig/v1/rtc
,将 WebSocket 请求转发到 信令服务器(如signal1989
)。
- 识别路径
- 信令服务器逻辑:
- 接受连接,为用户 1 分配信令通道,等待后续消息。
3. 加入房间阶段:信令交互(join
)
- 前端逻辑:
- 通过
sig.send({ action: 'join', room: '1234', display: 'user1' })
发送join
信令。 - 信令内容:告知信令服务器“用户 1 要加入房间 1234”。
- 通过
- 信令服务器逻辑:
- 检查房间
1234
是否存在,若不存在则创建。 - 记录用户 1 为房间成员,返回房间信息(如现有成员、流列表)。
- 若有其他用户(如用户 2)已在房间,信令服务器会向用户 2 推送“新成员加入”事件。
- 检查房间
4. 发布流阶段:采集并推送音视频(publish
)
- 前端逻辑:
- 调用
srs.sdk.js
的new SrsRtcPublisherAsync()
方法,初始化发布器:- 请求浏览器权限(摄像头、麦克风),采集音视频流。
- 返回
Publisher
对象(封装了发布流的能力)。
- 通过
Publisher.publish()
发起流发布:- 生成 WebRTC 的 SDP(媒体能力描述),并通过
sig.send({ action: 'publish', sdp: '...' })
发送给信令服务器。
- 生成 WebRTC 的 SDP(媒体能力描述),并通过
- 调用
- 信令服务器逻辑:
- 接收
publish
信令,解析 SDP 内容。 - 将 SDP 转发给 SRS(SFU)(通过
httpx-static
代理的/rtc/v1/publish
接口)。
- 接收
- SRS(SFU)逻辑:
- 接收 SDP,创建流发布通道,返回 SRS 的 SDP 响应(包含 ICE 候选等网络信息)。
- 信令服务器将 SRS 的响应回传给前端
Publisher
。
5. 订阅流阶段:接收对方音视频(用户 2 同理)
- 用户 2 流程:
用户 2 重复 步骤 1-4,加入房间1234
并发布自己的流。 - 信令服务器通知:
当用户 2 发布流后,信令服务器向用户 1 推送“新流发布”事件(包含用户 2 的流地址,如webrtc://your-domain/1234/user2
)。 - 前端订阅逻辑:
- 用户 1 的
srs.sdk.js
收到事件后,调用new SrsRtcSubscriberAsync()
初始化订阅器。 - 通过订阅器请求 SRS(SFU)拉取用户 2 的流,建立 WebRTC 连接。
- 用户 1 的
6. 音视频互通阶段:媒体流传输
- SRS(SFU)角色:
- 接收用户 1 的流(通过 WebRTC 推流),并转发给用户 2。
- 接收用户 2 的流(通过 WebRTC 推流),并转发给用户 1。
- 前端呈现:
- 用户 1 和用户 2 的浏览器通过
srs.sdk.js
渲染对方的音视频流,实现“一对一通话”。
- 用户 1 和用户 2 的浏览器通过
三、关键交互链路总结
四、核心协同点
-
httpx-static
的“桥梁作用”:- 统一代理 HTTP(如
/rtc/v1/publish
)和 WebSocket(如/sig/v1/rtc
)请求,让前端只需访问一个域名,简化配置。
- 统一代理 HTTP(如
-
信令服务器的“指挥作用”:
- 管理房间、用户、流的状态,协调 SRS 转发媒体流,让“谁该推流、谁该拉流”逻辑清晰。
-
SRS(SFU)的“管道作用”:
- 专注媒体流的转发,不处理业务逻辑,确保音视频传输低延迟、高性能。
-
前端 SDK 的“工具作用”:
srs.sig.js
封装信令交互,srs.sdk.js
封装 WebRTC 能力,让前端开发者无需关注复杂的协议细节。
五、类比理解:把整个流程当“线上电话亭”
one2one.html
= 电话亭的“操作面板”(用户输入要拨打的号码)。srs.sig.js
= 电话亭的“信号线路”(负责传递“拨号、接听”等信令)。srs.sdk.js
= 电话亭的“话筒+听筒”(负责采集、播放声音/画面)。httpx-static
= 电话局的“总机”(统一转接所有通话请求)。- 信令服务器 = 电话局的“交换机”(决定“谁能接通谁、怎么接通”)。
- SRS(SFU) = 电话局的“传输线路”(负责把声音/画面从 A 传到 B)。