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