Skip to content

Claude/heuristic curran - #4

Merged
ccowan93 merged 7 commits into
masterfrom
claude/heuristic-curran
Mar 20, 2026
Merged

Claude/heuristic curran#4
ccowan93 merged 7 commits into
masterfrom
claude/heuristic-curran

Conversation

@ccowan93

Copy link
Copy Markdown
Owner

No description provided.

ccowan93 and others added 7 commits March 10, 2026 19:52
In multi-seat mode:
- serverinfo reports SUNSHINE_SERVER_FREE when seats are available,
  preventing Moonlight from showing the "quit current app?" dialog
- launch() allows concurrent app launches on separate seats instead
  of blocking with "An app is already running"
- cancel() only terminates the requesting client's session, not all
  sessions, via new terminate_session_by_uuid() in RTSP server

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Each multi-seat session now gets its own independent resources:

- Per-seat proc_t: Each seat owns its own proc_t instance created
  during init(), so app processes run independently per seat
- Isolated desktops: The seat's proc_t has its desktop_name set
  during acquire(), routing all spawned processes to the seat's
  isolated Windows Desktop
- Per-seat virtual displays: Each seat creates its own SudoVDA
  virtual display in cmd_announce() instead of sharing the one
  created by the global proc
- Seat-aware launch: Seat is acquired early in nvhttp launch()
  and stored on launch_session_t, so execute() uses the seat's
  proc_t. Both "new app" and "resume same app" paths route
  through the seat's proc_t in multi-seat mode
- Per-seat cancel: cancel() finds the seat by client UUID,
  terminates only that seat's proc_t, and releases it
- Client tracking: seat_t now stores client_uuid for lookup
  during cancel and cleanup

Single-seat mode is completely unchanged — all multi-seat logic
is guarded by config::multiseat.enabled checks.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Two fixes for multi-seat streaming sessions being torn down immediately:

1. stream.cpp: The broadcast loop checked proc::proc.running() (global
   singleton) which returns 0 in multi-seat mode because the app runs on
   the seat's proc_t. Now checks each session's seat->process->running()
   in multi-seat mode instead of only the global proc.

2. rtsp.cpp: If execute() already created a virtual display for the seat
   (stored on launch_session->display_guid), adopt it to the seat instead
   of creating a duplicate. Only create a new virtual display if execute()
   didn't create one.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add worker mode (--worker, --port-offset, --credentials-dir) so multiple
Apollo instances can run independently in separate Windows RDP sessions.
A coordinator instance manages worker lifecycle for seamless Moonlight UX.

- config.h/cpp: New CLI flags and multiseat_mode/users/passwords config
- main.cpp: Skip web UI, mDNS, UPnP, tray in worker mode
- multiseat_launcher.h/cpp: Launch workers via LogonUserW + CreateProcessAsUserW
- nvhttp.cpp: Coordinator delegates launches to workers in multi_instance mode
- seat.h/cpp: Worker lifecycle tracking, cleanup on release
- windows.cmake: Add multiseat_launcher sources and wtsapi32 link

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The port_offset, worker_mode, and credentials_dir fields were added to
the struct but not to the aggregate initializer list, causing positional
mismatch errors.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Include winsock2.h before windows.h to prevent conflict with Boost.Asio.
Replace nvhttp.h/rtsp.h includes with local port constants to avoid
pulling in heavy headers that transitively include winsock.h.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
AMF's avcodec_receive_packet blocks forever on the second call after
producing the first IDR frame, instead of returning EAGAIN. This hangs
the entire startup during encoder probing, preventing the web UI from
ever loading.

Fix by running encode() in a separate thread during validation and
polling the packet queue. When a packet appears (before encode returns),
we accept it as success and detach the blocked thread. Resources are
shared via shared_ptr for safe lifetime management.

Also adds a 30-second outer timeout wrapper (validate_config_with_timeout)
around all encoder probes as a safety net for hangs in avcodec_open2.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@ccowan93
ccowan93 merged commit d44bd60 into master Mar 20, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants