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:
- A2DP (Advanced Audio Distribution Profile): It is mostly used on unidirectional Bluetooth audio system such as wireless Bluetooth speakers or multi-room audio streaming.
- HIP (Human Interface Profile): As the name suggests used for all Bluetooth mice, keyboards, and other input devices.
- FTP (File Transfer Protocol): User for file transfer as the name shows. Good old way file exchange between not-so-smartphones when the cloud was still just a mass of condensed water.
- HSP (Headset Profile) and HFP (Handsfree Profile): Used for communication between a Bluetooth enabled device and a headset.
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 BluEz Bluetooth agent: It is in charge of managing the pairing, trusting, and connection with any device.
- Ofono: Originally developed by Intel and Nokia for their phones, this software package will allow us to handle all telephony related signaling.
- Pulseaudio: While Ofono handles the signaling, once a call is established it is necessary to route all incoming and outgoing audio traffic from our old phones receiver all the way to the smartphone through our Bluetooth connection. Pulseaudio's capabilities to handle HSP Bluetooth profile are relatively newly added and we can say that they are still in continuous improvement. The current stable version of Pulseaudio is version 12, however only version 10 is included on the default Raspbian Stretch repository. Some other tweaks need to be performed to make the latest Pulseaudio compatible with our little Raspberry.
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>
<policy context="default"> <allow send_destination="org.ofono"/> </policy>
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:
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
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.