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

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
*/

20
21
#define _GNU_SOURCE

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

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

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

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

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

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

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

#include "enum.h"
55
const char *linphone_core_get_nat_address_resolved(LinphoneCore *lc);
aymeric's avatar
aymeric committed
56
57
58
59
60
61
void linphone_core_get_local_ip(LinphoneCore *lc, const char *dest, char *result);
static void toggle_video_preview(LinphoneCore *lc, bool_t val);

/* relative path where is stored local ring*/
#define LOCAL_RING "rings/oldphone.wav"
/* same for remote ring (ringback)*/
62
#define REMOTE_RING "ringback.wav"
63
64
#define HOLD_MUSIC "rings/toy-mono.wav"

aymeric's avatar
aymeric committed
65

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

void lc_callback_obj_init(LCCallbackObj *obj,LinphoneCoreCbFunc func,void* ud)
{
  obj->_func=func;
  obj->_user_data=ud;
}

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

79

aymeric's avatar
aymeric committed
80
81
/*prevent a gcc bug with %c*/
static size_t my_strftime(char *s, size_t max, const char  *fmt,  const struct tm *tm){
Jehan Monnier's avatar
Jehan Monnier committed
82
#if !defined(_WIN32_WCE)
aymeric's avatar
aymeric committed
83
	return strftime(s, max, fmt, tm);
Jehan Monnier's avatar
Jehan Monnier committed
84
85
86
87
#else
	return 0;
	/*FIXME*/
#endif /*_WIN32_WCE*/
aymeric's avatar
aymeric committed
88
89
}

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

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

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

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

123
124
125
	for(i=0,elem=lc->call_logs;elem!=NULL;elem=elem->next,++i){
		LinphoneCallLog *cl=(LinphoneCallLog*)elem->data;
		snprintf(logsection,sizeof(logsection),"call_log_%i",i);
126
		lp_config_clean_section(cfg,logsection);
127
128
129
130
131
132
133
134
		lp_config_set_int(cfg,logsection,"dir",cl->dir);
		lp_config_set_int(cfg,logsection,"status",cl->status);
		tmp=linphone_address_as_string(cl->from);
		lp_config_set_string(cfg,logsection,"from",tmp);
		ms_free(tmp);
		tmp=linphone_address_as_string(cl->to);
		lp_config_set_string(cfg,logsection,"to",tmp);
		ms_free(tmp);
135
136
137
		if (cl->start_date_time)
			lp_config_set_int64(cfg,logsection,"start_date_time",(int64_t)cl->start_date_time);
		else lp_config_set_string(cfg,logsection,"start_date",cl->start_date);
138
139
		lp_config_set_int(cfg,logsection,"duration",cl->duration);
		if (cl->refkey) lp_config_set_string(cfg,logsection,"refkey",cl->refkey);
140
		lp_config_set_float(cfg,logsection,"quality",cl->quality);
141
		lp_config_set_int(cfg,logsection,"video_enabled", cl->video_enabled);
142
143
144
145
146
147
148
	}
	for(;i<lc->max_call_logs;++i){
		snprintf(logsection,sizeof(logsection),"call_log_%i",i);
		lp_config_clean_section(cfg,logsection);
	}
}

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

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


aymeric's avatar
aymeric committed
198

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

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

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

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

smorlat's avatar
smorlat committed
257
258
259
260
261
262
263
264
void linphone_call_log_set_user_pointer(LinphoneCallLog *cl, void *up){
	cl->user_pointer=up;
}

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

smorlat's avatar
smorlat committed
265
266


267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
/**
 * Associate a persistent reference key to the call log.
 *
 * The reference key can be for example an id to an external database.
 * It is stored in the config file, thus can survive to process exits/restarts.
 *
**/
void linphone_call_log_set_ref_key(LinphoneCallLog *cl, const char *refkey){
	if (cl->refkey!=NULL){
		ms_free(cl->refkey);
		cl->refkey=NULL;
	}
	if (refkey) cl->refkey=ms_strdup(refkey);
}

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

smorlat's avatar
smorlat committed
293
294
/** @} */

