linphonecore.c 97.9 KB
Newer Older
aymeric's avatar
aymeric committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
/*
linphone
Copyright (C) 2000  Simon MORLAT (simon.morlat@linphone.org)

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 "linphonecore.h"
smorlat's avatar
smorlat committed
21
#include "sipsetup.h"
aymeric's avatar
aymeric committed
22 23 24
#include "lpconfig.h"
#include "private.h"
#include "mediastreamer2/mediastream.h"
smorlat's avatar
smorlat committed
25
#include "mediastreamer2/msvolume.h"
26
#include "mediastreamer2/msequalizer.h"
aymeric's avatar
aymeric committed
27 28 29 30

#include <ortp/telephonyevents.h>


31
#ifdef INET6
aymeric's avatar
aymeric committed
32
#ifndef WIN32
33
#include <netdb.h>
aymeric's avatar
aymeric committed
34 35 36
#endif
#endif

smorlat's avatar
smorlat committed
37
/*#define UNSTANDART_GSM_11K 1*/
aymeric's avatar
aymeric committed
38 39

static const char *liblinphone_version=LIBLINPHONE_VERSION;
40
static void set_network_reachable(LinphoneCore* lc,bool_t isReachable);
aymeric's avatar
aymeric committed
41 42 43 44 45 46 47 48 49

#include "enum.h"

void linphone_core_get_local_ip(LinphoneCore *lc, const char *dest, char *result);
static void toggle_video_preview(LinphoneCore *lc, bool_t val);

/* relative path where is stored local ring*/
#define LOCAL_RING "rings/oldphone.wav"
/* same for remote ring (ringback)*/
50
#define REMOTE_RING "ringback.wav"
aymeric's avatar
aymeric committed
51

Simon Morlat's avatar
Simon Morlat committed
52 53
extern SalCallbacks linphone_sal_callbacks;

aymeric's avatar
aymeric committed
54 55 56 57 58 59 60 61 62 63 64
void lc_callback_obj_init(LCCallbackObj *obj,LinphoneCoreCbFunc func,void* ud)
{
  obj->_func=func;
  obj->_user_data=ud;
}

int lc_callback_obj_invoke(LCCallbackObj *obj, LinphoneCore *lc){
	if (obj->_func!=NULL) obj->_func(lc,obj->_user_data);
	return 0;
}

65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112

static MSList *make_codec_list(const MSList *codecs){
	MSList *l=NULL;
	const MSList *it;
	for(it=codecs;it!=NULL;it=it->next){
		PayloadType *pt=(PayloadType*)it->data;
		if (pt->flags & PAYLOAD_TYPE_ENABLED){
			l=ms_list_append(l,payload_type_clone(pt));
		}
	}
	return l;
}

static SalMediaDescription *create_local_media_description(LinphoneCore *lc, 
    		const char *localip, const char *username){
	MSList *l;
	PayloadType *pt;
	SalMediaDescription *md=sal_media_description_new();
	md->nstreams=1;
	strncpy(md->addr,localip,sizeof(md->addr));
	strncpy(md->username,username,sizeof(md->username));
	/*set audio capabilities */
	strncpy(md->streams[0].addr,localip,sizeof(md->streams[0].addr));
	md->streams[0].port=linphone_core_get_audio_port(lc);
	md->streams[0].proto=SalProtoRtpAvp;
	md->streams[0].type=SalAudio;
	l=make_codec_list(lc->codecs_conf.audio_codecs);
	pt=payload_type_clone(rtp_profile_get_payload_from_mime(&av_profile,"telephone-event"));
	l=ms_list_append(l,pt);
	md->streams[0].payloads=l;
	
	if (lc->dw_audio_bw>0)
		md->streams[0].bandwidth=lc->dw_audio_bw;

	if (linphone_core_video_enabled (lc)){
		md->nstreams++;
		md->streams[1].port=linphone_core_get_video_port(lc);
		md->streams[1].proto=SalProtoRtpAvp;
		md->streams[1].type=SalVideo;
		l=make_codec_list(lc->codecs_conf.video_codecs);
		md->streams[1].payloads=l;
		if (lc->dw_video_bw)
			md->streams[1].bandwidth=lc->dw_video_bw;
	}
	return md;
}

static void linphone_call_init_common(LinphoneCall *call, LinphoneAddress *from, LinphoneAddress *to){
aymeric's avatar
aymeric committed
113 114
	call->state=LCStateInit;
	call->start_time=time(NULL);
smorlat's avatar
smorlat committed
115
	call->media_start_time=0;
aymeric's avatar
aymeric committed
116 117
	call->log=linphone_call_log_new(call, from, to);
	linphone_core_notify_all_friends(call->core,LINPHONE_STATUS_ONTHEPHONE);
118
	if (linphone_core_get_firewall_policy(call->core)==LINPHONE_POLICY_USE_STUN)
smorlat's avatar
smorlat committed
119
		linphone_core_run_stun_tests(call->core,call);
aymeric's avatar
aymeric committed
120 121 122 123 124 125 126 127 128 129 130 131 132 133 134
}

static void discover_mtu(LinphoneCore *lc, const char *remote){
	int mtu;
	if (lc->net_conf.mtu==0	){
		/*attempt to discover mtu*/
		mtu=ms_discover_mtu(remote);
		if (mtu>0){
			ms_set_mtu(mtu);
			ms_message("Discovered mtu is %i, RTP payload max size is %i",
				mtu, ms_get_payload_max_size());
		}
	}
}

135
LinphoneCall * linphone_call_new_outgoing(struct _LinphoneCore *lc, LinphoneAddress *from, LinphoneAddress *to)
aymeric's avatar
aymeric committed
136 137 138
{
	LinphoneCall *call=ms_new0(LinphoneCall,1);
	call->dir=LinphoneCallOutgoing;
139
	call->op=sal_op_new(lc->sal);
140
	sal_op_set_user_pointer(call->op,call);
aymeric's avatar
aymeric committed
141
	call->core=lc;
142
	linphone_core_get_local_ip(lc,linphone_address_get_domain(to),call->localip);
143 144
	call->localdesc=create_local_media_description (lc,call->localip,
		linphone_address_get_username(from));
145
	linphone_call_init_common(call,from,to);
146
	discover_mtu(lc,linphone_address_get_domain (to));
aymeric's avatar
aymeric committed
147 148 149
	return call;
}

