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 the far end's sip contact as a string, if available.
904 const char *linphone_call_get_remote_contact(LinphoneCall *call){
906 return sal_op_get_remote_contact(call->op);
912 * Returns true if this calls has received a transfer that has not been
914 * Pending transfers are executed when this call is being paused or closed,
915 * locally or by remote endpoint.
916 * If the call is already paused while receiving the transfer request, the
917 * transfer immediately occurs.
919 bool_t linphone_call_has_transfer_pending(const LinphoneCall *call){
920 return call->refer_pending;
924 * Returns call's duration in seconds.
926 int linphone_call_get_duration(const LinphoneCall *call){
927 if (call->media_start_time==0) return 0;
928 return time(NULL)-call->media_start_time;
932 * Returns the call object this call is replacing, if any.
933 * Call replacement can occur during call transfers.
934 * By default, the core automatically terminates the replaced call and accept the new one.
935 * This function allows the application to know whether a new incoming call is a one that replaces another one.
937 LinphoneCall *linphone_call_get_replaced_call(LinphoneCall *call){
938 SalOp *op=sal_call_get_replaces(call->op);
940 return (LinphoneCall*)sal_op_get_user_pointer(op);
946 * Indicate whether camera input should be sent to remote end.
948 void linphone_call_enable_camera (LinphoneCall *call, bool_t enable){
950 if (call->videostream!=NULL && call->videostream->ms.ticker!=NULL){
951 LinphoneCore *lc=call->core;
952 MSWebCam *nowebcam=get_nowebcam_device();
953 if (call->camera_active!=enable && lc->video_conf.device!=nowebcam){
954 video_stream_change_camera(call->videostream,
955 enable ? lc->video_conf.device : nowebcam);
958 call->camera_active=enable;
963 * Take a photo of currently received video and write it into a jpeg file.
965 int linphone_call_take_video_snapshot(LinphoneCall *call, const char *file){
967 if (call->videostream!=NULL && call->videostream->jpegwriter!=NULL){
968 return ms_filter_call_method(call->videostream->jpegwriter,MS_JPEG_WRITER_TAKE_SNAPSHOT,(void*)file);
970 ms_warning("Cannot take snapshot: no currently running video stream on this call.");
977 * Returns TRUE if camera pictures are sent to the remote party.
979 bool_t linphone_call_camera_enabled (const LinphoneCall *call){
980 return call->camera_active;
984 * Enable video stream.
986 void linphone_call_params_enable_video(LinphoneCallParams *cp, bool_t enabled){
987 cp->has_video=enabled;
990 const PayloadType* linphone_call_params_get_used_audio_codec(const LinphoneCallParams *cp) {
991 return cp->audio_codec;
994 const PayloadType* linphone_call_params_get_used_video_codec(const LinphoneCallParams *cp) {
995 return cp->video_codec;
999 * @ingroup call_control
1000 * Use to know if this call has been configured in low bandwidth mode.
1001 * This mode can be automatically discovered thanks to a stun server when activate_edge_workarounds=1 in section [net] of configuration file.
1002 * An application that would have reliable way to know network capacity may not use activate_edge_workarounds=1 but instead manually configure
1003 * low bandwidth mode with linphone_call_params_enable_low_bandwidth().
1004 * <br> When enabled, this param may transform a call request with video in audio only mode.
1005 * @return TRUE if low bandwidth has been configured/detected
1007 bool_t linphone_call_params_low_bandwidth_enabled(const LinphoneCallParams *cp) {
1008 return cp->low_bandwidth;
1012 * @ingroup call_control
1013 * Indicate low bandwith mode.
1014 * 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
1015 * 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
1016 * that it is achievable by the codec selected after SDP handshake. Video is automatically disabled.
1019 void linphone_call_params_enable_low_bandwidth(LinphoneCallParams *cp, bool_t enabled){
1020 cp->low_bandwidth=enabled;
1024 * Returns whether video is enabled.
1026 bool_t linphone_call_params_video_enabled(const LinphoneCallParams *cp){
1027 return cp->has_video;
1030 enum LinphoneMediaEncryption linphone_call_params_get_media_encryption(const LinphoneCallParams *cp) {
1031 return cp->media_encryption;
1034 void linphone_call_params_set_media_encryption(LinphoneCallParams *cp, enum LinphoneMediaEncryption e) {
1035 cp->media_encryption = e;
1040 * Enable sending of real early media (during outgoing calls).
1042 void linphone_call_params_enable_early_media_sending(LinphoneCallParams *cp, bool_t enabled){
1043 cp->real_early_media=enabled;
1046 bool_t linphone_call_params_early_media_sending_enabled(const LinphoneCallParams *cp){
1047 return cp->real_early_media;
1051 * Returns true if the call is part of the locally managed conference.
1053 bool_t linphone_call_params_local_conference_mode(const LinphoneCallParams *cp){
1054 return cp->in_conference;
1058 * Refine bandwidth settings for this call by setting a bandwidth limit for audio streams.
1059 * As a consequence, codecs whose bitrates are not compatible with this limit won't be used.
1061 void linphone_call_params_set_audio_bandwidth_limit(LinphoneCallParams *cp, int bandwidth){
1062 cp->audio_bw=bandwidth;
1065 #ifdef VIDEO_ENABLED
1067 * Request remote side to send us a Video Fast Update.
1069 void linphone_call_send_vfu_request(LinphoneCall *call)
1071 if (LinphoneCallStreamsRunning == linphone_call_get_state(call))
1072 sal_call_send_vfu_request(call->op);
1079 LinphoneCallParams * linphone_call_params_copy(const LinphoneCallParams *cp){
1080 LinphoneCallParams *ncp=ms_new0(LinphoneCallParams,1);
1081 memcpy(ncp,cp,sizeof(LinphoneCallParams));
1088 void linphone_call_params_destroy(LinphoneCallParams *p){
1097 #ifdef TEST_EXT_RENDERER
1098 static void rendercb(void *data, const MSPicture *local, const MSPicture *remote){
1099 ms_message("rendercb, local buffer=%p, remote buffer=%p",
1100 local ? local->planes[0] : NULL, remote? remote->planes[0] : NULL);
1104 #ifdef VIDEO_ENABLED
1105 static void video_stream_event_cb(void *user_pointer, const MSFilter *f, const unsigned int event_id, const void *args){
1106 LinphoneCall* call = (LinphoneCall*) user_pointer;
1107 ms_warning("In linphonecall.c: video_stream_event_cb");
1109 case MS_VIDEO_DECODER_DECODING_ERRORS:
1110 ms_warning("Case is MS_VIDEO_DECODER_DECODING_ERRORS");
1111 linphone_call_send_vfu_request(call);
1113 case MS_VIDEO_DECODER_FIRST_IMAGE_DECODED:
1114 ms_message("First video frame decoded successfully");
1115 if (call->nextVideoFrameDecoded._func != NULL)
1116 call->nextVideoFrameDecoded._func(call, call->nextVideoFrameDecoded._user_data);
1119 ms_warning("Unhandled event %i", event_id);
1125 void linphone_call_set_next_video_frame_decoded_callback(LinphoneCall *call, LinphoneCallCbFunc cb, void* user_data) {
1126 call->nextVideoFrameDecoded._func = cb;
1127 call->nextVideoFrameDecoded._user_data = user_data;
1128 #ifdef VIDEO_ENABLED
1129 ms_filter_call_method_noarg(call->videostream->ms.decoder, MS_VIDEO_DECODER_RESET_FIRST_IMAGE_NOTIFICATION);
1133 void linphone_call_init_audio_stream(LinphoneCall *call){
1134 LinphoneCore *lc=call->core;
1135 AudioStream *audiostream;
1138 if (call->audiostream != NULL) return;
1139 call->audiostream=audiostream=audio_stream_new(call->audio_port,call->audio_port+1,linphone_core_ipv6_enabled(lc));
1140 dscp=linphone_core_get_audio_dscp(lc);
1142 audio_stream_set_dscp(audiostream,dscp);
1143 if (linphone_core_echo_limiter_enabled(lc)){
1144 const char *type=lp_config_get_string(lc->config,"sound","el_type","mic");
1145 if (strcasecmp(type,"mic")==0)
1146 audio_stream_enable_echo_limiter(audiostream,ELControlMic);
1147 else if (strcasecmp(type,"full")==0)
1148 audio_stream_enable_echo_limiter(audiostream,ELControlFull);
1150 audio_stream_enable_gain_control(audiostream,TRUE);
1151 if (linphone_core_echo_cancellation_enabled(lc)){
1152 int len,delay,framesize;
1153 const char *statestr=lp_config_get_string(lc->config,"sound","ec_state",NULL);
1154 len=lp_config_get_int(lc->config,"sound","ec_tail_len",0);
1155 delay=lp_config_get_int(lc->config,"sound","ec_delay",0);
1156 framesize=lp_config_get_int(lc->config,"sound","ec_framesize",0);
1157 audio_stream_set_echo_canceller_params(audiostream,len,delay,framesize);
1158 if (statestr && audiostream->ec){
1159 ms_filter_call_method(audiostream->ec,MS_ECHO_CANCELLER_SET_STATE_STRING,(void*)statestr);
1162 audio_stream_enable_automatic_gain_control(audiostream,linphone_core_agc_enabled(lc));
1164 int enabled=lp_config_get_int(lc->config,"sound","noisegate",0);
1165 audio_stream_enable_noise_gate(audiostream,enabled);
1168 audio_stream_set_features(audiostream,linphone_core_get_audio_features(lc));
1171 RtpTransport *artp=lc->rtptf->audio_rtp_func(lc->rtptf->audio_rtp_func_data, call->audio_port);
1172 RtpTransport *artcp=lc->rtptf->audio_rtcp_func(lc->rtptf->audio_rtcp_func_data, call->audio_port+1);
1173 rtp_session_set_transports(audiostream->ms.session,artp,artcp);
1175 if ((linphone_core_get_firewall_policy(lc) == LinphonePolicyUseIce) && (call->ice_session != NULL)){
1176 rtp_session_set_pktinfo(audiostream->ms.session, TRUE);
1177 rtp_session_set_symmetric_rtp(audiostream->ms.session, FALSE);
1178 if (ice_session_check_list(call->ice_session, 0) == NULL) {
1179 ice_session_add_check_list(call->ice_session, ice_check_list_new());
1181 audiostream->ms.ice_check_list = ice_session_check_list(call->ice_session, 0);
1182 ice_check_list_set_rtp_session(audiostream->ms.ice_check_list, audiostream->ms.session);
1185 call->audiostream_app_evq = ortp_ev_queue_new();
1186 rtp_session_register_event_queue(audiostream->ms.session,call->audiostream_app_evq);
1189 void linphone_call_init_video_stream(LinphoneCall *call){
1190 #ifdef VIDEO_ENABLED
1191 LinphoneCore *lc=call->core;
1193 if (!call->params.has_video) {
1194 linphone_call_stop_video_stream(call);
1197 if (call->videostream != NULL) return;
1198 if ((lc->video_conf.display || lc->video_conf.capture) && call->params.has_video){
1199 int video_recv_buf_size=lp_config_get_int(lc->config,"video","recv_buf_size",0);
1200 int dscp=linphone_core_get_video_dscp(lc);
1202 call->videostream=video_stream_new(call->video_port,call->video_port+1,linphone_core_ipv6_enabled(lc));
1204 video_stream_set_dscp(call->videostream,dscp);
1205 video_stream_enable_display_filter_auto_rotate(call->videostream, lp_config_get_int(lc->config,"video","display_filter_auto_rotate",0));
1206 if (video_recv_buf_size>0) rtp_session_set_recv_buf_size(call->videostream->ms.session,video_recv_buf_size);
1208 if( lc->video_conf.displaytype != NULL)
1209 video_stream_set_display_filter_name(call->videostream,lc->video_conf.displaytype);
1210 video_stream_set_event_callback(call->videostream,video_stream_event_cb, call);
1212 RtpTransport *vrtp=lc->rtptf->video_rtp_func(lc->rtptf->video_rtp_func_data, call->video_port);
1213 RtpTransport *vrtcp=lc->rtptf->video_rtcp_func(lc->rtptf->video_rtcp_func_data, call->video_port+1);
1214 rtp_session_set_transports(call->videostream->ms.session,vrtp,vrtcp);
1216 if ((linphone_core_get_firewall_policy(lc) == LinphonePolicyUseIce) && (call->ice_session != NULL)){
1217 rtp_session_set_pktinfo(call->videostream->ms.session, TRUE);
1218 rtp_session_set_symmetric_rtp(call->videostream->ms.session, FALSE);
1219 if (ice_session_check_list(call->ice_session, 1) == NULL) {
1220 ice_session_add_check_list(call->ice_session, ice_check_list_new());
1222 call->videostream->ms.ice_check_list = ice_session_check_list(call->ice_session, 1);
1223 ice_check_list_set_rtp_session(call->videostream->ms.ice_check_list, call->videostream->ms.session);
1225 call->videostream_app_evq = ortp_ev_queue_new();
1226 rtp_session_register_event_queue(call->videostream->ms.session,call->videostream_app_evq);
1227 #ifdef TEST_EXT_RENDERER
1228 video_stream_set_render_callback(call->videostream,rendercb,NULL);
1232 call->videostream=NULL;
1236 void linphone_call_init_media_streams(LinphoneCall *call){
1237 linphone_call_init_audio_stream(call);
1238 linphone_call_init_video_stream(call);
1242 static int dtmf_tab[16]={'0','1','2','3','4','5','6','7','8','9','*','#','A','B','C','D'};
1244 static void linphone_core_dtmf_received(LinphoneCore *lc, int dtmf){
1245 if (dtmf<0 || dtmf>15){
1246 ms_warning("Bad dtmf value %i",dtmf);
1249 if (lc->vtable.dtmf_received != NULL)
1250 lc->vtable.dtmf_received(lc, linphone_core_get_current_call(lc), dtmf_tab[dtmf]);
1253 static void parametrize_equalizer(LinphoneCore *lc, AudioStream *st){
1255 MSFilter *f=st->equalizer;
1256 int enabled=lp_config_get_int(lc->config,"sound","eq_active",0);
1257 const char *gains=lp_config_get_string(lc->config,"sound","eq_gains",NULL);
1258 ms_filter_call_method(f,MS_EQUALIZER_SET_ACTIVE,&enabled);
1264 if (sscanf(gains,"%f:%f:%f %n",&g.frequency,&g.gain,&g.width,&bytes)==3){
1265 ms_message("Read equalizer gains: %f(~%f) --> %f",g.frequency,g.width,g.gain);
1266 ms_filter_call_method(f,MS_EQUALIZER_SET_GAIN,&g);
1275 void _post_configure_audio_stream(AudioStream *st, LinphoneCore *lc, bool_t muted){
1276 float mic_gain=lc->sound_conf.soft_mic_lev;
1279 float ng_thres=lp_config_get_float(lc->config,"sound","ng_thres",0.05);
1280 float ng_floorgain=lp_config_get_float(lc->config,"sound","ng_floorgain",0);
1281 int dc_removal=lp_config_get_int(lc->config,"sound","dc_removal",0);
1284 linphone_core_set_mic_gain_db (lc, mic_gain);
1286 audio_stream_set_mic_gain(st,0);
1288 recv_gain = lc->sound_conf.soft_play_lev;
1289 if (recv_gain != 0) {
1290 linphone_core_set_playback_gain_db (lc,recv_gain);
1294 ms_filter_call_method(st->volsend,MS_VOLUME_REMOVE_DC,&dc_removal);
1295 float speed=lp_config_get_float(lc->config,"sound","el_speed",-1);
1296 thres=lp_config_get_float(lc->config,"sound","el_thres",-1);
1297 float force=lp_config_get_float(lc->config,"sound","el_force",-1);
1298 int sustain=lp_config_get_int(lc->config,"sound","el_sustain",-1);
1299 float transmit_thres=lp_config_get_float(lc->config,"sound","el_transmit_thres",-1);
1302 if (speed==-1) speed=0.03;
1303 if (force==-1) force=25;
1304 ms_filter_call_method(f,MS_VOLUME_SET_EA_SPEED,&speed);
1305 ms_filter_call_method(f,MS_VOLUME_SET_EA_FORCE,&force);
1307 ms_filter_call_method(f,MS_VOLUME_SET_EA_THRESHOLD,&thres);
1309 ms_filter_call_method(f,MS_VOLUME_SET_EA_SUSTAIN,&sustain);
1310 if (transmit_thres!=-1)
1311 ms_filter_call_method(f,MS_VOLUME_SET_EA_TRANSMIT_THRESHOLD,&transmit_thres);
1313 ms_filter_call_method(st->volsend,MS_VOLUME_SET_NOISE_GATE_THRESHOLD,&ng_thres);
1314 ms_filter_call_method(st->volsend,MS_VOLUME_SET_NOISE_GATE_FLOORGAIN,&ng_floorgain);
1317 /* parameters for a limited noise-gate effect, using echo limiter threshold */
1318 float floorgain = 1/pow(10,(mic_gain)/10);
1319 int spk_agc=lp_config_get_int(lc->config,"sound","speaker_agc_enabled",0);
1320 ms_filter_call_method(st->volrecv, MS_VOLUME_ENABLE_AGC, &spk_agc);
1321 ms_filter_call_method(st->volrecv,MS_VOLUME_SET_NOISE_GATE_THRESHOLD,&ng_thres);
1322 ms_filter_call_method(st->volrecv,MS_VOLUME_SET_NOISE_GATE_FLOORGAIN,&floorgain);
1324 parametrize_equalizer(lc,st);
1327 static void post_configure_audio_streams(LinphoneCall*call){
1328 AudioStream *st=call->audiostream;
1329 LinphoneCore *lc=call->core;
1330 _post_configure_audio_stream(st,lc,call->audio_muted);
1331 if (lc->vtable.dtmf_received!=NULL){
1332 /* replace by our default action*/
1333 audio_stream_play_received_dtmfs(call->audiostream,FALSE);
1334 /*rtp_session_signal_connect(call->audiostream->session,"telephone-event",(RtpCallback)linphone_core_dtmf_received,(unsigned long)lc);*/
1338 static RtpProfile *make_profile(LinphoneCall *call, const SalMediaDescription *md, const SalStreamDescription *desc, int *used_pt){
1341 RtpProfile *prof=rtp_profile_new("Call profile");
1344 LinphoneCore *lc=call->core;
1346 const LinphoneCallParams *params=&call->params;
1349 for(elem=desc->payloads;elem!=NULL;elem=elem->next){
1350 PayloadType *pt=(PayloadType*)elem->data;
1353 if ((pt->flags & PAYLOAD_TYPE_FLAG_CAN_SEND) && first) {
1354 if (desc->type==SalAudio){
1355 linphone_core_update_allocated_audio_bandwidth_in_call(call,pt);
1356 if (params->up_ptime)
1357 up_ptime=params->up_ptime;
1358 else up_ptime=linphone_core_get_upload_ptime(lc);
1360 *used_pt=payload_type_get_number(pt);
1363 if (desc->bandwidth>0) remote_bw=desc->bandwidth;
1364 else if (md->bandwidth>0) {
1365 /*case where b=AS is given globally, not per stream*/
1366 remote_bw=md->bandwidth;
1367 if (desc->type==SalVideo){
1368 remote_bw=get_video_bandwidth(remote_bw,call->audio_bw);
1372 if (desc->type==SalAudio){
1373 int audio_bw=call->audio_bw;
1375 if (params->up_bw< audio_bw)
1376 audio_bw=params->up_bw;
1378 bw=get_min_bandwidth(audio_bw,remote_bw);
1379 }else bw=get_min_bandwidth(get_video_bandwidth(linphone_core_get_upload_bandwidth (lc),call->audio_bw),remote_bw);
1380 if (bw>0) pt->normal_bitrate=bw*1000;
1381 else if (desc->type==SalAudio){
1382 pt->normal_bitrate=-1;
1385 up_ptime=desc->ptime;
1389 snprintf(tmp,sizeof(tmp),"ptime=%i",up_ptime);
1390 payload_type_append_send_fmtp(pt,tmp);
1392 number=payload_type_get_number(pt);
1393 if (rtp_profile_get_payload(prof,number)!=NULL){
1394 ms_warning("A payload type with number %i already exists in profile !",number);
1396 rtp_profile_set_payload(prof,number,pt);
1402 static void setup_ring_player(LinphoneCore *lc, LinphoneCall *call){
1403 int pause_time=3000;
1404 audio_stream_play(call->audiostream,lc->sound_conf.ringback_tone);
1405 ms_filter_call_method(call->audiostream->soundread,MS_FILE_PLAYER_LOOP,&pause_time);
1408 static bool_t linphone_call_sound_resources_available(LinphoneCall *call){
1409 LinphoneCore *lc=call->core;
1410 LinphoneCall *current=linphone_core_get_current_call(lc);
1411 return !linphone_core_is_in_conference(lc) &&
1412 (current==NULL || current==call);
1414 static int find_crypto_index_from_tag(const SalSrtpCryptoAlgo crypto[],unsigned char tag) {
1416 for(i=0; i<SAL_CRYPTO_ALGO_MAX; i++) {
1417 if (crypto[i].tag == tag) {
1423 static void linphone_call_start_audio_stream(LinphoneCall *call, const char *cname, bool_t muted, bool_t send_ringbacktone, bool_t use_arc){
1424 LinphoneCore *lc=call->core;
1426 char rtcp_tool[128]={0};
1427 snprintf(rtcp_tool,sizeof(rtcp_tool)-1,"%s-%s",linphone_core_get_user_agent_name(),linphone_core_get_user_agent_version());
1428 /* look for savp stream first */
1429 const SalStreamDescription *stream=sal_media_description_find_stream(call->resultdesc,
1430 SalProtoRtpSavp,SalAudio);
1431 /* no savp audio stream, use avp */
1433 stream=sal_media_description_find_stream(call->resultdesc,
1434 SalProtoRtpAvp,SalAudio);
1436 if (stream && stream->dir!=SalStreamInactive && stream->rtp_port!=0){
1437 MSSndCard *playcard=lc->sound_conf.lsd_card ?
1438 lc->sound_conf.lsd_card : lc->sound_conf.play_sndcard;
1439 MSSndCard *captcard=lc->sound_conf.capt_sndcard;
1440 const char *playfile=lc->play_file;
1441 const char *recfile=lc->rec_file;
1442 call->audio_profile=make_profile(call,call->resultdesc,stream,&used_pt);
1446 call->current_params.audio_codec = rtp_profile_get_payload(call->audio_profile, used_pt);
1447 if (playcard==NULL) {
1448 ms_warning("No card defined for playback !");
1450 if (captcard==NULL) {
1451 ms_warning("No card defined for capture !");
1453 /*Replace soundcard filters by inactive file players or recorders
1454 when placed in recvonly or sendonly mode*/
1455 if (stream->rtp_port==0 || stream->dir==SalStreamRecvOnly){
1458 }else if (stream->dir==SalStreamSendOnly){
1462 /*And we will eventually play "playfile" if set by the user*/
1465 if (send_ringbacktone){
1467 playfile=NULL;/* it is setup later*/
1469 /*if playfile are supplied don't use soundcards*/
1470 if (lc->use_files) {
1474 if (call->params.in_conference){
1475 /* first create the graph without soundcard resources*/
1476 captcard=playcard=NULL;
1478 if (!linphone_call_sound_resources_available(call)){
1479 ms_message("Sound resources are used by another call, not using soundcard.");
1480 captcard=playcard=NULL;
1482 use_ec=captcard==NULL ? FALSE : linphone_core_echo_cancellation_enabled(lc);
1483 if (playcard && stream->max_rate>0) ms_snd_card_set_preferred_sample_rate(playcard, stream->max_rate);
1484 if (captcard && stream->max_rate>0) ms_snd_card_set_preferred_sample_rate(captcard, stream->max_rate);
1485 audio_stream_enable_adaptive_bitrate_control(call->audiostream,use_arc);
1486 audio_stream_enable_adaptive_jittcomp(call->audiostream, linphone_core_audio_adaptive_jittcomp_enabled(lc));
1487 audio_stream_start_full(
1489 call->audio_profile,
1490 stream->rtp_addr[0]!='\0' ? stream->rtp_addr : call->resultdesc->addr,
1492 stream->rtcp_addr[0]!='\0' ? stream->rtcp_addr : call->resultdesc->addr,
1493 linphone_core_rtcp_enabled(lc) ? (stream->rtcp_port) : 0,
1495 linphone_core_get_audio_jittcomp(lc),
1502 post_configure_audio_streams(call);
1503 if (muted && !send_ringbacktone){
1504 audio_stream_set_mic_gain(call->audiostream,0);
1506 if (stream->dir==SalStreamSendOnly && playfile!=NULL){
1508 ms_filter_call_method(call->audiostream->soundread,MS_FILE_PLAYER_LOOP,&pause_time);
1510 if (send_ringbacktone){
1511 setup_ring_player(lc,call);
1513 audio_stream_set_rtcp_information(call->audiostream, cname, rtcp_tool);
1515 /* valid local tags are > 0 */
1516 if (stream->proto == SalProtoRtpSavp) {
1517 const SalStreamDescription *local_st_desc=sal_media_description_find_stream(call->localdesc,
1518 SalProtoRtpSavp,SalAudio);
1519 int crypto_idx = find_crypto_index_from_tag(local_st_desc->crypto, stream->crypto_local_tag);
1521 if (crypto_idx >= 0) {
1522 audio_stream_enable_srtp(
1524 stream->crypto[0].algo,
1525 local_st_desc->crypto[crypto_idx].master_key,
1526 stream->crypto[0].master_key);
1527 call->audiostream_encrypted=TRUE;
1529 ms_warning("Failed to find local crypto algo with tag: %d", stream->crypto_local_tag);
1530 call->audiostream_encrypted=FALSE;
1532 }else call->audiostream_encrypted=FALSE;
1533 if (call->params.in_conference){
1534 /*transform the graph to connect it to the conference filter */
1535 bool_t mute=stream->dir==SalStreamRecvOnly;
1536 linphone_call_add_to_conf(call, mute);
1538 call->current_params.in_conference=call->params.in_conference;
1539 call->current_params.low_bandwidth=call->params.low_bandwidth;
1540 }else ms_warning("No audio stream accepted ?");
1544 static void linphone_call_start_video_stream(LinphoneCall *call, const char *cname,bool_t all_inputs_muted){
1545 #ifdef VIDEO_ENABLED
1546 LinphoneCore *lc=call->core;
1548 /* look for savp stream first */
1549 const SalStreamDescription *vstream=sal_media_description_find_stream(call->resultdesc,
1550 SalProtoRtpSavp,SalVideo);
1551 char rtcp_tool[128]={0};
1552 snprintf(rtcp_tool,sizeof(rtcp_tool)-1,"%s-%s",linphone_core_get_user_agent_name(),linphone_core_get_user_agent_version());
1554 /* no savp audio stream, use avp */
1556 vstream=sal_media_description_find_stream(call->resultdesc,
1557 SalProtoRtpAvp,SalVideo);
1559 /* shutdown preview */
1560 if (lc->previewstream!=NULL) {
1561 video_preview_stop(lc->previewstream);
1562 lc->previewstream=NULL;
1565 if (vstream!=NULL && vstream->dir!=SalStreamInactive && vstream->rtp_port!=0) {
1566 const char *rtp_addr=vstream->rtp_addr[0]!='\0' ? vstream->rtp_addr : call->resultdesc->addr;
1567 const char *rtcp_addr=vstream->rtcp_addr[0]!='\0' ? vstream->rtcp_addr : call->resultdesc->addr;
1568 call->video_profile=make_profile(call,call->resultdesc,vstream,&used_pt);
1570 call->current_params.video_codec = rtp_profile_get_payload(call->video_profile, used_pt);
1571 VideoStreamDir dir=VideoStreamSendRecv;
1572 MSWebCam *cam=lc->video_conf.device;
1573 bool_t is_inactive=FALSE;
1575 call->current_params.has_video=TRUE;
1577 video_stream_enable_adaptive_bitrate_control(call->videostream,
1578 linphone_core_adaptive_rate_control_enabled(lc));
1579 video_stream_enable_adaptive_jittcomp(call->videostream, linphone_core_video_adaptive_jittcomp_enabled(lc));
1580 video_stream_set_sent_video_size(call->videostream,linphone_core_get_preferred_video_size(lc));
1581 video_stream_enable_self_view(call->videostream,lc->video_conf.selfview);
1582 if (lc->video_window_id!=0)
1583 video_stream_set_native_window_id(call->videostream,lc->video_window_id);
1584 if (lc->preview_window_id!=0)
1585 video_stream_set_native_preview_window_id (call->videostream,lc->preview_window_id);
1586 video_stream_use_preview_video_window (call->videostream,lc->use_preview_window);
1588 if (vstream->dir==SalStreamSendOnly && lc->video_conf.capture ){
1589 cam=get_nowebcam_device();
1590 dir=VideoStreamSendOnly;
1591 }else if (vstream->dir==SalStreamRecvOnly && lc->video_conf.display ){
1592 dir=VideoStreamRecvOnly;
1593 }else if (vstream->dir==SalStreamSendRecv){
1594 if (lc->video_conf.display && lc->video_conf.capture)
1595 dir=VideoStreamSendRecv;
1596 else if (lc->video_conf.display)
1597 dir=VideoStreamRecvOnly;
1599 dir=VideoStreamSendOnly;
1601 ms_warning("video stream is inactive.");
1602 /*either inactive or incompatible with local capabilities*/
1605 if (call->camera_active==FALSE || all_inputs_muted){
1606 cam=get_nowebcam_device();
1609 call->log->video_enabled = TRUE;
1610 video_stream_set_direction (call->videostream, dir);
1611 ms_message("%s lc rotation:%d\n", __FUNCTION__, lc->device_rotation);
1612 video_stream_set_device_rotation(call->videostream, lc->device_rotation);
1613 video_stream_start(call->videostream,
1614 call->video_profile, rtp_addr, vstream->rtp_port,
1615 rtcp_addr, linphone_core_rtcp_enabled(lc) ? (vstream->rtcp_port) : 0,
1616 used_pt, linphone_core_get_video_jittcomp(lc), cam);
1617 video_stream_set_rtcp_information(call->videostream, cname,rtcp_tool);
1620 if (vstream->proto == SalProtoRtpSavp) {
1621 const SalStreamDescription *local_st_desc=sal_media_description_find_stream(call->localdesc,
1622 SalProtoRtpSavp,SalVideo);
1624 video_stream_enable_strp(
1626 vstream->crypto[0].algo,
1627 local_st_desc->crypto[0].master_key,
1628 vstream->crypto[0].master_key
1630 call->videostream_encrypted=TRUE;
1632 call->videostream_encrypted=FALSE;
1634 }else ms_warning("No video stream accepted.");
1636 ms_warning("No valid video stream defined.");
1641 void linphone_call_start_media_streams(LinphoneCall *call, bool_t all_inputs_muted, bool_t send_ringbacktone){
1642 LinphoneCore *lc=call->core;
1644 call->current_params.audio_codec = NULL;
1645 call->current_params.video_codec = NULL;
1647 LinphoneAddress *me=linphone_core_get_primary_contact_parsed(lc);
1649 bool_t use_arc=linphone_core_adaptive_rate_control_enabled(lc);
1650 #ifdef VIDEO_ENABLED
1651 const SalStreamDescription *vstream=sal_media_description_find_stream(call->resultdesc,
1652 SalProtoRtpAvp,SalVideo);
1655 if ((call->audiostream == NULL) && (call->videostream == NULL)) {
1656 ms_fatal("start_media_stream() called without prior init !");
1659 cname=linphone_address_as_string_uri_only(me);
1661 #if defined(VIDEO_ENABLED)
1662 if (vstream!=NULL && vstream->dir!=SalStreamInactive && vstream->payloads!=NULL){
1663 /*when video is used, do not make adaptive rate control on audio, it is stupid.*/
1667 if (call->audiostream!=NULL) {
1668 linphone_call_start_audio_stream(call,cname,all_inputs_muted,send_ringbacktone,use_arc);
1670 call->current_params.has_video=FALSE;
1671 if (call->videostream!=NULL) {
1672 linphone_call_start_video_stream(call,cname,all_inputs_muted);
1675 call->all_muted=all_inputs_muted;
1676 call->playing_ringbacktone=send_ringbacktone;
1677 call->up_bw=linphone_core_get_upload_bandwidth(lc);
1679 if (call->params.media_encryption==LinphoneMediaEncryptionZRTP) {
1680 OrtpZrtpParams params;
1681 /*will be set later when zrtp is activated*/
1682 call->current_params.media_encryption=LinphoneMediaEncryptionNone;
1684 params.zid_file=lc->zrtp_secrets_cache;
1685 audio_stream_enable_zrtp(call->audiostream,¶ms);
1686 }else if (call->params.media_encryption==LinphoneMediaEncryptionSRTP){
1687 call->current_params.media_encryption=linphone_call_are_all_streams_encrypted(call) ?
1688 LinphoneMediaEncryptionSRTP : LinphoneMediaEncryptionNone;
1691 /*also reflect the change if the "wished" params, in order to avoid to propose SAVP or video again
1692 * further in the call, for example during pause,resume, conferencing reINVITEs*/
1693 linphone_call_fix_call_parameters(call);
1694 if ((call->ice_session != NULL) && (ice_session_state(call->ice_session) != IS_Completed)) {
1695 ice_session_start_connectivity_checks(call->ice_session);
1701 linphone_address_destroy(me);
1704 void linphone_call_start_media_streams_for_ice_gathering(LinphoneCall *call){
1705 audio_stream_prepare_sound(call->audiostream, NULL, NULL);
1706 #ifdef VIDEO_ENABLED
1707 if (call->videostream) {
1708 video_stream_prepare_video(call->videostream);
1713 void linphone_call_stop_media_streams_for_ice_gathering(LinphoneCall *call){
1714 audio_stream_unprepare_sound(call->audiostream);
1715 #ifdef VIDEO_ENABLED
1716 if (call->videostream) {
1717 video_stream_unprepare_video(call->videostream);
1722 void linphone_call_update_crypto_parameters(LinphoneCall *call, SalMediaDescription *old_md, SalMediaDescription *new_md) {
1723 SalStreamDescription *old_stream;
1724 SalStreamDescription *new_stream;
1727 old_stream = sal_media_description_find_stream(old_md, SalProtoRtpSavp, SalAudio);
1728 new_stream = sal_media_description_find_stream(new_md, SalProtoRtpSavp, SalAudio);
1729 if (old_stream && new_stream) {
1730 const SalStreamDescription *local_st_desc = sal_media_description_find_stream(call->localdesc, SalProtoRtpSavp, SalAudio);
1731 if (local_st_desc) {
1732 int crypto_idx = find_crypto_index_from_tag(local_st_desc->crypto, new_stream->crypto_local_tag);
1733 if (crypto_idx >= 0) {
1734 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);
1735 call->audiostream_encrypted = TRUE;
1737 ms_warning("Failed to find local crypto algo with tag: %d", new_stream->crypto_local_tag);
1738 call->audiostream_encrypted = FALSE;
1740 for (i = 0; i < SAL_CRYPTO_ALGO_MAX; i++) {
1741 old_stream->crypto[i].tag = new_stream->crypto[i].tag;
1742 old_stream->crypto[i].algo = new_stream->crypto[i].algo;
1743 strncpy(old_stream->crypto[i].master_key, new_stream->crypto[i].master_key, sizeof(old_stream->crypto[i].master_key) - 1);
1748 #ifdef VIDEO_ENABLED
1749 old_stream = sal_media_description_find_stream(old_md, SalProtoRtpSavp, SalVideo);
1750 new_stream = sal_media_description_find_stream(new_md, SalProtoRtpSavp, SalVideo);
1751 if (old_stream && new_stream) {
1752 const SalStreamDescription *local_st_desc = sal_media_description_find_stream(call->localdesc, SalProtoRtpSavp, SalVideo);
1753 if (local_st_desc) {
1754 int crypto_idx = find_crypto_index_from_tag(local_st_desc->crypto, new_stream->crypto_local_tag);
1755 if (crypto_idx >= 0) {
1756 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);
1757 call->videostream_encrypted = TRUE;
1759 ms_warning("Failed to find local crypto algo with tag: %d", new_stream->crypto_local_tag);
1760 call->videostream_encrypted = FALSE;
1762 for (i = 0; i < SAL_CRYPTO_ALGO_MAX; i++) {
1763 old_stream->crypto[i].tag = new_stream->crypto[i].tag;
1764 old_stream->crypto[i].algo = new_stream->crypto[i].algo;
1765 strncpy(old_stream->crypto[i].master_key, new_stream->crypto[i].master_key, sizeof(old_stream->crypto[i].master_key) - 1);
1772 void linphone_call_update_remote_session_id_and_ver(LinphoneCall *call) {
1773 SalMediaDescription *remote_desc = sal_call_get_remote_media_description(call->op);
1775 call->remote_session_id = remote_desc->session_id;
1776 call->remote_session_ver = remote_desc->session_ver;
1780 void linphone_call_delete_ice_session(LinphoneCall *call){
1781 if (call->ice_session != NULL) {
1782 ice_session_destroy(call->ice_session);
1783 call->ice_session = NULL;
1784 if (call->audiostream != NULL) call->audiostream->ms.ice_check_list = NULL;
1785 if (call->videostream != NULL) call->videostream->ms.ice_check_list = NULL;
1786 call->stats[LINPHONE_CALL_STATS_AUDIO].ice_state = LinphoneIceStateNotActivated;
1787 call->stats[LINPHONE_CALL_STATS_VIDEO].ice_state = LinphoneIceStateNotActivated;
1792 void linphone_call_delete_upnp_session(LinphoneCall *call){
1793 if(call->upnp_session!=NULL) {
1794 linphone_upnp_session_destroy(call->upnp_session);
1795 call->upnp_session=NULL;
1800 static void linphone_call_log_fill_stats(LinphoneCallLog *log, AudioStream *st){
1801 audio_stream_get_local_rtp_stats (st,&log->local_stats);
1802 log->quality=audio_stream_get_average_quality_rating(st);
1805 void linphone_call_stop_audio_stream(LinphoneCall *call) {
1806 if (call->audiostream!=NULL) {
1807 rtp_session_unregister_event_queue(call->audiostream->ms.session,call->audiostream_app_evq);
1808 ortp_ev_queue_flush(call->audiostream_app_evq);
1809 ortp_ev_queue_destroy(call->audiostream_app_evq);
1810 call->audiostream_app_evq=NULL;
1812 if (call->audiostream->ec){
1813 const char *state_str=NULL;
1814 ms_filter_call_method(call->audiostream->ec,MS_ECHO_CANCELLER_GET_STATE_STRING,&state_str);
1816 ms_message("Writing echo canceler state, %i bytes",(int)strlen(state_str));
1817 lp_config_set_string(call->core->config,"sound","ec_state",state_str);
1820 linphone_call_log_fill_stats (call->log,call->audiostream);
1821 if (call->endpoint){
1822 linphone_call_remove_from_conf(call);
1824 audio_stream_stop(call->audiostream);
1825 call->audiostream=NULL;
1829 void linphone_call_stop_video_stream(LinphoneCall *call) {
1830 #ifdef VIDEO_ENABLED
1831 if (call->videostream!=NULL){
1832 rtp_session_unregister_event_queue(call->videostream->ms.session,call->videostream_app_evq);
1833 ortp_ev_queue_flush(call->videostream_app_evq);
1834 ortp_ev_queue_destroy(call->videostream_app_evq);
1835 call->videostream_app_evq=NULL;
1836 video_stream_stop(call->videostream);
1837 call->videostream=NULL;
1842 void linphone_call_stop_media_streams(LinphoneCall *call){
1843 linphone_call_stop_audio_stream(call);
1844 linphone_call_stop_video_stream(call);
1845 ms_event_queue_skip(call->core->msevq);
1847 if (call->audio_profile){
1848 rtp_profile_clear_all(call->audio_profile);
1849 rtp_profile_destroy(call->audio_profile);
1850 call->audio_profile=NULL;
1852 if (call->video_profile){
1853 rtp_profile_clear_all(call->video_profile);
1854 rtp_profile_destroy(call->video_profile);
1855 call->video_profile=NULL;
1861 void linphone_call_enable_echo_cancellation(LinphoneCall *call, bool_t enable) {
1862 if (call!=NULL && call->audiostream!=NULL && call->audiostream->ec){
1863 bool_t bypass_mode = !enable;
1864 ms_filter_call_method(call->audiostream->ec,MS_ECHO_CANCELLER_SET_BYPASS_MODE,&bypass_mode);
1867 bool_t linphone_call_echo_cancellation_enabled(LinphoneCall *call) {
1868 if (call!=NULL && call->audiostream!=NULL && call->audiostream->ec){
1870 ms_filter_call_method(call->audiostream->ec,MS_ECHO_CANCELLER_GET_BYPASS_MODE,&val);
1873 return linphone_core_echo_cancellation_enabled(call->core);
1877 void linphone_call_enable_echo_limiter(LinphoneCall *call, bool_t val){
1878 if (call!=NULL && call->audiostream!=NULL ) {
1880 const char *type=lp_config_get_string(call->core->config,"sound","el_type","mic");
1881 if (strcasecmp(type,"mic")==0)
1882 audio_stream_enable_echo_limiter(call->audiostream,ELControlMic);
1883 else if (strcasecmp(type,"full")==0)
1884 audio_stream_enable_echo_limiter(call->audiostream,ELControlFull);
1886 audio_stream_enable_echo_limiter(call->audiostream,ELInactive);
1891 bool_t linphone_call_echo_limiter_enabled(const LinphoneCall *call){
1892 if (call!=NULL && call->audiostream!=NULL ){
1893 return call->audiostream->el_type !=ELInactive ;
1895 return linphone_core_echo_limiter_enabled(call->core);
1900 * @addtogroup call_misc
1905 * Returns the measured sound volume played locally (received from remote).
1906 * It is expressed in dbm0.
1908 float linphone_call_get_play_volume(LinphoneCall *call){
1909 AudioStream *st=call->audiostream;
1910 if (st && st->volrecv){
1912 ms_filter_call_method(st->volrecv,MS_VOLUME_GET,&vol);
1916 return LINPHONE_VOLUME_DB_LOWEST;
1920 * Returns the measured sound volume recorded locally (sent to remote).
1921 * It is expressed in dbm0.
1923 float linphone_call_get_record_volume(LinphoneCall *call){
1924 AudioStream *st=call->audiostream;
1925 if (st && st->volsend && !call->audio_muted && call->state==LinphoneCallStreamsRunning){
1927 ms_filter_call_method(st->volsend,MS_VOLUME_GET,&vol);
1931 return LINPHONE_VOLUME_DB_LOWEST;
1935 * Obtain real-time quality rating of the call
1937 * Based on local RTP statistics and RTCP feedback, a quality rating is computed and updated
1938 * during all the duration of the call. This function returns its value at the time of the function call.
1939 * It is expected that the rating is updated at least every 5 seconds or so.
1940 * The rating is a floating point number comprised between 0 and 5.
1942 * 4-5 = good quality <br>
1943 * 3-4 = average quality <br>
1944 * 2-3 = poor quality <br>
1945 * 1-2 = very poor quality <br>
1946 * 0-1 = can't be worse, mostly unusable <br>
1948 * @returns The function returns -1 if no quality measurement is available, for example if no
1949 * active audio stream exist. Otherwise it returns the quality rating.
1951 float linphone_call_get_current_quality(LinphoneCall *call){
1952 if (call->audiostream){
1953 return audio_stream_get_quality_rating(call->audiostream);
1959 * Returns call quality averaged over all the duration of the call.
1961 * See linphone_call_get_current_quality() for more details about quality measurement.
1963 float linphone_call_get_average_quality(LinphoneCall *call){
1964 if (call->audiostream){
1965 return audio_stream_get_average_quality_rating(call->audiostream);
1971 * Access last known statistics for audio stream, for a given call.
1973 const LinphoneCallStats *linphone_call_get_audio_stats(const LinphoneCall *call) {
1974 return &call->stats[LINPHONE_CALL_STATS_AUDIO];
1978 * Access last known statistics for video stream, for a given call.
1980 const LinphoneCallStats *linphone_call_get_video_stats(const LinphoneCall *call) {
1981 return &call->stats[LINPHONE_CALL_STATS_VIDEO];
1989 static void report_bandwidth(LinphoneCall *call, RtpSession *as, RtpSession *vs){
1990 call->stats[LINPHONE_CALL_STATS_AUDIO].download_bandwidth=(as!=NULL) ? (rtp_session_compute_recv_bandwidth(as)*1e-3) : 0;
1991 call->stats[LINPHONE_CALL_STATS_AUDIO].upload_bandwidth=(as!=NULL) ? (rtp_session_compute_send_bandwidth(as)*1e-3) : 0;
1992 call->stats[LINPHONE_CALL_STATS_VIDEO].download_bandwidth=(vs!=NULL) ? (rtp_session_compute_recv_bandwidth(vs)*1e-3) : 0;
1993 call->stats[LINPHONE_CALL_STATS_VIDEO].upload_bandwidth=(vs!=NULL) ? (rtp_session_compute_send_bandwidth(vs)*1e-3) : 0;
1994 ms_message("bandwidth usage: audio=[d=%.1f,u=%.1f] video=[d=%.1f,u=%.1f] kbit/sec",
1995 call->stats[LINPHONE_CALL_STATS_AUDIO].download_bandwidth,
1996 call->stats[LINPHONE_CALL_STATS_AUDIO].upload_bandwidth ,
1997 call->stats[LINPHONE_CALL_STATS_VIDEO].download_bandwidth,
1998 call->stats[LINPHONE_CALL_STATS_VIDEO].upload_bandwidth
2002 static void linphone_core_disconnected(LinphoneCore *lc, LinphoneCall *call){
2006 from = linphone_call_get_remote_address_as_string(call);
2009 snprintf(temp,sizeof(temp),"Remote end %s seems to have disconnected, the call is going to be closed.",from);
2014 snprintf(temp,sizeof(temp),"Remote end seems to have disconnected, the call is going to be closed.");
2016 if (lc->vtable.display_warning!=NULL)
2017 lc->vtable.display_warning(lc,temp);
2018 linphone_core_terminate_call(lc,call);
2021 static void handle_ice_events(LinphoneCall *call, OrtpEvent *ev){
2022 OrtpEventType evt=ortp_event_get_type(ev);
2023 OrtpEventData *evd=ortp_event_get_data(ev);
2026 if (evt == ORTP_EVENT_ICE_SESSION_PROCESSING_FINISHED) {
2027 switch (ice_session_state(call->ice_session)) {
2029 ice_session_select_candidates(call->ice_session);
2030 if (ice_session_role(call->ice_session) == IR_Controlling) {
2031 linphone_core_update_call(call->core, call, &call->current_params);
2035 if (ice_session_has_completed_check_list(call->ice_session) == TRUE) {
2036 ice_session_select_candidates(call->ice_session);
2037 if (ice_session_role(call->ice_session) == IR_Controlling) {
2038 /* At least one ICE session has succeeded, so perform a call update. */
2039 linphone_core_update_call(call->core, call, &call->current_params);
2046 linphone_core_update_ice_state_in_call_stats(call);
2047 } else if (evt == ORTP_EVENT_ICE_GATHERING_FINISHED) {
2049 if (evd->info.ice_processing_successful==TRUE) {
2050 ice_session_compute_candidates_foundations(call->ice_session);
2051 ice_session_eliminate_redundant_candidates(call->ice_session);
2052 ice_session_choose_default_candidates(call->ice_session);
2053 ping_time = ice_session_average_gathering_round_trip_time(call->ice_session);
2054 if (ping_time >=0) {
2055 call->ping_time=ping_time;
2058 ms_warning("No STUN answer from [%s], disabling ICE",linphone_core_get_stun_server(call->core));
2059 linphone_call_delete_ice_session(call);
2061 switch (call->state) {
2062 case LinphoneCallUpdating:
2063 linphone_core_start_update_call(call->core, call);
2065 case LinphoneCallUpdatedByRemote:
2066 linphone_core_start_accept_call_update(call->core, call);
2068 case LinphoneCallOutgoingInit:
2069 linphone_call_stop_media_streams_for_ice_gathering(call);
2070 linphone_core_proceed_with_invite_if_ready(call->core, call, NULL);
2072 case LinphoneCallIdle:
2073 linphone_call_stop_media_streams_for_ice_gathering(call);
2074 linphone_core_notify_incoming_call(call->core, call);
2079 } else if (evt == ORTP_EVENT_ICE_LOSING_PAIRS_COMPLETED) {
2080 linphone_core_start_accept_call_update(call->core, call);
2081 linphone_core_update_ice_state_in_call_stats(call);
2082 } else if (evt == ORTP_EVENT_ICE_RESTART_NEEDED) {
2083 ice_session_restart(call->ice_session);
2084 ice_session_set_role(call->ice_session, IR_Controlling);
2085 linphone_core_update_call(call->core, call, &call->current_params);
2089 void linphone_call_background_tasks(LinphoneCall *call, bool_t one_second_elapsed){
2090 LinphoneCore* lc = call->core;
2091 int disconnect_timeout = linphone_core_get_nortp_timeout(call->core);
2092 bool_t disconnected=FALSE;
2094 if (call->state==LinphoneCallStreamsRunning && one_second_elapsed){
2095 RtpSession *as=NULL,*vs=NULL;
2096 float audio_load=0, video_load=0;
2097 if (call->audiostream!=NULL){
2098 as=call->audiostream->ms.session;
2099 if (call->audiostream->ms.ticker)
2100 audio_load=ms_ticker_get_average_load(call->audiostream->ms.ticker);
2102 if (call->videostream!=NULL){
2103 if (call->videostream->ms.ticker)
2104 video_load=ms_ticker_get_average_load(call->videostream->ms.ticker);
2105 vs=call->videostream->ms.session;
2107 report_bandwidth(call,as,vs);
2108 ms_message("Thread processing load: audio=%f\tvideo=%f",audio_load,video_load);
2112 linphone_upnp_call_process(call);
2115 #ifdef VIDEO_ENABLED
2116 if (call->videostream!=NULL) {
2119 /* Ensure there is no dangling ICE check list. */
2120 if (call->ice_session == NULL) call->videostream->ms.ice_check_list = NULL;
2122 // Beware that the application queue should not depend on treatments fron the
2123 // mediastreamer queue.
2124 video_stream_iterate(call->videostream);
2126 while (call->videostream_app_evq && (NULL != (ev=ortp_ev_queue_get(call->videostream_app_evq)))){
2127 OrtpEventType evt=ortp_event_get_type(ev);
2128 OrtpEventData *evd=ortp_event_get_data(ev);
2129 if (evt == ORTP_EVENT_ZRTP_ENCRYPTION_CHANGED){
2130 linphone_call_videostream_encryption_changed(call, evd->info.zrtp_stream_encrypted);
2131 } else if (evt == ORTP_EVENT_RTCP_PACKET_RECEIVED) {
2132 call->stats[LINPHONE_CALL_STATS_VIDEO].round_trip_delay = rtp_session_get_round_trip_propagation(call->videostream->ms.session);
2133 if(call->stats[LINPHONE_CALL_STATS_VIDEO].received_rtcp != NULL)
2134 freemsg(call->stats[LINPHONE_CALL_STATS_VIDEO].received_rtcp);
2135 call->stats[LINPHONE_CALL_STATS_VIDEO].received_rtcp = evd->packet;
2137 if (lc->vtable.call_stats_updated)
2138 lc->vtable.call_stats_updated(lc, call, &call->stats[LINPHONE_CALL_STATS_VIDEO]);
2139 } else if (evt == ORTP_EVENT_RTCP_PACKET_EMITTED) {
2140 memcpy(&call->stats[LINPHONE_CALL_STATS_VIDEO].jitter_stats, rtp_session_get_jitter_stats(call->videostream->ms.session), sizeof(jitter_stats_t));
2141 if(call->stats[LINPHONE_CALL_STATS_VIDEO].sent_rtcp != NULL)
2142 freemsg(call->stats[LINPHONE_CALL_STATS_VIDEO].sent_rtcp);
2143 call->stats[LINPHONE_CALL_STATS_VIDEO].sent_rtcp = evd->packet;
2145 if (lc->vtable.call_stats_updated)
2146 lc->vtable.call_stats_updated(lc, call, &call->stats[LINPHONE_CALL_STATS_VIDEO]);
2147 } else if ((evt == ORTP_EVENT_ICE_SESSION_PROCESSING_FINISHED) || (evt == ORTP_EVENT_ICE_GATHERING_FINISHED)
2148 || (evt == ORTP_EVENT_ICE_LOSING_PAIRS_COMPLETED) || (evt == ORTP_EVENT_ICE_RESTART_NEEDED)) {
2149 handle_ice_events(call, ev);
2151 ortp_event_destroy(ev);
2155 if (call->audiostream!=NULL) {
2158 /* Ensure there is no dangling ICE check list. */
2159 if (call->ice_session == NULL) call->audiostream->ms.ice_check_list = NULL;
2161 // Beware that the application queue should not depend on treatments fron the
2162 // mediastreamer queue.
2163 audio_stream_iterate(call->audiostream);
2165 while (call->audiostream_app_evq && (NULL != (ev=ortp_ev_queue_get(call->audiostream_app_evq)))){
2166 OrtpEventType evt=ortp_event_get_type(ev);
2167 OrtpEventData *evd=ortp_event_get_data(ev);
2168 if (evt == ORTP_EVENT_ZRTP_ENCRYPTION_CHANGED){
2169 linphone_call_audiostream_encryption_changed(call, evd->info.zrtp_stream_encrypted);
2170 } else if (evt == ORTP_EVENT_ZRTP_SAS_READY) {
2171 linphone_call_audiostream_auth_token_ready(call, evd->info.zrtp_sas.sas, evd->info.zrtp_sas.verified);
2172 } else if (evt == ORTP_EVENT_RTCP_PACKET_RECEIVED) {
2173 call->stats[LINPHONE_CALL_STATS_AUDIO].round_trip_delay = rtp_session_get_round_trip_propagation(call->audiostream->ms.session);
2174 if(call->stats[LINPHONE_CALL_STATS_AUDIO].received_rtcp != NULL)
2175 freemsg(call->stats[LINPHONE_CALL_STATS_AUDIO].received_rtcp);
2176 call->stats[LINPHONE_CALL_STATS_AUDIO].received_rtcp = evd->packet;
2178 if (lc->vtable.call_stats_updated)
2179 lc->vtable.call_stats_updated(lc, call, &call->stats[LINPHONE_CALL_STATS_AUDIO]);
2180 } else if (evt == ORTP_EVENT_RTCP_PACKET_EMITTED) {
2181 memcpy(&call->stats[LINPHONE_CALL_STATS_AUDIO].jitter_stats, rtp_session_get_jitter_stats(call->audiostream->ms.session), sizeof(jitter_stats_t));
2182 if(call->stats[LINPHONE_CALL_STATS_AUDIO].sent_rtcp != NULL)
2183 freemsg(call->stats[LINPHONE_CALL_STATS_AUDIO].sent_rtcp);
2184 call->stats[LINPHONE_CALL_STATS_AUDIO].sent_rtcp = evd->packet;
2186 if (lc->vtable.call_stats_updated)
2187 lc->vtable.call_stats_updated(lc, call, &call->stats[LINPHONE_CALL_STATS_AUDIO]);
2188 } else if ((evt == ORTP_EVENT_ICE_SESSION_PROCESSING_FINISHED) || (evt == ORTP_EVENT_ICE_GATHERING_FINISHED)
2189 || (evt == ORTP_EVENT_ICE_LOSING_PAIRS_COMPLETED) || (evt == ORTP_EVENT_ICE_RESTART_NEEDED)) {
2190 handle_ice_events(call, ev);
2191 } else if (evt==ORTP_EVENT_TELEPHONE_EVENT){
2192 linphone_core_dtmf_received(lc,evd->info.telephone_event);
2194 ortp_event_destroy(ev);
2197 if (call->state==LinphoneCallStreamsRunning && one_second_elapsed && call->audiostream!=NULL && disconnect_timeout>0 )
2198 disconnected=!audio_stream_alive(call->audiostream,disconnect_timeout);
2200 linphone_core_disconnected(call->core,call);
2203 void linphone_call_log_completed(LinphoneCall *call){
2204 LinphoneCore *lc=call->core;
2206 call->log->duration=time(NULL)-call->start_time;
2208 if (call->log->status==LinphoneCallMissed){
2211 info=ortp_strdup_printf(ngettext("You have missed %i call.",
2212 "You have missed %i calls.", lc->missed_calls),
2214 if (lc->vtable.display_status!=NULL)
2215 lc->vtable.display_status(lc,info);
2218 lc->call_logs=ms_list_prepend(lc->call_logs,(void *)call->log);
2219 if (ms_list_size(lc->call_logs)>lc->max_call_logs){
2220 MSList *elem,*prevelem=NULL;
2221 /*find the last element*/
2222 for(elem=lc->call_logs;elem!=NULL;elem=elem->next){
2226 linphone_call_log_destroy((LinphoneCallLog*)elem->data);
2227 lc->call_logs=ms_list_remove_link(lc->call_logs,elem);
2229 if (lc->vtable.call_log_updated!=NULL){
2230 lc->vtable.call_log_updated(lc,call->log);
2232 call_logs_write_to_config_file(lc);
2235 LinphoneCallState linphone_call_get_transfer_state(LinphoneCall *call) {
2236 return call->transfer_state;
2239 void linphone_call_set_transfer_state(LinphoneCall* call, LinphoneCallState state) {
2240 if (state != call->transfer_state) {
2241 LinphoneCore* lc = call->core;
2242 call->transfer_state = state;
2243 if (lc->vtable.transfer_state_changed)
2244 lc->vtable.transfer_state_changed(lc, call, state);
2249 * Returns true if the call is part of the conference.
2250 * @ingroup conferencing
2252 bool_t linphone_call_is_in_conference(const LinphoneCall *call) {
2253 return call->params.in_conference;
2258 * Perform a zoom of the video displayed during a call.
2259 * @param call the call.
2260 * @param zoom_factor a floating point number describing the zoom factor. A value 1.0 corresponds to no zoom applied.
2261 * @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.
2262 * @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.
2264 * 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.
2266 void linphone_call_zoom_video(LinphoneCall* call, float zoom_factor, float* cx, float* cy) {
2267 VideoStream* vstream = call->videostream;
2268 if (vstream && vstream->output) {
2271 if (zoom_factor < 1)
2273 float halfsize = 0.5 * 1.0 / zoom_factor;
2275 if ((*cx - halfsize) < 0)
2277 if ((*cx + halfsize) > 1)
2279 if ((*cy - halfsize) < 0)
2281 if ((*cy + halfsize) > 1)
2284 zoom[0] = zoom_factor;
2287 ms_filter_call_method(vstream->output, MS_VIDEO_DISPLAY_ZOOM, &zoom);
2288 }else ms_warning("Could not apply zoom: video output wasn't activated.");