Skip to main content

Cross-platform audio output for Python, powered by Rust and CPAL

Project description

PyAudioCast

CI PyPI codecov License: MIT

Cross-platform audio output library for Python, powered by Rust and CPAL.

Stream audio to any output device — including PipeWire/PulseAudio virtual sinks on Linux — with a simple Python API backed by a high-performance Rust core.

Features

  • Cross-platform: Linux (ALSA/PipeWire/PulseAudio), Windows (WASAPI), macOS (CoreAudio)
  • Auto-detect: Sample rate and channels are detected from the device — zero config needed
  • Auto-negotiate: If the device doesn't support your sample rate, it automatically resamples and upmixes (e.g. 22050Hz mono TTS → 48000Hz stereo device)
  • Device selection: List and select output devices by name, including PipeWire virtual sinks
  • Streaming audio: Write audio data in chunks via a lock-free ring buffer — ideal for real-time TTS, generative audio, live effects, etc.
  • Unified write(): Accepts bytes, numpy arrays (int16/int32/float32/float64), or list[float] — format is detected automatically
  • Interruption: clear() instantly discards buffered audio and unblocks drain() — perfect for voice assistant barge-in
  • Context manager: Clean resource management with with statement
  • GIL-friendly: Releases the Python GIL during audio writes and drain, so other threads run freely
  • Clean output: ALSA/JACK backend probe noise is automatically suppressed
  • Debug logging: Enable detailed logs with PYAUDIOCAST_LOG=debug

Installation

From PyPI

pip install pyaudiocast

Note (Linux): Pre-built wheels require ALSA. Install libasound2 if not already present:

sudo apt install libasound2  # Debian/Ubuntu
sudo dnf install alsa-lib    # Fedora

From source (requires Rust toolchain)

# Install Rust if needed
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

# Linux: install ALSA development headers
sudo apt install libasound2-dev  # Debian/Ubuntu
sudo dnf install alsa-lib-devel  # Fedora

# Clone and install
git clone https://github.com/nicokim/PyAudioCast.git
cd PyAudioCast
pip install maturin
maturin develop

Development setup (with uv)

uv venv && source .venv/bin/activate
uv pip install maturin numpy pytest
maturin develop

Quick Start

import pyaudiocast

# List all output devices
for dev in pyaudiocast.list_output_devices():
    print(f"[{dev['index']}] {dev['name']} ({dev['type']})")

# Stream audio — sample rate and channels auto-detected from device
with pyaudiocast.AudioPlayer() as player:
    print(f"Using: {player.sample_rate}Hz, {player.channels}ch")
    player.write(audio_bytes)   # bytes, numpy array, or list[float]
    player.drain()              # wait for playback to finish

# Override sample rate if your source requires it (auto-resampled to device)
with pyaudiocast.AudioPlayer(sample_rate=22050) as player:
    player.write(tts_audio)
    player.drain()

# Stream to a specific device
with pyaudiocast.AudioPlayer(device="Virtual-Mic") as player:
    player.write(samples)
    player.drain()

# One-shot WAV playback
pyaudiocast.play_file("audio.wav", device="pulse")

Streaming with Interruption

For real-time applications like voice assistants, you can interrupt playback instantly:

import pyaudiocast
import threading

with pyaudiocast.AudioPlayer(sample_rate=22050) as player:
    # Stream TTS chunks as they arrive
    for chunk in tts_stream:
        player.write(chunk)
    player.drain()  # wait for playback to finish
# Interrupt from another thread (e.g., when user starts speaking)
def on_user_speech_detected(player):
    player.clear()  # instantly stops audio, unblocks drain()

clear() discards all buffered audio immediately. Any blocked drain() returns right away. Calling write() again resumes normal playback.

Supported Audio Formats

write() auto-detects the input format:

Input type Format Conversion
bytes int16 little-endian PCM Converted to float32
numpy.ndarray (int16) int16 samples Converted to float32
numpy.ndarray (int32) int32 samples Converted to float32
numpy.ndarray (float32) float32 samples Direct (no conversion)
numpy.ndarray (float64) float64 samples Converted to float32
list[float] float32 samples (-1.0 to 1.0) Direct
import numpy as np

