linphonecore.c 158 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
/*
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.
*/

20 21
#define _GNU_SOURCE

aymeric's avatar
aymeric committed
22
#include "linphonecore.h"
smorlat's avatar
smorlat committed
23
#include "sipsetup.h"
aymeric's avatar
aymeric committed
24 25
#include "lpconfig.h"
#include "private.h"
26 27

#include <ortp/telephonyevents.h>
28
#include <ortp/zrtp.h>
aymeric's avatar
aymeric committed
29
#include "mediastreamer2/mediastream.h"
30
#include "mediastreamer2/mseventqueue.h"
smorlat's avatar
smorlat committed
31
#include "mediastreamer2/msvolume.h"
32
#include "mediastreamer2/msequalizer.h"
33
#include "mediastreamer2/dtmfgen.h"
aymeric's avatar
aymeric committed
34

35
#ifdef INET6
aymeric's avatar
aymeric committed
36
#ifndef WIN32
37
#include <netdb.h>
aymeric's avatar
aymeric committed
38 39 40
#endif
#endif

41 42 43 44
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

smorlat's avatar
smorlat committed
45
/*#define UNSTANDART_GSM_11K 1*/
aymeric's avatar
aymeric committed
46

47 48
#define ROOT_CA_FILE PACKAGE_DATA_DIR "/linphone/rootca.pem"

aymeric's avatar
aymeric committed
49
static const char *liblinphone_version=LIBLINPHONE_VERSION;
50
static void set_network_reachable(LinphoneCore* lc,bool_t isReachable, time_t curtime);
Simon Morlat's avatar
Simon Morlat committed
51 52
static void linphone_core_run_hooks(LinphoneCore *lc);
static void linphone_core_free_hooks(LinphoneCore *lc);
aymeric's avatar
aymeric committed
53 54

#include "enum.h"
55
const char *linphone_core_get_nat_address_resolved(LinphoneCore *lc);
aymeric's avatar
aymeric committed
56 57 58 59 60 61
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)*/
62
#define REMOTE_RING "ringback.wav"
63 64
#define HOLD_MUSIC "rings/toy-mono.wav"

aymeric's avatar
aymeric committed
65

Simon Morlat's avatar
Simon Morlat committed
66
extern SalCallbacks linphone_sal_callbacks;
aymeric's avatar
aymeric committed
67 68 69 70 71 72 73 74 75 76 77 78

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;
}

79

aymeric's avatar
aymeric committed
80 81
/*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
82
#if !defined(_WIN32_WCE)
aymeric's avatar
aymeric committed
83
	return strftime(s, max, fmt, tm);
Jehan Monnier's avatar
Jehan Monnier committed
84 85 86 87
#else
	return 0;
	/*FIXME*/
#endif /*_WIN32_WCE*/
aymeric's avatar
aymeric committed
88 89
}

90
static void set_call_log_date(LinphoneCallLog *cl, time_t start_time){
aymeric's avatar
aymeric committed
91 92
	struct tm loctime;
#ifdef WIN32
Jehan Monnier's avatar
Jehan Monnier committed
93
#if !defined(_WIN32_WCE)
94
	loctime=*localtime(&start_time);
Jehan Monnier's avatar
Jehan Monnier committed
95 96
	/*FIXME*/
#endif /*_WIN32_WCE*/
aymeric's avatar
aymeric committed
97
#else
98
	localtime_r(&start_time,&loctime);
aymeric's avatar
aymeric committed
99
#endif
100 101 102 103 104 105 106 107
	my_strftime(cl->start_date,sizeof(cl->start_date),"%c",&loctime);
}

LinphoneCallLog * linphone_call_log_new(LinphoneCall *call, LinphoneAddress *from, LinphoneAddress *to){
	LinphoneCallLog *cl=ms_new0(LinphoneCallLog,1);
	cl->dir=call->dir;
	cl->start_date_time=call->start_time;
	set_call_log_date(cl,cl->start_date_time);
aymeric's avatar
aymeric committed
108 109
	cl->from=from;
	cl->to=to;
110
    cl->status=LinphoneCallAborted; /*default status*/
aymeric's avatar
aymeric committed
111 112
	return cl;
}
113

114
void call_logs_write_to_config_file(LinphoneCore *lc){
115 116 117 118 119 120
	MSList *elem;
	char logsection[32];
	int i;
	char *tmp;
	LpConfig *cfg=lc->config;

121
	if (linphone_core_get_global_state (lc)==LinphoneGlobalStartup) return;
122

123 124 125
	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);