150
LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *from, LinphoneAddress *to, SalOp *op){
aymeric's avatar
aymeric committed
151
	LinphoneCall *call=ms_new0(LinphoneCall,1);
152
	LinphoneAddress *me=linphone_core_get_primary_contact_parsed(lc);
smorlat's avatar
smorlat committed
153

aymeric's avatar
aymeric committed
154
	call->dir=LinphoneCallIncoming;
Simon Morlat's avatar
Simon Morlat committed
155
	sal_op_set_user_pointer(op,call);
156
	call->op=op;
aymeric's avatar
aymeric committed
157
	call->core=lc;
158
	
159 160
	linphone_address_clean(from);
	linphone_core_get_local_ip(lc,linphone_address_get_domain(from),call->localip);
161 162
	call->localdesc=create_local_media_description (lc,call->localip,
	    linphone_address_get_username(me));
163
	linphone_call_init_common(call, from, to);
164 165
	discover_mtu(lc,linphone_address_get_domain(from));
	linphone_address_destroy(me);
aymeric's avatar
aymeric committed
166 167 168 169 170 171 172
	return call;
}

void linphone_call_destroy(LinphoneCall *obj)
{
	linphone_core_notify_all_friends(obj->core,obj->core->prev_mode);
	linphone_call_log_completed(obj->log,obj);
173
	linphone_core_update_allocated_audio_bandwidth(obj->core);
174 175 176
	if (obj->op!=NULL) sal_op_release(obj->op);
	if (obj->resultdesc!=NULL) sal_media_description_unref(obj->resultdesc);
	if (obj->localdesc!=NULL) sal_media_description_unref(obj->localdesc);
aymeric's avatar
aymeric committed
177 178 179 180 181
	ms_free(obj);
}

/*prevent a gcc bug with %c*/
static size_t my_strftime(char *s, size_t max, const char  *fmt,  const struct tm *tm){
Jehan Monnier's avatar
Jehan Monnier committed
182
#if !defined(_WIN32_WCE)
aymeric's avatar
aymeric committed
183
	return strftime(s, max, fmt, tm);
Jehan Monnier's avatar
Jehan Monnier committed
184 185 186 187
#else
	return 0;
	/*FIXME*/
#endif /*_WIN32_WCE*/
aymeric's avatar
aymeric committed
188 189
}

190 191 192 193
static void set_call_log_date(LinphoneCallLog *cl, const struct tm *loctime){
	my_strftime(cl->start_date,sizeof(cl->start_date),"%c",loctime);
}

194
LinphoneCallLog * linphone_call_log_new(LinphoneCall *call, LinphoneAddress *from, LinphoneAddress *to){
aymeric's avatar
aymeric committed
195 196 197 198
	LinphoneCallLog *cl=ms_new0(LinphoneCallLog,1);
	struct tm loctime;
	cl->dir=call->dir;
#ifdef WIN32
Jehan Monnier's avatar
Jehan Monnier committed
199
#if !defined(_WIN32_WCE)
aymeric's avatar
aymeric committed
200
	loctime=*localtime(&call->start_time);
Jehan Monnier's avatar
Jehan Monnier committed
201 202
	/*FIXME*/
#endif /*_WIN32_WCE*/
aymeric's avatar
aymeric committed
203 204 205
#else
	localtime_r(&call->start_time,&loctime);
#endif
206
	set_call_log_date(cl,&loctime);
aymeric's avatar
aymeric committed
207 208 209 210
	cl->from=from;
	cl->to=to;
	return cl;
}
211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267

static void call_logs_write_to_config_file(LinphoneCore *lc){
	MSList *elem;
	char logsection[32];
	int i;
	char *tmp;
	LpConfig *cfg=lc->config;

	if (!lc->ready) return;
	
	for(i=0,elem=lc->call_logs;elem!=NULL;elem=elem->next,++i){
		LinphoneCallLog *cl=(LinphoneCallLog*)elem->data;
		snprintf(logsection,sizeof(logsection),"call_log_%i",i);
		lp_config_set_int(cfg,logsection,"dir",cl->dir);
		lp_config_set_int(cfg,logsection,"status",cl->status);
		tmp=linphone_address_as_string(cl->from);
		lp_config_set_string(cfg,logsection,"from",tmp);
		ms_free(tmp);
		tmp=linphone_address_as_string(cl->to);
		lp_config_set_string(cfg,logsection,"to",tmp);
		ms_free(tmp);
		lp_config_set_string(cfg,logsection,"start_date",cl->start_date);
		lp_config_set_int(cfg,logsection,"duration",cl->duration);
		if (cl->refkey) lp_config_set_string(cfg,logsection,"refkey",cl->refkey);
	}
	for(;i<lc->max_call_logs;++i){
		snprintf(logsection,sizeof(logsection),"call_log_%i",i);
		lp_config_clean_section(cfg,logsection);
	}
}

static void call_logs_read_from_config_file(LinphoneCore *lc){
	char logsection[32];
	int i;
	const char *tmp;
	LpConfig *cfg=lc->config;
	for(i=0;;++i){
		snprintf(logsection,sizeof(logsection),"call_log_%i",i);
		if (lp_config_has_section(cfg,logsection)){
			LinphoneCallLog *cl=ms_new0(LinphoneCallLog,1);
			cl->dir=lp_config_get_int(cfg,logsection,"dir",0);
			cl->status=lp_config_get_int(cfg,logsection,"status",0);
			tmp=lp_config_get_string(cfg,logsection,"from",NULL);
			if (tmp) cl->from=linphone_address_new(tmp);
			tmp=lp_config_get_string(cfg,logsection,"to",NULL);
			if (tmp) cl->to=linphone_address_new(tmp);
			tmp=lp_config_get_string(cfg,logsection,"start_date",NULL);
			if (tmp) strncpy(cl->start_date,tmp,sizeof(cl->start_date));
			cl->duration=lp_config_get_int(cfg,logsection,"duration",0);
			tmp=lp_config_get_string(cfg,logsection,"refkey",NULL);
			if (tmp) cl->refkey=ms_strdup(tmp);
			lc->call_logs=ms_list_append(lc->call_logs,cl);
		}else break;	
	}
}