aymeric's avatar
aymeric committed
295
void linphone_call_log_destroy(LinphoneCallLog *cl){
296
297
298
	if (cl->from!=NULL) linphone_address_destroy(cl->from);
	if (cl->to!=NULL) linphone_address_destroy(cl->to);
	if (cl->refkey!=NULL) ms_free(cl->refkey);
aymeric's avatar
aymeric committed
299
300
301
	ms_free(cl);
}

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

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

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

326
327
328
329
330
331
/**
 * Enable logs in supplied FILE*.
 *
 * @ingroup misc
 *
 * @param file a C FILE* where to fprintf logs. If null stdout is used.
332
 *
333
**/
aymeric's avatar
aymeric committed
334
335
336
337
338
339
void linphone_core_enable_logs(FILE *file){
	if (file==NULL) file=stdout;
	ortp_set_log_file(file);
	ortp_set_log_level_mask(ORTP_MESSAGE|ORTP_WARNING|ORTP_ERROR|ORTP_FATAL);
}

340
341
342
343
344
345
346
/**
 * Enable logs through the user's supplied log callback.
 *
 * @ingroup misc
 *
 * @param logfunc The address of a OrtpLogFunc callback whose protoype is
 *            	  typedef void (*OrtpLogFunc)(OrtpLogLevel lev, const char *fmt, va_list args);
347
 *
348
**/
aymeric's avatar
aymeric committed
349
350
351
352
353
void linphone_core_enable_logs_with_cb(OrtpLogFunc logfunc){
	ortp_set_log_level_mask(ORTP_MESSAGE|ORTP_WARNING|ORTP_ERROR|ORTP_FATAL);
	ortp_set_log_handler(logfunc);
}

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


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

370
	lc->net_conf.nat_address_ip = NULL;
aymeric's avatar
aymeric committed
371
372
373
374
375
376
377
378
379
380
381
382
383
384
	tmp=lp_config_get_int(config,"net","download_bw",0);
	linphone_core_set_download_bandwidth(lc,tmp);
	tmp=lp_config_get_int(config,"net","upload_bw",0);
	linphone_core_set_upload_bandwidth(lc,tmp);
	linphone_core_set_stun_server(lc,lp_config_get_string(config,"net","stun_server",NULL));
	tmpstr=lp_config_get_string(lc->config,"net","nat_address",NULL);
	if (tmpstr!=NULL && (strlen(tmpstr)<1)) tmpstr=NULL;
	linphone_core_set_nat_address(lc,tmpstr);
	tmp=lp_config_get_int(lc->config,"net","firewall_policy",0);
	linphone_core_set_firewall_policy(lc,tmp);
	tmp=lp_config_get_int(lc->config,"net","nat_sdp_only",0);
	lc->net_conf.nat_sdp_only=tmp;
	tmp=lp_config_get_int(lc->config,"net","mtu",0);
	linphone_core_set_mtu(lc,tmp);
jehan's avatar
jehan committed
385
386
387
	tmp=lp_config_get_int(lc->config,"net","download_ptime",0);
	linphone_core_set_download_ptime(lc,tmp);

aymeric's avatar
aymeric committed
388
389
}

390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
static void build_sound_devices_table(LinphoneCore *lc){
	const char **devices;
	const char **old;
	int ndev;
	int i;
	const MSList *elem=ms_snd_card_manager_get_list(ms_snd_card_manager_get());
	ndev=ms_list_size(elem);
	devices=ms_malloc((ndev+1)*sizeof(const char *));
	for (i=0;elem!=NULL;elem=elem->next,i++){
		devices[i]=ms_snd_card_get_string_id((MSSndCard *)elem->data);
	}
	devices[ndev]=NULL;
	old=lc->sound_conf.cards;
	lc->sound_conf.cards=devices;
	if (old!=NULL) ms_free(old);
}
aymeric's avatar
aymeric committed
406

