linphonecore.c 204 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
#include "lpconfig.h"
#include "private.h"
24
#include "quality_reporting.h"
25

Yann Diorcet's avatar
Yann Diorcet committed
26
#include <math.h>
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
#ifdef HAVE_CONFIG_H
42
#include "config.h"
43 44 45
#ifndef ANDROID /*on Android LIBLINPHONE version is passed from root Makefile*/
	#include "liblinphone_gitversion.h"
#endif
Ghislain MARY's avatar
Ghislain MARY committed
46 47 48
#else
#ifndef LIBLINPHONE_GIT_VERSION
#define LIBLINPHONE_GIT_VERSION "unknown"
49 50 51
#endif
#endif

52 53 54
#ifdef __APPLE__
#include "TargetConditionals.h"
#endif
55

smorlat's avatar
smorlat committed
56
/*#define UNSTANDART_GSM_11K 1*/
aymeric's avatar
aymeric committed
57

58 59
#define ROOT_CA_FILE PACKAGE_DATA_DIR "/linphone/rootca.pem"

60 61 62 63 64 65 66
static const char *liblinphone_version=
#ifdef LIBLINPHONE_GIT_VERSION
	LIBLINPHONE_GIT_VERSION
#else
	LIBLINPHONE_VERSION
#endif
;
67
static bool_t liblinphone_serialize_logs = FALSE;
68
static void set_network_reachable(LinphoneCore* lc,bool_t isReachable, time_t curtime);
Simon Morlat's avatar
Simon Morlat committed
69 70
static void linphone_core_run_hooks(LinphoneCore *lc);
static void linphone_core_free_hooks(LinphoneCore *lc);
aymeric's avatar
aymeric committed
71 72

#include "enum.h"
73
#include "contact_providers_priv.h"
74

75

76
const char *linphone_core_get_nat_address_resolved(LinphoneCore *lc);
aymeric's avatar
aymeric committed
77 78
static void toggle_video_preview(LinphoneCore *lc, bool_t val);

79
#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
80
#define SOUNDS_PREFIX
81 82
#else
#define SOUNDS_PREFIX "Assets/Sounds/"
83
#endif
aymeric's avatar
aymeric committed
84
/* relative path where is stored local ring*/
85
#define LOCAL_RING SOUNDS_PREFIX "rings/oldphone.wav"
aymeric's avatar
aymeric committed
86
/* same for remote ring (ringback)*/
87 88
#define REMOTE_RING SOUNDS_PREFIX "ringback.wav"
#define HOLD_MUSIC SOUNDS_PREFIX "rings/toy-mono.wav"
89

aymeric's avatar
aymeric committed
90

Simon Morlat's avatar
Simon Morlat committed
91
extern SalCallbacks linphone_sal_callbacks;
aymeric's avatar
aymeric committed
92 93 94 95 96 97 98 99 100 101 102 103

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

104

105 106 107 108 109 110 111 112 113 114 115 116
/**
 * 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;
}

117 118
int linphone_core_get_current_call_duration(const LinphoneCore *lc){
	LinphoneCall *call=linphone_core_get_current_call((LinphoneCore *)lc);
119 120
	if (call)  return linphone_call_get_duration(call);
	return -1;
121 122 123 124
}

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
125
	if (call==NULL) return NULL;
126
	return linphone_call_get_remote_address(call);
smorlat's avatar
smorlat committed
127 128
}

129 130 131 132 133 134 135 136 137 138 139
void linphone_core_set_log_handler(OrtpLogFunc logfunc) {
	ortp_set_log_handler(logfunc);
}

void linphone_core_set_log_file(FILE *file) {
	if (file == NULL) file = stdout;
	ortp_set_log_file(file);
}

void linphone_core_set_log_level(OrtpLogLevel loglevel) {
	ortp_set_log_level_mask(loglevel);
140 141 142 143 144
	if (loglevel == 0) {
		sal_disable_logs();
	} else {
		sal_enable_logs();
	}
145 146
}

147 148 149 150
/**
 * Enable logs in supplied FILE*.
 *
 * @ingroup misc
151
 * @deprecated Use #linphone_core_set_log_file and #linphone_core_set_log_level instead.
152 153
 *
 * @param file a C FILE* where to fprintf logs. If null stdout is used.
154
 *
155
**/
aymeric's avatar
aymeric committed
156 157 158 159
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);
jehan's avatar
jehan committed
160
	sal_enable_logs();
aymeric's avatar
aymeric committed
161 162
}

163 164 165 166
/**
 * Enable logs through the user's supplied log callback.
 *
 * @ingroup misc
167
 * @deprecated Use #linphone_core_set_log_handler and #linphone_core_set_log_level instead.
168 169 170
 *
 * @param logfunc The address of a OrtpLogFunc callback whose protoype is
 *            	  typedef void (*OrtpLogFunc)(OrtpLogLevel lev, const char *fmt, va_list args);
171
 *
172
**/
aymeric's avatar
aymeric committed
173 174 175
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);
jehan's avatar
jehan committed
176
	sal_enable_logs();
