直播与 WebRTC/HLS/FLV
直播配置控制什么?
Section titled “直播配置控制什么?”livestream 控制 WHIP/RTMP 推流、WHEP/RTMP/RTSP/HTTP-FLV 外部拉流、WebRTC 会话、HLS 分片、HTTP-FLV 连接和直播缓存。
如果你只使用点播媒体 Provider,这一页大部分配置可以保持默认。
直播子系统的边界
Section titled “直播子系统的边界”直播子系统包含推流入口、RTP/frame 分发、WHEP/FLV 播放、HLS remux、HLS 存储和跨节点 publisher registry。点播 Provider 处理外部媒体 URL 和 Range proxy;直播子系统处理持续产生的数据流。
- WHIP ingest: 推流端向主 HTTP 服务提交 SDP offer。SyncTV 协商 H.264/Opus,保留 RTP,并生成 H.264/AAC frame。
- WHEP playback: 客户端通过 SDP offer 建立 WebRTC 播放会话。源必须提供 RTP。
- RTMP ingest: 推流端通过 RTMP 连接进入,认证阶段会把 publisher 注册到本节点或共享 registry。
- RTSP ingest: 外部 RTSP 源通过 DESCRIBE/SETUP/PLAY 拉取,经过 RTP 解包后进入同一个 StreamHub。
- StreamHub: 进程内同时分发 RTP packet 和 remux frame。普通 RTMP/RTSP/HTTP-FLV 源只提供 frame。
- HTTP-FLV: 适合低延迟观看。客户端保持长连接,服务端持续写 FLV chunk,并通过写超时保护慢客户端。
- HLS: 适合通用播放器和 CDN/对象存储形态。延迟更高,但对客户端兼容性和多副本扩展更友好。
播放协议怎么选?
Section titled “播放协议怎么选?”| 协议 | 优点 | 代价 | 适合场景 |
|---|---|---|---|
| WHEP | WebRTC 低延迟、浏览器原生媒体轨道、ICE/TURN 穿透 | 源需要保留 RTP,服务端和客户端都需要可达 ICE candidate | WHIP 推流、外部 WHEP 代理、低延迟浏览器播放 |
| HTTP-FLV | 延迟低、链路短、服务端直接推 chunk | 长连接多,弱网慢客户端需要严格超时 | 互动直播、房间内同步观看 |
| HLS | 播放器兼容性强,天然按 playlist/segment 拉取,可配共享存储 | 延迟高于 FLV,需要管理分片存储 | 移动端、通用播放器、多副本、对象存储 |
WHIP 推流与 WHEP 播放
Section titled “WHIP 推流与 WHEP 播放”SyncTV 在主 HTTP(S) 服务上实现 WHIP resource 和 WHEP resource。两个协议都使用一次性 SDP offer/answer;当前实现收集完整 ICE candidate,不提供 trickle ICE PATCH。
| 操作 | HTTP 资源 | 鉴权 |
|---|---|---|
| 创建 publish key | POST /api/playback-providers/{roomId}/rtmp/{mediaId}/publish-key |
当前用户 token 与推流权限 |
| 创建 WHIP 推流 | POST /api/playback-providers/{roomId}/rtmp/{mediaId}/whip |
Bearer <publish-key> |
| 删除 WHIP 推流 | DELETE <POST 响应的 Location> |
同一个 publish key |
| 播放 managed live | POST /api/playback-providers/{roomId}/live/{mediaId}/whep |
当前用户或游客访问 token |
| 播放 LiveProxy | POST /api/playback-providers/{roomId}/live-proxy/{mediaId}/whep |
当前用户或游客访问 token |
| 删除 WHEP 播放 | DELETE <POST 响应的 Location> |
同一个观看身份 |
POST 请求使用 Content-Type: application/sdp。成功响应返回 201 Created、SDP answer 和同源 Location;客户端停止推流或播放时应发送 DELETE。服务器在连接关闭、会话超时或进程退出时清理本地资源。
公开名称 live 表示由 SyncTV 管理的 WHIP/RTMP 推流源;liveProxy 表示 SyncTV 拉取的外部 WHEP/RTSP/RTMP/HTTP-FLV 源。protobuf wire/source-config oneof 继续使用 RTMP/rtmp 表示 SyncTV 管理的直播源。
Provider prepare API 使用 POST /api/providers/prepare/live。HLS 和 HTTP-FLV 播放 URL 同样使用 /api/playback-providers/{roomId}/live/...。
CLI 使用 live 创建 managed live 媒体,rtmp 仍作为输入别名:
synctv media add <ROOM_ID> --username alice \ --source-provider live \ --source-config-json '{"mode":"default"}' \ --name "直播"使用 publish-key API 创建密钥后,响应会同时包含 rtmp_url、stream_key 和 whip_url。生产环境设置公开 HTTP(S) origin:
livestream: public_webrtc_base_url: "https://live.example.com" webrtc: enabled: true ice_gathering_timeout_seconds: 10 max_sdp_bytes: 262144 max_sessions: 1000 max_session_duration_seconds: 86400public_webrtc_base_url 为空时,publish-key 响应返回相对当前 API origin 的 WHIP URL。该值只接受无 path、query 和 fragment 的 HTTP(S) origin。
SDP API 示例
Section titled “SDP API 示例”WHIP 客户端把 publish key 放在 Bearer header:
curl -i -X POST "$WHIP_URL" \ -H "Authorization: Bearer $PUBLISH_KEY" \ -H "Content-Type: application/sdp" \ --data-binary @offer.sdpWHEP 客户端使用访问房间的 token:
curl -i -X POST "$WHEP_URL" \ -H "Authorization: Bearer $ACCESS_TOKEN" \ -H "Content-Type: application/sdp" \ --data-binary @offer.sdpcurl 只能验证信令。媒体传输需要 WebRTC peer。浏览器客户端应创建 recvonly 音视频 transceiver,等待 ICE gathering 完成,POST pc.localDescription.sdp,再把响应设置为 remote answer。播放结束时对 Location 发送 DELETE。
OBS 的 WHIP service 填写响应中的 whip_url 和 publish key。GStreamer 需要安装带 whipclientsink 的 rswebrtc 插件,并输出 H.264/Opus。不同版本的属性名存在差异,可用 gst-inspect-1.0 whipclientsink 查看 endpoint 和 auth token 属性。FFmpeg 构建对 WHIP 的支持不一致;用 ffmpeg -muxers 检查当前二进制。没有 WHIP muxer 时,FFmpeg 可以继续向 rtmp_url 推送 H.264/AAC。
WHIP 和外部 WHEP 接受 H.264 constrained-baseline(profile-level-id=42e01f、packetization-mode=1)与 Opus。固定 H.264 profile 可以让未转码的 WHEP RTP 输出保持与 SDP 一致。SyncTV 将 H.264 RTP 解包为 AVC frame,并把 Opus 解码后编码为 AAC,因此同一输入可供 HLS 和 HTTP-FLV 播放。
SyncTV 实现标准 WHIP resource 语义和 WHEP draft resource 语义。云厂商的私有签名参数、私有信令接口、SIMULCAST 控制 API 和专用 ingest SDK 不属于这两个协议;接入此类服务时需要一个标准 WHIP/WHEP endpoint。
外部 WHEP 源
Section titled “外部 WHEP 源”LiveProxy 可以把远程 WHEP 资源代理到本地 WHEP、HLS 和 HTTP-FLV:
{ "provider": "liveProxy", "source": { "protocol": "whep", "url": "https://origin.example.com/whep/channel-1", "authorization": "Bearer upstream-token" }}SyncTV 对 endpoint 做 SSRF 校验和 DNS pinning,禁止 HTTP redirect,并要求上游返回 201 Created、application/sdp 与同源 Location。服务端限制 SDP 大小和读取时间;本地拉流结束后会 DELETE 远程 resource。管理查询不会回显 authorization,日志也不会记录上游 URL 或 Authorization。
WHEP URL 可以使用 query token。URL 不接受 userinfo 和 fragment;HTTP header 凭据应放在 authorization 字段。
ICE、STUN 与 TURN
Section titled “ICE、STUN 与 TURN”livestream.webrtc.ice_servers 配置直播 PeerConnection 使用的 STUN/TURN 服务。顶层 webrtc 配置管理房间语音/媒体 P2P 和内置 STUN,两组选项服务不同的 WebRTC 功能。
livestream: webrtc: ice_servers: - urls: - "stun:stun.example.com:3478" - "turn:turn.example.com:3478?transport=udp" - "turns:turn.example.com:5349?transport=tcp" username: "synctv" credential_file: "/run/secrets/livestream_turn_credential"STUN 只帮助 peer 发现地址。服务器位于 Kubernetes、NAT 或严格防火墙后时,部署一个客户端和 Pod 都可访问的 TURN 服务。TURN UDP 提供较低延迟,TURN/TLS over TCP 适合限制 UDP 的网络。
WHIP/WHEP 信令走现有 HTTP Service。ICE 媒体使用动态 UDP 端口,Helm chart 不创建固定的 WebRTC media UDP Service。Kubernetes 部署应使用 TURN;采用 hostNetwork 时需同时开放节点的 ICE UDP 端口范围。stunService 只暴露内置 STUN listener,不转发媒体。
RTSP 外部源
Section titled “RTSP 外部源”RTSP 外部源使用显式协议配置。每个媒体条目对应一个独立拉流会话,多个媒体条目可以并行拉取多个摄像头或流媒体服务器;每个节点默认最多运行 100 个外部流。
{ "provider": "liveProxy", "source": { "protocol": "rtsp", "url": "rtsp://camera.example/live", "transport": "tcp", "videoTrack": { "mode": "firstCompatible" }, "audioTrack": { "mode": "firstCompatible" } }}可用设置:
| 字段 | 值 | 含义 |
|---|---|---|
transport |
tcp / udp |
TCP 使用 interleaved RTP;UDP 适合可控局域网 |
videoTrack |
firstCompatible / index / disabled |
选择 H.264/H.265 视频轨道 |
audioTrack |
firstCompatible / index / disabled |
选择 AAC 音频轨道 |
指定 SDP 中第 2 个视频轨道并关闭音频:
{ "videoTrack": { "mode": "index", "index": 1 }, "audioTrack": { "mode": "disabled" }}Basic 和 Digest 认证可使用 RTSP URL userinfo,例如 rtsp://user:password@camera.example/live。日志会移除 userinfo、query 和 fragment;部署侧应通过受控配置入口管理包含凭据的 source config。
RTSP 输入支持 H.264、H.265 和 AAC。SyncTV 将它们转换为 AVC/HEVC/AAC FLV tag,HTTP-FLV 与 HLS 沿用现有直播交付、集群注册、跨节点 relay、空闲清理和断线重试链路。
外部 RTMP 源
Section titled “外部 RTMP 源”外部 RTMP 源通过 mode 控制转发的媒体类型。RTMP 消息本身按音频和视频分类,mode 负责过滤消息类型,不涉及 RTSP 的轨道编号选择。
{ "provider": "liveProxy", "source": { "protocol": "rtmp", "url": "rtmp://origin.example/live/stream", "mode": "default" }}mode 可取 default(音频和视频)、videoOnly(只转发视频)或 audioOnly(只转发音频)。外部 RTMP 拉流在拉流会话中过滤,SyncTV 管理的 RTMP 推流在认证后的 server session 中过滤,HTTP-FLV 和 HLS 会得到同一份筛选后的 Live StreamHub 数据。
RTSP 的 videoTrack 与 audioTrack 至少需要启用一项。双 disabled 配置会在添加媒体时被拒绝;具体轨道编号与编码兼容性在 RTSP SDP 建立连接时继续校验。
RTSP、外部 RTMP 与内部 RTMP 推流都进入同一个 Live StreamHub。SyncTV 为它们生成 HLS 和 HTTP-FLV;HLS playlist 使用短滑动窗口,TS 分片随窗口淘汰,任意时间跳转与持久录制属于当前产品范围之外。
HLS backend 的架构选择
Section titled “HLS backend 的架构选择”memory 是默认值,分片只存在当前进程内。它最简单,适合单副本、开发环境和低流量多副本。
限制:进程重启会丢分片;多副本下非 publisher 节点需要通过 HLS gRPC proxy 到 publisher 节点读取 playlist/segment。它可以工作,但不适合作为高并发生产 HLS 的首选。
file 把分片写入当前节点的 hls_storage.path。单副本可以用本地磁盘;多副本可以使用本地磁盘并依赖 publisher-node proxy。
不要把共享文件系统配置成 file;如果所有副本都能读写同一路径,使用 shared_file。
shared_file 把分片写入所有副本可见的 hls_storage.path。Publisher 节点写入分片,任意节点收到 .ts 请求时从当前节点挂载的共享路径读取。
典型选择:NFS、RWX PVC、CSI 共享卷。不要把 emptyDir、/tmp 或节点本地盘配置成 shared_file。
s3 使用 S3 兼容对象存储保存分片。它是 Kubernetes 多副本和跨节点部署中更明确的共享边界。
典型选择:AWS S3、MinIO、Cloudflare R2 或兼容服务。需要配置 endpoint、bucket、access key 和 secret key。
集群直播如何工作?
Section titled “集群直播如何工作?”- Publisher 通过 WHIP 或 RTMP 连接到任意一个 SyncTV 节点;LiveProxy 也可以在任意节点拉取外部 WHEP。
- 认证通过后,节点把
room_id/media_id -> node_id/api_address注册到 publisher registry。集群模式下 registry 使用 Redis。 - 本节点 StreamHub 接收 frame;WHIP/WHEP 源还会保留 RTP。HTTP-FLV 和 HLS 订阅 frame,WHEP 订阅 RTP。
- HLS 分片写入
memory、file、shared_file或s3backend。 - 观众请求落到非 publisher 节点时,该节点通过共享 registry 找到 publisher owner。gRPC relay 分别传输 frame 和 RTP,并使用 generation ID 与 lease epoch 拒绝过期 publisher。
shared_file的 TS 分片请求由当前节点从共享路径读取;本地 backend 仍使用 publisher-node HLS gRPC proxy 读取远端 playlist/segment。
livestream.rtmp_port
Section titled “livestream.rtmp_port”默认值:1935。
作用:RTMP 推流端口。
OBS 推流地址通常类似:
rtmp://your-domain:1935/live/<stream-key>managed live Provider 的媒体 source config 也支持相同的 mode 字段:
{ "provider": "live", "mode": "audioOnly"}该配置决定进入 StreamHub 的音视频类型,播放端继续使用 SyncTV 生成的 HLS 或 HTTP-FLV 地址。
如果服务器已经有其他 RTMP 服务占用 1935,可以改成别的端口。
livestream.public_rtmp_host
Section titled “livestream.public_rtmp_host”默认值为空。
作用:返回给推流客户端的公开 RTMP 主机名。
生产环境通常需要显式设置,尤其是:
- 集群内部
server.advertise_host是 Pod IP。 - 真实用户需要通过公网域名或 LoadBalancer 推流。
示例:
livestream: public_rtmp_host: "live.example.com"如果为空,SyncTV 只会回退到本机绑定地址,适合本地开发或单机内网测试;不会使用 Pod IP 或集群内部 server.advertise_host 作为公开推流地址。
livestream.gop_cache_size
Section titled “livestream.gop_cache_size”默认值:2。
GOP 是视频编码中的一组帧。GOP 缓存可以让新连接的观众更快开始播放,不必等下一个关键帧。
普通部署保持默认即可。
livestream.gop_cache_max_memory_mb
Section titled “livestream.gop_cache_max_memory_mb”默认值:100。
作用:限制单个直播流的 GOP 缓存内存。总 GOP 缓存占用可能接近该值乘以活跃直播流数量。
调大场景:
- 视频码率高。
- 新观众经常加入,想提升起播体验。
调小场景:
- 服务器内存有限。
livestream.stream_timeout_seconds
Section titled “livestream.stream_timeout_seconds”默认值:300。
作用:拉流空闲多久后自动停止。
如果你有长时间无人观看但希望保持拉流的场景,可以调大。否则保持默认能节省上游和本机资源。
拉流重试配置
Section titled “拉流重试配置”pull_max_retries
Section titled “pull_max_retries”默认值:10。
拉流失败最多重试多少次。
pull_initial_backoff_ms
Section titled “pull_initial_backoff_ms”默认值:1000。
第一次失败后等待多久再重试。
pull_max_backoff_ms
Section titled “pull_max_backoff_ms”默认值:30000。
重试等待时间最多增长到多少。
上游直播源短暂断线时,SyncTV 会自动重试。等待时间会逐步变长,避免持续高频请求上游。
livestream.max_flv_tag_size_bytes
Section titled “livestream.max_flv_tag_size_bytes”默认值:10485760,也就是 10 MB。
作用:限制单个 FLV tag 最大大小,防止异常流导致内存占用过高。
不建议随意调大。除非你明确知道上游会产生更大的合法 tag。
HLS 配置
Section titled “HLS 配置”livestream.hls_storage.type
Section titled “livestream.hls_storage.type”默认值:memory。
可选值:
| 值 | 作用 | 适用场景 |
|---|---|---|
memory |
HLS 分片保存在当前进程内存里 | 单副本、临时直播、开发环境 |
file |
HLS 分片写入当前节点的 livestream.hls_storage.path |
单副本文件存储,或小规模多副本 publisher-node proxy |
shared_file |
HLS 分片写入所有副本共享的 livestream.hls_storage.path |
多副本共享文件系统,TS 分片由当前节点从共享路径读取 |
s3 |
HLS 分片写入 S3 兼容对象存储 | 多副本、Kubernetes、跨节点共享 |
规范值是 memory、file、shared_file、s3。
集群模式可以使用 memory 或 file。非 publisher 节点会通过 HLS gRPC proxy 到 publisher 节点读取 playlist/segment。这个模式适合小规模部署或验证环境;生产高并发 HLS 推荐使用:
shared_file,并且hls_storage.path是所有副本可读写的共享文件系统。.ts请求会由当前节点直接从共享路径读取。s3,并配置livestream.hls_storage.*。
livestream.hls_storage.memory_max_mb
Section titled “livestream.hls_storage.memory_max_mb”默认值:0,表示使用内置默认。
作用:限制 hls_storage.type=memory 时的 HLS 分片内存占用。0 使用内置默认,当前内置默认是 512 MB。
共享文件 backend
Section titled “共享文件 backend”livestream: hls_storage: type: "shared_file" path: "/var/lib/synctv/hls"shared_file 明确表示这个路径是 NFS、RWX PVC、CSI volume 等所有副本可见的共享文件系统。不要把 Pod 本地 emptyDir、/tmp 或本机磁盘配置成 shared_file。
在 shared_file 模式下,publisher 节点负责写入 HLS 分片;任意节点收到 .ts 请求时,会从当前节点挂载的共享路径读取分片,不再回源到 publisher 节点获取 TS 文件。
livestream.hls_storage.path
Section titled “livestream.hls_storage.path”默认值为空。
作用:hls_storage.type=file 或 shared_file 时的 HLS 分片存储路径。相对路径会相对 data_dir。
示例:
data_dir: "/var/lib/synctv"livestream: hls_storage: type: "file" path: "livestream/hls"实际路径:
/var/lib/synctv/livestream/hlslivestream.hls_storage.* for S3
Section titled “livestream.hls_storage.* for S3”当 hls_storage.type=s3 时,SyncTV 使用 S3 兼容对象存储保存 HLS 分片。
livestream: hls_storage: type: "s3" endpoint: "https://s3.example.com" bucket: "synctv-hls" region: "auto" base_path: "synctv/hls/"secret 建议使用环境变量或 secret 文件注入:
export SYNCTV_LIVESTREAM_HLS_STORAGE_ACCESS_KEY_ID="..."export SYNCTV_LIVESTREAM_HLS_STORAGE_SECRET_ACCESS_KEY="..."字段说明:
| 字段 | 默认值 | 作用 |
|---|---|---|
livestream.hls_storage.endpoint |
"" |
S3-compatible endpoint,例如 AWS S3、MinIO、Cloudflare R2 或兼容服务的 endpoint |
livestream.hls_storage.bucket |
"" |
存储 HLS 分片的 bucket |
livestream.hls_storage.access_key_id |
"" |
Access key ID,支持 access_key_id_file |
livestream.hls_storage.secret_access_key |
"" |
Secret access key,支持 secret_access_key_file |
livestream.hls_storage.region |
null |
S3 region;某些兼容服务可留空或使用服务商要求的值 |
livestream.hls_storage.base_path |
hls/ |
bucket 内对象前缀;会规范化为不以 / 开头、以 / 结尾 |
HTTP-FLV 配置
Section titled “HTTP-FLV 配置”livestream.flv_max_connection_duration_seconds
Section titled “livestream.flv_max_connection_duration_seconds”默认值:86400,也就是 24 小时。
作用:单个 HTTP-FLV 连接最长保持多久。
设置为 0 可以关闭限制,但不推荐。长时间连接如果永不限制,异常客户端可能长期占用资源。
livestream.flv_write_timeout_seconds
Section titled “livestream.flv_write_timeout_seconds”默认值:30。
作用:向客户端写数据时最多等待多久。
如果客户端网络很慢,写入一直阻塞,SyncTV 会在超时后断开连接,避免慢客户端拖垮服务。