You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Cancellation during screen share enable orphans track resources after service bind #985
#983 fixes ScreenCaptureService staying bound when a coroutine is cancelled duringScreenCaptureConnection.connect(). A broader follow-up remains: LocalParticipant.setScreenShareEnabled / setTrackEnabled can still abandon a newly created screencast track on cancellation without calling stop() / dispose(), leaking WebRTC and capture resources. If cancel happens after a successful bind, the service binding is orphaned too.
Background
Screen share enable currently does roughly:
val track = createScreencastTrack(...)
track.startForegroundService(...) // suspend: bind + startForeground
track.startCapture()
if (!publishVideoTrack(track, ...)) {
// cleanup only on publish failure
track.stopCapture()
track.stop()
track.dispose()
}
setTrackEnabled has no try / finally around this path. Cleanup runs only when publishVideoTrack returns false. A CancellationException from startForegroundService or publishVideoTrack unwinds out of the function and drops the local track reference without cleanup.
After startForegroundService returns, only LocalScreencastVideoTrack.stop() → ScreenCaptureConnection.stop() releases the binding. Cancel after that point therefore also leaves ScreenCaptureService bound for the lifetime of the context.
What gets orphaned
Cancellation timing
Service binding
Other resources
After createScreencastTrack, during connect() (before it returns)
After startForegroundService returns, before / during publishVideoTrack
Orphaned
Same as above; after startCapture(), active MediaProjection can keep running too
Expected behavior
Cancelling setScreenShareEnabled(true, ...) (or the surrounding scope) should always tear down any screencast track that was created but not successfully published: stop capture, unbind / stop the screen capture service if it was started, dispose WebRTC objects, and invoke any onStop callback as appropriate.
Suggested direction
Make ownership transfer cancellation-safe in LocalParticipant.setTrackEnabled for SCREEN_SHARE (and likely review the camera / mic enable paths for the same pattern): e.g. try / finally that disposes the unpublished track on cancel or failure.
Confirm LocalScreencastVideoTrack / SurfaceTextureHelper ownership so dispose is correct even when publish never completes.
Add tests that cancel at each suspend point (startForegroundService, publishVideoTrack) and assert resources are released (and the service is unbound when a bind had succeeded).
Activity
adrian-niculescu commentedon Jul 27, 2026
@davidliu, shall I file a PR for this?
davidliu commentedon Jul 27, 2026
@adrian-niculescu yeah if you're able to, that'd be helpful.
adrian-niculescu commentedon Jul 27, 2026
Alright, I will, then. I was already playing with the followups I mentioned before.
L.E. PR: #986
Fixed setTrackEnabled orphaning track resources when cancelled before…
Fixed setTrackEnabled orphaning track resources when cancelled before…
Fixed setTrackEnabled orphaning track resources when cancelled before…
Fixed setTrackEnabled orphaning track resources when cancelled before…
Fixed setTrackEnabled orphaning track resources when cancelled before…
Fixed setTrackEnabled orphaning track resources when cancelled before…
Fixed setTrackEnabled orphaning track resources when cancelled before…
Fixed setTrackEnabled orphaning track resources when cancelled before…
Fixed setTrackEnabled orphaning track resources when cancelled before…
Fixed setTrackEnabled orphaning track resources when cancelled before…
Fixed setTrackEnabled orphaning track resources when cancelled before…