Windows 服务,运行多个相互隔离的 Sunshine 游戏流媒体会话供 Moonlight 使用,每个会话在独立的 RDP 会话中,由网页仪表板管理。
AI 翻译
Windows service that runs multiple isolated Sunshine game-streaming sessions for Moonlight, each in its own RDP session, managed from a web dashboard.
开发工具C# · JavaScriptGitHub @mlopezsegura在线运营者未确认
试用过了吗? 点一下就好,无需登录。
个人 GitHub 账号下公开仓库的所有者可以登录并验证所有权,自行管理介绍,无需管理员批准。
登录并生成验证文件,在 30 分钟内将其提交到此仓库的默认分支。其他分支或分叉仓库中的文件无效。然后在下方检查文件,即可无需管理员批准直接管理项目。请保留文件以维持管理权限。
如需登录,将前往登录页面。登录后请回到此处,再次点击所选的验证按钮。
在项目文件夹中运行 /nomorevibe verify,即可验证所有权并自行管理介绍。
一分钟完成验证The open stream multiseat alternative
翻译准备中
取自仓库 README
正在加载完整 README。 以下为已保存的摘录。
Windows service that automates the setup of a game streaming environment using Sunshine (Moonlight/GameStream host).
Manages the full lifecycle of isolated RDP streaming sessions — creation, monitoring, auto-restart, and teardown — from a web dashboard or REST API.查看完整 README ↗Windows service that automates the setup of a game streaming environment using Sunshine (Moonlight/GameStream host).
Manages the full lifecycle of isolated RDP streaming sessions — creation, monitoring, auto-restart, and teardown — from a web dashboard or REST API. With extra monitors, keyboards, mice and gamepads, the same sessions become local seats: several people using one PC at the same time, each with their own screen, input and sound.
USERPROFILE, APPDATA, LOCALAPPDATA, temp, and XDG paths) so local and stream sessions do not share common profile lock files/scalar/v1apps.json to keep a virtual display active even when the RDP client disconnectsosms-…), optionally ephemeral (wiped on stop); isolated sessions get a Steam (isolated) shortcut and handle steam:// links so each one can sign in to its own Steam accountOpenStreamMS-Setup-x.x.x.exe from ReleasesTo uninstall, use Apps & Features → OpenStreamMS → Uninstall. It asks two questions:
osms-… users with their profiles (including games and settings stored in them), stream profiles, %ProgramData%\OpenStreamMS and temporary files. No keeps sessions and settings for a reinstall.Silent uninstall: unins000.exe /VERYSILENT [/PURGEDATA] [/REMOVEDEPS].
Requirements
Build & install
dotnet publish -c Release -r win-x64 --self-contained -o publish\
cd publish
OpenStreamMS.exe --install
Uninstall
OpenStreamMS.exe --uninstall
Edit service.config.json in the install directory (created automatically on first run):
{
"StreamUser": {
"Username": "streamuser",
"Domain": ".",
"Password": "YourPassword"
},
"SunshineExePath": "C:\\Program Files\\Sunshine\\Sunshine.exe",
"RdpBackground": true,
"VddEnabled": false,
"ApiPort": 5000,
"AdminUsername": "",
"AdminPasswordHash": "",
"AuthSecret": ""
}
| Field | Default | Description |
|---|---|---|
StreamUser.Username | streamuser | Local Windows account for the streaming session |
StreamUser.Domain | . | Domain (. = local machine) |
StreamUser.Password | — | Password for the stream user |
SunshineExePath | Sunshine\sunshine.exe | Path to Sunshine.exe |
RdpBackground | true | Hide the FreeRDP window (set false for debugging) |
VddEnabled | false | Enable virtual display patch in Sunshine's apps.json |
ApiPort | 5000 | Port for the web dashboard and REST API |
AdminUsername | — | Web UI admin username (configured on first run) |
Open http://localhost:5000 in any browser.
On first access you will be prompted to create admin credentials. After that, the dashboard lets you:
/scalar/v1Sessions run the Sunshine in Sunshine\ (or the one set in SunshineExePath). With the
sunshine-webrtc build, a session can serve:
| Protocol | Clients | Ports opened in the firewall |
|---|---|---|
| Moonlight | Moonlight apps | TCP+UDP port-5 .. port+21 (HTTPS, HTTP, video/control/audio, RTSP) |
| WebRTC | Samsung TVs with Moonlight WebRTC | TCP WebRtcPort, UDP 8000 (TV discovery) and UDP WebRtcMediaPortMin..Max |
| Both (default for new sessions) | Both | All of the above |
The switch on each session card (and PUT /api/sessions/{id}/protocol) changes it live: OpenStreamMS
writes stream_protocol to the instance's sunshine.conf, opens or closes the ports and restarts only
Sunshine, keeping the RDP session. Sunshine's own panel has the same switch on its Network tab;
when Sunshine restarts, OpenStreamMS adopts the value saved there, so the last change wins. WebRTC
ports are managed by OpenStreamMS and rewritten on every start.
New sessions get free ports automatically (GET /api/sessions/ports/suggest: Moonlight base in steps
of 100 from 47989, WebRTC from 8000, media in blocks of 20 from 40000). Creating or editing a session
whose ports overlap another session's is refused, and so is starting one whose ports are in use by a
running session. Ports of a protocol that is off do not count. UDP 8000 is shared: every instance
answers a TV's discovery broadcast with its own name and port. Sessions created before this feature
stay Moonlight until switched.
The bundled Sunshine\ is a sunshine-webrtc build. To use another Sunshine, replace the contents of
Sunshine\ (or point SunshineExePath at one). Existing sessions pick up the new binaries on their next start; their
config\ (settings, paired Moonlight clients and TVs) is kept. A Sunshine without WebRTC support
ignores the protocol and the dashboard warns on sessions set to WebRTC or both. Paired TVs
(webrtc_tv_clients.json) are backed up with sunshine_state.json.
The bundled build streams to TVs with zero playout delay: each frame is shown the moment it is decoded, with no jitter buffer, and the picture no longer waits for the audio. Screen to screen, 1080p60 went from 54 to 38 ms and 2160p60 from 73 to about 50 ms in Sunshine-Web-RTC's latency test.
A seat is a set of physical devices — a monitor, an audio output, and USB keyboards, mice and gamepads — linked to a session. While the seat is on, the session is shown on that monitor and controlled only by those devices, as if it were a separate computer. Seats are managed from the Seats tab of the dashboard.
| What happens | |
|---|---|
| Monitor | Added to the desktop only while the seat is on (and placed so the console mouse can't wander into it). The session is captured inside its own RDP session and presented full-screen in ~2 ms, uncompressed, up to 125 Hz. The session is reconnected at the seat's resolution and refresh rate (fixed per seat or taken from the monitor) and restored when the seat turns off. |
| Keyboard & mouse | Switched to Microsoft's inbox WinUSB driver while the seat is on and read directly, so the console never sees them and every mouse moves independently. No third-party drivers. They return to their normal driver when the seat turns off, and on the next service start if it crashed. |
| Gamepads | Assigned by USB port and hidden from every other session with HidHide while the seat is on. |
| Audio | The session's audio plays on the seat's output with ~70 ms of latency and a jitter buffer. |
| Identify | In the seat editor, Test shows the OpenStreamMS logo on a monitor (turning it on for a few seconds if needed) or plays a chime on an audio output, and the keyboard, mouse or gamepad you press lights up in the device list. |
Exclusive and shared seats. An exclusive seat pauses Moonlight/WebRTC for its session while it is on. A shared seat keeps streaming, so the same desktop can be used at the desk and on a TV.
Rules that keep a shared PC safe:
Requirements and limits. Each seat monitor must be on the same GPU as the sessions. On Windows Pro the monitor is added to and removed from the desktop by OpenStreamMS, so it shows the console's desktop when no seat uses it. A seat's keyboard and mouse don't work on the console while the seat is on, and keyboard LEDs (Caps Lock…) stay off. Input is injected, so some anti-cheat systems may reject it. DRM-protected video is black, as in Sunshine. A host-only console (a technical user with autologon) is recommended.
Design notes and measurements (Spanish): docs/puestos-locales.md.
The tray icon (OpenStreamMS.exe --tray) runs in the user's desktop session and provides quick access without opening a browser:
The tray icon is registered at Windows startup automatically during installation.
When independent stream profile is enabled for a session, OpenStreamMS launches Explorer, Sunshine, and Sunshine apps with a separate profile root:
C:\Users\<user> ← your normal local profile
C:\Users\<user>\_OpenStreamMS_Stream ← stream session profile sandbox
The sandbox sets USERPROFILE, HOME, APPDATA, LOCALAPPDATA, LOCALAPPDATALOW, TEMP, TMP, and XDG paths for the stream process tree. Sunshine also receives the same values in apps.json, so commands launched from Moonlight inherit the isolated profile even after Sunshine restarts.
This is native Windows process/profile isolation, not Windows Sandbox. Windows Sandbox is a separate VM and cannot be attached transparently to the existing RDP/Sunshine session without a different streaming architecture.
Applications that use machine-global mutexes, HKCU registry keys, or their own installation directory for locks may still require a separate Windows user or a separate app installation.
OpenStreamMS.exe --run Run the service (called by Windows SCM)
OpenStreamMS.exe --install Install and register the Windows service
OpenStreamMS.exe --install --silent Install without prompts (used by installer)
OpenStreamMS.exe --uninstall Stop and remove the Windows service
OpenStreamMS.exe --tray Show system tray icon
Internal (launched by the service in the right Windows session):
OpenStreamMS.exe --seat-agent <pipe> Seat capture/input agent inside the seat's session
OpenStreamMS.exe --seat-host <pipe> Seat presenter on the console
OpenStreamMS.exe --display <cmd> Monitor topology changes on the console
OpenStreamMS.exe --identify <cmd> Test a monitor, an audio output or input devices
OpenStreamMS.exe --help Show help
Requires Inno Setup 6.
cd Installer
build-installer.bat
The resulting OpenStreamMS-Setup-x.x.x.exe is placed in dist\.
OpenStreamMS.exe (Windows Service, SYSTEM)
├── Program.cs — CLI entry point (--run / --install / --uninstall / --tray)
├── OpenstreamService.cs — BackgroundService; owns the 5-second monitoring loop
├── ServiceConfig.cs — Loads/saves service.config.json
├── RdpSessionCreator.cs — Creates the loopback RDP session via WTS API + FreeRDP
├── SunshineManager.cs — Launches and monitors Sunshine.exe inside the RDP session
├── SunshineConfigurator.cs — Patches apps.json to enable virtual-display support
├── ProcessInSession.cs — CreateProcessAsUser wrapper; supports custom env overrides
├── StreamProfileSetup.cs — Builds the stream profile sandbox; restarts Explorer with new env
├── TrayApp.cs — WinForms ApplicationContext for the system tray icon
├── WTSSessionManager.cs — WTS session enumeration helper
├── Logger.cs — Per-session timestamped logger
├── Seats/
│ ├── SeatManager.cs — Seats: inventory, validation, start/stop orchestration
│ ├── SeatAgent.cs — In-session capture (DDA), audio loopback and input injection
│ ├── SeatHost.cs — Console-side presenter, audio output and input routing
│ ├── SeatUsbCapture.cs — Switches seat keyboards/mice to WinUSB and reads them
│ ├── SeatHid.cs — HID report descriptor parser → mouse events and scancodes
│ ├── SeatIdentify.cs — Monitor logo, audio chime and pressed-device highlight
│ ├── DisplayTopology.cs — Turns seat monitors on/off (CCD)
│ └── ConsoleLockGuard.cs — Keeps the console from locking while seats are on
└── Api/
├── SeatEndpoints.cs — REST endpoints (/api/seats/*)
├── SessionEndpoints.cs — REST endpoints (/api/sessions/*)
├── StreamSessionService.cs — Session CRUD + lifecycle (start/stop/monitor)
├── StreamSession.cs — Session data model + state machine
├── AuthService.cs — Cookie + HTTP Basic Auth
└── CredentialTester.cs — Windows credential validation (LogonUser)
| Method | Path | Description |
|---|---|---|
GET | /api/sessions | List all sessions |
POST | /api/sessions | Create a session |
GET | /api/sessions/{id} | Get session details |
DELETE | /api/sessions/{id} | Delete a stopped session |
POST | /api/sessions/{id}/start | Start a session |
POST | /api/sessions/{id}/stop | Stop a session (force-closes the Windows session) |
PATCH | /api/sessions/{id}/enabled | Toggle auto-start |
GET | /api/sessions/{id}/logs | Fetch session logs |
POST | /api/sessions/test-credentials | Validate Windows credentials |
GET | /api/seats | List seats and their state |
GET | /api/seats/inventory | Free monitors, audio outputs and USB input devices |
POST | /api/seats | Create a seat |
PUT | /api/seats/{id} | Edit a stopped seat |
PATCH | /api/seats/{id}/autostart | Toggle seat auto-start |
DELETE | /api/seats/{id} | Delete a seat |
POST | /api/seats/{id}/start | Turn a seat on |
POST | /api/seats/{id}/stop | Turn a seat off |
POST | /api/seats/identify/monitor | Show the logo on a monitor ({ "id": "<device path>" }) |
Interactive docs: http://localhost:5000/scalar/v1
Planned features, such as a per-session LAN IP for running LAN games in several sessions at once, are tracked in ROADMAP.md.
OpenStreamMS is released under the MIT License.
The bundled Sunshine (GPL-3.0) and FreeRDP (Apache-2.0) binaries keep their own licenses — see THIRD_PARTY_NOTICES.md.
POST | /api/seats/identify/audio | Play a chime on an output ({ "id": "<endpoint id>" }) |
GET | /api/seats/identify/input | USB ports of the devices just pressed |