diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index c4b2aeac4..df5c1b374 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -948,10 +948,6 @@ static void call_failure(SalOp *op){ msg=_("Incompatible media parameters."); linphone_core_notify_display_status(lc,msg); break; - case SalReasonNoMatch: - /* Call leg does not exist response for case of section 5.5 of RFC 6141 */ - linphone_call_reinvite_to_recover_from_connection_loss(call); - return; /* Do not continue... */ default: linphone_core_notify_display_status(lc,_("Call failed.")); } @@ -961,9 +957,11 @@ static void call_failure(SalOp *op){ case LinphoneCallUpdating: case LinphoneCallPausing: case LinphoneCallResuming: - ms_message("Call error on state [%s], restoring previous state",linphone_call_state_to_string(call->prevstate)); - linphone_call_set_state(call, call->prevstate,ei->full_string); - return; + if (ei->reason != SalReasonNoMatch){ + ms_message("Call error on state [%s], restoring previous state",linphone_call_state_to_string(call->prevstate)); + linphone_call_set_state(call, call->prevstate,ei->full_string); + return; + } default: break; /*nothing to do*/ } @@ -979,7 +977,11 @@ static void call_failure(SalOp *op){ if (ei->reason==SalReasonDeclined){ linphone_call_set_state(call,LinphoneCallEnd,"Call declined."); }else{ - linphone_call_set_state(call,LinphoneCallError,ei->full_string); + if (linphone_call_state_is_early(call->state)){ + linphone_call_set_state(call,LinphoneCallError,ei->full_string); + }else{ + linphone_call_set_state(call, LinphoneCallEnd, ei->full_string); + } } if (ei->reason!=SalReasonNone) linphone_core_play_call_error_tone(lc,linphone_reason_from_sal(ei->reason)); } diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index d3b83c0b3..6a23187f4 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -49,6 +49,35 @@ static void _linphone_call_set_next_video_frame_decoded_trigger(LinphoneCall *ca void linphone_call_handle_stream_events(LinphoneCall *call, int stream_index); +bool_t linphone_call_state_is_early(LinphoneCallState state){ + switch (state){ + case LinphoneCallIdle: + case LinphoneCallOutgoingInit: + case LinphoneCallOutgoingEarlyMedia: + case LinphoneCallOutgoingRinging: + case LinphoneCallOutgoingProgress: + case LinphoneCallIncomingReceived: + case LinphoneCallIncomingEarlyMedia: + case LinphoneCallEarlyUpdatedByRemote: + case LinphoneCallEarlyUpdating: + return TRUE; + case LinphoneCallResuming: + case LinphoneCallEnd: + case LinphoneCallUpdating: + case LinphoneCallRefered: + case LinphoneCallPausing: + case LinphoneCallPausedByRemote: + case LinphoneCallPaused: + case LinphoneCallConnected: + case LinphoneCallError: + case LinphoneCallUpdatedByRemote: + case LinphoneCallReleased: + case LinphoneCallStreamsRunning: + break; + } + return FALSE; +} + MSWebCam *get_nowebcam_device(MSFactory* f){ #ifdef VIDEO_ENABLED return ms_web_cam_manager_get_cam(ms_factory_get_web_cam_manager(f),"StaticImage: Static picture"); diff --git a/coreapi/private.h b/coreapi/private.h index 5563b71e1..104d80d96 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -1634,6 +1634,8 @@ char *linphone_presence_model_to_xml(LinphonePresenceModel *model) ; void linphone_call_check_ice_session(LinphoneCall *call, IceRole role, bool_t is_reinvite); +bool_t linphone_call_state_is_early(LinphoneCallState state); + #ifdef __cplusplus } #endif diff --git a/mediastreamer2 b/mediastreamer2 index ff857a686..079df9659 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit ff857a68653beae24fff732b1afbdd082eb589cc +Subproject commit 079df9659a25a5a06c85e6a64bf226bc4fa7d91b diff --git a/tester/call_single_tester.c b/tester/call_single_tester.c index 032a276f4..601b3ad34 100644 --- a/tester/call_single_tester.c +++ b/tester/call_single_tester.c @@ -4559,6 +4559,48 @@ static void call_with_network_switch_and_socket_refresh(void){ _call_with_network_switch(TRUE, TRUE, FALSE); } +static void call_with_network_switch_no_recovery(void){ + LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new(transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc"); + LinphoneCallParams *pauline_params = NULL; + bctbx_list_t *lcs = NULL; + bool_t call_ok; + + lcs = bctbx_list_append(lcs, marie->lc); + lcs = bctbx_list_append(lcs, pauline->lc); + + linphone_core_set_nortp_timeout(marie->lc, 50000); + + BC_ASSERT_TRUE((call_ok=call_with_params(pauline, marie, pauline_params, NULL))); + if (!call_ok) goto end; + + wait_for_until(marie->lc, pauline->lc, NULL, 0, 2000); + + /*marie looses the network and reconnects*/ + linphone_core_set_network_reachable(marie->lc, FALSE); + /*but meanwhile pauline terminates the call.*/ + linphone_core_terminate_call(pauline->lc, linphone_core_get_current_call(pauline->lc)); + /* + * We have to wait 32 seconds so that the BYE transaction is terminated, and dialog removed. + * This is the condition to receive a 481 when marie sends the reINVITE.*/ + wait_for_list(lcs, NULL, 0, 32500); + + /*marie will reconnect, register, and send an automatic reINVITE to try to repair the call*/ + linphone_core_set_network_reachable(marie->lc, TRUE); + BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &marie->stat.number_of_LinphoneRegistrationOk, 2)); + BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &marie->stat.number_of_LinphoneCallUpdating, 1)); + /*This reINVITE should of course fail, so marie's call should be terminated.*/ + BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &marie->stat.number_of_LinphoneCallEnd, 1)); + +end: + if (pauline_params) { + linphone_call_params_unref(pauline_params); + } + bctbx_list_free(lcs); + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + static void call_with_sip_and_rtp_independant_switches(void){ LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new(transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc"); @@ -5350,6 +5392,7 @@ test_t call_tests[] = { TEST_NO_TAG("Call paused resumed with custom RTP Modifier", call_paused_resumed_with_custom_rtp_modifier), TEST_NO_TAG("Call record with custom RTP Modifier", call_record_with_custom_rtp_modifier), TEST_NO_TAG("Call with network switch", call_with_network_switch), + TEST_NO_TAG("Call with network switch and no recovery possible", call_with_network_switch_no_recovery), TEST_NO_TAG("Recovered call on network switch in early state 1", recovered_call_on_network_switch_in_early_state_1), TEST_NO_TAG("Recovered call on network switch in early state 2", recovered_call_on_network_switch_in_early_state_2), TEST_NO_TAG("Recovered call on network switch in early state 3", recovered_call_on_network_switch_in_early_state_3),