Repository navigation
Conversation
If stop() was called while the audio thread was still creating the AudioSwitch in start(), stop() saw no switch to tear down, and the new switch was then started and activated with nothing left to stop it. start() now records the handler it posted to. The creation job checks under the handler's lock that this start is still current before publishing the switch, and drops it otherwise. Once published, a subsequent stop() posts its teardown behind the running job. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
🦋 Changeset detectedLatest commit: 545cace 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 |
| synchronized(this@AudioSwitchHandler) { | ||
| if (handler !== startHandler) { | ||
| return@postAtFrontOfQueue | ||
| } | ||
| audioSwitch = switch |
There was a problem hiding this comment.
🔴 Repeated starts leave audio routing active
If start() runs again during switch construction, both jobs pass the startHandler check and publish separate switches. The second replaces audioSwitch, so stop() cannot stop the first; audio routing remains active.
Learn more
A start job is queued on the handler thread, but the switch reference stays null until construction finishes. If another start() occurs while construction is already running, start observes null and queues a second job on the same handler. Both jobs pass the handler identity check. The second job replaces the first switch reference; stop only retains and stops the latest switch.
Example: Thread A begins constructing switch A. A second start() queues switch B before A publishes. Both publish and activate. A later stop() stops B; A stays active.
Recommended fix: Track a start generation or pending-start state, and reject jobs that no longer own the current generation. Ensure a running job is stopped if a newer start supersedes it; add a test that pauses construction across a repeated start().
Was this helpful? React with 👍 or 👎 to provide feedback.
|
Diffuse output: AARJAR |
Problem
start()builds theAudioSwitchin a job on theAudioSwitchHandlerThread. Ifstop()is called while that job is already running,stop()can't cancel it, and it finds noaudioSwitchto tear down yet. The job then stores the switch and callsstart()/activate(), leaving audio focus, audio mode and routing active with nothing to stop them.Fix
start()records the handler it posted the creation job to. Before storing the switch, the job checks under the handler's lock (the same onestart()/stop()use) thathandleris still that one.stop()got there first:handlerhas changed, so the job drops the switch before starting it. That's safe because the audioswitch constructors register nothing; scanning, focus and routing only begin instart()/activate().stop()finds it and posts its teardown behind the running job.This follows up on #967, which made
stop()clearaudioSwitchstraight away.Testing
:livekit-android-sdk:compileDebugKotlin,detektRelease,spotlessCheck🤖 Generated with Claude Code