Handsfree calls are important to safely make phone calls during driving. This feature already exist before smartphones came to the mobile market, but unavailable in Linux Mobile distros such as postmarketOS.

What is Bluetooth HFP?

Bluetooth HFP is a Bluetooth specification which allows devices such as headsets, car multimedia systems, etc. to manage phone calls. This specification provides the necessary parts to connect the accept, hangup, reject buttons on your Bluetooth device to your phone. It also provides Bluetooth devices information about the call such as the phone number of an incoming call or the current cellular service status. Moreover, the specification also specifies how audio streams between the Bluetooth device and the phone, but that’s not in scope here since it is already supported.

How do phones and Bluetooth HFP devices communicate?

Bluetooth HFP devices and phones communicate with each other over RFCOMM by exchanging AT commands and responses to control phone calls, exchange information about the network operator, signal strength, phone battery level, service status, etc.

Integrating Bluetooth HFP in PulseAudio with ModemManager

I implemented support for almost the complete Bluetooth HFP 1.8 specification in PulseAudio with ModemManager:

  • Accept call (ATA)
  • Reject call (AT+CHUP)
  • Hang up call (AT+CHUP)
  • Dial number (ATD$number;)
  • Ring indication (RING)
  • Query signal strength, roaming & service status, call status (AT+CIND)
  • Enhanced Error Reporting (AT+CMEE)
  • Configure indicators (AT+BIA)
  • Update HFP if an indicator changes (+CIEV)
  • Enhanced Call reporting (AT+CLIP & +CLIP)
  • Call list (AT+CLCC)
  • DTMF tone generation during call (AT+VTS)
  • Subscriber number reporting (AT+CNUM)
  • Operator name reporting in both numeric & string format (AT+COPS)
  • Fake AT+NREC response: noise reduction is not active at all, but make the HF happy and following the spec by reporting ‘OK’
  • Only reply OK to commands we actually support, as the spec wants it
  • Advertise AG new features through AT+BRSF
  • Restart codec negotiation if the HF asks for it (AT+BCC)
  • Support a bunch of out-of-spec AT commands (3GPP standard) as they are used by car multimedia systems:
    • AT+CGSN: get IMEI
    • AT+CGMR: get modem revision ID
    • AT+CGMI: get modem name
    • AT+CGMM: get modem manufacturer
    • AT+CREG?: get service status

I haven’t implemented call holding and multiparty calls because the Linux Mobile stack such as GNOME Calls and KDE Plasma Dialer doesn’t support it either. Besides these, the following features are also not implemented:

  • Enhanced Voice Recognisation: needs a voice assistant to be running, out-of-scope for ModemManager
  • Memory dialing: needs phonebook access, out-of-scope for ModemManager
  • HF indicator: Enhanced Driver Safety. This indicator is not really documented by the specification, but Android supports it. No idea for what it is actually used.

I already made an upstream MR to merge my changes into PulseAudio: PulseAudio MR !693 and it will be available soon on postmarketOS.


HFP indicators in a car multimedia system indicate the cellular service status, signal strength and phone battery level:

Controlling calls from your headset or car multimedia system is now possible as well:

Demo video on PeerTube