126
		lp_config_clean_section(cfg,logsection);
127 128 129 130 131 132 133 134
		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);
135 136 137
		if (cl->start_date_time)
			lp_config_set_int64(cfg,logsection,"start_date_time",(int64_t)cl->start_date_time);
		else lp_config_set_string(cfg,logsection,"start_date",cl->start_date);
138 139
		lp_config_set_int(cfg,logsection,"duration",cl->duration);
		if (cl->refkey) lp_config_set_string(cfg,logsection,"refkey",cl->refkey);
140
		lp_config_set_float(cfg,logsection,"quality",cl->quality);
141
		lp_config_set_int(cfg,logsection,"video_enabled", cl->video_enabled);
142 143 144 145 146 147 148
	}
	for(;i<lc->max_call_logs;++i){
		snprintf(logsection,sizeof(logsection),"call_log_%i",i);
		lp_config_clean_section(cfg,logsection);
	}
}

149
static time_t string_to_time(const char *date){
150
#ifndef WIN32
151 152 153
	struct tm tmtime={0};
	strptime(date,"%c",&tmtime);
	return mktime(&tmtime);
154 155 156
#else
	return 0;
#endif
157 158
}

159 160 161 162
static void call_logs_read_from_config_file(LinphoneCore *lc){
	char logsection[32];
	int i;
	const char *tmp;
163
	uint64_t sec;
164 165 166 167 168 169 170 171 172 173 174
	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);
175 176 177 178 179 180 181 182 183 184 185 186
			sec=lp_config_get_int64(cfg,logsection,"start_date_time",0);
			if (sec) {
				/*new call log format with date expressed in seconds */
				cl->start_date_time=(time_t)sec;
				set_call_log_date(cl,cl->start_date_time);
			}else{
				tmp=lp_config_get_string(cfg,logsection,"start_date",NULL);
				if (tmp) {
					strncpy(cl->start_date,tmp,sizeof(cl->start_date));
					cl->start_date_time=string_to_time(cl->start_date);
				}
			}
187 188 189
			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);
190
			cl->quality=lp_config_get_float(cfg,logsection,"quality",-1);
191
			cl->video_enabled=lp_config_get_int(cfg,logsection,"video_enabled",0);
192
			lc->call_logs=ms_list_append(lc->call_logs,cl);
193
		}else break;
194 195 196 197
	}
}


aymeric's avatar
aymeric committed
198

smorlat's avatar
smorlat committed
199 200 201 202 203 204 205
/**
 * @addtogroup call_logs
 * @{
**/

/**
 * Returns a human readable string describing the call.
206
 *
smorlat's avatar
smorlat committed
207 208
 * @note: the returned char* must be freed by the application (use ms_free()).
**/
aymeric's avatar
aymeric committed
209 210
char * linphone_call_log_to_str(LinphoneCallLog *cl){
	char *status;
211
	char *tmp;
212 213
	char *from=linphone_address_as_string (cl->from);
	char *to=linphone_address_as_string (cl->to);
aymeric's avatar
aymeric committed
214 215 216 217 218 219 220 221 222 223 224 225 226
	switch(cl->status){
		case LinphoneCallAborted:
			status=_("aborted");
			break;
		case LinphoneCallSuccess:
			status=_("completed");
			break;
		case LinphoneCallMissed:
			status=_("missed");
			break;
		default:
			status="unknown";
	}
227
	tmp=ortp_strdup_printf(_("%s at %s\nFrom: %s\nTo: %s\nStatus: %s\nDuration: %i mn %i sec\n"),
aymeric's avatar
aymeric committed
228 229
			(cl->dir==LinphoneCallIncoming) ? _("Incoming call") : _("Outgoing call"),
			cl->start_date,
230 231
			from,
			to,
aymeric's avatar
aymeric committed
232 233 234
			status,
			cl->duration/60,
			cl->duration%60);
235 236 237
	ms_free(from);
	ms_free(to);
	return tmp;
aymeric's avatar
aymeric committed
238 239
}

240 241
/**
 * Returns RTP statistics computed locally regarding the call.
242
 *
243 244 245 246 247 248 249 250 251 252 253 254 255 256
**/
const rtp_stats_t *linphone_call_log_get_local_stats(const LinphoneCallLog *cl){
	return &cl->local_stats;
}

