diff --git a/include/btstack/hci_cmds.h b/include/btstack/hci_cmds.h index fefbeafbf..31a4490a4 100644 --- a/include/btstack/hci_cmds.h +++ b/include/btstack/hci_cmds.h @@ -639,6 +639,8 @@ extern "C" { #define HFP_SUBEVENT_CODECS_CONNECTION_COMPLETE 0x09 #define HFP_SUBEVENT_START_RINGINIG 0x0A #define HFP_SUBEVENT_STOP_RINGINIG 0x0B +#define HFP_SUBEVENT_CALL_TERMINATED 0x0C + diff --git a/src/hfp.c b/src/hfp.c index 5d8e4dd31..b431b3358 100644 --- a/src/hfp.c +++ b/src/hfp.c @@ -613,6 +613,10 @@ static hfp_command_t parse_command(const char * line_buffer, int isHandsFree){ return HFP_CMD_CALL_ANSWERED; } + if (strncmp(line_buffer+offset, HFP_HANG_UP_CALL, strlen(HFP_HANG_UP_CALL)) == 0){ + return HFP_CMD_HANG_UP_CALL; + } + if (strncmp(line_buffer+offset, HFP_ERROR, strlen(HFP_ERROR)) == 0){ return HFP_CMD_ERROR; } diff --git a/src/hfp.h b/src/hfp.h index 0b589402f..133dfb330 100644 --- a/src/hfp.h +++ b/src/hfp.h @@ -116,6 +116,7 @@ extern "C" { #define HFP_TRIGGER_CODEC_CONNECTION_SETUP "+BCC" #define HFP_CONFIRM_COMMON_CODEC "+BCS" #define HFP_CALL_ANSWERED "ATA" +#define HFP_HANG_UP_CALL "+CHUP" #define HFP_OK "OK" #define HFP_ERROR "ERROR" @@ -154,7 +155,8 @@ typedef enum { HFP_CMD_AG_SEND_COMMON_CODEC, HFP_CMD_AG_SUGGESTED_CODEC, HFP_CMD_HF_CONFIRMED_CODEC, - HFP_CMD_CALL_ANSWERED + HFP_CMD_CALL_ANSWERED, + HFP_CMD_HANG_UP_CALL } hfp_command_t; typedef enum { diff --git a/src/hfp_ag.c b/src/hfp_ag.c index 5cac2551e..0cecfc1cc 100644 --- a/src/hfp_ag.c +++ b/src/hfp_ag.c @@ -606,17 +606,22 @@ static int incoming_call_state_machine(hfp_connection_t * context){ // printf(" -> State machine: Incoming Call\n"); hfp_ag_indicator_t * indicator; - + if (context->command == HFP_CMD_HANG_UP_CALL){ + context->terminate_call = 1; + hfp_ag_ok(context->rfcomm_cid); + return 1; + } + if (context->terminate_call){ printf(" -> State machine: Terminate Incoming Call\n"); indicator = get_ag_indicator_for_name("call"); if (!indicator) return 0; indicator->status = HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS; - hfp_ag_transfer_ag_indicators_status_cmd(context->rfcomm_cid, indicator); - context->terminate_call = 0; context->run_call_state_machine = 0; + hfp_emit_event(hfp_callback, HFP_SUBEVENT_CALL_TERMINATED, 0); + hfp_ag_transfer_ag_indicators_status_cmd(context->rfcomm_cid, indicator); return 1; } diff --git a/test/hfp/hfp_ag_client_test.c b/test/hfp/hfp_ag_client_test.c index 09a301511..721ea4003 100644 --- a/test/hfp/hfp_ag_client_test.c +++ b/test/hfp/hfp_ag_client_test.c @@ -102,6 +102,7 @@ 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; int expected_rfcomm_command(const char * expected_cmd){ char * ag_cmd = (char *)get_rfcomm_payload(); @@ -177,6 +178,9 @@ void packet_handler(uint8_t * event, uint16_t event_size){ 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]); break; @@ -189,6 +193,9 @@ TEST_GROUP(HFPClient){ service_level_connection_established = 0; codecs_connection_established = 0; audio_connection_established = 0; + start_ringing = 0; + stop_ringing = 0; + call_termiated = 0; hfp_ag_init(rfcomm_channel_nr, supported_features_with_codec_negotiation, codecs, sizeof(codecs), @@ -218,7 +225,24 @@ TEST_GROUP(HFPClient){ } }; -TEST(HFPClient, HFAnswerIncomingCallWithInBandRingTone){ +TEST(HFPClient, HFAnswerIncomingCallWithInBandRingToneHFTermiantesCall){ + setup_hfp_service_level_connection(default_slc_setup(), default_slc_setup_size()); + CHECK_EQUAL(service_level_connection_established, 1); + + hfp_ag_set_use_in_band_ring_tone(1); + hfp_ag_incoming_call(); + 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(stop_ringing, 1); + + simulate_test_sequence(terminate_ic_hf_setup(), terminate_ic_hf_setup_size()); + CHECK_EQUAL(call_termiated,1); +} + + +TEST(HFPClient, HFAnswerIncomingCallWithInBandRingToneAGTerminatesCall){ setup_hfp_service_level_connection(default_slc_setup(), default_slc_setup_size()); CHECK_EQUAL(service_level_connection_established, 1); @@ -230,8 +254,10 @@ TEST(HFPClient, HFAnswerIncomingCallWithInBandRingTone){ simulate_test_sequence(alert_ic_setup(), alert_ic_setup_size()); CHECK_EQUAL(stop_ringing, 1); + // AG terminates call hfp_ag_terminate_call(); simulate_test_sequence(terminate_ic_ag_setup(), terminate_ic_ag_setup_size()); + CHECK_EQUAL(call_termiated,1); } diff --git a/test/hfp/test_sequences.c b/test/hfp/test_sequences.c index d852d4fe5..49c61e2e8 100644 --- a/test/hfp/test_sequences.c +++ b/test/hfp/test_sequences.c @@ -191,8 +191,10 @@ const char * ic_ag_terminates_call[] = { const char * ic_hf_terminates_call[] = { // HF terminates call + "NOP", "AT+CHUP", - "OK" + "OK", + "NOP", "+CIEV:2,0" };