source: mediastreamer2/linphone/coreapi/linphonecore.c @ 695:8ca32f535cf2

Last change on this file since 695:8ca32f535cf2 was 695:8ca32f535cf2, checked in by smorlat <smorlat@…>, 4 years ago

remove unstandart gsm/11025

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

File size: 78.7 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#ifdef VIDEO_ENABLED
659
660static PayloadType * payload_type_h264_packetization_mode_1=NULL;
661static PayloadType * linphone_h263_1998=NULL;
662static PayloadType * linphone_mp4v_es=NULL;
663static PayloadType * linphone_h263_old=NULL;
664#endif
665
666#ifdef UNSTANDART_GSM_11K
667static PayloadType *gsm_11k=NULL;
668#endif
669
670void linphone_core_init (LinphoneCore * lc, const LinphoneCoreVTable *vtable, const char *config_path, void * userdata)
671{
672        memset (lc, 0, sizeof (LinphoneCore));
673        lc->data=userdata;
674
675        memcpy(&lc->vtable,vtable,sizeof(LinphoneCoreVTable));
676
677        gstate_initialize(lc);
678        gstate_new_state(lc, GSTATE_POWER_STARTUP, NULL);
679       
680        ortp_init();
681        rtp_profile_set_payload(&av_profile,115,&payload_type_lpc1015);
682        rtp_profile_set_payload(&av_profile,110,&payload_type_speex_nb);
683        rtp_profile_set_payload(&av_profile,111,&payload_type_speex_wb);
684        rtp_profile_set_payload(&av_profile,112,&payload_type_ilbc);
685        rtp_profile_set_payload(&av_profile,116,&payload_type_truespeech);
686        rtp_profile_set_payload(&av_profile,101,&payload_type_telephone_event);
687       
688#ifdef VIDEO_ENABLED
689        rtp_profile_set_payload(&av_profile,97,&payload_type_theora);
690
691        linphone_h263_1998=payload_type_clone(&payload_type_h263_1998);
692        payload_type_set_recv_fmtp(linphone_h263_1998,"CIF=1;QCIF=1");
693        rtp_profile_set_payload(&av_profile,98,linphone_h263_1998);
694
695        linphone_h263_old=payload_type_clone(&payload_type_h263);
696        payload_type_set_recv_fmtp(linphone_h263_old,"QCIF=2");
697        rtp_profile_set_payload(&av_profile,34,linphone_h263_old);
698
699        linphone_mp4v_es=payload_type_clone(&payload_type_mp4v);
700        payload_type_set_recv_fmtp(linphone_mp4v_es,"profile-level-id=3");
701        rtp_profile_set_payload(&av_profile,99,linphone_mp4v_es);
702        rtp_profile_set_payload(&av_profile,100,&payload_type_x_snow);
703        payload_type_h264_packetization_mode_1=payload_type_clone(&payload_type_h264);
704        payload_type_set_recv_fmtp(payload_type_h264_packetization_mode_1,"packetization-mode=1");
705        rtp_profile_set_payload(&av_profile,103,payload_type_h264_packetization_mode_1);
706        rtp_profile_set_payload(&av_profile,102,&payload_type_h264);
707#endif
708
709#ifdef UNSTANDART_GSM_11K
710        gsm_11k=payload_type_clone(&payload_type_gsm);
711        gsm_11k->clock_rate=11025;
712        rtp_profile_set_payload(&av_profile,96,gsm_11k);
713#endif
714
715        ms_init();
716       
717        lc->config=lp_config_new(config_path);
718 
719#ifdef VINCENT_MAURY_RSVP
720        /* default qos parameters : rsvp on, rpc off */
721        lc->rsvp_enable = 1;
722        lc->rpc_enable = 0;
723#endif
724        sip_setup_register_all();
725        sound_config_read(lc);
726        net_config_read(lc);
727        rtp_config_read(lc);
728        codecs_config_read(lc);
729        sip_config_read(lc); /* this will start eXosip*/
730        video_config_read(lc);
731        //autoreplier_config_init(&lc->autoreplier_conf);
732        lc->prev_mode=LINPHONE_STATUS_ONLINE;
733        lc->presence_mode=LINPHONE_STATUS_ONLINE;
734        lc->max_call_logs=15;
735        ui_config_read(lc);
736        ms_mutex_init(&lc->lock,NULL);
737        lc->vtable.display_status(lc,_("Ready"));
738        gstate_new_state(lc, GSTATE_POWER_ON, NULL);
739        lc->ready=TRUE;
740}
741
742LinphoneCore *linphone_core_new(const LinphoneCoreVTable *vtable,
743                                                const char *config_path, void * userdata)
744{
745        LinphoneCore *core=ms_new(LinphoneCore,1);
746        linphone_core_init(core,vtable,config_path,userdata);
747        return core;
748}
749
750const MSList *linphone_core_get_audio_codecs(const LinphoneCore *lc)
751{
752        return lc->codecs_conf.audio_codecs;
753}
754
755const MSList *linphone_core_get_video_codecs(const LinphoneCore *lc)
756{
757        return lc->codecs_conf.video_codecs;
758}
759
760int linphone_core_set_primary_contact(LinphoneCore *lc, const char *contact)
761{
762        osip_from_t *ctt=NULL;
763        osip_from_init(&ctt);
764        if (osip_from_parse(ctt,contact)!=0){
765                ms_error("Bad contact url: %s",contact);
766                osip_from_free(ctt);
767                return -1;
768        }
769        if (lc->sip_conf.contact!=NULL) ms_free(lc->sip_conf.contact);
770        lc->sip_conf.contact=ms_strdup(contact);
771        if (lc->sip_conf.guessed_contact!=NULL){
772                ms_free(lc->sip_conf.guessed_contact);
773                lc->sip_conf.guessed_contact=NULL;
774        }
775        osip_from_free(ctt);
776        return 0;
777}
778
779
780/*result must be an array of chars at least LINPHONE_IPADDR_SIZE */
781void linphone_core_get_local_ip(LinphoneCore *lc, const char *dest, char *result){
782        if (lc->apply_nat_settings){
783                apply_nat_settings(lc);
784                lc->apply_nat_settings=FALSE;
785        }
786        if (linphone_core_get_firewall_policy(lc)==LINPHONE_POLICY_USE_NAT_ADDRESS){
787                strncpy(result,linphone_core_get_nat_address(lc),LINPHONE_IPADDR_SIZE);
788                return;
789        }
790        if (dest==NULL) dest="87.98.157.38"; /*a public IP address*/
791        if (linphone_core_get_local_ip_for(dest,result)==0)
792                return;
793        /*else fallback to exosip routine that will attempt to find the most realistic interface */
794        if (eXosip_guess_localip(lc->sip_conf.ipv6_enabled ? AF_INET6 : AF_INET,result,LINPHONE_IPADDR_SIZE)<0){
795                /*default to something */
796                strncpy(result,lc->sip_conf.ipv6_enabled ? "::1" : "127.0.0.1",LINPHONE_IPADDR_SIZE);
797                ms_error("Could not find default routable ip address !"); 
798        }
799}
800
801const char *linphone_core_get_primary_contact(LinphoneCore *lc)
802{
803        char *identity;
804        char tmp[LINPHONE_IPADDR_SIZE];
805        if (lc->sip_conf.guess_hostname){
806                if (lc->sip_conf.guessed_contact==NULL || lc->sip_conf.loopback_only){
807                        char *guessed=NULL;
808                        osip_from_t *url;
809                        if (lc->sip_conf.guessed_contact!=NULL){
810                                ms_free(lc->sip_conf.guessed_contact);
811                                lc->sip_conf.guessed_contact=NULL;
812                        }
813                       
814                        osip_from_init(&url);
815                        if (osip_from_parse(url,lc->sip_conf.contact)==0){
816                               
817                        }else ms_error("Could not parse identity contact !");
818                        linphone_core_get_local_ip(lc, NULL, tmp);
819                        if (strcmp(tmp,"127.0.0.1")==0 || strcmp(tmp,"::1")==0 ){
820                                ms_warning("Local loopback network only !");
821                                lc->sip_conf.loopback_only=TRUE;
822                        }else lc->sip_conf.loopback_only=FALSE;
823                        osip_free(url->url->host);
824                        url->url->host=osip_strdup(tmp);
825                        if (url->url->port!=NULL){
826                                osip_free(url->url->port);
827                                url->url->port=NULL;
828                        }
829                        if (lc->sip_conf.sip_port!=5060){
830                                url->url->port=ortp_strdup_printf("%i",lc->sip_conf.sip_port);
831                        }
832                        osip_from_to_str(url,&guessed);
833                        lc->sip_conf.guessed_contact=guessed;
834                       
835                        osip_from_free(url);
836                       
837                }
838                identity=lc->sip_conf.guessed_contact;
839        }else{
840                identity=lc->sip_conf.contact;
841        }
842        return identity;
843}
844
845void linphone_core_set_guess_hostname(LinphoneCore *lc, bool_t val){
846        lc->sip_conf.guess_hostname=val;
847}
848       
849bool_t linphone_core_get_guess_hostname(LinphoneCore *lc){
850        return lc->sip_conf.guess_hostname;
851}
852
853osip_from_t *linphone_core_get_primary_contact_parsed(LinphoneCore *lc){
854        int err;
855        osip_from_t *contact;
856        osip_from_init(&contact);
857        err=osip_from_parse(contact,linphone_core_get_primary_contact(lc));
858        if (err<0) {
859                osip_from_free(contact);
860                return NULL;
861        }
862        return contact;
863}
864
865int linphone_core_set_audio_codecs(LinphoneCore *lc, MSList *codecs)
866{
867        if (lc->codecs_conf.audio_codecs!=NULL) ms_list_free(lc->codecs_conf.audio_codecs);
868        lc->codecs_conf.audio_codecs=codecs;
869        return 0;
870}
871
872int linphone_core_set_video_codecs(LinphoneCore *lc, MSList *codecs)
873{
874        if (lc->codecs_conf.video_codecs!=NULL) ms_list_free(lc->codecs_conf.video_codecs);
875        lc->codecs_conf.video_codecs=codecs;
876        return 0;
877}
878
879const MSList * linphone_core_get_friend_list(LinphoneCore *lc)
880{
881        return lc->friends;
882}
883
884int linphone_core_get_audio_jittcomp(LinphoneCore *lc)
885{
886        return lc->rtp_conf.audio_jitt_comp;
887}
888
889int linphone_core_get_audio_port(const LinphoneCore *lc)
890{
891        return lc->rtp_conf.audio_rtp_port;
892}
893
894int linphone_core_get_video_port(const LinphoneCore *lc){
895        return lc->rtp_conf.video_rtp_port;
896}
897
898int linphone_core_get_nortp_timeout(const LinphoneCore *lc){
899        return lc->rtp_conf.nortp_timeout;
900}
901
902void linphone_core_set_audio_jittcomp(LinphoneCore *lc, int value)
903{
904        lc->rtp_conf.audio_jitt_comp=value;
905}
906
907void linphone_core_set_audio_port(LinphoneCore *lc, int port)
908{
909        lc->rtp_conf.audio_rtp_port=port;
910}
911
912void linphone_core_set_video_port(LinphoneCore *lc, int port){
913        lc->rtp_conf.video_rtp_port=port;
914}
915
916void linphone_core_set_nortp_timeout(LinphoneCore *lc, int nortp_timeout){
917        lc->rtp_conf.nortp_timeout=nortp_timeout;
918}
919
920bool_t linphone_core_get_use_info_for_dtmf(LinphoneCore *lc)
921{
922        return lc->sip_conf.use_info;
923}
924
925void linphone_core_set_use_info_for_dtmf(LinphoneCore *lc,bool_t use_info)
926{
927        lc->sip_conf.use_info=use_info;
928}
929
930int linphone_core_get_sip_port(LinphoneCore *lc)
931{
932        return lc->sip_conf.sip_port;
933}
934
935static bool_t exosip_running=FALSE;
936static char _ua_name[64]="Linphone";
937static char _ua_version[64]=LINPHONE_VERSION;
938
939static void apply_user_agent(void){
940        char ua_string[256];
941        snprintf(ua_string,sizeof(ua_string),"%s/%s (eXosip2/%s)",_ua_name,_ua_version,
942#ifdef HAVE_EXOSIP_GET_VERSION
943                 eXosip_get_version()
944#else
945                 "unknown"
946#endif
947        );
948        eXosip_set_user_agent(ua_string);
949}
950
951void linphone_core_set_user_agent(const char *name, const char *ver){
952        strncpy(_ua_name,name,sizeof(_ua_name)-1);
953        strncpy(_ua_version,ver,sizeof(_ua_version));
954}
955
956void linphone_core_set_sip_port(LinphoneCore *lc,int port)
957{
958        const char *anyaddr;
959        int err=0;
960        if (port==lc->sip_conf.sip_port) return;
961        lc->sip_conf.sip_port=port;
962        if (exosip_running) eXosip_quit();
963        eXosip_init();
964        err=0;
965        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
966                                        version of eXosip, which is not the case*/
967        eXosip_enable_ipv6(lc->sip_conf.ipv6_enabled);
968        if (lc->sip_conf.ipv6_enabled)
969                anyaddr="::0";
970        else
971                anyaddr="0.0.0.0";
972        err=eXosip_listen_addr (IPPROTO_UDP, anyaddr, port,
973                lc->sip_conf.ipv6_enabled ?  PF_INET6 : PF_INET, 0);
974        if (err<0){
975                char *msg=ortp_strdup_printf("UDP port %i seems already in use ! Cannot initialize.",port);
976                ms_warning(msg);
977                lc->vtable.display_warning(lc,msg);
978                ms_free(msg);
979                return;
980        }
981#ifdef VINCENT_MAURY_RSVP
982        /* tell exosip the qos settings according to default linphone parameters */
983        eXosip_set_rsvp_mode (lc->rsvp_enable);
984        eXosip_set_rpc_mode (lc->rpc_enable);
985#endif
986        apply_user_agent();
987        exosip_running=TRUE;
988}
989
990bool_t linphone_core_ipv6_enabled(LinphoneCore *lc){
991        return lc->sip_conf.ipv6_enabled;
992}
993void linphone_core_enable_ipv6(LinphoneCore *lc, bool_t val){
994        if (lc->sip_conf.ipv6_enabled!=val){
995                lc->sip_conf.ipv6_enabled=val;
996                if (exosip_running){
997                        /* we need to restart eXosip */
998                        linphone_core_set_sip_port(lc, lc->sip_conf.sip_port);
999                }
1000        }
1001}
1002
1003static void display_bandwidth(RtpSession *as, RtpSession *vs){
1004        ms_message("bandwidth usage: audio=[d=%.1f,u=%.1f] video=[d=%.1f,u=%.1f] kbit/sec",
1005        (as!=NULL) ? (rtp_session_compute_recv_bandwidth(as)*1e-3) : 0,
1006        (as!=NULL) ? (rtp_session_compute_send_bandwidth(as)*1e-3) : 0,
1007        (vs!=NULL) ? (rtp_session_compute_recv_bandwidth(vs)*1e-3) : 0,
1008        (vs!=NULL) ? (rtp_session_compute_send_bandwidth(vs)*1e-3) : 0);
1009}
1010
1011static void linphone_core_disconnected(LinphoneCore *lc){
1012        lc->vtable.display_warning(lc,_("Remote end seems to have disconnected, the call is going to be closed."));
1013        linphone_core_terminate_call(lc,NULL);
1014}
1015
1016static void proxy_update(LinphoneCore *lc, time_t curtime){
1017        bool_t doit=FALSE;
1018        static time_t last_check=0;
1019        static bool_t last_status=FALSE;
1020        if (lc->sip_conf.register_only_when_network_is_up){
1021                char result[LINPHONE_IPADDR_SIZE];
1022                /* only do the network up checking every five seconds */
1023                if (last_check==0 || (curtime-last_check)>=5){
1024                        if (eXosip_guess_localip(lc->sip_conf.ipv6_enabled ? AF_INET6 : AF_INET,result,LINPHONE_IPADDR_SIZE)==0){
1025                                if (strcmp(result,"::1")!=0 && strcmp(result,"127.0.0.1")!=0){
1026                                        last_status=TRUE;
1027                                        ms_message("Network is up, registering now (%s)",result);
1028                                }else last_status=FALSE;
1029                        }
1030                        last_check=curtime;
1031                }
1032                doit=last_status;
1033        }else doit=TRUE;
1034        if (doit) ms_list_for_each(lc->sip_conf.proxies,(void (*)(void*))&linphone_proxy_config_update);
1035}
1036
1037void linphone_core_iterate(LinphoneCore *lc)
1038{
1039        eXosip_event_t *ev;
1040        bool_t disconnected=FALSE;
1041        int disconnect_timeout = linphone_core_get_nortp_timeout(lc); 
1042        time_t curtime=time(NULL);
1043        int elapsed;
1044        bool_t one_second_elapsed=FALSE;
1045       
1046        if (curtime-lc->prevtime>=1){
1047                lc->prevtime=curtime;
1048                one_second_elapsed=TRUE;
1049        }
1050
1051        if (lc->preview_finished){
1052                lc->preview_finished=0;
1053                ring_stop(lc->ringstream);
1054                lc->ringstream=NULL;
1055                lc_callback_obj_invoke(&lc->preview_finished_cb,lc);
1056        }
1057       
1058        if (exosip_running){
1059                while((ev=eXosip_event_wait(0,0))!=NULL){
1060                        linphone_core_process_event(lc,ev);
1061                }
1062                if (lc->automatic_action==0) {
1063                        eXosip_lock();
1064                        eXosip_automatic_action();
1065                        eXosip_unlock();
1066                }
1067        }
1068
1069        proxy_update(lc,curtime);
1070
1071        if (lc->call!=NULL){
1072                LinphoneCall *call=lc->call;
1073               
1074                if (call->dir==LinphoneCallIncoming && call->state==LCStateRinging){
1075                        elapsed=curtime-call->start_time;
1076                        ms_message("incoming call ringing for %i seconds",elapsed);
1077                        if (elapsed>lc->sip_conf.inc_timeout){
1078                                linphone_core_terminate_call(lc,NULL);
1079                        }
1080                }else if (call->state==LCStateAVRunning){
1081                        if (one_second_elapsed){
1082                                RtpSession *as=NULL,*vs=NULL;
1083                                lc->prevtime=curtime;
1084                                if (lc->audiostream!=NULL)
1085                                        as=lc->audiostream->session;
1086                                if (lc->videostream!=NULL)
1087                                        vs=lc->videostream->session;
1088                                display_bandwidth(as,vs);
1089                        }
1090#ifdef VIDEO_ENABLED
1091                        if (lc->videostream!=NULL)
1092                                video_stream_iterate(lc->videostream);
1093#endif
1094                        if (lc->audiostream!=NULL && disconnect_timeout>0)
1095                                disconnected=!audio_stream_alive(lc->audiostream,disconnect_timeout);
1096                }
1097        }
1098        if (linphone_core_video_preview_enabled(lc)){
1099                if (lc->previewstream==NULL)
1100                        toggle_video_preview(lc,TRUE);
1101#ifdef VIDEO_ENABLED
1102                else video_stream_iterate(lc->previewstream);
1103#endif
1104        }else{
1105                if (lc->previewstream!=NULL)
1106                        toggle_video_preview(lc,FALSE);
1107        }
1108        if (disconnected)
1109                linphone_core_disconnected(lc);
1110        if (one_second_elapsed && lp_config_needs_commit(lc->config)){
1111                lp_config_sync(lc->config);
1112        }
1113}
1114
1115
1116bool_t linphone_core_is_in_main_thread(LinphoneCore *lc){
1117        return TRUE;
1118}
1119
1120static osip_to_t *osip_to_create(const char *to){
1121        osip_to_t *ret;
1122        osip_to_init(&ret);
1123        if (osip_to_parse(ret,to)<0){
1124                osip_to_free(ret);
1125                return NULL;
1126        }
1127        return ret;
1128}
1129
1130static char *guess_route_if_any(LinphoneCore *lc, osip_to_t *parsed_url){
1131        const MSList *elem=linphone_core_get_proxy_config_list(lc);
1132        for(;elem!=NULL;elem=elem->next){
1133                LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)elem->data;
1134                char prx[256];
1135                if (cfg->ssctx && sip_setup_context_get_proxy(cfg->ssctx,parsed_url->url->host,prx,sizeof(prx))==0){
1136                        ms_message("We have a proxy for domain %s",parsed_url->url->host);
1137                        if (strcmp(parsed_url->url->host,prx)!=0){
1138                                char *route=NULL;
1139                                osip_route_t *rt;
1140                                osip_route_init(&rt);
1141                                if (osip_route_parse(rt,prx)==0){
1142                                        char *rtstr;
1143                                        osip_uri_uparam_add(rt->url,osip_strdup("lr"),NULL);
1144                                        osip_route_to_str(rt,&rtstr);
1145                                        route=ms_strdup(rtstr);
1146                                        osip_free(rtstr);
1147                                }
1148                                osip_route_free(rt);
1149                                ms_message("Adding a route: %s",route);
1150                                return route;
1151                        }
1152                }
1153        }
1154        return NULL;
1155}
1156
1157bool_t linphone_core_interpret_url(LinphoneCore *lc, const char *url, char **real_url, osip_to_t **real_parsed_url, char **route){
1158        enum_lookup_res_t *enumres=NULL;
1159        osip_to_t *parsed_url=NULL;
1160        char *enum_domain=NULL;
1161        LinphoneProxyConfig *proxy;
1162        char *tmpurl;
1163        const char *tmproute;
1164        if (real_url!=NULL) *real_url=NULL;
1165        if (real_parsed_url!=NULL) *real_parsed_url=NULL;
1166        *route=NULL;
1167        tmproute=linphone_core_get_route(lc);
1168       
1169        if (is_enum(url,&enum_domain)){
1170                lc->vtable.display_status(lc,_("Looking for telephone number destination..."));
1171                if (enum_lookup(enum_domain,&enumres)<0){
1172                        lc->vtable.display_status(lc,_("Could not resolve this number."));
1173                        ms_free(enum_domain);
1174                        return FALSE;
1175                }
1176                ms_free(enum_domain);
1177                tmpurl=enumres->sip_address[0];
1178                if (real_url!=NULL) *real_url=ms_strdup(tmpurl);
1179                if (real_parsed_url!=NULL) *real_parsed_url=osip_to_create(tmpurl);
1180                enum_lookup_res_free(enumres);
1181                if (tmproute) *route=ms_strdup(tmproute);
1182                return TRUE;
1183        }
1184        /* check if we have a "sip:" */
1185        if (strstr(url,"sip:")==NULL){
1186                /* this doesn't look like a true sip uri */
1187                proxy=lc->default_proxy;
1188                if (proxy!=NULL){
1189                        /* append the proxy domain suffix */
1190                        osip_from_t *uri;
1191                        char *sipaddr;
1192                        const char *identity=linphone_proxy_config_get_identity(proxy);
1193                        osip_from_init(&uri);
1194                        if (osip_from_parse(uri,identity)<0){
1195                                osip_from_free(uri);
1196                                return FALSE;
1197                        }
1198                        sipaddr=ortp_strdup_printf("sip:%s@%s",url,uri->url->host);
1199                        if (real_parsed_url!=NULL) *real_parsed_url=osip_to_create(sipaddr);
1200                        if (real_url!=NULL) *real_url=sipaddr;
1201                        else ms_free(sipaddr);
1202#if 0
1203                        /*if the prompted uri was auto-suffixed with proxy domain,
1204                        then automatically set a route so that the request goes
1205                        through the proxy*/
1206                        if (tmproute==NULL){
1207                                osip_route_t *rt=NULL;
1208                                char *rtstr=NULL;
1209                                osip_route_init(&rt);
1210                                if (osip_route_parse(rt,linphone_proxy_config_get_addr(proxy))==0){
1211                                        osip_uri_uparam_add(rt->url,osip_strdup("lr"),NULL);
1212                                        osip_route_to_str(rt,&rtstr);
1213                                        *route=ms_strdup(rtstr);
1214                                        osip_free(rtstr);
1215                                }
1216                                ms_message("setting automatically a route to %s",*route);
1217                        }
1218                        else *route=ms_strdup(tmproute);
1219#else
1220                        if (tmproute==NULL) *route=guess_route_if_any(lc,*real_parsed_url);
1221                        if (tmproute) *route=ms_strdup(tmproute);
1222#endif
1223                        return TRUE;
1224                }
1225        }
1226        parsed_url=osip_to_create(url);
1227        if (parsed_url!=NULL){
1228                if (real_url!=NULL) *real_url=ms_strdup(url);
1229                if (real_parsed_url!=NULL) *real_parsed_url=parsed_url;
1230                else osip_to_free(parsed_url);
1231                if (tmproute) *route=ms_strdup(tmproute);
1232                else *route=guess_route_if_any(lc,*real_parsed_url);
1233                return TRUE;
1234        }
1235        /* else we could not do anything with url given by user, so display an error */
1236        if (lc->vtable.display_warning!=NULL){
1237                lc->vtable.display_warning(lc,_("Could not parse given sip address. A sip url usually looks like sip:user@domain"));
1238        }
1239        return FALSE;
1240}
1241
1242const char * linphone_core_get_identity(LinphoneCore *lc){
1243        LinphoneProxyConfig *proxy=NULL;
1244        const char *from;
1245        linphone_core_get_default_proxy(lc,&proxy);
1246        if (proxy!=NULL) {
1247                from=linphone_proxy_config_get_identity(proxy);
1248        }else from=linphone_core_get_primary_contact(lc);
1249        return from;
1250}
1251
1252const char * linphone_core_get_route(LinphoneCore *lc){
1253        LinphoneProxyConfig *proxy=NULL;
1254        const char *route=NULL;
1255        linphone_core_get_default_proxy(lc,&proxy);
1256        if (proxy!=NULL) {
1257                route=linphone_proxy_config_get_route(proxy);
1258        }
1259        return route;
1260}
1261
1262void linphone_set_sdp(osip_message_t *sip, const char *sdpmesg){
1263        int sdplen=strlen(sdpmesg);
1264        char clen[10];
1265        snprintf(clen,sizeof(clen),"%i",sdplen);
1266        osip_message_set_body(sip,sdpmesg,sdplen);
1267        osip_message_set_content_type(sip,"application/sdp");
1268        osip_message_set_content_length(sip,clen);
1269}
1270
1271LinphoneProxyConfig * linphone_core_lookup_known_proxy(LinphoneCore *lc, const char *uri){
1272        const MSList *elem;
1273        LinphoneProxyConfig *found_cfg=NULL;
1274        osip_from_t *parsed_uri;
1275        osip_from_init(&parsed_uri);
1276        osip_from_parse(parsed_uri,uri);
1277        for (elem=linphone_core_get_proxy_config_list(lc);elem!=NULL;elem=elem->next){
1278                LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)elem->data;
1279                const char *domain=linphone_proxy_config_get_domain(cfg);
1280                if (domain!=NULL && strcmp(domain,parsed_uri->url->host)==0){
1281                        found_cfg=cfg;
1282                        break;
1283                }
1284        }
1285        osip_from_free(parsed_uri);
1286        return found_cfg;
1287}
1288
1289static void fix_contact(LinphoneCore *lc, osip_message_t *msg, const char *localip, LinphoneProxyConfig *dest_proxy){
1290        osip_contact_t *ctt=NULL;
1291        const char *ip=NULL;
1292        int port=5060;
1293
1294        osip_message_get_contact(msg,0,&ctt);
1295        if (ctt!=NULL){
1296                if (dest_proxy!=NULL){
1297                        /* if we know the request will go to a known proxy for which we are registered,
1298                        we can use the same contact address as in the register */
1299                        linphone_proxy_config_get_contact(dest_proxy,&ip,&port);
1300                }else{
1301                        ip=localip;
1302                        port=linphone_core_get_sip_port(lc);
1303                }
1304                if (ip!=NULL){
1305                        osip_free(ctt->url->host);
1306                        ctt->url->host=osip_strdup(ip);
1307                }
1308                if (port!=0){
1309                        char tmp[10]={0};
1310                        char *str;
1311                        snprintf(tmp,sizeof(tmp)-1,"%i",port);
1312                        if (ctt->url->port!=NULL)
1313                                osip_free(ctt->url->port);
1314                        ctt->url->port=osip_strdup(tmp);
1315                        osip_contact_to_str(ctt,&str);
1316                        ms_message("Contact has been fixed to %s",str);
1317                        osip_free(str);
1318                }
1319        }
1320}
1321
1322int linphone_core_invite(LinphoneCore *lc, const char *url)
1323{
1324        char *barmsg;
1325        int err=0;
1326        char *sdpmesg=NULL;
1327        char *route=NULL;
1328        const char *from=NULL;
1329        osip_message_t *invite=NULL;
1330        sdp_context_t *ctx=NULL;
1331        LinphoneProxyConfig *proxy=NULL;
1332        osip_from_t *parsed_url2=NULL;
1333        osip_to_t *real_parsed_url=NULL;
1334        char *real_url=NULL;
1335        LinphoneProxyConfig *dest_proxy=NULL;
1336       
1337        if (lc->call!=NULL){
1338                lc->vtable.display_warning(lc,_("Sorry, having multiple simultaneous calls is not supported yet !"));
1339                return -1;
1340        }
1341
1342        gstate_new_state(lc, GSTATE_CALL_OUT_INVITE, url);
1343        linphone_core_get_default_proxy(lc,&proxy);
1344        if (!linphone_core_interpret_url(lc,url,&real_url,&real_parsed_url,&route)){
1345                /* bad url */
1346                gstate_new_state(lc, GSTATE_CALL_ERROR, NULL);
1347                return -1;
1348        }
1349        dest_proxy=linphone_core_lookup_known_proxy(lc,real_url);
1350
1351        if (proxy!=dest_proxy && dest_proxy!=NULL) {
1352                ms_message("Overriding default proxy setting for this call:");
1353                ms_message("The used identity will be %s",linphone_proxy_config_get_identity(dest_proxy));
1354        }
1355
1356        if (dest_proxy!=NULL) 
1357                from=linphone_proxy_config_get_identity(dest_proxy);
1358        else if (proxy!=NULL)
1359                from=linphone_proxy_config_get_identity(proxy);
1360
1361        /* if no proxy or no identity defined for this proxy, default to primary contact*/
1362        if (from==NULL) from=linphone_core_get_primary_contact(lc);
1363
1364        err=eXosip_call_build_initial_invite(&invite,real_url,from,
1365                                                route,"Phone call");
1366        if (err<0){
1367                ms_warning("Could not build initial invite");
1368                goto end;
1369        }
1370        if (lp_config_get_int(lc->config,"sip","use_session_timers",0)==1){
1371                osip_message_set_header(invite, "Session-expires", "200");
1372                osip_message_set_supported(invite, "timer");
1373        }
1374        /* make sdp message */
1375       
1376        osip_from_init(&parsed_url2);
1377        osip_from_parse(parsed_url2,from);
1378       
1379        lc->call=linphone_call_new_outgoing(lc,parsed_url2,real_parsed_url);
1380        /*try to be best-effort in giving real local or routable contact address,
1381        except when the user choosed to override the ipaddress */
1382        if (linphone_core_get_firewall_policy(lc)!=LINPHONE_POLICY_USE_NAT_ADDRESS)
1383                fix_contact(lc,invite,lc->call->localip,dest_proxy);
1384
1385        barmsg=ortp_strdup_printf("%s %s", _("Contacting"), real_url);
1386        lc->vtable.display_status(lc,barmsg);
1387        ms_free(barmsg);
1388        if (!lc->sip_conf.sdp_200_ack){
1389                ctx=lc->call->sdpctx;
1390                sdpmesg=sdp_context_get_offer(ctx);
1391                linphone_set_sdp(invite,sdpmesg);
1392                linphone_core_init_media_streams(lc);
1393        }
1394        eXosip_lock();
1395        err=eXosip_call_send_initial_invite(invite);
1396        lc->call->cid=err;
1397        eXosip_unlock();
1398        if (err<0){
1399                ms_warning("Could not initiate call.");
1400                lc->vtable.display_status(lc,_("could not call"));
1401                linphone_call_destroy(lc->call);
1402                lc->call=NULL;
1403                linphone_core_stop_media_streams(lc);
1404        }
1405       
1406        goto end;
1407        end:
1408                if (real_url!=NULL) ms_free(real_url);
1409                if (real_parsed_url!=NULL) osip_to_free(real_parsed_url);
1410                if (parsed_url2!=NULL) osip_from_free(parsed_url2);
1411                if (err<0)
1412                        gstate_new_state(lc, GSTATE_CALL_ERROR, NULL);
1413                if (route!=NULL) ms_free(route);
1414        return (err<0) ? -1 : 0;
1415}
1416
1417int linphone_core_refer(LinphoneCore *lc, const char *url)
1418{
1419        char *real_url=NULL;
1420        osip_to_t *real_parsed_url=NULL;
1421        LinphoneCall *call;
1422        osip_message_t *msg=NULL;
1423        char *route;
1424        if (!linphone_core_interpret_url(lc,url,&real_url,&real_parsed_url, &route)){
1425                /* bad url */
1426                return -1;
1427        }
1428        if (route!=NULL) ms_free(route);
1429        call=lc->call;
1430        if (call==NULL){
1431                ms_warning("No established call to refer.");
1432                return -1;
1433        }
1434        lc->call=NULL;
1435        eXosip_call_build_refer(call->did, real_url, &msg);
1436        eXosip_lock();
1437        eXosip_call_send_request(call->did, msg);
1438        eXosip_unlock();
1439        return 0;
1440}
1441
1442bool_t linphone_core_inc_invite_pending(LinphoneCore*lc){
1443        if (lc->call!=NULL && lc->call->dir==LinphoneCallIncoming){
1444                return TRUE;
1445        }
1446        return FALSE;
1447}
1448
1449#ifdef VINCENT_MAURY_RSVP
1450/* on=1 for RPC_ENABLE=1...*/
1451int linphone_core_set_rpc_mode(LinphoneCore *lc, int on)
1452{
1453        if (on==1)
1454                printf("RPC_ENABLE set on\n");
1455        else 
1456                printf("RPC_ENABLE set off\n");
1457        lc->rpc_enable = (on==1);
1458        /* need to tell eXosip the new setting */
1459        if (eXosip_set_rpc_mode (lc->rpc_enable)!=0)
1460                return -1;
1461        return 0;
1462}
1463
1464/* on=1 for RSVP_ENABLE=1...*/
1465int linphone_core_set_rsvp_mode(LinphoneCore *lc, int on)
1466{
1467        if (on==1)
1468                printf("RSVP_ENABLE set on\n");
1469        else 
1470                printf("RSVP_ENABLE set off\n");
1471        lc->rsvp_enable = (on==1);
1472        /* need to tell eXosip the new setting */
1473        if (eXosip_set_rsvp_mode (lc->rsvp_enable)!=0)
1474                return -1;
1475        return 0;
1476}
1477
1478/* answer : 1 for yes, 0 for no */
1479int linphone_core_change_qos(LinphoneCore *lc, int answer)
1480{
1481        char *sdpmesg;
1482        if (lc->call==NULL){
1483                return -1;
1484        }
1485       
1486        if (lc->rsvp_enable && answer==1)
1487        {
1488                /* answer is yes, local setting is with qos, so
1489                 * the user chose to continue with no qos ! */
1490                /* so switch in normal mode : ring and 180 */
1491                lc->rsvp_enable = 0; /* no more rsvp */
1492                eXosip_set_rsvp_mode (lc->rsvp_enable);
1493                /* send 180 */
1494                eXosip_lock();
1495                eXosip_answer_call(lc->call->did,180,NULL);
1496                eXosip_unlock();
1497                /* play the ring */
1498                ms_message("Starting local ring...");
1499                lc->ringstream=ring_start(lc->sound_conf.local_ring,
1500                                        2000,ms_snd_card_manager_get_card(ms_snd_card_manager_get(),lc->sound_conf.ring_sndcard));
1501        }
1502        else if (!lc->rsvp_enable && answer==1)
1503        {
1504                /* switch to QoS mode on : answer 183 session progress */
1505                lc->rsvp_enable = 1;
1506                eXosip_set_rsvp_mode (lc->rsvp_enable);
1507                /* take the sdp already computed, see osipuacb.c */
1508                sdpmesg=lc->call->sdpctx->answerstr;
1509                eXosip_lock();
1510                eXosip_answer_call_with_body(lc->call->did,183,"application/sdp",sdpmesg);
1511                eXosip_unlock();
1512        }
1513        else
1514        {
1515                /* decline offer (603) */
1516                linphone_core_terminate_call(lc, NULL);
1517        }
1518        return 0;
1519}
1520#endif
1521
1522void linphone_core_init_media_streams(LinphoneCore *lc){
1523        lc->audiostream=audio_stream_new(linphone_core_get_audio_port(lc),linphone_core_ipv6_enabled(lc));
1524        if (linphone_core_echo_limiter_enabled(lc)){
1525                const char *type=lp_config_get_string(lc->config,"sound","el_type","mic");
1526                if (strcasecmp(type,"mic")==0)
1527                        audio_stream_enable_echo_limiter(lc->audiostream,ELControlMic);
1528                else if (strcasecmp(type,"speaker")==0)
1529                        audio_stream_enable_echo_limiter(lc->audiostream,ELControlSpeaker);
1530        }
1531        audio_stream_enable_gain_control(lc->audiostream,TRUE);
1532        if (linphone_core_echo_cancelation_enabled(lc)){
1533                int len,delay,framesize;
1534                len=lp_config_get_int(lc->config,"sound","ec_tail_len",0);
1535                delay=lp_config_get_int(lc->config,"sound","ec_delay",0);
1536                framesize=lp_config_get_int(lc->config,"sound","ec_framesize",0);
1537                audio_stream_set_echo_canceler_params(lc->audiostream,len,delay,framesize);
1538        }
1539        audio_stream_enable_automatic_gain_control(lc->audiostream,linphone_core_agc_enabled(lc));
1540#ifdef VIDEO_ENABLED
1541        if (lc->video_conf.display || lc->video_conf.capture)
1542                lc->videostream=video_stream_new(linphone_core_get_video_port(lc),linphone_core_ipv6_enabled(lc));
1543#else
1544        lc->videostream=NULL;
1545#endif
1546}
1547
1548static void linphone_core_dtmf_received(RtpSession* s, int dtmf, void* user_data){
1549        LinphoneCore* lc = (LinphoneCore*)user_data;
1550        if (lc->vtable.dtmf_received != NULL)
1551                lc->vtable.dtmf_received(lc, dtmf);
1552}
1553
1554static void parametrize_equalizer(LinphoneCore *lc, AudioStream *st){
1555        if (st->equalizer){
1556                MSFilter *f=st->equalizer;
1557                int enabled=lp_config_get_int(lc->config,"sound","eq_active",0);
1558                const char *gains=lp_config_get_string(lc->config,"sound","eq_gains",NULL);
1559                ms_filter_call_method(f,MS_EQUALIZER_SET_ACTIVE,&enabled);
1560                if (enabled){
1561                        if (gains){
1562                                do{
1563                                        int bytes;
1564                                        MSEqualizerGain g;
1565                                        if (sscanf(gains,"%f:%f:%f %n",&g.frequency,&g.gain,&g.width,&bytes)==3){
1566                                                ms_message("Read equalizer gains: %f(~%f) --> %f",g.frequency,g.width,g.gain);
1567                                                ms_filter_call_method(f,MS_EQUALIZER_SET_GAIN,&g);
1568                                                gains+=bytes;
1569                                        }else break;
1570                                }while(1);
1571                        }
1572                }
1573        }
1574}
1575
1576static void post_configure_audio_streams(LinphoneCore *lc){
1577        AudioStream *st=lc->audiostream;
1578        float gain=lp_config_get_float(lc->config,"sound","mic_gain",-1);
1579        if (gain!=-1)
1580                audio_stream_set_mic_gain(st,gain);
1581        if (linphone_core_echo_limiter_enabled(lc)){
1582                float speed=lp_config_get_float(lc->config,"sound","el_speed",-1);
1583                float thres=lp_config_get_float(lc->config,"sound","el_thres",-1);
1584                float force=lp_config_get_float(lc->config,"sound","el_force",-1);
1585                int sustain=lp_config_get_int(lc->config,"sound","el_sustain",-1);
1586                MSFilter *f=NULL;
1587                if (st->el_type==ELControlMic){
1588                        f=st->volsend;
1589                        if (speed==-1) speed=0.03;
1590                        if (force==-1) force=10;
1591                }
1592                else if (st->el_type==ELControlSpeaker){
1593                        f=st->volrecv;
1594                        if (speed==-1) speed=0.02;
1595                        if (force==-1) force=5;
1596                }
1597                if (speed!=-1)
1598                        ms_filter_call_method(f,MS_VOLUME_SET_EA_SPEED,&speed);
1599                if (thres!=-1)
1600                        ms_filter_call_method(f,MS_VOLUME_SET_EA_THRESHOLD,&thres);
1601                if (force!=-1)
1602                        ms_filter_call_method(f,MS_VOLUME_SET_EA_FORCE,&force);
1603                if (sustain!=-1)
1604                        ms_filter_call_method(f,MS_VOLUME_SET_EA_SUSTAIN,&sustain);
1605               
1606        }
1607        parametrize_equalizer(lc,st);
1608        if (lc->vtable.dtmf_received!=NULL){
1609                /* replace by our default action*/
1610                audio_stream_play_received_dtmfs(lc->audiostream,FALSE);
1611                rtp_session_signal_connect(lc->audiostream->session,"telephone-event",(RtpCallback)linphone_core_dtmf_received,(unsigned long)lc);
1612        }
1613}
1614
1615void linphone_core_start_media_streams(LinphoneCore *lc, LinphoneCall *call){
1616        osip_from_t *me=linphone_core_get_primary_contact_parsed(lc);
1617        const char *tool="linphone-" LINPHONE_VERSION;
1618        /* adjust rtp jitter compensation. It must be at least the latency of the sound card */
1619        int jitt_comp=MAX(lc->sound_conf.latency,lc->rtp_conf.audio_jitt_comp);
1620
1621        if (call->media_start_time==0) call->media_start_time=time(NULL);
1622
1623        char *cname=ortp_strdup_printf("%s@%s",me->url->username,me->url->host);
1624        {
1625                StreamParams *audio_params=&call->audio_params;
1626                if (!lc->use_files){
1627                        MSSndCard *playcard=lc->sound_conf.play_sndcard;
1628                        MSSndCard *captcard=lc->sound_conf.capt_sndcard;
1629                        if (playcard==NULL) {
1630                                ms_warning("No card defined for playback !");
1631                                goto end;
1632                        }
1633                        if (captcard==NULL) {
1634                                ms_warning("No card defined for capture !");
1635                                goto end;
1636                        }
1637                        if (audio_params->relay_session_id!=NULL) 
1638                                audio_stream_set_relay_session_id(lc->audiostream,audio_params->relay_session_id);
1639                        audio_stream_start_now(
1640                                lc->audiostream,
1641                                call->profile,
1642                                audio_params->remoteaddr,
1643                                audio_params->remoteport,
1644                                audio_params->remotertcpport,
1645                                audio_params->pt,
1646                                jitt_comp,
1647                                playcard,
1648                                captcard,
1649                                linphone_core_echo_cancelation_enabled(lc));
1650                }else{
1651                        audio_stream_start_with_files(
1652                                lc->audiostream,
1653                                call->profile,
1654                                audio_params->remoteaddr,
1655                                audio_params->remoteport,
1656                                audio_params->remotertcpport,
1657                                audio_params->pt,
1658                                100,
1659                                lc->play_file,
1660                                lc->rec_file);
1661                }
1662                post_configure_audio_streams(lc);       
1663                audio_stream_set_rtcp_information(lc->audiostream, cname, tool);
1664        }
1665#ifdef VIDEO_ENABLED
1666        {
1667                /* shutdown preview */
1668                if (lc->previewstream!=NULL) {
1669                        video_preview_stop(lc->previewstream);
1670                        lc->previewstream=NULL;
1671                }
1672                if (lc->video_conf.display || lc->video_conf.capture) {
1673                        StreamParams *video_params=&call->video_params;
1674                       
1675                        if (video_params->remoteport>0){
1676                                if (video_params->relay_session_id!=NULL) 
1677                                        video_stream_set_relay_session_id(lc->videostream,video_params->relay_session_id);
1678                                video_stream_set_sent_video_size(lc->videostream,linphone_core_get_preferred_video_size(lc));
1679                                video_stream_enable_self_view(lc->videostream,lc->video_conf.selfview);
1680                                if (lc->video_conf.display && lc->video_conf.capture)
1681                                        video_stream_start(lc->videostream,
1682                                        call->profile, video_params->remoteaddr, video_params->remoteport,
1683                                        video_params->remotertcpport,
1684                                        video_params->pt, jitt_comp, lc->video_conf.device);
1685                                else if (lc->video_conf.display)
1686                                        video_stream_recv_only_start(lc->videostream,
1687                                        call->profile, video_params->remoteaddr, video_params->remoteport,
1688                                        video_params->pt, jitt_comp);
1689                                else if (lc->video_conf.capture)
1690                                        video_stream_send_only_start(lc->videostream,
1691                                        call->profile, video_params->remoteaddr, video_params->remoteport,
1692                                        video_params->remotertcpport,
1693                                        video_params->pt, jitt_comp, lc->video_conf.device);
1694                                video_stream_set_rtcp_information(lc->videostream, cname,tool);
1695                        }
1696                }
1697        }
1698#endif
1699        goto end;
1700        end:
1701        ms_free(cname);
1702        osip_from_free(me);
1703        lc->call->state=LCStateAVRunning;
1704}
1705
1706void linphone_core_stop_media_streams(LinphoneCore *lc){
1707        if (lc->audiostream!=NULL) {
1708                audio_stream_stop(lc->audiostream);
1709                lc->audiostream=NULL;
1710        }
1711#ifdef VIDEO_ENABLED
1712        if (lc->videostream!=NULL){
1713                if (lc->video_conf.display && lc->video_conf.capture)
1714                        video_stream_stop(lc->videostream);
1715                else if (lc->video_conf.display)
1716                        video_stream_recv_only_stop(lc->videostream);
1717                else if (lc->video_conf.capture)
1718                        video_stream_send_only_stop(lc->videostream);
1719                lc->videostream=NULL;
1720        }
1721        if (linphone_core_video_preview_enabled(lc)){
1722                if (lc->previewstream==NULL){
1723                        lc->previewstream=video_preview_start(lc->video_conf.device, lc->video_conf.vsize);
1724                }
1725        }
1726#endif
1727}
1728
1729int linphone_core_accept_call(LinphoneCore *lc, const char *url)
1730{
1731        char *sdpmesg;
1732        osip_message_t *msg=NULL;
1733        LinphoneCall *call=lc->call;
1734        int err;
1735        bool_t offering=FALSE;
1736       
1737        if (call==NULL){
1738                return -1;
1739        }
1740       
1741        if (lc->call->state==LCStateAVRunning){
1742                /*call already accepted*/
1743                return -1;
1744        }
1745
1746        /*stop ringing */
1747        if (lc->ringstream!=NULL) {
1748                ms_message("stop ringing");
1749                ring_stop(lc->ringstream);
1750                ms_message("ring stopped");
1751                lc->ringstream=NULL;
1752        }
1753        /* sends a 200 OK */
1754        err=eXosip_call_build_answer(call->tid,200,&msg);
1755        if (err<0 || msg==NULL){
1756                ms_error("Fail to build answer for call: err=%i",err);
1757                return -1;
1758        }
1759        if (lp_config_get_int(lc->config,"sip","use_session_timers",0)==1){
1760                if (call->supports_session_timers) osip_message_set_supported(msg, "timer");
1761        }
1762        /*try to be best-effort in giving real local or routable contact address,
1763        except when the user choosed to override the ipaddress */
1764        if (linphone_core_get_firewall_policy(lc)!=LINPHONE_POLICY_USE_NAT_ADDRESS)
1765                fix_contact(lc,msg,call->localip,NULL);
1766        /*if a sdp answer is computed, send it, else send an offer */
1767        sdpmesg=call->sdpctx->answerstr;
1768        if (sdpmesg==NULL){
1769                offering=TRUE;
1770                ms_message("generating sdp offer");
1771                sdpmesg=sdp_context_get_offer(call->sdpctx);
1772               
1773                if (sdpmesg==NULL){
1774                        ms_error("fail to generate sdp offer !");
1775                        return -1;
1776                }
1777                linphone_set_sdp(msg,sdpmesg);
1778                linphone_core_init_media_streams(lc);
1779        }else{
1780                linphone_set_sdp(msg,sdpmesg);
1781        }
1782        eXosip_lock();
1783        eXosip_call_send_answer(call->tid,200,msg);
1784        eXosip_unlock();
1785        lc->vtable.display_status(lc,_("Connected."));
1786        gstate_new_state(lc, GSTATE_CALL_IN_CONNECTED, NULL);
1787       
1788        if (!offering) linphone_core_start_media_streams(lc, lc->call);
1789        ms_message("call answered.");
1790        return 0;
1791}
1792
1793int linphone_core_terminate_call(LinphoneCore *lc, const char *url)
1794{
1795        LinphoneCall *call=lc->call;
1796        if (call==NULL){
1797                return -1;
1798        }
1799        lc->call=NULL;
1800       
1801        eXosip_lock();
1802        eXosip_call_terminate(call->cid,call->did);
1803        eXosip_unlock();
1804       
1805        /*stop ringing*/
1806        if (lc->ringstream!=NULL) {
1807                ring_stop(lc->ringstream);
1808                lc->ringstream=NULL;
1809        }
1810        linphone_core_stop_media_streams(lc);
1811        lc->vtable.display_status(lc,_("Call ended") );
1812        gstate_new_state(lc, GSTATE_CALL_END, NULL);
1813        linphone_call_destroy(call);
1814        return 0;
1815}
1816
1817bool_t linphone_core_in_call(const LinphoneCore *lc){
1818        return lc->call!=NULL;
1819}
1820
1821int linphone_core_send_publish(LinphoneCore *lc,
1822                               LinphoneOnlineStatus presence_mode)
1823{
1824        const MSList *elem;
1825        for (elem=linphone_core_get_proxy_config_list(lc);elem!=NULL;elem=ms_list_next(elem)){
1826                LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)elem->data;
1827                if (cfg->publish) linphone_proxy_config_send_publish(cfg,presence_mode);
1828        }
1829        return 0;
1830}
1831
1832void linphone_core_set_inc_timeout(LinphoneCore *lc, int seconds){
1833        lc->sip_conf.inc_timeout=seconds;
1834}
1835
1836int linphone_core_get_inc_timeout(LinphoneCore *lc){
1837        return lc->sip_conf.inc_timeout;
1838}
1839
1840void linphone_core_set_presence_info(LinphoneCore *lc,int minutes_away,
1841                                                                                                        const char *contact,
1842                                                                                                        LinphoneOnlineStatus presence_mode)
1843{
1844        int contactok=-1;
1845        if (minutes_away>0) lc->minutes_away=minutes_away;
1846        if (contact!=NULL) {
1847                osip_from_t *url;
1848                osip_from_init(&url);
1849                contactok=osip_from_parse(url,contact);
1850                if (contactok>=0) {
1851                        ms_message("contact url is correct.");
1852                }
1853                osip_from_free(url);
1854               
1855        }
1856        if (contactok>=0){
1857                if (lc->alt_contact!=NULL) ms_free(lc->alt_contact);
1858                lc->alt_contact=ms_strdup(contact);
1859        }
1860        if (lc->presence_mode!=presence_mode){
1861                linphone_core_notify_all_friends(lc,presence_mode);
1862                /*
1863                   Improve the use of all LINPHONE_STATUS available.
1864                   !TODO Do not mix "presence status" with "answer status code"..
1865                   Use correct parameter to follow sip_if_match/sip_etag.
1866                 */
1867                linphone_core_send_publish(lc,presence_mode);
1868        }
1869        lc->prev_mode=lc->presence_mode;
1870        lc->presence_mode=presence_mode;
1871       
1872}
1873
1874LinphoneOnlineStatus linphone_core_get_presence_info(const LinphoneCore *lc){
1875        return lc->presence_mode;
1876}
1877
1878/* sound functions */
1879int linphone_core_get_play_level(LinphoneCore *lc)
1880{
1881        return lc->sound_conf.play_lev;
1882}
1883int linphone_core_get_ring_level(LinphoneCore *lc)
1884{
1885        return lc->sound_conf.ring_lev;
1886}
1887int linphone_core_get_rec_level(LinphoneCore *lc){
1888        return lc->sound_conf.rec_lev;
1889}
1890void linphone_core_set_ring_level(LinphoneCore *lc, int level){
1891        MSSndCard *sndcard;
1892        lc->sound_conf.ring_lev=level;
1893        sndcard=lc->sound_conf.ring_sndcard;
1894        if (sndcard) ms_snd_card_set_level(sndcard,MS_SND_CARD_PLAYBACK,level);
1895}
1896
1897void linphone_core_set_play_level(LinphoneCore *lc, int level){
1898        MSSndCard *sndcard;
1899        lc->sound_conf.play_lev=level;
1900        sndcard=lc->sound_conf.play_sndcard;
1901        if (sndcard) ms_snd_card_set_level(sndcard,MS_SND_CARD_PLAYBACK,level);
1902}
1903
1904void linphone_core_set_rec_level(LinphoneCore *lc, int level)
1905{
1906        MSSndCard *sndcard;
1907        lc->sound_conf.rec_lev=level;
1908        sndcard=lc->sound_conf.capt_sndcard;
1909        if (sndcard) ms_snd_card_set_level(sndcard,MS_SND_CARD_CAPTURE,level);
1910}
1911
1912static MSSndCard *get_card_from_string_id(const char *devid, unsigned int cap){
1913        MSSndCard *sndcard=NULL;
1914        if (devid!=NULL){
1915                sndcard=ms_snd_card_manager_get_card(ms_snd_card_manager_get(),devid);
1916                if (sndcard!=NULL && 
1917                        (ms_snd_card_get_capabilities(sndcard) & cap)==0 ){
1918                        ms_warning("%s card does not have the %s capability, ignoring.",
1919                                devid,
1920                                cap==MS_SND_CARD_CAP_CAPTURE ? "capture" : "playback");
1921                        sndcard=NULL;
1922                }
1923        }
1924        if (sndcard==NULL) {
1925                /* get a card that has read+write capabilities */
1926                sndcard=ms_snd_card_manager_get_default_card(ms_snd_card_manager_get());
1927                /* otherwise refine to the first card having the right capability*/
1928                if (sndcard==NULL){
1929                        const MSList *elem=ms_snd_card_manager_get_list(ms_snd_card_manager_get());
1930                        for(;elem!=NULL;elem=elem->next){
1931                                sndcard=(MSSndCard*)elem->data;
1932                                if (ms_snd_card_get_capabilities(sndcard) & cap) break;
1933                        }
1934                }
1935                if (sndcard==NULL){/*looks like a bug! take the first one !*/
1936                        const MSList *elem=ms_snd_card_manager_get_list(ms_snd_card_manager_get());
1937                        sndcard=(MSSndCard*)elem->data;
1938                }
1939        }
1940        if (sndcard==NULL) ms_error("Could not find a suitable soundcard !");
1941        return sndcard;
1942}
1943
1944bool_t linphone_core_sound_device_can_capture(LinphoneCore *lc, const char *devid){
1945        MSSndCard *sndcard;
1946        sndcard=ms_snd_card_manager_get_card(ms_snd_card_manager_get(),devid);
1947        if (sndcard!=NULL && (ms_snd_card_get_capabilities(sndcard) & MS_SND_CARD_CAP_CAPTURE)) return TRUE;
1948        return FALSE;
1949}
1950
1951bool_t linphone_core_sound_device_can_playback(LinphoneCore *lc, const char *devid){
1952        MSSndCard *sndcard;
1953        sndcard=ms_snd_card_manager_get_card(ms_snd_card_manager_get(),devid);
1954        if (sndcard!=NULL && (ms_snd_card_get_capabilities(sndcard) & MS_SND_CARD_CAP_PLAYBACK)) return TRUE;
1955        return FALSE;
1956}
1957
1958int linphone_core_set_ringer_device(LinphoneCore *lc, const char * devid){
1959        MSSndCard *card=get_card_from_string_id(devid,MS_SND_CARD_CAP_PLAYBACK);
1960        lc->sound_conf.ring_sndcard=card;
1961        if (card && lc->ready)
1962                lp_config_set_string(lc->config,"sound","ringer_dev_id",ms_snd_card_get_string_id(card));
1963        return 0;
1964}
1965
1966int linphone_core_set_playback_device(LinphoneCore *lc, const char * devid){
1967        MSSndCard *card=get_card_from_string_id(devid,MS_SND_CARD_CAP_PLAYBACK);
1968        lc->sound_conf.play_sndcard=card;
1969        if (card && lc->ready)
1970                lp_config_set_string(lc->config,"sound","playback_dev_id",ms_snd_card_get_string_id(card));
1971        return 0;
1972}
1973
1974int linphone_core_set_capture_device(LinphoneCore *lc, const char * devid){
1975        MSSndCard *card=get_card_from_string_id(devid,MS_SND_CARD_CAP_CAPTURE);
1976        lc->sound_conf.capt_sndcard=card;
1977        if (card && lc->ready)
1978                lp_config_set_string(lc->config,"sound","capture_dev_id",ms_snd_card_get_string_id(card));
1979        return 0;
1980}
1981
1982const char * linphone_core_get_ringer_device(LinphoneCore *lc)
1983{
1984        if (lc->sound_conf.ring_sndcard) return ms_snd_card_get_string_id(lc->sound_conf.ring_sndcard);
1985        return NULL;
1986}
1987
1988const char * linphone_core_get_playback_device(LinphoneCore *lc)
1989{
1990        return lc->sound_conf.play_sndcard ? ms_snd_card_get_string_id(lc->sound_conf.play_sndcard) : NULL;
1991}
1992
1993const char * linphone_core_get_capture_device(LinphoneCore *lc)
1994{
1995        return lc->sound_conf.capt_sndcard ? ms_snd_card_get_string_id(lc->sound_conf.capt_sndcard) : NULL;
1996}
1997
1998/* returns a static array of string describing the sound devices */ 
1999const char**  linphone_core_get_sound_devices(LinphoneCore *lc){
2000        build_sound_devices_table(lc);
2001        return lc->sound_conf.cards;
2002}
2003
2004const char**  linphone_core_get_video_devices(const LinphoneCore *lc){
2005        return lc->video_conf.cams;
2006}
2007
2008char linphone_core_get_sound_source(LinphoneCore *lc)
2009{
2010        return lc->sound_conf.source;
2011}
2012
2013void linphone_core_set_sound_source(LinphoneCore *lc, char source)
2014{
2015        MSSndCard *sndcard=lc->sound_conf.capt_sndcard;
2016        lc->sound_conf.source=source;
2017        if (!sndcard) return;
2018        switch(source){
2019                case 'm':
2020                        ms_snd_card_set_capture(sndcard,MS_SND_CARD_MIC);
2021                        break;
2022                case 'l':
2023                        ms_snd_card_set_capture(sndcard,MS_SND_CARD_LINE);
2024                        break;
2025        }
2026       
2027}
2028
2029void linphone_core_set_ring(LinphoneCore *lc,const char *path){
2030        if (lc->sound_conf.local_ring!=0){
2031                ms_free(lc->sound_conf.local_ring);
2032        }
2033        lc->sound_conf.local_ring=ms_strdup(path);
2034        if (lc->ready && lc->sound_conf.local_ring)
2035                lp_config_set_string(lc->config,"sound","local_ring",lc->sound_conf.local_ring);
2036}
2037
2038const char *linphone_core_get_ring(const LinphoneCore *lc){
2039        return lc->sound_conf.local_ring;
2040}
2041
2042static void notify_end_of_ring(void *ud ,unsigned int event, void * arg){
2043        LinphoneCore *lc=(LinphoneCore*)ud;
2044        lc->preview_finished=1;
2045}
2046
2047int linphone_core_preview_ring(LinphoneCore *lc, const char *ring,LinphoneCoreCbFunc func,void * userdata)
2048{
2049        if (lc->ringstream!=0){
2050                ms_warning("Cannot start ring now,there's already a ring being played");
2051                return -1;
2052        }
2053        lc_callback_obj_init(&lc->preview_finished_cb,func,userdata);
2054        lc->preview_finished=0;
2055        if (lc->sound_conf.ring_sndcard!=NULL){
2056                lc->ringstream=ring_start_with_cb(ring,2000,lc->sound_conf.ring_sndcard,notify_end_of_ring,(void *)lc);
2057        }
2058        return 0;
2059}
2060
2061
2062void linphone_core_set_ringback(LinphoneCore *lc, const char *path){
2063        if (lc->sound_conf.remote_ring!=0){
2064                ms_free(lc->sound_conf.remote_ring);
2065        }
2066        lc->sound_conf.remote_ring=ms_strdup(path);
2067}
2068
2069const char * linphone_core_get_ringback(const LinphoneCore *lc){
2070        return lc->sound_conf.remote_ring;
2071}
2072
2073void linphone_core_enable_echo_cancelation(LinphoneCore *lc, bool_t val){
2074        lc->sound_conf.ec=val;
2075        if (lc->ready)
2076                lp_config_set_int(lc->config,"sound","echocancelation",val);
2077}
2078
2079bool_t linphone_core_echo_cancelation_enabled(LinphoneCore *lc){
2080        return lc->sound_conf.ec;
2081}
2082
2083void linphone_core_enable_echo_limiter(LinphoneCore *lc, bool_t val){
2084        lc->sound_conf.ea=val;
2085}
2086
2087bool_t linphone_core_echo_limiter_enabled(const LinphoneCore *lc){
2088        return lc->sound_conf.ea;
2089}
2090
2091void linphone_core_mute_mic(LinphoneCore *lc, bool_t val){
2092        if (lc->audiostream!=NULL){
2093                 audio_stream_set_mic_gain(lc->audiostream,
2094                        (val==TRUE) ? 0 : 1.0);
2095        }
2096}
2097
2098void linphone_core_enable_agc(LinphoneCore *lc, bool_t val){
2099        lc->sound_conf.agc=val;
2100}
2101
2102bool_t linphone_core_agc_enabled(const LinphoneCore *lc){
2103        return lc->sound_conf.agc;
2104}
2105
2106
2107void linphone_core_send_dtmf(LinphoneCore *lc,char dtmf)
2108{
2109        if (linphone_core_get_use_info_for_dtmf(lc)==0){
2110                /* In Band DTMF */
2111                if (lc->audiostream!=NULL){
2112                        audio_stream_send_dtmf(lc->audiostream,dtmf);
2113                }
2114        }else{
2115                char dtmf_body[1000];
2116                char clen[10];
2117                osip_message_t *msg=NULL;
2118                /* Out of Band DTMF (use INFO method) */
2119                LinphoneCall *call=lc->call;
2120                if (call==NULL){
2121                        return;
2122                }
2123                eXosip_call_build_info(call->did,&msg);
2124                snprintf(dtmf_body, 999, "Signal=%c\r\nDuration=250\r\n", dtmf);
2125                osip_message_set_body(msg,dtmf_body,strlen(dtmf_body));
2126                osip_message_set_content_type(msg,"application/dtmf-relay");
2127                snprintf(clen,sizeof(clen),"%lu",(unsigned long)strlen(dtmf_body));
2128                osip_message_set_content_length(msg,clen);
2129               
2130                eXosip_lock();
2131                eXosip_call_send_request(call->did,msg);
2132                eXosip_unlock();
2133        }
2134}
2135
2136void linphone_core_set_stun_server(LinphoneCore *lc, const char *server){
2137        if (lc->net_conf.stun_server!=NULL)
2138                ms_free(lc->net_conf.stun_server);
2139        if (server)
2140                lc->net_conf.stun_server=ms_strdup(server);
2141        else lc->net_conf.stun_server=NULL;
2142        lc->apply_nat_settings=TRUE;
2143}
2144
2145const char * linphone_core_get_stun_server(const LinphoneCore *lc){
2146        return lc->net_conf.stun_server;
2147}
2148
2149const char * linphone_core_get_relay_addr(const LinphoneCore *lc){
2150        return lc->net_conf.relay;
2151}
2152
2153int linphone_core_set_relay_addr(LinphoneCore *lc, const char *addr){
2154        if (lc->net_conf.relay!=NULL){
2155                ms_free(lc->net_conf.relay);
2156                lc->net_conf.relay=NULL;
2157        }
2158        if (addr){
2159                lc->net_conf.relay=ms_strdup(addr);
2160        }
2161        return 0;
2162}
2163
2164static void apply_nat_settings(LinphoneCore *lc){
2165        char *wmsg;
2166        char *tmp=NULL;
2167        int err;
2168        struct addrinfo hints,*res;
2169        const char *addr=lc->net_conf.nat_address;
2170       
2171        if (lc->net_conf.firewall_policy==LINPHONE_POLICY_USE_NAT_ADDRESS){
2172                if (addr==NULL || strlen(addr)==0){
2173                        lc->vtable.display_warning(lc,_("No nat/firewall address supplied !"));
2174                        linphone_core_set_firewall_policy(lc,LINPHONE_POLICY_NO_FIREWALL);
2175                }
2176                /*check the ip address given */
2177                memset(&hints,0,sizeof(struct addrinfo));
2178                if (lc->sip_conf.ipv6_enabled)
2179                        hints.ai_family=AF_INET6;
2180                else 
2181                        hints.ai_family=AF_INET;
2182                hints.ai_socktype = SOCK_DGRAM;
2183                err=getaddrinfo(addr,NULL,&hints,&res);
2184                if (err!=0){
2185                        wmsg=ortp_strdup_printf(_("Invalid nat address '%s' : %s"),
2186                                addr, gai_strerror(err));
2187                        ms_warning(wmsg); // what is this for ?
2188                        lc->vtable.display_warning(lc, wmsg);
2189                        ms_free(wmsg);
2190                        linphone_core_set_firewall_policy(lc,LINPHONE_POLICY_NO_FIREWALL);
2191                        return;
2192                }
2193                /*now get it as an numeric ip address */
2194                tmp=ms_malloc0(50);
2195                err=getnameinfo(res->ai_addr,res->ai_addrlen,tmp,50,NULL,0,NI_NUMERICHOST);
2196                if (err!=0){
2197                        wmsg=ortp_strdup_printf(_("Invalid nat address '%s' : %s"),
2198                                addr, gai_strerror(err));
2199                        ms_warning(wmsg); // what is this for ?
2200                        lc->vtable.display_warning(lc, wmsg);
2201                        ms_free(wmsg);
2202                        ms_free(tmp);
2203                        freeaddrinfo(res);
2204                        linphone_core_set_firewall_policy(lc,LINPHONE_POLICY_NO_FIREWALL);
2205                        return;
2206                }
2207                freeaddrinfo(res);
2208        }
2209
2210        if (lc->net_conf.firewall_policy==LINPHONE_POLICY_USE_NAT_ADDRESS){
2211                if (tmp!=NULL){
2212                        if (!lc->net_conf.nat_sdp_only){
2213                                eXosip_set_option(EXOSIP_OPT_SET_IPV4_FOR_GATEWAY,tmp);
2214                                /* the following does not work in all cases */
2215                                /*
2216                                eXosip_masquerade_contact(tmp,lc->sip_conf.sip_port);
2217                                */
2218                        }
2219                        ms_free(tmp);
2220                }
2221                else{
2222                        eXosip_set_option(EXOSIP_OPT_SET_IPV4_FOR_GATEWAY,NULL);
2223                        eXosip_masquerade_contact("",0);
2224                }
2225        }
2226        else {
2227                eXosip_set_option(EXOSIP_OPT_SET_IPV4_FOR_GATEWAY,NULL);
2228                eXosip_masquerade_contact("",0);       
2229        }
2230}
2231
2232
2233void linphone_core_set_nat_address(LinphoneCore *lc, const char *addr)
2234{
2235        if (lc->net_conf.nat_address!=NULL){
2236                ms_free(lc->net_conf.nat_address);
2237        }
2238        if (addr!=NULL) lc->net_conf.nat_address=ms_strdup(addr);
2239        else lc->net_conf.nat_address=NULL;
2240        lc->apply_nat_settings=TRUE;
2241}
2242
2243const char *linphone_core_get_nat_address(const LinphoneCore *lc)
2244{
2245        return lc->net_conf.nat_address;
2246}
2247
2248void linphone_core_set_firewall_policy(LinphoneCore *lc, LinphoneFirewallPolicy pol){
2249        lc->net_conf.firewall_policy=pol;
2250        lc->apply_nat_settings=TRUE;
2251}
2252
2253LinphoneFirewallPolicy linphone_core_get_firewall_policy(const LinphoneCore *lc){
2254        return lc->net_conf.firewall_policy;
2255}
2256
2257MSList * linphone_core_get_call_logs(LinphoneCore *lc){
2258        lc->missed_calls=0;
2259        return lc->call_logs;
2260}
2261
2262static void toggle_video_preview(LinphoneCore *lc, bool_t val){
2263#ifdef VIDEO_ENABLED
2264        if (lc->videostream==NULL){
2265                if (val){
2266                        if (lc->previewstream==NULL){
2267                                lc->previewstream=video_preview_start(lc->video_conf.device,
2268                                                        lc->video_conf.vsize);
2269                        }
2270                }else{
2271                        if (lc->previewstream!=NULL){
2272                                video_preview_stop(lc->previewstream);
2273                                lc->previewstream=NULL;
2274                        }
2275                }
2276        }
2277#endif
2278}
2279
2280void linphone_core_enable_video(LinphoneCore *lc, bool_t vcap_enabled, bool_t display_enabled){
2281#ifndef VIDEO_ENABLED
2282        if (vcap_enabled || display_enabled)
2283                ms_warning("This version of linphone was built without video support.");
2284#endif
2285        lc->video_conf.capture=vcap_enabled;
2286        lc->video_conf.display=display_enabled;
2287
2288        if (lc->ready){
2289                lp_config_set_int(lc->config,"video","display",display_enabled);
2290                lp_config_set_int(lc->config,"video","capture",vcap_enabled);
2291        }
2292
2293        /* need to re-apply network bandwidth settings*/
2294        linphone_core_set_download_bandwidth(lc,
2295                linphone_core_get_download_bandwidth(lc));
2296        linphone_core_set_upload_bandwidth(lc,
2297                linphone_core_get_upload_bandwidth(lc));
2298}
2299
2300bool_t linphone_core_video_enabled(LinphoneCore *lc){
2301        return (lc->video_conf.display || lc->video_conf.capture);
2302}
2303
2304void linphone_core_enable_video_preview(LinphoneCore *lc, bool_t val){
2305        lc->video_conf.show_local=val;
2306        if (lc->ready) lp_config_set_int(lc->config,"video","show_local",val);
2307}
2308
2309bool_t linphone_core_video_preview_enabled(const LinphoneCore *lc){
2310        return lc->video_conf.show_local;
2311}
2312
2313void linphone_core_enable_self_view(LinphoneCore *lc, bool_t val){
2314        lc->video_conf.selfview=val;
2315#ifdef VIDEO_ENABLED
2316        if (lc->videostream){
2317                video_stream_enable_self_view(lc->videostream,val);
2318        }
2319#endif
2320}
2321
2322bool_t linphone_core_self_view_enabled(const LinphoneCore *lc){
2323        return lc->video_conf.selfview;
2324}
2325
2326int linphone_core_set_video_device(LinphoneCore *lc, const char *id){
2327        MSWebCam *olddev=lc->video_conf.device;
2328        const char *vd;
2329        if (id!=NULL){
2330                lc->video_conf.device=ms_web_cam_manager_get_cam(ms_web_cam_manager_get(),id);
2331                if (lc->video_conf.device==NULL){
2332                        ms_warning("Could not found video device %s",id);
2333                }
2334        }
2335        if (lc->video_conf.device==NULL)
2336                lc->video_conf.device=ms_web_cam_manager_get_default_cam(ms_web_cam_manager_get());
2337        if (olddev!=NULL && olddev!=lc->video_conf.device){
2338                toggle_video_preview(lc,FALSE);/*restart the video local preview*/
2339        }
2340        if (lc->ready && lc->video_conf.device){
2341                vd=ms_web_cam_get_string_id(lc->video_conf.device);
2342                if (vd && strstr(vd,"Static picture")!=NULL){
2343                        vd=NULL;
2344                }
2345                lp_config_set_string(lc->config,"video","device",vd);
2346        }
2347        return 0;
2348}
2349
2350const char *linphone_core_get_video_device(const LinphoneCore *lc){
2351        if (lc->video_conf.device) return ms_web_cam_get_string_id(lc->video_conf.device);
2352        return NULL;
2353}
2354
2355unsigned long linphone_core_get_native_video_window_id(const LinphoneCore *lc){
2356#ifdef VIDEO_ENABLED
2357        if (lc->videostream)
2358                return video_stream_get_native_window_id(lc->videostream);
2359        if (lc->previewstream)
2360                return video_stream_get_native_window_id(lc->previewstream);
2361#endif
2362        return 0;
2363}
2364
2365static MSVideoSizeDef supported_resolutions[]={
2366        {       MS_VIDEO_SIZE_SVGA      ,       "svga"  },
2367        {       MS_VIDEO_SIZE_4CIF      ,       "4cif"  },
2368        {       MS_VIDEO_SIZE_VGA       ,       "vga"   },
2369        {       MS_VIDEO_SIZE_CIF       ,       "cif"   },
2370        {       MS_VIDEO_SIZE_QVGA      ,       "qvga"  },
2371        {       MS_VIDEO_SIZE_QCIF      ,       "qcif"  },
2372        {       {0,0}                   ,       NULL    }
2373};
2374
2375const MSVideoSizeDef *linphone_core_get_supported_video_sizes(LinphoneCore *lc){
2376        return supported_resolutions;
2377}
2378
2379static MSVideoSize video_size_get_by_name(const char *name){
2380        MSVideoSizeDef *pdef=supported_resolutions;
2381        for(;pdef->name!=NULL;pdef++){
2382                if (strcasecmp(name,pdef->name)==0){
2383                        return pdef->vsize;
2384                }
2385        }
2386        ms_warning("Video resolution %s is not supported in linphone.",name);
2387        return (MSVideoSize){0,0};
2388}
2389
2390const char *video_size_get_name(MSVideoSize vsize){
2391        MSVideoSizeDef *pdef=supported_resolutions;
2392        for(;pdef->name!=NULL;pdef++){
2393                if (pdef->vsize.width==vsize.width && pdef->vsize.height==vsize.height){
2394                        return pdef->name;
2395                }
2396        }
2397        return NULL;
2398}
2399
2400static bool_t video_size_supported(MSVideoSize vsize){
2401        if (video_size_get_name(vsize)) return TRUE;
2402        ms_warning("Video resolution %ix%i is not supported in linphone.",vsize.width,vsize.height);
2403        return FALSE;
2404}
2405
2406
2407void linphone_core_set_preferred_video_size(LinphoneCore *lc, MSVideoSize vsize){
2408        if (video_size_supported(vsize)){
2409                MSVideoSize oldvsize=lc->video_conf.vsize;
2410                lc->video_conf.vsize=vsize;
2411                if (!ms_video_size_equal(oldvsize,vsize) && lc->previewstream!=NULL){
2412                        toggle_video_preview(lc,FALSE);
2413                        toggle_video_preview(lc,TRUE);
2414                }
2415                if (lc->ready)
2416                        lp_config_set_string(lc->config,"video","size",video_size_get_name(vsize));
2417        }
2418}
2419
2420void linphone_core_set_preferred_video_size_by_name(LinphoneCore *lc, const char *name){
2421        MSVideoSize vsize=video_size_get_by_name(name);
2422        if (vsize.width!=0)     linphone_core_set_preferred_video_size(lc,vsize);
2423        else linphone_core_set_preferred_video_size(lc,MS_VIDEO_SIZE_CIF);
2424}
2425
2426MSVideoSize linphone_core_get_preferred_video_size(LinphoneCore *lc){
2427        return lc->video_conf.vsize;
2428}
2429
2430void linphone_core_use_files(LinphoneCore *lc, bool_t yesno){
2431        lc->use_files=yesno;
2432}
2433
2434void linphone_core_set_play_file(LinphoneCore *lc, const char *file){
2435        if (lc->play_file!=NULL){
2436                ms_free(lc->play_file);
2437                lc->play_file=NULL;
2438        }
2439        if (file!=NULL) {
2440                lc->play_file=ms_strdup(file);
2441                if (lc->audiostream)
2442                        audio_stream_play(lc->audiostream,file);
2443        }
2444}
2445
2446void linphone_core_set_record_file(LinphoneCore *lc, const char *file){
2447        if (lc->rec_file!=NULL){
2448                ms_free(lc->rec_file);
2449                lc->rec_file=NULL;
2450        }
2451        if (file!=NULL) {
2452                lc->rec_file=ms_strdup(file);
2453                if (lc->audiostream) 
2454                        audio_stream_record(lc->audiostream,file);
2455        }
2456}
2457
2458
2459void *linphone_core_get_user_data(LinphoneCore *lc){
2460        return lc->data;
2461}
2462
2463int linphone_core_get_mtu(const LinphoneCore *lc){
2464        return lc->net_conf.mtu;
2465}
2466
2467void linphone_core_set_mtu(LinphoneCore *lc, int mtu){
2468        lc->net_conf.mtu=mtu;
2469        if (mtu>0){
2470                if (mtu<500){
2471                        ms_error("MTU too small !");
2472                        mtu=500;
2473                }
2474                ms_set_mtu(mtu);
2475                ms_message("MTU is supposed to be %i, rtp payload max size will be %i",mtu, ms_get_payload_max_size());
2476        }else ms_set_mtu(0);//use mediastreamer2 default value
2477}
2478
2479void linphone_core_set_waiting_callback(LinphoneCore *lc, LinphoneWaitingCallback cb, void *user_context){
2480        lc->wait_cb=cb;
2481        lc->wait_ctx=user_context;
2482}
2483
2484void linphone_core_start_waiting(LinphoneCore *lc, const char *purpose){
2485        if (lc->wait_cb){
2486                lc->wait_ctx=lc->wait_cb(lc,lc->wait_ctx,LinphoneWaitingStart,purpose,0);
2487        }
2488}
2489
2490void linphone_core_update_progress(LinphoneCore *lc, const char *purpose, float progress){
2491        if (lc->wait_cb){
2492                lc->wait_ctx=lc->wait_cb(lc,lc->wait_ctx,LinphoneWaitingProgress,purpose,progress);
2493        }else{
2494#ifdef WIN32
2495                Sleep(50000);
2496#else
2497                usleep(50000);
2498#endif
2499        }
2500}
2501
2502void linphone_core_stop_waiting(LinphoneCore *lc){
2503        if (lc->wait_cb){
2504                lc->wait_ctx=lc->wait_cb(lc,lc->wait_ctx,LinphoneWaitingFinished,NULL,0);
2505        }
2506}
2507
2508void net_config_uninit(LinphoneCore *lc)
2509{
2510        net_config_t *config=&lc->net_conf;
2511        lp_config_set_int(lc->config,"net","download_bw",config->download_bw);
2512        lp_config_set_int(lc->config,"net","upload_bw",config->upload_bw);
2513       
2514        if (config->stun_server!=NULL)
2515                lp_config_set_string(lc->config,"net","stun_server",config->stun_server);
2516        if (config->nat_address!=NULL)
2517                lp_config_set_string(lc->config,"net","nat_address",config->nat_address);
2518        lp_config_set_int(lc->config,"net","firewall_policy",config->firewall_policy);
2519        lp_config_set_int(lc->config,"net","mtu",config->mtu);
2520}
2521
2522
2523void sip_config_uninit(LinphoneCore *lc)
2524{
2525        MSList *elem;
2526        int i;
2527        sip_config_t *config=&lc->sip_conf;
2528        lp_config_set_int(lc->config,"sip","sip_port",config->sip_port);
2529        lp_config_set_int(lc->config,"sip","guess_hostname",config->guess_hostname);
2530        lp_config_set_string(lc->config,"sip","contact",config->contact);
2531        lp_config_set_int(lc->config,"sip","inc_timeout",config->inc_timeout);
2532        lp_config_set_int(lc->config,"sip","use_info",config->use_info);
2533        lp_config_set_int(lc->config,"sip","use_ipv6",config->ipv6_enabled);
2534        lp_config_set_int(lc->config,"sip","register_only_when_network_is_up",config->register_only_when_network_is_up);
2535        for(elem=config->proxies,i=0;elem!=NULL;elem=ms_list_next(elem),i++){
2536                LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)(elem->data);
2537                linphone_proxy_config_write_to_config_file(lc->config,cfg,i);
2538                linphone_proxy_config_edit(cfg);        /* to unregister */
2539        }
2540
2541        if (exosip_running)
2542          {
2543            int i;
2544            for (i=0;i<20;i++)
2545              {
2546                eXosip_event_t *ev;
2547                while((ev=eXosip_event_wait(0,0))!=NULL){
2548                  linphone_core_process_event(lc,ev);
2549                }
2550                eXosip_automatic_action();
2551#ifndef WIN32
2552                usleep(100000);
2553#else
2554        Sleep(100);
2555#endif
2556              }
2557          }
2558       
2559        linphone_proxy_config_write_to_config_file(lc->config,NULL,i);  /*mark the end */
2560       
2561        for(elem=lc->auth_info,i=0;elem!=NULL;elem=ms_list_next(elem),i++){
2562                LinphoneAuthInfo *ai=(LinphoneAuthInfo*)(elem->data);
2563                linphone_auth_info_write_config(lc->config,ai,i);
2564        }
2565        linphone_auth_info_write_config(lc->config,NULL,i); /* mark the end */
2566}
2567
2568void rtp_config_uninit(LinphoneCore *lc)
2569{
2570        rtp_config_t *config=&lc->rtp_conf;
2571        lp_config_set_int(lc->config,"rtp","audio_rtp_port",config->audio_rtp_port);
2572        lp_config_set_int(lc->config,"rtp","video_rtp_port",config->video_rtp_port);
2573        lp_config_set_int(lc->config,"rtp","audio_jitt_comp",config->audio_jitt_comp);
2574        lp_config_set_int(lc->config,"rtp","video_jitt_comp",config->audio_jitt_comp);
2575        lp_config_set_int(lc->config,"rtp","nortp_timeout",config->nortp_timeout);
2576}
2577
2578void sound_config_uninit(LinphoneCore *lc)
2579{
2580        sound_config_t *config=&lc->sound_conf;
2581        ms_free(config->cards);
2582       
2583        lp_config_set_string(lc->config,"sound","remote_ring",config->remote_ring);
2584       
2585        if (config->local_ring) ms_free(config->local_ring);
2586        if (config->remote_ring) ms_free(config->remote_ring);
2587        ms_snd_card_manager_destroy();
2588}
2589
2590void video_config_uninit(LinphoneCore *lc)
2591{
2592               
2593}
2594
2595void codecs_config_uninit(LinphoneCore *lc)
2596{
2597        PayloadType *pt;
2598        codecs_config_t *config=&lc->codecs_conf;
2599        MSList *node;
2600        char key[50];
2601        int index;
2602        index=0;
2603        for(node=config->audio_codecs;node!=NULL;node=ms_list_next(node)){
2604                pt=(PayloadType*)(node->data);
2605                sprintf(key,"audio_codec_%i",index);
2606                lp_config_set_string(lc->config,key,"mime",pt->mime_type);
2607                lp_config_set_int(lc->config,key,"rate",pt->clock_rate);
2608                lp_config_set_int(lc->config,key,"enabled",payload_type_enabled(pt));
2609                index++;
2610        }
2611        index=0;
2612        for(node=config->video_codecs;node!=NULL;node=ms_list_next(node)){
2613                pt=(PayloadType*)(node->data);
2614                sprintf(key,"video_codec_%i",index);
2615                lp_config_set_string(lc->config,key,"mime",pt->mime_type);
2616                lp_config_set_int(lc->config,key,"rate",pt->clock_rate);
2617                lp_config_set_int(lc->config,key,"enabled",payload_type_enabled(pt));
2618                lp_config_set_string(lc->config,key,"recv_fmtp",pt->recv_fmtp);
2619                index++;
2620        }
2621}
2622
2623void ui_config_uninit(LinphoneCore* lc)
2624{
2625        if (lc->friends){
2626                ms_list_for_each(lc->friends,(void (*)(void *))linphone_friend_destroy);
2627                ms_list_free(lc->friends);
2628                lc->friends=NULL;
2629        }
2630}
2631
2632LpConfig *linphone_core_get_config(LinphoneCore *lc){
2633        return lc->config;
2634}
2635
2636void linphone_core_uninit(LinphoneCore *lc)
2637{
2638        if (lc->call){
2639                int i;
2640                linphone_core_terminate_call(lc,NULL);
2641                for(i=0;i<10;++i){
2642#ifndef WIN32
2643                        usleep(50000);
2644#else
2645                        Sleep(50);
2646#endif
2647                        linphone_core_iterate(lc);
2648                }
2649        }
2650        gstate_new_state(lc, GSTATE_POWER_SHUTDOWN, NULL);
2651#ifdef VIDEO_ENABLED
2652        if (lc->previewstream!=NULL){
2653                video_preview_stop(lc->previewstream);
2654                lc->previewstream=NULL;
2655        }
2656#endif
2657        /* save all config */
2658        net_config_uninit(lc);
2659        sip_config_uninit(lc);
2660        lp_config_set_int(lc->config,"sip","default_proxy",linphone_core_get_default_proxy(lc,NULL));
2661        rtp_config_uninit(lc);
2662        sound_config_uninit(lc);
2663        video_config_uninit(lc);
2664        codecs_config_uninit(lc);
2665        ui_config_uninit(lc);
2666        if (lp_config_needs_commit(lc->config)) lp_config_sync(lc->config);
2667        lp_config_destroy(lc->config);
2668        sip_setup_unregister_all();
2669#ifdef VIDEO_ENABLED
2670        if (payload_type_h264_packetization_mode_1!=NULL)
2671                payload_type_destroy(payload_type_h264_packetization_mode_1);
2672#endif
2673       
2674        ortp_exit();
2675        eXosip_quit();
2676        exosip_running=FALSE;
2677        gstate_new_state(lc, GSTATE_POWER_OFF, NULL);
2678}
2679
2680void linphone_core_destroy(LinphoneCore *lc){
2681        linphone_core_uninit(lc);
2682        ms_free(lc);
2683}
Note: See TracBrowser for help on using the repository browser.