Skip to main content
Integration with LiveKit is currently being reviewed

Overview

The livekit-plugins-camb package enables you to integrate Camb.ai’s MARS text-to-speech models into your LiveKit voice agents. This integration provides high-quality, low-latency voice synthesis for real-time conversational AI applications.

Key Features

  • MARS Models: Access to Camb.ai’s latest generation TTS models (mars-flash, mars-pro)
  • 140+ Languages: Extensive multilingual support
  • Real-time Streaming: HTTP chunked streaming for low-latency audio
  • Voice Customization: Voice selection and enhanced pronunciation for names/places
  • Model-specific Sample Rates: 22.05kHz (mars-flash) or 48kHz (mars-pro)

Installation

Prerequisites

  • Python 3.9 or higher
  • A Camb.ai API key (get one here)
  • LiveKit Cloud account or self-hosted LiveKit server

Install the Plugin

pip install livekit-plugins-camb
For a complete voice agent setup with VAD (Voice Activity Detection):
pip install livekit-plugins-camb 'livekit-agents[silero]' python-dotenv

Quick Start

1. Set Up Environment Variables

Create a .env file in your project directory:
# Camb.ai API key
CAMB_API_KEY=your_camb_api_key

# LiveKit credentials
LIVEKIT_URL=wss://your-project.livekit.cloud
LIVEKIT_API_KEY=your_livekit_api_key
LIVEKIT_API_SECRET=your_livekit_api_secret

# LLM provider (e.g., OpenAI)
OPENAI_API_KEY=your_openai_api_key

# STT provider (e.g., Deepgram)
DEEPGRAM_API_KEY=your_deepgram_api_key

2. Create Your Voice Agent

import logging

from dotenv import load_dotenv
from livekit.agents import (
    Agent,
    AgentServer,
    AgentSession,
    JobContext,
    JobProcess,
    cli,
    room_io,
)
from livekit.plugins import camb, silero

load_dotenv()

logger = logging.getLogger("voice-agent")


class MyAgent(Agent):
    def __init__(self) -> None:
        super().__init__(
            instructions=(
                "You are a helpful voice assistant. "
                "Keep your responses concise and conversational. "
                "Do not use emojis or special formatting."
            ),
        )

    async def on_enter(self):
        # Generate initial greeting
        self.session.generate_reply(allow_interruptions=False)


server = AgentServer()


def prewarm(proc: JobProcess):
    # Pre-load VAD model for faster startup
    proc.userdata["vad"] = silero.VAD.load()


server.setup_fnc = prewarm


@server.rtc_session()
async def entrypoint(ctx: JobContext):
    session = AgentSession(
        # Speech-to-text
        stt="deepgram/nova-3",
        # Language model
        llm="openai/gpt-4.1-mini",
        # Camb.ai TTS
        tts=camb.TTS(),
        # Voice activity detection
        vad=ctx.proc.userdata["vad"],
    )

    await session.start(
        agent=MyAgent(),
        room=ctx.room,
    )


if __name__ == "__main__":
    cli.run_app(server)

3. Run Your Agent

Development mode (with LiveKit Agents Playground):
python your_agent.py dev
Production mode:
python your_agent.py start

Configuration

TTS Options

The camb.TTS class accepts the following parameters:
ParameterTypeDefaultDescription
api_keystrCAMB_API_KEY env varYour Camb.ai API key
voice_idint147320Voice ID (use list_voices() to discover)
languagestr"en-us"BCP-47 language code
modelstr"mars-flash"MARS model to use (mars-flash or mars-pro)
output_formatstr"pcm_s16le"Audio format
enhance_named_entitiesboolFalseEnhanced pronunciation for names and places
sample_rateintAuto-detectedAudio sample rate (auto-detected from model if not specified)

Available Models

Voice Selection

Discover available voices using the list_voices() function:
import asyncio
from livekit.plugins import camb

async def main():
    voices = await camb.list_voices()
    for voice in voices:
        print(f"ID: {voice['id']}, Name: {voice['name']}, Gender: {voice['gender']}")

asyncio.run(main())
Then use your chosen voice:
tts=camb.TTS(voice_id=147320)

Language Support

Camb.ai supports 140+ languages. Specify the language using BCP-47 codes:
# English (US)
tts=camb.TTS(language="en-us")

# French
tts=camb.TTS(language="fr-fr")

# Spanish
tts=camb.TTS(language="es-es")

# German
tts=camb.TTS(language="de-de")

# Japanese
tts=camb.TTS(language="ja-jp")

Advanced Usage

Dynamic Option Updates

Update TTS settings during a session:
# Change voice mid-conversation
session.tts.update_options(voice_id=1234)

# Switch model
session.tts.update_options(model="mars-pro")

# Switch language
session.tts.update_options(language="es-es")

Function Tools

Add custom capabilities to your agent using the @function_tool decorator. The LLM automatically discovers these functions and calls them based on user conversation.
from livekit.agents.llm import function_tool
from livekit.agents import RunContext

