Skip to main content

easyaudiostream

Simple playback for intermittent audio byte streams in Python.

I built this library because I was tired of existing audio playback solutions in Python not supporting audio streams particularly well (compared to audio files). easyaudiostream is intended for simple, high-enough-fidelity playback of audio byte streams:

  • No choppiness between bytestream segments
  • Handles non-real-time streams -- faster and slower than real-time
  • Handles intermittent streams (i.e., streams that may not yield bytes for a while)
  • asyncio-safe -- no blocking computation on main thread

easyaudiostream also includes basic utilities for recording audio from a microphone.

Installation

Requires Python 3.8 or higher.

By default, easyaudiostream will use the ffmpeg (if it is installed) or the bundled PyDub library for playback.

$ pip install easyaudiostream

[!NOTE] You can also install PyAudio to slightly improve playback startup time and enable the microphone input utilities:

$ pip install easyaudiostream[pyaudio]

This is not installed by default due to compatibility issues across operating systems.

Usage

There are two main ways of playing an audio stream: using an iterator (if your audio generator yields bytes) or callbacks (if your audio generator calls a function with generated bytes).

Iterator Mode

For iterator mode, use the following two functions:

def play_stream(audio_stream: Iterable[bytes]):
    """
    Consume bytes from the audio stream and play them.

    .. note::
        This function will return as soon as the stream is exhausted!
        If your program ends after calling this function, the audio will not play - you might need to ``sleep(...)``.
    """


def play_raw_stream(
    audio_stream: Iterable[bytes], *, sample_width: int = 2, channels: int = 1, frame_rate: int = 24000
):
    """
    Consume PCM audio bytes from the audio stream and play them.

    .. warning::
        If you aren't sure which function to use, use :func:`.stream_audio` instead! Playing raw audio bytes is
        a minor optimization that avoids converting the audio format, but requires a specific input format.

    .. note::
        This function will return as soon as the stream is exhausted!
        If your program ends after calling this function, the audio will not play - you might need to ``sleep(...)``.

    By default, this method accepts raw 16 bit PCM audio at 24kHz, 1 channel, little-endian. You can control the
    expected format of the raw audio using the keyword arguments.
    """

Callback Mode

For callback mode, use the following two functions:

def play_audio(audio_bytes: bytes):
    """
    Play the given audio at the next available opportunity, using a global audio queue.

    .. note::
        This function will return immediately - it just puts the audio on a queue!
        If your program ends after calling this function, the audio will not play - you might need to ``sleep(...)``.
    """


def play_raw_audio(audio_bytes: bytes, *, sample_width: int = 2, channels: int = 1, frame_rate: int = 24000):
    """
    Play the given raw audio at the next available opportunity, using a global audio queue.

    .. warning::
        If you aren't sure which function to use, use :func:`.play_audio` instead! Playing raw audio bytes is
        a minor optimization that avoids converting the audio format, but requires a specific input format.

    .. note::
        This function will return immediately - it just puts the audio on a queue!
        If your program ends after calling this function, the audio will not play - you might need to ``sleep(...)``.

    By default, this method accepts raw 16 bit PCM audio at 24kHz, 1 channel, little-endian. You can control the
    expected format of the raw audio using the keyword arguments.
    """

Record Mic

The following functions are available to record audio from a mic:

def get_mic_stream(mic_id: int | None) -> Iterable[bytes]:
    """Return an audio stream manager that yields audio frames from the given mic."""


def get_mic_stream_async(mic_id: int | None) -> AsyncIterable[bytes]:
    """Return an audio stream manager that yields audio frames from the given mic."""


def list_mics():
    """Print a list of all microphones connected to this device."""

You can use python -m easyaudiostream to view a list of connected microphones.

Examples

import time

from easyaudiostream import play_stream

# load dummy audio from file -- normally you would get an audio stream from somewhere else
# in this example, test_audio.wav contains 16bLE mono PCM audio at 24kHz
with open("test_audio.wav", "rb") as f:
    audio = f.read()


# yield it in 1s packets every 0.95s
# but every 5s, add a 3s delay
def choppy_stream():
    for sec in range(0, len(audio), 48000 * 5):
        for i in range(0, 48000 * 5, 48000):
            yield audio[sec + i : sec + i + 48000]
            time.sleep(0.95)

        # oh no, my bytes!
        time.sleep(3)


play_stream(choppy_stream())
time.sleep(10)  # to allow all the audio to play

Release files for easyaudiostream 0.0.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for easyaudiostream 0.0.1
File Size Uploaded
easyaudiostream-0.0.1.tar.gz 9.3 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for easyaudiostream 0.0.1
File Interpreter ABI Platform
easyaudiostream-0.0.1-py3-none-any.whl Python 3 none any Details

Total release size: 18.4 kB

Release files / easyaudiostream-0.0.1.tar.gz

Download URL easyaudiostream-0.0.1.tar.gz
Size 9.3 kB
Tags Source
SHA-256 checksum
How to use checksums
88eb9b102fa1496c9cf2a82c313c05f738ad15cbca49a07c8a8256fefc62797e
BLAKE2b-256 checksum
How to use checksums
6ee428e50d76f8bb4dd0a8ba2c9a4768f4028a3a8775afb5c80fe61b71298042
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.12.8

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jan 29, 2025.

Transparency log

Release files / easyaudiostream-0.0.1-py3-none-any.whl

Download URL easyaudiostream-0.0.1-py3-none-any.whl
Size 9.2 kB
Tags Python 3
SHA-256 checksum
How to use checksums
5fdd84b5b8c46bf3e461e406b00ed92e2200a43ad471b46b6062dc7c53c869c3
BLAKE2b-256 checksum
How to use checksums
191ad788e6897f6574c494676472f78afc8c0801f406109a2a3b19c0f7d26621
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.12.8

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jan 29, 2025.

Transparency log

Release history Release notifications | RSS feed

This release

0.0.1 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page