/**
 * Returns RTP statistics computed by remote end and sent back via RTCP.
 *
 * @note Not implemented yet.
**/
const rtp_stats_t *linphone_call_log_get_remote_stats(const LinphoneCallLog *cl){
	return &cl->remote_stats;
}

smorlat's avatar
smorlat committed
257 258 259 260 261 262 263 264
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
265 266


267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292
/**
 * 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);
}

/**
 * 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
293 294
/** @} */

aymeric's avatar
aymeric committed
295
void linphone_call_log_destroy(LinphoneCallLog *cl){
296 297 298
	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
299 300 301
	ms_free(cl);
}

302 303 304 305 306 307 308 309 310 311 312 313
/**
 * Returns TRUE if the LinphoneCall asked to autoanswer
 *
**/
bool_t linphone_call_asked_to_autoanswer(LinphoneCall *call){
	//return TRUE if the unique(for the moment) incoming call asked to be autoanswered
	if(call)
		return sal_call_autoanswer_asked(call->op);
	else
		return FALSE;
}

314 315
int linphone_core_get_current_call_duration(const LinphoneCore *lc){
	LinphoneCall *call=linphone_core_get_current_call((LinphoneCore *)lc);
316 317
	if (call)  return linphone_call_get_duration(call);
	return -1;
318 319 320 321
}

const LinphoneAddress *linphone_core_get_current_call_remote_address(struct _LinphoneCore *lc){
	LinphoneCall *call=linphone_core_get_current_call(lc);
Simon Morlat's avatar
Simon Morlat committed
322
	if (call==NULL) return NULL;
323
	return linphone_call_get_remote_address(call);
smorlat's avatar
smorlat committed
324 325
}

326 327 328 329 330 331
/**
 * Enable logs in supplied FILE*.
 *
 * @ingroup misc
 *
 * @param file a C FILE* where to fprintf logs. If null stdout is used.
332
 *
333
**/
aymeric's avatar
aymeric committed
334 335 336 337 338 339
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);
}

340 341 342 343 344 345 346
/**
 * 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);
347
 *
348
**/
aymeric's avatar
aymeric committed
349 350 351 352 353
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);
}

354 355 356 357 358
/**
 * Entirely disable logging.
 *
 * @ingroup misc
**/
aymeric's avatar
aymeric committed
359 360 361 362 363
void linphone_core_disable_logs(){
	ortp_set_log_level_mask(ORTP_ERROR|ORTP_FATAL);
}


364
static void net_config_read (LinphoneCore *lc)
aymeric's avatar
aymeric committed
365 366 367 368 369
{
	int tmp;
	const char *tmpstr;
	LpConfig *config=lc->config;

370
	lc->net_conf.nat_address_ip = NULL;
aymeric's avatar
aymeric committed
371 372 373 374 375 376 377 378 379 380 381 382 383 384
	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);
jehan's avatar
jehan committed
385 386 387
	tmp=lp_config_get_int(lc->config,"net","download_ptime",0);
	linphone_core_set_download_ptime(lc,tmp);

aymeric's avatar
aymeric committed
388 389
}

390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405
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
406

