Skip to content
Open
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 70 additions & 0 deletions proposals/2026-05-14_pipewire.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
# PipeWire support for Mixxx

* **Owners:**
* `@pri-yan-shu`

* **Implementation Status:** `Not implemented`

> TL;DR: This proposes PipeWire audio API support to Mixxx, SoundDevice hotplug
for PipeWire, ability to route audio from Mixxx UI, and react to external changes.

## Why

PipeWire is an audio API for Linux. It replaces the multiple audio APIs already
present on Linux, like ALSA, JACK, PulseAudio, and has compatibility layer for
all those APIs. It also supports connecting any audio source/sink (from any
application) to Mixxx, like the system audio inputs/outputs. This allows for
flexibility in routing, for example adding an effect before input/after output.

### Pitfalls of the current solution

Currently Mixxx supports all audio APIs through PortAudio, which abstracts over
audio APIs for multiple platforms. Features specific to a single API are not
exposed, which leads to poor experience on Linux (for example,
[incorrect naming of JACK ports](https://github.com/mixxxdj/mixxx/issues/5979)).

* There is no hotplug for SoundDevices

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You may also mention the port model vs. the soundcard model.


## Goals

Goals and use cases for the solution as proposed in [How](#how):

* Refactor code related to current audio backends, and allow the selection of
PipeWire among the available backends.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With the latest findings, this can even be a compiler switch or a command line parameter. This releases the user form the decision if they should use Pipewire and probably you form corner cases when switching the API.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WDYM by corner cases, conditional code in CMake files and #ifdef (PIPEWIRE) and #ifdef (PORTAUDIO) macros?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have some doubts that a common iterator over Portaudio and Pipewire is an easy thing, because of the opposite abstraction models, but I might be wrong. The #ifdef solution works probably for all users well, but it is finally your project decision.

* Get feature parity with the current PortAudio backend. Ensure that drift and
jitter correction is happening properly.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
jitter correction is happening properly.
jitter correction of two DAC clocks is happening properly.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pleas also mention smoothing of the waveforms. A precise clock is key for that.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you elaborate, I don't understand WDYM by smoothing of waveforms.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We have quantization by the audio buffer and we have quantization by the display refresh rate. If we would straight forward pass the audio position to the waveforms we see a jitter, quantization noise. In addition we have two different clocks. The DAC clock and the GPU clock.
We have solved the issue by using the time ALSA reports when the sound reaches the DAC. The VisualPlayposition class calculated which sample is proceeded in the DAC when the next waveform frame is displayed. The Waveform position is moved to that place.
This works nicely with ALSA which reports precise timing. But not that perfectly with other APIs. Ther is a sanitary check implemented which falls back to the CPU clock counting samples when the check fails.

There is a similar issue with Ableton link where two DACs on two different devices needs to be synced. @JoergAtGithub has linked that above.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PipeWire has similar API for the time the sample will reach the DAC. That should work with current logic.
I assume this is what

Access to DAC timing info of the soundcards

meant in the idea.

* Hotplug for audio devices on PipeWire
* Synchronize routing UI with changes through external patchbays
* Have a design style that is concise and covers all the essential information.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you plan significant changes.

@pri-yan-shu pri-yan-shu May 19, 2026

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changes about what? The

Have a design style that is concise and covers all the essential information.

was left by mistake from the template, I'll remove it


Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Support external patch bays. (Not like now with Jack where only anyway connected ports are exposed)

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's what I meant by:

Synchronize routing UI with changes through external patchbays

I'll be more explicit.

### Audience

This change affects linux users using PipeWire.

## Non-Goals

* To be decided

## How

* The proposal will be implemented as a PipeWire client which listens for all
node/port/link objects (similar to existing PipeWire patchbays), and creates
SoundDevices accordingly. Since this happens for all source/sink available, not
just soundcard source/sink, we can route any source/sink to Mixxx. This will
work with the current routing UI in Sound Hardware preference page. Same
mechanism will be used to update the routing UI to reflect any changes made by
an external patchbay.

* On Linux systems, PipeWire would show up in the Sound API option in the

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the Sound API option...

I don't like the idea. Portaudio enumerates all devices from all APIs at start up. The "listening" nature of Pipewire does not fit to this approach. So it is probably more straight forward to have a switch above, that decides if its a Portaudio or a Pipewire build. Even a compiler switch will work for me.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I encountered similar issue while introducing libremidi along with PortMidi. PortMidi had a queryDevices() which returned all the devices, and libremidi had the "listening" nature. As a compromise, the initial libremidi events are supressed, they are recieved by calling its queryDevices() (which is part of the enumerator interface), and then onwards any new events trigger respective signals, and further queryDevices() calls give devices discovered till then.

So as a part of the refactor, when the PortAudioEnumerator and PipewireEnumerator are split up, both have the queryDevices(), which is used to get the devices when the Sound API switches, and any new device events are handled appropriately by Pipewire signals.

This is more complex than simply having one API at a time, maybe lets keep this in back of the mind, depending on how much additional complexity we have to incur to support this case.

preference panel, among other audio APIs offered by PortAudio. The existing
soundio code would be refactored into enumerators for different audio backends,
similar to Controller enumerators.

## Action Plan

The tasks to do in order to migrate to the new idea.

* [ ] Implement support for PipeWire backend.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[ ] test the multi soundcard sync of Pipwwire.

* [ ] Add soundcard hotplug support.
* [ ] Modify PipeWire graph from Mixxx UI

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure if this is beneficial work. Can't we just add a button to open the system installed Graph editor?
qpwgraph/Helvum than the user feels at home with the known tool.

It is unlikely that the user opens Mixxx for doing this. The GUI in Mixxx shall be optimized to do the easy Mixxx only tasks. The graphical representation seem to be overdone.

Maybe we can put a bit of business logic on top of it. For automatically suggest mappings.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder who is responsible for rewire the graph after restart.
At one point we have discussed two modes to switch between. The media player mode at home and the DJ mode when connecting the controller soundcard.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be super great if we finally can access the fader in the sound hardware via Mixxx.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

By "Modify PipeWire graph from Mixxx UI", I meant how currently in PortAudio backends, we can set the Mixxx Main/Headphone/Deck 1/2/3/4 outputs and Microphone 1/2/3/4 inputs from the Sound Hardware preference page, that UI is completely sufficient for routing to and from Mixxx. Only case it is lacking is to be able to input from multiple sources, or output to multiple sinks (if we want to address this too, we can add a plus (+) button to add additional source/sink to a single Mixxx input/output).

qpwgraph allows saving and loading patchbays. So if we edit the graph in qpwgraph (or from Mixxx UI, like mentioned above), we can save the patchbay, and qpwgraph sets the connections accordingly. We can include this feature in Mixxx, with above mentioned routing, to be independent of qpwgraph. Is this worth it?.
I do remember the discussion about the two modes, but I cannot recall the specifics or find the discussion, can you explain?

About accessing the analog volume, I still have to read about it, I will add this as TODO.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this worth it?.

IMHO not. When we look at the eco system of different audio application actions, it does not seem to be reasonable that any of these has its own idea of routing and storing the pipe wire graph. And finally may have evrn concurrent settings.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So I checked, it is possible to access soundcard hardware volume. There is a very nifty program pw-volume for reference. One issue is that PipeWire in Pro Audio mode does not manage setting hardware volume, so if we want that we will have to look other way (use ALSA API?).

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In normal mode, its a bit more complex, because even though we set the parameter on the soundcard, we need to mention the route we want to affect (in desktop case speaker or headphone route), so we need to keep track of the current route from the events.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Even if this is a manual choice, it would be a great benefit to be able to adjust the hardware volume from the controller.

* [ ] Update Mixxx UI from external graph changes

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Once the list is complete, you need to define mergable PRs with a testable goal and an estimated time frame.

Loading