weitianhua 6 лет назад
Родитель
Сommit
78cbdfa332
27 измененных файлов с 1684 добавлено и 20 удалено
  1. 4 1
      components/bt/host/bluedroid/bta/hf_ag/bta_ag_act.c
  2. 1 1
      components/bt/host/bluedroid/bta/hf_ag/bta_ag_main.c
  3. 2 0
      components/bt/host/bluedroid/bta/hf_ag/bta_ag_rfc.c
  4. 12 12
      components/bt/host/bluedroid/bta/hf_ag/bta_ag_sco.c
  5. 0 2
      components/bt/host/bluedroid/bta/hf_ag/include/bta_ag_int.h
  6. 6 3
      components/bt/host/bluedroid/bta/include/bta/bta_ag_co.h
  7. 2 1
      components/bt/host/bluedroid/hci/hci_hal_h4.c
  8. 1 0
      components/bt/sdkconfig.rename
  9. 6 0
      examples/bluetooth/bluedroid/classic_bt/hfp_ag/CMakeLists.txt
  10. 9 0
      examples/bluetooth/bluedroid/classic_bt/hfp_ag/Makefile
  11. 282 0
      examples/bluetooth/bluedroid/classic_bt/hfp_ag/README.md
  12. 8 0
      examples/bluetooth/bluedroid/classic_bt/hfp_ag/main/CMakeLists.txt
  13. 168 0
      examples/bluetooth/bluedroid/classic_bt/hfp_ag/main/app_hf_msg_prs.c
  14. 48 0
      examples/bluetooth/bluedroid/classic_bt/hfp_ag/main/app_hf_msg_prs.h
  15. 252 0
      examples/bluetooth/bluedroid/classic_bt/hfp_ag/main/app_hf_msg_set.c
  16. 26 0
      examples/bluetooth/bluedroid/classic_bt/hfp_ag/main/app_hf_msg_set.h
  17. 112 0
      examples/bluetooth/bluedroid/classic_bt/hfp_ag/main/bt_app_core.c
  18. 47 0
      examples/bluetooth/bluedroid/classic_bt/hfp_ag/main/bt_app_core.h
  19. 297 0
      examples/bluetooth/bluedroid/classic_bt/hfp_ag/main/bt_app_hf.c
  20. 27 0
      examples/bluetooth/bluedroid/classic_bt/hfp_ag/main/bt_app_hf.h
  21. 5 0
      examples/bluetooth/bluedroid/classic_bt/hfp_ag/main/component.mk
  22. 108 0
      examples/bluetooth/bluedroid/classic_bt/hfp_ag/main/console_uart.c
  23. 19 0
      examples/bluetooth/bluedroid/classic_bt/hfp_ag/main/console_uart.h
  24. 92 0
      examples/bluetooth/bluedroid/classic_bt/hfp_ag/main/gpio_pcm_config.c
  25. 20 0
      examples/bluetooth/bluedroid/classic_bt/hfp_ag/main/gpio_pcm_config.h
  26. 121 0
      examples/bluetooth/bluedroid/classic_bt/hfp_ag/main/main.c
  27. 9 0
      examples/bluetooth/bluedroid/classic_bt/hfp_ag/sdkconfig.defaults

+ 4 - 1
components/bt/host/bluedroid/bta/hf_ag/bta_ag_act.c

@@ -398,8 +398,9 @@ void bta_ag_rfc_close(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
     bta_sys_conn_close(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr);
     bta_sys_conn_close(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr);
 
 
     /* call close call-out */
     /* call close call-out */
-    // bta_ag_sco_co_close(close.hdr.handle);
+#if (BTM_SCO_HCI_INCLUDED == TRUE)
     bta_ag_sco_co_close();
     bta_ag_sco_co_close();
+#endif
     /* call close cback */
     /* call close cback */
     (*bta_ag_cb.p_cback)(BTA_AG_CLOSE_EVT, (tBTA_AG *) &close);
     (*bta_ag_cb.p_cback)(BTA_AG_CLOSE_EVT, (tBTA_AG *) &close);
 
 
@@ -463,7 +464,9 @@ void bta_ag_rfc_open(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
     bta_ag_at_init(&p_scb->at_cb);
     bta_ag_at_init(&p_scb->at_cb);
 
 
     /* call app open call-out */
     /* call app open call-out */
+#if (BTM_SCO_HCI_INCLUDED == TRUE)
     bta_ag_sco_co_open(bta_ag_scb_to_idx(p_scb), p_scb->air_mode, BTA_HFP_SCO_OUT_PKT_SIZE, bta_ag_svc_id[p_scb->conn_service]);
     bta_ag_sco_co_open(bta_ag_scb_to_idx(p_scb), p_scb->air_mode, BTA_HFP_SCO_OUT_PKT_SIZE, bta_ag_svc_id[p_scb->conn_service]);
+#endif
     bta_sys_conn_open(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr);
     bta_sys_conn_open(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr);
     bta_ag_cback_open(p_scb, NULL, BTA_AG_SUCCESS);
     bta_ag_cback_open(p_scb, NULL, BTA_AG_SUCCESS);
 
 

+ 1 - 1
components/bt/host/bluedroid/bta/hf_ag/bta_ag_main.c

@@ -24,6 +24,7 @@
 
 
 #include <string.h>
 #include <string.h>
 #include <stdlib.h>
 #include <stdlib.h>
+#include "bta_ag_int.h"
 #include "bta/bta_api.h"
 #include "bta/bta_api.h"
 #include "bta/bta_sys.h"
 #include "bta/bta_sys.h"
 #include "bta/bta_ag_api.h"
 #include "bta/bta_ag_api.h"
@@ -32,7 +33,6 @@
 #include "common/bt_defs.h"
 #include "common/bt_defs.h"
 #include "common/bt_trace.h"
 #include "common/bt_trace.h"
 #include "osi/allocator.h"
 #include "osi/allocator.h"
-#include "bta_ag_int.h"
 
 
 #if (BTA_AG_INCLUDED == TRUE)
 #if (BTA_AG_INCLUDED == TRUE)
 /*****************************************************************************
 /*****************************************************************************

+ 2 - 0
components/bt/host/bluedroid/bta/hf_ag/bta_ag_rfc.c

@@ -188,7 +188,9 @@ static int bta_ag_data_cback(UINT16 port_handle, void *p_data, UINT16 len, UINT1
     UNUSED(port_handle);
     UNUSED(port_handle);
 
 
     /* call data call-out directly */
     /* call data call-out directly */
+#if (BTM_SCO_HCI_INCLUDED == TRUE)
     bta_ag_co_tx_write(handle, (UINT8 *) p_data, len);
     bta_ag_co_tx_write(handle, (UINT8 *) p_data, len);
+#endif
     return 0;
     return 0;
 }
 }
 
 

+ 12 - 12
components/bt/host/bluedroid/bta/hf_ag/bta_ag_sco.c

@@ -66,9 +66,7 @@ enum
     BTA_AG_SCO_SHUTDOWN_E,      /* shutdown request */
     BTA_AG_SCO_SHUTDOWN_E,      /* shutdown request */
     BTA_AG_SCO_CONN_OPEN_E,     /* sco open */
     BTA_AG_SCO_CONN_OPEN_E,     /* sco open */
     BTA_AG_SCO_CONN_CLOSE_E,    /* sco closed */
     BTA_AG_SCO_CONN_CLOSE_E,    /* sco closed */
-#if (BTM_SCO_HCI_INCLUDED == TRUE)
     BTA_AG_SCO_CI_DATA_E        /* SCO data ready */
     BTA_AG_SCO_CI_DATA_E        /* SCO data ready */
-#endif
 };
 };
 
 
 #if (BTM_WBS_INCLUDED == TRUE )
 #if (BTM_WBS_INCLUDED == TRUE )
@@ -579,6 +577,7 @@ static void bta_ag_create_sco(tBTA_AG_SCB *p_scb, BOOLEAN is_orig)
         /* tell sys to stop av if any */
         /* tell sys to stop av if any */
         bta_sys_sco_use(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr);
         bta_sys_sco_use(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr);
 
 
+#if (BTM_SCO_HCI_INCLUDED == TRUE)
 #if (BTM_WBS_INCLUDED == TRUE)
 #if (BTM_WBS_INCLUDED == TRUE)
         /* Allow any platform specific pre-SCO set up to take place */
         /* Allow any platform specific pre-SCO set up to take place */
         bta_ag_sco_audio_state(bta_ag_scb_to_idx(p_scb), p_scb->app_id, SCO_STATE_SETUP, esco_codec);
         bta_ag_sco_audio_state(bta_ag_scb_to_idx(p_scb), p_scb->app_id, SCO_STATE_SETUP, esco_codec);
@@ -595,6 +594,7 @@ static void bta_ag_create_sco(tBTA_AG_SCB *p_scb, BOOLEAN is_orig)
         /* Allow any platform specific pre-SCO set up to take place */
         /* Allow any platform specific pre-SCO set up to take place */
         bta_ag_sco_audio_state(bta_ag_scb_to_idx(p_scb), p_scb->app_id, SCO_STATE_SETUP);
         bta_ag_sco_audio_state(bta_ag_scb_to_idx(p_scb), p_scb->app_id, SCO_STATE_SETUP);
 #endif
 #endif
+#endif
 
 
 #if (BTM_SCO_HCI_INCLUDED == TRUE)
 #if (BTM_SCO_HCI_INCLUDED == TRUE)
 #if (BTM_WBS_INCLUDED == TRUE)
 #if (BTM_WBS_INCLUDED == TRUE)
@@ -735,10 +735,7 @@ void bta_ag_codec_negotiate(tBTA_AG_SCB *p_scb)
 *******************************************************************************/
 *******************************************************************************/
 static void bta_ag_sco_event(tBTA_AG_SCB *p_scb, UINT8 event)
 static void bta_ag_sco_event(tBTA_AG_SCB *p_scb, UINT8 event)
 {
 {
-#if (BTM_SCO_HCI_INCLUDED == TRUE)
     tBTA_AG_SCO_CB *p_sco = &bta_ag_cb.sco;
     tBTA_AG_SCO_CB *p_sco = &bta_ag_cb.sco;
-    BT_HDR  *p_buf;
-#endif
 #if (BTM_WBS_INCLUDED == TRUE)
 #if (BTM_WBS_INCLUDED == TRUE)
     tBTA_AG_SCB *p_cn_scb = NULL;   /* For codec negotiation */
     tBTA_AG_SCB *p_cn_scb = NULL;   /* For codec negotiation */
 #endif
 #endif
@@ -748,6 +745,7 @@ static void bta_ag_sco_event(tBTA_AG_SCB *p_scb, UINT8 event)
                         bta_ag_sco_state_str(p_sco->state), event, bta_ag_sco_evt_str(event));
                         bta_ag_sco_state_str(p_sco->state), event, bta_ag_sco_evt_str(event));
 
 
 #if (BTM_SCO_HCI_INCLUDED == TRUE)
 #if (BTM_SCO_HCI_INCLUDED == TRUE)
