From 39ff61f8038890a24b1ffe83374061eceeb9714e Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Mon, 11 Jan 2010 18:40:04 +0100 Subject: [PATCH 01/50] SAL (signaling abstraction layer) in progress. --- linphone/coreapi/Makefile.am | 3 + linphone/coreapi/offeranswer.c | 142 ++++++++++++++++++++++++ linphone/coreapi/offeranswer.h | 47 ++++++++ linphone/coreapi/sal.h | 104 ++++++++++++++++++ linphone/coreapi/sal_eXosip2.c | 153 ++++++++++++++++++++++++++ linphone/coreapi/sal_eXosip2_sdp.c | 170 +++++++++++++++++++++++++++++ 6 files changed, 619 insertions(+) create mode 100644 linphone/coreapi/offeranswer.c create mode 100644 linphone/coreapi/offeranswer.h create mode 100644 linphone/coreapi/sal.h create mode 100644 linphone/coreapi/sal_eXosip2.c create mode 100644 linphone/coreapi/sal_eXosip2_sdp.c diff --git a/linphone/coreapi/Makefile.am b/linphone/coreapi/Makefile.am index c0a28ade3..7c3827f29 100644 --- a/linphone/coreapi/Makefile.am +++ b/linphone/coreapi/Makefile.am @@ -16,6 +16,9 @@ lib_LTLIBRARIES=liblinphone.la liblinphone_la_SOURCES=\ linphonecore.c linphonecore.h private.h\ exevents.c exevents.h \ + offeranswer.c offeranswer.h\ + sal_eXosip2.c sal.h \ + sal_eXosip2_sdp.c \ misc.c \ address.c \ enum.c enum.h \ diff --git a/linphone/coreapi/offeranswer.c b/linphone/coreapi/offeranswer.c new file mode 100644 index 000000000..03c134143 --- /dev/null +++ b/linphone/coreapi/offeranswer.c @@ -0,0 +1,142 @@ +/* +linphone +Copyright (C) 2010 Simon MORLAT (simon.morlat@free.fr) + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "sal.h" +#include "offeranswer.h" + + +static PayloadType * find_payload_type_best_match(const MSList *l, const PayloadType *refpt){ + PayloadType *pt; + char value[10]; + const MSList *elem; + PayloadType *candidate=NULL; + + for (elem=l;elem!=NULL;elem=elem->next){ + pt=(PayloadType*)elem->data; + if (strcasecmp(pt->mime_type,refpt->mime_type)==0 && pt->clock_rate==refpt->clock_rate){ + candidate=pt; + /*good candidate, check fmtp for H264 */ + if (strcasecmp(pt->mime_type,"H264")==0){ + if (pt->recv_fmtp!=NULL && refpt->recv_fmtp!=NULL){ + int mode1=0,mode2=0; + if (fmtp_get_value(pt->recv_fmtp,"packetization-mode",value,sizeof(value))){ + mode1=atoi(value); + } + if (fmtp_get_value(refpt->recv_fmtp,"packetization-mode",value,sizeof(value))){ + mode2=atoi(value); + } + if (mode1==mode2) + break; /*exact match */ + } + }else break; + } + } + return candidate; +} + +static MSList *match_payloads(const MSList *local, const MSList *remote){ + const MSList *e2; + MSList *res=NULL; + PayloadType *matched; + for(e2=remote;e2!=NULL;e2=e2->next){ + PayloadType *p2=(PayloadType*)e2->data; + matched=find_payload_type_best_match(local,p2); + if (matched){ + matched=payload_type_clone(matched); + if (p2->recv_fmtp) + payload_type_set_send_fmtp(matched,p2->recv_fmtp); + res=ms_list_append(res,matched); + payload_type_set_number(matched,payload_type_get_number(p2)); + }else{ + ms_message("No match for %s/%i",p2->mime_type,p2->clock_rate); + } + } + return res; +} + +static bool_t only_telephone_event(const MSList *l){ + for(;l!=NULL;l=l->next){ + PayloadType *p=(PayloadType*)l->data; + if (strcasecmp(p->mime_type,"telephone-event")!=0){ + return FALSE; + } + } + return TRUE; +} + +static void initiate_outgoing(const SalStreamDescription *local_offer, + const SalStreamDescription *remote_answer, + SalStreamDescription *result){ + result->payloads=match_payloads(local_offer->payloads,remote_answer->payloads); + if (result->payloads && !only_telephone_event(result->payloads)){ + result->port=remote_answer->port; + result->bandwidth=remote_answer->bandwidth; + result->ptime=remote_answer->ptime; + }else{ + result->port=0; + } +} + + +static void initiate_incoming(const SalStreamDescription *local_cap, + const SalStreamDescription *remote_offer, + SalStreamDescription *result){ + result->payloads=match_payloads(local_cap->payloads,remote_offer->payloads); + if (result->payloads && !only_telephone_event(result->payloads)){ + result->port=remote_offer->port; + result->bandwidth=remote_offer->bandwidth; + result->ptime=remote_offer->ptime; + }else{ + result->port=0; + } +} + +/** + * Returns a media description to run the streams with, based on a local offer + * and the returned response (remote). +**/ +int offer_answer_initiate_outgoing(const SalMediaDescription *local_offer, + const SalMediaDescription *remote_answer, + SalMediaDescription *result){ + int i; + for(i=0;instreams;++i){ + initiate_outgoing(&local_offer->streams[i],&remote_answer->streams[i],&result->streams[i]); + } + result->nstreams=local_offer->nstreams; + strcpy(result->addr,remote_answer->addr); + return 0; +} + +/** + * Returns a media description to run the streams with, based on the local capabilities and + * and the received offer. + * The returned media description is an answer and should be sent to the offerer. +**/ +int offer_answer_initiate_incoming(const SalMediaDescription *local_capabilities, + const SalMediaDescription *remote_offer, + SalMediaDescription *result){ + int i; + for(i=0;instreams;++i){ + initiate_incoming(&local_capabilities->streams[i],&remote_offer->streams[i],&result->streams[i]); + } + result->nstreams=local_capabilities->nstreams; + strcpy(result->addr,remote_offer->addr); + return 0; +} + diff --git a/linphone/coreapi/offeranswer.h b/linphone/coreapi/offeranswer.h new file mode 100644 index 000000000..079f41c96 --- /dev/null +++ b/linphone/coreapi/offeranswer.h @@ -0,0 +1,47 @@ +/* +linphone +Copyright (C) 2010 Simon MORLAT (simon.morlat@free.fr) + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#ifndef offeranswer_h +#define offeranswer_h + +/** + This header files defines the SDP offer answer API. + It can be used by implementations of SAL directly. +**/ + + +/** + * Returns a media description to run the streams with, based on a local offer + * and the returned response (remote). +**/ +int offer_answer_initiate_outgoing(const SalMediaDescription *local_offer, + const SalMediaDescription *remote_answer, + SalMediaDescription *result); + +/** + * Returns a media description to run the streams with, based on the local capabilities and + * and the received offer. + * The returned media description is an answer and should be sent to the offerer. +**/ +int offer_answer_initiate_incoming(const SalMediaDescription *local_capabilities, + const SalMediaDescription *remote_offer, + SalMediaDescription *result); + +#endif + diff --git a/linphone/coreapi/sal.h b/linphone/coreapi/sal.h new file mode 100644 index 000000000..12fd32bde --- /dev/null +++ b/linphone/coreapi/sal.h @@ -0,0 +1,104 @@ +/* +linphone +Copyright (C) 2010 Simon MORLAT (simon.morlat@free.fr) + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +/** + This header files defines the Signaling Abstraction Layer. + The purpose of this layer is too allow experiment different call signaling + protocols and implementations under linphone, for example SIP, JINGLE... +**/ + +#ifndef sal_h +#define sal_h + +#include "mediastreamer2/mscommon.h" + +struct Sal; + +typedef struct Sal Sal; + +struct SalOp; + +typedef struct SalOp SalOp; + +Sal * sal_init(); +void sal_uninit(Sal* sal); + +typedef enum { + SAL_TRANSPORT_DATAGRAM, + SAL_TRANSPORT_STREAM +}SalTransport; + +typedef enum { + SAL_AUDIO, + SAL_VIDEO, + SAL_OTHER +} SalStreamType; + +typedef struct SalStreamDescription{ + SalStreamType type; + int port; + MSList *payloads; //user_data=(void*)((long)n); +#define payload_type_get_number(pt) ((int)(long)(pt)->user_data) + +#endif diff --git a/linphone/coreapi/sal_eXosip2.c b/linphone/coreapi/sal_eXosip2.c new file mode 100644 index 000000000..be95a0661 --- /dev/null +++ b/linphone/coreapi/sal_eXosip2.c @@ -0,0 +1,153 @@ +/* +linphone +Copyright (C) 2010 Simon MORLAT (simon.morlat@free.fr) + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "sal.h" +#include + +extern char *media_description_to_sdp(const SalMediaDescription *sal); + +struct Sal{ + int running; + int session_expires; +}; + +struct SalOp{ + int cid; + int did; + int tid; + osip_message_t *request; +}; + +static SalOp * sal_op_new(){ + SalOp *op=ms_new(SalOp,1); + op->cid=op->did=op->tid=-1; + op->request=NULL; + return op; +} + +void sal_op_release(SalOp *op){ + ms_free(op); +} + +Sal * sal_init(){ + eXosip_init(); + return ms_new0(Sal,1); +} + +void sal_uninit(Sal* sal){ + eXosip_quit(); + ms_free(sal); +} + + +int sal_listen_port(Sal *ctx, const char *addr, int port, SalTransport tr, int is_secure){ + int err; + bool_t ipv6; + int proto=IPPROTO_UDP; + + 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*/ + /*see if it looks like an IPv6 address*/ + ipv6=strchr(addr,':')!=NULL; + eXosip_enable_ipv6(ipv6); + + if (tr!=SAL_TRANSPORT_DATAGRAM || is_secure){ + 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); + return err; +} + +void sal_set_user_agent(Sal *ctx, const char *user_agent){ + eXosip_set_user_agent(user_agent); +} + +void sal_use_session_timers(Sal *ctx, int expires){ + ctx->session_expires=expires; +} + +SalOp * sal_call_create(Sal *sal, const char *from, const char *to, const char *route, const char *contact){ + int err; + SalOp *op; + osip_message_t *invite=NULL; + err=eXosip_call_build_initial_invite(&invite,to,from, + route,"Phone call"); + if (err!=0){ + ms_error("Could not create call."); + return NULL; + } + if (contact) + osip_message_set_contact(invite,contact); + if (sal->session_expires!=0){ + osip_message_set_header(invite, "Session-expires", "200"); + osip_message_set_supported(invite, "timer"); + } + op=sal_op_new(); + op->request=invite; + return op; +} + +static void set_sdp(osip_message_t *sip, const SalMediaDescription *desc){ + int sdplen; + char clen[10]; + char *sdp=media_description_to_sdp(desc); + + if (sdp==NULL) { + ms_error("Fail to print sdp message !"); + return; + } + sdplen=strlen(sdp); + snprintf(clen,sizeof(clen),"%i",sdplen); + osip_message_set_body(sip,sdp,sdplen); + osip_message_set_content_type(sip,"application/sdp"); + osip_message_set_content_length(sip,clen); + osip_free(sdp); +} + +int sal_call_set_local_media_description(SalOp *h, const SalMediaDescription *desc){ + set_sdp(h->request,desc); + return 0; +} + +int sal_call(SalOp *h){ + int err; + eXosip_lock(); + err=eXosip_call_send_initial_invite(h->request); + eXosip_unlock(); + h->cid=err; + if (err<0){ + ms_error("Fail to send invite !"); + return -1; + } + return 0; +} + +int sal_call_accept(SalOp*h); +int sal_call_get_final_media_description(SalOp *h, SalMediaDescription *result); +int sal_call_terminate(SalOp *h); + +int sal_iterate(Sal *sal); + +SalOp *sal_register_create(Sal *ctx, const char *from, const char *contact, int expires); +int sal_register(SalOp *h); diff --git a/linphone/coreapi/sal_eXosip2_sdp.c b/linphone/coreapi/sal_eXosip2_sdp.c new file mode 100644 index 000000000..e679621b6 --- /dev/null +++ b/linphone/coreapi/sal_eXosip2_sdp.c @@ -0,0 +1,170 @@ +/* +linphone +Copyright (C) 2010 Simon MORLAT (simon.morlat@free.fr) + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + + +#include "ortp/b64.h" +#include "sal.h" +#include + +#define keywordcmp(key,b) strncmp(key,b,sizeof(key)) + +#ifdef FOR_LATER + +static char *make_relay_session_id(const char *username, const char *relay){ + /*ideally this should be a hash of the parameters with a random part*/ + char tmp[128]; + int s1=(int)random(); + int s2=(int)random(); + long long int res=((long long int)s1)<<32 | (long long int) s2; + void *src=&res; + b64_encode(src, sizeof(long long int), tmp, sizeof(tmp)); + return osip_strdup(tmp); +} + + +static void add_relay_info(sdp_message_t *sdp, int mline, const char *relay, const char *relay_session_id){ + + if (relay) sdp_message_a_attribute_add(sdp, mline, + osip_strdup ("relay-addr"),osip_strdup(relay)); + if (relay_session_id) sdp_message_a_attribute_add(sdp, mline, + osip_strdup ("relay-session-id"), osip_strdup(relay_session_id)); +} + +#endif + +char * int_2char(int a){ + char *p=osip_malloc(16); + snprintf(p,16,"%i",a); + return p; +} + +/* return the value of attr "field" for payload pt at line pos (field=rtpmap,fmtp...)*/ +char *sdp_message_a_attr_value_get_with_pt(sdp_message_t *sdp,int pos,int pt,const char *field) +{ + int i,tmppt=0,scanned=0; + char *tmp; + sdp_attribute_t *attr; + for (i=0;(attr=sdp_message_attribute_get(sdp,pos,i))!=NULL;i++){ + if (keywordcmp(field,attr->a_att_field)==0 && attr->a_att_value!=NULL){ + int nb = sscanf(attr->a_att_value,"%i %n",&tmppt,&scanned); + /* the return value may depend on how %n is interpreted by the libc: see manpage*/ + if (nb == 1 || nb==2 ){ + if (pt==tmppt){ + tmp=attr->a_att_value+scanned; + if (strlen(tmp)>0) + return tmp; + } + }else ms_warning("sdp has a strange a= line (%s) nb=%i",attr->a_att_value,nb); + } + } + return NULL; +} + +/* return the value of attr "field" */ +char *sdp_message_a_attr_value_get(sdp_message_t *sdp,int pos,const char *field) +{ + int i; + sdp_attribute_t *attr; + for (i=0;(attr=sdp_message_attribute_get(sdp,pos,i))!=NULL;i++){ + if (keywordcmp(field,attr->a_att_field)==0 && attr->a_att_value!=NULL){ + return attr->a_att_value; + } + } + return NULL; +} + +static int _sdp_message_get_a_ptime(sdp_message_t *sdp, int mline){ + int i,ret; + sdp_attribute_t *attr; + for (i=0;(attr=sdp_message_attribute_get(sdp,mline,i))!=NULL;i++){ + if (keywordcmp("ptime",attr->a_att_field)==0){ + int nb = sscanf(attr->a_att_value,"%i",&ret); + /* the return value may depend on how %n is interpreted by the libc: see manpage*/ + if (nb == 1){ + return ret; + }else ms_warning("sdp has a strange a=ptime line (%s) ",attr->a_att_value); + } + } + return 0; +} + +static sdp_message_t *create_generic_sdp(const SalMediaDescription *desc) +{ + sdp_message_t *local; + int inet6; + + sdp_message_init (&local); + if (strchr(desc->addr,':')!=NULL){ + inet6=1; + }else inet6=0; + sdp_message_v_version_set (local, osip_strdup ("0")); + sdp_message_o_origin_set (local, osip_strdup (desc->username), + osip_strdup ("123456"), osip_strdup ("654321"), + osip_strdup ("IN"), inet6 ? osip_strdup("IP6") : osip_strdup ("IP4"), + osip_strdup (desc->addr)); + sdp_message_s_name_set (local, osip_strdup ("A conversation")); + sdp_message_c_connection_add (local, -1, + osip_strdup ("IN"), inet6 ? osip_strdup ("IP6") : osip_strdup ("IP4"), + osip_strdup (desc->addr), NULL, NULL); + sdp_message_t_time_descr_add (local, osip_strdup ("0"), osip_strdup ("0")); + return local; +} + + + +void add_payload(sdp_message_t *msg, int line, const PayloadType *pt) +{ + char attr[256]; + sdp_message_m_payload_add (msg,line, int_2char (payload_type_get_number(pt))); + snprintf (attr,sizeof(attr),"%i %s", payload_type_get_number(pt), pt->mime_type); + sdp_message_a_attribute_add (msg, line, + osip_strdup ("rtpmap"), osip_strdup(attr)); + + if (pt->recv_fmtp != NULL) + { + snprintf (attr,sizeof(attr),"%i %s", payload_type_get_number(pt),pt->recv_fmtp); + sdp_message_a_attribute_add (msg, line, osip_strdup ("fmtp"), + osip_strdup(attr)); + } +} + + +static void add_line(sdp_message_t *msg, int lineno, const SalStreamDescription *desc){ + const char *mt=desc->type==SAL_AUDIO ? "audio" : "video"; + const MSList *elem; + sdp_message_m_media_add (msg, osip_strdup (mt), + int_2char (desc->port), NULL, + osip_strdup ("RTP/AVP")); + sdp_message_b_bandwidth_add (msg, lineno, osip_strdup ("AS"), + int_2char(desc->bandwidth)); + for(elem=desc->payloads;elem!=NULL;elem=elem->next){ + add_payload(msg, lineno, (PayloadType*)elem->data); + } +} + +char *media_description_to_sdp(const SalMediaDescription *desc){ + int i; + char *tmp; + sdp_message_t *msg=create_generic_sdp(desc); + for(i=0;instreams;++i){ + add_line(msg,i,&desc->streams[i]); + } + sdp_message_to_str(msg,&tmp); + return tmp; +} From 2848c5617c7826e4c945c7aaf594464f8fe9484f Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Wed, 20 Jan 2010 15:29:19 +0100 Subject: [PATCH 02/50] sdp parser ready. --- linphone/coreapi/sal.h | 12 +++- linphone/coreapi/sal_eXosip2_sdp.c | 108 +++++++++++++++++++++++++++-- 2 files changed, 114 insertions(+), 6 deletions(-) diff --git a/linphone/coreapi/sal.h b/linphone/coreapi/sal.h index 12fd32bde..c1ea3ad9f 100644 --- a/linphone/coreapi/sal.h +++ b/linphone/coreapi/sal.h @@ -50,19 +50,29 @@ typedef enum { SAL_OTHER } SalStreamType; +typedef enum{ + SAL_PROTO_UNKNOWN, + SAL_PROTO_RTP_AVP, + SAL_PROTO_RTP_SAVP +}SalMediaProto; + typedef struct SalStreamDescription{ + SalMediaProto proto; SalStreamType type; + char addr[64]; int port; MSList *payloads; //mime_type); + if (pt->type==PAYLOAD_AUDIO_CONTINUOUS || pt->type==PAYLOAD_AUDIO_PACKETIZED) + snprintf (attr,sizeof(attr),"%i %s/%i/%i", payload_type_get_number(pt), + pt->mime_type, pt->clock_rate,pt->channels); + else + snprintf (attr,sizeof(attr),"%i %s/%i", payload_type_get_number(pt), + pt->mime_type, pt->clock_rate); sdp_message_a_attribute_add (msg, line, osip_strdup ("rtpmap"), osip_strdup(attr)); @@ -168,3 +175,94 @@ char *media_description_to_sdp(const SalMediaDescription *desc){ sdp_message_to_str(msg,&tmp); return tmp; } + +static int payload_type_fill_from_rtpmap(PayloadType *pt, const char *rtpmap){ + if (rtpmap==NULL){ + PayloadType *refpt=rtp_profile_get_payload(&av_profile,payload_type_get_number(pt)); + if (refpt){ + pt->mime_type=ms_strdup(refpt->mime_type); + pt->clock_rate=refpt->clock_rate; + }else{ + ms_error("payload number %i has no rtpmap and is unknown in AV Profile, ignored.", + payload_type_get_number(pt)); + return -1; + } + }else{ + char *mime=ms_strdup(rtpmap); + char *p=strchr(mime,'/'); + if (p){ + char *chans; + *p='\0'; + p++; + chans=strchr(p,'/'); + if (chans){ + *chans='\0'; + chans++; + pt->channels=atoi(chans); + }else pt->channels=1; + pt->clock_rate=atoi(p); + } + pt->mime_type=mime; + } + return 0; +} + +int sdp_to_media_description(const char *sdp, SalMediaDescription *desc){ + int i,j; + const char *mtype,*proto,*port,*addr,*number; + sdp_message_t *msg; + sdp_bandwidth_t *sbw=NULL; + sdp_message_init(&msg); + if (sdp_message_parse(msg,sdp)!=0){ + ms_error("Fail to parse sdp message !"); + sdp_message_free(msg); + return -1; + } + addr=sdp_message_c_addr_get (msg, -1, 0); + if (addr) + strncpy(desc->addr,addr,sizeof(desc->addr)); + /* for each m= line */ + for (i=0; !sdp_message_endof_media (msg, i) && istreams[i]; + + memset(stream,0,sizeof(*stream)); + mtype = sdp_message_m_media_get(msg, i); + proto = sdp_message_m_proto_get (msg, i); + port = sdp_message_m_port_get(msg, i); + stream->proto=SAL_PROTO_UNKNOWN; + if (proto){ + if (strcasecmp(proto,"RTP/AVP")==0) + stream->proto=SAL_PROTO_RTP_AVP; + else if (strcasecmp(proto,"RTP/SAVP")==0){ + stream->proto=SAL_PROTO_RTP_SAVP; + } + } + addr = sdp_message_c_addr_get (msg, i, 0); + if (addr != NULL) + strncpy(stream->addr,addr,sizeof(stream->addr)); + stream->ptime=_sdp_message_get_a_ptime(msg,i); + if (strcasecmp("audio", mtype) == 0){ + stream->type=SAL_AUDIO; + }else if (strcasecmp("video", mtype) == 0){ + stream->type=SAL_VIDEO; + }else stream->type=SAL_OTHER; + for(j=0;(sbw=sdp_message_bandwidth_get(msg,i,j))!=NULL;++j){ + if (strcasecmp(sbw->b_bwtype,"AS")==0) stream->bandwidth=atoi(sbw->b_bandwidth); + } + /* for each payload type */ + for (j=0;((number=sdp_message_m_payload_get (msg, i,j)) != NULL); j++){ + const char *rtpmap,*fmtp; + int ptn=atoi(number); + PayloadType *pt=payload_type_new(); + payload_type_set_number(pt,ptn); + /* get the rtpmap associated to this codec, if any */ + rtpmap=sdp_message_a_attr_value_get_with_pt(msg, i,ptn,"rtpmap"); + payload_type_fill_from_rtpmap(pt,rtpmap); + /* get the fmtp, if any */ + fmtp=sdp_message_a_attr_value_get_with_pt(msg, i, ptn,"fmtp"); + payload_type_set_send_fmtp(pt,fmtp); + } + } + return 0; +} From df89bafa704aea669eecbe1e5886c96807f83f0c Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Fri, 22 Jan 2010 12:26:25 +0100 Subject: [PATCH 03/50] work in progress, new layout --- coreapi/Makefile.am | 5 +- {linphone/coreapi => coreapi}/offeranswer.c | 0 {linphone/coreapi => coreapi}/offeranswer.h | 0 {linphone/coreapi => coreapi}/sal.h | 58 ++++++++++--- {linphone/coreapi => coreapi}/sal_eXosip2.c | 85 +++++++++++-------- .../coreapi => coreapi}/sal_eXosip2_sdp.c | 0 6 files changed, 101 insertions(+), 47 deletions(-) rename {linphone/coreapi => coreapi}/offeranswer.c (100%) rename {linphone/coreapi => coreapi}/offeranswer.h (100%) rename {linphone/coreapi => coreapi}/sal.h (66%) rename {linphone/coreapi => coreapi}/sal_eXosip2.c (67%) rename {linphone/coreapi => coreapi}/sal_eXosip2_sdp.c (100%) diff --git a/coreapi/Makefile.am b/coreapi/Makefile.am index 7c3827f29..e46d0c492 100644 --- a/coreapi/Makefile.am +++ b/coreapi/Makefile.am @@ -17,7 +17,8 @@ liblinphone_la_SOURCES=\ linphonecore.c linphonecore.h private.h\ exevents.c exevents.h \ offeranswer.c offeranswer.h\ - sal_eXosip2.c sal.h \ + sal.c sal.h \ + sal_eXosip2.c \ sal_eXosip2_sdp.c \ misc.c \ address.c \ @@ -29,7 +30,7 @@ liblinphone_la_SOURCES=\ authentication.c \ lpconfig.c lpconfig.h \ chat.c \ - general_state.c \ + general_state.c \ sipsetup.c sipsetup.h \ siplogin.c diff --git a/linphone/coreapi/offeranswer.c b/coreapi/offeranswer.c similarity index 100% rename from linphone/coreapi/offeranswer.c rename to coreapi/offeranswer.c diff --git a/linphone/coreapi/offeranswer.h b/coreapi/offeranswer.h similarity index 100% rename from linphone/coreapi/offeranswer.h rename to coreapi/offeranswer.h diff --git a/linphone/coreapi/sal.h b/coreapi/sal.h similarity index 66% rename from linphone/coreapi/sal.h rename to coreapi/sal.h index c1ea3ad9f..1eb93cc2e 100644 --- a/linphone/coreapi/sal.h +++ b/coreapi/sal.h @@ -36,6 +36,7 @@ struct SalOp; typedef struct SalOp SalOp; + Sal * sal_init(); void sal_uninit(Sal* sal); @@ -75,7 +76,20 @@ typedef struct SalMediaDescription{ SalStreamDescription streams[SAL_MEDIA_DESCRIPTION_MAX_STREAMS]; } SalMediaDescription; -void sal_media_description_free(SalMediaDescription *md); +SalMediaDescription *sal_media_description_new(); +void sal_media_description_destroy(SalMediaDescription *md); + +/*this structure must be at the first byte of the SalOp structure defined by implementors*/ +typedef struct SalOpBase{ + Sal *root; + char *route; + char *contact; + char *from; + char *to; + SalMediaDescription *local_media; + SalMediaDescription *remote_media; +} SalOpBase; + typedef enum SalError{ SalErrorNetwork, @@ -90,25 +104,47 @@ typedef void (*SalOnCallAccepted)(SalOp *op); typedef void (*SalOnCallTerminated)(SalOp *op); typedef void (*SalOnCallFailure)(SalOp *op, SalError error, const char *details); +typedef struct SalCallbacks{ + SalOnCallReceived call_received; + SalOnCallRinging call_ringing; + SalOnCallAccepted call_accepted; + SalOnCallTerminated call_terminated; + SalOnCallFailure call_failure; +}SalCallbacks; + +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); void sal_set_user_agent(Sal *ctx, const char *user_agent); void sal_use_session_timers(Sal *ctx, int expires); - -SalOp * sal_call_create(Sal *sal, const char *from, const char *to, const char *route, const char *contact); -int sal_call_set_local_media_description(SalOp *h, const SalMediaDescription *desc); -int sal_call(SalOp *h); -int sal_call_accept(SalOp*h); -int sal_call_get_final_media_description(SalOp *h, SalMediaDescription *result); -int sal_call_terminate(SalOp *h); - int sal_iterate(Sal *sal); -SalOp *sal_register_create(Sal *ctx, const char *from, const char *contact, int expires); -int sal_register(SalOp *h); +/*create an operation */ +SalOp * sal_op_new(Sal *sal); +/*generic SalOp API, working for all operations */ +void sal_op_set_contact(SalOp *op, const char *contact); +void sal_op_set_route(SalOp *op, const char *route); +void sal_op_set_from(SalOp *op, const char *from); +void sal_op_set_to(SalOp *op, const char *to); void sal_op_release(SalOp *h); +/*Call API*/ +int sal_call_set_local_media_description(SalOp *h, SalMediaDescription *desc); +int sal_call(SalOp *h, const char *from, const char *to); +int sal_call_accept(SalOp*h); +const SalMediaDescription * sal_call_get_final_media_description(SalOp *h); +int sal_call_terminate(SalOp *h); + +int sal_register(SalOp *op, const char *from, const char *contact, int expires); + + #define payload_type_set_number(pt,n) (pt)->user_data=(void*)((long)n); #define payload_type_get_number(pt) ((int)(long)(pt)->user_data) + +/*internal API */ +void __sal_op_init(SalOp *b, Sal *sal); +void __sal_op_free(SalOp *b); + + #endif diff --git a/linphone/coreapi/sal_eXosip2.c b/coreapi/sal_eXosip2.c similarity index 67% rename from linphone/coreapi/sal_eXosip2.c rename to coreapi/sal_eXosip2.c index be95a0661..bbc46beb0 100644 --- a/linphone/coreapi/sal_eXosip2.c +++ b/coreapi/sal_eXosip2.c @@ -23,26 +23,29 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. extern char *media_description_to_sdp(const SalMediaDescription *sal); struct Sal{ + SalCallbacks callbacks; int running; int session_expires; }; struct SalOp{ + SalOpBase base; int cid; int did; int tid; - osip_message_t *request; + bool_t supports_session_timers; }; -static SalOp * sal_op_new(){ +SalOp * sal_op_new(Sal *sal){ SalOp *op=ms_new(SalOp,1); + __sal_op_init(op,sal); op->cid=op->did=op->tid=-1; - op->request=NULL; + op->supports_session_timers=FALSE; return op; } void sal_op_release(SalOp *op){ - ms_free(op); + __sal_op_free(op); } Sal * sal_init(){ @@ -87,27 +90,6 @@ void sal_use_session_timers(Sal *ctx, int expires){ ctx->session_expires=expires; } -SalOp * sal_call_create(Sal *sal, const char *from, const char *to, const char *route, const char *contact){ - int err; - SalOp *op; - osip_message_t *invite=NULL; - err=eXosip_call_build_initial_invite(&invite,to,from, - route,"Phone call"); - if (err!=0){ - ms_error("Could not create call."); - return NULL; - } - if (contact) - osip_message_set_contact(invite,contact); - if (sal->session_expires!=0){ - osip_message_set_header(invite, "Session-expires", "200"); - osip_message_set_supported(invite, "timer"); - } - op=sal_op_new(); - op->request=invite; - return op; -} - static void set_sdp(osip_message_t *sip, const SalMediaDescription *desc){ int sdplen; char clen[10]; @@ -125,15 +107,30 @@ static void set_sdp(osip_message_t *sip, const SalMediaDescription *desc){ osip_free(sdp); } -int sal_call_set_local_media_description(SalOp *h, const SalMediaDescription *desc){ - set_sdp(h->request,desc); +int sal_call_set_local_media_description(SalOp *h, SalMediaDescription *desc){ + h->base.local_media=desc; return 0; } -int sal_call(SalOp *h){ +int sal_call(SalOp *h, const char *from, const char *to){ int err; + osip_message_t *invite=NULL; + sal_op_set_from(h,from); + sal_op_set_to(h,to); + err=eXosip_call_build_initial_invite(&invite,to,from,h->base.route,"Phone call"); + if (err!=0){ + ms_error("Could not create call."); + return -1; + } + if (h->base.contact) + osip_message_set_contact(invite,h->base.contact); + if (h->base.root->session_expires!=0){ + osip_message_set_header(invite, "Session-expires", "200"); + osip_message_set_supported(invite, "timer"); + } + if (h->base.local_media) set_sdp(invite,h->base.local_media); eXosip_lock(); - err=eXosip_call_send_initial_invite(h->request); + err=eXosip_call_send_initial_invite(invite); eXosip_unlock(); h->cid=err; if (err<0){ @@ -143,11 +140,31 @@ int sal_call(SalOp *h){ return 0; } -int sal_call_accept(SalOp*h); -int sal_call_get_final_media_description(SalOp *h, SalMediaDescription *result); -int sal_call_terminate(SalOp *h); +int sal_call_accept(SalOp * h){ + osip_message_t *msg; + /* sends a 200 OK */ + int err=eXosip_call_build_answer(h->tid,200,&msg); + if (err<0 || msg==NULL){ + ms_error("Fail to build answer for call: err=%i",err); + return -1; + } + if (h->base.root->session_expires!=0){ + if (h->supports_session_timers) osip_message_set_supported(msg, "timer"); + } + return 0; +} + +const SalMediaDescription * sal_call_get_final_media_description(SalOp *h){ + return NULL; +} + +int sal_call_terminate(SalOp *h){ + eXosip_lock(); + eXosip_call_terminate(h->cid,h->did); + eXosip_unlock(); + return 0; +} int sal_iterate(Sal *sal); -SalOp *sal_register_create(Sal *ctx, const char *from, const char *contact, int expires); -int sal_register(SalOp *h); +int sal_register(SalOp *h, const char *from, const char *contact, int expires); diff --git a/linphone/coreapi/sal_eXosip2_sdp.c b/coreapi/sal_eXosip2_sdp.c similarity index 100% rename from linphone/coreapi/sal_eXosip2_sdp.c rename to coreapi/sal_eXosip2_sdp.c From 74e0bbb7a31a8a931e2f864d708e51ba830a0168 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Tue, 26 Jan 2010 10:58:10 +0100 Subject: [PATCH 04/50] update russian translation --- po/ru.po | 2266 ------------------------------------------------------ 1 file changed, 2266 deletions(-) delete mode 100644 po/ru.po diff --git a/po/ru.po b/po/ru.po deleted file mode 100644 index 669a5a96d..000000000 --- a/po/ru.po +++ /dev/null @@ -1,2266 +0,0 @@ -# SIP Telephony Application. -# Copyright (C) 2001, 2002 Free Software Foundation, Inc. -# Simon Morlat , 2001. -# -msgid "" -msgstr "" -"Project-Id-Version: linphone 0.7.1\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2009-10-16 15:24+0200\n" -"PO-Revision-Date: 2008-11-25 18:39+0300\n" -"Last-Translator: Grigory Fateyev \n" -"Language-Team: Russian \n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" - -#: ../gtk-glade/support.c:49 ../gtk-glade/support.c:73 -#: ../gtk-glade/support.c:102 -#, c-format -msgid "Couldn't find pixmap file: %s" -msgstr "Невозможно найти картинку: %s" - -#: ../gtk-glade/chat.c:27 -#, c-format -msgid "Chat with %s" -msgstr "Чат с %s" - -#: ../gtk-glade/main.c:90 -msgid "log to stdout some debug information while running." -msgstr "" - -#: ../gtk-glade/main.c:97 -msgid "Start only in the system tray, do not show the main interface." -msgstr "" - -#: ../gtk-glade/main.c:104 -msgid "address to call right now" -msgstr "" - -#: ../gtk-glade/main.c:111 -msgid "if set automatically answer incoming calls" -msgstr "" - -#: ../gtk-glade/main.c:119 -msgid "" -"Specifiy a working directory (should be the base of the installation, eg: c:" -"\\Program Files\\Linphone)" -msgstr "" - -#: ../gtk-glade/main.c:675 -#, c-format -msgid "Incoming call from %s" -msgstr "Входящий звонок %s" - -#: ../gtk-glade/main.c:707 -#, c-format -msgid "" -"%s would like to add you to his contact list.\n" -"Would you allow him to see your presence status or add him to your contact " -"list ?\n" -"If you answer no, this person will be temporarily blacklisted." -msgstr "" -"%s вы бы хотели быть добавленным в этот контактный лист.\n" -"Вы разрешаете ему(ей) видеть ваш статус присутствия или добавить в " -"контактный лист?\n" -"Если вы ответите Нет, эта персона будет временно заблокированна." - -#: ../gtk-glade/main.c:777 -#, fuzzy, c-format -msgid "" -"Please enter your password for username %s\n" -" at domain %s:" -msgstr "Пожалуйста, введите пароль для домена %s:" - -#: ../gtk-glade/main.c:871 -msgid "Website link" -msgstr "" - -#: ../gtk-glade/main.c:907 -msgid "Linphone - a video internet phone" -msgstr "Linphone - Интернет видео телефон" - -#: ../gtk-glade/main.c:926 -#, c-format -msgid "%s (Default)" -msgstr "%s (По умолчанию)" - -#: ../gtk-glade/main.c:1168 -msgid "A free SIP video-phone" -msgstr "Свободный SIP видео-телефон" - -#: ../gtk-glade/friendlist.c:205 ../gtk-glade/propertybox.c:245 -#: ../gtk-glade/contact.glade.h:3 -msgid "Name" -msgstr "Имя" - -#: ../gtk-glade/friendlist.c:212 -msgid "Presence status" -msgstr "Статус присутствия" - -#: ../gtk-glade/friendlist.c:243 -#, c-format -msgid "Search in %s directory" -msgstr "" - -#: ../gtk-glade/friendlist.c:432 -msgid "Invalid sip contact !" -msgstr "" - -#: ../gtk-glade/friendlist.c:474 -#, c-format -msgid "Call %s" -msgstr "Звонк %s" - -#: ../gtk-glade/friendlist.c:475 -#, c-format -msgid "Send text to %s" -msgstr "Послать текст к %s" - -#: ../gtk-glade/friendlist.c:476 -#, fuzzy, c-format -msgid "Edit contact '%s'" -msgstr "Редактировать контактную информацию" - -#: ../gtk-glade/friendlist.c:477 -#, c-format -msgid "Delete contact '%s'" -msgstr "" - -#: ../gtk-glade/friendlist.c:519 -#, c-format -msgid "Add new contact from %s directory" -msgstr "" - -#: ../gtk-glade/propertybox.c:251 -msgid "Rate (Hz)" -msgstr "Частота (Hz)" - -#: ../gtk-glade/propertybox.c:257 -msgid "Status" -msgstr "Статус" - -#: ../gtk-glade/propertybox.c:263 -msgid "Min bitrate (kbit/s)" -msgstr "Минимальный битрейт (kbit/s)" - -#: ../gtk-glade/propertybox.c:269 -msgid "Parameters" -msgstr "Параметры" - -#: ../gtk-glade/propertybox.c:296 ../gtk-glade/propertybox.c:435 -msgid "Enabled" -msgstr "Включить" - -#: ../gtk-glade/propertybox.c:297 ../gtk-glade/propertybox.c:435 -msgid "Disabled" -msgstr "Выключить" - -#: ../gtk-glade/propertybox.c:480 -msgid "Account" -msgstr "Аккаунт" - -#: ../gtk-glade/propertybox.c:620 -msgid "English" -msgstr "" - -#: ../gtk-glade/propertybox.c:621 -msgid "French" -msgstr "" - -#: ../gtk-glade/propertybox.c:622 -msgid "Swedish" -msgstr "" - -#: ../gtk-glade/propertybox.c:623 -msgid "Italian" -msgstr "" - -#: ../gtk-glade/propertybox.c:624 -msgid "Spanish" -msgstr "" - -#: ../gtk-glade/propertybox.c:625 -msgid "Brazilian Portugese" -msgstr "" - -#: ../gtk-glade/propertybox.c:626 -msgid "Polish" -msgstr "" - -#: ../gtk-glade/propertybox.c:627 -msgid "German" -msgstr "" - -#: ../gtk-glade/propertybox.c:628 -msgid "Russian" -msgstr "" - -#: ../gtk-glade/propertybox.c:629 -msgid "Japanese" -msgstr "" - -#: ../gtk-glade/propertybox.c:630 -msgid "Dutch" -msgstr "" - -#: ../gtk-glade/propertybox.c:631 -msgid "Hungarian" -msgstr "" - -#: ../gtk-glade/propertybox.c:632 -msgid "Czech" -msgstr "" - -#: ../gtk-glade/propertybox.c:633 -msgid "Chinese" -msgstr "" - -#: ../gtk-glade/propertybox.c:690 -msgid "" -"You need to restart linphone for the new language selection to take effect." -msgstr "" - -#: ../gtk-glade/update.c:80 -#, c-format -msgid "" -"A more recent version is availalble from %s.\n" -"Would you like to open a browser to download it ?" -msgstr "" - -#: ../gtk-glade/update.c:91 -msgid "You are running the lastest version." -msgstr "" - -#: ../gtk-glade/buddylookup.c:66 -msgid "Firstname, Lastname" -msgstr "" - -#: ../gtk-glade/buddylookup.c:73 -#, fuzzy -msgid "SIP address" -msgstr "SIP Адрес" - -#: ../gtk-glade/buddylookup.c:121 -msgid "Error communicating with server." -msgstr "" - -#: ../gtk-glade/buddylookup.c:125 -#, fuzzy -msgid "Connecting..." -msgstr "Verbindung" - -#: ../gtk-glade/buddylookup.c:129 -#, fuzzy -msgid "Connected" -msgstr "Соединён." - -#: ../gtk-glade/buddylookup.c:133 -msgid "Receiving data..." -msgstr "" - -#: ../gtk-glade/buddylookup.c:141 -#, c-format -msgid "Found %i contact" -msgid_plural "Found %i contacts" -msgstr[0] "" -msgstr[1] "" - -#: ../gtk-glade/setupwizard.c:25 -msgid "" -"Welcome !\n" -"This assistant will help you to use a SIP account for your calls." -msgstr "" - -#: ../gtk-glade/setupwizard.c:34 -msgid "Create an account by choosing a username" -msgstr "" - -#: ../gtk-glade/setupwizard.c:35 -msgid "I have already an account and just want to use it" -msgstr "" - -#: ../gtk-glade/setupwizard.c:53 -msgid "Please choose a username:" -msgstr "" - -#: ../gtk-glade/setupwizard.c:54 -#, fuzzy -msgid "Username:" -msgstr "Имя пользователя:" - -#: ../gtk-glade/setupwizard.c:92 -#, c-format -msgid "Checking if '%s' is available..." -msgstr "" - -#: ../gtk-glade/setupwizard.c:97 ../gtk-glade/setupwizard.c:164 -msgid "Please wait..." -msgstr "" - -#: ../gtk-glade/setupwizard.c:101 -msgid "Sorry this username already exists. Please try a new one." -msgstr "" - -#: ../gtk-glade/setupwizard.c:103 ../gtk-glade/setupwizard.c:168 -msgid "Ok !" -msgstr "" - -#: ../gtk-glade/setupwizard.c:106 ../gtk-glade/setupwizard.c:171 -msgid "Communication problem, please try again later." -msgstr "" - -#: ../gtk-glade/setupwizard.c:134 -msgid "Thank you. Your account is now configured and ready for use." -msgstr "" - -#: ../gtk-glade/setupwizard.c:228 -msgid "Welcome to the account setup assistant" -msgstr "" - -#: ../gtk-glade/setupwizard.c:232 -msgid "Account setup assistant" -msgstr "" - -#: ../gtk-glade/setupwizard.c:236 -#, fuzzy -msgid "Choosing a username" -msgstr "Ваше имя пользователя:" - -#: ../gtk-glade/setupwizard.c:240 -msgid "Verifying" -msgstr "" - -#: ../gtk-glade/setupwizard.c:244 -#, fuzzy -msgid "Confirmation" -msgstr "Информация" - -#: ../gtk-glade/setupwizard.c:249 -msgid "Creating your account" -msgstr "" - -#: ../gtk-glade/setupwizard.c:253 -msgid "Now ready !" -msgstr "" - -#: ../gtk-glade/incall_view.c:98 -#, fuzzy -msgid "Calling..." -msgstr "IPv6 использовать" - -#: ../gtk-glade/incall_view.c:122 -#, fuzzy -msgid "In call with" -msgstr "Прервать звонок" - -#: ../gtk-glade/incall_view.c:124 -msgid "00::00::00" -msgstr "" - -#: ../gtk-glade/incall_view.c:140 -#, c-format -msgid "%02i::%02i::%02i" -msgstr "" - -#: ../gtk-glade/incall_view.c:158 -#, fuzzy -msgid "Call ended." -msgstr "Разговор окончен" - -#: ../gtk-glade/incall_view.c:176 -#, fuzzy -msgid "Unmute" -msgstr "Безлимитный" - -#: ../gtk-glade/incall_view.c:180 ../gtk-glade/main.glade.h:40 -msgid "Mute" -msgstr "" - -#: ../gtk-glade/loginframe.c:82 -#, fuzzy, c-format -msgid "Please enter login information for %s" -msgstr "Пожалуйста, введите пароль для домена %s:" - -#: ../gtk-glade/main.glade.h:1 -msgid "#" -msgstr "#" - -#: ../gtk-glade/main.glade.h:2 -msgid "*" -msgstr "*" - -#: ../gtk-glade/main.glade.h:3 -msgid "0" -msgstr "0" - -#: ../gtk-glade/main.glade.h:4 -msgid "1" -msgstr "1" - -#: ../gtk-glade/main.glade.h:5 -msgid "2" -msgstr "2" - -#: ../gtk-glade/main.glade.h:6 -msgid "3" -msgstr "3" - -#: ../gtk-glade/main.glade.h:7 -msgid "4" -msgstr "4" - -#: ../gtk-glade/main.glade.h:8 -msgid "5" -msgstr "5" - -#: ../gtk-glade/main.glade.h:9 -msgid "6" -msgstr "6" - -#: ../gtk-glade/main.glade.h:10 -msgid "7" -msgstr "7" - -#: ../gtk-glade/main.glade.h:11 -msgid "8" -msgstr "8" - -#: ../gtk-glade/main.glade.h:12 -msgid "9" -msgstr "9" - -#: ../gtk-glade/main.glade.h:13 -msgid "Contact list" -msgstr "Контактный лист" - -#: ../gtk-glade/main.glade.h:14 -#, fuzzy -msgid "Terminate call" -msgstr "Прервать звонок" - -#: ../gtk-glade/main.glade.h:15 -#, fuzzy -msgid "Welcome !" -msgstr "Видео" - -#: ../gtk-glade/main.glade.h:16 -msgid "A" -msgstr "А" - -#: ../gtk-glade/main.glade.h:17 -msgid "" -"ADSL\n" -"Fiber Channel" -msgstr "" - -#: ../gtk-glade/main.glade.h:19 -msgid "" -"All users\n" -"Online users" -msgstr "" - -#: ../gtk-glade/main.glade.h:21 -msgid "Assistant" -msgstr "" - -#: ../gtk-glade/main.glade.h:22 -msgid "Audio & Video" -msgstr "Аудио & Видео" - -#: ../gtk-glade/main.glade.h:23 -msgid "Audio only" -msgstr "Только аудио" - -#: ../gtk-glade/main.glade.h:24 -#, fuzzy -msgid "Automatically log me in" -msgstr "Автоматически определить верный hostname" - -#: ../gtk-glade/main.glade.h:25 -msgid "B" -msgstr "Б" - -#: ../gtk-glade/main.glade.h:26 ../gtk-glade/parameters.glade.h:20 -msgid "C" -msgstr "В" - -#: ../gtk-glade/main.glade.h:27 -msgid "Check for updates" -msgstr "" - -#: ../gtk-glade/main.glade.h:28 -msgid "D" -msgstr "Г" - -#: ../gtk-glade/main.glade.h:29 -msgid "Default" -msgstr "По умолчанию" - -#: ../gtk-glade/main.glade.h:30 -msgid "Digits" -msgstr "Цифры" - -#: ../gtk-glade/main.glade.h:31 -#, fuzzy -msgid "Duration" -msgstr "Информация" - -#: ../gtk-glade/main.glade.h:32 -#, fuzzy -msgid "Duration:" -msgstr "Информация" - -#: ../gtk-glade/main.glade.h:33 -#, fuzzy -msgid "Enable self-view" -msgstr "Включить видео" - -#: ../gtk-glade/main.glade.h:34 -msgid "Enter username, phone number, or full sip address" -msgstr "" - -#: ../gtk-glade/main.glade.h:35 -#, fuzzy -msgid "In call" -msgstr "Входящие звонки" - -#: ../gtk-glade/main.glade.h:36 -msgid "Internet connection:" -msgstr "" - -#: ../gtk-glade/main.glade.h:37 -#, fuzzy -msgid "Login information" -msgstr "Контактная информация" - -#: ../gtk-glade/main.glade.h:38 -msgid "Lookup:" -msgstr "" - -#: ../gtk-glade/main.glade.h:39 -msgid "Main view" -msgstr "" - -#: ../gtk-glade/main.glade.h:41 -#, fuzzy -msgid "My current identity:" -msgstr "Мой идентификатор:" - -#: ../gtk-glade/main.glade.h:42 -#, fuzzy -msgid "Password" -msgstr "Пароль" - -#: ../gtk-glade/main.glade.h:43 -#, fuzzy -msgid "SIP address or phone number:" -msgstr "Введите sip адрес или телефонный номер." - -#: ../gtk-glade/main.glade.h:44 -#, fuzzy -msgid "Show current call" -msgstr "Текущий звонок" - -#: ../gtk-glade/main.glade.h:45 -msgid "Start call" -msgstr "Позвонить" - -#: ../gtk-glade/main.glade.h:46 -msgid "Terminate call" -msgstr "Прервать звонок" - -#: ../gtk-glade/main.glade.h:47 -#, fuzzy -msgid "Username" -msgstr "Имя пользователя:" - -#: ../gtk-glade/main.glade.h:48 -#, fuzzy -msgid "_Linphone" -msgstr "Linphone" - -#: ../gtk-glade/main.glade.h:49 -msgid "_Modes" -msgstr "_Режимы" - -#: ../gtk-glade/main.glade.h:50 -#, fuzzy -msgid "gtk-connect" -msgstr "Закрыть" - -#: ../gtk-glade/main.glade.h:51 -#, fuzzy -msgid "gtk-find" -msgstr "Выход" - -#: ../gtk-glade/main.glade.h:52 -msgid "in" -msgstr "" - -#: ../gtk-glade/main.glade.h:53 -#, fuzzy -msgid "label" -msgstr "label37" - -#: ../gtk-glade/about.glade.h:1 -msgid "About linphone" -msgstr "Про linphone" - -#: ../gtk-glade/about.glade.h:2 -msgid "An internet video phone using the standart SIP (rfc3261) protocol." -msgstr "Интернет видео телефон использующий стандарт SIP (rfc3261) протокола." - -#: ../gtk-glade/about.glade.h:3 -msgid "Created by Simon Morlat\n" -msgstr "Создан Simon Morlat\n" - -#: ../gtk-glade/about.glade.h:5 -msgid "" -"fr: Simon Morlat\n" -"en: Simon Morlat and Delphine Perreau\n" -"it: Alberto Zanoni \n" -"de: Jean-Jacques Sarton \n" -"sv: Daniel Nylander \n" -"es: Jesus Benitez \n" -"ja: YAMAGUCHI YOSHIYA \n" -"pt_BR: Rafael Caesar Lenzi \n" -"pl: Robert Nasiadek \n" -"cs: Petr Pisar \n" -"hu: anonymous\n" -msgstr "" -"fr: Simon Morlat\n" -"en: Simon Morlat and Delphine Perreau\n" -"it: Alberto Zanoni \n" -"de: Jean-Jacques Sarton \n" -"sv: Daniel Nylander \n" -"es: Jesus Benitez \n" -"ja: YAMAGUCHI YOSHIYA \n" -"pt_BR: Rafael Caesar Lenzi \n" -"pl: Robert Nasiadek \n" -"cs: Petr Pisar \n" -"hu: anonymous\n" - -#: ../gtk-glade/contact.glade.h:1 -#, fuzzy -msgid "Contact information" -msgstr "Контактная информация" - -#: ../gtk-glade/contact.glade.h:2 -msgid "Allow this contact to see my presence status" -msgstr "Разрешить этому контакту видеть мой статус присутствия" - -#: ../gtk-glade/contact.glade.h:4 -msgid "SIP Address" -msgstr "SIP Адрес" - -#: ../gtk-glade/contact.glade.h:5 -msgid "Show this contact presence status" -msgstr "Показывать этому контакту статус присутствия" - -#: ../gtk-glade/contact.glade.h:6 ../gtk-glade/password.glade.h:5 -#: ../gtk-glade/sip_account.glade.h:9 -msgid "gtk-cancel" -msgstr "Выход" - -#: ../gtk-glade/contact.glade.h:7 ../gtk-glade/password.glade.h:6 -#: ../gtk-glade/sip_account.glade.h:10 -msgid "gtk-ok" -msgstr "Ок" - -#: ../gtk-glade/log.glade.h:1 -msgid "Linphone debug window" -msgstr "Linphone окно ошибок" - -#: ../gtk-glade/log.glade.h:2 ../gtk-glade/call_logs.glade.h:2 -#: ../gtk-glade/chatroom.glade.h:2 -msgid "gtk-close" -msgstr "Закрыть" - -#: ../gtk-glade/password.glade.h:1 -msgid "Linphone - Authentication required" -msgstr "Linphone - Регистрация необходима" - -#: ../gtk-glade/password.glade.h:2 -msgid "Password:" -msgstr "Пароль" - -#: ../gtk-glade/password.glade.h:3 -#, fuzzy -msgid "Please enter the domain password" -msgstr "Пожалуйста, введите свой паспорт для домена..." - -#: ../gtk-glade/password.glade.h:4 -msgid "UserID" -msgstr "" - -#: ../gtk-glade/call_logs.glade.h:1 -msgid "Call history" -msgstr "История звонков" - -#: ../gtk-glade/sip_account.glade.h:1 -msgid "Configure a SIP account" -msgstr "Настроить SIP аккаунт" - -#: ../gtk-glade/sip_account.glade.h:2 -msgid "Linphone - Configure a SIP account" -msgstr "Linphone - Настроить SIP аккаунт" - -#: ../gtk-glade/sip_account.glade.h:3 -msgid "Publish presence information" -msgstr "Показывать статус присутствия" - -#: ../gtk-glade/sip_account.glade.h:4 -msgid "Register at startup" -msgstr "Регистрировать при старте" - -#: ../gtk-glade/sip_account.glade.h:5 -#, fuzzy -msgid "Registration duration (sec):" -msgstr "Период регистрации (сек):" - -#: ../gtk-glade/sip_account.glade.h:6 -msgid "Route (optional):" -msgstr "Маршрут (необязательно):" - -#: ../gtk-glade/sip_account.glade.h:7 -msgid "SIP Proxy address:" -msgstr "Адрес SIP прокси:" - -#: ../gtk-glade/sip_account.glade.h:8 -msgid "Your SIP identity:" -msgstr "Ваш SIP идентификатор:" - -#: ../gtk-glade/sip_account.glade.h:11 -msgid "sip:" -msgstr "sip:" - -#: ../gtk-glade/chatroom.glade.h:1 -msgid "Send" -msgstr "Отправить" - -#: ../gtk-glade/incoming_call.glade.h:1 -msgid "Accept" -msgstr "Принять" - -#: ../gtk-glade/incoming_call.glade.h:2 -msgid "Decline" -msgstr "Понижение" - -#: ../gtk-glade/incoming_call.glade.h:3 ../coreapi/linphonecore.c:235 -msgid "Incoming call" -msgstr "Входящие звонки" - -#: ../gtk-glade/incoming_call.glade.h:4 -msgid "Incoming call from" -msgstr "Входящий звонок от" - -#: ../gtk-glade/incoming_call.glade.h:5 -msgid "Linphone - Incoming call" -msgstr "Linphone - Входящий звонок" - -#: ../gtk-glade/parameters.glade.h:1 -msgid "0 stands for \"unlimited\"" -msgstr "0 поставить для \"безлимитный\"" - -#: ../gtk-glade/parameters.glade.h:2 -#, fuzzy -msgid "Audio" -msgstr "Звук" - -#: ../gtk-glade/parameters.glade.h:3 -#, fuzzy -msgid "Bandwidth control" -msgstr "Пропускная способность" - -#: ../gtk-glade/parameters.glade.h:4 -msgid "Codecs" -msgstr "Кодеки" - -#: ../gtk-glade/parameters.glade.h:5 -msgid "Default identity" -msgstr "Личность по умолчанию" - -#: ../gtk-glade/parameters.glade.h:6 -#, fuzzy -msgid "Language" -msgstr "IPv6 использовать" - -#: ../gtk-glade/parameters.glade.h:7 -#, fuzzy -msgid "NAT and Firewall" -msgstr "Настройки firewall" - -#: ../gtk-glade/parameters.glade.h:8 -#, fuzzy -msgid "Ports" -msgstr "Используемые порты" - -#: ../gtk-glade/parameters.glade.h:9 -msgid "Privacy" -msgstr "Секретность" - -#: ../gtk-glade/parameters.glade.h:10 -msgid "Proxy accounts" -msgstr "Proxy аккаунт" - -#: ../gtk-glade/parameters.glade.h:11 -#, fuzzy -msgid "Transport" -msgstr "Используемые порты" - -#: ../gtk-glade/parameters.glade.h:12 -msgid "Video" -msgstr "Видео" - -#: ../gtk-glade/parameters.glade.h:13 -#, fuzzy -msgid "ALSA special device (optional):" -msgstr "Специальное устройство ALSA (необязательно)" - -#: ../gtk-glade/parameters.glade.h:14 -msgid "Add" -msgstr "Добавить" - -#: ../gtk-glade/parameters.glade.h:15 -#, fuzzy -msgid "Audio RTP/UDP:" -msgstr "Аудио RTP/UDP" - -#: ../gtk-glade/parameters.glade.h:16 -msgid "" -"Audio codecs\n" -"Video codecs" -msgstr "" -"Аудио кодеки\n" -" и Видео кодеки" - -#: ../gtk-glade/parameters.glade.h:18 -msgid "Behind NAT / Firewall (specify gateway IP below)" -msgstr "" - -#: ../gtk-glade/parameters.glade.h:19 -msgid "Behind NAT / Firewall (use STUN to resolve)" -msgstr "" - -#: ../gtk-glade/parameters.glade.h:21 -msgid "CIF" -msgstr "" - -#: ../gtk-glade/parameters.glade.h:22 -#, fuzzy -msgid "Capture device:" -msgstr "Устройство захвата" - -#: ../gtk-glade/parameters.glade.h:23 -msgid "Codecs" -msgstr "Кодеки" - -#: ../gtk-glade/parameters.glade.h:24 -msgid "Direct connection to the Internet" -msgstr "" - -#: ../gtk-glade/parameters.glade.h:25 -msgid "Disable" -msgstr "Выключить" - -#: ../gtk-glade/parameters.glade.h:26 -#, fuzzy -msgid "Done" -msgstr "Ушёл" - -#: ../gtk-glade/parameters.glade.h:27 -#, fuzzy -msgid "Download speed limit in Kbit/sec:" -msgstr "Исходящий поток kbit/sec" - -#: ../gtk-glade/parameters.glade.h:28 -msgid "Edit" -msgstr "Изменить" - -#: ../gtk-glade/parameters.glade.h:29 -msgid "Enable" -msgstr "Включить" - -#: ../gtk-glade/parameters.glade.h:30 -#, fuzzy -msgid "Enable echo cancellation" -msgstr "Включить подавление эхо" - -#: ../gtk-glade/parameters.glade.h:31 -msgid "Erase all passwords" -msgstr "Стереть все пароли" - -#: ../gtk-glade/parameters.glade.h:32 -msgid "Manage SIP Accounts" -msgstr "Управление SIP аккаунтами" - -#: ../gtk-glade/parameters.glade.h:33 -msgid "Multimedia settings" -msgstr "Настройка мультимедиа" - -#: ../gtk-glade/parameters.glade.h:34 -msgid "Network settings" -msgstr "Настройки сети" - -#: ../gtk-glade/parameters.glade.h:35 -#, fuzzy -msgid "Playback device:" -msgstr "Устройство воспроизведения" - -#: ../gtk-glade/parameters.glade.h:36 -msgid "Prefered video resolution:" -msgstr "" - -#: ../gtk-glade/parameters.glade.h:37 -#, fuzzy -msgid "Public IP address:" -msgstr "Публичный IP адрес" - -#: ../gtk-glade/parameters.glade.h:38 -msgid "" -"Register to FONICS\n" -"virtual network !" -msgstr "" -"Регистрация в FONICS\n" -"вирнтуальной сети!" - -#: ../gtk-glade/parameters.glade.h:40 -msgid "Remove" -msgstr "Удалить" - -#: ../gtk-glade/parameters.glade.h:41 -#, fuzzy -msgid "Ring device:" -msgstr "Устройство звонка" - -#: ../gtk-glade/parameters.glade.h:42 -#, fuzzy -msgid "Ring sound:" -msgstr "Звук звонка" - -#: ../gtk-glade/parameters.glade.h:43 -#, fuzzy -msgid "SIP (UDP):" -msgstr "SIP (UDP)" - -#: ../gtk-glade/parameters.glade.h:44 -msgid "Send DTMFs as SIP info" -msgstr "Отправить DTFMы как SIP инфо" - -#: ../gtk-glade/parameters.glade.h:45 -#, fuzzy -msgid "Set Maximum Transmission Unit:" -msgstr "Установка максимального числа передаваемых единиц" - -#: ../gtk-glade/parameters.glade.h:46 -msgid "Settings" -msgstr "" - -#: ../gtk-glade/parameters.glade.h:47 -#, fuzzy -msgid "Stun server:" -msgstr "Stun сервер" - -#: ../gtk-glade/parameters.glade.h:48 -msgid "This section defines your SIP address when not using a SIP account" -msgstr "Поле определяет ваш SIP адрес когда вы не используете SIP аккаунт" - -#: ../gtk-glade/parameters.glade.h:49 -#, fuzzy -msgid "Upload speed limit in Kbit/sec:" -msgstr "Входящий поток kbit/sec" - -#: ../gtk-glade/parameters.glade.h:50 -msgid "Use IPv6 instead of IPv4" -msgstr "Использовать IPv6 вместо IPv4" - -#: ../gtk-glade/parameters.glade.h:51 -#, fuzzy -msgid "User interface" -msgstr "Имя пользователя:" - -#: ../gtk-glade/parameters.glade.h:52 -#, fuzzy -msgid "Video RTP/UDP:" -msgstr "Видео RTP/UDP" - -#: ../gtk-glade/parameters.glade.h:53 -#, fuzzy -msgid "Video input device:" -msgstr "Видео устройсво вывода" - -#: ../gtk-glade/parameters.glade.h:54 -msgid "Your display name (eg: John Doe):" -msgstr "Ваше видимое имя (Иван Сидоров):" - -#: ../gtk-glade/parameters.glade.h:55 -msgid "Your resulting SIP address:" -msgstr "Ваш результирующий sip адрес:" - -#: ../gtk-glade/parameters.glade.h:56 -msgid "Your username:" -msgstr "Ваше имя пользователя:" - -#: ../gtk-glade/parameters.glade.h:57 -msgid "a sound card\n" -msgstr "звуковая карта\n" - -#: ../gtk-glade/parameters.glade.h:59 -msgid "default camera" -msgstr "камера по умолчаию" - -#: ../gtk-glade/parameters.glade.h:60 -msgid "default soundcard" -msgstr "звуковая карта по умолчанию" - -#: ../gtk-glade/parameters.glade.h:61 -msgid "default soundcard\n" -msgstr "звуковая карта по умолчанию\n" - -#: ../gtk-glade/parameters.glade.h:63 -msgid "gtk-go-down" -msgstr "Свернуть" - -#: ../gtk-glade/parameters.glade.h:64 -msgid "gtk-go-up" -msgstr "Развернуть" - -#: ../gtk-glade/parameters.glade.h:65 -msgid "gtk-media-play" -msgstr "Медиа-play" - -#: ../gtk-glade/buddylookup.glade.h:1 -msgid "Search somebody" -msgstr "" - -#: ../gtk-glade/buddylookup.glade.h:2 -msgid "Add to my list" -msgstr "" - -#: ../gtk-glade/buddylookup.glade.h:3 -msgid "Search contacts in directory" -msgstr "" - -#: ../gtk-glade/waiting.glade.h:1 -msgid "Linphone" -msgstr "Linphone" - -#: ../gtk-glade/waiting.glade.h:2 -msgid "Please wait" -msgstr "" - -#: ../coreapi/linphonecore.c:195 -#, fuzzy, c-format -msgid "You have missed %i call." -msgid_plural "You have missed %i calls." -msgstr[0] "У вас пропущено %i звонков." -msgstr[1] "У вас пропущено %i звонков." - -#: ../coreapi/linphonecore.c:223 -msgid "aborted" -msgstr "остановленный" - -#: ../coreapi/linphonecore.c:226 -msgid "completed" -msgstr "заверщённый" - -#: ../coreapi/linphonecore.c:229 -msgid "missed" -msgstr "пропущен" - -#: ../coreapi/linphonecore.c:234 -#, c-format -msgid "" -"%s at %s\n" -"From: %s\n" -"To: %s\n" -"Status: %s\n" -"Duration: %i mn %i sec\n" -msgstr "" -"%s в %s\n" -"От: %s\n" -"К: %s\n" -"Статус: %s\n" -"Длительность: %i мн %i сек\n" - -#: ../coreapi/linphonecore.c:235 -msgid "Outgoing call" -msgstr "Исходящие звонки" - -#: ../coreapi/linphonecore.c:445 -msgid "" -"Your machine appears to be connected to an IPv6 network. By default linphone " -"always uses IPv4. Please update your configuration if you want to use IPv6" -msgstr "" -"Похоже Ваш компьютер подключен по сети с IPv6. Linphone по умолчанию " -"использует IPv4. Пожалуйста, обновите настройки если хотите использовать " -"IPv6." - -#: ../coreapi/linphonecore.c:739 -msgid "Ready" -msgstr "Готов" - -#: ../coreapi/linphonecore.c:1014 -msgid "Remote end seems to have disconnected, the call is going to be closed." -msgstr "Удалённый узел отключился, звонок завершён." - -#: ../coreapi/linphonecore.c:1172 -msgid "Looking for telephone number destination..." -msgstr "Поиск назначения для телефонного номера.." - -#: ../coreapi/linphonecore.c:1174 -msgid "Could not resolve this number." -msgstr "Не может принять решение по этому номеру." - -#: ../coreapi/linphonecore.c:1239 -msgid "" -"Could not parse given sip address. A sip url usually looks like sip:" -"user@domain" -msgstr "" -"Не могу опознать sip адрес. SIP url обычно выглядит как: " - -#: ../coreapi/linphonecore.c:1340 -msgid "Sorry, having multiple simultaneous calls is not supported yet !" -msgstr "Извините, несколько одновременных вызовов не поддерживаются пока!" - -#: ../coreapi/linphonecore.c:1387 -msgid "Contacting" -msgstr "Соединение" - -#: ../coreapi/linphonecore.c:1402 -msgid "could not call" -msgstr "невозможно позвонить" - -#: ../coreapi/linphonecore.c:1787 ../coreapi/exevents.c:50 -msgid "Connected." -msgstr "Соединён." - -#: ../coreapi/linphonecore.c:1813 -msgid "Call ended" -msgstr "Разговор окончен" - -#: ../coreapi/linphonecore.c:2175 -msgid "No nat/firewall address supplied !" -msgstr "NAT/firewall адрес не установлен !" - -#: ../coreapi/linphonecore.c:2187 ../coreapi/linphonecore.c:2199 -#, c-format -msgid "Invalid nat address '%s' : %s" -msgstr "Неверный NAT адрес '%s' : '%s'" - -#: ../coreapi/misc.c:134 -msgid "" -"Your computer appears to be using ALSA sound drivers.\n" -"This is the best choice. However the pcm oss emulation module\n" -"is missing and linphone needs it. Please execute\n" -"'modprobe snd-pcm-oss' as root to load it." -msgstr "" -"Ваш компьютер использует ALSA звуковой драйвер.\n" -"Это лучший выбор. Однако, pcm oss модуль эмуляции\n" -"не найден и он нужен для linphone.\n" -"Пожалуйста, выполните от пользователя root 'modprobe snd-pcm-oss' чтоб " -"загрузить его." - -#: ../coreapi/misc.c:137 -msgid "" -"Your computer appears to be using ALSA sound drivers.\n" -"This is the best choice. However the mixer oss emulation module\n" -"is missing and linphone needs it. Please execute\n" -" 'modprobe snd-mixer-oss' as root to load it." -msgstr "" -"Ваш компьютер использует ALSA звуковой драйвер.\n" -"Это лучший выбор. Однако, oss микшера модуля\n" -"не найден и он нужен для linphone.\n" -"Пожалуйста, выполните от пользователя root 'modprobe snd-pcm-oss' чтоб " -"загрузить его." - -#: ../coreapi/misc.c:610 -msgid "Stun lookup in progress..." -msgstr "Поиск Stun продолжается..." - -#: ../coreapi/exevents.c:127 -msgid "Call terminated." -msgstr "Звонок прерван." - -#: ../coreapi/exevents.c:149 -msgid "Could not reach destination." -msgstr "Невозможно соединиться." - -#: ../coreapi/exevents.c:158 -msgid "User is busy." -msgstr "Пользователь занят." - -#: ../coreapi/exevents.c:159 -msgid "User is temporarily unavailable." -msgstr "Пользователь временно недоступен." - -#: ../coreapi/exevents.c:160 -msgid "Request Cancelled." -msgstr "Запрос отменён." - -#. char *retrymsg=_("%s. Retry after %i minute(s)."); -#: ../coreapi/exevents.c:162 -msgid "User does not want to be disturbed." -msgstr "Пользователь не хочет чтоб его беспокоили." - -#: ../coreapi/exevents.c:163 -msgid "Call declined." -msgstr "Звонок отклонён." - -#: ../coreapi/exevents.c:191 -msgid "Bad request" -msgstr "Неверный запрос" - -#: ../coreapi/exevents.c:194 -msgid "User cannot be found at given address." -msgstr "Пользователь не может быть найден." - -#: ../coreapi/exevents.c:197 -msgid "Remote user cannot support any of proposed codecs." -msgstr "" -"Удалённый пользователь не поддерживает ни одного из предложенных кодеков." - -#. time out, call leg is lost -#: ../coreapi/exevents.c:227 -msgid "Timeout." -msgstr "Время закончилось." - -#: ../coreapi/exevents.c:230 -msgid "Remote host was found but refused connection." -msgstr "Удалённый узел был найден, но отказал в соединении." - -#: ../coreapi/exevents.c:339 -msgid "is contacting you." -msgstr "контактирует с вами." - -#: ../coreapi/exevents.c:424 -#, c-format -msgid "Redirected to %s..." -msgstr "Перенаправлен на %s..." - -#: ../coreapi/exevents.c:440 -msgid "" -"User is not reachable at the moment but he invites you\n" -"to contact him using the following alternate resource:" -msgstr "" -"Пользователь не доступен в данный момент, но\n" -" приглашает Вас пообщаться на альтернативном ресурсе:" - -#: ../coreapi/exevents.c:861 -msgid "Early media." -msgstr "Прошлые медиа." - -#: ../coreapi/exevents.c:972 -#, c-format -msgid "Registration on %s failed: %s" -msgstr "Регистрация на %s не удалась: %s" - -#: ../coreapi/exevents.c:972 -msgid "no response timeout" -msgstr "нет ответа" - -#: ../coreapi/exevents.c:998 -#, c-format -msgid "Registration on %s successful." -msgstr "Регистрация на %s прошла успешно." - -#: ../coreapi/exevents.c:999 -#, fuzzy, c-format -msgid "Unregistration on %s done." -msgstr "Регистрация на %s прошла успешно." - -#. people for which we don't have yet an answer should appear as offline -#: ../coreapi/presence.c:112 ../coreapi/presence.c:164 ../coreapi/friend.c:147 -msgid "Gone" -msgstr "Ушёл" - -#: ../coreapi/presence.c:129 -msgid "Waiting for Approval" -msgstr "Ждать одобрения" - -#: ../coreapi/presence.c:133 ../coreapi/friend.c:38 -msgid "Online" -msgstr "В сети" - -#: ../coreapi/presence.c:137 ../coreapi/friend.c:41 -msgid "Busy" -msgstr "Занят" - -#: ../coreapi/presence.c:142 -msgid "Be Right Back" -msgstr "Скоро вернусь" - -#: ../coreapi/presence.c:146 ../coreapi/friend.c:47 -msgid "Away" -msgstr "Отошёл" - -#: ../coreapi/presence.c:151 -msgid "On The Phone" -msgstr "На телефоне" - -#: ../coreapi/presence.c:156 -msgid "Out To Lunch" -msgstr "На обеде" - -#: ../coreapi/presence.c:160 ../coreapi/friend.c:71 -msgid "Closed" -msgstr "Закрыто" - -#: ../coreapi/friend.c:35 -msgid "Unknown" -msgstr "" - -#: ../coreapi/friend.c:44 -#, fuzzy -msgid "Be right back" -msgstr "Скоро вернусь" - -#: ../coreapi/friend.c:50 -#, fuzzy -msgid "On the phone" -msgstr "На телефоне" - -#: ../coreapi/friend.c:53 -#, fuzzy -msgid "Out to lunch" -msgstr "На обеде" - -#: ../coreapi/friend.c:56 -msgid "Do not disturb" -msgstr "Не беспокоить" - -#: ../coreapi/friend.c:59 -msgid "Moved" -msgstr "" - -#: ../coreapi/friend.c:62 -msgid "Using another messaging service" -msgstr "" - -#: ../coreapi/friend.c:65 -#, fuzzy -msgid "Offline" -msgstr "В сети" - -#: ../coreapi/friend.c:68 -msgid "Pending" -msgstr "" - -#: ../coreapi/friend.c:74 -msgid "Unknown-bug" -msgstr "" - -#: ../coreapi/proxy.c:221 -msgid "" -"The sip proxy address you entered is invalid, it must start with \"sip:\" " -"followed by a hostname." -msgstr "" - -#: ../coreapi/proxy.c:227 -msgid "" -"The sip identity you entered is invalid.\n" -"It should look like sip:username@proxydomain, such as sip:alice@example.net" -msgstr "" - -#: ../coreapi/proxy.c:634 -#, fuzzy, c-format -msgid "Could not login as %s" -msgstr "Невозможно найти картинку: %s" - -#: ../mediastreamer2/src/alaw.c:144 ../mediastreamer2/src/alaw.c:162 -msgid "ITU-G.711 alaw encoder" -msgstr "" - -#: ../mediastreamer2/src/alaw.c:194 ../mediastreamer2/src/alaw.c:211 -msgid "ITU-G.711 alaw decoder" -msgstr "" - -#: ../mediastreamer2/src/alsa.c:923 -#, fuzzy -msgid "Alsa sound source" -msgstr "звуковая карта\n" - -#: ../mediastreamer2/src/alsa.c:1027 -msgid "Alsa sound output" -msgstr "" - -#: ../mediastreamer2/src/aqsnd.c:891 -msgid "Sound capture filter for MacOS X Audio Queue Service" -msgstr "" - -#: ../mediastreamer2/src/aqsnd.c:915 -msgid "Sound playback filter for MacOS X Audio Queue Service" -msgstr "" - -#: ../mediastreamer2/src/dtmfgen.c:173 ../mediastreamer2/src/dtmfgen.c:191 -msgid "DTMF generator" -msgstr "" - -#: ../mediastreamer2/src/gsm.c:70 ../mediastreamer2/src/gsm.c:88 -msgid "The GSM full-rate codec" -msgstr "" - -#: ../mediastreamer2/src/gsm.c:134 ../mediastreamer2/src/gsm.c:152 -msgid "The GSM codec" -msgstr "" - -#: ../mediastreamer2/src/macsnd.c:670 -msgid "Sound capture filter for MacOS X Core Audio drivers" -msgstr "" - -#: ../mediastreamer2/src/macsnd.c:684 -msgid "Sound playback filter for MacOS X Core Audio drivers" -msgstr "" - -#: ../mediastreamer2/src/msconf.c:787 ../mediastreamer2/src/msconf.c:805 -msgid "A filter to make conferencing" -msgstr "" - -#: ../mediastreamer2/src/msfileplayer.c:295 -#: ../mediastreamer2/src/msfileplayer.c:313 -msgid "Raw files and wav reader" -msgstr "" - -#: ../mediastreamer2/src/msfilerec.c:170 ../mediastreamer2/src/msfilerec.c:188 -#: ../mediastreamer2/src/msfilerec_win.c:216 -#: ../mediastreamer2/src/msfilerec_win.c:234 -msgid "Wav file recorder" -msgstr "" - -#: ../mediastreamer2/src/msjoin.c:45 ../mediastreamer2/src/msjoin.c:63 -msgid "A filter that send several inputs to one output." -msgstr "" - -#: ../mediastreamer2/src/msresample.c:221 -#: ../mediastreamer2/src/msresample.c:239 -msgid "frequency resampler" -msgstr "" - -#: ../mediastreamer2/src/msrtp.c:233 ../mediastreamer2/src/msrtp.c:251 -msgid "RTP output filter" -msgstr "" - -#: ../mediastreamer2/src/msrtp.c:348 ../mediastreamer2/src/msrtp.c:366 -msgid "RTP input filter" -msgstr "" - -#: ../mediastreamer2/src/msspeex.c:359 ../mediastreamer2/src/msspeex.c:377 -#: ../mediastreamer2/src/msspeex.c:504 ../mediastreamer2/src/msspeex.c:522 -msgid "The free and wonderful speex codec" -msgstr "" - -#: ../mediastreamer2/src/msvolume.c:390 ../mediastreamer2/src/msvolume.c:405 -msgid "A filter that controls and measure sound volume" -msgstr "" - -#: ../mediastreamer2/src/msv4l.c:1009 -msgid "A video4linux compatible source filter to stream pictures." -msgstr "" - -#: ../mediastreamer2/src/msv4l2.c:458 -msgid "A filter to grab pictures from Video4Linux2-powered cameras" -msgstr "" - -#: ../mediastreamer2/src/nowebcam.c:1780 -msgid "A filter that outputs a static image." -msgstr "" - -#: ../mediastreamer2/src/oss.c:567 -msgid "Sound capture filter for OSS drivers" -msgstr "" - -#: ../mediastreamer2/src/oss.c:581 -msgid "Sound playback filter for OSS drivers" -msgstr "" - -#: ../mediastreamer2/src/pixconv.c:173 ../mediastreamer2/src/pixconv.c:191 -msgid "A pixel format converter" -msgstr "" - -#: ../mediastreamer2/src/sizeconv.c:204 -msgid "A video size converter" -msgstr "" - -#: ../mediastreamer2/src/sizeconv.c:222 -msgid "a small video size converter" -msgstr "" - -#: ../mediastreamer2/src/speexec.c:349 ../mediastreamer2/src/speexec.c:367 -msgid "Echo canceler using speex library" -msgstr "" - -#: ../mediastreamer2/src/tee.c:80 ../mediastreamer2/src/tee.c:98 -msgid "A filter that reads from input and copy to its multiple outputs." -msgstr "" - -#: ../mediastreamer2/src/theora.c:375 -msgid "The theora video encoder from xiph.org" -msgstr "" - -#: ../mediastreamer2/src/theora.c:393 -msgid "The open-source and royalty-free 'theora' video codec from xiph.org" -msgstr "" - -#: ../mediastreamer2/src/theora.c:561 ../mediastreamer2/src/theora.c:579 -msgid "The theora video decoder from xiph.org" -msgstr "" - -#: ../mediastreamer2/src/ulaw.c:146 ../mediastreamer2/src/ulaw.c:164 -msgid "ITU-G.711 ulaw encoder" -msgstr "" - -#: ../mediastreamer2/src/ulaw.c:196 ../mediastreamer2/src/ulaw.c:214 -msgid "ITU-G.711 ulaw decoder" -msgstr "" - -#: ../mediastreamer2/src/videodec.c:655 ../mediastreamer2/src/videodec.c:671 -#: ../mediastreamer2/src/videodec.c:754 ../mediastreamer2/src/videodec.c:770 -msgid "A H.263 decoder using ffmpeg library" -msgstr "" - -#: ../mediastreamer2/src/videodec.c:688 -msgid "A MPEG4 decoder using ffmpeg library" -msgstr "" - -#: ../mediastreamer2/src/videodec.c:704 -msgid "A RTP/JPEG decoder using ffmpeg library" -msgstr "" - -#: ../mediastreamer2/src/videodec.c:720 -msgid "A MJPEG decoder using ffmpeg library" -msgstr "" - -#: ../mediastreamer2/src/videodec.c:736 -msgid "A snow decoder using ffmpeg library" -msgstr "" - -#: ../mediastreamer2/src/videoenc.c:840 ../mediastreamer2/src/videoenc.c:922 -msgid "A video H.263 encoder using ffmpeg library." -msgstr "" - -#: ../mediastreamer2/src/videoenc.c:856 -msgid "" -"A video H.263 encoder using ffmpeg library. It is compliant with old RFC2190 " -"spec." -msgstr "" - -#: ../mediastreamer2/src/videoenc.c:872 ../mediastreamer2/src/videoenc.c:954 -msgid "A video MPEG4 encoder using ffmpeg library." -msgstr "" - -#: ../mediastreamer2/src/videoenc.c:888 -msgid "A video snow encoder using ffmpeg library." -msgstr "" - -#: ../mediastreamer2/src/videoenc.c:904 -msgid "A RTP/MJPEG encoder using ffmpeg library." -msgstr "" - -#: ../mediastreamer2/src/videoenc.c:938 -msgid "" -"A video H.263 encoder using ffmpeg library, compliant with old RFC2190 spec." -msgstr "" - -#: ../mediastreamer2/src/videoenc.c:970 -msgid "" -"The snow codec is royalty-free and is open-source. \n" -"It uses innovative techniques that makes it one of most promising video " -"codec. It is implemented within the ffmpeg project.\n" -"However it is under development, quite unstable and compatibility with other " -"versions cannot be guaranteed." -msgstr "" - -#: ../mediastreamer2/src/videoenc.c:990 -msgid "A MJPEG encoder using ffmpeg library." -msgstr "" - -#: ../mediastreamer2/src/videoout.c:974 ../mediastreamer2/src/videoout.c:992 -msgid "A generic video display" -msgstr "" - -#: ../mediastreamer2/src/wincevideods.c:966 -#: ../mediastreamer2/src/wincevideods.c:984 -#: ../mediastreamer2/src/winvideo.c:596 ../mediastreamer2/src/winvideo.c:614 -#: ../mediastreamer2/src/winvideods.c:1306 -#: ../mediastreamer2/src/winvideods.c:1324 -msgid "A video4windows compatible source filter to stream pictures." -msgstr "" - -#: ../mediastreamer2/src/winvideo2.c:436 ../mediastreamer2/src/winvideo2.c:454 -msgid "A video for windows (vfw.h) based source filter to grab pictures." -msgstr "" - -#: ../mediastreamer2/src/ice.c:1349 ../mediastreamer2/src/ice.c:1367 -msgid "ICE filter" -msgstr "" - -#: ../mediastreamer2/src/void.c:35 ../mediastreamer2/src/void.c:52 -msgid "A filter that trashes its input (useful for terminating some graphs)." -msgstr "" - -#: ../mediastreamer2/src/equalizer.c:337 ../mediastreamer2/src/equalizer.c:355 -msgid "Parametric sound equalizer." -msgstr "" - -#: ../mediastreamer2/src/msdscap-mingw.cc:1003 -msgid "A webcam grabber based on directshow." -msgstr "" - -#~ msgid "Show debug window" -#~ msgstr "Показать окно ошибок" - -#~ msgid "_View" -#~ msgstr "_Вид" - -#~ msgid "gtk-about" -#~ msgstr "О программе" - -#~ msgid "gtk-help" -#~ msgstr "Помощь" - -#~ msgid "gtk-preferences" -#~ msgstr "Параметры" - -#~ msgid "" -#~ "Show All\n" -#~ "Show Online" -#~ msgstr "" -#~ "Показать все\n" -#~ "Показать Online" - -#~ msgid "Search:" -#~ msgstr "Поиск:" - -#~ msgid "Display filters" -#~ msgstr "Показать фильтры" - -#~ msgid "I'm not behing a firewall" -#~ msgstr "Я не за firewall" - -#~ msgid "I'm behind a firewall, use supplied public IP address" -#~ msgstr "Я за firewall, использовать доступный IP адрес" - -#~ msgid "Use the supplied stun server above and do as best as possible" -#~ msgstr "Использовать доступный Stun сервер и делать так хорошо как возможно" - -#~ msgid "Miscelaneous" -#~ msgstr "Разное" - -#~ msgid "Go" -#~ msgstr "Старт" - -#~ msgid "Address book" -#~ msgstr "Адресная книга" - -#~ msgid "Shows calls" -#~ msgstr "Показать звонки" - -#~ msgid "Exit" -#~ msgstr "Выход" - -#~ msgid "Help" -#~ msgstr "Помощь" - -#~ msgid "Shows the address book" -#~ msgstr "Показать адресную книгу" - -#~ msgid "..." -#~ msgstr "..." - -#~ msgid "Proxy to use:" -#~ msgstr "Какой узел использовать:" - -#~ msgid "" -#~ "Call or\n" -#~ "answer" -#~ msgstr "" -#~ "Позвонить\n" -#~ "или ответить" - -#~ msgid "" -#~ "Hangup\n" -#~ "or refuse" -#~ msgstr "" -#~ "Прервать\n" -#~ "или отказать" - -#~ msgid "Or chat !" -#~ msgstr "Или Чат ! " - -#~ msgid "Show more..." -#~ msgstr "Показать больше..." - -#~ msgid "Playback level:" -#~ msgstr "Уровень воспроизведения:" - -#~ msgid "Recording level:" -#~ msgstr "Уровень записи:" - -#~ msgid "Ring level:" -#~ msgstr "Уровень звонка:" - -#~ msgid "Controls" -#~ msgstr "Управление" - -#~ msgid "Reachable" -#~ msgstr "Доступен" - -#~ msgid "Busy, I'll be back in " -#~ msgstr "Занят, я вернусь через " - -#~ msgid "The other party will be informed that you'll be back in X minutes" -#~ msgstr "Другая часть информирует, что Вы вернётесь через X минут" - -#~ msgid "mn" -#~ msgstr "мн" - -#~ msgid "Moved temporarily" -#~ msgstr "Временно переехал" - -#~ msgid "Alternative service" -#~ msgstr "Альтернативный сервис" - -#~ msgid "URL:" -#~ msgstr "URL:" - -#~ msgid "Presence" -#~ msgstr "Статус" - -#~ msgid "Press digits to send DTMFs." -#~ msgstr "Введите цифры, чтоб отправить DTMF." - -#~ msgid "" -#~ " 3\n" -#~ "def" -#~ msgstr "" -#~ " 3\n" -#~ "где" - -#~ msgid "" -#~ " 2\n" -#~ "abc" -#~ msgstr "" -#~ " 2\n" -#~ "абв" - -#~ msgid "" -#~ " 4\n" -#~ "ghi" -#~ msgstr "" -#~ " 4\n" -#~ "жзи" - -#~ msgid "" -#~ " 5\n" -#~ "jkl" -#~ msgstr "" -#~ " 5\n" -#~ "клм" - -#~ msgid "" -#~ " 6\n" -#~ "mno" -#~ msgstr "" -#~ " 6\n" -#~ "ноп" - -#~ msgid "" -#~ " 7\n" -#~ "pqrs" -#~ msgstr "" -#~ " 7\n" -#~ "рст" - -#~ msgid "" -#~ " 8\n" -#~ "tuv" -#~ msgstr "" -#~ " 8\n" -#~ "уфх" - -#~ msgid "" -#~ " 9\n" -#~ "wxyz" -#~ msgstr "" -#~ " 9\n" -#~ "шюя" - -#~ msgid "DTMF" -#~ msgstr "DTMF" - -#~ msgid "My online friends" -#~ msgstr "Мои друзья онлайн:" - -#~ msgid "" -#~ "C: 2001\n" -#~ "Made in Old Europe" -#~ msgstr "" -#~ "C: 2001\n" -#~ "Сделано в старой Европе" - -#~ msgid "" -#~ "Linphone is a web-phone.\n" -#~ "It is compatible with SIP and RTP protocols." -#~ msgstr "" -#~ "Linphone - это интернет телефон.\n" -#~ "Он совместим с SIP и RTP протоколами." - -#~ msgid "http://www.linphone.org" -#~ msgstr "http://www.linphone.org/" - -#~ msgid "Use IPv6 network (if available)" -#~ msgstr "Использовать IPv6 сеть (если доступно)" - -# msgstr "Teilnehmer zur Zeit nicht ansprechbar." -#~ msgid "" -#~ "Toggle this if you are on an ipv6 network and you wish linphone to use it." -#~ msgstr "Отметьте, если Вы в сети с ipv6 и будите использовать linphone." - -#~ msgid "Global" -#~ msgstr "Основные" - -#~ msgid "" -#~ "These options is only for users in a private network, behind a gateway. " -#~ "If you are not in this situation, then leave this empty." -#~ msgstr "" -#~ "Эта опция используется в частных сетях, за шлюзом. Если вы не в этой " -#~ "ситуации, просто оставьте пустой." - -#~ msgid "No firewall" -#~ msgstr "Нет firewall'a" - -#~ msgid "Use this STUN server to guess firewall address :" -#~ msgstr "Используйте этот STUN сервер чтоб определить адрес firewall :" - -#~ msgid "Specify firewall address manually:" -#~ msgstr "Определить адрес Firewall вручную:" - -#~ msgid "NAT traversal options (experimental)" -#~ msgstr "NAT опции (экспериментально)" - -#~ msgid "Number of buffered miliseconds (jitter compensation):" -#~ msgstr "Число милисекунд для буферизации (компенсация дрожания):" - -#~ msgid "RTP port used for audio:" -#~ msgstr "RTP порт для аудио:" - -#~ msgid "RTP properties" -#~ msgstr "RTP свойства" - -#~ msgid "Use SIP INFO message instead of RTP rfc2833 for DTMF transmitting" -#~ msgstr "" -#~ "Используйте SIP INFO сообщения вместо RTP rfc2833 для DTMF препровождения" - -#~ msgid "RTP-RFC2833 is the recommended way." -#~ msgstr "RTP-RFC2833 рекомендуемый." - -#~ msgid "Other" -#~ msgstr "Другое" - -#~ msgid "micro" -#~ msgstr "Микрофон" - -#~ msgid "Recording source:" -#~ msgstr "Источник записи:" - -#~ msgid "Enable echo-canceler (cancels the echo heard by the remote party)" -#~ msgstr "" -#~ "Включить подавление эхо (подавляет эхо слышимое с удалённого устройства)" - -#~ msgid "Choose file" -#~ msgstr "Выберите файл" - -#~ msgid "Listen" -#~ msgstr "Слушать" - -#~ msgid "Sound properties" -#~ msgstr "Настройки звука" - -#~ msgid "Sound device" -#~ msgstr "Устройство звука" - -#~ msgid "Run sip user agent on port:" -#~ msgstr "Запустить \"user agent\" на порту:" - -#~ msgid "It is strongly recommended to use port 5060." -#~ msgstr "Рекомендуется использовать порт 5060." - -#~ msgid "SIP port" -#~ msgstr "SIP порт" - -#~ msgid "@" -#~ msgstr "@" - -#~ msgid "Identity" -#~ msgstr "Личность" - -#~ msgid "Add proxy/registrar" -#~ msgstr "Добавить прокси/регистратора" - -#~ msgid "Remote services" -#~ msgstr "Удалённые сервисы" - -#~ msgid "Clear all stored authentication information (username,password...)" -#~ msgstr "Удалить всю информацию аунтефикации (логин, пароль...)" - -#~ msgid "Authentication information" -#~ msgstr "Информация аунтефикации" - -#~ msgid "SIP" -#~ msgstr "SIP" - -#~ msgid "List of audio codecs, in order of preference:" -#~ msgstr "Список аудио кодеков в приоритетном порядке:" - -#~ msgid "" -#~ "Note: Codecs in red are not usable regarding to your connection type to " -#~ "the internet." -#~ msgstr "" -#~ "Заметка: Кодеки отмеченные красным не подходят для вашего соединения в " -#~ "Internet." - -#~ msgid "No information availlable" -#~ msgstr "Информация недоступна" - -#~ msgid "Codec information" -#~ msgstr "Информация о кодеке" - -#~ msgid "Address Book" -#~ msgstr "Адресная книга" - -#~ msgid "Select" -#~ msgstr "Выбор" - -#~ msgid "" -#~ "User is not reachable at the moment but he invites you to contact him " -#~ "using the following alternate ressource:" -#~ msgstr "" -#~ "Пользователь не доступен в данный момент, но приглашает пообщаться на " -#~ "альтернативном ресурсе:" - -#~ msgid "None." -#~ msgstr "Нет." - -#~ msgid "Proxy/Registrar configuration box" -#~ msgstr "Прокси/Регистратор конфигуратор" - -#~ msgid "Send registration:" -#~ msgstr "Отправить регистрацию:" - -#~ msgid "Name:" -#~ msgstr "Имя:" - -#~ msgid "Subscribe policy:" -#~ msgstr "Правило подписки:" - -#~ msgid "Send subscription (see person's online status)" -#~ msgstr "Отправить подписку (смотреть статус персоны в сети)" - -#~ msgid "New incoming subscription" -#~ msgstr "Подтверждение новой подписки" - -#~ msgid "You have received a new subscription..." -#~ msgstr "Вы получили новое подтверждение..." - -#~ msgid "Refuse" -#~ msgstr "Отказать" - -#~ msgid "Authentication required for realm" -#~ msgstr "Регистрация для" - -#~ msgid "userid:" -#~ msgstr "ID пользователя:" - -#~ msgid "realm:" -#~ msgstr "Название:" - -#~ msgid "Linphone - Call history" -#~ msgstr "Linphone - История звонков" - -#~ msgid "Chat Room" -#~ msgstr "Комната чата" - -#~ msgid "Text:" -#~ msgstr "Текст" - -#~ msgid "The caller asks for resource reservation. Do you agree ?" -#~ msgstr "" -#~ "Вызывающий абонент спрашивает о резервировании ресурса. Вы согласны ?" - -#~ msgid "" -#~ "The caller doesn't use resource reservation. \t\t\t\t\tDo you wish to " -#~ "continue anyway ?" -#~ msgstr "" -#~ "Вызывающий не использует резервирование ресурса. \t\t\t\t\tВы всё равно " -#~ "желаете продолжить?" - -#~ msgid "linphone - receiving call from %s" -#~ msgstr "Linphone - принял звонок от %s" - -#~ msgid "" -#~ "You have received a subscription from %s.This means that this person " -#~ "wishes to be notified of your presence information (online, busy, " -#~ "away...).\n" -#~ "Do you agree ?" -#~ msgstr "" -#~ "Вы получили запрос на подключение от %s. Это значит что этот человек " -#~ "хочет знать ваш статус (онлайн, занят, отошёл...).\n" -#~ "Вы согласны ?" - -#~ msgid "Authentication required for realm %s" -#~ msgstr "Регистрация для %s" - -#~ msgid "None" -#~ msgstr "Нет" - -#~ msgid "Wait" -#~ msgstr "Подождать" - -#~ msgid "Deny" -#~ msgstr "Отказать" - -#~ msgid "Bad sip address: a sip address looks like sip:user@domain" -#~ msgstr "Неправильный sip адрес, он выглядит как: " - -#~ msgid "Stun lookup done..." -#~ msgstr "Поиск Stun завершён..." - -#~ msgid "enter sip uri here" -#~ msgstr "Sip URI eingeben" - -#~ msgid "User manual" -#~ msgstr "Anwender-Handbuch" - -#~ msgid "Ring sound selection" -#~ msgstr "Klingelton ausw�len" - -#~ msgid "Communication ended." -#~ msgstr "Kommunikation beendet." - -#~ msgid "Call cancelled." -#~ msgstr "Anruf annulliert" - -#, fuzzy -#~ msgid "Firewall 's external ip address (in dot notations):" -#~ msgstr "IP-Adresse des Firewall (in Punktnotation)" - -#, fuzzy -#~ msgid "Server address" -#~ msgstr "Server-Adresse:" - -#~ msgid "28k modem" -#~ msgstr "28K Modem" - -#~ msgid "56k modem" -#~ msgstr "56K Modem" - -#~ msgid "64k modem (numeris)" -#~ msgstr "64K Modem (ISDN)" - -#~ msgid "ADSL or Cable modem" -#~ msgstr "ADSL oder Kabel-Modem" - -#~ msgid "Ethernet or equivalent" -#~ msgstr "Ethernet oder �uivalent" - -#~ msgid "Connection type:" -#~ msgstr "Verbindungstyp:" - -#, fuzzy -#~ msgid "" -#~ "Linphone could not open audio device %s. Check if your sound card is " -#~ "fully configured and working." -#~ msgstr "" -#~ "Linphone kann das Soundger� nicht �fnen. Prfen Sie nach, ob dieSoundkarte " -#~ "vollst�dig konfiguriert und funktionsf�ig ist." - -#~ msgid "Type here the sip address of the person you want to call." -#~ msgstr "" -#~ "Geben Sie die Sip-Adresse des Anwenders, den Sie anrufen m�hten, hier ein." - -#~ msgid "" -#~ "Release or\n" -#~ "Refuse" -#~ msgstr "" -#~ "Auflegen oder\n" -#~ "Abweisen" - -#~ msgid "%s. Retry after %i minute(s)." -#~ msgstr "%s. In %i Minuten wieder versuchen." - -#~ msgid "Timeout..." -#~ msgstr "Zeitberschreitung..." - -#, fuzzy -#~ msgid "" -#~ "Add address\n" -#~ "book" -#~ msgstr "Adressbuch" - -#~ msgid "Toggle this if you want to be registered on a remote server." -#~ msgstr "" -#~ "Bitte ankreuzen, wenn Sie auf einem Sip-Server registriert werden wollen." - -#~ msgid "Address of record:" -#~ msgstr "Adresse des Eintrags:" - -#~ msgid "" -#~ "The password used for registration. On some servers it is not necessary" -#~ msgstr "" -#~ "Passwort fr die Registrierung. Bei manchen Servern nicht erforderlich." - -#~ msgid "Use this registrar server as outbound proxy." -#~ msgstr "Verwenden Sie diesen Registrarserver als externen proxy." - -#~ msgid "sip address:" -#~ msgstr "SIP-Adresse:" - -#~ msgid "Modify" -#~ msgstr "�dern" - -#~ msgid "Registering..." -#~ msgstr "Registrierung" - -#~ msgid "" -#~ "You are currently using the i810_audio driver.\n" -#~ "This driver is buggy and so does not work with Linphone.\n" -#~ "We suggest that you replace it by its equivalent ALSA driver,\n" -#~ "either with packages from your distribution, or by downloading\n" -#~ "ALSA drivers at http://www.alsa-project.org." -#~ msgstr "" -#~ "Sie verwenden zur Zeit den i810_audio Treiber.\n" -#~ "Diese Treiber ist fehlerhaft und funktioniert nicht mit Linphone\n" -#~ "Wir empfehlen, den Treiber entweder durch das ALSA-Treiber-Paket von " -#~ "ihrer Distribution\n" -#~ "zu ersetzen oder die gewnschten ALSA-Treiber von http://www.alsa-project." -#~ "org\n" -#~ "zu beziehen und zu installieren" - -#~ msgid "Unregistration successfull." -#~ msgstr "Abmeldung erfolgreich." - -#~ msgid "Select network interface to use:" -#~ msgstr "Netzwerkschnittstelle w�len:" - -#~ msgid "Network interface properties" -#~ msgstr "Eigenschaften der Netzwerkschnittstelle" - -#~ msgid "RTP" -#~ msgstr "RTP" - -#~ msgid "C: 2001" -#~ msgstr "April 2001" - -#~ msgid "Threads not supported by glib. Upgrade your glib.\n" -#~ msgstr "" -#~ "Threads werden von glib nicht untersttzt. Bitte aktualisieren Sie Ihre " -#~ "glib.\n" - -#~ msgid "Run linphone as a gnome-applet." -#~ msgstr "Linphone als gnome-Applet ausfhren." - -#~ msgid "Run linphone as a daemon (for use without gnome)." -#~ msgstr "Linphone als daemon ausfhren (Verwendung ohne Gnome)." - -#~ msgid "" -#~ "Cannot find network previously used interface %s.\n" -#~ "If your computer is temporary connected to the internet, please connect " -#~ "and then run linphone.\n" -#~ "If you want to change your default network interface, go to the " -#~ "parameters 'box." -#~ msgstr "" -#~ "Linphone konnte die zuvor verwendete Netzwerkschnittstelle %s nicht " -#~ "finden.\n" -#~ "Wenn linphone nur tempor� am Internet angeschlossen ist, stellen Sie eine " -#~ "Verbindung her und rufen Sie linphone erneut auf.\n" -#~ "Wenn Sie die vorgegebene Netzwerkschnittstelle �dern wollen, w�len Sie " -#~ "bitte \"Einstellungen\"." - -#~ msgid "" -#~ "Linphone cannot open the audio device.\n" -#~ "It may be caused by other programs using it.\n" -#~ "Do you want linphone to kill these programs (esd or artsd) ?" -#~ msgstr "" -#~ "Linphone kann die Soundschnittstelle nicht �fnen.\n" -#~ "Dies kann durch andere Applikationen verursacht sein.\n" -#~ "M�hten sie diese Programme (esd oder artsd) beenden?" - -#~ msgid "Use it as a:" -#~ msgstr "Verwenden als:" - -#~ msgid "Outbound proxy" -#~ msgstr "Ausgehender Proxy-Server" - -#~ msgid "" -#~ "Toggle this button if the registrar must be used to proxy calls through a " -#~ "firewall." -#~ msgstr "" -#~ "Verwenden Sie diesen Knopf, falls der Registrar zum Tunneln durch einen " -#~ "Firewall verwendet werden mu�" - -#~ msgid "kbit/s" -#~ msgstr "Kbits/s" - -#~ msgid "OSS" -#~ msgstr "OSS" - -#~ msgid "ALSA" -#~ msgstr "ALSA" - -#~ msgid "Automatically kill applications using soundcard when needed" -#~ msgstr "Applikationen die die Soundkarte verwenden, automatisch beenden." - -#~ msgid "" -#~ "Your computer is connected to several networks. Check in the global " -#~ "parameters if Linphone uses the one that you want." -#~ msgstr "" -#~ "Ihr Rechner ist an mehere Netze angeschlossen. Stellen Sie sicher, da�in " -#~ "den Globalen Parametern die richtige Schnittstelle selektiert ist." - -#~ msgid "" -#~ "Linphone failed to open the sound device. See the README file included in " -#~ "the distribution for details." -#~ msgstr "" -#~ "Linphone konnte die Soundschnittstelle nicht �fnen. Weitere Informationen " -#~ "finden Sie in der README-Datei (enthalten in der Distribution)." - -#~ msgid "Interface not found." -#~ msgstr "Schnittstelle nicht gefunden." - -#~ msgid "Warning" -#~ msgstr "Warnung" - -#~ msgid "" -#~ "Linphone cannot open the sound device. It may be caused by other programs " -#~ "using it. Do you want linphone to kill these programs (esd or artsd) ?" -#~ msgstr "" -#~ "Linphone kann die Soundschnittstelle nicht �fnen. Dies kann durch andere " -#~ "Applikationen verursacht sein. M�hten sie diese Programme (esd oder " -#~ "artsd) beenden?" - -#~ msgid "Linphone shutdowns..." -#~ msgstr "Linphone Ende..." - -#~ msgid "" -#~ "Please, wait a few seconds untils linphone unregisters your sip addess " -#~ "from registrar server..." -#~ msgstr "Bitte einige Sekunden warten, bis Sip-Adresse ausgetragen ist." - -#~ msgid "Bad formuled sip address." -#~ msgstr "SIP-Adresse fehlerhaft." - -#~ msgid "Couldn't create pixmap from file: %s" -#~ msgstr "Konnte Pixmap nicht aus Datei %s erzeugen." - -#~ msgid "" -#~ "Linphone did not detect any valid network interface. If you use a " -#~ "temporary internet connection, please connect and then run linphone again." -#~ msgstr "" -#~ "Linphone konnte keine Netzwerkschnittstelle finden. Wenn Sie nur eine " -#~ "tempor�e Internetverbindung haben, bitte erneut eine Internetverbindung " -#~ "herstellen und linphone nochmals starten." - -#~ msgid "List of network interfaces on your system." -#~ msgstr "Vorhandene Netzwerkschnittstellen ihres Systems" From 40e4b5d421a5f53bb87528123d84f778caa24915 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Tue, 26 Jan 2010 22:31:33 +0100 Subject: [PATCH 05/50] work in progress in sal. Near to code complete, except for subscribe/notify. --- coreapi/offeranswer.c | 8 +- coreapi/sal.h | 94 +++- coreapi/sal_eXosip2.c | 959 +++++++++++++++++++++++++++++++++++++- coreapi/sal_eXosip2_sdp.c | 15 +- 4 files changed, 1044 insertions(+), 32 deletions(-) diff --git a/coreapi/offeranswer.c b/coreapi/offeranswer.c index 03c134143..3e872c6e1 100644 --- a/coreapi/offeranswer.c +++ b/coreapi/offeranswer.c @@ -99,9 +99,9 @@ static void initiate_incoming(const SalStreamDescription *local_cap, SalStreamDescription *result){ result->payloads=match_payloads(local_cap->payloads,remote_offer->payloads); if (result->payloads && !only_telephone_event(result->payloads)){ - result->port=remote_offer->port; - result->bandwidth=remote_offer->bandwidth; - result->ptime=remote_offer->ptime; + result->port=local_cap->port; + result->bandwidth=local_cap->bandwidth; + result->ptime=local_cap->ptime; }else{ result->port=0; } @@ -136,7 +136,7 @@ int offer_answer_initiate_incoming(const SalMediaDescription *local_capabilities initiate_incoming(&local_capabilities->streams[i],&remote_offer->streams[i],&result->streams[i]); } result->nstreams=local_capabilities->nstreams; - strcpy(result->addr,remote_offer->addr); + strcpy(result->addr,local_capabilities->addr); return 0; } diff --git a/coreapi/sal.h b/coreapi/sal.h index 1eb93cc2e..a613cf71e 100644 --- a/coreapi/sal.h +++ b/coreapi/sal.h @@ -36,6 +36,29 @@ struct SalOp; typedef struct SalOp SalOp; +struct SalAddress; + +typedef struct SalAddress SalAddress; + +/* Address manipulation API*/ +SalAddress * sal_address_new(const char *uri); +SalAddress * sal_address_clone(const SalAddress *addr); +const char *sal_address_get_scheme(const SalAddress *addr); +const char *sal_address_get_display_name(const SalAddress* addr); +const char *sal_address_get_username(const SalAddress *addr); +const char *sal_address_get_domain(const SalAddress *addr); +void sal_address_set_display_name(SalAddress *addr, const char *display_name); +void sal_address_set_username(SalAddress *addr, const char *username); +void sal_address_set_domain(SalAddress *addr, const char *host); +void sal_address_set_port(SalAddress *addr, const char *port); +void sal_address_set_port_int(SalAddress *uri, int port); +void sal_address_clean(SalAddress *addr); +char *sal_address_as_string(const SalAddress *u); +char *sal_address_as_string_uri_only(const SalAddress *u); +void sal_address_destroy(SalAddress *u); + + + Sal * sal_init(); void sal_uninit(Sal* sal); @@ -92,26 +115,81 @@ typedef struct SalOpBase{ typedef enum SalError{ - SalErrorNetwork, + SalErrorNoResponse, SalErrorMedia, - SalErrorAuth, - SalErrorForbidden + SalErrorFailure, /* see SalReason for more details */ + SalErrorUnknown } SalError; +typedef enum SalReason{ + SalReasonDeclined, + SalReasonBusy, + SalReasonRedirect, + SalReasonTemporarilyUnavailable, + SalReasonNotFound, + SalReasonDoNotDisturb, + SalReasonForbidden, + SalReasonUnknown +}SalReason; + +typedef enum SalPresenceStatus{ + SalPresenceOffline, + SalPresenceOnline, + SalPresenceBusy, + SalPresenceBerightback, + SalPresenceAway, + SalPresenceOnthephone, + SalPresenceOuttolunch, + SalPresenceDonotdisturb, + SalPresenceMoved, + SalPresenceAltService, +}SalPresenceStatus; + typedef void (*SalOnCallReceived)(SalOp *op); typedef void (*SalOnCallRinging)(SalOp *op); typedef void (*SalOnCallAccepted)(SalOp *op); +typedef void (*SalOnCallAck)(SalOp *op); +typedef void (*SalOnCallUpdated)(SalOp *op); typedef void (*SalOnCallTerminated)(SalOp *op); -typedef void (*SalOnCallFailure)(SalOp *op, SalError error, const char *details); +typedef void (*SalOnCallFailure)(SalOp *op, SalError error, SalReason reason, const char *details); +typedef void (*SalOnAuthRequested)(SalOp *op, const char *realm, const char *username); +typedef void (*SalOnAuthSuccess)(SalOp *op, const char *realm, const char *username); +typedef void (*SalOnRegisterSuccess)(SalOp *op, bool_t registered); +typedef void (*SalOnRegisterFailure)(SalOp *op, SalError error, SalReason reason, const char *details); +typedef void (*SalOnVfuRequest)(SalOp *op); +typedef void (*SalOnDtmfReceived)(SalOp *op, char dtmf); +typedef void (*SalOnRefer)(Sal *sal, SalOp *op, const char *referto); +typedef void (*SalOnTextReceived)(Sal *sal, const char *from, const char *msg); +typedef void (*SalOnPresenceChanged)(Sal *sal, const char *from, SalPresenceStatus status); +typedef void (*SalOnInternalMsg)(Sal *sal, const char *msg); typedef struct SalCallbacks{ SalOnCallReceived call_received; SalOnCallRinging call_ringing; SalOnCallAccepted call_accepted; + SalOnCallAck call_ack; + SalOnCallUpdated call_updated; SalOnCallTerminated call_terminated; SalOnCallFailure call_failure; + SalOnAuthRequested auth_requested; + SalOnAuthSuccess auth_success; + SalOnRegisterSuccess register_success; + SalOnRegisterFailure register_failure; + SalOnVfuRequest vfu_request; + SalOnDtmfReceived dtmf_received; + SalOnRefer refer_received; + SalOnTextReceived text_received; + SalOnPresenceChanged presence_changed; + SalOnInternalMsg internal_message; }SalCallbacks; +typedef struct SalAuthInfo{ + char *username; + char *userid; + char *password; + char *realm; +}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); void sal_set_user_agent(Sal *ctx, const char *user_agent); @@ -127,15 +205,21 @@ void sal_op_set_route(SalOp *op, const char *route); void sal_op_set_from(SalOp *op, const char *from); void sal_op_set_to(SalOp *op, const char *to); void sal_op_release(SalOp *h); +void sal_op_authenticate(SalOp *h, const SalAuthInfo *info); + +const char *sal_op_get_from(const SalOp *op); +const char *sal_op_get_to(const SalOp *op); +const char *sal_op_get_contact(const SalOp *op); /*Call API*/ int sal_call_set_local_media_description(SalOp *h, SalMediaDescription *desc); int sal_call(SalOp *h, const char *from, const char *to); int sal_call_accept(SalOp*h); +int sal_call_decline(SalOp *h, SalReason reason, const char *redirection /*optional*/); const SalMediaDescription * sal_call_get_final_media_description(SalOp *h); int sal_call_terminate(SalOp *h); -int sal_register(SalOp *op, const char *from, const char *contact, int expires); +int sal_register(SalOp *op, const char *proxy, const char *from, int expires); #define payload_type_set_number(pt,n) (pt)->user_data=(void*)((long)n); diff --git a/coreapi/sal_eXosip2.c b/coreapi/sal_eXosip2.c index bbc46beb0..d3a706d3b 100644 --- a/coreapi/sal_eXosip2.c +++ b/coreapi/sal_eXosip2.c @@ -20,12 +20,16 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "sal.h" #include -extern char *media_description_to_sdp(const SalMediaDescription *sal); +#include "offeranswer.h" + +extern sdp_message_t *media_description_to_sdp(const SalMediaDescription *sal); +extern int sdp_to_media_description(sdp_message_t *sdp, SalMediaDescription *desc); struct Sal{ SalCallbacks callbacks; int running; int session_expires; + int automatic_action; }; struct SalOp{ @@ -33,7 +37,14 @@ struct SalOp{ int cid; int did; int tid; + int rid; + int expires; + SalMediaDescription *result; + sdp_message_t *sdp_answer; + eXosip_event_t *pending_auth; bool_t supports_session_timers; + bool_t sdp_offering; + bool_t reinvite; }; SalOp * sal_op_new(Sal *sal){ @@ -41,10 +52,18 @@ SalOp * sal_op_new(Sal *sal){ __sal_op_init(op,sal); op->cid=op->did=op->tid=-1; op->supports_session_timers=FALSE; + op->sdp_offering=TRUE; + op->pending_auth=NULL; + op->sdp_answer=NULL; + op->reinvite=FALSE; return op; } void sal_op_release(SalOp *op){ + if (op->sdp_answer) + sdp_message_free(op->sdp_answer); + if (op->pending_auth) + eXosip_event_free(op->pending_auth); __sal_op_free(op); } @@ -58,6 +77,39 @@ void sal_uninit(Sal* sal){ ms_free(sal); } +static void unimplemented_stub(){ + ms_warning("Unimplemented SAL callback"); +} + +void sal_set_callbacks(Sal *ctx, const SalCallbacks *cbs){ + memcpy(&ctx->callbacks,cbs,sizeof(*cbs)); + if (ctx->callbacks.call_received==NULL) + ctx->callbacks.call_received=(SalOnCallReceived)unimplemented_stub; + if (ctx->callbacks.call_ringing==NULL) + ctx->callbacks.call_ringing=(SalOnCallRinging)unimplemented_stub; + if (ctx->callbacks.call_accepted==NULL) + ctx->callbacks.call_accepted=(SalOnCallAccepted)unimplemented_stub; + if (ctx->callbacks.call_failure==NULL) + ctx->callbacks.call_failure=(SalOnCallFailure)unimplemented_stub; + if (ctx->callbacks.call_terminated==NULL) + ctx->callbacks.call_terminated=(SalOnCallTerminated)unimplemented_stub; + if (ctx->callbacks.call_updated==NULL) + ctx->callbacks.call_updated=(SalOnCallUpdated)unimplemented_stub; + if (ctx->callbacks.auth_requested==NULL) + ctx->callbacks.auth_requested=(SalOnAuthRequested)unimplemented_stub; + if (ctx->callbacks.auth_success==NULL) + ctx->callbacks.auth_success=(SalOnAuthSuccess)unimplemented_stub; + if (ctx->callbacks.register_success==NULL) + ctx->callbacks.register_success=(SalOnRegisterSuccess)unimplemented_stub; + if (ctx->callbacks.register_failure==NULL) + ctx->callbacks.register_failure=(SalOnRegisterFailure)unimplemented_stub; + if (ctx->callbacks.dtmf_received==NULL) + ctx->callbacks.dtmf_received=(SalOnDtmfReceived)unimplemented_stub; + if (ctx->callbacks.presence_changed==NULL) + ctx->callbacks.presence_changed=(SalOnPresenceChanged)unimplemented_stub; + if (ctx->callbacks.internal_message==NULL) + ctx->callbacks.internal_message=(SalOnInternalMsg)unimplemented_stub; +} int sal_listen_port(Sal *ctx, const char *addr, int port, SalTransport tr, int is_secure){ int err; @@ -90,15 +142,12 @@ void sal_use_session_timers(Sal *ctx, int expires){ ctx->session_expires=expires; } -static void set_sdp(osip_message_t *sip, const SalMediaDescription *desc){ + +static void set_sdp(osip_message_t *sip,sdp_message_t *msg){ int sdplen; char clen[10]; - char *sdp=media_description_to_sdp(desc); - - if (sdp==NULL) { - ms_error("Fail to print sdp message !"); - return; - } + char *sdp=NULL; + sdp_message_to_str(msg,&sdp); sdplen=strlen(sdp); snprintf(clen,sizeof(clen),"%i",sdplen); osip_message_set_body(sip,sdp,sdplen); @@ -107,6 +156,40 @@ static void set_sdp(osip_message_t *sip, const SalMediaDescription *desc){ osip_free(sdp); } +static void set_sdp_from_desc(osip_message_t *sip, const SalMediaDescription *desc){ + sdp_message_t *msg=media_description_to_sdp(desc); + if (msg==NULL) { + ms_error("Fail to print sdp message !"); + return; + } + set_sdp(sip,msg); + sdp_message_free(msg); +} + +static void sdp_process(SalOp *h){ + if (h->result){ + sal_media_description_destroy(h->result); + } + h->result=sal_media_description_new(); + if (h->sdp_offering){ + offer_answer_initiate_outgoing(h->base.local_media,h->base.remote_media,h->result); + }else{ + int i; + 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); + for(i=0;iresult->nstreams;++i){ + if (h->result->streams[i].port>0){ + strcpy(h->result->streams[i].addr,h->base.remote_media->streams[i].addr); + h->result->streams[i].ptime=h->base.remote_media->streams[i].ptime; + h->result->streams[i].bandwidth=h->base.remote_media->streams[i].bandwidth; + h->result->streams[i].port=h->base.remote_media->streams[i].port; + } + } + } + +} + int sal_call_set_local_media_description(SalOp *h, SalMediaDescription *desc){ h->base.local_media=desc; return 0; @@ -128,7 +211,10 @@ int sal_call(SalOp *h, const char *from, const char *to){ osip_message_set_header(invite, "Session-expires", "200"); osip_message_set_supported(invite, "timer"); } - if (h->base.local_media) set_sdp(invite,h->base.local_media); + if (h->base.local_media){ + h->sdp_offering=TRUE; + set_sdp_from_desc(invite,h->base.local_media); + }else h->sdp_offering=FALSE; eXosip_lock(); err=eXosip_call_send_initial_invite(invite); eXosip_unlock(); @@ -136,6 +222,8 @@ int sal_call(SalOp *h, const char *from, const char *to){ if (err<0){ ms_error("Fail to send invite !"); return -1; + }else{ + eXosip_call_set_reference(h->cid,h); } return 0; } @@ -151,20 +239,867 @@ int sal_call_accept(SalOp * h){ if (h->base.root->session_expires!=0){ if (h->supports_session_timers) osip_message_set_supported(msg, "timer"); } + + if (h->base.local_media){ + /*this is the case where we received an invite without SDP*/ + if (h->sdp_offering) { + set_sdp_from_desc(msg,h->base.local_media); + }else{ + if (h->sdp_answer) + set_sdp(msg,h->sdp_answer); + } + }else{ + ms_error("You are accepting a call but not defined any media capabilities !"); + } + eXosip_call_send_answer(h->tid,200,msg); return 0; } const SalMediaDescription * sal_call_get_final_media_description(SalOp *h){ - return NULL; + if (h->base.local_media && h->base.remote_media && !h->result){ + sdp_process(h); + } + return h->result; } int sal_call_terminate(SalOp *h){ eXosip_lock(); eXosip_call_terminate(h->cid,h->did); eXosip_unlock(); + eXosip_call_set_reference(h->cid,NULL); return 0; } -int sal_iterate(Sal *sal); +void sal_op_authenticate(SalOp *h, const SalAuthInfo *info){ + if (h->pending_auth){ + const char *userid; + if (info->userid==NULL || info->userid[0]=='\0') userid=info->username; + else userid=info->userid; + eXosip_lock(); + eXosip_add_authentication_info (info->username,userid, + info->password, NULL,info->realm); + eXosip_default_action(h->pending_auth); + eXosip_unlock(); + eXosip_event_free(h->pending_auth); + h->pending_auth=NULL; + } +} + +static void inc_new_call(Sal *sal, eXosip_event_t *ev){ + SalOp *op=sal_op_new(sal); + osip_from_t *from,*to; + char *tmp; + sdp_message_t *sdp=eXosip_get_sdp_info(ev->request); + if (sdp){ + op->base.remote_media=sal_media_description_new(); + sdp_to_media_description(sdp,op->base.remote_media); + sdp_message_free(sdp); + }else op->sdp_offering=TRUE; + + from=osip_message_get_from(ev->request); + to=osip_message_get_to(ev->request); + osip_from_to_str(from,&tmp); + sal_op_set_from(op,tmp); + osip_free(tmp); + osip_from_to_str(to,&tmp); + sal_op_set_to(op,tmp); + osip_free(tmp); + + op->tid=ev->tid; + op->cid=ev->cid; + op->did=ev->did; + + eXosip_call_set_reference(op->cid,op); + sal->callbacks.call_received(op); +} + +static void handle_reinvite(Sal *sal, eXosip_event_t *ev){ + SalOp *op=(SalOp*)ev->external_reference; + sdp_message_t *sdp; + osip_message_t *msg=NULL; + + if (op==NULL) { + ms_warning("Reinvite for non-existing operation !"); + return; + } + op->reinvite=TRUE; + op->tid=ev->tid; + sdp=eXosip_get_sdp_info(ev->request); + if (op->base.remote_media){ + sal_media_description_destroy(op->base.remote_media); + op->base.remote_media=NULL; + } + eXosip_lock(); + eXosip_call_build_answer(ev->tid,200,&msg); + eXosip_unlock(); + if (msg==NULL) return; + if (op->base.root->session_expires!=0){ + if (op->supports_session_timers) osip_message_set_supported(msg, "timer"); + } + if (sdp){ + op->sdp_offering=FALSE; + op->base.remote_media=sal_media_description_new(); + sdp_to_media_description(sdp,op->base.remote_media); + sdp_message_free(sdp); + sdp_process(op); + set_sdp(msg,op->sdp_answer); + }else { + op->sdp_offering=TRUE; + set_sdp_from_desc(msg,op->base.local_media); + } + eXosip_lock(); + eXosip_call_send_answer(ev->tid,200,msg); + eXosip_unlock(); +} + +static void handle_ack(Sal *sal, eXosip_event_t *ev){ + SalOp *op=(SalOp*)ev->external_reference; + sdp_message_t *sdp; + + if (op==NULL) { + ms_warning("ack for non-existing call !"); + return; + } + sdp=eXosip_get_sdp_info(ev->ack); + if (sdp){ + op->base.remote_media=sal_media_description_new(); + sdp_to_media_description(sdp,op->base.remote_media); + sdp_process(op); + sdp_message_free(sdp); + } + if (op->reinvite){ + sal->callbacks.call_updated(op); + op->reinvite=FALSE; + }else{ + sal->callbacks.call_ack(op); + } +} + +static int call_proceeding(Sal *sal, eXosip_event_t *ev){ + SalOp *op=(SalOp*)ev->external_reference; + if (op==NULL) { + ms_warning("This call has been canceled."); + eXosip_lock(); + eXosip_call_terminate(ev->cid,ev->did); + eXosip_unlock(); + return -1; + } + op->did=ev->did; + op->tid=ev->tid; + return 0; +} + +static void call_ringing(Sal *sal, eXosip_event_t *ev){ + sdp_message_t *sdp; + SalOp *op; + 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(); + sdp_to_media_description(sdp,op->base.remote_media); + sdp_message_free(sdp); + if (op->base.local_media) sdp_process(op); + } + sal->callbacks.call_ringing(op); +} + +static void call_accepted(Sal *sal, eXosip_event_t *ev){ + sdp_message_t *sdp; + osip_message_t *msg=NULL; + SalOp *op; + op=(SalOp*)ev->external_reference; + if (op==NULL){ + ms_error("A closed call is accepted ?"); + return; + } + sdp=eXosip_get_sdp_info(ev->response); + if (sdp){ + op->base.remote_media=sal_media_description_new(); + sdp_to_media_description(sdp,op->base.remote_media); + sdp_message_free(sdp); + if (op->base.local_media) sdp_process(op); + } + eXosip_call_build_ack(ev->did,&msg); + if (op->sdp_answer) + set_sdp(msg,op->sdp_answer); + eXosip_call_send_ack(ev->did,msg); + sal->callbacks.call_accepted(op); +} + +static void call_terminated(Sal *sal, eXosip_event_t *ev){ + SalOp *op; + op=(SalOp*)ev->external_reference; + if (op==NULL){ + ms_warning("Call terminated for already closed call ?"); + return; + } + eXosip_call_set_reference(ev->cid,NULL); + sal->callbacks.call_terminated(op); +} + +static void call_released(Sal *sal, eXosip_event_t *ev){ + SalOp *op; + op=(SalOp*)ev->external_reference; + if (op==NULL){ + return; + } + eXosip_call_set_reference(ev->cid,NULL); + sal->callbacks.call_terminated(op); +} + +static int get_auth_data(eXosip_event_t *ev, const char **realm, const char **username){ + const char *prx_realm=NULL,*www_realm=NULL; + osip_proxy_authenticate_t *prx_auth; + osip_www_authenticate_t *www_auth; + osip_message_t *resp=ev->response; + + *username=osip_uri_get_username(resp->from->url); + prx_auth=(osip_proxy_authenticate_t*)osip_list_get(&resp->proxy_authenticates,0); + www_auth=(osip_proxy_authenticate_t*)osip_list_get(&resp->www_authenticates,0); + if (prx_auth!=NULL) + prx_realm=osip_proxy_authenticate_get_realm(prx_auth); + if (www_auth!=NULL) + www_realm=osip_www_authenticate_get_realm(www_auth); + + if (prx_realm){ + *realm=prx_realm; + }else if (www_realm){ + *realm=www_realm; + }else{ + return -1; + } + return 0; +} + +static bool_t process_authentication(Sal *sal, eXosip_event_t *ev){ + SalOp *op; + const char *username,*realm; + op=(SalOp*)ev->external_reference; + if (op==NULL){ + ms_warning("No operation associated with this authentication !"); + return TRUE; + } + if (get_auth_data(ev,&realm,&username)==0){ + if (op->pending_auth!=NULL) + eXosip_event_free(op->pending_auth); + op->pending_auth=ev; + sal->callbacks.auth_requested(op,realm,username); + return FALSE; + } + return TRUE; +} + +static void authentication_ok(Sal *sal, eXosip_event_t *ev){ + SalOp *op; + const char *username,*realm; + op=(SalOp*)ev->external_reference; + if (op==NULL){ + ms_warning("No operation associated with this authentication_ok!"); + return ; + } + if (get_auth_data(ev,&realm,&username)==0){ + sal->callbacks.auth_success(op,realm,username); + } +} + +static bool_t call_failure(Sal *sal, eXosip_event_t *ev){ + SalOp *op; + int code=0; + const char *reason=NULL; + SalError error=SalErrorUnknown; + SalReason sr=SalReasonUnknown; + + op=(SalOp*)ev->external_reference; + + if (op==NULL) { + ms_warning("Call failure reported for a closed call, ignored."); + return TRUE; + } + + if (ev->response){ + code=osip_message_get_status_code(ev->response); + reason=osip_message_get_reason_phrase(ev->response); + } + switch(code) + { + case 401: + case 407: + return process_authentication(sal,ev); + break; + case 400: + error=SalErrorUnknown; + break; + case 404: + error=SalErrorFailure; + sr=SalReasonNotFound; + break; + case 415: + error=SalErrorMedia; + break; + case 422: + eXosip_default_action(ev); + return TRUE; + break; + case 480: + error=SalErrorFailure; + sr=SalReasonTemporarilyUnavailable; + case 486: + error=SalErrorFailure; + sr=SalReasonBusy; + break; + case 487: + break; + case 600: + error=SalErrorFailure; + sr=SalReasonDoNotDisturb; + break; + case 603: + error=SalErrorFailure; + sr=SalReasonDeclined; + break; + default: + if (code>0){ + error=SalErrorFailure; + sr=SalReasonUnknown; + }else error=SalErrorNoResponse; + } + sal->callbacks.call_failure(op,error,sr,reason); + return TRUE; +} + + +static void process_media_control_xml(Sal *sal, eXosip_event_t *ev){ + SalOp *op=(SalOp*)ev->external_reference; + osip_body_t *body=NULL; + + if (op==NULL){ + ms_warning("media control xml received without operation context!"); + return ; + } + + osip_message_get_body(ev->request,0,&body); + if (body && body->body!=NULL && + strstr(body->body,"picture_fast_update")){ + osip_message_t *ans=NULL; + ms_message("Receiving VFU request !"); + if (sal->callbacks.vfu_request){ + sal->callbacks.vfu_request(op); + eXosip_call_build_answer(ev->tid,200,&ans); + if (ans) + eXosip_call_send_answer(ev->tid,200,ans); + } + } +} + +static void process_dtmf_relay(Sal *sal, eXosip_event_t *ev){ + SalOp *op=(SalOp*)ev->external_reference; + osip_body_t *body=NULL; + + if (op==NULL){ + ms_warning("media dtmf relay received without operation context!"); + return ; + } + + osip_message_get_body(ev->request,0,&body); + if (body && body->body!=NULL){ + osip_message_t *ans=NULL; + const char *name=strstr(body->body,"Signal"); + if (name==NULL) name=strstr(body->body,"signal"); + if (name==NULL) { + ms_warning("Could not extract the dtmf name from the SIP INFO."); + }else{ + char tmp[2]; + name+=strlen("signal"); + if (sscanf(name," = %1s",tmp)==1){ + ms_message("Receiving dtmf %s via SIP INFO.",tmp); + if (sal->callbacks.dtmf_received != NULL) + sal->callbacks.dtmf_received(op, tmp[0]); + } + } + eXosip_call_build_answer(ev->tid,200,&ans); + if (ans) + eXosip_call_send_answer(ev->tid,200,ans); + } +} + +static void call_message_new(Sal *sal, eXosip_event_t *ev){ + osip_message_t *ans=NULL; + if (ev->request){ + if (MSG_IS_INFO(ev->request)){ + osip_content_type_t *ct; + ct=osip_message_get_content_type(ev->request); + if (ct && ct->subtype){ + if (strcmp(ct->subtype,"media_control+xml")==0) + process_media_control_xml(sal,ev); + else if (strcmp(ct->subtype,"dtmf-relay")==0) + process_dtmf_relay(sal,ev); + else { + ms_message("Unhandled SIP INFO."); + /*send an "Not implemented" answer*/ + eXosip_lock(); + eXosip_call_build_answer(ev->tid,501,&ans); + if (ans) + eXosip_call_send_answer(ev->tid,501,ans); + eXosip_unlock(); + } + }else{ + /*empty SIP INFO, probably to test we are alive. Send an empty answer*/ + eXosip_lock(); + eXosip_call_build_answer(ev->tid,200,&ans); + if (ans) + eXosip_call_send_answer(ev->tid,200,ans); + eXosip_unlock(); + } + } + }else ms_warning("call_message_new: No request ?"); +} + +static void inc_update(Sal *sal, eXosip_event_t *ev){ + osip_message_t *msg=NULL; + ms_message("Processing incoming UPDATE"); + eXosip_lock(); + eXosip_message_build_answer(ev->tid,200,&msg); + if (msg!=NULL) + eXosip_message_send_answer(ev->tid,200,msg); + eXosip_unlock(); +} + +static bool_t comes_from_local_if(osip_message_t *msg){ + osip_via_t *via=NULL; + osip_message_get_via(msg,0,&via); + if (via){ + const char *host; + host=osip_via_get_host(via); + if (strcmp(host,"127.0.0.1")==0 || strcmp(host,"::1")==0){ + osip_generic_param_t *param=NULL; + osip_via_param_get_byname(via,"received",¶m); + if (param==NULL) return TRUE; + if (param->gvalue && + (strcmp(param->gvalue,"127.0.0.1")==0 || strcmp(param->gvalue,"::1")==0)){ + return TRUE; + } + } + } + return FALSE; +} + +static void text_received(Sal *sal, eXosip_event_t *ev){ + osip_body_t *body=NULL; + char *from=NULL,*msg; + + osip_message_get_body(ev->request,0,&body); + if (body==NULL){ + ms_error("Could not get text message from SIP body"); + return; + } + msg=body->body; + osip_from_to_str(ev->request->from,&from); + sal->callbacks.text_received(sal,from,msg); + osip_free(from); +} + +static void other_request(Sal *sal, eXosip_event_t *ev){ + ms_message("in other_request"); + if (ev->request==NULL) return; + if (strcmp(ev->request->sip_method,"MESSAGE")==0){ + text_received(sal,ev); + eXosip_message_send_answer(ev->tid,200,NULL); + }else if (strcmp(ev->request->sip_method,"OPTIONS")==0){ + osip_message_t *options=NULL; + eXosip_options_build_answer(ev->tid,200,&options); + osip_message_set_allow(options,"INVITE, ACK, BYE, CANCEL, OPTIONS, MESSAGE, SUBSCRIBE, NOTIFY, INFO"); + osip_message_set_accept(options,"application/sdp"); + eXosip_options_send_answer(ev->tid,200,options); + }else if (strcmp(ev->request->sip_method,"WAKEUP")==0 + && comes_from_local_if(ev->request)) { + eXosip_message_send_answer(ev->tid,200,NULL); + ms_message("Receiving WAKEUP request !"); + sal->callbacks.internal_message(sal,"WAKEUP"); + }else if (strncmp(ev->request->sip_method, "REFER", 5) == 0){ + ms_message("Receiving REFER request !"); + if (comes_from_local_if(ev->request)) { + osip_header_t *h=NULL; + osip_message_header_get_byname(ev->request,"Refer-To",0,&h); + eXosip_message_send_answer(ev->tid,200,NULL); + if (h){ + sal->callbacks.refer_received(sal,NULL,h->hvalue); + } + }else ms_warning("Ignored REFER not coming from this local loopback interface."); + }else if (strncmp(ev->request->sip_method, "UPDATE", 6) == 0){ + inc_update(sal,ev); + }else { + char *tmp=NULL; + size_t msglen=0; + osip_message_to_str(ev->request,&tmp,&msglen); + if (tmp){ + ms_message("Unsupported request received:\n%s",tmp); + osip_free(tmp); + } + /*answer with a 501 Not implemented*/ + eXosip_message_send_answer(ev->tid,501,NULL); + } +} + +static void update_contact(SalOp *op, const char *received, const char *rport){ + SalAddress *addr=sal_address_new(sal_op_get_contact(op)); + char *tmp; + sal_address_set_domain(addr,received); + sal_address_set_port(addr,rport); + tmp=sal_address_as_string(addr); + sal_op_set_contact(op,tmp); + ms_free(tmp); +} + +static bool_t register_again_with_updated_contact(SalOp *op, osip_message_t *orig_request, osip_message_t *last_answer){ + osip_message_t *msg; + const char *rport,*received; + osip_via_t *via=NULL; + osip_generic_param_t *param=NULL; + osip_contact_t *ctt=NULL; + osip_message_get_via(last_answer,0,&via); + if (!via) return FALSE; + osip_via_param_get_byname(via,"rport",¶m); + if (param) rport=param->gvalue; + else return FALSE; + param=NULL; + osip_via_param_get_byname(via,"received",¶m); + if (param) received=param->gvalue; + else return FALSE; + osip_message_get_contact(orig_request,0,&ctt); + if (strcmp(ctt->url->host,received)==0){ + /*ip address matches, check ports*/ + const char *contact_port=ctt->url->port; + const char *via_rport=rport; + if (via_rport==NULL || strlen(via_rport)>0) + via_rport="5060"; + if (contact_port==NULL || strlen(contact_port)>0) + contact_port="5060"; + if (strcmp(contact_port,via_rport)==0){ + ms_message("Register has up to date contact, doing nothing."); + return FALSE; + }else ms_message("ports do not match, need to update the register (%s <> %s)", contact_port,via_rport); + } + eXosip_lock(); + msg=NULL; + eXosip_register_build_register(op->rid,op->expires,&msg); + if (msg==NULL){ + eXosip_unlock(); + ms_warning("Fail to create a contact updated register."); + return FALSE; + } + osip_message_get_contact(msg,0,&ctt); + if (ctt->url->host!=NULL){ + osip_free(ctt->url->host); + } + ctt->url->host=osip_strdup(received); + if (ctt->url->port!=NULL){ + osip_free(ctt->url->port); + } + ctt->url->port=osip_strdup(rport); + eXosip_register_send_register(op->rid,msg); + eXosip_unlock(); + update_contact(op,received,rport); + ms_message("Resending new register with updated contact %s:%s",received,rport); + return TRUE; +} + +static void registration_success(Sal *sal, eXosip_event_t *ev){ + SalOp *op=(SalOp*)ev->external_reference; + osip_header_t *h=NULL; + bool_t registered; + if (op==NULL){ + ms_error("Receiving register response for unknown operation"); + return; + } + osip_message_get_expires(ev->request,0,&h); + if (h!=NULL && atoi(h->hvalue)!=0){ + registered=TRUE; + if (!register_again_with_updated_contact(op,ev->request,ev->response)){ + sal->callbacks.register_success(op,registered); + } + }else registered=FALSE; +} + +static bool_t registration_failure(Sal *sal, eXosip_event_t *ev){ + int status_code=0; + const char *reason=NULL; + SalOp *op=(SalOp*)ev->external_reference; + SalReason sr=SalReasonUnknown; + SalError se=SalErrorUnknown; + + if (op==NULL){ + ms_error("Receiving register failure for unknown operation"); + return TRUE; + } + if (ev->response){ + status_code=osip_message_get_status_code(ev->response); + reason=osip_message_get_reason_phrase(ev->response); + }else return TRUE; + switch(status_code){ + case 401: + case 407: + return process_authentication(sal,ev); + break; + default: + /* if contact is up to date, process the failure, otherwise resend a new register with + updated contact first, just in case the faillure is due to incorrect contact */ + if (register_again_with_updated_contact(op,ev->request,ev->response)) + return TRUE; /*we are retrying with an updated contact*/ + if (status_code==403){ + se=SalErrorFailure; + sr=SalReasonForbidden; + }else if (status_code==0){ + se=SalErrorNoResponse; + } + sal->callbacks.register_failure(op,se,sr,reason); + } + return TRUE; +} + +static bool_t process_event(Sal *sal, eXosip_event_t *ev){ + switch(ev->type){ + case EXOSIP_CALL_ANSWERED: + ms_message("CALL_ANSWERED\n"); + call_accepted(sal,ev); + authentication_ok(sal,ev); + break; + case EXOSIP_CALL_CLOSED: + case EXOSIP_CALL_CANCELLED: + ms_message("CALL_CLOSED or CANCELLED\n"); + call_terminated(sal,ev); + break; + case EXOSIP_CALL_TIMEOUT: + case EXOSIP_CALL_NOANSWER: + ms_message("CALL_TIMEOUT or NOANSWER\n"); + return call_failure(sal,ev); + break; + case EXOSIP_CALL_REQUESTFAILURE: + case EXOSIP_CALL_GLOBALFAILURE: + case EXOSIP_CALL_SERVERFAILURE: + ms_message("CALL_REQUESTFAILURE or GLOBALFAILURE or SERVERFAILURE\n"); + return call_failure(sal,ev); + break; + case EXOSIP_CALL_INVITE: + ms_message("CALL_NEW\n"); + inc_new_call(sal,ev); + break; + case EXOSIP_CALL_REINVITE: + handle_reinvite(sal,ev); + break; + case EXOSIP_CALL_ACK: + ms_message("CALL_ACK"); + handle_ack(sal,ev); + break; + case EXOSIP_CALL_REDIRECTED: + ms_message("CALL_REDIRECTED"); + eXosip_default_action(ev); + break; + case EXOSIP_CALL_PROCEEDING: + ms_message("CALL_PROCEEDING"); + call_proceeding(sal,ev); + break; + case EXOSIP_CALL_RINGING: + ms_message("CALL_RINGING"); + call_ringing(sal,ev); + break; + case EXOSIP_CALL_MESSAGE_NEW: + ms_message("EXOSIP_CALL_MESSAGE_NEW"); + call_message_new(sal,ev); + break; + case EXOSIP_CALL_MESSAGE_REQUESTFAILURE: + if (ev->did<0 && ev->response && + (ev->response->status_code==407 || ev->response->status_code==401)){ + return process_authentication(sal,ev); + } + break; + case EXOSIP_IN_SUBSCRIPTION_NEW: + ms_message("CALL_SUBSCRIPTION_NEW or UPDATE"); + linphone_subscription_new(lc,ev); + break; + case EXOSIP_SUBSCRIPTION_UPDATE: + break; + case EXOSIP_SUBSCRIPTION_NOTIFY: + ms_message("CALL_SUBSCRIPTION_NOTIFY"); + linphone_notify_recv(lc,ev); + break; + case EXOSIP_SUBSCRIPTION_ANSWERED: + ms_message("EXOSIP_SUBSCRIPTION_ANSWERED, ev->sid=%i\n",ev->sid); + linphone_subscription_answered(lc,ev); + break; + case EXOSIP_SUBSCRIPTION_CLOSED: + ms_message("EXOSIP_SUBSCRIPTION_CLOSED\n"); + linphone_subscription_closed(lc,ev); + break; + case EXOSIP_CALL_RELEASED: + ms_message("CALL_RELEASED\n"); + call_released(sal, ev); + break; + case EXOSIP_REGISTRATION_FAILURE: + ms_message("REGISTRATION_FAILURE\n"); + return registration_failure(sal,ev); + break; + case EXOSIP_REGISTRATION_SUCCESS: + authentication_ok(sal,ev); + registration_success(sal,ev); + break; + case EXOSIP_MESSAGE_NEW: + other_request(sal,ev); + break; + case EXOSIP_MESSAGE_REQUESTFAILURE: + if (ev->response && (ev->response->status_code == 407 || ev->response->status_code == 401)){ + return process_authentication(sal,ev); + } + break; + default: + ms_message("Unhandled exosip event !"); + break; + } + return TRUE; +} + +int sal_iterate(Sal *sal){ + eXosip_event_t *ev; + if (sal->running){ + while((ev=eXosip_event_wait(0,0))!=NULL){ + if (process_event(sal,ev)) + eXosip_event_free(ev); + } + if (sal->automatic_action==0) { + eXosip_lock(); + eXosip_automatic_refresh(); + eXosip_unlock(); + } + } +} + +int sal_register(SalOp *h, const char *proxy, const char *from, int expires){ + osip_message_t *msg; + if (h->rid==-1){ + eXosip_lock(); + h->rid=eXosip_register_build_initial_register(from,proxy,sal_op_get_contact(op),expires,&msg); + }else{ + eXosip_lock(); + eXosip_register_build_register(h->rid,expires,&msg); + } + eXosip_register_send_register(h->rid,msg); + eXosip_unlock(); + op->expires=expires; + return 0; +} + + + +SalAddress * sal_address_new(const char *uri){ + osip_from_t *from; + osip_from_init(&from); + if (osip_from_parse(from,uri)!=0){ + osip_from_free(from); + return NULL; + } + return (SalAddress*)from; +} + +SalAddress * sal_address_clone(const SalAddress *addr){ + osip_from_t *ret=NULL; + osip_from_clone((osip_from_t*)addr,&ret); + return (SalAddress*)ret; +} + +#define null_if_empty(s) (((s)!=NULL && (s)[0]!='\0') ? (s) : NULL ) + +const char *sal_address_get_scheme(const SalAddress *addr){ + const osip_from_t *u=(const osip_from_t*)addr; + return null_if_empty(u->url->scheme); +} + +const char *sal_address_get_display_name(const SalAddress* addr){ + const osip_from_t *u=(const osip_from_t*)addr; + return null_if_empty(u->displayname); +} + +const char *sal_address_get_username(const SalAddress *addr){ + const osip_from_t *u=(const osip_from_t*)addr; + return null_if_empty(u->url->username); +} + +const char *sal_address_get_domain(const SalAddress *addr){ + const osip_from_t *u=(const osip_from_t*)addr; + return null_if_empty(u->url->host); +} + +void sal_address_set_display_name(SalAddress *addr, const char *display_name){ + osip_from_t *u=(osip_from_t*)addr; + if (u->displayname!=NULL){ + osip_free(u->displayname); + u->displayname=NULL; + } + if (display_name!=NULL) + u->displayname=osip_strdup(display_name); +} + +void sal_address_set_username(SalAddress *addr, const char *username){ + osip_from_t *uri=(osip_from_t*)addr; + if (uri->url->username!=NULL){ + osip_free(uri->url->username); + uri->url->username=NULL; + } + if (username) + uri->url->username=osip_strdup(username); +} + +void sal_address_set_domain(SalAddress *addr, const char *host){ + osip_from_t *uri=(osip_from_t*)addr; + if (uri->url->host!=NULL){ + osip_free(uri->url->host); + uri->url->host=NULL; + } + if (host) + uri->url->host=osip_strdup(host); +} + +void sal_address_set_port(SalAddress *addr, const char *port){ + osip_from_t *uri=(osip_from_t*)addr; + if (uri->url->port!=NULL){ + osip_free(uri->url->port); + uri->url->port=NULL; + } + if (port) + uri->url->port=osip_strdup(port); +} + +void sal_address_set_port_int(SalAddress *uri, int port){ + char tmp[12]; + if (port==5060){ + /*this is the default, special case to leave the port field blank*/ + sal_address_set_port(uri,NULL); + return; + } + snprintf(tmp,sizeof(tmp),"%i",port); + sal_address_set_port(uri,tmp); +} + +void sal_address_clean(SalAddress *addr){ + osip_generic_param_freelist(& ((osip_from_t*)addr)->gen_params); +} + +char *sal_address_as_string(const SalAddress *u){ + char *tmp,*ret; + osip_from_to_str((osip_from_t*)u,&tmp); + ret=ms_strdup(tmp); + osip_free(tmp); + return ret; +} + +char *sal_address_as_string_uri_only(const SalAddress *u){ + char *tmp=NULL,*ret; + osip_uri_to_str(((osip_from_t*)u)->url,&tmp); + ret=ms_strdup(tmp); + osip_free(tmp); + return ret; +} + +void sal_address_destroy(SalAddress *u){ + osip_from_free((osip_from_t*)u); +} -int sal_register(SalOp *h, const char *from, const char *contact, int expires); diff --git a/coreapi/sal_eXosip2_sdp.c b/coreapi/sal_eXosip2_sdp.c index 6b10551a1..68c6fd241 100644 --- a/coreapi/sal_eXosip2_sdp.c +++ b/coreapi/sal_eXosip2_sdp.c @@ -165,15 +165,14 @@ static void add_line(sdp_message_t *msg, int lineno, const SalStreamDescription } } -char *media_description_to_sdp(const SalMediaDescription *desc){ +sdp_message_t *media_description_to_sdp(const SalMediaDescription *desc){ int i; char *tmp; sdp_message_t *msg=create_generic_sdp(desc); for(i=0;instreams;++i){ add_line(msg,i,&desc->streams[i]); } - sdp_message_to_str(msg,&tmp); - return tmp; + return msg; } static int payload_type_fill_from_rtpmap(PayloadType *pt, const char *rtpmap){ @@ -207,17 +206,11 @@ static int payload_type_fill_from_rtpmap(PayloadType *pt, const char *rtpmap){ return 0; } -int sdp_to_media_description(const char *sdp, SalMediaDescription *desc){ +int sdp_to_media_description(sdp_message_t *msg, SalMediaDescription *desc){ int i,j; const char *mtype,*proto,*port,*addr,*number; - sdp_message_t *msg; sdp_bandwidth_t *sbw=NULL; - sdp_message_init(&msg); - if (sdp_message_parse(msg,sdp)!=0){ - ms_error("Fail to parse sdp message !"); - sdp_message_free(msg); - return -1; - } + addr=sdp_message_c_addr_get (msg, -1, 0); if (addr) strncpy(desc->addr,addr,sizeof(desc->addr)); From 5f0a6d55d9dfa26545a45e9954ab4b555390be64 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Wed, 27 Jan 2010 16:20:03 +0100 Subject: [PATCH 06/50] sal is code complete ! --- coreapi/Makefile.am | 3 +- coreapi/sal.c | 118 +++++++ coreapi/sal.h | 19 +- coreapi/sal_eXosip2.c | 79 +++-- coreapi/sal_eXosip2.h | 64 ++++ coreapi/sal_eXosip2_presence.c | 547 +++++++++++++++++++++++++++++++++ coreapi/sal_eXosip2_sdp.c | 1 - 7 files changed, 793 insertions(+), 38 deletions(-) create mode 100644 coreapi/sal.c create mode 100644 coreapi/sal_eXosip2.h create mode 100644 coreapi/sal_eXosip2_presence.c diff --git a/coreapi/Makefile.am b/coreapi/Makefile.am index e46d0c492..166232448 100644 --- a/coreapi/Makefile.am +++ b/coreapi/Makefile.am @@ -18,8 +18,9 @@ liblinphone_la_SOURCES=\ exevents.c exevents.h \ offeranswer.c offeranswer.h\ sal.c sal.h \ - sal_eXosip2.c \ + sal_eXosip2.c sal_eXosip2.h\ sal_eXosip2_sdp.c \ + sal_eXosip2_presence.c \ misc.c \ address.c \ enum.c enum.h \ diff --git a/coreapi/sal.c b/coreapi/sal.c new file mode 100644 index 000000000..7351d9277 --- /dev/null +++ b/coreapi/sal.c @@ -0,0 +1,118 @@ +/* +linphone +Copyright (C) 2010 Simon MORLAT (simon.morlat@free.fr) + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +/** + This header files defines the Signaling Abstraction Layer. + The purpose of this layer is too allow experiment different call signaling + protocols and implementations under linphone, for example SIP, JINGLE... +**/ + +#include "sal.h" + +SalMediaDescription *sal_media_description_new(){ + return ms_new0(SalMediaDescription,1); +} + +void sal_media_description_destroy(SalMediaDescription *md){ + int i; + for(i=0;istreams[i].payloads,(void (*)(void *))payload_type_destroy); + ms_list_free(md->streams[i].payloads); + } + ms_free(md); +} + +static void assign_string(char **str, const char *arg){ + if (*str){ + ms_free(*str); + *str=NULL; + } + if (arg) + *str=ms_strdup(arg); +} + +void sal_op_set_contact(SalOp *op, const char *contact){ + assign_string(&((SalOpBase*)op)->contact,contact); +} + +void sal_op_set_route(SalOp *op, const char *route){ + assign_string(&((SalOpBase*)op)->route,route); +} + +void sal_op_set_from(SalOp *op, const char *from){ + assign_string(&((SalOpBase*)op)->from,from); +} + +void sal_op_set_to(SalOp *op, const char *to){ + assign_string(&((SalOpBase*)op)->to,to); +} + +void sal_op_set_user_pointer(SalOp *op, void *up){ + ((SalOpBase*)op)->user_pointer=up; +} + +const char *sal_op_get_from(const SalOp *op){ + return ((SalOpBase*)op)->from; +} + +const char *sal_op_get_to(const SalOp *op){ + return ((SalOpBase*)op)->to; +} + +const char *sal_op_get_contact(const SalOp *op){ + return ((SalOpBase*)op)->contact; +} + +const char *sal_op_get_route(const SalOp *op){ + return ((SalOpBase*)op)->route; +} + +void *sal_op_get_user_pointer(const SalOp *op){ + return ((SalOpBase*)op)->user_pointer; +} + +void __sal_op_init(SalOp *b, Sal *sal){ + memset(b,0,sizeof(SalOpBase)); + ((SalOpBase*)b)->root=sal; +} + +void __sal_op_free(SalOp *op){ + SalOpBase *b=(SalOpBase *)op; + if (b->from) { + ms_free(b->from); + b->from=NULL; + } + if (b->to) { + ms_free(b->to); + b->to=NULL; + } + if (b->route) { + ms_free(b->route); + b->route=NULL; + } + if (b->contact) { + ms_free(b->contact); + b->contact=NULL; + } + if (b->local_media) + sal_media_description_destroy(b->local_media); + if (b->remote_media) + sal_media_description_destroy(b->remote_media); + ms_free(op); +} diff --git a/coreapi/sal.h b/coreapi/sal.h index a613cf71e..ba1778e04 100644 --- a/coreapi/sal.h +++ b/coreapi/sal.h @@ -111,6 +111,7 @@ typedef struct SalOpBase{ char *to; SalMediaDescription *local_media; SalMediaDescription *remote_media; + void *user_pointer; } SalOpBase; @@ -160,7 +161,8 @@ typedef void (*SalOnVfuRequest)(SalOp *op); typedef void (*SalOnDtmfReceived)(SalOp *op, char dtmf); typedef void (*SalOnRefer)(Sal *sal, SalOp *op, const char *referto); typedef void (*SalOnTextReceived)(Sal *sal, const char *from, const char *msg); -typedef void (*SalOnPresenceChanged)(Sal *sal, const char *from, SalPresenceStatus status); +typedef void (*SalOnPresenceChanged)(SalOp *op, SalPresenceStatus status, const char *msg); +typedef void (*SalOnSubscribeReceived)(SalOp *sal, const char *from); typedef void (*SalOnInternalMsg)(Sal *sal, const char *msg); typedef struct SalCallbacks{ @@ -180,6 +182,7 @@ typedef struct SalCallbacks{ SalOnRefer refer_received; SalOnTextReceived text_received; SalOnPresenceChanged presence_changed; + SalOnSubscribeReceived subscribe_received; SalOnInternalMsg internal_message; }SalCallbacks; @@ -206,10 +209,12 @@ void sal_op_set_from(SalOp *op, const char *from); void sal_op_set_to(SalOp *op, const char *to); void sal_op_release(SalOp *h); void sal_op_authenticate(SalOp *h, const SalAuthInfo *info); - +void sal_op_set_user_pointer(SalOp *h, void *up); const char *sal_op_get_from(const SalOp *op); const char *sal_op_get_to(const SalOp *op); const char *sal_op_get_contact(const SalOp *op); +const char *sal_op_get_route(const SalOp *op); +void *sal_op_get_user_pointer(const SalOp *op); /*Call API*/ int sal_call_set_local_media_description(SalOp *h, SalMediaDescription *desc); @@ -219,8 +224,18 @@ int sal_call_decline(SalOp *h, SalReason reason, const char *redirection /*optio const SalMediaDescription * sal_call_get_final_media_description(SalOp *h); int sal_call_terminate(SalOp *h); +/*Registration*/ int sal_register(SalOp *op, const char *proxy, const char *from, int expires); +/*Messaging */ +int sal_text_send(SalOp *op, const char *from, const char *to, const char *text); + +/*presence Subscribe/notify*/ +int sal_subscribe_presence(SalOp *op, const char *from, const char *to); +int sal_subscribe_accept(SalOp *op); +int sal_subscribe_decline(SalOp *op); +int sal_notify_presence(SalOp *op, SalPresenceStatus status, const char *status_message); + #define payload_type_set_number(pt,n) (pt)->user_data=(void*)((long)n); #define payload_type_get_number(pt) ((int)(long)(pt)->user_data) diff --git a/coreapi/sal_eXosip2.c b/coreapi/sal_eXosip2.c index d3a706d3b..efd082431 100644 --- a/coreapi/sal_eXosip2.c +++ b/coreapi/sal_eXosip2.c @@ -17,40 +17,41 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -#include "sal.h" -#include +#include "sal_eXosip2.h" #include "offeranswer.h" -extern sdp_message_t *media_description_to_sdp(const SalMediaDescription *sal); -extern int sdp_to_media_description(sdp_message_t *sdp, SalMediaDescription *desc); -struct Sal{ - SalCallbacks callbacks; - int running; - int session_expires; - int automatic_action; -}; +static SalOp * sal_find_register(Sal *sal, int rid){ + const MSList *elem; + SalOp *op; + for(elem=sal->registers;elem!=NULL;elem=elem->next){ + op=(SalOp*)elem->data; + if (op->rid==rid) return op; + } + return NULL; +} -struct SalOp{ - SalOpBase base; - int cid; - int did; - int tid; - int rid; - int expires; - SalMediaDescription *result; - sdp_message_t *sdp_answer; - eXosip_event_t *pending_auth; - bool_t supports_session_timers; - bool_t sdp_offering; - bool_t reinvite; -}; +static void sal_add_register(Sal *sal, SalOp *op){ + sal->registers=ms_list_append(sal->registers,op); +} + +static void sal_remove_register(Sal *sal, int rid){ + MSList *elem; + SalOp *op; + for(elem=sal->registers;elem!=NULL;elem=elem->next){ + op=(SalOp*)elem->data; + if (op->rid==rid) { + sal->registers=ms_list_remove_link(sal->registers,elem); + return; + } + } +} SalOp * sal_op_new(Sal *sal){ SalOp *op=ms_new(SalOp,1); __sal_op_init(op,sal); - op->cid=op->did=op->tid=-1; + op->cid=op->did=op->tid=op->rid=op->nid=op->sid-1; op->supports_session_timers=FALSE; op->sdp_offering=TRUE; op->pending_auth=NULL; @@ -64,6 +65,9 @@ void sal_op_release(SalOp *op){ sdp_message_free(op->sdp_answer); if (op->pending_auth) eXosip_event_free(op->pending_auth); + if( op->rid!=-1){ + sal_remove_register(op->base.root,op->rid); + } __sal_op_free(op); } @@ -107,6 +111,10 @@ void sal_set_callbacks(Sal *ctx, const SalCallbacks *cbs){ ctx->callbacks.dtmf_received=(SalOnDtmfReceived)unimplemented_stub; if (ctx->callbacks.presence_changed==NULL) ctx->callbacks.presence_changed=(SalOnPresenceChanged)unimplemented_stub; + if (ctx->callbacks.subscribe_received==NULL) + ctx->callbacks.subscribe_received=(SalOnSubscribeReceived)unimplemented_stub; + if (ctx->callbacks.text_received==NULL) + ctx->callbacks.text_received=(SalOnTextReceived)unimplemented_stub; if (ctx->callbacks.internal_message==NULL) ctx->callbacks.internal_message=(SalOnInternalMsg)unimplemented_stub; } @@ -805,7 +813,7 @@ static bool_t register_again_with_updated_contact(SalOp *op, osip_message_t *ori } static void registration_success(Sal *sal, eXosip_event_t *ev){ - SalOp *op=(SalOp*)ev->external_reference; + SalOp *op=sal_find_register(sal,ev->rid); osip_header_t *h=NULL; bool_t registered; if (op==NULL){ @@ -824,7 +832,7 @@ static void registration_success(Sal *sal, eXosip_event_t *ev){ static bool_t registration_failure(Sal *sal, eXosip_event_t *ev){ int status_code=0; const char *reason=NULL; - SalOp *op=(SalOp*)ev->external_reference; + SalOp *op=sal_find_register(sal,ev->rid); SalReason sr=SalReasonUnknown; SalError se=SalErrorUnknown; @@ -914,22 +922,23 @@ static bool_t process_event(Sal *sal, eXosip_event_t *ev){ } break; case EXOSIP_IN_SUBSCRIPTION_NEW: - ms_message("CALL_SUBSCRIPTION_NEW or UPDATE"); - linphone_subscription_new(lc,ev); + ms_message("CALL_SUBSCRIPTION_NEW "); + sal_exosip_subscription_recv(sal,ev); break; case EXOSIP_SUBSCRIPTION_UPDATE: + ms_message("CALL_SUBSCRIPTION_UPDATE"); break; case EXOSIP_SUBSCRIPTION_NOTIFY: ms_message("CALL_SUBSCRIPTION_NOTIFY"); - linphone_notify_recv(lc,ev); + sal_exosip_notify_recv(sal,ev); break; case EXOSIP_SUBSCRIPTION_ANSWERED: ms_message("EXOSIP_SUBSCRIPTION_ANSWERED, ev->sid=%i\n",ev->sid); - linphone_subscription_answered(lc,ev); + sal_exosip_subscription_answered(sal,ev); break; case EXOSIP_SUBSCRIPTION_CLOSED: ms_message("EXOSIP_SUBSCRIPTION_CLOSED\n"); - linphone_subscription_closed(lc,ev); + sal_exosip_subscription_closed(sal,ev); break; case EXOSIP_CALL_RELEASED: ms_message("CALL_RELEASED\n"); @@ -971,20 +980,22 @@ int sal_iterate(Sal *sal){ eXosip_unlock(); } } + return 0; } int sal_register(SalOp *h, const char *proxy, const char *from, int expires){ osip_message_t *msg; if (h->rid==-1){ eXosip_lock(); - h->rid=eXosip_register_build_initial_register(from,proxy,sal_op_get_contact(op),expires,&msg); + h->rid=eXosip_register_build_initial_register(from,proxy,sal_op_get_contact(h),expires,&msg); + sal_add_register(h->base.root,h); }else{ eXosip_lock(); eXosip_register_build_register(h->rid,expires,&msg); } eXosip_register_send_register(h->rid,msg); eXosip_unlock(); - op->expires=expires; + h->expires=expires; return 0; } diff --git a/coreapi/sal_eXosip2.h b/coreapi/sal_eXosip2.h new file mode 100644 index 000000000..c0d32fe0e --- /dev/null +++ b/coreapi/sal_eXosip2.h @@ -0,0 +1,64 @@ +/* +linphone +Copyright (C) 2010 Simon MORLAT (simon.morlat@free.fr) + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#ifndef sal_exosip2_h +#define sal_exosip2_h + +#include "sal.h" +#include + + + +sdp_message_t *media_description_to_sdp(const SalMediaDescription *sal); +int sdp_to_media_description(sdp_message_t *sdp, SalMediaDescription *desc); + +struct Sal{ + SalCallbacks callbacks; + MSList *registers;/*MSList of SalOp */ + MSList *out_subscribes;/*MSList of SalOp */ + MSList *in_subscribes;/*MSList of SalOp */ + int running; + int session_expires; + int automatic_action; +}; + +struct SalOp{ + SalOpBase base; + int cid; + int did; + int tid; + int rid; + int sid; + int nid; + int expires; + SalMediaDescription *result; + sdp_message_t *sdp_answer; + eXosip_event_t *pending_auth; + bool_t supports_session_timers; + bool_t sdp_offering; + bool_t reinvite; +}; + +void sal_exosip_subscription_recv(Sal *sal, eXosip_event_t *ev); +void sal_exosip_subscription_answered(Sal *sal,eXosip_event_t *ev); +void sal_exosip_notify_recv(Sal *sal,eXosip_event_t *ev); +void sal_exosip_subscription_closed(Sal *sal,eXosip_event_t *ev); + + +#endif diff --git a/coreapi/sal_eXosip2_presence.c b/coreapi/sal_eXosip2_presence.c new file mode 100644 index 000000000..d6ecc8839 --- /dev/null +++ b/coreapi/sal_eXosip2_presence.c @@ -0,0 +1,547 @@ +/* +linphone +Copyright (C) 2010 Simon MORLAT (simon.morlat@free.fr) + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + + +#include "sal_eXosip2.h" + + +static SalOp * sal_find_out_subscribe(Sal *sal, int sid){ + const MSList *elem; + SalOp *op; + for(elem=sal->out_subscribes;elem!=NULL;elem=elem->next){ + op=(SalOp*)elem->data; + if (op->sid==sid) return op; + } + return NULL; +} + +static void sal_add_out_subscribe(Sal *sal, SalOp *op){ + sal->out_subscribes=ms_list_append(sal->out_subscribes,op); +} + +static void sal_remove_out_subscribe(Sal *sal, int sid){ + MSList *elem; + SalOp *op; + for(elem=sal->out_subscribes;elem!=NULL;elem=elem->next){ + op=(SalOp*)elem->data; + if (op->sid==sid) { + sal->out_subscribes=ms_list_remove_link(sal->out_subscribes,elem); + return; + } + } +} + +static SalOp * sal_find_in_subscribe(Sal *sal, int nid){ + const MSList *elem; + SalOp *op; + for(elem=sal->in_subscribes;elem!=NULL;elem=elem->next){ + op=(SalOp*)elem->data; + if (op->nid==nid) return op; + } + return NULL; +} + +static void sal_add_in_subscribe(Sal *sal, SalOp *op){ + sal->in_subscribes=ms_list_append(sal->in_subscribes,op); +} + +static void sal_remove_in_subscribe(Sal *sal, int nid){ + MSList *elem; + SalOp *op; + for(elem=sal->in_subscribes;elem!=NULL;elem=elem->next){ + op=(SalOp*)elem->data; + if (op->nid==nid) { + sal->in_subscribes=ms_list_remove_link(sal->in_subscribes,elem); + return; + } + } +} + +int sal_text_send(SalOp *op, const char *from, const char *to, const char *msg){ + osip_message_t *sip=NULL; + if (from) + sal_op_set_from(op,from); + if (to) + sal_op_set_to(op,to); + + eXosip_lock(); + eXosip_message_build_request(&sip,"MESSAGE",sal_op_get_to(op), + sal_op_get_from(op),sal_op_get_route(op)); + osip_message_set_content_type(sip,"text/plain"); + osip_message_set_body(sip,msg,strlen(msg)); + eXosip_message_send_request(sip); + eXosip_unlock(); + return 0; +} + +/*presence Subscribe/notify*/ +int sal_subscribe_presence(SalOp *op, const char *from, const char *to){ + osip_message_t *msg; + if (from) + sal_op_set_from(op,from); + if (to) + sal_op_set_to(op,to); + eXosip_lock(); + eXosip_subscribe_build_initial_request(&msg,sal_op_get_to(op),sal_op_get_from(op), + sal_op_get_route(op),"presence",600); + op->sid=eXosip_subscribe_send_initial_request(msg); + eXosip_unlock(); + if (op->sid==-1){ + osip_message_free(msg); + return -1; + } + sal_add_out_subscribe(op->base.root,op); + return 0; +} + +int sal_unsubscribe(SalOp *op){ + osip_message_t *msg=NULL; + if (op->did==-1){ + ms_error("cannot unsubscribe, no dialog !"); + return -1; + } + eXosip_lock(); + eXosip_subscribe_build_refresh_request(op->did,&msg); + if (msg){ + osip_message_set_expires(msg,"0"); + eXosip_subscribe_send_refresh_request(op->did,msg); + }else ms_error("Could not build subscribe refresh request !"); + eXosip_unlock(); + return 0; +} + +int sal_subscribe_accept(SalOp *op){ + osip_message_t *msg; + eXosip_lock(); + eXosip_insubscription_build_answer(op->tid,202,&msg); + eXosip_insubscription_send_answer(op->tid,202,msg); + eXosip_unlock(); + return 0; +} + +int sal_subscribe_decline(SalOp *op){ + eXosip_lock(); + eXosip_insubscription_send_answer(op->tid,401,NULL); + eXosip_unlock(); + return 0; +} + +static eXosip_ss_status_t sal_presence_to_exosip(SalPresenceStatus s){ + switch(s){ + case SalPresenceOffline: + return EXOSIP_NOTIFY_CLOSED; + case SalPresenceOnline: + return EXOSIP_NOTIFY_ONLINE; + case SalPresenceBusy: + return EXOSIP_NOTIFY_BUSY; + case SalPresenceBerightback: + return EXOSIP_NOTIFY_BERIGHTBACK; + case SalPresenceAway: + return EXOSIP_NOTIFY_AWAY; + case SalPresenceOnthephone: + return EXOSIP_NOTIFY_ONTHEPHONE; + case SalPresenceOuttolunch: + return EXOSIP_NOTIFY_OUTTOLUNCH; + case SalPresenceDonotdisturb: + return EXOSIP_NOTIFY_BUSY; + case SalPresenceMoved: + case SalPresenceAltService: + default: + return EXOSIP_NOTIFY_AWAY; + } +} + +static void add_presence_body(osip_message_t *notify, SalPresenceStatus online_status) +{ + char buf[1000]; +#ifdef SUPPORT_MSN + int atom_id = 1000; +#endif + char *contact_info; + + osip_contact_t *ct=NULL; + osip_message_get_contact(notify,0,&ct); + osip_contact_to_str(ct,&contact_info); + +#ifdef SUPPORT_MSN + + if (online_status==SalPresenceOnline) + { + sprintf(buf, "\n\ +\n\ +\n\ +\n\ +\n\ +
\n\ +\n\ +\n\ +
\n\ +
\n\ +
", contact_info, atom_id, contact_info); + + } + else if (online_status==SalPresenceBusy) + { + sprintf(buf, "\n\ +\n\ +\n\ +\n\ +\n\ +
\n\ +\n\ +\n\ +
\n\ +
\n\ +
", contact_info, atom_id, contact_info); + + } + else if (online_status==SalPresenceBerightback) + { + sprintf(buf, "\n\ +\n\ +\n\ +\n\ +\n\ +
\n\ +\n\ +\n\ +
\n\ +
\n\ +
", contact_info, atom_id, contact_info); + + } + else if (online_status==SalPresenceAway) + { + sprintf(buf, "\n\ +\n\ +\n\ +\n\ +\n\ +
\n\ +\n\ +\n\ +
\n\ +
\n\ +
", contact_info, atom_id, contact_info); + + } + else if (online_status==SalPresenceOnthephone) + { + sprintf(buf, "\n\ +\n\ +\n\ +\n\ +\n\ +
\n\ +\n\ +\n\ +
\n\ +
\n\ +
", contact_info, atom_id, contact_info); + + } + else if (online_status==SalPresenceOuttolunch) + { + sprintf(buf, "\n\ +\n\ +\n\ +\n\ +\n\ +
\n\ +\n\ +\n\ +
\n\ +
\n\ +
", contact_info, atom_id, contact_info); + + } + else + { + sprintf(buf, "\n\ +\n\ +\n\ +\n\ +\n\ +
\n\ +\n\ +\n\ +
\n\ +
\n\ +
", contact_info, atom_id, contact_info); + } + + osip_message_set_body(notify, buf, strlen(buf)); + osip_message_set_content_type(notify, "application/xpidf+xml"); +#else + + if (online_status==SalPresenceOnline) + { + sprintf(buf, "\n\ +\n\ +\n\ +\n\ +open\n\ +\n\ +%s\n\ +online\n\ +\n\ +", + contact_info, contact_info); + } + else if (online_status==SalPresenceBusy) + { + sprintf(buf, "\n\ +\n\ +\n\ +\n\ +open\n\ +\n\ + busy\n\ +\n\ +\n\ +%s\n\ +busy\n\ +\n\ +", + contact_info, contact_info); + } + else if (online_status==SalPresenceBerightback) + { + sprintf(buf, "\n\ +\n\ +\n\ +\n\ +open\n\ +\n\ + in-transit\n\ +\n\ +\n\ +%s\n\ +be right back\n\ +\n\ +", + contact_info, contact_info); + } + else if (online_status==SalPresenceAway) + { + sprintf(buf, "\n\ +\n\ +\n\ +\n\ +open\n\ +\n\ + away\n\ +\n\ +\n\ +%s\n\ +away\n\ +\n\ +", + contact_info, contact_info); + } + else if (online_status==SalPresenceOnthephone) + { + sprintf(buf, "\n\ +\n\ +\n\ +\n\ +open\n\ +\n\ + on-the-phone\n\ +\n\ +\n\ +%s\n\ +on the phone\n\ +\n\ +", + contact_info, contact_info); + } + else if (online_status==SalPresenceOuttolunch) + { + sprintf(buf, "\n\ +\n\ +\n\ +\n\ +open\n\ +\n\ + meal\n\ +\n\ +\n\ +%s\n\ +out to lunch\n\ +\n\ +", + contact_info, contact_info); + } + else + { + /* */ + sprintf(buf, "\n\ +\n%s", + contact_info, +"\n\ +\n\ +closed\n\ +\n\ + permanent-absence\n\ +\n\ +\n\ +\n\ +\n\n"); + } + osip_message_set_body(notify, buf, strlen(buf)); + osip_message_set_content_type(notify, "application/pidf+xml"); + +#endif + osip_free(contact_info); +} + + +int sal_notify_presence(SalOp *op, SalPresenceStatus status, const char *status_message){ + osip_message_t *msg; + eXosip_ss_status_t ss; + if (op->nid==-1){ + ms_warning("Cannot notify, subscription was closed."); + return -1; + } + ss=sal_presence_to_exosip(status); + eXosip_lock(); + eXosip_insubscription_build_notify(op->did,ss,0,&msg); + if (msg!=NULL){ + const char *identity=sal_op_get_contact(op); + if (identity==NULL) identity=sal_op_get_to(op); + osip_message_set_contact(msg,identity); + add_presence_body(msg,status); + eXosip_insubscription_send_request(op->did,msg); + }else ms_error("could not create notify for incoming subscription."); + eXosip_unlock(); + return 0; +} + +void sal_exosip_subscription_recv(Sal *sal, eXosip_event_t *ev){ + SalOp *op=sal_op_new(sal); + char *tmp; + op->did=ev->did; + op->tid=ev->tid; + op->nid=ev->nid; + osip_from_to_str(ev->request->from,&tmp); + sal_op_set_from(op,tmp); + ms_free(tmp); + osip_from_to_str(ev->request->to,&tmp); + sal_op_set_to(op,tmp); + ms_free(tmp); + sal_add_in_subscribe(sal,op); + sal->callbacks.subscribe_received(op,sal_op_get_from(op)); +} + +void sal_exosip_notify_recv(Sal *sal, eXosip_event_t *ev){ + SalOp *op=sal_find_out_subscribe(sal,ev->sid); + char *tmp; + osip_from_t *from=NULL; + osip_body_t *body=NULL; + SalPresenceStatus estatus=SalPresenceOffline; + + ms_message("Receiving notify with sid=%i,nid=%i",ev->sid,ev->nid); + + if (op==NULL){ + ms_error("No operation related to this notify !"); + return; + } + if (ev->request==NULL) return; + + from=ev->request->from; + osip_message_get_body(ev->request,0,&body); + if (body==NULL){ + ms_error("No body in NOTIFY"); + return; + } + osip_from_to_str(from,&tmp); + if (strstr(body->body,"pending")!=NULL){ + estatus=SalPresenceOffline; + }else if ((strstr(body->body,"online")!=NULL) || (strstr(body->body,"open")!=NULL)) { + estatus=SalPresenceOnline; + }else if (strstr(body->body,"busy")!=NULL){ + estatus=SalPresenceBusy; + }else if (strstr(body->body,"berightback")!=NULL + || strstr(body->body,"in-transit")!=NULL ){ + estatus=SalPresenceBerightback; + }else if (strstr(body->body,"away")!=NULL){ + estatus=SalPresenceAway; + }else if (strstr(body->body,"onthephone")!=NULL + || strstr(body->body,"on-the-phone")!=NULL){ + estatus=SalPresenceOnthephone; + }else if (strstr(body->body,"outtolunch")!=NULL + || strstr(body->body,"meal")!=NULL){ + estatus=SalPresenceOuttolunch; + }else if (strstr(body->body,"closed")!=NULL){ + estatus=SalPresenceOffline; + }else{ + estatus=SalPresenceOffline; + } + ms_message("We are notified that %s has online status %i",tmp,estatus); + if (ev->ss_status==EXOSIP_SUBCRSTATE_TERMINATED) { + sal_remove_out_subscribe(sal,op->sid); + op->sid=-1; + op->did=-1; + ms_message("And outgoing subscription terminated by remote."); + } + sal->callbacks.presence_changed(op,estatus,NULL); + osip_free(tmp); +} + +void sal_exosip_subscription_answered(Sal *sal,eXosip_event_t *ev){ + SalOp *op=sal_find_out_subscribe(sal,ev->sid); + if (op==NULL){ + ms_error("Subscription answered but no associated op !"); + return; + } + op->did=ev->did; +} + +void sal_exosip_subscription_closed(Sal *sal,eXosip_event_t *ev){ + SalOp *op=sal_find_in_subscribe(sal,ev->sid); + if (op==NULL){ + ms_error("Subscription closed but no associated op !"); + return; + } + sal_remove_in_subscribe(sal,op->nid); + op->nid=-1; + op->did=0; +} + diff --git a/coreapi/sal_eXosip2_sdp.c b/coreapi/sal_eXosip2_sdp.c index 68c6fd241..2aed6283a 100644 --- a/coreapi/sal_eXosip2_sdp.c +++ b/coreapi/sal_eXosip2_sdp.c @@ -167,7 +167,6 @@ static void add_line(sdp_message_t *msg, int lineno, const SalStreamDescription sdp_message_t *media_description_to_sdp(const SalMediaDescription *desc){ int i; - char *tmp; sdp_message_t *msg=create_generic_sdp(desc); for(i=0;instreams;++i){ add_line(msg,i,&desc->streams[i]); From cda68ab8ad5fbbb95708be8f9e93f35db11a63c9 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Thu, 28 Jan 2010 10:14:37 +0100 Subject: [PATCH 07/50] fix 487 usage. --- coreapi/sal_eXosip2.c | 2 +- mediastreamer2 | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/coreapi/sal_eXosip2.c b/coreapi/sal_eXosip2.c index efd082431..393e9ee83 100644 --- a/coreapi/sal_eXosip2.c +++ b/coreapi/sal_eXosip2.c @@ -572,7 +572,7 @@ static bool_t call_failure(Sal *sal, eXosip_event_t *ev){ sr=SalReasonUnknown; }else error=SalErrorNoResponse; } - sal->callbacks.call_failure(op,error,sr,reason); + if (code!=487) sal->callbacks.call_failure(op,error,sr,reason); return TRUE; } diff --git a/mediastreamer2 b/mediastreamer2 index d0aa4b876..637302226 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit d0aa4b8769792e491fec91cd4cab4105fd08bb8d +Subproject commit 6373022261b4a529400a0c0e1661b4d3e5ebc7c5 From 907cd9a43b8d2980bdf58c46d941f6492d29838a Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Thu, 28 Jan 2010 11:40:51 +0100 Subject: [PATCH 08/50] add callbacks.c --- coreapi/callbacks.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 coreapi/callbacks.c diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c new file mode 100644 index 000000000..f4d2bc466 --- /dev/null +++ b/coreapi/callbacks.c @@ -0,0 +1,25 @@ +/* +linphone +Copyright (C) 2010 Simon MORLAT (simon.morlat@free.fr) + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + + +#include "sal.h" + +#include "linphonecore.h" +#include "private.h" + From f5c4c989ad5a9770318710872ca21645a05d3275 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Thu, 28 Jan 2010 12:34:21 +0100 Subject: [PATCH 09/50] api rationalisation of payload type. --- console/commands.c | 3 ++- coreapi/Makefile.am | 4 ++-- coreapi/exevents.c | 8 +++++--- coreapi/linphonecore.c | 4 ++-- coreapi/linphonecore.h | 14 ++++++-------- coreapi/misc.c | 39 ++++++++++++++++++++++++--------------- gtk-glade/propertybox.c | 6 +++--- 7 files changed, 44 insertions(+), 34 deletions(-) diff --git a/console/commands.c b/console/commands.c index cb684511c..08a747e56 100644 --- a/console/commands.c +++ b/console/commands.c @@ -1591,7 +1591,8 @@ static void linphonec_codec_list(LinphoneCore *lc){ MSList *node; for(node=config->audio_codecs;node!=NULL;node=ms_list_next(node)){ pt=(PayloadType*)(node->data); - linphonec_out("%2d: %s (%d) %s\n", index, pt->mime_type, pt->clock_rate, payload_type_enabled(pt) ? "enabled" : "disabled"); + linphonec_out("%2d: %s (%d) %s\n", index, pt->mime_type, pt->clock_rate, + linphone_core_payload_type_enabled(lc,pt) ? "enabled" : "disabled"); index++; } } diff --git a/coreapi/Makefile.am b/coreapi/Makefile.am index 166232448..2410f2d4e 100644 --- a/coreapi/Makefile.am +++ b/coreapi/Makefile.am @@ -15,16 +15,16 @@ lib_LTLIBRARIES=liblinphone.la liblinphone_la_SOURCES=\ linphonecore.c linphonecore.h private.h\ - exevents.c exevents.h \ offeranswer.c offeranswer.h\ sal.c sal.h \ sal_eXosip2.c sal_eXosip2.h\ sal_eXosip2_sdp.c \ sal_eXosip2_presence.c \ + callbacks.c \ + exevents.c sdphandler.c\ misc.c \ address.c \ enum.c enum.h \ - sdphandler.c sdphandler.h \ presence.c \ proxy.c \ friend.c \ diff --git a/coreapi/exevents.c b/coreapi/exevents.c index feebb9ea2..c5428bff6 100644 --- a/coreapi/exevents.c +++ b/coreapi/exevents.c @@ -464,7 +464,8 @@ int linphone_set_audio_offer(sdp_context_t *ctx) elem=lc->codecs_conf.audio_codecs; while(elem!=NULL){ codec=(PayloadType*) elem->data; - if (linphone_core_check_payload_type_usability(lc,codec) && payload_type_enabled(codec)){ + if (linphone_core_check_payload_type_usability(lc,codec) && + linphone_core_payload_type_enabled(lc,codec)){ sdp_payload_init(&payload); payload.a_rtpmap=ortp_strdup_printf("%s/%i/1",codec->mime_type,codec->clock_rate); payload.pt=rtp_profile_get_payload_number_from_rtpmap(lc->local_profile,payload.a_rtpmap); @@ -535,7 +536,8 @@ int linphone_set_video_offer(sdp_context_t *ctx) for(elem=lc->codecs_conf.video_codecs;elem!=NULL;elem=ms_list_next(elem)){ codec=(PayloadType*) elem->data; - if (linphone_core_check_payload_type_usability(lc,codec) && payload_type_enabled(codec)){ + if (linphone_core_check_payload_type_usability(lc,codec) && + linphone_core_payload_type_enabled(lc,codec)){ sdp_payload_t payload; sdp_payload_init(&payload); payload.line=1; @@ -587,7 +589,7 @@ SupportLevel linphone_payload_is_supported(LinphoneCore *lc, sdp_payload_t *payl ms_warning("payload %s is not usable",rtppayload->mime_type); return Unsupported; } - if ( !payload_type_enabled(rtppayload)) { + if ( !linphone_core_payload_type_enabled(lc,rtppayload)) { ms_warning("payload %s is not enabled.",rtppayload->mime_type); return Unsupported; } diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 3c46d92a0..19b4db9cf 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -3390,7 +3390,7 @@ void codecs_config_uninit(LinphoneCore *lc) sprintf(key,"audio_codec_%i",index); lp_config_set_string(lc->config,key,"mime",pt->mime_type); lp_config_set_int(lc->config,key,"rate",pt->clock_rate); - lp_config_set_int(lc->config,key,"enabled",payload_type_enabled(pt)); + lp_config_set_int(lc->config,key,"enabled",linphone_core_payload_type_enabled(lc,pt)); index++; } index=0; @@ -3399,7 +3399,7 @@ void codecs_config_uninit(LinphoneCore *lc) sprintf(key,"video_codec_%i",index); lp_config_set_string(lc->config,key,"mime",pt->mime_type); lp_config_set_int(lc->config,key,"rate",pt->clock_rate); - lp_config_set_int(lc->config,key,"enabled",payload_type_enabled(pt)); + lp_config_set_int(lc->config,key,"enabled",linphone_core_payload_type_enabled(lc,pt)); lp_config_set_string(lc->config,key,"recv_fmtp",pt->recv_fmtp); index++; } diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index 05dd32203..140822f87 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -40,14 +40,6 @@ extern "C" { struct _MSSndCard; struct _LinphoneCore; -bool_t payload_type_enabled(struct _PayloadType *pt); -void payload_type_set_enable(struct _PayloadType *pt,int value); -const char *payload_type_get_description(struct _PayloadType *pt); -int payload_type_get_bitrate(PayloadType *pt); -const char *payload_type_get_mime(PayloadType *pt); -int payload_type_get_rate(PayloadType *pt); - - struct _LpConfig; typedef struct sip_config @@ -726,6 +718,12 @@ const MSList *linphone_core_get_video_codecs(const LinphoneCore *lc); int linphone_core_set_video_codecs(LinphoneCore *lc, MSList *codecs); +bool_t linphone_core_payload_type_enabled(LinphoneCore *lc, PayloadType *pt); + +int linphone_core_enable_payload_type(LinphoneCore *lc, PayloadType *pt, bool_t enable); + +const char *linphone_core_get_payload_type_description(LinphoneCore *lc, PayloadType *pt); + bool_t linphone_core_check_payload_type_usability(LinphoneCore *lc, PayloadType *pt); int linphone_core_add_proxy_config(LinphoneCore *lc, LinphoneProxyConfig *config); diff --git a/coreapi/misc.c b/coreapi/misc.c index c2ba26297..9bdb90420 100644 --- a/coreapi/misc.c +++ b/coreapi/misc.c @@ -170,33 +170,42 @@ void check_sound_device(LinphoneCore *lc) #define RTP_HDR_SZ 12 #define IP4_HDR_SZ 20 /*20 is the minimum, but there may be some options*/ -const char *payload_type_get_description(PayloadType *pt){ - return _((const char *)pt->user_data); -} - -void payload_type_set_enable(PayloadType *pt,int value) +static void payload_type_set_enable(PayloadType *pt,int value) { if ((value)!=0) payload_type_set_flag(pt,PAYLOAD_TYPE_ENABLED); \ else payload_type_unset_flag(pt,PAYLOAD_TYPE_ENABLED); } - -bool_t payload_type_enabled(PayloadType *pt) { +static bool_t payload_type_enabled(PayloadType *pt) { return (((pt)->flags & PAYLOAD_TYPE_ENABLED)!=0); } -int payload_type_get_bitrate(PayloadType *pt) -{ - return pt->normal_bitrate; -} -const char *payload_type_get_mime(PayloadType *pt){ - return pt->mime_type; +bool_t linphone_core_payload_type_enabled(LinphoneCore *lc, PayloadType *pt){ + if (ms_list_find(lc->codecs_conf.audio_codecs,pt) || ms_list_find(lc->codecs_conf.video_codecs,pt)){ + return payload_type_enabled(pt); + } + ms_error("Getting enablement status of codec not in audio or video list of PayloadType !"); + return FALSE; } -int payload_type_get_rate(PayloadType *pt){ - return pt->clock_rate; +int linphone_core_enable_payload_type(LinphoneCore *lc, PayloadType *pt, bool_t enabled){ + if (ms_list_find(lc->codecs_conf.audio_codecs,pt) || ms_list_find(lc->codecs_conf.video_codecs,pt)){ + payload_type_set_enable(pt,enabled); + return 0; + } + ms_error("Enabling codec not in audio or video list of PayloadType !"); + return -1; } +const char *linphone_core_get_payload_type_description(LinphoneCore *lc, PayloadType *pt){ + if (ms_filter_codec_supported(pt->mime_type)){ + MSFilterDesc *desc=ms_filter_get_encoder(pt->mime_type); + return desc->text; + } + return NULL; +} + + /*this function makes a special case for speex/8000. This codec is variable bitrate. The 8kbit/s mode is interesting when having a low upload bandwidth, but its quality is not very good. We 'd better use its 15kbt/s mode when we have enough bandwidth*/ diff --git a/gtk-glade/propertybox.c b/gtk-glade/propertybox.c index cbc7b5c73..09af0709e 100644 --- a/gtk-glade/propertybox.c +++ b/gtk-glade/propertybox.c @@ -295,7 +295,7 @@ static void linphone_gtk_show_codecs(GtkTreeView *listview, const MSList *codecl gchar *color; const char *params=""; struct _PayloadType *pt=(struct _PayloadType *)elem->data; - if (payload_type_enabled(pt)) status=_("Enabled"); + if (linphone_core_payload_type_enabled(linphone_gtk_get_core(),pt)) status=_("Enabled"); else status=_("Disabled"); if (linphone_core_check_payload_type_usability(linphone_gtk_get_core(),pt)) color="blue"; else color="red"; @@ -311,7 +311,7 @@ static void linphone_gtk_show_codecs(GtkTreeView *listview, const MSList *codecl CODEC_PARAMS,params, CODEC_PRIVDATA,(gpointer)pt, CODEC_COLOR,(gpointer)color, - CODEC_INFO,(gpointer)payload_type_get_description(pt), + CODEC_INFO,(gpointer)linphone_core_get_payload_type_description(linphone_gtk_get_core(),pt), -1); } @@ -433,7 +433,7 @@ static void linphone_gtk_codec_set_enable(GtkWidget *button, gboolean enabled){ if (gtk_tree_selection_get_selected(sel,&mod,&iter)){ store=GTK_LIST_STORE(mod); gtk_tree_model_get(mod,&iter,CODEC_PRIVDATA,&pt,-1); - payload_type_set_enable(pt,enabled); + linphone_core_enable_payload_type(linphone_gtk_get_core(),pt,enabled); gtk_list_store_set(store,&iter,CODEC_STATUS, enabled ? _("Enabled") : _("Disabled"), -1); } } From 80e14f6a904906f6c21bf4e987c5b77e38e64809 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Fri, 29 Jan 2010 23:57:46 +0100 Subject: [PATCH 10/50] work in progress to use SAL in coreapi --- coreapi/address.c | 80 ++------ coreapi/callbacks.c | 78 ++++++++ coreapi/linphonecore.c | 412 ++++++++++++++--------------------------- coreapi/linphonecore.h | 252 ++----------------------- coreapi/private.h | 275 ++++++++++++++++++++++----- coreapi/sal.c | 31 +++- coreapi/sal.h | 25 ++- coreapi/sal_eXosip2.c | 65 ++++++- oRTP | 2 +- 9 files changed, 588 insertions(+), 632 deletions(-) diff --git a/coreapi/address.c b/coreapi/address.c index 36f6de903..51e3a1eee 100644 --- a/coreapi/address.c +++ b/coreapi/address.c @@ -20,7 +20,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "linphonecore.h" #include "lpconfig.h" #include "private.h" -#include /** * @addtogroup linphone_address @@ -31,122 +30,85 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * Constructs a LinphoneAddress object by parsing the user supplied address, * given as a string. **/ -LinphoneAddress * linphone_address_new(const char *uri){ - osip_from_t *from; - osip_from_init(&from); - if (osip_from_parse(from,uri)!=0){ - osip_from_free(from); - return NULL; - } - return from; +LinphoneAddress * linphone_address_new(const char *addr){ + return sal_address_new(addr); } /** * Clones a LinphoneAddress object. **/ -LinphoneAddress * linphone_address_clone(const LinphoneAddress *uri){ - osip_from_t *ret=NULL; - osip_from_clone(uri,&ret); - return ret; +LinphoneAddress * linphone_address_clone(const LinphoneAddress *addr){ + return sal_address_clone(addr); } -#define null_if_empty(s) (((s)!=NULL && (s)[0]!='\0') ? (s) : NULL ) - /** * Returns the address scheme, normally "sip". **/ const char *linphone_address_get_scheme(const LinphoneAddress *u){ - return null_if_empty(u->url->scheme); + return sal_address_get_scheme(u); } /** * Returns the display name. **/ const char *linphone_address_get_display_name(const LinphoneAddress* u){ - return null_if_empty(u->displayname); + return sal_address_get_display_name(u); } /** * Returns the username. **/ const char *linphone_address_get_username(const LinphoneAddress *u){ - return null_if_empty(u->url->username); + return sal_address_get_username(u); } /** * Returns the domain name. **/ const char *linphone_address_get_domain(const LinphoneAddress *u){ - return null_if_empty(u->url->host); + return sal_address_get_domain(u); } /** * Sets the display name. **/ void linphone_address_set_display_name(LinphoneAddress *u, const char *display_name){ - if (u->displayname!=NULL){ - osip_free(u->displayname); - u->displayname=NULL; - } - if (display_name!=NULL) - u->displayname=osip_strdup(display_name); + sal_address_set_display_name(u,display_name); } /** * Sets the username. **/ void linphone_address_set_username(LinphoneAddress *uri, const char *username){ - if (uri->url->username!=NULL){ - osip_free(uri->url->username); - uri->url->username=NULL; - } - if (username) - uri->url->username=osip_strdup(username); + sal_address_set_username(uri,username); } /** * Sets the domain. **/ void linphone_address_set_domain(LinphoneAddress *uri, const char *host){ - if (uri->url->host!=NULL){ - osip_free(uri->url->host); - uri->url->host=NULL; - } - if (host) - uri->url->host=osip_strdup(host); + sal_address_set_domain(uri,host); } /** * Sets the port number. **/ void linphone_address_set_port(LinphoneAddress *uri, const char *port){ - if (uri->url->port!=NULL){ - osip_free(uri->url->port); - uri->url->port=NULL; - } - if (port) - uri->url->port=osip_strdup(port); + sal_address_set_port(uri,port); } /** * Sets the port number. **/ void linphone_address_set_port_int(LinphoneAddress *uri, int port){ - char tmp[12]; - if (port==5060){ - /*this is the default, special case to leave the port field blank*/ - linphone_address_set_port(uri,NULL); - return; - } - snprintf(tmp,sizeof(tmp),"%i",port); - linphone_address_set_port(uri,tmp); + sal_address_set_port_int(uri,port); } /** * Removes address's tags and uri headers so that it is displayable to the user. **/ void linphone_address_clean(LinphoneAddress *uri){ - osip_generic_param_freelist(&uri->gen_params); + sal_address_clean(uri); } /** @@ -154,11 +116,7 @@ void linphone_address_clean(LinphoneAddress *uri){ * The returned char * must be freed by the application. Use ms_free(). **/ char *linphone_address_as_string(const LinphoneAddress *u){ - char *tmp,*ret; - osip_from_to_str(u,&tmp); - ret=ms_strdup(tmp); - osip_free(tmp); - return ret; + return sal_address_as_string(u); } /** @@ -166,18 +124,14 @@ char *linphone_address_as_string(const LinphoneAddress *u){ * The returned char * must be freed by the application. Use ms_free(). **/ char *linphone_address_as_string_uri_only(const LinphoneAddress *u){ - char *tmp=NULL,*ret; - osip_uri_to_str(u->url,&tmp); - ret=ms_strdup(tmp); - osip_free(tmp); - return ret; + return sal_address_as_string_uri_only(u); } /** * Destroys a LinphoneAddress object. **/ void linphone_address_destroy(LinphoneAddress *u){ - osip_from_free(u); + sal_address_destroy(u); } diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index f4d2bc466..73eeca56e 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -23,3 +23,81 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "linphonecore.h" #include "private.h" +static void call_received(SalOp *h){ +} + +static void call_ringing(SalOp *h){ +} + +static void call_accepted(SalOp *h){ +} + +static void call_ack(SalOp *h){ +} + +static void call_updated(SalOp *){ +} + +static void call_terminated(SalOp *h){ +} + +static void call_failure(SalOp *h, SalError error, SalReason reason, const char *details){ +} + +static void auth_requested(SalOp *h, const char *realm, const char *username){ +} + +static void auth_success(SalOp *h, const char *realm, const char *username){ +} + +static void register_success(SalOp *op, bool_t registered){ +} + +static void register_failure(SalOp *op, SalError error, SalReason reason, const char *details){ +} + +static void vfu_request(SalOp *op){ +} + +static void dtmf_received(SalOp *op, char dtmf){ +} + +static void refer_received(SalOp *op, SalOp *op, const char *referto){ +} + +static void text_received(Sal *sal, const char *from, const char *msg){ +} + +static void presence_changed(SalOp *op, SalPresenceStatus status, const char *msg){ +} + +static void subscribe_received(SalOp *op, const char *from){ +} + +static void internal_message(SalOp *op, const char *msg){ +} + + + +SalCallbacks linphone_sal_callbacks={ + call_received, + call_ringing, + call_accepted, + call_ack, + call_updated, + call_terminated, + call_failure, + auth_requested, + auth_success, + register_success, + register_failure, + vfu_request, + dtmf_received, + refer_received, + text_received, + presence_changed, + subscribe_received, + internal_message +}; + + diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 19b4db9cf..f9f47c9e4 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -24,11 +24,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "mediastreamer2/mediastream.h" #include "mediastreamer2/msvolume.h" #include "mediastreamer2/msequalizer.h" -#include -#include "sdphandler.h" #include -#include "exevents.h" #ifdef INET6 @@ -52,16 +49,6 @@ static void toggle_video_preview(LinphoneCore *lc, bool_t val); /* same for remote ring (ringback)*/ #define REMOTE_RING "ringback.wav" - -sdp_handler_t linphone_sdphandler={ - linphone_accept_audio_offer, /*from remote sdp */ - linphone_accept_video_offer, /*from remote sdp */ - linphone_set_audio_offer, /*to local sdp */ - linphone_set_video_offer, /*to local sdp */ - linphone_read_audio_answer, /*from incoming answer */ - linphone_read_video_answer /*from incoming answer */ -}; - void lc_callback_obj_init(LCCallbackObj *obj,LinphoneCoreCbFunc func,void* ud) { obj->_func=func; @@ -73,7 +60,54 @@ int lc_callback_obj_invoke(LCCallbackObj *obj, LinphoneCore *lc){ return 0; } -static void linphone_call_init_common(LinphoneCall *call, LinphoneAddress *from, LinphoneAddress *to){ + +static MSList *make_codec_list(const MSList *codecs){ + MSList *l=NULL; + const MSList *it; + for(it=codecs;it!=NULL;it=it->next){ + PayloadType *pt=(PayloadType*)it->data; + if (pt->flags & PAYLOAD_TYPE_ENABLED){ + l=ms_list_append(l,payload_type_clone(pt)); + } + } + return l; +} + +static SalMediaDescription *create_local_media_description(LinphoneCore *lc, + const char *localip, const char *username){ + MSList *l; + PayloadType *pt; + SalMediaDescription *md=sal_media_description_new(); + md->nstreams=1; + strncpy(md->addr,localip,sizeof(md->addr)); + strncpy(md->username,username,sizeof(md->username)); + /*set audio capabilities */ + strncpy(md->streams[0].addr,localip,sizeof(md->streams[0].addr)); + md->streams[0].port=linphone_core_get_audio_port(lc); + md->streams[0].proto=SalProtoRtpAvp; + md->streams[0].type=SalAudio; + l=make_codec_list(lc->codecs_conf.audio_codecs); + pt=payload_type_clone(rtp_profile_get_payload_from_mime(&av_profile,"telephone-event")); + l=ms_list_append(l,pt); + md->streams[0].payloads=l; + + if (lc->dw_audio_bw>0) + md->streams[0].bandwidth=lc->dw_audio_bw; + + if (linphone_core_video_enabled (lc)){ + md->nstreams++; + md->streams[1].port=linphone_core_get_video_port(lc); + md->streams[1].proto=SalProtoRtpAvp; + md->streams[1].type=SalVideo; + l=make_codec_list(lc->codecs_conf.video_codecs); + md->streams[1].payloads=l; + if (lc->dw_video_bw) + md->streams[1].bandwidth=lc->dw_video_bw; + } + return md; +} + +static void linphone_call_init_common(LinphoneCall *call, LinphoneAddress *from, LinphoneAddress *to){ call->state=LCStateInit; call->start_time=time(NULL); call->media_start_time=0; @@ -84,11 +118,6 @@ static void linphone_call_init_common(LinphoneCall *call, LinphoneAddress *from call->profile=rtp_profile_new("Call RTP profile"); } -void linphone_call_init_media_params(LinphoneCall *call){ - memset(&call->audio_params,0,sizeof(call->audio_params)); - memset(&call->video_params,0,sizeof(call->video_params)); -} - static void discover_mtu(LinphoneCore *lc, const char *remote){ int mtu; if (lc->net_conf.mtu==0 ){ @@ -106,44 +135,31 @@ LinphoneCall * linphone_call_new_outgoing(struct _LinphoneCore *lc, LinphoneAddr { LinphoneCall *call=ms_new0(LinphoneCall,1); call->dir=LinphoneCallOutgoing; - call->cid=-1; - call->did=-1; - call->tid=-1; + call->op=sal_op_new(lc->sal); call->core=lc; linphone_core_get_local_ip(lc,linphone_address_get_domain(to),call->localip); + call->localdesc=create_local_media_description (lc,call->localip, + linphone_address_get_username(from)); linphone_call_init_common(call,from,to); - call->sdpctx=sdp_handler_create_context(&linphone_sdphandler, - call->audio_params.natd_port>0 ? call->audio_params.natd_addr : call->localip, - linphone_address_get_username (from),NULL); - sdp_context_set_user_pointer(call->sdpctx,(void*)call); discover_mtu(lc,linphone_address_get_domain (to)); return call; } - -LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *from, LinphoneAddress *to, eXosip_event_t *ev){ +LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *from, LinphoneAddress *to, SalOp *op){ LinphoneCall *call=ms_new0(LinphoneCall,1); LinphoneAddress *me=linphone_core_get_primary_contact_parsed(lc); - osip_header_t *h=NULL; call->dir=LinphoneCallIncoming; - call->cid=ev->cid; - call->did=ev->did; - call->tid=ev->tid; + call->op=op; call->core=lc; linphone_address_clean(from); - linphone_core_get_local_ip(lc,linphone_address_get_domain(from),call->localip); + call->localdesc=create_local_media_description (lc,call->localip, + linphone_address_get_username(me)); linphone_call_init_common(call, from, to); - call->sdpctx=sdp_handler_create_context(&linphone_sdphandler, - call->audio_params.natd_port>0 ? call->audio_params.natd_addr : call->localip, - linphone_address_get_username (me),NULL); - sdp_context_set_user_pointer(call->sdpctx,(void*)call); discover_mtu(lc,linphone_address_get_domain(from)); linphone_address_destroy(me); - osip_message_header_get_byname(ev->request,"Session-expires",0,&h); - if (h) call->supports_session_timers=TRUE; return call; } @@ -153,7 +169,9 @@ void linphone_call_destroy(LinphoneCall *obj) linphone_call_log_completed(obj->log,obj); linphone_core_update_allocated_audio_bandwidth(obj->core); if (obj->profile!=NULL) rtp_profile_destroy(obj->profile); - if (obj->sdpctx!=NULL) sdp_context_free(obj->sdpctx); + if (obj->op!=NULL) sal_op_release(obj->op); + if (obj->resultdesc!=NULL) sal_media_description_unref(obj->resultdesc); + if (obj->localdesc!=NULL) sal_media_description_unref(obj->localdesc); ms_free(obj); } @@ -383,43 +401,6 @@ const LinphoneAddress *linphone_core_get_remote_uri(LinphoneCore *lc){ return call->dir==LinphoneCallIncoming ? call->log->from : call->log->to; } -void _osip_trace_func(char *fi, int li, osip_trace_level_t level, char *chfr, va_list ap){ - int ortp_level=ORTP_DEBUG; - switch(level){ - case OSIP_INFO1: - case OSIP_INFO2: - case OSIP_INFO3: - case OSIP_INFO4: - ortp_level=ORTP_MESSAGE; - break; - case OSIP_WARNING: - ortp_level=ORTP_WARNING; - break; - case OSIP_ERROR: - case OSIP_BUG: - ortp_level=ORTP_ERROR; - break; - case OSIP_FATAL: - ortp_level=ORTP_FATAL; - break; - case END_TRACE_LEVEL: - break; - } - if (ortp_log_level_enabled(level)){ - int len=strlen(chfr); - char *chfrdup=ortp_strdup(chfr); - /*need to remove endline*/ - if (len>1){ - if (chfrdup[len-1]=='\n') - chfrdup[len-1]='\0'; - if (chfrdup[len-2]=='\r') - chfrdup[len-2]='\0'; - } - ortp_logv(ortp_level,chfrdup,ap); - ortp_free(chfrdup); - } -} - /** * Enable logs in supplied FILE*. * @@ -432,7 +413,6 @@ void linphone_core_enable_logs(FILE *file){ if (file==NULL) file=stdout; ortp_set_log_file(file); ortp_set_log_level_mask(ORTP_MESSAGE|ORTP_WARNING|ORTP_ERROR|ORTP_FATAL); - osip_trace_initialize_func (OSIP_INFO4,&_osip_trace_func); } /** @@ -446,7 +426,6 @@ void linphone_core_enable_logs(FILE *file){ **/ void linphone_core_enable_logs_with_cb(OrtpLogFunc logfunc){ ortp_set_log_level_mask(ORTP_MESSAGE|ORTP_WARNING|ORTP_ERROR|ORTP_FATAL); - osip_trace_initialize_func (OSIP_INFO4,&_osip_trace_func); ortp_set_log_handler(logfunc); } @@ -456,8 +435,6 @@ void linphone_core_enable_logs_with_cb(OrtpLogFunc logfunc){ * @ingroup misc **/ void linphone_core_disable_logs(){ - int tl; - for (tl=0;tl<=OSIP_INFO4;tl++) osip_trace_disable_level(tl); ortp_set_log_level_mask(ORTP_ERROR|ORTP_FATAL); } @@ -866,6 +843,7 @@ static MSList *linphone_payload_types=NULL; static void linphone_core_assign_payload_type(PayloadType *const_pt, int number, const char *recv_fmtp){ PayloadType *pt; pt=payload_type_clone(const_pt); + payload_type_set_number(pt,number); if (recv_fmtp!=NULL) payload_type_set_recv_fmtp(pt,recv_fmtp); rtp_profile_set_payload(&av_profile,number,pt); linphone_payload_types=ms_list_append(linphone_payload_types,pt); @@ -931,6 +909,10 @@ static void linphone_core_init (LinphoneCore * lc, const LinphoneCoreVTable *vta lc->rsvp_enable = 1; lc->rpc_enable = 0; #endif + lc->sal=sal_init(); + if (lp_config_get_int(lc->config,"sip","use_session_timers",0)==1){ + sal_use_session_timers(lc->sal,200); + } sip_setup_register_all(); sound_config_read(lc); net_config_read(lc); @@ -943,7 +925,6 @@ static void linphone_core_init (LinphoneCore * lc, const LinphoneCoreVTable *vta lc->presence_mode=LINPHONE_STATUS_ONLINE; lc->max_call_logs=15; ui_config_read(lc); - ms_mutex_init(&lc->lock,NULL); lc->vtable.display_status(lc,_("Ready")); gstate_new_state(lc, GSTATE_POWER_ON, NULL); lc->ready=TRUE; @@ -1009,11 +990,11 @@ const MSList *linphone_core_get_video_codecs(const LinphoneCore *lc) **/ int linphone_core_set_primary_contact(LinphoneCore *lc, const char *contact) { - osip_from_t *ctt=NULL; - osip_from_init(&ctt); - if (osip_from_parse(ctt,contact)!=0){ + LinphoneAddress *ctt; + + if ((ctt=linphone_address_new(contact))!=0) { ms_error("Bad contact url: %s",contact); - osip_from_free(ctt); + linphone_address_destroy(ctt); return -1; } if (lc->sip_conf.contact!=NULL) ms_free(lc->sip_conf.contact); @@ -1022,7 +1003,7 @@ int linphone_core_set_primary_contact(LinphoneCore *lc, const char *contact) ms_free(lc->sip_conf.guessed_contact); lc->sip_conf.guessed_contact=NULL; } - osip_from_free(ctt); + linphone_address_destroy(ctt); return 0; } @@ -1040,12 +1021,8 @@ void linphone_core_get_local_ip(LinphoneCore *lc, const char *dest, char *result if (dest==NULL) dest="87.98.157.38"; /*a public IP address*/ if (linphone_core_get_local_ip_for(dest,result)==0) return; - /*else fallback to exosip routine that will attempt to find the most realistic interface */ - if (eXosip_guess_localip(lc->sip_conf.ipv6_enabled ? AF_INET6 : AF_INET,result,LINPHONE_IPADDR_SIZE)<0){ - /*default to something */ - strncpy(result,lc->sip_conf.ipv6_enabled ? "::1" : "127.0.0.1",LINPHONE_IPADDR_SIZE); - ms_error("Could not find default routable ip address !"); - } + /*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); } /** @@ -1053,42 +1030,32 @@ void linphone_core_get_local_ip(LinphoneCore *lc, const char *dest, char *result * * @ingroup proxies **/ -const char *linphone_core_get_primary_contact(LinphoneCore *lc) -{ +const char *linphone_core_get_primary_contact(LinphoneCore *lc){ char *identity; char tmp[LINPHONE_IPADDR_SIZE]; + if (lc->sip_conf.guess_hostname){ if (lc->sip_conf.guessed_contact==NULL || lc->sip_conf.loopback_only){ char *guessed=NULL; - osip_from_t *url; + LinphoneAddress *url; if (lc->sip_conf.guessed_contact!=NULL){ ms_free(lc->sip_conf.guessed_contact); lc->sip_conf.guessed_contact=NULL; } - - osip_from_init(&url); - if (osip_from_parse(url,lc->sip_conf.contact)==0){ - + url=linphone_address_new(lc->sip_conf.contact); + if (!url){ + url=linphone_address_new("sip:unknown@unkwownhost"); }else ms_error("Could not parse identity contact !"); linphone_core_get_local_ip(lc, NULL, tmp); if (strcmp(tmp,"127.0.0.1")==0 || strcmp(tmp,"::1")==0 ){ ms_warning("Local loopback network only !"); lc->sip_conf.loopback_only=TRUE; }else lc->sip_conf.loopback_only=FALSE; - osip_free(url->url->host); - url->url->host=osip_strdup(tmp); - if (url->url->port!=NULL){ - osip_free(url->url->port); - url->url->port=NULL; - } - if (lc->sip_conf.sip_port!=5060){ - url->url->port=ortp_strdup_printf("%i",lc->sip_conf.sip_port); - } - osip_from_to_str(url,&guessed); + linphone_address_set_domain(url,tmp); + linphone_address_set_port_int(url,lc->sip_conf.sip_port); + guessed=linphone_address_as_string(url); lc->sip_conf.guessed_contact=guessed; - - osip_from_free(url); - + linphone_address_destroy(url); } identity=lc->sip_conf.guessed_contact; }else{ @@ -1294,7 +1261,11 @@ static bool_t exosip_running=FALSE; static char _ua_name[64]="Linphone"; static char _ua_version[64]=LINPHONE_VERSION; -static void apply_user_agent(void){ +#ifdef HAVE_EXOSIP_GET_VERSION +extern const char *eXosip_get_version(); +#endif + +static void apply_user_agent(LinphoneCore *lc){ char ua_string[256]; snprintf(ua_string,sizeof(ua_string),"%s/%s (eXosip2/%s)",_ua_name,_ua_version, #ifdef HAVE_EXOSIP_GET_VERSION @@ -1303,7 +1274,7 @@ static void apply_user_agent(void){ "unknown" #endif ); - eXosip_set_user_agent(ua_string); + if (lc->sal) sal_set_user_agent(lc->sal,ua_string); } /** @@ -1327,18 +1298,14 @@ void linphone_core_set_sip_port(LinphoneCore *lc,int port) int err=0; if (port==lc->sip_conf.sip_port) return; lc->sip_conf.sip_port=port; - if (exosip_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*/ - eXosip_enable_ipv6(lc->sip_conf.ipv6_enabled); + + if (lc->sal==NULL) return; + if (lc->sip_conf.ipv6_enabled) anyaddr="::0"; else anyaddr="0.0.0.0"; - err=eXosip_listen_addr (IPPROTO_UDP, anyaddr, port, - lc->sip_conf.ipv6_enabled ? PF_INET6 : PF_INET, 0); + err=sal_listen_port (lc->sal,anyaddr,port, SalTransportDatagram,FALSE); if (err<0){ char *msg=ortp_strdup_printf("UDP port %i seems already in use ! Cannot initialize.",port); ms_warning(msg); @@ -1346,13 +1313,7 @@ void linphone_core_set_sip_port(LinphoneCore *lc,int port) ms_free(msg); return; } -#ifdef VINCENT_MAURY_RSVP - /* tell exosip the qos settings according to default linphone parameters */ - eXosip_set_rsvp_mode (lc->rsvp_enable); - eXosip_set_rpc_mode (lc->rpc_enable); -#endif - apply_user_agent(); - exosip_running=TRUE; + apply_user_agent(lc->sal); } /** @@ -1377,7 +1338,7 @@ bool_t linphone_core_ipv6_enabled(LinphoneCore *lc){ void linphone_core_enable_ipv6(LinphoneCore *lc, bool_t val){ if (lc->sip_conf.ipv6_enabled!=val){ lc->sip_conf.ipv6_enabled=val; - if (exosip_running){ + if (lc->sal){ /* we need to restart eXosip */ linphone_core_set_sip_port(lc, lc->sip_conf.sip_port); } @@ -1405,12 +1366,13 @@ static void proxy_update(LinphoneCore *lc, time_t curtime){ char result[LINPHONE_IPADDR_SIZE]; /* only do the network up checking every five seconds */ if (last_check==0 || (curtime-last_check)>=5){ - if (eXosip_guess_localip(lc->sip_conf.ipv6_enabled ? AF_INET6 : AF_INET,result,LINPHONE_IPADDR_SIZE)==0){ - if (strcmp(result,"::1")!=0 && strcmp(result,"127.0.0.1")!=0){ - last_status=TRUE; - ms_message("Network is up, registering now (%s)",result); - }else last_status=FALSE; - } + sal_get_default_local_ip(lc->sal, + lc->sip_conf.ipv6_enabled ? AF_INET6 : AF_INET, + ,result,LINPHONE_IPADDR_SIZE); + if (strcmp(result,"::1")!=0 && strcmp(result,"127.0.0.1")!=0){ + last_status=TRUE; + ms_message("Network is up, registering now (%s)",result); + }else last_status=FALSE; last_check=curtime; } doit=last_status; @@ -1524,17 +1486,7 @@ void linphone_core_iterate(LinphoneCore *lc) lc_callback_obj_invoke(&lc->preview_finished_cb,lc); } - if (exosip_running){ - while((ev=eXosip_event_wait(0,0))!=NULL){ - linphone_core_process_event(lc,ev); - } - if (lc->automatic_action==0) { - eXosip_lock(); - eXosip_automatic_action(); - eXosip_unlock(); - } - } - + sal_iterate(lc->sal); proxy_update(lc,curtime); if (lc->call!=NULL){ @@ -1585,37 +1537,6 @@ void linphone_core_iterate(LinphoneCore *lc) } -bool_t linphone_core_is_in_main_thread(LinphoneCore *lc){ - return TRUE; -} - -static char *guess_route_if_any(LinphoneCore *lc, osip_to_t *parsed_url){ - const MSList *elem=linphone_core_get_proxy_config_list(lc); - for(;elem!=NULL;elem=elem->next){ - LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)elem->data; - char prx[256]; - if (cfg->ssctx && sip_setup_context_get_proxy(cfg->ssctx,parsed_url->url->host,prx,sizeof(prx))==0){ - ms_message("We have a proxy for domain %s",parsed_url->url->host); - if (strcmp(parsed_url->url->host,prx)!=0){ - char *route=NULL; - osip_route_t *rt; - osip_route_init(&rt); - if (osip_route_parse(rt,prx)==0){ - char *rtstr; - osip_uri_uparam_add(rt->url,osip_strdup("lr"),NULL); - osip_route_to_str(rt,&rtstr); - route=ms_strdup(rtstr); - osip_free(rtstr); - } - osip_route_free(rt); - ms_message("Adding a route: %s",route); - return route; - } - } - } - return NULL; -} - bool_t linphone_core_interpret_url(LinphoneCore *lc, const char *url, LinphoneAddress **real_parsed_url, char **route){ enum_lookup_res_t *enumres=NULL; osip_to_t *parsed_url=NULL; @@ -1660,27 +1581,7 @@ bool_t linphone_core_interpret_url(LinphoneCore *lc, const char *url, LinphoneAd linphone_address_set_username(uri,normalized_username); if (real_parsed_url!=NULL) *real_parsed_url=uri; -#if 0 - /*if the prompted uri was auto-suffixed with proxy domain, - then automatically set a route so that the request goes - through the proxy*/ - if (tmproute==NULL){ - osip_route_t *rt=NULL; - char *rtstr=NULL; - osip_route_init(&rt); - if (osip_route_parse(rt,linphone_proxy_config_get_addr(proxy))==0){ - osip_uri_uparam_add(rt->url,osip_strdup("lr"),NULL); - osip_route_to_str(rt,&rtstr); - *route=ms_strdup(rtstr); - osip_free(rtstr); - } - ms_message("setting automatically a route to %s",*route); - } - else *route=ms_strdup(tmproute); -#else - if (tmproute==NULL) *route=guess_route_if_any(lc,*real_parsed_url); if (tmproute) *route=ms_strdup(tmproute); -#endif return TRUE; } } @@ -1729,15 +1630,6 @@ const char * linphone_core_get_route(LinphoneCore *lc){ return route; } -void linphone_set_sdp(osip_message_t *sip, const char *sdpmesg){ - int sdplen=strlen(sdpmesg); - char clen[10]; - snprintf(clen,sizeof(clen),"%i",sdplen); - osip_message_set_body(sip,sdpmesg,sdplen); - osip_message_set_content_type(sip,"application/sdp"); - osip_message_set_content_length(sip,clen); -} - LinphoneProxyConfig * linphone_core_lookup_known_proxy(LinphoneCore *lc, const LinphoneAddress *uri){ const MSList *elem; LinphoneProxyConfig *found_cfg=NULL; @@ -1752,37 +1644,29 @@ LinphoneProxyConfig * linphone_core_lookup_known_proxy(LinphoneCore *lc, const L return found_cfg; } -static void fix_contact(LinphoneCore *lc, osip_message_t *msg, const char *localip, LinphoneProxyConfig *dest_proxy){ - osip_contact_t *ctt=NULL; - const char *ip=NULL; - int port=5060; +static char *get_fixed_contact(LinphoneCore *lc, const char *localip, LinphoneProxyConfig *dest_proxy){ + LinphoneAddress *ctt; - osip_message_get_contact(msg,0,&ctt); - if (ctt!=NULL){ - if (dest_proxy!=NULL){ - /* if we know the request will go to a known proxy for which we are registered, - we can use the same contact address as in the register */ - linphone_proxy_config_get_contact(dest_proxy,&ip,&port); - }else{ - ip=localip; - port=linphone_core_get_sip_port(lc); - } - if (ip!=NULL){ - osip_free(ctt->url->host); - ctt->url->host=osip_strdup(ip); - } - if (port!=0){ - char tmp[10]={0}; - char *str; - snprintf(tmp,sizeof(tmp)-1,"%i",port); - if (ctt->url->port!=NULL) - osip_free(ctt->url->port); - ctt->url->port=osip_strdup(tmp); - osip_contact_to_str(ctt,&str); - ms_message("Contact has been fixed to %s",str); - osip_free(str); + if (dest_proxy){ + 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); + + if (ctt!=NULL){ + char *ret; + /*otherwise use supllied localip*/ + linphone_address_set_domain(ctt,localip); + linphone_address_set_port_int(ctt,linphone_core_get_sip_port(lc)); + ret=linphone_address_as_string_uri_only(ctt); + linphone_address_destroy(ctt); + ms_message("Contact has been fixed using local ip to %s",ret); + return ret; + } + return NULL; } /** @@ -1796,17 +1680,16 @@ int linphone_core_invite(LinphoneCore *lc, const char *url) { char *barmsg; int err=0; - char *sdpmesg=NULL; char *route=NULL; const char *from=NULL; - osip_message_t *invite=NULL; - sdp_context_t *ctx=NULL; + const char *contact=NULL; LinphoneProxyConfig *proxy=NULL; LinphoneAddress *parsed_url2=NULL; LinphoneAddress *real_parsed_url=NULL; char *real_url=NULL; LinphoneProxyConfig *dest_proxy=NULL; - + LinphoneCall *call; + if (lc->call!=NULL){ lc->vtable.display_warning(lc,_("Sorry, having multiple simultaneous calls is not supported yet !")); return -1; @@ -1832,44 +1715,34 @@ int linphone_core_invite(LinphoneCore *lc, const char *url) /* if no proxy or no identity defined for this proxy, default to primary contact*/ if (from==NULL) from=linphone_core_get_primary_contact(lc); - err=eXosip_call_build_initial_invite(&invite,real_url,from, - route,"Phone call"); - if (err<0){ - ms_warning("Could not build initial invite"); - goto end; - } - if (lp_config_get_int(lc->config,"sip","use_session_timers",0)==1){ - osip_message_set_header(invite, "Session-expires", "200"); - osip_message_set_supported(invite, "timer"); - } - /* make sdp message */ - parsed_url2=linphone_address_new(from); - lc->call=linphone_call_new_outgoing(lc,parsed_url2,real_parsed_url); + call=linphone_call_new_outgoing(lc,parsed_url2,real_parsed_url); + sal_op_set_route(call->op,route); + /*try to be best-effort in giving real local or routable contact address, except when the user choosed to override the ipaddress */ if (linphone_core_get_firewall_policy(lc)!=LINPHONE_POLICY_USE_NAT_ADDRESS) - fix_contact(lc,invite,lc->call->localip,dest_proxy); + contact=get_fixed_contact(lc,call->localip,dest_proxy); + if (contact) + sal_op_set_contact(call->op, contact); + + lc->call=call; + + linphone_core_init_media_streams(lc,lc->call); + if (!lc->sip_conf.sdp_200_ack){ + sal_call_set_local_media_description(call->op,call->localdesc); + } + err=sal_call(call->op,from,real_url); barmsg=ortp_strdup_printf("%s %s", _("Contacting"), real_url); lc->vtable.display_status(lc,barmsg); ms_free(barmsg); - if (!lc->sip_conf.sdp_200_ack){ - ctx=lc->call->sdpctx; - sdpmesg=sdp_context_get_offer(ctx); - linphone_set_sdp(invite,sdpmesg); - linphone_core_init_media_streams(lc); - } - eXosip_lock(); - err=eXosip_call_send_initial_invite(invite); - lc->call->cid=err; - eXosip_unlock(); if (err<0){ ms_warning("Could not initiate call."); lc->vtable.display_status(lc,_("could not call")); - linphone_call_destroy(lc->call); + linphone_call_destroy(call); lc->call=NULL; linphone_core_stop_media_streams(lc); }else gstate_new_state(lc, GSTATE_CALL_OUT_INVITE, url); @@ -1993,8 +1866,9 @@ int linphone_core_change_qos(LinphoneCore *lc, int answer) } #endif -void linphone_core_init_media_streams(LinphoneCore *lc){ - lc->audiostream=audio_stream_new(linphone_core_get_audio_port(lc),linphone_core_ipv6_enabled(lc)); +void linphone_core_init_media_streams(LinphoneCore *lc, LinphoneCall *call){ + SalMediaDescription *md=call->localdesc; + lc->audiostream=audio_stream_new(md->streams[0].port,linphone_core_ipv6_enabled(lc)); if (linphone_core_echo_limiter_enabled(lc)){ const char *type=lp_config_get_string(lc->config,"sound","el_type","mic"); if (strcasecmp(type,"mic")==0) @@ -2019,8 +1893,8 @@ void linphone_core_init_media_streams(LinphoneCore *lc){ rtp_session_set_transports(lc->audiostream->session,lc->a_rtp,lc->a_rtcp); #ifdef VIDEO_ENABLED - if (lc->video_conf.display || lc->video_conf.capture) - lc->videostream=video_stream_new(linphone_core_get_video_port(lc),linphone_core_ipv6_enabled(lc)); + if (lc->video_conf.display || lc->video_conf.capture && md->streams[1].port>0) + lc->videostream=video_stream_new(md->streams[1].port,linphone_core_ipv6_enabled(lc)); #else lc->videostream=NULL; #endif diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index 140822f87..e277fc0df 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -39,105 +39,10 @@ extern "C" { struct _MSSndCard; struct _LinphoneCore; +struct SalOp; struct _LpConfig; -typedef struct sip_config -{ - char *contact; - char *guessed_contact; - int sip_port; - MSList *proxies; - MSList *deleted_proxies; - int inc_timeout; /*timeout after an un-answered incoming call is rejected*/ - bool_t use_info; - bool_t use_rfc2833; /*force RFC2833 to be sent*/ - bool_t guess_hostname; - bool_t loopback_only; - bool_t ipv6_enabled; - bool_t sdp_200_ack; - bool_t only_one_codec; /*in SDP answers*/ - bool_t register_only_when_network_is_up; -} sip_config_t; - -typedef struct rtp_config -{ - int audio_rtp_port; - int video_rtp_port; - int audio_jitt_comp; /*jitter compensation*/ - int video_jitt_comp; /*jitter compensation*/ - int nortp_timeout; -}rtp_config_t; - - - -typedef struct net_config -{ - char *nat_address; - char *stun_server; - char *relay; - int download_bw; - int upload_bw; - int firewall_policy; - int mtu; - bool_t nat_sdp_only; -}net_config_t; - - -typedef struct sound_config -{ - struct _MSSndCard * ring_sndcard; /* the playback sndcard currently used */ - struct _MSSndCard * play_sndcard; /* the playback sndcard currently used */ - struct _MSSndCard * capt_sndcard; /* the capture sndcard currently used */ - const char **cards; - int latency; /* latency in samples of the current used sound device */ - char rec_lev; - char play_lev; - char ring_lev; - char source; - char *local_ring; - char *remote_ring; - bool_t ec; - bool_t ea; - bool_t agc; -} sound_config_t; - -typedef struct codecs_config -{ - MSList *audio_codecs; /* list of audio codecs in order of preference*/ - MSList *video_codecs; /* for later use*/ -}codecs_config_t; - -typedef struct video_config{ - struct _MSWebCam *device; - const char **cams; - MSVideoSize vsize; - bool_t capture; - bool_t show_local; - bool_t display; - bool_t selfview; /*during calls*/ -}video_config_t; - -typedef struct ui_config -{ - int is_daemon; - int is_applet; - unsigned int timer_id; /* the timer id for registration */ -}ui_config_t; - - - -typedef struct autoreplier_config -{ - int enabled; - int after_seconds; /* accept the call after x seconds*/ - int max_users; /* maximum number of user that can call simultaneously */ - int max_rec_time; /* the max time of incoming voice recorded */ - int max_rec_msg; /* maximum number of recorded messages */ - const char *message; /* the path of the file to be played */ -}autoreplier_config_t; - -struct osip_from; /** * Object that represents a SIP address. @@ -153,7 +58,7 @@ struct osip_from; * @ingroup linphone_address * @var LinphoneAddress */ -typedef struct osip_from LinphoneAddress; +typedef struct SalAddress LinphoneAddress; LinphoneAddress * linphone_address_new(const char *uri); LinphoneAddress * linphone_address_clone(const LinphoneAddress *uri); @@ -172,8 +77,6 @@ char *linphone_address_as_string(const LinphoneAddress *u); char *linphone_address_as_string_uri_only(const LinphoneAddress *u); void linphone_address_destroy(LinphoneAddress *u); -struct _LinphoneCore; -struct _sdp_context; struct _SipSetupContext; struct _LinphoneCall; @@ -254,21 +157,9 @@ typedef enum _LinphoneOnlineStatus{ const char *linphone_online_status_to_string(LinphoneOnlineStatus ss); -typedef struct _LinphoneFriend{ - LinphoneAddress *uri; - int in_did; - int out_did; - int sid; - int nid; - LinphoneSubscribePolicy pol; - LinphoneOnlineStatus status; - struct _LinphoneProxyConfig *proxy; - struct _LinphoneCore *lc; - BuddyInfo *info; - char *refkey; - bool_t subscribe; - bool_t inc_subscribe_pending; -}LinphoneFriend; +struct _LinphoneFriend; + +typedef struct _LinphoneFriend LinphoneFriend; LinphoneFriend * linphone_friend_new(); LinphoneFriend *linphone_friend_new_with_addr(const char *addr); @@ -291,6 +182,8 @@ const char *linphone_friend_get_ref_key(const LinphoneFriend *lf); #define linphone_friend_url(lf) ((lf)->url) +struct LinphoneProxyConfig; + /** * @addtogroup proxies * @{ @@ -311,28 +204,7 @@ const char *linphone_friend_get_ref_key(const LinphoneFriend *lf); * The default proxy (see linphone_core_set_default_proxy() ) is the one of the list * that is used by default for calls. **/ -typedef struct _LinphoneProxyConfig -{ - struct _LinphoneCore *lc; - char *reg_proxy; - char *reg_identity; - char *reg_route; - char *realm; - int expires; - int reg_time; - int rid; - char *type; - struct _SipSetupContext *ssctx; - int auth_failures; - char *contact_addr; /* our IP address as seen by the proxy, read from via 's received= parameter*/ - int contact_port; /*our IP port as seen by the proxy, read from via's rport= parameter */ - char *dial_prefix; - bool_t commit; - bool_t reg_sendregister; - bool_t registered; - bool_t publish; - bool_t dial_escape_plus; -} LinphoneProxyConfig; +typedef struct _LinphoneProxyConfig LinphoneProxyConfig; LinphoneProxyConfig *linphone_proxy_config_new(void); int linphone_proxy_config_set_server_addr(LinphoneProxyConfig *obj, const char *server_addr); @@ -393,6 +265,8 @@ int linphone_account_creator_test_existence(LinphoneAccountCreator *obj); LinphoneProxyConfig * linphone_account_creator_validate(LinphoneAccountCreator *obj); void linphone_account_creator_destroy(LinphoneAccountCreator *obj); +struct _LinphoneAuthInfo; + /** * @ingroup authentication * Object holding authentication information. @@ -417,16 +291,7 @@ void linphone_account_creator_destroy(LinphoneAccountCreator *obj); * transactions and retry them with authentication headers. * **/ -typedef struct _LinphoneAuthInfo -{ - char *username; - char *realm; - char *userid; - char *passwd; - char *ha1; - bool_t works; - bool_t first_time; -}LinphoneAuthInfo; +typedef struct _LinphoneAuthInfo LinphoneAuthInfo; LinphoneAuthInfo *linphone_auth_info_new(const char *username, const char *userid, const char *passwd, const char *ha1,const char *realm); @@ -437,13 +302,7 @@ void linphone_auth_info_set_userid(LinphoneAuthInfo *info, const char *userid); void linphone_auth_info_destroy(LinphoneAuthInfo *info); LinphoneAuthInfo * linphone_auth_info_new_from_config_file(struct _LpConfig *config, int pos); -struct _LinphoneChatRoom{ - struct _LinphoneCore *lc; - char *peer; - char *route; - LinphoneAddress *peer_url; - void * user_data; -}; +struct _LinphoneChatRoom; typedef struct _LinphoneChatRoom LinphoneChatRoom; LinphoneChatRoom * linphone_core_create_chat_room(struct _LinphoneCore *lc, const char *to); @@ -547,10 +406,6 @@ typedef struct _LinphoneVTable AuthInfoRequested auth_info_requested; /**< Ask the application some authentication information */ DisplayStatusCb display_status; /**< Callback that notifies various events with human readable text.*/ DisplayMessageCb display_message;/**< Callback to display a message to the user */ -#ifdef VINCENT_MAURY_RSVP - /* the yes/no dialog box */ - DisplayMessageCb display_yes_no; -#endif DisplayMessageCb display_warning;/** Callback to display a warning to the user */ DisplayUrlCb display_url; DisplayQuestionCb display_question; @@ -587,71 +442,7 @@ typedef enum _LinphoneWaitingState{ } LinphoneWaitingState; typedef void * (*LinphoneWaitingCallback)(struct _LinphoneCore *lc, void *context, LinphoneWaitingState ws, const char *purpose, float progress); - -typedef struct _LinphoneCore -{ - LinphoneCoreVTable vtable; - struct _LpConfig *config; - net_config_t net_conf; - sip_config_t sip_conf; - rtp_config_t rtp_conf; - sound_config_t sound_conf; - video_config_t video_conf; - codecs_config_t codecs_conf; - ui_config_t ui_conf; - autoreplier_config_t autoreplier_conf; - LinphoneProxyConfig *default_proxy; - MSList *friends; - MSList *auth_info; - struct _RingStream *ringstream; - LCCallbackObj preview_finished_cb; - bool_t preview_finished; - struct _LinphoneCall *call; /* the current call, in the future it will be a list of calls (conferencing)*/ - int rid; /*registration id*/ - MSList *queued_calls; /* used by the autoreplier */ - MSList *call_logs; - MSList *chatrooms; - int max_call_logs; - int missed_calls; - struct _AudioStream *audiostream; /**/ - struct _VideoStream *videostream; - struct _VideoStream *previewstream; - RtpTransport *a_rtp,*a_rtcp; - struct _RtpProfile *local_profile; - MSList *bl_reqs; - MSList *subscribers; /* unknown subscribers */ - int minutes_away; - LinphoneOnlineStatus presence_mode; - LinphoneOnlineStatus prev_mode; - char *alt_contact; - void *data; - ms_mutex_t lock; - char *play_file; - char *rec_file; - time_t prevtime; - int dw_audio_bw; - int up_audio_bw; - int dw_video_bw; - int up_video_bw; - int audio_bw; - int automatic_action; - gstate_t gstate_power; - gstate_t gstate_reg; - gstate_t gstate_call; - LinphoneWaitingCallback wait_cb; - void *wait_ctx; - bool_t use_files; - bool_t apply_nat_settings; - bool_t ready; - bool_t bl_refresh; -#ifdef VINCENT_MAURY_RSVP - /* QoS parameters*/ - int rsvp_enable; - int rpc_enable; -#endif -} LinphoneCore; - - +typedef struct _LinphoneCore LinphoneCore; /* THE main API */ @@ -896,8 +687,6 @@ const LinphoneAddress *linphone_core_get_remote_uri(LinphoneCore *lc); int linphone_core_get_mtu(const LinphoneCore *lc); void linphone_core_set_mtu(LinphoneCore *lc, int mtu); -bool_t linphone_core_is_in_main_thread(LinphoneCore *lc); - void *linphone_core_get_user_data(LinphoneCore *lc); /* returns LpConfig object to read/write to the config file: usefull if you wish to extend @@ -923,21 +712,6 @@ void linphone_core_destroy(LinphoneCore *lc); /*for advanced users:*/ void linphone_core_set_audio_transports(LinphoneCore *lc, RtpTransport *rtp, RtpTransport *rtcp); -/* end of lecacy api */ - -/*internal use only */ -#define linphone_core_lock(lc) ms_mutex_lock(&(lc)->lock) -#define linphone_core_unlock(lc) ms_mutex_unlock((&lc)->lock) -void linphone_core_start_media_streams(LinphoneCore *lc, struct _LinphoneCall *call); -void linphone_core_stop_media_streams(LinphoneCore *lc); -const char * linphone_core_get_identity(LinphoneCore *lc); -const char * linphone_core_get_route(LinphoneCore *lc); -bool_t linphone_core_interpret_url(LinphoneCore *lc, const char *url, LinphoneAddress **real_parsed_url, char **route); -void linphone_core_start_waiting(LinphoneCore *lc, const char *purpose); -void linphone_core_update_progress(LinphoneCore *lc, const char *purpose, float progresses); -void linphone_core_stop_waiting(LinphoneCore *lc); - - #ifdef __cplusplus } #endif diff --git a/coreapi/private.h b/coreapi/private.h index e9809dc83..93832080c 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -26,7 +26,7 @@ #define _PRIVATE_H #include "linphonecore.h" -#include +#include "sal.h" #ifdef HAVE_CONFIG_H #include "config.h" @@ -54,21 +54,6 @@ #endif #endif - -typedef struct _StreamParams -{ - int initialized; - int line; - int localport; - int remoteport; - int remotertcpport; - int pt; - char *relay_session_id; - int natd_port; - char remoteaddr[LINPHONE_HOSTNAME_SIZE]; - char natd_addr[LINPHONE_HOSTNAME_SIZE]; -} StreamParams; - typedef enum _LCState{ LCStateInit, LCStateRinging, @@ -79,25 +64,20 @@ typedef enum _LCState{ typedef struct _LinphoneCall { struct _LinphoneCore *core; - StreamParams audio_params; - StreamParams video_params; + SalMediaDescription *localdesc; + SalMediaDescription *resultdesc; LinphoneCallDir dir; struct _RtpProfile *profile; /*points to the local_profile or to the remote "guessed" profile*/ struct _LinphoneCallLog *log; - int cid; /*call id */ - int did; /*dialog id */ - int tid; /*last transaction id*/ + SalOp *op; char localip[LINPHONE_IPADDR_SIZE]; /* our best guess for local ipaddress for this call */ - struct _sdp_context *sdpctx; time_t start_time; /*time at which the call was initiated*/ time_t media_start_time; /*time at which it was accepted, media streams established*/ LCState state; - bool_t auth_pending; - bool_t supports_session_timers; } LinphoneCall; LinphoneCall * linphone_call_new_outgoing(struct _LinphoneCore *lc, LinphoneAddress *from, LinphoneAddress *to); -LinphoneCall * linphone_call_new_incoming(struct _LinphoneCore *lc, LinphoneAddress *from, LinphoneAddress *to, eXosip_event_t *ev); +LinphoneCall * linphone_call_new_incoming(struct _LinphoneCore *lc, LinphoneAddress *from, LinphoneAddress *to, SalOp *op); #define linphone_call_set_state(lcall,st) (lcall)->state=(st) void linphone_call_destroy(struct _LinphoneCall *obj); @@ -118,8 +98,6 @@ int linphone_proxy_config_send_publish(LinphoneProxyConfig *cfg, LinphoneOnlineS int linphone_online_status_to_eXosip(LinphoneOnlineStatus os); -void linphone_friend_set_sid(LinphoneFriend *lf, int sid); -void linphone_friend_set_nid(LinphoneFriend *lf, int nid); void linphone_friend_notify(LinphoneFriend *lf, int ss, LinphoneOnlineStatus os); int set_lock_file(); @@ -127,8 +105,6 @@ int get_lock_file(); int remove_lock_file(); int do_registration(LinphoneCore *lc, bool_t doit); void check_for_registration(LinphoneCore *lc); -char *int2str(int number); -int from_2char_without_params(osip_from_t *from,char **str); void check_sound_device(LinphoneCore *lc); void linphone_core_setup_local_rtp_profile(LinphoneCore *lc); void linphone_core_get_local_ip(LinphoneCore *lc, const char *to, char *result); @@ -157,24 +133,17 @@ static inline void set_string(char **dest, const char *src){ } #define PAYLOAD_TYPE_ENABLED PAYLOAD_TYPE_USER_FLAG_0 -bool_t linphone_proxy_config_register_again_with_updated_contact(LinphoneProxyConfig *obj, osip_message_t *orig_request, osip_message_t *last_answer); -void linphone_process_authentication(LinphoneCore* lc, eXosip_event_t *ev); -void linphone_authentication_ok(LinphoneCore *lc, eXosip_event_t *ev); -void linphone_subscription_new(LinphoneCore *lc, eXosip_event_t *ev); -void linphone_notify_recv(LinphoneCore *lc,eXosip_event_t *ev); -LinphoneProxyConfig *linphone_core_get_proxy_config_from_rid(LinphoneCore *lc, int rid); -void linphone_proxy_config_process_authentication_failure(LinphoneCore *lc, eXosip_event_t *ev); -void linphone_subscription_answered(LinphoneCore *lc, eXosip_event_t *ev); -void linphone_subscription_closed(LinphoneCore *lc, eXosip_event_t *ev); +void linphone_process_authentication(LinphoneCore* lc, SalOp *op); +void linphone_authentication_ok(LinphoneCore *lc, SalOp *op); +void linphone_subscription_new(LinphoneCore *lc, SalOp *op); +void linphone_notify_recv(LinphoneCore *lc, SalOp *op); +void linphone_proxy_config_process_authentication_failure(LinphoneCore *lc, SalOp *op); -void linphone_call_init_media_params(LinphoneCall *call); - -void linphone_set_sdp(osip_message_t *sip, const char *sdp); +void linphone_subscription_answered(LinphoneCore *lc, SalOp *op); +void linphone_subscription_closed(LinphoneCore *lc, SalOp *op); MSList *linphone_find_friend(MSList *fl, const LinphoneAddress *fri, LinphoneFriend **lf); -LinphoneFriend *linphone_find_friend_by_nid(MSList *l, int nid); -LinphoneFriend *linphone_find_friend_by_sid(MSList *l, int sid); void linphone_core_update_allocated_audio_bandwidth(LinphoneCore *lc); void linphone_core_update_allocated_audio_bandwidth_in_call(LinphoneCore *lc, const PayloadType *pt); @@ -194,4 +163,224 @@ void linphone_proxy_config_write_to_config_file(struct _LpConfig* config,Linphon int linphone_proxy_config_normalize_number(LinphoneProxyConfig *cfg, const char *username, char *result, size_t result_len); +/*internal use only */ +void linphone_core_start_media_streams(LinphoneCore *lc, struct _LinphoneCall *call); +void linphone_core_stop_media_streams(LinphoneCore *lc); +const char * linphone_core_get_identity(LinphoneCore *lc); +const char * linphone_core_get_route(LinphoneCore *lc); +bool_t linphone_core_interpret_url(LinphoneCore *lc, const char *url, LinphoneAddress **real_parsed_url, char **route); +void linphone_core_start_waiting(LinphoneCore *lc, const char *purpose); +void linphone_core_update_progress(LinphoneCore *lc, const char *purpose, float progresses); +void linphone_core_stop_waiting(LinphoneCore *lc); + + +extern SalCallbacks linphone_sal_callbacks; + + +struct _LinphoneProxyConfig +{ + struct _LinphoneCore *lc; + char *reg_proxy; + char *reg_identity; + char *reg_route; + char *realm; + int expires; + int reg_time; + SalOp *op; + char *type; + struct _SipSetupContext *ssctx; + int auth_failures; + char *dial_prefix; + bool_t commit; + bool_t reg_sendregister; + bool_t registered; + bool_t publish; + bool_t dial_escape_plus; +}; + +struct _LinphoneAuthInfo +{ + char *username; + char *realm; + char *userid; + char *passwd; + char *ha1; + bool_t works; + bool_t first_time; +}; + +struct _LinphoneChatRoom{ + struct _LinphoneCore *lc; + char *peer; + char *route; + LinphoneAddress *peer_url; + void * user_data; +}; + +struct _LinphoneFriend{ + LinphoneAddress *uri; + SalOp *insub; + SalOp *outsub; + LinphoneSubscribePolicy pol; + LinphoneOnlineStatus status; + struct _LinphoneProxyConfig *proxy; + struct _LinphoneCore *lc; + BuddyInfo *info; + char *refkey; + bool_t subscribe; + bool_t inc_subscribe_pending; +}; + +typedef struct sip_config +{ + char *contact; + char *guessed_contact; + int sip_port; + MSList *proxies; + MSList *deleted_proxies; + int inc_timeout; /*timeout after an un-answered incoming call is rejected*/ + bool_t use_info; + bool_t use_rfc2833; /*force RFC2833 to be sent*/ + bool_t guess_hostname; + bool_t loopback_only; + bool_t ipv6_enabled; + bool_t sdp_200_ack; + bool_t only_one_codec; /*in SDP answers*/ + bool_t register_only_when_network_is_up; +} sip_config_t; + +typedef struct rtp_config +{ + int audio_rtp_port; + int video_rtp_port; + int audio_jitt_comp; /*jitter compensation*/ + int video_jitt_comp; /*jitter compensation*/ + int nortp_timeout; +}rtp_config_t; + + + +typedef struct net_config +{ + char *nat_address; + char *stun_server; + char *relay; + int download_bw; + int upload_bw; + int firewall_policy; + int mtu; + bool_t nat_sdp_only; +}net_config_t; + + +typedef struct sound_config +{ + struct _MSSndCard * ring_sndcard; /* the playback sndcard currently used */ + struct _MSSndCard * play_sndcard; /* the playback sndcard currently used */ + struct _MSSndCard * capt_sndcard; /* the capture sndcard currently used */ + const char **cards; + int latency; /* latency in samples of the current used sound device */ + char rec_lev; + char play_lev; + char ring_lev; + char source; + char *local_ring; + char *remote_ring; + bool_t ec; + bool_t ea; + bool_t agc; +} sound_config_t; + +typedef struct codecs_config +{ + MSList *audio_codecs; /* list of audio codecs in order of preference*/ + MSList *video_codecs; /* for later use*/ +}codecs_config_t; + +typedef struct video_config{ + struct _MSWebCam *device; + const char **cams; + MSVideoSize vsize; + bool_t capture; + bool_t show_local; + bool_t display; + bool_t selfview; /*during calls*/ +}video_config_t; + +typedef struct ui_config +{ + int is_daemon; + int is_applet; + unsigned int timer_id; /* the timer id for registration */ +}ui_config_t; + + + +typedef struct autoreplier_config +{ + int enabled; + int after_seconds; /* accept the call after x seconds*/ + int max_users; /* maximum number of user that can call simultaneously */ + int max_rec_time; /* the max time of incoming voice recorded */ + int max_rec_msg; /* maximum number of recorded messages */ + const char *message; /* the path of the file to be played */ +}autoreplier_config_t; + + +struct _LinphoneCore +{ + LinphoneCoreVTable vtable; + Sal *sal; + struct _LpConfig *config; + net_config_t net_conf; + sip_config_t sip_conf; + rtp_config_t rtp_conf; + sound_config_t sound_conf; + video_config_t video_conf; + codecs_config_t codecs_conf; + ui_config_t ui_conf; + autoreplier_config_t autoreplier_conf; + LinphoneProxyConfig *default_proxy; + MSList *friends; + MSList *auth_info; + struct _RingStream *ringstream; + LCCallbackObj preview_finished_cb; + struct _LinphoneCall *call; /* the current call, in the future it will be a list of calls (conferencing)*/ + MSList *queued_calls; /* used by the autoreplier */ + MSList *call_logs; + MSList *chatrooms; + int max_call_logs; + int missed_calls; + struct _AudioStream *audiostream; /**/ + struct _VideoStream *videostream; + struct _VideoStream *previewstream; + RtpTransport *a_rtp,*a_rtcp; + struct _RtpProfile *local_profile; + MSList *bl_reqs; + MSList *subscribers; /* unknown subscribers */ + int minutes_away; + LinphoneOnlineStatus presence_mode; + LinphoneOnlineStatus prev_mode; + char *alt_contact; + void *data; + char *play_file; + char *rec_file; + time_t prevtime; + int dw_audio_bw; + int up_audio_bw; + int dw_video_bw; + int up_video_bw; + int audio_bw; + gstate_t gstate_power; + gstate_t gstate_reg; + gstate_t gstate_call; + LinphoneWaitingCallback wait_cb; + void *wait_ctx; + bool_t use_files; + bool_t apply_nat_settings; + bool_t ready; + bool_t bl_refresh; + bool_t preview_finished; +}; + #endif /* _PRIVATE_H */ diff --git a/coreapi/sal.c b/coreapi/sal.c index 7351d9277..150d7d94a 100644 --- a/coreapi/sal.c +++ b/coreapi/sal.c @@ -26,10 +26,11 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "sal.h" SalMediaDescription *sal_media_description_new(){ - return ms_new0(SalMediaDescription,1); + SalMediaDescription *md=ms_new0(SalMediaDescription,1); + md->refcount=1; } -void sal_media_description_destroy(SalMediaDescription *md){ +static void sal_media_description_destroy(SalMediaDescription *md){ int i; for(i=0;istreams[i].payloads,(void (*)(void *))payload_type_destroy); @@ -38,6 +39,28 @@ void sal_media_description_destroy(SalMediaDescription *md){ ms_free(md); } +void sal_media_description_ref(SalMediaDescription *md){ + md->refcount++; +} + +void sal_media_description_unref(SalMediaDescription *md){ + md->refcount--; + if (md->refcount==0){ + sal_media_description_destroy (md); + } +} + +SalStreamDescription *sal_media_description_find_stream(SalMediaDescription *md, + SalMediaProto proto, SalStreamType type){ + int i; + for(i=0;instreams;++i){ + SalStreamDescription *ss=&md->streams[i]; + if (ss->proto==proto && ss->type==type) return ss; + } + return NULL; +} + + static void assign_string(char **str, const char *arg){ if (*str){ ms_free(*str); @@ -111,8 +134,8 @@ void __sal_op_free(SalOp *op){ b->contact=NULL; } if (b->local_media) - sal_media_description_destroy(b->local_media); + sal_media_description_unref(b->local_media); if (b->remote_media) - sal_media_description_destroy(b->remote_media); + sal_media_description_unref(b->remote_media); ms_free(op); } diff --git a/coreapi/sal.h b/coreapi/sal.h index ba1778e04..37b28c189 100644 --- a/coreapi/sal.h +++ b/coreapi/sal.h @@ -64,20 +64,20 @@ Sal * sal_init(); void sal_uninit(Sal* sal); typedef enum { - SAL_TRANSPORT_DATAGRAM, - SAL_TRANSPORT_STREAM + SalTransportDatagram, + SalTransportStream }SalTransport; typedef enum { - SAL_AUDIO, - SAL_VIDEO, - SAL_OTHER + SalAudio, + SalVideo, + SalOther } SalStreamType; typedef enum{ - SAL_PROTO_UNKNOWN, - SAL_PROTO_RTP_AVP, - SAL_PROTO_RTP_SAVP + SalProtoUnknown, + SalProtoRtpAvp, + SalProtoRtpSavp }SalMediaProto; typedef struct SalStreamDescription{ @@ -93,6 +93,7 @@ typedef struct SalStreamDescription{ #define SAL_MEDIA_DESCRIPTION_MAX_STREAMS 4 typedef struct SalMediaDescription{ + int refcount; char addr[64]; char username[64]; int nstreams; @@ -100,7 +101,10 @@ typedef struct SalMediaDescription{ } SalMediaDescription; SalMediaDescription *sal_media_description_new(); -void sal_media_description_destroy(SalMediaDescription *md); +void sal_media_description_ref(SalMediaDescription *md); +void sal_media_description_unref(SalMediaDescription *md); +SalStreamDescription *sal_media_description_find_stream(SalMediaDescription *md, + SalMediaProto proto, SalStreamType type); /*this structure must be at the first byte of the SalOp structure defined by implementors*/ typedef struct SalOpBase{ @@ -240,6 +244,9 @@ int sal_notify_presence(SalOp *op, SalPresenceStatus status, const char *status_ #define payload_type_set_number(pt,n) (pt)->user_data=(void*)((long)n); #define payload_type_get_number(pt) ((int)(long)(pt)->user_data) +/*misc*/ +void sal_get_default_local_ip(Sal *sal, int address_family, char *ip, size_t iplen); + /*internal API */ void __sal_op_init(SalOp *b, Sal *sal); diff --git a/coreapi/sal_eXosip2.c b/coreapi/sal_eXosip2.c index 393e9ee83..5af843c9f 100644 --- a/coreapi/sal_eXosip2.c +++ b/coreapi/sal_eXosip2.c @@ -21,6 +21,13 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "offeranswer.h" +void sal_get_default_local_ip(Sal *sal, int address_family,char *ip, size_t iplen){ + if (eXosip_guess_localip(address_family,ip,iplen)<0){ + /*default to something */ + strncpy(ip,address_family==AF_INET6 ? "::1" : "127.0.0.1",iplen); + ms_error("Could not find default routable ip address !"); + } +} static SalOp * sal_find_register(Sal *sal, int rid){ const MSList *elem; @@ -65,13 +72,59 @@ void sal_op_release(SalOp *op){ sdp_message_free(op->sdp_answer); if (op->pending_auth) eXosip_event_free(op->pending_auth); - if( op->rid!=-1){ + if (op->rid!=-1){ sal_remove_register(op->base.root,op->rid); } + if (op->cid!=-1){ + eXosip_call_set_reference(op->cid,NULL); + } __sal_op_free(op); } +static void _osip_trace_func(char *fi, int li, osip_trace_level_t level, char *chfr, va_list ap){ + int ortp_level=ORTP_DEBUG; + switch(level){ + case OSIP_INFO1: + case OSIP_INFO2: + case OSIP_INFO3: + case OSIP_INFO4: + ortp_level=ORTP_MESSAGE; + break; + case OSIP_WARNING: + ortp_level=ORTP_WARNING; + break; + case OSIP_ERROR: + case OSIP_BUG: + ortp_level=ORTP_ERROR; + break; + case OSIP_FATAL: + ortp_level=ORTP_FATAL; + break; + case END_TRACE_LEVEL: + break; + } + if (ortp_log_level_enabled(level)){ + int len=strlen(chfr); + char *chfrdup=ortp_strdup(chfr); + /*need to remove endline*/ + if (len>1){ + if (chfrdup[len-1]=='\n') + chfrdup[len-1]='\0'; + if (chfrdup[len-2]=='\r') + chfrdup[len-2]='\0'; + } + ortp_logv(ortp_level,chfrdup,ap); + ortp_free(chfrdup); + } +} + + Sal * sal_init(){ + static bool_t firsttime=TRUE; + if (firsttime){ + osip_trace_initialize_func (OSIP_INFO4,&_osip_trace_func); + firsttime=FALSE; + } eXosip_init(); return ms_new0(Sal,1); } @@ -133,7 +186,7 @@ int sal_listen_port(Sal *ctx, const char *addr, int port, SalTransport tr, int i ipv6=strchr(addr,':')!=NULL; eXosip_enable_ipv6(ipv6); - if (tr!=SAL_TRANSPORT_DATAGRAM || is_secure){ + if (tr!=SalTransportDatagram || is_secure){ ms_fatal("SIP over TCP or TLS or DTLS is not supported yet."); return -1; } @@ -176,7 +229,7 @@ static void set_sdp_from_desc(osip_message_t *sip, const SalMediaDescription *de static void sdp_process(SalOp *h){ if (h->result){ - sal_media_description_destroy(h->result); + sal_media_description_unref(h->result); } h->result=sal_media_description_new(); if (h->sdp_offering){ @@ -199,6 +252,10 @@ static void sdp_process(SalOp *h){ } int sal_call_set_local_media_description(SalOp *h, SalMediaDescription *desc){ + if (desc) + sal_media_description_ref(desc); + if (h->base.local_media) + sal_media_description_unref(h->base.local_media); h->base.local_media=desc; return 0; } @@ -334,7 +391,7 @@ static void handle_reinvite(Sal *sal, eXosip_event_t *ev){ op->tid=ev->tid; sdp=eXosip_get_sdp_info(ev->request); if (op->base.remote_media){ - sal_media_description_destroy(op->base.remote_media); + sal_media_description_unref(op->base.remote_media); op->base.remote_media=NULL; } eXosip_lock(); diff --git a/oRTP b/oRTP index 7283d8357..5c64cbd80 160000 --- a/oRTP +++ b/oRTP @@ -1 +1 @@ -Subproject commit 7283d835734d07773ea9e37f89215c123322b48d +Subproject commit 5c64cbd803f83047e7c4d111a31b5d1726079423 From 0267c3213f4af3140959f73fcf95b87e641ed7a3 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Mon, 1 Feb 2010 18:30:15 +0100 Subject: [PATCH 11/50] work in progress --- coreapi/Makefile.am | 1 - coreapi/callbacks.c | 279 +++++++++++++++++++++++++++- coreapi/linphonecore.c | 408 ++++++++++++++++------------------------- coreapi/private.h | 11 +- coreapi/sal.c | 9 + coreapi/sal.h | 14 +- coreapi/sal_eXosip2.c | 107 ++++++++++- coreapi/sal_eXosip2.h | 2 +- 8 files changed, 554 insertions(+), 277 deletions(-) diff --git a/coreapi/Makefile.am b/coreapi/Makefile.am index 2410f2d4e..517780594 100644 --- a/coreapi/Makefile.am +++ b/coreapi/Makefile.am @@ -21,7 +21,6 @@ liblinphone_la_SOURCES=\ sal_eXosip2_sdp.c \ sal_eXosip2_presence.c \ callbacks.c \ - exevents.c sdphandler.c\ misc.c \ address.c \ enum.c enum.h \ diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index 73eeca56e..08267a30d 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -23,28 +23,301 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "linphonecore.h" #include "private.h" +static void linphone_connect_incoming(LinphoneCore *lc, LinphoneCall *call){ + if (lc->vtable.show) + lc->vtable.show(lc); + if (lc->vtable.display_status) + lc->vtable.display_status(lc,_("Connected.")); + call->state=LCStateAVRunning; + if (lc->ringstream!=NULL){ + ring_stop(lc->ringstream); + lc->ringstream=NULL; + } + linphone_core_start_media_streams(lc,call); +} + static void call_received(SalOp *h){ + LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_root(h)); + char *barmesg; + int err; + LinphoneCall *call; + const char *from,*to; + char *tmp; + LinphoneAddress *from_parsed; + + /* first check if we can answer successfully to this invite */ + if (lc->presence_mode!=LINPHONE_STATUS_ONLINE){ + ms_message("Not present !! presence mode : %d\n",lc->presence_mode); + if (lc->presence_mode==LINPHONE_STATUS_BUSY) + sal_call_decline(h,SalReasonBusy,NULL); + else if (lc->presence_mode==LINPHONE_STATUS_AWAY + ||lc->presence_mode==LINPHONE_STATUS_BERIGHTBACK + ||lc->presence_mode==LINPHONE_STATUS_ONTHEPHONE + ||lc->presence_mode==LINPHONE_STATUS_OUTTOLUNCH + ||lc->presence_mode==LINPHONE_STATUS_OFFLINE) + sal_call_decline(h,SalReasonTemporarilyUnavailable,NULL); + else if (lc->presence_mode==LINPHONE_STATUS_NOT_DISTURB) + sal_call_decline(h,SalReasonTemporarilyUnavailable,NULL); + else if (lc->alt_contact!=NULL && lc->presence_mode==LINPHONE_STATUS_MOVED) + sal_call_decline(h,SalReasonRedirect,lc->alt_contact); + else + sal_call_decline(h,SalReasonBusy,NULL); + sal_op_release(op); + return; + } + if (lc->call!=NULL){/*busy*/ + sal_call_decline(h,SalReasonBusy,NULL); + sal_op_release(op); + return; + } + from=sal_op_get_from(op); + to=sal_op_get_to(op); + + call=linphone_call_new_incoming(lc,linphone_address_new(from),linphone_address_new(to),op); + lc->call=call; + sal_call_set_local_media_description(op,call->localdesc); + call->resultdesc=sal_call_get_final_media_description(op); + if (call->resultdesc && sal_media_description_empty(call->resultdesc){ + sal_call_decline(op,SalReasonMedia,NULL); + linphone_call_destroy(call); + lc->call=NULL; + return; + } + + from_parsed=linphone_address_new(sal_op_get_from(op)); + linphone_address_clean(from_parsed); + tmp=linphone_address_as_string(from_parsed); + linphone_address_destroy(from_parsed); + gstate_new_state(lc, GSTATE_CALL_IN_INVITE, tmp); + barmesg=ortp_strdup_printf("%s %s",tmp,_("is contacting you.")); + if (lc->vtable.show) lc->vtable.show(lc); + if (lc->vtable.display_status) + lc->vtable.display_status(lc,barmesg); + + /* play the ring */ + if (lc->sound_conf.ring_sndcard!=NULL){ + ms_message("Starting local ring..."); + lc->ringstream=ring_start(lc->sound_conf.local_ring,2000,lc->sound_conf.ring_sndcard); + } + linphone_call_set_state(call,LCStateRinging); + sal_call_notify_ringing(op); + + if (lc->vtable.inv_recv) lc->vtable.inv_recv(lc,tmp); + ms_free(barmesg); + ms_free(tmp); } static void call_ringing(SalOp *h){ + LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_root(h)); + LinphoneCall *call=lc->call; + SalMediaDescription *md; + if (call==NULL) return; + if (lc->vtable.display_status) + lc->vtable.display_status(lc,_("Remote ringing.")); + md=sal_call_get_final_media_description(h); + if (md==NULL){ + if (lc->ringstream!=NULL) return; /*already ringing !*/ + if (lc->sound_conf.play_sndcard!=NULL){ + ms_message("Remote ringing..."); + lc->ringstream=ring_start(lc->sound_conf.remote_ring,2000,lc->sound_conf.play_sndcard); + } + }else{ + /*accept early media */ + if (lc->audiostream->ticker!=NULL){ + /*streams already started */ + ms_message("Early media already started."); + return; + } + sal_media_description_ref(md); + call->resultdesc=md; + if (lc->vtable.show) lc->vtable.show(lc); + if (lc->vtable.display_status) + lc->vtable.display_status(lc,_("Early media.")); + gstate_new_state(lc, GSTATE_CALL_OUT_CONNECTED, NULL); + if (lc->ringstream!=NULL){ + ring_stop(lc->ringstream); + lc->ringstream=NULL; + } + ms_message("Doing early media..."); + linphone_core_start_media_streams(lc,call); + } + call->state=LCStateRinging; } -static void call_accepted(SalOp *h){ +static void call_accepted(SalOp *op){ + LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_root(h)); + LinphoneCall *call=lc->call; + if (call==NULL){ + ms_warning("No call to accept."); + return 0; + } + if (sal_op_get_user_pointer(op)!=lc->call){ + ms_warning("call_accepted: ignoring."); + return; + } + if (call->state==LCStateAVRunning){ + return 0; /*already accepted*/ + } + if (lc->audiostream->ticker!=NULL){ + /*case where we accepted early media */ + linphone_core_stop_media_streams(lc,call); + linphone_core_init_media_streams(lc,call); + } + if (call->resultdesc) + sal_media_description_unref(call->resultdesc); + call->resultdesc=sal_call_get_final_media_description(op); + if (call->resultdesc && !sal_media_description_empty(call->resultdesc)){ + gstate_new_state(lc, GSTATE_CALL_OUT_CONNECTED, NULL); + linphone_connect_incoming(lc,call); + }else{ + /*send a bye*/ + ms_error("Incompatible SDP offer received in 200Ok, need to abort the call"); + linphone_core_terminate_call(lc,NULL); + } } static void call_ack(SalOp *h){ + LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_root(h)); + LinphoneCall *call=lc->call; + if (call==NULL){ + ms_warning("No call to be ACK'd"); + return ; + } + if (sal_op_get_user_pointer(op)!=lc->call){ + ms_warning("call_ack: ignoring."); + return; + } + if (lc->audiostream->ticker!=NULL){ + /*case where we accepted early media */ + linphone_core_stop_media_streams(lc,call); + linphone_core_init_media_streams(lc,call); + } + if (call->resultdesc) + sal_media_description_unref(call->resultdesc); + call->resultdesc=sal_call_get_final_media_description(op); + if (call->resultdesc && !sal_media_description_empty(call->resultdesc)){ + gstate_new_state(lc, GSTATE_CALL_IN_CONNECTED, NULL); + linphone_connect_incoming(lc,call); + }else{ + /*send a bye*/ + ms_error("Incompatible SDP response received in ACK, need to abort the call"); + linphone_core_terminate_call(lc,NULL); + } } static void call_updated(SalOp *){ + LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_root(h)); + linphone_core_stop_media_streams(lc,call); + linphone_core_init_media_streams(lc,call); + if (call->resultdesc) + sal_media_description_unref(call->resultdesc); + call->resultdesc=sal_call_get_final_media_description(op); + if (call->resultdesc && !sal_media_description_empty(call->resultdesc)){ + linphone_connect_incoming(lc,call); + } } -static void call_terminated(SalOp *h){ +static void call_terminated(SalOp *h, const char *from){ + LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_root(h)); + if (sal_op_get_user_pointer(op)!=lc->call){ + ms_warning("call_terminated: ignoring."); + return; + } + ms_message("Current call terminated..."); + if (lc->ringstream!=NULL) { + ring_stop(lc->ringstream); + lc->ringstream=NULL; + } + linphone_core_stop_media_streams(lc,lc->call); + lc->vtable.show(lc); + lc->vtable.display_status(lc,_("Call terminated.")); + gstate_new_state(lc, GSTATE_CALL_END, NULL); + if (lc->vtable.bye_recv!=NULL){ + LinphoneAddress *addr=linphone_address_new(from); + char *tmp; + linphone_address_clean(addr); + tmp=linphone_address_as_string(from); + lc->vtable.bye_recv(lc,tmp); + ms_free(tmp); + linphone_address_destroy(addr); + } + linphone_call_destroy(lc->call); + lc->call=NULL; } -static void call_failure(SalOp *h, SalError error, SalReason reason, const char *details){ +static void call_failure(SalOp *op, SalError error, SalReason sr, const char *details){ + LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_root(h)); + const char *reason=""; + char *msg486=_("User is busy."); + char *msg480=_("User is temporarily unavailable."); + /*char *retrymsg=_("%s. Retry after %i minute(s).");*/ + char *msg600=_("User does not want to be disturbed."); + char *msg603=_("Call declined."); + char* tmpmsg=msg486; + int code; + LinphoneCall *call=lc->call; + if (sal_op_get_user_pointer(op)!=lc->call){ + ms_warning("call_failure: ignoring."); + return; + } + if (lc->vtable.show) lc->vtable.show(lc); + + if (error==SalErrorNoResponse){ + if (lc->vtale.display_status) + lc->vtable.display_status(lc,_("No response.")); + }else if (error==SalErrorProtocol){ + if (lc->vtale.display_status) + lc->vtable.display_status(lc, details ? details : _("Error.")); + }else if (error==SalErrorFailure){ + switch(sr){ + case SalReasonDeclined: + if (lc->vtable.display_status) + lc->vtable.display_status(lc,msg603); + break; + case SalReasonBusy: + if (lc->vtable.display_status) + lc->vtable.display_status(lc,msg486); + break; + case SalReasonRedirect: + if (lc->vtable.display_status) + lc->vtable.display_status(lc,_("Redirected")); + break; + case SalReasonTemporarilyUnavailable: + if (lc->vtable.display_status) + lc->vtable.display_status(lc,msg480); + break; + case SalReasonNotFound: + if (lc->vtable.display_status) + lc->vtable.display_status(lc,msg404); + break; + case SalReasonDoNotDisturb: + if (lc->vtable.display_status) + lc->vtable.display_status(lc,msg600); + break; + case SalReasonMedia: + if (lc->vtable.display_status) + lc->vtable.display_status(lc,_("No common codecs")); + break; + default: + if (lc->vtable.display_status) + lc->vtable.display_status(lc,_("Call failed.")); + } + } + if (lc->ringstream!=NULL) { + ring_stop(lc->ringstream); + lc->ringstream=NULL; + } + linphone_core_stop_media_streams(lc); + if (call!=NULL) { + linphone_call_destroy(call); + gstate_new_state(lc, GSTATE_CALL_ERROR, NULL); + lc->call=NULL; + } } static void auth_requested(SalOp *h, const char *realm, const char *username){ + LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_root(h)); + LinphoneAuthInfo *ai=linphone_core_find_auth_info(lc); } static void auth_success(SalOp *h, const char *realm, const char *username){ diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index f9f47c9e4..33a8d588c 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -115,7 +115,6 @@ static void linphone_call_init_common(LinphoneCall *call, LinphoneAddress *from, linphone_core_notify_all_friends(call->core,LINPHONE_STATUS_ONTHEPHONE); if (linphone_core_get_firewall_policy(call->core)==LINPHONE_POLICY_USE_STUN) linphone_core_run_stun_tests(call->core,call); - call->profile=rtp_profile_new("Call RTP profile"); } static void discover_mtu(LinphoneCore *lc, const char *remote){ @@ -136,6 +135,7 @@ LinphoneCall * linphone_call_new_outgoing(struct _LinphoneCore *lc, LinphoneAddr LinphoneCall *call=ms_new0(LinphoneCall,1); call->dir=LinphoneCallOutgoing; call->op=sal_op_new(lc->sal); + sal_op_set_user_pointer(call->op,lc->call); call->core=lc; linphone_core_get_local_ip(lc,linphone_address_get_domain(to),call->localip); call->localdesc=create_local_media_description (lc,call->localip, @@ -150,6 +150,7 @@ LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *fro LinphoneAddress *me=linphone_core_get_primary_contact_parsed(lc); call->dir=LinphoneCallIncoming; + sal_op_set_user_pointer(op,call); call->op=op; call->core=lc; @@ -168,7 +169,6 @@ void linphone_call_destroy(LinphoneCall *obj) linphone_core_notify_all_friends(obj->core,obj->core->prev_mode); linphone_call_log_completed(obj->log,obj); linphone_core_update_allocated_audio_bandwidth(obj->core); - if (obj->profile!=NULL) rtp_profile_destroy(obj->profile); if (obj->op!=NULL) sal_op_release(obj->op); if (obj->resultdesc!=NULL) sal_media_description_unref(obj->resultdesc); if (obj->localdesc!=NULL) sal_media_description_unref(obj->localdesc); @@ -910,6 +910,7 @@ static void linphone_core_init (LinphoneCore * lc, const LinphoneCoreVTable *vta lc->rpc_enable = 0; #endif lc->sal=sal_init(); + sal_set_user_pointer(lc->sal,lc); if (lp_config_get_int(lc->config,"sip","use_session_timers",0)==1){ sal_use_session_timers(lc->sal,200); } @@ -1313,7 +1314,7 @@ void linphone_core_set_sip_port(LinphoneCore *lc,int port) ms_free(msg); return; } - apply_user_agent(lc->sal); + apply_user_agent(lc); } /** @@ -1368,7 +1369,7 @@ static void proxy_update(LinphoneCore *lc, time_t curtime){ 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); + result,LINPHONE_IPADDR_SIZE); if (strcmp(result,"::1")!=0 && strcmp(result,"127.0.0.1")!=0){ last_status=TRUE; ms_message("Network is up, registering now (%s)",result); @@ -1465,14 +1466,12 @@ static void linphone_core_do_plugin_tasks(LinphoneCore *lc){ * other liblinphone methods. In not the case make sure all liblinphone calls are * serialized with a mutex. **/ -void linphone_core_iterate(LinphoneCore *lc) -{ - eXosip_event_t *ev; - bool_t disconnected=FALSE; +void linphone_core_iterate(LinphoneCore *lc){ int disconnect_timeout = linphone_core_get_nortp_timeout(lc); time_t curtime=time(NULL); int elapsed; bool_t one_second_elapsed=FALSE; + bool_t disconnected=FALSE; if (curtime-lc->prevtime>=1){ lc->prevtime=curtime; @@ -1539,7 +1538,7 @@ void linphone_core_iterate(LinphoneCore *lc) bool_t linphone_core_interpret_url(LinphoneCore *lc, const char *url, LinphoneAddress **real_parsed_url, char **route){ enum_lookup_res_t *enumres=NULL; - osip_to_t *parsed_url=NULL; + LinphoneAddress *parsed_url=NULL; char *enum_domain=NULL; LinphoneProxyConfig *proxy; char *tmpurl; @@ -1590,7 +1589,7 @@ bool_t linphone_core_interpret_url(LinphoneCore *lc, const char *url, LinphoneAd if (real_parsed_url!=NULL) *real_parsed_url=parsed_url; else linphone_address_destroy(parsed_url); if (tmproute) *route=ms_strdup(tmproute); - else *route=guess_route_if_any(lc,*real_parsed_url); + return TRUE; } /* else we could not do anything with url given by user, so display an error */ @@ -1742,9 +1741,9 @@ int linphone_core_invite(LinphoneCore *lc, const char *url) if (err<0){ ms_warning("Could not initiate call."); lc->vtable.display_status(lc,_("could not call")); + linphone_core_stop_media_streams(lc,call); linphone_call_destroy(call); lc->call=NULL; - linphone_core_stop_media_streams(lc); }else gstate_new_state(lc, GSTATE_CALL_OUT_INVITE, url); goto end; @@ -1759,7 +1758,6 @@ int linphone_core_refer(LinphoneCore *lc, const char *url) char *real_url=NULL; LinphoneAddress *real_parsed_url=NULL; LinphoneCall *call; - osip_message_t *msg=NULL; char *route; if (!linphone_core_interpret_url(lc,url,&real_parsed_url, &route)){ /* bad url */ @@ -1773,11 +1771,8 @@ int linphone_core_refer(LinphoneCore *lc, const char *url) } lc->call=NULL; real_url=linphone_address_as_string (real_parsed_url); - eXosip_call_build_refer(call->did, real_url, &msg); + sal_refer(call->op,real_url); ms_free(real_url); - eXosip_lock(); - eXosip_call_send_request(call->did, msg); - eXosip_unlock(); return 0; } @@ -1793,79 +1788,6 @@ bool_t linphone_core_inc_invite_pending(LinphoneCore*lc){ return FALSE; } -#ifdef VINCENT_MAURY_RSVP -/* on=1 for RPC_ENABLE=1...*/ -int linphone_core_set_rpc_mode(LinphoneCore *lc, int on) -{ - if (on==1) - printf("RPC_ENABLE set on\n"); - else - printf("RPC_ENABLE set off\n"); - lc->rpc_enable = (on==1); - /* need to tell eXosip the new setting */ - if (eXosip_set_rpc_mode (lc->rpc_enable)!=0) - return -1; - return 0; -} - -/* on=1 for RSVP_ENABLE=1...*/ -int linphone_core_set_rsvp_mode(LinphoneCore *lc, int on) -{ - if (on==1) - printf("RSVP_ENABLE set on\n"); - else - printf("RSVP_ENABLE set off\n"); - lc->rsvp_enable = (on==1); - /* need to tell eXosip the new setting */ - if (eXosip_set_rsvp_mode (lc->rsvp_enable)!=0) - return -1; - return 0; -} - -/* answer : 1 for yes, 0 for no */ -int linphone_core_change_qos(LinphoneCore *lc, int answer) -{ - char *sdpmesg; - if (lc->call==NULL){ - return -1; - } - - if (lc->rsvp_enable && answer==1) - { - /* answer is yes, local setting is with qos, so - * the user chose to continue with no qos ! */ - /* so switch in normal mode : ring and 180 */ - lc->rsvp_enable = 0; /* no more rsvp */ - eXosip_set_rsvp_mode (lc->rsvp_enable); - /* send 180 */ - eXosip_lock(); - eXosip_answer_call(lc->call->did,180,NULL); - eXosip_unlock(); - /* play the ring */ - ms_message("Starting local ring..."); - lc->ringstream=ring_start(lc->sound_conf.local_ring, - 2000,ms_snd_card_manager_get_card(ms_snd_card_manager_get(),lc->sound_conf.ring_sndcard)); - } - else if (!lc->rsvp_enable && answer==1) - { - /* switch to QoS mode on : answer 183 session progress */ - lc->rsvp_enable = 1; - eXosip_set_rsvp_mode (lc->rsvp_enable); - /* take the sdp already computed, see osipuacb.c */ - sdpmesg=lc->call->sdpctx->answerstr; - eXosip_lock(); - eXosip_answer_call_with_body(lc->call->did,183,"application/sdp",sdpmesg); - eXosip_unlock(); - } - else - { - /* decline offer (603) */ - linphone_core_terminate_call(lc, NULL); - } - return 0; -} -#endif - void linphone_core_init_media_streams(LinphoneCore *lc, LinphoneCall *call){ SalMediaDescription *md=call->localdesc; lc->audiostream=audio_stream_new(md->streams[0].port,linphone_core_ipv6_enabled(lc)); @@ -1893,7 +1815,7 @@ void linphone_core_init_media_streams(LinphoneCore *lc, LinphoneCall *call){ rtp_session_set_transports(lc->audiostream->session,lc->a_rtp,lc->a_rtcp); #ifdef VIDEO_ENABLED - if (lc->video_conf.display || lc->video_conf.capture && md->streams[1].port>0) + if ((lc->video_conf.display || lc->video_conf.capture) && md->streams[1].port>0) lc->videostream=video_stream_new(md->streams[1].port,linphone_core_ipv6_enabled(lc)); #else lc->videostream=NULL; @@ -1973,99 +1895,129 @@ static void post_configure_audio_streams(LinphoneCore *lc){ } } +static RtpProfile *make_profile(LinphoneCore *lc, SalStreamDescription *desc, int *used_pt){ + int bw; + MSList *elem; + RtpProfile *prof=rtp_profile_new("Call profile"); + bool_t first=TRUE; + 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); + for(elem=desc->payloads;elem!=NULL;elem=elem->next){ + PayloadType *pt=(PayloadType*)elem->data; + if (bw>0) pt->normal_bitrate=bw*1000; + else if (desc->type==SalAudio){ + pt->normal_bitrate=-1; + } + if (first) { + *used_pt=payload_type_get_number(pt); + first=FALSE; + } + if (desc->ptime>0){ + char tmp[40]; + snprintf(tmp,sizeof(tmp),"ptime=%i",desc->ptime); + payload_type_append_send_fmtp(pt,tmp); + } + rtp_profile_set_payload(prof,payload_type_get_number(pt),pt); + } + return prof; +} + void linphone_core_start_media_streams(LinphoneCore *lc, LinphoneCall *call){ LinphoneAddress *me=linphone_core_get_primary_contact_parsed(lc); const char *tool="linphone-" LINPHONE_VERSION; char *cname; + int used_pt=-1; /* adjust rtp jitter compensation. It must be at least the latency of the sound card */ int jitt_comp=MAX(lc->sound_conf.latency,lc->rtp_conf.audio_jitt_comp); if (call->media_start_time==0) call->media_start_time=time(NULL); - cname=ortp_strdup_printf("%s@%s",me->url->username,me->url->host); + cname=linphone_address_as_string_uri_only(me); { - StreamParams *audio_params=&call->audio_params; - if (!lc->use_files){ - MSSndCard *playcard=lc->sound_conf.play_sndcard; - MSSndCard *captcard=lc->sound_conf.capt_sndcard; - if (playcard==NULL) { - ms_warning("No card defined for playback !"); - goto end; + SalStreamDescription *stream=sal_media_description_find_stream(call->resultdesc, + SalProtoRtpAvp,SalAudio); + if (stream){ + call->audio_profile=make_profile(lc,stream,&used_pt); + if (!lc->use_files){ + MSSndCard *playcard=lc->sound_conf.play_sndcard; + MSSndCard *captcard=lc->sound_conf.capt_sndcard; + if (playcard==NULL) { + ms_warning("No card defined for playback !"); + goto end; + } + if (captcard==NULL) { + ms_warning("No card defined for capture !"); + goto end; + } + audio_stream_start_now( + lc->audiostream, + call->audio_profile, + stream->addr[0]!='\0' ? stream->addr : call->resultdesc->addr, + stream->port, + stream->port+1, + used_pt, + jitt_comp, + playcard, + captcard, + linphone_core_echo_cancellation_enabled(lc)); + }else{ + audio_stream_start_with_files( + lc->audiostream, + call->audio_profile, + stream->addr[0]!='\0' ? stream->addr : call->resultdesc->addr, + stream->port, + stream->port+1, + used_pt, + 100, + lc->play_file, + lc->rec_file); } - if (captcard==NULL) { - ms_warning("No card defined for capture !"); - goto end; - } - if (audio_params->relay_session_id!=NULL) - audio_stream_set_relay_session_id(lc->audiostream,audio_params->relay_session_id); - audio_stream_start_now( - lc->audiostream, - call->profile, - audio_params->remoteaddr, - audio_params->remoteport, - audio_params->remotertcpport, - audio_params->pt, - jitt_comp, - playcard, - captcard, - linphone_core_echo_cancellation_enabled(lc)); - }else{ - audio_stream_start_with_files( - lc->audiostream, - call->profile, - audio_params->remoteaddr, - audio_params->remoteport, - audio_params->remotertcpport, - audio_params->pt, - 100, - lc->play_file, - lc->rec_file); - } - post_configure_audio_streams(lc); - audio_stream_set_rtcp_information(lc->audiostream, cname, tool); + post_configure_audio_streams(lc); + audio_stream_set_rtcp_information(lc->audiostream, cname, tool); + }else ms_warning("No audio stream defined ?"); } #ifdef VIDEO_ENABLED { + SalStreamDescription *stream=sal_media_description_find_stream(call->resultdesc, + SalProtoRtpAvp,SalVideo); /* shutdown preview */ if (lc->previewstream!=NULL) { video_preview_stop(lc->previewstream); lc->previewstream=NULL; } - if (lc->video_conf.display || lc->video_conf.capture) { - StreamParams *video_params=&call->video_params; - - if (video_params->remoteport>0){ - if (video_params->relay_session_id!=NULL) - video_stream_set_relay_session_id(lc->videostream,video_params->relay_session_id); - 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) - video_stream_start(lc->videostream, - call->profile, video_params->remoteaddr, video_params->remoteport, - video_params->remotertcpport, - video_params->pt, jitt_comp, lc->video_conf.device); - else if (lc->video_conf.display) - video_stream_recv_only_start(lc->videostream, - call->profile, video_params->remoteaddr, video_params->remoteport, - video_params->pt, jitt_comp); - else if (lc->video_conf.capture) - video_stream_send_only_start(lc->videostream, - call->profile, video_params->remoteaddr, video_params->remoteport, - video_params->remotertcpport, - video_params->pt, jitt_comp, lc->video_conf.device); - video_stream_set_rtcp_information(lc->videostream, cname,tool); - } + 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); + 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) + video_stream_start(lc->videostream, + call->video_profile, addr, stream->port, + stream->port+1, + used_pt, jitt_comp, lc->video_conf.device); + else if (lc->video_conf.display) + video_stream_recv_only_start(lc->videostream, + call->video_profile, addr, stream->port, + used_pt, jitt_comp); + else if (lc->video_conf.capture) + video_stream_send_only_start(lc->videostream, + call->video_profile, addr, stream->port, + stream->port+1, + used_pt, jitt_comp, lc->video_conf.device); + video_stream_set_rtcp_information(lc->videostream, cname,tool); } } #endif goto end; end: - ms_free(cname); - linphone_address_destroy(me); - lc->call->state=LCStateAVRunning; + ms_free(cname); + linphone_address_destroy(me); + lc->call->state=LCStateAVRunning; } -void linphone_core_stop_media_streams(LinphoneCore *lc){ +void linphone_core_stop_media_streams(LinphoneCore *lc, LinphoneCall *call){ if (lc->audiostream!=NULL) { audio_stream_stop(lc->audiostream); lc->audiostream=NULL; @@ -2086,6 +2038,14 @@ void linphone_core_stop_media_streams(LinphoneCore *lc){ } } #endif + if (call->audio_profile){ + rtp_profile_destroy(call->audio_profile); + call->audio_profile=NULL; + } + if (call->video_profile){ + rtp_profile_destroy(call->video_profile); + call->video_profile=NULL; + } } /** @@ -2104,17 +2064,14 @@ void linphone_core_stop_media_streams(LinphoneCore *lc){ **/ int linphone_core_accept_call(LinphoneCore *lc, const char *url) { - char *sdpmesg; - osip_message_t *msg=NULL; LinphoneCall *call=lc->call; - int err; - bool_t offering=FALSE; - + const char *contact=NULL; + if (call==NULL){ return -1; } - if (lc->call->state==LCStateAVRunning){ + if (call->state==LCStateAVRunning){ /*call already accepted*/ return -1; } @@ -2126,42 +2083,22 @@ int linphone_core_accept_call(LinphoneCore *lc, const char *url) ms_message("ring stopped"); lc->ringstream=NULL; } - /* sends a 200 OK */ - err=eXosip_call_build_answer(call->tid,200,&msg); - if (err<0 || msg==NULL){ - ms_error("Fail to build answer for call: err=%i",err); - return -1; - } - if (lp_config_get_int(lc->config,"sip","use_session_timers",0)==1){ - if (call->supports_session_timers) osip_message_set_supported(msg, "timer"); - } + /*try to be best-effort in giving real local or routable contact address, except when the user choosed to override the ipaddress */ if (linphone_core_get_firewall_policy(lc)!=LINPHONE_POLICY_USE_NAT_ADDRESS) - fix_contact(lc,msg,call->localip,NULL); - /*if a sdp answer is computed, send it, else send an offer */ - sdpmesg=call->sdpctx->answerstr; - if (sdpmesg==NULL){ - offering=TRUE; - ms_message("generating sdp offer"); - sdpmesg=sdp_context_get_offer(call->sdpctx); - - if (sdpmesg==NULL){ - ms_error("fail to generate sdp offer !"); - return -1; - } - linphone_set_sdp(msg,sdpmesg); - linphone_core_init_media_streams(lc); - }else{ - linphone_set_sdp(msg,sdpmesg); - } - eXosip_lock(); - eXosip_call_send_answer(call->tid,200,msg); - eXosip_unlock(); + contact=get_fixed_contact(lc,call->localip,NULL); + if (contact) + sal_op_set_contact(call->op,contact); + + sal_call_accept(call->op); lc->vtable.display_status(lc,_("Connected.")); gstate_new_state(lc, GSTATE_CALL_IN_CONNECTED, NULL); - - if (!offering) linphone_core_start_media_streams(lc, lc->call); + call->resultdesc=sal_call_get_final_media_description(call->op); + if (call->resultdesc){ + sal_media_description_ref(call->resultdesc); + linphone_core_start_media_streams(lc, call); + } ms_message("call answered."); return 0; } @@ -2181,17 +2118,14 @@ int linphone_core_terminate_call(LinphoneCore *lc, const char *url) return -1; } lc->call=NULL; - - eXosip_lock(); - eXosip_call_terminate(call->cid,call->did); - eXosip_unlock(); + sal_call_terminate(call->op); /*stop ringing*/ if (lc->ringstream!=NULL) { ring_stop(lc->ringstream); lc->ringstream=NULL; } - linphone_core_stop_media_streams(lc); + linphone_core_stop_media_streams(lc,call); lc->vtable.display_status(lc,_("Call ended") ); gstate_new_state(lc, GSTATE_CALL_END, NULL); linphone_call_destroy(call); @@ -2243,22 +2177,13 @@ void linphone_core_set_presence_info(LinphoneCore *lc,int minutes_away, const char *contact, LinphoneOnlineStatus presence_mode) { - int contactok=-1; if (minutes_away>0) lc->minutes_away=minutes_away; - if (contact!=NULL) { - osip_from_t *url; - osip_from_init(&url); - contactok=osip_from_parse(url,contact); - if (contactok>=0) { - ms_message("contact url is correct."); - } - osip_from_free(url); - - } - if (contactok>=0){ - if (lc->alt_contact!=NULL) ms_free(lc->alt_contact); - lc->alt_contact=ms_strdup(contact); + + if (lc->alt_contact!=NULL) { + ms_free(lc->alt_contact); + lc->alt_contact=NULL; } + if (contact) lc->alt_contact=ms_strdup(contact); if (lc->presence_mode!=presence_mode){ linphone_core_notify_all_friends(lc,presence_mode); /* @@ -2270,7 +2195,6 @@ void linphone_core_set_presence_info(LinphoneCore *lc,int minutes_away, } lc->prev_mode=lc->presence_mode; lc->presence_mode=presence_mode; - } LinphoneOnlineStatus linphone_core_get_presence_info(const LinphoneCore *lc){ @@ -2642,7 +2566,7 @@ bool_t linphone_core_agc_enabled(const LinphoneCore *lc){ * @param dtmf The dtmf name specified as a char, such as '0', '#' etc... * **/ -void linphone_core_send_dtmf(LinphoneCore *lc,char dtmf) +void linphone_core_send_dtmf(LinphoneCore *lc, char dtmf) { /*By default we send DTMF RFC2833 if we do not have enabled SIP_INFO but we can also send RFC2833 and SIP_INFO*/ if (linphone_core_get_use_rfc2833_for_dtmf(lc)!=0 || linphone_core_get_use_info_for_dtmf(lc)==0) @@ -2656,26 +2580,13 @@ void linphone_core_send_dtmf(LinphoneCore *lc,char dtmf) ms_error("we cannot send RFC2833 dtmf when we are not in communication"); } } - if (linphone_core_get_use_info_for_dtmf(lc)!=0) - { - char dtmf_body[1000]; - char clen[10]; - osip_message_t *msg=NULL; + if (linphone_core_get_use_info_for_dtmf(lc)!=0){ /* Out of Band DTMF (use INFO method) */ LinphoneCall *call=lc->call; if (call==NULL){ return; } - eXosip_call_build_info(call->did,&msg); - snprintf(dtmf_body, 999, "Signal=%c\r\nDuration=250\r\n", dtmf); - osip_message_set_body(msg,dtmf_body,strlen(dtmf_body)); - osip_message_set_content_type(msg,"application/dtmf-relay"); - snprintf(clen,sizeof(clen),"%lu",(unsigned long)strlen(dtmf_body)); - osip_message_set_content_length(msg,clen); - - eXosip_lock(); - eXosip_call_send_request(call->did,msg); - eXosip_unlock(); + sal_call_send_dtmf(call->op,dtmf); } } @@ -2742,7 +2653,7 @@ static void apply_nat_settings(LinphoneCore *lc){ if (err!=0){ wmsg=ortp_strdup_printf(_("Invalid nat address '%s' : %s"), addr, gai_strerror(err)); - ms_warning(wmsg); // what is this for ? + ms_warning("%s",wmsg); // what is this for ? lc->vtable.display_warning(lc, wmsg); ms_free(wmsg); ms_free(tmp); @@ -2756,22 +2667,16 @@ static void apply_nat_settings(LinphoneCore *lc){ if (lc->net_conf.firewall_policy==LINPHONE_POLICY_USE_NAT_ADDRESS){ if (tmp!=NULL){ if (!lc->net_conf.nat_sdp_only){ - eXosip_set_option(EXOSIP_OPT_SET_IPV4_FOR_GATEWAY,tmp); - /* the following does not work in all cases */ - /* - eXosip_masquerade_contact(tmp,lc->sip_conf.sip_port); - */ + sal_masquerade(lc->sal,tmp); } ms_free(tmp); } else{ - eXosip_set_option(EXOSIP_OPT_SET_IPV4_FOR_GATEWAY,NULL); - eXosip_masquerade_contact("",0); + sal_masquerade(lc->sal,NULL); } } else { - eXosip_set_option(EXOSIP_OPT_SET_IPV4_FOR_GATEWAY,NULL); - eXosip_masquerade_contact("",0); + sal_masquerade(lc->sal,NULL); } } @@ -3197,23 +3102,17 @@ void sip_config_uninit(LinphoneCore *lc) linphone_proxy_config_edit(cfg); /* to unregister */ } - if (exosip_running) - { + if (lc->sal){ int i; - for (i=0;i<20;i++) - { - eXosip_event_t *ev; - while((ev=eXosip_event_wait(0,0))!=NULL){ - linphone_core_process_event(lc,ev); - } - eXosip_automatic_action(); + for (i=0;i<20;i++){ + sal_iterate(lc->sal); #ifndef WIN32 - usleep(100000); + usleep(100000); #else - Sleep(100); + Sleep(100); #endif - } - } + } + } linphone_proxy_config_write_to_config_file(lc->config,NULL,i); /*mark the end */ @@ -3222,6 +3121,8 @@ void sip_config_uninit(LinphoneCore *lc) linphone_auth_info_write_config(lc->config,ai,i); } linphone_auth_info_write_config(lc->config,NULL,i); /* mark the end */ + sal_uninit(lc->sal); + lc->sal=NULL; } void rtp_config_uninit(LinphoneCore *lc) @@ -3341,7 +3242,6 @@ static void linphone_core_uninit(LinphoneCore *lc) linphone_core_free_payload_types(); ortp_exit(); - eXosip_quit(); exosip_running=FALSE; gstate_new_state(lc, GSTATE_POWER_OFF, NULL); } diff --git a/coreapi/private.h b/coreapi/private.h index 93832080c..667fdb7ac 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -67,7 +67,8 @@ typedef struct _LinphoneCall SalMediaDescription *localdesc; SalMediaDescription *resultdesc; LinphoneCallDir dir; - struct _RtpProfile *profile; /*points to the local_profile or to the remote "guessed" profile*/ + struct _RtpProfile *audio_profile; + struct _RtpProfile *video_profile; struct _LinphoneCallLog *log; SalOp *op; char localip[LINPHONE_IPADDR_SIZE]; /* our best guess for local ipaddress for this call */ @@ -87,7 +88,7 @@ void linphone_call_log_completed(LinphoneCallLog *calllog, LinphoneCall *call); void linphone_call_log_destroy(LinphoneCallLog *cl); -void linphone_core_init_media_streams(LinphoneCore *lc); +void linphone_core_init_media_streams(LinphoneCore *lc, LinphoneCall *call); void linphone_auth_info_write_config(struct _LpConfig *config, LinphoneAuthInfo *obj, int pos); @@ -112,8 +113,8 @@ bool_t host_has_ipv6_network(); bool_t lp_spawn_command_line_sync(const char *command, char **result,int *command_ret); static inline int get_min_bandwidth(int dbw, int ubw){ - if (dbw<0) return ubw; - if (ubw<0) return dbw; + if (dbw<=0) return ubw; + if (ubw<=0) return dbw; return MIN(dbw,ubw); } @@ -165,7 +166,7 @@ int linphone_proxy_config_normalize_number(LinphoneProxyConfig *cfg, const char /*internal use only */ void linphone_core_start_media_streams(LinphoneCore *lc, struct _LinphoneCall *call); -void linphone_core_stop_media_streams(LinphoneCore *lc); +void linphone_core_stop_media_streams(LinphoneCore *lc, struct _LinphoneCall *call); const char * linphone_core_get_identity(LinphoneCore *lc); const char * linphone_core_get_route(LinphoneCore *lc); bool_t linphone_core_interpret_url(LinphoneCore *lc, const char *url, LinphoneAddress **real_parsed_url, char **route); diff --git a/coreapi/sal.c b/coreapi/sal.c index 150d7d94a..6ff25bc10 100644 --- a/coreapi/sal.c +++ b/coreapi/sal.c @@ -28,6 +28,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. SalMediaDescription *sal_media_description_new(){ SalMediaDescription *md=ms_new0(SalMediaDescription,1); md->refcount=1; + return md; } static void sal_media_description_destroy(SalMediaDescription *md){ @@ -60,6 +61,14 @@ SalStreamDescription *sal_media_description_find_stream(SalMediaDescription *md, return NULL; } +bool_t sal_media_description_empty(SalMediaDescription *md){ + int i; + for(i=0;instreams;++i){ + SalStreamDescription *ss=&md->streams[i]; + if (ss->port!=0) return FALSE; + } + return TRUE; +} static void assign_string(char **str, const char *arg){ if (*str){ diff --git a/coreapi/sal.h b/coreapi/sal.h index 37b28c189..ebd8bc1e0 100644 --- a/coreapi/sal.h +++ b/coreapi/sal.h @@ -62,6 +62,8 @@ void sal_address_destroy(SalAddress *u); Sal * sal_init(); void sal_uninit(Sal* sal); +void sal_set_user_pointer(Sal *sal, void *user_data); +void *sal_get_user_pointer(const Sal *sal); typedef enum { SalTransportDatagram, @@ -103,6 +105,7 @@ typedef struct SalMediaDescription{ SalMediaDescription *sal_media_description_new(); void sal_media_description_ref(SalMediaDescription *md); void sal_media_description_unref(SalMediaDescription *md); +bool_t sal_media_description_empty(SalMediaDescription *md); SalStreamDescription *sal_media_description_find_stream(SalMediaDescription *md, SalMediaProto proto, SalStreamType type); @@ -121,7 +124,7 @@ typedef struct SalOpBase{ typedef enum SalError{ SalErrorNoResponse, - SalErrorMedia, + SalErrorProtocol, SalErrorFailure, /* see SalReason for more details */ SalErrorUnknown } SalError; @@ -133,6 +136,7 @@ typedef enum SalReason{ SalReasonTemporarilyUnavailable, SalReasonNotFound, SalReasonDoNotDisturb, + SalReasonMedia, SalReasonForbidden, SalReasonUnknown }SalReason; @@ -155,7 +159,7 @@ typedef void (*SalOnCallRinging)(SalOp *op); typedef void (*SalOnCallAccepted)(SalOp *op); typedef void (*SalOnCallAck)(SalOp *op); typedef void (*SalOnCallUpdated)(SalOp *op); -typedef void (*SalOnCallTerminated)(SalOp *op); +typedef void (*SalOnCallTerminated)(SalOp *op, const char *from); typedef void (*SalOnCallFailure)(SalOp *op, SalError error, SalReason reason, const char *details); typedef void (*SalOnAuthRequested)(SalOp *op, const char *realm, const char *username); typedef void (*SalOnAuthSuccess)(SalOp *op, const char *realm, const char *username); @@ -200,6 +204,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); void sal_set_user_agent(Sal *ctx, const char *user_agent); +void sal_masquerade(Sal *ctx, const char *ip); void sal_use_session_timers(Sal *ctx, int expires); int sal_iterate(Sal *sal); @@ -223,9 +228,12 @@ void *sal_op_get_user_pointer(const SalOp *op); /*Call API*/ int sal_call_set_local_media_description(SalOp *h, SalMediaDescription *desc); int sal_call(SalOp *h, const char *from, const char *to); +int sal_call_notify_ringing(SalOp *h); int sal_call_accept(SalOp*h); int sal_call_decline(SalOp *h, SalReason reason, const char *redirection /*optional*/); -const SalMediaDescription * sal_call_get_final_media_description(SalOp *h); +SalMediaDescription * sal_call_get_final_media_description(SalOp *h); +int sal_refer(SalOp *h, const char *refer_to); +int sal_call_send_dtmf(SalOp *h, char dtmf); int sal_call_terminate(SalOp *h); /*Registration*/ diff --git a/coreapi/sal_eXosip2.c b/coreapi/sal_eXosip2.c index 5af843c9f..6056533b9 100644 --- a/coreapi/sal_eXosip2.c +++ b/coreapi/sal_eXosip2.c @@ -134,6 +134,18 @@ void sal_uninit(Sal* sal){ ms_free(sal); } +void sal_set_user_pointer(Sal *sal, void *user_data){ + sal->up=user_data; +} + +void *sal_get_user_pointer(const Sal *sal){ + return sal->up; +} + +void sal_masquerade(Sal *ctx, const char *ip){ + eXosip_set_option(EXOSIP_OPT_SET_IPV4_FOR_GATEWAY,ip); +} + static void unimplemented_stub(){ ms_warning("Unimplemented SAL callback"); } @@ -293,8 +305,16 @@ int sal_call(SalOp *h, const char *from, const char *to){ return 0; } +int sal_call_notify_ringing(SalOp *h){ + eXosip_lock(); + eXosip_call_send_answer(h->tid,180,NULL); + eXosip_unlock(); + return 0; +} + int sal_call_accept(SalOp * h){ osip_message_t *msg; + const char *contact=sal_op_get_contact(h); /* sends a 200 OK */ int err=eXosip_call_build_answer(h->tid,200,&msg); if (err<0 || msg==NULL){ @@ -304,6 +324,8 @@ int sal_call_accept(SalOp * h){ if (h->base.root->session_expires!=0){ if (h->supports_session_timers) osip_message_set_supported(msg, "timer"); } + + if (contact) osip_message_set_contact(msg,contact); if (h->base.local_media){ /*this is the case where we received an invite without SDP*/ @@ -320,18 +342,80 @@ int sal_call_accept(SalOp * h){ return 0; } -const SalMediaDescription * sal_call_get_final_media_description(SalOp *h){ +int sal_call_decline(SalOp *h, SalReason reason, const char *redirect){ + if (reason==SalReasonBusy){ + eXosip_lock(); + eXosip_call_send_answer(h->tid,486,NULL); + eXosip_unlock(); + } + else if (reason==SalReasonTemporarilyUnavailable){ + eXosip_lock(); + eXosip_call_send_answer(h->tid,480,NULL); + eXosip_unlock(); + }else if (reason==SalReasonDoNotDisturb){ + eXosip_lock(); + eXosip_call_send_answer(h->tid,600,NULL); + eXosip_unlock(); + }else if (reason==SalReasonMedia){ + eXosip_lock(); + eXosip_call_send_answer(h->tid,415,NULL); + eXosip_unlock(); + }else if (redirect!=NULL && reason==SalReasonRedirect){ + osip_message_t *msg; + int code; + if (strstr(redirect,"sip:")!=0) code=302; + else code=380; + eXosip_lock(); + eXosip_call_build_answer(h->tid,code,&msg); + osip_message_set_contact(msg,redirect); + eXosip_call_send_answer(h->tid,code,msg); + eXosip_unlock(); + }else sal_call_terminate(h); + return 0; +} + +SalMediaDescription * sal_call_get_final_media_description(SalOp *h){ if (h->base.local_media && h->base.remote_media && !h->result){ sdp_process(h); } return h->result; } +int sal_refer(SalOp *h, const char *refer_to){ + osip_message_t *msg=NULL; + int err=0; + eXosip_lock(); + eXosip_call_build_refer(h->did,refer_to, &msg); + if (msg) err=eXosip_call_send_request(h->did, msg); + else err=-1; + eXosip_unlock(); + return err; +} + +int sal_call_send_dtmf(SalOp *h, char dtmf){ + osip_message_t *msg=NULL; + char dtmf_body[128]; + char clen[10]; + + eXosip_lock(); + eXosip_call_build_info(h->did,&msg); + if (msg){ + snprintf(dtmf_body, sizeof(dtmf_body), "Signal=%c\r\nDuration=250\r\n", dtmf); + osip_message_set_body(msg,dtmf_body,strlen(dtmf_body)); + osip_message_set_content_type(msg,"application/dtmf-relay"); + snprintf(clen,sizeof(clen),"%lu",(unsigned long)strlen(dtmf_body)); + osip_message_set_content_length(msg,clen); + eXosip_call_send_request(h->did,msg); + } + eXosip_unlock(); + return 0; +} + int sal_call_terminate(SalOp *h){ eXosip_lock(); eXosip_call_terminate(h->cid,h->did); - eXosip_unlock(); eXosip_call_set_reference(h->cid,NULL); + eXosip_unlock(); return 0; } @@ -494,13 +578,17 @@ static void call_accepted(Sal *sal, eXosip_event_t *ev){ static void call_terminated(Sal *sal, eXosip_event_t *ev){ SalOp *op; + char *from; op=(SalOp*)ev->external_reference; 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); - sal->callbacks.call_terminated(op); + op->cid=-1; + sal->callbacks.call_terminated(op,from); + osip_free(from); } static void call_released(Sal *sal, eXosip_event_t *ev){ @@ -510,7 +598,7 @@ static void call_released(Sal *sal, eXosip_event_t *ev){ return; } eXosip_call_set_reference(ev->cid,NULL); - sal->callbacks.call_terminated(op); + /*sal->callbacks.call_terminated(op);*/ } static int get_auth_data(eXosip_event_t *ev, const char **realm, const char **username){ @@ -600,7 +688,8 @@ static bool_t call_failure(Sal *sal, eXosip_event_t *ev){ sr=SalReasonNotFound; break; case 415: - error=SalErrorMedia; + error=SalErrorFailure; + sr=SalReasonMedia; break; case 422: eXosip_default_action(ev); @@ -1031,11 +1120,9 @@ int sal_iterate(Sal *sal){ if (process_event(sal,ev)) eXosip_event_free(ev); } - if (sal->automatic_action==0) { - eXosip_lock(); - eXosip_automatic_refresh(); - eXosip_unlock(); - } + eXosip_lock(); + eXosip_automatic_refresh(); + eXosip_unlock(); } return 0; } diff --git a/coreapi/sal_eXosip2.h b/coreapi/sal_eXosip2.h index c0d32fe0e..a2bae79f4 100644 --- a/coreapi/sal_eXosip2.h +++ b/coreapi/sal_eXosip2.h @@ -35,7 +35,7 @@ struct Sal{ MSList *in_subscribes;/*MSList of SalOp */ int running; int session_expires; - int automatic_action; + void *up; }; struct SalOp{ From 2b236a98b907b59e367c1b3d090653b686ad69f6 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Tue, 2 Feb 2010 16:24:43 +0100 Subject: [PATCH 12/50] advance oRTP and mediastreamer2 on dev_sal --- mediastreamer2 | 2 +- oRTP | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mediastreamer2 b/mediastreamer2 index 637302226..98911772b 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 6373022261b4a529400a0c0e1661b4d3e5ebc7c5 +Subproject commit 98911772b35a137e0026626138426abac1d1ada1 diff --git a/oRTP b/oRTP index 5c64cbd80..fd65d8401 160000 --- a/oRTP +++ b/oRTP @@ -1 +1 @@ -Subproject commit 5c64cbd803f83047e7c4d111a31b5d1726079423 +Subproject commit fd65d84014c4cb3c500952c2f4b42dc4630ac37d From cfbc05d22f54e127bbb11d1e3193718be91999a7 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Wed, 3 Feb 2010 11:20:56 +0100 Subject: [PATCH 13/50] fix bad copy/paste related to jitter buffer configuration --- coreapi/linphonecore.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 33a8d588c..7039a8225 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -3131,7 +3131,7 @@ void rtp_config_uninit(LinphoneCore *lc) lp_config_set_int(lc->config,"rtp","audio_rtp_port",config->audio_rtp_port); lp_config_set_int(lc->config,"rtp","video_rtp_port",config->video_rtp_port); lp_config_set_int(lc->config,"rtp","audio_jitt_comp",config->audio_jitt_comp); - lp_config_set_int(lc->config,"rtp","video_jitt_comp",config->audio_jitt_comp); + lp_config_set_int(lc->config,"rtp","video_jitt_comp",config->video_jitt_comp); lp_config_set_int(lc->config,"rtp","nortp_timeout",config->nortp_timeout); } From 9fc1a85d4fceac0726c36a6da1ebc81d166842f6 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Wed, 3 Feb 2010 15:02:05 +0100 Subject: [PATCH 14/50] update mediastreamer2 --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index 98911772b..a11023fbc 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 98911772b35a137e0026626138426abac1d1ada1 +Subproject commit a11023fbcc2ba355d40d474cc6b863e29a4960fb From fdd99cd205ebdc3d678696e7096ce50a7dc44faa Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Fri, 5 Feb 2010 18:42:34 +0100 Subject: [PATCH 15/50] sal in progress, near to code complete. --- coreapi/authentication.c | 2 - coreapi/callbacks.c | 133 +++++++--- coreapi/chat.c | 43 ++-- coreapi/friend.c | 432 +++++++-------------------------- coreapi/linphonecore.c | 100 ++++++-- coreapi/linphonecore.h | 13 +- coreapi/misc.c | 173 ++----------- coreapi/presence.c | 205 +++++++--------- coreapi/private.h | 19 +- coreapi/proxy.c | 423 ++++---------------------------- coreapi/sal.c | 8 + coreapi/sal.h | 32 ++- coreapi/sal_eXosip2.c | 67 ++++- coreapi/sal_eXosip2.h | 3 + coreapi/sal_eXosip2_presence.c | 201 ++++++++++++--- coreapi/sal_eXosip2_sdp.c | 35 ++- mediastreamer2 | 2 +- oRTP | 2 +- 18 files changed, 735 insertions(+), 1158 deletions(-) diff --git a/coreapi/authentication.c b/coreapi/authentication.c index ee360ecfe..e55ab495a 100644 --- a/coreapi/authentication.c +++ b/coreapi/authentication.c @@ -51,7 +51,6 @@ LinphoneAuthInfo *linphone_auth_info_new(const char *username, const char *useri if (ha1!=NULL && (strlen(ha1)>0)) obj->ha1=ms_strdup(ha1); if (realm!=NULL && (strlen(realm)>0)) obj->realm=ms_strdup(realm); obj->works=FALSE; - obj->first_time=TRUE; return obj; } @@ -252,7 +251,6 @@ void linphone_core_add_auth_info(LinphoneCore *lc, LinphoneAuthInfo *info) } refresh_exosip_auth_info(lc); /* if the user was prompted, re-allow automatic_action */ - if (lc->automatic_action>0) lc->automatic_action--; } diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index 08267a30d..a95f3570d 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -22,6 +22,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "linphonecore.h" #include "private.h" +#include "mediastreamer2/mediastream.h" static void linphone_connect_incoming(LinphoneCore *lc, LinphoneCall *call){ if (lc->vtable.show) @@ -37,9 +38,8 @@ static void linphone_connect_incoming(LinphoneCore *lc, LinphoneCall *call){ } static void call_received(SalOp *h){ - LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_root(h)); + LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(h)); char *barmesg; - int err; LinphoneCall *call; const char *from,*to; char *tmp; @@ -62,34 +62,34 @@ static void call_received(SalOp *h){ sal_call_decline(h,SalReasonRedirect,lc->alt_contact); else sal_call_decline(h,SalReasonBusy,NULL); - sal_op_release(op); + sal_op_release(h); return; } if (lc->call!=NULL){/*busy*/ sal_call_decline(h,SalReasonBusy,NULL); - sal_op_release(op); + sal_op_release(h); return; } - from=sal_op_get_from(op); - to=sal_op_get_to(op); + from=sal_op_get_from(h); + to=sal_op_get_to(h); - call=linphone_call_new_incoming(lc,linphone_address_new(from),linphone_address_new(to),op); + call=linphone_call_new_incoming(lc,linphone_address_new(from),linphone_address_new(to),h); lc->call=call; - sal_call_set_local_media_description(op,call->localdesc); - call->resultdesc=sal_call_get_final_media_description(op); - if (call->resultdesc && sal_media_description_empty(call->resultdesc){ - sal_call_decline(op,SalReasonMedia,NULL); + sal_call_set_local_media_description(h,call->localdesc); + call->resultdesc=sal_call_get_final_media_description(h); + if (call->resultdesc && sal_media_description_empty(call->resultdesc)){ + sal_call_decline(h,SalReasonMedia,NULL); linphone_call_destroy(call); lc->call=NULL; return; } - from_parsed=linphone_address_new(sal_op_get_from(op)); + from_parsed=linphone_address_new(sal_op_get_from(h)); linphone_address_clean(from_parsed); tmp=linphone_address_as_string(from_parsed); linphone_address_destroy(from_parsed); gstate_new_state(lc, GSTATE_CALL_IN_INVITE, tmp); - barmesg=ortp_strdup_printf("%s %s",tmp,_("is contacting you.")); + barmesg=ortp_strdup_printf(_("%s is contacting you"),tmp); if (lc->vtable.show) lc->vtable.show(lc); if (lc->vtable.display_status) lc->vtable.display_status(lc,barmesg); @@ -100,7 +100,7 @@ static void call_received(SalOp *h){ lc->ringstream=ring_start(lc->sound_conf.local_ring,2000,lc->sound_conf.ring_sndcard); } linphone_call_set_state(call,LCStateRinging); - sal_call_notify_ringing(op); + sal_call_notify_ringing(h); if (lc->vtable.inv_recv) lc->vtable.inv_recv(lc,tmp); ms_free(barmesg); @@ -108,7 +108,7 @@ static void call_received(SalOp *h){ } static void call_ringing(SalOp *h){ - LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_root(h)); + LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(h)); LinphoneCall *call=lc->call; SalMediaDescription *md; if (call==NULL) return; @@ -145,18 +145,18 @@ static void call_ringing(SalOp *h){ } static void call_accepted(SalOp *op){ - LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_root(h)); + LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op)); LinphoneCall *call=lc->call; if (call==NULL){ ms_warning("No call to accept."); - return 0; + return ; } if (sal_op_get_user_pointer(op)!=lc->call){ ms_warning("call_accepted: ignoring."); return; } if (call->state==LCStateAVRunning){ - return 0; /*already accepted*/ + return ; /*already accepted*/ } if (lc->audiostream->ticker!=NULL){ /*case where we accepted early media */ @@ -176,8 +176,8 @@ static void call_accepted(SalOp *op){ } } -static void call_ack(SalOp *h){ - LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_root(h)); +static void call_ack(SalOp *op){ + LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op)); LinphoneCall *call=lc->call; if (call==NULL){ ms_warning("No call to be ACK'd"); @@ -205,8 +205,9 @@ static void call_ack(SalOp *h){ } } -static void call_updated(SalOp *){ - LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_root(h)); +static void call_updated(SalOp *op){ + LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op)); + LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(op); linphone_core_stop_media_streams(lc,call); linphone_core_init_media_streams(lc,call); if (call->resultdesc) @@ -217,8 +218,8 @@ static void call_updated(SalOp *){ } } -static void call_terminated(SalOp *h, const char *from){ - LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_root(h)); +static void call_terminated(SalOp *op, const char *from){ + LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op)); if (sal_op_get_user_pointer(op)!=lc->call){ ms_warning("call_terminated: ignoring."); return; @@ -236,7 +237,7 @@ static void call_terminated(SalOp *h, const char *from){ LinphoneAddress *addr=linphone_address_new(from); char *tmp; linphone_address_clean(addr); - tmp=linphone_address_as_string(from); + tmp=linphone_address_as_string(addr); lc->vtable.bye_recv(lc,tmp); ms_free(tmp); linphone_address_destroy(addr); @@ -246,16 +247,14 @@ static void call_terminated(SalOp *h, const char *from){ } static void call_failure(SalOp *op, SalError error, SalReason sr, const char *details){ - LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_root(h)); - const char *reason=""; + LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op)); char *msg486=_("User is busy."); char *msg480=_("User is temporarily unavailable."); /*char *retrymsg=_("%s. Retry after %i minute(s).");*/ char *msg600=_("User does not want to be disturbed."); char *msg603=_("Call declined."); - char* tmpmsg=msg486; - int code; LinphoneCall *call=lc->call; + if (sal_op_get_user_pointer(op)!=lc->call){ ms_warning("call_failure: ignoring."); return; @@ -263,10 +262,10 @@ static void call_failure(SalOp *op, SalError error, SalReason sr, const char *de if (lc->vtable.show) lc->vtable.show(lc); if (error==SalErrorNoResponse){ - if (lc->vtale.display_status) + if (lc->vtable.display_status) lc->vtable.display_status(lc,_("No response.")); }else if (error==SalErrorProtocol){ - if (lc->vtale.display_status) + if (lc->vtable.display_status) lc->vtable.display_status(lc, details ? details : _("Error.")); }else if (error==SalErrorFailure){ switch(sr){ @@ -288,7 +287,7 @@ static void call_failure(SalOp *op, SalError error, SalReason sr, const char *de break; case SalReasonNotFound: if (lc->vtable.display_status) - lc->vtable.display_status(lc,msg404); + lc->vtable.display_status(lc,_("Not found")); break; case SalReasonDoNotDisturb: if (lc->vtable.display_status) @@ -307,7 +306,7 @@ static void call_failure(SalOp *op, SalError error, SalReason sr, const char *de ring_stop(lc->ringstream); lc->ringstream=NULL; } - linphone_core_stop_media_streams(lc); + linphone_core_stop_media_streams(lc,call); if (call!=NULL) { linphone_call_destroy(call); gstate_new_state(lc, GSTATE_CALL_ERROR, NULL); @@ -316,41 +315,94 @@ static void call_failure(SalOp *op, SalError error, SalReason sr, const char *de } static void auth_requested(SalOp *h, const char *realm, const char *username){ - LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_root(h)); - LinphoneAuthInfo *ai=linphone_core_find_auth_info(lc); + LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(h)); + LinphoneAuthInfo *ai=linphone_core_find_auth_info(lc,realm,username); + if (ai && (ai->works || ai->usecount<3)){ + SalAuthInfo sai; + sai.username=ai->username; + sai.userid=ai->userid; + sai.realm=ai->realm; + sai.password=ai->passwd; + sal_op_authenticate(h,&sai); + ai->usecount++; + }else{ + if (lc->vtable.auth_info_requested) + lc->vtable.auth_info_requested(lc,realm,username); + } } static void auth_success(SalOp *h, const char *realm, const char *username){ + LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(h)); + LinphoneAuthInfo *ai=linphone_core_find_auth_info(lc,realm,username); + if (ai) + ai->works=TRUE; } static void register_success(SalOp *op, bool_t registered){ + LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op)); + LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)sal_op_get_user_pointer(op); + char *msg; + gstate_new_state(lc, GSTATE_REG_OK, NULL); + if (cfg->registered) msg=ms_strdup_printf(_("Registration on %s successful."),sal_op_get_proxy(op)); + else msg=ms_strdup_printf(_("Unregistration on %s done."),sal_op_get_proxy(op)); + if (lc->vtable.display_status) + lc->vtable.display_status(lc,msg); + ms_free(msg); } static void register_failure(SalOp *op, SalError error, SalReason reason, const char *details){ + LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op)); + char *msg=ortp_strdup_printf(_("Registration on %s failed: %s"),sal_op_get_proxy(op),(details!=NULL) ? details : _("no response timeout")); + if (lc->vtable.display_status) lc->vtable.display_status(lc,msg); + gstate_new_state(lc, GSTATE_REG_FAILED, msg); + ms_free(msg); } static void vfu_request(SalOp *op){ + LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op)); +#ifdef VIDEO_ENABLED + if (lc->videostream) + video_stream_send_vfu(lc->videostream); +#endif } static void dtmf_received(SalOp *op, char dtmf){ + LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op)); + if (lc->vtable.dtmf_received != NULL) + lc->vtable.dtmf_received(lc, dtmf); } -static void refer_received(SalOp *op, SalOp *op, const char *referto){ +static void refer_received(Sal *sal, SalOp *op, const char *referto){ + LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal); + if (lc->vtable.refer_received) + lc->vtable.refer_received(lc,referto); } static void text_received(Sal *sal, const char *from, const char *msg){ + LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal); + linphone_core_text_received(lc,from,msg); } -static void presence_changed(SalOp *op, SalPresenceStatus status, const char *msg){ +static void notify(SalOp *op, SalSubscribeState ss, SalPresenceStatus status, const char *msg){ + LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op)); + linphone_notify_recv(lc,op,ss,status); } static void subscribe_received(SalOp *op, const char *from){ + LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op)); + linphone_subscription_new(lc,op,from); } -static void internal_message(SalOp *op, const char *msg){ +static void subscribe_closed(SalOp *op, const char *from){ + LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op)); + linphone_subscription_closed(lc,op); } - +static void internal_message(Sal *sal, const char *msg){ + LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal); + if (lc->vtable.show) + lc->vtable.show(lc); +} SalCallbacks linphone_sal_callbacks={ call_received, @@ -368,8 +420,9 @@ SalCallbacks linphone_sal_callbacks={ dtmf_received, refer_received, text_received, - presence_changed, + notify, subscribe_received, + subscribe_closed, internal_message }; diff --git a/coreapi/chat.c b/coreapi/chat.c index 95526274c..11c3c978f 100644 --- a/coreapi/chat.c +++ b/coreapi/chat.c @@ -24,7 +24,6 @@ #include "linphonecore.h" #include "private.h" - #include LinphoneChatRoom * linphone_core_create_chat_room(LinphoneCore *lc, const char *to){ LinphoneAddress *parsed_url=NULL; @@ -52,11 +51,10 @@ void linphone_chat_room_send_message(LinphoneChatRoom *cr, const char *msg){ const char *identity=linphone_core_get_identity(cr->lc); - osip_message_t *sip=NULL; - eXosip_message_build_request(&sip,"MESSAGE",cr->peer,identity,cr->route); - osip_message_set_content_type(sip,"text/plain"); - osip_message_set_body(sip,msg,strlen(msg)); - eXosip_message_send_request(sip); + SalOp *op=sal_op_new(cr->lc->sal); + + sal_op_set_route(op,cr->route); + sal_text_send(op,identity,cr->peer,msg); } bool_t linphone_chat_room_matches(LinphoneChatRoom *cr, const LinphoneAddress *from){ @@ -69,40 +67,29 @@ void linphone_chat_room_text_received(LinphoneChatRoom *cr, LinphoneCore *lc, co if (lc->vtable.text_received!=NULL) lc->vtable.text_received(lc, cr, from, msg); } -void linphone_core_text_received(LinphoneCore *lc, eXosip_event_t *ev){ +void linphone_core_text_received(LinphoneCore *lc, const char *from, const char *msg){ MSList *elem; - const char *msg; LinphoneChatRoom *cr=NULL; - char *from; - osip_from_t *from_url=ev->request->from; - osip_body_t *body=NULL; - LinphoneAddress *uri; + LinphoneAddress *addr; + char *cleanfrom; - osip_message_get_body(ev->request,0,&body); - if (body==NULL){ - ms_error("Could not get text message from SIP body"); - return; - } - msg=body->body; - osip_from_to_str(from_url,&from); - uri=linphone_address_new(from); - osip_free(from); - linphone_address_clean(uri); + addr=linphone_address_new(from); + linphone_address_clean(addr); for(elem=lc->chatrooms;elem!=NULL;elem=ms_list_next(elem)){ cr=(LinphoneChatRoom*)elem->data; - if (linphone_chat_room_matches(cr,uri)){ + if (linphone_chat_room_matches(cr,addr)){ break; } cr=NULL; } - from=linphone_address_as_string(uri); + cleanfrom=linphone_address_as_string(addr); if (cr==NULL){ /* create a new chat room */ - cr=linphone_core_create_chat_room(lc,from); + cr=linphone_core_create_chat_room(lc,cleanfrom); } - linphone_address_destroy(uri); - linphone_chat_room_text_received(cr,lc,from,msg); - ms_free(from); + linphone_address_destroy(addr); + linphone_chat_room_text_received(cr,lc,cleanfrom,msg); + ms_free(cleanfrom); } diff --git a/coreapi/friend.c b/coreapi/friend.c index 08f072de3..5dd51bec5 100644 --- a/coreapi/friend.c +++ b/coreapi/friend.c @@ -31,9 +31,6 @@ const char *linphone_online_status_to_string(LinphoneOnlineStatus ss){ const char *str=NULL; switch(ss){ - case LINPHONE_STATUS_UNKNOWN: - str=_("Unknown"); - break; case LINPHONE_STATUS_ONLINE: str=_("Online"); break; @@ -67,9 +64,6 @@ const char *linphone_online_status_to_string(LinphoneOnlineStatus ss){ case LINPHONE_STATUS_PENDING: str=_("Pending"); break; - case LINPHONE_STATUS_CLOSED: - str=_("Closed"); - break; default: str=_("Unknown-bug"); } @@ -114,20 +108,20 @@ MSList *linphone_find_friend(MSList *fl, const LinphoneAddress *friend, Linphone return res; } -LinphoneFriend *linphone_find_friend_by_nid(MSList *l, int nid){ +LinphoneFriend *linphone_find_friend_by_inc_subscribe(MSList *l, SalOp *op){ MSList *elem; for (elem=l;elem!=NULL;elem=elem->next){ LinphoneFriend *lf=(LinphoneFriend*)elem->data; - if (lf->nid==nid) return lf; + if (lf->insub==op) return lf; } return NULL; } -LinphoneFriend *linphone_find_friend_by_sid(MSList *l, int sid){ +LinphoneFriend *linphone_find_friend_by_out_subscribe(MSList *l, SalOp *op){ MSList *elem; for (elem=l;elem!=NULL;elem=elem->next){ LinphoneFriend *lf=(LinphoneFriend*)elem->data; - if (lf->sid==sid) return lf; + if (lf->outsub==op) return lf; } return NULL; } @@ -136,30 +130,30 @@ void __linphone_friend_do_subscribe(LinphoneFriend *fr){ char *friend=NULL; const char *route=NULL; const char *from=NULL; - osip_message_t *msg=NULL; + LinphoneProxyConfig *cfg; + friend=linphone_address_as_string(fr->uri); - if (fr->proxy!=NULL){ - route=fr->proxy->reg_route; - from=fr->proxy->reg_identity; + cfg=linphone_core_lookup_known_proxy(fr->lc,linphone_friend_get_address(fr)); + if (cfg!=NULL){ + route=linphone_proxy_config_get_route(cfg); + from=linphone_proxy_config_get_identity(cfg); }else from=linphone_core_get_primary_contact(fr->lc); - if (fr->sid<0){ + if (fr->outsub==NULL){ /* people for which we don't have yet an answer should appear as offline */ - fr->lc->vtable.notify_recv(fr->lc,(LinphoneFriend*)fr,friend,_("Gone"),"sip-closed.png"); + if (fr->lc->vtable.notify_recv) + fr->lc->vtable.notify_recv(fr->lc,(LinphoneFriend*)fr,friend,_("Gone"),"sip-closed.png"); + }else{ + sal_op_release(fr->outsub); + fr->outsub=NULL; } - eXosip_lock(); - eXosip_subscribe_build_initial_request(&msg,friend,from,route,"presence",600); - eXosip_subscribe_send_initial_request(msg); - eXosip_unlock(); + fr->outsub=sal_op_new(fr->lc->sal); + sal_op_set_route(fr->outsub,route); + sal_subscribe_presence(fr->outsub,from,friend); ms_free(friend); } - LinphoneFriend * linphone_friend_new(){ LinphoneFriend *obj=ms_new0(LinphoneFriend,1); - obj->out_did=-1; - obj->in_did=-1; - obj->nid=-1; - obj->sid=-1; obj->pol=LinphoneSPAccept; obj->status=LINPHONE_STATUS_OFFLINE; obj->subscribe=TRUE; @@ -214,6 +208,7 @@ int linphone_friend_set_sip_addr(LinphoneFriend *lf, const char *addr){ ms_warning("Invalid friend sip uri: %s",addr); return -1; } + linphone_address_clean(fr); if (lf->uri!=NULL) linphone_address_destroy(lf->uri); lf->uri=fr; return 0; @@ -240,335 +235,79 @@ int linphone_friend_set_inc_subscribe_policy(LinphoneFriend *fr, LinphoneSubscri return 0; } -int linphone_friend_set_proxy(LinphoneFriend *fr, struct _LinphoneProxyConfig *cfg){ - fr->proxy=cfg; - return 0; +SalPresenceStatus linphone_online_status_to_sal(LinphoneOnlineStatus os){ + switch(os){ + case LINPHONE_STATUS_OFFLINE: + return SalPresenceOffline; + break; + case LINPHONE_STATUS_ONLINE: + return SalPresenceOnline; + break; + case LINPHONE_STATUS_BUSY: + return SalPresenceBusy; + break; + case LINPHONE_STATUS_BERIGHTBACK: + return SalPresenceBerightback; + break; + case LINPHONE_STATUS_AWAY: + return SalPresenceAway; + break; + case LINPHONE_STATUS_ONTHEPHONE: + return SalPresenceOnthephone; + break; + case LINPHONE_STATUS_OUTTOLUNCH: + return SalPresenceOuttolunch; + break; + case LINPHONE_STATUS_NOT_DISTURB: + return SalPresenceDonotdisturb; + break; + case LINPHONE_STATUS_MOVED: + return SalPresenceMoved; + break; + case LINPHONE_STATUS_ALT_SERVICE: + return SalPresenceAltService; + break; + case LINPHONE_STATUS_PENDING: + return SalPresenceOffline; + break; + default: + return SalPresenceOffline; + break; + } + return SalPresenceOffline; } -void linphone_friend_set_sid(LinphoneFriend *lf, int sid){ - lf->sid=sid; -} -void linphone_friend_set_nid(LinphoneFriend *lf, int nid){ - lf->nid=nid; - lf->inc_subscribe_pending=TRUE; -} - -void add_presence_body(osip_message_t *notify, LinphoneOnlineStatus online_status) -{ - char buf[1000]; -#ifdef SUPPORT_MSN - int atom_id = 1000; -#endif - char *contact_info; - - osip_contact_t *ct=NULL; - osip_message_get_contact(notify,0,&ct); - osip_contact_to_str(ct,&contact_info); - -#ifdef SUPPORT_MSN - - if (online_status==LINPHONE_STATUS_ONLINE) - { - sprintf(buf, "\n\ -\n\ -\n\ -\n\ -\n\ -
\n\ -\n\ -\n\ -
\n\ -
\n\ -
", contact_info, atom_id, contact_info); - - } - else if (online_status==LINPHONE_STATUS_BUSY) - { - sprintf(buf, "\n\ -\n\ -\n\ -\n\ -\n\ -
\n\ -\n\ -\n\ -
\n\ -
\n\ -
", contact_info, atom_id, contact_info); - - } - else if (online_status==LINPHONE_STATUS_BERIGHTBACK) - { - sprintf(buf, "\n\ -\n\ -\n\ -\n\ -\n\ -
\n\ -\n\ -\n\ -
\n\ -
\n\ -
", contact_info, atom_id, contact_info); - - } - else if (online_status==LINPHONE_STATUS_AWAY) - { - sprintf(buf, "\n\ -\n\ -\n\ -\n\ -\n\ -
\n\ -\n\ -\n\ -
\n\ -
\n\ -
", contact_info, atom_id, contact_info); - - } - else if (online_status==LINPHONE_STATUS_ONTHEPHONE) - { - sprintf(buf, "\n\ -\n\ -\n\ -\n\ -\n\ -
\n\ -\n\ -\n\ -
\n\ -
\n\ -
", contact_info, atom_id, contact_info); - - } - else if (online_status==LINPHONE_STATUS_OUTTOLUNCH) - { - sprintf(buf, "\n\ -\n\ -\n\ -\n\ -\n\ -
\n\ -\n\ -\n\ -
\n\ -
\n\ -
", contact_info, atom_id, contact_info); - - } - else - { - sprintf(buf, "\n\ -\n\ -\n\ -\n\ -\n\ -
\n\ -\n\ -\n\ -
\n\ -
\n\ -
", contact_info, atom_id, contact_info); - } - - osip_message_set_body(notify, buf, strlen(buf)); - osip_message_set_content_type(notify, "application/xpidf+xml"); -#else - - if (online_status==LINPHONE_STATUS_ONLINE) - { - sprintf(buf, "\n\ -\n\ -\n\ -\n\ -open\n\ -\n\ -%s\n\ -online\n\ -\n\ -", - contact_info, contact_info); - } - else if (online_status==LINPHONE_STATUS_BUSY) - { - sprintf(buf, "\n\ -\n\ -\n\ -\n\ -open\n\ -\n\ - busy\n\ -\n\ -\n\ -%s\n\ -busy\n\ -\n\ -", - contact_info, contact_info); - } - else if (online_status==LINPHONE_STATUS_BERIGHTBACK) - { - sprintf(buf, "\n\ -\n\ -\n\ -\n\ -open\n\ -\n\ - in-transit\n\ -\n\ -\n\ -%s\n\ -be right back\n\ -\n\ -", - contact_info, contact_info); - } - else if (online_status==LINPHONE_STATUS_AWAY) - { - sprintf(buf, "\n\ -\n\ -\n\ -\n\ -open\n\ -\n\ - away\n\ -\n\ -\n\ -%s\n\ -away\n\ -\n\ -", - contact_info, contact_info); - } - else if (online_status==LINPHONE_STATUS_ONTHEPHONE) - { - sprintf(buf, "\n\ -\n\ -\n\ -\n\ -open\n\ -\n\ - on-the-phone\n\ -\n\ -\n\ -%s\n\ -on the phone\n\ -\n\ -", - contact_info, contact_info); - } - else if (online_status==LINPHONE_STATUS_OUTTOLUNCH) - { - sprintf(buf, "\n\ -\n\ -\n\ -\n\ -open\n\ -\n\ - meal\n\ -\n\ -\n\ -%s\n\ -out to lunch\n\ -\n\ -", - contact_info, contact_info); - } - else - { - /* */ - sprintf(buf, "\n\ -\n%s", - contact_info, -"\n\ -\n\ -closed\n\ -\n\ - permanent-absence\n\ -\n\ -\n\ -\n\ -\n\n"); - } - osip_message_set_body(notify, buf, strlen(buf)); - osip_message_set_content_type(notify, "application/pidf+xml"); - -#endif - osip_free(contact_info); -} - - -void linphone_friend_notify(LinphoneFriend *lf, int ss, LinphoneOnlineStatus os){ +void linphone_friend_notify(LinphoneFriend *lf, LinphoneOnlineStatus os){ //printf("Wish to notify %p, lf->nid=%i\n",lf,lf->nid); - if (lf->in_did!=-1){ - osip_message_t *msg=NULL; - const char *identity; - if (lf->proxy!=NULL) identity=lf->proxy->reg_identity; - else identity=linphone_core_get_primary_contact(lf->lc); - eXosip_lock(); - eXosip_insubscription_build_notify(lf->in_did,ss,0,&msg); - if (msg!=NULL){ - osip_message_set_contact(msg,identity); - add_presence_body(msg,os); - eXosip_insubscription_send_request(lf->in_did,msg); - }else ms_error("could not create notify for incoming subscription."); - eXosip_unlock(); + if (lf->insub!=NULL){ + sal_notify_presence(lf->insub,linphone_online_status_to_sal(os),NULL); } } static void linphone_friend_unsubscribe(LinphoneFriend *lf){ - if (lf->out_did!=-1) { - osip_message_t *msg=NULL; - eXosip_lock(); - eXosip_subscribe_build_refresh_request(lf->out_did,&msg); - if (msg){ - osip_message_set_expires(msg,"0"); - eXosip_subscribe_send_refresh_request(lf->out_did,msg); - }else ms_error("Could not build subscribe refresh request !"); - eXosip_unlock(); + if (lf->outsub!=NULL) { + sal_unsubscribe(lf->outsub); + sal_op_release(lf->outsub); + lf->outsub=NULL; } } void linphone_friend_destroy(LinphoneFriend *lf){ - linphone_friend_notify(lf,EXOSIP_SUBCRSTATE_TERMINATED,LINPHONE_STATUS_CLOSED); + linphone_friend_notify(lf,LINPHONE_STATUS_OFFLINE); linphone_friend_unsubscribe(lf); + if (lf->insub){ + sal_notify_close(lf->insub); + sal_op_release(lf->insub); + } if (lf->uri!=NULL) linphone_address_destroy(lf->uri); if (lf->info!=NULL) buddy_info_free(lf->info); ms_free(lf); } -void linphone_friend_check_for_removed_proxy(LinphoneFriend *lf, LinphoneProxyConfig *cfg){ - if (lf->proxy==cfg){ - lf->proxy=NULL; - } -} - const LinphoneAddress *linphone_friend_get_uri(const LinphoneFriend *lf){ return lf->uri; } - bool_t linphone_friend_get_send_subscribe(const LinphoneFriend *lf){ return lf->subscribe; } @@ -597,21 +336,21 @@ void linphone_friend_apply(LinphoneFriend *fr, LinphoneCore *lc){ if (fr->inc_subscribe_pending){ switch(fr->pol){ case LinphoneSPWait: - linphone_friend_notify(fr,EXOSIP_SUBCRSTATE_PENDING,LINPHONE_STATUS_PENDING); + linphone_friend_notify(fr,LINPHONE_STATUS_PENDING); break; case LinphoneSPAccept: if (fr->lc!=NULL) { - linphone_friend_notify(fr,EXOSIP_SUBCRSTATE_ACTIVE,fr->lc->presence_mode); + linphone_friend_notify(fr,fr->lc->presence_mode); } break; case LinphoneSPDeny: - linphone_friend_notify(fr,EXOSIP_SUBCRSTATE_TERMINATED,LINPHONE_STATUS_CLOSED); + linphone_friend_notify(fr,LINPHONE_STATUS_OFFLINE); break; } fr->inc_subscribe_pending=FALSE; } - if (fr->subscribe && fr->out_did==-1){ + if (fr->subscribe && fr->outsub==NULL){ __linphone_friend_do_subscribe(fr); } @@ -632,6 +371,14 @@ void linphone_core_add_friend(LinphoneCore *lc, LinphoneFriend *lf) { ms_return_if_fail(lf->lc==NULL); ms_return_if_fail(lf->uri!=NULL); + if (ms_list_find(lc->friends,lf)!=NULL){ + char *tmp=NULL; + const LinphoneAddress *addr=linphone_friend_get_address(lf); + if (addr) tmp=linphone_address_as_string(addr); + ms_warning("Friend %s already in list, ignored.", tmp ? tmp : "unknown"); + if (tmp) ms_free(tmp); + return ; + } lc->friends=ms_list_append(lc->friends,lf); linphone_friend_apply(lf,lc); return ; @@ -667,7 +414,7 @@ static bool_t username_match(const char *u1, const char *u2){ return FALSE; } -LinphoneFriend *linphone_core_get_friend_by_uri(const LinphoneCore *lc, const char *uri){ +LinphoneFriend *linphone_core_get_friend_by_address(const LinphoneCore *lc, const char *uri){ LinphoneAddress *puri=linphone_address_new(uri); const MSList *elem; const char *username=linphone_address_get_username(puri); @@ -752,10 +499,6 @@ LinphoneFriend * linphone_friend_new_from_config_file(LinphoneCore *lc, int inde a=lp_config_get_int(config,item,"subscribe",0); linphone_friend_send_subscribe(lf,a); - a=lp_config_get_int(config,item,"proxy",-1); - if (a!=-1) { - linphone_friend_set_proxy(lf,__index_to_proxy(lc,a)); - } linphone_friend_set_ref_key(lf,lp_config_get_string(config,item,"refkey",NULL)); return lf; } @@ -779,7 +522,6 @@ const char *__policy_enum_to_str(LinphoneSubscribePolicy pol){ void linphone_friend_write_to_config_file(LpConfig *config, LinphoneFriend *lf, int index){ char key[50]; char *tmp; - int a; const char *refkey; sprintf(key,"friend_%i",index); @@ -798,10 +540,6 @@ void linphone_friend_write_to_config_file(LpConfig *config, LinphoneFriend *lf, } lp_config_set_string(config,key,"pol",__policy_enum_to_str(lf->pol)); lp_config_set_int(config,key,"subscribe",lf->subscribe); - if (lf->proxy!=NULL){ - a=ms_list_index(lf->lc->sip_conf.proxies,lf->proxy); - lp_config_set_int(config,key,"proxy",a); - }else lp_config_set_int(config,key,"proxy",-1); refkey=linphone_friend_get_ref_key(lf); if (refkey){ diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 98f6d811f..cf16e8da3 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -650,28 +650,72 @@ static void rtp_config_read(LinphoneCore *lc) linphone_core_set_nortp_timeout(lc,nortp_timeout); } +static PayloadType * find_payload(RtpProfile *prof, const char *mime_type, int clock_rate, const char *recv_fmtp){ + PayloadType *candidate=NULL; + int i; + PayloadType *it; + for(i=0;i<127;++i){ + 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) || + (recv_fmtp==NULL && it->recv_fmtp==NULL) ){ + /*exact match*/ + return it; + }else candidate=it; + } + } + return candidate; +} -static PayloadType * get_codec(LpConfig *config, char* type,int index){ +static bool_t get_codec(LpConfig *config, char* type, int index, PayloadType **ret){ char codeckey[50]; const char *mime,*fmtp; int rate,enabled; PayloadType *pt; + *ret=NULL; snprintf(codeckey,50,"%s_%i",type,index); mime=lp_config_get_string(config,codeckey,"mime",NULL); - if (mime==NULL || strlen(mime)==0 ) return NULL; - - pt=payload_type_new(); - pt->mime_type=ms_strdup(mime); + if (mime==NULL || strlen(mime)==0 ) return FALSE; rate=lp_config_get_int(config,codeckey,"rate",8000); - pt->clock_rate=rate; fmtp=lp_config_get_string(config,codeckey,"recv_fmtp",NULL); - if (fmtp) pt->recv_fmtp=ms_strdup(fmtp); enabled=lp_config_get_int(config,codeckey,"enabled",1); - if (enabled ) pt->flags|=PAYLOAD_TYPE_ENABLED; + pt=find_payload(&av_profile,mime,rate,fmtp); + if (pt && enabled ) pt->flags|=PAYLOAD_TYPE_ENABLED; //ms_message("Found codec %s/%i",pt->mime_type,pt->clock_rate); - return pt; + if (pt==NULL) ms_warning("Ignoring codec config %s/%i with fmtp=%s because unsupported", + mime,rate,fmtp ? fmtp : ""); + *ret=pt; + return TRUE; +} + +static MSList *add_missing_codecs(SalStreamType mtype, MSList *l){ + int i; + for(i=0;i<127;++i){ + PayloadType *pt=rtp_profile_get_payload(&av_profile,i); + if (pt){ + if (mtype==SalVideo && pt->type!=PAYLOAD_VIDEO) + pt=NULL; + else if (mtype==SalAudio && (pt->type!=PAYLOAD_AUDIO_PACKETIZED + && pt->type!=PAYLOAD_AUDIO_CONTINUOUS)){ + pt=NULL; + } + if (pt && ms_filter_codec_supported(pt->mime_type)){ + if (ms_list_find(l,pt)==NULL){ + ms_message("Adding new codec %s/%i with fmtp %s", + pt->mime_type,pt->clock_rate,pt->recv_fmtp ? pt->recv_fmtp : ""); + if (strcasecmp(pt->mime_type,"speex")==0 || + strcasecmp(pt->mime_type,"MP4V-ES")==0 || + strcasecmp(pt->mime_type,"H264")==0) + l=ms_list_prepend(l,pt); + else l=ms_list_append(l,pt); + } + } + } + } + return l; } static void codecs_config_read(LinphoneCore *lc) @@ -680,23 +724,28 @@ static void codecs_config_read(LinphoneCore *lc) PayloadType *pt; MSList *audio_codecs=NULL; MSList *video_codecs=NULL; - for (i=0;;i++){ - pt=get_codec(lc->config,"audio_codec",i); - if (pt==NULL) break; - audio_codecs=ms_list_append(audio_codecs,(void *)pt); + for (i=0;get_codec(lc->config,"audio_codec",i,&pt);i++){ + if (pt){ + if (!ms_filter_codec_supported(pt->mime_type)){ + ms_warning("Codec %s is not supported by mediastreamer2, removed.",pt->mime_type); + }else audio_codecs=ms_list_append(audio_codecs,pt); + } } - for (i=0;;i++){ - pt=get_codec(lc->config,"video_codec",i); - if (pt==NULL) break; - video_codecs=ms_list_append(video_codecs,(void *)pt); + audio_codecs=add_missing_codecs(SalAudio,audio_codecs); + for (i=0;get_codec(lc->config,"video_codec",i,&pt);i++){ + if (pt){ + if (!ms_filter_codec_supported(pt->mime_type)){ + ms_warning("Codec %s is not supported by mediastreamer2, removed.",pt->mime_type); + }else video_codecs=ms_list_append(video_codecs,(void *)pt); + } } + video_codecs=add_missing_codecs(SalVideo,video_codecs); linphone_core_set_audio_codecs(lc,audio_codecs); linphone_core_set_video_codecs(lc,video_codecs); - linphone_core_setup_local_rtp_profile(lc); + linphone_core_update_allocated_audio_bandwidth(lc); } -static void video_config_read(LinphoneCore *lc) -{ +static void video_config_read(LinphoneCore *lc){ int capture, display, self_view; int enabled; const char *str; @@ -868,6 +917,9 @@ static void linphone_core_init (LinphoneCore * lc, const LinphoneCoreVTable *vta gstate_new_state(lc, GSTATE_POWER_STARTUP, NULL); ortp_init(); + linphone_core_assign_payload_type(&payload_type_pcmu8000,0,NULL); + linphone_core_assign_payload_type(&payload_type_gsm,3,NULL); + linphone_core_assign_payload_type(&payload_type_pcma8000,8,NULL); linphone_core_assign_payload_type(&payload_type_lpc1015,115,NULL); linphone_core_assign_payload_type(&payload_type_speex_nb,110,"vbr=on"); linphone_core_assign_payload_type(&payload_type_speex_wb,111,"vbr=on"); @@ -1383,7 +1435,7 @@ static void proxy_update(LinphoneCore *lc, time_t curtime){ } static void assign_buddy_info(LinphoneCore *lc, BuddyInfo *info){ - LinphoneFriend *lf=linphone_core_get_friend_by_uri(lc,info->sip_uri); + LinphoneFriend *lf=linphone_core_get_friend_by_address(lc,info->sip_uri); if (lf!=NULL){ lf->info=info; ms_message("%s has a BuddyInfo assigned with image %p",info->sip_uri, info->image_data); @@ -1647,7 +1699,7 @@ LinphoneProxyConfig * linphone_core_lookup_known_proxy(LinphoneCore *lc, const L static char *get_fixed_contact(LinphoneCore *lc, const char *localip, LinphoneProxyConfig *dest_proxy){ LinphoneAddress *ctt; - if (dest_proxy){ + 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); @@ -3178,10 +3230,6 @@ void codecs_config_uninit(LinphoneCore *lc) lp_config_set_string(lc->config,key,"recv_fmtp",pt->recv_fmtp); index++; } - if (lc->local_profile){ - rtp_profile_destroy(lc->local_profile); - lc->local_profile=NULL; - } } void ui_config_uninit(LinphoneCore* lc) diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index e277fc0df..2c2f5c582 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -139,7 +139,7 @@ typedef enum{ }LinphoneSubscribePolicy; typedef enum _LinphoneOnlineStatus{ - LINPHONE_STATUS_UNKNOWN, + LINPHONE_STATUS_OFFLINE, LINPHONE_STATUS_ONLINE, LINPHONE_STATUS_BUSY, LINPHONE_STATUS_BERIGHTBACK, @@ -149,9 +149,7 @@ typedef enum _LinphoneOnlineStatus{ LINPHONE_STATUS_NOT_DISTURB, LINPHONE_STATUS_MOVED, LINPHONE_STATUS_ALT_SERVICE, - LINPHONE_STATUS_OFFLINE, LINPHONE_STATUS_PENDING, - LINPHONE_STATUS_CLOSED, LINPHONE_STATUS_END }LinphoneOnlineStatus; @@ -167,11 +165,10 @@ int linphone_friend_set_sip_addr(LinphoneFriend *fr, const char *uri); int linphone_friend_set_name(LinphoneFriend *fr, const char *name); int linphone_friend_send_subscribe(LinphoneFriend *fr, bool_t val); int linphone_friend_set_inc_subscribe_policy(LinphoneFriend *fr, LinphoneSubscribePolicy pol); -int linphone_friend_set_proxy(LinphoneFriend *fr, struct _LinphoneProxyConfig *cfg); void linphone_friend_edit(LinphoneFriend *fr); void linphone_friend_done(LinphoneFriend *fr); void linphone_friend_destroy(LinphoneFriend *lf); -const LinphoneAddress *linphone_friend_get_uri(const LinphoneFriend *lf); +const LinphoneAddress *linphone_friend_get_address(const LinphoneFriend *lf); bool_t linphone_friend_get_send_subscribe(const LinphoneFriend *lf); LinphoneSubscribePolicy linphone_friend_get_inc_subscribe_policy(const LinphoneFriend *lf); LinphoneOnlineStatus linphone_friend_get_status(const LinphoneFriend *lf); @@ -208,8 +205,8 @@ typedef struct _LinphoneProxyConfig LinphoneProxyConfig; LinphoneProxyConfig *linphone_proxy_config_new(void); int linphone_proxy_config_set_server_addr(LinphoneProxyConfig *obj, const char *server_addr); -void linphone_proxy_config_set_identity(LinphoneProxyConfig *obj, const char *identity); -void linphone_proxy_config_set_route(LinphoneProxyConfig *obj, const char *route); +int linphone_proxy_config_set_identity(LinphoneProxyConfig *obj, const char *identity); +int linphone_proxy_config_set_route(LinphoneProxyConfig *obj, const char *route); void linphone_proxy_config_expires(LinphoneProxyConfig *obj, int expires); void linphone_proxy_config_enable_register(LinphoneProxyConfig *obj, bool_t val); #define linphone_proxy_config_enableregister linphone_proxy_config_enable_register @@ -638,7 +635,7 @@ void linphone_core_reject_subscriber(LinphoneCore *lc, LinphoneFriend *lf); const MSList * linphone_core_get_friend_list(const LinphoneCore *lc); /* notify all friends that have subscribed */ void linphone_core_notify_all_friends(LinphoneCore *lc, LinphoneOnlineStatus os); -LinphoneFriend *linphone_core_get_friend_by_uri(const LinphoneCore *lc, const char *uri); +LinphoneFriend *linphone_core_get_friend_by_address(const LinphoneCore *lc, const char *addr); LinphoneFriend *linphone_core_get_friend_by_ref_key(const LinphoneCore *lc, const char *key); /* returns a list of LinphoneCallLog */ diff --git a/coreapi/misc.c b/coreapi/misc.c index 9bdb90420..f0cf871fd 100644 --- a/coreapi/misc.c +++ b/coreapi/misc.c @@ -295,152 +295,6 @@ bool_t linphone_core_check_payload_type_usability(LinphoneCore *lc, PayloadType return ret; } -static PayloadType * find_payload(RtpProfile *prof, PayloadType *pt /*from config*/){ - PayloadType *candidate=NULL; - int i; - PayloadType *it; - for(i=0;i<127;++i){ - it=rtp_profile_get_payload(prof,i); - if (it!=NULL && strcasecmp(pt->mime_type,it->mime_type)==0 - && (pt->clock_rate==it->clock_rate || pt->clock_rate<=0) - && payload_type_get_user_data(it)==NULL ){ - if ( (pt->recv_fmtp && it->recv_fmtp && strcasecmp(pt->recv_fmtp,it->recv_fmtp)==0) || - (pt->recv_fmtp==NULL && it->recv_fmtp==NULL) ){ - /*exact match*/ - return it; - }else candidate=it; - } - } - return candidate; -} - -static bool_t check_h264_packmode(PayloadType *payload, MSFilterDesc *desc){ - if (payload->recv_fmtp==NULL || strstr(payload->recv_fmtp,"packetization-mode")==0){ - /*this is packetization-mode=0 H264, we only support it with a multislicing - enabled version of x264*/ - if (strstr(desc->text,"x264") && strstr(desc->text,"multislicing")==0){ - /*this is x264 without multisclicing*/ - ms_message("Disabling packetization-mode=0 H264 codec because " - "of lack of multislicing support"); - return FALSE; - } - } - return TRUE; -} - -static MSList *fix_codec_list(RtpProfile *prof, MSList *conflist) -{ - MSList *elem; - MSList *newlist=NULL; - PayloadType *payload,*confpayload; - - for (elem=conflist;elem!=NULL;elem=ms_list_next(elem)) - { - confpayload=(PayloadType*)elem->data; - payload=find_payload(prof,confpayload); - if (payload!=NULL){ - if (ms_filter_codec_supported(confpayload->mime_type)){ - MSFilterDesc *desc=ms_filter_get_encoder(confpayload->mime_type); - if (strcasecmp(confpayload->mime_type,"H264")==0){ - if (!check_h264_packmode(confpayload,desc)){ - continue; - } - } - payload_type_set_user_data(payload,(void*)desc->text); - payload_type_set_enable(payload,payload_type_enabled(confpayload)); - newlist=ms_list_append(newlist,payload); - } - } - else{ - ms_warning("Cannot support %s/%i: does not exist.",confpayload->mime_type, - confpayload->clock_rate); - } - } - return newlist; -} - - -void linphone_core_setup_local_rtp_profile(LinphoneCore *lc) -{ - int i; - MSList *audiopt,*videopt; - PayloadType *payload; - bool_t prepend; - lc->local_profile=rtp_profile_clone_full(&av_profile); - /* first look at the list given by configuration file to see if - it is correct */ - audiopt=fix_codec_list(lc->local_profile,lc->codecs_conf.audio_codecs); - videopt=fix_codec_list(lc->local_profile,lc->codecs_conf.video_codecs); - /* now find and add payloads that are not listed in the configuration - codec list */ - for (i=0;i<127;i++) - { - payload=rtp_profile_get_payload(lc->local_profile,i); - if (payload!=NULL){ - if (payload_type_get_user_data(payload)!=NULL) continue; - /* find a mediastreamer codec for this payload type */ - if (ms_filter_codec_supported(payload->mime_type)){ - MSFilterDesc *desc=ms_filter_get_encoder(payload->mime_type); - ms_message("Adding new codec %s/%i",payload->mime_type,payload->clock_rate); - payload_type_set_enable(payload,1); - payload_type_set_user_data(payload,(void *)desc->text); - prepend=FALSE; - /* by default, put speex, mpeg4, or h264 on top of list*/ - if (strcmp(payload->mime_type,"speex")==0) - prepend=TRUE; - else if (strcmp(payload->mime_type,"MP4V-ES")==0) - prepend=TRUE; - else if (strcasecmp(payload->mime_type,"H264")==0){ - if (check_h264_packmode(payload,desc)) - prepend=TRUE; - else continue; - } - switch (payload->type){ - case PAYLOAD_AUDIO_CONTINUOUS: - case PAYLOAD_AUDIO_PACKETIZED: - if (prepend) - audiopt=ms_list_prepend(audiopt,(void *)payload); - else - audiopt=ms_list_append(audiopt,(void *)payload); - break; - case PAYLOAD_VIDEO: - if (prepend) - videopt=ms_list_prepend(videopt,(void *)payload); - else - videopt=ms_list_append(videopt,(void *)payload); - break; - default: - ms_error("Unsupported rtp media type."); - } - } - } - } - ms_list_for_each(lc->codecs_conf.audio_codecs,(void (*)(void*))payload_type_destroy); - ms_list_for_each(lc->codecs_conf.video_codecs,(void (*)(void *))payload_type_destroy); - ms_list_free(lc->codecs_conf.audio_codecs); - ms_list_free(lc->codecs_conf.video_codecs); - /* set the fixed lists instead:*/ - lc->codecs_conf.audio_codecs=audiopt; - lc->codecs_conf.video_codecs=videopt; - linphone_core_update_allocated_audio_bandwidth(lc); -} - -int from_2char_without_params(osip_from_t *from,char **str) -{ - osip_from_t *tmpfrom=NULL; - osip_from_clone(from,&tmpfrom); - if (tmpfrom!=NULL){ - while(!osip_list_eol(&tmpfrom->gen_params,0)){ - osip_generic_param_t *param=(osip_generic_param_t*)osip_list_get(&tmpfrom->gen_params,0); - osip_generic_param_free(param); - osip_list_remove(&tmpfrom->gen_params,0); - } - }else return -1; - osip_from_to_str(tmpfrom,str); - osip_from_free(tmpfrom); - return 0; -} - bool_t lp_spawn_command_line_sync(const char *command, char **result,int *command_ret){ #if !defined(_WIN32_WCE) FILE *f=popen(command,"r"); @@ -619,6 +473,11 @@ void linphone_core_run_stun_tests(LinphoneCore *lc, LinphoneCall *call){ bool_t got_audio,got_video; bool_t cone_audio=FALSE,cone_video=FALSE; struct timeval init,cur; + SalEndpointCandidate *ac,*vc; + + ac=&call->localdesc->streams[0].candidates[0]; + vc=&call->localdesc->streams[1].candidates[0]; + if (parse_stun_server_addr(server,&ss,&ss_len)<0){ ms_error("Fail to parser stun server address: %s",server); return; @@ -651,20 +510,20 @@ void linphone_core_run_stun_tests(LinphoneCore *lc, LinphoneCall *call){ usleep(10000); #endif - if (recvStunResponse(sock1,call->audio_params.natd_addr, - &call->audio_params.natd_port,&id)>0){ + if (recvStunResponse(sock1,ac->addr, + &ac->port,&id)>0){ ms_message("STUN test result: local audio port maps to %s:%i", - call->audio_params.natd_addr, - call->audio_params.natd_port); + ac->addr, + ac->port); if (id==11) cone_audio=TRUE; got_audio=TRUE; } - if (recvStunResponse(sock2,call->video_params.natd_addr, - &call->video_params.natd_port,&id)>0){ + if (recvStunResponse(sock2,vc->addr, + &vc->port,&id)>0){ ms_message("STUN test result: local video port maps to %s:%i", - call->video_params.natd_addr, - call->video_params.natd_port); + vc->addr, + vc->port); if (id==22) cone_video=TRUE; got_video=TRUE; @@ -678,7 +537,8 @@ void linphone_core_run_stun_tests(LinphoneCore *lc, LinphoneCall *call){ }else{ if (!cone_audio) { ms_warning("NAT is symmetric for audio port"); - call->audio_params.natd_port=0; + ac->addr[0]='\0'; + ac->port=0; } } if (sock2>=0){ @@ -687,7 +547,8 @@ void linphone_core_run_stun_tests(LinphoneCore *lc, LinphoneCall *call){ }else{ if (!cone_video) { ms_warning("NAT is symmetric for video port."); - call->video_params.natd_port=0; + vc->addr[0]='\0'; + vc->port=0; } } } diff --git a/coreapi/presence.c b/coreapi/presence.c index fc8f46b74..ffff0f209 100644 --- a/coreapi/presence.c +++ b/coreapi/presence.c @@ -18,26 +18,23 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "linphonecore.h" -#include -#include #include "private.h" extern const char *__policy_enum_to_str(LinphoneSubscribePolicy pol); -void linphone_core_add_subscriber(LinphoneCore *lc, const char *subscriber, int did, int nid){ +void linphone_core_add_subscriber(LinphoneCore *lc, const char *subscriber, SalOp *op){ LinphoneFriend *fl=linphone_friend_new_with_addr(subscriber); if (fl==NULL) return ; - fl->in_did=did; - linphone_friend_set_nid(fl,nid); + fl->insub=op; linphone_friend_set_inc_subscribe_policy(fl,LinphoneSPAccept); fl->inc_subscribe_pending=TRUE; lc->subscribers=ms_list_append(lc->subscribers,(void *)fl); if (lc->vtable.new_unknown_subscriber!=NULL) { - char *subscriber=linphone_address_as_string(fl->uri); - lc->vtable.new_unknown_subscriber(lc,fl,subscriber); - ms_free(subscriber); + char *tmp=linphone_address_as_string(fl->uri); + lc->vtable.new_unknown_subscriber(lc,fl,tmp); + ms_free(tmp); } } @@ -45,167 +42,131 @@ void linphone_core_reject_subscriber(LinphoneCore *lc, LinphoneFriend *lf){ linphone_friend_set_inc_subscribe_policy(lf,LinphoneSPDeny); } -static void __do_notify(void * data, void * user_data){ - int *tab=(int*)user_data; - LinphoneFriend *lf=(LinphoneFriend*)data; - linphone_friend_notify(lf,tab[0],tab[1]); -} - -void __linphone_core_notify_all_friends(LinphoneCore *lc, int ss, int os){ - int tab[2]; - tab[0]=ss; - tab[1]=os; - ms_list_for_each2(lc->friends,__do_notify,(void *)tab); -} - void linphone_core_notify_all_friends(LinphoneCore *lc, LinphoneOnlineStatus os){ + MSList *elem; ms_message("Notifying all friends that we are in status %i",os); - __linphone_core_notify_all_friends(lc,EXOSIP_SUBCRSTATE_ACTIVE,os); + for(elem=lc->friends;elem!=NULL;elem=elem->next){ + LinphoneFriend *lf=(LinphoneFriend *)elem->data; + if (lf->insub){ + linphone_friend_notify(lf,os); + } + } } -/* check presence state before answering to call; returns TRUE if we can proceed, else answer the appropriate answer -to close the dialog*/ -bool_t linphone_core_check_presence(LinphoneCore *lc){ - return TRUE; -} - -void linphone_subscription_new(LinphoneCore *lc, eXosip_event_t *ev){ +void linphone_subscription_new(LinphoneCore *lc, SalOp *op, const char *from){ LinphoneFriend *lf=NULL; - osip_from_t *from=ev->request->from; char *tmp; - osip_message_t *msg=NULL; LinphoneAddress *uri; - osip_from_to_str(ev->request->from,&tmp); - uri=linphone_address_new(tmp); - ms_message("Receiving new subscription from %s.",tmp); + + uri=linphone_address_new(from); + linphone_address_clean(uri); + tmp=linphone_address_as_string(uri); + ms_message("Receiving new subscription from %s.",from); /* check if we answer to this subscription */ if (linphone_find_friend(lc->friends,uri,&lf)!=NULL){ - lf->in_did=ev->did; - linphone_friend_set_nid(lf,ev->nid); - eXosip_insubscription_build_answer(ev->tid,202,&msg); - eXosip_insubscription_send_answer(ev->tid,202,msg); - __eXosip_wakeup_event(); + lf->insub=op; + lf->inc_subscribe_pending=TRUE; + sal_subscribe_accept(op); linphone_friend_done(lf); /*this will do all necessary actions */ }else{ /* check if this subscriber is in our black list */ if (linphone_find_friend(lc->subscribers,uri,&lf)){ if (lf->pol==LinphoneSPDeny){ ms_message("Rejecting %s because we already rejected it once.",from); - eXosip_insubscription_send_answer(ev->tid,401,NULL); + sal_subscribe_decline(op); } else { /* else it is in wait for approval state, because otherwise it is in the friend list.*/ ms_message("New subscriber found in friend list, in %s state.",__policy_enum_to_str(lf->pol)); } }else { - eXosip_insubscription_build_answer(ev->tid,202,&msg); - eXosip_insubscription_send_answer(ev->tid,202,msg); - linphone_core_add_subscriber(lc,tmp,ev->did,ev->nid); + sal_subscribe_accept(op); + linphone_core_add_subscriber(lc,tmp,op); } } - osip_free(tmp); + ms_free(tmp); } -void linphone_notify_recv(LinphoneCore *lc, eXosip_event_t *ev) -{ +void linphone_notify_recv(LinphoneCore *lc, SalOp *op, SalSubscribeState ss, SalPresenceStatus sal_status){ const char *status=_("Gone"); const char *img="sip-closed.png"; char *tmp; LinphoneFriend *lf; LinphoneAddress *friend=NULL; - osip_from_t *from=NULL; - osip_body_t *body=NULL; - LinphoneOnlineStatus estatus=LINPHONE_STATUS_UNKNOWN; - ms_message("Receiving notify with sid=%i,nid=%i",ev->sid,ev->nid); - if (ev->request!=NULL){ - from=ev->request->from; - osip_message_get_body(ev->request,0,&body); - if (body==NULL){ - ms_error("No body in NOTIFY"); - return; - } - if (strstr(body->body,"pending")!=NULL){ - status=_("Waiting for Approval"); - img="sip-wfa.png"; - estatus=LINPHONE_STATUS_PENDING; - }else if ((strstr(body->body,"online")!=NULL) || (strstr(body->body,"open")!=NULL)) { - status=_("Online"); - img="sip-online.png"; - estatus=LINPHONE_STATUS_ONLINE; - }else if (strstr(body->body,"busy")!=NULL){ - status=_("Busy"); - img="sip-busy.png"; - estatus=LINPHONE_STATUS_BUSY; - }else if (strstr(body->body,"berightback")!=NULL - || strstr(body->body,"in-transit")!=NULL ){ - status=_("Be Right Back"); - img="sip-bifm.png"; - estatus=LINPHONE_STATUS_BERIGHTBACK; - }else if (strstr(body->body,"away")!=NULL){ - status=_("Away"); - img="sip-away.png"; - estatus=LINPHONE_STATUS_AWAY; - }else if (strstr(body->body,"onthephone")!=NULL - || strstr(body->body,"on-the-phone")!=NULL){ - status=_("On The Phone"); - img="sip-otp.png"; - estatus=LINPHONE_STATUS_ONTHEPHONE; - }else if (strstr(body->body,"outtolunch")!=NULL - || strstr(body->body,"meal")!=NULL){ - status=_("Out To Lunch"); - img="sip-otl.png"; - estatus=LINPHONE_STATUS_OUTTOLUNCH; - }else if (strstr(body->body,"closed")!=NULL){ - status=_("Closed"); - img="sip-away.png"; - estatus=LINPHONE_STATUS_CLOSED; - }else{ + LinphoneOnlineStatus estatus=LINPHONE_STATUS_OFFLINE; + + switch(sal_status){ + case SalPresenceOffline: status=_("Gone"); img="sip-closed.png"; estatus=LINPHONE_STATUS_OFFLINE; - } - ms_message("We are notified that sip:%s@%s has online status %s",from->url->username,from->url->host,status); + break; + case SalPresenceOnline: + status=_("Online"); + img="sip-online.png"; + estatus=LINPHONE_STATUS_ONLINE; + break; + case SalPresenceBusy: + status=_("Busy"); + img="sip-busy.png"; + estatus=LINPHONE_STATUS_BUSY; + break; + case SalPresenceBerightback: + status=_("Away"); + img="sip-away.png"; + estatus=LINPHONE_STATUS_AWAY; + break; + case SalPresenceAway: + status=_("Away"); + img="sip-away.png"; + estatus=LINPHONE_STATUS_AWAY; + break; + case SalPresenceOnthephone: + status=_("On The Phone"); + img="sip-otp.png"; + estatus=LINPHONE_STATUS_ONTHEPHONE; + break; + case SalPresenceOuttolunch: + status=_("Out To Lunch"); + img="sip-otl.png"; + estatus=LINPHONE_STATUS_OUTTOLUNCH; + break; + case SalPresenceDonotdisturb: + status=_("Busy"); + img="sip-busy.png"; + estatus=LINPHONE_STATUS_BUSY; + break; + case SalPresenceMoved: + case SalPresenceAltService: + status=_("Away"); + img="sip-away.png"; + estatus=LINPHONE_STATUS_AWAY; + break; } - lf=linphone_find_friend_by_sid(lc->friends,ev->sid); + lf=linphone_find_friend_by_out_subscribe(lc->friends,op); if (lf!=NULL){ friend=lf->uri; tmp=linphone_address_as_string(friend); lf->status=estatus; lc->vtable.notify_recv(lc,(LinphoneFriend*)lf,tmp,status,img); ms_free(tmp); - if (ev->ss_status==EXOSIP_SUBCRSTATE_TERMINATED) { - lf->sid=-1; - lf->out_did=-1; - ms_message("Outgoing subscription terminated by remote."); - } }else{ ms_message("But this person is not part of our friend list, so we don't care."); } + if (ss==SalSubscribeTerminated){ + sal_op_release(op); + if (lf) + lf->outsub=NULL; + } } -void linphone_subscription_answered(LinphoneCore *lc, eXosip_event_t *ev){ +void linphone_subscription_closed(LinphoneCore *lc, SalOp *op){ LinphoneFriend *lf; - osip_from_t *from=ev->response->to; - char *tmp; - osip_from_to_str(from,&tmp); - LinphoneAddress *uri=linphone_address_new(tmp); - linphone_find_friend(lc->friends,uri,&lf); + lf=linphone_find_friend_by_inc_subscribe(lc->friends,op); + sal_op_release(op); if (lf!=NULL){ - lf->out_did=ev->did; - linphone_friend_set_sid(lf,ev->sid); + lf->insub=NULL; }else{ - ms_warning("Receiving answer for unknown subscribe sip:%s@%s", from->url->username,from->url->host); - } - ms_free(tmp); -} -void linphone_subscription_closed(LinphoneCore *lc,eXosip_event_t *ev){ - LinphoneFriend *lf; - osip_from_t *from=ev->request->from; - lf=linphone_find_friend_by_nid(lc->friends,ev->nid); - if (lf!=NULL){ - lf->in_did=-1; - linphone_friend_set_nid(lf,-1); - }else{ - ms_warning("Receiving unsuscribe for unknown in-subscribtion from sip:%s@%s", from->url->username, from->url->host); + ms_warning("Receiving unsuscribe for unknown in-subscribtion from %s", sal_op_get_from(op)); } } diff --git a/coreapi/private.h b/coreapi/private.h index 667fdb7ac..abea80b82 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -99,7 +99,10 @@ int linphone_proxy_config_send_publish(LinphoneProxyConfig *cfg, LinphoneOnlineS int linphone_online_status_to_eXosip(LinphoneOnlineStatus os); -void linphone_friend_notify(LinphoneFriend *lf, int ss, LinphoneOnlineStatus os); +void linphone_friend_notify(LinphoneFriend *lf, LinphoneOnlineStatus os); +LinphoneFriend *linphone_find_friend_by_inc_subscribe(MSList *l, SalOp *op); +LinphoneFriend *linphone_find_friend_by_out_subscribe(MSList *l, SalOp *op); + int set_lock_file(); int get_lock_file(); @@ -107,7 +110,7 @@ int remove_lock_file(); int do_registration(LinphoneCore *lc, bool_t doit); void check_for_registration(LinphoneCore *lc); void check_sound_device(LinphoneCore *lc); -void linphone_core_setup_local_rtp_profile(LinphoneCore *lc); +void linphone_core_verify_codecs(LinphoneCore *lc); void linphone_core_get_local_ip(LinphoneCore *lc, const char *to, char *result); bool_t host_has_ipv6_network(); bool_t lp_spawn_command_line_sync(const char *command, char **result,int *command_ret); @@ -135,10 +138,11 @@ static inline void set_string(char **dest, const char *src){ #define PAYLOAD_TYPE_ENABLED PAYLOAD_TYPE_USER_FLAG_0 +SalPresenceStatus linphone_online_status_to_sal(LinphoneOnlineStatus os); void linphone_process_authentication(LinphoneCore* lc, SalOp *op); void linphone_authentication_ok(LinphoneCore *lc, SalOp *op); -void linphone_subscription_new(LinphoneCore *lc, SalOp *op); -void linphone_notify_recv(LinphoneCore *lc, SalOp *op); +void linphone_subscription_new(LinphoneCore *lc, SalOp *op, const char *from); +void linphone_notify_recv(LinphoneCore *lc, SalOp *op, SalSubscribeState ss, SalPresenceStatus status); void linphone_proxy_config_process_authentication_failure(LinphoneCore *lc, SalOp *op); void linphone_subscription_answered(LinphoneCore *lc, SalOp *op); @@ -164,7 +168,8 @@ void linphone_proxy_config_write_to_config_file(struct _LpConfig* config,Linphon int linphone_proxy_config_normalize_number(LinphoneProxyConfig *cfg, const char *username, char *result, size_t result_len); -/*internal use only */ +void linphone_core_text_received(LinphoneCore *lc, const char *from, const char *msg); + void linphone_core_start_media_streams(LinphoneCore *lc, struct _LinphoneCall *call); void linphone_core_stop_media_streams(LinphoneCore *lc, struct _LinphoneCall *call); const char * linphone_core_get_identity(LinphoneCore *lc); @@ -206,8 +211,8 @@ struct _LinphoneAuthInfo char *userid; char *passwd; char *ha1; + int usecount; bool_t works; - bool_t first_time; }; struct _LinphoneChatRoom{ @@ -224,7 +229,6 @@ struct _LinphoneFriend{ SalOp *outsub; LinphoneSubscribePolicy pol; LinphoneOnlineStatus status; - struct _LinphoneProxyConfig *proxy; struct _LinphoneCore *lc; BuddyInfo *info; char *refkey; @@ -356,7 +360,6 @@ struct _LinphoneCore struct _VideoStream *videostream; struct _VideoStream *previewstream; RtpTransport *a_rtp,*a_rtcp; - struct _RtpProfile *local_profile; MSList *bl_reqs; MSList *subscribers; /* unknown subscribers */ int minutes_away; diff --git a/coreapi/proxy.c b/coreapi/proxy.c index 437c85e60..69ebc7634 100644 --- a/coreapi/proxy.c +++ b/coreapi/proxy.c @@ -20,8 +20,6 @@ Copyright (C) 2000 Simon MORLAT (simon.morlat@linphone.org) #include "linphonecore.h" #include "sipsetup.h" -#include -#include #include "lpconfig.h" #include "private.h" @@ -40,7 +38,6 @@ void linphone_proxy_config_write_all_to_config_file(LinphoneCore *lc){ void linphone_proxy_config_init(LinphoneProxyConfig *obj){ memset(obj,0,sizeof(LinphoneProxyConfig)); - obj->rid=-1; obj->expires=3600; } @@ -72,8 +69,8 @@ void linphone_proxy_config_destroy(LinphoneProxyConfig *obj){ if (obj->ssctx!=NULL) sip_setup_context_free(obj->ssctx); if (obj->realm!=NULL) ms_free(obj->realm); if (obj->type!=NULL) ms_free(obj->type); - if (obj->contact_addr!=NULL) ms_free(obj->contact_addr); if (obj->dial_prefix!=NULL) ms_free(obj->dial_prefix); + if (obj->op) sal_op_release(obj->op); } /** @@ -83,79 +80,6 @@ bool_t linphone_proxy_config_is_registered(const LinphoneProxyConfig *obj){ return obj->registered; } -void linphone_proxy_config_get_contact(LinphoneProxyConfig *cfg, const char **ip, int *port){ - if (cfg->registered){ - *ip=cfg->contact_addr; - *port=cfg->contact_port; - }else{ - *ip=NULL; - *port=0; - } -} - -static void update_contact(LinphoneProxyConfig *cfg, const char *ip, const char *port){ - if (cfg->contact_addr){ - ms_free(cfg->contact_addr); - } - cfg->contact_addr=ms_strdup(ip); - if (port!=NULL) - cfg->contact_port=atoi(port); - else cfg->contact_port=5060; -} - -bool_t linphone_proxy_config_register_again_with_updated_contact(LinphoneProxyConfig *obj, osip_message_t *orig_request, osip_message_t *last_answer){ - osip_message_t *msg; - const char *rport,*received; - osip_via_t *via=NULL; - osip_generic_param_t *param=NULL; - osip_contact_t *ctt=NULL; - osip_message_get_via(last_answer,0,&via); - if (!via) return FALSE; - osip_via_param_get_byname(via,"rport",¶m); - if (param) rport=param->gvalue; - else return FALSE; - param=NULL; - osip_via_param_get_byname(via,"received",¶m); - if (param) received=param->gvalue; - else return FALSE; - osip_message_get_contact(orig_request,0,&ctt); - if (strcmp(ctt->url->host,received)==0){ - /*ip address matches, check ports*/ - const char *contact_port=ctt->url->port; - const char *via_rport=rport; - if (via_rport==NULL || strlen(via_rport)>0) - via_rport="5060"; - if (contact_port==NULL || strlen(contact_port)>0) - contact_port="5060"; - if (strcmp(contact_port,via_rport)==0){ - ms_message("Register has up to date contact, doing nothing."); - return FALSE; - }else ms_message("ports do not match, need to update the register (%s <> %s)", contact_port,via_rport); - } - eXosip_lock(); - msg=NULL; - eXosip_register_build_register(obj->rid,obj->expires,&msg); - if (msg==NULL){ - eXosip_unlock(); - ms_warning("Fail to create a contact updated register."); - return FALSE; - } - osip_message_get_contact(msg,0,&ctt); - if (ctt->url->host!=NULL){ - osip_free(ctt->url->host); - } - ctt->url->host=osip_strdup(received); - if (ctt->url->port!=NULL){ - osip_free(ctt->url->port); - } - ctt->url->port=osip_strdup(rport); - eXosip_register_send_register(obj->rid,msg); - eXosip_unlock(); - update_contact(obj,received,rport); - ms_message("Resending new register with updated contact %s:%s",received,rport); - return TRUE; -} - /** * Sets the proxy address * @@ -165,19 +89,18 @@ bool_t linphone_proxy_config_register_again_with_updated_contact(LinphoneProxyCo * - hostnames : sip:sip.example.net **/ int linphone_proxy_config_set_server_addr(LinphoneProxyConfig *obj, const char *server_addr){ - int err; - osip_from_t *url; + LinphoneAddress *addr; if (obj->reg_proxy!=NULL) ms_free(obj->reg_proxy); obj->reg_proxy=NULL; if (server_addr!=NULL && strlen(server_addr)>0){ - osip_from_init(&url); - err=osip_from_parse(url,server_addr); - if (err==0 && url->url->host!=NULL){ + addr=linphone_address_new(server_addr); + if (addr){ obj->reg_proxy=ms_strdup(server_addr); + linphone_address_destroy(addr); }else{ ms_warning("Could not parse %s",server_addr); + return -1; } - osip_from_free(url); } return 0; } @@ -191,30 +114,30 @@ int linphone_proxy_config_set_server_addr(LinphoneProxyConfig *obj, const char * * The REGISTER messages will have from and to set to this identity. * **/ -void linphone_proxy_config_set_identity(LinphoneProxyConfig *obj, const char *identity){ - int err=0; - osip_from_t *url=NULL; +int linphone_proxy_config_set_identity(LinphoneProxyConfig *obj, const char *identity){ + LinphoneAddress *addr; if (identity!=NULL && strlen(identity)>0){ - osip_from_init(&url); - err=osip_from_parse(url,identity); - if (err<0 || url->url->host==NULL || url->url->username==NULL){ - ms_warning("Could not parse %s",identity); - osip_from_free(url); - return; + addr=linphone_address_new(identity); + if (!addr || linphone_address_get_username(addr)==NULL){ + ms_warning("Invalid sip identity: %s",identity); + if (addr) + linphone_address_destroy(addr); + return -1; + }else{ + if (obj->reg_identity!=NULL) { + ms_free(obj->reg_identity); + obj->reg_identity=NULL; + } + obj->reg_identity=ms_strdup(identity); + if (obj->realm){ + ms_free(obj->realm); + } + obj->realm=ms_strdup(linphone_address_get_domain(addr)); + linphone_address_destroy(addr); + return 0; } - } else err=-2; - if (obj->reg_identity!=NULL) { - ms_free(obj->reg_identity); - obj->reg_identity=NULL; } - if (err==-2) obj->reg_identity=NULL; - else { - obj->reg_identity=ms_strdup(identity); - if (obj->realm) - ms_free(obj->realm); - obj->realm=ms_strdup(url->url->host); - } - if (url) osip_from_free(url); + return -1; } const char *linphone_proxy_config_get_domain(const LinphoneProxyConfig *cfg){ @@ -226,37 +149,14 @@ const char *linphone_proxy_config_get_domain(const LinphoneProxyConfig *cfg){ * When a route is set, all outgoing calls will go to the route's destination if this proxy * is the default one (see linphone_core_set_default_proxy() ). **/ -void linphone_proxy_config_set_route(LinphoneProxyConfig *obj, const char *route) +int linphone_proxy_config_set_route(LinphoneProxyConfig *obj, const char *route) { - int err; - osip_uri_param_t *lr_param=NULL; - osip_route_t *rt=NULL; - char *tmproute=NULL; - if (route!=NULL && strlen(route)>0){ - osip_route_init(&rt); - err=osip_route_parse(rt,route); - if (err<0){ - ms_warning("Could not parse %s",route); - osip_route_free(rt); - return ; - } - if (obj->reg_route!=NULL) { - ms_free(obj->reg_route); - obj->reg_route=NULL; - } - - /* check if the lr parameter is set , if not add it */ - osip_uri_uparam_get_byname(rt->url, "lr", &lr_param); - if (lr_param==NULL){ - osip_uri_uparam_add(rt->url,osip_strdup("lr"),NULL); - osip_route_to_str(rt,&tmproute); - obj->reg_route=ms_strdup(tmproute); - osip_free(tmproute); - }else obj->reg_route=ms_strdup(route); - }else{ - if (obj->reg_route!=NULL) ms_free(obj->reg_route); + if (obj->reg_route!=NULL){ + ms_free(obj->reg_route); obj->reg_route=NULL; } + obj->reg_route=ms_strdup(route); + return 0; } bool_t linphone_proxy_config_check(LinphoneCore *lc, LinphoneProxyConfig *obj){ @@ -304,15 +204,10 @@ void linphone_proxy_config_enable_publish(LinphoneProxyConfig *obj, bool_t val){ * linphone_proxy_config_done() to commit the changes. **/ void linphone_proxy_config_edit(LinphoneProxyConfig *obj){ - obj->auth_failures=0; if (obj->reg_sendregister){ /* unregister */ if (obj->registered) { - osip_message_t *msg; - eXosip_lock(); - eXosip_register_build_register(obj->rid,0,&msg); - eXosip_register_send_register(obj->rid,msg); - eXosip_unlock(); + sal_unregister(obj->op); obj->registered=FALSE; } } @@ -329,13 +224,10 @@ static void linphone_proxy_config_register(LinphoneProxyConfig *obj){ if (obj->reg_identity!=NULL) id_str=obj->reg_identity; else id_str=linphone_core_get_primary_contact(obj->lc); if (obj->reg_sendregister){ - char *ct=NULL; - osip_message_t *msg=NULL; - eXosip_lock(); - obj->rid=eXosip_register_build_initial_register(id_str,obj->reg_proxy,NULL,obj->expires,&msg); - eXosip_register_send_register(obj->rid,msg); - eXosip_unlock(); - if (ct!=NULL) osip_free(ct); + if (obj->op) + sal_op_release(obj->op); + obj->op=sal_op_new(obj->lc->sal); + sal_register(obj->op,obj->reg_proxy,obj->reg_identity,obj->expires); } } @@ -484,170 +376,13 @@ void linphone_proxy_config_set_realm(LinphoneProxyConfig *cfg, const char *realm } int linphone_proxy_config_send_publish(LinphoneProxyConfig *proxy, - LinphoneOnlineStatus presence_mode) -{ - osip_message_t *pub; - int i; - const char *from=NULL; - char buf[5000]; - - if (proxy->publish==FALSE) return 0; - - if (proxy!=NULL) { - from=linphone_proxy_config_get_identity(proxy); - } - if (from==NULL) from=linphone_core_get_primary_contact(proxy->lc); - - if (presence_mode==LINPHONE_STATUS_ONLINE) - { - snprintf(buf, 5000, "\n\ -\n\ -\n\ -\n\ -open\n\ -\n\ -%s\n\ -online\n\ -\n\ -", - from, from); - } - else if (presence_mode==LINPHONE_STATUS_BUSY - ||presence_mode==LINPHONE_STATUS_NOT_DISTURB) - { - snprintf(buf, 5000, "\n\ -\n\ -\n\ -\n\ -open\n\ -\n\ - busy\n\ -\n\ -\n\ -%s\n\ -busy\n\ -\n\ -", - from, from); - } - else if (presence_mode==LINPHONE_STATUS_BERIGHTBACK) - { - snprintf(buf, 5000, "\n\ -\n\ -\n\ -\n\ -open\n\ -\n\ - in-transit\n\ -\n\ -\n\ -%s\n\ -be right back\n\ -\n\ -", - from,from); - } - else if (presence_mode==LINPHONE_STATUS_AWAY - ||presence_mode==LINPHONE_STATUS_MOVED - ||presence_mode==LINPHONE_STATUS_ALT_SERVICE) - { - snprintf(buf, 5000, "\n\ -\n\ -\n\ -\n\ -open\n\ -\n\ - away\n\ -\n\ -\n\ -%s\n\ -away\n\ -\n\ -", - from, from); - } - else if (presence_mode==LINPHONE_STATUS_ONTHEPHONE) - { - snprintf(buf, 5000, "\n\ -\n\ -\n\ -\n\ -open\n\ -\n\ - on-the-phone\n\ -\n\ -\n\ -%s\n\ -on the phone\n\ -\n\ -", - from, from); - } - else if (presence_mode==LINPHONE_STATUS_OUTTOLUNCH) - { - snprintf(buf, 5000, "\n\ -\n\ -\n\ -\n\ -open\n\ -\n\ - meal\n\ -\n\ -\n\ -%s\n\ -out to lunch\n\ -\n\ -", - from, from); - } - else if (presence_mode==LINPHONE_STATUS_OFFLINE) - { - /* */ - snprintf(buf, 5000, "\n\ -\n%s", - from, -"\n\ -\n\ -closed\n\ -\n\ - permanent-absence\n\ -\n\ -\n\ -\n\ -\n\n"); - } - - i = eXosip_build_publish(&pub, (char *)from, (char *)from, NULL, "presence", "1800", "application/pidf+xml", buf); - - if (i<0) - { - ms_message("Failed to build publish request."); - return -1; - } - - eXosip_lock(); - i = eXosip_publish(pub, from); /* should update the sip-if-match parameter - from sip-etag from last 200ok of PUBLISH */ - eXosip_unlock(); - if (i<0) - { - ms_message("Failed to send publish request."); - return -1; - } - return 0; + LinphoneOnlineStatus presence_mode){ + int err; + SalOp *op=sal_op_new(proxy->lc->sal); + err=sal_publish(op,linphone_proxy_config_get_identity(proxy), + linphone_proxy_config_get_identity(proxy),linphone_online_status_to_sal(presence_mode)); + sal_op_release(op); + return err; } @@ -657,13 +392,15 @@ entity=\"%s\">\n%s", **/ int linphone_core_add_proxy_config(LinphoneCore *lc, LinphoneProxyConfig *cfg){ if (!linphone_proxy_config_check(lc,cfg)) return -1; + if (ms_list_find(lc->sip_conf.proxies,cfg)!=NULL){ + ms_warning("ProxyConfig already entered, ignored."); + return 0; + } lc->sip_conf.proxies=ms_list_append(lc->sip_conf.proxies,(void *)cfg); linphone_proxy_config_apply(cfg,lc); return 0; } -extern void linphone_friend_check_for_removed_proxy(LinphoneFriend *lf, LinphoneProxyConfig *cfg); - /** * Removes a proxy configuration. * @@ -671,7 +408,6 @@ extern void linphone_friend_check_for_removed_proxy(LinphoneFriend *lf, Linphone * on a deleted list. For that reason, a removed proxy does NOT need to be freed. **/ void linphone_core_remove_proxy_config(LinphoneCore *lc, LinphoneProxyConfig *cfg){ - MSList *elem; lc->sip_conf.proxies=ms_list_remove(lc->sip_conf.proxies,(void *)cfg); /* add to the list of destroyed proxies, so that the possible unREGISTER request can succeed authentication */ lc->sip_conf.deleted_proxies=ms_list_append(lc->sip_conf.deleted_proxies,(void *)cfg); @@ -680,11 +416,6 @@ void linphone_core_remove_proxy_config(LinphoneCore *lc, LinphoneProxyConfig *cf if (lc->default_proxy==cfg){ lc->default_proxy=NULL; } - /* invalidate all references to this proxy in our friend list */ - for (elem=lc->friends;elem!=NULL;elem=ms_list_next(elem)){ - linphone_friend_check_for_removed_proxy((LinphoneFriend*)elem->data,cfg); - } - } /** * Erase all proxies from config. @@ -735,23 +466,6 @@ int linphone_core_get_default_proxy(LinphoneCore *lc, LinphoneProxyConfig **conf return pos; } -static int rid_compare(const void *pcfg,const void *prid){ - const LinphoneProxyConfig *cfg=(const LinphoneProxyConfig*)pcfg; - const int *rid=(const int*)prid; - ms_message("cfg= %s, cfg->rid=%i, rid=%i",cfg->reg_proxy, cfg->rid, *rid); - return cfg->rid-(*rid); -} - -LinphoneProxyConfig *linphone_core_get_proxy_config_from_rid(LinphoneCore *lc, int rid){ - MSList *elem=ms_list_find_custom(lc->sip_conf.proxies,rid_compare, &rid); - if (elem==NULL){ - ms_message("linphone_core_get_proxy_config_from_rid: searching in deleted proxies..."); - elem=ms_list_find_custom(lc->sip_conf.deleted_proxies,rid_compare, &rid); - } - if (elem==NULL) return NULL; - else return (LinphoneProxyConfig*)elem->data; -} - /** * Returns an unmodifiable list of entered proxy configurations. **/ @@ -759,47 +473,6 @@ const MSList *linphone_core_get_proxy_config_list(const LinphoneCore *lc){ return lc->sip_conf.proxies; } - -void linphone_proxy_config_process_authentication_failure(LinphoneCore *lc, int code, eXosip_event_t *ev){ - if (code==403) { - LinphoneProxyConfig *cfg=linphone_core_get_proxy_config_from_rid(lc, ev->rid); - if (cfg){ - cfg->auth_failures++; - /*restart a new register so that the user gets a chance to be prompted for a password*/ - if (cfg->auth_failures==1){ - linphone_proxy_config_register(cfg); - } - } - } else { - //unknown error (possibly timeout) - char *prx_realm=NULL,*www_realm=NULL; - osip_proxy_authenticate_t *prx_auth; - osip_www_authenticate_t *www_auth; - osip_message_t *req=ev->request; - char *username; - username=osip_uri_get_username(req->from->url); - prx_auth=(osip_proxy_authenticate_t*)osip_list_get(&req->proxy_authenticates,0); - www_auth=(osip_proxy_authenticate_t*)osip_list_get(&req->www_authenticates,0); - if (prx_auth!=NULL) - prx_realm=osip_proxy_authenticate_get_realm(prx_auth); - if (www_auth!=NULL) - www_realm=osip_www_authenticate_get_realm(www_auth); - - if (prx_realm==NULL && www_realm==NULL){ - ms_warning("No realm in the client request."); - return; - } - LinphoneAuthInfo *as=NULL; - /* see if we already have this auth information , not to ask it everytime to the user */ - if (prx_realm!=NULL) - as=linphone_core_find_auth_info(lc,prx_realm,username); - if (www_realm!=NULL) - as=linphone_core_find_auth_info(lc,www_realm,username); - - if (as) as->first_time=TRUE; - } -} - void linphone_proxy_config_write_to_config_file(LpConfig *config, LinphoneProxyConfig *obj, int index) { char key[50]; diff --git a/coreapi/sal.c b/coreapi/sal.c index 6ff25bc10..d33124e8a 100644 --- a/coreapi/sal.c +++ b/coreapi/sal.c @@ -99,6 +99,10 @@ void sal_op_set_user_pointer(SalOp *op, void *up){ ((SalOpBase*)op)->user_pointer=up; } +Sal *sal_op_get_sal(const SalOp *op){ + return ((SalOpBase*)op)->root; +} + const char *sal_op_get_from(const SalOp *op){ return ((SalOpBase*)op)->from; } @@ -119,6 +123,10 @@ void *sal_op_get_user_pointer(const SalOp *op){ return ((SalOpBase*)op)->user_pointer; } +const char *sal_op_get_proxy(const SalOp *op){ + return ((SalOpBase*)op)->route; +} + void __sal_op_init(SalOp *b, Sal *sal){ memset(b,0,sizeof(SalOpBase)); ((SalOpBase*)b)->root=sal; diff --git a/coreapi/sal.h b/coreapi/sal.h index ebd8bc1e0..5dc91efd7 100644 --- a/coreapi/sal.h +++ b/coreapi/sal.h @@ -82,6 +82,13 @@ typedef enum{ SalProtoRtpSavp }SalMediaProto; +typedef struct SalEndpointCandidate{ + char addr[64]; + int port; +}SalEndpointCandidate; + +#define SAL_ENDPOINT_CANDIDATE_MAX 2 + typedef struct SalStreamDescription{ SalMediaProto proto; SalStreamType type; @@ -90,6 +97,7 @@ typedef struct SalStreamDescription{ MSList *payloads; //user_data=(void*)((long)n); #define payload_type_get_number(pt) ((int)(long)(pt)->user_data) diff --git a/coreapi/sal_eXosip2.c b/coreapi/sal_eXosip2.c index 6056533b9..88e502751 100644 --- a/coreapi/sal_eXosip2.c +++ b/coreapi/sal_eXosip2.c @@ -55,6 +55,39 @@ static void sal_remove_register(Sal *sal, int rid){ } } +static void sal_add_pending_auth(Sal *sal, SalOp *op){ + sal->pending_auths=ms_list_append(sal->pending_auths,op); +} + + +static void sal_remove_pending_auth(Sal *sal, SalOp *op){ + sal->pending_auths=ms_list_remove(sal->pending_auths,op); +} + +void sal_exosip_fix_route(SalOp *op){ + if (sal_op_get_route(op)!=NULL){ + osip_route_t *rt=NULL; + osip_uri_param_t *lr_param=NULL; + + osip_route_init(&rt); + if (osip_route_parse(rt,sal_op_get_route(op))<0){ + ms_warning("Bad route %s!",sal_op_get_route(op)); + sal_op_set_route(op,NULL); + }else{ + /* check if the lr parameter is set , if not add it */ + osip_uri_uparam_get_byname(rt->url, "lr", &lr_param); + if (lr_param==NULL){ + char *tmproute; + osip_uri_uparam_add(rt->url,osip_strdup("lr"),NULL); + osip_route_to_str(rt,&tmproute); + sal_op_set_route(op,tmproute); + osip_free(tmproute); + } + } + osip_route_free(rt); + } +} + SalOp * sal_op_new(Sal *sal){ SalOp *op=ms_new(SalOp,1); __sal_op_init(op,sal); @@ -78,6 +111,9 @@ void sal_op_release(SalOp *op){ if (op->cid!=-1){ eXosip_call_set_reference(op->cid,NULL); } + if (op->pending_auth){ + sal_remove_pending_auth(op->base.root,op); + } __sal_op_free(op); } @@ -174,8 +210,8 @@ void sal_set_callbacks(Sal *ctx, const SalCallbacks *cbs){ ctx->callbacks.register_failure=(SalOnRegisterFailure)unimplemented_stub; if (ctx->callbacks.dtmf_received==NULL) ctx->callbacks.dtmf_received=(SalOnDtmfReceived)unimplemented_stub; - if (ctx->callbacks.presence_changed==NULL) - ctx->callbacks.presence_changed=(SalOnPresenceChanged)unimplemented_stub; + if (ctx->callbacks.notify==NULL) + ctx->callbacks.notify=(SalOnNotify)unimplemented_stub; if (ctx->callbacks.subscribe_received==NULL) ctx->callbacks.subscribe_received=(SalOnSubscribeReceived)unimplemented_stub; if (ctx->callbacks.text_received==NULL) @@ -215,6 +251,10 @@ void sal_use_session_timers(Sal *ctx, int expires){ ctx->session_expires=expires; } +MSList *sal_get_pending_auths(Sal *sal){ + return ms_list_copy(sal->pending_auths); +} + static void set_sdp(osip_message_t *sip,sdp_message_t *msg){ int sdplen; @@ -277,7 +317,8 @@ int sal_call(SalOp *h, const char *from, const char *to){ osip_message_t *invite=NULL; sal_op_set_from(h,from); sal_op_set_to(h,to); - err=eXosip_call_build_initial_invite(&invite,to,from,h->base.route,"Phone call"); + sal_exosip_fix_route(h); + err=eXosip_call_build_initial_invite(&invite,to,from,sal_op_get_route(h),"Phone call"); if (err!=0){ ms_error("Could not create call."); return -1; @@ -625,6 +666,13 @@ static int get_auth_data(eXosip_event_t *ev, const char **realm, const char **us return 0; } +int sal_op_get_auth_requested(SalOp *op, const char **realm, const char **username){ + if (op->pending_auth){ + return get_auth_data(op->pending_auth,realm,username); + } + return -1; +} + static bool_t process_authentication(Sal *sal, eXosip_event_t *ev){ SalOp *op; const char *username,*realm; @@ -637,6 +685,7 @@ static bool_t process_authentication(Sal *sal, eXosip_event_t *ev){ if (op->pending_auth!=NULL) eXosip_event_free(op->pending_auth); op->pending_auth=ev; + sal_add_pending_auth (sal,op); sal->callbacks.auth_requested(op,realm,username); return FALSE; } @@ -1129,6 +1178,8 @@ int sal_iterate(Sal *sal){ int sal_register(SalOp *h, const char *proxy, const char *from, int expires){ osip_message_t *msg; + sal_op_set_route(h,proxy); + sal_exosip_fix_route(h); if (h->rid==-1){ eXosip_lock(); h->rid=eXosip_register_build_initial_register(from,proxy,sal_op_get_contact(h),expires,&msg); @@ -1143,6 +1194,16 @@ int sal_register(SalOp *h, const char *proxy, const char *from, int expires){ return 0; } +int sal_unregister(SalOp *h){ + osip_message_t *msg=NULL; + eXosip_lock(); + eXosip_register_build_register(h->rid,0,&msg); + if (msg) eXosip_register_send_register(h->rid,msg); + else ms_warning("Could not build unREGISTER !"); + eXosip_unlock(); + return 0; +} + SalAddress * sal_address_new(const char *uri){ diff --git a/coreapi/sal_eXosip2.h b/coreapi/sal_eXosip2.h index a2bae79f4..4e5d81240 100644 --- a/coreapi/sal_eXosip2.h +++ b/coreapi/sal_eXosip2.h @@ -33,6 +33,7 @@ struct Sal{ MSList *registers;/*MSList of SalOp */ MSList *out_subscribes;/*MSList of SalOp */ MSList *in_subscribes;/*MSList of SalOp */ + MSList *pending_auths;/*MSList of SalOp */ int running; int session_expires; void *up; @@ -60,5 +61,7 @@ void sal_exosip_subscription_answered(Sal *sal,eXosip_event_t *ev); void sal_exosip_notify_recv(Sal *sal,eXosip_event_t *ev); void sal_exosip_subscription_closed(Sal *sal,eXosip_event_t *ev); +void sal_exosip_fix_route(SalOp *op); + #endif diff --git a/coreapi/sal_eXosip2_presence.c b/coreapi/sal_eXosip2_presence.c index d6ecc8839..d4ab7ba41 100644 --- a/coreapi/sal_eXosip2_presence.c +++ b/coreapi/sal_eXosip2_presence.c @@ -97,6 +97,7 @@ int sal_subscribe_presence(SalOp *op, const char *from, const char *to){ sal_op_set_from(op,from); if (to) sal_op_set_to(op,to); + sal_exosip_fix_route(op); eXosip_lock(); eXosip_subscribe_build_initial_request(&msg,sal_op_get_to(op),sal_op_get_from(op), sal_op_get_route(op),"presence",600); @@ -142,31 +143,6 @@ int sal_subscribe_decline(SalOp *op){ return 0; } -static eXosip_ss_status_t sal_presence_to_exosip(SalPresenceStatus s){ - switch(s){ - case SalPresenceOffline: - return EXOSIP_NOTIFY_CLOSED; - case SalPresenceOnline: - return EXOSIP_NOTIFY_ONLINE; - case SalPresenceBusy: - return EXOSIP_NOTIFY_BUSY; - case SalPresenceBerightback: - return EXOSIP_NOTIFY_BERIGHTBACK; - case SalPresenceAway: - return EXOSIP_NOTIFY_AWAY; - case SalPresenceOnthephone: - return EXOSIP_NOTIFY_ONTHEPHONE; - case SalPresenceOuttolunch: - return EXOSIP_NOTIFY_OUTTOLUNCH; - case SalPresenceDonotdisturb: - return EXOSIP_NOTIFY_BUSY; - case SalPresenceMoved: - case SalPresenceAltService: - default: - return EXOSIP_NOTIFY_AWAY; - } -} - static void add_presence_body(osip_message_t *notify, SalPresenceStatus online_status) { char buf[1000]; @@ -435,14 +411,14 @@ entity=\"%s\">\n%s", int sal_notify_presence(SalOp *op, SalPresenceStatus status, const char *status_message){ osip_message_t *msg; - eXosip_ss_status_t ss; + eXosip_ss_t ss=EXOSIP_SUBCRSTATE_ACTIVE; if (op->nid==-1){ ms_warning("Cannot notify, subscription was closed."); return -1; } - ss=sal_presence_to_exosip(status); + eXosip_lock(); - eXosip_insubscription_build_notify(op->did,ss,0,&msg); + eXosip_insubscription_build_notify(op->did,ss,DEACTIVATED,&msg); if (msg!=NULL){ const char *identity=sal_op_get_contact(op); if (identity==NULL) identity=sal_op_get_to(op); @@ -454,6 +430,172 @@ int sal_notify_presence(SalOp *op, SalPresenceStatus status, const char *status_ return 0; } +int sal_notify_close(SalOp *op){ + osip_message_t *msg; + eXosip_lock(); + eXosip_insubscription_build_notify(op->did,EXOSIP_SUBCRSTATE_TERMINATED,DEACTIVATED,&msg); + if (msg!=NULL){ + const char *identity=sal_op_get_contact(op); + if (identity==NULL) identity=sal_op_get_to(op); + osip_message_set_contact(msg,identity); + eXosip_insubscription_send_request(op->did,msg); + }else ms_error("could not create notify for incoming subscription."); + eXosip_unlock(); + return 0; +} + +int sal_publish(SalOp *op, const char *from, const char *to, SalPresenceStatus presence_mode){ + osip_message_t *pub; + int i; + char buf[1024]; + + if (presence_mode==SalPresenceOnline) + { + snprintf(buf, sizeof(buf), "\n\ + \n\ + \n\ + \n\ + open\n\ + \n\ + %s\n\ + online\n\ + \n\ + ", + from, from); + } + else if (presence_mode==SalPresenceBusy + ||presence_mode==SalPresenceDonotdisturb) + { + snprintf(buf, sizeof(buf), "\n\ + \n\ + \n\ + \n\ + open\n\ + \n\ + busy\n\ + \n\ + \n\ + %s\n\ + busy\n\ + \n\ + ", + from, from); + } + else if (presence_mode==SalPresenceBerightback) + { + snprintf(buf, sizeof(buf), "\n\ + \n\ + \n\ + \n\ + open\n\ + \n\ + in-transit\n\ + \n\ + \n\ + %s\n\ + be right back\n\ + \n\ + ", + from,from); + } + else if (presence_mode==SalPresenceAway + ||presence_mode==SalPresenceMoved) + { + snprintf(buf, sizeof(buf), "\n\ + \n\ + \n\ + \n\ + open\n\ + \n\ + away\n\ + \n\ + \n\ + %s\n\ + away\n\ + \n\ + ", + from, from); + } + else if (presence_mode==SalPresenceOnthephone) + { + snprintf(buf, sizeof(buf), "\n\ + \n\ + \n\ + \n\ + open\n\ + \n\ + on-the-phone\n\ + \n\ + \n\ + %s\n\ + on the phone\n\ + \n\ + ", + from, from); + } + else if (presence_mode==SalPresenceOuttolunch) + { + snprintf(buf, sizeof(buf), "\n\ + \n\ + \n\ + \n\ + open\n\ + \n\ + meal\n\ + \n\ + \n\ + %s\n\ + out to lunch\n\ + \n\ + ", + from, from); + } + else{ + /* offline */ + snprintf(buf, sizeof(buf), "\n\ + \n%s", + from, + "\n\ + \n\ + closed\n\ + \n\ + permanent-absence\n\ + \n\ + \n\ + \n\ + \n\n"); + } + + i = eXosip_build_publish(&pub,from, to, NULL, "presence", "1800", "application/pidf+xml", buf); + if (i<0){ + ms_warning("Failed to build publish request."); + return -1; + } + + eXosip_lock(); + i = eXosip_publish(pub, to); /* should update the sip-if-match parameter + from sip-etag from last 200ok of PUBLISH */ + eXosip_unlock(); + if (i<0){ + ms_message("Failed to send publish request."); + return -1; + } + return 0; +} + void sal_exosip_subscription_recv(Sal *sal, eXosip_event_t *ev){ SalOp *op=sal_op_new(sal); char *tmp; @@ -521,7 +663,7 @@ void sal_exosip_notify_recv(Sal *sal, eXosip_event_t *ev){ op->did=-1; ms_message("And outgoing subscription terminated by remote."); } - sal->callbacks.presence_changed(op,estatus,NULL); + sal->callbacks.notify(op,op->sid!=-1 ? SalSubscribeActive : SalSubscribeTerminated, estatus,NULL); osip_free(tmp); } @@ -545,3 +687,4 @@ void sal_exosip_subscription_closed(Sal *sal,eXosip_event_t *ev){ op->did=0; } + diff --git a/coreapi/sal_eXosip2_sdp.c b/coreapi/sal_eXosip2_sdp.c index 2aed6283a..d517a7222 100644 --- a/coreapi/sal_eXosip2_sdp.c +++ b/coreapi/sal_eXosip2_sdp.c @@ -153,10 +153,29 @@ static void add_payload(sdp_message_t *msg, int line, const PayloadType *pt) static void add_line(sdp_message_t *msg, int lineno, const SalStreamDescription *desc){ - const char *mt=desc->type==SAL_AUDIO ? "audio" : "video"; + const char *mt=desc->type==SalAudio ? "audio" : "video"; const MSList *elem; + const char *addr; + int port; + if (desc->candidates[0].addr[0]!='\0'){ + addr=desc->candidates[0].addr; + port=desc->candidates[0].port; + }else{ + addr=desc->addr; + port=desc->port; + } + /*only add a c= line within the stream description if address are differents*/ + if (strcmp(addr,sdp_message_c_addr_get(msg, -1, 0))!=0){ + bool_t inet6; + if (strchr(addr,':')!=NULL){ + inet6=TRUE; + }else inet6=FALSE; + sdp_message_c_connection_add (msg, lineno, + osip_strdup ("IN"), inet6 ? osip_strdup ("IP6") : osip_strdup ("IP4"), + osip_strdup (addr), NULL, NULL); + } sdp_message_m_media_add (msg, osip_strdup (mt), - int_2char (desc->port), NULL, + int_2char (port), NULL, osip_strdup ("RTP/AVP")); sdp_message_b_bandwidth_add (msg, lineno, osip_strdup ("AS"), int_2char(desc->bandwidth)); @@ -222,12 +241,12 @@ int sdp_to_media_description(sdp_message_t *msg, SalMediaDescription *desc){ mtype = sdp_message_m_media_get(msg, i); proto = sdp_message_m_proto_get (msg, i); port = sdp_message_m_port_get(msg, i); - stream->proto=SAL_PROTO_UNKNOWN; + stream->proto=SalProtoUnknown; if (proto){ if (strcasecmp(proto,"RTP/AVP")==0) - stream->proto=SAL_PROTO_RTP_AVP; + stream->proto=SalProtoRtpAvp; else if (strcasecmp(proto,"RTP/SAVP")==0){ - stream->proto=SAL_PROTO_RTP_SAVP; + stream->proto=SalProtoRtpSavp; } } addr = sdp_message_c_addr_get (msg, i, 0); @@ -235,10 +254,10 @@ int sdp_to_media_description(sdp_message_t *msg, SalMediaDescription *desc){ strncpy(stream->addr,addr,sizeof(stream->addr)); stream->ptime=_sdp_message_get_a_ptime(msg,i); if (strcasecmp("audio", mtype) == 0){ - stream->type=SAL_AUDIO; + stream->type=SalAudio; }else if (strcasecmp("video", mtype) == 0){ - stream->type=SAL_VIDEO; - }else stream->type=SAL_OTHER; + stream->type=SalVideo; + }else stream->type=SalOther; for(j=0;(sbw=sdp_message_bandwidth_get(msg,i,j))!=NULL;++j){ if (strcasecmp(sbw->b_bwtype,"AS")==0) stream->bandwidth=atoi(sbw->b_bandwidth); } diff --git a/mediastreamer2 b/mediastreamer2 index a11023fbc..8dae09b11 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit a11023fbcc2ba355d40d474cc6b863e29a4960fb +Subproject commit 8dae09b11ee8a0fe29674944b207b5e06fb0f4ed diff --git a/oRTP b/oRTP index fd65d8401..da176d2f4 160000 --- a/oRTP +++ b/oRTP @@ -1 +1 @@ -Subproject commit fd65d84014c4cb3c500952c2f4b42dc4630ac37d +Subproject commit da176d2f439f990012a1bf47b39fb72070dbd580 From f3737ffb1aba8b89fc09cdd0974437d18a062341 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Sun, 7 Feb 2010 15:54:39 +0100 Subject: [PATCH 16/50] sal is code complete. --- coreapi/authentication.c | 122 ++++++--------------------------------- coreapi/general_state.c | 2 +- coreapi/sal_eXosip2.c | 3 +- coreapi/siplogin.c | 1 + 4 files changed, 21 insertions(+), 107 deletions(-) diff --git a/coreapi/authentication.c b/coreapi/authentication.c index e55ab495a..fc27142db 100644 --- a/coreapi/authentication.c +++ b/coreapi/authentication.c @@ -24,12 +24,8 @@ #include "linphonecore.h" #include "private.h" -#include -#include #include "lpconfig.h" -extern LinphoneProxyConfig *linphone_core_get_proxy_config_from_rid(LinphoneCore *lc, int rid); - /** * @addtogroup authentication * @{ @@ -211,21 +207,6 @@ LinphoneAuthInfo *linphone_core_find_auth_info(LinphoneCore *lc, const char *rea return ret; } -static void refresh_exosip_auth_info(LinphoneCore *lc){ - MSList *elem; - eXosip_lock(); - eXosip_clear_authentication_info(); - for (elem=lc->auth_info;elem!=NULL;elem=ms_list_next(elem)){ - LinphoneAuthInfo *info=(LinphoneAuthInfo*)elem->data; - char *userid; - if (info->userid==NULL || info->userid[0]=='\0') userid=info->username; - else userid=info->userid; - eXosip_add_authentication_info(info->username,userid, - info->passwd,info->ha1,info->realm); - } - eXosip_unlock(); -} - /** * Adds authentication information to the LinphoneCore. * @@ -249,8 +230,23 @@ void linphone_core_add_auth_info(LinphoneCore *lc, LinphoneAuthInfo *info) }else { lc->auth_info=ms_list_append(lc->auth_info,(void *)info); } - refresh_exosip_auth_info(lc); - /* if the user was prompted, re-allow automatic_action */ + /* retry pending authentication operations */ + for(elem=sal_get_pending_auths(lc->sal);elem!=NULL;elem=elem->next){ + const char *username,*realm; + SalOp *op=(SalOp*)elem->data; + LinphoneAuthInfo *ai; + sal_op_get_auth_requested(op,&realm,&username); + ai=linphone_core_find_auth_info(lc,realm,username); + if (ai){ + SalAuthInfo sai; + sai.username=ai->username; + sai.userid=ai->userid; + sai.realm=ai->realm; + sai.password=ai->passwd; + sal_op_authenticate(op,&sai); + ai->usecount++; + } + } } @@ -259,7 +255,6 @@ void linphone_core_add_auth_info(LinphoneCore *lc, LinphoneAuthInfo *info) * from the auth_info_requested callback of LinphoneCoreVTable. **/ void linphone_core_abort_authentication(LinphoneCore *lc, LinphoneAuthInfo *info){ - if (lc->automatic_action>0) lc->automatic_action--; } /** @@ -280,8 +275,6 @@ void linphone_core_remove_auth_info(LinphoneCore *lc, LinphoneAuthInfo *info){ for (elem=lc->auth_info,i=0;elem!=NULL;elem=ms_list_next(elem),i++){ linphone_auth_info_write_config(lc->config,(LinphoneAuthInfo*)elem->data,i); } - refresh_exosip_auth_info(lc); - } /** @@ -297,9 +290,6 @@ const MSList *linphone_core_get_auth_info_list(const LinphoneCore *lc){ void linphone_core_clear_all_auth_info(LinphoneCore *lc){ MSList *elem; int i; - eXosip_lock(); - eXosip_clear_authentication_info(); - eXosip_unlock(); for(i=0,elem=lc->auth_info;elem!=NULL;elem=ms_list_next(elem),i++){ LinphoneAuthInfo *info=(LinphoneAuthInfo*)elem->data; linphone_auth_info_destroy(info); @@ -309,84 +299,6 @@ void linphone_core_clear_all_auth_info(LinphoneCore *lc){ lc->auth_info=NULL; } -void linphone_authentication_ok(LinphoneCore *lc, eXosip_event_t *ev){ - char *prx_realm=NULL,*www_realm=NULL; - osip_proxy_authorization_t *prx_auth; - osip_authorization_t *www_auth; - osip_message_t *msg=ev->request; - char *username; - LinphoneAuthInfo *as=NULL; - - username=osip_uri_get_username(msg->from->url); - osip_message_get_proxy_authorization(msg,0,&prx_auth); - osip_message_get_authorization(msg,0,&www_auth); - if (prx_auth!=NULL) - prx_realm=osip_proxy_authorization_get_realm(prx_auth); - if (www_auth!=NULL) - www_realm=osip_authorization_get_realm(www_auth); - - if (prx_realm==NULL && www_realm==NULL){ - ms_message("No authentication info in the request, ignoring"); - return; - } - /* see if we already have this auth information , not to ask it everytime to the user */ - if (prx_realm!=NULL) - as=linphone_core_find_auth_info(lc,prx_realm,username); - if (www_realm!=NULL) - as=linphone_core_find_auth_info(lc,www_realm,username); - if (as){ - ms_message("Authentication for user=%s realm=%s is working.",username,prx_realm ? prx_realm : www_realm); - as->works=TRUE; - } -} - - -void linphone_core_find_or_ask_for_auth_info(LinphoneCore *lc,const char *username,const char* realm, int tid) -{ - LinphoneAuthInfo *as=linphone_core_find_auth_info(lc,realm,username); - if ( as==NULL || (as!=NULL && as->works==FALSE && as->first_time==FALSE)){ - if (lc->vtable.auth_info_requested!=NULL){ - lc->vtable.auth_info_requested(lc,realm,username); - lc->automatic_action++;/*suspends eXosip_automatic_action until the user supplies a password */ - } - } - if (as) as->first_time=FALSE; -} - -void linphone_process_authentication(LinphoneCore *lc, eXosip_event_t *ev) -{ - char *prx_realm=NULL,*www_realm=NULL; - osip_proxy_authenticate_t *prx_auth; - osip_www_authenticate_t *www_auth; - osip_message_t *resp=ev->response; - char *username; - - /* - if (strcmp(ev->request->sip_method,"REGISTER")==0) { - gstate_new_state(lc, GSTATE_REG_FAILED, "Authentication required"); - } - */ - - username=osip_uri_get_username(resp->from->url); - prx_auth=(osip_proxy_authenticate_t*)osip_list_get(&resp->proxy_authenticates,0); - www_auth=(osip_proxy_authenticate_t*)osip_list_get(&resp->www_authenticates,0); - if (prx_auth!=NULL) - prx_realm=osip_proxy_authenticate_get_realm(prx_auth); - if (www_auth!=NULL) - www_realm=osip_www_authenticate_get_realm(www_auth); - - if (prx_realm==NULL && www_realm==NULL){ - ms_warning("No realm in the server response."); - return; - } - /* see if we already have this auth information , not to ask it everytime to the user */ - if (prx_realm!=NULL) - linphone_core_find_or_ask_for_auth_info(lc,username,prx_realm,ev->tid); - if (www_realm!=NULL) - linphone_core_find_or_ask_for_auth_info(lc,username,www_realm,ev->tid); -} - - /** * @} **/ diff --git a/coreapi/general_state.c b/coreapi/general_state.c index 7cf713773..210037887 100644 --- a/coreapi/general_state.c +++ b/coreapi/general_state.c @@ -24,7 +24,7 @@ #include "linphonecore.h" - +#include "private.h" #if 0 static const char *_gstates_text[] = { "GSTATE_POWER_OFF", /* 0 */ diff --git a/coreapi/sal_eXosip2.c b/coreapi/sal_eXosip2.c index 88e502751..e76f2c248 100644 --- a/coreapi/sal_eXosip2.c +++ b/coreapi/sal_eXosip2.c @@ -465,11 +465,12 @@ void sal_op_authenticate(SalOp *h, const SalAuthInfo *info){ const char *userid; if (info->userid==NULL || info->userid[0]=='\0') userid=info->username; else userid=info->userid; - eXosip_lock(); eXosip_add_authentication_info (info->username,userid, info->password, NULL,info->realm); + eXosip_lock(); eXosip_default_action(h->pending_auth); eXosip_unlock(); + eXosip_clear_authentication_info(); eXosip_event_free(h->pending_auth); h->pending_auth=NULL; } diff --git a/coreapi/siplogin.c b/coreapi/siplogin.c index 528e3f328..0037fa1d6 100644 --- a/coreapi/siplogin.c +++ b/coreapi/siplogin.c @@ -22,6 +22,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #endif #include "linphonecore.h" +#include "private.h" #include static void sip_login_init_instance(SipSetupContext *ctx){ From 037145b937e7988d357d89850dc46b9f1d22a699 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Mon, 8 Feb 2010 13:07:40 +0100 Subject: [PATCH 17/50] ported everything to updated liblinphone api. --- console/Makefile.am | 2 +- console/commands.c | 17 +++++++-------- console/linphonec.c | 10 ++++----- coreapi/authentication.c | 18 +++++++++++++++ coreapi/friend.c | 9 ++++++-- coreapi/linphonecore.h | 30 +++++++++++++------------ coreapi/presence.c | 22 +------------------ coreapi/proxy.c | 47 ++++++++++++++++++++++++++++++++++++++++ gtk-glade/friendlist.c | 13 +++++------ gtk-glade/loginframe.c | 4 +++- gtk-glade/main.c | 4 ++-- oRTP | 2 +- 12 files changed, 114 insertions(+), 64 deletions(-) diff --git a/console/Makefile.am b/console/Makefile.am index 45f886580..70c2625b4 100644 --- a/console/Makefile.am +++ b/console/Makefile.am @@ -13,7 +13,7 @@ INCLUDES = \ -bin_PROGRAMS = linphonec sipomatic linphonecsh +bin_PROGRAMS = linphonec linphonecsh if BUILD_WIN32 bin_PROGRAMS += linphoned diff --git a/console/commands.c b/console/commands.c index 08a747e56..7b1a7912b 100644 --- a/console/commands.c +++ b/console/commands.c @@ -1255,7 +1255,7 @@ linphonec_proxy_use(LinphoneCore *lc, int index) static void linphonec_friend_display(LinphoneFriend *fr) { - LinphoneAddress *uri=linphone_address_clone(linphone_friend_get_uri(fr)); + LinphoneAddress *uri=linphone_address_clone(linphone_friend_get_address(fr)); char *str; linphonec_out("name: %s\n", linphone_address_get_display_name(uri)); @@ -1280,7 +1280,7 @@ linphonec_friend_list(LinphoneCore *lc, char *pat) { if ( pat ) { const char *name = linphone_address_get_display_name( - linphone_friend_get_uri((LinphoneFriend*)friend->data)); + linphone_friend_get_address((LinphoneFriend*)friend->data)); if (name && ! strstr(name, pat) ) continue; } linphonec_out("****** Friend %i *******\n",n); @@ -1302,7 +1302,7 @@ linphonec_friend_call(LinphoneCore *lc, unsigned int num) if ( n == num ) { int ret; - addr = linphone_address_as_string(linphone_friend_get_uri((LinphoneFriend*)friend->data)); + addr = linphone_address_as_string(linphone_friend_get_address((LinphoneFriend*)friend->data)); ret=lpc_cmd_call(lc, addr); ms_free(addr); return ret; @@ -1376,16 +1376,15 @@ static int lpc_cmd_register(LinphoneCore *lc, char *args){ return 1; } if (passwd[0]!='\0'){ - osip_from_t *from; + LinphoneAddress *from; LinphoneAuthInfo *info; - osip_from_init(&from); - if (osip_from_parse(from,identity)==0){ + if ((from=linphone_address_new(identity))!=NULL){ char realm[128]; - snprintf(realm,sizeof(realm)-1,"\"%s\"",from->url->host); - info=linphone_auth_info_new(from->url->username,NULL,passwd,NULL,NULL); + snprintf(realm,sizeof(realm)-1,"\"%s\"",linphone_address_get_domain(from)); + info=linphone_auth_info_new(linphone_address_get_username(from),NULL,passwd,NULL,NULL); linphone_core_add_auth_info(lc,info); + linphone_address_destroy(from); } - osip_from_free(from); } elem=linphone_core_get_proxy_config_list(lc); if (elem) { diff --git a/console/linphonec.c b/console/linphonec.c index 81fccea14..629612bb0 100644 --- a/console/linphonec.c +++ b/console/linphonec.c @@ -119,8 +119,7 @@ static void linphonec_display_something (LinphoneCore * lc, const char *somethin static void linphonec_display_url (LinphoneCore * lc, const char *something, const char *url); static void linphonec_display_warning (LinphoneCore * lc, const char *something); static void stub () {} -static void linphonec_notify_received(LinphoneCore *lc,LinphoneFriend *fid, - const char *from, const char *status, const char *img); +static void linphonec_notify_received(LinphoneCore *lc,LinphoneFriend *fid); static void linphonec_new_unknown_subscriber(LinphoneCore *lc, LinphoneFriend *lf, const char *url); static void linphonec_bye_received(LinphoneCore *lc, const char *from); @@ -283,10 +282,11 @@ linphonec_prompt_for_auth(LinphoneCore *lc, const char *realm, const char *usern * Linphone core callback */ static void -linphonec_notify_received(LinphoneCore *lc,LinphoneFriend *fid, - const char *from, const char *status, const char *img) +linphonec_notify_received(LinphoneCore *lc,LinphoneFriend *fid) { - printf("Friend %s is %s\n", from, status); + char *tmp=linphone_address_as_string(linphone_friend_get_address(fid)); + printf("Friend %s is %s\n", tmp, linphone_online_status_to_string(linphone_friend_get_status(fid))); + ms_free(tmp); // todo: update Friend list state (unimplemented) } diff --git a/coreapi/authentication.c b/coreapi/authentication.c index fc27142db..6551b7121 100644 --- a/coreapi/authentication.c +++ b/coreapi/authentication.c @@ -50,6 +50,24 @@ LinphoneAuthInfo *linphone_auth_info_new(const char *username, const char *useri return obj; } +/** + * Returns username. +**/ +const char *linphone_auth_info_get_username(const LinphoneAuthInfo *i){ + return i->username; +} + +/** + * Returns password. +**/ +const char *linphone_auth_info_get_passwd(const LinphoneAuthInfo *i){ + return i->passwd; +} + +const char *linphone_auth_info_get_userid(const LinphoneAuthInfo *i){ + return i->userid; +} + /** * Sets the password. **/ diff --git a/coreapi/friend.c b/coreapi/friend.c index 5dd51bec5..080dffb4e 100644 --- a/coreapi/friend.c +++ b/coreapi/friend.c @@ -140,8 +140,9 @@ void __linphone_friend_do_subscribe(LinphoneFriend *fr){ }else from=linphone_core_get_primary_contact(fr->lc); if (fr->outsub==NULL){ /* people for which we don't have yet an answer should appear as offline */ + fr->status=LINPHONE_STATUS_OFFLINE; if (fr->lc->vtable.notify_recv) - fr->lc->vtable.notify_recv(fr->lc,(LinphoneFriend*)fr,friend,_("Gone"),"sip-closed.png"); + fr->lc->vtable.notify_recv(fr->lc,(LinphoneFriend*)fr); }else{ sal_op_release(fr->outsub); fr->outsub=NULL; @@ -169,6 +170,10 @@ LinphoneFriend *linphone_friend_new_with_addr(const char *addr){ return fr; } +bool_t linphone_friend_in_list(const LinphoneFriend *lf){ + return lf->lc!=NULL; +} + void linphone_core_interpret_friend_uri(LinphoneCore *lc, const char *uri, char **result){ LinphoneAddress *fr=NULL; *result=NULL; @@ -304,7 +309,7 @@ void linphone_friend_destroy(LinphoneFriend *lf){ ms_free(lf); } -const LinphoneAddress *linphone_friend_get_uri(const LinphoneFriend *lf){ +const LinphoneAddress *linphone_friend_get_address(const LinphoneFriend *lf){ return lf->uri; } diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index 2c2f5c582..af5435769 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -175,7 +175,7 @@ LinphoneOnlineStatus linphone_friend_get_status(const LinphoneFriend *lf); BuddyInfo * linphone_friend_get_info(const LinphoneFriend *lf); void linphone_friend_set_ref_key(LinphoneFriend *lf, const char *key); const char *linphone_friend_get_ref_key(const LinphoneFriend *lf); -#define linphone_friend_in_list(lf) ((lf)->lc!=NULL) +bool_t linphone_friend_in_list(const LinphoneFriend *lf); #define linphone_friend_url(lf) ((lf)->url) @@ -218,18 +218,15 @@ void linphone_proxy_config_set_dial_prefix(LinphoneProxyConfig *cfg, const char bool_t linphone_proxy_config_is_registered(const LinphoneProxyConfig *obj); const char *linphone_proxy_config_get_domain(const LinphoneProxyConfig *cfg); -/** Returns the proxy configured identity as a const char * */ -#define linphone_proxy_config_get_route(obj) ((obj)->reg_route) -/** Returns the proxy configured identity as a const char * */ -#define linphone_proxy_config_get_identity(obj) ((obj)->reg_identity) -#define linphone_proxy_config_publish_enabled(obj) ((obj)->publish) -/** Returns the proxy sip address as const char * */ -#define linphone_proxy_config_get_addr(obj) ((obj)->reg_proxy) -/** Returns the 'expire' time of the registration */ -#define linphone_proxy_config_get_expires(obj) ((obj)->expires) -/** Returns TRUE if registration is enabled, FALSE otherwise */ -#define linphone_proxy_config_register_enabled(obj) ((obj)->reg_sendregister) -#define linphone_proxy_config_get_core(obj) ((obj)->lc) + +const char *linphone_proxy_config_get_route(const LinphoneProxyConfig *obj); +const char *linphone_proxy_config_get_identity(const LinphoneProxyConfig *obj); +bool_t linphone_proxy_config_publish_enabled(const LinphoneProxyConfig *obj); +const char *linphone_proxy_config_get_addr(const LinphoneProxyConfig *obj); +int linphone_proxy_config_get_expires(const LinphoneProxyConfig *obj); +bool_t linphone_proxy_config_register_enabled(const LinphoneProxyConfig *obj); +struct _LinphoneCore * linphone_proxy_config_get_core(const LinphoneProxyConfig *obj); + bool_t linphone_proxy_config_get_dial_escape_plus(const LinphoneProxyConfig *cfg); const char * linphone_proxy_config_get_dial_prefix(const LinphoneProxyConfig *cfg); @@ -295,6 +292,11 @@ LinphoneAuthInfo *linphone_auth_info_new(const char *username, const char *useri void linphone_auth_info_set_passwd(LinphoneAuthInfo *info, const char *passwd); void linphone_auth_info_set_username(LinphoneAuthInfo *info, const char *username); void linphone_auth_info_set_userid(LinphoneAuthInfo *info, const char *userid); + +const char *linphone_auth_info_get_username(const LinphoneAuthInfo *i); +const char *linphone_auth_info_get_passwd(const LinphoneAuthInfo *i); +const char *linphone_auth_info_get_userid(const LinphoneAuthInfo *i); + /* you don't need those function*/ void linphone_auth_info_destroy(LinphoneAuthInfo *info); LinphoneAuthInfo * linphone_auth_info_new_from_config_file(struct _LpConfig *config, int pos); @@ -371,7 +373,7 @@ typedef void (*DisplayQuestionCb)(struct _LinphoneCore *lc, const char *message) /** Callback prototype */ typedef void (*LinphoneCoreCbFunc)(struct _LinphoneCore *lc,void * user_data); /** Callback prototype */ -typedef void (*NotifyReceivedCb)(struct _LinphoneCore *lc, LinphoneFriend * fid, const char *url, const char *status, const char *img); +typedef void (*NotifyReceivedCb)(struct _LinphoneCore *lc, LinphoneFriend * fid); /** Callback prototype */ typedef void (*NewUnknownSubscriberCb)(struct _LinphoneCore *lc, LinphoneFriend *lf, const char *url); /** Callback prototype */ diff --git a/coreapi/presence.c b/coreapi/presence.c index ffff0f209..0ff498ff7 100644 --- a/coreapi/presence.c +++ b/coreapi/presence.c @@ -88,8 +88,6 @@ void linphone_subscription_new(LinphoneCore *lc, SalOp *op, const char *from){ } void linphone_notify_recv(LinphoneCore *lc, SalOp *op, SalSubscribeState ss, SalPresenceStatus sal_status){ - const char *status=_("Gone"); - const char *img="sip-closed.png"; char *tmp; LinphoneFriend *lf; LinphoneAddress *friend=NULL; @@ -97,49 +95,31 @@ void linphone_notify_recv(LinphoneCore *lc, SalOp *op, SalSubscribeState ss, Sal switch(sal_status){ case SalPresenceOffline: - status=_("Gone"); - img="sip-closed.png"; estatus=LINPHONE_STATUS_OFFLINE; break; case SalPresenceOnline: - status=_("Online"); - img="sip-online.png"; estatus=LINPHONE_STATUS_ONLINE; break; case SalPresenceBusy: - status=_("Busy"); - img="sip-busy.png"; estatus=LINPHONE_STATUS_BUSY; break; case SalPresenceBerightback: - status=_("Away"); - img="sip-away.png"; estatus=LINPHONE_STATUS_AWAY; break; case SalPresenceAway: - status=_("Away"); - img="sip-away.png"; estatus=LINPHONE_STATUS_AWAY; break; case SalPresenceOnthephone: - status=_("On The Phone"); - img="sip-otp.png"; estatus=LINPHONE_STATUS_ONTHEPHONE; break; case SalPresenceOuttolunch: - status=_("Out To Lunch"); - img="sip-otl.png"; estatus=LINPHONE_STATUS_OUTTOLUNCH; break; case SalPresenceDonotdisturb: - status=_("Busy"); - img="sip-busy.png"; estatus=LINPHONE_STATUS_BUSY; break; case SalPresenceMoved: case SalPresenceAltService: - status=_("Away"); - img="sip-away.png"; estatus=LINPHONE_STATUS_AWAY; break; } @@ -148,7 +128,7 @@ void linphone_notify_recv(LinphoneCore *lc, SalOp *op, SalSubscribeState ss, Sal friend=lf->uri; tmp=linphone_address_as_string(friend); lf->status=estatus; - lc->vtable.notify_recv(lc,(LinphoneFriend*)lf,tmp,status,img); + lc->vtable.notify_recv(lc,(LinphoneFriend*)lf); ms_free(tmp); }else{ ms_message("But this person is not part of our friend list, so we don't care."); diff --git a/coreapi/proxy.c b/coreapi/proxy.c index 69ebc7634..a033d1116 100644 --- a/coreapi/proxy.c +++ b/coreapi/proxy.c @@ -385,6 +385,53 @@ int linphone_proxy_config_send_publish(LinphoneProxyConfig *proxy, return err; } +/** + * Returns the route set for this proxy configuration. +**/ +const char *linphone_proxy_config_get_route(const LinphoneProxyConfig *obj){ + return obj->reg_route; +} + +/** + * Returns the SIP identity that belongs to this proxy configuration. + * + * The SIP identity is a SIP address (Display Name ) +**/ +const char *linphone_proxy_config_get_identity(const LinphoneProxyConfig *obj){ + return obj->reg_identity; +} + +/** + * Returns TRUE if PUBLISH request is enabled for this proxy. +**/ +bool_t linphone_proxy_config_publish_enabled(const LinphoneProxyConfig *obj){ + return obj->publish; +} + +/** + * Returns the proxy's SIP address. +**/ +const char *linphone_proxy_config_get_addr(const LinphoneProxyConfig *obj){ + return obj->reg_proxy; +} + +/** + * Returns the duration of registration. +**/ +int linphone_proxy_config_get_expires(const LinphoneProxyConfig *obj){ + return obj->expires; +} + +/** + * Returns TRUE if registration to the proxy is enabled. +**/ +bool_t linphone_proxy_config_register_enabled(const LinphoneProxyConfig *obj){ + return obj->reg_sendregister; +} + +struct _LinphoneCore * linphone_proxy_config_get_core(const LinphoneProxyConfig *obj){ + return obj->lc; +} /** * Add a proxy configuration. diff --git a/gtk-glade/friendlist.c b/gtk-glade/friendlist.c index 035a1079d..25173488d 100644 --- a/gtk-glade/friendlist.c +++ b/gtk-glade/friendlist.c @@ -39,7 +39,6 @@ typedef struct _status_picture_tab_t{ } status_picture_tab_t; status_picture_tab_t status_picture_tab[]={ - { LINPHONE_STATUS_UNKNOWN, "sip-closed.png" }, { LINPHONE_STATUS_ONLINE, "sip-online.png" }, { LINPHONE_STATUS_BUSY, "sip-busy.png" }, { LINPHONE_STATUS_BERIGHTBACK, "sip-bifm.png" }, @@ -51,7 +50,6 @@ status_picture_tab_t status_picture_tab[]={ { LINPHONE_STATUS_ALT_SERVICE, "sip-closed.png" }, { LINPHONE_STATUS_OFFLINE, "sip-away.png" }, { LINPHONE_STATUS_PENDING, "sip-wfa.png" }, - { LINPHONE_STATUS_CLOSED, "sip-closed.png" }, { LINPHONE_STATUS_END, NULL }, }; @@ -104,7 +102,7 @@ static void linphone_gtk_set_selection_to_uri_bar(GtkTreeView *treeview){ if (gtk_tree_selection_get_selected (select, &model, &iter)) { gtk_tree_model_get (model, &iter,FRIEND_ID , &lf, -1); - friend=linphone_address_as_string(linphone_friend_get_uri(lf)); + friend=linphone_address_as_string(linphone_friend_get_address(lf)); gtk_entry_set_text(GTK_ENTRY(linphone_gtk_get_widget(linphone_gtk_get_main_window(),"uribar")),friend); ms_free(friend); } @@ -134,8 +132,7 @@ static GtkWidget * create_presence_menu(){ GdkPixbuf *pbuf; status_picture_tab_t *t; for(t=status_picture_tab;t->img!=NULL;++t){ - if (t->status==LINPHONE_STATUS_UNKNOWN || - t->status==LINPHONE_STATUS_PENDING){ + if (t->status==LINPHONE_STATUS_PENDING){ continue; } menu_item=gtk_image_menu_item_new_with_label(linphone_online_status_to_string(t->status)); @@ -309,7 +306,7 @@ void linphone_gtk_show_friends(void){ for(itf=linphone_core_get_friend_list(core);itf!=NULL;itf=ms_list_next(itf)){ LinphoneFriend *lf=(LinphoneFriend*)itf->data; - const LinphoneAddress *f_uri=linphone_friend_get_uri(lf); + const LinphoneAddress *f_uri=linphone_friend_get_address(lf); char *uri=linphone_address_as_string(f_uri); const char *name=linphone_address_get_display_name(f_uri); const char *display=name; @@ -376,7 +373,7 @@ void linphone_gtk_show_contact(LinphoneFriend *lf){ GtkWidget *w=linphone_gtk_create_window("contact"); char *uri; const char *name; - const LinphoneAddress *f_uri=linphone_friend_get_uri(lf); + const LinphoneAddress *f_uri=linphone_friend_get_address(lf); uri=linphone_address_as_string_uri_only(f_uri); name=linphone_address_get_display_name(f_uri); if (uri) { @@ -419,7 +416,7 @@ void linphone_gtk_chat_selected(GtkWidget *item){ { char *uri; gtk_tree_model_get (model, &iter,FRIEND_ID , &lf, -1); - uri=linphone_address_as_string(linphone_friend_get_uri(lf)); + uri=linphone_address_as_string(linphone_friend_get_address(lf)); linphone_gtk_create_chatroom(uri); ms_free(uri); } diff --git a/gtk-glade/loginframe.c b/gtk-glade/loginframe.c index d4ed36974..ff49c0b24 100644 --- a/gtk-glade/loginframe.c +++ b/gtk-glade/loginframe.c @@ -60,6 +60,7 @@ void linphone_gtk_show_login_frame(LinphoneProxyConfig *cfg){ LinphoneAddress *from; LinphoneCore *lc=linphone_gtk_get_core(); int nettype; + const char *passwd=NULL; if (linphone_core_get_download_bandwidth(lc)==512 && @@ -91,8 +92,9 @@ void linphone_gtk_show_login_frame(LinphoneProxyConfig *cfg){ if (linphone_address_get_username(from)[0]!='?') gtk_entry_set_text(GTK_ENTRY(linphone_gtk_get_widget(mw,"login_username")), linphone_address_get_username(from)); + if (ai) passwd=linphone_auth_info_get_passwd(ai); gtk_entry_set_text(GTK_ENTRY(linphone_gtk_get_widget(mw,"login_password")), - ai!=NULL ? ai->passwd : ""); + passwd!=NULL ? passwd : ""); linphone_address_destroy(from); } diff --git a/gtk-glade/main.c b/gtk-glade/main.c index 579c3e34a..37628a5d9 100644 --- a/gtk-glade/main.c +++ b/gtk-glade/main.c @@ -42,7 +42,7 @@ static GtkWidget *the_ui=NULL; static void linphone_gtk_show(LinphoneCore *lc); static void linphone_gtk_inv_recv(LinphoneCore *lc, const char *from); static void linphone_gtk_bye_recv(LinphoneCore *lc, const char *from); -static void linphone_gtk_notify_recv(LinphoneCore *lc, LinphoneFriend * fid, const char *url, const char *status, const char *img); +static void linphone_gtk_notify_recv(LinphoneCore *lc, LinphoneFriend * fid); static void linphone_gtk_new_unknown_subscriber(LinphoneCore *lc, LinphoneFriend *lf, const char *url); static void linphone_gtk_auth_info_requested(LinphoneCore *lc, const char *realm, const char *username); static void linphone_gtk_display_status(LinphoneCore *lc, const char *status); @@ -711,7 +711,7 @@ static void linphone_gtk_bye_recv(LinphoneCore *lc, const char *from){ } -static void linphone_gtk_notify_recv(LinphoneCore *lc, LinphoneFriend * fid, const char *url, const char *status, const char *img){ +static void linphone_gtk_notify_recv(LinphoneCore *lc, LinphoneFriend * fid){ } static void linphone_gtk_new_subscriber_response(GtkWidget *dialog, guint response_id, LinphoneFriend *lf){ diff --git a/oRTP b/oRTP index da176d2f4..36773054c 160000 --- a/oRTP +++ b/oRTP @@ -1 +1 @@ -Subproject commit da176d2f439f990012a1bf47b39fb72070dbd580 +Subproject commit 36773054c1e9a47029432a2e8540161dad426293 From e487df8d7dd2684f5cc6a70bcac9158d1ac2334b Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Mon, 8 Feb 2010 13:49:52 +0100 Subject: [PATCH 18/50] register works. --- coreapi/callbacks.c | 1 + coreapi/linphonecore.c | 15 ++++++------- coreapi/proxy.c | 1 + coreapi/sal_eXosip2.c | 48 +++++++++++++++++++++--------------------- 4 files changed, 33 insertions(+), 32 deletions(-) diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index a95f3570d..5b5bcad86 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -343,6 +343,7 @@ static void register_success(SalOp *op, bool_t registered){ LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)sal_op_get_user_pointer(op); char *msg; gstate_new_state(lc, GSTATE_REG_OK, NULL); + cfg->registered=registered; if (cfg->registered) msg=ms_strdup_printf(_("Registration on %s successful."),sal_op_get_proxy(op)); else msg=ms_strdup_printf(_("Unregistration on %s done."),sal_op_get_proxy(op)); if (lc->vtable.display_status) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index cf16e8da3..9dd4cd9ce 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -49,6 +49,8 @@ static void toggle_video_preview(LinphoneCore *lc, bool_t val); /* same for remote ring (ringback)*/ #define REMOTE_RING "ringback.wav" +extern SalCallbacks linphone_sal_callbacks; + void lc_callback_obj_init(LCCallbackObj *obj,LinphoneCoreCbFunc func,void* ud) { obj->_func=func; @@ -704,6 +706,7 @@ static MSList *add_missing_codecs(SalStreamType mtype, MSList *l){ } if (pt && ms_filter_codec_supported(pt->mime_type)){ if (ms_list_find(l,pt)==NULL){ + payload_type_set_flag(pt,PAYLOAD_TYPE_ENABLED); ms_message("Adding new codec %s/%i with fmtp %s", pt->mime_type,pt->clock_rate,pt->recv_fmtp ? pt->recv_fmtp : ""); if (strcasecmp(pt->mime_type,"speex")==0 || @@ -957,13 +960,9 @@ static void linphone_core_init (LinphoneCore * lc, const LinphoneCoreVTable *vta if (factory_config_path) lp_config_read_file(lc->config,factory_config_path); -#ifdef VINCENT_MAURY_RSVP - /* default qos parameters : rsvp on, rpc off */ - lc->rsvp_enable = 1; - lc->rpc_enable = 0; -#endif lc->sal=sal_init(); sal_set_user_pointer(lc->sal,lc); + sal_set_callbacks(lc->sal,&linphone_sal_callbacks); if (lp_config_get_int(lc->config,"sip","use_session_timers",0)==1){ sal_use_session_timers(lc->sal,200); } @@ -1046,9 +1045,8 @@ int linphone_core_set_primary_contact(LinphoneCore *lc, const char *contact) { LinphoneAddress *ctt; - if ((ctt=linphone_address_new(contact))!=0) { + if ((ctt=linphone_address_new(contact))==0) { ms_error("Bad contact url: %s",contact); - linphone_address_destroy(ctt); return -1; } if (lc->sip_conf.contact!=NULL) ms_free(lc->sip_conf.contact); @@ -1098,8 +1096,9 @@ const char *linphone_core_get_primary_contact(LinphoneCore *lc){ } url=linphone_address_new(lc->sip_conf.contact); if (!url){ + ms_error("Could not parse identity contact !"); url=linphone_address_new("sip:unknown@unkwownhost"); - }else ms_error("Could not parse identity contact !"); + } linphone_core_get_local_ip(lc, NULL, tmp); if (strcmp(tmp,"127.0.0.1")==0 || strcmp(tmp,"::1")==0 ){ ms_warning("Local loopback network only !"); diff --git a/coreapi/proxy.c b/coreapi/proxy.c index a033d1116..01b96bd78 100644 --- a/coreapi/proxy.c +++ b/coreapi/proxy.c @@ -227,6 +227,7 @@ static void linphone_proxy_config_register(LinphoneProxyConfig *obj){ if (obj->op) sal_op_release(obj->op); obj->op=sal_op_new(obj->lc->sal); + sal_op_set_user_pointer(obj->op,obj); sal_register(obj->op,obj->reg_proxy,obj->reg_identity,obj->expires); } } diff --git a/coreapi/sal_eXosip2.c b/coreapi/sal_eXosip2.c index e76f2c248..ad8e5c191 100644 --- a/coreapi/sal_eXosip2.c +++ b/coreapi/sal_eXosip2.c @@ -91,7 +91,7 @@ void sal_exosip_fix_route(SalOp *op){ SalOp * sal_op_new(Sal *sal){ SalOp *op=ms_new(SalOp,1); __sal_op_init(op,sal); - op->cid=op->did=op->tid=op->rid=op->nid=op->sid-1; + op->cid=op->did=op->tid=op->rid=op->nid=op->sid=-1; op->supports_session_timers=FALSE; op->sdp_offering=TRUE; op->pending_auth=NULL; @@ -674,10 +674,19 @@ int sal_op_get_auth_requested(SalOp *op, const char **realm, const char **userna return -1; } +static SalOp *find_op(Sal *sal, eXosip_event_t *ev){ + if (ev->external_reference) + return (SalOp*)ev->external_reference; + if (ev->rid>0){ + return sal_find_register(sal,ev->rid); + } + return NULL; +} + static bool_t process_authentication(Sal *sal, eXosip_event_t *ev){ SalOp *op; const char *username,*realm; - op=(SalOp*)ev->external_reference; + op=find_op(sal,ev); if (op==NULL){ ms_warning("No operation associated with this authentication !"); return TRUE; @@ -696,7 +705,7 @@ static bool_t process_authentication(Sal *sal, eXosip_event_t *ev){ static void authentication_ok(Sal *sal, eXosip_event_t *ev){ SalOp *op; const char *username,*realm; - op=(SalOp*)ev->external_reference; + op=find_op(sal,ev); if (op==NULL){ ms_warning("No operation associated with this authentication_ok!"); return ; @@ -945,22 +954,14 @@ static void other_request(Sal *sal, eXosip_event_t *ev){ } } -static void update_contact(SalOp *op, const char *received, const char *rport){ - SalAddress *addr=sal_address_new(sal_op_get_contact(op)); - char *tmp; - sal_address_set_domain(addr,received); - sal_address_set_port(addr,rport); - tmp=sal_address_as_string(addr); - sal_op_set_contact(op,tmp); - ms_free(tmp); -} - static bool_t register_again_with_updated_contact(SalOp *op, osip_message_t *orig_request, osip_message_t *last_answer){ osip_message_t *msg; const char *rport,*received; osip_via_t *via=NULL; osip_generic_param_t *param=NULL; osip_contact_t *ctt=NULL; + char *tmp; + osip_message_get_via(last_answer,0,&via); if (!via) return FALSE; osip_via_param_get_byname(via,"rport",¶m); @@ -1003,8 +1004,10 @@ static bool_t register_again_with_updated_contact(SalOp *op, osip_message_t *ori ctt->url->port=osip_strdup(rport); eXosip_register_send_register(op->rid,msg); eXosip_unlock(); - update_contact(op,received,rport); - ms_message("Resending new register with updated contact %s:%s",received,rport); + osip_contact_to_str(ctt,&tmp); + sal_op_set_contact(op,tmp); + ms_message("Resending new register with updated contact %s",tmp); + ms_free(tmp); return TRUE; } @@ -1165,22 +1168,19 @@ static bool_t process_event(Sal *sal, eXosip_event_t *ev){ int sal_iterate(Sal *sal){ eXosip_event_t *ev; - if (sal->running){ - while((ev=eXosip_event_wait(0,0))!=NULL){ - if (process_event(sal,ev)) - eXosip_event_free(ev); - } - eXosip_lock(); - eXosip_automatic_refresh(); - eXosip_unlock(); + while((ev=eXosip_event_wait(0,0))!=NULL){ + if (process_event(sal,ev)) + eXosip_event_free(ev); } + eXosip_lock(); + eXosip_automatic_refresh(); + eXosip_unlock(); return 0; } int sal_register(SalOp *h, const char *proxy, const char *from, int expires){ osip_message_t *msg; sal_op_set_route(h,proxy); - sal_exosip_fix_route(h); if (h->rid==-1){ eXosip_lock(); h->rid=eXosip_register_build_initial_register(from,proxy,sal_op_get_contact(h),expires,&msg); From 8a03d2340acdb455970cf3123998104c600953fb Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Mon, 8 Feb 2010 14:56:23 +0100 Subject: [PATCH 19/50] fix bandwidths --- coreapi/sal_eXosip2_sdp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/coreapi/sal_eXosip2_sdp.c b/coreapi/sal_eXosip2_sdp.c index d517a7222..1189477d6 100644 --- a/coreapi/sal_eXosip2_sdp.c +++ b/coreapi/sal_eXosip2_sdp.c @@ -177,7 +177,7 @@ static void add_line(sdp_message_t *msg, int lineno, const SalStreamDescription sdp_message_m_media_add (msg, osip_strdup (mt), int_2char (port), NULL, osip_strdup ("RTP/AVP")); - sdp_message_b_bandwidth_add (msg, lineno, osip_strdup ("AS"), + if (desc->bandwidth>0) sdp_message_b_bandwidth_add (msg, lineno, osip_strdup ("AS"), int_2char(desc->bandwidth)); for(elem=desc->payloads;elem!=NULL;elem=elem->next){ add_payload(msg, lineno, (PayloadType*)elem->data); From 0015964665d0b3865abd48c6e41e592babf3ce55 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Fri, 12 Feb 2010 10:48:11 +0100 Subject: [PATCH 20/50] fix memory leaks, debug SDP nego --- coreapi/callbacks.c | 44 +++++++++++++++--------- coreapi/linphonecore.c | 71 +++++++++++++++++++++++++++++---------- coreapi/offeranswer.c | 49 +++++++++++++++++++-------- coreapi/private.h | 1 + coreapi/sal.c | 5 +-- coreapi/sal.h | 2 +- coreapi/sal_eXosip2.c | 19 ++++++++--- coreapi/sal_eXosip2_sdp.c | 7 ++++ mediastreamer2 | 2 +- 9 files changed, 145 insertions(+), 55 deletions(-) diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index 5b5bcad86..f6c5f034a 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -77,6 +77,8 @@ static void call_received(SalOp *h){ lc->call=call; sal_call_set_local_media_description(h,call->localdesc); call->resultdesc=sal_call_get_final_media_description(h); + if (call->resultdesc) + sal_media_description_ref(call->resultdesc); if (call->resultdesc && sal_media_description_empty(call->resultdesc)){ sal_call_decline(h,SalReasonMedia,NULL); linphone_call_destroy(call); @@ -101,7 +103,7 @@ static void call_received(SalOp *h){ } linphone_call_set_state(call,LCStateRinging); sal_call_notify_ringing(h); - + linphone_core_init_media_streams(lc,lc->call); if (lc->vtable.inv_recv) lc->vtable.inv_recv(lc,tmp); ms_free(barmesg); ms_free(tmp); @@ -140,6 +142,7 @@ static void call_ringing(SalOp *h){ } ms_message("Doing early media..."); linphone_core_start_media_streams(lc,call); + call->media_pending=TRUE; } call->state=LCStateRinging; } @@ -166,6 +169,10 @@ static void call_accepted(SalOp *op){ if (call->resultdesc) sal_media_description_unref(call->resultdesc); call->resultdesc=sal_call_get_final_media_description(op); + if (call->resultdesc){ + sal_media_description_ref(call->resultdesc); + call->media_pending=FALSE; + } if (call->resultdesc && !sal_media_description_empty(call->resultdesc)){ gstate_new_state(lc, GSTATE_CALL_OUT_CONNECTED, NULL); linphone_connect_incoming(lc,call); @@ -187,21 +194,26 @@ static void call_ack(SalOp *op){ ms_warning("call_ack: ignoring."); return; } - if (lc->audiostream->ticker!=NULL){ - /*case where we accepted early media */ - linphone_core_stop_media_streams(lc,call); - linphone_core_init_media_streams(lc,call); - } - if (call->resultdesc) - sal_media_description_unref(call->resultdesc); - call->resultdesc=sal_call_get_final_media_description(op); - if (call->resultdesc && !sal_media_description_empty(call->resultdesc)){ - gstate_new_state(lc, GSTATE_CALL_IN_CONNECTED, NULL); - linphone_connect_incoming(lc,call); - }else{ - /*send a bye*/ - ms_error("Incompatible SDP response received in ACK, need to abort the call"); - linphone_core_terminate_call(lc,NULL); + if (call->media_pending){ + if (lc->audiostream->ticker!=NULL){ + /*case where we accepted early media */ + linphone_core_stop_media_streams(lc,call); + linphone_core_init_media_streams(lc,call); + } + if (call->resultdesc) + sal_media_description_unref(call->resultdesc); + call->resultdesc=sal_call_get_final_media_description(op); + if (call->resultdesc) + sal_media_description_ref(call->resultdesc); + if (call->resultdesc && !sal_media_description_empty(call->resultdesc)){ + gstate_new_state(lc, GSTATE_CALL_IN_CONNECTED, NULL); + linphone_connect_incoming(lc,call); + }else{ + /*send a bye*/ + ms_error("Incompatible SDP response received in ACK, need to abort the call"); + linphone_core_terminate_call(lc,NULL); + } + call->media_pending=FALSE; } } diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 9dd4cd9ce..6ccac20b5 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -137,7 +137,7 @@ LinphoneCall * linphone_call_new_outgoing(struct _LinphoneCore *lc, LinphoneAddr LinphoneCall *call=ms_new0(LinphoneCall,1); call->dir=LinphoneCallOutgoing; call->op=sal_op_new(lc->sal); - sal_op_set_user_pointer(call->op,lc->call); + sal_op_set_user_pointer(call->op,call); call->core=lc; linphone_core_get_local_ip(lc,linphone_address_get_domain(to),call->localip); call->localdesc=create_local_media_description (lc,call->localip, @@ -693,6 +693,37 @@ static bool_t get_codec(LpConfig *config, char* type, int index, PayloadType **r return TRUE; } +static const char *codec_pref_order[]={ + "speex", + "gsm", + "pcmu", + "pcma", + "H264", + "MP4V-ES", + "theora", + "H263-1998", + "H263", + NULL, +}; + +static int find_codec_rank(const char *mime){ + int i; + for(i=0;codec_pref_order[i]!=NULL;++i){ + if (strcasecmp(codec_pref_order[i],mime)==0) + break; + } + return i; +} + +static int codec_compare(const PayloadType *a, const PayloadType *b){ + int ra,rb; + ra=find_codec_rank(a->mime_type); + rb=find_codec_rank(b->mime_type); + if (ra==rb) return 0; + if (ra>rb) return 1; + if (ramime_type,pt->clock_rate,pt->recv_fmtp ? pt->recv_fmtp : ""); - if (strcasecmp(pt->mime_type,"speex")==0 || - strcasecmp(pt->mime_type,"MP4V-ES")==0 || - strcasecmp(pt->mime_type,"H264")==0) - l=ms_list_prepend(l,pt); - else l=ms_list_append(l,pt); + l=ms_list_insert_sorted(l,pt,(int (*)(const void *, const void *))codec_compare); } } } @@ -1733,7 +1760,7 @@ int linphone_core_invite(LinphoneCore *lc, const char *url) int err=0; char *route=NULL; const char *from=NULL; - const char *contact=NULL; + char *contact=NULL; LinphoneProxyConfig *proxy=NULL; LinphoneAddress *parsed_url2=NULL; LinphoneAddress *real_parsed_url=NULL; @@ -1775,13 +1802,16 @@ int linphone_core_invite(LinphoneCore *lc, const char *url) except when the user choosed to override the ipaddress */ if (linphone_core_get_firewall_policy(lc)!=LINPHONE_POLICY_USE_NAT_ADDRESS) contact=get_fixed_contact(lc,call->localip,dest_proxy); - if (contact) + if (contact){ sal_op_set_contact(call->op, contact); + ms_free(contact); + } lc->call=call; linphone_core_init_media_streams(lc,lc->call); if (!lc->sip_conf.sdp_200_ack){ + call->media_pending=TRUE; sal_call_set_local_media_description(call->op,call->localdesc); } err=sal_call(call->op,from,real_url); @@ -1798,10 +1828,8 @@ int linphone_core_invite(LinphoneCore *lc, const char *url) lc->call=NULL; }else gstate_new_state(lc, GSTATE_CALL_OUT_INVITE, url); - goto end; - end: - if (real_url!=NULL) ms_free(real_url); - if (route!=NULL) ms_free(route); + if (real_url!=NULL) ms_free(real_url); + if (route!=NULL) ms_free(route); return (err<0) ? -1 : 0; } @@ -1947,9 +1975,9 @@ static void post_configure_audio_streams(LinphoneCore *lc){ } } -static RtpProfile *make_profile(LinphoneCore *lc, SalStreamDescription *desc, int *used_pt){ +static RtpProfile *make_profile(LinphoneCore *lc, const SalStreamDescription *desc, int *used_pt){ int bw; - MSList *elem; + const MSList *elem; RtpProfile *prof=rtp_profile_new("Call profile"); bool_t first=TRUE; if (desc->type==SalAudio){ @@ -1988,7 +2016,7 @@ void linphone_core_start_media_streams(LinphoneCore *lc, LinphoneCall *call){ cname=linphone_address_as_string_uri_only(me); { - SalStreamDescription *stream=sal_media_description_find_stream(call->resultdesc, + const SalStreamDescription *stream=sal_media_description_find_stream(call->resultdesc, SalProtoRtpAvp,SalAudio); if (stream){ call->audio_profile=make_profile(lc,stream,&used_pt); @@ -2032,7 +2060,7 @@ void linphone_core_start_media_streams(LinphoneCore *lc, LinphoneCall *call){ } #ifdef VIDEO_ENABLED { - SalStreamDescription *stream=sal_media_description_find_stream(call->resultdesc, + const SalStreamDescription *stream=sal_media_description_find_stream(call->resultdesc, SalProtoRtpAvp,SalVideo); /* shutdown preview */ if (lc->previewstream!=NULL) { @@ -2091,10 +2119,12 @@ void linphone_core_stop_media_streams(LinphoneCore *lc, LinphoneCall *call){ } #endif if (call->audio_profile){ + rtp_profile_clear_all(call->audio_profile); rtp_profile_destroy(call->audio_profile); call->audio_profile=NULL; } if (call->video_profile){ + rtp_profile_clear_all(call->video_profile); rtp_profile_destroy(call->video_profile); call->video_profile=NULL; } @@ -2150,7 +2180,7 @@ int linphone_core_accept_call(LinphoneCore *lc, const char *url) if (call->resultdesc){ sal_media_description_ref(call->resultdesc); linphone_core_start_media_streams(lc, call); - } + }else call->media_pending=TRUE; ms_message("call answered."); return 0; } @@ -3160,6 +3190,10 @@ void sip_config_uninit(LinphoneCore *lc) } } + ms_list_for_each(config->proxies,(void (*)(void*)) linphone_proxy_config_destroy); + ms_list_free(config->proxies); + config->proxies=NULL; + linphone_proxy_config_write_to_config_file(lc->config,NULL,i); /*mark the end */ for(elem=lc->auth_info,i=0;elem!=NULL;elem=ms_list_next(elem),i++){ @@ -3167,6 +3201,9 @@ void sip_config_uninit(LinphoneCore *lc) linphone_auth_info_write_config(lc->config,ai,i); } linphone_auth_info_write_config(lc->config,NULL,i); /* mark the end */ + ms_list_for_each(lc->auth_info,(void (*)(void*))linphone_auth_info_destroy); + ms_list_free(lc->auth_info); + lc->auth_info=NULL; sal_uninit(lc->sal); lc->sal=NULL; } diff --git a/coreapi/offeranswer.c b/coreapi/offeranswer.c index 3e872c6e1..f4b914381 100644 --- a/coreapi/offeranswer.c +++ b/coreapi/offeranswer.c @@ -71,11 +71,9 @@ static MSList *match_payloads(const MSList *local, const MSList *remote){ } static bool_t only_telephone_event(const MSList *l){ - for(;l!=NULL;l=l->next){ - PayloadType *p=(PayloadType*)l->data; - if (strcasecmp(p->mime_type,"telephone-event")!=0){ - return FALSE; - } + PayloadType *p=(PayloadType*)l->data; + if (strcasecmp(p->mime_type,"telephone-event")!=0){ + return FALSE; } return TRUE; } @@ -83,11 +81,15 @@ static bool_t only_telephone_event(const MSList *l){ static void initiate_outgoing(const SalStreamDescription *local_offer, const SalStreamDescription *remote_answer, SalStreamDescription *result){ - result->payloads=match_payloads(local_offer->payloads,remote_answer->payloads); + if (remote_answer->port!=0) + result->payloads=match_payloads(local_offer->payloads,remote_answer->payloads); if (result->payloads && !only_telephone_event(result->payloads)){ + strcpy(result->addr,remote_answer->addr); result->port=remote_answer->port; result->bandwidth=remote_answer->bandwidth; result->ptime=remote_answer->ptime; + result->proto=local_offer->proto; + result->type=local_offer->type; }else{ result->port=0; } @@ -99,9 +101,12 @@ static void initiate_incoming(const SalStreamDescription *local_cap, SalStreamDescription *result){ result->payloads=match_payloads(local_cap->payloads,remote_offer->payloads); if (result->payloads && !only_telephone_event(result->payloads)){ + strcpy(result->addr,local_cap->addr); result->port=local_cap->port; result->bandwidth=local_cap->bandwidth; result->ptime=local_cap->ptime; + result->proto=local_cap->proto; + result->type=local_cap->type; }else{ result->port=0; } @@ -114,11 +119,19 @@ static void initiate_incoming(const SalStreamDescription *local_cap, int offer_answer_initiate_outgoing(const SalMediaDescription *local_offer, const SalMediaDescription *remote_answer, SalMediaDescription *result){ - int i; - for(i=0;instreams;++i){ - initiate_outgoing(&local_offer->streams[i],&remote_answer->streams[i],&result->streams[i]); + int i,j; + const SalStreamDescription *ls,*rs; + for(i=0,j=0;instreams;++i){ + ms_message("Processing for stream %i",i); + ls=&local_offer->streams[i]; + rs=sal_media_description_find_stream(remote_answer,ls->proto,ls->type); + if (rs) { + initiate_outgoing(ls,rs,&result->streams[j]); + ++j; + } + else ms_warning("No matching stream for %i",i); } - result->nstreams=local_offer->nstreams; + result->nstreams=j; strcpy(result->addr,remote_answer->addr); return 0; } @@ -131,11 +144,19 @@ int offer_answer_initiate_outgoing(const SalMediaDescription *local_offer, int offer_answer_initiate_incoming(const SalMediaDescription *local_capabilities, const SalMediaDescription *remote_offer, SalMediaDescription *result){ - int i; - for(i=0;instreams;++i){ - initiate_incoming(&local_capabilities->streams[i],&remote_offer->streams[i],&result->streams[i]); + int i,j; + const SalStreamDescription *ls,*rs; + + for(i=0,j=0;instreams;++i){ + rs=&remote_offer->streams[i]; + ms_message("Processing for stream %i",i); + ls=sal_media_description_find_stream(local_capabilities,rs->proto,rs->type); + if (ls){ + initiate_incoming(ls,rs,&result->streams[j]); + ++j; + } } - result->nstreams=local_capabilities->nstreams; + result->nstreams=j; strcpy(result->addr,local_capabilities->addr); return 0; } diff --git a/coreapi/private.h b/coreapi/private.h index abea80b82..bcd914439 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -75,6 +75,7 @@ typedef struct _LinphoneCall time_t start_time; /*time at which the call was initiated*/ time_t media_start_time; /*time at which it was accepted, media streams established*/ LCState state; + bool_t media_pending; } LinphoneCall; LinphoneCall * linphone_call_new_outgoing(struct _LinphoneCore *lc, LinphoneAddress *from, LinphoneAddress *to); diff --git a/coreapi/sal.c b/coreapi/sal.c index d33124e8a..ae432d565 100644 --- a/coreapi/sal.c +++ b/coreapi/sal.c @@ -36,6 +36,7 @@ static void sal_media_description_destroy(SalMediaDescription *md){ for(i=0;istreams[i].payloads,(void (*)(void *))payload_type_destroy); ms_list_free(md->streams[i].payloads); + md->streams[i].payloads=NULL; } ms_free(md); } @@ -51,11 +52,11 @@ void sal_media_description_unref(SalMediaDescription *md){ } } -SalStreamDescription *sal_media_description_find_stream(SalMediaDescription *md, +const SalStreamDescription *sal_media_description_find_stream(const SalMediaDescription *md, SalMediaProto proto, SalStreamType type){ int i; for(i=0;instreams;++i){ - SalStreamDescription *ss=&md->streams[i]; + const SalStreamDescription *ss=&md->streams[i]; if (ss->proto==proto && ss->type==type) return ss; } return NULL; diff --git a/coreapi/sal.h b/coreapi/sal.h index 5dc91efd7..eb8042361 100644 --- a/coreapi/sal.h +++ b/coreapi/sal.h @@ -114,7 +114,7 @@ SalMediaDescription *sal_media_description_new(); void sal_media_description_ref(SalMediaDescription *md); void sal_media_description_unref(SalMediaDescription *md); bool_t sal_media_description_empty(SalMediaDescription *md); -SalStreamDescription *sal_media_description_find_stream(SalMediaDescription *md, +const SalStreamDescription *sal_media_description_find_stream(const SalMediaDescription *md, SalMediaProto proto, SalStreamType type); /*this structure must be at the first byte of the SalOp structure defined by implementors*/ diff --git a/coreapi/sal_eXosip2.c b/coreapi/sal_eXosip2.c index ad8e5c191..d3a6d224b 100644 --- a/coreapi/sal_eXosip2.c +++ b/coreapi/sal_eXosip2.c @@ -92,6 +92,7 @@ SalOp * sal_op_new(Sal *sal){ SalOp *op=ms_new(SalOp,1); __sal_op_init(op,sal); op->cid=op->did=op->tid=op->rid=op->nid=op->sid=-1; + op->result=NULL; op->supports_session_timers=FALSE; op->sdp_offering=TRUE; op->pending_auth=NULL; @@ -109,11 +110,14 @@ void sal_op_release(SalOp *op){ sal_remove_register(op->base.root,op->rid); } if (op->cid!=-1){ + ms_message("Cleaning cid %i",op->cid); eXosip_call_set_reference(op->cid,NULL); } if (op->pending_auth){ sal_remove_pending_auth(op->base.root,op); } + if (op->result) + sal_media_description_unref(op->result); __sal_op_free(op); } @@ -280,6 +284,7 @@ static void set_sdp_from_desc(osip_message_t *sip, const SalMediaDescription *de } static void sdp_process(SalOp *h){ + ms_message("Doing SDP offer/answer process"); if (h->result){ sal_media_description_unref(h->result); } @@ -323,8 +328,10 @@ int sal_call(SalOp *h, const char *from, const char *to){ ms_error("Could not create call."); return -1; } - if (h->base.contact) + if (h->base.contact){ + osip_list_special_free(&invite->contacts,(void (*)(void*))osip_contact_free); osip_message_set_contact(invite,h->base.contact); + } if (h->base.root->session_expires!=0){ osip_message_set_header(invite, "Session-expires", "200"); osip_message_set_supported(invite, "timer"); @@ -472,6 +479,7 @@ void sal_op_authenticate(SalOp *h, const SalAuthInfo *info){ eXosip_unlock(); eXosip_clear_authentication_info(); eXosip_event_free(h->pending_auth); + sal_remove_pending_auth(sal_op_get_sal(h),h); h->pending_auth=NULL; } } @@ -482,6 +490,7 @@ static void inc_new_call(Sal *sal, eXosip_event_t *ev){ char *tmp; sdp_message_t *sdp=eXosip_get_sdp_info(ev->request); if (sdp){ + op->sdp_offering=FALSE; op->base.remote_media=sal_media_description_new(); sdp_to_media_description(sdp,op->base.remote_media); sdp_message_free(sdp); @@ -635,12 +644,14 @@ static void call_terminated(Sal *sal, eXosip_event_t *ev){ static void call_released(Sal *sal, eXosip_event_t *ev){ SalOp *op; + char *from; op=(SalOp*)ev->external_reference; if (op==NULL){ return; } - eXosip_call_set_reference(ev->cid,NULL); - /*sal->callbacks.call_terminated(op);*/ + op->cid=-1; + if (op->did==-1) + sal->callbacks.call_failure(op,SalErrorNoResponse,SalReasonUnknown,NULL); } static int get_auth_data(eXosip_event_t *ev, const char **realm, const char **username){ @@ -1160,7 +1171,7 @@ static bool_t process_event(Sal *sal, eXosip_event_t *ev){ } break; default: - ms_message("Unhandled exosip event !"); + ms_message("Unhandled exosip event ! %i"); break; } return TRUE; diff --git a/coreapi/sal_eXosip2_sdp.c b/coreapi/sal_eXosip2_sdp.c index 1189477d6..3dfde45d3 100644 --- a/coreapi/sal_eXosip2_sdp.c +++ b/coreapi/sal_eXosip2_sdp.c @@ -252,6 +252,9 @@ int sdp_to_media_description(sdp_message_t *msg, SalMediaDescription *desc){ addr = sdp_message_c_addr_get (msg, i, 0); if (addr != NULL) strncpy(stream->addr,addr,sizeof(stream->addr)); + if (port) + stream->port=atoi(port); + stream->ptime=_sdp_message_get_a_ptime(msg,i); if (strcasecmp("audio", mtype) == 0){ stream->type=SalAudio; @@ -273,7 +276,11 @@ int sdp_to_media_description(sdp_message_t *msg, SalMediaDescription *desc){ /* get the fmtp, if any */ fmtp=sdp_message_a_attr_value_get_with_pt(msg, i, ptn,"fmtp"); payload_type_set_send_fmtp(pt,fmtp); + stream->payloads=ms_list_append(stream->payloads,pt); + ms_message("Found payload %s/%i fmtp=%s",pt->mime_type,pt->clock_rate, + pt->send_fmtp ? pt->send_fmtp : ""); } } + desc->nstreams=i; return 0; } diff --git a/mediastreamer2 b/mediastreamer2 index 8dae09b11..ae7dfdcae 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 8dae09b11ee8a0fe29674944b207b5e06fb0f4ed +Subproject commit ae7dfdcaea6d5fe6d4f44a6247b4ca506799e379 From 9c814fc357e5226220e586f0d42812876e89d40d Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Wed, 3 Mar 2010 11:38:13 +0100 Subject: [PATCH 21/50] fix bug in sdp offeranswer and malformed SDP. --- coreapi/linphonecore.c | 4 ++-- coreapi/offeranswer.c | 11 ++++++----- coreapi/sal_eXosip2.c | 10 ++++++++-- coreapi/sal_eXosip2_sdp.c | 2 +- mediastreamer2 | 2 +- oRTP | 2 +- 6 files changed, 19 insertions(+), 12 deletions(-) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 268e8f40f..58dde3adc 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -719,9 +719,9 @@ static int codec_compare(const PayloadType *a, const PayloadType *b){ int ra,rb; ra=find_codec_rank(a->mime_type); rb=find_codec_rank(b->mime_type); - if (ra==rb) return 0; if (ra>rb) return 1; if (raport!=0) result->payloads=match_payloads(local_offer->payloads,remote_answer->payloads); + result->proto=local_offer->proto; + result->type=local_offer->type; if (result->payloads && !only_telephone_event(result->payloads)){ strcpy(result->addr,remote_answer->addr); result->port=remote_answer->port; result->bandwidth=remote_answer->bandwidth; result->ptime=remote_answer->ptime; - result->proto=local_offer->proto; - result->type=local_offer->type; }else{ result->port=0; } @@ -100,13 +100,13 @@ static void initiate_incoming(const SalStreamDescription *local_cap, const SalStreamDescription *remote_offer, SalStreamDescription *result){ result->payloads=match_payloads(local_cap->payloads,remote_offer->payloads); + result->proto=local_cap->proto; + result->type=local_cap->type; if (result->payloads && !only_telephone_event(result->payloads)){ strcpy(result->addr,local_cap->addr); result->port=local_cap->port; result->bandwidth=local_cap->bandwidth; - result->ptime=local_cap->ptime; - result->proto=local_cap->proto; - result->type=local_cap->type; + result->ptime=local_cap->ptime; }else{ result->port=0; } @@ -157,6 +157,7 @@ int offer_answer_initiate_incoming(const SalMediaDescription *local_capabilities } } result->nstreams=j; + strcpy(result->username, local_capabilities->username); strcpy(result->addr,local_capabilities->addr); return 0; } diff --git a/coreapi/sal_eXosip2.c b/coreapi/sal_eXosip2.c index d3a6d224b..c4f00dac6 100644 --- a/coreapi/sal_eXosip2.c +++ b/coreapi/sal_eXosip2.c @@ -373,7 +373,10 @@ int sal_call_accept(SalOp * h){ if (h->supports_session_timers) osip_message_set_supported(msg, "timer"); } - if (contact) osip_message_set_contact(msg,contact); + if (contact) { + osip_list_special_free(&msg->contacts,(void (*)(void*))osip_contact_free); + osip_message_set_contact(msg,contact); + } if (h->base.local_media){ /*this is the case where we received an invite without SDP*/ @@ -536,6 +539,10 @@ static void handle_reinvite(Sal *sal, eXosip_event_t *ev){ if (op->base.root->session_expires!=0){ if (op->supports_session_timers) osip_message_set_supported(msg, "timer"); } + if (op->base.contact){ + osip_list_special_free(&msg->contacts,(void (*)(void*))osip_contact_free); + osip_message_set_contact(msg,op->base.contact); + } if (sdp){ op->sdp_offering=FALSE; op->base.remote_media=sal_media_description_new(); @@ -644,7 +651,6 @@ static void call_terminated(Sal *sal, eXosip_event_t *ev){ static void call_released(Sal *sal, eXosip_event_t *ev){ SalOp *op; - char *from; op=(SalOp*)ev->external_reference; if (op==NULL){ return; diff --git a/coreapi/sal_eXosip2_sdp.c b/coreapi/sal_eXosip2_sdp.c index 3dfde45d3..c1a1761cc 100644 --- a/coreapi/sal_eXosip2_sdp.c +++ b/coreapi/sal_eXosip2_sdp.c @@ -134,7 +134,7 @@ static void add_payload(sdp_message_t *msg, int line, const PayloadType *pt) { char attr[256]; sdp_message_m_payload_add (msg,line, int_2char (payload_type_get_number(pt))); - if (pt->type==PAYLOAD_AUDIO_CONTINUOUS || pt->type==PAYLOAD_AUDIO_PACKETIZED) + if (pt->channels>0) snprintf (attr,sizeof(attr),"%i %s/%i/%i", payload_type_get_number(pt), pt->mime_type, pt->clock_rate,pt->channels); else diff --git a/mediastreamer2 b/mediastreamer2 index ae7dfdcae..2e18cdfe5 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit ae7dfdcaea6d5fe6d4f44a6247b4ca506799e379 +Subproject commit 2e18cdfe53230763907f3f9b55adeb4c16d396a7 diff --git a/oRTP b/oRTP index 36773054c..0424a6538 160000 --- a/oRTP +++ b/oRTP @@ -1 +1 @@ -Subproject commit 36773054c1e9a47029432a2e8540161dad426293 +Subproject commit 0424a6538e1741e064c8d8573efee365b25593f1 From 8cdfef88fd0a554d6538ff24ba1a722dbea814af Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Fri, 5 Mar 2010 15:20:56 +0100 Subject: [PATCH 22/50] fix authentication that wasn't marked as "working". --- NEWS | 9 +++++++++ coreapi/callbacks.c | 6 +++++- coreapi/linphonecore.c | 12 +++++++++++- coreapi/sal_eXosip2.c | 29 +++++++++++++++++++++++++++-- gtk-glade/main.c | 3 ++- 5 files changed, 54 insertions(+), 5 deletions(-) diff --git a/NEWS b/NEWS index 6e15b91ef..ceab2b179 100644 --- a/NEWS +++ b/NEWS @@ -1,9 +1,18 @@ +linphone-3.3.0 -- ????????? + * liblinphone is ported to iphoneOS and Google Android + * Internal refactoring of liblinphone (code factorisation, encapsulation + of signaling) + * enhancements made to presence support (SIP/SIMPLE) + linphone-3.2.2 -- ????????? * improve bitrate usage of speex codec * allow speex to run with vbr (variable bit rate) mode * add speex/32000 (ultra wide band speex codec) * answer empty SIP INFO requests * reverse order of call logs + * optimize video display + * manual or automatic network connectivity management (so that REGISTERs + are only sent when network is up or refreshed when it comes back) linphone-3.2.1 -- October 5, 2009 * improve graphics and behaviour of mute button diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index cb0c7b48e..edce2c4e3 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -329,12 +329,14 @@ static void call_failure(SalOp *op, SalError error, SalReason sr, const char *de static void auth_requested(SalOp *h, const char *realm, const char *username){ LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(h)); LinphoneAuthInfo *ai=(LinphoneAuthInfo*)linphone_core_find_auth_info(lc,realm,username); + ms_message("auth_requested() for realm=%s, username=%s",realm,username); if (ai && (ai->works || ai->usecount<3)){ SalAuthInfo sai; sai.username=ai->username; sai.userid=ai->userid; sai.realm=ai->realm; sai.password=ai->passwd; + ms_message("auth_requested(): authenticating realm=%s, username=%s",realm,username); sal_op_authenticate(h,&sai); ai->usecount++; }else{ @@ -346,8 +348,10 @@ static void auth_requested(SalOp *h, const char *realm, const char *username){ static void auth_success(SalOp *h, const char *realm, const char *username){ LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(h)); LinphoneAuthInfo *ai=(LinphoneAuthInfo*)linphone_core_find_auth_info(lc,realm,username); - if (ai) + if (ai){ + ms_message("%s/%s authentication works.",realm,username); ai->works=TRUE; + } } static void register_success(SalOp *op, bool_t registered){ diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 1833de2fd..0c5ad1772 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -1833,6 +1833,10 @@ int linphone_core_invite(LinphoneCore *lc, const char *url) } err=sal_call(call->op,from,real_url); + if (lc->sip_conf.sdp_200_ack){ + call->media_pending=TRUE; + sal_call_set_local_media_description(call->op,call->localdesc); + } barmsg=ortp_strdup_printf("%s %s", _("Contacting"), real_url); lc->vtable.display_status(lc,barmsg); ms_free(barmsg); @@ -1919,10 +1923,16 @@ void linphone_core_init_media_streams(LinphoneCore *lc, LinphoneCall *call){ #endif } +static int dtmf_tab[16]={'0','1','2','3','4','5','6','7','8','9','*','#','A','B','C','D'}; + static void linphone_core_dtmf_received(RtpSession* s, int dtmf, void* user_data){ LinphoneCore* lc = (LinphoneCore*)user_data; + if (dtmf<0 || dtmf>15){ + ms_warning("Bad dtmf value %i",dtmf); + return; + } if (lc->vtable.dtmf_received != NULL) - lc->vtable.dtmf_received(lc, dtmf); + lc->vtable.dtmf_received(lc, dtmf_tab[dtmf]); } static void parametrize_equalizer(LinphoneCore *lc, AudioStream *st){ diff --git a/coreapi/sal_eXosip2.c b/coreapi/sal_eXosip2.c index c4f00dac6..10d15526a 100644 --- a/coreapi/sal_eXosip2.c +++ b/coreapi/sal_eXosip2.c @@ -475,11 +475,13 @@ void sal_op_authenticate(SalOp *h, const SalAuthInfo *info){ const char *userid; if (info->userid==NULL || info->userid[0]=='\0') userid=info->username; else userid=info->userid; + ms_message("Authentication info for %s %s added to eXosip", info->username,info->realm); eXosip_add_authentication_info (info->username,userid, info->password, NULL,info->realm); eXosip_lock(); eXosip_default_action(h->pending_auth); eXosip_unlock(); + ms_message("eXosip_default_action() done"); eXosip_clear_authentication_info(); eXosip_event_free(h->pending_auth); sal_remove_pending_auth(sal_op_get_sal(h),h); @@ -660,11 +662,10 @@ static void call_released(Sal *sal, eXosip_event_t *ev){ sal->callbacks.call_failure(op,SalErrorNoResponse,SalReasonUnknown,NULL); } -static int get_auth_data(eXosip_event_t *ev, const char **realm, const char **username){ +static int get_auth_data_from_response(osip_message_t *resp, const char **realm, const char **username){ const char *prx_realm=NULL,*www_realm=NULL; osip_proxy_authenticate_t *prx_auth; osip_www_authenticate_t *www_auth; - osip_message_t *resp=ev->response; *username=osip_uri_get_username(resp->from->url); prx_auth=(osip_proxy_authenticate_t*)osip_list_get(&resp->proxy_authenticates,0); @@ -684,6 +685,30 @@ static int get_auth_data(eXosip_event_t *ev, const char **realm, const char **us return 0; } +static int get_auth_data_from_request(osip_message_t *msg, const char **realm, const char **username){ + osip_authorization_t *auth=NULL; + osip_proxy_authorization_t *prx_auth=NULL; + + *username=osip_uri_get_username(msg->from->url); + osip_message_get_authorization(msg, 0, &auth); + if (auth){ + *realm=osip_authorization_get_realm(auth); + return 0; + } + osip_message_get_proxy_authorization(msg,0,&prx_auth); + if (prx_auth){ + *realm=osip_proxy_authorization_get_realm(prx_auth); + return 0; + } + return -1; +} + +static int get_auth_data(eXosip_event_t *ev, const char **realm, const char **username){ + if (ev->response && get_auth_data_from_response(ev->response,realm,username)==0) return 0; + if (ev->request && get_auth_data_from_request(ev->request,realm,username)==0) return 0; + return -1; +} + int sal_op_get_auth_requested(SalOp *op, const char **realm, const char **username){ if (op->pending_auth){ return get_auth_data(op->pending_auth,realm,username); diff --git a/gtk-glade/main.c b/gtk-glade/main.c index e492d821a..0b885d09a 100644 --- a/gtk-glade/main.c +++ b/gtk-glade/main.c @@ -208,7 +208,7 @@ static const char *linphone_gtk_get_factory_config_file(){ } static void linphone_gtk_init_liblinphone(const char *config_file, - const char *factory_config_file) { + const char *factory_config_file) { linphone_core_set_user_agent("Linphone", LINPHONE_VERSION); the_core=linphone_core_new(&vtable,config_file,factory_config_file,NULL); linphone_core_set_waiting_callback(the_core,linphone_gtk_wait,NULL); @@ -763,6 +763,7 @@ static void linphone_gtk_bye_recv(LinphoneCore *lc, const char *from){ } static void linphone_gtk_notify_recv(LinphoneCore *lc, LinphoneFriend * fid){ + linphone_gtk_show_friends(); } static void linphone_gtk_new_subscriber_response(GtkWidget *dialog, guint response_id, LinphoneFriend *lf){ From bcd737a4ae8abac688dbdef6fbc7c0eeb22477e3 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Fri, 5 Mar 2010 18:10:56 +0100 Subject: [PATCH 23/50] fix c++ compilation issue with proxyConfig --- coreapi/linphonecore.h | 1 - 1 file changed, 1 deletion(-) diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index afd523d0e..6e4e658e6 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -179,7 +179,6 @@ bool_t linphone_friend_in_list(const LinphoneFriend *lf); #define linphone_friend_url(lf) ((lf)->url) -struct LinphoneProxyConfig; /** * @addtogroup proxies From d54a04dc71744634fddb928ed2b8940e4f60e354 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Tue, 9 Mar 2010 11:25:33 +0100 Subject: [PATCH 24/50] make use of firewall ip address in contact and sdp. --- coreapi/linphonecore.c | 147 +++++++++++++---------------------------- coreapi/sal_eXosip2.c | 69 +++++++++++++------ 2 files changed, 95 insertions(+), 121 deletions(-) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 0c5ad1772..a1cb09b04 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -41,7 +41,6 @@ static const char *liblinphone_version=LIBLINPHONE_VERSION; #include "enum.h" void linphone_core_get_local_ip(LinphoneCore *lc, const char *dest, char *result); -static void apply_nat_settings(LinphoneCore *lc); static void toggle_video_preview(LinphoneCore *lc, bool_t val); /* relative path where is stored local ring*/ @@ -1094,10 +1093,6 @@ int linphone_core_set_primary_contact(LinphoneCore *lc, const char *contact) /*result must be an array of chars at least LINPHONE_IPADDR_SIZE */ void linphone_core_get_local_ip(LinphoneCore *lc, const char *dest, char *result){ - if (lc->apply_nat_settings){ - apply_nat_settings(lc); - lc->apply_nat_settings=FALSE; - } if (linphone_core_get_firewall_policy(lc)==LINPHONE_POLICY_USE_NAT_ADDRESS){ strncpy(result,linphone_core_get_nat_address(lc),LINPHONE_IPADDR_SIZE); return; @@ -1109,6 +1104,32 @@ void linphone_core_get_local_ip(LinphoneCore *lc, const char *dest, char *result sal_get_default_local_ip(lc->sal,lc->sip_conf.ipv6_enabled ? AF_INET6 : AF_INET,result,LINPHONE_IPADDR_SIZE); } +static void update_primary_contact(LinphoneCore *lc){ + char *guessed=NULL; + char tmp[LINPHONE_IPADDR_SIZE]; + + LinphoneAddress *url; + if (lc->sip_conf.guessed_contact!=NULL){ + ms_free(lc->sip_conf.guessed_contact); + lc->sip_conf.guessed_contact=NULL; + } + url=linphone_address_new(lc->sip_conf.contact); + if (!url){ + ms_error("Could not parse identity contact !"); + url=linphone_address_new("sip:unknown@unkwownhost"); + } + linphone_core_get_local_ip(lc, NULL, tmp); + if (strcmp(tmp,"127.0.0.1")==0 || strcmp(tmp,"::1")==0 ){ + ms_warning("Local loopback network only !"); + lc->sip_conf.loopback_only=TRUE; + }else lc->sip_conf.loopback_only=FALSE; + linphone_address_set_domain(url,tmp); + linphone_address_set_port_int(url,lc->sip_conf.sip_port); + guessed=linphone_address_as_string(url); + lc->sip_conf.guessed_contact=guessed; + linphone_address_destroy(url); +} + /** * Returns the default identity when no proxy configuration is used. * @@ -1116,31 +1137,10 @@ void linphone_core_get_local_ip(LinphoneCore *lc, const char *dest, char *result **/ const char *linphone_core_get_primary_contact(LinphoneCore *lc){ char *identity; - char tmp[LINPHONE_IPADDR_SIZE]; if (lc->sip_conf.guess_hostname){ if (lc->sip_conf.guessed_contact==NULL || lc->sip_conf.loopback_only){ - char *guessed=NULL; - LinphoneAddress *url; - if (lc->sip_conf.guessed_contact!=NULL){ - ms_free(lc->sip_conf.guessed_contact); - lc->sip_conf.guessed_contact=NULL; - } - url=linphone_address_new(lc->sip_conf.contact); - if (!url){ - ms_error("Could not parse identity contact !"); - url=linphone_address_new("sip:unknown@unkwownhost"); - } - linphone_core_get_local_ip(lc, NULL, tmp); - if (strcmp(tmp,"127.0.0.1")==0 || strcmp(tmp,"::1")==0 ){ - ms_warning("Local loopback network only !"); - lc->sip_conf.loopback_only=TRUE; - }else lc->sip_conf.loopback_only=FALSE; - linphone_address_set_domain(url,tmp); - linphone_address_set_port_int(url,lc->sip_conf.sip_port); - guessed=linphone_address_as_string(url); - lc->sip_conf.guessed_contact=guessed; - linphone_address_destroy(url); + update_primary_contact(lc); } identity=lc->sip_conf.guessed_contact; }else{ @@ -1739,9 +1739,20 @@ LinphoneProxyConfig * linphone_core_lookup_known_proxy(LinphoneCore *lc, const L return found_cfg; } -static char *get_fixed_contact(LinphoneCore *lc, const char *localip, LinphoneProxyConfig *dest_proxy){ +static char *get_fixed_contact(LinphoneCore *lc, LinphoneCall *call , LinphoneProxyConfig *dest_proxy){ LinphoneAddress *ctt; + const char *localip=call->localip; + if (linphone_core_get_firewall_policy(lc)==LINPHONE_POLICY_USE_NAT_ADDRESS){ + ctt=linphone_core_get_primary_contact_parsed(lc); + return ms_strdup_printf("sip:%s@%s",linphone_address_get_username(ctt), + linphone_core_get_nat_address(lc)); + } + + if (call->op && sal_op_get_contact(call->op)!=NULL){ + return NULL; + } + if (dest_proxy && dest_proxy->op){ const char *fixed_contact=sal_op_get_contact(dest_proxy->op); if (fixed_contact) { @@ -1815,10 +1826,8 @@ int linphone_core_invite(LinphoneCore *lc, const char *url) call=linphone_call_new_outgoing(lc,parsed_url2,real_parsed_url); sal_op_set_route(call->op,route); - /*try to be best-effort in giving real local or routable contact address, - except when the user choosed to override the ipaddress */ - if (linphone_core_get_firewall_policy(lc)!=LINPHONE_POLICY_USE_NAT_ADDRESS) - contact=get_fixed_contact(lc,call->localip,dest_proxy); + /*try to be best-effort in giving real local or routable contact address */ + contact=get_fixed_contact(lc,call,dest_proxy); if (contact){ sal_op_set_contact(call->op, contact); ms_free(contact); @@ -2193,10 +2202,8 @@ int linphone_core_accept_call(LinphoneCore *lc, const char *url) lc->ringstream=NULL; } - /*try to be best-effort in giving real local or routable contact address, - except when the user choosed to override the ipaddress */ - if (linphone_core_get_firewall_policy(lc)!=LINPHONE_POLICY_USE_NAT_ADDRESS) - contact=get_fixed_contact(lc,call->localip,NULL); + /*try to be best-effort in giving real local or routable contact address*/ + contact=get_fixed_contact(lc,call,NULL); if (contact) sal_op_set_contact(call->op,contact); @@ -2705,7 +2712,6 @@ void linphone_core_set_stun_server(LinphoneCore *lc, const char *server){ if (server) lc->net_conf.stun_server=ms_strdup(server); else lc->net_conf.stun_server=NULL; - lc->apply_nat_settings=TRUE; } const char * linphone_core_get_stun_server(const LinphoneCore *lc){ @@ -2727,69 +2733,6 @@ int linphone_core_set_relay_addr(LinphoneCore *lc, const char *addr){ return 0; } -static void apply_nat_settings(LinphoneCore *lc){ - char *wmsg; - char *tmp=NULL; - int err; - struct addrinfo hints,*res; - const char *addr=lc->net_conf.nat_address; - - if (lc->net_conf.firewall_policy==LINPHONE_POLICY_USE_NAT_ADDRESS){ - if (addr==NULL || strlen(addr)==0){ - lc->vtable.display_warning(lc,_("No nat/firewall address supplied !")); - linphone_core_set_firewall_policy(lc,LINPHONE_POLICY_NO_FIREWALL); - } - /*check the ip address given */ - memset(&hints,0,sizeof(struct addrinfo)); - if (lc->sip_conf.ipv6_enabled) - hints.ai_family=AF_INET6; - else - hints.ai_family=AF_INET; - hints.ai_socktype = SOCK_DGRAM; - err=getaddrinfo(addr,NULL,&hints,&res); - if (err!=0){ - wmsg=ortp_strdup_printf(_("Invalid nat address '%s' : %s"), - addr, gai_strerror(err)); - ms_warning(wmsg); // what is this for ? - lc->vtable.display_warning(lc, wmsg); - ms_free(wmsg); - linphone_core_set_firewall_policy(lc,LINPHONE_POLICY_NO_FIREWALL); - return; - } - /*now get it as an numeric ip address */ - tmp=ms_malloc0(50); - err=getnameinfo(res->ai_addr,res->ai_addrlen,tmp,50,NULL,0,NI_NUMERICHOST); - if (err!=0){ - wmsg=ortp_strdup_printf(_("Invalid nat address '%s' : %s"), - addr, gai_strerror(err)); - ms_warning("%s",wmsg); // what is this for ? - lc->vtable.display_warning(lc, wmsg); - ms_free(wmsg); - ms_free(tmp); - freeaddrinfo(res); - linphone_core_set_firewall_policy(lc,LINPHONE_POLICY_NO_FIREWALL); - return; - } - freeaddrinfo(res); - } - - if (lc->net_conf.firewall_policy==LINPHONE_POLICY_USE_NAT_ADDRESS){ - if (tmp!=NULL){ - if (!lc->net_conf.nat_sdp_only){ - sal_masquerade(lc->sal,tmp); - } - ms_free(tmp); - } - else{ - sal_masquerade(lc->sal,NULL); - } - } - else { - sal_masquerade(lc->sal,NULL); - } -} - - void linphone_core_set_nat_address(LinphoneCore *lc, const char *addr) { if (lc->net_conf.nat_address!=NULL){ @@ -2797,7 +2740,7 @@ void linphone_core_set_nat_address(LinphoneCore *lc, const char *addr) } if (addr!=NULL) lc->net_conf.nat_address=ms_strdup(addr); else lc->net_conf.nat_address=NULL; - lc->apply_nat_settings=TRUE; + update_primary_contact(lc); } const char *linphone_core_get_nat_address(const LinphoneCore *lc) @@ -2807,7 +2750,7 @@ const char *linphone_core_get_nat_address(const LinphoneCore *lc) void linphone_core_set_firewall_policy(LinphoneCore *lc, LinphoneFirewallPolicy pol){ lc->net_conf.firewall_policy=pol; - lc->apply_nat_settings=TRUE; + update_primary_contact(lc); } LinphoneFirewallPolicy linphone_core_get_firewall_policy(const LinphoneCore *lc){ diff --git a/coreapi/sal_eXosip2.c b/coreapi/sal_eXosip2.c index 10d15526a..597ab5c66 100644 --- a/coreapi/sal_eXosip2.c +++ b/coreapi/sal_eXosip2.c @@ -183,6 +183,7 @@ void *sal_get_user_pointer(const Sal *sal){ } void sal_masquerade(Sal *ctx, const char *ip){ + ms_message("Masquerading SIP with %s",ip); eXosip_set_option(EXOSIP_OPT_SET_IPV4_FOR_GATEWAY,ip); } @@ -259,6 +260,25 @@ MSList *sal_get_pending_auths(Sal *sal){ return ms_list_copy(sal->pending_auths); } +static int extract_received_rport(osip_message_t *msg, const char **received, int *rportval){ + osip_via_t *via=NULL; + osip_generic_param_t *param=NULL; + const char *rport; + + osip_message_get_via(msg,0,&via); + if (!via) return -1; + osip_via_param_get_byname(via,"rport",¶m); + if (param) { + rport=param->gvalue; + if (rport && rport[0]!='\0') *rportval=atoi(rport); + else *rportval=5060; + } + param=NULL; + osip_via_param_get_byname(via,"received",¶m); + if (param) *received=param->gvalue; + else return -1; + return 0; +} static void set_sdp(osip_message_t *sip,sdp_message_t *msg){ int sdplen; @@ -586,6 +606,9 @@ static void handle_ack(Sal *sal, eXosip_event_t *ev){ static int call_proceeding(Sal *sal, eXosip_event_t *ev){ SalOp *op=(SalOp*)ev->external_reference; + const char *received; + int rport; + if (op==NULL) { ms_warning("This call has been canceled."); eXosip_lock(); @@ -595,6 +618,24 @@ static int call_proceeding(Sal *sal, eXosip_event_t *ev){ } op->did=ev->did; op->tid=ev->tid; + /* update contact if received and rport are set by the server */ + if (extract_received_rport(ev->response,&received,&rport)==0){ + const char *contact=sal_op_get_contact(op); + if (!contact){ + /*no contact given yet, use from instead*/ + contact=sal_op_get_from(op); + } + if (contact){ + SalAddress *addr=sal_address_new(contact); + char *tmp; + sal_address_set_domain(addr,received); + sal_address_set_port_int(addr,rport); + tmp=sal_address_as_string(addr); + ms_message("Contact address automatically updated to %s for this call",tmp); + sal_op_set_contact(op,tmp); + ms_free(tmp); + } + } return 0; } @@ -998,34 +1039,23 @@ static void other_request(Sal *sal, eXosip_event_t *ev){ static bool_t register_again_with_updated_contact(SalOp *op, osip_message_t *orig_request, osip_message_t *last_answer){ osip_message_t *msg; - const char *rport,*received; - osip_via_t *via=NULL; - osip_generic_param_t *param=NULL; + const char *received; + int rport; osip_contact_t *ctt=NULL; char *tmp; + char port[20]; - osip_message_get_via(last_answer,0,&via); - if (!via) return FALSE; - osip_via_param_get_byname(via,"rport",¶m); - if (param) rport=param->gvalue; - else return FALSE; - param=NULL; - osip_via_param_get_byname(via,"received",¶m); - if (param) received=param->gvalue; - else return FALSE; + if (extract_received_rport(last_answer,&received,&rport)==-1) return FALSE; osip_message_get_contact(orig_request,0,&ctt); if (strcmp(ctt->url->host,received)==0){ /*ip address matches, check ports*/ const char *contact_port=ctt->url->port; - const char *via_rport=rport; - if (via_rport==NULL || strlen(via_rport)>0) - via_rport="5060"; - if (contact_port==NULL || strlen(contact_port)>0) + if (contact_port==NULL || contact_port[0]=='\0') contact_port="5060"; - if (strcmp(contact_port,via_rport)==0){ + if (atoi(contact_port)==rport){ ms_message("Register has up to date contact, doing nothing."); return FALSE; - }else ms_message("ports do not match, need to update the register (%s <> %s)", contact_port,via_rport); + }else ms_message("ports do not match, need to update the register (%s <> %i)", contact_port,rport); } eXosip_lock(); msg=NULL; @@ -1043,7 +1073,8 @@ static bool_t register_again_with_updated_contact(SalOp *op, osip_message_t *ori if (ctt->url->port!=NULL){ osip_free(ctt->url->port); } - ctt->url->port=osip_strdup(rport); + snprintf(port,sizeof(port),"%i",rport); + ctt->url->port=osip_strdup(port); eXosip_register_send_register(op->rid,msg); eXosip_unlock(); osip_contact_to_str(ctt,&tmp); From 1a218d544d15771dcab2a2a01d4024e136e0a9f8 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Tue, 9 Mar 2010 14:24:52 +0100 Subject: [PATCH 25/50] avoid use of osip_list_special_free because of signature changes among osip versions. --- coreapi/sal_eXosip2.c | 15 +- intltool-extract.in | 325 --------------------- intltool-merge.in | 657 ------------------------------------------ intltool-update.in | 634 ---------------------------------------- 4 files changed, 12 insertions(+), 1619 deletions(-) delete mode 100644 intltool-extract.in delete mode 100644 intltool-merge.in delete mode 100644 intltool-update.in diff --git a/coreapi/sal_eXosip2.c b/coreapi/sal_eXosip2.c index 597ab5c66..a8b9b2a16 100644 --- a/coreapi/sal_eXosip2.c +++ b/coreapi/sal_eXosip2.c @@ -21,6 +21,15 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "offeranswer.h" + +static void _osip_list_set_empty(osip_list_t *l, void (*freefunc)(void*)){ + void *data; + while((data=osip_list_get(l,0))!=NULL){ + osip_list_remove(l,0); + freefunc(data); + } +} + void sal_get_default_local_ip(Sal *sal, int address_family,char *ip, size_t iplen){ if (eXosip_guess_localip(address_family,ip,iplen)<0){ /*default to something */ @@ -349,7 +358,7 @@ int sal_call(SalOp *h, const char *from, const char *to){ return -1; } if (h->base.contact){ - osip_list_special_free(&invite->contacts,(void (*)(void*))osip_contact_free); + _osip_list_set_empty(&invite->contacts,(void (*)(void*))osip_contact_free); osip_message_set_contact(invite,h->base.contact); } if (h->base.root->session_expires!=0){ @@ -394,7 +403,7 @@ int sal_call_accept(SalOp * h){ } if (contact) { - osip_list_special_free(&msg->contacts,(void (*)(void*))osip_contact_free); + _osip_list_set_empty(&msg->contacts,(void (*)(void*))osip_contact_free); osip_message_set_contact(msg,contact); } @@ -562,7 +571,7 @@ static void handle_reinvite(Sal *sal, eXosip_event_t *ev){ if (op->supports_session_timers) osip_message_set_supported(msg, "timer"); } if (op->base.contact){ - osip_list_special_free(&msg->contacts,(void (*)(void*))osip_contact_free); + _osip_list_set_empty(&msg->contacts,(void (*)(void*))osip_contact_free); osip_message_set_contact(msg,op->base.contact); } if (sdp){ diff --git a/intltool-extract.in b/intltool-extract.in deleted file mode 100644 index 256a959a1..000000000 --- a/intltool-extract.in +++ /dev/null @@ -1,325 +0,0 @@ -#!@INTLTOOL_PERL@ -w -# -*- Mode: perl; indent-tabs-mode: nil; c-basic-offset: 4 -*- - -# -# The Intltool Message Extractor -# -# Copyright (C) 2000-2001 Free Software Foundation. -# -# Intltool is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License as -# published by the Free Software Foundation; either version 2 of the -# License, or (at your option) any later version. -# -# Intltool is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -# -# As a special exception to the GNU General Public License, if you -# distribute this file as part of a program that contains a -# configuration script generated by Autoconf, you may include it under -# the same distribution terms that you use for the rest of that program. -# -# Authors: Kenneth Christiansen -# Darin Adler -# - -## Release information -my $PROGRAM = "intltool-extract"; -my $PACKAGE = "intltool"; -my $VERSION = "0.22"; - -## Loaded modules -use strict; -use File::Basename; -use Getopt::Long; - -## Scalars used by the option stuff -my $TYPE_ARG = "0"; -my $LOCAL_ARG = "0"; -my $HELP_ARG = "0"; -my $VERSION_ARG = "0"; -my $UPDATE_ARG = "0"; -my $QUIET_ARG = "0"; - -my $FILE; -my $OUTFILE; - -my $gettext_type = ""; -my $input; -my %messages = (); - -## Use this instead of \w for XML files to handle more possible characters. -my $w = "[-A-Za-z0-9._:]"; - -## Always print first -$| = 1; - -## Handle options -GetOptions ( - "type=s" => \$TYPE_ARG, - "local|l" => \$LOCAL_ARG, - "help|h" => \$HELP_ARG, - "version|v" => \$VERSION_ARG, - "update" => \$UPDATE_ARG, - "quiet|q" => \$QUIET_ARG, - ) or &error; - -&split_on_argument; - - -## Check for options. -## This section will check for the different options. - -sub split_on_argument { - - if ($VERSION_ARG) { - &version; - - } elsif ($HELP_ARG) { - &help; - - } elsif ($LOCAL_ARG) { - &place_local; - &extract; - - } elsif ($UPDATE_ARG) { - &place_normal; - &extract; - - } elsif (@ARGV > 0) { - &place_normal; - &message; - &extract; - - } else { - &help; - - } -} - -sub place_normal { - $FILE = $ARGV[0]; - $OUTFILE = "$FILE.h"; -} - -sub place_local { - $OUTFILE = fileparse($FILE, ()); - if (!-e "tmp/") { - system("mkdir tmp/"); - } - $OUTFILE = "./tmp/$OUTFILE.h" -} - -sub determine_type { - if ($TYPE_ARG =~ /^gettext\/(.*)/) { - $gettext_type=$1 - } -} - -## Sub for printing release information -sub version{ - print "${PROGRAM} (${PACKAGE}) $VERSION\n"; - print "Copyright (C) 2000 Free Software Foundation, Inc.\n"; - print "Written by Kenneth Christiansen, 2000.\n\n"; - print "This is free software; see the source for copying conditions. There is NO\n"; - print "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"; - exit; -} - -## Sub for printing usage information -sub help{ - print "Usage: ${PROGRAM} [FILENAME] [OPTIONS] ...\n"; - print "Generates a header file from an xml source file.\n\nGrabs all strings "; - print "between <_translatable_node> and it's end tag,\nwhere tag are all allowed "; - print "xml tags. Read the docs for more info.\n\n"; - print " -v, --version shows the version\n"; - print " -h, --help shows this help page\n"; - print " -q, --quiet quiet mode\n"; - print "\nReport bugs to .\n"; - exit; -} - -## Sub for printing error messages -sub error{ - print "Try `${PROGRAM} --help' for more information.\n"; - exit; -} - -sub message { - print "Generating C format header file for translation.\n"; -} - -sub extract { - &determine_type; - - &convert ($FILE); - - open OUT, ">$OUTFILE"; - &msg_write; - close OUT; - - print "Wrote $OUTFILE\n" unless $QUIET_ARG; -} - -sub convert($) { - - ## Reading the file - { - local (*IN); - local $/; #slurp mode - open (IN, "<$FILE") || die "can't open $FILE: $!"; - $input = ; - } - - &type_ini if $gettext_type eq "ini"; - &type_keys if $gettext_type eq "keys"; - &type_xml if $gettext_type eq "xml"; - &type_glade if $gettext_type eq "glade"; - &type_scheme if $gettext_type eq "scheme"; - &type_schemas if $gettext_type eq "schemas"; -} - -sub entity_decode_minimal -{ - local ($_) = @_; - - s/'/'/g; # ' - s/"/"/g; # " - s/&/&/g; - - return $_; -} - -sub entity_decode -{ - local ($_) = @_; - - s/'/'/g; # ' - s/"/"/g; # " - s/&/&/g; - s/<//g; - - return $_; -} - -sub escape_char -{ - return '\"' if $_ eq '"'; - return '\n' if $_ eq "\n"; - return '\\' if $_ eq '\\'; - - return $_; -} - -sub escape -{ - my ($string) = @_; - return join "", map &escape_char, split //, $string; -} - -sub type_ini { - ### For generic translatable desktop files ### - while ($input =~ /^_.*=(.*)$/mg) { - $messages{$1} = []; - } -} - -sub type_keys { - ### For generic translatable mime/keys files ### - while ($input =~ /^\s*_\w+=(.*)$/mg) { - $messages{$1} = []; - } -} - -sub type_xml { - ### For generic translatable XML files ### - - while ($input =~ /\s_$w+=\"([^"]+)\"/sg) { # " - $messages{entity_decode_minimal($1)} = []; - } - - while ($input =~ /<_($w+)>(.+?)<\/_\1>/sg) { - $_ = $2; - s/\s+/ /g; - s/^ //; - s/ $//; - $messages{entity_decode_minimal($_)} = []; - } -} - -sub type_schemas { - ### For schemas XML files ### - - # FIXME: We should handle escaped < (less than) - while ($input =~ /<(short|long)>([^<]+)<\/\1>/sg) { - $_ = $2; - s/\s+/ /g; - s/^ //; - s/ $//; - $messages{entity_decode_minimal($_)} = []; - } -} - -sub type_glade { - ### For translatable Glade XML files ### - - my $tags = "label|title|text|format|copyright|comments|preview_text|tooltip|message"; - - while ($input =~ /<($tags)>([^<]+)<\/($tags)>/sg) { - # Glade sometimes uses tags that normally mark translatable things for - # little bits of non-translatable content. We work around this by not - # translating strings that only includes something like label4 or window1. - $messages{entity_decode($2)} = [] unless $2 =~ /^(window|label)[0-9]+$/; - } - - while ($input =~ /(..[^<]*)<\/items>/sg) { - for my $item (split (/\n/, $1)) { - $messages{entity_decode($item)} = []; - } - } - - ## handle new glade files - while ($input =~ /<(property|atkproperty)\s+[^>]*translatable\s*=\s*"yes"[^>]*>([^<]+)<\/\1>/sg) { - $messages{entity_decode($2)} = [] unless $2 =~ /^(window|label)[0-9]+$/; - } - while ($input =~ /]*)"\s+description="([^>]+)"\/>/sg) { - $messages{entity_decode_minimal($2)} = []; - } -} - -sub type_scheme { - while ($input =~ /_\(?"((?:[^"\\]+|\\.)*)"\)?/sg) { - $messages{$1} = []; - } -} - -sub msg_write { - for my $message (sort keys %messages) { - print OUT "/* xgettext:no-c-format */\n" if $message =~ /%/; - - my @lines = split (/\n/, $message); - for (my $n = 0; $n < @lines; $n++) { - if ($n == 0) { - print OUT "char *s = N_(\""; - } else { - print OUT " \""; - } - - print OUT escape($lines[$n]); - - if ($n < @lines - 1) { - print OUT "\\n\"\n"; - } else { - print OUT "\");\n"; - } - } - } -} - diff --git a/intltool-merge.in b/intltool-merge.in deleted file mode 100644 index fd35cfdef..000000000 --- a/intltool-merge.in +++ /dev/null @@ -1,657 +0,0 @@ -#!@INTLTOOL_PERL@ -w - -# -# The Intltool Message Merger -# -# Copyright (C) 2000, 2002 Free Software Foundation. -# Copyright (C) 2000, 2001 Eazel, Inc -# -# Intltool is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# version 2 published by the Free Software Foundation. -# -# Intltool is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -# -# As a special exception to the GNU General Public License, if you -# distribute this file as part of a program that contains a -# configuration script generated by Autoconf, you may include it under -# the same distribution terms that you use for the rest of that program. -# -# Authors: Maciej Stachowiak -# Kenneth Christiansen -# Darin Adler -# -# Proper XML UTF-8'ification written by Cyrille Chepelov -# - -## Release information -my $PROGRAM = "intltool-merge"; -my $PACKAGE = "intltool"; -my $VERSION = "0.22"; - -## Loaded modules -use strict; -use Getopt::Long; - -## Scalars used by the option stuff -my $HELP_ARG = 0; -my $VERSION_ARG = 0; -my $BA_STYLE_ARG = 0; -my $XML_STYLE_ARG = 0; -my $KEYS_STYLE_ARG = 0; -my $DESKTOP_STYLE_ARG = 0; -my $SCHEMAS_STYLE_ARG = 0; -my $QUIET_ARG = 0; -my $PASS_THROUGH_ARG = 0; -my $UTF8_ARG = 0; -my $cache_file; - -## Handle options -GetOptions -( - "help" => \$HELP_ARG, - "version" => \$VERSION_ARG, - "quiet|q" => \$QUIET_ARG, - "oaf-style|o" => \$BA_STYLE_ARG, ## for compatibility - "ba-style|b" => \$BA_STYLE_ARG, - "xml-style|x" => \$XML_STYLE_ARG, - "keys-style|k" => \$KEYS_STYLE_ARG, - "desktop-style|d" => \$DESKTOP_STYLE_ARG, - "schemas-style|s" => \$SCHEMAS_STYLE_ARG, - "pass-through|p" => \$PASS_THROUGH_ARG, - "utf8|u" => \$UTF8_ARG, - "cache|c=s" => \$cache_file - ) or &error; - -my $PO_DIR; -my $FILE; -my $OUTFILE; - -my %po_files_by_lang = (); -my %translations = (); - -# Use this instead of \w for XML files to handle more possible characters. -my $w = "[-A-Za-z0-9._:]"; - -# XML quoted string contents -my $q = "[^\\\"]*"; - -## Check for options. - -if ($VERSION_ARG) { - &print_version; -} elsif ($HELP_ARG) { - &print_help; -} elsif ($BA_STYLE_ARG && @ARGV > 2) { - &preparation; - &print_message; - &ba_merge_translations; - &finalize; -} elsif ($XML_STYLE_ARG && @ARGV > 2) { - &utf8_sanity_check; - &preparation; - &print_message; - &xml_merge_translations; - &finalize; -} elsif ($KEYS_STYLE_ARG && @ARGV > 2) { - &utf8_sanity_check; - &preparation; - &print_message; - &keys_merge_translations; - &finalize; -} elsif ($DESKTOP_STYLE_ARG && @ARGV > 2) { - &preparation; - &print_message; - &desktop_merge_translations; - &finalize; -} elsif ($SCHEMAS_STYLE_ARG && @ARGV > 2) { - &preparation; - &print_message; - &schemas_merge_translations; - &finalize; -} else { - &print_help; -} - -exit; - -## Sub for printing release information -sub print_version -{ - print "${PROGRAM} (${PACKAGE}) ${VERSION}\n"; - print "Written by Maciej Stachowiak, Darin Adler and Kenneth Christiansen.\n\n"; - print "Copyright (C) 2000-2002 Free Software Foundation, Inc.\n"; - print "Copyright (C) 2000-2001 Eazel, Inc.\n"; - print "This is free software; see the source for copying conditions. There is NO\n"; - print "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"; - exit; -} - -## Sub for printing usage information -sub print_help -{ - print "Usage: ${PROGRAM} [OPTIONS] PO_DIRECTORY FILENAME OUTPUT_FILE\n"; - print "Generates an output file that includes translated versions of some attributes,\n"; - print "from an untranslated source and a po directory that includes translations.\n\n"; - print " -b, --ba-style includes translations in the bonobo-activation style\n"; - print " -d, --desktop-style includes translations in the desktop style\n"; - print " -k, --keys-style includes translations in the keys style\n"; - print " -s, --schemas-style includes translations in the schemas style\n"; - print " -x, --xml-style includes translations in the standard xml style\n"; - print " -u, --utf8 convert all strings to UTF-8 before merging\n"; - print " -p, --pass-through use strings as found in .po files, without\n"; - print " conversion (STRONGLY unrecommended with -x)\n"; - print " -q, --quiet suppress most messages\n"; - print " --help display this help and exit\n"; - print " --version output version information and exit\n"; - print "\nReport bugs to bugzilla.gnome.org, module intltool, or contact us through \n"; - print ".\n"; - exit; -} - - -## Sub for printing error messages -sub print_error -{ - print "Try `${PROGRAM} --help' for more information.\n"; - exit; -} - - -sub print_message -{ - print "Merging translations into $OUTFILE.\n" unless $QUIET_ARG; -} - - -sub preparation -{ - $PO_DIR = $ARGV[0]; - $FILE = $ARGV[1]; - $OUTFILE = $ARGV[2]; - - &gather_po_files; - &get_translation_database; -} - -# General-purpose code for looking up translations in .po files - -sub po_file2lang -{ - my ($tmp) = @_; - $tmp =~ s/^.*\/(.*)\.po$/$1/; - return $tmp; -} - -sub gather_po_files -{ - for my $po_file (glob "$PO_DIR/*.po") { - $po_files_by_lang{po_file2lang($po_file)} = $po_file; - } -} - -sub get_po_encoding -{ - my ($in_po_file) = @_; - my $encoding = ""; - - open IN_PO_FILE, $in_po_file or die; - while () { - ## example: "Content-Type: text/plain; charset=ISO-8859-1\n" - if (/Content-Type\:.*charset=([-a-zA-Z0-9]+)\\n/) { - $encoding = $1; - last; - } - } - close IN_PO_FILE; - - if (!$encoding) { - print "Warning: no encoding found in $in_po_file. Assuming ISO-8859-1\n"; - $encoding = "ISO-8859-1"; - } - return $encoding -} - -sub utf8_sanity_check -{ - if (!$UTF8_ARG) { - if (!$PASS_THROUGH_ARG) { - $PASS_THROUGH_ARG="1"; - } - } -} - -sub get_translation_database -{ - if ($cache_file) { - &get_cached_translation_database; - } else { - &create_translation_database; - } -} - -sub get_newest_po_age -{ - my $newest_age; - - foreach my $file (values %po_files_by_lang) { - my $file_age = -M $file; - $newest_age = $file_age if !$newest_age || $file_age < $newest_age; - } - - return $newest_age; -} - -sub create_cache -{ - print "Generating and caching the translation database\n" unless $QUIET_ARG; - - &create_translation_database; - - open CACHE, ">$cache_file" || die; - print CACHE join "\x01", %translations; - close CACHE; -} - -sub load_cache -{ - print "Found cached translation database\n" unless $QUIET_ARG; - - my $contents; - open CACHE, "<$cache_file" || die; - { - local $/; - $contents = ; - } - close CACHE; - %translations = split "\x01", $contents; -} - -sub get_cached_translation_database -{ - my $cache_file_age = -M $cache_file; - if (defined $cache_file_age) { - if ($cache_file_age <= &get_newest_po_age) { - &load_cache; - return; - } - print "Found too-old cached translation database\n" unless $QUIET_ARG; - } - - &create_cache; -} - -sub create_translation_database -{ - for my $lang (keys %po_files_by_lang) { - my $po_file = $po_files_by_lang{$lang}; - - if ($UTF8_ARG) { - my $encoding = get_po_encoding ($po_file); - if (lc $encoding eq "utf-8") { - open PO_FILE, "<$po_file"; - } else { - my $iconv = $ENV{"INTLTOOL_ICONV"} || "iconv"; - open PO_FILE, "$iconv -f $encoding -t UTF-8 $po_file|"; - } - } else { - open PO_FILE, "<$po_file"; - } - - my $nextfuzzy = 0; - my $inmsgid = 0; - my $inmsgstr = 0; - my $msgid = ""; - my $msgstr = ""; - while () { - $nextfuzzy = 1 if /^#, fuzzy/; - if (/^msgid "((\\.|[^\\])*)"/ ) { - $translations{$lang, $msgid} = $msgstr if $inmsgstr && $msgid && $msgstr; - $msgid = ""; - $msgstr = ""; - - if ($nextfuzzy) { - $inmsgid = 0; - } else { - $msgid = unescape_po_string($1); - $inmsgid = 1; - } - $inmsgstr = 0; - $nextfuzzy = 0; - } - if (/^msgstr "((\\.|[^\\])*)"/) { - $msgstr = unescape_po_string($1); - $inmsgstr = 1; - $inmsgid = 0; - } - if (/^"((\\.|[^\\])*)"/) { - $msgid .= unescape_po_string($1) if $inmsgid; - $msgstr .= unescape_po_string($1) if $inmsgstr; - } - } - $translations{$lang, $msgid} = $msgstr if $inmsgstr && $msgid && $msgstr; - } -} - -sub finalize -{ -} - -sub unescape_one_sequence -{ - my ($sequence) = @_; - - return "\\" if $sequence eq "\\\\"; - return "\"" if $sequence eq "\\\""; - - # gettext also handles \n, \t, \b, \r, \f, \v, \a, \xxx (octal), - # \xXX (hex) and has a comment saying they want to handle \u and \U. - - return $sequence; -} - -sub unescape_po_string -{ - my ($string) = @_; - - $string =~ s/(\\.)/unescape_one_sequence($1)/eg; - - return $string; -} - -sub entity_decode -{ - local ($_) = @_; - - s/'/'/g; # ' - s/"/"/g; # " - s/&/&/g; - - return $_; -} - -sub entity_encode -{ - my ($pre_encoded) = @_; - - my @list_of_chars = unpack ('C*', $pre_encoded); - - if ($PASS_THROUGH_ARG) { - return join ('', map (&entity_encode_int_even_high_bit, @list_of_chars)); - } else { - return join ('', map (&entity_encode_int_minimalist, @list_of_chars)); - } -} - -sub entity_encode_int_minimalist -{ - return """ if $_ == 34; - return "&" if $_ == 38; - return "'" if $_ == 39; - return chr $_; -} - -sub entity_encode_int_even_high_bit -{ - if ($_ > 127 || $_ == 34 || $_ == 38 || $_ == 39) { - # the ($_ > 127) should probably be removed - return "&#" . $_ . ";"; - } else { - return chr $_; - } -} - -sub entity_encoded_translation -{ - my ($lang, $string) = @_; - - my $translation = $translations{$lang, $string}; - return $string if !$translation; - return entity_encode ($translation); -} - -## XML (bonobo-activation specific) merge code - -sub ba_merge_translations -{ - my $source; - - { - local $/; # slurp mode - open INPUT, "<$FILE" or die "can't open $FILE: $!"; - $source = ; - close INPUT; - } - - open OUTPUT, ">$OUTFILE" or die "can't open $OUTFILE: $!"; - - while ($source =~ s|^(.*?)([ \t]*<\s*$w+\s+($w+\s*=\s*"$q"\s*)+/?>)([ \t]*\n)?||s) { - print OUTPUT $1; - - my $node = $2 . "\n"; - - my @strings = (); - $_ = $node; - while (s/(\s)_($w+\s*=\s*"($q)")/$1$2/s) { - push @strings, entity_decode($3); - } - print OUTPUT; - - my %langs; - for my $string (@strings) { - for my $lang (keys %po_files_by_lang) { - $langs{$lang} = 1 if $translations{$lang, $string}; - } - } - - for my $lang (sort keys %langs) { - $_ = $node; - s/(\sname\s*=\s*)"($q)"/$1"$2-$lang"/s; - s/(\s)_($w+\s*=\s*")($q)"/$1 . $2 . entity_encoded_translation($lang, $3) . '"'/seg; - print OUTPUT; - } - } - - print OUTPUT $source; - - close OUTPUT; -} - - -## XML (non-bonobo-activation) merge code - -sub xml_merge_translations -{ - my $source; - - { - local $/; # slurp mode - open INPUT, "<$FILE" or die "can't open $FILE: $!"; - $source = ; - close INPUT; - } - - open OUTPUT, ">$OUTFILE" or die; - - # FIXME: support attribute translations - - # Empty nodes never need translation, so unmark all of them. - # For example, <_foo/> is just replaced by . - $source =~ s|<\s*_($w+)\s*/>|<$1/>|g; - - # Support for <_foo>blah style translations. - while ($source =~ s|^(.*?)([ \t]*)<\s*_($w+)\s*>(.*?)<\s*/_\3\s*>([ \t]*\n)?||s) { - print OUTPUT $1; - - my $spaces = $2; - my $tag = $3; - my $string = $4; - - print OUTPUT "$spaces<$tag>$string\n"; - - $string =~ s/\s+/ /g; - $string =~ s/^ //; - $string =~ s/ $//; - $string = entity_decode($string); - - for my $lang (sort keys %po_files_by_lang) { - my $translation = $translations{$lang, $string}; - next if !$translation; - $translation = entity_encode($translation); - print OUTPUT "$spaces<$tag xml:lang=\"$lang\">$translation\n"; - } - } - - print OUTPUT $source; - - close OUTPUT; -} - -sub keys_merge_translations -{ - open INPUT, "<${FILE}" or die; - open OUTPUT, ">${OUTFILE}" or die; - - while () { - if (s/^(\s*)_(\w+=(.*))/$1$2/) { - my $string = $3; - - print OUTPUT; - - my $non_translated_line = $_; - - for my $lang (sort keys %po_files_by_lang) { - my $translation = $translations{$lang, $string}; - next if !$translation; - - $_ = $non_translated_line; - s/(\w+)=.*/[$lang]$1=$translation/; - print OUTPUT; - } - } else { - print OUTPUT; - } - } - - close OUTPUT; - close INPUT; -} - -sub desktop_merge_translations -{ - open INPUT, "<${FILE}" or die; - open OUTPUT, ">${OUTFILE}" or die; - - while () { - if (s/^(\s*)_(\w+=(.*))/$1$2/) { - my $string = $3; - - print OUTPUT; - - my $non_translated_line = $_; - - for my $lang (sort keys %po_files_by_lang) { - my $translation = $translations{$lang, $string}; - next if !$translation; - - $_ = $non_translated_line; - s/(\w+)=.*/${1}[$lang]=$translation/; - print OUTPUT; - } - } else { - print OUTPUT; - } - } - - close OUTPUT; - close INPUT; -} - -sub schemas_merge_translations -{ - my $source; - - { - local $/; # slurp mode - open INPUT, "<$FILE" or die "can't open $FILE: $!"; - $source = ; - close INPUT; - } - - open OUTPUT, ">$OUTFILE" or die; - - # FIXME: support attribute translations - - # Empty nodes never need translation, so unmark all of them. - # For example, <_foo/> is just replaced by . - $source =~ s|<\s*_($w+)\s*/>|<$1/>|g; - - # Support for <_foo>blah style translations. - - my $regex_start = "^(.*?)([ \t]*)"; - my $regex_short = "([ \t\n]*)(.*?)"; - my $regex_long = "([ \t\n]*)(.*?)"; - my $regex_end = "([ \t\n]*)"; - - while ($source =~ s|$regex_start$regex_short$regex_long$regex_end||s) { - print OUTPUT $1; - - my $locale_start_spaces = $2; - my $locale_end_spaces = $7; - my $short_spaces = $3; - my $short_string = $4; - my $long_spaces = $5; - my $long_string = $6; - - # English first - - print OUTPUT "$locale_start_spaces"; - print OUTPUT "$short_spaces$short_string"; - print OUTPUT "$long_spaces$long_string"; - print OUTPUT "$locale_end_spaces"; - - $short_string =~ s/\s+/ /g; - $short_string =~ s/^ //; - $short_string =~ s/ $//; - $short_string = entity_decode($short_string); - - $long_string =~ s/\s+/ /g; - $long_string =~ s/^ //; - $long_string =~ s/ $//; - $long_string = entity_decode($long_string); - - for my $lang (sort keys %po_files_by_lang) { - my $short_translation = $translations{$lang, $short_string}; - my $long_translation = $translations{$lang, $long_string}; - - next if (!$short_translation && !$long_translation); - - print OUTPUT "\n$locale_start_spaces"; - - if ($short_translation) - { - $short_translation = entity_encode($short_translation); - print OUTPUT "$short_spaces$short_translation"; - } - - if ($long_translation) - { - $long_translation = entity_encode($long_translation); - print OUTPUT "$long_spaces$long_translation"; - } - - print OUTPUT "$locale_end_spaces"; - } - } - - print OUTPUT $source; - - close OUTPUT; -} diff --git a/intltool-update.in b/intltool-update.in deleted file mode 100644 index cc5fc141d..000000000 --- a/intltool-update.in +++ /dev/null @@ -1,634 +0,0 @@ -#!@INTLTOOL_PERL@ -w - -# -# The Intltool Message Updater -# -# Copyright (C) 2000-2002 Free Software Foundation. -# -# Intltool is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# version 2 published by the Free Software Foundation. -# -# Intltool is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -# -# As a special exception to the GNU General Public License, if you -# distribute this file as part of a program that contains a -# configuration script generated by Autoconf, you may include it under -# the same distribution terms that you use for the rest of that program. -# -# Authors: Kenneth Christiansen -# Maciej Stachowiak -# Darin Adler - -## Release information -my $PROGRAM = "intltool-update"; -my $VERSION = "0.22"; -my $PACKAGE = "intltool"; - -## Loaded modules -use strict; -use Getopt::Long; -use Cwd; -use File::Copy; -use File::Find; - -## Scalars used by the option stuff -my $HELP_ARG = 0; -my $VERSION_ARG = 0; -my $DIST_ARG = 0; -my $POT_ARG = 0; -my $HEADERS_ARG = 0; -my $MAINTAIN_ARG = 0; -my $REPORT_ARG = 0; -my $VERBOSE = 0; -my $GETTEXT_PACKAGE = ""; - -my @languages; -my %po_files_by_lang = (); - -# Regular expressions to categorize file types. -# FIXME: Please check if the following is correct - -my $xml_extension = -"xml(\.in)*|". # .in is not required -"ui|". -"glade2?(\.in)*|". # .in is not required -"scm(\.in)*|". # .in is not required -"oaf(\.in)+|". -"etspec|". -"sheet(\.in)+|". -"schemas(\.in)+|". -"pong(\.in)+"; - -my $ini_extension = -"desktop(\.in)+|". -"caves(\.in)+|". -"directory(\.in)+|". -"soundlist(\.in)+|". -"keys(\.in)+|". -"server(\.in)+"; - -## Always print as the first thing -$| = 1; - -## Handle options -GetOptions -( - "help" => \$HELP_ARG, - "version" => \$VERSION_ARG, - "dist|d" => \$DIST_ARG, - "pot|p" => \$POT_ARG, - "headers|s" => \$HEADERS_ARG, - "maintain|m" => \$MAINTAIN_ARG, - "report|r" => \$REPORT_ARG, - "verbose|x" => \$VERBOSE, - "gettext-package|g=s" => \$GETTEXT_PACKAGE, - ) or &print_error_invalid_option; - -&print_help if $HELP_ARG; -&print_version if $VERSION_ARG; - -my $arg_count = ($DIST_ARG > 0) - + ($POT_ARG > 0) - + ($HEADERS_ARG > 0) - + ($MAINTAIN_ARG > 0) - + ($REPORT_ARG > 0); -&print_help if $arg_count > 1; - -# --version and --help don't require a module name -my $MODULE = $GETTEXT_PACKAGE || &find_package_name; - -if ($DIST_ARG) { - if ($ARGV[0] =~ /^[a-z]/){ - &update_po_file ($ARGV[0]); - &print_status ($ARGV[0]); - } else { - &print_help; - } -} elsif ($POT_ARG) { - &generate_headers; - &generate_po_template; -} elsif ($HEADERS_ARG) { - &generate_headers; -} elsif ($MAINTAIN_ARG) { - &find_leftout_files; -} elsif ($REPORT_ARG) { - &print_report; -} else { - if ($ARGV[0] =~ /^[a-z]/) { - &main ($ARGV[0]); - } else { - &print_help; - } -} - -exit; - -######### - -sub print_version -{ - ## Print version information - print "${PROGRAM} (${PACKAGE}) $VERSION\n"; - print "Written by Kenneth Christiansen, Maciej Stachowiak, and Darin Adler.\n\n"; - print "Copyright (C) 2000-2002 Free Software Foundation, Inc.\n"; - print "This is free software; see the source for copying conditions. There is NO\n"; - print "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"; - exit; -} - -sub print_help -{ - ## Print usage information - print "Usage: ${PROGRAM} [OPTIONS] ...LANGCODE\n"; - print "Updates PO template files and merge them with the translations.\n\n"; - print " -p, --pot generate the PO template only\n"; - print " -s, --headers generate the header files in POTFILES.in\n"; - print " -m, --maintain search for left out files from POTFILES.in\n"; - print " -r, --report display a status report for the module.\n"; - print " -x, --verbose display lots of feedback\n"; - print " --help display this help and exit\n"; - print " --version output version information and exit\n"; - print "\nExamples of use:\n"; - print "${PROGRAM} --pot just creates a new PO template from the source\n"; - print "${PROGRAM} da created new PO template and updated the da.po file\n\n"; - print "Report bugs to bugzilla.gnome.org, module 'intltool'.\n"; - exit; -} - -sub main -{ - my ($lang) = @_; - - ## Report error if the language file supplied - ## to the command line is non-existent - &print_error_not_existing("$lang.po") if ! -s "$lang.po"; - - print "Working, please wait..." unless $VERBOSE; - &generate_headers; - &generate_po_template; - &update_po_file ($lang); - &print_status ($lang); -} - -sub determine_type ($) -{ - my $type = $_; - my $gettext_type; - - # FIXME: Use $xml_extentions, and maybe do all this even nicer - my $xml_regex = - "(?:xml(\.in)*|ui|oaf(?:\.in)+|server(?:\.in)+|sheet(?:\.in)+|". - "pong(?:\.in)+|etspec|schemas(?:\.in)+)"; - my $ini_regex = - "(?:desktop(?:\.in)+|caves(?:\.in)+|directory(?:\.in)+|". - "soundlist(?:\.in)+)"; - - if ($type =~ /\[type: gettext\/([^\]].*)]/) { - $gettext_type=$1; - } - elsif ($type =~ /schemas(\.in)+$/) { - $gettext_type="schemas"; - } - elsif ($type =~ /$xml_regex$/) { - $gettext_type="xml"; - } - elsif ($type =~ /glade2?(\.in)*$/) { - $gettext_type="glade"; - } - elsif ($type =~ /$ini_regex$/) { - $gettext_type="ini"; - } - elsif ($type =~ /scm(\.in)*$/) { - $gettext_type="scheme"; - } - elsif ($type =~ /keys(\.in)+$/) { - $gettext_type="keys"; - } - else { $gettext_type=""; } - - return "gettext\/$gettext_type"; -} - -sub find_leftout_files -{ - my (@buf_i18n_plain, - @buf_i18n_xml, - @buf_i18n_xml_unmarked, - @buf_i18n_ini, - @buf_potfiles, - @buf_potfiles_ignore, - @buf_allfiles, - @buf_allfiles_sorted, - @buf_potfiles_sorted - ); - - ## Search and find all translatable files - find sub { - push @buf_i18n_plain, "$File::Find::name" if /\.(c|y|cc|cpp|c\+\+|h|gob)$/ - }, ".."; - find sub { - push @buf_i18n_xml, "$File::Find::name" if /\.($xml_extension)$/ - }, ".."; - find sub { - push @buf_i18n_ini, "$File::Find::name" if /\.($ini_extension)$/ - }, ".."; - find sub { - push @buf_i18n_xml_unmarked, "$File::Find::name" if /\.(schemas(\.in)+)$/ - }, ".."; - - - open POTFILES, "POTFILES.in" or die "$PROGRAM: there's no POTFILES.in!\n"; - - @buf_potfiles = grep /^[^#]/, ; - - print "Searching for missing translatable files...\n" if $VERBOSE; - - ## Check if we should ignore some found files, when - ## comparing with POTFILES.in - foreach my $ignore ("POTFILES.skip", "POTFILES.ignore") { - if (-s $ignore) { - open FILE, $ignore; - while () { - if (/^[^#]/){ - push @buf_potfiles_ignore, $_; - } - } - print "Found $ignore: Ignoring files...\n" if $VERBOSE; - @buf_potfiles = (@buf_potfiles_ignore, @buf_potfiles); - } - } - - foreach my $file (@buf_i18n_plain) - { - my $in_comment = 0; - my $in_macro = 0; - - open FILE, "<$file"; - while () - { - # Handle continued multi-line comment. - if ($in_comment) - { - next unless s-.*\*/--; - $in_comment = 0; - } - - # Handle continued macro. - if ($in_macro) - { - $in_macro = 0 unless /\\$/; - next; - } - - # Handle start of macro (or any preprocessor directive). - if (/^\s*\#/) - { - $in_macro = 1 if /^([^\\]|\\.)*\\$/; - next; - } - - # Handle comments and quoted text. - while (m-(/\*|//|\'|\")-) # \' and \" keep emacs perl mode happy - { - my $match = $1; - if ($match eq "/*") - { - if (!s-/\*.*?\*/--) - { - s-/\*.*--; - $in_comment = 1; - } - } - elsif ($match eq "//") - { - s-//.*--; - } - else # ' or " - { - if (!s-$match([^\\]|\\.)*?$match-QUOTEDTEXT-) - { - warn "mismatched quotes at line $. in $file\n"; - s-$match.*--; - } - } - } - - - if (/_\(QUOTEDTEXT/) - { - ## Remove the first 3 chars and add newline - push @buf_allfiles, unpack("x3 A*", $file) . "\n"; - last; - } - } - close FILE; - } - - foreach my $file (@buf_i18n_xml) { - open FILE, "<$file"; - while () { - if (/\s_(.*)=\"/ || /translatable=\"yes\"/){ - push @buf_allfiles, unpack("x3 A*", $file) . "\n"; - last; - } - } - } - - foreach my $file (@buf_i18n_ini){ - open FILE, "<$file"; - while () { - if (/_(.*)=/){ - push @buf_allfiles, unpack("x3 A*", $file) . "\n"; - last; - } - } - } - - foreach my $file (@buf_i18n_xml_unmarked){ - push @buf_allfiles, unpack("x3 A*", $file) . "\n"; - } - - - @buf_allfiles_sorted = sort (@buf_allfiles); - @buf_potfiles_sorted = sort (@buf_potfiles); - - my %in2; - foreach (@buf_potfiles_sorted) { - $in2{$_} = 1; - } - - my @result; - - foreach (@buf_allfiles_sorted){ - if (!exists($in2{$_})){ - push @result, $_ - } - } - - ## Save file with information about the files missing - ## if any, and give information about this procedure. - if (@result) { - print "\n" if $VERBOSE; - open OUT, ">missing"; - print OUT @result; - print "The following files contain translations and are currently not in use. Please\n"; - print "consider adding these to the POTFILES.in file, located in the po/ directory.\n\n"; - print @result, "\n"; - print "If some of these files are left out on purpose then please add them to\n"; - print "POTFILES.skip instead of POTFILES.in. A file 'missing' containing this list\n"; - print "of left out files has been written in the current directory.\n"; - } - - ## If there is nothing to complain about, notify the user - else { - print "\nAll files containing translations are present in POTFILES.in.\n"; - } -} - -sub print_error_invalid_option -{ - ## Handle invalid arguments - print "Try `${PROGRAM} --help' for more information.\n"; - exit 1; -} - -sub generate_headers -{ - my $EXTRACT = `which intltool-extract 2>/dev/null`; - chomp $EXTRACT; - - $EXTRACT = $ENV{"INTLTOOL_EXTRACT"} if $ENV{"INTLTOOL_EXTRACT"}; - - ## Generate the .h header files, so we can allow glade and - ## xml translation support - if (! -s $EXTRACT) - { - print "\n *** The intltool-extract script wasn't found!" - ."\n *** Without it, intltool-update can not generate files.\n"; - exit; - } - else - { - open FILE, ") { - chomp; - - ## Find xml files in POTFILES.in and generate the - ## files with help from the extract script - - my $gettext_type= &determine_type ($1); - - if (/\.($xml_extension|$ini_extension)$/ || /^\[/){ - $_ =~ s/^\[[^\[].*]\s*//; - my $filename = "../$_"; - - if ($VERBOSE){ - system($EXTRACT, "--update", "--type=$gettext_type", $filename); - } else { - system($EXTRACT, "--update", "--type=$gettext_type", "--quiet", $filename); - } - } - } - close FILE; - } -} - -sub generate_po_template -{ - ## Generate the potfiles from the POTFILES.in file - - print "Building the $MODULE.pot...\n" if $VERBOSE; - - move ("POTFILES.in", "POTFILES.in.old"); - - open INFILE, "POTFILES.in"; - while () { - s/\.($xml_extension|$ini_extension)$/$&.h/; - s/^\[.*]\s*(.*)/$1.h/; - print OUTFILE $_; - } - close OUTFILE; - close INFILE; - - system ("xgettext", "--default-domain\=$MODULE", - "--directory\=\.\.", - "--add-comments", - "--keyword\=\_", - "--keyword\=N\_", - "--keyword\=U\_", - "--files-from\=\.\/POTFILES\.in"); - - move ("POTFILES.in.old", "POTFILES.in"); - - print "Removing generated header (.h) files..." if $VERBOSE; - - open FILE, ") - { - chomp; - unlink "../$_.h" if /\.($xml_extension|$ini_extension)$/; - } - - close FILE; - print "done\n" if $VERBOSE; - - if (!-e "$MODULE.po") { - print "WARNING: It seems that none of the files in POTFILES.in ". - "contain marked strings\n"; - exit (1); - } - - system ("rm", "-f", "$MODULE.pot"); - move ("$MODULE.po", "$MODULE.pot") or die "$PROGRAM: couldn't move $MODULE.po to $MODULE.pot.\n"; - - print "Wrote $MODULE.pot\n" if $VERBOSE; -} - -sub update_po_file -{ - my ($lang) = @_; - - print "Merging $lang.po with $MODULE.pot..." if $VERBOSE; - - copy ("$lang.po", "$lang.po.old") || die "copy failed: $!"; - - # Perform merge, remove backup file and the "messages" trash file - # generated by gettext - system ("msgmerge", "$lang.po.old", "$MODULE.pot", "-o", "$lang.po"); - unlink "$lang.po.old"; - unlink "messages"; -} - -sub print_error_not_existing -{ - my ($file) = @_; - - ## Report error if supplied language file is non-existing - print "$PROGRAM: $file does not exist!\n"; - print "Try '$PROGRAM --help' for more information.\n"; - exit; -} - -sub gather_po_files -{ - my @po_files = glob ("./*.po"); - - @languages = map (&po_file2lang, @po_files); - - foreach my $lang (@languages) { - $po_files_by_lang{$lang} = shift (@po_files); - } -} - -sub po_file2lang ($) -{ - my $tmp = $_; - $tmp =~ s/^.*\/(.*)\.po$/$1/; - return $tmp; -} - -sub print_status -{ - my ($lang) = @_; - - system ("msgfmt", "--statistics", "$lang.po"); - print "\n"; -} - -sub print_report -{ - &generate_headers; - &generate_po_template; - &gather_po_files; - - foreach my $lang (@languages) { - print "$lang: "; - &update_po_file ($lang); - } - - print "\n\n * Current translation support in $MODULE \n\n"; - - foreach my $lang (@languages){ - print "$lang: "; - system ("msgfmt", "--statistics", "$lang.po"); - } -} - -sub find_package_name -{ - my $base_dirname = getcwd(); - $base_dirname =~ s@.*/@@; - - my ($conf_in, $src_dir); - - if ($base_dirname =~ /^po(-.+)?$/) { - if (-f "../configure.in") { - $conf_in = "../configure.in"; - } elsif (-f "../configure.ac") { - $conf_in = "../configure.ac"; - } else { - my $makefile_source; - local (*IN); - open IN, ") { - if (/^top_srcdir[ \t]*=/) { - $src_dir = $_; - # print "${src_dir}\n"; - - $src_dir =~ s/^top_srcdir[ \t]*=[ \t]*([^ \t\n\r]*)/$1/; - # print "${src_dir}\n"; - chomp $src_dir; - $conf_in = "$src_dir" . "/configure.in" . "\n"; - last; - } - } - $conf_in || die "Cannot find top_srcdir in Makefile." - } - - my %varhash = (); - my $conf_source; { - local (*IN); - open (IN, "<$conf_in") || die "can't open $conf_in: $!"; - while () { - if (/^(\w+)=(\S+)/) { $varhash{$1} = $2 }; - } - seek (IN, 0, 0); - local $/; # slurp mode - $conf_source = ; - } - - my $name = ""; - $name = $1 if $conf_source =~ /^AM_INIT_AUTOMAKE\([\s\[]*([^,\)\s\]]+)/m; - if ($conf_source =~ /^AC_INIT\([\s\[]*([^,\)\s\]]+)\]?\s*,/m) { - $name = $1; - $varhash{"AC_PACKAGE_NAME"} = $1; - } - $name = $1 if $conf_source =~ /^GETTEXT_PACKAGE=\[?([^\s\]]+)/m; - - $name = "\$AC_PACKAGE_NAME" if "$name" eq "AC_PACKAGE_NAME"; - - my $oldname = ""; - while (($name =~ /[\$](\S+)/) && ("$oldname" ne "$name")) { - $oldname = $name; - if (exists $varhash{$1}) { - $name =~ s/[\$](\S+)/$varhash{$1}/; - } - } - return $name if $name; - } - - print "$PROGRAM: Unable to determine package name.\n" . - "Make sure to run this script inside the po directory.\n"; - exit; -} From 8e675c90eb66ff32d31726ecaa58a8644a2d6029 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Thu, 11 Mar 2010 15:08:43 +0100 Subject: [PATCH 26/50] use guessed contact address in ack too. --- coreapi/sal_eXosip2.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/coreapi/sal_eXosip2.c b/coreapi/sal_eXosip2.c index a8b9b2a16..daae709db 100644 --- a/coreapi/sal_eXosip2.c +++ b/coreapi/sal_eXosip2.c @@ -667,6 +667,7 @@ static void call_accepted(Sal *sal, eXosip_event_t *ev){ sdp_message_t *sdp; osip_message_t *msg=NULL; SalOp *op; + const char *contact; op=(SalOp*)ev->external_reference; if (op==NULL){ ms_error("A closed call is accepted ?"); @@ -680,6 +681,11 @@ static void call_accepted(Sal *sal, eXosip_event_t *ev){ if (op->base.local_media) sdp_process(op); } eXosip_call_build_ack(ev->did,&msg); + contact=sal_op_get_contact(op); + if (contact) { + _osip_list_set_empty(&msg->contacts,(void (*)(void*))osip_contact_free); + osip_message_set_contact(msg,contact); + } if (op->sdp_answer) set_sdp(msg,op->sdp_answer); eXosip_call_send_ack(ev->did,msg); From 00eaddcf28dc0ef5cc9de49f1e9af389e896b4bf Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Fri, 12 Mar 2010 17:27:10 +0100 Subject: [PATCH 27/50] add linphone_core_set/get_soft_play_lev --- coreapi/callbacks.c | 2 +- coreapi/linphonecore.c | 29 +++++++++++++++++++++++++++++ coreapi/linphonecore.h | 12 ++++++++++++ coreapi/linphonecore_jni.cc | 12 ++++++++++++ coreapi/private.h | 1 + 5 files changed, 55 insertions(+), 1 deletion(-) diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index edce2c4e3..30b5f0d55 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -125,7 +125,7 @@ static void call_ringing(SalOp *h){ } }else{ /*accept early media */ - if (lc->audiostream->ticker!=NULL){ + if (lc->audiostream && lc->audiostream->ticker!=NULL){ /*streams already started */ ms_message("Early media already started."); return; diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 0c5ad1772..14faa1195 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -490,6 +490,7 @@ static void sound_config_read(LinphoneCore *lc) /*int tmp;*/ const char *tmpbuf; const char *devid; + float gain=0; #ifdef __linux /*alsadev let the user use custom alsa device within linphone*/ devid=lp_config_get_string(lc->config,"sound","alsadev",NULL); @@ -555,6 +556,9 @@ static void sound_config_read(LinphoneCore *lc) lp_config_get_int(lc->config,"sound","echolimiter",0)); linphone_core_enable_agc(lc, lp_config_get_int(lc->config,"sound","agc",0)); + + gain=lp_config_get_float(lc->config,"sound","soft_play_lev",0); + linphone_core_set_soft_play_level(lc,gain); } static void sip_config_read(LinphoneCore *lc) @@ -1962,6 +1966,10 @@ static void post_configure_audio_streams(LinphoneCore *lc){ float gain=lp_config_get_float(lc->config,"sound","mic_gain",-1); if (gain!=-1) audio_stream_set_mic_gain(st,gain); + float recv_gain = lc->sound_conf.soft_play_lev; + if (recv_gain != 0) { + linphone_core_set_soft_play_level(lc,recv_gain); + } if (linphone_core_echo_limiter_enabled(lc)){ float speed=lp_config_get_float(lc->config,"sound","el_speed",-1); float thres=lp_config_get_float(lc->config,"sound","el_thres",-1); @@ -2351,6 +2359,27 @@ void linphone_core_set_ring_level(LinphoneCore *lc, int level){ if (sndcard) ms_snd_card_set_level(sndcard,MS_SND_CARD_PLAYBACK,level); } + +void linphone_core_set_soft_play_level(LinphoneCore *lc, float level){ + float gain=level; + lc->sound_conf.soft_play_lev=level; + AudioStream *st=lc->audiostream; + if (!st) return; /*just return*/ + + if (st->volrecv){ + ms_filter_call_method(st->volrecv,MS_VOLUME_SET_DB_GAIN,&gain); + }else ms_warning("Could not apply gain: gain control wasn't activated."); +} +float linphone_core_get_soft_play_level(LinphoneCore *lc) { + float gain=0; + AudioStream *st=lc->audiostream; + if (st->volrecv){ + ms_filter_call_method(st->volrecv,MS_VOLUME_GET,&gain); + }else ms_warning("Could not get gain: gain control wasn't activated."); + + return gain; +} + /** * Set sound playback level in 0-100 scale * diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index 6e4e658e6..bdd735f26 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -607,6 +607,18 @@ int linphone_core_get_play_level(LinphoneCore *lc); int linphone_core_get_rec_level(LinphoneCore *lc); void linphone_core_set_ring_level(LinphoneCore *lc, int level); void linphone_core_set_play_level(LinphoneCore *lc, int level); +/** + * Allow to control play level before entering sound card: level in db + * + * @ingroup media_parameters +**/ +void linphone_core_set_soft_play_level(LinphoneCore *lc, float level); +/** + * get play level before entering sound card: level in db + * + * @ingroup media_parameters +**/ +float linphone_core_get_soft_play_level(LinphoneCore *lc); void linphone_core_set_rec_level(LinphoneCore *lc, int level); const char * linphone_core_get_ringer_device(LinphoneCore *lc); const char * linphone_core_get_playback_device(LinphoneCore *lc); diff --git a/coreapi/linphonecore_jni.cc b/coreapi/linphonecore_jni.cc index 1c14757ca..a133e2116 100644 --- a/coreapi/linphonecore_jni.cc +++ b/coreapi/linphonecore_jni.cc @@ -268,6 +268,18 @@ extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setNetworkStateReachable linphone_core_set_network_reachable((LinphoneCore*)lc,isReachable); } +extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setSoftPlayLevel( JNIEnv* env + ,jobject thiz + ,jlong lc + ,jfloat gain) { + linphone_core_set_soft_play_level((LinphoneCore*)lc,gain); +} + +extern "C" float Java_org_linphone_core_LinphoneCoreImpl_getSoftPlayLevel( JNIEnv* env + ,jobject thiz + ,jlong lc) { + return linphone_core_get_soft_play_level((LinphoneCore*)lc); +} //ProxyConfig diff --git a/coreapi/private.h b/coreapi/private.h index 6050449d5..f92aa4faa 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -289,6 +289,7 @@ typedef struct sound_config char rec_lev; char play_lev; char ring_lev; + char soft_play_lev; char source; char *local_ring; char *remote_ring; From 64514608ee6db62fc38304000b75ba4d7bc971ce Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Fri, 12 Mar 2010 18:49:44 +0100 Subject: [PATCH 28/50] use OPTIONS message to try to discover local contact. - before outgoing INVITES - just after receiving an INVITE --- coreapi/callbacks.c | 13 +++- coreapi/linphonecore.c | 158 ++++++++++++++++++++++++++++------------- coreapi/private.h | 4 ++ coreapi/sal.c | 13 ++++ coreapi/sal.h | 11 ++- coreapi/sal_eXosip2.c | 137 +++++++++++++++++++++++++++++------ coreapi/sal_eXosip2.h | 3 + 7 files changed, 269 insertions(+), 70 deletions(-) diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index edce2c4e3..4e8f75028 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -421,6 +421,16 @@ static void internal_message(Sal *sal, const char *msg){ lc->vtable.show(lc); } +static void ping_reply(SalOp *op){ + LinphoneCall *call=(LinphoneCall*) sal_op_get_user_pointer(op); + ms_message("ping reply !"); + if (call){ + if (call->state==LCStatePreEstablishing){ + linphone_core_start_invite(call->core,call,NULL); + } + } +} + SalCallbacks linphone_sal_callbacks={ call_received, call_ringing, @@ -440,7 +450,8 @@ SalCallbacks linphone_sal_callbacks={ notify, subscribe_received, subscribe_closed, - internal_message + internal_message, + ping_reply }; diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 2c163d490..e269f4611 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -63,20 +63,21 @@ int lc_callback_obj_invoke(LCCallbackObj *obj, LinphoneCore *lc){ } -static MSList *make_codec_list(const MSList *codecs){ +static MSList *make_codec_list(const MSList *codecs, bool_t only_one_codec){ MSList *l=NULL; const MSList *it; for(it=codecs;it!=NULL;it=it->next){ PayloadType *pt=(PayloadType*)it->data; if (pt->flags & PAYLOAD_TYPE_ENABLED){ l=ms_list_append(l,payload_type_clone(pt)); + if (only_one_codec) break; } } return l; } static SalMediaDescription *create_local_media_description(LinphoneCore *lc, - const char *localip, const char *username){ + const char *localip, const char *username, bool_t only_one_codec){ MSList *l; PayloadType *pt; SalMediaDescription *md=sal_media_description_new(); @@ -88,7 +89,7 @@ static SalMediaDescription *create_local_media_description(LinphoneCore *lc, md->streams[0].port=linphone_core_get_audio_port(lc); md->streams[0].proto=SalProtoRtpAvp; md->streams[0].type=SalAudio; - l=make_codec_list(lc->codecs_conf.audio_codecs); + l=make_codec_list(lc->codecs_conf.audio_codecs,only_one_codec); pt=payload_type_clone(rtp_profile_get_payload_from_mime(&av_profile,"telephone-event")); l=ms_list_append(l,pt); md->streams[0].payloads=l; @@ -101,7 +102,7 @@ static SalMediaDescription *create_local_media_description(LinphoneCore *lc, md->streams[1].port=linphone_core_get_video_port(lc); md->streams[1].proto=SalProtoRtpAvp; md->streams[1].type=SalVideo; - l=make_codec_list(lc->codecs_conf.video_codecs); + l=make_codec_list(lc->codecs_conf.video_codecs,only_one_codec); md->streams[1].payloads=l; if (lc->dw_video_bw) md->streams[1].bandwidth=lc->dw_video_bw; @@ -141,7 +142,7 @@ LinphoneCall * linphone_call_new_outgoing(struct _LinphoneCore *lc, LinphoneAddr call->core=lc; linphone_core_get_local_ip(lc,linphone_address_get_domain(to),call->localip); call->localdesc=create_local_media_description (lc,call->localip, - linphone_address_get_username(from)); + linphone_address_get_username(from),FALSE); linphone_call_init_common(call,from,to); discover_mtu(lc,linphone_address_get_domain (to)); return call; @@ -150,16 +151,30 @@ LinphoneCall * linphone_call_new_outgoing(struct _LinphoneCore *lc, LinphoneAddr LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *from, LinphoneAddress *to, SalOp *op){ LinphoneCall *call=ms_new0(LinphoneCall,1); LinphoneAddress *me=linphone_core_get_primary_contact_parsed(lc); + char *to_str; + char *from_str; call->dir=LinphoneCallIncoming; sal_op_set_user_pointer(op,call); call->op=op; call->core=lc; + + if (lc->sip_conf.ping_with_options){ + /*the following sends an option request back to the caller so that + we get a chance to discover our nat'd address before answering.*/ + call->ping_op=sal_op_new(lc->sal); + to_str=linphone_address_as_string(to); + from_str=linphone_address_as_string(from); + sal_op_set_route(call->ping_op,sal_op_get_network_origin(call->op)); + sal_ping(call->ping_op,to_str,from_str); + ms_free(to_str); + ms_free(from_str); + } linphone_address_clean(from); linphone_core_get_local_ip(lc,linphone_address_get_domain(from),call->localip); call->localdesc=create_local_media_description (lc,call->localip, - linphone_address_get_username(me)); + linphone_address_get_username(me),lc->sip_conf.only_one_codec); linphone_call_init_common(call, from, to); discover_mtu(lc,linphone_address_get_domain(from)); linphone_address_destroy(me); @@ -171,9 +186,21 @@ void linphone_call_destroy(LinphoneCall *obj) linphone_core_notify_all_friends(obj->core,obj->core->prev_mode); linphone_call_log_completed(obj->log,obj); linphone_core_update_allocated_audio_bandwidth(obj->core); - if (obj->op!=NULL) sal_op_release(obj->op); - if (obj->resultdesc!=NULL) sal_media_description_unref(obj->resultdesc); - if (obj->localdesc!=NULL) sal_media_description_unref(obj->localdesc); + if (obj->op!=NULL) { + sal_op_release(obj->op); + obj->op=NULL; + } + if (obj->resultdesc!=NULL) { + sal_media_description_unref(obj->resultdesc); + obj->resultdesc=NULL; + } + if (obj->localdesc!=NULL) { + sal_media_description_unref(obj->localdesc); + obj->localdesc=NULL; + } + if (obj->ping_op) { + sal_op_release(obj->ping_op); + } ms_free(obj); } @@ -271,6 +298,7 @@ void linphone_call_log_completed(LinphoneCallLog *calllog, LinphoneCall *call){ calllog->duration=time(NULL)-call->start_time; switch(call->state){ case LCStateInit: + case LCStatePreEstablishing: calllog->status=LinphoneCallAborted; break; case LCStateRinging: @@ -630,11 +658,12 @@ static void sip_config_read(LinphoneCore *lc) } } - /*for test*/ + /*for tuning or test*/ lc->sip_conf.sdp_200_ack=lp_config_get_int(lc->config,"sip","sdp_200_ack",0); lc->sip_conf.only_one_codec=lp_config_get_int(lc->config,"sip","only_one_codec",0); lc->sip_conf.register_only_when_network_is_up= lp_config_get_int(lc->config,"sip","register_only_when_network_is_up",1); + lc->sip_conf.ping_with_options=lp_config_get_int(lc->config,"sip","ping_with_options",1); } static void rtp_config_read(LinphoneCore *lc) @@ -1581,7 +1610,10 @@ void linphone_core_iterate(LinphoneCore *lc){ if (lc->call!=NULL){ LinphoneCall *call=lc->call; - + if (call->state==LCStatePreEstablishing && (curtime-call->start_time>=2)){ + /*start the call even if the OPTIONS reply did not arrive*/ + linphone_core_start_invite(lc,call,NULL); + } if (call->dir==LinphoneCallIncoming && call->state==LCStateRinging){ elapsed=curtime-call->start_time; ms_message("incoming call ringing for %i seconds",elapsed); @@ -1749,16 +1781,18 @@ static char *get_fixed_contact(LinphoneCore *lc, LinphoneCall *call , LinphonePr LinphoneAddress *ctt; const char *localip=call->localip; + /* first use user's supplied ip address if asked*/ if (linphone_core_get_firewall_policy(lc)==LINPHONE_POLICY_USE_NAT_ADDRESS){ ctt=linphone_core_get_primary_contact_parsed(lc); return ms_strdup_printf("sip:%s@%s",linphone_address_get_username(ctt), linphone_core_get_nat_address(lc)); } - + + /* if already choosed, don't change it */ 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) { @@ -1766,6 +1800,16 @@ static char *get_fixed_contact(LinphoneCore *lc, LinphoneCall *call , LinphonePr return ms_strdup(fixed_contact); } } + /* if the ping OPTIONS request succeeded use the contact guessed from the + received, rport*/ + if (call->ping_op){ + const char *guessed=sal_op_get_contact(call->ping_op); + if (guessed){ + ms_message("Contact has been fixed using OPTIONS to %s",guessed); + return ms_strdup(guessed); + } + } + ctt=linphone_core_get_primary_contact_parsed(lc); if (ctt!=NULL){ @@ -1781,6 +1825,47 @@ static char *get_fixed_contact(LinphoneCore *lc, LinphoneCall *call , LinphonePr return NULL; } +int linphone_core_start_invite(LinphoneCore *lc, LinphoneCall *call, LinphoneProxyConfig *dest_proxy){ + int err; + char *contact; + char *real_url,*barmsg; + char *from; + /*try to be best-effort in giving real local or routable contact address */ + contact=get_fixed_contact(lc,call,dest_proxy); + if (contact){ + sal_op_set_contact(call->op, contact); + ms_free(contact); + } + call->state=LCStateInit; + linphone_core_init_media_streams(lc,lc->call); + if (!lc->sip_conf.sdp_200_ack){ + call->media_pending=TRUE; + sal_call_set_local_media_description(call->op,call->localdesc); + } + real_url=linphone_address_as_string(call->log->to); + from=linphone_address_as_string(call->log->from); + err=sal_call(call->op,from,real_url); + + if (lc->sip_conf.sdp_200_ack){ + call->media_pending=TRUE; + sal_call_set_local_media_description(call->op,call->localdesc); + } + barmsg=ortp_strdup_printf("%s %s", _("Contacting"), real_url); + lc->vtable.display_status(lc,barmsg); + ms_free(barmsg); + + if (err<0){ + ms_warning("Could not initiate call."); + lc->vtable.display_status(lc,_("could not call")); + linphone_core_stop_media_streams(lc,call); + linphone_call_destroy(call); + lc->call=NULL; + }else gstate_new_state(lc, GSTATE_CALL_OUT_INVITE, real_url); + ms_free(real_url); + ms_free(from); + return err; +} + /** * Initiates an outgoing call * @@ -1790,11 +1875,9 @@ static char *get_fixed_contact(LinphoneCore *lc, LinphoneCall *call , LinphonePr **/ int linphone_core_invite(LinphoneCore *lc, const char *url) { - char *barmsg; int err=0; char *route=NULL; const char *from=NULL; - char *contact=NULL; LinphoneProxyConfig *proxy=NULL; LinphoneAddress *parsed_url2=NULL; LinphoneAddress *real_parsed_url=NULL; @@ -1831,42 +1914,21 @@ int linphone_core_invite(LinphoneCore *lc, const char *url) call=linphone_call_new_outgoing(lc,parsed_url2,real_parsed_url); sal_op_set_route(call->op,route); - - /*try to be best-effort in giving real local or routable contact address */ - contact=get_fixed_contact(lc,call,dest_proxy); - if (contact){ - sal_op_set_contact(call->op, contact); - ms_free(contact); - } - - lc->call=call; - - linphone_core_init_media_streams(lc,lc->call); - if (!lc->sip_conf.sdp_200_ack){ - call->media_pending=TRUE; - sal_call_set_local_media_description(call->op,call->localdesc); - } - err=sal_call(call->op,from,real_url); - - if (lc->sip_conf.sdp_200_ack){ - call->media_pending=TRUE; - sal_call_set_local_media_description(call->op,call->localdesc); - } - barmsg=ortp_strdup_printf("%s %s", _("Contacting"), real_url); - lc->vtable.display_status(lc,barmsg); - ms_free(barmsg); - if (err<0){ - ms_warning("Could not initiate call."); - lc->vtable.display_status(lc,_("could not call")); - linphone_core_stop_media_streams(lc,call); - linphone_call_destroy(call); - lc->call=NULL; - }else gstate_new_state(lc, GSTATE_CALL_OUT_INVITE, url); - + lc->call=call; + if (dest_proxy!=NULL || lc->sip_conf.ping_with_options==FALSE){ + err=linphone_core_start_invite(lc,call,dest_proxy); + }else{ + /*defer the start of the call after the OPTIONS ping*/ + call->state=LCStatePreEstablishing; + call->ping_op=sal_op_new(lc->sal); + sal_ping(call->ping_op,from,real_url); + call->start_time=time(NULL); + } + if (real_url!=NULL) ms_free(real_url); if (route!=NULL) ms_free(route); - return (err<0) ? -1 : 0; + return err; } int linphone_core_refer(LinphoneCore *lc, const char *url) diff --git a/coreapi/private.h b/coreapi/private.h index 546b83dc2..b23dff67d 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -56,6 +56,7 @@ typedef enum _LCState{ LCStateInit, + LCStatePreEstablishing, LCStateRinging, LCStateAVRunning }LCState; @@ -71,6 +72,7 @@ typedef struct _LinphoneCall struct _RtpProfile *video_profile; struct _LinphoneCallLog *log; SalOp *op; + SalOp *ping_op; char localip[LINPHONE_IPADDR_SIZE]; /* our best guess for local ipaddress for this call */ time_t start_time; /*time at which the call was initiated*/ time_t media_start_time; /*time at which it was accepted, media streams established*/ @@ -180,6 +182,7 @@ void linphone_core_start_waiting(LinphoneCore *lc, const char *purpose); void linphone_core_update_progress(LinphoneCore *lc, const char *purpose, float progresses); void linphone_core_stop_waiting(LinphoneCore *lc); +int linphone_core_start_invite(LinphoneCore *lc, LinphoneCall *call, LinphoneProxyConfig *dest_proxy); extern SalCallbacks linphone_sal_callbacks; @@ -253,6 +256,7 @@ typedef struct sip_config bool_t sdp_200_ack; bool_t only_one_codec; /*in SDP answers*/ bool_t register_only_when_network_is_up; + bool_t ping_with_options; } sip_config_t; typedef struct rtp_config diff --git a/coreapi/sal.c b/coreapi/sal.c index ae432d565..750555016 100644 --- a/coreapi/sal.c +++ b/coreapi/sal.c @@ -128,11 +128,20 @@ const char *sal_op_get_proxy(const SalOp *op){ return ((SalOpBase*)op)->route; } +const char *sal_op_get_network_origin(const SalOp *op){ + return ((SalOpBase*)op)->origin; +} + void __sal_op_init(SalOp *b, Sal *sal){ memset(b,0,sizeof(SalOpBase)); ((SalOpBase*)b)->root=sal; } +void __sal_op_set_network_origin(SalOp *op, const char *origin){ + assign_string(&((SalOpBase*)op)->origin,origin); +} + + void __sal_op_free(SalOp *op){ SalOpBase *b=(SalOpBase *)op; if (b->from) { @@ -151,6 +160,10 @@ void __sal_op_free(SalOp *op){ ms_free(b->contact); b->contact=NULL; } + if (b->origin){ + ms_free(b->origin); + b->origin=NULL; + } if (b->local_media) sal_media_description_unref(b->local_media); if (b->remote_media) diff --git a/coreapi/sal.h b/coreapi/sal.h index eb8042361..e672216c9 100644 --- a/coreapi/sal.h +++ b/coreapi/sal.h @@ -124,6 +124,7 @@ typedef struct SalOpBase{ char *contact; char *from; char *to; + char *origin; SalMediaDescription *local_media; SalMediaDescription *remote_media; void *user_pointer; @@ -186,6 +187,7 @@ typedef void (*SalOnNotify)(SalOp *op, SalSubscribeState ss, SalPresenceStatus s typedef void (*SalOnSubscribeReceived)(SalOp *salop, const char *from); typedef void (*SalOnSubscribeClosed)(SalOp *salop, const char *from); typedef void (*SalOnInternalMsg)(Sal *sal, const char *msg); +typedef void (*SalOnPingReply)(SalOp *salop); typedef struct SalCallbacks{ SalOnCallReceived call_received; @@ -207,6 +209,7 @@ typedef struct SalCallbacks{ SalOnSubscribeReceived subscribe_received; SalOnSubscribeClosed subscribe_closed; SalOnInternalMsg internal_message; + SalOnPingReply ping_reply; }SalCallbacks; typedef struct SalAuthInfo{ @@ -219,7 +222,6 @@ 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); void sal_set_user_agent(Sal *ctx, const char *user_agent); -void sal_masquerade(Sal *ctx, const char *ip); void sal_use_session_timers(Sal *ctx, int expires); int sal_iterate(Sal *sal); MSList * sal_get_pending_auths(Sal *sal); @@ -242,6 +244,8 @@ const char *sal_op_get_to(const SalOp *op); const char *sal_op_get_contact(const SalOp *op); const char *sal_op_get_route(const SalOp *op); const char *sal_op_get_proxy(const SalOp *op); +/*for incoming requests, returns the origin of the packet as a sip uri*/ +const char *sal_op_get_network_origin(const SalOp *op); void *sal_op_get_user_pointer(const SalOp *op); /*Call API*/ @@ -273,6 +277,10 @@ int sal_notify_close(SalOp *op); /*presence publish */ int sal_publish(SalOp *op, const char *from, const char *to, SalPresenceStatus status); + +/*ping: main purpose is to obtain its own contact address behind firewalls*/ +int sal_ping(SalOp *op, const char *from, const char *to); + #define payload_type_set_number(pt,n) (pt)->user_data=(void*)((long)n); #define payload_type_get_number(pt) ((int)(long)(pt)->user_data) @@ -282,6 +290,7 @@ void sal_get_default_local_ip(Sal *sal, int address_family, char *ip, size_t ipl /*internal API */ void __sal_op_init(SalOp *b, Sal *sal); +void __sal_op_set_network_origin(SalOp *op, const char *origin /*a sip uri*/); void __sal_op_free(SalOp *b); diff --git a/coreapi/sal_eXosip2.c b/coreapi/sal_eXosip2.c index daae709db..cf6074db5 100644 --- a/coreapi/sal_eXosip2.c +++ b/coreapi/sal_eXosip2.c @@ -64,6 +64,36 @@ static void sal_remove_register(Sal *sal, int rid){ } } +static SalOp * sal_find_other(Sal *sal, osip_message_t *response){ + const MSList *elem; + SalOp *op; + osip_call_id_t *callid=osip_message_get_call_id(response); + if (callid==NULL) { + ms_error("There is no call-id in this response !"); + return NULL; + } + for(elem=sal->other_transactions;elem!=NULL;elem=elem->next){ + op=(SalOp*)elem->data; + if (osip_call_id_match(callid,op->call_id)==0) return op; + } + return NULL; +} + +static void sal_add_other(Sal *sal, SalOp *op, osip_message_t *request){ + osip_call_id_t *callid=osip_message_get_call_id(request); + if (callid==NULL) { + ms_error("There is no call id in the request !"); + return; + } + osip_call_id_clone(callid,&op->call_id); + sal->other_transactions=ms_list_append(sal->other_transactions,op); +} + +static void sal_remove_other(Sal *sal, SalOp *op){ + sal->other_transactions=ms_list_remove(sal->other_transactions,op); +} + + static void sal_add_pending_auth(Sal *sal, SalOp *op){ sal->pending_auths=ms_list_append(sal->pending_auths,op); } @@ -107,6 +137,7 @@ SalOp * sal_op_new(Sal *sal){ op->pending_auth=NULL; op->sdp_answer=NULL; op->reinvite=FALSE; + op->call_id=NULL; return op; } @@ -127,6 +158,10 @@ void sal_op_release(SalOp *op){ } if (op->result) sal_media_description_unref(op->result); + if (op->call_id){ + sal_remove_other(op->base.root,op); + osip_call_id_free(op->call_id); + } __sal_op_free(op); } @@ -191,11 +226,6 @@ void *sal_get_user_pointer(const Sal *sal){ return sal->up; } -void sal_masquerade(Sal *ctx, const char *ip){ - ms_message("Masquerading SIP with %s",ip); - eXosip_set_option(EXOSIP_OPT_SET_IPV4_FOR_GATEWAY,ip); -} - static void unimplemented_stub(){ ms_warning("Unimplemented SAL callback"); } @@ -232,6 +262,8 @@ void sal_set_callbacks(Sal *ctx, const SalCallbacks *cbs){ ctx->callbacks.text_received=(SalOnTextReceived)unimplemented_stub; if (ctx->callbacks.internal_message==NULL) ctx->callbacks.internal_message=(SalOnInternalMsg)unimplemented_stub; + if (ctx->callbacks.ping_reply==NULL) + ctx->callbacks.ping_reply=(SalOnPingReply)unimplemented_stub; } int sal_listen_port(Sal *ctx, const char *addr, int port, SalTransport tr, int is_secure){ @@ -461,6 +493,24 @@ SalMediaDescription * sal_call_get_final_media_description(SalOp *h){ return h->result; } +int sal_ping(SalOp *op, const char *from, const char *to){ + osip_message_t *options=NULL; + + sal_op_set_from(op,from); + sal_op_set_to(op,to); + eXosip_options_build_request (&options, sal_op_get_to(op), + sal_op_get_from(op),sal_op_get_route(op)); + if (options){ + if (op->base.root->session_expires!=0){ + osip_message_set_header(options, "Session-expires", "200"); + osip_message_set_supported(options, "timer"); + } + sal_add_other(sal_op_get_sal(op),op,options); + return eXosip_options_send_request(options); + } + return -1; +} + int sal_refer(SalOp *h, const char *refer_to){ osip_message_t *msg=NULL; int err=0; @@ -518,11 +568,30 @@ void sal_op_authenticate(SalOp *h, const SalAuthInfo *info){ } } +static void set_network_origin(SalOp *op, osip_message_t *req){ + const char *received=NULL; + int rport=5060; + char origin[64]; + if (extract_received_rport(req,&received,&rport)!=0){ + osip_via_t *via=NULL; + char *tmp; + osip_message_get_via(req,0,&via); + received=osip_via_get_host(via); + tmp=osip_via_get_port(via); + if (tmp) rport=atoi(tmp); + } + snprintf(origin,sizeof(origin)-1,"sip:%s:%i",received,rport); + __sal_op_set_network_origin(op,origin); +} + static void inc_new_call(Sal *sal, eXosip_event_t *ev){ SalOp *op=sal_op_new(sal); osip_from_t *from,*to; char *tmp; sdp_message_t *sdp=eXosip_get_sdp_info(ev->request); + + set_network_origin(op,ev->request); + if (sdp){ op->sdp_offering=FALSE; op->base.remote_media=sal_media_description_new(); @@ -613,22 +682,10 @@ static void handle_ack(Sal *sal, eXosip_event_t *ev){ } } -static int call_proceeding(Sal *sal, eXosip_event_t *ev){ - SalOp *op=(SalOp*)ev->external_reference; +static void update_contact_from_response(SalOp *op, osip_message_t *response){ const char *received; int rport; - - if (op==NULL) { - ms_warning("This call has been canceled."); - eXosip_lock(); - eXosip_call_terminate(ev->cid,ev->did); - eXosip_unlock(); - return -1; - } - op->did=ev->did; - op->tid=ev->tid; - /* update contact if received and rport are set by the server */ - if (extract_received_rport(ev->response,&received,&rport)==0){ + if (extract_received_rport(response,&received,&rport)==0){ const char *contact=sal_op_get_contact(op); if (!contact){ /*no contact given yet, use from instead*/ @@ -640,11 +697,29 @@ static int call_proceeding(Sal *sal, eXosip_event_t *ev){ sal_address_set_domain(addr,received); sal_address_set_port_int(addr,rport); tmp=sal_address_as_string(addr); - ms_message("Contact address automatically updated to %s for this call",tmp); + ms_message("Contact address updated to %s for this dialog",tmp); sal_op_set_contact(op,tmp); ms_free(tmp); } } +} + +static int call_proceeding(Sal *sal, eXosip_event_t *ev){ + SalOp *op=(SalOp*)ev->external_reference; + + if (op==NULL) { + ms_warning("This call has been canceled."); + eXosip_lock(); + eXosip_call_terminate(ev->cid,ev->did); + eXosip_unlock(); + return -1; + } + op->did=ev->did; + op->tid=ev->tid; + + /* update contact if received and rport are set by the server + note: will only be used by remote for next INVITE, if any...*/ + update_contact_from_response(op,ev->response); return 0; } @@ -668,6 +743,7 @@ static void call_accepted(Sal *sal, eXosip_event_t *ev){ osip_message_t *msg=NULL; SalOp *op; const char *contact; + op=(SalOp*)ev->external_reference; if (op==NULL){ ms_error("A closed call is accepted ?"); @@ -778,6 +854,7 @@ static SalOp *find_op(Sal *sal, eXosip_event_t *ev){ if (ev->rid>0){ return sal_find_register(sal,ev->rid); } + if (ev->response) return sal_find_other(sal,ev->response); return NULL; } @@ -1152,6 +1229,19 @@ static bool_t registration_failure(Sal *sal, eXosip_event_t *ev){ return TRUE; } +static void other_request_reply(Sal *sal,eXosip_event_t *ev){ + SalOp *op=find_op(sal,ev); + + if (op==NULL){ + ms_warning("other_request_reply(): Receiving response to unknown request."); + return; + } + if (ev->response){ + update_contact_from_response(op,ev->response); + sal->callbacks.ping_reply(op); + } +} + static bool_t process_event(Sal *sal, eXosip_event_t *ev){ switch(ev->type){ case EXOSIP_CALL_ANSWERED: @@ -1242,6 +1332,13 @@ static bool_t process_event(Sal *sal, eXosip_event_t *ev){ case EXOSIP_MESSAGE_NEW: other_request(sal,ev); break; + case EXOSIP_MESSAGE_PROCEEDING: + case EXOSIP_MESSAGE_ANSWERED: + case EXOSIP_MESSAGE_REDIRECTED: + case EXOSIP_MESSAGE_SERVERFAILURE: + case EXOSIP_MESSAGE_GLOBALFAILURE: + other_request_reply(sal,ev); + break; case EXOSIP_MESSAGE_REQUESTFAILURE: if (ev->response && (ev->response->status_code == 407 || ev->response->status_code == 401)){ return process_authentication(sal,ev); diff --git a/coreapi/sal_eXosip2.h b/coreapi/sal_eXosip2.h index 4e5d81240..226948134 100644 --- a/coreapi/sal_eXosip2.h +++ b/coreapi/sal_eXosip2.h @@ -34,6 +34,7 @@ struct Sal{ MSList *out_subscribes;/*MSList of SalOp */ MSList *in_subscribes;/*MSList of SalOp */ MSList *pending_auths;/*MSList of SalOp */ + MSList *other_transactions; /*MSList of SalOp */ int running; int session_expires; void *up; @@ -51,6 +52,8 @@ struct SalOp{ SalMediaDescription *result; sdp_message_t *sdp_answer; eXosip_event_t *pending_auth; + osip_call_id_t *call_id; /*used for out of calls transaction in order + to retrieve the operation when receiving a response*/ bool_t supports_session_timers; bool_t sdp_offering; bool_t reinvite; From 5346dfccb65f1b6f96ea620ec4d640436ed877e2 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Fri, 12 Mar 2010 18:57:23 +0100 Subject: [PATCH 29/50] up to date mediastreamer2 --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index 2e18cdfe5..5bcbcae29 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 2e18cdfe53230763907f3f9b55adeb4c16d396a7 +Subproject commit 5bcbcae29d9cf6d22b4f6880489eafa98e100008 From 2097e06808d135a3b2cb01f93a3b6dcfeb921d36 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Mon, 15 Mar 2010 12:18:20 +0100 Subject: [PATCH 30/50] fix crash when calling set_play_file() while the call isn't yet established. --- coreapi/linphonecore.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 3c3eb3598..1ed8b9428 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -3133,7 +3133,7 @@ void linphone_core_set_play_file(LinphoneCore *lc, const char *file){ } if (file!=NULL) { lc->play_file=ms_strdup(file); - if (lc->audiostream) + if (lc->audiostream->ticker) audio_stream_play(lc->audiostream,file); } } From 52fe995acb9c07e6e5632dffa438c18ebab37f4c Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Tue, 16 Mar 2010 10:50:54 +0100 Subject: [PATCH 31/50] start to fix bugs for presence support. --- coreapi/friend.c | 2 ++ coreapi/sal_eXosip2.c | 2 +- coreapi/sal_eXosip2_presence.c | 11 ++++++----- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/coreapi/friend.c b/coreapi/friend.c index 080dffb4e..a4ca54840 100644 --- a/coreapi/friend.c +++ b/coreapi/friend.c @@ -141,8 +141,10 @@ void __linphone_friend_do_subscribe(LinphoneFriend *fr){ if (fr->outsub==NULL){ /* people for which we don't have yet an answer should appear as offline */ fr->status=LINPHONE_STATUS_OFFLINE; + /* if (fr->lc->vtable.notify_recv) fr->lc->vtable.notify_recv(fr->lc,(LinphoneFriend*)fr); + */ }else{ sal_op_release(fr->outsub); fr->outsub=NULL; diff --git a/coreapi/sal_eXosip2.c b/coreapi/sal_eXosip2.c index cf6074db5..f8a45edb9 100644 --- a/coreapi/sal_eXosip2.c +++ b/coreapi/sal_eXosip2.c @@ -1310,7 +1310,7 @@ static bool_t process_event(Sal *sal, eXosip_event_t *ev){ sal_exosip_notify_recv(sal,ev); break; case EXOSIP_SUBSCRIPTION_ANSWERED: - ms_message("EXOSIP_SUBSCRIPTION_ANSWERED, ev->sid=%i\n",ev->sid); + ms_message("EXOSIP_SUBSCRIPTION_ANSWERED, ev->sid=%i, ev->did=%i\n",ev->sid,ev->did); sal_exosip_subscription_answered(sal,ev); break; case EXOSIP_SUBSCRIPTION_CLOSED: diff --git a/coreapi/sal_eXosip2_presence.c b/coreapi/sal_eXosip2_presence.c index d4ab7ba41..f6c85b5f2 100644 --- a/coreapi/sal_eXosip2_presence.c +++ b/coreapi/sal_eXosip2_presence.c @@ -122,7 +122,8 @@ int sal_unsubscribe(SalOp *op){ if (msg){ osip_message_set_expires(msg,"0"); eXosip_subscribe_send_refresh_request(op->did,msg); - }else ms_error("Could not build subscribe refresh request !"); + }else ms_error("Could not build subscribe refresh request ! op->sid=%i, op->did=%i", + op->sid,op->did); eXosip_unlock(); return 0; } @@ -130,8 +131,8 @@ int sal_unsubscribe(SalOp *op){ int sal_subscribe_accept(SalOp *op){ osip_message_t *msg; eXosip_lock(); - eXosip_insubscription_build_answer(op->tid,202,&msg); - eXosip_insubscription_send_answer(op->tid,202,msg); + eXosip_insubscription_build_answer(op->tid,200,&msg); + eXosip_insubscription_send_answer(op->tid,200,msg); eXosip_unlock(); return 0; } @@ -636,8 +637,6 @@ void sal_exosip_notify_recv(Sal *sal, eXosip_event_t *ev){ osip_from_to_str(from,&tmp); if (strstr(body->body,"pending")!=NULL){ estatus=SalPresenceOffline; - }else if ((strstr(body->body,"online")!=NULL) || (strstr(body->body,"open")!=NULL)) { - estatus=SalPresenceOnline; }else if (strstr(body->body,"busy")!=NULL){ estatus=SalPresenceBusy; }else if (strstr(body->body,"berightback")!=NULL @@ -653,6 +652,8 @@ void sal_exosip_notify_recv(Sal *sal, eXosip_event_t *ev){ estatus=SalPresenceOuttolunch; }else if (strstr(body->body,"closed")!=NULL){ estatus=SalPresenceOffline; + }else if ((strstr(body->body,"online")!=NULL) || (strstr(body->body,"open")!=NULL)) { + estatus=SalPresenceOnline; }else{ estatus=SalPresenceOffline; } From 7593b0073c01a188fb94b149c4d9afe746ac26bc Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Tue, 16 Mar 2010 11:55:30 +0100 Subject: [PATCH 32/50] fix several bug in presence support again. --- coreapi/friend.c | 7 ++++++- coreapi/linphonecore.c | 4 ++-- coreapi/private.h | 2 +- coreapi/sal_eXosip2.c | 6 ++++++ coreapi/sal_eXosip2.h | 3 +++ coreapi/sal_eXosip2_presence.c | 30 +++++++----------------------- 6 files changed, 25 insertions(+), 27 deletions(-) diff --git a/coreapi/friend.c b/coreapi/friend.c index a4ca54840..68f43e659 100644 --- a/coreapi/friend.c +++ b/coreapi/friend.c @@ -299,13 +299,18 @@ static void linphone_friend_unsubscribe(LinphoneFriend *lf){ } } -void linphone_friend_destroy(LinphoneFriend *lf){ +void linphone_friend_close_subscriptions(LinphoneFriend *lf){ linphone_friend_notify(lf,LINPHONE_STATUS_OFFLINE); linphone_friend_unsubscribe(lf); if (lf->insub){ sal_notify_close(lf->insub); sal_op_release(lf->insub); + lf->insub=NULL; } +} + +void linphone_friend_destroy(LinphoneFriend *lf){ + if (lf->uri!=NULL) linphone_address_destroy(lf->uri); if (lf->info!=NULL) buddy_info_free(lf->info); ms_free(lf); diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index ddb09892c..f699a2a3e 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -1392,7 +1392,6 @@ int linphone_core_get_sip_port(LinphoneCore *lc) return lc->sip_conf.sip_port; } -static bool_t exosip_running=FALSE; static char _ua_name[64]="Linphone"; static char _ua_version[64]=LINPHONE_VERSION; @@ -3389,6 +3388,8 @@ static void linphone_core_uninit(LinphoneCore *lc) linphone_core_iterate(lc); } } + if (lc->friends) + ms_list_for_each(lc->friends,(void (*)(void *))linphone_friend_close_subscriptions); gstate_new_state(lc, GSTATE_POWER_SHUTDOWN, NULL); #ifdef VIDEO_ENABLED if (lc->previewstream!=NULL){ @@ -3412,7 +3413,6 @@ static void linphone_core_uninit(LinphoneCore *lc) linphone_core_free_payload_types(); ortp_exit(); - exosip_running=FALSE; gstate_new_state(lc, GSTATE_POWER_OFF, NULL); } diff --git a/coreapi/private.h b/coreapi/private.h index 84b4d0778..cbb767207 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -101,7 +101,7 @@ void linphone_core_refresh_subscribes(LinphoneCore *lc); int linphone_proxy_config_send_publish(LinphoneProxyConfig *cfg, LinphoneOnlineStatus os); int linphone_online_status_to_eXosip(LinphoneOnlineStatus os); - +void linphone_friend_close_subscriptions(LinphoneFriend *lf); void linphone_friend_notify(LinphoneFriend *lf, LinphoneOnlineStatus os); LinphoneFriend *linphone_find_friend_by_inc_subscribe(MSList *l, SalOp *op); LinphoneFriend *linphone_find_friend_by_out_subscribe(MSList *l, SalOp *op); diff --git a/coreapi/sal_eXosip2.c b/coreapi/sal_eXosip2.c index f8a45edb9..5f337b3fa 100644 --- a/coreapi/sal_eXosip2.c +++ b/coreapi/sal_eXosip2.c @@ -153,6 +153,12 @@ void sal_op_release(SalOp *op){ ms_message("Cleaning cid %i",op->cid); eXosip_call_set_reference(op->cid,NULL); } + if (op->sid!=-1){ + sal_remove_out_subscribe(op->base.root,op); + } + if (op->nid!=-1){ + sal_remove_in_subscribe(op->base.root,op); + } if (op->pending_auth){ sal_remove_pending_auth(op->base.root,op); } diff --git a/coreapi/sal_eXosip2.h b/coreapi/sal_eXosip2.h index 226948134..6539dcae8 100644 --- a/coreapi/sal_eXosip2.h +++ b/coreapi/sal_eXosip2.h @@ -59,6 +59,9 @@ struct SalOp{ bool_t reinvite; }; +void sal_remove_out_subscribe(Sal *sal, SalOp *op); +void sal_remove_in_subscribe(Sal *sal, SalOp *op); + void sal_exosip_subscription_recv(Sal *sal, eXosip_event_t *ev); void sal_exosip_subscription_answered(Sal *sal,eXosip_event_t *ev); void sal_exosip_notify_recv(Sal *sal,eXosip_event_t *ev); diff --git a/coreapi/sal_eXosip2_presence.c b/coreapi/sal_eXosip2_presence.c index f6c85b5f2..11104b8d1 100644 --- a/coreapi/sal_eXosip2_presence.c +++ b/coreapi/sal_eXosip2_presence.c @@ -35,16 +35,8 @@ static void sal_add_out_subscribe(Sal *sal, SalOp *op){ sal->out_subscribes=ms_list_append(sal->out_subscribes,op); } -static void sal_remove_out_subscribe(Sal *sal, int sid){ - MSList *elem; - SalOp *op; - for(elem=sal->out_subscribes;elem!=NULL;elem=elem->next){ - op=(SalOp*)elem->data; - if (op->sid==sid) { - sal->out_subscribes=ms_list_remove_link(sal->out_subscribes,elem); - return; - } - } +void sal_remove_out_subscribe(Sal *sal, SalOp *op){ + sal->out_subscribes=ms_list_remove(sal->out_subscribes,op); } static SalOp * sal_find_in_subscribe(Sal *sal, int nid){ @@ -61,16 +53,8 @@ static void sal_add_in_subscribe(Sal *sal, SalOp *op){ sal->in_subscribes=ms_list_append(sal->in_subscribes,op); } -static void sal_remove_in_subscribe(Sal *sal, int nid){ - MSList *elem; - SalOp *op; - for(elem=sal->in_subscribes;elem!=NULL;elem=elem->next){ - op=(SalOp*)elem->data; - if (op->nid==nid) { - sal->in_subscribes=ms_list_remove_link(sal->in_subscribes,elem); - return; - } - } +void sal_remove_in_subscribe(Sal *sal, SalOp *op){ + sal->in_subscribes=ms_list_remove(sal->in_subscribes,op); } int sal_text_send(SalOp *op, const char *from, const char *to, const char *msg){ @@ -659,7 +643,7 @@ void sal_exosip_notify_recv(Sal *sal, eXosip_event_t *ev){ } ms_message("We are notified that %s has online status %i",tmp,estatus); if (ev->ss_status==EXOSIP_SUBCRSTATE_TERMINATED) { - sal_remove_out_subscribe(sal,op->sid); + sal_remove_out_subscribe(sal,op); op->sid=-1; op->did=-1; ms_message("And outgoing subscription terminated by remote."); @@ -683,9 +667,9 @@ void sal_exosip_subscription_closed(Sal *sal,eXosip_event_t *ev){ ms_error("Subscription closed but no associated op !"); return; } - sal_remove_in_subscribe(sal,op->nid); + sal_remove_in_subscribe(sal,op); op->nid=-1; - op->did=0; + op->did=-1; } From 308b63c9ce5d1e32c94ae64b25dc7e25ce24d3b7 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Tue, 16 Mar 2010 12:35:40 +0100 Subject: [PATCH 33/50] add new api "linphone_core_interpret_url" --- coreapi/chat.c | 6 +-- coreapi/linphonecore.c | 76 +++++++++++++++++----------------- coreapi/linphonecore.h | 4 ++ coreapi/private.h | 1 - coreapi/sal_eXosip2_presence.c | 2 +- 5 files changed, 45 insertions(+), 44 deletions(-) diff --git a/coreapi/chat.c b/coreapi/chat.c index 11c3c978f..c1a884964 100644 --- a/coreapi/chat.c +++ b/coreapi/chat.c @@ -27,13 +27,13 @@ LinphoneChatRoom * linphone_core_create_chat_room(LinphoneCore *lc, const char *to){ LinphoneAddress *parsed_url=NULL; - char *route; - if (linphone_core_interpret_url(lc,to,&parsed_url,&route)){ + + if ((parsed_url=linphone_core_interpret_url(lc,to))!=NULL){ LinphoneChatRoom *cr=ms_new0(LinphoneChatRoom,1); cr->lc=lc; cr->peer=linphone_address_as_string(parsed_url); cr->peer_url=parsed_url; - cr->route=route; + cr->route=ms_strdup(linphone_core_get_route(lc)); lc->chatrooms=ms_list_append(lc->chatrooms,(void *)cr); return cr; } diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index f699a2a3e..230776bda 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -1678,32 +1678,25 @@ void linphone_core_iterate(LinphoneCore *lc){ } -bool_t linphone_core_interpret_url(LinphoneCore *lc, const char *url, LinphoneAddress **real_parsed_url, char **route){ +LinphoneAddress * linphone_core_interpret_url(LinphoneCore *lc, const char *url){ enum_lookup_res_t *enumres=NULL; - LinphoneAddress *parsed_url=NULL; char *enum_domain=NULL; LinphoneProxyConfig *proxy=lc->default_proxy;; char *tmpurl; - const char *tmproute; LinphoneAddress *uri; - if (real_parsed_url!=NULL) *real_parsed_url=NULL; - *route=NULL; - tmproute=linphone_core_get_route(lc); - if (is_enum(url,&enum_domain)){ lc->vtable.display_status(lc,_("Looking for telephone number destination...")); if (enum_lookup(enum_domain,&enumres)<0){ lc->vtable.display_status(lc,_("Could not resolve this number.")); ms_free(enum_domain); - return FALSE; + return NULL; } ms_free(enum_domain); tmpurl=enumres->sip_address[0]; - if (real_parsed_url!=NULL) *real_parsed_url=linphone_address_new(tmpurl); + uri=linphone_address_new(tmpurl); enum_lookup_res_free(enumres); - if (tmproute) *route=ms_strdup(tmproute); - return TRUE; + return uri; } /* check if we have a "sip:" */ if (strstr(url,"sip:")==NULL){ @@ -1714,8 +1707,7 @@ bool_t linphone_core_interpret_url(LinphoneCore *lc, const char *url, LinphoneAd uri=linphone_address_new(tmpurl); ms_free(tmpurl); if (uri){ - if (real_parsed_url!=NULL) *real_parsed_url=uri; - return TRUE; + return uri; } } @@ -1725,31 +1717,24 @@ bool_t linphone_core_interpret_url(LinphoneCore *lc, const char *url, LinphoneAd char normalized_username[128]; uri=linphone_address_new(identity); if (uri==NULL){ - return FALSE; + return NULL; } linphone_address_set_display_name(uri,NULL); linphone_proxy_config_normalize_number(proxy,url,normalized_username, sizeof(normalized_username)); linphone_address_set_username(uri,normalized_username); - - if (real_parsed_url!=NULL) *real_parsed_url=uri; - if (tmproute) *route=ms_strdup(tmproute); - return TRUE; - }else return FALSE; + return uri; + }else return NULL; } - parsed_url=linphone_address_new(url); - if (parsed_url!=NULL){ - if (real_parsed_url!=NULL) *real_parsed_url=parsed_url; - else linphone_address_destroy(parsed_url); - if (tmproute) *route=ms_strdup(tmproute); - - return TRUE; + uri=linphone_address_new(url); + if (uri!=NULL){ + return uri; } /* else we could not do anything with url given by user, so display an error */ if (lc->vtable.display_warning!=NULL){ lc->vtable.display_warning(lc,_("Could not parse given sip address. A sip url usually looks like sip:user@domain")); } - return FALSE; + return NULL; } /** @@ -1890,16 +1875,32 @@ int linphone_core_start_invite(LinphoneCore *lc, LinphoneCall *call, LinphonePro * * @ingroup call_control * @param lc the LinphoneCore object + * @param url the destination of the call (sip address, or phone number). +**/ +int linphone_core_invite(LinphoneCore *lc, const char *url){ + LinphoneAddress *addr=linphone_core_interpret_url(lc,url); + if (addr){ + int err=linphone_core_invite_address(lc,addr); + linphone_address_destroy(addr); + return err; + } + return -1; +} + +/** + * Initiates an outgoing call given a destination LinphoneAddress + * + * @ingroup call_control + * @param lc the LinphoneCore object * @param url the destination of the call (sip address). **/ -int linphone_core_invite(LinphoneCore *lc, const char *url) +int linphone_core_invite_address(LinphoneCore *lc, const LinphoneAddress *real_parsed_url) { int err=0; - char *route=NULL; + const char *route=NULL; const char *from=NULL; LinphoneProxyConfig *proxy=NULL; LinphoneAddress *parsed_url2=NULL; - LinphoneAddress *real_parsed_url=NULL; char *real_url=NULL; LinphoneProxyConfig *dest_proxy=NULL; LinphoneCall *call; @@ -1910,9 +1911,8 @@ int linphone_core_invite(LinphoneCore *lc, const char *url) } linphone_core_get_default_proxy(lc,&proxy); - if (!linphone_core_interpret_url(lc,url,&real_parsed_url,&route)){ - return -1; - } + route=linphone_core_get_route(lc); + real_url=linphone_address_as_string(real_parsed_url); dest_proxy=linphone_core_lookup_known_proxy(lc,real_parsed_url); @@ -1931,7 +1931,7 @@ int linphone_core_invite(LinphoneCore *lc, const char *url) parsed_url2=linphone_address_new(from); - call=linphone_call_new_outgoing(lc,parsed_url2,real_parsed_url); + call=linphone_call_new_outgoing(lc,parsed_url2,linphone_address_clone(real_parsed_url)); sal_op_set_route(call->op,route); lc->call=call; @@ -1946,21 +1946,19 @@ int linphone_core_invite(LinphoneCore *lc, const char *url) } if (real_url!=NULL) ms_free(real_url); - if (route!=NULL) ms_free(route); return err; } int linphone_core_refer(LinphoneCore *lc, const char *url) { char *real_url=NULL; - LinphoneAddress *real_parsed_url=NULL; + LinphoneAddress *real_parsed_url=linphone_core_interpret_url(lc,url); LinphoneCall *call; - char *route; - if (!linphone_core_interpret_url(lc,url,&real_parsed_url, &route)){ + + if (!real_parsed_url){ /* bad url */ return -1; } - if (route!=NULL) ms_free(route); call=lc->call; if (call==NULL){ ms_warning("No established call to refer."); diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index 56c34c0a2..2006453b3 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -467,8 +467,12 @@ LinphoneCore *linphone_core_new(const LinphoneCoreVTable *vtable, /* function to be periodically called in a main loop */ void linphone_core_iterate(LinphoneCore *lc); +LinphoneAddress * linphone_core_interpret_url(LinphoneCore *lc, const char *url); + int linphone_core_invite(LinphoneCore *lc, const char *url); +int linphone_core_invite_address(LinphoneCore *lc, const LinphoneAddress *addr); + int linphone_core_refer(LinphoneCore *lc, const char *url); bool_t linphone_core_inc_invite_pending(LinphoneCore*lc); diff --git a/coreapi/private.h b/coreapi/private.h index cbb767207..4125936ff 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -177,7 +177,6 @@ void linphone_core_start_media_streams(LinphoneCore *lc, struct _LinphoneCall *c void linphone_core_stop_media_streams(LinphoneCore *lc, struct _LinphoneCall *call); const char * linphone_core_get_identity(LinphoneCore *lc); const char * linphone_core_get_route(LinphoneCore *lc); -bool_t linphone_core_interpret_url(LinphoneCore *lc, const char *url, LinphoneAddress **real_parsed_url, char **route); void linphone_core_start_waiting(LinphoneCore *lc, const char *purpose); void linphone_core_update_progress(LinphoneCore *lc, const char *purpose, float progresses); void linphone_core_stop_waiting(LinphoneCore *lc); diff --git a/coreapi/sal_eXosip2_presence.c b/coreapi/sal_eXosip2_presence.c index 11104b8d1..760d8fd8d 100644 --- a/coreapi/sal_eXosip2_presence.c +++ b/coreapi/sal_eXosip2_presence.c @@ -424,7 +424,7 @@ int sal_notify_close(SalOp *op){ if (identity==NULL) identity=sal_op_get_to(op); osip_message_set_contact(msg,identity); eXosip_insubscription_send_request(op->did,msg); - }else ms_error("could not create notify for incoming subscription."); + }else ms_error("sal_notify_close(): could not create notify for incoming subscription."); eXosip_unlock(); return 0; } From faaaa22fba68d6b0cc5d3c9a42f0215c5dec5180 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Tue, 16 Mar 2010 12:43:11 +0100 Subject: [PATCH 34/50] add user data in proxy config --- coreapi/linphonecore.h | 8 ++++++++ coreapi/linphonecore_jni.cc | 14 +++++++++++++- coreapi/private.h | 1 + coreapi/proxy.c | 8 ++++++++ 4 files changed, 30 insertions(+), 1 deletion(-) diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index c9f072f6e..07a108540 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -238,6 +238,14 @@ SipSetup *linphone_proxy_config_get_sip_setup(LinphoneProxyConfig *cfg); * normalize a human readable phone number into a basic string. 888-444-222 becomes 888444222 */ int linphone_proxy_config_normalize_number(LinphoneProxyConfig *proxy, const char *username, char *result, size_t result_len); +/* + * attached a user data to a proxy config + */ +void linphone_proxy_config_set_user_data(LinphoneProxyConfig *cr, void * ud); +/* + * get user data to a proxy config. return null if any + */ +void * linphone_proxy_config_get_user_data(LinphoneProxyConfig *cr); /** * @} diff --git a/coreapi/linphonecore_jni.cc b/coreapi/linphonecore_jni.cc index a133e2116..7acf1cede 100644 --- a/coreapi/linphonecore_jni.cc +++ b/coreapi/linphonecore_jni.cc @@ -193,6 +193,10 @@ extern "C" int Java_org_linphone_core_LinphoneCoreImpl_addProxyConfig( JNIEnv* ,jobject thiz ,jlong lc ,jlong pc) { + LinphoneProxyConfig* proxy = (LinphoneProxyConfig*)pc; + linphone_proxy_config_set_user_data(proxy + ,env->NewGlobalRef((jobject)linphone_proxy_config_get_user_data(proxy))); + return linphone_core_add_proxy_config((LinphoneCore*)lc,(LinphoneProxyConfig*)pc); } @@ -281,10 +285,18 @@ extern "C" float Java_org_linphone_core_LinphoneCoreImpl_getSoftPlayLevel( JNIEn return linphone_core_get_soft_play_level((LinphoneCore*)lc); } +extern "C" void Java_org_linphone_core_LinphoneCoreImpl_muteMic( JNIEnv* env + ,jobject thiz + ,jlong lc + ,jboolean isMuted) { + linphone_core_mute_mic((LinphoneCore*)lc,isMuted); +} //ProxyConfig extern "C" jlong Java_org_linphone_core_LinphoneProxyConfigImpl_newLinphoneProxyConfig(JNIEnv* env,jobject thiz) { - return (jlong) linphone_proxy_config_new(); + LinphoneProxyConfig* proxy = linphone_proxy_config_new(); + linphone_proxy_config_set_user_data(proxy,thiz); + return (jlong) proxy; } extern "C" void Java_org_linphone_core_LinphoneProxyConfigImpl_delete(JNIEnv* env,jobject thiz,jlong ptr) { diff --git a/coreapi/private.h b/coreapi/private.h index d2b206b6e..6fc176116 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -203,6 +203,7 @@ struct _LinphoneProxyConfig bool_t registered; bool_t publish; bool_t dial_escape_plus; + void* user_data; }; struct _LinphoneAuthInfo diff --git a/coreapi/proxy.c b/coreapi/proxy.c index ad59c06f8..d31046b80 100644 --- a/coreapi/proxy.c +++ b/coreapi/proxy.c @@ -737,5 +737,13 @@ void linphone_account_creator_destroy(LinphoneAccountCreator *obj){ } } +void linphone_proxy_config_set_user_data(LinphoneProxyConfig *cr, void * ud) { + cr->user_data=ud; +} + +void * linphone_proxy_config_get_user_data(LinphoneProxyConfig *cr) { + return cr->user_data; +} + From 58c0d50bb2816dfe1660529df84aeb750888ad4f Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Tue, 16 Mar 2010 15:49:58 +0100 Subject: [PATCH 35/50] take in account closed incoming subscriptions --- coreapi/friend.c | 3 ++- coreapi/presence.c | 5 ++++- coreapi/private.h | 1 + coreapi/sal_eXosip2.c | 14 +++++++++++++- coreapi/sal_eXosip2.h | 2 ++ coreapi/sal_eXosip2_presence.c | 24 +++++++++++++++++++++--- 6 files changed, 43 insertions(+), 6 deletions(-) diff --git a/coreapi/friend.c b/coreapi/friend.c index 68f43e659..047749e32 100644 --- a/coreapi/friend.c +++ b/coreapi/friend.c @@ -296,6 +296,7 @@ static void linphone_friend_unsubscribe(LinphoneFriend *lf){ sal_unsubscribe(lf->outsub); sal_op_release(lf->outsub); lf->outsub=NULL; + lf->subscribe_active=FALSE; } } @@ -362,7 +363,7 @@ void linphone_friend_apply(LinphoneFriend *fr, LinphoneCore *lc){ } fr->inc_subscribe_pending=FALSE; } - if (fr->subscribe && fr->outsub==NULL){ + if (fr->subscribe && fr->subscribe_active==FALSE){ __linphone_friend_do_subscribe(fr); } diff --git a/coreapi/presence.c b/coreapi/presence.c index 0ff498ff7..aa3c17bd2 100644 --- a/coreapi/presence.c +++ b/coreapi/presence.c @@ -128,6 +128,7 @@ void linphone_notify_recv(LinphoneCore *lc, SalOp *op, SalSubscribeState ss, Sal friend=lf->uri; tmp=linphone_address_as_string(friend); lf->status=estatus; + lf->subscribe_active=TRUE; lc->vtable.notify_recv(lc,(LinphoneFriend*)lf); ms_free(tmp); }else{ @@ -135,8 +136,10 @@ void linphone_notify_recv(LinphoneCore *lc, SalOp *op, SalSubscribeState ss, Sal } if (ss==SalSubscribeTerminated){ sal_op_release(op); - if (lf) + if (lf){ lf->outsub=NULL; + lf->subscribe_active=FALSE; + } } } diff --git a/coreapi/private.h b/coreapi/private.h index 4125936ff..fcaddfb67 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -236,6 +236,7 @@ struct _LinphoneFriend{ BuddyInfo *info; char *refkey; bool_t subscribe; + bool_t subscribe_active; bool_t inc_subscribe_pending; }; diff --git a/coreapi/sal_eXosip2.c b/coreapi/sal_eXosip2.c index 5f337b3fa..17eb3c004 100644 --- a/coreapi/sal_eXosip2.c +++ b/coreapi/sal_eXosip2.c @@ -1308,6 +1308,10 @@ static bool_t process_event(Sal *sal, eXosip_event_t *ev){ ms_message("CALL_SUBSCRIPTION_NEW "); sal_exosip_subscription_recv(sal,ev); break; + case EXOSIP_IN_SUBSCRIPTION_RELEASED: + ms_message("CALL_SUBSCRIPTION_NEW "); + sal_exosip_in_subscription_closed(sal,ev); + break; case EXOSIP_SUBSCRIPTION_UPDATE: ms_message("CALL_SUBSCRIPTION_UPDATE"); break; @@ -1323,6 +1327,14 @@ static bool_t process_event(Sal *sal, eXosip_event_t *ev){ ms_message("EXOSIP_SUBSCRIPTION_CLOSED\n"); sal_exosip_subscription_closed(sal,ev); break; + case EXOSIP_SUBSCRIPTION_REQUESTFAILURE: /**< announce a request failure */ + if (ev->response && (ev->response->status_code == 407 || ev->response->status_code == 401)){ + return process_authentication(sal,ev); + } + case EXOSIP_SUBSCRIPTION_SERVERFAILURE: + case EXOSIP_SUBSCRIPTION_GLOBALFAILURE: + sal_exosip_subscription_closed(sal,ev); + break; case EXOSIP_CALL_RELEASED: ms_message("CALL_RELEASED\n"); call_released(sal, ev); @@ -1351,7 +1363,7 @@ static bool_t process_event(Sal *sal, eXosip_event_t *ev){ } break; default: - ms_message("Unhandled exosip event ! %i"); + ms_message("Unhandled exosip event ! %i",ev->type); break; } return TRUE; diff --git a/coreapi/sal_eXosip2.h b/coreapi/sal_eXosip2.h index 6539dcae8..93def2d6f 100644 --- a/coreapi/sal_eXosip2.h +++ b/coreapi/sal_eXosip2.h @@ -67,6 +67,8 @@ void sal_exosip_subscription_answered(Sal *sal,eXosip_event_t *ev); void sal_exosip_notify_recv(Sal *sal,eXosip_event_t *ev); void sal_exosip_subscription_closed(Sal *sal,eXosip_event_t *ev); +void sal_exosip_in_subscription_closed(Sal *sal, eXosip_event_t *ev); + void sal_exosip_fix_route(SalOp *op); diff --git a/coreapi/sal_eXosip2_presence.c b/coreapi/sal_eXosip2_presence.c index 760d8fd8d..03aef7821 100644 --- a/coreapi/sal_eXosip2_presence.c +++ b/coreapi/sal_eXosip2_presence.c @@ -661,15 +661,33 @@ void sal_exosip_subscription_answered(Sal *sal,eXosip_event_t *ev){ op->did=ev->did; } -void sal_exosip_subscription_closed(Sal *sal,eXosip_event_t *ev){ - SalOp *op=sal_find_in_subscribe(sal,ev->sid); +void sal_exosip_in_subscription_closed(Sal *sal, eXosip_event_t *ev){ + SalOp *op=sal_find_in_subscribe(sal,ev->nid); + char *tmp; if (op==NULL){ - ms_error("Subscription closed but no associated op !"); + ms_error("Incoming subscription closed but no associated op !"); return; } + if (ev->request){ + osip_from_to_str(ev->request->from,&tmp); + sal->callbacks.subscribe_closed(op,tmp); + osip_free(tmp); + } + sal_remove_in_subscribe(sal,op); op->nid=-1; op->did=-1; } +void sal_exosip_subscription_closed(Sal *sal,eXosip_event_t *ev){ + SalOp *op=sal_find_out_subscribe(sal,ev->sid); + if (op==NULL){ + ms_error("Subscription closed but no associated op !"); + return; + } + sal_remove_out_subscribe(sal,op); + op->sid=-1; + op->did=-1; +} + From 180a835ed6535691f7d41b2dc6e15de2d0b83010 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Tue, 16 Mar 2010 16:28:14 +0100 Subject: [PATCH 36/50] fix bug causing double subscribe. --- coreapi/friend.c | 3 ++- coreapi/sal_eXosip2.c | 2 +- coreapi/sal_eXosip2_presence.c | 15 +++++++++------ 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/coreapi/friend.c b/coreapi/friend.c index 047749e32..d5377952d 100644 --- a/coreapi/friend.c +++ b/coreapi/friend.c @@ -152,6 +152,7 @@ void __linphone_friend_do_subscribe(LinphoneFriend *fr){ fr->outsub=sal_op_new(fr->lc->sal); sal_op_set_route(fr->outsub,route); sal_subscribe_presence(fr->outsub,from,friend); + fr->subscribe_active=TRUE; ms_free(friend); } @@ -364,7 +365,7 @@ void linphone_friend_apply(LinphoneFriend *fr, LinphoneCore *lc){ fr->inc_subscribe_pending=FALSE; } if (fr->subscribe && fr->subscribe_active==FALSE){ - + ms_message("Sending a new SUBSCRIBE"); __linphone_friend_do_subscribe(fr); } ms_message("linphone_friend_apply() done."); diff --git a/coreapi/sal_eXosip2.c b/coreapi/sal_eXosip2.c index 17eb3c004..8fa1ec016 100644 --- a/coreapi/sal_eXosip2.c +++ b/coreapi/sal_eXosip2.c @@ -1305,7 +1305,7 @@ static bool_t process_event(Sal *sal, eXosip_event_t *ev){ } break; case EXOSIP_IN_SUBSCRIPTION_NEW: - ms_message("CALL_SUBSCRIPTION_NEW "); + ms_message("CALL_IN_SUBSCRIPTION_NEW "); sal_exosip_subscription_recv(sal,ev); break; case EXOSIP_IN_SUBSCRIPTION_RELEASED: diff --git a/coreapi/sal_eXosip2_presence.c b/coreapi/sal_eXosip2_presence.c index 03aef7821..8b17dfea6 100644 --- a/coreapi/sal_eXosip2_presence.c +++ b/coreapi/sal_eXosip2_presence.c @@ -416,7 +416,7 @@ int sal_notify_presence(SalOp *op, SalPresenceStatus status, const char *status_ } int sal_notify_close(SalOp *op){ - osip_message_t *msg; + osip_message_t *msg=NULL; eXosip_lock(); eXosip_insubscription_build_notify(op->did,EXOSIP_SUBCRSTATE_TERMINATED,DEACTIVATED,&msg); if (msg!=NULL){ @@ -424,7 +424,8 @@ int sal_notify_close(SalOp *op){ if (identity==NULL) identity=sal_op_get_to(op); osip_message_set_contact(msg,identity); eXosip_insubscription_send_request(op->did,msg); - }else ms_error("sal_notify_close(): could not create notify for incoming subscription."); + }else ms_error("sal_notify_close(): could not create notify for incoming subscription" + " did=%i, nid=%i",op->did,op->nid); eXosip_unlock(); return 0; } @@ -668,15 +669,16 @@ void sal_exosip_in_subscription_closed(Sal *sal, eXosip_event_t *ev){ ms_error("Incoming subscription closed but no associated op !"); return; } + + + sal_remove_in_subscribe(sal,op); + op->nid=-1; + op->did=-1; if (ev->request){ osip_from_to_str(ev->request->from,&tmp); sal->callbacks.subscribe_closed(op,tmp); osip_free(tmp); } - - sal_remove_in_subscribe(sal,op); - op->nid=-1; - op->did=-1; } void sal_exosip_subscription_closed(Sal *sal,eXosip_event_t *ev){ @@ -688,6 +690,7 @@ void sal_exosip_subscription_closed(Sal *sal,eXosip_event_t *ev){ sal_remove_out_subscribe(sal,op); op->sid=-1; op->did=-1; + sal->callbacks.notify(op,SalSubscribeTerminated, SalPresenceOffline,NULL); } From 881f6024b41ae955c7b60dc18764a2b8b8a781aa Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Tue, 16 Mar 2010 17:46:08 +0100 Subject: [PATCH 37/50] add invite from address --- coreapi/linphonecore_jni.cc | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/coreapi/linphonecore_jni.cc b/coreapi/linphonecore_jni.cc index 7acf1cede..41b514546 100644 --- a/coreapi/linphonecore_jni.cc +++ b/coreapi/linphonecore_jni.cc @@ -223,6 +223,12 @@ extern "C" void Java_org_linphone_core_LinphoneCoreImpl_invite( JNIEnv* env linphone_core_invite((LinphoneCore*)lc,uri); env->ReleaseStringUTFChars(juri, uri); } +extern "C" void Java_org_linphone_core_LinphoneCoreImpl_inviteAddress( JNIEnv* env + ,jobject thiz + ,jlong lc + ,jlong to) { + linphone_core_invite_address((LinphoneCore*)lc,(LinphoneAddress*)to); +} extern "C" void Java_org_linphone_core_LinphoneCoreImpl_terminateCall( JNIEnv* env ,jobject thiz @@ -291,6 +297,17 @@ extern "C" void Java_org_linphone_core_LinphoneCoreImpl_muteMic( JNIEnv* env ,jboolean isMuted) { linphone_core_mute_mic((LinphoneCore*)lc,isMuted); } + +extern "C" jlong Java_org_linphone_core_LinphoneCoreImpl_interpretUrl( JNIEnv* env + ,jobject thiz + ,jlong lc + ,jstring jurl) { + const char* url = env->GetStringUTFChars(jurl, NULL); + jlong result = (jlong)linphone_core_interpret_url((LinphoneCore*)lc,url); + env->ReleaseStringUTFChars(jurl, url); + return result; +} + //ProxyConfig extern "C" jlong Java_org_linphone_core_LinphoneProxyConfigImpl_newLinphoneProxyConfig(JNIEnv* env,jobject thiz) { @@ -449,6 +466,15 @@ extern "C" jstring Java_org_linphone_core_LinphoneAddressImpl_toUri(JNIEnv* env ms_free(uri); return juri; } +extern "C" void Java_org_linphone_core_LinphoneAddressImpl_setDisplayName(JNIEnv* env + ,jobject thiz + ,jlong address + ,jstring jdisplayName) { + const char* displayName = env->GetStringUTFChars(jdisplayName, NULL); + linphone_address_set_display_name((LinphoneAddress*)address,displayName); + env->ReleaseStringUTFChars(jdisplayName, displayName); +} + //CallLog extern "C" jlong Java_org_linphone_core_LinphoneCallLogImpl_getFrom(JNIEnv* env From 047809f6ec96653ebeab2824c9ed7110a53604e4 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Wed, 17 Mar 2010 09:42:33 +0100 Subject: [PATCH 38/50] workaround bug in eXosip with unSUBSCRIBEs. --- coreapi/friend.c | 1 - coreapi/linphonecore.c | 2 +- coreapi/sal_eXosip2.c | 15 +++++++++++++++ coreapi/sal_eXosip2_presence.c | 35 +++++++++++++++++++++++++++++++--- 4 files changed, 48 insertions(+), 5 deletions(-) diff --git a/coreapi/friend.c b/coreapi/friend.c index d5377952d..c7d621a5e 100644 --- a/coreapi/friend.c +++ b/coreapi/friend.c @@ -302,7 +302,6 @@ static void linphone_friend_unsubscribe(LinphoneFriend *lf){ } void linphone_friend_close_subscriptions(LinphoneFriend *lf){ - linphone_friend_notify(lf,LINPHONE_STATUS_OFFLINE); linphone_friend_unsubscribe(lf); if (lf->insub){ sal_notify_close(lf->insub); diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 230776bda..35efadc56 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -1401,7 +1401,7 @@ extern const char *eXosip_get_version(); static void apply_user_agent(LinphoneCore *lc){ char ua_string[256]; - snprintf(ua_string,sizeof(ua_string),"%s/%s (eXosip2/%s)",_ua_name,_ua_version, + snprintf(ua_string,sizeof(ua_string)-1,"%s/%s (eXosip2/%s)",_ua_name,_ua_version, #ifdef HAVE_EXOSIP_GET_VERSION eXosip_get_version() #else diff --git a/coreapi/sal_eXosip2.c b/coreapi/sal_eXosip2.c index 8fa1ec016..ecd5bd24f 100644 --- a/coreapi/sal_eXosip2.c +++ b/coreapi/sal_eXosip2.c @@ -158,6 +158,9 @@ void sal_op_release(SalOp *op){ } if (op->nid!=-1){ sal_remove_in_subscribe(op->base.root,op); + if (op->call_id) + osip_call_id_free(op->call_id); + op->call_id=NULL; } if (op->pending_auth){ sal_remove_pending_auth(op->base.root,op); @@ -1135,6 +1138,17 @@ static void other_request(Sal *sal, eXosip_event_t *ev){ } } +static void masquerade_via(osip_message_t *msg, const char *ip, const char *port){ + osip_via_t *via=NULL; + osip_message_get_via(msg,0,&via); + if (via){ + osip_free(via->port); + via->port=osip_strdup(port); + osip_free(via->host); + via->host=osip_strdup(ip); + } +} + static bool_t register_again_with_updated_contact(SalOp *op, osip_message_t *orig_request, osip_message_t *last_answer){ osip_message_t *msg; const char *received; @@ -1173,6 +1187,7 @@ static bool_t register_again_with_updated_contact(SalOp *op, osip_message_t *ori } snprintf(port,sizeof(port),"%i",rport); ctt->url->port=osip_strdup(port); + masquerade_via(msg,received,port); eXosip_register_send_register(op->rid,msg); eXosip_unlock(); osip_contact_to_str(ctt,&tmp); diff --git a/coreapi/sal_eXosip2_presence.c b/coreapi/sal_eXosip2_presence.c index 8b17dfea6..9e77a173a 100644 --- a/coreapi/sal_eXosip2_presence.c +++ b/coreapi/sal_eXosip2_presence.c @@ -49,7 +49,19 @@ static SalOp * sal_find_in_subscribe(Sal *sal, int nid){ return NULL; } -static void sal_add_in_subscribe(Sal *sal, SalOp *op){ +static SalOp * sal_find_in_subscribe_by_call_id(Sal *sal, osip_call_id_t *call_id){ + const MSList *elem; + SalOp *op; + for(elem=sal->in_subscribes;elem!=NULL;elem=elem->next){ + op=(SalOp*)elem->data; + if (op->call_id && osip_call_id_match(op->call_id,call_id)==0) + return op; + } + return NULL; +} + +static void sal_add_in_subscribe(Sal *sal, SalOp *op, osip_message_t *subs){ + osip_call_id_clone(subs->call_id,&op->call_id); sal->in_subscribes=ms_list_append(sal->in_subscribes,op); } @@ -423,6 +435,7 @@ int sal_notify_close(SalOp *op){ const char *identity=sal_op_get_contact(op); if (identity==NULL) identity=sal_op_get_to(op); osip_message_set_contact(msg,identity); + add_presence_body(msg,SalPresenceOffline); eXosip_insubscription_send_request(op->did,msg); }else ms_error("sal_notify_close(): could not create notify for incoming subscription" " did=%i, nid=%i",op->did,op->nid); @@ -582,7 +595,7 @@ int sal_publish(SalOp *op, const char *from, const char *to, SalPresenceStatus p return 0; } -void sal_exosip_subscription_recv(Sal *sal, eXosip_event_t *ev){ +static void _sal_exosip_subscription_recv(Sal *sal, eXosip_event_t *ev){ SalOp *op=sal_op_new(sal); char *tmp; op->did=ev->did; @@ -594,10 +607,26 @@ void sal_exosip_subscription_recv(Sal *sal, eXosip_event_t *ev){ osip_from_to_str(ev->request->to,&tmp); sal_op_set_to(op,tmp); ms_free(tmp); - sal_add_in_subscribe(sal,op); + sal_add_in_subscribe(sal,op,ev->request); sal->callbacks.subscribe_received(op,sal_op_get_from(op)); } +void sal_exosip_subscription_recv(Sal *sal, eXosip_event_t *ev){ + /*workaround a bug in eXosip: incoming SUBSCRIBES within dialog with expires: 0 are + recognized as new incoming subscribes*/ + SalOp *op=sal_find_in_subscribe_by_call_id(sal,ev->request->call_id); + if (op){ + osip_header_t *h; + osip_message_header_get_byname(ev->request,"expires",0,&h); + if (h && h->hvalue && atoi(h->hvalue)==0){ + ms_warning("This susbscribe is not a new one but terminates an old one."); + ev->did=op->did; + ev->nid=op->nid; + sal_exosip_subscription_closed(sal,ev); + }else ms_warning("Probably a refresh subscribe"); + }else _sal_exosip_subscription_recv(sal,ev); +} + void sal_exosip_notify_recv(Sal *sal, eXosip_event_t *ev){ SalOp *op=sal_find_out_subscribe(sal,ev->sid); char *tmp; From 6594a22dfbb1b2f3be16a64fedd8e75951c36d3d Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Wed, 17 Mar 2010 12:07:26 +0100 Subject: [PATCH 39/50] workaround un-answered refresh request ! --- coreapi/linphonecore.c | 20 ++++++++++++-------- coreapi/sal_eXosip2_presence.c | 13 ++++++++++--- mediastreamer2 | 2 +- 3 files changed, 23 insertions(+), 12 deletions(-) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 35efadc56..2e5c78f36 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -2105,20 +2105,24 @@ static RtpProfile *make_profile(LinphoneCore *lc, const SalStreamDescription *de const MSList *elem; RtpProfile *prof=rtp_profile_new("Call profile"); bool_t first=TRUE; - 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); + for(elem=desc->payloads;elem!=NULL;elem=elem->next){ PayloadType *pt=(PayloadType*)elem->data; + + if (first) { + if (desc->type==SalAudio){ + linphone_core_update_allocated_audio_bandwidth_in_call(lc,pt); + } + *used_pt=payload_type_get_number(pt); + first=FALSE; + } + 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); if (bw>0) pt->normal_bitrate=bw*1000; else if (desc->type==SalAudio){ pt->normal_bitrate=-1; } - if (first) { - *used_pt=payload_type_get_number(pt); - first=FALSE; - } if (desc->ptime>0){ char tmp[40]; snprintf(tmp,sizeof(tmp),"ptime=%i",desc->ptime); diff --git a/coreapi/sal_eXosip2_presence.c b/coreapi/sal_eXosip2_presence.c index 9e77a173a..9d5641024 100644 --- a/coreapi/sal_eXosip2_presence.c +++ b/coreapi/sal_eXosip2_presence.c @@ -127,8 +127,8 @@ int sal_unsubscribe(SalOp *op){ int sal_subscribe_accept(SalOp *op){ osip_message_t *msg; eXosip_lock(); - eXosip_insubscription_build_answer(op->tid,200,&msg); - eXosip_insubscription_send_answer(op->tid,200,msg); + eXosip_insubscription_build_answer(op->tid,202,&msg); + eXosip_insubscription_send_answer(op->tid,202,msg); eXosip_unlock(); return 0; } @@ -623,7 +623,14 @@ void sal_exosip_subscription_recv(Sal *sal, eXosip_event_t *ev){ ev->did=op->did; ev->nid=op->nid; sal_exosip_subscription_closed(sal,ev); - }else ms_warning("Probably a refresh subscribe"); + }else { + osip_message_t *msg=NULL; + ms_warning("Probably a refresh subscribe"); + eXosip_lock(); + eXosip_insubscription_build_answer(ev->tid,202,&msg); + eXosip_insubscription_send_answer(ev->tid,202,msg); + eXosip_unlock(); + } }else _sal_exosip_subscription_recv(sal,ev); } diff --git a/mediastreamer2 b/mediastreamer2 index 5bcbcae29..6d48f5ac0 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 5bcbcae29d9cf6d22b4f6880489eafa98e100008 +Subproject commit 6d48f5ac0b1e1df8f455c7b26824dae631663cc8 From e1867cbe4e63a996091d6fe96edeeecff75ccb88 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Thu, 18 Mar 2010 16:14:12 +0100 Subject: [PATCH 40/50] fix crash in SAL, because of late 180/200 response arriving once the call is cancelled. --- coreapi/linphonecore.c | 8 ++++---- coreapi/misc.c | 6 ++++++ coreapi/sal_eXosip2.c | 35 ++++++++++++++++------------------- 3 files changed, 26 insertions(+), 23 deletions(-) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 2e5c78f36..328671adf 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -63,12 +63,12 @@ int lc_callback_obj_invoke(LCCallbackObj *obj, LinphoneCore *lc){ } -static MSList *make_codec_list(const MSList *codecs, bool_t only_one_codec){ +static MSList *make_codec_list(LinphoneCore *lc, const MSList *codecs, bool_t only_one_codec){ MSList *l=NULL; const MSList *it; for(it=codecs;it!=NULL;it=it->next){ PayloadType *pt=(PayloadType*)it->data; - if (pt->flags & PAYLOAD_TYPE_ENABLED){ + if ((pt->flags & PAYLOAD_TYPE_ENABLED) && linphone_core_check_payload_type_usability(lc,pt)){ l=ms_list_append(l,payload_type_clone(pt)); if (only_one_codec) break; } @@ -90,7 +90,7 @@ static SalMediaDescription *create_local_media_description(LinphoneCore *lc, md->streams[0].proto=SalProtoRtpAvp; md->streams[0].type=SalAudio; md->streams[0].ptime=lc->net_conf.down_ptime; - l=make_codec_list(lc->codecs_conf.audio_codecs,only_one_codec); + l=make_codec_list(lc,lc->codecs_conf.audio_codecs,only_one_codec); pt=payload_type_clone(rtp_profile_get_payload_from_mime(&av_profile,"telephone-event")); l=ms_list_append(l,pt); md->streams[0].payloads=l; @@ -103,7 +103,7 @@ static SalMediaDescription *create_local_media_description(LinphoneCore *lc, md->streams[1].port=linphone_core_get_video_port(lc); md->streams[1].proto=SalProtoRtpAvp; md->streams[1].type=SalVideo; - l=make_codec_list(lc->codecs_conf.video_codecs,only_one_codec); + l=make_codec_list(lc,lc->codecs_conf.video_codecs,only_one_codec); md->streams[1].payloads=l; if (lc->dw_video_bw) md->streams[1].bandwidth=lc->dw_video_bw; diff --git a/coreapi/misc.c b/coreapi/misc.c index 70c75d82a..c6e673547 100644 --- a/coreapi/misc.c +++ b/coreapi/misc.c @@ -276,6 +276,12 @@ bool_t linphone_core_check_payload_type_usability(LinphoneCore *lc, PayloadType case PAYLOAD_AUDIO_PACKETIZED: codec_band=get_audio_payload_bandwidth(lc,pt); ret=bandwidth_is_greater(min_audio_bw*1000,codec_band); + /*hack to avoid using uwb codecs when having low bitrate and video*/ + if (bandwidth_is_greater(199,min_audio_bw)){ + if (linphone_core_video_enabled(lc) && pt->clock_rate>16000){ + ret=FALSE; + } + } //ms_message("Payload %s: %g",pt->mime_type,codec_band); break; case PAYLOAD_VIDEO: diff --git a/coreapi/sal_eXosip2.c b/coreapi/sal_eXosip2.c index ecd5bd24f..8e1a4bbfd 100644 --- a/coreapi/sal_eXosip2.c +++ b/coreapi/sal_eXosip2.c @@ -593,6 +593,16 @@ static void set_network_origin(SalOp *op, osip_message_t *req){ __sal_op_set_network_origin(op,origin); } +static SalOp *find_op(Sal *sal, eXosip_event_t *ev){ + if (ev->cid>0) + return (SalOp*)eXosip_call_get_reference(ev->cid);; + if (ev->rid>0){ + return sal_find_register(sal,ev->rid); + } + if (ev->response) return sal_find_other(sal,ev->response); + return NULL; +} + static void inc_new_call(Sal *sal, eXosip_event_t *ev){ SalOp *op=sal_op_new(sal); osip_from_t *from,*to; @@ -626,7 +636,7 @@ static void inc_new_call(Sal *sal, eXosip_event_t *ev){ } static void handle_reinvite(Sal *sal, eXosip_event_t *ev){ - SalOp *op=(SalOp*)ev->external_reference; + SalOp *op=find_op(sal,ev); sdp_message_t *sdp; osip_message_t *msg=NULL; @@ -669,7 +679,7 @@ static void handle_reinvite(Sal *sal, eXosip_event_t *ev){ } static void handle_ack(Sal *sal, eXosip_event_t *ev){ - SalOp *op=(SalOp*)ev->external_reference; + SalOp *op=find_op(sal,ev); sdp_message_t *sdp; if (op==NULL) { @@ -714,7 +724,7 @@ static void update_contact_from_response(SalOp *op, osip_message_t *response){ } static int call_proceeding(Sal *sal, eXosip_event_t *ev){ - SalOp *op=(SalOp*)ev->external_reference; + SalOp *op=find_op(sal,ev); if (op==NULL) { ms_warning("This call has been canceled."); @@ -750,10 +760,9 @@ static void call_ringing(Sal *sal, eXosip_event_t *ev){ static void call_accepted(Sal *sal, eXosip_event_t *ev){ sdp_message_t *sdp; osip_message_t *msg=NULL; - SalOp *op; + SalOp *op=find_op(sal,ev); const char *contact; - op=(SalOp*)ev->external_reference; if (op==NULL){ ms_error("A closed call is accepted ?"); return; @@ -778,9 +787,8 @@ static void call_accepted(Sal *sal, eXosip_event_t *ev){ } static void call_terminated(Sal *sal, eXosip_event_t *ev){ - SalOp *op; char *from; - op=(SalOp*)ev->external_reference; + SalOp *op=find_op(sal,ev); if (op==NULL){ ms_warning("Call terminated for already closed call ?"); return; @@ -793,8 +801,7 @@ static void call_terminated(Sal *sal, eXosip_event_t *ev){ } static void call_released(Sal *sal, eXosip_event_t *ev){ - SalOp *op; - op=(SalOp*)ev->external_reference; + SalOp *op=find_op(sal,ev); if (op==NULL){ return; } @@ -857,16 +864,6 @@ int sal_op_get_auth_requested(SalOp *op, const char **realm, const char **userna return -1; } -static SalOp *find_op(Sal *sal, eXosip_event_t *ev){ - if (ev->external_reference) - return (SalOp*)ev->external_reference; - if (ev->rid>0){ - return sal_find_register(sal,ev->rid); - } - if (ev->response) return sal_find_other(sal,ev->response); - return NULL; -} - static bool_t process_authentication(Sal *sal, eXosip_event_t *ev){ SalOp *op; const char *username,*realm; From 93fea893b9aad5400ec63c7c43f259dd3a4f7bdc Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Fri, 19 Mar 2010 11:42:06 +0100 Subject: [PATCH 41/50] fix interrop problem with freephonie.net --- coreapi/sal_eXosip2.c | 14 +++++++++++++- coreapi/sal_eXosip2.h | 1 + 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/coreapi/sal_eXosip2.c b/coreapi/sal_eXosip2.c index 8e1a4bbfd..cc943e45a 100644 --- a/coreapi/sal_eXosip2.c +++ b/coreapi/sal_eXosip2.c @@ -138,6 +138,7 @@ SalOp * sal_op_new(Sal *sal){ op->sdp_answer=NULL; op->reinvite=FALSE; op->call_id=NULL; + op->masquerade_via=FALSE; return op; } @@ -1153,6 +1154,7 @@ static bool_t register_again_with_updated_contact(SalOp *op, osip_message_t *ori osip_contact_t *ctt=NULL; char *tmp; char port[20]; + SalAddress *addr; if (extract_received_rport(last_answer,&received,&rport)==-1) return FALSE; osip_message_get_contact(orig_request,0,&ctt); @@ -1184,10 +1186,14 @@ static bool_t register_again_with_updated_contact(SalOp *op, osip_message_t *ori } snprintf(port,sizeof(port),"%i",rport); ctt->url->port=osip_strdup(port); - masquerade_via(msg,received,port); + if (op->masquerade_via) masquerade_via(msg,received,port); eXosip_register_send_register(op->rid,msg); eXosip_unlock(); osip_contact_to_str(ctt,&tmp); + addr=sal_address_new(tmp); + osip_free(tmp); + sal_address_clean(addr); + tmp=sal_address_as_string(addr); sal_op_set_contact(op,tmp); ms_message("Resending new register with updated contact %s",tmp); ms_free(tmp); @@ -1231,6 +1237,11 @@ static bool_t registration_failure(Sal *sal, eXosip_event_t *ev){ case 407: return process_authentication(sal,ev); break; + case 606: /*Not acceptable, workaround for proxies that don't like private addresses + in vias, such as ekiga.net + On the opposite, freephonie.net bugs when via are masqueraded. + */ + op->masquerade_via=TRUE; default: /* if contact is up to date, process the failure, otherwise resend a new register with updated contact first, just in case the faillure is due to incorrect contact */ @@ -1513,6 +1524,7 @@ void sal_address_set_port_int(SalAddress *uri, int port){ void sal_address_clean(SalAddress *addr){ osip_generic_param_freelist(& ((osip_from_t*)addr)->gen_params); + osip_uri_param_freelist(& ((osip_from_t*)addr)->url->url_params); } char *sal_address_as_string(const SalAddress *u){ diff --git a/coreapi/sal_eXosip2.h b/coreapi/sal_eXosip2.h index 93def2d6f..8c4bd2438 100644 --- a/coreapi/sal_eXosip2.h +++ b/coreapi/sal_eXosip2.h @@ -57,6 +57,7 @@ struct SalOp{ bool_t supports_session_timers; bool_t sdp_offering; bool_t reinvite; + bool_t masquerade_via; }; void sal_remove_out_subscribe(Sal *sal, SalOp *op); From 1de0b99c1195f889ad0035b1b71ae5f9480b97f3 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Fri, 19 Mar 2010 17:25:17 +0100 Subject: [PATCH 42/50] add auto_net_state_mon to sip config --- coreapi/linphonecore.c | 3 ++- coreapi/linphonecore_jni.cc | 25 ++++++++++++++++++++++++- coreapi/private.h | 1 + 3 files changed, 27 insertions(+), 2 deletions(-) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 328671adf..fc9fef5f1 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -672,6 +672,7 @@ static void sip_config_read(LinphoneCore *lc) lc->sip_conf.register_only_when_network_is_up= lp_config_get_int(lc->config,"sip","register_only_when_network_is_up",1); lc->sip_conf.ping_with_options=lp_config_get_int(lc->config,"sip","ping_with_options",1); + lc->sip_conf.auto_net_state_mon=lp_config_get_int(lc->config,"sip","auto_net_state_mon",1); } static void rtp_config_read(LinphoneCore *lc) @@ -1059,7 +1060,7 @@ static void linphone_core_init (LinphoneCore * lc, const LinphoneCoreVTable *vta ui_config_read(lc); lc->vtable.display_status(lc,_("Ready")); gstate_new_state(lc, GSTATE_POWER_ON, NULL); - lc->auto_net_state_mon=TRUE; + lc->auto_net_state_mon=lc->sip_conf.auto_net_state_mon; lc->ready=TRUE; } diff --git a/coreapi/linphonecore_jni.cc b/coreapi/linphonecore_jni.cc index 41b514546..556c0e54d 100644 --- a/coreapi/linphonecore_jni.cc +++ b/coreapi/linphonecore_jni.cc @@ -150,6 +150,9 @@ extern "C" jlong Java_org_linphone_core_LinphoneCoreImpl_newLinphoneCore(JNIEnv* const char* userConfig = env->GetStringUTFChars(juserConfig, NULL); const char* factoryConfig = env->GetStringUTFChars(jfactoryConfig, NULL); LinphoneCoreData* ldata = new LinphoneCoreData(env,thiz,jlistener,juserdata); +#ifdef ANDROID + ms_andsnd_register_card(jvm); +#endif /*ANDROID*/ jlong nativePtr = (jlong)linphone_core_new( &ldata->vTable ,userConfig ,factoryConfig @@ -307,6 +310,18 @@ extern "C" jlong Java_org_linphone_core_LinphoneCoreImpl_interpretUrl( JNIEnv* env->ReleaseStringUTFChars(jurl, url); return result; } +extern "C" void Java_org_linphone_core_LinphoneCoreImpl_sendDtmf( JNIEnv* env + ,jobject thiz + ,jlong lc + ,jchar dtmf) { + linphone_core_send_dtmf((LinphoneCore*)lc,dtmf); +} +extern "C" void Java_org_linphone_core_LinphoneCoreImpl_clearCallLogs(JNIEnv* env + ,jobject thiz + ,jlong lc) { + linphone_core_clear_call_logs((LinphoneCore*)lc); +} + //ProxyConfig @@ -458,7 +473,7 @@ extern "C" jstring Java_org_linphone_core_LinphoneAddressImpl_getDomain(JNIEnv* } } -extern "C" jstring Java_org_linphone_core_LinphoneAddressImpl_toUri(JNIEnv* env +extern "C" jstring Java_org_linphone_core_LinphoneAddressImpl_toString(JNIEnv* env ,jobject thiz ,jlong ptr) { char* uri = linphone_address_as_string((LinphoneAddress*)ptr); @@ -466,6 +481,14 @@ extern "C" jstring Java_org_linphone_core_LinphoneAddressImpl_toUri(JNIEnv* env ms_free(uri); return juri; } +extern "C" jstring Java_org_linphone_core_LinphoneAddressImpl_toUri(JNIEnv* env + ,jobject thiz + ,jlong ptr) { + char* uri = linphone_address_as_string_uri_only((LinphoneAddress*)ptr); + jstring juri =env->NewStringUTF(uri); + ms_free(uri); + return juri; +} extern "C" void Java_org_linphone_core_LinphoneAddressImpl_setDisplayName(JNIEnv* env ,jobject thiz ,jlong address diff --git a/coreapi/private.h b/coreapi/private.h index 133fd1dcc..50de9c9c6 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -258,6 +258,7 @@ typedef struct sip_config bool_t only_one_codec; /*in SDP answers*/ bool_t register_only_when_network_is_up; bool_t ping_with_options; + bool_t auto_net_state_mon; } sip_config_t; typedef struct rtp_config From 902c241fffc98081753d21fd692cfa001bed8731 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Tue, 23 Mar 2010 09:47:44 +0100 Subject: [PATCH 43/50] allow to set server address without sip: --- coreapi/proxy.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/coreapi/proxy.c b/coreapi/proxy.c index d31046b80..e9aadd6c0 100644 --- a/coreapi/proxy.c +++ b/coreapi/proxy.c @@ -90,10 +90,20 @@ bool_t linphone_proxy_config_is_registered(const LinphoneProxyConfig *obj){ **/ int linphone_proxy_config_set_server_addr(LinphoneProxyConfig *obj, const char *server_addr){ LinphoneAddress *addr; + if (obj->reg_proxy!=NULL) ms_free(obj->reg_proxy); obj->reg_proxy=NULL; + if (server_addr!=NULL && strlen(server_addr)>0){ addr=linphone_address_new(server_addr); + if (!addr){ + /*try to prepend 'sip:' */ + if (strstr(server_addr,"sip:")==NULL){ + char *try=ms_strdup_printf("sip:%s",server_addr); + addr=linphone_address_new(try); + ms_free(try); + } + } if (addr){ obj->reg_proxy=ms_strdup(server_addr); linphone_address_destroy(addr); @@ -243,7 +253,7 @@ void linphone_proxy_config_set_dial_prefix(LinphoneProxyConfig *cfg, const char ms_free(cfg->dial_prefix); cfg->dial_prefix=NULL; } - if (prefix) cfg->dial_prefix=ms_strdup(prefix); + if (prefix && prefix[0]!='\0') cfg->dial_prefix=ms_strdup(prefix); } /** From f8f8b3ba3e3c46a77dda5f7b48c4711400d53a4a Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Tue, 23 Mar 2010 17:05:25 +0100 Subject: [PATCH 44/50] fix bug in linphone_proxy_config_set_server_addr fix compilation on some older version of eXosip2 --- coreapi/proxy.c | 5 +++-- coreapi/sal_eXosip2.c | 15 ++++++++++++--- m4/exosip.m4 | 4 ++++ 3 files changed, 19 insertions(+), 5 deletions(-) diff --git a/coreapi/proxy.c b/coreapi/proxy.c index e9aadd6c0..287d44652 100644 --- a/coreapi/proxy.c +++ b/coreapi/proxy.c @@ -90,6 +90,7 @@ bool_t linphone_proxy_config_is_registered(const LinphoneProxyConfig *obj){ **/ int linphone_proxy_config_set_server_addr(LinphoneProxyConfig *obj, const char *server_addr){ LinphoneAddress *addr; + char *try=NULL; if (obj->reg_proxy!=NULL) ms_free(obj->reg_proxy); obj->reg_proxy=NULL; @@ -99,13 +100,13 @@ int linphone_proxy_config_set_server_addr(LinphoneProxyConfig *obj, const char * if (!addr){ /*try to prepend 'sip:' */ if (strstr(server_addr,"sip:")==NULL){ - char *try=ms_strdup_printf("sip:%s",server_addr); + try=ms_strdup_printf("sip:%s",server_addr); addr=linphone_address_new(try); ms_free(try); } } if (addr){ - obj->reg_proxy=ms_strdup(server_addr); + obj->reg_proxy=linphone_address_as_string(addr); linphone_address_destroy(addr); }else{ ms_warning("Could not parse %s",server_addr); diff --git a/coreapi/sal_eXosip2.c b/coreapi/sal_eXosip2.c index cc943e45a..f55d3f1aa 100644 --- a/coreapi/sal_eXosip2.c +++ b/coreapi/sal_eXosip2.c @@ -16,11 +16,15 @@ You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif #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 _osip_list_set_empty(osip_list_t *l, void (*freefunc)(void*)){ void *data; @@ -595,8 +599,13 @@ 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) - return (SalOp*)eXosip_call_get_reference(ev->cid);; + 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 + } if (ev->rid>0){ return sal_find_register(sal,ev->rid); } diff --git a/m4/exosip.m4 b/m4/exosip.m4 index d3f89ee30..ae89236c8 100644 --- a/m4/exosip.m4 +++ b/m4/exosip.m4 @@ -24,6 +24,10 @@ AC_CHECK_LIB([eXosip2],[eXosip_get_version], [AC_DEFINE([HAVE_EXOSIP_GET_VERSION],[1],[Defined when eXosip_get_version is available])], [], [-losipparser2 -losip2 ]) +AC_CHECK_LIB([eXosip2],[eXosip_call_get_reference], + [], + [AC_MSG_ERROR([Could not find eXosip_call_get_reference() in eXosip2 !])], + [-losipparser2 -losip2 ]) dnl AC_CHECK_LIB([eXosip2],[eXosip_get_naptr], dnl [AC_DEFINE([HAVE_EXOSIP_NAPTR_SUPPORT],[1],[Defined when eXosip_get_naptr is available])], dnl [], From e9b6722f57ac734dcb1f71d61456075bdd8fd7a3 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Tue, 23 Mar 2010 17:17:08 +0100 Subject: [PATCH 45/50] add setDebugMode method to jni --- coreapi/linphonecore_jni.cc | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/coreapi/linphonecore_jni.cc b/coreapi/linphonecore_jni.cc index 556c0e54d..04373c159 100644 --- a/coreapi/linphonecore_jni.cc +++ b/coreapi/linphonecore_jni.cc @@ -42,8 +42,7 @@ static void linphone_android_log_handler(OrtpLogLevel lev, const char *fmt, va_l JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *ajvm, void *reserved) { - #ifdef ANDROID - linphone_core_enable_logs_with_cb(linphone_android_log_handler); +#ifdef ANDROID ms_andsnd_register_card(ajvm); #endif /*ANDROID*/ jvm=ajvm; @@ -51,7 +50,16 @@ JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *ajvm, void *reserved) } - +//LinphoneFactory +extern "C" void Java_org_linphone_core_LinphoneCoreFactory_setDebugMode(JNIEnv* env + ,jobject thiz + ,jboolean isDebug) { + if (isDebug) { + linphone_core_enable_logs_with_cb(linphone_android_log_handler); + } else { + linphone_core_disable_logs(); + } +} // LinphoneCore class LinphoneCoreData { @@ -194,11 +202,11 @@ extern "C" jlong Java_org_linphone_core_LinphoneCoreImpl_getDefaultProxyConfig( extern "C" int Java_org_linphone_core_LinphoneCoreImpl_addProxyConfig( JNIEnv* env ,jobject thiz + ,jobject jproxyCfg ,jlong lc ,jlong pc) { LinphoneProxyConfig* proxy = (LinphoneProxyConfig*)pc; - linphone_proxy_config_set_user_data(proxy - ,env->NewGlobalRef((jobject)linphone_proxy_config_get_user_data(proxy))); + linphone_proxy_config_set_user_data(proxy, env->NewGlobalRef(jproxyCfg)); return linphone_core_add_proxy_config((LinphoneCore*)lc,(LinphoneProxyConfig*)pc); } @@ -327,7 +335,6 @@ extern "C" void Java_org_linphone_core_LinphoneCoreImpl_clearCallLogs(JNIEnv* e extern "C" jlong Java_org_linphone_core_LinphoneProxyConfigImpl_newLinphoneProxyConfig(JNIEnv* env,jobject thiz) { LinphoneProxyConfig* proxy = linphone_proxy_config_new(); - linphone_proxy_config_set_user_data(proxy,thiz); return (jlong) proxy; } From 0fc72e21621aee190bea626209f256fe3597dd2e Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Tue, 23 Mar 2010 17:25:21 +0100 Subject: [PATCH 46/50] fix again bug with proxy config --- coreapi/proxy.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/coreapi/proxy.c b/coreapi/proxy.c index 287d44652..a1bf54a07 100644 --- a/coreapi/proxy.c +++ b/coreapi/proxy.c @@ -106,7 +106,7 @@ int linphone_proxy_config_set_server_addr(LinphoneProxyConfig *obj, const char * } } if (addr){ - obj->reg_proxy=linphone_address_as_string(addr); + obj->reg_proxy=linphone_address_as_string_uri_only(addr); linphone_address_destroy(addr); }else{ ms_warning("Could not parse %s",server_addr); From 3397123acbcd2996082b23982e572d1511a4d991 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Wed, 24 Mar 2010 17:06:11 +0100 Subject: [PATCH 47/50] report 487 also. --- coreapi/sal_eXosip2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/coreapi/sal_eXosip2.c b/coreapi/sal_eXosip2.c index cc943e45a..ef052532d 100644 --- a/coreapi/sal_eXosip2.c +++ b/coreapi/sal_eXosip2.c @@ -959,7 +959,7 @@ static bool_t call_failure(Sal *sal, eXosip_event_t *ev){ sr=SalReasonUnknown; }else error=SalErrorNoResponse; } - if (code!=487) sal->callbacks.call_failure(op,error,sr,reason); + sal->callbacks.call_failure(op,error,sr,reason); return TRUE; } From cfd21275fdd80909a8ad587960cd51088778ff4d Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Thu, 25 Mar 2010 13:53:15 +0100 Subject: [PATCH 48/50] update mediastreamer2 --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index 6d48f5ac0..705c57139 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 6d48f5ac0b1e1df8f455c7b26824dae631663cc8 +Subproject commit 705c57139cd2e3a7e2268dbdbe6a1c4e34392663 From 869a6a85ab79d5027538d65c960ec0207ea7aae1 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Thu, 25 Mar 2010 15:38:05 +0100 Subject: [PATCH 49/50] add linphone_core_is_mic_muted method --- coreapi/linphonecore.c | 9 +++++++++ coreapi/linphonecore.h | 6 ++++++ coreapi/linphonecore_jni.cc | 6 ++++++ mediastreamer2 | 2 +- 4 files changed, 22 insertions(+), 1 deletion(-) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index fc9fef5f1..65b11d3c3 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -2780,6 +2780,15 @@ void linphone_core_mute_mic(LinphoneCore *lc, bool_t val){ } } +bool_t linphone_core_is_mic_muted(LinphoneCore *lc) { + float gain=1.0; + if (lc->audiostream && lc->audiostream->volsend){ + ms_filter_call_method(lc->audiostream->volsend,MS_VOLUME_GET_GAIN,&gain); + }else ms_warning("Could not get gain: gain control wasn't activated. "); + + return gain==0; +} + void linphone_core_enable_agc(LinphoneCore *lc, bool_t val){ lc->sound_conf.agc=val; } diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index ee515f4e9..2582cfbee 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -667,6 +667,12 @@ void linphone_core_enable_agc(LinphoneCore *lc, bool_t val); bool_t linphone_core_agc_enabled(const LinphoneCore *lc); void linphone_core_mute_mic(LinphoneCore *lc, bool_t muted); +/** + * return mic state. + * + * @ingroup media_parameters +**/ +bool_t linphone_core_is_mic_muted(LinphoneCore *lc); void linphone_core_set_presence_info(LinphoneCore *lc,int minutes_away,const char *contact,LinphoneOnlineStatus os); diff --git a/coreapi/linphonecore_jni.cc b/coreapi/linphonecore_jni.cc index 04373c159..e65193e3b 100644 --- a/coreapi/linphonecore_jni.cc +++ b/coreapi/linphonecore_jni.cc @@ -329,6 +329,12 @@ extern "C" void Java_org_linphone_core_LinphoneCoreImpl_clearCallLogs(JNIEnv* e ,jlong lc) { linphone_core_clear_call_logs((LinphoneCore*)lc); } +extern "C" jboolean Java_org_linphone_core_LinphoneCoreImpl_isMicMuted( JNIEnv* env + ,jobject thiz + ,jlong lc) { + return linphone_core_is_mic_muted((LinphoneCore*)lc); +} + //ProxyConfig diff --git a/mediastreamer2 b/mediastreamer2 index 6d48f5ac0..af7bfe348 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 6d48f5ac0b1e1df8f455c7b26824dae631663cc8 +Subproject commit af7bfe348919a44cec3f10cc3a3b5ade3483784f From 549bee3830475f9b078e2ca6fe3e1e0aea68ed5e Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Thu, 25 Mar 2010 16:23:26 +0100 Subject: [PATCH 50/50] fix several memory leaks. --- coreapi/linphonecore.c | 29 +++++++++++++++++++++++------ coreapi/presence.c | 1 + coreapi/sal_eXosip2.c | 1 + 3 files changed, 25 insertions(+), 6 deletions(-) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 65b11d3c3..dbdd77c26 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -661,6 +661,7 @@ static void sip_config_read(LinphoneCore *lc) LinphoneAuthInfo *ai=linphone_auth_info_new_from_config_file(lc->config,i); if (ai!=NULL){ linphone_core_add_auth_info(lc,ai); + linphone_auth_info_destroy(ai); }else{ break; } @@ -3242,14 +3243,16 @@ void net_config_uninit(LinphoneCore *lc) lp_config_set_int(lc->config,"net","download_bw",config->download_bw); lp_config_set_int(lc->config,"net","upload_bw",config->upload_bw); - if (config->stun_server!=NULL) + if (config->stun_server!=NULL){ lp_config_set_string(lc->config,"net","stun_server",config->stun_server); - if (config->nat_address!=NULL) - lp_config_set_string(lc->config,"net","nat_address",config->nat_address); - lp_config_set_int(lc->config,"net","firewall_policy",config->firewall_policy); - lp_config_set_int(lc->config,"net","mtu",config->mtu); - if (lc->net_conf.stun_server!=NULL) ms_free(lc->net_conf.stun_server); + } + if (config->nat_address!=NULL){ + lp_config_set_string(lc->config,"net","nat_address",config->nat_address); + ms_free(lc->net_conf.nat_address); + } + lp_config_set_int(lc->config,"net","firewall_policy",config->firewall_policy); + lp_config_set_int(lc->config,"net","mtu",config->mtu); } @@ -3301,8 +3304,15 @@ void sip_config_uninit(LinphoneCore *lc) ms_list_for_each(lc->auth_info,(void (*)(void*))linphone_auth_info_destroy); ms_list_free(lc->auth_info); lc->auth_info=NULL; + sal_uninit(lc->sal); lc->sal=NULL; + + if (lc->sip_conf.guessed_contact) + ms_free(lc->sip_conf.guessed_contact); + if (config->contact) + ms_free(config->contact); + } void rtp_config_uninit(LinphoneCore *lc) @@ -3335,6 +3345,8 @@ void video_config_uninit(LinphoneCore *lc) lp_config_set_int(lc->config,"video","capture",lc->video_conf.capture); lp_config_set_int(lc->config,"video","show_local",linphone_core_video_preview_enabled(lc)); lp_config_set_int(lc->config,"video","self_view",linphone_core_self_view_enabled(lc)); + if (lc->video_conf.cams) + ms_free(lc->video_conf.cams); } void codecs_config_uninit(LinphoneCore *lc) @@ -3363,6 +3375,8 @@ void codecs_config_uninit(LinphoneCore *lc) lp_config_set_string(lc->config,key,"recv_fmtp",pt->recv_fmtp); index++; } + ms_list_free(lc->codecs_conf.audio_codecs); + ms_list_free(lc->codecs_conf.video_codecs); } void ui_config_uninit(LinphoneCore* lc) @@ -3422,6 +3436,9 @@ static void linphone_core_uninit(LinphoneCore *lc) lc->config = NULL; /* Mark the config as NULL to block further calls */ sip_setup_unregister_all(); + ms_list_for_each(lc->call_logs,(void (*)(void*))linphone_call_log_destroy); + lc->call_logs=ms_list_free(lc->call_logs); + linphone_core_free_payload_types(); ortp_exit(); diff --git a/coreapi/presence.c b/coreapi/presence.c index aa3c17bd2..4367130d5 100644 --- a/coreapi/presence.c +++ b/coreapi/presence.c @@ -84,6 +84,7 @@ void linphone_subscription_new(LinphoneCore *lc, SalOp *op, const char *from){ linphone_core_add_subscriber(lc,tmp,op); } } + linphone_address_destroy(uri); ms_free(tmp); } diff --git a/coreapi/sal_eXosip2.c b/coreapi/sal_eXosip2.c index 38ba14c91..d4ce598a3 100644 --- a/coreapi/sal_eXosip2.c +++ b/coreapi/sal_eXosip2.c @@ -1204,6 +1204,7 @@ static bool_t register_again_with_updated_contact(SalOp *op, osip_message_t *ori sal_address_clean(addr); tmp=sal_address_as_string(addr); sal_op_set_contact(op,tmp); + sal_address_destroy(addr); ms_message("Resending new register with updated contact %s",tmp); ms_free(tmp); return TRUE;