diff --git a/docs/README.md b/docs/README.md index 4890a99..fd1d6d9 100644 --- a/docs/README.md +++ b/docs/README.md @@ -21,7 +21,7 @@ - [ADR-0001](./adr/0001-p2p-first-media-topology.md): accepted P2P-first media topology and its consequences. - [ADR-0002](./adr/0002-persistent-protected-rooms.md): Host admission, room-scoped private Viewer grants, explicit public-watch, rotation, and minimal SQLite persistence. - [ADR-0004](./adr/0004-peer-assisted-media-experiment.md): proposed, experiment-only standard-WebRTC peer-assisted spike with hard fanout and failure gates. -- [ADR-0005](./adr/0005-automatic-hybrid-media-routing.md): accepted direct/peer UDP -> SFU-root -> optional exceptional-edge TURN direction, with the room-`1` exact smoke and broader migration gates. +- [ADR-0005](./adr/0005-automatic-hybrid-media-routing.md): accepted direct/peer UDP -> SFU-root -> optional exceptional-edge TURN direction, including the historical room-`1` smoke and broader migration gates. - [ADR-0006](./adr/0006-fixed-high-native-sender-canary.md): proposed fixed-`HIGH` native canary, current no-go result, and staged revalidation boundary. - [ADR-0007](./adr/0007-demand-driven-dual-representation-quality.md): accepted path-isolated `HIGH + at most one LOW` policy, optional idle-layer stop, evidence contract, and SVC boundary. - [ADR-0008](./adr/0008-window-scoped-audio-capture.md): browser window-audio hint and the Windows WASAPI process-loopback boundary. diff --git a/docs/adr/0005-automatic-hybrid-media-routing.md b/docs/adr/0005-automatic-hybrid-media-routing.md index bdccbb1..6bdb14c 100644 --- a/docs/adr/0005-automatic-hybrid-media-routing.md +++ b/docs/adr/0005-automatic-hybrid-media-routing.md @@ -70,20 +70,20 @@ The flagship deployment target supplies SFU capacity with a complete LiveKit endpoint/key/secret tuple. There is no user-facing topology selector and no process-wide `MEDIA_MODE` union. A deployment without that tuple ends at peer assistance and bounded waiting/failure and is not the final flagship route -configuration. Optional selected-edge TURN is a separate default-off deployment -tuple and remains a controller-owned transport attempt, never a topology choice. +configuration. Optional selected-edge TURN is a separate deployment tuple and +remains a controller-owned transport attempt, never a topology choice. ## Implementation Status Merged PR #17 implements this controller on top of merged PR #13, and PR #20 adds the bounded standby prewarm below. The process flag enables the controller for every normal room; room `1` is retained only as a historical smoke fixture, -and production remains -STUN-only. The current source no longer contains the rejected participant-wide +and production ordinary peer connections remain STUN-only. The current source +no longer contains the rejected participant-wide TURN config, issuer, capability, refresh wire, or client propagation. Stale `PEER_ICE_TURN_*` keys fail startup even when blank. The source candidate now -implements a complete default-off selected-edge tuple and one post-SFU -relay-only rebuild; it remains undeployed and lacks real TURN/media evidence. +implements a complete selected-edge tuple and one post-SFU relay-only rebuild; +production configures it, but real TURN/media evidence remains open. The wire has two explicit edge kinds: `peer-selected` for the last-mile failed peer edge and `host-sfu-ingress` for a restricted Host-to-SFU retry. Ordinary Peer ICE remains STUN-only. @@ -415,15 +415,16 @@ Healthy direct/peer UDP stays distributed. When no such path can satisfy admission or recovery, one SFU publication feeds one or two roots, which keep their bounded peer descendants. Only an edge that also cannot use SFU/UDP may receive a controller-selected authenticated TURN attempt. Production currently -ends in bounded failure and has no application TURN config. Source has no +configures that selected-edge attempt but still ends in bounded failure if it +cannot connect. Source has no participant-wide TURN path: the rejected candidate is removed and its stale -environment keys fail startup. The default-off selected-edge source candidate uses +environment keys fail startup. The selected-edge implementation uses a short coturn REST bearer and one server-generated connection identity per explicit edge kind. `peer-selected` binds the failed parent/Viewer pair; `host-sfu-ingress` binds the room, host session, SFU publication generation, and the old/new connection identities. The Host client applies that grant only to a -relay-only LiveKit publisher `RTCConfiguration`. It is undeployed and has no real -relay-media evidence. +relay-only LiveKit publisher `RTCConfiguration`. It is configured in production +but has no real relay-media evidence. LiveKit participant-wide embedded/external TURN remains a separate ICE domain. The bounded cost model and privacy-safe ICE fields diff --git a/docs/research/advanced-peer-distribution.md b/docs/research/advanced-peer-distribution.md index 2a81ebd..6520b09 100644 --- a/docs/research/advanced-peer-distribution.md +++ b/docs/research/advanced-peer-distribution.md @@ -312,7 +312,7 @@ optimizer, temporary fanout above budget, self-reported geography or device quality, or cannot beat the unchanged route. The earlier admission-rescue case remains valid, while this quality slice moves only the affected Viewer-rooted subtree and excludes only its current failed parent through the existing -peer-first, then SFU path. The default-off source candidate's selected-edge TURN attempt follows SFU +peer-first, then SFU path. The configured selected-edge TURN attempt follows SFU failure; healthy paths never enter relay optimization. ## Staged Connection Recovery Evidence diff --git a/docs/research/built-in-peer-ice-turn.md b/docs/research/built-in-peer-ice-turn.md index 2184ea8..7237887 100644 --- a/docs/research/built-in-peer-ice-turn.md +++ b/docs/research/built-in-peer-ice-turn.md @@ -26,8 +26,8 @@ the durable findings that still apply are summarized below. The current source no longer contains the rejected participant-wide config, issuer, authentication capability, refresh wire, or client propagation. Supplying any stale `PEER_ICE_TURN_*` key, even blank, fails startup. The replacement -selected-edge config, wire, and rebuild now exist as a default-off source -candidate; they remain undeployed and lack real relay-media evidence. +selected-edge config, wire, and rebuild now exist and are configured in +production. They remain controller-selected and lack real relay-media evidence. ## Production Canary diff --git a/docs/research/low-server-media-routes.md b/docs/research/low-server-media-routes.md index 8a006cf..6b1650a 100644 --- a/docs/research/low-server-media-routes.md +++ b/docs/research/low-server-media-routes.md @@ -5,16 +5,17 @@ media fanout at most two - Status: ADR-0005 accepts STUN-only direct/peer UDP, bounded SFU/UDP roots, then optional authenticated TURN/UDP for one controller-selected exceptional - edge; production remains STUN-only, and public transport behavior plus every - non-browser data plane is unverified + edge. Production enables the controller for all rooms and has a configured + selected-edge TURN tuple; ordinary peer connections remain STUN-only, while + real SFU/TURN media behavior remains unverified. ## Current Route Ladder The smallest current plan is: 1. Use direct host P2P for one or two viewers. -2. For later viewers, test the fixed two-chain browser relay in ADR-0004. It is - disabled by default with `PEER_ASSISTED_MEDIA=false`, is limited to at most +2. For later viewers, use the fixed two-chain browser relay in ADR-0004. It is + controlled by `PEER_ASSISTED_MEDIA`, is limited to at most eight viewers, and decodes and re-encodes at every relay. 3. Plan a separate native shared-encode sender regardless of the browser relay result. It reduces duplicate host encoding while retaining at most two @@ -24,7 +25,7 @@ The smallest current plan is: 4. Only if browser relay re-encoding is the isolated failure should another experiment add opt-in native volunteer encoded-RTP relays. 5. Keep a user-operated mini-SFU and a centrally operated single-node SFU as - optional capacity. The current default-off ADR-0005 controller uses that capacity + optional capacity. The ADR-0005 controller uses that capacity automatically only after deterministic peer recovery is exhausted. The SFU is a virtual parent for only one or two necessary roots; those roots continue bounded peer descendants. A necessary viewer may be a zero-descendant root @@ -34,9 +35,9 @@ The smallest current plan is: Any browser-spike failure other than isolated relay re-encoding closes that browser-relay route. It does not cancel the separate native sender plan. Closed PR #12's explicit whole-room SFU mode is superseded. ADR-0005 and merged PR #17 -own the automatic cross-mode controller. Production enables it only for room `1` -with a complete LiveKit tuple; participant entry was observed, but retained -media was not. Corrected localhost Chrome/LiveKit functional recovery passed, while public +own the automatic cross-mode controller. Production first enabled it only for +room `1` and later removed that rollout boundary. Participant entry was +observed, but retained media was not. Corrected localhost Chrome/LiveKit functional recovery passed, while public transport, quality, load, and browser validation remain open. ## Token-Free SFU Standby Prewarm @@ -190,11 +191,12 @@ SFU, not ordinary peer PCs. Selected-edge coturn uses independent configuration and credentials. LiveKit TURN cannot rescue an unavailable SFU; the application controller selects whether independent coturn may rebuild one failed peer edge. -Production and ordinary peer ICE remain STUN-only. The participant-wide TURN +Ordinary peer ICE remains STUN-only. The participant-wide TURN config, capability and refresh wire are removed; any stale `PEER_ICE_TURN_*` -key, including an empty value, fails startup. Selected-edge TURN is source-complete, -default-off and undeployed. Every ordinary room, Web peer and Native-shaped -client remains STUN-only. The tracked coturn example is UDP +key, including an empty value, fails startup. Selected-edge TURN is deployed as +a configured, controller-issued exceptional transport; its real media path is +not yet canary-proven. Every ordinary Web peer and Native-shaped client remains +STUN-only. The tracked coturn example is UDP `stun-only`; the LiveKit example exposes only ICE/UDP mux 7882, explicitly sets `tcp_port: 0` and `allow_tcp_fallback: false`, supplies the self-hosted STUN endpoint, and configures no external or embedded TURN. Candidate validation and rollback use isolated diff --git a/docs/research/peer-assisted-media.md b/docs/research/peer-assisted-media.md index 055c0ed..b24ae73 100644 --- a/docs/research/peer-assisted-media.md +++ b/docs/research/peer-assisted-media.md @@ -3,8 +3,8 @@ - Research date: 2026-08-19 - Scope: one game-screen broadcaster, at most eight trusted viewers, host media fanout at most two - Status: historical evidence for the bounded ADR-0004 experiment; accepted - ADR-0005 now owns automatic peer/SFU routing, with only room `1` enabled as a - production smoke and retained SFU media still unverified + ADR-0005 now owns automatic peer/SFU routing. Production later removed the + room-`1` rollout boundary; retained SFU media remains unverified. ## Conclusion @@ -28,9 +28,9 @@ The accepted flagship preference is `direct/peer UDP -> SFU-root fallback -> optional exceptional-edge TURN -> bounded failure`. Direct P2P remains the simplest path for one or two viewers. The experiment assigns the third and later viewers to peers automatically. ADR-0005 makes SFU capacity part of the flagship -target while retaining peer descendants. Production currently enables only a -room-`1` exact smoke; participant entry was observed, but retained SFU media and -broad rollout remain unverified. +target while retaining peer descendants. The first production rollout used a +room-`1` exact smoke; participant entry was observed, but retained SFU media +remained unverified. Production later removed that room boundary. ## What Browsers Can Share @@ -286,16 +286,18 @@ Peer assistance distributes traffic; it does not eliminate it. Relay eligibility must therefore be visible and voluntary in any production design. The standalone ADR-0004 spike has no runtime capability flag and relies on controlled join order. The accepted ADR-0005 controller starts every viewer as -a leaf, then accepts an explicit per-session capacity of zero or one; production -scopes it to room `1` while broader rollout remains gated. Its Web client +a leaf, then accepts an explicit per-session capacity of zero or one. The first +production smoke scoped it to room `1`; current production no longer has that +room boundary. Its Web client reports detected mobile/iPad clients as leaves and desktop-class browsers as one-child relays. That conservative heuristic is still unverified on the real mobile matrix and is not a substitute for a future voluntary relay policy. ## Bounded Spike And Gates -The feature remains default-off in configuration through -`PEER_ASSISTED_MEDIA=false`; production enables only the exact room-`1` smoke. +This historical gate assumed default-off configuration through +`PEER_ASSISTED_MEDIA=false`; current production enables the controller for all +rooms. It cannot be enabled above eight viewers and uses the existing standard WebRTC screen stream, current desktop Chrome/Edge as relay nodes, current Android Chrome and iOS Safari as required @@ -359,8 +361,9 @@ fallbacks. Passing these historical gates proved only that a second design phase was justified. ADR-0005 subsequently accepted the bounded controller and production -now has a room-`1` smoke, but retained SFU media, voluntary relay policy, and -broader audio/A-V verification remain open. The +first ran a room-`1` smoke and later removed that rollout boundary, but retained +SFU media, voluntary relay policy, and broader audio/A-V verification remain +open. The native host shared-encode sender is a separate planned phase regardless of this experiment's result and is not implemented here. diff --git a/docs/research/webrtc-p2p-screen-sharing.md b/docs/research/webrtc-p2p-screen-sharing.md index 1e6d572..921f593 100644 --- a/docs/research/webrtc-p2p-screen-sharing.md +++ b/docs/research/webrtc-p2p-screen-sharing.md @@ -3,7 +3,7 @@ - 调研日期:2026-08-18 - 移动端采集能力复核:2026-08-19 - 目标场景:一名玩家向少量熟人私密分享,观看者可用手机/桌面浏览器加入,低延迟,尽量不消耗媒体服务器带宽 -- 结论状态:本文记录已部署 PoC 的 P2P/coturn 基线。ADR-0005 与[低服务器成本媒体路由](./low-server-media-routes.md)已取代本文早期“每条 peer edge 必带 TURN”的旗舰建议;room `1` 已部署 peer/SFU controller smoke,ordinary ICE 仍为 STUN-only,selected-edge TURN 尚未实现 +- 结论状态:本文记录已部署 PoC 的 P2P/coturn 基线。ADR-0005 与[低服务器成本媒体路由](./low-server-media-routes.md)已取代本文早期“每条 peer edge 必带 TURN”的旗舰建议;生产后续移除了 room `1` 边界,ordinary ICE 仍为 STUN-only,selected-edge TURN 已配置但尚未完成真实媒体验收 ## 结论 @@ -115,10 +115,10 @@ IETF 对 mesh/SFU 的拓扑说明见 [RFC 7667](https://www.rfc-editor.org/rfc/r 当前生产基线: -- 未命中 exact allowlist 的小范围观看者默认使用 STUN-only P2P,每人一条独立连接;room `1` 启用 bounded peer-assisted/SFU controller smoke。 +- 生产已移除 exact-room allowlist,所有房间由 bounded peer-assisted/SFU controller 自动路由;ordinary peer 仍使用 STUN-only ICE。 - 当前 PoC 默认允许八名观看者,部署者可配置 1 至 16,超额连接会被明确拒绝。该数值只控制接入,不代表 1:8 已通过性能验收;必须收集可用上行、实际发送码率、`qualityLimitationReason`、编码耗时和发送队列来确定真实可持续人数。 -- 每条 ordinary peer 链路独立使用 STUN-only ICE;当前应用不向任何 peer connection 下发 TURN credential。 -- room `1` 在 peer recovery 与 alternate parent 耗尽后可准备最多两个 SFU/UDP roots;participant entry 已观察到,但 retained media 尚未验收。 +- 每条 ordinary peer 链路独立使用 STUN-only ICE;只有控制器选中的异常 edge 才会获得短期 TURN credential。 +- 所有房间在 peer recovery 与 alternate parent 耗尽后均可准备最多两个 SFU/UDP roots;首次 room `1` smoke 已观察到 participant entry,但 retained media 尚未验收。 - 桌面和手机观看者使用同一个 Web 播放端;分享者不要求朋友安装完整客户端。 产品目标要求分享端 fanout 永远不超过二。ADR-0004 的可删除实验验证第三名及后续 viewer 由客户端转发;ADR-0005 的自动 controller 已在 room `1` 受限部署,SFU 只服务必要 roots 并保留 peer descendants。retained SFU media、移动端矩阵和 broad rollout 仍未通过门槛;已关闭 PR #12 的显式整房 SFU 模式不再是当前方案。超过小房间上限时仍建议使用外部直播服务。观察项包括: diff --git a/src/client/components/StatusBadge.tsx b/src/client/components/StatusBadge.tsx index 153a180..4618d85 100644 --- a/src/client/components/StatusBadge.tsx +++ b/src/client/components/StatusBadge.tsx @@ -54,7 +54,7 @@ export function PeerStatusBadge({ export function PathBadge({ path }: { path: MediaPath }) { if (path === "direct") { return ( - + @@ -84,7 +84,7 @@ export function TopologyBadge({ const values: Record = { "host-direct": { tone: "good", label: "Host 直连" }, "peer-relay": { tone: "warning", label: "Peer 中转" }, - sfu: { tone: "warning", label: "SFU" }, + sfu: { tone: "warning", label: "SFU fallback" }, pending: { tone: "neutral", label: "连接中" }, }; return ;