/hsphfpd-prototype

Prototype of Bluetooth HSP/HFP daemon

Primary LanguagePerl

About hsphfpd
=============

hsphfpd is specification with some prototype implementation used for connecting
Bluetooth devices with HSP and HFP profiles on Linux operating system.

These two Bluetooth profiles are used by Bluetooth headphones, headsets or other
equipments and are they only standard way how to transfer sound from microphone
to computer.


Description of problem
======================

HSP (Headset Profile) and HFP (Hands-free Profile) use two separate
bi-directional link connections between local and remote device. First link
is used for transferring AT modem commands and second link for audio data.

Via AT modem commands are transferred more independent features. E.g.:

  - Initialization of HFP connection
  - Requests for establishing second link for audio data
  - Configuration of codec audio parameters
  - Changing volume of audio data
  - Signaling of button press events
  - Reporting of current battery level of both sides of connection
  - Requests for displaying text on remote side (if has display)
  - Usage of voice recognition function
  - Notifications of new arrived SMS
  - Standard Telephony operations (ring / dial / accept / hold / reject)
  - Custom vendor extensions and its own features (e.g. Siri)
  - ...

For parsing, interpreting and generating AT modem commands is needed to
implement modem Telephony stack and its state machine. Because lot of AT modem
commands are state dependent and because only owner of AT modem socket can read
and write AT modem commands, it just means that application which holds AT modem
socket is the only once which can communicate with remote Bluetooth device.

If application wants to receive voice from Bluetooth Headset's microphone
(e.g. audio server) it needs to take HSP / HFP connection, implement audio parts
of AT modem commands and initialize protocol connection. If another application
wants to read Headset's battery level (e.g. power supply software) it is off
luck as AT modem connection is already owned by audio server, it is statefull
and probably initialized without reporting of battery level from Headset as
audio server would not implement AT modem commands for periodic reporting of
battery level. And if another application wants to be informed when Headset
button is pressed (e.g. input layer) it is out of luck too. And also connecting
Telephony modem to process Hands-Free actions is in this design impossible.
Plus different vendors of Bluetooth Headset devices exports via AT modem
commands custom features which are not related to any standard functionality
(like displaying raw text on embedded display).

The only possible way how to get audio functionality together with battery
reporting status and with button press events and also with ability to display
custom text on embedded headset display is to implement all required AT modem
commands in one of these applications (which holds AT modem socket) and then
re-export other functionality to other applications.

But because neither audio server is interested in implementing functions for
embedded displays, neither power supply daemon is interested in implementing
audio routing, encoding, decoding and playing functionality, neither input
layer software is going to process battery and power relayed functionality and
also it is not up to the modem software to register input devices into kernel
and process button press events, the only reasonable solution for this problem
is to provide another software which would own HSP/HFP AT modem connection
for remote Bluetooth devices and would forward commands, signals and requests
to appropriate application. And this software is what hsphfpd.


API specification
=================

See file hsphfpd.txt. It contains DBus API specification for communication
between application and also design of ecosystem.


Installation
============

Prototype hsphfpd daemon is written in Perl and depends on Perl Net::DBus
module used for DBus communication.

Install Perl Net::DBus module via some package manager:

  sudo apt-get install libnet-dbus-perl
  sudo yum install perl-Net-DBus
  sudo zypper in perl-Net-DBus
  sudo pacman -S perl-net-dbus
  sudo cpan Net::DBus

And then copy DBus policy file into DBus system directory:

  sudo cp org.hsphfpd.conf /etc/dbus-1/system.d/


Running prototype
=================

Before trying to use hsphfpd prototye it is needed to stop any software which
may implement Bluetooth HSP or HFP profiles (e.g. pulseaudio, ofono).

To stop ofono just run:

  sudo service ofono stop

For pulseaudio there are already hsphfpd patches available in merge request:

  https://gitlab.freedesktop.org/pulseaudio/pulseaudio/-/merge_requests/288

If you are not using pulseaudio with above hsphfpd patches it is needed to
unload pulseaudio bluetooth modules:

  pactl unload-module module-bluez5-device
  pactl unload-module module-bluez5-discover
  pactl unload-module module-bluetooth-discover

After that it is possible to start hsphfpd prototype daemon implementation:

  sudo ./hsphfpd.pl

hsphfpd communicates via DBus directly with bluez daemon. If bluez daemon is
not running yet, it is needed to start it too.

And that is enough. For connecting HSP / HFP device it can be used any bluez
software (KDE, Gnome, command line, ...).

To see recognized HSP / HFP devices, look at system DBus. Any user in bluetooth
group can list them e.g. via qdbus tool:

  qdbus --system org.hsphfpd

They are exported on object paths /org/hsphfpd/hciX/dev_XX_XX_XX_XX_XX_XX/XXX_XX


Audio connection
================

For receiving audio from microphone or sending audio to speakers, it is needed
to implement Audio agent which would connect to hsphfpd via DBus.

If you are using pulseaudio with hsphfpd patches then pulseaudio already
implements needed Audio agent and therefore you should not need to use
example of Audio agent as described below.

This prototype implementation contains example of Audio agent audio_client.pl.
For every remote connection from hsphfpd it sends remote microphone data to
local speakers and local source of audio sends to remote speakers via external
"pacat" application (part of pulseaudio). Via pavucontrol is possible to control
what is local source of audio. To start this exmaple, just run:

  ./audio_client.pl

hsphfpd automatically accept audio connection from remote Bluetooth device and
pass it to compatible Audio agent. To establish a new audio connection (e.g. if
remote device did not do it yet), use DBus command:

  qdbus --system org.hsphfpd PATH org.hsphfpd.Endpoint.ConnectAudio '' ''

where PATH is DBus object path /org/hsphfpd/hciX/dev_XX_XX_XX_XX_XX_XX/XXX_XX
for particular device. Use qdbus --system org.hsphfpd for listing them.


Telephony connection
====================

All Telephony related AT commands are forwarded to Telephony application which
should implement needed parts of Telephony stack. Telephony agent is then
responsible for all Telephony related commands. If there is no Telephony agent
registered to hsphfpd then hsphfpd simply return errors for these Telephony
related commands (ring / dial / accept / hold / reject). So for normal audio
operations, telephony agent is not required.

Simple example of telephony agent which automatically accepts all incoming
calls is in file telephony_client.pl. To start this example, just run:

  ./telephony_client.pl

Telephony agent can be started or stopped at any time, hsphfd will take care
to properly initialize connection even if agent is started after HFP connection
is already setup.


Button press events
===================

Processing of them is implemented by hsphfpd itself. It registers kernel input
device and notify kernel about pressed button. No other software is required.


Power supply
============

Battery status level and device power source is exported via DBus property.
Power supply software could connect to DBus signals for property changes to
be informed about current state of battery in remote device.

HFP profile also supports notifying remote device about local battery status
level. For this purpose hsphfpd provides writable DBus properties which should
be periodically updated by power supply software.


Other functionality
===================

Most of other functions (like displaying text on embedded display) is exported
via DBus methods directly by hsphfpd. See specification file hsphfpd.txt. It is
expected that these non-standard or custom vendor extensions would be either
implemented by hsphfpd directly or exported via new agents for other software.


Audio features of bluetooth adapter
===================================

To list features of local bluetooth adapter there is tool sco_features.pl. It
prints which commands and codecs are supported by bluetooth adapter. Please
note that not all features supported by adapter are already implemented and
supported by kernel.

To print features of adapter with index 0, call:

  sudo ./sco_features.pl 0