hfp_ag: release audio connection only if it was opened before audio VR activated, open audio only if connection does not already exist

This commit is contained in:
Milanka Ringwald 2021-07-02 14:42:06 +02:00
parent 734ef2bdf5
commit 0b4debbf1d
6 changed files with 145 additions and 80 deletions

View File

@ -542,17 +542,19 @@ static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t * even
printf("Voice Recognition command failed with status 0x%02x\n", status);
break;
}
printf("\n");
switch(hfp_subevent_voice_recognition_status_get_state(event)){
case 0:
printf("Voice recognition status deactivated\n");
case HFP_VRA_VOICE_RECOGNITION_OFF:
printf("Voice recognition status DEACTIVATED\n");
break;
case 1:
printf("Voice recognition status activated\n");
case HFP_VRA_VOICE_RECOGNITION_ACTIVATED:
printf("Voice recognition status ACTIVATED\n");
break;
default:
btstack_assert(false);
break;
}
printf("\n");
break;
default:
break;

View File

@ -507,7 +507,7 @@ static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t * even
printf("Audio connection released\n");
sco_demo_close();
break;
case HFP_SUBEVENT_COMPLETE:
case HFP_SUBEVENT_COMPLETE:
status = hfp_subevent_complete_get_status(event);
if (status == ERROR_CODE_SUCCESS){
printf("Cmd \'%c\' succeeded\n", cmd);
@ -546,7 +546,7 @@ static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t * even
break;
case HFP_SUBEVENT_MICROPHONE_VOLUME:
printf("Microphone volume: gain %u\n",
hfp_subevent_microphone_volume_get_gain(event));
hfp_subevent_microphone_volume_get_gain(event));
break;
case HFP_SUBEVENT_CALLING_LINE_IDENTIFICATION_NOTIFICATION:
printf("Caller ID, number %s\n", hfp_subevent_calling_line_identification_notification_get_number(event));
@ -567,17 +567,20 @@ static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t * even
printf("Voice Recognition command failed with status 0x%02x\n", status);
break;
}
printf("\n");
switch(hfp_subevent_voice_recognition_status_get_state(event)){
case 0:
printf("Voice recognition status deactivated\n");
case HFP_VRA_VOICE_RECOGNITION_OFF:
printf("Voice recognition status DEACTIVATED\n");
break;
case 1:
printf("Voice recognition status activated\n");
case HFP_VRA_VOICE_RECOGNITION_ACTIVATED:
printf("Voice recognition status ACTIVATED\n");
break;
default:
printf("Voice recognition status unexpected state %d\n", hfp_subevent_voice_recognition_status_get_state(event));
btstack_assert(false);
break;
}
printf("\n");
break;
default:
break;

View File

