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->ms.zrtp_context==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->ms.zrtp_context);
169 }else if (call->auth_token_verified && !verified){
170 ortp_zrtp_sas_reset_verified(call->audiostream->ms.zrtp_context);
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(lc->default_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);
287 if(call->upnp_session != NULL) {
288 linphone_core_update_local_media_description_from_upnp(md, call->upnp_session);
289 linphone_core_update_upnp_state_in_call_stats(call);
292 linphone_address_destroy(addr);
294 if (old_md) sal_media_description_unref(old_md);
297 static int find_port_offset(LinphoneCore *lc, SalStreamType type){
302 bool_t already_used=FALSE;
303 for(offset=0;offset<100;offset+=2){
307 tried_port=linphone_core_get_audio_port (lc)+offset;
310 tried_port=linphone_core_get_video_port (lc)+offset;
314 for(elem=lc->calls;elem!=NULL;elem=elem->next){
315 LinphoneCall *call=(LinphoneCall*)elem->data;
319 existing_port = call->audio_port;
322 existing_port = call->video_port;
325 if (existing_port==tried_port) {
330 if (!already_used) break;
333 ms_error("Could not find any free port !");
339 static int select_random_port(LinphoneCore *lc, SalStreamType type) {
343 int existing_port = 0;
344 int min_port = 0, max_port = 0;
345 bool_t already_used = FALSE;
350 linphone_core_get_audio_port_range(lc, &min_port, &max_port);
353 linphone_core_get_video_port_range(lc, &min_port, &max_port);
356 tried_port = (rand() % (max_port - min_port) + min_port) & ~0x1;
357 if (tried_port < min_port) tried_port = min_port + 2;
358 for (nb_tries = 0; nb_tries < 100; nb_tries++) {
359 for (elem = lc->calls; elem != NULL; elem = elem->next) {
360 LinphoneCall *call = (LinphoneCall *)elem->data;
364 existing_port = call->audio_port;
367 existing_port = call->video_port;
370 if (existing_port == tried_port) {
375 if (!already_used) break;
377 if (nb_tries == 100) {
378 ms_error("Could not find any free port!");
384 static void linphone_call_init_common(LinphoneCall *call, LinphoneAddress *from, LinphoneAddress *to){
386 int min_port, max_port;
387 call->magic=linphone_call_magic;
389 call->state=LinphoneCallIdle;
390 call->transfer_state = LinphoneCallIdle;
391 call->start_time=time(NULL);
392 call->media_start_time=0;
393 call->log=linphone_call_log_new(call, from, to);
394 call->owns_call_log=TRUE;
395 linphone_core_notify_all_friends(call->core,LinphoneStatusOnThePhone);
396 linphone_core_get_audio_port_range(call->core, &min_port, &max_port);
397 if (min_port == max_port) {
398 /* Used fixed RTP audio port. */
399 port_offset=find_port_offset (call->core, SalAudio);
400 if (port_offset==-1) return;
401 call->audio_port=linphone_core_get_audio_port(call->core)+port_offset;
403 /* Select random RTP audio port in the specified range. */
404 call->audio_port = select_random_port(call->core, SalAudio);
406 linphone_core_get_video_port_range(call->core, &min_port, &max_port);
407 if (min_port == max_port) {
408 /* Used fixed RTP video port. */
409 port_offset=find_port_offset (call->core, SalVideo);
410 if (port_offset==-1) return;
411 call->video_port=linphone_core_get_video_port(call->core)+port_offset;
413 /* Select random RTP video port in the specified range. */
414 call->video_port = select_random_port(call->core, SalVideo);
416 linphone_call_init_stats(&call->stats[LINPHONE_CALL_STATS_AUDIO], LINPHONE_CALL_STATS_AUDIO);
417 linphone_call_init_stats(&call->stats[LINPHONE_CALL_STATS_VIDEO], LINPHONE_CALL_STATS_VIDEO);
420 void linphone_call_init_stats(LinphoneCallStats *stats, int type) {
422 stats->received_rtcp = NULL;
423 stats->sent_rtcp = NULL;
424 stats->ice_state = LinphoneIceStateNotActivated;
426 stats->upnp_state = LinphoneUpnpStateIdle;
428 stats->upnp_state = LinphoneUpnpStateNotAvailable;
433 static void discover_mtu(LinphoneCore *lc, const char *remote){
435 if (lc->net_conf.mtu==0 ){
436 /*attempt to discover mtu*/
437 mtu=ms_discover_mtu(remote);
440 ms_message("Discovered mtu is %i, RTP payload max size is %i",
441 mtu, ms_get_payload_max_size());
446 LinphoneCall * linphone_call_new_outgoing(struct _LinphoneCore *lc, LinphoneAddress *from, LinphoneAddress *to, const LinphoneCallParams *params)
448 LinphoneCall *call=ms_new0(LinphoneCall,1);
449 call->dir=LinphoneCallOutgoing;
450 call->op=sal_op_new(lc->sal);
451 sal_op_set_user_pointer(call->op,call);
453 linphone_core_get_local_ip(lc,linphone_address_get_domain(to),call->localip);
454 linphone_call_init_common(call,from,to);
455 call->params=*params;
456 if (linphone_core_get_firewall_policy(call->core) == LinphonePolicyUseIce) {
457 call->ice_session = ice_session_new();
458 ice_session_set_role(call->ice_session, IR_Controlling);
460 if (linphone_core_get_firewall_policy(call->core) == LinphonePolicyUseStun) {
461 call->ping_time=linphone_core_run_stun_tests(call->core,call);
464 if (linphone_core_get_firewall_policy(call->core) == LinphonePolicyUseUpnp) {
465 call->upnp_session = linphone_upnp_session_new(call);
468 call->camera_active=params->has_video;
470 discover_mtu(lc,linphone_address_get_domain (to));
471 if (params->referer){
472 sal_call_set_referer(call->op,params->referer->op);
473 call->referer=linphone_call_ref(params->referer);
478 LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *from, LinphoneAddress *to, SalOp *op){
479 LinphoneCall *call=ms_new0(LinphoneCall,1);
481 const SalMediaDescription *md;
483 call->dir=LinphoneCallIncoming;
484 sal_op_set_user_pointer(op,call);
488 if (lc->sip_conf.ping_with_options){
489 /*the following sends an option request back to the caller so that
490 we get a chance to discover our nat'd address before answering.*/
491 call->ping_op=sal_op_new(lc->sal);
492 from_str=linphone_address_as_string_uri_only(from);
493 sal_op_set_route(call->ping_op,sal_op_get_network_origin(op));
494 sal_op_set_user_pointer(call->ping_op,call);
495 sal_ping(call->ping_op,linphone_core_find_best_identity(lc,from,NULL),from_str);
499 linphone_address_clean(from);
500 linphone_core_get_local_ip(lc,linphone_address_get_domain(from),call->localip);
501 linphone_call_init_common(call, from, to);
502 call->log->call_id=ms_strdup(sal_op_get_call_id(op)); /*must be known at that time*/
503 linphone_core_init_default_params(lc, &call->params);
504 md=sal_call_get_remote_media_description(op);
505 call->params.has_video &= !!lc->video_policy.automatically_accept;
507 // It is licit to receive an INVITE without SDP
508 // In this case WE chose the media parameters according to policy.
509 call->params.has_video &= linphone_core_media_description_contains_video_stream(md);
511 switch (linphone_core_get_firewall_policy(call->core)) {
512 case LinphonePolicyUseIce:
513 call->ice_session = ice_session_new();
514 ice_session_set_role(call->ice_session, IR_Controlled);
515 linphone_core_update_ice_from_remote_media_description(call, sal_call_get_remote_media_description(op));
516 if (call->ice_session != NULL) {
517 linphone_call_init_media_streams(call);
518 linphone_call_start_media_streams_for_ice_gathering(call);
519 if (linphone_core_gather_ice_candidates(call->core,call)<0) {
520 /* Ice candidates gathering failed, proceed with the call anyway. */
521 linphone_call_delete_ice_session(call);
522 linphone_call_stop_media_streams_for_ice_gathering(call);
526 case LinphonePolicyUseStun:
527 call->ping_time=linphone_core_run_stun_tests(call->core,call);
528 /* No break to also destroy ice session in this case. */
530 case LinphonePolicyUseUpnp:
532 call->upnp_session = linphone_upnp_session_new(call);
533 if (call->upnp_session != NULL) {
534 linphone_call_init_media_streams(call);
535 if (linphone_core_update_upnp_from_remote_media_description(call, sal_call_get_remote_media_description(op))<0) {
536 /* uPnP port mappings failed, proceed with the call anyway. */
537 linphone_call_delete_upnp_session(call);
545 call->camera_active=call->params.has_video;
547 discover_mtu(lc,linphone_address_get_domain(from));
551 /* this function is called internally to get rid of a call.
552 It performs the following tasks:
553 - remove the call from the internal list of calls
554 - update the call logs accordingly
557 static void linphone_call_set_terminated(LinphoneCall *call){
558 LinphoneCore *lc=call->core;
560 linphone_core_update_allocated_audio_bandwidth(lc);
562 call->owns_call_log=FALSE;
563 linphone_call_log_completed(call);
566 if (call == lc->current_call){
567 ms_message("Resetting the current call");
568 lc->current_call=NULL;
571 if (linphone_core_del_call(lc,call) != 0){
572 ms_error("Could not remove the call from the list !!!");
575 if (ms_list_size(lc->calls)==0)
576 linphone_core_notify_all_friends(lc,lc->presence_mode);
578 linphone_core_conference_check_uninit(lc);
579 if (call->ringing_beep){
580 linphone_core_stop_dtmf(lc);
581 call->ringing_beep=FALSE;
584 linphone_call_unref(call->referer);
589 void linphone_call_fix_call_parameters(LinphoneCall *call){
590 call->params.has_video=call->current_params.has_video;
591 call->params.media_encryption=call->current_params.media_encryption;
594 const char *linphone_call_state_to_string(LinphoneCallState cs){
596 case LinphoneCallIdle:
597 return "LinphoneCallIdle";
598 case LinphoneCallIncomingReceived:
599 return "LinphoneCallIncomingReceived";
600 case LinphoneCallOutgoingInit:
601 return "LinphoneCallOutgoingInit";
602 case LinphoneCallOutgoingProgress:
603 return "LinphoneCallOutgoingProgress";
604 case LinphoneCallOutgoingRinging:
605 return "LinphoneCallOutgoingRinging";
606 case LinphoneCallOutgoingEarlyMedia:
607 return "LinphoneCallOutgoingEarlyMedia";
608 case LinphoneCallConnected:
609 return "LinphoneCallConnected";
610 case LinphoneCallStreamsRunning:
611 return "LinphoneCallStreamsRunning";
612 case LinphoneCallPausing:
613 return "LinphoneCallPausing";
614 case LinphoneCallPaused:
615 return "LinphoneCallPaused";
616 case LinphoneCallResuming:
617 return "LinphoneCallResuming";
618 case LinphoneCallRefered:
619 return "LinphoneCallRefered";
620 case LinphoneCallError:
621 return "LinphoneCallError";
622 case LinphoneCallEnd:
623 return "LinphoneCallEnd";
624 case LinphoneCallPausedByRemote:
625 return "LinphoneCallPausedByRemote";
626 case LinphoneCallUpdatedByRemote:
627 return "LinphoneCallUpdatedByRemote";
628 case LinphoneCallIncomingEarlyMedia:
629 return "LinphoneCallIncomingEarlyMedia";
630 case LinphoneCallUpdating:
631 return "LinphoneCallUpdating";
632 case LinphoneCallReleased:
633 return "LinphoneCallReleased";
635 return "undefined state";
638 void linphone_call_set_state(LinphoneCall *call, LinphoneCallState cstate, const char *message){
639 LinphoneCore *lc=call->core;
641 if (call->state!=cstate){
642 if (call->state==LinphoneCallEnd || call->state==LinphoneCallError){
643 if (cstate!=LinphoneCallReleased){
644 ms_warning("Spurious call state change from %s to %s, ignored.",linphone_call_state_to_string(call->state),
645 linphone_call_state_to_string(cstate));
649 ms_message("Call %p: moving from state %s to %s",call,linphone_call_state_to_string(call->state),
650 linphone_call_state_to_string(cstate));
651 if (cstate!=LinphoneCallRefered){
652 /*LinphoneCallRefered is rather an event, not a state.
653 Indeed it does not change the state of the call (still paused or running)*/
656 if (cstate==LinphoneCallEnd || cstate==LinphoneCallError){
657 switch(call->reason){
658 case LinphoneReasonDeclined:
659 call->log->status=LinphoneCallDeclined;
661 case LinphoneReasonNotAnswered:
662 call->log->status=LinphoneCallMissed;
667 linphone_call_set_terminated (call);
669 if (cstate == LinphoneCallConnected) {
670 call->log->status=LinphoneCallSuccess;
671 call->media_start_time=time(NULL);
674 if (lc->vtable.call_state_changed)
675 lc->vtable.call_state_changed(lc,call,cstate,message);
676 if (cstate==LinphoneCallReleased){
677 if (call->op!=NULL) {
678 /* so that we cannot have anymore upcalls for SAL
679 concerning this call*/
680 sal_op_release(call->op);
683 linphone_call_unref(call);
688 static void linphone_call_destroy(LinphoneCall *obj)
691 linphone_call_delete_upnp_session(obj);
693 linphone_call_delete_ice_session(obj);
695 sal_op_release(obj->op);
698 if (obj->resultdesc!=NULL) {
699 sal_media_description_unref(obj->resultdesc);
700 obj->resultdesc=NULL;
702 if (obj->localdesc!=NULL) {
703 sal_media_description_unref(obj->localdesc);
707 sal_op_release(obj->ping_op);
710 ms_free(obj->refer_to);
712 if (obj->owns_call_log)
713 linphone_call_log_destroy(obj->log);
714 if (obj->auth_token) {
715 ms_free(obj->auth_token);
722 * @addtogroup call_control
727 * Increments the call 's reference count.
728 * An application that wishes to retain a pointer to call object
729 * must use this function to unsure the pointer remains
730 * valid. Once the application no more needs this pointer,
731 * it must call linphone_call_unref().
733 LinphoneCall * linphone_call_ref(LinphoneCall *obj){
739 * Decrements the call object reference count.
740 * See linphone_call_ref().
742 void linphone_call_unref(LinphoneCall *obj){
745 linphone_call_destroy(obj);
750 * Returns current parameters associated to the call.
752 const LinphoneCallParams * linphone_call_get_current_params(const LinphoneCall *call){
753 return &call->current_params;
756 static bool_t is_video_active(const SalStreamDescription *sd){
757 return sd->rtp_port!=0 && sd->dir!=SalStreamInactive;
761 * Returns call parameters proposed by remote.
763 * This is useful when receiving an incoming call, to know whether the remote party
764 * supports video, encryption or whatever.
766 const LinphoneCallParams * linphone_call_get_remote_params(LinphoneCall *call){
767 LinphoneCallParams *cp=&call->remote_params;
768 memset(cp,0,sizeof(*cp));
770 SalMediaDescription *md=sal_call_get_remote_media_description(call->op);
772 SalStreamDescription *asd,*vsd,*secure_asd,*secure_vsd;
774 asd=sal_media_description_find_stream(md,SalProtoRtpAvp,SalAudio);
775 vsd=sal_media_description_find_stream(md,SalProtoRtpAvp,SalVideo);
776 secure_asd=sal_media_description_find_stream(md,SalProtoRtpSavp,SalAudio);
777 secure_vsd=sal_media_description_find_stream(md,SalProtoRtpSavp,SalVideo);
779 cp->has_video=is_video_active(secure_vsd);
780 if (secure_asd || asd==NULL)
781 cp->media_encryption=LinphoneMediaEncryptionSRTP;
783 cp->has_video=is_video_active(vsd);
786 if (md->bandwidth>0 && md->bandwidth<=linphone_core_get_edge_bw(call->core)){
787 cp->low_bandwidth=TRUE;
797 * Returns the remote address associated to this call
800 const LinphoneAddress * linphone_call_get_remote_address(const LinphoneCall *call){
801 return call->dir==LinphoneCallIncoming ? call->log->from : call->log->to;
805 * Returns the remote address associated to this call as a string.
807 * The result string must be freed by user using ms_free().
809 char *linphone_call_get_remote_address_as_string(const LinphoneCall *call){
810 return linphone_address_as_string(linphone_call_get_remote_address(call));
814 * Retrieves the call's current state.
816 LinphoneCallState linphone_call_get_state(const LinphoneCall *call){
821 * Returns the reason for a call termination (either error or normal termination)
823 LinphoneReason linphone_call_get_reason(const LinphoneCall *call){
828 * Get the user_pointer in the LinphoneCall
830 * @ingroup call_control
832 * return user_pointer an opaque user pointer that can be retrieved at any time
834 void *linphone_call_get_user_pointer(LinphoneCall *call)
836 return call->user_pointer;
840 * Set the user_pointer in the LinphoneCall
842 * @ingroup call_control
844 * the user_pointer is an opaque user pointer that can be retrieved at any time in the LinphoneCall
846 void linphone_call_set_user_pointer(LinphoneCall *call, void *user_pointer)
848 call->user_pointer = user_pointer;
852 * Returns the call log associated to this call.
854 LinphoneCallLog *linphone_call_get_call_log(const LinphoneCall *call){
859 * Returns the refer-to uri (if the call was transfered).
861 const char *linphone_call_get_refer_to(const LinphoneCall *call){
862 return call->refer_to;
866 * Returns direction of the call (incoming or outgoing).
868 LinphoneCallDir linphone_call_get_dir(const LinphoneCall *call){
869 return call->log->dir;
873 * Returns the far end's user agent description string, if available.
875 const char *linphone_call_get_remote_user_agent(LinphoneCall *call){
877 return sal_op_get_remote_ua (call->op);
883 * Returns true if this calls has received a transfer that has not been
885 * Pending transfers are executed when this call is being paused or closed,
886 * locally or by remote endpoint.
887 * If the call is already paused while receiving the transfer request, the
888 * transfer immediately occurs.
890 bool_t linphone_call_has_transfer_pending(const LinphoneCall *call){
891 return call->refer_pending;
895 * Returns call's duration in seconds.
897 int linphone_call_get_duration(const LinphoneCall *call){
898 if (call->media_start_time==0) return 0;
899 return time(NULL)-call->media_start_time;
903 * Returns the call object this call is replacing, if any.
904 * Call replacement can occur during call transfers.
905 * By default, the core automatically terminates the replaced call and accept the new one.
906 * This function allows the application to know whether a new incoming call is a one that replaces another one.
908 LinphoneCall *linphone_call_get_replaced_call(LinphoneCall *call){
909 SalOp *op=sal_call_get_replaces(call->op);
911 return (LinphoneCall*)sal_op_get_user_pointer(op);
917 * Indicate whether camera input should be sent to remote end.
919 void linphone_call_enable_camera (LinphoneCall *call, bool_t enable){
921 if (call->videostream!=NULL && call->videostream->ms.ticker!=NULL){
922 LinphoneCore *lc=call->core;
923 MSWebCam *nowebcam=get_nowebcam_device();
924 if (call->camera_active!=enable && lc->video_conf.device!=nowebcam){
925 video_stream_change_camera(call->videostream,
926 enable ? lc->video_conf.device : nowebcam);
929 call->camera_active=enable;
934 * Take a photo of currently received video and write it into a jpeg file.
936 int linphone_call_take_video_snapshot(LinphoneCall *call, const char *file){
938 if (call->videostream!=NULL && call->videostream->jpegwriter!=NULL){
939 return ms_filter_call_method(call->videostream->jpegwriter,MS_JPEG_WRITER_TAKE_SNAPSHOT,(void*)file);
941 ms_warning("Cannot take snapshot: no currently running video stream on this call.");
948 * Returns TRUE if camera pictures are sent to the remote party.
950 bool_t linphone_call_camera_enabled (const LinphoneCall *call){
951 return call->camera_active;
955 * Enable video stream.
957 void linphone_call_params_enable_video(LinphoneCallParams *cp, bool_t enabled){
958 cp->has_video=enabled;
961 const PayloadType* linphone_call_params_get_used_audio_codec(const LinphoneCallParams *cp) {
962 return cp->audio_codec;
965 const PayloadType* linphone_call_params_get_used_video_codec(const LinphoneCallParams *cp) {
966 return cp->video_codec;
970 * @ingroup call_control
971 * Use to know if this call has been configured in low bandwidth mode.
972 * This mode can be automatically discovered thanks to a stun server when activate_edge_workarounds=1 in section [net] of configuration file.
973 * An application that would have reliable way to know network capacity may not use activate_edge_workarounds=1 but instead manually configure
974 * low bandwidth mode with linphone_call_params_enable_low_bandwidth().
975 * <br> When enabled, this param may transform a call request with video in audio only mode.
976 * @return TRUE if low bandwidth has been configured/detected
978 bool_t linphone_call_params_low_bandwidth_enabled(const LinphoneCallParams *cp) {
979 return cp->low_bandwidth;
983 * @ingroup call_control
984 * Indicate low bandwith mode.
985 * 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
986 * 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
987 * that it is achievable by the codec selected after SDP handshake. Video is automatically disabled.
990 void linphone_call_params_enable_low_bandwidth(LinphoneCallParams *cp, bool_t enabled){
991 cp->low_bandwidth=enabled;
995 * Returns whether video is enabled.
997 bool_t linphone_call_params_video_enabled(const LinphoneCallParams *cp){
998 return cp->has_video;
1001 enum LinphoneMediaEncryption linphone_call_params_get_media_encryption(const LinphoneCallParams *cp) {
1002 return cp->media_encryption;
1005 void linphone_call_params_set_media_encryption(LinphoneCallParams *cp, enum LinphoneMediaEncryption e) {
1006 cp->media_encryption = e;
1011 * Enable sending of real early media (during outgoing calls).
1013 void linphone_call_params_enable_early_media_sending(LinphoneCallParams *cp, bool_t enabled){
1014 cp->real_early_media=enabled;
1017 bool_t linphone_call_params_early_media_sending_enabled(const LinphoneCallParams *cp){
1018 return cp->real_early_media;
1022 * Returns true if the call is part of the locally managed conference.
1024 bool_t linphone_call_params_local_conference_mode(const LinphoneCallParams *cp){
1025 return cp->in_conference;
1029 * Refine bandwidth settings for this call by setting a bandwidth limit for audio streams.
1030 * As a consequence, codecs whose bitrates are not compatible with this limit won't be used.
1032 void linphone_call_params_set_audio_bandwidth_limit(LinphoneCallParams *cp, int bandwidth){
1033 cp->audio_bw=bandwidth;
1036 #ifdef VIDEO_ENABLED
1038 * Request remote side to send us a Video Fast Update.
1040 void linphone_call_send_vfu_request(LinphoneCall *call)
1042 if (LinphoneCallStreamsRunning == linphone_call_get_state(call))
1043 sal_call_send_vfu_request(call->op);
1050 LinphoneCallParams * linphone_call_params_copy(const LinphoneCallParams *cp){
1051 LinphoneCallParams *ncp=ms_new0(LinphoneCallParams,1);
1052 memcpy(ncp,cp,sizeof(LinphoneCallParams));
1059 void linphone_call_params_destroy(LinphoneCallParams *p){
1068 #ifdef TEST_EXT_RENDERER
1069 static void rendercb(void *data, const MSPicture *local, const MSPicture *remote){
1070 ms_message("rendercb, local buffer=%p, remote buffer=%p",
1071 local ? local->planes[0] : NULL, remote? remote->planes[0] : NULL);
1075 #ifdef VIDEO_ENABLED
1076 static void video_stream_event_cb(void *user_pointer, const MSFilter *f, const unsigned int event_id, const void *args){
1077 LinphoneCall* call = (LinphoneCall*) user_pointer;
1078 ms_warning("In linphonecall.c: video_stream_event_cb");
1080 case MS_VIDEO_DECODER_DECODING_ERRORS:
1081 ms_warning("Case is MS_VIDEO_DECODER_DECODING_ERRORS");
1082 linphone_call_send_vfu_request(call);
1084 case MS_VIDEO_DECODER_FIRST_IMAGE_DECODED:
1085 ms_message("First video frame decoded successfully");
1086 if (call->nextVideoFrameDecoded._func != NULL)
1087 call->nextVideoFrameDecoded._func(call, call->nextVideoFrameDecoded._user_data);
1090 ms_warning("Unhandled event %i", event_id);
1096 void linphone_call_set_next_video_frame_decoded_callback(LinphoneCall *call, LinphoneCallCbFunc cb, void* user_data) {
1097 call->nextVideoFrameDecoded._func = cb;
1098 call->nextVideoFrameDecoded._user_data = user_data;
1099 #ifdef VIDEO_ENABLED
1100 ms_filter_call_method_noarg(call->videostream->ms.decoder, MS_VIDEO_DECODER_RESET_FIRST_IMAGE_NOTIFICATION);
1104 void linphone_call_init_audio_stream(LinphoneCall *call){
1105 LinphoneCore *lc=call->core;
1106 AudioStream *audiostream;
1109 if (call->audiostream != NULL) return;
1110 call->audiostream=audiostream=audio_stream_new(call->audio_port,call->audio_port+1,linphone_core_ipv6_enabled(lc));
1111 dscp=linphone_core_get_audio_dscp(lc);
1113 audio_stream_set_dscp(audiostream,dscp);
1114 if (linphone_core_echo_limiter_enabled(lc)){
1115 const char *type=lp_config_get_string(lc->config,"sound","el_type","mic");
1116 if (strcasecmp(type,"mic")==0)
1117 audio_stream_enable_echo_limiter(audiostream,ELControlMic);
1118 else if (strcasecmp(type,"full")==0)
1119 audio_stream_enable_echo_limiter(audiostream,ELControlFull);
1121 audio_stream_enable_gain_control(audiostream,TRUE);
1122 if (linphone_core_echo_cancellation_enabled(lc)){
1123 int len,delay,framesize;
1124 const char *statestr=lp_config_get_string(lc->config,"sound","ec_state",NULL);
1125 len=lp_config_get_int(lc->config,"sound","ec_tail_len",0);
1126 delay=lp_config_get_int(lc->config,"sound","ec_delay",0);
1127 framesize=lp_config_get_int(lc->config,"sound","ec_framesize",0);
1128 audio_stream_set_echo_canceller_params(audiostream,len,delay,framesize);
1129 if (statestr && audiostream->ec){
1130 ms_filter_call_method(audiostream->ec,MS_ECHO_CANCELLER_SET_STATE_STRING,(void*)statestr);
1133 audio_stream_enable_automatic_gain_control(audiostream,linphone_core_agc_enabled(lc));
1135 int enabled=lp_config_get_int(lc->config,"sound","noisegate",0);
1136 audio_stream_enable_noise_gate(audiostream,enabled);
1139 audio_stream_set_features(audiostream,linphone_core_get_audio_features(lc));
1142 RtpTransport *artp=lc->rtptf->audio_rtp_func(lc->rtptf->audio_rtp_func_data, call->audio_port);
1143 RtpTransport *artcp=lc->rtptf->audio_rtcp_func(lc->rtptf->audio_rtcp_func_data, call->audio_port+1);
1144 rtp_session_set_transports(audiostream->ms.session,artp,artcp);
1146 if ((linphone_core_get_firewall_policy(lc) == LinphonePolicyUseIce) && (call->ice_session != NULL)){
1147 rtp_session_set_pktinfo(audiostream->ms.session, TRUE);
1148 rtp_session_set_symmetric_rtp(audiostream->ms.session, FALSE);
1149 if (ice_session_check_list(call->ice_session, 0) == NULL) {
1150 ice_session_add_check_list(call->ice_session, ice_check_list_new());
1152 audiostream->ms.ice_check_list = ice_session_check_list(call->ice_session, 0);
1153 ice_check_list_set_rtp_session(audiostream->ms.ice_check_list, audiostream->ms.session);
1156 call->audiostream_app_evq = ortp_ev_queue_new();
1157 rtp_session_register_event_queue(audiostream->ms.session,call->audiostream_app_evq);
1160 void linphone_call_init_video_stream(LinphoneCall *call){
1161 #ifdef VIDEO_ENABLED
1162 LinphoneCore *lc=call->core;
1164 if (!call->params.has_video) {
1165 linphone_call_stop_video_stream(call);
1168 if (call->videostream != NULL) return;
1169 if ((lc->video_conf.display || lc->video_conf.capture) && call->params.has_video){
1170 int video_recv_buf_size=lp_config_get_int(lc->config,"video","recv_buf_size",0);
1171 int dscp=linphone_core_get_video_dscp(lc);
1173 call->videostream=video_stream_new(call->video_port,call->video_port+1,linphone_core_ipv6_enabled(lc));
1175 video_stream_set_dscp(call->videostream,dscp);
1176 video_stream_enable_display_filter_auto_rotate(call->videostream, lp_config_get_int(lc->config,"video","display_filter_auto_rotate",0));
1177 if (video_recv_buf_size>0) rtp_session_set_recv_buf_size(call->videostream->ms.session,video_recv_buf_size);
1179 if( lc->video_conf.displaytype != NULL)
1180 video_stream_set_display_filter_name(call->videostream,lc->video_conf.displaytype);
1181 video_stream_set_event_callback(call->videostream,video_stream_event_cb, call);
1183 RtpTransport *vrtp=lc->rtptf->video_rtp_func(lc->rtptf->video_rtp_func_data, call->video_port);
1184 RtpTransport *vrtcp=lc->rtptf->video_rtcp_func(lc->rtptf->video_rtcp_func_data, call->video_port+1);
1185 rtp_session_set_transports(call->videostream->ms.session,vrtp,vrtcp);
1187 if ((linphone_core_get_firewall_policy(lc) == LinphonePolicyUseIce) && (call->ice_session != NULL)){
1188 rtp_session_set_pktinfo(call->videostream->ms.session, TRUE);
1189 rtp_session_set_symmetric_rtp(call->videostream->ms.session, FALSE);
1190 if (ice_session_check_list(call->ice_session, 1) == NULL) {
1191 ice_session_add_check_list(call->ice_session, ice_check_list_new());
1193 call->videostream->ms.ice_check_list = ice_session_check_list(call->ice_session, 1);
1194 ice_check_list_set_rtp_session(call->videostream->ms.ice_check_list, call->videostream->ms.session);
1196 call->videostream_app_evq = ortp_ev_queue_new();
1197 rtp_session_register_event_queue(call->videostream->ms.session,call->videostream_app_evq);
1198 #ifdef TEST_EXT_RENDERER
1199 video_stream_set_render_callback(call->videostream,rendercb,NULL);
1203 call->videostream=NULL;
1207 void linphone_call_init_media_streams(LinphoneCall *call){
1208 linphone_call_init_audio_stream(call);
1209 linphone_call_init_video_stream(call);
1213 static int dtmf_tab[16]={'0','1','2','3','4','5','6','7','8','9','*','#','A','B','C','D'};
1215 static void linphone_core_dtmf_received(LinphoneCore *lc, int dtmf){
1216 if (dtmf<0 || dtmf>15){
1217 ms_warning("Bad dtmf value %i",dtmf);
1220 if (lc->vtable.dtmf_received != NULL)
1221 lc->vtable.dtmf_received(lc, linphone_core_get_current_call(lc), dtmf_tab[dtmf]);
1224 static void parametrize_equalizer(LinphoneCore *lc, AudioStream *st){
1226 MSFilter *f=st->equalizer;
1227 int enabled=lp_config_get_int(lc->config,"sound","eq_active",0);
1228 const char *gains=lp_config_get_string(lc->config,"sound","eq_gains",NULL);
1229 ms_filter_call_method(f,MS_EQUALIZER_SET_ACTIVE,&enabled);
1235 if (sscanf(gains,"%f:%f:%f %n",&g.frequency,&g.gain,&g.width,&bytes)==3){
1236 ms_message("Read equalizer gains: %f(~%f) --> %f",g.frequency,g.width,g.gain);
1237 ms_filter_call_method(f,MS_EQUALIZER_SET_GAIN,&g);
1246 void _post_configure_audio_stream(AudioStream *st, LinphoneCore *lc, bool_t muted){
1247 float mic_gain=lc->sound_conf.soft_mic_lev;
1250 float ng_thres=lp_config_get_float(lc->config,"sound","ng_thres",0.05);
1251 float ng_floorgain=lp_config_get_float(lc->config,"sound","ng_floorgain",0);
1252 int dc_removal=lp_config_get_int(lc->config,"sound","dc_removal",0);
1255 linphone_core_set_mic_gain_db (lc, mic_gain);
1257 audio_stream_set_mic_gain(st,0);
1259 recv_gain = lc->sound_conf.soft_play_lev;
1260 if (recv_gain != 0) {
1261 linphone_core_set_playback_gain_db (lc,recv_gain);
1265 ms_filter_call_method(st->volsend,MS_VOLUME_REMOVE_DC,&dc_removal);
1266 float speed=lp_config_get_float(lc->config,"sound","el_speed",-1);
1267 thres=lp_config_get_float(lc->config,"sound","el_thres",-1);
1268 float force=lp_config_get_float(lc->config,"sound","el_force",-1);
1269 int sustain=lp_config_get_int(lc->config,"sound","el_sustain",-1);
1270 float transmit_thres=lp_config_get_float(lc->config,"sound","el_transmit_thres",-1);
1273 if (speed==-1) speed=0.03;
1274 if (force==-1) force=25;
1275 ms_filter_call_method(f,MS_VOLUME_SET_EA_SPEED,&speed);
1276 ms_filter_call_method(f,MS_VOLUME_SET_EA_FORCE,&force);
1278 ms_filter_call_method(f,MS_VOLUME_SET_EA_THRESHOLD,&thres);
1280 ms_filter_call_method(f,MS_VOLUME_SET_EA_SUSTAIN,&sustain);
1281 if (transmit_thres!=-1)
1282 ms_filter_call_method(f,MS_VOLUME_SET_EA_TRANSMIT_THRESHOLD,&transmit_thres);
1284 ms_filter_call_method(st->volsend,MS_VOLUME_SET_NOISE_GATE_THRESHOLD,&ng_thres);
1285 ms_filter_call_method(st->volsend,MS_VOLUME_SET_NOISE_GATE_FLOORGAIN,&ng_floorgain);
1288 /* parameters for a limited noise-gate effect, using echo limiter threshold */
1289 float floorgain = 1/pow(10,(mic_gain)/10);
1290 int spk_agc=lp_config_get_int(lc->config,"sound","speaker_agc_enabled",0);
1291 ms_filter_call_method(st->volrecv, MS_VOLUME_ENABLE_AGC, &spk_agc);
1292 ms_filter_call_method(st->volrecv,MS_VOLUME_SET_NOISE_GATE_THRESHOLD,&ng_thres);
1293 ms_filter_call_method(st->volrecv,MS_VOLUME_SET_NOISE_GATE_FLOORGAIN,&floorgain);
1295 parametrize_equalizer(lc,st);
1298 static void post_configure_audio_streams(LinphoneCall*call){
1299 AudioStream *st=call->audiostream;
1300 LinphoneCore *lc=call->core;
1301 _post_configure_audio_stream(st,lc,call->audio_muted);
1302 if (lc->vtable.dtmf_received!=NULL){
1303 /* replace by our default action*/
1304 audio_stream_play_received_dtmfs(call->audiostream,FALSE);
1305 /*rtp_session_signal_connect(call->audiostream->session,"telephone-event",(RtpCallback)linphone_core_dtmf_received,(unsigned long)lc);*/
1309 static RtpProfile *make_profile(LinphoneCall *call, const SalMediaDescription *md, const SalStreamDescription *desc, int *used_pt){
1312 RtpProfile *prof=rtp_profile_new("Call profile");
1315 LinphoneCore *lc=call->core;
1317 const LinphoneCallParams *params=&call->params;
1320 for(elem=desc->payloads;elem!=NULL;elem=elem->next){
1321 PayloadType *pt=(PayloadType*)elem->data;
1324 if ((pt->flags & PAYLOAD_TYPE_FLAG_CAN_SEND) && first) {
1325 if (desc->type==SalAudio){
1326 linphone_core_update_allocated_audio_bandwidth_in_call(call,pt);
1327 if (params->up_ptime)
1328 up_ptime=params->up_ptime;
1329 else up_ptime=linphone_core_get_upload_ptime(lc);
1331 *used_pt=payload_type_get_number(pt);
1334 if (desc->bandwidth>0) remote_bw=desc->bandwidth;
1335 else if (md->bandwidth>0) {
1336 /*case where b=AS is given globally, not per stream*/
1337 remote_bw=md->bandwidth;
1338 if (desc->type==SalVideo){
1339 remote_bw=get_video_bandwidth(remote_bw,call->audio_bw);
1343 if (desc->type==SalAudio){
1344 int audio_bw=call->audio_bw;
1346 if (params->up_bw< audio_bw)
1347 audio_bw=params->up_bw;
1349 bw=get_min_bandwidth(audio_bw,remote_bw);
1350 }else bw=get_min_bandwidth(get_video_bandwidth(linphone_core_get_upload_bandwidth (lc),call->audio_bw),remote_bw);
1351 if (bw>0) pt->normal_bitrate=bw*1000;
1352 else if (desc->type==SalAudio){
1353 pt->normal_bitrate=-1;
1356 up_ptime=desc->ptime;
1360 snprintf(tmp,sizeof(tmp),"ptime=%i",up_ptime);
1361 payload_type_append_send_fmtp(pt,tmp);
1363 number=payload_type_get_number(pt);
1364 if (rtp_profile_get_payload(prof,number)!=NULL){
1365 ms_warning("A payload type with number %i already exists in profile !",number);
1367 rtp_profile_set_payload(prof,number,pt);
1373 static void setup_ring_player(LinphoneCore *lc, LinphoneCall *call){
1374 int pause_time=3000;
1375 audio_stream_play(call->audiostream,lc->sound_conf.ringback_tone);
1376 ms_filter_call_method(call->audiostream->soundread,MS_FILE_PLAYER_LOOP,&pause_time);
1379 static bool_t linphone_call_sound_resources_available(LinphoneCall *call){
1380 LinphoneCore *lc=call->core;
1381 LinphoneCall *current=linphone_core_get_current_call(lc);
1382 return !linphone_core_is_in_conference(lc) &&
1383 (current==NULL || current==call);
1385 static int find_crypto_index_from_tag(const SalSrtpCryptoAlgo crypto[],unsigned char tag) {
1387 for(i=0; i<SAL_CRYPTO_ALGO_MAX; i++) {
1388 if (crypto[i].tag == tag) {
1394 static void linphone_call_start_audio_stream(LinphoneCall *call, const char *cname, bool_t muted, bool_t send_ringbacktone, bool_t use_arc){
1395 LinphoneCore *lc=call->core;
1397 char rtcp_tool[128]={0};
1398 snprintf(rtcp_tool,sizeof(rtcp_tool)-1,"%s-%s",linphone_core_get_user_agent_name(),linphone_core_get_user_agent_version());
1399 /* look for savp stream first */
1400 const SalStreamDescription *stream=sal_media_description_find_stream(call->resultdesc,
1401 SalProtoRtpSavp,SalAudio);
1402 /* no savp audio stream, use avp */
1404 stream=sal_media_description_find_stream(call->resultdesc,
1405 SalProtoRtpAvp,SalAudio);
1407 if (stream && stream->dir!=SalStreamInactive && stream->rtp_port!=0){
1408 MSSndCard *playcard=lc->sound_conf.lsd_card ?
1409 lc->sound_conf.lsd_card : lc->sound_conf.play_sndcard;
1410 MSSndCard *captcard=lc->sound_conf.capt_sndcard;
1411 const char *playfile=lc->play_file;
1412 const char *recfile=lc->rec_file;
1413 call->audio_profile=make_profile(call,call->resultdesc,stream,&used_pt);
1417 call->current_params.audio_codec = rtp_profile_get_payload(call->audio_profile, used_pt);
1418 if (playcard==NULL) {
1419 ms_warning("No card defined for playback !");
1421 if (captcard==NULL) {
1422 ms_warning("No card defined for capture !");
1424 /*Replace soundcard filters by inactive file players or recorders
1425 when placed in recvonly or sendonly mode*/
1426 if (stream->rtp_port==0 || stream->dir==SalStreamRecvOnly){
1429 }else if (stream->dir==SalStreamSendOnly){
1433 /*And we will eventually play "playfile" if set by the user*/
1436 if (send_ringbacktone){
1438 playfile=NULL;/* it is setup later*/
1440 /*if playfile are supplied don't use soundcards*/
1441 if (lc->use_files) {
1445 if (call->params.in_conference){
1446 /* first create the graph without soundcard resources*/
1447 captcard=playcard=NULL;
1449 if (!linphone_call_sound_resources_available(call)){
1450 ms_message("Sound resources are used by another call, not using soundcard.");
1451 captcard=playcard=NULL;
1453 use_ec=captcard==NULL ? FALSE : linphone_core_echo_cancellation_enabled(lc);
1454 if (playcard && stream->max_rate>0) ms_snd_card_set_preferred_sample_rate(playcard, stream->max_rate);
1455 if (captcard && stream->max_rate>0) ms_snd_card_set_preferred_sample_rate(captcard, stream->max_rate);
1456 audio_stream_enable_adaptive_bitrate_control(call->audiostream,use_arc);
1457 audio_stream_enable_adaptive_jittcomp(call->audiostream, linphone_core_audio_adaptive_jittcomp_enabled(lc));
1458 audio_stream_start_full(
1460 call->audio_profile,
1461 stream->rtp_addr[0]!='\0' ? stream->rtp_addr : call->resultdesc->addr,
1463 stream->rtcp_addr[0]!='\0' ? stream->rtcp_addr : call->resultdesc->addr,
1464 linphone_core_rtcp_enabled(lc) ? (stream->rtcp_port) : 0,
1466 linphone_core_get_audio_jittcomp(lc),
1473 post_configure_audio_streams(call);
1474 if (muted && !send_ringbacktone){
1475 audio_stream_set_mic_gain(call->audiostream,0);
1477 if (stream->dir==SalStreamSendOnly && playfile!=NULL){
1479 ms_filter_call_method(call->audiostream->soundread,MS_FILE_PLAYER_LOOP,&pause_time);
1481 if (send_ringbacktone){
1482 setup_ring_player(lc,call);
1484 audio_stream_set_rtcp_information(call->audiostream, cname, rtcp_tool);
1486 /* valid local tags are > 0 */
1487 if (stream->proto == SalProtoRtpSavp) {
1488 const SalStreamDescription *local_st_desc=sal_media_description_find_stream(call->localdesc,
1489 SalProtoRtpSavp,SalAudio);
1490 int crypto_idx = find_crypto_index_from_tag(local_st_desc->crypto, stream->crypto_local_tag);
1492 if (crypto_idx >= 0) {
1493 audio_stream_enable_srtp(
1495 stream->crypto[0].algo,
1496 local_st_desc->crypto[crypto_idx].master_key,
1497 stream->crypto[0].master_key);
1498 call->audiostream_encrypted=TRUE;
1500 ms_warning("Failed to find local crypto algo with tag: %d", stream->crypto_local_tag);
1501 call->audiostream_encrypted=FALSE;
1503 }else call->audiostream_encrypted=FALSE;
1504 if (call->params.in_conference){
1505 /*transform the graph to connect it to the conference filter */
1506 bool_t mute=stream->dir==SalStreamRecvOnly;
1507 linphone_call_add_to_conf(call, mute);
1509 call->current_params.in_conference=call->params.in_conference;
1510 call->current_params.low_bandwidth=call->params.low_bandwidth;
1511 }else ms_warning("No audio stream accepted ?");
1515 static void linphone_call_start_video_stream(LinphoneCall *call, const char *cname,bool_t all_inputs_muted){
1516 #ifdef VIDEO_ENABLED
1517 LinphoneCore *lc=call->core;
1519 /* look for savp stream first */
1520 const SalStreamDescription *vstream=sal_media_description_find_stream(call->resultdesc,
1521 SalProtoRtpSavp,SalVideo);
1522 char rtcp_tool[128]={0};
1523 snprintf(rtcp_tool,sizeof(rtcp_tool)-1,"%s-%s",linphone_core_get_user_agent_name(),linphone_core_get_user_agent_version());
1525 /* no savp audio stream, use avp */
1527 vstream=sal_media_description_find_stream(call->resultdesc,
1528 SalProtoRtpAvp,SalVideo);
1530 /* shutdown preview */
1531 if (lc->previewstream!=NULL) {
1532 video_preview_stop(lc->previewstream);
1533 lc->previewstream=NULL;
1536 if (vstream!=NULL && vstream->dir!=SalStreamInactive && vstream->rtp_port!=0) {
1537 const char *rtp_addr=vstream->rtp_addr[0]!='\0' ? vstream->rtp_addr : call->resultdesc->addr;
1538 const char *rtcp_addr=vstream->rtcp_addr[0]!='\0' ? vstream->rtcp_addr : call->resultdesc->addr;
1539 call->video_profile=make_profile(call,call->resultdesc,vstream,&used_pt);
1541 call->current_params.video_codec = rtp_profile_get_payload(call->video_profile, used_pt);
1542 VideoStreamDir dir=VideoStreamSendRecv;
1543 MSWebCam *cam=lc->video_conf.device;
1544 bool_t is_inactive=FALSE;
1546 call->current_params.has_video=TRUE;
1548 video_stream_enable_adaptive_bitrate_control(call->videostream,
1549 linphone_core_adaptive_rate_control_enabled(lc));
1550 video_stream_enable_adaptive_jittcomp(call->videostream, linphone_core_video_adaptive_jittcomp_enabled(lc));
1551 video_stream_set_sent_video_size(call->videostream,linphone_core_get_preferred_video_size(lc));
1552 video_stream_enable_self_view(call->videostream,lc->video_conf.selfview);
1553 if (lc->video_window_id!=0)
1554 video_stream_set_native_window_id(call->videostream,lc->video_window_id);
1555 if (lc->preview_window_id!=0)
1556 video_stream_set_native_preview_window_id (call->videostream,lc->preview_window_id);
1557 video_stream_use_preview_video_window (call->videostream,lc->use_preview_window);
1559 if (vstream->dir==SalStreamSendOnly && lc->video_conf.capture ){
1560 cam=get_nowebcam_device();
1561 dir=VideoStreamSendOnly;
1562 }else if (vstream->dir==SalStreamRecvOnly && lc->video_conf.display ){
1563 dir=VideoStreamRecvOnly;
1564 }else if (vstream->dir==SalStreamSendRecv){
1565 if (lc->video_conf.display && lc->video_conf.capture)
1566 dir=VideoStreamSendRecv;
1567 else if (lc->video_conf.display)
1568 dir=VideoStreamRecvOnly;
1570 dir=VideoStreamSendOnly;
1572 ms_warning("video stream is inactive.");
1573 /*either inactive or incompatible with local capabilities*/
1576 if (call->camera_active==FALSE || all_inputs_muted){
1577 cam=get_nowebcam_device();
1580 call->log->video_enabled = TRUE;
1581 video_stream_set_direction (call->videostream, dir);
1582 ms_message("%s lc rotation:%d\n", __FUNCTION__, lc->device_rotation);
1583 video_stream_set_device_rotation(call->videostream, lc->device_rotation);
1584 video_stream_start(call->videostream,
1585 call->video_profile, rtp_addr, vstream->rtp_port,
1586 rtcp_addr, linphone_core_rtcp_enabled(lc) ? (vstream->rtcp_port) : 0,
1587 used_pt, linphone_core_get_video_jittcomp(lc), cam);
1588 video_stream_set_rtcp_information(call->videostream, cname,rtcp_tool);
1591 if (vstream->proto == SalProtoRtpSavp) {
1592 const SalStreamDescription *local_st_desc=sal_media_description_find_stream(call->localdesc,
1593 SalProtoRtpSavp,SalVideo);
1595 video_stream_enable_strp(
1597 vstream->crypto[0].algo,
1598 local_st_desc->crypto[0].master_key,
1599 vstream->crypto[0].master_key
1601 call->videostream_encrypted=TRUE;
1603 call->videostream_encrypted=FALSE;
1605 }else ms_warning("No video stream accepted.");
1607 ms_warning("No valid video stream defined.");
1612 void linphone_call_start_media_streams(LinphoneCall *call, bool_t all_inputs_muted, bool_t send_ringbacktone){
1613 LinphoneCore *lc=call->core;
1615 call->current_params.audio_codec = NULL;
1616 call->current_params.video_codec = NULL;
1618 LinphoneAddress *me=linphone_core_get_primary_contact_parsed(lc);
1620 bool_t use_arc=linphone_core_adaptive_rate_control_enabled(lc);
1621 #ifdef VIDEO_ENABLED
1622 const SalStreamDescription *vstream=sal_media_description_find_stream(call->resultdesc,
1623 SalProtoRtpAvp,SalVideo);
1626 if ((call->audiostream == NULL) && (call->videostream == NULL)) {
1627 ms_fatal("start_media_stream() called without prior init !");
1630 cname=linphone_address_as_string_uri_only(me);
1632 #if defined(VIDEO_ENABLED)
1633 if (vstream!=NULL && vstream->dir!=SalStreamInactive && vstream->payloads!=NULL){
1634 /*when video is used, do not make adaptive rate control on audio, it is stupid.*/
1638 if (call->audiostream!=NULL) {
1639 linphone_call_start_audio_stream(call,cname,all_inputs_muted,send_ringbacktone,use_arc);
1641 call->current_params.has_video=FALSE;
1642 if (call->videostream!=NULL) {
1643 linphone_call_start_video_stream(call,cname,all_inputs_muted);
1646 call->all_muted=all_inputs_muted;
1647 call->playing_ringbacktone=send_ringbacktone;
1648 call->up_bw=linphone_core_get_upload_bandwidth(lc);
1650 if (call->params.media_encryption==LinphoneMediaEncryptionZRTP) {
1651 OrtpZrtpParams params;
1652 /*will be set later when zrtp is activated*/
1653 call->current_params.media_encryption=LinphoneMediaEncryptionNone;
1655 params.zid_file=lc->zrtp_secrets_cache;
1656 audio_stream_enable_zrtp(call->audiostream,¶ms);
1657 }else if (call->params.media_encryption==LinphoneMediaEncryptionSRTP){
1658 call->current_params.media_encryption=linphone_call_are_all_streams_encrypted(call) ?
1659 LinphoneMediaEncryptionSRTP : LinphoneMediaEncryptionNone;
1662 /*also reflect the change if the "wished" params, in order to avoid to propose SAVP or video again
1663 * further in the call, for example during pause,resume, conferencing reINVITEs*/
1664 linphone_call_fix_call_parameters(call);
1665 if ((call->ice_session != NULL) && (ice_session_state(call->ice_session) != IS_Completed)) {
1666 ice_session_start_connectivity_checks(call->ice_session);
1672 linphone_address_destroy(me);
1675 void linphone_call_start_media_streams_for_ice_gathering(LinphoneCall *call){
1676 audio_stream_prepare_sound(call->audiostream, NULL, NULL);
1677 #ifdef VIDEO_ENABLED
1678 if (call->videostream) {
1679 video_stream_prepare_video(call->videostream);
1684 void linphone_call_stop_media_streams_for_ice_gathering(LinphoneCall *call){
1685 audio_stream_unprepare_sound(call->audiostream);
1686 #ifdef VIDEO_ENABLED
1687 if (call->videostream) {
1688 video_stream_unprepare_video(call->videostream);
1693 void linphone_call_update_crypto_parameters(LinphoneCall *call, SalMediaDescription *old_md, SalMediaDescription *new_md) {
1694 SalStreamDescription *old_stream;
1695 SalStreamDescription *new_stream;
1698 old_stream = sal_media_description_find_stream(old_md, SalProtoRtpSavp, SalAudio);
1699 new_stream = sal_media_description_find_stream(new_md, SalProtoRtpSavp, SalAudio);
1700 if (old_stream && new_stream) {
1701 const SalStreamDescription *local_st_desc = sal_media_description_find_stream(call->localdesc, SalProtoRtpSavp, SalAudio);
1702 int crypto_idx = find_crypto_index_from_tag(local_st_desc->crypto, new_stream->crypto_local_tag);
1703 if (crypto_idx >= 0) {
1704 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);
1705 call->audiostream_encrypted = TRUE;
1707 ms_warning("Failed to find local crypto algo with tag: %d", new_stream->crypto_local_tag);
1708 call->audiostream_encrypted = FALSE;
1710 for (i = 0; i < SAL_CRYPTO_ALGO_MAX; i++) {
1711 old_stream->crypto[i].tag = new_stream->crypto[i].tag;
1712 old_stream->crypto[i].algo = new_stream->crypto[i].algo;
1713 strncpy(old_stream->crypto[i].master_key, new_stream->crypto[i].master_key, sizeof(old_stream->crypto[i].master_key) - 1);
1717 #ifdef VIDEO_ENABLED
1718 old_stream = sal_media_description_find_stream(old_md, SalProtoRtpSavp, SalVideo);
1719 new_stream = sal_media_description_find_stream(new_md, SalProtoRtpSavp, SalVideo);
1720 if (old_stream && new_stream) {
1721 const SalStreamDescription *local_st_desc = sal_media_description_find_stream(call->localdesc, SalProtoRtpSavp, SalVideo);
1722 int crypto_idx = find_crypto_index_from_tag(local_st_desc->crypto, new_stream->crypto_local_tag);
1723 if (crypto_idx >= 0) {
1724 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);
1725 call->videostream_encrypted = TRUE;
1727 ms_warning("Failed to find local crypto algo with tag: %d", new_stream->crypto_local_tag);
1728 call->videostream_encrypted = FALSE;
1730 for (i = 0; i < SAL_CRYPTO_ALGO_MAX; i++) {
1731 old_stream->crypto[i].tag = new_stream->crypto[i].tag;
1732 old_stream->crypto[i].algo = new_stream->crypto[i].algo;
1733 strncpy(old_stream->crypto[i].master_key, new_stream->crypto[i].master_key, sizeof(old_stream->crypto[i].master_key) - 1);
1739 void linphone_call_delete_ice_session(LinphoneCall *call){
1740 if (call->ice_session != NULL) {
1741 ice_session_destroy(call->ice_session);
1742 call->ice_session = NULL;
1743 if (call->audiostream != NULL) call->audiostream->ms.ice_check_list = NULL;
1744 if (call->videostream != NULL) call->videostream->ms.ice_check_list = NULL;
1745 call->stats[LINPHONE_CALL_STATS_AUDIO].ice_state = LinphoneIceStateNotActivated;
1746 call->stats[LINPHONE_CALL_STATS_VIDEO].ice_state = LinphoneIceStateNotActivated;
1751 void linphone_call_delete_upnp_session(LinphoneCall *call){
1752 if(call->upnp_session!=NULL) {
1753 linphone_upnp_session_destroy(call->upnp_session);
1754 call->upnp_session=NULL;
1759 static void linphone_call_log_fill_stats(LinphoneCallLog *log, AudioStream *st){
1760 audio_stream_get_local_rtp_stats (st,&log->local_stats);
1761 log->quality=audio_stream_get_average_quality_rating(st);
1764 void linphone_call_stop_audio_stream(LinphoneCall *call) {
1765 if (call->audiostream!=NULL) {
1766 rtp_session_unregister_event_queue(call->audiostream->ms.session,call->audiostream_app_evq);
1767 ortp_ev_queue_flush(call->audiostream_app_evq);
1768 ortp_ev_queue_destroy(call->audiostream_app_evq);
1769 call->audiostream_app_evq=NULL;
1771 if (call->audiostream->ec){
1772 const char *state_str=NULL;
1773 ms_filter_call_method(call->audiostream->ec,MS_ECHO_CANCELLER_GET_STATE_STRING,&state_str);
1775 ms_message("Writing echo canceler state, %i bytes",(int)strlen(state_str));
1776 lp_config_set_string(call->core->config,"sound","ec_state",state_str);
1779 linphone_call_log_fill_stats (call->log,call->audiostream);
1780 if (call->endpoint){
1781 linphone_call_remove_from_conf(call);
1783 audio_stream_stop(call->audiostream);
1784 call->audiostream=NULL;
1788 void linphone_call_stop_video_stream(LinphoneCall *call) {
1789 #ifdef VIDEO_ENABLED
1790 if (call->videostream!=NULL){
1791 rtp_session_unregister_event_queue(call->videostream->ms.session,call->videostream_app_evq);
1792 ortp_ev_queue_flush(call->videostream_app_evq);
1793 ortp_ev_queue_destroy(call->videostream_app_evq);
1794 call->videostream_app_evq=NULL;
1795 video_stream_stop(call->videostream);
1796 call->videostream=NULL;
1801 void linphone_call_stop_media_streams(LinphoneCall *call){
1802 linphone_call_stop_audio_stream(call);
1803 linphone_call_stop_video_stream(call);
1804 ms_event_queue_skip(call->core->msevq);
1806 if (call->audio_profile){
1807 rtp_profile_clear_all(call->audio_profile);
1808 rtp_profile_destroy(call->audio_profile);
1809 call->audio_profile=NULL;
1811 if (call->video_profile){
1812 rtp_profile_clear_all(call->video_profile);
1813 rtp_profile_destroy(call->video_profile);
1814 call->video_profile=NULL;
1820 void linphone_call_enable_echo_cancellation(LinphoneCall *call, bool_t enable) {
1821 if (call!=NULL && call->audiostream!=NULL && call->audiostream->ec){
1822 bool_t bypass_mode = !enable;
1823 ms_filter_call_method(call->audiostream->ec,MS_ECHO_CANCELLER_SET_BYPASS_MODE,&bypass_mode);
1826 bool_t linphone_call_echo_cancellation_enabled(LinphoneCall *call) {
1827 if (call!=NULL && call->audiostream!=NULL && call->audiostream->ec){
1829 ms_filter_call_method(call->audiostream->ec,MS_ECHO_CANCELLER_GET_BYPASS_MODE,&val);
1832 return linphone_core_echo_cancellation_enabled(call->core);
1836 void linphone_call_enable_echo_limiter(LinphoneCall *call, bool_t val){
1837 if (call!=NULL && call->audiostream!=NULL ) {
1839 const char *type=lp_config_get_string(call->core->config,"sound","el_type","mic");
1840 if (strcasecmp(type,"mic")==0)
1841 audio_stream_enable_echo_limiter(call->audiostream,ELControlMic);
1842 else if (strcasecmp(type,"full")==0)
1843 audio_stream_enable_echo_limiter(call->audiostream,ELControlFull);
1845 audio_stream_enable_echo_limiter(call->audiostream,ELInactive);
1850 bool_t linphone_call_echo_limiter_enabled(const LinphoneCall *call){
1851 if (call!=NULL && call->audiostream!=NULL ){
1852 return call->audiostream->el_type !=ELInactive ;
1854 return linphone_core_echo_limiter_enabled(call->core);
1859 * @addtogroup call_misc
1864 * Returns the measured sound volume played locally (received from remote).
1865 * It is expressed in dbm0.
1867 float linphone_call_get_play_volume(LinphoneCall *call){
1868 AudioStream *st=call->audiostream;
1869 if (st && st->volrecv){
1871 ms_filter_call_method(st->volrecv,MS_VOLUME_GET,&vol);
1875 return LINPHONE_VOLUME_DB_LOWEST;
1879 * Returns the measured sound volume recorded locally (sent to remote).
1880 * It is expressed in dbm0.
1882 float linphone_call_get_record_volume(LinphoneCall *call){
1883 AudioStream *st=call->audiostream;
1884 if (st && st->volsend && !call->audio_muted && call->state==LinphoneCallStreamsRunning){
1886 ms_filter_call_method(st->volsend,MS_VOLUME_GET,&vol);
1890 return LINPHONE_VOLUME_DB_LOWEST;
1894 * Obtain real-time quality rating of the call
1896 * Based on local RTP statistics and RTCP feedback, a quality rating is computed and updated
1897 * during all the duration of the call. This function returns its value at the time of the function call.
1898 * It is expected that the rating is updated at least every 5 seconds or so.
1899 * The rating is a floating point number comprised between 0 and 5.
1901 * 4-5 = good quality <br>
1902 * 3-4 = average quality <br>
1903 * 2-3 = poor quality <br>
1904 * 1-2 = very poor quality <br>
1905 * 0-1 = can't be worse, mostly unusable <br>
1907 * @returns The function returns -1 if no quality measurement is available, for example if no
1908 * active audio stream exist. Otherwise it returns the quality rating.
1910 float linphone_call_get_current_quality(LinphoneCall *call){
1911 if (call->audiostream){
1912 return audio_stream_get_quality_rating(call->audiostream);
1918 * Returns call quality averaged over all the duration of the call.
1920 * See linphone_call_get_current_quality() for more details about quality measurement.
1922 float linphone_call_get_average_quality(LinphoneCall *call){
1923 if (call->audiostream){
1924 return audio_stream_get_average_quality_rating(call->audiostream);
1930 * Access last known statistics for audio stream, for a given call.
1932 const LinphoneCallStats *linphone_call_get_audio_stats(const LinphoneCall *call) {
1933 return &call->stats[LINPHONE_CALL_STATS_AUDIO];
1937 * Access last known statistics for video stream, for a given call.
1939 const LinphoneCallStats *linphone_call_get_video_stats(const LinphoneCall *call) {
1940 return &call->stats[LINPHONE_CALL_STATS_VIDEO];
1948 static void report_bandwidth(LinphoneCall *call, RtpSession *as, RtpSession *vs){
1949 call->stats[LINPHONE_CALL_STATS_AUDIO].download_bandwidth=(as!=NULL) ? (rtp_session_compute_recv_bandwidth(as)*1e-3) : 0;
1950 call->stats[LINPHONE_CALL_STATS_AUDIO].upload_bandwidth=(as!=NULL) ? (rtp_session_compute_send_bandwidth(as)*1e-3) : 0;
1951 call->stats[LINPHONE_CALL_STATS_VIDEO].download_bandwidth=(vs!=NULL) ? (rtp_session_compute_recv_bandwidth(vs)*1e-3) : 0;
1952 call->stats[LINPHONE_CALL_STATS_VIDEO].upload_bandwidth=(vs!=NULL) ? (rtp_session_compute_send_bandwidth(vs)*1e-3) : 0;
1953 ms_message("bandwidth usage: audio=[d=%.1f,u=%.1f] video=[d=%.1f,u=%.1f] kbit/sec",
1954 call->stats[LINPHONE_CALL_STATS_AUDIO].download_bandwidth,
1955 call->stats[LINPHONE_CALL_STATS_AUDIO].upload_bandwidth ,
1956 call->stats[LINPHONE_CALL_STATS_VIDEO].download_bandwidth,
1957 call->stats[LINPHONE_CALL_STATS_VIDEO].upload_bandwidth
1961 static void linphone_core_disconnected(LinphoneCore *lc, LinphoneCall *call){
1965 from = linphone_call_get_remote_address_as_string(call);
1968 snprintf(temp,sizeof(temp),"Remote end %s seems to have disconnected, the call is going to be closed.",from);
1973 snprintf(temp,sizeof(temp),"Remote end seems to have disconnected, the call is going to be closed.");
1975 if (lc->vtable.display_warning!=NULL)
1976 lc->vtable.display_warning(lc,temp);
1977 linphone_core_terminate_call(lc,call);
1980 static void handle_ice_events(LinphoneCall *call, OrtpEvent *ev){
1981 OrtpEventType evt=ortp_event_get_type(ev);
1982 OrtpEventData *evd=ortp_event_get_data(ev);
1985 if (evt == ORTP_EVENT_ICE_SESSION_PROCESSING_FINISHED) {
1986 switch (ice_session_state(call->ice_session)) {
1988 ice_session_select_candidates(call->ice_session);
1989 if (ice_session_role(call->ice_session) == IR_Controlling) {
1990 linphone_core_update_call(call->core, call, &call->current_params);
1994 if (ice_session_has_completed_check_list(call->ice_session) == TRUE) {
1995 ice_session_select_candidates(call->ice_session);
1996 if (ice_session_role(call->ice_session) == IR_Controlling) {
1997 /* At least one ICE session has succeeded, so perform a call update. */
1998 linphone_core_update_call(call->core, call, &call->current_params);
2005 linphone_core_update_ice_state_in_call_stats(call);
2006 } else if (evt == ORTP_EVENT_ICE_GATHERING_FINISHED) {
2008 if (evd->info.ice_processing_successful==TRUE) {
2009 ice_session_compute_candidates_foundations(call->ice_session);
2010 ice_session_eliminate_redundant_candidates(call->ice_session);
2011 ice_session_choose_default_candidates(call->ice_session);
2012 ping_time = ice_session_average_gathering_round_trip_time(call->ice_session);
2013 if (ping_time >=0) {
2014 call->ping_time=ping_time;
2017 ms_warning("No STUN answer from [%s], disabling ICE",linphone_core_get_stun_server(call->core));
2018 linphone_call_delete_ice_session(call);
2020 switch (call->state) {
2021 case LinphoneCallUpdating:
2022 linphone_core_start_update_call(call->core, call);
2024 case LinphoneCallUpdatedByRemote:
2025 linphone_core_start_accept_call_update(call->core, call);
2027 case LinphoneCallOutgoingInit:
2028 linphone_call_stop_media_streams_for_ice_gathering(call);
2029 linphone_core_proceed_with_invite_if_ready(call->core, call, NULL);
2031 case LinphoneCallIdle:
2032 linphone_call_stop_media_streams_for_ice_gathering(call);
2033 linphone_core_notify_incoming_call(call->core, call);
2038 } else if (evt == ORTP_EVENT_ICE_LOSING_PAIRS_COMPLETED) {
2039 linphone_core_start_accept_call_update(call->core, call);
2040 linphone_core_update_ice_state_in_call_stats(call);
2041 } else if (evt == ORTP_EVENT_ICE_RESTART_NEEDED) {
2042 ice_session_restart(call->ice_session);
2043 ice_session_set_role(call->ice_session, IR_Controlling);
2044 linphone_core_update_call(call->core, call, &call->current_params);
2048 void linphone_call_background_tasks(LinphoneCall *call, bool_t one_second_elapsed){
2049 LinphoneCore* lc = call->core;
2050 int disconnect_timeout = linphone_core_get_nortp_timeout(call->core);
2051 bool_t disconnected=FALSE;
2053 if (call->state==LinphoneCallStreamsRunning && one_second_elapsed){
2054 RtpSession *as=NULL,*vs=NULL;
2055 float audio_load=0, video_load=0;
2056 if (call->audiostream!=NULL){
2057 as=call->audiostream->ms.session;
2058 if (call->audiostream->ms.ticker)
2059 audio_load=ms_ticker_get_average_load(call->audiostream->ms.ticker);
2061 if (call->videostream!=NULL){
2062 if (call->videostream->ms.ticker)
2063 video_load=ms_ticker_get_average_load(call->videostream->ms.ticker);
2064 vs=call->videostream->ms.session;
2066 report_bandwidth(call,as,vs);
2067 ms_message("Thread processing load: audio=%f\tvideo=%f",audio_load,video_load);
2071 linphone_upnp_call_process(call);
2074 #ifdef VIDEO_ENABLED
2075 if (call->videostream!=NULL) {
2078 /* Ensure there is no dangling ICE check list. */
2079 if (call->ice_session == NULL) call->videostream->ms.ice_check_list = NULL;
2081 // Beware that the application queue should not depend on treatments fron the
2082 // mediastreamer queue.
2083 video_stream_iterate(call->videostream);
2085 while (call->videostream_app_evq && (NULL != (ev=ortp_ev_queue_get(call->videostream_app_evq)))){
2086 OrtpEventType evt=ortp_event_get_type(ev);
2087 OrtpEventData *evd=ortp_event_get_data(ev);
2088 if (evt == ORTP_EVENT_ZRTP_ENCRYPTION_CHANGED){
2089 linphone_call_videostream_encryption_changed(call, evd->info.zrtp_stream_encrypted);
2090 } else if (evt == ORTP_EVENT_RTCP_PACKET_RECEIVED) {
2091 call->stats[LINPHONE_CALL_STATS_VIDEO].round_trip_delay = rtp_session_get_round_trip_propagation(call->videostream->ms.session);
2092 if(call->stats[LINPHONE_CALL_STATS_VIDEO].received_rtcp != NULL)
2093 freemsg(call->stats[LINPHONE_CALL_STATS_VIDEO].received_rtcp);
2094 call->stats[LINPHONE_CALL_STATS_VIDEO].received_rtcp = evd->packet;
2096 if (lc->vtable.call_stats_updated)
2097 lc->vtable.call_stats_updated(lc, call, &call->stats[LINPHONE_CALL_STATS_VIDEO]);
2098 } else if (evt == ORTP_EVENT_RTCP_PACKET_EMITTED) {
2099 memcpy(&call->stats[LINPHONE_CALL_STATS_VIDEO].jitter_stats, rtp_session_get_jitter_stats(call->videostream->ms.session), sizeof(jitter_stats_t));
2100 if(call->stats[LINPHONE_CALL_STATS_VIDEO].sent_rtcp != NULL)
2101 freemsg(call->stats[LINPHONE_CALL_STATS_VIDEO].sent_rtcp);
2102 call->stats[LINPHONE_CALL_STATS_VIDEO].sent_rtcp = evd->packet;
2104 if (lc->vtable.call_stats_updated)
2105 lc->vtable.call_stats_updated(lc, call, &call->stats[LINPHONE_CALL_STATS_VIDEO]);
2106 } else if ((evt == ORTP_EVENT_ICE_SESSION_PROCESSING_FINISHED) || (evt == ORTP_EVENT_ICE_GATHERING_FINISHED)
2107 || (evt == ORTP_EVENT_ICE_LOSING_PAIRS_COMPLETED) || (evt == ORTP_EVENT_ICE_RESTART_NEEDED)) {
2108 handle_ice_events(call, ev);
2110 ortp_event_destroy(ev);
2114 if (call->audiostream!=NULL) {
2117 /* Ensure there is no dangling ICE check list. */
2118 if (call->ice_session == NULL) call->audiostream->ms.ice_check_list = NULL;
2120 // Beware that the application queue should not depend on treatments fron the
2121 // mediastreamer queue.
2122 audio_stream_iterate(call->audiostream);
2124 while (call->audiostream_app_evq && (NULL != (ev=ortp_ev_queue_get(call->audiostream_app_evq)))){
2125 OrtpEventType evt=ortp_event_get_type(ev);
2126 OrtpEventData *evd=ortp_event_get_data(ev);
2127 if (evt == ORTP_EVENT_ZRTP_ENCRYPTION_CHANGED){
2128 linphone_call_audiostream_encryption_changed(call, evd->info.zrtp_stream_encrypted);
2129 } else if (evt == ORTP_EVENT_ZRTP_SAS_READY) {
2130 linphone_call_audiostream_auth_token_ready(call, evd->info.zrtp_sas.sas, evd->info.zrtp_sas.verified);
2131 } else if (evt == ORTP_EVENT_RTCP_PACKET_RECEIVED) {
2132 call->stats[LINPHONE_CALL_STATS_AUDIO].round_trip_delay = rtp_session_get_round_trip_propagation(call->audiostream->ms.session);
2133 if(call->stats[LINPHONE_CALL_STATS_AUDIO].received_rtcp != NULL)
2134 freemsg(call->stats[LINPHONE_CALL_STATS_AUDIO].received_rtcp);
2135 call->stats[LINPHONE_CALL_STATS_AUDIO].received_rtcp = evd->packet;
2137 if (lc->vtable.call_stats_updated)
2138 lc->vtable.call_stats_updated(lc, call, &call->stats[LINPHONE_CALL_STATS_AUDIO]);
2139 } else if (evt == ORTP_EVENT_RTCP_PACKET_EMITTED) {
2140 memcpy(&call->stats[LINPHONE_CALL_STATS_AUDIO].jitter_stats, rtp_session_get_jitter_stats(call->audiostream->ms.session), sizeof(jitter_stats_t));
2141 if(call->stats[LINPHONE_CALL_STATS_AUDIO].sent_rtcp != NULL)
2142 freemsg(call->stats[LINPHONE_CALL_STATS_AUDIO].sent_rtcp);
2143 call->stats[LINPHONE_CALL_STATS_AUDIO].sent_rtcp = evd->packet;
2145 if (lc->vtable.call_stats_updated)
2146 lc->vtable.call_stats_updated(lc, call, &call->stats[LINPHONE_CALL_STATS_AUDIO]);
2147 } else if ((evt == ORTP_EVENT_ICE_SESSION_PROCESSING_FINISHED) || (evt == ORTP_EVENT_ICE_GATHERING_FINISHED)
2148 || (evt == ORTP_EVENT_ICE_LOSING_PAIRS_COMPLETED) || (evt == ORTP_EVENT_ICE_RESTART_NEEDED)) {
2149 handle_ice_events(call, ev);
2150 } else if (evt==ORTP_EVENT_TELEPHONE_EVENT){
2151 linphone_core_dtmf_received(lc,evd->info.telephone_event);
2153 ortp_event_destroy(ev);
2156 if (call->state==LinphoneCallStreamsRunning && one_second_elapsed && call->audiostream!=NULL && disconnect_timeout>0 )
2157 disconnected=!audio_stream_alive(call->audiostream,disconnect_timeout);
2159 linphone_core_disconnected(call->core,call);
2162 void linphone_call_log_completed(LinphoneCall *call){
2163 LinphoneCore *lc=call->core;
2165 call->log->duration=time(NULL)-call->start_time;
2167 if (call->log->status==LinphoneCallMissed){
2170 info=ortp_strdup_printf(ngettext("You have missed %i call.",
2171 "You have missed %i calls.", lc->missed_calls),
2173 if (lc->vtable.display_status!=NULL)
2174 lc->vtable.display_status(lc,info);
2177 lc->call_logs=ms_list_prepend(lc->call_logs,(void *)call->log);
2178 if (ms_list_size(lc->call_logs)>lc->max_call_logs){
2179 MSList *elem,*prevelem=NULL;
2180 /*find the last element*/
2181 for(elem=lc->call_logs;elem!=NULL;elem=elem->next){
2185 linphone_call_log_destroy((LinphoneCallLog*)elem->data);
2186 lc->call_logs=ms_list_remove_link(lc->call_logs,elem);
2188 if (lc->vtable.call_log_updated!=NULL){
2189 lc->vtable.call_log_updated(lc,call->log);
2191 call_logs_write_to_config_file(lc);
2194 LinphoneCallState linphone_call_get_transfer_state(LinphoneCall *call) {
2195 return call->transfer_state;
2198 void linphone_call_set_transfer_state(LinphoneCall* call, LinphoneCallState state) {
2199 if (state != call->transfer_state) {
2200 LinphoneCore* lc = call->core;
2201 call->transfer_state = state;
2202 if (lc->vtable.transfer_state_changed)
2203 lc->vtable.transfer_state_changed(lc, call, state);
2208 * Returns true if the call is part of the conference.
2209 * @ingroup conferencing
2211 bool_t linphone_call_is_in_conference(const LinphoneCall *call) {
2212 return call->params.in_conference;
2217 * Perform a zoom of the video displayed during a call.
2218 * @param call the call.
2219 * @param zoom_factor a floating point number describing the zoom factor. A value 1.0 corresponds to no zoom applied.
2220 * @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.
2221 * @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.
2223 * 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.
2225 void linphone_call_zoom_video(LinphoneCall* call, float zoom_factor, float* cx, float* cy) {
2226 VideoStream* vstream = call->videostream;
2227 if (vstream && vstream->output) {
2230 if (zoom_factor < 1)
2232 float halfsize = 0.5 * 1.0 / zoom_factor;
2234 if ((*cx - halfsize) < 0)
2236 if ((*cx + halfsize) > 1)
2238 if ((*cy - halfsize) < 0)
2240 if ((*cy + halfsize) > 1)
2243 zoom[0] = zoom_factor;
2246 ms_filter_call_method(vstream->output, MS_VIDEO_DISPLAY_ZOOM, &zoom);
2247 }else ms_warning("Could not apply zoom: video output wasn't activated.");