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