@ -869,6 +869,14 @@ void hfp_handle_hci_event(uint8_t packet_type, uint16_t channel, uint8_t *packet
hfp_connection->sco_handle = sco_handle;
hfp_connection->establish_audio_connection = 0;
hfp_connection->state = HFP_AUDIO_CONNECTION_ESTABLISHED;
switch (hfp_connection->vra_state){
case HFP_VRA_VOICE_RECOGNITION_ACTIVATED:
hfp_connection->ag_audio_connection_opened_after_vra = false;
break;
default:
hfp_connection->ag_audio_connection_opened_after_vra = true;
break;
}
hfp_emit_sco_event(hfp_connection, status, sco_handle, event_addr, hfp_connection->negotiated_codec);
break;
}
@ -899,6 +907,7 @@ void hfp_handle_hci_event(uint8_t packet_type, uint16_t channel, uint8_t *packet
}
hfp_connection->state = HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED;
hfp_connection->ag_audio_connection_opened_after_vra = false;
hfp_emit_audio_connection_released(hfp_connection, handle);
if (hfp_connection->release_slc_connection){
@ -1480,11 +1489,6 @@ static void parse_sequence(hfp_connection_t * hfp_connection){
hfp_connection->speaker_gain = value;
log_info("hfp parse HFP_CMD_SET_SPEAKER_GAIN %d\n", value);
break;
case HFP_CMD_HF_ACTIVATE_VOICE_RECOGNITION:
value = btstack_atoi((char *)&hfp_connection->line_buffer[0]);
hfp_connection->ag_activate_voice_recognition_value = value;
log_info("hfp parse HFP_CMD_HF_ACTIVATE_VOICE_RECOGNITION %d\n", value);
break;
case HFP_CMD_TURN_OFF_EC_AND_NR:
value = btstack_atoi((char *)&hfp_connection->line_buffer[0]);
hfp_connection->ag_echo_and_noise_reduction = value;
@ -1624,10 +1628,15 @@ 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_HF_ACTIVATE_VOICE_RECOGNITION:
value = btstack_atoi((char *)&hfp_connection->line_buffer[0]);
hfp_connection->ag_activate_voice_recognition_value = value;
log_info("hfp parse HFP_CMD_HF_ACTIVATE_VOICE_RECOGNITION %d\n", value);
break;
case HFP_CMD_AG_ACTIVATE_VOICE_RECOGNITION:
switch(hfp_connection->parser_item_index){
case 0:
hfp_connection->ag_vra_status = (hfp_voice_recognition_activation_status_t) btstack_atoi((char *)&hfp_connection->line_buffer[0]);
hfp_connection->ag_vra_status = btstack_atoi((char *)&hfp_connection->line_buffer[0]);
break;
case 1:
hfp_connection->ag_vra_state = (hfp_voice_recognition_state_t) btstack_atoi((char *)&hfp_connection->line_buffer[0]);
@ -1727,13 +1736,24 @@ void hfp_trigger_release_service_level_connection(hfp_connection_t * hfp_connect
hfp_connection->release_slc_connection = 1;
}
void hfp_trigger_release_audio_connection(hfp_connection_t * hfp_connection){
uint8_t hfp_trigger_release_audio_connection(hfp_connection_t * hfp_connection){
// called internally, NULL check already performed
btstack_assert(hfp_connection != NULL);
if (hfp_connection->state < HFP_W2_DISCONNECT_SCO){
hfp_connection->release_audio_connection = 1;
if (hfp_connection->state <= HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED){
return ERROR_CODE_COMMAND_DISALLOWED;
}
switch (hfp_connection->state) {
case HFP_W2_CONNECT_SCO:
hfp_connection->state = HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED;
break;
case HFP_W4_SCO_CONNECTED:
case HFP_AUDIO_CONNECTION_ESTABLISHED:
hfp_connection->release_audio_connection = 1;
break;
default:
return ERROR_CODE_COMMAND_DISALLOWED;
}
return ERROR_CODE_SUCCESS;
}
static const struct link_settings {

View File

@ -640,6 +640,8 @@ typedef struct hfp_connection {
uint8_t ag_echo_and_noise_reduction;
// used by AG: HFP parser stores here the activation value issued by HF
uint8_t ag_activate_voice_recognition_value;
bool ag_audio_connection_opened_after_vra;
uint8_t ag_notify_incoming_call_waiting;
uint8_t send_subscriber_number;
uint8_t next_subscriber_number_to_send;
@ -689,7 +691,7 @@ typedef struct hfp_connection {
hfp_voice_recognition_activation_status_t vra_state;
hfp_voice_recognition_activation_status_t vra_state_requested;
hfp_voice_recognition_activation_status_t ag_vra_status;
uint8_t ag_vra_status;
hfp_voice_recognition_state_t ag_vra_state;
hfp_voice_recognition_message_t ag_msg;
@ -782,7 +784,7 @@ void hfp_trigger_release_service_level_connection(hfp_connection_t * hfp_connect
* @brief Prepare connection for audio connection release
* @param hfp_connection
*/
void hfp_trigger_release_audio_connection(hfp_connection_t * hfp_connection);
uint8_t hfp_trigger_release_audio_connection(hfp_connection_t * hfp_connection);
void hfp_reset_context_flags(hfp_connection_t * hfp_connection);

View File

@ -778,19 +778,15 @@ static uint8_t hfp_ag_can_deactivate_voice_recognition_for_connection(hfp_connec
return ERROR_CODE_SUCCESS;
}
static int hfp_ag_voice_recognition_send(hfp_connection_t * hfp_connection, int value){
int done = 0;
switch(hfp_connection->command){
case HFP_CMD_HF_ACTIVATE_VOICE_RECOGNITION:
done = hfp_ag_send_ok(hfp_connection->rfcomm_cid);
break;
case HFP_CMD_AG_ACTIVATE_VOICE_RECOGNITION:
done = hfp_ag_send_activate_voice_recognition_cmd(hfp_connection->rfcomm_cid, value);
break;
static bool hfp_ag_is_audio_connection_active(hfp_connection_t * hfp_connection){
switch (hfp_connection->state){
case HFP_W2_CONNECT_SCO:
case HFP_W4_SCO_CONNECTED:
case HFP_AUDIO_CONNECTION_ESTABLISHED:
return true;
default:
break;
return false;
}
return done;
}
static int hfp_ag_voice_recognition_state_machine(hfp_connection_t * hfp_connection){
@ -802,11 +798,10 @@ static int hfp_ag_voice_recognition_state_machine(hfp_connection_t * hfp_connect
switch (hfp_connection->command){
case HFP_CMD_AG_ACTIVATE_VOICE_RECOGNITION:
done = hfp_ag_voice_recognition_send(hfp_connection, hfp_connection->ag_activate_voice_recognition_value);
done = hfp_ag_send_activate_voice_recognition_cmd(hfp_connection->rfcomm_cid, hfp_connection->ag_activate_voice_recognition_value);
if (done == 0){
hfp_connection->vra_state_requested = hfp_connection->vra_state;
hfp_emit_voice_recognition_state_event(hfp_connection, ERROR_CODE_COMMAND_DISALLOWED, 1 - hfp_connection->ag_activate_voice_recognition_value);
hfp_emit_voice_recognition_state_event(hfp_connection, ERROR_CODE_COMMAND_DISALLOWED, hfp_connection->vra_state);
return 0;
}
break;
@ -840,21 +835,28 @@ static int hfp_ag_voice_recognition_state_machine(hfp_connection_t * hfp_connect
hfp_connection->vra_state = HFP_VRA_VOICE_RECOGNITION_OFF;
hfp_connection->vra_state_requested = hfp_connection->vra_state;
hfp_trigger_release_audio_connection(hfp_connection);
// release audio connection only if it was opened before audio VR activated
if (hfp_ag_is_audio_connection_active(hfp_connection) && !hfp_connection->ag_audio_connection_opened_after_vra){
hfp_trigger_release_audio_connection(hfp_connection);
}
hfp_emit_voice_recognition_state_event(hfp_connection, ERROR_CODE_SUCCESS, 0);
break;
case HFP_VRA_W2_SEND_VOICE_RECOGNITION_ACTIVATED:
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, 0);
return 0;
// open only if audio connection does not already exist
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, hfp_connection->vra_state);
return 0;
}
}
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, status, 1);
hfp_emit_voice_recognition_state_event(hfp_connection, ERROR_CODE_SUCCESS, hfp_connection->vra_state);
break;
default:
@ -2456,7 +2458,6 @@ uint8_t hfp_ag_establish_audio_connection(hci_con_handle_t acl_handle){
if (!hfp_connection){
return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
}
uint8_t status = hfp_ag_setup_audio_connection(hfp_connection);
if (status != ERROR_CODE_SUCCESS){
return status;
@ -2471,9 +2472,16 @@ uint8_t hfp_ag_release_audio_connection(hci_con_handle_t acl_handle){
return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
}
hfp_trigger_release_audio_connection(hfp_connection);
hfp_ag_run_for_context(hfp_connection);
return ERROR_CODE_SUCCESS;
if (hfp_connection->vra_state == HFP_VRA_VOICE_RECOGNITION_ACTIVATED){
if (!hfp_connection->ag_audio_connection_opened_after_vra){
return ERROR_CODE_COMMAND_DISALLOWED;
}
}
uint8_t status = hfp_trigger_release_audio_connection(hfp_connection);
if (status == ERROR_CODE_SUCCESS){
hfp_ag_run_for_context(hfp_connection);
}
return status;
}
/**
@ -2641,6 +2649,7 @@ uint8_t hfp_ag_activate_voice_recognition(hci_con_handle_t acl_handle){
hfp_connection->ag_activate_voice_recognition_value = 1;
hfp_connection->vra_state_requested = HFP_VRA_W2_SEND_VOICE_RECOGNITION_ACTIVATED;
hfp_connection->command = HFP_CMD_AG_ACTIVATE_VOICE_RECOGNITION;
hfp_connection->ag_audio_connection_opened_after_vra = hfp_ag_is_audio_connection_active(hfp_connection);
hfp_ag_run_for_context(hfp_connection);
}
return status;

View File

@ -433,10 +433,8 @@ static int hfp_hf_run_for_context_service_level_connection(hfp_connection_t * hf
static int hfp_hf_run_for_context_service_level_connection_queries(hfp_connection_t * hfp_connection){
if (hfp_connection->state != HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED) return 0;
if (hfp_connection->ok_pending){
return 0;
}
log_info("ok not pending\n");
int done = 0;
if (hfp_connection->enable_status_update_for_ag_indicators != 0xFF){
hfp_connection->ok_pending = 1;
@ -484,6 +482,32 @@ static int hfp_hf_voice_recognition_state_machine(hfp_connection_t * hfp_connect
}
int done = 0;
if (hfp_connection->ok_pending == 1){
return 0;
}
// voice recognition activated from AG
if (hfp_connection->command == HFP_CMD_AG_ACTIVATE_VOICE_RECOGNITION){
switch(hfp_connection->vra_state_requested){
case HFP_VRA_W4_VOICE_RECOGNITION_ACTIVATED:
// ignore AG command, continue to wait for OK
return 0;
case HFP_VRA_W4_VOICE_RECOGNITION_OFF:
// ignore AG command, continue to wait for OK
return 0;
default:
if (hfp_connection->ag_vra_status > 0){
hfp_connection->vra_state_requested = HFP_VRA_W4_VOICE_RECOGNITION_ACTIVATED;
} else {
hfp_connection->vra_state_requested = HFP_VRA_W4_VOICE_RECOGNITION_OFF;
}
break;
}
hfp_connection->command = HFP_CMD_NONE;
}
switch (hfp_connection->vra_state_requested){
case HFP_VRA_W2_SEND_ENHANCED_VOICE_RECOGNITION_OFF:
case HFP_VRA_W2_SEND_VOICE_RECOGNITION_OFF:
@ -497,7 +521,7 @@ static int hfp_hf_voice_recognition_state_machine(hfp_connection_t * hfp_connect
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, 0);
hfp_emit_voice_recognition_state_event(hfp_connection, ERROR_CODE_SUCCESS, hfp_connection->vra_state);
break;
case HFP_VRA_W2_SEND_VOICE_RECOGNITION_ACTIVATED:
@ -505,13 +529,14 @@ static int hfp_hf_voice_recognition_state_machine(hfp_connection_t * hfp_connect
if (done != 0){
hfp_connection->vra_state_requested = HFP_VRA_W4_VOICE_RECOGNITION_ACTIVATED;
hfp_connection->ok_pending = 1;
return 1;
}
return 1;
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, 1);
hfp_emit_voice_recognition_state_event(hfp_connection, ERROR_CODE_SUCCESS, hfp_connection->vra_state);
break;
case HFP_VRA_W2_SEND_ENHANCED_VOICE_RECOGNITION_ACTIVATED:
@ -525,10 +550,11 @@ static int hfp_hf_voice_recognition_state_machine(hfp_connection_t * hfp_connect
case HFP_VRA_W4_ENHANCED_VOICE_RECOGNITION_ACTIVATED:
hfp_connection->vra_state = HFP_VRA_ENHANCED_VOICE_RECOGNITION_ACTIVATED;
hfp_connection->vra_state_requested = hfp_connection->vra_state;
hfp_emit_voice_recognition_state_event(hfp_connection, ERROR_CODE_SUCCESS, 2);
hfp_emit_voice_recognition_state_event(hfp_connection, ERROR_CODE_SUCCESS, hfp_connection->vra_state);
break;
default:
break;
}
return done;
@ -1128,7 +1154,8 @@ static void hfp_hf_handle_rfcomm_command(hfp_connection_t * hfp_connection){
hfp_connection->extended_audio_gateway_error = 0;
hfp_emit_event(hfp_connection, HFP_SUBEVENT_EXTENDED_AUDIO_GATEWAY_ERROR, hfp_connection->extended_audio_gateway_error_value);
break;
case HFP_CMD_AG_ACTIVATE_VOICE_RECOGNITION:
break;
case HFP_CMD_ERROR:
switch (hfp_connection->state){
case HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED:
@ -1144,18 +1171,18 @@ static void hfp_hf_handle_rfcomm_command(hfp_connection_t * hfp_connection){
default:
break;
}
// handle error response for voice activation (HF initiated)
switch(hfp_connection->command){
case HFP_CMD_HF_ACTIVATE_VOICE_RECOGNITION:
hfp_connection->vra_state_requested = hfp_connection->vra_state;
hfp_emit_voice_recognition_state_event(hfp_connection, ERROR_CODE_UNSPECIFIED_ERROR, hfp_connection->vra_state);
switch(hfp_connection->vra_state_requested){
case HFP_VRA_VOICE_RECOGNITION_ACTIVATED:
case HFP_VRA_VOICE_RECOGNITION_OFF:
break;
default:
hfp_emit_event(hfp_connection, HFP_SUBEVENT_COMPLETE, 1);
break;
hfp_connection->vra_state_requested = hfp_connection->vra_state;
hfp_emit_voice_recognition_state_event(hfp_connection, ERROR_CODE_UNSPECIFIED_ERROR, hfp_connection->vra_state);
hfp_reset_context_flags(hfp_connection);
return;
}
hfp_emit_event(hfp_connection, HFP_SUBEVENT_COMPLETE, 1);
hfp_reset_context_flags(hfp_connection);
break;
@ -1191,14 +1218,10 @@ static int hfp_parser_is_end_of_line(uint8_t byte){
return (byte == '\n') || (byte == '\r');
}
static void hfp_hf_handle_rfcomm_data(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
UNUSED(packet_type); // ok: only called with RFCOMM_DATA_PACKET
static void hfp_hf_handle_rfcomm_data(hfp_connection_t * hfp_connection, uint8_t *packet, uint16_t size){
// assertion: size >= 1 as rfcomm.c does not deliver empty packets
if (size < 1) return;
hfp_connection_t * hfp_connection = get_hfp_connection_context_for_rfcomm_cid(channel);
if (!hfp_connection) return;
hfp_log_rfcomm_message("HFP_HF_RX", packet, size);
#ifdef ENABLE_HFP_AT_MESSAGES
hfp_emit_string_event(hfp_connection, HFP_SUBEVENT_AT_MESSAGE_RECEIVED, (char *) packet);
@ -1208,13 +1231,10 @@ static void hfp_hf_handle_rfcomm_data(uint8_t packet_type, uint16_t channel, uin
int pos;
for (pos = 0; pos < size; pos++){
hfp_parse(hfp_connection, packet[pos], 1);
// parse until end of line "\r" or "\n"
if (!hfp_parser_is_end_of_line(packet[pos])) continue;
hfp_hf_handle_rfcomm_command(hfp_connection);
}
hfp_hf_run_for_context(hfp_connection);
hfp_hf_handle_rfcomm_command(hfp_connection);
}
static void hfp_hf_run(void){
@ -1228,10 +1248,14 @@ static void hfp_hf_run(void){
}
static void hfp_hf_rfcomm_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
hfp_connection_t * hfp_connection;
switch (packet_type){
case RFCOMM_DATA_PACKET:
hfp_hf_handle_rfcomm_data(packet_type, channel, packet, size);
break;
hfp_connection = get_hfp_connection_context_for_rfcomm_cid(channel);
if (!hfp_connection) return;
hfp_hf_handle_rfcomm_data(hfp_connection, packet, size);
hfp_hf_run_for_context(hfp_connection);
return;
case HCI_EVENT_PACKET:
if (packet[0] == RFCOMM_EVENT_CAN_SEND_NOW){
uint16_t rfcomm_cid = rfcomm_event_can_send_now_get_rfcomm_cid(packet);
@ -1407,7 +1431,6 @@ uint8_t hfp_hf_establish_audio_connection(hci_con_handle_t acl_handle){
if (hfp_connection->state >= HFP_W2_DISCONNECT_SCO){
return ERROR_CODE_COMMAND_DISALLOWED;
}
if (has_codec_negotiation_feature(hfp_connection)) {
switch (hfp_connection->codecs_state) {
case HFP_CODECS_W4_AG_COMMON_CODEC:
@ -1443,8 +1466,15 @@ uint8_t hfp_hf_release_audio_connection(hci_con_handle_t acl_handle){
if (!hfp_connection) {
return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
}
hfp_trigger_release_audio_connection(hfp_connection);
hfp_hf_run_for_context(hfp_connection);
if (hfp_connection->vra_state == HFP_VRA_VOICE_RECOGNITION_ACTIVATED){
if (!hfp_connection->ag_audio_connection_opened_after_vra){
return ERROR_CODE_COMMAND_DISALLOWED;
}
}
uint8_t status = hfp_trigger_release_audio_connection(hfp_connection);
if (status == ERROR_CODE_SUCCESS){
hfp_hf_run_for_context(hfp_connection);
}
return ERROR_CODE_SUCCESS;
}
@ -1736,7 +1766,6 @@ uint8_t hfp_hf_deactivate_voice_recognition(hci_con_handle_t acl_handle){
if (!hfp_hf_voice_recognition_supported(hfp_connection)){
return ERROR_CODE_COMMAND_DISALLOWED;
}
switch (hfp_connection->vra_state){
case HFP_VRA_VOICE_RECOGNITION_ACTIVATED:
hfp_connection->command = HFP_CMD_HF_ACTIVATE_VOICE_RECOGNITION;