Merge remote-tracking branch 'origin/dev_loc'

This commit is contained in:
Simon Morlat 2017-04-13 16:51:26 +02:00
commit d2925edca5
14 changed files with 723 additions and 40 deletions

View file

@ -510,6 +510,7 @@ static int is_media_description_acceptable(SalMediaDescription *md){
static SalReason process_sdp_for_invite(SalOp* op,belle_sip_request_t* invite) {
belle_sdp_session_description_t* sdp;
SalReason reason = SalReasonNone;
SalErrorInfo sei;
if (extract_sdp(op,BELLE_SIP_MESSAGE(invite),&sdp,&reason)==0) {
if (sdp){
@ -525,7 +526,10 @@ static SalReason process_sdp_for_invite(SalOp* op,belle_sip_request_t* invite) {
}
if (reason != SalReasonNone){
sal_call_decline(op,reason,NULL);
sal_error_info_init_to_null(&sei);
sal_error_info_set(&sei, reason,"SIP", 0, NULL, NULL);
sal_call_decline_with_error_info(op, &sei,NULL);
}
return reason;
}
@ -943,6 +947,17 @@ int sal_call_accept(SalOp*h){
return 0;
}
static belle_sip_header_reason_t *sal_call_make_reason_header( const SalErrorInfo *info){
if (info != NULL){
belle_sip_header_reason_t* reason = BELLE_SIP_HEADER_REASON(belle_sip_header_reason_new());
belle_sip_header_reason_set_text(reason, info->status_string);
belle_sip_header_reason_set_protocol(reason,info->protocol);
belle_sip_header_reason_set_cause(reason,info->protocol_code);
return reason;
}
return NULL;
}
int sal_call_decline(SalOp *op, SalReason reason, const char *redirection /*optional*/){
belle_sip_response_t* response;
belle_sip_header_contact_t* contact=NULL;
@ -971,6 +986,41 @@ int sal_call_decline(SalOp *op, SalReason reason, const char *redirection /*opti
return 0;
}
int sal_call_decline_with_error_info(SalOp *op, const SalErrorInfo *info, const char *redirection /*optional*/){
belle_sip_response_t* response;
belle_sip_header_contact_t* contact=NULL;
int status = info->protocol_code;
belle_sip_transaction_t *trans;
if (info->reason==SalReasonRedirect){
if (redirection!=NULL) {
if (strstr(redirection,"sip:")!=0) status=302;
else status=380;
contact= belle_sip_header_contact_new();
belle_sip_header_address_set_uri(BELLE_SIP_HEADER_ADDRESS(contact),belle_sip_uri_parse(redirection));
} else {
ms_error("Cannot redirect to null");
}
}
trans=(belle_sip_transaction_t*)op->pending_server_trans;
if (!trans) trans=(belle_sip_transaction_t*)op->pending_update_server_trans;
if (!trans){
ms_error("sal_call_decline_with_error_info(): no pending transaction to decline.");
return -1;
}
response = sal_op_create_response_from_request(op,belle_sip_transaction_get_request(trans),status);
belle_sip_header_reason_t* reason_header = sal_call_make_reason_header(info->sub_sei);
if (reason_header) {
belle_sip_message_add_header(BELLE_SIP_MESSAGE(response),BELLE_SIP_HEADER(reason_header));
}
if (contact) {
belle_sip_message_add_header(BELLE_SIP_MESSAGE(response),BELLE_SIP_HEADER(contact));
}
belle_sip_server_transaction_send_response(BELLE_SIP_SERVER_TRANSACTION(trans),response);
return 0;
}
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;
@ -1040,7 +1090,18 @@ int sal_call_send_dtmf(SalOp *h, char dtmf){
return 0;
}
int sal_call_terminate(SalOp *op){
int sal_call_terminate_with_error(SalOp *op, const SalErrorInfo *info){
SalErrorInfo sei;
const SalErrorInfo *p_sei;
if (info == NULL){
sal_error_info_init_to_null(&sei);
sal_error_info_set(&sei,SalReasonDeclined, "SIP", 0, NULL, NULL);
p_sei = &sei;
} else{
p_sei = info;
}
belle_sip_dialog_state_t dialog_state=op->dialog?belle_sip_dialog_get_state(op->dialog):BELLE_SIP_DIALOG_NULL;
if (op->state==SalOpStateTerminating || op->state==SalOpStateTerminated) {
ms_error("Cannot terminate op [%p] in state [%s]",op,sal_op_state_to_string(op->state));
@ -1048,13 +1109,19 @@ int sal_call_terminate(SalOp *op){
}
switch(dialog_state) {
case BELLE_SIP_DIALOG_CONFIRMED: {
sal_op_send_request(op,belle_sip_dialog_create_request(op->dialog,"BYE"));
belle_sip_request_t * req = belle_sip_dialog_create_request(op->dialog,"BYE");
if (info != NULL){
belle_sip_header_reason_t* reason = sal_call_make_reason_header(info);
belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(reason));
}
sal_op_send_request(op,req);
op->state=SalOpStateTerminating;
break;
}
case BELLE_SIP_DIALOG_NULL: {
if (op->dir == SalOpDirIncoming) {
sal_call_decline(op, SalReasonDeclined,NULL);
sal_call_decline_with_error_info(op, p_sei, NULL);
op->state=SalOpStateTerminated;
} else if (op->pending_client_trans){
if (belle_sip_transaction_get_state(BELLE_SIP_TRANSACTION(op->pending_client_trans)) == BELLE_SIP_TRANSACTION_PROCEEDING){
@ -1071,7 +1138,7 @@ int sal_call_terminate(SalOp *op){
}
case BELLE_SIP_DIALOG_EARLY: {
if (op->dir == SalOpDirIncoming) {
sal_call_decline(op, SalReasonDeclined,NULL);
sal_call_decline_with_error_info(op, p_sei,NULL);
op->state=SalOpStateTerminated;
} else {
cancelling_invite(op);
@ -1086,6 +1153,12 @@ int sal_call_terminate(SalOp *op){
return 0;
}
int sal_call_terminate(SalOp *op){
return sal_call_terminate_with_error(op, NULL);
}
bool_t sal_call_autoanswer_asked(SalOp *op){
return op->auto_answer_asked;
}

View file

@ -561,11 +561,22 @@ const SalErrorInfo *sal_error_info_none(void){
"Ok",
200,
NULL,
NULL
NULL,
};
return &none;
}
void sal_error_info_init_to_null(SalErrorInfo *sei){
sei->status_string = NULL;
sei->full_string = NULL;
sei->protocol = NULL;
sei->sub_sei = NULL;
sei->warnings = NULL;
sei->protocol_code=0;
sei->reason=SalReasonNone;
}
void sal_error_info_reset(SalErrorInfo *ei){
if (ei->status_string){
ms_free(ei->status_string);
@ -584,14 +595,23 @@ void sal_error_info_reset(SalErrorInfo *ei){
ms_free(ei->protocol);
ei->protocol = NULL;
}
if (ei->sub_sei){
ms_free(ei->sub_sei);
ei->sub_sei = NULL;
}
ei->protocol_code=0;
ei->reason=SalReasonNone;
}
void sal_error_info_set(SalErrorInfo *ei, SalReason reason, const char *protocol, int code, const char *status_string, const char *warning){
sal_error_info_reset(ei);
if (reason==SalReasonUnknown && strcmp(protocol, "SIP") == 0) ei->reason=_sal_reason_from_sip_code(code);
else ei->reason=reason;
if (reason==SalReasonUnknown && strcmp(protocol, "SIP") == 0 && code != 0) ei->reason=_sal_reason_from_sip_code(code);
else{
ei->reason=reason;
if (code == 0) {
code = sal_reason_to_sip_code(reason);
}
}
ei->protocol_code=code;
ei->status_string=status_string ? ms_strdup(status_string) : NULL;
ei->warnings=warning ? ms_strdup(warning) : NULL;
@ -606,7 +626,7 @@ void sal_error_info_set(SalErrorInfo *ei, SalReason reason, const char *protocol
void sal_op_set_reason_error_info(SalOp *op, belle_sip_message_t *msg){
belle_sip_header_reason_t* reason_header = belle_sip_message_get_header_by_type(msg,belle_sip_header_reason_t);
if (reason_header){
SalErrorInfo *ei=&op->reason_error_info;
SalErrorInfo *ei=&op->reason_error_info; // ?//
const char *protocol = belle_sip_header_reason_get_protocol(reason_header);
int code = belle_sip_header_reason_get_cause(reason_header);
const char *text = belle_sip_header_reason_get_text(reason_header);
@ -623,6 +643,7 @@ void sal_op_set_error_info_from_response(SalOp *op, belle_sip_response_t *respon
warnings=warning ? belle_sip_header_get_unparsed_value(warning) : NULL;
sal_error_info_set(ei,SalReasonUnknown,"SIP", code,reason_phrase,warnings);
sal_op_set_reason_error_info(op, BELLE_SIP_MESSAGE(response));
}
const SalErrorInfo *sal_op_get_error_info(const SalOp *op){
@ -633,6 +654,9 @@ const SalErrorInfo * sal_op_get_reason_error_info(const SalOp *op){
return &op->reason_error_info;
}
static void unlink_op_with_dialog(SalOp *op, belle_sip_dialog_t* dialog){
belle_sip_dialog_set_application_data(dialog,NULL);
sal_op_unref(op);

View file

@ -269,6 +269,7 @@ static void call_received(SalOp *h){
LinphoneAddress *from_address_to_search_if_me=NULL; /*address used to know if I'm the caller*/
SalMediaDescription *md;
const char * p_asserted_id;
SalErrorInfo sei;
LinphoneErrorInfo *ei = NULL;
/* Look if this INVITE is for a call that has already been notified but broken because of network failure */
@ -306,10 +307,12 @@ static void call_received(SalOp *h){
case LinphonePresenceActivityPermanentAbsence:
alt_contact = linphone_presence_model_get_contact(lc->presence_model);
if (alt_contact != NULL) {
sal_call_decline(h,SalReasonRedirect,alt_contact);
sal_error_info_init_to_null(&sei);
sal_error_info_set(&sei,SalReasonRedirect, "SIP", 0, NULL, NULL);
sal_call_decline_with_error_info(h, &sei,alt_contact);
ms_free(alt_contact);
ei = linphone_error_info_new();
linphone_error_info_set(ei, LinphoneReasonMovedPermanently, 302, "Moved permanently", NULL);
linphone_error_info_set(ei, NULL, LinphoneReasonMovedPermanently, 302, "Moved permanently", NULL);
linphone_core_report_early_failed_call(lc, LinphoneCallIncoming, from_addr, to_addr, ei);
sal_op_release(h);
return;
@ -324,7 +327,7 @@ static void call_received(SalOp *h){
if (!linphone_core_can_we_add_call(lc)){/*busy*/
sal_call_decline(h,SalReasonBusy,NULL);
ei = linphone_error_info_new();
linphone_error_info_set(ei, LinphoneReasonBusy, 486, "Busy - too many calls", NULL);
linphone_error_info_set(ei, NULL, LinphoneReasonBusy, 486, "Busy - too many calls", NULL);
linphone_core_report_early_failed_call(lc, LinphoneCallIncoming, from_addr, to_addr, ei);
sal_op_release(h);
return;
@ -344,7 +347,7 @@ static void call_received(SalOp *h){
ms_warning("Receiving a call while one with same address [%s] is initiated, refusing this one with busy message.",addr);
sal_call_decline(h,SalReasonBusy,NULL);
ei = linphone_error_info_new();
linphone_error_info_set(ei, LinphoneReasonBusy, 486, "Busy - duplicated call", NULL);
linphone_error_info_set(ei, NULL, LinphoneReasonBusy, 486, "Busy - duplicated call", NULL);
linphone_core_report_early_failed_call(lc, LinphoneCallIncoming, from_addr, to_addr, ei);
sal_op_release(h);
linphone_address_unref(from_address_to_search_if_me);
@ -362,7 +365,7 @@ static void call_received(SalOp *h){
if (md){
if (sal_media_description_empty(md) || linphone_core_incompatible_security(lc,md)){
ei = linphone_error_info_new();
linphone_error_info_set(ei, LinphoneReasonNotAcceptable, 488, "Not acceptable here", NULL);
linphone_error_info_set(ei, NULL, LinphoneReasonNotAcceptable, 488, "Not acceptable here", NULL);
linphone_core_report_early_failed_call(lc, LinphoneCallIncoming, linphone_address_ref(from_addr), linphone_address_ref(to_addr), ei);
sal_call_decline(call->op,SalReasonNotAcceptable,NULL);
linphone_call_unref(call);
@ -698,6 +701,7 @@ static void call_updated_by_remote(LinphoneCore *lc, LinphoneCall *call){
/* this callback is called when an incoming re-INVITE/ SIP UPDATE modifies the session*/
static void call_updated(LinphoneCore *lc, LinphoneCall *call, SalOp *op, bool_t is_update){
SalErrorInfo sei;
SalMediaDescription *rmd=sal_call_get_remote_media_description(op);
call->defer_update = lp_config_get_int(lc->config, "sip", "defer_update_default", FALSE);
@ -735,7 +739,9 @@ static void call_updated(LinphoneCore *lc, LinphoneCall *call, SalOp *op, bool_t
case LinphoneCallUpdating:
case LinphoneCallPausing:
case LinphoneCallResuming:
sal_call_decline(call->op,SalReasonInternalError,NULL);
sal_error_info_init_to_null(&sei);
sal_error_info_set(&sei,SalReasonInternalError, "SIP", 0, NULL, NULL);
sal_call_decline_with_error_info(call->op, &sei,NULL);
/*no break*/
case LinphoneCallIdle:
case LinphoneCallOutgoingInit:
@ -757,7 +763,8 @@ static void call_updating(SalOp *op, bool_t is_update){
LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(op);
SalMediaDescription *rmd=sal_call_get_remote_media_description(op);
SalErrorInfo sei;
if (!call) {
ms_error("call_updating(): call doesn't exist anymore");
return ;
@ -768,7 +775,7 @@ static void call_updating(SalOp *op, bool_t is_update){
if (rmd == NULL && lp_config_get_int(call->core->config,"sip","sdp_200_ack_follow_video_policy",0)) {
LinphoneCallParams *p=linphone_core_create_call_params(lc, NULL);
ms_message("Applying default policy for offering SDP on call [%p]",call);
linphone_call_set_new_params(call, p);
_linphone_call_set_new_params(call, p);
linphone_call_params_unref(p);
}
linphone_call_make_local_media_description(call);
@ -787,14 +794,18 @@ static void call_updating(SalOp *op, bool_t is_update){
md=sal_call_get_final_media_description(call->op);
if (md && (sal_media_description_empty(md) || linphone_core_incompatible_security(lc,md))){
sal_call_decline(call->op,SalReasonNotAcceptable,NULL);
sal_error_info_init_to_null(&sei);
sal_error_info_set(&sei,SalReasonNotAcceptable, "SIP", 0, NULL, NULL);
sal_call_decline_with_error_info(call->op, &sei,NULL);
return;
}
if (is_update && prev_result_desc && md){
int diff=sal_media_description_equals(prev_result_desc,md);
if (diff & (SAL_MEDIA_DESCRIPTION_CRYPTO_POLICY_CHANGED|SAL_MEDIA_DESCRIPTION_STREAMS_CHANGED)){
ms_warning("Cannot accept this update, it is changing parameters that require user approval");
sal_call_decline(call->op,SalReasonNotAcceptable,NULL); /*FIXME should send 504 Cannot change the session parameters without prompting the user"*/
sal_error_info_init_to_null(&sei);
sal_error_info_set(&sei,SalReasonUnknown, "SIP", 504, "Cannot change the session parameters without prompting the user", NULL);
sal_call_decline_with_error_info(call->op, &sei,NULL);
return;
}
}
@ -838,7 +849,7 @@ static void call_terminated(SalOp *op, const char *from){
break;
case LinphoneCallIncomingReceived:
case LinphoneCallIncomingEarlyMedia:
linphone_error_info_set(call->ei, LinphoneReasonNotAnswered, 0, "Incoming call cancelled", NULL);
linphone_error_info_set(call->ei,NULL, LinphoneReasonNotAnswered, 0, "Incoming call cancelled", NULL);
call->non_op_error = TRUE;
break;
default:

View file

@ -31,6 +31,7 @@ static void error_info_destroy(LinphoneErrorInfo *ei){
}
static void error_info_clone(LinphoneErrorInfo *ei, const LinphoneErrorInfo *other){
linphone_error_info_set_reason(ei, linphone_error_info_get_reason(other));
ei->protocol = bctbx_strdup(other->protocol);
ei->phrase = bctbx_strdup(other->phrase);
ei->warnings = bctbx_strdup(other->warnings);
@ -214,10 +215,29 @@ void linphone_error_info_from_sal_op(LinphoneErrorInfo *ei, const SalOp *op){
}
}
void linphone_error_info_set(LinphoneErrorInfo *ei, LinphoneReason reason, int code, const char *status_string, const char *warning){
LinphoneErrorInfo* linphone_error_info_get_sub(const LinphoneErrorInfo *ei){
return ei->sub_ei;
}
void linphone_error_info_set_sub_error_info(LinphoneErrorInfo *ei, LinphoneErrorInfo *appended_ei){
if (appended_ei != NULL){
ei->sub_ei = linphone_error_info_ref(appended_ei);
}
}
void linphone_error_info_set(LinphoneErrorInfo *ei, const char *protocol, LinphoneReason reason, int code, const char *status_string, const char *warning){
linphone_error_info_reset(ei);
ei->reason = reason;
ei->protocol_code = code;
if (protocol != NULL){
ei->protocol = bctbx_strdup(protocol);
}
else{
const char* prot = "SIP";
ei->protocol = bctbx_strdup(prot);
}
ei->phrase = bctbx_strdup(status_string);
ei->warnings = bctbx_strdup(warning);
}

View file

@ -52,6 +52,7 @@ struct _LinphoneFactory {
char *cached_ring_resources_dir;
char *cached_image_resources_dir;
char *cached_msplugins_dir;
LinphoneErrorInfo* ei;
};
static void linphone_factory_uninit(LinphoneFactory *obj){
@ -209,3 +210,9 @@ const char * linphone_factory_get_msplugins_dir(LinphoneFactory *factory) {
void linphone_factory_set_msplugins_dir(LinphoneFactory *factory, const char *path) {
STRING_SET(factory->msplugins_dir, path);
}
LinphoneErrorInfo *linphone_factory_create_error_info(LinphoneFactory *factory){
return linphone_error_info_new();
}

View file

@ -4419,7 +4419,7 @@ static void linphone_call_lost(LinphoneCall *call){
ms_message("LinphoneCall [%p]: %s", call, temp);
linphone_core_notify_display_warning(lc, temp);
call->non_op_error = TRUE;
linphone_error_info_set(call->ei, LinphoneReasonIOError, 503, "Media lost", NULL);
linphone_error_info_set(call->ei,NULL, LinphoneReasonIOError, 503, "Media lost", NULL);
linphone_call_terminate(call);
linphone_core_play_named_tone(lc, LinphoneToneCallLost);
ms_free(temp);
@ -4813,13 +4813,29 @@ LinphonePlayer *linphone_call_get_player(LinphoneCall *call){
return call->player;
}
void linphone_call_set_new_params(LinphoneCall *call, const LinphoneCallParams *params){
void linphone_call_set_params(LinphoneCall *call, const LinphoneCallParams *params){
if ( call->state == LinphoneCallOutgoingInit || call->state == LinphoneCallIncomingReceived){
_linphone_call_set_new_params(call, params);
}
else {
ms_error("linphone_call_set_params() invalid state %s to call this function", linphone_call_state_to_string(call->state));
}
}
void _linphone_call_set_new_params(LinphoneCall *call, const LinphoneCallParams *params){
LinphoneCallParams *cp=NULL;
if (params) cp=linphone_call_params_copy(params);
if (call->params) linphone_call_params_unref(call->params);
call->params=cp;
}
const LinphoneCallParams * linphone_call_get_params(LinphoneCall *call){
return call->params;
}
static int send_dtmf_handler(void *data, unsigned int revents){
LinphoneCall *call = (LinphoneCall*)data;
/*By default we send DTMF RFC2833 if we do not have enabled SIP_INFO but we can also send RFC2833 and SIP_INFO*/
@ -5141,10 +5157,70 @@ int linphone_call_terminate(LinphoneCall *call) {
return 0;
}
static void linphone_error_info_fields_to_sal(const LinphoneErrorInfo* ei, SalErrorInfo* sei){
sei->reason = linphone_error_info_get_reason(ei);
sei->status_string = bctbx_strdup(ei->phrase);
sei->full_string = bctbx_strdup(ei->full_string);
sei->warnings = bctbx_strdup(ei->warnings);
sei->protocol_code = ei->protocol_code;
sei->protocol = bctbx_strdup(ei->protocol);
}
static void linphone_error_info_to_sal(const LinphoneErrorInfo* ei, SalErrorInfo* sei){
linphone_error_info_fields_to_sal(ei, sei);
if (ei->sub_ei !=NULL) {
linphone_error_info_to_sal(ei->sub_ei, sei->sub_sei);
}
}
int linphone_call_terminate_with_error_info(LinphoneCall *call , const LinphoneErrorInfo *ei){
SalErrorInfo sei ;
sal_error_info_init_to_null(&sei);
LinphoneErrorInfo* p_ei = (LinphoneErrorInfo*) ei;
ms_message("Terminate call [%p] which is currently in state %s", call, linphone_call_state_to_string(call->state));
switch (call->state) {
case LinphoneCallReleased:
case LinphoneCallEnd:
case LinphoneCallError:
ms_warning("No need to terminate a call [%p] in state [%s]", call, linphone_call_state_to_string(call->state));
return -1;
case LinphoneCallIncomingReceived:
case LinphoneCallIncomingEarlyMedia:
linphone_error_info_set_reason(p_ei, LinphoneReasonDeclined);
return linphone_call_decline_with_error_info(call, p_ei);
case LinphoneCallOutgoingInit:
/* In state OutgoingInit, op has to be destroyed */
sal_op_release(call->op);
call->op = NULL;
break;
default:
if (ei == NULL){
sal_call_terminate(call->op);
}
else{
linphone_error_info_to_sal(ei, &sei);
sal_call_terminate_with_error(call->op, &sei);
sal_error_info_reset(&sei);
}
break;
}
terminate_call(call);
return 0;
}
int linphone_call_redirect(LinphoneCall *call, const char *redirect_uri) {
char *real_url = NULL;
LinphoneCore *lc;
LinphoneAddress *real_parsed_url;
SalErrorInfo sei;
if (call->state != LinphoneCallIncomingReceived) {
ms_error("Bad state for call redirection.");
@ -5160,9 +5236,11 @@ int linphone_call_redirect(LinphoneCall *call, const char *redirect_uri) {
}
real_url = linphone_address_as_string(real_parsed_url);
sal_call_decline(call->op, SalReasonRedirect, real_url);
sal_error_info_init_to_null(&sei);
sal_error_info_set(&sei,SalReasonRedirect, "SIP", 0, NULL, NULL);
sal_call_decline_with_error_info(call->op, &sei, real_url);
ms_free(real_url);
linphone_error_info_set(call->ei, LinphoneReasonMovedPermanently, 302, "Call redirected", NULL);
linphone_error_info_set(call->ei, NULL, LinphoneReasonMovedPermanently, 302, "Call redirected", NULL);
call->non_op_error = TRUE;
terminate_call(call);
linphone_address_unref(real_parsed_url);
@ -5174,12 +5252,29 @@ int linphone_call_decline(LinphoneCall * call, LinphoneReason reason) {
ms_error("Cannot decline a call that is in state %s", linphone_call_state_to_string(call->state));
return -1;
}
sal_call_decline(call->op, linphone_reason_to_sal(reason), NULL);
terminate_call(call);
return 0;
}
int linphone_call_decline_with_error_info(LinphoneCall * call, const LinphoneErrorInfo *ei) {
SalErrorInfo sei;
sal_error_info_init_to_null(&sei);
SalErrorInfo sub_sei;
sal_error_info_init_to_null(&sub_sei);
sei.sub_sei = &sub_sei;
if ((call->state != LinphoneCallIncomingReceived) && (call->state != LinphoneCallIncomingEarlyMedia)) {
ms_error("Cannot decline a call that is in state %s", linphone_call_state_to_string(call->state));
return -1;
}
linphone_error_info_to_sal(ei, &sei);
sal_call_decline_with_error_info(call->op, &sei , NULL);
terminate_call(call);
return 0;
}
int linphone_call_accept(LinphoneCall *call) {
return linphone_call_accept_with_params(call, NULL);
}
@ -5248,7 +5343,7 @@ int linphone_call_accept_with_params(LinphoneCall *call, const LinphoneCallParam
/* Try to be best-effort in giving real local or routable contact address */
linphone_call_set_contact_op(call);
if (params) {
linphone_call_set_new_params(call, params);
_linphone_call_set_new_params(call, params);
linphone_call_prepare_ice(call, TRUE);
linphone_call_make_local_media_description(call);
sal_call_set_local_media_description(call->op, call->localdesc);
@ -5304,7 +5399,7 @@ int linphone_call_accept_early_media_with_params(LinphoneCall *call, const Linph
/* If parameters are passed, update the media description */
if (params) {
linphone_call_set_new_params(call, params);
_linphone_call_set_new_params(call, params);
linphone_call_make_local_media_description(call);
sal_call_set_local_media_description(call->op, call->localdesc);
sal_op_set_sent_custom_header(call->op, params->custom_headers);
@ -5377,7 +5472,7 @@ int linphone_call_update(LinphoneCall *call, const LinphoneCallParams *params) {
}
}
#endif /* defined(VIDEO_ENABLED) && defined(BUILD_UPNP) */
linphone_call_set_new_params(call, params);
_linphone_call_set_new_params(call, params);
err = linphone_call_prepare_ice(call, FALSE);
if (err == 1) {
ms_message("Defer call update to gather ICE candidates");
@ -5525,7 +5620,7 @@ int _linphone_call_accept_update(LinphoneCall *call, const LinphoneCallParams *p
linphone_call_params_enable_video_multicast(call->params, FALSE);
}
} else {
linphone_call_set_new_params(call, params);
_linphone_call_set_new_params(call, params);
}
if (call->params->has_video && !linphone_core_video_enabled(lc)) {
@ -5774,6 +5869,7 @@ void linphone_call_reinvite_to_recover_from_connection_loss(LinphoneCall *call)
}
void linphone_call_repair_if_broken(LinphoneCall *call){
SalErrorInfo sei;
if (!call->broken) return;
if (!call->core->media_network_reachable) return;
@ -5803,7 +5899,9 @@ void linphone_call_repair_if_broken(LinphoneCall *call){
break;
case LinphoneCallUpdatedByRemote:
if (sal_call_dialog_request_pending(call->op)) {
sal_call_decline(call->op, SalReasonServiceUnavailable, NULL);
sal_error_info_init_to_null(&sei);
sal_error_info_set(&sei, SalReasonServiceUnavailable,"SIP", 0, NULL, NULL);
sal_call_decline_with_error_info(call->op, &sei,NULL);
}
linphone_call_reinvite_to_recover_from_connection_loss(call);
break;

View file

@ -3081,7 +3081,7 @@ void linphone_core_iterate(LinphoneCore *lc){
decline_reason = (lc->current_call != call) ? LinphoneReasonBusy : LinphoneReasonDeclined;
call->log->status=LinphoneCallMissed;
call->non_op_error = TRUE;
linphone_error_info_set(call->ei, decline_reason, linphone_reason_to_error_code(decline_reason), "Not answered", NULL);
linphone_error_info_set(call->ei, NULL, decline_reason, linphone_reason_to_error_code(decline_reason), "Not answered", NULL);
linphone_call_decline(call, decline_reason);
}
}

View file

@ -410,7 +410,9 @@ void linphone_call_notify_info_message_received(LinphoneCall *call, const Linpho
LinphoneCall * linphone_call_new_outgoing(struct _LinphoneCore *lc, LinphoneAddress *from, LinphoneAddress *to, const LinphoneCallParams *params, LinphoneProxyConfig *cfg);
LinphoneCall * linphone_call_new_incoming(struct _LinphoneCore *lc, LinphoneAddress *from, LinphoneAddress *to, SalOp *op);
void linphone_call_set_new_params(LinphoneCall *call, const LinphoneCallParams *params);
void _linphone_call_set_new_params(LinphoneCall *call, const LinphoneCallParams *params);
void linphone_call_set_params(LinphoneCall *call, const LinphoneCallParams *params);
const LinphoneCallParams * linphone_call_get_params(LinphoneCall *call);
void linphone_call_set_state(LinphoneCall *call, LinphoneCallState cstate, const char *message);
void linphone_call_set_contact_op(LinphoneCall* call);
void linphone_call_set_compatible_incoming_call_parameters(LinphoneCall *call, SalMediaDescription *md);
@ -1783,8 +1785,6 @@ void linphone_core_notify_display_status(LinphoneCore *lc, const char *message);
void linphone_core_notify_display_message(LinphoneCore *lc, const char *message);
void linphone_core_notify_display_warning(LinphoneCore *lc, const char *message);
void linphone_core_notify_display_url(LinphoneCore *lc, const char *message, const char *url);
void linphone_core_notify_notify_presence_received(LinphoneCore *lc, LinphoneFriend * lf);
void linphone_core_notify_notify_presence_received_for_uri_or_tel(LinphoneCore *lc, LinphoneFriend *lf, const char *uri_or_tel, const LinphonePresenceModel *presence_model);
void linphone_core_notify_new_subscription_requested(LinphoneCore *lc, LinphoneFriend *lf, const char *url);
void linphone_core_notify_auth_info_requested(LinphoneCore *lc, const char *realm, const char *username, const char *domain);
void linphone_core_notify_authentication_requested(LinphoneCore *lc, LinphoneAuthInfo *auth_info, LinphoneAuthMethod method);

View file

@ -203,9 +203,12 @@ LINPHONE_PUBLIC int linphone_call_take_preview_snapshot(LinphoneCall *call, cons
**/
LINPHONE_PUBLIC LinphoneReason linphone_call_get_reason(const LinphoneCall *call);
/**
* Returns full details about call errors or termination reasons.
**/
* @param call LinphoneCall object on which we want the information error
* @return LinphoneErrorInfo object holding the reason error.
*/
LINPHONE_PUBLIC const LinphoneErrorInfo *linphone_call_get_error_info(const LinphoneCall *call);
/**
@ -376,8 +379,16 @@ LINPHONE_PUBLIC int linphone_call_resume(LinphoneCall *call);
* Terminates a call.
* @param[in] call LinphoneCall object
* @return 0 on success, -1 on failure
**/LINPHONE_PUBLIC int linphone_call_terminate(LinphoneCall *call);
/**
* Terminates a call.
* @param[in] call LinphoneCall object
* @param[in] ei LinphoneErrorInfo
* @return 0 on success, -1 on failure
**/
LINPHONE_PUBLIC int linphone_call_terminate(LinphoneCall *call);
LINPHONE_PUBLIC int linphone_call_terminate_with_error_info(LinphoneCall *call, const LinphoneErrorInfo *ei);
/**
* Redirect the specified call to the given redirect URI.
@ -395,6 +406,14 @@ LINPHONE_PUBLIC int linphone_call_redirect(LinphoneCall *call, const char *redir
**/
LINPHONE_PUBLIC int linphone_call_decline(LinphoneCall * call, LinphoneReason reason);
/**
* Decline a pending incoming call, with a LinphoneErrorInfo object.
* @param[in] call A LinphoneCall object that must be in the IncomingReceived state
* @param[in] ei LinphoneErrorInfo containing more information on the call rejection.
* @return 0 on success, -1 on failure
*/
LINPHONE_PUBLIC int linphone_call_decline_with_error_info(LinphoneCall * call, const LinphoneErrorInfo *ei);
/**
* Accept an incoming call.
*

View file

@ -4885,6 +4885,28 @@ LINPHONE_PUBLIC LinphonePresencePerson * linphone_core_create_presence_person(Li
* @return The created #LinphonePresenceService object.
*/
LINPHONE_PUBLIC LinphonePresenceService * linphone_core_create_presence_service(LinphoneCore *lc, const char *id, LinphonePresenceBasicStatus basic_status, const char *contact);
/**
* Notifies the upper layer that a presence status has been received by calling the appropriate
* callback if one has been set.
* @param[in] lc the #LinphoneCore object.
* @param[in] lf the #LinphoneFriend whose presence information has been received.
*/
LINPHONE_PUBLIC void linphone_core_notify_notify_presence_received(LinphoneCore *lc, LinphoneFriend *lf);
/**
* Notifies the upper layer that a presence model change has been received for the uri or
* telephone number given as a parameter, by calling the appropriate callback if one has been set.
* @param[in] lc the #LinphoneCore object.
* @param[in] lf the #LinphoneFriend whose presence information has been received.
* @param[in] uri_or_tel telephone number or sip uri
* @param[in] presence_model the #LinphonePresenceModel that has been modified
*/
LINPHONE_PUBLIC void linphone_core_notify_notify_presence_received_for_uri_or_tel(LinphoneCore *lc, LinphoneFriend *lf, const char *uri_or_tel, const LinphonePresenceModel *presence_model);
/**
* @}

View file

@ -62,6 +62,13 @@ LINPHONE_PUBLIC void linphone_error_info_unref(LinphoneErrorInfo *ei);
**/
LINPHONE_PUBLIC LinphoneReason linphone_error_info_get_reason(const LinphoneErrorInfo *ei);
/**
* Get pointer to chained LinphoneErrorInfo set in sub_ei.
* @param ei ErrorInfo object
* @return LinphoneErrorInfo pointer defined in the ei object.
*/
LINPHONE_PUBLIC LinphoneErrorInfo* linphone_error_info_get_sub(const LinphoneErrorInfo *ei);
/**
* Get textual phrase from the error info.
* This is the text that is provided by the peer in the protocol (SIP).
@ -69,6 +76,13 @@ LINPHONE_PUBLIC LinphoneReason linphone_error_info_get_reason(const LinphoneErro
* @return The error phrase
**/
LINPHONE_PUBLIC const char * linphone_error_info_get_phrase(const LinphoneErrorInfo *ei);
/**
* Get protocol from the error info.
* @param[in] ei ErrorInfo object
* @return The protocol
*/
LINPHONE_PUBLIC const char *linphone_error_info_get_protocol(const LinphoneErrorInfo *ei);
/**
* Provides additional information regarding the failure.
@ -88,10 +102,28 @@ LINPHONE_PUBLIC int linphone_error_info_get_protocol_code(const LinphoneErrorInf
/**
* Assign information to a LinphoneErrorInfo object.
* @param[in] ei ErrorInfo object
* @param[in] ei ErrorInfo object
* @param[in] protocol protocol name
* @param[in] reason reason from LinphoneReason enum
* @param[in] code protocol code
* @param[in] status_string description of the reason
* @param[in] warning warning message
*/
LINPHONE_PUBLIC void linphone_error_info_set(LinphoneErrorInfo *ei, LinphoneReason reason, int code, const char *status_string, const char *warning);
LINPHONE_PUBLIC void linphone_error_info_set(LinphoneErrorInfo *ei, const char *protocol, LinphoneReason reason, int code, const char *status_string, const char *warning);
/**
* Set the sub_ei in LinphoneErrorInfo to another LinphoneErrorInfo.
* Used when there is more than one reason header.
* @param[in] ei LinphoneErrorInfo object to which the other LinphoneErrorInfo will be appended as ei->sub_ei.
* @param[in] appended_ei LinphoneErrorInfo to append
*/
LINPHONE_PUBLIC void linphone_error_info_set_sub_error_info(LinphoneErrorInfo *ei, LinphoneErrorInfo *appended_ei);
/**
* Assign reason LinphoneReason to a LinphoneErrorUnfo object.
* @param[in] ei ErrorInfo object
* @param[in] reason reason from LinphoneReason enum
*/
LINPHONE_PUBLIC void linphone_error_info_set_reason(LinphoneErrorInfo *ei, LinphoneReason reason);
/**

View file

@ -210,6 +210,12 @@ LINPHONE_PUBLIC const char * linphone_factory_get_msplugins_dir(LinphoneFactory
*/
LINPHONE_PUBLIC void linphone_factory_set_msplugins_dir(LinphoneFactory *factory, const char *path);
/**
* Creates an object LinphoneErrorInfo.
* @param[in] factory LinphoneFactory object
* @return LinphoneErrorInfo object.
*/
LINPHONE_PUBLIC LinphoneErrorInfo *linphone_factory_create_error_info(LinphoneFactory *factory);
/**
* @}
*/

View file

@ -412,6 +412,7 @@ typedef struct SalErrorInfo{
char *warnings;
char *protocol;
char *full_string; /*concatenation of status_string + warnings*/
struct SalErrorInfo *sub_sei;
}SalErrorInfo;
typedef enum SalPresenceStatus{
@ -730,6 +731,7 @@ const SalErrorInfo *sal_error_info_none(void);
LINPHONE_PUBLIC const SalErrorInfo *sal_op_get_error_info(const SalOp *op);
const SalErrorInfo *sal_op_get_reason_error_info(const SalOp *op);
void sal_error_info_reset(SalErrorInfo *ei);
void sal_error_info_init_to_null(SalErrorInfo *sei);
void sal_error_info_set(SalErrorInfo *ei, SalReason reason, const char *protocol, int code, const char *status_string, const char *warning);
/*entity tag used for publish (see RFC 3903)*/
@ -745,6 +747,7 @@ int sal_call_notify_ringing(SalOp *h, bool_t early_media);
/*accept an incoming call or, during a call accept a reINVITE*/
int sal_call_accept(SalOp*h);
int sal_call_decline(SalOp *h, SalReason reason, const char *redirection /*optional*/);
int sal_call_decline_with_error_info(SalOp *h, const SalErrorInfo* info, 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);
@ -758,6 +761,7 @@ int sal_call_set_referer(SalOp *h, SalOp *refered_call);
SalOp *sal_call_get_replaces(SalOp *h);
int sal_call_send_dtmf(SalOp *h, char dtmf);
int sal_call_terminate(SalOp *h);
int sal_call_terminate_with_error(SalOp *op, const SalErrorInfo *info);
bool_t sal_call_autoanswer_asked(SalOp *op);
void sal_call_send_vfu_request(SalOp *h);
int sal_call_is_offerer(const SalOp *h);

View file

@ -980,6 +980,59 @@ static void simple_call_compatibility_mode(void) {
linphone_core_manager_destroy(pauline);
}
static void terminate_call_with_error(void) {
LinphoneCall* call_callee ;
LinphoneErrorInfo *ei ;
const LinphoneErrorInfo *rei ;
LinphoneCoreManager *callee_mgr = linphone_core_manager_new("marie_rc");
LinphoneCoreManager *caller_mgr = linphone_core_manager_new(transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc");
LinphoneCall* out_call = linphone_core_invite_address(caller_mgr->lc,callee_mgr->identity);
linphone_call_ref(out_call);
ei = linphone_error_info_new();
linphone_error_info_set(ei, NULL, LinphoneReasonNone, 200, "Call completed elsewhere", NULL);
BC_ASSERT_TRUE(wait_for(caller_mgr->lc, callee_mgr->lc, &caller_mgr->stat.number_of_LinphoneCallOutgoingInit,1));
BC_ASSERT_TRUE(wait_for(caller_mgr->lc, callee_mgr->lc, &callee_mgr->stat.number_of_LinphoneCallIncomingReceived, 1));
BC_ASSERT_TRUE(wait_for(caller_mgr->lc, callee_mgr->lc, &caller_mgr->stat.number_of_LinphoneCallOutgoingProgress, 1));
call_callee = linphone_core_get_current_call(callee_mgr->lc);
BC_ASSERT_PTR_NOT_NULL(call_callee);
BC_ASSERT_EQUAL( linphone_core_accept_call(callee_mgr->lc,call_callee), 0 , int, "%d");
BC_ASSERT_TRUE(wait_for(caller_mgr->lc,callee_mgr->lc,&caller_mgr->stat.number_of_LinphoneCallConnected,1));
BC_ASSERT_TRUE(wait_for(caller_mgr->lc, callee_mgr->lc, &caller_mgr->stat.number_of_LinphoneCallStreamsRunning, 1));
rei = ei;
linphone_call_terminate_with_error_info(out_call,rei);
BC_ASSERT_TRUE(wait_for(caller_mgr->lc,callee_mgr->lc,&caller_mgr->stat.number_of_LinphoneCallEnd,1));
BC_ASSERT_PTR_NOT_NULL(rei);
if (rei){
BC_ASSERT_EQUAL(linphone_error_info_get_protocol_code(rei),200, int, "%d");
BC_ASSERT_PTR_NOT_NULL(linphone_error_info_get_phrase(rei));
BC_ASSERT_STRING_EQUAL(linphone_error_info_get_phrase(rei), "Call completed elsewhere");
BC_ASSERT_STRING_EQUAL(linphone_error_info_get_protocol(ei), "SIP");
}
BC_ASSERT_EQUAL(caller_mgr->stat.number_of_LinphoneCallEnd,1, int, "%d");
BC_ASSERT_TRUE(wait_for(caller_mgr->lc,callee_mgr->lc,&caller_mgr->stat.number_of_LinphoneCallReleased,1));
linphone_error_info_unref(ei);
linphone_call_unref(out_call);
linphone_core_manager_destroy(callee_mgr);
linphone_core_manager_destroy(caller_mgr);
}
static void cancelled_call(void) {
LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc");
@ -1136,6 +1189,62 @@ static void call_busy_when_calling_self(void) {
linphone_core_manager_destroy(marie);
}
static void call_declined_with_error(void) {
LinphoneCoreManager* callee_mgr = linphone_core_manager_new("marie_rc");
LinphoneCoreManager* caller_mgr = linphone_core_manager_new(transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc");
LinphoneCall* in_call = NULL;
LinphoneCall* out_call = linphone_core_invite_address(caller_mgr->lc,callee_mgr->identity);
LinphoneFactory* factory = linphone_factory_get();
const LinphoneErrorInfo* rcvd_ei;
const LinphoneErrorInfo* sub_rcvd_ei;
LinphoneErrorInfo *ei = linphone_factory_create_error_info(factory);
LinphoneErrorInfo *reason_ei = linphone_factory_create_error_info(factory);
linphone_error_info_set(ei, "SIP", LinphoneReasonUnknown, 603, "Decline", NULL); //ordre des arguments à vérifier
linphone_error_info_set(reason_ei, "hardware", LinphoneReasonUnknown, 66, "J'ai plus de batterie", NULL);
linphone_error_info_set_sub_error_info(ei, reason_ei);
BC_ASSERT_TRUE(wait_for(caller_mgr->lc,callee_mgr->lc,&callee_mgr->stat.number_of_LinphoneCallIncomingReceived,1));
BC_ASSERT_PTR_NOT_NULL(in_call=linphone_core_get_current_call(callee_mgr->lc));
linphone_call_ref(out_call);
BC_ASSERT_TRUE(wait_for(caller_mgr->lc,callee_mgr->lc,&callee_mgr->stat.number_of_LinphoneCallIncomingReceived,1));
BC_ASSERT_PTR_NOT_NULL(in_call=linphone_core_get_current_call(callee_mgr->lc));
if (in_call) {
linphone_call_ref(in_call);
linphone_call_decline_with_error_info(in_call, ei);
BC_ASSERT_TRUE(wait_for(caller_mgr->lc,callee_mgr->lc,&callee_mgr->stat.number_of_LinphoneCallEnd,1));
BC_ASSERT_TRUE(wait_for(callee_mgr->lc,caller_mgr->lc,&caller_mgr->stat.number_of_LinphoneCallEnd,1));
rcvd_ei = linphone_call_get_error_info(out_call);
sub_rcvd_ei = linphone_error_info_get_sub(rcvd_ei);
BC_ASSERT_STRING_EQUAL(linphone_error_info_get_phrase(rcvd_ei), "Decline");
BC_ASSERT_STRING_EQUAL(linphone_error_info_get_protocol(rcvd_ei), "SIP");
BC_ASSERT_STRING_EQUAL(linphone_error_info_get_phrase(sub_rcvd_ei), "J'ai plus de batterie");
BC_ASSERT_STRING_EQUAL(linphone_error_info_get_protocol(sub_rcvd_ei), "hardware");
BC_ASSERT_EQUAL(linphone_call_get_reason(in_call),LinphoneReasonDeclined, int, "%d");
BC_ASSERT_EQUAL(linphone_call_log_get_status(linphone_call_get_call_log(in_call)),LinphoneCallDeclined, int, "%d");
BC_ASSERT_EQUAL(linphone_call_get_reason(out_call),LinphoneReasonDeclined, int, "%d");
BC_ASSERT_EQUAL(linphone_call_log_get_status(linphone_call_get_call_log(out_call)),LinphoneCallDeclined, int, "%d");
BC_ASSERT_TRUE(wait_for(caller_mgr->lc,callee_mgr->lc,&callee_mgr->stat.number_of_LinphoneCallReleased,1));
BC_ASSERT_TRUE(wait_for(caller_mgr->lc,callee_mgr->lc,&caller_mgr->stat.number_of_LinphoneCallReleased,1));
linphone_call_unref(in_call);
}
linphone_call_unref(out_call);
linphone_error_info_unref(reason_ei);
linphone_error_info_unref(ei);
linphone_core_manager_destroy(callee_mgr);
linphone_core_manager_destroy(caller_mgr);
}
static void call_declined(void) {
LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc");
@ -1523,6 +1632,260 @@ static void call_with_custom_sdp_attributes(void) {
linphone_core_manager_destroy(pauline);
}
static void call_with_custom_header_or_sdp_cb(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState cstate, const char *message) {
const char *value;
if (cstate == LinphoneCallOutgoingInit){
LinphoneCallParams *params = linphone_call_params_copy(linphone_call_get_params(call));
linphone_call_params_add_custom_sdp_attribute(params, "working", "maybe");
linphone_call_set_params(call, params);
linphone_call_params_unref(params);
}
else if (cstate == LinphoneCallIncomingReceived){
const LinphoneCallParams *tparams = linphone_call_get_remote_params(call);
LinphoneCallParams *params = linphone_call_params_copy(tparams);
//Check received params
//SDP
value = linphone_call_params_get_custom_sdp_attribute(params, "working");
BC_ASSERT_PTR_NOT_NULL(value);
if (value) BC_ASSERT_STRING_EQUAL(value, "maybe");
//header
value = linphone_call_params_get_custom_header(params, "weather");
BC_ASSERT_PTR_NOT_NULL(value);
if (value) BC_ASSERT_STRING_EQUAL(value, "thunderstorm");
//modify SDP
linphone_call_params_add_custom_sdp_attribute(params, "working", "yes");
linphone_call_set_params(call, params);
linphone_call_params_unref(params);
}
}
static void call_caller_with_custom_header_or_sdp_attributes(void) {
LinphoneCoreManager *callee_mgr = linphone_core_manager_new("marie_rc");
LinphoneCoreManager *caller_mgr = linphone_core_manager_new(transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc");
LinphoneCall *call_caller = NULL, *call_callee = NULL;
LinphoneCallParams *caller_params; // *callee_params ;
LinphoneCoreVTable *vtable;
LinphoneCallTestParams caller_test_params = {0};
LinphoneCallTestParams callee_test_params = {0};
stats initial_caller=caller_mgr->stat;
stats initial_callee=callee_mgr->stat;
bool_t result=FALSE;
bool_t did_receive_call;
//Create caller params with custom header and custom SDP
caller_params = linphone_core_create_call_params(caller_mgr->lc, NULL);
linphone_call_params_add_custom_header(caller_params, "weather", "thunderstorm");
linphone_call_params_add_custom_sdp_media_attribute(caller_params, LinphoneStreamTypeAudio, "sleeping", "almost");
caller_test_params.base = (LinphoneCallParams*)caller_params;
callee_test_params.base = NULL;
/* TODO: This should be handled correctly inside the liblinphone library but meanwhile handle this here. */
linphone_core_manager_wait_for_stun_resolution(caller_mgr);
linphone_core_manager_wait_for_stun_resolution(callee_mgr);
setup_sdp_handling(&caller_test_params, caller_mgr);
setup_sdp_handling(&callee_test_params, callee_mgr);
// Assign dedicated callback to vtable for caller and callee
vtable = linphone_core_v_table_new();
vtable->call_state_changed = call_with_custom_header_or_sdp_cb;
linphone_core_add_listener(callee_mgr->lc, vtable);
linphone_core_add_listener(caller_mgr->lc, vtable);
//Caller initates the call with INVITE
// caller params not null
BC_ASSERT_PTR_NOT_NULL((call_caller=linphone_core_invite_address_with_params(caller_mgr->lc,callee_mgr->identity,caller_params)));
BC_ASSERT_PTR_NULL(linphone_call_get_remote_params(call_caller)); /*assert that remote params are NULL when no response is received yet*/
// Wait for Incoming received
did_receive_call = wait_for(callee_mgr->lc
,caller_mgr->lc
,&callee_mgr->stat.number_of_LinphoneCallIncomingReceived
,initial_callee.number_of_LinphoneCallIncomingReceived+1);
BC_ASSERT_EQUAL(did_receive_call, !callee_test_params.sdp_simulate_error, int, "%d");
linphone_call_params_unref(caller_params);
sal_default_set_sdp_handling(caller_mgr->lc->sal, SalOpSDPNormal);
sal_default_set_sdp_handling(callee_mgr->lc->sal, SalOpSDPNormal);
// Wait for Outgoing Progress
if (linphone_core_get_calls_nb(callee_mgr->lc)<=1)
BC_ASSERT_TRUE(linphone_core_inc_invite_pending(callee_mgr->lc));
BC_ASSERT_EQUAL(caller_mgr->stat.number_of_LinphoneCallOutgoingProgress,initial_caller.number_of_LinphoneCallOutgoingProgress+1, int, "%d");
LinphoneCallParams *default_params=linphone_core_create_call_params(callee_mgr->lc,call_callee);
ms_message("Created default call params with video=%i", linphone_call_params_video_enabled(default_params));
linphone_core_accept_call_with_params(callee_mgr->lc,call_callee,default_params);
linphone_call_params_unref(default_params);
BC_ASSERT_TRUE(wait_for(callee_mgr->lc,caller_mgr->lc,&callee_mgr->stat.number_of_LinphoneCallConnected,initial_callee.number_of_LinphoneCallConnected+1));
BC_ASSERT_TRUE(wait_for(callee_mgr->lc,caller_mgr->lc,&caller_mgr->stat.number_of_LinphoneCallConnected,initial_caller.number_of_LinphoneCallConnected+1));
result = wait_for_until(callee_mgr->lc,caller_mgr->lc,&caller_mgr->stat.number_of_LinphoneCallStreamsRunning,initial_caller.number_of_LinphoneCallStreamsRunning+1, 2000)
&&
wait_for_until(callee_mgr->lc,caller_mgr->lc,&callee_mgr->stat.number_of_LinphoneCallStreamsRunning,initial_callee.number_of_LinphoneCallStreamsRunning+1, 2000);
caller_params = linphone_core_create_call_params(caller_mgr->lc, call_caller);
linphone_call_params_clear_custom_sdp_attributes(caller_params);
linphone_call_params_clear_custom_sdp_media_attributes(caller_params, LinphoneStreamTypeAudio);
linphone_call_params_add_custom_sdp_attribute(caller_params, "weather", "sunny");
linphone_core_update_call(caller_mgr->lc, call_caller, caller_params);
linphone_call_params_unref(caller_params);
end_call(caller_mgr, callee_mgr);
linphone_core_manager_destroy(callee_mgr);
linphone_core_manager_destroy(caller_mgr);
}
static void call_callee_with_custom_header_or_sdp_cb(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState cstate, const char *message) {
const char *value;
if (cstate == LinphoneCallOutgoingInit){
LinphoneCallParams *params = linphone_call_params_copy(linphone_call_get_params(call));
linphone_call_params_add_custom_sdp_attribute(params, "working", "maybe");
linphone_call_set_params(call, params);
linphone_call_params_unref(params);
}
else if (cstate == LinphoneCallIncomingReceived){
const LinphoneCallParams *tparams = linphone_call_get_remote_params(call);
LinphoneCallParams *params = linphone_call_params_copy(tparams);
value = linphone_call_params_get_custom_sdp_attribute(params, "working");
BC_ASSERT_PTR_NOT_NULL(value);
if (value) BC_ASSERT_STRING_EQUAL(value, "maybe");
linphone_call_set_params(call, params);
linphone_call_params_unref(params);
}
}
static void call_callee_with_custom_header_or_sdp_attributes(void) {
int result;
LinphoneCoreManager *callee_mgr = linphone_core_manager_new("marie_rc");
LinphoneCoreManager *caller_mgr = linphone_core_manager_new(transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc");
LinphoneCall *call_caller = NULL, *call_callee = NULL;
LinphoneCallParams *callee_params, *caller_params ;
LinphoneCoreVTable *vtable;
const char *value;
LinphoneCallTestParams caller_test_params = {0};
LinphoneCallTestParams callee_test_params = {0};
stats initial_caller=caller_mgr->stat;
stats initial_callee=callee_mgr->stat;
bool_t did_receive_call;
const LinphoneCallParams *caller_remote_params;
caller_params = linphone_core_create_call_params(caller_mgr->lc, NULL);
callee_test_params.base = NULL;
caller_test_params.base = NULL;
/* TODO: This should be handled correctly inside the liblinphone library but meanwhile handle this here. */
linphone_core_manager_wait_for_stun_resolution(caller_mgr);
linphone_core_manager_wait_for_stun_resolution(callee_mgr);
setup_sdp_handling(&caller_test_params, caller_mgr);
setup_sdp_handling(&callee_test_params, callee_mgr);
// Assign dedicated callback to vtable for caller and callee
vtable = linphone_core_v_table_new();
vtable->call_state_changed = call_callee_with_custom_header_or_sdp_cb;
linphone_core_add_listener(callee_mgr->lc, vtable);
linphone_core_add_listener(caller_mgr->lc, vtable);
//Caller initates the call with INVITE
// caller params not null
BC_ASSERT_PTR_NOT_NULL((call_caller=linphone_core_invite_address_with_params(caller_mgr->lc,callee_mgr->identity,caller_params)));
BC_ASSERT_PTR_NULL(linphone_call_get_remote_params(call_caller)); /*assert that remote params are NULL when no response is received yet*/
// Wait for Incoming received
did_receive_call = wait_for(callee_mgr->lc
,caller_mgr->lc
,&callee_mgr->stat.number_of_LinphoneCallIncomingReceived
,initial_callee.number_of_LinphoneCallIncomingReceived+1);
BC_ASSERT_EQUAL(did_receive_call, !callee_test_params.sdp_simulate_error, int, "%d");
sal_default_set_sdp_handling(caller_mgr->lc->sal, SalOpSDPNormal);
sal_default_set_sdp_handling(callee_mgr->lc->sal, SalOpSDPNormal);
// Wait for Outgoing Progress
if (linphone_core_get_calls_nb(callee_mgr->lc)<=1)
BC_ASSERT_TRUE(linphone_core_inc_invite_pending(callee_mgr->lc));
BC_ASSERT_EQUAL(caller_mgr->stat.number_of_LinphoneCallOutgoingProgress,initial_caller.number_of_LinphoneCallOutgoingProgress+1, int, "%d");
//Create callee params with custom header and custom SDP
callee_params = linphone_core_create_call_params(callee_mgr->lc,call_callee);
linphone_call_params_add_custom_header(callee_params, "weather", "thunderstorm");
linphone_call_params_add_custom_sdp_media_attribute(callee_params, LinphoneStreamTypeAudio, "sleeping", "almost");
linphone_call_params_add_custom_sdp_attribute(callee_params, "working", "yes");
ms_message("Created default call params with video=%i", linphone_call_params_video_enabled(callee_params));
linphone_core_accept_call_with_params(callee_mgr->lc,call_callee,callee_params);
linphone_call_params_unref(callee_params);
BC_ASSERT_TRUE(wait_for(callee_mgr->lc,caller_mgr->lc,&callee_mgr->stat.number_of_LinphoneCallConnected,initial_callee.number_of_LinphoneCallConnected+1));
BC_ASSERT_TRUE(wait_for(callee_mgr->lc,caller_mgr->lc,&caller_mgr->stat.number_of_LinphoneCallConnected,initial_caller.number_of_LinphoneCallConnected+1));
result = wait_for_until(callee_mgr->lc,caller_mgr->lc,&caller_mgr->stat.number_of_LinphoneCallStreamsRunning,initial_caller.number_of_LinphoneCallStreamsRunning+1, 2000)
&&
wait_for_until(callee_mgr->lc,caller_mgr->lc,&callee_mgr->stat.number_of_LinphoneCallStreamsRunning,initial_callee.number_of_LinphoneCallStreamsRunning+1, 2000);
caller_remote_params = linphone_call_get_remote_params(call_caller);
value = linphone_call_params_get_custom_sdp_attribute(caller_remote_params, "working");
BC_ASSERT_PTR_NOT_NULL(value);
if (value) BC_ASSERT_STRING_EQUAL(value, "yes");
//header
value = linphone_call_params_get_custom_header(caller_remote_params, "weather");
BC_ASSERT_PTR_NOT_NULL(value);
if (value) BC_ASSERT_STRING_EQUAL(value, "thunderstorm");
linphone_call_params_unref(caller_params);
end_call(caller_mgr, callee_mgr);
linphone_core_manager_destroy(callee_mgr);
linphone_core_manager_destroy(caller_mgr);
}
void call_paused_resumed_base(bool_t multicast, bool_t with_losses) {
LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc");
LinphoneCoreManager* pauline = linphone_core_manager_new(transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc");
@ -5462,6 +5825,7 @@ static void call_with_network_reachable_down_in_callback(void){
test_t call_tests[] = {
TEST_NO_TAG("Early declined call", early_declined_call),
TEST_NO_TAG("Call declined", call_declined),
TEST_NO_TAG("Call declined with error", call_declined_with_error),
TEST_NO_TAG("Cancelled call", cancelled_call),
TEST_NO_TAG("Early cancelled call", early_cancelled_call),
TEST_NO_TAG("Call with DNS timeout", call_with_dns_time_out),
@ -5535,6 +5899,8 @@ test_t call_tests[] = {
TEST_ONE_TAG("Call with ICE added by reINVITE", ice_added_by_reinvite, "ICE"),
TEST_NO_TAG("Call with custom headers", call_with_custom_headers),
TEST_NO_TAG("Call with custom SDP attributes", call_with_custom_sdp_attributes),
TEST_NO_TAG("Call caller with custom header or sdp", call_caller_with_custom_header_or_sdp_attributes),
TEST_NO_TAG("Call callee with custom header or sdp", call_callee_with_custom_header_or_sdp_attributes),
TEST_NO_TAG("Call established with rejected INFO", call_established_with_rejected_info),
TEST_NO_TAG("Call established with rejected RE-INVITE", call_established_with_rejected_reinvite),
TEST_NO_TAG("Call established with rejected incoming RE-INVITE", call_established_with_rejected_incoming_reinvite),
@ -5602,7 +5968,8 @@ test_t call_tests[] = {
TEST_NO_TAG("Call with ZRTP configured receiver side only", call_with_zrtp_configured_callee_side),
TEST_NO_TAG("Call from plain RTP to ZRTP mandatory should be silent", call_from_plain_rtp_to_zrtp),
TEST_NO_TAG("Call ZRTP mandatory to plain RTP should be silent", call_from_zrtp_to_plain_rtp),
TEST_NO_TAG("Call with network reachable down in callback", call_with_network_reachable_down_in_callback)
TEST_NO_TAG("Call with network reachable down in callback", call_with_network_reachable_down_in_callback),
TEST_NO_TAG("Call terminated with reason", terminate_call_with_error)
};
test_suite_t call_test_suite = {"Single Call", NULL, NULL, liblinphone_tester_before_each, liblinphone_tester_after_each,