4 Copyright (C) 2010 Belledonne Communications SARL
5 (simon.morlat@linphone.org)
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.
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.
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.
24 #include "linphonecore.h"
28 #include <ortp/event.h>
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"
41 static MSWebCam *get_nowebcam_device(){
42 return ms_web_cam_manager_get_cam(ms_web_cam_manager_get(),"StaticImage: Static picture");
46 static bool_t generate_b64_crypto_key(int key_length, char* key_out) {
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");
55 b64_size = b64_encode((const char*)tmp, key_length, NULL, 0);
57 ms_error("Failed to b64 encode key");
61 key_out[b64_size] = '\0';
62 b64_encode((const char*)tmp, key_length, key_out, 40);
67 LinphoneCore *linphone_call_get_core(const LinphoneCall *call){
71 const char* linphone_call_get_authentication_token(LinphoneCall *call){
72 return call->auth_token;
75 bool_t linphone_call_get_authentication_token_verified(LinphoneCall *call){
76 return call->auth_token_verified;
79 static bool_t linphone_call_are_all_streams_encrypted(LinphoneCall *call) {
80 // Check ZRTP encryption in audiostream
81 if (!call->audiostream_encrypted) {
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) {
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);
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);
112 static void linphone_call_videostream_encryption_changed(void *data, bool_t encrypted){
113 ms_message("Video stream is %s", encrypted ? "encrypted" : "not encrypted");
115 LinphoneCall *call = (LinphoneCall *)data;
116 call->videostream_encrypted=encrypted;
117 propagate_encryption_changed(call);
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");
125 LinphoneCall *call = (LinphoneCall *)data;
126 call->audiostream_encrypted=encrypted;
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);
133 propagate_encryption_changed(call);
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,¶ms);
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);
154 call->auth_token=ms_strdup(auth_token);
155 call->auth_token_verified=verified;
157 ms_message("Authentication token is %s (%s)", auth_token, verified?"verified":"unverified");
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");
164 if (call->audiostream->ortpZrtpContext==NULL){
165 ms_error("linphone_call_set_authentication_token_verified(): No zrtp context.");
167 if (!call->auth_token_verified && verified){
168 ortp_zrtp_sas_verified(call->audiostream->ortpZrtpContext);
169 }else if (call->auth_token_verified && !verified){
170 ortp_zrtp_sas_reset_verified(call->audiostream->ortpZrtpContext);
172 call->auth_token_verified=verified;
173 propagate_encryption_changed(call);
176 static MSList *make_codec_list(LinphoneCore *lc, const MSList *codecs, int bandwidth_limit,int* max_sample_rate){
179 if (max_sample_rate) *max_sample_rate=0;
180 for(it=codecs;it!=NULL;it=it->next){
181 PayloadType *pt=(PayloadType*)it->data;
182 if (pt->flags & PAYLOAD_TYPE_ENABLED){
183 if (bandwidth_limit>0 && !linphone_core_is_payload_type_usable_for_bandwidth(lc,pt,bandwidth_limit)){
184 ms_message("Codec %s/%i eliminated because of audio bandwidth constraint.",pt->mime_type,pt->clock_rate);
187 if (linphone_core_check_payload_type_usability(lc,pt)){
188 l=ms_list_append(l,payload_type_clone(pt));
189 if (max_sample_rate && payload_type_get_rate(pt)>*max_sample_rate) *max_sample_rate=payload_type_get_rate(pt);
196 static void update_media_description_from_stun(SalMediaDescription *md, const StunCandidate *ac, const StunCandidate *vc){
198 strcpy(md->streams[0].rtp_addr,ac->addr);
199 md->streams[0].rtp_port=ac->port;
200 if ((ac->addr[0]!='\0' && vc->addr[0]!='\0' && strcmp(ac->addr,vc->addr)==0) || md->nstreams==1){
201 strcpy(md->addr,ac->addr);
205 strcpy(md->streams[1].rtp_addr,vc->addr);
206 md->streams[1].rtp_port=vc->port;
211 void linphone_call_make_local_media_description(LinphoneCore *lc, LinphoneCall *call){
214 SalMediaDescription *old_md=call->localdesc;
216 const char *me=linphone_core_get_identity(lc);
217 LinphoneAddress *addr=linphone_address_new(me);
218 const char *username=linphone_address_get_username (addr);
219 SalMediaDescription *md=sal_media_description_new();
220 bool_t keep_srtp_keys=lp_config_get_int(lc->config,"sip","keep_srtp_keys",0);
222 linphone_core_adapt_to_network(lc,call->ping_time,&call->params);
224 md->session_id=(old_md ? old_md->session_id : (rand() & 0xfff));
225 md->session_ver=(old_md ? (old_md->session_ver+1) : (rand() & 0xfff));
227 strncpy(md->addr,call->localip,sizeof(md->addr));
228 strncpy(md->username,username,sizeof(md->username));
230 if (call->params.down_bw)
231 md->bandwidth=call->params.down_bw;
232 else md->bandwidth=linphone_core_get_download_bandwidth(lc);
234 /*set audio capabilities */
235 strncpy(md->streams[0].rtp_addr,call->localip,sizeof(md->streams[0].rtp_addr));
236 strncpy(md->streams[0].rtcp_addr,call->localip,sizeof(md->streams[0].rtcp_addr));
237 md->streams[0].rtp_port=call->audio_port;
238 md->streams[0].rtcp_port=call->audio_port+1;
239 md->streams[0].proto=(call->params.media_encryption == LinphoneMediaEncryptionSRTP) ?
240 SalProtoRtpSavp : SalProtoRtpAvp;
241 md->streams[0].type=SalAudio;
242 if (call->params.down_ptime)
243 md->streams[0].ptime=call->params.down_ptime;
245 md->streams[0].ptime=linphone_core_get_download_ptime(lc);
246 l=make_codec_list(lc,lc->codecs_conf.audio_codecs,call->params.audio_bw,&md->streams[0].max_rate);
247 pt=payload_type_clone(rtp_profile_get_payload_from_mime(&av_profile,"telephone-event"));
248 l=ms_list_append(l,pt);
249 md->streams[0].payloads=l;
251 if (call->params.has_video){
253 md->streams[1].rtp_port=call->video_port;
254 md->streams[1].rtcp_port=call->video_port+1;
255 md->streams[1].proto=md->streams[0].proto;
256 md->streams[1].type=SalVideo;
257 l=make_codec_list(lc,lc->codecs_conf.video_codecs,0,NULL);
258 md->streams[1].payloads=l;
261 for(i=0; i<md->nstreams; i++) {
262 if (md->streams[i].proto == SalProtoRtpSavp) {
263 if (keep_srtp_keys && old_md && old_md->streams[i].proto==SalProtoRtpSavp){
265 for(j=0;j<SAL_CRYPTO_ALGO_MAX;++j){
266 memcpy(&md->streams[i].crypto[j],&old_md->streams[i].crypto[j],sizeof(SalSrtpCryptoAlgo));
269 md->streams[i].crypto[0].tag = 1;
270 md->streams[i].crypto[0].algo = AES_128_SHA1_80;
271 if (!generate_b64_crypto_key(30, md->streams[i].crypto[0].master_key))
272 md->streams[i].crypto[0].algo = 0;
273 md->streams[i].crypto[1].tag = 2;
274 md->streams[i].crypto[1].algo = AES_128_SHA1_32;
275 if (!generate_b64_crypto_key(30, md->streams[i].crypto[1].master_key))
276 md->streams[i].crypto[1].algo = 0;
277 md->streams[i].crypto[2].algo = 0;
281 update_media_description_from_stun(md,&call->ac,&call->vc);
282 if (call->ice_session != NULL) {
283 linphone_core_update_local_media_description_from_ice(md, call->ice_session);
284 linphone_core_update_ice_state_in_call_stats(call);
286 linphone_address_destroy(addr);
288 if (old_md) sal_media_description_unref(old_md);
291 static int find_port_offset(LinphoneCore *lc, SalStreamType type){
296 bool_t already_used=FALSE;
297 for(offset=0;offset<100;offset+=2){
301 tried_port=linphone_core_get_audio_port (lc)+offset;
304 tried_port=linphone_core_get_video_port (lc)+offset;
308 for(elem=lc->calls;elem!=NULL;elem=elem->next){
309 LinphoneCall *call=(LinphoneCall*)elem->data;
313 existing_port = call->audio_port;
316 existing_port = call->video_port;
319 if (existing_port==tried_port) {
324 if (!already_used) break;
327 ms_error("Could not find any free port !");
333 static int select_random_port(LinphoneCore *lc, SalStreamType type) {
337 int existing_port = 0;
338 int min_port = 0, max_port = 0;
339 bool_t already_used = FALSE;
344 linphone_core_get_audio_port_range(lc, &min_port, &max_port);
347 linphone_core_get_video_port_range(lc, &min_port, &max_port);
350 tried_port = (rand() % (max_port - min_port) + min_port) & ~0x1;
351 if (tried_port < min_port) tried_port = min_port + 2;
352 for (nb_tries = 0; nb_tries < 100; nb_tries++) {
353 for (elem = lc->calls; elem != NULL; elem = elem->next) {
354 LinphoneCall *call = (LinphoneCall *)elem->data;
358 existing_port = call->audio_port;
361 existing_port = call->video_port;
364 if (existing_port == tried_port) {
369 if (!already_used) break;
371 if (nb_tries == 100) {
372 ms_error("Could not find any free port!");
378 static void linphone_call_init_common(LinphoneCall *call, LinphoneAddress *from, LinphoneAddress *to){
380 int min_port, max_port;
381 call->magic=linphone_call_magic;
383 call->state=LinphoneCallIdle;
384 call->transfer_state = LinphoneCallIdle;
385 call->start_time=time(NULL);
386 call->media_start_time=0;
387 call->log=linphone_call_log_new(call, from, to);
388 call->owns_call_log=TRUE;
389 linphone_core_notify_all_friends(call->core,LinphoneStatusOnThePhone);
390 linphone_core_get_audio_port_range(call->core, &min_port, &max_port);
391 if (min_port == max_port) {
392 /* Used fixed RTP audio port. */
393 port_offset=find_port_offset (call->core, SalAudio);
394 if (port_offset==-1) return;
395 call->audio_port=linphone_core_get_audio_port(call->core)+port_offset;
397 /* Select random RTP audio port in the specified range. */
398 call->audio_port = select_random_port(call->core, SalAudio);
400 linphone_core_get_video_port_range(call->core, &min_port, &max_port);
401 if (min_port == max_port) {
402 /* Used fixed RTP video port. */
403 port_offset=find_port_offset (call->core, SalVideo);
404 if (port_offset==-1) return;
405 call->video_port=linphone_core_get_video_port(call->core)+port_offset;
407 /* Select random RTP video port in the specified range. */
408 call->video_port = select_random_port(call->core, SalVideo);
410 linphone_call_init_stats(&call->stats[LINPHONE_CALL_STATS_AUDIO], LINPHONE_CALL_STATS_AUDIO);
411 linphone_call_init_stats(&call->stats[LINPHONE_CALL_STATS_VIDEO], LINPHONE_CALL_STATS_VIDEO);
414 void linphone_call_init_stats(LinphoneCallStats *stats, int type) {
416 stats->received_rtcp = NULL;
417 stats->sent_rtcp = NULL;
418 stats->ice_state = LinphoneIceStateNotActivated;
422 static void discover_mtu(LinphoneCore *lc, const char *remote){
424 if (lc->net_conf.mtu==0 ){
425 /*attempt to discover mtu*/
426 mtu=ms_discover_mtu(remote);
429 ms_message("Discovered mtu is %i, RTP payload max size is %i",
430 mtu, ms_get_payload_max_size());
435 LinphoneCall * linphone_call_new_outgoing(struct _LinphoneCore *lc, LinphoneAddress *from, LinphoneAddress *to, const LinphoneCallParams *params)
437 LinphoneCall *call=ms_new0(LinphoneCall,1);
438 call->dir=LinphoneCallOutgoing;
439 call->op=sal_op_new(lc->sal);
440 sal_op_set_user_pointer(call->op,call);
442 linphone_core_get_local_ip(lc,linphone_address_get_domain(to),call->localip);
443 linphone_call_init_common(call,from,to);
444 call->params=*params;
445 if (linphone_core_get_firewall_policy(call->core) == LinphonePolicyUseIce) {
446 call->ice_session = ice_session_new();
447 ice_session_set_role(call->ice_session, IR_Controlling);
449 if (linphone_core_get_firewall_policy(call->core) == LinphonePolicyUseStun) {
450 call->ping_time=linphone_core_run_stun_tests(call->core,call);
452 call->camera_active=params->has_video;
454 discover_mtu(lc,linphone_address_get_domain (to));
455 if (params->referer){
456 sal_call_set_referer(call->op,params->referer->op);
457 call->referer=linphone_call_ref(params->referer);
462 LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *from, LinphoneAddress *to, SalOp *op){
463 LinphoneCall *call=ms_new0(LinphoneCall,1);
466 call->dir=LinphoneCallIncoming;
467 sal_op_set_user_pointer(op,call);
471 if (lc->sip_conf.ping_with_options){
472 /*the following sends an option request back to the caller so that
473 we get a chance to discover our nat'd address before answering.*/
474 call->ping_op=sal_op_new(lc->sal);
475 from_str=linphone_address_as_string_uri_only(from);
476 sal_op_set_route(call->ping_op,sal_op_get_network_origin(op));
477 sal_op_set_user_pointer(call->ping_op,call);
478 sal_ping(call->ping_op,linphone_core_find_best_identity(lc,from,NULL),from_str);
482 linphone_address_clean(from);
483 linphone_core_get_local_ip(lc,linphone_address_get_domain(from),call->localip);
484 linphone_call_init_common(call, from, to);
485 call->log->call_id=ms_strdup(sal_op_get_call_id(op)); /*must be known at that time*/
486 linphone_core_init_default_params(lc, &call->params);
487 call->params.has_video &= !!lc->video_policy.automatically_accept;
488 call->params.has_video &= linphone_core_media_description_contains_video_stream(sal_call_get_remote_media_description(op));
489 switch (linphone_core_get_firewall_policy(call->core)) {
490 case LinphonePolicyUseIce:
491 call->ice_session = ice_session_new();
492 ice_session_set_role(call->ice_session, IR_Controlled);
493 linphone_core_update_ice_from_remote_media_description(call, sal_call_get_remote_media_description(op));
494 if (call->ice_session != NULL) {
495 linphone_call_init_media_streams(call);
496 linphone_call_start_media_streams_for_ice_gathering(call);
497 if (linphone_core_gather_ice_candidates(call->core,call)<0) {
498 /* Ice candidates gathering failed, proceed with the call anyway. */
499 linphone_call_delete_ice_session(call);
500 linphone_call_stop_media_streams_for_ice_gathering(call);
504 case LinphonePolicyUseStun:
505 call->ping_time=linphone_core_run_stun_tests(call->core,call);
506 /* No break to also destroy ice session in this case. */
510 call->camera_active=call->params.has_video;
512 discover_mtu(lc,linphone_address_get_domain(from));
516 /* this function is called internally to get rid of a call.
517 It performs the following tasks:
518 - remove the call from the internal list of calls
519 - update the call logs accordingly
522 static void linphone_call_set_terminated(LinphoneCall *call){
523 LinphoneCore *lc=call->core;
525 linphone_core_update_allocated_audio_bandwidth(lc);
527 call->owns_call_log=FALSE;
528 linphone_call_log_completed(call);
531 if (call == lc->current_call){
532 ms_message("Resetting the current call");
533 lc->current_call=NULL;
536 if (linphone_core_del_call(lc,call) != 0){
537 ms_error("Could not remove the call from the list !!!");
540 if (ms_list_size(lc->calls)==0)
541 linphone_core_notify_all_friends(lc,lc->presence_mode);
543 linphone_core_conference_check_uninit(lc);
544 if (call->ringing_beep){
545 linphone_core_stop_dtmf(lc);
546 call->ringing_beep=FALSE;
549 linphone_call_unref(call->referer);
554 void linphone_call_fix_call_parameters(LinphoneCall *call){
555 call->params.has_video=call->current_params.has_video;
556 call->params.media_encryption=call->current_params.media_encryption;
559 const char *linphone_call_state_to_string(LinphoneCallState cs){
561 case LinphoneCallIdle:
562 return "LinphoneCallIdle";
563 case LinphoneCallIncomingReceived:
564 return "LinphoneCallIncomingReceived";
565 case LinphoneCallOutgoingInit:
566 return "LinphoneCallOutgoingInit";
567 case LinphoneCallOutgoingProgress:
568 return "LinphoneCallOutgoingProgress";
569 case LinphoneCallOutgoingRinging:
570 return "LinphoneCallOutgoingRinging";
571 case LinphoneCallOutgoingEarlyMedia:
572 return "LinphoneCallOutgoingEarlyMedia";
573 case LinphoneCallConnected:
574 return "LinphoneCallConnected";
575 case LinphoneCallStreamsRunning:
576 return "LinphoneCallStreamsRunning";
577 case LinphoneCallPausing:
578 return "LinphoneCallPausing";
579 case LinphoneCallPaused:
580 return "LinphoneCallPaused";
581 case LinphoneCallResuming:
582 return "LinphoneCallResuming";
583 case LinphoneCallRefered:
584 return "LinphoneCallRefered";
585 case LinphoneCallError:
586 return "LinphoneCallError";
587 case LinphoneCallEnd:
588 return "LinphoneCallEnd";
589 case LinphoneCallPausedByRemote:
590 return "LinphoneCallPausedByRemote";
591 case LinphoneCallUpdatedByRemote:
592 return "LinphoneCallUpdatedByRemote";
593 case LinphoneCallIncomingEarlyMedia:
594 return "LinphoneCallIncomingEarlyMedia";
595 case LinphoneCallUpdating:
596 return "LinphoneCallUpdating";
597 case LinphoneCallReleased:
598 return "LinphoneCallReleased";
600 return "undefined state";
603 void linphone_call_set_state(LinphoneCall *call, LinphoneCallState cstate, const char *message){
604 LinphoneCore *lc=call->core;
606 if (call->state!=cstate){
607 if (call->state==LinphoneCallEnd || call->state==LinphoneCallError){
608 if (cstate!=LinphoneCallReleased){
609 ms_warning("Spurious call state change from %s to %s, ignored.",linphone_call_state_to_string(call->state),
610 linphone_call_state_to_string(cstate));
614 ms_message("Call %p: moving from state %s to %s",call,linphone_call_state_to_string(call->state),
615 linphone_call_state_to_string(cstate));
616 if (cstate!=LinphoneCallRefered){
617 /*LinphoneCallRefered is rather an event, not a state.
618 Indeed it does not change the state of the call (still paused or running)*/
621 if (cstate==LinphoneCallEnd || cstate==LinphoneCallError){
622 switch(call->reason){
623 case LinphoneReasonDeclined:
624 call->log->status=LinphoneCallDeclined;
626 case LinphoneReasonNotAnswered:
627 call->log->status=LinphoneCallMissed;
632 linphone_call_set_terminated (call);
634 if (cstate == LinphoneCallConnected) {
635 call->log->status=LinphoneCallSuccess;
636 call->media_start_time=time(NULL);
639 if (lc->vtable.call_state_changed)
640 lc->vtable.call_state_changed(lc,call,cstate,message);
641 if (cstate==LinphoneCallReleased){
642 if (call->op!=NULL) {
643 /* so that we cannot have anymore upcalls for SAL
644 concerning this call*/
645 sal_op_release(call->op);
648 linphone_call_unref(call);
653 static void linphone_call_destroy(LinphoneCall *obj)
655 linphone_call_delete_ice_session(obj);
657 sal_op_release(obj->op);
660 if (obj->resultdesc!=NULL) {
661 sal_media_description_unref(obj->resultdesc);
662 obj->resultdesc=NULL;
664 if (obj->localdesc!=NULL) {
665 sal_media_description_unref(obj->localdesc);
669 sal_op_release(obj->ping_op);
672 ms_free(obj->refer_to);
674 if (obj->owns_call_log)
675 linphone_call_log_destroy(obj->log);
676 if (obj->auth_token) {
677 ms_free(obj->auth_token);
684 * @addtogroup call_control
689 * Increments the call 's reference count.
690 * An application that wishes to retain a pointer to call object
691 * must use this function to unsure the pointer remains
692 * valid. Once the application no more needs this pointer,
693 * it must call linphone_call_unref().
695 LinphoneCall * linphone_call_ref(LinphoneCall *obj){
701 * Decrements the call object reference count.
702 * See linphone_call_ref().
704 void linphone_call_unref(LinphoneCall *obj){
707 linphone_call_destroy(obj);
712 * Returns current parameters associated to the call.
714 const LinphoneCallParams * linphone_call_get_current_params(const LinphoneCall *call){
715 return &call->current_params;
718 static bool_t is_video_active(const SalStreamDescription *sd){
719 return sd->rtp_port!=0 && sd->dir!=SalStreamInactive;
723 * Returns call parameters proposed by remote.
725 * This is useful when receiving an incoming call, to know whether the remote party
726 * supports video, encryption or whatever.
728 const LinphoneCallParams * linphone_call_get_remote_params(LinphoneCall *call){
729 LinphoneCallParams *cp=&call->remote_params;
730 memset(cp,0,sizeof(*cp));
732 SalMediaDescription *md=sal_call_get_remote_media_description(call->op);
734 SalStreamDescription *asd,*vsd,*secure_asd,*secure_vsd;
736 asd=sal_media_description_find_stream(md,SalProtoRtpAvp,SalAudio);
737 vsd=sal_media_description_find_stream(md,SalProtoRtpAvp,SalVideo);
738 secure_asd=sal_media_description_find_stream(md,SalProtoRtpSavp,SalAudio);
739 secure_vsd=sal_media_description_find_stream(md,SalProtoRtpSavp,SalVideo);
741 cp->has_video=is_video_active(secure_vsd);
742 if (secure_asd || asd==NULL)
743 cp->media_encryption=LinphoneMediaEncryptionSRTP;
745 cp->has_video=is_video_active(vsd);
748 if (md->bandwidth>0 && md->bandwidth<=linphone_core_get_edge_bw(call->core)){
749 cp->low_bandwidth=TRUE;
759 * Returns the remote address associated to this call
762 const LinphoneAddress * linphone_call_get_remote_address(const LinphoneCall *call){
763 return call->dir==LinphoneCallIncoming ? call->log->from : call->log->to;
767 * Returns the remote address associated to this call as a string.
769 * The result string must be freed by user using ms_free().
771 char *linphone_call_get_remote_address_as_string(const LinphoneCall *call){
772 return linphone_address_as_string(linphone_call_get_remote_address(call));
776 * Retrieves the call's current state.
778 LinphoneCallState linphone_call_get_state(const LinphoneCall *call){
783 * Returns the reason for a call termination (either error or normal termination)
785 LinphoneReason linphone_call_get_reason(const LinphoneCall *call){
790 * Get the user_pointer in the LinphoneCall
792 * @ingroup call_control
794 * return user_pointer an opaque user pointer that can be retrieved at any time
796 void *linphone_call_get_user_pointer(LinphoneCall *call)
798 return call->user_pointer;
802 * Set the user_pointer in the LinphoneCall
804 * @ingroup call_control
806 * the user_pointer is an opaque user pointer that can be retrieved at any time in the LinphoneCall
808 void linphone_call_set_user_pointer(LinphoneCall *call, void *user_pointer)
810 call->user_pointer = user_pointer;
814 * Returns the call log associated to this call.
816 LinphoneCallLog *linphone_call_get_call_log(const LinphoneCall *call){
821 * Returns the refer-to uri (if the call was transfered).
823 const char *linphone_call_get_refer_to(const LinphoneCall *call){
824 return call->refer_to;
828 * Returns direction of the call (incoming or outgoing).
830 LinphoneCallDir linphone_call_get_dir(const LinphoneCall *call){
831 return call->log->dir;
835 * Returns the far end's user agent description string, if available.
837 const char *linphone_call_get_remote_user_agent(LinphoneCall *call){
839 return sal_op_get_remote_ua (call->op);
845 * Returns true if this calls has received a transfer that has not been
847 * Pending transfers are executed when this call is being paused or closed,
848 * locally or by remote endpoint.
849 * If the call is already paused while receiving the transfer request, the
850 * transfer immediately occurs.
852 bool_t linphone_call_has_transfer_pending(const LinphoneCall *call){
853 return call->refer_pending;
857 * Returns call's duration in seconds.
859 int linphone_call_get_duration(const LinphoneCall *call){
860 if (call->media_start_time==0) return 0;
861 return time(NULL)-call->media_start_time;
865 * Returns the call object this call is replacing, if any.
866 * Call replacement can occur during call transfers.
867 * By default, the core automatically terminates the replaced call and accept the new one.
868 * This function allows the application to know whether a new incoming call is a one that replaces another one.
870 LinphoneCall *linphone_call_get_replaced_call(LinphoneCall *call){
871 SalOp *op=sal_call_get_replaces(call->op);
873 return (LinphoneCall*)sal_op_get_user_pointer(op);
879 * Indicate whether camera input should be sent to remote end.
881 void linphone_call_enable_camera (LinphoneCall *call, bool_t enable){
883 if (call->videostream!=NULL && call->videostream->ticker!=NULL){
884 LinphoneCore *lc=call->core;
885 MSWebCam *nowebcam=get_nowebcam_device();
886 if (call->camera_active!=enable && lc->video_conf.device!=nowebcam){
887 video_stream_change_camera(call->videostream,
888 enable ? lc->video_conf.device : nowebcam);
891 call->camera_active=enable;
896 * Take a photo of currently received video and write it into a jpeg file.
898 int linphone_call_take_video_snapshot(LinphoneCall *call, const char *file){
900 if (call->videostream!=NULL && call->videostream->jpegwriter!=NULL){
901 return ms_filter_call_method(call->videostream->jpegwriter,MS_JPEG_WRITER_TAKE_SNAPSHOT,(void*)file);
903 ms_warning("Cannot take snapshot: no currently running video stream on this call.");
910 * Returns TRUE if camera pictures are sent to the remote party.
912 bool_t linphone_call_camera_enabled (const LinphoneCall *call){
913 return call->camera_active;
917 * Enable video stream.
919 void linphone_call_params_enable_video(LinphoneCallParams *cp, bool_t enabled){
920 cp->has_video=enabled;
923 const PayloadType* linphone_call_params_get_used_audio_codec(const LinphoneCallParams *cp) {
924 return cp->audio_codec;
927 const PayloadType* linphone_call_params_get_used_video_codec(const LinphoneCallParams *cp) {
928 return cp->video_codec;
932 * @ingroup call_control
933 * Use to know if this call has been configured in low bandwidth mode.
934 * This mode can be automatically discovered thanks to a stun server when activate_edge_workarounds=1 in section [net] of configuration file.
935 * An application that would have reliable way to know network capacity may not use activate_edge_workarounds=1 but instead manually configure
936 * low bandwidth mode with linphone_call_params_enable_low_bandwidth().
937 * <br> When enabled, this param may transform a call request with video in audio only mode.
938 * @return TRUE if low bandwidth has been configured/detected
940 bool_t linphone_call_params_low_bandwidth_enabled(const LinphoneCallParams *cp) {
941 return cp->low_bandwidth;
945 * @ingroup call_control
946 * Indicate low bandwith mode.
947 * Configuring a call to low bandwidth mode will result in the core to activate several settings for the call in order to ensure that bitrate usage
948 * is lowered to the minimum possible. Typically, ptime (packetization time) will be increased, audio codec's output bitrate will be targetted to 20kbit/s provided
949 * that it is achievable by the codec selected after SDP handshake. Video is automatically disabled.
952 void linphone_call_params_enable_low_bandwidth(LinphoneCallParams *cp, bool_t enabled){
953 cp->low_bandwidth=enabled;
957 * Returns whether video is enabled.
959 bool_t linphone_call_params_video_enabled(const LinphoneCallParams *cp){
960 return cp->has_video;
963 enum LinphoneMediaEncryption linphone_call_params_get_media_encryption(const LinphoneCallParams *cp) {
964 return cp->media_encryption;
967 void linphone_call_params_set_media_encryption(LinphoneCallParams *cp, enum LinphoneMediaEncryption e) {
968 cp->media_encryption = e;
973 * Enable sending of real early media (during outgoing calls).
975 void linphone_call_params_enable_early_media_sending(LinphoneCallParams *cp, bool_t enabled){
976 cp->real_early_media=enabled;
979 bool_t linphone_call_params_early_media_sending_enabled(const LinphoneCallParams *cp){
980 return cp->real_early_media;
984 * Returns true if the call is part of the locally managed conference.
986 bool_t linphone_call_params_local_conference_mode(const LinphoneCallParams *cp){
987 return cp->in_conference;
991 * Refine bandwidth settings for this call by setting a bandwidth limit for audio streams.
992 * As a consequence, codecs whose bitrates are not compatible with this limit won't be used.
994 void linphone_call_params_set_audio_bandwidth_limit(LinphoneCallParams *cp, int bandwidth){
995 cp->audio_bw=bandwidth;
1000 * Request remote side to send us a Video Fast Update.
1002 void linphone_call_send_vfu_request(LinphoneCall *call)
1004 if (LinphoneCallStreamsRunning == linphone_call_get_state(call))
1005 sal_call_send_vfu_request(call->op);
1012 LinphoneCallParams * linphone_call_params_copy(const LinphoneCallParams *cp){
1013 LinphoneCallParams *ncp=ms_new0(LinphoneCallParams,1);
1014 memcpy(ncp,cp,sizeof(LinphoneCallParams));
1021 void linphone_call_params_destroy(LinphoneCallParams *p){
1030 #ifdef TEST_EXT_RENDERER
1031 static void rendercb(void *data, const MSPicture *local, const MSPicture *remote){
1032 ms_message("rendercb, local buffer=%p, remote buffer=%p",
1033 local ? local->planes[0] : NULL, remote? remote->planes[0] : NULL);
1037 #ifdef VIDEO_ENABLED
1038 static void video_stream_event_cb(void *user_pointer, const MSFilter *f, const unsigned int event_id, const void *args){
1039 LinphoneCall* call = (LinphoneCall*) user_pointer;
1040 ms_warning("In linphonecall.c: video_stream_event_cb");
1042 case MS_VIDEO_DECODER_DECODING_ERRORS:
1043 ms_warning("Case is MS_VIDEO_DECODER_DECODING_ERRORS");
1044 linphone_call_send_vfu_request(call);
1046 case MS_VIDEO_DECODER_FIRST_IMAGE_DECODED:
1047 ms_message("First video frame decoded successfully");
1048 if (call->nextVideoFrameDecoded._func != NULL)
1049 call->nextVideoFrameDecoded._func(call, call->nextVideoFrameDecoded._user_data);
1052 ms_warning("Unhandled event %i", event_id);
1058 void linphone_call_set_next_video_frame_decoded_callback(LinphoneCall *call, LinphoneCallCbFunc cb, void* user_data) {
1059 call->nextVideoFrameDecoded._func = cb;
1060 call->nextVideoFrameDecoded._user_data = user_data;
1061 #ifdef VIDEO_ENABLED
1062 ms_filter_call_method_noarg(call->videostream->decoder, MS_VIDEO_DECODER_RESET_FIRST_IMAGE_NOTIFICATION);
1066 void linphone_call_init_audio_stream(LinphoneCall *call){
1067 LinphoneCore *lc=call->core;
1068 AudioStream *audiostream;
1071 if (call->audiostream != NULL) return;
1072 call->audiostream=audiostream=audio_stream_new(call->audio_port,call->audio_port+1,linphone_core_ipv6_enabled(lc));
1073 dscp=linphone_core_get_audio_dscp(lc);
1075 audio_stream_set_dscp(audiostream,dscp);
1076 if (linphone_core_echo_limiter_enabled(lc)){
1077 const char *type=lp_config_get_string(lc->config,"sound","el_type","mic");
1078 if (strcasecmp(type,"mic")==0)
1079 audio_stream_enable_echo_limiter(audiostream,ELControlMic);
1080 else if (strcasecmp(type,"full")==0)
1081 audio_stream_enable_echo_limiter(audiostream,ELControlFull);
1083 audio_stream_enable_gain_control(audiostream,TRUE);
1084 if (linphone_core_echo_cancellation_enabled(lc)){
1085 int len,delay,framesize;
1086 const char *statestr=lp_config_get_string(lc->config,"sound","ec_state",NULL);
1087 len=lp_config_get_int(lc->config,"sound","ec_tail_len",0);
1088 delay=lp_config_get_int(lc->config,"sound","ec_delay",0);
1089 framesize=lp_config_get_int(lc->config,"sound","ec_framesize",0);
1090 audio_stream_set_echo_canceller_params(audiostream,len,delay,framesize);
1091 if (statestr && audiostream->ec){
1092 ms_filter_call_method(audiostream->ec,MS_ECHO_CANCELLER_SET_STATE_STRING,(void*)statestr);
1095 audio_stream_enable_automatic_gain_control(audiostream,linphone_core_agc_enabled(lc));
1097 int enabled=lp_config_get_int(lc->config,"sound","noisegate",0);
1098 audio_stream_enable_noise_gate(audiostream,enabled);
1101 audio_stream_set_features(audiostream,linphone_core_get_audio_features(lc));
1104 RtpTransport *artp=lc->rtptf->audio_rtp_func(lc->rtptf->audio_rtp_func_data, call->audio_port);
1105 RtpTransport *artcp=lc->rtptf->audio_rtcp_func(lc->rtptf->audio_rtcp_func_data, call->audio_port+1);
1106 rtp_session_set_transports(audiostream->session,artp,artcp);
1108 if ((linphone_core_get_firewall_policy(lc) == LinphonePolicyUseIce) && (call->ice_session != NULL)){
1109 rtp_session_set_pktinfo(audiostream->session, TRUE);
1110 rtp_session_set_symmetric_rtp(audiostream->session, FALSE);
1111 if (ice_session_check_list(call->ice_session, 0) == NULL) {
1112 ice_session_add_check_list(call->ice_session, ice_check_list_new());
1114 audiostream->ice_check_list = ice_session_check_list(call->ice_session, 0);
1115 ice_check_list_set_rtp_session(audiostream->ice_check_list, audiostream->session);
1118 call->audiostream_app_evq = ortp_ev_queue_new();
1119 rtp_session_register_event_queue(audiostream->session,call->audiostream_app_evq);
1122 void linphone_call_init_video_stream(LinphoneCall *call){
1123 #ifdef VIDEO_ENABLED
1124 LinphoneCore *lc=call->core;
1126 if (!call->params.has_video) {
1127 linphone_call_stop_video_stream(call);
1130 if (call->videostream != NULL) return;
1131 if ((lc->video_conf.display || lc->video_conf.capture) && call->params.has_video){
1132 int video_recv_buf_size=lp_config_get_int(lc->config,"video","recv_buf_size",0);
1133 int dscp=linphone_core_get_video_dscp(lc);
1135 call->videostream=video_stream_new(call->video_port,call->video_port+1,linphone_core_ipv6_enabled(lc));
1137 video_stream_set_dscp(call->videostream,dscp);
1138 video_stream_enable_display_filter_auto_rotate(call->videostream, lp_config_get_int(lc->config,"video","display_filter_auto_rotate",0));
1139 if (video_recv_buf_size>0) rtp_session_set_recv_buf_size(call->videostream->session,video_recv_buf_size);
1141 if( lc->video_conf.displaytype != NULL)
1142 video_stream_set_display_filter_name(call->videostream,lc->video_conf.displaytype);
1143 video_stream_set_event_callback(call->videostream,video_stream_event_cb, call);
1145 RtpTransport *vrtp=lc->rtptf->video_rtp_func(lc->rtptf->video_rtp_func_data, call->video_port);
1146 RtpTransport *vrtcp=lc->rtptf->video_rtcp_func(lc->rtptf->video_rtcp_func_data, call->video_port+1);
1147 rtp_session_set_transports(call->videostream->session,vrtp,vrtcp);
1149 if ((linphone_core_get_firewall_policy(lc) == LinphonePolicyUseIce) && (call->ice_session != NULL)){
1150 rtp_session_set_pktinfo(call->videostream->session, TRUE);
1151 rtp_session_set_symmetric_rtp(call->videostream->session, FALSE);
1152 if (ice_session_check_list(call->ice_session, 1) == NULL) {
1153 ice_session_add_check_list(call->ice_session, ice_check_list_new());
1155 call->videostream->ice_check_list = ice_session_check_list(call->ice_session, 1);
1156 ice_check_list_set_rtp_session(call->videostream->ice_check_list, call->videostream->session);
1158 call->videostream_app_evq = ortp_ev_queue_new();
1159 rtp_session_register_event_queue(call->videostream->session,call->videostream_app_evq);
1160 #ifdef TEST_EXT_RENDERER
1161 video_stream_set_render_callback(call->videostream,rendercb,NULL);
1165 call->videostream=NULL;
1169 void linphone_call_init_media_streams(LinphoneCall *call){
1170 linphone_call_init_audio_stream(call);
1171 linphone_call_init_video_stream(call);
1175 static int dtmf_tab[16]={'0','1','2','3','4','5','6','7','8','9','*','#','A','B','C','D'};
1177 static void linphone_core_dtmf_received(LinphoneCore *lc, int dtmf){
1178 if (dtmf<0 || dtmf>15){
1179 ms_warning("Bad dtmf value %i",dtmf);
1182 if (lc->vtable.dtmf_received != NULL)
1183 lc->vtable.dtmf_received(lc, linphone_core_get_current_call(lc), dtmf_tab[dtmf]);
1186 static void parametrize_equalizer(LinphoneCore *lc, AudioStream *st){
1188 MSFilter *f=st->equalizer;
1189 int enabled=lp_config_get_int(lc->config,"sound","eq_active",0);
1190 const char *gains=lp_config_get_string(lc->config,"sound","eq_gains",NULL);
1191 ms_filter_call_method(f,MS_EQUALIZER_SET_ACTIVE,&enabled);
1197 if (sscanf(gains,"%f:%f:%f %n",&g.frequency,&g.gain,&g.width,&bytes)==3){
1198 ms_message("Read equalizer gains: %f(~%f) --> %f",g.frequency,g.width,g.gain);
1199 ms_filter_call_method(f,MS_EQUALIZER_SET_GAIN,&g);
1208 void _post_configure_audio_stream(AudioStream *st, LinphoneCore *lc, bool_t muted){
1209 float mic_gain=lc->sound_conf.soft_mic_lev;
1212 float ng_thres=lp_config_get_float(lc->config,"sound","ng_thres",0.05);
1213 float ng_floorgain=lp_config_get_float(lc->config,"sound","ng_floorgain",0);
1214 int dc_removal=lp_config_get_int(lc->config,"sound","dc_removal",0);
1217 linphone_core_set_mic_gain_db (lc, mic_gain);
1219 audio_stream_set_mic_gain(st,0);
1221 recv_gain = lc->sound_conf.soft_play_lev;
1222 if (recv_gain != 0) {
1223 linphone_core_set_playback_gain_db (lc,recv_gain);
1227 ms_filter_call_method(st->volsend,MS_VOLUME_REMOVE_DC,&dc_removal);
1228 float speed=lp_config_get_float(lc->config,"sound","el_speed",-1);
1229 thres=lp_config_get_float(lc->config,"sound","el_thres",-1);
1230 float force=lp_config_get_float(lc->config,"sound","el_force",-1);
1231 int sustain=lp_config_get_int(lc->config,"sound","el_sustain",-1);
1232 float transmit_thres=lp_config_get_float(lc->config,"sound","el_transmit_thres",-1);
1235 if (speed==-1) speed=0.03;
1236 if (force==-1) force=25;
1237 ms_filter_call_method(f,MS_VOLUME_SET_EA_SPEED,&speed);
1238 ms_filter_call_method(f,MS_VOLUME_SET_EA_FORCE,&force);
1240 ms_filter_call_method(f,MS_VOLUME_SET_EA_THRESHOLD,&thres);
1242 ms_filter_call_method(f,MS_VOLUME_SET_EA_SUSTAIN,&sustain);
1243 if (transmit_thres!=-1)
1244 ms_filter_call_method(f,MS_VOLUME_SET_EA_TRANSMIT_THRESHOLD,&transmit_thres);
1246 ms_filter_call_method(st->volsend,MS_VOLUME_SET_NOISE_GATE_THRESHOLD,&ng_thres);
1247 ms_filter_call_method(st->volsend,MS_VOLUME_SET_NOISE_GATE_FLOORGAIN,&ng_floorgain);
1250 /* parameters for a limited noise-gate effect, using echo limiter threshold */
1251 float floorgain = 1/pow(10,(mic_gain)/10);
1252 int spk_agc=lp_config_get_int(lc->config,"sound","speaker_agc_enabled",0);
1253 ms_filter_call_method(st->volrecv, MS_VOLUME_ENABLE_AGC, &spk_agc);
1254 ms_filter_call_method(st->volrecv,MS_VOLUME_SET_NOISE_GATE_THRESHOLD,&ng_thres);
1255 ms_filter_call_method(st->volrecv,MS_VOLUME_SET_NOISE_GATE_FLOORGAIN,&floorgain);
1257 parametrize_equalizer(lc,st);
1260 static void post_configure_audio_streams(LinphoneCall*call){
1261 AudioStream *st=call->audiostream;
1262 LinphoneCore *lc=call->core;
1263 _post_configure_audio_stream(st,lc,call->audio_muted);
1264 if (lc->vtable.dtmf_received!=NULL){
1265 /* replace by our default action*/
1266 audio_stream_play_received_dtmfs(call->audiostream,FALSE);
1267 /*rtp_session_signal_connect(call->audiostream->session,"telephone-event",(RtpCallback)linphone_core_dtmf_received,(unsigned long)lc);*/
1271 static RtpProfile *make_profile(LinphoneCall *call, const SalMediaDescription *md, const SalStreamDescription *desc, int *used_pt){
1274 RtpProfile *prof=rtp_profile_new("Call profile");
1277 LinphoneCore *lc=call->core;
1279 const LinphoneCallParams *params=&call->params;
1282 for(elem=desc->payloads;elem!=NULL;elem=elem->next){
1283 PayloadType *pt=(PayloadType*)elem->data;
1286 if ((pt->flags & PAYLOAD_TYPE_FLAG_CAN_SEND) && first) {
1287 if (desc->type==SalAudio){
1288 linphone_core_update_allocated_audio_bandwidth_in_call(call,pt);
1289 if (params->up_ptime)
1290 up_ptime=params->up_ptime;
1291 else up_ptime=linphone_core_get_upload_ptime(lc);
1293 *used_pt=payload_type_get_number(pt);
1296 if (desc->bandwidth>0) remote_bw=desc->bandwidth;
1297 else if (md->bandwidth>0) {
1298 /*case where b=AS is given globally, not per stream*/
1299 remote_bw=md->bandwidth;
1300 if (desc->type==SalVideo){
1301 remote_bw=get_video_bandwidth(remote_bw,call->audio_bw);
1305 if (desc->type==SalAudio){
1306 int audio_bw=call->audio_bw;
1308 if (params->up_bw< audio_bw)
1309 audio_bw=params->up_bw;
1311 bw=get_min_bandwidth(audio_bw,remote_bw);
1312 }else bw=get_min_bandwidth(get_video_bandwidth(linphone_core_get_upload_bandwidth (lc),call->audio_bw),remote_bw);
1313 if (bw>0) pt->normal_bitrate=bw*1000;
1314 else if (desc->type==SalAudio){
1315 pt->normal_bitrate=-1;
1318 up_ptime=desc->ptime;
1322 snprintf(tmp,sizeof(tmp),"ptime=%i",up_ptime);
1323 payload_type_append_send_fmtp(pt,tmp);
1325 number=payload_type_get_number(pt);
1326 if (rtp_profile_get_payload(prof,number)!=NULL){
1327 ms_warning("A payload type with number %i already exists in profile !",number);
1329 rtp_profile_set_payload(prof,number,pt);
1335 static void setup_ring_player(LinphoneCore *lc, LinphoneCall *call){
1336 int pause_time=3000;
1337 audio_stream_play(call->audiostream,lc->sound_conf.ringback_tone);
1338 ms_filter_call_method(call->audiostream->soundread,MS_FILE_PLAYER_LOOP,&pause_time);
1341 static bool_t linphone_call_sound_resources_available(LinphoneCall *call){
1342 LinphoneCore *lc=call->core;
1343 LinphoneCall *current=linphone_core_get_current_call(lc);
1344 return !linphone_core_is_in_conference(lc) &&
1345 (current==NULL || current==call);
1347 static int find_crypto_index_from_tag(const SalSrtpCryptoAlgo crypto[],unsigned char tag) {
1349 for(i=0; i<SAL_CRYPTO_ALGO_MAX; i++) {
1350 if (crypto[i].tag == tag) {
1356 static void linphone_call_start_audio_stream(LinphoneCall *call, const char *cname, bool_t muted, bool_t send_ringbacktone, bool_t use_arc){
1357 LinphoneCore *lc=call->core;
1359 char rtcp_tool[128]={0};
1360 snprintf(rtcp_tool,sizeof(rtcp_tool)-1,"%s-%s",linphone_core_get_user_agent_name(),linphone_core_get_user_agent_version());
1361 /* look for savp stream first */
1362 const SalStreamDescription *stream=sal_media_description_find_stream(call->resultdesc,
1363 SalProtoRtpSavp,SalAudio);
1364 /* no savp audio stream, use avp */
1366 stream=sal_media_description_find_stream(call->resultdesc,
1367 SalProtoRtpAvp,SalAudio);
1369 if (stream && stream->dir!=SalStreamInactive && stream->rtp_port!=0){
1370 MSSndCard *playcard=lc->sound_conf.lsd_card ?
1371 lc->sound_conf.lsd_card : lc->sound_conf.play_sndcard;
1372 MSSndCard *captcard=lc->sound_conf.capt_sndcard;
1373 const char *playfile=lc->play_file;
1374 const char *recfile=lc->rec_file;
1375 call->audio_profile=make_profile(call,call->resultdesc,stream,&used_pt);
1379 call->current_params.audio_codec = rtp_profile_get_payload(call->audio_profile, used_pt);
1380 if (playcard==NULL) {
1381 ms_warning("No card defined for playback !");
1383 if (captcard==NULL) {
1384 ms_warning("No card defined for capture !");
1386 /*Replace soundcard filters by inactive file players or recorders
1387 when placed in recvonly or sendonly mode*/
1388 if (stream->rtp_port==0 || stream->dir==SalStreamRecvOnly){
1391 }else if (stream->dir==SalStreamSendOnly){
1395 /*And we will eventually play "playfile" if set by the user*/
1398 if (send_ringbacktone){
1400 playfile=NULL;/* it is setup later*/
1402 /*if playfile are supplied don't use soundcards*/
1403 if (lc->use_files) {
1407 if (call->params.in_conference){
1408 /* first create the graph without soundcard resources*/
1409 captcard=playcard=NULL;
1411 if (!linphone_call_sound_resources_available(call)){
1412 ms_message("Sound resources are used by another call, not using soundcard.");
1413 captcard=playcard=NULL;
1415 use_ec=captcard==NULL ? FALSE : linphone_core_echo_cancellation_enabled(lc);
1416 if (playcard && stream->max_rate>0) ms_snd_card_set_preferred_sample_rate(playcard, stream->max_rate);
1417 if (captcard && stream->max_rate>0) ms_snd_card_set_preferred_sample_rate(captcard, stream->max_rate);
1418 audio_stream_enable_adaptive_bitrate_control(call->audiostream,use_arc);
1419 audio_stream_enable_adaptive_jittcomp(call->audiostream, linphone_core_audio_adaptive_jittcomp_enabled(lc));
1420 audio_stream_start_full(
1422 call->audio_profile,
1423 stream->rtp_addr[0]!='\0' ? stream->rtp_addr : call->resultdesc->addr,
1425 stream->rtcp_addr[0]!='\0' ? stream->rtcp_addr : call->resultdesc->addr,
1426 linphone_core_rtcp_enabled(lc) ? (stream->rtcp_port) : 0,
1428 linphone_core_get_audio_jittcomp(lc),
1435 post_configure_audio_streams(call);
1436 if (muted && !send_ringbacktone){
1437 audio_stream_set_mic_gain(call->audiostream,0);
1439 if (stream->dir==SalStreamSendOnly && playfile!=NULL){
1441 ms_filter_call_method(call->audiostream->soundread,MS_FILE_PLAYER_LOOP,&pause_time);
1443 if (send_ringbacktone){
1444 setup_ring_player(lc,call);
1446 audio_stream_set_rtcp_information(call->audiostream, cname, rtcp_tool);
1448 /* valid local tags are > 0 */
1449 if (stream->proto == SalProtoRtpSavp) {
1450 const SalStreamDescription *local_st_desc=sal_media_description_find_stream(call->localdesc,
1451 SalProtoRtpSavp,SalAudio);
1452 int crypto_idx = find_crypto_index_from_tag(local_st_desc->crypto, stream->crypto_local_tag);
1454 if (crypto_idx >= 0) {
1455 audio_stream_enable_strp(
1457 stream->crypto[0].algo,
1458 local_st_desc->crypto[crypto_idx].master_key,
1459 stream->crypto[0].master_key);
1460 call->audiostream_encrypted=TRUE;
1462 ms_warning("Failed to find local crypto algo with tag: %d", stream->crypto_local_tag);
1463 call->audiostream_encrypted=FALSE;
1465 }else call->audiostream_encrypted=FALSE;
1466 if (call->params.in_conference){
1467 /*transform the graph to connect it to the conference filter */
1468 bool_t mute=stream->dir==SalStreamRecvOnly;
1469 linphone_call_add_to_conf(call, mute);
1471 call->current_params.in_conference=call->params.in_conference;
1472 call->current_params.low_bandwidth=call->params.low_bandwidth;
1473 }else ms_warning("No audio stream accepted ?");
1477 static void linphone_call_start_video_stream(LinphoneCall *call, const char *cname,bool_t all_inputs_muted){
1478 #ifdef VIDEO_ENABLED
1479 LinphoneCore *lc=call->core;
1481 /* look for savp stream first */
1482 const SalStreamDescription *vstream=sal_media_description_find_stream(call->resultdesc,
1483 SalProtoRtpSavp,SalVideo);
1484 char rtcp_tool[128]={0};
1485 snprintf(rtcp_tool,sizeof(rtcp_tool)-1,"%s-%s",linphone_core_get_user_agent_name(),linphone_core_get_user_agent_version());
1487 /* no savp audio stream, use avp */
1489 vstream=sal_media_description_find_stream(call->resultdesc,
1490 SalProtoRtpAvp,SalVideo);
1492 /* shutdown preview */
1493 if (lc->previewstream!=NULL) {
1494 video_preview_stop(lc->previewstream);
1495 lc->previewstream=NULL;
1498 if (vstream!=NULL && vstream->dir!=SalStreamInactive && vstream->rtp_port!=0) {
1499 const char *rtp_addr=vstream->rtp_addr[0]!='\0' ? vstream->rtp_addr : call->resultdesc->addr;
1500 const char *rtcp_addr=vstream->rtcp_addr[0]!='\0' ? vstream->rtcp_addr : call->resultdesc->addr;
1501 call->video_profile=make_profile(call,call->resultdesc,vstream,&used_pt);
1503 call->current_params.video_codec = rtp_profile_get_payload(call->video_profile, used_pt);
1504 VideoStreamDir dir=VideoStreamSendRecv;
1505 MSWebCam *cam=lc->video_conf.device;
1506 bool_t is_inactive=FALSE;
1508 call->current_params.has_video=TRUE;
1510 video_stream_enable_adaptive_bitrate_control(call->videostream,
1511 linphone_core_adaptive_rate_control_enabled(lc));
1512 video_stream_enable_adaptive_jittcomp(call->videostream, linphone_core_video_adaptive_jittcomp_enabled(lc));
1513 video_stream_set_sent_video_size(call->videostream,linphone_core_get_preferred_video_size(lc));
1514 video_stream_enable_self_view(call->videostream,lc->video_conf.selfview);
1515 if (lc->video_window_id!=0)
1516 video_stream_set_native_window_id(call->videostream,lc->video_window_id);
1517 if (lc->preview_window_id!=0)
1518 video_stream_set_native_preview_window_id (call->videostream,lc->preview_window_id);
1519 video_stream_use_preview_video_window (call->videostream,lc->use_preview_window);
1521 if (vstream->dir==SalStreamSendOnly && lc->video_conf.capture ){
1522 cam=get_nowebcam_device();
1523 dir=VideoStreamSendOnly;
1524 }else if (vstream->dir==SalStreamRecvOnly && lc->video_conf.display ){
1525 dir=VideoStreamRecvOnly;
1526 }else if (vstream->dir==SalStreamSendRecv){
1527 if (lc->video_conf.display && lc->video_conf.capture)
1528 dir=VideoStreamSendRecv;
1529 else if (lc->video_conf.display)
1530 dir=VideoStreamRecvOnly;
1532 dir=VideoStreamSendOnly;
1534 ms_warning("video stream is inactive.");
1535 /*either inactive or incompatible with local capabilities*/
1538 if (call->camera_active==FALSE || all_inputs_muted){
1539 cam=get_nowebcam_device();
1542 call->log->video_enabled = TRUE;
1543 video_stream_set_direction (call->videostream, dir);
1544 ms_message("%s lc rotation:%d\n", __FUNCTION__, lc->device_rotation);
1545 video_stream_set_device_rotation(call->videostream, lc->device_rotation);
1546 video_stream_start(call->videostream,
1547 call->video_profile, rtp_addr, vstream->rtp_port,
1548 rtcp_addr, linphone_core_rtcp_enabled(lc) ? (vstream->rtcp_port) : 0,
1549 used_pt, linphone_core_get_video_jittcomp(lc), cam);
1550 video_stream_set_rtcp_information(call->videostream, cname,rtcp_tool);
1553 if (vstream->proto == SalProtoRtpSavp) {
1554 const SalStreamDescription *local_st_desc=sal_media_description_find_stream(call->localdesc,
1555 SalProtoRtpSavp,SalVideo);
1557 video_stream_enable_strp(
1559 vstream->crypto[0].algo,
1560 local_st_desc->crypto[0].master_key,
1561 vstream->crypto[0].master_key
1563 call->videostream_encrypted=TRUE;
1565 call->videostream_encrypted=FALSE;
1567 }else ms_warning("No video stream accepted.");
1569 ms_warning("No valid video stream defined.");
1574 void linphone_call_start_media_streams(LinphoneCall *call, bool_t all_inputs_muted, bool_t send_ringbacktone){
1575 LinphoneCore *lc=call->core;
1577 call->current_params.audio_codec = NULL;
1578 call->current_params.video_codec = NULL;
1580 LinphoneAddress *me=linphone_core_get_primary_contact_parsed(lc);
1582 bool_t use_arc=linphone_core_adaptive_rate_control_enabled(lc);
1583 #ifdef VIDEO_ENABLED
1584 const SalStreamDescription *vstream=sal_media_description_find_stream(call->resultdesc,
1585 SalProtoRtpAvp,SalVideo);
1588 if ((call->audiostream == NULL) && (call->videostream == NULL)) {
1589 ms_fatal("start_media_stream() called without prior init !");
1592 cname=linphone_address_as_string_uri_only(me);
1594 #if defined(VIDEO_ENABLED)
1595 if (vstream!=NULL && vstream->dir!=SalStreamInactive && vstream->payloads!=NULL){
1596 /*when video is used, do not make adaptive rate control on audio, it is stupid.*/
1600 if (call->audiostream!=NULL) {
1601 linphone_call_start_audio_stream(call,cname,all_inputs_muted,send_ringbacktone,use_arc);
1603 call->current_params.has_video=FALSE;
1604 if (call->videostream!=NULL) {
1605 linphone_call_start_video_stream(call,cname,all_inputs_muted);
1608 call->all_muted=all_inputs_muted;
1609 call->playing_ringbacktone=send_ringbacktone;
1610 call->up_bw=linphone_core_get_upload_bandwidth(lc);
1612 if (call->params.media_encryption==LinphoneMediaEncryptionZRTP) {
1613 OrtpZrtpParams params;
1614 /*will be set later when zrtp is activated*/
1615 call->current_params.media_encryption=LinphoneMediaEncryptionNone;
1617 params.zid_file=lc->zrtp_secrets_cache;
1618 audio_stream_enable_zrtp(call->audiostream,¶ms);
1619 }else if (call->params.media_encryption==LinphoneMediaEncryptionSRTP){
1620 call->current_params.media_encryption=linphone_call_are_all_streams_encrypted(call) ?
1621 LinphoneMediaEncryptionSRTP : LinphoneMediaEncryptionNone;
1624 /*also reflect the change if the "wished" params, in order to avoid to propose SAVP or video again
1625 * further in the call, for example during pause,resume, conferencing reINVITEs*/
1626 linphone_call_fix_call_parameters(call);
1627 if ((call->ice_session != NULL) && (ice_session_state(call->ice_session) != IS_Completed)) {
1628 ice_session_start_connectivity_checks(call->ice_session);
1634 linphone_address_destroy(me);
1637 void linphone_call_start_media_streams_for_ice_gathering(LinphoneCall *call){
1638 audio_stream_prepare_sound(call->audiostream, NULL, NULL);
1639 #ifdef VIDEO_ENABLED
1640 if (call->videostream) {
1641 video_stream_prepare_video(call->videostream);
1646 void linphone_call_stop_media_streams_for_ice_gathering(LinphoneCall *call){
1647 audio_stream_unprepare_sound(call->audiostream);
1648 #ifdef VIDEO_ENABLED
1649 if (call->videostream) {
1650 video_stream_unprepare_video(call->videostream);
1655 void linphone_call_delete_ice_session(LinphoneCall *call){
1656 if (call->ice_session != NULL) {
1657 ice_session_destroy(call->ice_session);
1658 call->ice_session = NULL;
1659 if (call->audiostream != NULL) call->audiostream->ice_check_list = NULL;
1660 if (call->videostream != NULL) call->videostream->ice_check_list = NULL;
1661 call->stats[LINPHONE_CALL_STATS_AUDIO].ice_state = LinphoneIceStateNotActivated;
1662 call->stats[LINPHONE_CALL_STATS_VIDEO].ice_state = LinphoneIceStateNotActivated;
1666 static void linphone_call_log_fill_stats(LinphoneCallLog *log, AudioStream *st){
1667 audio_stream_get_local_rtp_stats (st,&log->local_stats);
1668 log->quality=audio_stream_get_average_quality_rating(st);
1671 void linphone_call_stop_audio_stream(LinphoneCall *call) {
1672 if (call->audiostream!=NULL) {
1673 rtp_session_unregister_event_queue(call->audiostream->session,call->audiostream_app_evq);
1674 ortp_ev_queue_flush(call->audiostream_app_evq);
1675 ortp_ev_queue_destroy(call->audiostream_app_evq);
1676 call->audiostream_app_evq=NULL;
1678 if (call->audiostream->ec){
1679 const char *state_str=NULL;
1680 ms_filter_call_method(call->audiostream->ec,MS_ECHO_CANCELLER_GET_STATE_STRING,&state_str);
1682 ms_message("Writing echo canceler state, %i bytes",(int)strlen(state_str));
1683 lp_config_set_string(call->core->config,"sound","ec_state",state_str);
1686 linphone_call_log_fill_stats (call->log,call->audiostream);
1687 if (call->endpoint){
1688 linphone_call_remove_from_conf(call);
1690 audio_stream_stop(call->audiostream);
1691 call->audiostream=NULL;
1695 void linphone_call_stop_video_stream(LinphoneCall *call) {
1696 #ifdef VIDEO_ENABLED
1697 if (call->videostream!=NULL){
1698 rtp_session_unregister_event_queue(call->videostream->session,call->videostream_app_evq);
1699 ortp_ev_queue_flush(call->videostream_app_evq);
1700 ortp_ev_queue_destroy(call->videostream_app_evq);
1701 call->videostream_app_evq=NULL;
1702 video_stream_stop(call->videostream);
1703 call->videostream=NULL;
1708 void linphone_call_stop_media_streams(LinphoneCall *call){
1709 linphone_call_stop_audio_stream(call);
1710 linphone_call_stop_video_stream(call);
1711 ms_event_queue_skip(call->core->msevq);
1713 if (call->audio_profile){
1714 rtp_profile_clear_all(call->audio_profile);
1715 rtp_profile_destroy(call->audio_profile);
1716 call->audio_profile=NULL;
1718 if (call->video_profile){
1719 rtp_profile_clear_all(call->video_profile);
1720 rtp_profile_destroy(call->video_profile);
1721 call->video_profile=NULL;
1727 void linphone_call_enable_echo_cancellation(LinphoneCall *call, bool_t enable) {
1728 if (call!=NULL && call->audiostream!=NULL && call->audiostream->ec){
1729 bool_t bypass_mode = !enable;
1730 ms_filter_call_method(call->audiostream->ec,MS_ECHO_CANCELLER_SET_BYPASS_MODE,&bypass_mode);
1733 bool_t linphone_call_echo_cancellation_enabled(LinphoneCall *call) {
1734 if (call!=NULL && call->audiostream!=NULL && call->audiostream->ec){
1736 ms_filter_call_method(call->audiostream->ec,MS_ECHO_CANCELLER_GET_BYPASS_MODE,&val);
1739 return linphone_core_echo_cancellation_enabled(call->core);
1743 void linphone_call_enable_echo_limiter(LinphoneCall *call, bool_t val){
1744 if (call!=NULL && call->audiostream!=NULL ) {
1746 const char *type=lp_config_get_string(call->core->config,"sound","el_type","mic");
1747 if (strcasecmp(type,"mic")==0)
1748 audio_stream_enable_echo_limiter(call->audiostream,ELControlMic);
1749 else if (strcasecmp(type,"full")==0)
1750 audio_stream_enable_echo_limiter(call->audiostream,ELControlFull);
1752 audio_stream_enable_echo_limiter(call->audiostream,ELInactive);
1757 bool_t linphone_call_echo_limiter_enabled(const LinphoneCall *call){
1758 if (call!=NULL && call->audiostream!=NULL ){
1759 return call->audiostream->el_type !=ELInactive ;
1761 return linphone_core_echo_limiter_enabled(call->core);
1766 * @addtogroup call_misc
1771 * Returns the measured sound volume played locally (received from remote).
1772 * It is expressed in dbm0.
1774 float linphone_call_get_play_volume(LinphoneCall *call){
1775 AudioStream *st=call->audiostream;
1776 if (st && st->volrecv){
1778 ms_filter_call_method(st->volrecv,MS_VOLUME_GET,&vol);
1782 return LINPHONE_VOLUME_DB_LOWEST;
1786 * Returns the measured sound volume recorded locally (sent to remote).
1787 * It is expressed in dbm0.
1789 float linphone_call_get_record_volume(LinphoneCall *call){
1790 AudioStream *st=call->audiostream;
1791 if (st && st->volsend && !call->audio_muted && call->state==LinphoneCallStreamsRunning){
1793 ms_filter_call_method(st->volsend,MS_VOLUME_GET,&vol);
1797 return LINPHONE_VOLUME_DB_LOWEST;
1801 * Obtain real-time quality rating of the call
1803 * Based on local RTP statistics and RTCP feedback, a quality rating is computed and updated
1804 * during all the duration of the call. This function returns its value at the time of the function call.
1805 * It is expected that the rating is updated at least every 5 seconds or so.
1806 * The rating is a floating point number comprised between 0 and 5.
1808 * 4-5 = good quality <br>
1809 * 3-4 = average quality <br>
1810 * 2-3 = poor quality <br>
1811 * 1-2 = very poor quality <br>
1812 * 0-1 = can't be worse, mostly unusable <br>
1814 * @returns The function returns -1 if no quality measurement is available, for example if no
1815 * active audio stream exist. Otherwise it returns the quality rating.
1817 float linphone_call_get_current_quality(LinphoneCall *call){
1818 if (call->audiostream){
1819 return audio_stream_get_quality_rating(call->audiostream);
1825 * Returns call quality averaged over all the duration of the call.
1827 * See linphone_call_get_current_quality() for more details about quality measurement.
1829 float linphone_call_get_average_quality(LinphoneCall *call){
1830 if (call->audiostream){
1831 return audio_stream_get_average_quality_rating(call->audiostream);
1837 * Access last known statistics for audio stream, for a given call.
1839 const LinphoneCallStats *linphone_call_get_audio_stats(const LinphoneCall *call) {
1840 return &call->stats[LINPHONE_CALL_STATS_AUDIO];
1844 * Access last known statistics for video stream, for a given call.
1846 const LinphoneCallStats *linphone_call_get_video_stats(const LinphoneCall *call) {
1847 return &call->stats[LINPHONE_CALL_STATS_VIDEO];
1855 static void report_bandwidth(LinphoneCall *call, RtpSession *as, RtpSession *vs){
1856 call->stats[LINPHONE_CALL_STATS_AUDIO].download_bandwidth=(as!=NULL) ? (rtp_session_compute_recv_bandwidth(as)*1e-3) : 0;
1857 call->stats[LINPHONE_CALL_STATS_AUDIO].upload_bandwidth=(as!=NULL) ? (rtp_session_compute_send_bandwidth(as)*1e-3) : 0;
1858 call->stats[LINPHONE_CALL_STATS_VIDEO].download_bandwidth=(vs!=NULL) ? (rtp_session_compute_recv_bandwidth(vs)*1e-3) : 0;
1859 call->stats[LINPHONE_CALL_STATS_VIDEO].upload_bandwidth=(vs!=NULL) ? (rtp_session_compute_send_bandwidth(vs)*1e-3) : 0;
1860 ms_message("bandwidth usage: audio=[d=%.1f,u=%.1f] video=[d=%.1f,u=%.1f] kbit/sec",
1861 call->stats[LINPHONE_CALL_STATS_AUDIO].download_bandwidth,
1862 call->stats[LINPHONE_CALL_STATS_AUDIO].upload_bandwidth ,
1863 call->stats[LINPHONE_CALL_STATS_VIDEO].download_bandwidth,
1864 call->stats[LINPHONE_CALL_STATS_VIDEO].upload_bandwidth
1868 static void linphone_core_disconnected(LinphoneCore *lc, LinphoneCall *call){
1872 from = linphone_call_get_remote_address_as_string(call);
1875 snprintf(temp,sizeof(temp),"Remote end %s seems to have disconnected, the call is going to be closed.",from);
1880 snprintf(temp,sizeof(temp),"Remote end seems to have disconnected, the call is going to be closed.");
1882 if (lc->vtable.display_warning!=NULL)
1883 lc->vtable.display_warning(lc,temp);
1884 linphone_core_terminate_call(lc,call);
1887 static void handle_ice_events(LinphoneCall *call, OrtpEvent *ev){
1888 OrtpEventType evt=ortp_event_get_type(ev);
1889 OrtpEventData *evd=ortp_event_get_data(ev);
1892 if (evt == ORTP_EVENT_ICE_SESSION_PROCESSING_FINISHED) {
1893 switch (ice_session_state(call->ice_session)) {
1895 ice_session_select_candidates(call->ice_session);
1896 if (ice_session_role(call->ice_session) == IR_Controlling) {
1897 linphone_core_update_call(call->core, call, &call->current_params);
1901 if (ice_session_has_completed_check_list(call->ice_session) == TRUE) {
1902 ice_session_select_candidates(call->ice_session);
1903 if (ice_session_role(call->ice_session) == IR_Controlling) {
1904 /* At least one ICE session has succeeded, so perform a call update. */
1905 linphone_core_update_call(call->core, call, &call->current_params);
1912 linphone_core_update_ice_state_in_call_stats(call);
1913 } else if (evt == ORTP_EVENT_ICE_GATHERING_FINISHED) {
1915 if (evd->info.ice_processing_successful==TRUE) {
1916 ice_session_compute_candidates_foundations(call->ice_session);
1917 ice_session_eliminate_redundant_candidates(call->ice_session);
1918 ice_session_choose_default_candidates(call->ice_session);
1919 ping_time = ice_session_average_gathering_round_trip_time(call->ice_session);
1920 if (ping_time >=0) {
1921 call->ping_time=ping_time;
1924 ms_warning("No STUN answer from [%s], disabling ICE",linphone_core_get_stun_server(call->core));
1925 linphone_call_delete_ice_session(call);
1927 switch (call->state) {
1928 case LinphoneCallUpdating:
1929 linphone_core_start_update_call(call->core, call);
1931 case LinphoneCallUpdatedByRemote:
1932 linphone_core_start_accept_call_update(call->core, call);
1934 case LinphoneCallOutgoingInit:
1935 linphone_call_stop_media_streams_for_ice_gathering(call);
1936 linphone_core_proceed_with_invite_if_ready(call->core, call, NULL);
1938 case LinphoneCallIdle:
1939 linphone_call_stop_media_streams_for_ice_gathering(call);
1940 linphone_core_notify_incoming_call(call->core, call);
1945 } else if (evt == ORTP_EVENT_ICE_LOSING_PAIRS_COMPLETED) {
1946 linphone_core_start_accept_call_update(call->core, call);
1947 linphone_core_update_ice_state_in_call_stats(call);
1948 } else if (evt == ORTP_EVENT_ICE_RESTART_NEEDED) {
1949 ice_session_restart(call->ice_session);
1950 ice_session_set_role(call->ice_session, IR_Controlling);
1951 linphone_core_update_call(call->core, call, &call->current_params);
1955 void linphone_call_background_tasks(LinphoneCall *call, bool_t one_second_elapsed){
1956 LinphoneCore* lc = call->core;
1957 int disconnect_timeout = linphone_core_get_nortp_timeout(call->core);
1958 bool_t disconnected=FALSE;
1960 if (call->state==LinphoneCallStreamsRunning && one_second_elapsed){
1961 RtpSession *as=NULL,*vs=NULL;
1962 float audio_load=0, video_load=0;
1963 if (call->audiostream!=NULL){
1964 as=call->audiostream->session;
1965 if (call->audiostream->ticker)
1966 audio_load=ms_ticker_get_average_load(call->audiostream->ticker);
1968 if (call->videostream!=NULL){
1969 if (call->videostream->ticker)
1970 video_load=ms_ticker_get_average_load(call->videostream->ticker);
1971 vs=call->videostream->session;
1973 report_bandwidth(call,as,vs);
1974 ms_message("Thread processing load: audio=%f\tvideo=%f",audio_load,video_load);
1976 #ifdef VIDEO_ENABLED
1977 if (call->videostream!=NULL) {
1980 /* Ensure there is no dangling ICE check list. */
1981 if (call->ice_session == NULL) call->videostream->ice_check_list = NULL;
1983 // Beware that the application queue should not depend on treatments fron the
1984 // mediastreamer queue.
1985 video_stream_iterate(call->videostream);
1987 while (call->videostream_app_evq && (NULL != (ev=ortp_ev_queue_get(call->videostream_app_evq)))){
1988 OrtpEventType evt=ortp_event_get_type(ev);
1989 OrtpEventData *evd=ortp_event_get_data(ev);
1990 if (evt == ORTP_EVENT_ZRTP_ENCRYPTION_CHANGED){
1991 linphone_call_videostream_encryption_changed(call, evd->info.zrtp_stream_encrypted);
1992 } else if (evt == ORTP_EVENT_RTCP_PACKET_RECEIVED) {
1993 call->stats[LINPHONE_CALL_STATS_VIDEO].round_trip_delay = rtp_session_get_round_trip_propagation(call->videostream->session);
1994 if(call->stats[LINPHONE_CALL_STATS_VIDEO].received_rtcp != NULL)
1995 freemsg(call->stats[LINPHONE_CALL_STATS_VIDEO].received_rtcp);
1996 call->stats[LINPHONE_CALL_STATS_VIDEO].received_rtcp = evd->packet;
1998 if (lc->vtable.call_stats_updated)
1999 lc->vtable.call_stats_updated(lc, call, &call->stats[LINPHONE_CALL_STATS_VIDEO]);
2000 } else if (evt == ORTP_EVENT_RTCP_PACKET_EMITTED) {
2001 memcpy(&call->stats[LINPHONE_CALL_STATS_VIDEO].jitter_stats, rtp_session_get_jitter_stats(call->videostream->session), sizeof(jitter_stats_t));
2002 if(call->stats[LINPHONE_CALL_STATS_VIDEO].sent_rtcp != NULL)
2003 freemsg(call->stats[LINPHONE_CALL_STATS_VIDEO].sent_rtcp);
2004 call->stats[LINPHONE_CALL_STATS_VIDEO].sent_rtcp = evd->packet;
2006 if (lc->vtable.call_stats_updated)
2007 lc->vtable.call_stats_updated(lc, call, &call->stats[LINPHONE_CALL_STATS_VIDEO]);
2008 } else if ((evt == ORTP_EVENT_ICE_SESSION_PROCESSING_FINISHED) || (evt == ORTP_EVENT_ICE_GATHERING_FINISHED)
2009 || (evt == ORTP_EVENT_ICE_LOSING_PAIRS_COMPLETED) || (evt == ORTP_EVENT_ICE_RESTART_NEEDED)) {
2010 handle_ice_events(call, ev);
2012 ortp_event_destroy(ev);
2016 if (call->audiostream!=NULL) {
2019 /* Ensure there is no dangling ICE check list. */
2020 if (call->ice_session == NULL) call->audiostream->ice_check_list = NULL;
2022 // Beware that the application queue should not depend on treatments fron the
2023 // mediastreamer queue.
2024 audio_stream_iterate(call->audiostream);
2026 while (call->audiostream_app_evq && (NULL != (ev=ortp_ev_queue_get(call->audiostream_app_evq)))){
2027 OrtpEventType evt=ortp_event_get_type(ev);
2028 OrtpEventData *evd=ortp_event_get_data(ev);
2029 if (evt == ORTP_EVENT_ZRTP_ENCRYPTION_CHANGED){
2030 linphone_call_audiostream_encryption_changed(call, evd->info.zrtp_stream_encrypted);
2031 } else if (evt == ORTP_EVENT_ZRTP_SAS_READY) {
2032 linphone_call_audiostream_auth_token_ready(call, evd->info.zrtp_sas.sas, evd->info.zrtp_sas.verified);
2033 } else if (evt == ORTP_EVENT_RTCP_PACKET_RECEIVED) {
2034 call->stats[LINPHONE_CALL_STATS_AUDIO].round_trip_delay = rtp_session_get_round_trip_propagation(call->audiostream->session);
2035 if(call->stats[LINPHONE_CALL_STATS_AUDIO].received_rtcp != NULL)
2036 freemsg(call->stats[LINPHONE_CALL_STATS_AUDIO].received_rtcp);
2037 call->stats[LINPHONE_CALL_STATS_AUDIO].received_rtcp = evd->packet;
2039 if (lc->vtable.call_stats_updated)
2040 lc->vtable.call_stats_updated(lc, call, &call->stats[LINPHONE_CALL_STATS_AUDIO]);
2041 } else if (evt == ORTP_EVENT_RTCP_PACKET_EMITTED) {
2042 memcpy(&call->stats[LINPHONE_CALL_STATS_AUDIO].jitter_stats, rtp_session_get_jitter_stats(call->audiostream->session), sizeof(jitter_stats_t));
2043 if(call->stats[LINPHONE_CALL_STATS_AUDIO].sent_rtcp != NULL)
2044 freemsg(call->stats[LINPHONE_CALL_STATS_AUDIO].sent_rtcp);
2045 call->stats[LINPHONE_CALL_STATS_AUDIO].sent_rtcp = evd->packet;
2047 if (lc->vtable.call_stats_updated)
2048 lc->vtable.call_stats_updated(lc, call, &call->stats[LINPHONE_CALL_STATS_AUDIO]);
2049 } else if ((evt == ORTP_EVENT_ICE_SESSION_PROCESSING_FINISHED) || (evt == ORTP_EVENT_ICE_GATHERING_FINISHED)
2050 || (evt == ORTP_EVENT_ICE_LOSING_PAIRS_COMPLETED) || (evt == ORTP_EVENT_ICE_RESTART_NEEDED)) {
2051 handle_ice_events(call, ev);
2052 } else if (evt==ORTP_EVENT_TELEPHONE_EVENT){
2053 linphone_core_dtmf_received(lc,evd->info.telephone_event);
2055 ortp_event_destroy(ev);
2058 if (call->state==LinphoneCallStreamsRunning && one_second_elapsed && call->audiostream!=NULL && disconnect_timeout>0 )
2059 disconnected=!audio_stream_alive(call->audiostream,disconnect_timeout);
2061 linphone_core_disconnected(call->core,call);
2064 void linphone_call_log_completed(LinphoneCall *call){
2065 LinphoneCore *lc=call->core;
2067 call->log->duration=time(NULL)-call->start_time;
2069 if (call->log->status==LinphoneCallMissed){
2072 info=ortp_strdup_printf(ngettext("You have missed %i call.",
2073 "You have missed %i calls.", lc->missed_calls),
2075 if (lc->vtable.display_status!=NULL)
2076 lc->vtable.display_status(lc,info);
2079 lc->call_logs=ms_list_prepend(lc->call_logs,(void *)call->log);
2080 if (ms_list_size(lc->call_logs)>lc->max_call_logs){
2081 MSList *elem,*prevelem=NULL;
2082 /*find the last element*/
2083 for(elem=lc->call_logs;elem!=NULL;elem=elem->next){
2087 linphone_call_log_destroy((LinphoneCallLog*)elem->data);
2088 lc->call_logs=ms_list_remove_link(lc->call_logs,elem);
2090 if (lc->vtable.call_log_updated!=NULL){
2091 lc->vtable.call_log_updated(lc,call->log);
2093 call_logs_write_to_config_file(lc);
2096 LinphoneCallState linphone_call_get_transfer_state(LinphoneCall *call) {
2097 return call->transfer_state;
2100 void linphone_call_set_transfer_state(LinphoneCall* call, LinphoneCallState state) {
2101 if (state != call->transfer_state) {
2102 LinphoneCore* lc = call->core;
2103 call->transfer_state = state;
2104 if (lc->vtable.transfer_state_changed)
2105 lc->vtable.transfer_state_changed(lc, call, state);
2110 * Returns true if the call is part of the conference.
2111 * @ingroup conferencing
2113 bool_t linphone_call_is_in_conference(const LinphoneCall *call) {
2114 return call->params.in_conference;
2119 * Perform a zoom of the video displayed during a call.
2120 * @param call the call.
2121 * @param zoom_factor a floating point number describing the zoom factor. A value 1.0 corresponds to no zoom applied.
2122 * @param cx a floating point number pointing the horizontal center of the zoom to be applied. This value should be between 0.0 and 1.0.
2123 * @param cy a floating point number pointing the vertical center of the zoom to be applied. This value should be between 0.0 and 1.0.
2125 * cx and cy are updated in return in case their coordinates were to excentrated for the requested zoom factor. The zoom ensures that all the screen is fullfilled with the video.
2127 void linphone_call_zoom_video(LinphoneCall* call, float zoom_factor, float* cx, float* cy) {
2128 VideoStream* vstream = call->videostream;
2129 if (vstream && vstream->output) {
2132 if (zoom_factor < 1)
2134 float halfsize = 0.5 * 1.0 / zoom_factor;
2136 if ((*cx - halfsize) < 0)
2138 if ((*cx + halfsize) > 1)
2140 if ((*cy - halfsize) < 0)
2142 if ((*cy + halfsize) > 1)
2145 zoom[0] = zoom_factor;
2148 ms_filter_call_method(vstream->output, MS_VIDEO_DISPLAY_ZOOM, &zoom);
2149 }else ms_warning("Could not apply zoom: video output wasn't activated.");