diff --git a/src/btstack_defines.h b/src/btstack_defines.h index 1ed6e8ac7..d50010935 100644 --- a/src/btstack_defines.h +++ b/src/btstack_defines.h @@ -1762,18 +1762,20 @@ typedef uint8_t sm_key_t[16]; #define HFP_SUBEVENT_VOICE_RECOGNITION_STATUS 0x1E /** - * @format 1H1 + * @format 1H11 * @param subevent_code * @param acl_handle + * @param status * @param state */ #define HFP_SUBEVENT_ENHANCED_VOICE_RECOGNITION_STATUS 0x1F /** - * @format 1H21LV + * @format 1H211LV * @param subevent_code * @param acl_handle * @param text_id + * @param text_operation * @param text_type * @param text_length * @param text diff --git a/src/btstack_event.h b/src/btstack_event.h index cf560572c..31903fd45 100644 --- a/src/btstack_event.h +++ b/src/btstack_event.h @@ -4690,6 +4690,15 @@ static inline uint8_t hfp_subevent_voice_recognition_status_get_activated(const static inline hci_con_handle_t hfp_subevent_enhanced_voice_recognition_status_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 + * @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){ + return event[5]; +} /** * @brief Get field state from event HFP_SUBEVENT_ENHANCED_VOICE_RECOGNITION_STATUS * @param event packet @@ -4697,7 +4706,7 @@ static inline hci_con_handle_t hfp_subevent_enhanced_voice_recognition_status_ge * @note: btstack_type 1 */ static inline uint8_t hfp_subevent_enhanced_voice_recognition_status_get_state(const uint8_t * event){ - return event[5]; + return event[6]; } /** @@ -4718,6 +4727,15 @@ static inline hci_con_handle_t hfp_subevent_enhanced_voice_recognition_text_get_ static inline uint16_t hfp_subevent_enhanced_voice_recognition_text_get_text_id(const uint8_t * event){ return little_endian_read_16(event, 5); } +/** + * @brief Get field text_operation from event HFP_SUBEVENT_ENHANCED_VOICE_RECOGNITION_TEXT + * @param event packet + * @return text_operation + * @note: btstack_type 1 + */ +static inline uint8_t hfp_subevent_enhanced_voice_recognition_text_get_text_operation(const uint8_t * event){ + return event[7]; +} /** * @brief Get field text_type from event HFP_SUBEVENT_ENHANCED_VOICE_RECOGNITION_TEXT * @param event packet @@ -4725,7 +4743,7 @@ static inline uint16_t hfp_subevent_enhanced_voice_recognition_text_get_text_id( * @note: btstack_type 1 */ static inline uint8_t hfp_subevent_enhanced_voice_recognition_text_get_text_type(const uint8_t * event){ - return event[7]; + return event[8]; } /** * @brief Get field text_length from event HFP_SUBEVENT_ENHANCED_VOICE_RECOGNITION_TEXT @@ -4734,7 +4752,7 @@ static inline uint8_t hfp_subevent_enhanced_voice_recognition_text_get_text_type * @note: btstack_type L */ static inline uint16_t hfp_subevent_enhanced_voice_recognition_text_get_text_length(const uint8_t * event){ - return little_endian_read_16(event, 8); + return little_endian_read_16(event, 9); } /** * @brief Get field text from event HFP_SUBEVENT_ENHANCED_VOICE_RECOGNITION_TEXT @@ -4743,7 +4761,7 @@ static inline uint16_t hfp_subevent_enhanced_voice_recognition_text_get_text_len * @note: btstack_type V */ static inline const uint8_t * hfp_subevent_enhanced_voice_recognition_text_get_text(const uint8_t * event){ - return &event[10]; + return &event[11]; } #ifdef ENABLE_BLE diff --git a/src/classic/hfp.c b/src/classic/hfp.c index 93f18548b..d42a1c6e3 100644 --- a/src/classic/hfp.c +++ b/src/classic/hfp.c @@ -413,6 +413,44 @@ void hfp_emit_string_event(hfp_connection_t * hfp_connection, uint8_t event_subt hfp_emit_event_for_context(hfp_connection, event, sizeof(event)); } +static void hfp_emit_enhanced_voice_recognition_state(hfp_connection_t * hfp_connection){ + btstack_assert(hfp_connection != NULL); + uint8_t event[7]; + int pos = 0; + event[pos++] = HCI_EVENT_HFP_META; + event[pos++] = sizeof(event) - 2; + event[pos++] = HFP_SUBEVENT_ENHANCED_VOICE_RECOGNITION_STATUS; + little_endian_store_16(event, pos, hfp_connection->acl_handle); + pos += 2; + event[pos++] = hfp_connection->ag_vra_status; + event[pos++] = hfp_connection->ag_vra_state; + hfp_emit_event_for_context(hfp_connection, event, sizeof(event)); +} + +static void hfp_emit_enhanced_voice_recognition_text(hfp_connection_t * hfp_connection, uint16_t value_length, uint8_t * value){ + btstack_assert(hfp_connection != NULL); + uint8_t event[HFP_MAX_VR_TEXT_SIZE]; + int pos = 0; + event[pos++] = HCI_EVENT_HFP_META; + event[pos++] = sizeof(event) - 2; + event[pos++] = HFP_SUBEVENT_ENHANCED_VOICE_RECOGNITION_TEXT; + little_endian_store_16(event, pos, hfp_connection->acl_handle); + pos += 2; + little_endian_store_16(event, pos, hfp_connection->ag_text_id); + pos += 2; + event[pos++] = hfp_connection->ag_text_operation; + event[pos++] = hfp_connection->ag_text_type; + + // length, zero ending + uint16_t size = btstack_min(value_length, sizeof(event) - pos - 2 - 1); + little_endian_store_16(event, pos, size+1); + pos += 2; + memcpy(&event[pos], value, size); + event[pos + size] = 0; + pos += size + 1; + hfp_emit_event_for_context(hfp_connection, event, pos); +} + btstack_linked_list_t * hfp_get_connections(void){ return (btstack_linked_list_t *) &hfp_connections; } @@ -1573,6 +1611,36 @@ static void parse_sequence(hfp_connection_t * hfp_connection){ case HFP_CMD_ENABLE_CALL_WAITING_NOTIFICATION: hfp_connection->call_waiting_notification_enabled = hfp_connection->line_buffer[0] != '0'; break; + case HFP_CMD_AG_ACTIVATE_VOICE_RECOGNITION: + switch(hfp_connection->parser_item_index){ + case 0: + hfp_connection->ag_vra_status = btstack_atoi((char *)&hfp_connection->line_buffer[0]); + break; + case 1: + hfp_connection->ag_vra_state = btstack_atoi((char *)&hfp_connection->line_buffer[0]); + hfp_emit_enhanced_voice_recognition_state(hfp_connection); + break; + case 2: + hfp_connection->ag_text_id = 0; + for (i = 0 ; i < 4; i++){ + hfp_connection->ag_text_id = (hfp_connection->ag_text_id << 4) | nibble_for_char(hfp_connection->line_buffer[i]); + } + printf("text ID 0x%04X\n", hfp_connection->ag_text_id); + break; + case 3: + hfp_connection->ag_text_operation = btstack_atoi((char *)&hfp_connection->line_buffer[0]); + break; + case 4: + hfp_connection->ag_text_type = btstack_atoi((char *)&hfp_connection->line_buffer[0]); + break; + case 5: + printf("text%s\n", hfp_connection->line_buffer); + hfp_emit_enhanced_voice_recognition_text(hfp_connection, hfp_connection->line_size, &hfp_connection->line_buffer[0]); + break; + default: + break; + } + break; default: break; } diff --git a/src/classic/hfp.h b/src/classic/hfp.h index be3d08946..387947fb7 100644 --- a/src/classic/hfp.h +++ b/src/classic/hfp.h @@ -117,7 +117,8 @@ extern "C" { #define HFP_CALL_SERVICE_SIZE 3 #define HFP_MAX_NUM_CODECS 10 -#define HFP_MAX_INDICATOR_DESC_SIZE 20 +#define HFP_MAX_INDICATOR_DESC_SIZE 20 +#define HFP_MAX_VR_TEXT_SIZE 100 #define HFP_MAX_NETWORK_OPERATOR_NAME_SIZE 17 @@ -205,6 +206,7 @@ typedef enum { HFP_CMD_REDIAL_LAST_NUMBER, HFP_CMD_TURN_OFF_EC_AND_NR, HFP_CMD_AG_ACTIVATE_VOICE_RECOGNITION, + HFP_CMD_AG_ACTIVATE_ENHANCED_VOICE_RECOGNITION, HFP_CMD_HF_ACTIVATE_VOICE_RECOGNITION, HFP_CMD_HF_REQUEST_PHONE_NUMBER, HFP_CMD_AG_SENT_PHONE_NUMBER, @@ -327,10 +329,10 @@ typedef enum { } hfp_text_type_t; typedef enum { - HFP_TEXT_OPERATOR_NEW_TEXT = 1, - HFP_TEXT_OPERATOR_REPLACE, - HFP_TEXT_OPERATOR_APPEND -} hfp_text_operator_t; + HFP_TEXT_OPERATION_NEW_TEXT = 1, + HFP_TEXT_OPERATION_REPLACE, + HFP_TEXT_OPERATION_APPEND +} hfp_text_operation_t; typedef enum { HFP_IDLE = 0, //0 @@ -397,7 +399,7 @@ typedef enum { HFP_VRA_W4_ENHANCED_VOICE_RECOGNITION_ACTIVATED, HFP_VRA_W4_ENHANCED_VOICE_RECOGNITION_NEW_SESSION, HFP_VRA_ENHANCED_VOICE_RECOGNITION_ACTIVATED -} hfp_voice_recognition_activation_t; +} hfp_voice_recognition_activation_status_t; typedef enum { HFP_CODECS_IDLE, @@ -542,7 +544,7 @@ typedef struct hfp_connection { int parser_indicator_index; uint32_t parser_indicator_value; bool parser_quoted; - uint8_t line_buffer[HFP_MAX_INDICATOR_DESC_SIZE]; + uint8_t line_buffer[HFP_MAX_VR_TEXT_SIZE]; int line_size; uint32_t remote_supported_features; @@ -666,11 +668,13 @@ typedef struct hfp_connection { uint8_t hf_activate_echo_canceling_and_noise_reduction; uint8_t hf_deactivate_echo_canceling_and_noise_reduction; - hfp_voice_recognition_activation_t vra_state; - // uint8_t voice_recognition_status_required; - // uint8_t voice_recognition_status_current; // 1-enabled; 0-dissabled + hfp_voice_recognition_activation_status_t vra_status; - // hfp_voice_recognition_state_t voice_recognition_state; + hfp_voice_recognition_activation_status_t ag_vra_status; + hfp_voice_recognition_state_t ag_vra_state; + uint16_t ag_text_id; + hfp_text_operation_t ag_text_operation; + hfp_text_type_t ag_text_type; uint8_t clcc_idx; uint8_t clcc_dir; diff --git a/src/classic/hfp_hf.c b/src/classic/hfp_hf.c index 52d5db4b9..2d74ff1c6 100644 --- a/src/classic/hfp_hf.c +++ b/src/classic/hfp_hf.c @@ -480,7 +480,7 @@ static int voice_recognition_state_machine(hfp_connection_t * hfp_connection){ } int done = 0; if (hfp_connection->ok_pending == 0) { - switch (hfp_connection->vra_state){ + switch (hfp_connection->vra_status){ case HFP_VRA_W4_VOICE_RECOGNITION_OFF: case HFP_VRA_W4_ENHANCED_VOICE_RECOGNITION_OFF: hfp_connection->ok_pending = 1; @@ -503,20 +503,20 @@ static int voice_recognition_state_machine(hfp_connection_t * hfp_connection){ break; } } else { - switch (hfp_connection->vra_state){ + switch (hfp_connection->vra_status){ case HFP_VRA_W4_VOICE_RECOGNITION_ACTIVATED: - hfp_connection->vra_state = HFP_VRA_VOICE_RECOGNITION_ACTIVATED; + hfp_connection->vra_status = HFP_VRA_VOICE_RECOGNITION_ACTIVATED; hfp_emit_event(hfp_connection, HFP_SUBEVENT_VOICE_RECOGNITION_STATUS, 1); break; case HFP_VRA_W4_ENHANCED_VOICE_RECOGNITION_ACTIVATED: - hfp_connection->vra_state = HFP_VRA_ENHANCED_VOICE_RECOGNITION_ACTIVATED; + hfp_connection->vra_status = HFP_VRA_ENHANCED_VOICE_RECOGNITION_ACTIVATED; hfp_emit_event(hfp_connection, HFP_SUBEVENT_VOICE_RECOGNITION_STATUS, 2); break; case HFP_VRA_W4_VOICE_RECOGNITION_OFF: case HFP_VRA_W4_ENHANCED_VOICE_RECOGNITION_OFF: - hfp_connection->vra_state = HFP_VRA_VOICE_RECOGNITION_OFF; + hfp_connection->vra_status = HFP_VRA_VOICE_RECOGNITION_OFF; hfp_emit_event(hfp_connection, HFP_SUBEVENT_VOICE_RECOGNITION_STATUS, 0); break; default: @@ -1140,16 +1140,16 @@ static void hfp_hf_handle_rfcomm_command(hfp_connection_t * hfp_connection){ } - switch (hfp_connection->vra_state){ + switch (hfp_connection->vra_status){ case HFP_VRA_W4_VOICE_RECOGNITION_OFF: - hfp_connection->vra_state = HFP_VRA_VOICE_RECOGNITION_ACTIVATED; + hfp_connection->vra_status = HFP_VRA_VOICE_RECOGNITION_ACTIVATED; break; case HFP_VRA_W4_ENHANCED_VOICE_RECOGNITION_OFF: - hfp_connection->vra_state = HFP_VRA_ENHANCED_VOICE_RECOGNITION_ACTIVATED; + hfp_connection->vra_status = HFP_VRA_ENHANCED_VOICE_RECOGNITION_ACTIVATED; break; case HFP_VRA_W4_VOICE_RECOGNITION_ACTIVATED: case HFP_VRA_W4_ENHANCED_VOICE_RECOGNITION_ACTIVATED: - hfp_connection->vra_state = HFP_VRA_VOICE_RECOGNITION_OFF; + hfp_connection->vra_status = HFP_VRA_VOICE_RECOGNITION_OFF; break; default: break; @@ -1701,12 +1701,12 @@ uint8_t hfp_hf_activate_voice_recognition_notification(hci_con_handle_t acl_hand return ERROR_CODE_COMMAND_DISALLOWED; } - switch (hfp_connection->vra_state){ + switch (hfp_connection->vra_status){ case HFP_VRA_VOICE_RECOGNITION_ACTIVATED: hfp_emit_event(hfp_connection, HFP_SUBEVENT_VOICE_RECOGNITION_STATUS, 1); break; case HFP_VRA_VOICE_RECOGNITION_OFF: - hfp_connection->vra_state = HFP_VRA_W4_VOICE_RECOGNITION_ACTIVATED; + hfp_connection->vra_status = HFP_VRA_W4_VOICE_RECOGNITION_ACTIVATED; hfp_hf_run_for_context(hfp_connection); break; default: @@ -1716,7 +1716,7 @@ uint8_t hfp_hf_activate_voice_recognition_notification(hci_con_handle_t acl_hand } -uint8_t hfp_hf_activate_start_enhanced_voice_recognition_session(hci_con_handle_t acl_handle){ +uint8_t hfp_hf_start_enhanced_voice_recognition_session(hci_con_handle_t acl_handle){ hfp_connection_t * hfp_connection = get_hfp_hf_connection_context_for_acl_handle(acl_handle); if (!hfp_connection) { log_error("HFP HF: ACL handle 0x%2x is not found.", acl_handle); @@ -1727,10 +1727,10 @@ uint8_t hfp_hf_activate_start_enhanced_voice_recognition_session(hci_con_handle_ return ERROR_CODE_COMMAND_DISALLOWED; } - switch (hfp_connection->vra_state){ + switch (hfp_connection->vra_status){ case HFP_VRA_ENHANCED_VOICE_RECOGNITION_ACTIVATED: case HFP_VRA_VOICE_RECOGNITION_OFF: - hfp_connection->vra_state = HFP_VRA_W4_ENHANCED_VOICE_RECOGNITION_ACTIVATED; + hfp_connection->vra_status = HFP_VRA_W4_ENHANCED_VOICE_RECOGNITION_ACTIVATED; hfp_hf_run_for_context(hfp_connection); break; default: @@ -1740,16 +1740,16 @@ uint8_t hfp_hf_activate_start_enhanced_voice_recognition_session(hci_con_handle_ } static uint8_t hfp_hf_deactivate_voice_recognition(hfp_connection_t * hfp_connection){ - switch (hfp_connection->vra_state){ + switch (hfp_connection->vra_status){ case HFP_VRA_VOICE_RECOGNITION_OFF: hfp_emit_event(hfp_connection, HFP_SUBEVENT_VOICE_RECOGNITION_STATUS, 0); break; case HFP_VRA_VOICE_RECOGNITION_ACTIVATED: - hfp_connection->vra_state = HFP_VRA_W4_VOICE_RECOGNITION_OFF; + hfp_connection->vra_status = HFP_VRA_W4_VOICE_RECOGNITION_OFF; hfp_hf_run_for_context(hfp_connection); break; case HFP_VRA_ENHANCED_VOICE_RECOGNITION_ACTIVATED: - hfp_connection->vra_state = HFP_VRA_W4_ENHANCED_VOICE_RECOGNITION_OFF; + hfp_connection->vra_status = HFP_VRA_W4_ENHANCED_VOICE_RECOGNITION_OFF; hfp_hf_run_for_context(hfp_connection); break; default: @@ -1772,7 +1772,7 @@ uint8_t hfp_hf_deactivate_voice_recognition_notification(hci_con_handle_t acl_ha } -uint8_t hfp_hf_deactivate_enhanced_voice_recognition_notification(hci_con_handle_t acl_handle){ +uint8_t hfp_hf_stop_enhanced_voice_recognition_session(hci_con_handle_t acl_handle){ hfp_connection_t * hfp_connection = get_hfp_hf_connection_context_for_acl_handle(acl_handle); if (!hfp_connection) { log_error("HFP HF: ACL handle 0x%2x is not found.", acl_handle); diff --git a/src/classic/hfp_hf.h b/src/classic/hfp_hf.h index a23bbce04..96f15089b 100644 --- a/src/classic/hfp_hf.h +++ b/src/classic/hfp_hf.h @@ -324,9 +324,9 @@ uint8_t hfp_hf_activate_voice_recognition_notification(hci_con_handle_t acl_hand */ uint8_t hfp_hf_deactivate_voice_recognition_notification(hci_con_handle_t acl_handle); -uint8_t hfp_hf_activate_start_enhanced_voice_recognition_session(hci_con_handle_t acl_handle); +uint8_t hfp_hf_start_enhanced_voice_recognition_session(hci_con_handle_t acl_handle); -uint8_t hfp_hf_deactivate_enhanced_voice_recognition_notification(hci_con_handle_t acl_handle); +uint8_t hfp_hf_stop_enhanced_voice_recognition_session(hci_con_handle_t acl_handle); /* * @brief Set microphone gain. diff --git a/test/pts/hfp_hf_test.c b/test/pts/hfp_hf_test.c index f2996d80a..ce8828856 100644 --- a/test/pts/hfp_hf_test.c +++ b/test/pts/hfp_hf_test.c @@ -315,12 +315,12 @@ static void stdin_process(char c){ case 'r': log_info("USER:\'%c\'", cmd); printf("Deactivate enhanced voice recognition\n"); - hfp_hf_deactivate_enhanced_voice_recognition_notification(acl_handle); + hfp_hf_stop_enhanced_voice_recognition_session(acl_handle); break; case 'R': log_info("USER:\'%c\'", cmd); printf("Activate enhanced voice recognition %s\n", bd_addr_to_str(device_addr)); - hfp_hf_activate_start_enhanced_voice_recognition_session(acl_handle); + hfp_hf_start_enhanced_voice_recognition_session(acl_handle); break; case 'o':