aymeric's avatar
aymeric committed
177 178
}

179 180 181 182
/**
 * Entirely disable logging.
 *
 * @ingroup misc
183
 * @deprecated Use #linphone_core_set_log_level instead.
184
**/
185
void linphone_core_disable_logs(void){
aymeric's avatar
aymeric committed
186
	ortp_set_log_level_mask(ORTP_ERROR|ORTP_FATAL);
jehan's avatar
jehan committed
187
	sal_disable_logs();
aymeric's avatar
aymeric committed
188 189
}

190 191 192 193
void linphone_core_serialize_logs(void) {
	liblinphone_serialize_logs = TRUE;
}

aymeric's avatar
aymeric committed
194

195
static void net_config_read (LinphoneCore *lc)
aymeric's avatar
aymeric committed
196 197 198 199 200
{
	int tmp;
	const char *tmpstr;
	LpConfig *config=lc->config;

201
	lc->net_conf.nat_address_ip = NULL;
aymeric's avatar
aymeric committed
202 203 204 205 206 207 208 209 210 211
	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","nat_sdp_only",0);
	lc->net_conf.nat_sdp_only=tmp;
212
	tmp=lp_config_get_int(lc->config,"net","mtu",1300);
aymeric's avatar
aymeric committed
213
	linphone_core_set_mtu(lc,tmp);
214 215 216 217 218
	tmp=lp_config_get_int(lc->config,"net","download_ptime",-1);
	if (tmp !=-1 && linphone_core_get_download_ptime(lc) !=0) {
		/*legacy parameter*/
		linphone_core_set_download_ptime(lc,tmp);
	}
219 220
	tmp = lp_config_get_int(lc->config, "net", "dns_srv_enabled", 1);
	linphone_core_enable_dns_srv(lc, tmp);
221 222 223

	/* This is to filter out unsupported firewall policies */
	linphone_core_set_firewall_policy(lc, linphone_core_get_firewall_policy(lc));
aymeric's avatar
aymeric committed
224 225
}

226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241
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
242