aymeric's avatar
aymeric committed
268 269
void linphone_call_log_completed(LinphoneCallLog *calllog, LinphoneCall *call){
	LinphoneCore *lc=call->core;
270
	
aymeric's avatar
aymeric committed
271 272 273 274 275 276 277 278 279 280
	calllog->duration=time(NULL)-call->start_time;
	switch(call->state){
		case LCStateInit:
			calllog->status=LinphoneCallAborted;
			break;
		case LCStateRinging:
			if (calllog->dir==LinphoneCallIncoming){
				char *info;
				calllog->status=LinphoneCallMissed;
				lc->missed_calls++;
281 282 283
				info=ortp_strdup_printf(ngettext("You have missed %i call.",
                            "You have missed %i calls.", lc->missed_calls),
                        lc->missed_calls);
aymeric's avatar
aymeric committed
284 285 286 287 288 289 290 291 292
				lc->vtable.display_status(lc,info);
				ms_free(info);
			}
			else calllog->status=LinphoneCallAborted;
			break;
		case LCStateAVRunning:
			calllog->status=LinphoneCallSuccess;
			break;
	}
Simon Morlat's avatar
Simon Morlat committed
293
	lc->call_logs=ms_list_prepend(lc->call_logs,(void *)calllog);
aymeric's avatar
aymeric committed
294
	if (ms_list_size(lc->call_logs)>lc->max_call_logs){
Simon Morlat's avatar
Simon Morlat committed
295 296 297 298 299 300
		MSList *elem,*prevelem=NULL;
		/*find the last element*/
		for(elem=lc->call_logs;elem!=NULL;elem=elem->next){
			prevelem=elem;
		}
		elem=prevelem;
aymeric's avatar
aymeric committed
301 302 303 304 305 306
		linphone_call_log_destroy((LinphoneCallLog*)elem->data);
		lc->call_logs=ms_list_remove_link(lc->call_logs,elem);
	}
	if (lc->vtable.call_log_updated!=NULL){
		lc->vtable.call_log_updated(lc,calllog);
	}
307
	call_logs_write_to_config_file(lc);
aymeric's avatar
aymeric committed
308 309
}

smorlat's avatar
smorlat committed
310 311 312 313 314 315 316 317 318 319
/**
 * @addtogroup call_logs
 * @{
**/

/**
 * Returns a human readable string describing the call.
 * 
 * @note: the returned char* must be freed by the application (use ms_free()).
**/
aymeric's avatar
aymeric committed
320 321
char * linphone_call_log_to_str(LinphoneCallLog *cl){
	char *status;
322
	char *tmp;
323 324
	char *from=linphone_address_as_string (cl->from);
	char *to=linphone_address_as_string (cl->to);
aymeric's avatar
aymeric committed
325 326 327 328 329 330 331 332 333 334 335 336 337
	switch(cl->status){
		case LinphoneCallAborted:
			status=_("aborted");
			break;
		case LinphoneCallSuccess:
			status=_("completed");
			break;
		case LinphoneCallMissed:
			status=_("missed");
			break;
		default:
			status="unknown";
	}
338
	tmp=ortp_strdup_printf(_("%s at %s\nFrom: %s\nTo: %s\nStatus: %s\nDuration: %i mn %i sec\n"),
aymeric's avatar
aymeric committed
339 340
			(cl->dir==LinphoneCallIncoming) ? _("Incoming call") : _("Outgoing call"),
			cl->start_date,
341 342
			from,
			to,
aymeric's avatar
aymeric committed
343 344 345
			status,
			cl->duration/60,
			cl->duration%60);
346 347 348
	ms_free(from);
	ms_free(to);
	return tmp;
aymeric's avatar
aymeric committed
349 350
}

smorlat's avatar
smorlat committed
351 352 353 354 355 356 357 358
void linphone_call_log_set_user_pointer(LinphoneCallLog *cl, void *up){
	cl->user_pointer=up;
}

void *linphone_call_log_get_user_pointer(const LinphoneCallLog *cl){
	return cl->user_pointer;
}

smorlat's avatar
smorlat committed
359 360


361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387
/**
 * Associate a persistent reference key to the call log.
 *
 * The reference key can be for example an id to an external database.
 * It is stored in the config file, thus can survive to process exits/restarts.
 *
**/
void linphone_call_log_set_ref_key(LinphoneCallLog *cl, const char *refkey){
	if (cl->refkey!=NULL){
		ms_free(cl->refkey);
		cl->refkey=NULL;
	}
	if (refkey) cl->refkey=ms_strdup(refkey);
	call_logs_write_to_config_file(cl->lc);
}

/**
 * Get the persistent reference key associated to the call log.
 *
 * The reference key can be for example an id to an external database.
 * It is stored in the config file, thus can survive to process exits/restarts.
 *
**/
const char *linphone_call_log_get_ref_key(const LinphoneCallLog *cl){
	return cl->refkey;
}

smorlat's avatar
smorlat committed
388 389
/** @} */

aymeric's avatar
aymeric committed
390
void linphone_call_log_destroy(LinphoneCallLog *cl){
391 392 393
	if (cl->from!=NULL) linphone_address_destroy(cl->from);
	if (cl->to!=NULL) linphone_address_destroy(cl->to);
	if (cl->refkey!=NULL) ms_free(cl->refkey);
aymeric's avatar
aymeric committed
394 395 396
	ms_free(cl);
}

smorlat's avatar
smorlat committed
397 398 399
int linphone_core_get_current_call_duration(const LinphoneCore *lc){
	LinphoneCall *call=lc->call;
	if (call==NULL) return 0;
smorlat's avatar
smorlat committed
400 401 402 403
	if (call->media_start_time==0) return 0;
	return time(NULL)-call->media_start_time;
}

404
const LinphoneAddress *linphone_core_get_remote_uri(LinphoneCore *lc){
smorlat's avatar
smorlat committed
405 406 407
	LinphoneCall *call=lc->call;
	if (call==NULL) return 0;
	return call->dir==LinphoneCallIncoming ? call->log->from : call->log->to;
smorlat's avatar
smorlat committed
408 409
}

410 411 412 413 414 415 416 417
/**
 * Enable logs in supplied FILE*.
 *
 * @ingroup misc
 *
 * @param file a C FILE* where to fprintf logs. If null stdout is used.
 * 
**/
aymeric's avatar
aymeric committed
418 419 420 421 422 423
void linphone_core_enable_logs(FILE *file){
	if (file==NULL) file=stdout;
	ortp_set_log_file(file);
	ortp_set_log_level_mask(ORTP_MESSAGE|ORTP_WARNING|ORTP_ERROR|ORTP_FATAL);
}

