HFP_HF
HFP (Hands-Free Profile) is a Bluetooth hands-free protocol that allows Bluetooth devices to control phone calls on peer Bluetooth devices, such as Bluetooth headsets controlling phone call answering, hanging up, rejecting, voice dialing, etc. Data interaction between the two Bluetooth ends in HFP is communicated through predefined AT commands. HFP defines two roles: Audio Gateway (AG) and Hands-Free component (HF):
Audio Gateway (AG): This device serves as the gateway for audio input/output. Typical gateway devices are mobile phones
Hands-Free component (HF): This device serves as the remote audio input/output mechanism for the audio gateway and can provide several remote control functions. Typical hands-free component devices are car systems and Bluetooth headsets
AT command rules:
One command line can only represent one AT command
< cr > abbreviation for carriage return, equivalent to the enter key, ASCII code is 0x0D
< lf > abbreviation for NL line feed, new line, equivalent to the line feed key, ASCII code is 0x0A
HF -> AG sends AT command format: < AT command >< cr >
AG -> HF sends AT command format: < cr >< lf >result code< cr >< lf >
If the AT command result code sent by AG to HF is a message reply, it must be followed by an OK message, unless the reply is a +CME ERROR message, where the following parameters represent the reason for failure.
This document is mainly based on Sifli SDK, introducing how to use basic functions of HF role. Related files include:
bts2_app_interface
bts2_app_hfp_hf
HFP_HF Initialization
HF initialization function: bt_hfp_hf_init, assigns initial values to HF-related states and flags
HF service startup function: bt_hfp_hf_start_enb, configures AT+BRSF related attributes, users can adjust corresponding feature values according to requirements
AT cmd:
AT+BRSF: HF support features (Bluetooth Retrieve Supported Features)
Format: AT+BRSF=< HF support features >
When establishing connection, HF side sends its supported features to AG side
#define HFP_HF_LOCAL_FEATURES ( HFP_HF_FEAT_ECNR | \
HFP_HF_FEAT_3WAY | \
HFP_HF_FEAT_CLI | \
HFP_HF_FEAT_VREC | \
HFP_HF_FEAT_VOL | \
HFP_HF_FEAT_ECS | \
HFP_HF_FEAT_ECC | \
HFP_HF_FEAT_CODEC | \
HFP_HF_FEAT_ESCO )
/* HFP peer features */
#define HFP_HF_FEAT_ECNR 0x0001 /* Echo cancellation/noise reduction */
#define HFP_HF_FEAT_3WAY 0x0002 /* Call waiting and three-way calling */
#define HFP_HF_FEAT_CLI 0x0004 /* Caller ID presentation capability */
#define HFP_HF_FEAT_VREC 0x0008 /* Voice recognition activation */
#define HFP_HF_FEAT_VOL 0x0010 /* Remote volume control */
#define HFP_HF_FEAT_ECS 0x0020 /* Enhanced Call Status */
#define HFP_HF_FEAT_ECC 0x0040 /* Enhanced Call Control */
#define HFP_HF_FEAT_CODEC 0x0080 /* Codec Negotiation */
#define HFP_HF_FEAT_HF_IND 0x0100 /* HF Indicators */
#define HFP_HF_FEAT_ESCO 0x0200 /* eSCO S4 (and T2) setting supported */
#define HFP_HF_FEAT_ENVR_EXT 0x0400 /*ENHANCED_VOICE_RECOGNITION_ST*/
#define HFP_HF_FEAT_VREC_TEXT 0x0800
/* Proprietary features: using bits after 12 */
/* Pass unknown AT command responses to application */
#define HFP_HF_FEAT_UNAT 0x1000
#define HFP_HF_FEAT_VOIP 0x2000 /* VoIP call */
HFP_HF Device Connection
AG devices and HF devices establishing connection and making calls will roughly go through the following four phases. Next, we will focus on introducing the Service Level Connection and Audio Connection processes according to the Specification.
LMP link: First establish LMP Link, there is no fixed master or slave in HFP connection
RFCOMM Connection: Then establish serial port emulation data link channel for HF to transmit user data to AG (including modem control signals and AT commands), AG parses AT commands and sends corresponding responses to HF through the serial port emulation
Service Level Connection: Service level connection is the foundation for application layer HF <<>> AG control and interaction information.
Service Level Connection establishment
Service Level Connection release
Synchronous Connection/Audio Connection: SCO/eSCO call connection usually refers to voice data connection
Codec Connection
Wide Band Speech Connection
SLC (Service Level Connection) Establishment Process
When LM Link and RFCOMM Connection already exist, user behavior or other internal events that want to use HFP service need to first establish SLC (Service Level Connection). Establishing SLC connection requires the following 5 phases:
Supported features exchange (AT+BRSF)
Codec Negotiation (AT+BAC)
AG Indicators (AT+CIND, AT+CMER, +CIEV, AT+CHLD)
HF Indicators (AT+BIND, AT+BIEV)
End of Service Level Connection
Sifli HFP_HF Connect/Disconnect Device
HF device connection interface:
bts2_app_interface connection interface: bt_interface_conn_ext
bts2_app_hfp_hf connection interface: bt_hfp_hf_start_connecting
HF device disconnection interface:
bts2_app_interface disconnection interface: bt_interface_disc_ext
bts2_app_hfp_hf disconnection interface: bt_hfp_hf_start_disc
HF connection status callback events:
HF connection successful: BT_NOTIFY_HF_PROFILE_CONNECTED
HF connection failed: BT_NOTIFY_HF_PROFILE_DISCONNECTED
Note
Note: The address parameters passed by the two interfaces need to be converted accordingly.
// After calling the API to connect HF role, the HF connection success message is sent to user through notify
// Users need to implement hdl functions to receive notify events, such as: bt_notify_handle
// SLC message: BT_NOTIFY_HF_PROFILE_CONNECTED, users can forward the message to user task for processing.
// BT_NOTIFY_HF_PROFILE_CONNECTED event includes: address information, profile_type, res: 0 (success)
// To disconnect device connection, call bt_hfp_hf_start_disc
// BT_NOTIFY_HF_PROFILE_DISCONNECTED event includes: address information, profile_type, reason
// For specific structure information, refer to API comments
static int bt_notify_handle(uint16_t type, uint16_t event_id, uint8_t *data, uint16_t data_len)
{
int ret = -1;
switch (type)
{
case BT_NOTIFY_HFP_HF:
{
bt_sifli_notify_hfp_hf_event_hdl(event_id, data, data_len);
}
break;
}
return 0;
}
int bt_sifli_notify_hfp_hf_event_hdl(uint16_t event_id, uint8_t *data, uint16_t data_len)
{
switch (event_id)
{
case BT_NOTIFY_HF_PROFILE_CONNECTED:
{
//handle hf connected msg(bt_notify_profile_state_info_t *)
break;
}
case BT_NOTIFY_HF_PROFILE_DISCONNECTED:
{
//handle disconnected msg(bt_notify_profile_state_info_t *)
break;
}
}
return 0;
}
HFP_HF Basic Functionality Usage
Call Audio Establishment
Audio Connection in HFP specification usually refers to SCO/eSCO voice path connection. Before SCO/eSCO, HF (AT+BCC) needs to notify AG to first select codec algorithm.
AT cmd:
AT+BCC: Bluetooth Codec Connection
Format: AT+BCC
HF sends to AG, triggers AG to initiate codec connection process
If AG decides to initiate codec connection process, reply OK; otherwise ERROR. After replying OK, AG side will send +BCS:< codec_id > and HF side replies: AT+BCS=< codec_id >. After that, eSCO link is established
Sifli HFP_HF Connect/Disconnect Call Audio
bts2_app_interface call audio connect/disconnect interface: bt_interface_audio_switch
bts2_app_hfp_hf call audio connect/disconnect interface: bt_hfp_hf_audio_transfer
Prerequisites for successful call audio establishment: phone end call status is not idle; because when call is idle, phone end will reject AT+BCC request to establish SCO.
Call audio encoding includes: CVSD and msbc, interface to control whether msbc codec is enabled: bt_interface_set_wbs_status
After call audio is successfully established, need to call audio_open; after call audio is disconnected or HF is disconnected, need to call audio_close. Related implementation can be found in: hfp_audio_api
// Call audio establishment connection interface bt_interface_audio_switch parameters: type 0:connect audio type 1:disconnect audio
// Call audio connection successful BT_NOTIFY_COMMON_SCO_CONNECTED event: sco type (distinguish HF or AG) status (status)
// For specific structure explanation, please refer to relevant descriptions in interface
static int bt_notify_handle(uint16_t type, uint16_t event_id, uint8_t *data, uint16_t data_len)
{
int ret = -1;
switch (type)
{
case BT_NOTIFY_COMMON:
{
bt_sifli_notify_common_event_hdl(event_id, data, data_len);
}
break;
}
return 0;
}
int bt_sifli_notify_common_event_hdl(uint16_t event_id, uint8_t *data, uint16_t data_len)
{
switch (event_id)
{
case BT_NOTIFY_COMMON_SCO_CONNECTED:
{
//handle hf sco connected msg(bt_notify_device_sco_info_t *)
break;
}
case BT_NOTIFY_COMMON_SCO_DISCONNECTED:
{
//handle sco disconnected msg(bt_notify_device_sco_info_t *)
break;
}
}
return 0;
}
Call Audio Volume Control
AT cmd:
AT+VGM: Gain of Microphone
Format: AT+VGM=< gain >
+VGM: Gain of Microphone
Format: +VGM:< gain >
Adjust MIC volume in audio path, value range 0~15
AT cmd:
AT+VGS: Gain of Speaker
Format: AT+VGS=< gain >
+VGS: Gain of Speaker
Format: +VGS:< gain >
Adjust speaker volume in audio path, value range 0~15
Active volume control interface:
bts2_app_interface speaker volume control interface: bt_interface_set_speaker_volume
bts2_app_hfp_hf speaker volume control interface: bt_hfp_hf_update_spk_vol
bts2_app_hfp_hf microphone volume control interface: bt_hfp_hf_update_mic_vol
Volume setting processing result event: BT_NOTIFY_HF_AT_CMD_CFM with cmd_id (HFP_HF_AT_VGS/HFP_HF_AT_VGM)
Peer device volume control event: BT_NOTIFY_HF_VOLUME_CHANGE
// When call audio exists, to control call audio volume, call bt_interface_set_speaker_volume with volume value
// HF will notify AG of volume value using AT+VGS format
// After AG receives volume value, reply OK if processing successful, reply ERROR if processing failed
// Corresponding user event: BT_NOTIFY_HF_AT_CMD_CFM with cmd_id (HFP_HF_AT_VGS/HFP_HF_AT_VGM)
// For specific structure explanation, please refer to relevant descriptions in interface
static int bt_notify_handle(uint16_t type, uint16_t event_id, uint8_t *data, uint16_t data_len)
{
int ret = -1;
switch (type)
{
case BT_NOTIFY_HFP_HF:
{
bt_sifli_notify_hfp_hf_event_hdl(event_id, data, data_len);
}
break;
}
return 0;
}
int bt_sifli_notify_hfp_hf_event_hdl(uint16_t event_id, uint8_t *data, uint16_t data_len)
{
switch (event_id)
{
case BT_NOTIFY_HF_VOLUME_CHANGE:
{
//handle volume value
break;
}
case BT_NOTIFY_HF_AT_CMD_CFM:
{
//handle at cmd result msg(bt_notify_at_cmd_cfm_t *)
break;
}
}
return 0;
}
// at cmd_id
enum
{
HFP_HF_AT_NONE = 0x00,
HFP_HF_AT_BRSF,
HFP_HF_AT_BAC,
HFP_HF_AT_CIND,
HFP_HF_AT_CIND_STATUS,
HFP_HF_AT_CMER,
HFP_HF_AT_CHLD,
HFP_HF_AT_CHLD_CMD,
HFP_HF_AT_CMEE,
HFP_HF_AT_BIA,
HFP_HF_AT_CLIP,
HFP_HF_AT_CCWA,
HFP_HF_AT_COPS,
HFP_HF_AT_COPS_CMD,
HFP_HF_AT_CLCC,
HFP_HF_AT_BVRA,
HFP_HF_AT_VGS, //speaker volume control cmd_id
HFP_HF_AT_VGM, //microphone volume control cmd_id
HFP_HF_AT_ATD,
HFP_HF_AT_BLDN,
HFP_HF_AT_ATA,
HFP_HF_AT_CHUP,
HFP_HF_AT_BTRH,
HFP_HF_AT_BTRH_MODE,
HFP_HF_AT_VTS,
HFP_HF_AT_BCC,
HFP_HF_AT_BCS,
HFP_HF_AT_CNUM,
HFP_HF_AT_NREC,
HFP_HF_AT_BINP,
HFP_HF_AT_CBC,
HFP_HF_AT_BIND,
HFP_HF_AT_BIEV,
HFP_HF_AT_BATT_UPDATE,
HFP_HS_AT_CKPD,
HFP_AT_EXTERN_AT_CMD
};
Voice Recognition Function
AT cmd:
AT+BVRA: Voice Recognition Activation
Format: AT+BVRA=< status >
status
0 (Disable Voice recognition in the AG)
1 (Enable voice recognition in the AG)
2 (Enable voice recognition in the AG with esco exist)
AT cmd:
+BVRA: Voice Recognition Activation
Format: +BVRA:< status >
status
0 (Voice recognition is disabled in the AG)
1 (Voice recognition is enabled in the AG)
HF initiates voice recognition application activation by sending AT+BVRA command to AG. Voice recognition application is installed in AG. Apart from audio routing, voice recognition activation control and other functions that need Bluetooth functionality, everything else depends on the voice recognition application implementation.
Peer device supports voice recognition function event: BT_NOTIFY_HF_VOICE_RECOG_CAP_UPDATE
Peer device actively uses voice recognition function status sync event: BT_NOTIFY_HF_VOICE_RECOG_STATUS_CHANGE
Active wake up/close voice function interface:
bts2_app_interface voice recognition interface: bt_interface_voice_recog
bts2_app_hfp_hf voice recognition interface: bt_hfp_hf_voice_recog_send
Voice cmd processing result event: BT_NOTIFY_HF_AT_CMD_CFM with cmd_id (HFP_HF_AT_BVRA)
// step1: HF actively wakes up voice recognition by calling bt_interface_voice_recog(1);
// step2: HF sends AT+BVRA=1
// step3: AG receives AT+BVRA=1, sends OK/ERROR after processing
// step4: HF receives AG reply, notify event: BT_NOTIFY_HF_AT_CMD_CFM with cmd_id (HFP_HF_AT_BVRA)
// Close process is similar to open process
// When peer device actively wakes up voice recognition, HF receives notify event: BT_NOTIFY_HF_VOICE_RECOG_STATUS_CHANGE
// For specific structure explanation, please refer to relevant descriptions in interface
static int bt_notify_handle(uint16_t type, uint16_t event_id, uint8_t *data, uint16_t data_len)
{
int ret = -1;
switch (type)
{
case BT_NOTIFY_HFP_HF:
{
bt_sifli_notify_hfp_hf_event_hdl(event_id, data, data_len);
}
break;
}
return 0;
}
int bt_sifli_notify_hfp_hf_event_hdl(uint16_t event_id, uint8_t *data, uint16_t data_len)
{
switch (event_id)
{
case BT_NOTIFY_HF_VOICE_RECOG_CAP_UPDATE:
{
//handle
break;
}
case BT_NOTIFY_HF_VOICE_RECOG_STATUS_CHANGE:
{
//handle
break;
}
case BT_NOTIFY_HF_AT_CMD_CFM:
{
//handle at cmd result msg(bt_notify_at_cmd_cfm_t *)
//cmd_id:HFP_HF_AT_BVRA
break;
}
}
return 0;
}
HFP_HF Call Function Usage Demo
First, during project initialization, register the processing function for receiving notify events
Enter the MAC address of the phone to connect to, wait for connection success message
After receiving connection success, enter the phone number and length for making a call
//register notify event handle function start
// HF side receives AG side AT cmd id processing result: 0 (success) 1 (failure) 2 (timeout, no reply from AG end)
static void bt_sifli_notify_hdl_at_cmd(uint8_t cmd_id, uint8_t res)
{
switch (cmd_id)
{
//(voice recognition cmd processing result)
case HFP_HF_AT_BVRA:
{
break;
}
//(get current call information list processing complete)
case HFP_HF_AT_CLCC:
{
//step5.request phone call information complete then hangup call
bt_interface_handup_call();
break;
}
//(AG side processing make call request result)
case HFP_HF_AT_ATD:
{
//step2.make a call request result
break;
}
//(AG side processing redial call request result)
case HFP_HF_AT_BLDN:
{
break;
}
//(AG side DTMF voice key processing result)
case HFP_HF_AT_VTS:
{
break;
}
//(AG side volume control processing result)
case HFP_HF_AT_VGS:
{
break;
}
//(AG hang up call processing result)
case HFP_HF_AT_CHUP:
{
//step6.hangup call over and recv phone call status change:BT_NOTIFY_HF_INDICATOR_UPDATE
break;
}
default:
break;
}
}
int bt_sifli_notify_hfp_hf_event_hdl(uint16_t event_id, uint8_t *data, uint16_t data_len)
{
switch (event_id)
{
// SLC CONNECTED
case BT_NOTIFY_HF_PROFILE_CONNECTED:
{
bt_notify_profile_state_info_t *profile_info = (bt_notify_profile_state_info_t *)data;
//step1.make a call request
char *phone_number = "10086";
bt_interface_hf_out_going_call(strlen(phone_number),phone_number);
break;
}
//SLC DISCONNECTED
case BT_NOTIFY_HF_PROFILE_DISCONNECTED:
{
bt_notify_profile_state_info_t *profile_info = (bt_notify_profile_state_info_t *)data;
break;
}
// notify whether AG supports voice recognition function
case BT_NOTIFY_HF_VOICE_RECOG_CAP_UPDATE:
{
break;
}
// notify AG voice recognition function status
case BT_NOTIFY_HF_VOICE_RECOG_STATUS_CHANGE:
{
break;
}
// notify local number
case BT_NOTIFY_HF_LOCAL_PHONE_NUMBER:
{
break;
}
// notify all current call information
case BT_NOTIFY_HF_REMOTE_CALL_INFO_IND:
{
bt_notify_clcc_ind_t *clcc_info = (bt_notify_clcc_ind_t *)data;
//step4.recv phone call information
break;
}
// volume change
case BT_NOTIFY_HF_VOLUME_CHANGE:
{
break;
}
// all call status
case BT_NOTIFY_HF_CALL_STATUS_UPDATE:
{
bt_notify_all_call_status *call_status = (bt_notify_all_call_status *)data;
break;
}
// call status change
case BT_NOTIFY_HF_INDICATOR_UPDATE:
{
bt_notify_cind_ind_t *cind_status = (bt_notify_cind_ind_t *)data;
//step3.recv phone call status change and then get call information
bt_interface_get_remote_call_status();
break;
}
case BT_NOTIFY_HF_AT_CMD_CFM:
{
bt_notify_at_cmd_cfm_t *at_cmd_cfm = (bt_notify_at_cmd_cfm_t *) data;
bt_sifli_notify_hdl_at_cmd(at_cmd_cfm->at_cmd_id, at_cmd_cfm->res);
break;
}
default:
return -1;
}
return 0;
}
static int bt_sifli_notify_common_event_hdl(uint16_t event_id, uint8_t *data, uint16_t data_len)
{
switch (event_id)
{
//BT functionality enabled successfully, can be used normally
case BT_NOTIFY_COMMON_BT_STACK_READY:
{
break;
}
//BT shutdown successful
case BT_NOTIFY_COMMON_CLOSE_COMPLETE:
{
break;
}
// ACL connection successful
case BT_NOTIFY_COMMON_ACL_CONNECTED:
{
bt_notify_device_acl_conn_info_t *acl_info = (bt_notify_device_acl_conn_info_t *) data;
//device acl connected
break;
}
// ACL disconnection successful
case BT_NOTIFY_COMMON_ACL_DISCONNECTED:
{
bt_notify_device_base_info_t *device_info = (bt_notify_device_base_info_t *)data;
//device acl disconnected
break;
}
// SCO connection successful
case BT_NOTIFY_COMMON_SCO_CONNECTED:
{
bt_notify_device_sco_info_t *sco_info = (bt_notify_device_sco_info_t *)data;
break;
}
// SCO disconnection successful
case BT_NOTIFY_COMMON_SCO_DISCONNECTED:
{
bt_notify_device_sco_info_t *sco_info = (bt_notify_device_sco_info_t *)data;
break;
}
default:
return -1;
}
return 0;
}
static int bt_notify_handle(uint16_t type, uint16_t event_id, uint8_t *data, uint16_t data_len)
{
int ret = -1;
switch (type)
{
case BT_NOTIFY_COMMON:
{
ret = bt_sifli_notify_common_event_hdl(event_id, data, data_len);
}
break;
case BT_NOTIFY_HFP_HF:
{
bt_sifli_notify_hfp_hf_event_hdl(event_id, data, data_len);
}
break;
default:
break;
}
return 0;
}
int app_bt_notify_init(void)
{
bt_interface_register_bt_event_notify_callback(bt_notify_handle);
return BT_EOK;
}
INIT_ENV_EXPORT(app_bt_notify_init);
//register notify event handle function end
// start connect with phone:001bdcf4b6bd
unsigned char mac[6] = {0x00,0x1b,0xdc,0xf4,0xb6,0xbd}
bt_interface_conn_ext((unsigned char *)(mac), BT_PROFILE_HFP);
//