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