Skip to main content

Simple playback for intermittent audio byte streams in Python.

Project description

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

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

easyaudiostream-0.0.1.tar.gz (9.3 kB view details)

Uploaded Source

Built Distribution

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

easyaudiostream-0.0.1-py3-none-any.whl (9.2 kB view details)

Uploaded Python 3

File details

Details for the file easyaudiostream-0.0.1.tar.gz.

File metadata

  • Download URL: easyaudiostream-0.0.1.tar.gz
  • Upload date:
  • Size: 9.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.12.8

File hashes

Hashes for easyaudiostream-0.0.1.tar.gz
Algorithm Hash digest
SHA256 88eb9b102fa1496c9cf2a82c313c05f738ad15cbca49a07c8a8256fefc62797e
MD5 d8ff51ce2c0cffd4975210785730c20f
BLAKE2b-256 6ee428e50d76f8bb4dd0a8ba2c9a4768f4028a3a8775afb5c80fe61b71298042

See more details on using hashes here.

Provenance

The following attestation bundles were made for easyaudiostream-0.0.1.tar.gz:

Publisher: pythonpublish.yml on zhudotexe/easyaudiostream

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

File details

Details for the file easyaudiostream-0.0.1-py3-none-any.whl.

File metadata

File hashes

Hashes for easyaudiostream-0.0.1-py3-none-any.whl
Algorithm Hash digest
SHA256 5fdd84b5b8c46bf3e461e406b00ed92e2200a43ad471b46b6062dc7c53c869c3
MD5 7dd8529fd5a3559895ea4bfcd3fb37e4
BLAKE2b-256 191ad788e6897f6574c494676472f78afc8c0801f406109a2a3b19c0f7d26621

See more details on using hashes here.

Provenance

The following attestation bundles were made for easyaudiostream-0.0.1-py3-none-any.whl:

Publisher: pythonpublish.yml on zhudotexe/easyaudiostream

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