Skip to content

HFP Audio Gateway

import { Aside } from ‘@astrojs/starlight/components’;

mcbluetooth can act as an HFP Audio Gateway (the “phone” role), allowing you to test Bluetooth headsets and hands-free devices by simulating calls and controlling audio indicators.

HFP (Hands-Free Profile) defines two roles:

RoleDescriptionExample Device
AG (Audio Gateway)The phone side — originates calls, sends ring signalsPhone, Linux (with mcbluetooth)
HF (Hands-Free)The headset side — answers calls, controls volumeHeadset, car kit, ESP32 test device

mcbluetooth implements the AG role, so headsets connect to Linux as if it were a phone.

bt_hfp_ag_enable

This registers a custom HFP AG profile with BlueZ via the ProfileManager1 D-Bus interface. Headsets can now discover and connect to Linux.

When a headset connects, the following happens automatically:

1. HF connects RFCOMM → BlueZ calls NewConnection
2. AT+BRSF exchange → Both sides share feature flags
3. AT+CIND=? / AT+CIND? → Indicator mapping and values
4. AT+CMER=3,0,0,1 → Enable indicator reporting → SLC established
5. AT+BAC / +BCS → Codec negotiation (CVSD or mSBC)

Check the connection status:

bt_hfp_ag_status

Once a headset is connected with SLC established:

bt_hfp_ag_simulate_call address="AA:BB:CC:DD:EE:FF" number="+15551234567"

The headset receives:

  • RING alerts every 3 seconds
  • +CLIP with caller ID information

The headset can:

  • Answer with ATA (call becomes active)
  • Reject with AT+CHUP (call is ended)

From the AG (Linux) side:

bt_hfp_ag_end_call address="AA:BB:CC:DD:EE:FF"

This terminates both ringing and active calls, updating the headset’s indicators.

HFP volume uses a 0-15 scale:

# Set speaker volume
bt_hfp_ag_set_volume address="AA:BB:CC:DD:EE:FF" type="speaker" level=12
# Set microphone gain
bt_hfp_ag_set_volume address="AA:BB:CC:DD:EE:FF" type="microphone" level=10

Simulate phone status changes shown on the headset display:

# Signal strength (0-5)
bt_hfp_ag_set_signal address="AA:BB:CC:DD:EE:FF" level=4
# Battery level (0-5)
bt_hfp_ag_set_battery address="AA:BB:CC:DD:EE:FF" level=3

These send +CIEV indicator updates to the headset.

The AG maintains 7 standard indicators, reported to the HF device:

IndexNameRangeDescription
1service0-1Network service available
2call0-1Active call exists
3callsetup0-30=none, 1=incoming, 2=outgoing, 3=alerting
4callheld0-20=none, 1=held+active, 2=held only
5signal0-5Signal strength
6roam0-1Roaming active
7battchg0-5Battery charge level

The HFP AG tools are designed for end-to-end testing with the mcbluetooth-esp32 test harness, where the ESP32 acts as the HF (headset) device.

# 1. Enable AG on Linux
bt_hfp_ag_enable
# 2. ESP32 connects as HF (from mcbluetooth-esp32)
# SLC auto-negotiated
# 3. Linux simulates incoming call
bt_hfp_ag_simulate_call address="<esp32>" number="5551234567"
# 4. ESP32 answers (sends ATA)
# Call becomes active
# 5. Linux ends call
bt_hfp_ag_end_call address="<esp32>"
# 6. Check status
bt_hfp_ag_status

The AG automatically handles these AT commands from the HF device:

CommandPurpose
AT+BRSFFeature exchange
AT+CINDIndicator mapping/values
AT+CMEREnable indicator reporting
AT+CHLDCall hold/multiparty support
AT+BAC / AT+BCSCodec negotiation
ATAAnswer call
AT+CHUPHang up / reject
ATDOutgoing call (from HF)
AT+VGS / AT+VGMVolume control
AT+CLCCList current calls
AT+COPSOperator name query
AT+CNUMSubscriber number
AT+BVRAVoice recognition
AT+NRECNoise reduction
bt_hfp_ag_disable

This unregisters the profile, disconnecting any active HFP sessions.