temp/pulseaudio: fork for Bluetooth HFP/HSP support

Merged Dylan Van Assche requested to merge pulseaudio-bluetooth-hfp into master

🚨 PSA for distros 🚨

The UPSTREAM MR is still in its early days, do not ship this to any stable branch of your distro! Distros & maintainers violating this disclaimer will be called out in public. You have been warned! 🔥 This may be shipped now to unstable branches such as postmarketOS edge for more feedback from users

UPSTREAM MR STATUS: unreviewed, but tested by pmOS developers, thanks! Can be shipped to unstable branches such as postmarketOS edge
I will update this description when the status changes regarding this.

UPSTREAM MR URL: https://gitlab.freedesktop.org/pulseaudio/pulseaudio/-/merge_requests/693

Don't Ship Badge
Read more here: https://do-not-ship.it/

💡 The more feedback we have for these patches, the faster they can be integrated upstream. Upstream does not have phones available so it is hard to test these patches for them 💡

ModemManager integration in PulseAudio for Bluetooth HFP 1.8 support

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 hfp_client.py 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.

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

HFP indicators


Call management


Tested by

Thanks to anyone who tested this MR! To avoid losing the test results in comments, I collect them here for upstream:

  • @TravMurav: Briefly tested the MR on msm8916 wileyfox-crackling and a bunch of cheap-ish headsets: all three were able to ring on the call, button works to answer and drop the call, the headset that spells the number out did spell it out (in Chinese but I assume it said the right digits :)
  • @TravMurav: Extensively tested the MR in a car and found an edge case where hanging up didn't work. Fixed in v7.
  • @tiol11: Tested this MR extensively in a car, everything works with Phosh. Discovered a bug in KDE Plasma dialer related to this. This MR is not responsible for this, reported upstream.
Edited by Dylan Van Assche