Skip to main content

Python high-level interface and ctypes-based bindings for PulseAudio (libpulse)

Project description

Python (3.x and 2.x) high-level interface and ctypes-based bindings for PulseAudio (libpulse), mostly focused on mixer-like controls and introspection-related operations (as opposed to e.g. submitting sound samples to play, player-like client).

Originally forked from pulsemixer project, which had this code bundled.


Usage

Simple example:

from pulsectl import Pulse

with Pulse('volume-increaser') as pulse:
  for sink in pulse.sink_list():
    # Volume is usually in 0-1.0 range, with >1.0 being soft-boosted
    pulse.volume_change_all_chans(sink, 0.1)

Listening for server state change events:

from pulsectl import Pulse, PulseLoopStop

with Pulse('event-printer') as pulse:
  # print('Event types:', ', '.join(pulse.event_types))
  # print('Event facilities:', ', '.join(pulse.event_facilities))
  # print('Event masks:', ', '.join(pulse.event_masks))

  def print_events(ev):
    print('Pulse event:', ev)
    ### Raise PulseLoopStop for event_listen() to return before timeout (if any)
    # raise PulseLoopStop

  pulse.event_mask_set('all')
  pulse.event_callback_set(print_events)
  pulse.event_listen(timeout=10)

Misc other tinkering:

>>> from pulsectl import Pulse
>>> pulse = Pulse('my-client-name')

>>> pulse.sink_list()
[<PulseSinkInfo at 7f85cfd053d0 - desc='Built-in Audio', index=0L, mute=0, name='alsa-speakers', channels=2, volumes='44.0%, 44.0%'>]

>>> pulse.sink_input_list()
[<PulseSinkInputInfo at 7fa06562d3d0 - index=181L, mute=0, name='mpv Media Player', channels=2, volumes='25.0%, 25.0%'>]

>>> pulse.sink_input_list()[0].proplist
{'application.icon_name': 'mpv',
 'application.language': 'C',
 'application.name': 'mpv Media Player',
 ...
 'native-protocol.version': '30',
 'window.x11.display': ':1.0'}

>>> pulse.source_list()
[<PulseSourceInfo at 7fcb0615d8d0 - desc='Monitor of Built-in Audio', index=0L, mute=0, name='alsa-speakers.monitor', channels=2, volumes='100.0%, 100.0%'>,
 <PulseSourceInfo at 7fcb0615da10 - desc='Built-in Audio', index=1L, mute=0, name='alsa-mic', channels=2, volumes='100.0%, 100.0%'>]

>>> sink = pulse.sink_list()[0]
>>> pulse.volume_change_all_chans(sink, -0.1)
>>> pulse.volume_set_all_chans(sink, 0.5)

>>> help(pulse)
...

Current code logic is that all methods are invoked through the Pulse instance, and everything returned from these are “Pulse-Something-Info” objects - thin wrappers around C structs that describe the thing, without any methods attached.

Pulse client can be integrated into existing eventloop (e.g. asyncio, twisted, etc) using Pulse.set_poll_func() or Pulse.event_listen() in a separate thread.

Somewhat extended usage example can be found in pulseaudio-mixer-cli project code.

Concepts

Some less obvious things are described in this section.

Volume

All volume values in this module are float objects in 0-65536.0 range, with following meaning:

  • 0.0 volume there is “no sound”.

  • 1.0 value is “current sink volume level”, 100% or PA_VOLUME_NORM.

  • >1.0 and up to 65536.0 (PA_VOLUME_MAX / PA_VOLUME_NORM) - software-boosted sound volume (higher values will negatively affect sound quality).

Probably a good idea to set volume only in 0-1.0 range and boost volume in hardware without any quality loss, e.g. by tweaking sink volume, which corresponds to ALSA/hardware volume, if that option is available.

See src/pulse/volume.h in pulseaudio sources for all the gory details.

Event-handling code and threads

libpulse clients always work as an event loop, though this module kinda hides it, presenting a more conventional blocking interface.

So what happens on any call (e.g. pulse.mute(...)) is:

  • Send command to libpulse, specifying callback for when its done.

  • Run libpulse event loop until that callback gets called.

  • Return result of that callback.

event_callback_set() and event_listen() calls essentally do raw first and second step here.

Which means that any pulse calls from callback function can’t be used when event_listen() (or any other pulse call through this module, for that matter) waits for return value and runs libpulse loop already.

One can raise PulseLoopStop exception there to make event_listen() return, run whatever pulse calls after that, then re-start the event_listen() thing.

This will not miss any events, as all calls do same thing as event_listen() does (second step above), and can cause callable passed to event_callback_set() to fire.

Also, same instance of libpulse eventloop can’t be run from different threads, naturally, so if threads are used, client can be initialized with threading_lock=True option (can also accept lock instance instead of True) to create a mutex around step-2 (run event loop) from the list above, so two threads won’t try to do it at the same time.

Installation

It’s a regular package for Python (3.x or 2.x).

Be sure to use python3/python2, pip3/pip2, easy_install-… binaries below, based on which python version you want to install the module for, if you have several on the system (as is norm these days for py2-py3 transition).

Using pip is the best way:

% pip install pulsectl

If you don’t have pip:

% easy_install pip
% pip install pulsectl

Alternatively (see also pip2014.com and pip install guide):

% curl https://raw.github.com/pypa/pip/master/contrib/get-pip.py | python
% pip install pulsectl

Or, if you absolutely must:

% easy_install pulsectl

But, you really shouldn’t do that.

Current-git version can be installed like this:

% pip install 'git+https://github.com/mk-fg/python-pulse-control.git#egg=pulsectl'

Note that to install stuff in system-wide PATH and site-packages, elevated privileges are often required. Use “…install –user”, ~/.pydistutils.cfg or virtualenv to do unprivileged installs into custom paths.

Project details


Release history Release notifications | RSS feed

Download files

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

Source Distribution

pulsectl-16.4.5.tar.gz (16.0 kB view hashes)

Uploaded Source

Supported by

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