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>
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
Become a Hackaday.io Member
Create an account to leave a comment. Already have an account? Log In.
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
additional information:
at the same time both, mic and speaker of my android phone are still working
Are you sure? yes | no
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
i had to run bluetoothctl as sudo to prevent "No default controller available"
Are you sure? yes | no
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
Does pulseaudio need to be installed first ?
/etc/pulse doesn't exist
Are you sure? yes | no
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