docs(quality): accept single-high SFU representation (#247)
This commit is contained in:
1 parent
30594107f0
commit
3cc858477b
13 files changed
+191
-373
No files matched your search
+2
-2
@@ -17,7 +17,7 @@
|
||||
- [Native shared-encode sender](./research/native-shared-encode-sender.md): consolidated Draft #16/#18/#22/#23/#25/#28 ladder, unclassified product-gate failure, staged revalidation, and stop line.
|
||||
- [Native H.264 hardware decision](./research/native-h264-hardware-decision.md): bounded WebCodecs no-go, proved Media Foundation/NVIDIA hardware encode, the default-fmtp `42c01f` stop, and the retained interop boundary.
|
||||
- [Native H.264 opt-in path](./research/native-h264-opt-in-path.md): explicit H.264 sender mode, exact Pion profile registration, and one bounded Host/Viewer loopback with hardware caveats.
|
||||
- [Realtime quality adaptation](./research/realtime-quality-adaptation.md): fixed Browser VP8/no-video-hint evidence, manual quality ceilings, diagnostic-only capture/send/receive correlation, path-isolated dual representations, and bounded simulcast/Dynacast/SVC checks.
|
||||
- [Realtime quality adaptation](./research/realtime-quality-adaptation.md): fixed Browser VP8/no-video-hint evidence, manual quality ceilings, diagnostic-only capture/send/receive correlation, the single-`HIGH` decision, and rejected dual/SVC evidence.
|
||||
- [Browser background capture diagnostics](./research/browser-background-capture.md): browser lifecycle evidence, a privacy-bounded capture/send/receive experiment, interpretation gates, and non-goal keepalive mechanisms.
|
||||
- [Browser screen-audio quality](./research/browser-screen-audio-quality.md): capture/source compatibility, live sender-ceiling readback, Opus negotiation boundaries, and remaining audible/device evidence.
|
||||
- [Display name and presence boundaries](./research/display-name-presence.md): browser-local storage failure behavior, Unicode normalization, control-character policy, and the Web-only presence capability boundary.
|
||||
@@ -27,7 +27,7 @@
|
||||
- [ADR-0004](./adr/0004-peer-assisted-media-experiment.md): historical standard-WebRTC peer-assisted experiment and reusable evidence.
|
||||
- [ADR-0005](./adr/0005-automatic-hybrid-media-routing.md): accepted P2P-first single-reconcile route model, including deployed Browser SFU ICE-server isolation; remaining real-network validation is tracked in verification status.
|
||||
- [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-0007](./adr/0007-path-isolated-representation-quality.md): accepted path-isolated single-`HIGH` Browser SFU representation, evidence contract, and rejected dual/SVC boundaries.
|
||||
- [ADR-0008](./adr/0008-window-scoped-audio-capture.md): browser window-audio hint and the Windows WASAPI process-loopback boundary.
|
||||
|
||||
Documentation and project memory are part of the product source of truth. Update them in the same change that alters the corresponding requirement or architecture.
|
||||
@@ -195,10 +195,11 @@ pass.
|
||||
ADR-0006 records a bounded candidate and its failed first product gate, not an
|
||||
accepted architecture or shipped sender. The deployed Web sender and ordinary
|
||||
viewer remain unchanged. ADR-0007 continues to own path-isolated
|
||||
`HIGH + at most one LOW`; this canary cannot advance or replace it.
|
||||
representations; the current Browser SFU contract is one `HIGH`, and this canary
|
||||
cannot advance or replace it.
|
||||
|
||||
## References
|
||||
|
||||
- `docs/research/native-shared-encode-sender.md`
|
||||
- `docs/adr/0007-demand-driven-dual-representation-quality.md`
|
||||
- `docs/adr/0007-path-isolated-representation-quality.md`
|
||||
- `docs/research/browser-screen-audio-quality.md`
|
||||
+71
-102
@@ -1,7 +1,8 @@
|
||||
# ADR-0007: Path-Isolated Dual-Representation Quality
|
||||
# ADR-0007: Path-Isolated Representation Quality
|
||||
|
||||
- Status: Accepted quality/representation decision; topology capacity follows ADR-0005
|
||||
- Date: 2026-08-19
|
||||
- Last reviewed: 2026-08-25
|
||||
|
||||
## Context
|
||||
|
||||
@@ -21,35 +22,32 @@ relay/SFU. Per-viewer encoders would violate the game's performance budget.
|
||||
|
||||
## Decision
|
||||
|
||||
Use path-isolated dual representations:
|
||||
Use path-isolated representations:
|
||||
|
||||
1. Direct/peer paths keep their requested `HIGH` target and independent stock
|
||||
WebRTC congestion control. No viewer feedback changes another path's target.
|
||||
2. Each SFU path starts with a `HIGH` ceiling. The preferred implementation
|
||||
publishes one shared `HIGH+LOW` pair and lets LiveKit BWE independently
|
||||
choose and recover the forwarded layer for each subscriber. If that gate
|
||||
passes, Screener does not add a media-layer selector.
|
||||
2. The Browser Host's single SFU publication sends one `HIGH` VP8
|
||||
representation. LiveKit/WebRTC independently controls each SFU downlink,
|
||||
but the application does not publish `LOW`, enable simulcast or Dynacast, or
|
||||
add a media-layer selector.
|
||||
3. Sender/viewer evidence diagnoses capture, encode, transport, receive, and
|
||||
decode behavior. It does not change topology or command ordinary built-in
|
||||
layer changes. ADR-0005 reacts only to an exact child edge's hard connection
|
||||
failure or non-paused decoded-frame stall.
|
||||
4. Explicit subscriber quality or sender layer activation is considered only
|
||||
if the built-in candidate fails its bounded gate. Deactivating an unused
|
||||
`LOW` is a resource optimization, not an acceptance requirement.
|
||||
5. The active representation/layer count is a hard `HIGH + at most one LOW <=
|
||||
2`; it never grows with viewer count.
|
||||
4. A future dual-representation Browser path requires a new accepted decision
|
||||
and physical evidence that the additional representation does not reduce
|
||||
`HIGH`, game performance, or the Host-to-SFU upload budget.
|
||||
5. The accepted Browser representation count is exactly one and never grows
|
||||
with Viewer count.
|
||||
|
||||
Making `LOW` available is conditional on positive hardware-encoder evidence and
|
||||
measured spare game-performance and upload budget. A permanently active
|
||||
two-representation path is acceptable when that gate passes; stopping unused
|
||||
`LOW` remains a later optimization. If the hardware path is absent or the
|
||||
additional representation causes unacceptable CPU/GPU/game/upload cost, fail
|
||||
closed for that attempt: preserve `HIGH` and show the weak path an explicit
|
||||
degraded/unavailable state. This is exceptional damage containment, not
|
||||
permission to ignore a weak path indefinitely. A supported sender cohort that
|
||||
cannot reliably provide the one shared `LOW`, either always-on or on demand,
|
||||
fails quality acceptance; optimize its encode path or mark
|
||||
that cohort unsupported. Never protect a weak path by reducing `HIGH`.
|
||||
The pinned two-layer LiveKit candidate failed this gate. On exact production,
|
||||
an always-active `LOW` consumed the same Host-to-SFU congestion budget and
|
||||
reduced the progressing 1904x928 `HIGH` stream from about 23 fps to about 9 fps
|
||||
under the measured public path. `LOW` therefore cannot remain active, and the
|
||||
current Browser contract preserves only `HIGH`. A constrained SFU ingress may
|
||||
still emit fewer frames because sender ceilings are not guarantees; that is a
|
||||
stock WebRTC result, not authority to restore `LOW`, change routes, or add a
|
||||
custom controller.
|
||||
|
||||
There is no weighted score, device ranking, machine-learning controller, custom
|
||||
media selector, or continuous room-wide optimizer. Representation evidence does
|
||||
@@ -63,11 +61,11 @@ encoded packets without decoding or re-encoding. Future dual-tree or striped
|
||||
delivery may reduce host upload from about two full copies toward one copy plus
|
||||
necessary redundancy, but it does not block this decision.
|
||||
|
||||
LiveKit may downshift an SFU subscription before the application observes it.
|
||||
That is normal per-subscriber adaptation and does not alter relay eligibility.
|
||||
With one encoded representation, LiveKit may adapt an SFU downlink but cannot
|
||||
create a second spatial representation. That does not alter relay eligibility.
|
||||
If the exact ingress later hard-fails or stops decoding while unpaused,
|
||||
ADR-0005 reparents that Viewer as a child and retains its subtree. A viewer's
|
||||
advisory quality request cannot trigger route mutation by itself.
|
||||
ADR-0005 reparents that Viewer as a child and retains its subtree. Viewer
|
||||
quality evidence cannot trigger route mutation or publication changes.
|
||||
|
||||
## Evidence Contract
|
||||
|
||||
@@ -104,10 +102,8 @@ stats, candidate addresses, or raw device/network identifiers. Opaque
|
||||
server-issued path and connection IDs authorize diagnostic correlation only.
|
||||
Do not build a general telemetry schema.
|
||||
|
||||
A viewer may request `LOW`, but the request is advisory. It must be carried on
|
||||
an authenticated, current room/path session and be rate-limited and deduplicated.
|
||||
It may be shown with matching sender/viewer diagnosis, but it cannot lower
|
||||
quality, start a representation, or change topology.
|
||||
Authenticated Viewer quality evidence may diagnose only its current path. It
|
||||
cannot lower Host quality, start another representation, or change topology.
|
||||
|
||||
UA, platform, and device-model detection does not participate in quality or
|
||||
relay-capacity selection. Browser capability queries can guide a bounded probe,
|
||||
@@ -133,50 +129,29 @@ results do not create an application media-layer selector or route authority:
|
||||
required product semantic is absent. In particular, the normative rule that
|
||||
`active=false` stops sending an encoding is not evidence that its physical
|
||||
encoder, CPU work, or GPU allocation is released.
|
||||
2. **Pinned LiveKit two-layer simulcast: implemented; acceptance remains open.**
|
||||
Client 2.22.0 can publish a screen-share original plus one lower simulcast
|
||||
encoding. `RemoteTrackPublication.setVideoQuality(HIGH)` sets a per-subscriber
|
||||
spatial-quality ceiling. Server 1.13.5 derives requested spatial/temporal
|
||||
maxima from quality, dimensions and FPS, but actual selection is
|
||||
codec-specific: VP8 has temporal selection, while H.264/H.265 simulcast is
|
||||
spatial-only. A VP8 publication can adapt each SFU downtrack between
|
||||
`q,h` spatial representations and recover it independently. Server
|
||||
Dynacast takes the maximum requested quality and enables every quality at or
|
||||
below it, so any `HIGH` root keeps `LOW` active. That cumulative behavior
|
||||
prevents dynamic `LOW` stop while `HIGH` is subscribed, but dynamic stop is
|
||||
now an optimization rather than a hard requirement.
|
||||
2. **Pinned LiveKit two-layer simulcast: rejected for the current Browser
|
||||
contract (`no-go-livekit-always-on-low`).** Client 2.22.0 can publish a
|
||||
screen-share original plus one lower simulcast encoding, but server 1.13.5
|
||||
Dynacast enables every quality at or below the highest requested quality.
|
||||
Any `HIGH` subscriber therefore keeps `LOW` active; turning Dynacast on does
|
||||
not isolate the Host-to-SFU congestion budget.
|
||||
|
||||
The candidate therefore publishes exactly `HIGH+LOW` with standard
|
||||
simulcast/send encodings, leaves each LiveKit root's ceiling at `HIGH`, and
|
||||
first tests built-in per-subscriber SFU bandwidth adaptation on
|
||||
zero-descendant leaf viewers. Start with deterministic two-layer publication
|
||||
and Dynacast off. Dynacast controls publisher-layer pausing from aggregated
|
||||
subscriber demand; disabling it does not disable server-side per-subscriber
|
||||
BWE or turn a `HIGH` ceiling into a guaranteed received layer. Its pinned
|
||||
cumulative behavior can later be measured as the equivalent always-on case.
|
||||
Screener's
|
||||
subscriber does not attach a `RemoteTrack`, so LiveKit `adaptiveStream` is not
|
||||
directly usable without changing that ownership; it is not required for the
|
||||
SFU bandwidth-adaptation candidate. A root with children uses the same
|
||||
built-in BWE; an automatic downshift does not mutate topology. If built-in selection
|
||||
fails the product gates, test explicit standard subscriber quality selection
|
||||
before sender activation/deactivation. The gate must prove that a healthy
|
||||
P2P/`HIGH` path is unchanged, no third layer appears, the expected layer is
|
||||
actually received, and hardware encoder, game FPS/p1 low, CPU/GPU, interval
|
||||
encode cost, host upload, and `HIGH+LOW` bytes fit budget. Every active SFU
|
||||
publication now configures exactly two ordered `q,h` encodings, constructs
|
||||
`Room({ dynacast: false })`, disables backup-codec publication, and sets each
|
||||
subscriber's ceiling to `HIGH`; the two-layer publication is not behind a
|
||||
separate quality flag. Client 2.22.0 also defaults Dynacast to `false`, but
|
||||
the explicit option prevents silent option drift and `backupCodec: false`
|
||||
prevents the pinned multi-codec path from enabling it automatically.
|
||||
The 2026-08-22 executable preflight verifies this configuration, retains a
|
||||
zero-child subscriber, and rejects excess central roots. Per-subscriber BWE,
|
||||
actual layer forwarding for leaves and relay roots, and hardware cost remain
|
||||
unverified, so no runtime performance claim follows. If the always-on
|
||||
cost fails, test manual standard sender activation/deactivation next;
|
||||
custom/native dual encoding follows only if built-in and manual standard
|
||||
primitives fail.
|
||||
The exact production gate used Chrome 151, runtime `bf32859`, a continuously
|
||||
changing 1904x928 capture, and the same public SFU path. With ordered `q,h`
|
||||
encodings active, the `h` stream stabilized near 9.2 fps and 1.37 Mbps. With
|
||||
`q` inactive from the first sender-parameter application, `h` stabilized near
|
||||
23.3 fps and 3.32 Mbps while encoding took about 4.46 ms per frame, packet
|
||||
loss and retransmission remained zero, and the selected pair reported about
|
||||
4.81 Mbps available outgoing bitrate. Source and capture remained near 60
|
||||
fps. The lower representation therefore consumed the shared ingress budget
|
||||
and materially reduced `HIGH`; the candidate fails the existing stop line.
|
||||
|
||||
The current Browser decision is one `HIGH` representation without simulcast,
|
||||
Dynacast, or a manual layer controller. The measured public `q`-inactive A/B
|
||||
remained bandwidth-constrained, so this verdict does not claim SFU 60 fps or
|
||||
replace the pending exact single-representation production gate.
|
||||
Reopening a dual/native representation is a new decision with new physical
|
||||
game, encoder, and upload evidence.
|
||||
3. **Current Web/LiveKit SVC: rejected
|
||||
(`no-go-web-svc-cross-path-hardware-contract`).** WebRTC-SVC adds
|
||||
`scalabilityMode` to sender encoding parameters, but it adds no receiver
|
||||
@@ -192,7 +167,7 @@ results do not create an application media-layer selector or route authority:
|
||||
Pinned LiveKit narrows the result further. Client 2.22.0 overwrites SVC
|
||||
screen-share publication to `L1T3`: one spatial resolution and three temporal
|
||||
layers, so it provides no low-resolution base and exceeds this product's
|
||||
two-active-layer ceiling. Its `RemoteTrackPublication.setVideoQuality()`
|
||||
current one-representation contract. Its `RemoteTrackPublication.setVideoQuality()`
|
||||
controls per-subscriber spatial quality, while server 1.13.5 maps
|
||||
quality/dimensions/FPS to requested spatial/temporal maxima. Actual selection
|
||||
remains codec-dependent: VP8 has a temporal selector, whereas H.264/H.265
|
||||
@@ -208,12 +183,13 @@ results do not create an application media-layer selector or route authority:
|
||||
media run, so no harness was written and no browser was run.
|
||||
|
||||
None may reuse PR #28's minimum-of-two target, bypass a per-edge stock WebRTC
|
||||
congestion controller, or expand the representation limit beyond two.
|
||||
congestion controller, or expand the current one-representation contract.
|
||||
|
||||
## SVC Static Verdict
|
||||
|
||||
This static verdict rejects current Web/LiveKit SVC, not the separate LiveKit
|
||||
two-layer simulcast candidate above. Requested and post-negotiation applied
|
||||
This static verdict rejects current Web/LiveKit SVC; the two-layer LiveKit
|
||||
simulcast candidate is independently rejected by its physical gate. Requested
|
||||
and post-negotiation applied
|
||||
`scalabilityMode` remain useful diagnostics, because the browser may apply a
|
||||
different mode or omit the field when none was requested. They are not proof
|
||||
of the actual hardware implementation, and neither a support query nor a
|
||||
@@ -233,18 +209,16 @@ decision, not completion of this browser spike.
|
||||
Positive:
|
||||
|
||||
- Healthy viewers are not reduced to the worst path.
|
||||
- One shared `LOW` is available to all SFU paths and LiveKit selects it per
|
||||
subscriber; its idle deactivation is allowed but not required. Physical
|
||||
encoder instances and resource cost remain measured outcomes.
|
||||
- Encode cost is bounded independently of viewer count.
|
||||
- Browser SFU uses one outbound `HIGH` representation, so publication and
|
||||
ingress cost stay bounded independently of Viewer count.
|
||||
- The diagnostic evidence remains inspectable.
|
||||
|
||||
Negative:
|
||||
|
||||
- An always-on `LOW` adds representation bandwidth and may require another
|
||||
physical encoder even without a weak path; the exact cost is an acceptance
|
||||
measurement, not an assumed negligible overhead.
|
||||
- Any later explicit quality/layer fallback needs a keyframe-safe transition.
|
||||
- A weak SFU downlink cannot select a separate low-resolution representation;
|
||||
stock congestion control may reduce bitrate, resolution, or encoded cadence.
|
||||
- A configured 60 fps ceiling is not a delivery guarantee on a constrained
|
||||
Host-to-SFU path.
|
||||
- Browser capability reporting cannot by itself prove hardware or sustained
|
||||
decode performance. The current SVC path is rejected before that matrix;
|
||||
custom/native candidates still require it.
|
||||
@@ -258,30 +232,25 @@ Negative:
|
||||
- Do not create one representation or encoder per viewer.
|
||||
- Do not use UA/device identity as a quality signal.
|
||||
- Do not enable software SVC as an invisible fallback.
|
||||
- Do not start or retain `LOW` when its measured hardware, game, or upload cost
|
||||
violates budget.
|
||||
- Do not publish `LOW` in the current Browser contract.
|
||||
- Do not add a composite health score or media selector when built-in adaptation
|
||||
and ADR-0005 edge recovery suffice.
|
||||
|
||||
## Verification Gates
|
||||
|
||||
- Direct/peer paths retain independent stock WebRTC congestion control. Each SFU
|
||||
path starts with a `HIGH` ceiling; under shaping, built-in LiveKit BWE sends a
|
||||
weak leaf the shared `LOW` while a healthy leaf stays `HIGH`, then restores the
|
||||
weak leaf without an application media selector.
|
||||
- An idle `LOW` may remain active only after hardware, game-performance, and
|
||||
upload cost passes. If idle stopping exists, verify bytes/frames stop;
|
||||
otherwise record and accept the bounded always-on cost.
|
||||
- Representation count never exceeds two. Host and relay endpoint media copies
|
||||
follow ADR-0005 steady capacity `C`; the two-edge result is only the bounded
|
||||
experiment configuration.
|
||||
- Direct/peer paths retain independent stock WebRTC congestion control.
|
||||
- An active Browser SFU publication exposes exactly one outbound video RTP
|
||||
encoding using VP8, with no `q,h` RID simulcast or second representation.
|
||||
- Host and relay endpoint media copies follow ADR-0005 steady capacity `C`;
|
||||
SFU publication accounting is unchanged by the representation decision.
|
||||
- Built-in BWE downshift and recovery remain local to each SFU subscription and
|
||||
do not change topology. Exact ingress failure is handled only by ADR-0005's
|
||||
generic child reparent operation.
|
||||
- An unavailable/over-budget `LOW` fails visibly for weak paths while healthy
|
||||
paths and `HIGH` remain unchanged.
|
||||
- Every supported sender cohort can reliably provide the one shared `LOW`,
|
||||
always-on or on demand; otherwise the quality gate does not pass.
|
||||
- Controlled exact-production evidence records source, capture, encode, send,
|
||||
receive, decode, render, selected transport, bitrate, loss, and encoder cost;
|
||||
it does not require 60 fps where the measured path cannot carry it.
|
||||
- No second representation sends frames or bytes, and a Viewer quality report
|
||||
cannot start one.
|
||||
- Native relays show packet forwarding without an added decode/encode stage.
|
||||
- Spoofed, stale, duplicated, or rate-excessive viewer requests have no effect.
|
||||
- Controlled capture/CPU/bandwidth/direct/SFU/receiver/display cases produce the
|
||||
@@ -289,7 +258,7 @@ Negative:
|
||||
|
||||
## References
|
||||
|
||||
Primary sources checked through 2026-08-22:
|
||||
Primary sources checked through 2026-08-25:
|
||||
|
||||
- [W3C WebRTC Statistics](https://www.w3.org/TR/webrtc-stats/)
|
||||
- [W3C Media Capture and Streams](https://www.w3.org/TR/mediacapture-streams/)
|
||||
@@ -17,6 +17,7 @@ Last updated: 2026-08-25
|
||||
- One Host publication may serve all SFU subscriptions. Its exact generation owns one ingress handle and exact Viewer subscription handles own egress; later SFU children reuse the publication, while reserved, committed, and draining handles remain charged until the managed room is deleted and proven absent. Actual SFU usage release wakes only rooms that previously lost a candidate to global admission, and SFU-fed and peer-fed endpoints use the same provisional-child transaction. Parent choice hard-filters authority, reachability, cycles, effective capacity, and producer transition, then orders by shallowest result, remaining steady sender capacity, stable join order, and peer identity; server admission is checked at the current cursor. Acyclicity and room admission bound maximum depth; depth is observed but has no separate hard cap. Healthy committed edges remain sticky: the controller repairs waiting, invalid, departed-parent, and overflow children but does not periodically rebalance the graph. Raw IP, claimed NAT type, UA, geography, all-pairs probes, weighted scores, and periodic room rebalancing are not route inputs.
|
||||
- Ordinary peer ICE is STUN-only. Browser LiveKit publisher and subscriber PCs use no external ICE server, retain LiveKit-signaled UDP candidates, and let standard ICE nominate a non-relay pair; deployment STUN remains available to ordinary peers and LiveKit server-side public-IP discovery. This Browser SFU ICE-server isolation avoids the reproduced external-STUN/SFU association conflict without constraining candidate type or count and without adding TURN, another route, a port, or a timeout. Credentials, room secrets, candidate details, and diagnostic data remain private and narrowly scoped. A future strict-firewall transport requires separate evidence and must remain inside LiveKit rather than becoming another Screener route candidate.
|
||||
- Browser peers use existing periodic WebRTC/LiveKit stats to maintain one exact-route decoded-progress timestamp. New frames or route/connection changes reset it; a non-paused deadline reports the edge once. Track availability, bitrate, FPS, resolution, freeze, RTT, jitter, loss, sender stats, and SFU layer describe only the current path: they remain framework or diagnostic inputs and cannot prove another parent would be better.
|
||||
- ADR-0007 accepts one Browser SFU VP8 `HIGH` representation without `LOW`, simulcast, Dynacast, or an application layer selector. Weak Viewers cannot change Host publication, healthy paths, or topology; dual representation requires a new decision and physical proof.
|
||||
- Browser capture requests available share audio by default on initial capture and source switch, with an explicit video-only warning when no audio track is returned. Its screen-audio control offers live-switchable 64/128/256 kbps sender ceilings and defaults to 128. The last-wins quality wire owns desired state; each endpoint serially applies and reads back current Host/relay/SFU audio senders, exposes local failures, and gives future senders the latest desired value. Opus remains fixed, and without an applied-ack wire the Host does not claim room-wide atomic convergence. These are configuration ceilings, not fidelity claims.
|
||||
- Browser display video leaves `contentHint` unset so Chromium retains its screen-capture classification; returned audio tracks keep `contentHint = "music"`. Browser video is fixed to VP8 across direct, browser-relay, and SFU paths; codec selection, fallback to another media codec, quality-state/wire fields, and share-lifetime codec branches are not product features. Actual codec/profile/encoder stats remain diagnostic only.
|
||||
- Recommended quality remains exactly `1080p60`, `1080p30`, and `720p30`, with the middle `1080p30` as the accepted default. `480p` means only an advanced `854x480` resolution choice whose FPS and bitrate remain independently selected; it is not a fourth recommended profile.
|
||||
@@ -32,14 +33,14 @@ Last updated: 2026-08-25
|
||||
- Current source and production admit up to `20` Viewers and implement the uniform `1/2/3` endpoint cap, exact prepare candidate, first-decoded-frame commit, strict rollback revision, decoded-progress stall, a two-stage direct/SFU operation deadline, and one event-driven room controller. A short-lived exact-generation decoded-frame observer proves only the pending candidate inside the existing total deadline; the periodic stats sampler remains responsible for active-path diagnostics and stalls. Ordinary peer ICE is STUN-only and the sole application fallback is SFU/UDP; stale TURN environment keys fail startup. SFU admission uses exact publication and Viewer-subscription handles with explicit no-default ingress/egress capacities and a listener-fenced dedicated LiveKit owner. Browser SFU publisher/subscriber connects use fresh empty ICE-server options; the owner physically verified deployed SFU fallback media after release `c4962f5`, closing the prior core-route hold.
|
||||
- Source and production use random four-digit memory rooms, dormant leases, exact-Host resume, restart loss, local preference replay, orthogonal grants/code entry, and no SQLite runtime. V12 uses a 22-character room-incarnation grant, `ROOM_NOT_FOUND`, no diagnostic-file export, and a compact UI showing the complete shorter URL.
|
||||
- Exact production artifacts, services, ports, and any change-scoped infrastructure recovery boundary are owned by [deployment](./deployment.md) and indexed by [status](./status.md).
|
||||
- Source and production require v12, fix Browser direct, browser-relay, and SFU media to VP8, leave video `contentHint` unset, and contain no codec UI, quality state, wire field, fallback media codec, or share-lifetime codec branch. They use `shareGeneration`-fenced Pause/Resume, implement live 64/128/256 kbps audio-ceiling mutation, bind Host and SFU publisher audio metrics to the exact current sender, reconcile relay audio-track changes on the persistent stream, and reacquire exact SFU publications/senders across reconnect. They keep typed first-frame Viewer presentation and expose exactly three recommended profiles with `1080p30` as default plus advanced-only `854x480`.
|
||||
- Source and production require v12, fixed VP8, and no video hint. Their SFU publisher still sends ordered `q,h` simulcast and is not yet aligned with accepted single `HIGH`. Current Pause/Resume, live audio ceilings, exact-sender metrics, relay/SFU audio continuity, typed Viewer presentation, and quality profiles match the product truths above.
|
||||
- Browser SFU subscribers reconcile eligible Host screen publications across connect/activate event ordering, participant/track arrival, and reconnect. Production LiveKit logs only warn/error, and the application service has a bounded same-host LiveKit readiness preflight.
|
||||
- Exact `main@bf32859` passed TypeScript, 613 Web tests in 44 files, both builds, repository hygiene, focused review, and production artifact/service postflight. Its Chrome 151 physical audio gate covered direct, browser-relay, SFU, all three sender ceilings, and source replacement; SFU A/V playout timestamps remained unavailable, so real-game synchronization stays in route acceptance.
|
||||
- Exact `main@bf32859` passed TypeScript, 613 Web tests, both builds, hygiene, review, and production postflight. Chrome 151 closed direct/browser-relay VP8 cadence and active-audio ceilings; its SFU A/B rejected always-active `LOW` without claiming a deployed single representation, public SFU 60 fps, or real-game synchronization. Exact metrics live in [verification status](./verification-status.md).
|
||||
- Chrome loopback, cap2/cap3, short resource, recovery, MBB, and A/V fixtures are bounded evidence only. They do not establish quality, resource limits, or product policy.
|
||||
|
||||
## Current Priority
|
||||
|
||||
1. Diagnose the reported localhost `1080p60` shortfall and physically validate exact direct, browser-relay, and SFU VP8/no-video-hint behavior on the deployed Browser release.
|
||||
1. Implement, deploy, and physically verify the accepted single-`HIGH` Browser SFU publication; leave direct, browser-relay, content-hint, and routing behavior unchanged.
|
||||
2. Then finish real-network route, recovery, screen-audio and real-game A/V acceptance. Browser VP8 hardware acceleration and mobile Viewer lifecycle remain Accepted Later; Native/executable, distribution, and repository-wide simplification remain later phases.
|
||||
|
||||
The desktop Host background/minimized report is deferred until it reproduces on current production with a real game and synchronized media plus CPU/GPU evidence. The bounded current-Chrome screening found no immediate Host-page lifecycle drop, and removal of the old harmful `contentHint = "motion"` remains a plausible confound rather than a proven background fix. Mobile Viewer playback and assigned-relay survival remain a separate lifecycle gate.
|
||||
|
||||
@@ -46,7 +46,7 @@ overhead. Protocol headers and retransmission overhead are additional.
|
||||
| Current full-stream browser chains | at most `2B` | zero on direct peer edges; SFU legs are accounted separately | host up to two encoders; every relay encodes again |
|
||||
| Native full-stream RTP relay | at most `2B` | zero on direct peer edges | relay zero encode; native host can share one encode |
|
||||
| Two encoded-object stripe trees | about `(1+r)B` | zero on direct peer edges | host one encode; relay zero encode |
|
||||
| Host publication with bounded SFU subscriptions | measured `B_pub` | per-subscriber egress; see low-server model | one publication may carry at most two active representations; physical encoder count remains measured evidence |
|
||||
| Host publication with bounded SFU subscriptions | measured `B_pub` | per-subscriber egress; see low-server model | current Browser publication carries one representation; dual representation requires a new decision and physical evidence |
|
||||
| Full central SFU/MoQ fanout | about `B` | ingress `B`, egress `N*B` | a possible bounded fallback result, never the default topology or mode |
|
||||
|
||||
Useful last-hop traffic remains approximately `N*B`; these routes only decide
|
||||
|
||||
@@ -254,19 +254,13 @@ conservative feedback-derived reconfiguration while feeding two transports. It
|
||||
does not establish heterogeneous feedback behavior and must not evolve into a
|
||||
room-wide minimum controller.
|
||||
|
||||
ADR-0007 keeps stock WebRTC GCC per direct/peer path. Each SFU path starts with
|
||||
a `HIGH` ceiling and built-in BWE selects from one shared `HIGH+LOW` pair. App
|
||||
evidence is diagnostic and does not select routes or ordinary layers. `LOW` may
|
||||
already be active, and idle stop depends on the resource
|
||||
gate. The active representation/layer limit is two, never one per viewer; the
|
||||
the host follows the configured non-server outbound media-copy capacity; the
|
||||
two-edge result in this experiment is a historical configuration, not a fixed
|
||||
policy.
|
||||
|
||||
If a qualified hardware/power-efficient `LOW` path is unavailable or its
|
||||
measured encoder/CPU/GPU game or upload load is unacceptable, `LOW` fails closed
|
||||
for weak paths while healthy paths keep `HIGH`. `LOW` may remain active when
|
||||
that measured budget passes; stopping it while idle is an optimization.
|
||||
ADR-0007 keeps stock WebRTC GCC per direct/peer path and accepts one Browser SFU
|
||||
`HIGH` representation. The exact-production gate rejected an always-active
|
||||
`LOW` because it reduced `HIGH` on the shared Host-to-SFU congestion budget.
|
||||
Application evidence remains diagnostic and does not select routes or layers.
|
||||
The Host still follows the configured non-server outbound media-copy capacity;
|
||||
the two-edge result in this experiment is a historical configuration, not a
|
||||
fixed policy.
|
||||
|
||||
The app does not derive topology eligibility from representation state. Viewer
|
||||
quality requests are authenticated, rate-limited, deduplicated diagnostic advice
|
||||
@@ -274,25 +268,18 @@ and do not form a composite score. UA and device identity do not participate.
|
||||
|
||||
A native relay forwards the selected encoded packets and must not decode or
|
||||
re-encode them. An ordinary non-scalable representation cannot be forwarded
|
||||
into a second quality; the bounded choices are a second encode, SVC, or
|
||||
transcoding. ADR-0007 statically closes current Web P2P simulcast and
|
||||
Web/LiveKit SVC as cross-path shortcuts, but keeps pinned LiveKit exactly-two
|
||||
simulcast with built-in SFU bandwidth adaptation as the priority runtime
|
||||
candidate. SFU BWE does not change topology. Explicit subscriber quality is next
|
||||
if built-in selection fails; manual sender activation follows if always-on cost
|
||||
fails; custom/native dual encode is last. A future native SVC decision may
|
||||
reopen only with an explicit hardware encoder contract, at most two decodable
|
||||
layers, one encoded
|
||||
output reused across direct/peer/SFU, independent path selection, and the real
|
||||
game/power matrix. Media Capabilities or RTCStats power-efficiency signals are
|
||||
diagnostics, not hardware proof; an unestablished path stays disabled rather
|
||||
than silently using software. Future dual-tree/striped distribution may reduce
|
||||
two-copy host upload toward one copy plus redundancy, but does not block
|
||||
dual-representation work.
|
||||
into a second quality; doing so would require another encode, scalable layers,
|
||||
or transcoding. ADR-0007 closes current Web P2P simulcast, Browser dual
|
||||
representation, and Web/LiveKit SVC. A future native decision may reopen a
|
||||
second representation only with an explicit hardware contract, bounded layer
|
||||
count, one encoded output reused across accepted transports, independent path
|
||||
selection, and the real game/power matrix. Media Capabilities and RTCStats
|
||||
power-efficiency fields remain diagnostics, not hardware proof.
|
||||
|
||||
Simulcast does not change this native proof boundary: one sender may negotiate
|
||||
`HIGH`/`LOW`, but separate direct PeerConnections have no portable shared-encode
|
||||
contract and inactive API state is not physical resource proof. ADR-0007 and
|
||||
multiple representations, but separate direct PeerConnections have no portable
|
||||
shared-encode contract and inactive API state is not physical resource proof.
|
||||
ADR-0007 and
|
||||
[Realtime Quality Adaptation](./realtime-quality-adaptation.md) own the
|
||||
static standard-path results and any future native reopen gate. This path still
|
||||
requires measured per-representation traffic/resources and cannot bypass #28's
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
# Realtime Screen-Share Quality Adaptation
|
||||
|
||||
- Research date: 2026-08-24
|
||||
- Research date: 2026-08-25
|
||||
- Scope: realtime game screen sharing in the browser
|
||||
- Status: implementation input; real-device quality remains unverified
|
||||
- Status: exact-production Browser gate completed; real-game and heterogeneous-device quality remain unverified
|
||||
|
||||
## Finding
|
||||
|
||||
@@ -12,9 +12,9 @@ game UI, maps, subtitles, and text become unreadable; `maintain-resolution`
|
||||
may instead lower frame rate. Neither preference overrides congestion control.
|
||||
|
||||
Production runs exact deployed application/runtime revision
|
||||
`c4962f54443ad5f98bc65861195a3d9c74a48996`, release `c4962f5`; canonical
|
||||
`bf328590b3de5dfa509fcc70f6316286af3eae7e`, release `bf32859`; canonical
|
||||
`main` contains the same runtime code. Current Browser source and production use
|
||||
strict `screener-v11`, fixed VP8, no video `contentHint`, and no codec UI,
|
||||
strict `screener-v12`, fixed VP8, no video `contentHint`, and no codec UI,
|
||||
quality state, or wire field. They use `balanced` as the recommended profile
|
||||
and advanced default;
|
||||
`maintain-resolution` and `maintain-framerate` remain explicit choices. These
|
||||
@@ -37,6 +37,30 @@ on 2024-05-22; the commit says it had already been disabled for several years
|
||||
and was not maintained. Current Chromium behavior must therefore not be
|
||||
described as automatically detecting game motion and forcing a 720p cap.
|
||||
|
||||
## 2026-08-25 Exact-Production VP8 Gate
|
||||
|
||||
Chrome 151 exercised exact production `bf32859` with real `getDisplayMedia()`, a
|
||||
continuously changing source, separate Browser processes, VP8/libvpx, and no
|
||||
video content hint. The direct path stabilized near 59.5 encoded, received,
|
||||
decoded, and rendered fps at 1904x928 and about 7.5 Mbps. A Browser relay kept
|
||||
every stage near 59.4--59.7 fps; its outbound adapted to 1428x696 under the
|
||||
available bandwidth without losing frame cadence. Both paths needed about
|
||||
25--30 seconds for stock bandwidth-estimation ramp-up. This closes the reported
|
||||
intrinsic VP8/no-hint localhost 60 fps shortfall; sender ceilings are not startup
|
||||
or delivery guarantees, and no application start-bitrate hack follows.
|
||||
|
||||
The exact SFU path isolated a different issue. With the current ordered `q,h`
|
||||
publication, the 1904x928 `h` stream stabilized near 9.2 fps and 1.37 Mbps. With
|
||||
`q` inactive from the first sender-parameter application, the otherwise
|
||||
unchanged `h` stream reached about 23.3 fps and 3.32 Mbps. Source/capture stayed
|
||||
near 60 fps, encode cost was about 4.46 ms per frame, packet loss and
|
||||
retransmission were zero, and the selected pair reported about 4.81 Mbps
|
||||
available outgoing bitrate. The always-active lower representation therefore
|
||||
consumed the same Host-to-SFU congestion budget and materially reduced `HIGH`.
|
||||
ADR-0007 rejects that candidate and accepts one Browser SFU `HIGH`
|
||||
representation. The public SFU ingress remained constrained, so this gate does
|
||||
not claim SFU 60 fps or real-game performance.
|
||||
|
||||
## Route Quality Authority
|
||||
|
||||
Current-path WebRTC stats can diagnose loss, RTT, jitter, bitrate, resolution,
|
||||
@@ -147,16 +171,11 @@ updates, but an accepted answer itself does not rewrite the profile. A future
|
||||
workaround requires a controlled, real-capture reproduction that isolates one
|
||||
intervention from stock BWE ramp-up.
|
||||
|
||||
This evidence does not justify an SFU change. The current SFU publisher always
|
||||
publishes the ordered `q,h` pair when an SFU route is active and configures its
|
||||
sender after SDK publication. The pinned client publication defaults to
|
||||
`HIGH`, and Screener also requests a `HIGH` subscriber ceiling immediately
|
||||
after subscribing. A low SFU receive layer can still be a valid server BWE
|
||||
choice. Diagnose that case by correlating publisher high-layer stats with the
|
||||
Viewer's actual inbound layer; do not infer a missing `HIGH` request or change
|
||||
the application policy without those measurements. LiveKit's pinned client
|
||||
also contains an SDP start-bitrate mitigation for initial video blur, but
|
||||
Screener's accepted boundary forbids adding application SDP bitrate hacks.
|
||||
This observation alone did not justify an SFU change because stock BWE ramp-up
|
||||
was not isolated. The later exact-production gate above independently measured
|
||||
the SFU publication and rejected its always-active lower representation.
|
||||
LiveKit's pinned client contains an SDP start-bitrate mitigation for initial
|
||||
video blur, but Screener does not add application SDP bitrate hacks.
|
||||
|
||||
The same release was also reported to reduce game-stream frame rate and
|
||||
consume noticeable Host resources. That report applies only to
|
||||
@@ -236,9 +255,9 @@ SFU publication explicitly uses VP8 with no backup codec. The UI and quality
|
||||
wire expose no codec choice. Codec/profile/encoder stats remain diagnostic and
|
||||
do not authorize automatic switching, route changes, or another controller.
|
||||
Production runs exact deployed application/runtime revision
|
||||
`c4962f54443ad5f98bc65861195a3d9c74a48996`, release `c4962f5`; canonical
|
||||
`bf328590b3de5dfa509fcc70f6316286af3eae7e`, release `bf32859`; canonical
|
||||
`main` contains the same runtime code. Current source and production implement
|
||||
this strict `screener-v11` contract.
|
||||
this strict `screener-v12` contract.
|
||||
|
||||
Chromium maps video `contentHint = "motion"` to libwebrtc `kFluid`, and
|
||||
libwebrtc clears `is_screencast` for that mode, replacing the display-capture
|
||||
@@ -424,11 +443,11 @@ one unambiguous encoding. Current quality settings do not request a mode, so
|
||||
the requested value remains null and a browser-reported default is not called
|
||||
a mismatch; multiple encodings remain unknown. Inbound stats provide no current
|
||||
standard `scalabilityMode` source, so C does not carry a null-only placeholder.
|
||||
The current SFU publisher already configures the shared ordered `q,h`
|
||||
`HIGH+LOW` publication. Real LiveKit per-subscriber BWE downshift/recovery,
|
||||
hardware and game-resource cost, and heterogeneous-network behavior remain open
|
||||
acceptance evidence. Physically stopping an unused `LOW` is a resource
|
||||
optimization rather than a prerequisite.
|
||||
Current source and production still configure the ordered `q,h` publication,
|
||||
but the exact-production gate above rejected it because the active lower
|
||||
representation reduced `HIGH`. ADR-0007 now accepts one Browser SFU `HIGH`;
|
||||
source implementation and the exact single-representation production gate are
|
||||
the next scoped work.
|
||||
|
||||
Official W3C text checked 2026-08-19 defines names ending in `Id` as stats-object
|
||||
references. In particular, outbound [`mediaSourceId`](https://www.w3.org/TR/webrtc-stats/#dom-rtcoutboundrtpstreamstats-mediasourceid)
|
||||
@@ -453,178 +472,29 @@ default. Chromium currently maps its configured per-stream mode into the
|
||||
outbound stats field; other browser implementations may omit any optional
|
||||
member, which remains null rather than a capability conclusion.
|
||||
|
||||
## Accepted Adaptation Direction
|
||||
## Superseded Two-Layer Candidate Analysis (2026-08-22)
|
||||
|
||||
ADR-0007 rejects room-wide worst-link adaptation. Direct/peer paths retain their
|
||||
independent stock WebRTC congestion control. Each SFU path starts with a `HIGH`
|
||||
ceiling; the preferred candidate publishes one shared `HIGH+LOW` pair and lets
|
||||
LiveKit BWE independently select and recover its forwarded layer. If that gate
|
||||
passes, Screener does not add a media-layer selector. The hard active
|
||||
representation/layer limit is two, never one per viewer, and stopping idle
|
||||
`LOW` remains optional.
|
||||
This retained analysis explains the candidate that the 2026-08-25 physical gate
|
||||
rejected. It does not define current product truth, implementation scope, or a
|
||||
next gate; ADR-0007 owns the accepted single-`HIGH` decision.
|
||||
|
||||
Sender/viewer evidence diagnoses capture, encode, transport, receive, and decode
|
||||
behavior. It does not classify topology eligibility. An observed BWE downshift
|
||||
is ordinary per-subscriber adaptation and does not command route or media-layer
|
||||
changes.
|
||||
|
||||
`LOW` itself is conditional: if no qualified hardware/power-efficient media
|
||||
path exists or the additional representation exceeds the measured
|
||||
CPU/GPU/game/upload budget, the system preserves `HIGH` and fails visibly for
|
||||
the weak path. It never intentionally buys weak-path recovery by degrading
|
||||
healthy paths.
|
||||
|
||||
That fail-closed result is exceptional damage containment, not a supported
|
||||
steady state. A supported sender cohort that cannot reliably provide the one
|
||||
shared `LOW`, either always-on or on demand, fails the quality gate; its encoding
|
||||
path must be improved or the cohort explicitly marked unsupported. `HIGH`
|
||||
remains protected in either case.
|
||||
|
||||
A viewer's `LOW` request is advisory and must be authenticated, session-bound,
|
||||
rate-limited, deduplicated, and corroborated by sender transport/encode and
|
||||
viewer receive/decode stats. UA or device-model detection is not quality or
|
||||
relay-capacity evidence. A valid report does not change topology or command
|
||||
built-in WebRTC/LiveKit media adaptation. Built-in SFU BWE may downshift and
|
||||
recover a subscription without any Screener route action; only the exact
|
||||
ingress's hard failure or non-paused decoded-frame stall wakes ADR-0005.
|
||||
|
||||
An ordinary non-scalable stream cannot yield a second independent quality by
|
||||
packet forwarding alone. The alternatives are a second representation,
|
||||
scalable layers, or relay/SFU transcoding. Static review closes current Web P2P
|
||||
simulcast and Web/LiveKit SVC as cross-path shortcuts, while pinned LiveKit
|
||||
two-layer simulcast remains the priority bounded runtime candidate. This SVC
|
||||
gate does not run a browser or select a custom implementation.
|
||||
|
||||
WebRTC provides sender-side encoding control but no
|
||||
`RTCRtpReceiver.setParameters()` or other standard per-RID subscription method.
|
||||
Consequently, direct P2P receivers cannot explicitly choose `HIGH` versus `LOW`
|
||||
from one shared simulcast sender, while separate viewer PeerConnections have no
|
||||
portable shared-encoder contract. This is
|
||||
`no-go-web-p2p-simulcast-layer-selection`. The unrun sender experiment makes no
|
||||
claim about per-RID traffic or whether `active=false` releases a physical
|
||||
encoder, CPU work, or GPU allocation.
|
||||
|
||||
Pinned LiveKit 2.22.0 can publish screen-share original plus one lower
|
||||
simulcast encoding. `RemoteTrackPublication.setVideoQuality(HIGH)` sets a
|
||||
per-subscriber spatial-quality ceiling. Server 1.13.5 derives requested
|
||||
spatial/temporal maxima from quality, dimensions and FPS, but applies them
|
||||
through codec-specific selectors: VP8 has temporal selection, while H.264/H.265
|
||||
simulcast is spatial-only. When H.264 is selected, the candidate can adapt each
|
||||
SFU downtrack between `q,h` spatial representations and recover it independently.
|
||||
Server Dynacast
|
||||
takes the maximum quality requested across subscribers and subscriber nodes,
|
||||
then enables every quality at or below that maximum; a `HIGH` root therefore
|
||||
keeps `LOW` active. That prevents dynamic `LOW` stop while `HIGH` is subscribed,
|
||||
but idle-layer stop is only an optimization, so this cumulative behavior is not
|
||||
a product no-go. The Firefox branch's 4x scale, 10 bps, and non-standard
|
||||
`maxFrameRate` fallback likewise cautions against assuming a clean stopped
|
||||
layer; it does not invalidate the always-on two-layer candidate.
|
||||
|
||||
The next runtime gate must publish exactly `HIGH+LOW` with standard
|
||||
simulcast/send encodings, leave each SFU subscription's ceiling at `HIGH`, and
|
||||
test built-in per-subscriber SFU bandwidth adaptation and
|
||||
recovery. Start with Dynacast off for a deterministic always-on measurement;
|
||||
pinned cumulative
|
||||
Dynacast-on is another always-on form, not a third representation. Prove the
|
||||
received layer, the two-layer ceiling, unchanged healthy P2P/`HIGH`, and
|
||||
hardware encoder, game FPS/p1 low, CPU/GPU, interval encode cost, upload, and
|
||||
per-layer byte budgets for both leaves and relay roots. An autonomous downshift
|
||||
does not evacuate children or alter route state. Screener's current publisher always
|
||||
configures exactly two ordered `q`/`h` encodings whenever an SFU publication is
|
||||
active, explicitly constructs `Room({ dynacast: false })`, disables backup-codec
|
||||
publication, and its subscriber sets a `HIGH` ceiling after selectively
|
||||
subscribing. Client 2.22.0 also defaults Dynacast to `false`; the explicit option
|
||||
prevents silent drift, while `backupCodec: false` prevents the pinned
|
||||
multi-codec publish path from enabling Dynacast automatically. Dynacast off
|
||||
prevents the pinned SDK's subscribed-quality handler from toggling publisher
|
||||
encoding activation. It does not disable per-subscriber SFU BWE, force the
|
||||
server to forward `HIGH`, or prove that both encoders consume resources
|
||||
continuously. The publication is not behind a separate quality flag. The
|
||||
subscriber also does not attach a
|
||||
`RemoteTrack`, so SDK `adaptiveStream` is not directly usable without changing
|
||||
that ownership; built-in SFU bandwidth adaptation does not depend on enabling
|
||||
that feature. If built-in selection fails the product gates, test explicit
|
||||
standard subscriber quality selection before manual sender
|
||||
activation/deactivation.
|
||||
The candidate assumed one shared `HIGH+LOW` SFU publication could preserve
|
||||
healthy `HIGH` while LiveKit selected a lower representation per constrained
|
||||
subscriber. Static review established two limits before the runtime gate:
|
||||
ordinary WebRTC receivers have no portable per-RID selection API across
|
||||
separate PeerConnections, and LiveKit 1.13.5 Dynacast cumulatively enables every
|
||||
quality below the highest requested quality. A `HIGH` subscriber therefore
|
||||
keeps `LOW` active. The 2026-08-25 exact-production A/B then proved that this
|
||||
always-active lower representation materially reduced `HIGH`, so ADR-0007
|
||||
rejected the candidate. Sender/viewer evidence remains diagnostic and does not
|
||||
change topology or command a representation.
|
||||
|
||||
### Historical SFU Source Gate
|
||||
|
||||
This section records the exact 2026-08-22 source gate; it is evidence rather
|
||||
than current routing policy.
|
||||
|
||||
The 2026-08-22 `gate:sfu-root-invariants` source gate proves that the publisher
|
||||
passes explicit `dynacast: false`, exposes exactly the ordered active `q,h`
|
||||
encodings, and the selectively subscribed screen publication retains a `HIGH`
|
||||
ceiling. Server route state and token allowlists reject a third SFU root. A Host
|
||||
with one direct child plus one active SFU publication is charged two outbound
|
||||
media edges, while a third edge fails. A committed SFU root with zero peer
|
||||
children stays selected across reauthentication, and its active subscriber is
|
||||
reconciled with an empty child list without deactivation. The benchmark
|
||||
acceptance evaluator independently rejects a third root or Host media edge.
|
||||
|
||||
This preflight does not start LiveKit 1.13.5, a browser, or a network shaper. It
|
||||
therefore does not prove packet receipt/forwarding, autonomous BWE downshift and
|
||||
recovery, actual `LOW`/`HIGH` dimensions, per-layer bytes, encoder count, CPU/GPU,
|
||||
game frame time, or upload cost. Those remain acceptance requirements for the
|
||||
isolated run below; relay-root behavior remains resource and quality evidence,
|
||||
not a route gate.
|
||||
|
||||
### Per-Flow Shaping Preflight
|
||||
|
||||
The 2026-08-22 Windows 11 re-audit stopped before writing a harness or starting
|
||||
media. Chrome 151 and Edge 151 are installed. A cached official LiveKit 1.13.5
|
||||
Linux amd64 archive contains only `LICENSE` and `livekit-server`; its SHA-256
|
||||
`c020fac437b7cc9b776eef1ad5ea8af77be9acfa07602eca20a3a44930dfbc70`
|
||||
matches the release asset digest. Obtaining the pinned server is therefore not
|
||||
the blocker.
|
||||
|
||||
The workstation has no Docker, Podman, nerdctl, Lima, Multipass, Vagrant, QEMU,
|
||||
Go, Linux `ip`, or Linux `tc`. `wsl.exe --version`, `--status`, and
|
||||
`--list --verbose` all report that WSL itself is not installed, not merely that
|
||||
a distribution is stopped, and the current session is not elevated. The
|
||||
existing peer-assisted benchmark can start Screener and Chromium and already
|
||||
collect route/media snapshots plus whole-browser CDP CPU deltas, but it starts
|
||||
neither LiveKit nor an SFU quality fixture, isolates no leaf transport, and CDP
|
||||
does not provide the required server or browser RSS. Those parts are reusable
|
||||
sampling seams, not shaped-media evidence.
|
||||
|
||||
Windows policy-based QoS can match outbound traffic by application or IP
|
||||
tuple, but this setup has not proved that it can follow one ICE-generated,
|
||||
ephemeral subscriber downtrack across generation changes or apply an auditable
|
||||
limit to the local loopback media path. CDP `Network` throttling likewise has no
|
||||
accepted per-WebRTC-flow contract. Neither mechanism may be used as evidence
|
||||
that one SFU subscriber was weakened while another stayed healthy.
|
||||
|
||||
The minimum external prerequisite is a disposable Linux VM or equivalent host
|
||||
with root or `CAP_NET_ADMIN`, `iproute2` (`ip`, `tc`, `tbf`, and a tuple-capable
|
||||
filter such as `flower`), readable per-process CPU/RSS counters, Node 24, and a
|
||||
supported Chromium. It must put the publisher, healthy leaf, and weak leaf in
|
||||
separate network namespaces with separate veth devices and allow the selected
|
||||
LiveKit UDP flow to cross those devices. Run the pinned application and
|
||||
LiveKit 1.13.5 without TURN or media TCP and without touching production
|
||||
networking or firewall state. Before media, prove only the namespace, route,
|
||||
veth, filter, and qdisc availability; the selected ICE tuple does not exist yet.
|
||||
Use `tbf` for a bounded rate and `netem` only when the case explicitly adds loss
|
||||
or delay.
|
||||
|
||||
The sole browser run has three ordered phases. First establish both leaves
|
||||
without shaping, identify the selected LiveKit ICE/UDP tuples locally, record
|
||||
the healthy and weak veth baselines, and require `HIGH/HIGH`. Next attach the
|
||||
filter and qdisc to only the weak leaf's selected media tuple and direction.
|
||||
Require filter packet/byte growth, independent TBF overlimit/queue evidence and
|
||||
the expected weak-path throughput bound before accepting `HIGH/LOW`; a filter
|
||||
counter alone proves classification, not shaping. The healthy veth counters,
|
||||
inbound bitrate, dimensions, FPS, and decode progress must remain within the
|
||||
unshaped baseline envelope. Finally remove the weak qdisc and require recovery
|
||||
to `HIGH/HIGH` while the healthy leaf remains unchanged.
|
||||
|
||||
Retain gate evidence for the publisher's ordered `q`/`h` encodings and
|
||||
per-layer bytes, both subscribers' actual dimensions, FPS, bytes, codec and
|
||||
decode progress, correlated A+B/C windows, Host upload and interval encode
|
||||
cost, and available system CPU/GPU/game proxies. A third layer, an affected
|
||||
healthy leaf, missing classification or shaping counters, or an
|
||||
application-issued `LOW` command fails the run. Root migration remains outside
|
||||
this zero-descendant-leaf gate.
|
||||
The 2026-08-22 source-only gate verified ordered `q,h` configuration and existing
|
||||
SFU route/admission accounting, but did not start LiveKit or a Browser. The
|
||||
2026-08-25 exact-production gate supersedes that candidate's quality verdict;
|
||||
Git history retains the abandoned shaping plan.
|
||||
|
||||
SVC is the third static no-go,
|
||||
`no-go-web-svc-cross-path-hardware-contract`. WebRTC-SVC configures an outgoing
|
||||
@@ -666,26 +536,13 @@ the high layer, so the application does not own the actual layer choice.
|
||||
For this screen-share product the pin has an additional hard mismatch. Client
|
||||
2.22.0 overwrites SVC screen-share publication to `L1T3`, even when another
|
||||
mode was supplied: one spatial resolution and three temporal layers. It
|
||||
therefore supplies no low-resolution base and exceeds the two-active-layer
|
||||
ceiling. LiveKit also documents that Dynacast can pause only an entire SVC
|
||||
therefore supplies no low-resolution base and exceeds the accepted
|
||||
one-representation contract. LiveKit also documents that Dynacast can pause only an entire SVC
|
||||
stream, not individual SVC layers. Changing those contracts would require a
|
||||
different dependency/native design decision, not a runtime proof of the pinned
|
||||
path. No SVC harness was written and no Chrome run was performed. None of the
|
||||
rejected standard paths may bypass PR #28's stock-GCC/RTX stop line.
|
||||
|
||||
If built-in LiveKit selection fails the product gates, test explicit standard
|
||||
subscriber quality selection. If the always-on representation cost itself
|
||||
exceeds budget, test manual activation/deactivation through standard sender
|
||||
primitives. Only if these standard forms fail may custom/native dual
|
||||
representation remain a candidate. Retain the
|
||||
favorable, testable hypothesis that one low-rate, low-resolution hardware `LOW`
|
||||
may have no material game impact, but compare `HIGH` against `HIGH+LOW` under
|
||||
one scene using game FPS/p1 low, CPU, GPU video-encode/copy activity, interval
|
||||
encode cost, actual encoder identity, upload, and per-layer bytes before
|
||||
accepting any custom path. Failure preserves `HIGH` and fails the weak path
|
||||
visibly. It cannot reopen an earlier static no-go or bypass the topology policy
|
||||
and resource budget.
|
||||
|
||||
## Why Offline Encoding Presets Do Not Transfer
|
||||
|
||||
[Maruko Toolbox](https://github.com/wzxjohn/marukotoolbox) is an Apache-2.0
|
||||
@@ -714,7 +571,7 @@ The three user-visible profiles remain ceilings rather than promised rates:
|
||||
| 1080p30 | 1920x1080 at 30 fps | 5 Mbps |
|
||||
| 720p30 | 1280x720 at 30 fps | 3 Mbps |
|
||||
|
||||
Current v11 source and production default to the middle `1080p30` ceiling.
|
||||
Current v12 source and production default to the middle `1080p30` ceiling.
|
||||
Choosing that
|
||||
default trades a 60 fps ceiling for a 1080p capture bound. The recommended set
|
||||
remains exactly the three profiles
|
||||
@@ -734,7 +591,7 @@ guarantees the emitted resolution, frame rate, or bitrate.
|
||||
`maintain-framerate` choices. None promises an emitted resolution or rate.
|
||||
- `maxBitrate` and `maxFramerate` are ceilings. They are neither minimums nor
|
||||
target guarantees, and the project does not use SDP bitrate hacks.
|
||||
- The strict `screener-v11` Share advanced settings panel in current source and
|
||||
- The strict `screener-v12` Share advanced settings panel in current source and
|
||||
production accepts 480p/720p/1080p/1440p, integer 15-60 fps, 2-12 Mbps, and
|
||||
the three preferences. Browser media is fixed VP8, with no codec UI,
|
||||
quality-state field, or wire field. The `480p` choice is only advanced
|
||||
@@ -815,12 +672,11 @@ pipeline.
|
||||
Compare image readability and motion continuity instead of declaring success
|
||||
from FPS alone. If reproducible evidence later shows a supported preference
|
||||
oscillates or makes the wrong tradeoff on supported machines, revise that
|
||||
explicit option before enabling ADR-0007. Its acceptance matrix must prove that built-in
|
||||
LiveKit BWE independently moves one shaped SFU leaf to the shared `LOW` and back
|
||||
while a healthy leaf remains `HIGH`, without an application media selector. The
|
||||
application's evidence windows remain diagnostic only. Each supported sender cohort must provide `LOW`
|
||||
within measured hardware, game, and upload budgets; idle-layer resource release
|
||||
is a separate optimization.
|
||||
explicit option only from a new controlled gate. Browser SFU verification must
|
||||
show exactly one VP8 outbound video encoding, no `q,h` simulcast, continuing
|
||||
publisher/subscriber frame progress, and unchanged ADR-0005 resource accounting.
|
||||
The application's evidence windows remain diagnostic only; they do not command
|
||||
another representation, change topology, or override stock congestion control.
|
||||
|
||||
## Primary Sources
|
||||
|
||||
|
||||
@@ -55,7 +55,10 @@ Current high-signal boundary:
|
||||
v12 source and production have no codec UI/state/wire or fallback media codec.
|
||||
Automated source gates and the exact deployment postflight passed. Chrome 151
|
||||
physically verified direct/browser-relay/SFU screen-audio continuity and all
|
||||
three sender ceilings; the separate VP8 performance/codec gate remains open.
|
||||
three sender ceilings. An exact-production VP8 gate sustained about 59.5 fps
|
||||
on direct and Browser-relay paths and rejected the current SFU `q,h`
|
||||
publication because active `LOW` reduced `HIGH`. ADR-0007 accepts one Browser
|
||||
SFU `HIGH`; source and production remain `q,h` until the next scoped change.
|
||||
- Ordinary browser ICE owns direct reachability. Do not build port prediction,
|
||||
guessed candidates, NAT classification, TCP probes, quality scores, or
|
||||
quality-driven reparenting. Current-path quality is diagnostic; a healthy
|
||||
|
||||
+5
-5
@@ -11,9 +11,9 @@ This is the current execution index. Git history owns completed timelines; [veri
|
||||
- The service process resolves its working directory to exact release `bf32859`; it has no writable room `StateDirectory` or SQLite runtime.
|
||||
- Production admits one Host plus 20 Viewers, applies endpoint capacity `2`, rejects stale Browser and executable-sender wires before room authority, and runs the one-controller exact-candidate route model with one staged total deadline. Rooms use random free four-digit codes, a 24-hour dormant lease, restart loss, local Host creation preferences, a room-lived 22-character Viewer grant, and exactly `open | private` code entry. Private rooms without a password are invitation-only; configuring one additionally permits matching code-and-password entry. LiveKit remains dedicated with `room.auto_create: false`, `max_participants: 21`, and global admission `1` publication ingress / `20` subscription egress.
|
||||
- Production media ports remain STUN-only UDP 3478 and LiveKit UDP 7882; coturn TCP/TLS, port 5349, media TCP, and relay ranges are disabled. The public Web ingress remains TCP 80/443; Node 8787 and LiveKit control/signaling 7880 are internal-only. The stable `inet bonfire_filter` table SHA-256 is `afaf9d066e9f292d8bd19032b38c0978ccf60dd01c2fe7f210968ff751f90534`; the dynamic fail2ban table is excluded from that identity.
|
||||
- SFU subscribers reconcile Host screen publications across connect, activation, participant arrival, track publication, and reconnect. LiveKit runs at `warn`/Pion `error`, and the Screener unit waits boundedly for the same-host LiveKit control listener before startup. The current postflight found healthy unchanged services; owner physical SFU fallback proof remains bounded to exact predecessor release `c4962f5`. Full current-release direct/browser-relay/SFU codec and real-network acceptance remain open.
|
||||
- SFU subscribers reconcile Host screen publications across connect, activation, participant arrival, track publication, and reconnect. LiveKit runs at `warn`/Pion `error`, and the Screener unit waits boundedly for the same-host LiveKit control listener before startup. The current postflight found healthy unchanged services; exact-production direct and Browser-relay VP8 evidence is closed, while accepted single-`HIGH` SFU deployment/physical proof and broader real-network acceptance remain open.
|
||||
- Production Browser SFU publisher and subscriber PCs explicitly use empty external ICE-server lists while retaining LiveKit-signaled UDP candidates. The owner verified that the deployed isolation fixes the reported SFU connection failure; the prior P1 core-route hold is closed.
|
||||
- Production leaves video `contentHint` unset, keeps audio `contentHint = "music"`, and fixes Browser direct, browser-relay, and SFU video to VP8 without codec UI, quality state, wire fields, or fallback media codecs.
|
||||
- Production leaves video `contentHint` unset, keeps audio `contentHint = "music"`, and fixes Browser direct, browser-relay, and SFU video to VP8 without codec UI, quality state, wire fields, or fallback media codecs. The deployed SFU publisher still sends ordered `q,h` simulcast; the exact-production quality gate rejected that candidate, so production is not yet aligned with ADR-0007's accepted single-`HIGH` representation.
|
||||
|
||||
## Current Source
|
||||
|
||||
@@ -22,14 +22,14 @@ This is the current execution index. Git history owns completed timelines; [veri
|
||||
- One event-driven controller owns the committed graph and at most one room-serial child operation. It uses one deterministic candidate list/cursor and one total direct-then-SFU deadline; exact admission and physical resources remain charged through drain, and the pending candidate commits only after an exact-generation decoded-frame proof. A short-lived 100 ms stats observer proves only that candidate inside the existing deadline, while the 2-second sampler remains responsible for active-path diagnostics and decoded-frame stalls. Healthy edges remain sticky and current-path quality does not authorize reparenting.
|
||||
- Ordinary peer ICE is STUN-only and the only application fallback is the dedicated LiveKit SFU over UDP. SFU generations use explicit no-default ingress/egress capacities, exact `reserved | committed | draining` accounting, delete-plus-absence release, one Host publication, and exact Viewer subscription handles. No Screener TURN, ICE/TCP, media TCP, or TLS-relayed media route exists.
|
||||
- Current Browser SFU publisher and subscriber connects supply fresh `autoSubscribe: false` plus `rtcConfig: { iceServers: [] }` options. Ordinary peers retain deployment STUN; LiveKit signaling candidates, server-side public-IP discovery, route deadlines, ports, and retry behavior are unchanged.
|
||||
- Current source leaves video `contentHint` unset and keeps audio `contentHint = "music"`. Browser direct and browser-relay offers contain VP8 as their only media codec, and SFU publication explicitly uses VP8 with no backup codec. Codec UI, quality state, wire fields, fallback media codecs, and share-lifetime codec branches are absent. Live 64/128/256 kbps audio-ceiling mutation remains unchanged; ordinary Host and SFU publisher metrics select the exact current audio sender, relays reconcile audio-track additions and removals on the persistent stream, and an SFU reconnect reacquires the current publication/sender or fails the route closed.
|
||||
- Current source leaves video `contentHint` unset and keeps audio `contentHint = "music"`. Browser direct and browser-relay offers contain VP8 as their only media codec, and SFU publication explicitly uses VP8 with no backup codec. Codec UI, quality state, wire fields, fallback media codecs, and share-lifetime codec branches are absent. The SFU publisher still configures ordered `q,h` simulcast and is therefore out of alignment with ADR-0007's accepted single-`HIGH` representation until the next scoped source change. Live 64/128/256 kbps audio-ceiling mutation remains unchanged; ordinary Host and SFU publisher metrics select the exact current audio sender, relays reconcile audio-track additions and removals on the persistent stream, and an SFU reconnect reacquires the current publication/sender or fails the route closed.
|
||||
- Current source implements typed first-frame Viewer presentation and recovery, Chinese user-facing route/access failures, local connection details without a diagnostic-file export, authenticated Host-only on-demand route snapshots for automatic acceptance, explicit missing-room presentation, and responsive entry controls. Host invitation controls remain independent from two-state room-code entry.
|
||||
- Recommended quality remains exactly `1080p60`, `1080p30`, and `720p30`; current source defaults to `1080p30`. Advanced resolution adds `480p` as `854x480` without adding a fourth preset, and advanced FPS and bitrate remain independent.
|
||||
- Exact `main@bf32859` passed repository hygiene, TypeScript, all 613 Web tests in 44 files, both production builds, focused independent review, and the production artifact/service postflight above. A Chrome 151 production gate then exercised two direct children, one browser-relay child, one SFU subscription, all three audio ceilings, and live source replacement with progressing audio/video; exact evidence boundaries remain in [verification status](./verification-status.md).
|
||||
- Exact `main@bf32859` passed repository hygiene, TypeScript, all 613 Web tests in 44 files, both production builds, focused independent review, and the production artifact/service postflight above. A Chrome 151 production gate then exercised two direct children, one browser-relay child, one SFU subscription, all three audio ceilings, and live source replacement with progressing audio/video. A separate exact-production VP8 gate sustained about 59.5 fps on direct and browser-relay paths, while its SFU A/B proved that the always-active `LOW` materially reduced `HIGH`; exact applicability remains in [verification status](./verification-status.md).
|
||||
|
||||
## Current Milestone
|
||||
|
||||
1. Physically diagnose the reported localhost `1080p60` shortfall and verify fixed-VP8/no-video-hint direct, browser-relay, and SFU paths from actual capture, encode, send, receive, decode, render, codec, and resource evidence.
|
||||
1. Align Browser SFU publication with ADR-0007's accepted single-`HIGH` VP8 representation, deploy the exact artifact, and physically verify one outbound video encoding with progressing publisher/subscriber media. Direct and browser-relay VP8/no-hint performance is already closed by the exact-production gate.
|
||||
2. Finish representative ICE/STUN/SFU acceptance, including route recovery, screen-audio continuity and real-game A/V sync on mobile and heterogeneous networks. Browser port prediction, NAT classification, TCP probing, fake page keepalive, and quality-driven reparenting remain outside the accepted model.
|
||||
|
||||
## Active Boundaries
|
||||
|
||||
+1
-1
@@ -6,7 +6,7 @@ Only items in **Now** are executable after their stated decision gate. A branch
|
||||
|
||||
## Now
|
||||
|
||||
1. **Diagnose and physically validate Browser VP8 performance with no video hint.** First reproduce the reported localhost `1080p60` shortfall with current production and separate source capture, encoded, sent, received, decoded, and rendered frame rates plus encode time, quality limitation, CPU/GPU load, and actual encoder implementation. Compare `contentHint` only as a controlled diagnostic and do not restore it by assumption. Then confirm actual VP8 codec, capture, outbound, and decoded stats on direct, browser-relay, and SFU paths; automated gates and the predecessor SFU connectivity proof do not close this performance/codec gate.
|
||||
1. **Align Browser SFU publication with the accepted single-`HIGH` verdict.** Exact production Chrome 151 closed the intrinsic VP8/no-hint shortfall on direct and browser-relay paths, but proved that the always-active SFU `LOW` materially reduces `HIGH` on the measured public ingress. Replace the current ordered `q,h` publication with one VP8 `HIGH` representation, remove only the now-unowned two-layer helpers and assertions, deploy the exact artifact, and physically verify one outbound video encoding plus progressing publisher/subscriber frames over LiveKit UDP. Do not change direct/browser-relay media, `contentHint`, route ordering, deadlines, or add a bitrate controller.
|
||||
2. **Finish real-network route acceptance.** Measure standard ICE/STUN direct paths, peer relay, SFU ingress/subscription, exact first-frame commit and rollback, relay-ingress repair with subtree retention, disconnect/capacity drain, Pause/Resume, screen-audio continuity and real-game A/V sync, and bounded explicit failure across representative IPv4/IPv6 NATs and mobile networks. Include an all-UDP-blocked case to establish the current failure boundary. Do not add port prediction, NAT classification, TCP probes, guessed candidates, route scores, or quality-driven reparenting.
|
||||
|
||||
## Accepted Later Roadmap
|
||||
|
||||
@@ -20,25 +20,26 @@ Capacity and routing entries below describe the exact tested source or release o
|
||||
|
||||
- Exact deployed `main@bf32859` passed repository hygiene, TypeScript typecheck, all 613 Web tests in 44 files, client and server production builds, focused independent review, and production artifact/service postflight. Exact predecessor `b68c471` separately passed the 261-test SFU admission gate and explicit-Chrome access/privacy gate. Retained Chrome 20-Viewer and responsive visual checks apply only to their recorded predecessor revisions.
|
||||
- Chrome 151 on exact production `bf32859` captured a continuously changing tab with generated audio through real `getDisplayMedia()`. Two Host-direct children plus one browser-relay child and one forced-SFU Viewer all advanced decoded audio energy and video frames at 64/128/256 kbps sender ceilings and after live source replacement. Ordinary paths selected direct UDP; the SFU publisher/subscriber selected LiveKit UDP with empty external ICE-server lists. The UI never reported the faulty constant `1 kbps` with active audio. Direct/browser-relay actual traffic tracked each selected ceiling; SFU 64/128 traffic was higher because the accepted LiveKit default retains RED, so sender ceiling/readback and wire traffic remain distinct. After RTCP mapping became available, direct/browser-relay audio-minus-video playout timestamps ranged from -101 to +4 ms; Chrome exposed no corresponding value on the SFU subscription, so real-game SFU A/V synchronization remains open rather than inferred.
|
||||
- Exact Browser SFU ICE-server-isolation implementation `ae09c760adec76fd26da611d4928486d105c6d3b` passed repository hygiene, TypeScript typecheck, all 605 Web tests in 45 files, client and server production builds, three independent code reviews, focused 95-test publisher/subscriber and ordinary-peer isolation coverage, deployment postflight, and owner physical SFU fallback media proof. This establishes the reported production connection fix without turning candidate type/count into an invariant; full route/codec/network acceptance remains open.
|
||||
- Chrome 151 on exact production `bf32859` used real `getDisplayMedia()`, a continuously changing source, separate Browser processes, VP8/libvpx, and no video hint. Direct stabilized near 59.5 encoded/received/decoded/rendered fps at 1904x928; a Browser relay kept every stage near 59.4--59.7 fps, adapting its outbound to 1428x696 under bandwidth pressure. Both converged after about 25--30 seconds of stock BWE ramp-up. On the exact public SFU path, current `q,h` publication held `h` near 9.2 fps/1.37 Mbps; making `q` inactive from the first sender-parameter application raised the same 1904x928 `h` to about 23.3 fps/3.32 Mbps with source/capture near 60, 4.46 ms encode time per frame, zero loss/retransmission, and about 4.81 Mbps available outgoing bitrate. This closes an intrinsic VP8/no-hint direct/relay shortfall and rejects always-active `LOW`; it does not prove a deployed single-representation SFU path, public SFU 60 fps, or real-game performance.
|
||||
- Exact Browser SFU ICE-server-isolation implementation `ae09c760adec76fd26da611d4928486d105c6d3b` passed repository hygiene, TypeScript typecheck, all 605 Web tests in 45 files, client and server production builds, three independent code reviews, focused 95-test publisher/subscriber and ordinary-peer isolation coverage, deployment postflight, and owner physical SFU fallback media proof. This establishes the reported production connection fix without turning candidate type/count into an invariant; full route/network acceptance remains open.
|
||||
- A fresh canonical `main@c4962f5` background gate passed repository hygiene, all 605 Web tests, both production builds, the 254-test SFU admission suite, and the Chrome 151 20-Viewer 720p30/30-second local route gate. All 20 Viewers advanced decoded frames, Host and relays stayed within endpoint cap `2`, no orphan SFU publication appeared, and all four current-child timing distributions contained 20 values. The browser gate uses deterministic canvas and does not start LiveKit, so it proves local direct/browser-relay control and media behavior only; it is not physical capture or SFU evidence.
|
||||
- Exact v10 runtime source `fdd5a4a529ff297f41c05ea3388bf484d76afe8f` passed repository hygiene, TypeScript typecheck, client and server production builds, all 610 Web tests in 45 files, the 257-test SFU admission gate, the access/privacy Browser gate, and the production-dependency audit with zero vulnerabilities. Its one-Host/20-Viewer Chrome 151 direct-loopback report passed all seven assertions: all Viewers decoded, the selected VP8 settings reached every participant, Host and relay media edges stayed within cap `2`, no orphan SFU publication appeared, and all four current-child timing distributions contained 20 values. The report SHA-256 is `802CBB7632E9AEA3C39FE831A7F7880D24140B2E83942CE0DFDA05DE4B408EED`. This validates the v10 source boundary, not H.264 quality, hardware attribution, physical capture, public-network behavior, or SFU packet flow.
|
||||
- Chrome 151 synthetic `1/3/5/8` and 720p30 runs preserved bounded fanout and decoding. A `9461e20`-era three-Viewer rerun kept Host2/Browser Viewer1, decoded every Viewer, and recovered a hard first-level relay departure in 5,380 ms; it did not exercise quality-triggered MBB. Sixteen-Viewer cap2/cap3 loopbacks decoded all Viewers and a ten-second follow-up recorded guarded sender and aggregate Chromium CPU evidence, but resolution/FPS remained low and the ordinary-PC data cannot rank caps, select product policy, or prove sustainable heterogeneous-network quality. See [peer-assisted media](./research/peer-assisted-media.md).
|
||||
- Chrome 151 with local LiveKit 1.13.5/client 2.22.0 proved one SFU/UDP root after `q,f` -> `q,h`: decoded frames advanced 3 -> 23, rendered frames reached 26, Host used one edge, and leaves were clean. This is functional evidence only. See [low-server media routes](./research/low-server-media-routes.md).
|
||||
- Chrome 151 on the current Windows TUN path reproduced intermittent production LiveKit initial ICE before publication: server counters observed both ingress and egress while Browser ICE received no responses. Eight isolated Host attempts using the LiveKit-provided STUN endpoint succeeded `2/8`; explicitly empty Browser SFU `iceServers` succeeded `8/8`, observed a peer-reflexive-to-host UDP pair within 0.5--1.7 seconds, and published 75--89 ms later. This selects Browser SFU ICE-server isolation; the observed candidate type is diagnostic, not a gate, and the run does not close exact deployed Host/Viewer first-frame, mobile, quality, or endurance evidence. See [low-server media routes](./research/low-server-media-routes.md).
|
||||
- Host A+B and authenticated P2P Viewer C evidence is sanitized, generation-bound, diagnostic-only, and closed for stale or ambiguous reports. Production can expose a Host-local current SFU `h` snapshot and clears it on publisher identity changes; raw media metadata is not retained. See [realtime quality adaptation](./research/realtime-quality-adaptation.md).
|
||||
- Fresh Chrome 151 tab-capture probes identified two separate Browser boundaries. Removing video `contentHint = "motion"` changed VP8 from 14.93 fps at 428x208 to 29.73 fps at 1904x928 under the same 5 Mbps balanced setup. No-hint AMD H.264 remained about 14--16 fps with hundreds of outer rate-limiter drops, while the same MFT reached 29.93 fps under diagnostic Desktop SW BRC; OpenH264 was slower. The page cannot enable that Chromium field trial or select an adapter/MFT. No-hint VP8 used libvpx software and held about 30 fps in one- and two-sender loopback on the test machine, but the process CPU totals include capture and local decode and are not real-game or weaker-device evidence. This evidence selects fixed VP8 for the Browser contract; current source and production implement that decision, while physical production codec behavior remains unverified. See [realtime quality adaptation](./research/realtime-quality-adaptation.md), [Native H.264](./research/native-h264-hardware-decision.md), and [Native shared encode](./research/native-shared-encode-sender.md).
|
||||
- Fresh Chrome 151 tab-capture probes identified two separate Browser boundaries. Removing video `contentHint = "motion"` changed VP8 from 14.93 fps at 428x208 to 29.73 fps at 1904x928 under the same 5 Mbps balanced setup. No-hint AMD H.264 remained about 14--16 fps with hundreds of outer rate-limiter drops, while the same MFT reached 29.93 fps under diagnostic Desktop SW BRC; OpenH264 was slower. The page cannot enable that Chromium field trial or select an adapter/MFT. No-hint VP8 used libvpx software and held about 30 fps in one- and two-sender loopback on the test machine, but the process CPU totals include capture and local decode and are not real-game or weaker-device evidence. This evidence selects fixed VP8 for the Browser contract; current source and production implement that decision, and the exact-production gate above now verifies VP8 on direct, Browser-relay, and current dual-representation SFU paths. See [realtime quality adaptation](./research/realtime-quality-adaptation.md), [Native H.264](./research/native-h264-hardware-decision.md), and [Native shared encode](./research/native-shared-encode-sender.md).
|
||||
- One bounded Chrome 151/Windows 25H2 current-browser screening used real `getDisplayMedia()` window capture, VP8/libvpx with no video hint, a continuously changing WPF source, and one same-machine loopback receiver. Focused, hidden-tab, and minimized 15-second windows measured about 29.4--29.6 capture/encoded/decoded fps and 1.35--1.50 ms encode time per frame; each boundary sample read an enabled, unmuted, live 1186x712 track and each end sample reported `qualityLimitationReason=none`. All rates used monotonic counter deltas over the outbound-RTP RTCStats timestamp interval; source/inbound timestamps and raw stats identities were not retained independently. The sample did not observe an immediate Host-document background drop; it does not cover exact production code, a real game, physical Viewer, CPU/GPU contention, audio, repetition, a hold beyond five minutes, or public routing. See [Browser background capture](./research/browser-background-capture.md).
|
||||
- Native Windows 11 process audio is source-only and default-off. A retained run isolated the target by about 4018x and delivered 495 Opus packets to one Viewer; package download, game sync, Windows 10, and other routes remain open. See [ADR-0008](./adr/0008-window-scoped-audio-capture.md).
|
||||
|
||||
## Open Proof Boundaries
|
||||
|
||||
- Routing: exact v10 local direct loopback remains historical evidence for admission-20 initial ingress and exact-candidate first-frame commit timing on that source. Current v12 production still needs physical direct, browser-relay, and SFU codec verification, together with route rollback, direct-stage exhaustion and SFU admission, relay-ingress reparent with subtree retention, disconnect/effective-capacity drain, pause/resume, and bounded failure on real browser/media paths. Silent control partitions may wait 30 to 60 seconds for heartbeat detection before the default five-second grace; a non-paused decoded-frame stall may invalidate only that exact child edge.
|
||||
- Quality: production startup blur remains unclassified. One same-`balanced` local A/B retained route/PC/SSRC/track while 720p rose to 1080p, but natural ramp prevents causal, production, or SFU conclusions. Correlate Host capture/encode/send with Viewer receive/decode before changing policy.
|
||||
- Routing: exact v10 local direct loopback remains historical evidence for admission-20 initial ingress and exact-candidate first-frame commit timing on that source. Current v12 production still needs route rollback, direct-stage exhaustion and SFU admission, relay-ingress reparent with subtree retention, disconnect/effective-capacity drain, pause/resume, and bounded failure on real browser/media paths. Silent control partitions may wait 30 to 60 seconds for heartbeat detection before the default five-second grace; a non-paused decoded-frame stall may invalidate only that exact child edge.
|
||||
- Quality: exact-production direct and Browser-relay VP8/no-hint cadence is closed. The current dual-representation SFU publication failed ADR-0007's quality gate; source/deployment alignment and exact single-representation publisher/subscriber evidence remain open. Startup ramp is stock BWE behavior and does not authorize an SDP or application bitrate workaround.
|
||||
- Host background: deferred until the report reproduces on exact production with a continuously changing real game or replay, a separate direct wired Viewer, synchronized capture/outbound/inbound plus CPU/GPU evidence, and repeated focused/unfocused/hidden/minimized windows. The current-Chrome Browser `getDisplayMedia()` WPF-window screening did not observe an immediate Host-page media drop, and the old harmful `contentHint = "motion"` release remains a plausible confound rather than a proven background cause. Current evidence authorizes no keepalive, Wake Lock, timer, codec switch, route change, or Native fallback.
|
||||
- Relay resources: current source and production expose the authenticated `1/2/3` endpoint-cap boundary, and retained v10 local loopback evidence covers 20 Viewers at cap `2` only for that source. CPU/GPU/upload and heterogeneous-network measurements remain diagnostics, not authority to change the contract.
|
||||
- Room scale: current source and production admit 20 Viewers plus one Host, and the retained v10 local Browser convergence gate covers that bound on direct loopback. A real public-network 1:20 session, quality, and sustained resource matrix remain open.
|
||||
- SFU: production uses one Host publication with exact Viewer subscriptions and no fixed root-count or room-wide lease rule. Browser SFU PCs use the accepted empty-external-ICE-server rule and owner physical media proof closed the reported connection hold. Real LiveKit lifecycle/JWT replay, shaped packet-flow, BWE downshift/recovery, resource use, SFU-fed first-child behavior, and broader heterogeneous-network acceptance remain open. Use Linux `tc` or an authorized public canary for per-leaf shaping, never CDP throttling.
|
||||
- SFU: production uses one Host publication with exact Viewer subscriptions and no fixed root-count or room-wide lease rule. Browser SFU PCs use the accepted empty-external-ICE-server rule and owner physical media proof closed the reported connection hold. Current production still publishes `q,h`; the accepted single-`HIGH` source/deployment change and its exact physical gate remain open. Real LiveKit lifecycle/JWT replay, resource use, SFU-fed first-child behavior, and broader heterogeneous-network acceptance remain open.
|
||||
- Audio: current v12 source and production select the exact active ordinary Host or SFU publisher audio sender, reset samples across track changes or absence, keep relay children synchronized with persistent-stream audio changes, and reacquire exact SFU publications/senders after reconnect. The reported active-source `1 kbps` observation and all three live ceilings are physically closed on current Chrome/production across direct, browser-relay and SFU. Audible game quality, heterogeneous-network changes and real-game A/V synchronization remain part of route acceptance; a muted/idle Opus track may still legitimately remain near 1 kbps.
|
||||
- Observability: current v12 source and production keep local connection details but no Host/Viewer diagnostic downloads or Browser file-export plumbing. The Host-only bounded snapshot stays for automatic acceptance. Chrome 151 supplied selected candidate endpoints and ordinary-route A/V playout timestamps in the current gate, but omitted the SFU A/V timestamp. Target-browser availability and actual values remain open for codec/fmtp and encoder implementation/power efficiency, media-source and encoded FPS, and broader jitter/concealment cases. All retained fields diagnose and have no recovery authority; they do not by themselves prove hardware encode, synchronization quality, or route quality.
|
||||
- Mobile: Android/iOS remain Viewer-only. Autoplay, rotation, iOS lock-screen/page reclamation, background reconnection, and network changes need device evidence. AirPlay/system mirroring is Viewer-local output, not a portable in-app WebRTC output contract.
|
||||
|
||||
+4
-4
@@ -188,7 +188,7 @@ Viewer 本地连接详情只从当前 route 的唯一 inbound screen video/audio
|
||||
|
||||
`frameRate` 约束和 sender 的 `maxFramerate` 都是目标或上限;浏览器仍控制实际捕获、重复帧处理、编码和拥塞降级。静态画面可能由浏览器减少实际编码数据,但标准没有保证每个实现以同一种方式节省采集或 GPU 开销。本 PoC 不添加画面差分、定时改约束或自定义动态 FPS 状态机,先用 `framesEncoded`、实际发送码率、`totalEncodeTime`、质量受限原因和主机资源占用测量真实问题。
|
||||
|
||||
质量自适应采用 ADR-0007 的 built-in-first 路径隔离双表示,而不是全房间按最差链路降档。Direct/peer 保留每条 PeerConnection 的 stock WebRTC GCC。每条 SFU path 从 `HIGH` ceiling 开始;优先发布共享 `HIGH+LOW` 并让 LiveKit BWE 独立降层和恢复。若该 gate 通过,Screener 不实现媒体层 selector。应用证据只用于诊断。`LOW` 可以常驻;关闭空闲层只是资源优化。active representation/layer 数量硬限制为二,不能按 viewer 增长。标准浏览器不保证跨 PeerConnection 共用一个物理编码器,inactive 层也不保证释放 GPU;实际层数、实例数、CPU/GPU、游戏 FPS/p1 low、区间 encode cost、上传与释放行为必须实测。若没有合格 hardware/power-efficient 路径或额外表示破坏游戏/上传预算,则 fail closed,保留健康路径并明确显示弱路径降级或失败。
|
||||
质量自适应采用 ADR-0007 的路径隔离单表示,而不是全房间按最差链路降档。Direct/peer 保留每条 PeerConnection 的 stock WebRTC GCC。Browser Host 的唯一 SFU publication 发布一层 `HIGH` VP8,不启用 `LOW`、simulcast、Dynacast、SVC 或应用媒体层 selector。Host 到 SFU 的 stock WebRTC 拥塞控制决定该共享 ingress 的实际码率、分辨率和帧率;LiveKit 为每个 Viewer 独立发送下行,但不能从单一编码表示生成另一档画质。应用证据只用于诊断,弱下行不命令 Host 降档或改变拓扑。任何未来 Browser 双表示候选都必须以新决策证明额外表示不挤占 `HIGH` 的上传、编码和游戏预算。
|
||||
|
||||
质量证据只用于诊断,不形成全房分数或 parent authority。路由只消费 exact child edge 的 `failed/closed` 和非暂停 decoded-frame stall。prepare/commit/abort 绑定 authenticated sessions、share generation、base/pending revision 与 candidate connection;candidate child 的第一帧新 decoded video 是唯一应用层 media-ready,ICE connected 不能单独提交。
|
||||
|
||||
@@ -204,15 +204,15 @@ Viewer 本地连接详情只从当前 route 的唯一 inbound screen video/audio
|
||||
|
||||
探针按最小顺序落地:先在 host 同一个采样 tick 内关联 A+B,并携带明确 window、媒体/stats identity 和有效 delta;需要 Viewer 诊断时只增加受限、已鉴权 C 上报。不建设通用遥测 schema,只传派生后的协商字段,绝不上传 raw stats、raw SDP、candidate 地址或原始设备/网络标识;这些字段不产生路由 authority。
|
||||
|
||||
Viewer 可通过已鉴权、绑定当前房间/路径代次的控制面报告需要 `LOW`,但该请求只用于表示诊断,不能命令内建 WebRTC/LiveKit 媒体层或改变拓扑。报告必须限频、去重;UA、平台和设备型号不参与质量或 relay capacity 决策。
|
||||
Viewer 的已鉴权质量证据只描述当前路径,不能命令 WebRTC/LiveKit 改层、改变 Host publication 或改变拓扑。UA、平台和设备型号不参与质量或 relay capacity 决策。
|
||||
|
||||
SVC 的标准能力门禁已经静态关闭为 `no-go-web-svc-cross-path-hardware-contract`。WebRTC-SVC 只配置单个 outgoing sender,direct/peer receiver 没有对应的按层选择 API,独立 PeerConnection 之间也没有 shared-encode 契约;requested/applied codec/`scalabilityMode`、Media Capabilities `powerEfficient` 与 RTCStats encoder 字段不能证明编码器一定是硬件。Pinned LiveKit 虽能在 SFU 内为每个 subscriber 设置最大空间/时间层请求,但实际选择依 codec/selector 而异:server 1.13.5 只为 VP8 安装 temporal selector,当前 H.264 `q,h` simulcast 只有空间层选择。Client 2.22.0 还会把 screen-share SVC 强制成三层 temporal-only `L1T3`,既没有低分辨率 base,也超过最多两层的门槛;这种 SFU 选层也不延伸到 direct/peer descendants。当前静态结论不运行 browser harness。未来只能由能明确锁定硬编、最多两层、跨 direct/peer/SFU 复用同一输出且通过游戏性能/延迟门槛的 native sender 以新决策重开。普通非分层编码包不能只靠转发生成另一档画质,实现路径差异只能用第二表示、合格的 scalable layers 或 relay/SFU 转码。
|
||||
SVC 的标准能力门禁已经静态关闭为 `no-go-web-svc-cross-path-hardware-contract`。WebRTC-SVC 只配置单个 outgoing sender,direct/peer receiver 没有对应的按层选择 API,独立 PeerConnection 之间也没有 shared-encode 契约;requested/applied codec/`scalabilityMode`、Media Capabilities `powerEfficient` 与 RTCStats encoder 字段不能证明编码器一定是硬件。Pinned LiveKit 虽能在 SFU 内为每个 subscriber 设置最大空间/时间层请求,但实际选择依 codec/selector 而异:server 1.13.5 只为 VP8 安装 temporal selector,当前 H.264 `q,h` simulcast 只有空间层选择。Client 2.22.0 还会把 screen-share SVC 强制成三层 temporal-only `L1T3`,违反当前 Browser 无 SVC、单表示合同;这种 SFU 选层也不延伸到 direct/peer descendants。当前静态结论不运行 browser harness。未来只能由能明确锁定硬编、最多两层、跨 direct/peer/SFU 复用同一输出且通过游戏性能/延迟门槛的 native sender 以新决策重开。普通非分层编码包不能只靠转发生成另一档画质,实现路径差异只能用第二表示、合格的 scalable layers 或 relay/SFU 转码。
|
||||
|
||||
质量控制不放宽稳态 outbound media-copy 预算:所有非服务器端点继续受统一静态 capacity 约束;native relay 只转发选定表示的编码包,不解码重编码。后续双树或条带化必须另行验收,不能绕过当前 graph、identity 和 capacity invariant。
|
||||
|
||||
路由状态只有 committed graph 和一个 pending child operation;该对象聚合 candidate list/cursor、一个 current candidate/预留和一个总 deadline。relay 自身 ingress 失效时,它作为 child 进入同一 reparent 并保留 subtree;disconnect 或 effective capacity 降低时让 direct/overflow children 逐个回到 reconcile。多个下游 edge 若各自失效,会独立迁移并自然排空 relay。权威 pause abort operation、保持 active graph、抑制 stall;resume 重新 reconcile。
|
||||
|
||||
标准表示能力排在任何自定义双表示媒体实现之前。当前 Web P2P simulcast 缺少 receiver 选 RID 与跨 PeerConnection shared-encode 契约;当前 Web/LiveKit SVC 也缺少 direct/peer 独立选层和可移植硬件保证。Production 的 exactly-two screen-share simulcast 与 `dynacast: false` 只是实现和质量实验事实,不证明 root topology、publication accounting 或 subscriber model。具体表示门槛由 ADR-0007 和[实时质量调研](./research/realtime-quality-adaptation.md)持有,不得绕过 stock WebRTC congestion control。
|
||||
标准表示能力排在任何自定义双表示媒体实现之前。当前 Web P2P simulcast 缺少 receiver 选 RID 与跨 PeerConnection shared-encode 契约;当前 Web/LiveKit SVC 也缺少 direct/peer 独立选层和可移植硬件保证。Browser SFU 因此只发布单层 `HIGH`;具体表示门槛由 ADR-0007 和[实时质量调研](./research/realtime-quality-adaptation.md)持有,不得绕过 stock WebRTC congestion control。
|
||||
|
||||
## 移动分享端能力边界与排期
|
||||
|
||||
|
||||
+6
-6
@@ -28,7 +28,7 @@ SFU 的 publication、subscription、server-resource accounting、临时 overlap
|
||||
- P2P 优先:每条普通逻辑媒体边先尝试 direct/peer UDP,服务器不得默认中转可直连媒体。更多观看者优先沿满足统一端点容量的无环 peer 图分布;每名 Viewer 同时至多一个 active upstream,失败时只影响需要重选的 child。任何 source-reachable endpoint 在 effective capacity 有空位时都可作为 parent candidate;Peer-fed 与 SFU-fed endpoint 使用同一个 provisional-child transaction,并在 candidate child 解码出第一帧新画面后独立提交该 edge。Host 已满且首次需要 SFU 时,同一 reconcile 将 affected Host direct child(若无则稳定顺序中最新的 connected Host direct child)作为本次 child operation,创建唯一 Host publication 并把该 child 变为首个 SFU subscriber,subtree 不动;publication 取代释放的 Host peer slot,下一次扫描再处理原受限 Viewer,不建立 bootstrap 状态机。
|
||||
- NAT 与传输边界:STUN 必须可用,所有 ordinary peer `RTCPeerConnection` 只接收 STUN ICE servers。Browser LiveKit publisher/subscriber PC 必须显式使用空 `iceServers`,保留 LiveKit signaling 交付的授权 SFU UDP candidates,并由标准 ICE 选择 nominated non-relay pair;不得把 ordinary-peer STUN、LiveKit join response 中的 STUN 或默认公共 STUN混入该 PC,也不得把某一种 candidate type 或数量写成成功条件。部署 STUN 仍供 ordinary peers 和 LiveKit server-side 公网地址发现使用。浏览器 ICE connectivity checks 是 direct UDP 可达性的权威;Screener 不合成 remote candidate、不预测端口、不分类 NAT,也不使用 TCP 探测推断 UDP 媒体可达性。所有恢复和候选授权必须绑定 authenticated room/endpoint session、share generation、base/pending route revision 与 candidate connection identity;成功即停止,失败、超时或绑定失效即撤销,direct 阶段耗尽后在同一 operation deadline 内进入 SFU/UDP,全部可用路径耗尽后明确等待或失败。已接受的完整顺序只有保持或尝试 direct/STUN peers,再复用或建立 direct-ingress Host publication/SFU subscription。Screener 不配置 TURN、ICE/TCP、media TCP 或 TLS-relayed media;当前 LiveKit 也保持 UDP-only。未来若真实严格防火墙矩阵证明需要另一种传输,必须把它作为 LiveKit 内部能力重新决策,不能增加第三种应用 route candidate。LiveKit join JWT 仅按协议进入不得记录的 WebSocket request target;HTTPS/WSS 继续独立使用 TLS/TCP。
|
||||
- 质量控制:推荐档位始终只有 1080p60(8 Mbps)、1080p30(5 Mbps)、720p30(3 Mbps)三档,默认选择中档 `1080p30`。高级设置的分辨率选项增加 `480p`(854x480),其 FPS 与码率仍由高级控件独立选择;不增加 `480p` 推荐档、preset ID 或固定的 480p FPS/码率组合。三档与高级设置初始值统一采用 `balanced`(平衡),`maintain-resolution`(清晰优先)、`maintain-framerate`(流畅优先)保留为显式选择。Browser 视频固定使用 VP8;界面、质量状态和 wire 不提供 codec 选择或切换。分享期间可直接换视频档位和 64/128/256 kbps 音频 sender ceiling,不重新选择来源或重建健康连接。Peer-assisted relay 与已配置的 SFU 必须接收同一个严格校验的房间级权威设置,覆盖当前和以后建立的 sender;普通 P2P 信令结构保持不变。任何设置都只是浏览器上限和偏好,具体降级由浏览器决定;必须读回实际 sender 参数并通过 stats 观测结果、显示参数拒绝、改写和持续受限原因。不做自定义动态 FPS、综合评分或周期性全房间调档。
|
||||
- 路径隔离双表示:direct/peer 继续使用每条 PeerConnection 独立的 stock WebRTC GCC,不把 viewer 反馈合成全房目标。每条 SFU path 从 `HIGH` ceiling 开始;优先使用 pinned LiveKit 的标准两层 screen-share simulcast,让内建 per-subscriber BWE 独立降层和恢复,Screener 不实现媒体层 selector。应用只诊断实际接收层、硬件编码、游戏性能、资源和上传;SFU 自动降层不改变拓扑。`LOW` 停编只是资源优化,active representation/layer 硬上限为二且不随 viewer 增长。当前 Web P2P simulcast 与 Web/LiveKit SVC 不能证明跨 direct/peer 共享编码或可移植硬件路径;全部标准路径失败后才考虑 custom/native dual encode。
|
||||
- 路径隔离表示:direct/peer 继续使用每条 PeerConnection 独立的 stock WebRTC GCC,不把 viewer 反馈合成全房目标。Browser Host 的唯一 SFU publication 只发送一层 `HIGH` VP8;不启用 `LOW`、simulcast、Dynacast、SVC 或应用媒体层 selector。SFU 每个 Viewer 的独立下行仍由 LiveKit/WebRTC 拥塞控制,弱下行不能命令 Host 降档或改变拓扑;单一编码表示也不能凭转发生成第二档画质。任何 Browser 双表示候选必须先以新决策证明不会挤占 `HIGH` 的上传、编码和游戏预算。
|
||||
- 路由失效输入:应用不推断 parent-wide 质量,也不计算综合分数。当前 authenticated child 只在 PeerConnection `failed/closed`,或非权威暂停时现有 periodic stats 在统一 deadline 内没有新 decoded frame 时,使自己的 exact edge 失效并唤醒同一个 reconcile。decoded progress 只保存 route-keyed `lastDecodedAt`,route/connection变化或新帧重置、暂停抑制,同一 edge只报告一次,不增加轮询器。该 operation 把失败的 exact direct parent 在当前 fact version 直接视为已尝试,先选择其他 direct parent,再进入有界 SFU suffix;新的外部事实才允许原 direct tuple 重新进入。Track availability、低码率、低 FPS、模糊、sender/viewer stats 与 SFU layer只用于stock WebRTC/LiveKit恢复和诊断。relay自身ingress失效时,它作为child换父并保留subtree;disconnect或effective downstream capacity降低只让direct/overflow children逐个走同一事务。
|
||||
- 断线恢复:临时网络变化先交给 WebRTC/LiveKit 的 ICE、consent、重连和流状态。Direct edge 可在 exact current parent/child sessions 内采用 framework rebuild 的新 connection ID而不改变topology。应用只在上述exact edge失效后运行一次有界reconcile;任一步成功即停止。候选耗尽时hard-invalid、confirmed-departed或overflow edge被退休并进入明确waiting,healthy bootstrap edge保留。所有异步结果受authenticated session、share generation、base/pending route revision与candidate connection identity约束,未受影响分支保持sticky。权威暂停abort未提交candidate、保留active graph、抑制stall,并在resume后重新reconcile。
|
||||
- 同一 operation 的一个总 deadline 只按实际存在的 `direct | sfu` 语义阶段等分,不配置每个 candidate 的 magic timeout。阶段内的硬失败继续推进 cursor;silent ICE 到达 direct 阶段边界时跳过剩余 direct tuple,必须把派生份额留给 SFU。20 名 Viewer 同时加入时,每名 child 的 operation deadline 不会被人数除分,但单一 room-serial operation 可能形成线性排队尾延迟;在接受另一种并发模型前,只测量 queue wait、candidate start、first decoded frame 与 final route 的 p50/p95/max,不用 NAT 猜测、TCP probe 或 magic timeout 绕过排队。
|
||||
@@ -50,9 +50,9 @@ SFU 的 publication、subscription、server-resource accounting、临时 overlap
|
||||
- SFU 质量设置生命周期:直播中修改档位时,浏览器 sender 的 applied readback、LiveKit `LocalVideoTrack` 保存的 degradation preference、track restart options 与 `LocalTrackPublication` 的 republish options 必须作为同一次串行操作更新;任一步失败恢复旧 sender 与旧 SDK 保存态,旧 publication generation 不得回写当前状态。LiveKit full reconnect/republish 不得恢复初次发布的旧偏好。该修复不改变 codec、码率上限、层数或路由,也不能单独解释即时低帧。
|
||||
- 本地预览性能候选:在相同动态场景中 A/B 测量 Host 动态预览开/关的 CPU、GPU、encode time 和实际 FPS。只有稳定收益且捕获、编码和远端画面不受影响时,才允许直播开始后默认显示静止缩略图或隐藏动态预览并提供按需展开;未测前不宣称收益。
|
||||
- Peer-assisted 媒体路径:所有非服务器 endpoint 都受同一个服务端权威稳态 outbound media-copy capacity 约束,默认 `2` 且可静态配置为 `1`、`2` 或 `3`;peer child 与 Host publication 都按实际发送副本计数。每名 Viewer 任一时刻只有一个 active upstream,活动媒体图保持无环;只在离散事件中做有界分配或换父。浏览器把收到的标准 remote track 加入独立下游 `RTCPeerConnection` 时会逐跳解码并分别重编码,必须测量而不能称为 shared encode。服务端只在有界房间内存中保存严格校验的质量设置,不写入持久存储。
|
||||
- 原生 shared encode 分享端:后续独立的 Electron/原生分享端必须让每个 active representation 只产生一份兼容编码结果,并在 direct、peer 与 SFU transport 间复用;健康路径选择共享 `HIGH`,最多另有一份弱路径共用的 `LOW`,是否常驻由硬件、游戏和上传门槛决定。每条连接仍保留独立 WebRTC packetization、SSRC、pacing、加密和反馈,且各自消耗上传带宽。浏览器不保证跨 `RTCPeerConnection` 复用编码器,因此当前 Web spike 不能宣称满足该保证。
|
||||
- 原生 shared encode 分享端:后续独立的 Electron/原生分享端若获新决策,必须让每个 active representation 只产生一份兼容编码结果,并在获准的 direct、peer 与 SFU transport 间复用。第二表示不属于当前合同,只有明确硬件路径和真实游戏、编码、上传门槛通过后才可重开。每条连接仍保留独立 WebRTC packetization、SSRC、pacing、加密和反馈,且各自消耗上传带宽。浏览器不保证跨 `RTCPeerConnection` 复用编码器,因此当前 Web spike 不能宣称满足该保证。
|
||||
- 原生 shared encode relay:具备原生 relay 能力的非服务器端点同样受统一服务端权威下游容量约束,并应复用兼容编码输出而不再次编码。当前普通浏览器 relay 使用逐边重编码的标准 WebRTC 路径,不伪称 shared encode。
|
||||
- SVC 重开条件:当前标准 Web/LiveKit SVC 已静态拒绝为 `no-go-web-svc-cross-path-hardware-contract`。sender `scalabilityMode` 没有 direct/peer receiver 对应的按层选择或跨 PeerConnection shared-encode 契约;requested/applied mode、Media Capabilities `powerEfficient` 和 RTCStats encoder 字段也不能证明没有静默软件 fallback。Pinned client 2.22.0 还会把 screen-share SVC 覆盖为三层 temporal-only `L1T3`,不满足低分辨率 base 与最多两层。只有未来 native sender 能明确选择硬件编码器、最多发布两层、将同一编码输出复用于 direct/peer/SFU、保持每条路径独立选择并通过真实游戏和亚秒延迟门槛时,才可用新的 capability decision 重开 SVC;不能把浏览器 API 支持或 UA 推断当成采用理由。
|
||||
- SVC 重开条件:当前标准 Web/LiveKit SVC 已静态拒绝为 `no-go-web-svc-cross-path-hardware-contract`。sender `scalabilityMode` 没有 direct/peer receiver 对应的按层选择或跨 PeerConnection shared-encode 契约;requested/applied mode、Media Capabilities `powerEfficient` 和 RTCStats encoder 字段也不能证明没有静默软件 fallback。Pinned client 2.22.0 还会把 screen-share SVC 覆盖为三层 temporal-only `L1T3`,违反当前 Browser 无 SVC、单表示合同。只有未来 native sender 能明确选择硬件编码器、最多发布两层、将同一编码输出复用于 direct/peer/SFU、保持每条路径独立选择并通过真实游戏和亚秒延迟门槛时,才可用新的 capability decision 重开 SVC;不能把浏览器 API 支持或 UA 推断当成采用理由。
|
||||
- 分包/分层多树实验:把编码包、对象或可独立解码层拆到多个 peer 路径以分散上传,只能在独立 spike 中验证。必须保持亚秒级,处理多父重组、排序、丢包恢复、关键帧、同步和节点退出;未通过门槛前不进入产品路由控制器。
|
||||
- SFU 中央兜底:产品部署提供有界 SFU 资源,但不要求用户选模式,也不得默认变成整房 always-SFU。只有 Host 拥有一个 authoritative publication;SFU-fed 与 peer-fed endpoint 使用同一个 provisional-child first-frame transaction,严格受限 endpoint 在没有成功 child candidate 时自然保持 leaf。启用 LiveKit fallback 时必须使用专用且关闭 `room.auto_create` 的实例,并显式提供私有 `LIVEKIT_API_URL`、无默认值的正整数 `SFU_INGRESS_CAPACITY` 与 `SFU_EGRESS_CAPACITY`。单进程全局账本按 exact room/share/publication 保存一份 Host publication ingress,并在该 generation 下按 exact Viewer 保存 subscription egress;当前 publication 被后续 SFU Viewer 复用,每个 child candidate 只 reserve/commit 自己的 subscription。一份 publication 占一个 ingress,每份 reserved、committed 或 draining subscription 占一个 egress;离开 route 的 subscription 在整个 publication room 删除并确认 absent 前仍作为 draining 计费,同一 Viewer handle 再次启用不重复计数。新 generation 在发 token 前 reserve publication 与首个 subscription,并先通过 RoomService 创建对应 room;first-frame ready同步commit admission后才promote graph。publication replacement、abort、timeout、disconnect、share rollover、room stop/delete按资源差集或controller `dispose()`进入draining,只有DeleteRoom成功和absent readback才释放该generation的ingress/egress。启动时必须先拒绝外来room、清除全部遗留Screener room并确认namespace为空;Host信令离线但LiveKit participant仍存在时继续保留和计费,participant消失后有界回收。实际因deployment-wide admission失败的房间只进入一个waiter Set;LiveKit drain完成时一次性touch这些controller的external fact并走普通reconcile,不轮询。固定root数和普通endpoint child数不能代替准入;资源耗尽进入明确waiting或failure。多应用进程部署必须先引入共享原子owner。
|
||||
- 分享端桌面封装:用 Electron 固定 Chromium 版本、改善选源/热键/系统音频体验,同时保留 Web 观看端。
|
||||
@@ -151,14 +151,14 @@ SFU 的 publication、subscription、server-resource accounting、临时 overlap
|
||||
### 质量和恢复
|
||||
|
||||
- Given 用户选择任一推荐档位或高级质量参数,When 接收端实际分辨率、帧率或码率持续显著低于该目标,Then 诊断数据能区分采集约束、发送编码、带宽/拥塞、当前 peer/SFU 路径和接收端限制;产品不得只改变档位标签却继续隐藏实际降级。
|
||||
- Given 一个健康 SFU leaf 和一个受控弱 SFU leaf 都以 `HIGH` ceiling 订阅,When 内建 LiveKit BWE 运行,Then 弱 leaf 自动使用唯一共享 `LOW` 并在恢复后回到 `HIGH`,健康 leaf 不受影响,且 Screener 没有实现媒体层 selector;direct/peer 继续使用各自的 stock WebRTC GCC。
|
||||
- Given Browser Host 建立 SFU publication,When sender 参数和 RTCStats 可读,Then 只存在一个 VP8 outbound video encoding,不出现 `q,h` RID simulcast 或第二表示;弱下行只由 stock LiveKit/WebRTC 传输适应,不能改变 Host publication、健康路径或拓扑,direct/peer 继续使用各自的 stock WebRTC GCC。
|
||||
- Given 当前 Viewer 的 exact edge 进入 `failed/closed`,或在非权威暂停时超过统一 deadline 没有新 decoded frame,When 服务端确认 authenticated child、share generation、active revision 与 connection identity 仍匹配,Then 只把该 child 送入同一个 reserve/prepare/first-frame/commit-or-abort 事务;低码率、低 FPS、模糊和 SFU layer 只进入诊断。
|
||||
- Given 当前 edge 仍在解码但分辨率、FPS、码率、freeze ratio、RTT、jitter、loss 或 limitation evidence 持续影响观感,When 评估是否自动换父,Then 当前产品只诊断而不迁移:现有路径证据不能证明未连接 parent 的反事实质量,WebRTC/LiveKit 继续拥有拥塞适应,应用不建立 alternative-parent probe、hysteresis/cooldown、加权分数或周期性重排。
|
||||
- Given 同一 Viewer 同时是某人的 child 和其他人的 parent,When 自身 ingress 失效,Then 它作为 child 换父、在新 ingress 首帧提交前保留可用旧 edge,并保持 subtree。Given endpoint disconnect 或 `effectiveDownstreamCapacity` 降低,Then controller 只保留稳定顺序内可容纳的 children,并将 deterministic overflow children 逐个送入同一事务;childless 后删除 disconnected relay。
|
||||
- Given 当前分享权威 paused,When 新 Viewer 加入、edge 失效或已有 child operation 尚未提交,Then abort 整个 pending route operation 及其 current candidate/预留、保留 active graph、让新 Viewer waiting,并且不因没有 decoded frame 触发恢复。普通 Pause/Resume 只通过当前 Host session 与 `shareGeneration` 约束的一次 paused-state 更新同步本地 capture tracks、服务端快照、`host-status` 和 route pause;Resume 重新启用同一批 tracks并从当前 graph 唤醒 fresh reconciliation,不建立第二次授权、source acknowledgement、媒体 proof 或回滚状态。较早 share generation、已替换 Host session、stop 或新分享的迟到更新不得改变当前状态。
|
||||
- Given exactly-two publication 的实测 encoder/CPU/GPU 或上传成本超过游戏预算,或没有合格 hardware/power-efficient 路径,When 评估该候选,Then 保留健康路径并明确显示弱路径降级或不可用,不得退回全房间最低目标或静默软件编码;若 supported sender cohort 无法以常驻或按需方式提供共享 `LOW`,Then 质量验收失败,必须优化编码路径或明确标记不支持。
|
||||
- Given 当前 Browser SFU publication,When 进行质量验收,Then 第二表示的 frames/bytes 必须不存在;公开 SFU 路径若受带宽限制,只如实显示 stock transport 的降级或不可用,不得恢复 `LOW`、退回全房间最低目标或增加应用媒体层 controller。
|
||||
- Given 同一时刻采集、host outbound 与 viewer inbound 证据,When 进行根因分类,Then 关联派生后的实际协商视频 codec/profile/parameters、适用时的 `scalabilityMode` 与真实解码表现,依次区分 Capture 低、Capture 高但 outbound 因 CPU 低、Capture 高但 outbound 因 bandwidth 低、outbound 正常但 inbound 低、以及 inbound 正常但肉眼模糊五类;不用 UA 或设备型号代替运行时证据,也不上传 raw SDP。
|
||||
- Given Viewer 发送低档请求,When 请求未鉴权、过频、重复、过期或没有匹配的 sender/viewer 统计,Then 请求不改变表示或路径状态;有效请求也只能作为交叉验证输入。
|
||||
- Given Viewer 上报当前路径质量证据,When 报告未鉴权、过频、重复、过期或没有匹配的 sender/viewer 统计,Then 报告被丢弃;有效报告也只能用于诊断,不能改变 Host 表示或路径状态。
|
||||
- Given 受控 RTT/丢包测试条件,When 连续分享高动态游戏画面 30 分钟,Then 延迟、帧率与丢帧达到上述目标,且没有不可恢复的冻结。
|
||||
- Given Windows Chrome/Edge Browser Host 开始或继续分享,When 浏览器返回 display video track,Then 应用不赋任何视频 `contentHint`,并按浏览器 stats 如实显示实际 RTP codec 与实现字段。Given 已接受的 `screener-v12` 建立 direct 或 browser-relay sender,Then offer 的唯一视频媒体 codec 是 VP8;RTX/RED/FEC 只可作为修复格式,不能引入另一媒体 codec。若浏览器缺少 VP8 capability、`setCodecPreferences()` 或应用失败,Then 在创建 offer 前明确失败而不是静默协商其他 codec。Given 建立 SFU publication,Then LiveKit 固定使用 VP8 且不启用 backup codec。
|
||||
- Given 分享过程中切换 Wi-Fi/有线网络,When ICE 连接失败,Then 客户端触发 ICE restart,并在成功或超时后给出明确状态。
|
||||
|
||||
Reference in new issue
Block a user