with pyaudiocast.AudioPlayer() as player:
    # All of these work with the same write() method
    player.write(b"\x00\x00" * 100)                    # bytes (int16 LE)
    player.write(np.zeros(100, dtype=np.int16))         # numpy int16
    player.write(np.zeros(100, dtype=np.float32))       # numpy float32 (fastest)
    player.write(np.zeros(100, dtype=np.float64))       # numpy float64
    player.write(np.zeros(100, dtype=np.int32))         # numpy int32
    player.write([0.0] * 100)                           # list[float]

API Reference

pyaudiocast.list_output_devices() -> list[dict]

Returns a list of available output devices. Each dict contains:

  • name (str): Device name
  • index (int): Device index
  • type (str): "alsa" for ALSA/cpal devices, "pipewire" for PipeWire/PulseAudio sinks

pyaudiocast.AudioPlayer(device=None, sample_rate=None, channels=None)

Streaming audio player with ring buffer.

Parameter Type Default Description
device str | None None Device name (substring match) or None for default
sample_rate int | None None Sample rate in Hz, or None to auto-detect
channels int | None None Number of audio channels, or None to auto-detect

If sample_rate or channels don't match the device natively, pyaudiocast automatically resamples and/or upmixes to the device's supported configuration.

Methods:

Method Description
write(data) Write audio data (bytes, numpy array, or list[float])
drain() Block until all buffered audio is played
clear() Discard buffer and unblock drain() immediately
stop() Stop playback and release resources

Properties:

Property Type Description
sample_rate int Requested sample rate (what you send)
channels int Requested channel count (what you send)
device_sample_rate int Actual device sample rate (what plays)
device_channels int Actual device channel count (what plays)
is_active bool Whether the player is active

Context manager: Supports with statement (calls stop() on exit).

pyaudiocast.play_file(path, device=None)

Play a WAV file to completion. Blocks until playback is done.

Device Selection

Default device

player = pyaudiocast.AudioPlayer()  # uses system default

ALSA device (by name substring)

player = pyaudiocast.AudioPlayer(device="pulse")
player = pyaudiocast.AudioPlayer(device="hw:CARD=Audio")

PipeWire/PulseAudio virtual sinks (Linux)

# Virtual sinks are auto-detected via pactl
player = pyaudiocast.AudioPlayer(device="Virtual-Mic")

PipeWire sinks are routed transparently through PULSE_SINK + the pulse ALSA device.

Environment Variables

Variable Description Example
PYAUDIOCAST_LOG Enable debug logging. Uses env_logger filter syntax. PYAUDIOCAST_LOG=debug

Logging

# Show everything (including ALSA/JACK backend messages)
PYAUDIOCAST_LOG=debug python my_script.py

# Show info and above
PYAUDIOCAST_LOG=info python my_script.py

# Default (no env var): warnings only, ALSA/JACK noise suppressed
python my_script.py

Cross-Platform Support

Platform Backend Device listing Virtual sinks
Linux ALSA + PipeWire/Pulse Full Yes (via pactl)
Windows WASAPI cpal devices N/A
macOS CoreAudio cpal devices N/A

The audio engine (cpal) is fully cross-platform. PipeWire/PulseAudio virtual sink detection uses pactl and is automatically compiled out on non-Linux systems via #[cfg(target_os = "linux")].

Architecture

Python (pyaudiocast)
  |
  +- write(data)  ->  auto-detect format  ->  convert to f32
  |     |
  |     v
  |  [resample + upmix if needed]
  |     |
  |     v
  |  Lock-free Ring Buffer (ringbuf crate)
  |     |
  |     v
  |  cpal audio callback (OS audio thread)
  |     |                          ^
  |     v                          |
  +- Speaker / Virtual Sink    clear() -> discard + silence
  • Ring buffer: Lock-free producer/consumer. Python pushes samples, the OS audio callback pulls them — no locks in the audio path.
  • GIL release: write() and drain() release the Python GIL during blocking operations.
  • Sample conversion: All input formats are converted to float32 in Rust before entering the ring buffer.
  • Auto-resample: If the device doesn't natively support the requested sample rate, linear interpolation resampling is applied transparently.
  • Auto-upmix: Mono audio is automatically duplicated to stereo (or more channels) to match the device.
  • Interruption: clear() sets an atomic flag checked by the audio callback, which discards remaining samples and outputs silence.

