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,NULL,call->localip);
473 linphone_call_init_common(call,from,to);
474 _linphone_call_params_copy(&call->params,params);
475 sal_op_set_custom_header(call->op,call->params.custom_headers);
476 call->params.custom_headers=NULL;
478 if (linphone_core_get_firewall_policy(call->core) == LinphonePolicyUseIce) {
479 call->ice_session = ice_session_new();
480 ice_session_set_role(call->ice_session, IR_Controlling);
482 if (linphone_core_get_firewall_policy(call->core) == LinphonePolicyUseStun) {
483 call->ping_time=linphone_core_run_stun_tests(call->core,call);
486 if (linphone_core_get_firewall_policy(call->core) == LinphonePolicyUseUpnp) {
487 if(!lc->rtp_conf.disable_upnp) {
488 call->upnp_session = linphone_upnp_session_new(call);
492 call->camera_active=params->has_video;
494 discover_mtu(lc,linphone_address_get_domain (to));
495 if (params->referer){
496 sal_call_set_referer(call->op,params->referer->op);
497 call->referer=linphone_call_ref(params->referer);
502 LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *from, LinphoneAddress *to, SalOp *op){
503 LinphoneCall *call=ms_new0(LinphoneCall,1);
505 const SalMediaDescription *md;
507 call->dir=LinphoneCallIncoming;
508 sal_op_set_user_pointer(op,call);
512 if (lc->sip_conf.ping_with_options){
514 if (lc->upnp != NULL && linphone_core_get_firewall_policy(lc)==LinphonePolicyUseUpnp &&
515 linphone_upnp_context_get_state(lc->upnp) == LinphoneUpnpStateOk) {
519 /*the following sends an option request back to the caller so that
520 we get a chance to discover our nat'd address before answering.*/
521 call->ping_op=sal_op_new(lc->sal);
522 from_str=linphone_address_as_string_uri_only(from);
523 sal_op_set_route(call->ping_op,sal_op_get_network_origin(op));
524 sal_op_set_user_pointer(call->ping_op,call);
525 sal_ping(call->ping_op,linphone_core_find_best_identity(lc,from,NULL),from_str);
530 linphone_address_clean(from);
531 linphone_core_get_local_ip(lc,NULL,call->localip);
532 linphone_call_init_common(call, from, to);
533 call->log->call_id=ms_strdup(sal_op_get_call_id(op)); /*must be known at that time*/
534 linphone_core_init_default_params(lc, &call->params);
535 md=sal_call_get_remote_media_description(op);
536 call->params.has_video &= !!lc->video_policy.automatically_accept;
538 // It is licit to receive an INVITE without SDP
539 // In this case WE chose the media parameters according to policy.
540 call->params.has_video &= linphone_core_media_description_contains_video_stream(md);
542 switch (linphone_core_get_firewall_policy(call->core)) {
543 case LinphonePolicyUseIce:
544 call->ice_session = ice_session_new();
545 ice_session_set_role(call->ice_session, IR_Controlled);
546 linphone_core_update_ice_from_remote_media_description(call, sal_call_get_remote_media_description(op));
547 if (call->ice_session != NULL) {
548 linphone_call_init_media_streams(call);
549 linphone_call_start_media_streams_for_ice_gathering(call);
550 if (linphone_core_gather_ice_candidates(call->core,call)<0) {
551 /* Ice candidates gathering failed, proceed with the call anyway. */
552 linphone_call_delete_ice_session(call);
553 linphone_call_stop_media_streams_for_ice_gathering(call);
557 case LinphonePolicyUseStun:
558 call->ping_time=linphone_core_run_stun_tests(call->core,call);
559 /* No break to also destroy ice session in this case. */
561 case LinphonePolicyUseUpnp:
563 if(!lc->rtp_conf.disable_upnp) {
564 call->upnp_session = linphone_upnp_session_new(call);
565 if (call->upnp_session != NULL) {
566 linphone_call_init_media_streams(call);
567 if (linphone_core_update_upnp_from_remote_media_description(call, sal_call_get_remote_media_description(op))<0) {
568 /* uPnP port mappings failed, proceed with the call anyway. */
569 linphone_call_delete_upnp_session(call);
578 call->camera_active=call->params.has_video;
580 discover_mtu(lc,linphone_address_get_domain(from));
584 /* this function is called internally to get rid of a call.
585 It performs the following tasks:
586 - remove the call from the internal list of calls
587 - update the call logs accordingly
590 static void linphone_call_set_terminated(LinphoneCall *call){
591 LinphoneCore *lc=call->core;
593 linphone_core_update_allocated_audio_bandwidth(lc);
595 call->owns_call_log=FALSE;
596 linphone_call_log_completed(call);
599 if (call == lc->current_call){
600 ms_message("Resetting the current call");
601 lc->current_call=NULL;
604 if (linphone_core_del_call(lc,call) != 0){
605 ms_error("Could not remove the call from the list !!!");
608 if (ms_list_size(lc->calls)==0)
609 linphone_core_notify_all_friends(lc,lc->presence_mode);
611 linphone_core_conference_check_uninit(lc);
612 if (call->ringing_beep){
613 linphone_core_stop_dtmf(lc);
614 call->ringing_beep=FALSE;
617 linphone_call_unref(call->referer);
622 void linphone_call_fix_call_parameters(LinphoneCall *call){
623 call->params.has_video=call->current_params.has_video;
624 call->params.media_encryption=call->current_params.media_encryption;
627 const char *linphone_call_state_to_string(LinphoneCallState cs){
629 case LinphoneCallIdle:
630 return "LinphoneCallIdle";
631 case LinphoneCallIncomingReceived:
632 return "LinphoneCallIncomingReceived";
633 case LinphoneCallOutgoingInit:
634 return "LinphoneCallOutgoingInit";
635 case LinphoneCallOutgoingProgress:
636 return "LinphoneCallOutgoingProgress";
637 case LinphoneCallOutgoingRinging:
638 return "LinphoneCallOutgoingRinging";
639 case LinphoneCallOutgoingEarlyMedia:
640 return "LinphoneCallOutgoingEarlyMedia";
641 case LinphoneCallConnected:
642 return "LinphoneCallConnected";
643 case LinphoneCallStreamsRunning:
644 return "LinphoneCallStreamsRunning";
645 case LinphoneCallPausing:
646 return "LinphoneCallPausing";
647 case LinphoneCallPaused:
648 return "LinphoneCallPaused";
649 case LinphoneCallResuming:
650 return "LinphoneCallResuming";
651 case LinphoneCallRefered:
652 return "LinphoneCallRefered";
653 case LinphoneCallError:
654 return "LinphoneCallError";
655 case LinphoneCallEnd:
656 return "LinphoneCallEnd";
657 case LinphoneCallPausedByRemote:
658 return "LinphoneCallPausedByRemote";
659 case LinphoneCallUpdatedByRemote:
660 return "LinphoneCallUpdatedByRemote";
661 case LinphoneCallIncomingEarlyMedia:
662 return "LinphoneCallIncomingEarlyMedia";
663 case LinphoneCallUpdating:
664 return "LinphoneCallUpdating";
665 case LinphoneCallReleased:
666 return "LinphoneCallReleased";
668 return "undefined state";
671 void linphone_call_set_state(LinphoneCall *call, LinphoneCallState cstate, const char *message){
672 LinphoneCore *lc=call->core;
674 if (call->state!=cstate){
675 if (call->state==LinphoneCallEnd || call->state==LinphoneCallError){
676 if (cstate!=LinphoneCallReleased){
677 ms_warning("Spurious call state change from %s to %s, ignored.",linphone_call_state_to_string(call->state),
678 linphone_call_state_to_string(cstate));
682 ms_message("Call %p: moving from state %s to %s",call,linphone_call_state_to_string(call->state),
683 linphone_call_state_to_string(cstate));
684 if (cstate!=LinphoneCallRefered){
685 /*LinphoneCallRefered is rather an event, not a state.
686 Indeed it does not change the state of the call (still paused or running)*/
689 if (cstate==LinphoneCallEnd || cstate==LinphoneCallError){
690 switch(call->reason){
691 case LinphoneReasonDeclined:
692 call->log->status=LinphoneCallDeclined;
694 case LinphoneReasonNotAnswered:
695 call->log->status=LinphoneCallMissed;
700 linphone_call_set_terminated (call);
702 if (cstate == LinphoneCallConnected) {
703 call->log->status=LinphoneCallSuccess;
704 call->media_start_time=time(NULL);
707 if (lc->vtable.call_state_changed)
708 lc->vtable.call_state_changed(lc,call,cstate,message);
709 if (cstate==LinphoneCallReleased){
710 if (call->op!=NULL) {
711 /* so that we cannot have anymore upcalls for SAL
712 concerning this call*/
713 sal_op_release(call->op);
716 linphone_call_unref(call);
721 static void linphone_call_destroy(LinphoneCall *obj)
724 linphone_call_delete_upnp_session(obj);
726 linphone_call_delete_ice_session(obj);
728 sal_op_release(obj->op);
731 if (obj->resultdesc!=NULL) {
732 sal_media_description_unref(obj->resultdesc);
733 obj->resultdesc=NULL;
735 if (obj->localdesc!=NULL) {
736 sal_media_description_unref(obj->localdesc);
740 sal_op_release(obj->ping_op);
743 ms_free(obj->refer_to);
745 if (obj->owns_call_log)
746 linphone_call_log_destroy(obj->log);
747 if (obj->auth_token) {
748 ms_free(obj->auth_token);
750 linphone_call_params_uninit(&obj->params);
755 * @addtogroup call_control
760 * Increments the call 's reference count.
761 * An application that wishes to retain a pointer to call object
762 * must use this function to unsure the pointer remains
763 * valid. Once the application no more needs this pointer,
764 * it must call linphone_call_unref().
766 LinphoneCall * linphone_call_ref(LinphoneCall *obj){
772 * Decrements the call object reference count.
773 * See linphone_call_ref().
775 void linphone_call_unref(LinphoneCall *obj){
778 linphone_call_destroy(obj);
783 * Returns current parameters associated to the call.
785 const LinphoneCallParams * linphone_call_get_current_params(LinphoneCall *call){
786 if (call->params.record_file)
787 call->current_params.record_file=call->params.record_file;
788 return &call->current_params;
791 static bool_t is_video_active(const SalStreamDescription *sd){
792 return sd->rtp_port!=0 && sd->dir!=SalStreamInactive;
796 * Returns call parameters proposed by remote.
798 * This is useful when receiving an incoming call, to know whether the remote party
799 * supports video, encryption or whatever.
801 const LinphoneCallParams * linphone_call_get_remote_params(LinphoneCall *call){
802 LinphoneCallParams *cp=&call->remote_params;
803 memset(cp,0,sizeof(*cp));
805 SalMediaDescription *md=sal_call_get_remote_media_description(call->op);
807 SalStreamDescription *asd,*vsd,*secure_asd,*secure_vsd;
809 asd=sal_media_description_find_stream(md,SalProtoRtpAvp,SalAudio);
810 vsd=sal_media_description_find_stream(md,SalProtoRtpAvp,SalVideo);
811 secure_asd=sal_media_description_find_stream(md,SalProtoRtpSavp,SalAudio);
812 secure_vsd=sal_media_description_find_stream(md,SalProtoRtpSavp,SalVideo);
814 cp->has_video=is_video_active(secure_vsd);
815 if (secure_asd || asd==NULL)
816 cp->media_encryption=LinphoneMediaEncryptionSRTP;
818 cp->has_video=is_video_active(vsd);
821 if (md->bandwidth>0 && md->bandwidth<=linphone_core_get_edge_bw(call->core)){
822 cp->low_bandwidth=TRUE;
825 cp->custom_headers=(SalCustomHeader*)sal_op_get_custom_header(call->op);
833 * Returns the remote address associated to this call
836 const LinphoneAddress * linphone_call_get_remote_address(const LinphoneCall *call){
837 return call->dir==LinphoneCallIncoming ? call->log->from : call->log->to;
841 * Returns the remote address associated to this call as a string.
843 * The result string must be freed by user using ms_free().
845 char *linphone_call_get_remote_address_as_string(const LinphoneCall *call){
846 return linphone_address_as_string(linphone_call_get_remote_address(call));
850 * Retrieves the call's current state.
852 LinphoneCallState linphone_call_get_state(const LinphoneCall *call){
857 * Returns the reason for a call termination (either error or normal termination)
859 LinphoneReason linphone_call_get_reason(const LinphoneCall *call){
864 * Get the user_pointer in the LinphoneCall
866 * @ingroup call_control
868 * return user_pointer an opaque user pointer that can be retrieved at any time
870 void *linphone_call_get_user_pointer(LinphoneCall *call)
872 return call->user_pointer;
876 * Set the user_pointer in the LinphoneCall
878 * @ingroup call_control
880 * the user_pointer is an opaque user pointer that can be retrieved at any time in the LinphoneCall
882 void linphone_call_set_user_pointer(LinphoneCall *call, void *user_pointer)
884 call->user_pointer = user_pointer;
888 * Returns the call log associated to this call.
890 LinphoneCallLog *linphone_call_get_call_log(const LinphoneCall *call){
895 * Returns the refer-to uri (if the call was transfered).
897 const char *linphone_call_get_refer_to(const LinphoneCall *call){
898 return call->refer_to;
902 * Returns direction of the call (incoming or outgoing).
904 LinphoneCallDir linphone_call_get_dir(const LinphoneCall *call){
905 return call->log->dir;
909 * Returns the far end's user agent description string, if available.
911 const char *linphone_call_get_remote_user_agent(LinphoneCall *call){
913 return sal_op_get_remote_ua (call->op);
919 * Returns the far end's sip contact as a string, if available.
921 const char *linphone_call_get_remote_contact(LinphoneCall *call){
923 return sal_op_get_remote_contact(call->op);
929 * Returns true if this calls has received a transfer that has not been
931 * Pending transfers are executed when this call is being paused or closed,
932 * locally or by remote endpoint.
933 * If the call is already paused while receiving the transfer request, the
934 * transfer immediately occurs.
936 bool_t linphone_call_has_transfer_pending(const LinphoneCall *call){
937 return call->refer_pending;
941 * Returns call's duration in seconds.
943 int linphone_call_get_duration(const LinphoneCall *call){
944 if (call->media_start_time==0) return 0;
945 return time(NULL)-call->media_start_time;
949 * Returns the call object this call is replacing, if any.
950 * Call replacement can occur during call transfers.
951 * By default, the core automatically terminates the replaced call and accept the new one.
952 * This function allows the application to know whether a new incoming call is a one that replaces another one.
954 LinphoneCall *linphone_call_get_replaced_call(LinphoneCall *call){
955 SalOp *op=sal_call_get_replaces(call->op);
957 return (LinphoneCall*)sal_op_get_user_pointer(op);
963 * Indicate whether camera input should be sent to remote end.
965 void linphone_call_enable_camera (LinphoneCall *call, bool_t enable){
967 if (call->videostream!=NULL && call->videostream->ms.ticker!=NULL){
968 LinphoneCore *lc=call->core;
969 MSWebCam *nowebcam=get_nowebcam_device();
970 if (call->camera_active!=enable && lc->video_conf.device!=nowebcam){
971 video_stream_change_camera(call->videostream,
972 enable ? lc->video_conf.device : nowebcam);
975 call->camera_active=enable;
981 * Request remote side to send us a Video Fast Update.
983 void linphone_call_send_vfu_request(LinphoneCall *call)
985 if (LinphoneCallStreamsRunning == linphone_call_get_state(call))
986 sal_call_send_vfu_request(call->op);
992 * Take a photo of currently received video and write it into a jpeg file.
994 int linphone_call_take_video_snapshot(LinphoneCall *call, const char *file){
996 if (call->videostream!=NULL && call->videostream->jpegwriter!=NULL){
997 return ms_filter_call_method(call->videostream->jpegwriter,MS_JPEG_WRITER_TAKE_SNAPSHOT,(void*)file);
999 ms_warning("Cannot take snapshot: no currently running video stream on this call.");
1006 * Returns TRUE if camera pictures are sent to the remote party.
1008 bool_t linphone_call_camera_enabled (const LinphoneCall *call){
1009 return call->camera_active;
1013 * Enable video stream.
1015 void linphone_call_params_enable_video(LinphoneCallParams *cp, bool_t enabled){
1016 cp->has_video=enabled;
1020 * Returns the audio codec used in the call, described as a PayloadType structure.
1022 const PayloadType* linphone_call_params_get_used_audio_codec(const LinphoneCallParams *cp) {
1023 return cp->audio_codec;
1028 * Returns the video codec used in the call, described as a PayloadType structure.
1030 const PayloadType* linphone_call_params_get_used_video_codec(const LinphoneCallParams *cp) {
1031 return cp->video_codec;
1035 * @ingroup call_control
1036 * Use to know if this call has been configured in low bandwidth mode.
1037 * This mode can be automatically discovered thanks to a stun server when activate_edge_workarounds=1 in section [net] of configuration file.
1038 * An application that would have reliable way to know network capacity may not use activate_edge_workarounds=1 but instead manually configure
1039 * low bandwidth mode with linphone_call_params_enable_low_bandwidth().
1040 * <br> When enabled, this param may transform a call request with video in audio only mode.
1041 * @return TRUE if low bandwidth has been configured/detected
1043 bool_t linphone_call_params_low_bandwidth_enabled(const LinphoneCallParams *cp) {
1044 return cp->low_bandwidth;
1048 * @ingroup call_control
1049 * Indicate low bandwith mode.
1050 * 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
1051 * 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
1052 * that it is achievable by the codec selected after SDP handshake. Video is automatically disabled.
1055 void linphone_call_params_enable_low_bandwidth(LinphoneCallParams *cp, bool_t enabled){
1056 cp->low_bandwidth=enabled;
1060 * Returns whether video is enabled.
1062 bool_t linphone_call_params_video_enabled(const LinphoneCallParams *cp){
1063 return cp->has_video;
1067 * Returns kind of media encryption selected for the call.
1069 enum LinphoneMediaEncryption linphone_call_params_get_media_encryption(const LinphoneCallParams *cp) {
1070 return cp->media_encryption;
1074 * Set requested media encryption for a call.
1076 void linphone_call_params_set_media_encryption(LinphoneCallParams *cp, enum LinphoneMediaEncryption e) {
1077 cp->media_encryption = e;
1082 * Enable sending of real early media (during outgoing calls).
1084 void linphone_call_params_enable_early_media_sending(LinphoneCallParams *cp, bool_t enabled){
1085 cp->real_early_media=enabled;
1089 * Indicates whether sending of early media was enabled.
1091 bool_t linphone_call_params_early_media_sending_enabled(const LinphoneCallParams *cp){
1092 return cp->real_early_media;
1096 * Returns true if the call is part of the locally managed conference.
1098 bool_t linphone_call_params_local_conference_mode(const LinphoneCallParams *cp){
1099 return cp->in_conference;
1103 * Refine bandwidth settings for this call by setting a bandwidth limit for audio streams.
1104 * As a consequence, codecs whose bitrates are not compatible with this limit won't be used.
1106 void linphone_call_params_set_audio_bandwidth_limit(LinphoneCallParams *cp, int bandwidth){
1107 cp->audio_bw=bandwidth;
1110 void linphone_call_params_add_custom_header(LinphoneCallParams *params, const char *header_name, const char *header_value){
1111 params->custom_headers=sal_custom_header_append(params->custom_headers,header_name,header_value);
1114 const char *linphone_call_params_get_custom_header(const LinphoneCallParams *params, const char *header_name){
1115 return sal_custom_header_find(params->custom_headers,header_name);
1118 void _linphone_call_params_copy(LinphoneCallParams *ncp, const LinphoneCallParams *cp){
1119 memcpy(ncp,cp,sizeof(LinphoneCallParams));
1120 if (cp->record_file) ncp->record_file=ms_strdup(cp->record_file);
1122 * The management of the custom headers is not optimal. We copy everything while ref counting would be more efficient.
1124 if (cp->custom_headers) ncp->custom_headers=sal_custom_header_clone(cp->custom_headers);
1128 * Copy existing LinphoneCallParams to a new LinphoneCallParams object.
1130 LinphoneCallParams * linphone_call_params_copy(const LinphoneCallParams *cp){
1131 LinphoneCallParams *ncp=ms_new0(LinphoneCallParams,1);
1132 _linphone_call_params_copy(ncp,cp);
1136 void linphone_call_params_uninit(LinphoneCallParams *p){
1137 if (p->record_file) ms_free(p->record_file);
1138 if (p->custom_headers) sal_custom_header_free(p->custom_headers);
1142 * Destroy LinphoneCallParams.
1144 void linphone_call_params_destroy(LinphoneCallParams *p){
1145 linphone_call_params_uninit(p);
1155 #ifdef TEST_EXT_RENDERER
1156 static void rendercb(void *data, const MSPicture *local, const MSPicture *remote){
1157 ms_message("rendercb, local buffer=%p, remote buffer=%p",
1158 local ? local->planes[0] : NULL, remote? remote->planes[0] : NULL);
1162 #ifdef VIDEO_ENABLED
1163 static void video_stream_event_cb(void *user_pointer, const MSFilter *f, const unsigned int event_id, const void *args){
1164 LinphoneCall* call = (LinphoneCall*) user_pointer;
1165 ms_warning("In linphonecall.c: video_stream_event_cb");
1167 case MS_VIDEO_DECODER_DECODING_ERRORS:
1168 ms_warning("Case is MS_VIDEO_DECODER_DECODING_ERRORS");
1169 linphone_call_send_vfu_request(call);
1171 case MS_VIDEO_DECODER_FIRST_IMAGE_DECODED:
1172 ms_message("First video frame decoded successfully");
1173 if (call->nextVideoFrameDecoded._func != NULL)
1174 call->nextVideoFrameDecoded._func(call, call->nextVideoFrameDecoded._user_data);
1177 ms_warning("Unhandled event %i", event_id);
1183 void linphone_call_set_next_video_frame_decoded_callback(LinphoneCall *call, LinphoneCallCbFunc cb, void* user_data) {
1184 call->nextVideoFrameDecoded._func = cb;
1185 call->nextVideoFrameDecoded._user_data = user_data;
1186 #ifdef VIDEO_ENABLED
1187 ms_filter_call_method_noarg(call->videostream->ms.decoder, MS_VIDEO_DECODER_RESET_FIRST_IMAGE_NOTIFICATION);
1191 void linphone_call_init_audio_stream(LinphoneCall *call){
1192 LinphoneCore *lc=call->core;
1193 AudioStream *audiostream;
1196 if (call->audiostream != NULL) return;
1197 call->audiostream=audiostream=audio_stream_new(call->audio_port,call->audio_port+1,linphone_core_ipv6_enabled(lc));
1198 dscp=linphone_core_get_audio_dscp(lc);
1200 audio_stream_set_dscp(audiostream,dscp);
1201 if (linphone_core_echo_limiter_enabled(lc)){
1202 const char *type=lp_config_get_string(lc->config,"sound","el_type","mic");
1203 if (strcasecmp(type,"mic")==0)
1204 audio_stream_enable_echo_limiter(audiostream,ELControlMic);
1205 else if (strcasecmp(type,"full")==0)
1206 audio_stream_enable_echo_limiter(audiostream,ELControlFull);
1208 audio_stream_enable_gain_control(audiostream,TRUE);
1209 if (linphone_core_echo_cancellation_enabled(lc)){
1210 int len,delay,framesize;
1211 const char *statestr=lp_config_get_string(lc->config,"sound","ec_state",NULL);
1212 len=lp_config_get_int(lc->config,"sound","ec_tail_len",0);
1213 delay=lp_config_get_int(lc->config,"sound","ec_delay",0);
1214 framesize=lp_config_get_int(lc->config,"sound","ec_framesize",0);
1215 audio_stream_set_echo_canceller_params(audiostream,len,delay,framesize);
1216 if (statestr && audiostream->ec){
1217 ms_filter_call_method(audiostream->ec,MS_ECHO_CANCELLER_SET_STATE_STRING,(void*)statestr);
1220 audio_stream_enable_automatic_gain_control(audiostream,linphone_core_agc_enabled(lc));
1222 int enabled=lp_config_get_int(lc->config,"sound","noisegate",0);
1223 audio_stream_enable_noise_gate(audiostream,enabled);
1226 audio_stream_set_features(audiostream,linphone_core_get_audio_features(lc));
1229 RtpTransport *artp=lc->rtptf->audio_rtp_func(lc->rtptf->audio_rtp_func_data, call->audio_port);
1230 RtpTransport *artcp=lc->rtptf->audio_rtcp_func(lc->rtptf->audio_rtcp_func_data, call->audio_port+1);
1231 rtp_session_set_transports(audiostream->ms.session,artp,artcp);
1233 if ((linphone_core_get_firewall_policy(lc) == LinphonePolicyUseIce) && (call->ice_session != NULL)){
1234 rtp_session_set_pktinfo(audiostream->ms.session, TRUE);
1235 rtp_session_set_symmetric_rtp(audiostream->ms.session, FALSE);
1236 if (ice_session_check_list(call->ice_session, 0) == NULL) {
1237 ice_session_add_check_list(call->ice_session, ice_check_list_new());
1239 audiostream->ms.ice_check_list = ice_session_check_list(call->ice_session, 0);
1240 ice_check_list_set_rtp_session(audiostream->ms.ice_check_list, audiostream->ms.session);
1243 call->audiostream_app_evq = ortp_ev_queue_new();
1244 rtp_session_register_event_queue(audiostream->ms.session,call->audiostream_app_evq);
1247 void linphone_call_init_video_stream(LinphoneCall *call){
1248 #ifdef VIDEO_ENABLED
1249 LinphoneCore *lc=call->core;
1251 if (!call->params.has_video) {
1252 linphone_call_stop_video_stream(call);
1255 if (call->videostream != NULL) return;
1256 if ((lc->video_conf.display || lc->video_conf.capture) && call->params.has_video){
1257 int video_recv_buf_size=lp_config_get_int(lc->config,"video","recv_buf_size",0);
1258 int dscp=linphone_core_get_video_dscp(lc);
1260 call->videostream=video_stream_new(call->video_port,call->video_port+1,linphone_core_ipv6_enabled(lc));
1262 video_stream_set_dscp(call->videostream,dscp);
1263 video_stream_enable_display_filter_auto_rotate(call->videostream, lp_config_get_int(lc->config,"video","display_filter_auto_rotate",0));
1264 if (video_recv_buf_size>0) rtp_session_set_recv_buf_size(call->videostream->ms.session,video_recv_buf_size);
1266 if( lc->video_conf.displaytype != NULL)
1267 video_stream_set_display_filter_name(call->videostream,lc->video_conf.displaytype);
1268 video_stream_set_event_callback(call->videostream,video_stream_event_cb, call);
1270 RtpTransport *vrtp=lc->rtptf->video_rtp_func(lc->rtptf->video_rtp_func_data, call->video_port);
1271 RtpTransport *vrtcp=lc->rtptf->video_rtcp_func(lc->rtptf->video_rtcp_func_data, call->video_port+1);
1272 rtp_session_set_transports(call->videostream->ms.session,vrtp,vrtcp);
1274 if ((linphone_core_get_firewall_policy(lc) == LinphonePolicyUseIce) && (call->ice_session != NULL)){
1275 rtp_session_set_pktinfo(call->videostream->ms.session, TRUE);
1276 rtp_session_set_symmetric_rtp(call->videostream->ms.session, FALSE);
1277 if (ice_session_check_list(call->ice_session, 1) == NULL) {
1278 ice_session_add_check_list(call->ice_session, ice_check_list_new());
1280 call->videostream->ms.ice_check_list = ice_session_check_list(call->ice_session, 1);
1281 ice_check_list_set_rtp_session(call->videostream->ms.ice_check_list, call->videostream->ms.session);
1283 call->videostream_app_evq = ortp_ev_queue_new();
1284 rtp_session_register_event_queue(call->videostream->ms.session,call->videostream_app_evq);
1285 #ifdef TEST_EXT_RENDERER
1286 video_stream_set_render_callback(call->videostream,rendercb,NULL);
1290 call->videostream=NULL;
1294 void linphone_call_init_media_streams(LinphoneCall *call){
1295 linphone_call_init_audio_stream(call);
1296 linphone_call_init_video_stream(call);
1300 static int dtmf_tab[16]={'0','1','2','3','4','5','6','7','8','9','*','#','A','B','C','D'};
1302 static void linphone_core_dtmf_received(LinphoneCore *lc, int dtmf){
1303 if (dtmf<0 || dtmf>15){
1304 ms_warning("Bad dtmf value %i",dtmf);
1307 if (lc->vtable.dtmf_received != NULL)
1308 lc->vtable.dtmf_received(lc, linphone_core_get_current_call(lc), dtmf_tab[dtmf]);
1311 static void parametrize_equalizer(LinphoneCore *lc, AudioStream *st){
1313 MSFilter *f=st->equalizer;
1314 int enabled=lp_config_get_int(lc->config,"sound","eq_active",0);
1315 const char *gains=lp_config_get_string(lc->config,"sound","eq_gains",NULL);
1316 ms_filter_call_method(f,MS_EQUALIZER_SET_ACTIVE,&enabled);
1322 if (sscanf(gains,"%f:%f:%f %n",&g.frequency,&g.gain,&g.width,&bytes)==3){
1323 ms_message("Read equalizer gains: %f(~%f) --> %f",g.frequency,g.width,g.gain);
1324 ms_filter_call_method(f,MS_EQUALIZER_SET_GAIN,&g);
1333 void _post_configure_audio_stream(AudioStream *st, LinphoneCore *lc, bool_t muted){
1334 float mic_gain=lc->sound_conf.soft_mic_lev;
1337 float ng_thres=lp_config_get_float(lc->config,"sound","ng_thres",0.05);
1338 float ng_floorgain=lp_config_get_float(lc->config,"sound","ng_floorgain",0);
1339 int dc_removal=lp_config_get_int(lc->config,"sound","dc_removal",0);
1342 linphone_core_set_mic_gain_db (lc, mic_gain);
1344 audio_stream_set_mic_gain(st,0);
1346 recv_gain = lc->sound_conf.soft_play_lev;
1347 if (recv_gain != 0) {
1348 linphone_core_set_playback_gain_db (lc,recv_gain);
1352 ms_filter_call_method(st->volsend,MS_VOLUME_REMOVE_DC,&dc_removal);
1353 float speed=lp_config_get_float(lc->config,"sound","el_speed",-1);
1354 thres=lp_config_get_float(lc->config,"sound","el_thres",-1);
1355 float force=lp_config_get_float(lc->config,"sound","el_force",-1);
1356 int sustain=lp_config_get_int(lc->config,"sound","el_sustain",-1);
1357 float transmit_thres=lp_config_get_float(lc->config,"sound","el_transmit_thres",-1);
1360 if (speed==-1) speed=0.03;
1361 if (force==-1) force=25;
1362 ms_filter_call_method(f,MS_VOLUME_SET_EA_SPEED,&speed);
1363 ms_filter_call_method(f,MS_VOLUME_SET_EA_FORCE,&force);
1365 ms_filter_call_method(f,MS_VOLUME_SET_EA_THRESHOLD,&thres);
1367 ms_filter_call_method(f,MS_VOLUME_SET_EA_SUSTAIN,&sustain);
1368 if (transmit_thres!=-1)
1369 ms_filter_call_method(f,MS_VOLUME_SET_EA_TRANSMIT_THRESHOLD,&transmit_thres);
1371 ms_filter_call_method(st->volsend,MS_VOLUME_SET_NOISE_GATE_THRESHOLD,&ng_thres);
1372 ms_filter_call_method(st->volsend,MS_VOLUME_SET_NOISE_GATE_FLOORGAIN,&ng_floorgain);
1375 /* parameters for a limited noise-gate effect, using echo limiter threshold */
1376 float floorgain = 1/pow(10,(mic_gain)/10);
1377 int spk_agc=lp_config_get_int(lc->config,"sound","speaker_agc_enabled",0);
1378 ms_filter_call_method(st->volrecv, MS_VOLUME_ENABLE_AGC, &spk_agc);
1379 ms_filter_call_method(st->volrecv,MS_VOLUME_SET_NOISE_GATE_THRESHOLD,&ng_thres);
1380 ms_filter_call_method(st->volrecv,MS_VOLUME_SET_NOISE_GATE_FLOORGAIN,&floorgain);
1382 parametrize_equalizer(lc,st);
1385 static void post_configure_audio_streams(LinphoneCall*call){
1386 AudioStream *st=call->audiostream;
1387 LinphoneCore *lc=call->core;
1388 _post_configure_audio_stream(st,lc,call->audio_muted);
1389 if (lc->vtable.dtmf_received!=NULL){
1390 audio_stream_play_received_dtmfs(call->audiostream,FALSE);
1392 if (call->record_active)
1393 linphone_call_start_recording(call);
1396 static RtpProfile *make_profile(LinphoneCall *call, const SalMediaDescription *md, const SalStreamDescription *desc, int *used_pt){
1399 RtpProfile *prof=rtp_profile_new("Call profile");
1402 LinphoneCore *lc=call->core;
1404 const LinphoneCallParams *params=&call->params;
1407 for(elem=desc->payloads;elem!=NULL;elem=elem->next){
1408 PayloadType *pt=(PayloadType*)elem->data;
1411 if ((pt->flags & PAYLOAD_TYPE_FLAG_CAN_SEND) && first) {
1412 if (desc->type==SalAudio){
1413 linphone_core_update_allocated_audio_bandwidth_in_call(call,pt);
1414 if (params->up_ptime)
1415 up_ptime=params->up_ptime;
1416 else up_ptime=linphone_core_get_upload_ptime(lc);
1418 *used_pt=payload_type_get_number(pt);
1421 if (desc->bandwidth>0) remote_bw=desc->bandwidth;
1422 else if (md->bandwidth>0) {
1423 /*case where b=AS is given globally, not per stream*/
1424 remote_bw=md->bandwidth;
1425 if (desc->type==SalVideo){
1426 remote_bw=get_video_bandwidth(remote_bw,call->audio_bw);
1430 if (desc->type==SalAudio){
1431 int audio_bw=call->audio_bw;
1433 if (params->up_bw< audio_bw)
1434 audio_bw=params->up_bw;
1436 bw=get_min_bandwidth(audio_bw,remote_bw);
1437 }else bw=get_min_bandwidth(get_video_bandwidth(linphone_core_get_upload_bandwidth (lc),call->audio_bw),remote_bw);
1438 if (bw>0) pt->normal_bitrate=bw*1000;
1439 else if (desc->type==SalAudio){
1440 pt->normal_bitrate=-1;
1443 up_ptime=desc->ptime;
1447 snprintf(tmp,sizeof(tmp),"ptime=%i",up_ptime);
1448 payload_type_append_send_fmtp(pt,tmp);
1450 number=payload_type_get_number(pt);
1451 if (rtp_profile_get_payload(prof,number)!=NULL){
1452 ms_warning("A payload type with number %i already exists in profile !",number);
1454 rtp_profile_set_payload(prof,number,pt);
1460 static void setup_ring_player(LinphoneCore *lc, LinphoneCall *call){
1461 int pause_time=3000;
1462 audio_stream_play(call->audiostream,lc->sound_conf.ringback_tone);
1463 ms_filter_call_method(call->audiostream->soundread,MS_FILE_PLAYER_LOOP,&pause_time);
1466 static bool_t linphone_call_sound_resources_available(LinphoneCall *call){
1467 LinphoneCore *lc=call->core;
1468 LinphoneCall *current=linphone_core_get_current_call(lc);
1469 return !linphone_core_is_in_conference(lc) &&
1470 (current==NULL || current==call);
1472 static int find_crypto_index_from_tag(const SalSrtpCryptoAlgo crypto[],unsigned char tag) {
1474 for(i=0; i<SAL_CRYPTO_ALGO_MAX; i++) {
1475 if (crypto[i].tag == tag) {
1481 static void linphone_call_start_audio_stream(LinphoneCall *call, const char *cname, bool_t muted, bool_t send_ringbacktone, bool_t use_arc){
1482 LinphoneCore *lc=call->core;
1484 char rtcp_tool[128]={0};
1485 snprintf(rtcp_tool,sizeof(rtcp_tool)-1,"%s-%s",linphone_core_get_user_agent_name(),linphone_core_get_user_agent_version());
1486 /* look for savp stream first */
1487 const SalStreamDescription *stream=sal_media_description_find_stream(call->resultdesc,
1488 SalProtoRtpSavp,SalAudio);
1489 /* no savp audio stream, use avp */
1491 stream=sal_media_description_find_stream(call->resultdesc,
1492 SalProtoRtpAvp,SalAudio);
1494 if (stream && stream->dir!=SalStreamInactive && stream->rtp_port!=0){
1495 MSSndCard *playcard=lc->sound_conf.lsd_card ?
1496 lc->sound_conf.lsd_card : lc->sound_conf.play_sndcard;
1497 MSSndCard *captcard=lc->sound_conf.capt_sndcard;
1498 const char *playfile=lc->play_file;
1499 const char *recfile=lc->rec_file;
1500 call->audio_profile=make_profile(call,call->resultdesc,stream,&used_pt);
1504 call->current_params.audio_codec = rtp_profile_get_payload(call->audio_profile, used_pt);
1505 if (playcard==NULL) {
1506 ms_warning("No card defined for playback !");
1508 if (captcard==NULL) {
1509 ms_warning("No card defined for capture !");
1511 /*Replace soundcard filters by inactive file players or recorders
1512 when placed in recvonly or sendonly mode*/
1513 if (stream->rtp_port==0 || stream->dir==SalStreamRecvOnly){
1516 }else if (stream->dir==SalStreamSendOnly){
1520 /*And we will eventually play "playfile" if set by the user*/
1523 if (send_ringbacktone){
1525 playfile=NULL;/* it is setup later*/
1527 /*if playfile are supplied don't use soundcards*/
1528 if (lc->use_files) {
1532 if (call->params.in_conference){
1533 /* first create the graph without soundcard resources*/
1534 captcard=playcard=NULL;
1536 if (!linphone_call_sound_resources_available(call)){
1537 ms_message("Sound resources are used by another call, not using soundcard.");
1538 captcard=playcard=NULL;
1540 use_ec=captcard==NULL ? FALSE : linphone_core_echo_cancellation_enabled(lc);
1541 if (playcard && stream->max_rate>0) ms_snd_card_set_preferred_sample_rate(playcard, stream->max_rate);
1542 if (captcard && stream->max_rate>0) ms_snd_card_set_preferred_sample_rate(captcard, stream->max_rate);
1543 audio_stream_enable_adaptive_bitrate_control(call->audiostream,use_arc);
1544 audio_stream_enable_adaptive_jittcomp(call->audiostream, linphone_core_audio_adaptive_jittcomp_enabled(lc));
1545 if (!call->params.in_conference && call->params.record_file)
1546 audio_stream_mixed_record_open(call->audiostream,call->params.record_file);
1547 audio_stream_start_full(
1549 call->audio_profile,
1550 stream->rtp_addr[0]!='\0' ? stream->rtp_addr : call->resultdesc->addr,
1552 stream->rtcp_addr[0]!='\0' ? stream->rtcp_addr : call->resultdesc->addr,
1553 linphone_core_rtcp_enabled(lc) ? (stream->rtcp_port) : 0,
1555 linphone_core_get_audio_jittcomp(lc),
1562 post_configure_audio_streams(call);
1563 if (muted && !send_ringbacktone){
1564 audio_stream_set_mic_gain(call->audiostream,0);
1566 if (stream->dir==SalStreamSendOnly && playfile!=NULL){
1568 ms_filter_call_method(call->audiostream->soundread,MS_FILE_PLAYER_LOOP,&pause_time);
1570 if (send_ringbacktone){
1571 setup_ring_player(lc,call);
1573 audio_stream_set_rtcp_information(call->audiostream, cname, rtcp_tool);
1575 /* valid local tags are > 0 */
1576 if (stream->proto == SalProtoRtpSavp) {
1577 const SalStreamDescription *local_st_desc=sal_media_description_find_stream(call->localdesc,
1578 SalProtoRtpSavp,SalAudio);
1579 int crypto_idx = find_crypto_index_from_tag(local_st_desc->crypto, stream->crypto_local_tag);
1581 if (crypto_idx >= 0) {
1582 audio_stream_enable_srtp(
1584 stream->crypto[0].algo,
1585 local_st_desc->crypto[crypto_idx].master_key,
1586 stream->crypto[0].master_key);
1587 call->audiostream_encrypted=TRUE;
1589 ms_warning("Failed to find local crypto algo with tag: %d", stream->crypto_local_tag);
1590 call->audiostream_encrypted=FALSE;
1592 }else call->audiostream_encrypted=FALSE;
1593 if (call->params.in_conference){
1594 /*transform the graph to connect it to the conference filter */
1595 bool_t mute=stream->dir==SalStreamRecvOnly;
1596 linphone_call_add_to_conf(call, mute);
1598 call->current_params.in_conference=call->params.in_conference;
1599 call->current_params.low_bandwidth=call->params.low_bandwidth;
1600 }else ms_warning("No audio stream accepted ?");
1604 static void linphone_call_start_video_stream(LinphoneCall *call, const char *cname,bool_t all_inputs_muted){
1605 #ifdef VIDEO_ENABLED
1606 LinphoneCore *lc=call->core;
1608 /* look for savp stream first */
1609 const SalStreamDescription *vstream=sal_media_description_find_stream(call->resultdesc,
1610 SalProtoRtpSavp,SalVideo);
1611 char rtcp_tool[128]={0};
1612 snprintf(rtcp_tool,sizeof(rtcp_tool)-1,"%s-%s",linphone_core_get_user_agent_name(),linphone_core_get_user_agent_version());
1614 /* no savp audio stream, use avp */
1616 vstream=sal_media_description_find_stream(call->resultdesc,
1617 SalProtoRtpAvp,SalVideo);
1619 /* shutdown preview */
1620 if (lc->previewstream!=NULL) {
1621 video_preview_stop(lc->previewstream);
1622 lc->previewstream=NULL;
1625 if (vstream!=NULL && vstream->dir!=SalStreamInactive && vstream->rtp_port!=0) {
1626 const char *rtp_addr=vstream->rtp_addr[0]!='\0' ? vstream->rtp_addr : call->resultdesc->addr;
1627 const char *rtcp_addr=vstream->rtcp_addr[0]!='\0' ? vstream->rtcp_addr : call->resultdesc->addr;
1628 call->video_profile=make_profile(call,call->resultdesc,vstream,&used_pt);
1630 call->current_params.video_codec = rtp_profile_get_payload(call->video_profile, used_pt);
1631 VideoStreamDir dir=VideoStreamSendRecv;
1632 MSWebCam *cam=lc->video_conf.device;
1633 bool_t is_inactive=FALSE;
1635 call->current_params.has_video=TRUE;
1637 video_stream_enable_adaptive_bitrate_control(call->videostream,
1638 linphone_core_adaptive_rate_control_enabled(lc));
1639 video_stream_enable_adaptive_jittcomp(call->videostream, linphone_core_video_adaptive_jittcomp_enabled(lc));
1640 video_stream_set_sent_video_size(call->videostream,linphone_core_get_preferred_video_size(lc));
1641 video_stream_enable_self_view(call->videostream,lc->video_conf.selfview);
1642 if (lc->video_window_id!=0)
1643 video_stream_set_native_window_id(call->videostream,lc->video_window_id);
1644 if (lc->preview_window_id!=0)
1645 video_stream_set_native_preview_window_id (call->videostream,lc->preview_window_id);
1646 video_stream_use_preview_video_window (call->videostream,lc->use_preview_window);
1648 if (vstream->dir==SalStreamSendOnly && lc->video_conf.capture ){
1649 cam=get_nowebcam_device();
1650 dir=VideoStreamSendOnly;
1651 }else if (vstream->dir==SalStreamRecvOnly && lc->video_conf.display ){
1652 dir=VideoStreamRecvOnly;
1653 }else if (vstream->dir==SalStreamSendRecv){
1654 if (lc->video_conf.display && lc->video_conf.capture)
1655 dir=VideoStreamSendRecv;
1656 else if (lc->video_conf.display)
1657 dir=VideoStreamRecvOnly;
1659 dir=VideoStreamSendOnly;
1661 ms_warning("video stream is inactive.");
1662 /*either inactive or incompatible with local capabilities*/
1665 if (call->camera_active==FALSE || all_inputs_muted){
1666 cam=get_nowebcam_device();
1669 call->log->video_enabled = TRUE;
1670 video_stream_set_direction (call->videostream, dir);
1671 ms_message("%s lc rotation:%d\n", __FUNCTION__, lc->device_rotation);
1672 video_stream_set_device_rotation(call->videostream, lc->device_rotation);
1673 video_stream_start(call->videostream,
1674 call->video_profile, rtp_addr, vstream->rtp_port,
1675 rtcp_addr, linphone_core_rtcp_enabled(lc) ? (vstream->rtcp_port) : 0,
1676 used_pt, linphone_core_get_video_jittcomp(lc), cam);
1677 video_stream_set_rtcp_information(call->videostream, cname,rtcp_tool);
1680 if (vstream->proto == SalProtoRtpSavp) {
1681 const SalStreamDescription *local_st_desc=sal_media_description_find_stream(call->localdesc,
1682 SalProtoRtpSavp,SalVideo);
1684 video_stream_enable_strp(
1686 vstream->crypto[0].algo,
1687 local_st_desc->crypto[0].master_key,
1688 vstream->crypto[0].master_key
1690 call->videostream_encrypted=TRUE;
1692 call->videostream_encrypted=FALSE;
1694 }else ms_warning("No video stream accepted.");
1696 ms_warning("No valid video stream defined.");
1701 void linphone_call_start_media_streams(LinphoneCall *call, bool_t all_inputs_muted, bool_t send_ringbacktone){
1702 LinphoneCore *lc=call->core;
1704 call->current_params.audio_codec = NULL;
1705 call->current_params.video_codec = NULL;
1707 LinphoneAddress *me=linphone_core_get_primary_contact_parsed(lc);
1709 bool_t use_arc=linphone_core_adaptive_rate_control_enabled(lc);
1710 #ifdef VIDEO_ENABLED
1711 const SalStreamDescription *vstream=sal_media_description_find_stream(call->resultdesc,
1712 SalProtoRtpAvp,SalVideo);
1715 if ((call->audiostream == NULL) && (call->videostream == NULL)) {
1716 ms_fatal("start_media_stream() called without prior init !");
1719 cname=linphone_address_as_string_uri_only(me);
1721 #if defined(VIDEO_ENABLED)
1722 if (vstream!=NULL && vstream->dir!=SalStreamInactive && vstream->payloads!=NULL){
1723 /*when video is used, do not make adaptive rate control on audio, it is stupid.*/
1727 if (call->audiostream!=NULL) {
1728 linphone_call_start_audio_stream(call,cname,all_inputs_muted,send_ringbacktone,use_arc);
1730 call->current_params.has_video=FALSE;
1731 if (call->videostream!=NULL) {
1732 linphone_call_start_video_stream(call,cname,all_inputs_muted);
1735 call->all_muted=all_inputs_muted;
1736 call->playing_ringbacktone=send_ringbacktone;
1737 call->up_bw=linphone_core_get_upload_bandwidth(lc);
1739 if (call->params.media_encryption==LinphoneMediaEncryptionZRTP) {
1740 OrtpZrtpParams params;
1741 /*will be set later when zrtp is activated*/
1742 call->current_params.media_encryption=LinphoneMediaEncryptionNone;
1744 params.zid_file=lc->zrtp_secrets_cache;
1745 audio_stream_enable_zrtp(call->audiostream,¶ms);
1746 }else if (call->params.media_encryption==LinphoneMediaEncryptionSRTP){
1747 call->current_params.media_encryption=linphone_call_are_all_streams_encrypted(call) ?
1748 LinphoneMediaEncryptionSRTP : LinphoneMediaEncryptionNone;
1751 /*also reflect the change if the "wished" params, in order to avoid to propose SAVP or video again
1752 * further in the call, for example during pause,resume, conferencing reINVITEs*/
1753 linphone_call_fix_call_parameters(call);
1754 if ((call->ice_session != NULL) && (ice_session_state(call->ice_session) != IS_Completed)) {
1755 ice_session_start_connectivity_checks(call->ice_session);
1761 linphone_address_destroy(me);
1764 void linphone_call_start_media_streams_for_ice_gathering(LinphoneCall *call){
1765 audio_stream_prepare_sound(call->audiostream, NULL, NULL);
1766 #ifdef VIDEO_ENABLED
1767 if (call->videostream) {
1768 video_stream_prepare_video(call->videostream);
1773 void linphone_call_stop_media_streams_for_ice_gathering(LinphoneCall *call){
1774 audio_stream_unprepare_sound(call->audiostream);
1775 #ifdef VIDEO_ENABLED
1776 if (call->videostream) {
1777 video_stream_unprepare_video(call->videostream);
1782 void linphone_call_update_crypto_parameters(LinphoneCall *call, SalMediaDescription *old_md, SalMediaDescription *new_md) {
1783 SalStreamDescription *old_stream;
1784 SalStreamDescription *new_stream;
1787 old_stream = sal_media_description_find_stream(old_md, SalProtoRtpSavp, SalAudio);
1788 new_stream = sal_media_description_find_stream(new_md, SalProtoRtpSavp, SalAudio);
1789 if (old_stream && new_stream) {
1790 const SalStreamDescription *local_st_desc = sal_media_description_find_stream(call->localdesc, SalProtoRtpSavp, SalAudio);
1791 if (local_st_desc) {
1792 int crypto_idx = find_crypto_index_from_tag(local_st_desc->crypto, new_stream->crypto_local_tag);
1793 if (crypto_idx >= 0) {
1794 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);
1795 call->audiostream_encrypted = TRUE;
1797 ms_warning("Failed to find local crypto algo with tag: %d", new_stream->crypto_local_tag);
1798 call->audiostream_encrypted = FALSE;
1800 for (i = 0; i < SAL_CRYPTO_ALGO_MAX; i++) {
1801 old_stream->crypto[i].tag = new_stream->crypto[i].tag;
1802 old_stream->crypto[i].algo = new_stream->crypto[i].algo;
1803 strncpy(old_stream->crypto[i].master_key, new_stream->crypto[i].master_key, sizeof(old_stream->crypto[i].master_key) - 1);
1808 #ifdef VIDEO_ENABLED
1809 old_stream = sal_media_description_find_stream(old_md, SalProtoRtpSavp, SalVideo);
1810 new_stream = sal_media_description_find_stream(new_md, SalProtoRtpSavp, SalVideo);
1811 if (old_stream && new_stream) {
1812 const SalStreamDescription *local_st_desc = sal_media_description_find_stream(call->localdesc, SalProtoRtpSavp, SalVideo);
1813 if (local_st_desc) {
1814 int crypto_idx = find_crypto_index_from_tag(local_st_desc->crypto, new_stream->crypto_local_tag);
1815 if (crypto_idx >= 0) {
1816 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);
1817 call->videostream_encrypted = TRUE;
1819 ms_warning("Failed to find local crypto algo with tag: %d", new_stream->crypto_local_tag);
1820 call->videostream_encrypted = FALSE;
1822 for (i = 0; i < SAL_CRYPTO_ALGO_MAX; i++) {
1823 old_stream->crypto[i].tag = new_stream->crypto[i].tag;
1824 old_stream->crypto[i].algo = new_stream->crypto[i].algo;
1825 strncpy(old_stream->crypto[i].master_key, new_stream->crypto[i].master_key, sizeof(old_stream->crypto[i].master_key) - 1);
1832 void linphone_call_update_remote_session_id_and_ver(LinphoneCall *call) {
1833 SalMediaDescription *remote_desc = sal_call_get_remote_media_description(call->op);
1835 call->remote_session_id = remote_desc->session_id;
1836 call->remote_session_ver = remote_desc->session_ver;
1840 void linphone_call_delete_ice_session(LinphoneCall *call){
1841 if (call->ice_session != NULL) {
1842 ice_session_destroy(call->ice_session);
1843 call->ice_session = NULL;
1844 if (call->audiostream != NULL) call->audiostream->ms.ice_check_list = NULL;
1845 if (call->videostream != NULL) call->videostream->ms.ice_check_list = NULL;
1846 call->stats[LINPHONE_CALL_STATS_AUDIO].ice_state = LinphoneIceStateNotActivated;
1847 call->stats[LINPHONE_CALL_STATS_VIDEO].ice_state = LinphoneIceStateNotActivated;
1852 void linphone_call_delete_upnp_session(LinphoneCall *call){
1853 if(call->upnp_session!=NULL) {
1854 linphone_upnp_session_destroy(call->upnp_session);
1855 call->upnp_session=NULL;
1860 static void linphone_call_log_fill_stats(LinphoneCallLog *log, MediaStream *st){
1861 float quality=media_stream_get_average_quality_rating(st);
1863 if (log->quality!=-1){
1864 log->quality*=quality/5.0;
1865 }else log->quality=quality;
1869 void linphone_call_stop_audio_stream(LinphoneCall *call) {
1870 if (call->audiostream!=NULL) {
1871 rtp_session_unregister_event_queue(call->audiostream->ms.session,call->audiostream_app_evq);
1872 ortp_ev_queue_flush(call->audiostream_app_evq);
1873 ortp_ev_queue_destroy(call->audiostream_app_evq);
1874 call->audiostream_app_evq=NULL;
1876 if (call->audiostream->ec){
1877 const char *state_str=NULL;
1878 ms_filter_call_method(call->audiostream->ec,MS_ECHO_CANCELLER_GET_STATE_STRING,&state_str);
1880 ms_message("Writing echo canceler state, %i bytes",(int)strlen(state_str));
1881 lp_config_set_string(call->core->config,"sound","ec_state",state_str);
1884 audio_stream_get_local_rtp_stats(call->audiostream,&call->log->local_stats);
1885 linphone_call_log_fill_stats (call->log,(MediaStream*)call->audiostream);
1886 if (call->endpoint){
1887 linphone_call_remove_from_conf(call);
1889 audio_stream_stop(call->audiostream);
1890 call->audiostream=NULL;
1894 void linphone_call_stop_video_stream(LinphoneCall *call) {
1895 #ifdef VIDEO_ENABLED
1896 if (call->videostream!=NULL){
1897 rtp_session_unregister_event_queue(call->videostream->ms.session,call->videostream_app_evq);
1898 ortp_ev_queue_flush(call->videostream_app_evq);
1899 ortp_ev_queue_destroy(call->videostream_app_evq);
1900 call->videostream_app_evq=NULL;
1901 linphone_call_log_fill_stats(call->log,(MediaStream*)call->videostream);
1902 video_stream_stop(call->videostream);
1903 call->videostream=NULL;
1908 void linphone_call_stop_media_streams(LinphoneCall *call){
1909 linphone_call_stop_audio_stream(call);
1910 linphone_call_stop_video_stream(call);
1911 ms_event_queue_skip(call->core->msevq);
1913 if (call->audio_profile){
1914 rtp_profile_clear_all(call->audio_profile);
1915 rtp_profile_destroy(call->audio_profile);
1916 call->audio_profile=NULL;
1918 if (call->video_profile){
1919 rtp_profile_clear_all(call->video_profile);
1920 rtp_profile_destroy(call->video_profile);
1921 call->video_profile=NULL;
1927 void linphone_call_enable_echo_cancellation(LinphoneCall *call, bool_t enable) {
1928 if (call!=NULL && call->audiostream!=NULL && call->audiostream->ec){
1929 bool_t bypass_mode = !enable;
1930 ms_filter_call_method(call->audiostream->ec,MS_ECHO_CANCELLER_SET_BYPASS_MODE,&bypass_mode);
1933 bool_t linphone_call_echo_cancellation_enabled(LinphoneCall *call) {
1934 if (call!=NULL && call->audiostream!=NULL && call->audiostream->ec){
1936 ms_filter_call_method(call->audiostream->ec,MS_ECHO_CANCELLER_GET_BYPASS_MODE,&val);
1939 return linphone_core_echo_cancellation_enabled(call->core);
1943 void linphone_call_enable_echo_limiter(LinphoneCall *call, bool_t val){
1944 if (call!=NULL && call->audiostream!=NULL ) {
1946 const char *type=lp_config_get_string(call->core->config,"sound","el_type","mic");
1947 if (strcasecmp(type,"mic")==0)
1948 audio_stream_enable_echo_limiter(call->audiostream,ELControlMic);
1949 else if (strcasecmp(type,"full")==0)
1950 audio_stream_enable_echo_limiter(call->audiostream,ELControlFull);
1952 audio_stream_enable_echo_limiter(call->audiostream,ELInactive);
1957 bool_t linphone_call_echo_limiter_enabled(const LinphoneCall *call){
1958 if (call!=NULL && call->audiostream!=NULL ){
1959 return call->audiostream->el_type !=ELInactive ;
1961 return linphone_core_echo_limiter_enabled(call->core);
1966 * @addtogroup call_misc
1971 * Returns the measured sound volume played locally (received from remote).
1972 * It is expressed in dbm0.
1974 float linphone_call_get_play_volume(LinphoneCall *call){
1975 AudioStream *st=call->audiostream;
1976 if (st && st->volrecv){
1978 ms_filter_call_method(st->volrecv,MS_VOLUME_GET,&vol);
1982 return LINPHONE_VOLUME_DB_LOWEST;
1986 * Returns the measured sound volume recorded locally (sent to remote).
1987 * It is expressed in dbm0.
1989 float linphone_call_get_record_volume(LinphoneCall *call){
1990 AudioStream *st=call->audiostream;
1991 if (st && st->volsend && !call->audio_muted && call->state==LinphoneCallStreamsRunning){
1993 ms_filter_call_method(st->volsend,MS_VOLUME_GET,&vol);
1997 return LINPHONE_VOLUME_DB_LOWEST;
2001 * Obtain real-time quality rating of the call
2003 * Based on local RTP statistics and RTCP feedback, a quality rating is computed and updated
2004 * during all the duration of the call. This function returns its value at the time of the function call.
2005 * It is expected that the rating is updated at least every 5 seconds or so.
2006 * The rating is a floating point number comprised between 0 and 5.
2008 * 4-5 = good quality <br>
2009 * 3-4 = average quality <br>
2010 * 2-3 = poor quality <br>
2011 * 1-2 = very poor quality <br>
2012 * 0-1 = can't be worse, mostly unusable <br>
2014 * @returns The function returns -1 if no quality measurement is available, for example if no
2015 * active audio stream exist. Otherwise it returns the quality rating.
2017 float linphone_call_get_current_quality(LinphoneCall *call){
2018 float audio_rating=-1;
2019 float video_rating=-1;
2021 if (call->audiostream){
2022 audio_rating=media_stream_get_quality_rating((MediaStream*)call->audiostream)/5.0;
2024 if (call->videostream){
2025 video_rating=media_stream_get_quality_rating((MediaStream*)call->videostream)/5.0;
2027 if (audio_rating<0 && video_rating<0) result=-1;
2028 else if (audio_rating<0) result=video_rating*5.0;
2029 else if (video_rating<0) result=audio_rating*5.0;
2030 else result=audio_rating*video_rating*5.0;
2035 * Returns call quality averaged over all the duration of the call.
2037 * See linphone_call_get_current_quality() for more details about quality measurement.
2039 float linphone_call_get_average_quality(LinphoneCall *call){
2040 if (call->audiostream){
2041 return audio_stream_get_average_quality_rating(call->audiostream);
2046 static void update_local_stats(LinphoneCallStats *stats, MediaStream *stream){
2047 const MSQualityIndicator *qi=media_stream_get_quality_indicator(stream);
2049 stats->local_late_rate=ms_quality_indicator_get_local_late_rate(qi);
2050 stats->local_loss_rate=ms_quality_indicator_get_local_loss_rate(qi);
2055 * Access last known statistics for audio stream, for a given call.
2057 const LinphoneCallStats *linphone_call_get_audio_stats(LinphoneCall *call) {
2058 LinphoneCallStats *stats=&call->stats[LINPHONE_CALL_STATS_AUDIO];
2059 if (call->audiostream){
2060 update_local_stats(stats,(MediaStream*)call->audiostream);
2066 * Access last known statistics for video stream, for a given call.
2068 const LinphoneCallStats *linphone_call_get_video_stats(LinphoneCall *call) {
2069 LinphoneCallStats *stats=&call->stats[LINPHONE_CALL_STATS_VIDEO];
2070 if (call->videostream){
2071 update_local_stats(stats,(MediaStream*)call->videostream);
2077 * Enable recording of the call (voice-only).
2078 * This function must be used before the call parameters are assigned to the call.
2079 * The call recording can be started and paused after the call is established with
2080 * linphone_call_start_recording() and linphone_call_pause_recording().
2081 * @param cp the call parameters
2082 * @param path path and filename of the file where audio is written.
2084 void linphone_call_params_set_record_file(LinphoneCallParams *cp, const char *path){
2085 if (cp->record_file){
2086 ms_free(cp->record_file);
2087 cp->record_file=NULL;
2089 if (path) cp->record_file=ms_strdup(path);
2093 * Retrieves the path for the audio recoding of the call.
2095 const char *linphone_call_params_get_record_file(const LinphoneCallParams *cp){
2096 return cp->record_file;
2100 * Start call recording.
2101 * The output file where audio is recorded must be previously specified with linphone_call_params_set_record_file().
2103 void linphone_call_start_recording(LinphoneCall *call){
2104 if (!call->params.record_file){
2105 ms_error("linphone_call_start_recording(): no output file specified. Use linphone_call_params_set_record_file().");
2108 if (call->audiostream && !call->params.in_conference){
2109 audio_stream_mixed_record_start(call->audiostream);
2111 call->record_active=TRUE;
2115 * Stop call recording.
2117 void linphone_call_stop_recording(LinphoneCall *call){
2118 if (call->audiostream && !call->params.in_conference){
2119 audio_stream_mixed_record_stop(call->audiostream);
2121 call->record_active=FALSE;
2128 static void report_bandwidth(LinphoneCall *call, RtpSession *as, RtpSession *vs){
2129 call->stats[LINPHONE_CALL_STATS_AUDIO].download_bandwidth=(as!=NULL) ? (rtp_session_compute_recv_bandwidth(as)*1e-3) : 0;
2130 call->stats[LINPHONE_CALL_STATS_AUDIO].upload_bandwidth=(as!=NULL) ? (rtp_session_compute_send_bandwidth(as)*1e-3) : 0;
2131 call->stats[LINPHONE_CALL_STATS_VIDEO].download_bandwidth=(vs!=NULL) ? (rtp_session_compute_recv_bandwidth(vs)*1e-3) : 0;
2132 call->stats[LINPHONE_CALL_STATS_VIDEO].upload_bandwidth=(vs!=NULL) ? (rtp_session_compute_send_bandwidth(vs)*1e-3) : 0;
2133 ms_message("bandwidth usage: audio=[d=%.1f,u=%.1f] video=[d=%.1f,u=%.1f] kbit/sec",
2134 call->stats[LINPHONE_CALL_STATS_AUDIO].download_bandwidth,
2135 call->stats[LINPHONE_CALL_STATS_AUDIO].upload_bandwidth ,
2136 call->stats[LINPHONE_CALL_STATS_VIDEO].download_bandwidth,
2137 call->stats[LINPHONE_CALL_STATS_VIDEO].upload_bandwidth
2141 static void linphone_core_disconnected(LinphoneCore *lc, LinphoneCall *call){
2145 from = linphone_call_get_remote_address_as_string(call);
2148 snprintf(temp,sizeof(temp),"Remote end %s seems to have disconnected, the call is going to be closed.",from);
2153 snprintf(temp,sizeof(temp),"Remote end seems to have disconnected, the call is going to be closed.");
2155 if (lc->vtable.display_warning!=NULL)
2156 lc->vtable.display_warning(lc,temp);
2157 linphone_core_terminate_call(lc,call);
2158 linphone_core_play_named_tone(lc,LinphoneToneCallFailed);
2161 static void handle_ice_events(LinphoneCall *call, OrtpEvent *ev){
2162 OrtpEventType evt=ortp_event_get_type(ev);
2163 OrtpEventData *evd=ortp_event_get_data(ev);
2166 if (evt == ORTP_EVENT_ICE_SESSION_PROCESSING_FINISHED) {
2167 switch (ice_session_state(call->ice_session)) {
2169 ice_session_select_candidates(call->ice_session);
2170 if (ice_session_role(call->ice_session) == IR_Controlling) {
2171 linphone_core_update_call(call->core, call, &call->current_params);
2175 if (ice_session_has_completed_check_list(call->ice_session) == TRUE) {
2176 ice_session_select_candidates(call->ice_session);
2177 if (ice_session_role(call->ice_session) == IR_Controlling) {
2178 /* At least one ICE session has succeeded, so perform a call update. */
2179 linphone_core_update_call(call->core, call, &call->current_params);
2186 linphone_core_update_ice_state_in_call_stats(call);
2187 } else if (evt == ORTP_EVENT_ICE_GATHERING_FINISHED) {
2189 if (evd->info.ice_processing_successful==TRUE) {
2190 ice_session_compute_candidates_foundations(call->ice_session);
2191 ice_session_eliminate_redundant_candidates(call->ice_session);
2192 ice_session_choose_default_candidates(call->ice_session);
2193 ping_time = ice_session_average_gathering_round_trip_time(call->ice_session);
2194 if (ping_time >=0) {
2195 call->ping_time=ping_time;
2198 ms_warning("No STUN answer from [%s], disabling ICE",linphone_core_get_stun_server(call->core));
2199 linphone_call_delete_ice_session(call);
2201 switch (call->state) {
2202 case LinphoneCallUpdating:
2203 linphone_core_start_update_call(call->core, call);
2205 case LinphoneCallUpdatedByRemote:
2206 linphone_core_start_accept_call_update(call->core, call);
2208 case LinphoneCallOutgoingInit:
2209 linphone_call_stop_media_streams_for_ice_gathering(call);
2210 linphone_core_proceed_with_invite_if_ready(call->core, call, NULL);
2212 case LinphoneCallIdle:
2213 linphone_call_stop_media_streams_for_ice_gathering(call);
2214 linphone_core_notify_incoming_call(call->core, call);
2219 } else if (evt == ORTP_EVENT_ICE_LOSING_PAIRS_COMPLETED) {
2220 linphone_core_start_accept_call_update(call->core, call);
2221 linphone_core_update_ice_state_in_call_stats(call);
2222 } else if (evt == ORTP_EVENT_ICE_RESTART_NEEDED) {
2223 ice_session_restart(call->ice_session);
2224 ice_session_set_role(call->ice_session, IR_Controlling);
2225 linphone_core_update_call(call->core, call, &call->current_params);
2229 void linphone_call_background_tasks(LinphoneCall *call, bool_t one_second_elapsed){
2230 LinphoneCore* lc = call->core;
2231 int disconnect_timeout = linphone_core_get_nortp_timeout(call->core);
2232 bool_t disconnected=FALSE;
2234 if (call->state==LinphoneCallStreamsRunning && one_second_elapsed){
2235 RtpSession *as=NULL,*vs=NULL;
2236 float audio_load=0, video_load=0;
2237 if (call->audiostream!=NULL){
2238 as=call->audiostream->ms.session;
2239 if (call->audiostream->ms.ticker)
2240 audio_load=ms_ticker_get_average_load(call->audiostream->ms.ticker);
2242 if (call->videostream!=NULL){
2243 if (call->videostream->ms.ticker)
2244 video_load=ms_ticker_get_average_load(call->videostream->ms.ticker);
2245 vs=call->videostream->ms.session;
2247 report_bandwidth(call,as,vs);
2248 ms_message("Thread processing load: audio=%f\tvideo=%f",audio_load,video_load);
2252 linphone_upnp_call_process(call);
2255 #ifdef VIDEO_ENABLED
2256 if (call->videostream!=NULL) {
2259 /* Ensure there is no dangling ICE check list. */
2260 if (call->ice_session == NULL) call->videostream->ms.ice_check_list = NULL;
2262 // Beware that the application queue should not depend on treatments fron the
2263 // mediastreamer queue.
2264 video_stream_iterate(call->videostream);
2266 while (call->videostream_app_evq && (NULL != (ev=ortp_ev_queue_get(call->videostream_app_evq)))){
2267 OrtpEventType evt=ortp_event_get_type(ev);
2268 OrtpEventData *evd=ortp_event_get_data(ev);
2269 if (evt == ORTP_EVENT_ZRTP_ENCRYPTION_CHANGED){
2270 linphone_call_videostream_encryption_changed(call, evd->info.zrtp_stream_encrypted);
2271 } else if (evt == ORTP_EVENT_RTCP_PACKET_RECEIVED) {
2272 call->stats[LINPHONE_CALL_STATS_VIDEO].round_trip_delay = rtp_session_get_round_trip_propagation(call->videostream->ms.session);
2273 if(call->stats[LINPHONE_CALL_STATS_VIDEO].received_rtcp != NULL)
2274 freemsg(call->stats[LINPHONE_CALL_STATS_VIDEO].received_rtcp);
2275 call->stats[LINPHONE_CALL_STATS_VIDEO].received_rtcp = evd->packet;
2277 update_local_stats(&call->stats[LINPHONE_CALL_STATS_VIDEO],(MediaStream*)call->videostream);
2278 if (lc->vtable.call_stats_updated)
2279 lc->vtable.call_stats_updated(lc, call, &call->stats[LINPHONE_CALL_STATS_VIDEO]);
2280 } else if (evt == ORTP_EVENT_RTCP_PACKET_EMITTED) {
2281 memcpy(&call->stats[LINPHONE_CALL_STATS_VIDEO].jitter_stats, rtp_session_get_jitter_stats(call->videostream->ms.session), sizeof(jitter_stats_t));
2282 if(call->stats[LINPHONE_CALL_STATS_VIDEO].sent_rtcp != NULL)
2283 freemsg(call->stats[LINPHONE_CALL_STATS_VIDEO].sent_rtcp);
2284 call->stats[LINPHONE_CALL_STATS_VIDEO].sent_rtcp = evd->packet;
2286 update_local_stats(&call->stats[LINPHONE_CALL_STATS_VIDEO],(MediaStream*)call->videostream);
2287 if (lc->vtable.call_stats_updated)
2288 lc->vtable.call_stats_updated(lc, call, &call->stats[LINPHONE_CALL_STATS_VIDEO]);
2289 } else if ((evt == ORTP_EVENT_ICE_SESSION_PROCESSING_FINISHED) || (evt == ORTP_EVENT_ICE_GATHERING_FINISHED)
2290 || (evt == ORTP_EVENT_ICE_LOSING_PAIRS_COMPLETED) || (evt == ORTP_EVENT_ICE_RESTART_NEEDED)) {
2291 handle_ice_events(call, ev);
2293 ortp_event_destroy(ev);
2297 if (call->audiostream!=NULL) {
2300 /* Ensure there is no dangling ICE check list. */
2301 if (call->ice_session == NULL) call->audiostream->ms.ice_check_list = NULL;
2303 // Beware that the application queue should not depend on treatments fron the
2304 // mediastreamer queue.
2305 audio_stream_iterate(call->audiostream);
2307 while (call->audiostream_app_evq && (NULL != (ev=ortp_ev_queue_get(call->audiostream_app_evq)))){
2308 OrtpEventType evt=ortp_event_get_type(ev);
2309 OrtpEventData *evd=ortp_event_get_data(ev);
2310 if (evt == ORTP_EVENT_ZRTP_ENCRYPTION_CHANGED){
2311 linphone_call_audiostream_encryption_changed(call, evd->info.zrtp_stream_encrypted);
2312 } else if (evt == ORTP_EVENT_ZRTP_SAS_READY) {
2313 linphone_call_audiostream_auth_token_ready(call, evd->info.zrtp_sas.sas, evd->info.zrtp_sas.verified);
2314 } else if (evt == ORTP_EVENT_RTCP_PACKET_RECEIVED) {
2315 call->stats[LINPHONE_CALL_STATS_AUDIO].round_trip_delay = rtp_session_get_round_trip_propagation(call->audiostream->ms.session);
2316 if(call->stats[LINPHONE_CALL_STATS_AUDIO].received_rtcp != NULL)
2317 freemsg(call->stats[LINPHONE_CALL_STATS_AUDIO].received_rtcp);
2318 call->stats[LINPHONE_CALL_STATS_AUDIO].received_rtcp = evd->packet;
2320 update_local_stats(&call->stats[LINPHONE_CALL_STATS_AUDIO],(MediaStream*)call->audiostream);
2321 if (lc->vtable.call_stats_updated)
2322 lc->vtable.call_stats_updated(lc, call, &call->stats[LINPHONE_CALL_STATS_AUDIO]);
2323 } else if (evt == ORTP_EVENT_RTCP_PACKET_EMITTED) {
2324 memcpy(&call->stats[LINPHONE_CALL_STATS_AUDIO].jitter_stats, rtp_session_get_jitter_stats(call->audiostream->ms.session), sizeof(jitter_stats_t));
2325 if(call->stats[LINPHONE_CALL_STATS_AUDIO].sent_rtcp != NULL)
2326 freemsg(call->stats[LINPHONE_CALL_STATS_AUDIO].sent_rtcp);
2327 call->stats[LINPHONE_CALL_STATS_AUDIO].sent_rtcp = evd->packet;
2329 update_local_stats(&call->stats[LINPHONE_CALL_STATS_AUDIO],(MediaStream*)call->audiostream);
2330 if (lc->vtable.call_stats_updated)
2331 lc->vtable.call_stats_updated(lc, call, &call->stats[LINPHONE_CALL_STATS_AUDIO]);
2332 } else if ((evt == ORTP_EVENT_ICE_SESSION_PROCESSING_FINISHED) || (evt == ORTP_EVENT_ICE_GATHERING_FINISHED)
2333 || (evt == ORTP_EVENT_ICE_LOSING_PAIRS_COMPLETED) || (evt == ORTP_EVENT_ICE_RESTART_NEEDED)) {
2334 handle_ice_events(call, ev);
2335 } else if (evt==ORTP_EVENT_TELEPHONE_EVENT){
2336 linphone_core_dtmf_received(lc,evd->info.telephone_event);
2338 ortp_event_destroy(ev);
2341 if (call->state==LinphoneCallStreamsRunning && one_second_elapsed && call->audiostream!=NULL && disconnect_timeout>0 )
2342 disconnected=!audio_stream_alive(call->audiostream,disconnect_timeout);
2344 linphone_core_disconnected(call->core,call);
2347 void linphone_call_log_completed(LinphoneCall *call){
2348 LinphoneCore *lc=call->core;
2350 call->log->duration=time(NULL)-call->start_time;
2352 if (call->log->status==LinphoneCallMissed){
2355 info=ortp_strdup_printf(ngettext("You have missed %i call.",
2356 "You have missed %i calls.", lc->missed_calls),
2358 if (lc->vtable.display_status!=NULL)
2359 lc->vtable.display_status(lc,info);
2362 lc->call_logs=ms_list_prepend(lc->call_logs,(void *)call->log);
2363 if (ms_list_size(lc->call_logs)>lc->max_call_logs){
2364 MSList *elem,*prevelem=NULL;
2365 /*find the last element*/
2366 for(elem=lc->call_logs;elem!=NULL;elem=elem->next){
2370 linphone_call_log_destroy((LinphoneCallLog*)elem->data);
2371 lc->call_logs=ms_list_remove_link(lc->call_logs,elem);
2373 if (lc->vtable.call_log_updated!=NULL){
2374 lc->vtable.call_log_updated(lc,call->log);
2376 call_logs_write_to_config_file(lc);
2379 LinphoneCallState linphone_call_get_transfer_state(LinphoneCall *call) {
2380 return call->transfer_state;
2383 void linphone_call_set_transfer_state(LinphoneCall* call, LinphoneCallState state) {
2384 if (state != call->transfer_state) {
2385 LinphoneCore* lc = call->core;
2386 call->transfer_state = state;
2387 if (lc->vtable.transfer_state_changed)
2388 lc->vtable.transfer_state_changed(lc, call, state);
2393 * Returns true if the call is part of the conference.
2394 * @ingroup conferencing
2396 bool_t linphone_call_is_in_conference(const LinphoneCall *call) {
2397 return call->params.in_conference;
2402 * Perform a zoom of the video displayed during a call.
2403 * @param call the call.
2404 * @param zoom_factor a floating point number describing the zoom factor. A value 1.0 corresponds to no zoom applied.
2405 * @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.
2406 * @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.
2408 * 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.
2410 void linphone_call_zoom_video(LinphoneCall* call, float zoom_factor, float* cx, float* cy) {
2411 VideoStream* vstream = call->videostream;
2412 if (vstream && vstream->output) {
2415 if (zoom_factor < 1)
2417 float halfsize = 0.5 * 1.0 / zoom_factor;
2419 if ((*cx - halfsize) < 0)
2421 if ((*cx + halfsize) > 1)
2423 if ((*cy - halfsize) < 0)
2425 if ((*cy + halfsize) > 1)
2428 zoom[0] = zoom_factor;
2431 ms_filter_call_method(vstream->output, MS_VIDEO_DISPLAY_ZOOM, &zoom);
2432 }else ms_warning("Could not apply zoom: video output wasn't activated.");