Skip to content

feat(airy): add Airy TTS plugin - #7394

Open
swigls wants to merge 8 commits into
livekit:mainfrom
Out-of-Set:feat/airy-tts-plugin
Open

swigls wants to merge 8 commits into
livekit:mainfrom
Out-of-Set:feat/airy-tts-plugin

Conversation

@swigls

@swigls swigls commented Sep 22, 2026 •

Copy link
Copy Markdown

Adds livekit-plugins-airy so LiveKit agents can use Airy Cloud TTS. Each complete utterance is sent to Airy's streaming speech endpoint, and the returned 24 kHz mono signed 16-bit PCM is forwarded as it arrives. The plugin also exposes Airy's trailing_silence option for natural pauses between sentences.

Usage

Set AIRY_API_KEY, then configure the session's TTS:

from livekit.plugins import airy

speech = airy.TTS(language="ko")  # 0.3 s trailing silence by default
# AgentSession(..., tts=speech)

language also supports "en". Model, voice, and style can be configured; otherwise the plugin uses Airy's documented defaults. The LiveKit plugin defaults trailing_silence to 0.3 seconds per utterance; Airy's API default remains 0. Set it to a value from 0 to 5, or pass None to defer to the API default. See the streaming API documentation and the package README for installation and the runnable agent example.

Behavior

  • Uses POST /v1/audio/speech/stream with progressive PCM output. streaming=False describes text input; LiveKit's StreamAdapter supplies complete sentences.
  • Sends trailing_silence with each synthesis request by default; omits it when explicitly set to None. Rejects non-finite and out-of-range values locally.
  • Does not follow redirects; preserves 3xx status codes and treats them as non-retryable.
  • Validates input, options, response format, empty audio, and incomplete PCM samples, and preserves provider request IDs.
  • Bounds connection acquisition and socket reads using APIConnectOptions.timeout.
  • Preserves HTTP status and retry policy even if the error body times out or disconnects, or an injected session enables automatic HTTP exceptions.
  • Propagates cancellation and keeps injected/shared HTTP sessions caller-owned. Transport failures after PCM begins are not retried.
  • Adds workspace registration, the livekit-agents[airy] extra, documentation, and tests.

Validation

  • uv run pytest tests/test_plugin_airy_tts.py tests/test_agent_tts_node.py tests/test_audio_byte_stream.py --unit -q — 125 passed after merging main at 1.8.3, including the 0.3-second default, explicit API-default omission, range, invalid-value, and redirect cases.
  • make check — formatting, lint, and strict type checking passed for 686 source files.
  • uv lock --check — resolved successfully with the current 1.8.3 workspace.
  • Live Airy streaming requests with Sori at 0 and 0.5 seconds and Gina at the plugin default of 0.3 seconds returned PCM. Gina's responses ended with exactly 7,200 zero samples (0.3 seconds) at 24 kHz.
  • Previous browser-to-LiveKit-Cloud conversation check covered Korean STT, LLM, Sori TTS, WebRTC playback, and room cleanup. The local 5092 demo now uses Gina and the 0.3-second plugin default, offers 0/0.3-second comparison clips, and was checked for LiveKit room connection and cleanup.

Limits

  • Each utterance must contain 1–1,280 Unicode characters; oversized input is rejected without automatic splitting or truncation.
  • Native text-input streaming and word alignment are unsupported.
  • Adding trailing silence lengthens each utterance's audio; it need not delay the first PCM frame.
  • Retry-After is retained as error metadata; LiveKit's retry scheduler does not dynamically honor it.
  • Client cancellation does not guarantee cancellation of provider-side synthesis or billing.

The Out of Set / Airy team intends to maintain this provider integration.

@CLAassistant

CLAassistant commented Sep 22, 2026 •

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

@AinaLuc

AinaLuc commented Sep 22, 2026

Copy link
Copy Markdown

Hey Hyeonseung, I took a quick look at PR #7394. CI is green and I didn't spot any blocking issues in the Airy TTS plugin code.

The PR is still in draft, so the main thing left is to mark it ready for review when you're comfortable. Reviewer should mainly double-check the Airy API contract/defaults, since no live API smoke test was run without credentials.

@swigls
swigls marked this pull request as ready for review September 23, 2026 05:46
@swigls
swigls requested a review from a team as a code owner September 23, 2026 05:46
devin-ai-integration[bot]

This comment was marked as resolved.

@AinaLuc

AinaLuc commented Sep 23, 2026

Copy link
Copy Markdown

Thanks for the updates. CI is green and the trailing-silence additions look reasonable.

I agree with Devin's remaining comment: redirects/non-2xx responses should go through _status_error so the original status and retry policy are preserved. Could you change response.status >= 400 to not 200 <= response.status < 300?

@AinaLuc

AinaLuc commented Sep 23, 2026

Copy link
Copy Markdown

@swigls CI is green and Devin's remaining comment is resolved. This looks ready for a final human review/approval pass.

This branch has not been deployed

No deployments
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