Skip to content

feature: cameras - #389

Merged
lukepolo merged 17 commits into
mainfrom
feature/cameras
Aug 14, 2026
Merged

feature: cameras#389
lukepolo merged 17 commits into
mainfrom
feature/cameras

Conversation

@lukepolo

Copy link
Copy Markdown
Contributor

No description provided.

lukepolo and others added 2 commits August 12, 2026 19:17
The game-streamer pod has no site session, so it could not use the
organizer-gated WHEP route to put the spectated player's camera on the
stream. Adds a route it can use as the match itself, on the same
x-origin-auth scheme status-reporter and snapshot already use.

Scoped hard: one pod is authorized for one match, the steam id must be
a Steam64 on that match's roster, and the match must actually require
cameras. The path is still built through the encoding boundary in
MediaMtxService, so a crafted id cannot address another match's feed.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QnoNWfftRZL47DxmGUyh8K
lukepolo and others added 15 commits August 13, 2026 09:52
Joining party voice showed a spinner and then nothing at all. The
composable captured the failure into an `error` ref that no template
ever rendered, and Button holds its spinner for a 2s minimum, so a
failure that happened instantly still looked like a hang. Nothing was
reaching the network because getUserMedia was throwing first --
`navigator.mediaDevices` is undefined on an insecure origin, so a panel
served over plain http has no way to get a microphone.

Errors are now surfaced in the panel and named rather than dumped:
insecure origin, denied permission, no microphone, microphone in use.
The insecure-origin case is checked before joining so the button is
disabled with an explanation instead of failing on click.

Also flips public.voice_chat_enabled to on by default (only an explicit
"false" disables it, matching require_login_for_live_streams). Cameras
stay off by default -- voice is a convenience for players who already
chose to party up, not a surveillance control.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QnoNWfftRZL47DxmGUyh8K
…efaults

public.player_cameras_enabled gated the whole feature, and the two
match-option defaults were nested under it. Since it shipped off, the
defaults were invisible on a fresh install -- the settings page showed
one disabled toggle and nothing else.

Cameras are already opt-in at the level that matters: an organizer turns
Require Webcam on per match. A second global switch in front of that
only hid the settings that decide what a new match starts with. Removed;
the defaults now stand on their own. Party voice keeps its toggle, since
that one really is a feature that can be turned off.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QnoNWfftRZL47DxmGUyh8K
Hasura reflects the request origin, so GraphQL already works from a dev
machine against a deployed stack. The routes this process serves use a
fixed allowlist built from the configured domains, so the same browser
that can query GraphQL from localhost is refused by /voice and
/matches/camera -- both of which are preflighted, since an
application/sdp body is not a CORS-safelisted content type.

Empty by default; an operator opts their own dev origin in.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QnoNWfftRZL47DxmGUyh8K
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QnoNWfftRZL47DxmGUyh8K
…wn match

Two things were wrong. Check-in happens at WaitingForCheckIn, which was
not in the camera status list -- so no token had been minted yet, the
overlay never appeared, and nothing stopped a player checking in without
a webcam. Tokens are now minted on that edge too, the status counts as
active, and checkIntoMatch refuses until the player's camera is actually
publishing. Check-in is the right gate: enforcing only at Live means a
player reaches the server unwatched and the match pauses on them instead.

Also carves out an exception to "nobody playing may watch": a site
administrator keeps full access so the feature can be exercised
end-to-end without a second account. Organizers who are playing stay
scoped to their own side -- they are competitors, and a live view of the
other team is exactly what this prevents.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QnoNWfftRZL47DxmGUyh8K
@lukepolo
lukepolo merged commit 09b65f2 into main Aug 14, 2026
1 of 2 checks passed
@lukepolo
lukepolo deleted the feature/cameras branch August 14, 2026 19:21
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.

1 participant