From b95cac54e24879273ad0f4f5455476272ffbba09 Mon Sep 17 00:00:00 2001 From: Milanka Ringwald Date: Thu, 8 Jul 2021 16:21:08 +0200 Subject: [PATCH] hfp: handle AG send EVR message --- example/hfp_ag_demo.c | 41 ++++++++++++++++++--------- example/hfp_hf_demo.c | 7 ++++- src/classic/hfp.c | 27 +----------------- src/classic/hfp.h | 8 ++---- src/classic/hfp_ag.c | 66 ++++++++++++++++++++++++++++--------------- src/classic/hfp_ag.h | 2 +- src/classic/hfp_hf.c | 33 +++++++++++++++++++++- 7 files changed, 113 insertions(+), 71 deletions(-) diff --git a/example/hfp_ag_demo.c b/example/hfp_ag_demo.c index 76302b846..2ccacb941 100644 --- a/example/hfp_ag_demo.c +++ b/example/hfp_ag_demo.c @@ -106,6 +106,10 @@ static hfp_generic_status_indicator_t hf_indicators[] = { {2, 1}, }; +static hfp_voice_recognition_message_t msg = { + 0xABCD, HFP_TEXT_TYPE_MESSAGE_FROM_AG, HFP_TEXT_OPERATION_REPLACE, "test message" +}; + #define INQUIRY_INTERVAL 5 enum STATE {INIT, W4_INQUIRY_MODE_COMPLETE, ACTIVE} ; @@ -168,7 +172,7 @@ static void show_usage(void){ printf("n - Disable Voice Recognition | N - Enable Voice Recognition\n"); printf("z - Disable Enhanced Voice Recognition | Z - Enable Enhanced Voice Recognition\n"); printf("1 - EVR report starting sound | 2 - EVR report ready for input\n"); - printf("3 - EVR report processing input | 4 - EVR report message\n"); + printf("3 - EVR report processing input | 4 - EVR send message\n"); printf("o - Set speaker volume to 0 (minimum) | O - Set speaker volume to 9 (default)\n"); printf("p - Set speaker volume to 12 (higher) | P - Set speaker volume to 15 (maximum)\n"); @@ -353,8 +357,8 @@ static void stdin_process(char cmd){ break; case '4': log_info("USER:\'%c\'", cmd); - printf("Enhanced_Voice Recognition: report message\n"); - // status = hfp_ag_enhanced_voice_recognition_report_message(acl_handle); + printf("Enhanced_Voice Recognition: send message\n"); + status = hfp_ag_enhanced_voice_recognition_send_message(acl_handle, HFP_VOICE_RECOGNITION_STATE_AG_READY_TO_ACCEPT_AUDIO_INPUT, msg); break; case 'o': @@ -592,37 +596,46 @@ static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t * even 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 READY FOR AUDIO cmd failed\n"); + printf("Enhanced Voice recognition: READY FOR AUDIO cmd failed\n"); break; } - printf("\nEnhanced Voice recognition status READY FOR AUDIO\n\n"); + printf("\nEnhanced Voice recognition: READY FOR AUDIO\n\n"); break; case HFP_SUBEVENT_ENHANCED_VOICE_RECOGNITION_AG_READY_TO_ACCEPT_AUDIO_INPUT: - status = hfp_subevent_enhanced_voice_recognition_hf_ready_for_audio_get_status(event); + status = hfp_subevent_enhanced_voice_recognition_ag_ready_to_accept_audio_input_get_status(event); if (status != ERROR_CODE_SUCCESS){ - printf("Enhanced Voice recognition AG READY TO ACCEPT AUDIO INPU cmd failed\n"); + printf("Enhanced Voice recognition: AG READY TO ACCEPT AUDIO INPU cmd failed\n"); break; } - printf("\nEnhanced Voice recognition AG status: AG READY TO ACCEPT AUDIO INPUT\n\n"); + printf("\nEnhanced Voice recognition: AG READY TO ACCEPT AUDIO INPUT\n\n"); break; case HFP_SUBEVENT_ENHANCED_VOICE_RECOGNITION_AG_IS_STARTING_SOUND: - status = hfp_subevent_enhanced_voice_recognition_hf_ready_for_audio_get_status(event); + status = hfp_subevent_enhanced_voice_recognition_ag_is_starting_sound_get_status(event); if (status != ERROR_CODE_SUCCESS){ - printf("Enhanced Voice recognition AG IS STARTING SOUND cmd failed\n"); + printf("Enhanced Voice recognition: AG IS STARTING SOUND cmd failed\n"); break; } - printf("\nEnhanced Voice recognition AG status: AG IS STARTING SOUND\n\n"); + printf("\nEnhanced Voice recognition: AG IS STARTING SOUND\n\n"); break; case HFP_SUBEVENT_ENHANCED_VOICE_RECOGNITION_AG_IS_PROCESSING_AUDIO_INPUT: - status = hfp_subevent_enhanced_voice_recognition_hf_ready_for_audio_get_status(event); + status = hfp_subevent_enhanced_voice_recognition_ag_is_processing_audio_input_get_status(event); if (status != ERROR_CODE_SUCCESS){ - printf("Enhanced Voice recognition AG IS PROCESSING AUDIO INPUT cmd failed\n"); + printf("Enhanced Voice recognition: AG IS PROCESSING AUDIO INPUT cmd failed\n"); break; } - printf("\nEnhanced Voice recognition AG status: AG IS PROCESSING AUDIO INPUT\n\n"); + printf("\nEnhanced Voice recognition: AG IS PROCESSING AUDIO INPUT\n\n"); + break; + + case HFP_SUBEVENT_ENHANCED_VOICE_RECOGNITION_AG_MESSAGE_SENT: + status = hfp_subevent_enhanced_voice_recognition_ag_message_sent_get_status(event); + if (status != ERROR_CODE_SUCCESS){ + printf("Enhanced Voice recognition: AG SEND MSG cmd failed\n"); + break; + } + printf("\nEnhanced Voice recognition: AG SEND MSG \'%s\'\n\n", msg.text); break; default: diff --git a/example/hfp_hf_demo.c b/example/hfp_hf_demo.c index 9ff213779..72634d761 100644 --- a/example/hfp_hf_demo.c +++ b/example/hfp_hf_demo.c @@ -617,7 +617,12 @@ static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t * even case HFP_SUBEVENT_ENHANCED_VOICE_RECOGNITION_AG_IS_PROCESSING_AUDIO_INPUT: printf("\nEnhanced Voice recognition AG status: AG IS PROCESSING AUDIO INPUT\n\n"); break; - + + case HFP_SUBEVENT_ENHANCED_VOICE_RECOGNITION_AG_MESSAGE: + printf("\nEnhanced Voice recognition AG message: \'%s\'\n", hfp_subevent_enhanced_voice_recognition_ag_message_get_text(event)); + + break; + default: break; } diff --git a/src/classic/hfp.c b/src/classic/hfp.c index bfb0f81e4..9e05adbc3 100644 --- a/src/classic/hfp.c +++ b/src/classic/hfp.c @@ -405,7 +405,6 @@ void hfp_emit_enhanced_voice_recognition_state_event(hfp_connection_t * hfp_conn default: btstack_unreachable(); break; - } little_endian_store_16(event, 3, acl_handle); @@ -477,30 +476,6 @@ 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_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_msg.text_id); - pos += 2; - event[pos++] = hfp_connection->ag_msg.text_operation; - event[pos++] = hfp_connection->ag_msg.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; } @@ -1712,7 +1687,7 @@ static void parse_sequence(hfp_connection_t * hfp_connection){ hfp_connection->ag_msg.text_type = (hfp_text_type_t) btstack_atoi((char *)&hfp_connection->line_buffer[0]); break; case 5: - hfp_emit_enhanced_voice_recognition_text(hfp_connection, hfp_connection->line_size, &hfp_connection->line_buffer[0]); + hfp_connection->ag_vra_msg_length = hfp_connection->line_size; break; default: break; diff --git a/src/classic/hfp.h b/src/classic/hfp.h index a6e0b6aee..ede2389e4 100644 --- a/src/classic/hfp.h +++ b/src/classic/hfp.h @@ -402,17 +402,14 @@ typedef enum { HFP_VRA_ENHANCED_VOICE_RECOGNITION_READY_FOR_AUDIO, HFP_VRA_W2_SEND_ENHANCED_VOICE_RECOGNITION_STATUS, - HFP_VRA_W4_ENHANCED_VOICE_RECOGNITION_STATUS, - - // TODO delete - HFP_VRA_W2_SEND_ENHANCED_VOICE_RECOGNITION_MSG, + HFP_VRA_W2_SEND_ENHANCED_VOICE_RECOGNITION_MSG } hfp_voice_recognition_activation_status_t; typedef struct { uint16_t text_id; hfp_text_type_t text_type; hfp_text_operation_t text_operation; - uint8_t * text; + const char * text; } hfp_voice_recognition_message_t; typedef enum { @@ -695,6 +692,7 @@ typedef struct hfp_connection { uint8_t ag_vra_status; hfp_voice_recognition_state_t ag_vra_state; hfp_voice_recognition_message_t ag_msg; + uint16_t ag_vra_msg_length; uint8_t clcc_idx; uint8_t clcc_dir; diff --git a/src/classic/hfp_ag.c b/src/classic/hfp_ag.c index f3339f534..2333c8634 100644 --- a/src/classic/hfp_ag.c +++ b/src/classic/hfp_ag.c @@ -815,6 +815,18 @@ static bool hfp_ag_is_audio_connection_active(hfp_connection_t * hfp_connection) } } +static void hfp_ag_emit_enhanced_voice_recognition_msg_sent_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_AG_TEXT_SENT; + little_endian_store_16(event, 3, acl_handle); + event[5] = status; + (*hfp_ag_callback)(HCI_EVENT_PACKET, 0, event, sizeof(event)); +} + static int hfp_ag_voice_recognition_state_machine(hfp_connection_t * hfp_connection){ if (hfp_connection->state < HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED) { return 0; @@ -825,6 +837,16 @@ static int hfp_ag_voice_recognition_state_machine(hfp_connection_t * hfp_connect switch (hfp_connection->command){ case HFP_CMD_AG_ACTIVATE_VOICE_RECOGNITION: switch (hfp_connection->vra_state_requested){ + case HFP_VRA_W2_SEND_ENHANCED_VOICE_RECOGNITION_MSG: + done = hfp_ag_send_enhanced_voice_recognition_msg_cmd(hfp_connection); + if (done == 0){ + hfp_ag_emit_enhanced_voice_recognition_msg_sent_event(hfp_connection, ERROR_CODE_UNSPECIFIED_ERROR); + } else { + hfp_ag_emit_enhanced_voice_recognition_msg_sent_event(hfp_connection, ERROR_CODE_SUCCESS); + } + hfp_connection->vra_state_requested = hfp_connection->vra_state; + return done; + case HFP_VRA_W2_SEND_ENHANCED_VOICE_RECOGNITION_STATUS: done = hfp_ag_send_enhanced_voice_recognition_state_cmd(hfp_connection); if (done == 0){ @@ -833,7 +855,8 @@ static int hfp_ag_voice_recognition_state_machine(hfp_connection_t * hfp_connect hfp_emit_enhanced_voice_recognition_state_event(hfp_connection, ERROR_CODE_SUCCESS); } hfp_connection->vra_state_requested = hfp_connection->vra_state; - break; + return done; + default: done = hfp_ag_send_voice_recognition_cmd(hfp_connection, hfp_connection->ag_activate_voice_recognition_value); if (done == 0){ @@ -926,11 +949,6 @@ static int hfp_ag_voice_recognition_state_machine(hfp_connection_t * hfp_connect hfp_emit_voice_recognition_state_event(hfp_connection, ERROR_CODE_SUCCESS); break; - case HFP_VRA_W2_SEND_ENHANCED_VOICE_RECOGNITION_MSG: - hfp_connection->ag_vra_status = HFP_VRA_VOICE_RECOGNITION_ACTIVATED; - done = hfp_ag_send_enhanced_voice_recognition_msg_cmd(hfp_connection); - break; - default: break; } @@ -2743,23 +2761,6 @@ uint8_t hfp_ag_deactivate_enhanced_voice_recognition(hci_con_handle_t acl_handle return deactivate_voice_recognition(acl_handle, true); } -uint8_t hfp_ag_enhanced_voice_recognition_report_message(hci_con_handle_t acl_handle, hfp_voice_recognition_state_t state, hfp_voice_recognition_message_t msg){ - hfp_connection_t * hfp_connection = get_hfp_ag_connection_context_for_acl_handle(acl_handle); - if (!hfp_connection){ - return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; - } - - uint8_t status = hfp_ag_can_send_enahnced_voice_recognition_message(hfp_connection, true); - if (status == ERROR_CODE_SUCCESS){ - hfp_connection->command = HFP_CMD_AG_ACTIVATE_VOICE_RECOGNITION; - hfp_connection->vra_state_requested = HFP_VRA_W2_SEND_ENHANCED_VOICE_RECOGNITION_STATUS; - hfp_connection->ag_msg = msg; - hfp_connection->ag_vra_state = state; - hfp_ag_run_for_context(hfp_connection); - } - return status; -} - static uint8_t hfp_ag_enhanced_voice_recognition_send_state(hci_con_handle_t acl_handle, hfp_voice_recognition_state_t state){ hfp_connection_t * hfp_connection = get_hfp_ag_connection_context_for_acl_handle(acl_handle); if (!hfp_connection){ @@ -2786,6 +2787,25 @@ uint8_t hfp_ag_enhanced_voice_recognition_report_processing_input(hci_con_handle return hfp_ag_enhanced_voice_recognition_send_state(acl_handle, HFP_VOICE_RECOGNITION_STATE_AG_IS_PROCESSING_AUDIO_INPUT); } + +uint8_t hfp_ag_enhanced_voice_recognition_send_message(hci_con_handle_t acl_handle, hfp_voice_recognition_state_t state, hfp_voice_recognition_message_t msg){ + hfp_connection_t * hfp_connection = get_hfp_ag_connection_context_for_acl_handle(acl_handle); + if (!hfp_connection){ + return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; + } + + uint8_t status = hfp_ag_can_send_enahnced_voice_recognition_message(hfp_connection, true); + if (status == ERROR_CODE_SUCCESS){ + hfp_connection->command = HFP_CMD_AG_ACTIVATE_VOICE_RECOGNITION; + hfp_connection->vra_state_requested = HFP_VRA_W2_SEND_ENHANCED_VOICE_RECOGNITION_MSG; + hfp_connection->ag_msg = msg; + hfp_connection->ag_vra_state = state; + hfp_ag_run_for_context(hfp_connection); + } + return status; +} + + uint8_t hfp_ag_set_microphone_gain(hci_con_handle_t acl_handle, int gain){ hfp_connection_t * hfp_connection = get_hfp_ag_connection_context_for_acl_handle(acl_handle); if (!hfp_connection){ diff --git a/src/classic/hfp_ag.h b/src/classic/hfp_ag.h index d542c9b60..495ac1b8c 100644 --- a/src/classic/hfp_ag.h +++ b/src/classic/hfp_ag.h @@ -339,7 +339,7 @@ uint8_t hfp_ag_enhanced_voice_recognition_report_processing_input(hci_con_handle * - ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER if connection does not exist, or * - ERROR_CODE_COMMAND_DISALLOWED if AG or HF does not support enhanced voice recognition */ -uint8_t hfp_ag_enhanced_voice_recognition_report_message(hci_con_handle_t acl_handle, hfp_voice_recognition_state_t state, hfp_voice_recognition_message_t msg); +uint8_t hfp_ag_enhanced_voice_recognition_send_message(hci_con_handle_t acl_handle, hfp_voice_recognition_state_t state, hfp_voice_recognition_message_t msg); /** * @brief Deactivate enhanced voice recognition (EVR) and emit HFP_SUBEVENT_ENHANCED_VOICE_RECOGNITION_STATUS event with status ERROR_CODE_SUCCESS diff --git a/src/classic/hfp_hf.c b/src/classic/hfp_hf.c index 4ee72d6f9..5e6560de5 100644 --- a/src/classic/hfp_hf.c +++ b/src/classic/hfp_hf.c @@ -212,6 +212,33 @@ static void hfp_emit_network_operator_event(const hfp_connection_t * hfp_connect (*hfp_hf_callback)(HCI_EVENT_PACKET, 0, event, sizeof(event)); } + +static void hfp_hf_emit_enhanced_voice_recognition_text(hfp_connection_t * hfp_connection){ + 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_AG_MESSAGE; + little_endian_store_16(event, pos, hfp_connection->acl_handle); + pos += 2; + little_endian_store_16(event, pos, hfp_connection->ag_msg.text_id); + pos += 2; + event[pos++] = hfp_connection->ag_msg.text_operation; + event[pos++] = hfp_connection->ag_msg.text_type; + + // length, zero ending + uint16_t value_length = hfp_connection->ag_vra_msg_length; + uint8_t * value = &hfp_connection->line_buffer[0]; + 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_hf_callback)(HCI_EVENT_PACKET, 0, event, pos); +} + /* send commands */ static inline int hfp_hf_send_cmd(uint16_t cid, const char * cmd){ @@ -495,7 +522,11 @@ static int hfp_hf_voice_recognition_state_machine(hfp_connection_t * hfp_connect return 0; default: - printf("status %d state %d\n", hfp_connection->ag_vra_status, hfp_connection->ag_vra_state); + if (hfp_connection->ag_vra_msg_length > 0){ + hfp_hf_emit_enhanced_voice_recognition_text(hfp_connection); + hfp_connection->ag_vra_msg_length = 0; + break; + } switch(hfp_connection->ag_vra_state){ case HFP_VOICE_RECOGNITION_STATE_AG_READY: switch (hfp_connection->ag_vra_status){