243
static void sound_config_read(LinphoneCore *lc)
aymeric's avatar
aymeric committed
244
{
245
	int tmp;
aymeric's avatar
aymeric committed
246 247
	const char *tmpbuf;
	const char *devid;
248
#ifdef __linux
aymeric's avatar
aymeric committed
249 250 251
	/*alsadev let the user use custom alsa device within linphone*/
	devid=lp_config_get_string(lc->config,"sound","alsadev",NULL);
	if (devid){
252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270
		MSSndCard* card;
		const char* delim=",";
		size_t l=strlen(devid);
		char* d=malloc(l+1);
		char* i;
		memcpy(d,devid,l+1);
		for (l=0,i=strpbrk(d+l,delim);i;i=strpbrk(d+l,delim)){
			char s=*i;
			*i='\0';
			card=ms_alsa_card_new_custom(d+l,d+l);
			ms_snd_card_manager_add_card(ms_snd_card_manager_get(),card);
			*i=s;
			l=i-d+1;
		}
		if(d[l]!='\0') {
			card=ms_alsa_card_new_custom(d+l,d+l);
			ms_snd_card_manager_add_card(ms_snd_card_manager_get(),card);
		}
		free(d);
aymeric's avatar
aymeric committed
271
	}
Simon Morlat's avatar
Simon Morlat committed
272
	tmp=lp_config_get_int(lc->config,"sound","alsa_forced_rate",-1);
273
	if (tmp>0) ms_alsa_card_set_forced_sample_rate(tmp);
aymeric's avatar
aymeric committed
274 275
#endif
	/* retrieve all sound devices */
276 277
	build_sound_devices_table(lc);

aymeric's avatar
aymeric committed
278 279
	devid=lp_config_get_string(lc->config,"sound","playback_dev_id",NULL);
	linphone_core_set_playback_device(lc,devid);
280

aymeric's avatar
aymeric committed
281 282
	devid=lp_config_get_string(lc->config,"sound","ringer_dev_id",NULL);
	linphone_core_set_ringer_device(lc,devid);
283

aymeric's avatar
aymeric committed
284 285
	devid=lp_config_get_string(lc->config,"sound","capture_dev_id",NULL);
	linphone_core_set_capture_device(lc,devid);
286

aymeric's avatar
aymeric committed
287 288 289 290 291 292 293 294 295 296
/*
	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]);
*/
297

aymeric's avatar
aymeric committed
298 299
	tmpbuf=PACKAGE_SOUND_DIR "/" LOCAL_RING;
	tmpbuf=lp_config_get_string(lc->config,"sound","local_ring",tmpbuf);
Jehan Monnier's avatar
Jehan Monnier committed
300
	if (ortp_file_exist(tmpbuf)==-1) {
301
		ms_warning("%s does not exist",tmpbuf);
aymeric's avatar
aymeric committed
302 303 304 305 306 307 308
		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);
309

310
	tmpbuf=PACKAGE_SOUND_DIR "/" REMOTE_RING;
aymeric's avatar
aymeric committed
311
	tmpbuf=lp_config_get_string(lc->config,"sound","remote_ring",tmpbuf);
Jehan Monnier's avatar
Jehan Monnier committed
312
	if (ortp_file_exist(tmpbuf)==-1){
313
		tmpbuf=PACKAGE_SOUND_DIR "/" REMOTE_RING;
aymeric's avatar
aymeric committed
314 315 316
	}
	if (strstr(tmpbuf,".wav")==NULL){
		/* it currently uses old sound files, so replace them */
317
		tmpbuf=PACKAGE_SOUND_DIR "/" REMOTE_RING;
aymeric's avatar
aymeric committed
318
	}
319
	linphone_core_set_ringback(lc,tmpbuf);
320 321

	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
322
	lc->sound_conf.latency=0;
323
#ifndef __ios
Simon Morlat's avatar
Simon Morlat committed
324
	tmp=TRUE;
325
#else
Simon Morlat's avatar
Simon Morlat committed
326
	tmp=FALSE; /* on iOS we have builtin echo cancellation.*/
327
#endif
Simon Morlat's avatar
Simon Morlat committed
328
	tmp=lp_config_get_int(lc->config,"sound","echocancellation",tmp);
329
	linphone_core_enable_echo_cancellation(lc,tmp);
smorlat's avatar
smorlat committed
330 331
	linphone_core_enable_echo_limiter(lc,
		lp_config_get_int(lc->config,"sound","echolimiter",0));
332 333
	linphone_core_enable_agc(lc,
		lp_config_get_int(lc->config,"sound","agc",0));
334

Yann Diorcet's avatar
Yann Diorcet committed
335 336
	linphone_core_set_playback_gain_db (lc,lp_config_get_float(lc->config,"sound","playback_gain_db",0));
	linphone_core_set_mic_gain_db (lc,lp_config_get_float(lc->config,"sound","mic_gain_db",0));
337 338

	linphone_core_set_remote_ringback_tone (lc,lp_config_get_string(lc->config,"sound","ringback_tone",NULL));
339 340 341

	/*just parse requested stream feature once at start to print out eventual errors*/
	linphone_core_get_audio_features(lc);
342

343
	_linphone_core_set_tone(lc,LinphoneReasonBusy,LinphoneToneBusy,NULL);
aymeric's avatar
aymeric committed
344 345
}

346 347
static void certificates_config_read(LinphoneCore *lc)
{
348
	const char *rootca;
349
#ifdef __linux
350
	rootca=lp_config_get_string(lc->config,"sip","root_ca", "/etc/ssl/certs");
351
#else
352
	rootca=lp_config_get_string(lc->config,"sip","root_ca", ROOT_CA_FILE);
353
#endif
354
	linphone_core_set_root_ca(lc,rootca);
355
	linphone_core_verify_server_certificates(lc,lp_config_get_int(lc->config,"sip","verify_server_certs",TRUE));
356
	linphone_core_verify_server_cn(lc,lp_config_get_int(lc->config,"sip","verify_server_cn",TRUE));
357 358
}

359
static void sip_config_read(LinphoneCore *lc)
aymeric's avatar
aymeric committed
360 361 362
{
	char *contact;
	const char *tmpstr;
363
	LCSipTransports tr;
aymeric's avatar
aymeric committed
364 365
	int i,tmp;
	int ipv6;
366 367 368 369

	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
370

371
	sal_use_no_initial_route(lc->sal,lp_config_get_int(lc->config,"sip","use_no_initial_route",0));
372 373
	sal_use_rport(lc->sal,lp_config_get_int(lc->config,"sip","use_rport",1));

aymeric's avatar
aymeric committed
374 375 376 377 378
	ipv6=lp_config_get_int(lc->config,"sip","use_ipv6",-1);
	if (ipv6==-1){
		ipv6=0;
	}
	linphone_core_enable_ipv6(lc,ipv6);
379
	memset(&tr,0,sizeof(tr));
380

381 382 383 384
	tr.udp_port=lp_config_get_int(lc->config,"sip","sip_port",5060);
	tr.tcp_port=lp_config_get_int(lc->config,"sip","sip_tcp_port",5060);
	/*we are not listening inbound connection for tls, port has no meaning*/
	tr.tls_port=lp_config_get_int(lc->config,"sip","sip_tls_port",LC_SIP_TRANSPORT_RANDOM);
385

386
	certificates_config_read(lc);
387 388
	/*setting the dscp must be done before starting the transports, otherwise it is not taken into effect*/
	sal_set_dscp(lc->sal,linphone_core_get_sip_dscp(lc));
389
	/*start listening on ports*/
390
	linphone_core_set_sip_transports(lc,&tr);
391

aymeric's avatar
aymeric committed
392 393
	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
394 395
		const char *hostname=NULL;
		const char *username=NULL;
396
#ifdef HAVE_GETENV
smorlat's avatar
smorlat committed
397 398
		hostname=getenv("HOST");
		username=getenv("USER");
aymeric's avatar
aymeric committed
399
		if (hostname==NULL) hostname=getenv("HOSTNAME");
400
#endif /*HAVE_GETENV*/
aymeric's avatar
aymeric committed
401 402 403 404 405 406 407 408 409 410 411 412
		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);
