docs: record relay measurement boundaries
This commit is contained in:
1 parent
be00ca84a0
commit
d5ac1ea604
8 files changed
+201
-25
No files matched your search
@@ -9,6 +9,7 @@
|
||||
- [P2P WebRTC research](./research/webrtc-p2p-screen-sharing.md): evidence, bandwidth model, browser constraints, reference implementations, and feasibility assessment.
|
||||
- [Peer-assisted media research](./research/peer-assisted-media.md): browser shared-encode limits, standard relay re-encoding, rejected custom encoded transport, deterministic sticky topology, and abandon gates.
|
||||
- [Low-server-cost media routes](./research/low-server-media-routes.md): traffic accounting, route screening, conditional native encoded-RTP relay, and explicit SFU fallbacks.
|
||||
- [Native shared-encode sender](./research/native-shared-encode-sender.md): bounded libwebrtc encoder-proxy risk spike, Pion fallback, and hard failure gates.
|
||||
- [Realtime quality adaptation](./research/realtime-quality-adaptation.md): browser degradation policy, live profile changes, offline-encoding boundaries, and measurement gates.
|
||||
- [Agent context governance research](./research/agent-context-governance.md): official Codex, Claude Code, Hermes Agent, and GitHub practices adopted by this repository.
|
||||
- [ADR-0001](./adr/0001-p2p-first-media-topology.md): accepted P2P-first media topology and its consequences.
|
||||
|
||||
@@ -39,7 +39,9 @@ Last updated: 2026-08-19
|
||||
- A Chromium 151 one-to-eight synthetic functional smoke formed two depth-four chains: two connected host outbound peers, one inbound plus one outbound at viewers 1 through 6, inbound-only viewers 7 and 8, and decoded frames everywhere. This proves topology only, not profile quality, resource cost, latency, or endurance.
|
||||
- Closing the first-level relay reattached its branch and resumed decoding in about 5.3 seconds while host active connected outbound edges peaked at two. A silent partition instead waits for the 30-second heartbeat, so detection can take 30 to 60 seconds before the default 5-second viewer grace; that path is unverified.
|
||||
- The peer-assisted authenticated snapshot and host-only update synchronize one bounded, non-persistent room profile. Online viewers receive changes; `ViewerRelay` uses the latest desired profile for current and future children, while `HostPeer` serializes sender setup, stream replacement, and last-wins profile updates. The ordinary P2P wire is unchanged. Real 1/3/5/8 quality, resource, and latency measurements remain pending.
|
||||
- The recorded peer-assisted full check passes type checking, 12 Vitest files with 141 tests, and both client and server production builds. Production release `5b2fb005f6f7` separately passed 108 Vitest tests, both builds, loopback and public HTTPS/access-gate checks, and a clean activation without disturbing nginx, coturn, or the blog.
|
||||
- Chromium 151 kept the same relay peer, sender, and signaling generations while changing its sender ceilings from 8 Mbps/60 fps to 5 Mbps/30 fps and 3 Mbps/30 fps; the leaf continued decoding. The synthetic 640x360/30 source proves profile propagation and connection preservation only, not full-resolution quality or load.
|
||||
- Per-frame encode/decode diagnostics use adjacent non-overlapping `getStats()` deltas rather than connection-lifetime averages; first, empty, changed-stream, and reset intervals remain unknown and rebase.
|
||||
- The recorded peer-assisted full check passes type checking, 12 Vitest files with 144 tests, and both client and server production builds. Production release `5b2fb005f6f7` separately passed 108 Vitest tests, both builds, loopback and public HTTPS/access-gate checks, and a clean activation without disturbing nginx, coturn, or the blog.
|
||||
- Draft SFU PR #12 and ADR-0003 remain unmerged, undeployed, and independently reversible. There is no infrastructure blocker for the deployed Web baseline or bounded peer-assisted experiment.
|
||||
|
||||
## Provisional Quality Targets
|
||||
@@ -64,6 +66,6 @@ These are measurement gates, not performance claims.
|
||||
|
||||
- Documentation index and current phase: `docs/README.md` and `docs/status.md`
|
||||
- Requirements and design: `docs/需求理解.md` and `docs/方案设计.md`
|
||||
- Media research: `docs/research/webrtc-p2p-screen-sharing.md`, `docs/research/realtime-quality-adaptation.md`, `docs/research/peer-assisted-media.md`, and `docs/research/low-server-media-routes.md`
|
||||
- Media research: `docs/research/webrtc-p2p-screen-sharing.md`, `docs/research/realtime-quality-adaptation.md`, `docs/research/peer-assisted-media.md`, `docs/research/low-server-media-routes.md`, and `docs/research/native-shared-encode-sender.md`
|
||||
- Architecture: ADR-0001, ADR-0002, proposed experiment ADR-0004, and Draft PR #12's unaccepted ADR-0003
|
||||
- Deployment and maintenance: `docs/deployment.md`, `docs/maintenance.md`, `AGENTS.md`, and `.codex/`
|
||||
@@ -16,7 +16,9 @@ The smallest current plan is:
|
||||
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
|
||||
standard WebRTC edges, so it does not remove their upload cost.
|
||||
standard WebRTC edges, so it does not remove their upload cost. The bounded
|
||||
risk spike is specified in
|
||||
[Native Shared-Encode Sender](./native-shared-encode-sender.md).
|
||||
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
|
||||
@@ -58,7 +60,7 @@ lost.
|
||||
| --- | --- | --- | --- |
|
||||
| Direct host P2P | Host emits one copy per viewer | Host upload and sender pipelines grow with viewers | Keep for one or two viewers |
|
||||
| Fixed two-chain browser relay | Host emits at most two copies; each relay emits at most one | Ordinary browser, but every relay decodes and re-encodes and adds a hop | Current default-off, maximum-eight-viewer spike |
|
||||
| Native shared-encode host | Host encodes once for at most two standard WebRTC edges | Native sender packaging and custom libwebrtc encoder fanout | Planned separate sender phase; still pays per-edge upload |
|
||||
| Native shared-encode host | Host targets one encode for at most two standard WebRTC edges | libwebrtc public-API proxy risk spike, with Pion as fallback | Planned separate sender phase; still pays per-edge upload |
|
||||
| Native volunteer encoded-RTP relay | Each volunteer forwards one encoded copy | Native install, RTP/RTCP forwarding, packaging, and opt-in relay policy | Conditional experiment only if relay re-encoding is the sole browser-spike failure |
|
||||
| User-operated mini-SFU | User's SFU emits viewer copies | Separate deployment and its egress bill; running it on the host does not reduce that host's uplink | Explicit fallback |
|
||||
| Central single-node SFU | Service SFU emits viewer copies | Lowest endpoint relay burden; service pays approximately `N * B` egress | Explicit fallback; Draft PR #12 only |
|
||||
|
||||
@@ -0,0 +1,140 @@
|
||||
# Native Shared-Encode Sender
|
||||
|
||||
- Research date: 2026-08-19
|
||||
- Scope: one Windows game-capture sender, one encoded video stream, and at most
|
||||
two independent standard WebRTC media edges
|
||||
- Status: candidate risk spike; not implemented or accepted for production
|
||||
|
||||
## Decision Input
|
||||
|
||||
TeamSpeak-style shared encoding is a required later sender phase. It can remove
|
||||
duplicate host encoding work, but it cannot remove the upload copy, RTP state,
|
||||
or congestion control required by each outgoing edge. The first implementation
|
||||
must prove one narrow property before adding capture, audio, UI, or packaging:
|
||||
|
||||
> Two unmodified browser viewers receive two independent WebRTC sessions while
|
||||
> one physical encoder invocation produces the compatible encoded access unit
|
||||
> consumed by both sessions.
|
||||
|
||||
The preferred first experiment is a standalone Windows C++ sender using a fixed
|
||||
libwebrtc revision. It keeps libwebrtc's mature PeerConnection, RTP/RTCP, pacing,
|
||||
NACK/RTX, DTLS-SRTP, ICE, and TURN behavior on each edge. Electron is not part of
|
||||
the media experiment; it can only wrap a proven helper later.
|
||||
|
||||
## Minimal Risk Spike
|
||||
|
||||
```text
|
||||
existing Node signaling
|
||||
|
|
||||
Windows sender.exe
|
||||
synthetic source -> shared encoder coordinator -> encoder proxy A -> PC A -> browser A
|
||||
`--------> encoder proxy B -> PC B -> browser B
|
||||
```
|
||||
|
||||
- Windows x64, C++, video-only, fixed 720p30, and exactly two outgoing edges.
|
||||
- Inject a custom `VideoEncoderFactory` into libwebrtc. It returns two proxy
|
||||
encoders, one for each normal send pipeline.
|
||||
- Each proxy keeps its own `EncodedImageCallback`; one coordinator owns the
|
||||
physical counting encoder.
|
||||
- The coordinator deduplicates matching input-frame timestamps and publishes
|
||||
the same reference-counted encoded buffer to both callbacks.
|
||||
- Reject the second edge when codec, profile, dimensions, or layer configuration
|
||||
differ. Never hide incompatibility by creating a second physical encoder.
|
||||
- In this fixed single-layer spike, aggregate the two `SetRates()` requests by
|
||||
taking the minimum total target bitrate and minimum requested frame rate,
|
||||
bounded by the selected profile. Do not attempt to merge per-edge loss, RTT,
|
||||
bandwidth-allocation, or multilayer state. A weak edge can therefore lower
|
||||
quality for the strong edge; independent quality requires another encode or
|
||||
a separately accepted layered design.
|
||||
- Coalesce PLI/keyframe requests so one physical keyframe is delivered to both
|
||||
packetizers. RTP sequence numbers, SSRC, TWCC, pacing, retransmission caches,
|
||||
RTCP, DTLS-SRTP, and ICE remain independent per edge.
|
||||
|
||||
libwebrtc officially permits an application to inject a `VideoEncoderFactory`
|
||||
and defines `VideoEncoder::Encode`, `SetRates`, loss/RTT notifications, and the
|
||||
encoded callback. It does **not** promise cross-PeerConnection shared encoding.
|
||||
The proxy/coordinator design is therefore an inference that this spike must
|
||||
validate, not a supported feature claim.
|
||||
|
||||
Stop the libwebrtc route if two send pipelines produce incompatible cadence,
|
||||
timestamps, adaptation, or callback behavior and correctness would require a
|
||||
fork of `VideoStreamEncoder`, `RtpVideoSender`, or another libwebrtc internal.
|
||||
Do not carry a permanent media-engine fork for this feature.
|
||||
|
||||
## Capture And Hardware Encoding Come Later
|
||||
|
||||
Only after the synthetic two-edge property passes:
|
||||
|
||||
1. Capture a window or display with Windows Graphics Capture into a D3D11
|
||||
surface.
|
||||
2. Convert BGRA to NV12 once. Do not claim zero-copy until profiling proves the
|
||||
actual texture path.
|
||||
3. Enumerate hardware Media Foundation H.264 encoders with `MFTEnumEx` and
|
||||
`MFT_ENUM_FLAG_HARDWARE`, then probe every required input/output type and
|
||||
`ICodecAPI` control. Enumeration alone is not a capability guarantee.
|
||||
4. Require proven support for low-latency operation, runtime bitrate control,
|
||||
and explicit keyframe requests; reject that adapter instead of silently
|
||||
weakening the contract when a property is unavailable or read-only.
|
||||
5. Request one H.264 Constrained Baseline, packetization-mode 1 stream, then
|
||||
inspect the emitted SPS and negotiated `profile-level-id` before accepting
|
||||
the path. Browser baseline interoperability does not guarantee a particular
|
||||
hardware MFT or 1080p60; test every target GPU/browser combination.
|
||||
|
||||
Audio, per-process WASAPI capture, WGC/DDA fallback, source selection, Electron,
|
||||
installers, updating, and cross-platform abstractions stay outside the first
|
||||
spike.
|
||||
|
||||
## Pion Fallback
|
||||
|
||||
Pion is the fallback when public libwebrtc encoder APIs cannot satisfy the
|
||||
shared property without internal changes. `TrackLocalStaticSample` owns one
|
||||
packetizer and writes through a `TrackLocalStaticRTP` that can bind to multiple
|
||||
PeerConnections, making encoded-payload fanout explicit.
|
||||
|
||||
This certainty moves more responsibility into the application. Pion's default
|
||||
interceptors provide NACK, RTCP reports, statistics, and transport-wide feedback,
|
||||
but an external encoder still needs explicit send-side bandwidth estimation,
|
||||
aggregation of both edge targets, encoder bitrate control, PLI handling, and
|
||||
bounded RTP/RTX queues. A Pion route must use the same minimum-edge rate rule and
|
||||
must not invent a custom SRTP, ICE, or congestion protocol.
|
||||
|
||||
## Acceptance And Failure Gates
|
||||
|
||||
- Two current unmodified browsers decode continuously.
|
||||
- Unique physical encode calls equal unique input frames, not twice that count.
|
||||
- Direct and TURN edges can coexist; rebuilding one edge does not create a
|
||||
second physical encoder or interrupt the other edge.
|
||||
- Limiting one edge lowers the common encoder target without an unbounded pacer
|
||||
queue; removing that weak edge lets the remaining target recover.
|
||||
- One viewer's PLI produces one physical keyframe and both viewers recover.
|
||||
- Measurements include encode count/time, target and actual bitrate, PLI/NACK,
|
||||
RTT/loss, queue growth, CPU, GPU, and host upload.
|
||||
|
||||
Reject a libwebrtc fork, deprecated internal-source encoder APIs, SVC/simulcast,
|
||||
a second codec, FFmpeg/x264, a third host edge, custom RTP/SRTP or congestion
|
||||
control, automatic topology switching, audio, UI, and packaging in the risk
|
||||
spike. These are separate decisions after the shared property is proven.
|
||||
|
||||
## Primary Sources And License Boundary
|
||||
|
||||
- [libwebrtc PeerConnection factory injection](https://webrtc.googlesource.com/src/+/refs/heads/main/api/create_peerconnection_factory.h)
|
||||
- [libwebrtc VideoEncoder API](https://webrtc.googlesource.com/src/+/refs/heads/main/api/video_codecs/video_encoder.h)
|
||||
- [libwebrtc license](https://webrtc.googlesource.com/src/+/refs/heads/main/LICENSE)
|
||||
and [PATENTS](https://webrtc.googlesource.com/src/+/refs/heads/main/PATENTS)
|
||||
- [Windows Graphics Capture](https://learn.microsoft.com/en-us/windows/apps/develop/media-authoring-processing/screen-capture)
|
||||
- [Media Foundation `MFTEnumEx`](https://learn.microsoft.com/en-us/windows/win32/api/mfapi/nf-mfapi-mftenumex)
|
||||
- [Media Foundation `ICodecAPI::IsSupported`](https://learn.microsoft.com/en-us/windows/win32/api/icodecapi/nf-icodecapi-icodecapi-issupported)
|
||||
and [`IsModifiable`](https://learn.microsoft.com/en-us/windows/win32/api/icodecapi/nf-icodecapi-icodecapi-ismodifiable)
|
||||
- [Media Foundation H.264 encoder](https://learn.microsoft.com/en-us/windows/win32/medfound/h-264-video-encoder)
|
||||
- [Media Foundation low-latency codec property](https://learn.microsoft.com/en-us/windows/win32/medfound/codecapi-avlowlatencymode)
|
||||
- [Media Foundation force-keyframe property](https://learn.microsoft.com/en-us/windows/win32/medfound/codecapi-avencvideoforcekeyframe)
|
||||
- [WebRTC video codec requirements, RFC 7742](https://www.rfc-editor.org/rfc/rfc7742.html)
|
||||
- [WebRTC congestion control requirements, RFC 8836](https://www.rfc-editor.org/rfc/rfc8836.html)
|
||||
- [Pion track fanout implementation](https://github.com/pion/webrtc/blob/main/track_local_static.go)
|
||||
- [Pion send-side bandwidth estimator](https://github.com/pion/interceptor/blob/main/pkg/gcc/send_side_bwe.go)
|
||||
- [Pion WebRTC license](https://github.com/pion/webrtc/blob/main/LICENSE)
|
||||
- [Electron desktop capture](https://www.electronjs.org/docs/latest/api/desktop-capturer/)
|
||||
|
||||
libwebrtc uses a BSD-style license and Pion uses MIT, but distribution still
|
||||
requires a full libwebrtc third-party notice review and an H.264 patent/licensing
|
||||
review. No source code from these projects was copied into Screener.
|
||||
@@ -129,21 +129,21 @@ sending the result directly to viewers. This removes repeated encoding and
|
||||
memory cost, but it does not remove one network copy per viewer. It therefore
|
||||
does not satisfy a hard host fanout of two by itself.
|
||||
|
||||
A planned native Screener sender can preserve standard browser receivers without
|
||||
writing a new transport. libwebrtc accepts an application-supplied
|
||||
`VideoEncoderFactory`; a factory can return per-send-stream proxy encoders
|
||||
backed by one shared hardware encoder and fan the resulting `EncodedImage` into
|
||||
each stream's `EncodedImageCallback`. libwebrtc can then retain independent RTP
|
||||
A candidate native Screener sender could preserve standard browser receivers
|
||||
without writing a new transport. libwebrtc accepts an application-supplied
|
||||
`VideoEncoderFactory`, which creates a possible boundary for per-stream proxy
|
||||
encoders backed by one shared hardware encoder. If the bounded spike proves the
|
||||
callback and adaptation contract, libwebrtc could retain independent RTP
|
||||
sequence numbers, packetization, SRTP, RTCP, NACK/RTX, ICE, and congestion state
|
||||
for the two host edges.
|
||||
|
||||
This is an engineering inference from the native interfaces, not a ready-made
|
||||
libwebrtc feature. The coordinator must deduplicate input frames, reconcile
|
||||
independent rate requests, combine keyframe requests, preserve timestamps, and
|
||||
require one common codec/profile/resolution/layer. It is high-complexity native
|
||||
work, but it is the viable long-term way to **guarantee** one host encode while
|
||||
keeping normal browser first-hop receivers. Browser JavaScript cannot provide
|
||||
that guarantee.
|
||||
require one common codec/profile/resolution/layer. The separate bounded risk
|
||||
spike must prove whether this route can guarantee one host encode while keeping
|
||||
normal browser first-hop receivers; requiring a libwebrtc internal fork rejects
|
||||
the route. Browser JavaScript cannot provide that guarantee.
|
||||
|
||||
Sources:
|
||||
|
||||
@@ -208,6 +208,15 @@ and RTP sender parameters remain targets, so achieved bitrate, frame rate,
|
||||
resolution, encode work, and cross-hop quality still require the measurement
|
||||
matrix below. It does not add or imply shared encoding.
|
||||
|
||||
A controlled Chromium 151 loopback smoke used one host, three viewers, and a
|
||||
synthetic 640x360/30 source. The downstream relay kept the same peer, sender,
|
||||
and signaling generations while its configured ceilings changed from
|
||||
8 Mbps/60 fps to 5 Mbps/30 fps and then 3 Mbps/30 fps. Each real
|
||||
`setParameters()` call and both host `applyConstraints()` calls succeeded, and
|
||||
the leaf kept decoding. This verifies wire ordering, relay propagation, and
|
||||
connection preservation only. It does not verify 1080p output, visual quality,
|
||||
CPU/GPU cost, TURN, public networks, or endurance.
|
||||
|
||||
Peer multicast research such as SplitStream demonstrates why load-balanced,
|
||||
failure-tolerant overlays normally introduce multiple trees and content
|
||||
striping. Those mechanisms are intentionally excluded: needing them is a reason
|
||||
@@ -273,6 +282,14 @@ and relay upload, packets lost, jitter, frames encoded/decoded/dropped, total
|
||||
encode/decode time, decoded FPS, `qualityLimitationReason`, first picture,
|
||||
reparent time, CPU, GPU, and glass-to-glass latency.
|
||||
|
||||
The in-app per-frame encode/decode fields use adjacent `getStats()` counter
|
||||
deltas and skip a tick while the same connection already has a sample in
|
||||
flight. A first sample, zero-frame interval, changed stats object, or counter
|
||||
reset reports unknown and rebases; a connection-lifetime average is not
|
||||
accepted as relay-load evidence. Long-run percentiles and event timing still
|
||||
come from a tracked run manifest plus browser WebRTC diagnostics, not a new
|
||||
telemetry service.
|
||||
|
||||
All hard gates must pass:
|
||||
|
||||
1. The host has no more than two outgoing media edges and every viewer has no
|
||||
|
||||
@@ -80,6 +80,13 @@ resolution, frame rate, or bitrate.
|
||||
- Pausing the picture disables the existing video track, producing black video
|
||||
without closing the room or media connection. Audio remains enabled.
|
||||
|
||||
A Chromium 151 loopback smoke with one host, three viewers, and a synthetic
|
||||
640x360/30 source kept the same relay peer, sender, and signaling generations
|
||||
while applying 8 Mbps/60 fps, 5 Mbps/30 fps, and 3 Mbps/30 fps sender ceilings.
|
||||
The leaf continued decoding after both live switches. This verifies control
|
||||
propagation and connection preservation, not actual 1080p output, visual
|
||||
quality, CPU/GPU cost, public-network behavior, or sustained performance.
|
||||
|
||||
## Deliberate Non-Goals
|
||||
|
||||
- No canvas pixel-difference detector, machine-learned rate controller, or
|
||||
@@ -99,6 +106,15 @@ dropped frames, RTT, packet loss, and host CPU/GPU utilization. A live profile
|
||||
change must preserve peer connection IDs, avoid a second source prompt, and
|
||||
visibly converge to the requested bounds.
|
||||
|
||||
Compute per-frame encode and decode cost from adjacent samples of cumulative
|
||||
`totalEncodeTime`/`totalDecodeTime` and frame counters. The first sample, a
|
||||
zero-frame interval, changed stats object, or a counter reset is unknown and
|
||||
establishes a new baseline. Skip overlapping sampling ticks on the same peer so
|
||||
reports cannot complete out of order. Do not use a connection-lifetime average
|
||||
to judge a later overload. Use browser WebRTC diagnostics plus a small run
|
||||
manifest for time series and percentiles rather than adding a server telemetry
|
||||
pipeline.
|
||||
|
||||
Compare image readability and motion continuity instead of declaring success
|
||||
from FPS alone. If reproducible evidence later shows that `balanced` still
|
||||
oscillates or makes the wrong tradeoff on supported machines, revise the fixed
|
||||
|
||||
+9
-11
@@ -4,10 +4,9 @@ Last updated: 2026-08-19
|
||||
|
||||
## Phase
|
||||
|
||||
The WebRTC proof of concept is deployed at `https://share.bonfire.icu`. Commit
|
||||
`5b2fb005f6f7` adds live 1080p60/1080p30/720p30 quality changes, video-only
|
||||
pause, clearer connection states, protected SQLite persistence, sequential room
|
||||
IDs, reusable links, and a waiting state after sharing stops. Production room ID
|
||||
The WebRTC proof of concept is deployed at `https://share.bonfire.icu` on commit
|
||||
`5b2fb005f6f7`. It supports live quality/source changes, video-only pause,
|
||||
protected SQLite persistence, sequential room IDs, and reusable links; room ID
|
||||
`1` survived the deployment restart.
|
||||
|
||||
Production still uses one host `RTCPeerConnection` per viewer. Draft PR #13 adds
|
||||
@@ -21,8 +20,6 @@ Draft SFU PR #12 is also unmerged and undeployed.
|
||||
|
||||
## Current Snapshot
|
||||
|
||||
- Product scope is private game sharing for one broadcaster and a small trusted friend group; public broadcasting remains out of scope.
|
||||
- Runtime is Node.js 24, React, TypeScript, Vite, native browser WebRTC, `ws`, Zod, Vitest, and a separate coturn deployment.
|
||||
- Capture precedes room creation. Live source and quality changes preserve healthy peers; picture pause keeps audio and connections active. `contentHint = "motion"` and explicit `balanced` degradation do not guarantee resolution-first behavior.
|
||||
- Whole-site `ACCESS_PASSWORD` is optional. Protected sessions use a stateless 12-hour HMAC HttpOnly `SameSite=Strict` cookie; host authentication remains internal and signaling is role-bound.
|
||||
- Without `ROOM_DATABASE_PATH`, rooms are random and temporary. With both the database path and site password, room IDs start at `1`, links persist, and stopping a share leaves viewers waiting. SQLite stores only room ID and host-token digest.
|
||||
@@ -32,18 +29,19 @@ Draft SFU PR #12 is also unmerged and undeployed.
|
||||
|
||||
## Verified Evidence
|
||||
|
||||
- Production release `5b2fb005f6f7` passed type checking, 108 Vitest tests, both production builds, loopback smoke, public HTTPS/access-gate checks, and clean activation under `/opt/screener/current`. The new 1080p30 asset loaded, Screener had zero automatic restarts, and nginx, coturn, and the existing blog remained healthy.
|
||||
- Production release `5b2fb005f6f7` passed type checking, 108 tests, both builds, loopback/public HTTPS and access-gate checks, and clean activation without disturbing nginx, coturn, or the blog.
|
||||
- The protected production database and permissions survived restart, and room ID `1` remained present. Stop-and-republish and link reuse still require a browser cycle.
|
||||
- The recorded peer-assisted full check passes type checking, 12 Vitest files with 141 tests, and both client and server production builds.
|
||||
- The recorded peer-assisted full check passes type checking, 12 Vitest files with 144 tests, and both production builds.
|
||||
- Chromium 151 one-to-three evidence held exactly two connected host outbound peers. Viewer 1 held one inbound plus one outbound peer and forwarded to viewer 3; viewer 2 stayed direct; all three decoded frames.
|
||||
- A Chromium 151 one-to-three loopback smoke kept the same relay peer, sender, and signaling generations through 8 Mbps/60, 5 Mbps/30, and 3 Mbps/30 ceilings; calls succeeded and the leaf kept decoding. Its synthetic 640x360/30 source proves propagation and connection preservation, not 1080p quality or load.
|
||||
- A Chromium 151 one-to-eight synthetic functional smoke formed two depth-four chains. The host held two outbound peers; viewers 1 through 6 each held one inbound plus one outbound; viewers 7 and 8 were leaves; all decoded frames. This proves topology only, not quality, resource cost, latency, or endurance.
|
||||
- Closing the first-level relay caused its branch to reattach and decode again after about 5.3 seconds while host active connected outbound edges peaked at two.
|
||||
- Local WebRTC diagnostics derive per-frame encode/decode cost from adjacent non-overlapping `getStats()` samples. First, empty, changed-stream, and reset intervals stay unknown and rebase instead of publishing a misleading lifetime average.
|
||||
- Production HTTPS/WSS, access cookie, room/WebSocket authorization, certificate renewal, public STUN, and authenticated TURN/UDP and TURN/TCP relay-only bidirectional paths are verified. TURN/TLS is intentionally disabled.
|
||||
- Headless Chromium 151 synthetic checks cover direct UDP media, offer/answer/create-offer recovery, generation isolation, live video/audio replacement, quality parameter updates, and video-only pause. Layout checks used actual inner widths 500, 781, and 820 px; a true 390 px viewport remains unverified.
|
||||
|
||||
## Unverified Boundaries
|
||||
|
||||
- Room profile propagation is implemented, replacing the fixed relay `1080p60` envelope. Actual cross-hop resolution, bitrate, frame rate, encode cost, and generational quality under each profile remain unverified.
|
||||
- Room profile propagation and live sender-ceiling changes are verified on the synthetic loopback path. Actual full-resolution cross-hop output, sustained bitrate and frame rate, encode cost, visual quality, and heterogeneous-network behavior under each profile remain unverified.
|
||||
- Peer assistance has not completed 1/3/5/8-viewer 30-minute runs, relay CPU/GPU and generational-quality measurements, controlled loss/RTT tests, or depth-four latency gates.
|
||||
- Android Chrome and iOS Safari remain required leaves but are not verified for this topology. There is no runtime relay-capability bit; controlled join order is the only mobile-leaf enforcement, so arbitrary-user deployment is excluded.
|
||||
- The observed recovery starts from a page close immediately seen by the server. A silent partition can wait 30 to 60 seconds for heartbeat detection before the default 5-second grace; it remains unverified.
|
||||
@@ -55,7 +53,7 @@ Draft SFU PR #12 is also unmerged and undeployed.
|
||||
Complete only the bounded ADR-0004 experiment, with distribution work ahead of
|
||||
UI polish:
|
||||
|
||||
- validate authentication, live switching, stream replacement, and child rebuild against the latest room profile in real browsers;
|
||||
- repeat live switching with full-resolution high-motion capture, then validate stream replacement, stop/restart, child rebuild, reparenting, and signaling interruption against the latest room profile in real browsers;
|
||||
- preserve host fanout at two and viewer fanout at one across joins, reconnects, grace expiry, and reparenting;
|
||||
- run reproducible 1/3/5/8-viewer measurements using the deployed profiles, recording topology depth, selected ICE path, host/relay upload, encode/decode work, first picture, decoded FPS, quality limitation, and glass-to-glass latency;
|
||||
- repeat first-level relay loss with a server-observed close and separately measure silent heartbeat-detected partition recovery; and
|
||||
|
||||
+1
-1
@@ -176,7 +176,7 @@ TURN/TLS 是可选能力,不是生产启动门槛。启用时默认使用 RFC
|
||||
- 本地 relay candidate 的 `relayProtocol`;规范禁止远端 candidate 暴露该字段,因此不推断远端使用 TURN/UDP、TCP 还是 TLS;
|
||||
- `currentRoundTripTime`、发送码率和 `availableOutgoingBitrate`;
|
||||
- 实际帧率、分辨率和丢包;
|
||||
- codec、编码实现、每帧平均编码耗时和 `qualityLimitationReason`。
|
||||
- codec、编码实现、最近采样区间内的每帧编解码耗时和 `qualityLimitationReason`;同一连接不并发采样,首个样本、无新帧、统计对象换代或计数器重置时显示未知并重新建立基线,不用连接生命周期均值掩盖后续过载。
|
||||
|
||||
观看者显示接收码率、帧率、分辨率、丢包、jitter、解码/丢帧和当前路径。字段不可用时显示“未知”。RTT 只标为网络往返时间,不能冒充玻璃到玻璃延迟。
|
||||
|
||||
|
||||
Reference in new issue
Block a user