Skip to content

Turning the camera off and on left no room for a screen share (GRYT-1329) - #625

Merged
sivert-io merged 2 commits into
mainfrom
claude/GRYT-1329-camera-slot
Sep 21, 2026
Merged

sivert-io merged 2 commits into
mainfrom
claude/GRYT-1329-camera-slot

Conversation

@sivert-io

@sivert-io sivert-io commented Sep 21, 2026 •

Copy link
Copy Markdown
Member

Fixes GRYT-1329. Takes @gryt/voice 0.5.9, which has Gryt-chat/voice#63, and yarn.lock moves only that package.

What was wrong

Turn the camera on, off and on again, then share your screen, and everyone else gets "'s screen isn't coming through". Share first and then turn the camera off and on, and the camera doesn't come back. The engine removed the camera's sender each time the camera went off, and addTrack never reuses a transceiver that has sent. So each time the camera came back it took another of the SFU's m-lines, and it only offers two for video. Gryt-chat/voice#63 has the transceiver dumps from before and after.

It's probably behind some of the reports in GRYT-1324 and GRYT-1312: a share that didn't come through until the sharer reconnected, sometimes the camera too, from somebody who turned their webcam on and off a lot.

What changed

  • @gryt/voice 0.5.9. It pauses the camera's sender with replaceTrack(null) and reuses it when the camera comes back. 0.5.9 also carries Lower the microphone's default ceiling, and stop replacing the camera's track with itself (GRYT-1332, 1333, 1330) voice#64: the microphone's lower default ceiling, and no replacing the camera's track with itself.

  • forgetSenderStreamId is gone. The camera's sender now lasts as long as the connection, and so does its stream id, so Controls keeps announcing the first camera stream's id after the camera comes back. check-media-state-reassert checks that turning the camera off doesn't change the id.

  • roleSender finds the camera's sender for its encoding settings. A resumed sender only gets its new track when replaceTrack resolves, so the lookup by track missed it. Since The camera was re-added four times a second, and Video Debug's report count never filled in (GRYT-1333, 1334) #626, and with 0.5.9's getters staying the same between renders, nothing ran the effect again, and a camera turned back on during a share stayed at medium instead of low. roleSender remembers the sender per connection, found by its track while the track is on it.

  • Two tests in e2e/nightly/voice.spec.ts, each for two rounds:

    • The camera off and on, then a share. The other guest's screen tile plays, and the camera keeps playing.
    • A share, then the camera off and on. The camera plays again, and the screen keeps playing.

    Both check that the camera gives way to the screen (low next to its high) while both are on, and that every stream id Alice announced is one Bob's tiles played.

Tested

Locally, with two headless Chrome guests on fake devices, against a server (a49b2c4) and an SFU (3cd22b7) built from main:

  • Client main with voice 0.5.8: both new tests fail. The first on the screen tile ("the tile has no video, only its placeholder"), the second on the camera coming back ("the video never got a frame").
  • This branch, rebased on main, with 0.5.9 from npm: the whole nightly call project passes, 5 of 5.
  • The same without roleSender: the share-first test fails in its second round, with the camera at medium next to the screen's high.
  • Every test:* step in ci.yml, yarn lint, yarn tsc -p e2e and yarn build pass. yarn e2e: 46 passed and 1 skipped. sidebar-folders.spec.ts failed, because my local server:latest is four days old and predates Folders carry permissions their channels follow (GRYT-1306) server#207. CI pulls the current one.

The phone needs the same stream id change when it takes 0.5.9. That's GRYT-1336.

🤖 Generated with Claude Code

sivert-io and others added 2 commits September 21, 2026 14:09
…329)

The engine removed the camera's sender each time the camera went off. When
the camera came back, it took the m-line the SFU had set aside for the
screen, and a share after that never reached anyone. @gryt/voice 0.5.9
pauses the sender with replaceTrack(null) and reuses it, the way it already
handles the screen (voice#63).

A paused sender keeps its stream id, so the camera now comes back under the
id it first went out with. forgetSenderStreamId is gone, and Controls keeps
announcing the first camera stream's id for the rest of the connection.
With the new engine and the old id handling, the camera never got a frame
for the other guest after it came back.

Two nightly tests cover it, each for two rounds. One turns the camera off
and on, then shares. The other shares first, then turns the camera off and
on. On client main with voice 0.5.8, the first fails on the screen tile's
placeholder and the second on the camera never getting a frame. Both pass
with this and the voice branch.

Co-Authored-By: Claude Opus 5 <[email protected]>
Controls looked the camera's sender up by its track to set its encoding
priority. A camera that comes back goes out on its paused sender, and that
sender only gets the new track when replaceTrack resolves, so the lookup
missed it. Since client#626 and voice 0.5.9 the effect no longer re-runs on
every render, so nothing fixed it later. Turned back on during a share, the
camera stayed at medium instead of dropping to low under the screen's high.

roleSender remembers the camera's sender per connection, found by its track
while the track is on it, and Controls uses that. The nightly tests now check
that the camera gives way to the screen whenever both are on. Without this,
the second round of the share-first test fails with the camera at medium.

Co-Authored-By: Claude Opus 5 <[email protected]>
@sivert-io
sivert-io force-pushed the claude/GRYT-1329-camera-slot branch from 853f929 to 5b1c835 Compare September 21, 2026 12:10
@sivert-io
sivert-io marked this pull request as ready for review September 21, 2026 12:17
@sivert-io
sivert-io merged commit b6065d9 into main Sep 21, 2026
9 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.

1 participant