413 414


415
	tmp=lp_config_get_int(lc->config,"sip","inc_timeout",30);
aymeric's avatar
aymeric committed
416 417
	linphone_core_set_inc_timeout(lc,tmp);

Yann Diorcet's avatar
Yann Diorcet committed
418 419
	tmp=lp_config_get_int(lc->config,"sip","in_call_timeout",0);
	linphone_core_set_in_call_timeout(lc,tmp);
420

421 422
	tmp=lp_config_get_int(lc->config,"sip","delayed_timeout",4);
	linphone_core_set_delayed_timeout(lc,tmp);
Yann Diorcet's avatar
Yann Diorcet committed
423

aymeric's avatar
aymeric committed
424 425
	/* get proxies config */
	for(i=0;; i++){
jehan's avatar
jehan committed
426
		LinphoneProxyConfig *cfg=linphone_proxy_config_new_from_config_file(lc,i);
aymeric's avatar
aymeric committed
427 428
		if (cfg!=NULL){
			linphone_core_add_proxy_config(lc,cfg);
Simon Morlat's avatar
Simon Morlat committed
429
			linphone_proxy_config_unref(cfg);
aymeric's avatar
aymeric committed
430 431 432 433 434 435 436
		}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);
437

aymeric's avatar
aymeric committed
438 439 440 441 442
	/* 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
443
			linphone_auth_info_destroy(ai);
aymeric's avatar
aymeric committed
444 445 446 447
		}else{
			break;
		}
	}
448 449
	/*this is to filter out unsupported encryption schemes*/
	linphone_core_set_media_encryption(lc,linphone_core_get_media_encryption(lc));
450

451
	/*for tuning or test*/
aymeric's avatar
aymeric committed
452
	lc->sip_conf.sdp_200_ack=lp_config_get_int(lc->config,"sip","sdp_200_ack",0);
453
	lc->sip_conf.register_only_when_network_is_up=
454
		lp_config_get_int(lc->config,"sip","register_only_when_network_is_up",1);
455 456
	lc->sip_conf.register_only_when_upnp_is_ok=
		lp_config_get_int(lc->config,"sip","register_only_when_upnp_is_ok",1);
457
	lc->sip_conf.ping_with_options=lp_config_get_int(lc->config,"sip","ping_with_options",0);
jehan's avatar
jehan committed
458
	lc->sip_conf.auto_net_state_mon=lp_config_get_int(lc->config,"sip","auto_net_state_mon",1);
459
	lc->sip_conf.keepalive_period=lp_config_get_int(lc->config,"sip","keepalive_period",10000);
460 461
	lc->sip_conf.tcp_tls_keepalive=lp_config_get_int(lc->config,"sip","tcp_tls_keepalive",0);
	linphone_core_enable_keep_alive(lc, (lc->sip_conf.keepalive_period > 0));
Simon Morlat's avatar
Simon Morlat committed
462
	sal_use_one_matching_codec_policy(lc->sal,lp_config_get_int(lc->config,"sip","only_one_codec",0));
463
	sal_use_dates(lc->sal,lp_config_get_int(lc->config,"sip","put_date",0));
464
	sal_enable_sip_update_method(lc->sal,lp_config_get_int(lc->config,"sip","sip_update",1));
465
	lc->sip_conf.vfu_with_info=lp_config_get_int(lc->config,"sip","vfu_with_info",1);
466
	linphone_core_set_sip_transport_timeout(lc, lp_config_get_int(lc->config, "sip", "transport_timeout", 63000));
aymeric's avatar
aymeric committed
467 468
}

