Audio interface
The audio interface connects a session to the sound on your side. It captures the user's audio and hands it to the SDK, and it plays the audio the agent sends back. The SDK only moves audio between your interface and Mistral: transcription, the model, and speech all run at Mistral.
This page applies to Python and Node.js. In the browser, the SDK captures and plays audio for you, see Browser.
How audio flows
You pass an interface with audio_interface (audioInterface in TypeScript) when you create the session. From then on, the SDK drives it:
- Before the session is created, the SDK runs the interface's preflight check, so a missing device or audio library fails before Mistral allocates a session.
- When the session connects, the SDK calls
start()to open your devices or streams. - Once the agent joins, the SDK reads the user's audio from
input_audio()and sends each chunk to Mistral. While the microphone is muted withset_input_enabled(False), the SDK keeps reading but drops the chunks. - Each time the agent speaks, the SDK passes its audio to
output_audio(), chunk by chunk. - When the session closes, the SDK calls
stop()so you can release your resources.
Audio uses the same format in both directions:
| Property | Value |
|---|---|
| Encoding | 16-bit signed PCM, little-endian |
| Channels | Mono |
| Sample rate | 48 kHz |
| Frame size | The default interface captures 20 ms frames: 960 samples, or 1,920 bytes |
The SDK doesn't resample or convert audio. If your source uses another format, such as 8 kHz telephony audio or stereo, convert it to 48 kHz mono PCM before you yield it.
Choose an integration
| You want | Use |
|---|---|
| The computer's microphone and speakers | The default interface. |
| Audio from another source, such as a WebSocket, a phone bridge, or a file, with the SDK still running the exchange | A custom interface. |
| To push audio and receive the agent's audio yourself, for example in a test harness | Manual audio, with no interface. |
The default interface
DefaultAudioInterface records from the system's default microphone and plays to the default speakers. In Python, it uses PyAudio, which needs PortAudio. In Node.js, it uses SoX. See Install the SDK.
Before sending the microphone audio, it cleans it up: it removes the agent's own voice picked up by the microphone (echo cancellation), reduces background noise, and evens out the volume. On the way out, it buffers the agent's audio and plays it at a steady pace. If the agent's audio arrives faster than it plays and the buffer fills up, the oldest audio is dropped.
In Python, these options tune it:
| Parameter | Default | Description |
|---|---|---|
echo_cancellation | True | Remove the agent's voice from the microphone input. |
noise_suppression | True | Reduce background noise. |
high_pass_filter | True | Remove low-frequency noise, such as hum. |
auto_gain_control | True | Normalize the microphone volume. |
output_buffer_size_ms | 300 | Maximum audio waiting to be played, in milliseconds. |
frames_per_buffer | 960 (20 ms) | Samples read from the microphone at a time. |
echo_cancellation_delay_ms | Measured | Fixed delay between playback and capture for echo cancellation. Set it only if the measured delay is wrong on your hardware. |
Keep echo cancellation on when you use speakers instead of headphones. Otherwise, the agent can hear and answer itself.
from mistralai.extra.voice_agents import DefaultAudioInterface
audio_interface = DefaultAudioInterface(
noise_suppression=False, # The input is already clean
output_buffer_size_ms=500,
)Implement a custom interface
To use another audio source or destination, subclass AudioInterface (implement it in TypeScript) and pass an instance with audio_interface. It has four methods:
| Method | Called | What to do |
|---|---|---|
start() | When the session connects | Open your devices, sockets, or files. |
input_audio() | Once the agent joins, for the whole session | Yield the user's audio as PCM chunks, as they become available. The session streams each chunk to the agent as live audio. |
output_audio(audio) | For each chunk of the agent's audio | Play or forward the chunk. Return quickly: the session waits for it before it handles the next event. |
stop() | When the session closes | Release your resources. |
from collections.abc import AsyncIterator
from mistralai.extra.voice_agents import AudioInterface
class MyAudioInterface(AudioInterface):
async def start(self) -> None:
"""Open devices, sockets, or other audio resources."""
...
async def input_audio(self) -> AsyncIterator[bytes]:
"""Yield user audio chunks to send to the agent."""
...
async def output_audio(self, audio: bytes) -> None:
"""Play or forward agent audio."""
...
async def stop(self) -> None:
"""Release resources."""
...
session = await client.audio.sessions.init(
instructions="You are a helpful voice assistant.",
audio_interface=MyAudioInterface(),
)In Python, you can also override preflight(). The SDK calls it before creating the session, so a missing device fails early instead of after the session is allocated. To change only part of the default behavior, subclass the default interface instead of starting from scratch.
If start(), input_audio(), or output_audio() raises an error, the session closes with the start_failed, audio_input_error, or audio_output_error disconnect reason. If stop() fails, the session emits a non-fatal error event and still closes.
Handle audio manually
If you don't pass an audio interface, the session neither records nor plays anything. Send audio to the agent with send_audio() (sendAudio() in TypeScript), in the same format, once the session is connected. Receive the agent's audio from the audio event.
session = await client.audio.sessions.init(
instructions="You are a helpful voice assistant.",
)
async def handle_audio(audio: bytes) -> None:
... # Play or forward agent audio
session.on("audio", handle_audio)
async with session:
await session.send_audio(audio_bytes) # 16-bit PCM, mono, 48 kHz
await session.wait()