407
static void sound_config_read(LinphoneCore *lc)
aymeric's avatar
aymeric committed
408
{
409
	int tmp;
aymeric's avatar
aymeric committed
410 411
	const char *tmpbuf;
	const char *devid;
412
	float gain=0;
413
#ifdef __linux
aymeric's avatar
aymeric committed
414 415 416 417 418 419
	/*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);
	}
Simon Morlat's avatar
Simon Morlat committed
420
	tmp=lp_config_get_int(lc->config,"sound","alsa_forced_rate",-1);
421
	if (tmp>0) ms_alsa_card_set_forced_sample_rate(tmp);
aymeric's avatar
aymeric committed
422 423
#endif
	/* retrieve all sound devices */
424 425
	build_sound_devices_table(lc);

aymeric's avatar
aymeric committed
426 427
	devid=lp_config_get_string(lc->config,"sound","playback_dev_id",NULL);
	linphone_core_set_playback_device(lc,devid);
428

aymeric's avatar
aymeric committed
429 430
	devid=lp_config_get_string(lc->config,"sound","ringer_dev_id",NULL);
	linphone_core_set_ringer_device(lc,devid);
431

aymeric's avatar
aymeric committed
432 433
	devid=lp_config_get_string(lc->config,"sound","capture_dev_id",NULL);
	linphone_core_set_capture_device(lc,devid);
434

aymeric's avatar
aymeric committed
435 436 437 438 439 440 441 442 443 444
/*
	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]);
*/
445

aymeric's avatar
aymeric committed
446 447
	tmpbuf=PACKAGE_SOUND_DIR "/" LOCAL_RING;
	tmpbuf=lp_config_get_string(lc->config,"sound","local_ring",tmpbuf);
Jehan Monnier's avatar
Jehan Monnier committed
448
	if (ortp_file_exist(tmpbuf)==-1) {
449
		ms_warning("%s does not exist",tmpbuf);
aymeric's avatar
aymeric committed
450 451 452 453 454 455 456
		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;
	}
	linphone_core_set_ring(lc,tmpbuf);
457

458
	tmpbuf=PACKAGE_SOUND_DIR "/" REMOTE_RING;
aymeric's avatar
aymeric committed
459
	tmpbuf=lp_config_get_string(lc->config,"sound","remote_ring",tmpbuf);
Jehan Monnier's avatar
Jehan Monnier committed
460
	if (ortp_file_exist(tmpbuf)==-1){
461
		tmpbuf=PACKAGE_SOUND_DIR "/" REMOTE_RING;
aymeric's avatar
aymeric committed
462 463 464
	}
	if (strstr(tmpbuf,".wav")==NULL){
		/* it currently uses old sound files, so replace them */
465
		tmpbuf=PACKAGE_SOUND_DIR "/" REMOTE_RING;
aymeric's avatar
aymeric committed
466
	}
467
	linphone_core_set_ringback(lc,tmpbuf);
468 469

	linphone_core_set_play_file(lc,lp_config_get_string(lc->config,"sound","hold_music",PACKAGE_SOUND_DIR "/" HOLD_MUSIC));
aymeric's avatar
aymeric committed
470 471
	check_sound_device(lc);
	lc->sound_conf.latency=0;
Simon Morlat's avatar
Simon Morlat committed
472
#ifndef __ios 
473
    tmp=TRUE;
474
#else
Simon Morlat's avatar
Simon Morlat committed
475
    tmp=FALSE; /* on iOS we have builtin echo cancellation.*/
476 477 478
#endif
    tmp=lp_config_get_int(lc->config,"sound","echocancellation",tmp);
	linphone_core_enable_echo_cancellation(lc,tmp);
smorlat's avatar
smorlat committed
479 480
	linphone_core_enable_echo_limiter(lc,
		lp_config_get_int(lc->config,"sound","echolimiter",0));
481 482
	linphone_core_enable_agc(lc,
		lp_config_get_int(lc->config,"sound","agc",0));
483

484 485
	gain=lp_config_get_float(lc->config,"sound","playback_gain_db",0);
	linphone_core_set_playback_gain_db (lc,gain);
486 487

	linphone_core_set_remote_ringback_tone (lc,lp_config_get_string(lc->config,"sound","ringback_tone",NULL));
488 489 490

	/*just parse requested stream feature once at start to print out eventual errors*/
	linphone_core_get_audio_features(lc);
aymeric's avatar
aymeric committed
491 492
}