469
static void rtp_config_read(LinphoneCore *lc)
aymeric's avatar
aymeric committed
470
{
471
	int min_port, max_port;
aymeric's avatar
aymeric committed
472 473
	int jitt_comp;
	int nortp_timeout;
Simon Morlat's avatar
Simon Morlat committed
474
	bool_t rtp_no_xmit_on_audio_mute;
475
	bool_t adaptive_jitt_comp_enabled;
Simon Morlat's avatar
Simon Morlat committed
476

477 478 479 480 481 482 483 484
	if (lp_config_get_range(lc->config, "rtp", "audio_rtp_port", &min_port, &max_port, 7078, 7078) == TRUE) {
		if (min_port <= 0) min_port = 1;
		if (max_port > 65535) max_port = 65535;
		linphone_core_set_audio_port_range(lc, min_port, max_port);
	} else {
		min_port = lp_config_get_int(lc->config, "rtp", "audio_rtp_port", 7078);
		linphone_core_set_audio_port(lc, min_port);
	}
485

486 487 488 489 490 491 492 493
	if (lp_config_get_range(lc->config, "rtp", "video_rtp_port", &min_port, &max_port, 9078, 9078) == TRUE) {
		if (min_port <= 0) min_port = 1;
		if (max_port > 65535) max_port = 65535;
		linphone_core_set_video_port_range(lc, min_port, max_port);
	} else {
		min_port = lp_config_get_int(lc->config, "rtp", "video_rtp_port", 9078);
		linphone_core_set_video_port(lc, min_port);
	}
494

aymeric's avatar
aymeric committed
495
	jitt_comp=lp_config_get_int(lc->config,"rtp","audio_jitt_comp",60);
496
	linphone_core_set_audio_jittcomp(lc,jitt_comp);
aymeric's avatar
aymeric committed
497
	jitt_comp=lp_config_get_int(lc->config,"rtp","video_jitt_comp",60);
498
	if (jitt_comp==0) jitt_comp=60;
499
	linphone_core_set_video_jittcomp(lc,jitt_comp);
aymeric's avatar
aymeric committed
500
	nortp_timeout=lp_config_get_int(lc->config,"rtp","nortp_timeout",30);
501
	linphone_core_set_nortp_timeout(lc,nortp_timeout);
Simon Morlat's avatar
Simon Morlat committed
502
	rtp_no_xmit_on_audio_mute=lp_config_get_int(lc->config,"rtp","rtp_no_xmit_on_audio_mute",FALSE);
503
	linphone_core_set_rtp_no_xmit_on_audio_mute(lc,rtp_no_xmit_on_audio_mute);
504 505 506 507
	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);
508
	lc->rtp_conf.disable_upnp = lp_config_get_int(lc->config, "rtp", "disable_upnp", FALSE);
aymeric's avatar
aymeric committed
509 510
}

511
static PayloadType * find_payload(RtpProfile *prof, const char *mime_type, int clock_rate, int channels, const char *recv_fmtp){
512 513 514
	PayloadType *candidate=NULL;
	int i;
	PayloadType *it;
515
	for(i=0;i<RTP_PROFILE_MAX_PAYLOADS;++i){
516 517
		it=rtp_profile_get_payload(prof,i);
		if (it!=NULL && strcasecmp(mime_type,it->mime_type)==0
518 519
			&& (clock_rate==it->clock_rate || clock_rate<=0)
			&& (channels==it->channels || channels<=0) ){
520
			if ( (recv_fmtp && it->recv_fmtp && strstr(recv_fmtp,it->recv_fmtp)!=NULL) ||
521 522
				(recv_fmtp==NULL && it->recv_fmtp==NULL) ){
				/*exact match*/
523
				if (recv_fmtp) payload_type_set_recv_fmtp(it,recv_fmtp);
524
				return it;
525 526 527 528 529
			}else {
				if (candidate){
					if (it->recv_fmtp==NULL) candidate=it;
				}else candidate=it;
			}
530 531
		}
	}
532 533 534
	if (candidate && recv_fmtp){
		payload_type_set_recv_fmtp(candidate,recv_fmtp);
	}
535 536
	return candidate;
}
aymeric's avatar
aymeric committed
537

Simon Morlat's avatar
Simon Morlat committed
538
static bool_t get_codec(LinphoneCore *lc, const char* type, int index, PayloadType **ret){
aymeric's avatar
aymeric committed
539 540
	char codeckey[50];
	const char *mime,*fmtp;
541
	int rate,channels,enabled;
aymeric's avatar
aymeric committed
542
	PayloadType *pt;
Simon Morlat's avatar
Simon Morlat committed
543
	LpConfig *config=lc->config;
544

545
	*ret=NULL;
aymeric's avatar
aymeric committed
546 547
	snprintf(codeckey,50,"%s_%i",type,index);
	mime=lp_config_get_string(config,codeckey,"mime",NULL);
548
	if (mime==NULL || strlen(mime)==0 ) return FALSE;
549

aymeric's avatar
aymeric committed
550 551
	rate=lp_config_get_int(config,codeckey,"rate",8000);
	fmtp=lp_config_get_string(config,codeckey,"recv_fmtp",NULL);
552
	channels=lp_config_get_int(config,codeckey,"channels",0);
aymeric's avatar
aymeric committed
553
	enabled=lp_config_get_int(config,codeckey,"enabled",1);
Simon Morlat's avatar
Simon Morlat committed
554
	pt=find_payload(lc->default_profile,mime,rate,channels,fmtp);
555
	if (pt && enabled ) pt->flags|=PAYLOAD_TYPE_ENABLED;
aymeric's avatar
aymeric committed
556
	//ms_message("Found codec %s/%i",pt->mime_type,pt->clock_rate);
557
	if (pt==NULL) ms_warning("Ignoring codec config %s/%i with fmtp=%s because unsupported",
558
				mime,rate,fmtp ? fmtp : "");
559 560 561 562
	*ret=pt;
	return TRUE;
}

