feat(host/windows): two-process mux test toggle + live-validate step 5
PUNKTFUNK_SECURE_TEST_PERIOD_MS=N drives a square-wave secure/normal toggle in
virtual_stream_relay (instead of the real DesktopWatcher), to exercise the
mid-session helper↔DDA mux without a live UAC/lock. Gated behind the env var,
in the style of PUNKTFUNK_VIDEO_DROP / PUNKTFUNK_FEC_PCT.
Live-validated on the RTX 4090 (host as SYSTEM): with a 4s toggle the mux
switched secure(DDA)↔normal(WGC relay) cleanly 5× in one session and the client
decoded 308 HEVC Main-10 frames continuously across every switch — the
wait-for-IDR latch held with no decode break. The real Winlogon DDA capture is
pre-proven by the single-process secure path (f4b4a6c); the toggle exercises the
new surface (the mux). Doc updated with the validation + the SYSTEM-mode audio
caveat.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -2345,6 +2345,14 @@ fn virtual_stream_relay(
|
|||||||
|
|
||||||
// The authoritative Default↔Winlogon signal (requires SYSTEM to read the Winlogon desktop name).
|
// The authoritative Default↔Winlogon signal (requires SYSTEM to read the Winlogon desktop name).
|
||||||
let watcher = crate::capture::desktop_watch::DesktopWatcher::start();
|
let watcher = crate::capture::desktop_watch::DesktopWatcher::start();
|
||||||
|
// Test hook: PUNKTFUNK_SECURE_TEST_PERIOD_MS=N drives a square-wave secure/normal toggle every N ms
|
||||||
|
// instead of the real watcher — exercises the mid-session helper↔DDA mux without a live UAC/lock
|
||||||
|
// (the real Winlogon DDA capture is already proven by the single-process secure path).
|
||||||
|
let secure_test_ms: Option<u128> = std::env::var("PUNKTFUNK_SECURE_TEST_PERIOD_MS")
|
||||||
|
.ok()
|
||||||
|
.and_then(|s| s.parse().ok())
|
||||||
|
.filter(|&n| n > 0);
|
||||||
|
let start = std::time::Instant::now();
|
||||||
|
|
||||||
let mut interval = std::time::Duration::from_secs_f64(1.0 / effective_hz.max(1) as f64);
|
let mut interval = std::time::Duration::from_secs_f64(1.0 / effective_hz.max(1) as f64);
|
||||||
let deadline = std::time::Instant::now() + std::time::Duration::from_secs(seconds as u64);
|
let deadline = std::time::Instant::now() + std::time::Duration::from_secs(seconds as u64);
|
||||||
@@ -2420,7 +2428,10 @@ fn virtual_stream_relay(
|
|||||||
// Source mux: capture the secure (Winlogon) desktop via the host's DDA, the normal desktop via
|
// Source mux: capture the secure (Winlogon) desktop via the host's DDA, the normal desktop via
|
||||||
// the helper relay. On a switch, latch await_idr + force the now-active source to emit an IDR
|
// the helper relay. On a switch, latch await_idr + force the now-active source to emit an IDR
|
||||||
// so the client resumes cleanly.
|
// so the client resumes cleanly.
|
||||||
let secure = watcher.is_secure();
|
let secure = match secure_test_ms {
|
||||||
|
Some(p) => (start.elapsed().as_millis() / p) % 2 == 1,
|
||||||
|
None => watcher.is_secure(),
|
||||||
|
};
|
||||||
if secure != on_secure {
|
if secure != on_secure {
|
||||||
on_secure = secure;
|
on_secure = secure;
|
||||||
await_idr = true;
|
await_idr = true;
|
||||||
|
|||||||
@@ -16,15 +16,26 @@ Implemented so far:
|
|||||||
helper relay on `Default`, the host's own DDA capturer+encoder on `Winlogon`; every switch latches
|
helper relay on `Default`, the host's own DDA capturer+encoder on `Winlogon`; every switch latches
|
||||||
"wait for IDR" + forces the now-active source to emit a keyframe.
|
"wait for IDR" + forces the now-active source to emit a keyframe.
|
||||||
|
|
||||||
|
**Live-validated on the RTX 4090 (2026-06-16, host as SYSTEM):**
|
||||||
|
- Step 4: the helper spawns via `CreateProcessAsUserW`, runs WGC with no hang (HDR FP16 BT.2020 PQ),
|
||||||
|
opens NVENC (D3D11 Main10), and relays AUs — `client-rs` over the LAN decoded 411 HEVC Main-10
|
||||||
|
frames. (Bug found+fixed: `CreateProcessAsUserW` gave the helper the *user's* env, dropping
|
||||||
|
`PUNKTFUNK_ENCODER=nvenc` → software-encoder fallback; fixed by `merged_env_block`.)
|
||||||
|
- Step 5: with `PUNKTFUNK_SECURE_TEST_PERIOD_MS=4000` driving a square-wave toggle, the source mux
|
||||||
|
switched `secure(DDA)`↔`normal(WGC relay)` cleanly 5× in one session; the client decoded 308 frames
|
||||||
|
continuously across every switch (the wait-for-IDR latch held — no decode break). The real Winlogon
|
||||||
|
DDA capture itself is pre-proven by the single-process secure path (commit `f4b4a6c`); step 5's new
|
||||||
|
surface is the mux, which the toggle exercises directly.
|
||||||
|
|
||||||
Remaining: **step 6** (helper relaunch watchdog on console connect/disconnect + crash, then a
|
Remaining: **step 6** (helper relaunch watchdog on console connect/disconnect + crash, then a
|
||||||
lock/unlock+UAC soak) and **step 2** (SendInput retry-on-failure refactor — input works today via the
|
lock/unlock+UAC soak) and **step 2** (SendInput retry-on-failure refactor — input works today via the
|
||||||
existing path; this hardens it across the desktop boundary).
|
existing path; this hardens it across the desktop boundary). Also a **final user-driven smoke test**:
|
||||||
|
trigger a *real* UAC/lock on the box during a session and confirm the dialog appears on the client
|
||||||
|
(the box's UAC auto-elevates admins, so a real prompt can't be triggered headless over SSH).
|
||||||
|
|
||||||
Live validation to run when the box is up (single session, host as SYSTEM via the `-s -i 1` scheduled
|
> **Note:** the two-process path requires the host to run as SYSTEM (`run.cmd.sysbak` → `-s -i 1`).
|
||||||
task): connect a client → confirm video via the helper relay on the normal desktop (host log
|
> As SYSTEM, WASAPI loopback audio (session 0) does not capture the user session's audio — a known
|
||||||
`source switch … normal(WGC relay)` + `WGC helper spawned`), trigger a UAC prompt → the stream shows
|
> limitation of SYSTEM-mode capture, separate from this work.
|
||||||
the UAC dialog (host log `source switch … secure(DDA)`), dismiss → back to the helper; the QUIC
|
|
||||||
session stays up throughout.
|
|
||||||
|
|
||||||
## The constraint (verified live on the RTX 4090)
|
## The constraint (verified live on the RTX 4090)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user