PortAudio / portaudio

PortAudio is a cross-platform, open-source C language library for real-time audio input and output.
Other
1.43k stars 296 forks source link

PipeWire backend for better user experience on Linux #425

Open Be-ing opened 3 years ago

Be-ing commented 3 years ago

Fedora 34 will be switching to the new PipeWire sound server by default instead of PulseAudio. Other Linux distribution will probably follow in the coming 1-2 years. PipeWire is compatible with the ALSA, JACK, and PulseAudio APIs so there is no urgent need to write a new backend, but it may be a good idea to write one nevertheless.

Related issue on PipeWire's issue tracker

Be-ing commented 3 years ago

I tested PipeWire and it mostly works with the JACK host API as well as the PulseAudio host API in #336, with some caveats I reported on PipeWire's issue tracker. So I think there is no urgent need to write a new backend. However, JACK does not support hotplug, so I think we should add a PipeWire backend for that reason. According to the PipeWire wiki, PipeWire does not currently support hotplug but that is planned.

Be-ing commented 3 years ago

The JACK host API requires a few small changes to how it enumerates devices. PortAudio passes a regex to JACK to query for JACK ports. The device names in this regex need to be escaped. PipeWire calls my RME Babyface Pro Babyface Pro (70785713) and the parentheses cause the regex to not match. I don't think anyone has stumbled on this PortAudio bug before because JACK simply calls the audio interface system.

Also, PipeWire creates loopback ports. This confusingly inflates PortAudio's input channel count, so I think these should be filtered out in the regex.

Be-ing commented 3 years ago

In addition to hotplug, another reason to add a new PipeWire backend is that JACK does not have an API for applications to set the buffer size. In JACK, there is one buffer size set by jackd and that cannot be changed. PipeWire applications can request a buffer size and PipeWire will adjust all applications to use the lowest size that any application requested. Currently PortAudio applications can only request a buffer size from PipeWire by the user setting the PIPEWIRE_LATENCY environment variable. From the PipeWire wiki:

Is PipeWire Another JACK Implementation? PipeWire has a very similar processing model as JACK but adds the following features compared to JACK: Dynamic sinks and sources. Devices can be hotplugged. There is automatic slaving between devices similar to what a2j does when graphs are joined. Dynamic latency, it adapts the buffer period to the lowest requested latency. Smaller buffer sizes use more CPU but larger buffer sizes have more latency. Synchronous clients are providing data for the current processing cycle of the device(s). There is no extra period of latency. Dynamic device suspend and resume. Unused devices are closed to save CPU.

For more details read https://gitlab.freedesktop.org/pipewire/pipewire/-/wikis/FAQ#pipewire-buffering-explained

Be-ing commented 3 years ago

Who might be interested in working on this? @daschuer, @jcelerier, are you interested?

jcelerier commented 3 years ago

As much as I'd like to contribute to that, I'm already stretched pretty thin ^^'

Be-ing commented 3 years ago

In addition to hotplug, another reason to add a new PipeWire backend is that JACK does not have an API for applications to set the buffer size.

Actually, it does: jack_set_buffer_size. Currently the JACK OpenStream implementation ignores the framesPerBuffer parameter. This seems incorrect.

Dynamic latency, it adapts the buffer period to the lowest requested latency. Smaller buffer sizes use more CPU but larger buffer sizes have more latency.

This can be supported by providing an interface for jack_client_deactivate to yield control back to the PipeWire server to set the buffer size dynamically. ALSA and PulseAudio also support this. I don't know about APIs for other operating systems.

Be-ing commented 3 years ago

Actually, the JACK API could support hotplug. I think jack_set_client_registration_callback would be the key function for that. As long as PortAudio is using the JACK API to communicate with PipeWire rather than jackd, I think hotplug could work. So I'm not sure there would be a benefit of writing a new host API using the PipeWire API.

illuusio commented 3 years ago

Does Pipewire has own backend or is it just Jack/PulseAudio/ALSA layer?

Be-ing commented 3 years ago

PipeWire has its own API but I think for PortAudio's purpose there might not be any advantage of using the PipeWire API versus PipeWire's implementation of the JACK API.

illuusio commented 3 years ago

@Be-ing I have to look if it's more low latency than PulseAudio (hopefully they have learned lesson). Personally I have very bad feelings with JACK API. Don't get me wrong it's great and latency with mixing is something that I haven't seen that in Linux besides that but getting you gear working can be too much hustle for amateur like me.

Be-ing commented 3 years ago

Yes, PipeWire works at lower latencies than PulseAudio.

Chris2000SP commented 1 year ago

I have the Issue that a Game called X4 Foundations on Steam uses Jack over portaudio only if it detects it but could use pulse or alsa but can not switch to it because the original jack would conflict with pulse. If i use a Jabra Engage 75 or any bluetooth audio device i get a bad sound over pipewire-jack, it is forced and if i start Mumble first and use it with the Jabra and Start the Game second. On Arch linux portaudio forces to install jack2 or pipewire-jack. This is a bad situation because i have to force remove it and if i would start mixxx for example i get an error because all programs that depends on jack would not start. I could workaround it with the order of starting applications by first start the app using jack then start others using pipewire, pulse, alsa etc.

It is bad because a bluetooth audio alike devices are bad with jack.

jcelerier commented 1 year ago

regarding this issue, if that can be of interest to anyone I have a quick and dirty binding here: https://github.com/ossia/libossia/blob/master/src/ossia/audio/pipewire_protocol.hpp

Poikilos commented 2 weeks ago

Pipewire becoming the standard (being the default in a distro, or being tied into jack 2) makes the issue more significant. In Linux Mint 21.3, sudo apt install portaudio19-dev, which is the only package in Ubuntu Jammy or Ubuntu Noble to provide portaudio.h, downgrades jack, which uninstalls wine...

The following additional packages will be installed:
  libjack-dev libjack0 libportaudiocpp0
Suggested packages:
  jackd1 portaudio19-doc
The following packages will be REMOVED:
  libasound2-plugins:i386 libjack-jackd2-0 libjack-jackd2-0:i386 wine-stable wine-stable-i386:i386 winehq-stable
The following NEW packages will be installed:
  libjack-dev libjack0 libportaudiocpp0 portaudio19-dev

:edit: :star: Downgrades can be prevented as follows:

install libjack-jackd2-dev before installing portaudio19-dev. -https://bugs.launchpad.net/ubuntu/+source/portaudio19/+bug/132002

I also tested adding libjack-jackd2-dev to the same apt command as portaudio19-dev, and that works as well (There is no need to install libjack-jackd2-dev separately).

jcelerier commented 2 weeks ago

both @Poikilos and @Chris2000SP issues are more on the distro packaging side though - distros could entirely choose to make pipewire-jack the "default" jack implementation so that a package that depends on "jack" or "jack2" would actually go through pipewire as pipewire provides its own jack implementation

fredvs commented 2 weeks ago

It would be really great if PortAudio could handle PipeWire out of the box. For example, Mageia has PipeWire by default and Mixxx or Audacity which use Portaudio can't run it. (and all my apps too)

fredvs commented 2 weeks ago

Ooops, no it works, sorry for the noise. (But using "PipeWire with PipeWire Media Session" does not give sound.)

mageia5