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

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

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

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

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

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

72

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

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

aymeric's avatar
aymeric committed
87

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

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

101

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

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

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

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

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

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

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

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

aymeric's avatar
aymeric committed
191

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

	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
367

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

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

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

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

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


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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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