Running Tests

# Python tests
pytest tests/ -v

# Rust tests
cargo test

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pyaudiocast-0.1.10.tar.gz (30.7 kB view details)

Uploaded Source

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

pyaudiocast-0.1.10-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl (981.7 kB view details)

Uploaded CPython 3.14manylinux: glibc 2.17+ x86-64

pyaudiocast-0.1.10-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl (982.0 kB view details)

Uploaded CPython 3.13manylinux: glibc 2.17+ x86-64

pyaudiocast-0.1.10-cp312-cp312-win_amd64.whl (737.1 kB view details)

Uploaded CPython 3.12Windows x86-64

pyaudiocast-0.1.10-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl (982.1 kB view details)

Uploaded CPython 3.12manylinux: glibc 2.17+ x86-64

pyaudiocast-0.1.10-cp312-cp312-macosx_11_0_arm64.whl (843.8 kB view details)

Uploaded CPython 3.12macOS 11.0+ ARM64

pyaudiocast-0.1.10-cp312-cp312-macosx_10_12_x86_64.whl (898.2 kB view details)

Uploaded CPython 3.12macOS 10.12+ x86-64

pyaudiocast-0.1.10-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl (984.6 kB view details)

Uploaded CPython 3.11manylinux: glibc 2.17+ x86-64

pyaudiocast-0.1.10-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl (985.0 kB view details)

Uploaded CPython 3.10manylinux: glibc 2.17+ x86-64

pyaudiocast-0.1.10-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.whl (987.6 kB view details)

Uploaded CPython 3.9manylinux: glibc 2.17+ x86-64

File details

Details for the file pyaudiocast-0.1.10.tar.gz.

File metadata

  • Download URL: pyaudiocast-0.1.10.tar.gz
  • Upload date:
  • Size: 30.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for pyaudiocast-0.1.10.tar.gz
Algorithm Hash digest
SHA256 299240d6cf31c5a19b64ee388346ae1daf29cbb931b32aee52fa3ba3faf0c1f8
MD5 49e2132e70b8b58fe7ae6a11838c9db6
BLAKE2b-256 4a980fa15a712bd592a93c4002ff1aef1a8bf07049d8601ca66ff835ca9c11f9

See more details on using hashes here.

Provenance

The following attestation bundles were made for pyaudiocast-0.1.10.tar.gz:

Publisher: release.yml on nicokim/PyAudioCast

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file pyaudiocast-0.1.10-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl.

File metadata

File hashes

Hashes for pyaudiocast-0.1.10-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl
Algorithm Hash digest
SHA256 3189deac49fdf72362749d9716e29e811e38b737bbcb47c6436b23cda2180a79
MD5 5daaadab84a73ffd5f93875ab9359d61
BLAKE2b-256 e7d3813600b1eb7e7b58a3e3320c260cb63696489b8522e7e5678264898db166

See more details on using hashes here.

Provenance

The following attestation bundles were made for pyaudiocast-0.1.10-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl:

Publisher: release.yml on nicokim/PyAudioCast

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file pyaudiocast-0.1.10-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl.

File metadata

File hashes

Hashes for pyaudiocast-0.1.10-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl
Algorithm Hash digest
SHA256 a73dfc9fe8899a13da79b1f44cd3290598418270954601c30b37e349e5edbffe
MD5 a5ca8fec1dcd3d9fa168f4e9ae8e4f88
BLAKE2b-256 f5e94001023d2f76b8b992571edf40d73208dcbefc0052650dcf1a4a943fde50

See more details on using hashes here.

Provenance

The following attestation bundles were made for pyaudiocast-0.1.10-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl:

Publisher: release.yml on nicokim/PyAudioCast

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file pyaudiocast-0.1.10-cp312-cp312-win_amd64.whl.

File metadata

File hashes

Hashes for pyaudiocast-0.1.10-cp312-cp312-win_amd64.whl
Algorithm Hash digest
SHA256 18c69f29c471e9fe0150f6be5d67390477c0c82696c3794b8ba756fda3d93702
MD5 05d26b7663581cb1fa2744d8b893af1d
BLAKE2b-256 f17dec8cc83965e812a76099dd782e410ac69bb952dea000750968b5fc536091

