linphonecore.c 164 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

45
46
#include "liblinphone_gitversion.h"

smorlat's avatar
smorlat committed
47
/*#define UNSTANDART_GSM_11K 1*/
aymeric's avatar
aymeric committed
48

49
50
#define ROOT_CA_FILE PACKAGE_DATA_DIR "/linphone/rootca.pem"

51
52
53
54
55
56
57
static const char *liblinphone_version=
#ifdef LIBLINPHONE_GIT_VERSION
	LIBLINPHONE_GIT_VERSION
#else
	LIBLINPHONE_VERSION
#endif
;
58
static void set_network_reachable(LinphoneCore* lc,bool_t isReachable, time_t curtime);
Simon Morlat's avatar
Simon Morlat committed
59
60
static void linphone_core_run_hooks(LinphoneCore *lc);
static void linphone_core_free_hooks(LinphoneCore *lc);
aymeric's avatar
aymeric committed
61
62

#include "enum.h"
63
const char *linphone_core_get_nat_address_resolved(LinphoneCore *lc);
aymeric's avatar
aymeric committed
64
65
66
67
68
69
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)*/
70
#define REMOTE_RING "ringback.wav"
71
72
#define HOLD_MUSIC "rings/toy-mono.wav"

aymeric's avatar
aymeric committed
73

Simon Morlat's avatar
Simon Morlat committed
74
extern SalCallbacks linphone_sal_callbacks;
aymeric's avatar
aymeric committed
75
76
77
78
79
80
81
82
83
84
85
86

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

87

aymeric's avatar
aymeric committed
88
89
/*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
90
#if !defined(_WIN32_WCE)
aymeric's avatar
aymeric committed
91
	return strftime(s, max, fmt, tm);
Jehan Monnier's avatar
Jehan Monnier committed
92
93
94
95
#else
	return 0;
	/*FIXME*/
#endif /*_WIN32_WCE*/
aymeric's avatar
aymeric committed
96
97
}

98
static void set_call_log_date(LinphoneCallLog *cl, time_t start_time){
aymeric's avatar
aymeric committed
99
100
	struct tm loctime;
#ifdef WIN32
Jehan Monnier's avatar
Jehan Monnier committed
101
#if !defined(_WIN32_WCE)
102
	loctime=*localtime(&start_time);
Jehan Monnier's avatar
Jehan Monnier committed
103
104
	/*FIXME*/
#endif /*_WIN32_WCE*/
aymeric's avatar
aymeric committed
105
#else
106
	localtime_r(&start_time,&loctime);
aymeric's avatar
aymeric committed
107
#endif
108
109
110
111
112
113
114
115
	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
116
117
	cl->from=from;
	cl->to=to;
118
    cl->status=LinphoneCallAborted; /*default status*/
aymeric's avatar
aymeric committed
119
120
	return cl;
}
121

122
void call_logs_write_to_config_file(LinphoneCore *lc){
123
124
125
126
127
128
	MSList *elem;
	char logsection[32];
	int i;
	char *tmp;
	LpConfig *cfg=lc->config;

129
	if (linphone_core_get_global_state (lc)==LinphoneGlobalStartup) return;
130

131
132
133
	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);
134
		lp_config_clean_section(cfg,logsection);
135
136
137
138
139
140
141
142
		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);
143
144
145
		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);
146
147
		lp_config_set_int(cfg,logsection,"duration",cl->duration);
		if (cl->refkey) lp_config_set_string(cfg,logsection,"refkey",cl->refkey);
148
		lp_config_set_float(cfg,logsection,"quality",cl->quality);
149
		lp_config_set_int(cfg,logsection,"video_enabled", cl->video_enabled);
jehan's avatar
jehan committed
150
		lp_config_set_string(cfg,logsection,"call_id",cl->call_id);
151
152
153
154
155
156
157
	}
	for(;i<lc->max_call_logs;++i){
		snprintf(logsection,sizeof(logsection),"call_log_%i",i);
		lp_config_clean_section(cfg,logsection);
	}
}

