Skip to content

Ensure input stream is only tee'd when it's actually being used - #1088

Merged
lukasIO merged 3 commits into
mainfrom
lukas/hanging-tee
Mar 5, 2026
Merged

Ensure input stream is only tee'd when it's actually being used#1088
lukasIO merged 3 commits into
mainfrom
lukas/hanging-tee

Conversation

@lukasIO

@lukasIO lukasIO commented Mar 2, 2026

Copy link
Copy Markdown
Contributor

Description

closes #1070

Changes Made

Pre-Review Checklist

  • Build passes: All builds (lint, typecheck, tests) pass locally
  • AI-generated code reviewed: Removed unnecessary comments and ensured code quality
  • Changes explained: All changes are properly documented and justified above
  • Scope appropriate: All changes relate to the PR title, or explanations provided for why they're included
  • Video demo: A small video demo showing changes works as expected and did not break any existing functionality using Agent Playground (if applicable)

Testing

  • Automated tests added/updated (if applicable)
  • All tests pass
  • Make sure both restaurant_agent.ts and realtime_agent.ts work properly (for major changes)

Additional Notes


Note to reviewers: Please ensure the pre-review checklist is completed before starting your review.

@changeset-bot

changeset-bot Bot commented Mar 2, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: b1c8ba6

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

This PR includes changesets to release 21 packages
Name Type
@livekit/agents Patch
@livekit/agents-plugin-anam Patch
@livekit/agents-plugin-baseten Patch
@livekit/agents-plugin-bey Patch
@livekit/agents-plugin-cartesia Patch
@livekit/agents-plugin-deepgram Patch
@livekit/agents-plugin-elevenlabs Patch
@livekit/agents-plugin-google Patch
@livekit/agents-plugin-hedra Patch
@livekit/agents-plugin-inworld Patch
@livekit/agents-plugin-lemonslice Patch
@livekit/agents-plugin-livekit Patch
@livekit/agents-plugin-neuphonic Patch
@livekit/agents-plugin-openai Patch
@livekit/agents-plugin-phonic Patch
@livekit/agents-plugin-resemble Patch
@livekit/agents-plugin-rime Patch
@livekit/agents-plugin-sarvam Patch
@livekit/agents-plugin-silero Patch
@livekit/agents-plugins-test Patch
@livekit/agents-plugin-xai 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

@lukasIO
lukasIO requested a review from toubatbrian March 2, 2026 15:38

@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 potential bugs to report.

View in Devin Review to see 3 additional findings.

Open in Devin Review

@toubatbrian toubatbrian 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.

LGTM. qq: is this change addressing a specific bug, or is it mainly a general improvement?

@lukasIO

lukasIO commented Mar 5, 2026

Copy link
Copy Markdown
Contributor Author

is this change addressing a specific bug, or is it mainly a general improvement?

see the linked issue #1070

@lukasIO
lukasIO merged commit 062c619 into main Mar 5, 2026
6 of 8 checks passed
@lukasIO
lukasIO deleted the lukas/hanging-tee branch March 5, 2026 06:52

@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 found 1 new potential issue.

View 4 additional findings in Devin Review.

Open in Devin Review

Comment on lines +504 to +511
if (this.realtimeSession && this.audioRecognition) {
const [realtimeAudioStream, recognitionAudioStream] = this.audioStream.stream.tee();
this.realtimeSession.setInputAudioStream(realtimeAudioStream);
}

if (this.audioRecognition) {
this.audioRecognition.setInputAudioStream(recognitionAudioStream);
} else if (this.realtimeSession) {
this.realtimeSession.setInputAudioStream(this.audioStream.stream);
} else if (this.audioRecognition) {
this.audioRecognition.setInputAudioStream(this.audioStream.stream);

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.

🔴 aecWarmupAudioFilter is defined but never applied to the audio stream

The refactored code creates the aecWarmupAudioFilter TransformStream (lines 492-500) but never pipes the audio stream through it. The old code applied the filter via .pipeThrough(aecWarmupAudioFilter) before .tee(), which discarded audio frames during AEC warmup (when the agent is speaking and _aecWarmupRemaining > 0). In the new code, all three branches pass this.audioStream.stream (or its .tee()) directly to consumers without the filter. This means audio frames that should be discarded during AEC warmup will now be forwarded to realtimeSession.setInputAudioStream() and audioRecognition.setInputAudioStream(), potentially causing echo/feedback issues.

Prompt for agents
In agents/src/voice/agent_activity.ts, the attachAudioInput method (around line 484) defines an aecWarmupAudioFilter TransformStream but never uses it. The audio stream must be piped through this filter before being consumed. All three branches (lines 504-512) need to apply the filter:

1. For the tee branch (realtimeSession && audioRecognition): pipe through filter first, then tee:
   const [realtimeAudioStream, recognitionAudioStream] = this.audioStream.stream.pipeThrough(aecWarmupAudioFilter).tee();

2. For realtimeSession-only branch: pipe through filter:
   this.realtimeSession.setInputAudioStream(this.audioStream.stream.pipeThrough(aecWarmupAudioFilter));

3. For audioRecognition-only branch: pipe through filter:
   this.audioRecognition.setInputAudioStream(this.audioStream.stream.pipeThrough(aecWarmupAudioFilter));

Note: The comment on lines 488-491 explains why the filter is applied on the downstream stream rather than on the source audioStream. Make sure the filter is still applied on the downstream side.
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

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.

Memory leak: unconsumed .tee() branch in attachAudioInput when not using RealtimeModel

2 participants