This repository contains a greenfield MVP for streaming one preselected Windows application window from a VM to a user's Windows machine.
Components:
cmd/signaling: public signaling service for host registration, session creation, WebSocket SDP/ICE relay, and in-memory session locking.cmd/streamer: VM-side user-session agent. It finds a configured top-level window, starts FFmpeggdigrabonly when a receiver requests a session, publishes VP8 over Pion WebRTC, and applies keyboard/mouse input through Win32SendInput.apps/receiver: Wails-style Windows receiver shell. The WebView frontend owns browser WebRTC playback and sends normalized input messages over a data channel.
The MVP intentionally excludes audio, clipboard, file transfer, app launch, persistence, and multi-user control.
- Windows 10/11 for streamer and receiver.
- Go 1.23+.
- FFmpeg on the VM
PATH, built withgdigrabandlibvpx. - Wails CLI for packaging the receiver:
go install github.com/wailsapp/wails/v2/cmd/wails@latest. - A coturn deployment for production internet use.
Go and FFmpeg were not installed in the authoring workspace, so the implementation was not compiled here.
-
Copy example configs:
Copy-Item configs\signaling.example.json configs\signaling.local.json Copy-Item configs\streamer.example.json configs\streamer.local.json
-
Start signaling:
go run .\cmd\signaling -config .\configs\signaling.local.json -
On the VM, open the target application, then start the streamer:
go run .\cmd\streamer -config .\configs\streamer.local.json -
For the receiver frontend during development, serve
apps/receiver/frontendover HTTPS or package with Wails. Configure the receiver with:- Signaling URL:
https://your-signaling-host - Host ID: the configured VM
host_id - Receiver token:
configs/signaling.local.jsonreceiver_tokens[0]
- Signaling URL:
The streamer preserves the target window aspect ratio and treats video.width / video.height as maximum output dimensions. It does not upscale smaller app windows before encoding, which keeps desktop text sharper. For CAD/model applications on localhost, use 1920x1080, 20 fps, 24000 kbps, quality: cad. If CPU usage is too high, lower bitrate_kbps, then reduce the max resolution.
For applications whose menus and modal dialogs are separate windows, use capture_mode: desktop_region. Tune region_padding_left, region_padding_top, region_padding_right, and region_padding_bottom to include popups while excluding the taskbar and neighboring apps.
- Use TLS in front of
cmd/signalingfor any public deployment. - The included signaling service accepts host enrollment bearer tokens plus either static receiver bearer tokens or HS256 receiver JWTs. Replace the MVP token issuance/storage with proper identity, rotation, and audit logging before production.
SendInputcan only inject into equal-or-lower integrity processes. Run the streamer at the same elevation level as the target app.- This is remote control of a dedicated VM session, not a Windows application sandbox.
go test ./...
go build -o bin\signaling.exe .\cmd\signaling
go build -o bin\streamer.exe .\cmd\streamer
cd apps\receiver
wails build -webview2 embed