493
static void sip_config_read(LinphoneCore *lc)
aymeric's avatar
aymeric committed
494 495 496
{
	char *contact;
	const char *tmpstr;
497
	LCSipTransports tr;
aymeric's avatar
aymeric committed
498 499
	int i,tmp;
	int ipv6;
Simon Morlat's avatar
Simon Morlat committed
500
	int random_port;
501

502 503
	tmp=lp_config_get_int(lc->config,"sip","use_info",0);
	linphone_core_set_use_info_for_dtmf(lc,tmp);
aymeric's avatar
aymeric committed
504

505 506 507
	if (lp_config_get_int(lc->config,"sip","use_session_timers",0)==1){
		sal_use_session_timers(lc->sal,200);
	}
aymeric's avatar
aymeric committed
508

509
	sal_use_rport(lc->sal,lp_config_get_int(lc->config,"sip","use_rport",1));
510
	sal_use_101(lc->sal,lp_config_get_int(lc->config,"sip","use_101",1));
511
	sal_reuse_authorization(lc->sal, lp_config_get_int(lc->config,"sip","reuse_authorization",0));
512
	sal_expire_old_registration_contacts(lc->sal,lp_config_get_int(lc->config,"sip","expire_old_registration_contacts",0));
513

514 515
	tmp=lp_config_get_int(lc->config,"sip","use_rfc2833",0);
	linphone_core_set_use_rfc2833_for_dtmf(lc,tmp);
516

aymeric's avatar
aymeric committed
517 518 519 520 521
	ipv6=lp_config_get_int(lc->config,"sip","use_ipv6",-1);
	if (ipv6==-1){
		ipv6=0;
	}
	linphone_core_enable_ipv6(lc,ipv6);
522
	memset(&tr,0,sizeof(tr));
Simon Morlat's avatar
Simon Morlat committed
523 524 525 526 527 528 529 530 531 532 533 534 535 536 537
	
	tr.udp_port=lp_config_get_int(lc->config,"sip","sip_port",0);
	tr.tcp_port=lp_config_get_int(lc->config,"sip","sip_tcp_port",0);
	tr.tls_port=lp_config_get_int(lc->config,"sip","sip_tls_port",0);
	
	if (lp_config_get_int(lc->config,"sip","sip_random_port",0)==1)
		random_port=(0xDFFF&random())+1024;
	else random_port=0;
	
	if (tr.udp_port==0 && tr.tcp_port==0 && tr.tls_port==0){
		tr.udp_port=5060;
	}	
	
	if (tr.udp_port>0 && random_port){
		tr.udp_port=random_port;
538
		tr.tls_port=tr.tcp_port=0; /*make sure only one transport is active at a time*/
Simon Morlat's avatar
Simon Morlat committed
539 540
	}else if (tr.tcp_port>0 && random_port){
		tr.tcp_port=random_port;
541
		tr.tls_port=tr.udp_port=0; /*make sure only one transport is active at a time*/
Simon Morlat's avatar
Simon Morlat committed
542 543
	}else if (tr.tls_port>0 && random_port){
		tr.tls_port=random_port;
544
		tr.udp_port=tr.tcp_port=0; /*make sure only one transport is active at a time*/
Simon Morlat's avatar
Simon Morlat committed
545
	} 
546 547 548 549 550 551 552

#ifdef __linux
	sal_set_root_ca(lc->sal, lp_config_get_string(lc->config,"sip","root_ca", "/etc/ssl/certs"));
#else
	sal_set_root_ca(lc->sal, lp_config_get_string(lc->config,"sip","root_ca", ROOT_CA_FILE));
#endif
	linphone_core_verify_server_certificates(lc,lp_config_get_int(lc->config,"sip","verify_server_certs",TRUE));
553 554
	/*start listening on ports*/
 	linphone_core_set_sip_transports(lc,&tr);
555

aymeric's avatar
aymeric committed
556 557
	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
558 559
		const char *hostname=NULL;
		const char *username=NULL;
560
#ifdef HAVE_GETENV
smorlat's avatar
smorlat committed
561 562
		hostname=getenv("HOST");
		username=getenv("USER");
aymeric's avatar
aymeric committed
563
		if (hostname==NULL) hostname=getenv("HOSTNAME");
564
#endif /*HAVE_GETENV*/
aymeric's avatar
aymeric committed
565 566 567 568 569 570 571 572 573 574 575 576
		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);
577 578


579
	tmp=lp_config_get_int(lc->config,"sip","inc_timeout",30);
aymeric's avatar
aymeric committed
580 581 582 583 584 585 586 587 588 589 590 591 592 593
	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);
594

aymeric's avatar
aymeric committed
595 596 597 598 599
	/* 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);
Simon Morlat's avatar
Simon Morlat committed
600
			linphone_auth_info_destroy(ai);
aymeric's avatar
aymeric committed
601 602 603 604
		}else{
			break;
		}
	}
605 606
	/*this is to filter out unsupported encryption schemes*/
	linphone_core_set_media_encryption(lc,linphone_core_get_media_encryption(lc));
607

608
	/*for tuning or test*/
aymeric's avatar
aymeric committed
609
	lc->sip_conf.sdp_200_ack=lp_config_get_int(lc->config,"sip","sdp_200_ack",0);
610
	lc->sip_conf.register_only_when_network_is_up=
611
		lp_config_get_int(lc->config,"sip","register_only_when_network_is_up",1);
612
	lc->sip_conf.ping_with_options=lp_config_get_int(lc->config,"sip","ping_with_options",1);
