fangorn/sunshine-qemu
public
Pairing modes: VMs as Moonlight apps in one instance, plus CLI pairing #13
Links
Two ways to pair, and a way to finish pairing without a GUI.
Why
Phase 1 ships one Sunshine process per VM (#6). Each instance has its own identity, so a client pairs with every VM separately: N PINs, N web UI logins, N hosts in Moonlight. That is the right shape when two VMs must stream at once, and the wrong shape for day-to-day development, where one person streams one VM at a time and just wants to pick which.
Pairing also can’t be finished from a terminal today. GET/POST /api/pin exist, but the only client is the web UI, so a headless setup has to drive a browser.
Mode A: VMs as apps in one instance (REQ-DEP-003, the default for development)
One Sunshine, one pairing, one port set, one mDNS name. Each VM is an app in Moonlight’s list; launching it streams that VM. One VM at a time.
This fits Sunshine’s existing lifetimes: the capture thread (src/video.cpp:709) and the audio context (src/audio.cpp:277) are refcounted singletons that live for a streaming era, not the process, and they re-read config when constructed. So switching VMs between streams needs no new lifetime.
- Per-app VM: new
ctx_tfield (src/process.h:57), parsed insrc/process.cpp, added toapps.jsonand the apps web UI. Empty means the globalqemu_dbus_address. - Resolve the app’s VM at launch before
configure_displayandprobe_encoders(src/nvhttp.cpp:1387,:1393), which both run beforeproc::proc.execute(:1414). -
platf::init()latches the QEMU source only whenverify_qemu()can reach the configured address (src/platform/linux/misc.cpp:1405). With no VM booted at startup, capture stays disabled for the process lifetime. Select the backend oncapture = qemuand verify per launch instead. -
shared_sessionis a single-slot cache keyed on one address (qemu/session.cpp:1600). Make it a map so switching VMs doesn’t reconnect every time. -
qemu::input_tbinds the address once at startup (virtualhid_input.cpp:1046). The capture binding already redirects input to the streaming VM; fix the pre-stream fallback. - Decide what
display_names()reports: this VM’s consoles, or every configured VM. Keep theswitch_displayhotkey (src/video.cpp:1580) from jumping between VMs mid-stream. - Docs and an example apps.json.
Not in scope: two VMs streaming at once from one process. nvhttp.cpp:1368 allows one running app per host, and one display object is shared by every session in an era; changing either is a deep refactor of upstream. Concurrency stays with mode B.
Mode B: one instance per VM (REQ-DEP-001, unchanged)
Keeps isolation and concurrent streams. Stays the default for the systemd deployment.
- Document when to choose which, including that mode A trusts one pairing for every VM it serves.
CLI pairing (REQ-DEP-004)
-
sunshine-qemu-pair: list pending requests, approve one with its PIN, list paired clients, unpair. Talks to an instance’s API over HTTPS with the web UI credentials. CSRF is skipped for non-browser clients (src/confighttp.cpp:790), so no browser is needed. - Resolve the instance from a VM name (its config’s
port) or an explicit port. - Packaging test with a real instance.
Done when
- A client pairs once with a mode A instance, sees each VM as an app, and streams two different VMs one after the other.
sunshine-qemu-paircompletes a pairing end to end with no browser.- Mode B still passes its existing tests.