424 425 426 427 428 429 430 431 432
/**
 * Enable logs through the user's supplied log callback.
 *
 * @ingroup misc
 *
 * @param logfunc The address of a OrtpLogFunc callback whose protoype is
 *            	  typedef void (*OrtpLogFunc)(OrtpLogLevel lev, const char *fmt, va_list args);
 * 
**/
aymeric's avatar
aymeric committed
433 434 435 436 437
void linphone_core_enable_logs_with_cb(OrtpLogFunc logfunc){
	ortp_set_log_level_mask(ORTP_MESSAGE|ORTP_WARNING|ORTP_ERROR|ORTP_FATAL);
	ortp_set_log_handler(logfunc);
}

438 439 440 441 442
/**
 * Entirely disable logging.
 *
 * @ingroup misc
**/
aymeric's avatar
aymeric committed
443 444 445 446 447
void linphone_core_disable_logs(){
	ortp_set_log_level_mask(ORTP_ERROR|ORTP_FATAL);
}


448
static void
aymeric's avatar
aymeric committed
449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470
net_config_read (LinphoneCore *lc)
{
	int tmp;
	const char *tmpstr;
	LpConfig *config=lc->config;

	tmp=lp_config_get_int(config,"net","download_bw",0);
	linphone_core_set_download_bandwidth(lc,tmp);
	tmp=lp_config_get_int(config,"net","upload_bw",0);
	linphone_core_set_upload_bandwidth(lc,tmp);
	linphone_core_set_stun_server(lc,lp_config_get_string(config,"net","stun_server",NULL));
	tmpstr=lp_config_get_string(lc->config,"net","nat_address",NULL);
	if (tmpstr!=NULL && (strlen(tmpstr)<1)) tmpstr=NULL;
	linphone_core_set_nat_address(lc,tmpstr);
	tmp=lp_config_get_int(lc->config,"net","firewall_policy",0);
	linphone_core_set_firewall_policy(lc,tmp);
	tmp=lp_config_get_int(lc->config,"net","nat_sdp_only",0);
	lc->net_conf.nat_sdp_only=tmp;
	tmp=lp_config_get_int(lc->config,"net","mtu",0);
	linphone_core_set_mtu(lc,tmp);
}

471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486
static void build_sound_devices_table(LinphoneCore *lc){
	const char **devices;
	const char **old;
	int ndev;
	int i;
	const MSList *elem=ms_snd_card_manager_get_list(ms_snd_card_manager_get());
	ndev=ms_list_size(elem);
	devices=ms_malloc((ndev+1)*sizeof(const char *));
	for (i=0;elem!=NULL;elem=elem->next,i++){
		devices[i]=ms_snd_card_get_string_id((MSSndCard *)elem->data);
	}
	devices[ndev]=NULL;
	old=lc->sound_conf.cards;
	lc->sound_conf.cards=devices;
	if (old!=NULL) ms_free(old);
}
aymeric's avatar
aymeric committed
487

488
static void sound_config_read(LinphoneCore *lc)
aymeric's avatar
aymeric committed
489 490 491 492
{
	/*int tmp;*/
	const char *tmpbuf;
	const char *devid;
493
#ifdef __linux
aymeric's avatar
aymeric committed
494 495 496 497 498 499 500 501
	/*alsadev let the user use custom alsa device within linphone*/
	devid=lp_config_get_string(lc->config,"sound","alsadev",NULL);
	if (devid){
		MSSndCard *card=ms_alsa_card_new_custom(devid,devid);
		ms_snd_card_manager_add_card(ms_snd_card_manager_get(),card);
	}
#endif
	/* retrieve all sound devices */
502 503
	build_sound_devices_table(lc);

aymeric's avatar
aymeric committed
504 505
	devid=lp_config_get_string(lc->config,"sound","playback_dev_id",NULL);
	linphone_core_set_playback_device(lc,devid);
506

aymeric's avatar
aymeric committed
507 508
	devid=lp_config_get_string(lc->config,"sound","ringer_dev_id",NULL);
	linphone_core_set_ringer_device(lc,devid);
509

aymeric's avatar
aymeric committed
510 511
	devid=lp_config_get_string(lc->config,"sound","capture_dev_id",NULL);
	linphone_core_set_capture_device(lc,devid);
512

aymeric's avatar
aymeric committed
513 514 515 516 517 518 519 520 521 522
/*
	tmp=lp_config_get_int(lc->config,"sound","play_lev",80);
	linphone_core_set_play_level(lc,tmp);
	tmp=lp_config_get_int(lc->config,"sound","ring_lev",80);
	linphone_core_set_ring_level(lc,tmp);
	tmp=lp_config_get_int(lc->config,"sound","rec_lev",80);
	linphone_core_set_rec_level(lc,tmp);
	tmpbuf=lp_config_get_string(lc->config,"sound","source","m");
	linphone_core_set_sound_source(lc,tmpbuf[0]);
*/
523

aymeric's avatar
aymeric committed
524 525
	tmpbuf=PACKAGE_SOUND_DIR "/" LOCAL_RING;
	tmpbuf=lp_config_get_string(lc->config,"sound","local_ring",tmpbuf);
Jehan Monnier's avatar
Jehan Monnier committed
526
	if (ortp_file_exist(tmpbuf)==-1) {
aymeric's avatar
aymeric committed
527 528 529 530 531 532
		tmpbuf=PACKAGE_SOUND_DIR "/" LOCAL_RING;
	}
	if (strstr(tmpbuf,".wav")==NULL){
		/* it currently uses old sound files, so replace them */
		tmpbuf=PACKAGE_SOUND_DIR "/" LOCAL_RING;
	}
533

aymeric's avatar
aymeric committed
534
	linphone_core_set_ring(lc,tmpbuf);
535

536
	tmpbuf=PACKAGE_SOUND_DIR "/" REMOTE_RING;
aymeric's avatar
aymeric committed
537
	tmpbuf=lp_config_get_string(lc->config,"sound","remote_ring",tmpbuf);
Jehan Monnier's avatar
Jehan Monnier committed
538
	if (ortp_file_exist(tmpbuf)==-1){
539
		tmpbuf=PACKAGE_SOUND_DIR "/" REMOTE_RING;
aymeric's avatar
aymeric committed
540 541 542
	}
	if (strstr(tmpbuf,".wav")==NULL){
		/* it currently uses old sound files, so replace them */
543
		tmpbuf=PACKAGE_SOUND_DIR "/" REMOTE_RING;
aymeric's avatar
aymeric committed
544
	}
545
	linphone_core_set_ringback(lc,tmpbuf);
aymeric's avatar
aymeric committed
546 547 548
	check_sound_device(lc);
	lc->sound_conf.latency=0;

549 550 551 552
	linphone_core_enable_echo_cancellation(lc,
	    lp_config_get_int(lc->config,"sound","echocancelation",0) |
	    lp_config_get_int(lc->config,"sound","echocancellation",0)
		);
smorlat's avatar
smorlat committed
553 554 555

	linphone_core_enable_echo_limiter(lc,
		lp_config_get_int(lc->config,"sound","echolimiter",0));
556 557
	linphone_core_enable_agc(lc,
		lp_config_get_int(lc->config,"sound","agc",0));
aymeric's avatar
aymeric committed
558 559
}

