source: mediastreamer2/linphone/coreapi/linphonecore.c @ 795:653a07331dfa

Last change on this file since 795:653a07331dfa was 795:653a07331dfa, checked in by smorlat <smorlat@…>, 4 years ago

add persistent call logs feature + refkey

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

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