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