3ea096ace9
ci / rust (push) Has been cancelled
The shared-core architecture pays off: platform clients now link ONE Rust library that does the entire lumen/1 protocol, and only add decode/present/input on top. lumen-core: - client.rs (quic feature): NativeClient — QUIC handshake + UDP data plane + input datagrams on internal threads; embedder surface = connect / next_frame / send_input. - abi.rs: lumen_connect / lumen_connection_next_au (borrow-until-next-call, matching lumen_client_poll_frame semantics) / lumen_connection_send_input / lumen_connection_mode / lumen_connection_close. Guarded in the generated header by LUMEN_FEATURE_QUIC (cbindgen [defines] mapping), so the checked-in header is stable across feature sets. - error.rs: append-only LumenStatus additions Timeout (-9) and Closed (-10). - TESTED end-to-end through the C ABI: in-process lumen/1 host, lumen_connect pulls 25 byte-verified frames, sends input, closes (m3.rs::c_abi_connection_roundtrip). Apple client (clients/apple — SCAFFOLD, written on Linux, first Xcode build pending): - scripts/build-xcframework.sh: cargo per Apple target → universal staticlib + header (LUMEN_FEATURE_QUIC pre-defined) + modulemap → LumenCore.xcframework. - Package.swift (LumenKit) + Swift sources: LumenConnection (ABI wrapper), AnnexB (in-band VPS/SPS/PPS → CMVideoFormatDescription, Annex-B → AVCC CMSampleBuffers with DisplayImmediately), StreamView (SwiftUI over AVSampleBufferDisplayLayer — stage-1 presenter that hardware-decodes compressed HEVC itself), InputCapture (GCMouse raw deltas + GCKeyboard HID→VK). - README.md is the full handoff for the next (Mac-side) agent: build steps, ABI contract, first-light test recipe against the Linux host, stage-2 (VT+Metal pacing) plan, and the known host-side gaps (single-session m3-host, no lumen/1 audio yet, gamepad kinds not yet routed in m3's injector, seed-stage trust). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
lumen Apple client (SwiftUI) — handoff
The native macOS/iOS client for lumen/1 (the post-GameStream protocol). All
networking/protocol work — QUIC control plane, UDP data plane, GF(2¹⁶) FEC, AES-GCM,
input datagrams — lives in the shared Rust core and is done and tested; this package
is the Swift shell: decode (VideoToolbox), present (SwiftUI), input capture.
What exists (built + tested on the Linux host)
- The connector:
lumen_core::client::NativeClient(Rust) exposed over the C ABI aslumen_connect/lumen_connection_next_au/lumen_connection_send_input/lumen_connection_mode/lumen_connection_close(seeinclude/lumen_core.h, guarded byLUMEN_FEATURE_QUIC). End-to-end tested through the C ABI against an in-process host (crates/lumen-host/src/m3.rs::tests::c_abi_connection_roundtrip). - The host to test against:
lumen-host m3-host --source virtual --seconds 60on the Linux box (it creates a native virtual output at whatever mode the client requests and streams HEVC;LUMEN_COMPOSITOR=gamescope LUMEN_GAMESCOPE_APP=vkcubefor moving content). - This package (SCAFFOLD — written on Linux, never compiled in Xcode):
LumenConnection.swift— Swift wrapper over the C ABI (AUs copied intoData).AnnexB.swift— in-band VPS/SPS/PPS →CMVideoFormatDescription; Annex-B → AVCCCMSampleBufferwithDisplayImmediatelyset.StreamView.swift— SwiftUINSViewRepresentableoverAVSampleBufferDisplayLayer(stage-1 presenter: the layer hardware-decodes compressed HEVC itself).InputCapture.swift—GCMouseraw deltas +GCKeyboardHID→VK mapping →lumen_connection_send_input.
Build steps (on the Mac)
rustup target add aarch64-apple-darwin x86_64-apple-darwin
bash scripts/build-xcframework.sh # → clients/apple/LumenCore.xcframework
open clients/apple/Package.swift # or add the package to an Xcode app project
Minimal app around it:
@main struct LumenApp: App {
var body: some Scene { WindowGroup { ContentView() } }
}
struct ContentView: View {
@State private var conn: LumenConnection?
var body: some View {
if let conn {
StreamView(connection: conn)
.onAppear { InputCapture(connection: conn).start() }
} else {
Button("Connect") {
conn = try? LumenConnection(
host: "192.168.1.70", width: 2560, height: 1440, refreshHz: 120)
}
}
}
}
Handoff — what the next agent needs to know
- Expect small compile fixes. Every Swift file is flagged SCAFFOLD: API-checked from
documentation, never run through Xcode. Likely friction: the imported C enum spellings
(
LUMEN_STATUS_OKetc. — cbindgen emitsQualifiedScreamingSnakeCase),LumenFrame()zero-init,_padtuple shape onLumenInputEvent. - ABI contract (matches
lumen_core.hdocs):next_au's pointer is valid only until the next call on that handle (we copy toDataimmediately); one pump thread per connection;send_inputis enqueue-only and thread-safe alongside it;closejoins the Rust threads — never call it with anext_aucall in flight. - Decode flow: the host opens every stream with an IDR carrying VPS/SPS/PPS in-band,
and recovery keyframes re-send them — so "wait for the first format description, refresh
it on every IDR" (already what
StreamViewdoes) is sufficient; there is no out-of-band extradata, ever. - First-light test: Linux box runs
PATH=/tmp/gamescope-src/build/src:$PATH LUMEN_COMPOSITOR=gamescope \ LUMEN_GAMESCOPE_APP=vkcube LUMEN_ZEROCOPY=1 cargo run -rp lumen-host -- m3-host --source virtual --seconds 120; Mac connects with the app. Success = the spinning vkcube on glass. Then mouse/keys should appear inside the gamescope session (verify withLUMEN_GAMESCOPE_APP=xevand the box-side log/tmp/lumen-gamescope.log). - Stage 2 (after first light): replace
AVSampleBufferDisplayLayerwith explicitVTDecompressionSession+CAMetalLayerfor frame-pacing control (ProMotion/120 Hz), and add glass-to-glass measurement (tools/latency-probeis the scaffold; the host already stampspts_nswith its capture wall clock — across machines you'll need a clock-offset estimate from the QUIC RTT, or the probe's visual timestamp loop). - Gamepads:
GCController→GamepadButton/GamepadAxisLumenInputEvents. The host does NOT yet route those kinds inm3.rs's injector path (mouse/keys work; the gamepad kinds need aGamepadManagerhookup like the GameStream control stream has — small host-side task). - Trust model is seed-stage: the client accepts any host certificate
(
endpoint::client_insecure). Pairing + pinning is a planned lumen-core task; design it alongside this client's "add host" UX. - iOS: same package (
BUILD_IOS=1for the xcframework slice);StreamViewneeds theUIViewRepresentabletwin and touch→input mapping.
Known limitations of the current host (relevant to client UX)
m3-hostserves one session and exits — fine for development; the persistent lumen/1 listener (serve-style) is a small host-side task.- No audio on lumen/1 yet (the GameStream path has it; porting the Opus stream onto a second datagram flow is straightforward).
- Mid-stream renegotiation (resolution change without reconnect) is designed-for but not implemented (the Welcome is one-shot today).