407
static void sound_config_read(LinphoneCore *lc)
aymeric's avatar
aymeric committed
408
{
409
	int tmp;
aymeric's avatar
aymeric committed
410
411
	const char *tmpbuf;
	const char *devid;
412
	float gain=0;
413
#ifdef __linux
aymeric's avatar
aymeric committed
414
415
416
417
418
419
	/*alsadev let the user use custom alsa device within linphone*/
	devid=lp_config_get_string(lc->config,"sound","alsadev",NULL);
	if (devid){
		MSSndCard *card=ms_alsa_card_new_custom(devid,devid);
		ms_snd_card_manager_add_card(ms_snd_card_manager_get(),card);
	}
Simon Morlat's avatar
Simon Morlat committed
420
	tmp=lp_config_get_int(lc->config,"sound","alsa_forced_rate",-1);
421
	if (tmp>0) ms_alsa_card_set_forced_sample_rate(tmp);
aymeric's avatar
aymeric committed
422
423
#endif
	/* retrieve all sound devices */
424
425
	build_sound_devices_table(lc);

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

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

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

aymeric's avatar
aymeric committed
435
436
437
438
439
440
441
442
443
444
/*
	tmp=lp_config_get_int(lc->config,"sound","play_lev",80);
	linphone_core_set_play_level(lc,tmp);
	tmp=lp_config_get_int(lc->config,"sound","ring_lev",80);
	linphone_core_set_ring_level(lc,tmp);
	tmp=lp_config_get_int(lc->config,"sound","rec_lev",80);
	linphone_core_set_rec_level(lc,tmp);
	tmpbuf=lp_config_get_string(lc->config,"sound","source","m");
	linphone_core_set_sound_source(lc,tmpbuf[0]);
*/
445

aymeric's avatar
aymeric committed
446
447
	tmpbuf=PACKAGE_SOUND_DIR "/" LOCAL_RING;
	tmpbuf=lp_config_get_string(lc->config,"sound","local_ring",tmpbuf);
Jehan Monnier's avatar
Jehan Monnier committed
448
	if (ortp_file_exist(tmpbuf)==-1) {
449
		ms_warning("%s does not exist",tmpbuf);
aymeric's avatar
aymeric committed
450
451
452
453
454
455
456
		tmpbuf=PACKAGE_SOUND_DIR "/" LOCAL_RING;
	}
	if (strstr(tmpbuf,".wav")==NULL){
		/* it currently uses old sound files, so replace them */
		tmpbuf=PACKAGE_SOUND_DIR "/" LOCAL_RING;
	}
	linphone_core_set_ring(lc,tmpbuf);
457

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

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

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

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

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

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

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

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

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

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

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

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

aymeric's avatar
aymeric committed
556
557
	tmpstr=lp_config_get_string(lc->config,"sip","contact",NULL);
	if (tmpstr==NULL || linphone_core_set_primary_contact(lc,tmpstr)==-1) {
smorlat's avatar
smorlat committed
558
559
		const char *hostname=NULL;
		const char *username=NULL;
560
#ifdef HAVE_GETENV
smorlat's avatar
smorlat committed
561
562
		hostname=getenv("HOST");
		username=getenv("USER");
aymeric's avatar
aymeric committed
563
		if (hostname==NULL) hostname=getenv("HOSTNAME");
564
#endif /*HAVE_GETENV*/
aymeric's avatar
aymeric committed
565
566
567
568
569
570
571
572
573
574
575
576
		if (hostname==NULL)
			hostname="unknown-host";
		if (username==NULL){
			username="toto";
		}
		contact=ortp_strdup_printf("sip:%s@%s",username,hostname);
		linphone_core_set_primary_contact(lc,contact);
		ms_free(contact);
	}

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


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

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

aymeric's avatar
aymeric committed
595
596
597
598
599
	/* read authentication information */
	for(i=0;; i++){
		LinphoneAuthInfo *ai=linphone_auth_info_new_from_config_file(lc->config,i);
		if (ai!=NULL){
			linphone_core_add_auth_info(lc,ai);
Simon Morlat's avatar
Simon Morlat committed
600
			linphone_auth_info_destroy(ai);
aymeric's avatar
aymeric committed
601
602
603
604
		}else{
			break;
		}
	}
605
606
	/*this is to filter out unsupported encryption schemes*/
	linphone_core_set_media_encryption(lc,linphone_core_get_media_encryption(lc));
607

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

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

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

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

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

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

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

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

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

699
#define RANK_END 10000
700
static const char *codec_pref_order[]={
701
	"SILK",
702
	"speex",
703
704
	"iLBC",
	"amr",
705
706
707
	"gsm",
	"pcmu",
	"pcma",
708
	"VP8",
709
710
711
712
713
714
715
716
717
718
	"H264",
	"MP4V-ES",
	"H263-1998",
	NULL,
};

static int find_codec_rank(const char *mime){
	int i;
	for(i=0;codec_pref_order[i]!=NULL;++i){
		if (strcasecmp(codec_pref_order[i],mime)==0)
719
			return i;
720
	}
721
	return RANK_END;
722
723
724
725
726
727
728
729
}

static int codec_compare(const PayloadType *a, const PayloadType *b){
	int ra,rb;
	ra=find_codec_rank(a->mime_type);
	rb=find_codec_rank(b->mime_type);
	if (ra>rb) return 1;
	if (ra<rb) return -1;
730
	return 0;
731
732
}

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

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

771
static void codecs_config_read(LinphoneCore *lc)
aymeric's avatar
aymeric committed
772
773
774
775
776
{
	int i;
	PayloadType *pt;
	MSList *audio_codecs=NULL;
	MSList *video_codecs=NULL;
777
778
779
780
	for (i=0;get_codec(lc->config,"audio_codec",i,&pt);i++){
		if (pt){
			if (!ms_filter_codec_supported(pt->mime_type)){
				ms_warning("Codec %s is not supported by mediastreamer2, removed.",pt->mime_type);
781
			}else audio_codecs=codec_append_if_new(audio_codecs,pt);
782
		}
aymeric's avatar
aymeric committed
783
	}
784
785
786
787
788
	audio_codecs=add_missing_codecs(SalAudio,audio_codecs);
	for (i=0;get_codec(lc->config,"video_codec",i,&pt);i++){
		if (pt){
			if (!ms_filter_codec_supported(pt->mime_type)){
				ms_warning("Codec %s is not supported by mediastreamer2, removed.",pt->mime_type);
789
			}else video_codecs=codec_append_if_new(video_codecs,(void *)pt);
790
		}
aymeric's avatar
aymeric committed
791
	}
792
	video_codecs=add_missing_codecs(SalVideo,video_codecs);
aymeric's avatar
aymeric committed
793
794
	linphone_core_set_audio_codecs(lc,audio_codecs);
	linphone_core_set_video_codecs(lc,video_codecs);
795
	linphone_core_update_allocated_audio_bandwidth(lc);
aymeric's avatar
aymeric committed
796
797
}

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

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

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

smorlat's avatar
smorlat committed
830
831
832
	linphone_core_set_preferred_video_size_by_name(lc,
		lp_config_get_string(lc->config,"video","size","cif"));

833
#ifdef VIDEO_ENABLED
834
835
836
	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);