jehan's avatar
jehan committed
613
	lc->sip_conf.auto_net_state_mon=lp_config_get_int(lc->config,"sip","auto_net_state_mon",1);
614 615
	lc->sip_conf.keepalive_period=lp_config_get_int(lc->config,"sip","keepalive_period",10000);
	sal_set_keepalive_period(lc->sal,lc->sip_conf.keepalive_period);
Simon Morlat's avatar
Simon Morlat committed
616
	sal_use_one_matching_codec_policy(lc->sal,lp_config_get_int(lc->config,"sip","only_one_codec",0));
617
	sal_use_double_registrations(lc->sal,lp_config_get_int(lc->config,"sip","use_double_registrations",1));
618
	sal_set_dscp(lc->sal,linphone_core_get_sip_dscp(lc));
aymeric's avatar
aymeric committed
619 620
}

621
static void rtp_config_read(LinphoneCore *lc)
aymeric's avatar
aymeric committed
622 623 624 625
{
	int port;
	int jitt_comp;
	int nortp_timeout;
Simon Morlat's avatar
Simon Morlat committed
626
	bool_t rtp_no_xmit_on_audio_mute;
627
	bool_t adaptive_jitt_comp_enabled;
Simon Morlat's avatar
Simon Morlat committed
628

aymeric's avatar
aymeric committed
629 630
	port=lp_config_get_int(lc->config,"rtp","audio_rtp_port",7078);
	linphone_core_set_audio_port(lc,port);
631

aymeric's avatar
aymeric committed
632 633 634
	port=lp_config_get_int(lc->config,"rtp","video_rtp_port",9078);
	if (port==0) port=9078;
	linphone_core_set_video_port(lc,port);
635

aymeric's avatar
aymeric committed
636
	jitt_comp=lp_config_get_int(lc->config,"rtp","audio_jitt_comp",60);
637
	linphone_core_set_audio_jittcomp(lc,jitt_comp);
aymeric's avatar
aymeric committed
638
	jitt_comp=lp_config_get_int(lc->config,"rtp","video_jitt_comp",60);
639
	if (jitt_comp==0) jitt_comp=60;
640
	linphone_core_set_video_jittcomp(lc,jitt_comp);
aymeric's avatar
aymeric committed
641
	nortp_timeout=lp_config_get_int(lc->config,"rtp","nortp_timeout",30);
642
	linphone_core_set_nortp_timeout(lc,nortp_timeout);
Simon Morlat's avatar
Simon Morlat committed
643
	rtp_no_xmit_on_audio_mute=lp_config_get_int(lc->config,"rtp","rtp_no_xmit_on_audio_mute",FALSE);
644
	linphone_core_set_rtp_no_xmit_on_audio_mute(lc,rtp_no_xmit_on_audio_mute);
645 646 647 648
	adaptive_jitt_comp_enabled = lp_config_get_int(lc->config, "rtp", "audio_adaptive_jitt_comp_enabled", TRUE);
	linphone_core_enable_audio_adaptive_jittcomp(lc, adaptive_jitt_comp_enabled);
	adaptive_jitt_comp_enabled = lp_config_get_int(lc->config, "rtp", "video_adaptive_jitt_comp_enabled", TRUE);
	linphone_core_enable_video_adaptive_jittcomp(lc, adaptive_jitt_comp_enabled);
aymeric's avatar
aymeric committed
649 650
}

651
static PayloadType * find_payload(RtpProfile *prof, const char *mime_type, int clock_rate, int channels, const char *recv_fmtp){
652 653 654
	PayloadType *candidate=NULL;
	int i;
	PayloadType *it;
655
	for(i=0;i<RTP_PROFILE_MAX_PAYLOADS;++i){
656 657
		it=rtp_profile_get_payload(prof,i);
		if (it!=NULL && strcasecmp(mime_type,it->mime_type)==0
658 659
			&& (clock_rate==it->clock_rate || clock_rate<=0)
			&& (channels==it->channels || channels<=0) ){
660
			if ( (recv_fmtp && it->recv_fmtp && strstr(recv_fmtp,it->recv_fmtp)!=NULL) ||
661 662
				(recv_fmtp==NULL && it->recv_fmtp==NULL) ){
				/*exact match*/
663
				if (recv_fmtp) payload_type_set_recv_fmtp(it,recv_fmtp);
664
				return it;
665 666 667 668 669
			}else {
				if (candidate){
					if (it->recv_fmtp==NULL) candidate=it;
				}else candidate=it;
			}
670 671
		}
	}
672 673 674
	if (candidate && recv_fmtp){
		payload_type_set_recv_fmtp(candidate,recv_fmtp);
	}
675 676
	return candidate;
}
aymeric's avatar
aymeric committed
677

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

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

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