class MyAgent(Agent):
    def __init__(self) -> None:
        super().__init__(
            instructions="You are a helpful assistant that can look up weather.",
        )

    @function_tool
    async def lookup_weather(
        self,
        context: RunContext,
        location: str,
        latitude: str,
        longitude: str
    ):
        """Called when the user asks for weather related information.
        Ensure the user's location (city or region) is provided.
        When given a location, please estimate the latitude and longitude of the location and
        do not ask the user for them.

        Args:
            location: The location they are asking for
            latitude: The latitude of the location, do not ask user for it
            longitude: The longitude of the location, do not ask user for it
        """
        # Your weather lookup logic here
        return "sunny with a temperature of 70 degrees."
For more details, see the LiveKit Function Tools documentation.

Custom HTTP Session

For advanced use cases, provide your own aiohttp session:
import aiohttp

async with aiohttp.ClientSession() as session:
    tts = camb.TTS(http_session=session)
    # Use TTS...

Metrics and Logging

Track usage and performance:
from livekit.agents import metrics, MetricsCollectedEvent

usage_collector = metrics.UsageCollector()

@session.on("metrics_collected")
def on_metrics(ev: MetricsCollectedEvent):
    metrics.log_metrics(ev.metrics)
    usage_collector.collect(ev.metrics)

# Get usage summary after session
summary = usage_collector.get_summary()
logger.info(f"Session usage: {summary}")

Full Voice Agent Example

Here’s a full example combining all features.

Installation

pip install livekit-plugins-camb 'livekit-agents[silero]' python-dotenv

Code

import logging

from dotenv import load_dotenv

from livekit.agents import (
    Agent,
    AgentServer,
    AgentSession,
    JobContext,
    JobProcess,
    MetricsCollectedEvent,
    RunContext,
    cli,
    metrics,
    room_io,
)
from livekit.agents.llm import function_tool
from livekit.plugins import camb, silero
from livekit.plugins.turn_detector.multilingual import MultilingualModel

logger = logging.getLogger("basic-agent")

load_dotenv()


class MyAgent(Agent):
    def __init__(self) -> None:
        super().__init__(
            instructions="Your name is Kelly. You would interact with users via voice."
            "with that in mind keep your responses concise and to the point."
            "do not use emojis, asterisks, markdown, or other special characters in your responses."
            "You are curious and friendly, and have a sense of humor."
            "you will speak english to the user",
        )

    async def on_enter(self):
        # when the agent is added to the session, it'll generate a reply
        # according to its instructions
        # Keep it uninterruptible so the client has time to calibrate AEC
        self.session.generate_reply(allow_interruptions=False)

    @function_tool
    async def lookup_weather(
        self, context: RunContext, location: str, latitude: str, longitude: str
    ):
        """Called when the user asks for weather related information.
        Ensure the user's location (city or region) is provided.
        When given a location, please estimate the latitude and longitude of the location and
        do not ask the user for them.

        Args:
            location: The location they are asking for
            latitude: The latitude of the location, do not ask user for it
            longitude: The longitude of the location, do not ask user for it
        """
        logger.info(f"Looking up weather for {location}")
        return "sunny with a temperature of 70 degrees."


server = AgentServer()


def prewarm(proc: JobProcess):
    proc.userdata["vad"] = silero.VAD.load()


server.setup_fnc = prewarm


@server.rtc_session()
async def entrypoint(ctx: JobContext):
    ctx.log_context_fields = {"room": ctx.room.name}

    session = AgentSession(
        stt="deepgram/nova-3",
        llm="openai/gpt-4.1-mini",
        tts=camb.TTS(),
        turn_detection=MultilingualModel(),
        vad=ctx.proc.userdata["vad"],
        preemptive_generation=True,
        resume_false_interruption=True,
        false_interruption_timeout=1.0,
    )

    usage_collector = metrics.UsageCollector()

    @session.on("metrics_collected")
    def _on_metrics_collected(ev: MetricsCollectedEvent):
        metrics.log_metrics(ev.metrics)
        usage_collector.collect(ev.metrics)

    async def log_usage():
        summary = usage_collector.get_summary()
        logger.info(f"Usage: {summary}")

    ctx.add_shutdown_callback(log_usage)

    await session.start(
        agent=MyAgent(),
        room=ctx.room,
        room_options=room_io.RoomOptions(
            audio_input=room_io.AudioInputOptions(),
        ),
    )


if __name__ == "__main__":
    cli.run_app(server)

Run

Development mode (opens playground in browser):
python your_agent.py dev
Production mode:
python your_agent.py start
Then connect via the LiveKit Agents Playground.

Troubleshooting

Common Issues

Ensure your CAMB_API_KEY environment variable is set correctly:
export CAMB_API_KEY=your_api_key_here
Or pass it directly:
tts=camb.TTS(api_key="your_api_key")
The voice ID must be an integer. Use list_voices() to find available voices:
voices = await camb.list_voices()
print(voices)
TTS synthesis can take time for longer texts. The plugin automatically uses a minimum 60-second timeout.For very long texts, consider breaking them into smaller chunks.
  • Use mars-pro for highest quality (48kHz) or mars-flash for best latency (22.05kHz)
  • Ensure your network connection is stable
  • Use pcm_s16le format for lowest latency
Check that you can reach the Camb.ai API:
curl -H "x-api-key: YOUR_KEY" https://client.camb.ai/apis/list-voices

Debug Logging

Enable debug logging for detailed information:
import logging

logging.basicConfig(level=logging.DEBUG)
logger = logging.getLogger("livekit.plugins.camb")
logger.setLevel(logging.DEBUG)

Resources