Skip to content

strands.experimental.bidi.io.audio

Send and receive audio data from devices.

Reads user audio from input device and sends agent audio to output device using PyAudio. If a user interrupts the agent, the output buffer is cleared to stop playback.

Audio configuration is provided by the model via agent.model.config[“audio”].

Optional microphone audio processing (acoustic echo cancellation, noise suppression, and automatic gain control) is enabled by passing an AudioProcessorConfig (from strands.experimental.bidi.audio) to BidiAudioIO. It requires pywebrtc-audio (pip install strands-agents[bidi-aec]); see that module for the processing implementation.

class _BidiAudioBuffer()

Defined in: src/strands/experimental/bidi/io/audio.py:51

Buffer chunks of audio data between agent and PyAudio.

def __init__(size: int | None = None)

Defined in: src/strands/experimental/bidi/io/audio.py:57

Initialize buffer settings.

Arguments:

  • size - Size of the buffer (default: unbounded).
def start() -> None

Defined in: src/strands/experimental/bidi/io/audio.py:65

Setup buffer.

def stop() -> None

Defined in: src/strands/experimental/bidi/io/audio.py:70

Tear down buffer.

def put(chunk: bytes) -> None

Defined in: src/strands/experimental/bidi/io/audio.py:88

Put data chunk into buffer.

If full, removes the oldest chunk.

def get(byte_count: int | None = None) -> bytes

Defined in: src/strands/experimental/bidi/io/audio.py:103

Get the number of bytes specified from the buffer.

Arguments:

  • byte_count - Number of bytes to get from buffer.

    • If the number of bytes specified is not available, the return is padded with silence.
    • If the number of bytes is not specified, get the first chunk put in the buffer.

Returns:

Specified number of bytes.

def clear() -> None

Defined in: src/strands/experimental/bidi/io/audio.py:133

Clear the buffer.

class _BidiAudioInput(BidiInput)

Defined in: src/strands/experimental/bidi/io/audio.py:142

Handle audio input from user.

Attributes:

  • _audio - PyAudio instance for audio system access.
  • _stream - Audio input stream.
  • _buffer - Buffer for sharing audio data between agent and PyAudio.
def __init__(config: dict[str, Any],
processor: "_AudioProcessor | None" = None) -> None

Defined in: src/strands/experimental/bidi/io/audio.py:158

Extract configs.

Arguments:

  • config - Audio device configuration.
  • processor - Shared audio processor for echo cancellation, or None to disable processing.
async def start(agent: "BidiAgent") -> None

Defined in: src/strands/experimental/bidi/io/audio.py:187

Start input stream.

Arguments:

  • agent - The BidiAgent instance, providing access to model configuration.

Raises:

  • ValueError - If audio processing is enabled but the input rate is unsupported.
async def stop() -> None

Defined in: src/strands/experimental/bidi/io/audio.py:232

Stop input stream.

async def __call__() -> BidiAudioInputEvent

Defined in: src/strands/experimental/bidi/io/audio.py:245

Read audio from input stream, applying echo cancellation if enabled.

class _BidiAudioOutput(BidiOutput)

Defined in: src/strands/experimental/bidi/io/audio.py:269

Handle audio output from bidi agent.

Attributes:

  • _audio - PyAudio instance for audio system access.
  • _stream - Audio output stream.
  • _buffer - Buffer for sharing audio data between agent and PyAudio.
def __init__(config: dict[str, Any],
processor: "_AudioProcessor | None" = None) -> None

Defined in: src/strands/experimental/bidi/io/audio.py:285

Extract configs.

Arguments:

  • config - Audio device configuration.
  • processor - Shared audio processor — output records played frames as the AEC reference.
async def start(agent: "BidiAgent") -> None

Defined in: src/strands/experimental/bidi/io/audio.py:303

Start output stream.

Arguments:

  • agent - The BidiAgent instance, providing access to model configuration.
async def stop() -> None

Defined in: src/strands/experimental/bidi/io/audio.py:337

Stop output stream.

async def __call__(event: BidiOutputEvent) -> None

Defined in: src/strands/experimental/bidi/io/audio.py:350

Send audio to output stream.

class BidiAudioIO()

Defined in: src/strands/experimental/bidi/io/audio.py:383

Send and receive audio data from devices using PyAudio.

Reads microphone audio via input() and plays agent audio via output(). On interruption, the playback buffer is cleared to stop the agent mid-response.

When an AudioProcessorConfig is passed as processor, the microphone signal gets noise suppression and automatic gain control, and (when echo cancellation is enabled) the agent’s speaker output is used as a reference to cancel echo from the mic input, preventing the model from hearing its own voice. The same processor instance is shared between the input and output channels this factory produces, so echo cancellation only works when both input() and output() come from the same BidiAudioIO instance.

Audio processing requires pywebrtc-audio (pip install strands-agents[bidi-aec]) and a microphone sample rate of 16000, 32000, or 48000 Hz (set via the model’s audio config).

Device audio requires PyAudio. Install the PortAudio system library, then install strands-agents[bidi-pyaudio].

Example:

from strands.experimental.bidi.audio import AudioProcessorConfig
from strands.experimental.bidi.io import BidiAudioIO
# Plain mic/speaker, no processing (a headset is recommended to avoid echo):
audio_io = BidiAudioIO()
await agent.run(inputs=[audio_io.input()], outputs=[audio_io.output()])
# Full processing: echo cancellation, noise suppression, and auto gain control:
audio_io = BidiAudioIO(processor=AudioProcessorConfig())
await agent.run(inputs=[audio_io.input()], outputs=[audio_io.output()])
# Noise suppression and auto gain control without echo cancellation (e.g. headset users):
audio_io = BidiAudioIO(processor=AudioProcessorConfig(echo_cancellation=False))
await agent.run(inputs=[audio_io.input()], outputs=[audio_io.output()])
# Processing on a specific input device:
audio_io = BidiAudioIO(processor=AudioProcessorConfig(), input_device_index=1)
await agent.run(inputs=[audio_io.input()], outputs=[audio_io.output()])
def __init__(**config: Any) -> None

Defined in: src/strands/experimental/bidi/io/audio.py:425

Initialize audio devices.

Arguments:

  • **config - Optional configuration:

    • processor (AudioProcessorConfig): Enable microphone audio processing (noise suppression, automatic gain control, and optionally echo cancellation) by passing an AudioProcessorConfig (from strands.experimental.bidi.audio). Requires pywebrtc-audio (pip install strands-agents[bidi-aec]). Defaults to None (processing disabled).
    • input_buffer_size (int): Maximum input buffer size (default: None). Ignored when echo cancellation is on — the mic buffer is bound to the reference horizon so the two stay aligned.
    • input_device_index (int): Specific input device (default: None = system default)
    • input_frames_per_buffer (int): Input buffer size (default: 512, ignored when processing is on)
    • output_buffer_size (int): Maximum output buffer size (default: None)
    • output_device_index (int): Specific output device (default: None = system default)
    • output_frames_per_buffer (int): Output buffer size (default: 512, ignored when processing is on)

Raises:

  • ImportError - If a processor config is set but pywebrtc-audio is not installed.
def input() -> _BidiAudioInput

Defined in: src/strands/experimental/bidi/io/audio.py:457

Return audio processing BidiInput.

def output() -> _BidiAudioOutput

Defined in: src/strands/experimental/bidi/io/audio.py:461

Return audio processing BidiOutput.