Skip to content

A python wrapper for the "PulseAudio simple API". Supports playing and recording audio via PulseAudio and PipeWire.

License

Notifications You must be signed in to change notification settings

henrikschnor/pasimple

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

10 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

pulseaudio-simple

A python wrapper for the pulseaudio simple API. Supports playing and recording audio via PulseAudio and PipeWire.

This library is feature-complete, so there won't be much ongoing activity in this repository. Reported bugs will be fixed. PRs for improvements are always welcome.

Dependencies

  • libpulse-simple.so.0 (part of libpulse0 on Debian or libpulse on Arch)
  • A running PulseAudio/PipeWire server

There's a good chance your Linux distribution comes with PulseAudio or PipeWire preinstalled.

Installation

pip3 install pasimple

Quick start

There are two simple convenience functions for recording/playing audio to/from a .wav file:

from pasimple import record_wav, play_wav

# Record 5 seconds of audio from the default recording device
record_wav('/tmp/test_recording.wav', 5)

# Play the recording via the default output device
play_wav('/tmp/test_recording.wav')

Both functions block until all audio has been recorded/played. The default encoding used by record_wav is PA_SAMPLE_S24LE, mono, 41kHz. The function play_wav can only recognize files encoded in one of the following formats: PA_SAMPLE_U8, PA_SAMPLE_S16LE, PA_SAMPLE_S24LE, PA_SAMPLE_S32LE. For more complex use cases, scroll down to the "Documentation" section.

Recording

A more extensive example for recording audio can be found in examples/record.py:

import wave
import pasimple

# Audio attributes for the recording
FORMAT = pasimple.PA_SAMPLE_S32LE
SAMPLE_WIDTH = pasimple.format2width(FORMAT)
CHANNELS = 1
SAMPLE_RATE = 41000

# Record 10 seconds of audio
with pasimple.PaSimple(pasimple.PA_STREAM_RECORD, FORMAT, CHANNELS, SAMPLE_RATE) as pa:
    audio_data = pa.read(CHANNELS * SAMPLE_RATE * SAMPLE_WIDTH * 10)

# Save audio to a file
with wave.open('recording.wav', 'wb') as wave_file:
    wave_file.setsampwidth(SAMPLE_WIDTH)
    wave_file.setnchannels(CHANNELS)
    wave_file.setframerate(SAMPLE_RATE)
    wave_file.writeframes(audio_data)

In this example we're explicity specifying the audio format to be used for recording. When the PaSimple object is created, it opens a PulseAudio stream with the specified format. Further parameters that can be used in the PaSimple constructor are described in more detail under "Documentation" below.

The recording starts as soon as the PaSimple object is created and audio data is buffered internally. Calls to read can retrieve the raw audio data, specifying the number of bytes to read as an argument. The function will block until the requested number of bytes is available. When done recording, the PaSimple object's audio stream should be closed with a call to close(). Alternatively, it can be used with python's context manager (the with statement in the example above).

Finally, the data is written to a .wav file. We specify the audio format again, so that a correct .wav file header can be written.

Playing

An example for playing audio can be found in examples/play.py:

import wave
import pasimple

# Read a .wav file with its attributes
with wave.open('recording.wav', 'rb') as wave_file:
    format = pasimple.width2format(wave_file.getsampwidth())
    channels = wave_file.getnchannels()
    sample_rate = wave_file.getframerate()
    audio_data = wave_file.readframes(wave_file.getnframes())

# Play the file via PulseAudio
with pasimple.PaSimple(pasimple.PA_STREAM_PLAYBACK, format, channels, sample_rate) as pa:
    pa.write(audio_data)
    pa.drain()

To play a .wav file, we basically do the recording steps in reverse. First, we read the audio encoding together with the raw audio data from the file. When creating the PaSimple object, this time, we're opening a playback stream and specify the format of the audio we're going to play. It's then as simple as passing the raw audio data to the write function. Finally, we call drain to make sure all audio has played before closing the stream by leaving the with context.

Streaming

An annotated example of how to stream audio from/to a source/sink can be found in examples/echo.py

Documentation

This sections describes all constants/functions/classes available in the pasimple module.

Constants

Stream directions

The stream direction is used when creating a PaSimple object to specify whether the stream should be used for playing or recording audio.

Constant Description
PA_STREAM_PLAYBACK Open a stream for playback
PA_STREAM_RECORD Open a stream for recording

Audio formats

Formats that can be used with PulseAudio to play or record audio. PulseAudio's documentation for these formats can be found here.

Constant Description
PA_SAMPLE_U8 Unsigned 8 Bit PCM
PA_SAMPLE_ALAW 8 Bit a-Law
PA_SAMPLE_ULAW 8 Bit mu-Law
PA_SAMPLE_S16LE Signed 16 Bit PCM, little endian (PC)
PA_SAMPLE_S16BE Signed 16 Bit PCM, big endian
PA_SAMPLE_FLOAT32LE 32 Bit IEEE floating point, little endian (PC), range -1.0 to 1.0
PA_SAMPLE_FLOAT32BE 32 Bit IEEE floating point, big endian, range -1.0 to 1.0
PA_SAMPLE_S32LE Signed 32 Bit PCM, little endian (PC)
PA_SAMPLE_S32BE Signed 32 Bit PCM, big endian
PA_SAMPLE_S24LE Signed 24 Bit PCM packed, little endian (PC)
PA_SAMPLE_S24BE Signed 24 Bit PCM packed, big endian
PA_SAMPLE_S24_32LE Signed 24 Bit PCM in LSB of 32 Bit words, little endian (PC)
PA_SAMPLE_S24_32BE Signed 24 Bit PCM in LSB of 32 Bit words, big endian

