Ubuntu – A2DP on PulseAudio – terrible choppy/skipping audio

bluetoothpulseaudiorealtimesound

I have paired my Bluetooth headset with my Ubuntu 12.04 laptop with a Bluetooth chip inside:

lsusb | grep Bluetooth

Bus 003 Device 003: ID 045e:0745 Microsoft Corp. Nano Transceiver v1.0 for Bluetooth

The device has been paired, and with the help of blueman, I've connected it to PulseAudio as a sink. Audio does come across in A2DP mode, but is terribly choppy and skips to the point of being not much better than nothing.

I read around and saw that there was a fix involving adjusting the nice priority of the PulseAudio server. Since by default, PulseAudio runs on a per-user basis, I added the following to my /etc/security/limits.conf:

*       hard    rtpio   0
*       soft    rtpio   0
@audio  hard    rtpio   20
@audio  soft    rtpio   20
pulse   hard    rtpio   20
pulse   soft    rtpio   20

I then added myself to the audio group to be able to schedule priority for the pulseaudio process. It seems that pulseaudio is now running with a priority of -11:

ps -eo pri,ni,cmd | grep [p]ulse

30 -11 /usr/bin/pulseaudio --start --log-target=syslog

This should mean that PulseAudio is running with a priority of -11, which is good.

However, even after restarting, I still get the terrible choppy audio.

How should I proceed? I'm trying to make this Bluetooth headset I purchased usable.

Note: I've tried pairing this device with an Android tablet right next to my laptop and it works fine, so it's not wireless congestion, it seems to be directly correlated to Linux somehow.

Best Answer

As none of the other answers worked on my system (Ubuntu 18.04 LTS on a 2012 MacBook Air), I found my solution on the german ubuntuusers wiki. English summary of the german instructions:

The choppy output might be caused by the A2DP implementation, and how it buffers sound before encoding it. For me, changing this buffer's size solved the choppy sound problem. You need to perform three steps:

  1. Find necessary info about the bluetooth device (while it is connected!)

    pactl list | grep -Pzo '.*bluez_card(.*\n)*'
    

The output should be something like

    Name: bluez_card.28_11_A5_84_B6_F9
    Driver: module-bluez5-device.c
    ...
    Ports:
    speaker-output: Speaker (priority: 0, latency offset: 0 usec, available)
        Part of profile(s): a2dp_sink, headset_head_unit
    speaker-input: Bluetooth Input (priority: 0, latency offset: 0 usec, not available)
        Part of profile(s): headset_head_unit

We see that the buffers have currently 0 latency. In the next step, you will need the NAME and PORT of your output. In this example, these are bluez_card.28_11_A5_84_B6_F9 and speaker-output, respectively.

  1. Set the buffer size (latency) of your card to a suitable value with this command pattern:

    pactl set-port-latency-offset <NAME> <PORT> <BUFFER_SIZE_MICROSECONDS> 
    

The latency unit of the following command is microseconds, so I'm using a 50 millisecond buffer for my command here:

    pactl set-port-latency-offset bluez_card.28_11_A5_84_B6_F9 speaker-output 50000 
  1. Restart your bluetooth service to apply your change

    sudo service bluetooth restart
    

As there is usually no documentation about this, you may have to experiment with higher or lower buffer values. Many people people posted their working latencies in the comments to this answer. Check them out for guidance on the latency value.