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