source: mediastreamer2/linphone/coreapi/linphonecore.c @ 797:204f2e97bc62

Last change on this file since 797:204f2e97bc62 was 797:204f2e97bc62, checked in by smorlat <smorlat@…>, 3 years ago

Add API docs for liblinphone.

git-svn-id: svn+ssh://svn.savannah.nongnu.org/linphone/trunk@785 3f6dc0c8-ddfe-455d-9043-3cd528dc4637

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