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.9.tar.gz (30.9 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.9-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.9-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.9-cp312-cp312-win_amd64.whl (737.1 kB view details)

Uploaded CPython 3.12Windows x86-64

pyaudiocast-0.1.9-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl (982.0 kB view details)

Uploaded CPython 3.12manylinux: glibc 2.17+ x86-64

pyaudiocast-0.1.9-cp312-cp312-macosx_11_0_arm64.whl (843.6 kB view details)

Uploaded CPython 3.12macOS 11.0+ ARM64

pyaudiocast-0.1.9-cp312-cp312-macosx_10_12_x86_64.whl (898.3 kB view details)

Uploaded CPython 3.12macOS 10.12+ x86-64

pyaudiocast-0.1.9-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl (984.7 kB view details)

Uploaded CPython 3.11manylinux: glibc 2.17+ x86-64

pyaudiocast-0.1.9-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl (985.1 kB view details)

Uploaded CPython 3.10manylinux: glibc 2.17+ x86-64

pyaudiocast-0.1.9-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.9.tar.gz.

File metadata

  • Download URL: pyaudiocast-0.1.9.tar.gz
  • Upload date:
  • Size: 30.9 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.9.tar.gz
Algorithm Hash digest
SHA256 c8b68f7d9fd5dbde00bca8ca0fac525a10241317ef1b50664a20fbc8ecaa2bba
MD5 cedae1262f3cd2eca36ffeabeb4a9e33
BLAKE2b-256 ee94a42fd8a052205988a92ea8e3e49be2b7632149b050701a80879196afd427

See more details on using hashes here.

Provenance

The following attestation bundles were made for pyaudiocast-0.1.9.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.9-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl.

File metadata

File hashes

Hashes for pyaudiocast-0.1.9-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl
Algorithm Hash digest
SHA256 b116249b81bc66e0f5eab586eab9ebfb55749bc64c1a05bf276c8aa46d5e375b
MD5 b8bca23c6a2826eddc7c2a65f2055479
BLAKE2b-256 c584aebb144909817543c7b134a95a1d655edfd335e5f537e1c361fa05d313c2

See more details on using hashes here.

Provenance

The following attestation bundles were made for pyaudiocast-0.1.9-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.9-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl.

File metadata

File hashes

Hashes for pyaudiocast-0.1.9-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl
Algorithm Hash digest
SHA256 d9540d32762a1a929a47eceb50031fb8b45c3268b98436b39a98a005fc76467c
MD5 583643b2bd81a8cbdd3bf58a342e7700
BLAKE2b-256 7089843f5a2366659ac9e81f8617e327b1afc961a58b3784764d658a78686bf6

See more details on using hashes here.

Provenance

The following attestation bundles were made for pyaudiocast-0.1.9-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.9-cp312-cp312-win_amd64.whl.

File metadata

  • Download URL: pyaudiocast-0.1.9-cp312-cp312-win_amd64.whl
  • Upload date:
  • Size: 737.1 kB
  • Tags: CPython 3.12, Windows x86-64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for pyaudiocast-0.1.9-cp312-cp312-win_amd64.whl
Algorithm Hash digest
SHA256 d0ebe071c1a59ee64c2d4a78063b040957ab03e0adfefff41f89a9664311d1ff
MD5 b1ad0208148aa298ae1d51f13c082afe
BLAKE2b-256 dd152ab5c5dce6d85255ab1967e5c37bfbd8ed5de977fcc199eeda860cecb564

See more details on using hashes here.

Provenance

The following attestation bundles were made for pyaudiocast-0.1.9-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.9-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl.

File metadata

File hashes

Hashes for pyaudiocast-0.1.9-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl
Algorithm Hash digest
SHA256 7c69e7c95b74b50858094c87c18d65f2eb7bf2e24a31d5d4da0c1a8a7b4ee88e
MD5 842bf1916f133a6542a8228a49470415
BLAKE2b-256 ab1f49ea3d329e470947eb5f1fe2f8bf3d2983a758d834bf1d1b2409fe601db1

See more details on using hashes here.

Provenance

The following attestation bundles were made for pyaudiocast-0.1.9-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.9-cp312-cp312-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for pyaudiocast-0.1.9-cp312-cp312-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 ed43ac7919fcc3eef8d9501d31b1906352e4040ffb0b6058874530f6235c525e
MD5 2e8cefb103af87ef45572fc7c315be8f
BLAKE2b-256 45e1b16a7083610474e688f36ad0bafde060477d1d1caeb3b10125458dadf172

See more details on using hashes here.

Provenance

The following attestation bundles were made for pyaudiocast-0.1.9-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.9-cp312-cp312-macosx_10_12_x86_64.whl.

File metadata

File hashes

Hashes for pyaudiocast-0.1.9-cp312-cp312-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 8e638c645a14d70d6153c5838adca8550837f69f7ae080dfbbd63ecbe393483b
MD5 aea334e0b1eb35be1cf0617e5a7fc7a6
BLAKE2b-256 c82c0bfbb2c0d0943d78f522390bc05f1b80d2cb0e6d0d4a0d6046e1ffcb52e3

See more details on using hashes here.

Provenance

The following attestation bundles were made for pyaudiocast-0.1.9-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.9-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl.

File metadata

File hashes

Hashes for pyaudiocast-0.1.9-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl
Algorithm Hash digest
SHA256 953009ad7dde4c2b3f5907be74316bf71fe2eef2b5fe088bf54e1f72acafdef9
MD5 b19a22a8c251225666b8d26061975ecc
BLAKE2b-256 b31a45525410fa5a034e45200f169b408ae52194a789f95f8f1ee404d94add26

See more details on using hashes here.

Provenance

The following attestation bundles were made for pyaudiocast-0.1.9-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.9-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl.

File metadata

File hashes

Hashes for pyaudiocast-0.1.9-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl
Algorithm Hash digest
SHA256 62df9ac92b44b4eb348bf169e71af0133e24fe31666300ab91a0775cb944e594
MD5 4e9d4f280cc8f62b7478675de51c657f
BLAKE2b-256 eae9d63a4ffae5b08225cf48c9eb6262a30ea435b72dd6a5bc87ace43b714bd3

See more details on using hashes here.

Provenance

The following attestation bundles were made for pyaudiocast-0.1.9-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.9-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.whl.

File metadata

File hashes

Hashes for pyaudiocast-0.1.9-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.whl
Algorithm Hash digest
SHA256 e7fa7b34bd930981d9abf2d1c8af2fb9a73e14ab241388e54b84f3943d42c64d
MD5 d3493eefb2e783650777392c16e24732
BLAKE2b-256 80c3130a5c68e33127aeafeb4c0a93ebe2118c22c654a53f26c4dca9dce88ee1

See more details on using hashes here.

Provenance

The following attestation bundles were made for pyaudiocast-0.1.9-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