Image of an arrow

PipeWire in Linux embedded project: a multi-ports audio system demo on i.MX8 (Part 2)

Avatar

lebaotinha

PipeWire, implementation and evaluation

In the last article, we prepared an audio system on which we could replace the sound server. In addition, we explained the main concepts of JACK and PulseAudio in audio recording and playback. This second part presents PipeWire, how to use it in our audio system and measures its performance.

PipeWire

PipeWire is an open-source project for handling multimedia pipelines in Linux system.  There is already a very good introduction about PipeWire which was made by Bootlin that everyone can refer to, which can be accessed here. The aim of this project is to provide a low-latency, graph-based processing engine on top of audio and video devices. Each element of the graph (sound device, application…) is called a node. The whole PipeWire system graph can be observed by running this command:

 $pw-dot -a -d -9 

This command will show every node in the Pipewire graph including the audio input/output nodes, client nodes and library nodes with details. Here is a view of our project’s entire graph.

In this project, we use WirePlumber as a modular session/policy manager. WirePlumber is an advanced session/policy manager, based on Glib/GObject. Its purpose is  to wrap aroundPipeWire API, by using the daemon’s modules or the external tools to manage PipeWire functionality.

Source: https://www.collabora.com/news-and-blog/blog/2020/05/07/wireplumber-the-pipewire-session-manager/

During initialization, WirePlumber creates the nodes for Alsa playback and capture devices. It will also create the nodes for its clients, which are applications using PipeWire as server. A node consists of multiple ports, classified by their direction: input or output. PipeWire will use the links to connect these ports between different nodes together. A node created from Alsa devices with only the input ports is called an “Audio/Sink” and those with only the output ports is called an “Audio/Source”.

You can see here how PipeWire creates and connects the ports between CamillaDSP ports (cpal_client_*) and our Alsa device ports (*_sound_cs42448) together. The linking is done by a port mapping in API, but these links are interactive and can be manipulated by user. This means we can delete, create, or redirect a link to another port on the fly.

PipeWire can be used to replace both PulseAudio and JACK, by providing a  PulseAudio-compatible server implementation and an ABI-compatible libraries for JACK clients.

JACK and PulseAudio replacement

To replace JACK server by PipeWire for running a JACK client, we must:

  1. Run PipeWire and Wireplumber (by program or by service).
  2. Run pw-jack right before the JACK Client in one command line. For example in our case:
     $pw-jack camilladsp /etc/camilladsp/jackconfig.conf 

pw-jack will force the JACK client to use PipeWire’s reimplementation of JACK libraries by changing the LD_LIBRARY_PATH environment variable, instead of the standard JACK libraries .

To replace PulseAudio server by PipeWire for running a PulseAudio client, we must:

  1. Run PipeWire, Wireplumber and PipeWire-pulse. PipeWire-pulse is a PulseAudio-compatible daemon that integrates with the PipeWire media server, which can be used to replace the standard PulseAudio.
  2. Check current daemon information by:
     $pactl info 

    You should see this in the output: “Server Name: PulseAudio (on PipeWire x.x.x)”. This indicates that PipeWire daemon will be used by the PulseAudio clients instead of a standard Pulseaudio server.

  3. Run the PulseAudio client.

From the point of view of applications, they are still using JACK and PulseAudio API, but these APIs are in fact provided by PipeWire. This makes it possible for us to run at the same time a JACK client and a PulseAudio client, which required specific configuration before.

 

Example of running at a same time a JACK client, a PulseAudio client and a PipeWire client

 

Schema illustrating the way PulseAudio and JACK applications are supported

Source: https://bootlin.com/blog/an-introduction-to-PipeWire/

Performance Results

Wim Taymans, the developer of PipeWire, has already done a complete article about PipeWire performance, you can see it here. However, these tests are run on the desktop platforms and the results might be different for embedded systems.

In this article, we compare PipeWire with JACK, PulseAudio, and direct ALSA access through alsa-libs in the context of an embedded platform (i.MX8 Nano Ultralite). CPU usage and latency are the main comparison factors.

CamillaDSP with only Alsa-lib

We first test the performance when CamillaDSP is running only with Alsa, which means no sound server is used. In this case, CamillaDSP directly uses the Alsa-lib API to exchange audio data with the device through ALSA.

With htop, we can see that the process “CamillaDSP” consumes 28% of the CPU with three small threads.

The oscilloscope shows a latency around 4 ms:

 

As you can see, these results show a very good performance. The limitation is that only CamillaDSP can read/write samples to the audio device. If there is only one application, this would probably be the most efficient solution, otherwise this may be a limitation for complex use-cases involving multiple applications.

CamillaDSP with JACK and PipeWire-JACK

We compared JACK and PipeWire with 256 samples buffers for both sound servers. The CPU load measurements with CamillaDSP running, measured with htop, are shown below:

