mirror of
https://github.com/bluekitchen/btstack.git
synced 2025-04-17 20:42:47 +00:00
hfp: start audio conneciton
This commit is contained in:
parent
289b079ef5
commit
912d34aa7f
@ -628,7 +628,8 @@ extern "C" {
|
||||
#define HFP_SUBEVENT_AG_INDICATOR_STATUS_CHANGED 0x06
|
||||
#define HFP_SUBEVENT_NETWORK_OPERATOR_CHANGED 0x07
|
||||
#define HFP_SUBEVENT_EXTENDED_AUDIO_GATEWAY_ERROR 0x08
|
||||
|
||||
#define HFP_SUBEVENT_AUDIO_CONNECTION_COMPLETE 0x09
|
||||
|
||||
// ANCS Client
|
||||
#define ANCS_CLIENT_CONNECTED 0xF0
|
||||
#define ANCS_CLIENT_NOTIFICATION 0xF1
|
||||
|
109
src/hfp.c
109
src/hfp.c
@ -245,6 +245,41 @@ static hfp_connection_t * get_hfp_connection_context_for_handle(uint16_t handle)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void hfp_reset_context_flags(hfp_connection_t * context){
|
||||
context->wait_ok = 0;
|
||||
context->send_ok = 0;
|
||||
context->send_error = 0;
|
||||
|
||||
context->keep_separator = 0;
|
||||
|
||||
context->retrieve_ag_indicators = 0; // HFP_CMD_INDICATOR, check if needed
|
||||
context->retrieve_ag_indicators_status = 0;
|
||||
|
||||
context->list_generic_status_indicators = 0; // HFP_CMD_LIST_GENERIC_STATUS_INDICATOR
|
||||
context->retrieve_generic_status_indicators = 0; // HFP_CMD_GENERIC_STATUS_INDICATOR
|
||||
context->retrieve_generic_status_indicators_state = 0; // HFP_CMD_GENERIC_STATUS_INDICATOR_STATE
|
||||
|
||||
context->change_status_update_for_individual_ag_indicators = 0;
|
||||
|
||||
context->operator_name_format = 0;
|
||||
context->operator_name = 0;
|
||||
context->operator_name_changed = 0;
|
||||
|
||||
context->enable_extended_audio_gateway_error_report = 0;
|
||||
context->extended_audio_gateway_error = 0;
|
||||
|
||||
// can come any time (here taken into account only after SLE),
|
||||
// if codec negotiation feature is set
|
||||
context->notify_ag_on_new_codecs = 0;
|
||||
|
||||
// establish codecs connection
|
||||
context->trigger_codec_connection_setup = 0;
|
||||
context->remote_codec_received = 0;
|
||||
|
||||
context->establish_audio_connection = 0;
|
||||
context->release_audio_connection = 0;
|
||||
}
|
||||
|
||||
static hfp_connection_t * create_hfp_connection_context(){
|
||||
hfp_connection_t * context = btstack_memory_hfp_connection_get();
|
||||
if (!context) return NULL;
|
||||
@ -459,6 +494,59 @@ void hfp_handle_hci_event(hfp_callback_t callback, uint8_t packet_type, uint8_t
|
||||
}
|
||||
break;
|
||||
|
||||
case HCI_EVENT_SYNCHRONOUS_CONNECTION_COMPLETE:{
|
||||
int index = 2;
|
||||
uint8_t status = packet[index++];
|
||||
uint16_t sco_handle = READ_BT_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 = READ_BT_16(packet, index); // measured in bytes
|
||||
index+=2;
|
||||
uint16_t tx_packet_length = READ_BT_16(packet, index); // measured in bytes
|
||||
index+=2;
|
||||
uint8_t air_mode = packet[index];
|
||||
|
||||
if (status != 0){
|
||||
log_error("(e)SCO Connection is not established, status %u", status);
|
||||
break;
|
||||
}
|
||||
switch (link_type){
|
||||
case 0x00:
|
||||
printf("SCO Connection established. \n");
|
||||
if (transmission_interval != 0) log_error("SCO Connection: transmission_interval not zero: %d.", transmission_interval);
|
||||
if (retransmission_interval != 0) log_error("SCO Connection: retransmission_interval not zero: %d.", retransmission_interval);
|
||||
if (rx_packet_length != 0) log_error("SCO Connection: rx_packet_length not zero: %d.", rx_packet_length);
|
||||
if (tx_packet_length != 0) log_error("SCO Connection: tx_packet_length not zero: %d.", tx_packet_length);
|
||||
break;
|
||||
case 0x02:
|
||||
printf("eSCO Connection established. \n");
|
||||
break;
|
||||
default:
|
||||
log_error("(e)SCO reserved link_type 0x%2x", link_type);
|
||||
break;
|
||||
}
|
||||
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);
|
||||
|
||||
context = get_hfp_connection_context_for_bd_addr(address);
|
||||
|
||||
if (context->state == HFP_W4_CONNECTION_ESTABLISHED_TO_SHUTDOWN){
|
||||
context->state = HFP_W2_DISCONNECT_SCO;
|
||||
break;
|
||||
}
|
||||
|
||||
context->sco_handle = sco_handle;
|
||||
context->state = HFP_AUDIO_CONNECTION_ESTABLISHED;
|
||||
hfp_emit_event(callback, HFP_SUBEVENT_AUDIO_CONNECTION_COMPLETE, packet[2]);
|
||||
break;
|
||||
}
|
||||
|
||||
case RFCOMM_EVENT_CHANNEL_CLOSED:
|
||||
rfcomm_cid = READ_BT_16(packet,2);
|
||||
context = get_hfp_connection_context_for_rfcomm_cid(rfcomm_cid);
|
||||
@ -605,6 +693,17 @@ void process_command(hfp_connection_t * context){
|
||||
context->command = HFP_CMD_ENABLE_EXTENDED_AUDIO_GATEWAY_ERROR;
|
||||
return;
|
||||
}
|
||||
|
||||
if (strncmp((char *)context->line_buffer+offset, HFP_TRIGGER_CODEC_CONNECTION_SETUP, strlen(HFP_TRIGGER_CODEC_CONNECTION_SETUP)) == 0){
|
||||
context->command = HFP_CMD_TRIGGER_CODEC_CONNECTION_SETUP;
|
||||
return;
|
||||
}
|
||||
|
||||
if (strncmp((char *)context->line_buffer+offset, HFP_CONFIRM_COMMON_CODEC, strlen(HFP_CONFIRM_COMMON_CODEC)) == 0){
|
||||
context->command = HFP_CMD_CONFIRM_COMMON_CODEC;
|
||||
return;
|
||||
}
|
||||
|
||||
printf(" process unknown command 3 %s \n", context->line_buffer);
|
||||
}
|
||||
|
||||
@ -921,10 +1020,7 @@ void hfp_establish_service_level_connection(bd_addr_t bd_addr, uint16_t service_
|
||||
}
|
||||
|
||||
void hfp_release_service_level_connection(hfp_connection_t * context){
|
||||
if (!context) {
|
||||
log_error("hfp_release_service_level_connection failed");
|
||||
return;
|
||||
}
|
||||
if (!context) return;
|
||||
|
||||
switch (context->state){
|
||||
case HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED:
|
||||
@ -939,4 +1035,9 @@ void hfp_release_service_level_connection(hfp_connection_t * context){
|
||||
return;
|
||||
}
|
||||
|
||||
void hfp_establish_audio_connection(hfp_connection_t * context, uint8_t codec_negotiation_feature_enabled){
|
||||
}
|
||||
|
||||
void hfp_release_audio_connection(hfp_connection_t * context){
|
||||
}
|
||||
|
||||
|
37
src/hfp.h
37
src/hfp.h
@ -112,6 +112,8 @@ extern "C" {
|
||||
#define HFP_QUERY_OPERATOR_SELECTION "+COPS" // +COPS: <mode>,0,<opearator>
|
||||
#define HFP_ENABLE_EXTENDED_AUDIO_GATEWAY_ERROR "+CMEE"
|
||||
#define HFP_EXTENDED_AUDIO_GATEWAY_ERROR "+CME ERROR"
|
||||
#define HFP_TRIGGER_CODEC_CONNECTION_SETUP "+BCC"
|
||||
#define HFP_CONFIRM_COMMON_CODEC "+BCS"
|
||||
|
||||
#define HFP_OK "OK"
|
||||
#define HFP_ERROR "ERROR"
|
||||
@ -137,7 +139,9 @@ typedef enum {
|
||||
HFP_CMD_QUERY_OPERATOR_SELECTION,
|
||||
|
||||
HFP_CMD_ENABLE_EXTENDED_AUDIO_GATEWAY_ERROR,
|
||||
HFP_CMD_EXTENDED_AUDIO_GATEWAY_ERROR
|
||||
HFP_CMD_EXTENDED_AUDIO_GATEWAY_ERROR,
|
||||
HFP_CMD_TRIGGER_CODEC_CONNECTION_SETUP,
|
||||
HFP_CMD_CONFIRM_COMMON_CODEC
|
||||
|
||||
} hfp_command_t;
|
||||
|
||||
@ -238,6 +242,19 @@ typedef enum {
|
||||
|
||||
HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED, // 22
|
||||
|
||||
HFP_SLE_W2_EXCHANGE_COMMON_CODEC,
|
||||
HFP_SLE_W4_EXCHANGE_COMMON_CODEC,
|
||||
|
||||
HFP_CODECS_CONNECTION_ESTABLISHED,
|
||||
|
||||
HFP_CCE_W2_ESTABLISH_SCO,
|
||||
HFP_CCE_W4_SCO_CONNECTION_ESTABLISHED,
|
||||
|
||||
HFP_AUDIO_CONNECTION_ESTABLISHED,
|
||||
|
||||
HFP_W2_DISCONNECT_SCO,
|
||||
HFP_W4_SCO_DISCONNECTED,
|
||||
|
||||
HFP_W2_DISCONNECT_RFCOMM,
|
||||
HFP_W4_RFCOMM_DISCONNECTED,
|
||||
HFP_W4_RFCOMM_DISCONNECTED_AND_RESTART,
|
||||
@ -279,6 +296,7 @@ typedef struct hfp_connection {
|
||||
|
||||
bd_addr_t remote_addr;
|
||||
uint16_t con_handle;
|
||||
uint16_t sco_handle;
|
||||
uint16_t rfcomm_channel_nr;
|
||||
uint16_t rfcomm_cid;
|
||||
|
||||
@ -294,6 +312,8 @@ typedef struct hfp_connection {
|
||||
int line_size;
|
||||
|
||||
uint32_t remote_supported_features;
|
||||
|
||||
// TODO: rename into hf_codecs_nr
|
||||
int remote_codecs_nr;
|
||||
uint16_t remote_codecs[HFP_MAX_INDICATOR_DESC_SIZE];
|
||||
int ag_indicators_nr;
|
||||
@ -335,6 +355,17 @@ typedef struct hfp_connection {
|
||||
uint8_t enable_extended_audio_gateway_error_report;
|
||||
uint8_t extended_audio_gateway_error;
|
||||
|
||||
// can come any time (here taken into account only after SLE),
|
||||
// if codec negotiation feature is set
|
||||
uint8_t notify_ag_on_new_codecs;
|
||||
|
||||
// establish codecs connection
|
||||
uint8_t trigger_codec_connection_setup;
|
||||
uint8_t ag_ready_for_codecs_connection_setup;
|
||||
uint8_t remote_codec_received;
|
||||
|
||||
uint8_t establish_audio_connection;
|
||||
uint8_t release_audio_connection;
|
||||
|
||||
} hfp_connection_t;
|
||||
|
||||
@ -358,7 +389,9 @@ void hfp_parse(hfp_connection_t * context, uint8_t byte);
|
||||
void hfp_init(uint16_t rfcomm_channel_nr);
|
||||
void hfp_establish_service_level_connection(bd_addr_t bd_addr, uint16_t service_uuid);
|
||||
void hfp_release_service_level_connection(hfp_connection_t * connection);
|
||||
|
||||
void hfp_establish_audio_connection(hfp_connection_t * context, uint8_t codec_negotiation_feature_enabled);
|
||||
void hfp_release_audio_connection(hfp_connection_t * context);
|
||||
void hfp_reset_context_flags(hfp_connection_t * context);
|
||||
|
||||
const char * hfp_hf_feature(int index);
|
||||
const char * hfp_ag_feature(int index);
|
||||
|
101
src/hfp_ag.c
101
src/hfp_ag.c
@ -348,6 +348,27 @@ int hfp_ag_report_network_operator_name_cmd(uint16_t cid, hfp_network_opearator_
|
||||
return send_str_over_rfcomm(cid, buffer);
|
||||
}
|
||||
|
||||
|
||||
int hfp_ag_cmd_confirm_codec(uint16_t cid, uint8_t codec){
|
||||
char buffer[30];
|
||||
sprintf(buffer, "\r\nOK\r\n%s=%d\r\n", HFP_CONFIRM_COMMON_CODEC, codec);
|
||||
return send_str_over_rfcomm(cid, buffer);
|
||||
}
|
||||
|
||||
static uint8_t hfp_ag_choose_codec(hfp_connection_t *context){
|
||||
int i,j;
|
||||
uint8_t codec = 0;
|
||||
for (i = 0; i < hfp_codecs_nr; i++){
|
||||
for (j = 0; j < context->remote_codecs_nr; j++){
|
||||
if (context->remote_codecs[j] == hfp_codecs[i]){
|
||||
codec = context->remote_codecs[j];
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
return codec;
|
||||
}
|
||||
|
||||
void hfp_run_for_context(hfp_connection_t *context){
|
||||
// printf(" hfp_run_for_context \n");
|
||||
if (!context) return;
|
||||
@ -387,7 +408,37 @@ void hfp_run_for_context(hfp_connection_t *context){
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (context->state == HFP_AUDIO_CONNECTION_ESTABLISHED){
|
||||
// TODO
|
||||
}
|
||||
|
||||
switch(context->command){
|
||||
// START codec setup
|
||||
case HFP_CMD_TRIGGER_CODEC_CONNECTION_SETUP:
|
||||
if (!hfp_ag_choose_codec(context)){
|
||||
hfp_ag_error(context->rfcomm_cid);
|
||||
break;
|
||||
}
|
||||
switch (context->state){
|
||||
case HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED:
|
||||
// hfp_ag_ok(context->rfcomm_cid);
|
||||
context->negotiated_codec = hfp_ag_choose_codec(context);
|
||||
hfp_ag_cmd_confirm_codec(context->rfcomm_cid, context->negotiated_codec);
|
||||
context->state = HFP_SLE_W4_EXCHANGE_COMMON_CODEC;
|
||||
break;
|
||||
default:
|
||||
hfp_ag_error(context->rfcomm_cid);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case HFP_CMD_CONFIRM_COMMON_CODEC:
|
||||
hfp_ag_ok(context->rfcomm_cid);
|
||||
context->state = HFP_CODECS_CONNECTION_ESTABLISHED;
|
||||
break;
|
||||
// END codec setup
|
||||
|
||||
case HFP_CMD_SUPPORTED_FEATURES:
|
||||
switch(context->state){
|
||||
case HFP_W4_EXCHANGE_SUPPORTED_FEATURES:
|
||||
@ -644,9 +695,9 @@ void hfp_ag_transfer_callsetup_status(bd_addr_t bd_addr, hfp_callsetup_status_t
|
||||
}
|
||||
|
||||
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);
|
||||
hfp_connection_t * connection = get_hfp_connection_context_for_bd_addr(bd_addr);
|
||||
if (!connection){
|
||||
log_error("HFP HF: connection doesn't exist.");
|
||||
log_error("HFP AG: connection doesn't exist.");
|
||||
return;
|
||||
}
|
||||
if (!connection->enable_status_update_for_ag_indicators) return;
|
||||
@ -654,24 +705,58 @@ void hfp_ag_transfer_callheld_status(bd_addr_t bd_addr, hfp_callheld_status_t st
|
||||
hfp_run_for_context(connection);
|
||||
}
|
||||
|
||||
void hfp_ag_audio_connection_setup(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);
|
||||
void hfp_ag_codec_connection_setup(hfp_connection_t * connection){
|
||||
if (!connection){
|
||||
log_error("HFP HF: connection doesn't exist.");
|
||||
log_error("HFP AG: connection doesn't exist.");
|
||||
return;
|
||||
}
|
||||
// TODO:
|
||||
hfp_run_for_context(connection);
|
||||
}
|
||||
|
||||
void hfp_ag_audio_connection_release(bd_addr_t bd_addr){
|
||||
/**
|
||||
* @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);
|
||||
|
||||
*/
|
||||
|
||||
void hfp_ag_establish_audio_connection(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 (!connection){
|
||||
log_error("HFP HF: connection doesn't exist.");
|
||||
log_error("HFP AG: connection doesn't exist.");
|
||||
return;
|
||||
}
|
||||
if (connection->state == HFP_AUDIO_CONNECTION_ESTABLISHED) return;
|
||||
// if (connection->remote_codecs_nr == 0) {
|
||||
// log_error("HFP AG: codecs not exchanged, or no codecs specified in HF.");
|
||||
// return;
|
||||
// }
|
||||
connection->trigger_codec_connection_setup = 1;
|
||||
connection->establish_audio_connection = 1;
|
||||
|
||||
if (!has_codec_negotiation_feature(connection)){
|
||||
connection->trigger_codec_connection_setup = 0;
|
||||
connection->establish_audio_connection = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if (connection->state == HFP_CODECS_CONNECTION_ESTABLISHED){
|
||||
connection->trigger_codec_connection_setup = 0;
|
||||
return;
|
||||
}
|
||||
hfp_run_for_context(connection);
|
||||
}
|
||||
|
||||
void hfp_ag_release_audio_connection(bd_addr_t bd_addr){
|
||||
hfp_connection_t * connection = get_hfp_connection_context_for_bd_addr(bd_addr);
|
||||
// TODO:
|
||||
hfp_run_for_context(connection);
|
||||
}
|
||||
|
@ -152,12 +152,12 @@ void hfp_ag_transfer_callheld_status(bd_addr_t bd_addr, hfp_callheld_status_t st
|
||||
/**
|
||||
* @brief
|
||||
*/
|
||||
void hfp_ag_audio_connection_setup(bd_addr_t bd_addr);
|
||||
void hfp_ag_establish_audio_connection(bd_addr_t bd_addr);
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*/
|
||||
void hfp_ag_audio_connection_release(bd_addr_t bd_addr);
|
||||
void hfp_ag_release_audio_connection(bd_addr_t bd_addr);
|
||||
|
||||
|
||||
/* API_END */
|
||||
|
414
src/hfp_hf.c
414
src/hfp_hf.c
@ -82,7 +82,13 @@ void hfp_hf_register_packet_handler(hfp_callback_t callback){
|
||||
hfp_callback = callback;
|
||||
}
|
||||
|
||||
|
||||
static int hfp_hf_supports_codec(uint8_t codec){
|
||||
int i;
|
||||
for (i = 0; i < hfp_codecs_nr; i++){
|
||||
if (hfp_codecs[i] == codec) return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
static int has_codec_negotiation_feature(hfp_connection_t * connection){
|
||||
int hf = get_bit(hfp_supported_features, HFP_HFSF_CODEC_NEGOTIATION);
|
||||
int ag = get_bit(connection->remote_supported_features, HFP_AGSF_CODEC_NEGOTIATION);
|
||||
@ -112,14 +118,14 @@ void hfp_hf_create_sdp_record(uint8_t * service, int rfcomm_channel_nr, const ch
|
||||
}
|
||||
|
||||
|
||||
int hfp_hs_exchange_supported_features_cmd(uint16_t cid){
|
||||
int hfp_hf_cmd_exchange_supported_features(uint16_t cid){
|
||||
char buffer[20];
|
||||
sprintf(buffer, "AT%s=%d\r\n", HFP_SUPPORTED_FEATURES, hfp_supported_features);
|
||||
// printf("exchange_supported_features %s\n", buffer);
|
||||
return send_str_over_rfcomm(cid, buffer);
|
||||
}
|
||||
|
||||
int hfp_hs_retrieve_codec_cmd(uint16_t cid){
|
||||
int hfp_hf_cmd_notify_on_codecs(uint16_t cid){
|
||||
char buffer[30];
|
||||
int offset = snprintf(buffer, sizeof(buffer), "AT%s=", HFP_AVAILABLE_CODECS);
|
||||
offset += join(buffer+offset, sizeof(buffer)-offset, hfp_codecs, hfp_codecs_nr);
|
||||
@ -128,28 +134,28 @@ int hfp_hs_retrieve_codec_cmd(uint16_t cid){
|
||||
return send_str_over_rfcomm(cid, buffer);
|
||||
}
|
||||
|
||||
int hfp_hs_retrieve_indicators_cmd(uint16_t cid){
|
||||
int hfp_hf_cmd_retrieve_indicators(uint16_t cid){
|
||||
char buffer[20];
|
||||
sprintf(buffer, "AT%s=?\r\n", HFP_INDICATOR);
|
||||
// printf("retrieve_indicators %s\n", buffer);
|
||||
return send_str_over_rfcomm(cid, buffer);
|
||||
}
|
||||
|
||||
int hfp_hs_retrieve_indicators_status_cmd(uint16_t cid){
|
||||
int hfp_hf_cmd_retrieve_indicators_status(uint16_t cid){
|
||||
char buffer[20];
|
||||
sprintf(buffer, "AT%s?\r\n", HFP_INDICATOR);
|
||||
// printf("retrieve_indicators_status %s\n", buffer);
|
||||
return send_str_over_rfcomm(cid, buffer);
|
||||
}
|
||||
|
||||
int hfp_hs_activate_status_update_for_all_ag_indicators_cmd(uint16_t cid, uint8_t activate){
|
||||
int hfp_hf_cmd_activate_status_update_for_all_ag_indicators(uint16_t cid, uint8_t activate){
|
||||
char buffer[20];
|
||||
sprintf(buffer, "AT%s=3,0,0,%d\r\n", HFP_ENABLE_STATUS_UPDATE_FOR_AG_INDICATORS, activate);
|
||||
// printf("toggle_indicator_status_update %s\n", buffer);
|
||||
return send_str_over_rfcomm(cid, buffer);
|
||||
}
|
||||
|
||||
int hfp_hs_activate_status_update_for_ag_indicator_cmd(uint16_t cid, uint32_t indicators_status, int indicators_nr){
|
||||
int hfp_hf_cmd_activate_status_update_for_ag_indicator(uint16_t cid, uint32_t indicators_status, int indicators_nr){
|
||||
char buffer[50];
|
||||
int offset = snprintf(buffer, sizeof(buffer), "AT%s=", HFP_UPDATE_ENABLE_STATUS_FOR_INDIVIDUAL_AG_INDICATORS);
|
||||
offset += join_bitmap(buffer+offset, sizeof(buffer)-offset, indicators_status, indicators_nr);
|
||||
@ -158,14 +164,14 @@ int hfp_hs_activate_status_update_for_ag_indicator_cmd(uint16_t cid, uint32_t in
|
||||
return send_str_over_rfcomm(cid, buffer);
|
||||
}
|
||||
|
||||
int hfp_hs_retrieve_can_hold_call_cmd(uint16_t cid){
|
||||
int hfp_hf_cmd_retrieve_can_hold_call(uint16_t cid){
|
||||
char buffer[20];
|
||||
sprintf(buffer, "AT%s=?\r\n", HFP_SUPPORT_CALL_HOLD_AND_MULTIPARTY_SERVICES);
|
||||
// printf("retrieve_can_hold_call %s\n", buffer);
|
||||
return send_str_over_rfcomm(cid, buffer);
|
||||
}
|
||||
|
||||
int hfp_hs_list_supported_generic_status_indicators_cmd(uint16_t cid){
|
||||
int hfp_hf_cmd_list_supported_generic_status_indicators(uint16_t cid){
|
||||
char buffer[30];
|
||||
int offset = snprintf(buffer, sizeof(buffer), "AT%s=", HFP_GENERIC_STATUS_INDICATOR);
|
||||
offset += join(buffer+offset, sizeof(buffer)-offset, hfp_indicators, hfp_indicators_nr);
|
||||
@ -174,38 +180,50 @@ int hfp_hs_list_supported_generic_status_indicators_cmd(uint16_t cid){
|
||||
return send_str_over_rfcomm(cid, buffer);
|
||||
}
|
||||
|
||||
int hfp_hs_retrieve_supported_generic_status_indicators_cmd(uint16_t cid){
|
||||
int hfp_hf_cmd_retrieve_supported_generic_status_indicators(uint16_t cid){
|
||||
char buffer[20];
|
||||
sprintf(buffer, "AT%s=?\r\n", HFP_GENERIC_STATUS_INDICATOR);
|
||||
// printf("retrieve_supported_generic_status_indicators %s\n", buffer);
|
||||
return send_str_over_rfcomm(cid, buffer);
|
||||
}
|
||||
|
||||
int hfp_hs_list_initital_supported_generic_status_indicators_cmd(uint16_t cid){
|
||||
int hfp_hf_cmd_list_initital_supported_generic_status_indicators(uint16_t cid){
|
||||
char buffer[20];
|
||||
sprintf(buffer, "AT%s?\r\n", HFP_GENERIC_STATUS_INDICATOR);
|
||||
// printf("list_initital_supported_generic_status_indicators %s\n", buffer);
|
||||
return send_str_over_rfcomm(cid, buffer);
|
||||
}
|
||||
|
||||
int hfp_hs_query_operator_name_format_cmd(uint16_t cid){
|
||||
int hfp_hf_cmd_query_operator_name_format(uint16_t cid){
|
||||
char buffer[20];
|
||||
sprintf(buffer, "AT%s=3,0\r\n", HFP_QUERY_OPERATOR_SELECTION);
|
||||
return send_str_over_rfcomm(cid, buffer);
|
||||
}
|
||||
|
||||
int hfp_hs_query_operator_name_cmd(uint16_t cid){
|
||||
int hfp_hf_cmd_query_operator_name(uint16_t cid){
|
||||
char buffer[20];
|
||||
sprintf(buffer, "AT%s?\r\n", HFP_QUERY_OPERATOR_SELECTION);
|
||||
return send_str_over_rfcomm(cid, buffer);
|
||||
}
|
||||
|
||||
int hfp_hs_enable_extended_audio_gateway_error_report_cmd(uint16_t cid, uint8_t enable){
|
||||
int hfp_hf_cmd_enable_extended_audio_gateway_error_report(uint16_t cid, uint8_t enable){
|
||||
char buffer[20];
|
||||
sprintf(buffer, "AT%s=%d\r\n", HFP_ENABLE_EXTENDED_AUDIO_GATEWAY_ERROR, enable);
|
||||
return send_str_over_rfcomm(cid, buffer);
|
||||
}
|
||||
|
||||
|
||||
int hfp_hf_cmd_trigger_codec_connection_setup(uint16_t cid){
|
||||
char buffer[20];
|
||||
sprintf(buffer, "AT%s\r\n", HFP_TRIGGER_CODEC_CONNECTION_SETUP);
|
||||
return send_str_over_rfcomm(cid, buffer);
|
||||
}
|
||||
|
||||
int hfp_hf_cmd_confirm_codec(uint16_t cid, uint8_t codec){
|
||||
char buffer[20];
|
||||
sprintf(buffer, "AT%s=%d\r\n", HFP_CONFIRM_COMMON_CODEC, codec);
|
||||
return send_str_over_rfcomm(cid, buffer);
|
||||
}
|
||||
|
||||
static void hfp_emit_ag_indicator_event(hfp_callback_t callback, int status, hfp_ag_indicator_t indicator){
|
||||
if (!callback) return;
|
||||
uint8_t event[6];
|
||||
@ -231,117 +249,67 @@ static void hfp_emit_network_operator_event(hfp_callback_t callback, int status,
|
||||
(*callback)(event, sizeof(event));
|
||||
}
|
||||
|
||||
static void hfp_run_for_context(hfp_connection_t * context){
|
||||
if (!context) return;
|
||||
// printf("hfp send cmd: context %p, RFCOMM cid %u \n", context, context->rfcomm_cid );
|
||||
if (!rfcomm_can_send_packet_now(context->rfcomm_cid)) return;
|
||||
|
||||
static void hfp_hf_run_for_context_handle_service_level_connection_establishment(hfp_connection_t * context){
|
||||
if (context->state >= HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED) return;
|
||||
|
||||
switch (context->state){
|
||||
case HFP_EXCHANGE_SUPPORTED_FEATURES:
|
||||
hfp_hs_exchange_supported_features_cmd(context->rfcomm_cid);
|
||||
hfp_hf_cmd_exchange_supported_features(context->rfcomm_cid);
|
||||
context->state = HFP_W4_EXCHANGE_SUPPORTED_FEATURES;
|
||||
break;
|
||||
case HFP_NOTIFY_ON_CODECS:
|
||||
hfp_hs_retrieve_codec_cmd(context->rfcomm_cid);
|
||||
hfp_hf_cmd_notify_on_codecs(context->rfcomm_cid);
|
||||
context->state = HFP_W4_NOTIFY_ON_CODECS;
|
||||
break;
|
||||
case HFP_RETRIEVE_INDICATORS:
|
||||
hfp_hs_retrieve_indicators_cmd(context->rfcomm_cid);
|
||||
hfp_hf_cmd_retrieve_indicators(context->rfcomm_cid);
|
||||
context->state = HFP_W4_RETRIEVE_INDICATORS;
|
||||
context->retrieve_ag_indicators = 1;
|
||||
context->retrieve_ag_indicators_status = 0;
|
||||
break;
|
||||
case HFP_RETRIEVE_INDICATORS_STATUS:
|
||||
hfp_hs_retrieve_indicators_status_cmd(context->rfcomm_cid);
|
||||
hfp_hf_cmd_retrieve_indicators_status(context->rfcomm_cid);
|
||||
context->state = HFP_W4_RETRIEVE_INDICATORS_STATUS;
|
||||
context->retrieve_ag_indicators_status = 1;
|
||||
context->retrieve_ag_indicators = 0;
|
||||
break;
|
||||
case HFP_ENABLE_INDICATORS_STATUS_UPDATE:
|
||||
hfp_hs_activate_status_update_for_all_ag_indicators_cmd(context->rfcomm_cid, 1);
|
||||
hfp_hf_cmd_activate_status_update_for_all_ag_indicators(context->rfcomm_cid, 1);
|
||||
context->state = HFP_W4_ENABLE_INDICATORS_STATUS_UPDATE;
|
||||
break;
|
||||
case HFP_RETRIEVE_CAN_HOLD_CALL:
|
||||
hfp_hs_retrieve_can_hold_call_cmd(context->rfcomm_cid);
|
||||
hfp_hf_cmd_retrieve_can_hold_call(context->rfcomm_cid);
|
||||
context->state = HFP_W4_RETRIEVE_CAN_HOLD_CALL;
|
||||
break;
|
||||
case HFP_LIST_GENERIC_STATUS_INDICATORS:
|
||||
hfp_hs_list_supported_generic_status_indicators_cmd(context->rfcomm_cid);
|
||||
hfp_hf_cmd_list_supported_generic_status_indicators(context->rfcomm_cid);
|
||||
context->state = HFP_W4_LIST_GENERIC_STATUS_INDICATORS;
|
||||
context->list_generic_status_indicators = 1;
|
||||
context->retrieve_generic_status_indicators = 0;
|
||||
context->retrieve_generic_status_indicators_state = 0;
|
||||
break;
|
||||
case HFP_RETRIEVE_GENERIC_STATUS_INDICATORS:
|
||||
hfp_hs_retrieve_supported_generic_status_indicators_cmd(context->rfcomm_cid);
|
||||
hfp_hf_cmd_retrieve_supported_generic_status_indicators(context->rfcomm_cid);
|
||||
context->state = HFP_W4_RETRIEVE_GENERIC_STATUS_INDICATORS;
|
||||
context->list_generic_status_indicators = 0;
|
||||
context->retrieve_generic_status_indicators = 1;
|
||||
context->retrieve_generic_status_indicators_state = 0;
|
||||
break;
|
||||
case HFP_RETRIEVE_INITITAL_STATE_GENERIC_STATUS_INDICATORS:
|
||||
hfp_hs_list_initital_supported_generic_status_indicators_cmd(context->rfcomm_cid);
|
||||
hfp_hf_cmd_list_initital_supported_generic_status_indicators(context->rfcomm_cid);
|
||||
context->state = HFP_W4_RETRIEVE_INITITAL_STATE_GENERIC_STATUS_INDICATORS;
|
||||
context->list_generic_status_indicators = 0;
|
||||
context->retrieve_generic_status_indicators = 0;
|
||||
context->retrieve_generic_status_indicators_state = 1;
|
||||
|
||||
break;
|
||||
case HFP_W2_DISCONNECT_RFCOMM:
|
||||
context->state = HFP_W4_RFCOMM_DISCONNECTED;
|
||||
rfcomm_disconnect_internal(context->rfcomm_cid);
|
||||
break;
|
||||
case HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED:{
|
||||
int i;
|
||||
for (i = 0; i < context->ag_indicators_nr; i++){
|
||||
if (context->ag_indicators[i].status_changed) {
|
||||
hfp_emit_ag_indicator_event(hfp_callback, 0, context->ag_indicators[i]);
|
||||
context->ag_indicators[i].status_changed = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (context->wait_ok) return;
|
||||
|
||||
if (context->enable_status_update_for_ag_indicators != 0xFF){
|
||||
hfp_hs_activate_status_update_for_all_ag_indicators_cmd(context->rfcomm_cid, context->enable_status_update_for_ag_indicators);
|
||||
context->wait_ok = 1;
|
||||
break;
|
||||
};
|
||||
if (context->change_status_update_for_individual_ag_indicators){
|
||||
hfp_hs_activate_status_update_for_ag_indicator_cmd(context->rfcomm_cid,
|
||||
context->ag_indicators_status_update_bitmap,
|
||||
context->ag_indicators_nr);
|
||||
context->wait_ok = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (context->operator_name_format){
|
||||
hfp_hs_query_operator_name_format_cmd(context->rfcomm_cid);
|
||||
context->wait_ok = 1;
|
||||
break;
|
||||
}
|
||||
if (context->operator_name){
|
||||
hfp_hs_query_operator_name_cmd(context->rfcomm_cid);
|
||||
context->wait_ok = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (context->enable_extended_audio_gateway_error_report){
|
||||
hfp_hs_enable_extended_audio_gateway_error_report_cmd(context->rfcomm_cid, context->enable_extended_audio_gateway_error_report);
|
||||
context->wait_ok = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void handle_switch_on_ok(hfp_connection_t *context){
|
||||
// printf("switch on ok\n");
|
||||
void hfp_hf_switch_on_ok_handle_service_level_connection_establishment(hfp_connection_t *context){
|
||||
if (context->state >= HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED) return;
|
||||
|
||||
switch (context->state){
|
||||
case HFP_W4_EXCHANGE_SUPPORTED_FEATURES:
|
||||
if (has_codec_negotiation_feature(context)){
|
||||
@ -402,39 +370,185 @@ void handle_switch_on_ok(hfp_connection_t *context){
|
||||
context->retrieve_generic_status_indicators_state = 0;
|
||||
hfp_emit_event(hfp_callback, HFP_SUBEVENT_SERVICE_LEVEL_CONNECTION_ESTABLISHED, 0);
|
||||
break;
|
||||
|
||||
case HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED:
|
||||
context->wait_ok = 0;
|
||||
|
||||
if (context->enable_status_update_for_ag_indicators != 0xFF){
|
||||
context->enable_status_update_for_ag_indicators = 0xFF;
|
||||
hfp_emit_event(hfp_callback, HFP_SUBEVENT_COMPLETE, 0);
|
||||
break;
|
||||
};
|
||||
|
||||
if (context->change_status_update_for_individual_ag_indicators == 1){
|
||||
context->change_status_update_for_individual_ag_indicators = 0;
|
||||
hfp_emit_event(hfp_callback, HFP_SUBEVENT_COMPLETE, 0);
|
||||
break;
|
||||
}
|
||||
|
||||
if (context->operator_name_format){
|
||||
context->operator_name_format = 0;
|
||||
context->operator_name = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (context->operator_name){
|
||||
context->operator_name = 0;
|
||||
hfp_emit_network_operator_event(hfp_callback, 0, context->network_operator);
|
||||
break;
|
||||
}
|
||||
if (context->enable_extended_audio_gateway_error_report){
|
||||
context->enable_extended_audio_gateway_error_report = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void hfp_hf_run_for_context_handle_service_level_connection_queries(hfp_connection_t * context){
|
||||
if (context->state != HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED) return;
|
||||
if (context->wait_ok) return;
|
||||
|
||||
if (context->enable_status_update_for_ag_indicators != 0xFF){
|
||||
hfp_hf_cmd_activate_status_update_for_all_ag_indicators(context->rfcomm_cid, context->enable_status_update_for_ag_indicators);
|
||||
context->wait_ok = 1;
|
||||
return;
|
||||
};
|
||||
if (context->change_status_update_for_individual_ag_indicators){
|
||||
hfp_hf_cmd_activate_status_update_for_ag_indicator(context->rfcomm_cid,
|
||||
context->ag_indicators_status_update_bitmap,
|
||||
context->ag_indicators_nr);
|
||||
context->wait_ok = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
if (context->operator_name_format){
|
||||
hfp_hf_cmd_query_operator_name_format(context->rfcomm_cid);
|
||||
context->wait_ok = 1;
|
||||
return;
|
||||
}
|
||||
if (context->operator_name){
|
||||
hfp_hf_cmd_query_operator_name(context->rfcomm_cid);
|
||||
context->wait_ok = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
if (context->enable_extended_audio_gateway_error_report){
|
||||
hfp_hf_cmd_enable_extended_audio_gateway_error_report(context->rfcomm_cid, context->enable_extended_audio_gateway_error_report);
|
||||
context->wait_ok = 1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void hfp_hf_switch_on_ok_handle_service_level_connection_queries(hfp_connection_t * context){
|
||||
if (context->state != HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED) return;
|
||||
|
||||
if (context->enable_status_update_for_ag_indicators != 0xFF){
|
||||
context->enable_status_update_for_ag_indicators = 0xFF;
|
||||
hfp_emit_event(hfp_callback, HFP_SUBEVENT_COMPLETE, 0);
|
||||
return;
|
||||
};
|
||||
|
||||
if (context->change_status_update_for_individual_ag_indicators == 1){
|
||||
context->change_status_update_for_individual_ag_indicators = 0;
|
||||
hfp_emit_event(hfp_callback, HFP_SUBEVENT_COMPLETE, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
if (context->operator_name_format){
|
||||
context->operator_name_format = 0;
|
||||
context->operator_name = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
if (context->operator_name){
|
||||
context->operator_name = 0;
|
||||
hfp_emit_network_operator_event(hfp_callback, 0, context->network_operator);
|
||||
return;
|
||||
}
|
||||
if (context->enable_extended_audio_gateway_error_report){
|
||||
context->enable_extended_audio_gateway_error_report = 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void hfp_run_for_context(hfp_connection_t * context){
|
||||
if (!context) return;
|
||||
|
||||
hfp_hf_run_for_context_handle_service_level_connection_establishment(context);
|
||||
hfp_hf_run_for_context_handle_service_level_connection_queries(context);
|
||||
|
||||
// if (context->state >= HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED && context->state <= HFP_AUDIO_CONNECTION_ESTABLISHED){
|
||||
|
||||
// handle audio connection setup
|
||||
switch (context->state){
|
||||
case HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED:
|
||||
if (context->wait_ok) return;
|
||||
|
||||
if (context->notify_ag_on_new_codecs){
|
||||
hfp_hf_cmd_notify_on_codecs(context->rfcomm_cid);
|
||||
context->wait_ok = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (context->trigger_codec_connection_setup){
|
||||
hfp_hf_cmd_trigger_codec_connection_setup(context->rfcomm_cid);
|
||||
context->wait_ok = 1;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case HFP_SLE_W2_EXCHANGE_COMMON_CODEC:
|
||||
if (!context->remote_codec_received) return;
|
||||
context->wait_ok = 1;
|
||||
|
||||
if (hfp_hf_supports_codec(context->remote_codec_received)){
|
||||
context->state = HFP_SLE_W4_EXCHANGE_COMMON_CODEC;
|
||||
hfp_hf_cmd_confirm_codec(context->rfcomm_cid, context->negotiated_codec);
|
||||
break;
|
||||
}
|
||||
|
||||
context->state = HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED;
|
||||
context->notify_ag_on_new_codecs = 1;
|
||||
context->remote_codec_received = 0;
|
||||
hfp_hf_cmd_notify_on_codecs(context->rfcomm_cid);
|
||||
break;
|
||||
|
||||
case HFP_CODECS_CONNECTION_ESTABLISHED:
|
||||
|
||||
if (context->notify_ag_on_new_codecs){
|
||||
hfp_hf_cmd_notify_on_codecs(context->rfcomm_cid);
|
||||
context->negotiated_codec = 0;
|
||||
context->wait_ok = 1;
|
||||
context->state = HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED;
|
||||
break;
|
||||
}
|
||||
|
||||
if (context->establish_audio_connection){
|
||||
// TODO AUDIO CONNECTION
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
// deal with disconnect
|
||||
switch (context->state){
|
||||
case HFP_W2_DISCONNECT_RFCOMM:
|
||||
context->state = HFP_W4_RFCOMM_DISCONNECTED;
|
||||
rfcomm_disconnect_internal(context->rfcomm_cid);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void hfp_hf_switch_on_ok(hfp_connection_t *context){
|
||||
// printf("switch on ok\n");
|
||||
context->wait_ok = 0;
|
||||
|
||||
hfp_hf_switch_on_ok_handle_service_level_connection_establishment(context);
|
||||
hfp_hf_switch_on_ok_handle_service_level_connection_queries(context);
|
||||
|
||||
// handle audio connection setup
|
||||
switch (context->state){
|
||||
case HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED:
|
||||
if (context->notify_ag_on_new_codecs){
|
||||
context->notify_ag_on_new_codecs = 0;
|
||||
if (context->trigger_codec_connection_setup){
|
||||
hfp_run_for_context(context);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (context->trigger_codec_connection_setup){
|
||||
context->trigger_codec_connection_setup = 0;
|
||||
context->state = HFP_SLE_W2_EXCHANGE_COMMON_CODEC;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case HFP_SLE_W4_EXCHANGE_COMMON_CODEC:
|
||||
context->negotiated_codec = context->remote_codec_received;
|
||||
context->remote_codec_received = 0;
|
||||
context->state = HFP_CODECS_CONNECTION_ESTABLISHED;
|
||||
break;
|
||||
|
||||
case HFP_AUDIO_CONNECTION_ESTABLISHED:
|
||||
printf("HFP_AUDIO_CONNECTION_ESTABLISHED \n");
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
|
||||
@ -443,18 +557,29 @@ void handle_switch_on_ok(hfp_connection_t *context){
|
||||
context->command = HFP_CMD_NONE;
|
||||
}
|
||||
|
||||
|
||||
static void hfp_handle_rfcomm_event(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
|
||||
hfp_connection_t * context = get_hfp_connection_context_for_rfcomm_cid(channel);
|
||||
if (!context) return;
|
||||
|
||||
packet[size] = 0;
|
||||
int pos;
|
||||
int pos, i;
|
||||
printf("parse command: %s\n", packet+2);
|
||||
for (pos = 0; pos < size ; pos++){
|
||||
hfp_parse(context, packet[pos]);
|
||||
|
||||
// emit indicators status changed
|
||||
for (i = 0; i < context->ag_indicators_nr; i++){
|
||||
if (context->ag_indicators[i].status_changed) {
|
||||
hfp_emit_ag_indicator_event(hfp_callback, 0, context->ag_indicators[i]);
|
||||
context->ag_indicators[i].status_changed = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (context->command == HFP_CMD_ERROR){
|
||||
context->wait_ok = 0;
|
||||
hfp_reset_context_flags(context);
|
||||
hfp_emit_event(hfp_callback, HFP_SUBEVENT_COMPLETE, 1);
|
||||
return;
|
||||
}
|
||||
@ -466,7 +591,7 @@ static void hfp_handle_rfcomm_event(uint8_t packet_type, uint16_t channel, uint8
|
||||
}
|
||||
|
||||
if (context->command != HFP_CMD_OK) continue;
|
||||
handle_switch_on_ok(context);
|
||||
hfp_hf_switch_on_ok(context);
|
||||
}
|
||||
}
|
||||
|
||||
@ -492,24 +617,36 @@ static void packet_handler(void * connection, uint8_t packet_type, uint16_t chan
|
||||
hfp_run();
|
||||
}
|
||||
|
||||
void hfp_hf_init(uint16_t rfcomm_channel_nr, uint32_t supported_features, uint8_t * codecs, int codecs_nr, uint16_t * indicators, int indicators_nr, uint32_t indicators_status){
|
||||
void hfp_hf_set_codecs(uint8_t * codecs, int codecs_nr){
|
||||
if (codecs_nr > HFP_MAX_NUM_CODECS){
|
||||
log_error("hfp_init: codecs_nr (%d) > HFP_MAX_NUM_CODECS (%d)", codecs_nr, HFP_MAX_NUM_CODECS);
|
||||
log_error("hfp_hf_set_codecs: codecs_nr (%d) > HFP_MAX_NUM_CODECS (%d)", codecs_nr, HFP_MAX_NUM_CODECS);
|
||||
return;
|
||||
}
|
||||
rfcomm_register_packet_handler(packet_handler);
|
||||
hfp_init(rfcomm_channel_nr);
|
||||
|
||||
hfp_supported_features = supported_features;
|
||||
|
||||
hfp_codecs_nr = codecs_nr;
|
||||
|
||||
int i;
|
||||
for (i=0; i<codecs_nr; i++){
|
||||
hfp_codecs[i] = codecs[i];
|
||||
}
|
||||
|
||||
linked_list_iterator_t it;
|
||||
linked_list_iterator_init(&it, hfp_get_connections());
|
||||
while (linked_list_iterator_has_next(&it)){
|
||||
hfp_connection_t * connection = (hfp_connection_t *)linked_list_iterator_next(&it);
|
||||
if (!connection) continue;
|
||||
connection->notify_ag_on_new_codecs = 1;
|
||||
}
|
||||
}
|
||||
|
||||
void hfp_hf_init(uint16_t rfcomm_channel_nr, uint32_t supported_features, uint16_t * indicators, int indicators_nr, uint32_t indicators_status){
|
||||
rfcomm_register_packet_handler(packet_handler);
|
||||
hfp_init(rfcomm_channel_nr);
|
||||
|
||||
hfp_supported_features = supported_features;
|
||||
|
||||
hfp_indicators_nr = indicators_nr;
|
||||
hfp_indicators_status = indicators_status;
|
||||
int i;
|
||||
for (i=0; i<indicators_nr; i++){
|
||||
hfp_indicators[i] = indicators[i];
|
||||
}
|
||||
@ -571,25 +708,40 @@ void hfp_hf_enable_report_extended_audio_gateway_error_result_code(bd_addr_t bd_
|
||||
hfp_run_for_context(connection);
|
||||
}
|
||||
|
||||
void hfp_hf_audio_connection_setup(bd_addr_t bd_addr){
|
||||
|
||||
void hfp_hf_establish_audio_connection(bd_addr_t bd_addr){
|
||||
hfp_hf_establish_service_level_connection(bd_addr);
|
||||
hfp_connection_t * connection = get_hfp_connection_context_for_bd_addr(bd_addr);
|
||||
if (!connection){
|
||||
log_error("HFP HF: connection doesn't exist.");
|
||||
return;
|
||||
}
|
||||
// TODO:
|
||||
hfp_run_for_context(connection);
|
||||
}
|
||||
|
||||
void hfp_hf_audio_connection_release(bd_addr_t bd_addr){
|
||||
hfp_hf_establish_service_level_connection(bd_addr);
|
||||
hfp_connection_t * connection = get_hfp_connection_context_for_bd_addr(bd_addr);
|
||||
if (!connection){
|
||||
log_error("HFP HF: connection doesn't exist.");
|
||||
if (connection->state == HFP_AUDIO_CONNECTION_ESTABLISHED) return;
|
||||
|
||||
connection->trigger_codec_connection_setup = 1;
|
||||
connection->establish_audio_connection = 1;
|
||||
|
||||
if (!has_codec_negotiation_feature(connection)){
|
||||
connection->trigger_codec_connection_setup = 0;
|
||||
connection->establish_audio_connection = 0;
|
||||
return;
|
||||
}
|
||||
// TODO:
|
||||
|
||||
if (connection->state == HFP_CODECS_CONNECTION_ESTABLISHED){
|
||||
connection->trigger_codec_connection_setup = 0;
|
||||
return;
|
||||
}
|
||||
hfp_run_for_context(connection);
|
||||
}
|
||||
|
||||
void hfp_hf_release_audio_connection(bd_addr_t bd_addr){
|
||||
hfp_connection_t * connection = get_hfp_connection_context_for_bd_addr(bd_addr);
|
||||
|
||||
if (!connection) return;
|
||||
if (connection->state >= HFP_W2_DISCONNECT_SCO) return;
|
||||
connection->release_audio_connection = 1;
|
||||
|
||||
hfp_run_for_context(connection);
|
||||
}
|
||||
|
||||
|
@ -65,7 +65,8 @@ void hfp_hf_create_sdp_record(uint8_t * service, int rfcomm_channel_nr, const ch
|
||||
* @brief Intialize HFP Hands-Free (HF) device.
|
||||
* TODO: move optional params into setters
|
||||
*/
|
||||
void hfp_hf_init(uint16_t rfcomm_channel_nr, uint32_t supported_features, uint8_t * codecs, int codecs_nr, uint16_t * indicators, int indicators_nr, uint32_t indicators_status);
|
||||
void hfp_hf_init(uint16_t rfcomm_channel_nr, uint32_t supported_features, uint16_t * indicators, int indicators_nr, uint32_t indicators_status);
|
||||
void hfp_hf_set_codecs(uint8_t * codecs, int codecs_nr);
|
||||
|
||||
/**
|
||||
* @brief Register callback for the HFP Hands-Free (HF) client.
|
||||
@ -140,12 +141,12 @@ void hfp_hf_enable_report_extended_audio_gateway_error_result_code(bd_addr_t bd_
|
||||
/**
|
||||
* @brief
|
||||
*/
|
||||
void hfp_hf_audio_connection_setup(bd_addr_t bd_addr);
|
||||
void hfp_hf_establish_audio_connection(bd_addr_t bd_addr);
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*/
|
||||
void hfp_hf_audio_connection_release(bd_addr_t bd_addr);
|
||||
void hfp_hf_release_audio_connection(bd_addr_t bd_addr);
|
||||
|
||||
|
||||
/* API_END */
|
||||
|
@ -149,11 +149,11 @@ static int stdin_process(struct data_source *ds){
|
||||
break;
|
||||
case 'b':
|
||||
printf("Establish Audio connection %s...\n", bd_addr_to_str(device_addr));
|
||||
hfp_ag_audio_connection_setup(device_addr);
|
||||
hfp_ag_establish_audio_connection(device_addr);
|
||||
break;
|
||||
case 'B':
|
||||
printf("Release Audio connection.\n");
|
||||
hfp_ag_audio_connection_release(device_addr);
|
||||
hfp_ag_release_audio_connection(device_addr);
|
||||
break;
|
||||
case 'd':
|
||||
printf("Report AG failure\n");
|
||||
|
@ -148,11 +148,11 @@ static int stdin_process(struct data_source *ds){
|
||||
break;
|
||||
case 'b':
|
||||
printf("Establish Audio connection %s...\n", bd_addr_to_str(device_addr));
|
||||
hfp_hf_audio_connection_setup(device_addr);
|
||||
hfp_hf_establish_audio_connection(device_addr);
|
||||
break;
|
||||
case 'B':
|
||||
printf("Release Audio connection.\n");
|
||||
hfp_hf_audio_connection_release(device_addr);
|
||||
hfp_hf_release_audio_connection(device_addr);
|
||||
break;
|
||||
|
||||
case 'd':
|
||||
@ -238,8 +238,9 @@ int btstack_main(int argc, const char * argv[]){
|
||||
rfcomm_init();
|
||||
|
||||
// hfp_hf_init(rfcomm_channel_nr, HFP_DEFAULT_HF_SUPPORTED_FEATURES, codecs, sizeof(codecs), indicators, sizeof(indicators)/sizeof(uint16_t), 1);
|
||||
hfp_hf_init(rfcomm_channel_nr, 438, codecs, sizeof(codecs), indicators, sizeof(indicators)/sizeof(uint16_t), 1);
|
||||
|
||||
hfp_hf_init(rfcomm_channel_nr, 438, indicators, sizeof(indicators)/sizeof(uint16_t), 1);
|
||||
hfp_hf_set_codecs(codecs, sizeof(codecs));
|
||||
|
||||
hfp_hf_register_packet_handler(packet_handler);
|
||||
|
||||
sdp_init();
|
||||
|
Loading…
x
Reference in New Issue
Block a user