560
static void sip_config_read(LinphoneCore *lc)
aymeric's avatar
aymeric committed
561 562 563 564 565 566 567 568 569
{
	char *contact;
	const char *tmpstr;
	int port;
	int i,tmp;
	int ipv6;
	port=lp_config_get_int(lc->config,"sip","use_info",0);
	linphone_core_set_use_info_for_dtmf(lc,port);

570 571 572
	port=lp_config_get_int(lc->config,"sip","use_rfc2833",0);
	linphone_core_set_use_rfc2833_for_dtmf(lc,port);

aymeric's avatar
aymeric committed
573 574 575 576 577 578 579 580 581 582
	ipv6=lp_config_get_int(lc->config,"sip","use_ipv6",-1);
	if (ipv6==-1){
		ipv6=0;
		if (host_has_ipv6_network()){
			lc->vtable.display_message(lc,_("Your machine appears to be connected to an IPv6 network. By default linphone always uses IPv4. Please update your configuration if you want to use IPv6"));
		}
	}
	linphone_core_enable_ipv6(lc,ipv6);
	port=lp_config_get_int(lc->config,"sip","sip_port",5060);
	linphone_core_set_sip_port(lc,port);
583

aymeric's avatar
aymeric committed
584 585
	tmpstr=lp_config_get_string(lc->config,"sip","contact",NULL);
	if (tmpstr==NULL || linphone_core_set_primary_contact(lc,tmpstr)==-1) {
smorlat's avatar
smorlat committed
586 587
		const char *hostname=NULL;
		const char *username=NULL;
588
#ifdef HAVE_GETENV
smorlat's avatar
smorlat committed
589 590
		hostname=getenv("HOST");
		username=getenv("USER");
aymeric's avatar
aymeric committed
591
		if (hostname==NULL) hostname=getenv("HOSTNAME");
592
#endif /*HAVE_GETENV*/
aymeric's avatar
aymeric committed
593 594 595 596 597 598 599 600 601 602 603 604
		if (hostname==NULL)
			hostname="unknown-host";
		if (username==NULL){
			username="toto";
		}
		contact=ortp_strdup_printf("sip:%s@%s",username,hostname);
		linphone_core_set_primary_contact(lc,contact);
		ms_free(contact);
	}

	tmp=lp_config_get_int(lc->config,"sip","guess_hostname",1);
	linphone_core_set_guess_hostname(lc,tmp);
605 606


aymeric's avatar
aymeric committed
607 608 609 610 611 612 613 614 615 616 617 618 619 620 621
	tmp=lp_config_get_int(lc->config,"sip","inc_timeout",15);
	linphone_core_set_inc_timeout(lc,tmp);

	/* get proxies config */
	for(i=0;; i++){
		LinphoneProxyConfig *cfg=linphone_proxy_config_new_from_config_file(lc->config,i);
		if (cfg!=NULL){
			linphone_core_add_proxy_config(lc,cfg);
		}else{
			break;
		}
	}
	/* get the default proxy */
	tmp=lp_config_get_int(lc->config,"sip","default_proxy",-1);
	linphone_core_set_default_proxy_index(lc,tmp);
622

aymeric's avatar
aymeric committed
623 624 625 626 627 628 629 630 631
	/* read authentication information */
	for(i=0;; i++){
		LinphoneAuthInfo *ai=linphone_auth_info_new_from_config_file(lc->config,i);
		if (ai!=NULL){
			linphone_core_add_auth_info(lc,ai);
		}else{
			break;
		}
	}
632
	
aymeric's avatar
aymeric committed
633 634
	/*for test*/
	lc->sip_conf.sdp_200_ack=lp_config_get_int(lc->config,"sip","sdp_200_ack",0);
smorlat's avatar
smorlat committed
635
	lc->sip_conf.only_one_codec=lp_config_get_int(lc->config,"sip","only_one_codec",0);
636
	lc->sip_conf.register_only_when_network_is_up=
637
		lp_config_get_int(lc->config,"sip","register_only_when_network_is_up",1);
aymeric's avatar
aymeric committed
638 639
}

640
static void rtp_config_read(LinphoneCore *lc)
aymeric's avatar
aymeric committed
641 642 643 644 645 646
{
	int port;
	int jitt_comp;
	int nortp_timeout;
	port=lp_config_get_int(lc->config,"rtp","audio_rtp_port",7078);
	linphone_core_set_audio_port(lc,port);
647

aymeric's avatar
aymeric committed
648 649 650
	port=lp_config_get_int(lc->config,"rtp","video_rtp_port",9078);
	if (port==0) port=9078;
	linphone_core_set_video_port(lc,port);
651

aymeric's avatar
aymeric committed
652
	jitt_comp=lp_config_get_int(lc->config,"rtp","audio_jitt_comp",60);
653
	linphone_core_set_audio_jittcomp(lc,jitt_comp);
aymeric's avatar
aymeric committed
654 655
	jitt_comp=lp_config_get_int(lc->config,"rtp","video_jitt_comp",60);
	nortp_timeout=lp_config_get_int(lc->config,"rtp","nortp_timeout",30);
656
	linphone_core_set_nortp_timeout(lc,nortp_timeout);
aymeric's avatar
aymeric committed
657 658
}

659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675
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;
}
aymeric's avatar
aymeric committed
676