CamillaDSP with JACK serverCamillaDSP with PipeWire server
CamillaDSPJACKCamillaDSPPipewire
%CPU28%18%16%14%
Threads5151

 

As can be seen, CamillaDSP running with Pipewire server consumes much less CPU, almost half of what it consumes when running with JACK server !

Then, we changed the value of buffer size in two cases in a range from 32 samples to 1024 to test the latency. For each buffer size, the full audio chain latency is measured with the oscilloscope. The results are displayed below:

 

Our results are similar to the results of Wim Taymans in his article. For small fixed buffer size, JACK seems to do better than PipeWire. But starting from buffer of 128 samples, PipeWire gradually becomes better in terms of system latency.

CamillaDSP with PulseAudio and PipeWire-Pulse

PulseAudio uses a dynamic buffer size to make the system as balanced as possible. In our case, the latency we measured is about 60 ms.

PipeWire-Pulse also uses a dynamic buffer latency, but we can force Pipewire to use a fixed value or to specify the maximum buffer size in its configuration. This means PipeWire-Pulse can have a better latency compared to PulseAudio if we ignore all other aspects, concerning the CPU usage and the configuration complexity. But to fairly compare CPU load, we set the latency of PipeWire-Pulse client to 60ms.

CamillaDSP with PulseAudio serverCamillaDSP with PipeWire server
CamillaDSPPulseAudioCamillaDSPPipeWirePipeWire-Pulse
%CPU25%34%34%17%20%
Threads51511

 

The above results show that, when compared to standard PulseAudio at the same latency, PipeWire used more CPU due to having to run PipeWire daemon and PipeWire-Pulse daemon at the same time. This causes a high CPU usage in general although the latency is not too outstanding.

CPU usage of four previous cases when fixing the same latency

To make a CPU load comparison between all sound servers, we manually set  their latency to 60ms. The following table details the CPU load  comparison at this set latency, to show which solution is the most  efficient.

CamillaDSP with JACKCamillaDSP with PipeWire-jack
ProcessCamillaDSPJACKCamillaDSPPipeWire
%CPU26.114.114.310.5

 

CamillaDSP with PulseAudioCamillaDSP with PipeWire & PipeWire-Pulse
ProcessCamillaDSPPulseAudioCamillaDSPPipeWirePipeWire-Pulse
%CPU26.735.135.617.424.3

 

These results show that, while PipeWire itself is an efficient solution, the use of PipeWire-pulse hinders its performance. This makes it a good candidate for real-time designs as a JACK replacement, where it can be used to gain CPU load for other processes. However, as of now, further developments or configuration optimizations are required to make it a Pulseaudio replacement in use-cases where JACK compatibility is not needed.

Conclusion

PipeWire is still a young project compared to JACK and PulseAudio but it has really met the majority of users expectations in the embedded projects about its major strides, its convenience of new features and its performance. With the reimplementation of JACK and PulseAudio APIs, PipeWire does not require users to do any change to their application. Instead, users can still take advantage of its strengths, even combine them together.

In addition, the developer’s ambition for PipeWire is to be a multimedia platform, not only an audio server, which can also control image streams, so the future of PipeWire is to be able to manipulate the whole multimedia system in a project. This will be extremely convenient for developers who only have to master and to maintain one back-end technology and rely on established clients.

Leave a comment

Your email address will not be published. Required fields are marked *


Similar articles

Image of an arrow

What’s new? We’re happy to announce the release of v2.7.0, which includes a few new features as well as bug fixes. Check out the summarized changelog below: Add bitbake environment scan for global variables Add skipped recipes to the tree view with skip reason Add support for latest Yocto devtool status output Add sanity check […]

What’s new? We’re happy to announce the release of v2.6.0, which includes which a few new features, improvements to user experience, and minor bug fixes. Check out the summarized changelog below: Handle completion on bash simple variable expansion Handle keywords import, require and inherit in Bash/Python context Add SPDX license suggestions Show license description on […]

What’s new? We’re happy to announce the release of v2.5.0, which includes a few new features as well as quality-of-life improvements and minor bug fixes. Here is the change log: Add Yocto variables renaming across a recipe file Add code suggestions for SRC_URI local files Add code suggestions for recipe names in variables (DEPENDS, RDEPENDS, […]

Nuremberg, April 9th, 2024 – In an era where cybersecurity threats are increasingly sophisticated and pervasive, Savoir-faire Linux, a leading provider in open-source technological innovation and software engineering for embedded systems across North America and Europe, is proud to announce the launch of its Cybersecurity professional services tailored specifically for product engineering and embedded systems. […]

Savoir-faire Linux is happy to introduce the v2.4.0 release of the official Yocto Project extension for VS Code. These developments were carried out as part of the investment provided by the Sovereign Tech Fund to the Yocto Project to improves the long-term sustainability of the project by attracting a new generation of developers. The changelog […]