feat: M3 — lumen/1 native streaming: real video at client mode + input over QUIC datagrams
The native protocol now does the real thing, end to end: - Hello carries the client's requested mode; the host creates a NATIVE virtual output at exactly that size/refresh (same vdisplay backends as the GameStream path) and streams NVENC HEVC through the M1 Session (GF(2^16) Leopard FEC + AES-GCM, QUIC-negotiated). - Input rides QUIC DATAGRAMS — encrypted, congestion-managed, no ENet retransmission spikes — decoded into lumen_core InputEvents and fed to the session's input injector. - Frames are stamped with the capture wall clock; the reference client computes per-frame capture→reassembled latency percentiles and writes a playable .h265. - m3-host gains --source synthetic|virtual + --seconds; the client gains --mode WxHxFPS, --out, --input-test (scripted mouse/keyboard datagrams). VALIDATED live (gamescope session, xev nested): client requested 1280x720@120 → host created gamescope at that mode → 1680/1680 frames over 14s, zero loss, valid HEVC; pipeline latency p50 0.83ms / p95 1.2ms / p99 1.3ms (capture→encode→FEC→crypto→UDP→ reassembled, same-host clock); 176 input datagrams sent → injector (GamescopeEi) → 164 X events observed inside the nested session. Known follow-on: slice-level sub-frame pipelining needs the NVENC SDK directly (libavcodec emits whole AUs only) — the next big latency lever. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -60,21 +60,24 @@ fn real_main() -> Result<()> {
|
||||
Some("zerocopy-probe") => zerocopy::probe(),
|
||||
// M0 pipeline spike.
|
||||
Some("m0") => m0::run(parse_m0(&args[1..])?),
|
||||
// M3 seed: native lumen/1 host (QUIC control plane + UDP data plane).
|
||||
// M3: native lumen/1 host (QUIC control plane + UDP data plane).
|
||||
Some("m3-host") => {
|
||||
let port = args
|
||||
.iter()
|
||||
.skip_while(|a| *a != "--port")
|
||||
.nth(1)
|
||||
.and_then(|s| s.parse().ok())
|
||||
.unwrap_or(9777);
|
||||
let frames = args
|
||||
.iter()
|
||||
.skip_while(|a| *a != "--frames")
|
||||
.nth(1)
|
||||
.and_then(|s| s.parse().ok())
|
||||
.unwrap_or(300);
|
||||
m3::run(port, frames)
|
||||
let get = |flag: &str| {
|
||||
args.iter()
|
||||
.skip_while(|a| *a != flag)
|
||||
.nth(1)
|
||||
.map(String::as_str)
|
||||
};
|
||||
let source = match get("--source") {
|
||||
Some("virtual") => m3::M3Source::Virtual,
|
||||
_ => m3::M3Source::Synthetic,
|
||||
};
|
||||
m3::run(m3::M3Options {
|
||||
port: get("--port").and_then(|s| s.parse().ok()).unwrap_or(9777),
|
||||
source,
|
||||
seconds: get("--seconds").and_then(|s| s.parse().ok()).unwrap_or(30),
|
||||
frames: get("--frames").and_then(|s| s.parse().ok()).unwrap_or(300),
|
||||
})
|
||||
}
|
||||
Some("-h") | Some("--help") | Some("help") | None => {
|
||||
print_usage();
|
||||
|
||||
Reference in New Issue
Block a user