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 ZRTP is enabled, put the hello hash into the audiostream's desc
258 if (call->audiostream && call->audiostream->ms.zrtp_context!=NULL){
259 ortp_zrtp_get_hello_hash(call->audiostream->ms.zrtp_context,
260 md->streams[0].zrtp_hello_hash,
261 sizeof(md->streams[0].zrtp_hello_hash));
262 ms_message("Audio stream zrtp hash: %s", md->streams[0].zrtp_hello_hash);
265 if (call->params.has_video){
266 md->n_active_streams++;
267 md->streams[1].rtp_port=call->video_port;
268 md->streams[1].rtcp_port=call->video_port+1;
269 md->streams[1].proto=md->streams[0].proto;
270 md->streams[1].type=SalVideo;
271 l=make_codec_list(lc,lc->codecs_conf.video_codecs,0,NULL,-1);
272 md->streams[1].payloads=l;
273 // if ZRTP is enabled, put the hello hash into the audiostream's desc
274 if (call->videostream->ms.zrtp_context!=NULL){
275 ortp_zrtp_get_hello_hash(call->videostream->ms.zrtp_context,
276 md->streams[1].zrtp_hello_hash,
277 sizeof(md->streams[1].zrtp_hello_hash));
278 ms_message("Video stream zrtp hash: %s", md->streams[1].zrtp_hello_hash);
281 if (md->n_total_streams < md->n_active_streams)
282 md->n_total_streams = md->n_active_streams;
284 /* Deactivate inactive streams. */
285 for (i = md->n_active_streams; i < md->n_total_streams; i++) {
286 md->streams[i].rtp_port = 0;
287 md->streams[i].rtcp_port = 0;
288 md->streams[i].proto = SalProtoRtpAvp;
289 md->streams[i].type = old_md->streams[i].type;
290 md->streams[i].dir = SalStreamInactive;
291 l = make_codec_list(lc, lc->codecs_conf.video_codecs, 0, NULL, 1);
292 md->streams[i].payloads = l;
295 for(i=0; i<md->n_active_streams; i++) {
296 if (md->streams[i].proto == SalProtoRtpSavp) {
297 if (keep_srtp_keys && old_md && old_md->streams[i].proto==SalProtoRtpSavp){
299 for(j=0;j<SAL_CRYPTO_ALGO_MAX;++j){
300 memcpy(&md->streams[i].crypto[j],&old_md->streams[i].crypto[j],sizeof(SalSrtpCryptoAlgo));
303 md->streams[i].crypto[0].tag = 1;
304 md->streams[i].crypto[0].algo = AES_128_SHA1_80;
305 if (!generate_b64_crypto_key(30, md->streams[i].crypto[0].master_key))
306 md->streams[i].crypto[0].algo = 0;
307 md->streams[i].crypto[1].tag = 2;
308 md->streams[i].crypto[1].algo = AES_128_SHA1_32;
309 if (!generate_b64_crypto_key(30, md->streams[i].crypto[1].master_key))
310 md->streams[i].crypto[1].algo = 0;
311 md->streams[i].crypto[2].algo = 0;
315 update_media_description_from_stun(md,&call->ac,&call->vc);
316 if (call->ice_session != NULL) {
317 linphone_core_update_local_media_description_from_ice(md, call->ice_session);
318 linphone_core_update_ice_state_in_call_stats(call);
321 if(call->upnp_session != NULL) {
322 linphone_core_update_local_media_description_from_upnp(md, call->upnp_session);
323 linphone_core_update_upnp_state_in_call_stats(call);
326 linphone_address_destroy(addr);
328 if (old_md) sal_media_description_unref(old_md);
331 static int find_port_offset(LinphoneCore *lc, SalStreamType type){
336 bool_t already_used=FALSE;
337 for(offset=0;offset<100;offset+=2){
341 tried_port=linphone_core_get_audio_port (lc)+offset;
344 tried_port=linphone_core_get_video_port (lc)+offset;
348 for(elem=lc->calls;elem!=NULL;elem=elem->next){
349 LinphoneCall *call=(LinphoneCall*)elem->data;
353 existing_port = call->audio_port;
356 existing_port = call->video_port;
359 if (existing_port==tried_port) {
364 if (!already_used) break;
367 ms_error("Could not find any free port !");
373 static int select_random_port(LinphoneCore *lc, SalStreamType type) {
377 int existing_port = 0;
378 int min_port = 0, max_port = 0;
379 bool_t already_used = FALSE;
384 linphone_core_get_audio_port_range(lc, &min_port, &max_port);
387 linphone_core_get_video_port_range(lc, &min_port, &max_port);
390 tried_port = (rand() % (max_port - min_port) + min_port) & ~0x1;
391 if (tried_port < min_port) tried_port = min_port + 2;
392 for (nb_tries = 0; nb_tries < 100; nb_tries++) {
393 for (elem = lc->calls; elem != NULL; elem = elem->next) {
394 LinphoneCall *call = (LinphoneCall *)elem->data;
398 existing_port = call->audio_port;
401 existing_port = call->video_port;
404 if (existing_port == tried_port) {
409 if (!already_used) break;
411 if (nb_tries == 100) {
412 ms_error("Could not find any free port!");
418 static void linphone_call_init_common(LinphoneCall *call, LinphoneAddress *from, LinphoneAddress *to){
420 int min_port, max_port;
421 call->magic=linphone_call_magic;
423 call->state=LinphoneCallIdle;
424 call->transfer_state = LinphoneCallIdle;
425 call->start_time=time(NULL);
426 call->media_start_time=0;
427 call->log=linphone_call_log_new(call, from, to);
428 call->owns_call_log=TRUE;
429 linphone_core_notify_all_friends(call->core,LinphoneStatusOnThePhone);
430 linphone_core_get_audio_port_range(call->core, &min_port, &max_port);
431 if (min_port == max_port) {
432 /* Used fixed RTP audio port. */
433 port_offset=find_port_offset (call->core, SalAudio);
434 if (port_offset==-1) return;
435 call->audio_port=linphone_core_get_audio_port(call->core)+port_offset;
437 /* Select random RTP audio port in the specified range. */
438 call->audio_port = select_random_port(call->core, SalAudio);
440 linphone_core_get_video_port_range(call->core, &min_port, &max_port);
441 if (min_port == max_port) {
442 /* Used fixed RTP video port. */
443 port_offset=find_port_offset (call->core, SalVideo);
444 if (port_offset==-1) return;
445 call->video_port=linphone_core_get_video_port(call->core)+port_offset;
447 /* Select random RTP video port in the specified range. */
448 call->video_port = select_random_port(call->core, SalVideo);
450 linphone_call_init_stats(&call->stats[LINPHONE_CALL_STATS_AUDIO], LINPHONE_CALL_STATS_AUDIO);
451 linphone_call_init_stats(&call->stats[LINPHONE_CALL_STATS_VIDEO], LINPHONE_CALL_STATS_VIDEO);
454 void linphone_call_init_stats(LinphoneCallStats *stats, int type) {
456 stats->received_rtcp = NULL;
457 stats->sent_rtcp = NULL;
458 stats->ice_state = LinphoneIceStateNotActivated;
460 stats->upnp_state = LinphoneUpnpStateIdle;
462 stats->upnp_state = LinphoneUpnpStateNotAvailable;
467 static void discover_mtu(LinphoneCore *lc, const char *remote){
469 if (lc->net_conf.mtu==0 ){
470 /*attempt to discover mtu*/
471 mtu=ms_discover_mtu(remote);
474 ms_message("Discovered mtu is %i, RTP payload max size is %i",
475 mtu, ms_get_payload_max_size());
480 LinphoneCall * linphone_call_new_outgoing(struct _LinphoneCore *lc, LinphoneAddress *from, LinphoneAddress *to, const LinphoneCallParams *params)
482 LinphoneCall *call=ms_new0(LinphoneCall,1);
483 call->dir=LinphoneCallOutgoing;
484 call->op=sal_op_new(lc->sal);
485 sal_op_set_user_pointer(call->op,call);
487 linphone_core_get_local_ip(lc,linphone_address_get_domain(to),call->localip);
488 linphone_call_init_common(call,from,to);
489 _linphone_call_params_copy(&call->params,params);
490 sal_op_set_custom_header(call->op,call->params.custom_headers);
491 call->params.custom_headers=NULL;
493 if (linphone_core_get_firewall_policy(call->core) == LinphonePolicyUseIce) {
494 call->ice_session = ice_session_new();
495 ice_session_set_role(call->ice_session, IR_Controlling);
497 if (linphone_core_get_firewall_policy(call->core) == LinphonePolicyUseStun) {
498 call->ping_time=linphone_core_run_stun_tests(call->core,call);
501 if (linphone_core_get_firewall_policy(call->core) == LinphonePolicyUseUpnp) {
502 if(!lc->rtp_conf.disable_upnp) {
503 call->upnp_session = linphone_upnp_session_new(call);
507 call->camera_active=params->has_video;
509 discover_mtu(lc,linphone_address_get_domain (to));
510 if (params->referer){
511 sal_call_set_referer(call->op,params->referer->op);
512 call->referer=linphone_call_ref(params->referer);
517 LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *from, LinphoneAddress *to, SalOp *op){
518 LinphoneCall *call=ms_new0(LinphoneCall,1);
520 const SalMediaDescription *md;
522 call->dir=LinphoneCallIncoming;
523 sal_op_set_user_pointer(op,call);
527 if (lc->sip_conf.ping_with_options){
529 if (lc->upnp != NULL && linphone_core_get_firewall_policy(lc)==LinphonePolicyUseUpnp &&
530 linphone_upnp_context_get_state(lc->upnp) == LinphoneUpnpStateOk) {
534 /*the following sends an option request back to the caller so that
535 we get a chance to discover our nat'd address before answering.*/
536 call->ping_op=sal_op_new(lc->sal);
537 from_str=linphone_address_as_string_uri_only(from);
538 sal_op_set_route(call->ping_op,sal_op_get_network_origin(op));
539 sal_op_set_user_pointer(call->ping_op,call);
540 sal_ping(call->ping_op,linphone_core_find_best_identity(lc,from,NULL),from_str);
545 linphone_address_clean(from);
546 linphone_core_get_local_ip(lc,linphone_address_get_domain(from),call->localip);
547 linphone_call_init_common(call, from, to);
548 call->log->call_id=ms_strdup(sal_op_get_call_id(op)); /*must be known at that time*/
549 linphone_core_init_default_params(lc, &call->params);
550 md=sal_call_get_remote_media_description(op);
551 call->params.has_video &= !!lc->video_policy.automatically_accept;
553 // It is licit to receive an INVITE without SDP
554 // In this case WE chose the media parameters according to policy.
555 call->params.has_video &= linphone_core_media_description_contains_video_stream(md);
557 switch (linphone_core_get_firewall_policy(call->core)) {
558 case LinphonePolicyUseIce:
559 call->ice_session = ice_session_new();
560 ice_session_set_role(call->ice_session, IR_Controlled);
561 linphone_core_update_ice_from_remote_media_description(call, sal_call_get_remote_media_description(op));
562 if (call->ice_session != NULL) {
563 linphone_call_init_media_streams(call);
564 linphone_call_start_media_streams_for_ice_gathering(call);
565 if (linphone_core_gather_ice_candidates(call->core,call)<0) {
566 /* Ice candidates gathering failed, proceed with the call anyway. */
567 linphone_call_delete_ice_session(call);
568 linphone_call_stop_media_streams_for_ice_gathering(call);
572 case LinphonePolicyUseStun:
573 call->ping_time=linphone_core_run_stun_tests(call->core,call);
574 /* No break to also destroy ice session in this case. */
576 case LinphonePolicyUseUpnp:
578 if(!lc->rtp_conf.disable_upnp) {
579 call->upnp_session = linphone_upnp_session_new(call);
580 if (call->upnp_session != NULL) {
581 linphone_call_init_media_streams(call);
582 if (linphone_core_update_upnp_from_remote_media_description(call, sal_call_get_remote_media_description(op))<0) {
583 /* uPnP port mappings failed, proceed with the call anyway. */
584 linphone_call_delete_upnp_session(call);
593 call->camera_active=call->params.has_video;
595 discover_mtu(lc,linphone_address_get_domain(from));
599 /* this function is called internally to get rid of a call.
600 It performs the following tasks:
601 - remove the call from the internal list of calls
602 - update the call logs accordingly
605 static void linphone_call_set_terminated(LinphoneCall *call){
606 LinphoneCore *lc=call->core;
608 linphone_core_update_allocated_audio_bandwidth(lc);
610 call->owns_call_log=FALSE;
611 linphone_call_log_completed(call);
614 if (call == lc->current_call){
615 ms_message("Resetting the current call");
616 lc->current_call=NULL;
619 if (linphone_core_del_call(lc,call) != 0){
620 ms_error("Could not remove the call from the list !!!");
623 if (ms_list_size(lc->calls)==0)
624 linphone_core_notify_all_friends(lc,lc->presence_mode);
626 linphone_core_conference_check_uninit(lc);
627 if (call->ringing_beep){
628 linphone_core_stop_dtmf(lc);
629 call->ringing_beep=FALSE;
632 linphone_call_unref(call->referer);
637 void linphone_call_fix_call_parameters(LinphoneCall *call){
638 call->params.has_video=call->current_params.has_video;
639 call->params.media_encryption=call->current_params.media_encryption;
642 const char *linphone_call_state_to_string(LinphoneCallState cs){
644 case LinphoneCallIdle:
645 return "LinphoneCallIdle";
646 case LinphoneCallIncomingReceived:
647 return "LinphoneCallIncomingReceived";
648 case LinphoneCallOutgoingInit:
649 return "LinphoneCallOutgoingInit";
650 case LinphoneCallOutgoingProgress:
651 return "LinphoneCallOutgoingProgress";
652 case LinphoneCallOutgoingRinging:
653 return "LinphoneCallOutgoingRinging";
654 case LinphoneCallOutgoingEarlyMedia:
655 return "LinphoneCallOutgoingEarlyMedia";
656 case LinphoneCallConnected:
657 return "LinphoneCallConnected";
658 case LinphoneCallStreamsRunning:
659 return "LinphoneCallStreamsRunning";
660 case LinphoneCallPausing:
661 return "LinphoneCallPausing";
662 case LinphoneCallPaused:
663 return "LinphoneCallPaused";
664 case LinphoneCallResuming:
665 return "LinphoneCallResuming";
666 case LinphoneCallRefered:
667 return "LinphoneCallRefered";
668 case LinphoneCallError:
669 return "LinphoneCallError";
670 case LinphoneCallEnd:
671 return "LinphoneCallEnd";
672 case LinphoneCallPausedByRemote:
673 return "LinphoneCallPausedByRemote";
674 case LinphoneCallUpdatedByRemote:
675 return "LinphoneCallUpdatedByRemote";
676 case LinphoneCallIncomingEarlyMedia:
677 return "LinphoneCallIncomingEarlyMedia";
678 case LinphoneCallUpdating:
679 return "LinphoneCallUpdating";
680 case LinphoneCallReleased:
681 return "LinphoneCallReleased";
683 return "undefined state";
686 void linphone_call_set_state(LinphoneCall *call, LinphoneCallState cstate, const char *message){
687 LinphoneCore *lc=call->core;
689 if (call->state!=cstate){
690 if (call->state==LinphoneCallEnd || call->state==LinphoneCallError){
691 if (cstate!=LinphoneCallReleased){
692 ms_warning("Spurious call state change from %s to %s, ignored.",linphone_call_state_to_string(call->state),
693 linphone_call_state_to_string(cstate));
697 ms_message("Call %p: moving from state %s to %s",call,linphone_call_state_to_string(call->state),
698 linphone_call_state_to_string(cstate));
699 if (cstate!=LinphoneCallRefered){
700 /*LinphoneCallRefered is rather an event, not a state.
701 Indeed it does not change the state of the call (still paused or running)*/
704 if (cstate==LinphoneCallEnd || cstate==LinphoneCallError){
705 switch(call->reason){
706 case LinphoneReasonDeclined:
707 call->log->status=LinphoneCallDeclined;
709 case LinphoneReasonNotAnswered:
710 call->log->status=LinphoneCallMissed;
715 linphone_call_set_terminated (call);
717 if (cstate == LinphoneCallConnected) {
718 call->log->status=LinphoneCallSuccess;
719 call->media_start_time=time(NULL);
722 if (lc->vtable.call_state_changed)
723 lc->vtable.call_state_changed(lc,call,cstate,message);
724 if (cstate==LinphoneCallReleased){
725 if (call->op!=NULL) {
726 /* so that we cannot have anymore upcalls for SAL
727 concerning this call*/
728 sal_op_release(call->op);
731 linphone_call_unref(call);
736 static void linphone_call_destroy(LinphoneCall *obj)
739 linphone_call_delete_upnp_session(obj);
741 linphone_call_delete_ice_session(obj);
743 sal_op_release(obj->op);
746 if (obj->resultdesc!=NULL) {
747 sal_media_description_unref(obj->resultdesc);
748 obj->resultdesc=NULL;
750 if (obj->localdesc!=NULL) {
751 sal_media_description_unref(obj->localdesc);
755 sal_op_release(obj->ping_op);
758 ms_free(obj->refer_to);
760 if (obj->owns_call_log)
761 linphone_call_log_destroy(obj->log);
762 if (obj->auth_token) {
763 ms_free(obj->auth_token);
765 linphone_call_params_uninit(&obj->params);
770 * @addtogroup call_control
775 * Increments the call 's reference count.
776 * An application that wishes to retain a pointer to call object
777 * must use this function to unsure the pointer remains
778 * valid. Once the application no more needs this pointer,
779 * it must call linphone_call_unref().
781 LinphoneCall * linphone_call_ref(LinphoneCall *obj){
787 * Decrements the call object reference count.
788 * See linphone_call_ref().
790 void linphone_call_unref(LinphoneCall *obj){
793 linphone_call_destroy(obj);
798 * Returns current parameters associated to the call.
800 const LinphoneCallParams * linphone_call_get_current_params(LinphoneCall *call){
801 if (call->params.record_file)
802 call->current_params.record_file=call->params.record_file;
803 return &call->current_params;
806 static bool_t is_video_active(const SalStreamDescription *sd){
807 return sd->rtp_port!=0 && sd->dir!=SalStreamInactive;
811 * Returns call parameters proposed by remote.
813 * This is useful when receiving an incoming call, to know whether the remote party
814 * supports video, encryption or whatever.
816 const LinphoneCallParams * linphone_call_get_remote_params(LinphoneCall *call){
817 LinphoneCallParams *cp=&call->remote_params;
818 memset(cp,0,sizeof(*cp));
820 SalMediaDescription *md=sal_call_get_remote_media_description(call->op);
822 SalStreamDescription *asd,*vsd,*secure_asd,*secure_vsd;
824 asd=sal_media_description_find_stream(md,SalProtoRtpAvp,SalAudio);
825 vsd=sal_media_description_find_stream(md,SalProtoRtpAvp,SalVideo);
826 secure_asd=sal_media_description_find_stream(md,SalProtoRtpSavp,SalAudio);
827 secure_vsd=sal_media_description_find_stream(md,SalProtoRtpSavp,SalVideo);
829 cp->has_video=is_video_active(secure_vsd);
830 if (secure_asd || asd==NULL)
831 cp->media_encryption=LinphoneMediaEncryptionSRTP;
833 cp->has_video=is_video_active(vsd);
836 if (md->bandwidth>0 && md->bandwidth<=linphone_core_get_edge_bw(call->core)){
837 cp->low_bandwidth=TRUE;
840 cp->custom_headers=(SalCustomHeader*)sal_op_get_custom_header(call->op);
848 * Returns the remote address associated to this call
851 const LinphoneAddress * linphone_call_get_remote_address(const LinphoneCall *call){
852 return call->dir==LinphoneCallIncoming ? call->log->from : call->log->to;
856 * Returns the remote address associated to this call as a string.
858 * The result string must be freed by user using ms_free().
860 char *linphone_call_get_remote_address_as_string(const LinphoneCall *call){
861 return linphone_address_as_string(linphone_call_get_remote_address(call));
865 * Retrieves the call's current state.
867 LinphoneCallState linphone_call_get_state(const LinphoneCall *call){
872 * Returns the reason for a call termination (either error or normal termination)
874 LinphoneReason linphone_call_get_reason(const LinphoneCall *call){
879 * Get the user_pointer in the LinphoneCall
881 * @ingroup call_control
883 * return user_pointer an opaque user pointer that can be retrieved at any time
885 void *linphone_call_get_user_pointer(LinphoneCall *call)
887 return call->user_pointer;
891 * Set the user_pointer in the LinphoneCall
893 * @ingroup call_control
895 * the user_pointer is an opaque user pointer that can be retrieved at any time in the LinphoneCall
897 void linphone_call_set_user_pointer(LinphoneCall *call, void *user_pointer)
899 call->user_pointer = user_pointer;
903 * Returns the call log associated to this call.
905 LinphoneCallLog *linphone_call_get_call_log(const LinphoneCall *call){
910 * Returns the refer-to uri (if the call was transfered).
912 const char *linphone_call_get_refer_to(const LinphoneCall *call){
913 return call->refer_to;
917 * Returns direction of the call (incoming or outgoing).
919 LinphoneCallDir linphone_call_get_dir(const LinphoneCall *call){
920 return call->log->dir;
924 * Returns the far end's user agent description string, if available.
926 const char *linphone_call_get_remote_user_agent(LinphoneCall *call){
928 return sal_op_get_remote_ua (call->op);
934 * Returns the far end's sip contact as a string, if available.
936 const char *linphone_call_get_remote_contact(LinphoneCall *call){
938 return sal_op_get_remote_contact(call->op);
944 * Returns true if this calls has received a transfer that has not been
946 * Pending transfers are executed when this call is being paused or closed,
947 * locally or by remote endpoint.
948 * If the call is already paused while receiving the transfer request, the
949 * transfer immediately occurs.
951 bool_t linphone_call_has_transfer_pending(const LinphoneCall *call){
952 return call->refer_pending;
956 * Returns call's duration in seconds.
958 int linphone_call_get_duration(const LinphoneCall *call){
959 if (call->media_start_time==0) return 0;
960 return time(NULL)-call->media_start_time;
964 * Returns the call object this call is replacing, if any.
965 * Call replacement can occur during call transfers.
966 * By default, the core automatically terminates the replaced call and accept the new one.
967 * This function allows the application to know whether a new incoming call is a one that replaces another one.
969 LinphoneCall *linphone_call_get_replaced_call(LinphoneCall *call){
970 SalOp *op=sal_call_get_replaces(call->op);
972 return (LinphoneCall*)sal_op_get_user_pointer(op);
978 * Indicate whether camera input should be sent to remote end.
980 void linphone_call_enable_camera (LinphoneCall *call, bool_t enable){
982 if (call->videostream!=NULL && call->videostream->ms.ticker!=NULL){
983 LinphoneCore *lc=call->core;
984 MSWebCam *nowebcam=get_nowebcam_device();
985 if (call->camera_active!=enable && lc->video_conf.device!=nowebcam){
986 video_stream_change_camera(call->videostream,
987 enable ? lc->video_conf.device : nowebcam);
990 call->camera_active=enable;
996 * Request remote side to send us a Video Fast Update.
998 void linphone_call_send_vfu_request(LinphoneCall *call)
1000 if (LinphoneCallStreamsRunning == linphone_call_get_state(call))
1001 sal_call_send_vfu_request(call->op);
1007 * Take a photo of currently received video and write it into a jpeg file.
1009 int linphone_call_take_video_snapshot(LinphoneCall *call, const char *file){
1010 #ifdef VIDEO_ENABLED
1011 if (call->videostream!=NULL && call->videostream->jpegwriter!=NULL){
1012 return ms_filter_call_method(call->videostream->jpegwriter,MS_JPEG_WRITER_TAKE_SNAPSHOT,(void*)file);
1014 ms_warning("Cannot take snapshot: no currently running video stream on this call.");
1021 * Returns TRUE if camera pictures are sent to the remote party.
1023 bool_t linphone_call_camera_enabled (const LinphoneCall *call){
1024 return call->camera_active;
1028 * Enable video stream.
1030 void linphone_call_params_enable_video(LinphoneCallParams *cp, bool_t enabled){
1031 cp->has_video=enabled;
1035 * Returns the audio codec used in the call, described as a PayloadType structure.
1037 const PayloadType* linphone_call_params_get_used_audio_codec(const LinphoneCallParams *cp) {
1038 return cp->audio_codec;
1043 * Returns the video codec used in the call, described as a PayloadType structure.
1045 const PayloadType* linphone_call_params_get_used_video_codec(const LinphoneCallParams *cp) {
1046 return cp->video_codec;
1050 * @ingroup call_control
1051 * Use to know if this call has been configured in low bandwidth mode.
1052 * This mode can be automatically discovered thanks to a stun server when activate_edge_workarounds=1 in section [net] of configuration file.
1053 * An application that would have reliable way to know network capacity may not use activate_edge_workarounds=1 but instead manually configure
1054 * low bandwidth mode with linphone_call_params_enable_low_bandwidth().
1055 * <br> When enabled, this param may transform a call request with video in audio only mode.
1056 * @return TRUE if low bandwidth has been configured/detected
1058 bool_t linphone_call_params_low_bandwidth_enabled(const LinphoneCallParams *cp) {
1059 return cp->low_bandwidth;
1063 * @ingroup call_control
1064 * Indicate low bandwith mode.
1065 * 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
1066 * 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
1067 * that it is achievable by the codec selected after SDP handshake. Video is automatically disabled.
1070 void linphone_call_params_enable_low_bandwidth(LinphoneCallParams *cp, bool_t enabled){
1071 cp->low_bandwidth=enabled;
1075 * Returns whether video is enabled.
1077 bool_t linphone_call_params_video_enabled(const LinphoneCallParams *cp){
1078 return cp->has_video;
1082 * Returns kind of media encryption selected for the call.
1084 enum LinphoneMediaEncryption linphone_call_params_get_media_encryption(const LinphoneCallParams *cp) {
1085 return cp->media_encryption;
1089 * Set requested media encryption for a call.
1091 void linphone_call_params_set_media_encryption(LinphoneCallParams *cp, enum LinphoneMediaEncryption e) {
1092 cp->media_encryption = e;
1097 * Enable sending of real early media (during outgoing calls).
1099 void linphone_call_params_enable_early_media_sending(LinphoneCallParams *cp, bool_t enabled){
1100 cp->real_early_media=enabled;
1104 * Indicates whether sending of early media was enabled.
1106 bool_t linphone_call_params_early_media_sending_enabled(const LinphoneCallParams *cp){
1107 return cp->real_early_media;
1111 * Returns true if the call is part of the locally managed conference.
1113 bool_t linphone_call_params_local_conference_mode(const LinphoneCallParams *cp){
1114 return cp->in_conference;
1118 * Refine bandwidth settings for this call by setting a bandwidth limit for audio streams.
1119 * As a consequence, codecs whose bitrates are not compatible with this limit won't be used.
1121 void linphone_call_params_set_audio_bandwidth_limit(LinphoneCallParams *cp, int bandwidth){
1122 cp->audio_bw=bandwidth;
1125 void linphone_call_params_add_custom_header(LinphoneCallParams *params, const char *header_name, const char *header_value){
1126 params->custom_headers=sal_custom_header_append(params->custom_headers,header_name,header_value);
1129 const char *linphone_call_params_get_custom_header(const LinphoneCallParams *params, const char *header_name){
1130 return sal_custom_header_find(params->custom_headers,header_name);
1133 void _linphone_call_params_copy(LinphoneCallParams *ncp, const LinphoneCallParams *cp){
1134 memcpy(ncp,cp,sizeof(LinphoneCallParams));
1135 if (cp->record_file) ncp->record_file=ms_strdup(cp->record_file);
1137 * The management of the custom headers is not optimal. We copy everything while ref counting would be more efficient.
1139 if (cp->custom_headers) ncp->custom_headers=sal_custom_header_clone(cp->custom_headers);
1143 * Copy existing LinphoneCallParams to a new LinphoneCallParams object.
1145 LinphoneCallParams * linphone_call_params_copy(const LinphoneCallParams *cp){
1146 LinphoneCallParams *ncp=ms_new0(LinphoneCallParams,1);
1147 _linphone_call_params_copy(ncp,cp);
1151 void linphone_call_params_uninit(LinphoneCallParams *p){
1152 if (p->record_file) ms_free(p->record_file);
1153 if (p->custom_headers) sal_custom_header_free(p->custom_headers);
1157 * Destroy LinphoneCallParams.
1159 void linphone_call_params_destroy(LinphoneCallParams *p){
1160 linphone_call_params_uninit(p);
1170 #ifdef TEST_EXT_RENDERER
1171 static void rendercb(void *data, const MSPicture *local, const MSPicture *remote){
1172 ms_message("rendercb, local buffer=%p, remote buffer=%p",
1173 local ? local->planes[0] : NULL, remote? remote->planes[0] : NULL);
1177 #ifdef VIDEO_ENABLED
1178 static void video_stream_event_cb(void *user_pointer, const MSFilter *f, const unsigned int event_id, const void *args){
1179 LinphoneCall* call = (LinphoneCall*) user_pointer;
1180 ms_warning("In linphonecall.c: video_stream_event_cb");
1182 case MS_VIDEO_DECODER_DECODING_ERRORS:
1183 ms_warning("Case is MS_VIDEO_DECODER_DECODING_ERRORS");
1184 linphone_call_send_vfu_request(call);
1186 case MS_VIDEO_DECODER_FIRST_IMAGE_DECODED:
1187 ms_message("First video frame decoded successfully");
1188 if (call->nextVideoFrameDecoded._func != NULL)
1189 call->nextVideoFrameDecoded._func(call, call->nextVideoFrameDecoded._user_data);
1192 ms_warning("Unhandled event %i", event_id);
1198 void linphone_call_set_next_video_frame_decoded_callback(LinphoneCall *call, LinphoneCallCbFunc cb, void* user_data) {
1199 call->nextVideoFrameDecoded._func = cb;
1200 call->nextVideoFrameDecoded._user_data = user_data;
1201 #ifdef VIDEO_ENABLED
1202 ms_filter_call_method_noarg(call->videostream->ms.decoder, MS_VIDEO_DECODER_RESET_FIRST_IMAGE_NOTIFICATION);
1206 void linphone_call_init_audio_stream(LinphoneCall *call){
1207 LinphoneCore *lc=call->core;
1208 AudioStream *audiostream;
1211 if (call->audiostream != NULL) return;
1212 call->audiostream=audiostream=audio_stream_new(call->audio_port,call->audio_port+1,linphone_core_ipv6_enabled(lc));
1213 dscp=linphone_core_get_audio_dscp(lc);
1215 audio_stream_set_dscp(audiostream,dscp);
1216 if (linphone_core_echo_limiter_enabled(lc)){
1217 const char *type=lp_config_get_string(lc->config,"sound","el_type","mic");
1218 if (strcasecmp(type,"mic")==0)
1219 audio_stream_enable_echo_limiter(audiostream,ELControlMic);
1220 else if (strcasecmp(type,"full")==0)
1221 audio_stream_enable_echo_limiter(audiostream,ELControlFull);
1223 audio_stream_enable_gain_control(audiostream,TRUE);
1224 if (linphone_core_echo_cancellation_enabled(lc)){
1225 int len,delay,framesize;
1226 const char *statestr=lp_config_get_string(lc->config,"sound","ec_state",NULL);
1227 len=lp_config_get_int(lc->config,"sound","ec_tail_len",0);
1228 delay=lp_config_get_int(lc->config,"sound","ec_delay",0);
1229 framesize=lp_config_get_int(lc->config,"sound","ec_framesize",0);
1230 audio_stream_set_echo_canceller_params(audiostream,len,delay,framesize);
1231 if (statestr && audiostream->ec){
1232 ms_filter_call_method(audiostream->ec,MS_ECHO_CANCELLER_SET_STATE_STRING,(void*)statestr);
1235 audio_stream_enable_automatic_gain_control(audiostream,linphone_core_agc_enabled(lc));
1237 int enabled=lp_config_get_int(lc->config,"sound","noisegate",0);
1238 audio_stream_enable_noise_gate(audiostream,enabled);
1241 audio_stream_set_features(audiostream,linphone_core_get_audio_features(lc));
1244 RtpTransport *artp=lc->rtptf->audio_rtp_func(lc->rtptf->audio_rtp_func_data, call->audio_port);
1245 RtpTransport *artcp=lc->rtptf->audio_rtcp_func(lc->rtptf->audio_rtcp_func_data, call->audio_port+1);
1246 rtp_session_set_transports(audiostream->ms.session,artp,artcp);
1248 if ((linphone_core_get_firewall_policy(lc) == LinphonePolicyUseIce) && (call->ice_session != NULL)){
1249 rtp_session_set_pktinfo(audiostream->ms.session, TRUE);
1250 rtp_session_set_symmetric_rtp(audiostream->ms.session, FALSE);
1251 if (ice_session_check_list(call->ice_session, 0) == NULL) {
1252 ice_session_add_check_list(call->ice_session, ice_check_list_new());
1254 audiostream->ms.ice_check_list = ice_session_check_list(call->ice_session, 0);
1255 ice_check_list_set_rtp_session(audiostream->ms.ice_check_list, audiostream->ms.session);
1258 call->audiostream_app_evq = ortp_ev_queue_new();
1259 rtp_session_register_event_queue(audiostream->ms.session,call->audiostream_app_evq);
1262 void linphone_call_init_video_stream(LinphoneCall *call){
1263 #ifdef VIDEO_ENABLED
1264 LinphoneCore *lc=call->core;
1266 if (!call->params.has_video) {
1267 linphone_call_stop_video_stream(call);
1270 if (call->videostream != NULL) return;
1271 if ((lc->video_conf.display || lc->video_conf.capture) && call->params.has_video){
1272 int video_recv_buf_size=lp_config_get_int(lc->config,"video","recv_buf_size",0);
1273 int dscp=linphone_core_get_video_dscp(lc);
1275 call->videostream=video_stream_new(call->video_port,call->video_port+1,linphone_core_ipv6_enabled(lc));
1277 video_stream_set_dscp(call->videostream,dscp);
1278 video_stream_enable_display_filter_auto_rotate(call->videostream, lp_config_get_int(lc->config,"video","display_filter_auto_rotate",0));
1279 if (video_recv_buf_size>0) rtp_session_set_recv_buf_size(call->videostream->ms.session,video_recv_buf_size);
1281 if( lc->video_conf.displaytype != NULL)
1282 video_stream_set_display_filter_name(call->videostream,lc->video_conf.displaytype);
1283 video_stream_set_event_callback(call->videostream,video_stream_event_cb, call);
1285 RtpTransport *vrtp=lc->rtptf->video_rtp_func(lc->rtptf->video_rtp_func_data, call->video_port);
1286 RtpTransport *vrtcp=lc->rtptf->video_rtcp_func(lc->rtptf->video_rtcp_func_data, call->video_port+1);
1287 rtp_session_set_transports(call->videostream->ms.session,vrtp,vrtcp);
1289 if ((linphone_core_get_firewall_policy(lc) == LinphonePolicyUseIce) && (call->ice_session != NULL)){
1290 rtp_session_set_pktinfo(call->videostream->ms.session, TRUE);
1291 rtp_session_set_symmetric_rtp(call->videostream->ms.session, FALSE);
1292 if (ice_session_check_list(call->ice_session, 1) == NULL) {
1293 ice_session_add_check_list(call->ice_session, ice_check_list_new());
1295 call->videostream->ms.ice_check_list = ice_session_check_list(call->ice_session, 1);
1296 ice_check_list_set_rtp_session(call->videostream->ms.ice_check_list, call->videostream->ms.session);
1298 call->videostream_app_evq = ortp_ev_queue_new();
1299 rtp_session_register_event_queue(call->videostream->ms.session,call->videostream_app_evq);
1300 #ifdef TEST_EXT_RENDERER
1301 video_stream_set_render_callback(call->videostream,rendercb,NULL);
1305 call->videostream=NULL;
1309 void linphone_call_init_media_streams(LinphoneCall *call){
1310 linphone_call_init_audio_stream(call);
1311 linphone_call_init_video_stream(call);
1313 // moved from linphone_call_start_media_streams, because ZRTP needs to be
1314 // at least partially initialized so that the SDP can contain 'zrtp-hash'
1315 if (call->params.media_encryption==LinphoneMediaEncryptionZRTP) {
1316 OrtpZrtpParams params;
1317 /*will be set later when zrtp is activated*/
1318 call->current_params.media_encryption=LinphoneMediaEncryptionNone;
1320 params.zid_file=call->core->zrtp_secrets_cache;
1321 audio_stream_enable_zrtp(call->audiostream,¶ms);
1322 } else if (call->params.media_encryption==LinphoneMediaEncryptionSRTP){
1323 call->current_params.media_encryption=linphone_call_are_all_streams_encrypted(call) ?
1324 LinphoneMediaEncryptionSRTP : LinphoneMediaEncryptionNone;
1329 static int dtmf_tab[16]={'0','1','2','3','4','5','6','7','8','9','*','#','A','B','C','D'};
1331 static void linphone_core_dtmf_received(LinphoneCore *lc, int dtmf){
1332 if (dtmf<0 || dtmf>15){
1333 ms_warning("Bad dtmf value %i",dtmf);
1336 if (lc->vtable.dtmf_received != NULL)
1337 lc->vtable.dtmf_received(lc, linphone_core_get_current_call(lc), dtmf_tab[dtmf]);
1340 static void parametrize_equalizer(LinphoneCore *lc, AudioStream *st){
1342 MSFilter *f=st->equalizer;
1343 int enabled=lp_config_get_int(lc->config,"sound","eq_active",0);
1344 const char *gains=lp_config_get_string(lc->config,"sound","eq_gains",NULL);
1345 ms_filter_call_method(f,MS_EQUALIZER_SET_ACTIVE,&enabled);
1351 if (sscanf(gains,"%f:%f:%f %n",&g.frequency,&g.gain,&g.width,&bytes)==3){
1352 ms_message("Read equalizer gains: %f(~%f) --> %f",g.frequency,g.width,g.gain);
1353 ms_filter_call_method(f,MS_EQUALIZER_SET_GAIN,&g);
1362 void _post_configure_audio_stream(AudioStream *st, LinphoneCore *lc, bool_t muted){
1363 float mic_gain=lc->sound_conf.soft_mic_lev;
1366 float ng_thres=lp_config_get_float(lc->config,"sound","ng_thres",0.05);
1367 float ng_floorgain=lp_config_get_float(lc->config,"sound","ng_floorgain",0);
1368 int dc_removal=lp_config_get_int(lc->config,"sound","dc_removal",0);
1371 linphone_core_set_mic_gain_db (lc, mic_gain);
1373 audio_stream_set_mic_gain(st,0);
1375 recv_gain = lc->sound_conf.soft_play_lev;
1376 if (recv_gain != 0) {
1377 linphone_core_set_playback_gain_db (lc,recv_gain);
1381 ms_filter_call_method(st->volsend,MS_VOLUME_REMOVE_DC,&dc_removal);
1382 float speed=lp_config_get_float(lc->config,"sound","el_speed",-1);
1383 thres=lp_config_get_float(lc->config,"sound","el_thres",-1);
1384 float force=lp_config_get_float(lc->config,"sound","el_force",-1);
1385 int sustain=lp_config_get_int(lc->config,"sound","el_sustain",-1);
1386 float transmit_thres=lp_config_get_float(lc->config,"sound","el_transmit_thres",-1);
1389 if (speed==-1) speed=0.03;
1390 if (force==-1) force=25;
1391 ms_filter_call_method(f,MS_VOLUME_SET_EA_SPEED,&speed);
1392 ms_filter_call_method(f,MS_VOLUME_SET_EA_FORCE,&force);
1394 ms_filter_call_method(f,MS_VOLUME_SET_EA_THRESHOLD,&thres);
1396 ms_filter_call_method(f,MS_VOLUME_SET_EA_SUSTAIN,&sustain);
1397 if (transmit_thres!=-1)
1398 ms_filter_call_method(f,MS_VOLUME_SET_EA_TRANSMIT_THRESHOLD,&transmit_thres);
1400 ms_filter_call_method(st->volsend,MS_VOLUME_SET_NOISE_GATE_THRESHOLD,&ng_thres);
1401 ms_filter_call_method(st->volsend,MS_VOLUME_SET_NOISE_GATE_FLOORGAIN,&ng_floorgain);
1404 /* parameters for a limited noise-gate effect, using echo limiter threshold */
1405 float floorgain = 1/pow(10,(mic_gain)/10);
1406 int spk_agc=lp_config_get_int(lc->config,"sound","speaker_agc_enabled",0);
1407 ms_filter_call_method(st->volrecv, MS_VOLUME_ENABLE_AGC, &spk_agc);
1408 ms_filter_call_method(st->volrecv,MS_VOLUME_SET_NOISE_GATE_THRESHOLD,&ng_thres);
1409 ms_filter_call_method(st->volrecv,MS_VOLUME_SET_NOISE_GATE_FLOORGAIN,&floorgain);
1411 parametrize_equalizer(lc,st);
1414 static void post_configure_audio_streams(LinphoneCall*call){
1415 AudioStream *st=call->audiostream;
1416 LinphoneCore *lc=call->core;
1417 _post_configure_audio_stream(st,lc,call->audio_muted);
1418 if (lc->vtable.dtmf_received!=NULL){
1419 audio_stream_play_received_dtmfs(call->audiostream,FALSE);
1421 if (call->record_active)
1422 linphone_call_start_recording(call);
1425 static RtpProfile *make_profile(LinphoneCall *call, const SalMediaDescription *md, const SalStreamDescription *desc, int *used_pt){
1428 RtpProfile *prof=rtp_profile_new("Call profile");
1431 LinphoneCore *lc=call->core;
1433 const LinphoneCallParams *params=&call->params;
1436 for(elem=desc->payloads;elem!=NULL;elem=elem->next){
1437 PayloadType *pt=(PayloadType*)elem->data;
1440 if ((pt->flags & PAYLOAD_TYPE_FLAG_CAN_SEND) && first) {
1441 if (desc->type==SalAudio){
1442 linphone_core_update_allocated_audio_bandwidth_in_call(call,pt);
1443 if (params->up_ptime)
1444 up_ptime=params->up_ptime;
1445 else up_ptime=linphone_core_get_upload_ptime(lc);
1447 *used_pt=payload_type_get_number(pt);
1450 if (desc->bandwidth>0) remote_bw=desc->bandwidth;
1451 else if (md->bandwidth>0) {
1452 /*case where b=AS is given globally, not per stream*/
1453 remote_bw=md->bandwidth;
1454 if (desc->type==SalVideo){
1455 remote_bw=get_video_bandwidth(remote_bw,call->audio_bw);
1459 if (desc->type==SalAudio){
1460 int audio_bw=call->audio_bw;
1462 if (params->up_bw< audio_bw)
1463 audio_bw=params->up_bw;
1465 bw=get_min_bandwidth(audio_bw,remote_bw);
1466 }else bw=get_min_bandwidth(get_video_bandwidth(linphone_core_get_upload_bandwidth (lc),call->audio_bw),remote_bw);
1467 if (bw>0) pt->normal_bitrate=bw*1000;
1468 else if (desc->type==SalAudio){
1469 pt->normal_bitrate=-1;
1472 up_ptime=desc->ptime;
1476 snprintf(tmp,sizeof(tmp),"ptime=%i",up_ptime);
1477 payload_type_append_send_fmtp(pt,tmp);
1479 number=payload_type_get_number(pt);
1480 if (rtp_profile_get_payload(prof,number)!=NULL){
1481 ms_warning("A payload type with number %i already exists in profile !",number);
1483 rtp_profile_set_payload(prof,number,pt);
1489 static void setup_ring_player(LinphoneCore *lc, LinphoneCall *call){
1490 int pause_time=3000;
1491 audio_stream_play(call->audiostream,lc->sound_conf.ringback_tone);
1492 ms_filter_call_method(call->audiostream->soundread,MS_FILE_PLAYER_LOOP,&pause_time);
1495 static bool_t linphone_call_sound_resources_available(LinphoneCall *call){
1496 LinphoneCore *lc=call->core;
1497 LinphoneCall *current=linphone_core_get_current_call(lc);
1498 return !linphone_core_is_in_conference(lc) &&
1499 (current==NULL || current==call);
1501 static int find_crypto_index_from_tag(const SalSrtpCryptoAlgo crypto[],unsigned char tag) {
1503 for(i=0; i<SAL_CRYPTO_ALGO_MAX; i++) {
1504 if (crypto[i].tag == tag) {
1510 static void linphone_call_start_audio_stream(LinphoneCall *call, const char *cname, bool_t muted, bool_t send_ringbacktone, bool_t use_arc){
1511 LinphoneCore *lc=call->core;
1513 char rtcp_tool[128]={0};
1514 snprintf(rtcp_tool,sizeof(rtcp_tool)-1,"%s-%s",linphone_core_get_user_agent_name(),linphone_core_get_user_agent_version());
1515 /* look for savp stream first */
1516 const SalStreamDescription *stream=sal_media_description_find_stream(call->resultdesc,
1517 SalProtoRtpSavp,SalAudio);
1518 /* no savp audio stream, use avp */
1520 stream=sal_media_description_find_stream(call->resultdesc,
1521 SalProtoRtpAvp,SalAudio);
1523 if (stream && stream->dir!=SalStreamInactive && stream->rtp_port!=0){
1524 MSSndCard *playcard=lc->sound_conf.lsd_card ?
1525 lc->sound_conf.lsd_card : lc->sound_conf.play_sndcard;
1526 MSSndCard *captcard=lc->sound_conf.capt_sndcard;
1527 const char *playfile=lc->play_file;
1528 const char *recfile=lc->rec_file;
1529 call->audio_profile=make_profile(call,call->resultdesc,stream,&used_pt);
1533 call->current_params.audio_codec = rtp_profile_get_payload(call->audio_profile, used_pt);
1534 if (playcard==NULL) {
1535 ms_warning("No card defined for playback !");
1537 if (captcard==NULL) {
1538 ms_warning("No card defined for capture !");
1540 /*Replace soundcard filters by inactive file players or recorders
1541 when placed in recvonly or sendonly mode*/
1542 if (stream->rtp_port==0 || stream->dir==SalStreamRecvOnly){
1545 }else if (stream->dir==SalStreamSendOnly){
1549 /*And we will eventually play "playfile" if set by the user*/
1552 if (send_ringbacktone){
1554 playfile=NULL;/* it is setup later*/
1556 /*if playfile are supplied don't use soundcards*/
1557 if (lc->use_files) {
1561 if (call->params.in_conference){
1562 /* first create the graph without soundcard resources*/
1563 captcard=playcard=NULL;
1565 if (!linphone_call_sound_resources_available(call)){
1566 ms_message("Sound resources are used by another call, not using soundcard.");
1567 captcard=playcard=NULL;
1569 use_ec=captcard==NULL ? FALSE : linphone_core_echo_cancellation_enabled(lc);
1570 if (playcard && stream->max_rate>0) ms_snd_card_set_preferred_sample_rate(playcard, stream->max_rate);
1571 if (captcard && stream->max_rate>0) ms_snd_card_set_preferred_sample_rate(captcard, stream->max_rate);
1572 audio_stream_enable_adaptive_bitrate_control(call->audiostream,use_arc);
1573 audio_stream_enable_adaptive_jittcomp(call->audiostream, linphone_core_audio_adaptive_jittcomp_enabled(lc));
1574 if (!call->params.in_conference && call->params.record_file)
1575 audio_stream_mixed_record_open(call->audiostream,call->params.record_file);
1576 audio_stream_start_full(
1578 call->audio_profile,
1579 stream->rtp_addr[0]!='\0' ? stream->rtp_addr : call->resultdesc->addr,
1581 stream->rtcp_addr[0]!='\0' ? stream->rtcp_addr : call->resultdesc->addr,
1582 linphone_core_rtcp_enabled(lc) ? (stream->rtcp_port) : 0,
1584 linphone_core_get_audio_jittcomp(lc),
1591 post_configure_audio_streams(call);
1592 if (muted && !send_ringbacktone){
1593 audio_stream_set_mic_gain(call->audiostream,0);
1595 if (stream->dir==SalStreamSendOnly && playfile!=NULL){
1597 ms_filter_call_method(call->audiostream->soundread,MS_FILE_PLAYER_LOOP,&pause_time);
1599 if (send_ringbacktone){
1600 setup_ring_player(lc,call);
1602 audio_stream_set_rtcp_information(call->audiostream, cname, rtcp_tool);
1604 /* valid local tags are > 0 */
1605 if (stream->proto == SalProtoRtpSavp) {
1606 const SalStreamDescription *local_st_desc=sal_media_description_find_stream(call->localdesc,
1607 SalProtoRtpSavp,SalAudio);
1608 int crypto_idx = find_crypto_index_from_tag(local_st_desc->crypto, stream->crypto_local_tag);
1610 if (crypto_idx >= 0) {
1611 audio_stream_enable_srtp(
1613 stream->crypto[0].algo,
1614 local_st_desc->crypto[crypto_idx].master_key,
1615 stream->crypto[0].master_key);
1616 call->audiostream_encrypted=TRUE;
1618 ms_warning("Failed to find local crypto algo with tag: %d", stream->crypto_local_tag);
1619 call->audiostream_encrypted=FALSE;
1621 }else call->audiostream_encrypted=FALSE;
1622 if (call->params.in_conference){
1623 /*transform the graph to connect it to the conference filter */
1624 bool_t mute=stream->dir==SalStreamRecvOnly;
1625 linphone_call_add_to_conf(call, mute);
1627 call->current_params.in_conference=call->params.in_conference;
1628 call->current_params.low_bandwidth=call->params.low_bandwidth;
1629 }else ms_warning("No audio stream accepted ?");
1633 static void linphone_call_start_video_stream(LinphoneCall *call, const char *cname,bool_t all_inputs_muted){
1634 #ifdef VIDEO_ENABLED
1635 LinphoneCore *lc=call->core;
1637 /* look for savp stream first */
1638 const SalStreamDescription *vstream=sal_media_description_find_stream(call->resultdesc,
1639 SalProtoRtpSavp,SalVideo);
1640 char rtcp_tool[128]={0};
1641 snprintf(rtcp_tool,sizeof(rtcp_tool)-1,"%s-%s",linphone_core_get_user_agent_name(),linphone_core_get_user_agent_version());
1643 /* no savp audio stream, use avp */
1645 vstream=sal_media_description_find_stream(call->resultdesc,
1646 SalProtoRtpAvp,SalVideo);
1648 /* shutdown preview */
1649 if (lc->previewstream!=NULL) {
1650 video_preview_stop(lc->previewstream);
1651 lc->previewstream=NULL;
1654 if (vstream!=NULL && vstream->dir!=SalStreamInactive && vstream->rtp_port!=0) {
1655 const char *rtp_addr=vstream->rtp_addr[0]!='\0' ? vstream->rtp_addr : call->resultdesc->addr;
1656 const char *rtcp_addr=vstream->rtcp_addr[0]!='\0' ? vstream->rtcp_addr : call->resultdesc->addr;
1657 call->video_profile=make_profile(call,call->resultdesc,vstream,&used_pt);
1659 call->current_params.video_codec = rtp_profile_get_payload(call->video_profile, used_pt);
1660 VideoStreamDir dir=VideoStreamSendRecv;
1661 MSWebCam *cam=lc->video_conf.device;
1662 bool_t is_inactive=FALSE;
1664 call->current_params.has_video=TRUE;
1666 video_stream_enable_adaptive_bitrate_control(call->videostream,
1667 linphone_core_adaptive_rate_control_enabled(lc));
1668 video_stream_enable_adaptive_jittcomp(call->videostream, linphone_core_video_adaptive_jittcomp_enabled(lc));
1669 video_stream_set_sent_video_size(call->videostream,linphone_core_get_preferred_video_size(lc));
1670 video_stream_enable_self_view(call->videostream,lc->video_conf.selfview);
1671 if (lc->video_window_id!=0)
1672 video_stream_set_native_window_id(call->videostream,lc->video_window_id);
1673 if (lc->preview_window_id!=0)
1674 video_stream_set_native_preview_window_id (call->videostream,lc->preview_window_id);
1675 video_stream_use_preview_video_window (call->videostream,lc->use_preview_window);
1677 if (vstream->dir==SalStreamSendOnly && lc->video_conf.capture ){
1678 cam=get_nowebcam_device();
1679 dir=VideoStreamSendOnly;
1680 }else if (vstream->dir==SalStreamRecvOnly && lc->video_conf.display ){
1681 dir=VideoStreamRecvOnly;
1682 }else if (vstream->dir==SalStreamSendRecv){
1683 if (lc->video_conf.display && lc->video_conf.capture)
1684 dir=VideoStreamSendRecv;
1685 else if (lc->video_conf.display)
1686 dir=VideoStreamRecvOnly;
1688 dir=VideoStreamSendOnly;
1690 ms_warning("video stream is inactive.");
1691 /*either inactive or incompatible with local capabilities*/
1694 if (call->camera_active==FALSE || all_inputs_muted){
1695 cam=get_nowebcam_device();
1698 call->log->video_enabled = TRUE;
1699 video_stream_set_direction (call->videostream, dir);
1700 ms_message("%s lc rotation:%d\n", __FUNCTION__, lc->device_rotation);
1701 video_stream_set_device_rotation(call->videostream, lc->device_rotation);
1702 video_stream_start(call->videostream,
1703 call->video_profile, rtp_addr, vstream->rtp_port,
1704 rtcp_addr, linphone_core_rtcp_enabled(lc) ? (vstream->rtcp_port) : 0,
1705 used_pt, linphone_core_get_video_jittcomp(lc), cam);
1706 video_stream_set_rtcp_information(call->videostream, cname,rtcp_tool);
1709 if (vstream->proto == SalProtoRtpSavp) {
1710 const SalStreamDescription *local_st_desc=sal_media_description_find_stream(call->localdesc,
1711 SalProtoRtpSavp,SalVideo);
1713 video_stream_enable_strp(
1715 vstream->crypto[0].algo,
1716 local_st_desc->crypto[0].master_key,
1717 vstream->crypto[0].master_key
1719 call->videostream_encrypted=TRUE;
1721 call->videostream_encrypted=FALSE;
1723 }else ms_warning("No video stream accepted.");
1725 ms_warning("No valid video stream defined.");
1730 void linphone_call_start_media_streams(LinphoneCall *call, bool_t all_inputs_muted, bool_t send_ringbacktone){
1731 LinphoneCore *lc=call->core;
1733 call->current_params.audio_codec = NULL;
1734 call->current_params.video_codec = NULL;
1736 LinphoneAddress *me=linphone_core_get_primary_contact_parsed(lc);
1738 bool_t use_arc=linphone_core_adaptive_rate_control_enabled(lc);
1739 #ifdef VIDEO_ENABLED
1740 const SalStreamDescription *vstream=sal_media_description_find_stream(call->resultdesc,
1741 SalProtoRtpAvp,SalVideo);
1744 if ((call->audiostream == NULL) && (call->videostream == NULL)) {
1745 ms_fatal("start_media_stream() called without prior init !");
1748 cname=linphone_address_as_string_uri_only(me);
1750 #if defined(VIDEO_ENABLED)
1751 if (vstream!=NULL && vstream->dir!=SalStreamInactive && vstream->payloads!=NULL){
1752 /*when video is used, do not make adaptive rate control on audio, it is stupid.*/
1756 if (call->audiostream!=NULL) {
1757 linphone_call_start_audio_stream(call,cname,all_inputs_muted,send_ringbacktone,use_arc);
1759 call->current_params.has_video=FALSE;
1760 if (call->videostream!=NULL) {
1761 linphone_call_start_video_stream(call,cname,all_inputs_muted);
1764 call->all_muted=all_inputs_muted;
1765 call->playing_ringbacktone=send_ringbacktone;
1766 call->up_bw=linphone_core_get_upload_bandwidth(lc);
1768 // ZRTP was initialized in linphone_call_init_media_streams with a
1769 // partially iniitalized RtpSession, and now needs to get an update
1770 if (call->params.media_encryption==LinphoneMediaEncryptionZRTP) {
1771 ortp_zrtp_start_engine(call->audiostream->ms.zrtp_context,call->audiostream->ms.session);
1774 /*also reflect the change if the "wished" params, in order to avoid to propose SAVP or video again
1775 * further in the call, for example during pause,resume, conferencing reINVITEs*/
1776 linphone_call_fix_call_parameters(call);
1777 if ((call->ice_session != NULL) && (ice_session_state(call->ice_session) != IS_Completed)) {
1778 ice_session_start_connectivity_checks(call->ice_session);
1784 linphone_address_destroy(me);
1787 void linphone_call_start_media_streams_for_ice_gathering(LinphoneCall *call){
1788 audio_stream_prepare_sound(call->audiostream, NULL, NULL);
1789 #ifdef VIDEO_ENABLED
1790 if (call->videostream) {
1791 video_stream_prepare_video(call->videostream);
1796 void linphone_call_stop_media_streams_for_ice_gathering(LinphoneCall *call){
1797 audio_stream_unprepare_sound(call->audiostream);
1798 #ifdef VIDEO_ENABLED
1799 if (call->videostream) {
1800 video_stream_unprepare_video(call->videostream);
1805 void linphone_call_update_crypto_parameters(LinphoneCall *call, SalMediaDescription *old_md, SalMediaDescription *new_md) {
1806 SalStreamDescription *old_stream;
1807 SalStreamDescription *new_stream;
1810 old_stream = sal_media_description_find_stream(old_md, SalProtoRtpSavp, SalAudio);
1811 new_stream = sal_media_description_find_stream(new_md, SalProtoRtpSavp, SalAudio);
1812 if (old_stream && new_stream) {
1813 const SalStreamDescription *local_st_desc = sal_media_description_find_stream(call->localdesc, SalProtoRtpSavp, SalAudio);
1814 if (local_st_desc) {
1815 int crypto_idx = find_crypto_index_from_tag(local_st_desc->crypto, new_stream->crypto_local_tag);
1816 if (crypto_idx >= 0) {
1817 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);
1818 call->audiostream_encrypted = TRUE;
1820 ms_warning("Failed to find local crypto algo with tag: %d", new_stream->crypto_local_tag);
1821 call->audiostream_encrypted = FALSE;
1823 for (i = 0; i < SAL_CRYPTO_ALGO_MAX; i++) {
1824 old_stream->crypto[i].tag = new_stream->crypto[i].tag;
1825 old_stream->crypto[i].algo = new_stream->crypto[i].algo;
1826 strncpy(old_stream->crypto[i].master_key, new_stream->crypto[i].master_key, sizeof(old_stream->crypto[i].master_key) - 1);
1831 #ifdef VIDEO_ENABLED
1832 old_stream = sal_media_description_find_stream(old_md, SalProtoRtpSavp, SalVideo);
1833 new_stream = sal_media_description_find_stream(new_md, SalProtoRtpSavp, SalVideo);
1834 if (old_stream && new_stream) {
1835 const SalStreamDescription *local_st_desc = sal_media_description_find_stream(call->localdesc, SalProtoRtpSavp, SalVideo);
1836 if (local_st_desc) {
1837 int crypto_idx = find_crypto_index_from_tag(local_st_desc->crypto, new_stream->crypto_local_tag);
1838 if (crypto_idx >= 0) {
1839 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);
1840 call->videostream_encrypted = TRUE;
1842 ms_warning("Failed to find local crypto algo with tag: %d", new_stream->crypto_local_tag);
1843 call->videostream_encrypted = FALSE;
1845 for (i = 0; i < SAL_CRYPTO_ALGO_MAX; i++) {
1846 old_stream->crypto[i].tag = new_stream->crypto[i].tag;
1847 old_stream->crypto[i].algo = new_stream->crypto[i].algo;
1848 strncpy(old_stream->crypto[i].master_key, new_stream->crypto[i].master_key, sizeof(old_stream->crypto[i].master_key) - 1);
1855 void linphone_call_update_remote_session_id_and_ver(LinphoneCall *call) {
1856 SalMediaDescription *remote_desc = sal_call_get_remote_media_description(call->op);
1858 call->remote_session_id = remote_desc->session_id;
1859 call->remote_session_ver = remote_desc->session_ver;
1863 void linphone_call_delete_ice_session(LinphoneCall *call){
1864 if (call->ice_session != NULL) {
1865 ice_session_destroy(call->ice_session);
1866 call->ice_session = NULL;
1867 if (call->audiostream != NULL) call->audiostream->ms.ice_check_list = NULL;
1868 if (call->videostream != NULL) call->videostream->ms.ice_check_list = NULL;
1869 call->stats[LINPHONE_CALL_STATS_AUDIO].ice_state = LinphoneIceStateNotActivated;
1870 call->stats[LINPHONE_CALL_STATS_VIDEO].ice_state = LinphoneIceStateNotActivated;
1875 void linphone_call_delete_upnp_session(LinphoneCall *call){
1876 if(call->upnp_session!=NULL) {
1877 linphone_upnp_session_destroy(call->upnp_session);
1878 call->upnp_session=NULL;
1883 static void linphone_call_log_fill_stats(LinphoneCallLog *log, AudioStream *st){
1884 audio_stream_get_local_rtp_stats (st,&log->local_stats);
1885 log->quality=audio_stream_get_average_quality_rating(st);
1888 void linphone_call_stop_audio_stream(LinphoneCall *call) {
1889 if (call->audiostream!=NULL) {
1890 rtp_session_unregister_event_queue(call->audiostream->ms.session,call->audiostream_app_evq);
1891 ortp_ev_queue_flush(call->audiostream_app_evq);
1892 ortp_ev_queue_destroy(call->audiostream_app_evq);
1893 call->audiostream_app_evq=NULL;
1895 if (call->audiostream->ec){
1896 const char *state_str=NULL;
1897 ms_filter_call_method(call->audiostream->ec,MS_ECHO_CANCELLER_GET_STATE_STRING,&state_str);
1899 ms_message("Writing echo canceler state, %i bytes",(int)strlen(state_str));
1900 lp_config_set_string(call->core->config,"sound","ec_state",state_str);
1903 linphone_call_log_fill_stats (call->log,call->audiostream);
1904 if (call->endpoint){
1905 linphone_call_remove_from_conf(call);
1907 audio_stream_stop(call->audiostream);
1908 call->audiostream=NULL;
1912 void linphone_call_stop_video_stream(LinphoneCall *call) {
1913 #ifdef VIDEO_ENABLED
1914 if (call->videostream!=NULL){
1915 rtp_session_unregister_event_queue(call->videostream->ms.session,call->videostream_app_evq);
1916 ortp_ev_queue_flush(call->videostream_app_evq);
1917 ortp_ev_queue_destroy(call->videostream_app_evq);
1918 call->videostream_app_evq=NULL;
1919 video_stream_stop(call->videostream);
1920 call->videostream=NULL;
1925 void linphone_call_stop_media_streams(LinphoneCall *call){
1926 linphone_call_stop_audio_stream(call);
1927 linphone_call_stop_video_stream(call);
1928 ms_event_queue_skip(call->core->msevq);
1930 if (call->audio_profile){
1931 rtp_profile_clear_all(call->audio_profile);
1932 rtp_profile_destroy(call->audio_profile);
1933 call->audio_profile=NULL;
1935 if (call->video_profile){
1936 rtp_profile_clear_all(call->video_profile);
1937 rtp_profile_destroy(call->video_profile);
1938 call->video_profile=NULL;
1944 void linphone_call_enable_echo_cancellation(LinphoneCall *call, bool_t enable) {
1945 if (call!=NULL && call->audiostream!=NULL && call->audiostream->ec){
1946 bool_t bypass_mode = !enable;
1947 ms_filter_call_method(call->audiostream->ec,MS_ECHO_CANCELLER_SET_BYPASS_MODE,&bypass_mode);
1950 bool_t linphone_call_echo_cancellation_enabled(LinphoneCall *call) {
1951 if (call!=NULL && call->audiostream!=NULL && call->audiostream->ec){
1953 ms_filter_call_method(call->audiostream->ec,MS_ECHO_CANCELLER_GET_BYPASS_MODE,&val);
1956 return linphone_core_echo_cancellation_enabled(call->core);
1960 void linphone_call_enable_echo_limiter(LinphoneCall *call, bool_t val){
1961 if (call!=NULL && call->audiostream!=NULL ) {
1963 const char *type=lp_config_get_string(call->core->config,"sound","el_type","mic");
1964 if (strcasecmp(type,"mic")==0)
1965 audio_stream_enable_echo_limiter(call->audiostream,ELControlMic);
1966 else if (strcasecmp(type,"full")==0)
1967 audio_stream_enable_echo_limiter(call->audiostream,ELControlFull);
1969 audio_stream_enable_echo_limiter(call->audiostream,ELInactive);
1974 bool_t linphone_call_echo_limiter_enabled(const LinphoneCall *call){
1975 if (call!=NULL && call->audiostream!=NULL ){
1976 return call->audiostream->el_type !=ELInactive ;
1978 return linphone_core_echo_limiter_enabled(call->core);
1983 * @addtogroup call_misc
1988 * Returns the measured sound volume played locally (received from remote).
1989 * It is expressed in dbm0.
1991 float linphone_call_get_play_volume(LinphoneCall *call){
1992 AudioStream *st=call->audiostream;
1993 if (st && st->volrecv){
1995 ms_filter_call_method(st->volrecv,MS_VOLUME_GET,&vol);
1999 return LINPHONE_VOLUME_DB_LOWEST;
2003 * Returns the measured sound volume recorded locally (sent to remote).
2004 * It is expressed in dbm0.
2006 float linphone_call_get_record_volume(LinphoneCall *call){
2007 AudioStream *st=call->audiostream;
2008 if (st && st->volsend && !call->audio_muted && call->state==LinphoneCallStreamsRunning){
2010 ms_filter_call_method(st->volsend,MS_VOLUME_GET,&vol);
2014 return LINPHONE_VOLUME_DB_LOWEST;
2018 * Obtain real-time quality rating of the call
2020 * Based on local RTP statistics and RTCP feedback, a quality rating is computed and updated
2021 * during all the duration of the call. This function returns its value at the time of the function call.
2022 * It is expected that the rating is updated at least every 5 seconds or so.
2023 * The rating is a floating point number comprised between 0 and 5.
2025 * 4-5 = good quality <br>
2026 * 3-4 = average quality <br>
2027 * 2-3 = poor quality <br>
2028 * 1-2 = very poor quality <br>
2029 * 0-1 = can't be worse, mostly unusable <br>
2031 * @returns The function returns -1 if no quality measurement is available, for example if no
2032 * active audio stream exist. Otherwise it returns the quality rating.
2034 float linphone_call_get_current_quality(LinphoneCall *call){
2035 if (call->audiostream){
2036 return audio_stream_get_quality_rating(call->audiostream);
2042 * Returns call quality averaged over all the duration of the call.
2044 * See linphone_call_get_current_quality() for more details about quality measurement.
2046 float linphone_call_get_average_quality(LinphoneCall *call){
2047 if (call->audiostream){
2048 return audio_stream_get_average_quality_rating(call->audiostream);
2054 * Access last known statistics for audio stream, for a given call.
2056 const LinphoneCallStats *linphone_call_get_audio_stats(const LinphoneCall *call) {
2057 return &call->stats[LINPHONE_CALL_STATS_AUDIO];
2061 * Access last known statistics for video stream, for a given call.
2063 const LinphoneCallStats *linphone_call_get_video_stats(const LinphoneCall *call) {
2064 return &call->stats[LINPHONE_CALL_STATS_VIDEO];
2068 * Enable recording of the call (voice-only).
2069 * This function must be used before the call parameters are assigned to the call.
2070 * The call recording can be started and paused after the call is established with
2071 * linphone_call_start_recording() and linphone_call_pause_recording().
2072 * @param cp the call parameters
2073 * @param path path and filename of the file where audio is written.
2075 void linphone_call_params_set_record_file(LinphoneCallParams *cp, const char *path){
2076 if (cp->record_file){
2077 ms_free(cp->record_file);
2078 cp->record_file=NULL;
2080 if (path) cp->record_file=ms_strdup(path);
2084 * Retrieves the path for the audio recoding of the call.
2086 const char *linphone_call_params_get_record_file(const LinphoneCallParams *cp){
2087 return cp->record_file;
2091 * Start call recording.
2092 * The output file where audio is recorded must be previously specified with linphone_call_params_set_record_file().
2094 void linphone_call_start_recording(LinphoneCall *call){
2095 if (!call->params.record_file){
2096 ms_error("linphone_call_start_recording(): no output file specified. Use linphone_call_params_set_record_file().");
2099 if (call->audiostream && !call->params.in_conference){
2100 audio_stream_mixed_record_start(call->audiostream);
2102 call->record_active=TRUE;
2106 * Stop call recording.
2108 void linphone_call_stop_recording(LinphoneCall *call){
2109 if (call->audiostream && !call->params.in_conference){
2110 audio_stream_mixed_record_stop(call->audiostream);
2112 call->record_active=FALSE;
2119 static void report_bandwidth(LinphoneCall *call, RtpSession *as, RtpSession *vs){
2120 call->stats[LINPHONE_CALL_STATS_AUDIO].download_bandwidth=(as!=NULL) ? (rtp_session_compute_recv_bandwidth(as)*1e-3) : 0;
2121 call->stats[LINPHONE_CALL_STATS_AUDIO].upload_bandwidth=(as!=NULL) ? (rtp_session_compute_send_bandwidth(as)*1e-3) : 0;
2122 call->stats[LINPHONE_CALL_STATS_VIDEO].download_bandwidth=(vs!=NULL) ? (rtp_session_compute_recv_bandwidth(vs)*1e-3) : 0;
2123 call->stats[LINPHONE_CALL_STATS_VIDEO].upload_bandwidth=(vs!=NULL) ? (rtp_session_compute_send_bandwidth(vs)*1e-3) : 0;
2124 ms_message("bandwidth usage: audio=[d=%.1f,u=%.1f] video=[d=%.1f,u=%.1f] kbit/sec",
2125 call->stats[LINPHONE_CALL_STATS_AUDIO].download_bandwidth,
2126 call->stats[LINPHONE_CALL_STATS_AUDIO].upload_bandwidth ,
2127 call->stats[LINPHONE_CALL_STATS_VIDEO].download_bandwidth,
2128 call->stats[LINPHONE_CALL_STATS_VIDEO].upload_bandwidth
2132 static void linphone_core_disconnected(LinphoneCore *lc, LinphoneCall *call){
2136 from = linphone_call_get_remote_address_as_string(call);
2139 snprintf(temp,sizeof(temp),"Remote end %s seems to have disconnected, the call is going to be closed.",from);
2144 snprintf(temp,sizeof(temp),"Remote end seems to have disconnected, the call is going to be closed.");
2146 if (lc->vtable.display_warning!=NULL)
2147 lc->vtable.display_warning(lc,temp);
2148 linphone_core_terminate_call(lc,call);
2149 linphone_core_play_named_tone(lc,LinphoneToneCallFailed);
2152 static void handle_ice_events(LinphoneCall *call, OrtpEvent *ev){
2153 OrtpEventType evt=ortp_event_get_type(ev);
2154 OrtpEventData *evd=ortp_event_get_data(ev);
2157 if (evt == ORTP_EVENT_ICE_SESSION_PROCESSING_FINISHED) {
2158 switch (ice_session_state(call->ice_session)) {
2160 ice_session_select_candidates(call->ice_session);
2161 if (ice_session_role(call->ice_session) == IR_Controlling) {
2162 linphone_core_update_call(call->core, call, &call->current_params);
2166 if (ice_session_has_completed_check_list(call->ice_session) == TRUE) {
2167 ice_session_select_candidates(call->ice_session);
2168 if (ice_session_role(call->ice_session) == IR_Controlling) {
2169 /* At least one ICE session has succeeded, so perform a call update. */
2170 linphone_core_update_call(call->core, call, &call->current_params);
2177 linphone_core_update_ice_state_in_call_stats(call);
2178 } else if (evt == ORTP_EVENT_ICE_GATHERING_FINISHED) {
2180 if (evd->info.ice_processing_successful==TRUE) {
2181 ice_session_compute_candidates_foundations(call->ice_session);
2182 ice_session_eliminate_redundant_candidates(call->ice_session);
2183 ice_session_choose_default_candidates(call->ice_session);
2184 ping_time = ice_session_average_gathering_round_trip_time(call->ice_session);
2185 if (ping_time >=0) {
2186 call->ping_time=ping_time;
2189 ms_warning("No STUN answer from [%s], disabling ICE",linphone_core_get_stun_server(call->core));
2190 linphone_call_delete_ice_session(call);
2192 switch (call->state) {
2193 case LinphoneCallUpdating:
2194 linphone_core_start_update_call(call->core, call);
2196 case LinphoneCallUpdatedByRemote:
2197 linphone_core_start_accept_call_update(call->core, call);
2199 case LinphoneCallOutgoingInit:
2200 linphone_call_stop_media_streams_for_ice_gathering(call);
2201 linphone_core_proceed_with_invite_if_ready(call->core, call, NULL);
2203 case LinphoneCallIdle:
2204 linphone_call_stop_media_streams_for_ice_gathering(call);
2205 linphone_core_notify_incoming_call(call->core, call);
2210 } else if (evt == ORTP_EVENT_ICE_LOSING_PAIRS_COMPLETED) {
2211 linphone_core_start_accept_call_update(call->core, call);
2212 linphone_core_update_ice_state_in_call_stats(call);
2213 } else if (evt == ORTP_EVENT_ICE_RESTART_NEEDED) {
2214 ice_session_restart(call->ice_session);
2215 ice_session_set_role(call->ice_session, IR_Controlling);
2216 linphone_core_update_call(call->core, call, &call->current_params);
2220 void linphone_call_background_tasks(LinphoneCall *call, bool_t one_second_elapsed){
2221 LinphoneCore* lc = call->core;
2222 int disconnect_timeout = linphone_core_get_nortp_timeout(call->core);
2223 bool_t disconnected=FALSE;
2225 if (call->state==LinphoneCallStreamsRunning && one_second_elapsed){
2226 RtpSession *as=NULL,*vs=NULL;
2227 float audio_load=0, video_load=0;
2228 if (call->audiostream!=NULL){
2229 as=call->audiostream->ms.session;
2230 if (call->audiostream->ms.ticker)
2231 audio_load=ms_ticker_get_average_load(call->audiostream->ms.ticker);
2233 if (call->videostream!=NULL){
2234 if (call->videostream->ms.ticker)
2235 video_load=ms_ticker_get_average_load(call->videostream->ms.ticker);
2236 vs=call->videostream->ms.session;
2238 report_bandwidth(call,as,vs);
2239 ms_message("Thread processing load: audio=%f\tvideo=%f",audio_load,video_load);
2243 linphone_upnp_call_process(call);
2246 #ifdef VIDEO_ENABLED
2247 if (call->videostream!=NULL) {
2250 /* Ensure there is no dangling ICE check list. */
2251 if (call->ice_session == NULL) call->videostream->ms.ice_check_list = NULL;
2253 // Beware that the application queue should not depend on treatments fron the
2254 // mediastreamer queue.
2255 video_stream_iterate(call->videostream);
2257 while (call->videostream_app_evq && (NULL != (ev=ortp_ev_queue_get(call->videostream_app_evq)))){
2258 OrtpEventType evt=ortp_event_get_type(ev);
2259 OrtpEventData *evd=ortp_event_get_data(ev);
2260 if (evt == ORTP_EVENT_ZRTP_ENCRYPTION_CHANGED){
2261 linphone_call_videostream_encryption_changed(call, evd->info.zrtp_stream_encrypted);
2262 } else if (evt == ORTP_EVENT_RTCP_PACKET_RECEIVED) {
2263 call->stats[LINPHONE_CALL_STATS_VIDEO].round_trip_delay = rtp_session_get_round_trip_propagation(call->videostream->ms.session);
2264 if(call->stats[LINPHONE_CALL_STATS_VIDEO].received_rtcp != NULL)
2265 freemsg(call->stats[LINPHONE_CALL_STATS_VIDEO].received_rtcp);
2266 call->stats[LINPHONE_CALL_STATS_VIDEO].received_rtcp = evd->packet;
2268 if (lc->vtable.call_stats_updated)
2269 lc->vtable.call_stats_updated(lc, call, &call->stats[LINPHONE_CALL_STATS_VIDEO]);
2270 } else if (evt == ORTP_EVENT_RTCP_PACKET_EMITTED) {
2271 memcpy(&call->stats[LINPHONE_CALL_STATS_VIDEO].jitter_stats, rtp_session_get_jitter_stats(call->videostream->ms.session), sizeof(jitter_stats_t));
2272 if(call->stats[LINPHONE_CALL_STATS_VIDEO].sent_rtcp != NULL)
2273 freemsg(call->stats[LINPHONE_CALL_STATS_VIDEO].sent_rtcp);
2274 call->stats[LINPHONE_CALL_STATS_VIDEO].sent_rtcp = evd->packet;
2276 if (lc->vtable.call_stats_updated)
2277 lc->vtable.call_stats_updated(lc, call, &call->stats[LINPHONE_CALL_STATS_VIDEO]);
2278 } else if ((evt == ORTP_EVENT_ICE_SESSION_PROCESSING_FINISHED) || (evt == ORTP_EVENT_ICE_GATHERING_FINISHED)
2279 || (evt == ORTP_EVENT_ICE_LOSING_PAIRS_COMPLETED) || (evt == ORTP_EVENT_ICE_RESTART_NEEDED)) {
2280 handle_ice_events(call, ev);
2282 ortp_event_destroy(ev);
2286 if (call->audiostream!=NULL) {
2289 /* Ensure there is no dangling ICE check list. */
2290 if (call->ice_session == NULL) call->audiostream->ms.ice_check_list = NULL;
2292 // Beware that the application queue should not depend on treatments fron the
2293 // mediastreamer queue.
2294 audio_stream_iterate(call->audiostream);
2296 while (call->audiostream_app_evq && (NULL != (ev=ortp_ev_queue_get(call->audiostream_app_evq)))){
2297 OrtpEventType evt=ortp_event_get_type(ev);
2298 OrtpEventData *evd=ortp_event_get_data(ev);
2299 if (evt == ORTP_EVENT_ZRTP_ENCRYPTION_CHANGED){
2300 linphone_call_audiostream_encryption_changed(call, evd->info.zrtp_stream_encrypted);
2301 } else if (evt == ORTP_EVENT_ZRTP_SAS_READY) {
2302 linphone_call_audiostream_auth_token_ready(call, evd->info.zrtp_sas.sas, evd->info.zrtp_sas.verified);
2303 } else if (evt == ORTP_EVENT_RTCP_PACKET_RECEIVED) {
2304 call->stats[LINPHONE_CALL_STATS_AUDIO].round_trip_delay = rtp_session_get_round_trip_propagation(call->audiostream->ms.session);
2305 if(call->stats[LINPHONE_CALL_STATS_AUDIO].received_rtcp != NULL)
2306 freemsg(call->stats[LINPHONE_CALL_STATS_AUDIO].received_rtcp);
2307 call->stats[LINPHONE_CALL_STATS_AUDIO].received_rtcp = evd->packet;
2309 if (lc->vtable.call_stats_updated)
2310 lc->vtable.call_stats_updated(lc, call, &call->stats[LINPHONE_CALL_STATS_AUDIO]);
2311 } else if (evt == ORTP_EVENT_RTCP_PACKET_EMITTED) {
2312 memcpy(&call->stats[LINPHONE_CALL_STATS_AUDIO].jitter_stats, rtp_session_get_jitter_stats(call->audiostream->ms.session), sizeof(jitter_stats_t));
2313 if(call->stats[LINPHONE_CALL_STATS_AUDIO].sent_rtcp != NULL)
2314 freemsg(call->stats[LINPHONE_CALL_STATS_AUDIO].sent_rtcp);
2315 call->stats[LINPHONE_CALL_STATS_AUDIO].sent_rtcp = evd->packet;
2317 if (lc->vtable.call_stats_updated)
2318 lc->vtable.call_stats_updated(lc, call, &call->stats[LINPHONE_CALL_STATS_AUDIO]);
2319 } else if ((evt == ORTP_EVENT_ICE_SESSION_PROCESSING_FINISHED) || (evt == ORTP_EVENT_ICE_GATHERING_FINISHED)
2320 || (evt == ORTP_EVENT_ICE_LOSING_PAIRS_COMPLETED) || (evt == ORTP_EVENT_ICE_RESTART_NEEDED)) {
2321 handle_ice_events(call, ev);
2322 } else if (evt==ORTP_EVENT_TELEPHONE_EVENT){
2323 linphone_core_dtmf_received(lc,evd->info.telephone_event);
2325 ortp_event_destroy(ev);
2328 if (call->state==LinphoneCallStreamsRunning && one_second_elapsed && call->audiostream!=NULL && disconnect_timeout>0 )
2329 disconnected=!audio_stream_alive(call->audiostream,disconnect_timeout);
2331 linphone_core_disconnected(call->core,call);
2334 void linphone_call_log_completed(LinphoneCall *call){
2335 LinphoneCore *lc=call->core;
2337 call->log->duration=time(NULL)-call->start_time;
2339 if (call->log->status==LinphoneCallMissed){
2342 info=ortp_strdup_printf(ngettext("You have missed %i call.",
2343 "You have missed %i calls.", lc->missed_calls),
2345 if (lc->vtable.display_status!=NULL)
2346 lc->vtable.display_status(lc,info);
2349 lc->call_logs=ms_list_prepend(lc->call_logs,(void *)call->log);
2350 if (ms_list_size(lc->call_logs)>lc->max_call_logs){
2351 MSList *elem,*prevelem=NULL;
2352 /*find the last element*/
2353 for(elem=lc->call_logs;elem!=NULL;elem=elem->next){
2357 linphone_call_log_destroy((LinphoneCallLog*)elem->data);
2358 lc->call_logs=ms_list_remove_link(lc->call_logs,elem);
2360 if (lc->vtable.call_log_updated!=NULL){
2361 lc->vtable.call_log_updated(lc,call->log);
2363 call_logs_write_to_config_file(lc);
2366 LinphoneCallState linphone_call_get_transfer_state(LinphoneCall *call) {
2367 return call->transfer_state;
2370 void linphone_call_set_transfer_state(LinphoneCall* call, LinphoneCallState state) {
2371 if (state != call->transfer_state) {
2372 LinphoneCore* lc = call->core;
2373 call->transfer_state = state;
2374 if (lc->vtable.transfer_state_changed)
2375 lc->vtable.transfer_state_changed(lc, call, state);
2380 * Returns true if the call is part of the conference.
2381 * @ingroup conferencing
2383 bool_t linphone_call_is_in_conference(const LinphoneCall *call) {
2384 return call->params.in_conference;
2389 * Perform a zoom of the video displayed during a call.
2390 * @param call the call.
2391 * @param zoom_factor a floating point number describing the zoom factor. A value 1.0 corresponds to no zoom applied.
2392 * @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.
2393 * @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.
2395 * 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.
2397 void linphone_call_zoom_video(LinphoneCall* call, float zoom_factor, float* cx, float* cy) {
2398 VideoStream* vstream = call->videostream;
2399 if (vstream && vstream->output) {
2402 if (zoom_factor < 1)
2404 float halfsize = 0.5 * 1.0 / zoom_factor;
2406 if ((*cx - halfsize) < 0)
2408 if ((*cx + halfsize) > 1)
2410 if ((*cy - halfsize) < 0)
2412 if ((*cy + halfsize) > 1)
2415 zoom[0] = zoom_factor;
2418 ms_filter_call_method(vstream->output, MS_VIDEO_DISPLAY_ZOOM, &zoom);
2419 }else ms_warning("Could not apply zoom: video output wasn't activated.");