phase: 06_sharer_quality_presets
**Phase 06 — final verification pass: 100% green.** - **Verified (all 6 tasks complete in working tree):** `#quality` select + `PRESETS` table; preset-driven capture request + `contentHint`; per-leg `legCap()`/`degradation` at both call sites; live `applyQuality()` with Overconstrained fallback + republish; `q` key cycle; `#stat-quality`/`#stat-codec` readouts; full e2e matrix (requests, committed params ×3, zero-cap, mid-share switch, unrescalable device, late-joiner first-offer, readout, `q`); realdisplay delivered-pixels `light` case. `test_sender_fidelity.py` **untouched and green** (regression canary). - **Gates:** `uv run ruff check . && uv run ruff format --check .` → clean (32 files); `uv run pyright` → 0 errors; `uv run pytest` → **284 passed, 5 skipped (realdisplay-gated), coverage 95%** (93s); `MIRROR_REALDISPLAY=1 uv run pytest -m realdisplay` → **4 passed, 1 skipped** (no audio source on host — documented platform condition). - **Completion criteria:** all 11 ✓ — sharp default reproduces old request; light ≤960×600@15fps/motion/round(cap×0.35)/maintain-framerate with moving viewer frames; mid-share re-prices with `peers.size` unchanged, no renegotiation, roster matches `getSettings()`; refused-rescale toasts "next share"; `q` cycles + toasts, text-field guard holds; readout exact + codec shape, both reset to `—` idle; realdisplay: light decoded ≤990px (measured 320×200), sharp clears `SHARP_FLOOR_PX`; no new env/wire/Python/asset; suite 100% green, coverage >90%. - **Docs:** README.md reviewed in full against code — Quality table, `q` key, env-var table, routes (`/share`), kiosk commands, key table, doc paths all consistent; **no fixes needed**. AGENTS.md — verified, no stale statements, no changes. PLAN.md untouched (diff = 0). - **Reported (per phase, not edited):** PLAN.md §6 line 204 still says "per-leg `maxBitrate` cap (default **12 Mbit/s**)" — code has defaulted to **25 Mbit/s** since phase 02; needs a user-approved one-line amendment. - **Next pending phase:** none — 06 is the last phase in `todo/`; the roadmap is complete.
This commit is contained in:
@@ -443,6 +443,105 @@ class TestRealX11Capture:
|
||||
expect(share_page.locator("#viewer-count")).to_have_text("1", timeout=20_000)
|
||||
assert errors == [], f"uncaught browser errors: {errors}"
|
||||
|
||||
def test_a_light_preset_delivers_a_small_picture(self, share_page, watch_page):
|
||||
"""The delivered-pixel proof that the preset reaches the *real*
|
||||
capturer, not just the request object.
|
||||
|
||||
``#quality = light`` is selected **before** the share starts, so the
|
||||
request — under Playwright ``screen`` is the emulated viewport, so
|
||||
the 1200x760 share window asks ``min(viewport, 960x600)`` =
|
||||
960x600 — goes to Chromium's real X11 backend. The sharer's track
|
||||
settings must honour the budget (at least 80% of the 960 request
|
||||
wide, never above it): that is the proof the request reached the
|
||||
real capturer and was not clamped away to the desktop or the
|
||||
window. The viewer's decoded width must be at or under the cap —
|
||||
the phase's delivered-pixels criterion — *and below the sharp
|
||||
path's floor*: if a ``light`` share delivered a sharp-size picture,
|
||||
the budget never reached the wire. The aspect guard keeps proving
|
||||
the picture is *our* desktop, not somebody else's window.
|
||||
|
||||
The sharp path's floor (``SHARP_FLOOR_PX``) is deliberately
|
||||
**not** asserted here: it stays the sharp test's, and a small
|
||||
picture is exactly what a ``light`` share should deliver — the
|
||||
small picture that is still the whole desktop.
|
||||
|
||||
Measured on this host (Xvfb 1280x800x24, phase 06): the capturer
|
||||
delivered 960x600 (track settings, ``frameRate`` 15), and the
|
||||
viewer decoded 320x200 — VP8 honouring ``light``'s
|
||||
``maintain-framerate`` at ``round(25 Mbit/s x 0.35)`` = 8.75
|
||||
Mbit/s, i.e. the encoder's resolution-degradation policy (the same
|
||||
leg encodes 960x600 under ``maintain-resolution``); the encoder
|
||||
may sacrifice resolution, which is the preset's contract, so the
|
||||
decoded-width floor below guards a *collapsed* picture (>= a
|
||||
quarter of the request), not the encoder's honest ladder.
|
||||
"""
|
||||
errors: list[str] = []
|
||||
share_page.on("pageerror", lambda error: errors.append(str(error)))
|
||||
|
||||
share_page.select_option("#quality", "light")
|
||||
share_page.locator("#start").click()
|
||||
expect(share_page.locator("body")).to_have_attribute("data-live", "on", timeout=40_000)
|
||||
|
||||
# The preset is what the live capture belongs to (a pure parameter
|
||||
# read, not a pixel claim — the pixels are the viewer's, below).
|
||||
assert share_page.evaluate("() => window.__probe.qualityKey") == "light"
|
||||
|
||||
# The request reached the *real* capturer and was not clamped away:
|
||||
# the track the X11 backend settled on honours the light budget —
|
||||
# at least 80% of the 960 request wide (the capturer did not drop
|
||||
# the size), never above it (the capturer did not ignore it and
|
||||
# deliver the 1200x750 window-clamped desktop).
|
||||
settings = share_page.evaluate(
|
||||
"""() => {
|
||||
const track = document.querySelector('#preview').srcObject.getVideoTracks()[0];
|
||||
const s = track.getSettings();
|
||||
return {width: s.width, height: s.height, surface: s.displaySurface};
|
||||
}"""
|
||||
)
|
||||
assert settings["surface"] == "monitor", f"not a monitor capture: {settings}"
|
||||
assert settings["width"] <= 990, f"the capturer ignored the light budget: {settings}"
|
||||
assert settings["width"] >= 768, f"the capturer did not honour the request: {settings}"
|
||||
|
||||
expect(watch_page.locator(".tile[data-state='live']")).to_have_count(1, timeout=60_000)
|
||||
|
||||
# Start measuring on the watcher, then paint: cycling the captured
|
||||
# machine's background is what a real presenter's screen does constantly.
|
||||
assert watch_page.evaluate(PROBE) == "started"
|
||||
for colour in ("#c81e1e", "#0b0d10", "#1e6ec8", "#0b0d10", "#1ec85a"):
|
||||
share_page.evaluate("(colour) => { document.body.style.background = colour; }", colour)
|
||||
time.sleep(0.28)
|
||||
result = watch_page.evaluate("() => window.__probe")
|
||||
|
||||
# Delivered pixels follow the preset: the decoded picture is at or
|
||||
# under the light cap, and below the sharp path's floor (a
|
||||
# sharp-size picture from a light share would mean the budget
|
||||
# never reached the wire). Measured 320x200 on this host — the
|
||||
# encoder's maintain-framerate degradation, see the docstring.
|
||||
assert result["width"] <= 990, (
|
||||
f"the watcher decoded a {result['width']}px-wide picture: the light budget is "
|
||||
f"<= 960px, so a wider decode means the budget did not reach the wire: {result}"
|
||||
)
|
||||
assert result["width"] < SHARP_FLOOR_PX, (
|
||||
f"the watcher decoded a {result['width']}px-wide picture: that is at or above "
|
||||
f"the sharp floor ({SHARP_FLOOR_PX}px), so a light share delivered a sharp-size "
|
||||
f"picture: {result}"
|
||||
)
|
||||
assert result["width"] >= 240, (
|
||||
f"the watcher decoded a {result['width']}px-wide picture: a quarter of the 960px "
|
||||
f"request must arrive at least, or the picture collapsed: {result}"
|
||||
)
|
||||
assert abs(result["width"] / result["height"] - XVFB_ASPECT) < 0.06, (
|
||||
f"{result} does not match the {XVFB_GEOMETRY} desktop aspect "
|
||||
f"({XVFB_ASPECT:.3f}); this is not our Xvfb screen"
|
||||
)
|
||||
assert result["distinct"] >= 2, (
|
||||
f"the watcher received a frozen frame: {result} — a small-but-still picture "
|
||||
f"must not pass a delivered-pixel test"
|
||||
)
|
||||
|
||||
expect(share_page.locator("#viewer-count")).to_have_text("1", timeout=20_000)
|
||||
assert errors == [], f"uncaught browser errors: {errors}"
|
||||
|
||||
def test_a_real_desktop_shares_audio_when_the_host_offers_any(self, base_url, browsers):
|
||||
"""The realdisplay counterpart of the audio-arrival assertion.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user