Reuse inactive publisher transceivers in RTCEngine to reduce memory growth on republish#1827
Open
moufmouf wants to merge 2 commits intolivekit:mainfrom
Open
Reuse inactive publisher transceivers in RTCEngine to reduce memory growth on republish#1827moufmouf wants to merge 2 commits intolivekit:mainfrom
moufmouf wants to merge 2 commits intolivekit:mainfrom
Conversation
…ansceiver churn `RTCEngine.createSender`/`createSimulcastSender` always created new publisher transceivers via addTransceiver(). During repeated unpublish/publish cycles, this could accumulate inactive transceivers and increase memory usage. Add a reuse path that: - looks for an inactive publisher transceiver of matching media kind - switches it back to sendonly - replaces its sender track instead of creating a new transceiver - applies to both primary sender creation and simulcast sender creation This reduces transceiver churn and keeps memory growth bounded in restart-heavy flows (e.g. screenshare stop/start loops).
🦋 Changeset detectedLatest commit: d3b394d The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
…gine to reduce memory growth on republish
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?
I'm developing WorkAdventure, a virtual space platform and we use Livekit for big meetings (more than 4 participants). Under 4 participants, we use a direct P2P mesh. I'm telling this because we have a workflow where we manage the MediaTracks (they are created by us, not Livekit JS client SDK) and when we unpublish a track, we usually set
stopOnUnpublish: falsewhen callinglocalParticipant.unpublishTrack.The issue that triggered this PR is that when we start publishing a screen sharing, the memory goes up by about 400MB. We stop publishing the screen sharing with
localParticipant.unpublishTrack, the memory does not go down. We start publishing another screen sharing again (maybe another window), the memory goes up by another 400MB, etc...In short, we have a memory leak, where each started screen sharing is never releasing memory.
As a side note, using
track.pauseUpstreamto stop the track then replace the track with another track later seems to work better, but this workflow causes other issues.Finding the memory leak
I tried to track down where the memory leak was, and after a few trial and errors (and with the help of Codex), I ended up finding that the transceivers in the
RTCEngineseem to be piling up each time we start a new track. TheRTCRtpTransceiverseem to hold a reference to theMediaTrackthat is never freed and eating a lot of memory. I did not find any way to properly free theMediaTrackreference, but Codex (again) proposed me the patch below. Basically, it tries to reuse an inactive existing sender that shares the same track "kind".I tested this with WorkAdventure and the patch works. When I stop / start many screen sharing many times, the memory does not pile up. I also re-read the patch and validated it myself (to avoid any AI slop).
Note: I tried an alternative: freeing the memory as soon as
localParticipant.unpublishTrackis called (usingreplaceTrack(null)) instead of waiting for the next track to start to reuse the transceiver. Alas, I could not make this work (that would be ideal as the memory would be freed as soon as we finish publishing... here, we have to wait getting out of the Livekit room for the memory to be freed)What do you think of this patch? I can happily work on it if it needs any improvement.