Post

Full Linux Audio Modernization on Zorin OS (PipeWire + Bluetooth A2DP)

Full Linux Audio Modernization on Zorin OS (PipeWire + Bluetooth A2DP)

Modern Ubuntu-based distributions (including Zorin OS 17) ship both PipeWire and PulseAudio, creating a hybrid audio stack.
That stack may work acceptably until you introduce: HDMI displays, Bluetooth devices, GNOME Wayland sessions, and profile switching.
The result can be instability and degraded audio.

This article documents a real-world modernization on Zorin OS where two major issues were resolved:

  • HDMI audio distortion caused by sample-rate instability
  • Bluetooth refusing A2DP connections, producing org.bluez.Error.* failures

Once corrected, the system delivered:

  • 48 kHz stable HDMI
  • PipeWire-only routing
  • WirePlumber as session manager
  • Bluetooth A2DP SBC-XQ high-fidelity
  • Zero distortions, zero reboots

1. Detect whether PulseAudio or PipeWire owns the server

You want the PulseAudio server shim running on PipeWire, not the PulseAudio daemon itself.

1
pactl info | grep "Server Name"

Expected:

1
Server Name: PulseAudio (on PipeWire 0.3.48)

If instead:

1
Server Name: pulseaudio

then the legacy daemon is interfering. Check processes:

1
ps aux | grep -i pulse

2. Disable and mask native PulseAudio

Prevent it from respawning:

1
2
systemctl --user --now disable pulseaudio.service pulseaudio.socket
systemctl --user --now mask pulseaudio.service pulseaudio.socket

Start PipeWire’s PulseAudio layer:

1
systemctl --user start pipewire-pulse.service

Re-check:

1
pactl info | grep "Server Name"

3. Replace pipewire-media-session with WirePlumber

Legacy configurations still ship pipewire-media-session, which is deprecated.

Check state:

1
systemctl --user status wireplumber

If inactive, enable it:

1
2
sudo apt install wireplumber
systemctl --user enable --now wireplumber

Disable the old session manager:

1
systemctl --user status pipewire-media-session.service

It should be masked.


4. Fix HDMI distortion by enforcing 48 kHz

HDMI devices expect 48 kHz audio.
Linux may default to 44.1 kHz, causing glitching, resampling artifacts, and unstable timing.

Create:

1
~/.config/pipewire/pipewire.conf.d/10-force-48k.conf

Contents:

1
2
3
4
5
6
context.properties = {
    default.clock.rate          = 48000
    default.clock.allowed-rates = [ 48000 ]
    default.clock.min-quantum   = 16
    default.clock.quantum       = 1024
}

Restart:

1
2
systemctl --user restart pipewire
systemctl --user restart wireplumber

Confirm:

1
pactl list sinks | grep -E 'Sample'

Expected:

1
s32le 2ch 48000Hz

This eliminated HDMI rattling and static when connecting a TV.


5. Identify Bluetooth failure modes

Typical Bluetooth problems include:

  • Device pairs but never connects
  • org.bluez.Error.Failed br-connection-profile-unavailable
  • No A2DP profiles in PulseAudio
  • Device shows only Serial Port
  • Audio sink never appears
  • HSP/HFP fallback breaks sound quality
  • No pairing agent under Wayland

Example state:

1
2
bluetoothctl connect <MAC>
Failed to connect: org.bluez.Error.Failed br-connection-profile-unavailable

This means the application layer has no A2DP backend.


6. Install PipeWire Bluetooth support

Check packages:

1
apt list --installed | grep libspa

You must have:

1
2
libspa-0.2-bluetooth
libspa-0.2-modules

If missing:

1
sudo apt install libspa-0.2-bluetooth libspa-0.2-modules -y

Restart entire audio and Bluetooth stack:

1
2
3
systemctl --user restart wireplumber
systemctl --user restart pipewire
sudo systemctl restart bluetooth

7. Install Blueman for pairing on Wayland

Wayland GNOME often does not spawn a proper pairing agent.
Blueman fills the gap.

1
sudo apt install blueman

Autostart:

1
2
mkdir -p ~/.config/autostart
cp /etc/xdg/autostart/blueman.desktop ~/.config/autostart/

Start once:

1
blueman-applet &

8. Pair with bluetoothctl when needed

1
2
3
4
5
6
7
bluetoothctl
agent on
default-agent
power on
pair XX:XX:XX:XX:XX:XX
trust XX:XX:XX:XX:XX:XX
connect XX:XX:XX:XX:XX:XX

Now profiles should appear.


9. Validate A2DP profiles

1
pactl list cards | grep -i bluez -A20

Expected:

1
2
3
4
a2dp-sink
a2dp-sink-sbc
a2dp-sink-sbc_xq
headset-head-unit

The highest‑quality SBC is:

1
a2dp-sink-sbc_xq

Set it using Blueman’s Audio Profile UI.


10. Validate the sink and codec

1
pactl list sinks | grep -E 'bluez|Sample'

Expected:

1
2
Sample Specification: s16le 2ch 48000Hz
api.bluez5.codec = "sbc_xq"

This confirms:

  • 48 kHz
  • A2DP mode
  • high-bandwidth SBC-XQ

11. Validate PipeWire timing with pw-top

1
pw-top

Look for:

  • QUANT≈256 or 1024
  • RATE=48000
  • ERR=0

Example:

1
bluez_output.<MAC>  QUANT=256  RATE=48000  ERR=0

That indicates perfect stability.


12. Final Result

After applying these steps:

  • HDMI distortion vanished
  • PulseAudio was removed from the signal path
  • WirePlumber enforced stable sample clocks
  • Bluetooth paired reliably
  • High‑fidelity A2DP SBC‑XQ streamed flawlessly
  • Zero reboots required
  • Audio survived HDMI hot‑plugging

This is what Linux audio should be in 2025.


13. Looking ahead

  • Zorin OS 18 (Ubuntu 24.04 base) ships newer PipeWire stacks (0.3.6x+)
  • Most of these issues disappear automatically
  • SBC‑XQ becomes default on many devices
  • Some platforms begin exposing AAC and LDAC

Conclusion

Linux audio modernization means:

  • PipeWire in control
  • WirePlumber policy active
  • No PulseAudio daemon
  • Forced 48 kHz for HDMI
  • Proper Bluetooth SPA
  • High‑quality A2DP

When configured this way, HDMI and Bluetooth become zero‑maintenance subsystems, fully Wayland‑compatible and stable.

This post is licensed under CC BY 4.0 by the author.