4 Copyright (C) 2010 Belledonne Communications SARL
5 (simon.morlat@linphone.org)
7 This program is free software; you can redistribute it and/or
8 modify it under the terms of the GNU General Public License
9 as published by the Free Software Foundation; either version 2
10 of the License, or (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24 #include "linphonecore.h"
28 #include <ortp/event.h>
32 #include "mediastreamer2/mediastream.h"
33 #include "mediastreamer2/msvolume.h"
34 #include "mediastreamer2/msequalizer.h"
35 #include "mediastreamer2/msfileplayer.h"
36 #include "mediastreamer2/msjpegwriter.h"
37 #include "mediastreamer2/mseventqueue.h"
38 #include "mediastreamer2/mssndcard.h"
41 static MSWebCam *get_nowebcam_device(){
42 return ms_web_cam_manager_get_cam(ms_web_cam_manager_get(),"StaticImage: Static picture");
46 static bool_t generate_b64_crypto_key(int key_length, char* key_out) {
48 uint8_t* tmp = (uint8_t*) malloc(key_length);
49 if (ortp_crypto_get_random(tmp, key_length)!=0) {
50 ms_error("Failed to generate random key");
55 b64_size = b64_encode((const char*)tmp, key_length, NULL, 0);
57 ms_error("Failed to b64 encode key");
61 key_out[b64_size] = '\0';
62 b64_encode((const char*)tmp, key_length, key_out, 40);
67 LinphoneCore *linphone_call_get_core(const LinphoneCall *call){
71 const char* linphone_call_get_authentication_token(LinphoneCall *call){
72 return call->auth_token;
75 bool_t linphone_call_get_authentication_token_verified(LinphoneCall *call){
76 return call->auth_token_verified;
79 static bool_t linphone_call_are_all_streams_encrypted(LinphoneCall *call) {
80 // Check ZRTP encryption in audiostream
81 if (!call->audiostream_encrypted) {
86 // If video enabled, check ZRTP encryption in videostream
87 const LinphoneCallParams *params=linphone_call_get_current_params(call);
88 if (params->has_video && !call->videostream_encrypted) {
96 void propagate_encryption_changed(LinphoneCall *call){
97 LinphoneCore *lc=call->core;
98 if (!linphone_call_are_all_streams_encrypted(call)) {
99 ms_message("Some streams are not encrypted");
100 call->current_params.media_encryption=LinphoneMediaEncryptionNone;
101 if (lc->vtable.call_encryption_changed)
102 lc->vtable.call_encryption_changed(call->core, call, FALSE, call->auth_token);
104 ms_message("All streams are encrypted");
105 call->current_params.media_encryption=LinphoneMediaEncryptionZRTP;
106 if (lc->vtable.call_encryption_changed)
107 lc->vtable.call_encryption_changed(call->core, call, TRUE, call->auth_token);
112 static void linphone_call_videostream_encryption_changed(void *data, bool_t encrypted){
113 ms_message("Video stream is %s", encrypted ? "encrypted" : "not encrypted");
115 LinphoneCall *call = (LinphoneCall *)data;
116 call->videostream_encrypted=encrypted;
117 propagate_encryption_changed(call);
121 static void linphone_call_audiostream_encryption_changed(void *data, bool_t encrypted) {
122 char status[255]={0};
123 ms_message("Audio stream is %s ", encrypted ? "encrypted" : "not encrypted");
125 LinphoneCall *call = (LinphoneCall *)data;
126 call->audiostream_encrypted=encrypted;
128 if (encrypted && call->core->vtable.display_status != NULL) {
129 snprintf(status,sizeof(status)-1,_("Authentication token is %s"),call->auth_token);
130 call->core->vtable.display_status(call->core, status);
133 propagate_encryption_changed(call);
137 // Enable video encryption
138 const LinphoneCallParams *params=linphone_call_get_current_params(call);
139 if (params->has_video) {
140 ms_message("Trying to enable encryption on video stream");
141 OrtpZrtpParams params;
142 params.zid_file=NULL; //unused
143 video_stream_enable_zrtp(call->videostream,call->audiostream,¶ms);
149 static void linphone_call_audiostream_auth_token_ready(void *data, const char* auth_token, bool_t verified) {
150 LinphoneCall *call=(LinphoneCall *)data;
151 if (call->auth_token != NULL)
152 ms_free(call->auth_token);
154 call->auth_token=ms_strdup(auth_token);
155 call->auth_token_verified=verified;
157 ms_message("Authentication token is %s (%s)", auth_token, verified?"verified":"unverified");
160 void linphone_call_set_authentication_token_verified(LinphoneCall *call, bool_t verified){
161 if (call->audiostream==NULL){
162 ms_error("linphone_call_set_authentication_token_verified(): No audio stream");
164 if (call->audiostream->ortpZrtpContext==NULL){
165 ms_error("linphone_call_set_authentication_token_verified(): No zrtp context.");
167 if (!call->auth_token_verified && verified){
168 ortp_zrtp_sas_verified(call->audiostream->ortpZrtpContext);
169 }else if (call->auth_token_verified && !verified){
170 ortp_zrtp_sas_reset_verified(call->audiostream->ortpZrtpContext);
172 call->auth_token_verified=verified;
173 propagate_encryption_changed(call);
176 static MSList *make_codec_list(LinphoneCore *lc, const MSList *codecs, int bandwidth_limit,int* max_sample_rate){
179 if (max_sample_rate) *max_sample_rate=0;
180 for(it=codecs;it!=NULL;it=it->next){
181 PayloadType *pt=(PayloadType*)it->data;
182 if (pt->flags & PAYLOAD_TYPE_ENABLED){
183 if (bandwidth_limit>0 && !linphone_core_is_payload_type_usable_for_bandwidth(lc,pt,bandwidth_limit)){
184 ms_message("Codec %s/%i eliminated because of audio bandwidth constraint.",pt->mime_type,pt->clock_rate);
187 if (linphone_core_check_payload_type_usability(lc,pt)){
188 l=ms_list_append(l,payload_type_clone(pt));
189 if (max_sample_rate && payload_type_get_rate(pt)>*max_sample_rate) *max_sample_rate=payload_type_get_rate(pt);
196 static void update_media_description_from_stun(SalMediaDescription *md, const StunCandidate *ac, const StunCandidate *vc){
198 strcpy(md->streams[0].rtp_addr,ac->addr);
199 md->streams[0].rtp_port=ac->port;
200 if ((ac->addr[0]!='\0' && vc->addr[0]!='\0' && strcmp(ac->addr,vc->addr)==0) || md->nstreams==1){
201 strcpy(md->addr,ac->addr);
205 strcpy(md->streams[1].rtp_addr,vc->addr);
206 md->streams[1].rtp_port=vc->port;
211 void linphone_call_make_local_media_description(LinphoneCore *lc, LinphoneCall *call){
214 SalMediaDescription *old_md=call->localdesc;
216 const char *me=linphone_core_get_identity(lc);
217 LinphoneAddress *addr=linphone_address_new(me);
218 const char *username=linphone_address_get_username (addr);
219 SalMediaDescription *md=sal_media_description_new();
220 bool_t keep_srtp_keys=lp_config_get_int(lc->config,"sip","keep_srtp_keys",0);
222 linphone_core_adapt_to_network(lc,call->ping_time,&call->params);
224 md->session_id=(old_md ? old_md->session_id : (rand() & 0xfff));
225 md->session_ver=(old_md ? (old_md->session_ver+1) : (rand() & 0xfff));
227 strncpy(md->addr,call->localip,sizeof(md->addr));
228 strncpy(md->username,username,sizeof(md->username));
230 if (call->params.down_bw)
231 md->bandwidth=call->params.down_bw;
232 else md->bandwidth=linphone_core_get_download_bandwidth(lc);
234 /*set audio capabilities */
235 strncpy(md->streams[0].rtp_addr,call->localip,sizeof(md->streams[0].rtp_addr));
236 strncpy(md->streams[0].rtcp_addr,call->localip,sizeof(md->streams[0].rtcp_addr));
237 md->streams[0].rtp_port=call->audio_port;
238 md->streams[0].rtcp_port=call->audio_port+1;
239 md->streams[0].proto=(call->params.media_encryption == LinphoneMediaEncryptionSRTP) ?
240 SalProtoRtpSavp : SalProtoRtpAvp;
241 md->streams[0].type=SalAudio;
242 if (call->params.down_ptime)
243 md->streams[0].ptime=call->params.down_ptime;
245 md->streams[0].ptime=linphone_core_get_download_ptime(lc);
246 l=make_codec_list(lc,lc->codecs_conf.audio_codecs,call->params.audio_bw,&md->streams[0].max_rate);
247 pt=payload_type_clone(rtp_profile_get_payload_from_mime(&av_profile,"telephone-event"));
248 l=ms_list_append(l,pt);
249 md->streams[0].payloads=l;
251 if (call->params.has_video){
253 md->streams[1].rtp_port=call->video_port;
254 md->streams[1].rtcp_port=call->video_port+1;
255 md->streams[1].proto=md->streams[0].proto;
256 md->streams[1].type=SalVideo;
257 l=make_codec_list(lc,lc->codecs_conf.video_codecs,0,NULL);
258 md->streams[1].payloads=l;
261 for(i=0; i<md->nstreams; i++) {
262 if (md->streams[i].proto == SalProtoRtpSavp) {
263 if (keep_srtp_keys && old_md && old_md->streams[i].proto==SalProtoRtpSavp){
265 for(j=0;j<SAL_CRYPTO_ALGO_MAX;++j){
266 memcpy(&md->streams[i].crypto[j],&old_md->streams[i].crypto[j],sizeof(SalSrtpCryptoAlgo));
269 md->streams[i].crypto[0].tag = 1;
270 md->streams[i].crypto[0].algo = AES_128_SHA1_80;
271 if (!generate_b64_crypto_key(30, md->streams[i].crypto[0].master_key))
272 md->streams[i].crypto[0].algo = 0;
273 md->streams[i].crypto[1].tag = 2;
274 md->streams[i].crypto[1].algo = AES_128_SHA1_32;
275 if (!generate_b64_crypto_key(30, md->streams[i].crypto[1].master_key))
276 md->streams[i].crypto[1].algo = 0;
277 md->streams[i].crypto[2].algo = 0;
281 update_media_description_from_stun(md,&call->ac,&call->vc);
282 if (call->ice_session != NULL) {
283 linphone_core_update_local_media_description_from_ice(md, call->ice_session);
284 linphone_core_update_ice_state_in_call_stats(call);
287 if(call->upnp_session != NULL) {
288 linphone_core_update_local_media_description_from_upnp(md, call->upnp_session);
291 linphone_address_destroy(addr);
293 if (old_md) sal_media_description_unref(old_md);
296 static int find_port_offset(LinphoneCore *lc, SalStreamType type){
301 bool_t already_used=FALSE;
302 for(offset=0;offset<100;offset+=2){
306 tried_port=linphone_core_get_audio_port (lc)+offset;
309 tried_port=linphone_core_get_video_port (lc)+offset;
313 for(elem=lc->calls;elem!=NULL;elem=elem->next){
314 LinphoneCall *call=(LinphoneCall*)elem->data;
318 existing_port = call->audio_port;
321 existing_port = call->video_port;
324 if (existing_port==tried_port) {
329 if (!already_used) break;
332 ms_error("Could not find any free port !");
338 static int select_random_port(LinphoneCore *lc, SalStreamType type) {
342 int existing_port = 0;
343 int min_port = 0, max_port = 0;
344 bool_t already_used = FALSE;
349 linphone_core_get_audio_port_range(lc, &min_port, &max_port);
352 linphone_core_get_video_port_range(lc, &min_port, &max_port);
355 tried_port = (rand() % (max_port - min_port) + min_port) & ~0x1;
356 if (tried_port < min_port) tried_port = min_port + 2;
357 for (nb_tries = 0; nb_tries < 100; nb_tries++) {
358 for (elem = lc->calls; elem != NULL; elem = elem->next) {
359 LinphoneCall *call = (LinphoneCall *)elem->data;
363 existing_port = call->audio_port;
366 existing_port = call->video_port;
369 if (existing_port == tried_port) {
374 if (!already_used) break;
376 if (nb_tries == 100) {
377 ms_error("Could not find any free port!");
383 static void linphone_call_init_common(LinphoneCall *call, LinphoneAddress *from, LinphoneAddress *to){
385 int min_port, max_port;
386 call->magic=linphone_call_magic;
388 call->state=LinphoneCallIdle;
389 call->transfer_state = LinphoneCallIdle;
390 call->start_time=time(NULL);
391 call->media_start_time=0;
392 call->log=linphone_call_log_new(call, from, to);
393 call->owns_call_log=TRUE;
394 linphone_core_notify_all_friends(call->core,LinphoneStatusOnThePhone);
395 linphone_core_get_audio_port_range(call->core, &min_port, &max_port);
396 if (min_port == max_port) {
397 /* Used fixed RTP audio port. */
398 port_offset=find_port_offset (call->core, SalAudio);
399 if (port_offset==-1) return;
400 call->audio_port=linphone_core_get_audio_port(call->core)+port_offset;
402 /* Select random RTP audio port in the specified range. */
403 call->audio_port = select_random_port(call->core, SalAudio);
405 linphone_core_get_video_port_range(call->core, &min_port, &max_port);
406 if (min_port == max_port) {
407 /* Used fixed RTP video port. */
408 port_offset=find_port_offset (call->core, SalVideo);
409 if (port_offset==-1) return;
410 call->video_port=linphone_core_get_video_port(call->core)+port_offset;
412 /* Select random RTP video port in the specified range. */
413 call->video_port = select_random_port(call->core, SalVideo);
415 linphone_call_init_stats(&call->stats[LINPHONE_CALL_STATS_AUDIO], LINPHONE_CALL_STATS_AUDIO);
416 linphone_call_init_stats(&call->stats[LINPHONE_CALL_STATS_VIDEO], LINPHONE_CALL_STATS_VIDEO);
419 void linphone_call_init_stats(LinphoneCallStats *stats, int type) {
421 stats->received_rtcp = NULL;
422 stats->sent_rtcp = NULL;
423 stats->ice_state = LinphoneIceStateNotActivated;
427 static void discover_mtu(LinphoneCore *lc, const char *remote){
429 if (lc->net_conf.mtu==0 ){
430 /*attempt to discover mtu*/
431 mtu=ms_discover_mtu(remote);
434 ms_message("Discovered mtu is %i, RTP payload max size is %i",
435 mtu, ms_get_payload_max_size());
440 LinphoneCall * linphone_call_new_outgoing(struct _LinphoneCore *lc, LinphoneAddress *from, LinphoneAddress *to, const LinphoneCallParams *params)
442 LinphoneCall *call=ms_new0(LinphoneCall,1);
443 call->dir=LinphoneCallOutgoing;
444 call->op=sal_op_new(lc->sal);
445 sal_op_set_user_pointer(call->op,call);
447 linphone_core_get_local_ip(lc,linphone_address_get_domain(to),call->localip);
448 linphone_call_init_common(call,from,to);
449 call->params=*params;
450 if (linphone_core_get_firewall_policy(call->core) == LinphonePolicyUseIce) {
451 call->ice_session = ice_session_new();
452 ice_session_set_role(call->ice_session, IR_Controlling);
454 if (linphone_core_get_firewall_policy(call->core) == LinphonePolicyUseStun) {
455 call->ping_time=linphone_core_run_stun_tests(call->core,call);
458 if (linphone_core_get_firewall_policy(call->core) == LinphonePolicyUseUpnp) {
459 call->upnp_session = linphone_upnp_session_new(call);
462 call->camera_active=params->has_video;
464 discover_mtu(lc,linphone_address_get_domain (to));
465 if (params->referer){
466 sal_call_set_referer(call->op,params->referer->op);
467 call->referer=linphone_call_ref(params->referer);
472 LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *from, LinphoneAddress *to, SalOp *op){
473 LinphoneCall *call=ms_new0(LinphoneCall,1);
475 const SalMediaDescription *md;
477 call->dir=LinphoneCallIncoming;
478 sal_op_set_user_pointer(op,call);
482 if (lc->sip_conf.ping_with_options){
483 /*the following sends an option request back to the caller so that
484 we get a chance to discover our nat'd address before answering.*/
485 call->ping_op=sal_op_new(lc->sal);
486 from_str=linphone_address_as_string_uri_only(from);
487 sal_op_set_route(call->ping_op,sal_op_get_network_origin(op));
488 sal_op_set_user_pointer(call->ping_op,call);
489 sal_ping(call->ping_op,linphone_core_find_best_identity(lc,from,NULL),from_str);
493 linphone_address_clean(from);
494 linphone_core_get_local_ip(lc,linphone_address_get_domain(from),call->localip);
495 linphone_call_init_common(call, from, to);
496 call->log->call_id=ms_strdup(sal_op_get_call_id(op)); /*must be known at that time*/
497 linphone_core_init_default_params(lc, &call->params);
498 md=sal_call_get_remote_media_description(op);
499 call->params.has_video &= !!lc->video_policy.automatically_accept;
501 // It is licit to receive an INVITE without SDP
502 // In this case WE chose the media parameters according to policy.
503 call->params.has_video &= linphone_core_media_description_contains_video_stream(md);
505 switch (linphone_core_get_firewall_policy(call->core)) {
506 case LinphonePolicyUseIce:
507 call->ice_session = ice_session_new();
508 ice_session_set_role(call->ice_session, IR_Controlled);
509 linphone_core_update_ice_from_remote_media_description(call, sal_call_get_remote_media_description(op));
510 if (call->ice_session != NULL) {
511 linphone_call_init_media_streams(call);
512 linphone_call_start_media_streams_for_ice_gathering(call);
513 if (linphone_core_gather_ice_candidates(call->core,call)<0) {
514 /* Ice candidates gathering failed, proceed with the call anyway. */
515 linphone_call_delete_ice_session(call);
516 linphone_call_stop_media_streams_for_ice_gathering(call);
520 case LinphonePolicyUseStun:
521 call->ping_time=linphone_core_run_stun_tests(call->core,call);
522 /* No break to also destroy ice session in this case. */
524 case LinphonePolicyUseUpnp:
526 call->upnp_session = linphone_upnp_session_new(call);
527 if (call->upnp_session != NULL) {
528 linphone_call_init_media_streams(call);
529 if (linphone_core_update_upnp_from_remote_media_description(call, sal_call_get_remote_media_description(op))<0) {
530 /* uPnP port mappings failed, proceed with the call anyway. */
531 linphone_call_delete_upnp_session(call);
539 call->camera_active=call->params.has_video;
541 discover_mtu(lc,linphone_address_get_domain(from));
545 /* this function is called internally to get rid of a call.
546 It performs the following tasks:
547 - remove the call from the internal list of calls
548 - update the call logs accordingly
551 static void linphone_call_set_terminated(LinphoneCall *call){
552 LinphoneCore *lc=call->core;
554 linphone_core_update_allocated_audio_bandwidth(lc);
556 call->owns_call_log=FALSE;
557 linphone_call_log_completed(call);
560 if (call == lc->current_call){
561 ms_message("Resetting the current call");
562 lc->current_call=NULL;
565 if (linphone_core_del_call(lc,call) != 0){
566 ms_error("Could not remove the call from the list !!!");
569 if (ms_list_size(lc->calls)==0)
570 linphone_core_notify_all_friends(lc,lc->presence_mode);
572 linphone_core_conference_check_uninit(lc);
573 if (call->ringing_beep){
574 linphone_core_stop_dtmf(lc);
575 call->ringing_beep=FALSE;
578 linphone_call_unref(call->referer);
583 void linphone_call_fix_call_parameters(LinphoneCall *call){
584 call->params.has_video=call->current_params.has_video;
585 call->params.media_encryption=call->current_params.media_encryption;
588 const char *linphone_call_state_to_string(LinphoneCallState cs){
590 case LinphoneCallIdle:
591 return "LinphoneCallIdle";
592 case LinphoneCallIncomingReceived:
593 return "LinphoneCallIncomingReceived";
594 case LinphoneCallOutgoingInit:
595 return "LinphoneCallOutgoingInit";
596 case LinphoneCallOutgoingProgress:
597 return "LinphoneCallOutgoingProgress";
598 case LinphoneCallOutgoingRinging:
599 return "LinphoneCallOutgoingRinging";
600 case LinphoneCallOutgoingEarlyMedia:
601 return "LinphoneCallOutgoingEarlyMedia";
602 case LinphoneCallConnected:
603 return "LinphoneCallConnected";
604 case LinphoneCallStreamsRunning:
605 return "LinphoneCallStreamsRunning";
606 case LinphoneCallPausing:
607 return "LinphoneCallPausing";
608 case LinphoneCallPaused:
609 return "LinphoneCallPaused";
610 case LinphoneCallResuming:
611 return "LinphoneCallResuming";
612 case LinphoneCallRefered:
613 return "LinphoneCallRefered";
614 case LinphoneCallError:
615 return "LinphoneCallError";
616 case LinphoneCallEnd:
617 return "LinphoneCallEnd";
618 case LinphoneCallPausedByRemote:
619 return "LinphoneCallPausedByRemote";
620 case LinphoneCallUpdatedByRemote:
621 return "LinphoneCallUpdatedByRemote";
622 case LinphoneCallIncomingEarlyMedia:
623 return "LinphoneCallIncomingEarlyMedia";
624 case LinphoneCallUpdating:
625 return "LinphoneCallUpdating";
626 case LinphoneCallReleased:
627 return "LinphoneCallReleased";
629 return "undefined state";
632 void linphone_call_set_state(LinphoneCall *call, LinphoneCallState cstate, const char *message){
633 LinphoneCore *lc=call->core;
635 if (call->state!=cstate){
636 if (call->state==LinphoneCallEnd || call->state==LinphoneCallError){
637 if (cstate!=LinphoneCallReleased){
638 ms_warning("Spurious call state change from %s to %s, ignored.",linphone_call_state_to_string(call->state),
639 linphone_call_state_to_string(cstate));
643 ms_message("Call %p: moving from state %s to %s",call,linphone_call_state_to_string(call->state),
644 linphone_call_state_to_string(cstate));
645 if (cstate!=LinphoneCallRefered){
646 /*LinphoneCallRefered is rather an event, not a state.
647 Indeed it does not change the state of the call (still paused or running)*/
650 if (cstate==LinphoneCallEnd || cstate==LinphoneCallError){
651 switch(call->reason){
652 case LinphoneReasonDeclined:
653 call->log->status=LinphoneCallDeclined;
655 case LinphoneReasonNotAnswered:
656 call->log->status=LinphoneCallMissed;
661 linphone_call_set_terminated (call);
663 if (cstate == LinphoneCallConnected) {
664 call->log->status=LinphoneCallSuccess;
665 call->media_start_time=time(NULL);
668 if (lc->vtable.call_state_changed)
669 lc->vtable.call_state_changed(lc,call,cstate,message);
670 if (cstate==LinphoneCallReleased){
671 if (call->op!=NULL) {
672 /* so that we cannot have anymore upcalls for SAL
673 concerning this call*/
674 sal_op_release(call->op);
677 linphone_call_unref(call);
682 static void linphone_call_destroy(LinphoneCall *obj)
685 linphone_call_delete_upnp_session(obj);
687 linphone_call_delete_ice_session(obj);
689 sal_op_release(obj->op);
692 if (obj->resultdesc!=NULL) {
693 sal_media_description_unref(obj->resultdesc);
694 obj->resultdesc=NULL;
696 if (obj->localdesc!=NULL) {
697 sal_media_description_unref(obj->localdesc);
701 sal_op_release(obj->ping_op);
704 ms_free(obj->refer_to);
706 if (obj->owns_call_log)
707 linphone_call_log_destroy(obj->log);
708 if (obj->auth_token) {
709 ms_free(obj->auth_token);
716 * @addtogroup call_control
721 * Increments the call 's reference count.
722 * An application that wishes to retain a pointer to call object
723 * must use this function to unsure the pointer remains
724 * valid. Once the application no more needs this pointer,
725 * it must call linphone_call_unref().
727 LinphoneCall * linphone_call_ref(LinphoneCall *obj){
733 * Decrements the call object reference count.
734 * See linphone_call_ref().
736 void linphone_call_unref(LinphoneCall *obj){
739 linphone_call_destroy(obj);
744 * Returns current parameters associated to the call.
746 const LinphoneCallParams * linphone_call_get_current_params(const LinphoneCall *call){
747 return &call->current_params;
750 static bool_t is_video_active(const SalStreamDescription *sd){
751 return sd->rtp_port!=0 && sd->dir!=SalStreamInactive;
755 * Returns call parameters proposed by remote.
757 * This is useful when receiving an incoming call, to know whether the remote party
758 * supports video, encryption or whatever.
760 const LinphoneCallParams * linphone_call_get_remote_params(LinphoneCall *call){
761 LinphoneCallParams *cp=&call->remote_params;
762 memset(cp,0,sizeof(*cp));
764 SalMediaDescription *md=sal_call_get_remote_media_description(call->op);
766 SalStreamDescription *asd,*vsd,*secure_asd,*secure_vsd;
768 asd=sal_media_description_find_stream(md,SalProtoRtpAvp,SalAudio);
769 vsd=sal_media_description_find_stream(md,SalProtoRtpAvp,SalVideo);
770 secure_asd=sal_media_description_find_stream(md,SalProtoRtpSavp,SalAudio);
771 secure_vsd=sal_media_description_find_stream(md,SalProtoRtpSavp,SalVideo);
773 cp->has_video=is_video_active(secure_vsd);
774 if (secure_asd || asd==NULL)
775 cp->media_encryption=LinphoneMediaEncryptionSRTP;
777 cp->has_video=is_video_active(vsd);
780 if (md->bandwidth>0 && md->bandwidth<=linphone_core_get_edge_bw(call->core)){
781 cp->low_bandwidth=TRUE;
791 * Returns the remote address associated to this call
794 const LinphoneAddress * linphone_call_get_remote_address(const LinphoneCall *call){
795 return call->dir==LinphoneCallIncoming ? call->log->from : call->log->to;
799 * Returns the remote address associated to this call as a string.
801 * The result string must be freed by user using ms_free().
803 char *linphone_call_get_remote_address_as_string(const LinphoneCall *call){
804 return linphone_address_as_string(linphone_call_get_remote_address(call));
808 * Retrieves the call's current state.
810 LinphoneCallState linphone_call_get_state(const LinphoneCall *call){
815 * Returns the reason for a call termination (either error or normal termination)
817 LinphoneReason linphone_call_get_reason(const LinphoneCall *call){
822 * Get the user_pointer in the LinphoneCall
824 * @ingroup call_control
826 * return user_pointer an opaque user pointer that can be retrieved at any time
828 void *linphone_call_get_user_pointer(LinphoneCall *call)
830 return call->user_pointer;
834 * Set the user_pointer in the LinphoneCall
836 * @ingroup call_control
838 * the user_pointer is an opaque user pointer that can be retrieved at any time in the LinphoneCall
840 void linphone_call_set_user_pointer(LinphoneCall *call, void *user_pointer)
842 call->user_pointer = user_pointer;
846 * Returns the call log associated to this call.
848 LinphoneCallLog *linphone_call_get_call_log(const LinphoneCall *call){
853 * Returns the refer-to uri (if the call was transfered).
855 const char *linphone_call_get_refer_to(const LinphoneCall *call){
856 return call->refer_to;
860 * Returns direction of the call (incoming or outgoing).
862 LinphoneCallDir linphone_call_get_dir(const LinphoneCall *call){
863 return call->log->dir;
867 * Returns the far end's user agent description string, if available.
869 const char *linphone_call_get_remote_user_agent(LinphoneCall *call){
871 return sal_op_get_remote_ua (call->op);
877 * Returns true if this calls has received a transfer that has not been
879 * Pending transfers are executed when this call is being paused or closed,
880 * locally or by remote endpoint.
881 * If the call is already paused while receiving the transfer request, the
882 * transfer immediately occurs.
884 bool_t linphone_call_has_transfer_pending(const LinphoneCall *call){
885 return call->refer_pending;
889 * Returns call's duration in seconds.
891 int linphone_call_get_duration(const LinphoneCall *call){
892 if (call->media_start_time==0) return 0;
893 return time(NULL)-call->media_start_time;
897 * Returns the call object this call is replacing, if any.
898 * Call replacement can occur during call transfers.
899 * By default, the core automatically terminates the replaced call and accept the new one.
900 * This function allows the application to know whether a new incoming call is a one that replaces another one.
902 LinphoneCall *linphone_call_get_replaced_call(LinphoneCall *call){
903 SalOp *op=sal_call_get_replaces(call->op);
905 return (LinphoneCall*)sal_op_get_user_pointer(op);
911 * Indicate whether camera input should be sent to remote end.
913 void linphone_call_enable_camera (LinphoneCall *call, bool_t enable){
915 if (call->videostream!=NULL && call->videostream->ticker!=NULL){
916 LinphoneCore *lc=call->core;
917 MSWebCam *nowebcam=get_nowebcam_device();
918 if (call->camera_active!=enable && lc->video_conf.device!=nowebcam){
919 video_stream_change_camera(call->videostream,
920 enable ? lc->video_conf.device : nowebcam);
923 call->camera_active=enable;
928 * Take a photo of currently received video and write it into a jpeg file.
930 int linphone_call_take_video_snapshot(LinphoneCall *call, const char *file){
932 if (call->videostream!=NULL && call->videostream->jpegwriter!=NULL){
933 return ms_filter_call_method(call->videostream->jpegwriter,MS_JPEG_WRITER_TAKE_SNAPSHOT,(void*)file);
935 ms_warning("Cannot take snapshot: no currently running video stream on this call.");
942 * Returns TRUE if camera pictures are sent to the remote party.
944 bool_t linphone_call_camera_enabled (const LinphoneCall *call){
945 return call->camera_active;
949 * Enable video stream.
951 void linphone_call_params_enable_video(LinphoneCallParams *cp, bool_t enabled){
952 cp->has_video=enabled;
955 const PayloadType* linphone_call_params_get_used_audio_codec(const LinphoneCallParams *cp) {
956 return cp->audio_codec;
959 const PayloadType* linphone_call_params_get_used_video_codec(const LinphoneCallParams *cp) {
960 return cp->video_codec;
964 * @ingroup call_control
965 * Use to know if this call has been configured in low bandwidth mode.
966 * This mode can be automatically discovered thanks to a stun server when activate_edge_workarounds=1 in section [net] of configuration file.
967 * An application that would have reliable way to know network capacity may not use activate_edge_workarounds=1 but instead manually configure
968 * low bandwidth mode with linphone_call_params_enable_low_bandwidth().
969 * <br> When enabled, this param may transform a call request with video in audio only mode.
970 * @return TRUE if low bandwidth has been configured/detected
972 bool_t linphone_call_params_low_bandwidth_enabled(const LinphoneCallParams *cp) {
973 return cp->low_bandwidth;
977 * @ingroup call_control
978 * Indicate low bandwith mode.
979 * 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
980 * 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
981 * that it is achievable by the codec selected after SDP handshake. Video is automatically disabled.
984 void linphone_call_params_enable_low_bandwidth(LinphoneCallParams *cp, bool_t enabled){
985 cp->low_bandwidth=enabled;
989 * Returns whether video is enabled.
991 bool_t linphone_call_params_video_enabled(const LinphoneCallParams *cp){
992 return cp->has_video;
995 enum LinphoneMediaEncryption linphone_call_params_get_media_encryption(const LinphoneCallParams *cp) {
996 return cp->media_encryption;
999 void linphone_call_params_set_media_encryption(LinphoneCallParams *cp, enum LinphoneMediaEncryption e) {
1000 cp->media_encryption = e;
1005 * Enable sending of real early media (during outgoing calls).
1007 void linphone_call_params_enable_early_media_sending(LinphoneCallParams *cp, bool_t enabled){
1008 cp->real_early_media=enabled;
1011 bool_t linphone_call_params_early_media_sending_enabled(const LinphoneCallParams *cp){
1012 return cp->real_early_media;
1016 * Returns true if the call is part of the locally managed conference.
1018 bool_t linphone_call_params_local_conference_mode(const LinphoneCallParams *cp){
1019 return cp->in_conference;
1023 * Refine bandwidth settings for this call by setting a bandwidth limit for audio streams.
1024 * As a consequence, codecs whose bitrates are not compatible with this limit won't be used.
1026 void linphone_call_params_set_audio_bandwidth_limit(LinphoneCallParams *cp, int bandwidth){
1027 cp->audio_bw=bandwidth;
1030 #ifdef VIDEO_ENABLED
1032 * Request remote side to send us a Video Fast Update.
1034 void linphone_call_send_vfu_request(LinphoneCall *call)
1036 if (LinphoneCallStreamsRunning == linphone_call_get_state(call))
1037 sal_call_send_vfu_request(call->op);
1044 LinphoneCallParams * linphone_call_params_copy(const LinphoneCallParams *cp){
1045 LinphoneCallParams *ncp=ms_new0(LinphoneCallParams,1);
1046 memcpy(ncp,cp,sizeof(LinphoneCallParams));
1053 void linphone_call_params_destroy(LinphoneCallParams *p){
1062 #ifdef TEST_EXT_RENDERER
1063 static void rendercb(void *data, const MSPicture *local, const MSPicture *remote){
1064 ms_message("rendercb, local buffer=%p, remote buffer=%p",
1065 local ? local->planes[0] : NULL, remote? remote->planes[0] : NULL);
1069 #ifdef VIDEO_ENABLED
1070 static void video_stream_event_cb(void *user_pointer, const MSFilter *f, const unsigned int event_id, const void *args){
1071 LinphoneCall* call = (LinphoneCall*) user_pointer;
1072 ms_warning("In linphonecall.c: video_stream_event_cb");
1074 case MS_VIDEO_DECODER_DECODING_ERRORS:
1075 ms_warning("Case is MS_VIDEO_DECODER_DECODING_ERRORS");
1076 linphone_call_send_vfu_request(call);
1078 case MS_VIDEO_DECODER_FIRST_IMAGE_DECODED:
1079 ms_message("First video frame decoded successfully");
1080 if (call->nextVideoFrameDecoded._func != NULL)
1081 call->nextVideoFrameDecoded._func(call, call->nextVideoFrameDecoded._user_data);
1084 ms_warning("Unhandled event %i", event_id);
1090 void linphone_call_set_next_video_frame_decoded_callback(LinphoneCall *call, LinphoneCallCbFunc cb, void* user_data) {
1091 call->nextVideoFrameDecoded._func = cb;
1092 call->nextVideoFrameDecoded._user_data = user_data;
1093 #ifdef VIDEO_ENABLED
1094 ms_filter_call_method_noarg(call->videostream->decoder, MS_VIDEO_DECODER_RESET_FIRST_IMAGE_NOTIFICATION);
1098 void linphone_call_init_audio_stream(LinphoneCall *call){
1099 LinphoneCore *lc=call->core;
1100 AudioStream *audiostream;
1103 if (call->audiostream != NULL) return;
1104 call->audiostream=audiostream=audio_stream_new(call->audio_port,call->audio_port+1,linphone_core_ipv6_enabled(lc));
1105 dscp=linphone_core_get_audio_dscp(lc);
1107 audio_stream_set_dscp(audiostream,dscp);
1108 if (linphone_core_echo_limiter_enabled(lc)){
1109 const char *type=lp_config_get_string(lc->config,"sound","el_type","mic");
1110 if (strcasecmp(type,"mic")==0)
1111 audio_stream_enable_echo_limiter(audiostream,ELControlMic);
1112 else if (strcasecmp(type,"full")==0)
1113 audio_stream_enable_echo_limiter(audiostream,ELControlFull);
1115 audio_stream_enable_gain_control(audiostream,TRUE);
1116 if (linphone_core_echo_cancellation_enabled(lc)){
1117 int len,delay,framesize;
1118 const char *statestr=lp_config_get_string(lc->config,"sound","ec_state",NULL);
1119 len=lp_config_get_int(lc->config,"sound","ec_tail_len",0);
1120 delay=lp_config_get_int(lc->config,"sound","ec_delay",0);
1121 framesize=lp_config_get_int(lc->config,"sound","ec_framesize",0);
1122 audio_stream_set_echo_canceller_params(audiostream,len,delay,framesize);
1123 if (statestr && audiostream->ec){
1124 ms_filter_call_method(audiostream->ec,MS_ECHO_CANCELLER_SET_STATE_STRING,(void*)statestr);
1127 audio_stream_enable_automatic_gain_control(audiostream,linphone_core_agc_enabled(lc));
1129 int enabled=lp_config_get_int(lc->config,"sound","noisegate",0);
1130 audio_stream_enable_noise_gate(audiostream,enabled);
1133 audio_stream_set_features(audiostream,linphone_core_get_audio_features(lc));
1136 RtpTransport *artp=lc->rtptf->audio_rtp_func(lc->rtptf->audio_rtp_func_data, call->audio_port);
1137 RtpTransport *artcp=lc->rtptf->audio_rtcp_func(lc->rtptf->audio_rtcp_func_data, call->audio_port+1);
1138 rtp_session_set_transports(audiostream->session,artp,artcp);
1140 if ((linphone_core_get_firewall_policy(lc) == LinphonePolicyUseIce) && (call->ice_session != NULL)){
1141 rtp_session_set_pktinfo(audiostream->session, TRUE);
1142 rtp_session_set_symmetric_rtp(audiostream->session, FALSE);
1143 if (ice_session_check_list(call->ice_session, 0) == NULL) {
1144 ice_session_add_check_list(call->ice_session, ice_check_list_new());
1146 audiostream->ice_check_list = ice_session_check_list(call->ice_session, 0);
1147 ice_check_list_set_rtp_session(audiostream->ice_check_list, audiostream->session);
1150 call->audiostream_app_evq = ortp_ev_queue_new();
1151 rtp_session_register_event_queue(audiostream->session,call->audiostream_app_evq);
1154 void linphone_call_init_video_stream(LinphoneCall *call){
1155 #ifdef VIDEO_ENABLED
1156 LinphoneCore *lc=call->core;
1158 if (!call->params.has_video) {
1159 linphone_call_stop_video_stream(call);
1162 if (call->videostream != NULL) return;
1163 if ((lc->video_conf.display || lc->video_conf.capture) && call->params.has_video){
1164 int video_recv_buf_size=lp_config_get_int(lc->config,"video","recv_buf_size",0);
1165 int dscp=linphone_core_get_video_dscp(lc);
1167 call->videostream=video_stream_new(call->video_port,call->video_port+1,linphone_core_ipv6_enabled(lc));
1169 video_stream_set_dscp(call->videostream,dscp);
1170 video_stream_enable_display_filter_auto_rotate(call->videostream, lp_config_get_int(lc->config,"video","display_filter_auto_rotate",0));
1171 if (video_recv_buf_size>0) rtp_session_set_recv_buf_size(call->videostream->session,video_recv_buf_size);
1173 if( lc->video_conf.displaytype != NULL)
1174 video_stream_set_display_filter_name(call->videostream,lc->video_conf.displaytype);
1175 video_stream_set_event_callback(call->videostream,video_stream_event_cb, call);
1177 RtpTransport *vrtp=lc->rtptf->video_rtp_func(lc->rtptf->video_rtp_func_data, call->video_port);
1178 RtpTransport *vrtcp=lc->rtptf->video_rtcp_func(lc->rtptf->video_rtcp_func_data, call->video_port+1);
1179 rtp_session_set_transports(call->videostream->session,vrtp,vrtcp);
1181 if ((linphone_core_get_firewall_policy(lc) == LinphonePolicyUseIce) && (call->ice_session != NULL)){
1182 rtp_session_set_pktinfo(call->videostream->session, TRUE);
1183 rtp_session_set_symmetric_rtp(call->videostream->session, FALSE);
1184 if (ice_session_check_list(call->ice_session, 1) == NULL) {
1185 ice_session_add_check_list(call->ice_session, ice_check_list_new());
1187 call->videostream->ice_check_list = ice_session_check_list(call->ice_session, 1);
1188 ice_check_list_set_rtp_session(call->videostream->ice_check_list, call->videostream->session);
1190 call->videostream_app_evq = ortp_ev_queue_new();
1191 rtp_session_register_event_queue(call->videostream->session,call->videostream_app_evq);
1192 #ifdef TEST_EXT_RENDERER
1193 video_stream_set_render_callback(call->videostream,rendercb,NULL);
1197 call->videostream=NULL;
1201 void linphone_call_init_media_streams(LinphoneCall *call){
1202 linphone_call_init_audio_stream(call);
1203 linphone_call_init_video_stream(call);
1207 static int dtmf_tab[16]={'0','1','2','3','4','5','6','7','8','9','*','#','A','B','C','D'};
1209 static void linphone_core_dtmf_received(LinphoneCore *lc, int dtmf){
1210 if (dtmf<0 || dtmf>15){
1211 ms_warning("Bad dtmf value %i",dtmf);
1214 if (lc->vtable.dtmf_received != NULL)
1215 lc->vtable.dtmf_received(lc, linphone_core_get_current_call(lc), dtmf_tab[dtmf]);
1218 static void parametrize_equalizer(LinphoneCore *lc, AudioStream *st){
1220 MSFilter *f=st->equalizer;
1221 int enabled=lp_config_get_int(lc->config,"sound","eq_active",0);
1222 const char *gains=lp_config_get_string(lc->config,"sound","eq_gains",NULL);
1223 ms_filter_call_method(f,MS_EQUALIZER_SET_ACTIVE,&enabled);
1229 if (sscanf(gains,"%f:%f:%f %n",&g.frequency,&g.gain,&g.width,&bytes)==3){
1230 ms_message("Read equalizer gains: %f(~%f) --> %f",g.frequency,g.width,g.gain);
1231 ms_filter_call_method(f,MS_EQUALIZER_SET_GAIN,&g);
1240 void _post_configure_audio_stream(AudioStream *st, LinphoneCore *lc, bool_t muted){
1241 float mic_gain=lc->sound_conf.soft_mic_lev;
1244 float ng_thres=lp_config_get_float(lc->config,"sound","ng_thres",0.05);
1245 float ng_floorgain=lp_config_get_float(lc->config,"sound","ng_floorgain",0);
1246 int dc_removal=lp_config_get_int(lc->config,"sound","dc_removal",0);
1249 linphone_core_set_mic_gain_db (lc, mic_gain);
1251 audio_stream_set_mic_gain(st,0);
1253 recv_gain = lc->sound_conf.soft_play_lev;
1254 if (recv_gain != 0) {
1255 linphone_core_set_playback_gain_db (lc,recv_gain);
1259 ms_filter_call_method(st->volsend,MS_VOLUME_REMOVE_DC,&dc_removal);
1260 float speed=lp_config_get_float(lc->config,"sound","el_speed",-1);
1261 thres=lp_config_get_float(lc->config,"sound","el_thres",-1);
1262 float force=lp_config_get_float(lc->config,"sound","el_force",-1);
1263 int sustain=lp_config_get_int(lc->config,"sound","el_sustain",-1);
1264 float transmit_thres=lp_config_get_float(lc->config,"sound","el_transmit_thres",-1);
1267 if (speed==-1) speed=0.03;
1268 if (force==-1) force=25;
1269 ms_filter_call_method(f,MS_VOLUME_SET_EA_SPEED,&speed);
1270 ms_filter_call_method(f,MS_VOLUME_SET_EA_FORCE,&force);
1272 ms_filter_call_method(f,MS_VOLUME_SET_EA_THRESHOLD,&thres);
1274 ms_filter_call_method(f,MS_VOLUME_SET_EA_SUSTAIN,&sustain);
1275 if (transmit_thres!=-1)
1276 ms_filter_call_method(f,MS_VOLUME_SET_EA_TRANSMIT_THRESHOLD,&transmit_thres);
1278 ms_filter_call_method(st->volsend,MS_VOLUME_SET_NOISE_GATE_THRESHOLD,&ng_thres);
1279 ms_filter_call_method(st->volsend,MS_VOLUME_SET_NOISE_GATE_FLOORGAIN,&ng_floorgain);
1282 /* parameters for a limited noise-gate effect, using echo limiter threshold */
1283 float floorgain = 1/pow(10,(mic_gain)/10);
1284 int spk_agc=lp_config_get_int(lc->config,"sound","speaker_agc_enabled",0);
1285 ms_filter_call_method(st->volrecv, MS_VOLUME_ENABLE_AGC, &spk_agc);
1286 ms_filter_call_method(st->volrecv,MS_VOLUME_SET_NOISE_GATE_THRESHOLD,&ng_thres);
1287 ms_filter_call_method(st->volrecv,MS_VOLUME_SET_NOISE_GATE_FLOORGAIN,&floorgain);
1289 parametrize_equalizer(lc,st);
1292 static void post_configure_audio_streams(LinphoneCall*call){
1293 AudioStream *st=call->audiostream;
1294 LinphoneCore *lc=call->core;
1295 _post_configure_audio_stream(st,lc,call->audio_muted);
1296 if (lc->vtable.dtmf_received!=NULL){
1297 /* replace by our default action*/
1298 audio_stream_play_received_dtmfs(call->audiostream,FALSE);
1299 /*rtp_session_signal_connect(call->audiostream->session,"telephone-event",(RtpCallback)linphone_core_dtmf_received,(unsigned long)lc);*/
1303 static RtpProfile *make_profile(LinphoneCall *call, const SalMediaDescription *md, const SalStreamDescription *desc, int *used_pt){
1306 RtpProfile *prof=rtp_profile_new("Call profile");
1309 LinphoneCore *lc=call->core;
1311 const LinphoneCallParams *params=&call->params;
1314 for(elem=desc->payloads;elem!=NULL;elem=elem->next){
1315 PayloadType *pt=(PayloadType*)elem->data;
1318 if ((pt->flags & PAYLOAD_TYPE_FLAG_CAN_SEND) && first) {
1319 if (desc->type==SalAudio){
1320 linphone_core_update_allocated_audio_bandwidth_in_call(call,pt);
1321 if (params->up_ptime)
1322 up_ptime=params->up_ptime;
1323 else up_ptime=linphone_core_get_upload_ptime(lc);
1325 *used_pt=payload_type_get_number(pt);
1328 if (desc->bandwidth>0) remote_bw=desc->bandwidth;
1329 else if (md->bandwidth>0) {
1330 /*case where b=AS is given globally, not per stream*/
1331 remote_bw=md->bandwidth;
1332 if (desc->type==SalVideo){
1333 remote_bw=get_video_bandwidth(remote_bw,call->audio_bw);
1337 if (desc->type==SalAudio){
1338 int audio_bw=call->audio_bw;
1340 if (params->up_bw< audio_bw)
1341 audio_bw=params->up_bw;
1343 bw=get_min_bandwidth(audio_bw,remote_bw);
1344 }else bw=get_min_bandwidth(get_video_bandwidth(linphone_core_get_upload_bandwidth (lc),call->audio_bw),remote_bw);
1345 if (bw>0) pt->normal_bitrate=bw*1000;
1346 else if (desc->type==SalAudio){
1347 pt->normal_bitrate=-1;
1350 up_ptime=desc->ptime;
1354 snprintf(tmp,sizeof(tmp),"ptime=%i",up_ptime);
1355 payload_type_append_send_fmtp(pt,tmp);
1357 number=payload_type_get_number(pt);
1358 if (rtp_profile_get_payload(prof,number)!=NULL){
1359 ms_warning("A payload type with number %i already exists in profile !",number);
1361 rtp_profile_set_payload(prof,number,pt);
1367 static void setup_ring_player(LinphoneCore *lc, LinphoneCall *call){
1368 int pause_time=3000;
1369 audio_stream_play(call->audiostream,lc->sound_conf.ringback_tone);
1370 ms_filter_call_method(call->audiostream->soundread,MS_FILE_PLAYER_LOOP,&pause_time);
1373 static bool_t linphone_call_sound_resources_available(LinphoneCall *call){
1374 LinphoneCore *lc=call->core;
1375 LinphoneCall *current=linphone_core_get_current_call(lc);
1376 return !linphone_core_is_in_conference(lc) &&
1377 (current==NULL || current==call);
1379 static int find_crypto_index_from_tag(const SalSrtpCryptoAlgo crypto[],unsigned char tag) {
1381 for(i=0; i<SAL_CRYPTO_ALGO_MAX; i++) {
1382 if (crypto[i].tag == tag) {
1388 static void linphone_call_start_audio_stream(LinphoneCall *call, const char *cname, bool_t muted, bool_t send_ringbacktone, bool_t use_arc){
1389 LinphoneCore *lc=call->core;
1391 char rtcp_tool[128]={0};
1392 snprintf(rtcp_tool,sizeof(rtcp_tool)-1,"%s-%s",linphone_core_get_user_agent_name(),linphone_core_get_user_agent_version());
1393 /* look for savp stream first */
1394 const SalStreamDescription *stream=sal_media_description_find_stream(call->resultdesc,
1395 SalProtoRtpSavp,SalAudio);
1396 /* no savp audio stream, use avp */
1398 stream=sal_media_description_find_stream(call->resultdesc,
1399 SalProtoRtpAvp,SalAudio);
1401 if (stream && stream->dir!=SalStreamInactive && stream->rtp_port!=0){
1402 MSSndCard *playcard=lc->sound_conf.lsd_card ?
1403 lc->sound_conf.lsd_card : lc->sound_conf.play_sndcard;
1404 MSSndCard *captcard=lc->sound_conf.capt_sndcard;
1405 const char *playfile=lc->play_file;
1406 const char *recfile=lc->rec_file;
1407 call->audio_profile=make_profile(call,call->resultdesc,stream,&used_pt);
1411 call->current_params.audio_codec = rtp_profile_get_payload(call->audio_profile, used_pt);
1412 if (playcard==NULL) {
1413 ms_warning("No card defined for playback !");
1415 if (captcard==NULL) {
1416 ms_warning("No card defined for capture !");
1418 /*Replace soundcard filters by inactive file players or recorders
1419 when placed in recvonly or sendonly mode*/
1420 if (stream->rtp_port==0 || stream->dir==SalStreamRecvOnly){
1423 }else if (stream->dir==SalStreamSendOnly){
1427 /*And we will eventually play "playfile" if set by the user*/
1430 if (send_ringbacktone){
1432 playfile=NULL;/* it is setup later*/
1434 /*if playfile are supplied don't use soundcards*/
1435 if (lc->use_files) {
1439 if (call->params.in_conference){
1440 /* first create the graph without soundcard resources*/
1441 captcard=playcard=NULL;
1443 if (!linphone_call_sound_resources_available(call)){
1444 ms_message("Sound resources are used by another call, not using soundcard.");
1445 captcard=playcard=NULL;
1447 use_ec=captcard==NULL ? FALSE : linphone_core_echo_cancellation_enabled(lc);
1448 if (playcard && stream->max_rate>0) ms_snd_card_set_preferred_sample_rate(playcard, stream->max_rate);
1449 if (captcard && stream->max_rate>0) ms_snd_card_set_preferred_sample_rate(captcard, stream->max_rate);
1450 audio_stream_enable_adaptive_bitrate_control(call->audiostream,use_arc);
1451 audio_stream_enable_adaptive_jittcomp(call->audiostream, linphone_core_audio_adaptive_jittcomp_enabled(lc));
1452 audio_stream_start_full(
1454 call->audio_profile,
1455 stream->rtp_addr[0]!='\0' ? stream->rtp_addr : call->resultdesc->addr,
1457 stream->rtcp_addr[0]!='\0' ? stream->rtcp_addr : call->resultdesc->addr,
1458 linphone_core_rtcp_enabled(lc) ? (stream->rtcp_port) : 0,
1460 linphone_core_get_audio_jittcomp(lc),
1467 post_configure_audio_streams(call);
1468 if (muted && !send_ringbacktone){
1469 audio_stream_set_mic_gain(call->audiostream,0);
1471 if (stream->dir==SalStreamSendOnly && playfile!=NULL){
1473 ms_filter_call_method(call->audiostream->soundread,MS_FILE_PLAYER_LOOP,&pause_time);
1475 if (send_ringbacktone){
1476 setup_ring_player(lc,call);
1478 audio_stream_set_rtcp_information(call->audiostream, cname, rtcp_tool);
1480 /* valid local tags are > 0 */
1481 if (stream->proto == SalProtoRtpSavp) {
1482 const SalStreamDescription *local_st_desc=sal_media_description_find_stream(call->localdesc,
1483 SalProtoRtpSavp,SalAudio);
1484 int crypto_idx = find_crypto_index_from_tag(local_st_desc->crypto, stream->crypto_local_tag);
1486 if (crypto_idx >= 0) {
1487 audio_stream_enable_strp(
1489 stream->crypto[0].algo,
1490 local_st_desc->crypto[crypto_idx].master_key,
1491 stream->crypto[0].master_key);
1492 call->audiostream_encrypted=TRUE;
1494 ms_warning("Failed to find local crypto algo with tag: %d", stream->crypto_local_tag);
1495 call->audiostream_encrypted=FALSE;
1497 }else call->audiostream_encrypted=FALSE;
1498 if (call->params.in_conference){
1499 /*transform the graph to connect it to the conference filter */
1500 bool_t mute=stream->dir==SalStreamRecvOnly;
1501 linphone_call_add_to_conf(call, mute);
1503 call->current_params.in_conference=call->params.in_conference;
1504 call->current_params.low_bandwidth=call->params.low_bandwidth;
1505 }else ms_warning("No audio stream accepted ?");
1509 static void linphone_call_start_video_stream(LinphoneCall *call, const char *cname,bool_t all_inputs_muted){
1510 #ifdef VIDEO_ENABLED
1511 LinphoneCore *lc=call->core;
1513 /* look for savp stream first */
1514 const SalStreamDescription *vstream=sal_media_description_find_stream(call->resultdesc,
1515 SalProtoRtpSavp,SalVideo);
1516 char rtcp_tool[128]={0};
1517 snprintf(rtcp_tool,sizeof(rtcp_tool)-1,"%s-%s",linphone_core_get_user_agent_name(),linphone_core_get_user_agent_version());
1519 /* no savp audio stream, use avp */
1521 vstream=sal_media_description_find_stream(call->resultdesc,
1522 SalProtoRtpAvp,SalVideo);
1524 /* shutdown preview */
1525 if (lc->previewstream!=NULL) {
1526 video_preview_stop(lc->previewstream);
1527 lc->previewstream=NULL;
1530 if (vstream!=NULL && vstream->dir!=SalStreamInactive && vstream->rtp_port!=0) {
1531 const char *rtp_addr=vstream->rtp_addr[0]!='\0' ? vstream->rtp_addr : call->resultdesc->addr;
1532 const char *rtcp_addr=vstream->rtcp_addr[0]!='\0' ? vstream->rtcp_addr : call->resultdesc->addr;
1533 call->video_profile=make_profile(call,call->resultdesc,vstream,&used_pt);
1535 call->current_params.video_codec = rtp_profile_get_payload(call->video_profile, used_pt);
1536 VideoStreamDir dir=VideoStreamSendRecv;
1537 MSWebCam *cam=lc->video_conf.device;
1538 bool_t is_inactive=FALSE;
1540 call->current_params.has_video=TRUE;
1542 video_stream_enable_adaptive_bitrate_control(call->videostream,
1543 linphone_core_adaptive_rate_control_enabled(lc));
1544 video_stream_enable_adaptive_jittcomp(call->videostream, linphone_core_video_adaptive_jittcomp_enabled(lc));
1545 video_stream_set_sent_video_size(call->videostream,linphone_core_get_preferred_video_size(lc));
1546 video_stream_enable_self_view(call->videostream,lc->video_conf.selfview);
1547 if (lc->video_window_id!=0)
1548 video_stream_set_native_window_id(call->videostream,lc->video_window_id);
1549 if (lc->preview_window_id!=0)
1550 video_stream_set_native_preview_window_id (call->videostream,lc->preview_window_id);
1551 video_stream_use_preview_video_window (call->videostream,lc->use_preview_window);
1553 if (vstream->dir==SalStreamSendOnly && lc->video_conf.capture ){
1554 cam=get_nowebcam_device();
1555 dir=VideoStreamSendOnly;
1556 }else if (vstream->dir==SalStreamRecvOnly && lc->video_conf.display ){
1557 dir=VideoStreamRecvOnly;
1558 }else if (vstream->dir==SalStreamSendRecv){
1559 if (lc->video_conf.display && lc->video_conf.capture)
1560 dir=VideoStreamSendRecv;
1561 else if (lc->video_conf.display)
1562 dir=VideoStreamRecvOnly;
1564 dir=VideoStreamSendOnly;
1566 ms_warning("video stream is inactive.");
1567 /*either inactive or incompatible with local capabilities*/
1570 if (call->camera_active==FALSE || all_inputs_muted){
1571 cam=get_nowebcam_device();
1574 call->log->video_enabled = TRUE;
1575 video_stream_set_direction (call->videostream, dir);
1576 ms_message("%s lc rotation:%d\n", __FUNCTION__, lc->device_rotation);
1577 video_stream_set_device_rotation(call->videostream, lc->device_rotation);
1578 video_stream_start(call->videostream,
1579 call->video_profile, rtp_addr, vstream->rtp_port,
1580 rtcp_addr, linphone_core_rtcp_enabled(lc) ? (vstream->rtcp_port) : 0,
1581 used_pt, linphone_core_get_video_jittcomp(lc), cam);
1582 video_stream_set_rtcp_information(call->videostream, cname,rtcp_tool);
1585 if (vstream->proto == SalProtoRtpSavp) {
1586 const SalStreamDescription *local_st_desc=sal_media_description_find_stream(call->localdesc,
1587 SalProtoRtpSavp,SalVideo);
1589 video_stream_enable_strp(
1591 vstream->crypto[0].algo,
1592 local_st_desc->crypto[0].master_key,
1593 vstream->crypto[0].master_key
1595 call->videostream_encrypted=TRUE;
1597 call->videostream_encrypted=FALSE;
1599 }else ms_warning("No video stream accepted.");
1601 ms_warning("No valid video stream defined.");
1606 void linphone_call_start_media_streams(LinphoneCall *call, bool_t all_inputs_muted, bool_t send_ringbacktone){
1607 LinphoneCore *lc=call->core;
1609 call->current_params.audio_codec = NULL;
1610 call->current_params.video_codec = NULL;
1612 LinphoneAddress *me=linphone_core_get_primary_contact_parsed(lc);
1614 bool_t use_arc=linphone_core_adaptive_rate_control_enabled(lc);
1615 #ifdef VIDEO_ENABLED
1616 const SalStreamDescription *vstream=sal_media_description_find_stream(call->resultdesc,
1617 SalProtoRtpAvp,SalVideo);
1620 if ((call->audiostream == NULL) && (call->videostream == NULL)) {
1621 ms_fatal("start_media_stream() called without prior init !");
1624 cname=linphone_address_as_string_uri_only(me);
1626 #if defined(VIDEO_ENABLED)
1627 if (vstream!=NULL && vstream->dir!=SalStreamInactive && vstream->payloads!=NULL){
1628 /*when video is used, do not make adaptive rate control on audio, it is stupid.*/
1632 if (call->audiostream!=NULL) {
1633 linphone_call_start_audio_stream(call,cname,all_inputs_muted,send_ringbacktone,use_arc);
1635 call->current_params.has_video=FALSE;
1636 if (call->videostream!=NULL) {
1637 linphone_call_start_video_stream(call,cname,all_inputs_muted);
1640 call->all_muted=all_inputs_muted;
1641 call->playing_ringbacktone=send_ringbacktone;
1642 call->up_bw=linphone_core_get_upload_bandwidth(lc);
1644 if (call->params.media_encryption==LinphoneMediaEncryptionZRTP) {
1645 OrtpZrtpParams params;
1646 /*will be set later when zrtp is activated*/
1647 call->current_params.media_encryption=LinphoneMediaEncryptionNone;
1649 params.zid_file=lc->zrtp_secrets_cache;
1650 audio_stream_enable_zrtp(call->audiostream,¶ms);
1651 }else if (call->params.media_encryption==LinphoneMediaEncryptionSRTP){
1652 call->current_params.media_encryption=linphone_call_are_all_streams_encrypted(call) ?
1653 LinphoneMediaEncryptionSRTP : LinphoneMediaEncryptionNone;
1656 /*also reflect the change if the "wished" params, in order to avoid to propose SAVP or video again
1657 * further in the call, for example during pause,resume, conferencing reINVITEs*/
1658 linphone_call_fix_call_parameters(call);
1659 if ((call->ice_session != NULL) && (ice_session_state(call->ice_session) != IS_Completed)) {
1660 ice_session_start_connectivity_checks(call->ice_session);
1666 linphone_address_destroy(me);
1669 void linphone_call_start_media_streams_for_ice_gathering(LinphoneCall *call){
1670 audio_stream_prepare_sound(call->audiostream, NULL, NULL);
1671 #ifdef VIDEO_ENABLED
1672 if (call->videostream) {
1673 video_stream_prepare_video(call->videostream);
1678 void linphone_call_stop_media_streams_for_ice_gathering(LinphoneCall *call){
1679 audio_stream_unprepare_sound(call->audiostream);
1680 #ifdef VIDEO_ENABLED
1681 if (call->videostream) {
1682 video_stream_unprepare_video(call->videostream);
1687 void linphone_call_delete_ice_session(LinphoneCall *call){
1688 if (call->ice_session != NULL) {
1689 ice_session_destroy(call->ice_session);
1690 call->ice_session = NULL;
1691 if (call->audiostream != NULL) call->audiostream->ice_check_list = NULL;
1692 if (call->videostream != NULL) call->videostream->ice_check_list = NULL;
1693 call->stats[LINPHONE_CALL_STATS_AUDIO].ice_state = LinphoneIceStateNotActivated;
1694 call->stats[LINPHONE_CALL_STATS_VIDEO].ice_state = LinphoneIceStateNotActivated;
1699 void linphone_call_delete_upnp_session(LinphoneCall *call){
1700 if(call->upnp_session!=NULL) {
1701 linphone_upnp_session_destroy(call->upnp_session);
1702 call->upnp_session=NULL;
1707 static void linphone_call_log_fill_stats(LinphoneCallLog *log, AudioStream *st){
1708 audio_stream_get_local_rtp_stats (st,&log->local_stats);
1709 log->quality=audio_stream_get_average_quality_rating(st);
1712 void linphone_call_stop_audio_stream(LinphoneCall *call) {
1713 if (call->audiostream!=NULL) {
1714 rtp_session_unregister_event_queue(call->audiostream->session,call->audiostream_app_evq);
1715 ortp_ev_queue_flush(call->audiostream_app_evq);
1716 ortp_ev_queue_destroy(call->audiostream_app_evq);
1717 call->audiostream_app_evq=NULL;
1719 if (call->audiostream->ec){
1720 const char *state_str=NULL;
1721 ms_filter_call_method(call->audiostream->ec,MS_ECHO_CANCELLER_GET_STATE_STRING,&state_str);
1723 ms_message("Writing echo canceler state, %i bytes",(int)strlen(state_str));
1724 lp_config_set_string(call->core->config,"sound","ec_state",state_str);
1727 linphone_call_log_fill_stats (call->log,call->audiostream);
1728 if (call->endpoint){
1729 linphone_call_remove_from_conf(call);
1731 audio_stream_stop(call->audiostream);
1732 call->audiostream=NULL;
1736 void linphone_call_stop_video_stream(LinphoneCall *call) {
1737 #ifdef VIDEO_ENABLED
1738 if (call->videostream!=NULL){
1739 rtp_session_unregister_event_queue(call->videostream->session,call->videostream_app_evq);
1740 ortp_ev_queue_flush(call->videostream_app_evq);
1741 ortp_ev_queue_destroy(call->videostream_app_evq);
1742 call->videostream_app_evq=NULL;
1743 video_stream_stop(call->videostream);
1744 call->videostream=NULL;
1749 void linphone_call_stop_media_streams(LinphoneCall *call){
1750 linphone_call_stop_audio_stream(call);
1751 linphone_call_stop_video_stream(call);
1752 ms_event_queue_skip(call->core->msevq);
1754 if (call->audio_profile){
1755 rtp_profile_clear_all(call->audio_profile);
1756 rtp_profile_destroy(call->audio_profile);
1757 call->audio_profile=NULL;
1759 if (call->video_profile){
1760 rtp_profile_clear_all(call->video_profile);
1761 rtp_profile_destroy(call->video_profile);
1762 call->video_profile=NULL;
1768 void linphone_call_enable_echo_cancellation(LinphoneCall *call, bool_t enable) {
1769 if (call!=NULL && call->audiostream!=NULL && call->audiostream->ec){
1770 bool_t bypass_mode = !enable;
1771 ms_filter_call_method(call->audiostream->ec,MS_ECHO_CANCELLER_SET_BYPASS_MODE,&bypass_mode);
1774 bool_t linphone_call_echo_cancellation_enabled(LinphoneCall *call) {
1775 if (call!=NULL && call->audiostream!=NULL && call->audiostream->ec){
1777 ms_filter_call_method(call->audiostream->ec,MS_ECHO_CANCELLER_GET_BYPASS_MODE,&val);
1780 return linphone_core_echo_cancellation_enabled(call->core);
1784 void linphone_call_enable_echo_limiter(LinphoneCall *call, bool_t val){
1785 if (call!=NULL && call->audiostream!=NULL ) {
1787 const char *type=lp_config_get_string(call->core->config,"sound","el_type","mic");
1788 if (strcasecmp(type,"mic")==0)
1789 audio_stream_enable_echo_limiter(call->audiostream,ELControlMic);
1790 else if (strcasecmp(type,"full")==0)
1791 audio_stream_enable_echo_limiter(call->audiostream,ELControlFull);
1793 audio_stream_enable_echo_limiter(call->audiostream,ELInactive);
1798 bool_t linphone_call_echo_limiter_enabled(const LinphoneCall *call){
1799 if (call!=NULL && call->audiostream!=NULL ){
1800 return call->audiostream->el_type !=ELInactive ;
1802 return linphone_core_echo_limiter_enabled(call->core);
1807 * @addtogroup call_misc
1812 * Returns the measured sound volume played locally (received from remote).
1813 * It is expressed in dbm0.
1815 float linphone_call_get_play_volume(LinphoneCall *call){
1816 AudioStream *st=call->audiostream;
1817 if (st && st->volrecv){
1819 ms_filter_call_method(st->volrecv,MS_VOLUME_GET,&vol);
1823 return LINPHONE_VOLUME_DB_LOWEST;
1827 * Returns the measured sound volume recorded locally (sent to remote).
1828 * It is expressed in dbm0.
1830 float linphone_call_get_record_volume(LinphoneCall *call){
1831 AudioStream *st=call->audiostream;
1832 if (st && st->volsend && !call->audio_muted && call->state==LinphoneCallStreamsRunning){
1834 ms_filter_call_method(st->volsend,MS_VOLUME_GET,&vol);
1838 return LINPHONE_VOLUME_DB_LOWEST;
1842 * Obtain real-time quality rating of the call
1844 * Based on local RTP statistics and RTCP feedback, a quality rating is computed and updated
1845 * during all the duration of the call. This function returns its value at the time of the function call.
1846 * It is expected that the rating is updated at least every 5 seconds or so.
1847 * The rating is a floating point number comprised between 0 and 5.
1849 * 4-5 = good quality <br>
1850 * 3-4 = average quality <br>
1851 * 2-3 = poor quality <br>
1852 * 1-2 = very poor quality <br>
1853 * 0-1 = can't be worse, mostly unusable <br>
1855 * @returns The function returns -1 if no quality measurement is available, for example if no
1856 * active audio stream exist. Otherwise it returns the quality rating.
1858 float linphone_call_get_current_quality(LinphoneCall *call){
1859 if (call->audiostream){
1860 return audio_stream_get_quality_rating(call->audiostream);
1866 * Returns call quality averaged over all the duration of the call.
1868 * See linphone_call_get_current_quality() for more details about quality measurement.
1870 float linphone_call_get_average_quality(LinphoneCall *call){
1871 if (call->audiostream){
1872 return audio_stream_get_average_quality_rating(call->audiostream);
1878 * Access last known statistics for audio stream, for a given call.
1880 const LinphoneCallStats *linphone_call_get_audio_stats(const LinphoneCall *call) {
1881 return &call->stats[LINPHONE_CALL_STATS_AUDIO];
1885 * Access last known statistics for video stream, for a given call.
1887 const LinphoneCallStats *linphone_call_get_video_stats(const LinphoneCall *call) {
1888 return &call->stats[LINPHONE_CALL_STATS_VIDEO];
1896 static void report_bandwidth(LinphoneCall *call, RtpSession *as, RtpSession *vs){
1897 call->stats[LINPHONE_CALL_STATS_AUDIO].download_bandwidth=(as!=NULL) ? (rtp_session_compute_recv_bandwidth(as)*1e-3) : 0;
1898 call->stats[LINPHONE_CALL_STATS_AUDIO].upload_bandwidth=(as!=NULL) ? (rtp_session_compute_send_bandwidth(as)*1e-3) : 0;
1899 call->stats[LINPHONE_CALL_STATS_VIDEO].download_bandwidth=(vs!=NULL) ? (rtp_session_compute_recv_bandwidth(vs)*1e-3) : 0;
1900 call->stats[LINPHONE_CALL_STATS_VIDEO].upload_bandwidth=(vs!=NULL) ? (rtp_session_compute_send_bandwidth(vs)*1e-3) : 0;
1901 ms_message("bandwidth usage: audio=[d=%.1f,u=%.1f] video=[d=%.1f,u=%.1f] kbit/sec",
1902 call->stats[LINPHONE_CALL_STATS_AUDIO].download_bandwidth,
1903 call->stats[LINPHONE_CALL_STATS_AUDIO].upload_bandwidth ,
1904 call->stats[LINPHONE_CALL_STATS_VIDEO].download_bandwidth,
1905 call->stats[LINPHONE_CALL_STATS_VIDEO].upload_bandwidth
1909 static void linphone_core_disconnected(LinphoneCore *lc, LinphoneCall *call){
1913 from = linphone_call_get_remote_address_as_string(call);
1916 snprintf(temp,sizeof(temp),"Remote end %s seems to have disconnected, the call is going to be closed.",from);
1921 snprintf(temp,sizeof(temp),"Remote end seems to have disconnected, the call is going to be closed.");
1923 if (lc->vtable.display_warning!=NULL)
1924 lc->vtable.display_warning(lc,temp);
1925 linphone_core_terminate_call(lc,call);
1928 static void handle_ice_events(LinphoneCall *call, OrtpEvent *ev){
1929 OrtpEventType evt=ortp_event_get_type(ev);
1930 OrtpEventData *evd=ortp_event_get_data(ev);
1933 if (evt == ORTP_EVENT_ICE_SESSION_PROCESSING_FINISHED) {
1934 switch (ice_session_state(call->ice_session)) {
1936 ice_session_select_candidates(call->ice_session);
1937 if (ice_session_role(call->ice_session) == IR_Controlling) {
1938 linphone_core_update_call(call->core, call, &call->current_params);
1942 if (ice_session_has_completed_check_list(call->ice_session) == TRUE) {
1943 ice_session_select_candidates(call->ice_session);
1944 if (ice_session_role(call->ice_session) == IR_Controlling) {
1945 /* At least one ICE session has succeeded, so perform a call update. */
1946 linphone_core_update_call(call->core, call, &call->current_params);
1953 linphone_core_update_ice_state_in_call_stats(call);
1954 } else if (evt == ORTP_EVENT_ICE_GATHERING_FINISHED) {
1956 if (evd->info.ice_processing_successful==TRUE) {
1957 ice_session_compute_candidates_foundations(call->ice_session);
1958 ice_session_eliminate_redundant_candidates(call->ice_session);
1959 ice_session_choose_default_candidates(call->ice_session);
1960 ping_time = ice_session_average_gathering_round_trip_time(call->ice_session);
1961 if (ping_time >=0) {
1962 call->ping_time=ping_time;
1965 ms_warning("No STUN answer from [%s], disabling ICE",linphone_core_get_stun_server(call->core));
1966 linphone_call_delete_ice_session(call);
1968 switch (call->state) {
1969 case LinphoneCallUpdating:
1970 linphone_core_start_update_call(call->core, call);
1972 case LinphoneCallUpdatedByRemote:
1973 linphone_core_start_accept_call_update(call->core, call);
1975 case LinphoneCallOutgoingInit:
1976 linphone_call_stop_media_streams_for_ice_gathering(call);
1977 linphone_core_proceed_with_invite_if_ready(call->core, call, NULL);
1979 case LinphoneCallIdle:
1980 linphone_call_stop_media_streams_for_ice_gathering(call);
1981 linphone_core_notify_incoming_call(call->core, call);
1986 } else if (evt == ORTP_EVENT_ICE_LOSING_PAIRS_COMPLETED) {
1987 linphone_core_start_accept_call_update(call->core, call);
1988 linphone_core_update_ice_state_in_call_stats(call);
1989 } else if (evt == ORTP_EVENT_ICE_RESTART_NEEDED) {
1990 ice_session_restart(call->ice_session);
1991 ice_session_set_role(call->ice_session, IR_Controlling);
1992 linphone_core_update_call(call->core, call, &call->current_params);
1996 void linphone_call_background_tasks(LinphoneCall *call, bool_t one_second_elapsed){
1997 LinphoneCore* lc = call->core;
1998 int disconnect_timeout = linphone_core_get_nortp_timeout(call->core);
1999 bool_t disconnected=FALSE;
2001 if (call->state==LinphoneCallStreamsRunning && one_second_elapsed){
2002 RtpSession *as=NULL,*vs=NULL;
2003 float audio_load=0, video_load=0;
2004 if (call->audiostream!=NULL){
2005 as=call->audiostream->session;
2006 if (call->audiostream->ticker)
2007 audio_load=ms_ticker_get_average_load(call->audiostream->ticker);
2009 if (call->videostream!=NULL){
2010 if (call->videostream->ticker)
2011 video_load=ms_ticker_get_average_load(call->videostream->ticker);
2012 vs=call->videostream->session;
2014 report_bandwidth(call,as,vs);
2015 ms_message("Thread processing load: audio=%f\tvideo=%f",audio_load,video_load);
2019 linphone_upnp_call_process(call);
2022 #ifdef VIDEO_ENABLED
2023 if (call->videostream!=NULL) {
2026 /* Ensure there is no dangling ICE check list. */
2027 if (call->ice_session == NULL) call->videostream->ice_check_list = NULL;
2029 // Beware that the application queue should not depend on treatments fron the
2030 // mediastreamer queue.
2031 video_stream_iterate(call->videostream);
2033 while (call->videostream_app_evq && (NULL != (ev=ortp_ev_queue_get(call->videostream_app_evq)))){
2034 OrtpEventType evt=ortp_event_get_type(ev);
2035 OrtpEventData *evd=ortp_event_get_data(ev);
2036 if (evt == ORTP_EVENT_ZRTP_ENCRYPTION_CHANGED){
2037 linphone_call_videostream_encryption_changed(call, evd->info.zrtp_stream_encrypted);
2038 } else if (evt == ORTP_EVENT_RTCP_PACKET_RECEIVED) {
2039 call->stats[LINPHONE_CALL_STATS_VIDEO].round_trip_delay = rtp_session_get_round_trip_propagation(call->videostream->session);
2040 if(call->stats[LINPHONE_CALL_STATS_VIDEO].received_rtcp != NULL)
2041 freemsg(call->stats[LINPHONE_CALL_STATS_VIDEO].received_rtcp);
2042 call->stats[LINPHONE_CALL_STATS_VIDEO].received_rtcp = evd->packet;
2044 if (lc->vtable.call_stats_updated)
2045 lc->vtable.call_stats_updated(lc, call, &call->stats[LINPHONE_CALL_STATS_VIDEO]);
2046 } else if (evt == ORTP_EVENT_RTCP_PACKET_EMITTED) {
2047 memcpy(&call->stats[LINPHONE_CALL_STATS_VIDEO].jitter_stats, rtp_session_get_jitter_stats(call->videostream->session), sizeof(jitter_stats_t));
2048 if(call->stats[LINPHONE_CALL_STATS_VIDEO].sent_rtcp != NULL)
2049 freemsg(call->stats[LINPHONE_CALL_STATS_VIDEO].sent_rtcp);
2050 call->stats[LINPHONE_CALL_STATS_VIDEO].sent_rtcp = evd->packet;
2052 if (lc->vtable.call_stats_updated)
2053 lc->vtable.call_stats_updated(lc, call, &call->stats[LINPHONE_CALL_STATS_VIDEO]);
2054 } else if ((evt == ORTP_EVENT_ICE_SESSION_PROCESSING_FINISHED) || (evt == ORTP_EVENT_ICE_GATHERING_FINISHED)
2055 || (evt == ORTP_EVENT_ICE_LOSING_PAIRS_COMPLETED) || (evt == ORTP_EVENT_ICE_RESTART_NEEDED)) {
2056 handle_ice_events(call, ev);
2058 ortp_event_destroy(ev);
2062 if (call->audiostream!=NULL) {
2065 /* Ensure there is no dangling ICE check list. */
2066 if (call->ice_session == NULL) call->audiostream->ice_check_list = NULL;
2068 // Beware that the application queue should not depend on treatments fron the
2069 // mediastreamer queue.
2070 audio_stream_iterate(call->audiostream);
2072 while (call->audiostream_app_evq && (NULL != (ev=ortp_ev_queue_get(call->audiostream_app_evq)))){
2073 OrtpEventType evt=ortp_event_get_type(ev);
2074 OrtpEventData *evd=ortp_event_get_data(ev);
2075 if (evt == ORTP_EVENT_ZRTP_ENCRYPTION_CHANGED){
2076 linphone_call_audiostream_encryption_changed(call, evd->info.zrtp_stream_encrypted);
2077 } else if (evt == ORTP_EVENT_ZRTP_SAS_READY) {
2078 linphone_call_audiostream_auth_token_ready(call, evd->info.zrtp_sas.sas, evd->info.zrtp_sas.verified);
2079 } else if (evt == ORTP_EVENT_RTCP_PACKET_RECEIVED) {
2080 call->stats[LINPHONE_CALL_STATS_AUDIO].round_trip_delay = rtp_session_get_round_trip_propagation(call->audiostream->session);
2081 if(call->stats[LINPHONE_CALL_STATS_AUDIO].received_rtcp != NULL)
2082 freemsg(call->stats[LINPHONE_CALL_STATS_AUDIO].received_rtcp);
2083 call->stats[LINPHONE_CALL_STATS_AUDIO].received_rtcp = evd->packet;
2085 if (lc->vtable.call_stats_updated)
2086 lc->vtable.call_stats_updated(lc, call, &call->stats[LINPHONE_CALL_STATS_AUDIO]);
2087 } else if (evt == ORTP_EVENT_RTCP_PACKET_EMITTED) {
2088 memcpy(&call->stats[LINPHONE_CALL_STATS_AUDIO].jitter_stats, rtp_session_get_jitter_stats(call->audiostream->session), sizeof(jitter_stats_t));
2089 if(call->stats[LINPHONE_CALL_STATS_AUDIO].sent_rtcp != NULL)
2090 freemsg(call->stats[LINPHONE_CALL_STATS_AUDIO].sent_rtcp);
2091 call->stats[LINPHONE_CALL_STATS_AUDIO].sent_rtcp = evd->packet;
2093 if (lc->vtable.call_stats_updated)
2094 lc->vtable.call_stats_updated(lc, call, &call->stats[LINPHONE_CALL_STATS_AUDIO]);
2095 } else if ((evt == ORTP_EVENT_ICE_SESSION_PROCESSING_FINISHED) || (evt == ORTP_EVENT_ICE_GATHERING_FINISHED)
2096 || (evt == ORTP_EVENT_ICE_LOSING_PAIRS_COMPLETED) || (evt == ORTP_EVENT_ICE_RESTART_NEEDED)) {
2097 handle_ice_events(call, ev);
2098 } else if (evt==ORTP_EVENT_TELEPHONE_EVENT){
2099 linphone_core_dtmf_received(lc,evd->info.telephone_event);
2101 ortp_event_destroy(ev);
2104 if (call->state==LinphoneCallStreamsRunning && one_second_elapsed && call->audiostream!=NULL && disconnect_timeout>0 )
2105 disconnected=!audio_stream_alive(call->audiostream,disconnect_timeout);
2107 linphone_core_disconnected(call->core,call);
2110 void linphone_call_log_completed(LinphoneCall *call){
2111 LinphoneCore *lc=call->core;
2113 call->log->duration=time(NULL)-call->start_time;
2115 if (call->log->status==LinphoneCallMissed){
2118 info=ortp_strdup_printf(ngettext("You have missed %i call.",
2119 "You have missed %i calls.", lc->missed_calls),
2121 if (lc->vtable.display_status!=NULL)
2122 lc->vtable.display_status(lc,info);
2125 lc->call_logs=ms_list_prepend(lc->call_logs,(void *)call->log);
2126 if (ms_list_size(lc->call_logs)>lc->max_call_logs){
2127 MSList *elem,*prevelem=NULL;
2128 /*find the last element*/
2129 for(elem=lc->call_logs;elem!=NULL;elem=elem->next){
2133 linphone_call_log_destroy((LinphoneCallLog*)elem->data);
2134 lc->call_logs=ms_list_remove_link(lc->call_logs,elem);
2136 if (lc->vtable.call_log_updated!=NULL){
2137 lc->vtable.call_log_updated(lc,call->log);
2139 call_logs_write_to_config_file(lc);
2142 LinphoneCallState linphone_call_get_transfer_state(LinphoneCall *call) {
2143 return call->transfer_state;
2146 void linphone_call_set_transfer_state(LinphoneCall* call, LinphoneCallState state) {
2147 if (state != call->transfer_state) {
2148 LinphoneCore* lc = call->core;
2149 call->transfer_state = state;
2150 if (lc->vtable.transfer_state_changed)
2151 lc->vtable.transfer_state_changed(lc, call, state);
2156 * Returns true if the call is part of the conference.
2157 * @ingroup conferencing
2159 bool_t linphone_call_is_in_conference(const LinphoneCall *call) {
2160 return call->params.in_conference;
2165 * Perform a zoom of the video displayed during a call.
2166 * @param call the call.
2167 * @param zoom_factor a floating point number describing the zoom factor. A value 1.0 corresponds to no zoom applied.
2168 * @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.
2169 * @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.
2171 * 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.
2173 void linphone_call_zoom_video(LinphoneCall* call, float zoom_factor, float* cx, float* cy) {
2174 VideoStream* vstream = call->videostream;
2175 if (vstream && vstream->output) {
2178 if (zoom_factor < 1)
2180 float halfsize = 0.5 * 1.0 / zoom_factor;
2182 if ((*cx - halfsize) < 0)
2184 if ((*cx + halfsize) > 1)
2186 if ((*cy - halfsize) < 0)
2188 if ((*cy + halfsize) > 1)
2191 zoom[0] = zoom_factor;
2194 ms_filter_call_method(vstream->output, MS_VIDEO_DISPLAY_ZOOM, &zoom);
2195 }else ms_warning("Could not apply zoom: video output wasn't activated.");