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);
306 if(call->upnp_session != NULL) {
307 linphone_core_update_local_media_description_from_upnp(md, call->upnp_session);
308 linphone_core_update_upnp_state_in_call_stats(call);
311 linphone_address_destroy(addr);
313 if (old_md) sal_media_description_unref(old_md);
316 static int find_port_offset(LinphoneCore *lc, SalStreamType type){
321 bool_t already_used=FALSE;
322 for(offset=0;offset<100;offset+=2){
326 tried_port=linphone_core_get_audio_port (lc)+offset;
329 tried_port=linphone_core_get_video_port (lc)+offset;
333 for(elem=lc->calls;elem!=NULL;elem=elem->next){
334 LinphoneCall *call=(LinphoneCall*)elem->data;
338 existing_port = call->audio_port;
341 existing_port = call->video_port;
344 if (existing_port==tried_port) {
349 if (!already_used) break;
352 ms_error("Could not find any free port !");
358 static int select_random_port(LinphoneCore *lc, SalStreamType type) {
362 int existing_port = 0;
363 int min_port = 0, max_port = 0;
364 bool_t already_used = FALSE;
369 linphone_core_get_audio_port_range(lc, &min_port, &max_port);
372 linphone_core_get_video_port_range(lc, &min_port, &max_port);
375 tried_port = (rand() % (max_port - min_port) + min_port) & ~0x1;
376 if (tried_port < min_port) tried_port = min_port + 2;
377 for (nb_tries = 0; nb_tries < 100; nb_tries++) {
378 for (elem = lc->calls; elem != NULL; elem = elem->next) {
379 LinphoneCall *call = (LinphoneCall *)elem->data;
383 existing_port = call->audio_port;
386 existing_port = call->video_port;
389 if (existing_port == tried_port) {
394 if (!already_used) break;
396 if (nb_tries == 100) {
397 ms_error("Could not find any free port!");
403 static void linphone_call_init_common(LinphoneCall *call, LinphoneAddress *from, LinphoneAddress *to){
405 int min_port, max_port;
406 call->magic=linphone_call_magic;
408 call->state=LinphoneCallIdle;
409 call->transfer_state = LinphoneCallIdle;
410 call->start_time=time(NULL);
411 call->media_start_time=0;
412 call->log=linphone_call_log_new(call, from, to);
413 call->owns_call_log=TRUE;
414 linphone_core_notify_all_friends(call->core,LinphoneStatusOnThePhone);
415 linphone_core_get_audio_port_range(call->core, &min_port, &max_port);
416 if (min_port == max_port) {
417 /* Used fixed RTP audio port. */
418 port_offset=find_port_offset (call->core, SalAudio);
419 if (port_offset==-1) return;
420 call->audio_port=linphone_core_get_audio_port(call->core)+port_offset;
422 /* Select random RTP audio port in the specified range. */
423 call->audio_port = select_random_port(call->core, SalAudio);
425 linphone_core_get_video_port_range(call->core, &min_port, &max_port);
426 if (min_port == max_port) {
427 /* Used fixed RTP video port. */
428 port_offset=find_port_offset (call->core, SalVideo);
429 if (port_offset==-1) return;
430 call->video_port=linphone_core_get_video_port(call->core)+port_offset;
432 /* Select random RTP video port in the specified range. */
433 call->video_port = select_random_port(call->core, SalVideo);
435 linphone_call_init_stats(&call->stats[LINPHONE_CALL_STATS_AUDIO], LINPHONE_CALL_STATS_AUDIO);
436 linphone_call_init_stats(&call->stats[LINPHONE_CALL_STATS_VIDEO], LINPHONE_CALL_STATS_VIDEO);
439 void linphone_call_init_stats(LinphoneCallStats *stats, int type) {
441 stats->received_rtcp = NULL;
442 stats->sent_rtcp = NULL;
443 stats->ice_state = LinphoneIceStateNotActivated;
445 stats->upnp_state = LinphoneUpnpStateIdle;
447 stats->upnp_state = LinphoneUpnpStateNotAvailable;
452 static void discover_mtu(LinphoneCore *lc, const char *remote){
454 if (lc->net_conf.mtu==0 ){
455 /*attempt to discover mtu*/
456 mtu=ms_discover_mtu(remote);
459 ms_message("Discovered mtu is %i, RTP payload max size is %i",
460 mtu, ms_get_payload_max_size());
465 LinphoneCall * linphone_call_new_outgoing(struct _LinphoneCore *lc, LinphoneAddress *from, LinphoneAddress *to, const LinphoneCallParams *params)
467 LinphoneCall *call=ms_new0(LinphoneCall,1);
468 call->dir=LinphoneCallOutgoing;
469 call->op=sal_op_new(lc->sal);
470 sal_op_set_user_pointer(call->op,call);
472 linphone_core_get_local_ip(lc,linphone_address_get_domain(to),call->localip);
473 linphone_call_init_common(call,from,to);
474 call->params=*params;
475 if (linphone_core_get_firewall_policy(call->core) == LinphonePolicyUseIce) {
476 call->ice_session = ice_session_new();
477 ice_session_set_role(call->ice_session, IR_Controlling);
479 if (linphone_core_get_firewall_policy(call->core) == LinphonePolicyUseStun) {
480 call->ping_time=linphone_core_run_stun_tests(call->core,call);
483 if (linphone_core_get_firewall_policy(call->core) == LinphonePolicyUseUpnp) {
484 call->upnp_session = linphone_upnp_session_new(call);
487 call->camera_active=params->has_video;
489 discover_mtu(lc,linphone_address_get_domain (to));
490 if (params->referer){
491 sal_call_set_referer(call->op,params->referer->op);
492 call->referer=linphone_call_ref(params->referer);
497 LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *from, LinphoneAddress *to, SalOp *op){
498 LinphoneCall *call=ms_new0(LinphoneCall,1);
500 const SalMediaDescription *md;
502 call->dir=LinphoneCallIncoming;
503 sal_op_set_user_pointer(op,call);
507 if (lc->sip_conf.ping_with_options){
508 /*the following sends an option request back to the caller so that
509 we get a chance to discover our nat'd address before answering.*/
510 call->ping_op=sal_op_new(lc->sal);
511 from_str=linphone_address_as_string_uri_only(from);
512 sal_op_set_route(call->ping_op,sal_op_get_network_origin(op));
513 sal_op_set_user_pointer(call->ping_op,call);
514 sal_ping(call->ping_op,linphone_core_find_best_identity(lc,from,NULL),from_str);
518 linphone_address_clean(from);
519 linphone_core_get_local_ip(lc,linphone_address_get_domain(from),call->localip);
520 linphone_call_init_common(call, from, to);
521 call->log->call_id=ms_strdup(sal_op_get_call_id(op)); /*must be known at that time*/
522 linphone_core_init_default_params(lc, &call->params);
523 md=sal_call_get_remote_media_description(op);
524 call->params.has_video &= !!lc->video_policy.automatically_accept;
526 // It is licit to receive an INVITE without SDP
527 // In this case WE chose the media parameters according to policy.
528 call->params.has_video &= linphone_core_media_description_contains_video_stream(md);
530 switch (linphone_core_get_firewall_policy(call->core)) {
531 case LinphonePolicyUseIce:
532 call->ice_session = ice_session_new();
533 ice_session_set_role(call->ice_session, IR_Controlled);
534 linphone_core_update_ice_from_remote_media_description(call, sal_call_get_remote_media_description(op));
535 if (call->ice_session != NULL) {
536 linphone_call_init_media_streams(call);
537 linphone_call_start_media_streams_for_ice_gathering(call);
538 if (linphone_core_gather_ice_candidates(call->core,call)<0) {
539 /* Ice candidates gathering failed, proceed with the call anyway. */
540 linphone_call_delete_ice_session(call);
541 linphone_call_stop_media_streams_for_ice_gathering(call);
545 case LinphonePolicyUseStun:
546 call->ping_time=linphone_core_run_stun_tests(call->core,call);
547 /* No break to also destroy ice session in this case. */
549 case LinphonePolicyUseUpnp:
551 call->upnp_session = linphone_upnp_session_new(call);
552 if (call->upnp_session != NULL) {
553 linphone_call_init_media_streams(call);
554 if (linphone_core_update_upnp_from_remote_media_description(call, sal_call_get_remote_media_description(op))<0) {
555 /* uPnP port mappings failed, proceed with the call anyway. */
556 linphone_call_delete_upnp_session(call);
564 call->camera_active=call->params.has_video;
566 discover_mtu(lc,linphone_address_get_domain(from));
570 /* this function is called internally to get rid of a call.
571 It performs the following tasks:
572 - remove the call from the internal list of calls
573 - update the call logs accordingly
576 static void linphone_call_set_terminated(LinphoneCall *call){
577 LinphoneCore *lc=call->core;
579 linphone_core_update_allocated_audio_bandwidth(lc);
581 call->owns_call_log=FALSE;
582 linphone_call_log_completed(call);
585 if (call == lc->current_call){
586 ms_message("Resetting the current call");
587 lc->current_call=NULL;
590 if (linphone_core_del_call(lc,call) != 0){
591 ms_error("Could not remove the call from the list !!!");
594 if (ms_list_size(lc->calls)==0)
595 linphone_core_notify_all_friends(lc,lc->presence_mode);
597 linphone_core_conference_check_uninit(lc);
598 if (call->ringing_beep){
599 linphone_core_stop_dtmf(lc);
600 call->ringing_beep=FALSE;
603 linphone_call_unref(call->referer);
608 void linphone_call_fix_call_parameters(LinphoneCall *call){
609 call->params.has_video=call->current_params.has_video;
610 call->params.media_encryption=call->current_params.media_encryption;
613 const char *linphone_call_state_to_string(LinphoneCallState cs){
615 case LinphoneCallIdle:
616 return "LinphoneCallIdle";
617 case LinphoneCallIncomingReceived:
618 return "LinphoneCallIncomingReceived";
619 case LinphoneCallOutgoingInit:
620 return "LinphoneCallOutgoingInit";
621 case LinphoneCallOutgoingProgress:
622 return "LinphoneCallOutgoingProgress";
623 case LinphoneCallOutgoingRinging:
624 return "LinphoneCallOutgoingRinging";
625 case LinphoneCallOutgoingEarlyMedia:
626 return "LinphoneCallOutgoingEarlyMedia";
627 case LinphoneCallConnected:
628 return "LinphoneCallConnected";
629 case LinphoneCallStreamsRunning:
630 return "LinphoneCallStreamsRunning";
631 case LinphoneCallPausing:
632 return "LinphoneCallPausing";
633 case LinphoneCallPaused:
634 return "LinphoneCallPaused";
635 case LinphoneCallResuming:
636 return "LinphoneCallResuming";
637 case LinphoneCallRefered:
638 return "LinphoneCallRefered";
639 case LinphoneCallError:
640 return "LinphoneCallError";
641 case LinphoneCallEnd:
642 return "LinphoneCallEnd";
643 case LinphoneCallPausedByRemote:
644 return "LinphoneCallPausedByRemote";
645 case LinphoneCallUpdatedByRemote:
646 return "LinphoneCallUpdatedByRemote";
647 case LinphoneCallIncomingEarlyMedia:
648 return "LinphoneCallIncomingEarlyMedia";
649 case LinphoneCallUpdating:
650 return "LinphoneCallUpdating";
651 case LinphoneCallReleased:
652 return "LinphoneCallReleased";
654 return "undefined state";
657 void linphone_call_set_state(LinphoneCall *call, LinphoneCallState cstate, const char *message){
658 LinphoneCore *lc=call->core;
660 if (call->state!=cstate){
661 if (call->state==LinphoneCallEnd || call->state==LinphoneCallError){
662 if (cstate!=LinphoneCallReleased){
663 ms_warning("Spurious call state change from %s to %s, ignored.",linphone_call_state_to_string(call->state),
664 linphone_call_state_to_string(cstate));
668 ms_message("Call %p: moving from state %s to %s",call,linphone_call_state_to_string(call->state),
669 linphone_call_state_to_string(cstate));
670 if (cstate!=LinphoneCallRefered){
671 /*LinphoneCallRefered is rather an event, not a state.
672 Indeed it does not change the state of the call (still paused or running)*/
675 if (cstate==LinphoneCallEnd || cstate==LinphoneCallError){
676 switch(call->reason){
677 case LinphoneReasonDeclined:
678 call->log->status=LinphoneCallDeclined;
680 case LinphoneReasonNotAnswered:
681 call->log->status=LinphoneCallMissed;
686 linphone_call_set_terminated (call);
688 if (cstate == LinphoneCallConnected) {
689 call->log->status=LinphoneCallSuccess;
690 call->media_start_time=time(NULL);
693 if (lc->vtable.call_state_changed)
694 lc->vtable.call_state_changed(lc,call,cstate,message);
695 if (cstate==LinphoneCallReleased){
696 if (call->op!=NULL) {
697 /* so that we cannot have anymore upcalls for SAL
698 concerning this call*/
699 sal_op_release(call->op);
702 linphone_call_unref(call);
707 static void linphone_call_destroy(LinphoneCall *obj)
710 linphone_call_delete_upnp_session(obj);
712 linphone_call_delete_ice_session(obj);
714 sal_op_release(obj->op);
717 if (obj->resultdesc!=NULL) {
718 sal_media_description_unref(obj->resultdesc);
719 obj->resultdesc=NULL;
721 if (obj->localdesc!=NULL) {
722 sal_media_description_unref(obj->localdesc);
726 sal_op_release(obj->ping_op);
729 ms_free(obj->refer_to);
731 if (obj->owns_call_log)
732 linphone_call_log_destroy(obj->log);
733 if (obj->auth_token) {
734 ms_free(obj->auth_token);
741 * @addtogroup call_control
746 * Increments the call 's reference count.
747 * An application that wishes to retain a pointer to call object
748 * must use this function to unsure the pointer remains
749 * valid. Once the application no more needs this pointer,
750 * it must call linphone_call_unref().
752 LinphoneCall * linphone_call_ref(LinphoneCall *obj){
758 * Decrements the call object reference count.
759 * See linphone_call_ref().
761 void linphone_call_unref(LinphoneCall *obj){
764 linphone_call_destroy(obj);
769 * Returns current parameters associated to the call.
771 const LinphoneCallParams * linphone_call_get_current_params(const LinphoneCall *call){
772 return &call->current_params;
775 static bool_t is_video_active(const SalStreamDescription *sd){
776 return sd->rtp_port!=0 && sd->dir!=SalStreamInactive;
780 * Returns call parameters proposed by remote.
782 * This is useful when receiving an incoming call, to know whether the remote party
783 * supports video, encryption or whatever.
785 const LinphoneCallParams * linphone_call_get_remote_params(LinphoneCall *call){
786 LinphoneCallParams *cp=&call->remote_params;
787 memset(cp,0,sizeof(*cp));
789 SalMediaDescription *md=sal_call_get_remote_media_description(call->op);
791 SalStreamDescription *asd,*vsd,*secure_asd,*secure_vsd;
793 asd=sal_media_description_find_stream(md,SalProtoRtpAvp,SalAudio);
794 vsd=sal_media_description_find_stream(md,SalProtoRtpAvp,SalVideo);
795 secure_asd=sal_media_description_find_stream(md,SalProtoRtpSavp,SalAudio);
796 secure_vsd=sal_media_description_find_stream(md,SalProtoRtpSavp,SalVideo);
798 cp->has_video=is_video_active(secure_vsd);
799 if (secure_asd || asd==NULL)
800 cp->media_encryption=LinphoneMediaEncryptionSRTP;
802 cp->has_video=is_video_active(vsd);
805 if (md->bandwidth>0 && md->bandwidth<=linphone_core_get_edge_bw(call->core)){
806 cp->low_bandwidth=TRUE;
816 * Returns the remote address associated to this call
819 const LinphoneAddress * linphone_call_get_remote_address(const LinphoneCall *call){
820 return call->dir==LinphoneCallIncoming ? call->log->from : call->log->to;
824 * Returns the remote address associated to this call as a string.
826 * The result string must be freed by user using ms_free().
828 char *linphone_call_get_remote_address_as_string(const LinphoneCall *call){
829 return linphone_address_as_string(linphone_call_get_remote_address(call));
833 * Retrieves the call's current state.
835 LinphoneCallState linphone_call_get_state(const LinphoneCall *call){
840 * Returns the reason for a call termination (either error or normal termination)
842 LinphoneReason linphone_call_get_reason(const LinphoneCall *call){
847 * Get the user_pointer in the LinphoneCall
849 * @ingroup call_control
851 * return user_pointer an opaque user pointer that can be retrieved at any time
853 void *linphone_call_get_user_pointer(LinphoneCall *call)
855 return call->user_pointer;
859 * Set the user_pointer in the LinphoneCall
861 * @ingroup call_control
863 * the user_pointer is an opaque user pointer that can be retrieved at any time in the LinphoneCall
865 void linphone_call_set_user_pointer(LinphoneCall *call, void *user_pointer)
867 call->user_pointer = user_pointer;
871 * Returns the call log associated to this call.
873 LinphoneCallLog *linphone_call_get_call_log(const LinphoneCall *call){
878 * Returns the refer-to uri (if the call was transfered).
880 const char *linphone_call_get_refer_to(const LinphoneCall *call){
881 return call->refer_to;
885 * Returns direction of the call (incoming or outgoing).
887 LinphoneCallDir linphone_call_get_dir(const LinphoneCall *call){
888 return call->log->dir;
892 * Returns the far end's user agent description string, if available.
894 const char *linphone_call_get_remote_user_agent(LinphoneCall *call){
896 return sal_op_get_remote_ua (call->op);
902 * Returns true if this calls has received a transfer that has not been
904 * Pending transfers are executed when this call is being paused or closed,
905 * locally or by remote endpoint.
906 * If the call is already paused while receiving the transfer request, the
907 * transfer immediately occurs.
909 bool_t linphone_call_has_transfer_pending(const LinphoneCall *call){
910 return call->refer_pending;
914 * Returns call's duration in seconds.
916 int linphone_call_get_duration(const LinphoneCall *call){
917 if (call->media_start_time==0) return 0;
918 return time(NULL)-call->media_start_time;
922 * Returns the call object this call is replacing, if any.
923 * Call replacement can occur during call transfers.
924 * By default, the core automatically terminates the replaced call and accept the new one.
925 * This function allows the application to know whether a new incoming call is a one that replaces another one.
927 LinphoneCall *linphone_call_get_replaced_call(LinphoneCall *call){
928 SalOp *op=sal_call_get_replaces(call->op);
930 return (LinphoneCall*)sal_op_get_user_pointer(op);
936 * Indicate whether camera input should be sent to remote end.
938 void linphone_call_enable_camera (LinphoneCall *call, bool_t enable){
940 if (call->videostream!=NULL && call->videostream->ms.ticker!=NULL){
941 LinphoneCore *lc=call->core;
942 MSWebCam *nowebcam=get_nowebcam_device();
943 if (call->camera_active!=enable && lc->video_conf.device!=nowebcam){
944 video_stream_change_camera(call->videostream,
945 enable ? lc->video_conf.device : nowebcam);
948 call->camera_active=enable;
953 * Take a photo of currently received video and write it into a jpeg file.
955 int linphone_call_take_video_snapshot(LinphoneCall *call, const char *file){
957 if (call->videostream!=NULL && call->videostream->jpegwriter!=NULL){
958 return ms_filter_call_method(call->videostream->jpegwriter,MS_JPEG_WRITER_TAKE_SNAPSHOT,(void*)file);
960 ms_warning("Cannot take snapshot: no currently running video stream on this call.");
967 * Returns TRUE if camera pictures are sent to the remote party.
969 bool_t linphone_call_camera_enabled (const LinphoneCall *call){
970 return call->camera_active;
974 * Enable video stream.
976 void linphone_call_params_enable_video(LinphoneCallParams *cp, bool_t enabled){
977 cp->has_video=enabled;
980 const PayloadType* linphone_call_params_get_used_audio_codec(const LinphoneCallParams *cp) {
981 return cp->audio_codec;
984 const PayloadType* linphone_call_params_get_used_video_codec(const LinphoneCallParams *cp) {
985 return cp->video_codec;
989 * @ingroup call_control
990 * Use to know if this call has been configured in low bandwidth mode.
991 * This mode can be automatically discovered thanks to a stun server when activate_edge_workarounds=1 in section [net] of configuration file.
992 * An application that would have reliable way to know network capacity may not use activate_edge_workarounds=1 but instead manually configure
993 * low bandwidth mode with linphone_call_params_enable_low_bandwidth().
994 * <br> When enabled, this param may transform a call request with video in audio only mode.
995 * @return TRUE if low bandwidth has been configured/detected
997 bool_t linphone_call_params_low_bandwidth_enabled(const LinphoneCallParams *cp) {
998 return cp->low_bandwidth;
1002 * @ingroup call_control
1003 * Indicate low bandwith mode.
1004 * 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
1005 * 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
1006 * that it is achievable by the codec selected after SDP handshake. Video is automatically disabled.
1009 void linphone_call_params_enable_low_bandwidth(LinphoneCallParams *cp, bool_t enabled){
1010 cp->low_bandwidth=enabled;
1014 * Returns whether video is enabled.
1016 bool_t linphone_call_params_video_enabled(const LinphoneCallParams *cp){
1017 return cp->has_video;
1020 enum LinphoneMediaEncryption linphone_call_params_get_media_encryption(const LinphoneCallParams *cp) {
1021 return cp->media_encryption;
1024 void linphone_call_params_set_media_encryption(LinphoneCallParams *cp, enum LinphoneMediaEncryption e) {
1025 cp->media_encryption = e;
1030 * Enable sending of real early media (during outgoing calls).
1032 void linphone_call_params_enable_early_media_sending(LinphoneCallParams *cp, bool_t enabled){
1033 cp->real_early_media=enabled;
1036 bool_t linphone_call_params_early_media_sending_enabled(const LinphoneCallParams *cp){
1037 return cp->real_early_media;
1041 * Returns true if the call is part of the locally managed conference.
1043 bool_t linphone_call_params_local_conference_mode(const LinphoneCallParams *cp){
1044 return cp->in_conference;
1048 * Refine bandwidth settings for this call by setting a bandwidth limit for audio streams.
1049 * As a consequence, codecs whose bitrates are not compatible with this limit won't be used.
1051 void linphone_call_params_set_audio_bandwidth_limit(LinphoneCallParams *cp, int bandwidth){
1052 cp->audio_bw=bandwidth;
1055 #ifdef VIDEO_ENABLED
1057 * Request remote side to send us a Video Fast Update.
1059 void linphone_call_send_vfu_request(LinphoneCall *call)
1061 if (LinphoneCallStreamsRunning == linphone_call_get_state(call))
1062 sal_call_send_vfu_request(call->op);
1069 LinphoneCallParams * linphone_call_params_copy(const LinphoneCallParams *cp){
1070 LinphoneCallParams *ncp=ms_new0(LinphoneCallParams,1);
1071 memcpy(ncp,cp,sizeof(LinphoneCallParams));
1078 void linphone_call_params_destroy(LinphoneCallParams *p){
1087 #ifdef TEST_EXT_RENDERER
1088 static void rendercb(void *data, const MSPicture *local, const MSPicture *remote){
1089 ms_message("rendercb, local buffer=%p, remote buffer=%p",
1090 local ? local->planes[0] : NULL, remote? remote->planes[0] : NULL);
1094 #ifdef VIDEO_ENABLED
1095 static void video_stream_event_cb(void *user_pointer, const MSFilter *f, const unsigned int event_id, const void *args){
1096 LinphoneCall* call = (LinphoneCall*) user_pointer;
1097 ms_warning("In linphonecall.c: video_stream_event_cb");
1099 case MS_VIDEO_DECODER_DECODING_ERRORS:
1100 ms_warning("Case is MS_VIDEO_DECODER_DECODING_ERRORS");
1101 linphone_call_send_vfu_request(call);
1103 case MS_VIDEO_DECODER_FIRST_IMAGE_DECODED:
1104 ms_message("First video frame decoded successfully");
1105 if (call->nextVideoFrameDecoded._func != NULL)
1106 call->nextVideoFrameDecoded._func(call, call->nextVideoFrameDecoded._user_data);
1109 ms_warning("Unhandled event %i", event_id);
1115 void linphone_call_set_next_video_frame_decoded_callback(LinphoneCall *call, LinphoneCallCbFunc cb, void* user_data) {
1116 call->nextVideoFrameDecoded._func = cb;
1117 call->nextVideoFrameDecoded._user_data = user_data;
1118 #ifdef VIDEO_ENABLED
1119 ms_filter_call_method_noarg(call->videostream->ms.decoder, MS_VIDEO_DECODER_RESET_FIRST_IMAGE_NOTIFICATION);
1123 void linphone_call_init_audio_stream(LinphoneCall *call){
1124 LinphoneCore *lc=call->core;
1125 AudioStream *audiostream;
1128 if (call->audiostream != NULL) return;
1129 call->audiostream=audiostream=audio_stream_new(call->audio_port,call->audio_port+1,linphone_core_ipv6_enabled(lc));
1130 dscp=linphone_core_get_audio_dscp(lc);
1132 audio_stream_set_dscp(audiostream,dscp);
1133 if (linphone_core_echo_limiter_enabled(lc)){
1134 const char *type=lp_config_get_string(lc->config,"sound","el_type","mic");
1135 if (strcasecmp(type,"mic")==0)
1136 audio_stream_enable_echo_limiter(audiostream,ELControlMic);
1137 else if (strcasecmp(type,"full")==0)
1138 audio_stream_enable_echo_limiter(audiostream,ELControlFull);
1140 audio_stream_enable_gain_control(audiostream,TRUE);
1141 if (linphone_core_echo_cancellation_enabled(lc)){
1142 int len,delay,framesize;
1143 const char *statestr=lp_config_get_string(lc->config,"sound","ec_state",NULL);
1144 len=lp_config_get_int(lc->config,"sound","ec_tail_len",0);
1145 delay=lp_config_get_int(lc->config,"sound","ec_delay",0);
1146 framesize=lp_config_get_int(lc->config,"sound","ec_framesize",0);
1147 audio_stream_set_echo_canceller_params(audiostream,len,delay,framesize);
1148 if (statestr && audiostream->ec){
1149 ms_filter_call_method(audiostream->ec,MS_ECHO_CANCELLER_SET_STATE_STRING,(void*)statestr);
1152 audio_stream_enable_automatic_gain_control(audiostream,linphone_core_agc_enabled(lc));
1154 int enabled=lp_config_get_int(lc->config,"sound","noisegate",0);
1155 audio_stream_enable_noise_gate(audiostream,enabled);
1158 audio_stream_set_features(audiostream,linphone_core_get_audio_features(lc));
1161 RtpTransport *artp=lc->rtptf->audio_rtp_func(lc->rtptf->audio_rtp_func_data, call->audio_port);
1162 RtpTransport *artcp=lc->rtptf->audio_rtcp_func(lc->rtptf->audio_rtcp_func_data, call->audio_port+1);
1163 rtp_session_set_transports(audiostream->ms.session,artp,artcp);
1165 if ((linphone_core_get_firewall_policy(lc) == LinphonePolicyUseIce) && (call->ice_session != NULL)){
1166 rtp_session_set_pktinfo(audiostream->ms.session, TRUE);
1167 rtp_session_set_symmetric_rtp(audiostream->ms.session, FALSE);
1168 if (ice_session_check_list(call->ice_session, 0) == NULL) {
1169 ice_session_add_check_list(call->ice_session, ice_check_list_new());
1171 audiostream->ms.ice_check_list = ice_session_check_list(call->ice_session, 0);
1172 ice_check_list_set_rtp_session(audiostream->ms.ice_check_list, audiostream->ms.session);
1175 call->audiostream_app_evq = ortp_ev_queue_new();
1176 rtp_session_register_event_queue(audiostream->ms.session,call->audiostream_app_evq);
1179 void linphone_call_init_video_stream(LinphoneCall *call){
1180 #ifdef VIDEO_ENABLED
1181 LinphoneCore *lc=call->core;
1183 if (!call->params.has_video) {
1184 linphone_call_stop_video_stream(call);
1187 if (call->videostream != NULL) return;
1188 if ((lc->video_conf.display || lc->video_conf.capture) && call->params.has_video){
1189 int video_recv_buf_size=lp_config_get_int(lc->config,"video","recv_buf_size",0);
1190 int dscp=linphone_core_get_video_dscp(lc);
1192 call->videostream=video_stream_new(call->video_port,call->video_port+1,linphone_core_ipv6_enabled(lc));
1194 video_stream_set_dscp(call->videostream,dscp);
1195 video_stream_enable_display_filter_auto_rotate(call->videostream, lp_config_get_int(lc->config,"video","display_filter_auto_rotate",0));
1196 if (video_recv_buf_size>0) rtp_session_set_recv_buf_size(call->videostream->ms.session,video_recv_buf_size);
1198 if( lc->video_conf.displaytype != NULL)
1199 video_stream_set_display_filter_name(call->videostream,lc->video_conf.displaytype);
1200 video_stream_set_event_callback(call->videostream,video_stream_event_cb, call);
1202 RtpTransport *vrtp=lc->rtptf->video_rtp_func(lc->rtptf->video_rtp_func_data, call->video_port);
1203 RtpTransport *vrtcp=lc->rtptf->video_rtcp_func(lc->rtptf->video_rtcp_func_data, call->video_port+1);
1204 rtp_session_set_transports(call->videostream->ms.session,vrtp,vrtcp);
1206 if ((linphone_core_get_firewall_policy(lc) == LinphonePolicyUseIce) && (call->ice_session != NULL)){
1207 rtp_session_set_pktinfo(call->videostream->ms.session, TRUE);
1208 rtp_session_set_symmetric_rtp(call->videostream->ms.session, FALSE);
1209 if (ice_session_check_list(call->ice_session, 1) == NULL) {
1210 ice_session_add_check_list(call->ice_session, ice_check_list_new());
1212 call->videostream->ms.ice_check_list = ice_session_check_list(call->ice_session, 1);
1213 ice_check_list_set_rtp_session(call->videostream->ms.ice_check_list, call->videostream->ms.session);
1215 call->videostream_app_evq = ortp_ev_queue_new();
1216 rtp_session_register_event_queue(call->videostream->ms.session,call->videostream_app_evq);
1217 #ifdef TEST_EXT_RENDERER
1218 video_stream_set_render_callback(call->videostream,rendercb,NULL);
1222 call->videostream=NULL;
1226 void linphone_call_init_media_streams(LinphoneCall *call){
1227 linphone_call_init_audio_stream(call);
1228 linphone_call_init_video_stream(call);
1232 static int dtmf_tab[16]={'0','1','2','3','4','5','6','7','8','9','*','#','A','B','C','D'};
1234 static void linphone_core_dtmf_received(LinphoneCore *lc, int dtmf){
1235 if (dtmf<0 || dtmf>15){
1236 ms_warning("Bad dtmf value %i",dtmf);
1239 if (lc->vtable.dtmf_received != NULL)
1240 lc->vtable.dtmf_received(lc, linphone_core_get_current_call(lc), dtmf_tab[dtmf]);
1243 static void parametrize_equalizer(LinphoneCore *lc, AudioStream *st){
1245 MSFilter *f=st->equalizer;
1246 int enabled=lp_config_get_int(lc->config,"sound","eq_active",0);
1247 const char *gains=lp_config_get_string(lc->config,"sound","eq_gains",NULL);
1248 ms_filter_call_method(f,MS_EQUALIZER_SET_ACTIVE,&enabled);
1254 if (sscanf(gains,"%f:%f:%f %n",&g.frequency,&g.gain,&g.width,&bytes)==3){
1255 ms_message("Read equalizer gains: %f(~%f) --> %f",g.frequency,g.width,g.gain);
1256 ms_filter_call_method(f,MS_EQUALIZER_SET_GAIN,&g);
1265 void _post_configure_audio_stream(AudioStream *st, LinphoneCore *lc, bool_t muted){
1266 float mic_gain=lc->sound_conf.soft_mic_lev;
1269 float ng_thres=lp_config_get_float(lc->config,"sound","ng_thres",0.05);
1270 float ng_floorgain=lp_config_get_float(lc->config,"sound","ng_floorgain",0);
1271 int dc_removal=lp_config_get_int(lc->config,"sound","dc_removal",0);
1274 linphone_core_set_mic_gain_db (lc, mic_gain);
1276 audio_stream_set_mic_gain(st,0);
1278 recv_gain = lc->sound_conf.soft_play_lev;
1279 if (recv_gain != 0) {
1280 linphone_core_set_playback_gain_db (lc,recv_gain);
1284 ms_filter_call_method(st->volsend,MS_VOLUME_REMOVE_DC,&dc_removal);
1285 float speed=lp_config_get_float(lc->config,"sound","el_speed",-1);
1286 thres=lp_config_get_float(lc->config,"sound","el_thres",-1);
1287 float force=lp_config_get_float(lc->config,"sound","el_force",-1);
1288 int sustain=lp_config_get_int(lc->config,"sound","el_sustain",-1);
1289 float transmit_thres=lp_config_get_float(lc->config,"sound","el_transmit_thres",-1);
1292 if (speed==-1) speed=0.03;
1293 if (force==-1) force=25;
1294 ms_filter_call_method(f,MS_VOLUME_SET_EA_SPEED,&speed);
1295 ms_filter_call_method(f,MS_VOLUME_SET_EA_FORCE,&force);
1297 ms_filter_call_method(f,MS_VOLUME_SET_EA_THRESHOLD,&thres);
1299 ms_filter_call_method(f,MS_VOLUME_SET_EA_SUSTAIN,&sustain);
1300 if (transmit_thres!=-1)
1301 ms_filter_call_method(f,MS_VOLUME_SET_EA_TRANSMIT_THRESHOLD,&transmit_thres);
1303 ms_filter_call_method(st->volsend,MS_VOLUME_SET_NOISE_GATE_THRESHOLD,&ng_thres);
1304 ms_filter_call_method(st->volsend,MS_VOLUME_SET_NOISE_GATE_FLOORGAIN,&ng_floorgain);
1307 /* parameters for a limited noise-gate effect, using echo limiter threshold */
1308 float floorgain = 1/pow(10,(mic_gain)/10);
1309 int spk_agc=lp_config_get_int(lc->config,"sound","speaker_agc_enabled",0);
1310 ms_filter_call_method(st->volrecv, MS_VOLUME_ENABLE_AGC, &spk_agc);
1311 ms_filter_call_method(st->volrecv,MS_VOLUME_SET_NOISE_GATE_THRESHOLD,&ng_thres);
1312 ms_filter_call_method(st->volrecv,MS_VOLUME_SET_NOISE_GATE_FLOORGAIN,&floorgain);
1314 parametrize_equalizer(lc,st);
1317 static void post_configure_audio_streams(LinphoneCall*call){
1318 AudioStream *st=call->audiostream;
1319 LinphoneCore *lc=call->core;
1320 _post_configure_audio_stream(st,lc,call->audio_muted);
1321 if (lc->vtable.dtmf_received!=NULL){
1322 /* replace by our default action*/
1323 audio_stream_play_received_dtmfs(call->audiostream,FALSE);
1324 /*rtp_session_signal_connect(call->audiostream->session,"telephone-event",(RtpCallback)linphone_core_dtmf_received,(unsigned long)lc);*/
1328 static RtpProfile *make_profile(LinphoneCall *call, const SalMediaDescription *md, const SalStreamDescription *desc, int *used_pt){
1331 RtpProfile *prof=rtp_profile_new("Call profile");
1334 LinphoneCore *lc=call->core;
1336 const LinphoneCallParams *params=&call->params;
1339 for(elem=desc->payloads;elem!=NULL;elem=elem->next){
1340 PayloadType *pt=(PayloadType*)elem->data;
1343 if ((pt->flags & PAYLOAD_TYPE_FLAG_CAN_SEND) && first) {
1344 if (desc->type==SalAudio){
1345 linphone_core_update_allocated_audio_bandwidth_in_call(call,pt);
1346 if (params->up_ptime)
1347 up_ptime=params->up_ptime;
1348 else up_ptime=linphone_core_get_upload_ptime(lc);
1350 *used_pt=payload_type_get_number(pt);
1353 if (desc->bandwidth>0) remote_bw=desc->bandwidth;
1354 else if (md->bandwidth>0) {
1355 /*case where b=AS is given globally, not per stream*/
1356 remote_bw=md->bandwidth;
1357 if (desc->type==SalVideo){
1358 remote_bw=get_video_bandwidth(remote_bw,call->audio_bw);
1362 if (desc->type==SalAudio){
1363 int audio_bw=call->audio_bw;
1365 if (params->up_bw< audio_bw)
1366 audio_bw=params->up_bw;
1368 bw=get_min_bandwidth(audio_bw,remote_bw);
1369 }else bw=get_min_bandwidth(get_video_bandwidth(linphone_core_get_upload_bandwidth (lc),call->audio_bw),remote_bw);
1370 if (bw>0) pt->normal_bitrate=bw*1000;
1371 else if (desc->type==SalAudio){
1372 pt->normal_bitrate=-1;
1375 up_ptime=desc->ptime;
1379 snprintf(tmp,sizeof(tmp),"ptime=%i",up_ptime);
1380 payload_type_append_send_fmtp(pt,tmp);
1382 number=payload_type_get_number(pt);
1383 if (rtp_profile_get_payload(prof,number)!=NULL){
1384 ms_warning("A payload type with number %i already exists in profile !",number);
1386 rtp_profile_set_payload(prof,number,pt);
1392 static void setup_ring_player(LinphoneCore *lc, LinphoneCall *call){
1393 int pause_time=3000;
1394 audio_stream_play(call->audiostream,lc->sound_conf.ringback_tone);
1395 ms_filter_call_method(call->audiostream->soundread,MS_FILE_PLAYER_LOOP,&pause_time);
1398 static bool_t linphone_call_sound_resources_available(LinphoneCall *call){
1399 LinphoneCore *lc=call->core;
1400 LinphoneCall *current=linphone_core_get_current_call(lc);
1401 return !linphone_core_is_in_conference(lc) &&
1402 (current==NULL || current==call);
1404 static int find_crypto_index_from_tag(const SalSrtpCryptoAlgo crypto[],unsigned char tag) {
1406 for(i=0; i<SAL_CRYPTO_ALGO_MAX; i++) {
1407 if (crypto[i].tag == tag) {
1413 static void linphone_call_start_audio_stream(LinphoneCall *call, const char *cname, bool_t muted, bool_t send_ringbacktone, bool_t use_arc){
1414 LinphoneCore *lc=call->core;
1416 char rtcp_tool[128]={0};
1417 snprintf(rtcp_tool,sizeof(rtcp_tool)-1,"%s-%s",linphone_core_get_user_agent_name(),linphone_core_get_user_agent_version());
1418 /* look for savp stream first */
1419 const SalStreamDescription *stream=sal_media_description_find_stream(call->resultdesc,
1420 SalProtoRtpSavp,SalAudio);
1421 /* no savp audio stream, use avp */
1423 stream=sal_media_description_find_stream(call->resultdesc,
1424 SalProtoRtpAvp,SalAudio);
1426 if (stream && stream->dir!=SalStreamInactive && stream->rtp_port!=0){
1427 MSSndCard *playcard=lc->sound_conf.lsd_card ?
1428 lc->sound_conf.lsd_card : lc->sound_conf.play_sndcard;
1429 MSSndCard *captcard=lc->sound_conf.capt_sndcard;
1430 const char *playfile=lc->play_file;
1431 const char *recfile=lc->rec_file;
1432 call->audio_profile=make_profile(call,call->resultdesc,stream,&used_pt);
1436 call->current_params.audio_codec = rtp_profile_get_payload(call->audio_profile, used_pt);
1437 if (playcard==NULL) {
1438 ms_warning("No card defined for playback !");
1440 if (captcard==NULL) {
1441 ms_warning("No card defined for capture !");
1443 /*Replace soundcard filters by inactive file players or recorders
1444 when placed in recvonly or sendonly mode*/
1445 if (stream->rtp_port==0 || stream->dir==SalStreamRecvOnly){
1448 }else if (stream->dir==SalStreamSendOnly){
1452 /*And we will eventually play "playfile" if set by the user*/
1455 if (send_ringbacktone){
1457 playfile=NULL;/* it is setup later*/
1459 /*if playfile are supplied don't use soundcards*/
1460 if (lc->use_files) {
1464 if (call->params.in_conference){
1465 /* first create the graph without soundcard resources*/
1466 captcard=playcard=NULL;
1468 if (!linphone_call_sound_resources_available(call)){
1469 ms_message("Sound resources are used by another call, not using soundcard.");
1470 captcard=playcard=NULL;
1472 use_ec=captcard==NULL ? FALSE : linphone_core_echo_cancellation_enabled(lc);
1473 if (playcard && stream->max_rate>0) ms_snd_card_set_preferred_sample_rate(playcard, stream->max_rate);
1474 if (captcard && stream->max_rate>0) ms_snd_card_set_preferred_sample_rate(captcard, stream->max_rate);
1475 audio_stream_enable_adaptive_bitrate_control(call->audiostream,use_arc);
1476 audio_stream_enable_adaptive_jittcomp(call->audiostream, linphone_core_audio_adaptive_jittcomp_enabled(lc));
1477 audio_stream_start_full(
1479 call->audio_profile,
1480 stream->rtp_addr[0]!='\0' ? stream->rtp_addr : call->resultdesc->addr,
1482 stream->rtcp_addr[0]!='\0' ? stream->rtcp_addr : call->resultdesc->addr,
1483 linphone_core_rtcp_enabled(lc) ? (stream->rtcp_port) : 0,
1485 linphone_core_get_audio_jittcomp(lc),
1492 post_configure_audio_streams(call);
1493 if (muted && !send_ringbacktone){
1494 audio_stream_set_mic_gain(call->audiostream,0);
1496 if (stream->dir==SalStreamSendOnly && playfile!=NULL){
1498 ms_filter_call_method(call->audiostream->soundread,MS_FILE_PLAYER_LOOP,&pause_time);
1500 if (send_ringbacktone){
1501 setup_ring_player(lc,call);
1503 audio_stream_set_rtcp_information(call->audiostream, cname, rtcp_tool);
1505 /* valid local tags are > 0 */
1506 if (stream->proto == SalProtoRtpSavp) {
1507 const SalStreamDescription *local_st_desc=sal_media_description_find_stream(call->localdesc,
1508 SalProtoRtpSavp,SalAudio);
1509 int crypto_idx = find_crypto_index_from_tag(local_st_desc->crypto, stream->crypto_local_tag);
1511 if (crypto_idx >= 0) {
1512 audio_stream_enable_srtp(
1514 stream->crypto[0].algo,
1515 local_st_desc->crypto[crypto_idx].master_key,
1516 stream->crypto[0].master_key);
1517 call->audiostream_encrypted=TRUE;
1519 ms_warning("Failed to find local crypto algo with tag: %d", stream->crypto_local_tag);
1520 call->audiostream_encrypted=FALSE;
1522 }else call->audiostream_encrypted=FALSE;
1523 if (call->params.in_conference){
1524 /*transform the graph to connect it to the conference filter */
1525 bool_t mute=stream->dir==SalStreamRecvOnly;
1526 linphone_call_add_to_conf(call, mute);
1528 call->current_params.in_conference=call->params.in_conference;
1529 call->current_params.low_bandwidth=call->params.low_bandwidth;
1530 }else ms_warning("No audio stream accepted ?");
1534 static void linphone_call_start_video_stream(LinphoneCall *call, const char *cname,bool_t all_inputs_muted){
1535 #ifdef VIDEO_ENABLED
1536 LinphoneCore *lc=call->core;
1538 /* look for savp stream first */
1539 const SalStreamDescription *vstream=sal_media_description_find_stream(call->resultdesc,
1540 SalProtoRtpSavp,SalVideo);
1541 char rtcp_tool[128]={0};
1542 snprintf(rtcp_tool,sizeof(rtcp_tool)-1,"%s-%s",linphone_core_get_user_agent_name(),linphone_core_get_user_agent_version());
1544 /* no savp audio stream, use avp */
1546 vstream=sal_media_description_find_stream(call->resultdesc,
1547 SalProtoRtpAvp,SalVideo);
1549 /* shutdown preview */
1550 if (lc->previewstream!=NULL) {
1551 video_preview_stop(lc->previewstream);
1552 lc->previewstream=NULL;
1555 if (vstream!=NULL && vstream->dir!=SalStreamInactive && vstream->rtp_port!=0) {
1556 const char *rtp_addr=vstream->rtp_addr[0]!='\0' ? vstream->rtp_addr : call->resultdesc->addr;
1557 const char *rtcp_addr=vstream->rtcp_addr[0]!='\0' ? vstream->rtcp_addr : call->resultdesc->addr;
1558 call->video_profile=make_profile(call,call->resultdesc,vstream,&used_pt);
1560 call->current_params.video_codec = rtp_profile_get_payload(call->video_profile, used_pt);
1561 VideoStreamDir dir=VideoStreamSendRecv;
1562 MSWebCam *cam=lc->video_conf.device;
1563 bool_t is_inactive=FALSE;
1565 call->current_params.has_video=TRUE;
1567 video_stream_enable_adaptive_bitrate_control(call->videostream,
1568 linphone_core_adaptive_rate_control_enabled(lc));
1569 video_stream_enable_adaptive_jittcomp(call->videostream, linphone_core_video_adaptive_jittcomp_enabled(lc));
1570 video_stream_set_sent_video_size(call->videostream,linphone_core_get_preferred_video_size(lc));
1571 video_stream_enable_self_view(call->videostream,lc->video_conf.selfview);
1572 if (lc->video_window_id!=0)
1573 video_stream_set_native_window_id(call->videostream,lc->video_window_id);
1574 if (lc->preview_window_id!=0)
1575 video_stream_set_native_preview_window_id (call->videostream,lc->preview_window_id);
1576 video_stream_use_preview_video_window (call->videostream,lc->use_preview_window);
1578 if (vstream->dir==SalStreamSendOnly && lc->video_conf.capture ){
1579 cam=get_nowebcam_device();
1580 dir=VideoStreamSendOnly;
1581 }else if (vstream->dir==SalStreamRecvOnly && lc->video_conf.display ){
1582 dir=VideoStreamRecvOnly;
1583 }else if (vstream->dir==SalStreamSendRecv){
1584 if (lc->video_conf.display && lc->video_conf.capture)
1585 dir=VideoStreamSendRecv;
1586 else if (lc->video_conf.display)
1587 dir=VideoStreamRecvOnly;
1589 dir=VideoStreamSendOnly;
1591 ms_warning("video stream is inactive.");
1592 /*either inactive or incompatible with local capabilities*/
1595 if (call->camera_active==FALSE || all_inputs_muted){
1596 cam=get_nowebcam_device();
1599 call->log->video_enabled = TRUE;
1600 video_stream_set_direction (call->videostream, dir);
1601 ms_message("%s lc rotation:%d\n", __FUNCTION__, lc->device_rotation);
1602 video_stream_set_device_rotation(call->videostream, lc->device_rotation);
1603 video_stream_start(call->videostream,
1604 call->video_profile, rtp_addr, vstream->rtp_port,
1605 rtcp_addr, linphone_core_rtcp_enabled(lc) ? (vstream->rtcp_port) : 0,
1606 used_pt, linphone_core_get_video_jittcomp(lc), cam);
1607 video_stream_set_rtcp_information(call->videostream, cname,rtcp_tool);
1610 if (vstream->proto == SalProtoRtpSavp) {
1611 const SalStreamDescription *local_st_desc=sal_media_description_find_stream(call->localdesc,
1612 SalProtoRtpSavp,SalVideo);
1614 video_stream_enable_strp(
1616 vstream->crypto[0].algo,
1617 local_st_desc->crypto[0].master_key,
1618 vstream->crypto[0].master_key
1620 call->videostream_encrypted=TRUE;
1622 call->videostream_encrypted=FALSE;
1624 }else ms_warning("No video stream accepted.");
1626 ms_warning("No valid video stream defined.");
1631 void linphone_call_start_media_streams(LinphoneCall *call, bool_t all_inputs_muted, bool_t send_ringbacktone){
1632 LinphoneCore *lc=call->core;
1634 call->current_params.audio_codec = NULL;
1635 call->current_params.video_codec = NULL;
1637 LinphoneAddress *me=linphone_core_get_primary_contact_parsed(lc);
1639 bool_t use_arc=linphone_core_adaptive_rate_control_enabled(lc);
1640 #ifdef VIDEO_ENABLED
1641 const SalStreamDescription *vstream=sal_media_description_find_stream(call->resultdesc,
1642 SalProtoRtpAvp,SalVideo);
1645 if ((call->audiostream == NULL) && (call->videostream == NULL)) {
1646 ms_fatal("start_media_stream() called without prior init !");
1649 cname=linphone_address_as_string_uri_only(me);
1651 #if defined(VIDEO_ENABLED)
1652 if (vstream!=NULL && vstream->dir!=SalStreamInactive && vstream->payloads!=NULL){
1653 /*when video is used, do not make adaptive rate control on audio, it is stupid.*/
1657 if (call->audiostream!=NULL) {
1658 linphone_call_start_audio_stream(call,cname,all_inputs_muted,send_ringbacktone,use_arc);
1660 call->current_params.has_video=FALSE;
1661 if (call->videostream!=NULL) {
1662 linphone_call_start_video_stream(call,cname,all_inputs_muted);
1665 call->all_muted=all_inputs_muted;
1666 call->playing_ringbacktone=send_ringbacktone;
1667 call->up_bw=linphone_core_get_upload_bandwidth(lc);
1669 if (call->params.media_encryption==LinphoneMediaEncryptionZRTP) {
1670 OrtpZrtpParams params;
1671 /*will be set later when zrtp is activated*/
1672 call->current_params.media_encryption=LinphoneMediaEncryptionNone;
1674 params.zid_file=lc->zrtp_secrets_cache;
1675 audio_stream_enable_zrtp(call->audiostream,¶ms);
1676 }else if (call->params.media_encryption==LinphoneMediaEncryptionSRTP){
1677 call->current_params.media_encryption=linphone_call_are_all_streams_encrypted(call) ?
1678 LinphoneMediaEncryptionSRTP : LinphoneMediaEncryptionNone;
1681 /*also reflect the change if the "wished" params, in order to avoid to propose SAVP or video again
1682 * further in the call, for example during pause,resume, conferencing reINVITEs*/
1683 linphone_call_fix_call_parameters(call);
1684 if ((call->ice_session != NULL) && (ice_session_state(call->ice_session) != IS_Completed)) {
1685 ice_session_start_connectivity_checks(call->ice_session);
1691 linphone_address_destroy(me);
1694 void linphone_call_start_media_streams_for_ice_gathering(LinphoneCall *call){
1695 audio_stream_prepare_sound(call->audiostream, NULL, NULL);
1696 #ifdef VIDEO_ENABLED
1697 if (call->videostream) {
1698 video_stream_prepare_video(call->videostream);
1703 void linphone_call_stop_media_streams_for_ice_gathering(LinphoneCall *call){
1704 audio_stream_unprepare_sound(call->audiostream);
1705 #ifdef VIDEO_ENABLED
1706 if (call->videostream) {
1707 video_stream_unprepare_video(call->videostream);
1712 void linphone_call_update_crypto_parameters(LinphoneCall *call, SalMediaDescription *old_md, SalMediaDescription *new_md) {
1713 SalStreamDescription *old_stream;
1714 SalStreamDescription *new_stream;
1717 old_stream = sal_media_description_find_stream(old_md, SalProtoRtpSavp, SalAudio);
1718 new_stream = sal_media_description_find_stream(new_md, SalProtoRtpSavp, SalAudio);
1719 if (old_stream && new_stream) {
1720 const SalStreamDescription *local_st_desc = sal_media_description_find_stream(call->localdesc, SalProtoRtpSavp, SalAudio);
1721 if (local_st_desc) {
1722 int crypto_idx = find_crypto_index_from_tag(local_st_desc->crypto, new_stream->crypto_local_tag);
1723 if (crypto_idx >= 0) {
1724 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);
1725 call->audiostream_encrypted = TRUE;
1727 ms_warning("Failed to find local crypto algo with tag: %d", new_stream->crypto_local_tag);
1728 call->audiostream_encrypted = FALSE;
1730 for (i = 0; i < SAL_CRYPTO_ALGO_MAX; i++) {
1731 old_stream->crypto[i].tag = new_stream->crypto[i].tag;
1732 old_stream->crypto[i].algo = new_stream->crypto[i].algo;
1733 strncpy(old_stream->crypto[i].master_key, new_stream->crypto[i].master_key, sizeof(old_stream->crypto[i].master_key) - 1);
1738 #ifdef VIDEO_ENABLED
1739 old_stream = sal_media_description_find_stream(old_md, SalProtoRtpSavp, SalVideo);
1740 new_stream = sal_media_description_find_stream(new_md, SalProtoRtpSavp, SalVideo);
1741 if (old_stream && new_stream) {
1742 const SalStreamDescription *local_st_desc = sal_media_description_find_stream(call->localdesc, SalProtoRtpSavp, SalVideo);
1743 if (local_st_desc) {
1744 int crypto_idx = find_crypto_index_from_tag(local_st_desc->crypto, new_stream->crypto_local_tag);
1745 if (crypto_idx >= 0) {
1746 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);
1747 call->videostream_encrypted = TRUE;
1749 ms_warning("Failed to find local crypto algo with tag: %d", new_stream->crypto_local_tag);
1750 call->videostream_encrypted = FALSE;
1752 for (i = 0; i < SAL_CRYPTO_ALGO_MAX; i++) {
1753 old_stream->crypto[i].tag = new_stream->crypto[i].tag;
1754 old_stream->crypto[i].algo = new_stream->crypto[i].algo;
1755 strncpy(old_stream->crypto[i].master_key, new_stream->crypto[i].master_key, sizeof(old_stream->crypto[i].master_key) - 1);
1762 void linphone_call_update_remote_session_id_and_ver(LinphoneCall *call) {
1763 SalMediaDescription *remote_desc = sal_call_get_remote_media_description(call->op);
1765 call->remote_session_id = remote_desc->session_id;
1766 call->remote_session_ver = remote_desc->session_ver;
1770 void linphone_call_delete_ice_session(LinphoneCall *call){
1771 if (call->ice_session != NULL) {
1772 ice_session_destroy(call->ice_session);
1773 call->ice_session = NULL;
1774 if (call->audiostream != NULL) call->audiostream->ms.ice_check_list = NULL;
1775 if (call->videostream != NULL) call->videostream->ms.ice_check_list = NULL;
1776 call->stats[LINPHONE_CALL_STATS_AUDIO].ice_state = LinphoneIceStateNotActivated;
1777 call->stats[LINPHONE_CALL_STATS_VIDEO].ice_state = LinphoneIceStateNotActivated;
1782 void linphone_call_delete_upnp_session(LinphoneCall *call){
1783 if(call->upnp_session!=NULL) {
1784 linphone_upnp_session_destroy(call->upnp_session);
1785 call->upnp_session=NULL;
1790 static void linphone_call_log_fill_stats(LinphoneCallLog *log, AudioStream *st){
1791 audio_stream_get_local_rtp_stats (st,&log->local_stats);
1792 log->quality=audio_stream_get_average_quality_rating(st);
1795 void linphone_call_stop_audio_stream(LinphoneCall *call) {
1796 if (call->audiostream!=NULL) {
1797 rtp_session_unregister_event_queue(call->audiostream->ms.session,call->audiostream_app_evq);
1798 ortp_ev_queue_flush(call->audiostream_app_evq);
1799 ortp_ev_queue_destroy(call->audiostream_app_evq);
1800 call->audiostream_app_evq=NULL;
1802 if (call->audiostream->ec){
1803 const char *state_str=NULL;
1804 ms_filter_call_method(call->audiostream->ec,MS_ECHO_CANCELLER_GET_STATE_STRING,&state_str);
1806 ms_message("Writing echo canceler state, %i bytes",(int)strlen(state_str));
1807 lp_config_set_string(call->core->config,"sound","ec_state",state_str);
1810 linphone_call_log_fill_stats (call->log,call->audiostream);
1811 if (call->endpoint){
1812 linphone_call_remove_from_conf(call);
1814 audio_stream_stop(call->audiostream);
1815 call->audiostream=NULL;
1819 void linphone_call_stop_video_stream(LinphoneCall *call) {
1820 #ifdef VIDEO_ENABLED
1821 if (call->videostream!=NULL){
1822 rtp_session_unregister_event_queue(call->videostream->ms.session,call->videostream_app_evq);
1823 ortp_ev_queue_flush(call->videostream_app_evq);
1824 ortp_ev_queue_destroy(call->videostream_app_evq);
1825 call->videostream_app_evq=NULL;
1826 video_stream_stop(call->videostream);
1827 call->videostream=NULL;
1832 void linphone_call_stop_media_streams(LinphoneCall *call){
1833 linphone_call_stop_audio_stream(call);
1834 linphone_call_stop_video_stream(call);
1835 ms_event_queue_skip(call->core->msevq);
1837 if (call->audio_profile){
1838 rtp_profile_clear_all(call->audio_profile);
1839 rtp_profile_destroy(call->audio_profile);
1840 call->audio_profile=NULL;
1842 if (call->video_profile){
1843 rtp_profile_clear_all(call->video_profile);
1844 rtp_profile_destroy(call->video_profile);
1845 call->video_profile=NULL;
1851 void linphone_call_enable_echo_cancellation(LinphoneCall *call, bool_t enable) {
1852 if (call!=NULL && call->audiostream!=NULL && call->audiostream->ec){
1853 bool_t bypass_mode = !enable;
1854 ms_filter_call_method(call->audiostream->ec,MS_ECHO_CANCELLER_SET_BYPASS_MODE,&bypass_mode);
1857 bool_t linphone_call_echo_cancellation_enabled(LinphoneCall *call) {
1858 if (call!=NULL && call->audiostream!=NULL && call->audiostream->ec){
1860 ms_filter_call_method(call->audiostream->ec,MS_ECHO_CANCELLER_GET_BYPASS_MODE,&val);
1863 return linphone_core_echo_cancellation_enabled(call->core);
1867 void linphone_call_enable_echo_limiter(LinphoneCall *call, bool_t val){
1868 if (call!=NULL && call->audiostream!=NULL ) {
1870 const char *type=lp_config_get_string(call->core->config,"sound","el_type","mic");
1871 if (strcasecmp(type,"mic")==0)
1872 audio_stream_enable_echo_limiter(call->audiostream,ELControlMic);
1873 else if (strcasecmp(type,"full")==0)
1874 audio_stream_enable_echo_limiter(call->audiostream,ELControlFull);
1876 audio_stream_enable_echo_limiter(call->audiostream,ELInactive);
1881 bool_t linphone_call_echo_limiter_enabled(const LinphoneCall *call){
1882 if (call!=NULL && call->audiostream!=NULL ){
1883 return call->audiostream->el_type !=ELInactive ;
1885 return linphone_core_echo_limiter_enabled(call->core);
1890 * @addtogroup call_misc
1895 * Returns the measured sound volume played locally (received from remote).
1896 * It is expressed in dbm0.
1898 float linphone_call_get_play_volume(LinphoneCall *call){
1899 AudioStream *st=call->audiostream;
1900 if (st && st->volrecv){
1902 ms_filter_call_method(st->volrecv,MS_VOLUME_GET,&vol);
1906 return LINPHONE_VOLUME_DB_LOWEST;
1910 * Returns the measured sound volume recorded locally (sent to remote).
1911 * It is expressed in dbm0.
1913 float linphone_call_get_record_volume(LinphoneCall *call){
1914 AudioStream *st=call->audiostream;
1915 if (st && st->volsend && !call->audio_muted && call->state==LinphoneCallStreamsRunning){
1917 ms_filter_call_method(st->volsend,MS_VOLUME_GET,&vol);
1921 return LINPHONE_VOLUME_DB_LOWEST;
1925 * Obtain real-time quality rating of the call
1927 * Based on local RTP statistics and RTCP feedback, a quality rating is computed and updated
1928 * during all the duration of the call. This function returns its value at the time of the function call.
1929 * It is expected that the rating is updated at least every 5 seconds or so.
1930 * The rating is a floating point number comprised between 0 and 5.
1932 * 4-5 = good quality <br>
1933 * 3-4 = average quality <br>
1934 * 2-3 = poor quality <br>
1935 * 1-2 = very poor quality <br>
1936 * 0-1 = can't be worse, mostly unusable <br>
1938 * @returns The function returns -1 if no quality measurement is available, for example if no
1939 * active audio stream exist. Otherwise it returns the quality rating.
1941 float linphone_call_get_current_quality(LinphoneCall *call){
1942 if (call->audiostream){
1943 return audio_stream_get_quality_rating(call->audiostream);
1949 * Returns call quality averaged over all the duration of the call.
1951 * See linphone_call_get_current_quality() for more details about quality measurement.
1953 float linphone_call_get_average_quality(LinphoneCall *call){
1954 if (call->audiostream){
1955 return audio_stream_get_average_quality_rating(call->audiostream);
1961 * Access last known statistics for audio stream, for a given call.
1963 const LinphoneCallStats *linphone_call_get_audio_stats(const LinphoneCall *call) {
1964 return &call->stats[LINPHONE_CALL_STATS_AUDIO];
1968 * Access last known statistics for video stream, for a given call.
1970 const LinphoneCallStats *linphone_call_get_video_stats(const LinphoneCall *call) {
1971 return &call->stats[LINPHONE_CALL_STATS_VIDEO];
1979 static void report_bandwidth(LinphoneCall *call, RtpSession *as, RtpSession *vs){
1980 call->stats[LINPHONE_CALL_STATS_AUDIO].download_bandwidth=(as!=NULL) ? (rtp_session_compute_recv_bandwidth(as)*1e-3) : 0;
1981 call->stats[LINPHONE_CALL_STATS_AUDIO].upload_bandwidth=(as!=NULL) ? (rtp_session_compute_send_bandwidth(as)*1e-3) : 0;
1982 call->stats[LINPHONE_CALL_STATS_VIDEO].download_bandwidth=(vs!=NULL) ? (rtp_session_compute_recv_bandwidth(vs)*1e-3) : 0;
1983 call->stats[LINPHONE_CALL_STATS_VIDEO].upload_bandwidth=(vs!=NULL) ? (rtp_session_compute_send_bandwidth(vs)*1e-3) : 0;
1984 ms_message("bandwidth usage: audio=[d=%.1f,u=%.1f] video=[d=%.1f,u=%.1f] kbit/sec",
1985 call->stats[LINPHONE_CALL_STATS_AUDIO].download_bandwidth,
1986 call->stats[LINPHONE_CALL_STATS_AUDIO].upload_bandwidth ,
1987 call->stats[LINPHONE_CALL_STATS_VIDEO].download_bandwidth,
1988 call->stats[LINPHONE_CALL_STATS_VIDEO].upload_bandwidth
1992 static void linphone_core_disconnected(LinphoneCore *lc, LinphoneCall *call){
1996 from = linphone_call_get_remote_address_as_string(call);
1999 snprintf(temp,sizeof(temp),"Remote end %s seems to have disconnected, the call is going to be closed.",from);
2004 snprintf(temp,sizeof(temp),"Remote end seems to have disconnected, the call is going to be closed.");
2006 if (lc->vtable.display_warning!=NULL)
2007 lc->vtable.display_warning(lc,temp);
2008 linphone_core_terminate_call(lc,call);
2011 static void handle_ice_events(LinphoneCall *call, OrtpEvent *ev){
2012 OrtpEventType evt=ortp_event_get_type(ev);
2013 OrtpEventData *evd=ortp_event_get_data(ev);
2016 if (evt == ORTP_EVENT_ICE_SESSION_PROCESSING_FINISHED) {
2017 switch (ice_session_state(call->ice_session)) {
2019 ice_session_select_candidates(call->ice_session);
2020 if (ice_session_role(call->ice_session) == IR_Controlling) {
2021 linphone_core_update_call(call->core, call, &call->current_params);
2025 if (ice_session_has_completed_check_list(call->ice_session) == TRUE) {
2026 ice_session_select_candidates(call->ice_session);
2027 if (ice_session_role(call->ice_session) == IR_Controlling) {
2028 /* At least one ICE session has succeeded, so perform a call update. */
2029 linphone_core_update_call(call->core, call, &call->current_params);
2036 linphone_core_update_ice_state_in_call_stats(call);
2037 } else if (evt == ORTP_EVENT_ICE_GATHERING_FINISHED) {
2039 if (evd->info.ice_processing_successful==TRUE) {
2040 ice_session_compute_candidates_foundations(call->ice_session);
2041 ice_session_eliminate_redundant_candidates(call->ice_session);
2042 ice_session_choose_default_candidates(call->ice_session);
2043 ping_time = ice_session_average_gathering_round_trip_time(call->ice_session);
2044 if (ping_time >=0) {
2045 call->ping_time=ping_time;
2048 ms_warning("No STUN answer from [%s], disabling ICE",linphone_core_get_stun_server(call->core));
2049 linphone_call_delete_ice_session(call);
2051 switch (call->state) {
2052 case LinphoneCallUpdating:
2053 linphone_core_start_update_call(call->core, call);
2055 case LinphoneCallUpdatedByRemote:
2056 linphone_core_start_accept_call_update(call->core, call);
2058 case LinphoneCallOutgoingInit:
2059 linphone_call_stop_media_streams_for_ice_gathering(call);
2060 linphone_core_proceed_with_invite_if_ready(call->core, call, NULL);
2062 case LinphoneCallIdle:
2063 linphone_call_stop_media_streams_for_ice_gathering(call);
2064 linphone_core_notify_incoming_call(call->core, call);
2069 } else if (evt == ORTP_EVENT_ICE_LOSING_PAIRS_COMPLETED) {
2070 linphone_core_start_accept_call_update(call->core, call);
2071 linphone_core_update_ice_state_in_call_stats(call);
2072 } else if (evt == ORTP_EVENT_ICE_RESTART_NEEDED) {
2073 ice_session_restart(call->ice_session);
2074 ice_session_set_role(call->ice_session, IR_Controlling);
2075 linphone_core_update_call(call->core, call, &call->current_params);
2079 void linphone_call_background_tasks(LinphoneCall *call, bool_t one_second_elapsed){
2080 LinphoneCore* lc = call->core;
2081 int disconnect_timeout = linphone_core_get_nortp_timeout(call->core);
2082 bool_t disconnected=FALSE;
2084 if (call->state==LinphoneCallStreamsRunning && one_second_elapsed){
2085 RtpSession *as=NULL,*vs=NULL;
2086 float audio_load=0, video_load=0;
2087 if (call->audiostream!=NULL){
2088 as=call->audiostream->ms.session;
2089 if (call->audiostream->ms.ticker)
2090 audio_load=ms_ticker_get_average_load(call->audiostream->ms.ticker);
2092 if (call->videostream!=NULL){
2093 if (call->videostream->ms.ticker)
2094 video_load=ms_ticker_get_average_load(call->videostream->ms.ticker);
2095 vs=call->videostream->ms.session;
2097 report_bandwidth(call,as,vs);
2098 ms_message("Thread processing load: audio=%f\tvideo=%f",audio_load,video_load);
2102 linphone_upnp_call_process(call);
2105 #ifdef VIDEO_ENABLED
2106 if (call->videostream!=NULL) {
2109 /* Ensure there is no dangling ICE check list. */
2110 if (call->ice_session == NULL) call->videostream->ms.ice_check_list = NULL;
2112 // Beware that the application queue should not depend on treatments fron the
2113 // mediastreamer queue.
2114 video_stream_iterate(call->videostream);
2116 while (call->videostream_app_evq && (NULL != (ev=ortp_ev_queue_get(call->videostream_app_evq)))){
2117 OrtpEventType evt=ortp_event_get_type(ev);
2118 OrtpEventData *evd=ortp_event_get_data(ev);
2119 if (evt == ORTP_EVENT_ZRTP_ENCRYPTION_CHANGED){
2120 linphone_call_videostream_encryption_changed(call, evd->info.zrtp_stream_encrypted);
2121 } else if (evt == ORTP_EVENT_RTCP_PACKET_RECEIVED) {
2122 call->stats[LINPHONE_CALL_STATS_VIDEO].round_trip_delay = rtp_session_get_round_trip_propagation(call->videostream->ms.session);
2123 if(call->stats[LINPHONE_CALL_STATS_VIDEO].received_rtcp != NULL)
2124 freemsg(call->stats[LINPHONE_CALL_STATS_VIDEO].received_rtcp);
2125 call->stats[LINPHONE_CALL_STATS_VIDEO].received_rtcp = evd->packet;
2127 if (lc->vtable.call_stats_updated)
2128 lc->vtable.call_stats_updated(lc, call, &call->stats[LINPHONE_CALL_STATS_VIDEO]);
2129 } else if (evt == ORTP_EVENT_RTCP_PACKET_EMITTED) {
2130 memcpy(&call->stats[LINPHONE_CALL_STATS_VIDEO].jitter_stats, rtp_session_get_jitter_stats(call->videostream->ms.session), sizeof(jitter_stats_t));
2131 if(call->stats[LINPHONE_CALL_STATS_VIDEO].sent_rtcp != NULL)
2132 freemsg(call->stats[LINPHONE_CALL_STATS_VIDEO].sent_rtcp);
2133 call->stats[LINPHONE_CALL_STATS_VIDEO].sent_rtcp = evd->packet;
2135 if (lc->vtable.call_stats_updated)
2136 lc->vtable.call_stats_updated(lc, call, &call->stats[LINPHONE_CALL_STATS_VIDEO]);
2137 } else if ((evt == ORTP_EVENT_ICE_SESSION_PROCESSING_FINISHED) || (evt == ORTP_EVENT_ICE_GATHERING_FINISHED)
2138 || (evt == ORTP_EVENT_ICE_LOSING_PAIRS_COMPLETED) || (evt == ORTP_EVENT_ICE_RESTART_NEEDED)) {
2139 handle_ice_events(call, ev);
2141 ortp_event_destroy(ev);
2145 if (call->audiostream!=NULL) {
2148 /* Ensure there is no dangling ICE check list. */
2149 if (call->ice_session == NULL) call->audiostream->ms.ice_check_list = NULL;
2151 // Beware that the application queue should not depend on treatments fron the
2152 // mediastreamer queue.
2153 audio_stream_iterate(call->audiostream);
2155 while (call->audiostream_app_evq && (NULL != (ev=ortp_ev_queue_get(call->audiostream_app_evq)))){
2156 OrtpEventType evt=ortp_event_get_type(ev);
2157 OrtpEventData *evd=ortp_event_get_data(ev);
2158 if (evt == ORTP_EVENT_ZRTP_ENCRYPTION_CHANGED){
2159 linphone_call_audiostream_encryption_changed(call, evd->info.zrtp_stream_encrypted);
2160 } else if (evt == ORTP_EVENT_ZRTP_SAS_READY) {
2161 linphone_call_audiostream_auth_token_ready(call, evd->info.zrtp_sas.sas, evd->info.zrtp_sas.verified);
2162 } else if (evt == ORTP_EVENT_RTCP_PACKET_RECEIVED) {
2163 call->stats[LINPHONE_CALL_STATS_AUDIO].round_trip_delay = rtp_session_get_round_trip_propagation(call->audiostream->ms.session);
2164 if(call->stats[LINPHONE_CALL_STATS_AUDIO].received_rtcp != NULL)
2165 freemsg(call->stats[LINPHONE_CALL_STATS_AUDIO].received_rtcp);
2166 call->stats[LINPHONE_CALL_STATS_AUDIO].received_rtcp = evd->packet;
2168 if (lc->vtable.call_stats_updated)
2169 lc->vtable.call_stats_updated(lc, call, &call->stats[LINPHONE_CALL_STATS_AUDIO]);
2170 } else if (evt == ORTP_EVENT_RTCP_PACKET_EMITTED) {
2171 memcpy(&call->stats[LINPHONE_CALL_STATS_AUDIO].jitter_stats, rtp_session_get_jitter_stats(call->audiostream->ms.session), sizeof(jitter_stats_t));
2172 if(call->stats[LINPHONE_CALL_STATS_AUDIO].sent_rtcp != NULL)
2173 freemsg(call->stats[LINPHONE_CALL_STATS_AUDIO].sent_rtcp);
2174 call->stats[LINPHONE_CALL_STATS_AUDIO].sent_rtcp = evd->packet;
2176 if (lc->vtable.call_stats_updated)
2177 lc->vtable.call_stats_updated(lc, call, &call->stats[LINPHONE_CALL_STATS_AUDIO]);
2178 } else if ((evt == ORTP_EVENT_ICE_SESSION_PROCESSING_FINISHED) || (evt == ORTP_EVENT_ICE_GATHERING_FINISHED)
2179 || (evt == ORTP_EVENT_ICE_LOSING_PAIRS_COMPLETED) || (evt == ORTP_EVENT_ICE_RESTART_NEEDED)) {
2180 handle_ice_events(call, ev);
2181 } else if (evt==ORTP_EVENT_TELEPHONE_EVENT){
2182 linphone_core_dtmf_received(lc,evd->info.telephone_event);
2184 ortp_event_destroy(ev);
2187 if (call->state==LinphoneCallStreamsRunning && one_second_elapsed && call->audiostream!=NULL && disconnect_timeout>0 )
2188 disconnected=!audio_stream_alive(call->audiostream,disconnect_timeout);
2190 linphone_core_disconnected(call->core,call);
2193 void linphone_call_log_completed(LinphoneCall *call){
2194 LinphoneCore *lc=call->core;
2196 call->log->duration=time(NULL)-call->start_time;
2198 if (call->log->status==LinphoneCallMissed){
2201 info=ortp_strdup_printf(ngettext("You have missed %i call.",
2202 "You have missed %i calls.", lc->missed_calls),
2204 if (lc->vtable.display_status!=NULL)
2205 lc->vtable.display_status(lc,info);
2208 lc->call_logs=ms_list_prepend(lc->call_logs,(void *)call->log);
2209 if (ms_list_size(lc->call_logs)>lc->max_call_logs){
2210 MSList *elem,*prevelem=NULL;
2211 /*find the last element*/
2212 for(elem=lc->call_logs;elem!=NULL;elem=elem->next){
2216 linphone_call_log_destroy((LinphoneCallLog*)elem->data);
2217 lc->call_logs=ms_list_remove_link(lc->call_logs,elem);
2219 if (lc->vtable.call_log_updated!=NULL){
2220 lc->vtable.call_log_updated(lc,call->log);
2222 call_logs_write_to_config_file(lc);
2225 LinphoneCallState linphone_call_get_transfer_state(LinphoneCall *call) {
2226 return call->transfer_state;
2229 void linphone_call_set_transfer_state(LinphoneCall* call, LinphoneCallState state) {
2230 if (state != call->transfer_state) {
2231 LinphoneCore* lc = call->core;
2232 call->transfer_state = state;
2233 if (lc->vtable.transfer_state_changed)
2234 lc->vtable.transfer_state_changed(lc, call, state);
2239 * Returns true if the call is part of the conference.
2240 * @ingroup conferencing
2242 bool_t linphone_call_is_in_conference(const LinphoneCall *call) {
2243 return call->params.in_conference;
2248 * Perform a zoom of the video displayed during a call.
2249 * @param call the call.
2250 * @param zoom_factor a floating point number describing the zoom factor. A value 1.0 corresponds to no zoom applied.
2251 * @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.
2252 * @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.
2254 * 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.
2256 void linphone_call_zoom_video(LinphoneCall* call, float zoom_factor, float* cx, float* cy) {
2257 VideoStream* vstream = call->videostream;
2258 if (vstream && vstream->output) {
2261 if (zoom_factor < 1)
2263 float halfsize = 0.5 * 1.0 / zoom_factor;
2265 if ((*cx - halfsize) < 0)
2267 if ((*cx + halfsize) > 1)
2269 if ((*cy - halfsize) < 0)
2271 if ((*cy + halfsize) > 1)
2274 zoom[0] = zoom_factor;
2277 ms_filter_call_method(vstream->output, MS_VIDEO_DISPLAY_ZOOM, &zoom);
2278 }else ms_warning("Could not apply zoom: video output wasn't activated.");