837
838
	vpol.automatically_initiate=lp_config_get_int(lc->config,"video","automatically_initiate",1);
	vpol.automatically_accept=lp_config_get_int(lc->config,"video","automatically_accept",1);
839
840
841
	lc->video_conf.displaytype=lp_config_get_string(lc->config,"video","displaytype",NULL);
	if(lc->video_conf.displaytype)
		ms_message("we are using a specific display:%s\n",lc->video_conf.displaytype);
842

aymeric's avatar
aymeric committed
843
	linphone_core_enable_video(lc,capture,display);
Simon Morlat's avatar
Simon Morlat committed
844
	linphone_core_enable_self_view(lc,self_view);
845
	linphone_core_set_video_policy(lc,&vpol);
aymeric's avatar
aymeric committed
846
847
848
#endif
}

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

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

Simon Morlat's avatar
Simon Morlat committed
872
bool_t linphone_core_tunnel_available(void){
Guillaume Beraudo's avatar
Guillaume Beraudo committed
873
874
875
876
877
878
879
#ifdef TUNNEL_ENABLED
	return TRUE;
#else
	return FALSE;
#endif
}

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

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

900
901
902
903
bool_t linphone_core_rtcp_enabled(const LinphoneCore *lc){
	return lp_config_get_int(lc->config,"rtp","rtcp_enabled",TRUE);
}

904
905
906
907
908
909
910
911
912
913
914
915
916
917
/**
 * Sets maximum available download bandwidth
 *
 * @ingroup media_parameters
 *
 * This is IP bandwidth, in kbit/s.
 * This information is used signaled to other parties during
 * calls (within SDP messages) so that the remote end can have
 * sufficient knowledge to properly configure its audio & video
 * codec output bitrate to not overflow available bandwidth.
 *
 * @param lc the LinphoneCore object
 * @param bw the bandwidth in kbits/s, 0 for infinite
 */