158
static time_t string_to_time(const char *date){
159
#ifndef WIN32
160
161
162
	struct tm tmtime={0};
	strptime(date,"%c",&tmtime);
	return mktime(&tmtime);
163
164
165
#else
	return 0;
#endif
166
167
}

168
169
170
171
static void call_logs_read_from_config_file(LinphoneCore *lc){
	char logsection[32];
	int i;
	const char *tmp;
172
	uint64_t sec;
173
174
175
176
177
178
179
180
181
182
183
	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);
184
185
186
187
188
189
190
191
192
193
194
195
			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);
				}
			}
196
197
198
			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);
199
			cl->quality=lp_config_get_float(cfg,logsection,"quality",-1);
200
			cl->video_enabled=lp_config_get_int(cfg,logsection,"video_enabled",0);
jehan's avatar
jehan committed
201
202
			cl->call_id=lp_config_get_string(cfg,logsection,"call_id",NULL);
			if(cl->call_id) cl->call_id=ms_strdup(cl->call_id);
203
			lc->call_logs=ms_list_append(lc->call_logs,cl);
204
		}else break;
205
206
207
208
	}
}


aymeric's avatar
aymeric committed
209

smorlat's avatar
smorlat committed
210
211
212
213
214
215
216
/**
 * @addtogroup call_logs
 * @{
**/

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

251
252
/**
 * Returns RTP statistics computed locally regarding the call.
253
 *
254
255
256
257
258
259
260
261
262
263
264
265
266
267
**/
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
268
269
270
271
272
273
274
275
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
276
277


278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
/**
 * 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
304
305
/** @} */

aymeric's avatar
aymeric committed
306
void linphone_call_log_destroy(LinphoneCallLog *cl){
307
308
309
	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);
jehan's avatar
jehan committed
310
	if (cl->call_id) ms_free((void*)cl->call_id);
aymeric's avatar
aymeric committed
311
312
313
	ms_free(cl);
}

314
315
316
317
318
319
320
321
322
323
324
325
/**
 * 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;
}

326
327
int linphone_core_get_current_call_duration(const LinphoneCore *lc){
	LinphoneCall *call=linphone_core_get_current_call((LinphoneCore *)lc);
328
329
	if (call)  return linphone_call_get_duration(call);
	return -1;
330
331
332
333
}

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
334
	if (call==NULL) return NULL;
335
	return linphone_call_get_remote_address(call);
smorlat's avatar
smorlat committed
336
337
}

338
339
340
341
342
343
/**
 * Enable logs in supplied FILE*.
 *
 * @ingroup misc
 *
 * @param file a C FILE* where to fprintf logs. If null stdout is used.
344
 *
345
**/
aymeric's avatar
aymeric committed
346
347
348
349
350
351
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);
}

352
353
354
355
356
357
358
/**
 * 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);
359
 *
360
**/
aymeric's avatar
aymeric committed
361
362
363
364
365
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);
}

366
367
368
369
370
/**
 * Entirely disable logging.
 *
 * @ingroup misc
**/
aymeric's avatar
aymeric committed
371
372
373
374
375
void linphone_core_disable_logs(){
	ortp_set_log_level_mask(ORTP_ERROR|ORTP_FATAL);
}


376
static void net_config_read (LinphoneCore *lc)
aymeric's avatar
aymeric committed
377
378
379
380
381
{
	int tmp;
	const char *tmpstr;
	LpConfig *config=lc->config;

382
	lc->net_conf.nat_address_ip = NULL;
aymeric's avatar
aymeric committed
383
384
385
386
387
388
389
390
391
392
393
394
395
396
	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
397
398
399
	tmp=lp_config_get_int(lc->config,"net","download_ptime",0);
	linphone_core_set_download_ptime(lc,tmp);

aymeric's avatar
aymeric committed
400
401
}

402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
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
418

