forked from mirrors/linphone-iphone
implement automatic repairing of SIP dialogs broken by a network disconnection.
This commit is contained in:
parent
1127f97f8c
commit
13f0d85f68
6 changed files with 130 additions and 10 deletions
|
|
@ -3651,16 +3651,23 @@ static void report_bandwidth(LinphoneCall *call, MediaStream *as, MediaStream *v
|
|||
|
||||
}
|
||||
|
||||
static void linphone_core_disconnected(LinphoneCore *lc, LinphoneCall *call){
|
||||
char temp[256]={0};
|
||||
static void linphone_call_lost(LinphoneCall *call, LinphoneReason reason){
|
||||
LinphoneCore *lc = call->core;
|
||||
char *temp = NULL;
|
||||
char *from=NULL;
|
||||
|
||||
from = linphone_call_get_remote_address_as_string(call);
|
||||
snprintf(temp,sizeof(temp)-1,"Remote end %s seems to have disconnected, the call is going to be closed.",from ? from : "");
|
||||
switch(reason){
|
||||
case LinphoneReasonIOError:
|
||||
temp = ms_strdup_printf("Call with %s disconnected because of network, it is going to be closed.", from ? from : "?");
|
||||
break;
|
||||
default:
|
||||
temp = ms_strdup_printf("Media connectivity with %s is lost, call is going to be closed.", from ? from : "?");
|
||||
break;
|
||||
}
|
||||
if (from) ms_free(from);
|
||||
|
||||
ms_message("On call [%p]: %s",call,temp);
|
||||
linphone_core_notify_display_warning(lc,temp);
|
||||
ms_message("LinphoneCall [%p]: %s",call, temp);
|
||||
linphone_core_notify_display_warning(lc, temp);
|
||||
linphone_core_terminate_call(lc,call);
|
||||
linphone_core_play_named_tone(lc,LinphoneToneCallLost);
|
||||
}
|
||||
|
|
@ -3928,7 +3935,7 @@ void linphone_call_background_tasks(LinphoneCall *call, bool_t one_second_elapse
|
|||
&& call->audiostream->ms.state==MSStreamStarted && disconnect_timeout>0 )
|
||||
disconnected=!audio_stream_alive(call->audiostream,disconnect_timeout);
|
||||
if (disconnected)
|
||||
linphone_core_disconnected(call->core,call);
|
||||
linphone_call_lost(call, LinphoneReasonUnknown);
|
||||
}
|
||||
|
||||
void linphone_call_log_completed(LinphoneCall *call){
|
||||
|
|
@ -4234,3 +4241,52 @@ RtpTransport* linphone_call_get_meta_rtcp_transport(LinphoneCall *call, int stre
|
|||
rtp_session_get_transports(call->sessions[stream_index].rtp_session, &meta_rtp, &meta_rtcp);
|
||||
return meta_rtcp;
|
||||
}
|
||||
|
||||
void linphone_call_set_broken(LinphoneCall *call){
|
||||
switch(call->state){
|
||||
/*for all the early states, we prefer to drop the call*/
|
||||
case LinphoneCallOutgoingInit:
|
||||
case LinphoneCallOutgoingRinging:
|
||||
case LinphoneCallOutgoingEarlyMedia:
|
||||
case LinphoneCallIncomingReceived:
|
||||
case LinphoneCallIncomingEarlyMedia:
|
||||
linphone_call_lost(call, LinphoneReasonIOError);
|
||||
break;
|
||||
case LinphoneCallStreamsRunning:
|
||||
case LinphoneCallPaused:
|
||||
case LinphoneCallPausedByRemote:
|
||||
call->broken = TRUE;
|
||||
break;
|
||||
default:
|
||||
ms_error("linphone_call_set_broken() unimplemented case.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void linphone_call_repair_if_broken(LinphoneCall *call){
|
||||
LinphoneCallParams *params;
|
||||
|
||||
if (!call->broken) return;
|
||||
|
||||
/*First, make sure that the proxy from which we received this call, or to which we routed this call is registered*/
|
||||
if (!call->dest_proxy || linphone_proxy_config_get_state(call->dest_proxy) != LinphoneRegistrationOk) return;
|
||||
|
||||
|
||||
switch (call->state){
|
||||
case LinphoneCallStreamsRunning:
|
||||
case LinphoneCallPaused:
|
||||
case LinphoneCallPausedByRemote:
|
||||
ms_message("LinphoneCall[%p] is going to be updated (reINVITE) in order to recover from lost connectivity", call);
|
||||
if (call->ice_session){
|
||||
ice_session_restart(call->ice_session);
|
||||
ice_session_set_role(call->ice_session, IR_Controlling);
|
||||
}
|
||||
params = linphone_core_create_call_params(call->core, call);
|
||||
linphone_core_update_call(call->core, call, params);
|
||||
linphone_call_params_unref(params);
|
||||
break;
|
||||
default:
|
||||
ms_error("linphone_call_resume_if_broken(): don't know what to do in state [%s]", linphone_call_state_to_string(call->state));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3281,6 +3281,7 @@ int linphone_core_update_call(LinphoneCore *lc, LinphoneCall *call, const Linpho
|
|||
}
|
||||
|
||||
if (params!=NULL){
|
||||
call->broken = FALSE;
|
||||
linphone_call_set_state(call,nextstate,"Updating call");
|
||||
#if defined(VIDEO_ENABLED) && defined(BUILD_UPNP)
|
||||
has_video = call->params->has_video;
|
||||
|
|
@ -6200,6 +6201,8 @@ static void set_network_reachable(LinphoneCore* lc,bool_t isReachable, time_t cu
|
|||
if (!lc->network_reachable){
|
||||
linphone_core_invalidate_friend_subscriptions(lc);
|
||||
sal_reset_transports(lc->sal);
|
||||
/*mark all calls as broken, so that they can be either dropped immediately or restaured when network will be back*/
|
||||
ms_list_for_each(lc->calls, (MSIterateFunc) linphone_call_set_broken);
|
||||
}else{
|
||||
linphone_core_resolve_stun_server(lc);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1833,4 +1833,3 @@ void linphone_task_list_run(LinphoneTaskList *t){
|
|||
void linphone_task_list_free(LinphoneTaskList *t){
|
||||
t->hooks = ms_list_free_with_data(t->hooks, (void (*)(void*))ms_free);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -311,6 +311,7 @@ struct _LinphoneCall{
|
|||
bool_t record_active;
|
||||
|
||||
bool_t paused_by_app;
|
||||
bool_t broken; /*set to TRUE when the call is in broken state due to network disconnection or transport */
|
||||
};
|
||||
|
||||
BELLE_SIP_DECLARE_VPTR(LinphoneCall);
|
||||
|
|
@ -935,6 +936,8 @@ LinphoneEcCalibratorStatus ec_calibrator_get_status(EcCalibrator *ecc);
|
|||
void ec_calibrator_destroy(EcCalibrator *ecc);
|
||||
|
||||
void linphone_call_background_tasks(LinphoneCall *call, bool_t one_second_elapsed);
|
||||
void linphone_call_set_broken(LinphoneCall *call);
|
||||
void linphone_call_repair_if_broken(LinphoneCall *call);
|
||||
void linphone_core_preempt_sound_resources(LinphoneCore *lc);
|
||||
int _linphone_core_pause_call(LinphoneCore *lc, LinphoneCall *call);
|
||||
|
||||
|
|
|
|||
|
|
@ -1512,8 +1512,13 @@ void linphone_proxy_config_set_state(LinphoneProxyConfig *cfg, LinphoneRegistrat
|
|||
if (update_friends){
|
||||
linphone_core_update_friends_subscriptions(lc,cfg,TRUE);
|
||||
}
|
||||
if (lc)
|
||||
if (lc){
|
||||
linphone_core_notify_registration_state_changed(lc,cfg,state,message);
|
||||
if (lc->calls && lp_config_get_int(lc->config, "sip", "repair_broken_calls", 1)){
|
||||
/*if we are registered and there were broken calls due to a past network disconnection, attempt to repair them*/
|
||||
ms_list_for_each(lc->calls, (MSIterateFunc) linphone_call_repair_if_broken);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/*state already reported*/
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4901,6 +4901,55 @@ static void call_record_with_custom_rtp_modifier(void) {
|
|||
custom_rtp_modifier(FALSE, TRUE);
|
||||
}
|
||||
|
||||
static void _call_with_network_switch(bool_t use_ice){
|
||||
LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc");
|
||||
LinphoneCoreManager* pauline = linphone_core_manager_new(transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc");
|
||||
bool_t call_ok;
|
||||
|
||||
if (use_ice){
|
||||
linphone_core_set_firewall_policy(marie->lc,LinphonePolicyUseIce);
|
||||
linphone_core_set_firewall_policy(pauline->lc,LinphonePolicyUseIce);
|
||||
}
|
||||
|
||||
BC_ASSERT_TRUE((call_ok=call(pauline,marie)));
|
||||
if (!call_ok) goto end;
|
||||
|
||||
wait_for_until(marie->lc, pauline->lc, NULL, 0, 2000);
|
||||
if (use_ice) BC_ASSERT_TRUE(check_ice(pauline,marie,LinphoneIceStateHostConnection));
|
||||
|
||||
/*marie looses the network and reconnects*/
|
||||
linphone_core_set_network_reachable(marie->lc, FALSE);
|
||||
wait_for_until(marie->lc, pauline->lc, NULL, 0, 1000);
|
||||
|
||||
/*marie will reconnect and register*/
|
||||
linphone_core_set_network_reachable(marie->lc, TRUE);
|
||||
BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &marie->stat.number_of_LinphoneRegistrationOk, 2));
|
||||
|
||||
/*pauline shall receive a reINVITE to update the session*/
|
||||
BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &pauline->stat.number_of_LinphoneCallUpdatedByRemote, 1));
|
||||
BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &pauline->stat.number_of_LinphoneCallStreamsRunning, 2));
|
||||
BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &marie->stat.number_of_LinphoneCallStreamsRunning, 2));
|
||||
|
||||
liblinphone_tester_check_rtcp(pauline, marie);
|
||||
if (use_ice) BC_ASSERT_TRUE(check_ice(pauline,marie,LinphoneIceStateHostConnection));
|
||||
|
||||
/*pauline shall be able to end the call without problem now*/
|
||||
end_call(pauline, marie);
|
||||
end:
|
||||
linphone_core_manager_destroy(marie);
|
||||
linphone_core_manager_destroy(pauline);
|
||||
}
|
||||
|
||||
static void call_with_network_switch(void){
|
||||
_call_with_network_switch(FALSE);
|
||||
}
|
||||
|
||||
#if 0
|
||||
static void call_with_network_switch_and_ice(void){
|
||||
_call_with_network_switch(TRUE);
|
||||
}
|
||||
#endif
|
||||
|
||||
test_t call_tests[] = {
|
||||
{ "Early declined call", early_declined_call },
|
||||
{ "Call declined", call_declined },
|
||||
|
|
@ -5033,7 +5082,12 @@ test_t call_tests[] = {
|
|||
{ "Call with complex late offering", call_with_complex_late_offering },
|
||||
{ "Call with custom RTP Modifier", call_with_custom_rtp_modifier },
|
||||
{ "Call paused resumed with custom RTP Modifier", call_paused_resumed_with_custom_rtp_modifier },
|
||||
{ "Call record with custom RTP Modifier", call_record_with_custom_rtp_modifier }
|
||||
{ "Call record with custom RTP Modifier", call_record_with_custom_rtp_modifier },
|
||||
{ "Call with network switch", call_with_network_switch }
|
||||
#if 0
|
||||
,
|
||||
{ "Call with network switch and ICE", call_with_network_switch_and_ice }
|
||||
#endif
|
||||
};
|
||||
|
||||
test_suite_t call_test_suite = {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue