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 _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,linphone_address_get_domain(from),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, AudioStream *st){
1861 audio_stream_get_local_rtp_stats (st,&log->local_stats);
1862 log->quality=audio_stream_get_average_quality_rating(st);
1865 void linphone_call_stop_audio_stream(LinphoneCall *call) {
1866 if (call->audiostream!=NULL) {
1867 rtp_session_unregister_event_queue(call->audiostream->ms.session,call->audiostream_app_evq);
1868 ortp_ev_queue_flush(call->audiostream_app_evq);
1869 ortp_ev_queue_destroy(call->audiostream_app_evq);
1870 call->audiostream_app_evq=NULL;
1872 if (call->audiostream->ec){
1873 const char *state_str=NULL;
1874 ms_filter_call_method(call->audiostream->ec,MS_ECHO_CANCELLER_GET_STATE_STRING,&state_str);
1876 ms_message("Writing echo canceler state, %i bytes",(int)strlen(state_str));
1877 lp_config_set_string(call->core->config,"sound","ec_state",state_str);
1880 linphone_call_log_fill_stats (call->log,call->audiostream);
1881 if (call->endpoint){
1882 linphone_call_remove_from_conf(call);
1884 audio_stream_stop(call->audiostream);
1885 call->audiostream=NULL;
1889 void linphone_call_stop_video_stream(LinphoneCall *call) {
1890 #ifdef VIDEO_ENABLED
1891 if (call->videostream!=NULL){
1892 rtp_session_unregister_event_queue(call->videostream->ms.session,call->videostream_app_evq);
1893 ortp_ev_queue_flush(call->videostream_app_evq);
1894 ortp_ev_queue_destroy(call->videostream_app_evq);
1895 call->videostream_app_evq=NULL;
1896 video_stream_stop(call->videostream);
1897 call->videostream=NULL;
1902 void linphone_call_stop_media_streams(LinphoneCall *call){
1903 linphone_call_stop_audio_stream(call);
1904 linphone_call_stop_video_stream(call);
1905 ms_event_queue_skip(call->core->msevq);
1907 if (call->audio_profile){
1908 rtp_profile_clear_all(call->audio_profile);
1909 rtp_profile_destroy(call->audio_profile);
1910 call->audio_profile=NULL;
1912 if (call->video_profile){
1913 rtp_profile_clear_all(call->video_profile);
1914 rtp_profile_destroy(call->video_profile);
1915 call->video_profile=NULL;
1921 void linphone_call_enable_echo_cancellation(LinphoneCall *call, bool_t enable) {
1922 if (call!=NULL && call->audiostream!=NULL && call->audiostream->ec){
1923 bool_t bypass_mode = !enable;
1924 ms_filter_call_method(call->audiostream->ec,MS_ECHO_CANCELLER_SET_BYPASS_MODE,&bypass_mode);
1927 bool_t linphone_call_echo_cancellation_enabled(LinphoneCall *call) {
1928 if (call!=NULL && call->audiostream!=NULL && call->audiostream->ec){
1930 ms_filter_call_method(call->audiostream->ec,MS_ECHO_CANCELLER_GET_BYPASS_MODE,&val);
1933 return linphone_core_echo_cancellation_enabled(call->core);
1937 void linphone_call_enable_echo_limiter(LinphoneCall *call, bool_t val){
1938 if (call!=NULL && call->audiostream!=NULL ) {
1940 const char *type=lp_config_get_string(call->core->config,"sound","el_type","mic");
1941 if (strcasecmp(type,"mic")==0)
1942 audio_stream_enable_echo_limiter(call->audiostream,ELControlMic);
1943 else if (strcasecmp(type,"full")==0)
1944 audio_stream_enable_echo_limiter(call->audiostream,ELControlFull);
1946 audio_stream_enable_echo_limiter(call->audiostream,ELInactive);
1951 bool_t linphone_call_echo_limiter_enabled(const LinphoneCall *call){
1952 if (call!=NULL && call->audiostream!=NULL ){
1953 return call->audiostream->el_type !=ELInactive ;
1955 return linphone_core_echo_limiter_enabled(call->core);
1960 * @addtogroup call_misc
1965 * Returns the measured sound volume played locally (received from remote).
1966 * It is expressed in dbm0.
1968 float linphone_call_get_play_volume(LinphoneCall *call){
1969 AudioStream *st=call->audiostream;
1970 if (st && st->volrecv){
1972 ms_filter_call_method(st->volrecv,MS_VOLUME_GET,&vol);
1976 return LINPHONE_VOLUME_DB_LOWEST;
1980 * Returns the measured sound volume recorded locally (sent to remote).
1981 * It is expressed in dbm0.
1983 float linphone_call_get_record_volume(LinphoneCall *call){
1984 AudioStream *st=call->audiostream;
1985 if (st && st->volsend && !call->audio_muted && call->state==LinphoneCallStreamsRunning){
1987 ms_filter_call_method(st->volsend,MS_VOLUME_GET,&vol);
1991 return LINPHONE_VOLUME_DB_LOWEST;
1995 * Obtain real-time quality rating of the call
1997 * Based on local RTP statistics and RTCP feedback, a quality rating is computed and updated
1998 * during all the duration of the call. This function returns its value at the time of the function call.
1999 * It is expected that the rating is updated at least every 5 seconds or so.
2000 * The rating is a floating point number comprised between 0 and 5.
2002 * 4-5 = good quality <br>
2003 * 3-4 = average quality <br>
2004 * 2-3 = poor quality <br>
2005 * 1-2 = very poor quality <br>
2006 * 0-1 = can't be worse, mostly unusable <br>
2008 * @returns The function returns -1 if no quality measurement is available, for example if no
2009 * active audio stream exist. Otherwise it returns the quality rating.
2011 float linphone_call_get_current_quality(LinphoneCall *call){
2012 if (call->audiostream){
2013 return audio_stream_get_quality_rating(call->audiostream);
2019 * Returns call quality averaged over all the duration of the call.
2021 * See linphone_call_get_current_quality() for more details about quality measurement.
2023 float linphone_call_get_average_quality(LinphoneCall *call){
2024 if (call->audiostream){
2025 return audio_stream_get_average_quality_rating(call->audiostream);
2031 * Access last known statistics for audio stream, for a given call.
2033 const LinphoneCallStats *linphone_call_get_audio_stats(const LinphoneCall *call) {
2034 return &call->stats[LINPHONE_CALL_STATS_AUDIO];
2038 * Access last known statistics for video stream, for a given call.
2040 const LinphoneCallStats *linphone_call_get_video_stats(const LinphoneCall *call) {
2041 return &call->stats[LINPHONE_CALL_STATS_VIDEO];
2045 * Enable recording of the call (voice-only).
2046 * This function must be used before the call parameters are assigned to the call.
2047 * The call recording can be started and paused after the call is established with
2048 * linphone_call_start_recording() and linphone_call_pause_recording().
2049 * @param cp the call parameters
2050 * @param path path and filename of the file where audio is written.
2052 void linphone_call_params_set_record_file(LinphoneCallParams *cp, const char *path){
2053 if (cp->record_file){
2054 ms_free(cp->record_file);
2055 cp->record_file=NULL;
2057 if (path) cp->record_file=ms_strdup(path);
2061 * Retrieves the path for the audio recoding of the call.
2063 const char *linphone_call_params_get_record_file(const LinphoneCallParams *cp){
2064 return cp->record_file;
2068 * Start call recording.
2069 * The output file where audio is recorded must be previously specified with linphone_call_params_set_record_file().
2071 void linphone_call_start_recording(LinphoneCall *call){
2072 if (!call->params.record_file){
2073 ms_error("linphone_call_start_recording(): no output file specified. Use linphone_call_params_set_record_file().");
2076 if (call->audiostream && !call->params.in_conference){
2077 audio_stream_mixed_record_start(call->audiostream);
2079 call->record_active=TRUE;
2083 * Stop call recording.
2085 void linphone_call_stop_recording(LinphoneCall *call){
2086 if (call->audiostream && !call->params.in_conference){
2087 audio_stream_mixed_record_stop(call->audiostream);
2089 call->record_active=FALSE;
2096 static void report_bandwidth(LinphoneCall *call, RtpSession *as, RtpSession *vs){
2097 call->stats[LINPHONE_CALL_STATS_AUDIO].download_bandwidth=(as!=NULL) ? (rtp_session_compute_recv_bandwidth(as)*1e-3) : 0;
2098 call->stats[LINPHONE_CALL_STATS_AUDIO].upload_bandwidth=(as!=NULL) ? (rtp_session_compute_send_bandwidth(as)*1e-3) : 0;
2099 call->stats[LINPHONE_CALL_STATS_VIDEO].download_bandwidth=(vs!=NULL) ? (rtp_session_compute_recv_bandwidth(vs)*1e-3) : 0;
2100 call->stats[LINPHONE_CALL_STATS_VIDEO].upload_bandwidth=(vs!=NULL) ? (rtp_session_compute_send_bandwidth(vs)*1e-3) : 0;
2101 ms_message("bandwidth usage: audio=[d=%.1f,u=%.1f] video=[d=%.1f,u=%.1f] kbit/sec",
2102 call->stats[LINPHONE_CALL_STATS_AUDIO].download_bandwidth,
2103 call->stats[LINPHONE_CALL_STATS_AUDIO].upload_bandwidth ,
2104 call->stats[LINPHONE_CALL_STATS_VIDEO].download_bandwidth,
2105 call->stats[LINPHONE_CALL_STATS_VIDEO].upload_bandwidth
2109 static void linphone_core_disconnected(LinphoneCore *lc, LinphoneCall *call){
2113 from = linphone_call_get_remote_address_as_string(call);
2116 snprintf(temp,sizeof(temp),"Remote end %s seems to have disconnected, the call is going to be closed.",from);
2121 snprintf(temp,sizeof(temp),"Remote end seems to have disconnected, the call is going to be closed.");
2123 if (lc->vtable.display_warning!=NULL)
2124 lc->vtable.display_warning(lc,temp);
2125 linphone_core_terminate_call(lc,call);
2128 static void handle_ice_events(LinphoneCall *call, OrtpEvent *ev){
2129 OrtpEventType evt=ortp_event_get_type(ev);
2130 OrtpEventData *evd=ortp_event_get_data(ev);
2133 if (evt == ORTP_EVENT_ICE_SESSION_PROCESSING_FINISHED) {
2134 switch (ice_session_state(call->ice_session)) {
2136 ice_session_select_candidates(call->ice_session);
2137 if (ice_session_role(call->ice_session) == IR_Controlling) {
2138 linphone_core_update_call(call->core, call, &call->current_params);
2142 if (ice_session_has_completed_check_list(call->ice_session) == TRUE) {
2143 ice_session_select_candidates(call->ice_session);
2144 if (ice_session_role(call->ice_session) == IR_Controlling) {
2145 /* At least one ICE session has succeeded, so perform a call update. */
2146 linphone_core_update_call(call->core, call, &call->current_params);
2153 linphone_core_update_ice_state_in_call_stats(call);
2154 } else if (evt == ORTP_EVENT_ICE_GATHERING_FINISHED) {
2156 if (evd->info.ice_processing_successful==TRUE) {
2157 ice_session_compute_candidates_foundations(call->ice_session);
2158 ice_session_eliminate_redundant_candidates(call->ice_session);
2159 ice_session_choose_default_candidates(call->ice_session);
2160 ping_time = ice_session_average_gathering_round_trip_time(call->ice_session);
2161 if (ping_time >=0) {
2162 call->ping_time=ping_time;
2165 ms_warning("No STUN answer from [%s], disabling ICE",linphone_core_get_stun_server(call->core));
2166 linphone_call_delete_ice_session(call);
2168 switch (call->state) {
2169 case LinphoneCallUpdating:
2170 linphone_core_start_update_call(call->core, call);
2172 case LinphoneCallUpdatedByRemote:
2173 linphone_core_start_accept_call_update(call->core, call);
2175 case LinphoneCallOutgoingInit:
2176 linphone_call_stop_media_streams_for_ice_gathering(call);
2177 linphone_core_proceed_with_invite_if_ready(call->core, call, NULL);
2179 case LinphoneCallIdle:
2180 linphone_call_stop_media_streams_for_ice_gathering(call);
2181 linphone_core_notify_incoming_call(call->core, call);
2186 } else if (evt == ORTP_EVENT_ICE_LOSING_PAIRS_COMPLETED) {
2187 linphone_core_start_accept_call_update(call->core, call);
2188 linphone_core_update_ice_state_in_call_stats(call);
2189 } else if (evt == ORTP_EVENT_ICE_RESTART_NEEDED) {
2190 ice_session_restart(call->ice_session);
2191 ice_session_set_role(call->ice_session, IR_Controlling);
2192 linphone_core_update_call(call->core, call, &call->current_params);
2196 void linphone_call_background_tasks(LinphoneCall *call, bool_t one_second_elapsed){
2197 LinphoneCore* lc = call->core;
2198 int disconnect_timeout = linphone_core_get_nortp_timeout(call->core);
2199 bool_t disconnected=FALSE;
2201 if (call->state==LinphoneCallStreamsRunning && one_second_elapsed){
2202 RtpSession *as=NULL,*vs=NULL;
2203 float audio_load=0, video_load=0;
2204 if (call->audiostream!=NULL){
2205 as=call->audiostream->ms.session;
2206 if (call->audiostream->ms.ticker)
2207 audio_load=ms_ticker_get_average_load(call->audiostream->ms.ticker);
2209 if (call->videostream!=NULL){
2210 if (call->videostream->ms.ticker)
2211 video_load=ms_ticker_get_average_load(call->videostream->ms.ticker);
2212 vs=call->videostream->ms.session;
2214 report_bandwidth(call,as,vs);
2215 ms_message("Thread processing load: audio=%f\tvideo=%f",audio_load,video_load);
2219 linphone_upnp_call_process(call);
2222 #ifdef VIDEO_ENABLED
2223 if (call->videostream!=NULL) {
2226 /* Ensure there is no dangling ICE check list. */
2227 if (call->ice_session == NULL) call->videostream->ms.ice_check_list = NULL;
2229 // Beware that the application queue should not depend on treatments fron the
2230 // mediastreamer queue.
2231 video_stream_iterate(call->videostream);
2233 while (call->videostream_app_evq && (NULL != (ev=ortp_ev_queue_get(call->videostream_app_evq)))){
2234 OrtpEventType evt=ortp_event_get_type(ev);
2235 OrtpEventData *evd=ortp_event_get_data(ev);
2236 if (evt == ORTP_EVENT_ZRTP_ENCRYPTION_CHANGED){
2237 linphone_call_videostream_encryption_changed(call, evd->info.zrtp_stream_encrypted);
2238 } else if (evt == ORTP_EVENT_RTCP_PACKET_RECEIVED) {
2239 call->stats[LINPHONE_CALL_STATS_VIDEO].round_trip_delay = rtp_session_get_round_trip_propagation(call->videostream->ms.session);
2240 if(call->stats[LINPHONE_CALL_STATS_VIDEO].received_rtcp != NULL)
2241 freemsg(call->stats[LINPHONE_CALL_STATS_VIDEO].received_rtcp);
2242 call->stats[LINPHONE_CALL_STATS_VIDEO].received_rtcp = evd->packet;
2244 if (lc->vtable.call_stats_updated)
2245 lc->vtable.call_stats_updated(lc, call, &call->stats[LINPHONE_CALL_STATS_VIDEO]);
2246 } else if (evt == ORTP_EVENT_RTCP_PACKET_EMITTED) {
2247 memcpy(&call->stats[LINPHONE_CALL_STATS_VIDEO].jitter_stats, rtp_session_get_jitter_stats(call->videostream->ms.session), sizeof(jitter_stats_t));
2248 if(call->stats[LINPHONE_CALL_STATS_VIDEO].sent_rtcp != NULL)
2249 freemsg(call->stats[LINPHONE_CALL_STATS_VIDEO].sent_rtcp);
2250 call->stats[LINPHONE_CALL_STATS_VIDEO].sent_rtcp = evd->packet;
2252 if (lc->vtable.call_stats_updated)
2253 lc->vtable.call_stats_updated(lc, call, &call->stats[LINPHONE_CALL_STATS_VIDEO]);
2254 } else if ((evt == ORTP_EVENT_ICE_SESSION_PROCESSING_FINISHED) || (evt == ORTP_EVENT_ICE_GATHERING_FINISHED)
2255 || (evt == ORTP_EVENT_ICE_LOSING_PAIRS_COMPLETED) || (evt == ORTP_EVENT_ICE_RESTART_NEEDED)) {
2256 handle_ice_events(call, ev);
2258 ortp_event_destroy(ev);
2262 if (call->audiostream!=NULL) {
2265 /* Ensure there is no dangling ICE check list. */
2266 if (call->ice_session == NULL) call->audiostream->ms.ice_check_list = NULL;
2268 // Beware that the application queue should not depend on treatments fron the
2269 // mediastreamer queue.
2270 audio_stream_iterate(call->audiostream);
2272 while (call->audiostream_app_evq && (NULL != (ev=ortp_ev_queue_get(call->audiostream_app_evq)))){
2273 OrtpEventType evt=ortp_event_get_type(ev);
2274 OrtpEventData *evd=ortp_event_get_data(ev);
2275 if (evt == ORTP_EVENT_ZRTP_ENCRYPTION_CHANGED){
2276 linphone_call_audiostream_encryption_changed(call, evd->info.zrtp_stream_encrypted);
2277 } else if (evt == ORTP_EVENT_ZRTP_SAS_READY) {
2278 linphone_call_audiostream_auth_token_ready(call, evd->info.zrtp_sas.sas, evd->info.zrtp_sas.verified);
2279 } else if (evt == ORTP_EVENT_RTCP_PACKET_RECEIVED) {
2280 call->stats[LINPHONE_CALL_STATS_AUDIO].round_trip_delay = rtp_session_get_round_trip_propagation(call->audiostream->ms.session);
2281 if(call->stats[LINPHONE_CALL_STATS_AUDIO].received_rtcp != NULL)
2282 freemsg(call->stats[LINPHONE_CALL_STATS_AUDIO].received_rtcp);
2283 call->stats[LINPHONE_CALL_STATS_AUDIO].received_rtcp = evd->packet;
2285 if (lc->vtable.call_stats_updated)
2286 lc->vtable.call_stats_updated(lc, call, &call->stats[LINPHONE_CALL_STATS_AUDIO]);
2287 } else if (evt == ORTP_EVENT_RTCP_PACKET_EMITTED) {
2288 memcpy(&call->stats[LINPHONE_CALL_STATS_AUDIO].jitter_stats, rtp_session_get_jitter_stats(call->audiostream->ms.session), sizeof(jitter_stats_t));
2289 if(call->stats[LINPHONE_CALL_STATS_AUDIO].sent_rtcp != NULL)
2290 freemsg(call->stats[LINPHONE_CALL_STATS_AUDIO].sent_rtcp);
2291 call->stats[LINPHONE_CALL_STATS_AUDIO].sent_rtcp = evd->packet;
2293 if (lc->vtable.call_stats_updated)
2294 lc->vtable.call_stats_updated(lc, call, &call->stats[LINPHONE_CALL_STATS_AUDIO]);
2295 } else if ((evt == ORTP_EVENT_ICE_SESSION_PROCESSING_FINISHED) || (evt == ORTP_EVENT_ICE_GATHERING_FINISHED)
2296 || (evt == ORTP_EVENT_ICE_LOSING_PAIRS_COMPLETED) || (evt == ORTP_EVENT_ICE_RESTART_NEEDED)) {
2297 handle_ice_events(call, ev);
2298 } else if (evt==ORTP_EVENT_TELEPHONE_EVENT){
2299 linphone_core_dtmf_received(lc,evd->info.telephone_event);
2301 ortp_event_destroy(ev);
2304 if (call->state==LinphoneCallStreamsRunning && one_second_elapsed && call->audiostream!=NULL && disconnect_timeout>0 )
2305 disconnected=!audio_stream_alive(call->audiostream,disconnect_timeout);
2307 linphone_core_disconnected(call->core,call);
2310 void linphone_call_log_completed(LinphoneCall *call){
2311 LinphoneCore *lc=call->core;
2313 call->log->duration=time(NULL)-call->start_time;
2315 if (call->log->status==LinphoneCallMissed){
2318 info=ortp_strdup_printf(ngettext("You have missed %i call.",
2319 "You have missed %i calls.", lc->missed_calls),
2321 if (lc->vtable.display_status!=NULL)
2322 lc->vtable.display_status(lc,info);
2325 lc->call_logs=ms_list_prepend(lc->call_logs,(void *)call->log);
2326 if (ms_list_size(lc->call_logs)>lc->max_call_logs){
2327 MSList *elem,*prevelem=NULL;
2328 /*find the last element*/
2329 for(elem=lc->call_logs;elem!=NULL;elem=elem->next){
2333 linphone_call_log_destroy((LinphoneCallLog*)elem->data);
2334 lc->call_logs=ms_list_remove_link(lc->call_logs,elem);
2336 if (lc->vtable.call_log_updated!=NULL){
2337 lc->vtable.call_log_updated(lc,call->log);
2339 call_logs_write_to_config_file(lc);
2342 LinphoneCallState linphone_call_get_transfer_state(LinphoneCall *call) {
2343 return call->transfer_state;
2346 void linphone_call_set_transfer_state(LinphoneCall* call, LinphoneCallState state) {
2347 if (state != call->transfer_state) {
2348 LinphoneCore* lc = call->core;
2349 call->transfer_state = state;
2350 if (lc->vtable.transfer_state_changed)
2351 lc->vtable.transfer_state_changed(lc, call, state);
2356 * Returns true if the call is part of the conference.
2357 * @ingroup conferencing
2359 bool_t linphone_call_is_in_conference(const LinphoneCall *call) {
2360 return call->params.in_conference;
2365 * Perform a zoom of the video displayed during a call.
2366 * @param call the call.
2367 * @param zoom_factor a floating point number describing the zoom factor. A value 1.0 corresponds to no zoom applied.
2368 * @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.
2369 * @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.
2371 * 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.
2373 void linphone_call_zoom_video(LinphoneCall* call, float zoom_factor, float* cx, float* cy) {
2374 VideoStream* vstream = call->videostream;
2375 if (vstream && vstream->output) {
2378 if (zoom_factor < 1)
2380 float halfsize = 0.5 * 1.0 / zoom_factor;
2382 if ((*cx - halfsize) < 0)
2384 if ((*cx + halfsize) > 1)
2386 if ((*cy - halfsize) < 0)
2388 if ((*cy + halfsize) > 1)
2391 zoom[0] = zoom_factor;
2394 ms_filter_call_method(vstream->output, MS_VIDEO_DISPLAY_ZOOM, &zoom);
2395 }else ms_warning("Could not apply zoom: video output wasn't activated.");