From de9e0ea7a74966417a0fd17ac6486a0d1ada55c5 Mon Sep 17 00:00:00 2001 From: Milanka Ringwald Date: Thu, 8 Jul 2021 14:24:27 +0200 Subject: [PATCH] hfp: enhanced audio recognition, HF ready for audio --- example/hfp_ag_demo.c | 30 ++++---------- example/hfp_hf_demo.c | 37 +++++++---------- src/btstack_defines.h | 5 +-- src/btstack_event.h | 17 ++------ src/classic/hfp.c | 24 ++++++++--- src/classic/hfp.h | 8 ++-- src/classic/hfp_ag.c | 52 ++++++++++++++++++----- src/classic/hfp_hf.c | 95 +++++++++++++++++++++++++++++++++++++------ src/classic/hfp_hf.h | 2 +- 9 files changed, 178 insertions(+), 92 deletions(-) diff --git a/example/hfp_ag_demo.c b/example/hfp_ag_demo.c index 98b992eef..3511db762 100644 --- a/example/hfp_ag_demo.c +++ b/example/hfp_ag_demo.c @@ -70,7 +70,7 @@ const uint8_t rfcomm_channel_nr = 1; const char hfp_ag_service_name[] = "HFP AG Demo"; static bd_addr_t device_addr; -static const char * device_addr_string = "00:02:72:DC:31:C1"; +static const char * device_addr_string = "00:1A:7D:DA:71:13"; #ifdef ENABLE_HFP_WIDE_BAND_SPEECH static uint8_t codecs[] = {HFP_CODEC_CVSD, HFP_CODEC_MSBC}; @@ -549,43 +549,29 @@ static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t * even case HFP_SUBEVENT_VOICE_RECOGNITION_STATUS: status = hfp_subevent_voice_recognition_status_get_status(event); if (status != ERROR_CODE_SUCCESS){ - printf("Voice Recognition command failed with status 0x%02x\n", status); + printf("Voice Recognition command failed\n"); break; } - printf("\n"); switch(hfp_subevent_voice_recognition_status_get_state(event)){ case 0: - printf("Voice recognition status DEACTIVATED\n"); + printf("\nVoice recognition status DEACTIVATED\n\n"); break; case 1: - printf("Voice recognition status ACTIVATED\n"); + printf("\nVoice recognition status ACTIVATED\n\n"); break; default: btstack_assert(false); break; } - printf("\n"); break; - case HFP_SUBEVENT_ENHANCED_VOICE_RECOGNITION_STATUS: - status = hfp_subevent_voice_recognition_status_get_status(event); + case HFP_SUBEVENT_ENHANCED_VOICE_RECOGNITION_HF_READY_FOR_AUDIO: + status = hfp_subevent_enhanced_voice_recognition_hf_ready_for_audio_get_status(event); if (status != ERROR_CODE_SUCCESS){ - printf("Enhanced Voice Recognition command failed with status 0x%02x\n", status); + printf("Enhanced Voice recognition READY FOR AUDIO cmd failed\n"); break; } - printf("\n"); - switch(hfp_subevent_voice_recognition_status_get_state(event)){ - case 0: - printf("Enhanced Voice recognition status DEACTIVATED\n"); - break; - case 1: - printf("Enhanced Voice recognition status ACTIVATED\n"); - break; - default: - btstack_assert(false); - break; - } - printf("\n"); + printf("\nEnhanced Voice recognition status READY FOR AUDIO\n\n"); break; default: break; diff --git a/example/hfp_hf_demo.c b/example/hfp_hf_demo.c index b6c3d0968..d10b818c9 100644 --- a/example/hfp_hf_demo.c +++ b/example/hfp_hf_demo.c @@ -68,7 +68,7 @@ const char hfp_hf_service_name[] = "HFP HF Demo"; #ifdef HAVE_BTSTACK_STDIN // static const char * device_addr_string = "6C:72:E7:10:22:EE"; -static const char * device_addr_string = "00:1A:7D:DA:71:13"; +static const char * device_addr_string = "00:02:72:DC:31:C1"; #endif static bd_addr_t device_addr; @@ -150,6 +150,8 @@ static void show_usage(void){ printf("m/M - deactivate/activate echo canceling and noise reduction\n"); printf("n/N - deactivate/activate voice recognition\n"); printf("z/Z - deactivate/activate enhanced voice recognition\n"); + printf("h - start new audio enhanced voice recognition session\n"); + printf("0123456789#*-+ - send DTMF dial tones\n"); printf("x - request phone number for voice tag | X - current call status (ECS)\n"); printf("y - release call with index 2 (ECC) | Y - private consultation with call 2(ECC)\n"); @@ -325,6 +327,11 @@ static void stdin_process(char c){ printf("Activate enhanced voice recognition %s\n", bd_addr_to_str(device_addr)); status = hfp_hf_activate_enhanced_voice_recognition(acl_handle); break; + case 'h': + log_info("USER:\'%c\'", cmd); + printf("Start new audio enhanced voice recognition session %s\n", bd_addr_to_str(device_addr)); + status = hfp_hf_enhanced_voice_recognition_report_ready_for_audio(acl_handle); + break; case 'o': log_info("USER:\'%c\'", cmd); printf("Set speaker gain to 0 (minimum)\n"); @@ -576,43 +583,29 @@ static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t * even case HFP_SUBEVENT_VOICE_RECOGNITION_STATUS: status = hfp_subevent_voice_recognition_status_get_status(event); if (status != ERROR_CODE_SUCCESS){ - printf("Voice Recognition command failed with status 0x%02x\n", status); + printf("Voice Recognition command failed\n"); break; } - printf("\n"); switch(hfp_subevent_voice_recognition_status_get_state(event)){ case 0: - printf("Voice recognition status DEACTIVATED\n"); + printf("\nVoice recognition status DEACTIVATED\n\n"); break; case 1: - printf("Voice recognition status ACTIVATED\n"); + printf("\nVoice recognition status ACTIVATED\n\n"); break; default: btstack_assert(false); break; } - printf("\n"); break; - case HFP_SUBEVENT_ENHANCED_VOICE_RECOGNITION_STATUS: - status = hfp_subevent_voice_recognition_status_get_status(event); + case HFP_SUBEVENT_ENHANCED_VOICE_RECOGNITION_HF_READY_FOR_AUDIO: + status = hfp_subevent_enhanced_voice_recognition_hf_ready_for_audio_get_status(event); if (status != ERROR_CODE_SUCCESS){ - printf("Enhanced Voice Recognition command failed with status 0x%02x\n", status); + printf("Enhanced Voice recognition READY FOR AUDIO cmd failed\n"); break; } - printf("\n"); - switch(hfp_subevent_voice_recognition_status_get_state(event)){ - case 0: - printf("Enhanced Voice recognition status DEACTIVATED\n"); - break; - case 1: - printf("Enhanced Voice recognition status ACTIVATED\n"); - break; - default: - btstack_assert(false); - break; - } - printf("\n"); + printf("\nEnhanced Voice recognition status READY FOR AUDIO\n\n"); break; default: diff --git a/src/btstack_defines.h b/src/btstack_defines.h index 87bcc7737..7bcabba10 100644 --- a/src/btstack_defines.h +++ b/src/btstack_defines.h @@ -1781,13 +1781,12 @@ typedef uint8_t sm_key_t[16]; #define HFP_SUBEVENT_VOICE_RECOGNITION_STATUS 0x1E /** - * @format 1H11 + * @format 1H1 * @param subevent_code * @param acl_handle * @param status - * @param state */ -#define HFP_SUBEVENT_ENHANCED_VOICE_RECOGNITION_STATUS 0x1F +#define HFP_SUBEVENT_ENHANCED_VOICE_RECOGNITION_HF_READY_FOR_AUDIO 0x1F /** * @format 1H211LV diff --git a/src/btstack_event.h b/src/btstack_event.h index 106cf8761..b5c26cfdf 100644 --- a/src/btstack_event.h +++ b/src/btstack_event.h @@ -4746,32 +4746,23 @@ static inline uint8_t hfp_subevent_voice_recognition_status_get_state(const uint } /** - * @brief Get field acl_handle from event HFP_SUBEVENT_ENHANCED_VOICE_RECOGNITION_STATUS + * @brief Get field acl_handle from event HFP_SUBEVENT_ENHANCED_VOICE_RECOGNITION_HF_READY_FOR_AUDIO * @param event packet * @return acl_handle * @note: btstack_type H */ -static inline hci_con_handle_t hfp_subevent_enhanced_voice_recognition_status_get_acl_handle(const uint8_t * event){ +static inline hci_con_handle_t hfp_subevent_enhanced_voice_recognition_hf_ready_for_audio_get_acl_handle(const uint8_t * event){ return little_endian_read_16(event, 3); } /** - * @brief Get field status from event HFP_SUBEVENT_ENHANCED_VOICE_RECOGNITION_STATUS + * @brief Get field status from event HFP_SUBEVENT_ENHANCED_VOICE_RECOGNITION_HF_READY_FOR_AUDIO * @param event packet * @return status * @note: btstack_type 1 */ -static inline uint8_t hfp_subevent_enhanced_voice_recognition_status_get_status(const uint8_t * event){ +static inline uint8_t hfp_subevent_enhanced_voice_recognition_hf_ready_for_audio_get_status(const uint8_t * event){ return event[5]; } -/** - * @brief Get field state from event HFP_SUBEVENT_ENHANCED_VOICE_RECOGNITION_STATUS - * @param event packet - * @return state - * @note: btstack_type 1 - */ -static inline uint8_t hfp_subevent_enhanced_voice_recognition_status_get_state(const uint8_t * event){ - return event[6]; -} /** * @brief Get field acl_handle from event HFP_SUBEVENT_ENHANCED_VOICE_RECOGNITION_TEXT diff --git a/src/classic/hfp.c b/src/classic/hfp.c index 5a26be90a..4673459c6 100644 --- a/src/classic/hfp.c +++ b/src/classic/hfp.c @@ -355,11 +355,8 @@ void hfp_emit_voice_recognition_state_event(hfp_connection_t * hfp_connection, u uint8_t event[7]; event[0] = HCI_EVENT_HFP_META; event[1] = sizeof(event) - 2; - if (hfp_connection->enhanced_voice_recognition_enabled){ - event[2] = HFP_SUBEVENT_ENHANCED_VOICE_RECOGNITION_STATUS; - } else { - event[2] = HFP_SUBEVENT_VOICE_RECOGNITION_STATUS; - } + event[2] = HFP_SUBEVENT_VOICE_RECOGNITION_STATUS; + little_endian_store_16(event, 3, acl_handle); event[5] = status; // 0:success @@ -367,6 +364,9 @@ void hfp_emit_voice_recognition_state_event(hfp_connection_t * hfp_connection, u case HFP_VRA_VOICE_RECOGNITION_ACTIVATED: event[6] = 1; break; + case HFP_VRA_ENHANCED_VOICE_RECOGNITION_READY_FOR_AUDIO: + event[6] = 2; + break; default: event[6] = 0; break; @@ -374,6 +374,18 @@ void hfp_emit_voice_recognition_state_event(hfp_connection_t * hfp_connection, u hfp_emit_event_for_context(hfp_connection, event, sizeof(event)); } +void hfp_emit_enhanced_voice_recognition_hf_ready_for_audio_event(hfp_connection_t * hfp_connection, uint8_t status){ + hci_con_handle_t acl_handle = (hfp_connection != NULL) ? hfp_connection->acl_handle : HCI_CON_HANDLE_INVALID; + + uint8_t event[6]; + event[0] = HCI_EVENT_HFP_META; + event[1] = sizeof(event) - 2; + event[2] = HFP_SUBEVENT_ENHANCED_VOICE_RECOGNITION_HF_READY_FOR_AUDIO; + little_endian_store_16(event, 3, acl_handle); + event[5] = status; + hfp_emit_event_for_context(hfp_connection, event, sizeof(event)); +} + void hfp_emit_slc_connection_event(hfp_connection_t * hfp_connection, uint8_t status, hci_con_handle_t con_handle, bd_addr_t addr){ btstack_assert(hfp_connection != NULL); uint8_t event[12]; @@ -762,6 +774,8 @@ static void hfp_reset_voice_recognition(hfp_connection_t * hfp_connection){ hfp_connection->vra_state = HFP_VRA_VOICE_RECOGNITION_OFF; hfp_connection->vra_state_requested = HFP_VRA_VOICE_RECOGNITION_OFF; hfp_connection->ag_vra_status = 0; + hfp_connection->activate_voice_recognition = false; + hfp_connection->deactivate_voice_recognition = false; hfp_connection->enhanced_voice_recognition_enabled = false; hfp_connection->ag_vra_state = HFP_VOICE_RECOGNITION_STATE_AG_READY; } diff --git a/src/classic/hfp.h b/src/classic/hfp.h index f5b4318f4..fe3439932 100644 --- a/src/classic/hfp.h +++ b/src/classic/hfp.h @@ -406,9 +406,8 @@ typedef enum { HFP_VRA_W2_SEND_ENHANCED_VOICE_RECOGNITION_MSG, HFP_VRA_W2_SEND_ENHANCED_VOICE_RECOGNITION_STATUS, - HFP_VRA_W4_ENHANCED_VOICE_RECOGNITION_STATUS, + HFP_VRA_W4_ENHANCED_VOICE_RECOGNITION_STATUS - HFP_VRA_W4_ENHANCED_VOICE_RECOGNITION_NEW_SESSION, } hfp_voice_recognition_activation_status_t; typedef struct { @@ -690,7 +689,9 @@ typedef struct hfp_connection { hfp_voice_recognition_activation_status_t vra_state; hfp_voice_recognition_activation_status_t vra_state_requested; - + bool deactivate_voice_recognition; + bool activate_voice_recognition; + uint8_t ag_vra_status; hfp_voice_recognition_state_t ag_vra_state; bool enhanced_voice_recognition_enabled; @@ -754,6 +755,7 @@ void hfp_emit_slc_connection_event(hfp_connection_t * hfp_connection, uint8_t st * @param state 0 if deactivated, 1 if activated */ void hfp_emit_voice_recognition_state_event(hfp_connection_t * hfp_connection, uint8_t status); +void hfp_emit_enhanced_voice_recognition_hf_ready_for_audio_event(hfp_connection_t * hfp_connection, uint8_t status); hfp_connection_t * get_hfp_connection_context_for_rfcomm_cid(uint16_t cid); hfp_connection_t * get_hfp_connection_context_for_bd_addr(bd_addr_t bd_addr, hfp_role_t hfp_role); diff --git a/src/classic/hfp_ag.c b/src/classic/hfp_ag.c index 7ea03e4b8..af068955a 100644 --- a/src/classic/hfp_ag.c +++ b/src/classic/hfp_ag.c @@ -781,6 +781,9 @@ static uint8_t hfp_ag_voice_recognition_session_active(hfp_connection_t * hfp_co return ERROR_CODE_COMMAND_DISALLOWED; } if (hfp_connection->vra_state != HFP_VRA_VOICE_RECOGNITION_ACTIVATED){ + if (hfp_connection->vra_state == HFP_VRA_ENHANCED_VOICE_RECOGNITION_READY_FOR_AUDIO){ + return ERROR_CODE_SUCCESS; + } return ERROR_CODE_COMMAND_DISALLOWED; } return ERROR_CODE_SUCCESS; @@ -826,16 +829,29 @@ static int hfp_ag_voice_recognition_state_machine(hfp_connection_t * hfp_connect case HFP_CMD_HF_ACTIVATE_VOICE_RECOGNITION: // HF initiatied voice recognition, parser extracted activation value - if (hfp_connection->ag_activate_voice_recognition_value == 0){ - if (hfp_ag_voice_recognition_session_active(hfp_connection, hfp_connection->enhanced_voice_recognition_enabled) == ERROR_CODE_SUCCESS){ - hfp_connection->vra_state_requested = HFP_VRA_W2_SEND_VOICE_RECOGNITION_OFF; - done = hfp_ag_send_ok(hfp_connection->rfcomm_cid); - } - } else { - if (hfp_ag_can_activate_voice_recognition(hfp_connection, hfp_connection->enhanced_voice_recognition_enabled) == ERROR_CODE_SUCCESS){ - hfp_connection->vra_state_requested = HFP_VRA_W2_SEND_VOICE_RECOGNITION_ACTIVATED; - done = hfp_ag_send_ok(hfp_connection->rfcomm_cid); - } + switch (hfp_connection->ag_activate_voice_recognition_value){ + case 0: + if (hfp_ag_voice_recognition_session_active(hfp_connection, hfp_connection->enhanced_voice_recognition_enabled) == ERROR_CODE_SUCCESS){ + hfp_connection->vra_state_requested = HFP_VRA_W2_SEND_VOICE_RECOGNITION_OFF; + done = hfp_ag_send_ok(hfp_connection->rfcomm_cid); + } + break; + + case 1: + if (hfp_ag_can_activate_voice_recognition(hfp_connection, hfp_connection->enhanced_voice_recognition_enabled) == ERROR_CODE_SUCCESS){ + hfp_connection->vra_state_requested = HFP_VRA_W2_SEND_VOICE_RECOGNITION_ACTIVATED; + done = hfp_ag_send_ok(hfp_connection->rfcomm_cid); + } + break; + + case 2: + if (hfp_ag_voice_recognition_session_active(hfp_connection, hfp_connection->enhanced_voice_recognition_enabled) == ERROR_CODE_SUCCESS){ + hfp_connection->vra_state_requested = HFP_VRA_W2_SEND_ENHANCED_VOICE_RECOGNITION_READY_FOR_AUDIO; + done = hfp_ag_send_ok(hfp_connection->rfcomm_cid); + } + break; + default: + break; } if (done == 0){ hfp_connection->vra_state_requested = hfp_connection->vra_state; @@ -849,6 +865,22 @@ static int hfp_ag_voice_recognition_state_machine(hfp_connection_t * hfp_connect } switch (hfp_connection->vra_state_requested){ + case HFP_VRA_W2_SEND_ENHANCED_VOICE_RECOGNITION_READY_FOR_AUDIO: + + if (!hfp_ag_is_audio_connection_active(hfp_connection)){ + status = hfp_ag_setup_audio_connection(hfp_connection); + if (status != ERROR_CODE_SUCCESS){ + hfp_connection->vra_state_requested = hfp_connection->vra_state; + hfp_emit_voice_recognition_state_event(hfp_connection, status); + return 0; + } + } + hfp_connection->enhanced_voice_recognition_enabled = true; + hfp_connection->vra_state = HFP_VRA_ENHANCED_VOICE_RECOGNITION_READY_FOR_AUDIO; + hfp_connection->vra_state_requested = hfp_connection->vra_state; + hfp_emit_enhanced_voice_recognition_hf_ready_for_audio_event(hfp_connection, ERROR_CODE_SUCCESS); + break; + case HFP_VRA_W2_SEND_VOICE_RECOGNITION_OFF: hfp_connection->vra_state = HFP_VRA_VOICE_RECOGNITION_OFF; hfp_connection->vra_state_requested = hfp_connection->vra_state; diff --git a/src/classic/hfp_hf.c b/src/classic/hfp_hf.c index c81838fac..7ebf05506 100644 --- a/src/classic/hfp_hf.c +++ b/src/classic/hfp_hf.c @@ -490,6 +490,7 @@ static int hfp_hf_voice_recognition_state_machine(hfp_connection_t * hfp_connect switch(hfp_connection->vra_state_requested){ case HFP_VRA_W4_VOICE_RECOGNITION_ACTIVATED: case HFP_VRA_W4_VOICE_RECOGNITION_OFF: + case HFP_VRA_W4_ENHANCED_VOICE_RECOGNITION_READY_FOR_AUDIO: // ignore AG command, continue to wait for OK return 0; default: @@ -521,11 +522,6 @@ static int hfp_hf_voice_recognition_state_machine(hfp_connection_t * hfp_connect } return 1; - case HFP_VRA_W4_VOICE_RECOGNITION_OFF: - hfp_connection->vra_state = HFP_VRA_VOICE_RECOGNITION_OFF; - hfp_connection->vra_state_requested = hfp_connection->vra_state; - hfp_emit_voice_recognition_state_event(hfp_connection, ERROR_CODE_SUCCESS); - break; case HFP_VRA_W2_SEND_VOICE_RECOGNITION_ACTIVATED: done = hfp_hf_set_voice_recognition_notification_cmd(hfp_connection->rfcomm_cid, 1); @@ -536,20 +532,50 @@ static int hfp_hf_voice_recognition_state_machine(hfp_connection_t * hfp_connect } break; + case HFP_VRA_W2_SEND_ENHANCED_VOICE_RECOGNITION_READY_FOR_AUDIO: + done = hfp_hf_set_voice_recognition_notification_cmd(hfp_connection->rfcomm_cid, 2); + if (done != 0){ + hfp_connection->vra_state_requested = HFP_VRA_W4_ENHANCED_VOICE_RECOGNITION_READY_FOR_AUDIO; + hfp_connection->ok_pending = 1; + return 1; + } + break; + + case HFP_VRA_W4_VOICE_RECOGNITION_OFF: + hfp_connection->vra_state = HFP_VRA_VOICE_RECOGNITION_OFF; + hfp_connection->vra_state_requested = hfp_connection->vra_state; + hfp_connection->activate_voice_recognition = false; + if (hfp_connection->activate_voice_recognition){ + hfp_hf_activate_voice_recognition(hfp_connection->acl_handle); + } else { + hfp_emit_voice_recognition_state_event(hfp_connection, ERROR_CODE_SUCCESS); + } + break; + case HFP_VRA_W4_VOICE_RECOGNITION_ACTIVATED: hfp_connection->vra_state = HFP_VRA_VOICE_RECOGNITION_ACTIVATED; hfp_connection->vra_state_requested = hfp_connection->vra_state; - hfp_emit_voice_recognition_state_event(hfp_connection, ERROR_CODE_SUCCESS); + hfp_connection->activate_voice_recognition = false; + if (hfp_connection->deactivate_voice_recognition){ + hfp_hf_deactivate_voice_recognition(hfp_connection->acl_handle); + } else { + hfp_emit_voice_recognition_state_event(hfp_connection, ERROR_CODE_SUCCESS); + } break; - + + case HFP_VRA_W4_ENHANCED_VOICE_RECOGNITION_READY_FOR_AUDIO: hfp_connection->vra_state = HFP_VRA_ENHANCED_VOICE_RECOGNITION_READY_FOR_AUDIO; hfp_connection->vra_state_requested = hfp_connection->vra_state; - hfp_emit_voice_recognition_state_event(hfp_connection, ERROR_CODE_SUCCESS); + hfp_connection->activate_voice_recognition = false; + if (hfp_connection->deactivate_voice_recognition){ + hfp_hf_deactivate_voice_recognition(hfp_connection->acl_handle); + } else { + hfp_emit_enhanced_voice_recognition_hf_ready_for_audio_event(hfp_connection, ERROR_CODE_SUCCESS); + } break; default: - break; } return done; @@ -1168,8 +1194,8 @@ static void hfp_hf_handle_rfcomm_command(hfp_connection_t * hfp_connection){ } // handle error response for voice activation (HF initiated) switch(hfp_connection->vra_state_requested){ - case HFP_VRA_VOICE_RECOGNITION_ACTIVATED: - case HFP_VRA_VOICE_RECOGNITION_OFF: + case HFP_VRA_W4_ENHANCED_VOICE_RECOGNITION_READY_FOR_AUDIO: + hfp_emit_enhanced_voice_recognition_hf_ready_for_audio_event(hfp_connection, ERROR_CODE_UNSPECIFIED_ERROR); break; default: hfp_connection->vra_state_requested = hfp_connection->vra_state; @@ -1742,10 +1768,14 @@ static uint8_t activate_voice_recognition(hci_con_handle_t acl_handle, bool enha switch (hfp_connection->vra_state){ case HFP_VRA_VOICE_RECOGNITION_OFF: + case HFP_VRA_W2_SEND_VOICE_RECOGNITION_OFF: hfp_connection->command = HFP_CMD_HF_ACTIVATE_VOICE_RECOGNITION; hfp_connection->vra_state_requested = HFP_VRA_W2_SEND_VOICE_RECOGNITION_ACTIVATED; hfp_connection->enhanced_voice_recognition_enabled = enhanced; break; + case HFP_VRA_W4_VOICE_RECOGNITION_OFF: + hfp_connection->activate_voice_recognition = true; + break; default: return ERROR_CODE_COMMAND_DISALLOWED; } @@ -1760,18 +1790,30 @@ static uint8_t deactivate_voice_recognition(hci_con_handle_t acl_handle, bool en if (!hfp_connection) { return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; } - if (hfp_connection->state < HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED || hfp_connection->state > HFP_AUDIO_CONNECTION_ESTABLISHED){ + if (hfp_connection->state != HFP_AUDIO_CONNECTION_ESTABLISHED){ return ERROR_CODE_COMMAND_DISALLOWED; } if (!hfp_hf_voice_recognition_supported(hfp_connection, enhanced)){ return ERROR_CODE_COMMAND_DISALLOWED; } - + switch (hfp_connection->vra_state){ + case HFP_VRA_W2_SEND_VOICE_RECOGNITION_ACTIVATED: case HFP_VRA_VOICE_RECOGNITION_ACTIVATED: + case HFP_VRA_W2_SEND_ENHANCED_VOICE_RECOGNITION_READY_FOR_AUDIO: + case HFP_VRA_ENHANCED_VOICE_RECOGNITION_READY_FOR_AUDIO: hfp_connection->command = HFP_CMD_HF_ACTIVATE_VOICE_RECOGNITION; hfp_connection->vra_state_requested = HFP_VRA_W2_SEND_VOICE_RECOGNITION_OFF; break; + + case HFP_VRA_W4_VOICE_RECOGNITION_ACTIVATED: + case HFP_VRA_W4_ENHANCED_VOICE_RECOGNITION_READY_FOR_AUDIO: + hfp_connection->deactivate_voice_recognition = true; + break; + + case HFP_VRA_VOICE_RECOGNITION_OFF: + case HFP_VRA_W2_SEND_VOICE_RECOGNITION_OFF: + case HFP_VRA_W4_VOICE_RECOGNITION_OFF: default: return ERROR_CODE_COMMAND_DISALLOWED; } @@ -1788,6 +1830,32 @@ uint8_t hfp_hf_activate_enhanced_voice_recognition(hci_con_handle_t acl_handle){ return activate_voice_recognition(acl_handle, true); } +uint8_t hfp_hf_enhanced_voice_recognition_report_ready_for_audio(hci_con_handle_t acl_handle){ + hfp_connection_t * hfp_connection = get_hfp_hf_connection_context_for_acl_handle(acl_handle); + if (!hfp_connection) { + return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; + } + if (hfp_connection->state != HFP_AUDIO_CONNECTION_ESTABLISHED){ + return ERROR_CODE_COMMAND_DISALLOWED; + } + if (!hfp_hf_voice_recognition_supported(hfp_connection, true)){ + return ERROR_CODE_COMMAND_DISALLOWED; + } + + switch (hfp_connection->vra_state){ + case HFP_VRA_VOICE_RECOGNITION_ACTIVATED: + case HFP_VRA_ENHANCED_VOICE_RECOGNITION_READY_FOR_AUDIO: + hfp_connection->command = HFP_CMD_HF_ACTIVATE_VOICE_RECOGNITION; + hfp_connection->vra_state_requested = HFP_VRA_W2_SEND_ENHANCED_VOICE_RECOGNITION_READY_FOR_AUDIO; + break; + default: + return ERROR_CODE_COMMAND_DISALLOWED; + } + + hfp_hf_run_for_context(hfp_connection); + return ERROR_CODE_SUCCESS; +} + uint8_t hfp_hf_deactivate_voice_recognition(hci_con_handle_t acl_handle){ return deactivate_voice_recognition(acl_handle, false); @@ -1797,6 +1865,7 @@ uint8_t hfp_hf_deactivate_enhanced_voice_recognition(hci_con_handle_t acl_handle return deactivate_voice_recognition(acl_handle, true); } + uint8_t hfp_hf_set_microphone_gain(hci_con_handle_t acl_handle, int gain){ hfp_connection_t * hfp_connection = get_hfp_hf_connection_context_for_acl_handle(acl_handle); if (!hfp_connection) { diff --git a/src/classic/hfp_hf.h b/src/classic/hfp_hf.h index b208ecfa2..09749d6c4 100644 --- a/src/classic/hfp_hf.h +++ b/src/classic/hfp_hf.h @@ -408,7 +408,7 @@ uint8_t hfp_hf_activate_enhanced_voice_recognition(hci_con_handle_t acl_handle); * @return status ERROR_CODE_SUCCESS if successful, otherwise: * - ERROR_CODE_COMMAND_DISALLOWED if HF does not support it, or wrong VRA status */ -uint8_t hfp_hf_enhanced_voice_recognition_ready_to_accept_audio(hci_con_handle_t acl_handle); +uint8_t hfp_hf_enhanced_voice_recognition_report_ready_for_audio(hci_con_handle_t acl_handle); /** * @brief Deactivate enhanced voice recognition (EVR) and emit HFP_SUBEVENT_ENHANCED_VOICE_RECOGNITION_STATUS event with status ERROR_CODE_SUCCESS