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);
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);
465 const SalMediaDescription *md;
467 call->dir=LinphoneCallIncoming;
468 sal_op_set_user_pointer(op,call);
472 if (lc->sip_conf.ping_with_options){
473 /*the following sends an option request back to the caller so that
474 we get a chance to discover our nat'd address before answering.*/
475 call->ping_op=sal_op_new(lc->sal);
476 from_str=linphone_address_as_string_uri_only(from);
477 sal_op_set_route(call->ping_op,sal_op_get_network_origin(op));
478 sal_op_set_user_pointer(call->ping_op,call);
479 sal_ping(call->ping_op,linphone_core_find_best_identity(lc,from,NULL),from_str);
483 linphone_address_clean(from);
484 linphone_core_get_local_ip(lc,linphone_address_get_domain(from),call->localip);
485 linphone_call_init_common(call, from, to);
486 call->log->call_id=ms_strdup(sal_op_get_call_id(op)); /*must be known at that time*/
487 linphone_core_init_default_params(lc, &call->params);
488 md=sal_call_get_remote_media_description(op);
489 call->params.has_video &= !!lc->video_policy.automatically_accept;
491 // It is licit to receive an INVITE without SDP
492 // In this case WE chose the media parameters according to policy.
493 call->params.has_video &= linphone_core_media_description_contains_video_stream(md);
495 switch (linphone_core_get_firewall_policy(call->core)) {
496 case LinphonePolicyUseIce:
497 call->ice_session = ice_session_new();
498 ice_session_set_role(call->ice_session, IR_Controlled);
499 linphone_core_update_ice_from_remote_media_description(call, sal_call_get_remote_media_description(op));
500 if (call->ice_session != NULL) {
501 linphone_call_init_media_streams(call);
502 linphone_call_start_media_streams_for_ice_gathering(call);
503 if (linphone_core_gather_ice_candidates(call->core,call)<0) {
504 /* Ice candidates gathering failed, proceed with the call anyway. */
505 linphone_call_delete_ice_session(call);
506 linphone_call_stop_media_streams_for_ice_gathering(call);
510 case LinphonePolicyUseStun:
511 call->ping_time=linphone_core_run_stun_tests(call->core,call);
512 /* No break to also destroy ice session in this case. */
516 call->camera_active=call->params.has_video;
518 discover_mtu(lc,linphone_address_get_domain(from));
522 /* this function is called internally to get rid of a call.
523 It performs the following tasks:
524 - remove the call from the internal list of calls
525 - update the call logs accordingly
528 static void linphone_call_set_terminated(LinphoneCall *call){
529 LinphoneCore *lc=call->core;
531 linphone_core_update_allocated_audio_bandwidth(lc);
533 call->owns_call_log=FALSE;
534 linphone_call_log_completed(call);
537 if (call == lc->current_call){
538 ms_message("Resetting the current call");
539 lc->current_call=NULL;
542 if (linphone_core_del_call(lc,call) != 0){
543 ms_error("Could not remove the call from the list !!!");
546 if (ms_list_size(lc->calls)==0)
547 linphone_core_notify_all_friends(lc,lc->presence_mode);
549 linphone_core_conference_check_uninit(lc);
550 if (call->ringing_beep){
551 linphone_core_stop_dtmf(lc);
552 call->ringing_beep=FALSE;
555 linphone_call_unref(call->referer);
560 void linphone_call_fix_call_parameters(LinphoneCall *call){
561 call->params.has_video=call->current_params.has_video;
562 call->params.media_encryption=call->current_params.media_encryption;
565 const char *linphone_call_state_to_string(LinphoneCallState cs){
567 case LinphoneCallIdle:
568 return "LinphoneCallIdle";
569 case LinphoneCallIncomingReceived:
570 return "LinphoneCallIncomingReceived";
571 case LinphoneCallOutgoingInit:
572 return "LinphoneCallOutgoingInit";
573 case LinphoneCallOutgoingProgress:
574 return "LinphoneCallOutgoingProgress";
575 case LinphoneCallOutgoingRinging:
576 return "LinphoneCallOutgoingRinging";
577 case LinphoneCallOutgoingEarlyMedia:
578 return "LinphoneCallOutgoingEarlyMedia";
579 case LinphoneCallConnected:
580 return "LinphoneCallConnected";
581 case LinphoneCallStreamsRunning:
582 return "LinphoneCallStreamsRunning";
583 case LinphoneCallPausing:
584 return "LinphoneCallPausing";
585 case LinphoneCallPaused:
586 return "LinphoneCallPaused";
587 case LinphoneCallResuming:
588 return "LinphoneCallResuming";
589 case LinphoneCallRefered:
590 return "LinphoneCallRefered";
591 case LinphoneCallError:
592 return "LinphoneCallError";
593 case LinphoneCallEnd:
594 return "LinphoneCallEnd";
595 case LinphoneCallPausedByRemote:
596 return "LinphoneCallPausedByRemote";
597 case LinphoneCallUpdatedByRemote:
598 return "LinphoneCallUpdatedByRemote";
599 case LinphoneCallIncomingEarlyMedia:
600 return "LinphoneCallIncomingEarlyMedia";
601 case LinphoneCallUpdating:
602 return "LinphoneCallUpdating";
603 case LinphoneCallReleased:
604 return "LinphoneCallReleased";
606 return "undefined state";
609 void linphone_call_set_state(LinphoneCall *call, LinphoneCallState cstate, const char *message){
610 LinphoneCore *lc=call->core;
612 if (call->state!=cstate){
613 if (call->state==LinphoneCallEnd || call->state==LinphoneCallError){
614 if (cstate!=LinphoneCallReleased){
615 ms_warning("Spurious call state change from %s to %s, ignored.",linphone_call_state_to_string(call->state),
616 linphone_call_state_to_string(cstate));
620 ms_message("Call %p: moving from state %s to %s",call,linphone_call_state_to_string(call->state),
621 linphone_call_state_to_string(cstate));
622 if (cstate!=LinphoneCallRefered){
623 /*LinphoneCallRefered is rather an event, not a state.
624 Indeed it does not change the state of the call (still paused or running)*/
627 if (cstate==LinphoneCallEnd || cstate==LinphoneCallError){
628 switch(call->reason){
629 case LinphoneReasonDeclined:
630 call->log->status=LinphoneCallDeclined;
632 case LinphoneReasonNotAnswered:
633 call->log->status=LinphoneCallMissed;
638 linphone_call_set_terminated (call);
640 if (cstate == LinphoneCallConnected) {
641 call->log->status=LinphoneCallSuccess;
642 call->media_start_time=time(NULL);
645 if (lc->vtable.call_state_changed)
646 lc->vtable.call_state_changed(lc,call,cstate,message);
647 if (cstate==LinphoneCallReleased){
648 if (call->op!=NULL) {
649 /* so that we cannot have anymore upcalls for SAL
650 concerning this call*/
651 sal_op_release(call->op);
654 linphone_call_unref(call);
659 static void linphone_call_destroy(LinphoneCall *obj)
661 linphone_call_delete_ice_session(obj);
663 sal_op_release(obj->op);
666 if (obj->resultdesc!=NULL) {
667 sal_media_description_unref(obj->resultdesc);
668 obj->resultdesc=NULL;
670 if (obj->localdesc!=NULL) {
671 sal_media_description_unref(obj->localdesc);
675 sal_op_release(obj->ping_op);
678 ms_free(obj->refer_to);
680 if (obj->owns_call_log)
681 linphone_call_log_destroy(obj->log);
682 if (obj->auth_token) {
683 ms_free(obj->auth_token);
690 * @addtogroup call_control
695 * Increments the call 's reference count.
696 * An application that wishes to retain a pointer to call object
697 * must use this function to unsure the pointer remains
698 * valid. Once the application no more needs this pointer,
699 * it must call linphone_call_unref().
701 LinphoneCall * linphone_call_ref(LinphoneCall *obj){
707 * Decrements the call object reference count.
708 * See linphone_call_ref().
710 void linphone_call_unref(LinphoneCall *obj){
713 linphone_call_destroy(obj);
718 * Returns current parameters associated to the call.
720 const LinphoneCallParams * linphone_call_get_current_params(const LinphoneCall *call){
721 return &call->current_params;
724 static bool_t is_video_active(const SalStreamDescription *sd){
725 return sd->rtp_port!=0 && sd->dir!=SalStreamInactive;
729 * Returns call parameters proposed by remote.
731 * This is useful when receiving an incoming call, to know whether the remote party
732 * supports video, encryption or whatever.
734 const LinphoneCallParams * linphone_call_get_remote_params(LinphoneCall *call){
735 LinphoneCallParams *cp=&call->remote_params;
736 memset(cp,0,sizeof(*cp));
738 SalMediaDescription *md=sal_call_get_remote_media_description(call->op);
740 SalStreamDescription *asd,*vsd,*secure_asd,*secure_vsd;
742 asd=sal_media_description_find_stream(md,SalProtoRtpAvp,SalAudio);
743 vsd=sal_media_description_find_stream(md,SalProtoRtpAvp,SalVideo);
744 secure_asd=sal_media_description_find_stream(md,SalProtoRtpSavp,SalAudio);
745 secure_vsd=sal_media_description_find_stream(md,SalProtoRtpSavp,SalVideo);
747 cp->has_video=is_video_active(secure_vsd);
748 if (secure_asd || asd==NULL)
749 cp->media_encryption=LinphoneMediaEncryptionSRTP;
751 cp->has_video=is_video_active(vsd);
754 if (md->bandwidth>0 && md->bandwidth<=linphone_core_get_edge_bw(call->core)){
755 cp->low_bandwidth=TRUE;
765 * Returns the remote address associated to this call
768 const LinphoneAddress * linphone_call_get_remote_address(const LinphoneCall *call){
769 return call->dir==LinphoneCallIncoming ? call->log->from : call->log->to;
773 * Returns the remote address associated to this call as a string.
775 * The result string must be freed by user using ms_free().
777 char *linphone_call_get_remote_address_as_string(const LinphoneCall *call){
778 return linphone_address_as_string(linphone_call_get_remote_address(call));
782 * Retrieves the call's current state.
784 LinphoneCallState linphone_call_get_state(const LinphoneCall *call){
789 * Returns the reason for a call termination (either error or normal termination)
791 LinphoneReason linphone_call_get_reason(const LinphoneCall *call){
796 * Get the user_pointer in the LinphoneCall
798 * @ingroup call_control
800 * return user_pointer an opaque user pointer that can be retrieved at any time
802 void *linphone_call_get_user_pointer(LinphoneCall *call)
804 return call->user_pointer;
808 * Set the user_pointer in the LinphoneCall
810 * @ingroup call_control
812 * the user_pointer is an opaque user pointer that can be retrieved at any time in the LinphoneCall
814 void linphone_call_set_user_pointer(LinphoneCall *call, void *user_pointer)
816 call->user_pointer = user_pointer;
820 * Returns the call log associated to this call.
822 LinphoneCallLog *linphone_call_get_call_log(const LinphoneCall *call){
827 * Returns the refer-to uri (if the call was transfered).
829 const char *linphone_call_get_refer_to(const LinphoneCall *call){
830 return call->refer_to;
834 * Returns direction of the call (incoming or outgoing).
836 LinphoneCallDir linphone_call_get_dir(const LinphoneCall *call){
837 return call->log->dir;
841 * Returns the far end's user agent description string, if available.
843 const char *linphone_call_get_remote_user_agent(LinphoneCall *call){
845 return sal_op_get_remote_ua (call->op);
851 * Returns true if this calls has received a transfer that has not been
853 * Pending transfers are executed when this call is being paused or closed,
854 * locally or by remote endpoint.
855 * If the call is already paused while receiving the transfer request, the
856 * transfer immediately occurs.
858 bool_t linphone_call_has_transfer_pending(const LinphoneCall *call){
859 return call->refer_pending;
863 * Returns call's duration in seconds.
865 int linphone_call_get_duration(const LinphoneCall *call){
866 if (call->media_start_time==0) return 0;
867 return time(NULL)-call->media_start_time;
871 * Returns the call object this call is replacing, if any.
872 * Call replacement can occur during call transfers.
873 * By default, the core automatically terminates the replaced call and accept the new one.
874 * This function allows the application to know whether a new incoming call is a one that replaces another one.
876 LinphoneCall *linphone_call_get_replaced_call(LinphoneCall *call){
877 SalOp *op=sal_call_get_replaces(call->op);
879 return (LinphoneCall*)sal_op_get_user_pointer(op);
885 * Indicate whether camera input should be sent to remote end.
887 void linphone_call_enable_camera (LinphoneCall *call, bool_t enable){
889 if (call->videostream!=NULL && call->videostream->ms.ticker!=NULL){
890 LinphoneCore *lc=call->core;
891 MSWebCam *nowebcam=get_nowebcam_device();
892 if (call->camera_active!=enable && lc->video_conf.device!=nowebcam){
893 video_stream_change_camera(call->videostream,
894 enable ? lc->video_conf.device : nowebcam);
897 call->camera_active=enable;
902 * Take a photo of currently received video and write it into a jpeg file.
904 int linphone_call_take_video_snapshot(LinphoneCall *call, const char *file){
906 if (call->videostream!=NULL && call->videostream->jpegwriter!=NULL){
907 return ms_filter_call_method(call->videostream->jpegwriter,MS_JPEG_WRITER_TAKE_SNAPSHOT,(void*)file);
909 ms_warning("Cannot take snapshot: no currently running video stream on this call.");
916 * Returns TRUE if camera pictures are sent to the remote party.
918 bool_t linphone_call_camera_enabled (const LinphoneCall *call){
919 return call->camera_active;
923 * Enable video stream.
925 void linphone_call_params_enable_video(LinphoneCallParams *cp, bool_t enabled){
926 cp->has_video=enabled;
929 const PayloadType* linphone_call_params_get_used_audio_codec(const LinphoneCallParams *cp) {
930 return cp->audio_codec;
933 const PayloadType* linphone_call_params_get_used_video_codec(const LinphoneCallParams *cp) {
934 return cp->video_codec;
938 * @ingroup call_control
939 * Use to know if this call has been configured in low bandwidth mode.
940 * This mode can be automatically discovered thanks to a stun server when activate_edge_workarounds=1 in section [net] of configuration file.
941 * An application that would have reliable way to know network capacity may not use activate_edge_workarounds=1 but instead manually configure
942 * low bandwidth mode with linphone_call_params_enable_low_bandwidth().
943 * <br> When enabled, this param may transform a call request with video in audio only mode.
944 * @return TRUE if low bandwidth has been configured/detected
946 bool_t linphone_call_params_low_bandwidth_enabled(const LinphoneCallParams *cp) {
947 return cp->low_bandwidth;
951 * @ingroup call_control
952 * Indicate low bandwith mode.
953 * 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
954 * 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
955 * that it is achievable by the codec selected after SDP handshake. Video is automatically disabled.
958 void linphone_call_params_enable_low_bandwidth(LinphoneCallParams *cp, bool_t enabled){
959 cp->low_bandwidth=enabled;
963 * Returns whether video is enabled.
965 bool_t linphone_call_params_video_enabled(const LinphoneCallParams *cp){
966 return cp->has_video;
969 enum LinphoneMediaEncryption linphone_call_params_get_media_encryption(const LinphoneCallParams *cp) {
970 return cp->media_encryption;
973 void linphone_call_params_set_media_encryption(LinphoneCallParams *cp, enum LinphoneMediaEncryption e) {
974 cp->media_encryption = e;
979 * Enable sending of real early media (during outgoing calls).
981 void linphone_call_params_enable_early_media_sending(LinphoneCallParams *cp, bool_t enabled){
982 cp->real_early_media=enabled;
985 bool_t linphone_call_params_early_media_sending_enabled(const LinphoneCallParams *cp){
986 return cp->real_early_media;
990 * Returns true if the call is part of the locally managed conference.
992 bool_t linphone_call_params_local_conference_mode(const LinphoneCallParams *cp){
993 return cp->in_conference;
997 * Refine bandwidth settings for this call by setting a bandwidth limit for audio streams.
998 * As a consequence, codecs whose bitrates are not compatible with this limit won't be used.
1000 void linphone_call_params_set_audio_bandwidth_limit(LinphoneCallParams *cp, int bandwidth){
1001 cp->audio_bw=bandwidth;
1004 #ifdef VIDEO_ENABLED
1006 * Request remote side to send us a Video Fast Update.
1008 void linphone_call_send_vfu_request(LinphoneCall *call)
1010 if (LinphoneCallStreamsRunning == linphone_call_get_state(call))
1011 sal_call_send_vfu_request(call->op);
1018 LinphoneCallParams * linphone_call_params_copy(const LinphoneCallParams *cp){
1019 LinphoneCallParams *ncp=ms_new0(LinphoneCallParams,1);
1020 memcpy(ncp,cp,sizeof(LinphoneCallParams));
1027 void linphone_call_params_destroy(LinphoneCallParams *p){
1036 #ifdef TEST_EXT_RENDERER
1037 static void rendercb(void *data, const MSPicture *local, const MSPicture *remote){
1038 ms_message("rendercb, local buffer=%p, remote buffer=%p",
1039 local ? local->planes[0] : NULL, remote? remote->planes[0] : NULL);
1043 #ifdef VIDEO_ENABLED
1044 static void video_stream_event_cb(void *user_pointer, const MSFilter *f, const unsigned int event_id, const void *args){
1045 LinphoneCall* call = (LinphoneCall*) user_pointer;
1046 ms_warning("In linphonecall.c: video_stream_event_cb");
1048 case MS_VIDEO_DECODER_DECODING_ERRORS:
1049 ms_warning("Case is MS_VIDEO_DECODER_DECODING_ERRORS");
1050 linphone_call_send_vfu_request(call);
1052 case MS_VIDEO_DECODER_FIRST_IMAGE_DECODED:
1053 ms_message("First video frame decoded successfully");
1054 if (call->nextVideoFrameDecoded._func != NULL)
1055 call->nextVideoFrameDecoded._func(call, call->nextVideoFrameDecoded._user_data);
1058 ms_warning("Unhandled event %i", event_id);
1064 void linphone_call_set_next_video_frame_decoded_callback(LinphoneCall *call, LinphoneCallCbFunc cb, void* user_data) {
1065 call->nextVideoFrameDecoded._func = cb;
1066 call->nextVideoFrameDecoded._user_data = user_data;
1067 #ifdef VIDEO_ENABLED
1068 ms_filter_call_method_noarg(call->videostream->ms.decoder, MS_VIDEO_DECODER_RESET_FIRST_IMAGE_NOTIFICATION);
1072 void linphone_call_init_audio_stream(LinphoneCall *call){
1073 LinphoneCore *lc=call->core;
1074 AudioStream *audiostream;
1077 if (call->audiostream != NULL) return;
1078 call->audiostream=audiostream=audio_stream_new(call->audio_port,call->audio_port+1,linphone_core_ipv6_enabled(lc));
1079 dscp=linphone_core_get_audio_dscp(lc);
1081 audio_stream_set_dscp(audiostream,dscp);
1082 if (linphone_core_echo_limiter_enabled(lc)){
1083 const char *type=lp_config_get_string(lc->config,"sound","el_type","mic");
1084 if (strcasecmp(type,"mic")==0)
1085 audio_stream_enable_echo_limiter(audiostream,ELControlMic);
1086 else if (strcasecmp(type,"full")==0)
1087 audio_stream_enable_echo_limiter(audiostream,ELControlFull);
1089 audio_stream_enable_gain_control(audiostream,TRUE);
1090 if (linphone_core_echo_cancellation_enabled(lc)){
1091 int len,delay,framesize;
1092 const char *statestr=lp_config_get_string(lc->config,"sound","ec_state",NULL);
1093 len=lp_config_get_int(lc->config,"sound","ec_tail_len",0);
1094 delay=lp_config_get_int(lc->config,"sound","ec_delay",0);
1095 framesize=lp_config_get_int(lc->config,"sound","ec_framesize",0);
1096 audio_stream_set_echo_canceller_params(audiostream,len,delay,framesize);
1097 if (statestr && audiostream->ec){
1098 ms_filter_call_method(audiostream->ec,MS_ECHO_CANCELLER_SET_STATE_STRING,(void*)statestr);
1101 audio_stream_enable_automatic_gain_control(audiostream,linphone_core_agc_enabled(lc));
1103 int enabled=lp_config_get_int(lc->config,"sound","noisegate",0);
1104 audio_stream_enable_noise_gate(audiostream,enabled);
1107 audio_stream_set_features(audiostream,linphone_core_get_audio_features(lc));
1110 RtpTransport *artp=lc->rtptf->audio_rtp_func(lc->rtptf->audio_rtp_func_data, call->audio_port);
1111 RtpTransport *artcp=lc->rtptf->audio_rtcp_func(lc->rtptf->audio_rtcp_func_data, call->audio_port+1);
1112 rtp_session_set_transports(audiostream->ms.session,artp,artcp);
1114 if ((linphone_core_get_firewall_policy(lc) == LinphonePolicyUseIce) && (call->ice_session != NULL)){
1115 rtp_session_set_pktinfo(audiostream->ms.session, TRUE);
1116 rtp_session_set_symmetric_rtp(audiostream->ms.session, FALSE);
1117 if (ice_session_check_list(call->ice_session, 0) == NULL) {
1118 ice_session_add_check_list(call->ice_session, ice_check_list_new());
1120 audiostream->ms.ice_check_list = ice_session_check_list(call->ice_session, 0);
1121 ice_check_list_set_rtp_session(audiostream->ms.ice_check_list, audiostream->ms.session);
1124 call->audiostream_app_evq = ortp_ev_queue_new();
1125 rtp_session_register_event_queue(audiostream->ms.session,call->audiostream_app_evq);
1128 void linphone_call_init_video_stream(LinphoneCall *call){
1129 #ifdef VIDEO_ENABLED
1130 LinphoneCore *lc=call->core;
1132 if (!call->params.has_video) {
1133 linphone_call_stop_video_stream(call);
1136 if (call->videostream != NULL) return;
1137 if ((lc->video_conf.display || lc->video_conf.capture) && call->params.has_video){
1138 int video_recv_buf_size=lp_config_get_int(lc->config,"video","recv_buf_size",0);
1139 int dscp=linphone_core_get_video_dscp(lc);
1141 call->videostream=video_stream_new(call->video_port,call->video_port+1,linphone_core_ipv6_enabled(lc));
1143 video_stream_set_dscp(call->videostream,dscp);
1144 video_stream_enable_display_filter_auto_rotate(call->videostream, lp_config_get_int(lc->config,"video","display_filter_auto_rotate",0));
1145 if (video_recv_buf_size>0) rtp_session_set_recv_buf_size(call->videostream->ms.session,video_recv_buf_size);
1147 if( lc->video_conf.displaytype != NULL)
1148 video_stream_set_display_filter_name(call->videostream,lc->video_conf.displaytype);
1149 video_stream_set_event_callback(call->videostream,video_stream_event_cb, call);
1151 RtpTransport *vrtp=lc->rtptf->video_rtp_func(lc->rtptf->video_rtp_func_data, call->video_port);
1152 RtpTransport *vrtcp=lc->rtptf->video_rtcp_func(lc->rtptf->video_rtcp_func_data, call->video_port+1);
1153 rtp_session_set_transports(call->videostream->ms.session,vrtp,vrtcp);
1155 if ((linphone_core_get_firewall_policy(lc) == LinphonePolicyUseIce) && (call->ice_session != NULL)){
1156 rtp_session_set_pktinfo(call->videostream->ms.session, TRUE);
1157 rtp_session_set_symmetric_rtp(call->videostream->ms.session, FALSE);
1158 if (ice_session_check_list(call->ice_session, 1) == NULL) {
1159 ice_session_add_check_list(call->ice_session, ice_check_list_new());
1161 call->videostream->ms.ice_check_list = ice_session_check_list(call->ice_session, 1);
1162 ice_check_list_set_rtp_session(call->videostream->ms.ice_check_list, call->videostream->ms.session);
1164 call->videostream_app_evq = ortp_ev_queue_new();
1165 rtp_session_register_event_queue(call->videostream->ms.session,call->videostream_app_evq);
1166 #ifdef TEST_EXT_RENDERER
1167 video_stream_set_render_callback(call->videostream,rendercb,NULL);
1171 call->videostream=NULL;
1175 void linphone_call_init_media_streams(LinphoneCall *call){
1176 linphone_call_init_audio_stream(call);
1177 linphone_call_init_video_stream(call);
1181 static int dtmf_tab[16]={'0','1','2','3','4','5','6','7','8','9','*','#','A','B','C','D'};
1183 static void linphone_core_dtmf_received(LinphoneCore *lc, int dtmf){
1184 if (dtmf<0 || dtmf>15){
1185 ms_warning("Bad dtmf value %i",dtmf);
1188 if (lc->vtable.dtmf_received != NULL)
1189 lc->vtable.dtmf_received(lc, linphone_core_get_current_call(lc), dtmf_tab[dtmf]);
1192 static void parametrize_equalizer(LinphoneCore *lc, AudioStream *st){
1194 MSFilter *f=st->equalizer;
1195 int enabled=lp_config_get_int(lc->config,"sound","eq_active",0);
1196 const char *gains=lp_config_get_string(lc->config,"sound","eq_gains",NULL);
1197 ms_filter_call_method(f,MS_EQUALIZER_SET_ACTIVE,&enabled);
1203 if (sscanf(gains,"%f:%f:%f %n",&g.frequency,&g.gain,&g.width,&bytes)==3){
1204 ms_message("Read equalizer gains: %f(~%f) --> %f",g.frequency,g.width,g.gain);
1205 ms_filter_call_method(f,MS_EQUALIZER_SET_GAIN,&g);
1214 void _post_configure_audio_stream(AudioStream *st, LinphoneCore *lc, bool_t muted){
1215 float mic_gain=lc->sound_conf.soft_mic_lev;
1218 float ng_thres=lp_config_get_float(lc->config,"sound","ng_thres",0.05);
1219 float ng_floorgain=lp_config_get_float(lc->config,"sound","ng_floorgain",0);
1220 int dc_removal=lp_config_get_int(lc->config,"sound","dc_removal",0);
1223 linphone_core_set_mic_gain_db (lc, mic_gain);
1225 audio_stream_set_mic_gain(st,0);
1227 recv_gain = lc->sound_conf.soft_play_lev;
1228 if (recv_gain != 0) {
1229 linphone_core_set_playback_gain_db (lc,recv_gain);
1233 ms_filter_call_method(st->volsend,MS_VOLUME_REMOVE_DC,&dc_removal);
1234 float speed=lp_config_get_float(lc->config,"sound","el_speed",-1);
1235 thres=lp_config_get_float(lc->config,"sound","el_thres",-1);
1236 float force=lp_config_get_float(lc->config,"sound","el_force",-1);
1237 int sustain=lp_config_get_int(lc->config,"sound","el_sustain",-1);
1238 float transmit_thres=lp_config_get_float(lc->config,"sound","el_transmit_thres",-1);
1241 if (speed==-1) speed=0.03;
1242 if (force==-1) force=25;
1243 ms_filter_call_method(f,MS_VOLUME_SET_EA_SPEED,&speed);
1244 ms_filter_call_method(f,MS_VOLUME_SET_EA_FORCE,&force);
1246 ms_filter_call_method(f,MS_VOLUME_SET_EA_THRESHOLD,&thres);
1248 ms_filter_call_method(f,MS_VOLUME_SET_EA_SUSTAIN,&sustain);
1249 if (transmit_thres!=-1)
1250 ms_filter_call_method(f,MS_VOLUME_SET_EA_TRANSMIT_THRESHOLD,&transmit_thres);
1252 ms_filter_call_method(st->volsend,MS_VOLUME_SET_NOISE_GATE_THRESHOLD,&ng_thres);
1253 ms_filter_call_method(st->volsend,MS_VOLUME_SET_NOISE_GATE_FLOORGAIN,&ng_floorgain);
1256 /* parameters for a limited noise-gate effect, using echo limiter threshold */
1257 float floorgain = 1/pow(10,(mic_gain)/10);
1258 int spk_agc=lp_config_get_int(lc->config,"sound","speaker_agc_enabled",0);
1259 ms_filter_call_method(st->volrecv, MS_VOLUME_ENABLE_AGC, &spk_agc);
1260 ms_filter_call_method(st->volrecv,MS_VOLUME_SET_NOISE_GATE_THRESHOLD,&ng_thres);
1261 ms_filter_call_method(st->volrecv,MS_VOLUME_SET_NOISE_GATE_FLOORGAIN,&floorgain);
1263 parametrize_equalizer(lc,st);
1266 static void post_configure_audio_streams(LinphoneCall*call){
1267 AudioStream *st=call->audiostream;
1268 LinphoneCore *lc=call->core;
1269 _post_configure_audio_stream(st,lc,call->audio_muted);
1270 if (lc->vtable.dtmf_received!=NULL){
1271 /* replace by our default action*/
1272 audio_stream_play_received_dtmfs(call->audiostream,FALSE);
1273 /*rtp_session_signal_connect(call->audiostream->session,"telephone-event",(RtpCallback)linphone_core_dtmf_received,(unsigned long)lc);*/
1277 static RtpProfile *make_profile(LinphoneCall *call, const SalMediaDescription *md, const SalStreamDescription *desc, int *used_pt){
1280 RtpProfile *prof=rtp_profile_new("Call profile");
1283 LinphoneCore *lc=call->core;
1285 const LinphoneCallParams *params=&call->params;
1288 for(elem=desc->payloads;elem!=NULL;elem=elem->next){
1289 PayloadType *pt=(PayloadType*)elem->data;
1292 if ((pt->flags & PAYLOAD_TYPE_FLAG_CAN_SEND) && first) {
1293 if (desc->type==SalAudio){
1294 linphone_core_update_allocated_audio_bandwidth_in_call(call,pt);
1295 if (params->up_ptime)
1296 up_ptime=params->up_ptime;
1297 else up_ptime=linphone_core_get_upload_ptime(lc);
1299 *used_pt=payload_type_get_number(pt);
1302 if (desc->bandwidth>0) remote_bw=desc->bandwidth;
1303 else if (md->bandwidth>0) {
1304 /*case where b=AS is given globally, not per stream*/
1305 remote_bw=md->bandwidth;
1306 if (desc->type==SalVideo){
1307 remote_bw=get_video_bandwidth(remote_bw,call->audio_bw);
1311 if (desc->type==SalAudio){
1312 int audio_bw=call->audio_bw;
1314 if (params->up_bw< audio_bw)
1315 audio_bw=params->up_bw;
1317 bw=get_min_bandwidth(audio_bw,remote_bw);
1318 }else bw=get_min_bandwidth(get_video_bandwidth(linphone_core_get_upload_bandwidth (lc),call->audio_bw),remote_bw);
1319 if (bw>0) pt->normal_bitrate=bw*1000;
1320 else if (desc->type==SalAudio){
1321 pt->normal_bitrate=-1;
1324 up_ptime=desc->ptime;
1328 snprintf(tmp,sizeof(tmp),"ptime=%i",up_ptime);
1329 payload_type_append_send_fmtp(pt,tmp);
1331 number=payload_type_get_number(pt);
1332 if (rtp_profile_get_payload(prof,number)!=NULL){
1333 ms_warning("A payload type with number %i already exists in profile !",number);
1335 rtp_profile_set_payload(prof,number,pt);
1341 static void setup_ring_player(LinphoneCore *lc, LinphoneCall *call){
1342 int pause_time=3000;
1343 audio_stream_play(call->audiostream,lc->sound_conf.ringback_tone);
1344 ms_filter_call_method(call->audiostream->soundread,MS_FILE_PLAYER_LOOP,&pause_time);
1347 static bool_t linphone_call_sound_resources_available(LinphoneCall *call){
1348 LinphoneCore *lc=call->core;
1349 LinphoneCall *current=linphone_core_get_current_call(lc);
1350 return !linphone_core_is_in_conference(lc) &&
1351 (current==NULL || current==call);
1353 static int find_crypto_index_from_tag(const SalSrtpCryptoAlgo crypto[],unsigned char tag) {
1355 for(i=0; i<SAL_CRYPTO_ALGO_MAX; i++) {
1356 if (crypto[i].tag == tag) {
1362 static void linphone_call_start_audio_stream(LinphoneCall *call, const char *cname, bool_t muted, bool_t send_ringbacktone, bool_t use_arc){
1363 LinphoneCore *lc=call->core;
1365 char rtcp_tool[128]={0};
1366 snprintf(rtcp_tool,sizeof(rtcp_tool)-1,"%s-%s",linphone_core_get_user_agent_name(),linphone_core_get_user_agent_version());
1367 /* look for savp stream first */
1368 const SalStreamDescription *stream=sal_media_description_find_stream(call->resultdesc,
1369 SalProtoRtpSavp,SalAudio);
1370 /* no savp audio stream, use avp */
1372 stream=sal_media_description_find_stream(call->resultdesc,
1373 SalProtoRtpAvp,SalAudio);
1375 if (stream && stream->dir!=SalStreamInactive && stream->rtp_port!=0){
1376 MSSndCard *playcard=lc->sound_conf.lsd_card ?
1377 lc->sound_conf.lsd_card : lc->sound_conf.play_sndcard;
1378 MSSndCard *captcard=lc->sound_conf.capt_sndcard;
1379 const char *playfile=lc->play_file;
1380 const char *recfile=lc->rec_file;
1381 call->audio_profile=make_profile(call,call->resultdesc,stream,&used_pt);
1385 call->current_params.audio_codec = rtp_profile_get_payload(call->audio_profile, used_pt);
1386 if (playcard==NULL) {
1387 ms_warning("No card defined for playback !");
1389 if (captcard==NULL) {
1390 ms_warning("No card defined for capture !");
1392 /*Replace soundcard filters by inactive file players or recorders
1393 when placed in recvonly or sendonly mode*/
1394 if (stream->rtp_port==0 || stream->dir==SalStreamRecvOnly){
1397 }else if (stream->dir==SalStreamSendOnly){
1401 /*And we will eventually play "playfile" if set by the user*/
1404 if (send_ringbacktone){
1406 playfile=NULL;/* it is setup later*/
1408 /*if playfile are supplied don't use soundcards*/
1409 if (lc->use_files) {
1413 if (call->params.in_conference){
1414 /* first create the graph without soundcard resources*/
1415 captcard=playcard=NULL;
1417 if (!linphone_call_sound_resources_available(call)){
1418 ms_message("Sound resources are used by another call, not using soundcard.");
1419 captcard=playcard=NULL;
1421 use_ec=captcard==NULL ? FALSE : linphone_core_echo_cancellation_enabled(lc);
1422 if (playcard && stream->max_rate>0) ms_snd_card_set_preferred_sample_rate(playcard, stream->max_rate);
1423 if (captcard && stream->max_rate>0) ms_snd_card_set_preferred_sample_rate(captcard, stream->max_rate);
1424 audio_stream_enable_adaptive_bitrate_control(call->audiostream,use_arc);
1425 audio_stream_enable_adaptive_jittcomp(call->audiostream, linphone_core_audio_adaptive_jittcomp_enabled(lc));
1426 audio_stream_start_full(
1428 call->audio_profile,
1429 stream->rtp_addr[0]!='\0' ? stream->rtp_addr : call->resultdesc->addr,
1431 stream->rtcp_addr[0]!='\0' ? stream->rtcp_addr : call->resultdesc->addr,
1432 linphone_core_rtcp_enabled(lc) ? (stream->rtcp_port) : 0,
1434 linphone_core_get_audio_jittcomp(lc),
1441 post_configure_audio_streams(call);
1442 if (muted && !send_ringbacktone){
1443 audio_stream_set_mic_gain(call->audiostream,0);
1445 if (stream->dir==SalStreamSendOnly && playfile!=NULL){
1447 ms_filter_call_method(call->audiostream->soundread,MS_FILE_PLAYER_LOOP,&pause_time);
1449 if (send_ringbacktone){
1450 setup_ring_player(lc,call);
1452 audio_stream_set_rtcp_information(call->audiostream, cname, rtcp_tool);
1454 /* valid local tags are > 0 */
1455 if (stream->proto == SalProtoRtpSavp) {
1456 const SalStreamDescription *local_st_desc=sal_media_description_find_stream(call->localdesc,
1457 SalProtoRtpSavp,SalAudio);
1458 int crypto_idx = find_crypto_index_from_tag(local_st_desc->crypto, stream->crypto_local_tag);
1460 if (crypto_idx >= 0) {
1461 audio_stream_enable_srtp(
1463 stream->crypto[0].algo,
1464 local_st_desc->crypto[crypto_idx].master_key,
1465 stream->crypto[0].master_key);
1466 call->audiostream_encrypted=TRUE;
1468 ms_warning("Failed to find local crypto algo with tag: %d", stream->crypto_local_tag);
1469 call->audiostream_encrypted=FALSE;
1471 }else call->audiostream_encrypted=FALSE;
1472 if (call->params.in_conference){
1473 /*transform the graph to connect it to the conference filter */
1474 bool_t mute=stream->dir==SalStreamRecvOnly;
1475 linphone_call_add_to_conf(call, mute);
1477 call->current_params.in_conference=call->params.in_conference;
1478 call->current_params.low_bandwidth=call->params.low_bandwidth;
1479 }else ms_warning("No audio stream accepted ?");
1483 static void linphone_call_start_video_stream(LinphoneCall *call, const char *cname,bool_t all_inputs_muted){
1484 #ifdef VIDEO_ENABLED
1485 LinphoneCore *lc=call->core;
1487 /* look for savp stream first */
1488 const SalStreamDescription *vstream=sal_media_description_find_stream(call->resultdesc,
1489 SalProtoRtpSavp,SalVideo);
1490 char rtcp_tool[128]={0};
1491 snprintf(rtcp_tool,sizeof(rtcp_tool)-1,"%s-%s",linphone_core_get_user_agent_name(),linphone_core_get_user_agent_version());
1493 /* no savp audio stream, use avp */
1495 vstream=sal_media_description_find_stream(call->resultdesc,
1496 SalProtoRtpAvp,SalVideo);
1498 /* shutdown preview */
1499 if (lc->previewstream!=NULL) {
1500 video_preview_stop(lc->previewstream);
1501 lc->previewstream=NULL;
1504 if (vstream!=NULL && vstream->dir!=SalStreamInactive && vstream->rtp_port!=0) {
1505 const char *rtp_addr=vstream->rtp_addr[0]!='\0' ? vstream->rtp_addr : call->resultdesc->addr;
1506 const char *rtcp_addr=vstream->rtcp_addr[0]!='\0' ? vstream->rtcp_addr : call->resultdesc->addr;
1507 call->video_profile=make_profile(call,call->resultdesc,vstream,&used_pt);
1509 call->current_params.video_codec = rtp_profile_get_payload(call->video_profile, used_pt);
1510 VideoStreamDir dir=VideoStreamSendRecv;
1511 MSWebCam *cam=lc->video_conf.device;
1512 bool_t is_inactive=FALSE;
1514 call->current_params.has_video=TRUE;
1516 video_stream_enable_adaptive_bitrate_control(call->videostream,
1517 linphone_core_adaptive_rate_control_enabled(lc));
1518 video_stream_enable_adaptive_jittcomp(call->videostream, linphone_core_video_adaptive_jittcomp_enabled(lc));
1519 video_stream_set_sent_video_size(call->videostream,linphone_core_get_preferred_video_size(lc));
1520 video_stream_enable_self_view(call->videostream,lc->video_conf.selfview);
1521 if (lc->video_window_id!=0)
1522 video_stream_set_native_window_id(call->videostream,lc->video_window_id);
1523 if (lc->preview_window_id!=0)
1524 video_stream_set_native_preview_window_id (call->videostream,lc->preview_window_id);
1525 video_stream_use_preview_video_window (call->videostream,lc->use_preview_window);
1527 if (vstream->dir==SalStreamSendOnly && lc->video_conf.capture ){
1528 cam=get_nowebcam_device();
1529 dir=VideoStreamSendOnly;
1530 }else if (vstream->dir==SalStreamRecvOnly && lc->video_conf.display ){
1531 dir=VideoStreamRecvOnly;
1532 }else if (vstream->dir==SalStreamSendRecv){
1533 if (lc->video_conf.display && lc->video_conf.capture)
1534 dir=VideoStreamSendRecv;
1535 else if (lc->video_conf.display)
1536 dir=VideoStreamRecvOnly;
1538 dir=VideoStreamSendOnly;
1540 ms_warning("video stream is inactive.");
1541 /*either inactive or incompatible with local capabilities*/
1544 if (call->camera_active==FALSE || all_inputs_muted){
1545 cam=get_nowebcam_device();
1548 call->log->video_enabled = TRUE;
1549 video_stream_set_direction (call->videostream, dir);
1550 ms_message("%s lc rotation:%d\n", __FUNCTION__, lc->device_rotation);
1551 video_stream_set_device_rotation(call->videostream, lc->device_rotation);
1552 video_stream_start(call->videostream,
1553 call->video_profile, rtp_addr, vstream->rtp_port,
1554 rtcp_addr, linphone_core_rtcp_enabled(lc) ? (vstream->rtcp_port) : 0,
1555 used_pt, linphone_core_get_video_jittcomp(lc), cam);
1556 video_stream_set_rtcp_information(call->videostream, cname,rtcp_tool);
1559 if (vstream->proto == SalProtoRtpSavp) {
1560 const SalStreamDescription *local_st_desc=sal_media_description_find_stream(call->localdesc,
1561 SalProtoRtpSavp,SalVideo);
1563 video_stream_enable_strp(
1565 vstream->crypto[0].algo,
1566 local_st_desc->crypto[0].master_key,
1567 vstream->crypto[0].master_key
1569 call->videostream_encrypted=TRUE;
1571 call->videostream_encrypted=FALSE;
1573 }else ms_warning("No video stream accepted.");
1575 ms_warning("No valid video stream defined.");
1580 void linphone_call_start_media_streams(LinphoneCall *call, bool_t all_inputs_muted, bool_t send_ringbacktone){
1581 LinphoneCore *lc=call->core;
1583 call->current_params.audio_codec = NULL;
1584 call->current_params.video_codec = NULL;
1586 LinphoneAddress *me=linphone_core_get_primary_contact_parsed(lc);
1588 bool_t use_arc=linphone_core_adaptive_rate_control_enabled(lc);
1589 #ifdef VIDEO_ENABLED
1590 const SalStreamDescription *vstream=sal_media_description_find_stream(call->resultdesc,
1591 SalProtoRtpAvp,SalVideo);
1594 if ((call->audiostream == NULL) && (call->videostream == NULL)) {
1595 ms_fatal("start_media_stream() called without prior init !");
1598 cname=linphone_address_as_string_uri_only(me);
1600 #if defined(VIDEO_ENABLED)
1601 if (vstream!=NULL && vstream->dir!=SalStreamInactive && vstream->payloads!=NULL){
1602 /*when video is used, do not make adaptive rate control on audio, it is stupid.*/
1606 if (call->audiostream!=NULL) {
1607 linphone_call_start_audio_stream(call,cname,all_inputs_muted,send_ringbacktone,use_arc);
1609 call->current_params.has_video=FALSE;
1610 if (call->videostream!=NULL) {
1611 linphone_call_start_video_stream(call,cname,all_inputs_muted);
1614 call->all_muted=all_inputs_muted;
1615 call->playing_ringbacktone=send_ringbacktone;
1616 call->up_bw=linphone_core_get_upload_bandwidth(lc);
1618 if (call->params.media_encryption==LinphoneMediaEncryptionZRTP) {
1619 OrtpZrtpParams params;
1620 /*will be set later when zrtp is activated*/
1621 call->current_params.media_encryption=LinphoneMediaEncryptionNone;
1623 params.zid_file=lc->zrtp_secrets_cache;
1624 audio_stream_enable_zrtp(call->audiostream,¶ms);
1625 }else if (call->params.media_encryption==LinphoneMediaEncryptionSRTP){
1626 call->current_params.media_encryption=linphone_call_are_all_streams_encrypted(call) ?
1627 LinphoneMediaEncryptionSRTP : LinphoneMediaEncryptionNone;
1630 /*also reflect the change if the "wished" params, in order to avoid to propose SAVP or video again
1631 * further in the call, for example during pause,resume, conferencing reINVITEs*/
1632 linphone_call_fix_call_parameters(call);
1633 if ((call->ice_session != NULL) && (ice_session_state(call->ice_session) != IS_Completed)) {
1634 ice_session_start_connectivity_checks(call->ice_session);
1640 linphone_address_destroy(me);
1643 void linphone_call_start_media_streams_for_ice_gathering(LinphoneCall *call){
1644 audio_stream_prepare_sound(call->audiostream, NULL, NULL);
1645 #ifdef VIDEO_ENABLED
1646 if (call->videostream) {
1647 video_stream_prepare_video(call->videostream);
1652 void linphone_call_stop_media_streams_for_ice_gathering(LinphoneCall *call){
1653 audio_stream_unprepare_sound(call->audiostream);
1654 #ifdef VIDEO_ENABLED
1655 if (call->videostream) {
1656 video_stream_unprepare_video(call->videostream);
1661 void linphone_call_update_crypto_parameters(LinphoneCall *call, SalMediaDescription *old_md, SalMediaDescription *new_md) {
1662 SalStreamDescription *old_stream;
1663 SalStreamDescription *new_stream;
1666 old_stream = sal_media_description_find_stream(old_md, SalProtoRtpSavp, SalAudio);
1667 new_stream = sal_media_description_find_stream(new_md, SalProtoRtpSavp, SalAudio);
1668 if (old_stream && new_stream) {
1669 const SalStreamDescription *local_st_desc = sal_media_description_find_stream(call->localdesc, SalProtoRtpSavp, SalAudio);
1670 if (local_st_desc) {
1671 int crypto_idx = find_crypto_index_from_tag(local_st_desc->crypto, new_stream->crypto_local_tag);
1672 if (crypto_idx >= 0) {
1673 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);
1674 call->audiostream_encrypted = TRUE;
1676 ms_warning("Failed to find local crypto algo with tag: %d", new_stream->crypto_local_tag);
1677 call->audiostream_encrypted = FALSE;
1679 for (i = 0; i < SAL_CRYPTO_ALGO_MAX; i++) {
1680 old_stream->crypto[i].tag = new_stream->crypto[i].tag;
1681 old_stream->crypto[i].algo = new_stream->crypto[i].algo;
1682 strncpy(old_stream->crypto[i].master_key, new_stream->crypto[i].master_key, sizeof(old_stream->crypto[i].master_key) - 1);
1687 #ifdef VIDEO_ENABLED
1688 old_stream = sal_media_description_find_stream(old_md, SalProtoRtpSavp, SalVideo);
1689 new_stream = sal_media_description_find_stream(new_md, SalProtoRtpSavp, SalVideo);
1690 if (old_stream && new_stream) {
1691 const SalStreamDescription *local_st_desc = sal_media_description_find_stream(call->localdesc, SalProtoRtpSavp, SalVideo);
1692 if (local_st_desc) {
1693 int crypto_idx = find_crypto_index_from_tag(local_st_desc->crypto, new_stream->crypto_local_tag);
1694 if (crypto_idx >= 0) {
1695 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);
1696 call->videostream_encrypted = TRUE;
1698 ms_warning("Failed to find local crypto algo with tag: %d", new_stream->crypto_local_tag);
1699 call->videostream_encrypted = FALSE;
1701 for (i = 0; i < SAL_CRYPTO_ALGO_MAX; i++) {
1702 old_stream->crypto[i].tag = new_stream->crypto[i].tag;
1703 old_stream->crypto[i].algo = new_stream->crypto[i].algo;
1704 strncpy(old_stream->crypto[i].master_key, new_stream->crypto[i].master_key, sizeof(old_stream->crypto[i].master_key) - 1);
1711 void linphone_call_update_remote_session_id_and_ver(LinphoneCall *call) {
1712 SalMediaDescription *remote_desc = sal_call_get_remote_media_description(call->op);
1714 call->remote_session_id = remote_desc->session_id;
1715 call->remote_session_ver = remote_desc->session_ver;
1719 void linphone_call_delete_ice_session(LinphoneCall *call){
1720 if (call->ice_session != NULL) {
1721 ice_session_destroy(call->ice_session);
1722 call->ice_session = NULL;
1723 if (call->audiostream != NULL) call->audiostream->ms.ice_check_list = NULL;
1724 if (call->videostream != NULL) call->videostream->ms.ice_check_list = NULL;
1725 call->stats[LINPHONE_CALL_STATS_AUDIO].ice_state = LinphoneIceStateNotActivated;
1726 call->stats[LINPHONE_CALL_STATS_VIDEO].ice_state = LinphoneIceStateNotActivated;
1730 static void linphone_call_log_fill_stats(LinphoneCallLog *log, AudioStream *st){
1731 audio_stream_get_local_rtp_stats (st,&log->local_stats);
1732 log->quality=audio_stream_get_average_quality_rating(st);
1735 void linphone_call_stop_audio_stream(LinphoneCall *call) {
1736 if (call->audiostream!=NULL) {
1737 rtp_session_unregister_event_queue(call->audiostream->ms.session,call->audiostream_app_evq);
1738 ortp_ev_queue_flush(call->audiostream_app_evq);
1739 ortp_ev_queue_destroy(call->audiostream_app_evq);
1740 call->audiostream_app_evq=NULL;
1742 if (call->audiostream->ec){
1743 const char *state_str=NULL;
1744 ms_filter_call_method(call->audiostream->ec,MS_ECHO_CANCELLER_GET_STATE_STRING,&state_str);
1746 ms_message("Writing echo canceler state, %i bytes",(int)strlen(state_str));
1747 lp_config_set_string(call->core->config,"sound","ec_state",state_str);
1750 linphone_call_log_fill_stats (call->log,call->audiostream);
1751 if (call->endpoint){
1752 linphone_call_remove_from_conf(call);
1754 audio_stream_stop(call->audiostream);
1755 call->audiostream=NULL;
1759 void linphone_call_stop_video_stream(LinphoneCall *call) {
1760 #ifdef VIDEO_ENABLED
1761 if (call->videostream!=NULL){
1762 rtp_session_unregister_event_queue(call->videostream->ms.session,call->videostream_app_evq);
1763 ortp_ev_queue_flush(call->videostream_app_evq);
1764 ortp_ev_queue_destroy(call->videostream_app_evq);
1765 call->videostream_app_evq=NULL;
1766 video_stream_stop(call->videostream);
1767 call->videostream=NULL;
1772 void linphone_call_stop_media_streams(LinphoneCall *call){
1773 linphone_call_stop_audio_stream(call);
1774 linphone_call_stop_video_stream(call);
1775 ms_event_queue_skip(call->core->msevq);
1777 if (call->audio_profile){
1778 rtp_profile_clear_all(call->audio_profile);
1779 rtp_profile_destroy(call->audio_profile);
1780 call->audio_profile=NULL;
1782 if (call->video_profile){
1783 rtp_profile_clear_all(call->video_profile);
1784 rtp_profile_destroy(call->video_profile);
1785 call->video_profile=NULL;
1791 void linphone_call_enable_echo_cancellation(LinphoneCall *call, bool_t enable) {
1792 if (call!=NULL && call->audiostream!=NULL && call->audiostream->ec){
1793 bool_t bypass_mode = !enable;
1794 ms_filter_call_method(call->audiostream->ec,MS_ECHO_CANCELLER_SET_BYPASS_MODE,&bypass_mode);
1797 bool_t linphone_call_echo_cancellation_enabled(LinphoneCall *call) {
1798 if (call!=NULL && call->audiostream!=NULL && call->audiostream->ec){
1800 ms_filter_call_method(call->audiostream->ec,MS_ECHO_CANCELLER_GET_BYPASS_MODE,&val);
1803 return linphone_core_echo_cancellation_enabled(call->core);
1807 void linphone_call_enable_echo_limiter(LinphoneCall *call, bool_t val){
1808 if (call!=NULL && call->audiostream!=NULL ) {
1810 const char *type=lp_config_get_string(call->core->config,"sound","el_type","mic");
1811 if (strcasecmp(type,"mic")==0)
1812 audio_stream_enable_echo_limiter(call->audiostream,ELControlMic);
1813 else if (strcasecmp(type,"full")==0)
1814 audio_stream_enable_echo_limiter(call->audiostream,ELControlFull);
1816 audio_stream_enable_echo_limiter(call->audiostream,ELInactive);
1821 bool_t linphone_call_echo_limiter_enabled(const LinphoneCall *call){
1822 if (call!=NULL && call->audiostream!=NULL ){
1823 return call->audiostream->el_type !=ELInactive ;
1825 return linphone_core_echo_limiter_enabled(call->core);
1830 * @addtogroup call_misc
1835 * Returns the measured sound volume played locally (received from remote).
1836 * It is expressed in dbm0.
1838 float linphone_call_get_play_volume(LinphoneCall *call){
1839 AudioStream *st=call->audiostream;
1840 if (st && st->volrecv){
1842 ms_filter_call_method(st->volrecv,MS_VOLUME_GET,&vol);
1846 return LINPHONE_VOLUME_DB_LOWEST;
1850 * Returns the measured sound volume recorded locally (sent to remote).
1851 * It is expressed in dbm0.
1853 float linphone_call_get_record_volume(LinphoneCall *call){
1854 AudioStream *st=call->audiostream;
1855 if (st && st->volsend && !call->audio_muted && call->state==LinphoneCallStreamsRunning){
1857 ms_filter_call_method(st->volsend,MS_VOLUME_GET,&vol);
1861 return LINPHONE_VOLUME_DB_LOWEST;
1865 * Obtain real-time quality rating of the call
1867 * Based on local RTP statistics and RTCP feedback, a quality rating is computed and updated
1868 * during all the duration of the call. This function returns its value at the time of the function call.
1869 * It is expected that the rating is updated at least every 5 seconds or so.
1870 * The rating is a floating point number comprised between 0 and 5.
1872 * 4-5 = good quality <br>
1873 * 3-4 = average quality <br>
1874 * 2-3 = poor quality <br>
1875 * 1-2 = very poor quality <br>
1876 * 0-1 = can't be worse, mostly unusable <br>
1878 * @returns The function returns -1 if no quality measurement is available, for example if no
1879 * active audio stream exist. Otherwise it returns the quality rating.
1881 float linphone_call_get_current_quality(LinphoneCall *call){
1882 if (call->audiostream){
1883 return audio_stream_get_quality_rating(call->audiostream);
1889 * Returns call quality averaged over all the duration of the call.
1891 * See linphone_call_get_current_quality() for more details about quality measurement.
1893 float linphone_call_get_average_quality(LinphoneCall *call){
1894 if (call->audiostream){
1895 return audio_stream_get_average_quality_rating(call->audiostream);
1901 * Access last known statistics for audio stream, for a given call.
1903 const LinphoneCallStats *linphone_call_get_audio_stats(const LinphoneCall *call) {
1904 return &call->stats[LINPHONE_CALL_STATS_AUDIO];
1908 * Access last known statistics for video stream, for a given call.
1910 const LinphoneCallStats *linphone_call_get_video_stats(const LinphoneCall *call) {
1911 return &call->stats[LINPHONE_CALL_STATS_VIDEO];
1919 static void report_bandwidth(LinphoneCall *call, RtpSession *as, RtpSession *vs){
1920 call->stats[LINPHONE_CALL_STATS_AUDIO].download_bandwidth=(as!=NULL) ? (rtp_session_compute_recv_bandwidth(as)*1e-3) : 0;
1921 call->stats[LINPHONE_CALL_STATS_AUDIO].upload_bandwidth=(as!=NULL) ? (rtp_session_compute_send_bandwidth(as)*1e-3) : 0;
1922 call->stats[LINPHONE_CALL_STATS_VIDEO].download_bandwidth=(vs!=NULL) ? (rtp_session_compute_recv_bandwidth(vs)*1e-3) : 0;
1923 call->stats[LINPHONE_CALL_STATS_VIDEO].upload_bandwidth=(vs!=NULL) ? (rtp_session_compute_send_bandwidth(vs)*1e-3) : 0;
1924 ms_message("bandwidth usage: audio=[d=%.1f,u=%.1f] video=[d=%.1f,u=%.1f] kbit/sec",
1925 call->stats[LINPHONE_CALL_STATS_AUDIO].download_bandwidth,
1926 call->stats[LINPHONE_CALL_STATS_AUDIO].upload_bandwidth ,
1927 call->stats[LINPHONE_CALL_STATS_VIDEO].download_bandwidth,
1928 call->stats[LINPHONE_CALL_STATS_VIDEO].upload_bandwidth
1932 static void linphone_core_disconnected(LinphoneCore *lc, LinphoneCall *call){
1936 from = linphone_call_get_remote_address_as_string(call);
1939 snprintf(temp,sizeof(temp),"Remote end %s seems to have disconnected, the call is going to be closed.",from);
1944 snprintf(temp,sizeof(temp),"Remote end seems to have disconnected, the call is going to be closed.");
1946 if (lc->vtable.display_warning!=NULL)
1947 lc->vtable.display_warning(lc,temp);
1948 linphone_core_terminate_call(lc,call);
1951 static void handle_ice_events(LinphoneCall *call, OrtpEvent *ev){
1952 OrtpEventType evt=ortp_event_get_type(ev);
1953 OrtpEventData *evd=ortp_event_get_data(ev);
1956 if (evt == ORTP_EVENT_ICE_SESSION_PROCESSING_FINISHED) {
1957 switch (ice_session_state(call->ice_session)) {
1959 ice_session_select_candidates(call->ice_session);
1960 if (ice_session_role(call->ice_session) == IR_Controlling) {
1961 linphone_core_update_call(call->core, call, &call->current_params);
1965 if (ice_session_has_completed_check_list(call->ice_session) == TRUE) {
1966 ice_session_select_candidates(call->ice_session);
1967 if (ice_session_role(call->ice_session) == IR_Controlling) {
1968 /* At least one ICE session has succeeded, so perform a call update. */
1969 linphone_core_update_call(call->core, call, &call->current_params);
1976 linphone_core_update_ice_state_in_call_stats(call);
1977 } else if (evt == ORTP_EVENT_ICE_GATHERING_FINISHED) {
1979 if (evd->info.ice_processing_successful==TRUE) {
1980 ice_session_compute_candidates_foundations(call->ice_session);
1981 ice_session_eliminate_redundant_candidates(call->ice_session);
1982 ice_session_choose_default_candidates(call->ice_session);
1983 ping_time = ice_session_average_gathering_round_trip_time(call->ice_session);
1984 if (ping_time >=0) {
1985 call->ping_time=ping_time;
1988 ms_warning("No STUN answer from [%s], disabling ICE",linphone_core_get_stun_server(call->core));
1989 linphone_call_delete_ice_session(call);
1991 switch (call->state) {
1992 case LinphoneCallUpdating:
1993 linphone_core_start_update_call(call->core, call);
1995 case LinphoneCallUpdatedByRemote:
1996 linphone_core_start_accept_call_update(call->core, call);
1998 case LinphoneCallOutgoingInit:
1999 linphone_call_stop_media_streams_for_ice_gathering(call);
2000 linphone_core_proceed_with_invite_if_ready(call->core, call, NULL);
2002 case LinphoneCallIdle:
2003 linphone_call_stop_media_streams_for_ice_gathering(call);
2004 linphone_core_notify_incoming_call(call->core, call);
2009 } else if (evt == ORTP_EVENT_ICE_LOSING_PAIRS_COMPLETED) {
2010 linphone_core_start_accept_call_update(call->core, call);
2011 linphone_core_update_ice_state_in_call_stats(call);
2012 } else if (evt == ORTP_EVENT_ICE_RESTART_NEEDED) {
2013 ice_session_restart(call->ice_session);
2014 ice_session_set_role(call->ice_session, IR_Controlling);
2015 linphone_core_update_call(call->core, call, &call->current_params);
2019 void linphone_call_background_tasks(LinphoneCall *call, bool_t one_second_elapsed){
2020 LinphoneCore* lc = call->core;
2021 int disconnect_timeout = linphone_core_get_nortp_timeout(call->core);
2022 bool_t disconnected=FALSE;
2024 if (call->state==LinphoneCallStreamsRunning && one_second_elapsed){
2025 RtpSession *as=NULL,*vs=NULL;
2026 float audio_load=0, video_load=0;
2027 if (call->audiostream!=NULL){
2028 as=call->audiostream->ms.session;
2029 if (call->audiostream->ms.ticker)
2030 audio_load=ms_ticker_get_average_load(call->audiostream->ms.ticker);
2032 if (call->videostream!=NULL){
2033 if (call->videostream->ms.ticker)
2034 video_load=ms_ticker_get_average_load(call->videostream->ms.ticker);
2035 vs=call->videostream->ms.session;
2037 report_bandwidth(call,as,vs);
2038 ms_message("Thread processing load: audio=%f\tvideo=%f",audio_load,video_load);
2040 #ifdef VIDEO_ENABLED
2041 if (call->videostream!=NULL) {
2044 /* Ensure there is no dangling ICE check list. */
2045 if (call->ice_session == NULL) call->videostream->ms.ice_check_list = NULL;
2047 // Beware that the application queue should not depend on treatments fron the
2048 // mediastreamer queue.
2049 video_stream_iterate(call->videostream);
2051 while (call->videostream_app_evq && (NULL != (ev=ortp_ev_queue_get(call->videostream_app_evq)))){
2052 OrtpEventType evt=ortp_event_get_type(ev);
2053 OrtpEventData *evd=ortp_event_get_data(ev);
2054 if (evt == ORTP_EVENT_ZRTP_ENCRYPTION_CHANGED){
2055 linphone_call_videostream_encryption_changed(call, evd->info.zrtp_stream_encrypted);
2056 } else if (evt == ORTP_EVENT_RTCP_PACKET_RECEIVED) {
2057 call->stats[LINPHONE_CALL_STATS_VIDEO].round_trip_delay = rtp_session_get_round_trip_propagation(call->videostream->ms.session);
2058 if(call->stats[LINPHONE_CALL_STATS_VIDEO].received_rtcp != NULL)
2059 freemsg(call->stats[LINPHONE_CALL_STATS_VIDEO].received_rtcp);
2060 call->stats[LINPHONE_CALL_STATS_VIDEO].received_rtcp = evd->packet;
2062 if (lc->vtable.call_stats_updated)
2063 lc->vtable.call_stats_updated(lc, call, &call->stats[LINPHONE_CALL_STATS_VIDEO]);
2064 } else if (evt == ORTP_EVENT_RTCP_PACKET_EMITTED) {
2065 memcpy(&call->stats[LINPHONE_CALL_STATS_VIDEO].jitter_stats, rtp_session_get_jitter_stats(call->videostream->ms.session), sizeof(jitter_stats_t));
2066 if(call->stats[LINPHONE_CALL_STATS_VIDEO].sent_rtcp != NULL)
2067 freemsg(call->stats[LINPHONE_CALL_STATS_VIDEO].sent_rtcp);
2068 call->stats[LINPHONE_CALL_STATS_VIDEO].sent_rtcp = evd->packet;
2070 if (lc->vtable.call_stats_updated)
2071 lc->vtable.call_stats_updated(lc, call, &call->stats[LINPHONE_CALL_STATS_VIDEO]);
2072 } else if ((evt == ORTP_EVENT_ICE_SESSION_PROCESSING_FINISHED) || (evt == ORTP_EVENT_ICE_GATHERING_FINISHED)
2073 || (evt == ORTP_EVENT_ICE_LOSING_PAIRS_COMPLETED) || (evt == ORTP_EVENT_ICE_RESTART_NEEDED)) {
2074 handle_ice_events(call, ev);
2076 ortp_event_destroy(ev);
2080 if (call->audiostream!=NULL) {
2083 /* Ensure there is no dangling ICE check list. */
2084 if (call->ice_session == NULL) call->audiostream->ms.ice_check_list = NULL;
2086 // Beware that the application queue should not depend on treatments fron the
2087 // mediastreamer queue.
2088 audio_stream_iterate(call->audiostream);
2090 while (call->audiostream_app_evq && (NULL != (ev=ortp_ev_queue_get(call->audiostream_app_evq)))){
2091 OrtpEventType evt=ortp_event_get_type(ev);
2092 OrtpEventData *evd=ortp_event_get_data(ev);
2093 if (evt == ORTP_EVENT_ZRTP_ENCRYPTION_CHANGED){
2094 linphone_call_audiostream_encryption_changed(call, evd->info.zrtp_stream_encrypted);
2095 } else if (evt == ORTP_EVENT_ZRTP_SAS_READY) {
2096 linphone_call_audiostream_auth_token_ready(call, evd->info.zrtp_sas.sas, evd->info.zrtp_sas.verified);
2097 } else if (evt == ORTP_EVENT_RTCP_PACKET_RECEIVED) {
2098 call->stats[LINPHONE_CALL_STATS_AUDIO].round_trip_delay = rtp_session_get_round_trip_propagation(call->audiostream->ms.session);
2099 if(call->stats[LINPHONE_CALL_STATS_AUDIO].received_rtcp != NULL)
2100 freemsg(call->stats[LINPHONE_CALL_STATS_AUDIO].received_rtcp);
2101 call->stats[LINPHONE_CALL_STATS_AUDIO].received_rtcp = evd->packet;
2103 if (lc->vtable.call_stats_updated)
2104 lc->vtable.call_stats_updated(lc, call, &call->stats[LINPHONE_CALL_STATS_AUDIO]);
2105 } else if (evt == ORTP_EVENT_RTCP_PACKET_EMITTED) {
2106 memcpy(&call->stats[LINPHONE_CALL_STATS_AUDIO].jitter_stats, rtp_session_get_jitter_stats(call->audiostream->ms.session), sizeof(jitter_stats_t));
2107 if(call->stats[LINPHONE_CALL_STATS_AUDIO].sent_rtcp != NULL)
2108 freemsg(call->stats[LINPHONE_CALL_STATS_AUDIO].sent_rtcp);
2109 call->stats[LINPHONE_CALL_STATS_AUDIO].sent_rtcp = evd->packet;
2111 if (lc->vtable.call_stats_updated)
2112 lc->vtable.call_stats_updated(lc, call, &call->stats[LINPHONE_CALL_STATS_AUDIO]);
2113 } else if ((evt == ORTP_EVENT_ICE_SESSION_PROCESSING_FINISHED) || (evt == ORTP_EVENT_ICE_GATHERING_FINISHED)
2114 || (evt == ORTP_EVENT_ICE_LOSING_PAIRS_COMPLETED) || (evt == ORTP_EVENT_ICE_RESTART_NEEDED)) {
2115 handle_ice_events(call, ev);
2116 } else if (evt==ORTP_EVENT_TELEPHONE_EVENT){
2117 linphone_core_dtmf_received(lc,evd->info.telephone_event);
2119 ortp_event_destroy(ev);
2122 if (call->state==LinphoneCallStreamsRunning && one_second_elapsed && call->audiostream!=NULL && disconnect_timeout>0 )
2123 disconnected=!audio_stream_alive(call->audiostream,disconnect_timeout);
2125 linphone_core_disconnected(call->core,call);
2128 void linphone_call_log_completed(LinphoneCall *call){
2129 LinphoneCore *lc=call->core;
2131 call->log->duration=time(NULL)-call->start_time;
2133 if (call->log->status==LinphoneCallMissed){
2136 info=ortp_strdup_printf(ngettext("You have missed %i call.",
2137 "You have missed %i calls.", lc->missed_calls),
2139 if (lc->vtable.display_status!=NULL)
2140 lc->vtable.display_status(lc,info);
2143 lc->call_logs=ms_list_prepend(lc->call_logs,(void *)call->log);
2144 if (ms_list_size(lc->call_logs)>lc->max_call_logs){
2145 MSList *elem,*prevelem=NULL;
2146 /*find the last element*/
2147 for(elem=lc->call_logs;elem!=NULL;elem=elem->next){
2151 linphone_call_log_destroy((LinphoneCallLog*)elem->data);
2152 lc->call_logs=ms_list_remove_link(lc->call_logs,elem);
2154 if (lc->vtable.call_log_updated!=NULL){
2155 lc->vtable.call_log_updated(lc,call->log);
2157 call_logs_write_to_config_file(lc);
2160 LinphoneCallState linphone_call_get_transfer_state(LinphoneCall *call) {
2161 return call->transfer_state;
2164 void linphone_call_set_transfer_state(LinphoneCall* call, LinphoneCallState state) {
2165 if (state != call->transfer_state) {
2166 LinphoneCore* lc = call->core;
2167 call->transfer_state = state;
2168 if (lc->vtable.transfer_state_changed)
2169 lc->vtable.transfer_state_changed(lc, call, state);
2174 * Returns true if the call is part of the conference.
2175 * @ingroup conferencing
2177 bool_t linphone_call_is_in_conference(const LinphoneCall *call) {
2178 return call->params.in_conference;
2183 * Perform a zoom of the video displayed during a call.
2184 * @param call the call.
2185 * @param zoom_factor a floating point number describing the zoom factor. A value 1.0 corresponds to no zoom applied.
2186 * @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.
2187 * @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.
2189 * 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.
2191 void linphone_call_zoom_video(LinphoneCall* call, float zoom_factor, float* cx, float* cy) {
2192 VideoStream* vstream = call->videostream;
2193 if (vstream && vstream->output) {
2196 if (zoom_factor < 1)
2198 float halfsize = 0.5 * 1.0 / zoom_factor;
2200 if ((*cx - halfsize) < 0)
2202 if ((*cx + halfsize) > 1)
2204 if ((*cy - halfsize) < 0)
2206 if ((*cy + halfsize) > 1)
2209 zoom[0] = zoom_factor;
2212 ms_filter_call_method(vstream->output, MS_VIDEO_DISPLAY_ZOOM, &zoom);
2213 }else ms_warning("Could not apply zoom: video output wasn't activated.");