Skip to content

feat(agents): add sampleRate option to OpenAI.TTS - #2448

Open
BlueskyFR wants to merge 2 commits into
livekit:mainfrom
BlueskyFR:patch-1
Open

feat(agents): add sampleRate option to OpenAI.TTS#2448
BlueskyFR wants to merge 2 commits into
livekit:mainfrom
BlueskyFR:patch-1

Conversation

@BlueskyFR

@BlueskyFR BlueskyFR commented Sep 8, 2026

Copy link
Copy Markdown

Description

Currently, the OpenAI.TTS class hardcodes a sample rate of 24000 hz.

Some models, such as FishAudio S2 Pro, are using a different one, such as 44100 hz.
This PR adds the ability to override the sample rate as part of the constructor, which falls back to 24000 hz as before if not supplied.

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
    • No docs yet!
  • 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.

Please tell me what I can do to get this merged asap!

@BlueskyFR
BlueskyFR requested a review from a team as a code owner September 8, 2026 09:44
@changeset-bot

changeset-bot Bot commented Sep 8, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: d737a2d

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

This PR includes changesets to release 38 packages
Name Type
@livekit/agents-plugin-openai Patch
@livekit/agents-plugin-anam Patch
@livekit/agents-plugin-cartesia Patch
@livekit/agents-plugin-cerebras Patch
@livekit/agents-plugin-elevenlabs Patch
@livekit/agents-plugin-fishaudio Patch
@livekit/agents-plugin-google Patch
@livekit/agents-plugin-hume Patch
@livekit/agents-plugin-inworld Patch
@livekit/agents-plugin-krisp Patch
@livekit/agents-plugin-neuphonic Patch
@livekit/agents-plugin-perplexity Patch
@livekit/agents-plugin-rime Patch
@livekit/agents-plugin-sarvam Patch
@livekit/agents-plugin-xai Patch
@livekit/agents Patch
@livekit/agents-plugin-anthropic Patch
@livekit/agents-plugin-assemblyai Patch
@livekit/agents-plugin-azure Patch
@livekit/agents-plugin-baseten Patch
@livekit/agents-plugin-bey Patch
@livekit/agents-plugin-deepgram Patch
@livekit/agents-plugin-did Patch
@livekit/agents-plugin-lemonslice Patch
@livekit/agents-plugin-liveavatar Patch
@livekit/agents-plugin-livekit Patch
@livekit/agents-plugin-minimax Patch
@livekit/agents-plugin-mistral Patch
@livekit/agents-plugin-mistralai Patch
@livekit/agents-plugin-phonic Patch
@livekit/agents-plugin-protoface Patch
@livekit/agents-plugin-resemble Patch
@livekit/agents-plugin-runway Patch
@livekit/agents-plugin-silero Patch
@livekit/agents-plugin-soniox Patch
@livekit/agents-plugin-tavus Patch
@livekit/agents-plugins-test Patch
@livekit/agents-plugin-trugen 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

@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 3 potential issues.

1 flag not posted on this PR by your GitHub settings — view it in Devin Review. (Configure)

Devin Review

Comment thread plugins/openai/src/tts.ts
const buffer = await this.stream.then((r) => r.arrayBuffer());
const requestId = shortuuid();
const audioByteStream = new AudioByteStream(OPENAI_TTS_SAMPLE_RATE, OPENAI_TTS_CHANNELS);
const audioByteStream = new AudioByteStream(this.sampleRate, OPENAI_TTS_CHANNELS);

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.

🔴 Invalid sample rates freeze synthesis

With sampleRate zero or negative, synthesis enters an endless loop after receiving audio. AudioByteStream.write cannot consume non-positive frame sizes, blocking the Node.js event loop.

Prompt for agents
Validate the new sampleRate constructor option before it reaches the base TTS class or AudioByteStream. Accept only finite positive sample rates, preferably positive integers, and throw a clear configuration error otherwise. Ensure the validated or defaulted value is used consistently for both TTS metadata and PCM framing in plugins/openai/src/tts.ts.
Devin Review

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

Comment thread plugins/openai/src/tts.ts
},
{ signal },
),
this.#opts.sampleRate!,

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.

🟡 Undefined sample rate silences output

With explicit sampleRate: undefined, construction advertises 24 kHz while #opts retains undefined. Each synthesis then emits no audio frames.

Suggested change
this.#opts.sampleRate!,
this.sampleRate,
Devin Review

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

Comment thread plugins/openai/src/tts.ts
const buffer = await this.stream.then((r) => r.arrayBuffer());
const requestId = shortuuid();
const audioByteStream = new AudioByteStream(OPENAI_TTS_SAMPLE_RATE, OPENAI_TTS_CHANNELS);
const audioByteStream = new AudioByteStream(this.sampleRate, OPENAI_TTS_CHANNELS);

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.

🟡 Final speech audio is discarded

Responses outside exact 100 ms multiples lose their final partial frame. AudioByteStream.write retains that audio, but this stream closes without flushing it.

Prompt for agents
In ChunkedStream.run in plugins/openai/src/tts.ts, include AudioByteStream.flush() output after write(buffer), then feed both complete and final partial frames through the existing last-frame logic. Preserve exactly one final=true event for the final emitted frame.
Devin Review

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

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

Add sampleRate option for OpenAI.TTS in agents plugin.
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.

3 participants