563
#define RANK_END 10000
Simon Morlat's avatar
Simon Morlat committed
564 565 566 567 568 569 570

typedef struct codec_desc{
	const char *name;
	int rate;
}codec_desc_t;

static codec_desc_t codec_pref_order[]={
Ghislain MARY's avatar
Ghislain MARY committed
571
	{"opus", 48000},
Simon Morlat's avatar
Simon Morlat committed
572 573 574 575 576 577 578 579 580
	{"SILK", 16000},
	{"speex", 16000},
	{"speex", 8000},
	{"pcmu",8000},
	{"pcma",8000},
	{"VP8",90000},
	{"H264",90000},
	{"MP4V-ES",90000},
	{NULL,0}
581 582
};

Simon Morlat's avatar
Simon Morlat committed
583
static int find_codec_rank(const char *mime, int clock_rate){
584
	int i;
585 586 587 588 589 590 591

#ifdef __arm__
	/*hack for opus, that needs to be disabed by default on ARM single processor, otherwise there is no cpu left for video processing*/
	if (strcasecmp(mime,"opus")==0){
		if (ms_get_cpu_count()==1) return RANK_END;
	}
#endif
Simon Morlat's avatar
Simon Morlat committed
592 593
	for(i=0;codec_pref_order[i].name!=NULL;++i){
		if (strcasecmp(codec_pref_order[i].name,mime)==0 && clock_rate==codec_pref_order[i].rate)
594
			return i;
595
	}
596
	return RANK_END;
597 598 599 600
}

static int codec_compare(const PayloadType *a, const PayloadType *b){
	int ra,rb;
Simon Morlat's avatar
Simon Morlat committed
601 602
	ra=find_codec_rank(a->mime_type,a->clock_rate);
	rb=find_codec_rank(b->mime_type,b->clock_rate);
603 604
	if (ra>rb) return 1;
	if (ra<rb) return -1;
605
	return 1;
606 607
}

Simon Morlat's avatar
Simon Morlat committed
608
static MSList *add_missing_codecs(LinphoneCore *lc, SalStreamType mtype, MSList *l){
609
	int i;
610
	for(i=0;i<RTP_PROFILE_MAX_PAYLOADS;++i){
Simon Morlat's avatar
Simon Morlat committed
611
		PayloadType *pt=rtp_profile_get_payload(lc->default_profile,i);
612 613 614
		if (pt){
			if (mtype==SalVideo && pt->type!=PAYLOAD_VIDEO)
				pt=NULL;
615
			else if (mtype==SalAudio && (pt->type!=PAYLOAD_AUDIO_PACKETIZED
616
				&& pt->type!=PAYLOAD_AUDIO_CONTINUOUS)){
617 618 619 620
				pt=NULL;
			}
			if (pt && ms_filter_codec_supported(pt->mime_type)){
				if (ms_list_find(l,pt)==NULL){
621
					/*unranked codecs are disabled by default*/
Simon Morlat's avatar
Simon Morlat committed
622
					if (find_codec_rank(pt->mime_type, pt->clock_rate)!=RANK_END){
623 624
						payload_type_set_flag(pt,PAYLOAD_TYPE_ENABLED);
					}
625
					ms_message("Adding new codec %s/%i with fmtp %s",
626
						pt->mime_type,pt->clock_rate,pt->recv_fmtp ? pt->recv_fmtp : "");
627
					l=ms_list_insert_sorted(l,pt,(int (*)(const void *, const void *))codec_compare);
628 629 630 631 632
				}
			}
		}
	}
	return l;
aymeric's avatar
aymeric committed
633 634
}

635 636
static MSList *codec_append_if_new(MSList *l, PayloadType *pt){
	MSList *elem;
637
	for (elem=l;elem!=NULL;elem=elem->next){
638 639 640 641 642 643 644 645
		PayloadType *ept=(PayloadType*)elem->data;
		if (pt==ept)
			return l;
	}
	l=ms_list_append(l,pt);
	return l;
}

