Skip to content
Open
11 changes: 11 additions & 0 deletions .changeset/google-cloud-tts-plugin.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
---
"@livekit/agents-plugin-google-cloud": patch
"@livekit/agents": patch
---

feat: add Google Cloud Text-to-Speech plugin

Ports the Google Cloud TTS integration from the Python SDK, supporting both
streaming (via gRPC bidirectional streaming) and non-streaming synthesis.
Uses @google-cloud/text-to-speech client with standard Google Cloud auth
(credentials object, keyFilename, GOOGLE_APPLICATION_CREDENTIALS, or ADC).
4 changes: 2 additions & 2 deletions agents/src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -334,11 +334,11 @@ export class AsyncIterableQueue<T> implements AsyncIterableIterator<T> {
this.#queue.put(AsyncIterableQueue.CLOSE_SENTINEL);
}

async next(): Promise<IteratorResult<T>> {
async next(options: { signal?: AbortSignal } = {}): Promise<IteratorResult<T>> {
if (this.#closed && this.#queue.items.length === 0) {
return { value: undefined, done: true };
}
const item = await this.#queue.get();
const item = await this.#queue.get(options);
if (item === AsyncIterableQueue.CLOSE_SENTINEL && this.#closed) {
return { value: undefined, done: true };
}
Expand Down
60 changes: 60 additions & 0 deletions plugins/google-cloud/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
<!--
SPDX-FileCopyrightText: 2026 LiveKit, Inc.

SPDX-License-Identifier: Apache-2.0
-->

# Google Cloud plugin for LiveKit Agents

The Agents Framework is designed for building realtime, programmable
participants that run on servers. Use it to create conversational, multi-modal
voice agents that can see, hear, and understand.

This package contains the Google Cloud plugin, which provides text-to-speech
via the [Google Cloud Text-to-Speech API](https://cloud.google.com/text-to-speech).

## Installation

```bash
pnpm add @livekit/agents-plugin-google-cloud
```

## Authentication

Credentials are resolved by the underlying `@google-cloud/text-to-speech` client in order:

1. `credentials` object passed directly (`{ client_email, private_key }`)
2. `keyFilename` path to a service account JSON key file
3. `GOOGLE_APPLICATION_CREDENTIALS` environment variable
4. Application Default Credentials (auto-detected by `gcloud auth`)

## Usage

```typescript
import { TTS } from '@livekit/agents-plugin-google-cloud';

// Streaming synthesis (gRPC, default)
const tts = new TTS({
language: 'en-US',
voiceName: 'en-US-Standard-H',
});

// Non-streaming synthesis (REST)
const tts = new TTS({
language: 'en-IN',
voiceName: 'en-IN-Standard-C',
streaming: false,
});

// Streaming synthesis
const stream = tts.stream();
stream.pushText('Hello, world!');
stream.flush();
for await (const event of stream) {
// event.frame contains AudioFrame data
}
```

## License

Apache 2.0
8 changes: 8 additions & 0 deletions plugins/google-cloud/api-extractor.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
/**
* Config file for API Extractor. For more info, please visit: https://api-extractor.com
*/
{
"$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json",
"extends": "../../api-extractor-shared.json",
"mainEntryPointFilePath": "./dist/index.d.ts"
}
51 changes: 51 additions & 0 deletions plugins/google-cloud/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
{
"name": "@livekit/agents-plugin-google-cloud",
"version": "1.4.4",
"description": "Google Cloud TTS plugin for LiveKit Node Agents",
"main": "dist/index.js",
"require": "dist/index.cjs",
"types": "dist/index.d.ts",
"exports": {
"import": {
"types": "./dist/index.d.ts",
"default": "./dist/index.js"
},
"require": {
"types": "./dist/index.d.cts",
"default": "./dist/index.cjs"
}
},
"author": "LiveKit",
"type": "module",
"repository": "git@github.com:livekit/agents-js.git",
"license": "Apache-2.0",
"files": [
"dist",
"src",
"README.md"
],
"scripts": {
"build": "tsup --onSuccess \"pnpm build:types\"",
"build:types": "tsc --declaration --emitDeclarationOnly && node ../../scripts/copyDeclarationOutput.js",
"clean": "rm -rf dist",
"clean:build": "pnpm clean && pnpm build",
"lint": "eslint -f unix \"src/**/*.{ts,js}\"",
"api:check": "api-extractor run --typescript-compiler-folder ../../node_modules/typescript",
"api:update": "api-extractor run --local --typescript-compiler-folder ../../node_modules/typescript --verbose"
},
"devDependencies": {
"@livekit/agents": "workspace:*",
"@livekit/agents-plugins-test": "workspace:*",
"@livekit/rtc-node": "catalog:",
"@microsoft/api-extractor": "^7.35.0",
"tsup": "^8.3.5",
"typescript": "^5.0.0"
},
"dependencies": {
"@google-cloud/text-to-speech": "^6.0.0"
},
"peerDependencies": {
"@livekit/agents": "workspace:*",
"@livekit/rtc-node": "catalog:"
}
}
19 changes: 19 additions & 0 deletions plugins/google-cloud/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// SPDX-FileCopyrightText: 2026 LiveKit, Inc.
//
// SPDX-License-Identifier: Apache-2.0
import { Plugin } from '@livekit/agents';

export * from './models.js';
export { ChunkedStream, SynthesizeStream, TTS, type TTSOptions } from './tts.js';

class GoogleCloudPlugin extends Plugin {
constructor() {
super({
title: 'google-cloud',
version: __PACKAGE_VERSION__,
package: __PACKAGE_NAME__,
});
}
}

Plugin.registerPlugin(new GoogleCloudPlugin());
39 changes: 39 additions & 0 deletions plugins/google-cloud/src/models.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// SPDX-FileCopyrightText: 2026 LiveKit, Inc.
//
// SPDX-License-Identifier: Apache-2.0

/** Google Cloud TTS models. */
export type TTSModel =
| 'chirp-3'
| 'chirp-3-hd'
| 'journey'
| 'journey-2'
| 'chirp-2-hd'
| 'chirp-2-lq'
| string;

/** Google Cloud TTS voice genders. */
export type TTSGender = 'male' | 'female' | 'neutral';

/** Speech language codes (BCP-47). */
export type TTSLanguage =
| 'en-US'
| 'en-GB'
| 'en-AU'
| 'en-IN'
| 'hi-IN'
| 'bn-IN'
| 'ta-IN'
| 'te-IN'
| 'mr-IN'
| 'gu-IN'
| 'kn-IN'
| 'ml-IN'
| 'pa-IN'
| string;

/** Audio encoding formats for non-streaming synthesis. */
export type TTSAudioEncoding = 'LINEAR16' | 'MP3' | 'OGG_OPUS' | 'MULAW' | 'ALAW';

/** Default voice name used when none is specified. */
export const DEFAULT_VOICE_NAME = 'en-US-Standard-H';
Loading