677
static bool_t get_codec(LpConfig *config, char* type, int index, PayloadType **ret){
aymeric's avatar
aymeric committed
678 679 680 681
	char codeckey[50];
	const char *mime,*fmtp;
	int rate,enabled;
	PayloadType *pt;
682

683
	*ret=NULL;
aymeric's avatar
aymeric committed
684 685
	snprintf(codeckey,50,"%s_%i",type,index);
	mime=lp_config_get_string(config,codeckey,"mime",NULL);
686
	if (mime==NULL || strlen(mime)==0 ) return FALSE;
687

aymeric's avatar
aymeric committed
688 689 690
	rate=lp_config_get_int(config,codeckey,"rate",8000);
	fmtp=lp_config_get_string(config,codeckey,"recv_fmtp",NULL);
	enabled=lp_config_get_int(config,codeckey,"enabled",1);
691 692
	pt=find_payload(&av_profile,mime,rate,fmtp);
	if (pt && enabled ) pt->flags|=PAYLOAD_TYPE_ENABLED;
aymeric's avatar
aymeric committed
693
	//ms_message("Found codec %s/%i",pt->mime_type,pt->clock_rate);
694 695 696 697 698 699
	if (pt==NULL) ms_warning("Ignoring codec config %s/%i with fmtp=%s because unsupported",
	    		mime,rate,fmtp ? fmtp : "");
	*ret=pt;
	return TRUE;
}

700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727
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;
728
	return 0;
729 730
}

731 732 733 734 735 736 737 738 739 740 741 742 743
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){
Simon Morlat's avatar
Simon Morlat committed
744
					payload_type_set_flag(pt,PAYLOAD_TYPE_ENABLED);
745 746
					ms_message("Adding new codec %s/%i with fmtp %s",
					    pt->mime_type,pt->clock_rate,pt->recv_fmtp ? pt->recv_fmtp : "");
747
					l=ms_list_insert_sorted(l,pt,(int (*)(const void *, const void *))codec_compare);
748 749 750 751 752
				}
			}
		}
	}
	return l;
aymeric's avatar
aymeric committed
753 754
}

755
static void codecs_config_read(LinphoneCore *lc)
aymeric's avatar
aymeric committed
756 757 758 759 760
{
	int i;
	PayloadType *pt;
	MSList *audio_codecs=NULL;
	MSList *video_codecs=NULL;
761 762 763 764 765 766
	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);
		}
aymeric's avatar
aymeric committed
767
	}
768 769 770 771 772 773 774
	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);
		}
aymeric's avatar
aymeric committed
775
	}
776
	video_codecs=add_missing_codecs(SalVideo,video_codecs);
aymeric's avatar
aymeric committed
777 778
	linphone_core_set_audio_codecs(lc,audio_codecs);
	linphone_core_set_video_codecs(lc,video_codecs);
779
	linphone_core_update_allocated_audio_bandwidth(lc);
aymeric's avatar
aymeric committed
780 781
}

782
static void video_config_read(LinphoneCore *lc){
Simon Morlat's avatar
Simon Morlat committed
783
	int capture, display, self_view;
aymeric's avatar
aymeric committed
784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803
	int enabled;
	const char *str;
	int ndev;
	const char **devices;
	const MSList *elem;
	int i;

	/* retrieve all video devices */
	elem=ms_web_cam_manager_get_list(ms_web_cam_manager_get());
	ndev=ms_list_size(elem);
	devices=ms_malloc((ndev+1)*sizeof(const char *));
	for (i=0;elem!=NULL;elem=elem->next,i++){
		devices[i]=ms_web_cam_get_string_id((MSWebCam *)elem->data);
	}
	devices[ndev]=NULL;
	lc->video_conf.cams=devices;

	str=lp_config_get_string(lc->config,"video","device",NULL);
	if (str && str[0]==0) str=NULL;
	linphone_core_set_video_device(lc,str);
804

smorlat's avatar
smorlat committed
805 806 807
	linphone_core_set_preferred_video_size_by_name(lc,
		lp_config_get_string(lc->config,"video","size","cif"));

aymeric's avatar
aymeric committed
808 809 810
	enabled=lp_config_get_int(lc->config,"video","enabled",1);
	capture=lp_config_get_int(lc->config,"video","capture",enabled);
	display=lp_config_get_int(lc->config,"video","display",enabled);
Simon Morlat's avatar
Simon Morlat committed
811
	self_view=lp_config_get_int(lc->config,"video","self_view",enabled);
aymeric's avatar
aymeric committed
812 813
#ifdef VIDEO_ENABLED
	linphone_core_enable_video(lc,capture,display);
Simon Morlat's avatar
Simon Morlat committed
814
	linphone_core_enable_self_view(lc,self_view);
aymeric's avatar
aymeric committed
815 816 817
#endif
}

818
static void ui_config_read(LinphoneCore *lc)
aymeric's avatar
aymeric committed
819 820 821 822 823 824
{
	LinphoneFriend *lf;
	int i;
	for (i=0;(lf=linphone_friend_new_from_config_file(lc,i))!=NULL;i++){
		linphone_core_add_friend(lc,lf);
	}
825
	call_logs_read_from_config_file(lc);
aymeric's avatar
aymeric committed
826 827
}

828 829
/*
static void autoreplier_config_init(LinphoneCore *lc)
aymeric's avatar
aymeric committed
830 831 832 833 834 835 836 837 838
{
	autoreplier_config_t *config=&lc->autoreplier_conf;
	config->enabled=lp_config_get_int(lc->config,"autoreplier","enabled",0);
	config->after_seconds=lp_config_get_int(lc->config,"autoreplier","after_seconds",6);
	config->max_users=lp_config_get_int(lc->config,"autoreplier","max_users",1);
	config->max_rec_time=lp_config_get_int(lc->config,"autoreplier","max_rec_time",60);
	config->max_rec_msg=lp_config_get_int(lc->config,"autoreplier","max_rec_msg",10);
	config->message=lp_config_get_string(lc->config,"autoreplier","message",NULL);
}
839
*/
aymeric's avatar
aymeric committed
840

841 842 843 844 845 846 847 848 849 850 851 852 853 854
/**
 * Sets maximum available download bandwidth
 *
 * @ingroup media_parameters
 *
 * This is IP bandwidth, in kbit/s.
 * This information is used signaled to other parties during
 * calls (within SDP messages) so that the remote end can have
 * sufficient knowledge to properly configure its audio & video
 * codec output bitrate to not overflow available bandwidth.
 *
 * @param lc the LinphoneCore object
 * @param bw the bandwidth in kbits/s, 0 for infinite
 */
