Skip to content

fix(rtc): end AudioMixer iteration when endInput() runs with no streams left - #744

Open
Abhishek-B-R wants to merge 1 commit into
livekit:mainfrom
Abhishek-B-R:fix/audio-mixer-end-input-wakeup
Open

Abhishek-B-R wants to merge 1 commit into
livekit:mainfrom
Abhishek-B-R:fix/audio-mixer-end-input-wakeup

Conversation

@Abhishek-B-R

Copy link
Copy Markdown

Description

If a consumer is already waiting on for await (const frame of mixer) and endInput() is called after the last stream was removed (or before any was added), the loop never ends.

const mixer = new AudioMixer(48000, 1);
const done = (async () => { for await (const _ of mixer) {} })();
// ...later, nothing left to mix
mixer.endInput();
await done; // never settles

When there are no streams, the mixer task parks on streamSignal.waitForItem() until addStream() puts a signal. endInput() only sets this.ending = true, so nothing wakes that task. It never reaches the ending && streams.size === 0 check at the top of its loop, so it never closes the output queue, and the consumer parked in queue.waitForItem() waits forever. The existing "handles empty mixer" test passes only because it calls endInput() before it starts iterating, so getNextFrame() sees the flag on its first check.

The Python mixer does not have this problem: its _mixer loop sleeps 10ms and rechecks _ending when there are no streams, so end_input() is always noticed.

Fix

endInput() also closes streamSignal. A parked mixer task wakes, sees it is ending with no streams, breaks, and closes the output queue, which releases the consumer. When streams are still active nothing changes: the task does not touch streamSignal while it has streams, and it still drains them until they are exhausted. addStream() after endInput() already throws, so the closed signal queue is never written to again.

Testing

Two tests in audio_mixer.test.ts, each giving the consumer 1s to finish after endInput():

  • consumer waiting, no streams ever added, then endInput()

  • consumer waiting, a silent stream added and removed, then endInput()

  • Before the change: both fail with expected 'hung' to deeply equal [], 8 passed, 2 failed.

  • After: 10 of 10 pass in src/audio_mixer.test.ts (473ms, down from 2.48s with the two hangs), and 22 of 22 across audio_mixer and async_queue on 15 repeated runs.

  • npx vitest run src in packages/livekit-rtc: all unit tests pass. The two e2e files fail to load on main too, because they need a built livekit-server-sdk and a live server.

  • tsc --noEmit, pnpm lint and prettier report nothing in the changed files.

A patch changeset for @livekit/rtc-node is included.

…ms left

When the last stream has been removed (or none was ever added), the mixer
task parks on the stream signal queue waiting for an addStream() that can
no longer happen. endInput() only set the ending flag, so nothing woke the
task, the output queue was never closed, and a consumer already waiting in
for await stayed blocked forever.

endInput() now closes the stream signal queue, so the parked task wakes,
sees it is ending with no streams, exits and closes the output queue.
@changeset-bot

changeset-bot Bot commented Oct 17, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: c2a1096

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@livekit/rtc-node Patch

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

@CLAassistant

Copy link
Copy Markdown

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.
You have signed the CLA already but the status is still pending? Let us recheck it.

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Devin Review: No Issues Found

Devin Review analyzed this PR and found no bugs or issues to report.

Devin Review

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants