Skip to content

A client can ask for a screen pair per window it shares (GRYT-1905) - #67

Merged
sivert-io merged 1 commit into
mainfrom
claude/GRYT-1905-screen-slots
Oct 26, 2026
Merged

sivert-io merged 1 commit into
mainfrom
claude/GRYT-1905-screen-slots

Conversation

@grytchat

Copy link
Copy Markdown
Contributor

First piece of sharing several windows at once (GRYT-1905). Forwarding is already dynamic: every track in a room gets its own AddTrack on each subscriber. Ingest wasn't. Each peer got four receive-only transceivers at join (mic, camera, one screen video, one screen audio), and since the SFU makes every offer, a second window had no m-line to arrive on.

What changes

  • renegotiate may carry {"screens": n}. An empty data, which today's clients send, behaves exactly as before.
  • For n > 1 the SFU adds receive-only video and audio pairs until the peer has n, then re-offers as usual. It never removes them. An unused pair costs an idle m-line until the peer closes.
  • n is capped at 8 (maxScreenShares). That isn't a product limit, it bounds what one client can make the SFU allocate. Each window costs the sender an encoder and upload long before it gets near 8.
  • The added receivers go in a package-level sync.Map, and slotOf reports them as slotScreen or slotScreenAudio. So refusedBy gates them on share_screen like the first pair, and never on share_video. The entries are deleted when the peer is cleaned up.

Where to look

  • slotOf in handler_join.go: an extra receiver is recognised by registry lookup, not by position. Forwarded tracks share the same peer connection, so index alone can't say what a later transceiver is for.
  • ensureScreenSlots runs even while the peer isn't stable. The renegotiation is deferred as before, and the new transceivers ride along in the next offer.
  • The registry is global state in the package. A per-handler map would mean threading it through refusedBy and its tests.

Tests: screenslots_test.go covers a pair per window, no growth on a repeat or smaller request, the ceiling, the second window's video and audio gated on share_screen, and cleanup. go test ./... passes.

Not in this PR: the client side. @gryt/voice still has one screen sender, and the server and client still track one share per person. Those come next, and nothing sends screens until they land.

🤖 Generated with Claude Code

…905)

renegotiate may carry {"screens": n}; the SFU adds receive-only video and audio pairs up to n,
at most 8, before re-offering. The added pairs answer to share_screen like the first.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@grytchat
grytchat requested a review from sivert-io as a code owner October 26, 2026 19:28
@sivert-io
sivert-io merged commit fe31a8f into main Oct 26, 2026
7 checks passed
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