]> sjero.net Git - linphone/blob - coreapi/linphonecall.c
Send ZRTP hello hash in SIP SDP.
[linphone] / coreapi / linphonecall.c
1
2 /*
3 linphone
4 Copyright (C) 2010  Belledonne Communications SARL
5  (simon.morlat@linphone.org)
6
7 This program is free software; you can redistribute it and/or
8 modify it under the terms of the GNU General Public License
9 as published by the Free Software Foundation; either version 2
10 of the License, or (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
20 */
21 #ifdef WIN32
22 #include <time.h>
23 #endif
24 #include "linphonecore.h"
25 #include "sipsetup.h"
26 #include "lpconfig.h"
27 #include "private.h"
28 #include <ortp/event.h>
29 #include <ortp/b64.h>
30 #include <math.h>
31
32 #include "mediastreamer2/mediastream.h"
33 #include "mediastreamer2/msvolume.h"
34 #include "mediastreamer2/msequalizer.h"
35 #include "mediastreamer2/msfileplayer.h"
36 #include "mediastreamer2/msjpegwriter.h"
37 #include "mediastreamer2/mseventqueue.h"
38 #include "mediastreamer2/mssndcard.h"
39
40 #ifdef VIDEO_ENABLED
41 static MSWebCam *get_nowebcam_device(){
42         return ms_web_cam_manager_get_cam(ms_web_cam_manager_get(),"StaticImage: Static picture");
43 }
44 #endif
45
46 static bool_t generate_b64_crypto_key(int key_length, char* key_out) {
47         int b64_size;
48         uint8_t* tmp = (uint8_t*) malloc(key_length);                   
49         if (ortp_crypto_get_random(tmp, key_length)!=0) {
50                 ms_error("Failed to generate random key");
51                 free(tmp);
52                 return FALSE;
53         }
54         
55         b64_size = b64_encode((const char*)tmp, key_length, NULL, 0);
56         if (b64_size == 0) {
57                 ms_error("Failed to b64 encode key");
58                 free(tmp);
59                 return FALSE;
60         }
61         key_out[b64_size] = '\0';
62         b64_encode((const char*)tmp, key_length, key_out, 40);
63         free(tmp);
64         return TRUE;
65 }
66
67 LinphoneCore *linphone_call_get_core(const LinphoneCall *call){
68         return call->core;
69 }
70
71 const char* linphone_call_get_authentication_token(LinphoneCall *call){
72         return call->auth_token;
73 }
74
75 bool_t linphone_call_get_authentication_token_verified(LinphoneCall *call){
76         return call->auth_token_verified;
77 }
78
79 static bool_t linphone_call_are_all_streams_encrypted(LinphoneCall *call) {
80         // Check ZRTP encryption in audiostream
81         if (!call->audiostream_encrypted) {
82                 return FALSE;
83         }
84
85 #ifdef VIDEO_ENABLED
86         // If video enabled, check ZRTP encryption in videostream
87         const LinphoneCallParams *params=linphone_call_get_current_params(call);
88         if (params->has_video && !call->videostream_encrypted) {
89                 return FALSE;
90         }
91 #endif
92
93         return TRUE;
94 }
95
96 void propagate_encryption_changed(LinphoneCall *call){
97         LinphoneCore *lc=call->core;
98         if (!linphone_call_are_all_streams_encrypted(call)) {
99                 ms_message("Some streams are not encrypted");
100                 call->current_params.media_encryption=LinphoneMediaEncryptionNone;
101                 if (lc->vtable.call_encryption_changed)
102                         lc->vtable.call_encryption_changed(call->core, call, FALSE, call->auth_token);
103         } else {
104                 ms_message("All streams are encrypted");
105                 call->current_params.media_encryption=LinphoneMediaEncryptionZRTP;
106                 if (lc->vtable.call_encryption_changed)
107                         lc->vtable.call_encryption_changed(call->core, call, TRUE, call->auth_token);
108         }
109 }
110
111 #ifdef VIDEO_ENABLED
112 static void linphone_call_videostream_encryption_changed(void *data, bool_t encrypted){
113         ms_message("Video stream is %s", encrypted ? "encrypted" : "not encrypted");
114
115         LinphoneCall *call = (LinphoneCall *)data;
116         call->videostream_encrypted=encrypted;
117         propagate_encryption_changed(call);
118 }
119 #endif
120
121 static void linphone_call_audiostream_encryption_changed(void *data, bool_t encrypted) {
122         char status[255]={0};
123         ms_message("Audio stream is %s ", encrypted ? "encrypted" : "not encrypted");
124
125         LinphoneCall *call = (LinphoneCall *)data;
126         call->audiostream_encrypted=encrypted;
127         
128         if (encrypted && call->core->vtable.display_status != NULL) {
129                 snprintf(status,sizeof(status)-1,_("Authentication token is %s"),call->auth_token);
130                  call->core->vtable.display_status(call->core, status);
131         }
132
133         propagate_encryption_changed(call);
134
135
136 #ifdef VIDEO_ENABLED
137         // Enable video encryption
138         const LinphoneCallParams *params=linphone_call_get_current_params(call);
139         if (params->has_video) {
140                 ms_message("Trying to enable encryption on video stream");
141                 OrtpZrtpParams params;
142                 params.zid_file=NULL; //unused
143                 video_stream_enable_zrtp(call->videostream,call->audiostream,&params);
144         }
145 #endif
146 }
147
148
149 static void linphone_call_audiostream_auth_token_ready(void *data, const char* auth_token, bool_t verified) {
150         LinphoneCall *call=(LinphoneCall *)data;
151         if (call->auth_token != NULL)
152                 ms_free(call->auth_token);
153
154         call->auth_token=ms_strdup(auth_token);
155         call->auth_token_verified=verified;
156
157         ms_message("Authentication token is %s (%s)", auth_token, verified?"verified":"unverified");
158 }
159
160 void linphone_call_set_authentication_token_verified(LinphoneCall *call, bool_t verified){
161         if (call->audiostream==NULL){
162                 ms_error("linphone_call_set_authentication_token_verified(): No audio stream");
163         }
164         if (call->audiostream->ms.zrtp_context==NULL){
165                 ms_error("linphone_call_set_authentication_token_verified(): No zrtp context.");
166         }
167         if (!call->auth_token_verified && verified){
168                 ortp_zrtp_sas_verified(call->audiostream->ms.zrtp_context);
169         }else if (call->auth_token_verified && !verified){
170                 ortp_zrtp_sas_reset_verified(call->audiostream->ms.zrtp_context);
171         }
172         call->auth_token_verified=verified;
173         propagate_encryption_changed(call);
174 }
175
176 static MSList *make_codec_list(LinphoneCore *lc, const MSList *codecs, int bandwidth_limit,int* max_sample_rate, int nb_codecs_limit){
177         MSList *l=NULL;
178         const MSList *it;
179         int nb = 0;
180         if (max_sample_rate) *max_sample_rate=0;
181         for(it=codecs;it!=NULL;it=it->next){
182                 PayloadType *pt=(PayloadType*)it->data;
183                 if (pt->flags & PAYLOAD_TYPE_ENABLED){
184                         if (bandwidth_limit>0 && !linphone_core_is_payload_type_usable_for_bandwidth(lc,pt,bandwidth_limit)){
185                                 ms_message("Codec %s/%i eliminated because of audio bandwidth constraint.",pt->mime_type,pt->clock_rate);
186                                 continue;
187                         }
188                         if (linphone_core_check_payload_type_usability(lc,pt)){
189                                 l=ms_list_append(l,payload_type_clone(pt));
190                                 nb++;
191                                 if (max_sample_rate && payload_type_get_rate(pt)>*max_sample_rate) *max_sample_rate=payload_type_get_rate(pt);
192                         }
193                 }
194                 if ((nb_codecs_limit > 0) && (nb >= nb_codecs_limit)) break;
195         }
196         return l;
197 }
198
199 static void update_media_description_from_stun(SalMediaDescription *md, const StunCandidate *ac, const StunCandidate *vc){
200         int i;
201         for (i = 0; i < md->n_active_streams; i++) {
202                 if ((md->streams[i].type == SalAudio) && (ac->port != 0)) {
203                         strcpy(md->streams[0].rtp_addr,ac->addr);
204                         md->streams[0].rtp_port=ac->port;
205                         if ((ac->addr[0]!='\0' && vc->addr[0]!='\0' && strcmp(ac->addr,vc->addr)==0) || md->n_active_streams==1){
206                                 strcpy(md->addr,ac->addr);
207                         }
208                 }
209                 if ((md->streams[i].type == SalVideo) && (vc->port != 0)) {
210                         strcpy(md->streams[1].rtp_addr,vc->addr);
211                         md->streams[1].rtp_port=vc->port;
212                 }
213         }
214 }
215
216 void linphone_call_make_local_media_description(LinphoneCore *lc, LinphoneCall *call){
217         MSList *l;
218         PayloadType *pt;
219         SalMediaDescription *old_md=call->localdesc;
220         int i;
221         const char *me=linphone_core_get_identity(lc);
222         LinphoneAddress *addr=linphone_address_new(me);
223         const char *username=linphone_address_get_username (addr);
224         SalMediaDescription *md=sal_media_description_new();
225         bool_t keep_srtp_keys=lp_config_get_int(lc->config,"sip","keep_srtp_keys",0);
226
227         linphone_core_adapt_to_network(lc,call->ping_time,&call->params);
228
229         md->session_id=(old_md ? old_md->session_id : (rand() & 0xfff));
230         md->session_ver=(old_md ? (old_md->session_ver+1) : (rand() & 0xfff));
231         md->n_total_streams=(old_md ? old_md->n_total_streams : 1);
232         md->n_active_streams=1;
233         strncpy(md->addr,call->localip,sizeof(md->addr));
234         strncpy(md->username,username,sizeof(md->username));
235         
236         if (call->params.down_bw)
237                 md->bandwidth=call->params.down_bw;
238         else md->bandwidth=linphone_core_get_download_bandwidth(lc);
239
240         /*set audio capabilities */
241         strncpy(md->streams[0].rtp_addr,call->localip,sizeof(md->streams[0].rtp_addr));
242         strncpy(md->streams[0].rtcp_addr,call->localip,sizeof(md->streams[0].rtcp_addr));
243         md->streams[0].rtp_port=call->audio_port;
244         md->streams[0].rtcp_port=call->audio_port+1;
245         md->streams[0].proto=(call->params.media_encryption == LinphoneMediaEncryptionSRTP) ? 
246                 SalProtoRtpSavp : SalProtoRtpAvp;
247         md->streams[0].type=SalAudio;
248         if (call->params.down_ptime)
249                 md->streams[0].ptime=call->params.down_ptime;
250         else
251                 md->streams[0].ptime=linphone_core_get_download_ptime(lc);
252         l=make_codec_list(lc,lc->codecs_conf.audio_codecs,call->params.audio_bw,&md->streams[0].max_rate,-1);
253         pt=payload_type_clone(rtp_profile_get_payload_from_mime(lc->default_profile,"telephone-event"));
254         l=ms_list_append(l,pt);
255         md->streams[0].payloads=l;
256
257         // if ZRTP is enabled, put the hello hash into the audiostream's desc
258         if (call->audiostream && call->audiostream->ms.zrtp_context!=NULL){
259                 ortp_zrtp_get_hello_hash(call->audiostream->ms.zrtp_context,
260                         md->streams[0].zrtp_hello_hash,
261                         sizeof(md->streams[0].zrtp_hello_hash));
262                 ms_message("Audio stream zrtp hash: %s", md->streams[0].zrtp_hello_hash);
263         }
264
265         if (call->params.has_video){
266                 md->n_active_streams++;
267                 md->streams[1].rtp_port=call->video_port;
268                 md->streams[1].rtcp_port=call->video_port+1;
269                 md->streams[1].proto=md->streams[0].proto;
270                 md->streams[1].type=SalVideo;
271                 l=make_codec_list(lc,lc->codecs_conf.video_codecs,0,NULL,-1);
272                 md->streams[1].payloads=l;
273                 // if ZRTP is enabled, put the hello hash into the audiostream's desc
274                 if (call->videostream->ms.zrtp_context!=NULL){
275                         ortp_zrtp_get_hello_hash(call->videostream->ms.zrtp_context,
276                                 md->streams[1].zrtp_hello_hash,
277                                 sizeof(md->streams[1].zrtp_hello_hash));
278                         ms_message("Video stream zrtp hash: %s", md->streams[1].zrtp_hello_hash);
279                 }
280         }
281         if (md->n_total_streams < md->n_active_streams)
282                 md->n_total_streams = md->n_active_streams;
283
284         /* Deactivate inactive streams. */
285         for (i = md->n_active_streams; i < md->n_total_streams; i++) {
286                 md->streams[i].rtp_port = 0;
287                 md->streams[i].rtcp_port = 0;
288                 md->streams[i].proto = SalProtoRtpAvp;
289                 md->streams[i].type = old_md->streams[i].type;
290                 md->streams[i].dir = SalStreamInactive;
291                 l = make_codec_list(lc, lc->codecs_conf.video_codecs, 0, NULL, 1);
292                 md->streams[i].payloads = l;
293         }
294
295         for(i=0; i<md->n_active_streams; i++) {
296                 if (md->streams[i].proto == SalProtoRtpSavp) {
297                         if (keep_srtp_keys && old_md && old_md->streams[i].proto==SalProtoRtpSavp){
298                                 int j;
299                                 for(j=0;j<SAL_CRYPTO_ALGO_MAX;++j){
300                                         memcpy(&md->streams[i].crypto[j],&old_md->streams[i].crypto[j],sizeof(SalSrtpCryptoAlgo));
301                                 }
302                         }else{
303                                 md->streams[i].crypto[0].tag = 1;
304                                 md->streams[i].crypto[0].algo = AES_128_SHA1_80;
305                                 if (!generate_b64_crypto_key(30, md->streams[i].crypto[0].master_key))
306                                         md->streams[i].crypto[0].algo = 0;
307                                 md->streams[i].crypto[1].tag = 2;
308                                 md->streams[i].crypto[1].algo = AES_128_SHA1_32;
309                                 if (!generate_b64_crypto_key(30, md->streams[i].crypto[1].master_key))
310                                         md->streams[i].crypto[1].algo = 0;
311                                 md->streams[i].crypto[2].algo = 0;
312                         }
313                 }
314         }
315         update_media_description_from_stun(md,&call->ac,&call->vc);
316         if (call->ice_session != NULL) {
317                 linphone_core_update_local_media_description_from_ice(md, call->ice_session);
318                 linphone_core_update_ice_state_in_call_stats(call);
319         }
320 #ifdef BUILD_UPNP
321         if(call->upnp_session != NULL) {
322                 linphone_core_update_local_media_description_from_upnp(md, call->upnp_session);
323                 linphone_core_update_upnp_state_in_call_stats(call);
324         }
325 #endif  //BUILD_UPNP
326         linphone_address_destroy(addr);
327         call->localdesc=md;
328         if (old_md) sal_media_description_unref(old_md);
329 }
330
331 static int find_port_offset(LinphoneCore *lc, SalStreamType type){
332         int offset;
333         MSList *elem;
334         int tried_port;
335         int existing_port;
336         bool_t already_used=FALSE;
337         for(offset=0;offset<100;offset+=2){
338                 switch (type) {
339                         default:
340                         case SalAudio:
341                                 tried_port=linphone_core_get_audio_port (lc)+offset;
342                                 break;
343                         case SalVideo:
344                                 tried_port=linphone_core_get_video_port (lc)+offset;
345                                 break;
346                 }
347                 already_used=FALSE;
348                 for(elem=lc->calls;elem!=NULL;elem=elem->next){
349                         LinphoneCall *call=(LinphoneCall*)elem->data;
350                         switch (type) {
351                                 default:
352                                 case SalAudio:
353                                         existing_port = call->audio_port;
354                                         break;
355                                 case SalVideo:
356                                         existing_port = call->video_port;
357                                         break;
358                         }
359                         if (existing_port==tried_port) {
360                                 already_used=TRUE;
361                                 break;
362                         }
363                 }
364                 if (!already_used) break;
365         }
366         if (offset==100){
367                 ms_error("Could not find any free port !");
368                 return -1;
369         }
370         return offset;
371 }
372
373 static int select_random_port(LinphoneCore *lc, SalStreamType type) {
374         MSList *elem;
375         int nb_tries;
376         int tried_port = 0;
377         int existing_port = 0;
378         int min_port = 0, max_port = 0;
379         bool_t already_used = FALSE;
380
381         switch (type) {
382                 default:
383                 case SalAudio:
384                         linphone_core_get_audio_port_range(lc, &min_port, &max_port);
385                         break;
386                 case SalVideo:
387                         linphone_core_get_video_port_range(lc, &min_port, &max_port);
388                         break;
389         }
390         tried_port = (rand() % (max_port - min_port) + min_port) & ~0x1;
391         if (tried_port < min_port) tried_port = min_port + 2;
392         for (nb_tries = 0; nb_tries < 100; nb_tries++) {
393                 for (elem = lc->calls; elem != NULL; elem = elem->next) {
394                         LinphoneCall *call = (LinphoneCall *)elem->data;
395                         switch (type) {
396                                 default:
397                                 case SalAudio:
398                                         existing_port = call->audio_port;
399                                         break;
400                                 case SalVideo:
401                                         existing_port = call->video_port;
402                                         break;
403                         }
404                         if (existing_port == tried_port) {
405                                 already_used = TRUE;
406                                 break;
407                         }
408                 }
409                 if (!already_used) break;
410         }
411         if (nb_tries == 100) {
412                 ms_error("Could not find any free port!");
413                 return -1;
414         }
415         return tried_port;
416 }
417
418 static void linphone_call_init_common(LinphoneCall *call, LinphoneAddress *from, LinphoneAddress *to){
419         int port_offset;
420         int min_port, max_port;
421         call->magic=linphone_call_magic;
422         call->refcnt=1;
423         call->state=LinphoneCallIdle;
424         call->transfer_state = LinphoneCallIdle;
425         call->start_time=time(NULL);
426         call->media_start_time=0;
427         call->log=linphone_call_log_new(call, from, to);
428         call->owns_call_log=TRUE;
429         linphone_core_notify_all_friends(call->core,LinphoneStatusOnThePhone);
430         linphone_core_get_audio_port_range(call->core, &min_port, &max_port);
431         if (min_port == max_port) {
432                 /* Used fixed RTP audio port. */
433                 port_offset=find_port_offset (call->core, SalAudio);
434                 if (port_offset==-1) return;
435                 call->audio_port=linphone_core_get_audio_port(call->core)+port_offset;
436         } else {
437                 /* Select random RTP audio port in the specified range. */
438                 call->audio_port = select_random_port(call->core, SalAudio);
439         }
440         linphone_core_get_video_port_range(call->core, &min_port, &max_port);
441         if (min_port == max_port) {
442                 /* Used fixed RTP video port. */
443                 port_offset=find_port_offset (call->core, SalVideo);
444                 if (port_offset==-1) return;
445                 call->video_port=linphone_core_get_video_port(call->core)+port_offset;
446         } else {
447                 /* Select random RTP video port in the specified range. */
448                 call->video_port = select_random_port(call->core, SalVideo);
449         }
450         linphone_call_init_stats(&call->stats[LINPHONE_CALL_STATS_AUDIO], LINPHONE_CALL_STATS_AUDIO);
451         linphone_call_init_stats(&call->stats[LINPHONE_CALL_STATS_VIDEO], LINPHONE_CALL_STATS_VIDEO);
452 }
453
454 void linphone_call_init_stats(LinphoneCallStats *stats, int type) {
455         stats->type = type;
456         stats->received_rtcp = NULL;
457         stats->sent_rtcp = NULL;
458         stats->ice_state = LinphoneIceStateNotActivated;
459 #ifdef BUILD_UPNP
460         stats->upnp_state = LinphoneUpnpStateIdle;
461 #else
462         stats->upnp_state = LinphoneUpnpStateNotAvailable;
463 #endif //BUILD_UPNP
464 }
465
466
467 static void discover_mtu(LinphoneCore *lc, const char *remote){
468         int mtu;
469         if (lc->net_conf.mtu==0 ){
470                 /*attempt to discover mtu*/
471                 mtu=ms_discover_mtu(remote);
472                 if (mtu>0){
473                         ms_set_mtu(mtu);
474                         ms_message("Discovered mtu is %i, RTP payload max size is %i",
475                                 mtu, ms_get_payload_max_size());
476                 }
477         }
478 }
479
480 LinphoneCall * linphone_call_new_outgoing(struct _LinphoneCore *lc, LinphoneAddress *from, LinphoneAddress *to, const LinphoneCallParams *params)
481 {
482         LinphoneCall *call=ms_new0(LinphoneCall,1);
483         call->dir=LinphoneCallOutgoing;
484         call->op=sal_op_new(lc->sal);
485         sal_op_set_user_pointer(call->op,call);
486         call->core=lc;
487         linphone_core_get_local_ip(lc,linphone_address_get_domain(to),call->localip);
488         linphone_call_init_common(call,from,to);
489         _linphone_call_params_copy(&call->params,params);
490         sal_op_set_custom_header(call->op,call->params.custom_headers);
491         call->params.custom_headers=NULL;
492         
493         if (linphone_core_get_firewall_policy(call->core) == LinphonePolicyUseIce) {
494                 call->ice_session = ice_session_new();
495                 ice_session_set_role(call->ice_session, IR_Controlling);
496         }
497         if (linphone_core_get_firewall_policy(call->core) == LinphonePolicyUseStun) {
498                 call->ping_time=linphone_core_run_stun_tests(call->core,call);
499         }
500 #ifdef BUILD_UPNP
501         if (linphone_core_get_firewall_policy(call->core) == LinphonePolicyUseUpnp) {
502                 if(!lc->rtp_conf.disable_upnp) {
503                         call->upnp_session = linphone_upnp_session_new(call);
504                 }
505         }
506 #endif //BUILD_UPNP
507         call->camera_active=params->has_video;
508         
509         discover_mtu(lc,linphone_address_get_domain (to));
510         if (params->referer){
511                 sal_call_set_referer(call->op,params->referer->op);
512                 call->referer=linphone_call_ref(params->referer);
513         }
514         return call;
515 }
516
517 LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *from, LinphoneAddress *to, SalOp *op){
518         LinphoneCall *call=ms_new0(LinphoneCall,1);
519         char *from_str;
520         const SalMediaDescription *md;
521
522         call->dir=LinphoneCallIncoming;
523         sal_op_set_user_pointer(op,call);
524         call->op=op;
525         call->core=lc;
526
527         if (lc->sip_conf.ping_with_options){
528 #ifdef BUILD_UPNP
529                 if (lc->upnp != NULL && linphone_core_get_firewall_policy(lc)==LinphonePolicyUseUpnp &&
530                         linphone_upnp_context_get_state(lc->upnp) == LinphoneUpnpStateOk) {
531 #else //BUILD_UPNP
532                 {
533 #endif //BUILD_UPNP
534                         /*the following sends an option request back to the caller so that
535                          we get a chance to discover our nat'd address before answering.*/
536                         call->ping_op=sal_op_new(lc->sal);
537                         from_str=linphone_address_as_string_uri_only(from);
538                         sal_op_set_route(call->ping_op,sal_op_get_network_origin(op));
539                         sal_op_set_user_pointer(call->ping_op,call);
540                         sal_ping(call->ping_op,linphone_core_find_best_identity(lc,from,NULL),from_str);
541                         ms_free(from_str);
542                 }
543         }
544
545         linphone_address_clean(from);
546         linphone_core_get_local_ip(lc,linphone_address_get_domain(from),call->localip);
547         linphone_call_init_common(call, from, to);
548         call->log->call_id=ms_strdup(sal_op_get_call_id(op)); /*must be known at that time*/
549         linphone_core_init_default_params(lc, &call->params);
550         md=sal_call_get_remote_media_description(op);
551         call->params.has_video &= !!lc->video_policy.automatically_accept;
552         if (md) {
553                 // It is licit to receive an INVITE without SDP
554                 // In this case WE chose the media parameters according to policy.
555                 call->params.has_video &= linphone_core_media_description_contains_video_stream(md);
556         }
557         switch (linphone_core_get_firewall_policy(call->core)) {
558                 case LinphonePolicyUseIce:
559                         call->ice_session = ice_session_new();
560                         ice_session_set_role(call->ice_session, IR_Controlled);
561                         linphone_core_update_ice_from_remote_media_description(call, sal_call_get_remote_media_description(op));
562                         if (call->ice_session != NULL) {
563                                 linphone_call_init_media_streams(call);
564                                 linphone_call_start_media_streams_for_ice_gathering(call);
565                                 if (linphone_core_gather_ice_candidates(call->core,call)<0) {
566                                         /* Ice candidates gathering failed, proceed with the call anyway. */
567                                         linphone_call_delete_ice_session(call);
568                                         linphone_call_stop_media_streams_for_ice_gathering(call);
569                                 }
570                         }
571                         break;
572                 case LinphonePolicyUseStun:
573                         call->ping_time=linphone_core_run_stun_tests(call->core,call);
574                         /* No break to also destroy ice session in this case. */
575                         break;
576                 case LinphonePolicyUseUpnp:
577 #ifdef BUILD_UPNP
578                         if(!lc->rtp_conf.disable_upnp) {
579                                 call->upnp_session = linphone_upnp_session_new(call);
580                                 if (call->upnp_session != NULL) {
581                                         linphone_call_init_media_streams(call);
582                                         if (linphone_core_update_upnp_from_remote_media_description(call, sal_call_get_remote_media_description(op))<0) {
583                                                 /* uPnP port mappings failed, proceed with the call anyway. */
584                                                 linphone_call_delete_upnp_session(call);
585                                         }
586                                 }
587                         }
588 #endif //BUILD_UPNP
589                         break;
590                 default:
591                         break;
592         }
593         call->camera_active=call->params.has_video;
594         
595         discover_mtu(lc,linphone_address_get_domain(from));
596         return call;
597 }
598
599 /* this function is called internally to get rid of a call.
600  It performs the following tasks:
601  - remove the call from the internal list of calls
602  - update the call logs accordingly
603 */
604
605 static void linphone_call_set_terminated(LinphoneCall *call){
606         LinphoneCore *lc=call->core;
607
608         linphone_core_update_allocated_audio_bandwidth(lc);
609
610         call->owns_call_log=FALSE;
611         linphone_call_log_completed(call);
612
613
614         if (call == lc->current_call){
615                 ms_message("Resetting the current call");
616                 lc->current_call=NULL;
617         }
618
619         if (linphone_core_del_call(lc,call) != 0){
620                 ms_error("Could not remove the call from the list !!!");
621         }
622
623         if (ms_list_size(lc->calls)==0)
624                 linphone_core_notify_all_friends(lc,lc->presence_mode);
625
626         linphone_core_conference_check_uninit(lc);
627         if (call->ringing_beep){
628                 linphone_core_stop_dtmf(lc);
629                 call->ringing_beep=FALSE;
630         }
631         if (call->referer){
632                 linphone_call_unref(call->referer);
633                 call->referer=NULL;
634         }
635 }
636
637 void linphone_call_fix_call_parameters(LinphoneCall *call){
638         call->params.has_video=call->current_params.has_video;
639         call->params.media_encryption=call->current_params.media_encryption;
640 }
641
642 const char *linphone_call_state_to_string(LinphoneCallState cs){
643         switch (cs){
644                 case LinphoneCallIdle:
645                         return "LinphoneCallIdle";
646                 case LinphoneCallIncomingReceived:
647                         return "LinphoneCallIncomingReceived";
648                 case LinphoneCallOutgoingInit:
649                         return "LinphoneCallOutgoingInit";
650                 case LinphoneCallOutgoingProgress:
651                         return "LinphoneCallOutgoingProgress";
652                 case LinphoneCallOutgoingRinging:
653                         return "LinphoneCallOutgoingRinging";
654                 case LinphoneCallOutgoingEarlyMedia:
655                         return "LinphoneCallOutgoingEarlyMedia";
656                 case LinphoneCallConnected:
657                         return "LinphoneCallConnected";
658                 case LinphoneCallStreamsRunning:
659                         return "LinphoneCallStreamsRunning";
660                 case LinphoneCallPausing:
661                         return "LinphoneCallPausing";
662                 case LinphoneCallPaused:
663                         return "LinphoneCallPaused";
664                 case LinphoneCallResuming:
665                         return "LinphoneCallResuming";
666                 case LinphoneCallRefered:
667                         return "LinphoneCallRefered";
668                 case LinphoneCallError:
669                         return "LinphoneCallError";
670                 case LinphoneCallEnd:
671                         return "LinphoneCallEnd";
672                 case LinphoneCallPausedByRemote:
673                         return "LinphoneCallPausedByRemote";
674                 case LinphoneCallUpdatedByRemote:
675                         return "LinphoneCallUpdatedByRemote";
676                 case LinphoneCallIncomingEarlyMedia:
677                         return "LinphoneCallIncomingEarlyMedia";
678                 case LinphoneCallUpdating:
679                         return "LinphoneCallUpdating";
680                 case LinphoneCallReleased:
681                         return "LinphoneCallReleased";
682         }
683         return "undefined state";
684 }
685
686 void linphone_call_set_state(LinphoneCall *call, LinphoneCallState cstate, const char *message){
687         LinphoneCore *lc=call->core;
688
689         if (call->state!=cstate){
690                 if (call->state==LinphoneCallEnd || call->state==LinphoneCallError){
691                         if (cstate!=LinphoneCallReleased){
692                                 ms_warning("Spurious call state change from %s to %s, ignored.",linphone_call_state_to_string(call->state),
693                                    linphone_call_state_to_string(cstate));
694                                 return;
695                         }
696                 }
697                 ms_message("Call %p: moving from state %s to %s",call,linphone_call_state_to_string(call->state),
698                            linphone_call_state_to_string(cstate));
699                 if (cstate!=LinphoneCallRefered){
700                         /*LinphoneCallRefered is rather an event, not a state.
701                          Indeed it does not change the state of the call (still paused or running)*/
702                         call->state=cstate;
703                 }
704                 if (cstate==LinphoneCallEnd || cstate==LinphoneCallError){
705                         switch(call->reason){
706                                 case LinphoneReasonDeclined:
707                                         call->log->status=LinphoneCallDeclined;
708                                         break;
709                                 case LinphoneReasonNotAnswered:
710                                         call->log->status=LinphoneCallMissed;
711                                 break;
712                                 default:
713                                 break;
714                         }
715                         linphone_call_set_terminated (call);
716                 }
717                 if (cstate == LinphoneCallConnected) {
718                         call->log->status=LinphoneCallSuccess;
719                         call->media_start_time=time(NULL);
720                 }
721
722                 if (lc->vtable.call_state_changed)
723                         lc->vtable.call_state_changed(lc,call,cstate,message);
724                 if (cstate==LinphoneCallReleased){
725                         if (call->op!=NULL) {
726                                 /* so that we cannot have anymore upcalls for SAL
727                                  concerning this call*/
728                                 sal_op_release(call->op);
729                                 call->op=NULL;
730                         }
731                         linphone_call_unref(call);
732                 }
733         }
734 }
735
736 static void linphone_call_destroy(LinphoneCall *obj)
737 {
738 #ifdef BUILD_UPNP
739         linphone_call_delete_upnp_session(obj);
740 #endif //BUILD_UPNP
741         linphone_call_delete_ice_session(obj);
742         if (obj->op!=NULL) {
743                 sal_op_release(obj->op);
744                 obj->op=NULL;
745         }
746         if (obj->resultdesc!=NULL) {
747                 sal_media_description_unref(obj->resultdesc);
748                 obj->resultdesc=NULL;
749         }
750         if (obj->localdesc!=NULL) {
751                 sal_media_description_unref(obj->localdesc);
752                 obj->localdesc=NULL;
753         }
754         if (obj->ping_op) {
755                 sal_op_release(obj->ping_op);
756         }
757         if (obj->refer_to){
758                 ms_free(obj->refer_to);
759         }
760         if (obj->owns_call_log)
761                 linphone_call_log_destroy(obj->log);
762         if (obj->auth_token) {
763                 ms_free(obj->auth_token);
764         }
765         linphone_call_params_uninit(&obj->params);
766         ms_free(obj);
767 }
768
769 /**
770  * @addtogroup call_control
771  * @{
772 **/
773
774 /**
775  * Increments the call 's reference count.
776  * An application that wishes to retain a pointer to call object
777  * must use this function to unsure the pointer remains
778  * valid. Once the application no more needs this pointer,
779  * it must call linphone_call_unref().
780 **/
781 LinphoneCall * linphone_call_ref(LinphoneCall *obj){
782         obj->refcnt++;
783         return obj;
784 }
785
786 /**
787  * Decrements the call object reference count.
788  * See linphone_call_ref().
789 **/
790 void linphone_call_unref(LinphoneCall *obj){
791         obj->refcnt--;
792         if (obj->refcnt==0){
793                 linphone_call_destroy(obj);
794         }
795 }
796
797 /**
798  * Returns current parameters associated to the call.
799 **/
800 const LinphoneCallParams * linphone_call_get_current_params(LinphoneCall *call){
801         if (call->params.record_file)
802                 call->current_params.record_file=call->params.record_file;
803         return &call->current_params;
804 }
805
806 static bool_t is_video_active(const SalStreamDescription *sd){
807         return sd->rtp_port!=0 && sd->dir!=SalStreamInactive;
808 }
809
810 /**
811  * Returns call parameters proposed by remote.
812  * 
813  * This is useful when receiving an incoming call, to know whether the remote party
814  * supports video, encryption or whatever.
815 **/
816 const LinphoneCallParams * linphone_call_get_remote_params(LinphoneCall *call){
817         LinphoneCallParams *cp=&call->remote_params;
818         memset(cp,0,sizeof(*cp));
819         if (call->op){
820                 SalMediaDescription *md=sal_call_get_remote_media_description(call->op);
821                 if (md){
822                         SalStreamDescription *asd,*vsd,*secure_asd,*secure_vsd;
823
824                         asd=sal_media_description_find_stream(md,SalProtoRtpAvp,SalAudio);
825                         vsd=sal_media_description_find_stream(md,SalProtoRtpAvp,SalVideo);
826                         secure_asd=sal_media_description_find_stream(md,SalProtoRtpSavp,SalAudio);
827                         secure_vsd=sal_media_description_find_stream(md,SalProtoRtpSavp,SalVideo);
828                         if (secure_vsd){
829                                 cp->has_video=is_video_active(secure_vsd);
830                                 if (secure_asd || asd==NULL)
831                                         cp->media_encryption=LinphoneMediaEncryptionSRTP;
832                         }else if (vsd){
833                                 cp->has_video=is_video_active(vsd);
834                         }
835                         if (!cp->has_video){
836                                 if (md->bandwidth>0 && md->bandwidth<=linphone_core_get_edge_bw(call->core)){
837                                         cp->low_bandwidth=TRUE;
838                                 }
839                         }
840                         cp->custom_headers=(SalCustomHeader*)sal_op_get_custom_header(call->op);
841                         return cp;
842                 }
843         }
844         return NULL;
845 }
846
847 /**
848  * Returns the remote address associated to this call
849  *
850 **/
851 const LinphoneAddress * linphone_call_get_remote_address(const LinphoneCall *call){
852         return call->dir==LinphoneCallIncoming ? call->log->from : call->log->to;
853 }
854
855 /**
856  * Returns the remote address associated to this call as a string.
857  *
858  * The result string must be freed by user using ms_free().
859 **/
860 char *linphone_call_get_remote_address_as_string(const LinphoneCall *call){
861         return linphone_address_as_string(linphone_call_get_remote_address(call));
862 }
863
864 /**
865  * Retrieves the call's current state.
866 **/
867 LinphoneCallState linphone_call_get_state(const LinphoneCall *call){
868         return call->state;
869 }
870
871 /**
872  * Returns the reason for a call termination (either error or normal termination)
873 **/
874 LinphoneReason linphone_call_get_reason(const LinphoneCall *call){
875         return call->reason;
876 }
877
878 /**
879  * Get the user_pointer in the LinphoneCall
880  *
881  * @ingroup call_control
882  *
883  * return user_pointer an opaque user pointer that can be retrieved at any time
884 **/
885 void *linphone_call_get_user_pointer(LinphoneCall *call)
886 {
887         return call->user_pointer;
888 }
889
890 /**
891  * Set the user_pointer in the LinphoneCall
892  *
893  * @ingroup call_control
894  *
895  * the user_pointer is an opaque user pointer that can be retrieved at any time in the LinphoneCall
896 **/
897 void linphone_call_set_user_pointer(LinphoneCall *call, void *user_pointer)
898 {
899         call->user_pointer = user_pointer;
900 }
901
902 /**
903  * Returns the call log associated to this call.
904 **/
905 LinphoneCallLog *linphone_call_get_call_log(const LinphoneCall *call){
906         return call->log;
907 }
908
909 /**
910  * Returns the refer-to uri (if the call was transfered).
911 **/
912 const char *linphone_call_get_refer_to(const LinphoneCall *call){
913         return call->refer_to;
914 }
915
916 /**
917  * Returns direction of the call (incoming or outgoing).
918 **/
919 LinphoneCallDir linphone_call_get_dir(const LinphoneCall *call){
920         return call->log->dir;
921 }
922
923 /**
924  * Returns the far end's user agent description string, if available.
925 **/
926 const char *linphone_call_get_remote_user_agent(LinphoneCall *call){
927         if (call->op){
928                 return sal_op_get_remote_ua (call->op);
929         }
930         return NULL;
931 }
932
933 /**
934  * Returns the far end's sip contact as a string, if available.
935 **/
936 const char *linphone_call_get_remote_contact(LinphoneCall *call){
937         if (call->op){
938                 return sal_op_get_remote_contact(call->op);
939         }
940         return NULL;
941 }
942
943 /**
944  * Returns true if this calls has received a transfer that has not been
945  * executed yet.
946  * Pending transfers are executed when this call is being paused or closed,
947  * locally or by remote endpoint.
948  * If the call is already paused while receiving the transfer request, the
949  * transfer immediately occurs.
950 **/
951 bool_t linphone_call_has_transfer_pending(const LinphoneCall *call){
952         return call->refer_pending;
953 }
954
955 /**
956  * Returns call's duration in seconds.
957 **/
958 int linphone_call_get_duration(const LinphoneCall *call){
959         if (call->media_start_time==0) return 0;
960         return time(NULL)-call->media_start_time;
961 }
962
963 /**
964  * Returns the call object this call is replacing, if any.
965  * Call replacement can occur during call transfers.
966  * By default, the core automatically terminates the replaced call and accept the new one.
967  * This function allows the application to know whether a new incoming call is a one that replaces another one.
968 **/
969 LinphoneCall *linphone_call_get_replaced_call(LinphoneCall *call){
970         SalOp *op=sal_call_get_replaces(call->op);
971         if (op){
972                 return (LinphoneCall*)sal_op_get_user_pointer(op);
973         }
974         return NULL;
975 }
976
977 /**
978  * Indicate whether camera input should be sent to remote end.
979 **/
980 void linphone_call_enable_camera (LinphoneCall *call, bool_t enable){
981 #ifdef VIDEO_ENABLED
982         if (call->videostream!=NULL && call->videostream->ms.ticker!=NULL){
983                 LinphoneCore *lc=call->core;
984                 MSWebCam *nowebcam=get_nowebcam_device();
985                 if (call->camera_active!=enable && lc->video_conf.device!=nowebcam){
986                         video_stream_change_camera(call->videostream,
987                                      enable ? lc->video_conf.device : nowebcam);
988                 }
989         }
990         call->camera_active=enable;
991 #endif
992 }
993
994 #ifdef VIDEO_ENABLED
995 /**
996  * Request remote side to send us a Video Fast Update.
997 **/
998 void linphone_call_send_vfu_request(LinphoneCall *call)
999 {
1000         if (LinphoneCallStreamsRunning == linphone_call_get_state(call))
1001                 sal_call_send_vfu_request(call->op);
1002 }
1003 #endif
1004
1005
1006 /**
1007  * Take a photo of currently received video and write it into a jpeg file.
1008 **/
1009 int linphone_call_take_video_snapshot(LinphoneCall *call, const char *file){
1010 #ifdef VIDEO_ENABLED
1011         if (call->videostream!=NULL && call->videostream->jpegwriter!=NULL){
1012                 return ms_filter_call_method(call->videostream->jpegwriter,MS_JPEG_WRITER_TAKE_SNAPSHOT,(void*)file);
1013         }
1014         ms_warning("Cannot take snapshot: no currently running video stream on this call.");
1015         return -1;
1016 #endif
1017         return -1;
1018 }
1019
1020 /**
1021  * Returns TRUE if camera pictures are sent to the remote party.
1022 **/
1023 bool_t linphone_call_camera_enabled (const LinphoneCall *call){
1024         return call->camera_active;
1025 }
1026
1027 /**
1028  * Enable video stream.
1029 **/
1030 void linphone_call_params_enable_video(LinphoneCallParams *cp, bool_t enabled){
1031         cp->has_video=enabled;
1032 }
1033
1034 /**
1035  * Returns the audio codec used in the call, described as a PayloadType structure.
1036 **/
1037 const PayloadType* linphone_call_params_get_used_audio_codec(const LinphoneCallParams *cp) {
1038         return cp->audio_codec;
1039 }
1040
1041
1042 /**
1043  * Returns the video codec used in the call, described as a PayloadType structure.
1044 **/
1045 const PayloadType* linphone_call_params_get_used_video_codec(const LinphoneCallParams *cp) {
1046         return cp->video_codec;
1047 }
1048
1049 /**
1050  * @ingroup call_control
1051  * Use to know if this call has been configured in low bandwidth mode.
1052  * This mode can be automatically discovered thanks to a stun server when activate_edge_workarounds=1 in section [net] of configuration file.
1053  * An application that would have reliable way to know network capacity may not use activate_edge_workarounds=1 but instead manually configure
1054  * low bandwidth mode with linphone_call_params_enable_low_bandwidth().
1055  * <br> When enabled, this param may transform a call request with video in audio only mode.
1056  * @return TRUE if low bandwidth has been configured/detected
1057  */
1058 bool_t linphone_call_params_low_bandwidth_enabled(const LinphoneCallParams *cp) {
1059         return cp->low_bandwidth;
1060 }
1061
1062 /**
1063  * @ingroup call_control
1064  * Indicate low bandwith mode. 
1065  * Configuring a call to low bandwidth mode will result in the core to activate several settings for the call in order to ensure that bitrate usage
1066  * is lowered to the minimum possible. Typically, ptime (packetization time) will be increased, audio codec's output bitrate will be targetted to 20kbit/s provided
1067  * that it is achievable by the codec selected after SDP handshake. Video is automatically disabled.
1068  * 
1069 **/
1070 void linphone_call_params_enable_low_bandwidth(LinphoneCallParams *cp, bool_t enabled){
1071         cp->low_bandwidth=enabled;
1072 }
1073
1074 /**
1075  * Returns whether video is enabled.
1076 **/
1077 bool_t linphone_call_params_video_enabled(const LinphoneCallParams *cp){
1078         return cp->has_video;
1079 }
1080
1081 /**
1082  * Returns kind of media encryption selected for the call.
1083 **/
1084 enum LinphoneMediaEncryption linphone_call_params_get_media_encryption(const LinphoneCallParams *cp) {
1085         return cp->media_encryption;
1086 }
1087
1088 /**
1089  * Set requested media encryption for a call.
1090 **/
1091 void linphone_call_params_set_media_encryption(LinphoneCallParams *cp, enum LinphoneMediaEncryption e) {
1092         cp->media_encryption = e;
1093 }
1094
1095
1096 /**
1097  * Enable sending of real early media (during outgoing calls).
1098 **/
1099 void linphone_call_params_enable_early_media_sending(LinphoneCallParams *cp, bool_t enabled){
1100         cp->real_early_media=enabled;
1101 }
1102
1103 /**
1104  * Indicates whether sending of early media was enabled.
1105 **/
1106 bool_t linphone_call_params_early_media_sending_enabled(const LinphoneCallParams *cp){
1107         return cp->real_early_media;
1108 }
1109
1110 /**
1111  * Returns true if the call is part of the locally managed conference.
1112 **/
1113 bool_t linphone_call_params_local_conference_mode(const LinphoneCallParams *cp){
1114         return cp->in_conference;
1115 }
1116
1117 /**
1118  * Refine bandwidth settings for this call by setting a bandwidth limit for audio streams.
1119  * As a consequence, codecs whose bitrates are not compatible with this limit won't be used.
1120 **/
1121 void linphone_call_params_set_audio_bandwidth_limit(LinphoneCallParams *cp, int bandwidth){
1122         cp->audio_bw=bandwidth;
1123 }
1124
1125 void linphone_call_params_add_custom_header(LinphoneCallParams *params, const char *header_name, const char *header_value){
1126         params->custom_headers=sal_custom_header_append(params->custom_headers,header_name,header_value);
1127 }
1128
1129 const char *linphone_call_params_get_custom_header(const LinphoneCallParams *params, const char *header_name){
1130         return sal_custom_header_find(params->custom_headers,header_name);
1131 }
1132
1133 void _linphone_call_params_copy(LinphoneCallParams *ncp, const LinphoneCallParams *cp){
1134         memcpy(ncp,cp,sizeof(LinphoneCallParams));
1135         if (cp->record_file) ncp->record_file=ms_strdup(cp->record_file);
1136         /*
1137          * The management of the custom headers is not optimal. We copy everything while ref counting would be more efficient.
1138          */
1139         if (cp->custom_headers) ncp->custom_headers=sal_custom_header_clone(cp->custom_headers);
1140 }
1141
1142 /**
1143  * Copy existing LinphoneCallParams to a new LinphoneCallParams object.
1144 **/
1145 LinphoneCallParams * linphone_call_params_copy(const LinphoneCallParams *cp){
1146         LinphoneCallParams *ncp=ms_new0(LinphoneCallParams,1);
1147         _linphone_call_params_copy(ncp,cp);
1148         return ncp;
1149 }
1150
1151 void linphone_call_params_uninit(LinphoneCallParams *p){
1152         if (p->record_file) ms_free(p->record_file);
1153         if (p->custom_headers) sal_custom_header_free(p->custom_headers);
1154 }
1155
1156 /**
1157  * Destroy LinphoneCallParams.
1158 **/
1159 void linphone_call_params_destroy(LinphoneCallParams *p){
1160         linphone_call_params_uninit(p);
1161         ms_free(p);
1162 }
1163
1164
1165 /**
1166  * @}
1167 **/
1168
1169
1170 #ifdef TEST_EXT_RENDERER
1171 static void rendercb(void *data, const MSPicture *local, const MSPicture *remote){
1172         ms_message("rendercb, local buffer=%p, remote buffer=%p",
1173                    local ? local->planes[0] : NULL, remote? remote->planes[0] : NULL);
1174 }
1175 #endif
1176
1177 #ifdef VIDEO_ENABLED
1178 static void video_stream_event_cb(void *user_pointer, const MSFilter *f, const unsigned int event_id, const void *args){
1179     LinphoneCall* call = (LinphoneCall*) user_pointer;
1180         ms_warning("In linphonecall.c: video_stream_event_cb");
1181         switch (event_id) {
1182                 case MS_VIDEO_DECODER_DECODING_ERRORS:
1183                         ms_warning("Case is MS_VIDEO_DECODER_DECODING_ERRORS");
1184                         linphone_call_send_vfu_request(call);
1185                         break;
1186                 case MS_VIDEO_DECODER_FIRST_IMAGE_DECODED:
1187                         ms_message("First video frame decoded successfully");
1188                         if (call->nextVideoFrameDecoded._func != NULL)
1189                         call->nextVideoFrameDecoded._func(call, call->nextVideoFrameDecoded._user_data);
1190                         break;
1191                 default:
1192                         ms_warning("Unhandled event %i", event_id);
1193                         break;
1194         }
1195 }
1196 #endif
1197
1198 void linphone_call_set_next_video_frame_decoded_callback(LinphoneCall *call, LinphoneCallCbFunc cb, void* user_data) {
1199         call->nextVideoFrameDecoded._func = cb;
1200         call->nextVideoFrameDecoded._user_data = user_data;
1201 #ifdef VIDEO_ENABLED
1202         ms_filter_call_method_noarg(call->videostream->ms.decoder, MS_VIDEO_DECODER_RESET_FIRST_IMAGE_NOTIFICATION);
1203 #endif
1204 }
1205
1206 void linphone_call_init_audio_stream(LinphoneCall *call){
1207         LinphoneCore *lc=call->core;
1208         AudioStream *audiostream;
1209         int dscp;
1210
1211         if (call->audiostream != NULL) return;
1212         call->audiostream=audiostream=audio_stream_new(call->audio_port,call->audio_port+1,linphone_core_ipv6_enabled(lc));
1213         dscp=linphone_core_get_audio_dscp(lc);
1214         if (dscp!=-1)
1215                 audio_stream_set_dscp(audiostream,dscp);
1216         if (linphone_core_echo_limiter_enabled(lc)){
1217                 const char *type=lp_config_get_string(lc->config,"sound","el_type","mic");
1218                 if (strcasecmp(type,"mic")==0)
1219                         audio_stream_enable_echo_limiter(audiostream,ELControlMic);
1220                 else if (strcasecmp(type,"full")==0)
1221                         audio_stream_enable_echo_limiter(audiostream,ELControlFull);
1222         }
1223         audio_stream_enable_gain_control(audiostream,TRUE);
1224         if (linphone_core_echo_cancellation_enabled(lc)){
1225                 int len,delay,framesize;
1226                 const char *statestr=lp_config_get_string(lc->config,"sound","ec_state",NULL);
1227                 len=lp_config_get_int(lc->config,"sound","ec_tail_len",0);
1228                 delay=lp_config_get_int(lc->config,"sound","ec_delay",0);
1229                 framesize=lp_config_get_int(lc->config,"sound","ec_framesize",0);
1230                 audio_stream_set_echo_canceller_params(audiostream,len,delay,framesize);
1231                 if (statestr && audiostream->ec){
1232                         ms_filter_call_method(audiostream->ec,MS_ECHO_CANCELLER_SET_STATE_STRING,(void*)statestr);
1233                 }
1234         }
1235         audio_stream_enable_automatic_gain_control(audiostream,linphone_core_agc_enabled(lc));
1236         {
1237                 int enabled=lp_config_get_int(lc->config,"sound","noisegate",0);
1238                 audio_stream_enable_noise_gate(audiostream,enabled);
1239         }
1240
1241         audio_stream_set_features(audiostream,linphone_core_get_audio_features(lc));
1242
1243         if (lc->rtptf){
1244                 RtpTransport *artp=lc->rtptf->audio_rtp_func(lc->rtptf->audio_rtp_func_data, call->audio_port);
1245                 RtpTransport *artcp=lc->rtptf->audio_rtcp_func(lc->rtptf->audio_rtcp_func_data, call->audio_port+1);
1246                 rtp_session_set_transports(audiostream->ms.session,artp,artcp);
1247         }
1248         if ((linphone_core_get_firewall_policy(lc) == LinphonePolicyUseIce) && (call->ice_session != NULL)){
1249                 rtp_session_set_pktinfo(audiostream->ms.session, TRUE);
1250                 rtp_session_set_symmetric_rtp(audiostream->ms.session, FALSE);
1251                 if (ice_session_check_list(call->ice_session, 0) == NULL) {
1252                         ice_session_add_check_list(call->ice_session, ice_check_list_new());
1253                 }
1254                 audiostream->ms.ice_check_list = ice_session_check_list(call->ice_session, 0);
1255                 ice_check_list_set_rtp_session(audiostream->ms.ice_check_list, audiostream->ms.session);
1256         }
1257
1258         call->audiostream_app_evq = ortp_ev_queue_new();
1259         rtp_session_register_event_queue(audiostream->ms.session,call->audiostream_app_evq);
1260 }
1261
1262 void linphone_call_init_video_stream(LinphoneCall *call){
1263 #ifdef VIDEO_ENABLED
1264         LinphoneCore *lc=call->core;
1265
1266         if (!call->params.has_video) {
1267                 linphone_call_stop_video_stream(call);
1268                 return;
1269         }
1270         if (call->videostream != NULL) return;
1271         if ((lc->video_conf.display || lc->video_conf.capture) && call->params.has_video){
1272                 int video_recv_buf_size=lp_config_get_int(lc->config,"video","recv_buf_size",0);
1273                 int dscp=linphone_core_get_video_dscp(lc);
1274                 
1275                 call->videostream=video_stream_new(call->video_port,call->video_port+1,linphone_core_ipv6_enabled(lc));
1276                 if (dscp!=-1)
1277                         video_stream_set_dscp(call->videostream,dscp);
1278                 video_stream_enable_display_filter_auto_rotate(call->videostream, lp_config_get_int(lc->config,"video","display_filter_auto_rotate",0));
1279                 if (video_recv_buf_size>0) rtp_session_set_recv_buf_size(call->videostream->ms.session,video_recv_buf_size);
1280
1281                 if( lc->video_conf.displaytype != NULL)
1282                         video_stream_set_display_filter_name(call->videostream,lc->video_conf.displaytype);
1283                 video_stream_set_event_callback(call->videostream,video_stream_event_cb, call);
1284                 if (lc->rtptf){
1285                         RtpTransport *vrtp=lc->rtptf->video_rtp_func(lc->rtptf->video_rtp_func_data, call->video_port);
1286                         RtpTransport *vrtcp=lc->rtptf->video_rtcp_func(lc->rtptf->video_rtcp_func_data, call->video_port+1);
1287                         rtp_session_set_transports(call->videostream->ms.session,vrtp,vrtcp);
1288                 }
1289                 if ((linphone_core_get_firewall_policy(lc) == LinphonePolicyUseIce) && (call->ice_session != NULL)){
1290                         rtp_session_set_pktinfo(call->videostream->ms.session, TRUE);
1291                         rtp_session_set_symmetric_rtp(call->videostream->ms.session, FALSE);
1292                         if (ice_session_check_list(call->ice_session, 1) == NULL) {
1293                                 ice_session_add_check_list(call->ice_session, ice_check_list_new());
1294                         }
1295                         call->videostream->ms.ice_check_list = ice_session_check_list(call->ice_session, 1);
1296                         ice_check_list_set_rtp_session(call->videostream->ms.ice_check_list, call->videostream->ms.session);
1297                 }
1298                 call->videostream_app_evq = ortp_ev_queue_new();
1299                 rtp_session_register_event_queue(call->videostream->ms.session,call->videostream_app_evq);
1300 #ifdef TEST_EXT_RENDERER
1301                 video_stream_set_render_callback(call->videostream,rendercb,NULL);
1302 #endif
1303         }
1304 #else
1305         call->videostream=NULL;
1306 #endif
1307 }
1308
1309 void linphone_call_init_media_streams(LinphoneCall *call){
1310         linphone_call_init_audio_stream(call);
1311         linphone_call_init_video_stream(call);
1312
1313         // moved from linphone_call_start_media_streams, because ZRTP needs to be
1314         // at least partially initialized so that the SDP can contain 'zrtp-hash'
1315         if (call->params.media_encryption==LinphoneMediaEncryptionZRTP) {
1316                 OrtpZrtpParams params;
1317                 /*will be set later when zrtp is activated*/
1318                 call->current_params.media_encryption=LinphoneMediaEncryptionNone;
1319
1320                 params.zid_file=call->core->zrtp_secrets_cache;
1321                 audio_stream_enable_zrtp(call->audiostream,&params);
1322         } else if (call->params.media_encryption==LinphoneMediaEncryptionSRTP){
1323                 call->current_params.media_encryption=linphone_call_are_all_streams_encrypted(call) ?
1324                         LinphoneMediaEncryptionSRTP : LinphoneMediaEncryptionNone;
1325         }
1326 }
1327
1328
1329 static int dtmf_tab[16]={'0','1','2','3','4','5','6','7','8','9','*','#','A','B','C','D'};
1330
1331 static void linphone_core_dtmf_received(LinphoneCore *lc, int dtmf){
1332         if (dtmf<0 || dtmf>15){
1333                 ms_warning("Bad dtmf value %i",dtmf);
1334                 return;
1335         }
1336         if (lc->vtable.dtmf_received != NULL)
1337                 lc->vtable.dtmf_received(lc, linphone_core_get_current_call(lc), dtmf_tab[dtmf]);
1338 }
1339
1340 static void parametrize_equalizer(LinphoneCore *lc, AudioStream *st){
1341         if (st->equalizer){
1342                 MSFilter *f=st->equalizer;
1343                 int enabled=lp_config_get_int(lc->config,"sound","eq_active",0);
1344                 const char *gains=lp_config_get_string(lc->config,"sound","eq_gains",NULL);
1345                 ms_filter_call_method(f,MS_EQUALIZER_SET_ACTIVE,&enabled);
1346                 if (enabled){
1347                         if (gains){
1348                                 do{
1349                                         int bytes;
1350                                         MSEqualizerGain g;
1351                                         if (sscanf(gains,"%f:%f:%f %n",&g.frequency,&g.gain,&g.width,&bytes)==3){
1352                                                 ms_message("Read equalizer gains: %f(~%f) --> %f",g.frequency,g.width,g.gain);
1353                                                 ms_filter_call_method(f,MS_EQUALIZER_SET_GAIN,&g);
1354                                                 gains+=bytes;
1355                                         }else break;
1356                                 }while(1);
1357                         }
1358                 }
1359         }
1360 }
1361
1362 void _post_configure_audio_stream(AudioStream *st, LinphoneCore *lc, bool_t muted){
1363         float mic_gain=lc->sound_conf.soft_mic_lev;
1364         float thres = 0;
1365         float recv_gain;
1366         float ng_thres=lp_config_get_float(lc->config,"sound","ng_thres",0.05);
1367         float ng_floorgain=lp_config_get_float(lc->config,"sound","ng_floorgain",0);
1368         int dc_removal=lp_config_get_int(lc->config,"sound","dc_removal",0);
1369
1370         if (!muted)
1371                 linphone_core_set_mic_gain_db (lc, mic_gain);
1372         else
1373                 audio_stream_set_mic_gain(st,0);
1374
1375         recv_gain = lc->sound_conf.soft_play_lev;
1376         if (recv_gain != 0) {
1377                 linphone_core_set_playback_gain_db (lc,recv_gain);
1378         }
1379         
1380         if (st->volsend){
1381                 ms_filter_call_method(st->volsend,MS_VOLUME_REMOVE_DC,&dc_removal);
1382                 float speed=lp_config_get_float(lc->config,"sound","el_speed",-1);
1383                 thres=lp_config_get_float(lc->config,"sound","el_thres",-1);
1384                 float force=lp_config_get_float(lc->config,"sound","el_force",-1);
1385                 int sustain=lp_config_get_int(lc->config,"sound","el_sustain",-1);
1386                 float transmit_thres=lp_config_get_float(lc->config,"sound","el_transmit_thres",-1);
1387                 MSFilter *f=NULL;
1388                 f=st->volsend;
1389                 if (speed==-1) speed=0.03;
1390                 if (force==-1) force=25;
1391                 ms_filter_call_method(f,MS_VOLUME_SET_EA_SPEED,&speed);
1392                 ms_filter_call_method(f,MS_VOLUME_SET_EA_FORCE,&force);
1393                 if (thres!=-1)
1394                         ms_filter_call_method(f,MS_VOLUME_SET_EA_THRESHOLD,&thres);
1395                 if (sustain!=-1)
1396                         ms_filter_call_method(f,MS_VOLUME_SET_EA_SUSTAIN,&sustain);
1397                 if (transmit_thres!=-1)
1398                                 ms_filter_call_method(f,MS_VOLUME_SET_EA_TRANSMIT_THRESHOLD,&transmit_thres);
1399
1400                 ms_filter_call_method(st->volsend,MS_VOLUME_SET_NOISE_GATE_THRESHOLD,&ng_thres);
1401                 ms_filter_call_method(st->volsend,MS_VOLUME_SET_NOISE_GATE_FLOORGAIN,&ng_floorgain);
1402         }
1403         if (st->volrecv){
1404                 /* parameters for a limited noise-gate effect, using echo limiter threshold */
1405                 float floorgain = 1/pow(10,(mic_gain)/10);
1406                 int spk_agc=lp_config_get_int(lc->config,"sound","speaker_agc_enabled",0);
1407                 ms_filter_call_method(st->volrecv, MS_VOLUME_ENABLE_AGC, &spk_agc);
1408                 ms_filter_call_method(st->volrecv,MS_VOLUME_SET_NOISE_GATE_THRESHOLD,&ng_thres);
1409                 ms_filter_call_method(st->volrecv,MS_VOLUME_SET_NOISE_GATE_FLOORGAIN,&floorgain);
1410         }
1411         parametrize_equalizer(lc,st);
1412 }
1413
1414 static void post_configure_audio_streams(LinphoneCall*call){
1415         AudioStream *st=call->audiostream;
1416         LinphoneCore *lc=call->core;
1417         _post_configure_audio_stream(st,lc,call->audio_muted);
1418         if (lc->vtable.dtmf_received!=NULL){
1419                 audio_stream_play_received_dtmfs(call->audiostream,FALSE);
1420         }
1421         if (call->record_active) 
1422                 linphone_call_start_recording(call);
1423 }
1424
1425 static RtpProfile *make_profile(LinphoneCall *call, const SalMediaDescription *md, const SalStreamDescription *desc, int *used_pt){
1426         int bw;
1427         const MSList *elem;
1428         RtpProfile *prof=rtp_profile_new("Call profile");
1429         bool_t first=TRUE;
1430         int remote_bw=0;
1431         LinphoneCore *lc=call->core;
1432         int up_ptime=0;
1433         const LinphoneCallParams *params=&call->params;
1434         *used_pt=-1;
1435
1436         for(elem=desc->payloads;elem!=NULL;elem=elem->next){
1437                 PayloadType *pt=(PayloadType*)elem->data;
1438                 int number;
1439
1440                 if ((pt->flags & PAYLOAD_TYPE_FLAG_CAN_SEND) && first) {
1441                         if (desc->type==SalAudio){
1442                                 linphone_core_update_allocated_audio_bandwidth_in_call(call,pt);
1443                                 if (params->up_ptime)
1444                                         up_ptime=params->up_ptime;
1445                                 else up_ptime=linphone_core_get_upload_ptime(lc);
1446                         }
1447                         *used_pt=payload_type_get_number(pt);
1448                         first=FALSE;
1449                 }
1450                 if (desc->bandwidth>0) remote_bw=desc->bandwidth;
1451                 else if (md->bandwidth>0) {
1452                         /*case where b=AS is given globally, not per stream*/
1453                         remote_bw=md->bandwidth;
1454                         if (desc->type==SalVideo){
1455                                 remote_bw=get_video_bandwidth(remote_bw,call->audio_bw);
1456                         }
1457                 }
1458
1459                 if (desc->type==SalAudio){
1460                         int audio_bw=call->audio_bw;
1461                         if (params->up_bw){
1462                                 if (params->up_bw< audio_bw)
1463                                         audio_bw=params->up_bw;
1464                         }
1465                         bw=get_min_bandwidth(audio_bw,remote_bw);
1466                 }else bw=get_min_bandwidth(get_video_bandwidth(linphone_core_get_upload_bandwidth (lc),call->audio_bw),remote_bw);
1467                 if (bw>0) pt->normal_bitrate=bw*1000;
1468                 else if (desc->type==SalAudio){
1469                         pt->normal_bitrate=-1;
1470                 }
1471                 if (desc->ptime>0){
1472                         up_ptime=desc->ptime;
1473                 }
1474                 if (up_ptime>0){
1475                         char tmp[40];
1476                         snprintf(tmp,sizeof(tmp),"ptime=%i",up_ptime);
1477                         payload_type_append_send_fmtp(pt,tmp);
1478                 }
1479                 number=payload_type_get_number(pt);
1480                 if (rtp_profile_get_payload(prof,number)!=NULL){
1481                         ms_warning("A payload type with number %i already exists in profile !",number);
1482                 }else
1483                         rtp_profile_set_payload(prof,number,pt);
1484         }
1485         return prof;
1486 }
1487
1488
1489 static void setup_ring_player(LinphoneCore *lc, LinphoneCall *call){
1490         int pause_time=3000;
1491         audio_stream_play(call->audiostream,lc->sound_conf.ringback_tone);
1492         ms_filter_call_method(call->audiostream->soundread,MS_FILE_PLAYER_LOOP,&pause_time);
1493 }
1494
1495 static bool_t linphone_call_sound_resources_available(LinphoneCall *call){
1496         LinphoneCore *lc=call->core;
1497         LinphoneCall *current=linphone_core_get_current_call(lc);
1498         return !linphone_core_is_in_conference(lc) && 
1499                 (current==NULL || current==call);
1500 }
1501 static int find_crypto_index_from_tag(const SalSrtpCryptoAlgo crypto[],unsigned char tag) {
1502     int i;
1503     for(i=0; i<SAL_CRYPTO_ALGO_MAX; i++) {
1504         if (crypto[i].tag == tag) {
1505             return i;
1506         }
1507     }
1508     return -1;
1509 }
1510 static void linphone_call_start_audio_stream(LinphoneCall *call, const char *cname, bool_t muted, bool_t send_ringbacktone, bool_t use_arc){
1511         LinphoneCore *lc=call->core;
1512         int used_pt=-1;
1513         char rtcp_tool[128]={0};
1514         snprintf(rtcp_tool,sizeof(rtcp_tool)-1,"%s-%s",linphone_core_get_user_agent_name(),linphone_core_get_user_agent_version());
1515         /* look for savp stream first */
1516         const SalStreamDescription *stream=sal_media_description_find_stream(call->resultdesc,
1517                                                 SalProtoRtpSavp,SalAudio);
1518         /* no savp audio stream, use avp */
1519         if (!stream)
1520                 stream=sal_media_description_find_stream(call->resultdesc,
1521                                                 SalProtoRtpAvp,SalAudio);
1522
1523         if (stream && stream->dir!=SalStreamInactive && stream->rtp_port!=0){
1524                 MSSndCard *playcard=lc->sound_conf.lsd_card ?
1525                         lc->sound_conf.lsd_card : lc->sound_conf.play_sndcard;
1526                 MSSndCard *captcard=lc->sound_conf.capt_sndcard;
1527                 const char *playfile=lc->play_file;
1528                 const char *recfile=lc->rec_file;
1529                 call->audio_profile=make_profile(call,call->resultdesc,stream,&used_pt);
1530                 bool_t use_ec;
1531
1532                 if (used_pt!=-1){
1533                         call->current_params.audio_codec = rtp_profile_get_payload(call->audio_profile, used_pt);
1534                         if (playcard==NULL) {
1535                                 ms_warning("No card defined for playback !");
1536                         }
1537                         if (captcard==NULL) {
1538                                 ms_warning("No card defined for capture !");
1539                         }
1540                         /*Replace soundcard filters by inactive file players or recorders
1541                          when placed in recvonly or sendonly mode*/
1542                         if (stream->rtp_port==0 || stream->dir==SalStreamRecvOnly){
1543                                 captcard=NULL;
1544                                 playfile=NULL;
1545                         }else if (stream->dir==SalStreamSendOnly){
1546                                 playcard=NULL;
1547                                 captcard=NULL;
1548                                 recfile=NULL;
1549                                 /*And we will eventually play "playfile" if set by the user*/
1550                                 /*playfile=NULL;*/
1551                         }
1552                         if (send_ringbacktone){
1553                                 captcard=NULL;
1554                                 playfile=NULL;/* it is setup later*/
1555                         }
1556                         /*if playfile are supplied don't use soundcards*/
1557                         if (lc->use_files) {
1558                                 captcard=NULL;
1559                                 playcard=NULL;
1560                         }
1561                         if (call->params.in_conference){
1562                                 /* first create the graph without soundcard resources*/
1563                                 captcard=playcard=NULL;
1564                         }
1565                         if (!linphone_call_sound_resources_available(call)){
1566                                 ms_message("Sound resources are used by another call, not using soundcard.");
1567                                 captcard=playcard=NULL;
1568                         }
1569                         use_ec=captcard==NULL ? FALSE : linphone_core_echo_cancellation_enabled(lc);
1570                         if (playcard &&  stream->max_rate>0) ms_snd_card_set_preferred_sample_rate(playcard, stream->max_rate);
1571                         if (captcard &&  stream->max_rate>0) ms_snd_card_set_preferred_sample_rate(captcard, stream->max_rate);
1572                         audio_stream_enable_adaptive_bitrate_control(call->audiostream,use_arc);
1573                         audio_stream_enable_adaptive_jittcomp(call->audiostream, linphone_core_audio_adaptive_jittcomp_enabled(lc));
1574                         if (!call->params.in_conference && call->params.record_file)
1575                                 audio_stream_mixed_record_open(call->audiostream,call->params.record_file);
1576                         audio_stream_start_full(
1577                                 call->audiostream,
1578                                 call->audio_profile,
1579                                 stream->rtp_addr[0]!='\0' ? stream->rtp_addr : call->resultdesc->addr,
1580                                 stream->rtp_port,
1581                                 stream->rtcp_addr[0]!='\0' ? stream->rtcp_addr : call->resultdesc->addr,
1582                                 linphone_core_rtcp_enabled(lc) ? (stream->rtcp_port) : 0,
1583                                 used_pt,
1584                                 linphone_core_get_audio_jittcomp(lc),
1585                                 playfile,
1586                                 recfile,
1587                                 playcard,
1588                                 captcard,
1589                                 use_ec
1590                                 );
1591                         post_configure_audio_streams(call);
1592                         if (muted && !send_ringbacktone){
1593                                 audio_stream_set_mic_gain(call->audiostream,0);
1594                         }
1595                         if (stream->dir==SalStreamSendOnly && playfile!=NULL){
1596                                 int pause_time=500;
1597                                 ms_filter_call_method(call->audiostream->soundread,MS_FILE_PLAYER_LOOP,&pause_time);
1598                         }
1599                         if (send_ringbacktone){
1600                                 setup_ring_player(lc,call);
1601                         }
1602                         audio_stream_set_rtcp_information(call->audiostream, cname, rtcp_tool);
1603                         
1604                         /* valid local tags are > 0 */
1605                         if (stream->proto == SalProtoRtpSavp) {
1606                         const SalStreamDescription *local_st_desc=sal_media_description_find_stream(call->localdesc,
1607                                                                                                         SalProtoRtpSavp,SalAudio);
1608                         int crypto_idx = find_crypto_index_from_tag(local_st_desc->crypto, stream->crypto_local_tag);
1609
1610                         if (crypto_idx >= 0) {
1611                                 audio_stream_enable_srtp(
1612                                                         call->audiostream, 
1613                                                         stream->crypto[0].algo,
1614                                                         local_st_desc->crypto[crypto_idx].master_key,
1615                                                         stream->crypto[0].master_key);
1616                                 call->audiostream_encrypted=TRUE;
1617                         } else {
1618                                 ms_warning("Failed to find local crypto algo with tag: %d", stream->crypto_local_tag);
1619                                 call->audiostream_encrypted=FALSE;
1620                         }
1621                         }else call->audiostream_encrypted=FALSE;
1622                         if (call->params.in_conference){
1623                                 /*transform the graph to connect it to the conference filter */
1624                                 bool_t mute=stream->dir==SalStreamRecvOnly;
1625                                 linphone_call_add_to_conf(call, mute);
1626                         }
1627                         call->current_params.in_conference=call->params.in_conference;
1628                         call->current_params.low_bandwidth=call->params.low_bandwidth;
1629                 }else ms_warning("No audio stream accepted ?");
1630         }
1631 }
1632
1633 static void linphone_call_start_video_stream(LinphoneCall *call, const char *cname,bool_t all_inputs_muted){
1634 #ifdef VIDEO_ENABLED
1635         LinphoneCore *lc=call->core;
1636         int used_pt=-1;
1637         /* look for savp stream first */
1638         const SalStreamDescription *vstream=sal_media_description_find_stream(call->resultdesc,
1639                                                 SalProtoRtpSavp,SalVideo);
1640         char rtcp_tool[128]={0};
1641         snprintf(rtcp_tool,sizeof(rtcp_tool)-1,"%s-%s",linphone_core_get_user_agent_name(),linphone_core_get_user_agent_version());
1642         
1643         /* no savp audio stream, use avp */
1644         if (!vstream)
1645                 vstream=sal_media_description_find_stream(call->resultdesc,
1646                                                 SalProtoRtpAvp,SalVideo);
1647                                                 
1648         /* shutdown preview */
1649         if (lc->previewstream!=NULL) {
1650                 video_preview_stop(lc->previewstream);
1651                 lc->previewstream=NULL;
1652         }
1653         
1654         if (vstream!=NULL && vstream->dir!=SalStreamInactive && vstream->rtp_port!=0) {
1655                 const char *rtp_addr=vstream->rtp_addr[0]!='\0' ? vstream->rtp_addr : call->resultdesc->addr;
1656                 const char *rtcp_addr=vstream->rtcp_addr[0]!='\0' ? vstream->rtcp_addr : call->resultdesc->addr;
1657                 call->video_profile=make_profile(call,call->resultdesc,vstream,&used_pt);
1658                 if (used_pt!=-1){
1659                         call->current_params.video_codec = rtp_profile_get_payload(call->video_profile, used_pt);
1660                         VideoStreamDir dir=VideoStreamSendRecv;
1661                         MSWebCam *cam=lc->video_conf.device;
1662                         bool_t is_inactive=FALSE;
1663
1664                         call->current_params.has_video=TRUE;
1665
1666                         video_stream_enable_adaptive_bitrate_control(call->videostream,
1667                                                                   linphone_core_adaptive_rate_control_enabled(lc));
1668                         video_stream_enable_adaptive_jittcomp(call->videostream, linphone_core_video_adaptive_jittcomp_enabled(lc));
1669                         video_stream_set_sent_video_size(call->videostream,linphone_core_get_preferred_video_size(lc));
1670                         video_stream_enable_self_view(call->videostream,lc->video_conf.selfview);
1671                         if (lc->video_window_id!=0)
1672                                 video_stream_set_native_window_id(call->videostream,lc->video_window_id);
1673                         if (lc->preview_window_id!=0)
1674                                 video_stream_set_native_preview_window_id (call->videostream,lc->preview_window_id);
1675                         video_stream_use_preview_video_window (call->videostream,lc->use_preview_window);
1676                         
1677                         if (vstream->dir==SalStreamSendOnly && lc->video_conf.capture ){
1678                                 cam=get_nowebcam_device();
1679                                 dir=VideoStreamSendOnly;
1680                         }else if (vstream->dir==SalStreamRecvOnly && lc->video_conf.display ){
1681                                 dir=VideoStreamRecvOnly;
1682                         }else if (vstream->dir==SalStreamSendRecv){
1683                                 if (lc->video_conf.display && lc->video_conf.capture)
1684                                         dir=VideoStreamSendRecv;
1685                                 else if (lc->video_conf.display)
1686                                         dir=VideoStreamRecvOnly;
1687                                 else
1688                                         dir=VideoStreamSendOnly;
1689                         }else{
1690                                 ms_warning("video stream is inactive.");
1691                                 /*either inactive or incompatible with local capabilities*/
1692                                 is_inactive=TRUE;
1693                         }
1694                         if (call->camera_active==FALSE || all_inputs_muted){
1695                                 cam=get_nowebcam_device();
1696                         }
1697                         if (!is_inactive){
1698                                 call->log->video_enabled = TRUE;
1699                                 video_stream_set_direction (call->videostream, dir);
1700                                 ms_message("%s lc rotation:%d\n", __FUNCTION__, lc->device_rotation);
1701                                 video_stream_set_device_rotation(call->videostream, lc->device_rotation);
1702                                 video_stream_start(call->videostream,
1703                                         call->video_profile, rtp_addr, vstream->rtp_port,
1704                                         rtcp_addr, linphone_core_rtcp_enabled(lc) ? (vstream->rtcp_port) : 0,
1705                                         used_pt, linphone_core_get_video_jittcomp(lc), cam);
1706                                 video_stream_set_rtcp_information(call->videostream, cname,rtcp_tool);
1707                         }
1708                         
1709                         if (vstream->proto == SalProtoRtpSavp) {
1710                                 const SalStreamDescription *local_st_desc=sal_media_description_find_stream(call->localdesc,
1711                                                 SalProtoRtpSavp,SalVideo);
1712                                                 
1713                                 video_stream_enable_strp(
1714                                         call->videostream, 
1715                                         vstream->crypto[0].algo,
1716                                         local_st_desc->crypto[0].master_key, 
1717                                         vstream->crypto[0].master_key
1718                                         );
1719                                 call->videostream_encrypted=TRUE;
1720                         }else{
1721                                 call->videostream_encrypted=FALSE;
1722                         }
1723                 }else ms_warning("No video stream accepted.");
1724         }else{
1725                 ms_warning("No valid video stream defined.");
1726         }
1727 #endif
1728 }
1729
1730 void linphone_call_start_media_streams(LinphoneCall *call, bool_t all_inputs_muted, bool_t send_ringbacktone){
1731         LinphoneCore *lc=call->core;
1732
1733         call->current_params.audio_codec = NULL;
1734         call->current_params.video_codec = NULL;
1735
1736         LinphoneAddress *me=linphone_core_get_primary_contact_parsed(lc);
1737         char *cname;
1738         bool_t use_arc=linphone_core_adaptive_rate_control_enabled(lc);
1739 #ifdef VIDEO_ENABLED
1740         const SalStreamDescription *vstream=sal_media_description_find_stream(call->resultdesc,
1741                                                         SalProtoRtpAvp,SalVideo);
1742 #endif
1743
1744         if ((call->audiostream == NULL) && (call->videostream == NULL)) {
1745                 ms_fatal("start_media_stream() called without prior init !");
1746                 return;
1747         }
1748         cname=linphone_address_as_string_uri_only(me);
1749
1750 #if defined(VIDEO_ENABLED)
1751         if (vstream!=NULL && vstream->dir!=SalStreamInactive && vstream->payloads!=NULL){
1752                 /*when video is used, do not make adaptive rate control on audio, it is stupid.*/
1753                 use_arc=FALSE;
1754         }
1755 #endif
1756         if (call->audiostream!=NULL) {
1757                 linphone_call_start_audio_stream(call,cname,all_inputs_muted,send_ringbacktone,use_arc);
1758         }
1759         call->current_params.has_video=FALSE;
1760         if (call->videostream!=NULL) {
1761                 linphone_call_start_video_stream(call,cname,all_inputs_muted);
1762         }
1763
1764         call->all_muted=all_inputs_muted;
1765         call->playing_ringbacktone=send_ringbacktone;
1766         call->up_bw=linphone_core_get_upload_bandwidth(lc);
1767
1768         // ZRTP was initialized in linphone_call_init_media_streams with a
1769         // partially iniitalized RtpSession, and now needs to get an update
1770         if (call->params.media_encryption==LinphoneMediaEncryptionZRTP) {
1771                 ortp_zrtp_start_engine(call->audiostream->ms.zrtp_context,call->audiostream->ms.session);
1772         }
1773
1774         /*also reflect the change if the "wished" params, in order to avoid to propose SAVP or video again
1775          * further in the call, for example during pause,resume, conferencing reINVITEs*/
1776         linphone_call_fix_call_parameters(call);
1777         if ((call->ice_session != NULL) && (ice_session_state(call->ice_session) != IS_Completed)) {
1778                 ice_session_start_connectivity_checks(call->ice_session);
1779         }
1780
1781         goto end;
1782         end:
1783                 ms_free(cname);
1784                 linphone_address_destroy(me);
1785 }
1786
1787 void linphone_call_start_media_streams_for_ice_gathering(LinphoneCall *call){
1788         audio_stream_prepare_sound(call->audiostream, NULL, NULL);
1789 #ifdef VIDEO_ENABLED
1790         if (call->videostream) {
1791                 video_stream_prepare_video(call->videostream);
1792         }
1793 #endif
1794 }
1795
1796 void linphone_call_stop_media_streams_for_ice_gathering(LinphoneCall *call){
1797         audio_stream_unprepare_sound(call->audiostream);
1798 #ifdef VIDEO_ENABLED
1799         if (call->videostream) {
1800                 video_stream_unprepare_video(call->videostream);
1801         }
1802 #endif
1803 }
1804
1805 void linphone_call_update_crypto_parameters(LinphoneCall *call, SalMediaDescription *old_md, SalMediaDescription *new_md) {
1806         SalStreamDescription *old_stream;
1807         SalStreamDescription *new_stream;
1808         int i;
1809
1810         old_stream = sal_media_description_find_stream(old_md, SalProtoRtpSavp, SalAudio);
1811         new_stream = sal_media_description_find_stream(new_md, SalProtoRtpSavp, SalAudio);
1812         if (old_stream && new_stream) {
1813                 const SalStreamDescription *local_st_desc = sal_media_description_find_stream(call->localdesc, SalProtoRtpSavp, SalAudio);
1814                 if (local_st_desc) {
1815                         int crypto_idx = find_crypto_index_from_tag(local_st_desc->crypto, new_stream->crypto_local_tag);
1816                         if (crypto_idx >= 0) {
1817                                 audio_stream_enable_srtp(call->audiostream, new_stream->crypto[0].algo, local_st_desc->crypto[crypto_idx].master_key, new_stream->crypto[0].master_key);
1818                                 call->audiostream_encrypted = TRUE;
1819                         } else {
1820                                 ms_warning("Failed to find local crypto algo with tag: %d", new_stream->crypto_local_tag);
1821                                 call->audiostream_encrypted = FALSE;
1822                         }
1823                         for (i = 0; i < SAL_CRYPTO_ALGO_MAX; i++) {
1824                                 old_stream->crypto[i].tag = new_stream->crypto[i].tag;
1825                                 old_stream->crypto[i].algo = new_stream->crypto[i].algo;
1826                                 strncpy(old_stream->crypto[i].master_key, new_stream->crypto[i].master_key, sizeof(old_stream->crypto[i].master_key) - 1);
1827                         }
1828                 }
1829         }
1830
1831 #ifdef VIDEO_ENABLED
1832         old_stream = sal_media_description_find_stream(old_md, SalProtoRtpSavp, SalVideo);
1833         new_stream = sal_media_description_find_stream(new_md, SalProtoRtpSavp, SalVideo);
1834         if (old_stream && new_stream) {
1835                 const SalStreamDescription *local_st_desc = sal_media_description_find_stream(call->localdesc, SalProtoRtpSavp, SalVideo);
1836                 if (local_st_desc) {
1837                         int crypto_idx = find_crypto_index_from_tag(local_st_desc->crypto, new_stream->crypto_local_tag);
1838                         if (crypto_idx >= 0) {
1839                                 video_stream_enable_strp(call->videostream, new_stream->crypto[0].algo, local_st_desc->crypto[crypto_idx].master_key, new_stream->crypto[0].master_key);
1840                                 call->videostream_encrypted = TRUE;
1841                         } else {
1842                                 ms_warning("Failed to find local crypto algo with tag: %d", new_stream->crypto_local_tag);
1843                                 call->videostream_encrypted = FALSE;
1844                         }
1845                         for (i = 0; i < SAL_CRYPTO_ALGO_MAX; i++) {
1846                                 old_stream->crypto[i].tag = new_stream->crypto[i].tag;
1847                                 old_stream->crypto[i].algo = new_stream->crypto[i].algo;
1848                                 strncpy(old_stream->crypto[i].master_key, new_stream->crypto[i].master_key, sizeof(old_stream->crypto[i].master_key) - 1);
1849                         }
1850                 }
1851         }
1852 #endif
1853 }
1854
1855 void linphone_call_update_remote_session_id_and_ver(LinphoneCall *call) {
1856         SalMediaDescription *remote_desc = sal_call_get_remote_media_description(call->op);
1857         if (remote_desc) {
1858                 call->remote_session_id = remote_desc->session_id;
1859                 call->remote_session_ver = remote_desc->session_ver;
1860         }
1861 }
1862
1863 void linphone_call_delete_ice_session(LinphoneCall *call){
1864         if (call->ice_session != NULL) {
1865                 ice_session_destroy(call->ice_session);
1866                 call->ice_session = NULL;
1867                 if (call->audiostream != NULL) call->audiostream->ms.ice_check_list = NULL;
1868                 if (call->videostream != NULL) call->videostream->ms.ice_check_list = NULL;
1869                 call->stats[LINPHONE_CALL_STATS_AUDIO].ice_state = LinphoneIceStateNotActivated;
1870                 call->stats[LINPHONE_CALL_STATS_VIDEO].ice_state = LinphoneIceStateNotActivated;
1871         }
1872 }
1873
1874 #ifdef BUILD_UPNP
1875 void linphone_call_delete_upnp_session(LinphoneCall *call){
1876         if(call->upnp_session!=NULL) {
1877                 linphone_upnp_session_destroy(call->upnp_session);
1878                 call->upnp_session=NULL;
1879         }
1880 }
1881 #endif //BUILD_UPNP
1882
1883 static void linphone_call_log_fill_stats(LinphoneCallLog *log, AudioStream *st){
1884         audio_stream_get_local_rtp_stats (st,&log->local_stats);
1885         log->quality=audio_stream_get_average_quality_rating(st);
1886 }
1887
1888 void linphone_call_stop_audio_stream(LinphoneCall *call) {
1889         if (call->audiostream!=NULL) {
1890                 rtp_session_unregister_event_queue(call->audiostream->ms.session,call->audiostream_app_evq);
1891                 ortp_ev_queue_flush(call->audiostream_app_evq);
1892                 ortp_ev_queue_destroy(call->audiostream_app_evq);
1893                 call->audiostream_app_evq=NULL;
1894
1895                 if (call->audiostream->ec){
1896                         const char *state_str=NULL;
1897                         ms_filter_call_method(call->audiostream->ec,MS_ECHO_CANCELLER_GET_STATE_STRING,&state_str);
1898                         if (state_str){
1899                                 ms_message("Writing echo canceler state, %i bytes",(int)strlen(state_str));
1900                                 lp_config_set_string(call->core->config,"sound","ec_state",state_str);
1901                         }
1902                 }
1903                 linphone_call_log_fill_stats (call->log,call->audiostream);
1904                 if (call->endpoint){
1905                         linphone_call_remove_from_conf(call);
1906                 }
1907                 audio_stream_stop(call->audiostream);
1908                 call->audiostream=NULL;
1909         }
1910 }
1911
1912 void linphone_call_stop_video_stream(LinphoneCall *call) {
1913 #ifdef VIDEO_ENABLED
1914         if (call->videostream!=NULL){
1915                 rtp_session_unregister_event_queue(call->videostream->ms.session,call->videostream_app_evq);
1916                 ortp_ev_queue_flush(call->videostream_app_evq);
1917                 ortp_ev_queue_destroy(call->videostream_app_evq);
1918                 call->videostream_app_evq=NULL;
1919                 video_stream_stop(call->videostream);
1920                 call->videostream=NULL;
1921         }
1922 #endif
1923 }
1924
1925 void linphone_call_stop_media_streams(LinphoneCall *call){
1926         linphone_call_stop_audio_stream(call);
1927         linphone_call_stop_video_stream(call);
1928         ms_event_queue_skip(call->core->msevq);
1929         
1930         if (call->audio_profile){
1931                 rtp_profile_clear_all(call->audio_profile);
1932                 rtp_profile_destroy(call->audio_profile);
1933                 call->audio_profile=NULL;
1934         }
1935         if (call->video_profile){
1936                 rtp_profile_clear_all(call->video_profile);
1937                 rtp_profile_destroy(call->video_profile);
1938                 call->video_profile=NULL;
1939         }
1940 }
1941
1942
1943
1944 void linphone_call_enable_echo_cancellation(LinphoneCall *call, bool_t enable) {
1945         if (call!=NULL && call->audiostream!=NULL && call->audiostream->ec){
1946                 bool_t bypass_mode = !enable;
1947                 ms_filter_call_method(call->audiostream->ec,MS_ECHO_CANCELLER_SET_BYPASS_MODE,&bypass_mode);
1948         }
1949 }
1950 bool_t linphone_call_echo_cancellation_enabled(LinphoneCall *call) {
1951         if (call!=NULL && call->audiostream!=NULL && call->audiostream->ec){
1952                 bool_t val;
1953                 ms_filter_call_method(call->audiostream->ec,MS_ECHO_CANCELLER_GET_BYPASS_MODE,&val);
1954                 return !val;
1955         } else {
1956                 return linphone_core_echo_cancellation_enabled(call->core);
1957         }
1958 }
1959
1960 void linphone_call_enable_echo_limiter(LinphoneCall *call, bool_t val){
1961         if (call!=NULL && call->audiostream!=NULL ) {
1962                 if (val) {
1963                 const char *type=lp_config_get_string(call->core->config,"sound","el_type","mic");
1964                 if (strcasecmp(type,"mic")==0)
1965                         audio_stream_enable_echo_limiter(call->audiostream,ELControlMic);
1966                 else if (strcasecmp(type,"full")==0)
1967                         audio_stream_enable_echo_limiter(call->audiostream,ELControlFull);
1968                 } else {
1969                         audio_stream_enable_echo_limiter(call->audiostream,ELInactive);
1970                 }
1971         }
1972 }
1973
1974 bool_t linphone_call_echo_limiter_enabled(const LinphoneCall *call){
1975         if (call!=NULL && call->audiostream!=NULL ){
1976                 return call->audiostream->el_type !=ELInactive ;
1977         } else {
1978                 return linphone_core_echo_limiter_enabled(call->core);
1979         }
1980 }
1981
1982 /**
1983  * @addtogroup call_misc
1984  * @{
1985 **/
1986
1987 /**
1988  * Returns the measured sound volume played locally (received from remote).
1989  * It is expressed in dbm0.
1990 **/
1991 float linphone_call_get_play_volume(LinphoneCall *call){
1992         AudioStream *st=call->audiostream;
1993         if (st && st->volrecv){
1994                 float vol=0;
1995                 ms_filter_call_method(st->volrecv,MS_VOLUME_GET,&vol);
1996                 return vol;
1997
1998         }
1999         return LINPHONE_VOLUME_DB_LOWEST;
2000 }
2001
2002 /**
2003  * Returns the measured sound volume recorded locally (sent to remote).
2004  * It is expressed in dbm0.
2005 **/
2006 float linphone_call_get_record_volume(LinphoneCall *call){
2007         AudioStream *st=call->audiostream;
2008         if (st && st->volsend && !call->audio_muted && call->state==LinphoneCallStreamsRunning){
2009                 float vol=0;
2010                 ms_filter_call_method(st->volsend,MS_VOLUME_GET,&vol);
2011                 return vol;
2012
2013         }
2014         return LINPHONE_VOLUME_DB_LOWEST;
2015 }
2016
2017 /**
2018  * Obtain real-time quality rating of the call
2019  *
2020  * Based on local RTP statistics and RTCP feedback, a quality rating is computed and updated
2021  * during all the duration of the call. This function returns its value at the time of the function call.
2022  * It is expected that the rating is updated at least every 5 seconds or so.
2023  * The rating is a floating point number comprised between 0 and 5.
2024  *
2025  * 4-5 = good quality <br>
2026  * 3-4 = average quality <br>
2027  * 2-3 = poor quality <br>
2028  * 1-2 = very poor quality <br>
2029  * 0-1 = can't be worse, mostly unusable <br>
2030  *
2031  * @returns The function returns -1 if no quality measurement is available, for example if no
2032  * active audio stream exist. Otherwise it returns the quality rating.
2033 **/
2034 float linphone_call_get_current_quality(LinphoneCall *call){
2035         if (call->audiostream){
2036                 return audio_stream_get_quality_rating(call->audiostream);
2037         }
2038         return -1;
2039 }
2040
2041 /**
2042  * Returns call quality averaged over all the duration of the call.
2043  *
2044  * See linphone_call_get_current_quality() for more details about quality measurement.
2045 **/
2046 float linphone_call_get_average_quality(LinphoneCall *call){
2047         if (call->audiostream){
2048                 return audio_stream_get_average_quality_rating(call->audiostream);
2049         }
2050         return -1;
2051 }
2052
2053 /**
2054  * Access last known statistics for audio stream, for a given call.
2055 **/
2056 const LinphoneCallStats *linphone_call_get_audio_stats(const LinphoneCall *call) {
2057         return &call->stats[LINPHONE_CALL_STATS_AUDIO];
2058 }
2059
2060 /**
2061  * Access last known statistics for video stream, for a given call.
2062 **/
2063 const LinphoneCallStats *linphone_call_get_video_stats(const LinphoneCall *call) {
2064         return &call->stats[LINPHONE_CALL_STATS_VIDEO];
2065 }
2066
2067 /**
2068  * Enable recording of the call (voice-only).
2069  * This function must be used before the call parameters are assigned to the call.
2070  * The call recording can be started and paused after the call is established with
2071  * linphone_call_start_recording() and linphone_call_pause_recording().
2072  * @param cp the call parameters
2073  * @param path path and filename of the file where audio is written.
2074 **/
2075 void linphone_call_params_set_record_file(LinphoneCallParams *cp, const char *path){
2076         if (cp->record_file){
2077                 ms_free(cp->record_file);
2078                 cp->record_file=NULL;
2079         }
2080         if (path) cp->record_file=ms_strdup(path);
2081 }
2082
2083 /**
2084  * Retrieves the path for the audio recoding of the call.
2085 **/
2086 const char *linphone_call_params_get_record_file(const LinphoneCallParams *cp){
2087         return cp->record_file;
2088 }
2089
2090 /**
2091  * Start call recording.
2092  * The output file where audio is recorded must be previously specified with linphone_call_params_set_record_file().
2093 **/
2094 void linphone_call_start_recording(LinphoneCall *call){
2095         if (!call->params.record_file){
2096                 ms_error("linphone_call_start_recording(): no output file specified. Use linphone_call_params_set_record_file().");
2097                 return;
2098         }
2099         if (call->audiostream && !call->params.in_conference){
2100                 audio_stream_mixed_record_start(call->audiostream);
2101         }
2102         call->record_active=TRUE;
2103 }
2104
2105 /**
2106  * Stop call recording.
2107 **/
2108 void linphone_call_stop_recording(LinphoneCall *call){
2109         if (call->audiostream && !call->params.in_conference){
2110                 audio_stream_mixed_record_stop(call->audiostream);
2111         }
2112         call->record_active=FALSE;
2113 }
2114
2115 /**
2116  * @}
2117 **/
2118
2119 static void report_bandwidth(LinphoneCall *call, RtpSession *as, RtpSession *vs){
2120         call->stats[LINPHONE_CALL_STATS_AUDIO].download_bandwidth=(as!=NULL) ? (rtp_session_compute_recv_bandwidth(as)*1e-3) : 0;
2121         call->stats[LINPHONE_CALL_STATS_AUDIO].upload_bandwidth=(as!=NULL) ? (rtp_session_compute_send_bandwidth(as)*1e-3) : 0;
2122         call->stats[LINPHONE_CALL_STATS_VIDEO].download_bandwidth=(vs!=NULL) ? (rtp_session_compute_recv_bandwidth(vs)*1e-3) : 0;
2123         call->stats[LINPHONE_CALL_STATS_VIDEO].upload_bandwidth=(vs!=NULL) ? (rtp_session_compute_send_bandwidth(vs)*1e-3) : 0;
2124         ms_message("bandwidth usage: audio=[d=%.1f,u=%.1f] video=[d=%.1f,u=%.1f] kbit/sec",
2125                 call->stats[LINPHONE_CALL_STATS_AUDIO].download_bandwidth,
2126                 call->stats[LINPHONE_CALL_STATS_AUDIO].upload_bandwidth ,
2127                 call->stats[LINPHONE_CALL_STATS_VIDEO].download_bandwidth,
2128                 call->stats[LINPHONE_CALL_STATS_VIDEO].upload_bandwidth
2129         );
2130 }
2131
2132 static void linphone_core_disconnected(LinphoneCore *lc, LinphoneCall *call){
2133         char temp[256];
2134         char *from=NULL;
2135         if(call)
2136                 from = linphone_call_get_remote_address_as_string(call);
2137         if (from)
2138         {
2139                 snprintf(temp,sizeof(temp),"Remote end %s seems to have disconnected, the call is going to be closed.",from);
2140                 ms_free(from);
2141         }
2142         else
2143         {
2144                 snprintf(temp,sizeof(temp),"Remote end seems to have disconnected, the call is going to be closed.");
2145         }
2146         if (lc->vtable.display_warning!=NULL)
2147                 lc->vtable.display_warning(lc,temp);
2148         linphone_core_terminate_call(lc,call);
2149         linphone_core_play_named_tone(lc,LinphoneToneCallFailed);
2150 }
2151
2152 static void handle_ice_events(LinphoneCall *call, OrtpEvent *ev){
2153         OrtpEventType evt=ortp_event_get_type(ev);
2154         OrtpEventData *evd=ortp_event_get_data(ev);
2155         int ping_time;
2156
2157         if (evt == ORTP_EVENT_ICE_SESSION_PROCESSING_FINISHED) {
2158                 switch (ice_session_state(call->ice_session)) {
2159                         case IS_Completed:
2160                                 ice_session_select_candidates(call->ice_session);
2161                                 if (ice_session_role(call->ice_session) == IR_Controlling) {
2162                                         linphone_core_update_call(call->core, call, &call->current_params);
2163                                 }
2164                                 break;
2165                         case IS_Failed:
2166                                 if (ice_session_has_completed_check_list(call->ice_session) == TRUE) {
2167                                         ice_session_select_candidates(call->ice_session);
2168                                         if (ice_session_role(call->ice_session) == IR_Controlling) {
2169                                                 /* At least one ICE session has succeeded, so perform a call update. */
2170                                                 linphone_core_update_call(call->core, call, &call->current_params);
2171                                         }
2172                                 }
2173                                 break;
2174                         default:
2175                                 break;
2176                 }
2177                 linphone_core_update_ice_state_in_call_stats(call);
2178         } else if (evt == ORTP_EVENT_ICE_GATHERING_FINISHED) {
2179
2180                 if (evd->info.ice_processing_successful==TRUE) {
2181                         ice_session_compute_candidates_foundations(call->ice_session);
2182                         ice_session_eliminate_redundant_candidates(call->ice_session);
2183                         ice_session_choose_default_candidates(call->ice_session);
2184                         ping_time = ice_session_average_gathering_round_trip_time(call->ice_session);
2185                         if (ping_time >=0) {
2186                                 call->ping_time=ping_time;
2187                         }
2188                 } else {
2189                         ms_warning("No STUN answer from [%s], disabling ICE",linphone_core_get_stun_server(call->core));
2190                         linphone_call_delete_ice_session(call);
2191                 }
2192                 switch (call->state) {
2193                         case LinphoneCallUpdating:
2194                                 linphone_core_start_update_call(call->core, call);
2195                                 break;
2196                         case LinphoneCallUpdatedByRemote:
2197                                 linphone_core_start_accept_call_update(call->core, call);
2198                                 break;
2199                         case LinphoneCallOutgoingInit:
2200                                 linphone_call_stop_media_streams_for_ice_gathering(call);
2201                                 linphone_core_proceed_with_invite_if_ready(call->core, call, NULL);
2202                                 break;
2203                         case LinphoneCallIdle:
2204                                 linphone_call_stop_media_streams_for_ice_gathering(call);
2205                                 linphone_core_notify_incoming_call(call->core, call);
2206                                 break;
2207                         default:
2208                                 break;
2209                 }
2210         } else if (evt == ORTP_EVENT_ICE_LOSING_PAIRS_COMPLETED) {
2211                 linphone_core_start_accept_call_update(call->core, call);
2212                 linphone_core_update_ice_state_in_call_stats(call);
2213         } else if (evt == ORTP_EVENT_ICE_RESTART_NEEDED) {
2214                 ice_session_restart(call->ice_session);
2215                 ice_session_set_role(call->ice_session, IR_Controlling);
2216                 linphone_core_update_call(call->core, call, &call->current_params);
2217         }
2218 }
2219
2220 void linphone_call_background_tasks(LinphoneCall *call, bool_t one_second_elapsed){
2221         LinphoneCore* lc = call->core;
2222         int disconnect_timeout = linphone_core_get_nortp_timeout(call->core);
2223         bool_t disconnected=FALSE;
2224
2225         if (call->state==LinphoneCallStreamsRunning && one_second_elapsed){
2226                 RtpSession *as=NULL,*vs=NULL;
2227                 float audio_load=0, video_load=0;
2228                 if (call->audiostream!=NULL){
2229                         as=call->audiostream->ms.session;
2230                         if (call->audiostream->ms.ticker)
2231                                 audio_load=ms_ticker_get_average_load(call->audiostream->ms.ticker);
2232                 }
2233                 if (call->videostream!=NULL){
2234                         if (call->videostream->ms.ticker)
2235                                 video_load=ms_ticker_get_average_load(call->videostream->ms.ticker);
2236                         vs=call->videostream->ms.session;
2237                 }
2238                 report_bandwidth(call,as,vs);
2239                 ms_message("Thread processing load: audio=%f\tvideo=%f",audio_load,video_load);
2240         }
2241
2242 #ifdef BUILD_UPNP
2243         linphone_upnp_call_process(call);
2244 #endif //BUILD_UPNP
2245
2246 #ifdef VIDEO_ENABLED
2247         if (call->videostream!=NULL) {
2248                 OrtpEvent *ev;
2249
2250                 /* Ensure there is no dangling ICE check list. */
2251                 if (call->ice_session == NULL) call->videostream->ms.ice_check_list = NULL;
2252
2253                 // Beware that the application queue should not depend on treatments fron the
2254                 // mediastreamer queue.
2255                 video_stream_iterate(call->videostream);
2256
2257                 while (call->videostream_app_evq && (NULL != (ev=ortp_ev_queue_get(call->videostream_app_evq)))){
2258                         OrtpEventType evt=ortp_event_get_type(ev);
2259                         OrtpEventData *evd=ortp_event_get_data(ev);
2260                         if (evt == ORTP_EVENT_ZRTP_ENCRYPTION_CHANGED){
2261                                 linphone_call_videostream_encryption_changed(call, evd->info.zrtp_stream_encrypted);
2262                         } else if (evt == ORTP_EVENT_RTCP_PACKET_RECEIVED) {
2263                                 call->stats[LINPHONE_CALL_STATS_VIDEO].round_trip_delay = rtp_session_get_round_trip_propagation(call->videostream->ms.session);
2264                                 if(call->stats[LINPHONE_CALL_STATS_VIDEO].received_rtcp != NULL)
2265                                         freemsg(call->stats[LINPHONE_CALL_STATS_VIDEO].received_rtcp);
2266                                 call->stats[LINPHONE_CALL_STATS_VIDEO].received_rtcp = evd->packet;
2267                                 evd->packet = NULL;
2268                                 if (lc->vtable.call_stats_updated)
2269                                         lc->vtable.call_stats_updated(lc, call, &call->stats[LINPHONE_CALL_STATS_VIDEO]);
2270                         } else if (evt == ORTP_EVENT_RTCP_PACKET_EMITTED) {
2271                                 memcpy(&call->stats[LINPHONE_CALL_STATS_VIDEO].jitter_stats, rtp_session_get_jitter_stats(call->videostream->ms.session), sizeof(jitter_stats_t));
2272                                 if(call->stats[LINPHONE_CALL_STATS_VIDEO].sent_rtcp != NULL)
2273                                         freemsg(call->stats[LINPHONE_CALL_STATS_VIDEO].sent_rtcp);
2274                                 call->stats[LINPHONE_CALL_STATS_VIDEO].sent_rtcp = evd->packet;
2275                                 evd->packet = NULL;
2276                                 if (lc->vtable.call_stats_updated)
2277                                         lc->vtable.call_stats_updated(lc, call, &call->stats[LINPHONE_CALL_STATS_VIDEO]);
2278                         } else if ((evt == ORTP_EVENT_ICE_SESSION_PROCESSING_FINISHED) || (evt == ORTP_EVENT_ICE_GATHERING_FINISHED)
2279                                 || (evt == ORTP_EVENT_ICE_LOSING_PAIRS_COMPLETED) || (evt == ORTP_EVENT_ICE_RESTART_NEEDED)) {
2280                                 handle_ice_events(call, ev);
2281                         }
2282                         ortp_event_destroy(ev);
2283                 }
2284         }
2285 #endif
2286         if (call->audiostream!=NULL) {
2287                 OrtpEvent *ev;
2288
2289                 /* Ensure there is no dangling ICE check list. */
2290                 if (call->ice_session == NULL) call->audiostream->ms.ice_check_list = NULL;
2291
2292                 // Beware that the application queue should not depend on treatments fron the
2293                 // mediastreamer queue.
2294                 audio_stream_iterate(call->audiostream);
2295
2296                 while (call->audiostream_app_evq && (NULL != (ev=ortp_ev_queue_get(call->audiostream_app_evq)))){
2297                         OrtpEventType evt=ortp_event_get_type(ev);
2298                         OrtpEventData *evd=ortp_event_get_data(ev);
2299                         if (evt == ORTP_EVENT_ZRTP_ENCRYPTION_CHANGED){
2300                                 linphone_call_audiostream_encryption_changed(call, evd->info.zrtp_stream_encrypted);
2301                         } else if (evt == ORTP_EVENT_ZRTP_SAS_READY) {
2302                                 linphone_call_audiostream_auth_token_ready(call, evd->info.zrtp_sas.sas, evd->info.zrtp_sas.verified);
2303                         } else if (evt == ORTP_EVENT_RTCP_PACKET_RECEIVED) {
2304                                 call->stats[LINPHONE_CALL_STATS_AUDIO].round_trip_delay = rtp_session_get_round_trip_propagation(call->audiostream->ms.session);
2305                                 if(call->stats[LINPHONE_CALL_STATS_AUDIO].received_rtcp != NULL)
2306                                         freemsg(call->stats[LINPHONE_CALL_STATS_AUDIO].received_rtcp);
2307                                 call->stats[LINPHONE_CALL_STATS_AUDIO].received_rtcp = evd->packet;
2308                                 evd->packet = NULL;
2309                                 if (lc->vtable.call_stats_updated)
2310                                         lc->vtable.call_stats_updated(lc, call, &call->stats[LINPHONE_CALL_STATS_AUDIO]);
2311                         } else if (evt == ORTP_EVENT_RTCP_PACKET_EMITTED) {
2312                                 memcpy(&call->stats[LINPHONE_CALL_STATS_AUDIO].jitter_stats, rtp_session_get_jitter_stats(call->audiostream->ms.session), sizeof(jitter_stats_t));
2313                                 if(call->stats[LINPHONE_CALL_STATS_AUDIO].sent_rtcp != NULL)
2314                                         freemsg(call->stats[LINPHONE_CALL_STATS_AUDIO].sent_rtcp);
2315                                 call->stats[LINPHONE_CALL_STATS_AUDIO].sent_rtcp = evd->packet;
2316                                 evd->packet = NULL;
2317                                 if (lc->vtable.call_stats_updated)
2318                                         lc->vtable.call_stats_updated(lc, call, &call->stats[LINPHONE_CALL_STATS_AUDIO]);
2319                         } else if ((evt == ORTP_EVENT_ICE_SESSION_PROCESSING_FINISHED) || (evt == ORTP_EVENT_ICE_GATHERING_FINISHED)
2320                                 || (evt == ORTP_EVENT_ICE_LOSING_PAIRS_COMPLETED) || (evt == ORTP_EVENT_ICE_RESTART_NEEDED)) {
2321                                 handle_ice_events(call, ev);
2322                         } else if (evt==ORTP_EVENT_TELEPHONE_EVENT){
2323                                 linphone_core_dtmf_received(lc,evd->info.telephone_event);
2324                         }
2325                         ortp_event_destroy(ev);
2326                 }
2327         }
2328         if (call->state==LinphoneCallStreamsRunning && one_second_elapsed && call->audiostream!=NULL && disconnect_timeout>0 )
2329                 disconnected=!audio_stream_alive(call->audiostream,disconnect_timeout);
2330         if (disconnected)
2331                 linphone_core_disconnected(call->core,call);
2332 }
2333
2334 void linphone_call_log_completed(LinphoneCall *call){
2335         LinphoneCore *lc=call->core;
2336
2337         call->log->duration=time(NULL)-call->start_time;
2338
2339         if (call->log->status==LinphoneCallMissed){
2340                 char *info;
2341                 lc->missed_calls++;
2342                 info=ortp_strdup_printf(ngettext("You have missed %i call.",
2343                                          "You have missed %i calls.", lc->missed_calls),
2344                                 lc->missed_calls);
2345         if (lc->vtable.display_status!=NULL)
2346             lc->vtable.display_status(lc,info);
2347                 ms_free(info);
2348         }
2349         lc->call_logs=ms_list_prepend(lc->call_logs,(void *)call->log);
2350         if (ms_list_size(lc->call_logs)>lc->max_call_logs){
2351                 MSList *elem,*prevelem=NULL;
2352                 /*find the last element*/
2353                 for(elem=lc->call_logs;elem!=NULL;elem=elem->next){
2354                         prevelem=elem;
2355                 }
2356                 elem=prevelem;
2357                 linphone_call_log_destroy((LinphoneCallLog*)elem->data);
2358                 lc->call_logs=ms_list_remove_link(lc->call_logs,elem);
2359         }
2360         if (lc->vtable.call_log_updated!=NULL){
2361                 lc->vtable.call_log_updated(lc,call->log);
2362         }
2363         call_logs_write_to_config_file(lc);
2364 }
2365
2366 LinphoneCallState linphone_call_get_transfer_state(LinphoneCall *call) {
2367         return call->transfer_state;
2368 }
2369
2370 void linphone_call_set_transfer_state(LinphoneCall* call, LinphoneCallState state) {
2371         if (state != call->transfer_state) {
2372                 LinphoneCore* lc = call->core;
2373                 call->transfer_state = state;
2374                 if (lc->vtable.transfer_state_changed)
2375                         lc->vtable.transfer_state_changed(lc, call, state);
2376         }
2377 }
2378
2379 /**
2380  * Returns true if the call is part of the conference.
2381  * @ingroup conferencing
2382 **/
2383 bool_t linphone_call_is_in_conference(const LinphoneCall *call) {
2384         return call->params.in_conference;
2385 }
2386
2387
2388 /**
2389  * Perform a zoom of the video displayed during a call.
2390  * @param call the call.
2391  * @param zoom_factor a floating point number describing the zoom factor. A value 1.0 corresponds to no zoom applied.
2392  * @param cx a floating point number pointing the horizontal center of the zoom to be applied. This value should be between 0.0 and 1.0.
2393  * @param cy a floating point number pointing the vertical center of the zoom to be applied. This value should be between 0.0 and 1.0.
2394  * 
2395  * cx and cy are updated in return in case their coordinates were to excentrated for the requested zoom factor. The zoom ensures that all the screen is fullfilled with the video.
2396 **/
2397 void linphone_call_zoom_video(LinphoneCall* call, float zoom_factor, float* cx, float* cy) {
2398         VideoStream* vstream = call->videostream;
2399         if (vstream && vstream->output) {
2400                 float zoom[3];
2401                 
2402                 if (zoom_factor < 1)
2403                         zoom_factor = 1;
2404                 float halfsize = 0.5 * 1.0 / zoom_factor;
2405
2406                 if ((*cx - halfsize) < 0)
2407                         *cx = 0 + halfsize;
2408                 if ((*cx + halfsize) > 1)
2409                         *cx = 1 - halfsize;
2410                 if ((*cy - halfsize) < 0)
2411                         *cy = 0 + halfsize;
2412                 if ((*cy + halfsize) > 1)
2413                         *cy = 1 - halfsize;
2414         
2415                 zoom[0] = zoom_factor;
2416                 zoom[1] = *cx;
2417                 zoom[2] = *cy;
2418                 ms_filter_call_method(vstream->output, MS_VIDEO_DISPLAY_ZOOM, &zoom);
2419         }else ms_warning("Could not apply zoom: video output wasn't activated.");
2420 }
2421