702
#define RANK_END 10000
703
static const char *codec_pref_order[]={
704
	"SILK",
705
	"speex",
706 707
	"iLBC",
	"amr",
708 709 710
	"gsm",
	"pcmu",
	"pcma",
711
	"VP8",
712 713 714 715 716 717 718 719 720 721
	"H264",
	"MP4V-ES",
	"H263-1998",
	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)
722
			return i;
723
	}
724
	return RANK_END;
725 726 727 728 729 730 731 732
}

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;
733
	return 0;
734 735
}

736 737
static MSList *add_missing_codecs(SalStreamType mtype, MSList *l){
	int i;
738
	for(i=0;i<RTP_PROFILE_MAX_PAYLOADS;++i){
739 740 741 742
		PayloadType *pt=rtp_profile_get_payload(&av_profile,i);
		if (pt){
			if (mtype==SalVideo && pt->type!=PAYLOAD_VIDEO)
				pt=NULL;
743
			else if (mtype==SalAudio && (pt->type!=PAYLOAD_AUDIO_PACKETIZED
744 745 746 747 748
			    && pt->type!=PAYLOAD_AUDIO_CONTINUOUS)){
				pt=NULL;
			}
			if (pt && ms_filter_codec_supported(pt->mime_type)){
				if (ms_list_find(l,pt)==NULL){
749 750
					/*unranked codecs are disabled by default*/
					if (find_codec_rank(pt->mime_type)!=RANK_END){
751 752
						payload_type_set_flag(pt,PAYLOAD_TYPE_ENABLED);
					}
753 754
					ms_message("Adding new codec %s/%i with fmtp %s",
					    pt->mime_type,pt->clock_rate,pt->recv_fmtp ? pt->recv_fmtp : "");
755
					l=ms_list_insert_sorted(l,pt,(int (*)(const void *, const void *))codec_compare);
756 757 758 759 760
				}
			}
		}
	}
	return l;
aymeric's avatar
aymeric committed
761 762
}

763 764
static MSList *codec_append_if_new(MSList *l, PayloadType *pt){
	MSList *elem;
765
	for (elem=l;elem!=NULL;elem=elem->next){
766 767 768 769 770 771 772 773
		PayloadType *ept=(PayloadType*)elem->data;
		if (pt==ept)
			return l;
	}
	l=ms_list_append(l,pt);
	return l;
}

774
static void codecs_config_read(LinphoneCore *lc)
aymeric's avatar
aymeric committed
775 776 777 778 779
{
	int i;
	PayloadType *pt;
	MSList *audio_codecs=NULL;
	MSList *video_codecs=NULL;
780 781 782 783
	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);
784
			}else audio_codecs=codec_append_if_new(audio_codecs,pt);
785
		}
aymeric's avatar
aymeric committed
786
	}
787 788 789 790 791
	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);
792
			}else video_codecs=codec_append_if_new(video_codecs,(void *)pt);
793
		}
aymeric's avatar
aymeric committed
794
	}
795
	video_codecs=add_missing_codecs(SalVideo,video_codecs);
aymeric's avatar
aymeric committed
796 797
	linphone_core_set_audio_codecs(lc,audio_codecs);
	linphone_core_set_video_codecs(lc,video_codecs);
798
	linphone_core_update_allocated_audio_bandwidth(lc);
aymeric's avatar
aymeric committed
799 800
}

