Merge branch 'dev_rat'

This commit is contained in:
Ghislain MARY 2016-10-19 10:29:27 +02:00
commit 871984b4ee
10 changed files with 472 additions and 53 deletions

View file

@ -130,6 +130,7 @@ SalOp* sal_op_ref(SalOp* op);
void* sal_op_unref(SalOp* op);
void sal_op_release_impl(SalOp *op);
void sal_op_set_replaces(SalOp* op,belle_sip_header_replaces_t* replaces);
void sal_op_set_remote_ua(SalOp*op,belle_sip_message_t* message);
int sal_op_send_request(SalOp* op, belle_sip_request_t* request);
int sal_op_send_request_with_expires(SalOp* op, belle_sip_request_t* request,int expires);

View file

@ -208,7 +208,7 @@ static void handle_sdp_from_response(SalOp* op,belle_sip_response_t* response) {
if (op->base.local_media) sdp_process(op);
}
static void cancelling_invite(SalOp* op ){
void sal_call_cancel_invite(SalOp* op) {
belle_sip_request_t* cancel;
ms_message("Cancelling INVITE request from [%s] to [%s] ",sal_op_get_from(op), sal_op_get_to(op));
cancel = belle_sip_client_transaction_create_cancel(op->pending_client_trans);
@ -229,6 +229,10 @@ static void cancelling_invite(SalOp* op ){
break;
}
}
}
static void cancelling_invite(SalOp *op) {
sal_call_cancel_invite(op);
op->state=SalOpStateTerminating;
}
@ -295,7 +299,7 @@ static void call_process_response(void *op_base, const belle_sip_response_event_
}
} else if (code >=200
&& code<300
&& strcmp("UPDATE",belle_sip_request_get_method(req))==0) {
&& strcmp("UPDATE",method)==0) {
handle_sdp_from_response(op,response);
op->base.root->callbacks.call_accepted(op);
}
@ -339,6 +343,9 @@ static void call_process_response(void *op_base, const belle_sip_response_event_
}
}else if (strcmp("UPDATE",method)==0){
op->base.root->callbacks.call_accepted(op); /*INVITE*/
}else if (strcmp("CANCEL",method)==0){
sal_op_set_error_info_from_response(op,response);
op->base.root->callbacks.call_failure(op);
}
break;
case SalOpStateTerminating:
@ -496,6 +503,7 @@ static int process_sdp_for_invite(SalOp* op,belle_sip_request_t* invite) {
belle_sdp_session_description_t* sdp;
int err=0;
SalReason reason;
if (extract_sdp(op,BELLE_SIP_MESSAGE(invite),&sdp,&reason)==0) {
if (sdp){
op->sdp_offering=FALSE;
@ -878,9 +886,9 @@ int sal_call_accept(SalOp*h){
return -1;
}
ms_message("Accepting server transaction [%p] on op [%p]", transaction, h);
/* sends a 200 OK */
response = sal_op_create_response_from_request(h,belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(transaction)),200);
if (response==NULL){
ms_error("Fail to build answer for call");
return -1;
@ -1086,6 +1094,24 @@ int sal_call_is_offerer(const SalOp *h){
return h->sdp_offering;
}
bool_t sal_call_compare_op(const SalOp *op1, const SalOp *op2) {
if (strcmp(op1->base.call_id, op2->base.call_id) == 0) return TRUE;
return FALSE;
}
bool_t sal_call_dialog_request_pending(const SalOp *op) {
return belle_sip_dialog_request_pending(op->dialog) ? TRUE : FALSE;
}
const char * sal_call_get_local_tag(SalOp *op) {
return belle_sip_dialog_get_local_tag(op->dialog);
}
const char * sal_call_get_remote_tag(SalOp *op) {
return belle_sip_dialog_get_remote_tag(op->dialog);
}
void sal_call_set_replaces(SalOp *op, const char *call_id, const char *from_tag, const char *to_tag) {
belle_sip_header_replaces_t *replaces = belle_sip_header_replaces_create(call_id, from_tag, to_tag);
sal_op_set_replaces(op, replaces);
}

View file

@ -22,13 +22,6 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
/*call transfer*/
static void sal_op_set_replaces(SalOp* op,belle_sip_header_replaces_t* replaces) {
if (op->replaces){
belle_sip_object_unref(op->replaces);
}
op->replaces=replaces;
belle_sip_object_ref(op->replaces);
}
static void sal_op_set_referred_by(SalOp* op,belle_sip_header_referred_by_t* referred_by) {
if (op->referred_by){
belle_sip_object_unref(op->referred_by);

View file

@ -30,6 +30,11 @@ SalOp * sal_op_new(Sal *sal){
return op;
}
void sal_op_kill_dialog(SalOp *op) {
ms_warning("op [%p]: force kill of dialog [%p]", op, op->dialog);
belle_sip_dialog_delete(op->dialog);
}
void sal_op_release(SalOp *op){
/*if in terminating state, keep this state because it means we are waiting for a response to be able to terminate the operation.*/
if (op->state!=SalOpStateTerminating)
@ -235,6 +240,14 @@ int sal_ping(SalOp *op, const char *from, const char *to){
return sal_op_send_request(op,sal_op_build_request(op,"OPTIONS"));
}
void sal_op_set_replaces(SalOp* op,belle_sip_header_replaces_t* replaces) {
if (op->replaces){
belle_sip_object_unref(op->replaces);
}
op->replaces=replaces;
belle_sip_object_ref(op->replaces);
}
void sal_op_set_remote_ua(SalOp*op,belle_sip_message_t* message) {
belle_sip_header_user_agent_t* user_agent=belle_sip_message_get_header_by_type(message,belle_sip_header_user_agent_t);
char user_agent_string[256];

View file

@ -240,9 +240,28 @@ static bool_t already_a_call_with_remote_address(const LinphoneCore *lc, const L
}
static LinphoneCall * look_for_broken_call_to_replace(SalOp *h, LinphoneCore *lc) {
const bctbx_list_t *calls = linphone_core_get_calls(lc);
const bctbx_list_t *it = calls;
while (it != NULL) {
LinphoneCall *replaced_call = NULL;
LinphoneCall *call = (LinphoneCall *)bctbx_list_get_data(it);
SalOp *replaced_op = sal_call_get_replaces(h);
if (replaced_op) replaced_call = (LinphoneCall*)sal_op_get_user_pointer(replaced_op);
if ((call->broken && sal_call_compare_op(h, call->op))
|| ((replaced_call == call) && (strcmp(sal_op_get_from(h), sal_op_get_from(replaced_op)) == 0) && (strcmp(sal_op_get_to(h), sal_op_get_to(replaced_op)) == 0))) {
return call;
}
it = bctbx_list_next(it);
}
return NULL;
}
static void call_received(SalOp *h){
LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(h));
LinphoneCall *call;
LinphoneCall *replaced_call;
char *alt_contact;
LinphoneAddress *from_addr=NULL;
LinphoneAddress *to_addr=NULL;
@ -250,6 +269,13 @@ static void call_received(SalOp *h){
SalMediaDescription *md;
const char * p_asserted_id;
/* Look if this INVITE is for a call that has already been notified but broken because of network failure */
replaced_call = look_for_broken_call_to_replace(h, lc);
if (replaced_call != NULL) {
linphone_call_replace_op(replaced_call, h);
return;
}
/* first check if we can answer successfully to this invite */
if (linphone_presence_model_get_basic_status(lc->presence_model) == LinphonePresenceBasicStatusClosed) {
LinphonePresenceActivity *activity = linphone_presence_model_get_activity(lc->presence_model);
@ -421,8 +447,7 @@ static void call_ringing(SalOp *h){
/*already doing early media */
return;
}
if (lc->ringstream!=NULL) return;/*already ringing !*/
start_remote_ring(lc, call);
if (lc->ringstream == NULL) start_remote_ring(lc, call);
ms_message("Remote ringing...");
linphone_core_notify_display_status(lc,_("Remote ringing..."));
linphone_call_set_state(call,LinphoneCallOutgoingRinging,"Remote ringing");
@ -659,6 +684,7 @@ static void call_updated(LinphoneCore *lc, LinphoneCall *call, SalOp *op, bool_t
break;
case LinphoneCallStreamsRunning:
case LinphoneCallConnected:
case LinphoneCallUpdatedByRemote: // Can happen on UAC connectivity loss
if (sal_media_description_has_dir(rmd,SalStreamSendOnly) || sal_media_description_has_dir(rmd,SalStreamInactive)){
call_paused_by_remote(lc,call);
}else{
@ -672,7 +698,6 @@ static void call_updated(LinphoneCore *lc, LinphoneCall *call, SalOp *op, bool_t
case LinphoneCallUpdating:
case LinphoneCallPausing:
case LinphoneCallResuming:
case LinphoneCallUpdatedByRemote:
sal_call_decline(call->op,SalReasonInternalError,NULL);
/*no break*/
case LinphoneCallIdle:
@ -918,6 +943,10 @@ 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."));
}

View file

@ -5039,10 +5039,14 @@ void linphone_call_set_broken(LinphoneCall *call){
case LinphoneCallIncomingEarlyMedia:
/*during the early states, the SAL layer reports the failure from the dialog or transaction layer,
* hence, there is nothing special to do*/
break;
//break;
case LinphoneCallStreamsRunning:
case LinphoneCallUpdating:
case LinphoneCallPausing:
case LinphoneCallResuming:
case LinphoneCallPaused:
case LinphoneCallPausedByRemote:
case LinphoneCallUpdatedByRemote:
/*during these states, the dialog is established. A failure of a transaction is not expected to close it.
* Instead we have to repair the dialog by sending a reINVITE*/
call->broken = TRUE;
@ -5054,9 +5058,28 @@ void linphone_call_set_broken(LinphoneCall *call){
}
}
void linphone_call_repair_if_broken(LinphoneCall *call){
LinphoneCallParams *params;
static void linphone_call_repair_by_invite_with_replaces(LinphoneCall *call) {
const char *call_id = sal_op_get_call_id(call->op);
const char *from_tag = sal_call_get_local_tag(call->op);
const char *to_tag = sal_call_get_remote_tag(call->op);
sal_op_kill_dialog(call->op);
linphone_call_create_op(call);
sal_call_set_replaces(call->op, call_id, from_tag, to_tag);
linphone_core_start_invite(call->core, call, NULL);
}
void linphone_call_reinvite_to_recover_from_connection_loss(LinphoneCall *call) {
LinphoneCallParams *params;
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, IR_Controlling);
}
params = linphone_core_create_call_params(call->core, call);
linphone_core_update_call(call->core, call, params);
linphone_call_params_unref(params);
}
void linphone_call_repair_if_broken(LinphoneCall *call){
if (!call->broken) return;
if (!call->core->media_network_reachable) return;
@ -5070,19 +5093,34 @@ void linphone_call_repair_if_broken(LinphoneCall *call){
switch (call->state){
case LinphoneCallUpdating:
case LinphoneCallPausing:
if (sal_call_dialog_request_pending(call->op)) {
/* Need to cancel first re-INVITE as described in section 5.5 of RFC 6141 */
sal_call_cancel_invite(call->op);
}
break;
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, IR_Controlling);
if (!sal_call_dialog_request_pending(call->op)) {
linphone_call_reinvite_to_recover_from_connection_loss(call);
}
params = linphone_core_create_call_params(call->core, call);
linphone_core_update_call(call->core, call, params);
linphone_call_params_unref(params);
break;
break;
case LinphoneCallUpdatedByRemote:
if (sal_call_dialog_request_pending(call->op)) {
sal_call_decline(call->op, SalReasonServiceUnavailable, NULL);
}
linphone_call_reinvite_to_recover_from_connection_loss(call);
break;
case LinphoneCallOutgoingEarlyMedia:
case LinphoneCallOutgoingInit:
case LinphoneCallOutgoingProgress:
case LinphoneCallOutgoingRinging:
linphone_call_repair_by_invite_with_replaces(call);
break;
default:
ms_warning("linphone_call_resume_if_broken(): don't know what to do in state [%s]", linphone_call_state_to_string(call->state));
ms_warning("linphone_call_repair_if_broken(): don't know what to do in state [%s]", linphone_call_state_to_string(call->state));
call->broken = FALSE;
break;
}
@ -5097,3 +5135,32 @@ void linphone_call_refresh_sockets(LinphoneCall *call){
}
}
}
void linphone_call_replace_op(LinphoneCall *call, SalOp *op) {
switch (linphone_call_get_state(call)) {
case LinphoneCallConnected:
case LinphoneCallStreamsRunning:
sal_call_terminate(call->op);
break;
default:
break;
}
sal_op_kill_dialog(call->op);
sal_op_release(call->op);
call->op = op;
sal_op_set_user_pointer(call->op, call);
sal_call_set_local_media_description(call->op, call->localdesc);
switch (linphone_call_get_state(call)) {
case LinphoneCallIncomingEarlyMedia:
case LinphoneCallIncomingReceived:
sal_call_notify_ringing(call->op, (linphone_call_get_state(call) == LinphoneCallIncomingEarlyMedia) ? TRUE : FALSE);
break;
case LinphoneCallConnected:
case LinphoneCallStreamsRunning:
sal_call_accept(call->op);
break;
default:
ms_warning("linphone_call_replace_op(): don't know what to do in state [%s]", linphone_call_state_to_string(call->state));
break;
}
}

View file

@ -3622,8 +3622,14 @@ int linphone_core_update_call(LinphoneCore *lc, LinphoneCall *call, const Linpho
case LinphoneCallStreamsRunning:
case LinphoneCallPaused:
case LinphoneCallPausedByRemote:
case LinphoneCallUpdatedByRemote:
nextstate=LinphoneCallUpdating;
break;
case LinphoneCallPausing:
case LinphoneCallResuming:
case LinphoneCallUpdating:
nextstate=call->state;
break;
default:
ms_error("linphone_core_update_call() is not allowed in [%s] state",linphone_call_state_to_string(call->state));
return -1;

View file

@ -390,6 +390,8 @@ void linphone_call_log_destroy(LinphoneCallLog *cl);
void linphone_call_set_transfer_state(LinphoneCall* call, LinphoneCallState state);
LinphonePlayer *linphone_call_build_player(LinphoneCall*call);
void linphone_call_refresh_sockets(LinphoneCall *call);
void linphone_call_replace_op(LinphoneCall *call, SalOp *op);
void linphone_call_reinvite_to_recover_from_connection_loss(LinphoneCall *call);
LinphoneCallParams * linphone_call_params_new(void);
SalMediaProto get_proto_from_call_params(const LinphoneCallParams *params);

View file

@ -680,6 +680,7 @@ SalOp *sal_op_ref(SalOp* h);
void sal_op_stop_refreshing(SalOp *op);
int sal_op_refresh(SalOp *op);
void sal_op_kill_dialog(SalOp *op);
void sal_op_release(SalOp *h);
/*same as release, but does not stop refresher if any*/
void* sal_op_unref(SalOp* op);
@ -737,6 +738,7 @@ int sal_call_notify_ringing(SalOp *h, bool_t early_media);
int sal_call_accept(SalOp*h);
int sal_call_decline(SalOp *h, SalReason reason, const char *redirection /*optional*/);
int sal_call_update(SalOp *h, const char *subject, bool_t no_user_consent);
void sal_call_cancel_invite(SalOp *op);
SalMediaDescription * sal_call_get_remote_media_description(SalOp *h);
LINPHONE_PUBLIC SalMediaDescription * sal_call_get_final_media_description(SalOp *h);
int sal_call_refer(SalOp *h, const char *refer_to);
@ -752,6 +754,11 @@ bool_t sal_call_autoanswer_asked(SalOp *op);
void sal_call_send_vfu_request(SalOp *h);
int sal_call_is_offerer(const SalOp *h);
int sal_call_notify_refer_state(SalOp *h, SalOp *newcall);
bool_t sal_call_compare_op(const SalOp *op1, const SalOp *op2);
bool_t sal_call_dialog_request_pending(const SalOp *op);
const char * sal_call_get_local_tag(SalOp *op);
const char * sal_call_get_remote_tag(SalOp *op);
void sal_call_set_replaces(SalOp *op, const char *call_id, const char *from_tag, const char *to_tag);
/* Call test API */

View file

@ -1550,17 +1550,11 @@ void call_paused_resumed_base(bool_t multicast, bool_t with_losses) {
BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallPausing,2));
BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallPausedByRemote,2));
BC_ASSERT_TRUE(wait_for_until(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallPaused,2,1000));
/*now try to resume*/
/*now try to resume, it should be OK*/
sal_set_send_error(pauline->lc->sal,0);
linphone_core_resume_call(pauline->lc,call_pauline);
BC_ASSERT_FALSE(wait_for_until(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallStreamsRunning,3,2000));
BC_ASSERT_FALSE(wait_for_until(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallStreamsRunning,3,2000));
/*resume failed because ACK not received to re-invite is rejected*/
/*next try is ok*/
linphone_core_resume_call(pauline->lc,call_pauline);
BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallStreamsRunning,3));
BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallStreamsRunning,3));
BC_ASSERT_TRUE(wait_for_until(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallStreamsRunning,3,2000));
BC_ASSERT_TRUE(wait_for_until(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallStreamsRunning,3,2000));
}
@ -4156,26 +4150,28 @@ static void call_record_with_custom_rtp_modifier(void) {
custom_rtp_modifier(FALSE, TRUE);
}
static void _call_with_network_switch_in_early_state(bool_t network_loosed_by_caller){
static void recovered_call_on_network_switch_in_early_state_1(void) {
LinphoneCall *incoming_call;
LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc");
LinphoneCoreManager* pauline = linphone_core_manager_new(transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc");
linphone_core_invite_address(marie->lc, pauline->identity);
if (!BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &pauline->stat.number_of_LinphoneCallIncomingReceived, 1))) goto end;
if (!BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &marie->stat.number_of_LinphoneCallOutgoingRinging, 1))) goto end;
if (network_loosed_by_caller){
linphone_core_set_network_reachable(marie->lc, FALSE);
BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &marie->stat.number_of_LinphoneCallError, 1));
linphone_core_set_network_reachable(marie->lc, TRUE);
linphone_core_terminate_call(pauline->lc, linphone_core_get_current_call(pauline->lc));
BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &pauline->stat.number_of_LinphoneCallEnd, 1));
}else{
linphone_core_set_network_reachable(pauline->lc, FALSE);
BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &pauline->stat.number_of_LinphoneCallError, 1));
linphone_core_set_network_reachable(pauline->lc, TRUE);
linphone_core_terminate_call(marie->lc, linphone_core_get_current_call(marie->lc));
BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &marie->stat.number_of_LinphoneCallEnd, 1));
}
linphone_core_set_network_reachable(marie->lc, FALSE);
wait_for(marie->lc, pauline->lc, &marie->stat.number_of_NetworkReachableFalse, 1);
linphone_core_set_network_reachable(marie->lc, TRUE);
wait_for(marie->lc, pauline->lc, &marie->stat.number_of_NetworkReachableTrue, 2);
BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &marie->stat.number_of_LinphoneCallOutgoingRinging, 2));
incoming_call = linphone_core_get_current_call(pauline->lc);
linphone_core_accept_call(pauline->lc, incoming_call);
BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &marie->stat.number_of_LinphoneCallStreamsRunning, 1));
BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &pauline->stat.number_of_LinphoneCallStreamsRunning, 1));
linphone_core_terminate_call(pauline->lc, incoming_call);
BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &pauline->stat.number_of_LinphoneCallEnd, 1));
BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &marie->stat.number_of_LinphoneCallReleased, 1));
BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &pauline->stat.number_of_LinphoneCallReleased, 1));
end:
@ -4183,12 +4179,285 @@ end:
linphone_core_manager_destroy(pauline);
}
static void call_with_network_switch_in_early_state_1(void){
_call_with_network_switch_in_early_state(TRUE);
static void recovered_call_on_network_switch_in_early_state_2(void) {
LinphoneCall *incoming_call;
LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc");
LinphoneCoreManager* pauline = linphone_core_manager_new(transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc");
linphone_core_invite_address(marie->lc, pauline->identity);
if (!BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &pauline->stat.number_of_LinphoneCallIncomingReceived, 1))) goto end;
if (!BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &marie->stat.number_of_LinphoneCallOutgoingRinging, 1))) goto end;
incoming_call = linphone_core_get_current_call(pauline->lc);
linphone_core_accept_call(pauline->lc, incoming_call);
//linphone_core_iterate(pauline->lc);
linphone_core_set_network_reachable(marie->lc, FALSE);
wait_for(marie->lc, pauline->lc, &marie->stat.number_of_NetworkReachableFalse, 1);
linphone_core_set_network_reachable(marie->lc, TRUE);
wait_for(marie->lc, pauline->lc, &marie->stat.number_of_NetworkReachableTrue, 2);
BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &marie->stat.number_of_LinphoneCallStreamsRunning, 1));
BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &pauline->stat.number_of_LinphoneCallStreamsRunning, 1));
linphone_core_terminate_call(pauline->lc, incoming_call);
BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &pauline->stat.number_of_LinphoneCallEnd, 1));
BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &marie->stat.number_of_LinphoneCallReleased, 1));
BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &pauline->stat.number_of_LinphoneCallReleased, 1));
end:
linphone_core_manager_destroy(marie);
linphone_core_manager_destroy(pauline);
}
static void call_with_network_switch_in_early_state_2(void){
_call_with_network_switch_in_early_state(FALSE);
static void recovered_call_on_network_switch_in_early_state_3(void) {
LinphoneCall *incoming_call;
LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc");
LinphoneCoreManager* pauline = linphone_core_manager_new(transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc");
linphone_core_invite_address(marie->lc, pauline->identity);
if (!BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &pauline->stat.number_of_LinphoneCallIncomingReceived, 1))) goto end;
if (!BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &marie->stat.number_of_LinphoneCallOutgoingRinging, 1))) goto end;
linphone_core_set_network_reachable(pauline->lc, FALSE);
wait_for(marie->lc, pauline->lc, &pauline->stat.number_of_NetworkReachableFalse, 1);
linphone_core_set_network_reachable(pauline->lc, TRUE);
wait_for(marie->lc, pauline->lc, &pauline->stat.number_of_NetworkReachableTrue, 2);
wait_for_until(marie->lc, pauline->lc, NULL, 1, 2000);
incoming_call = linphone_core_get_current_call(pauline->lc);
linphone_core_accept_call(pauline->lc, incoming_call);
BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &marie->stat.number_of_LinphoneCallStreamsRunning, 1));
BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &pauline->stat.number_of_LinphoneCallStreamsRunning, 1));
linphone_core_terminate_call(pauline->lc, incoming_call);
BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &pauline->stat.number_of_LinphoneCallEnd, 1));
BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &marie->stat.number_of_LinphoneCallReleased, 1));
BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &pauline->stat.number_of_LinphoneCallReleased, 1));
end:
linphone_core_manager_destroy(marie);
linphone_core_manager_destroy(pauline);
}
static void recovered_call_on_network_switch_in_early_state_4(void) {
LinphoneCall *incoming_call;
LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc");
LinphoneCoreManager* pauline = linphone_core_manager_new("pauline_tcp_rc");
linphone_core_invite_address(marie->lc, pauline->identity);
if (!BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &pauline->stat.number_of_LinphoneCallIncomingReceived, 1))) goto end;
if (!BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &marie->stat.number_of_LinphoneCallOutgoingRinging, 1))) goto end;
incoming_call = linphone_core_get_current_call(pauline->lc);
linphone_core_accept_call(pauline->lc, incoming_call);
linphone_core_set_network_reachable(pauline->lc, FALSE);
wait_for(marie->lc, pauline->lc, &pauline->stat.number_of_NetworkReachableFalse, 1);
linphone_core_set_network_reachable(pauline->lc, TRUE);
wait_for(marie->lc, pauline->lc, &pauline->stat.number_of_NetworkReachableTrue, 2);
BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &marie->stat.number_of_LinphoneCallStreamsRunning, 1));
BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &pauline->stat.number_of_LinphoneCallStreamsRunning, 1));
BC_ASSERT_TRUE(sal_call_dialog_request_pending(incoming_call->op));
wait_for_until(marie->lc, pauline->lc, NULL, 1, 2000);
BC_ASSERT_FALSE(sal_call_dialog_request_pending(incoming_call->op));
linphone_core_terminate_call(pauline->lc, incoming_call);
BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &pauline->stat.number_of_LinphoneCallEnd, 1));
BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &marie->stat.number_of_LinphoneCallReleased, 1));
BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &pauline->stat.number_of_LinphoneCallReleased, 1));
end:
linphone_core_manager_destroy(marie);
linphone_core_manager_destroy(pauline);
}
static void recovered_call_on_network_switch_during_reinvite_1(void) {
LinphoneCall *incoming_call;
LinphoneCall *outgoing_call;
LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc");
LinphoneCoreManager* pauline = linphone_core_manager_new("pauline_tcp_rc");
linphone_core_invite_address(marie->lc, pauline->identity);
if (!BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &pauline->stat.number_of_LinphoneCallIncomingReceived, 1))) goto end;
if (!BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &marie->stat.number_of_LinphoneCallOutgoingRinging, 1))) goto end;
incoming_call = linphone_core_get_current_call(pauline->lc);
linphone_core_accept_call(pauline->lc, incoming_call);
BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &marie->stat.number_of_LinphoneCallStreamsRunning, 1));
BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &pauline->stat.number_of_LinphoneCallStreamsRunning, 1));
outgoing_call = linphone_core_get_current_call(marie->lc);
linphone_core_pause_call(marie->lc, outgoing_call);
linphone_core_set_network_reachable(marie->lc, FALSE);
wait_for(marie->lc, pauline->lc, &marie->stat.number_of_NetworkReachableFalse, 1);
linphone_core_set_network_reachable(marie->lc, TRUE);
wait_for(marie->lc, pauline->lc, &marie->stat.number_of_NetworkReachableTrue, 2);
BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &marie->stat.number_of_LinphoneCallPaused, 1));
linphone_core_terminate_call(pauline->lc, incoming_call);
BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &pauline->stat.number_of_LinphoneCallEnd, 1));
BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &marie->stat.number_of_LinphoneCallReleased, 1));
BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &pauline->stat.number_of_LinphoneCallReleased, 1));
end:
linphone_core_manager_destroy(marie);
linphone_core_manager_destroy(pauline);
}
static void configure_video_policies_for_network_switch(LinphoneCore *marie, LinphoneCore *pauline) {
LinphoneVideoPolicy policy;
policy.automatically_accept = FALSE;
policy.automatically_initiate = FALSE;
linphone_core_enable_video_capture(marie, TRUE);
linphone_core_enable_video_display(marie, TRUE);
linphone_core_enable_video_capture(pauline, TRUE);
linphone_core_enable_video_display(pauline, TRUE);
linphone_core_set_video_policy(marie, &policy);
linphone_core_set_video_policy(pauline, &policy);
lp_config_set_int(pauline->config, "sip", "defer_update_default", TRUE);
}
static void recovered_call_on_network_switch_during_reinvite_2(void) {
LinphoneCall *incoming_call;
LinphoneCall *outgoing_call;
LinphoneCallParams *params;
LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc");
LinphoneCoreManager* pauline = linphone_core_manager_new("pauline_tcp_rc");
configure_video_policies_for_network_switch(marie->lc, pauline->lc);
linphone_core_invite_address(marie->lc, pauline->identity);
if (!BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &pauline->stat.number_of_LinphoneCallIncomingReceived, 1))) goto end;
if (!BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &marie->stat.number_of_LinphoneCallOutgoingRinging, 1))) goto end;
incoming_call = linphone_core_get_current_call(pauline->lc);
linphone_core_accept_call(pauline->lc, incoming_call);
BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &marie->stat.number_of_LinphoneCallStreamsRunning, 1));
BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &pauline->stat.number_of_LinphoneCallStreamsRunning, 1));
outgoing_call = linphone_core_get_current_call(marie->lc);
params = linphone_core_create_call_params(marie->lc, outgoing_call);
linphone_call_params_enable_video(params, TRUE);
linphone_core_update_call(marie->lc, outgoing_call, params);
linphone_call_params_unref(params);
linphone_core_set_network_reachable(marie->lc, FALSE);
wait_for(marie->lc, pauline->lc, &marie->stat.number_of_NetworkReachableFalse, 1);
linphone_core_set_network_reachable(marie->lc, TRUE);
wait_for(marie->lc, pauline->lc, &marie->stat.number_of_NetworkReachableTrue, 2);
BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &pauline->stat.number_of_LinphoneCallUpdatedByRemote, 1));
BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &marie->stat.number_of_LinphoneRegistrationOk, 2));
wait_for_until(marie->lc, pauline->lc, NULL, 1, 2000);
params = linphone_core_create_call_params(pauline->lc, incoming_call);
linphone_call_params_enable_video(params, TRUE);
linphone_core_accept_call_update(pauline->lc, incoming_call, params);
linphone_call_params_unref(params);
BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &marie->stat.number_of_LinphoneCallStreamsRunning, 2));
BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &pauline->stat.number_of_LinphoneCallStreamsRunning, 2));
wait_for_until(marie->lc, pauline->lc, NULL, 1, 2000);
linphone_core_terminate_call(pauline->lc, incoming_call);
BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &pauline->stat.number_of_LinphoneCallEnd, 1));
BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &marie->stat.number_of_LinphoneCallReleased, 1));
BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &pauline->stat.number_of_LinphoneCallReleased, 1));
end:
linphone_core_manager_destroy(marie);
linphone_core_manager_destroy(pauline);
}
static void recovered_call_on_network_switch_during_reinvite_3(void) {
LinphoneCall *incoming_call;
LinphoneCall *outgoing_call;
LinphoneCallParams *params;
LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc");
LinphoneCoreManager* pauline = linphone_core_manager_new("pauline_tcp_rc");
configure_video_policies_for_network_switch(marie->lc, pauline->lc);
linphone_core_invite_address(marie->lc, pauline->identity);
if (!BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &pauline->stat.number_of_LinphoneCallIncomingReceived, 1))) goto end;
if (!BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &marie->stat.number_of_LinphoneCallOutgoingRinging, 1))) goto end;
incoming_call = linphone_core_get_current_call(pauline->lc);
linphone_core_accept_call(pauline->lc, incoming_call);
BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &marie->stat.number_of_LinphoneCallStreamsRunning, 1));
BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &pauline->stat.number_of_LinphoneCallStreamsRunning, 1));
outgoing_call = linphone_core_get_current_call(marie->lc);
params = linphone_core_create_call_params(marie->lc, outgoing_call);
linphone_call_params_enable_video(params, TRUE);
linphone_core_update_call(marie->lc, outgoing_call, params);
linphone_call_params_unref(params);
BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &pauline->stat.number_of_LinphoneCallUpdatedByRemote, 1));
linphone_core_set_network_reachable(pauline->lc, FALSE);
wait_for(marie->lc, pauline->lc, &pauline->stat.number_of_NetworkReachableFalse, 1);
linphone_core_set_network_reachable(pauline->lc, TRUE);
wait_for(marie->lc, pauline->lc, &pauline->stat.number_of_NetworkReachableTrue, 2);
BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &pauline->stat.number_of_LinphoneRegistrationOk, 2));
BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &marie->stat.number_of_LinphoneCallUpdatedByRemote, 1));
BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &marie->stat.number_of_LinphoneCallStreamsRunning, 2));
BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &pauline->stat.number_of_LinphoneCallStreamsRunning, 2));
params = linphone_core_create_call_params(marie->lc, outgoing_call);
linphone_call_params_enable_video(params, TRUE);
linphone_core_update_call(marie->lc, outgoing_call, params);
linphone_call_params_unref(params);
wait_for_until(marie->lc, pauline->lc, NULL, 1, 2000);
params = linphone_core_create_call_params(pauline->lc, incoming_call);
linphone_call_params_enable_video(params, TRUE);
linphone_core_accept_call_update(pauline->lc, incoming_call, params);
linphone_call_params_unref(params);
wait_for_until(marie->lc, pauline->lc, NULL, 1, 2000);
linphone_core_terminate_call(pauline->lc, incoming_call);
BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &pauline->stat.number_of_LinphoneCallEnd, 1));
BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &marie->stat.number_of_LinphoneCallReleased, 1));
BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &pauline->stat.number_of_LinphoneCallReleased, 1));
end:
linphone_core_manager_destroy(marie);
linphone_core_manager_destroy(pauline);
}
static void recovered_call_on_network_switch_during_reinvite_4(void) {
LinphoneCall *incoming_call;
LinphoneCall *outgoing_call;
LinphoneCallParams *params;
LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc");
LinphoneCoreManager* pauline = linphone_core_manager_new("pauline_tcp_rc");
configure_video_policies_for_network_switch(marie->lc, pauline->lc);
linphone_core_invite_address(marie->lc, pauline->identity);
if (!BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &pauline->stat.number_of_LinphoneCallIncomingReceived, 1))) goto end;
if (!BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &marie->stat.number_of_LinphoneCallOutgoingRinging, 1))) goto end;
incoming_call = linphone_core_get_current_call(pauline->lc);
linphone_core_accept_call(pauline->lc, incoming_call);
BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &marie->stat.number_of_LinphoneCallStreamsRunning, 1));
BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &pauline->stat.number_of_LinphoneCallStreamsRunning, 1));
outgoing_call = linphone_core_get_current_call(marie->lc);
params = linphone_core_create_call_params(marie->lc, outgoing_call);
linphone_call_params_enable_video(params, TRUE);
linphone_core_update_call(marie->lc, outgoing_call, params);
linphone_call_params_unref(params);
BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &pauline->stat.number_of_LinphoneCallUpdatedByRemote, 1));
params = linphone_core_create_call_params(pauline->lc, incoming_call);
linphone_call_params_enable_video(params, TRUE);
linphone_core_accept_call_update(pauline->lc, incoming_call, params);
linphone_call_params_unref(params);
linphone_core_set_network_reachable(pauline->lc, FALSE);
wait_for(marie->lc, pauline->lc, &pauline->stat.number_of_NetworkReachableFalse, 1);
linphone_core_set_network_reachable(pauline->lc, TRUE);
wait_for(marie->lc, pauline->lc, &pauline->stat.number_of_NetworkReachableTrue, 2);
BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &pauline->stat.number_of_LinphoneRegistrationOk, 2));
BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &marie->stat.number_of_LinphoneCallStreamsRunning, 2));
BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &pauline->stat.number_of_LinphoneCallStreamsRunning, 2));
wait_for_until(marie->lc, pauline->lc, NULL, 1, 2000);
linphone_core_terminate_call(pauline->lc, incoming_call);
BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &pauline->stat.number_of_LinphoneCallEnd, 1));
BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &marie->stat.number_of_LinphoneCallReleased, 1));
BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &pauline->stat.number_of_LinphoneCallReleased, 1));
end:
linphone_core_manager_destroy(marie);
linphone_core_manager_destroy(pauline);
}
static void _call_with_network_switch(bool_t use_ice, bool_t with_socket_refresh, bool_t enable_rtt) {
@ -5073,8 +5342,14 @@ 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 in early state 1", call_with_network_switch_in_early_state_1),
TEST_NO_TAG("Call with network switch in early state 2", call_with_network_switch_in_early_state_2),
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),
TEST_NO_TAG("Recovered call on network switch in early state 4", recovered_call_on_network_switch_in_early_state_4),
TEST_NO_TAG("Recovered call on network switch during re-invite 1", recovered_call_on_network_switch_during_reinvite_1),
TEST_NO_TAG("Recovered call on network switch during re-invite 2", recovered_call_on_network_switch_during_reinvite_2),
TEST_NO_TAG("Recovered call on network switch during re-invite 3", recovered_call_on_network_switch_during_reinvite_3),
TEST_NO_TAG("Recovered call on network switch during re-invite 4", recovered_call_on_network_switch_during_reinvite_4),
TEST_ONE_TAG("Call with network switch and ICE", call_with_network_switch_and_ice, "ICE"),
TEST_ONE_TAG("Call with network switch, ICE and RTT", call_with_network_switch_ice_and_rtt, "ICE"),
TEST_NO_TAG("Call with network switch with socket refresh", call_with_network_switch_and_socket_refresh),