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"
Ghislain MARY's avatar
Ghislain MARY committed
43 44 45 46
#include "liblinphone_gitversion.h"
#else
#ifndef LIBLINPHONE_GIT_VERSION
#define LIBLINPHONE_GIT_VERSION "unknown"
47 48 49
#endif
#endif

50 51 52
#ifdef __APPLE__
#include "TargetConditionals.h"
#endif
53

smorlat's avatar
smorlat committed
54
/*#define UNSTANDART_GSM_11K 1*/
aymeric's avatar
aymeric committed
55

56 57
#define ROOT_CA_FILE PACKAGE_DATA_DIR "/linphone/rootca.pem"

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

#include "enum.h"
71
#include "contact_providers_priv.h"
72

73

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

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

aymeric's avatar
aymeric committed
88

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

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

102

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

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

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

127 128 129 130 131 132 133 134 135 136 137
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);
138 139 140 141 142
	if (loglevel == 0) {
		sal_disable_logs();
	} else {
		sal_enable_logs();
	}
143 144
}

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

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

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

188 189 190 191
void linphone_core_serialize_logs(void) {
	liblinphone_serialize_logs = TRUE;
}

aymeric's avatar
aymeric committed
192

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

199
	lc->net_conf.nat_address_ip = NULL;
aymeric's avatar
aymeric committed
200 201 202 203 204 205 206 207 208 209
	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;
210
	tmp=lp_config_get_int(lc->config,"net","mtu",1300);
aymeric's avatar
aymeric committed
211
	linphone_core_set_mtu(lc,tmp);
212 213 214 215 216
	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);
	}
217 218
	tmp = lp_config_get_int(lc->config, "net", "dns_srv_enabled", 1);
	linphone_core_enable_dns_srv(lc, tmp);
219 220 221

	/* 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
222 223
}

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

241
static void sound_config_read(LinphoneCore *lc)
aymeric's avatar
aymeric committed
242
{
243
	int tmp;
aymeric's avatar
aymeric committed
244 245
	const char *tmpbuf;
	const char *devid;
246
#ifdef __linux
aymeric's avatar
aymeric committed
247 248 249
	/*alsadev let the user use custom alsa device within linphone*/
	devid=lp_config_get_string(lc->config,"sound","alsadev",NULL);
	if (devid){
250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268
		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
269
	}
Simon Morlat's avatar
Simon Morlat committed
270
	tmp=lp_config_get_int(lc->config,"sound","alsa_forced_rate",-1);
271
	if (tmp>0) ms_alsa_card_set_forced_sample_rate(tmp);
aymeric's avatar
aymeric committed
272 273
#endif
	/* retrieve all sound devices */
274 275
	build_sound_devices_table(lc);

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

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

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

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

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

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

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

Yann Diorcet's avatar
Yann Diorcet committed
333 334
	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));
335 336

	linphone_core_set_remote_ringback_tone (lc,lp_config_get_string(lc->config,"sound","ringback_tone",NULL));
337 338 339

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

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

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

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

	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
368

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

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

379 380 381 382
	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);
383

384
	certificates_config_read(lc);
385 386
	/*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));
387
	/*start listening on ports*/
388
	linphone_core_set_sip_transports(lc,&tr);
389

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


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

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

419 420
	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
421

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

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

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

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

475 476 477 478 479 480 481 482
	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);
	}
483

484 485 486 487 488 489 490 491
	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);
	}
492

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

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

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

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

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

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

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
569
	{"opus", 48000},
Simon Morlat's avatar
Simon Morlat committed
570 571 572 573 574 575 576 577 578
	{"SILK", 16000},
	{"speex", 16000},
	{"speex", 8000},
	{"pcmu",8000},
	{"pcma",8000},
	{"VP8",90000},
	{"H264",90000},
	{"MP4V-ES",90000},
	{NULL,0}
579 580
};

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

#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
590 591
	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)
592
			return i;
593
	}
594
	return RANK_END;
595 596 597 598
}

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

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

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

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

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

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

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

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

708 709
	linphone_core_set_preview_video_size_by_name(lc,
		lp_config_get_string(lc->config,"video","preview_size",NULL));
710

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

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

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

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

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

761
/**
762
 * Enable adaptive rate control.
763
 *
764
 * @ingroup media_parameters
765 766
 *
 * Adaptive rate control consists in using RTCP feedback provided information to dynamically
767 768 769
 * 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.
770 771 772 773 774 775 776
**/
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.
777
 *
778
 * @ingroup media_parameters
779 780 781 782
 *
 * See linphone_core_enable_adaptive_rate_control().
**/
bool_t linphone_core_adaptive_rate_control_enabled(const LinphoneCore *lc){
783
	return lp_config_get_int(lc->config,"net","adaptive_rate_control",TRUE);
784 785
}

786 787 788 789
bool_t linphone_core_rtcp_enabled(const LinphoneCore *lc){
	return lp_config_get_int(lc->config,"rtp","rtcp_enabled",TRUE);
}

790 791 792 793 794 795 796
/**
 * 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.
797
 *
Simon Morlat's avatar
Simon Morlat committed
798
 * @ingroup media_parameters
799 800 801 802
 *
 * @param lc the LinphoneCore object
 * @param bw the bandwidth in kbits/s, 0 for infinite
 */
aymeric's avatar
aymeric committed
803 804
void linphone_core_set_download_bandwidth(LinphoneCore *lc, int bw){
	lc->net_conf.download_bw=bw;
805
	if (linphone_core_ready(lc)) lp_config_set_int(lc->config,"net","download_bw",bw);
aymeric's avatar
aymeric committed
806 807
}

808 809 810 811 812 813 814 815 816
/**
 * 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
817
 * @ingroup media_parameters
818
 */
aymeric's avatar
aymeric committed
819 820
void linphone_core_set_upload_bandwidth(LinphoneCore *lc, int bw){
	lc->net_conf.upload_bw=bw;
821
	if (linphone_core_ready(lc)) lp_config_set_int(lc->config,"net","upload_bw",bw);
aymeric's avatar
aymeric committed
822 823
}

824 825 826 827 828 829 830 831 832 833
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);
}

834 835 836 837 838 839 840 841 842 843
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);
}

844 845 846
/**
 * Retrieve the maximum available download bandwidth.
 * This value was set by linphone_core_set_download_bandwidth().
Simon Morlat's avatar
Simon Morlat committed
847
 * @ingroup media_parameters
848
**/
aymeric's avatar
aymeric committed
849 850 851 852
int linphone_core_get_download_bandwidth(const LinphoneCore *lc){
	return lc->net_conf.download_bw;
}

853 854 855
/**
 * Retrieve the maximum available upload bandwidth.
 * This value was set by linphone_core_set_upload_bandwidth().
Simon Morlat's avatar
Simon Morlat committed
856
 * @ingroup media_parameters
857
**/
aymeric's avatar
aymeric committed
858 859 860
int linphone_core_get_upload_bandwidth(const LinphoneCore *lc){
	return lc->net_conf.upload_bw;