hfp_ag: enhanced voice recognition

This commit is contained in:
Milanka Ringwald 2021-04-28 14:44:38 +02:00 committed by Matthias Ringwald
parent db3cdbd454
commit 45796ff1c6
6 changed files with 263 additions and 32 deletions

View File

@ -436,10 +436,10 @@ static void hfp_emit_enhanced_voice_recognition_text(hfp_connection_t * hfp_conn
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);
little_endian_store_16(event, pos, hfp_connection->ag_msg.text_id);
pos += 2;
event[pos++] = hfp_connection->ag_text_operation;
event[pos++] = hfp_connection->ag_text_type;
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);
@ -1621,17 +1621,16 @@ static void parse_sequence(hfp_connection_t * hfp_connection){
hfp_emit_enhanced_voice_recognition_state(hfp_connection);
break;
case 2:
hfp_connection->ag_text_id = 0;
hfp_connection->ag_msg.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]);
hfp_connection->ag_msg.text_id = (hfp_connection->ag_msg.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]);
hfp_connection->ag_msg.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]);
hfp_connection->ag_msg.text_type = btstack_atoi((char *)&hfp_connection->line_buffer[0]);
break;
case 5:
printf("text%s\n", hfp_connection->line_buffer);

View File

@ -206,8 +206,8 @@ 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_AG_ACTIVATE_ENHANCED_VOICE_RECOGNITION,
HFP_CMD_HF_REQUEST_PHONE_NUMBER,
HFP_CMD_AG_SENT_PHONE_NUMBER,
HFP_CMD_TRANSMIT_DTMF_CODES,
@ -316,7 +316,8 @@ typedef enum {
} hfp_parser_state_t;
typedef enum {
HFP_VOICE_RECOGNITION_STATE_AG_READY_TO_ACCEPT_AUDIO_INPUT = 0,
HFP_VOICE_RECOGNITION_STATE_AG_READY = 0,
HFP_VOICE_RECOGNITION_STATE_AG_READY_TO_ACCEPT_AUDIO_INPUT = 1,
HFP_VOICE_RECOGNITION_STATE_AG_IS_SENDING_AUDIO_TO_HF = 2,
HFP_VOICE_RECOGNITION_STATE_AG_IS_PROCESSING_AUDIO_INPUT = 4
} hfp_voice_recognition_state_t;
@ -397,10 +398,19 @@ typedef enum {
HFP_VRA_W4_ENHANCED_VOICE_RECOGNITION_OFF,
HFP_VRA_W4_ENHANCED_VOICE_RECOGNITION_ACTIVATED,
HFP_VRA_W4_ENHANCED_VOICE_RECOGNITION_STATUS,
HFP_VRA_W4_ENHANCED_VOICE_RECOGNITION_MSG,
HFP_VRA_W4_ENHANCED_VOICE_RECOGNITION_NEW_SESSION,
HFP_VRA_ENHANCED_VOICE_RECOGNITION_ACTIVATED
} 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;
} hfp_voice_recognition_message_t;
typedef enum {
HFP_CODECS_IDLE,
HFP_CODECS_RECEIVED_LIST,
@ -672,9 +682,8 @@ typedef struct hfp_connection {
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;
hfp_voice_recognition_message_t ag_msg;
uint8_t clcc_idx;
uint8_t clcc_dir;

View File

@ -509,6 +509,23 @@ static int hfp_ag_send_set_response_and_hold(uint16_t cid, int state){
return hfp_ag_send_cmd_with_space_and_int(cid, HFP_RESPONSE_AND_HOLD, state);
}
static int hfp_ag_send_enhanced_voice_recognition_cmd(uint16_t cid, uint8_t status, uint8_t state){
char buffer[30];
snprintf(buffer, sizeof(buffer), "\r\n%s: %d,%d\r\n", HFP_ACTIVATE_VOICE_RECOGNITION, status, state);
return send_str_over_rfcomm(cid, buffer);
}
static int hfp_ag_send_enhanced_voice_recognition_msg_cmd(hfp_connection_t *hfp_connection){
char buffer[100];
snprintf(buffer, sizeof(buffer), "\r\n%s: 1,%d,%X,%d,%d,\"%s\"\r\n", HFP_ACTIVATE_VOICE_RECOGNITION,
hfp_connection->ag_vra_state,
hfp_connection->ag_msg.text_id,
hfp_connection->ag_msg.text_type,
hfp_connection->ag_msg.text_operation,
hfp_connection->ag_msg.text);
return send_str_over_rfcomm(hfp_connection->rfcomm_cid, buffer);
}
static uint8_t hfp_ag_suggest_codec(hfp_connection_t *hfp_connection){
if (hfp_connection->sco_for_msbc_failed) return HFP_CODEC_CVSD;
@ -741,11 +758,45 @@ static int hfp_ag_run_for_context_service_level_connection_queries(hfp_connectio
hfp_release_audio_connection(hfp_connection);
}
return 1;
case HFP_CMD_AG_ACTIVATE_ENHANCED_VOICE_RECOGNITION:
switch (hfp_connection->ag_vra_status){
case HFP_VRA_W4_ENHANCED_VOICE_RECOGNITION_ACTIVATED:
hfp_connection->ag_vra_status = HFP_VRA_ENHANCED_VOICE_RECOGNITION_ACTIVATED;
hfp_ag_send_enhanced_voice_recognition_cmd(hfp_connection->rfcomm_cid, 1, hfp_connection->ag_vra_state);
hfp_ag_setup_audio_connection(hfp_connection);
break;
case HFP_VRA_W4_ENHANCED_VOICE_RECOGNITION_STATUS:
hfp_connection->ag_vra_status = HFP_VRA_ENHANCED_VOICE_RECOGNITION_ACTIVATED;
hfp_ag_send_enhanced_voice_recognition_cmd(hfp_connection->rfcomm_cid, 1, hfp_connection->ag_vra_state);
break;
case HFP_VRA_W4_ENHANCED_VOICE_RECOGNITION_OFF:
hfp_connection->ag_vra_status = HFP_VRA_VOICE_RECOGNITION_OFF;
hfp_ag_send_enhanced_voice_recognition_cmd(hfp_connection->rfcomm_cid, 0, hfp_connection->ag_vra_state);
hfp_release_audio_connection(hfp_connection);
break;
case HFP_VRA_W4_ENHANCED_VOICE_RECOGNITION_MSG:
hfp_connection->ag_vra_status = HFP_VRA_ENHANCED_VOICE_RECOGNITION_ACTIVATED;
hfp_ag_send_enhanced_voice_recognition_msg_cmd(hfp_connection);
break;
default:
return 0;
}
return 1;
case HFP_CMD_HF_ACTIVATE_VOICE_RECOGNITION:
if (get_bit(hfp_supported_features, HFP_AGSF_VOICE_RECOGNITION_FUNCTION)){
hfp_ag_send_ok(hfp_connection->rfcomm_cid);
} else {
hfp_ag_send_error(hfp_connection->rfcomm_cid);
switch (hfp_connection->ag_vra_status){
case HFP_VRA_ENHANCED_VOICE_RECOGNITION_ACTIVATED:
hfp_ag_send_ok(hfp_connection->rfcomm_cid);
break;
default:
hfp_ag_send_error(hfp_connection->rfcomm_cid);
break;
}
}
return 1;
case HFP_CMD_CHANGE_IN_BAND_RING_TONE_SETTING:
@ -1951,6 +2002,11 @@ static void hfp_ag_handle_rfcomm_data(uint8_t packet_type, uint16_t channel, uin
hfp_generic_status_indicator_t * indicator;
switch(hfp_connection->command){
case HFP_CMD_HF_ACTIVATE_VOICE_RECOGNITION:
if (hfp_connection->ag_activate_voice_recognition == 0){
hfp_release_audio_connection(hfp_connection);
}
break;
case HFP_CMD_RESPONSE_AND_HOLD_QUERY:
if (hfp_ag_response_and_hold_active){
hfp_connection->send_response_and_hold_status = HFP_RESPONSE_AND_HOLD_INCOMING_ON_HOLD + 1;
@ -2466,6 +2522,81 @@ void hfp_ag_activate_voice_recognition(hci_con_handle_t acl_handle, int activate
hfp_ag_run_for_context(hfp_connection);
}
void hfp_ag_enhanced_voice_recognition_activate(hci_con_handle_t acl_handle){
if (!get_bit(hfp_supported_features, HFP_AGSF_VOICE_RECOGNITION_FUNCTION)) return;
hfp_connection_t * hfp_connection = get_hfp_ag_connection_context_for_acl_handle(acl_handle);
if (!hfp_connection){
log_error("HFP AG: ACL connection 0x%2x is not found.", acl_handle);
return;
}
if (!get_bit(hfp_connection->remote_supported_features, HFP_HFSF_VOICE_RECOGNITION_FUNCTION)) return;
hfp_connection->command = HFP_CMD_AG_ACTIVATE_ENHANCED_VOICE_RECOGNITION;
hfp_connection->ag_vra_state = HFP_VOICE_RECOGNITION_STATE_AG_READY;
hfp_connection->ag_vra_status = HFP_VRA_W4_ENHANCED_VOICE_RECOGNITION_ACTIVATED;
hfp_ag_run_for_context(hfp_connection);
}
void hfp_ag_enhanced_voice_recognition_deactivate(hci_con_handle_t acl_handle){
if (!get_bit(hfp_supported_features, HFP_AGSF_VOICE_RECOGNITION_FUNCTION)) return;
hfp_connection_t * hfp_connection = get_hfp_ag_connection_context_for_acl_handle(acl_handle);
if (!hfp_connection){
log_error("HFP AG: ACL connection 0x%2x is not found.", acl_handle);
return;
}
if (!get_bit(hfp_connection->remote_supported_features, HFP_HFSF_VOICE_RECOGNITION_FUNCTION)) return;
hfp_connection->command = HFP_CMD_AG_ACTIVATE_ENHANCED_VOICE_RECOGNITION;
hfp_connection->ag_vra_state = HFP_VOICE_RECOGNITION_STATE_AG_READY;
hfp_connection->ag_vra_status = HFP_VRA_W4_ENHANCED_VOICE_RECOGNITION_OFF;
hfp_ag_run_for_context(hfp_connection);
}
void hfp_ag_enhanced_voice_recognition_status(hci_con_handle_t acl_handle, hfp_voice_recognition_state_t state){
if (!get_bit(hfp_supported_features, HFP_AGSF_VOICE_RECOGNITION_FUNCTION)) return;
hfp_connection_t * hfp_connection = get_hfp_ag_connection_context_for_acl_handle(acl_handle);
if (!hfp_connection){
log_error("HFP AG: ACL connection 0x%2x is not found.", acl_handle);
return;
}
if (!get_bit(hfp_connection->remote_supported_features, HFP_HFSF_VOICE_RECOGNITION_FUNCTION)) return;
hfp_connection->command = HFP_CMD_AG_ACTIVATE_ENHANCED_VOICE_RECOGNITION;
hfp_connection->ag_vra_state = state;
hfp_connection->ag_vra_status = HFP_VRA_W4_ENHANCED_VOICE_RECOGNITION_STATUS;
hfp_ag_run_for_context(hfp_connection);
}
void hfp_ag_enhanced_voice_recognition_starting_sound(hci_con_handle_t acl_handle){
hfp_ag_enhanced_voice_recognition_status(acl_handle, HFP_VOICE_RECOGNITION_STATE_AG_IS_SENDING_AUDIO_TO_HF);
}
void hfp_ag_enhanced_voice_recognition_ready_for_input(hci_con_handle_t acl_handle){
hfp_ag_enhanced_voice_recognition_status(acl_handle, HFP_VOICE_RECOGNITION_STATE_AG_READY_TO_ACCEPT_AUDIO_INPUT);
}
void hfp_ag_enhanced_voice_recognition_processing_input(hci_con_handle_t acl_handle){
hfp_ag_enhanced_voice_recognition_status(acl_handle, HFP_VOICE_RECOGNITION_STATE_AG_IS_PROCESSING_AUDIO_INPUT);
}
void hfp_ag_enhanced_voice_recognition_message(hci_con_handle_t acl_handle, hfp_voice_recognition_state_t state, hfp_voice_recognition_message_t msg){
if (!get_bit(hfp_supported_features, HFP_AGSF_VOICE_RECOGNITION_FUNCTION)) return;
hfp_connection_t * hfp_connection = get_hfp_ag_connection_context_for_acl_handle(acl_handle);
if (!hfp_connection){
log_error("HFP AG: ACL connection 0x%2x is not found.", acl_handle);
return;
}
if (!get_bit(hfp_connection->remote_supported_features, HFP_HFSF_VOICE_RECOGNITION_FUNCTION)) return;
hfp_connection->command = HFP_CMD_AG_ACTIVATE_ENHANCED_VOICE_RECOGNITION;
hfp_connection->ag_vra_state = state;
hfp_connection->ag_vra_status = HFP_VRA_W4_ENHANCED_VOICE_RECOGNITION_MSG;
hfp_connection->ag_msg = msg;
hfp_ag_run_for_context(hfp_connection);
}
void 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){

View File

@ -245,6 +245,16 @@ void hfp_ag_notify_incoming_call_waiting(hci_con_handle_t acl_handle);
*/
void hfp_ag_activate_voice_recognition(hci_con_handle_t acl_handle, int activate);
void hfp_ag_enhanced_voice_recognition_activate(hci_con_handle_t acl_handle);
void hfp_ag_enhanced_voice_recognition_status(hci_con_handle_t acl_handle, hfp_voice_recognition_state_t state);
void hfp_ag_enhanced_voice_recognition_starting_sound(hci_con_handle_t acl_handle);
void hfp_ag_enhanced_voice_recognition_ready_for_input(hci_con_handle_t acl_handle);
void hfp_ag_enhanced_voice_recognition_processing_input(hci_con_handle_t acl_handle);
void hfp_ag_enhanced_voice_recognition_message(hci_con_handle_t acl_handle, hfp_voice_recognition_state_t state, hfp_voice_recognition_message_t msg);
void hfp_ag_enhanced_voice_recognition_deactivate(hci_con_handle_t acl_handle);
/*
* @brief Send a phone number back to the HF.
* @param bd_addr Bluetooth address of the HF

View File

@ -153,23 +153,23 @@ HFP/AG/IIC/BV-03-I: a, f, g, t
HFP/AG/HFI/BV-02-I: a, t
HFP/AG/HFI/BI-03-I: a, t
HFP/AG/EVR/BV-01-I:
HFP/AG/EVR/BV-02-I:
HFP/AG/EVR/BV-03-I:
HFP/AG/EVR/BV-01-I: a, 1, 2, 5, A
HFP/AG/EVR/BV-02-I: a, 1, 3, 5, A
HFP/AG/EVR/BV-03-I: a, 1, 4, 5, A
HFP/AG/VRT/BV-01-I:
HFP/AG/VRT/BV-02-I:
HFP/AG/VRT/BV-03-I:
HFP/AG/VRT/BV-04-I:
HFP/AG/VRT/BV-05-I:
HFP/AG/VRT/BV-06-I:
HFP/AG/VRT/BV-07-I:
HFP/AG/VRT/BV-08-I:
HFP/AG/VRT/BV-09-I:
HFP/AG/VRT/BV-01-I: a, 1, 6, 5, A
HFP/AG/VRT/BV-02-I: a, 1, 6, 7, 5, A
HFP/AG/VRT/BV-03-I: a, 1, 6, 7, 5, A
HFP/AG/VRT/BV-04-I: a, 1, 6, 8, 5, A
HFP/AG/VRT/BV-05-I: a, 1, 6, 9, 5, A
HFP/AG/VRT/BV-06-I: a, 1, 6, 5, A
HFP/AG/VRT/BV-07-I: a, 1, 7, 5, A
HFP/AG/VRT/BV-08-I: a, 1, *, 5, A
HFP/AG/VRT/BV-09-I: a, 1, @, 5, A
HFP/AG/VRR/BV-02-I:
HFP/AG/VRR/BV-02-I: a, 1, 5, A
HFP/AG/VTA/BV-02-I:
HFP/AG/VTA/BV-02-I: a, 1, 3, 2, 5, A
HFP/AG/ATAH/BV-01-I: a, c, B, B, b, C, A

View File

@ -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:1B:DC:08:E2:72";
static const char * device_addr_string = "00:1B:DC:08:E2:5C";
// configuration
static const int wide_band_speech = 1;
@ -164,7 +164,9 @@ static void show_usage(void){
printf("l - Clear last number | L - Set last number to 7654321\n");
printf("m - simulate incoming call from 7654321\n");
printf("M - simulate outgoing call to 1234567\n");
printf("n - Disable Voice Regocnition | N - Enable Voice Recognition\n");
printf("n - Disable Voice Recognition | N - Enable Voice Recognition\n");
printf("z - Disable Enhanced Voice Recognition | Z - Enable Enhanced Voice Recognition\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");
printf("q - Set microphone gain to 0 (minimum) | Q - Set microphone gain to 9 (default)\n");
@ -327,6 +329,86 @@ static void stdin_process(char cmd){
printf("Enable Voice Recognition\n");
hfp_ag_activate_voice_recognition(acl_handle, 1);
break;
case '1':
printf("Enable Enhanced Voice Recognition\n");
hfp_ag_enhanced_voice_recognition_activate(acl_handle);
break;
case '2':
printf("EVR Status ready_for_input\n");
hfp_ag_enhanced_voice_recognition_ready_for_input(acl_handle);
break;
case '3':
printf("EVR Send audio outputt\n");
hfp_ag_enhanced_voice_recognition_starting_sound(acl_handle);
break;
case '4':
printf("EVR Processing Input\n");
hfp_ag_enhanced_voice_recognition_processing_input(acl_handle);
break;
case '5':
printf("Disable Enhanced Voice Recognition\n");
hfp_ag_enhanced_voice_recognition_deactivate(acl_handle);
break;
case '6':{
hfp_voice_recognition_message_t msg = {
0xAB13, 0, 1, (uint8_t *) "test"
};
printf("EVR Msg, Status ready_for_input\n");
hfp_ag_enhanced_voice_recognition_message(acl_handle, HFP_VOICE_RECOGNITION_STATE_AG_READY_TO_ACCEPT_AUDIO_INPUT, msg);
break;
}
case '7':{
// changed type, change iD
hfp_voice_recognition_message_t msg = {
0xAB14, 1, 1, (uint8_t *) "test"
};
printf("EVR Msg Processing Input\n");
hfp_ag_enhanced_voice_recognition_message(acl_handle, HFP_VOICE_RECOGNITION_STATE_AG_IS_PROCESSING_AUDIO_INPUT, msg);
break;
}
case '8':{
// replace op, leave id and type
hfp_voice_recognition_message_t msg = {
0xAB13, 0, 2, (uint8_t *) "test"
};
printf("EVR Msg Processing Input\n");
hfp_ag_enhanced_voice_recognition_message(acl_handle, HFP_VOICE_RECOGNITION_STATE_AG_IS_PROCESSING_AUDIO_INPUT, msg);
break;
}
case '9':{
// replace op, leave id and type
hfp_voice_recognition_message_t msg = {
0xAB13, 0, 3, (uint8_t *) "test"
};
printf("EVR Msg Processing Input\n");
hfp_ag_enhanced_voice_recognition_message(acl_handle, HFP_VOICE_RECOGNITION_STATE_AG_IS_PROCESSING_AUDIO_INPUT, msg);
break;
}
case '*':{
hfp_voice_recognition_message_t msg = {
0xAB13, 2, 1, (uint8_t *) "test"
};
printf("EVR Msg, Status ready_for_input\n");
hfp_ag_enhanced_voice_recognition_message(acl_handle, HFP_VOICE_RECOGNITION_STATE_AG_READY_TO_ACCEPT_AUDIO_INPUT, msg);
break;
}
case '@':{
hfp_voice_recognition_message_t msg = {
0xAB13, 3, 1, (uint8_t *) "test"
};
printf("EVR Msg, Status ready_for_input\n");
hfp_ag_enhanced_voice_recognition_message(acl_handle, HFP_VOICE_RECOGNITION_STATE_AG_READY_TO_ACCEPT_AUDIO_INPUT, msg);
break;
}
case 'o':
log_info("USER:\'%c\'", cmd);
printf("Set speaker gain to 0 (minimum)\n");
@ -595,8 +677,8 @@ int btstack_main(int argc, const char * argv[]){
(1<<HFP_AGSF_VOICE_RECOGNITION_FUNCTION) |
(1<<HFP_AGSF_THREE_WAY_CALLING) |
(1<<HFP_AGSF_ATTACH_A_NUMBER_TO_A_VOICE_TAG) |
(1<<HFP_HFSF_ENHANCED_VOICE_RECOGNITION_STATUS) |
(1<<HFP_HFSF_VOICE_RECOGNITION_TEXT);
(1<<HFP_AGSF_ENHANCED_VOICE_RECOGNITION_STATUS) |
(1<<HFP_AGSF_VOICE_RECOGNITION_TEXT);
// HFP
rfcomm_init();