Repository navigation
fix(realtime): subscribe to the server's audio track only when the client publishes audio - #219
Merged
Merged
Conversation
…ient publishes audio (remoteAudio option)
tomershlasky
force-pushed
the
fix/video-only-remote-subscribe
branch
from
October 7, 2026 13:12
c10b66f to
4b7275d
Compare
commit: |
…ream; drop the remoteAudio option Stacked on #219. The server's audio track is the client's own audio played back delayed to stay in sync with the transformed video, so the only correct subscription rule is "subscribe exactly when we publish audio", which #219 already uses as the default. The explicit `remoteAudio` override had no caller: `true` would serve a model that emits audio the client never sent (none is served), `false` would serve an app that sends its microphone but does not want the synced voice back. Removing it keeps the fix transparent to apps and avoids a public knob for a hypothetical. The connect-time decision is stable for the life of the session: the SDK's only post-connect change to the local stream is replaceVideoTrack, which preserves the audio tracks. Tests: the two option tests go; a null-localStream case pins the video-only default for sessions without a camera stream.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
A video-only React Native client on iOS gets a microphone permission prompt on a fresh install even though it never publishes audio. The realtime server publishes an audio track at join on every session (it is what libwebrtc's initial bandwidth probe rides on, so it stays), and the SDK joined the LiveKit room with the default
autoSubscribe: true, so it subscribed to that track. On iOS, playing out a remote audio track starts the WebRTC audio engine, which is what triggers the microphone prompt. The server's audio track is the client's own audio delayed to stay in sync with the transformed video, so a video-only client was only ever receiving silence.What
autoSubscribe: falseand the SDK subscribes per track: always to the server's video, and to its audio exactly when the local stream carries an audio track. No new option; the rule is derived from what the app publishes (fix(realtime): derive the remote-audio subscription from the local stream; drop the remoteAudio option #220, merged into this branch).connect(publications already in the room never emitTrackPublished), on every laterTrackPublished, and onRoomEvent.Reconnected(a full reconnect lands on a fresh SFU session).setSubscribed(true)is idempotent, so repeating it is safe. Signal resumes already re-send the subscribed set via livekit-client's sync state.Behavior change
Apps that publish audio keep today's behavior. Apps that publish video only now receive a remote stream with no audio track (it was a silent track before). A model that one day emits audio the client never sent would need an SDK change driven by a server capability, not an app flag. Suggest shipping as a minor release with a changelog note.
Tests
tests/realtime.unit.test.ts: video-only client subscribes video only (join sweep, late publication, and a strayTrackSubscribedaudio never reaches the consumer), audio-publishing client gets audio, no local stream at all, re-sweep onReconnected, non-server participants ignored.getAudioTracksandremoteParticipants;connectassertions now include{ autoSubscribe: false }.pnpm test,pnpm typecheckandbiome checkare clean. Not yet verified end to end on an iOS device.Note
Medium Risk
Changes WebRTC subscription behavior for all realtime publishers; video-only apps lose the (silent) remote audio track, while audio sessions should match prior behavior.
Overview
Fixes spurious iOS microphone permission on video-only realtime clients by stopping blind subscription to the inference server’s always-present audio track.
LiveKit connect now uses
{ autoSubscribe: false }. The SDK selectively subscribes to the inference server’s video always, and to audio only when the localMediaStreamhas audio tracks (wantsRemoteAudio()). A post-connect sweep plusTrackPublishedandReconnectedhandlers re-apply subscriptions;TrackSubscribedstill omits audio from the emittedremoteStreamwhen the client is video-only.README adds a Remote audio section: play the delayed server audio (not the local mic) when you publish audio; video-only sessions get no remote audio track.
Tests cover video-only vs audio publishing, reconnect re-sweep, and non-server participants. Watch/subscribe client behavior is unchanged.
Reviewed by Cursor Bugbot for commit e44b601. Bugbot is set up for automated code reviews on this repo. Configure here.