See more details on using hashes here.

Provenance

The following attestation bundles were made for pyaudiocast-0.1.10-cp312-cp312-win_amd64.whl:

Publisher: release.yml on nicokim/PyAudioCast

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file pyaudiocast-0.1.10-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl.

File metadata

File hashes

Hashes for pyaudiocast-0.1.10-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl
Algorithm Hash digest
SHA256 3fb5b4eba9208756cc28a8691e2765574339f260de9c803f5cca47a1d0e33058
MD5 5da0271a44a2bc78ffd75eb63e010d6b
BLAKE2b-256 90753c666574b538c9c870f037dfa676f7332940342d6294a1bd0dfc8086cf1e

See more details on using hashes here.

Provenance

The following attestation bundles were made for pyaudiocast-0.1.10-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl:

Publisher: release.yml on nicokim/PyAudioCast

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file pyaudiocast-0.1.10-cp312-cp312-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for pyaudiocast-0.1.10-cp312-cp312-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 021cc853c2984b7aa589508a3af1876cea7ec0e104d411e7e26810421daced34
MD5 25368c4b76d8a7eb6a0776c698f7588e
BLAKE2b-256 548a04d49c401ea8170ea0f7560b0549a75e562451bd2cd3d226e48d2cf0bb30

See more details on using hashes here.

Provenance

The following attestation bundles were made for pyaudiocast-0.1.10-cp312-cp312-macosx_11_0_arm64.whl:

Publisher: release.yml on nicokim/PyAudioCast

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file pyaudiocast-0.1.10-cp312-cp312-macosx_10_12_x86_64.whl.

File metadata

File hashes

Hashes for pyaudiocast-0.1.10-cp312-cp312-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 cabf85eada900f5c4b2c80ec4fc97f276d7b30be3ab98f9ed81dfc8082c59ae9
MD5 b6094f189b813238111ae03b88693e43
BLAKE2b-256 4626d74824a00b959ddf87a346a7d4a64b6761e84132b5e0c2107320a62ab834

See more details on using hashes here.

Provenance

The following attestation bundles were made for pyaudiocast-0.1.10-cp312-cp312-macosx_10_12_x86_64.whl:

Publisher: release.yml on nicokim/PyAudioCast

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file pyaudiocast-0.1.10-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl.

File metadata

File hashes

Hashes for pyaudiocast-0.1.10-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl
Algorithm Hash digest
SHA256 676c747fb1c0d8146792ac44f57522751259cf50c7755ba856041bd2f8db9b40
MD5 1bf28cd7c84d49647087e8e32d4824e6
BLAKE2b-256 85b898b5a2c4876ce7f21be0343b88b67cd49a69732dc585d5775ef8d07c7ac0

See more details on using hashes here.

Provenance

The following attestation bundles were made for pyaudiocast-0.1.10-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl:

Publisher: release.yml on nicokim/PyAudioCast

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file pyaudiocast-0.1.10-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl.

File metadata

File hashes

Hashes for pyaudiocast-0.1.10-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl
Algorithm Hash digest
SHA256 af06e9490ee81ac1dd10aad4c31e528b667c774997bbd08fd356f15b32651c25
MD5 95800b610043f6d57e461e90fbd0caf2
BLAKE2b-256 85241864aabdfda062d551e76a92f1d9940b1fabd04e1d93da2ea46bd0b817c4

See more details on using hashes here.

Provenance

The following attestation bundles were made for pyaudiocast-0.1.10-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl:

Publisher: release.yml on nicokim/PyAudioCast

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file pyaudiocast-0.1.10-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.whl.

File metadata

File hashes

Hashes for pyaudiocast-0.1.10-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.whl
Algorithm Hash digest
SHA256 4ef2dee333800ea54223445c4d4c7c71e85537228cd285cb983a7453a5f6534e
MD5 5a4d4916740a8ac40a8e0a34b8c71849
BLAKE2b-256 dd477abd10e51f8dbb39ddb2b0147b520f0bd7f47dcde71909b8009a7d55969e

See more details on using hashes here.

Provenance

The following attestation bundles were made for pyaudiocast-0.1.10-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.whl:

Publisher: release.yml on nicokim/PyAudioCast

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page