419
static void sound_config_read(LinphoneCore *lc)
aymeric's avatar
aymeric committed
420
{
421
	int tmp;
aymeric's avatar
aymeric committed
422
423
	const char *tmpbuf;
	const char *devid;
424
	float gain=0;
425
#ifdef __linux
aymeric's avatar
aymeric committed
426
427
428
429
430
431
	/*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
432
	tmp=lp_config_get_int(lc->config,"sound","alsa_forced_rate",-1);
433
	if (tmp>0) ms_alsa_card_set_forced_sample_rate(tmp);
aymeric's avatar
aymeric committed
434
435
#endif
	/* retrieve all sound devices */
436
437
	build_sound_devices_table(lc);

aymeric's avatar
aymeric committed
438
439
	devid=lp_config_get_string(lc->config,"sound","playback_dev_id",NULL);
	linphone_core_set_playback_device(lc,devid);
440

aymeric's avatar
aymeric committed
441
442
	devid=lp_config_get_string(lc->config,"sound","ringer_dev_id",NULL);
	linphone_core_set_ringer_device(lc,devid);
443

aymeric's avatar
aymeric committed
444
445
	devid=lp_config_get_string(lc->config,"sound","capture_dev_id",NULL);
	linphone_core_set_capture_device(lc,devid);
446

aymeric's avatar
aymeric committed
447
448
449
450
451
452
453
454
455
456
/*
	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]);
*/
457

aymeric's avatar
aymeric committed
458
459
	tmpbuf=PACKAGE_SOUND_DIR "/" LOCAL_RING;
	tmpbuf=lp_config_get_string(lc->config,"sound","local_ring",tmpbuf);
Jehan Monnier's avatar
Jehan Monnier committed
460
	if (ortp_file_exist(tmpbuf)==-1) {
461
		ms_warning("%s does not exist",tmpbuf);
aymeric's avatar
aymeric committed
462
463
464
465
466
467
468
		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);
469

470
	tmpbuf=PACKAGE_SOUND_DIR "/" REMOTE_RING;
aymeric's avatar
aymeric committed
471
	tmpbuf=lp_config_get_string(lc->config,"sound","remote_ring",tmpbuf);
Jehan Monnier's avatar
Jehan Monnier committed
472
	if (ortp_file_exist(tmpbuf)==-1){
473
		tmpbuf=PACKAGE_SOUND_DIR "/" REMOTE_RING;
aymeric's avatar
aymeric committed
474
475
476
	}
	if (strstr(tmpbuf,".wav")==NULL){
		/* it currently uses old sound files, so replace them */
477
		tmpbuf=PACKAGE_SOUND_DIR "/" REMOTE_RING;
aymeric's avatar
aymeric committed
478
	}
479
	linphone_core_set_ringback(lc,tmpbuf);
480
481

	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
482
483
	check_sound_device(lc);
	lc->sound_conf.latency=0;
Simon Morlat's avatar
Simon Morlat committed
484
#ifndef __ios 
485
    tmp=TRUE;
486
#else
Simon Morlat's avatar
Simon Morlat committed
487
    tmp=FALSE; /* on iOS we have builtin echo cancellation.*/
488
489
490
#endif
    tmp=lp_config_get_int(lc->config,"sound","echocancellation",tmp);
	linphone_core_enable_echo_cancellation(lc,tmp);
smorlat's avatar
smorlat committed
491
492
	linphone_core_enable_echo_limiter(lc,
		lp_config_get_int(lc->config,"sound","echolimiter",0));
493
494
	linphone_core_enable_agc(lc,
		lp_config_get_int(lc->config,"sound","agc",0));
495

496
497
	gain=lp_config_get_float(lc->config,"sound","playback_gain_db",0);
	linphone_core_set_playback_gain_db (lc,gain);
498
499

	linphone_core_set_remote_ringback_tone (lc,lp_config_get_string(lc->config,"sound","ringback_tone",NULL));
500
501
502

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

505
static void sip_config_read(LinphoneCore *lc)
aymeric's avatar
aymeric committed
506
507
508
{
	char *contact;
	const char *tmpstr;
509
	LCSipTransports tr;
aymeric's avatar
aymeric committed
510
511
	int i,tmp;
	int ipv6;
Simon Morlat's avatar
Simon Morlat committed
512
	int random_port;
513

514
515
	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
516

517
518
519
	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
520

521
	sal_use_rport(lc->sal,lp_config_get_int(lc->config,"sip","use_rport",1));
522
	sal_use_101(lc->sal,lp_config_get_int(lc->config,"sip","use_101",1));
523
	sal_reuse_authorization(lc->sal, lp_config_get_int(lc->config,"sip","reuse_authorization",0));
524
	sal_expire_old_registration_contacts(lc->sal,lp_config_get_int(lc->config,"sip","expire_old_registration_contacts",0));
525

526
527
	tmp=lp_config_get_int(lc->config,"sip","use_rfc2833",0);
	linphone_core_set_use_rfc2833_for_dtmf(lc,tmp);
528

aymeric's avatar
aymeric committed
529
530
531
532
533
	ipv6=lp_config_get_int(lc->config,"sip","use_ipv6",-1);
	if (ipv6==-1){
		ipv6=0;
	}
	linphone_core_enable_ipv6(lc,ipv6);
534
	memset(&tr,0,sizeof(tr));
Simon Morlat's avatar
Simon Morlat committed
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
	
	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;
550
		tr.tls_port=tr.tcp_port=0; /*make sure only one transport is active at a time*/
Simon Morlat's avatar
Simon Morlat committed
551
552
	}else if (tr.tcp_port>0 && random_port){
		tr.tcp_port=random_port;
553
		tr.tls_port=tr.udp_port=0; /*make sure only one transport is active at a time*/
Simon Morlat's avatar
Simon Morlat committed
554
555
	}else if (tr.tls_port>0 && random_port){
		tr.tls_port=random_port;
556
		tr.udp_port=tr.tcp_port=0; /*make sure only one transport is active at a time*/
Simon Morlat's avatar
Simon Morlat committed
557
	} 
558
559
560
561
562
563
564

#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));
565
566
	/*start listening on ports*/
 	linphone_core_set_sip_transports(lc,&tr);
567

aymeric's avatar
aymeric committed
568
569
	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
570
571
		const char *hostname=NULL;
		const char *username=NULL;
572
#ifdef HAVE_GETENV
smorlat's avatar
smorlat committed
573
574
		hostname=getenv("HOST");
		username=getenv("USER");
aymeric's avatar
aymeric committed
575
		if (hostname==NULL) hostname=getenv("HOSTNAME");
576
#endif /*HAVE_GETENV*/
aymeric's avatar
aymeric committed
577
578
579
580
581
582
583
584
585
586
587
588
		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);
