[HowTo] Troubleshoot crackling in PipeWire

Difficulty: ★★☆☆☆

This tutorial will help you get rid of crackling/popping issues in PipeWire and PipeWire-Pulse, as well as replace PulseAudio with PipeWire.

Tips:

Click to expand
  • Try using ALSA without PulseAudio or PipeWire and see if you still have issues on ALSA (if you do, it’s unlikely that any setting you set in PipeWire is going to solve the issue) if you are using PipeWire and want to switch to ALSA, the command to stop Pipewire is:

    systemctl --user stop pipewire.socket
    
  • The command to restart PipeWire is:

    systemctl --user restart pipewire pipewire-pulse pipewire-media-session
    
  • PipeWire has it’s own wiki that contains a lot of useful information.

  • To replace PulseAudio with PipeWire on Manjaro run:

    pamac remove manjaro-pulse pulseaudio-equalizer pulseaudio-jack pulseaudio-lirc pulseaudio-rtp && pamac install manjaro-pipewire
    
  • To replace PipeWire with PulseAudio (undo the above):

    pamac remove manjaro-pipewire && pamac install pulseaudio-bluetooth manjaro-pulse
    
  • If you accidentally uninstalled your volume controls for pulse while trying to install PipeWire, just reinstall them after installing PipeWire. I.E. for KDE users it’s:

    pamac install plasma-pa
    
  • Run

    inxi -A
    

    to confirm that you are running PipeWire and not pulse, it should output something like:

    Audio:    Device-1: Intel Cannon Lake PCH cAVS driver: snd_hda_intel 
              Device-2: NVIDIA TU106 High Definition Audio driver: snd_hda_intel 
              Sound Server-1: ALSA v: k5.14.2-1-MANJARO running: yes 
              Sound Server-2: PipeWire v: 0.3.35 running: yes 
    

    With the PipeWire version being whatever version you happen to be running.

  • Run

    pw-top
    

    to see all open audio streams (can be useful to double check if an application is ignoring your settings)

  • QUANT = Quantum = Latency = Buffer Size.
    Quantum divided by clock rate equals latency in seconds
    (E.G. 1024/48000=0.02s or 21ms)

  • Worst case scenario for below settings is setting the system’s minimum latency to ~40ms, this is not good for professional audio, but it is perfectly solid for consumer audio. In most cases though you will only have ~20ms min latency which is a lot better.

  • The default max latency in PipeWire is 170ms (8192/48000), it is probably safe to reduce to 85ms (4096/48000) which is still an acceptable latency for consumer audio, but wait with that until after you solve your initial crackling problem first.

  • For reference, standard audio on Windows, DirectSound normally has around 50-80ms latency. (WASAPI has around 10-30ms latency, ASIO has 1-10ms)

  • You can use pw-metadata to force a system-wide clock rate or quantum setting with:

    pw-metadata -n settings 0 clock.force-rate
    pw-metadata -n settings 0 clock.force-quantum
    

    (where 0 is the id of your sound card, you can see the IDs of all PipeWire detected sound cards by running the command without arguments), this can be quite useful to test different settings without having to restart pipewire.

Short Guide:

A much less detailed version of this guide meant for people who more or less know what they’re doing, but are feeling too lazy to be thorough about troubleshooting the issue.

Click to expand

In pipewire.conf set:

default.clock.allowed-rates = [ 44100 48000 ]    # This is not default because: https://gitlab.freedesktop.org/pipewire/pipewire/-/wikis/Config-PipeWire#setting-global-sample-rate    

in pipewire-pulse.conf set:

pulse.min.req = 1024/48000              # 21ms, see: https://gitlab.freedesktop.org/pipewire/pipewire/-/wikis/Config-PulseAudio#playback-buffering-options

For applications that the above two settings do not solve, use environment variables:

PULSE_LATENCY_MSEC=[INT]              # Example: PULSE_LATENCY_MSEC=128
PIPEWIRE_LATENCY=[QUANT]/[RATE]       # Example: PIPEWIRE_LATENCY=2048/48000

To manually set the buffer size on a per application basis.

Note: PIPEWIRE_LATENCY does not work for pipewire-pulse, use PULSE_LATENCY_MSEC instead.
Note: PULSE_LATENCY_MSEC currently does not work as cleanly as it does in pulseaudio, when using this setting, confirm that the correct latency is being set with pw-top.

