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