mirror of
https://github.com/bluekitchen/btstack.git
synced 2025-03-28 08:37:22 +00:00
hfp_hf: send codec_event(CVSD) if no codec negotation happens. hfp_ag: use T2/T1 connection settings. only accept SCO connections in hfp_hf
This commit is contained in:
parent
d6ff09e13f
commit
7522e673fc
@ -318,7 +318,7 @@ void hfp_reset_context_flags(hfp_connection_t * hfp_connection){
|
|||||||
|
|
||||||
// establish codecs hfp_connection
|
// establish codecs hfp_connection
|
||||||
hfp_connection->suggested_codec = 0;
|
hfp_connection->suggested_codec = 0;
|
||||||
hfp_connection->negotiated_codec = HFP_CODEC_CVSD;
|
hfp_connection->negotiated_codec = 0;
|
||||||
hfp_connection->codec_confirmed = 0;
|
hfp_connection->codec_confirmed = 0;
|
||||||
|
|
||||||
hfp_connection->establish_audio_connection = 0;
|
hfp_connection->establish_audio_connection = 0;
|
||||||
@ -495,14 +495,22 @@ static void hfp_handle_failed_sco_connection(uint8_t status){
|
|||||||
sco_establishment_active->link_setting = HFP_LINK_SETTINGS_D1;
|
sco_establishment_active->link_setting = HFP_LINK_SETTINGS_D1;
|
||||||
break;
|
break;
|
||||||
case HFP_LINK_SETTINGS_S2:
|
case HFP_LINK_SETTINGS_S2:
|
||||||
case HFP_LINK_SETTINGS_S3:
|
|
||||||
case HFP_LINK_SETTINGS_S4:
|
|
||||||
sco_establishment_active->link_setting = HFP_LINK_SETTINGS_S1;
|
sco_establishment_active->link_setting = HFP_LINK_SETTINGS_S1;
|
||||||
break;
|
break;
|
||||||
case HFP_LINK_SETTINGS_T1:
|
case HFP_LINK_SETTINGS_S3:
|
||||||
case HFP_LINK_SETTINGS_T2:
|
sco_establishment_active->link_setting = HFP_LINK_SETTINGS_S2;
|
||||||
|
break;
|
||||||
|
case HFP_LINK_SETTINGS_S4:
|
||||||
sco_establishment_active->link_setting = HFP_LINK_SETTINGS_S3;
|
sco_establishment_active->link_setting = HFP_LINK_SETTINGS_S3;
|
||||||
break;
|
break;
|
||||||
|
case HFP_LINK_SETTINGS_T1:
|
||||||
|
log_info("T1 failed, fallback to CVSD - D1");
|
||||||
|
sco_establishment_active->negotiated_codec = HFP_CODEC_CVSD;
|
||||||
|
sco_establishment_active->link_setting = HFP_LINK_SETTINGS_D1;
|
||||||
|
break;
|
||||||
|
case HFP_LINK_SETTINGS_T2:
|
||||||
|
sco_establishment_active->link_setting = HFP_LINK_SETTINGS_T1;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
sco_establishment_active->establish_audio_connection = 1;
|
sco_establishment_active->establish_audio_connection = 1;
|
||||||
sco_establishment_active = 0;
|
sco_establishment_active = 0;
|
||||||
@ -520,12 +528,16 @@ void hfp_handle_hci_event(uint8_t packet_type, uint16_t channel, uint8_t *packet
|
|||||||
switch (hci_event_packet_get_type(packet)) {
|
switch (hci_event_packet_get_type(packet)) {
|
||||||
case HCI_EVENT_CONNECTION_REQUEST:
|
case HCI_EVENT_CONNECTION_REQUEST:
|
||||||
// printf("hfp HCI_EVENT_CONNECTION_REQUEST\n");
|
// printf("hfp HCI_EVENT_CONNECTION_REQUEST\n");
|
||||||
|
switch(hci_event_connection_request_get_link_type(packet)){
|
||||||
|
case 0: // SCO
|
||||||
|
case 2: // eSCO
|
||||||
hci_event_connection_request_get_bd_addr(packet, event_addr);
|
hci_event_connection_request_get_bd_addr(packet, event_addr);
|
||||||
hfp_connection = provide_hfp_connection_context_for_bd_addr(event_addr);
|
hfp_connection = get_hfp_connection_context_for_bd_addr(event_addr);
|
||||||
|
|
||||||
if (!hfp_connection) break;
|
if (!hfp_connection) break;
|
||||||
hfp_connection->ag_establish_SCO = 1;
|
hfp_connection->ag_establish_SCO = 1;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case RFCOMM_EVENT_INCOMING_CONNECTION:
|
case RFCOMM_EVENT_INCOMING_CONNECTION:
|
||||||
@ -1400,7 +1412,7 @@ void hfp_setup_synchronous_connection(hfp_connection_t * hfp_connection){
|
|||||||
sco_establishment_active = hfp_connection;
|
sco_establishment_active = hfp_connection;
|
||||||
uint16_t sco_voice_setting = hci_get_sco_voice_setting();
|
uint16_t sco_voice_setting = hci_get_sco_voice_setting();
|
||||||
if (hfp_connection->negotiated_codec == HFP_CODEC_MSBC){
|
if (hfp_connection->negotiated_codec == HFP_CODEC_MSBC){
|
||||||
sco_voice_setting = 0x0003; // Transparent data
|
sco_voice_setting = 0x0043; // Transparent data
|
||||||
}
|
}
|
||||||
hci_send_cmd(&hci_setup_synchronous_connection, hfp_connection->acl_handle, 8000, 8000, hfp_link_settings[setting].max_latency,
|
hci_send_cmd(&hci_setup_synchronous_connection, hfp_connection->acl_handle, 8000, 8000, hfp_link_settings[setting].max_latency,
|
||||||
sco_voice_setting, hfp_link_settings[setting].retransmission_effort, hfp_link_settings[setting].packet_types); // all types 0x003f, only 2-ev3 0x380
|
sco_voice_setting, hfp_link_settings[setting].retransmission_effort, hfp_link_settings[setting].packet_types); // all types 0x003f, only 2-ev3 0x380
|
||||||
|
@ -536,6 +536,29 @@ static uint8_t hfp_ag_suggest_codec(hfp_connection_t *hfp_connection){
|
|||||||
return HFP_CODEC_CVSD;
|
return HFP_CODEC_CVSD;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void hfp_init_link_settings(hfp_connection_t * hfp_connection){
|
||||||
|
// determine highest possible link setting
|
||||||
|
hfp_connection->link_setting = HFP_LINK_SETTINGS_D1;
|
||||||
|
switch (hfp_connection->negotiated_codec){
|
||||||
|
default:
|
||||||
|
case HFP_CODEC_CVSD:
|
||||||
|
if (hci_remote_esco_supported(hfp_connection->acl_handle)){
|
||||||
|
hfp_connection->link_setting = HFP_LINK_SETTINGS_S3;
|
||||||
|
if ((hfp_connection->remote_supported_features & (1<<HFP_HFSF_ESCO_S4))
|
||||||
|
&& (hfp_supported_features & (1<<HFP_AGSF_ESCO_S4))){
|
||||||
|
hfp_connection->link_setting = HFP_LINK_SETTINGS_S4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case HFP_CODEC_MSBC:
|
||||||
|
if (hci_remote_esco_supported(hfp_connection->acl_handle)){
|
||||||
|
hfp_connection->link_setting = HFP_LINK_SETTINGS_T2;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
log_info("hfp_init_link_settings: %u", hfp_connection->link_setting);
|
||||||
|
}
|
||||||
|
|
||||||
static int codecs_exchange_state_machine(hfp_connection_t * hfp_connection){
|
static int codecs_exchange_state_machine(hfp_connection_t * hfp_connection){
|
||||||
/* events ( == commands):
|
/* events ( == commands):
|
||||||
HFP_CMD_AVAILABLE_CODECS == received AT+BAC with list of codecs
|
HFP_CMD_AVAILABLE_CODECS == received AT+BAC with list of codecs
|
||||||
@ -599,6 +622,8 @@ static int codecs_exchange_state_machine(hfp_connection_t * hfp_connection){
|
|||||||
log_info("hfp: codec confirmed: %s", hfp_connection->negotiated_codec == HFP_CODEC_MSBC ? "mSBC" : "CVSD");
|
log_info("hfp: codec confirmed: %s", hfp_connection->negotiated_codec == HFP_CODEC_MSBC ? "mSBC" : "CVSD");
|
||||||
hfp_emit_codec_event(hfp_callback, 0, hfp_connection->negotiated_codec);
|
hfp_emit_codec_event(hfp_callback, 0, hfp_connection->negotiated_codec);
|
||||||
hfp_ag_ok(hfp_connection->rfcomm_cid);
|
hfp_ag_ok(hfp_connection->rfcomm_cid);
|
||||||
|
// now, pick link settings
|
||||||
|
hfp_init_link_settings(hfp_connection);
|
||||||
return 1;
|
return 1;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
@ -606,24 +631,10 @@ static int codecs_exchange_state_machine(hfp_connection_t * hfp_connection){
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void hfp_init_link_settings(hfp_connection_t * hfp_connection){
|
|
||||||
// determine highest possible link setting
|
|
||||||
hfp_connection->link_setting = HFP_LINK_SETTINGS_D1;
|
|
||||||
if (hci_remote_esco_supported(hfp_connection->acl_handle)){
|
|
||||||
hfp_connection->link_setting = HFP_LINK_SETTINGS_S3;
|
|
||||||
if ((hfp_connection->remote_supported_features & (1<<HFP_HFSF_ESCO_S4))
|
|
||||||
&& (hfp_supported_features & (1<<HFP_AGSF_ESCO_S4))){
|
|
||||||
hfp_connection->link_setting = HFP_LINK_SETTINGS_S4;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void hfp_ag_slc_established(hfp_connection_t * hfp_connection){
|
static void hfp_ag_slc_established(hfp_connection_t * hfp_connection){
|
||||||
hfp_connection->state = HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED;
|
hfp_connection->state = HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED;
|
||||||
hfp_emit_connection_event(hfp_callback, HFP_SUBEVENT_SERVICE_LEVEL_CONNECTION_ESTABLISHED, 0, hfp_connection->acl_handle, hfp_connection->remote_addr);
|
hfp_emit_connection_event(hfp_callback, HFP_SUBEVENT_SERVICE_LEVEL_CONNECTION_ESTABLISHED, 0, hfp_connection->acl_handle, hfp_connection->remote_addr);
|
||||||
|
|
||||||
hfp_init_link_settings(hfp_connection);
|
|
||||||
|
|
||||||
// if active call exist, set per-hfp_connection state active, too (when audio is on)
|
// if active call exist, set per-hfp_connection state active, too (when audio is on)
|
||||||
if (hfp_gsm_call_status() == HFP_CALL_STATUS_ACTIVE_OR_HELD_CALL_IS_PRESENT){
|
if (hfp_gsm_call_status() == HFP_CALL_STATUS_ACTIVE_OR_HELD_CALL_IS_PRESENT){
|
||||||
hfp_connection->call_state = HFP_CALL_W4_AUDIO_CONNECTION_FOR_ACTIVE;
|
hfp_connection->call_state = HFP_CALL_W4_AUDIO_CONNECTION_FOR_ACTIVE;
|
||||||
@ -1626,34 +1637,6 @@ static void hfp_run_for_context(hfp_connection_t *hfp_connection){
|
|||||||
|
|
||||||
if (!hfp_connection->rfcomm_cid) return;
|
if (!hfp_connection->rfcomm_cid) return;
|
||||||
|
|
||||||
if (hfp_connection->ag_establish_SCO && 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;
|
|
||||||
uint8_t retransmission_effort;
|
|
||||||
uint16_t packet_types;
|
|
||||||
|
|
||||||
if (hci_remote_esco_supported(hfp_connection->acl_handle)){
|
|
||||||
max_latency = 0x000c;
|
|
||||||
retransmission_effort = 0x02;
|
|
||||||
packet_types = 0x388;
|
|
||||||
} else {
|
|
||||||
max_latency = 0xffff;
|
|
||||||
retransmission_effort = 0xff;
|
|
||||||
packet_types = 0x003f;
|
|
||||||
}
|
|
||||||
|
|
||||||
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)) {
|
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);
|
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);
|
rfcomm_request_can_send_now_event(hfp_connection->rfcomm_cid);
|
||||||
@ -2134,6 +2117,8 @@ static void hfp_ag_setup_audio_connection(hfp_connection_t * hfp_connection){
|
|||||||
hfp_connection->negotiated_codec = HFP_CODEC_CVSD;
|
hfp_connection->negotiated_codec = HFP_CODEC_CVSD;
|
||||||
hfp_connection->codecs_state = HFP_CODECS_EXCHANGED;
|
hfp_connection->codecs_state = HFP_CODECS_EXCHANGED;
|
||||||
hfp_emit_codec_event(hfp_callback, 0, hfp_connection->negotiated_codec);
|
hfp_emit_codec_event(hfp_callback, 0, hfp_connection->negotiated_codec);
|
||||||
|
// now, pick link settings
|
||||||
|
hfp_init_link_settings(hfp_connection);
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (hfp_connection->codecs_state){
|
switch (hfp_connection->codecs_state){
|
||||||
|
@ -588,6 +588,42 @@ static int call_setup_state_machine(hfp_connection_t * hfp_connection){
|
|||||||
static void hfp_run_for_context(hfp_connection_t * hfp_connection){
|
static void hfp_run_for_context(hfp_connection_t * hfp_connection){
|
||||||
if (!hfp_connection) return;
|
if (!hfp_connection) return;
|
||||||
if (!hfp_connection->rfcomm_cid) return;
|
if (!hfp_connection->rfcomm_cid) return;
|
||||||
|
|
||||||
|
if (hfp_connection->ag_establish_SCO && hci_can_send_command_packet_now()){
|
||||||
|
|
||||||
|
// notify about codec selection if not done already
|
||||||
|
if (hfp_connection->negotiated_codec == 0){
|
||||||
|
hfp_connection->negotiated_codec = HFP_CODEC_CVSD;
|
||||||
|
hfp_emit_codec_event(hfp_callback, 0, hfp_connection->negotiated_codec);
|
||||||
|
}
|
||||||
|
|
||||||
|
// remote supported feature eSCO is set if link type is eSCO
|
||||||
|
// eSCO: S4 - max latency == transmission interval = 0x000c == 12 ms,
|
||||||
|
uint16_t max_latency;
|
||||||
|
uint8_t retransmission_effort;
|
||||||
|
uint16_t packet_types;
|
||||||
|
|
||||||
|
if (hci_remote_esco_supported(hfp_connection->acl_handle)){
|
||||||
|
max_latency = 0x000c;
|
||||||
|
retransmission_effort = 0x02;
|
||||||
|
packet_types = 0x388;
|
||||||
|
} else {
|
||||||
|
max_latency = 0xffff;
|
||||||
|
retransmission_effort = 0xff;
|
||||||
|
packet_types = 0x003f;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t sco_voice_setting = hci_get_sco_voice_setting();
|
||||||
|
if (hfp_connection->negotiated_codec == HFP_CODEC_MSBC){
|
||||||
|
sco_voice_setting = 0x0043; // 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)) return;
|
if (!rfcomm_can_send_packet_now(hfp_connection->rfcomm_cid)) return;
|
||||||
|
|
||||||
int done = hfp_hf_run_for_context_service_level_connection(hfp_connection);
|
int done = hfp_hf_run_for_context_service_level_connection(hfp_connection);
|
||||||
@ -824,23 +860,11 @@ static void hfp_run_for_context(hfp_connection_t * hfp_connection){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void hfp_init_link_settings(hfp_connection_t * hfp_connection){
|
|
||||||
// determine highest possible link setting
|
|
||||||
hfp_connection->link_setting = HFP_LINK_SETTINGS_D1;
|
|
||||||
if (hci_remote_esco_supported(hfp_connection->acl_handle)){
|
|
||||||
hfp_connection->link_setting = HFP_LINK_SETTINGS_S3;
|
|
||||||
if ((hfp_supported_features & (1<<HFP_HFSF_ESCO_S4))
|
|
||||||
&& (hfp_connection->remote_supported_features & (1<<HFP_AGSF_ESCO_S4))){
|
|
||||||
hfp_connection->link_setting = HFP_LINK_SETTINGS_S4;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void hfp_ag_slc_established(hfp_connection_t * hfp_connection){
|
static void hfp_ag_slc_established(hfp_connection_t * hfp_connection){
|
||||||
hfp_connection->state = HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED;
|
hfp_connection->state = HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED;
|
||||||
|
|
||||||
hfp_emit_connection_event(hfp_callback, HFP_SUBEVENT_SERVICE_LEVEL_CONNECTION_ESTABLISHED, 0, hfp_connection->acl_handle, hfp_connection->remote_addr);
|
hfp_emit_connection_event(hfp_callback, HFP_SUBEVENT_SERVICE_LEVEL_CONNECTION_ESTABLISHED, 0, hfp_connection->acl_handle, hfp_connection->remote_addr);
|
||||||
hfp_init_link_settings(hfp_connection);
|
|
||||||
// restore volume settings
|
// restore volume settings
|
||||||
hfp_connection->speaker_gain = hfp_hf_speaker_gain;
|
hfp_connection->speaker_gain = hfp_hf_speaker_gain;
|
||||||
hfp_connection->send_speaker_gain = 1;
|
hfp_connection->send_speaker_gain = 1;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user