-
Notifications
You must be signed in to change notification settings - Fork 239
fix(room): finish local unpublish cleanup when the transport is gone #1436
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
LautaroPetaccio
wants to merge
2
commits into
livekit:main
Choose a base branch
from
LautaroPetaccio:fix/unpublish-track-cleanup-on-error
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
2 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,16 @@ | ||
| --- | ||
| livekit: patch | ||
| livekit-capture: patch | ||
| livekit-ffi: patch | ||
| --- | ||
|
|
||
| Fix a local publication and its track leaking when unpublish cannot reach the transport. | ||
|
|
||
| Unpublishing asks the engine to remove the RTP sender and stopped on failure, skipping the | ||
| cleanup that detaches the track from its publication. The publication holds its track and | ||
| the track holds the publication back through its mute callbacks, so the pair kept itself | ||
| alive along with the transceiver and its peer connection. Removing the sender fails on two | ||
| routine paths — an abnormal disconnect, where the transport is already closed, and a full | ||
| reconnect, where the sender belongs to the replaced transport — and the error was discarded, | ||
| so neither surfaced. The local cleanup now always runs and the failure is reported once | ||
| local state is consistent. |
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
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
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
Oops, something went wrong.
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🔴 Full reconnects retain stale frame cryptors
When
remove_trackfails during a full reconnect,local_track_unpublishedis skipped and the old frame cryptor remains registered.on_local_track_unpublishedis the only per-track path removing the previous SID's cryptor. Each full reconnect retains another native cryptor and its old RTP sender until room shutdown.Learn more
A full reconnect replaces the RTC session, then republishes every local track. Removing an old sender through the new session fails, so this guard suppresses the callback. That callback invokes
on_local_track_unpublished, which removes the frame cryptor stored under the old track SID. The subsequent publish creates a new frame cryptor under the new SID, leaving the old native cryptor registered. The stale cryptor holds the old RTP sender and related native transport resources until the room-wide E2EE cleanup runs at shutdown.Example: An encrypted track starts under SID
TR_old. A full reconnect makes sender removal fail, then republishes it asTR_new. The manager contains cryptors for bothTR_oldandTR_new; repeated reconnects add another stale entry each time.Recommended fix: Separate internal E2EE teardown from the externally visible
LocalTrackUnpublishedevent. Always remove the cryptor for the old SID after local unpublish cleanup, while preserving the reconnect event contract for bindings. Add a full-reconnect lifecycle test that verifies the old SID disappears and the cryptor count returns to one.Was this helpful? React with 👍 or 👎 to provide feedback.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I implemented this and could not reproduce the leak, so I reverted it.
On unpatched code the cryptor map after a full reconnect holds one entry under the new sid, with the old one already gone:
So
remove_trackis not failing on the reconnect path the way it does on an abnormal disconnect, and the unpublished callback removes the old sid normally. The other path is covered too:RoomSession::closecallse2ee_manager.cleanup(), which clears every cryptor.The test I wrote for it passed with and without the change, which makes it worthless as a guard. Measured against a local dev server, so if you have a trace showing two cryptors after a reconnect, send it and I will put the change back.