4 Copyright (C) 2010 Belledonne Communications SARL
5 (simon.morlat@linphone.org)
7 This program is free software; you can redistribute it and/or
8 modify it under the terms of the GNU General Public License
9 as published by the Free Software Foundation; either version 2
10 of the License, or (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24 #include "linphonecore.h"
28 #include <ortp/event.h>
32 #include "mediastreamer2/mediastream.h"
33 #include "mediastreamer2/msvolume.h"
34 #include "mediastreamer2/msequalizer.h"
35 #include "mediastreamer2/msfileplayer.h"
36 #include "mediastreamer2/msjpegwriter.h"
37 #include "mediastreamer2/mseventqueue.h"
38 #include "mediastreamer2/mssndcard.h"
41 static MSWebCam *get_nowebcam_device(){
42 return ms_web_cam_manager_get_cam(ms_web_cam_manager_get(),"StaticImage: Static picture");
46 static bool_t generate_b64_crypto_key(int key_length, char* key_out) {
48 uint8_t* tmp = (uint8_t*) malloc(key_length);
49 if (ortp_crypto_get_random(tmp, key_length)!=0) {
50 ms_error("Failed to generate random key");
55 b64_size = b64_encode((const char*)tmp, key_length, NULL, 0);
57 ms_error("Failed to b64 encode key");
61 key_out[b64_size] = '\0';
62 b64_encode((const char*)tmp, key_length, key_out, 40);
67 LinphoneCore *linphone_call_get_core(const LinphoneCall *call){
71 const char* linphone_call_get_authentication_token(LinphoneCall *call){
72 return call->auth_token;
75 bool_t linphone_call_get_authentication_token_verified(LinphoneCall *call){
76 return call->auth_token_verified;
79 static bool_t linphone_call_are_all_streams_encrypted(LinphoneCall *call) {
80 // Check ZRTP encryption in audiostream
81 if (!call->audiostream_encrypted) {
86 // If video enabled, check ZRTP encryption in videostream
87 const LinphoneCallParams *params=linphone_call_get_current_params(call);
88 if (params->has_video && !call->videostream_encrypted) {
96 void propagate_encryption_changed(LinphoneCall *call){
97 LinphoneCore *lc=call->core;
98 if (!linphone_call_are_all_streams_encrypted(call)) {
99 ms_message("Some streams are not encrypted");
100 call->current_params.media_encryption=LinphoneMediaEncryptionNone;
101 if (lc->vtable.call_encryption_changed)
102 lc->vtable.call_encryption_changed(call->core, call, FALSE, call->auth_token);
104 ms_message("All streams are encrypted");
105 call->current_params.media_encryption=LinphoneMediaEncryptionZRTP;
106 if (lc->vtable.call_encryption_changed)
107 lc->vtable.call_encryption_changed(call->core, call, TRUE, call->auth_token);
112 static void linphone_call_videostream_encryption_changed(void *data, bool_t encrypted){
113 ms_message("Video stream is %s", encrypted ? "encrypted" : "not encrypted");
115 LinphoneCall *call = (LinphoneCall *)data;
116 call->videostream_encrypted=encrypted;
117 propagate_encryption_changed(call);
121 static void linphone_call_audiostream_encryption_changed(void *data, bool_t encrypted) {
122 char status[255]={0};
123 ms_message("Audio stream is %s ", encrypted ? "encrypted" : "not encrypted");
125 LinphoneCall *call = (LinphoneCall *)data;
126 call->audiostream_encrypted=encrypted;
128 if (encrypted && call->core->vtable.display_status != NULL) {
129 snprintf(status,sizeof(status)-1,_("Authentication token is %s"),call->auth_token);
130 call->core->vtable.display_status(call->core, status);
133 propagate_encryption_changed(call);
137 // Enable video encryption
138 const LinphoneCallParams *params=linphone_call_get_current_params(call);
139 if (params->has_video) {
140 ms_message("Trying to enable encryption on video stream");
141 OrtpZrtpParams params;
142 params.zid_file=NULL; //unused
143 video_stream_enable_zrtp(call->videostream,call->audiostream,¶ms);
149 static void linphone_call_audiostream_auth_token_ready(void *data, const char* auth_token, bool_t verified) {
150 LinphoneCall *call=(LinphoneCall *)data;
151 if (call->auth_token != NULL)
152 ms_free(call->auth_token);
154 call->auth_token=ms_strdup(auth_token);
155 call->auth_token_verified=verified;
157 ms_message("Authentication token is %s (%s)", auth_token, verified?"verified":"unverified");
160 void linphone_call_set_authentication_token_verified(LinphoneCall *call, bool_t verified){
161 if (call->audiostream==NULL){
162 ms_error("linphone_call_set_authentication_token_verified(): No audio stream");
164 if (call->audiostream->ortpZrtpContext==NULL){
165 ms_error("linphone_call_set_authentication_token_verified(): No zrtp context.");
167 if (!call->auth_token_verified && verified){
168 ortp_zrtp_sas_verified(call->audiostream->ortpZrtpContext);
169 }else if (call->auth_token_verified && !verified){
170 ortp_zrtp_sas_reset_verified(call->audiostream->ortpZrtpContext);
172 call->auth_token_verified=verified;
173 propagate_encryption_changed(call);
176 static MSList *make_codec_list(LinphoneCore *lc, const MSList *codecs, int bandwidth_limit,int* max_sample_rate){
179 if (max_sample_rate) *max_sample_rate=0;
180 for(it=codecs;it!=NULL;it=it->next){
181 PayloadType *pt=(PayloadType*)it->data;
182 if (pt->flags & PAYLOAD_TYPE_ENABLED){
183 if (bandwidth_limit>0 && !linphone_core_is_payload_type_usable_for_bandwidth(lc,pt,bandwidth_limit)){
184 ms_message("Codec %s/%i eliminated because of audio bandwidth constraint.",pt->mime_type,pt->clock_rate);
187 if (linphone_core_check_payload_type_usability(lc,pt)){
188 l=ms_list_append(l,payload_type_clone(pt));
189 if (max_sample_rate && payload_type_get_rate(pt)>*max_sample_rate) *max_sample_rate=payload_type_get_rate(pt);
196 static void update_media_description_from_stun(SalMediaDescription *md, const StunCandidate *ac, const StunCandidate *vc){
198 strcpy(md->streams[0].rtp_addr,ac->addr);
199 md->streams[0].rtp_port=ac->port;
200 if ((ac->addr[0]!='\0' && vc->addr[0]!='\0' && strcmp(ac->addr,vc->addr)==0) || md->nstreams==1){
201 strcpy(md->addr,ac->addr);
205 strcpy(md->streams[1].rtp_addr,vc->addr);
206 md->streams[1].rtp_port=vc->port;
211 void linphone_call_make_local_media_description(LinphoneCore *lc, LinphoneCall *call){
214 SalMediaDescription *old_md=call->localdesc;
216 const char *me=linphone_core_get_identity(lc);
217 LinphoneAddress *addr=linphone_address_new(me);
218 const char *username=linphone_address_get_username (addr);
219 SalMediaDescription *md=sal_media_description_new();
220 bool_t keep_srtp_keys=lp_config_get_int(lc->config,"sip","keep_srtp_keys",0);
222 linphone_core_adapt_to_network(lc,call->ping_time,&call->params);
224 md->session_id=(old_md ? old_md->session_id : (rand() & 0xfff));
225 md->session_ver=(old_md ? (old_md->session_ver+1) : (rand() & 0xfff));
227 strncpy(md->addr,call->localip,sizeof(md->addr));
228 strncpy(md->username,username,sizeof(md->username));
230 if (call->params.down_bw)
231 md->bandwidth=call->params.down_bw;
232 else md->bandwidth=linphone_core_get_download_bandwidth(lc);
234 /*set audio capabilities */
235 strncpy(md->streams[0].rtp_addr,call->localip,sizeof(md->streams[0].rtp_addr));
236 strncpy(md->streams[0].rtcp_addr,call->localip,sizeof(md->streams[0].rtcp_addr));
237 md->streams[0].rtp_port=call->audio_port;
238 md->streams[0].rtcp_port=call->audio_port+1;
239 md->streams[0].proto=(call->params.media_encryption == LinphoneMediaEncryptionSRTP) ?
240 SalProtoRtpSavp : SalProtoRtpAvp;
241 md->streams[0].type=SalAudio;
242 if (call->params.down_ptime)
243 md->streams[0].ptime=call->params.down_ptime;
245 md->streams[0].ptime=linphone_core_get_download_ptime(lc);
246 l=make_codec_list(lc,lc->codecs_conf.audio_codecs,call->params.audio_bw,&md->streams[0].max_rate);
247 pt=payload_type_clone(rtp_profile_get_payload_from_mime(&av_profile,"telephone-event"));
248 l=ms_list_append(l,pt);
249 md->streams[0].payloads=l;
251 if (call->params.has_video){
253 md->streams[1].rtp_port=call->video_port;
254 md->streams[1].rtcp_port=call->video_port+1;
255 md->streams[1].proto=md->streams[0].proto;
256 md->streams[1].type=SalVideo;
257 l=make_codec_list(lc,lc->codecs_conf.video_codecs,0,NULL);
258 md->streams[1].payloads=l;
261 for(i=0; i<md->nstreams; i++) {
262 if (md->streams[i].proto == SalProtoRtpSavp) {
263 if (keep_srtp_keys && old_md && old_md->streams[i].proto==SalProtoRtpSavp){
265 for(j=0;j<SAL_CRYPTO_ALGO_MAX;++j){
266 memcpy(&md->streams[i].crypto[j],&old_md->streams[i].crypto[j],sizeof(SalSrtpCryptoAlgo));
269 md->streams[i].crypto[0].tag = 1;
270 md->streams[i].crypto[0].algo = AES_128_SHA1_80;
271 if (!generate_b64_crypto_key(30, md->streams[i].crypto[0].master_key))
272 md->streams[i].crypto[0].algo = 0;
273 md->streams[i].crypto[1].tag = 2;
274 md->streams[i].crypto[1].algo = AES_128_SHA1_32;
275 if (!generate_b64_crypto_key(30, md->streams[i].crypto[1].master_key))
276 md->streams[i].crypto[1].algo = 0;
277 md->streams[i].crypto[2].algo = 0;
281 update_media_description_from_stun(md,&call->ac,&call->vc);
282 if (call->ice_session != NULL) {
283 linphone_core_update_local_media_description_from_ice(md, call->ice_session);
284 linphone_core_update_ice_state_in_call_stats(call);
286 linphone_address_destroy(addr);
288 if (old_md) sal_media_description_unref(old_md);
291 static int find_port_offset(LinphoneCore *lc, SalStreamType type){
296 bool_t already_used=FALSE;
297 for(offset=0;offset<100;offset+=2){
301 tried_port=linphone_core_get_audio_port (lc)+offset;
304 tried_port=linphone_core_get_video_port (lc)+offset;
308 for(elem=lc->calls;elem!=NULL;elem=elem->next){
309 LinphoneCall *call=(LinphoneCall*)elem->data;
313 existing_port = call->audio_port;
316 existing_port = call->video_port;
319 if (existing_port==tried_port) {
324 if (!already_used) break;
327 ms_error("Could not find any free port !");
333 static int select_random_port(LinphoneCore *lc, SalStreamType type) {
337 int existing_port = 0;
338 int min_port = 0, max_port = 0;
339 bool_t already_used = FALSE;
344 linphone_core_get_audio_port_range(lc, &min_port, &max_port);
347 linphone_core_get_video_port_range(lc, &min_port, &max_port);
350 tried_port = (rand() % (max_port - min_port) + min_port) & ~0x1;
351 if (tried_port < min_port) tried_port = min_port + 2;
352 for (nb_tries = 0; nb_tries < 100; nb_tries++) {
353 for (elem = lc->calls; elem != NULL; elem = elem->next) {
354 LinphoneCall *call = (LinphoneCall *)elem->data;
358 existing_port = call->audio_port;
361 existing_port = call->video_port;
364 if (existing_port == tried_port) {
369 if (!already_used) break;
371 if (nb_tries == 100) {
372 ms_error("Could not find any free port!");
378 static void linphone_call_init_common(LinphoneCall *call, LinphoneAddress *from, LinphoneAddress *to){
380 int min_port, max_port;
381 call->magic=linphone_call_magic;
383 call->state=LinphoneCallIdle;
384 call->transfer_state = LinphoneCallIdle;
385 call->start_time=time(NULL);
386 call->media_start_time=0;
387 call->log=linphone_call_log_new(call, from, to);
388 call->owns_call_log=TRUE;
389 linphone_core_notify_all_friends(call->core,LinphoneStatusOnThePhone);
390 linphone_core_get_audio_port_range(call->core, &min_port, &max_port);
391 if (min_port == max_port) {
392 /* Used fixed RTP audio port. */
393 port_offset=find_port_offset (call->core, SalAudio);
394 if (port_offset==-1) return;
395 call->audio_port=linphone_core_get_audio_port(call->core)+port_offset;
397 /* Select random RTP audio port in the specified range. */
398 call->audio_port = select_random_port(call->core, SalAudio);
400 linphone_core_get_video_port_range(call->core, &min_port, &max_port);
401 if (min_port == max_port) {
402 /* Used fixed RTP video port. */
403 port_offset=find_port_offset (call->core, SalVideo);
404 if (port_offset==-1) return;
405 call->video_port=linphone_core_get_video_port(call->core)+port_offset;
407 /* Select random RTP video port in the specified range. */
408 call->video_port = select_random_port(call->core, SalVideo);
410 linphone_call_init_stats(&call->stats[LINPHONE_CALL_STATS_AUDIO], LINPHONE_CALL_STATS_AUDIO);
411 linphone_call_init_stats(&call->stats[LINPHONE_CALL_STATS_VIDEO], LINPHONE_CALL_STATS_VIDEO);
414 void linphone_call_init_stats(LinphoneCallStats *stats, int type) {
416 stats->received_rtcp = NULL;
417 stats->sent_rtcp = NULL;
418 stats->ice_state = LinphoneIceStateNotActivated;
422 static void discover_mtu(LinphoneCore *lc, const char *remote){
424 if (lc->net_conf.mtu==0 ){
425 /*attempt to discover mtu*/
426 mtu=ms_discover_mtu(remote);
429 ms_message("Discovered mtu is %i, RTP payload max size is %i",
430 mtu, ms_get_payload_max_size());
435 LinphoneCall * linphone_call_new_outgoing(struct _LinphoneCore *lc, LinphoneAddress *from, LinphoneAddress *to, const LinphoneCallParams *params)
437 LinphoneCall *call=ms_new0(LinphoneCall,1);
438 call->dir=LinphoneCallOutgoing;
439 call->op=sal_op_new(lc->sal);
440 sal_op_set_user_pointer(call->op,call);
442 linphone_core_get_local_ip(lc,linphone_address_get_domain(to),call->localip);
443 linphone_call_init_common(call,from,to);
444 call->params=*params;
445 if (linphone_core_get_firewall_policy(call->core) == LinphonePolicyUseIce) {
446 call->ice_session = ice_session_new();
447 ice_session_set_role(call->ice_session, IR_Controlling);
449 if (linphone_core_get_firewall_policy(call->core) == LinphonePolicyUseStun) {
450 call->ping_time=linphone_core_run_stun_tests(call->core,call);
453 if (linphone_core_get_firewall_policy(call->core) == LinphonePolicyUseUpnp) {
454 call->upnp_session = upnp_session_new(call);
457 call->camera_active=params->has_video;
459 discover_mtu(lc,linphone_address_get_domain (to));
460 if (params->referer){
461 sal_call_set_referer(call->op,params->referer->op);
462 call->referer=linphone_call_ref(params->referer);
467 LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *from, LinphoneAddress *to, SalOp *op){
468 LinphoneCall *call=ms_new0(LinphoneCall,1);
470 const SalMediaDescription *md;
472 call->dir=LinphoneCallIncoming;
473 sal_op_set_user_pointer(op,call);
477 if (lc->sip_conf.ping_with_options){
478 /*the following sends an option request back to the caller so that
479 we get a chance to discover our nat'd address before answering.*/
480 call->ping_op=sal_op_new(lc->sal);
481 from_str=linphone_address_as_string_uri_only(from);
482 sal_op_set_route(call->ping_op,sal_op_get_network_origin(op));
483 sal_op_set_user_pointer(call->ping_op,call);
484 sal_ping(call->ping_op,linphone_core_find_best_identity(lc,from,NULL),from_str);
488 linphone_address_clean(from);
489 linphone_core_get_local_ip(lc,linphone_address_get_domain(from),call->localip);
490 linphone_call_init_common(call, from, to);
491 call->log->call_id=ms_strdup(sal_op_get_call_id(op)); /*must be known at that time*/
492 linphone_core_init_default_params(lc, &call->params);
493 md=sal_call_get_remote_media_description(op);
494 call->params.has_video &= !!lc->video_policy.automatically_accept;
496 // It is licit to receive an INVITE without SDP
497 // In this case WE chose the media parameters according to policy.
498 call->params.has_video &= linphone_core_media_description_contains_video_stream(md);
500 switch (linphone_core_get_firewall_policy(call->core)) {
501 case LinphonePolicyUseIce:
502 call->ice_session = ice_session_new();
503 ice_session_set_role(call->ice_session, IR_Controlled);
504 linphone_core_update_ice_from_remote_media_description(call, sal_call_get_remote_media_description(op));
505 if (call->ice_session != NULL) {
506 linphone_call_init_media_streams(call);
507 linphone_call_start_media_streams_for_ice_gathering(call);
508 if (linphone_core_gather_ice_candidates(call->core,call)<0) {
509 /* Ice candidates gathering failed, proceed with the call anyway. */
510 linphone_call_delete_ice_session(call);
511 linphone_call_stop_media_streams_for_ice_gathering(call);
515 case LinphonePolicyUseStun:
516 call->ping_time=linphone_core_run_stun_tests(call->core,call);
517 /* No break to also destroy ice session in this case. */
519 case LinphonePolicyUseUpnp:
521 call->upnp_session = upnp_session_new(call);
522 if (call->ice_session != NULL) {
523 linphone_call_init_media_streams(call);
524 if (linphone_core_update_upnp(call->core,call)<0) {
525 /* uPnP port mappings failed, proceed with the call anyway. */
526 linphone_call_delete_upnp_session(call);
534 call->camera_active=call->params.has_video;
536 discover_mtu(lc,linphone_address_get_domain(from));
540 /* this function is called internally to get rid of a call.
541 It performs the following tasks:
542 - remove the call from the internal list of calls
543 - update the call logs accordingly
546 static void linphone_call_set_terminated(LinphoneCall *call){
547 LinphoneCore *lc=call->core;
549 linphone_core_update_allocated_audio_bandwidth(lc);
551 call->owns_call_log=FALSE;
552 linphone_call_log_completed(call);
555 if (call == lc->current_call){
556 ms_message("Resetting the current call");
557 lc->current_call=NULL;
560 if (linphone_core_del_call(lc,call) != 0){
561 ms_error("Could not remove the call from the list !!!");
564 if (ms_list_size(lc->calls)==0)
565 linphone_core_notify_all_friends(lc,lc->presence_mode);
567 linphone_core_conference_check_uninit(lc);
568 if (call->ringing_beep){
569 linphone_core_stop_dtmf(lc);
570 call->ringing_beep=FALSE;
573 linphone_call_unref(call->referer);
578 void linphone_call_fix_call_parameters(LinphoneCall *call){
579 call->params.has_video=call->current_params.has_video;
580 call->params.media_encryption=call->current_params.media_encryption;
583 const char *linphone_call_state_to_string(LinphoneCallState cs){
585 case LinphoneCallIdle:
586 return "LinphoneCallIdle";
587 case LinphoneCallIncomingReceived:
588 return "LinphoneCallIncomingReceived";
589 case LinphoneCallOutgoingInit:
590 return "LinphoneCallOutgoingInit";
591 case LinphoneCallOutgoingProgress:
592 return "LinphoneCallOutgoingProgress";
593 case LinphoneCallOutgoingRinging:
594 return "LinphoneCallOutgoingRinging";
595 case LinphoneCallOutgoingEarlyMedia:
596 return "LinphoneCallOutgoingEarlyMedia";
597 case LinphoneCallConnected:
598 return "LinphoneCallConnected";
599 case LinphoneCallStreamsRunning:
600 return "LinphoneCallStreamsRunning";
601 case LinphoneCallPausing:
602 return "LinphoneCallPausing";
603 case LinphoneCallPaused:
604 return "LinphoneCallPaused";
605 case LinphoneCallResuming:
606 return "LinphoneCallResuming";
607 case LinphoneCallRefered:
608 return "LinphoneCallRefered";
609 case LinphoneCallError:
610 return "LinphoneCallError";
611 case LinphoneCallEnd:
612 return "LinphoneCallEnd";
613 case LinphoneCallPausedByRemote:
614 return "LinphoneCallPausedByRemote";
615 case LinphoneCallUpdatedByRemote:
616 return "LinphoneCallUpdatedByRemote";
617 case LinphoneCallIncomingEarlyMedia:
618 return "LinphoneCallIncomingEarlyMedia";
619 case LinphoneCallUpdating:
620 return "LinphoneCallUpdating";
621 case LinphoneCallReleased:
622 return "LinphoneCallReleased";
624 return "undefined state";
627 void linphone_call_set_state(LinphoneCall *call, LinphoneCallState cstate, const char *message){
628 LinphoneCore *lc=call->core;
630 if (call->state!=cstate){
631 if (call->state==LinphoneCallEnd || call->state==LinphoneCallError){
632 if (cstate!=LinphoneCallReleased){
633 ms_warning("Spurious call state change from %s to %s, ignored.",linphone_call_state_to_string(call->state),
634 linphone_call_state_to_string(cstate));
638 ms_message("Call %p: moving from state %s to %s",call,linphone_call_state_to_string(call->state),
639 linphone_call_state_to_string(cstate));
640 if (cstate!=LinphoneCallRefered){
641 /*LinphoneCallRefered is rather an event, not a state.
642 Indeed it does not change the state of the call (still paused or running)*/
645 if (cstate==LinphoneCallEnd || cstate==LinphoneCallError){
646 switch(call->reason){
647 case LinphoneReasonDeclined:
648 call->log->status=LinphoneCallDeclined;
650 case LinphoneReasonNotAnswered:
651 call->log->status=LinphoneCallMissed;
656 linphone_call_set_terminated (call);
658 if (cstate == LinphoneCallConnected) {
659 call->log->status=LinphoneCallSuccess;
660 call->media_start_time=time(NULL);
663 if (lc->vtable.call_state_changed)
664 lc->vtable.call_state_changed(lc,call,cstate,message);
665 if (cstate==LinphoneCallReleased){
666 if (call->op!=NULL) {
667 /* so that we cannot have anymore upcalls for SAL
668 concerning this call*/
669 sal_op_release(call->op);
672 linphone_call_unref(call);
677 static void linphone_call_destroy(LinphoneCall *obj)
680 linphone_call_delete_upnp_session(obj);
682 linphone_call_delete_ice_session(obj);
684 sal_op_release(obj->op);
687 if (obj->resultdesc!=NULL) {
688 sal_media_description_unref(obj->resultdesc);
689 obj->resultdesc=NULL;
691 if (obj->localdesc!=NULL) {
692 sal_media_description_unref(obj->localdesc);
696 sal_op_release(obj->ping_op);
699 ms_free(obj->refer_to);
701 if (obj->owns_call_log)
702 linphone_call_log_destroy(obj->log);
703 if (obj->auth_token) {
704 ms_free(obj->auth_token);
711 * @addtogroup call_control
716 * Increments the call 's reference count.
717 * An application that wishes to retain a pointer to call object
718 * must use this function to unsure the pointer remains
719 * valid. Once the application no more needs this pointer,
720 * it must call linphone_call_unref().
722 LinphoneCall * linphone_call_ref(LinphoneCall *obj){
728 * Decrements the call object reference count.
729 * See linphone_call_ref().
731 void linphone_call_unref(LinphoneCall *obj){
734 linphone_call_destroy(obj);
739 * Returns current parameters associated to the call.
741 const LinphoneCallParams * linphone_call_get_current_params(const LinphoneCall *call){
742 return &call->current_params;
745 static bool_t is_video_active(const SalStreamDescription *sd){
746 return sd->rtp_port!=0 && sd->dir!=SalStreamInactive;
750 * Returns call parameters proposed by remote.
752 * This is useful when receiving an incoming call, to know whether the remote party
753 * supports video, encryption or whatever.
755 const LinphoneCallParams * linphone_call_get_remote_params(LinphoneCall *call){
756 LinphoneCallParams *cp=&call->remote_params;
757 memset(cp,0,sizeof(*cp));
759 SalMediaDescription *md=sal_call_get_remote_media_description(call->op);
761 SalStreamDescription *asd,*vsd,*secure_asd,*secure_vsd;
763 asd=sal_media_description_find_stream(md,SalProtoRtpAvp,SalAudio);
764 vsd=sal_media_description_find_stream(md,SalProtoRtpAvp,SalVideo);
765 secure_asd=sal_media_description_find_stream(md,SalProtoRtpSavp,SalAudio);
766 secure_vsd=sal_media_description_find_stream(md,SalProtoRtpSavp,SalVideo);
768 cp->has_video=is_video_active(secure_vsd);
769 if (secure_asd || asd==NULL)
770 cp->media_encryption=LinphoneMediaEncryptionSRTP;
772 cp->has_video=is_video_active(vsd);
775 if (md->bandwidth>0 && md->bandwidth<=linphone_core_get_edge_bw(call->core)){
776 cp->low_bandwidth=TRUE;
786 * Returns the remote address associated to this call
789 const LinphoneAddress * linphone_call_get_remote_address(const LinphoneCall *call){
790 return call->dir==LinphoneCallIncoming ? call->log->from : call->log->to;
794 * Returns the remote address associated to this call as a string.
796 * The result string must be freed by user using ms_free().
798 char *linphone_call_get_remote_address_as_string(const LinphoneCall *call){
799 return linphone_address_as_string(linphone_call_get_remote_address(call));
803 * Retrieves the call's current state.
805 LinphoneCallState linphone_call_get_state(const LinphoneCall *call){
810 * Returns the reason for a call termination (either error or normal termination)
812 LinphoneReason linphone_call_get_reason(const LinphoneCall *call){
817 * Get the user_pointer in the LinphoneCall
819 * @ingroup call_control
821 * return user_pointer an opaque user pointer that can be retrieved at any time
823 void *linphone_call_get_user_pointer(LinphoneCall *call)
825 return call->user_pointer;
829 * Set the user_pointer in the LinphoneCall
831 * @ingroup call_control
833 * the user_pointer is an opaque user pointer that can be retrieved at any time in the LinphoneCall
835 void linphone_call_set_user_pointer(LinphoneCall *call, void *user_pointer)
837 call->user_pointer = user_pointer;
841 * Returns the call log associated to this call.
843 LinphoneCallLog *linphone_call_get_call_log(const LinphoneCall *call){
848 * Returns the refer-to uri (if the call was transfered).
850 const char *linphone_call_get_refer_to(const LinphoneCall *call){
851 return call->refer_to;
855 * Returns direction of the call (incoming or outgoing).
857 LinphoneCallDir linphone_call_get_dir(const LinphoneCall *call){
858 return call->log->dir;
862 * Returns the far end's user agent description string, if available.
864 const char *linphone_call_get_remote_user_agent(LinphoneCall *call){
866 return sal_op_get_remote_ua (call->op);
872 * Returns true if this calls has received a transfer that has not been
874 * Pending transfers are executed when this call is being paused or closed,
875 * locally or by remote endpoint.
876 * If the call is already paused while receiving the transfer request, the
877 * transfer immediately occurs.
879 bool_t linphone_call_has_transfer_pending(const LinphoneCall *call){
880 return call->refer_pending;
884 * Returns call's duration in seconds.
886 int linphone_call_get_duration(const LinphoneCall *call){
887 if (call->media_start_time==0) return 0;
888 return time(NULL)-call->media_start_time;
892 * Returns the call object this call is replacing, if any.
893 * Call replacement can occur during call transfers.
894 * By default, the core automatically terminates the replaced call and accept the new one.
895 * This function allows the application to know whether a new incoming call is a one that replaces another one.
897 LinphoneCall *linphone_call_get_replaced_call(LinphoneCall *call){
898 SalOp *op=sal_call_get_replaces(call->op);
900 return (LinphoneCall*)sal_op_get_user_pointer(op);
906 * Indicate whether camera input should be sent to remote end.
908 void linphone_call_enable_camera (LinphoneCall *call, bool_t enable){
910 if (call->videostream!=NULL && call->videostream->ticker!=NULL){
911 LinphoneCore *lc=call->core;
912 MSWebCam *nowebcam=get_nowebcam_device();
913 if (call->camera_active!=enable && lc->video_conf.device!=nowebcam){
914 video_stream_change_camera(call->videostream,
915 enable ? lc->video_conf.device : nowebcam);
918 call->camera_active=enable;
923 * Take a photo of currently received video and write it into a jpeg file.
925 int linphone_call_take_video_snapshot(LinphoneCall *call, const char *file){
927 if (call->videostream!=NULL && call->videostream->jpegwriter!=NULL){
928 return ms_filter_call_method(call->videostream->jpegwriter,MS_JPEG_WRITER_TAKE_SNAPSHOT,(void*)file);
930 ms_warning("Cannot take snapshot: no currently running video stream on this call.");
937 * Returns TRUE if camera pictures are sent to the remote party.
939 bool_t linphone_call_camera_enabled (const LinphoneCall *call){
940 return call->camera_active;
944 * Enable video stream.
946 void linphone_call_params_enable_video(LinphoneCallParams *cp, bool_t enabled){
947 cp->has_video=enabled;
950 const PayloadType* linphone_call_params_get_used_audio_codec(const LinphoneCallParams *cp) {
951 return cp->audio_codec;
954 const PayloadType* linphone_call_params_get_used_video_codec(const LinphoneCallParams *cp) {
955 return cp->video_codec;
959 * @ingroup call_control
960 * Use to know if this call has been configured in low bandwidth mode.
961 * This mode can be automatically discovered thanks to a stun server when activate_edge_workarounds=1 in section [net] of configuration file.
962 * An application that would have reliable way to know network capacity may not use activate_edge_workarounds=1 but instead manually configure
963 * low bandwidth mode with linphone_call_params_enable_low_bandwidth().
964 * <br> When enabled, this param may transform a call request with video in audio only mode.
965 * @return TRUE if low bandwidth has been configured/detected
967 bool_t linphone_call_params_low_bandwidth_enabled(const LinphoneCallParams *cp) {
968 return cp->low_bandwidth;
972 * @ingroup call_control
973 * Indicate low bandwith mode.
974 * 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
975 * 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
976 * that it is achievable by the codec selected after SDP handshake. Video is automatically disabled.
979 void linphone_call_params_enable_low_bandwidth(LinphoneCallParams *cp, bool_t enabled){
980 cp->low_bandwidth=enabled;
984 * Returns whether video is enabled.
986 bool_t linphone_call_params_video_enabled(const LinphoneCallParams *cp){
987 return cp->has_video;
990 enum LinphoneMediaEncryption linphone_call_params_get_media_encryption(const LinphoneCallParams *cp) {
991 return cp->media_encryption;
994 void linphone_call_params_set_media_encryption(LinphoneCallParams *cp, enum LinphoneMediaEncryption e) {
995 cp->media_encryption = e;
1000 * Enable sending of real early media (during outgoing calls).
1002 void linphone_call_params_enable_early_media_sending(LinphoneCallParams *cp, bool_t enabled){
1003 cp->real_early_media=enabled;
1006 bool_t linphone_call_params_early_media_sending_enabled(const LinphoneCallParams *cp){
1007 return cp->real_early_media;
1011 * Returns true if the call is part of the locally managed conference.
1013 bool_t linphone_call_params_local_conference_mode(const LinphoneCallParams *cp){
1014 return cp->in_conference;
1018 * Refine bandwidth settings for this call by setting a bandwidth limit for audio streams.
1019 * As a consequence, codecs whose bitrates are not compatible with this limit won't be used.
1021 void linphone_call_params_set_audio_bandwidth_limit(LinphoneCallParams *cp, int bandwidth){
1022 cp->audio_bw=bandwidth;
1025 #ifdef VIDEO_ENABLED
1027 * Request remote side to send us a Video Fast Update.
1029 void linphone_call_send_vfu_request(LinphoneCall *call)
1031 if (LinphoneCallStreamsRunning == linphone_call_get_state(call))
1032 sal_call_send_vfu_request(call->op);
1039 LinphoneCallParams * linphone_call_params_copy(const LinphoneCallParams *cp){
1040 LinphoneCallParams *ncp=ms_new0(LinphoneCallParams,1);
1041 memcpy(ncp,cp,sizeof(LinphoneCallParams));
1048 void linphone_call_params_destroy(LinphoneCallParams *p){
1057 #ifdef TEST_EXT_RENDERER
1058 static void rendercb(void *data, const MSPicture *local, const MSPicture *remote){
1059 ms_message("rendercb, local buffer=%p, remote buffer=%p",
1060 local ? local->planes[0] : NULL, remote? remote->planes[0] : NULL);
1064 #ifdef VIDEO_ENABLED
1065 static void video_stream_event_cb(void *user_pointer, const MSFilter *f, const unsigned int event_id, const void *args){
1066 LinphoneCall* call = (LinphoneCall*) user_pointer;
1067 ms_warning("In linphonecall.c: video_stream_event_cb");
1069 case MS_VIDEO_DECODER_DECODING_ERRORS:
1070 ms_warning("Case is MS_VIDEO_DECODER_DECODING_ERRORS");
1071 linphone_call_send_vfu_request(call);
1073 case MS_VIDEO_DECODER_FIRST_IMAGE_DECODED:
1074 ms_message("First video frame decoded successfully");
1075 if (call->nextVideoFrameDecoded._func != NULL)
1076 call->nextVideoFrameDecoded._func(call, call->nextVideoFrameDecoded._user_data);
1079 ms_warning("Unhandled event %i", event_id);
1085 void linphone_call_set_next_video_frame_decoded_callback(LinphoneCall *call, LinphoneCallCbFunc cb, void* user_data) {
1086 call->nextVideoFrameDecoded._func = cb;
1087 call->nextVideoFrameDecoded._user_data = user_data;
1088 #ifdef VIDEO_ENABLED
1089 ms_filter_call_method_noarg(call->videostream->decoder, MS_VIDEO_DECODER_RESET_FIRST_IMAGE_NOTIFICATION);
1093 void linphone_call_init_audio_stream(LinphoneCall *call){
1094 LinphoneCore *lc=call->core;
1095 AudioStream *audiostream;
1098 if (call->audiostream != NULL) return;
1099 call->audiostream=audiostream=audio_stream_new(call->audio_port,call->audio_port+1,linphone_core_ipv6_enabled(lc));
1100 dscp=linphone_core_get_audio_dscp(lc);
1102 audio_stream_set_dscp(audiostream,dscp);
1103 if (linphone_core_echo_limiter_enabled(lc)){
1104 const char *type=lp_config_get_string(lc->config,"sound","el_type","mic");
1105 if (strcasecmp(type,"mic")==0)
1106 audio_stream_enable_echo_limiter(audiostream,ELControlMic);
1107 else if (strcasecmp(type,"full")==0)
1108 audio_stream_enable_echo_limiter(audiostream,ELControlFull);
1110 audio_stream_enable_gain_control(audiostream,TRUE);
1111 if (linphone_core_echo_cancellation_enabled(lc)){
1112 int len,delay,framesize;
1113 const char *statestr=lp_config_get_string(lc->config,"sound","ec_state",NULL);
1114 len=lp_config_get_int(lc->config,"sound","ec_tail_len",0);
1115 delay=lp_config_get_int(lc->config,"sound","ec_delay",0);
1116 framesize=lp_config_get_int(lc->config,"sound","ec_framesize",0);
1117 audio_stream_set_echo_canceller_params(audiostream,len,delay,framesize);
1118 if (statestr && audiostream->ec){
1119 ms_filter_call_method(audiostream->ec,MS_ECHO_CANCELLER_SET_STATE_STRING,(void*)statestr);
1122 audio_stream_enable_automatic_gain_control(audiostream,linphone_core_agc_enabled(lc));
1124 int enabled=lp_config_get_int(lc->config,"sound","noisegate",0);
1125 audio_stream_enable_noise_gate(audiostream,enabled);
1128 audio_stream_set_features(audiostream,linphone_core_get_audio_features(lc));
1131 RtpTransport *artp=lc->rtptf->audio_rtp_func(lc->rtptf->audio_rtp_func_data, call->audio_port);
1132 RtpTransport *artcp=lc->rtptf->audio_rtcp_func(lc->rtptf->audio_rtcp_func_data, call->audio_port+1);
1133 rtp_session_set_transports(audiostream->session,artp,artcp);
1135 if ((linphone_core_get_firewall_policy(lc) == LinphonePolicyUseIce) && (call->ice_session != NULL)){
1136 rtp_session_set_pktinfo(audiostream->session, TRUE);
1137 rtp_session_set_symmetric_rtp(audiostream->session, FALSE);
1138 if (ice_session_check_list(call->ice_session, 0) == NULL) {
1139 ice_session_add_check_list(call->ice_session, ice_check_list_new());
1141 audiostream->ice_check_list = ice_session_check_list(call->ice_session, 0);
1142 ice_check_list_set_rtp_session(audiostream->ice_check_list, audiostream->session);
1145 call->audiostream_app_evq = ortp_ev_queue_new();
1146 rtp_session_register_event_queue(audiostream->session,call->audiostream_app_evq);
1149 void linphone_call_init_video_stream(LinphoneCall *call){
1150 #ifdef VIDEO_ENABLED
1151 LinphoneCore *lc=call->core;
1153 if (!call->params.has_video) {
1154 linphone_call_stop_video_stream(call);
1157 if (call->videostream != NULL) return;
1158 if ((lc->video_conf.display || lc->video_conf.capture) && call->params.has_video){
1159 int video_recv_buf_size=lp_config_get_int(lc->config,"video","recv_buf_size",0);
1160 int dscp=linphone_core_get_video_dscp(lc);
1162 call->videostream=video_stream_new(call->video_port,call->video_port+1,linphone_core_ipv6_enabled(lc));
1164 video_stream_set_dscp(call->videostream,dscp);
1165 video_stream_enable_display_filter_auto_rotate(call->videostream, lp_config_get_int(lc->config,"video","display_filter_auto_rotate",0));
1166 if (video_recv_buf_size>0) rtp_session_set_recv_buf_size(call->videostream->session,video_recv_buf_size);
1168 if( lc->video_conf.displaytype != NULL)
1169 video_stream_set_display_filter_name(call->videostream,lc->video_conf.displaytype);
1170 video_stream_set_event_callback(call->videostream,video_stream_event_cb, call);
1172 RtpTransport *vrtp=lc->rtptf->video_rtp_func(lc->rtptf->video_rtp_func_data, call->video_port);
1173 RtpTransport *vrtcp=lc->rtptf->video_rtcp_func(lc->rtptf->video_rtcp_func_data, call->video_port+1);
1174 rtp_session_set_transports(call->videostream->session,vrtp,vrtcp);
1176 if ((linphone_core_get_firewall_policy(lc) == LinphonePolicyUseIce) && (call->ice_session != NULL)){
1177 rtp_session_set_pktinfo(call->videostream->session, TRUE);
1178 rtp_session_set_symmetric_rtp(call->videostream->session, FALSE);
1179 if (ice_session_check_list(call->ice_session, 1) == NULL) {
1180 ice_session_add_check_list(call->ice_session, ice_check_list_new());
1182 call->videostream->ice_check_list = ice_session_check_list(call->ice_session, 1);
1183 ice_check_list_set_rtp_session(call->videostream->ice_check_list, call->videostream->session);
1185 call->videostream_app_evq = ortp_ev_queue_new();
1186 rtp_session_register_event_queue(call->videostream->session,call->videostream_app_evq);
1187 #ifdef TEST_EXT_RENDERER
1188 video_stream_set_render_callback(call->videostream,rendercb,NULL);
1192 call->videostream=NULL;
1196 void linphone_call_init_media_streams(LinphoneCall *call){
1197 linphone_call_init_audio_stream(call);
1198 linphone_call_init_video_stream(call);
1202 static int dtmf_tab[16]={'0','1','2','3','4','5','6','7','8','9','*','#','A','B','C','D'};
1204 static void linphone_core_dtmf_received(LinphoneCore *lc, int dtmf){
1205 if (dtmf<0 || dtmf>15){
1206 ms_warning("Bad dtmf value %i",dtmf);
1209 if (lc->vtable.dtmf_received != NULL)
1210 lc->vtable.dtmf_received(lc, linphone_core_get_current_call(lc), dtmf_tab[dtmf]);
1213 static void parametrize_equalizer(LinphoneCore *lc, AudioStream *st){
1215 MSFilter *f=st->equalizer;
1216 int enabled=lp_config_get_int(lc->config,"sound","eq_active",0);
1217 const char *gains=lp_config_get_string(lc->config,"sound","eq_gains",NULL);
1218 ms_filter_call_method(f,MS_EQUALIZER_SET_ACTIVE,&enabled);
1224 if (sscanf(gains,"%f:%f:%f %n",&g.frequency,&g.gain,&g.width,&bytes)==3){
1225 ms_message("Read equalizer gains: %f(~%f) --> %f",g.frequency,g.width,g.gain);
1226 ms_filter_call_method(f,MS_EQUALIZER_SET_GAIN,&g);
1235 void _post_configure_audio_stream(AudioStream *st, LinphoneCore *lc, bool_t muted){
1236 float mic_gain=lc->sound_conf.soft_mic_lev;
1239 float ng_thres=lp_config_get_float(lc->config,"sound","ng_thres",0.05);
1240 float ng_floorgain=lp_config_get_float(lc->config,"sound","ng_floorgain",0);
1241 int dc_removal=lp_config_get_int(lc->config,"sound","dc_removal",0);
1244 linphone_core_set_mic_gain_db (lc, mic_gain);
1246 audio_stream_set_mic_gain(st,0);
1248 recv_gain = lc->sound_conf.soft_play_lev;
1249 if (recv_gain != 0) {
1250 linphone_core_set_playback_gain_db (lc,recv_gain);
1254 ms_filter_call_method(st->volsend,MS_VOLUME_REMOVE_DC,&dc_removal);
1255 float speed=lp_config_get_float(lc->config,"sound","el_speed",-1);
1256 thres=lp_config_get_float(lc->config,"sound","el_thres",-1);
1257 float force=lp_config_get_float(lc->config,"sound","el_force",-1);
1258 int sustain=lp_config_get_int(lc->config,"sound","el_sustain",-1);
1259 float transmit_thres=lp_config_get_float(lc->config,"sound","el_transmit_thres",-1);
1262 if (speed==-1) speed=0.03;
1263 if (force==-1) force=25;
1264 ms_filter_call_method(f,MS_VOLUME_SET_EA_SPEED,&speed);
1265 ms_filter_call_method(f,MS_VOLUME_SET_EA_FORCE,&force);
1267 ms_filter_call_method(f,MS_VOLUME_SET_EA_THRESHOLD,&thres);
1269 ms_filter_call_method(f,MS_VOLUME_SET_EA_SUSTAIN,&sustain);
1270 if (transmit_thres!=-1)
1271 ms_filter_call_method(f,MS_VOLUME_SET_EA_TRANSMIT_THRESHOLD,&transmit_thres);
1273 ms_filter_call_method(st->volsend,MS_VOLUME_SET_NOISE_GATE_THRESHOLD,&ng_thres);
1274 ms_filter_call_method(st->volsend,MS_VOLUME_SET_NOISE_GATE_FLOORGAIN,&ng_floorgain);
1277 /* parameters for a limited noise-gate effect, using echo limiter threshold */
1278 float floorgain = 1/pow(10,(mic_gain)/10);
1279 int spk_agc=lp_config_get_int(lc->config,"sound","speaker_agc_enabled",0);
1280 ms_filter_call_method(st->volrecv, MS_VOLUME_ENABLE_AGC, &spk_agc);
1281 ms_filter_call_method(st->volrecv,MS_VOLUME_SET_NOISE_GATE_THRESHOLD,&ng_thres);
1282 ms_filter_call_method(st->volrecv,MS_VOLUME_SET_NOISE_GATE_FLOORGAIN,&floorgain);
1284 parametrize_equalizer(lc,st);
1287 static void post_configure_audio_streams(LinphoneCall*call){
1288 AudioStream *st=call->audiostream;
1289 LinphoneCore *lc=call->core;
1290 _post_configure_audio_stream(st,lc,call->audio_muted);
1291 if (lc->vtable.dtmf_received!=NULL){
1292 /* replace by our default action*/
1293 audio_stream_play_received_dtmfs(call->audiostream,FALSE);
1294 /*rtp_session_signal_connect(call->audiostream->session,"telephone-event",(RtpCallback)linphone_core_dtmf_received,(unsigned long)lc);*/
1298 static RtpProfile *make_profile(LinphoneCall *call, const SalMediaDescription *md, const SalStreamDescription *desc, int *used_pt){
1301 RtpProfile *prof=rtp_profile_new("Call profile");
1304 LinphoneCore *lc=call->core;
1306 const LinphoneCallParams *params=&call->params;
1309 for(elem=desc->payloads;elem!=NULL;elem=elem->next){
1310 PayloadType *pt=(PayloadType*)elem->data;
1313 if ((pt->flags & PAYLOAD_TYPE_FLAG_CAN_SEND) && first) {
1314 if (desc->type==SalAudio){
1315 linphone_core_update_allocated_audio_bandwidth_in_call(call,pt);
1316 if (params->up_ptime)
1317 up_ptime=params->up_ptime;
1318 else up_ptime=linphone_core_get_upload_ptime(lc);
1320 *used_pt=payload_type_get_number(pt);
1323 if (desc->bandwidth>0) remote_bw=desc->bandwidth;
1324 else if (md->bandwidth>0) {
1325 /*case where b=AS is given globally, not per stream*/
1326 remote_bw=md->bandwidth;
1327 if (desc->type==SalVideo){
1328 remote_bw=get_video_bandwidth(remote_bw,call->audio_bw);
1332 if (desc->type==SalAudio){
1333 int audio_bw=call->audio_bw;
1335 if (params->up_bw< audio_bw)
1336 audio_bw=params->up_bw;
1338 bw=get_min_bandwidth(audio_bw,remote_bw);
1339 }else bw=get_min_bandwidth(get_video_bandwidth(linphone_core_get_upload_bandwidth (lc),call->audio_bw),remote_bw);
1340 if (bw>0) pt->normal_bitrate=bw*1000;
1341 else if (desc->type==SalAudio){
1342 pt->normal_bitrate=-1;
1345 up_ptime=desc->ptime;
1349 snprintf(tmp,sizeof(tmp),"ptime=%i",up_ptime);
1350 payload_type_append_send_fmtp(pt,tmp);
1352 number=payload_type_get_number(pt);
1353 if (rtp_profile_get_payload(prof,number)!=NULL){
1354 ms_warning("A payload type with number %i already exists in profile !",number);
1356 rtp_profile_set_payload(prof,number,pt);
1362 static void setup_ring_player(LinphoneCore *lc, LinphoneCall *call){
1363 int pause_time=3000;
1364 audio_stream_play(call->audiostream,lc->sound_conf.ringback_tone);
1365 ms_filter_call_method(call->audiostream->soundread,MS_FILE_PLAYER_LOOP,&pause_time);
1368 static bool_t linphone_call_sound_resources_available(LinphoneCall *call){
1369 LinphoneCore *lc=call->core;
1370 LinphoneCall *current=linphone_core_get_current_call(lc);
1371 return !linphone_core_is_in_conference(lc) &&
1372 (current==NULL || current==call);
1374 static int find_crypto_index_from_tag(const SalSrtpCryptoAlgo crypto[],unsigned char tag) {
1376 for(i=0; i<SAL_CRYPTO_ALGO_MAX; i++) {
1377 if (crypto[i].tag == tag) {
1383 static void linphone_call_start_audio_stream(LinphoneCall *call, const char *cname, bool_t muted, bool_t send_ringbacktone, bool_t use_arc){
1384 LinphoneCore *lc=call->core;
1386 char rtcp_tool[128]={0};
1387 snprintf(rtcp_tool,sizeof(rtcp_tool)-1,"%s-%s",linphone_core_get_user_agent_name(),linphone_core_get_user_agent_version());
1388 /* look for savp stream first */
1389 const SalStreamDescription *stream=sal_media_description_find_stream(call->resultdesc,
1390 SalProtoRtpSavp,SalAudio);
1391 /* no savp audio stream, use avp */
1393 stream=sal_media_description_find_stream(call->resultdesc,
1394 SalProtoRtpAvp,SalAudio);
1396 if (stream && stream->dir!=SalStreamInactive && stream->rtp_port!=0){
1397 MSSndCard *playcard=lc->sound_conf.lsd_card ?
1398 lc->sound_conf.lsd_card : lc->sound_conf.play_sndcard;
1399 MSSndCard *captcard=lc->sound_conf.capt_sndcard;
1400 const char *playfile=lc->play_file;
1401 const char *recfile=lc->rec_file;
1402 call->audio_profile=make_profile(call,call->resultdesc,stream,&used_pt);
1406 call->current_params.audio_codec = rtp_profile_get_payload(call->audio_profile, used_pt);
1407 if (playcard==NULL) {
1408 ms_warning("No card defined for playback !");
1410 if (captcard==NULL) {
1411 ms_warning("No card defined for capture !");
1413 /*Replace soundcard filters by inactive file players or recorders
1414 when placed in recvonly or sendonly mode*/
1415 if (stream->rtp_port==0 || stream->dir==SalStreamRecvOnly){
1418 }else if (stream->dir==SalStreamSendOnly){
1422 /*And we will eventually play "playfile" if set by the user*/
1425 if (send_ringbacktone){
1427 playfile=NULL;/* it is setup later*/
1429 /*if playfile are supplied don't use soundcards*/
1430 if (lc->use_files) {
1434 if (call->params.in_conference){
1435 /* first create the graph without soundcard resources*/
1436 captcard=playcard=NULL;
1438 if (!linphone_call_sound_resources_available(call)){
1439 ms_message("Sound resources are used by another call, not using soundcard.");
1440 captcard=playcard=NULL;
1442 use_ec=captcard==NULL ? FALSE : linphone_core_echo_cancellation_enabled(lc);
1443 if (playcard && stream->max_rate>0) ms_snd_card_set_preferred_sample_rate(playcard, stream->max_rate);
1444 if (captcard && stream->max_rate>0) ms_snd_card_set_preferred_sample_rate(captcard, stream->max_rate);
1445 audio_stream_enable_adaptive_bitrate_control(call->audiostream,use_arc);
1446 audio_stream_enable_adaptive_jittcomp(call->audiostream, linphone_core_audio_adaptive_jittcomp_enabled(lc));
1447 audio_stream_start_full(
1449 call->audio_profile,
1450 stream->rtp_addr[0]!='\0' ? stream->rtp_addr : call->resultdesc->addr,
1452 stream->rtcp_addr[0]!='\0' ? stream->rtcp_addr : call->resultdesc->addr,
1453 linphone_core_rtcp_enabled(lc) ? (stream->rtcp_port) : 0,
1455 linphone_core_get_audio_jittcomp(lc),
1462 post_configure_audio_streams(call);
1463 if (muted && !send_ringbacktone){
1464 audio_stream_set_mic_gain(call->audiostream,0);
1466 if (stream->dir==SalStreamSendOnly && playfile!=NULL){
1468 ms_filter_call_method(call->audiostream->soundread,MS_FILE_PLAYER_LOOP,&pause_time);
1470 if (send_ringbacktone){
1471 setup_ring_player(lc,call);
1473 audio_stream_set_rtcp_information(call->audiostream, cname, rtcp_tool);
1475 /* valid local tags are > 0 */
1476 if (stream->proto == SalProtoRtpSavp) {
1477 const SalStreamDescription *local_st_desc=sal_media_description_find_stream(call->localdesc,
1478 SalProtoRtpSavp,SalAudio);
1479 int crypto_idx = find_crypto_index_from_tag(local_st_desc->crypto, stream->crypto_local_tag);
1481 if (crypto_idx >= 0) {
1482 audio_stream_enable_strp(
1484 stream->crypto[0].algo,
1485 local_st_desc->crypto[crypto_idx].master_key,
1486 stream->crypto[0].master_key);
1487 call->audiostream_encrypted=TRUE;
1489 ms_warning("Failed to find local crypto algo with tag: %d", stream->crypto_local_tag);
1490 call->audiostream_encrypted=FALSE;
1492 }else call->audiostream_encrypted=FALSE;
1493 if (call->params.in_conference){
1494 /*transform the graph to connect it to the conference filter */
1495 bool_t mute=stream->dir==SalStreamRecvOnly;
1496 linphone_call_add_to_conf(call, mute);
1498 call->current_params.in_conference=call->params.in_conference;
1499 call->current_params.low_bandwidth=call->params.low_bandwidth;
1500 }else ms_warning("No audio stream accepted ?");
1504 static void linphone_call_start_video_stream(LinphoneCall *call, const char *cname,bool_t all_inputs_muted){
1505 #ifdef VIDEO_ENABLED
1506 LinphoneCore *lc=call->core;
1508 /* look for savp stream first */
1509 const SalStreamDescription *vstream=sal_media_description_find_stream(call->resultdesc,
1510 SalProtoRtpSavp,SalVideo);
1511 char rtcp_tool[128]={0};
1512 snprintf(rtcp_tool,sizeof(rtcp_tool)-1,"%s-%s",linphone_core_get_user_agent_name(),linphone_core_get_user_agent_version());
1514 /* no savp audio stream, use avp */
1516 vstream=sal_media_description_find_stream(call->resultdesc,
1517 SalProtoRtpAvp,SalVideo);
1519 /* shutdown preview */
1520 if (lc->previewstream!=NULL) {
1521 video_preview_stop(lc->previewstream);
1522 lc->previewstream=NULL;
1525 if (vstream!=NULL && vstream->dir!=SalStreamInactive && vstream->rtp_port!=0) {
1526 const char *rtp_addr=vstream->rtp_addr[0]!='\0' ? vstream->rtp_addr : call->resultdesc->addr;
1527 const char *rtcp_addr=vstream->rtcp_addr[0]!='\0' ? vstream->rtcp_addr : call->resultdesc->addr;
1528 call->video_profile=make_profile(call,call->resultdesc,vstream,&used_pt);
1530 call->current_params.video_codec = rtp_profile_get_payload(call->video_profile, used_pt);
1531 VideoStreamDir dir=VideoStreamSendRecv;
1532 MSWebCam *cam=lc->video_conf.device;
1533 bool_t is_inactive=FALSE;
1535 call->current_params.has_video=TRUE;
1537 video_stream_enable_adaptive_bitrate_control(call->videostream,
1538 linphone_core_adaptive_rate_control_enabled(lc));
1539 video_stream_enable_adaptive_jittcomp(call->videostream, linphone_core_video_adaptive_jittcomp_enabled(lc));
1540 video_stream_set_sent_video_size(call->videostream,linphone_core_get_preferred_video_size(lc));
1541 video_stream_enable_self_view(call->videostream,lc->video_conf.selfview);
1542 if (lc->video_window_id!=0)
1543 video_stream_set_native_window_id(call->videostream,lc->video_window_id);
1544 if (lc->preview_window_id!=0)
1545 video_stream_set_native_preview_window_id (call->videostream,lc->preview_window_id);
1546 video_stream_use_preview_video_window (call->videostream,lc->use_preview_window);
1548 if (vstream->dir==SalStreamSendOnly && lc->video_conf.capture ){
1549 cam=get_nowebcam_device();
1550 dir=VideoStreamSendOnly;
1551 }else if (vstream->dir==SalStreamRecvOnly && lc->video_conf.display ){
1552 dir=VideoStreamRecvOnly;
1553 }else if (vstream->dir==SalStreamSendRecv){
1554 if (lc->video_conf.display && lc->video_conf.capture)
1555 dir=VideoStreamSendRecv;
1556 else if (lc->video_conf.display)
1557 dir=VideoStreamRecvOnly;
1559 dir=VideoStreamSendOnly;
1561 ms_warning("video stream is inactive.");
1562 /*either inactive or incompatible with local capabilities*/
1565 if (call->camera_active==FALSE || all_inputs_muted){
1566 cam=get_nowebcam_device();
1569 call->log->video_enabled = TRUE;
1570 video_stream_set_direction (call->videostream, dir);
1571 ms_message("%s lc rotation:%d\n", __FUNCTION__, lc->device_rotation);
1572 video_stream_set_device_rotation(call->videostream, lc->device_rotation);
1573 video_stream_start(call->videostream,
1574 call->video_profile, rtp_addr, vstream->rtp_port,
1575 rtcp_addr, linphone_core_rtcp_enabled(lc) ? (vstream->rtcp_port) : 0,
1576 used_pt, linphone_core_get_video_jittcomp(lc), cam);
1577 video_stream_set_rtcp_information(call->videostream, cname,rtcp_tool);
1580 if (vstream->proto == SalProtoRtpSavp) {
1581 const SalStreamDescription *local_st_desc=sal_media_description_find_stream(call->localdesc,
1582 SalProtoRtpSavp,SalVideo);
1584 video_stream_enable_strp(
1586 vstream->crypto[0].algo,
1587 local_st_desc->crypto[0].master_key,
1588 vstream->crypto[0].master_key
1590 call->videostream_encrypted=TRUE;
1592 call->videostream_encrypted=FALSE;
1594 }else ms_warning("No video stream accepted.");
1596 ms_warning("No valid video stream defined.");
1601 void linphone_call_start_media_streams(LinphoneCall *call, bool_t all_inputs_muted, bool_t send_ringbacktone){
1602 LinphoneCore *lc=call->core;
1604 call->current_params.audio_codec = NULL;
1605 call->current_params.video_codec = NULL;
1607 LinphoneAddress *me=linphone_core_get_primary_contact_parsed(lc);
1609 bool_t use_arc=linphone_core_adaptive_rate_control_enabled(lc);
1610 #ifdef VIDEO_ENABLED
1611 const SalStreamDescription *vstream=sal_media_description_find_stream(call->resultdesc,
1612 SalProtoRtpAvp,SalVideo);
1615 if ((call->audiostream == NULL) && (call->videostream == NULL)) {
1616 ms_fatal("start_media_stream() called without prior init !");
1619 cname=linphone_address_as_string_uri_only(me);
1621 #if defined(VIDEO_ENABLED)
1622 if (vstream!=NULL && vstream->dir!=SalStreamInactive && vstream->payloads!=NULL){
1623 /*when video is used, do not make adaptive rate control on audio, it is stupid.*/
1627 if (call->audiostream!=NULL) {
1628 linphone_call_start_audio_stream(call,cname,all_inputs_muted,send_ringbacktone,use_arc);
1630 call->current_params.has_video=FALSE;
1631 if (call->videostream!=NULL) {
1632 linphone_call_start_video_stream(call,cname,all_inputs_muted);
1635 call->all_muted=all_inputs_muted;
1636 call->playing_ringbacktone=send_ringbacktone;
1637 call->up_bw=linphone_core_get_upload_bandwidth(lc);
1639 if (call->params.media_encryption==LinphoneMediaEncryptionZRTP) {
1640 OrtpZrtpParams params;
1641 /*will be set later when zrtp is activated*/
1642 call->current_params.media_encryption=LinphoneMediaEncryptionNone;
1644 params.zid_file=lc->zrtp_secrets_cache;
1645 audio_stream_enable_zrtp(call->audiostream,¶ms);
1646 }else if (call->params.media_encryption==LinphoneMediaEncryptionSRTP){
1647 call->current_params.media_encryption=linphone_call_are_all_streams_encrypted(call) ?
1648 LinphoneMediaEncryptionSRTP : LinphoneMediaEncryptionNone;
1651 /*also reflect the change if the "wished" params, in order to avoid to propose SAVP or video again
1652 * further in the call, for example during pause,resume, conferencing reINVITEs*/
1653 linphone_call_fix_call_parameters(call);
1654 if ((call->ice_session != NULL) && (ice_session_state(call->ice_session) != IS_Completed)) {
1655 ice_session_start_connectivity_checks(call->ice_session);
1661 linphone_address_destroy(me);
1664 void linphone_call_start_media_streams_for_ice_gathering(LinphoneCall *call){
1665 audio_stream_prepare_sound(call->audiostream, NULL, NULL);
1666 #ifdef VIDEO_ENABLED
1667 if (call->videostream) {
1668 video_stream_prepare_video(call->videostream);
1673 void linphone_call_stop_media_streams_for_ice_gathering(LinphoneCall *call){
1674 audio_stream_unprepare_sound(call->audiostream);
1675 #ifdef VIDEO_ENABLED
1676 if (call->videostream) {
1677 video_stream_unprepare_video(call->videostream);
1682 void linphone_call_delete_ice_session(LinphoneCall *call){
1683 if (call->ice_session != NULL) {
1684 ice_session_destroy(call->ice_session);
1685 call->ice_session = NULL;
1686 if (call->audiostream != NULL) call->audiostream->ice_check_list = NULL;
1687 if (call->videostream != NULL) call->videostream->ice_check_list = NULL;
1688 call->stats[LINPHONE_CALL_STATS_AUDIO].ice_state = LinphoneIceStateNotActivated;
1689 call->stats[LINPHONE_CALL_STATS_VIDEO].ice_state = LinphoneIceStateNotActivated;
1694 void linphone_call_delete_upnp_session(LinphoneCall *call){
1695 if(call->upnp_session!=NULL) {
1696 upnp_session_destroy(call->upnp_session);
1697 call->upnp_session=NULL;
1702 static void linphone_call_log_fill_stats(LinphoneCallLog *log, AudioStream *st){
1703 audio_stream_get_local_rtp_stats (st,&log->local_stats);
1704 log->quality=audio_stream_get_average_quality_rating(st);
1707 void linphone_call_stop_audio_stream(LinphoneCall *call) {
1708 if (call->audiostream!=NULL) {
1709 rtp_session_unregister_event_queue(call->audiostream->session,call->audiostream_app_evq);
1710 ortp_ev_queue_flush(call->audiostream_app_evq);
1711 ortp_ev_queue_destroy(call->audiostream_app_evq);
1712 call->audiostream_app_evq=NULL;
1714 if (call->audiostream->ec){
1715 const char *state_str=NULL;
1716 ms_filter_call_method(call->audiostream->ec,MS_ECHO_CANCELLER_GET_STATE_STRING,&state_str);
1718 ms_message("Writing echo canceler state, %i bytes",(int)strlen(state_str));
1719 lp_config_set_string(call->core->config,"sound","ec_state",state_str);
1722 linphone_call_log_fill_stats (call->log,call->audiostream);
1723 if (call->endpoint){
1724 linphone_call_remove_from_conf(call);
1726 audio_stream_stop(call->audiostream);
1727 call->audiostream=NULL;
1731 void linphone_call_stop_video_stream(LinphoneCall *call) {
1732 #ifdef VIDEO_ENABLED
1733 if (call->videostream!=NULL){
1734 rtp_session_unregister_event_queue(call->videostream->session,call->videostream_app_evq);
1735 ortp_ev_queue_flush(call->videostream_app_evq);
1736 ortp_ev_queue_destroy(call->videostream_app_evq);
1737 call->videostream_app_evq=NULL;
1738 video_stream_stop(call->videostream);
1739 call->videostream=NULL;
1744 void linphone_call_stop_media_streams(LinphoneCall *call){
1745 linphone_call_stop_audio_stream(call);
1746 linphone_call_stop_video_stream(call);
1747 ms_event_queue_skip(call->core->msevq);
1749 if (call->audio_profile){
1750 rtp_profile_clear_all(call->audio_profile);
1751 rtp_profile_destroy(call->audio_profile);
1752 call->audio_profile=NULL;
1754 if (call->video_profile){
1755 rtp_profile_clear_all(call->video_profile);
1756 rtp_profile_destroy(call->video_profile);
1757 call->video_profile=NULL;
1763 void linphone_call_enable_echo_cancellation(LinphoneCall *call, bool_t enable) {
1764 if (call!=NULL && call->audiostream!=NULL && call->audiostream->ec){
1765 bool_t bypass_mode = !enable;
1766 ms_filter_call_method(call->audiostream->ec,MS_ECHO_CANCELLER_SET_BYPASS_MODE,&bypass_mode);
1769 bool_t linphone_call_echo_cancellation_enabled(LinphoneCall *call) {
1770 if (call!=NULL && call->audiostream!=NULL && call->audiostream->ec){
1772 ms_filter_call_method(call->audiostream->ec,MS_ECHO_CANCELLER_GET_BYPASS_MODE,&val);
1775 return linphone_core_echo_cancellation_enabled(call->core);
1779 void linphone_call_enable_echo_limiter(LinphoneCall *call, bool_t val){
1780 if (call!=NULL && call->audiostream!=NULL ) {
1782 const char *type=lp_config_get_string(call->core->config,"sound","el_type","mic");
1783 if (strcasecmp(type,"mic")==0)
1784 audio_stream_enable_echo_limiter(call->audiostream,ELControlMic);
1785 else if (strcasecmp(type,"full")==0)
1786 audio_stream_enable_echo_limiter(call->audiostream,ELControlFull);
1788 audio_stream_enable_echo_limiter(call->audiostream,ELInactive);
1793 bool_t linphone_call_echo_limiter_enabled(const LinphoneCall *call){
1794 if (call!=NULL && call->audiostream!=NULL ){
1795 return call->audiostream->el_type !=ELInactive ;
1797 return linphone_core_echo_limiter_enabled(call->core);
1802 * @addtogroup call_misc
1807 * Returns the measured sound volume played locally (received from remote).
1808 * It is expressed in dbm0.
1810 float linphone_call_get_play_volume(LinphoneCall *call){
1811 AudioStream *st=call->audiostream;
1812 if (st && st->volrecv){
1814 ms_filter_call_method(st->volrecv,MS_VOLUME_GET,&vol);
1818 return LINPHONE_VOLUME_DB_LOWEST;
1822 * Returns the measured sound volume recorded locally (sent to remote).
1823 * It is expressed in dbm0.
1825 float linphone_call_get_record_volume(LinphoneCall *call){
1826 AudioStream *st=call->audiostream;
1827 if (st && st->volsend && !call->audio_muted && call->state==LinphoneCallStreamsRunning){
1829 ms_filter_call_method(st->volsend,MS_VOLUME_GET,&vol);
1833 return LINPHONE_VOLUME_DB_LOWEST;
1837 * Obtain real-time quality rating of the call
1839 * Based on local RTP statistics and RTCP feedback, a quality rating is computed and updated
1840 * during all the duration of the call. This function returns its value at the time of the function call.
1841 * It is expected that the rating is updated at least every 5 seconds or so.
1842 * The rating is a floating point number comprised between 0 and 5.
1844 * 4-5 = good quality <br>
1845 * 3-4 = average quality <br>
1846 * 2-3 = poor quality <br>
1847 * 1-2 = very poor quality <br>
1848 * 0-1 = can't be worse, mostly unusable <br>
1850 * @returns The function returns -1 if no quality measurement is available, for example if no
1851 * active audio stream exist. Otherwise it returns the quality rating.
1853 float linphone_call_get_current_quality(LinphoneCall *call){
1854 if (call->audiostream){
1855 return audio_stream_get_quality_rating(call->audiostream);
1861 * Returns call quality averaged over all the duration of the call.
1863 * See linphone_call_get_current_quality() for more details about quality measurement.
1865 float linphone_call_get_average_quality(LinphoneCall *call){
1866 if (call->audiostream){
1867 return audio_stream_get_average_quality_rating(call->audiostream);
1873 * Access last known statistics for audio stream, for a given call.
1875 const LinphoneCallStats *linphone_call_get_audio_stats(const LinphoneCall *call) {
1876 return &call->stats[LINPHONE_CALL_STATS_AUDIO];
1880 * Access last known statistics for video stream, for a given call.
1882 const LinphoneCallStats *linphone_call_get_video_stats(const LinphoneCall *call) {
1883 return &call->stats[LINPHONE_CALL_STATS_VIDEO];
1891 static void report_bandwidth(LinphoneCall *call, RtpSession *as, RtpSession *vs){
1892 call->stats[LINPHONE_CALL_STATS_AUDIO].download_bandwidth=(as!=NULL) ? (rtp_session_compute_recv_bandwidth(as)*1e-3) : 0;
1893 call->stats[LINPHONE_CALL_STATS_AUDIO].upload_bandwidth=(as!=NULL) ? (rtp_session_compute_send_bandwidth(as)*1e-3) : 0;
1894 call->stats[LINPHONE_CALL_STATS_VIDEO].download_bandwidth=(vs!=NULL) ? (rtp_session_compute_recv_bandwidth(vs)*1e-3) : 0;
1895 call->stats[LINPHONE_CALL_STATS_VIDEO].upload_bandwidth=(vs!=NULL) ? (rtp_session_compute_send_bandwidth(vs)*1e-3) : 0;
1896 ms_message("bandwidth usage: audio=[d=%.1f,u=%.1f] video=[d=%.1f,u=%.1f] kbit/sec",
1897 call->stats[LINPHONE_CALL_STATS_AUDIO].download_bandwidth,
1898 call->stats[LINPHONE_CALL_STATS_AUDIO].upload_bandwidth ,
1899 call->stats[LINPHONE_CALL_STATS_VIDEO].download_bandwidth,
1900 call->stats[LINPHONE_CALL_STATS_VIDEO].upload_bandwidth
1904 static void linphone_core_disconnected(LinphoneCore *lc, LinphoneCall *call){
1908 from = linphone_call_get_remote_address_as_string(call);
1911 snprintf(temp,sizeof(temp),"Remote end %s seems to have disconnected, the call is going to be closed.",from);
1916 snprintf(temp,sizeof(temp),"Remote end seems to have disconnected, the call is going to be closed.");
1918 if (lc->vtable.display_warning!=NULL)
1919 lc->vtable.display_warning(lc,temp);
1920 linphone_core_terminate_call(lc,call);
1923 static void handle_ice_events(LinphoneCall *call, OrtpEvent *ev){
1924 OrtpEventType evt=ortp_event_get_type(ev);
1925 OrtpEventData *evd=ortp_event_get_data(ev);
1928 if (evt == ORTP_EVENT_ICE_SESSION_PROCESSING_FINISHED) {
1929 switch (ice_session_state(call->ice_session)) {
1931 ice_session_select_candidates(call->ice_session);
1932 if (ice_session_role(call->ice_session) == IR_Controlling) {
1933 linphone_core_update_call(call->core, call, &call->current_params);
1937 if (ice_session_has_completed_check_list(call->ice_session) == TRUE) {
1938 ice_session_select_candidates(call->ice_session);
1939 if (ice_session_role(call->ice_session) == IR_Controlling) {
1940 /* At least one ICE session has succeeded, so perform a call update. */
1941 linphone_core_update_call(call->core, call, &call->current_params);
1948 linphone_core_update_ice_state_in_call_stats(call);
1949 } else if (evt == ORTP_EVENT_ICE_GATHERING_FINISHED) {
1951 if (evd->info.ice_processing_successful==TRUE) {
1952 ice_session_compute_candidates_foundations(call->ice_session);
1953 ice_session_eliminate_redundant_candidates(call->ice_session);
1954 ice_session_choose_default_candidates(call->ice_session);
1955 ping_time = ice_session_average_gathering_round_trip_time(call->ice_session);
1956 if (ping_time >=0) {
1957 call->ping_time=ping_time;
1960 ms_warning("No STUN answer from [%s], disabling ICE",linphone_core_get_stun_server(call->core));
1961 linphone_call_delete_ice_session(call);
1963 switch (call->state) {
1964 case LinphoneCallUpdating:
1965 linphone_core_start_update_call(call->core, call);
1967 case LinphoneCallUpdatedByRemote:
1968 linphone_core_start_accept_call_update(call->core, call);
1970 case LinphoneCallOutgoingInit:
1971 linphone_call_stop_media_streams_for_ice_gathering(call);
1972 linphone_core_proceed_with_invite_if_ready(call->core, call, NULL);
1974 case LinphoneCallIdle:
1975 linphone_call_stop_media_streams_for_ice_gathering(call);
1976 linphone_core_notify_incoming_call(call->core, call);
1981 } else if (evt == ORTP_EVENT_ICE_LOSING_PAIRS_COMPLETED) {
1982 linphone_core_start_accept_call_update(call->core, call);
1983 linphone_core_update_ice_state_in_call_stats(call);
1984 } else if (evt == ORTP_EVENT_ICE_RESTART_NEEDED) {
1985 ice_session_restart(call->ice_session);
1986 ice_session_set_role(call->ice_session, IR_Controlling);
1987 linphone_core_update_call(call->core, call, &call->current_params);
1991 void linphone_call_background_tasks(LinphoneCall *call, bool_t one_second_elapsed){
1992 LinphoneCore* lc = call->core;
1993 int disconnect_timeout = linphone_core_get_nortp_timeout(call->core);
1994 bool_t disconnected=FALSE;
1996 if (call->state==LinphoneCallStreamsRunning && one_second_elapsed){
1997 RtpSession *as=NULL,*vs=NULL;
1998 float audio_load=0, video_load=0;
1999 if (call->audiostream!=NULL){
2000 as=call->audiostream->session;
2001 if (call->audiostream->ticker)
2002 audio_load=ms_ticker_get_average_load(call->audiostream->ticker);
2004 if (call->videostream!=NULL){
2005 if (call->videostream->ticker)
2006 video_load=ms_ticker_get_average_load(call->videostream->ticker);
2007 vs=call->videostream->session;
2009 report_bandwidth(call,as,vs);
2010 ms_message("Thread processing load: audio=%f\tvideo=%f",audio_load,video_load);
2014 upnp_call_process(call);
2017 #ifdef VIDEO_ENABLED
2018 if (call->videostream!=NULL) {
2021 /* Ensure there is no dangling ICE check list. */
2022 if (call->ice_session == NULL) call->videostream->ice_check_list = NULL;
2024 // Beware that the application queue should not depend on treatments fron the
2025 // mediastreamer queue.
2026 video_stream_iterate(call->videostream);
2028 while (call->videostream_app_evq && (NULL != (ev=ortp_ev_queue_get(call->videostream_app_evq)))){
2029 OrtpEventType evt=ortp_event_get_type(ev);
2030 OrtpEventData *evd=ortp_event_get_data(ev);
2031 if (evt == ORTP_EVENT_ZRTP_ENCRYPTION_CHANGED){
2032 linphone_call_videostream_encryption_changed(call, evd->info.zrtp_stream_encrypted);
2033 } else if (evt == ORTP_EVENT_RTCP_PACKET_RECEIVED) {
2034 call->stats[LINPHONE_CALL_STATS_VIDEO].round_trip_delay = rtp_session_get_round_trip_propagation(call->videostream->session);
2035 if(call->stats[LINPHONE_CALL_STATS_VIDEO].received_rtcp != NULL)
2036 freemsg(call->stats[LINPHONE_CALL_STATS_VIDEO].received_rtcp);
2037 call->stats[LINPHONE_CALL_STATS_VIDEO].received_rtcp = evd->packet;
2039 if (lc->vtable.call_stats_updated)
2040 lc->vtable.call_stats_updated(lc, call, &call->stats[LINPHONE_CALL_STATS_VIDEO]);
2041 } else if (evt == ORTP_EVENT_RTCP_PACKET_EMITTED) {
2042 memcpy(&call->stats[LINPHONE_CALL_STATS_VIDEO].jitter_stats, rtp_session_get_jitter_stats(call->videostream->session), sizeof(jitter_stats_t));
2043 if(call->stats[LINPHONE_CALL_STATS_VIDEO].sent_rtcp != NULL)
2044 freemsg(call->stats[LINPHONE_CALL_STATS_VIDEO].sent_rtcp);
2045 call->stats[LINPHONE_CALL_STATS_VIDEO].sent_rtcp = evd->packet;
2047 if (lc->vtable.call_stats_updated)
2048 lc->vtable.call_stats_updated(lc, call, &call->stats[LINPHONE_CALL_STATS_VIDEO]);
2049 } else if ((evt == ORTP_EVENT_ICE_SESSION_PROCESSING_FINISHED) || (evt == ORTP_EVENT_ICE_GATHERING_FINISHED)
2050 || (evt == ORTP_EVENT_ICE_LOSING_PAIRS_COMPLETED) || (evt == ORTP_EVENT_ICE_RESTART_NEEDED)) {
2051 handle_ice_events(call, ev);
2053 ortp_event_destroy(ev);
2057 if (call->audiostream!=NULL) {
2060 /* Ensure there is no dangling ICE check list. */
2061 if (call->ice_session == NULL) call->audiostream->ice_check_list = NULL;
2063 // Beware that the application queue should not depend on treatments fron the
2064 // mediastreamer queue.
2065 audio_stream_iterate(call->audiostream);
2067 while (call->audiostream_app_evq && (NULL != (ev=ortp_ev_queue_get(call->audiostream_app_evq)))){
2068 OrtpEventType evt=ortp_event_get_type(ev);
2069 OrtpEventData *evd=ortp_event_get_data(ev);
2070 if (evt == ORTP_EVENT_ZRTP_ENCRYPTION_CHANGED){
2071 linphone_call_audiostream_encryption_changed(call, evd->info.zrtp_stream_encrypted);
2072 } else if (evt == ORTP_EVENT_ZRTP_SAS_READY) {
2073 linphone_call_audiostream_auth_token_ready(call, evd->info.zrtp_sas.sas, evd->info.zrtp_sas.verified);
2074 } else if (evt == ORTP_EVENT_RTCP_PACKET_RECEIVED) {
2075 call->stats[LINPHONE_CALL_STATS_AUDIO].round_trip_delay = rtp_session_get_round_trip_propagation(call->audiostream->session);
2076 if(call->stats[LINPHONE_CALL_STATS_AUDIO].received_rtcp != NULL)
2077 freemsg(call->stats[LINPHONE_CALL_STATS_AUDIO].received_rtcp);
2078 call->stats[LINPHONE_CALL_STATS_AUDIO].received_rtcp = evd->packet;
2080 if (lc->vtable.call_stats_updated)
2081 lc->vtable.call_stats_updated(lc, call, &call->stats[LINPHONE_CALL_STATS_AUDIO]);
2082 } else if (evt == ORTP_EVENT_RTCP_PACKET_EMITTED) {
2083 memcpy(&call->stats[LINPHONE_CALL_STATS_AUDIO].jitter_stats, rtp_session_get_jitter_stats(call->audiostream->session), sizeof(jitter_stats_t));
2084 if(call->stats[LINPHONE_CALL_STATS_AUDIO].sent_rtcp != NULL)
2085 freemsg(call->stats[LINPHONE_CALL_STATS_AUDIO].sent_rtcp);
2086 call->stats[LINPHONE_CALL_STATS_AUDIO].sent_rtcp = evd->packet;
2088 if (lc->vtable.call_stats_updated)
2089 lc->vtable.call_stats_updated(lc, call, &call->stats[LINPHONE_CALL_STATS_AUDIO]);
2090 } else if ((evt == ORTP_EVENT_ICE_SESSION_PROCESSING_FINISHED) || (evt == ORTP_EVENT_ICE_GATHERING_FINISHED)
2091 || (evt == ORTP_EVENT_ICE_LOSING_PAIRS_COMPLETED) || (evt == ORTP_EVENT_ICE_RESTART_NEEDED)) {
2092 handle_ice_events(call, ev);
2093 } else if (evt==ORTP_EVENT_TELEPHONE_EVENT){
2094 linphone_core_dtmf_received(lc,evd->info.telephone_event);
2096 ortp_event_destroy(ev);
2099 if (call->state==LinphoneCallStreamsRunning && one_second_elapsed && call->audiostream!=NULL && disconnect_timeout>0 )
2100 disconnected=!audio_stream_alive(call->audiostream,disconnect_timeout);
2102 linphone_core_disconnected(call->core,call);
2105 void linphone_call_log_completed(LinphoneCall *call){
2106 LinphoneCore *lc=call->core;
2108 call->log->duration=time(NULL)-call->start_time;
2110 if (call->log->status==LinphoneCallMissed){
2113 info=ortp_strdup_printf(ngettext("You have missed %i call.",
2114 "You have missed %i calls.", lc->missed_calls),
2116 if (lc->vtable.display_status!=NULL)
2117 lc->vtable.display_status(lc,info);
2120 lc->call_logs=ms_list_prepend(lc->call_logs,(void *)call->log);
2121 if (ms_list_size(lc->call_logs)>lc->max_call_logs){
2122 MSList *elem,*prevelem=NULL;
2123 /*find the last element*/
2124 for(elem=lc->call_logs;elem!=NULL;elem=elem->next){
2128 linphone_call_log_destroy((LinphoneCallLog*)elem->data);
2129 lc->call_logs=ms_list_remove_link(lc->call_logs,elem);
2131 if (lc->vtable.call_log_updated!=NULL){
2132 lc->vtable.call_log_updated(lc,call->log);
2134 call_logs_write_to_config_file(lc);
2137 LinphoneCallState linphone_call_get_transfer_state(LinphoneCall *call) {
2138 return call->transfer_state;
2141 void linphone_call_set_transfer_state(LinphoneCall* call, LinphoneCallState state) {
2142 if (state != call->transfer_state) {
2143 LinphoneCore* lc = call->core;
2144 call->transfer_state = state;
2145 if (lc->vtable.transfer_state_changed)
2146 lc->vtable.transfer_state_changed(lc, call, state);
2151 * Returns true if the call is part of the conference.
2152 * @ingroup conferencing
2154 bool_t linphone_call_is_in_conference(const LinphoneCall *call) {
2155 return call->params.in_conference;
2160 * Perform a zoom of the video displayed during a call.
2161 * @param call the call.
2162 * @param zoom_factor a floating point number describing the zoom factor. A value 1.0 corresponds to no zoom applied.
2163 * @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.
2164 * @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.
2166 * 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.
2168 void linphone_call_zoom_video(LinphoneCall* call, float zoom_factor, float* cx, float* cy) {
2169 VideoStream* vstream = call->videostream;
2170 if (vstream && vstream->output) {
2173 if (zoom_factor < 1)
2175 float halfsize = 0.5 * 1.0 / zoom_factor;
2177 if ((*cx - halfsize) < 0)
2179 if ((*cx + halfsize) > 1)
2181 if ((*cy - halfsize) < 0)
2183 if ((*cy + halfsize) > 1)
2186 zoom[0] = zoom_factor;
2189 ms_filter_call_method(vstream->output, MS_VIDEO_DISPLAY_ZOOM, &zoom);
2190 }else ms_warning("Could not apply zoom: video output wasn't activated.");