From 0b160493948846679afcb6d53481e946e1103596 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Mon, 5 Dec 2016 14:03:46 +0100 Subject: [PATCH] If connectivity is lost during an outgoing call at a very early stage (the dialog has not been created yet), try to repair the call by cancelling the INVITE and issuing a new one. --- coreapi/bellesip_sal/sal_op_call.c | 39 ++++++++++++++++-------------- coreapi/linphonecall.c | 6 ++++- coreapi/linphonecore.c | 1 + 3 files changed, 27 insertions(+), 19 deletions(-) diff --git a/coreapi/bellesip_sal/sal_op_call.c b/coreapi/bellesip_sal/sal_op_call.c index d393dc1af..5d48aa366 100644 --- a/coreapi/bellesip_sal/sal_op_call.c +++ b/coreapi/bellesip_sal/sal_op_call.c @@ -142,21 +142,12 @@ static int set_sdp_from_desc(belle_sip_message_t *msg, const SalMediaDescription return err; } -static void call_process_io_error(void *user_ctx, const belle_sip_io_error_event_t *event){ - SalOp* op=(SalOp*)user_ctx; - if (op->state==SalOpStateTerminated) return; - - if (!op->dialog) { - /*call terminated very early*/ - sal_error_info_set(&op->error_info,SalReasonIOError,503,"IO error",NULL); - op->base.root->callbacks.call_failure(op); - op->state = SalOpStateTerminating; - call_set_released(op); - } else { - /*dialog will terminated shortly, nothing to do*/ - } +static void call_process_io_error(void *user_ctx, const belle_sip_io_error_event_t *event) { + /* Nothing to be done. If the error comes from a connectivity loss, + * the call will be marked as broken, and an attempt to repair it will be done. */ } + static void process_dialog_terminated(void *ctx, const belle_sip_dialog_terminated_event_t *event) { SalOp* op=(SalOp*)ctx; @@ -297,11 +288,13 @@ static void call_process_response(void *op_base, const belle_sip_response_event_ call_set_error(op, response, TRUE); if (op->dialog==NULL) call_set_released(op); } - } else if (code >=200 - && code<300 - && strcmp("UPDATE",method)==0) { + } else if (code >=200 && code<300) { + if (strcmp("UPDATE",method)==0) { handle_sdp_from_response(op,response); op->base.root->callbacks.call_accepted(op); + } else if (strcmp("CANCEL", method) == 0) { + op->base.root->callbacks.call_cancel_done(op); + } } } break; @@ -949,7 +942,17 @@ int sal_call_decline(SalOp *op, SalReason reason, const char *redirection /*opti int sal_call_update(SalOp *op, const char *subject, bool_t no_user_consent){ belle_sip_request_t *update; - belle_sip_dialog_state_t state=belle_sip_dialog_get_state(op->dialog); + belle_sip_dialog_state_t state; + + if (op->dialog == NULL) { + /* If the dialog does not exist, this is that we are trying to recover from a connection loss + during a very early state of outgoing call initiation (the dialog has not been created yet). */ + const char *from = sal_op_get_from(op); + const char *to = sal_op_get_to(op); + return sal_call(op, from, to); + } + + state = belle_sip_dialog_get_state(op->dialog); belle_sip_dialog_enable_pending_trans_checking(op->dialog,op->base.root->pending_trans_checking); /*check for dialog state*/ @@ -978,7 +981,7 @@ int sal_call_update(SalOp *op, const char *subject, bool_t no_user_consent){ } SalMediaDescription * sal_call_get_remote_media_description(SalOp *h){ - return h->base.remote_media;; + return h->base.remote_media; } SalMediaDescription * sal_call_get_final_media_description(SalOp *h){ diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index bcbba4d86..46725088d 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -5036,6 +5036,7 @@ void linphone_call_set_broken(LinphoneCall *call){ switch(call->state){ /*for all the early states, we prefer to drop the call*/ case LinphoneCallOutgoingInit: + case LinphoneCallOutgoingProgress: case LinphoneCallOutgoingRinging: case LinphoneCallOutgoingEarlyMedia: case LinphoneCallIncomingReceived: @@ -5117,9 +5118,12 @@ void linphone_call_repair_if_broken(LinphoneCall *call){ } linphone_call_reinvite_to_recover_from_connection_loss(call); break; - case LinphoneCallOutgoingEarlyMedia: case LinphoneCallOutgoingInit: case LinphoneCallOutgoingProgress: + sal_call_cancel_invite(call->op); + call->reinvite_on_cancel_response_requested = TRUE; + break; + case LinphoneCallOutgoingEarlyMedia: case LinphoneCallOutgoingRinging: linphone_call_repair_by_invite_with_replaces(call); break; diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 28c1cdc3e..bae86b8bd 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -3666,6 +3666,7 @@ int linphone_core_update_call(LinphoneCore *lc, LinphoneCall *call, const Linpho case LinphoneCallUpdatedByRemote: nextstate=LinphoneCallUpdating; break; + case LinphoneCallOutgoingProgress: case LinphoneCallPausing: case LinphoneCallResuming: case LinphoneCallUpdating: