diff --git a/src/hfp.h b/src/hfp.h index 17c3d767e..e375d691a 100644 --- a/src/hfp.h +++ b/src/hfp.h @@ -330,6 +330,7 @@ typedef enum { HFP_CODECS_W4_AG_COMMON_CODEC, HFP_CODECS_AG_SENT_COMMON_CODEC, HFP_CODECS_AG_RESEND_COMMON_CODEC, + HFP_CODECS_HF_CONFIRMED_CODEC, HFP_CODECS_EXCHANGED, HFP_CODECS_ERROR } hfp_codecs_state_t; diff --git a/src/hfp_hf.c b/src/hfp_hf.c index b4a59a60e..74f1700ab 100644 --- a/src/hfp_hf.c +++ b/src/hfp_hf.c @@ -300,67 +300,6 @@ static int hfp_hf_run_for_context_service_level_connection(hfp_connection_t * co return done; } -static void hfp_hf_handle_ok_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)){ - context->state = HFP_NOTIFY_ON_CODECS; - break; - } - context->state = HFP_RETRIEVE_INDICATORS; - break; - - case HFP_W4_NOTIFY_ON_CODECS: - context->state = HFP_RETRIEVE_INDICATORS; - break; - - case HFP_W4_RETRIEVE_INDICATORS: - context->state = HFP_RETRIEVE_INDICATORS_STATUS; - break; - - case HFP_W4_RETRIEVE_INDICATORS_STATUS: - context->state = HFP_ENABLE_INDICATORS_STATUS_UPDATE; - 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_SERVICE_LEVEL_CONNECTION_ESTABLISHED; - hfp_emit_event(hfp_callback, HFP_SUBEVENT_SERVICE_LEVEL_CONNECTION_ESTABLISHED, 0); - 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_SERVICE_LEVEL_CONNECTION_ESTABLISHED; - hfp_emit_event(hfp_callback, HFP_SUBEVENT_SERVICE_LEVEL_CONNECTION_ESTABLISHED, 0); - break; - - case HFP_W4_LIST_GENERIC_STATUS_INDICATORS: - context->state = HFP_RETRIEVE_GENERIC_STATUS_INDICATORS; - break; - - case HFP_W4_RETRIEVE_GENERIC_STATUS_INDICATORS: - context->state = HFP_RETRIEVE_INITITAL_STATE_GENERIC_STATUS_INDICATORS; - break; - - case HFP_W4_RETRIEVE_INITITAL_STATE_GENERIC_STATUS_INDICATORS: - context->state = HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED; - hfp_emit_event(hfp_callback, HFP_SUBEVENT_SERVICE_LEVEL_CONNECTION_ESTABLISHED, 0); - break; - default: - break; - } -} static int hfp_hf_run_for_context_service_level_connection_queries(hfp_connection_t * context){ if (context->state != HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED) return 0; @@ -405,92 +344,58 @@ static int hfp_hf_run_for_context_service_level_connection_queries(hfp_connectio return done; } -static void hfp_hf_handle_ok_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->command == HFP_CMD_QUERY_OPERATOR_SELECTION_NAME_FORMAT){ - context->command = HFP_CMD_QUERY_OPERATOR_SELECTION_NAME; - return; - } - - if (context->command == HFP_CMD_QUERY_OPERATOR_SELECTION_NAME){ - 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 int codecs_exchange_state_machine(hfp_connection_t * context){ + /* events ( == commands): + HFP_CMD_AVAILABLE_CODECS == received AT+BAC with list of codecs + HFP_CMD_TRIGGER_CODEC_CONNECTION_SETUP: + hf_trigger_codec_connection_setup == received BCC + ag_trigger_codec_connection_setup == received from AG to send BCS + HFP_CMD_HF_CONFIRMED_CODEC == received AT+BCS + */ + if (context->ok_pending) return 0; int done = 1; + printf(" -> State machine: CC\n"); - switch(context->command){ + switch (context->command){ case HFP_CMD_AVAILABLE_CODECS: - switch (context->codecs_state){ - case HFP_CODECS_W4_AG_COMMON_CODEC: - context->codec_confirmed = 0; - context->suggested_codec = 0; - context->negotiated_codec = 0; - break; - case HFP_CODECS_EXCHANGED: - context->negotiated_codec = 0; - context->codecs_state = HFP_CODECS_W4_AG_COMMON_CODEC; - break; - default: - break; - } + if (context->codecs_state == HFP_CODECS_W4_AG_COMMON_CODEC) return 0; + + context->codecs_state = HFP_CODECS_W4_AG_COMMON_CODEC; + context->ok_pending = 1; hfp_hf_cmd_notify_on_codecs(context->rfcomm_cid); - break; + return 1; case HFP_CMD_TRIGGER_CODEC_CONNECTION_SETUP: + context->codec_confirmed = 0; + context->suggested_codec = 0; + context->negotiated_codec = 0; + context->codecs_state = HFP_CODECS_RECEIVED_TRIGGER_CODEC_EXCHANGE; + context->ok_pending = 1; hfp_hf_cmd_trigger_codec_connection_setup(context->rfcomm_cid); break; - case HFP_CMD_AG_SUGGESTED_CODEC: + case HFP_CMD_AG_SUGGESTED_CODEC: if (hfp_hf_supports_codec(context->suggested_codec)){ context->codec_confirmed = context->suggested_codec; + context->ok_pending = 1; + context->codecs_state = HFP_CODECS_HF_CONFIRMED_CODEC; hfp_hf_cmd_confirm_codec(context->rfcomm_cid, context->suggested_codec); } else { context->codec_confirmed = 0; context->suggested_codec = 0; context->negotiated_codec = 0; + context->codecs_state = HFP_CODECS_W4_AG_COMMON_CODEC; + context->ok_pending = 1; hfp_hf_cmd_notify_on_codecs(context->rfcomm_cid); + } break; - default: - return 0; - } - - if (done){ - context->ok_pending = 1; - } - return done; -} - -static void hfp_hf_handle_ok_codecs_connection(hfp_connection_t * context){ - // handle audio connection setup - switch (context->codecs_state){ - case HFP_CODECS_RECEIVED_TRIGGER_CODEC_EXCHANGE: - context->codecs_state = HFP_CODECS_W4_AG_COMMON_CODEC; - break; + default: break; } + return 0; } static void hfp_run_for_context(hfp_connection_t * context){ @@ -519,12 +424,109 @@ static void hfp_run_for_context(hfp_connection_t * context){ } static void hfp_hf_switch_on_ok(hfp_connection_t *context){ - // printf("switch on ok\n"); context->ok_pending = 0; - - hfp_hf_handle_ok_service_level_connection_establishment(context); - hfp_hf_handle_ok_service_level_connection_queries(context); - hfp_hf_handle_ok_codecs_connection(context); + int done = 1; + switch (context->state){ + 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_NOTIFY_ON_CODECS: + context->state = HFP_RETRIEVE_INDICATORS; + break; + + case HFP_W4_RETRIEVE_INDICATORS: + context->state = HFP_RETRIEVE_INDICATORS_STATUS; + break; + + case HFP_W4_RETRIEVE_INDICATORS_STATUS: + context->state = HFP_ENABLE_INDICATORS_STATUS_UPDATE; + 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_SERVICE_LEVEL_CONNECTION_ESTABLISHED; + hfp_emit_event(hfp_callback, HFP_SUBEVENT_SERVICE_LEVEL_CONNECTION_ESTABLISHED, 0); + 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_SERVICE_LEVEL_CONNECTION_ESTABLISHED; + hfp_emit_event(hfp_callback, HFP_SUBEVENT_SERVICE_LEVEL_CONNECTION_ESTABLISHED, 0); + break; + + case HFP_W4_LIST_GENERIC_STATUS_INDICATORS: + context->state = HFP_RETRIEVE_GENERIC_STATUS_INDICATORS; + break; + + case HFP_W4_RETRIEVE_GENERIC_STATUS_INDICATORS: + context->state = HFP_RETRIEVE_INITITAL_STATE_GENERIC_STATUS_INDICATORS; + break; + + case HFP_W4_RETRIEVE_INITITAL_STATE_GENERIC_STATUS_INDICATORS: + 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: + 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->command == HFP_CMD_QUERY_OPERATOR_SELECTION_NAME_FORMAT){ + context->command = HFP_CMD_QUERY_OPERATOR_SELECTION_NAME; + break; + } + + if (context->command == HFP_CMD_QUERY_OPERATOR_SELECTION_NAME){ + 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; + } + printf(" CC received ok\n"); + + switch (context->codecs_state){ + case HFP_CODECS_RECEIVED_TRIGGER_CODEC_EXCHANGE: + context->codecs_state = HFP_CODECS_W4_AG_COMMON_CODEC; + break; + case HFP_CODECS_HF_CONFIRMED_CODEC: + context->codecs_state = HFP_CODECS_EXCHANGED; + hfp_emit_event(hfp_callback, HFP_SUBEVENT_CODECS_CONNECTION_COMPLETE, 0); + break; + default: + done = 0; + break; + } + break; + default: + done = 0; + break; + } + // done context->command = HFP_CMD_NONE; } diff --git a/test/hfp/hfp_hf_client_test.c b/test/hfp/hfp_hf_client_test.c index 6f27a83e5..50f92590b 100644 --- a/test/hfp/hfp_hf_client_test.c +++ b/test/hfp/hfp_hf_client_test.c @@ -71,10 +71,18 @@ const uint8_t rfcomm_channel_nr = 1; static bd_addr_t device_addr = {0xD8,0xBb,0x2C,0xDf,0xF1,0x08}; static uint8_t codecs[2] = {1,2}; +static uint8_t default_codecs[2] = {1}; static uint16_t indicators[1] = {0x01}; static uint8_t service_level_connection_established = 0; static uint8_t codecs_connection_established = 0; +static uint8_t audio_connection_established = 0; +static uint8_t start_ringing = 0; +static uint8_t stop_ringing = 0; +static uint8_t call_termiated = 0; + +static int supported_features_with_codec_negotiation = 438; // 0001 1011 0110 +static int supported_features_without_codec_negotiation = 310; // 0001 0011 0110 int expected_rfcomm_command(const char * cmd){ char * ag_cmd = (char *)get_rfcomm_payload(); @@ -143,28 +151,37 @@ void packet_handler(uint8_t * event, uint16_t event_size){ case HFP_SUBEVENT_SERVICE_LEVEL_CONNECTION_ESTABLISHED: printf("\n** SLC established **\n\n"); service_level_connection_established = 1; + codecs_connection_established = 0; + audio_connection_established = 0; break; case HFP_SUBEVENT_CODECS_CONNECTION_COMPLETE: printf("\n** CC established **\n\n"); codecs_connection_established = 1; + audio_connection_established = 0; break; - case HFP_SUBEVENT_SERVICE_LEVEL_CONNECTION_RELEASED: + printf("\n** SLC released **\n\n"); service_level_connection_established = 0; break; - - case HFP_SUBEVENT_COMPLETE: - printf("HFP_SUBEVENT_COMPLETE.\n\n"); + case HFP_SUBEVENT_AUDIO_CONNECTION_ESTABLISHED: + printf("\n** AC established **\n\n"); + audio_connection_established = 1; break; - case HFP_SUBEVENT_AG_INDICATOR_STATUS_CHANGED: - printf("AG_INDICATOR_STATUS_CHANGED, AG indicator index: %d, status: %d\n", event[4], event[5]); + case HFP_SUBEVENT_AUDIO_CONNECTION_RELEASED: + printf("\n** AC released **\n\n"); + audio_connection_established = 0; break; - case HFP_SUBEVENT_NETWORK_OPERATOR_CHANGED: - printf("NETWORK_OPERATOR_CHANGED, operator mode: %d, format: %d, name: %s\n", event[4], event[5], (char *) &event[6]); + case HFP_SUBEVENT_START_RINGINIG: + printf("\n** Start ringing **\n\n"); + start_ringing = 1; break; - case HFP_SUBEVENT_EXTENDED_AUDIO_GATEWAY_ERROR: - if (event[4]) - printf("EXTENDED_AUDIO_GATEWAY_ERROR_REPORT, status : %d\n", event[3]); + case HFP_SUBEVENT_STOP_RINGINIG: + printf("\n** Stop ringing **\n\n"); + stop_ringing = 1; + start_ringing = 0; + break; + case HFP_SUBEVENT_CALL_TERMINATED: + call_termiated = 1; break; default: printf("event not handled %u\n", event[2]); @@ -179,14 +196,22 @@ TEST_GROUP(HFPClient){ void setup(void){ service_level_connection_established = 0; codecs_connection_established = 0; + audio_connection_established = 0; + start_ringing = 0; + stop_ringing = 0; + call_termiated = 0; + + hfp_hf_init(rfcomm_channel_nr, supported_features_with_codec_negotiation, indicators, sizeof(indicators)/sizeof(uint16_t), 1); + hfp_hf_set_codecs(codecs, sizeof(codecs)); } void teardown(void){ - if (service_level_connection_established){ - hfp_hf_release_service_level_connection(device_addr); - CHECK_EQUAL(service_level_connection_established, 0); - } + hfp_hf_release_audio_connection(device_addr); + hfp_hf_release_service_level_connection(device_addr); + + service_level_connection_established = 0; codecs_connection_established = 0; + audio_connection_established = 0; } void setup_hfp_service_level_connection(char ** test_steps, int nr_test_steps){ @@ -202,6 +227,22 @@ TEST_GROUP(HFPClient){ }; +TEST(HFPClient, HFAudioConnectionEstablishedWithoutCodecNegotiation){ + hfp_hf_init(rfcomm_channel_nr, supported_features_without_codec_negotiation, indicators, sizeof(indicators)/sizeof(uint16_t), 1); + hfp_hf_set_codecs(default_codecs, 1); + + setup_hfp_service_level_connection(hfp_slc_tests()[1].test, hfp_slc_tests()[1].len); + CHECK_EQUAL(service_level_connection_established, 1); + + setup_hfp_codecs_connection(default_cc_setup(), default_cc_setup_size()); + CHECK_EQUAL(codecs_connection_established, 1); + + // hfp_hf_establish_audio_connection(device_addr); + // CHECK_EQUAL(audio_connection_established, 1); + + // hfp_hf_release_audio_connection(device_addr); + // CHECK_EQUAL(audio_connection_established, 0); +} TEST(HFPClient, HFCodecsConnectionEstablished){ for (int i = 0; i < cc_tests_size(); i++){ @@ -231,9 +272,6 @@ TEST(HFPClient, HFServiceLevelConnectionEstablished){ int main (int argc, const char * argv[]){ - 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); - return CommandLineTestRunner::RunAllTests(argc, argv); }