Skip to content

Bump @gryt/voice to 0.5.9 and fix the stream ids the phone announces (GRYT-1336) - #232

Merged
sivert-io merged 1 commit into
mainfrom
claude/GRYT-1336-mobile-voice-0.5.9
Sep 21, 2026
Merged

sivert-io merged 1 commit into
mainfrom
claude/GRYT-1336-mobile-voice-0.5.9

Conversation

@sivert-io

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

Copy link
Copy Markdown
Member

For GRYT-1336. This takes @gryt/voice 0.5.9 and changes the stream ids the phone announces. They're in one PR because each breaks something without the other.

What was wrong

The engine sends the camera and the screen on one sender each, for the whole connection. A sender keeps its stream id through replaceTrack. So every track after the first goes out under the first stream's id.

The phone announced each new stream's own id in voice:camera:state and voice:screen:state. Everyone else looks the video up by that id. So they waited for a stream that never came, and showed the placeholder.

  • A second screen share from the phone already did this on 0.5.8. The engine only pauses the screen's sender between shares.
  • On 0.5.9 the camera does it too. Keep the camera's sender when the camera turns off voice#63 pauses the camera's sender where it used to remove it, so a camera turned back on comes back under the first camera's id.

Staying on 0.5.8 isn't a fix either. The phone runs the same engine, so it should have GRYT-1329 there too. A camera turned off and on would take the screen's m-line, and a share after that wouldn't reach anyone.

What changed

  • @gryt/voice 0.5.9, which is voice#63 and voice#64. Drop the connection state from under your name (GRYT-496) #64 lowers the microphone's default ceiling from 510 to 64 kbps. The phone passes no channel bitrate to connect, so it gets the new default. The rest of Drop the connection state from under your name (GRYT-496) #64 fixes re-renders the phone doesn't have. It calls addVideoTrack once per camera-on, and none of its effects lists an engine getter.
  • src/voice/senderStreamIds.ts has the rule from the desktop client's senderStreamIds.ts (Focusing a tile blanked your camera or screen share for everyone else (GRYT-1319) client#624, and #625 for the camera). The first stream a role gets on a connection names its sender. A new connection starts over. useCamera and useScreenShare announce that id.
  • useScreenShare works the id out as it hands the track to the engine, before any announce. On iOS the sender exists before the broadcast sheet opens. So a share that never started has still named it.
  • senderStreamIds.test.ts covers the rule. If the rule hands back each stream's own id instead, four of its five tests fail.

Where to look

  • The connection comes from getPeerConnection, which SFUInterface marks optional. Without it the phone announces each stream's own id, like before.
  • The phone never sends screen audio, so its roles are camera and screenVideo. The client's also has screenAudio.
  • The rule is a copy of the client's. GRYT-1345 is for keeping one copy.

Tested on an emulator

I ran it on the gryt-android emulator (API 36), against a server from the 1.10.18 image and an SFU built from main. A headless Chrome guest on the web client from main watched. It read the ids from server:clients, the SFU's SDP and the tile's <video>.

  • Camera on, off and on again. This branch announced the first camera's id each time the camera came back, three times over two runs. Each time the other guest's tile played it. With main's two files swapped back in, the camera coming back announced its own id. The SFU still sent the first one, and the other guest got "Video isn't coming through".
  • Share, stop, share again. This branch announced the first share's id for the second share, and the tile played it. With main's files the second share announced its own id, and the other guest got "Cove's screen isn't coming through".

The share run needed a local change this branch doesn't carry. Screen capture on Android 14 and later never starts, because nothing turns on react-native-webrtc's MediaProjectionService. It's filed as GRYT-1351. I set it in a local build for this run only.

iOS isn't tested. It runs the same two hooks, but I didn't run the simulator.

It also turned up GRYT-1352. An invite link opened while the app is running mounts a second copy of the tabs, call sheet included.

Checks

Rebased on main at 9c3a06e. tsc --noEmit, yarn test (75 files, 837 tests), yarn test:comment-length and expo-doctor with CI's settings pass locally. yarn.lock moves only @gryt/voice, and a clean install from it gets 0.5.9.

🤖 Generated with Claude Code

…(GRYT-1336)

0.5.9 is Gryt-chat/voice#63 and #64. #63 pauses the camera's sender when
the camera turns off. It used to remove it, and a camera turned back on
then took the screen's m-line (GRYT-1329). #64 lowers the microphone's
default ceiling from 510 to 64 kbps. The phone passes no channel bitrate,
so it gets the new default.

A sender keeps its stream id through replaceTrack, so a paused sender
comes back under the first stream's id. But the phone announced each new
stream's own id. On 0.5.9 everyone else would see a placeholder for a
camera turned back on, and a second screen share already did that on
0.5.8. Now the phone announces the id of the first stream each role sent
on the connection. It's the same rule as the desktop client's
senderStreamIds.ts (client#624, #625).

Co-Authored-By: Claude Opus 5 <[email protected]>
@sivert-io
sivert-io force-pushed the claude/GRYT-1336-mobile-voice-0.5.9 branch from 91c1f28 to 5920593 Compare September 21, 2026 11:13
@sivert-io
sivert-io merged commit c72236a into main Sep 21, 2026
5 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