589
590


591
	tmp=lp_config_get_int(lc->config,"sip","inc_timeout",30);
aymeric's avatar
aymeric committed
592
593
	linphone_core_set_inc_timeout(lc,tmp);

Yann Diorcet's avatar
Yann Diorcet committed
594
595
596
	tmp=lp_config_get_int(lc->config,"sip","in_call_timeout",0);
	linphone_core_set_in_call_timeout(lc,tmp);

aymeric's avatar
aymeric committed
597
598
599
600
601
602
603
604
605
606
607
608
	/* 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);
609

aymeric's avatar
aymeric committed
610
611
612
613
614
	/* 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
615
			linphone_auth_info_destroy(ai);
aymeric's avatar
aymeric committed
616
617
618
619
		}else{
			break;
		}
	}
620
621
	/*this is to filter out unsupported encryption schemes*/
	linphone_core_set_media_encryption(lc,linphone_core_get_media_encryption(lc));
622

623
	/*for tuning or test*/
aymeric's avatar
aymeric committed
624
	lc->sip_conf.sdp_200_ack=lp_config_get_int(lc->config,"sip","sdp_200_ack",0);
625
	lc->sip_conf.register_only_when_network_is_up=
626
		lp_config_get_int(lc->config,"sip","register_only_when_network_is_up",1);
627
	lc->sip_conf.ping_with_options=lp_config_get_int(lc->config,"sip","ping_with_options",1);
jehan's avatar
jehan committed
628
	lc->sip_conf.auto_net_state_mon=lp_config_get_int(lc->config,"sip","auto_net_state_mon",1);
629
630
	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
631
	sal_use_one_matching_codec_policy(lc->sal,lp_config_get_int(lc->config,"sip","only_one_codec",0));
