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