801
static void build_video_devices_table(LinphoneCore *lc){
aymeric's avatar
aymeric committed
802 803
	const MSList *elem;
	int i;
804 805 806 807
	int ndev;
	const char **devices;
	if (lc->video_conf.cams)
		ms_free(lc->video_conf.cams);
aymeric's avatar
aymeric committed
808 809 810 811 812 813 814 815 816
	/* 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;
817 818 819 820 821 822 823
}

static void video_config_read(LinphoneCore *lc){
#ifdef VIDEO_ENABLED
	int capture, display, self_view;
#endif
	const char *str;	
824
#ifdef VIDEO_ENABLED	
825
	LinphoneVideoPolicy vpol;
826
#endif
827
	build_video_devices_table(lc);
aymeric's avatar
aymeric committed
828 829 830 831

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

smorlat's avatar
smorlat committed
833 834 835
	linphone_core_set_preferred_video_size_by_name(lc,
		lp_config_get_string(lc->config,"video","size","cif"));

836
#ifdef VIDEO_ENABLED
837 838 839
	capture=lp_config_get_int(lc->config,"video","capture",1);
	display=lp_config_get_int(lc->config,"video","display",1);
	self_view=lp_config_get_int(lc->config,"video","self_view",1);
840 841
	vpol.automatically_initiate=lp_config_get_int(lc->config,"video","automatically_initiate",1);
	vpol.automatically_accept=lp_config_get_int(lc->config,"video","automatically_accept",1);
842 843 844
	lc->video_conf.displaytype=lp_config_get_string(lc->config,"video","displaytype",NULL);
	if(lc->video_conf.displaytype)
		ms_message("we are using a specific display:%s\n",lc->video_conf.displaytype);
845

aymeric's avatar
aymeric committed
846
	linphone_core_enable_video(lc,capture,display);
Simon Morlat's avatar
Simon Morlat committed
847
	linphone_core_enable_video_preview(lc,lp_config_get_int(lc->config,"video","show_local",0));
Simon Morlat's avatar
Simon Morlat committed
848
	linphone_core_enable_self_view(lc,self_view);
849
	linphone_core_set_video_policy(lc,&vpol);
aymeric's avatar
aymeric committed
850 851 852
#endif
}

853
static void ui_config_read(LinphoneCore *lc)
aymeric's avatar
aymeric committed
854 855 856 857 858 859
{
	LinphoneFriend *lf;
	int i;
	for (i=0;(lf=linphone_friend_new_from_config_file(lc,i))!=NULL;i++){
		linphone_core_add_friend(lc,lf);
	}
860
	call_logs_read_from_config_file(lc);
aymeric's avatar
aymeric committed
861 862
}

863 864
/*
static void autoreplier_config_init(LinphoneCore *lc)
aymeric's avatar
aymeric committed
865 866 867 868 869 870 871 872 873
{
	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);
}
874
*/
aymeric's avatar
aymeric committed
875

Simon Morlat's avatar
Simon Morlat committed
876
bool_t linphone_core_tunnel_available(void){
Guillaume Beraudo's avatar
Guillaume Beraudo committed
877 878 879 880 881 882 883
#ifdef TUNNEL_ENABLED
	return TRUE;
#else
	return FALSE;
#endif
}

884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900
/**
 * Enable adaptive rate control (experimental feature, audio-only).
 *
 * Adaptive rate control consists in using RTCP feedback provided information to dynamically
 * control the output bitrate of the encoders, so that we can adapt to the network conditions and
 * available bandwidth.
**/
void linphone_core_enable_adaptive_rate_control(LinphoneCore *lc, bool_t enabled){
	lp_config_set_int(lc->config,"net","adaptive_rate_control",(int)enabled);
}

/**
 * Returns whether adaptive rate control is enabled.
 *
 * See linphone_core_enable_adaptive_rate_control().
**/
bool_t linphone_core_adaptive_rate_control_enabled(const LinphoneCore *lc){
901
	return lp_config_get_int(lc->config,"net","adaptive_rate_control",TRUE);
902 903
}

904 905 906 907
bool_t linphone_core_rtcp_enabled(const LinphoneCore *lc){
	return lp_config_get_int(lc->config,"rtp","rtcp_enabled",TRUE);
}

908 909 910 911 912 913 914 915 916 917 918 919 920 921
/**
 * 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
922 923
void linphone_core_set_download_bandwidth(LinphoneCore *lc, int bw){
	lc->net_conf.download_bw=bw;
924
	if (linphone_core_ready(lc)) lp_config_set_int(lc->config,"net","download_bw",bw);
aymeric's avatar
aymeric committed
925 926
}

927 928 929 930 931 932 933 934 935 936 937 938 939
/**
 * 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
940 941
void linphone_core_set_upload_bandwidth(LinphoneCore *lc, int bw){
	lc->net_conf.upload_bw=bw;
942
	if (linphone_core_ready(lc)) lp_config_set_int(lc->config,"net","upload_bw",bw);
aymeric's avatar
aymeric committed
943 944
}

945 946 947