+    BT_HDR  *p_buf;
     if (event == BTA_AG_SCO_CI_DATA_E)
     if (event == BTA_AG_SCO_CI_DATA_E)
     {
     {
         UINT16 pkt_offset = 1 + HCI_SCO_PREAMBLE_SIZE;
         UINT16 pkt_offset = 1 + HCI_SCO_PREAMBLE_SIZE;
@@ -1512,7 +1510,9 @@ void bta_ag_sco_conn_open(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
 *******************************************************************************/
 *******************************************************************************/
 void bta_ag_sco_conn_close(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
 void bta_ag_sco_conn_close(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
 {
 {
+#if (BTM_SCO_HCI_INCLUDED == TRUE)
     UINT16 handle = bta_ag_scb_to_idx(p_scb);
     UINT16 handle = bta_ag_scb_to_idx(p_scb);
+#endif
     UNUSED(p_data);
     UNUSED(p_data);
 
 
     /* clear current scb */
     /* clear current scb */
@@ -1542,6 +1542,7 @@ void bta_ag_sco_conn_close(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
 #endif
 #endif
     else
     else
     {
     {
+#if (BTM_SCO_HCI_INCLUDED == TRUE)
         sco_state_t sco_state = bta_ag_cb.sco.p_xfer_scb ? SCO_STATE_OFF_TRANSFER : SCO_STATE_OFF;
         sco_state_t sco_state = bta_ag_cb.sco.p_xfer_scb ? SCO_STATE_OFF_TRANSFER : SCO_STATE_OFF;
 #if (BTM_WBS_INCLUDED == TRUE)
 #if (BTM_WBS_INCLUDED == TRUE)
         /* Indicate if the closing of audio is because of transfer */
         /* Indicate if the closing of audio is because of transfer */
@@ -1549,6 +1550,7 @@ void bta_ag_sco_conn_close(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
 #else
 #else
         /* Indicate if the closing of audio is because of transfer */
         /* Indicate if the closing of audio is because of transfer */
         bta_ag_sco_audio_state(handle, p_scb->app_id, sco_state);
         bta_ag_sco_audio_state(handle, p_scb->app_id, sco_state);
+#endif
 #endif
 #endif
         bta_ag_sco_event(p_scb, BTA_AG_SCO_CONN_CLOSE_E);
         bta_ag_sco_event(p_scb, BTA_AG_SCO_CONN_CLOSE_E);
 
 
@@ -1626,17 +1628,15 @@ void bta_ag_sco_conn_rsp(tBTA_AG_SCB *p_scb, tBTM_ESCO_CONN_REQ_EVT_DATA *p_data
         /* tell sys to stop av if any */
         /* tell sys to stop av if any */
         bta_sys_sco_use(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr);
         bta_sys_sco_use(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr);
 
 
-#if (BTM_WBS_INCLUDED == FALSE)
+#if (BTM_SCO_HCI_INCLUDED == TRUE)
+#if (BTM_WBS_INCLUDED == TRUE)
+        /* When HS initiated SCO, it cannot be WBS. */
         /* Allow any platform specific pre-SCO set up to take place */
         /* Allow any platform specific pre-SCO set up to take place */
-        bta_ag_sco_audio_state(bta_ag_scb_to_idx(p_scb), p_scb->app_id, SCO_STATE_SETUP);
+        bta_ag_sco_audio_state(bta_ag_scb_to_idx(p_scb), p_scb->app_id, SCO_STATE_SETUP, BTA_AG_CODEC_CVSD);
 #else
 #else
-        /* When HS initiated SCO, it cannot be WBS. */
         /* Allow any platform specific pre-SCO set up to take place */
         /* Allow any platform specific pre-SCO set up to take place */
-        bta_ag_sco_audio_state(bta_ag_scb_to_idx(p_scb), p_scb->app_id, SCO_STATE_SETUP,
-                              BTA_AG_CODEC_CVSD);
+        bta_ag_sco_audio_state(bta_ag_scb_to_idx(p_scb), p_scb->app_id, SCO_STATE_SETUP);
 #endif
 #endif
-
-#if (BTM_SCO_HCI_INCLUDED == TRUE)
         pcm_sample_rate = BTA_HFP_SCO_SAMP_RATE_8K;
         pcm_sample_rate = BTA_HFP_SCO_SAMP_RATE_8K;
         /* initialize SCO setup, no voice setting for AG, data rate <==> sample rate */
         /* initialize SCO setup, no voice setting for AG, data rate <==> sample rate */
         BTM_ConfigScoPath(bta_ag_sco_co_init(pcm_sample_rate, pcm_sample_rate, &codec_info, p_scb->app_id),
         BTM_ConfigScoPath(bta_ag_sco_co_init(pcm_sample_rate, pcm_sample_rate, &codec_info, p_scb->app_id),

+ 0 - 2
components/bt/host/bluedroid/bta/hf_ag/include/bta_ag_int.h

@@ -110,9 +110,7 @@ enum
     BTA_AG_CI_RX_WRITE_EVT,
     BTA_AG_CI_RX_WRITE_EVT,
     BTA_AG_RING_TOUT_EVT,
     BTA_AG_RING_TOUT_EVT,
     BTA_AG_SVC_TOUT_EVT,
     BTA_AG_SVC_TOUT_EVT,
-    #if (BTM_SCO_HCI_INCLUDED == TRUE )
     BTA_AG_CI_SCO_DATA_EVT,
     BTA_AG_CI_SCO_DATA_EVT,
-    #endif /* (BTM_SCO_HCI_INCLUDED == TRUE ) */    
     BTA_AG_CI_SLC_READY_EVT,
     BTA_AG_CI_SLC_READY_EVT,
     BTA_AG_MAX_EVT,
     BTA_AG_MAX_EVT,
 
 

+ 6 - 3
components/bt/host/bluedroid/bta/include/bta/bta_ag_co.h

@@ -21,13 +21,14 @@
  *  This is the interface file for audio gateway call-out  and call-in functions.
  *  This is the interface file for audio gateway call-out  and call-in functions.
  *
  *
  ******************************************************************************/
  ******************************************************************************/
-#ifndef BTA_AG_CIO_H
-#define BTA_AG_CIO_H
+#ifndef BTA_AG_CO_H
+#define BTA_AG_CO_H
 
 
 #include "bta/bta_ag_api.h"
 #include "bta/bta_ag_api.h"
 #include "hci/hci_audio.h"
 #include "hci/hci_audio.h"
 
 
 #if (BTA_AG_INCLUDED == TRUE)
 #if (BTA_AG_INCLUDED == TRUE)
+#if (BTM_SCO_HCI_INCLUDED == TRUE)
 /*******************************************************************************
 /*******************************************************************************
 **
 **
 ** Function         bta_ag_sco_audio_state
 ** Function         bta_ag_sco_audio_state
@@ -155,6 +156,8 @@ extern void bta_ag_ci_rx_write(UINT16 handle, char *p_data, UINT16 len);
 ******************************************************************************/
 ******************************************************************************/
 extern void bta_ag_ci_slc_ready(UINT16 handle);
 extern void bta_ag_ci_slc_ready(UINT16 handle);
 
 
+#endif /* #if (BTM_SCO_HCI_INCLUDED == TRUE) */
+
 #endif /* #if (BTA_AG_INCLUDED == TRUE) */
 #endif /* #if (BTA_AG_INCLUDED == TRUE) */
 
 
-#endif /* BTA_AG_CIO_H */
+#endif /* BTA_AG_CO_H */

+ 2 - 1
components/bt/host/bluedroid/hci/hci_hal_h4.c

@@ -228,14 +228,15 @@ static void hci_update_adv_report_flow_control(BT_HDR *packet)
         // update adv free number
         // update adv free number
         hci_hal_env.adv_free_num ++;
         hci_hal_env.adv_free_num ++;
         if (esp_vhci_host_check_send_available()){
         if (esp_vhci_host_check_send_available()){
+#if (BLE_INCLUDED == TRUE)
             // send hci cmd
             // send hci cmd
             btsnd_hcic_ble_update_adv_report_flow_control(hci_hal_env.adv_free_num);
             btsnd_hcic_ble_update_adv_report_flow_control(hci_hal_env.adv_free_num);
+#endif
             hci_hal_env.adv_free_num = 0;
             hci_hal_env.adv_free_num = 0;
         } else {
         } else {
             //do nothing
             //do nothing
         }
         }
     }
     }
-
 }
 }
 #endif
 #endif
 
 

+ 1 - 0
components/bt/sdkconfig.rename

@@ -45,6 +45,7 @@ CONFIG_A2DP_ENABLE                                          CONFIG_BT_A2DP_ENABL
 CONFIG_HFP_ENABLE                                           CONFIG_BT_HFP_ENABLE
 CONFIG_HFP_ENABLE                                           CONFIG_BT_HFP_ENABLE
 CONFIG_HFP_ROLE                                             CONFIG_BT_HFP_ROLE
 CONFIG_HFP_ROLE                                             CONFIG_BT_HFP_ROLE
 CONFIG_HFP_CLIENT_ENABLE                                    CONFIG_BT_HFP_CLIENT_ENABLE
 CONFIG_HFP_CLIENT_ENABLE                                    CONFIG_BT_HFP_CLIENT_ENABLE
+CONFIG_HFP_AG_ENABLE                                        CONFIG_BT_HFP_AG_ENABLE
 CONFIG_HFP_AUDIO_DATA_PATH                                  CONFIG_BT_HFP_AUDIO_DATA_PATH
 CONFIG_HFP_AUDIO_DATA_PATH                                  CONFIG_BT_HFP_AUDIO_DATA_PATH
 CONFIG_HFP_AUDIO_DATA_PATH_PCM                              CONFIG_BT_HFP_AUDIO_DATA_PATH_PCM
 CONFIG_HFP_AUDIO_DATA_PATH_PCM                              CONFIG_BT_HFP_AUDIO_DATA_PATH_PCM
 CONFIG_HFP_AUDIO_DATA_PATH_HCI                              CONFIG_BT_HFP_AUDIO_DATA_PATH_HCI
 CONFIG_HFP_AUDIO_DATA_PATH_HCI                              CONFIG_BT_HFP_AUDIO_DATA_PATH_HCI

+ 6 - 0
examples/bluetooth/bluedroid/classic_bt/hfp_ag/CMakeLists.txt

@@ -0,0 +1,6 @@
+# The following lines of boilerplate have to be in your project's
+# CMakeLists in this exact order for cmake to work correctly
+cmake_minimum_required(VERSION 3.5)
+
+include($ENV{IDF_PATH}/tools/cmake/project.cmake)
+project(hfp_ag)

+ 9 - 0
examples/bluetooth/bluedroid/classic_bt/hfp_ag/Makefile

@@ -0,0 +1,9 @@
+#
+# This is a project Makefile. It is assumed the directory this Makefile resides in is a
+# project subdirectory.
+#
+
+PROJECT_NAME := hfp_ag
+
+include $(IDF_PATH)/make/project.mk
+

+ 282 - 0
examples/bluetooth/bluedroid/classic_bt/hfp_ag/README.md

@@ -0,0 +1,282 @@
+# Hands-Free Audio Gateway
+
+This example is to show how to use the APIs of Hands-Free (HF) Audio Gateway (AG) Component and the effects of them with the help of user commands. You can use this example to communicate with a Hands-Free Unit (e.g. a headphone set). This example uses UART as a transportation of user commands and configured GPIO for PCM audio data stream.
+
+## How to use example
+
+### Hardware Required
+
+If possible, example should be able to run on any commonly available ESP32 development board and is supposed to connect to _Hands Free Unit example (hfp_hf)_ in ESP-IDF.
+
+### Configure the project
+
+```
+idf.py menuconfig
+```
+
+- Enable `Classic Bluetooth`,  `Hands Free/Handset` and `Aduio Gateway` under `Component config ---> Bluetooth ---> Bluedroid Options`.
+- When using PCM as the data path and this example configures PCM audio data to GPIO pins. You can link the GPIO pins to a speaker via i2s port. PCM data path does not support mSBC codec but CVSD codec.
+- When using HCI data path, ESP32 support both CVSD and mSBC codec.
+
+### Build and Flash
+
+Build the project and flash it to the board, then run monitor tool to view serial output:
+
+```
+idf.py -p PORT flash monitor
+```
+
+(Replace PORT with the name of the serial port to use.)
+
+(To exit the serial monitor, type ``Ctrl-]``.)
+
+See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.
+
+## Example Output
+
+When you run this example the command table will prints like:
+
+```
+########################################################################
+HFP AG command usage manual
+HFP AG commands begins with "hf" and ends with ";"
+Supported commands are as follows, arguments are embraced with < and >
+
+hf con;                   -- setup connection with peer device
+hf dis;                   -- release connection with peer device
+hf cona;                  -- setup audio connection with peer device
+hf disa;                  -- release connection with peer device
+hf vron;                  -- start voice recognition
+hf vroff;                 -- stop voice recognition
+hf vu <tgt> <vol>;        -- volume update
+     tgt: 0-speaker, 1-microphone
+     vol: volume gain ranges from 0 to 15
+hf ind <call> <ntk> <callsetup> <sig>;       -- unsolicited notify device notification to HF Client
+     call: call status [0,1]
+     callsetup: call setup status [0,3]
+     ntk: network status [0,1]
+     sig: signal strength value from 0~5
+hf ate <rep> <err>;       -- send extended at error code
+     rep: response code from 0 to 7
+     err: error code from 0 to 32
+hf iron;                  -- inband ring tone provided
+hf iroff;                 -- inband ring tone not provided
+hf ac;                    -- Answer Incoming Call from AG
+hf rc;                    -- Reject Incoming Call from AG
+hf d <num>;               -- Dial Number by AG, e.g. hf d 11223344
+hf end;                   -- End up a call by AG
+hf h;                     -- to see the command for HFP AG
+########################################################################
+```
+
+The commands help table will print out in monitor whenever you type `hf h;` or input a command that is not required by the command parse rule.
+
+### Service Level Connection and Disconnection
+
+You can type `hf con;` to establish a service level connection with HF Unit device and log prints like:
+
+```
+E (100147) CNSL: Command [hf dis;]
+disconnect
+W (100427) BT_RFCOMM: port_rfc_closed RFCOMM connection in state 3 closed: Closed (res: 19)
+W (100427) BT_APPL: BTA_HF_CLIENT_SCO_SHUTDOWN_ST: Ignoring event 3
+E (100427) BT_HF: APP HFP event: CONNECTION_STATE_EVT
+E (100437) BT_HF: --connection state disconnected, peer feats 0x0, chld_feats 0x0
+```
+
+**Note: Only after HF service is initiated and a service level connection exists between the HF Unit and AG that other commands are available.**
+
+You can type `hf dis;` to disconnect with the connected HF Unit device, and log prints like:
+
+```
+E (100147) CNSL: Command [hf dis;]
+disconnect
+W (100427) BT_RFCOMM: port_rfc_closed RFCOMM connection in state 3 closed: Closed (res: 19)
+W (100427) BT_APPL: BTA_HF_CLIENT_SCO_SHUTDOWN_ST: Ignoring event 3
+E (100427) BT_HF: APP HFP event: CONNECTION_STATE_EVT
+E (100437) BT_HF: --connection state disconnected, peer feats 0x0, chld_feats 0x0
+```
+
+### Audio Connection and Disconnection
+
+You can type `hf cona;` to establish the audio connection between HF Unit and AG device. Also, you can type `hf disa;` to close the audio data stream.
+
+#### Situations for Audio Connection
+
+- Answer an incoming call
+- Enable voice recognition
+- Dial an outgoing call
+
+#### Situations for Audio Disconnection
+
+- Reject an incoming call
+- Disable the voice recognition
+
+#### Audio Data path
+
+ESP32 supports two type of audio data pth: PCM and HCI.
+
+- PCM : When using PCM audio data stream is "matrixed" to GPIO pins and you should link these GPIO pins to a speaker via i2s port. 
+- HCI : When using HCI audio data stream will act in "loopback" mode. For example, you can hear your own voice when you place a call to a phone connected with a ESP32 development borad.
+
+#### Codec
+
+ESP32 supports both CVSD and mSBC codec. HF Unit and AG device determine which codec to use when establishing a service level connection. The choice of codec also depends on the user's configuration in `menuconfig`. 
+
+Since CVSD is the default codec in HFP, we just show the situation using mSBC :
+
+- If you enable `BT_HFP_WBS_ENABLE` in `menuconfig`, mSBC will be available.
+- If both HF Unit and AG support mSBC and also `BT_HFP_WBS_ENABLE` is enabled, ESP32 chooses mSBC.
+- If you use PCM data path, mSBC is not available.
+
+### Answer or Reject an Incoming Call
+
+#### Answer an Incoming Call
+
+You can type `hf ac;` to answer an incoming call and log prints like:
+
+```
+E (1066280) CNSL: Command [hf ac;]
+Answer Call from AG.
+W (1066280) BT_APPL: BTA_AG_SCO_CODEC_ST: Ignoring event 1
+I (1067200) BT_APP_HF: APP HFP event: BCS_EVT
+I (1067200) BT_APP_HF: --AG choose codec mode: CVSD Only
+E (1067230) BT_BTM: btm_sco_connected, handle 180
+I (1067240) BT_APP_HF: APP HFP event: AUDIO_STATE_EVT
+I (1067240) BT_APP_HF: --Audio State connected
+```
+
+#### Reject an Incoming Call
+
+You can type `hf rc;` to reject an incoming call and log prints like:
+
+```
+E (10040) CNSL: Command [hf rc;]
+Reject Call from AG.
+I (1067240) BT_APP_HF: APP HFP event: AUDIO_STATE_EVT
+I (1067240) BT_APP_HF: --Audio State disconnected
+```
+
+#### End Up a Call
+
+You can type `hf end;` to end up the current ongoing call and log prints like:
+
+```
+E (40390) CNSL: Command [hf end;]
+End Call from AG.
+I (1067240) BT_APP_HF: APP HFP event: AUDIO_STATE_EVT
+I (1067240) BT_APP_HF: --Audio State disconnected
+```
+
+### Dial Number
+
+You can type `hf d <num>;` to dial `<num>` from AG and log prints like:
+
+```
+E (105600) CNSL: Command [hf d 18629485549;]
+Dial number 18629485549
+I (105610) BT_APP_HF: APP HFP event: AUDIO_STATE_EVT
+I (105610) BT_APP_HF: --Audio State connecting
+I (106120) BT_APP_HF: APP HFP event: BCS_EVT
+I (106130) BT_APP_HF: --AG choose codec mode: CVSD Only
+E (106160) BT_BTM: btm_sco_connected, handle 180
+I (106160) BT_APP_HF: APP HFP event: AUDIO_STATE_EVT
+I (106160) BT_APP_HF: --Audio State connected
+
+```
+
+### Volume Control
+
+You can type `hf vu <tgt> <vol>;` to sync volume gain of headset or microphone. The parameter set:
+
+- `<tgt>` : 0 - headset, 1 - microphone.
+- `<vol>` : Integer among 0 - 15.
+
+For example,  `hf vu 0 9;` sync the volume of headset and log on AG side prints `volume update`, on HF Unit side log prints like:
+
+```
+E (17087) BT_HF: APP HFP event: VOLUME_CONTROL_EVT
+E (17087) BT_HF: --volume_target: SPEAKER, volume 9
+
+```
+
+And also,  `hf vu 1 9;` sync the volume gain of microphone and log on HF  Unit side prints like:
+
+```
+E (32087) BT_HF: APP HFP event: VOLUME_CONTROL_EVT
+E (32087) BT_HF: --volume_target: MICROPHONE, volume 9
+
+```
+
+#### Voice Recognition
+
+You can type `hf vron;` to start the voice recognition of AG and type `hf vroff;` to end the voice recognition. Both command will notify the HF Unit the status of voice recognition. For example, type `hf vron;` and log prints like:
+
+```
+E (203128) CNSL: Command [hf vron;]
+Start Voice Recognition.
+I (203138) BT_APP_HF: APP HFP event: AUDIO_STATE_EVT
+I (203138) BT_APP_HF: --Audio State connecting
+I (203148) BT_APP_HF: APP HFP event: AUDIO_STATE_EVT
+I (1014138) BT_APP_HF: --Audio State connected
+
+```
+
+#### Notify Device Notification
+
+When use `hf ind <call> <ntk> <callsetup> <sig>` AG will send some device status to HF Unit. Log on AG will printout like:  `Device Indicator Changed!`  and on HF Unit side will prints like:
+
+```
+E (293641) BT_HF: APP HFP event: CALL_IND_EVT
+E (293641) BT_HF: --Call indicator call in progress
+E (293641) BT_HF: APP HFP event: CALL_SETUP_IND_EVT
+E (293651) BT_HF: --Call setup indicator INCOMING
+E (293651) BT_HF: APP HFP event: SIGNAL_STRENGTH_IND_EVT
+E (293661) BT_HF: -- signal strength: 5
+
+```
+
+**Note: AG only sends changed status to HF Unit.**
+
+#### Send Extended AT Error Code
+
+You can type `hf ate <rep> <err>` to send extended AT error coed to HF Unit. Parameter set:
+
+- `<rep>` : integer among 0 - 7.
+- `<err>` : integer among 0 - 32.
+
+When you type `hf ate 7 7;` log on AG side prints like `Send CME Error.` and on HF Unit side prints like:
+
+```
+E (448146) BT_HF: APP HFP event: AT_RESPONSE
+E (448146) BT_HF: --AT response event, code 7, cme 7
+
+```
+
+#### Inband Ring Tone Enable and Disable
+
+You can type `hf iron;` to enable inband ring tone and type `hf iroff;` to disable inband ring tone. Log on AG side prints like `Device Indicator Changed!` and on HF Unit side prints like:
+
+```
+E (19546) BT_HF: APP HFP event: INBAND_RING_TONE_EVT
+E (19556) BT_HF: --inband ring state Provided
+
+```
+
+## Troubleshooting
+
+- You should type the command in the terminal according to the format described in the command help table. 
+- Not all commands in the table are supported by HF Unit.
+- If you want to use AG to establish a service level connection with HF Unit, you should add the MAC address of HF Unit in `hfp_hf/main/bt_app.c`, for example: `esp_bd_addr_t peer_addr = {0xb4, 0xe6, 0x2d, 0xeb, 0x09, 0x93};`
+- Use `esp_hf_client_register_callback()` and  `esp_hf_client_init();` before  establishing a service level connection.
+
+## Example Breakdown
+
+This example has relatively more source files than other bluetooth examples because _Hands Free Profile_ is somehow complex. But we want to show the functions of _Hands Free Profile_ in a simple way, so we use the _Commands and Effects_ scheme to show the usage of APIs of HFP in ESP-IDF.
+
+- The example will respond to user command through UART console. Please go to `hfp_hf/main/console_uart.c`  for the configuration details.
+- For voice interface, ESP32 has provided PCM input/output signals which can be mapped to GPIO pins, please go to `hfp_hf/main/gpio_pcm_config.c` for the configuration details. 
+- If you want to fix the command table, please refer to `hfp_hf/main/app_hf_msg_set.c`.
+- If you want to fix the command parse rules, please refer to `hfp_hf/main/app_hf_msg_prs.c`.
+- If you want to fix the responses of AG or want to fix the log, please refer to `hfp_hf/main/bt_app_hf.c`.
+- Task configuration part is in `hfp_hf/main/bt_app_core.c`.

+ 8 - 0
examples/bluetooth/bluedroid/classic_bt/hfp_ag/main/CMakeLists.txt

@@ -0,0 +1,8 @@
+idf_component_register(SRCS "app_hf_msg_prs.c"
+                            "app_hf_msg_set.c"
+                            "bt_app_core.c"
+                            "bt_app_hf.c"
+                            "console_uart.c"
+                            "gpio_pcm_config.c"
+                            "main.c"
+                    INCLUDE_DIRS ".")

+ 168 - 0
examples/bluetooth/bluedroid/classic_bt/hfp_ag/main/app_hf_msg_prs.c

@@ -0,0 +1,168 @@
+/*
+   This example code is in the Public Domain (or CC0 licensed, at your option.)
+
+   Unless required by applicable law or agreed to in writing, this
+   software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+   CONDITIONS OF ANY KIND, either express or implied.
+*/
+
+#include <ctype.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <string.h>
+#include <stdlib.h>
+#include "app_hf_msg_prs.h"
+#include "app_hf_msg_set.h"
+
+// according to the design, message header length shall be no less than 2.
+#define HF_MSG_HDR_LEN        (3)
+const static char hf_msg_hdr[HF_MSG_HDR_LEN] = {'h', 'f', ' '};
+
+// according to the design, message header length shall be no less than 2.
+#define HF_MSG_TAIL_LEN       (1)
+const static char hf_msg_tail[HF_MSG_TAIL_LEN] = {';'};
+
+void hf_msg_parser_reset_state(hf_msg_prs_cb_t *prs)
+{
+    prs->state = HF_MSG_PRS_IDLE;
+    prs->cnt = 0;
+    prs->h_idx = 0;
+    prs->t_idx = 0;
+}
+
+void hf_msg_parser_register_callback(hf_msg_prs_cb_t *prs, hf_msg_callback cb)
+{
+    prs->callback = cb;
+}
+
+hf_msg_prs_err_t hf_msg_parse(char c, hf_msg_prs_cb_t *prs)
+{
+    hf_msg_prs_err_t err = HF_MSG_PRS_ERR_IN_PROGRESS;
+    switch (prs->state) 
+    {
+        case HF_MSG_PRS_IDLE: 
+        {
+            if (c == hf_msg_hdr[0]) {
+                prs->state = HF_MSG_PRS_HDR;
+                prs->buf[0] = c;
+                prs->cnt = 1;
+                prs->h_idx = 1;
+            } else {
+                err = HF_MSG_PRS_ERR_HDR_UNDETECTED;
+            }
+        }
+        break;
+        
+        case HF_MSG_PRS_HDR: 
+        {
+            if (c == hf_msg_hdr[prs->h_idx]) {
+                prs->buf[prs->cnt++] = c;
+                if (++(prs->h_idx) == HF_MSG_HDR_LEN) {
+                    prs->state = HF_MSG_PRS_PAYL;
+                    prs->t_idx = 0;
+                }
+            } else {
+                hf_msg_parser_reset_state(prs);
+                err = HF_MSG_PRS_ERR_HDR_SYNC_FAILED;
+            }
+        }
+        break;
+        
+        case HF_MSG_PRS_PAYL: 
+        {
+            prs->buf[prs->cnt++] = c;
+            if (c == hf_msg_tail[prs->t_idx]) {
+                if (++(prs->t_idx) == HF_MSG_TAIL_LEN) {
+                    prs->buf[prs->cnt] = '\0';
+                    prs->callback(prs->buf, prs->cnt);
+                    hf_msg_parser_reset_state(prs);
+                    err = HF_MSG_PRS_ERR_OK;
+                    break;
+                }
+            } else {
+                prs->t_idx = 0;
+            }
+
+            if (prs->cnt >= HF_MSG_LEN_MAX) {
+                hf_msg_parser_reset_state(prs);
+                err = HF_MSG_PRS_ERR_BUF_OVERFLOW;
+            }
+        }
+        break;
+    }
+    return err;
+}
+
+
+void hf_msg_split_args(char *start, char *end, char **argv, int *argn)
+{
+    if (argn == NULL || *argn == 0) {
+        return;
+    }
+
+    memset(argv, 0, (*argn) * sizeof(void *));
+
+    int max_argn = *argn;
+    *argn = 0;
+
+    char *p = start;
+    for (int i = 0; i < max_argn; ++i) {
+        while (isspace((int)*p) && p != end) {
+            ++p;
+        }
+        if (p == end) {
+            return;
+        }
+
+        argv[i] = p++;
+        ++(*argn);
+
+        while (!isspace((int)*p) && p != end) {
+            ++p;
+        }
+
+        if (p == end) {
+            return;
+        } else {
+            *p = '\0';
+            ++p;
+        }
+    }
+}
+
+void hf_msg_args_parser(char *buf, int len)
+{
+    char *argv[HF_MSG_ARGS_MAX];
+    int argn = HF_MSG_ARGS_MAX;
+    char *start = buf + HF_MSG_HDR_LEN;
+    // set the command terminitor to '\0'
+    char *end = buf + len - HF_MSG_TAIL_LEN;
+    *end = '\0';
+
+    hf_msg_split_args(start, end, argv, &argn);
+
+    if (argn == 0) {
+        return;
+    }
+
+    bool cmd_supported = false;
+
+    hf_msg_hdl_t *cmd_tbl = hf_get_cmd_tbl();
+    size_t cmd_tbl_size = hf_get_cmd_tbl_size();
+    for (int i = 0; i < cmd_tbl_size; ++i) {
+        hf_msg_hdl_t *hdl = &cmd_tbl[i];
+        if (strcmp(argv[0], hdl->str) == 0) {
+            if (hdl->handler) {
+                hdl->handler(argn, argv);
+                cmd_supported = true;
+                break;
+            }
+        }
+    }
+    if (!cmd_supported) {
+        printf("unsupported command\n");
+        hf_msg_show_usage();
+    }
+    return;
+}

+ 48 - 0
examples/bluetooth/bluedroid/classic_bt/hfp_ag/main/app_hf_msg_prs.h

@@ -0,0 +1,48 @@
+/*
+   This example code is in the Public Domain (or CC0 licensed, at your option.)
+
+   Unless required by applicable law or agreed to in writing, this
+   software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+   CONDITIONS OF ANY KIND, either express or implied.
+*/
+
+#ifndef __APP_HF_MSG_PRS_H__
+#define __APP_HF_MSG_PRS_H__
+
+typedef enum {
+    HF_MSG_PRS_ERR_OK = 0,          // a complete message is finished
+    HF_MSG_PRS_ERR_IN_PROGRESS,     // message parsing is in progress
+    HF_MSG_PRS_ERR_HDR_UNDETECTED,  // header not detected
+    HF_MSG_PRS_ERR_HDR_SYNC_FAILED, // failed to sync header
+    HF_MSG_PRS_ERR_BUF_OVERFLOW,    // exceeds the buffer size: HF_MSG_LEN_MAX
+} hf_msg_prs_err_t;
+
+typedef enum {
+    HF_MSG_PRS_IDLE = 0,
+    HF_MSG_PRS_HDR,
+    HF_MSG_PRS_PAYL,
+} hf_msg_prs_state_t;
+
+typedef void (*hf_msg_callback)(char *buf, int len);
+
+#define HF_MSG_LEN_MAX        (128)
+
+typedef struct {
+    hf_msg_prs_state_t state;
+    char buf[HF_MSG_LEN_MAX + 1];
+    int cnt;
+    int h_idx;
+    int t_idx;
+    hf_msg_callback callback;
+} hf_msg_prs_cb_t;
+
+void hf_msg_parser_reset_state(hf_msg_prs_cb_t *prs);
+
+void hf_msg_parser_register_callback(hf_msg_prs_cb_t *prs, hf_msg_callback cb);
+
+hf_msg_prs_err_t hf_msg_parse(char c, hf_msg_prs_cb_t *prs);
+
+void hf_msg_show_usage(void);
+
+#endif /* __APP_HF_MSG_PRS_H__*/
+

+ 252 - 0
examples/bluetooth/bluedroid/classic_bt/hfp_ag/main/app_hf_msg_set.c

@@ -0,0 +1,252 @@
+/*
+   This example code is in the Public Domain (or CC0 licensed, at your option.)
+
+   Unless required by applicable law or agreed to in writing, this
+   software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+   CONDITIONS OF ANY KIND, either express or implied.
+*/
+
+#include <stdio.h>
+#include <string.h>
+#include "esp_hf_ag_api.h"
+#include "app_hf_msg_set.h"
+#include "bt_app_hf.h"
+
+void hf_msg_show_usage(void)
+{
+    printf("########################################################################\n");
+    printf("HFP AG command usage manual\n");
+    printf("HFP AG commands begins with \"hf\" and ends with \";\"\n");
+    printf("Supported commands are as follows, arguments are embraced with < and >\n\n");
+    printf("hf con;                   -- setup connection with peer device\n");
+    printf("hf dis;                   -- release connection with peer device\n");
+    printf("hf cona;                  -- setup audio connection with peer device\n");
+    printf("hf disa;                  -- release connection with peer device\n");
+    printf("hf vron;                  -- start voice recognition\n");
+    printf("hf vroff;                 -- stop voice recognition\n");
+    printf("hf vu <tgt> <vol>;        -- volume update\n");
+    printf("     tgt: 0-speaker, 1-microphone\n");
+    printf("     vol: volume gain ranges from 0 to 15\n");
+    printf("hf ind <call> <ntk> <callsetup> <sig>;       -- unsolicited notify device notification to HF Client\n");
+    printf("     call: call status [0,1]\n");
+    printf("     callsetup: call setup status [0,3]\n");
+    printf("     ntk: network status [0,1]\n");
+    printf("     sig: signal strength value from 0~5\n");
+    printf("hf ate <rep> <err>;       -- send extended at error code\n");
+    printf("     rep: response code from 0 to 7\n");
+    printf("     err: error code from 0 to 32\n");
+    printf("hf iron;                  -- inband ring tone provided\n");
+    printf("hf iroff;                 -- inband ring tone not provided\n");
+    printf("hf ac;                    -- Answer Incoming Call from AG\n");
+    printf("hf rc;                    -- Reject Incoming Call from AG\n");
+    printf("hf d <num>;               -- Dial Number by AG, e.g. hf d 11223344\n");
+    printf("hf end;                   -- End up a call by AG\n");
+    printf("hf h;                     -- to see the command for HFP AG\n");
+    printf("########################################################################\n");
+}
+
+#define HF_CMD_HANDLER(cmd)    static void hf_##cmd##_handler(int argn, char **argv)
+
+HF_CMD_HANDLER(help)
+{
+    hf_msg_show_usage();
+}
+
+HF_CMD_HANDLER(conn)
+{
+    printf("Connect.\n");
+    esp_bt_hf_connect(hf_peer_addr);
+}
+
+HF_CMD_HANDLER(disc)
+{
+    printf("Disconnect\n");
+    esp_bt_hf_disconnect(hf_peer_addr);
+}
+
+HF_CMD_HANDLER(conn_audio)
+{
+    printf("Connect Audio\n");
+    esp_bt_hf_connect_audio(hf_peer_addr);
+}
+
+HF_CMD_HANDLER(disc_audio)
+{
+    printf("Disconnect Audio\n");
+    esp_bt_hf_disconnect_audio(hf_peer_addr);
+}
+
+//AT+BVRA
+HF_CMD_HANDLER(vra_on)
+{
+    printf("Start Voice Recognition.\n");
+    esp_bt_hf_vra(hf_peer_addr,1);
+}
+//AT+BVRA
+HF_CMD_HANDLER(vra_off)
+{
+    printf("Stop Voicer Recognition.\n");
+    esp_bt_hf_vra(hf_peer_addr,0);
+}
+
+//AT+VGS or AT+VGM
+HF_CMD_HANDLER(volume_control)
+{
+    if (argn != 3) {
+        printf("Insufficient number of arguments");
+        return;
+    }
+    int target, volume;
+    if (sscanf(argv[1], "%d", &target) != 1 ||
+        (target != ESP_HF_VOLUME_CONTROL_TARGET_SPK &&
+        target != ESP_HF_VOLUME_CONTROL_TARGET_MIC)) {
+        printf("Invalid argument for target %s\n", argv[1]);
+        return;
+    }
+    if (sscanf(argv[2], "%d", &volume) != 1 ||
+            (volume < 0 || volume > 15)) {
+        printf("Invalid argument for volume %s\n", argv[2]);
+        return;
+    }
+    printf("Volume Update\n");
+    esp_bt_hf_volume_control(hf_peer_addr, target, volume);
+}
+
+//+CIEV
+HF_CMD_HANDLER(ind_change)
+{
+    if (argn != 5) {
+        printf("Insufficient number of arguments");
+        return;
+    }
+
+    int call_state, ntk_state, call_setup_state, signal;
+
+    if (sscanf(argv[1], "%d", &call_state) != 1 ||
+        (call_state != ESP_HF_CALL_STATUS_NO_CALLS &&
+        call_state != ESP_HF_CALL_STATUS_CALL_IN_PROGRESS)) {
+        printf("Invalid argument for call state %s\n", argv[1]);
+        return;
+    }
+    if (sscanf(argv[2], "%d", &call_setup_state) != 1 ||
+        (call_setup_state < ESP_HF_CALL_SETUP_STATUS_IDLE || call_setup_state > ESP_HF_CALL_SETUP_STATUS_OUTGOING_ALERTING)) {
+        printf("Invalid argument for callsetup state %s\n", argv[2]);
+        return;
+    }
+    if (sscanf(argv[3], "%d", &ntk_state) != 1 ||
+        (ntk_state != ESP_HF_NETWORK_STATE_NOT_AVAILABLE &&
+        ntk_state != ESP_HF_NETWORK_STATE_AVAILABLE)) {
+        printf("Invalid argument for netwrok state %s\n", argv[3]);
+        return;
+    }
+    if (sscanf(argv[4], "%d", &signal) != 1 ||
+            (signal < 0 || signal > 5)) {
+        printf("Invalid argument for signal %s\n", argv[4]);
+        return;
+    }
+    printf("Device Indicator Changed!\n");
+    esp_bt_hf_indchange_notification(hf_peer_addr, call_state, call_setup_state, ntk_state, signal);
+}
+
+//AT+CMEE
+HF_CMD_HANDLER(cme_err)
+{
+    if (argn != 3) {
+        printf("Insufficient number of arguments");
+        return;
+    }
+
+    int response_code, error_code;
+    if (sscanf(argv[1], "%d", &response_code) != 1 ||
+        (response_code < ESP_HF_AT_RESPONSE_CODE_OK && response_code > ESP_HF_AT_RESPONSE_CODE_CME)) {
+        printf("Invalid argument for response_code %s\n", argv[1]);
+        return;
+    }
+
+    if (sscanf(argv[2], "%d", &error_code) != 1 ||
+            (error_code < ESP_HF_CME_AG_FAILURE || error_code > ESP_HF_CME_NETWORK_NOT_ALLOWED)) {
+        printf("Invalid argument for volume %s\n", argv[2]);
+        return;
+    }
+
+    printf("Send CME Error.\n");
+    esp_bt_hf_cmee_response(hf_peer_addr,response_code,error_code);
+}
+
+//+BSIR:1
+HF_CMD_HANDLER(ir_on)
+{
+    printf("Enable Voicer Recognition.\n");
+    esp_bt_hf_bsir(hf_peer_addr,1);
+}
+
+//+BSIR:0
+HF_CMD_HANDLER(ir_off)
+{
+    printf("Disable Voicer Recognition.\n");
+    esp_bt_hf_bsir(hf_peer_addr,0);
+}
+
+//Answer Call from AG
+HF_CMD_HANDLER(ac)
+{
+    printf("Answer Call from AG.\n");
+    char *number = {"186xxxx5549"};
+    esp_bt_hf_answer_call(hf_peer_addr,1,0,1,1,number,0);
+}
+
+//Reject Call from AG
+HF_CMD_HANDLER(rc)
+{
+    printf("Reject Call from AG.\n");
+    char *number = {"186xxxx5549"};
+    esp_bt_hf_reject_call(hf_peer_addr,0,0,0,0,number,0);
+}
+
+//End Call from AG
+HF_CMD_HANDLER(end)
+{
+    printf("End Call from AG.\n");
+    char *number = {"186xxxx5549"};
+    esp_bt_hf_end_call(hf_peer_addr,0,0,0,0,number,0);
+}
+
+//Dial Call from AG
+HF_CMD_HANDLER(d)
+{
+    if (argn != 2) {
+        printf("Insufficient number of arguments");
+    } else {
+        printf("Dial number %s\n", argv[1]);
+        esp_bt_hf_out_call(hf_peer_addr,1,0,1,2,argv[1],0);
+    }
+}
+
+static hf_msg_hdl_t hf_cmd_tbl[] = {
+    {0,    "h",            hf_help_handler},
+    {5,    "con",          hf_conn_handler},
+    {10,   "dis",          hf_disc_handler},
+    {20,   "cona",         hf_conn_audio_handler},
+    {30,   "disa",         hf_disc_audio_handler},
+    {40,   "vu",           hf_volume_control_handler},
+    {50,   "ind",          hf_ind_change_handler},
+    {60,   "vron",         hf_vra_on_handler},
+    {70,   "vroff",        hf_vra_off_handler},
+    {80,   "ate",          hf_cme_err_handler},
+    {90,   "iron",         hf_ir_on_handler},
+    {100,  "iroff",        hf_ir_off_handler},
+    {110,  "ac",           hf_ac_handler},
+    {120,  "rc",           hf_rc_handler},
+    {130,  "end",          hf_end_handler},
+    {140,  "d",            hf_d_handler},
+};
+
+hf_msg_hdl_t *hf_get_cmd_tbl(void)
+{
+    return hf_cmd_tbl;
+}
+
+size_t hf_get_cmd_tbl_size(void)
+{
+    return sizeof(hf_cmd_tbl) / sizeof(hf_msg_hdl_t);
+}

+ 26 - 0
examples/bluetooth/bluedroid/classic_bt/hfp_ag/main/app_hf_msg_set.h

@@ -0,0 +1,26 @@
+/*
+   This example code is in the Public Domain (or CC0 licensed, at your option.)
+
+   Unless required by applicable law or agreed to in writing, this
+   software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+   CONDITIONS OF ANY KIND, either express or implied.
+*/
+
+#ifndef __APP_HF_MSG_SET_H__
+#define __APP_HF_MSG_SET_H__
+
+#define HF_MSG_ARGS_MAX             (8)
+
+typedef void (* hf_cmd_handler)(int argn, char **argv);
+
+typedef struct {
+    uint16_t opcode;
+    const char *str;
+    hf_cmd_handler handler;
+} hf_msg_hdl_t;
+
+extern hf_msg_hdl_t *hf_get_cmd_tbl(void);
+extern size_t hf_get_cmd_tbl_size(void);
+
+void hf_msg_show_usage(void);
+#endif /* __APP_HF_MSG_SET_H__*/

+ 112 - 0
examples/bluetooth/bluedroid/classic_bt/hfp_ag/main/bt_app_core.c

@@ -0,0 +1,112 @@
+/*
+   This example code is in the Public Domain (or CC0 licensed, at your option.)
+
+   Unless required by applicable law or agreed to in writing, this
+   software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+   CONDITIONS OF ANY KIND, either express or implied.
+*/
+
+#include <stdint.h>
+#include <string.h>
+#include <stdbool.h>
+#include "freertos/xtensa_api.h"
+#include "freertos/FreeRTOSConfig.h"
+#include "freertos/FreeRTOS.h"
+#include "freertos/queue.h"
+#include "freertos/task.h"
+#include "esp_log.h"
+#include "bt_app_core.h"
+
+static void bt_app_task_handler(void *arg);
+static bool bt_app_send_msg(bt_app_msg_t *msg);
+static void bt_app_work_dispatched(bt_app_msg_t *msg);
+
+static xQueueHandle bt_app_task_queue = NULL;
+static xTaskHandle bt_app_task_handle = NULL;
+
+bool bt_app_work_dispatch(bt_app_cb_t p_cback, uint16_t event, void *p_params, int param_len, bt_app_copy_cb_t p_copy_cback)
+{
+    ESP_LOGD(BT_APP_CORE_TAG, "%s event 0x%x, param len %d", __func__, event, param_len);
+
+    bt_app_msg_t msg;
+    memset(&msg, 0, sizeof(bt_app_msg_t));
+
+    msg.sig = BT_APP_SIG_WORK_DISPATCH;
+    msg.event = event;
+    msg.cb = p_cback;
+
+    if (param_len == 0) {
+        return bt_app_send_msg(&msg);
+    } else if (p_params && param_len > 0) {
+        if ((msg.param = malloc(param_len)) != NULL) {
+            memcpy(msg.param, p_params, param_len);
+            /* check if caller has provided a copy callback to do the deep copy */
+            if (p_copy_cback) {
+                p_copy_cback(&msg, msg.param, p_params);
+            }
+            return bt_app_send_msg(&msg);
+        }
+    }
+    return false;
+}
+
+static bool bt_app_send_msg(bt_app_msg_t *msg)
+{
+    if (msg == NULL) {
+        return false;
+    }
+
+    if (xQueueSend(bt_app_task_queue, msg, 10 / portTICK_RATE_MS) != pdTRUE) {
+        ESP_LOGE(BT_APP_CORE_TAG, "%s xQueue send failed", __func__);
+        return false;
+    }
+    return true;
+}
+
+static void bt_app_work_dispatched(bt_app_msg_t *msg)
+{
+    if (msg->cb) {
+        msg->cb(msg->event, msg->param);
+    }
+}
+
+static void bt_app_task_handler(void *arg)
+{
+    bt_app_msg_t msg;
+    for (;;) {
+        if (pdTRUE == xQueueReceive(bt_app_task_queue, &msg, (portTickType)portMAX_DELAY)) {
+            ESP_LOGD(BT_APP_CORE_TAG, "%s, sig 0x%x, 0x%x", __func__, msg.sig, msg.event);
+            switch (msg.sig) {
+            case BT_APP_SIG_WORK_DISPATCH:
+                bt_app_work_dispatched(&msg);
+                break;
+            default:
+                ESP_LOGW(BT_APP_CORE_TAG, "%s, unhandled sig: %d", __func__, msg.sig);
+                break;
+            } // switch (msg.sig)
+
+            if (msg.param) {
+                free(msg.param);
+            }
+        }
+    }
+}
+
+void bt_app_task_start_up(void)
+{
+    bt_app_task_queue = xQueueCreate(10, sizeof(bt_app_msg_t));
+    xTaskCreate(bt_app_task_handler, "BtAppT", 2048, NULL, configMAX_PRIORITIES - 3, &bt_app_task_handle);
+    return;
+}
+
+void bt_app_task_shut_down(void)
+{
+    if (bt_app_task_handle) {
+        vTaskDelete(bt_app_task_handle);
+        bt_app_task_handle = NULL;
+    }
+    if (bt_app_task_queue) {
+        vQueueDelete(bt_app_task_queue);
+        bt_app_task_queue = NULL;
+    }
+}

+ 47 - 0
examples/bluetooth/bluedroid/classic_bt/hfp_ag/main/bt_app_core.h

@@ -0,0 +1,47 @@
+/*
+   This example code is in the Public Domain (or CC0 licensed, at your option.)
+
+   Unless required by applicable law or agreed to in writing, this
+   software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+   CONDITIONS OF ANY KIND, either express or implied.
+*/
+
+#ifndef __BT_APP_CORE_H__
+#define __BT_APP_CORE_H__
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <stdio.h>
+
+#define BT_APP_CORE_TAG                   "BT_APP_CORE"
+
+#define BT_APP_SIG_WORK_DISPATCH          (0x01)
+
+/**
+ * @brief     handler for the dispatched work
+ */
+typedef void (* bt_app_cb_t) (uint16_t event, void *param);
+
+/* message to be sent */
+typedef struct {
+    uint16_t             sig;      /*!< signal to bt_app_task */
+    uint16_t             event;    /*!< message event id */
+    bt_app_cb_t          cb;       /*!< context switch callback */
+    void                 *param;   /*!< parameter area needs to be last */
+} bt_app_msg_t;
+
+/**
+ * @brief     parameter deep-copy function to be customized
+ */
+typedef void (* bt_app_copy_cb_t) (bt_app_msg_t *msg, void *p_dest, void *p_src);
+
+/**
+ * @brief     work dispatcher for the application task
+ */
+bool bt_app_work_dispatch(bt_app_cb_t p_cback, uint16_t event, void *p_params, int param_len, bt_app_copy_cb_t p_copy_cback);
+
+void bt_app_task_start_up(void);
+
+void bt_app_task_shut_down(void);
+
+#endif /* __BT_APP_CORE_H__ */

+ 297 - 0
examples/bluetooth/bluedroid/classic_bt/hfp_ag/main/bt_app_hf.c

@@ -0,0 +1,297 @@
+/*
+   This example code is in the Public Domain (or CC0 licensed, at your option.)
+
+   Unless required by applicable law or agreed to in writing, this
+   software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+   CONDITIONS OF ANY KIND, either express or implied.
+*/
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include "esp_log.h"
+#include "esp_bt_main.h"
+#include "esp_bt_device.h"
+#include "esp_gap_bt_api.h"
+#include "esp_hf_ag_api.h"
+#include "freertos/FreeRTOS.h"
+#include "freertos/task.h"
+#include "freertos/queue.h"
+#include "freertos/semphr.h"
+#include "time.h"
+#include "sys/time.h"
+#include "sdkconfig.h"
+#include "bt_app_core.h"
+#include "bt_app_hf.h"
+
+const char *c_hf_evt_str[] = {
+    "CONNECTION_STATE_EVT",              /*!< SERVICE LEVEL CONNECTION STATE CONTROL */
+    "AUDIO_STATE_EVT",                   /*!< AUDIO CONNECTION STATE CONTROL */
+    "VR_STATE_CHANGE_EVT",               /*!< VOICE RECOGNITION CHANGE */
+    "VOLUME_CONTROL_EVT",                /*!< AUDIO VOLUME CONTROL */
+    "UNKNOW_AT_CMD",                     /*!< UNKNOW AT COMMAND RECIEVED */
+    "CIND_RESPONSE_EVT",                 /*!< CALL & DEVICE INDICATION */
+    "COPS_RESPONSE_EVT",                 /*!< CURRENT OPERATOR EVENT */
+    "CLCC_RESPONSE_EVT",                 /*!< LIST OF CURRENT CALL EVENT */
+    "CNUM_RESPONSE_EVT",                 /*!< SUBSCRIBER INFORTMATION OF CALL EVENT */
+    "DTMF_RESPONSE_EVT",                 /*!< DTMF TRANSFER EVT */
+    "NREC_RESPONSE_EVT",                 /*!< NREC RESPONSE EVT */
+    "ANSWER_INCOMING_EVT",               /*!< ANSWER INCOMING EVT */
+    "REJECT_INCOMING_EVT",               /*!< AREJECT INCOMING EVT */
+    "DIAL_EVT",                          /*!< DIAL INCOMING EVT */
+    "BAC_EVT",                           /*!< CODEC NEGO EVT */
+    "BCS_EVT",                           /*!< CODEC NEGO EVT */
+};
+
+//esp_hf_connection_state_t
+const char *c_connection_state_str[] = {
+    "DISCONNECTED",
+    "CONNECTING",
+    "CONNECTED",
+    "SLC_CONNECTED",
+    "DISCONNECTING",
+};
+
+// esp_hf_audio_state_t
+const char *c_audio_state_str[] = {
+    "disconnected",
+    "connecting",
+    "connected",
+    "connected_msbc",
+};
+
+/// esp_hf_vr_state_t
+const char *c_vr_state_str[] = {
+    "Disabled",
+    "Enabled",
+};
+
+// esp_hf_nrec_t
+const char *c_nrec_status_str[] = {
+    "NREC DISABLE",
+    "NREC ABLE",
+};
+
+// esp_hf_control_target_t
+const char *c_volume_control_target_str[] = {
+    "SPEAKER",
+    "MICROPHONE",
+};
+
+// esp_hf_subscriber_service_type_t
+char *c_operator_name_str[] = {
+    "中国移动",
+    "中国联通",
+    "中国电信",
+};
+
+// esp_hf_subscriber_service_type_t
+char *c_subscriber_service_type_str[] = {
+    "UNKNOWN",
+    "VOICE",
+    "FAX",
+};
+
+// esp_hf_nego_codec_status_t
+const char *c_codec_mode_str[] = {
+    "CVSD Only",
+    "Use CVSD",
+    "Use MSBC",
+};
+
+#if CONFIG_BTDM_CTRL_BR_EDR_SCO_DATA_PATH_HCI
+// Produce a sine audio
+static const int16_t sine_int16[] = {
+     0,    2057,    4107,    6140,    8149,   10126,   12062,   13952,   15786,   17557,
+ 19260,   20886,   22431,   23886,   25247,   26509,   27666,   28714,   29648,   30466,
+ 31163,   31738,   32187,   32509,   32702,   32767,   32702,   32509,   32187,   31738,
+ 31163,   30466,   29648,   28714,   27666,   26509,   25247,   23886,   22431,   20886,
+ 19260,   17557,   15786,   13952,   12062,   10126,    8149,    6140,    4107,    2057,
+     0,   -2057,   -4107,   -6140,   -8149,  -10126,  -12062,  -13952,  -15786,  -17557,
+-19260,  -20886,  -22431,  -23886,  -25247,  -26509,  -27666,  -28714,  -29648,  -30466,
+-31163,  -31738,  -32187,  -32509,  -32702,  -32767,  -32702,  -32509,  -32187,  -31738,
+-31163,  -30466,  -29648,  -28714,  -27666,  -26509,  -25247,  -23886,  -22431,  -20886,
+-19260,  -17557,  -15786,  -13952,  -12062,  -10126,   -8149,   -6140,   -4107,   -2057,
+};
+
+#define TABLE_SIZE_CVSD   100
+static uint32_t bt_app_hf_outgoing_cb(uint8_t *p_buf, uint32_t sz)
+{
+    int sine_phase = esp_random();
+
+    for (int i = 0; i < TABLE_SIZE_CVSD; i++) {
+        p_buf[i * 2]     = sine_int16[sine_phase];
+        p_buf[i * 2 + 1] = sine_int16[sine_phase];
+        ++sine_phase;
+        if (sine_phase >= TABLE_SIZE_CVSD) {
+            sine_phase -= TABLE_SIZE_CVSD;
+        }
+    }
+    return sz;
+}
+ 
+static void bt_app_hf_incoming_cb(const uint8_t *buf, uint32_t sz)
+{
+    // direct to i2s
+    esp_hf_outgoing_data_ready();
+}
+#endif /* #if CONFIG_BTDM_CTRL_BR_EDR_SCO_DATA_PATH_HCI */
+
+void bt_app_hf_cb(esp_hf_cb_event_t event, esp_hf_cb_param_t *param)
+{
+    if (event <= ESP_HF_BCS_RESPONSE_EVT) {
+        ESP_LOGI(BT_HF_TAG, "APP HFP event: %s", c_hf_evt_str[event]);
+    } else {
+        ESP_LOGE(BT_HF_TAG, "APP HFP invalid event %d", event);
+    }
+
+    switch (event) {
+        case ESP_HF_CONNECTION_STATE_EVT:
+        {
+            ESP_LOGI(BT_HF_TAG, "--connection state %s, peer feats 0x%x, chld_feats 0x%x",
+                    c_connection_state_str[param->conn_stat.state],
+                    param->conn_stat.peer_feat,
+                    param->conn_stat.chld_feat);
+            memcpy(hf_peer_addr, param->conn_stat.remote_bda, ESP_BD_ADDR_LEN);
+            if (param->conn_stat.state == ESP_HF_CONNECTION_STATE_CONNECTING) {
+                esp_bt_hf_connect(hf_peer_addr);
+            } else if (param->conn_stat.state == ESP_HF_CONNECTION_STATE_DISCONNECTING) {
+                esp_bt_hf_disconnect(hf_peer_addr);
+            }
+            break;
+        }
+
+        case ESP_HF_AUDIO_STATE_EVT:
+        {
+            ESP_LOGI(BT_HF_TAG, "--Audio State %s", c_audio_state_str[param->audio_stat.state]);
+#if CONFIG_BTDM_CTRL_BR_EDR_SCO_DATA_PATH_HCI
+            if (param->audio_stat.state == ESP_HF_AUDIO_STATE_CONNECTED ||
+                param->audio_stat.state == ESP_HF_AUDIO_STATE_CONNECTED_MSBC) {
+                esp_bt_hf_register_data_callback(bt_app_hf_incoming_cb, bt_app_hf_outgoing_cb);
+            } else if (param->audio_stat.state == ESP_HF_AUDIO_STATE_DISCONNECTED) {
+                ESP_LOGI(BT_HF_TAG, "--ESP AG Audio Connection Disconnected.");
+            }
+#endif /* #if CONFIG_BTDM_CTRL_BR_EDR_SCO_DATA_PATH_HCI */
+            break;
+        }
+
+        case ESP_HF_BVRA_EVT:
+        {
+            ESP_LOGI(BT_HF_TAG, "--Voice Recognition is %s", c_vr_state_str[param->vra_rep.value]);
+            break;
+        }
+
+        case ESP_HF_VOLUME_CONTROL_EVT:
+        {
+            ESP_LOGI(BT_HF_TAG, "--Volume Target: %s, Volume %d", c_volume_control_target_str[param->volume_control.type], param->volume_control.volume);
+            break;
+        }
+
+        case ESP_HF_UNAT_RESPONSE_EVT:
+        {
+            ESP_LOGI(BT_HF_TAG, "--UNKOW AT CMD: %s", param->unat_rep.unat);
+            esp_hf_unat_response(hf_peer_addr, param->unat_rep.unat);
+            break;
+        }
+
+        case ESP_HF_CIND_RESPONSE_EVT:
+        {
+            ESP_LOGI(BT_HF_TAG, "--CIND Start.");
+            esp_hf_call_status_t call_status = 0;
+            esp_hf_call_setup_status_t call_setup_status = 0;
+            esp_hf_network_state_t ntk_state = 1;
+            int signal = 4;
+            esp_hf_roaming_status_t roam = 0;
+            int batt_lev = 3;
+            esp_hf_call_held_status_t call_held_status = 0;
+            esp_bt_hf_cind_response(hf_peer_addr,call_status,call_setup_status,ntk_state,signal,roam,batt_lev,call_held_status);
+            break;
+        }
+
+        case ESP_HF_COPS_RESPONSE_EVT:
+        {
+            const int svc_type = 1;
+            esp_bt_hf_cops_response(hf_peer_addr, c_operator_name_str[svc_type]);
+            break;
+        }
+
+        case ESP_HF_CLCC_RESPONSE_EVT:
+        {
+            int index = 1;
+            //mandatory
+            esp_hf_current_call_direction_t dir = 1;
+            esp_hf_current_call_status_t current_call_status = 0;
+            esp_hf_current_call_mode_t mode = 0;
+            esp_hf_current_call_mpty_type_t mpty = 0;
+            //option
+            char *number = {"186xxxx5549"};
+            esp_hf_call_addr_type_t type = ESP_HF_CALL_ADDR_TYPE_UNKNOWN;
+
+            ESP_LOGI(BT_HF_TAG, "--Calling Line Identification.");
+            esp_bt_hf_clcc_response(hf_peer_addr, index, dir, current_call_status, mode, mpty, number, type);
+            break;
+        }
+
+        case ESP_HF_CNUM_RESPONSE_EVT:
+        {
+            char *number = {"186xxxx5549"};
+            esp_hf_subscriber_service_type_t type = 1;
+            ESP_LOGI(BT_HF_TAG, "--Current Number is %s ,Type is %s.", number, c_subscriber_service_type_str[type]);
+            esp_bt_hf_cnum_response(hf_peer_addr, number,type);
+            break;
+        }
+
+        case ESP_HF_VTS_RESPONSE_EVT:
+        {
+            ESP_LOGI(BT_HF_TAG, "--DTMF code is: %s.", param->vts_rep.code);
+            break;
+        }
+
+        case ESP_HF_NREC_RESPONSE_EVT:
+        {
+            ESP_LOGI(BT_HF_TAG, "--NREC status is: %s.", c_nrec_status_str[param->nrec.state]);
+            break;
+        }
+
+        case ESP_HF_ATA_RESPONSE_EVT:
+        {
+            ESP_LOGI(BT_HF_TAG, "--Asnwer Incoming Call.");
+            char *number = {"186xxxx5549"};
+            esp_bt_hf_answer_call(hf_peer_addr,1,0,1,0,number,0);
+            break;
+        }
+
+        case ESP_HF_CHUP_RESPONSE_EVT:
+        {
+            ESP_LOGI(BT_HF_TAG, "--Reject Incoming Call.");
+            char *number = {"186xxxx5549"};
+            esp_bt_hf_reject_call(hf_peer_addr,0,0,0,0,number,0);
+            break;
+        }
+
+        case ESP_HF_DIAL_EVT:
+        {
+            if (param->out_call.num_or_loc) {
+                //dia_num_or_mem
+                ESP_LOGI(BT_HF_TAG, "--Dial \"%s\".", param->out_call.num_or_loc);
+                esp_bt_hf_out_call(hf_peer_addr,1,0,1,0,param->out_call.num_or_loc,0);
+            } else {
+                //dia_last
+                ESP_LOGI(BT_HF_TAG, "--Dial last number.");
+            }
+            break;
+        }
+
+        // case ESP_HF_BAC_RESPONSE_EVT:
+        case ESP_HF_BCS_RESPONSE_EVT:
+        {
+            ESP_LOGI(BT_HF_TAG, "--AG choose codec mode: %s",c_codec_mode_str[param->codec.mode]);
+            break;
+        }
+
+        default:
+            ESP_LOGI(BT_HF_TAG, "Unsupported HF_AG EVT: %d.", event);
+            break;
+    }
+}

+ 27 - 0
examples/bluetooth/bluedroid/classic_bt/hfp_ag/main/bt_app_hf.h

@@ -0,0 +1,27 @@
+/*
+   This example code is in the Public Domain (or CC0 licensed, at your option.)
+
+   Unless required by applicable law or agreed to in writing, this
+   software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+   CONDITIONS OF ANY KIND, either express or implied.
+*/
+
+#ifndef __BT_APP_HF_H__
+#define __BT_APP_HF_H__
+
+#include <stdint.h>
+#include "esp_hf_ag_api.h"
+#include "esp_bt_defs.h"
+
+esp_bd_addr_t hf_peer_addr; // Declaration of peer device bdaddr
+
+#define BT_HF_TAG               "BT_APP_HF"
+
+/**
+ * @brief     callback function for HF client
+ */
+void bt_app_hf_cb(esp_hf_cb_event_t event, esp_hf_cb_param_t *param);
+
+
+#endif /* __BT_APP_HF_H__*/
+ 

+ 5 - 0
examples/bluetooth/bluedroid/classic_bt/hfp_ag/main/component.mk

@@ -0,0 +1,5 @@
+#
+# "main" pseudo-component makefile.
+#
+# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)
+

+ 108 - 0
examples/bluetooth/bluedroid/classic_bt/hfp_ag/main/console_uart.c

@@ -0,0 +1,108 @@
+/*
+   This example code is in the Public Domain (or CC0 licensed, at your option.)
+
+   Unless required by applicable law or agreed to in writing, this
+   software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+   CONDITIONS OF ANY KIND, either express or implied.
+*/
+
+#include "driver/uart.h"
+#include "freertos/xtensa_api.h"
+#include "freertos/FreeRTOS.h"
+#include "freertos/task.h"
+#include "freertos/queue.h"
+#include "esp_log.h"
+#include "console_uart.h"
+#include "app_hf_msg_prs.h"
+
+#define CONSOLE_UART_NUM    UART_NUM_0
+
+static QueueHandle_t uart_queue;
+static hf_msg_prs_cb_t hf_msg_parser;
+
+static const uart_config_t uart_cfg = {
+    .baud_rate = 115200,   //1.5M
+    .data_bits = UART_DATA_8_BITS,
+    .parity = UART_PARITY_DISABLE,
+    .stop_bits = UART_STOP_BITS_1,
+    .flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
+    .rx_flow_ctrl_thresh = 127,
+};
+
+extern void hf_msg_args_parser(char *buf, int len);
+
+void hf_msg_handler(char *buf, int len)
+{
+    ESP_LOGE(TAG_CNSL, "Command [%s]", buf);
+    hf_msg_args_parser(buf, len);
+}
+
+static void console_uart_task(void *pvParameters)
+{
+    int len;
+    uart_event_t event;
+    hf_msg_prs_cb_t *parser = &hf_msg_parser;
+    hf_msg_parser_reset_state(parser);
+    hf_msg_parser_register_callback(parser, hf_msg_handler);
+    hf_msg_show_usage();
+#define TMP_BUF_LEN 128
+    uint8_t tmp_buf[TMP_BUF_LEN] = {0};
+
+    for (;;) {
+        //Waiting for UART event.
+        if (xQueueReceive(uart_queue, (void * )&event, (portTickType)portMAX_DELAY)) {
+            switch (event.type) {
+            //Event of UART receving data
+            case UART_DATA: {
+                len = uart_read_bytes(CONSOLE_UART_NUM, tmp_buf, TMP_BUF_LEN, 0);
+                for (int i = 0; i < len; i++) {
+                    hf_msg_parse(tmp_buf[i], parser);
+                }
+                break;
+            }
+            //Event of HW FIFO overflow detected
+            case UART_FIFO_OVF:
+                ESP_LOGI(TAG_CNSL, "hw fifo overflow\n");
+                break;
+            //Event of UART ring buffer full
+            case UART_BUFFER_FULL:
+                ESP_LOGI(TAG_CNSL, "ring buffer full\n");
+                break;
+            //Event of UART RX break detected
+            case UART_BREAK:
+                ESP_LOGI(TAG_CNSL, "uart rx break\n");
+                break;
+            //Event of UART parity check error
+            case UART_PARITY_ERR:
+                ESP_LOGI(TAG_CNSL, "uart parity error\n");
+                break;
+            //Event of UART frame error
+            case UART_FRAME_ERR:
+                ESP_LOGI(TAG_CNSL, "uart frame error\n");
+                break;
+            //Others
+            default:
+                break;
+            }
+        }
+    }
+    vTaskDelete(NULL);
+}
+
+
+esp_err_t console_uart_init(void)
+{
+    esp_err_t ret;
+
+    ret =  uart_param_config(CONSOLE_UART_NUM, &uart_cfg);
+    if (ret != ESP_OK) {
+        ESP_LOGE(TAG_CNSL, "Uart %d initialize err %04x\n", CONSOLE_UART_NUM, ret);
+        return ret;
+    }
+
+    uart_set_pin(CONSOLE_UART_NUM, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);
+    uart_driver_install(CONSOLE_UART_NUM, 1024, 1024, 8, &uart_queue, 0);
+    xTaskCreate(console_uart_task, "uTask", 2048, NULL, 8, NULL);
+
+    return ESP_OK;
+}

+ 19 - 0
examples/bluetooth/bluedroid/classic_bt/hfp_ag/main/console_uart.h

@@ -0,0 +1,19 @@
+/*
+   This example code is in the Public Domain (or CC0 licensed, at your option.)
+
+   Unless required by applicable law or agreed to in writing, this
+   software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+   CONDITIONS OF ANY KIND, either express or implied.
+*/
+
+#ifndef __CONSOLE_UART_H__
+#define __CONSOLE_UART_H__
+
+#define TAG_CNSL "CNSL"
+
+/**
+ * @brief     configure uart console for command input and process
+ */
+esp_err_t console_uart_init(void);
+
+#endif /* __BT_APP_HF_H__*/

+ 92 - 0
examples/bluetooth/bluedroid/classic_bt/hfp_ag/main/gpio_pcm_config.c

@@ -0,0 +1,92 @@
+/*
+   This example code is in the Public Domain (or CC0 licensed, at your option.)
+
+   Unless required by applicable law or agreed to in writing, this
+   software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+   CONDITIONS OF ANY KIND, either express or implied.
+*/
+
+#include "driver/gpio.h"
+#include "soc/gpio_reg.h"
+#include "soc/gpio_sig_map.h"
+#include "gpio_pcm_config.h"
+
+#define GPIO_OUTPUT_PCM_FSYNC      (25)
+#define GPIO_OUTPUT_PCM_CLK_OUT    (5)
+#define GPIO_OUTPUT_PCM_DOUT       (26)
+#define GPIO_INPUT_PCM_DIN         (35)
+
+#define GPIO_OUTPUT_PCM_PIN_SEL  ((1ULL<<GPIO_OUTPUT_PCM_FSYNC) | (1ULL<<GPIO_OUTPUT_PCM_CLK_OUT) | (1ULL<<GPIO_OUTPUT_PCM_DOUT))
+
+#define GPIO_INPUT_PCM_PIN_SEL (1ULL<<GPIO_INPUT_PCM_DIN)
+
+void app_gpio_pcm_io_cfg(void)
+{
+    gpio_config_t io_conf;
+    /// configure the PCM output pins
+    //disable interrupt
+    io_conf.intr_type = GPIO_PIN_INTR_DISABLE;
+    //set as output mode
+    io_conf.mode = GPIO_MODE_OUTPUT;
+    //bit mask of the pins that you want to set,e.g.GPIO18/19
+    io_conf.pin_bit_mask = GPIO_OUTPUT_PCM_PIN_SEL;
+    //disable pull-down mode
+    io_conf.pull_down_en = 0;
+    //disable pull-up mode
+    io_conf.pull_up_en = 0;
+    //configure GPIO with the given settings
+    gpio_config(&io_conf);
+
+    /// configure the PCM input pin
+    //interrupt of rising edge
+    io_conf.intr_type = GPIO_PIN_INTR_DISABLE;
+    //bit mask of the pins, use GPIO4/5 here
+    io_conf.pin_bit_mask = GPIO_INPUT_PCM_PIN_SEL;
+    //set as input mode
+    io_conf.mode = GPIO_MODE_INPUT;
+    //enable pull-up mode
+    io_conf.pull_up_en = 0;
+    io_conf.pull_down_en = 0;
+    //configure GPIO with the given settings
+    gpio_config(&io_conf);
+
+    /// matrix out | in the internal PCM signals to the GPIOs
+    gpio_matrix_out(GPIO_OUTPUT_PCM_FSYNC, PCMFSYNC_OUT_IDX, false, false);
+    gpio_matrix_out(GPIO_OUTPUT_PCM_CLK_OUT, PCMCLK_OUT_IDX, false, false);
+    gpio_matrix_out(GPIO_OUTPUT_PCM_DOUT, PCMDOUT_IDX, false, false);
+    gpio_matrix_in(GPIO_INPUT_PCM_DIN, PCMDIN_IDX, false);
+}
+
+#if ACOUSTIC_ECHO_CANCELLATION_ENABLE
+
+#define GPIO_OUTPUT_AEC_1      (19)
+#define GPIO_OUTPUT_AEC_2      (21)
+#define GPIO_OUTPUT_AEC_3      (22)
+#define GPIO_OUTPUT_AEC_PIN_SEL  ((1ULL<<GPIO_OUTPUT_AEC_1) | (1ULL<<GPIO_OUTPUT_AEC_2) | (1ULL<<GPIO_OUTPUT_AEC_3))
+
+void app_gpio_aec_io_cfg(void)
+{
+    gpio_config_t io_conf;
+    //disable interrupt
+    io_conf.intr_type = GPIO_PIN_INTR_DISABLE;
+    //set as output mode
+    io_conf.mode = GPIO_MODE_OUTPUT;
+    //bit mask of the pins that you want to set,e.g.GPIO18/19
+    io_conf.pin_bit_mask = GPIO_OUTPUT_AEC_PIN_SEL;
+    //disable pull-down mode
+    io_conf.pull_down_en = 0;
+    //disable pull-up mode
+    io_conf.pull_up_en = 0;
+    //configure GPIO with the given settings
+    gpio_config(&io_conf);
+
+    // set the output pins
+    gpio_set_level(GPIO_OUTPUT_AEC_2, 0);
+
+    gpio_set_level(GPIO_OUTPUT_AEC_1, 0);
+
+    gpio_set_level(GPIO_OUTPUT_AEC_1, 1);
+
+    gpio_set_level(GPIO_OUTPUT_AEC_3, 1);
+}
+#endif /* ACOUSTIC_ECHO_CANCELLATION_ENABLE */

+ 20 - 0
examples/bluetooth/bluedroid/classic_bt/hfp_ag/main/gpio_pcm_config.h

@@ -0,0 +1,20 @@
+/*
+   This example code is in the Public Domain (or CC0 licensed, at your option.)
+
+   Unless required by applicable law or agreed to in writing, this
+   software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+   CONDITIONS OF ANY KIND, either express or implied.
+*/
+
+#ifndef __GPIO_PCM_CONFIG_H__
+#define __GPIO_PCM_CONFIG_H__
+
+#define ACOUSTIC_ECHO_CANCELLATION_ENABLE    1
+
+void app_gpio_pcm_io_cfg(void);
+
+#if ACOUSTIC_ECHO_CANCELLATION_ENABLE
+void app_gpio_aec_io_cfg(void);
+#endif /* ACOUSTIC_ECHO_CANCELLATION_ENABLE */
+
+#endif /* #define __GPIO_PCM_CONFIG_H__ */

+ 121 - 0
examples/bluetooth/bluedroid/classic_bt/hfp_ag/main/main.c

@@ -0,0 +1,121 @@
+/*
+   This example code is in the Public Domain (or CC0 licensed, at your option.)
+
+   Unless required by applicable law or agreed to in writing, this
+   software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+   CONDITIONS OF ANY KIND, either express or implied.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include "freertos/FreeRTOS.h"
+#include "freertos/task.h"
+#include "nvs.h"
+#include "nvs_flash.h"
+#include "esp_system.h"
+#include "esp_log.h"
+#include "esp_bt.h"
+#include "bt_app_core.h"
+#include "esp_bt_main.h"
+#include "esp_bt_device.h"
+#include "esp_gap_bt_api.h"
+#include "esp_hf_ag_api.h"
+#include "bt_app_hf.h"
+#include "gpio_pcm_config.h"
+#include "console_uart.h"
+
+#define BT_HF_AG_TAG            "HF_AG_DEMO_MAIN"
+
+/* event for handler "hf_ag_hdl_stack_up */
+enum {
+    BT_APP_EVT_STACK_UP = 0,
+};
+
+/* handler for bluetooth stack enabled events */
+static void bt_hf_hdl_stack_evt(uint16_t event, void *p_param)
+{
+    ESP_LOGD(BT_HF_TAG, "%s evt %d", __func__, event);
+    switch (event)
+    {
+        case BT_APP_EVT_STACK_UP:
+        {
+            /* set up device name */
+            char *dev_name = "ESP_HFP_AG";
+            esp_bt_dev_set_device_name(dev_name);
+
+            esp_bt_hf_register_callback(bt_app_hf_cb);
+            
+            // init and register for HFP_AG functions
+            esp_bt_hf_init(hf_peer_addr);
+
+            /*
+            * Set default parameters for Legacy Pairing
+            * Use variable pin, input pin code when pairing
+            */
+            esp_bt_pin_type_t pin_type = ESP_BT_PIN_TYPE_VARIABLE;
+            esp_bt_pin_code_t pin_code;
+            pin_code[0] = '0';
+            pin_code[1] = '0';
+            pin_code[2] = '0';
+            pin_code[3] = '0';
+            esp_bt_gap_set_pin(pin_type, 4, pin_code);
+
+            /* set discoverable and connectable mode, wait to be connected */
+            esp_bt_gap_set_scan_mode(ESP_BT_CONNECTABLE, ESP_BT_GENERAL_DISCOVERABLE);
+            break;
+        }
+        default:
+            ESP_LOGE(BT_HF_TAG, "%s unhandled evt %d", __func__, event);
+            break;
+    }
+}
+
+void app_main(void)
+{
+    /* Initialize NVS — it is used to store PHY calibration data */
+    esp_err_t ret = nvs_flash_init();
+    if (ret == ESP_ERR_NVS_NO_FREE_PAGES) {
+        ESP_ERROR_CHECK(nvs_flash_erase());
+        ret = nvs_flash_init();
+    }
+    ESP_ERROR_CHECK(ret);
+    ESP_ERROR_CHECK(esp_bt_controller_mem_release(ESP_BT_MODE_BLE));
+
+    esp_err_t err;
+    esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
+    if ((err = esp_bt_controller_init(&bt_cfg)) != ESP_OK) {
+        ESP_LOGE(BT_HF_TAG, "%s initialize controller failed: %s\n", __func__, esp_err_to_name(ret));
+        return;
+    }
+    if ((err = esp_bt_controller_enable(ESP_BT_MODE_CLASSIC_BT)) != ESP_OK) {
+        ESP_LOGE(BT_HF_TAG, "%s enable controller failed: %s\n", __func__, esp_err_to_name(ret));
+        return;
+    }
+    if ((err = esp_bluedroid_init()) != ESP_OK) {
+        ESP_LOGE(BT_HF_TAG, "%s initialize bluedroid failed: %s\n", __func__, esp_err_to_name(ret));
+        return;
+    }
+    if ((err = esp_bluedroid_enable()) != ESP_OK) {
+        ESP_LOGE(BT_HF_TAG, "%s enable bluedroid failed: %s\n", __func__, esp_err_to_name(ret));
+        return;
+    }
+
+    /* create application task */
+    bt_app_task_start_up();
+
+    /* Bluetooth device name, connection mode and profile set up */
+    bt_app_work_dispatch(bt_hf_hdl_stack_evt, BT_APP_EVT_STACK_UP, NULL, 0, NULL);
+
+    /* initialize console via UART */
+    console_uart_init();
+
+    /* configure the PCM interface and PINs used */
+    app_gpio_pcm_io_cfg();
+
+    /* configure externel chip for acoustic echo cancellation */
+#if ACOUSTIC_ECHO_CANCELLATION_ENABLE
+    app_gpio_aec_io_cfg();
+#endif /* ACOUSTIC_ECHO_CANCELLATION_ENABLE */
+}

+ 9 - 0
examples/bluetooth/bluedroid/classic_bt/hfp_ag/sdkconfig.defaults

@@ -0,0 +1,9 @@
+# Override some defaults so BT stack is enabled and
+# Classic BT is enabled and BT_DRAM_RELEASE is disabled
+CONFIG_BT_ENABLED=y
+CONFIG_BT_BLE_ENABLED=n
+CONFIG_BTDM_CTRL_MODE_BR_EDR_ONLY=y
+CONFIG_BT_BLUEDROID_ENABLED=y
+CONFIG_BT_CLASSIC_ENABLED=y
+CONFIG_BT_HFP_ENABLE=y
+CONFIG_BT_HFP_AG_ENABLE=y