Skip to content

fix: complete PipeWire dynamic loading and channel mapping - #2

Closed
bot-for-imitoy wants to merge 10 commits into
MorizeroDev:releases/v9.0.2from
bot-for-imitoy:fix/pipewire-review
Closed

bot-for-imitoy wants to merge 10 commits into
MorizeroDev:releases/v9.0.2from
bot-for-imitoy:fix/pipewire-review

Conversation

@bot-for-imitoy

Copy link
Copy Markdown

Fixes two issues found during review of the PipeWire backend:

  • dynamically loads pw_stream_state_as_string, avoiding an unintended link-time dependency on libpipewire
  • preserves selected JUCE channel positions when negotiating the PipeWire stream

Also includes the required raw channel type declaration for the channel-position conversion.

bot-for-imitoy and others added 10 commits September 9, 2026 22:01
Add a new "PipeWire" AudioIODeviceType for Linux, driven by native
libpipewire-0.3. Like the JACK backend, libpipewire is loaded dynamically
at run-time, so no extra library has to be linked into the app, but the
PipeWire development headers are required to compile with JUCE_PIPEWIRE
enabled (which is off by default).

The device type lists the sinks and sources of the PipeWire graph as
separate input/output devices and reads the session manager's "default"
metadata to pick sensible default devices. Opening a device creates a
playback and/or capture stream, negotiates float32 planar audio, and runs
the JUCE callback from a dedicated high-priority thread; full-duplex I/O
is aligned to the playback block, with input data buffered by one block.

This is a plain config flag: JUCE_PIPEWIRE can be set to 1 by any app that
has the libpipewire-0.3-dev headers installed.
PipeWire always delivers string properties (node.name, node.description,
object.path, port channels, the default-device metadata) as UTF-8, but the
backend built juce::String objects from these with the plain 'const char*'
constructor, which treats the data as single-byte ASCII/Latin-1 text. Any
non-ASCII characters in a device name or description (e.g. a localized
device description) were therefore shown as mojibake.

Construct those strings with String::fromUTF8() instead.
The format negotiation events can arrive asynchronously after the streams
are up, so before the first process callback the device currently reported
a sample rate and block size of zero. Fall back to the values requested in
open() so that host code which queries the device straight after opening
sees sensible numbers.
Document the libpipewire-0.3-dev package which is needed to build JUCE
with the PipeWire audio device type enabled, and add it to the full apt
install command.
PipeWire always delivers string properties (node.name, node.description,
object.path, port channels, the default-device metadata) as UTF-8, but the
backend built juce::String objects from these with the plain 'const char*'
constructor, which treats the data as single-byte ASCII/Latin-1 text. Any
non-ASCII characters in a device name or description (e.g. a localized
device description) were therefore shown as mojibake.

Construct those strings with String::fromUTF8() instead.
Document the libpipewire-0.3-dev package which is needed to build JUCE
with the PipeWire audio device type enabled, and add it to the full apt
install command.
- Clamp block sizes to each plane's capacity, honour chunk->offset and
  validate the buffer pointers, so a growing quantum can no longer read
  or write past a buffer.
- Destroy the streams on the loop thread via pw_loop_invoke and drain
  in-flight callbacks before swapping the JUCE callback; the process path
  no longer allocates or locks, because all callback buffers are
  preallocated when the streams are created.
- Report the real routed device by following the graph links, and refresh
  the stream node id once the stream is ready.
- Bound the synchronous registry scan with a timeout and a core error
  handler, and convert pw_time.delay to samples correctly.
- Detect a dead stream or server, notify the host via audioDeviceError and
  audioDeviceStopped, and rebuild the streams when the server returns.
- Follow the session default sink and source when they change.
- Watch the graph from the device type and inform listeners when the
  device list changes, including server loss and recovery.
- Reset the xrun count when playback starts and make the shared state
  (sample rate, block size, error string) thread safe.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants