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 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_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); connection->establish_audio_connection = 0; if (connection->state == HFP_AUDIO_CONNECTION_ESTABLISHED) return; if (connection->state >= HFP_W2_DISCONNECT_SCO) return; connection->establish_audio_connection = 1; if (!has_codec_negotiation_feature(connection)){ log_info("hfp_ag_establish_audio_connection - no codec negotiation feature, using defaults"); connection->codecs_state = HFP_CODECS_EXCHANGED; } switch (connection->codecs_state){ case HFP_CODECS_IDLE: case HFP_CODECS_RECEIVED_LIST: case HFP_CODECS_AG_RESEND_COMMON_CODEC: case HFP_CODECS_ERROR: connection->command = HFP_CMD_AG_SEND_COMMON_CODEC; break; default: break; } hfp_run_for_context(connection); }
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 (!has_codec_negotiation_feature(connection)) return; connection->establish_audio_connection = 0; if (connection->state == HFP_AUDIO_CONNECTION_ESTABLISHED) return; if (connection->state >= HFP_W2_DISCONNECT_SCO) return; connection->establish_audio_connection = 1; if (connection->state < HFP_SLE_W4_EXCHANGE_COMMON_CODEC){ connection->ag_trigger_codec_connection_setup = 1; } hfp_run_for_context(connection); }
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); }
static void hfp_ag_run_for_context_service_level_connection(hfp_connection_t * context){ if (context->state >= HFP_CODECS_CONNECTION_ESTABLISHED) return; printf(" AG run for context_service_level_connection \n"); switch(context->command){ case HFP_CMD_SUPPORTED_FEATURES: switch(context->state){ case HFP_W4_EXCHANGE_SUPPORTED_FEATURES: hfp_ag_exchange_supported_features_cmd(context->rfcomm_cid); if (has_codec_negotiation_feature(context)){ context->state = HFP_W4_NOTIFY_ON_CODECS; break; } context->state = HFP_W4_RETRIEVE_INDICATORS; break; default: break; } break; case HFP_CMD_AVAILABLE_CODECS: switch(context->state){ case HFP_W4_NOTIFY_ON_CODECS: hfp_ag_retrieve_codec_cmd(context->rfcomm_cid); context->state = HFP_W4_RETRIEVE_INDICATORS; break; case HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED: context->suggested_codec = hfp_ag_suggest_codec(context); printf("received BAC == new HF codecs, suggested codec %d\n", context->suggested_codec); hfp_ag_ok(context->rfcomm_cid); break; default: break; } break; case HFP_CMD_INDICATOR: switch(context->state){ case HFP_W4_RETRIEVE_INDICATORS: if (context->retrieve_ag_indicators == 0) break; hfp_ag_retrieve_indicators_cmd(context->rfcomm_cid, context); context->state = HFP_W4_RETRIEVE_INDICATORS_STATUS; break; case HFP_W4_RETRIEVE_INDICATORS_STATUS: if (context->retrieve_ag_indicators_status == 0) break; hfp_ag_retrieve_indicators_status_cmd(context->rfcomm_cid); context->state = HFP_W4_ENABLE_INDICATORS_STATUS_UPDATE; break; default: break; } break; case HFP_CMD_ENABLE_INDICATOR_STATUS_UPDATE: switch(context->state){ case HFP_W4_ENABLE_INDICATORS_STATUS_UPDATE: hfp_ag_toggle_indicator_status_update_cmd(context->rfcomm_cid, 1); if (has_call_waiting_and_3way_calling_feature(context)){ context->state = HFP_W4_RETRIEVE_CAN_HOLD_CALL; break; } if (has_hf_indicators_feature(context)){ context->state = HFP_W4_LIST_GENERIC_STATUS_INDICATORS; break; } context->state = HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED; hfp_emit_event(hfp_callback, HFP_SUBEVENT_SERVICE_LEVEL_CONNECTION_ESTABLISHED, 0); break; default: break; } break; case HFP_CMD_SUPPORT_CALL_HOLD_AND_MULTIPARTY_SERVICES: switch(context->state){ case HFP_W4_RETRIEVE_CAN_HOLD_CALL: hfp_ag_retrieve_can_hold_call_cmd(context->rfcomm_cid); if (has_hf_indicators_feature(context)){ context->state = HFP_W4_LIST_GENERIC_STATUS_INDICATORS; break; } context->state = HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED; hfp_emit_event(hfp_callback, HFP_SUBEVENT_SERVICE_LEVEL_CONNECTION_ESTABLISHED, 0); break; default: break; } break; case HFP_CMD_GENERIC_STATUS_INDICATOR: switch(context->state){ case HFP_W4_LIST_GENERIC_STATUS_INDICATORS: if (context->list_generic_status_indicators == 0) break; hfp_ag_list_supported_generic_status_indicators_cmd(context->rfcomm_cid); context->state = HFP_W4_RETRIEVE_GENERIC_STATUS_INDICATORS; context->list_generic_status_indicators = 0; break; case HFP_W4_RETRIEVE_GENERIC_STATUS_INDICATORS: if (context->retrieve_generic_status_indicators == 0) break; hfp_ag_retrieve_supported_generic_status_indicators_cmd(context->rfcomm_cid); context->state = HFP_W4_RETRIEVE_INITITAL_STATE_GENERIC_STATUS_INDICATORS; context->retrieve_generic_status_indicators = 0; break; case HFP_W4_RETRIEVE_INITITAL_STATE_GENERIC_STATUS_INDICATORS: if (context->retrieve_generic_status_indicators_state == 0) break; hfp_ag_retrieve_initital_supported_generic_status_indicators_cmd(context->rfcomm_cid); context->state = HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED; context->retrieve_generic_status_indicators_state = 0; hfp_emit_event(hfp_callback, HFP_SUBEVENT_SERVICE_LEVEL_CONNECTION_ESTABLISHED, 0); break; default: break; } break; default: break; } }
void handle_switch_on_ok(hfp_connection_t *context){ printf("handle switch on OK\n"); switch (context->state){ case HFP_W4_RETRIEVE_GENERIC_STATUS_INDICATORS: context->remote_hf_indicators_status = 0; context->state = HFP_RETRIEVE_INITITAL_STATE_GENERIC_STATUS_INDICATORS; break; case HFP_W4_NOTIFY_ON_CODECS: printf("switch on OK: HFP_RETRIEVE_INDICATORS\n"); context->state = HFP_RETRIEVE_INDICATORS; break; case HFP_W4_LIST_GENERIC_STATUS_INDICATORS: printf("switch on OK: HFP_W4_LIST_GENERIC_STATUS_INDICATORS\n"); context->state = HFP_RETRIEVE_GENERIC_STATUS_INDICATORS; break; case HFP_W4_EXCHANGE_SUPPORTED_FEATURES: if (has_codec_negotiation_feature(context)){ context->state = HFP_NOTIFY_ON_CODECS; break; } context->state = HFP_RETRIEVE_INDICATORS; break; case HFP_W4_RETRIEVE_INDICATORS: context->remote_indicators_status = 0; context->state = HFP_RETRIEVE_INDICATORS_STATUS; break; case HFP_W4_RETRIEVE_INDICATORS_STATUS: if (context->remote_indicators_update_enabled == 0){ context->state = HFP_ENABLE_INDICATORS_STATUS_UPDATE; break; } if (has_call_waiting_and_3way_calling_feature(context)){ context->state = HFP_RETRIEVE_CAN_HOLD_CALL; break; } if (has_hf_indicators_feature(context)){ context->state = HFP_LIST_GENERIC_STATUS_INDICATORS; break; } context->state = HFP_ACTIVE; break; case HFP_W4_ENABLE_INDICATORS_STATUS_UPDATE: if (has_call_waiting_and_3way_calling_feature(context)){ context->state = HFP_RETRIEVE_CAN_HOLD_CALL; break; } if (has_hf_indicators_feature(context)){ context->state = HFP_LIST_GENERIC_STATUS_INDICATORS; break; } context->state = HFP_ACTIVE; break; case HFP_W4_RETRIEVE_CAN_HOLD_CALL: if (has_hf_indicators_feature(context)){ context->state = HFP_LIST_GENERIC_STATUS_INDICATORS; break; } context->state = HFP_ACTIVE; break; case HFP_W4_RETRIEVE_INITITAL_STATE_GENERIC_STATUS_INDICATORS: printf("Supported initial state generic status indicators \n"); break; default: break; } // done context->command = HFP_CMD_NONE; }
void hfp_run_for_context(hfp_connection_t *context) { // printf(" hfp_run_for_context \n"); if (!context) return; if (!rfcomm_can_send_packet_now(context->rfcomm_cid)) return; //printf(" hfp_run_for_context 1 state %d, command %d\n", context->state, context->command); if (context->state == HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED) { if (context->send_ok) { hfp_ag_ok(context->rfcomm_cid); context->send_ok = 0; return; } if (context->send_error) { hfp_ag_error(context->rfcomm_cid); context->send_error = 0; return; } if (context->enable_status_update_for_ag_indicators) { 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]); context->ag_indicators[i].status_changed = 0; return; } } if (context->enable_extended_audio_gateway_error_report) { if (context->extended_audio_gateway_error) { hfp_ag_report_extended_audio_gateway_error(context->rfcomm_cid, context->extended_audio_gateway_error); context->extended_audio_gateway_error = 0; return; } } } 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: hfp_ag_exchange_supported_features_cmd(context->rfcomm_cid); if (has_codec_negotiation_feature(context)) { context->state = HFP_W4_NOTIFY_ON_CODECS; break; } context->state = HFP_W4_RETRIEVE_INDICATORS; break; default: break; } break; case HFP_CMD_AVAILABLE_CODECS: switch(context->state) { case HFP_W4_NOTIFY_ON_CODECS: hfp_ag_retrieve_codec_cmd(context->rfcomm_cid); context->state = HFP_W4_RETRIEVE_INDICATORS; break; default: break; } break; case HFP_CMD_INDICATOR: switch(context->state) { case HFP_W4_RETRIEVE_INDICATORS: if (context->retrieve_ag_indicators == 0) break; hfp_ag_retrieve_indicators_cmd(context->rfcomm_cid, context); context->state = HFP_W4_RETRIEVE_INDICATORS_STATUS; break; case HFP_W4_RETRIEVE_INDICATORS_STATUS: if (context->retrieve_ag_indicators_status == 0) break; hfp_ag_retrieve_indicators_status_cmd(context->rfcomm_cid); context->state = HFP_W4_ENABLE_INDICATORS_STATUS_UPDATE; break; default: break; } break; case HFP_CMD_ENABLE_INDICATOR_STATUS_UPDATE: switch(context->state) { case HFP_W4_ENABLE_INDICATORS_STATUS_UPDATE: hfp_ag_toggle_indicator_status_update_cmd(context->rfcomm_cid, 1); if (has_call_waiting_and_3way_calling_feature(context)) { context->state = HFP_W4_RETRIEVE_CAN_HOLD_CALL; break; } if (has_hf_indicators_feature(context)) { context->state = HFP_W4_LIST_GENERIC_STATUS_INDICATORS; break; } context->state = HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED; hfp_emit_event(hfp_callback, HFP_SUBEVENT_SERVICE_LEVEL_CONNECTION_ESTABLISHED, 0); break; case HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED: // TODO break; default: break; } break; case HFP_CMD_SUPPORT_CALL_HOLD_AND_MULTIPARTY_SERVICES: switch(context->state) { case HFP_W4_RETRIEVE_CAN_HOLD_CALL: hfp_ag_retrieve_can_hold_call_cmd(context->rfcomm_cid); if (has_hf_indicators_feature(context)) { context->state = HFP_W4_LIST_GENERIC_STATUS_INDICATORS; break; } context->state = HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED; hfp_emit_event(hfp_callback, HFP_SUBEVENT_SERVICE_LEVEL_CONNECTION_ESTABLISHED, 0); break; default: break; } break; case HFP_CMD_GENERIC_STATUS_INDICATOR: switch(context->state) { case HFP_W4_LIST_GENERIC_STATUS_INDICATORS: if (context->list_generic_status_indicators == 0) break; hfp_ag_list_supported_generic_status_indicators_cmd(context->rfcomm_cid); context->state = HFP_W4_RETRIEVE_GENERIC_STATUS_INDICATORS; context->list_generic_status_indicators = 0; break; case HFP_W4_RETRIEVE_GENERIC_STATUS_INDICATORS: if (context->retrieve_generic_status_indicators == 0) break; hfp_ag_retrieve_supported_generic_status_indicators_cmd(context->rfcomm_cid); context->state = HFP_W4_RETRIEVE_INITITAL_STATE_GENERIC_STATUS_INDICATORS; context->retrieve_generic_status_indicators = 0; break; case HFP_W4_RETRIEVE_INITITAL_STATE_GENERIC_STATUS_INDICATORS: if (context->retrieve_generic_status_indicators_state == 0) break; hfp_ag_retrieve_initital_supported_generic_status_indicators_cmd(context->rfcomm_cid); context->state = HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED; context->retrieve_generic_status_indicators_state = 0; hfp_emit_event(hfp_callback, HFP_SUBEVENT_SERVICE_LEVEL_CONNECTION_ESTABLISHED, 0); break; default: break; } break; case HFP_CMD_QUERY_OPERATOR_SELECTION: if (context->state != HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED) break; if (context->operator_name_format == 1) { if (context->network_operator.format != 0) { hfp_ag_error(context->rfcomm_cid); break; } hfp_ag_ok(context->rfcomm_cid); context->operator_name_format = 0; break; } if (context->operator_name == 1) { hfp_ag_report_network_operator_name_cmd(context->rfcomm_cid, context->network_operator); context->operator_name = 0; break; } break; case HFP_CMD_NONE: switch(context->state) { case HFP_W2_DISCONNECT_RFCOMM: // printf("rfcomm_disconnect_internal cid 0x%02x\n", context->rfcomm_cid); context->state = HFP_W4_RFCOMM_DISCONNECTED; rfcomm_disconnect_internal(context->rfcomm_cid); break; default: break; } break; default: break; } // done context->command = HFP_CMD_NONE; }
static int hfp_ag_run_for_context_service_level_connection(hfp_connection_t * context){ if (context->state >= HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED) return 0; int done = 0; // printf(" -> State machine: SLC\n"); switch(context->command){ case HFP_CMD_SUPPORTED_FEATURES: switch(context->state){ case HFP_W4_EXCHANGE_SUPPORTED_FEATURES: case HFP_EXCHANGE_SUPPORTED_FEATURES: if (has_codec_negotiation_feature(context)){ context->state = HFP_W4_NOTIFY_ON_CODECS; } else { context->state = HFP_W4_RETRIEVE_INDICATORS; } hfp_ag_exchange_supported_features_cmd(context->rfcomm_cid); return 1; default: break; } break; case HFP_CMD_AVAILABLE_CODECS: done = codecs_exchange_state_machine(context); if (context->codecs_state == HFP_CODECS_RECEIVED_LIST){ context->state = HFP_W4_RETRIEVE_INDICATORS; } return done; case HFP_CMD_RETRIEVE_AG_INDICATORS: if (context->state != HFP_W4_RETRIEVE_INDICATORS) break; context->state = HFP_W4_RETRIEVE_INDICATORS_STATUS; hfp_ag_retrieve_indicators_cmd(context->rfcomm_cid, context); return 1; case HFP_CMD_RETRIEVE_AG_INDICATORS_STATUS: if (context->state != HFP_W4_RETRIEVE_INDICATORS_STATUS) break; context->state = HFP_W4_ENABLE_INDICATORS_STATUS_UPDATE; hfp_ag_retrieve_indicators_status_cmd(context->rfcomm_cid); return 1; case HFP_CMD_ENABLE_INDICATOR_STATUS_UPDATE: if (context->state != HFP_W4_ENABLE_INDICATORS_STATUS_UPDATE) break; if (has_call_waiting_and_3way_calling_feature(context)){ context->state = HFP_W4_RETRIEVE_CAN_HOLD_CALL; } else if (has_hf_indicators_feature(context)){ context->state = HFP_W4_LIST_GENERIC_STATUS_INDICATORS; } else { context->state = HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED; hfp_emit_event(hfp_callback, HFP_SUBEVENT_SERVICE_LEVEL_CONNECTION_ESTABLISHED, 0); } hfp_ag_set_indicator_status_update_cmd(context->rfcomm_cid, 1); return 1; case HFP_CMD_SUPPORT_CALL_HOLD_AND_MULTIPARTY_SERVICES: if (context->state != HFP_W4_RETRIEVE_CAN_HOLD_CALL) break; if (has_hf_indicators_feature(context)){ context->state = HFP_W4_LIST_GENERIC_STATUS_INDICATORS; } else { context->state = HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED; hfp_emit_event(hfp_callback, HFP_SUBEVENT_SERVICE_LEVEL_CONNECTION_ESTABLISHED, 0); } hfp_ag_retrieve_can_hold_call_cmd(context->rfcomm_cid); return 1; case HFP_CMD_LIST_GENERIC_STATUS_INDICATORS: if (context->state != HFP_W4_LIST_GENERIC_STATUS_INDICATORS) break; context->state = HFP_W4_RETRIEVE_GENERIC_STATUS_INDICATORS; hfp_ag_list_supported_generic_status_indicators_cmd(context->rfcomm_cid); return 1; case HFP_CMD_RETRIEVE_GENERIC_STATUS_INDICATORS: if (context->state != HFP_W4_RETRIEVE_GENERIC_STATUS_INDICATORS) break; context->state = HFP_W4_RETRIEVE_INITITAL_STATE_GENERIC_STATUS_INDICATORS; hfp_ag_retrieve_supported_generic_status_indicators_cmd(context->rfcomm_cid); return 1; case HFP_CMD_RETRIEVE_GENERIC_STATUS_INDICATORS_STATE: if (context->state != HFP_W4_RETRIEVE_INITITAL_STATE_GENERIC_STATUS_INDICATORS) break; context->state = HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED; hfp_emit_event(hfp_callback, HFP_SUBEVENT_SERVICE_LEVEL_CONNECTION_ESTABLISHED, 0); hfp_ag_retrieve_initital_supported_generic_status_indicators_cmd(context->rfcomm_cid); return 1; default: break; } return done; }