646
static void codecs_config_read(LinphoneCore *lc)
aymeric's avatar
aymeric committed
647 648 649 650 651
{
	int i;
	PayloadType *pt;
	MSList *audio_codecs=NULL;
	MSList *video_codecs=NULL;
Simon Morlat's avatar
Simon Morlat committed
652
	for (i=0;get_codec(lc,"audio_codec",i,&pt);i++){
653 654 655
		if (pt){
			if (!ms_filter_codec_supported(pt->mime_type)){
				ms_warning("Codec %s is not supported by mediastreamer2, removed.",pt->mime_type);
656
			}else audio_codecs=codec_append_if_new(audio_codecs,pt);
657
		}
aymeric's avatar
aymeric committed
658
	}
Simon Morlat's avatar
Simon Morlat committed
659 660
	audio_codecs=add_missing_codecs(lc,SalAudio,audio_codecs);
	for (i=0;get_codec(lc,"video_codec",i,&pt);i++){
661 662 663
		if (pt){
			if (!ms_filter_codec_supported(pt->mime_type)){
				ms_warning("Codec %s is not supported by mediastreamer2, removed.",pt->mime_type);
664
			}else video_codecs=codec_append_if_new(video_codecs,(void *)pt);
665
		}
aymeric's avatar
aymeric committed
666
	}
Simon Morlat's avatar
Simon Morlat committed
667
	video_codecs=add_missing_codecs(lc,SalVideo,video_codecs);
aymeric's avatar
aymeric committed
668 669
	linphone_core_set_audio_codecs(lc,audio_codecs);
	linphone_core_set_video_codecs(lc,video_codecs);
670
	linphone_core_update_allocated_audio_bandwidth(lc);
aymeric's avatar
aymeric committed
671 672
}