Convenience functions

width2format(sample_width)

  • sample_width: Audio sample width to return a matching format for.

Returns one of PA_SAMPLE_U8, PA_SAMPLE_S16LE, PA_SAMPLE_S24LE or PA_SAMPLE_S32LE (common PCM audio formats), corresponding to the provided sample width or an error if none match.

format2width(audio_format)

  • audio_format: One of the PA_SAMPLE_* audio formats to return the width for.

Returns the sample width for an audio format.

play_wav(file_path)

  • file_path: Path to a .wav file to be played.

Plays a .wav file via PulseAudio and blocks until all audio data has been played. The following formats are supported: PA_SAMPLE_U8, PA_SAMPLE_S16LE, PA_SAMPLE_S24LE, PA_SAMPLE_S32LE. Throws a wave.Error if the .wav file cannot be read or a PaSimpleError if the audio data cannot be played.

record_wav(file_path, length, format=PA_SAMPLE_S24LE, channels=1, sample_rate=41000)

  • file_path: Path to a .wav file the recorded audio will be written to.
  • length: The length of the recording in seconds.
  • format: Audio format to be used for the recording (one of PA_SAMPLE_U8, PA_SAMPLE_S16LE, PA_SAMPLE_S24LE, PA_SAMPLE_S32LE).
  • channels: Number of channels to record (1=mono, 2=stereo).
  • sample_rate: Sample rate for the recording in Hz.

Records a .wav file via PulseAudio and blocks until all audio data has been recorded. The following formats are supported: PA_SAMPLE_U8, PA_SAMPLE_S16LE, PA_SAMPLE_S24LE, PA_SAMPLE_S32LE. Throws a wave.Error if the .wav file cannot be written or a PaSimpleError if the audio data cannot be recorded.

PaSimple

An instance of PaSimple represents an audio stream for playing or recording audio via PulseAudio. On error, all functions throw a PaSimpleError.

PaSimple(direction, format, channels, rate, app_name='python', stream_name=None, server_name=None, device_name=None, maxlength=-1, tlength=-1, prebuf=-1, minreq=-1, fragsize=-1):

  • direction: Either PA_STREAM_PLAYBACK or PA_STREAM_RECORD.
  • format: The audio encoding (one of PA_SAMPLE_*) for this stream.
  • channels: Integer specifying the number of channels (1=mono, 2=stereo).
  • rate: Integer specifying the sample rate in Hz.
  • app_name: String specifying the name of the application that will be registered in PulseAudio.
  • stream_name: None (use app_name) or a string specifying the name of this stream that will be registered in PulseAudio.
  • server_name: None (default) or a string specifying a PulseAudio server name.
  • device_name: None (default) or a string specifying a specific PulseAudio device for recording or playback.
  • maxlength: -1 (default: max supported) or an integer specifying the buffer size limit in bytes.
  • tlength: -1 (default: about 2s) or an integer specifying how many bytes to keep in the playback buffer.
  • prebuf: -1 (use tlength) or an integer specifying how many bytes to buffer before starting playback.
  • minreq: -1 (default: about 2s) or an integer specifying the minimum size of chunks for refilling the playback buffer in bytes.
  • fragsize: -1 (default: about 2s) or an integer specifying the size of recording chunks in bytes.

Initialize a PulseAudio simple API stream for playing or recording audio data.

close()

Close the underlying stream and free resources.

direction()

Returns the direction specified in the constructor.

format()

Returns the audio format specified in the constructor.

channels()

Returns the number of audio channels specified in the constructor.

rate()

Returns the audio rate specified in the constructor.

read(num_bytes)

  • num_bytes: The number of bytes to read.

Record data from the PulseAudio server. PA_STREAM_RECORD must have been used during initialization. This function blocks and returns num_bytes bytes of audio data.

write(data)

  • data: Raw audio data to be played.

Play audio via the PulseAudio server. PA_STREAM_PLAYBACK must have been used during initialization. Encoding of data must match the one specified in the constructor.

drain()

Blocks until all remaining data in the buffer has been played.

flush()

Discards any data in the record/playback buffers.

get_latency()

Returns the record/playback latency reported by PulseAudio in microseconds.

PulseAudio error codes

This list of PulseAudio internal error codes has been taken from here.

Error code Description
0 No error
1 Access failure
2 Unknown command
3 Invalid argument
4 Entity exists
5 No such entity
6 Connection refused
7 Protocol error
8 Timeout
9 No authentication key
10 Internal error
11 Connection terminated
12 Entity killed
13 Invalid server
14 Module initialization failed
15 Bad state
16 No data
17 Incompatible protocol version
18 Data too large
19 Operation not supported
20 The error code was unknown to the client
21 Extension does not exist
22 Obsolete functionality
23 Missing implementation
24 The caller forked without calling execve() and tried to reuse the context
25 An IO error happened
26 Device or resource busy
27 Not really an error but the first invalid error code

About

A python wrapper for the "PulseAudio simple API". Supports playing and recording audio via PulseAudio and PipeWire.

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages