Audio (Python)
Session audio I/O — mic capture, speaker playback, agent-audio frames, level metering, and the mute gate.
Audio lives on RealtimeSession. The media transport and OS-device capture/playback both ship with the base install:
pip install cosmo-ai-sdkOn Linux, OS mic/speaker use needs the system PortAudio library (apt install libportaudio2); sessions that never touch OS audio don't load it.
async with agent.start() as session:
await session.set_microphone_enabled(True)
await session.set_speaker_enabled(True)
async for event in session:
...Microphone
await session.set_microphone_enabled(enabled: bool)True captures and publishes the default OS microphone; False stops and unpublishes it, then gates the server side with set_muted(True). For non-mic audio input (synthetic generator, WAV replay) use publish_audio_source instead.
await session.set_muted(muted: bool)Toggle the server-side mic gate only — no track is published or unpublished, so it is the right primitive for push-to-talk. The SDK re-asserts the last mute state automatically after a reconnect.
await session.publish_audio_source(source, *, track_name: str = "mic")Publish a caller-supplied rtc.AudioSource as the mic track (requires the livekit extra). You own the source and keep it fed via source.capture_frame(...) — livekit-rtc for Python has no OS-mic capture of its own, so any audio input is captured caller-side and pushed in. Returns the transport's track publication handle. Publishing audio binds the agent's input to this client and unmutes it.
Speaker
await session.set_speaker_enabled(enabled: bool)Play the agent's voice on the default OS output device, or stop. Idempotent. For custom playback consume agent_audio() directly.
session.set_agent_playback_volume(volume: float)Software gain for OS playback: 0 mutes, 1 is unity; values outside 0…1 are clamped, NaN raises ValueError. Affects only set_speaker_enabled output, never agent_audio() frames. May be called before the speaker is enabled; the value persists.
Agent audio frames
async for frame in session.agent_audio(): # AgentAudioFrame
...The agent's decoded voice — record it, pipe it elsewhere, or feed a custom player (requires the livekit extra). Frames flow once the agent publishes audio; the iterator finishes when the session ends. Multiple concurrent iterators each receive every frame; a stalled consumer drops its oldest frames.
Agent audio is decoded at a fixed geometry — 48 kHz, mono, 16-bit (cosmo_ai.audio.AGENT_AUDIO_SAMPLE_RATE == 48000):
from cosmo_ai.audio import AgentAudioFrame
@dataclass(frozen=True)
class AgentAudioFrame:
data: bytes # 16-bit little-endian PCM, channels interleaved
sample_rate: int
num_channels: int
samples_per_channel: intLevel metering
async for levels in session.audio_levels(): # AudioLevels
...Mic and agent RMS levels sampled at a fixed ~20 Hz cadence, latest-value — a slow consumer skips samples, it never lags (requires the livekit extra). mic is live while the microphone is publishing; agent is live once the agent's track exists and decays to 0.0 between utterances. Finishes when the session ends.
from cosmo_ai.audio import AudioLevels
@dataclass(frozen=True)
class AudioLevels:
mic: float # RMS 0…1, 0.0 while inactive
agent: float # RMS 0…1, 0.0 while inactiveAgentAudioFrame and AudioLevels are the only types you import from cosmo_ai.audio, and only when you take audio somewhere yourself. A small voice app never imports them: set_speaker_enabled(True) plays the agent out loud and audio_levels() yields ready-made samples.
See Audio for the conceptual model and gating directives.