673
static void build_video_devices_table(LinphoneCore *lc){
aymeric's avatar
aymeric committed
674 675
	const MSList *elem;
	int i;
676 677 678 679
	int ndev;
	const char **devices;
	if (lc->video_conf.cams)
		ms_free(lc->video_conf.cams);
aymeric's avatar
aymeric committed
680 681 682 683 684 685 686 687 688
	/* 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;
689 690 691 692 693
}

static void video_config_read(LinphoneCore *lc){
#ifdef VIDEO_ENABLED
	int capture, display, self_view;
Simon Morlat's avatar
Simon Morlat committed
694
	int automatic_video=1;
695
#endif
696 697
	const char *str;
#ifdef VIDEO_ENABLED
698
	LinphoneVideoPolicy vpol;
699
	memset(&vpol, 0, sizeof(LinphoneVideoPolicy));
700
#endif
701
	build_video_devices_table(lc);
aymeric's avatar
aymeric committed
702 703 704 705

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

smorlat's avatar
smorlat committed
707 708
	linphone_core_set_preferred_video_size_by_name(lc,
		lp_config_get_string(lc->config,"video","size","cif"));
709

710 711
	linphone_core_set_preview_video_size_by_name(lc,
		lp_config_get_string(lc->config,"video","preview_size",NULL));
712

713
	linphone_core_set_preferred_framerate(lc,lp_config_get_float(lc->config,"video","framerate",0));
smorlat's avatar
smorlat committed
714

715
#ifdef VIDEO_ENABLED
Simon Morlat's avatar
Simon Morlat committed
716 717 718
#if defined(ANDROID) || defined(__ios)
	automatic_video=0;
#endif
719 720 721
	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);
Simon Morlat's avatar
Simon Morlat committed
722 723
	vpol.automatically_initiate=lp_config_get_int(lc->config,"video","automatically_initiate",automatic_video);
	vpol.automatically_accept=lp_config_get_int(lc->config,"video","automatically_accept",automatic_video);
724 725
	linphone_core_enable_video_capture(lc, capture);
	linphone_core_enable_video_display(lc, display);
Simon Morlat's avatar
Simon Morlat committed
726
	linphone_core_enable_video_preview(lc,lp_config_get_int(lc->config,"video","show_local",0));
Simon Morlat's avatar
Simon Morlat committed
727
	linphone_core_enable_self_view(lc,self_view);
728
	linphone_core_set_video_policy(lc,&vpol);
aymeric's avatar
aymeric committed
729 730 731
#endif
}

732
static void ui_config_read(LinphoneCore *lc)
aymeric's avatar
aymeric committed
733 734 735 736 737 738
{
	LinphoneFriend *lf;
	int i;
	for (i=0;(lf=linphone_friend_new_from_config_file(lc,i))!=NULL;i++){
		linphone_core_add_friend(lc,lf);
	}
739
	call_logs_read_from_config_file(lc);
aymeric's avatar
aymeric committed
740 741
}

742 743
/*
static void autoreplier_config_init(LinphoneCore *lc)
aymeric's avatar
aymeric committed
744 745 746 747 748 749 750 751 752
{
	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);
}
753
*/
aymeric's avatar
aymeric committed
754

Simon Morlat's avatar
Simon Morlat committed
755
bool_t linphone_core_tunnel_available(void){
Guillaume Beraudo's avatar
Guillaume Beraudo committed
756 757 758 759 760 761 762
#ifdef TUNNEL_ENABLED
	return TRUE;
#else
	return FALSE;
#endif
}

763
/**
764
 * Enable adaptive rate control.
765
 *
766
 * @ingroup media_parameters
767 768
 *
 * Adaptive rate control consists in using RTCP feedback provided information to dynamically
769 770 771
 * control the output bitrate of the audio and video encoders, so that we can adapt to the network conditions and
 * available bandwidth. Control of the audio encoder is done in case of audio-only call, and control of the video encoder is done for audio & video calls.
 * Adaptive rate control feature is enabled by default.
772 773 774 775 776 777 778
**/
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.
779
 *
780
 * @ingroup media_parameters
781 782 783 784
 *
 * See linphone_core_enable_adaptive_rate_control().
**/
bool_t linphone_core_adaptive_rate_control_enabled(const LinphoneCore *lc){
785
	return lp_config_get_int(lc->config,"net","adaptive_rate_control",TRUE);
786 787
}

788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817
/**
 * Sets adaptive rate algorithm. It will be used for each new calls starting from
 * now. Calls already started will not be updated.
 *
 * @ingroup media_parameters
 *
**/
void linphone_core_set_adaptive_rate_algorithm(LinphoneCore *lc, MSQosAnalyzerAlgorithm algorithm){
	lp_config_set_string(lc->config,"net","adaptive_rate_algorithm",ms_qos_analyzer_algorithm_to_string(algorithm));
}

/**
 * Returns which adaptive rate algorithm is currently configured for future calls.
 *
 * @ingroup media_parameters
 *
 * See linphone_core_set_adaptive_rate_algorithm().
**/
MSQosAnalyzerAlgorithm linphone_core_get_adaptive_rate_algorithm(const LinphoneCore *lc){
	const char* alg = lp_config_get_string(lc->config, "net", "adaptive_rate_algorithm", NULL);

	if (alg == NULL || strcmp(alg, "Simple")==0)
		return MSQosAnalyzerAlgorithmSimple;
	else if (strcmp(alg, "Stateful")==0)
		return MSQosAnalyzerAlgorithmStateful;

	ms_error("Invalid value for key net/adaptive_rate_control: %s", alg);
	return MSQosAnalyzerAlgorithmSimple;
}

818 819 820 821
bool_t linphone_core_rtcp_enabled(const LinphoneCore *lc){
	return lp_config_get_int(lc->config,"rtp","rtcp_enabled",TRUE);
}

822 823 824 825 826 827 828
/**
 * Sets maximum available download bandwidth
 * 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.
829
 *
Simon Morlat's avatar
Simon Morlat committed
830
 * @ingroup media_parameters
831 832 833 834
 *
 * @param lc the LinphoneCore object
 * @param bw the bandwidth in kbits/s, 0 for infinite
 */
aymeric's avatar
aymeric committed
835 836
void linphone_core_set_download_bandwidth(LinphoneCore *lc, int bw){
	lc->net_conf.download_bw=bw;
837
	if (linphone_core_ready(lc)) lp_config_set_int(lc->config,"net","download_bw",bw);
aymeric's avatar
aymeric committed
838 839
}

840 841 842 843 844 845 846 847 848
/**
 * Sets maximum available upload bandwidth
 * 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
Simon Morlat's avatar
Simon Morlat committed
849
 * @ingroup media_parameters
850
 */
aymeric's avatar
aymeric committed
851 852
void linphone_core_set_upload_bandwidth(LinphoneCore *lc, int bw){
	lc->net_conf.upload_bw=bw;
853
	if (linphone_core_ready(lc)) lp_config_set_int(lc->config,"net","upload_bw",bw);
aymeric's avatar
aymeric committed
854 855
}

856 857 858 859 860 861 862 863 864 865
void linphone_core_set_sip_transport_timeout(LinphoneCore *lc, int timeout_ms) {
	sal_set_transport_timeout(lc->sal, timeout_ms);
	if (linphone_core_ready(lc))
		lp_config_set_int(lc->config, "sip", "transport_timeout", timeout_ms);
}

int linphone_core_get_sip_transport_timeout(LinphoneCore *lc) {
	return sal_get_transport_timeout(lc->sal);
}

866 867 868 869 870 871 872 873 874 875
void linphone_core_enable_dns_srv(LinphoneCore *lc, bool_t enable) {
	sal_enable_dns_srv(lc->sal, enable);
	if (linphone_core_ready(lc))
		lp_config_set_int(lc->config, "net", "dns_srv_enabled", enable ? 1 : 0);
}

bool_t linphone_core_dns_srv_enabled(const LinphoneCore *lc) {
	return sal_dns_srv_enabled(lc->sal);
}