Repository navigation
fix: keep publish consistent with a reconnect - #32
Merged
Merged
Conversation
A publish that waited for the media lock kept the connection it read before waiting. If a reconnect swapped the connection meanwhile, the publish negotiated with the replaced session. Read the connection once the lock is held, as stop_publish and the other publisher paths do. Co-authored-by: Neevash Ramdial (Nash) <mail@neevash.com>
A publish that ran between the connection swap and the restore had already added its sender to the new publisher. The restore added a second transceiver for the same track, the SFU rejected the negotiation and the SDK rejoined again. Skip tracks the publisher already sends. Co-authored-by: Neevash Ramdial (Nash) <mail@neevash.com>
dangusev
marked this pull request as ready for review
October 14, 2026 11:16
dangusev
approved these changes
Oct 14, 2026
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.
Two fixes for a
publishthat overlaps a reconnect (rejoin or migration). Each is its own commit with its own regression test.1.
publishuses the connection that is current when it gets the media lockRtcCore::publishread the publisher connection before waiting for the media lock. If a reconnect replaced the connection while it waited, the publish negotiated with the old session. After a rejoin it failed even though the call had recovered.publishnow reads the connection after taking the lock, likestop_publish,apply_publish_optionsandrestart_publisher_icealready do. A side benefit: apublishqueued behindleavenow fails withpublish() before join()and no longer negotiates on a torn-down connection. This mirrors the stale-negotiation fix in stream-video-swift (GetStream/stream-video-swift#1342).2. Each publication gets one sender after a reconnect
A
publishthat ran after the connection swap but beforerestore_published_trackshad already put its sender on the new publisher. The restore then added a second transceiver for the same track. The SFU rejected the duplicate m-line, so the SDK rejoined again. The restore now skips tracks the publisher already sends, the same way the JS SDK reuses existing transceivers.Tests
a_publish_that_waits_for_a_reconnect_negotiates_with_the_new_session: fails 10/10 without the fix and passes 30/30 with it. There is no timing dependence; the media lock orders the steps.restoring_publications_adds_no_second_sender_for_a_track_published_meanwhile: failed with a duplicated sender before the fix.Maintenance checks this run
GetStream/protocolmain; no proto changes.CallSettingsResponse::additional_fields.cargo fmt --check,cargo clippy -D warnings(stable, as in CI),cargo test --locked(including the live suites), doc tests andcargo doc -D warningsall pass. Thejoin_callexample joins and leaves cleanly.Note
Medium Risk
Changes core publish/reconnect negotiation ordering and restore logic; wrong locking or sender dedup could break publishing or recovery after reconnect.
Overview
Fixes two race conditions when
publishoverlaps a reconnect (rejoin or migration).RtcCore::publishnow takes the media lock before resolving publisher handles, so negotiation uses the connection that is current when the call proceeds—not the session that was replaced while the call waited on the lock. That avoids failed publishes after a successful rejoin and aligns withstop_publishand related paths (apublishqueued behindleavecan fail withpublish() before join()instead of negotiating on a torn-down PC).restore_published_tracksskips adding a transceiver when the publisher already has a sender for that track ID, so apublishthat ran after the connection swap does not get a duplicate m-line and trigger SFU rejection / another rejoin.The changelog documents both fixes; regression tests record Twirp
SetPublisherrouting and assert a single sender per track after restore.Reviewed by Cursor Bugbot for commit fd0e943. Bugbot is set up for automated code reviews on this repo. Configure here.