aymeric's avatar
aymeric committed
855 856 857 858 859 860
void linphone_core_set_download_bandwidth(LinphoneCore *lc, int bw){
	lc->net_conf.download_bw=bw;
	if (bw==0){ /*infinite*/
		lc->dw_audio_bw=-1;
		lc->dw_video_bw=-1;
	}else {
861 862
		lc->dw_audio_bw=MIN(lc->audio_bw,bw);
		lc->dw_video_bw=MAX(bw-lc->dw_audio_bw-10,0);/*-10: security margin*/
aymeric's avatar
aymeric committed
863 864 865
	}
}

866 867 868 869 870 871 872 873 874 875 876 877 878
/**
 * Sets maximum available upload bandwidth
 *
 * @ingroup media_parameters
 *
 * This is IP bandwidth, in kbit/s.
 * This information is used by liblinphone together with remote
 * side available bandwidth signaled in SDP messages to properly
 * configure audio & video codec's output bitrate.
 *
 * @param lc the LinphoneCore object
 * @param bw the bandwidth in kbits/s, 0 for infinite
 */
aymeric's avatar
aymeric committed
879 880 881 882 883 884
void linphone_core_set_upload_bandwidth(LinphoneCore *lc, int bw){
	lc->net_conf.upload_bw=bw;
	if (bw==0){ /*infinite*/
		lc->up_audio_bw=-1;
		lc->up_video_bw=-1;
	}else{
885 886
		lc->up_audio_bw=MIN(lc->audio_bw,bw);
		lc->up_video_bw=MAX(bw-lc->up_audio_bw-10,0);/*-10: security margin*/
aymeric's avatar
aymeric committed
887 888 889
	}
}

890 891 892 893 894 895 896 897
/**
 * Retrieve the maximum available download bandwidth.
 *
 * @ingroup media_parameters
 *
 * This value was set by linphone_core_set_download_bandwidth().
 *
**/
aymeric's avatar
aymeric committed
898 899 900 901
int linphone_core_get_download_bandwidth(const LinphoneCore *lc){
	return lc->net_conf.download_bw;
}

902 903 904 905 906 907 908 909
/**
 * Retrieve the maximum available upload bandwidth.
 *
 * @ingroup media_parameters
 *
 * This value was set by linphone_core_set_upload_bandwidth().
 *
**/
aymeric's avatar
aymeric committed
910 911 912 913
int linphone_core_get_upload_bandwidth(const LinphoneCore *lc){
	return lc->net_conf.upload_bw;
}

914 915 916 917 918 919
/**
 * Returns liblinphone's version as a string.
 *
 * @ingroup misc
 *
**/
aymeric's avatar
aymeric committed
920 921 922 923 924
const char * linphone_core_get_version(void){
	return liblinphone_version;
}


925
static MSList *linphone_payload_types=NULL;
aymeric's avatar
aymeric committed
926

927 928 929
static void linphone_core_assign_payload_type(PayloadType *const_pt, int number, const char *recv_fmtp){
	PayloadType *pt;
	pt=payload_type_clone(const_pt);
930
	payload_type_set_number(pt,number);
931 932
	if (recv_fmtp!=NULL) payload_type_set_recv_fmtp(pt,recv_fmtp);
	rtp_profile_set_payload(&av_profile,number,pt);
933
	linphone_payload_types=ms_list_append(linphone_payload_types,pt);
934 935 936 937 938 939 940
}

static void linphone_core_free_payload_types(void){
	ms_list_for_each(linphone_payload_types,(void (*)(void*))payload_type_destroy);
	ms_list_free(linphone_payload_types);
	linphone_payload_types=NULL;
}
941

942 943
static void linphone_core_init (LinphoneCore * lc, const LinphoneCoreVTable *vtable, const char *config_path, 
    const char *factory_config_path, void * userdata)
aymeric's avatar
aymeric committed
944 945 946
{
	memset (lc, 0, sizeof (LinphoneCore));
	lc->data=userdata;
smorlat's avatar
fixes  
smorlat committed
947

aymeric's avatar
aymeric committed
948 949
	memcpy(&lc->vtable,vtable,sizeof(LinphoneCoreVTable));

smorlat's avatar
fixes  
smorlat committed
950 951
	gstate_initialize(lc);
	gstate_new_state(lc, GSTATE_POWER_STARTUP, NULL);
952

aymeric's avatar
aymeric committed
953
	ortp_init();
954 955 956
	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);
957 958 959 960
	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");
961
	linphone_core_assign_payload_type(&payload_type_telephone_event,101,"0-11");
962
	linphone_core_assign_payload_type(&payload_type_ilbc,113,"mode=30");
963 964 965 966 967 968 969

#ifdef ENABLE_NONSTANDARD_GSM
	{
		PayloadType *pt;
		pt=payload_type_clone(&payload_type_gsm);
		pt->clock_rate=11025;
		rtp_profile_set_payload(&av_profile,114,pt);
970 971 972 973 974
		linphone_payload_types=ms_list_append(linphone_payload_types,pt);
		pt=payload_type_clone(&payload_type_gsm);
		pt->clock_rate=22050;
		rtp_profile_set_payload(&av_profile,115,pt);
		linphone_payload_types=ms_list_append(linphone_payload_types,pt);
975
	}
aymeric's avatar
aymeric committed
976 977
#endif

978 979 980 981 982 983 984 985
#ifdef VIDEO_ENABLED
	linphone_core_assign_payload_type(&payload_type_h263,34,NULL);
	linphone_core_assign_payload_type(&payload_type_theora,97,NULL);
	linphone_core_assign_payload_type(&payload_type_h263_1998,98,"CIF=1;QCIF=1");
	linphone_core_assign_payload_type(&payload_type_mp4v,99,"profile-level-id=3");
	linphone_core_assign_payload_type(&payload_type_x_snow,100,NULL);
	linphone_core_assign_payload_type(&payload_type_h264,102,NULL);
	linphone_core_assign_payload_type(&payload_type_h264,103,"packetization-mode=1");
986 987
#endif

aymeric's avatar
aymeric committed
988
	ms_init();
989

aymeric's avatar
aymeric committed
990
	lc->config=lp_config_new(config_path);
991 992
	if (factory_config_path)
		lp_config_read_file(lc->config,factory_config_path);
993

994
	lc->sal=sal_init();
Simon Morlat's avatar
Simon Morlat committed
995
	sal_set_user_pointer(lc->sal,lc);
Simon Morlat's avatar
Simon Morlat committed
996
	sal_set_callbacks(lc->sal,&linphone_sal_callbacks);
997 998 999
	if (lp_config_get_int(lc->config,"sip","use_session_timers",0)==1){
		sal_use_session_timers(lc->sal,200);
	}