aymeric's avatar
aymeric committed
918
919
void linphone_core_set_download_bandwidth(LinphoneCore *lc, int bw){
	lc->net_conf.download_bw=bw;
920
	if (linphone_core_ready(lc)) lp_config_set_int(lc->config,"net","download_bw",bw);
aymeric's avatar
aymeric committed
921
922
}

923
924
925
926
927
928
929
930
931
932
933
934
935
/**
 * Sets maximum available upload bandwidth
 *
 * @ingroup media_parameters
 *
 * This is IP bandwidth, in kbit/s.
 * This information is used by liblinphone together with remote
 * side available bandwidth signaled in SDP messages to properly
 * configure audio & video codec's output bitrate.
 *
 * @param lc the LinphoneCore object
 * @param bw the bandwidth in kbits/s, 0 for infinite
 */
aymeric's avatar
aymeric committed
936
937
void linphone_core_set_upload_bandwidth(LinphoneCore *lc, int bw){
	lc->net_conf.upload_bw=bw;
938
	if (linphone_core_ready(lc)) lp_config_set_int(lc->config,"net","upload_bw",bw);
aymeric's avatar
aymeric committed
939
940
}

941
942
943
944
945
946
947
948
/**
 * Retrieve the maximum available download bandwidth.
 *
 * @ingroup media_parameters
 *
 * This value was set by linphone_core_set_download_bandwidth().
 *
**/
aymeric's avatar
aymeric committed
949
950
951
952
int linphone_core_get_download_bandwidth(const LinphoneCore *lc){
	return lc->net_conf.download_bw;
}

953
954
955
956
957
958
959
960
/**
 * Retrieve the maximum available upload bandwidth.
 *
 * @ingroup media_parameters
 *
 * This value was set by linphone_core_set_upload_bandwidth().
 *
**/
aymeric's avatar
aymeric committed
961
962
963
int linphone_core_get_upload_bandwidth(const LinphoneCore *lc){
	return lc->net_conf.upload_bw;
}
jehan's avatar
jehan committed
964
/**
965
 * Set audio packetization time linphone expects to receive from peer
jehan's avatar
jehan committed
966
967
 */
void linphone_core_set_download_ptime(LinphoneCore *lc, int ptime) {
968
	lc->net_conf.down_ptime=ptime;
jehan's avatar
jehan committed
969
}
970

971
972
973
974
/**
 * Get audio packetization time linphone expects to receive from peer
 */
int linphone_core_get_download_ptime(LinphoneCore *lc) {
975
	return lc->net_conf.down_ptime;
jehan's avatar
jehan committed
976
977
}

978
979
980
981
982
983
/**
 * Set audio packetization time linphone will send (in absence of requirement from peer)
 * A value of 0 stands for the current codec default packetization time.
 *
**/
void linphone_core_set_upload_ptime(LinphoneCore *lc, int ptime){
984
	lp_config_set_int(lc->config,"rtp","upload_ptime",ptime);
985
986
987
988
989
990
991
992
}

/**
 * Set audio packetization time linphone will send (in absence of requirement from peer)
 * A value of 0 stands for the current codec default packetization time.
 *
**/
int linphone_core_get_upload_ptime(LinphoneCore *lc){
993
	return lp_config_get_int(lc->config,"rtp","upload_ptime",0);
994
995
996
}


aymeric's avatar
aymeric committed
997

998
999
1000
1001
1002
1003
/**
 * Returns liblinphone's version as a string.
 *
 * @ingroup misc
 *
**/
aymeric's avatar
aymeric committed
1004
1005
1006
1007
const char * linphone_core_get_version(void){
	return liblinphone_version;
}

