From b85a795209a4568f990a9d680ae023f7aa893e66 Mon Sep 17 00:00:00 2001 From: AAA <35992542+TNTcraftHIM@users.noreply.github.com> Date: Wed, 19 Aug 2026 21:15:38 +0800 Subject: [PATCH] docs(media): gate twenty-viewer default --- docs/adr/0004-peer-assisted-media-experiment.md | 3 +++ docs/adr/0005-automatic-hybrid-media-routing.md | 4 +++- docs/project-memory.md | 2 +- docs/status.md | 3 ++- docs/方案设计.md | 8 +++++--- docs/需求理解.md | 7 ++++--- 6 files changed, 18 insertions(+), 9 deletions(-) diff --git a/docs/adr/0004-peer-assisted-media-experiment.md b/docs/adr/0004-peer-assisted-media-experiment.md index 623bcdf..d4ba47a 100644 --- a/docs/adr/0004-peer-assisted-media-experiment.md +++ b/docs/adr/0004-peer-assisted-media-experiment.md @@ -124,6 +124,9 @@ Safari join last as leaf checks. ADR-0005 now adds a per-session binary relay capacity: detected mobile/iPad clients report zero and desktop-class browsers report one. That heuristic, background lifecycle, and voluntary relay policy remain unverified, so the spike is still unsafe for arbitrary-user deployment. +This one-child, depth-four gate remains an eight-viewer experiment; it cannot +authorize the accepted 20-viewer default. That later release requires a separate +20-viewer matrix and proven capacity-two relay or bounded central exceptions. The proposal advances only if every condition holds: diff --git a/docs/adr/0005-automatic-hybrid-media-routing.md b/docs/adr/0005-automatic-hybrid-media-routing.md index 38ab401..c40df33 100644 --- a/docs/adr/0005-automatic-hybrid-media-routing.md +++ b/docs/adr/0005-automatic-hybrid-media-routing.md @@ -362,7 +362,9 @@ record which boundary is actually configured and the UI must not claim E2EE. 4. Implement server prepare/commit/abort and strict authorization. 5. Integrate host/viewer first-frame switching while retaining relay children. 6. Extend the tracked `1/3/5/8` benchmark with automatic fallback, peer/SFU UDP, - optional selected-edge TURN, source/profile/pause/stop, and server-egress measurements. + optional selected-edge TURN, source/profile/pause/stop, and server-egress + measurements; only after those pass, add the 20-viewer gate before changing + the room default. ## Acceptance Gates diff --git a/docs/project-memory.md b/docs/project-memory.md index cb2bdee..6be7740 100644 --- a/docs/project-memory.md +++ b/docs/project-memory.md @@ -62,7 +62,7 @@ These are measurement gates, not performance claims. ## Open Decisions -- Sustainable viewer count by broadcaster and relay hardware, quality profile, network class, and media route; use instrumented 1/3/5/8 comparisons rather than a 1:8 claim. +- Sustainable count by hardware, quality, network, and route: finish instrumented `1/3/5/8`, then pass a 20-viewer matrix before changing the accepted target default to 20. - Whether ADR-0004 passes fanout, re-encoding, depth-four latency, reparenting, silent-partition, and mobile-leaf gates. - Which optional TURN/media-TCP transport and port, if any, survives ADR-0005's public UDP-first canary; current LiveKit ICE/TCP/coturn stays until migration passes. - Exact mobile lifecycle behavior and whether Windows per-application audio is required for the first release. diff --git a/docs/status.md b/docs/status.md index 13aba9c..23f88de 100644 --- a/docs/status.md +++ b/docs/status.md @@ -61,7 +61,8 @@ After media gates, UI adds local volume/mute, names/roster, local endpoint details, and RTP loss rate. ADR-0004 still requires a full-resolution 30-minute `1/3/5/8` network, -resource, quality, latency, recovery, and browser/mobile-leaf matrix. +resource, quality, latency, recovery, and browser/mobile-leaf matrix. A separate +20-viewer gate must pass before the current default eight changes to target 20. Observed disconnects retain 5-second grace plus at most 3 seconds to a decodable picture; silent partitions add detection delay. diff --git a/docs/方案设计.md b/docs/方案设计.md index b9fe6a4..4447ce7 100644 --- a/docs/方案设计.md +++ b/docs/方案设计.md @@ -6,7 +6,7 @@ ## 目标与边界 -首个 PoC 验证一名分享者向小范围朋友进行低延迟游戏画面分享。观看端使用普通桌面或手机浏览器;媒体对每名观看者独立进行 ICE,能直连时走 P2P,只有失败的链路使用 coturn。房间默认最多八名观看者,可配置范围为 1 至 16;八人是接入默认值,不是未经真实 1:8 测试即可宣称的性能能力。 +首个 PoC 验证一名分享者向小范围朋友进行低延迟游戏画面分享。观看端使用普通桌面或手机浏览器;媒体对每名观看者独立进行 ICE,能直连时走 P2P,只有失败的链路使用 coturn。当前房间默认最多八名观看者、可配置范围为 1 至 16;自动分布式拓扑通过 20 人门禁后,目标 release 才把默认值和上限原子改为 20。容量配置只是接入边界,不是性能声明。 本阶段必须形成完整的最小纵向链路: @@ -80,7 +80,7 @@ tests/ RoomStore、TURN、协议和 WebSocket 集成测试 房间规则: -- 一名在线分享者、默认最多八名在线观看者;部署配置只接受 1 至 16; +- 一名在线分享者;当前默认最多八名在线观看者、配置只接受 1 至 16,目标路由 release 通过门禁后统一改为 20; - 分享者明确停止或捕获轨结束时只停止当前发布并通知观看者进入等待,不删除房间或使链接失效;host 信令短断仅更新在线状态并触发恢复,不能主动关闭仍健康的 P2P 媒体; - 临时房间到达 TTL 后才拒绝新连接、通知现有参与者并从内存清理;持久房间没有 TTL,进程启动时从 SQLite 恢复房间身份; - 设置全局房间上限防止内存耗尽;持久房间没有自动删除策略,运维方必须保护和备份数据库文件; @@ -253,7 +253,7 @@ SFU 是主要中央兜底,但正常只作为 virtual parent 向一至两个必 自动测试: - AccessSession 的密码开关、12 小时签名 cookie、过期、篡改、cookie 属性和无服务端 session 状态; -- RoomStore 的随机临时房间、TTL、host token 摘要验证、停止分享等待、默认八人上限、自定义 1 至 16 边界和超额拒绝; +- RoomStore 的随机临时房间、TTL、host token 摘要验证、停止分享等待、当前默认八人/1 至 16 边界、目标 20 人 gate 和超额拒绝; - SQLite 房间库从 `1` 自增、重启恢复、持久房间无过期时间、数据最小化、数据库路径无全站密码时启动失败; - 现行 TURN HMAC 固定向量、TTL 与生产 TURN/UDP+TCP 强校验保持回归覆盖;目标配置迁移另测 STUN 必需、TURN 全空正常禁用、部分配置 fail-fast、ordinary peer 的 per-edge coturn grant/wire,以及 LiveKit participant TURN 独立边界; - 协议非法 JSON、未知消息、错误方向、跨房间目标和 payload 限制; @@ -300,6 +300,8 @@ room code 规则且不重复的 ID;非法配置启动即失败。未配置或 实验只实现一个由服务端确定的广度优先拓扑:host 最多两个 child,每名 viewer 最多一个 child,因此形成两条按加入顺序平衡的 sticky 链。父节点只按深度和 `serverJoinSequence` 选择第一个空 slot。新 viewer 加入时不搬动已有节点;parent 离开时只把失去 parent 的 subtree root 重新分配到第一个空 slot,其 descendants 保持连接。该规则不采集或组合 RTT、带宽、CPU、地理位置与质量评分,也不主动重平衡。没有 parent 时明确等待或拒绝,不能创建分享端第三条边。 +该 one-child 浏览器实验在深度四时只能覆盖八名观看者,不能证明 20 人能力。目标 20 人需要资源门禁通过的 relay `downstreamCapacity=2`(两棵深度四二叉树理论可容纳 30 人,但这只是可达性)或受独立中央 egress cap 约束的 SFU 例外;必须实测逐跳重编码、上行、延迟和故障半径。未通过时保持当前默认八人,不增加深度或 Host fanout 来凑容量。 + 所有边都继续使用标准 WebRTC。每名 viewer 播放收到的 remote `MediaStream`,并把其中的 remote tracks 加入给唯一 child 的新 `RTCPeerConnection`。该路径会逐跳解码和重编码;实验必须记录每层 encode time、CPU/GPU、`qualityLimitationReason`、帧率、分辨率和延迟,不能称为 zero-copy 或 shared encode。 Peer-assisted 信令只接受一个严格对象:`resolution` 为 `720p | 1080p | 1440p`,`maxFramerate` 为 15 至 60 的整数,`maxBitrate` 为 2,000,000 至 12,000,000 的整数,`degradationPreference` 为 `maintain-resolution | balanced | maintain-framerate`,缺字段、多余字段和越界值都拒绝。服务端用受房间容量限制的内存 Map 保存完整设置,默认 1080p60、8 Mbps、清晰优先,不写入 SQLite;停止分享时保留,房间被放弃或过期时删除。只有 peer-assisted host 可更新,鉴权快照和在线广播携带同一完整设置;普通 P2P 的严格鉴权 wire 保持原样,host 或 viewer 在该模式发送同步消息都会被拒绝。启用 SFU 时 publisher 也使用这一设置,不另建一套质量协议。 diff --git a/docs/需求理解.md b/docs/需求理解.md index 910e940..711fa8a 100644 --- a/docs/需求理解.md +++ b/docs/需求理解.md @@ -6,7 +6,7 @@ 构建一个面向熟人游戏场景的低延迟屏幕共享工具。分享者可以在私密房间内分享游戏、应用窗口或显示器画面及声音,多名朋友可以即时观看。系统采用类似 Photon Host Mode 的产品抽象:中心服务负责房间、身份、确定性拓扑和建立连接,媒体优先级依次为小规模直接 P2P、peer-assisted 转发、部署提供的 SFU virtual parent;STUN 协助打洞,SFU 只向一至两个必要 roots 送流,roots 继续分布式服务其 peer descendants。TURN 是部署可选的极端网络 transport 兼容层,不是普通 peer 边的默认候选或独立拓扑。系统必须自动、无感地完成分配、故障恢复和必要的路线迁移,分享者与观看者不手动选择拓扑。分享端 Web 优先并允许后续 Electron/原生增强;观看端必须可通过桌面或手机浏览器打开邀请链接,不绑定专用客户端。 -当前 PoC 默认允许一名分享者和最多八名观看者,部署者可在 1 至 16 之间配置上限,超额观看者会被明确拒绝。八人只是当前容量默认值,不是已验证的性能承诺;真实 1:8 上行、编码和稳定性仍须测量。产品不承担公开直播或大规模观看,相关需求交给 OBS/Twitch 等成熟直播服务。 +当前 PoC 默认允许一名分享者和最多八名观看者,部署者可在 1 至 16 之间配置上限,超额观看者会被明确拒绝。已接受的自动分布式拓扑目标把默认值和可配置上限提高到 20,但只能与通过 20 人资源、质量、深度和恢复门禁的路由 release 原子启用;在此之前不得只改常量,让普通逐观看者 P2P 建立 20 条 Host 边。产品仍不承担公开直播或大规模观看,相关需求交给 OBS/Twitch 等成熟直播服务。 ## 功能需求 @@ -19,7 +19,7 @@ - [ ] 游戏声音:Windows Chrome/Edge 目标环境可请求系统音频;没有返回音轨时必须明确提示,而不是静默无声。 - [ ] 观看端本地音量:播放控制栏提供 `0%` 至 `100%` 音量条和静音按钮,只改变当前浏览器的媒体元素,不修改 Host 音轨、编码、房间状态或其他观看者。切流、换父和 ICE 恢复保留当前页面内的值;刷新后不持久化。静音保留上次非零音量,拖动到非零值自动取消静音。 - [ ] 本地显示名与房间成员:用户可设置一个保存在当前浏览器 `localStorage` 的显示名;信令只在当前在线会话内保存和广播经严格长度/字符校验的纯文本标签,不写 SQLite。Host 页面显示“{分享者显示名} 的房间”,Host 与 Viewer 都看到包含分享者和当前观看者的权威 roster。显示名不是账号、授权身份或可信唯一标识,重复名称允许且不得参与路由或质量决策。 -- [ ] 一对多观看:一名分享者可向配置允许的多名观看者发送画面;默认上限为 8,可配置范围为 1 至 16。当前 PoC 的逐观看者连接是测量基线,不再是超过两名观看者时的目标拓扑。 +- [ ] 一对多观看:当前安全默认上限为 8、可配置范围为 1 至 16;自动分布式拓扑验收后,同一 release 将默认值和上限改为 20。当前 PoC 的逐观看者连接是测量基线,不再是超过两名观看者时的目标拓扑;未通过 20 人门禁时继续明确拒绝超额加入。 - [ ] 端点 fanout 硬上限:任一非服务器端点任何时刻最多维护两条 active downstream media edges,包括加入、断线、换父和恢复过程;上游接收不计入这项上传预算。当前 browser relay 因逐跳重编码仍保守限制为一个 child,只有资源矩阵通过后才可升到二。第三名及后续观看者由系统自动分配给通过验收的 peer-assisted 拓扑,不能隐藏地回退为 Host 第三条连接。没有可行 peer path 时,SFU 作为主要中央兜底 virtual parent 正常向一至两个必要 roots 送流;媒体到达 root 后其余可行观看者仍优先沿受限 peer descendants 扩散。多个无法挂到健康 root 的极端 viewer 可成为额外 server-fed 例外,但必须受显式中央 egress/admission 上限约束,不能无界整房 fanout。TURN 只作为可选的极端网络 transport 兼容层,不定义房间拓扑。 - [ ] P2P 优先:每条逻辑媒体边的 ICE 必须先尝试直接 UDP 路径,服务器不得默认中转可直连的媒体。一个或两个观看者优先直接连接分享端;更多观看者的 peer-assisted 行为须先通过 ADR-0004 的实验门槛。 - [ ] NAT 与传输兜底:STUN 必须可用。普通 direct/peer 边默认只使用 ICE/UDP;其路径不可用时改由 SFU virtual parent 承担必要 root,而不是给每条 peer edge 常驻 TURN candidates。旗舰默认媒体路径为 `direct/peer UDP -> SFU ICE/UDP -> 明确失败`。部署者可为已验证的受限网络额外启用短期鉴权 TURN。普通 Host 到 peer root 或 root 到 viewer 的异常边需要新增、绑定当前 assignment/connection generation 的独立 coturn grant/wire;一个 TURN seed root 收到媒体后仍优先服务 bounded peer descendants。LiveKit publisher/subscriber 到 SFU 是另一 ICE 域,pinned 1.13.5 的 embedded/external TURN 当前按 LiveKit participant 广告,不是 Screener selected-edge grant。两者必须分开配置、鉴权和验收。媒体 ICE/TCP、TURN/TCP 和 TURN/TLS 不是默认质量路径。HTTPS/WSS 仍使用 TLS/TCP。全部可选 TURN 配置缺失表示正常禁用且不提示,部分配置必须启动即失败。 @@ -73,7 +73,7 @@ - 首版不包含远程键鼠控制、公开/大规模直播、录制、社区系统或完整语音聊天;大规模分享直接使用现有直播服务。 - 公开模式中,随机数字房间码是唯一观看 capability,不提供强私密保证;面向互联网且要求私密的部署必须配置全站密码。可枚举的自增房间码只允许出现在已经由全站密码保护的持久模式中。 - SQLite 只用于持久房间身份,不得保存全站密码、host token 明文、access cookie、SDP、ICE candidate、IP 地址、观看者状态、媒体或 TURN 凭据;首版仍是单进程、单实例控制面。 -- 默认八名观看者和可配置的 1 至 16 范围是接入容量边界,不承诺任意机器、档位或网络都能稳定承载该人数,也不承诺跨洲网络下的固定低延迟。 +- 当前八名观看者和 1 至 16 配置范围是接入边界;目标默认 20 也只是通过指定矩阵后的接入边界,不承诺任意机器、档位、网络或跨洲路径都稳定承载。 - 浏览器规范要求每次由用户主动选择分享源,权限不能永久保存;纯网页不能保证指定游戏窗口或始终获得系统音频。 - 1080p60 是能力目标,实际分辨率、帧率和硬件编码由浏览器、GPU、驱动、画面复杂度及网络共同决定。 - 已部署首版仍是标准 WebRTC P2P。Peer-assisted spike 只复用标准 remote-track WebRTC,不加入 Encoded Transform/DataChannel/WebCodecs 媒体协议,也不自研 UDP、编解码器、拥塞控制、FEC/RTX、多树、转码、codec ladder 或综合评分器;需要其中任一项即放弃本次浏览器 relay 实验。独立计划中的 native shared encode sender 不在本 spike 实现,也不能挽救其他拓扑门槛失败。跨 P2P、peer-assisted 与 SFU-root 的自动路由是产品要求,但由单独 ADR 约束;当前 spike 尚未实现跨模式迁移或短时双发。 @@ -112,6 +112,7 @@ - Given 一名分享者和一至两名观看者,When 运行直接 P2P,Then 分享端为每人建立独立媒体边且总 fanout 不超过二。 - Given peer-assisted spike 分别运行 1、3、5、8 名观看者,When 用户加入、离开或 relay 失效,Then 服务端使用同一个确定性广度优先规则形成两条 sticky 链,只为新 viewer 或失去 parent 的 subtree root 分配 parent,不主动搬动其他节点;分享端在任何瞬间都不超过两个 child 且每名 viewer 不超过一个,没有可用 parent 时明确等待或拒绝,而不是增加分享端 fanout。 - Given 一名分享者和八名观看者,When 在受控网络中运行已记录的质量档位,Then 记录每条边的拓扑深度、候选类型、码率、编码/解码负载、分享端与 relay 上行、首帧和玻璃到玻璃延迟;该条在真实矩阵完成前保持未验收。 +- Given candidate 将房间默认上限改为 20,When 在 exact-room 中连续运行 20 名观看者 30 分钟并注入 relay departure、重连和一个弱路径,Then 每名观看者持续解码、Host 下游边不超过二、每个 relay 不超过已验收能力、深度与故障半径有界、未受影响 subtree 不迁移,并记录端点/SFU 的 CPU、GPU、内存、上行、出口、帧率、丢包率、冻结和恢复;任一门槛失败时不得切换默认值。 - Given peer-assisted host 鉴权或直播中连续修改质量设置,When 服务端校验其分辨率、FPS、码率和偏好,Then 只有 host 的完整有界设置被接受,last-wins 地应用到当前和以后建立的 relay child sender 以及启用的 SFU publisher;越界、缺字段和多余字段被拒绝,普通 P2P 的鉴权 wire 不新增该字段且不接受同步消息。 - Given 标准浏览器把收到的 remote track 直接加入下游 `RTCPeerConnection`,When 检查 relay 统计和 libwebrtc 路径,Then 明确记录新的 outbound encoder、编码耗时和 CPU/GPU 限制,不把它当作 encoded forwarding 或 shared encode 成果。 - Given ADR-0004 的任一硬门槛只有在引入 Encoded Transform/DataChannel/WebCodecs 媒体、自定义拥塞控制、FEC/RTX、多树、综合评分、转码、codec ladder、浏览器 RTP 注入 hack 或放宽 host fanout 后才能满足,When 结束 bounded spike,Then 放弃并删除浏览器 relay 实验运行时代码,保留标准 P2P 和 SFU-root fallback;后续 native shared encode sender 仍按独立 ADR 推进,但不能据此把失败的 relay 拓扑判为通过。