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