Full Guide:

  1. Create the config files for pipewire (If they don’t exist)

    You only need one set of config files. User config files will override system config files for your user account if the user config files exist.

    Create System Config Files:

    sudo mkdir -p /etc/pipewire/media-session.d/ && sudo cp /usr/share/pipewire/*.conf /etc/pipewire/ && sudo cp /usr/share/pipewire/media-session.d/*.conf /etc/pipewire/media-session.d/
    

    Create User Config Files:

    mkdir -p ~/.config/pipewire/media-session.d/ && cp /usr/share/pipewire/*.conf ~/.config/pipewire/ && cp /usr/share/pipewire/media-session.d/*.conf ~/.config/pipewire/media-session.d/
    
  2. Enable sample rate switching

    Some applications need to be able to run at 44.1khz or they will have crackling (common issue for instance for games run through Wine). This is easy to fix.

    • In pipewire.conf change
      #default.clock.allowed-rates = [ 48000 ]
      
      to:
      default.clock.allowed-rates = [ 44100 48000 ]    # This is not default because: https://gitlab.freedesktop.org/pipewire/pipewire/-/wikis/Config-PipeWire#setting-global-sample-rate
      
    • Restart pipewire to apply.
    • Now these applications should be allowed to run at 44.1khz instead of the default 48khz clock rate thus reducing likelihood of issues such as crackling.
  3. Try setting alsa headroom
    If enabling sample rate switching was not enough to solve the issue, try changing the alsa headroom setting next to see if that solves the issue.

    • In alsa-monitor.conf change
      #api.alsa.headroom      = 0
      
      to
      api.alsa.headroom      = 1024    # See: https://gitlab.freedesktop.org/pipewire/pipewire/-/wikis/Config-ALSA#alsa-buffer-properties
      
    • Restart pipewire to apply.
    • If setting headroom to 1024 has an effect but doesn’t entirely solve the issue, try setting it to 2048.
    • If setting headroom to 1024 completely solves the issue, see if lower values work (512, 256, 128, 64, 32) and use the lowest value that works.
  4. Try changing the alsa period size
    If the problem still isn’t resolved, try changing the alsa period size.

    • In alsa-monitor.conf change
      #api.alsa.period-size   = 1024
      #api.alsa.headroom      = 0
      
      to
      # See: https://gitlab.freedesktop.org/pipewire/pipewire/-/wikis/Config-ALSA#alsa-buffer-properties
      api.alsa.period-size   = 256
      api.alsa.headroom      = 1024
      
    • Restart pipewire to apply.
    • If this does not solve your issue, try setting it to different values (512, 128, 64 and maybe 2048).
    • If it does solve your issue, try to find the lowest setting combination that does work.
    • If this does not affect your issue, comment out both settings to reset them to default before continuing.
  5. Set the playback buffer size
    If none of the above solved the issue, you should try setting the audio buffer size/latency.

    When an application has it’s own audio buffer size setting you will want to use that to do this, for example:

    chromium --audio-buffer-size=2048 # Sets latency to about 40ms"
    

    For applications that do not support configuring their audio buffer size, we can use system variables.

    Try setting the latency to about 20ms by running:

    PULSE_LATENCY_MSEC=83 COMMAND # Works for pipewire-pulse (most applications use this!)
    #or
    PIPEWIRE_LATENCY=1024/48000 COMMAND # Works for pipewire, pipewire-alsa & pipewire-jack.
    

    Where COMMAND is the executable for the program you’re having problems with.

    Confirm with pw-top that the latency is correct (QUANT should be between 1024 and 1050)


    If that was not enough, try setting the latency to about 40ms by running:

    PULSE_LATENCY_MSEC=126 COMMAND  # Works for pipewire-pulse (most applications use this!)
    #or
    PIPEWIRE_LATENCY=2048/48000 COMMAND # Works for pipewire, pipewire-alsa & pipewire-jack.
    

    Where COMMAND is the executable for the program you’re having problems with.

    Confirm with pw-top that the latency is correct (QUANT should be between 2048 and 2100)


    The vast majority of applications use pulseaudio, and therefore pipewire-pulse, which means that you will almost always use the PULSE_LATENCY_MSEC variable rather than PIPEWIRE_LATENCY.

    When in doubt, always use pw-top to check the quant values of running audio streams to make sure that the command worked.


    Why am I saying it’s 20ms when PULSE_LATENCY_MSEC is to set it to 86? or that it’s 40ms when set to 128?

    Click to expand

    The reason is that if I look at the application in pw-top and see the QUANT and RATE values and do the math for total latency as mentioned in the tips above, that’s the actual latency the application seems to be getting set to. Remember, this is pipewire, not pulse. It seems that this variable simply behaves differently here, but if I am actually wrong about this, I invite anyone who knows better to inform me about it in the comments below.


    If this solves your issue, then I suggest you just stick to setting the PULSE_LATENCY_MSEC variable as needed for individual applications, and just edit the .desktop file shortcuts used by your DE/Launcher, or create aliases in .bashrc for all offending applications.

  6. Set minimum playback buffer size
    If you would rather have the audio buffer size set systemwide instead of applying it on a per-application basis, in pipewire-pulse.conf change:

    #pulse.min.req = 256/48000              # 5ms
    

    to

    pulse.min.req = 1024/48000              # 21ms, see: https://gitlab.freedesktop.org/pipewire/pipewire/-/wikis/Config-PulseAudio#playback-buffering-options
    

    Restart pipewire to apply.

    I would advise against setting this any higher as it can cause some issues, if there are applications that need 40ms latency, you really should just set those manually instead.

    The above only requests 21ms latency though, applications can still force a lower latency so this is a sort of soft setting for the minimum buffer size. Even then, on my system this setting helped a lot.

    To truly force it (I would advise against this), in pipewire-pulse.conf:

    #pulse.min.quantum      = 256/48000     # 5ms
    

    to

    pulse.min.quantum      = 1024/48000     # 21ms, see: https://gitlab.freedesktop.org/pipewire/pipewire/-/wikis/Config-PulseAudio#scheduling-options
    

    Restart pipewire to apply.


    I very strongly(!!) advise against this, but if you want to set systemwide latency for everything (not just pipewire-pulse), change in pipewire.conf:

    #default.clock.min-quantum   = 32
    

    to

    default.clock.min-quantum   = 1024  # You preferably should not use this setting! See: https://gitlab.freedesktop.org/pipewire/pipewire/-/wikis/Config-PipeWire#setting-buffer-size
    

    Never(!!) set this higher than 1024, stuff will start breaking, some things supposedly can already break when this setting is set to 1024, but I have not personally experienced it (probably only applies to professional applications.)

    Restart pipewire to apply.

    I highly suggest though that instead of doing this, you would rather use the PIPEWIRE_LATENCY variable on a per-application basis instead of facing the risks of using this setting.

If you have any additional tips for this tutorial, please leave them below.

:slightly_smiling_face:

10 Likes