+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
-bin_PROGRAMS = linphonec sipomatic linphonecsh
+bin_PROGRAMS = linphonec linphonecsh
if BUILD_WIN32
bin_PROGRAMS += linphoned
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));
{
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);
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;
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);
linphone_auth_info_destroy(info);
}
- osip_from_free(from);
}
elem=linphone_core_get_proxy_config_list(lc);
if (elem) {
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++;
}
}
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);
* 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)
}
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 \
misc.c \
address.c \
enum.c enum.h \
- sdphandler.c sdphandler.h \
presence.c \
proxy.c \
friend.c \
authentication.c \
lpconfig.c lpconfig.h \
chat.c \
- general_state.c \
+ general_state.c \
sipsetup.c sipsetup.h \
siplogin.c
#include "linphonecore.h"
#include "lpconfig.h"
#include "private.h"
-#include <eXosip2/eXosip.h>
/**
* @addtogroup linphone_address
* 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);
- ms_error("Cannot create LinphoneAddress, bad uri [%s]",uri);
- return NULL;
- }
- return from;
+LinphoneAddress * linphone_address_new(const char *addr){
+ SalAddress *saddr=sal_address_new(addr);
+ if (saddr==NULL) ms_error("Cannot create LinphoneAddress, bad uri [%s]",addr);
+ return saddr;
}
/**
* 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);
}
/**
* 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);
}
/**
* 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);
}
#include "linphonecore.h"
#include "private.h"
-#include <eXosip2/eXosip.h>
-#include <osipparser2/osip_message.h>
#include "lpconfig.h"
-extern LinphoneProxyConfig *linphone_core_get_proxy_config_from_rid(LinphoneCore *lc, int rid);
-
/**
* @addtogroup authentication
* @{
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;
}
if (ai->ha1) obj->ha1=ms_strdup(ai->ha1);
if (ai->realm) obj->realm=ms_strdup(ai->realm);
obj->works=FALSE;
- obj->first_time=TRUE;
+ obj->usecount=0;
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.
**/
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.
*
void linphone_core_add_auth_info(LinphoneCore *lc, const LinphoneAuthInfo *info)
{
LinphoneAuthInfo *ai;
+ MSList *elem;
/* find if we are attempting to modify an existing auth info */
ai=(LinphoneAuthInfo*)linphone_core_find_auth_info(lc,info->realm,info->username);
linphone_auth_info_destroy(ai);
}
lc->auth_info=ms_list_append(lc->auth_info,linphone_auth_info_clone(info));
-
- refresh_exosip_auth_info(lc);
- /* if the user was prompted, re-allow automatic_action */
- if (lc->automatic_action>0) lc->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=(LinphoneAuthInfo*)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++;
+ }
+ }
}
* 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--;
}
/**
linphone_auth_info_write_config(lc->config,(LinphoneAuthInfo*)elem->data,i);
}
linphone_auth_info_write_config(lc->config,NULL,i);
- refresh_exosip_auth_info(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);
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=(LinphoneAuthInfo*)linphone_core_find_auth_info(lc,prx_realm,username);
- if (www_realm!=NULL)
- as=(LinphoneAuthInfo*)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=(LinphoneAuthInfo*)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);
-}
-
-
/**
* @}
**/
--- /dev/null
+/*
+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"
+#include "mediastreamer2/mediastream.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_sal(h));
+ char *barmesg;
+ 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(h);
+ return;
+ }
+ if (lc->call!=NULL){/*busy*/
+ sal_call_decline(h,SalReasonBusy,NULL);
+ sal_op_release(h);
+ return;
+ }
+ 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),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);
+ lc->call=NULL;
+ return;
+ }
+
+ 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 is contacting you"),tmp);
+ 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(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);
+}
+
+static void call_ringing(SalOp *h){
+ LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(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 && 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->media_pending=TRUE;
+ }
+ call->state=LCStateRinging;
+}
+
+static void call_accepted(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 accept.");
+ return ;
+ }
+ if (sal_op_get_user_pointer(op)!=lc->call){
+ ms_warning("call_accepted: ignoring.");
+ return;
+ }
+ if (call->state==LCStateAVRunning){
+ return ; /*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_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);
+ }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 *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");
+ return ;
+ }
+ if (sal_op_get_user_pointer(op)!=lc->call){
+ ms_warning("call_ack: ignoring.");
+ return;
+ }
+ 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;
+ }
+}
+
+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)
+ 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 *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;
+ }
+ 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(addr);
+ 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 *op, SalError error, SalReason sr, const char *details){
+ 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.");
+ 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->vtable.display_status)
+ lc->vtable.display_status(lc,_("No response."));
+ }else if (error==SalErrorProtocol){
+ if (lc->vtable.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,_("Not found"));
+ 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,call);
+ 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_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{
+ 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=(LinphoneAuthInfo*)linphone_core_find_auth_info(lc,realm,username);
+ if (ai){
+ ms_message("%s/%s authentication works.",realm,username);
+ 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);
+ 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)
+ 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(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 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 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);
+}
+
+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,
+ 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,
+ notify,
+ subscribe_received,
+ subscribe_closed,
+ internal_message,
+ ping_reply
+};
+
+
#include "linphonecore.h"
#include "private.h"
- #include <eXosip2/eXosip.h>
LinphoneChatRoom * linphone_core_create_chat_room(LinphoneCore *lc, const char *to){
LinphoneAddress *parsed_url=NULL;
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){
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);
}
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);
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;
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;
}
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;
case LINPHONE_STATUS_PENDING:
str=_("Pending");
break;
- case LINPHONE_STATUS_CLOSED:
- str=_("Closed");
- break;
default:
str=_("Unknown-bug");
}
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;
}
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");
- }
- eXosip_lock();
- eXosip_subscribe_build_initial_request(&msg,friend,from,route,"presence",600);
- eXosip_subscribe_send_initial_request(msg);
- eXosip_unlock();
+ 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;
+ }
+ 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;
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;
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;
return 0;
}
-int linphone_friend_set_proxy(LinphoneFriend *fr, struct _LinphoneProxyConfig *cfg){
- fr->proxy=cfg;
- return 0;
-}
-
-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;
+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 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, "<?xml version=\"1.0\"?>\n\
-<!DOCTYPE presence\n\
-PUBLIC \"-//IETF//DTD RFCxxxx XPIDF 1.0//EN\" \"xpidf.dtd\">\n\
-<presence>\n\
-<presentity uri=\"%s;method=SUBSCRIBE\" />\n\
-<atom id=\"%i\">\n\
-<address uri=\"%s;user=ip\" priority=\"0.800000\">\n\
-<status status=\"open\" />\n\
-<msnsubstatus substatus=\"online\" />\n\
-</address>\n\
-</atom>\n\
-</presence>", contact_info, atom_id, contact_info);
-
- }
- else if (online_status==LINPHONE_STATUS_BUSY)
- {
- sprintf(buf, "<?xml version=\"1.0\"?>\n\
-<!DOCTYPE presence\n\
-PUBLIC \"-//IETF//DTD RFCxxxx XPIDF 1.0//EN\" \"xpidf.dtd\">\n\
-<presence>\n\
-<presentity uri=\"%s;method=SUBSCRIBE\" />\n\
-<atom id=\"%i\">\n\
-<address uri=\"%s;user=ip\" priority=\"0.800000\">\n\
-<status status=\"inuse\" />\n\
-<msnsubstatus substatus=\"busy\" />\n\
-</address>\n\
-</atom>\n\
-</presence>", contact_info, atom_id, contact_info);
-
- }
- else if (online_status==LINPHONE_STATUS_BERIGHTBACK)
- {
- sprintf(buf, "<?xml version=\"1.0\"?>\n\
-<!DOCTYPE presence\n\
-PUBLIC \"-//IETF//DTD RFCxxxx XPIDF 1.0//EN\" \"xpidf.dtd\">\n\
-<presence>\n\
-<presentity uri=\"%s;method=SUBSCRIBE\" />\n\
-<atom id=\"%i\">\n\
-<address uri=\"%s;user=ip\" priority=\"0.800000\">\n\
-<status status=\"inactive\" />\n\
-<msnsubstatus substatus=\"berightback\" />\n\
-</address>\n\
-</atom>\n\
-</presence>", contact_info, atom_id, contact_info);
-
- }
- else if (online_status==LINPHONE_STATUS_AWAY)
- {
- sprintf(buf, "<?xml version=\"1.0\"?>\n\
-<!DOCTYPE presence\n\
-PUBLIC \"-//IETF//DTD RFCxxxx XPIDF 1.0//EN\" \"xpidf.dtd\">\n\
-<presence>\n\
-<presentity uri=\"%s;method=SUBSCRIBE\" />\n\
-<atom id=\"%i\">\n\
-<address uri=\"%s;user=ip\" priority=\"0.800000\">\n\
-<status status=\"inactive\" />\n\
-<msnsubstatus substatus=\"away\" />\n\
-</address>\n\
-</atom>\n\
-</presence>", contact_info, atom_id, contact_info);
-
- }
- else if (online_status==LINPHONE_STATUS_ONTHEPHONE)
- {
- sprintf(buf, "<?xml version=\"1.0\"?>\n\
-<!DOCTYPE presence\n\
-PUBLIC \"-//IETF//DTD RFCxxxx XPIDF 1.0//EN\" \"xpidf.dtd\">\n\
-<presence>\n\
-<presentity uri=\"%s;method=SUBSCRIBE\" />\n\
-<atom id=\"%i\">\n\
-<address uri=\"%s;user=ip\" priority=\"0.800000\">\n\
-<status status=\"inuse\" />\n\
-<msnsubstatus substatus=\"onthephone\" />\n\
-</address>\n\
-</atom>\n\
-</presence>", contact_info, atom_id, contact_info);
-
- }
- else if (online_status==LINPHONE_STATUS_OUTTOLUNCH)
- {
- sprintf(buf, "<?xml version=\"1.0\"?>\n\
-<!DOCTYPE presence\n\
-PUBLIC \"-//IETF//DTD RFCxxxx XPIDF 1.0//EN\" \"xpidf.dtd\">\n\
-<presence>\n\
-<presentity uri=\"%s;method=SUBSCRIBE\" />\n\
-<atom id=\"%i\">\n\
-<address uri=\"%s;user=ip\" priority=\"0.800000\">\n\
-<status status=\"inactive\" />\n\
-<msnsubstatus substatus=\"outtolunch\" />\n\
-</address>\n\
-</atom>\n\
-</presence>", contact_info, atom_id, contact_info);
-
- }
- else
- {
- sprintf(buf, "<?xml version=\"1.0\"?>\n\
-<!DOCTYPE presence\n\
-PUBLIC \"-//IETF//DTD RFCxxxx XPIDF 1.0//EN\" \"xpidf.dtd\">\n\
-<presence>\n\
-<presentity uri=\"%s;method=SUBSCRIBE\" />\n\
-<atom id=\"%i\">\n\
-<address uri=\"%s;user=ip\" priority=\"0.800000\">\n\
-<status status=\"inactive\" />\n\
-<msnsubstatus substatus=\"away\" />\n\
-</address>\n\
-</atom>\n\
-</presence>", 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, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
-<presence xmlns=\"urn:ietf:params:xml:ns:pidf\"\n\
- entity=\"%s\">\n\
-<tuple id=\"sg89ae\">\n\
-<status>\n\
-<basic>open</basic>\n\
-</status>\n\
-<contact priority=\"0.8\">%s</contact>\n\
-<note>online</note>\n\
-</tuple>\n\
-</presence>",
- contact_info, contact_info);
- }
- else if (online_status==LINPHONE_STATUS_BUSY)
- {
- sprintf(buf, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
-<presence xmlns=\"urn:ietf:params:xml:ns:pidf\"\n\
- xmlns:es=\"urn:ietf:params:xml:ns:pidf:status:rpid-status\"\n\
- entity=\"%s\">\n\
-<tuple id=\"sg89ae\">\n\
-<status>\n\
-<basic>open</basic>\n\
-<es:activities>\n\
- <es:activity>busy</es:activity>\n\
-</es:activities>\n\
-</status>\n\
-<contact priority=\"0.8\">%s</contact>\n\
-<note>busy</note>\n\
-</tuple>\n\
-</presence>",
- contact_info, contact_info);
- }
- else if (online_status==LINPHONE_STATUS_BERIGHTBACK)
- {
- sprintf(buf, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
-<presence xmlns=\"urn:ietf:params:xml:ns:pidf\"\n\
- xmlns:es=\"urn:ietf:params:xml:ns:pidf:status:rpid-status\"\n\
- entity=\"%s\">\n\
-<tuple id=\"sg89ae\">\n\
-<status>\n\
-<basic>open</basic>\n\
-<es:activities>\n\
- <es:activity>in-transit</es:activity>\n\
-</es:activities>\n\
-</status>\n\
-<contact priority=\"0.8\">%s</contact>\n\
-<note>be right back</note>\n\
-</tuple>\n\
-</presence>",
- contact_info, contact_info);
- }
- else if (online_status==LINPHONE_STATUS_AWAY)
- {
- sprintf(buf, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
-<presence xmlns=\"urn:ietf:params:xml:ns:pidf\"\n\
- xmlns:es=\"urn:ietf:params:xml:ns:pidf:status:rpid-status\"\n\
- entity=\"%s\">\n\
-<tuple id=\"sg89ae\">\n\
-<status>\n\
-<basic>open</basic>\n\
-<es:activities>\n\
- <es:activity>away</es:activity>\n\
-</es:activities>\n\
-</status>\n\
-<contact priority=\"0.8\">%s</contact>\n\
-<note>away</note>\n\
-</tuple>\n\
-</presence>",
- contact_info, contact_info);
- }
- else if (online_status==LINPHONE_STATUS_ONTHEPHONE)
- {
- sprintf(buf, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
-<presence xmlns=\"urn:ietf:params:xml:ns:pidf\"\n\
- xmlns:es=\"urn:ietf:params:xml:ns:pidf:status:rpid-status\"\n\
- entity=\"%s\">\n\
-<tuple id=\"sg89ae\">\n\
-<status>\n\
-<basic>open</basic>\n\
-<es:activities>\n\
- <es:activity>on-the-phone</es:activity>\n\
-</es:activities>\n\
-</status>\n\
-<contact priority=\"0.8\">%s</contact>\n\
-<note>on the phone</note>\n\
-</tuple>\n\
-</presence>",
- contact_info, contact_info);
- }
- else if (online_status==LINPHONE_STATUS_OUTTOLUNCH)
- {
- sprintf(buf, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
-<presence xmlns=\"urn:ietf:params:xml:ns:pidf\"\n\
- xmlns:es=\"urn:ietf:params:xml:ns:pidf:status:rpid-status\"\n\
- entity=\"%s\">\n\
-<tuple id=\"sg89ae\">\n\
-<status>\n\
-<basic>open</basic>\n\
-<es:activities>\n\
- <es:activity>meal</es:activity>\n\
-</es:activities>\n\
-</status>\n\
-<contact priority=\"0.8\">%s</contact>\n\
-<note>out to lunch</note>\n\
-</tuple>\n\
-</presence>",
- contact_info, contact_info);
- }
- else
- {
- /* */
- sprintf(buf, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
-<presence xmlns=\"urn:ietf:params:xml:ns:pidf\"\n\
-xmlns:es=\"urn:ietf:params:xml:ns:pidf:status:rpid-status\"\n\
-entity=\"%s\">\n%s",
- contact_info,
-"<tuple id=\"sg89ae\">\n\
-<status>\n\
-<basic>closed</basic>\n\
-<es:activities>\n\
- <es:activity>permanent-absence</es:activity>\n\
-</es:activities>\n\
-</status>\n\
-</tuple>\n\
-\n</presence>\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){
+const LinphoneAddress *linphone_friend_get_address(const LinphoneFriend *lf){
return lf->uri;
}
-
bool_t linphone_friend_get_send_subscribe(const LinphoneFriend *lf){
return lf->subscribe;
}
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);
}
{
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 ;
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);
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;
}
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);
}
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){
#include "linphonecore.h"
-
+#include "private.h"
#if 0
static const char *_gstates_text[] = {
"GSTATE_POWER_OFF", /* 0 */
#include "mediastreamer2/mediastream.h"
#include "mediastreamer2/msvolume.h"
#include "mediastreamer2/msequalizer.h"
-#include <eXosip2/eXosip.h>
-#include "sdphandler.h"
#include <ortp/telephonyevents.h>
-#include "exevents.h"
#ifdef INET6
#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*/
/* 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 */
-};
+extern SalCallbacks linphone_sal_callbacks;
void lc_callback_obj_init(LCCallbackObj *obj,LinphoneCoreCbFunc func,void* ud)
{
return 0;
}
-static void linphone_call_init_common(LinphoneCall *call, LinphoneAddress *from, LinphoneAddress *to){
+
+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, bool_t only_one_codec){
+ 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;
+ md->streams[0].ptime=lc->net_conf.down_ptime;
+ 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;
+
+ 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,only_one_codec);
+ 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;
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");
-}
-
-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){
{
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);
+ 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,
+ linphone_address_get_username(from),FALSE);
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;
+ char *to_str;
+ char *from_str;
call->dir=LinphoneCallIncoming;
- call->cid=ev->cid;
- call->did=ev->did;
- call->tid=ev->tid;
+ 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),lc->sip_conf.only_one_codec);
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;
}
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->sdpctx!=NULL) sdp_context_free(obj->sdpctx);
+ 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);
}
calllog->duration=time(NULL)-call->start_time;
switch(call->state){
case LCStateInit:
+ case LCStatePreEstablishing:
calllog->status=LinphoneCallAborted;
break;
case LCStateRinging:
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*.
*
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);
}
/**
**/
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);
}
* @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);
}
/*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);
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)
}
}
- /*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)
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 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 1;
+ if (ra<rb) return -1;
+ return 0;
+}
+
+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){
+ 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 : "");
+ l=ms_list_insert_sorted(l,pt,(int (*)(const void *, const void *))codec_compare);
+ }
+ }
+ }
+ }
+ return l;
}
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;
/**
* set audio packetization time linphone expect to received from peer
*/
-void linphone_core_set_download_ptime(LinphoneCore *lc, int ptime);
-
void linphone_core_set_download_ptime(LinphoneCore *lc, int ptime) {
- lc->down_ptime=ptime;
+ lc->net_conf.down_ptime=ptime;
}
+
int linphone_core_get_download_ptime(LinphoneCore *lc) {
- return lc->down_ptime;
+ return lc->net_conf.down_ptime;
}
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);
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");
linphone_core_assign_payload_type(&payload_type_speex_uwb,112,"vbr=on");
- linphone_core_assign_payload_type(&payload_type_telephone_event,101,NULL);
+ linphone_core_assign_payload_type(&payload_type_telephone_event,101,"0-11");
linphone_core_assign_payload_type(&payload_type_ilbc,113,"mode=30");
#ifdef ENABLE_NONSTANDARD_GSM
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);
+ }
sip_setup_register_all();
sound_config_read(lc);
net_config_read(lc);
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->auto_net_state_mon=TRUE;
**/
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);
return -1;
}
if (lc->sip_conf.contact!=NULL) ms_free(lc->sip_conf.contact);
ms_free(lc->sip_conf.guessed_contact);
lc->sip_conf.guessed_contact=NULL;
}
- osip_from_free(ctt);
+ linphone_address_destroy(ctt);
return 0;
}
/*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;
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);
+}
+
+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);
}
/**
*
* @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;
- 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){
-
- }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);
- lc->sip_conf.guessed_contact=guessed;
-
- osip_from_free(url);
-
+ update_primary_contact(lc);
}
identity=lc->sip_conf.guessed_contact;
}else{
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
"unknown"
#endif
);
- eXosip_set_user_agent(ua_string);
+ if (lc->sal) sal_set_user_agent(lc->sal,ua_string);
}
/**
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);
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);
}
/**
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);
}
/* 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){
- new_status=TRUE;
- }else new_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){
+ new_status=TRUE;
+ }else new_status=FALSE;
last_check=curtime;
if (new_status!=last_status) {
set_network_reachable(lc,new_status);
}
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);
* 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;
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);
if (lc->auto_net_state_mon) monitor_network_state(lc,curtime);
proxy_update(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);
}
-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;
+ LinphoneAddress *parsed_url=NULL;
char *enum_domain=NULL;
LinphoneProxyConfig *proxy=lc->default_proxy;;
char *tmpurl;
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;
}else return FALSE;
}
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 */
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;
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, LinphoneCall *call , LinphoneProxyConfig *dest_proxy){
+ LinphoneAddress *ctt;
+ const char *localip=call->localip;
- 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);
+ /* 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) {
+ ms_message("Contact has been fixed using proxy to %s",fixed_contact);
+ return ms_strdup(fixed_contact);
}
- 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 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){
+ 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;
+}
+
+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;
}
/**
**/
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;
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;
/* 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 cause [%i]",err);
- 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);
- /*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);
-
- 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();
+ call=linphone_call_new_outgoing(lc,parsed_url2,real_parsed_url);
+ sal_op_set_route(call->op,route);
- if (err<0){
- ms_warning("Could not initiate call.");
- lc->vtable.display_status(lc,_("could not call"));
- linphone_call_destroy(lc->call);
- lc->call=NULL;
- linphone_core_stop_media_streams(lc);
- }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);
- return (err<0) ? -1 : 0;
+ 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;
}
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 */
}
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;
}
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){
- 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)
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
}
+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){
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);
}
}
+static RtpProfile *make_profile(LinphoneCore *lc, const SalStreamDescription *desc, int *used_pt){
+ int bw;
+ 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 (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;
- }
- if (captcard==NULL) {
- ms_warning("No card defined for capture !");
- goto end;
+ const 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 (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
{
+ const 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;
}
}
#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;
+ }
}
/**
**/
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;
}
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();
+
+ /*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);
+
+ 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);
+ }else call->media_pending=TRUE;
ms_message("call answered.");
return 0;
}
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);
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);
/*
}
lc->prev_mode=lc->presence_mode;
lc->presence_mode=presence_mode;
-
}
LinphoneOnlineStatus linphone_core_get_presence_info(const LinphoneCore *lc){
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
*
* @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)
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);
}
}
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){
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(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){
- 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);
- */
- }
- ms_free(tmp);
- }
- else{
- eXosip_set_option(EXOSIP_OPT_SET_IPV4_FOR_GATEWAY,NULL);
- eXosip_masquerade_contact("",0);
- }
- }
- else {
- eXosip_set_option(EXOSIP_OPT_SET_IPV4_FOR_GATEWAY,NULL);
- eXosip_masquerade_contact("",0);
- }
-}
-
-
void linphone_core_set_nat_address(LinphoneCore *lc, const char *addr)
{
if (lc->net_conf.nat_address!=NULL){
}
if (addr!=NULL) lc->net_conf.nat_address=ms_strdup(addr);
else lc->net_conf.nat_address=NULL;
- lc->apply_nat_settings=TRUE;
+ if (lc->sip_conf.contact) update_primary_contact(lc);
}
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;
+ if (lc->sip_conf.contact) update_primary_contact(lc);
}
LinphoneFirewallPolicy linphone_core_get_firewall_policy(const LinphoneCore *lc){
}
if (file!=NULL) {
lc->play_file=ms_strdup(file);
- if (lc->audiostream)
+ if (lc->audiostream->ticker)
audio_stream_play(lc->audiostream,file);
}
}
lp_config_set_int(lc->config,"sip","use_rfc2833",config->use_rfc2833);
lp_config_set_int(lc->config,"sip","use_ipv6",config->ipv6_enabled);
lp_config_set_int(lc->config,"sip","register_only_when_network_is_up",config->register_only_when_network_is_up);
+
+ lp_config_set_int(lc->config,"sip","default_proxy",linphone_core_get_default_proxy(lc,NULL));
+
for(elem=config->proxies,i=0;elem!=NULL;elem=ms_list_next(elem),i++){
LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)(elem->data);
linphone_proxy_config_write_to_config_file(lc->config,cfg,i);
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
- }
- }
+ }
+ }
+ 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++){
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;
}
void rtp_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;
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++;
}
- if (lc->local_profile){
- rtp_profile_destroy(lc->local_profile);
- lc->local_profile=NULL;
- }
}
void ui_config_uninit(LinphoneCore* lc)
/* save all config */
net_config_uninit(lc);
sip_config_uninit(lc);
- lp_config_set_int(lc->config,"sip","default_proxy",linphone_core_get_default_proxy(lc,NULL));
rtp_config_uninit(lc);
sound_config_uninit(lc);
video_config_uninit(lc);
linphone_core_free_payload_types();
ortp_exit();
- eXosip_quit();
exosip_running=FALSE;
gstate_new_state(lc, GSTATE_POWER_OFF, NULL);
}
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);
+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.
* @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);
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;
}LinphoneSubscribePolicy;
typedef enum _LinphoneOnlineStatus{
- LINPHONE_STATUS_UNKNOWN,
+ LINPHONE_STATUS_OFFLINE,
LINPHONE_STATUS_ONLINE,
LINPHONE_STATUS_BUSY,
LINPHONE_STATUS_BERIGHTBACK,
LINPHONE_STATUS_NOT_DISTURB,
LINPHONE_STATUS_MOVED,
LINPHONE_STATUS_ALT_SERVICE,
- LINPHONE_STATUS_OFFLINE,
LINPHONE_STATUS_PENDING,
- LINPHONE_STATUS_CLOSED,
LINPHONE_STATUS_END
}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);
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);
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)
+
/**
* @addtogroup proxies
* @{
* 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);
-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
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);
LinphoneProxyConfig * linphone_account_creator_validate(LinphoneAccountCreator *obj);
void linphone_account_creator_destroy(LinphoneAccountCreator *obj);
+struct _LinphoneAuthInfo;
+
/**
* @ingroup authentication
* Object holding authentication information.
* 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);
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);
-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);
/** 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 */
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;
} 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
+typedef struct _LinphoneCore LinphoneCore;
/*set this field to false if application manage network connection state
* In case of false, network state must be communicate to linphone core with method linphone_core_
*/
bool_t auto_net_state_mon;
bool_t network_reachable;
int down_ptime;
-} LinphoneCore;
-
-
/* THE main API */
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);
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);
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 */
void linphone_core_set_network_reachable(LinphoneCore* lc,bool_t value);
-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
/*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
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
#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);
}
+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 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*/
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");
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;
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;
}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){
}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;
}
}
}
--- /dev/null
+/*
+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){
+ 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){
+ if (remote_answer->port!=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;
+ }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);
+ 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;
+ }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,j;
+ const SalStreamDescription *ls,*rs;
+ for(i=0,j=0;i<local_offer->nstreams;++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=j;
+ 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,j;
+ const SalStreamDescription *ls,*rs;
+
+ for(i=0,j=0;i<remote_offer->nstreams;++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=j;
+ strcpy(result->username, local_capabilities->username);
+ strcpy(result->addr,local_capabilities->addr);
+ return 0;
+}
+
--- /dev/null
+/*
+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
+
*/
#include "linphonecore.h"
-#include <eXosip2/eXosip.h>
-#include <osipparser2/osip_message.h>
#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);
}
}
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);
-}
-
-/* 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;
+ for(elem=lc->friends;elem!=NULL;elem=elem->next){
+ LinphoneFriend *lf=(LinphoneFriend *)elem->data;
+ if (lf->insub){
+ linphone_friend_notify(lf,os);
+ }
+ }
}
-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)
-{
- const char *status=_("Gone");
- const char *img="sip-closed.png";
+void linphone_notify_recv(LinphoneCore *lc, SalOp *op, SalSubscribeState ss, SalPresenceStatus sal_status){
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";
+ LinphoneOnlineStatus estatus=LINPHONE_STATUS_OFFLINE;
+
+ switch(sal_status){
+ case SalPresenceOffline:
+ estatus=LINPHONE_STATUS_OFFLINE;
+ break;
+ case SalPresenceOnline:
estatus=LINPHONE_STATUS_ONLINE;
- }else if (strstr(body->body,"busy")!=NULL){
- status=_("Busy");
- img="sip-busy.png";
+ break;
+ case SalPresenceBusy:
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";
+ break;
+ case SalPresenceBerightback:
+ estatus=LINPHONE_STATUS_AWAY;
+ break;
+ case SalPresenceAway:
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";
+ break;
+ case SalPresenceOnthephone:
estatus=LINPHONE_STATUS_ONTHEPHONE;
- }else if (strstr(body->body,"outtolunch")!=NULL
- || strstr(body->body,"meal")!=NULL){
- status=_("Out To Lunch");
- img="sip-otl.png";
+ break;
+ case SalPresenceOuttolunch:
estatus=LINPHONE_STATUS_OUTTOLUNCH;
- }else if (strstr(body->body,"closed")!=NULL){
- status=_("Closed");
- img="sip-away.png";
- estatus=LINPHONE_STATUS_CLOSED;
- }else{
- 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 SalPresenceDonotdisturb:
+ estatus=LINPHONE_STATUS_BUSY;
+ break;
+ case SalPresenceMoved:
+ case SalPresenceAltService:
+ 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);
+ lc->vtable.notify_recv(lc,(LinphoneFriend*)lf);
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.");
}
-}
-
-void linphone_subscription_answered(LinphoneCore *lc, eXosip_event_t *ev){
- 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);
- if (lf!=NULL){
- lf->out_did=ev->did;
- linphone_friend_set_sid(lf,ev->sid);
- }else{
- ms_warning("Receiving answer for unknown subscribe sip:%s@%s", from->url->username,from->url->host);
+ if (ss==SalSubscribeTerminated){
+ sal_op_release(op);
+ if (lf)
+ lf->outsub=NULL;
}
- ms_free(tmp);
}
-void linphone_subscription_closed(LinphoneCore *lc,eXosip_event_t *ev){
+
+void linphone_subscription_closed(LinphoneCore *lc, SalOp *op){
LinphoneFriend *lf;
- osip_from_t *from=ev->request->from;
- lf=linphone_find_friend_by_nid(lc->friends,ev->nid);
+ lf=linphone_find_friend_by_inc_subscribe(lc->friends,op);
+ sal_op_release(op);
if (lf!=NULL){
- lf->in_did=-1;
- linphone_friend_set_nid(lf,-1);
+ lf->insub=NULL;
}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));
}
}
#define _PRIVATE_H
#include "linphonecore.h"
-#include <eXosip2/eXosip.h>
+#include "sal.h"
#ifdef HAVE_CONFIG_H
#include "config.h"
#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,
+ LCStatePreEstablishing,
LCStateRinging,
LCStateAVRunning
}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 _RtpProfile *audio_profile;
+ struct _RtpProfile *video_profile;
struct _LinphoneCallLog *log;
- int cid; /*call id */
- int did; /*dialog id */
- int tid; /*last transaction id*/
+ SalOp *op;
+ SalOp *ping_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;
+ bool_t media_pending;
} 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);
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);
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);
+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();
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_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);
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);
}
}
#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, int code, 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_call_init_media_params(LinphoneCall *call);
+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, 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_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);
int linphone_proxy_config_normalize_number(LinphoneProxyConfig *cfg, const char *username, char *result, size_t result_len);
+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);
+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);
+
+int linphone_core_start_invite(LinphoneCore *lc, LinphoneCall *call, LinphoneProxyConfig *dest_proxy);
+
+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;
+ int usecount;
+ bool_t works;
+};
+
+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 _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;
+ bool_t ping_with_options;
+} 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;
+ int down_ptime;
+ 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 soft_play_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;
+ 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;
+ bool_t auto_net_state_mon;
+ bool_t network_reachable;
+};
+
#endif /* _PRIVATE_H */
#include "linphonecore.h"
#include "sipsetup.h"
-#include <eXosip2/eXosip.h>
-#include <osipparser2/osip_message.h>
#include "lpconfig.h"
#include "private.h"
void linphone_proxy_config_init(LinphoneProxyConfig *obj){
memset(obj,0,sizeof(LinphoneProxyConfig));
- obj->rid=-1;
obj->expires=3600;
}
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);
}
/**
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
*
* - 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;
}
* 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){
* 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){
* 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;
}
}
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_op_set_user_pointer(obj->op,obj);
+ sal_register(obj->op,obj->reg_proxy,obj->reg_identity,obj->expires);
}
}
}
int linphone_proxy_config_send_publish(LinphoneProxyConfig *proxy,
- LinphoneOnlineStatus presence_mode)
-{
- osip_message_t *pub;
- int i;
- const char *from=NULL;
- char buf[5000];
+ 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;
+}
- 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, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
-<presence xmlns=\"urn:ietf:params:xml:ns:pidf\"\n\
- entity=\"%s\">\n\
-<tuple id=\"sg89ae\">\n\
-<status>\n\
-<basic>open</basic>\n\
-</status>\n\
-<contact priority=\"0.8\">%s</contact>\n\
-<note>online</note>\n\
-</tuple>\n\
-</presence>",
- from, from);
- }
- else if (presence_mode==LINPHONE_STATUS_BUSY
- ||presence_mode==LINPHONE_STATUS_NOT_DISTURB)
- {
- snprintf(buf, 5000, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
-<presence xmlns=\"urn:ietf:params:xml:ns:pidf\"\n\
- xmlns:es=\"urn:ietf:params:xml:ns:pidf:status:rpid-status\"\n\
- entity=\"%s\">\n\
-<tuple id=\"sg89ae\">\n\
-<status>\n\
-<basic>open</basic>\n\
-<es:activities>\n\
- <es:activity>busy</es:activity>\n\
-</es:activities>\n\
-</status>\n\
-<contact priority=\"0.8\">%s</contact>\n\
-<note>busy</note>\n\
-</tuple>\n\
-</presence>",
- from, from);
- }
- else if (presence_mode==LINPHONE_STATUS_BERIGHTBACK)
- {
- snprintf(buf, 5000, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
-<presence xmlns=\"urn:ietf:params:xml:ns:pidf\"\n\
- xmlns:es=\"urn:ietf:params:xml:ns:pidf:status:rpid-status\"\n\
- entity=\"%s\">\n\
-<tuple id=\"sg89ae\">\n\
-<status>\n\
-<basic>open</basic>\n\
-<es:activities>\n\
- <es:activity>in-transit</es:activity>\n\
-</es:activities>\n\
-</status>\n\
-<contact priority=\"0.8\">%s</contact>\n\
-<note>be right back</note>\n\
-</tuple>\n\
-</presence>",
- from,from);
- }
- else if (presence_mode==LINPHONE_STATUS_AWAY
- ||presence_mode==LINPHONE_STATUS_MOVED
- ||presence_mode==LINPHONE_STATUS_ALT_SERVICE)
- {
- snprintf(buf, 5000, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
-<presence xmlns=\"urn:ietf:params:xml:ns:pidf\"\n\
- xmlns:es=\"urn:ietf:params:xml:ns:pidf:status:rpid-status\"\n\
- entity=\"%s\">\n\
-<tuple id=\"sg89ae\">\n\
-<status>\n\
-<basic>open</basic>\n\
-<es:activities>\n\
- <es:activity>away</es:activity>\n\
-</es:activities>\n\
-</status>\n\
-<contact priority=\"0.8\">%s</contact>\n\
-<note>away</note>\n\
-</tuple>\n\
-</presence>",
- from, from);
- }
- else if (presence_mode==LINPHONE_STATUS_ONTHEPHONE)
- {
- snprintf(buf, 5000, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
-<presence xmlns=\"urn:ietf:params:xml:ns:pidf\"\n\
- xmlns:es=\"urn:ietf:params:xml:ns:pidf:status:rpid-status\"\n\
- entity=\"%s\">\n\
-<tuple id=\"sg89ae\">\n\
-<status>\n\
-<basic>open</basic>\n\
-<es:activities>\n\
- <es:activity>on-the-phone</es:activity>\n\
-</es:activities>\n\
-</status>\n\
-<contact priority=\"0.8\">%s</contact>\n\
-<note>on the phone</note>\n\
-</tuple>\n\
-</presence>",
- from, from);
- }
- else if (presence_mode==LINPHONE_STATUS_OUTTOLUNCH)
- {
- snprintf(buf, 5000, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
-<presence xmlns=\"urn:ietf:params:xml:ns:pidf\"\n\
- xmlns:es=\"urn:ietf:params:xml:ns:pidf:status:rpid-status\"\n\
- entity=\"%s\">\n\
-<tuple id=\"sg89ae\">\n\
-<status>\n\
-<basic>open</basic>\n\
-<es:activities>\n\
- <es:activity>meal</es:activity>\n\
-</es:activities>\n\
-</status>\n\
-<contact priority=\"0.8\">%s</contact>\n\
-<note>out to lunch</note>\n\
-</tuple>\n\
-</presence>",
- from, from);
- }
- else if (presence_mode==LINPHONE_STATUS_OFFLINE)
- {
- /* */
- snprintf(buf, 5000, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
-<presence xmlns=\"urn:ietf:params:xml:ns:pidf\"\n\
-xmlns:es=\"urn:ietf:params:xml:ns:pidf:status:rpid-status\"\n\
-entity=\"%s\">\n%s",
- from,
-"<tuple id=\"sg89ae\">\n\
-<status>\n\
-<basic>closed</basic>\n\
-<es:activities>\n\
- <es:activity>permanent-absence</e:activity>\n\
-</es:activities>\n\
-</status>\n\
-</tuple>\n\
-\n</presence>\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;
+/**
+ * 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 <sip:username@domain> )
+**/
+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.
**/
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.
*
* 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);
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.
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.
**/
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=(LinphoneAuthInfo*)linphone_core_find_auth_info(lc,prx_realm,username);
- if (www_realm!=NULL)
- as=(LinphoneAuthInfo*)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];
--- /dev/null
+/*
+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(){
+ SalMediaDescription *md=ms_new0(SalMediaDescription,1);
+ md->refcount=1;
+ return md;
+}
+
+static void sal_media_description_destroy(SalMediaDescription *md){
+ int i;
+ for(i=0;i<SAL_MEDIA_DESCRIPTION_MAX_STREAMS;i++){
+ ms_list_for_each(md->streams[i].payloads,(void (*)(void *))payload_type_destroy);
+ ms_list_free(md->streams[i].payloads);
+ md->streams[i].payloads=NULL;
+ }
+ 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);
+ }
+}
+
+const SalStreamDescription *sal_media_description_find_stream(const SalMediaDescription *md,
+ SalMediaProto proto, SalStreamType type){
+ int i;
+ for(i=0;i<md->nstreams;++i){
+ const SalStreamDescription *ss=&md->streams[i];
+ if (ss->proto==proto && ss->type==type) return ss;
+ }
+ return NULL;
+}
+
+bool_t sal_media_description_empty(SalMediaDescription *md){
+ int i;
+ for(i=0;i<md->nstreams;++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){
+ 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;
+}
+
+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;
+}
+
+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;
+}
+
+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) {
+ 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->origin){
+ ms_free(b->origin);
+ b->origin=NULL;
+ }
+ if (b->local_media)
+ sal_media_description_unref(b->local_media);
+ if (b->remote_media)
+ sal_media_description_unref(b->remote_media);
+ ms_free(op);
+}
--- /dev/null
+/*
+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;
+
+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);
+void sal_set_user_pointer(Sal *sal, void *user_data);
+void *sal_get_user_pointer(const Sal *sal);
+
+typedef enum {
+ SalTransportDatagram,
+ SalTransportStream
+}SalTransport;
+
+typedef enum {
+ SalAudio,
+ SalVideo,
+ SalOther
+} SalStreamType;
+
+typedef enum{
+ SalProtoUnknown,
+ SalProtoRtpAvp,
+ SalProtoRtpSavp
+}SalMediaProto;
+
+typedef struct SalEndpointCandidate{
+ char addr[64];
+ int port;
+}SalEndpointCandidate;
+
+#define SAL_ENDPOINT_CANDIDATE_MAX 2
+
+typedef struct SalStreamDescription{
+ SalMediaProto proto;
+ SalStreamType type;
+ char addr[64];
+ int port;
+ MSList *payloads; //<list of PayloadType
+ int bandwidth;
+ int ptime;
+ SalEndpointCandidate candidates[SAL_ENDPOINT_CANDIDATE_MAX];
+} SalStreamDescription;
+
+#define SAL_MEDIA_DESCRIPTION_MAX_STREAMS 4
+
+typedef struct SalMediaDescription{
+ int refcount;
+ char addr[64];
+ char username[64];
+ int nstreams;
+ SalStreamDescription streams[SAL_MEDIA_DESCRIPTION_MAX_STREAMS];
+} 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);
+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*/
+typedef struct SalOpBase{
+ Sal *root;
+ char *route; /*or request-uri for REGISTER*/
+ char *contact;
+ char *from;
+ char *to;
+ char *origin;
+ SalMediaDescription *local_media;
+ SalMediaDescription *remote_media;
+ void *user_pointer;
+} SalOpBase;
+
+
+typedef enum SalError{
+ SalErrorNoResponse,
+ SalErrorProtocol,
+ SalErrorFailure, /* see SalReason for more details */
+ SalErrorUnknown
+} SalError;
+
+typedef enum SalReason{
+ SalReasonDeclined,
+ SalReasonBusy,
+ SalReasonRedirect,
+ SalReasonTemporarilyUnavailable,
+ SalReasonNotFound,
+ SalReasonDoNotDisturb,
+ SalReasonMedia,
+ SalReasonForbidden,
+ SalReasonUnknown
+}SalReason;
+
+typedef enum SalPresenceStatus{
+ SalPresenceOffline,
+ SalPresenceOnline,
+ SalPresenceBusy,
+ SalPresenceBerightback,
+ SalPresenceAway,
+ SalPresenceOnthephone,
+ SalPresenceOuttolunch,
+ SalPresenceDonotdisturb,
+ SalPresenceMoved,
+ SalPresenceAltService,
+}SalPresenceStatus;
+
+typedef enum SalSubscribeState{
+ SalSubscribeActive,
+ SalSubscribeTerminated
+}SalSubscribeState;
+
+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, 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);
+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 (*SalOnNotify)(SalOp *op, SalSubscribeState ss, SalPresenceStatus status, const char *msg);
+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;
+ 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;
+ SalOnNotify notify;
+ SalOnSubscribeReceived subscribe_received;
+ SalOnSubscribeClosed subscribe_closed;
+ SalOnInternalMsg internal_message;
+ SalOnPingReply ping_reply;
+}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);
+void sal_use_session_timers(Sal *ctx, int expires);
+int sal_iterate(Sal *sal);
+MSList * sal_get_pending_auths(Sal *sal);
+
+/*create an operation */
+SalOp * sal_op_new(Sal *sal);
+
+/*generic SalOp API, working for all operations */
+Sal *sal_op_get_sal(const SalOp *op);
+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);
+void sal_op_authenticate(SalOp *h, const SalAuthInfo *info);
+void sal_op_set_user_pointer(SalOp *h, void *up);
+int sal_op_get_auth_requested(SalOp *h, const char **realm, const char **username);
+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);
+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*/
+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*/);
+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*/
+int sal_register(SalOp *op, const char *proxy, const char *from, int expires);
+int sal_unregister(SalOp *h);
+
+/*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_unsubscribe(SalOp *op);
+int sal_subscribe_accept(SalOp *op);
+int sal_subscribe_decline(SalOp *op);
+int sal_notify_presence(SalOp *op, SalPresenceStatus status, const char *status_message);
+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)
+
+/*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);
+void __sal_op_set_network_origin(SalOp *op, const char *origin /*a sip uri*/);
+void __sal_op_free(SalOp *b);
+
+
+#endif
--- /dev/null
+/*
+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"
+
+#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 */
+ 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;
+ SalOp *op;
+ for(elem=sal->registers;elem!=NULL;elem=elem->next){
+ op=(SalOp*)elem->data;
+ if (op->rid==rid) return op;
+ }
+ return NULL;
+}
+
+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;
+ }
+ }
+}
+
+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);
+}
+
+
+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);
+ 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;
+ op->sdp_answer=NULL;
+ op->reinvite=FALSE;
+ op->call_id=NULL;
+ 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);
+ if (op->rid!=-1){
+ 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);
+ if (op->call_id){
+ sal_remove_other(op->base.root,op);
+ osip_call_id_free(op->call_id);
+ }
+ __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);
+}
+
+void sal_uninit(Sal* sal){
+ eXosip_quit();
+ 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;
+}
+
+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.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)
+ 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){
+ 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!=SalTransportDatagram || 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;
+}
+
+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;
+ char clen[10];
+ 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);
+ osip_message_set_content_type(sip,"application/sdp");
+ osip_message_set_content_length(sip,clen);
+ 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){
+ ms_message("Doing SDP offer/answer process");
+ if (h->result){
+ sal_media_description_unref(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;i<h->result->nstreams;++i){
+ if (h->result->streams[i].port>0){
+ strcpy(h->result->streams[i].addr,h->base.remote_media->streams[i].addr);
+ 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){
+ 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;
+}
+
+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);
+ 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;
+ }
+ if (h->base.contact){
+ _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){
+ osip_message_set_header(invite, "Session-expires", "200");
+ osip_message_set_supported(invite, "timer");
+ }
+ 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();
+ h->cid=err;
+ if (err<0){
+ ms_error("Fail to send invite !");
+ return -1;
+ }else{
+ eXosip_call_set_reference(h->cid,h);
+ }
+ 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){
+ 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");
+ }
+
+ if (contact) {
+ _osip_list_set_empty(&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*/
+ 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;
+}
+
+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_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;
+ 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_call_set_reference(h->cid,NULL);
+ eXosip_unlock();
+ return 0;
+}
+
+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;
+ 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);
+ h->pending_auth=NULL;
+ }
+}
+
+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();
+ 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_unref(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 (op->base.contact){
+ _osip_list_set_empty(&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();
+ 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 void update_contact_from_response(SalOp *op, osip_message_t *response){
+ const char *received;
+ int rport;
+ 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*/
+ 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 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;
+}
+
+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;
+ const char *contact;
+
+ 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);
+ 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);
+ sal->callbacks.call_accepted(op);
+}
+
+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);
+ op->cid=-1;
+ sal->callbacks.call_terminated(op,from);
+ osip_free(from);
+}
+
+static void call_released(Sal *sal, eXosip_event_t *ev){
+ SalOp *op;
+ op=(SalOp*)ev->external_reference;
+ if (op==NULL){
+ return;
+ }
+ op->cid=-1;
+ if (op->did==-1)
+ sal->callbacks.call_failure(op,SalErrorNoResponse,SalReasonUnknown,NULL);
+}
+
+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;
+
+ *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 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);
+ }
+ 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;
+ op=find_op(sal,ev);
+ 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_add_pending_auth (sal,op);
+ 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=find_op(sal,ev);
+ 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=SalErrorFailure;
+ sr=SalReasonMedia;
+ 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;
+ }
+ if (code!=487) 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 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;
+ int rport;
+ osip_contact_t *ctt=NULL;
+ char *tmp;
+ char port[20];
+
+ 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;
+ if (contact_port==NULL || contact_port[0]=='\0')
+ contact_port="5060";
+ 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 <> %i)", contact_port,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);
+ }
+ 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);
+ sal_op_set_contact(op,tmp);
+ ms_message("Resending new register with updated contact %s",tmp);
+ ms_free(tmp);
+ return TRUE;
+}
+
+static void registration_success(Sal *sal, eXosip_event_t *ev){
+ SalOp *op=sal_find_register(sal,ev->rid);
+ 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=sal_find_register(sal,ev->rid);
+ 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 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:
+ 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 ");
+ 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");
+ sal_exosip_notify_recv(sal,ev);
+ break;
+ case EXOSIP_SUBSCRIPTION_ANSWERED:
+ ms_message("EXOSIP_SUBSCRIPTION_ANSWERED, ev->sid=%i\n",ev->sid);
+ sal_exosip_subscription_answered(sal,ev);
+ break;
+ case EXOSIP_SUBSCRIPTION_CLOSED:
+ ms_message("EXOSIP_SUBSCRIPTION_CLOSED\n");
+ sal_exosip_subscription_closed(sal,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_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);
+ }
+ break;
+ default:
+ ms_message("Unhandled exosip event ! %i");
+ break;
+ }
+ return TRUE;
+}
+
+int sal_iterate(Sal *sal){
+ eXosip_event_t *ev;
+ 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);
+ if (h->rid==-1){
+ eXosip_lock();
+ 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();
+ h->expires=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){
+ 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);
+}
+
--- /dev/null
+/*
+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 <eXosip2/eXosip.h>
+
+
+
+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 */
+ MSList *pending_auths;/*MSList of SalOp */
+ MSList *other_transactions; /*MSList of SalOp */
+ int running;
+ int session_expires;
+ void *up;
+};
+
+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;
+ 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;
+};
+
+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);
+
+void sal_exosip_fix_route(SalOp *op);
+
+
+#endif
--- /dev/null
+/*
+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);
+ 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);
+ 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 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, "<?xml version=\"1.0\"?>\n\
+<!DOCTYPE presence\n\
+PUBLIC \"-//IETF//DTD RFCxxxx XPIDF 1.0//EN\" \"xpidf.dtd\">\n\
+<presence>\n\
+<presentity uri=\"%s;method=SUBSCRIBE\" />\n\
+<atom id=\"%i\">\n\
+<address uri=\"%s;user=ip\" priority=\"0.800000\">\n\
+<status status=\"open\" />\n\
+<msnsubstatus substatus=\"online\" />\n\
+</address>\n\
+</atom>\n\
+</presence>", contact_info, atom_id, contact_info);
+
+ }
+ else if (online_status==SalPresenceBusy)
+ {
+ sprintf(buf, "<?xml version=\"1.0\"?>\n\
+<!DOCTYPE presence\n\
+PUBLIC \"-//IETF//DTD RFCxxxx XPIDF 1.0//EN\" \"xpidf.dtd\">\n\
+<presence>\n\
+<presentity uri=\"%s;method=SUBSCRIBE\" />\n\
+<atom id=\"%i\">\n\
+<address uri=\"%s;user=ip\" priority=\"0.800000\">\n\
+<status status=\"inuse\" />\n\
+<msnsubstatus substatus=\"busy\" />\n\
+</address>\n\
+</atom>\n\
+</presence>", contact_info, atom_id, contact_info);
+
+ }
+ else if (online_status==SalPresenceBerightback)
+ {
+ sprintf(buf, "<?xml version=\"1.0\"?>\n\
+<!DOCTYPE presence\n\
+PUBLIC \"-//IETF//DTD RFCxxxx XPIDF 1.0//EN\" \"xpidf.dtd\">\n\
+<presence>\n\
+<presentity uri=\"%s;method=SUBSCRIBE\" />\n\
+<atom id=\"%i\">\n\
+<address uri=\"%s;user=ip\" priority=\"0.800000\">\n\
+<status status=\"inactive\" />\n\
+<msnsubstatus substatus=\"berightback\" />\n\
+</address>\n\
+</atom>\n\
+</presence>", contact_info, atom_id, contact_info);
+
+ }
+ else if (online_status==SalPresenceAway)
+ {
+ sprintf(buf, "<?xml version=\"1.0\"?>\n\
+<!DOCTYPE presence\n\
+PUBLIC \"-//IETF//DTD RFCxxxx XPIDF 1.0//EN\" \"xpidf.dtd\">\n\
+<presence>\n\
+<presentity uri=\"%s;method=SUBSCRIBE\" />\n\
+<atom id=\"%i\">\n\
+<address uri=\"%s;user=ip\" priority=\"0.800000\">\n\
+<status status=\"inactive\" />\n\
+<msnsubstatus substatus=\"away\" />\n\
+</address>\n\
+</atom>\n\
+</presence>", contact_info, atom_id, contact_info);
+
+ }
+ else if (online_status==SalPresenceOnthephone)
+ {
+ sprintf(buf, "<?xml version=\"1.0\"?>\n\
+<!DOCTYPE presence\n\
+PUBLIC \"-//IETF//DTD RFCxxxx XPIDF 1.0//EN\" \"xpidf.dtd\">\n\
+<presence>\n\
+<presentity uri=\"%s;method=SUBSCRIBE\" />\n\
+<atom id=\"%i\">\n\
+<address uri=\"%s;user=ip\" priority=\"0.800000\">\n\
+<status status=\"inuse\" />\n\
+<msnsubstatus substatus=\"onthephone\" />\n\
+</address>\n\
+</atom>\n\
+</presence>", contact_info, atom_id, contact_info);
+
+ }
+ else if (online_status==SalPresenceOuttolunch)
+ {
+ sprintf(buf, "<?xml version=\"1.0\"?>\n\
+<!DOCTYPE presence\n\
+PUBLIC \"-//IETF//DTD RFCxxxx XPIDF 1.0//EN\" \"xpidf.dtd\">\n\
+<presence>\n\
+<presentity uri=\"%s;method=SUBSCRIBE\" />\n\
+<atom id=\"%i\">\n\
+<address uri=\"%s;user=ip\" priority=\"0.800000\">\n\
+<status status=\"inactive\" />\n\
+<msnsubstatus substatus=\"outtolunch\" />\n\
+</address>\n\
+</atom>\n\
+</presence>", contact_info, atom_id, contact_info);
+
+ }
+ else
+ {
+ sprintf(buf, "<?xml version=\"1.0\"?>\n\
+<!DOCTYPE presence\n\
+PUBLIC \"-//IETF//DTD RFCxxxx XPIDF 1.0//EN\" \"xpidf.dtd\">\n\
+<presence>\n\
+<presentity uri=\"%s;method=SUBSCRIBE\" />\n\
+<atom id=\"%i\">\n\
+<address uri=\"%s;user=ip\" priority=\"0.800000\">\n\
+<status status=\"inactive\" />\n\
+<msnsubstatus substatus=\"away\" />\n\
+</address>\n\
+</atom>\n\
+</presence>", 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, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
+<presence xmlns=\"urn:ietf:params:xml:ns:pidf\"\n\
+ entity=\"%s\">\n\
+<tuple id=\"sg89ae\">\n\
+<status>\n\
+<basic>open</basic>\n\
+</status>\n\
+<contact priority=\"0.8\">%s</contact>\n\
+<note>online</note>\n\
+</tuple>\n\
+</presence>",
+ contact_info, contact_info);
+ }
+ else if (online_status==SalPresenceBusy)
+ {
+ sprintf(buf, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
+<presence xmlns=\"urn:ietf:params:xml:ns:pidf\"\n\
+ xmlns:es=\"urn:ietf:params:xml:ns:pidf:status:rpid-status\"\n\
+ entity=\"%s\">\n\
+<tuple id=\"sg89ae\">\n\
+<status>\n\
+<basic>open</basic>\n\
+<es:activities>\n\
+ <es:activity>busy</es:activity>\n\
+</es:activities>\n\
+</status>\n\
+<contact priority=\"0.8\">%s</contact>\n\
+<note>busy</note>\n\
+</tuple>\n\
+</presence>",
+ contact_info, contact_info);
+ }
+ else if (online_status==SalPresenceBerightback)
+ {
+ sprintf(buf, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
+<presence xmlns=\"urn:ietf:params:xml:ns:pidf\"\n\
+ xmlns:es=\"urn:ietf:params:xml:ns:pidf:status:rpid-status\"\n\
+ entity=\"%s\">\n\
+<tuple id=\"sg89ae\">\n\
+<status>\n\
+<basic>open</basic>\n\
+<es:activities>\n\
+ <es:activity>in-transit</es:activity>\n\
+</es:activities>\n\
+</status>\n\
+<contact priority=\"0.8\">%s</contact>\n\
+<note>be right back</note>\n\
+</tuple>\n\
+</presence>",
+ contact_info, contact_info);
+ }
+ else if (online_status==SalPresenceAway)
+ {
+ sprintf(buf, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
+<presence xmlns=\"urn:ietf:params:xml:ns:pidf\"\n\
+ xmlns:es=\"urn:ietf:params:xml:ns:pidf:status:rpid-status\"\n\
+ entity=\"%s\">\n\
+<tuple id=\"sg89ae\">\n\
+<status>\n\
+<basic>open</basic>\n\
+<es:activities>\n\
+ <es:activity>away</es:activity>\n\
+</es:activities>\n\
+</status>\n\
+<contact priority=\"0.8\">%s</contact>\n\
+<note>away</note>\n\
+</tuple>\n\
+</presence>",
+ contact_info, contact_info);
+ }
+ else if (online_status==SalPresenceOnthephone)
+ {
+ sprintf(buf, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
+<presence xmlns=\"urn:ietf:params:xml:ns:pidf\"\n\
+ xmlns:es=\"urn:ietf:params:xml:ns:pidf:status:rpid-status\"\n\
+ entity=\"%s\">\n\
+<tuple id=\"sg89ae\">\n\
+<status>\n\
+<basic>open</basic>\n\
+<es:activities>\n\
+ <es:activity>on-the-phone</es:activity>\n\
+</es:activities>\n\
+</status>\n\
+<contact priority=\"0.8\">%s</contact>\n\
+<note>on the phone</note>\n\
+</tuple>\n\
+</presence>",
+ contact_info, contact_info);
+ }
+ else if (online_status==SalPresenceOuttolunch)
+ {
+ sprintf(buf, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
+<presence xmlns=\"urn:ietf:params:xml:ns:pidf\"\n\
+ xmlns:es=\"urn:ietf:params:xml:ns:pidf:status:rpid-status\"\n\
+ entity=\"%s\">\n\
+<tuple id=\"sg89ae\">\n\
+<status>\n\
+<basic>open</basic>\n\
+<es:activities>\n\
+ <es:activity>meal</es:activity>\n\
+</es:activities>\n\
+</status>\n\
+<contact priority=\"0.8\">%s</contact>\n\
+<note>out to lunch</note>\n\
+</tuple>\n\
+</presence>",
+ contact_info, contact_info);
+ }
+ else
+ {
+ /* */
+ sprintf(buf, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
+<presence xmlns=\"urn:ietf:params:xml:ns:pidf\"\n\
+xmlns:es=\"urn:ietf:params:xml:ns:pidf:status:rpid-status\"\n\
+entity=\"%s\">\n%s",
+ contact_info,
+"<tuple id=\"sg89ae\">\n\
+<status>\n\
+<basic>closed</basic>\n\
+<es:activities>\n\
+ <es:activity>permanent-absence</es:activity>\n\
+</es:activities>\n\
+</status>\n\
+</tuple>\n\
+\n</presence>\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_t ss=EXOSIP_SUBCRSTATE_ACTIVE;
+ if (op->nid==-1){
+ ms_warning("Cannot notify, subscription was closed.");
+ return -1;
+ }
+
+ eXosip_lock();
+ 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);
+ 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;
+}
+
+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), "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
+ <presence xmlns=\"urn:ietf:params:xml:ns:pidf\"\n\
+ entity=\"%s\">\n\
+ <tuple id=\"sg89ae\">\n\
+ <status>\n\
+ <basic>open</basic>\n\
+ </status>\n\
+ <contact priority=\"0.8\">%s</contact>\n\
+ <note>online</note>\n\
+ </tuple>\n\
+ </presence>",
+ from, from);
+ }
+ else if (presence_mode==SalPresenceBusy
+ ||presence_mode==SalPresenceDonotdisturb)
+ {
+ snprintf(buf, sizeof(buf), "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
+ <presence xmlns=\"urn:ietf:params:xml:ns:pidf\"\n\
+ xmlns:es=\"urn:ietf:params:xml:ns:pidf:status:rpid-status\"\n\
+ entity=\"%s\">\n\
+ <tuple id=\"sg89ae\">\n\
+ <status>\n\
+ <basic>open</basic>\n\
+ <es:activities>\n\
+ <es:activity>busy</es:activity>\n\
+ </es:activities>\n\
+ </status>\n\
+ <contact priority=\"0.8\">%s</contact>\n\
+ <note>busy</note>\n\
+ </tuple>\n\
+ </presence>",
+ from, from);
+ }
+ else if (presence_mode==SalPresenceBerightback)
+ {
+ snprintf(buf, sizeof(buf), "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
+ <presence xmlns=\"urn:ietf:params:xml:ns:pidf\"\n\
+ xmlns:es=\"urn:ietf:params:xml:ns:pidf:status:rpid-status\"\n\
+ entity=\"%s\">\n\
+ <tuple id=\"sg89ae\">\n\
+ <status>\n\
+ <basic>open</basic>\n\
+ <es:activities>\n\
+ <es:activity>in-transit</es:activity>\n\
+ </es:activities>\n\
+ </status>\n\
+ <contact priority=\"0.8\">%s</contact>\n\
+ <note>be right back</note>\n\
+ </tuple>\n\
+ </presence>",
+ from,from);
+ }
+ else if (presence_mode==SalPresenceAway
+ ||presence_mode==SalPresenceMoved)
+ {
+ snprintf(buf, sizeof(buf), "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
+ <presence xmlns=\"urn:ietf:params:xml:ns:pidf\"\n\
+ xmlns:es=\"urn:ietf:params:xml:ns:pidf:status:rpid-status\"\n\
+ entity=\"%s\">\n\
+ <tuple id=\"sg89ae\">\n\
+ <status>\n\
+ <basic>open</basic>\n\
+ <es:activities>\n\
+ <es:activity>away</es:activity>\n\
+ </es:activities>\n\
+ </status>\n\
+ <contact priority=\"0.8\">%s</contact>\n\
+ <note>away</note>\n\
+ </tuple>\n\
+ </presence>",
+ from, from);
+ }
+ else if (presence_mode==SalPresenceOnthephone)
+ {
+ snprintf(buf, sizeof(buf), "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
+ <presence xmlns=\"urn:ietf:params:xml:ns:pidf\"\n\
+ xmlns:es=\"urn:ietf:params:xml:ns:pidf:status:rpid-status\"\n\
+ entity=\"%s\">\n\
+ <tuple id=\"sg89ae\">\n\
+ <status>\n\
+ <basic>open</basic>\n\
+ <es:activities>\n\
+ <es:activity>on-the-phone</es:activity>\n\
+ </es:activities>\n\
+ </status>\n\
+ <contact priority=\"0.8\">%s</contact>\n\
+ <note>on the phone</note>\n\
+ </tuple>\n\
+ </presence>",
+ from, from);
+ }
+ else if (presence_mode==SalPresenceOuttolunch)
+ {
+ snprintf(buf, sizeof(buf), "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
+ <presence xmlns=\"urn:ietf:params:xml:ns:pidf\"\n\
+ xmlns:es=\"urn:ietf:params:xml:ns:pidf:status:rpid-status\"\n\
+ entity=\"%s\">\n\
+ <tuple id=\"sg89ae\">\n\
+ <status>\n\
+ <basic>open</basic>\n\
+ <es:activities>\n\
+ <es:activity>meal</es:activity>\n\
+ </es:activities>\n\
+ </status>\n\
+ <contact priority=\"0.8\">%s</contact>\n\
+ <note>out to lunch</note>\n\
+ </tuple>\n\
+ </presence>",
+ from, from);
+ }
+ else{
+ /* offline */
+ snprintf(buf, sizeof(buf), "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
+ <presence xmlns=\"urn:ietf:params:xml:ns:pidf\"\n\
+ xmlns:es=\"urn:ietf:params:xml:ns:pidf:status:rpid-status\"\n\
+ entity=\"%s\">\n%s",
+ from,
+ "<tuple id=\"sg89ae\">\n\
+ <status>\n\
+ <basic>closed</basic>\n\
+ <es:activities>\n\
+ <es:activity>permanent-absence</e:activity>\n\
+ </es:activities>\n\
+ </status>\n\
+ </tuple>\n\
+ \n</presence>\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;
+ 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.notify(op,op->sid!=-1 ? SalSubscribeActive : SalSubscribeTerminated, 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;
+}
+
+
--- /dev/null
+/*
+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 <eXosip2/eXosip.h>
+
+#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
+
+static 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...)*/
+static const 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;
+}
+
+#ifdef FOR_LATER
+/* return the value of attr "field" */
+static const 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;
+}
+#endif
+
+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;
+}
+
+
+
+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->channels>0)
+ 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));
+
+ 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==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 (port), NULL,
+ osip_strdup ("RTP/AVP"));
+ if (desc->bandwidth>0) sdp_message_b_bandwidth_add (msg, lineno, osip_strdup ("AS"),
+ int_2char(desc->bandwidth));
+ if (desc->ptime>0) sdp_message_a_attribute_add(msg,lineno,osip_strdup("ptime"),
+ int_2char(desc->ptime));
+ for(elem=desc->payloads;elem!=NULL;elem=elem->next){
+ add_payload(msg, lineno, (PayloadType*)elem->data);
+ }
+}
+
+sdp_message_t *media_description_to_sdp(const SalMediaDescription *desc){
+ int i;
+ sdp_message_t *msg=create_generic_sdp(desc);
+ for(i=0;i<desc->nstreams;++i){
+ add_line(msg,i,&desc->streams[i]);
+ }
+ return msg;
+}
+
+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(sdp_message_t *msg, SalMediaDescription *desc){
+ int i,j;
+ const char *mtype,*proto,*port,*addr,*number;
+ sdp_bandwidth_t *sbw=NULL;
+
+ 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) && i<SAL_MEDIA_DESCRIPTION_MAX_STREAMS; i++)
+ {
+ SalStreamDescription *stream=&desc->streams[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=SalProtoUnknown;
+ if (proto){
+ if (strcasecmp(proto,"RTP/AVP")==0)
+ stream->proto=SalProtoRtpAvp;
+ else if (strcasecmp(proto,"RTP/SAVP")==0){
+ stream->proto=SalProtoRtpSavp;
+ }
+ }
+ 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;
+ }else if (strcasecmp("video", mtype) == 0){
+ 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);
+ }
+ /* 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);
+ 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;
+}
#endif
#include "linphonecore.h"
+#include "private.h"
#include <ctype.h>
static void sip_login_init_instance(SipSetupContext *ctx){
} 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" },
{ 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 },
};
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);
}
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));
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;
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) {
{
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);
}
/* lc->config will turn NULL at exit, close the file to flush and
return to stop logging */
- if (lc->config == NULL) {
+ if (linphone_core_get_config(lc) == NULL) {
linphone_gtk_log_uninit();
return;
}
LinphoneAddress *from;
LinphoneCore *lc=linphone_gtk_get_core();
int nettype;
+ const char *passwd=NULL;
if (linphone_core_get_download_bandwidth(lc)==512 &&
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);
}
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);
}
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);
}
-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){
+ linphone_gtk_show_friends();
}
static void linphone_gtk_new_subscriber_response(GtkWidget *dialog, guint response_id, LinphoneFriend *lf){
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";
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);
}
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);
}
}