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