Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/i-rinat/apulse

PulseAudio emulation for ALSA
https://github.com/i-rinat/apulse

alsa c linux pulseaudio pulseaudio-emulation sound

Last synced: 6 days ago
JSON representation

PulseAudio emulation for ALSA

Awesome Lists containing this project

README

        

About
=====

PulseAudio emulation for ALSA.

The program provides an alternative partial implementation of the PulseAudio
API. It consists of a loader script and a number of shared libraries with the
same names as from original PulseAudio, so applications could dynamically load
them and think they are talking to PulseAudio. Internally, no separate sound
mixing daemon is used. Instead, apulse relies on ALSA's `dmix`, `dsnoop`, and
`plug` plugins to handle multiple sound sources and capture streams running at
the same time. `dmix` plugin muxes multiple playback streams; `dsnoop` plugin
allow multiple applications to capture from a single microphone; and `plug`
plugin transparently converts audio between various sample formats, sample rates
and channel numbers. For more than a decade now, ALSA comes with these plugins
enabled and configured by default.

`apulse` wasn't designed to be a drop-in replacement of PulseAudio. It's
pointless, since that will be just reimplementation of original PulseAudio, with
the same client-daemon architecture, required by the complete feature
set. Instead, only parts of the API that are crucial to specific applications
are implemented. That's why there is a loader script, named `apulse`. It updates
value of `LD_LIBRARY_PATH` environment variable to point also to the directory
where apulse's libraries are installed, making them available to the
application.

Name comes from names of both ALSA and PulseAudio. As `aoss` was a compatibility
layer between OSS programs and ALSA, `apulse` was designed to be compatibility
layer between PulseAudio applications and ALSA.

Install
=======

You need ALSA libraries and GLib installed. On Debian-based distributions, they
are in packages `libasound2-dev` and `libglib2.0-dev`.

To build and install, run in source directory:

```
$ mkdir build && cd build
$ cmake -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_BUILD_TYPE=Release ..
$ make
# make install
```

That will create directory named `build`, and build there. It's possible to
install just by running `make install` as `root`, as shown above. But you won't
be able to uninstall installed files. That's why it's recommended to wrap files
into a package. Use `checkinstall`, or some alternative.

If you want 32-bit binaries on 64-bit machine (for example, for Skype), use:
```
$ mkdir build && cd build
$ CFLAGS=-m32 cmake -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_BUILD_TYPE=Release ..
$ make
# make install
```

Recent GLib versions use different `.pc` files for `i386` and `amd64`. To help
`pkg-config` find 32-bit versions, use `PKG_CONFIG_PATH` variable. So, on
Debian it will be something like:

```
$ PKG_CONFIG_PATH=/usr/lib/i386-linux-gnu/pkgconfig CFLAGS=-m32 cmake -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_BUILD_TYPE=Release ..
```

There is a way to configure where apulse libraries will be installed, via
`APULSEPATH` cmake variable. For example, if you want to install libraries
into default path, `/usr/lib`, use
```
cmake -DAPULSEPATH=/usr/lib -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_BUILD_TYPE=Release ..
```

If libraries are installed to a regular library path, you don't need run applications
through `apulse` wrapper.

Usage
=====

```
$ apulse [program-parameters]
```

Environment variables `APULSE_CAPTURE_DEVICE` and `APULSE_PLAYBACK_DEVICE` can be used
to configure capture and playback devices. Try `hw:0,0`, `plughw:0,0` and the like.
Refer to the ALSA user guide for a full list of device names.

System directory versus separate directory installations
--------------------------------------------------------

By default, libraries from `apulse` are installed into a separate directory, in
order to hide them from all applications.

Most applications in the wild, that support both PulseAudio and ALSA, try to
autodetect which sound system is used. First, applications try to start with
PulseAudio. Original client libraries fail early if no PulseAudio daemon is
running or can be started. Then they switch to ALSA. Decision is made once, at
the beginning. It works fine with PulseAudio, but doesn't work with
`apulse`. Latter has no daemons, it happily says that everything is fine, and
it's capable of playing audio. Applications then try to call more functions, and
eventually touch unimplemented parts, often with crashes. So, libraries are
hidden, and become visible only when a program is called through `apulse`
wrapper script.

