播放模型
SyncTV 的同步观看由服务端房间状态驱动。客户端不把自己的播放器状态当成事实来源;它接收房间当前播放状态,并在有权限时提交播放控制动作。
| 状态 | 谁维护 | 用途 |
|---|---|---|
| 当前播放状态 | SyncTV 服务端 | 当前媒体、播放/暂停、进度、速度和版本 |
| 播放信息 | Provider 和 SyncTV 生成 | 播放 URL、代理 URL、header、字幕、变体和过期时间 |
当前播放状态回答“房间正在看什么、看到哪里”。播放信息回答“这个客户端现在应该怎么播放这个媒体”。
Realtime 如何参与
Section titled “Realtime 如何参与”房间 WebSocket 负责同步播放控制、聊天、WebRTC 信令和资源观察事件。客户端断线重连后,应重新获取关键资源,而不是假设旧订阅仍然存在。
典型顺序:
- 客户端进入房间。
- 获取当前播放状态和播放信息。
- 连接 Realtime。
- 收到播放、暂停、seek 或切换媒体事件。
- 如果媒体 URL 过期、Provider 凭据变化或资源版本变化,重新获取播放信息。
| 模式 | 适合场景 | 风险 |
|---|---|---|
| 直连 | 客户端能访问上游 URL,并能设置所需 header | 浏览器可能不能设置部分 header |
| SyncTV proxy | 需要隐藏上游凭据、统一 header、处理 Range 或绕过客户端限制 | SyncTV 承担出口带宽和代理延迟 |
Provider 明确返回需要使用的 header。SyncTV proxy 不自动转发客户端原始 header,避免把不该传给上游的信息泄露出去。
同一个播放结果可以同时包含直连模式和 proxy_* 模式。Provider 在生成播放信息时决定这些模式、默认模式、header 暴露策略和签名代理 URL。共享 helper 只负责生成标准 proxy sibling URL,不能替代各 Provider 自己的播放决策。
HTTP 和 gRPC 是传输入口。它们解析路径、query、JSON/protobuf、headers 和流式 body,然后调用 synctv-api/src/impls。权限、播放状态、Provider 调用、缓存、fanout、时长合并和资源生命周期处理在 impls 与 core service 中完成,让两种传输共享同一套行为。
Range 和缓存
Section titled “Range 和缓存”seek 通常依赖 HTTP Range。上游支持 Range 时,SyncTV proxy slice cache 可以缓存固定分片;上游不支持 Range 时,SyncTV 会绕过 slice cache,不把完整大文件写成缓存。
后台播放任务
Section titled “后台播放任务”播放时长探测和播放自动切换由本节点 active room 驱动。房间只有在当前进程存在 Realtime 连接时,才会进入该节点的后台播放扫描集合。
这些 worker 在每个节点运行,让后台任务跟随真实连接生命周期。集群中多个节点同时承载同一房间时,数据库负责并发安全:时长探测用任务抢占,自动切换用播放状态事务和乐观版本。
后台任务的输入集合来自 ConnectionRuntime::active_room_ids()。Presence hot-room 统计用于房间列表、管理视图和 metrics;播放生命周期 worker 使用本节点实时连接集合,并通过数据库锁、SKIP LOCKED 和播放状态版本写入收敛。
动态 playlist 的后台任务还需要绑定当前 target。Repository 查询保留 room_id = ANY(active_room_ids) 和当前 room_playback_progress.target_hash join,确保探测、缓存和自动切换围绕房间当前播放项进行。
- 普通用户排查播放问题:读 同步观看 和 用户排障。
- 客户端实现播放:读 客户端集成指南。
- 配置代理缓存:读 Proxy slice cache。