1008
static void linphone_core_assign_payload_type(LinphoneCore *lc, PayloadType *const_pt, int number, const char *recv_fmtp){
1009
1010
	PayloadType *pt;
	pt=payload_type_clone(const_pt);
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
	if (number==-1){
		/*look for a free number */
		MSList *elem;
		int i;
		for(i=lc->dyn_pt;i<=127;++i){
			bool_t already_assigned=FALSE;
			for(elem=lc->payload_types;elem!=NULL;elem=elem->next){
				PayloadType *it=(PayloadType*)elem->data;
				if (payload_type_get_number(it)==i){
					already_assigned=TRUE;
					break;
				}
			}
			if (!already_assigned){
				number=i;
				lc->dyn_pt=i+1;
				break;
			}
		}
		if (number==-1){
			ms_fatal("FIXME: too many codecs, no more free numbers.");
		}
	}
	ms_message("assigning %s/%i payload type number %i",pt->mime_type,pt->clock_rate,number);
1035
	payload_type_set_number(pt,number);
1036
1037
	if (recv_fmtp!=NULL) payload_type_set_recv_fmtp(pt,recv_fmtp);
	rtp_profile_set_payload(&av_profile,number,pt);
1038
	lc->payload_types=ms_list_append(lc->payload_types,pt);
1039
1040
}

1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
static void linphone_core_handle_static_payloads(LinphoneCore *lc){
	RtpProfile *prof=&av_profile;
	int i;
	for(i=0;i<128;++i){
		PayloadType *pt=rtp_profile_get_payload(prof,i);
		if (pt){
			if (payload_type_get_number(pt)!=i){
				linphone_core_assign_payload_type(lc,pt,i,NULL);
			}
		}
	}
}

1054
1055
1056
1057
static void linphone_core_free_payload_types(LinphoneCore *lc){
	ms_list_for_each(lc->payload_types,(void (*)(void*))payload_type_destroy);
	ms_list_free(lc->payload_types);
	lc->payload_types=NULL;
1058
}
1059

1060
void linphone_core_set_state(LinphoneCore *lc, LinphoneGlobalState gstate, const char *message){
Simon Morlat's avatar
Simon Morlat committed
1061
	lc->state=gstate;
1062
1063
1064
1065
	if (lc->vtable.global_state_changed){
		lc->vtable.global_state_changed(lc,gstate,message);
	}
}
1066
1067
1068
static void misc_config_read (LinphoneCore *lc) {
	LpConfig *config=lc->config;
    lc->max_call_logs=lp_config_get_int(config,"misc","history_max_size",15);
1069
    lc->max_calls=lp_config_get_int(config,"misc","max_calls",NB_MAX_CALLS);
1070
}
1071

Guillaume Beraudo's avatar
Guillaume Beraudo committed
1072

1073

Guillaume Beraudo's avatar
Guillaume Beraudo committed
1074

1075
static void linphone_core_init (LinphoneCore * lc, const LinphoneCoreVTable *vtable, const char *config_path,
1076
    const char *factory_config_path, void * userdata)
aymeric's avatar
aymeric committed
1077
1078
1079
{
	memset (lc, 0, sizeof (LinphoneCore));
	lc->data=userdata;
1080
	lc->ringstream_autorelease=TRUE;
1081

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

1084
	linphone_core_set_state(lc,LinphoneGlobalStartup,"Starting up");
aymeric's avatar
aymeric committed
1085
	ortp_init();
1086
1087
1088
1089
1090
1091
1092
1093
	lc->dyn_pt=96;
	linphone_core_assign_payload_type(lc,&payload_type_pcmu8000,0,NULL);
	linphone_core_assign_payload_type(lc,&payload_type_gsm,3,NULL);
	linphone_core_assign_payload_type(lc,&payload_type_pcma8000,8,NULL);
	linphone_core_assign_payload_type(lc,&payload_type_speex_nb,110,"vbr=on");
	linphone_core_assign_payload_type(lc,&payload_type_speex_wb,111,"vbr=on");
	linphone_core_assign_payload_type(lc,&payload_type_speex_uwb,112,"vbr=on");
	linphone_core_assign_payload_type(lc,&payload_type_telephone_event,101,"0-11");
Sylvain Berfini's avatar
Sylvain Berfini committed
1094
	linphone_core_assign_payload_type(lc,&payload_type_g722,9,NULL);
1095

1096
1097
1098
1099
1100
1101
1102
1103
#if defined(ANDROID) || defined (__IPHONE_OS_VERSION_MIN_REQUIRED)
	/*shorten the DNS lookup time and send more retransmissions on mobiles:
	 - to workaround potential packet losses
	 - to avoid hanging for 30 seconds when the network doesn't work despite the phone thinks it does.
	 */
	_linphone_core_configure_resolver();
#endif

1104
1105
1106