4 Copyright (C) 2010 Belledonne Communications SARL
5 (simon.morlat@linphone.org)
7 This program is free software; you can redistribute it and/or
8 modify it under the terms of the GNU General Public License
9 as published by the Free Software Foundation; either version 2
10 of the License, or (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24 #include "linphonecore.h"
28 #include <ortp/event.h>
32 #include "mediastreamer2/mediastream.h"
33 #include "mediastreamer2/msvolume.h"
34 #include "mediastreamer2/msequalizer.h"
35 #include "mediastreamer2/msfileplayer.h"
36 #include "mediastreamer2/msjpegwriter.h"
37 #include "mediastreamer2/mseventqueue.h"
38 #include "mediastreamer2/mssndcard.h"
41 static MSWebCam *get_nowebcam_device(){
42 return ms_web_cam_manager_get_cam(ms_web_cam_manager_get(),"StaticImage: Static picture");
46 static bool_t generate_b64_crypto_key(int key_length, char* key_out) {
48 uint8_t* tmp = (uint8_t*) malloc(key_length);
49 if (ortp_crypto_get_random(tmp, key_length)!=0) {
50 ms_error("Failed to generate random key");
55 b64_size = b64_encode((const char*)tmp, key_length, NULL, 0);
57 ms_error("Failed to b64 encode key");
61 key_out[b64_size] = '\0';
62 b64_encode((const char*)tmp, key_length, key_out, 40);
67 LinphoneCore *linphone_call_get_core(const LinphoneCall *call){
71 const char* linphone_call_get_authentication_token(LinphoneCall *call){
72 return call->auth_token;
75 bool_t linphone_call_get_authentication_token_verified(LinphoneCall *call){
76 return call->auth_token_verified;
79 static bool_t linphone_call_are_all_streams_encrypted(LinphoneCall *call) {
80 // Check ZRTP encryption in audiostream
81 if (!call->audiostream_encrypted) {
86 // If video enabled, check ZRTP encryption in videostream
87 const LinphoneCallParams *params=linphone_call_get_current_params(call);
88 if (params->has_video && !call->videostream_encrypted) {
96 void propagate_encryption_changed(LinphoneCall *call){
97 LinphoneCore *lc=call->core;
98 if (!linphone_call_are_all_streams_encrypted(call)) {
99 ms_message("Some streams are not encrypted");
100 call->current_params.media_encryption=LinphoneMediaEncryptionNone;
101 if (lc->vtable.call_encryption_changed)
102 lc->vtable.call_encryption_changed(call->core, call, FALSE, call->auth_token);
104 ms_message("All streams are encrypted");
105 call->current_params.media_encryption=LinphoneMediaEncryptionZRTP;
106 if (lc->vtable.call_encryption_changed)
107 lc->vtable.call_encryption_changed(call->core, call, TRUE, call->auth_token);
112 static void linphone_call_videostream_encryption_changed(void *data, bool_t encrypted){
113 ms_message("Video stream is %s", encrypted ? "encrypted" : "not encrypted");
115 LinphoneCall *call = (LinphoneCall *)data;
116 call->videostream_encrypted=encrypted;
117 propagate_encryption_changed(call);
121 static void linphone_call_audiostream_encryption_changed(void *data, bool_t encrypted) {
122 char status[255]={0};
123 ms_message("Audio stream is %s ", encrypted ? "encrypted" : "not encrypted");
125 LinphoneCall *call = (LinphoneCall *)data;
126 call->audiostream_encrypted=encrypted;
128 if (encrypted && call->core->vtable.display_status != NULL) {
129 snprintf(status,sizeof(status)-1,_("Authentication token is %s"),call->auth_token);
130 call->core->vtable.display_status(call->core, status);
133 propagate_encryption_changed(call);
137 // Enable video encryption
138 const LinphoneCallParams *params=linphone_call_get_current_params(call);
139 if (params->has_video) {
140 ms_message("Trying to enable encryption on video stream");
141 OrtpZrtpParams params;
142 params.zid_file=NULL; //unused
143 video_stream_enable_zrtp(call->videostream,call->audiostream,¶ms);
149 static void linphone_call_audiostream_auth_token_ready(void *data, const char* auth_token, bool_t verified) {
150 LinphoneCall *call=(LinphoneCall *)data;
151 if (call->auth_token != NULL)
152 ms_free(call->auth_token);
154 call->auth_token=ms_strdup(auth_token);
155 call->auth_token_verified=verified;
157 ms_message("Authentication token is %s (%s)", auth_token, verified?"verified":"unverified");
160 void linphone_call_set_authentication_token_verified(LinphoneCall *call, bool_t verified){
161 if (call->audiostream==NULL){
162 ms_error("linphone_call_set_authentication_token_verified(): No audio stream");
164 if (call->audiostream->ms.zrtp_context==NULL){
165 ms_error("linphone_call_set_authentication_token_verified(): No zrtp context.");
167 if (!call->auth_token_verified && verified){
168 ortp_zrtp_sas_verified(call->audiostream->ms.zrtp_context);
169 }else if (call->auth_token_verified && !verified){
170 ortp_zrtp_sas_reset_verified(call->audiostream->ms.zrtp_context);
172 call->auth_token_verified=verified;
173 propagate_encryption_changed(call);
176 static MSList *make_codec_list(LinphoneCore *lc, const MSList *codecs, int bandwidth_limit,int* max_sample_rate, int nb_codecs_limit){
180 if (max_sample_rate) *max_sample_rate=0;
181 for(it=codecs;it!=NULL;it=it->next){
182 PayloadType *pt=(PayloadType*)it->data;
183 if (pt->flags & PAYLOAD_TYPE_ENABLED){
184 if (bandwidth_limit>0 && !linphone_core_is_payload_type_usable_for_bandwidth(lc,pt,bandwidth_limit)){
185 ms_message("Codec %s/%i eliminated because of audio bandwidth constraint.",pt->mime_type,pt->clock_rate);
188 if (linphone_core_check_payload_type_usability(lc,pt)){
189 l=ms_list_append(l,payload_type_clone(pt));
191 if (max_sample_rate && payload_type_get_rate(pt)>*max_sample_rate) *max_sample_rate=payload_type_get_rate(pt);
194 if ((nb_codecs_limit > 0) && (nb >= nb_codecs_limit)) break;
199 static void update_media_description_from_stun(SalMediaDescription *md, const StunCandidate *ac, const StunCandidate *vc){
201 for (i = 0; i < md->n_active_streams; i++) {
202 if ((md->streams[i].type == SalAudio) && (ac->port != 0)) {
203 strcpy(md->streams[0].rtp_addr,ac->addr);
204 md->streams[0].rtp_port=ac->port;
205 if ((ac->addr[0]!='\0' && vc->addr[0]!='\0' && strcmp(ac->addr,vc->addr)==0) || md->n_active_streams==1){
206 strcpy(md->addr,ac->addr);
209 if ((md->streams[i].type == SalVideo) && (vc->port != 0)) {
210 strcpy(md->streams[1].rtp_addr,vc->addr);
211 md->streams[1].rtp_port=vc->port;
216 void linphone_call_make_local_media_description(LinphoneCore *lc, LinphoneCall *call){
219 SalMediaDescription *old_md=call->localdesc;
221 const char *me=linphone_core_get_identity(lc);
222 LinphoneAddress *addr=linphone_address_new(me);
223 const char *username=linphone_address_get_username (addr);
224 SalMediaDescription *md=sal_media_description_new();
225 bool_t keep_srtp_keys=lp_config_get_int(lc->config,"sip","keep_srtp_keys",0);
227 linphone_core_adapt_to_network(lc,call->ping_time,&call->params);
229 md->session_id=(old_md ? old_md->session_id : (rand() & 0xfff));
230 md->session_ver=(old_md ? (old_md->session_ver+1) : (rand() & 0xfff));
231 md->n_total_streams=(old_md ? old_md->n_total_streams : 1);
232 md->n_active_streams=1;
233 strncpy(md->addr,call->localip,sizeof(md->addr));
234 strncpy(md->username,username,sizeof(md->username));
236 if (call->params.down_bw)
237 md->bandwidth=call->params.down_bw;
238 else md->bandwidth=linphone_core_get_download_bandwidth(lc);
240 /*set audio capabilities */
241 strncpy(md->streams[0].rtp_addr,call->localip,sizeof(md->streams[0].rtp_addr));
242 strncpy(md->streams[0].rtcp_addr,call->localip,sizeof(md->streams[0].rtcp_addr));
243 md->streams[0].rtp_port=call->audio_port;
244 md->streams[0].rtcp_port=call->audio_port+1;
245 md->streams[0].proto=(call->params.media_encryption == LinphoneMediaEncryptionSRTP) ?
246 SalProtoRtpSavp : SalProtoRtpAvp;
247 md->streams[0].type=SalAudio;
248 if (call->params.down_ptime)
249 md->streams[0].ptime=call->params.down_ptime;
251 md->streams[0].ptime=linphone_core_get_download_ptime(lc);
252 l=make_codec_list(lc,lc->codecs_conf.audio_codecs,call->params.audio_bw,&md->streams[0].max_rate,-1);
253 pt=payload_type_clone(rtp_profile_get_payload_from_mime(lc->default_profile,"telephone-event"));
254 l=ms_list_append(l,pt);
255 md->streams[0].payloads=l;
257 if (call->params.has_video){
258 md->n_active_streams++;
259 md->streams[1].rtp_port=call->video_port;
260 md->streams[1].rtcp_port=call->video_port+1;
261 md->streams[1].proto=md->streams[0].proto;
262 md->streams[1].type=SalVideo;
263 l=make_codec_list(lc,lc->codecs_conf.video_codecs,0,NULL,-1);
264 md->streams[1].payloads=l;
266 if (md->n_total_streams < md->n_active_streams)
267 md->n_total_streams = md->n_active_streams;
269 /* Deactivate inactive streams. */
270 for (i = md->n_active_streams; i < md->n_total_streams; i++) {
271 md->streams[i].rtp_port = 0;
272 md->streams[i].rtcp_port = 0;
273 md->streams[i].proto = SalProtoRtpAvp;
274 md->streams[i].type = old_md->streams[i].type;
275 md->streams[i].dir = SalStreamInactive;
276 l = make_codec_list(lc, lc->codecs_conf.video_codecs, 0, NULL, 1);
277 md->streams[i].payloads = l;
280 for(i=0; i<md->n_active_streams; i++) {
281 if (md->streams[i].proto == SalProtoRtpSavp) {
282 if (keep_srtp_keys && old_md && old_md->streams[i].proto==SalProtoRtpSavp){
284 for(j=0;j<SAL_CRYPTO_ALGO_MAX;++j){
285 memcpy(&md->streams[i].crypto[j],&old_md->streams[i].crypto[j],sizeof(SalSrtpCryptoAlgo));
288 md->streams[i].crypto[0].tag = 1;
289 md->streams[i].crypto[0].algo = AES_128_SHA1_80;
290 if (!generate_b64_crypto_key(30, md->streams[i].crypto[0].master_key))
291 md->streams[i].crypto[0].algo = 0;
292 md->streams[i].crypto[1].tag = 2;
293 md->streams[i].crypto[1].algo = AES_128_SHA1_32;
294 if (!generate_b64_crypto_key(30, md->streams[i].crypto[1].master_key))
295 md->streams[i].crypto[1].algo = 0;
296 md->streams[i].crypto[2].algo = 0;
300 update_media_description_from_stun(md,&call->ac,&call->vc);
301 if (call->ice_session != NULL) {
302 linphone_core_update_local_media_description_from_ice(md, call->ice_session);
303 linphone_core_update_ice_state_in_call_stats(call);
305 linphone_address_destroy(addr);
307 if (old_md) sal_media_description_unref(old_md);
310 static int find_port_offset(LinphoneCore *lc, SalStreamType type){
315 bool_t already_used=FALSE;
316 for(offset=0;offset<100;offset+=2){
320 tried_port=linphone_core_get_audio_port (lc)+offset;
323 tried_port=linphone_core_get_video_port (lc)+offset;
327 for(elem=lc->calls;elem!=NULL;elem=elem->next){
328 LinphoneCall *call=(LinphoneCall*)elem->data;
332 existing_port = call->audio_port;
335 existing_port = call->video_port;
338 if (existing_port==tried_port) {
343 if (!already_used) break;
346 ms_error("Could not find any free port !");
352 static int select_random_port(LinphoneCore *lc, SalStreamType type) {
356 int existing_port = 0;
357 int min_port = 0, max_port = 0;
358 bool_t already_used = FALSE;
363 linphone_core_get_audio_port_range(lc, &min_port, &max_port);
366 linphone_core_get_video_port_range(lc, &min_port, &max_port);
369 tried_port = (rand() % (max_port - min_port) + min_port) & ~0x1;
370 if (tried_port < min_port) tried_port = min_port + 2;
371 for (nb_tries = 0; nb_tries < 100; nb_tries++) {
372 for (elem = lc->calls; elem != NULL; elem = elem->next) {
373 LinphoneCall *call = (LinphoneCall *)elem->data;
377 existing_port = call->audio_port;
380 existing_port = call->video_port;
383 if (existing_port == tried_port) {
388 if (!already_used) break;
390 if (nb_tries == 100) {
391 ms_error("Could not find any free port!");
397 static void linphone_call_init_common(LinphoneCall *call, LinphoneAddress *from, LinphoneAddress *to){
399 int min_port, max_port;
400 call->magic=linphone_call_magic;
402 call->state=LinphoneCallIdle;
403 call->transfer_state = LinphoneCallIdle;
404 call->start_time=time(NULL);
405 call->media_start_time=0;
406 call->log=linphone_call_log_new(call, from, to);
407 call->owns_call_log=TRUE;
408 linphone_core_notify_all_friends(call->core,LinphoneStatusOnThePhone);
409 linphone_core_get_audio_port_range(call->core, &min_port, &max_port);
410 if (min_port == max_port) {
411 /* Used fixed RTP audio port. */
412 port_offset=find_port_offset (call->core, SalAudio);
413 if (port_offset==-1) return;
414 call->audio_port=linphone_core_get_audio_port(call->core)+port_offset;
416 /* Select random RTP audio port in the specified range. */
417 call->audio_port = select_random_port(call->core, SalAudio);
419 linphone_core_get_video_port_range(call->core, &min_port, &max_port);
420 if (min_port == max_port) {
421 /* Used fixed RTP video port. */
422 port_offset=find_port_offset (call->core, SalVideo);
423 if (port_offset==-1) return;
424 call->video_port=linphone_core_get_video_port(call->core)+port_offset;
426 /* Select random RTP video port in the specified range. */
427 call->video_port = select_random_port(call->core, SalVideo);
429 linphone_call_init_stats(&call->stats[LINPHONE_CALL_STATS_AUDIO], LINPHONE_CALL_STATS_AUDIO);
430 linphone_call_init_stats(&call->stats[LINPHONE_CALL_STATS_VIDEO], LINPHONE_CALL_STATS_VIDEO);
433 void linphone_call_init_stats(LinphoneCallStats *stats, int type) {
435 stats->received_rtcp = NULL;
436 stats->sent_rtcp = NULL;
437 stats->ice_state = LinphoneIceStateNotActivated;
441 static void discover_mtu(LinphoneCore *lc, const char *remote){
443 if (lc->net_conf.mtu==0 ){
444 /*attempt to discover mtu*/
445 mtu=ms_discover_mtu(remote);
448 ms_message("Discovered mtu is %i, RTP payload max size is %i",
449 mtu, ms_get_payload_max_size());
454 LinphoneCall * linphone_call_new_outgoing(struct _LinphoneCore *lc, LinphoneAddress *from, LinphoneAddress *to, const LinphoneCallParams *params)
456 LinphoneCall *call=ms_new0(LinphoneCall,1);
457 call->dir=LinphoneCallOutgoing;
458 call->op=sal_op_new(lc->sal);
459 sal_op_set_user_pointer(call->op,call);
461 linphone_core_get_local_ip(lc,linphone_address_get_domain(to),call->localip);
462 linphone_call_init_common(call,from,to);
463 call->params=*params;
464 if (linphone_core_get_firewall_policy(call->core) == LinphonePolicyUseIce) {
465 call->ice_session = ice_session_new();
466 ice_session_set_role(call->ice_session, IR_Controlling);
468 if (linphone_core_get_firewall_policy(call->core) == LinphonePolicyUseStun) {
469 call->ping_time=linphone_core_run_stun_tests(call->core,call);
471 call->camera_active=params->has_video;
473 discover_mtu(lc,linphone_address_get_domain (to));
474 if (params->referer){
475 sal_call_set_referer(call->op,params->referer->op);
476 call->referer=linphone_call_ref(params->referer);
481 LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *from, LinphoneAddress *to, SalOp *op){
482 LinphoneCall *call=ms_new0(LinphoneCall,1);
484 const SalMediaDescription *md;
486 call->dir=LinphoneCallIncoming;
487 sal_op_set_user_pointer(op,call);
491 if (lc->sip_conf.ping_with_options){
492 /*the following sends an option request back to the caller so that
493 we get a chance to discover our nat'd address before answering.*/
494 call->ping_op=sal_op_new(lc->sal);
495 from_str=linphone_address_as_string_uri_only(from);
496 sal_op_set_route(call->ping_op,sal_op_get_network_origin(op));
497 sal_op_set_user_pointer(call->ping_op,call);
498 sal_ping(call->ping_op,linphone_core_find_best_identity(lc,from,NULL),from_str);
502 linphone_address_clean(from);
503 linphone_core_get_local_ip(lc,linphone_address_get_domain(from),call->localip);
504 linphone_call_init_common(call, from, to);
505 call->log->call_id=ms_strdup(sal_op_get_call_id(op)); /*must be known at that time*/
506 linphone_core_init_default_params(lc, &call->params);
507 md=sal_call_get_remote_media_description(op);
508 call->params.has_video &= !!lc->video_policy.automatically_accept;
510 // It is licit to receive an INVITE without SDP
511 // In this case WE chose the media parameters according to policy.
512 call->params.has_video &= linphone_core_media_description_contains_video_stream(md);
514 switch (linphone_core_get_firewall_policy(call->core)) {
515 case LinphonePolicyUseIce:
516 call->ice_session = ice_session_new();
517 ice_session_set_role(call->ice_session, IR_Controlled);
518 linphone_core_update_ice_from_remote_media_description(call, sal_call_get_remote_media_description(op));
519 if (call->ice_session != NULL) {
520 linphone_call_init_media_streams(call);
521 linphone_call_start_media_streams_for_ice_gathering(call);
522 if (linphone_core_gather_ice_candidates(call->core,call)<0) {
523 /* Ice candidates gathering failed, proceed with the call anyway. */
524 linphone_call_delete_ice_session(call);
525 linphone_call_stop_media_streams_for_ice_gathering(call);
529 case LinphonePolicyUseStun:
530 call->ping_time=linphone_core_run_stun_tests(call->core,call);
531 /* No break to also destroy ice session in this case. */
535 call->camera_active=call->params.has_video;
537 discover_mtu(lc,linphone_address_get_domain(from));
541 /* this function is called internally to get rid of a call.
542 It performs the following tasks:
543 - remove the call from the internal list of calls
544 - update the call logs accordingly
547 static void linphone_call_set_terminated(LinphoneCall *call){
548 LinphoneCore *lc=call->core;
550 linphone_core_update_allocated_audio_bandwidth(lc);
552 call->owns_call_log=FALSE;
553 linphone_call_log_completed(call);
556 if (call == lc->current_call){
557 ms_message("Resetting the current call");
558 lc->current_call=NULL;
561 if (linphone_core_del_call(lc,call) != 0){
562 ms_error("Could not remove the call from the list !!!");
565 if (ms_list_size(lc->calls)==0)
566 linphone_core_notify_all_friends(lc,lc->presence_mode);
568 linphone_core_conference_check_uninit(lc);
569 if (call->ringing_beep){
570 linphone_core_stop_dtmf(lc);
571 call->ringing_beep=FALSE;
574 linphone_call_unref(call->referer);
579 void linphone_call_fix_call_parameters(LinphoneCall *call){
580 call->params.has_video=call->current_params.has_video;
581 call->params.media_encryption=call->current_params.media_encryption;
584 const char *linphone_call_state_to_string(LinphoneCallState cs){
586 case LinphoneCallIdle:
587 return "LinphoneCallIdle";
588 case LinphoneCallIncomingReceived:
589 return "LinphoneCallIncomingReceived";
590 case LinphoneCallOutgoingInit:
591 return "LinphoneCallOutgoingInit";
592 case LinphoneCallOutgoingProgress:
593 return "LinphoneCallOutgoingProgress";
594 case LinphoneCallOutgoingRinging:
595 return "LinphoneCallOutgoingRinging";
596 case LinphoneCallOutgoingEarlyMedia:
597 return "LinphoneCallOutgoingEarlyMedia";
598 case LinphoneCallConnected:
599 return "LinphoneCallConnected";
600 case LinphoneCallStreamsRunning:
601 return "LinphoneCallStreamsRunning";
602 case LinphoneCallPausing:
603 return "LinphoneCallPausing";
604 case LinphoneCallPaused:
605 return "LinphoneCallPaused";
606 case LinphoneCallResuming:
607 return "LinphoneCallResuming";
608 case LinphoneCallRefered:
609 return "LinphoneCallRefered";
610 case LinphoneCallError:
611 return "LinphoneCallError";
612 case LinphoneCallEnd:
613 return "LinphoneCallEnd";
614 case LinphoneCallPausedByRemote:
615 return "LinphoneCallPausedByRemote";
616 case LinphoneCallUpdatedByRemote:
617 return "LinphoneCallUpdatedByRemote";
618 case LinphoneCallIncomingEarlyMedia:
619 return "LinphoneCallIncomingEarlyMedia";
620 case LinphoneCallUpdating:
621 return "LinphoneCallUpdating";
622 case LinphoneCallReleased:
623 return "LinphoneCallReleased";
625 return "undefined state";
628 void linphone_call_set_state(LinphoneCall *call, LinphoneCallState cstate, const char *message){
629 LinphoneCore *lc=call->core;
631 if (call->state!=cstate){
632 if (call->state==LinphoneCallEnd || call->state==LinphoneCallError){
633 if (cstate!=LinphoneCallReleased){
634 ms_warning("Spurious call state change from %s to %s, ignored.",linphone_call_state_to_string(call->state),
635 linphone_call_state_to_string(cstate));
639 ms_message("Call %p: moving from state %s to %s",call,linphone_call_state_to_string(call->state),
640 linphone_call_state_to_string(cstate));
641 if (cstate!=LinphoneCallRefered){
642 /*LinphoneCallRefered is rather an event, not a state.
643 Indeed it does not change the state of the call (still paused or running)*/
646 if (cstate==LinphoneCallEnd || cstate==LinphoneCallError){
647 switch(call->reason){
648 case LinphoneReasonDeclined:
649 call->log->status=LinphoneCallDeclined;
651 case LinphoneReasonNotAnswered:
652 call->log->status=LinphoneCallMissed;
657 linphone_call_set_terminated (call);
659 if (cstate == LinphoneCallConnected) {
660 call->log->status=LinphoneCallSuccess;
661 call->media_start_time=time(NULL);
664 if (lc->vtable.call_state_changed)
665 lc->vtable.call_state_changed(lc,call,cstate,message);
666 if (cstate==LinphoneCallReleased){
667 if (call->op!=NULL) {
668 /* so that we cannot have anymore upcalls for SAL
669 concerning this call*/
670 sal_op_release(call->op);
673 linphone_call_unref(call);
678 static void linphone_call_destroy(LinphoneCall *obj)
680 linphone_call_delete_ice_session(obj);
682 sal_op_release(obj->op);
685 if (obj->resultdesc!=NULL) {
686 sal_media_description_unref(obj->resultdesc);
687 obj->resultdesc=NULL;
689 if (obj->localdesc!=NULL) {
690 sal_media_description_unref(obj->localdesc);
694 sal_op_release(obj->ping_op);
697 ms_free(obj->refer_to);
699 if (obj->owns_call_log)
700 linphone_call_log_destroy(obj->log);
701 if (obj->auth_token) {
702 ms_free(obj->auth_token);
709 * @addtogroup call_control
714 * Increments the call 's reference count.
715 * An application that wishes to retain a pointer to call object
716 * must use this function to unsure the pointer remains
717 * valid. Once the application no more needs this pointer,
718 * it must call linphone_call_unref().
720 LinphoneCall * linphone_call_ref(LinphoneCall *obj){
726 * Decrements the call object reference count.
727 * See linphone_call_ref().
729 void linphone_call_unref(LinphoneCall *obj){
732 linphone_call_destroy(obj);
737 * Returns current parameters associated to the call.
739 const LinphoneCallParams * linphone_call_get_current_params(const LinphoneCall *call){
740 return &call->current_params;
743 static bool_t is_video_active(const SalStreamDescription *sd){
744 return sd->rtp_port!=0 && sd->dir!=SalStreamInactive;
748 * Returns call parameters proposed by remote.
750 * This is useful when receiving an incoming call, to know whether the remote party
751 * supports video, encryption or whatever.
753 const LinphoneCallParams * linphone_call_get_remote_params(LinphoneCall *call){
754 LinphoneCallParams *cp=&call->remote_params;
755 memset(cp,0,sizeof(*cp));
757 SalMediaDescription *md=sal_call_get_remote_media_description(call->op);
759 SalStreamDescription *asd,*vsd,*secure_asd,*secure_vsd;
761 asd=sal_media_description_find_stream(md,SalProtoRtpAvp,SalAudio);
762 vsd=sal_media_description_find_stream(md,SalProtoRtpAvp,SalVideo);
763 secure_asd=sal_media_description_find_stream(md,SalProtoRtpSavp,SalAudio);
764 secure_vsd=sal_media_description_find_stream(md,SalProtoRtpSavp,SalVideo);
766 cp->has_video=is_video_active(secure_vsd);
767 if (secure_asd || asd==NULL)
768 cp->media_encryption=LinphoneMediaEncryptionSRTP;
770 cp->has_video=is_video_active(vsd);
773 if (md->bandwidth>0 && md->bandwidth<=linphone_core_get_edge_bw(call->core)){
774 cp->low_bandwidth=TRUE;
784 * Returns the remote address associated to this call
787 const LinphoneAddress * linphone_call_get_remote_address(const LinphoneCall *call){
788 return call->dir==LinphoneCallIncoming ? call->log->from : call->log->to;
792 * Returns the remote address associated to this call as a string.
794 * The result string must be freed by user using ms_free().
796 char *linphone_call_get_remote_address_as_string(const LinphoneCall *call){
797 return linphone_address_as_string(linphone_call_get_remote_address(call));
801 * Retrieves the call's current state.
803 LinphoneCallState linphone_call_get_state(const LinphoneCall *call){
808 * Returns the reason for a call termination (either error or normal termination)
810 LinphoneReason linphone_call_get_reason(const LinphoneCall *call){
815 * Get the user_pointer in the LinphoneCall
817 * @ingroup call_control
819 * return user_pointer an opaque user pointer that can be retrieved at any time
821 void *linphone_call_get_user_pointer(LinphoneCall *call)
823 return call->user_pointer;
827 * Set the user_pointer in the LinphoneCall
829 * @ingroup call_control
831 * the user_pointer is an opaque user pointer that can be retrieved at any time in the LinphoneCall
833 void linphone_call_set_user_pointer(LinphoneCall *call, void *user_pointer)
835 call->user_pointer = user_pointer;
839 * Returns the call log associated to this call.
841 LinphoneCallLog *linphone_call_get_call_log(const LinphoneCall *call){
846 * Returns the refer-to uri (if the call was transfered).
848 const char *linphone_call_get_refer_to(const LinphoneCall *call){
849 return call->refer_to;
853 * Returns direction of the call (incoming or outgoing).
855 LinphoneCallDir linphone_call_get_dir(const LinphoneCall *call){
856 return call->log->dir;
860 * Returns the far end's user agent description string, if available.
862 const char *linphone_call_get_remote_user_agent(LinphoneCall *call){
864 return sal_op_get_remote_ua (call->op);
870 * Returns true if this calls has received a transfer that has not been
872 * Pending transfers are executed when this call is being paused or closed,
873 * locally or by remote endpoint.
874 * If the call is already paused while receiving the transfer request, the
875 * transfer immediately occurs.
877 bool_t linphone_call_has_transfer_pending(const LinphoneCall *call){
878 return call->refer_pending;
882 * Returns call's duration in seconds.
884 int linphone_call_get_duration(const LinphoneCall *call){
885 if (call->media_start_time==0) return 0;
886 return time(NULL)-call->media_start_time;
890 * Returns the call object this call is replacing, if any.
891 * Call replacement can occur during call transfers.
892 * By default, the core automatically terminates the replaced call and accept the new one.
893 * This function allows the application to know whether a new incoming call is a one that replaces another one.
895 LinphoneCall *linphone_call_get_replaced_call(LinphoneCall *call){
896 SalOp *op=sal_call_get_replaces(call->op);
898 return (LinphoneCall*)sal_op_get_user_pointer(op);
904 * Indicate whether camera input should be sent to remote end.
906 void linphone_call_enable_camera (LinphoneCall *call, bool_t enable){
908 if (call->videostream!=NULL && call->videostream->ms.ticker!=NULL){
909 LinphoneCore *lc=call->core;
910 MSWebCam *nowebcam=get_nowebcam_device();
911 if (call->camera_active!=enable && lc->video_conf.device!=nowebcam){
912 video_stream_change_camera(call->videostream,
913 enable ? lc->video_conf.device : nowebcam);
916 call->camera_active=enable;
921 * Take a photo of currently received video and write it into a jpeg file.
923 int linphone_call_take_video_snapshot(LinphoneCall *call, const char *file){
925 if (call->videostream!=NULL && call->videostream->jpegwriter!=NULL){
926 return ms_filter_call_method(call->videostream->jpegwriter,MS_JPEG_WRITER_TAKE_SNAPSHOT,(void*)file);
928 ms_warning("Cannot take snapshot: no currently running video stream on this call.");
935 * Returns TRUE if camera pictures are sent to the remote party.
937 bool_t linphone_call_camera_enabled (const LinphoneCall *call){
938 return call->camera_active;
942 * Enable video stream.
944 void linphone_call_params_enable_video(LinphoneCallParams *cp, bool_t enabled){
945 cp->has_video=enabled;
948 const PayloadType* linphone_call_params_get_used_audio_codec(const LinphoneCallParams *cp) {
949 return cp->audio_codec;
952 const PayloadType* linphone_call_params_get_used_video_codec(const LinphoneCallParams *cp) {
953 return cp->video_codec;
957 * @ingroup call_control
958 * Use to know if this call has been configured in low bandwidth mode.
959 * This mode can be automatically discovered thanks to a stun server when activate_edge_workarounds=1 in section [net] of configuration file.
960 * An application that would have reliable way to know network capacity may not use activate_edge_workarounds=1 but instead manually configure
961 * low bandwidth mode with linphone_call_params_enable_low_bandwidth().
962 * <br> When enabled, this param may transform a call request with video in audio only mode.
963 * @return TRUE if low bandwidth has been configured/detected
965 bool_t linphone_call_params_low_bandwidth_enabled(const LinphoneCallParams *cp) {
966 return cp->low_bandwidth;
970 * @ingroup call_control
971 * Indicate low bandwith mode.
972 * 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
973 * 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
974 * that it is achievable by the codec selected after SDP handshake. Video is automatically disabled.
977 void linphone_call_params_enable_low_bandwidth(LinphoneCallParams *cp, bool_t enabled){
978 cp->low_bandwidth=enabled;
982 * Returns whether video is enabled.
984 bool_t linphone_call_params_video_enabled(const LinphoneCallParams *cp){
985 return cp->has_video;
988 enum LinphoneMediaEncryption linphone_call_params_get_media_encryption(const LinphoneCallParams *cp) {
989 return cp->media_encryption;
992 void linphone_call_params_set_media_encryption(LinphoneCallParams *cp, enum LinphoneMediaEncryption e) {
993 cp->media_encryption = e;
998 * Enable sending of real early media (during outgoing calls).
1000 void linphone_call_params_enable_early_media_sending(LinphoneCallParams *cp, bool_t enabled){
1001 cp->real_early_media=enabled;
1004 bool_t linphone_call_params_early_media_sending_enabled(const LinphoneCallParams *cp){
1005 return cp->real_early_media;
1009 * Returns true if the call is part of the locally managed conference.
1011 bool_t linphone_call_params_local_conference_mode(const LinphoneCallParams *cp){
1012 return cp->in_conference;
1016 * Refine bandwidth settings for this call by setting a bandwidth limit for audio streams.
1017 * As a consequence, codecs whose bitrates are not compatible with this limit won't be used.
1019 void linphone_call_params_set_audio_bandwidth_limit(LinphoneCallParams *cp, int bandwidth){
1020 cp->audio_bw=bandwidth;
1023 #ifdef VIDEO_ENABLED
1025 * Request remote side to send us a Video Fast Update.
1027 void linphone_call_send_vfu_request(LinphoneCall *call)
1029 if (LinphoneCallStreamsRunning == linphone_call_get_state(call))
1030 sal_call_send_vfu_request(call->op);
1037 LinphoneCallParams * linphone_call_params_copy(const LinphoneCallParams *cp){
1038 LinphoneCallParams *ncp=ms_new0(LinphoneCallParams,1);
1039 memcpy(ncp,cp,sizeof(LinphoneCallParams));
1046 void linphone_call_params_destroy(LinphoneCallParams *p){
1055 #ifdef TEST_EXT_RENDERER
1056 static void rendercb(void *data, const MSPicture *local, const MSPicture *remote){
1057 ms_message("rendercb, local buffer=%p, remote buffer=%p",
1058 local ? local->planes[0] : NULL, remote? remote->planes[0] : NULL);
1062 #ifdef VIDEO_ENABLED
1063 static void video_stream_event_cb(void *user_pointer, const MSFilter *f, const unsigned int event_id, const void *args){
1064 LinphoneCall* call = (LinphoneCall*) user_pointer;
1065 ms_warning("In linphonecall.c: video_stream_event_cb");
1067 case MS_VIDEO_DECODER_DECODING_ERRORS:
1068 ms_warning("Case is MS_VIDEO_DECODER_DECODING_ERRORS");
1069 linphone_call_send_vfu_request(call);
1071 case MS_VIDEO_DECODER_FIRST_IMAGE_DECODED:
1072 ms_message("First video frame decoded successfully");
1073 if (call->nextVideoFrameDecoded._func != NULL)
1074 call->nextVideoFrameDecoded._func(call, call->nextVideoFrameDecoded._user_data);
1077 ms_warning("Unhandled event %i", event_id);
1083 void linphone_call_set_next_video_frame_decoded_callback(LinphoneCall *call, LinphoneCallCbFunc cb, void* user_data) {
1084 call->nextVideoFrameDecoded._func = cb;
1085 call->nextVideoFrameDecoded._user_data = user_data;
1086 #ifdef VIDEO_ENABLED
1087 ms_filter_call_method_noarg(call->videostream->ms.decoder, MS_VIDEO_DECODER_RESET_FIRST_IMAGE_NOTIFICATION);
1091 void linphone_call_init_audio_stream(LinphoneCall *call){
1092 LinphoneCore *lc=call->core;
1093 AudioStream *audiostream;
1096 if (call->audiostream != NULL) return;
1097 call->audiostream=audiostream=audio_stream_new(call->audio_port,call->audio_port+1,linphone_core_ipv6_enabled(lc));
1098 dscp=linphone_core_get_audio_dscp(lc);
1100 audio_stream_set_dscp(audiostream,dscp);
1101 if (linphone_core_echo_limiter_enabled(lc)){
1102 const char *type=lp_config_get_string(lc->config,"sound","el_type","mic");
1103 if (strcasecmp(type,"mic")==0)
1104 audio_stream_enable_echo_limiter(audiostream,ELControlMic);
1105 else if (strcasecmp(type,"full")==0)
1106 audio_stream_enable_echo_limiter(audiostream,ELControlFull);
1108 audio_stream_enable_gain_control(audiostream,TRUE);
1109 if (linphone_core_echo_cancellation_enabled(lc)){
1110 int len,delay,framesize;
1111 const char *statestr=lp_config_get_string(lc->config,"sound","ec_state",NULL);
1112 len=lp_config_get_int(lc->config,"sound","ec_tail_len",0);
1113 delay=lp_config_get_int(lc->config,"sound","ec_delay",0);
1114 framesize=lp_config_get_int(lc->config,"sound","ec_framesize",0);
1115 audio_stream_set_echo_canceller_params(audiostream,len,delay,framesize);
1116 if (statestr && audiostream->ec){
1117 ms_filter_call_method(audiostream->ec,MS_ECHO_CANCELLER_SET_STATE_STRING,(void*)statestr);
1120 audio_stream_enable_automatic_gain_control(audiostream,linphone_core_agc_enabled(lc));
1122 int enabled=lp_config_get_int(lc->config,"sound","noisegate",0);
1123 audio_stream_enable_noise_gate(audiostream,enabled);
1126 audio_stream_set_features(audiostream,linphone_core_get_audio_features(lc));
1129 RtpTransport *artp=lc->rtptf->audio_rtp_func(lc->rtptf->audio_rtp_func_data, call->audio_port);
1130 RtpTransport *artcp=lc->rtptf->audio_rtcp_func(lc->rtptf->audio_rtcp_func_data, call->audio_port+1);
1131 rtp_session_set_transports(audiostream->ms.session,artp,artcp);
1133 if ((linphone_core_get_firewall_policy(lc) == LinphonePolicyUseIce) && (call->ice_session != NULL)){
1134 rtp_session_set_pktinfo(audiostream->ms.session, TRUE);
1135 rtp_session_set_symmetric_rtp(audiostream->ms.session, FALSE);
1136 if (ice_session_check_list(call->ice_session, 0) == NULL) {
1137 ice_session_add_check_list(call->ice_session, ice_check_list_new());
1139 audiostream->ms.ice_check_list = ice_session_check_list(call->ice_session, 0);
1140 ice_check_list_set_rtp_session(audiostream->ms.ice_check_list, audiostream->ms.session);
1143 call->audiostream_app_evq = ortp_ev_queue_new();
1144 rtp_session_register_event_queue(audiostream->ms.session,call->audiostream_app_evq);
1147 void linphone_call_init_video_stream(LinphoneCall *call){
1148 #ifdef VIDEO_ENABLED
1149 LinphoneCore *lc=call->core;
1151 if (!call->params.has_video) {
1152 linphone_call_stop_video_stream(call);
1155 if (call->videostream != NULL) return;
1156 if ((lc->video_conf.display || lc->video_conf.capture) && call->params.has_video){
1157 int video_recv_buf_size=lp_config_get_int(lc->config,"video","recv_buf_size",0);
1158 int dscp=linphone_core_get_video_dscp(lc);
1160 call->videostream=video_stream_new(call->video_port,call->video_port+1,linphone_core_ipv6_enabled(lc));
1162 video_stream_set_dscp(call->videostream,dscp);
1163 video_stream_enable_display_filter_auto_rotate(call->videostream, lp_config_get_int(lc->config,"video","display_filter_auto_rotate",0));
1164 if (video_recv_buf_size>0) rtp_session_set_recv_buf_size(call->videostream->ms.session,video_recv_buf_size);
1166 if( lc->video_conf.displaytype != NULL)
1167 video_stream_set_display_filter_name(call->videostream,lc->video_conf.displaytype);
1168 video_stream_set_event_callback(call->videostream,video_stream_event_cb, call);
1170 RtpTransport *vrtp=lc->rtptf->video_rtp_func(lc->rtptf->video_rtp_func_data, call->video_port);
1171 RtpTransport *vrtcp=lc->rtptf->video_rtcp_func(lc->rtptf->video_rtcp_func_data, call->video_port+1);
1172 rtp_session_set_transports(call->videostream->ms.session,vrtp,vrtcp);
1174 if ((linphone_core_get_firewall_policy(lc) == LinphonePolicyUseIce) && (call->ice_session != NULL)){
1175 rtp_session_set_pktinfo(call->videostream->ms.session, TRUE);
1176 rtp_session_set_symmetric_rtp(call->videostream->ms.session, FALSE);
1177 if (ice_session_check_list(call->ice_session, 1) == NULL) {
1178 ice_session_add_check_list(call->ice_session, ice_check_list_new());
1180 call->videostream->ms.ice_check_list = ice_session_check_list(call->ice_session, 1);
1181 ice_check_list_set_rtp_session(call->videostream->ms.ice_check_list, call->videostream->ms.session);
1183 call->videostream_app_evq = ortp_ev_queue_new();
1184 rtp_session_register_event_queue(call->videostream->ms.session,call->videostream_app_evq);
1185 #ifdef TEST_EXT_RENDERER
1186 video_stream_set_render_callback(call->videostream,rendercb,NULL);
1190 call->videostream=NULL;
1194 void linphone_call_init_media_streams(LinphoneCall *call){
1195 linphone_call_init_audio_stream(call);
1196 linphone_call_init_video_stream(call);
1200 static int dtmf_tab[16]={'0','1','2','3','4','5','6','7','8','9','*','#','A','B','C','D'};
1202 static void linphone_core_dtmf_received(LinphoneCore *lc, int dtmf){
1203 if (dtmf<0 || dtmf>15){
1204 ms_warning("Bad dtmf value %i",dtmf);
1207 if (lc->vtable.dtmf_received != NULL)
1208 lc->vtable.dtmf_received(lc, linphone_core_get_current_call(lc), dtmf_tab[dtmf]);
1211 static void parametrize_equalizer(LinphoneCore *lc, AudioStream *st){
1213 MSFilter *f=st->equalizer;
1214 int enabled=lp_config_get_int(lc->config,"sound","eq_active",0);
1215 const char *gains=lp_config_get_string(lc->config,"sound","eq_gains",NULL);
1216 ms_filter_call_method(f,MS_EQUALIZER_SET_ACTIVE,&enabled);
1222 if (sscanf(gains,"%f:%f:%f %n",&g.frequency,&g.gain,&g.width,&bytes)==3){
1223 ms_message("Read equalizer gains: %f(~%f) --> %f",g.frequency,g.width,g.gain);
1224 ms_filter_call_method(f,MS_EQUALIZER_SET_GAIN,&g);
1233 void _post_configure_audio_stream(AudioStream *st, LinphoneCore *lc, bool_t muted){
1234 float mic_gain=lc->sound_conf.soft_mic_lev;
1237 float ng_thres=lp_config_get_float(lc->config,"sound","ng_thres",0.05);
1238 float ng_floorgain=lp_config_get_float(lc->config,"sound","ng_floorgain",0);
1239 int dc_removal=lp_config_get_int(lc->config,"sound","dc_removal",0);
1242 linphone_core_set_mic_gain_db (lc, mic_gain);
1244 audio_stream_set_mic_gain(st,0);
1246 recv_gain = lc->sound_conf.soft_play_lev;
1247 if (recv_gain != 0) {
1248 linphone_core_set_playback_gain_db (lc,recv_gain);
1252 ms_filter_call_method(st->volsend,MS_VOLUME_REMOVE_DC,&dc_removal);
1253 float speed=lp_config_get_float(lc->config,"sound","el_speed",-1);
1254 thres=lp_config_get_float(lc->config,"sound","el_thres",-1);
1255 float force=lp_config_get_float(lc->config,"sound","el_force",-1);
1256 int sustain=lp_config_get_int(lc->config,"sound","el_sustain",-1);
1257 float transmit_thres=lp_config_get_float(lc->config,"sound","el_transmit_thres",-1);
1260 if (speed==-1) speed=0.03;
1261 if (force==-1) force=25;
1262 ms_filter_call_method(f,MS_VOLUME_SET_EA_SPEED,&speed);
1263 ms_filter_call_method(f,MS_VOLUME_SET_EA_FORCE,&force);
1265 ms_filter_call_method(f,MS_VOLUME_SET_EA_THRESHOLD,&thres);
1267 ms_filter_call_method(f,MS_VOLUME_SET_EA_SUSTAIN,&sustain);
1268 if (transmit_thres!=-1)
1269 ms_filter_call_method(f,MS_VOLUME_SET_EA_TRANSMIT_THRESHOLD,&transmit_thres);
1271 ms_filter_call_method(st->volsend,MS_VOLUME_SET_NOISE_GATE_THRESHOLD,&ng_thres);
1272 ms_filter_call_method(st->volsend,MS_VOLUME_SET_NOISE_GATE_FLOORGAIN,&ng_floorgain);
1275 /* parameters for a limited noise-gate effect, using echo limiter threshold */
1276 float floorgain = 1/pow(10,(mic_gain)/10);
1277 int spk_agc=lp_config_get_int(lc->config,"sound","speaker_agc_enabled",0);
1278 ms_filter_call_method(st->volrecv, MS_VOLUME_ENABLE_AGC, &spk_agc);
1279 ms_filter_call_method(st->volrecv,MS_VOLUME_SET_NOISE_GATE_THRESHOLD,&ng_thres);
1280 ms_filter_call_method(st->volrecv,MS_VOLUME_SET_NOISE_GATE_FLOORGAIN,&floorgain);
1282 parametrize_equalizer(lc,st);
1285 static void post_configure_audio_streams(LinphoneCall*call){
1286 AudioStream *st=call->audiostream;
1287 LinphoneCore *lc=call->core;
1288 _post_configure_audio_stream(st,lc,call->audio_muted);
1289 if (lc->vtable.dtmf_received!=NULL){
1290 /* replace by our default action*/
1291 audio_stream_play_received_dtmfs(call->audiostream,FALSE);
1292 /*rtp_session_signal_connect(call->audiostream->session,"telephone-event",(RtpCallback)linphone_core_dtmf_received,(unsigned long)lc);*/
1296 static RtpProfile *make_profile(LinphoneCall *call, const SalMediaDescription *md, const SalStreamDescription *desc, int *used_pt){
1299 RtpProfile *prof=rtp_profile_new("Call profile");
1302 LinphoneCore *lc=call->core;
1304 const LinphoneCallParams *params=&call->params;
1307 for(elem=desc->payloads;elem!=NULL;elem=elem->next){
1308 PayloadType *pt=(PayloadType*)elem->data;
1311 if ((pt->flags & PAYLOAD_TYPE_FLAG_CAN_SEND) && first) {
1312 if (desc->type==SalAudio){
1313 linphone_core_update_allocated_audio_bandwidth_in_call(call,pt);
1314 if (params->up_ptime)
1315 up_ptime=params->up_ptime;
1316 else up_ptime=linphone_core_get_upload_ptime(lc);
1318 *used_pt=payload_type_get_number(pt);
1321 if (desc->bandwidth>0) remote_bw=desc->bandwidth;
1322 else if (md->bandwidth>0) {
1323 /*case where b=AS is given globally, not per stream*/
1324 remote_bw=md->bandwidth;
1325 if (desc->type==SalVideo){
1326 remote_bw=get_video_bandwidth(remote_bw,call->audio_bw);
1330 if (desc->type==SalAudio){
1331 int audio_bw=call->audio_bw;
1333 if (params->up_bw< audio_bw)
1334 audio_bw=params->up_bw;
1336 bw=get_min_bandwidth(audio_bw,remote_bw);
1337 }else bw=get_min_bandwidth(get_video_bandwidth(linphone_core_get_upload_bandwidth (lc),call->audio_bw),remote_bw);
1338 if (bw>0) pt->normal_bitrate=bw*1000;
1339 else if (desc->type==SalAudio){
1340 pt->normal_bitrate=-1;
1343 up_ptime=desc->ptime;
1347 snprintf(tmp,sizeof(tmp),"ptime=%i",up_ptime);
1348 payload_type_append_send_fmtp(pt,tmp);
1350 number=payload_type_get_number(pt);
1351 if (rtp_profile_get_payload(prof,number)!=NULL){
1352 ms_warning("A payload type with number %i already exists in profile !",number);
1354 rtp_profile_set_payload(prof,number,pt);
1360 static void setup_ring_player(LinphoneCore *lc, LinphoneCall *call){
1361 int pause_time=3000;
1362 audio_stream_play(call->audiostream,lc->sound_conf.ringback_tone);
1363 ms_filter_call_method(call->audiostream->soundread,MS_FILE_PLAYER_LOOP,&pause_time);
1366 static bool_t linphone_call_sound_resources_available(LinphoneCall *call){
1367 LinphoneCore *lc=call->core;
1368 LinphoneCall *current=linphone_core_get_current_call(lc);
1369 return !linphone_core_is_in_conference(lc) &&
1370 (current==NULL || current==call);
1372 static int find_crypto_index_from_tag(const SalSrtpCryptoAlgo crypto[],unsigned char tag) {
1374 for(i=0; i<SAL_CRYPTO_ALGO_MAX; i++) {
1375 if (crypto[i].tag == tag) {
1381 static void linphone_call_start_audio_stream(LinphoneCall *call, const char *cname, bool_t muted, bool_t send_ringbacktone, bool_t use_arc){
1382 LinphoneCore *lc=call->core;
1384 char rtcp_tool[128]={0};
1385 snprintf(rtcp_tool,sizeof(rtcp_tool)-1,"%s-%s",linphone_core_get_user_agent_name(),linphone_core_get_user_agent_version());
1386 /* look for savp stream first */
1387 const SalStreamDescription *stream=sal_media_description_find_stream(call->resultdesc,
1388 SalProtoRtpSavp,SalAudio);
1389 /* no savp audio stream, use avp */
1391 stream=sal_media_description_find_stream(call->resultdesc,
1392 SalProtoRtpAvp,SalAudio);
1394 if (stream && stream->dir!=SalStreamInactive && stream->rtp_port!=0){
1395 MSSndCard *playcard=lc->sound_conf.lsd_card ?
1396 lc->sound_conf.lsd_card : lc->sound_conf.play_sndcard;
1397 MSSndCard *captcard=lc->sound_conf.capt_sndcard;
1398 const char *playfile=lc->play_file;
1399 const char *recfile=lc->rec_file;
1400 call->audio_profile=make_profile(call,call->resultdesc,stream,&used_pt);
1404 call->current_params.audio_codec = rtp_profile_get_payload(call->audio_profile, used_pt);
1405 if (playcard==NULL) {
1406 ms_warning("No card defined for playback !");
1408 if (captcard==NULL) {
1409 ms_warning("No card defined for capture !");
1411 /*Replace soundcard filters by inactive file players or recorders
1412 when placed in recvonly or sendonly mode*/
1413 if (stream->rtp_port==0 || stream->dir==SalStreamRecvOnly){
1416 }else if (stream->dir==SalStreamSendOnly){
1420 /*And we will eventually play "playfile" if set by the user*/
1423 if (send_ringbacktone){
1425 playfile=NULL;/* it is setup later*/
1427 /*if playfile are supplied don't use soundcards*/
1428 if (lc->use_files) {
1432 if (call->params.in_conference){
1433 /* first create the graph without soundcard resources*/
1434 captcard=playcard=NULL;
1436 if (!linphone_call_sound_resources_available(call)){
1437 ms_message("Sound resources are used by another call, not using soundcard.");
1438 captcard=playcard=NULL;
1440 use_ec=captcard==NULL ? FALSE : linphone_core_echo_cancellation_enabled(lc);
1441 if (playcard && stream->max_rate>0) ms_snd_card_set_preferred_sample_rate(playcard, stream->max_rate);
1442 if (captcard && stream->max_rate>0) ms_snd_card_set_preferred_sample_rate(captcard, stream->max_rate);
1443 audio_stream_enable_adaptive_bitrate_control(call->audiostream,use_arc);
1444 audio_stream_enable_adaptive_jittcomp(call->audiostream, linphone_core_audio_adaptive_jittcomp_enabled(lc));
1445 audio_stream_start_full(
1447 call->audio_profile,
1448 stream->rtp_addr[0]!='\0' ? stream->rtp_addr : call->resultdesc->addr,
1450 stream->rtcp_addr[0]!='\0' ? stream->rtcp_addr : call->resultdesc->addr,
1451 linphone_core_rtcp_enabled(lc) ? (stream->rtcp_port) : 0,
1453 linphone_core_get_audio_jittcomp(lc),
1460 post_configure_audio_streams(call);
1461 if (muted && !send_ringbacktone){
1462 audio_stream_set_mic_gain(call->audiostream,0);
1464 if (stream->dir==SalStreamSendOnly && playfile!=NULL){
1466 ms_filter_call_method(call->audiostream->soundread,MS_FILE_PLAYER_LOOP,&pause_time);
1468 if (send_ringbacktone){
1469 setup_ring_player(lc,call);
1471 audio_stream_set_rtcp_information(call->audiostream, cname, rtcp_tool);
1473 /* valid local tags are > 0 */
1474 if (stream->proto == SalProtoRtpSavp) {
1475 const SalStreamDescription *local_st_desc=sal_media_description_find_stream(call->localdesc,
1476 SalProtoRtpSavp,SalAudio);
1477 int crypto_idx = find_crypto_index_from_tag(local_st_desc->crypto, stream->crypto_local_tag);
1479 if (crypto_idx >= 0) {
1480 audio_stream_enable_srtp(
1482 stream->crypto[0].algo,
1483 local_st_desc->crypto[crypto_idx].master_key,
1484 stream->crypto[0].master_key);
1485 call->audiostream_encrypted=TRUE;
1487 ms_warning("Failed to find local crypto algo with tag: %d", stream->crypto_local_tag);
1488 call->audiostream_encrypted=FALSE;
1490 }else call->audiostream_encrypted=FALSE;
1491 if (call->params.in_conference){
1492 /*transform the graph to connect it to the conference filter */
1493 bool_t mute=stream->dir==SalStreamRecvOnly;
1494 linphone_call_add_to_conf(call, mute);
1496 call->current_params.in_conference=call->params.in_conference;
1497 call->current_params.low_bandwidth=call->params.low_bandwidth;
1498 }else ms_warning("No audio stream accepted ?");
1502 static void linphone_call_start_video_stream(LinphoneCall *call, const char *cname,bool_t all_inputs_muted){
1503 #ifdef VIDEO_ENABLED
1504 LinphoneCore *lc=call->core;
1506 /* look for savp stream first */
1507 const SalStreamDescription *vstream=sal_media_description_find_stream(call->resultdesc,
1508 SalProtoRtpSavp,SalVideo);
1509 char rtcp_tool[128]={0};
1510 snprintf(rtcp_tool,sizeof(rtcp_tool)-1,"%s-%s",linphone_core_get_user_agent_name(),linphone_core_get_user_agent_version());
1512 /* no savp audio stream, use avp */
1514 vstream=sal_media_description_find_stream(call->resultdesc,
1515 SalProtoRtpAvp,SalVideo);
1517 /* shutdown preview */
1518 if (lc->previewstream!=NULL) {
1519 video_preview_stop(lc->previewstream);
1520 lc->previewstream=NULL;
1523 if (vstream!=NULL && vstream->dir!=SalStreamInactive && vstream->rtp_port!=0) {
1524 const char *rtp_addr=vstream->rtp_addr[0]!='\0' ? vstream->rtp_addr : call->resultdesc->addr;
1525 const char *rtcp_addr=vstream->rtcp_addr[0]!='\0' ? vstream->rtcp_addr : call->resultdesc->addr;
1526 call->video_profile=make_profile(call,call->resultdesc,vstream,&used_pt);
1528 call->current_params.video_codec = rtp_profile_get_payload(call->video_profile, used_pt);
1529 VideoStreamDir dir=VideoStreamSendRecv;
1530 MSWebCam *cam=lc->video_conf.device;
1531 bool_t is_inactive=FALSE;
1533 call->current_params.has_video=TRUE;
1535 video_stream_enable_adaptive_bitrate_control(call->videostream,
1536 linphone_core_adaptive_rate_control_enabled(lc));
1537 video_stream_enable_adaptive_jittcomp(call->videostream, linphone_core_video_adaptive_jittcomp_enabled(lc));
1538 video_stream_set_sent_video_size(call->videostream,linphone_core_get_preferred_video_size(lc));
1539 video_stream_enable_self_view(call->videostream,lc->video_conf.selfview);
1540 if (lc->video_window_id!=0)
1541 video_stream_set_native_window_id(call->videostream,lc->video_window_id);
1542 if (lc->preview_window_id!=0)
1543 video_stream_set_native_preview_window_id (call->videostream,lc->preview_window_id);
1544 video_stream_use_preview_video_window (call->videostream,lc->use_preview_window);
1546 if (vstream->dir==SalStreamSendOnly && lc->video_conf.capture ){
1547 cam=get_nowebcam_device();
1548 dir=VideoStreamSendOnly;
1549 }else if (vstream->dir==SalStreamRecvOnly && lc->video_conf.display ){
1550 dir=VideoStreamRecvOnly;
1551 }else if (vstream->dir==SalStreamSendRecv){
1552 if (lc->video_conf.display && lc->video_conf.capture)
1553 dir=VideoStreamSendRecv;
1554 else if (lc->video_conf.display)
1555 dir=VideoStreamRecvOnly;
1557 dir=VideoStreamSendOnly;
1559 ms_warning("video stream is inactive.");
1560 /*either inactive or incompatible with local capabilities*/
1563 if (call->camera_active==FALSE || all_inputs_muted){
1564 cam=get_nowebcam_device();
1567 call->log->video_enabled = TRUE;
1568 video_stream_set_direction (call->videostream, dir);
1569 ms_message("%s lc rotation:%d\n", __FUNCTION__, lc->device_rotation);
1570 video_stream_set_device_rotation(call->videostream, lc->device_rotation);
1571 video_stream_start(call->videostream,
1572 call->video_profile, rtp_addr, vstream->rtp_port,
1573 rtcp_addr, linphone_core_rtcp_enabled(lc) ? (vstream->rtcp_port) : 0,
1574 used_pt, linphone_core_get_video_jittcomp(lc), cam);
1575 video_stream_set_rtcp_information(call->videostream, cname,rtcp_tool);
1578 if (vstream->proto == SalProtoRtpSavp) {
1579 const SalStreamDescription *local_st_desc=sal_media_description_find_stream(call->localdesc,
1580 SalProtoRtpSavp,SalVideo);
1582 video_stream_enable_strp(
1584 vstream->crypto[0].algo,
1585 local_st_desc->crypto[0].master_key,
1586 vstream->crypto[0].master_key
1588 call->videostream_encrypted=TRUE;
1590 call->videostream_encrypted=FALSE;
1592 }else ms_warning("No video stream accepted.");
1594 ms_warning("No valid video stream defined.");
1599 void linphone_call_start_media_streams(LinphoneCall *call, bool_t all_inputs_muted, bool_t send_ringbacktone){
1600 LinphoneCore *lc=call->core;
1602 call->current_params.audio_codec = NULL;
1603 call->current_params.video_codec = NULL;
1605 LinphoneAddress *me=linphone_core_get_primary_contact_parsed(lc);
1607 bool_t use_arc=linphone_core_adaptive_rate_control_enabled(lc);
1608 #ifdef VIDEO_ENABLED
1609 const SalStreamDescription *vstream=sal_media_description_find_stream(call->resultdesc,
1610 SalProtoRtpAvp,SalVideo);
1613 if ((call->audiostream == NULL) && (call->videostream == NULL)) {
1614 ms_fatal("start_media_stream() called without prior init !");
1617 cname=linphone_address_as_string_uri_only(me);
1619 #if defined(VIDEO_ENABLED)
1620 if (vstream!=NULL && vstream->dir!=SalStreamInactive && vstream->payloads!=NULL){
1621 /*when video is used, do not make adaptive rate control on audio, it is stupid.*/
1625 if (call->audiostream!=NULL) {
1626 linphone_call_start_audio_stream(call,cname,all_inputs_muted,send_ringbacktone,use_arc);
1628 call->current_params.has_video=FALSE;
1629 if (call->videostream!=NULL) {
1630 linphone_call_start_video_stream(call,cname,all_inputs_muted);
1633 call->all_muted=all_inputs_muted;
1634 call->playing_ringbacktone=send_ringbacktone;
1635 call->up_bw=linphone_core_get_upload_bandwidth(lc);
1637 if (call->params.media_encryption==LinphoneMediaEncryptionZRTP) {
1638 OrtpZrtpParams params;
1639 /*will be set later when zrtp is activated*/
1640 call->current_params.media_encryption=LinphoneMediaEncryptionNone;
1642 params.zid_file=lc->zrtp_secrets_cache;
1643 audio_stream_enable_zrtp(call->audiostream,¶ms);
1644 }else if (call->params.media_encryption==LinphoneMediaEncryptionSRTP){
1645 call->current_params.media_encryption=linphone_call_are_all_streams_encrypted(call) ?
1646 LinphoneMediaEncryptionSRTP : LinphoneMediaEncryptionNone;
1649 /*also reflect the change if the "wished" params, in order to avoid to propose SAVP or video again
1650 * further in the call, for example during pause,resume, conferencing reINVITEs*/
1651 linphone_call_fix_call_parameters(call);
1652 if ((call->ice_session != NULL) && (ice_session_state(call->ice_session) != IS_Completed)) {
1653 ice_session_start_connectivity_checks(call->ice_session);
1659 linphone_address_destroy(me);
1662 void linphone_call_start_media_streams_for_ice_gathering(LinphoneCall *call){
1663 audio_stream_prepare_sound(call->audiostream, NULL, NULL);
1664 #ifdef VIDEO_ENABLED
1665 if (call->videostream) {
1666 video_stream_prepare_video(call->videostream);
1671 void linphone_call_stop_media_streams_for_ice_gathering(LinphoneCall *call){
1672 audio_stream_unprepare_sound(call->audiostream);
1673 #ifdef VIDEO_ENABLED
1674 if (call->videostream) {
1675 video_stream_unprepare_video(call->videostream);
1680 void linphone_call_update_crypto_parameters(LinphoneCall *call, SalMediaDescription *old_md, SalMediaDescription *new_md) {
1681 SalStreamDescription *old_stream;
1682 SalStreamDescription *new_stream;
1685 old_stream = sal_media_description_find_stream(old_md, SalProtoRtpSavp, SalAudio);
1686 new_stream = sal_media_description_find_stream(new_md, SalProtoRtpSavp, SalAudio);
1687 if (old_stream && new_stream) {
1688 const SalStreamDescription *local_st_desc = sal_media_description_find_stream(call->localdesc, SalProtoRtpSavp, SalAudio);
1689 if (local_st_desc) {
1690 int crypto_idx = find_crypto_index_from_tag(local_st_desc->crypto, new_stream->crypto_local_tag);
1691 if (crypto_idx >= 0) {
1692 audio_stream_enable_srtp(call->audiostream, new_stream->crypto[0].algo, local_st_desc->crypto[crypto_idx].master_key, new_stream->crypto[0].master_key);
1693 call->audiostream_encrypted = TRUE;
1695 ms_warning("Failed to find local crypto algo with tag: %d", new_stream->crypto_local_tag);
1696 call->audiostream_encrypted = FALSE;
1698 for (i = 0; i < SAL_CRYPTO_ALGO_MAX; i++) {
1699 old_stream->crypto[i].tag = new_stream->crypto[i].tag;
1700 old_stream->crypto[i].algo = new_stream->crypto[i].algo;
1701 strncpy(old_stream->crypto[i].master_key, new_stream->crypto[i].master_key, sizeof(old_stream->crypto[i].master_key) - 1);
1706 #ifdef VIDEO_ENABLED
1707 old_stream = sal_media_description_find_stream(old_md, SalProtoRtpSavp, SalVideo);
1708 new_stream = sal_media_description_find_stream(new_md, SalProtoRtpSavp, SalVideo);
1709 if (old_stream && new_stream) {
1710 const SalStreamDescription *local_st_desc = sal_media_description_find_stream(call->localdesc, SalProtoRtpSavp, SalVideo);
1711 if (local_st_desc) {
1712 int crypto_idx = find_crypto_index_from_tag(local_st_desc->crypto, new_stream->crypto_local_tag);
1713 if (crypto_idx >= 0) {
1714 video_stream_enable_strp(call->videostream, new_stream->crypto[0].algo, local_st_desc->crypto[crypto_idx].master_key, new_stream->crypto[0].master_key);
1715 call->videostream_encrypted = TRUE;
1717 ms_warning("Failed to find local crypto algo with tag: %d", new_stream->crypto_local_tag);
1718 call->videostream_encrypted = FALSE;
1720 for (i = 0; i < SAL_CRYPTO_ALGO_MAX; i++) {
1721 old_stream->crypto[i].tag = new_stream->crypto[i].tag;
1722 old_stream->crypto[i].algo = new_stream->crypto[i].algo;
1723 strncpy(old_stream->crypto[i].master_key, new_stream->crypto[i].master_key, sizeof(old_stream->crypto[i].master_key) - 1);
1730 void linphone_call_update_remote_session_id_and_ver(LinphoneCall *call) {
1731 SalMediaDescription *remote_desc = sal_call_get_remote_media_description(call->op);
1733 call->remote_session_id = remote_desc->session_id;
1734 call->remote_session_ver = remote_desc->session_ver;
1738 void linphone_call_delete_ice_session(LinphoneCall *call){
1739 if (call->ice_session != NULL) {
1740 ice_session_destroy(call->ice_session);
1741 call->ice_session = NULL;
1742 if (call->audiostream != NULL) call->audiostream->ms.ice_check_list = NULL;
1743 if (call->videostream != NULL) call->videostream->ms.ice_check_list = NULL;
1744 call->stats[LINPHONE_CALL_STATS_AUDIO].ice_state = LinphoneIceStateNotActivated;
1745 call->stats[LINPHONE_CALL_STATS_VIDEO].ice_state = LinphoneIceStateNotActivated;
1749 static void linphone_call_log_fill_stats(LinphoneCallLog *log, AudioStream *st){
1750 audio_stream_get_local_rtp_stats (st,&log->local_stats);
1751 log->quality=audio_stream_get_average_quality_rating(st);
1754 void linphone_call_stop_audio_stream(LinphoneCall *call) {
1755 if (call->audiostream!=NULL) {
1756 rtp_session_unregister_event_queue(call->audiostream->ms.session,call->audiostream_app_evq);
1757 ortp_ev_queue_flush(call->audiostream_app_evq);
1758 ortp_ev_queue_destroy(call->audiostream_app_evq);
1759 call->audiostream_app_evq=NULL;
1761 if (call->audiostream->ec){
1762 const char *state_str=NULL;
1763 ms_filter_call_method(call->audiostream->ec,MS_ECHO_CANCELLER_GET_STATE_STRING,&state_str);
1765 ms_message("Writing echo canceler state, %i bytes",(int)strlen(state_str));
1766 lp_config_set_string(call->core->config,"sound","ec_state",state_str);
1769 linphone_call_log_fill_stats (call->log,call->audiostream);
1770 if (call->endpoint){
1771 linphone_call_remove_from_conf(call);
1773 audio_stream_stop(call->audiostream);
1774 call->audiostream=NULL;
1778 void linphone_call_stop_video_stream(LinphoneCall *call) {
1779 #ifdef VIDEO_ENABLED
1780 if (call->videostream!=NULL){
1781 rtp_session_unregister_event_queue(call->videostream->ms.session,call->videostream_app_evq);
1782 ortp_ev_queue_flush(call->videostream_app_evq);
1783 ortp_ev_queue_destroy(call->videostream_app_evq);
1784 call->videostream_app_evq=NULL;
1785 video_stream_stop(call->videostream);
1786 call->videostream=NULL;
1791 void linphone_call_stop_media_streams(LinphoneCall *call){
1792 linphone_call_stop_audio_stream(call);
1793 linphone_call_stop_video_stream(call);
1794 ms_event_queue_skip(call->core->msevq);
1796 if (call->audio_profile){
1797 rtp_profile_clear_all(call->audio_profile);
1798 rtp_profile_destroy(call->audio_profile);
1799 call->audio_profile=NULL;
1801 if (call->video_profile){
1802 rtp_profile_clear_all(call->video_profile);
1803 rtp_profile_destroy(call->video_profile);
1804 call->video_profile=NULL;
1810 void linphone_call_enable_echo_cancellation(LinphoneCall *call, bool_t enable) {
1811 if (call!=NULL && call->audiostream!=NULL && call->audiostream->ec){
1812 bool_t bypass_mode = !enable;
1813 ms_filter_call_method(call->audiostream->ec,MS_ECHO_CANCELLER_SET_BYPASS_MODE,&bypass_mode);
1816 bool_t linphone_call_echo_cancellation_enabled(LinphoneCall *call) {
1817 if (call!=NULL && call->audiostream!=NULL && call->audiostream->ec){
1819 ms_filter_call_method(call->audiostream->ec,MS_ECHO_CANCELLER_GET_BYPASS_MODE,&val);
1822 return linphone_core_echo_cancellation_enabled(call->core);
1826 void linphone_call_enable_echo_limiter(LinphoneCall *call, bool_t val){
1827 if (call!=NULL && call->audiostream!=NULL ) {
1829 const char *type=lp_config_get_string(call->core->config,"sound","el_type","mic");
1830 if (strcasecmp(type,"mic")==0)
1831 audio_stream_enable_echo_limiter(call->audiostream,ELControlMic);
1832 else if (strcasecmp(type,"full")==0)
1833 audio_stream_enable_echo_limiter(call->audiostream,ELControlFull);
1835 audio_stream_enable_echo_limiter(call->audiostream,ELInactive);
1840 bool_t linphone_call_echo_limiter_enabled(const LinphoneCall *call){
1841 if (call!=NULL && call->audiostream!=NULL ){
1842 return call->audiostream->el_type !=ELInactive ;
1844 return linphone_core_echo_limiter_enabled(call->core);
1849 * @addtogroup call_misc
1854 * Returns the measured sound volume played locally (received from remote).
1855 * It is expressed in dbm0.
1857 float linphone_call_get_play_volume(LinphoneCall *call){
1858 AudioStream *st=call->audiostream;
1859 if (st && st->volrecv){
1861 ms_filter_call_method(st->volrecv,MS_VOLUME_GET,&vol);
1865 return LINPHONE_VOLUME_DB_LOWEST;
1869 * Returns the measured sound volume recorded locally (sent to remote).
1870 * It is expressed in dbm0.
1872 float linphone_call_get_record_volume(LinphoneCall *call){
1873 AudioStream *st=call->audiostream;
1874 if (st && st->volsend && !call->audio_muted && call->state==LinphoneCallStreamsRunning){
1876 ms_filter_call_method(st->volsend,MS_VOLUME_GET,&vol);
1880 return LINPHONE_VOLUME_DB_LOWEST;
1884 * Obtain real-time quality rating of the call
1886 * Based on local RTP statistics and RTCP feedback, a quality rating is computed and updated
1887 * during all the duration of the call. This function returns its value at the time of the function call.
1888 * It is expected that the rating is updated at least every 5 seconds or so.
1889 * The rating is a floating point number comprised between 0 and 5.
1891 * 4-5 = good quality <br>
1892 * 3-4 = average quality <br>
1893 * 2-3 = poor quality <br>
1894 * 1-2 = very poor quality <br>
1895 * 0-1 = can't be worse, mostly unusable <br>
1897 * @returns The function returns -1 if no quality measurement is available, for example if no
1898 * active audio stream exist. Otherwise it returns the quality rating.
1900 float linphone_call_get_current_quality(LinphoneCall *call){
1901 if (call->audiostream){
1902 return audio_stream_get_quality_rating(call->audiostream);
1908 * Returns call quality averaged over all the duration of the call.
1910 * See linphone_call_get_current_quality() for more details about quality measurement.
1912 float linphone_call_get_average_quality(LinphoneCall *call){
1913 if (call->audiostream){
1914 return audio_stream_get_average_quality_rating(call->audiostream);
1920 * Access last known statistics for audio stream, for a given call.
1922 const LinphoneCallStats *linphone_call_get_audio_stats(const LinphoneCall *call) {
1923 return &call->stats[LINPHONE_CALL_STATS_AUDIO];
1927 * Access last known statistics for video stream, for a given call.
1929 const LinphoneCallStats *linphone_call_get_video_stats(const LinphoneCall *call) {
1930 return &call->stats[LINPHONE_CALL_STATS_VIDEO];
1938 static void report_bandwidth(LinphoneCall *call, RtpSession *as, RtpSession *vs){
1939 call->stats[LINPHONE_CALL_STATS_AUDIO].download_bandwidth=(as!=NULL) ? (rtp_session_compute_recv_bandwidth(as)*1e-3) : 0;
1940 call->stats[LINPHONE_CALL_STATS_AUDIO].upload_bandwidth=(as!=NULL) ? (rtp_session_compute_send_bandwidth(as)*1e-3) : 0;
1941 call->stats[LINPHONE_CALL_STATS_VIDEO].download_bandwidth=(vs!=NULL) ? (rtp_session_compute_recv_bandwidth(vs)*1e-3) : 0;
1942 call->stats[LINPHONE_CALL_STATS_VIDEO].upload_bandwidth=(vs!=NULL) ? (rtp_session_compute_send_bandwidth(vs)*1e-3) : 0;
1943 ms_message("bandwidth usage: audio=[d=%.1f,u=%.1f] video=[d=%.1f,u=%.1f] kbit/sec",
1944 call->stats[LINPHONE_CALL_STATS_AUDIO].download_bandwidth,
1945 call->stats[LINPHONE_CALL_STATS_AUDIO].upload_bandwidth ,
1946 call->stats[LINPHONE_CALL_STATS_VIDEO].download_bandwidth,
1947 call->stats[LINPHONE_CALL_STATS_VIDEO].upload_bandwidth
1951 static void linphone_core_disconnected(LinphoneCore *lc, LinphoneCall *call){
1955 from = linphone_call_get_remote_address_as_string(call);
1958 snprintf(temp,sizeof(temp),"Remote end %s seems to have disconnected, the call is going to be closed.",from);
1963 snprintf(temp,sizeof(temp),"Remote end seems to have disconnected, the call is going to be closed.");
1965 if (lc->vtable.display_warning!=NULL)
1966 lc->vtable.display_warning(lc,temp);
1967 linphone_core_terminate_call(lc,call);
1970 static void handle_ice_events(LinphoneCall *call, OrtpEvent *ev){
1971 OrtpEventType evt=ortp_event_get_type(ev);
1972 OrtpEventData *evd=ortp_event_get_data(ev);
1975 if (evt == ORTP_EVENT_ICE_SESSION_PROCESSING_FINISHED) {
1976 switch (ice_session_state(call->ice_session)) {
1978 ice_session_select_candidates(call->ice_session);
1979 if (ice_session_role(call->ice_session) == IR_Controlling) {
1980 linphone_core_update_call(call->core, call, &call->current_params);
1984 if (ice_session_has_completed_check_list(call->ice_session) == TRUE) {
1985 ice_session_select_candidates(call->ice_session);
1986 if (ice_session_role(call->ice_session) == IR_Controlling) {
1987 /* At least one ICE session has succeeded, so perform a call update. */
1988 linphone_core_update_call(call->core, call, &call->current_params);
1995 linphone_core_update_ice_state_in_call_stats(call);
1996 } else if (evt == ORTP_EVENT_ICE_GATHERING_FINISHED) {
1998 if (evd->info.ice_processing_successful==TRUE) {
1999 ice_session_compute_candidates_foundations(call->ice_session);
2000 ice_session_eliminate_redundant_candidates(call->ice_session);
2001 ice_session_choose_default_candidates(call->ice_session);
2002 ping_time = ice_session_average_gathering_round_trip_time(call->ice_session);
2003 if (ping_time >=0) {
2004 call->ping_time=ping_time;
2007 ms_warning("No STUN answer from [%s], disabling ICE",linphone_core_get_stun_server(call->core));
2008 linphone_call_delete_ice_session(call);
2010 switch (call->state) {
2011 case LinphoneCallUpdating:
2012 linphone_core_start_update_call(call->core, call);
2014 case LinphoneCallUpdatedByRemote:
2015 linphone_core_start_accept_call_update(call->core, call);
2017 case LinphoneCallOutgoingInit:
2018 linphone_call_stop_media_streams_for_ice_gathering(call);
2019 linphone_core_proceed_with_invite_if_ready(call->core, call, NULL);
2021 case LinphoneCallIdle:
2022 linphone_call_stop_media_streams_for_ice_gathering(call);
2023 linphone_core_notify_incoming_call(call->core, call);
2028 } else if (evt == ORTP_EVENT_ICE_LOSING_PAIRS_COMPLETED) {
2029 linphone_core_start_accept_call_update(call->core, call);
2030 linphone_core_update_ice_state_in_call_stats(call);
2031 } else if (evt == ORTP_EVENT_ICE_RESTART_NEEDED) {
2032 ice_session_restart(call->ice_session);
2033 ice_session_set_role(call->ice_session, IR_Controlling);
2034 linphone_core_update_call(call->core, call, &call->current_params);
2038 void linphone_call_background_tasks(LinphoneCall *call, bool_t one_second_elapsed){
2039 LinphoneCore* lc = call->core;
2040 int disconnect_timeout = linphone_core_get_nortp_timeout(call->core);
2041 bool_t disconnected=FALSE;
2043 if (call->state==LinphoneCallStreamsRunning && one_second_elapsed){
2044 RtpSession *as=NULL,*vs=NULL;
2045 float audio_load=0, video_load=0;
2046 if (call->audiostream!=NULL){
2047 as=call->audiostream->ms.session;
2048 if (call->audiostream->ms.ticker)
2049 audio_load=ms_ticker_get_average_load(call->audiostream->ms.ticker);
2051 if (call->videostream!=NULL){
2052 if (call->videostream->ms.ticker)
2053 video_load=ms_ticker_get_average_load(call->videostream->ms.ticker);
2054 vs=call->videostream->ms.session;
2056 report_bandwidth(call,as,vs);
2057 ms_message("Thread processing load: audio=%f\tvideo=%f",audio_load,video_load);
2059 #ifdef VIDEO_ENABLED
2060 if (call->videostream!=NULL) {
2063 /* Ensure there is no dangling ICE check list. */
2064 if (call->ice_session == NULL) call->videostream->ms.ice_check_list = NULL;
2066 // Beware that the application queue should not depend on treatments fron the
2067 // mediastreamer queue.
2068 video_stream_iterate(call->videostream);
2070 while (call->videostream_app_evq && (NULL != (ev=ortp_ev_queue_get(call->videostream_app_evq)))){
2071 OrtpEventType evt=ortp_event_get_type(ev);
2072 OrtpEventData *evd=ortp_event_get_data(ev);
2073 if (evt == ORTP_EVENT_ZRTP_ENCRYPTION_CHANGED){
2074 linphone_call_videostream_encryption_changed(call, evd->info.zrtp_stream_encrypted);
2075 } else if (evt == ORTP_EVENT_RTCP_PACKET_RECEIVED) {
2076 call->stats[LINPHONE_CALL_STATS_VIDEO].round_trip_delay = rtp_session_get_round_trip_propagation(call->videostream->ms.session);
2077 if(call->stats[LINPHONE_CALL_STATS_VIDEO].received_rtcp != NULL)
2078 freemsg(call->stats[LINPHONE_CALL_STATS_VIDEO].received_rtcp);
2079 call->stats[LINPHONE_CALL_STATS_VIDEO].received_rtcp = evd->packet;
2081 if (lc->vtable.call_stats_updated)
2082 lc->vtable.call_stats_updated(lc, call, &call->stats[LINPHONE_CALL_STATS_VIDEO]);
2083 } else if (evt == ORTP_EVENT_RTCP_PACKET_EMITTED) {
2084 memcpy(&call->stats[LINPHONE_CALL_STATS_VIDEO].jitter_stats, rtp_session_get_jitter_stats(call->videostream->ms.session), sizeof(jitter_stats_t));
2085 if(call->stats[LINPHONE_CALL_STATS_VIDEO].sent_rtcp != NULL)
2086 freemsg(call->stats[LINPHONE_CALL_STATS_VIDEO].sent_rtcp);
2087 call->stats[LINPHONE_CALL_STATS_VIDEO].sent_rtcp = evd->packet;
2089 if (lc->vtable.call_stats_updated)
2090 lc->vtable.call_stats_updated(lc, call, &call->stats[LINPHONE_CALL_STATS_VIDEO]);
2091 } else if ((evt == ORTP_EVENT_ICE_SESSION_PROCESSING_FINISHED) || (evt == ORTP_EVENT_ICE_GATHERING_FINISHED)
2092 || (evt == ORTP_EVENT_ICE_LOSING_PAIRS_COMPLETED) || (evt == ORTP_EVENT_ICE_RESTART_NEEDED)) {
2093 handle_ice_events(call, ev);
2095 ortp_event_destroy(ev);
2099 if (call->audiostream!=NULL) {
2102 /* Ensure there is no dangling ICE check list. */
2103 if (call->ice_session == NULL) call->audiostream->ms.ice_check_list = NULL;
2105 // Beware that the application queue should not depend on treatments fron the
2106 // mediastreamer queue.
2107 audio_stream_iterate(call->audiostream);
2109 while (call->audiostream_app_evq && (NULL != (ev=ortp_ev_queue_get(call->audiostream_app_evq)))){
2110 OrtpEventType evt=ortp_event_get_type(ev);
2111 OrtpEventData *evd=ortp_event_get_data(ev);
2112 if (evt == ORTP_EVENT_ZRTP_ENCRYPTION_CHANGED){
2113 linphone_call_audiostream_encryption_changed(call, evd->info.zrtp_stream_encrypted);
2114 } else if (evt == ORTP_EVENT_ZRTP_SAS_READY) {
2115 linphone_call_audiostream_auth_token_ready(call, evd->info.zrtp_sas.sas, evd->info.zrtp_sas.verified);
2116 } else if (evt == ORTP_EVENT_RTCP_PACKET_RECEIVED) {
2117 call->stats[LINPHONE_CALL_STATS_AUDIO].round_trip_delay = rtp_session_get_round_trip_propagation(call->audiostream->ms.session);
2118 if(call->stats[LINPHONE_CALL_STATS_AUDIO].received_rtcp != NULL)
2119 freemsg(call->stats[LINPHONE_CALL_STATS_AUDIO].received_rtcp);
2120 call->stats[LINPHONE_CALL_STATS_AUDIO].received_rtcp = evd->packet;
2122 if (lc->vtable.call_stats_updated)
2123 lc->vtable.call_stats_updated(lc, call, &call->stats[LINPHONE_CALL_STATS_AUDIO]);
2124 } else if (evt == ORTP_EVENT_RTCP_PACKET_EMITTED) {
2125 memcpy(&call->stats[LINPHONE_CALL_STATS_AUDIO].jitter_stats, rtp_session_get_jitter_stats(call->audiostream->ms.session), sizeof(jitter_stats_t));
2126 if(call->stats[LINPHONE_CALL_STATS_AUDIO].sent_rtcp != NULL)
2127 freemsg(call->stats[LINPHONE_CALL_STATS_AUDIO].sent_rtcp);
2128 call->stats[LINPHONE_CALL_STATS_AUDIO].sent_rtcp = evd->packet;
2130 if (lc->vtable.call_stats_updated)
2131 lc->vtable.call_stats_updated(lc, call, &call->stats[LINPHONE_CALL_STATS_AUDIO]);
2132 } else if ((evt == ORTP_EVENT_ICE_SESSION_PROCESSING_FINISHED) || (evt == ORTP_EVENT_ICE_GATHERING_FINISHED)
2133 || (evt == ORTP_EVENT_ICE_LOSING_PAIRS_COMPLETED) || (evt == ORTP_EVENT_ICE_RESTART_NEEDED)) {
2134 handle_ice_events(call, ev);
2135 } else if (evt==ORTP_EVENT_TELEPHONE_EVENT){
2136 linphone_core_dtmf_received(lc,evd->info.telephone_event);
2138 ortp_event_destroy(ev);
2141 if (call->state==LinphoneCallStreamsRunning && one_second_elapsed && call->audiostream!=NULL && disconnect_timeout>0 )
2142 disconnected=!audio_stream_alive(call->audiostream,disconnect_timeout);
2144 linphone_core_disconnected(call->core,call);
2147 void linphone_call_log_completed(LinphoneCall *call){
2148 LinphoneCore *lc=call->core;
2150 call->log->duration=time(NULL)-call->start_time;
2152 if (call->log->status==LinphoneCallMissed){
2155 info=ortp_strdup_printf(ngettext("You have missed %i call.",
2156 "You have missed %i calls.", lc->missed_calls),
2158 if (lc->vtable.display_status!=NULL)
2159 lc->vtable.display_status(lc,info);
2162 lc->call_logs=ms_list_prepend(lc->call_logs,(void *)call->log);
2163 if (ms_list_size(lc->call_logs)>lc->max_call_logs){
2164 MSList *elem,*prevelem=NULL;
2165 /*find the last element*/
2166 for(elem=lc->call_logs;elem!=NULL;elem=elem->next){
2170 linphone_call_log_destroy((LinphoneCallLog*)elem->data);
2171 lc->call_logs=ms_list_remove_link(lc->call_logs,elem);
2173 if (lc->vtable.call_log_updated!=NULL){
2174 lc->vtable.call_log_updated(lc,call->log);
2176 call_logs_write_to_config_file(lc);
2179 LinphoneCallState linphone_call_get_transfer_state(LinphoneCall *call) {
2180 return call->transfer_state;
2183 void linphone_call_set_transfer_state(LinphoneCall* call, LinphoneCallState state) {
2184 if (state != call->transfer_state) {
2185 LinphoneCore* lc = call->core;
2186 call->transfer_state = state;
2187 if (lc->vtable.transfer_state_changed)
2188 lc->vtable.transfer_state_changed(lc, call, state);
2193 * Returns true if the call is part of the conference.
2194 * @ingroup conferencing
2196 bool_t linphone_call_is_in_conference(const LinphoneCall *call) {
2197 return call->params.in_conference;
2202 * Perform a zoom of the video displayed during a call.
2203 * @param call the call.
2204 * @param zoom_factor a floating point number describing the zoom factor. A value 1.0 corresponds to no zoom applied.
2205 * @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.
2206 * @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.
2208 * 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.
2210 void linphone_call_zoom_video(LinphoneCall* call, float zoom_factor, float* cx, float* cy) {
2211 VideoStream* vstream = call->videostream;
2212 if (vstream && vstream->output) {
2215 if (zoom_factor < 1)
2217 float halfsize = 0.5 * 1.0 / zoom_factor;
2219 if ((*cx - halfsize) < 0)
2221 if ((*cx + halfsize) > 1)
2223 if ((*cy - halfsize) < 0)
2225 if ((*cy + halfsize) > 1)
2228 zoom[0] = zoom_factor;
2231 ms_filter_call_method(vstream->output, MS_VIDEO_DISPLAY_ZOOM, &zoom);
2232 }else ms_warning("Could not apply zoom: video output wasn't activated.");