It's possible to install apulse libraries to `/usr/lib`. Wrapper script won't
be required, but then all applications will try to use PulseAudio API, despite
they can use ALSA.

Per-app RPATH trick
-------------------

There is the RPATH property of ELF executable format, which is used to specify
paths to search for dynamic libraries. It's like LD_LIBRARY_PATH variable, but
per-executable. Since all that `apulse` launcher script does is setting
LD_LIBRARY_PATH value before launching an application, it's possible to bake
paths to apulse libraries into target executable itself. And so to launch it
as usual, without helper script.

For example, for Firefox it would be:

```
# patchelf --set-rpath /usr/lib/apulse /usr/lib/firefox/libxul.so
```

For some reason, it doesn't work if RPATH is set for `/usr/lib/firefox/firefox`
itself, so some experiments are required to make it work.

Known issues
============

Not implemented functions, application crashes
----------------------------------------------

Large portion of PulseAudio API is not implemented. There are functions that do
nothing and return some arbitraty values. Often, if application tries to call
something not implemented, it crashes while trying to dereference a NULL
pointer. By default, tracing level is set to `0`, which means no messages are
printed to standard output. It's possible to increase that value to `1`, which
shows unimplemented function calls, or to `2`, which shows all function calls.

To change level, use `WITH_TRACE` parameter when calling `cmake`. Something like
`cmake -DWITH_TRACE=1 ..`

Building apulse with trace level 1 won't fix issues, but will at least help to
identify if crashes are caused by not implemented functions.

Generic errors in do_connect_pcm
--------------------------------

Apulse acts as a generic ALSA client. It tries to open audio device, and
sometimes fails. At its core, apulse does neither audio mixing nor
resampling. Instead, it relies on `plug`, `dmix`, and `dsnoop` ALSA plugins,
which are usually enabled by default. These plugins handle multiple audio
sources, performing resampling and mixing transparently. For years now ALSA
comes with those plugins enabled. Audio just works without configuring
anything. But not everybody use default settings.

On custom configurations apulse may fail to output and/or capture audio. There
could be no sound at all, or just a single audio stream playing at a time. It's
also possible that adapters with hardware mixers, which capable of playing
multiple streams, may still be unable to handle multiple capture
streams. Depending on hardware, you may still need either `dmix` or `dsnoop`
plugins. Or both.

In other words, for apulse to work, your setup should be capable of playing and
capturing multiple streams simultaneously.

Access errors in do_connect_pcm
-------------------------------

If other applications output sound just fine, it's possible that application you
are using restricts itself.

For example, Firefox now have a sandbox, that blocks file access. It has
predefined list of allowed paths, but ALSA devices are not included by
default. Fortunately, it's possible to add those path by hand. Add "/dev/snd/"
to "security.sandbox.content.write_path_whitelist" parameter in
`about:config`. Note that trailing slash in "/dev/snd/" is required.

Firefox 58 tabs crashing when trying to play audio
--------------------------------------------------

Firefox 58 (Nightly) tightened its sandbox a bit more. Now `ioctl()` calls are
forbidden too, but are used by ALSA libraries. That causes sandbox violation
with subsequent process termination. Exception can be added by setting parameter
`security.sandbox.content.syscall_whitelist` in `about:config`. That field
accepts a comma separated list of system call numbers. Add there `16` for
x86-64, or `54` for x86 or ARM.

Firefox 60 tighened its content sandbox more, but at the same time moved audio
accesses from content processes to the main process. From Firefox 60 onwards no
changes to the sandbox settings are necessary.

License
=======

Source code is distributed under the terms of the MIT License. See LICENSE.MIT for full text.

Third party code
================

`/3rdparty/pulseaudio-headers` contains part of PulseAudio project and is distributed
under LGPLv2.1+ terms. See content of the files for details.