632
	sal_use_double_registrations(lc->sal,lp_config_get_int(lc->config,"sip","use_double_registrations",1));
633
	sal_set_dscp(lc->sal,linphone_core_get_sip_dscp(lc));
634
	sal_use_dates(lc->sal,lp_config_get_int(lc->config,"sip","put_date",0));
aymeric's avatar
aymeric committed
635
636
}

637
static void rtp_config_read(LinphoneCore *lc)
aymeric's avatar
aymeric committed
638
{
639
	int min_port, max_port;
aymeric's avatar
aymeric committed
640
641
	int jitt_comp;
	int nortp_timeout;
Simon Morlat's avatar
Simon Morlat committed
642
	bool_t rtp_no_xmit_on_audio_mute;
643
	bool_t adaptive_jitt_comp_enabled;
Simon Morlat's avatar
Simon Morlat committed
644

645
646
647
648
649
650
651
652
	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);
	}
653

654
655
656
657
658
659
660
661
	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);
	}
662

aymeric's avatar
aymeric committed
663
	jitt_comp=lp_config_get_int(lc->config,"rtp","audio_jitt_comp",60);
664
	linphone_core_set_audio_jittcomp(lc,jitt_comp);
aymeric's avatar
aymeric committed
665
	jitt_comp=lp_config_get_int(lc->config,"rtp","video_jitt_comp",60);
666
	if (jitt_comp==0) jitt_comp=60;
667
	linphone_core_set_video_jittcomp(lc,jitt_comp);
aymeric's avatar
aymeric committed
668
	nortp_timeout=lp_config_get_int(lc->config,"rtp","nortp_timeout",30);
669
	linphone_core_set_nortp_timeout(lc,nortp_timeout);
Simon Morlat's avatar
Simon Morlat committed
670
	rtp_no_xmit_on_audio_mute=lp_config_get_int(lc->config,"rtp","rtp_no_xmit_on_audio_mute",FALSE);
671
	linphone_core_set_rtp_no_xmit_on_audio_mute(lc,rtp_no_xmit_on_audio_mute);
672
673
674
675
	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
676
677
}

678
static PayloadType * find_payload(RtpProfile *prof, const char *mime_type, int clock_rate, int channels, const char *recv_fmtp){
679
680
681
	PayloadType *candidate=NULL;
	int i;
	PayloadType *it;
682
	for(i=0;i<RTP_PROFILE_MAX_PAYLOADS;++i){
683
684
		it=rtp_profile_get_payload(prof,i);
		if (it!=NULL && strcasecmp(mime_type,it->mime_type)==0
685
686
			&& (clock_rate==it->clock_rate || clock_rate<=0)
			&& (channels==it->channels || channels<=0) ){
687
			if ( (recv_fmtp && it->recv_fmtp && strstr(recv_fmtp,it->recv_fmtp)!=NULL) ||
688
689
				(recv_fmtp==NULL && it->recv_fmtp==NULL) ){
				/*exact match*/
690
				if (recv_fmtp) payload_type_set_recv_fmtp(it,recv_fmtp);
691
				return it;
692
693
694
695
696
			}else {
				if (candidate){
					if (it->recv_fmtp==NULL) candidate=it;
				}else candidate=it;
			}
697
698
		}
	}
699
700
701
	if (candidate && recv_fmtp){
		payload_type_set_recv_fmtp(candidate,recv_fmtp);
	}
702
703
	return candidate;
}
aymeric's avatar
aymeric committed
704

