Close

Setting up the Bluetooth

A project log for An old rotary phone as Bluetooth set

When did the charm of holding a bulky receiver to your ear end? What if we could bring the feel of the old times to our smartphones?

Xabi ZXabi Z 04/25/2019 at 21:097 Comments

Bluetooth allows to communicate between different types of devices and with different purposes. Therefore, several profiles exist for each communication type. The classical and best known ones are:

HSP fits perfectly our needs. It allows us to handle the signaling (dialing, call start/end) between the smartphone and the telephone as well as the audio stream exchange. On top of that, one must make the distinction between the HSP "Server" and the HSP "Client". In our case the Pi will function as client while our smartphone will be the server.

Unfortunately for us, the A2DP profile is the only straightforward out-of-the box implemented profile for the Raspberry Pi so enabling our Pi Zero to work as a HSP will not be such a trivial task.

Three applications take part on the whole Bluetooth routing:

The first two packages can be installed from the standard Raspbian Stretch repository with the following command:

sudo apt-get install pi-bluetooth ofono

A small change needs to be made to the dbus policy of ofono in order to be able to open the audio link properly and communicate with other processes. The file /etc/dbus-1/system.d/ofono.conf needs to be modifies so that the line reading

  <policy context="default">
    <deny send_destination="org.ofono"/>
  </policy>

 reads

  <policy context="default">
    <allow send_destination="org.ofono"/>
  </policy>

Compiling Pulseaudio

On the other hand, the Pulseaudio source requires a small modification and needs to be manually built. It can be fetched from the project's GitHub repository:

git clone git://anongit.freedesktop.org/pulseaudio/pulseaudio

The problem here lies on how Pulseaudio implements the HSP Audio routing. When two Bluetooth enabled devices establish a HSP Audio link, the data is exchanged by means of Synchronous Connection Oriented (SCO) packages. This is a real-time narrow-band protocol without package retransmission suitable for Bluetooth voice exchange. The synchronization between the transmitting and receiving parts is made by sending one SCO package per received SCO package. 

This all works perfectly if both packages have same or very similar size, however Pulseaudio hard codes the SCO package size to 48 bytes, while the controller from the Raspberry Pi negotiates a package size of 60 bytes. This behavior was observed by using the btmon debug tool:

[btmon extract]

Therefore, the packages sent by the Android phone comply with the negotiated length of 60 bytes but the packages sent from the Raspberry Pi have a length of 48 bytes. This causes terrible audio desynchronization once the link is established which ultimately leads to severe underruns and latency issues that can be both heard and seen on the Pulseaudio log.

For this purpose, the Pulseaudio source needs to be changed to account for the negotiated package size of 60 bytes. 

The changes need to be made on the files 

src/modules/bluetooth/backend-native.c

and

src/modules/bluetooth/backend-ofono.c

from the Pulseaudio source. The line that reads

*imtu = 48;

has to be changed to

*imtu = 60;

Once this is done the Pulseaudio module can be compiled by calling

sudo apt-get build-dep pulseaudio
./bootstrap.sh
make
sudo make install
sudo ldconfig

The process of building is not complex but quite time consuming on our slow little Pi, so be sure to grab a coffee  and have enough spare time before starting it. The first command automatically installs all build dependencies for Pulseaudio. Be sure to enable the  developer sources in the /etc/apt/sources.list file by commenting out the line starting with deb-src.

Although not compulsory we can make one change more to the Pulseaudio configuration to limit the Bluetooth profiles to HSP only. By default, Pulseaudio should automatically switch from the A2DP profile HSP on demand. However, this switching can be a source to many problems and anyway we don't intent to use our old phone as a Bluetooth speaker for listening music.

The changes take place in the file /etc/pulse/default.pa 

.ifexists module-bluetooth-discover.so
load-module module-bluetooth-discover headset=ofono
.endif

By forcing the 'headset' to 'ofono' we will guarantee that Pulseaudio will only serve the HSP profile. Now Pulseaudio is installed and ready to work.


Connecting the smartphone

We will use the Bluetooth controller to pair, trust, and connect to our device. The Raspberry Pi Zero W already includes a built in Bluetooth so there is no need for any external adapter, anyway it only has a single USB port already occupied by the USB sound-card.

We will turn on the Bluetooth from our smartphone and make it discoverable. We will use 'bluetoothctl' from the Pi to perform the whole process:

bluetoothctl
power on
scan on

With this we will find the MAC address of our device in the format of XX:XX:XX:XX:XX:XX

We will use this address to identify our device. Next, the pairing, trusting, and connecting process can be performed using

pair XX:XX:XX:XX:XX:XX
trust XX:XX:XX:XX:XX:XX
connect XX:XX:XX:XX:XX:XX

If everything worked properly, our smartphone should be connected to the Pi with a HSP profile, ofono should be able to place and handle calls, and Pulseaudio should handle properly all audio exchange between the devices. We can already test the Bluetooth capabilities of our new device by placing a call using our smartphone.


Discussions

f0m3 wrote 01/17/2021 at 20:38 point

I have a Problem. Bluetooth seems to work, my android phone connects. The soundcard works because i can record and playback sound through the fetap to files. But when i connect it as headset to my android phone the sound "playback" is on my android phone, the fetap seems to only be connected as microphone. Any ideas?

  Are you sure? yes | no

f0m3 wrote 01/19/2021 at 21:38 point

additional information:

at the same time both, mic and speaker of my android phone are still working

  Are you sure? yes | no

f0m3 wrote 01/23/2021 at 12:37 point

Found out that i had to pulseaudio --start after reboot

I did some more stuff but i thing that fixed it!

  Are you sure? yes | no

f0m3 wrote 12/03/2020 at 19:21 point

i had to run bluetoothctl as sudo to prevent "No default controller available"

  Are you sure? yes | no

box brownie wrote 10/01/2020 at 07:58 point

I found mine in /home/pi/pulseaudio/src/default.pa

but I later found that if you build the git clone in /etc with    cd /etc  everything works better you will need sudo to run the git clone in /etc.

also if you in australia like me and your phone numbers start with 0 put "" around them in the yaml file to stop them being changed.

  Are you sure? yes | no

StuartIanNaylor wrote 02/28/2020 at 05:57 point

Does pulseaudio need to be installed first ?
/etc/pulse doesn't exist 

  Are you sure? yes | no

Csoban Kesmarki wrote 07/11/2019 at 15:41 point

Hi,

Thank you for documenting this project exactly the one I was looking for for quite some time.

I started doing the "easy" part without the phone hardware mod: the RPI and software things, however I felt stacked at the end of this step:

I cannot get my audio onto the RPI (Zero W w raspbian) having always a short ofono error: "ofonod[...]: Reject SCO: Agent not registered"

I have forcing the HSP in /etc/pulse/default.pa but still the same error.

Found a suggestion (here: https://www.freedesktop.org/wiki/Software/PulseAudio/Documentation/User/Bluetooth/#index9h3) to add "autodetect_mtu=yes" to module-bluetooth-discover in /etc/pulse/default.pa which helps a bit (now the called numbers shown in the ofonod debug) but still no audio and the same error.

Basically I have 3 questions if you can help:

- Have you experienced something similar during your project?

- I changed the omtu to 60 besides the imtu although you did not mentioned can that be an issue?

- Do you think that the autodetect_mtu can help resolving the pulseaudio vs RPI SCO packet size issue?

Thanks indeed,

CK

  Are you sure? yes | no