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