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