mirror of
https://github.com/bluekitchen/btstack.git
synced 2025-03-28 19:20:54 +00:00
hfp ag: start impl incoming call
This commit is contained in:
parent
8c72a38b3b
commit
deaf6c13c4
@ -637,6 +637,9 @@ extern "C" {
|
|||||||
#define HFP_SUBEVENT_NETWORK_OPERATOR_CHANGED 0x07
|
#define HFP_SUBEVENT_NETWORK_OPERATOR_CHANGED 0x07
|
||||||
#define HFP_SUBEVENT_EXTENDED_AUDIO_GATEWAY_ERROR 0x08
|
#define HFP_SUBEVENT_EXTENDED_AUDIO_GATEWAY_ERROR 0x08
|
||||||
#define HFP_SUBEVENT_CODECS_CONNECTION_COMPLETE 0x09
|
#define HFP_SUBEVENT_CODECS_CONNECTION_COMPLETE 0x09
|
||||||
|
#define HFP_SUBEVENT_START_RINGINIG 0x0A
|
||||||
|
#define HFP_SUBEVENT_STOP_RINGINIG 0x0B
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// ANCS Client
|
// ANCS Client
|
||||||
|
35
src/hfp.c
35
src/hfp.c
@ -204,6 +204,16 @@ void hfp_emit_event(hfp_callback_t callback, uint8_t event_subtype, uint8_t valu
|
|||||||
(*callback)(event, sizeof(event));
|
(*callback)(event, sizeof(event));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void hfp_emit_audio_connection_established_event(hfp_callback_t callback, uint8_t value, uint16_t sco_handle){
|
||||||
|
if (!callback) return;
|
||||||
|
uint8_t event[6];
|
||||||
|
event[0] = HCI_EVENT_HFP_META;
|
||||||
|
event[1] = sizeof(event) - 2;
|
||||||
|
event[2] = HFP_SUBEVENT_AUDIO_CONNECTION_ESTABLISHED;
|
||||||
|
event[3] = value; // status 0 == OK
|
||||||
|
bt_store_16(event, 4, sco_handle);
|
||||||
|
(*callback)(event, sizeof(event));
|
||||||
|
}
|
||||||
|
|
||||||
linked_list_t * hfp_get_connections(){
|
linked_list_t * hfp_get_connections(){
|
||||||
return (linked_list_t *) &hfp_connections;
|
return (linked_list_t *) &hfp_connections;
|
||||||
@ -560,8 +570,9 @@ void hfp_handle_hci_event(hfp_callback_t callback, uint8_t packet_type, uint8_t
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
context->sco_handle = sco_handle;
|
context->sco_handle = sco_handle;
|
||||||
|
context->establish_audio_connection = 0;
|
||||||
context->state = HFP_AUDIO_CONNECTION_ESTABLISHED;
|
context->state = HFP_AUDIO_CONNECTION_ESTABLISHED;
|
||||||
hfp_emit_event(callback, HFP_SUBEVENT_AUDIO_CONNECTION_ESTABLISHED, packet[2]);
|
hfp_emit_audio_connection_established_event(callback, packet[2], sco_handle);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -735,10 +746,23 @@ static void process_command(hfp_connection_t * context){
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strncmp((char *)context->line_buffer+offset, "NOP", 3) == 0) return;
|
|
||||||
|
|
||||||
context->command = HFP_CMD_ERROR;
|
if (strncmp((char *)context->line_buffer+offset, "AT+", 3) == 0){
|
||||||
printf(" process unknown command %s \n", context->line_buffer);
|
context->command = HFP_CMD_UNKNOWN;
|
||||||
|
printf(" process unknown HF command %s \n", context->line_buffer);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (strncmp((char *)context->line_buffer+offset, "+", 1) == 0){
|
||||||
|
context->command = HFP_CMD_UNKNOWN;
|
||||||
|
printf(" process unknown AG command %s \n", context->line_buffer);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strncmp((char *)context->line_buffer+offset, "NOP", 3) == 0){
|
||||||
|
context->command = HFP_CMD_NONE;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
@ -941,7 +965,8 @@ void hfp_parse(hfp_connection_t * context, uint8_t byte){
|
|||||||
case HFP_CMD_TRANSFER_AG_INDICATOR_STATUS:
|
case HFP_CMD_TRANSFER_AG_INDICATOR_STATUS:
|
||||||
// indicators are indexed starting with 1
|
// indicators are indexed starting with 1
|
||||||
context->parser_item_index = atoi((char *)&context->line_buffer[0]) - 1;
|
context->parser_item_index = atoi((char *)&context->line_buffer[0]) - 1;
|
||||||
log_info("Parsed status of the AG indicator %d, status ", context->parser_item_index);
|
printf("Parsed status of the AG indicator %d, status ", context->parser_item_index);
|
||||||
|
printf("\n");
|
||||||
break;
|
break;
|
||||||
case HFP_CMD_QUERY_OPERATOR_SELECTION:
|
case HFP_CMD_QUERY_OPERATOR_SELECTION:
|
||||||
if (context->operator_name_format == 1){
|
if (context->operator_name_format == 1){
|
||||||
|
@ -125,6 +125,7 @@ extern "C" {
|
|||||||
typedef enum {
|
typedef enum {
|
||||||
HFP_CMD_NONE = 0,
|
HFP_CMD_NONE = 0,
|
||||||
HFP_CMD_ERROR,
|
HFP_CMD_ERROR,
|
||||||
|
HFP_CMD_UNKNOWN,
|
||||||
HFP_CMD_OK,
|
HFP_CMD_OK,
|
||||||
HFP_CMD_SUPPORTED_FEATURES,
|
HFP_CMD_SUPPORTED_FEATURES,
|
||||||
HFP_CMD_AVAILABLE_CODECS,
|
HFP_CMD_AVAILABLE_CODECS,
|
||||||
@ -370,6 +371,10 @@ typedef struct hfp_connection {
|
|||||||
uint8_t establish_audio_connection;
|
uint8_t establish_audio_connection;
|
||||||
uint8_t release_audio_connection;
|
uint8_t release_audio_connection;
|
||||||
|
|
||||||
|
uint8_t start_call;
|
||||||
|
uint8_t terminate_call;
|
||||||
|
uint8_t start_ringing;
|
||||||
|
uint8_t stop_ringing;
|
||||||
} hfp_connection_t;
|
} hfp_connection_t;
|
||||||
|
|
||||||
// UTILS_START : TODO move to utils
|
// UTILS_START : TODO move to utils
|
||||||
|
193
src/hfp_ag.c
193
src/hfp_ag.c
@ -92,6 +92,16 @@ hfp_ag_indicator_t * get_hfp_ag_indicators(hfp_connection_t * context){
|
|||||||
return (hfp_ag_indicator_t *)&(context->ag_indicators);
|
return (hfp_ag_indicator_t *)&(context->ag_indicators);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hfp_ag_indicator_t * get_ag_indicator_for_name(hfp_connection_t * context, const char * name){
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < context->ag_indicators_nr; i++){
|
||||||
|
if (strcmp(context->ag_indicators[i].name, name) == 0){
|
||||||
|
return &context->ag_indicators[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
void set_hfp_ag_indicators(hfp_ag_indicator_t * indicators, int indicator_nr){
|
void set_hfp_ag_indicators(hfp_ag_indicator_t * indicators, int indicator_nr){
|
||||||
memcpy(hfp_ag_indicators, indicators, indicator_nr * sizeof(hfp_ag_indicator_t));
|
memcpy(hfp_ag_indicators, indicators, indicator_nr * sizeof(hfp_ag_indicator_t));
|
||||||
hfp_ag_indicators_nr = indicator_nr;
|
hfp_ag_indicators_nr = indicator_nr;
|
||||||
@ -114,24 +124,6 @@ void hfp_ag_register_packet_handler(hfp_callback_t callback){
|
|||||||
hfp_callback = callback;
|
hfp_callback = callback;
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint8_t hfp_get_indicator_index_by_name(hfp_connection_t * context, const char * name){
|
|
||||||
int i;
|
|
||||||
for (i=0; i<context->ag_indicators_nr; i++){
|
|
||||||
if (strcmp(context->ag_indicators[i].name, name) == 0){
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0xFF;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void hfp_ag_update_indicator_status(hfp_connection_t * context, const char * indicator_name, uint8_t status){
|
|
||||||
int index = hfp_get_indicator_index_by_name(context, indicator_name);
|
|
||||||
if (index == 0xFF) return;
|
|
||||||
if (context->ag_indicators[index].status == status) return;
|
|
||||||
context->ag_indicators[index].status = status;
|
|
||||||
context->ag_indicators[index].status_changed = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int has_codec_negotiation_feature(hfp_connection_t * connection){
|
static int has_codec_negotiation_feature(hfp_connection_t * connection){
|
||||||
int hf = get_bit(connection->remote_supported_features, HFP_HFSF_CODEC_NEGOTIATION);
|
int hf = get_bit(connection->remote_supported_features, HFP_HFSF_CODEC_NEGOTIATION);
|
||||||
int ag = get_bit(hfp_supported_features, HFP_AGSF_CODEC_NEGOTIATION);
|
int ag = get_bit(hfp_supported_features, HFP_AGSF_CODEC_NEGOTIATION);
|
||||||
@ -329,12 +321,11 @@ static int hfp_ag_retrieve_initital_supported_generic_status_indicators_cmd(uint
|
|||||||
return send_str_over_rfcomm(cid, buffer);
|
return send_str_over_rfcomm(cid, buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
// static int hfp_ag_transfer_ag_indicators_status_cmd(uint16_t cid, hfp_ag_indicator_t indicator){
|
static int hfp_ag_transfer_ag_indicators_status_cmd(uint16_t cid, hfp_ag_indicator_t * indicator){
|
||||||
// char buffer[20];
|
char buffer[20];
|
||||||
// sprintf(buffer, "\r\n%s:%d,%d\r\n\r\nOK\r\n", HFP_TRANSFER_AG_INDICATOR_STATUS, indicator.index, indicator.status);
|
sprintf(buffer, "\r\n%s:%d,%d\r\n", HFP_TRANSFER_AG_INDICATOR_STATUS, indicator->index, indicator->status);
|
||||||
// log_info("HFP_CMD_ENABLE_INDIVIDUAL_AG_INDICATOR_STATUS_UPDATE send %s", buffer);
|
return send_str_over_rfcomm(cid, buffer);
|
||||||
// return send_str_over_rfcomm(cid, buffer);
|
}
|
||||||
// }
|
|
||||||
|
|
||||||
static int hfp_ag_report_network_operator_name_cmd(uint16_t cid, hfp_network_opearator_t op){
|
static int hfp_ag_report_network_operator_name_cmd(uint16_t cid, hfp_network_opearator_t op){
|
||||||
char buffer[40];
|
char buffer[40];
|
||||||
@ -369,10 +360,9 @@ static uint8_t hfp_ag_suggest_codec(hfp_connection_t *context){
|
|||||||
|
|
||||||
|
|
||||||
static int hfp_ag_run_for_context_service_level_connection(hfp_connection_t * context){
|
static int hfp_ag_run_for_context_service_level_connection(hfp_connection_t * context){
|
||||||
log_info(" AG run for context_service_level_connection \n");
|
|
||||||
if (context->state >= HFP_CODECS_CONNECTION_ESTABLISHED) return 0;
|
if (context->state >= HFP_CODECS_CONNECTION_ESTABLISHED) return 0;
|
||||||
int done = 0;
|
int done = 0;
|
||||||
log_info(" AG run for context_service_level_connection 1\n");
|
// printf(" AG run for context_service_level_connection 1\n");
|
||||||
|
|
||||||
switch(context->command){
|
switch(context->command){
|
||||||
case HFP_CMD_SUPPORTED_FEATURES:
|
case HFP_CMD_SUPPORTED_FEATURES:
|
||||||
@ -500,8 +490,8 @@ static int hfp_ag_run_for_context_service_level_connection(hfp_connection_t * co
|
|||||||
static int hfp_ag_run_for_context_service_level_connection_queries(hfp_connection_t * context){
|
static int hfp_ag_run_for_context_service_level_connection_queries(hfp_connection_t * context){
|
||||||
if (context->state != HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED) return 0;
|
if (context->state != HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED) return 0;
|
||||||
int done = 0;
|
int done = 0;
|
||||||
log_info(" SLC queries: ");
|
printf(" SLC queries: \n");
|
||||||
|
|
||||||
switch(context->command){
|
switch(context->command){
|
||||||
case HFP_CMD_AVAILABLE_CODECS:
|
case HFP_CMD_AVAILABLE_CODECS:
|
||||||
context->suggested_codec = hfp_ag_suggest_codec(context);
|
context->suggested_codec = hfp_ag_suggest_codec(context);
|
||||||
@ -530,20 +520,9 @@ static int hfp_ag_run_for_context_service_level_connection_queries(hfp_connectio
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case HFP_CMD_ENABLE_INDIVIDUAL_AG_INDICATOR_STATUS_UPDATE:{
|
case HFP_CMD_ENABLE_INDIVIDUAL_AG_INDICATOR_STATUS_UPDATE:{
|
||||||
|
|
||||||
hfp_ag_ok(context->rfcomm_cid);
|
hfp_ag_ok(context->rfcomm_cid);
|
||||||
done = 1;
|
done = 1;
|
||||||
break;
|
break;
|
||||||
// int i;
|
|
||||||
// for (i = 0; i < context->ag_indicators_nr; i++){
|
|
||||||
// if (context->ag_indicators[i].enabled == 0) continue;
|
|
||||||
// if (context->ag_indicators[i].status_changed == 0) continue;
|
|
||||||
// hfp_ag_transfer_ag_indicators_status_cmd(context->rfcomm_cid, context->ag_indicators[i]);
|
|
||||||
// done = 1;
|
|
||||||
// context->ag_indicators[i].status_changed = 0;
|
|
||||||
// return done;
|
|
||||||
// }
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
case HFP_CMD_TRIGGER_CODEC_CONNECTION_SETUP:
|
case HFP_CMD_TRIGGER_CODEC_CONNECTION_SETUP:
|
||||||
if (context->hf_trigger_codec_connection_setup){ // received BCC
|
if (context->hf_trigger_codec_connection_setup){ // received BCC
|
||||||
@ -577,6 +556,26 @@ static int hfp_ag_run_for_context_service_level_connection_queries(hfp_connectio
|
|||||||
case HFP_CMD_ENABLE_INDICATOR_STATUS_UPDATE:
|
case HFP_CMD_ENABLE_INDICATOR_STATUS_UPDATE:
|
||||||
printf("TODO\n");
|
printf("TODO\n");
|
||||||
break;
|
break;
|
||||||
|
case HFP_CMD_NONE:
|
||||||
|
if (context->start_call){
|
||||||
|
context->start_call = 0;
|
||||||
|
hfp_ag_indicator_t * indicator = get_ag_indicator_for_name(context, "callsetup");
|
||||||
|
if (!indicator) break;
|
||||||
|
// TODO: do we need this check?
|
||||||
|
if (indicator->status != HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS){
|
||||||
|
context->start_call = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
indicator->status = HFP_CALLSETUP_STATUS_INCOMING_CALL_SETUP_IN_PROGRESS;
|
||||||
|
hfp_ag_transfer_ag_indicators_status_cmd(context->rfcomm_cid, indicator);
|
||||||
|
context->state = HFP_SLE_W2_EXCHANGE_COMMON_CODEC;
|
||||||
|
context->ag_trigger_codec_connection_setup = 1;
|
||||||
|
context->establish_audio_connection = 1;
|
||||||
|
context->start_ringing = 1;
|
||||||
|
done = 1;
|
||||||
|
return done;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -585,7 +584,7 @@ static int hfp_ag_run_for_context_service_level_connection_queries(hfp_connectio
|
|||||||
|
|
||||||
|
|
||||||
static int hfp_ag_run_for_context_codecs_connection(hfp_connection_t * context){
|
static int hfp_ag_run_for_context_codecs_connection(hfp_connection_t * context){
|
||||||
log_info(" AG run for context_codecs_connection: ");
|
printf(" AG run for context_codecs_connection: \n");
|
||||||
if (context->state <= HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED ||
|
if (context->state <= HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED ||
|
||||||
context->state > HFP_W2_DISCONNECT_SCO) return 0;
|
context->state > HFP_W2_DISCONNECT_SCO) return 0;
|
||||||
|
|
||||||
@ -691,10 +690,9 @@ static int hfp_ag_run_for_context_codecs_connection(hfp_connection_t * context){
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (done) return done;
|
if (done) return done;
|
||||||
|
|
||||||
if (context->establish_audio_connection){
|
if (context->establish_audio_connection){
|
||||||
if (context->state < HFP_SLE_W4_EXCHANGE_COMMON_CODEC){
|
if (context->state < HFP_SLE_W4_EXCHANGE_COMMON_CODEC){
|
||||||
printf("hfp_ag_establish_audio_connection ag_trigger_codec_connection_setup");
|
|
||||||
context->ag_trigger_codec_connection_setup = 0;
|
context->ag_trigger_codec_connection_setup = 0;
|
||||||
context->state = HFP_SLE_W4_EXCHANGE_COMMON_CODEC;
|
context->state = HFP_SLE_W4_EXCHANGE_COMMON_CODEC;
|
||||||
context->suggested_codec = hfp_ag_suggest_codec(context);
|
context->suggested_codec = hfp_ag_suggest_codec(context);
|
||||||
@ -702,7 +700,6 @@ static int hfp_ag_run_for_context_codecs_connection(hfp_connection_t * context){
|
|||||||
done = 1;
|
done = 1;
|
||||||
return done;
|
return done;
|
||||||
} else {
|
} else {
|
||||||
printf("create sco");
|
|
||||||
context->state = HFP_W4_SCO_CONNECTED;
|
context->state = HFP_W4_SCO_CONNECTED;
|
||||||
hci_send_cmd(&hci_setup_synchronous_connection, context->con_handle, 8000, 8000, 0xFFFF, hci_get_sco_voice_setting(), 0xFF, 0x003F);
|
hci_send_cmd(&hci_setup_synchronous_connection, context->con_handle, 8000, 8000, 0xFFFF, hci_get_sco_voice_setting(), 0xFF, 0x003F);
|
||||||
done = 1;
|
done = 1;
|
||||||
@ -716,6 +713,17 @@ static int hfp_ag_run_for_context_codecs_connection(hfp_connection_t * context){
|
|||||||
done = 1;
|
done = 1;
|
||||||
return done;
|
return done;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (context->start_ringing){
|
||||||
|
context->start_ringing = 0;
|
||||||
|
hfp_emit_event(hfp_callback, HFP_SUBEVENT_START_RINGINIG, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (context->stop_ringing){
|
||||||
|
context->stop_ringing = 0;
|
||||||
|
hfp_emit_event(hfp_callback, HFP_SUBEVENT_STOP_RINGINIG, 0);
|
||||||
|
}
|
||||||
|
|
||||||
return done;
|
return done;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -728,8 +736,8 @@ static void hfp_run_for_context(hfp_connection_t *context){
|
|||||||
if (!rfcomm_can_send_packet_now(context->rfcomm_cid)) return;
|
if (!rfcomm_can_send_packet_now(context->rfcomm_cid)) return;
|
||||||
log_info("ag hfp_run_for_context rfcomm_can_send_packet_now");
|
log_info("ag hfp_run_for_context rfcomm_can_send_packet_now");
|
||||||
|
|
||||||
if (context->command == HFP_CMD_ERROR){
|
if (context->command == HFP_CMD_UNKNOWN){
|
||||||
log_info("ag hfp_run_for_context HFP_CMD_ERROR");
|
log_info("ag hfp_run_for_context HFP_CMD_UNKNOWN");
|
||||||
hfp_ag_error(context->rfcomm_cid);
|
hfp_ag_error(context->rfcomm_cid);
|
||||||
context->send_ok = 0;
|
context->send_ok = 0;
|
||||||
context->send_error = 0;
|
context->send_error = 0;
|
||||||
@ -886,78 +894,6 @@ void hfp_ag_report_extended_audio_gateway_error_result_code(bd_addr_t bd_addr, h
|
|||||||
hfp_run_for_context(connection);
|
hfp_run_for_context(connection);
|
||||||
}
|
}
|
||||||
|
|
||||||
void hfp_ag_transfer_call_status(bd_addr_t bd_addr, hfp_call_status_t status){
|
|
||||||
hfp_connection_t * connection = get_hfp_connection_context_for_bd_addr(bd_addr);
|
|
||||||
if (!connection){
|
|
||||||
log_error("HFP HF: connection doesn't exist.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!connection->enable_status_update_for_ag_indicators) return;
|
|
||||||
hfp_ag_update_indicator_status(connection, (char *)"call", status);
|
|
||||||
}
|
|
||||||
|
|
||||||
void hfp_ag_transfer_callsetup_status(bd_addr_t bd_addr, hfp_callsetup_status_t status){
|
|
||||||
hfp_connection_t * connection = get_hfp_connection_context_for_bd_addr(bd_addr);
|
|
||||||
if (!connection){
|
|
||||||
log_error("HFP HF: connection doesn't exist.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!connection->enable_status_update_for_ag_indicators) return;
|
|
||||||
hfp_ag_update_indicator_status(connection, (char *)"callsetup", status);
|
|
||||||
}
|
|
||||||
|
|
||||||
void hfp_ag_transfer_callheld_status(bd_addr_t bd_addr, hfp_callheld_status_t status){
|
|
||||||
hfp_connection_t * connection = get_hfp_connection_context_for_bd_addr(bd_addr);
|
|
||||||
if (!connection){
|
|
||||||
log_error("HFP AG: connection doesn't exist.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!connection->enable_status_update_for_ag_indicators) return;
|
|
||||||
hfp_ag_update_indicator_status(connection, (char *)"callheld", status);
|
|
||||||
hfp_run_for_context(connection);
|
|
||||||
}
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
static void hfp_ag_codec_connection_setup(hfp_connection_t * connection){
|
|
||||||
if (!connection){
|
|
||||||
log_error("HFP AG: connection doesn't exist.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// TODO:
|
|
||||||
hfp_run_for_context(connection);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param handle
|
|
||||||
* @param transmit_bandwidth 8000(64kbps)
|
|
||||||
* @param receive_bandwidth 8000(64kbps)
|
|
||||||
* @param max_latency >= 7ms for eSCO, 0xFFFF do not care
|
|
||||||
* @param voice_settings e.g. CVSD, Input Coding: Linear, Input Data Format: 2’s complement, data 16bit: 00011000000 == 0x60
|
|
||||||
* @param retransmission_effort e.g. 0xFF do not care
|
|
||||||
* @param packet_type at least EV3 for eSCO
|
|
||||||
|
|
||||||
hci_send_cmd(&hci_setup_synchronous_connection, rfcomm_handle, 8000, 8000, 0xFFFF, 0x0060, 0xFF, 0x003F);
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
static void hfp_ag_negotiate_codecs(bd_addr_t bd_addr){
|
|
||||||
hfp_ag_establish_service_level_connection(bd_addr);
|
|
||||||
hfp_connection_t * connection = get_hfp_connection_context_for_bd_addr(bd_addr);
|
|
||||||
if (!has_codec_negotiation_feature(connection)) return;
|
|
||||||
if (connection->remote_codecs_nr == 0) return;
|
|
||||||
|
|
||||||
if (connection->state >= HFP_W2_DISCONNECT_SCO) return;
|
|
||||||
|
|
||||||
if (connection->state != HFP_SLE_W2_EXCHANGE_COMMON_CODEC &&
|
|
||||||
connection->state != HFP_SLE_W4_EXCHANGE_COMMON_CODEC){
|
|
||||||
connection->ag_trigger_codec_connection_setup = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
hfp_run_for_context(connection);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void hfp_ag_establish_audio_connection(bd_addr_t bd_addr){
|
void hfp_ag_establish_audio_connection(bd_addr_t bd_addr){
|
||||||
hfp_ag_establish_service_level_connection(bd_addr);
|
hfp_ag_establish_service_level_connection(bd_addr);
|
||||||
@ -988,3 +924,26 @@ void hfp_ag_release_audio_connection(bd_addr_t bd_addr){
|
|||||||
hfp_release_audio_connection(connection);
|
hfp_release_audio_connection(connection);
|
||||||
hfp_run_for_context(connection);
|
hfp_run_for_context(connection);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief
|
||||||
|
*/
|
||||||
|
void hfp_ag_call(bd_addr_t bd_addr){
|
||||||
|
hfp_ag_establish_service_level_connection(bd_addr);
|
||||||
|
hfp_connection_t * connection = get_hfp_connection_context_for_bd_addr(bd_addr);
|
||||||
|
connection->start_call = 1;
|
||||||
|
printf("hfp_ag_call\n");
|
||||||
|
hfp_run_for_context(connection);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief
|
||||||
|
*/
|
||||||
|
void hfp_ag_terminate_call(bd_addr_t bd_addr){
|
||||||
|
hfp_connection_t * connection = get_hfp_connection_context_for_bd_addr(bd_addr);
|
||||||
|
if (connection->state != HFP_AUDIO_CONNECTION_ESTABLISHED) return;
|
||||||
|
connection->terminate_call = 1;
|
||||||
|
hfp_run_for_context(connection);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
10
src/hfp_ag.h
10
src/hfp_ag.h
@ -162,6 +162,16 @@ void hfp_ag_establish_audio_connection(bd_addr_t bd_addr);
|
|||||||
void hfp_ag_release_audio_connection(bd_addr_t bd_addr);
|
void hfp_ag_release_audio_connection(bd_addr_t bd_addr);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief
|
||||||
|
*/
|
||||||
|
void hfp_ag_call(bd_addr_t bd_addr);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief
|
||||||
|
*/
|
||||||
|
void hfp_ag_terminate_call(bd_addr_t bd_addr);
|
||||||
|
|
||||||
/* API_END */
|
/* API_END */
|
||||||
|
|
||||||
#if defined __cplusplus
|
#if defined __cplusplus
|
||||||
|
@ -97,6 +97,7 @@ static hfp_generic_status_indicator_t hf_indicators[] = {
|
|||||||
static uint8_t service_level_connection_established = 0;
|
static uint8_t service_level_connection_established = 0;
|
||||||
static uint8_t codecs_connection_established = 0;
|
static uint8_t codecs_connection_established = 0;
|
||||||
static uint8_t audio_connection_established = 0;
|
static uint8_t audio_connection_established = 0;
|
||||||
|
static uint8_t start_ringing = 0;
|
||||||
|
|
||||||
|
|
||||||
int expected_rfcomm_command(const char * expected_cmd){
|
int expected_rfcomm_command(const char * expected_cmd){
|
||||||
@ -164,6 +165,14 @@ void packet_handler(uint8_t * event, uint16_t event_size){
|
|||||||
printf("\n** AC released **\n\n");
|
printf("\n** AC released **\n\n");
|
||||||
audio_connection_established = 0;
|
audio_connection_established = 0;
|
||||||
break;
|
break;
|
||||||
|
case HFP_SUBEVENT_START_RINGINIG:
|
||||||
|
printf("\n** Start ringing **\n\n");
|
||||||
|
start_ringing = 1;
|
||||||
|
break;
|
||||||
|
case HFP_SUBEVENT_STOP_RINGINIG:
|
||||||
|
printf("\n** Stop ringing **\n\n");
|
||||||
|
start_ringing = 0;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
printf("event not handled %u\n", event[2]);
|
printf("event not handled %u\n", event[2]);
|
||||||
break;
|
break;
|
||||||
@ -201,9 +210,21 @@ TEST_GROUP(HFPClient){
|
|||||||
codecs_connection_established = 0;
|
codecs_connection_established = 0;
|
||||||
simulate_test_sequence((char **) test_steps, nr_test_steps);
|
simulate_test_sequence((char **) test_steps, nr_test_steps);
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
TEST(HFPClient, HFAnswerIncomingCallWithInBandRingTone){
|
||||||
|
setup_hfp_service_level_connection(default_slc_setup(), default_slc_setup_size());
|
||||||
|
CHECK_EQUAL(service_level_connection_established, 1);
|
||||||
|
|
||||||
|
hfp_ag_call(device_addr);
|
||||||
|
simulate_test_sequence(default_ic_setup(), default_ic_setup_size());
|
||||||
|
CHECK_EQUAL(audio_connection_established, 1);
|
||||||
|
|
||||||
|
simulate_test_sequence(alert_ic_setup(), alert_ic_setup_size());
|
||||||
|
CHECK_EQUAL(start_ringing, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
TEST(HFPClient, HFAudioConnectionEstablished){
|
TEST(HFPClient, HFAudioConnectionEstablished){
|
||||||
setup_hfp_service_level_connection(default_slc_setup(), default_slc_setup_size());
|
setup_hfp_service_level_connection(default_slc_setup(), default_slc_setup_size());
|
||||||
CHECK_EQUAL(service_level_connection_established, 1);
|
CHECK_EQUAL(service_level_connection_established, 1);
|
||||||
|
@ -143,6 +143,41 @@ hfp_test_item_t cc_tests[] = {
|
|||||||
TEST_SEQUENCE(cc_test4)
|
TEST_SEQUENCE(cc_test4)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* Incoming call sequence */
|
||||||
|
const char * ic_test1[] = {
|
||||||
|
"+CIEV:3,1",
|
||||||
|
"NOP",
|
||||||
|
"BCS:1",
|
||||||
|
"AT+BCS=1",
|
||||||
|
"OK",
|
||||||
|
"NOP"
|
||||||
|
};
|
||||||
|
|
||||||
|
const char * ic_alert_test1[] = {
|
||||||
|
"NOP",
|
||||||
|
// //"RING",
|
||||||
|
// "NOP",
|
||||||
|
// "+CLIP:\"1234\",128",
|
||||||
|
// "NOP",
|
||||||
|
// "InBandRingTone",
|
||||||
|
// "NOP",
|
||||||
|
// "RING",
|
||||||
|
// "NOP",
|
||||||
|
// "+CLIP:\"1234\",128", // 128-143, 144-159, 160-175
|
||||||
|
// "NOP",
|
||||||
|
// "InBandRingTone",
|
||||||
|
// "ATA",
|
||||||
|
// "OK",
|
||||||
|
// "NOP",
|
||||||
|
// "+CIEV:2,1", // call = 1
|
||||||
|
// "NOP",
|
||||||
|
// "+CIEV:3,0"
|
||||||
|
};
|
||||||
|
|
||||||
|
hfp_test_item_t ic_tests[] = {
|
||||||
|
TEST_SEQUENCE(ic_test1)
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//////////////
|
//////////////
|
||||||
@ -165,10 +200,15 @@ int default_slc_cmds_setup_size(){ return sizeof(slc_cmds_test1)/sizeof(char*);}
|
|||||||
|
|
||||||
// CC
|
// CC
|
||||||
hfp_test_item_t * hfp_cc_tests(){ return cc_tests;}
|
hfp_test_item_t * hfp_cc_tests(){ return cc_tests;}
|
||||||
int cc_tests_size(){ return sizeof(cc_tests) /test_item_size;
|
int cc_tests_size(){ return sizeof(cc_tests) /test_item_size;}
|
||||||
}
|
|
||||||
char ** default_cc_setup() { return (char **)cc_test1;}
|
char ** default_cc_setup() { return (char **)cc_test1;}
|
||||||
int default_cc_setup_size(){ return sizeof(cc_test1)/sizeof(char*);}
|
int default_cc_setup_size(){ return sizeof(cc_test1)/sizeof(char*);}
|
||||||
|
|
||||||
|
// IC
|
||||||
|
char ** default_ic_setup() { return (char **)ic_test1;}
|
||||||
|
int default_ic_setup_size(){ return sizeof(ic_test1)/sizeof(char*);}
|
||||||
|
|
||||||
|
char ** alert_ic_setup() { return (char **)ic_alert_test1;}
|
||||||
|
int alert_ic_setup_size(){ return sizeof(ic_alert_test1)/sizeof(char*);}
|
||||||
|
|
@ -70,3 +70,9 @@ int cc_tests_size();
|
|||||||
char ** default_cc_setup();
|
char ** default_cc_setup();
|
||||||
int default_cc_setup_size();
|
int default_cc_setup_size();
|
||||||
|
|
||||||
|
/* Incoming call (ic) test sequences */
|
||||||
|
char ** default_ic_setup();
|
||||||
|
int default_ic_setup_size();
|
||||||
|
|
||||||
|
char ** alert_ic_setup();
|
||||||
|
int alert_ic_setup_size();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user