]> sjero.net Git - linphone/blob - coreapi/linphonecore.c
sal in progress, near to code complete.
[linphone] / coreapi / linphonecore.c
1 /*
2 linphone
3 Copyright (C) 2000  Simon MORLAT (simon.morlat@linphone.org)
4
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License
7 as published by the Free Software Foundation; either version 2
8 of the License, or (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18 */
19
20 #include "linphonecore.h"
21 #include "sipsetup.h"
22 #include "lpconfig.h"
23 #include "private.h"
24 #include "mediastreamer2/mediastream.h"
25 #include "mediastreamer2/msvolume.h"
26 #include "mediastreamer2/msequalizer.h"
27
28 #include <ortp/telephonyevents.h>
29
30
31 #ifdef INET6
32 #ifndef WIN32
33 #include <netdb.h>
34 #endif
35 #endif
36
37 /*#define UNSTANDART_GSM_11K 1*/
38
39 static const char *liblinphone_version=LIBLINPHONE_VERSION;
40
41 #include "enum.h"
42
43 void linphone_core_get_local_ip(LinphoneCore *lc, const char *dest, char *result);
44 static void apply_nat_settings(LinphoneCore *lc);
45 static void toggle_video_preview(LinphoneCore *lc, bool_t val);
46
47 /* relative path where is stored local ring*/
48 #define LOCAL_RING "rings/oldphone.wav"
49 /* same for remote ring (ringback)*/
50 #define REMOTE_RING "ringback.wav"
51
52 void lc_callback_obj_init(LCCallbackObj *obj,LinphoneCoreCbFunc func,void* ud)
53 {
54   obj->_func=func;
55   obj->_user_data=ud;
56 }
57
58 int lc_callback_obj_invoke(LCCallbackObj *obj, LinphoneCore *lc){
59         if (obj->_func!=NULL) obj->_func(lc,obj->_user_data);
60         return 0;
61 }
62
63
64 static MSList *make_codec_list(const MSList *codecs){
65         MSList *l=NULL;
66         const MSList *it;
67         for(it=codecs;it!=NULL;it=it->next){
68                 PayloadType *pt=(PayloadType*)it->data;
69                 if (pt->flags & PAYLOAD_TYPE_ENABLED){
70                         l=ms_list_append(l,payload_type_clone(pt));
71                 }
72         }
73         return l;
74 }
75
76 static SalMediaDescription *create_local_media_description(LinphoneCore *lc, 
77                 const char *localip, const char *username){
78         MSList *l;
79         PayloadType *pt;
80         SalMediaDescription *md=sal_media_description_new();
81         md->nstreams=1;
82         strncpy(md->addr,localip,sizeof(md->addr));
83         strncpy(md->username,username,sizeof(md->username));
84         /*set audio capabilities */
85         strncpy(md->streams[0].addr,localip,sizeof(md->streams[0].addr));
86         md->streams[0].port=linphone_core_get_audio_port(lc);
87         md->streams[0].proto=SalProtoRtpAvp;
88         md->streams[0].type=SalAudio;
89         l=make_codec_list(lc->codecs_conf.audio_codecs);
90         pt=payload_type_clone(rtp_profile_get_payload_from_mime(&av_profile,"telephone-event"));
91         l=ms_list_append(l,pt);
92         md->streams[0].payloads=l;
93         
94         if (lc->dw_audio_bw>0)
95                 md->streams[0].bandwidth=lc->dw_audio_bw;
96
97         if (linphone_core_video_enabled (lc)){
98                 md->nstreams++;
99                 md->streams[1].port=linphone_core_get_video_port(lc);
100                 md->streams[1].proto=SalProtoRtpAvp;
101                 md->streams[1].type=SalVideo;
102                 l=make_codec_list(lc->codecs_conf.video_codecs);
103                 md->streams[1].payloads=l;
104                 if (lc->dw_video_bw)
105                         md->streams[1].bandwidth=lc->dw_video_bw;
106         }
107         return md;
108 }
109
110 static void linphone_call_init_common(LinphoneCall *call, LinphoneAddress *from, LinphoneAddress *to){
111         call->state=LCStateInit;
112         call->start_time=time(NULL);
113         call->media_start_time=0;
114         call->log=linphone_call_log_new(call, from, to);
115         linphone_core_notify_all_friends(call->core,LINPHONE_STATUS_ONTHEPHONE);
116         if (linphone_core_get_firewall_policy(call->core)==LINPHONE_POLICY_USE_STUN)
117                 linphone_core_run_stun_tests(call->core,call);
118 }
119
120 static void discover_mtu(LinphoneCore *lc, const char *remote){
121         int mtu;
122         if (lc->net_conf.mtu==0 ){
123                 /*attempt to discover mtu*/
124                 mtu=ms_discover_mtu(remote);
125                 if (mtu>0){
126                         ms_set_mtu(mtu);
127                         ms_message("Discovered mtu is %i, RTP payload max size is %i",
128                                 mtu, ms_get_payload_max_size());
129                 }
130         }
131 }
132
133 LinphoneCall * linphone_call_new_outgoing(struct _LinphoneCore *lc, LinphoneAddress *from, LinphoneAddress *to)
134 {
135         LinphoneCall *call=ms_new0(LinphoneCall,1);
136         call->dir=LinphoneCallOutgoing;
137         call->op=sal_op_new(lc->sal);
138         sal_op_set_user_pointer(call->op,lc->call);
139         call->core=lc;
140         linphone_core_get_local_ip(lc,linphone_address_get_domain(to),call->localip);
141         call->localdesc=create_local_media_description (lc,call->localip,
142                 linphone_address_get_username(from));
143         linphone_call_init_common(call,from,to);
144         discover_mtu(lc,linphone_address_get_domain (to));
145         return call;
146 }
147
148 LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *from, LinphoneAddress *to, SalOp *op){
149         LinphoneCall *call=ms_new0(LinphoneCall,1);
150         LinphoneAddress *me=linphone_core_get_primary_contact_parsed(lc);
151
152         call->dir=LinphoneCallIncoming;
153         sal_op_set_user_pointer(op,call);
154         call->op=op;
155         call->core=lc;
156         
157         linphone_address_clean(from);
158         linphone_core_get_local_ip(lc,linphone_address_get_domain(from),call->localip);
159         call->localdesc=create_local_media_description (lc,call->localip,
160             linphone_address_get_username(me));
161         linphone_call_init_common(call, from, to);
162         discover_mtu(lc,linphone_address_get_domain(from));
163         linphone_address_destroy(me);
164         return call;
165 }
166
167 void linphone_call_destroy(LinphoneCall *obj)
168 {
169         linphone_core_notify_all_friends(obj->core,obj->core->prev_mode);
170         linphone_call_log_completed(obj->log,obj);
171         linphone_core_update_allocated_audio_bandwidth(obj->core);
172         if (obj->op!=NULL) sal_op_release(obj->op);
173         if (obj->resultdesc!=NULL) sal_media_description_unref(obj->resultdesc);
174         if (obj->localdesc!=NULL) sal_media_description_unref(obj->localdesc);
175         ms_free(obj);
176 }
177
178 /*prevent a gcc bug with %c*/
179 static size_t my_strftime(char *s, size_t max, const char  *fmt,  const struct tm *tm){
180 #if !defined(_WIN32_WCE)
181         return strftime(s, max, fmt, tm);
182 #else
183         return 0;
184         /*FIXME*/
185 #endif /*_WIN32_WCE*/
186 }
187
188 static void set_call_log_date(LinphoneCallLog *cl, const struct tm *loctime){
189         my_strftime(cl->start_date,sizeof(cl->start_date),"%c",loctime);
190 }
191
192 LinphoneCallLog * linphone_call_log_new(LinphoneCall *call, LinphoneAddress *from, LinphoneAddress *to){
193         LinphoneCallLog *cl=ms_new0(LinphoneCallLog,1);
194         struct tm loctime;
195         cl->dir=call->dir;
196 #ifdef WIN32
197 #if !defined(_WIN32_WCE)
198         loctime=*localtime(&call->start_time);
199         /*FIXME*/
200 #endif /*_WIN32_WCE*/
201 #else
202         localtime_r(&call->start_time,&loctime);
203 #endif
204         set_call_log_date(cl,&loctime);
205         cl->from=from;
206         cl->to=to;
207         return cl;
208 }
209
210 static void call_logs_write_to_config_file(LinphoneCore *lc){
211         MSList *elem;
212         char logsection[32];
213         int i;
214         char *tmp;
215         LpConfig *cfg=lc->config;
216
217         if (!lc->ready) return;
218         
219         for(i=0,elem=lc->call_logs;elem!=NULL;elem=elem->next,++i){
220                 LinphoneCallLog *cl=(LinphoneCallLog*)elem->data;
221                 snprintf(logsection,sizeof(logsection),"call_log_%i",i);
222                 lp_config_set_int(cfg,logsection,"dir",cl->dir);
223                 lp_config_set_int(cfg,logsection,"status",cl->status);
224                 tmp=linphone_address_as_string(cl->from);
225                 lp_config_set_string(cfg,logsection,"from",tmp);
226                 ms_free(tmp);
227                 tmp=linphone_address_as_string(cl->to);
228                 lp_config_set_string(cfg,logsection,"to",tmp);
229                 ms_free(tmp);
230                 lp_config_set_string(cfg,logsection,"start_date",cl->start_date);
231                 lp_config_set_int(cfg,logsection,"duration",cl->duration);
232                 if (cl->refkey) lp_config_set_string(cfg,logsection,"refkey",cl->refkey);
233         }
234         for(;i<lc->max_call_logs;++i){
235                 snprintf(logsection,sizeof(logsection),"call_log_%i",i);
236                 lp_config_clean_section(cfg,logsection);
237         }
238 }
239
240 static void call_logs_read_from_config_file(LinphoneCore *lc){
241         char logsection[32];
242         int i;
243         const char *tmp;
244         LpConfig *cfg=lc->config;
245         for(i=0;;++i){
246                 snprintf(logsection,sizeof(logsection),"call_log_%i",i);
247                 if (lp_config_has_section(cfg,logsection)){
248                         LinphoneCallLog *cl=ms_new0(LinphoneCallLog,1);
249                         cl->dir=lp_config_get_int(cfg,logsection,"dir",0);
250                         cl->status=lp_config_get_int(cfg,logsection,"status",0);
251                         tmp=lp_config_get_string(cfg,logsection,"from",NULL);
252                         if (tmp) cl->from=linphone_address_new(tmp);
253                         tmp=lp_config_get_string(cfg,logsection,"to",NULL);
254                         if (tmp) cl->to=linphone_address_new(tmp);
255                         tmp=lp_config_get_string(cfg,logsection,"start_date",NULL);
256                         if (tmp) strncpy(cl->start_date,tmp,sizeof(cl->start_date));
257                         cl->duration=lp_config_get_int(cfg,logsection,"duration",0);
258                         tmp=lp_config_get_string(cfg,logsection,"refkey",NULL);
259                         if (tmp) cl->refkey=ms_strdup(tmp);
260                         lc->call_logs=ms_list_append(lc->call_logs,cl);
261                 }else break;    
262         }
263 }
264
265
266 void linphone_call_log_completed(LinphoneCallLog *calllog, LinphoneCall *call){
267         LinphoneCore *lc=call->core;
268         
269         calllog->duration=time(NULL)-call->start_time;
270         switch(call->state){
271                 case LCStateInit:
272                         calllog->status=LinphoneCallAborted;
273                         break;
274                 case LCStateRinging:
275                         if (calllog->dir==LinphoneCallIncoming){
276                                 char *info;
277                                 calllog->status=LinphoneCallMissed;
278                                 lc->missed_calls++;
279                                 info=ortp_strdup_printf(ngettext("You have missed %i call.",
280                             "You have missed %i calls.", lc->missed_calls),
281                         lc->missed_calls);
282                                 lc->vtable.display_status(lc,info);
283                                 ms_free(info);
284                         }
285                         else calllog->status=LinphoneCallAborted;
286                         break;
287                 case LCStateAVRunning:
288                         calllog->status=LinphoneCallSuccess;
289                         break;
290         }
291         lc->call_logs=ms_list_append(lc->call_logs,(void *)calllog);
292         if (ms_list_size(lc->call_logs)>lc->max_call_logs){
293                 MSList *elem;
294                 elem=lc->call_logs;
295                 linphone_call_log_destroy((LinphoneCallLog*)elem->data);
296                 lc->call_logs=ms_list_remove_link(lc->call_logs,elem);
297         }
298         if (lc->vtable.call_log_updated!=NULL){
299                 lc->vtable.call_log_updated(lc,calllog);
300         }
301         call_logs_write_to_config_file(lc);
302 }
303
304 /**
305  * @addtogroup call_logs
306  * @{
307 **/
308
309 /**
310  * Returns a human readable string describing the call.
311  * 
312  * @note: the returned char* must be freed by the application (use ms_free()).
313 **/
314 char * linphone_call_log_to_str(LinphoneCallLog *cl){
315         char *status;
316         char *tmp;
317         char *from=linphone_address_as_string (cl->from);
318         char *to=linphone_address_as_string (cl->to);
319         switch(cl->status){
320                 case LinphoneCallAborted:
321                         status=_("aborted");
322                         break;
323                 case LinphoneCallSuccess:
324                         status=_("completed");
325                         break;
326                 case LinphoneCallMissed:
327                         status=_("missed");
328                         break;
329                 default:
330                         status="unknown";
331         }
332         tmp=ortp_strdup_printf(_("%s at %s\nFrom: %s\nTo: %s\nStatus: %s\nDuration: %i mn %i sec\n"),
333                         (cl->dir==LinphoneCallIncoming) ? _("Incoming call") : _("Outgoing call"),
334                         cl->start_date,
335                         from,
336                         to,
337                         status,
338                         cl->duration/60,
339                         cl->duration%60);
340         ms_free(from);
341         ms_free(to);
342         return tmp;
343 }
344
345 void linphone_call_log_set_user_pointer(LinphoneCallLog *cl, void *up){
346         cl->user_pointer=up;
347 }
348
349 void *linphone_call_log_get_user_pointer(const LinphoneCallLog *cl){
350         return cl->user_pointer;
351 }
352
353
354
355 /**
356  * Associate a persistent reference key to the call log.
357  *
358  * The reference key can be for example an id to an external database.
359  * It is stored in the config file, thus can survive to process exits/restarts.
360  *
361 **/
362 void linphone_call_log_set_ref_key(LinphoneCallLog *cl, const char *refkey){
363         if (cl->refkey!=NULL){
364                 ms_free(cl->refkey);
365                 cl->refkey=NULL;
366         }
367         if (refkey) cl->refkey=ms_strdup(refkey);
368         call_logs_write_to_config_file(cl->lc);
369 }
370
371 /**
372  * Get the persistent reference key associated to the call log.
373  *
374  * The reference key can be for example an id to an external database.
375  * It is stored in the config file, thus can survive to process exits/restarts.
376  *
377 **/
378 const char *linphone_call_log_get_ref_key(const LinphoneCallLog *cl){
379         return cl->refkey;
380 }
381
382 /** @} */
383
384 void linphone_call_log_destroy(LinphoneCallLog *cl){
385         if (cl->from!=NULL) linphone_address_destroy(cl->from);
386         if (cl->to!=NULL) linphone_address_destroy(cl->to);
387         if (cl->refkey!=NULL) ms_free(cl->refkey);
388         ms_free(cl);
389 }
390
391 int linphone_core_get_current_call_duration(const LinphoneCore *lc){
392         LinphoneCall *call=lc->call;
393         if (call==NULL) return 0;
394         if (call->media_start_time==0) return 0;
395         return time(NULL)-call->media_start_time;
396 }
397
398 const LinphoneAddress *linphone_core_get_remote_uri(LinphoneCore *lc){
399         LinphoneCall *call=lc->call;
400         if (call==NULL) return 0;
401         return call->dir==LinphoneCallIncoming ? call->log->from : call->log->to;
402 }
403
404 /**
405  * Enable logs in supplied FILE*.
406  *
407  * @ingroup misc
408  *
409  * @param file a C FILE* where to fprintf logs. If null stdout is used.
410  * 
411 **/
412 void linphone_core_enable_logs(FILE *file){
413         if (file==NULL) file=stdout;
414         ortp_set_log_file(file);
415         ortp_set_log_level_mask(ORTP_MESSAGE|ORTP_WARNING|ORTP_ERROR|ORTP_FATAL);
416 }
417
418 /**
419  * Enable logs through the user's supplied log callback.
420  *
421  * @ingroup misc
422  *
423  * @param logfunc The address of a OrtpLogFunc callback whose protoype is
424  *                typedef void (*OrtpLogFunc)(OrtpLogLevel lev, const char *fmt, va_list args);
425  * 
426 **/
427 void linphone_core_enable_logs_with_cb(OrtpLogFunc logfunc){
428         ortp_set_log_level_mask(ORTP_MESSAGE|ORTP_WARNING|ORTP_ERROR|ORTP_FATAL);
429         ortp_set_log_handler(logfunc);
430 }
431
432 /**
433  * Entirely disable logging.
434  *
435  * @ingroup misc
436 **/
437 void linphone_core_disable_logs(){
438         ortp_set_log_level_mask(ORTP_ERROR|ORTP_FATAL);
439 }
440
441
442 static void
443 net_config_read (LinphoneCore *lc)
444 {
445         int tmp;
446         const char *tmpstr;
447         LpConfig *config=lc->config;
448
449         tmp=lp_config_get_int(config,"net","download_bw",0);
450         linphone_core_set_download_bandwidth(lc,tmp);
451         tmp=lp_config_get_int(config,"net","upload_bw",0);
452         linphone_core_set_upload_bandwidth(lc,tmp);
453         linphone_core_set_stun_server(lc,lp_config_get_string(config,"net","stun_server",NULL));
454         tmpstr=lp_config_get_string(lc->config,"net","nat_address",NULL);
455         if (tmpstr!=NULL && (strlen(tmpstr)<1)) tmpstr=NULL;
456         linphone_core_set_nat_address(lc,tmpstr);
457         tmp=lp_config_get_int(lc->config,"net","firewall_policy",0);
458         linphone_core_set_firewall_policy(lc,tmp);
459         tmp=lp_config_get_int(lc->config,"net","nat_sdp_only",0);
460         lc->net_conf.nat_sdp_only=tmp;
461         tmp=lp_config_get_int(lc->config,"net","mtu",0);
462         linphone_core_set_mtu(lc,tmp);
463 }
464
465 static void build_sound_devices_table(LinphoneCore *lc){
466         const char **devices;
467         const char **old;
468         int ndev;
469         int i;
470         const MSList *elem=ms_snd_card_manager_get_list(ms_snd_card_manager_get());
471         ndev=ms_list_size(elem);
472         devices=ms_malloc((ndev+1)*sizeof(const char *));
473         for (i=0;elem!=NULL;elem=elem->next,i++){
474                 devices[i]=ms_snd_card_get_string_id((MSSndCard *)elem->data);
475         }
476         devices[ndev]=NULL;
477         old=lc->sound_conf.cards;
478         lc->sound_conf.cards=devices;
479         if (old!=NULL) ms_free(old);
480 }
481
482 static void sound_config_read(LinphoneCore *lc)
483 {
484         /*int tmp;*/
485         const char *tmpbuf;
486         const char *devid;
487 #ifdef __linux
488         /*alsadev let the user use custom alsa device within linphone*/
489         devid=lp_config_get_string(lc->config,"sound","alsadev",NULL);
490         if (devid){
491                 MSSndCard *card=ms_alsa_card_new_custom(devid,devid);
492                 ms_snd_card_manager_add_card(ms_snd_card_manager_get(),card);
493         }
494 #endif
495         /* retrieve all sound devices */
496         build_sound_devices_table(lc);
497
498         devid=lp_config_get_string(lc->config,"sound","playback_dev_id",NULL);
499         linphone_core_set_playback_device(lc,devid);
500
501         devid=lp_config_get_string(lc->config,"sound","ringer_dev_id",NULL);
502         linphone_core_set_ringer_device(lc,devid);
503
504         devid=lp_config_get_string(lc->config,"sound","capture_dev_id",NULL);
505         linphone_core_set_capture_device(lc,devid);
506
507 /*
508         tmp=lp_config_get_int(lc->config,"sound","play_lev",80);
509         linphone_core_set_play_level(lc,tmp);
510         tmp=lp_config_get_int(lc->config,"sound","ring_lev",80);
511         linphone_core_set_ring_level(lc,tmp);
512         tmp=lp_config_get_int(lc->config,"sound","rec_lev",80);
513         linphone_core_set_rec_level(lc,tmp);
514         tmpbuf=lp_config_get_string(lc->config,"sound","source","m");
515         linphone_core_set_sound_source(lc,tmpbuf[0]);
516 */
517
518         tmpbuf=PACKAGE_SOUND_DIR "/" LOCAL_RING;
519         tmpbuf=lp_config_get_string(lc->config,"sound","local_ring",tmpbuf);
520         if (ortp_file_exist(tmpbuf)==-1) {
521                 tmpbuf=PACKAGE_SOUND_DIR "/" LOCAL_RING;
522         }
523         if (strstr(tmpbuf,".wav")==NULL){
524                 /* it currently uses old sound files, so replace them */
525                 tmpbuf=PACKAGE_SOUND_DIR "/" LOCAL_RING;
526         }
527
528         linphone_core_set_ring(lc,tmpbuf);
529
530         tmpbuf=PACKAGE_SOUND_DIR "/" REMOTE_RING;
531         tmpbuf=lp_config_get_string(lc->config,"sound","remote_ring",tmpbuf);
532         if (ortp_file_exist(tmpbuf)==-1){
533                 tmpbuf=PACKAGE_SOUND_DIR "/" REMOTE_RING;
534         }
535         if (strstr(tmpbuf,".wav")==NULL){
536                 /* it currently uses old sound files, so replace them */
537                 tmpbuf=PACKAGE_SOUND_DIR "/" REMOTE_RING;
538         }
539         linphone_core_set_ringback(lc,tmpbuf);
540         check_sound_device(lc);
541         lc->sound_conf.latency=0;
542
543         linphone_core_enable_echo_cancellation(lc,
544             lp_config_get_int(lc->config,"sound","echocancelation",0) |
545             lp_config_get_int(lc->config,"sound","echocancellation",0)
546                 );
547
548         linphone_core_enable_echo_limiter(lc,
549                 lp_config_get_int(lc->config,"sound","echolimiter",0));
550         linphone_core_enable_agc(lc,
551                 lp_config_get_int(lc->config,"sound","agc",0));
552 }
553
554 static void sip_config_read(LinphoneCore *lc)
555 {
556         char *contact;
557         const char *tmpstr;
558         int port;
559         int i,tmp;
560         int ipv6;
561         port=lp_config_get_int(lc->config,"sip","use_info",0);
562         linphone_core_set_use_info_for_dtmf(lc,port);
563
564         port=lp_config_get_int(lc->config,"sip","use_rfc2833",0);
565         linphone_core_set_use_rfc2833_for_dtmf(lc,port);
566
567         ipv6=lp_config_get_int(lc->config,"sip","use_ipv6",-1);
568         if (ipv6==-1){
569                 ipv6=0;
570                 if (host_has_ipv6_network()){
571                         lc->vtable.display_message(lc,_("Your machine appears to be connected to an IPv6 network. By default linphone always uses IPv4. Please update your configuration if you want to use IPv6"));
572                 }
573         }
574         linphone_core_enable_ipv6(lc,ipv6);
575         port=lp_config_get_int(lc->config,"sip","sip_port",5060);
576         linphone_core_set_sip_port(lc,port);
577
578         tmpstr=lp_config_get_string(lc->config,"sip","contact",NULL);
579         if (tmpstr==NULL || linphone_core_set_primary_contact(lc,tmpstr)==-1) {
580                 const char *hostname=NULL;
581                 const char *username=NULL;
582 #ifdef HAVE_GETENV
583                 hostname=getenv("HOST");
584                 username=getenv("USER");
585                 if (hostname==NULL) hostname=getenv("HOSTNAME");
586 #endif /*HAVE_GETENV*/
587                 if (hostname==NULL)
588                         hostname="unknown-host";
589                 if (username==NULL){
590                         username="toto";
591                 }
592                 contact=ortp_strdup_printf("sip:%s@%s",username,hostname);
593                 linphone_core_set_primary_contact(lc,contact);
594                 ms_free(contact);
595         }
596
597         tmp=lp_config_get_int(lc->config,"sip","guess_hostname",1);
598         linphone_core_set_guess_hostname(lc,tmp);
599
600
601         tmp=lp_config_get_int(lc->config,"sip","inc_timeout",15);
602         linphone_core_set_inc_timeout(lc,tmp);
603
604         /* get proxies config */
605         for(i=0;; i++){
606                 LinphoneProxyConfig *cfg=linphone_proxy_config_new_from_config_file(lc->config,i);
607                 if (cfg!=NULL){
608                         linphone_core_add_proxy_config(lc,cfg);
609                 }else{
610                         break;
611                 }
612         }
613         /* get the default proxy */
614         tmp=lp_config_get_int(lc->config,"sip","default_proxy",-1);
615         linphone_core_set_default_proxy_index(lc,tmp);
616
617         /* read authentication information */
618         for(i=0;; i++){
619                 LinphoneAuthInfo *ai=linphone_auth_info_new_from_config_file(lc->config,i);
620                 if (ai!=NULL){
621                         linphone_core_add_auth_info(lc,ai);
622                 }else{
623                         break;
624                 }
625         }
626         
627         /*for test*/
628         lc->sip_conf.sdp_200_ack=lp_config_get_int(lc->config,"sip","sdp_200_ack",0);
629         lc->sip_conf.only_one_codec=lp_config_get_int(lc->config,"sip","only_one_codec",0);
630         lc->sip_conf.register_only_when_network_is_up=
631                 lp_config_get_int(lc->config,"sip","register_only_when_network_is_up",0);
632 }
633
634 static void rtp_config_read(LinphoneCore *lc)
635 {
636         int port;
637         int jitt_comp;
638         int nortp_timeout;
639         port=lp_config_get_int(lc->config,"rtp","audio_rtp_port",7078);
640         linphone_core_set_audio_port(lc,port);
641
642         port=lp_config_get_int(lc->config,"rtp","video_rtp_port",9078);
643         if (port==0) port=9078;
644         linphone_core_set_video_port(lc,port);
645
646         jitt_comp=lp_config_get_int(lc->config,"rtp","audio_jitt_comp",60);
647         linphone_core_set_audio_jittcomp(lc,jitt_comp);
648         jitt_comp=lp_config_get_int(lc->config,"rtp","video_jitt_comp",60);
649         nortp_timeout=lp_config_get_int(lc->config,"rtp","nortp_timeout",30);
650         linphone_core_set_nortp_timeout(lc,nortp_timeout);
651 }
652
653 static PayloadType * find_payload(RtpProfile *prof, const char *mime_type, int clock_rate, const char *recv_fmtp){
654         PayloadType *candidate=NULL;
655         int i;
656         PayloadType *it;
657         for(i=0;i<127;++i){
658                 it=rtp_profile_get_payload(prof,i);
659                 if (it!=NULL && strcasecmp(mime_type,it->mime_type)==0
660                         && (clock_rate==it->clock_rate || clock_rate<=0) ){
661                         if ( (recv_fmtp && it->recv_fmtp && strcasecmp(recv_fmtp,it->recv_fmtp)==0) ||
662                                 (recv_fmtp==NULL && it->recv_fmtp==NULL) ){
663                                 /*exact match*/
664                                 return it;
665                         }else candidate=it;
666                 }
667         }
668         return candidate;
669 }
670
671 static bool_t get_codec(LpConfig *config, char* type, int index, PayloadType **ret){
672         char codeckey[50];
673         const char *mime,*fmtp;
674         int rate,enabled;
675         PayloadType *pt;
676
677         *ret=NULL;
678         snprintf(codeckey,50,"%s_%i",type,index);
679         mime=lp_config_get_string(config,codeckey,"mime",NULL);
680         if (mime==NULL || strlen(mime)==0 ) return FALSE;
681
682         rate=lp_config_get_int(config,codeckey,"rate",8000);
683         fmtp=lp_config_get_string(config,codeckey,"recv_fmtp",NULL);
684         enabled=lp_config_get_int(config,codeckey,"enabled",1);
685         pt=find_payload(&av_profile,mime,rate,fmtp);
686         if (pt && enabled ) pt->flags|=PAYLOAD_TYPE_ENABLED;
687         //ms_message("Found codec %s/%i",pt->mime_type,pt->clock_rate);
688         if (pt==NULL) ms_warning("Ignoring codec config %s/%i with fmtp=%s because unsupported",
689                         mime,rate,fmtp ? fmtp : "");
690         *ret=pt;
691         return TRUE;
692 }
693
694 static MSList *add_missing_codecs(SalStreamType mtype, MSList *l){
695         int i;
696         for(i=0;i<127;++i){
697                 PayloadType *pt=rtp_profile_get_payload(&av_profile,i);
698                 if (pt){
699                         if (mtype==SalVideo && pt->type!=PAYLOAD_VIDEO)
700                                 pt=NULL;
701                         else if (mtype==SalAudio && (pt->type!=PAYLOAD_AUDIO_PACKETIZED 
702                             && pt->type!=PAYLOAD_AUDIO_CONTINUOUS)){
703                                 pt=NULL;
704                         }
705                         if (pt && ms_filter_codec_supported(pt->mime_type)){
706                                 if (ms_list_find(l,pt)==NULL){
707                                         ms_message("Adding new codec %s/%i with fmtp %s",
708                                             pt->mime_type,pt->clock_rate,pt->recv_fmtp ? pt->recv_fmtp : "");
709                                         if (strcasecmp(pt->mime_type,"speex")==0 ||
710                                             strcasecmp(pt->mime_type,"MP4V-ES")==0 ||
711                                             strcasecmp(pt->mime_type,"H264")==0)
712                                                 l=ms_list_prepend(l,pt);
713                                         else l=ms_list_append(l,pt);
714                                 }
715                         }
716                 }
717         }
718         return l;
719 }
720
721 static void codecs_config_read(LinphoneCore *lc)
722 {
723         int i;
724         PayloadType *pt;
725         MSList *audio_codecs=NULL;
726         MSList *video_codecs=NULL;
727         for (i=0;get_codec(lc->config,"audio_codec",i,&pt);i++){
728                 if (pt){
729                         if (!ms_filter_codec_supported(pt->mime_type)){
730                                 ms_warning("Codec %s is not supported by mediastreamer2, removed.",pt->mime_type);
731                         }else audio_codecs=ms_list_append(audio_codecs,pt);
732                 }
733         }
734         audio_codecs=add_missing_codecs(SalAudio,audio_codecs);
735         for (i=0;get_codec(lc->config,"video_codec",i,&pt);i++){
736                 if (pt){
737                         if (!ms_filter_codec_supported(pt->mime_type)){
738                                 ms_warning("Codec %s is not supported by mediastreamer2, removed.",pt->mime_type);
739                         }else video_codecs=ms_list_append(video_codecs,(void *)pt);
740                 }
741         }
742         video_codecs=add_missing_codecs(SalVideo,video_codecs);
743         linphone_core_set_audio_codecs(lc,audio_codecs);
744         linphone_core_set_video_codecs(lc,video_codecs);
745         linphone_core_update_allocated_audio_bandwidth(lc);
746 }
747
748 static void video_config_read(LinphoneCore *lc){
749         int capture, display, self_view;
750         int enabled;
751         const char *str;
752         int ndev;
753         const char **devices;
754         const MSList *elem;
755         int i;
756
757         /* retrieve all video devices */
758         elem=ms_web_cam_manager_get_list(ms_web_cam_manager_get());
759         ndev=ms_list_size(elem);
760         devices=ms_malloc((ndev+1)*sizeof(const char *));
761         for (i=0;elem!=NULL;elem=elem->next,i++){
762                 devices[i]=ms_web_cam_get_string_id((MSWebCam *)elem->data);
763         }
764         devices[ndev]=NULL;
765         lc->video_conf.cams=devices;
766
767         str=lp_config_get_string(lc->config,"video","device",NULL);
768         if (str && str[0]==0) str=NULL;
769         linphone_core_set_video_device(lc,str);
770
771         linphone_core_set_preferred_video_size_by_name(lc,
772                 lp_config_get_string(lc->config,"video","size","cif"));
773
774         enabled=lp_config_get_int(lc->config,"video","enabled",1);
775         capture=lp_config_get_int(lc->config,"video","capture",enabled);
776         display=lp_config_get_int(lc->config,"video","display",enabled);
777         self_view=lp_config_get_int(lc->config,"video","self_view",enabled);
778 #ifdef VIDEO_ENABLED
779         linphone_core_enable_video(lc,capture,display);
780         linphone_core_enable_self_view(lc,self_view);
781 #endif
782 }
783
784 static void ui_config_read(LinphoneCore *lc)
785 {
786         LinphoneFriend *lf;
787         int i;
788         for (i=0;(lf=linphone_friend_new_from_config_file(lc,i))!=NULL;i++){
789                 linphone_core_add_friend(lc,lf);
790         }
791         call_logs_read_from_config_file(lc);
792 }
793
794 /*
795 static void autoreplier_config_init(LinphoneCore *lc)
796 {
797         autoreplier_config_t *config=&lc->autoreplier_conf;
798         config->enabled=lp_config_get_int(lc->config,"autoreplier","enabled",0);
799         config->after_seconds=lp_config_get_int(lc->config,"autoreplier","after_seconds",6);
800         config->max_users=lp_config_get_int(lc->config,"autoreplier","max_users",1);
801         config->max_rec_time=lp_config_get_int(lc->config,"autoreplier","max_rec_time",60);
802         config->max_rec_msg=lp_config_get_int(lc->config,"autoreplier","max_rec_msg",10);
803         config->message=lp_config_get_string(lc->config,"autoreplier","message",NULL);
804 }
805 */
806
807 /**
808  * Sets maximum available download bandwidth
809  *
810  * @ingroup media_parameters
811  *
812  * This is IP bandwidth, in kbit/s.
813  * This information is used signaled to other parties during
814  * calls (within SDP messages) so that the remote end can have
815  * sufficient knowledge to properly configure its audio & video
816  * codec output bitrate to not overflow available bandwidth.
817  *
818  * @param lc the LinphoneCore object
819  * @param bw the bandwidth in kbits/s, 0 for infinite
820  */
821 void linphone_core_set_download_bandwidth(LinphoneCore *lc, int bw){
822         lc->net_conf.download_bw=bw;
823         if (bw==0){ /*infinite*/
824                 lc->dw_audio_bw=-1;
825                 lc->dw_video_bw=-1;
826         }else {
827                 lc->dw_audio_bw=MIN(lc->audio_bw,bw);
828                 lc->dw_video_bw=MAX(bw-lc->dw_audio_bw-10,0);/*-10: security margin*/
829         }
830 }
831
832 /**
833  * Sets maximum available upload bandwidth
834  *
835  * @ingroup media_parameters
836  *
837  * This is IP bandwidth, in kbit/s.
838  * This information is used by liblinphone together with remote
839  * side available bandwidth signaled in SDP messages to properly
840  * configure audio & video codec's output bitrate.
841  *
842  * @param lc the LinphoneCore object
843  * @param bw the bandwidth in kbits/s, 0 for infinite
844  */
845 void linphone_core_set_upload_bandwidth(LinphoneCore *lc, int bw){
846         lc->net_conf.upload_bw=bw;
847         if (bw==0){ /*infinite*/
848                 lc->up_audio_bw=-1;
849                 lc->up_video_bw=-1;
850         }else{
851                 lc->up_audio_bw=MIN(lc->audio_bw,bw);
852                 lc->up_video_bw=MAX(bw-lc->up_audio_bw-10,0);/*-10: security margin*/
853         }
854 }
855
856 /**
857  * Retrieve the maximum available download bandwidth.
858  *
859  * @ingroup media_parameters
860  *
861  * This value was set by linphone_core_set_download_bandwidth().
862  *
863 **/
864 int linphone_core_get_download_bandwidth(const LinphoneCore *lc){
865         return lc->net_conf.download_bw;
866 }
867
868 /**
869  * Retrieve the maximum available upload bandwidth.
870  *
871  * @ingroup media_parameters
872  *
873  * This value was set by linphone_core_set_upload_bandwidth().
874  *
875 **/
876 int linphone_core_get_upload_bandwidth(const LinphoneCore *lc){
877         return lc->net_conf.upload_bw;
878 }
879
880 /**
881  * Returns liblinphone's version as a string.
882  *
883  * @ingroup misc
884  *
885 **/
886 const char * linphone_core_get_version(void){
887         return liblinphone_version;
888 }
889
890
891 static MSList *linphone_payload_types=NULL;
892
893 static void linphone_core_assign_payload_type(PayloadType *const_pt, int number, const char *recv_fmtp){
894         PayloadType *pt;
895         pt=payload_type_clone(const_pt);
896         payload_type_set_number(pt,number);
897         if (recv_fmtp!=NULL) payload_type_set_recv_fmtp(pt,recv_fmtp);
898         rtp_profile_set_payload(&av_profile,number,pt);
899         linphone_payload_types=ms_list_append(linphone_payload_types,pt);
900 }
901
902 static void linphone_core_free_payload_types(void){
903         ms_list_for_each(linphone_payload_types,(void (*)(void*))payload_type_destroy);
904         ms_list_free(linphone_payload_types);
905         linphone_payload_types=NULL;
906 }
907
908 static void linphone_core_init (LinphoneCore * lc, const LinphoneCoreVTable *vtable, const char *config_path, 
909     const char *factory_config_path, void * userdata)
910 {
911         memset (lc, 0, sizeof (LinphoneCore));
912         lc->data=userdata;
913
914         memcpy(&lc->vtable,vtable,sizeof(LinphoneCoreVTable));
915
916         gstate_initialize(lc);
917         gstate_new_state(lc, GSTATE_POWER_STARTUP, NULL);
918
919         ortp_init();
920         linphone_core_assign_payload_type(&payload_type_pcmu8000,0,NULL);
921         linphone_core_assign_payload_type(&payload_type_gsm,3,NULL);
922         linphone_core_assign_payload_type(&payload_type_pcma8000,8,NULL);
923         linphone_core_assign_payload_type(&payload_type_lpc1015,115,NULL);
924         linphone_core_assign_payload_type(&payload_type_speex_nb,110,"vbr=on");
925         linphone_core_assign_payload_type(&payload_type_speex_wb,111,"vbr=on");
926         linphone_core_assign_payload_type(&payload_type_speex_uwb,112,"vbr=on");
927         linphone_core_assign_payload_type(&payload_type_telephone_event,101,NULL);
928         linphone_core_assign_payload_type(&payload_type_ilbc,113,"mode=30");
929
930 #ifdef ENABLE_NONSTANDARD_GSM
931         {
932                 PayloadType *pt;
933                 pt=payload_type_clone(&payload_type_gsm);
934                 pt->clock_rate=11025;
935                 rtp_profile_set_payload(&av_profile,114,pt);
936                 linphone_payload_types=ms_list_append(linphone_payload_types,pt);
937                 pt=payload_type_clone(&payload_type_gsm);
938                 pt->clock_rate=22050;
939                 rtp_profile_set_payload(&av_profile,115,pt);
940                 linphone_payload_types=ms_list_append(linphone_payload_types,pt);
941         }
942 #endif
943
944 #ifdef VIDEO_ENABLED
945         linphone_core_assign_payload_type(&payload_type_h263,34,NULL);
946         linphone_core_assign_payload_type(&payload_type_theora,97,NULL);
947         linphone_core_assign_payload_type(&payload_type_h263_1998,98,"CIF=1;QCIF=1");
948         linphone_core_assign_payload_type(&payload_type_mp4v,99,"profile-level-id=3");
949         linphone_core_assign_payload_type(&payload_type_x_snow,100,NULL);
950         linphone_core_assign_payload_type(&payload_type_h264,102,NULL);
951         linphone_core_assign_payload_type(&payload_type_h264,103,"packetization-mode=1");
952 #endif
953
954         ms_init();
955
956         lc->config=lp_config_new(config_path);
957         if (factory_config_path)
958                 lp_config_read_file(lc->config,factory_config_path);
959
960 #ifdef VINCENT_MAURY_RSVP
961         /* default qos parameters : rsvp on, rpc off */
962         lc->rsvp_enable = 1;
963         lc->rpc_enable = 0;
964 #endif
965         lc->sal=sal_init();
966         sal_set_user_pointer(lc->sal,lc);
967         if (lp_config_get_int(lc->config,"sip","use_session_timers",0)==1){
968                 sal_use_session_timers(lc->sal,200);
969         }
970         sip_setup_register_all();
971         sound_config_read(lc);
972         net_config_read(lc);
973         rtp_config_read(lc);
974         codecs_config_read(lc);
975         sip_config_read(lc); /* this will start eXosip*/
976         video_config_read(lc);
977         //autoreplier_config_init(&lc->autoreplier_conf);
978         lc->prev_mode=LINPHONE_STATUS_ONLINE;
979         lc->presence_mode=LINPHONE_STATUS_ONLINE;
980         lc->max_call_logs=15;
981         ui_config_read(lc);
982         lc->vtable.display_status(lc,_("Ready"));
983         gstate_new_state(lc, GSTATE_POWER_ON, NULL);
984         lc->ready=TRUE;
985 }
986
987 /**
988  * Instanciates a LinphoneCore object.
989  * @ingroup initializing
990  * 
991  * The LinphoneCore object is the primary handle for doing all phone actions.
992  * It should be unique within your application.
993  * @param vtable a LinphoneCoreVTable structure holding your application callbacks
994  * @param config_path a path to a config file. If it does not exists it will be created.
995  *        The config file is used to store all user settings, call logs, friends, proxies...
996  * @param factory_config_path a path to a read-only config file that can be used to 
997  *        to store hard-coded preference such as proxy settings or internal preferences.
998  *        The settings in this factory file always override the one in the normal config file.
999  *        It is OPTIONAL, use NULL if unneeded.
1000  * @param userdata an opaque user pointer that can be retrieved at any time (for example in
1001  *        callbacks) using linphone_core_get_user_data().
1002  * 
1003 **/
1004 LinphoneCore *linphone_core_new(const LinphoneCoreVTable *vtable,
1005                                                 const char *config_path, const char *factory_config_path, void * userdata)
1006 {
1007         LinphoneCore *core=ms_new(LinphoneCore,1);
1008         linphone_core_init(core,vtable,config_path, factory_config_path, userdata);
1009         return core;
1010 }
1011
1012 /**
1013  * Returns the list of available audio codecs.
1014  *
1015  * This list is unmodifiable. The ->data field of the MSList points a PayloadType
1016  * structure holding the codec information.
1017  * It is possible to make copy of the list with ms_list_copy() in order to modify it
1018  * (such as the order of codecs).
1019 **/
1020 const MSList *linphone_core_get_audio_codecs(const LinphoneCore *lc)
1021 {
1022         return lc->codecs_conf.audio_codecs;
1023 }
1024
1025 /**
1026  * Returns the list of available video codecs.
1027  *
1028  * This list is unmodifiable. The ->data field of the MSList points a PayloadType
1029  * structure holding the codec information.
1030  * It is possible to make copy of the list with ms_list_copy() in order to modify it
1031  * (such as the order of codecs).
1032 **/
1033 const MSList *linphone_core_get_video_codecs(const LinphoneCore *lc)
1034 {
1035         return lc->codecs_conf.video_codecs;
1036 }
1037
1038 /**
1039  * Sets the local "from" identity.
1040  *
1041  * @ingroup proxies
1042  * This data is used in absence of any proxy configuration or when no
1043  * default proxy configuration is set. See LinphoneProxyConfig
1044 **/
1045 int linphone_core_set_primary_contact(LinphoneCore *lc, const char *contact)
1046 {
1047         LinphoneAddress *ctt;
1048
1049         if ((ctt=linphone_address_new(contact))!=0) {
1050                 ms_error("Bad contact url: %s",contact);
1051                 linphone_address_destroy(ctt);
1052                 return -1;
1053         }
1054         if (lc->sip_conf.contact!=NULL) ms_free(lc->sip_conf.contact);
1055         lc->sip_conf.contact=ms_strdup(contact);
1056         if (lc->sip_conf.guessed_contact!=NULL){
1057                 ms_free(lc->sip_conf.guessed_contact);
1058                 lc->sip_conf.guessed_contact=NULL;
1059         }
1060         linphone_address_destroy(ctt);
1061         return 0;
1062 }
1063
1064
1065 /*result must be an array of chars at least LINPHONE_IPADDR_SIZE */
1066 void linphone_core_get_local_ip(LinphoneCore *lc, const char *dest, char *result){
1067         if (lc->apply_nat_settings){
1068                 apply_nat_settings(lc);
1069                 lc->apply_nat_settings=FALSE;
1070         }
1071         if (linphone_core_get_firewall_policy(lc)==LINPHONE_POLICY_USE_NAT_ADDRESS){
1072                 strncpy(result,linphone_core_get_nat_address(lc),LINPHONE_IPADDR_SIZE);
1073                 return;
1074         }
1075         if (dest==NULL) dest="87.98.157.38"; /*a public IP address*/
1076         if (linphone_core_get_local_ip_for(dest,result)==0)
1077                 return;
1078         /*else fallback to SAL routine that will attempt to find the most realistic interface */
1079         sal_get_default_local_ip(lc->sal,lc->sip_conf.ipv6_enabled ? AF_INET6 : AF_INET,result,LINPHONE_IPADDR_SIZE);
1080 }
1081
1082 /**
1083  * Returns the default identity when no proxy configuration is used.
1084  *
1085  * @ingroup proxies
1086 **/
1087 const char *linphone_core_get_primary_contact(LinphoneCore *lc){
1088         char *identity;
1089         char tmp[LINPHONE_IPADDR_SIZE];
1090         
1091         if (lc->sip_conf.guess_hostname){
1092                 if (lc->sip_conf.guessed_contact==NULL || lc->sip_conf.loopback_only){
1093                         char *guessed=NULL;
1094                         LinphoneAddress *url;
1095                         if (lc->sip_conf.guessed_contact!=NULL){
1096                                 ms_free(lc->sip_conf.guessed_contact);
1097                                 lc->sip_conf.guessed_contact=NULL;
1098                         }
1099                         url=linphone_address_new(lc->sip_conf.contact);
1100                         if (!url){
1101                                 url=linphone_address_new("sip:unknown@unkwownhost");
1102                         }else ms_error("Could not parse identity contact !");
1103                         linphone_core_get_local_ip(lc, NULL, tmp);
1104                         if (strcmp(tmp,"127.0.0.1")==0 || strcmp(tmp,"::1")==0 ){
1105                                 ms_warning("Local loopback network only !");
1106                                 lc->sip_conf.loopback_only=TRUE;
1107                         }else lc->sip_conf.loopback_only=FALSE;
1108                         linphone_address_set_domain(url,tmp);
1109                         linphone_address_set_port_int(url,lc->sip_conf.sip_port);
1110                         guessed=linphone_address_as_string(url);
1111                         lc->sip_conf.guessed_contact=guessed;
1112                         linphone_address_destroy(url);
1113                 }
1114                 identity=lc->sip_conf.guessed_contact;
1115         }else{
1116                 identity=lc->sip_conf.contact;
1117         }
1118         return identity;
1119 }
1120
1121 /**
1122  * Tells LinphoneCore to guess local hostname automatically in primary contact.
1123  *
1124  * @ingroup proxies
1125 **/
1126 void linphone_core_set_guess_hostname(LinphoneCore *lc, bool_t val){
1127         lc->sip_conf.guess_hostname=val;
1128 }
1129
1130 /**
1131  * Returns TRUE if hostname part of primary contact is guessed automatically.
1132  *
1133  * @ingroup proxies
1134 **/
1135 bool_t linphone_core_get_guess_hostname(LinphoneCore *lc){
1136         return lc->sip_conf.guess_hostname;
1137 }
1138
1139 /**
1140  * Same as linphone_core_get_primary_contact() but the result is a LinphoneAddress object
1141  * instead of const char*
1142  *
1143  * @ingroup proxies
1144 **/
1145 LinphoneAddress *linphone_core_get_primary_contact_parsed(LinphoneCore *lc){
1146         return linphone_address_new(linphone_core_get_primary_contact(lc));
1147 }
1148
1149 /**
1150  * Sets the list of audio codecs.
1151  *
1152  * @ingroup media_parameters
1153  * The list is taken by the LinphoneCore thus the application should not free it.
1154  * This list is made of struct PayloadType describing the codec parameters.
1155 **/
1156 int linphone_core_set_audio_codecs(LinphoneCore *lc, MSList *codecs)
1157 {
1158         if (lc->codecs_conf.audio_codecs!=NULL) ms_list_free(lc->codecs_conf.audio_codecs);
1159         lc->codecs_conf.audio_codecs=codecs;
1160         return 0;
1161 }
1162
1163 /**
1164  * Sets the list of video codecs.
1165  *
1166  * @ingroup media_parameters
1167  * The list is taken by the LinphoneCore thus the application should not free it.
1168  * This list is made of struct PayloadType describing the codec parameters.
1169 **/
1170 int linphone_core_set_video_codecs(LinphoneCore *lc, MSList *codecs)
1171 {
1172         if (lc->codecs_conf.video_codecs!=NULL) ms_list_free(lc->codecs_conf.video_codecs);
1173         lc->codecs_conf.video_codecs=codecs;
1174         return 0;
1175 }
1176
1177 const MSList * linphone_core_get_friend_list(const LinphoneCore *lc)
1178 {
1179         return lc->friends;
1180 }
1181
1182 /**
1183  * Returns the nominal jitter buffer size in milliseconds.
1184  *
1185  * @ingroup media_parameters
1186 **/
1187 int linphone_core_get_audio_jittcomp(LinphoneCore *lc)
1188 {
1189         return lc->rtp_conf.audio_jitt_comp;
1190 }
1191
1192 /**
1193  * Returns the UDP port used for audio streaming.
1194  *
1195  * @ingroup network_parameters
1196 **/
1197 int linphone_core_get_audio_port(const LinphoneCore *lc)
1198 {
1199         return lc->rtp_conf.audio_rtp_port;
1200 }
1201
1202 /**
1203  * Returns the UDP port used for video streaming.
1204  *
1205  * @ingroup network_parameters
1206 **/
1207 int linphone_core_get_video_port(const LinphoneCore *lc){
1208         return lc->rtp_conf.video_rtp_port;
1209 }
1210
1211
1212 /**
1213  * Returns the value in seconds of the no-rtp timeout.
1214  *
1215  * @ingroup media_parameters
1216  * When no RTP or RTCP packets have been received for a while
1217  * LinphoneCore will consider the call is broken (remote end crashed or
1218  * disconnected from the network), and thus will terminate the call.
1219  * The no-rtp timeout is the duration above which the call is considered broken.
1220 **/
1221 int linphone_core_get_nortp_timeout(const LinphoneCore *lc){
1222         return lc->rtp_conf.nortp_timeout;
1223 }
1224
1225 /**
1226  * Sets the nominal audio jitter buffer size in milliseconds.
1227  *
1228  * @ingroup media_parameters
1229 **/
1230 void linphone_core_set_audio_jittcomp(LinphoneCore *lc, int value)
1231 {
1232         lc->rtp_conf.audio_jitt_comp=value;
1233 }
1234
1235 /**
1236  * Sets the UDP port used for audio streaming.
1237  *
1238  * @ingroup network_parameters
1239 **/
1240 void linphone_core_set_audio_port(LinphoneCore *lc, int port)
1241 {
1242         lc->rtp_conf.audio_rtp_port=port;
1243 }
1244
1245 /**
1246  * Sets the UDP port used for video streaming.
1247  *
1248  * @ingroup network_parameters
1249 **/
1250 void linphone_core_set_video_port(LinphoneCore *lc, int port){
1251         lc->rtp_conf.video_rtp_port=port;
1252 }
1253
1254 /**
1255  * Sets the no-rtp timeout value in seconds.
1256  * 
1257  * @ingroup media_parameters
1258  * See linphone_core_get_nortp_timeout() for details.
1259 **/
1260 void linphone_core_set_nortp_timeout(LinphoneCore *lc, int nortp_timeout){
1261         lc->rtp_conf.nortp_timeout=nortp_timeout;
1262 }
1263
1264 /**
1265  * Indicates whether SIP INFO is used for sending digits.
1266  *
1267  * @ingroup media_parameters
1268 **/
1269 bool_t linphone_core_get_use_info_for_dtmf(LinphoneCore *lc)
1270 {
1271         return lc->sip_conf.use_info;
1272 }
1273
1274 /**
1275  * Sets whether SIP INFO is to be used for sending digits.
1276  *
1277  * @ingroup media_parameters
1278 **/
1279 void linphone_core_set_use_info_for_dtmf(LinphoneCore *lc,bool_t use_info)
1280 {
1281         lc->sip_conf.use_info=use_info;
1282 }
1283
1284 /**
1285  * Indicates whether RFC2833 is used for sending digits.
1286  *
1287  * @ingroup media_parameters
1288 **/
1289 bool_t linphone_core_get_use_rfc2833_for_dtmf(LinphoneCore *lc)
1290 {
1291         return lc->sip_conf.use_rfc2833;
1292 }
1293
1294 /**
1295  * Sets whether RFC2833 is to be used for sending digits.
1296  *
1297  * @ingroup media_parameters
1298 **/
1299 void linphone_core_set_use_rfc2833_for_dtmf(LinphoneCore *lc,bool_t use_rfc2833)
1300 {
1301         lc->sip_conf.use_rfc2833=use_rfc2833;
1302 }
1303
1304 /**
1305  * Returns the UDP port used by SIP.
1306  *
1307  * @ingroup network_parameters
1308 **/
1309 int linphone_core_get_sip_port(LinphoneCore *lc)
1310 {
1311         return lc->sip_conf.sip_port;
1312 }
1313
1314 static bool_t exosip_running=FALSE;
1315 static char _ua_name[64]="Linphone";
1316 static char _ua_version[64]=LINPHONE_VERSION;
1317
1318 #ifdef HAVE_EXOSIP_GET_VERSION
1319 extern const char *eXosip_get_version();
1320 #endif
1321
1322 static void apply_user_agent(LinphoneCore *lc){
1323         char ua_string[256];
1324         snprintf(ua_string,sizeof(ua_string),"%s/%s (eXosip2/%s)",_ua_name,_ua_version,
1325 #ifdef HAVE_EXOSIP_GET_VERSION
1326                  eXosip_get_version()
1327 #else
1328                  "unknown"
1329 #endif
1330         );
1331         if (lc->sal) sal_set_user_agent(lc->sal,ua_string);
1332 }
1333
1334 /**
1335  * Sets the user agent string used in SIP messages.
1336  *
1337  * @ingroup misc
1338 **/
1339 void linphone_core_set_user_agent(const char *name, const char *ver){
1340         strncpy(_ua_name,name,sizeof(_ua_name)-1);
1341         strncpy(_ua_version,ver,sizeof(_ua_version));
1342 }
1343
1344 /**
1345  * Sets the UDP port to be used by SIP.
1346  *
1347  * @ingroup network_parameters
1348 **/
1349 void linphone_core_set_sip_port(LinphoneCore *lc,int port)
1350 {
1351         const char *anyaddr;
1352         int err=0;
1353         if (port==lc->sip_conf.sip_port) return;
1354         lc->sip_conf.sip_port=port;
1355
1356         if (lc->sal==NULL) return;
1357         
1358         if (lc->sip_conf.ipv6_enabled)
1359                 anyaddr="::0";
1360         else
1361                 anyaddr="0.0.0.0";
1362         err=sal_listen_port (lc->sal,anyaddr,port, SalTransportDatagram,FALSE);
1363         if (err<0){
1364                 char *msg=ortp_strdup_printf("UDP port %i seems already in use ! Cannot initialize.",port);
1365                 ms_warning(msg);
1366                 lc->vtable.display_warning(lc,msg);
1367                 ms_free(msg);
1368                 return;
1369         }
1370         apply_user_agent(lc);
1371 }
1372
1373 /**
1374  * Returns TRUE if IPv6 is enabled.
1375  *
1376  * @ingroup network_parameters
1377  * See linphone_core_enable_ipv6() for more details on how IPv6 is supported in liblinphone.
1378 **/
1379 bool_t linphone_core_ipv6_enabled(LinphoneCore *lc){
1380         return lc->sip_conf.ipv6_enabled;
1381 }
1382
1383 /**
1384  * Turns IPv6 support on or off.
1385  *
1386  * @ingroup network_parameters
1387  *
1388  * @note IPv6 support is exclusive with IPv4 in liblinphone:
1389  * when IPv6 is turned on, IPv4 calls won't be possible anymore.
1390  * By default IPv6 support is off.
1391 **/
1392 void linphone_core_enable_ipv6(LinphoneCore *lc, bool_t val){
1393         if (lc->sip_conf.ipv6_enabled!=val){
1394                 lc->sip_conf.ipv6_enabled=val;
1395                 if (lc->sal){
1396                         /* we need to restart eXosip */
1397                         linphone_core_set_sip_port(lc, lc->sip_conf.sip_port);
1398                 }
1399         }
1400 }
1401
1402 static void display_bandwidth(RtpSession *as, RtpSession *vs){
1403         ms_message("bandwidth usage: audio=[d=%.1f,u=%.1f] video=[d=%.1f,u=%.1f] kbit/sec",
1404         (as!=NULL) ? (rtp_session_compute_recv_bandwidth(as)*1e-3) : 0,
1405         (as!=NULL) ? (rtp_session_compute_send_bandwidth(as)*1e-3) : 0,
1406         (vs!=NULL) ? (rtp_session_compute_recv_bandwidth(vs)*1e-3) : 0,
1407         (vs!=NULL) ? (rtp_session_compute_send_bandwidth(vs)*1e-3) : 0);
1408 }
1409
1410 static void linphone_core_disconnected(LinphoneCore *lc){
1411         lc->vtable.display_warning(lc,_("Remote end seems to have disconnected, the call is going to be closed."));
1412         linphone_core_terminate_call(lc,NULL);
1413 }
1414
1415 static void proxy_update(LinphoneCore *lc, time_t curtime){
1416         bool_t doit=FALSE;
1417         static time_t last_check=0;
1418         static bool_t last_status=FALSE;
1419         if (lc->sip_conf.register_only_when_network_is_up){
1420                 char result[LINPHONE_IPADDR_SIZE];
1421                 /* only do the network up checking every five seconds */
1422                 if (last_check==0 || (curtime-last_check)>=5){
1423                         sal_get_default_local_ip(lc->sal,
1424                             lc->sip_conf.ipv6_enabled ? AF_INET6 : AF_INET,
1425                             result,LINPHONE_IPADDR_SIZE);
1426                         if (strcmp(result,"::1")!=0 && strcmp(result,"127.0.0.1")!=0){
1427                                 last_status=TRUE;
1428                                 ms_message("Network is up, registering now (%s)",result);
1429                         }else last_status=FALSE;
1430                         last_check=curtime;
1431                 }
1432                 doit=last_status;
1433         }else doit=TRUE;
1434         if (doit) ms_list_for_each(lc->sip_conf.proxies,(void (*)(void*))&linphone_proxy_config_update);
1435 }
1436
1437 static void assign_buddy_info(LinphoneCore *lc, BuddyInfo *info){
1438         LinphoneFriend *lf=linphone_core_get_friend_by_address(lc,info->sip_uri);
1439         if (lf!=NULL){
1440                 lf->info=info;
1441                 ms_message("%s has a BuddyInfo assigned with image %p",info->sip_uri, info->image_data);
1442                 if (lc->vtable.buddy_info_updated)
1443                         lc->vtable.buddy_info_updated(lc,lf);
1444         }else{
1445                 ms_warning("Could not any friend with uri %s",info->sip_uri);
1446         }
1447 }
1448
1449 static void analyze_buddy_lookup_results(LinphoneCore *lc, LinphoneProxyConfig *cfg){
1450         MSList *elem;
1451         SipSetupContext *ctx=linphone_proxy_config_get_sip_setup_context(cfg);
1452         for (elem=lc->bl_reqs;elem!=NULL;elem=ms_list_next(elem)){
1453                 BuddyLookupRequest *req=(BuddyLookupRequest *)elem->data;
1454                 if (req->status==BuddyLookupDone || req->status==BuddyLookupFailure){
1455                         if (req->results!=NULL){
1456                                 BuddyInfo *i=(BuddyInfo*)req->results->data;
1457                                 ms_list_free(req->results);
1458                                 req->results=NULL;
1459                                 assign_buddy_info(lc,i);
1460                         }
1461                         sip_setup_context_buddy_lookup_free(ctx,req);
1462                         elem->data=NULL;
1463                 }
1464         }
1465         /*purge completed requests */
1466         while((elem=ms_list_find(lc->bl_reqs,NULL))!=NULL){
1467                 lc->bl_reqs=ms_list_remove_link(lc->bl_reqs,elem);
1468         }
1469 }
1470
1471 static void linphone_core_grab_buddy_infos(LinphoneCore *lc, LinphoneProxyConfig *cfg){
1472         const MSList *elem;
1473         SipSetupContext *ctx=linphone_proxy_config_get_sip_setup_context(cfg);
1474         for(elem=linphone_core_get_friend_list(lc);elem!=NULL;elem=elem->next){
1475                 LinphoneFriend *lf=(LinphoneFriend*)elem->data;
1476                 if (lf->info==NULL){
1477                         if (linphone_core_lookup_known_proxy(lc,lf->uri)==cfg){
1478                                 if (linphone_address_get_username(lf->uri)!=NULL){
1479                                         BuddyLookupRequest *req;
1480                                         char *tmp=linphone_address_as_string_uri_only(lf->uri);
1481                                         req=sip_setup_context_create_buddy_lookup_request(ctx);
1482                                         buddy_lookup_request_set_key(req,tmp);
1483                                         buddy_lookup_request_set_max_results(req,1);
1484                                         sip_setup_context_buddy_lookup_submit(ctx,req);
1485                                         lc->bl_reqs=ms_list_append(lc->bl_reqs,req);
1486                                         ms_free(tmp);
1487                                 }
1488                         }
1489                 }
1490         }
1491 }
1492
1493 static void linphone_core_do_plugin_tasks(LinphoneCore *lc){
1494         LinphoneProxyConfig *cfg=NULL;
1495         linphone_core_get_default_proxy(lc,&cfg);
1496         if (cfg){
1497                 if (lc->bl_refresh){
1498                         SipSetupContext *ctx=linphone_proxy_config_get_sip_setup_context(cfg);
1499                         if (ctx && (sip_setup_context_get_capabilities(ctx) & SIP_SETUP_CAP_BUDDY_LOOKUP)){
1500                                 linphone_core_grab_buddy_infos(lc,cfg);
1501                                 lc->bl_refresh=FALSE;
1502                         }
1503                 }
1504                 if (lc->bl_reqs) analyze_buddy_lookup_results(lc,cfg);
1505         }
1506 }
1507
1508 /**
1509  * Main loop function. It is crucial that your application call it periodically.
1510  *
1511  * @ingroup initializing
1512  * linphone_core_iterate() performs various backgrounds tasks:
1513  * - receiving of SIP messages
1514  * - handles timers and timeout
1515  * - performs registration to proxies
1516  * - authentication retries
1517  * The application MUST call this function from periodically, in its main loop.
1518  * Be careful that this function must be call from the same thread as
1519  * other liblinphone methods. In not the case make sure all liblinphone calls are 
1520  * serialized with a mutex.
1521 **/
1522 void linphone_core_iterate(LinphoneCore *lc){
1523         int disconnect_timeout = linphone_core_get_nortp_timeout(lc);
1524         time_t curtime=time(NULL);
1525         int elapsed;
1526         bool_t one_second_elapsed=FALSE;
1527         bool_t disconnected=FALSE;
1528
1529         if (curtime-lc->prevtime>=1){
1530                 lc->prevtime=curtime;
1531                 one_second_elapsed=TRUE;
1532         }
1533
1534         if (lc->preview_finished){
1535                 lc->preview_finished=0;
1536                 ring_stop(lc->ringstream);
1537                 lc->ringstream=NULL;
1538                 lc_callback_obj_invoke(&lc->preview_finished_cb,lc);
1539         }
1540
1541         sal_iterate(lc->sal);
1542         proxy_update(lc,curtime);
1543
1544         if (lc->call!=NULL){
1545                 LinphoneCall *call=lc->call;
1546
1547                 if (call->dir==LinphoneCallIncoming && call->state==LCStateRinging){
1548                         elapsed=curtime-call->start_time;
1549                         ms_message("incoming call ringing for %i seconds",elapsed);
1550                         if (elapsed>lc->sip_conf.inc_timeout){
1551                                 linphone_core_terminate_call(lc,NULL);
1552                         }
1553                 }else if (call->state==LCStateAVRunning){
1554                         if (one_second_elapsed){
1555                                 RtpSession *as=NULL,*vs=NULL;
1556                                 lc->prevtime=curtime;
1557                                 if (lc->audiostream!=NULL)
1558                                         as=lc->audiostream->session;
1559                                 if (lc->videostream!=NULL)
1560                                         vs=lc->videostream->session;
1561                                 display_bandwidth(as,vs);
1562                         }
1563 #ifdef VIDEO_ENABLED
1564                         if (lc->videostream!=NULL)
1565                                 video_stream_iterate(lc->videostream);
1566 #endif
1567                         if (lc->audiostream!=NULL && disconnect_timeout>0)
1568                                 disconnected=!audio_stream_alive(lc->audiostream,disconnect_timeout);
1569                 }
1570         }
1571         if (linphone_core_video_preview_enabled(lc)){
1572                 if (lc->previewstream==NULL)
1573                         toggle_video_preview(lc,TRUE);
1574 #ifdef VIDEO_ENABLED
1575                 else video_stream_iterate(lc->previewstream);
1576 #endif
1577         }else{
1578                 if (lc->previewstream!=NULL)
1579                         toggle_video_preview(lc,FALSE);
1580         }
1581         if (disconnected)
1582                 linphone_core_disconnected(lc);
1583
1584         linphone_core_do_plugin_tasks(lc);
1585
1586         if (one_second_elapsed && lp_config_needs_commit(lc->config)){
1587                 lp_config_sync(lc->config);
1588         }
1589 }
1590
1591
1592 bool_t linphone_core_interpret_url(LinphoneCore *lc, const char *url, LinphoneAddress **real_parsed_url, char **route){
1593         enum_lookup_res_t *enumres=NULL;
1594         LinphoneAddress *parsed_url=NULL;       
1595         char *enum_domain=NULL;
1596         LinphoneProxyConfig *proxy;
1597         char *tmpurl;
1598         const char *tmproute;
1599         if (real_parsed_url!=NULL) *real_parsed_url=NULL;
1600         *route=NULL;
1601         tmproute=linphone_core_get_route(lc);
1602
1603         if (is_enum(url,&enum_domain)){
1604                 lc->vtable.display_status(lc,_("Looking for telephone number destination..."));
1605                 if (enum_lookup(enum_domain,&enumres)<0){
1606                         lc->vtable.display_status(lc,_("Could not resolve this number."));
1607                         ms_free(enum_domain);
1608                         return FALSE;
1609                 }
1610                 ms_free(enum_domain);
1611                 tmpurl=enumres->sip_address[0];
1612                 if (real_parsed_url!=NULL) *real_parsed_url=linphone_address_new(tmpurl);
1613                 enum_lookup_res_free(enumres);
1614                 if (tmproute) *route=ms_strdup(tmproute);
1615                 return TRUE;
1616         }
1617         /* check if we have a "sip:" */
1618         if (strstr(url,"sip:")==NULL){
1619                 /* this doesn't look like a true sip uri */
1620                 proxy=lc->default_proxy;
1621                 if (proxy!=NULL){
1622                         /* append the proxy domain suffix */
1623                         LinphoneAddress *uri;
1624                         const char *identity=linphone_proxy_config_get_identity(proxy);
1625                         char normalized_username[128];
1626                         uri=linphone_address_new(identity);
1627                         if (uri==NULL){
1628                                 return FALSE;
1629                         }
1630                         linphone_address_set_display_name(uri,NULL);
1631                         linphone_proxy_config_normalize_number(proxy,url,normalized_username,
1632                                                                 sizeof(normalized_username));
1633                         linphone_address_set_username(uri,normalized_username);
1634                                                                                 
1635                         if (real_parsed_url!=NULL) *real_parsed_url=uri;
1636                         if (tmproute) *route=ms_strdup(tmproute);
1637                         return TRUE;
1638                 }
1639         }
1640         parsed_url=linphone_address_new(url);
1641         if (parsed_url!=NULL){
1642                 if (real_parsed_url!=NULL) *real_parsed_url=parsed_url;
1643                 else linphone_address_destroy(parsed_url);
1644                 if (tmproute) *route=ms_strdup(tmproute);
1645                 
1646                 return TRUE;
1647         }
1648         /* else we could not do anything with url given by user, so display an error */
1649         if (lc->vtable.display_warning!=NULL){
1650                 lc->vtable.display_warning(lc,_("Could not parse given sip address. A sip url usually looks like sip:user@domain"));
1651         }
1652         return FALSE;
1653 }
1654
1655 /**
1656  * Returns the default identity SIP address.
1657  *
1658  * @ingroup proxies
1659  * This is an helper function:
1660  *
1661  * If no default proxy is set, this will return the primary contact (
1662  * see linphone_core_get_primary_contact() ). If a default proxy is set
1663  * it returns the registered identity on the proxy.
1664 **/
1665 const char * linphone_core_get_identity(LinphoneCore *lc){
1666         LinphoneProxyConfig *proxy=NULL;
1667         const char *from;
1668         linphone_core_get_default_proxy(lc,&proxy);
1669         if (proxy!=NULL) {
1670                 from=linphone_proxy_config_get_identity(proxy);
1671         }else from=linphone_core_get_primary_contact(lc);
1672         return from;
1673 }
1674
1675 const char * linphone_core_get_route(LinphoneCore *lc){
1676         LinphoneProxyConfig *proxy=NULL;
1677         const char *route=NULL;
1678         linphone_core_get_default_proxy(lc,&proxy);
1679         if (proxy!=NULL) {
1680                 route=linphone_proxy_config_get_route(proxy);
1681         }
1682         return route;
1683 }
1684
1685 LinphoneProxyConfig * linphone_core_lookup_known_proxy(LinphoneCore *lc, const LinphoneAddress *uri){
1686         const MSList *elem;
1687         LinphoneProxyConfig *found_cfg=NULL;
1688         for (elem=linphone_core_get_proxy_config_list(lc);elem!=NULL;elem=elem->next){
1689                 LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)elem->data;
1690                 const char *domain=linphone_proxy_config_get_domain(cfg);
1691                 if (domain!=NULL && strcmp(domain,linphone_address_get_domain(uri))==0){
1692                         found_cfg=cfg;
1693                         break;
1694                 }
1695         }
1696         return found_cfg;
1697 }
1698
1699 static char *get_fixed_contact(LinphoneCore *lc, const char *localip, LinphoneProxyConfig *dest_proxy){
1700         LinphoneAddress *ctt;
1701
1702         if (dest_proxy && dest_proxy->op){
1703                 const char *fixed_contact=sal_op_get_contact(dest_proxy->op);
1704                 if (fixed_contact) {
1705                         ms_message("Contact has been fixed using proxy to %s",fixed_contact);
1706                         return ms_strdup(fixed_contact);
1707                 }
1708         }
1709         ctt=linphone_core_get_primary_contact_parsed(lc);
1710         
1711         if (ctt!=NULL){
1712                 char *ret;
1713                 /*otherwise use supllied localip*/
1714                 linphone_address_set_domain(ctt,localip);
1715                 linphone_address_set_port_int(ctt,linphone_core_get_sip_port(lc));
1716                 ret=linphone_address_as_string_uri_only(ctt);
1717                 linphone_address_destroy(ctt);
1718                 ms_message("Contact has been fixed using local ip to %s",ret);
1719                 return ret;
1720         }
1721         return NULL;
1722 }
1723
1724 /**
1725  * Initiates an outgoing call
1726  *
1727  * @ingroup call_control
1728  * @param lc the LinphoneCore object
1729  * @param url the destination of the call (sip address).
1730 **/
1731 int linphone_core_invite(LinphoneCore *lc, const char *url)
1732 {
1733         char *barmsg;
1734         int err=0;
1735         char *route=NULL;
1736         const char *from=NULL;
1737         const char *contact=NULL;
1738         LinphoneProxyConfig *proxy=NULL;
1739         LinphoneAddress *parsed_url2=NULL;
1740         LinphoneAddress *real_parsed_url=NULL;
1741         char *real_url=NULL;
1742         LinphoneProxyConfig *dest_proxy=NULL;
1743         LinphoneCall *call;
1744         
1745         if (lc->call!=NULL){
1746                 lc->vtable.display_warning(lc,_("Sorry, having multiple simultaneous calls is not supported yet !"));
1747                 return -1;
1748         }
1749
1750         linphone_core_get_default_proxy(lc,&proxy);
1751         if (!linphone_core_interpret_url(lc,url,&real_parsed_url,&route)){
1752                 return -1;
1753         }
1754         real_url=linphone_address_as_string(real_parsed_url);
1755         dest_proxy=linphone_core_lookup_known_proxy(lc,real_parsed_url);
1756
1757         if (proxy!=dest_proxy && dest_proxy!=NULL) {
1758                 ms_message("Overriding default proxy setting for this call:");
1759                 ms_message("The used identity will be %s",linphone_proxy_config_get_identity(dest_proxy));
1760         }
1761
1762         if (dest_proxy!=NULL)
1763                 from=linphone_proxy_config_get_identity(dest_proxy);
1764         else if (proxy!=NULL)
1765                 from=linphone_proxy_config_get_identity(proxy);
1766
1767         /* if no proxy or no identity defined for this proxy, default to primary contact*/
1768         if (from==NULL) from=linphone_core_get_primary_contact(lc);
1769
1770         parsed_url2=linphone_address_new(from);
1771
1772         call=linphone_call_new_outgoing(lc,parsed_url2,real_parsed_url);
1773         sal_op_set_route(call->op,route);
1774
1775         /*try to be best-effort in giving real local or routable contact address,
1776         except when the user choosed to override the ipaddress */
1777         if (linphone_core_get_firewall_policy(lc)!=LINPHONE_POLICY_USE_NAT_ADDRESS)
1778                 contact=get_fixed_contact(lc,call->localip,dest_proxy);
1779         if (contact)
1780                 sal_op_set_contact(call->op, contact);
1781
1782         lc->call=call;
1783
1784         linphone_core_init_media_streams(lc,lc->call);
1785         if (!lc->sip_conf.sdp_200_ack){ 
1786                 sal_call_set_local_media_description(call->op,call->localdesc);
1787         }
1788         err=sal_call(call->op,from,real_url);
1789
1790         barmsg=ortp_strdup_printf("%s %s", _("Contacting"), real_url);
1791         lc->vtable.display_status(lc,barmsg);
1792         ms_free(barmsg);
1793         
1794         if (err<0){
1795                 ms_warning("Could not initiate call.");
1796                 lc->vtable.display_status(lc,_("could not call"));
1797                 linphone_core_stop_media_streams(lc,call);
1798                 linphone_call_destroy(call);
1799                 lc->call=NULL;
1800         }else gstate_new_state(lc, GSTATE_CALL_OUT_INVITE, url);
1801
1802         goto end;
1803         end:
1804                 if (real_url!=NULL) ms_free(real_url);
1805                 if (route!=NULL) ms_free(route);
1806         return (err<0) ? -1 : 0;
1807 }
1808
1809 int linphone_core_refer(LinphoneCore *lc, const char *url)
1810 {
1811         char *real_url=NULL;
1812         LinphoneAddress *real_parsed_url=NULL;
1813         LinphoneCall *call;
1814         char *route;
1815         if (!linphone_core_interpret_url(lc,url,&real_parsed_url, &route)){
1816                 /* bad url */
1817                 return -1;
1818         }
1819         if (route!=NULL) ms_free(route);
1820         call=lc->call;
1821         if (call==NULL){
1822                 ms_warning("No established call to refer.");
1823                 return -1;
1824         }
1825         lc->call=NULL;
1826         real_url=linphone_address_as_string (real_parsed_url);
1827         sal_refer(call->op,real_url);
1828         ms_free(real_url);
1829         return 0;
1830 }
1831
1832 /**
1833  * Returns true if in incoming call is pending, ie waiting for being answered or declined.
1834  *
1835  * @ingroup call_control
1836 **/
1837 bool_t linphone_core_inc_invite_pending(LinphoneCore*lc){
1838         if (lc->call!=NULL && lc->call->dir==LinphoneCallIncoming){
1839                 return TRUE;
1840         }
1841         return FALSE;
1842 }
1843
1844 void linphone_core_init_media_streams(LinphoneCore *lc, LinphoneCall *call){
1845         SalMediaDescription *md=call->localdesc;
1846         lc->audiostream=audio_stream_new(md->streams[0].port,linphone_core_ipv6_enabled(lc));
1847         if (linphone_core_echo_limiter_enabled(lc)){
1848                 const char *type=lp_config_get_string(lc->config,"sound","el_type","mic");
1849                 if (strcasecmp(type,"mic")==0)
1850                         audio_stream_enable_echo_limiter(lc->audiostream,ELControlMic);
1851                 else if (strcasecmp(type,"speaker")==0)
1852                         audio_stream_enable_echo_limiter(lc->audiostream,ELControlSpeaker);
1853         }
1854         audio_stream_enable_gain_control(lc->audiostream,TRUE);
1855         if (linphone_core_echo_cancellation_enabled(lc)){
1856                 int len,delay,framesize;
1857                 len=lp_config_get_int(lc->config,"sound","ec_tail_len",0);
1858                 delay=lp_config_get_int(lc->config,"sound","ec_delay",0);
1859                 framesize=lp_config_get_int(lc->config,"sound","ec_framesize",0);
1860                 audio_stream_set_echo_canceller_params(lc->audiostream,len,delay,framesize);
1861         }
1862         audio_stream_enable_automatic_gain_control(lc->audiostream,linphone_core_agc_enabled(lc));
1863         {
1864                 int enabled=lp_config_get_int(lc->config,"sound","noisegate",0);
1865                 audio_stream_enable_noise_gate(lc->audiostream,enabled);
1866         }
1867         if (lc->a_rtp)
1868                 rtp_session_set_transports(lc->audiostream->session,lc->a_rtp,lc->a_rtcp);
1869
1870 #ifdef VIDEO_ENABLED
1871         if ((lc->video_conf.display || lc->video_conf.capture) && md->streams[1].port>0)
1872                 lc->videostream=video_stream_new(md->streams[1].port,linphone_core_ipv6_enabled(lc));
1873 #else
1874         lc->videostream=NULL;
1875 #endif
1876 }
1877
1878 static void linphone_core_dtmf_received(RtpSession* s, int dtmf, void* user_data){
1879         LinphoneCore* lc = (LinphoneCore*)user_data;
1880         if (lc->vtable.dtmf_received != NULL)
1881                 lc->vtable.dtmf_received(lc, dtmf);
1882 }
1883
1884 static void parametrize_equalizer(LinphoneCore *lc, AudioStream *st){
1885         if (st->equalizer){
1886                 MSFilter *f=st->equalizer;
1887                 int enabled=lp_config_get_int(lc->config,"sound","eq_active",0);
1888                 const char *gains=lp_config_get_string(lc->config,"sound","eq_gains",NULL);
1889                 ms_filter_call_method(f,MS_EQUALIZER_SET_ACTIVE,&enabled);
1890                 if (enabled){
1891                         if (gains){
1892                                 do{
1893                                         int bytes;
1894                                         MSEqualizerGain g;
1895                                         if (sscanf(gains,"%f:%f:%f %n",&g.frequency,&g.gain,&g.width,&bytes)==3){
1896                                                 ms_message("Read equalizer gains: %f(~%f) --> %f",g.frequency,g.width,g.gain);
1897                                                 ms_filter_call_method(f,MS_EQUALIZER_SET_GAIN,&g);
1898                                                 gains+=bytes;
1899                                         }else break;
1900                                 }while(1);
1901                         }
1902                 }
1903         }
1904 }
1905
1906 static void post_configure_audio_streams(LinphoneCore *lc){
1907         AudioStream *st=lc->audiostream;
1908         float gain=lp_config_get_float(lc->config,"sound","mic_gain",-1);
1909         if (gain!=-1)
1910                 audio_stream_set_mic_gain(st,gain);
1911         if (linphone_core_echo_limiter_enabled(lc)){
1912                 float speed=lp_config_get_float(lc->config,"sound","el_speed",-1);
1913                 float thres=lp_config_get_float(lc->config,"sound","el_thres",-1);
1914                 float force=lp_config_get_float(lc->config,"sound","el_force",-1);
1915                 int sustain=lp_config_get_int(lc->config,"sound","el_sustain",-1);
1916                 MSFilter *f=NULL;
1917                 if (st->el_type==ELControlMic){
1918                         f=st->volsend;
1919                         if (speed==-1) speed=0.03;
1920                         if (force==-1) force=10;
1921                 }
1922                 else if (st->el_type==ELControlSpeaker){
1923                         f=st->volrecv;
1924                         if (speed==-1) speed=0.02;
1925                         if (force==-1) force=5;
1926                 }
1927                 if (speed!=-1)
1928                         ms_filter_call_method(f,MS_VOLUME_SET_EA_SPEED,&speed);
1929                 if (thres!=-1)
1930                         ms_filter_call_method(f,MS_VOLUME_SET_EA_THRESHOLD,&thres);
1931                 if (force!=-1)
1932                         ms_filter_call_method(f,MS_VOLUME_SET_EA_FORCE,&force);
1933                 if (sustain!=-1)
1934                         ms_filter_call_method(f,MS_VOLUME_SET_EA_SUSTAIN,&sustain);
1935
1936         }
1937         if (st->volsend){
1938                 float ng_thres=lp_config_get_float(lc->config,"sound","ng_thres",0.05);
1939                 float ng_floorgain=lp_config_get_float(lc->config,"sound","ng_floorgain",0);
1940                 ms_filter_call_method(st->volsend,MS_VOLUME_SET_NOISE_GATE_THRESHOLD,&ng_thres);
1941                 ms_filter_call_method(st->volsend,MS_VOLUME_SET_NOISE_GATE_FLOORGAIN,&ng_floorgain);
1942         }
1943         parametrize_equalizer(lc,st);
1944         if (lc->vtable.dtmf_received!=NULL){
1945                 /* replace by our default action*/
1946                 audio_stream_play_received_dtmfs(lc->audiostream,FALSE);
1947                 rtp_session_signal_connect(lc->audiostream->session,"telephone-event",(RtpCallback)linphone_core_dtmf_received,(unsigned long)lc);
1948         }
1949 }
1950
1951 static RtpProfile *make_profile(LinphoneCore *lc, SalStreamDescription *desc, int *used_pt){
1952         int bw;
1953         MSList *elem;
1954         RtpProfile *prof=rtp_profile_new("Call profile");
1955         bool_t first=TRUE;
1956         if (desc->type==SalAudio){
1957                 bw=get_min_bandwidth(lc->up_audio_bw,desc->bandwidth);
1958         }
1959         else bw=get_min_bandwidth(lc->up_video_bw,desc->bandwidth);
1960         for(elem=desc->payloads;elem!=NULL;elem=elem->next){
1961                 PayloadType *pt=(PayloadType*)elem->data;
1962                 if (bw>0) pt->normal_bitrate=bw*1000;
1963                 else if (desc->type==SalAudio){
1964                         pt->normal_bitrate=-1;
1965                 }
1966                 if (first) {
1967                         *used_pt=payload_type_get_number(pt);
1968                         first=FALSE;
1969                 }
1970                 if (desc->ptime>0){
1971                         char tmp[40];
1972                         snprintf(tmp,sizeof(tmp),"ptime=%i",desc->ptime);
1973                         payload_type_append_send_fmtp(pt,tmp);
1974                 }
1975                 rtp_profile_set_payload(prof,payload_type_get_number(pt),pt);
1976         }
1977         return prof;
1978 }
1979
1980 void linphone_core_start_media_streams(LinphoneCore *lc, LinphoneCall *call){
1981         LinphoneAddress *me=linphone_core_get_primary_contact_parsed(lc);
1982         const char *tool="linphone-" LINPHONE_VERSION;
1983         char *cname;
1984         int used_pt=-1;
1985         /* adjust rtp jitter compensation. It must be at least the latency of the sound card */
1986         int jitt_comp=MAX(lc->sound_conf.latency,lc->rtp_conf.audio_jitt_comp);
1987
1988         if (call->media_start_time==0) call->media_start_time=time(NULL);
1989
1990         cname=linphone_address_as_string_uri_only(me);
1991         {
1992                 SalStreamDescription *stream=sal_media_description_find_stream(call->resultdesc,
1993                                                         SalProtoRtpAvp,SalAudio);
1994                 if (stream){
1995                         call->audio_profile=make_profile(lc,stream,&used_pt);
1996                         if (!lc->use_files){
1997                                 MSSndCard *playcard=lc->sound_conf.play_sndcard;
1998                                 MSSndCard *captcard=lc->sound_conf.capt_sndcard;
1999                                 if (playcard==NULL) {
2000                                         ms_warning("No card defined for playback !");
2001                                         goto end;
2002                                 }
2003                                 if (captcard==NULL) {
2004                                         ms_warning("No card defined for capture !");
2005                                         goto end;
2006                                 }
2007                                 audio_stream_start_now(
2008                                         lc->audiostream,
2009                                         call->audio_profile,
2010                                         stream->addr[0]!='\0' ? stream->addr : call->resultdesc->addr,
2011                                         stream->port,
2012                                         stream->port+1,
2013                                         used_pt,
2014                                         jitt_comp,
2015                                         playcard,
2016                                         captcard,
2017                                         linphone_core_echo_cancellation_enabled(lc));
2018                         }else{
2019                                 audio_stream_start_with_files(
2020                                         lc->audiostream,
2021                                         call->audio_profile,
2022                                         stream->addr[0]!='\0' ? stream->addr : call->resultdesc->addr,
2023                                         stream->port,
2024                                         stream->port+1,
2025                                         used_pt,
2026                                         100,
2027                                         lc->play_file,
2028                                         lc->rec_file);
2029                         }
2030                         post_configure_audio_streams(lc);
2031                         audio_stream_set_rtcp_information(lc->audiostream, cname, tool);
2032                 }else ms_warning("No audio stream defined ?");
2033         }
2034 #ifdef VIDEO_ENABLED
2035         {
2036                 SalStreamDescription *stream=sal_media_description_find_stream(call->resultdesc,
2037                                                         SalProtoRtpAvp,SalVideo);
2038                 /* shutdown preview */
2039                 if (lc->previewstream!=NULL) {
2040                         video_preview_stop(lc->previewstream);
2041                         lc->previewstream=NULL;
2042                 }
2043                 if (stream && (lc->video_conf.display || lc->video_conf.capture)) {
2044                         const char *addr=stream->addr[0]!='\0' ? stream->addr : call->resultdesc->addr;
2045                         call->video_profile=make_profile(lc,stream,&used_pt);
2046                         video_stream_set_sent_video_size(lc->videostream,linphone_core_get_preferred_video_size(lc));
2047                         video_stream_enable_self_view(lc->videostream,lc->video_conf.selfview);
2048                         if (lc->video_conf.display && lc->video_conf.capture)
2049                                 video_stream_start(lc->videostream,
2050                                 call->video_profile, addr, stream->port,
2051                                 stream->port+1,
2052                                 used_pt, jitt_comp, lc->video_conf.device);
2053                         else if (lc->video_conf.display)
2054                                 video_stream_recv_only_start(lc->videostream,
2055                                 call->video_profile, addr, stream->port,
2056                                 used_pt, jitt_comp);
2057                         else if (lc->video_conf.capture)
2058                                 video_stream_send_only_start(lc->videostream,
2059                                 call->video_profile, addr, stream->port,
2060                                 stream->port+1,
2061                                 used_pt, jitt_comp, lc->video_conf.device);
2062                         video_stream_set_rtcp_information(lc->videostream, cname,tool);
2063                 }
2064         }
2065 #endif
2066         goto end;
2067         end:
2068                 ms_free(cname);
2069                 linphone_address_destroy(me);
2070                 lc->call->state=LCStateAVRunning;
2071 }
2072
2073 void linphone_core_stop_media_streams(LinphoneCore *lc, LinphoneCall *call){
2074         if (lc->audiostream!=NULL) {
2075                 audio_stream_stop(lc->audiostream);
2076                 lc->audiostream=NULL;
2077         }
2078 #ifdef VIDEO_ENABLED
2079         if (lc->videostream!=NULL){
2080                 if (lc->video_conf.display && lc->video_conf.capture)
2081                         video_stream_stop(lc->videostream);
2082                 else if (lc->video_conf.display)
2083                         video_stream_recv_only_stop(lc->videostream);
2084                 else if (lc->video_conf.capture)
2085                         video_stream_send_only_stop(lc->videostream);
2086                 lc->videostream=NULL;
2087         }
2088         if (linphone_core_video_preview_enabled(lc)){
2089                 if (lc->previewstream==NULL){
2090                         lc->previewstream=video_preview_start(lc->video_conf.device, lc->video_conf.vsize);
2091                 }
2092         }
2093 #endif
2094         if (call->audio_profile){
2095                 rtp_profile_destroy(call->audio_profile);
2096                 call->audio_profile=NULL;
2097         }
2098         if (call->video_profile){
2099                 rtp_profile_destroy(call->video_profile);
2100                 call->video_profile=NULL;
2101         }
2102 }
2103
2104 /**
2105  * Accept an incoming call.
2106  *
2107  * @ingroup call_control
2108  * Basically the application is notified of incoming calls within the
2109  * invite_recv callback of the #LinphoneCoreVTable structure.
2110  * The application can later respond positively to the call using
2111  * this method.
2112  * @param lc the LinphoneCore object
2113  * @param url the SIP address of the originator of the call, or NULL.
2114  *            This argument is useful for managing multiple calls simulatenously,
2115  *            however this feature is not supported yet.
2116  *            Using NULL will accept the unique incoming call in progress.
2117 **/
2118 int linphone_core_accept_call(LinphoneCore *lc, const char *url)
2119 {
2120         LinphoneCall *call=lc->call;
2121         const char *contact=NULL;
2122         
2123         if (call==NULL){
2124                 return -1;
2125         }
2126
2127         if (call->state==LCStateAVRunning){
2128                 /*call already accepted*/
2129                 return -1;
2130         }
2131
2132         /*stop ringing */
2133         if (lc->ringstream!=NULL) {
2134                 ms_message("stop ringing");
2135                 ring_stop(lc->ringstream);
2136                 ms_message("ring stopped");
2137                 lc->ringstream=NULL;
2138         }
2139         
2140         /*try to be best-effort in giving real local or routable contact address,
2141         except when the user choosed to override the ipaddress */
2142         if (linphone_core_get_firewall_policy(lc)!=LINPHONE_POLICY_USE_NAT_ADDRESS)
2143                 contact=get_fixed_contact(lc,call->localip,NULL);
2144         if (contact)
2145                 sal_op_set_contact(call->op,contact);
2146         
2147         sal_call_accept(call->op);
2148         lc->vtable.display_status(lc,_("Connected."));
2149         gstate_new_state(lc, GSTATE_CALL_IN_CONNECTED, NULL);
2150         call->resultdesc=sal_call_get_final_media_description(call->op);
2151         if (call->resultdesc){
2152                 sal_media_description_ref(call->resultdesc);
2153                 linphone_core_start_media_streams(lc, call);
2154         }
2155         ms_message("call answered.");
2156         return 0;
2157 }
2158
2159 /**
2160  * Terminates a call.
2161  *
2162  * @ingroup call_control
2163  * @param lc The LinphoneCore
2164  * @param url the destination of the call to be terminated, use NULL if there is
2165  *            only one call (which is case in this version of liblinphone).
2166 **/
2167 int linphone_core_terminate_call(LinphoneCore *lc, const char *url)
2168 {
2169         LinphoneCall *call=lc->call;
2170         if (call==NULL){
2171                 return -1;
2172         }
2173         lc->call=NULL;
2174         sal_call_terminate(call->op);
2175
2176         /*stop ringing*/
2177         if (lc->ringstream!=NULL) {
2178                 ring_stop(lc->ringstream);
2179                 lc->ringstream=NULL;
2180         }
2181         linphone_core_stop_media_streams(lc,call);
2182         lc->vtable.display_status(lc,_("Call ended") );
2183         gstate_new_state(lc, GSTATE_CALL_END, NULL);
2184         linphone_call_destroy(call);
2185         return 0;
2186 }
2187
2188 /**
2189  * Returns TRUE if there is a call running or pending.
2190  *
2191  * @ingroup call_control
2192 **/
2193 bool_t linphone_core_in_call(const LinphoneCore *lc){
2194         return lc->call!=NULL;
2195 }
2196
2197 int linphone_core_send_publish(LinphoneCore *lc,
2198                                LinphoneOnlineStatus presence_mode)
2199 {
2200         const MSList *elem;
2201         for (elem=linphone_core_get_proxy_config_list(lc);elem!=NULL;elem=ms_list_next(elem)){
2202                 LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)elem->data;
2203                 if (cfg->publish) linphone_proxy_config_send_publish(cfg,presence_mode);
2204         }
2205         return 0;
2206 }
2207
2208 /**
2209  * Set the incoming call timeout in seconds.
2210  *
2211  * @ingroup call_control
2212  * If an incoming call isn't answered for this timeout period, it is 
2213  * automatically declined.
2214 **/
2215 void linphone_core_set_inc_timeout(LinphoneCore *lc, int seconds){
2216         lc->sip_conf.inc_timeout=seconds;
2217 }
2218
2219 /**
2220  * Returns the incoming call timeout
2221  *
2222  * @ingroup call_control
2223  * See linphone_core_set_inc_timeout() for details.
2224 **/
2225 int linphone_core_get_inc_timeout(LinphoneCore *lc){
2226         return lc->sip_conf.inc_timeout;
2227 }
2228
2229 void linphone_core_set_presence_info(LinphoneCore *lc,int minutes_away,
2230                                                                                                         const char *contact,
2231                                                                                                         LinphoneOnlineStatus presence_mode)
2232 {
2233         if (minutes_away>0) lc->minutes_away=minutes_away;
2234         
2235         if (lc->alt_contact!=NULL) {
2236                 ms_free(lc->alt_contact);
2237                 lc->alt_contact=NULL;
2238         }
2239         if (contact) lc->alt_contact=ms_strdup(contact);
2240         if (lc->presence_mode!=presence_mode){
2241                 linphone_core_notify_all_friends(lc,presence_mode);
2242                 /*
2243                    Improve the use of all LINPHONE_STATUS available.
2244                    !TODO Do not mix "presence status" with "answer status code"..
2245                    Use correct parameter to follow sip_if_match/sip_etag.
2246                  */
2247                 linphone_core_send_publish(lc,presence_mode);
2248         }
2249         lc->prev_mode=lc->presence_mode;
2250         lc->presence_mode=presence_mode;
2251 }
2252
2253 LinphoneOnlineStatus linphone_core_get_presence_info(const LinphoneCore *lc){
2254         return lc->presence_mode;
2255 }
2256
2257 /**
2258  * Get playback sound level in 0-100 scale.
2259  *
2260  * @ingroup media_parameters
2261 **/
2262 int linphone_core_get_play_level(LinphoneCore *lc)
2263 {
2264         return lc->sound_conf.play_lev;
2265 }
2266
2267 /**
2268  * Get ring sound level in 0-100 scale
2269  *
2270  * @ingroup media_parameters
2271 **/
2272 int linphone_core_get_ring_level(LinphoneCore *lc)
2273 {
2274         return lc->sound_conf.ring_lev;
2275 }
2276
2277 /**
2278  * Get sound capture level in 0-100 scale
2279  *
2280  * @ingroup media_parameters
2281 **/
2282 int linphone_core_get_rec_level(LinphoneCore *lc){
2283         return lc->sound_conf.rec_lev;
2284 }
2285
2286 /**
2287  * Set sound ring level in 0-100 scale
2288  *
2289  * @ingroup media_parameters
2290 **/
2291 void linphone_core_set_ring_level(LinphoneCore *lc, int level){
2292         MSSndCard *sndcard;
2293         lc->sound_conf.ring_lev=level;
2294         sndcard=lc->sound_conf.ring_sndcard;
2295         if (sndcard) ms_snd_card_set_level(sndcard,MS_SND_CARD_PLAYBACK,level);
2296 }
2297
2298 /**
2299  * Set sound playback level in 0-100 scale
2300  *
2301  * @ingroup media_parameters
2302 **/
2303 void linphone_core_set_play_level(LinphoneCore *lc, int level){
2304         MSSndCard *sndcard;
2305         lc->sound_conf.play_lev=level;
2306         sndcard=lc->sound_conf.play_sndcard;
2307         if (sndcard) ms_snd_card_set_level(sndcard,MS_SND_CARD_PLAYBACK,level);
2308 }
2309
2310 /**
2311  * Set sound capture level in 0-100 scale
2312  *
2313  * @ingroup media_parameters
2314 **/
2315 void linphone_core_set_rec_level(LinphoneCore *lc, int level)
2316 {
2317         MSSndCard *sndcard;
2318         lc->sound_conf.rec_lev=level;
2319         sndcard=lc->sound_conf.capt_sndcard;
2320         if (sndcard) ms_snd_card_set_level(sndcard,MS_SND_CARD_CAPTURE,level);
2321 }
2322
2323 static MSSndCard *get_card_from_string_id(const char *devid, unsigned int cap){
2324         MSSndCard *sndcard=NULL;
2325         if (devid!=NULL){
2326                 sndcard=ms_snd_card_manager_get_card(ms_snd_card_manager_get(),devid);
2327                 if (sndcard!=NULL &&
2328                         (ms_snd_card_get_capabilities(sndcard) & cap)==0 ){
2329                         ms_warning("%s card does not have the %s capability, ignoring.",
2330                                 devid,
2331                                 cap==MS_SND_CARD_CAP_CAPTURE ? "capture" : "playback");
2332                         sndcard=NULL;
2333                 }
2334         }
2335         if (sndcard==NULL) {
2336                 /* get a card that has read+write capabilities */
2337                 sndcard=ms_snd_card_manager_get_default_card(ms_snd_card_manager_get());
2338                 /* otherwise refine to the first card having the right capability*/
2339                 if (sndcard==NULL){
2340                         const MSList *elem=ms_snd_card_manager_get_list(ms_snd_card_manager_get());
2341                         for(;elem!=NULL;elem=elem->next){
2342                                 sndcard=(MSSndCard*)elem->data;
2343                                 if (ms_snd_card_get_capabilities(sndcard) & cap) break;
2344                         }
2345                 }
2346                 if (sndcard==NULL){/*looks like a bug! take the first one !*/
2347                         const MSList *elem=ms_snd_card_manager_get_list(ms_snd_card_manager_get());
2348                         sndcard=(MSSndCard*)elem->data;
2349                 }
2350         }
2351         if (sndcard==NULL) ms_error("Could not find a suitable soundcard !");
2352         return sndcard;
2353 }
2354
2355 /**
2356  * Returns true if the specified sound device can capture sound.
2357  *
2358  * @ingroup media_parameters
2359  * @param devid the device name as returned by linphone_core_get_sound_devices()
2360 **/
2361 bool_t linphone_core_sound_device_can_capture(LinphoneCore *lc, const char *devid){
2362         MSSndCard *sndcard;
2363         sndcard=ms_snd_card_manager_get_card(ms_snd_card_manager_get(),devid);
2364         if (sndcard!=NULL && (ms_snd_card_get_capabilities(sndcard) & MS_SND_CARD_CAP_CAPTURE)) return TRUE;
2365         return FALSE;
2366 }
2367
2368 /**
2369  * Returns true if the specified sound device can play sound.
2370  *
2371  * @ingroup media_parameters
2372  * @param devid the device name as returned by linphone_core_get_sound_devices()
2373 **/
2374 bool_t linphone_core_sound_device_can_playback(LinphoneCore *lc, const char *devid){
2375         MSSndCard *sndcard;
2376         sndcard=ms_snd_card_manager_get_card(ms_snd_card_manager_get(),devid);
2377         if (sndcard!=NULL && (ms_snd_card_get_capabilities(sndcard) & MS_SND_CARD_CAP_PLAYBACK)) return TRUE;
2378         return FALSE;
2379 }
2380
2381 /**
2382  * Sets the sound device used for ringing.
2383  *
2384  * @ingroup media_parameters
2385  * @param devid the device name as returned by linphone_core_get_sound_devices()
2386 **/
2387 int linphone_core_set_ringer_device(LinphoneCore *lc, const char * devid){
2388         MSSndCard *card=get_card_from_string_id(devid,MS_SND_CARD_CAP_PLAYBACK);
2389         lc->sound_conf.ring_sndcard=card;
2390         if (card && lc->ready)
2391                 lp_config_set_string(lc->config,"sound","ringer_dev_id",ms_snd_card_get_string_id(card));
2392         return 0;
2393 }
2394
2395 /**
2396  * Sets the sound device used for playback.
2397  *
2398  * @ingroup media_parameters
2399  * @param devid the device name as returned by linphone_core_get_sound_devices()
2400 **/
2401 int linphone_core_set_playback_device(LinphoneCore *lc, const char * devid){
2402         MSSndCard *card=get_card_from_string_id(devid,MS_SND_CARD_CAP_PLAYBACK);
2403         lc->sound_conf.play_sndcard=card;
2404         if (card && lc->ready)
2405                 lp_config_set_string(lc->config,"sound","playback_dev_id",ms_snd_card_get_string_id(card));
2406         return 0;
2407 }
2408
2409 /**
2410  * Sets the sound device used for capture.
2411  *
2412  * @ingroup media_parameters
2413  * @param devid the device name as returned by linphone_core_get_sound_devices()
2414 **/
2415 int linphone_core_set_capture_device(LinphoneCore *lc, const char * devid){
2416         MSSndCard *card=get_card_from_string_id(devid,MS_SND_CARD_CAP_CAPTURE);
2417         lc->sound_conf.capt_sndcard=card;
2418         if (card && lc->ready)
2419                 lp_config_set_string(lc->config,"sound","capture_dev_id",ms_snd_card_get_string_id(card));
2420         return 0;
2421 }
2422
2423 /**
2424  * Returns the name of the currently assigned sound device for ringing.
2425  *
2426  * @ingroup media_parameters
2427 **/
2428 const char * linphone_core_get_ringer_device(LinphoneCore *lc)
2429 {
2430         if (lc->sound_conf.ring_sndcard) return ms_snd_card_get_string_id(lc->sound_conf.ring_sndcard);
2431         return NULL;
2432 }
2433
2434 /**
2435  * Returns the name of the currently assigned sound device for playback.
2436  *
2437  * @ingroup media_parameters
2438 **/
2439 const char * linphone_core_get_playback_device(LinphoneCore *lc)
2440 {
2441         return lc->sound_conf.play_sndcard ? ms_snd_card_get_string_id(lc->sound_conf.play_sndcard) : NULL;
2442 }
2443
2444 /**
2445  * Returns the name of the currently assigned sound device for capture.
2446  *
2447  * @ingroup media_parameters
2448 **/
2449 const char * linphone_core_get_capture_device(LinphoneCore *lc)
2450 {
2451         return lc->sound_conf.capt_sndcard ? ms_snd_card_get_string_id(lc->sound_conf.capt_sndcard) : NULL;
2452 }
2453
2454 /**
2455  * Returns an unmodifiable array of available sound devices.
2456  *
2457  * @ingroup media_parameters
2458  * The array is NULL terminated.
2459 **/
2460 const char**  linphone_core_get_sound_devices(LinphoneCore *lc){
2461         build_sound_devices_table(lc);
2462         return lc->sound_conf.cards;
2463 }
2464
2465 /**
2466  * Returns an unmodifiable array of available video capture devices.
2467  *
2468  * @ingroup media_parameters
2469  * The array is NULL terminated.
2470 **/
2471 const char**  linphone_core_get_video_devices(const LinphoneCore *lc){
2472         return lc->video_conf.cams;
2473 }
2474
2475 char linphone_core_get_sound_source(LinphoneCore *lc)
2476 {
2477         return lc->sound_conf.source;
2478 }
2479
2480 void linphone_core_set_sound_source(LinphoneCore *lc, char source)
2481 {
2482         MSSndCard *sndcard=lc->sound_conf.capt_sndcard;
2483         lc->sound_conf.source=source;
2484         if (!sndcard) return;
2485         switch(source){
2486                 case 'm':
2487                         ms_snd_card_set_capture(sndcard,MS_SND_CARD_MIC);
2488                         break;
2489                 case 'l':
2490                         ms_snd_card_set_capture(sndcard,MS_SND_CARD_LINE);
2491                         break;
2492         }
2493
2494 }
2495
2496
2497 /**
2498  * Sets the path to a wav file used for ringing.
2499  *
2500  * The file must be a wav 16bit linear.
2501  *
2502  * @ingroup media_parameters
2503 **/
2504 void linphone_core_set_ring(LinphoneCore *lc,const char *path){
2505         if (lc->sound_conf.local_ring!=0){
2506                 ms_free(lc->sound_conf.local_ring);
2507         }
2508         lc->sound_conf.local_ring=ms_strdup(path);
2509         if (lc->ready && lc->sound_conf.local_ring)
2510                 lp_config_set_string(lc->config,"sound","local_ring",lc->sound_conf.local_ring);
2511 }
2512
2513 /**
2514  * Returns the path to the wav file used for ringing.
2515  *
2516  * @ingroup media_parameters
2517 **/
2518 const char *linphone_core_get_ring(const LinphoneCore *lc){
2519         return lc->sound_conf.local_ring;
2520 }
2521
2522 static void notify_end_of_ring(void *ud ,unsigned int event, void * arg){
2523         LinphoneCore *lc=(LinphoneCore*)ud;
2524         lc->preview_finished=1;
2525 }
2526
2527 int linphone_core_preview_ring(LinphoneCore *lc, const char *ring,LinphoneCoreCbFunc func,void * userdata)
2528 {
2529         if (lc->ringstream!=0){
2530                 ms_warning("Cannot start ring now,there's already a ring being played");
2531                 return -1;
2532         }
2533         lc_callback_obj_init(&lc->preview_finished_cb,func,userdata);
2534         lc->preview_finished=0;
2535         if (lc->sound_conf.ring_sndcard!=NULL){
2536                 lc->ringstream=ring_start_with_cb(ring,2000,lc->sound_conf.ring_sndcard,notify_end_of_ring,(void *)lc);
2537         }
2538         return 0;
2539 }
2540
2541 /**
2542  * Sets the path to a wav file used for ringing back.
2543  *
2544  * Ringback means the ring that is heard when it's ringing at the remote party.
2545  * The file must be a wav 16bit linear.
2546  *
2547  * @ingroup media_parameters
2548 **/
2549 void linphone_core_set_ringback(LinphoneCore *lc, const char *path){
2550         if (lc->sound_conf.remote_ring!=0){
2551                 ms_free(lc->sound_conf.remote_ring);
2552         }
2553         lc->sound_conf.remote_ring=ms_strdup(path);
2554 }
2555
2556 /**
2557  * Returns the path to the wav file used for ringing back.
2558  *
2559  * @ingroup media_parameters
2560 **/
2561 const char * linphone_core_get_ringback(const LinphoneCore *lc){
2562         return lc->sound_conf.remote_ring;
2563 }
2564
2565 /**
2566  * Enables or disable echo cancellation.
2567  *
2568  * @ingroup media_parameters
2569 **/
2570 void linphone_core_enable_echo_cancellation(LinphoneCore *lc, bool_t val){
2571         lc->sound_conf.ec=val;
2572         if (lc->ready)
2573                 lp_config_set_int(lc->config,"sound","echocancellation",val);
2574 }
2575
2576 /**
2577  * Returns TRUE if echo cancellation is enabled.
2578  *
2579  * @ingroup media_parameters
2580 **/
2581 bool_t linphone_core_echo_cancellation_enabled(LinphoneCore *lc){
2582         return lc->sound_conf.ec;
2583 }
2584
2585 void linphone_core_enable_echo_limiter(LinphoneCore *lc, bool_t val){
2586         lc->sound_conf.ea=val;
2587 }
2588
2589 bool_t linphone_core_echo_limiter_enabled(const LinphoneCore *lc){
2590         return lc->sound_conf.ea;
2591 }
2592
2593 /**
2594  * Mutes or unmutes the local microphone.
2595  *
2596  * @ingroup media_parameters
2597 **/
2598 void linphone_core_mute_mic(LinphoneCore *lc, bool_t val){
2599         if (lc->audiostream!=NULL){
2600                  audio_stream_set_mic_gain(lc->audiostream,
2601                         (val==TRUE) ? 0 : 1.0);
2602         }
2603 }
2604
2605 void linphone_core_enable_agc(LinphoneCore *lc, bool_t val){
2606         lc->sound_conf.agc=val;
2607 }
2608
2609 bool_t linphone_core_agc_enabled(const LinphoneCore *lc){
2610         return lc->sound_conf.agc;
2611 }
2612
2613 /**
2614  * Send the specified dtmf.
2615  *
2616  * @ingroup media_parameters
2617  * This function only works during calls. The dtmf is automatically played to the user.
2618  * @param lc The LinphoneCore object
2619  * @param dtmf The dtmf name specified as a char, such as '0', '#' etc...
2620  *
2621 **/
2622 void linphone_core_send_dtmf(LinphoneCore *lc, char dtmf)
2623 {
2624         /*By default we send DTMF RFC2833 if we do not have enabled SIP_INFO but we can also send RFC2833 and SIP_INFO*/
2625         if (linphone_core_get_use_rfc2833_for_dtmf(lc)!=0 || linphone_core_get_use_info_for_dtmf(lc)==0)
2626         {
2627                 /* In Band DTMF */
2628                 if (lc->audiostream!=NULL){
2629                         audio_stream_send_dtmf(lc->audiostream,dtmf);
2630                 }
2631                 else
2632                 {
2633                         ms_error("we cannot send RFC2833 dtmf when we are not in communication");
2634                 }
2635         }
2636         if (linphone_core_get_use_info_for_dtmf(lc)!=0){
2637                 /* Out of Band DTMF (use INFO method) */
2638                 LinphoneCall *call=lc->call;
2639                 if (call==NULL){
2640                         return;
2641                 }
2642                 sal_call_send_dtmf(call->op,dtmf);
2643         }
2644 }
2645
2646 void linphone_core_set_stun_server(LinphoneCore *lc, const char *server){
2647         if (lc->net_conf.stun_server!=NULL)
2648                 ms_free(lc->net_conf.stun_server);
2649         if (server)
2650                 lc->net_conf.stun_server=ms_strdup(server);
2651         else lc->net_conf.stun_server=NULL;
2652         lc->apply_nat_settings=TRUE;
2653 }
2654
2655 const char * linphone_core_get_stun_server(const LinphoneCore *lc){
2656         return lc->net_conf.stun_server;
2657 }
2658
2659 const char * linphone_core_get_relay_addr(const LinphoneCore *lc){
2660         return lc->net_conf.relay;
2661 }
2662
2663 int linphone_core_set_relay_addr(LinphoneCore *lc, const char *addr){
2664         if (lc->net_conf.relay!=NULL){
2665                 ms_free(lc->net_conf.relay);
2666                 lc->net_conf.relay=NULL;
2667         }
2668         if (addr){
2669                 lc->net_conf.relay=ms_strdup(addr);
2670         }
2671         return 0;
2672 }
2673
2674 static void apply_nat_settings(LinphoneCore *lc){
2675         char *wmsg;
2676         char *tmp=NULL;
2677         int err;
2678         struct addrinfo hints,*res;
2679         const char *addr=lc->net_conf.nat_address;
2680
2681         if (lc->net_conf.firewall_policy==LINPHONE_POLICY_USE_NAT_ADDRESS){
2682                 if (addr==NULL || strlen(addr)==0){
2683                         lc->vtable.display_warning(lc,_("No nat/firewall address supplied !"));
2684                         linphone_core_set_firewall_policy(lc,LINPHONE_POLICY_NO_FIREWALL);
2685                 }
2686                 /*check the ip address given */
2687                 memset(&hints,0,sizeof(struct addrinfo));
2688                 if (lc->sip_conf.ipv6_enabled)
2689                         hints.ai_family=AF_INET6;
2690                 else
2691                         hints.ai_family=AF_INET;
2692                 hints.ai_socktype = SOCK_DGRAM;
2693                 err=getaddrinfo(addr,NULL,&hints,&res);
2694                 if (err!=0){
2695                         wmsg=ortp_strdup_printf(_("Invalid nat address '%s' : %s"),
2696                                 addr, gai_strerror(err));
2697                         ms_warning(wmsg); // what is this for ?
2698                         lc->vtable.display_warning(lc, wmsg);
2699                         ms_free(wmsg);
2700                         linphone_core_set_firewall_policy(lc,LINPHONE_POLICY_NO_FIREWALL);
2701                         return;
2702                 }
2703                 /*now get it as an numeric ip address */
2704                 tmp=ms_malloc0(50);
2705                 err=getnameinfo(res->ai_addr,res->ai_addrlen,tmp,50,NULL,0,NI_NUMERICHOST);
2706                 if (err!=0){
2707                         wmsg=ortp_strdup_printf(_("Invalid nat address '%s' : %s"),
2708                                 addr, gai_strerror(err));
2709                         ms_warning("%s",wmsg); // what is this for ?
2710                         lc->vtable.display_warning(lc, wmsg);
2711                         ms_free(wmsg);
2712                         ms_free(tmp);
2713                         freeaddrinfo(res);
2714                         linphone_core_set_firewall_policy(lc,LINPHONE_POLICY_NO_FIREWALL);
2715                         return;
2716                 }
2717                 freeaddrinfo(res);
2718         }
2719
2720         if (lc->net_conf.firewall_policy==LINPHONE_POLICY_USE_NAT_ADDRESS){
2721                 if (tmp!=NULL){
2722                         if (!lc->net_conf.nat_sdp_only){
2723                                 sal_masquerade(lc->sal,tmp);
2724                         }
2725                         ms_free(tmp);
2726                 }
2727                 else{
2728                         sal_masquerade(lc->sal,NULL);
2729                 }
2730         }
2731         else {
2732                 sal_masquerade(lc->sal,NULL);
2733         }
2734 }
2735
2736
2737 void linphone_core_set_nat_address(LinphoneCore *lc, const char *addr)
2738 {
2739         if (lc->net_conf.nat_address!=NULL){
2740                 ms_free(lc->net_conf.nat_address);
2741         }
2742         if (addr!=NULL) lc->net_conf.nat_address=ms_strdup(addr);
2743         else lc->net_conf.nat_address=NULL;
2744         lc->apply_nat_settings=TRUE;
2745 }
2746
2747 const char *linphone_core_get_nat_address(const LinphoneCore *lc)
2748 {
2749         return lc->net_conf.nat_address;
2750 }
2751
2752 void linphone_core_set_firewall_policy(LinphoneCore *lc, LinphoneFirewallPolicy pol){
2753         lc->net_conf.firewall_policy=pol;
2754         lc->apply_nat_settings=TRUE;
2755 }
2756
2757 LinphoneFirewallPolicy linphone_core_get_firewall_policy(const LinphoneCore *lc){
2758         return lc->net_conf.firewall_policy;
2759 }
2760
2761 /**
2762  * Get the list of call logs (past calls).
2763  *
2764  * @ingroup call_logs
2765 **/
2766 const MSList * linphone_core_get_call_logs(LinphoneCore *lc){
2767         lc->missed_calls=0;
2768         return lc->call_logs;
2769 }
2770
2771 /**
2772  * Erase the call log.
2773  *
2774  * @ingroup call_logs
2775 **/
2776 void linphone_core_clear_call_logs(LinphoneCore *lc){
2777         lc->missed_calls=0;
2778         ms_list_for_each(lc->call_logs,(void (*)(void*))linphone_call_log_destroy);
2779         lc->call_logs=ms_list_free(lc->call_logs);
2780         call_logs_write_to_config_file(lc);
2781 }
2782
2783 static void toggle_video_preview(LinphoneCore *lc, bool_t val){
2784 #ifdef VIDEO_ENABLED
2785         if (lc->videostream==NULL){
2786                 if (val){
2787                         if (lc->previewstream==NULL){
2788                                 lc->previewstream=video_preview_start(lc->video_conf.device,
2789                                                         lc->video_conf.vsize);
2790                         }
2791                 }else{
2792                         if (lc->previewstream!=NULL){
2793                                 video_preview_stop(lc->previewstream);
2794                                 lc->previewstream=NULL;
2795                         }
2796                 }
2797         }
2798 #endif
2799 }
2800
2801 /**
2802  * Enables video globally.
2803  *
2804  * @ingroup media_parameters
2805  * This function does not have any effect during calls. It just indicates LinphoneCore to
2806  * initiate future calls with video or not. The two boolean parameters indicate in which
2807  * direction video is enabled. Setting both to false disables video entirely.
2808  *
2809  * @param vcap_enabled indicates whether video capture is enabled
2810  * @param display_enabled indicates whether video display should be shown
2811  *
2812 **/
2813 void linphone_core_enable_video(LinphoneCore *lc, bool_t vcap_enabled, bool_t display_enabled){
2814 #ifndef VIDEO_ENABLED
2815         if (vcap_enabled || display_enabled)
2816                 ms_warning("This version of linphone was built without video support.");
2817 #endif
2818         lc->video_conf.capture=vcap_enabled;
2819         lc->video_conf.display=display_enabled;
2820
2821         /* need to re-apply network bandwidth settings*/
2822         linphone_core_set_download_bandwidth(lc,
2823                 linphone_core_get_download_bandwidth(lc));
2824         linphone_core_set_upload_bandwidth(lc,
2825                 linphone_core_get_upload_bandwidth(lc));
2826 }
2827
2828 /**
2829  * Returns TRUE if video is enabled, FALSE otherwise.
2830  * @ingroup media_parameters
2831 **/
2832 bool_t linphone_core_video_enabled(LinphoneCore *lc){
2833         return (lc->video_conf.display || lc->video_conf.capture);
2834 }
2835
2836 /**
2837  * Controls video preview enablement.
2838  *
2839  * @ingroup media_parameters
2840  * Video preview refers to the action of displaying the local webcam image
2841  * to the user while not in call.
2842 **/
2843 void linphone_core_enable_video_preview(LinphoneCore *lc, bool_t val){
2844         lc->video_conf.show_local=val;
2845 }
2846
2847 /**
2848  * Returns TRUE if video previewing is enabled.
2849  * @ingroup media_parameters
2850 **/
2851 bool_t linphone_core_video_preview_enabled(const LinphoneCore *lc){
2852         return lc->video_conf.show_local;
2853 }
2854
2855 /**
2856  * Enables or disable self view during calls.
2857  *
2858  * @ingroup media_parameters
2859  * Self-view refers to having local webcam image inserted in corner
2860  * of the video window during calls.
2861  * This function works at any time, including during calls.
2862 **/
2863 void linphone_core_enable_self_view(LinphoneCore *lc, bool_t val){
2864         lc->video_conf.selfview=val;
2865 #ifdef VIDEO_ENABLED
2866         if (lc->videostream){
2867                 video_stream_enable_self_view(lc->videostream,val);
2868         }
2869 #endif
2870 }
2871
2872 /**
2873  * Returns TRUE if self-view is enabled, FALSE otherwise.
2874  *
2875  * @ingroup media_parameters
2876  *
2877  * Refer to linphone_core_enable_self_view() for details.
2878 **/
2879 bool_t linphone_core_self_view_enabled(const LinphoneCore *lc){
2880         return lc->video_conf.selfview;
2881 }
2882
2883 /**
2884  * Sets the active video device.
2885  *
2886  * @ingroup media_parameters
2887  * @param id the name of the video device as returned by linphone_core_get_video_devices()
2888 **/
2889 int linphone_core_set_video_device(LinphoneCore *lc, const char *id){
2890         MSWebCam *olddev=lc->video_conf.device;
2891         const char *vd;
2892         if (id!=NULL){
2893                 lc->video_conf.device=ms_web_cam_manager_get_cam(ms_web_cam_manager_get(),id);
2894                 if (lc->video_conf.device==NULL){
2895                         ms_warning("Could not found video device %s",id);
2896                 }
2897         }
2898         if (lc->video_conf.device==NULL)
2899                 lc->video_conf.device=ms_web_cam_manager_get_default_cam(ms_web_cam_manager_get());
2900         if (olddev!=NULL && olddev!=lc->video_conf.device){
2901                 toggle_video_preview(lc,FALSE);/*restart the video local preview*/
2902         }
2903         if (lc->ready && lc->video_conf.device){
2904                 vd=ms_web_cam_get_string_id(lc->video_conf.device);
2905                 if (vd && strstr(vd,"Static picture")!=NULL){
2906                         vd=NULL;
2907                 }
2908                 lp_config_set_string(lc->config,"video","device",vd);
2909         }
2910         return 0;
2911 }
2912
2913 /**
2914  * Returns the name of the currently active video device.
2915  *
2916  * @ingroup media_parameters
2917 **/
2918 const char *linphone_core_get_video_device(const LinphoneCore *lc){
2919         if (lc->video_conf.device) return ms_web_cam_get_string_id(lc->video_conf.device);
2920         return NULL;
2921 }
2922
2923 /**
2924  * Returns the native window handle of the video window, casted as an unsigned long.
2925  *
2926  * @ingroup media_parameters
2927 **/
2928 unsigned long linphone_core_get_native_video_window_id(const LinphoneCore *lc){
2929 #ifdef VIDEO_ENABLED
2930         if (lc->videostream)
2931                 return video_stream_get_native_window_id(lc->videostream);
2932         if (lc->previewstream)
2933                 return video_stream_get_native_window_id(lc->previewstream);
2934 #endif
2935         return 0;
2936 }
2937
2938 static MSVideoSizeDef supported_resolutions[]={
2939         {       {MS_VIDEO_SIZE_SVGA_W,MS_VIDEO_SIZE_SVGA_H}     ,       "svga"  },
2940         {       {MS_VIDEO_SIZE_4CIF_W,MS_VIDEO_SIZE_4CIF_H}     ,       "4cif"  },
2941         {       {MS_VIDEO_SIZE_VGA_W,MS_VIDEO_SIZE_VGA_H}       ,       "vga"   },
2942         {       {MS_VIDEO_SIZE_CIF_W,MS_VIDEO_SIZE_CIF_H}       ,       "cif"   },
2943         {       {MS_VIDEO_SIZE_QVGA_W,MS_VIDEO_SIZE_QVGA_H}     ,       "qvga"  },
2944         {       {MS_VIDEO_SIZE_QCIF_W,MS_VIDEO_SIZE_QCIF_H}     ,       "qcif"  },
2945         {       {0,0}                   ,       NULL    }
2946 };
2947
2948 /**
2949  * Returns the zero terminated table of supported video resolutions.
2950  *
2951  * @ingroup media_parameters
2952 **/
2953 const MSVideoSizeDef *linphone_core_get_supported_video_sizes(LinphoneCore *lc){
2954         return supported_resolutions;
2955 }
2956
2957 static MSVideoSize video_size_get_by_name(const char *name){
2958         MSVideoSizeDef *pdef=supported_resolutions;
2959         MSVideoSize null_vsize={0,0};
2960         for(;pdef->name!=NULL;pdef++){
2961                 if (strcasecmp(name,pdef->name)==0){
2962                         return pdef->vsize;
2963                 }
2964         }
2965         ms_warning("Video resolution %s is not supported in linphone.",name);
2966         return null_vsize;
2967 }
2968
2969 static const char *video_size_get_name(MSVideoSize vsize){
2970         MSVideoSizeDef *pdef=supported_resolutions;
2971         for(;pdef->name!=NULL;pdef++){
2972                 if (pdef->vsize.width==vsize.width && pdef->vsize.height==vsize.height){
2973                         return pdef->name;
2974                 }
2975         }
2976         return NULL;
2977 }
2978
2979 static bool_t video_size_supported(MSVideoSize vsize){
2980         if (video_size_get_name(vsize)) return TRUE;
2981         ms_warning("Video resolution %ix%i is not supported in linphone.",vsize.width,vsize.height);
2982         return FALSE;
2983 }
2984
2985 /**
2986  * Sets the preferred video size.
2987  *
2988  * @ingroup media_parameters
2989  * This applies only to the stream that is captured and sent to the remote party,
2990  * since we accept all standart video size on the receive path.
2991 **/
2992 void linphone_core_set_preferred_video_size(LinphoneCore *lc, MSVideoSize vsize){
2993         if (video_size_supported(vsize)){
2994                 MSVideoSize oldvsize=lc->video_conf.vsize;
2995                 lc->video_conf.vsize=vsize;
2996                 if (!ms_video_size_equal(oldvsize,vsize) && lc->previewstream!=NULL){
2997                         toggle_video_preview(lc,FALSE);
2998                         toggle_video_preview(lc,TRUE);
2999                 }
3000                 if (lc->ready)
3001                         lp_config_set_string(lc->config,"video","size",video_size_get_name(vsize));
3002         }
3003 }
3004
3005 /**
3006  * Sets the preferred video size by its name.
3007  *
3008  * @ingroup media_parameters
3009  * This is identical to linphone_core_set_preferred_video_size() except
3010  * that it takes the name of the video resolution as input.
3011  * Video resolution names are: qcif, svga, cif, vga, 4cif, svga ...
3012 **/
3013 void linphone_core_set_preferred_video_size_by_name(LinphoneCore *lc, const char *name){
3014         MSVideoSize vsize=video_size_get_by_name(name);
3015         MSVideoSize default_vsize={MS_VIDEO_SIZE_CIF_W,MS_VIDEO_SIZE_CIF_H};
3016         if (vsize.width!=0)     linphone_core_set_preferred_video_size(lc,vsize);
3017         else linphone_core_set_preferred_video_size(lc,default_vsize);
3018 }
3019
3020 /**
3021  * Returns the current preferred video size for sending.
3022  *
3023  * @ingroup media_parameters
3024 **/
3025 MSVideoSize linphone_core_get_preferred_video_size(LinphoneCore *lc){
3026         return lc->video_conf.vsize;
3027 }
3028
3029 void linphone_core_use_files(LinphoneCore *lc, bool_t yesno){
3030         lc->use_files=yesno;
3031 }
3032
3033 void linphone_core_set_play_file(LinphoneCore *lc, const char *file){
3034         if (lc->play_file!=NULL){
3035                 ms_free(lc->play_file);
3036                 lc->play_file=NULL;
3037         }
3038         if (file!=NULL) {
3039                 lc->play_file=ms_strdup(file);
3040                 if (lc->audiostream)
3041                         audio_stream_play(lc->audiostream,file);
3042         }
3043 }
3044
3045 void linphone_core_set_record_file(LinphoneCore *lc, const char *file){
3046         if (lc->rec_file!=NULL){
3047                 ms_free(lc->rec_file);
3048                 lc->rec_file=NULL;
3049         }
3050         if (file!=NULL) {
3051                 lc->rec_file=ms_strdup(file);
3052                 if (lc->audiostream)
3053                         audio_stream_record(lc->audiostream,file);
3054         }
3055 }
3056
3057 /**
3058  * Retrieves the user pointer that was given to linphone_core_new()
3059  *
3060  * @ingroup initializing
3061 **/
3062 void *linphone_core_get_user_data(LinphoneCore *lc){
3063         return lc->data;
3064 }
3065
3066 int linphone_core_get_mtu(const LinphoneCore *lc){
3067         return lc->net_conf.mtu;
3068 }
3069
3070 void linphone_core_set_mtu(LinphoneCore *lc, int mtu){
3071         lc->net_conf.mtu=mtu;
3072         if (mtu>0){
3073                 if (mtu<500){
3074                         ms_error("MTU too small !");
3075                         mtu=500;
3076                 }
3077                 ms_set_mtu(mtu);
3078                 ms_message("MTU is supposed to be %i, rtp payload max size will be %i",mtu, ms_get_payload_max_size());
3079         }else ms_set_mtu(0);//use mediastreamer2 default value
3080 }
3081
3082 void linphone_core_set_waiting_callback(LinphoneCore *lc, LinphoneWaitingCallback cb, void *user_context){
3083         lc->wait_cb=cb;
3084         lc->wait_ctx=user_context;
3085 }
3086
3087 void linphone_core_start_waiting(LinphoneCore *lc, const char *purpose){
3088         if (lc->wait_cb){
3089                 lc->wait_ctx=lc->wait_cb(lc,lc->wait_ctx,LinphoneWaitingStart,purpose,0);
3090         }
3091 }
3092
3093 void linphone_core_update_progress(LinphoneCore *lc, const char *purpose, float progress){
3094         if (lc->wait_cb){
3095                 lc->wait_ctx=lc->wait_cb(lc,lc->wait_ctx,LinphoneWaitingProgress,purpose,progress);
3096         }else{
3097 #ifdef WIN32
3098                 Sleep(50000);
3099 #else
3100                 usleep(50000);
3101 #endif
3102         }
3103 }
3104
3105 void linphone_core_stop_waiting(LinphoneCore *lc){
3106         if (lc->wait_cb){
3107                 lc->wait_ctx=lc->wait_cb(lc,lc->wait_ctx,LinphoneWaitingFinished,NULL,0);
3108         }
3109 }
3110
3111 void linphone_core_set_audio_transports(LinphoneCore *lc, RtpTransport *rtp, RtpTransport *rtcp){
3112         lc->a_rtp=rtp;
3113         lc->a_rtcp=rtcp;
3114 }
3115
3116 void net_config_uninit(LinphoneCore *lc)
3117 {
3118         net_config_t *config=&lc->net_conf;
3119         lp_config_set_int(lc->config,"net","download_bw",config->download_bw);
3120         lp_config_set_int(lc->config,"net","upload_bw",config->upload_bw);
3121
3122         if (config->stun_server!=NULL)
3123                 lp_config_set_string(lc->config,"net","stun_server",config->stun_server);
3124         if (config->nat_address!=NULL)
3125                 lp_config_set_string(lc->config,"net","nat_address",config->nat_address);
3126         lp_config_set_int(lc->config,"net","firewall_policy",config->firewall_policy);
3127         lp_config_set_int(lc->config,"net","mtu",config->mtu);
3128         if (lc->net_conf.stun_server!=NULL)
3129                 ms_free(lc->net_conf.stun_server);
3130 }
3131
3132
3133 void sip_config_uninit(LinphoneCore *lc)
3134 {
3135         MSList *elem;
3136         int i;
3137         sip_config_t *config=&lc->sip_conf;
3138         lp_config_set_int(lc->config,"sip","sip_port",config->sip_port);
3139         lp_config_set_int(lc->config,"sip","guess_hostname",config->guess_hostname);
3140         lp_config_set_string(lc->config,"sip","contact",config->contact);
3141         lp_config_set_int(lc->config,"sip","inc_timeout",config->inc_timeout);
3142         lp_config_set_int(lc->config,"sip","use_info",config->use_info);
3143         lp_config_set_int(lc->config,"sip","use_rfc2833",config->use_rfc2833);
3144         lp_config_set_int(lc->config,"sip","use_ipv6",config->ipv6_enabled);
3145         lp_config_set_int(lc->config,"sip","register_only_when_network_is_up",config->register_only_when_network_is_up);
3146         for(elem=config->proxies,i=0;elem!=NULL;elem=ms_list_next(elem),i++){
3147                 LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)(elem->data);
3148                 linphone_proxy_config_write_to_config_file(lc->config,cfg,i);
3149                 linphone_proxy_config_edit(cfg);        /* to unregister */
3150         }
3151
3152         if (lc->sal){
3153             int i;
3154                 for (i=0;i<20;i++){
3155                         sal_iterate(lc->sal);
3156 #ifndef WIN32
3157                         usleep(100000);
3158 #else
3159                         Sleep(100);
3160 #endif
3161                 }
3162         }
3163
3164         linphone_proxy_config_write_to_config_file(lc->config,NULL,i);  /*mark the end */
3165
3166         for(elem=lc->auth_info,i=0;elem!=NULL;elem=ms_list_next(elem),i++){
3167                 LinphoneAuthInfo *ai=(LinphoneAuthInfo*)(elem->data);
3168                 linphone_auth_info_write_config(lc->config,ai,i);
3169         }
3170         linphone_auth_info_write_config(lc->config,NULL,i); /* mark the end */
3171         sal_uninit(lc->sal);
3172         lc->sal=NULL;
3173 }
3174
3175 void rtp_config_uninit(LinphoneCore *lc)
3176 {
3177         rtp_config_t *config=&lc->rtp_conf;
3178         lp_config_set_int(lc->config,"rtp","audio_rtp_port",config->audio_rtp_port);
3179         lp_config_set_int(lc->config,"rtp","video_rtp_port",config->video_rtp_port);
3180         lp_config_set_int(lc->config,"rtp","audio_jitt_comp",config->audio_jitt_comp);
3181         lp_config_set_int(lc->config,"rtp","video_jitt_comp",config->video_jitt_comp);
3182         lp_config_set_int(lc->config,"rtp","nortp_timeout",config->nortp_timeout);
3183 }
3184
3185 void sound_config_uninit(LinphoneCore *lc)
3186 {
3187         sound_config_t *config=&lc->sound_conf;
3188         ms_free(config->cards);
3189
3190         lp_config_set_string(lc->config,"sound","remote_ring",config->remote_ring);
3191
3192         if (config->local_ring) ms_free(config->local_ring);
3193         if (config->remote_ring) ms_free(config->remote_ring);
3194         ms_snd_card_manager_destroy();
3195 }
3196
3197 void video_config_uninit(LinphoneCore *lc)
3198 {
3199         lp_config_set_int(lc->config,"video","enabled",linphone_core_video_enabled(lc));
3200         lp_config_set_string(lc->config,"video","size",video_size_get_name(linphone_core_get_preferred_video_size(lc)));
3201         lp_config_set_int(lc->config,"video","display",lc->video_conf.display);
3202         lp_config_set_int(lc->config,"video","capture",lc->video_conf.capture);
3203         lp_config_set_int(lc->config,"video","show_local",linphone_core_video_preview_enabled(lc));
3204         lp_config_set_int(lc->config,"video","self_view",linphone_core_self_view_enabled(lc));
3205 }
3206
3207 void codecs_config_uninit(LinphoneCore *lc)
3208 {
3209         PayloadType *pt;
3210         codecs_config_t *config=&lc->codecs_conf;
3211         MSList *node;
3212         char key[50];
3213         int index;
3214         index=0;
3215         for(node=config->audio_codecs;node!=NULL;node=ms_list_next(node)){
3216                 pt=(PayloadType*)(node->data);
3217                 sprintf(key,"audio_codec_%i",index);
3218                 lp_config_set_string(lc->config,key,"mime",pt->mime_type);
3219                 lp_config_set_int(lc->config,key,"rate",pt->clock_rate);
3220                 lp_config_set_int(lc->config,key,"enabled",linphone_core_payload_type_enabled(lc,pt));
3221                 index++;
3222         }
3223         index=0;
3224         for(node=config->video_codecs;node!=NULL;node=ms_list_next(node)){
3225                 pt=(PayloadType*)(node->data);
3226                 sprintf(key,"video_codec_%i",index);
3227                 lp_config_set_string(lc->config,key,"mime",pt->mime_type);
3228                 lp_config_set_int(lc->config,key,"rate",pt->clock_rate);
3229                 lp_config_set_int(lc->config,key,"enabled",linphone_core_payload_type_enabled(lc,pt));
3230                 lp_config_set_string(lc->config,key,"recv_fmtp",pt->recv_fmtp);
3231                 index++;
3232         }
3233 }
3234
3235 void ui_config_uninit(LinphoneCore* lc)
3236 {
3237         if (lc->friends){
3238                 ms_list_for_each(lc->friends,(void (*)(void *))linphone_friend_destroy);
3239                 ms_list_free(lc->friends);
3240                 lc->friends=NULL;
3241         }
3242 }
3243
3244 /**
3245  * Returns the LpConfig object used to manage the storage (config) file.
3246  *
3247  * @ingroup misc
3248  * The application can use the LpConfig object to insert its own private 
3249  * sections and pairs of key=value in the configuration file.
3250  * 
3251 **/
3252 LpConfig *linphone_core_get_config(LinphoneCore *lc){
3253         return lc->config;
3254 }
3255
3256 static void linphone_core_uninit(LinphoneCore *lc)
3257 {
3258         if (lc->call){
3259                 int i;
3260                 linphone_core_terminate_call(lc,NULL);
3261                 for(i=0;i<10;++i){
3262 #ifndef WIN32
3263                         usleep(50000);
3264 #else
3265                         Sleep(50);
3266 #endif
3267                         linphone_core_iterate(lc);
3268                 }
3269         }
3270         gstate_new_state(lc, GSTATE_POWER_SHUTDOWN, NULL);
3271 #ifdef VIDEO_ENABLED
3272         if (lc->previewstream!=NULL){
3273                 video_preview_stop(lc->previewstream);
3274                 lc->previewstream=NULL;
3275         }
3276 #endif
3277         /* save all config */
3278         net_config_uninit(lc);
3279         sip_config_uninit(lc);
3280         lp_config_set_int(lc->config,"sip","default_proxy",linphone_core_get_default_proxy(lc,NULL));
3281         rtp_config_uninit(lc);
3282         sound_config_uninit(lc);
3283         video_config_uninit(lc);
3284         codecs_config_uninit(lc);
3285         ui_config_uninit(lc);
3286         if (lp_config_needs_commit(lc->config)) lp_config_sync(lc->config);
3287         lp_config_destroy(lc->config);
3288         sip_setup_unregister_all();
3289
3290         linphone_core_free_payload_types();
3291
3292         ortp_exit();
3293         exosip_running=FALSE;
3294         gstate_new_state(lc, GSTATE_POWER_OFF, NULL);
3295 }
3296
3297 /**
3298  * Destroys a LinphoneCore
3299  *
3300  * @ingroup initializing
3301 **/
3302 void linphone_core_destroy(LinphoneCore *lc){
3303         linphone_core_uninit(lc);
3304         ms_free(lc);
3305 }
3306