705
static bool_t get_codec(LpConfig *config, const char* type, int index, PayloadType **ret){
aymeric's avatar
aymeric committed
706
707
	char codeckey[50];
	const char *mime,*fmtp;
708
	int rate,channels,enabled;
aymeric's avatar
aymeric committed
709
	PayloadType *pt;
710

711
	*ret=NULL;
aymeric's avatar
aymeric committed
712
713
	snprintf(codeckey,50,"%s_%i",type,index);
	mime=lp_config_get_string(config,codeckey,"mime",NULL);
714
	if (mime==NULL || strlen(mime)==0 ) return FALSE;
715

aymeric's avatar
aymeric committed
716
717
	rate=lp_config_get_int(config,codeckey,"rate",8000);
	fmtp=lp_config_get_string(config,codeckey,"recv_fmtp",NULL);
718
	channels=lp_config_get_int(config,codeckey,"channels",0);
aymeric's avatar
aymeric committed
719
	enabled=lp_config_get_int(config,codeckey,"enabled",1);
720
	pt=find_payload(&av_profile,mime,rate,channels,fmtp);
721
	if (pt && enabled ) pt->flags|=PAYLOAD_TYPE_ENABLED;
aymeric's avatar
aymeric committed
722
	//ms_message("Found codec %s/%i",pt->mime_type,pt->clock_rate);
723
724
725
726
727
728
	if (pt==NULL) ms_warning("Ignoring codec config %s/%i with fmtp=%s because unsupported",
	    		mime,rate,fmtp ? fmtp : "");
	*ret=pt;
	return TRUE;
}

729
#define RANK_END 10000
Simon Morlat's avatar
Simon Morlat committed
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745

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

static codec_desc_t codec_pref_order[]={
	{"SILK", 16000},
	{"speex", 16000},
	{"speex", 8000},
	{"pcmu",8000},
	{"pcma",8000},
	{"VP8",90000},
	{"H264",90000},
	{"MP4V-ES",90000},
	{NULL,0}
746
747
};

Simon Morlat's avatar
Simon Morlat committed
748
static int find_codec_rank(const char *mime, int clock_rate){
749
	int i;
Simon Morlat's avatar
Simon Morlat committed
750
751
	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)
752
			return i;
753
	}
754
	return RANK_END;
755
756
757
758
}

static int codec_compare(const PayloadType *a, const PayloadType *b){
	int ra,rb;
Simon Morlat's avatar
Simon Morlat committed
759
760
	ra=find_codec_rank(a->mime_type,a->clock_rate);
	rb=find_codec_rank(b->mime_type,b->clock_rate);
761
762
	if (ra>rb) return 1;
	if (ra<rb) return -1;
763
	return 0;
764
765
}

766
767
static MSList *add_missing_codecs(SalStreamType mtype, MSList *l){
	int i;
768
	for(i=0;i<RTP_PROFILE_MAX_PAYLOADS;++i){
769
770
771
772
		PayloadType *pt=rtp_profile_get_payload(&av_profile,i);
		if (pt){
			if (mtype==SalVideo && pt->type!=PAYLOAD_VIDEO)
				pt=NULL;
773
			else if (mtype==SalAudio && (pt->type!=PAYLOAD_AUDIO_PACKETIZED
774
775
776
777
778
			    && pt->type!=PAYLOAD_AUDIO_CONTINUOUS)){
				pt=NULL;
			}
			if (pt && ms_filter_codec_supported(pt->mime_type)){
				if (ms_list_find(l,pt)==NULL){
779
					/*unranked codecs are disabled by default*/
Simon Morlat's avatar
Simon Morlat committed
780
					if (find_codec_rank(pt->mime_type, pt->clock_rate)!=RANK_END){
781
782
						payload_type_set_flag(pt,PAYLOAD_TYPE_ENABLED);
					}
783
784
					ms_message("Adding new codec %s/%i with fmtp %s",
					    pt->mime_type,pt->clock_rate,pt->recv_fmtp ? pt->recv_fmtp : "");
785
					l=ms_list_insert_sorted(l,pt,(int (*)(const void *, const void *))codec_compare);
786
787
788
789
790
				}
			}
		}
	}
	return l;
aymeric's avatar
aymeric committed
791
792
}

793
794
static MSList *codec_append_if_new(MSList *l, PayloadType *pt){
	MSList *elem;
795
	for (elem=l;elem!=NULL;elem=elem->next){
796
797
798
799
800
801
802
803
		PayloadType *ept=(PayloadType*)elem->data;
		if (pt==ept)
			return l;
	}
	l=ms_list_append(l,pt);
	return l;
}

