diff --git a/src/classic/hfp.c b/src/classic/hfp.c index 00a1f20f8..0b99cfa4f 100644 --- a/src/classic/hfp.c +++ b/src/classic/hfp.c @@ -518,6 +518,15 @@ void hfp_handle_hci_event(uint8_t packet_type, uint16_t channel, uint8_t *packet log_info("AG packet_handler type %u, event type %x, size %u", packet_type, hci_event_packet_get_type(packet), size); switch (hci_event_packet_get_type(packet)) { + case HCI_EVENT_CONNECTION_REQUEST: + // printf("hfp HCI_EVENT_CONNECTION_REQUEST\n"); + + hci_event_connection_request_get_bd_addr(packet, event_addr); + hfp_connection = provide_hfp_connection_context_for_bd_addr(event_addr); + + if (!hfp_connection) break; + hfp_connection->ag_establish_eSCO = 1; + break; case RFCOMM_EVENT_INCOMING_CONNECTION: // data: event (8), len(8), address(48), channel (8), rfcomm_cid (16) @@ -575,30 +584,27 @@ void hfp_handle_hci_event(uint8_t packet_type, uint16_t channel, uint8_t *packet break; case HCI_EVENT_SYNCHRONOUS_CONNECTION_COMPLETE:{ - - reverse_bd_addr(&packet[5], event_addr); - int index = 2; - status = packet[index++]; - + hci_event_synchronous_connection_complete_get_bd_addr(packet, event_addr); + hfp_connection = get_hfp_connection_context_for_bd_addr(event_addr); + if (!hfp_connection) { + log_error("HFP: connection does not exist for remote with addr %s.", bd_addr_to_str(event_addr)); + return; + } + hfp_connection->ag_establish_eSCO = 0; + + status = hci_event_synchronous_connection_complete_get_status(packet); if (status != 0){ hfp_handle_failed_sco_connection(status); break; } - uint16_t sco_handle = little_endian_read_16(packet, index); - index+=2; - - reverse_bd_addr(&packet[index], event_addr); - index+=6; - - uint8_t link_type = packet[index++]; - uint8_t transmission_interval = packet[index++]; // measured in slots - uint8_t retransmission_interval = packet[index++];// measured in slots - uint16_t rx_packet_length = little_endian_read_16(packet, index); // measured in bytes - index+=2; - uint16_t tx_packet_length = little_endian_read_16(packet, index); // measured in bytes - index+=2; - uint8_t air_mode = packet[index]; + uint16_t sco_handle = hci_event_synchronous_connection_complete_get_handle(packet); + uint8_t link_type = hci_event_synchronous_connection_complete_get_link_type(packet); + uint8_t transmission_interval = hci_event_synchronous_connection_complete_get_transmission_interval(packet); // measured in slots + uint8_t retransmission_interval = hci_event_synchronous_connection_complete_get_retransmission_interval(packet);// measured in slots + uint16_t rx_packet_length = hci_event_synchronous_connection_complete_get_rx_packet_length(packet); // measured in bytes + uint16_t tx_packet_length = hci_event_synchronous_connection_complete_get_tx_packet_length(packet); // measured in bytes + uint8_t air_mode = hci_event_synchronous_connection_complete_get_air_mode(packet); switch (link_type){ case 0x00: diff --git a/src/classic/hfp.h b/src/classic/hfp.h index a38d2fead..83b67259d 100644 --- a/src/classic/hfp.h +++ b/src/classic/hfp.h @@ -561,6 +561,7 @@ typedef struct hfp_connection { uint8_t send_response_and_hold_status; // 0 - don't send. BRTH:0 == 1, .. // AG only + uint8_t ag_establish_eSCO; uint8_t change_in_band_ring_tone_setting; uint8_t ag_ring; uint8_t ag_send_clip; diff --git a/src/classic/hfp_ag.c b/src/classic/hfp_ag.c index b181139d1..e28f146b7 100644 --- a/src/classic/hfp_ag.c +++ b/src/classic/hfp_ag.c @@ -1626,6 +1626,23 @@ static void hfp_run_for_context(hfp_connection_t *hfp_connection){ if (!hfp_connection->rfcomm_cid) return; + if (hfp_connection->ag_establish_eSCO && hci_can_send_command_packet_now()){ + // remote supported feature eSCO is set if link type is eSCO + // eSCO: S4 - max latency == transmission interval = 0x000c == 12 ms, + uint16_t max_latency = 0x000c; + uint8_t retransmission_effort = 0x02; + uint16_t packet_types = 0x388; + uint16_t sco_voice_setting = hci_get_sco_voice_setting(); + + if (hfp_connection->negotiated_codec == HFP_CODEC_MSBC){ + sco_voice_setting = 0x0003; // Transparent data + } + log_info("HFP: sending hci_accept_connection_request, sco_voice_setting %02x", sco_voice_setting); + hci_send_cmd(&hci_accept_synchronous_connection, hfp_connection->remote_addr, 8000, 8000, max_latency, + sco_voice_setting, retransmission_effort, packet_types); + return; + } + if (!rfcomm_can_send_packet_now(hfp_connection->rfcomm_cid)) { log_info("hfp_run_for_context: request can send for 0x%02x", hfp_connection->rfcomm_cid); rfcomm_request_can_send_now_event(hfp_connection->rfcomm_cid); diff --git a/src/classic/hsp_ag.c b/src/classic/hsp_ag.c index d055a3e5c..0f89810ad 100644 --- a/src/classic/hsp_ag.c +++ b/src/classic/hsp_ag.c @@ -76,6 +76,7 @@ static const char default_hsp_ag_service_name[] = "Audio Gateway"; static bd_addr_t remote; +static bd_addr_t sco_event_addr; static uint8_t channel_nr = 0; static uint16_t mtu; @@ -91,7 +92,7 @@ static uint8_t ag_send_ok = 0; static uint8_t ag_send_error = 0; static uint8_t ag_num_button_press_received = 0; static uint8_t ag_support_custom_commands = 0; - +static uint8_t ag_establish_eSCO = 0; static uint8_t hsp_disconnect_rfcomm = 0; static uint8_t hsp_establish_audio_connection = 0; static uint8_t hsp_release_audio_connection = 0; @@ -380,6 +381,11 @@ void hsp_ag_stop_ringing(void){ } static void hsp_run(void){ + if (ag_establish_eSCO && hci_can_send_command_packet_now()){ + log_info("HSP: sending hci_accept_connection_request."); + hci_send_cmd(&hci_accept_synchronous_connection, sco_event_addr, 8000, 8000, 0xFFFF, hci_get_sco_voice_setting(), 0xFF, 0x003F); + return; + } if (ag_send_ok){ if (!rfcomm_can_send_packet_now(rfcomm_cid)) { @@ -557,28 +563,29 @@ static void packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *pack uint16_t handle; switch (event) { + case HCI_EVENT_CONNECTION_REQUEST: + printf("hsp HCI_EVENT_CONNECTION_REQUEST\n"); + hci_event_connection_request_get_bd_addr(packet, sco_event_addr); + ag_establish_eSCO = 1; + break; case HCI_EVENT_SYNCHRONOUS_CONNECTION_COMPLETE:{ - int index = 2; - uint8_t status = packet[index++]; - sco_handle = little_endian_read_16(packet, index); - index+=2; - bd_addr_t address; - memcpy(address, &packet[index], 6); - index+=6; - uint8_t link_type = packet[index++]; - uint8_t transmission_interval = packet[index++]; // measured in slots - uint8_t retransmission_interval = packet[index++];// measured in slots - uint16_t rx_packet_length = little_endian_read_16(packet, index); // measured in bytes - index+=2; - uint16_t tx_packet_length = little_endian_read_16(packet, index); // measured in bytes - index+=2; - uint8_t air_mode = packet[index]; - + ag_establish_eSCO = 0; + uint8_t status = hci_event_synchronous_connection_complete_get_status(packet); if (status != 0){ log_error("(e)SCO Connection failed, status %u", status); emit_event_audio_connected(status, sco_handle); break; } + + hci_event_synchronous_connection_complete_get_bd_addr(packet, event_addr); + sco_handle = hci_event_synchronous_connection_complete_get_handle(packet); + uint8_t link_type = hci_event_synchronous_connection_complete_get_link_type(packet); + uint8_t transmission_interval = hci_event_synchronous_connection_complete_get_transmission_interval(packet); // measured in slots + uint8_t retransmission_interval = hci_event_synchronous_connection_complete_get_retransmission_interval(packet);// measured in slots + uint16_t rx_packet_length = hci_event_synchronous_connection_complete_get_rx_packet_length(packet); // measured in bytes + uint16_t tx_packet_length = hci_event_synchronous_connection_complete_get_tx_packet_length(packet); // measured in bytes + uint8_t air_mode = hci_event_synchronous_connection_complete_get_air_mode(packet); + switch (link_type){ case 0x00: log_info("SCO Connection established."); @@ -596,7 +603,7 @@ static void packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *pack } log_info("sco_handle 0x%2x, address %s, transmission_interval %u slots, retransmission_interval %u slots, " " rx_packet_length %u bytes, tx_packet_length %u bytes, air_mode 0x%2x (0x02 == CVSD)", sco_handle, - bd_addr_to_str(address), transmission_interval, retransmission_interval, rx_packet_length, tx_packet_length, air_mode); + bd_addr_to_str(event_addr), transmission_interval, retransmission_interval, rx_packet_length, tx_packet_length, air_mode); if (hsp_state == HSP_W4_CONNECTION_ESTABLISHED_TO_SHUTDOWN){ hsp_state = HSP_W2_DISCONNECT_SCO; diff --git a/src/hci.c b/src/hci.c index 6bc7fb48f..2ba86637a 100644 --- a/src/hci.c +++ b/src/hci.c @@ -2544,21 +2544,11 @@ static void hci_run(void){ hci_send_cmd(&hci_accept_connection_request, connection->address, 1); } else { // remote supported feature eSCO is set if link type is eSCO - uint16_t max_latency; - uint8_t retransmission_effort; - uint16_t packet_types; - // remote supported feature eSCO is set if link type is eSCO - if (connection->remote_supported_feature_eSCO){ - // eSCO: S4 - max latency == transmission interval = 0x000c == 12 ms, - max_latency = 0x000c; - retransmission_effort = 0x02; - packet_types = 0x388; - } else { - // SCO: max latency, retransmission interval: N/A. any packet type - max_latency = 0xffff; - retransmission_effort = 0xff; - packet_types = 0x003f; - } + if (connection->remote_supported_feature_eSCO) return; + // SCO: max latency, retransmission interval: N/A. any packet type + uint16_t max_latency = 0xffff; + uint8_t retransmission_effort = 0xff; + uint16_t packet_types = 0x003f; hci_send_cmd(&hci_accept_synchronous_connection, connection->address, 8000, 8000, max_latency, hci_stack->sco_voice_setting, retransmission_effort, packet_types); } return; diff --git a/test/hfp/mock.c b/test/hfp/mock.c index 034139e05..35da7b360 100644 --- a/test/hfp/mock.c +++ b/test/hfp/mock.c @@ -212,6 +212,10 @@ int hci_send_cmd(const hci_cmd_t *cmd, ...){ return 0; } +int hci_can_send_command_packet_now(void){ + return 1; +} + static void sdp_query_complete_response(uint8_t status){ uint8_t event[3]; event[0] = SDP_EVENT_QUERY_COMPLETE;