Skip to content

bluetooth: enhanced HFP support in backend-native with ModemManager

🚨 PSA for distros 🚨

This MR is still in its early days, do not ship this to any branch of your distro! I also do not want any social media buzz or whatever. I put in a lot of work into this to get it in an upstreamable shape, so the least you can do as a distro is to be patient and give developers the credit they deserve ;) Toot is out to the general public: Distros & maintainers violating this disclaimer will be called out in public. You have been warned! 🔥

MR STATUS: unreviewed, do not ship to any branch
I will update this description when the status changes regarding this.

Don't Ship Badge
Read more here:

ModemManager integration in native-backend

PulseAudio has 2 backends for Bluetooth HFP: native-backend & ofono-backend. The latter includes audio support, HFP AT commands support, etc. completely bypassing PulseAudio. ModemManager is a similar daemon as oFono, but only handles the modem. Bluetooth HFP is not support, that's up to another daemon such as PulseAudio or PipeWire. This MR adds the necessary glue to allow PulseAudio talk to ModemManager if ModemManager is present, if not, the cellular AT commands report proper ERRORs, so the backend acts still like before.

Supported HFP 1.8 features

Followed the Bluetooth HFP 1.8 spec for implementing the following features:

  • 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

Unsupported HFP 1.8 features

Not supported since the Linux Mobile stack does not support these features yet in the various dialers (ModemManager has the necessary capabilities though):

  • Call holding
  • Call multiparty/conference I marked the code in various places where we can apply changes to implement these features in the future. This MR is already a lot, let's do that in a following up MR.

Other unsupported features are:

  • Enhanced Voice Recognisation: needs some kind of voice assitant
  • Memory dialing: needs phonebook access
  • HF indicator: Enhanced Driver Safety. This indicator is not really documented, but Android supports it. No idea for what it is actually used.

This list is rather small after this MR so we have finally feature-parity with Android/iOS/brick phones 🎉

Testing tools for this MR

  • Your Bluetooth HFP device: not all HFP devices support these features. My car multimedia system is the only one supporting them all. My headset only supports half of them.
    • Pair & connect your HFP device
    • Test each feature of your HFP device
  • nOBEX: provides an HFP client, instructions are explained in detail in their README. You can compare your Android phone in various scenarios with this MR, all AT commands & responses are printed out with nOBEX.
    • Run the as root after enabling --compat in BlueZ
    • Pair & connect your phone (you might need to send some setup commands, see their README)
    • AT commands can be send/received in nOBEX's hfp_client.

MR dependencies

Depends on !631 (merged). The UPower support is included in the list of commits (first 5 commits), since it provides the necessary infrastructure for the AT commands, therefore that MR needs to be merged first. Once merged, this MR will be a few commits smaller.

Open questions for PulseAudio maintainers

  1. ModemManager uses several constants to signal a call status for example. I used some #define statements to define them, but they are also shipped through ModemManager's GLib library. Should we depend on that library or use these lightweight #define statements?
  2. What is still needed to land !631 (merged)? It blocks a lot this MR.
  3. Some HFP devices such as the Sennheiser HD350BT have additional \r\n characters in its RFCOMM responses, breaking AT commands. My car multimedia system does something similar, I see ^M at the end of each AT command from it in PulseAudio logs. Do we need to add some function to clean them? Implemented in v2.

Demo on my HFP headset

  1. Call is received on phone, headset is notified over RFCOMM
  2. Headset button is used to 'answer' the call, triggers sending ATA over RFCOMM
  3. Headset button is used to 'end' the call, triggers sending AT+CHUP over RFCOMM
  4. Call is ended, headset is notified over RFCOMM


Demo on my car multimedia system



Call management

Edited by Dylan Van Assche

Merge request reports