smorlat's avatar
smorlat committed
1000
	sip_setup_register_all();
aymeric's avatar
aymeric committed
1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013
	sound_config_read(lc);
	net_config_read(lc);
	rtp_config_read(lc);
	codecs_config_read(lc);
	sip_config_read(lc); /* this will start eXosip*/
	video_config_read(lc);
	//autoreplier_config_init(&lc->autoreplier_conf);
	lc->prev_mode=LINPHONE_STATUS_ONLINE;
	lc->presence_mode=LINPHONE_STATUS_ONLINE;
	lc->max_call_logs=15;
	ui_config_read(lc);
	lc->vtable.display_status(lc,_("Ready"));
        gstate_new_state(lc, GSTATE_POWER_ON, NULL);
jehan's avatar
jehan committed
1014 1015
	lc->auto_net_state_mon=TRUE;
    lc->ready=TRUE;
aymeric's avatar
aymeric committed
1016 1017
}

1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034
/**
 * Instanciates a LinphoneCore object.
 * @ingroup initializing
 * 
 * The LinphoneCore object is the primary handle for doing all phone actions.
 * It should be unique within your application.
 * @param vtable a LinphoneCoreVTable structure holding your application callbacks
 * @param config_path a path to a config file. If it does not exists it will be created.
 *        The config file is used to store all user settings, call logs, friends, proxies...
 * @param factory_config_path a path to a read-only config file that can be used to 
 *        to store hard-coded preference such as proxy settings or internal preferences.
 *        The settings in this factory file always override the one in the normal config file.
 *        It is OPTIONAL, use NULL if unneeded.
 * @param userdata an opaque user pointer that can be retrieved at any time (for example in
 *        callbacks) using linphone_core_get_user_data().
 * 
**/
aymeric's avatar
aymeric committed
1035
LinphoneCore *linphone_core_new(const LinphoneCoreVTable *vtable,
1036
						const char *config_path, const char *factory_config_path, void * userdata)
aymeric's avatar
aymeric committed
1037 1038
{
	LinphoneCore *core=ms_new(LinphoneCore,1);
1039
	linphone_core_init(core,vtable,config_path, factory_config_path, userdata);
aymeric's avatar
aymeric committed
1040 1041 1042
	return core;
}

1043 1044 1045 1046 1047 1048 1049 1050
/**
 * Returns the list of available audio codecs.
 *
 * This list is unmodifiable. The ->data field of the MSList points a PayloadType
 * structure holding the codec information.
 * It is possible to make copy of the list with ms_list_copy() in order to modify it
 * (such as the order of codecs).
**/
aymeric's avatar
aymeric committed
1051 1052 1053 1054 1055
const MSList *linphone_core_get_audio_codecs(const LinphoneCore *lc)
{
	return lc->codecs_conf.audio_codecs;
}

1056 1057 1058 1059 1060 1061 1062 1063
/**
 * Returns the list of available video codecs.
 *
 * This list is unmodifiable. The ->data field of the MSList points a PayloadType
 * structure holding the codec information.
 * It is possible to make copy of the list with ms_list_copy() in order to modify it
 * (such as the order of codecs).
**/
aymeric's avatar
aymeric committed
1064 1065 1066 1067 1068
const MSList *linphone_core_get_video_codecs(const LinphoneCore *lc)
{
	return lc->codecs_conf.video_codecs;
}

smorlat's avatar
smorlat committed
1069 1070 1071 1072 1073 1074 1075
/**
 * Sets the local "from" identity.
 *
 * @ingroup proxies
 * This data is used in absence of any proxy configuration or when no
 * default proxy configuration is set. See LinphoneProxyConfig
**/
aymeric's avatar
aymeric committed
1076 1077
int linphone_core_set_primary_contact(LinphoneCore *lc, const char *contact)
{
1078 1079
	LinphoneAddress *ctt;

Simon Morlat's avatar
Simon Morlat committed
1080
	if ((ctt=linphone_address_new(contact))==0) {
aymeric's avatar
aymeric committed
1081 1082 1083 1084 1085 1086 1087 1088 1089
		ms_error("Bad contact url: %s",contact);
		return -1;
	}
	if (lc->sip_conf.contact!=NULL) ms_free(lc->sip_conf.contact);
	lc->sip_conf.contact=ms_strdup(contact);
	if (lc->sip_conf.guessed_contact!=NULL){
		ms_free(lc->sip_conf.guessed_contact);
		lc->sip_conf.guessed_contact=NULL;
	}
1090
	linphone_address_destroy(ctt);
aymeric's avatar
aymeric committed
1091 1092 1093 1094 1095 1096 1097 1098 1099 1100
	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 (linphone_core_get_firewall_policy(lc)==LINPHONE_POLICY_USE_NAT_ADDRESS){
		strncpy(result,linphone_core_get_nat_address(lc),LINPHONE_IPADDR_SIZE);
		return;
	}
1101
	if (dest==NULL) dest="87.98.157.38"; /*a public IP address*/
1102 1103
	if (linphone_core_get_local_ip_for(dest,result)==0)
		return;
1104 1105
	/*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);
aymeric's avatar
aymeric committed
1106 1107
}

1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133
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);
}

smorlat's avatar
smorlat committed
1134 1135 1136 1137 1138
/**
 * Returns the default identity when no proxy configuration is used.
 *
 * @ingroup proxies
**/
1139
const char *linphone_core_get_primary_contact(LinphoneCore *lc){
aymeric's avatar
aymeric committed
1140
	char *identity;
1141
	
aymeric's avatar
aymeric committed
1142 1143
	if (lc->sip_conf.guess_hostname){
		if (lc->sip_conf.guessed_contact==NULL || lc->sip_conf.loopback_only){
1144
			update_primary_contact(lc);
aymeric's avatar
aymeric committed
1145 1146 1147 1148 1149 1150 1151 1152
		}
		identity=lc->sip_conf.guessed_contact;
	}else{
		identity=lc->sip_conf.contact;
	}
	return identity;
}

smorlat's avatar
smorlat committed
1153 1154 1155 1156 1157
/**
 * Tells LinphoneCore to guess local hostname automatically in primary contact.
 *
 * @ingroup proxies
**/
aymeric's avatar
aymeric committed
1158 1159 1160
void linphone_core_set_guess_hostname(LinphoneCore *lc, bool_t val){
	lc->sip_conf.guess_hostname=val;
}