source: mediastreamer2/linphone/coreapi/linphonecore.c @ 718:dbec724cbc49

Last change on this file since 718:dbec724cbc49 was 718:dbec724cbc49, checked in by smorlat <smorlat@…>, 4 years ago
  • enhance speex narrowband usage (finer bitrate choices in liblinphone)
  • fix missing parenthesis in computations
  • allow read-only config files

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

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