From 38200c1d684327a5920d45b4be19fa94733bcd74 Mon Sep 17 00:00:00 2001 From: Milanka Ringwald Date: Tue, 2 Oct 2018 21:41:46 +0200 Subject: [PATCH] hfp_hf: setup SCO connection if codec negotiation not supported --- src/classic/hfp.c | 50 ++++++++++++++++++++++++++------------------ src/classic/hfp_hf.c | 29 +++++++++++++++++++++++-- 2 files changed, 57 insertions(+), 22 deletions(-) diff --git a/src/classic/hfp.c b/src/classic/hfp.c index 67e632837..77620b17f 100644 --- a/src/classic/hfp.c +++ b/src/classic/hfp.c @@ -520,20 +520,20 @@ static void handle_query_rfcomm_event(uint8_t packet_type, uint16_t channel, uin } } -static void hfp_handle_failed_sco_connection(uint8_t status){ - +// returns 0 if unexpected error or no other link options remained, otherwise 1 +static int hfp_handle_failed_sco_connection(uint8_t status){ + if (!sco_establishment_active){ log_error("(e)SCO Connection failed but not started by us"); - return; + return 0; } - log_error("(e)SCO Connection failed status 0x%02x", status); - + log_info("(e)SCO Connection failed status 0x%02x", status); // invalid params / unspecified error - if (status != 0x11 && status != 0x1f) return; + if (status != 0x11 && status != 0x1f && status != 0x0D) return 0; - switch (sco_establishment_active->link_setting){ + switch (sco_establishment_active->link_setting){ case HFP_LINK_SETTINGS_D0: - return; // no other option left + return 0; // no other option left case HFP_LINK_SETTINGS_D1: sco_establishment_active->link_setting = HFP_LINK_SETTINGS_D0; break; @@ -560,8 +560,10 @@ static void hfp_handle_failed_sco_connection(uint8_t status){ sco_establishment_active->link_setting = HFP_LINK_SETTINGS_T1; break; } + log_info("e)SCO Connection: try new link_setting %d", sco_establishment_active->link_setting); sco_establishment_active->establish_audio_connection = 1; - sco_establishment_active = 0; + sco_establishment_active = NULL; + return 1; } @@ -597,9 +599,13 @@ void hfp_handle_hci_event(uint8_t packet_type, uint16_t channel, uint8_t *packet case HCI_EVENT_COMMAND_STATUS: if (hci_event_command_status_get_command_opcode(packet) == hci_setup_synchronous_connection.opcode) { status = hci_event_command_status_get_status(packet); - if (status) { - hfp_handle_failed_sco_connection(hci_event_command_status_get_status(packet)); - } + if (status == ERROR_CODE_SUCCESS) break; + + hfp_connection = sco_establishment_active; + if (hfp_handle_failed_sco_connection(status)) break; + hfp_connection->establish_audio_connection = 0; + hfp_connection->state = HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED; + hfp_emit_sco_event(hfp_connection, status, 0, hfp_connection->remote_addr, hfp_connection->negotiated_codec); } break; @@ -612,9 +618,13 @@ void hfp_handle_hci_event(uint8_t packet_type, uint16_t channel, uint8_t *packet } status = hci_event_synchronous_connection_complete_get_status(packet); - if (status != 0){ + if (status != ERROR_CODE_SUCCESS){ hfp_connection->hf_accept_sco = 0; - hfp_handle_failed_sco_connection(status); + if (hfp_handle_failed_sco_connection(status)) break; + + hfp_connection->establish_audio_connection = 0; + hfp_connection->state = HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED; + hfp_emit_sco_event(hfp_connection, status, 0, event_addr, hfp_connection->negotiated_codec); break; } @@ -645,12 +655,12 @@ void hfp_handle_hci_event(uint8_t packet_type, uint16_t channel, uint8_t *packet " rx_packet_length %u bytes, tx_packet_length %u bytes, air_mode 0x%2x (0x02 == CVSD)\n", sco_handle, bd_addr_to_str(event_addr), transmission_interval, retransmission_interval, rx_packet_length, tx_packet_length, air_mode); - hfp_connection = get_hfp_connection_context_for_bd_addr(event_addr, local_role); + // hfp_connection = get_hfp_connection_context_for_bd_addr(event_addr, local_role); - if (!hfp_connection) { - log_error("SCO link created, hfp_connection for address %s not found.", bd_addr_to_str(event_addr)); - break; - } + // if (!hfp_connection) { + // log_error("SCO link created, hfp_connection for address %s not found.", bd_addr_to_str(event_addr)); + // break; + // } if (hfp_connection->state == HFP_W4_CONNECTION_ESTABLISHED_TO_SHUTDOWN){ log_info("SCO about to disconnect: HFP_W4_CONNECTION_ESTABLISHED_TO_SHUTDOWN"); @@ -660,7 +670,7 @@ 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; - hfp_emit_sco_event(hfp_connection, packet[2], sco_handle, event_addr, hfp_connection->negotiated_codec); + hfp_emit_sco_event(hfp_connection, status, sco_handle, event_addr, hfp_connection->negotiated_codec); break; } diff --git a/src/classic/hfp_hf.c b/src/classic/hfp_hf.c index 6a3e36569..c3c966eec 100644 --- a/src/classic/hfp_hf.c +++ b/src/classic/hfp_hf.c @@ -551,10 +551,19 @@ static int hfp_hf_run_for_audio_connection(hfp_connection_t * hfp_connection){ // run codecs exchange int done = codecs_exchange_state_machine(hfp_connection); if (done) return 1; - + + if (hfp_connection->codecs_state != HFP_CODECS_EXCHANGED) return 0; + if (hfp_connection->establish_audio_connection){ + hfp_connection->state = HFP_W4_SCO_CONNECTED; + hfp_connection->establish_audio_connection = 0; + hfp_setup_synchronous_connection(hfp_connection); + return 1; + } + return 0; } + static int call_setup_state_machine(hfp_connection_t * hfp_connection){ if (hfp_connection->hf_answer_incoming_call){ hfp_hf_cmd_ata(hfp_connection->rfcomm_cid); @@ -1110,6 +1119,11 @@ static void rfcomm_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t static void hci_event_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ hfp_handle_hci_event(packet_type, channel, packet, size, HFP_ROLE_HF); + + // allow for sco established -> ring transition and sco retry + if (packet_type != HCI_EVENT_PACKET) return; + if (hci_event_packet_get_type(packet) != HCI_EVENT_SYNCHRONOUS_CONNECTION_COMPLETE) return; + hfp_run(); } void hfp_hf_init(uint16_t rfcomm_channel_nr){ @@ -1239,6 +1253,9 @@ void hfp_hf_disable_report_extended_audio_gateway_error_result_code(hci_con_hand hfp_hf_set_report_extended_audio_gateway_error_result_code(acl_handle, 0); } +static uint8_t hfp_hf_esco_s4_supported(hfp_connection_t * hfp_connection){ + return (hfp_connection->remote_supported_features & (1<state == HFP_AUDIO_CONNECTION_ESTABLISHED) return; if (hfp_connection->state >= HFP_W2_DISCONNECT_SCO) return; + hfp_connection->trigger_codec_exchange = 0; + hfp_connection->establish_audio_connection = 1; if (!has_codec_negotiation_feature(hfp_connection)){ log_info("hfp_ag_establish_audio_connection - no codec negotiation feature, using defaults"); hfp_connection->codecs_state = HFP_CODECS_EXCHANGED; - hfp_connection->establish_audio_connection = 1; + hfp_connection->suggested_codec = HFP_CODEC_CVSD; + hfp_connection->codec_confirmed = hfp_connection->suggested_codec; + hfp_connection->negotiated_codec = hfp_connection->suggested_codec; + hfp_init_link_settings(hfp_connection, hfp_hf_esco_s4_supported(hfp_connection)); + hfp_connection->trigger_codec_exchange = 0; + hfp_connection->state = HFP_W4_SCO_CONNECTED; } else { switch (hfp_connection->codecs_state){ case HFP_CODECS_W4_AG_COMMON_CODEC: break; default: + hfp_connection->trigger_codec_exchange = 1; hfp_connection->command = HFP_CMD_TRIGGER_CODEC_CONNECTION_SETUP; break; }