804
static void codecs_config_read(LinphoneCore *lc)
aymeric's avatar
aymeric committed
805
806
807
808
809
{
	int i;
	PayloadType *pt;
	MSList *audio_codecs=NULL;
	MSList *video_codecs=NULL;
810
811
812
813
	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);
814
			}else audio_codecs=codec_append_if_new(audio_codecs,pt);
815
		}
aymeric's avatar
aymeric committed
816
	}
817
818
819
820
821
	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);
822
			}else video_codecs=codec_append_if_new(video_codecs,(void *)pt);
823
		}
aymeric's avatar
aymeric committed
824
	}
825
	video_codecs=add_missing_codecs(SalVideo,video_codecs);
aymeric's avatar
aymeric committed
826
827
	linphone_core_set_audio_codecs(lc,audio_codecs);
	linphone_core_set_video_codecs(lc,video_codecs);
828
	linphone_core_update_allocated_audio_bandwidth(lc);
aymeric's avatar
aymeric committed
829
830
}

831
static void build_video_devices_table(LinphoneCore *lc){
aymeric's avatar
aymeric committed
832
833
	const MSList *elem;
	int i;
834
835
836
837
	int ndev;
	const char **devices;
	if (lc->video_conf.cams)
		ms_free(lc->video_conf.cams);
aymeric's avatar
aymeric committed
838
839
840
841
842
843
844
845
846
	/* 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;
847
848
849
850
851
852
853
}

static void video_config_read(LinphoneCore *lc){
#ifdef VIDEO_ENABLED
	int capture, display, self_view;
#endif
	const char *str;	
854
#ifdef VIDEO_ENABLED	
855
	LinphoneVideoPolicy vpol;
856
	memset(&vpol, 0, sizeof(LinphoneVideoPolicy));
857
#endif
858
	build_video_devices_table(lc);
aymeric's avatar
aymeric committed
859
860
861
862

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

smorlat's avatar
smorlat committed
864
865
866
	linphone_core_set_preferred_video_size_by_name(lc,
		lp_config_get_string(lc->config,"video","size","cif"));

867
#ifdef VIDEO_ENABLED
868
869
870
	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);
871
872
	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);
873
874
875
	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);
876

aymeric's avatar
aymeric committed
877
	linphone_core_enable_video(lc,capture,display);
Simon Morlat's avatar
Simon Morlat committed
878
	linphone_core_enable_video_preview(lc,lp_config_get_int(lc->config,"video","show_local",0));
Simon Morlat's avatar
Simon Morlat committed
879
	linphone_core_enable_self_view(lc,self_view);
880
	linphone_core_set_video_policy(lc,&vpol);
aymeric's avatar
aymeric committed
881
882
883
#endif
}

884
static void ui_config_read(LinphoneCore *lc)
aymeric's avatar
aymeric committed
885
886
887
888
889
890
{
	LinphoneFriend *lf;
	int i;
	for (i=0;(lf=linphone_friend_new_from_config_file(lc,i))!=NULL;i++){
		linphone_core_add_friend(lc,lf);
	}
891
	call_logs_read_from_config_file(lc);
aymeric's avatar
aymeric committed
892
893
}

894
895
/*
static void autoreplier_config_init(LinphoneCore *lc)
aymeric's avatar
aymeric committed
896
897
898
899
900
901
902
903
904
{
	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);
}
905
*/
aymeric's avatar
aymeric committed
906

Simon Morlat's avatar
Simon Morlat committed
907
bool_t linphone_core_tunnel_available(void){
Guillaume Beraudo's avatar
Guillaume Beraudo committed
908
909
910
911
912
913
914
#ifdef TUNNEL_ENABLED
	return TRUE;
#else
	return FALSE;
#endif
}

915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
/**
 * 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){
932
	return lp_config_get_int(lc->config,"net","adaptive_rate_control",TRUE);
933
934
}

935
936
937
938
bool_t linphone_core_rtcp_enabled(const LinphoneCore *lc){
	return lp_config_get_int(lc->config,"rtp","rtcp_enabled",TRUE);
}

939
940
941
942
943
944
945
946
947
948
949
950
951
952
/**
 * 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
953
954
void linphone_core_set_download_bandwidth(LinphoneCore *lc, int bw){
	lc->net_conf.download_bw=bw;
955
	if (linphone_core_ready(lc)) lp_config_set_int(lc->config,"net","download_bw",bw);
aymeric's avatar
aymeric committed
956
957
}

958
959
960
961
962
963
964
965
966
967
968
969
970
/**
 * 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
971
972
void linphone_core_set_upload_bandwidth(LinphoneCore *lc, int bw){
	lc->net_conf.upload_bw=bw;
973
	if (linphone_core_ready(lc)) lp_config_set_int(lc->config,"net","upload_bw",bw);
aymeric's avatar
aymeric committed
974
975
}

976
977
978
979
980
981
982
983
/**
 * Retrieve the maximum available download bandwidth.
 *
 * @ingroup media_parameters
 *
 * This value was set by linphone_core_set_download_bandwidth().
 *
**/
aymeric's avatar
aymeric committed
984
985
986
987
int linphone_core_get_download_bandwidth(const LinphoneCore *lc){
	return lc->net_conf.download_bw;
}

988
989
990
991
992
993
994
995
/**
 * Retrieve the maximum available upload bandwidth.
 *
 * @ingroup media_parameters
 *
 * This value was set by linphone_core_set_upload_bandwidth().
 *
**/
aymeric's avatar
aymeric committed
996
997
998
int linphone_core_get_upload_bandwidth(const LinphoneCore *lc){
	return lc->net_conf.upload_bw;
}
jehan's avatar
jehan committed
999
/**
1000
 * Set audio packetization time linphone expects to receive from peer
jehan's avatar
jehan committed
1001
1002
 */
void linphone_core_set_download_ptime(LinphoneCore *lc, int ptime) {
1003
	lp_config_set_int(lc->config,"rtp","download_ptime",ptime);
jehan's avatar
jehan committed
1004
}
1005

1006
1007
1008
1009
/**
 * Get audio packetization time linphone expects to receive from peer
 */
int linphone_core_get_download_ptime(LinphoneCore *lc) {
1010
	return lp_config_get_int(lc->config,"rtp","download_ptime",0);
jehan's avatar
jehan committed
1011
1012
}

1013
1014
1015
1016
1017
1018
/**
 * 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){
1019
	lp_config_set_int(lc->config,"rtp","upload_ptime",ptime);
1020
1021
1022
1023
1024
1025
1026
1027
}

/**
 * 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){
1028
	return lp_config_get_int(lc->config,"rtp","upload_ptime",0);
1029
1030
1031
}


aymeric's avatar
aymeric committed
1032

1033
1034
1035
1036
1037
1038
/**
 * Returns liblinphone's version as a string.
 *
 * @ingroup misc
 *
**/
aymeric's avatar
aymeric committed
1039
1040
1041
1042
const char * linphone_core_get_version(void){
	return liblinphone_version;
}

1043
static void linphone_core_assign_payload_type(LinphoneCore *lc, PayloadType *const_pt, int number, const char *recv_fmtp){
1044
1045
	PayloadType *pt;
	pt=payload_type_clone(const_pt);
1046
1047
1048
1049
	if (number==-1){
		/*look for a free number */
		MSList *elem;
		int i;
1050
		for(i=lc->dyn_pt;i<RTP_PROFILE_MAX_PAYLOADS;++i){
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
			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);
1070
	payload_type_set_number(pt,number);
1071
1072
	if (recv_fmtp!=NULL) payload_type_set_recv_fmtp(pt,recv_fmtp);
	rtp_profile_set_payload(&av_profile,number,pt);
1073
	lc->payload_types=ms_list_append(lc->payload_types,pt);
1074
1075
}

1076
1077
1078
static void linphone_core_handle_static_payloads(LinphoneCore *lc){
	RtpProfile *prof=&av_profile;
	int i;
1079
	for(i=0;i<RTP_PROFILE_MAX_PAYLOADS;++i){
1080
1081
1082
1083
1084
1085
1086
1087
1088
		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,