Commit 7f649c56 authored by Simon Morlat's avatar Simon Morlat
Browse files

Merge branch 'master' of git.linphone.org:linphone-private

parents 50d4dbf6 737997cb
......@@ -3,8 +3,10 @@ linphone-3.3.0 -- ?????????
* Internal refactoring of liblinphone (code factorisation, encapsulation
of signaling)
* enhancements made to presence support (SIP/SIMPLE)
linphone-3.2.2 -- ?????????
* new icons
* new tabbed ui
* be nat friendly using OPTIONS request and using received,rport from
responses.
* improve bitrate usage of speex codec
* allow speex to run with vbr (variable bit rate) mode
* add speex/32000 (ultra wide band speex codec)
......
#!/bin/sh
AM_VERSION="1.10"
#AM_VERSION="1.10"
if ! type aclocal-$AM_VERSION 1>/dev/null 2>&1; then
# automake-1.10 (recommended) is not available on Fedora 8
AUTOMAKE=automake
......
dnl Process this file with autoconf to produce a configure script.
AC_INIT([linphone],[3.2.99.1],[linphone-developers@nongnu.org])
AC_INIT([linphone],[3.2.99.4],[linphone-developers@nongnu.org])
AC_CANONICAL_SYSTEM
dnl Source packaging numbers
......
......@@ -267,6 +267,7 @@ static void call_failure(SalOp *op, SalError error, SalReason sr, const char *de
/*char *retrymsg=_("%s. Retry after %i minute(s).");*/
char *msg600=_("User does not want to be disturbed.");
char *msg603=_("Call declined.");
char *msg=NULL;
LinphoneCall *call=lc->call;
if (sal_op_get_user_pointer(op)!=lc->call){
......@@ -280,36 +281,43 @@ static void call_failure(SalOp *op, SalError error, SalReason sr, const char *de
lc->vtable.display_status(lc,_("No response."));
}else if (error==SalErrorProtocol){
if (lc->vtable.display_status)
lc->vtable.display_status(lc, details ? details : _("Error."));
lc->vtable.display_status(lc, details ? details : _("Protocol error."));
}else if (error==SalErrorFailure){
switch(sr){
case SalReasonDeclined:
msg=msg603;
if (lc->vtable.display_status)
lc->vtable.display_status(lc,msg603);
break;
case SalReasonBusy:
msg=msg486;
if (lc->vtable.display_status)
lc->vtable.display_status(lc,msg486);
break;
case SalReasonRedirect:
msg=_("Redirected");
if (lc->vtable.display_status)
lc->vtable.display_status(lc,_("Redirected"));
lc->vtable.display_status(lc,msg);
break;
case SalReasonTemporarilyUnavailable:
msg=msg480;
if (lc->vtable.display_status)
lc->vtable.display_status(lc,msg480);
break;
case SalReasonNotFound:
msg=_("Not found");
if (lc->vtable.display_status)
lc->vtable.display_status(lc,_("Not found"));
lc->vtable.display_status(lc,msg);
break;
case SalReasonDoNotDisturb:
msg=msg600;
if (lc->vtable.display_status)
lc->vtable.display_status(lc,msg600);
break;
case SalReasonMedia:
msg=_("No common codecs");
if (lc->vtable.display_status)
lc->vtable.display_status(lc,_("No common codecs"));
lc->vtable.display_status(lc,msg);
break;
default:
if (lc->vtable.display_status)
......@@ -323,7 +331,8 @@ static void call_failure(SalOp *op, SalError error, SalReason sr, const char *de
linphone_core_stop_media_streams(lc,call);
if (call!=NULL) {
linphone_call_destroy(call);
gstate_new_state(lc, GSTATE_CALL_ERROR, NULL);
if (sr!=SalReasonDeclined) gstate_new_state(lc, GSTATE_CALL_ERROR, msg);
else gstate_new_state(lc, GSTATE_CALL_END, NULL);
lc->call=NULL;
}
}
......
......@@ -84,6 +84,7 @@ static SalMediaDescription *create_local_media_description(LinphoneCore *lc,
md->nstreams=1;
strncpy(md->addr,localip,sizeof(md->addr));
strncpy(md->username,username,sizeof(md->username));
md->bandwidth=linphone_core_get_download_bandwidth(lc);
/*set audio capabilities */
strncpy(md->streams[0].addr,localip,sizeof(md->streams[0].addr));
md->streams[0].port=linphone_core_get_audio_port(lc);
......@@ -715,13 +716,21 @@ static PayloadType * find_payload(RtpProfile *prof, const char *mime_type, int c
it=rtp_profile_get_payload(prof,i);
if (it!=NULL && strcasecmp(mime_type,it->mime_type)==0
&& (clock_rate==it->clock_rate || clock_rate<=0) ){
if ( (recv_fmtp && it->recv_fmtp && strcasecmp(recv_fmtp,it->recv_fmtp)==0) ||
if ( (recv_fmtp && it->recv_fmtp && strstr(recv_fmtp,it->recv_fmtp)!=NULL) ||
(recv_fmtp==NULL && it->recv_fmtp==NULL) ){
/*exact match*/
if (recv_fmtp) payload_type_set_recv_fmtp(it,recv_fmtp);
return it;
}else candidate=it;
}else {
if (candidate){
if (it->recv_fmtp==NULL) candidate=it;
}else candidate=it;
}
}
}
if (candidate && recv_fmtp){
payload_type_set_recv_fmtp(candidate,recv_fmtp);
}
return candidate;
}
......@@ -1161,8 +1170,7 @@ void linphone_core_get_local_ip(LinphoneCore *lc, const char *dest, char *result
strncpy(result,linphone_core_get_nat_address(lc),LINPHONE_IPADDR_SIZE);
return;
}
if (dest==NULL) dest="87.98.157.38"; /*a public IP address*/
if (linphone_core_get_local_ip_for(dest,result)==0)
if (linphone_core_get_local_ip_for(lc->sip_conf.ipv6_enabled ? AF_INET6 : AF_INET,dest,result)==0)
return;
/*else fallback to SAL routine that will attempt to find the most realistic interface */
sal_get_default_local_ip(lc->sal,lc->sip_conf.ipv6_enabled ? AF_INET6 : AF_INET,result,LINPHONE_IPADDR_SIZE);
......@@ -1514,14 +1522,15 @@ static void monitor_network_state(LinphoneCore *lc, time_t curtime){
/* only do the network up checking every five seconds */
if (last_check==0 || (curtime-last_check)>=5){
sal_get_default_local_ip(lc->sal,
lc->sip_conf.ipv6_enabled ? AF_INET6 : AF_INET,
result,LINPHONE_IPADDR_SIZE);
linphone_core_get_local_ip_for(lc->sip_conf.ipv6_enabled ? AF_INET6 : AF_INET,NULL,result);
if (strcmp(result,"::1")!=0 && strcmp(result,"127.0.0.1")!=0){
new_status=TRUE;
}else new_status=FALSE;
last_check=curtime;
if (new_status!=last_status) {
if (new_status){
ms_message("New local ip address is %s",result);
}
set_network_reachable(lc,new_status);
last_status=new_status;
}
......@@ -1842,14 +1851,7 @@ static char *get_fixed_contact(LinphoneCore *lc, LinphoneCall *call , LinphonePr
if (call->op && sal_op_get_contact(call->op)!=NULL){
return NULL;
}
/*if using a proxy, use the contact address as guessed with the REGISTERs*/
if (dest_proxy && dest_proxy->op){
const char *fixed_contact=sal_op_get_contact(dest_proxy->op);
if (fixed_contact) {
ms_message("Contact has been fixed using proxy to %s",fixed_contact);
return ms_strdup(fixed_contact);
}
}
/* if the ping OPTIONS request succeeded use the contact guessed from the
received, rport*/
if (call->ping_op){
......@@ -1859,6 +1861,15 @@ static char *get_fixed_contact(LinphoneCore *lc, LinphoneCall *call , LinphonePr
return ms_strdup(guessed);
}
}
/*if using a proxy, use the contact address as guessed with the REGISTERs*/
if (dest_proxy && dest_proxy->op){
const char *fixed_contact=sal_op_get_contact(dest_proxy->op);
if (fixed_contact) {
ms_message("Contact has been fixed using proxy to %s",fixed_contact);
return ms_strdup(fixed_contact);
}
}
ctt=linphone_core_get_primary_contact_parsed(lc);
......@@ -2147,11 +2158,12 @@ static void post_configure_audio_streams(LinphoneCore *lc){
}
}
static RtpProfile *make_profile(LinphoneCore *lc, const SalStreamDescription *desc, int *used_pt){
static RtpProfile *make_profile(LinphoneCore *lc, const SalMediaDescription *md, const SalStreamDescription *desc, int *used_pt){
int bw;
const MSList *elem;
RtpProfile *prof=rtp_profile_new("Call profile");
bool_t first=TRUE;
int remote_bw=0;
for(elem=desc->payloads;elem!=NULL;elem=elem->next){
PayloadType *pt=(PayloadType*)elem->data;
......@@ -2163,9 +2175,18 @@ static RtpProfile *make_profile(LinphoneCore *lc, const SalStreamDescription *de
*used_pt=payload_type_get_number(pt);
first=FALSE;
}
if (desc->bandwidth>0) remote_bw=desc->bandwidth;
else if (md->bandwidth>0) {
/*case where b=AS is given globally, not per stream*/
remote_bw=md->bandwidth;
if (desc->type==SalVideo){
remote_bw-=lc->audio_bw;
}
}
if (desc->type==SalAudio){
bw=get_min_bandwidth(lc->up_audio_bw,desc->bandwidth);
}else bw=get_min_bandwidth(lc->up_video_bw,desc->bandwidth);
bw=get_min_bandwidth(lc->up_audio_bw,remote_bw);
}else bw=get_min_bandwidth(lc->up_video_bw,remote_bw);
if (bw>0) pt->normal_bitrate=bw*1000;
else if (desc->type==SalAudio){
pt->normal_bitrate=-1;
......@@ -2195,7 +2216,7 @@ void linphone_core_start_media_streams(LinphoneCore *lc, LinphoneCall *call){
const SalStreamDescription *stream=sal_media_description_find_stream(call->resultdesc,
SalProtoRtpAvp,SalAudio);
if (stream){
call->audio_profile=make_profile(lc,stream,&used_pt);
call->audio_profile=make_profile(lc,call->resultdesc,stream,&used_pt);
if (!lc->use_files){
MSSndCard *playcard=lc->sound_conf.play_sndcard;
MSSndCard *captcard=lc->sound_conf.capt_sndcard;
......@@ -2245,7 +2266,7 @@ void linphone_core_start_media_streams(LinphoneCore *lc, LinphoneCall *call){
}
if (stream && (lc->video_conf.display || lc->video_conf.capture)) {
const char *addr=stream->addr[0]!='\0' ? stream->addr : call->resultdesc->addr;
call->video_profile=make_profile(lc,stream,&used_pt);
call->video_profile=make_profile(lc,call->resultdesc,stream,&used_pt);
video_stream_set_sent_video_size(lc->videostream,linphone_core_get_preferred_video_size(lc));
video_stream_enable_self_view(lc->videostream,lc->video_conf.selfview);
if (lc->video_conf.display && lc->video_conf.capture)
......@@ -2323,6 +2344,7 @@ void linphone_core_stop_media_streams(LinphoneCore *lc, LinphoneCall *call){
int linphone_core_accept_call(LinphoneCore *lc, const char *url)
{
LinphoneCall *call=lc->call;
LinphoneProxyConfig *cfg=NULL;
const char *contact=NULL;
if (call==NULL){
......@@ -2341,9 +2363,10 @@ int linphone_core_accept_call(LinphoneCore *lc, const char *url)
ms_message("ring stopped");
lc->ringstream=NULL;
}
linphone_core_get_default_proxy(lc,&cfg);
/*try to be best-effort in giving real local or routable contact address*/
contact=get_fixed_contact(lc,call,NULL);
contact=get_fixed_contact(lc,call,cfg);
if (contact)
sal_op_set_contact(call->op,contact);
......@@ -3559,6 +3582,13 @@ void linphone_core_set_network_reachable(LinphoneCore* lc,bool_t isReachable) {
}
set_network_reachable(lc,isReachable);
}
bool_t linphone_core_is_network_reachabled(LinphoneCore* lc) {
return lc->network_reachable;
}
ortp_socket_t linphone_core_get_sip_socket(LinphoneCore *lc){
return sal_get_socket(lc->sal);
}
/**
* Destroys a LinphoneCore
*
......
......@@ -607,6 +607,8 @@ int linphone_core_get_sip_port(LinphoneCore *lc);
void linphone_core_set_sip_port(LinphoneCore *lc,int port);
ortp_socket_t linphone_core_get_sip_socket(LinphoneCore *lc);
void linphone_core_set_inc_timeout(LinphoneCore *lc, int seconds);
int linphone_core_get_inc_timeout(LinphoneCore *lc);
......@@ -752,6 +754,10 @@ void linphone_core_set_mtu(LinphoneCore *lc, int mtu);
*
*/
void linphone_core_set_network_reachable(LinphoneCore* lc,bool_t value);
/**
* return network state either as positioned by the application or by linphone
*/
bool_t linphone_core_is_network_reachabled(LinphoneCore* lc);
void *linphone_core_get_user_data(LinphoneCore *lc);
......
......@@ -38,6 +38,11 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#undef snprintf
#include <ortp/stun.h>
#ifdef HAVE_GETIFADDRS
#include <net/if.h>
#include <ifaddrs.h>
#endif
#if !defined(WIN32)
......@@ -646,7 +651,40 @@ int linphone_core_wake_up_possible_already_running_instance(
return -1;
}
int linphone_core_get_local_ip_for(const char *dest, char *result){
#ifdef HAVE_GETIFADDRS
#include <ifaddrs.h>
static int get_local_ip_with_getifaddrs(int type, char *address, int size)
{
struct ifaddrs *ifp;
struct ifaddrs *ifpstart;
int ret = 0;
if (getifaddrs(&ifpstart) < 0) {
return -1;
}
for (ifp = ifpstart; ifp != NULL; ifp = ifp->ifa_next) {
if (ifp->ifa_addr && ifp->ifa_addr->sa_family == type
&& (ifp->ifa_flags & IFF_RUNNING) && !(ifp->ifa_flags & IFF_LOOPBACK))
{
getnameinfo(ifp->ifa_addr,
(type == AF_INET6) ?
sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in),
address, size, NULL, 0, NI_NUMERICHOST);
if (strchr(address, '%') == NULL) { /*avoid ipv6 link-local addresses */
/*ms_message("getifaddrs() found %s",address);*/
ret++;
}
}
}
freeifaddrs(ifpstart);
return ret;
}
#endif
static int get_local_ip_for_with_connect(int type, const char *dest, char *result){
int err,tmp;
struct addrinfo hints;
struct addrinfo *res=NULL;
......@@ -656,7 +694,7 @@ int linphone_core_get_local_ip_for(const char *dest, char *result){
socklen_t s;
memset(&hints,0,sizeof(hints));
hints.ai_family=PF_UNSPEC;
hints.ai_family=(type==AF_INET6) ? PF_INET6 : PF_INET;
hints.ai_socktype=SOCK_DGRAM;
/*hints.ai_flags=AI_NUMERICHOST|AI_CANONNAME;*/
err=getaddrinfo(dest,"5060",&hints,&res);
......@@ -705,3 +743,27 @@ int linphone_core_get_local_ip_for(const char *dest, char *result){
ms_message("Local interface to reach %s is %s.",dest,result);
return 0;
}
int linphone_core_get_local_ip_for(int type, const char *dest, char *result){
if (dest==NULL) {
if (type==AF_INET)
dest="87.98.157.38"; /*a public IP address*/
else dest="2a00:1450:8002::68";
}
strcpy(result,type==AF_INET ? "127.0.0.1" : "::1");
#ifdef HAVE_GETIFADDRS
{
int found_ifs;
found_ifs=get_local_ip_with_getifaddrs(type,result,LINPHONE_IPADDR_SIZE);
if (found_ifs==1){
return 0;
}else if (found_ifs<=0){
/*absolutely no network on this machine */
return -1;
}
}
#endif
/*else use connect to find the best local ip address */
return get_local_ip_for_with_connect(type,dest,result);
}
......@@ -164,7 +164,7 @@ LinphoneFriend * linphone_friend_new_from_config_file(struct _LinphoneCore *lc,
void linphone_proxy_config_update(LinphoneProxyConfig *cfg);
void linphone_proxy_config_get_contact(LinphoneProxyConfig *cfg, const char **ip, int *port);
LinphoneProxyConfig * linphone_core_lookup_known_proxy(LinphoneCore *lc, const LinphoneAddress *uri);
int linphone_core_get_local_ip_for(const char *dest, char *result);
int linphone_core_get_local_ip_for(int type, const char *dest, char *result);
LinphoneProxyConfig *linphone_proxy_config_new_from_config_file(struct _LpConfig *config, int index);
void linphone_proxy_config_write_to_config_file(struct _LpConfig* config,LinphoneProxyConfig *obj, int index);
......
......@@ -107,6 +107,7 @@ typedef struct SalMediaDescription{
char addr[64];
char username[64];
int nstreams;
int bandwidth;
SalStreamDescription streams[SAL_MEDIA_DESCRIPTION_MAX_STREAMS];
} SalMediaDescription;
......@@ -223,6 +224,7 @@ typedef struct SalAuthInfo{
void sal_set_callbacks(Sal *ctx, const SalCallbacks *cbs);
int sal_listen_port(Sal *ctx, const char *addr, int port, SalTransport tr, int is_secure);
ortp_socket_t sal_get_socket(Sal *ctx);
void sal_set_user_agent(Sal *ctx, const char *user_agent);
void sal_use_session_timers(Sal *ctx, int expires);
int sal_iterate(Sal *sal);
......
......@@ -23,8 +23,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "sal_eXosip2.h"
#include "offeranswer.h"
/*this function is not declared in some versions of eXosip*/
extern void *eXosip_call_get_reference(int cid);
static void text_received(Sal *sal, eXosip_event_t *ev);
......@@ -44,6 +42,25 @@ void sal_get_default_local_ip(Sal *sal, int address_family,char *ip, size_t iple
}
}
static SalOp * sal_find_call(Sal *sal, int cid){
const MSList *elem;
SalOp *op;
for(elem=sal->calls;elem!=NULL;elem=elem->next){
op=(SalOp*)elem->data;
if (op->cid==cid) return op;
}
return NULL;
}
static void sal_add_call(Sal *sal, SalOp *op){
sal->calls=ms_list_append(sal->calls,op);
}
static void sal_remove_call(Sal *sal, SalOp *op){
sal->calls=ms_list_remove(sal->calls, op);
}
static SalOp * sal_find_register(Sal *sal, int rid){
const MSList *elem;
SalOp *op;
......@@ -164,7 +181,7 @@ void sal_op_release(SalOp *op){
}
if (op->cid!=-1){
ms_message("Cleaning cid %i",op->cid);
eXosip_call_set_reference(op->cid,NULL);
sal_remove_call(op->base.root,op);
}
if (op->sid!=-1){
sal_remove_out_subscribe(op->base.root,op);
......@@ -227,12 +244,14 @@ static void _osip_trace_func(char *fi, int li, osip_trace_level_t level, char *c
Sal * sal_init(){
static bool_t firsttime=TRUE;
Sal *sal;
if (firsttime){
osip_trace_initialize_func (OSIP_INFO4,&_osip_trace_func);
firsttime=FALSE;
}
eXosip_init();
return ms_new0(Sal,1);
sal=ms_new0(Sal,1);
return sal;
}
void sal_uninit(Sal* sal){
......@@ -295,8 +314,10 @@ int sal_listen_port(Sal *ctx, const char *addr, int port, SalTransport tr, int i
bool_t ipv6;
int proto=IPPROTO_UDP;
if (ctx->running) eXosip_quit();
eXosip_init();
if (ctx->running){
eXosip_quit();
eXosip_init();
}
err=0;
eXosip_set_option(13,&err); /*13=EXOSIP_OPT_SRV_WITH_NAPTR, as it is an enum value, we can't use it unless we are sure of the
version of eXosip, which is not the case*/
......@@ -308,11 +329,23 @@ int sal_listen_port(Sal *ctx, const char *addr, int port, SalTransport tr, int i
ms_fatal("SIP over TCP or TLS or DTLS is not supported yet.");
return -1;
}
err=eXosip_listen_addr(proto, addr, port, ipv6 ? PF_INET6 : PF_INET, 0);
#ifdef HAVE_EXOSIP_GET_SOCKET
ms_message("Exosip has socket number %i",eXosip_get_socket(proto));
#endif
ctx->running=TRUE;
return err;
}
ortp_socket_t sal_get_socket(Sal *ctx){
#ifdef HAVE_EXOSIP_GET_SOCKET
return eXosip_get_socket(IPPROTO_UDP);
#else
ms_warning("Sorry, eXosip does not have eXosip_get_socket() method");
return -1;
#endif
}
void sal_set_user_agent(Sal *ctx, const char *user_agent){
eXosip_set_user_agent(user_agent);
}
......@@ -337,6 +370,7 @@ static int extract_received_rport(osip_message_t *msg, const char **received, in
rport=param->gvalue;
if (rport && rport[0]!='\0') *rportval=atoi(rport);
else *rportval=5060;
*received=via->host;
}
param=NULL;
osip_via_param_get_byname(via,"received",&param);
......@@ -381,6 +415,7 @@ static void sdp_process(SalOp *h){
offer_answer_initiate_incoming(h->base.local_media,h->base.remote_media,h->result);
h->sdp_answer=media_description_to_sdp(h->result);
strcpy(h->result->addr,h->base.remote_media->addr);
h->result->bandwidth=h->base.remote_media->bandwidth;
for(i=0;i<h->result->nstreams;++i){
if (h->result->streams[i].port>0){
strcpy(h->result->streams[i].addr,h->base.remote_media->streams[i].addr);
......@@ -413,6 +448,7 @@ int sal_call(SalOp *h, const char *from, const char *to){
ms_error("Could not create call.");
return -1;
}
osip_message_set_allow(invite, "INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY, MESSAGE, SUBSCRIBE, INFO");
if (h->base.contact){
_osip_list_set_empty(&invite->contacts,(void (*)(void*))osip_contact_free);
osip_message_set_contact(invite,h->base.contact);
......@@ -433,7 +469,7 @@ int sal_call(SalOp *h, const char *from, const char *to){
ms_error("Fail to send invite !");
return -1;
}else{
eXosip_call_set_reference(h->cid,h);
sal_add_call(h->base.root,h);
}
return 0;
}
......@@ -588,8 +624,9 @@ int sal_call_send_dtmf(SalOp *h, char dtmf){
int sal_call_terminate(SalOp *h){
eXosip_lock();
eXosip_call_terminate(h->cid,h->did);
eXosip_call_set_reference(h->cid,NULL);
eXosip_unlock();
sal_remove_call(h->base.root,h);
h->cid=-1;
return 0;
}
......@@ -630,11 +667,7 @@ static void set_network_origin(SalOp *op, osip_message_t *req){
static SalOp *find_op(Sal *sal, eXosip_event_t *ev){
if (ev->cid>0){
#ifdef HAVE_EXOSIP_GET_REF
return (SalOp*)eXosip_call_get_ref(ev->cid);
#else
return (SalOp*)eXosip_call_get_reference(ev->cid);
#endif
return sal_find_call(sal,ev->cid);
}
if (ev->rid>0){
return sal_find_register(sal,ev->rid);
......@@ -684,7 +717,7 @@ static void inc_new_call(Sal *sal, eXosip_event_t *ev){
op->cid=ev->cid;
op->did=ev->did;
eXosip_call_set_reference(op->cid,op);
sal_add_call(op->base.root,op);
sal->callbacks.call_received(op);
}
......@@ -797,9 +830,9 @@ static int call_proceeding(Sal *sal, eXosip_event_t *ev){
static void call_ringing(Sal *sal, eXosip_event_t *ev){
sdp_message_t *sdp;
SalOp *op;
SalOp *op=find_op(sal,ev);
if (call_proceeding(sal, ev)==-1) return;
op=(SalOp*)ev->external_reference;
sdp=eXosip_get_sdp_info(ev->response);
if (sdp){
op->base.remote_media=sal_media_description_new();
......@@ -840,22 +873,25 @@ static void call_accepted(Sal *sal, eXosip_event_t *ev){
}
static void call_terminated(Sal *sal, eXosip_event_t *ev){
char *from;
char *from=NULL;
SalOp *op=find_op(sal,ev);
if (op==NULL){
ms_warning("Call terminated for already closed call ?");
return;
}
osip_from_to_str(ev->request->from,&from);
eXosip_call_set_reference(ev->cid,NULL);
if (ev->request){
osip_from_to_str(ev->request->from,&from);
}
sal_remove_call(sal,op);
op->cid=-1;
sal->callbacks.call_terminated(op,from);
osip_free(from);
sal->callbacks.call_terminated(op,from!=NULL ? from : sal_op_get_from(op));
if (from) osip_free(from);
}
static void call_released<