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);
477 if (linphone_core_get_firewall_policy(call->core) == LinphonePolicyUseIce) {
478 call->ice_session = ice_session_new();
479 ice_session_set_role(call->ice_session, IR_Controlling);
481 if (linphone_core_get_firewall_policy(call->core) == LinphonePolicyUseStun) {
482 call->ping_time=linphone_core_run_stun_tests(call->core,call);
485 if (linphone_core_get_firewall_policy(call->core) == LinphonePolicyUseUpnp) {
486 call->upnp_session = linphone_upnp_session_new(call);
489 call->camera_active=params->has_video;
491 discover_mtu(lc,linphone_address_get_domain (to));
492 if (params->referer){
493 sal_call_set_referer(call->op,params->referer->op);
494 call->referer=linphone_call_ref(params->referer);
499 LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *from, LinphoneAddress *to, SalOp *op){
500 LinphoneCall *call=ms_new0(LinphoneCall,1);
502 const SalMediaDescription *md;
504 call->dir=LinphoneCallIncoming;
505 sal_op_set_user_pointer(op,call);
509 if (lc->sip_conf.ping_with_options){
510 /*the following sends an option request back to the caller so that
511 we get a chance to discover our nat'd address before answering.*/
512 call->ping_op=sal_op_new(lc->sal);
513 from_str=linphone_address_as_string_uri_only(from);
514 sal_op_set_route(call->ping_op,sal_op_get_network_origin(op));
515 sal_op_set_user_pointer(call->ping_op,call);
516 sal_ping(call->ping_op,linphone_core_find_best_identity(lc,from,NULL),from_str);
520 linphone_address_clean(from);
521 linphone_core_get_local_ip(lc,linphone_address_get_domain(from),call->localip);
522 linphone_call_init_common(call, from, to);
523 call->log->call_id=ms_strdup(sal_op_get_call_id(op)); /*must be known at that time*/
524 linphone_core_init_default_params(lc, &call->params);
525 md=sal_call_get_remote_media_description(op);
526 call->params.has_video &= !!lc->video_policy.automatically_accept;
528 // It is licit to receive an INVITE without SDP
529 // In this case WE chose the media parameters according to policy.
530 call->params.has_video &= linphone_core_media_description_contains_video_stream(md);
532 switch (linphone_core_get_firewall_policy(call->core)) {
533 case LinphonePolicyUseIce:
534 call->ice_session = ice_session_new();
535 ice_session_set_role(call->ice_session, IR_Controlled);
536 linphone_core_update_ice_from_remote_media_description(call, sal_call_get_remote_media_description(op));
537 if (call->ice_session != NULL) {
538 linphone_call_init_media_streams(call);
539 linphone_call_start_media_streams_for_ice_gathering(call);
540 if (linphone_core_gather_ice_candidates(call->core,call)<0) {
541 /* Ice candidates gathering failed, proceed with the call anyway. */
542 linphone_call_delete_ice_session(call);
543 linphone_call_stop_media_streams_for_ice_gathering(call);
547 case LinphonePolicyUseStun:
548 call->ping_time=linphone_core_run_stun_tests(call->core,call);
549 /* No break to also destroy ice session in this case. */
551 case LinphonePolicyUseUpnp:
553 call->upnp_session = linphone_upnp_session_new(call);
554 if (call->upnp_session != NULL) {
555 linphone_call_init_media_streams(call);
556 if (linphone_core_update_upnp_from_remote_media_description(call, sal_call_get_remote_media_description(op))<0) {
557 /* uPnP port mappings failed, proceed with the call anyway. */
558 linphone_call_delete_upnp_session(call);
566 call->camera_active=call->params.has_video;
568 discover_mtu(lc,linphone_address_get_domain(from));
572 /* this function is called internally to get rid of a call.
573 It performs the following tasks:
574 - remove the call from the internal list of calls
575 - update the call logs accordingly
578 static void linphone_call_set_terminated(LinphoneCall *call){
579 LinphoneCore *lc=call->core;
581 linphone_core_update_allocated_audio_bandwidth(lc);
583 call->owns_call_log=FALSE;
584 linphone_call_log_completed(call);
587 if (call == lc->current_call){
588 ms_message("Resetting the current call");
589 lc->current_call=NULL;
592 if (linphone_core_del_call(lc,call) != 0){
593 ms_error("Could not remove the call from the list !!!");
596 if (ms_list_size(lc->calls)==0)
597 linphone_core_notify_all_friends(lc,lc->presence_mode);
599 linphone_core_conference_check_uninit(lc);
600 if (call->ringing_beep){
601 linphone_core_stop_dtmf(lc);
602 call->ringing_beep=FALSE;
605 linphone_call_unref(call->referer);
610 void linphone_call_fix_call_parameters(LinphoneCall *call){
611 call->params.has_video=call->current_params.has_video;
612 call->params.media_encryption=call->current_params.media_encryption;
615 const char *linphone_call_state_to_string(LinphoneCallState cs){
617 case LinphoneCallIdle:
618 return "LinphoneCallIdle";
619 case LinphoneCallIncomingReceived:
620 return "LinphoneCallIncomingReceived";
621 case LinphoneCallOutgoingInit:
622 return "LinphoneCallOutgoingInit";
623 case LinphoneCallOutgoingProgress:
624 return "LinphoneCallOutgoingProgress";
625 case LinphoneCallOutgoingRinging:
626 return "LinphoneCallOutgoingRinging";
627 case LinphoneCallOutgoingEarlyMedia:
628 return "LinphoneCallOutgoingEarlyMedia";
629 case LinphoneCallConnected:
630 return "LinphoneCallConnected";
631 case LinphoneCallStreamsRunning:
632 return "LinphoneCallStreamsRunning";
633 case LinphoneCallPausing:
634 return "LinphoneCallPausing";
635 case LinphoneCallPaused:
636 return "LinphoneCallPaused";
637 case LinphoneCallResuming:
638 return "LinphoneCallResuming";
639 case LinphoneCallRefered:
640 return "LinphoneCallRefered";
641 case LinphoneCallError:
642 return "LinphoneCallError";
643 case LinphoneCallEnd:
644 return "LinphoneCallEnd";
645 case LinphoneCallPausedByRemote:
646 return "LinphoneCallPausedByRemote";
647 case LinphoneCallUpdatedByRemote:
648 return "LinphoneCallUpdatedByRemote";
649 case LinphoneCallIncomingEarlyMedia:
650 return "LinphoneCallIncomingEarlyMedia";
651 case LinphoneCallUpdating:
652 return "LinphoneCallUpdating";
653 case LinphoneCallReleased:
654 return "LinphoneCallReleased";
656 return "undefined state";
659 void linphone_call_set_state(LinphoneCall *call, LinphoneCallState cstate, const char *message){
660 LinphoneCore *lc=call->core;
662 if (call->state!=cstate){
663 if (call->state==LinphoneCallEnd || call->state==LinphoneCallError){
664 if (cstate!=LinphoneCallReleased){
665 ms_warning("Spurious call state change from %s to %s, ignored.",linphone_call_state_to_string(call->state),
666 linphone_call_state_to_string(cstate));
670 ms_message("Call %p: moving from state %s to %s",call,linphone_call_state_to_string(call->state),
671 linphone_call_state_to_string(cstate));
672 if (cstate!=LinphoneCallRefered){
673 /*LinphoneCallRefered is rather an event, not a state.
674 Indeed it does not change the state of the call (still paused or running)*/
677 if (cstate==LinphoneCallEnd || cstate==LinphoneCallError){
678 switch(call->reason){
679 case LinphoneReasonDeclined:
680 call->log->status=LinphoneCallDeclined;
682 case LinphoneReasonNotAnswered:
683 call->log->status=LinphoneCallMissed;
688 linphone_call_set_terminated (call);
690 if (cstate == LinphoneCallConnected) {
691 call->log->status=LinphoneCallSuccess;
692 call->media_start_time=time(NULL);
695 if (lc->vtable.call_state_changed)
696 lc->vtable.call_state_changed(lc,call,cstate,message);
697 if (cstate==LinphoneCallReleased){
698 if (call->op!=NULL) {
699 /* so that we cannot have anymore upcalls for SAL
700 concerning this call*/
701 sal_op_release(call->op);
704 linphone_call_unref(call);
709 static void linphone_call_destroy(LinphoneCall *obj)
712 linphone_call_delete_upnp_session(obj);
714 linphone_call_delete_ice_session(obj);
716 sal_op_release(obj->op);
719 if (obj->resultdesc!=NULL) {
720 sal_media_description_unref(obj->resultdesc);
721 obj->resultdesc=NULL;
723 if (obj->localdesc!=NULL) {
724 sal_media_description_unref(obj->localdesc);
728 sal_op_release(obj->ping_op);
731 ms_free(obj->refer_to);
733 if (obj->owns_call_log)
734 linphone_call_log_destroy(obj->log);
735 if (obj->auth_token) {
736 ms_free(obj->auth_token);
738 linphone_call_params_uninit(&obj->params);
743 * @addtogroup call_control
748 * Increments the call 's reference count.
749 * An application that wishes to retain a pointer to call object
750 * must use this function to unsure the pointer remains
751 * valid. Once the application no more needs this pointer,
752 * it must call linphone_call_unref().
754 LinphoneCall * linphone_call_ref(LinphoneCall *obj){
760 * Decrements the call object reference count.
761 * See linphone_call_ref().
763 void linphone_call_unref(LinphoneCall *obj){
766 linphone_call_destroy(obj);
771 * Returns current parameters associated to the call.
773 const LinphoneCallParams * linphone_call_get_current_params(LinphoneCall *call){
774 if (call->params.record_file)
775 call->current_params.record_file=call->params.record_file;
776 return &call->current_params;
779 static bool_t is_video_active(const SalStreamDescription *sd){
780 return sd->rtp_port!=0 && sd->dir!=SalStreamInactive;
784 * Returns call parameters proposed by remote.
786 * This is useful when receiving an incoming call, to know whether the remote party
787 * supports video, encryption or whatever.
789 const LinphoneCallParams * linphone_call_get_remote_params(LinphoneCall *call){
790 LinphoneCallParams *cp=&call->remote_params;
791 memset(cp,0,sizeof(*cp));
793 SalMediaDescription *md=sal_call_get_remote_media_description(call->op);
795 SalStreamDescription *asd,*vsd,*secure_asd,*secure_vsd;
797 asd=sal_media_description_find_stream(md,SalProtoRtpAvp,SalAudio);
798 vsd=sal_media_description_find_stream(md,SalProtoRtpAvp,SalVideo);
799 secure_asd=sal_media_description_find_stream(md,SalProtoRtpSavp,SalAudio);
800 secure_vsd=sal_media_description_find_stream(md,SalProtoRtpSavp,SalVideo);
802 cp->has_video=is_video_active(secure_vsd);
803 if (secure_asd || asd==NULL)
804 cp->media_encryption=LinphoneMediaEncryptionSRTP;
806 cp->has_video=is_video_active(vsd);
809 if (md->bandwidth>0 && md->bandwidth<=linphone_core_get_edge_bw(call->core)){
810 cp->low_bandwidth=TRUE;
813 cp->custom_headers=(SalCustomHeader*)sal_op_get_custom_header(call->op);
821 * Returns the remote address associated to this call
824 const LinphoneAddress * linphone_call_get_remote_address(const LinphoneCall *call){
825 return call->dir==LinphoneCallIncoming ? call->log->from : call->log->to;
829 * Returns the remote address associated to this call as a string.
831 * The result string must be freed by user using ms_free().
833 char *linphone_call_get_remote_address_as_string(const LinphoneCall *call){
834 return linphone_address_as_string(linphone_call_get_remote_address(call));
838 * Retrieves the call's current state.
840 LinphoneCallState linphone_call_get_state(const LinphoneCall *call){
845 * Returns the reason for a call termination (either error or normal termination)
847 LinphoneReason linphone_call_get_reason(const LinphoneCall *call){
852 * Get the user_pointer in the LinphoneCall
854 * @ingroup call_control
856 * return user_pointer an opaque user pointer that can be retrieved at any time
858 void *linphone_call_get_user_pointer(LinphoneCall *call)
860 return call->user_pointer;
864 * Set the user_pointer in the LinphoneCall
866 * @ingroup call_control
868 * the user_pointer is an opaque user pointer that can be retrieved at any time in the LinphoneCall
870 void linphone_call_set_user_pointer(LinphoneCall *call, void *user_pointer)
872 call->user_pointer = user_pointer;
876 * Returns the call log associated to this call.
878 LinphoneCallLog *linphone_call_get_call_log(const LinphoneCall *call){
883 * Returns the refer-to uri (if the call was transfered).
885 const char *linphone_call_get_refer_to(const LinphoneCall *call){
886 return call->refer_to;
890 * Returns direction of the call (incoming or outgoing).
892 LinphoneCallDir linphone_call_get_dir(const LinphoneCall *call){
893 return call->log->dir;
897 * Returns the far end's user agent description string, if available.
899 const char *linphone_call_get_remote_user_agent(LinphoneCall *call){
901 return sal_op_get_remote_ua (call->op);
907 * Returns the far end's sip contact as a string, if available.
909 const char *linphone_call_get_remote_contact(LinphoneCall *call){
911 return sal_op_get_remote_contact(call->op);
917 * Returns true if this calls has received a transfer that has not been
919 * Pending transfers are executed when this call is being paused or closed,
920 * locally or by remote endpoint.
921 * If the call is already paused while receiving the transfer request, the
922 * transfer immediately occurs.
924 bool_t linphone_call_has_transfer_pending(const LinphoneCall *call){
925 return call->refer_pending;
929 * Returns call's duration in seconds.
931 int linphone_call_get_duration(const LinphoneCall *call){
932 if (call->media_start_time==0) return 0;
933 return time(NULL)-call->media_start_time;
937 * Returns the call object this call is replacing, if any.
938 * Call replacement can occur during call transfers.
939 * By default, the core automatically terminates the replaced call and accept the new one.
940 * This function allows the application to know whether a new incoming call is a one that replaces another one.
942 LinphoneCall *linphone_call_get_replaced_call(LinphoneCall *call){
943 SalOp *op=sal_call_get_replaces(call->op);
945 return (LinphoneCall*)sal_op_get_user_pointer(op);
951 * Indicate whether camera input should be sent to remote end.
953 void linphone_call_enable_camera (LinphoneCall *call, bool_t enable){
955 if (call->videostream!=NULL && call->videostream->ms.ticker!=NULL){
956 LinphoneCore *lc=call->core;
957 MSWebCam *nowebcam=get_nowebcam_device();
958 if (call->camera_active!=enable && lc->video_conf.device!=nowebcam){
959 video_stream_change_camera(call->videostream,
960 enable ? lc->video_conf.device : nowebcam);
963 call->camera_active=enable;
969 * Request remote side to send us a Video Fast Update.
971 void linphone_call_send_vfu_request(LinphoneCall *call)
973 if (LinphoneCallStreamsRunning == linphone_call_get_state(call))
974 sal_call_send_vfu_request(call->op);
980 * Take a photo of currently received video and write it into a jpeg file.
982 int linphone_call_take_video_snapshot(LinphoneCall *call, const char *file){
984 if (call->videostream!=NULL && call->videostream->jpegwriter!=NULL){
985 return ms_filter_call_method(call->videostream->jpegwriter,MS_JPEG_WRITER_TAKE_SNAPSHOT,(void*)file);
987 ms_warning("Cannot take snapshot: no currently running video stream on this call.");
994 * Returns TRUE if camera pictures are sent to the remote party.
996 bool_t linphone_call_camera_enabled (const LinphoneCall *call){
997 return call->camera_active;
1001 * Enable video stream.
1003 void linphone_call_params_enable_video(LinphoneCallParams *cp, bool_t enabled){
1004 cp->has_video=enabled;
1008 * Returns the audio codec used in the call, described as a PayloadType structure.
1010 const PayloadType* linphone_call_params_get_used_audio_codec(const LinphoneCallParams *cp) {
1011 return cp->audio_codec;
1016 * Returns the video codec used in the call, described as a PayloadType structure.
1018 const PayloadType* linphone_call_params_get_used_video_codec(const LinphoneCallParams *cp) {
1019 return cp->video_codec;
1023 * @ingroup call_control
1024 * Use to know if this call has been configured in low bandwidth mode.
1025 * This mode can be automatically discovered thanks to a stun server when activate_edge_workarounds=1 in section [net] of configuration file.
1026 * An application that would have reliable way to know network capacity may not use activate_edge_workarounds=1 but instead manually configure
1027 * low bandwidth mode with linphone_call_params_enable_low_bandwidth().
1028 * <br> When enabled, this param may transform a call request with video in audio only mode.
1029 * @return TRUE if low bandwidth has been configured/detected
1031 bool_t linphone_call_params_low_bandwidth_enabled(const LinphoneCallParams *cp) {
1032 return cp->low_bandwidth;
1036 * @ingroup call_control
1037 * Indicate low bandwith mode.
1038 * 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
1039 * 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
1040 * that it is achievable by the codec selected after SDP handshake. Video is automatically disabled.
1043 void linphone_call_params_enable_low_bandwidth(LinphoneCallParams *cp, bool_t enabled){
1044 cp->low_bandwidth=enabled;
1048 * Returns whether video is enabled.
1050 bool_t linphone_call_params_video_enabled(const LinphoneCallParams *cp){
1051 return cp->has_video;
1055 * Returns kind of media encryption selected for the call.
1057 enum LinphoneMediaEncryption linphone_call_params_get_media_encryption(const LinphoneCallParams *cp) {
1058 return cp->media_encryption;
1062 * Set requested media encryption for a call.
1064 void linphone_call_params_set_media_encryption(LinphoneCallParams *cp, enum LinphoneMediaEncryption e) {
1065 cp->media_encryption = e;
1070 * Enable sending of real early media (during outgoing calls).
1072 void linphone_call_params_enable_early_media_sending(LinphoneCallParams *cp, bool_t enabled){
1073 cp->real_early_media=enabled;
1077 * Indicates whether sending of early media was enabled.
1079 bool_t linphone_call_params_early_media_sending_enabled(const LinphoneCallParams *cp){
1080 return cp->real_early_media;
1084 * Returns true if the call is part of the locally managed conference.
1086 bool_t linphone_call_params_local_conference_mode(const LinphoneCallParams *cp){
1087 return cp->in_conference;
1091 * Refine bandwidth settings for this call by setting a bandwidth limit for audio streams.
1092 * As a consequence, codecs whose bitrates are not compatible with this limit won't be used.
1094 void linphone_call_params_set_audio_bandwidth_limit(LinphoneCallParams *cp, int bandwidth){
1095 cp->audio_bw=bandwidth;
1098 void linphone_call_params_add_custom_header(LinphoneCallParams *params, const char *header_name, const char *header_value){
1099 params->custom_headers=sal_custom_header_append(params->custom_headers,header_name,header_value);
1102 const char *linphone_call_params_get_custom_header(LinphoneCallParams *params, const char *header_name){
1103 return sal_custom_header_find(params->custom_headers,header_name);
1106 void _linphone_call_params_copy(LinphoneCallParams *ncp, const LinphoneCallParams *cp){
1107 memcpy(ncp,cp,sizeof(LinphoneCallParams));
1108 if (cp->record_file) ncp->record_file=ms_strdup(cp->record_file);
1110 * The management of the custom headers is not optimal. We copy everything while ref counting would be more efficient.
1112 if (cp->custom_headers) ncp->custom_headers=sal_custom_header_clone(cp->custom_headers);
1116 * Copy existing LinphoneCallParams to a new LinphoneCallParams object.
1118 LinphoneCallParams * linphone_call_params_copy(const LinphoneCallParams *cp){
1119 LinphoneCallParams *ncp=ms_new0(LinphoneCallParams,1);
1120 _linphone_call_params_copy(ncp,cp);
1124 void linphone_call_params_uninit(LinphoneCallParams *p){
1125 if (p->record_file) ms_free(p->record_file);
1126 if (p->custom_headers) sal_custom_header_free(p->custom_headers);
1130 * Destroy LinphoneCallParams.
1132 void linphone_call_params_destroy(LinphoneCallParams *p){
1133 linphone_call_params_uninit(p);
1143 #ifdef TEST_EXT_RENDERER
1144 static void rendercb(void *data, const MSPicture *local, const MSPicture *remote){
1145 ms_message("rendercb, local buffer=%p, remote buffer=%p",
1146 local ? local->planes[0] : NULL, remote? remote->planes[0] : NULL);
1150 #ifdef VIDEO_ENABLED
1151 static void video_stream_event_cb(void *user_pointer, const MSFilter *f, const unsigned int event_id, const void *args){
1152 LinphoneCall* call = (LinphoneCall*) user_pointer;
1153 ms_warning("In linphonecall.c: video_stream_event_cb");
1155 case MS_VIDEO_DECODER_DECODING_ERRORS:
1156 ms_warning("Case is MS_VIDEO_DECODER_DECODING_ERRORS");
1157 linphone_call_send_vfu_request(call);
1159 case MS_VIDEO_DECODER_FIRST_IMAGE_DECODED:
1160 ms_message("First video frame decoded successfully");
1161 if (call->nextVideoFrameDecoded._func != NULL)
1162 call->nextVideoFrameDecoded._func(call, call->nextVideoFrameDecoded._user_data);
1165 ms_warning("Unhandled event %i", event_id);
1171 void linphone_call_set_next_video_frame_decoded_callback(LinphoneCall *call, LinphoneCallCbFunc cb, void* user_data) {
1172 call->nextVideoFrameDecoded._func = cb;
1173 call->nextVideoFrameDecoded._user_data = user_data;
1174 #ifdef VIDEO_ENABLED
1175 ms_filter_call_method_noarg(call->videostream->ms.decoder, MS_VIDEO_DECODER_RESET_FIRST_IMAGE_NOTIFICATION);
1179 void linphone_call_init_audio_stream(LinphoneCall *call){
1180 LinphoneCore *lc=call->core;
1181 AudioStream *audiostream;
1184 if (call->audiostream != NULL) return;
1185 call->audiostream=audiostream=audio_stream_new(call->audio_port,call->audio_port+1,linphone_core_ipv6_enabled(lc));
1186 dscp=linphone_core_get_audio_dscp(lc);
1188 audio_stream_set_dscp(audiostream,dscp);
1189 if (linphone_core_echo_limiter_enabled(lc)){
1190 const char *type=lp_config_get_string(lc->config,"sound","el_type","mic");
1191 if (strcasecmp(type,"mic")==0)
1192 audio_stream_enable_echo_limiter(audiostream,ELControlMic);
1193 else if (strcasecmp(type,"full")==0)
1194 audio_stream_enable_echo_limiter(audiostream,ELControlFull);
1196 audio_stream_enable_gain_control(audiostream,TRUE);
1197 if (linphone_core_echo_cancellation_enabled(lc)){
1198 int len,delay,framesize;
1199 const char *statestr=lp_config_get_string(lc->config,"sound","ec_state",NULL);
1200 len=lp_config_get_int(lc->config,"sound","ec_tail_len",0);
1201 delay=lp_config_get_int(lc->config,"sound","ec_delay",0);
1202 framesize=lp_config_get_int(lc->config,"sound","ec_framesize",0);
1203 audio_stream_set_echo_canceller_params(audiostream,len,delay,framesize);
1204 if (statestr && audiostream->ec){
1205 ms_filter_call_method(audiostream->ec,MS_ECHO_CANCELLER_SET_STATE_STRING,(void*)statestr);
1208 audio_stream_enable_automatic_gain_control(audiostream,linphone_core_agc_enabled(lc));
1210 int enabled=lp_config_get_int(lc->config,"sound","noisegate",0);
1211 audio_stream_enable_noise_gate(audiostream,enabled);
1214 audio_stream_set_features(audiostream,linphone_core_get_audio_features(lc));
1217 RtpTransport *artp=lc->rtptf->audio_rtp_func(lc->rtptf->audio_rtp_func_data, call->audio_port);
1218 RtpTransport *artcp=lc->rtptf->audio_rtcp_func(lc->rtptf->audio_rtcp_func_data, call->audio_port+1);
1219 rtp_session_set_transports(audiostream->ms.session,artp,artcp);
1221 if ((linphone_core_get_firewall_policy(lc) == LinphonePolicyUseIce) && (call->ice_session != NULL)){
1222 rtp_session_set_pktinfo(audiostream->ms.session, TRUE);
1223 rtp_session_set_symmetric_rtp(audiostream->ms.session, FALSE);
1224 if (ice_session_check_list(call->ice_session, 0) == NULL) {
1225 ice_session_add_check_list(call->ice_session, ice_check_list_new());
1227 audiostream->ms.ice_check_list = ice_session_check_list(call->ice_session, 0);
1228 ice_check_list_set_rtp_session(audiostream->ms.ice_check_list, audiostream->ms.session);
1231 call->audiostream_app_evq = ortp_ev_queue_new();
1232 rtp_session_register_event_queue(audiostream->ms.session,call->audiostream_app_evq);
1235 void linphone_call_init_video_stream(LinphoneCall *call){
1236 #ifdef VIDEO_ENABLED
1237 LinphoneCore *lc=call->core;
1239 if (!call->params.has_video) {
1240 linphone_call_stop_video_stream(call);
1243 if (call->videostream != NULL) return;
1244 if ((lc->video_conf.display || lc->video_conf.capture) && call->params.has_video){
1245 int video_recv_buf_size=lp_config_get_int(lc->config,"video","recv_buf_size",0);
1246 int dscp=linphone_core_get_video_dscp(lc);
1248 call->videostream=video_stream_new(call->video_port,call->video_port+1,linphone_core_ipv6_enabled(lc));
1250 video_stream_set_dscp(call->videostream,dscp);
1251 video_stream_enable_display_filter_auto_rotate(call->videostream, lp_config_get_int(lc->config,"video","display_filter_auto_rotate",0));
1252 if (video_recv_buf_size>0) rtp_session_set_recv_buf_size(call->videostream->ms.session,video_recv_buf_size);
1254 if( lc->video_conf.displaytype != NULL)
1255 video_stream_set_display_filter_name(call->videostream,lc->video_conf.displaytype);
1256 video_stream_set_event_callback(call->videostream,video_stream_event_cb, call);
1258 RtpTransport *vrtp=lc->rtptf->video_rtp_func(lc->rtptf->video_rtp_func_data, call->video_port);
1259 RtpTransport *vrtcp=lc->rtptf->video_rtcp_func(lc->rtptf->video_rtcp_func_data, call->video_port+1);
1260 rtp_session_set_transports(call->videostream->ms.session,vrtp,vrtcp);
1262 if ((linphone_core_get_firewall_policy(lc) == LinphonePolicyUseIce) && (call->ice_session != NULL)){
1263 rtp_session_set_pktinfo(call->videostream->ms.session, TRUE);
1264 rtp_session_set_symmetric_rtp(call->videostream->ms.session, FALSE);
1265 if (ice_session_check_list(call->ice_session, 1) == NULL) {
1266 ice_session_add_check_list(call->ice_session, ice_check_list_new());
1268 call->videostream->ms.ice_check_list = ice_session_check_list(call->ice_session, 1);
1269 ice_check_list_set_rtp_session(call->videostream->ms.ice_check_list, call->videostream->ms.session);
1271 call->videostream_app_evq = ortp_ev_queue_new();
1272 rtp_session_register_event_queue(call->videostream->ms.session,call->videostream_app_evq);
1273 #ifdef TEST_EXT_RENDERER
1274 video_stream_set_render_callback(call->videostream,rendercb,NULL);
1278 call->videostream=NULL;
1282 void linphone_call_init_media_streams(LinphoneCall *call){
1283 linphone_call_init_audio_stream(call);
1284 linphone_call_init_video_stream(call);
1288 static int dtmf_tab[16]={'0','1','2','3','4','5','6','7','8','9','*','#','A','B','C','D'};
1290 static void linphone_core_dtmf_received(LinphoneCore *lc, int dtmf){
1291 if (dtmf<0 || dtmf>15){
1292 ms_warning("Bad dtmf value %i",dtmf);
1295 if (lc->vtable.dtmf_received != NULL)
1296 lc->vtable.dtmf_received(lc, linphone_core_get_current_call(lc), dtmf_tab[dtmf]);
1299 static void parametrize_equalizer(LinphoneCore *lc, AudioStream *st){
1301 MSFilter *f=st->equalizer;
1302 int enabled=lp_config_get_int(lc->config,"sound","eq_active",0);
1303 const char *gains=lp_config_get_string(lc->config,"sound","eq_gains",NULL);
1304 ms_filter_call_method(f,MS_EQUALIZER_SET_ACTIVE,&enabled);
1310 if (sscanf(gains,"%f:%f:%f %n",&g.frequency,&g.gain,&g.width,&bytes)==3){
1311 ms_message("Read equalizer gains: %f(~%f) --> %f",g.frequency,g.width,g.gain);
1312 ms_filter_call_method(f,MS_EQUALIZER_SET_GAIN,&g);
1321 void _post_configure_audio_stream(AudioStream *st, LinphoneCore *lc, bool_t muted){
1322 float mic_gain=lc->sound_conf.soft_mic_lev;
1325 float ng_thres=lp_config_get_float(lc->config,"sound","ng_thres",0.05);
1326 float ng_floorgain=lp_config_get_float(lc->config,"sound","ng_floorgain",0);
1327 int dc_removal=lp_config_get_int(lc->config,"sound","dc_removal",0);
1330 linphone_core_set_mic_gain_db (lc, mic_gain);
1332 audio_stream_set_mic_gain(st,0);
1334 recv_gain = lc->sound_conf.soft_play_lev;
1335 if (recv_gain != 0) {
1336 linphone_core_set_playback_gain_db (lc,recv_gain);
1340 ms_filter_call_method(st->volsend,MS_VOLUME_REMOVE_DC,&dc_removal);
1341 float speed=lp_config_get_float(lc->config,"sound","el_speed",-1);
1342 thres=lp_config_get_float(lc->config,"sound","el_thres",-1);
1343 float force=lp_config_get_float(lc->config,"sound","el_force",-1);
1344 int sustain=lp_config_get_int(lc->config,"sound","el_sustain",-1);
1345 float transmit_thres=lp_config_get_float(lc->config,"sound","el_transmit_thres",-1);
1348 if (speed==-1) speed=0.03;
1349 if (force==-1) force=25;
1350 ms_filter_call_method(f,MS_VOLUME_SET_EA_SPEED,&speed);
1351 ms_filter_call_method(f,MS_VOLUME_SET_EA_FORCE,&force);
1353 ms_filter_call_method(f,MS_VOLUME_SET_EA_THRESHOLD,&thres);
1355 ms_filter_call_method(f,MS_VOLUME_SET_EA_SUSTAIN,&sustain);
1356 if (transmit_thres!=-1)
1357 ms_filter_call_method(f,MS_VOLUME_SET_EA_TRANSMIT_THRESHOLD,&transmit_thres);
1359 ms_filter_call_method(st->volsend,MS_VOLUME_SET_NOISE_GATE_THRESHOLD,&ng_thres);
1360 ms_filter_call_method(st->volsend,MS_VOLUME_SET_NOISE_GATE_FLOORGAIN,&ng_floorgain);
1363 /* parameters for a limited noise-gate effect, using echo limiter threshold */
1364 float floorgain = 1/pow(10,(mic_gain)/10);
1365 int spk_agc=lp_config_get_int(lc->config,"sound","speaker_agc_enabled",0);
1366 ms_filter_call_method(st->volrecv, MS_VOLUME_ENABLE_AGC, &spk_agc);
1367 ms_filter_call_method(st->volrecv,MS_VOLUME_SET_NOISE_GATE_THRESHOLD,&ng_thres);
1368 ms_filter_call_method(st->volrecv,MS_VOLUME_SET_NOISE_GATE_FLOORGAIN,&floorgain);
1370 parametrize_equalizer(lc,st);
1373 static void post_configure_audio_streams(LinphoneCall*call){
1374 AudioStream *st=call->audiostream;
1375 LinphoneCore *lc=call->core;
1376 _post_configure_audio_stream(st,lc,call->audio_muted);
1377 if (lc->vtable.dtmf_received!=NULL){
1378 audio_stream_play_received_dtmfs(call->audiostream,FALSE);
1380 if (call->record_active)
1381 linphone_call_start_recording(call);
1384 static RtpProfile *make_profile(LinphoneCall *call, const SalMediaDescription *md, const SalStreamDescription *desc, int *used_pt){
1387 RtpProfile *prof=rtp_profile_new("Call profile");
1390 LinphoneCore *lc=call->core;
1392 const LinphoneCallParams *params=&call->params;
1395 for(elem=desc->payloads;elem!=NULL;elem=elem->next){
1396 PayloadType *pt=(PayloadType*)elem->data;
1399 if ((pt->flags & PAYLOAD_TYPE_FLAG_CAN_SEND) && first) {
1400 if (desc->type==SalAudio){
1401 linphone_core_update_allocated_audio_bandwidth_in_call(call,pt);
1402 if (params->up_ptime)
1403 up_ptime=params->up_ptime;
1404 else up_ptime=linphone_core_get_upload_ptime(lc);
1406 *used_pt=payload_type_get_number(pt);
1409 if (desc->bandwidth>0) remote_bw=desc->bandwidth;
1410 else if (md->bandwidth>0) {
1411 /*case where b=AS is given globally, not per stream*/
1412 remote_bw=md->bandwidth;
1413 if (desc->type==SalVideo){
1414 remote_bw=get_video_bandwidth(remote_bw,call->audio_bw);
1418 if (desc->type==SalAudio){
1419 int audio_bw=call->audio_bw;
1421 if (params->up_bw< audio_bw)
1422 audio_bw=params->up_bw;
1424 bw=get_min_bandwidth(audio_bw,remote_bw);
1425 }else bw=get_min_bandwidth(get_video_bandwidth(linphone_core_get_upload_bandwidth (lc),call->audio_bw),remote_bw);
1426 if (bw>0) pt->normal_bitrate=bw*1000;
1427 else if (desc->type==SalAudio){
1428 pt->normal_bitrate=-1;
1431 up_ptime=desc->ptime;
1435 snprintf(tmp,sizeof(tmp),"ptime=%i",up_ptime);
1436 payload_type_append_send_fmtp(pt,tmp);
1438 number=payload_type_get_number(pt);
1439 if (rtp_profile_get_payload(prof,number)!=NULL){
1440 ms_warning("A payload type with number %i already exists in profile !",number);
1442 rtp_profile_set_payload(prof,number,pt);
1448 static void setup_ring_player(LinphoneCore *lc, LinphoneCall *call){
1449 int pause_time=3000;
1450 audio_stream_play(call->audiostream,lc->sound_conf.ringback_tone);
1451 ms_filter_call_method(call->audiostream->soundread,MS_FILE_PLAYER_LOOP,&pause_time);
1454 static bool_t linphone_call_sound_resources_available(LinphoneCall *call){
1455 LinphoneCore *lc=call->core;
1456 LinphoneCall *current=linphone_core_get_current_call(lc);
1457 return !linphone_core_is_in_conference(lc) &&
1458 (current==NULL || current==call);
1460 static int find_crypto_index_from_tag(const SalSrtpCryptoAlgo crypto[],unsigned char tag) {
1462 for(i=0; i<SAL_CRYPTO_ALGO_MAX; i++) {
1463 if (crypto[i].tag == tag) {
1469 static void linphone_call_start_audio_stream(LinphoneCall *call, const char *cname, bool_t muted, bool_t send_ringbacktone, bool_t use_arc){
1470 LinphoneCore *lc=call->core;
1472 char rtcp_tool[128]={0};
1473 snprintf(rtcp_tool,sizeof(rtcp_tool)-1,"%s-%s",linphone_core_get_user_agent_name(),linphone_core_get_user_agent_version());
1474 /* look for savp stream first */
1475 const SalStreamDescription *stream=sal_media_description_find_stream(call->resultdesc,
1476 SalProtoRtpSavp,SalAudio);
1477 /* no savp audio stream, use avp */
1479 stream=sal_media_description_find_stream(call->resultdesc,
1480 SalProtoRtpAvp,SalAudio);
1482 if (stream && stream->dir!=SalStreamInactive && stream->rtp_port!=0){
1483 MSSndCard *playcard=lc->sound_conf.lsd_card ?
1484 lc->sound_conf.lsd_card : lc->sound_conf.play_sndcard;
1485 MSSndCard *captcard=lc->sound_conf.capt_sndcard;
1486 const char *playfile=lc->play_file;
1487 const char *recfile=lc->rec_file;
1488 call->audio_profile=make_profile(call,call->resultdesc,stream,&used_pt);
1492 call->current_params.audio_codec = rtp_profile_get_payload(call->audio_profile, used_pt);
1493 if (playcard==NULL) {
1494 ms_warning("No card defined for playback !");
1496 if (captcard==NULL) {
1497 ms_warning("No card defined for capture !");
1499 /*Replace soundcard filters by inactive file players or recorders
1500 when placed in recvonly or sendonly mode*/
1501 if (stream->rtp_port==0 || stream->dir==SalStreamRecvOnly){
1504 }else if (stream->dir==SalStreamSendOnly){
1508 /*And we will eventually play "playfile" if set by the user*/
1511 if (send_ringbacktone){
1513 playfile=NULL;/* it is setup later*/
1515 /*if playfile are supplied don't use soundcards*/
1516 if (lc->use_files) {
1520 if (call->params.in_conference){
1521 /* first create the graph without soundcard resources*/
1522 captcard=playcard=NULL;
1524 if (!linphone_call_sound_resources_available(call)){
1525 ms_message("Sound resources are used by another call, not using soundcard.");
1526 captcard=playcard=NULL;
1528 use_ec=captcard==NULL ? FALSE : linphone_core_echo_cancellation_enabled(lc);
1529 if (playcard && stream->max_rate>0) ms_snd_card_set_preferred_sample_rate(playcard, stream->max_rate);
1530 if (captcard && stream->max_rate>0) ms_snd_card_set_preferred_sample_rate(captcard, stream->max_rate);
1531 audio_stream_enable_adaptive_bitrate_control(call->audiostream,use_arc);
1532 audio_stream_enable_adaptive_jittcomp(call->audiostream, linphone_core_audio_adaptive_jittcomp_enabled(lc));
1533 if (!call->params.in_conference && call->params.record_file)
1534 audio_stream_mixed_record_open(call->audiostream,call->params.record_file);
1535 audio_stream_start_full(
1537 call->audio_profile,
1538 stream->rtp_addr[0]!='\0' ? stream->rtp_addr : call->resultdesc->addr,
1540 stream->rtcp_addr[0]!='\0' ? stream->rtcp_addr : call->resultdesc->addr,
1541 linphone_core_rtcp_enabled(lc) ? (stream->rtcp_port) : 0,
1543 linphone_core_get_audio_jittcomp(lc),
1550 post_configure_audio_streams(call);
1551 if (muted && !send_ringbacktone){
1552 audio_stream_set_mic_gain(call->audiostream,0);
1554 if (stream->dir==SalStreamSendOnly && playfile!=NULL){
1556 ms_filter_call_method(call->audiostream->soundread,MS_FILE_PLAYER_LOOP,&pause_time);
1558 if (send_ringbacktone){
1559 setup_ring_player(lc,call);
1561 audio_stream_set_rtcp_information(call->audiostream, cname, rtcp_tool);
1563 /* valid local tags are > 0 */
1564 if (stream->proto == SalProtoRtpSavp) {
1565 const SalStreamDescription *local_st_desc=sal_media_description_find_stream(call->localdesc,
1566 SalProtoRtpSavp,SalAudio);
1567 int crypto_idx = find_crypto_index_from_tag(local_st_desc->crypto, stream->crypto_local_tag);
1569 if (crypto_idx >= 0) {
1570 audio_stream_enable_srtp(
1572 stream->crypto[0].algo,
1573 local_st_desc->crypto[crypto_idx].master_key,
1574 stream->crypto[0].master_key);
1575 call->audiostream_encrypted=TRUE;
1577 ms_warning("Failed to find local crypto algo with tag: %d", stream->crypto_local_tag);
1578 call->audiostream_encrypted=FALSE;
1580 }else call->audiostream_encrypted=FALSE;
1581 if (call->params.in_conference){
1582 /*transform the graph to connect it to the conference filter */
1583 bool_t mute=stream->dir==SalStreamRecvOnly;
1584 linphone_call_add_to_conf(call, mute);
1586 call->current_params.in_conference=call->params.in_conference;
1587 call->current_params.low_bandwidth=call->params.low_bandwidth;
1588 }else ms_warning("No audio stream accepted ?");
1592 static void linphone_call_start_video_stream(LinphoneCall *call, const char *cname,bool_t all_inputs_muted){
1593 #ifdef VIDEO_ENABLED
1594 LinphoneCore *lc=call->core;
1596 /* look for savp stream first */
1597 const SalStreamDescription *vstream=sal_media_description_find_stream(call->resultdesc,
1598 SalProtoRtpSavp,SalVideo);
1599 char rtcp_tool[128]={0};
1600 snprintf(rtcp_tool,sizeof(rtcp_tool)-1,"%s-%s",linphone_core_get_user_agent_name(),linphone_core_get_user_agent_version());
1602 /* no savp audio stream, use avp */
1604 vstream=sal_media_description_find_stream(call->resultdesc,
1605 SalProtoRtpAvp,SalVideo);
1607 /* shutdown preview */
1608 if (lc->previewstream!=NULL) {
1609 video_preview_stop(lc->previewstream);
1610 lc->previewstream=NULL;
1613 if (vstream!=NULL && vstream->dir!=SalStreamInactive && vstream->rtp_port!=0) {
1614 const char *rtp_addr=vstream->rtp_addr[0]!='\0' ? vstream->rtp_addr : call->resultdesc->addr;
1615 const char *rtcp_addr=vstream->rtcp_addr[0]!='\0' ? vstream->rtcp_addr : call->resultdesc->addr;
1616 call->video_profile=make_profile(call,call->resultdesc,vstream,&used_pt);
1618 call->current_params.video_codec = rtp_profile_get_payload(call->video_profile, used_pt);
1619 VideoStreamDir dir=VideoStreamSendRecv;
1620 MSWebCam *cam=lc->video_conf.device;
1621 bool_t is_inactive=FALSE;
1623 call->current_params.has_video=TRUE;
1625 video_stream_enable_adaptive_bitrate_control(call->videostream,
1626 linphone_core_adaptive_rate_control_enabled(lc));
1627 video_stream_enable_adaptive_jittcomp(call->videostream, linphone_core_video_adaptive_jittcomp_enabled(lc));
1628 video_stream_set_sent_video_size(call->videostream,linphone_core_get_preferred_video_size(lc));
1629 video_stream_enable_self_view(call->videostream,lc->video_conf.selfview);
1630 if (lc->video_window_id!=0)
1631 video_stream_set_native_window_id(call->videostream,lc->video_window_id);
1632 if (lc->preview_window_id!=0)
1633 video_stream_set_native_preview_window_id (call->videostream,lc->preview_window_id);
1634 video_stream_use_preview_video_window (call->videostream,lc->use_preview_window);
1636 if (vstream->dir==SalStreamSendOnly && lc->video_conf.capture ){
1637 cam=get_nowebcam_device();
1638 dir=VideoStreamSendOnly;
1639 }else if (vstream->dir==SalStreamRecvOnly && lc->video_conf.display ){
1640 dir=VideoStreamRecvOnly;
1641 }else if (vstream->dir==SalStreamSendRecv){
1642 if (lc->video_conf.display && lc->video_conf.capture)
1643 dir=VideoStreamSendRecv;
1644 else if (lc->video_conf.display)
1645 dir=VideoStreamRecvOnly;
1647 dir=VideoStreamSendOnly;
1649 ms_warning("video stream is inactive.");
1650 /*either inactive or incompatible with local capabilities*/
1653 if (call->camera_active==FALSE || all_inputs_muted){
1654 cam=get_nowebcam_device();
1657 call->log->video_enabled = TRUE;
1658 video_stream_set_direction (call->videostream, dir);
1659 ms_message("%s lc rotation:%d\n", __FUNCTION__, lc->device_rotation);
1660 video_stream_set_device_rotation(call->videostream, lc->device_rotation);
1661 video_stream_start(call->videostream,
1662 call->video_profile, rtp_addr, vstream->rtp_port,
1663 rtcp_addr, linphone_core_rtcp_enabled(lc) ? (vstream->rtcp_port) : 0,
1664 used_pt, linphone_core_get_video_jittcomp(lc), cam);
1665 video_stream_set_rtcp_information(call->videostream, cname,rtcp_tool);
1668 if (vstream->proto == SalProtoRtpSavp) {
1669 const SalStreamDescription *local_st_desc=sal_media_description_find_stream(call->localdesc,
1670 SalProtoRtpSavp,SalVideo);
1672 video_stream_enable_strp(
1674 vstream->crypto[0].algo,
1675 local_st_desc->crypto[0].master_key,
1676 vstream->crypto[0].master_key
1678 call->videostream_encrypted=TRUE;
1680 call->videostream_encrypted=FALSE;
1682 }else ms_warning("No video stream accepted.");
1684 ms_warning("No valid video stream defined.");
1689 void linphone_call_start_media_streams(LinphoneCall *call, bool_t all_inputs_muted, bool_t send_ringbacktone){
1690 LinphoneCore *lc=call->core;
1692 call->current_params.audio_codec = NULL;
1693 call->current_params.video_codec = NULL;
1695 LinphoneAddress *me=linphone_core_get_primary_contact_parsed(lc);
1697 bool_t use_arc=linphone_core_adaptive_rate_control_enabled(lc);
1698 #ifdef VIDEO_ENABLED
1699 const SalStreamDescription *vstream=sal_media_description_find_stream(call->resultdesc,
1700 SalProtoRtpAvp,SalVideo);
1703 if ((call->audiostream == NULL) && (call->videostream == NULL)) {
1704 ms_fatal("start_media_stream() called without prior init !");
1707 cname=linphone_address_as_string_uri_only(me);
1709 #if defined(VIDEO_ENABLED)
1710 if (vstream!=NULL && vstream->dir!=SalStreamInactive && vstream->payloads!=NULL){
1711 /*when video is used, do not make adaptive rate control on audio, it is stupid.*/
1715 if (call->audiostream!=NULL) {
1716 linphone_call_start_audio_stream(call,cname,all_inputs_muted,send_ringbacktone,use_arc);
1718 call->current_params.has_video=FALSE;
1719 if (call->videostream!=NULL) {
1720 linphone_call_start_video_stream(call,cname,all_inputs_muted);
1723 call->all_muted=all_inputs_muted;
1724 call->playing_ringbacktone=send_ringbacktone;
1725 call->up_bw=linphone_core_get_upload_bandwidth(lc);
1727 if (call->params.media_encryption==LinphoneMediaEncryptionZRTP) {
1728 OrtpZrtpParams params;
1729 /*will be set later when zrtp is activated*/
1730 call->current_params.media_encryption=LinphoneMediaEncryptionNone;
1732 params.zid_file=lc->zrtp_secrets_cache;
1733 audio_stream_enable_zrtp(call->audiostream,¶ms);
1734 }else if (call->params.media_encryption==LinphoneMediaEncryptionSRTP){
1735 call->current_params.media_encryption=linphone_call_are_all_streams_encrypted(call) ?
1736 LinphoneMediaEncryptionSRTP : LinphoneMediaEncryptionNone;
1739 /*also reflect the change if the "wished" params, in order to avoid to propose SAVP or video again
1740 * further in the call, for example during pause,resume, conferencing reINVITEs*/
1741 linphone_call_fix_call_parameters(call);
1742 if ((call->ice_session != NULL) && (ice_session_state(call->ice_session) != IS_Completed)) {
1743 ice_session_start_connectivity_checks(call->ice_session);
1749 linphone_address_destroy(me);
1752 void linphone_call_start_media_streams_for_ice_gathering(LinphoneCall *call){
1753 audio_stream_prepare_sound(call->audiostream, NULL, NULL);
1754 #ifdef VIDEO_ENABLED
1755 if (call->videostream) {
1756 video_stream_prepare_video(call->videostream);
1761 void linphone_call_stop_media_streams_for_ice_gathering(LinphoneCall *call){
1762 audio_stream_unprepare_sound(call->audiostream);
1763 #ifdef VIDEO_ENABLED
1764 if (call->videostream) {
1765 video_stream_unprepare_video(call->videostream);
1770 void linphone_call_update_crypto_parameters(LinphoneCall *call, SalMediaDescription *old_md, SalMediaDescription *new_md) {
1771 SalStreamDescription *old_stream;
1772 SalStreamDescription *new_stream;
1775 old_stream = sal_media_description_find_stream(old_md, SalProtoRtpSavp, SalAudio);
1776 new_stream = sal_media_description_find_stream(new_md, SalProtoRtpSavp, SalAudio);
1777 if (old_stream && new_stream) {
1778 const SalStreamDescription *local_st_desc = sal_media_description_find_stream(call->localdesc, SalProtoRtpSavp, SalAudio);
1779 if (local_st_desc) {
1780 int crypto_idx = find_crypto_index_from_tag(local_st_desc->crypto, new_stream->crypto_local_tag);
1781 if (crypto_idx >= 0) {
1782 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);
1783 call->audiostream_encrypted = TRUE;
1785 ms_warning("Failed to find local crypto algo with tag: %d", new_stream->crypto_local_tag);
1786 call->audiostream_encrypted = FALSE;
1788 for (i = 0; i < SAL_CRYPTO_ALGO_MAX; i++) {
1789 old_stream->crypto[i].tag = new_stream->crypto[i].tag;
1790 old_stream->crypto[i].algo = new_stream->crypto[i].algo;
1791 strncpy(old_stream->crypto[i].master_key, new_stream->crypto[i].master_key, sizeof(old_stream->crypto[i].master_key) - 1);
1796 #ifdef VIDEO_ENABLED
1797 old_stream = sal_media_description_find_stream(old_md, SalProtoRtpSavp, SalVideo);
1798 new_stream = sal_media_description_find_stream(new_md, SalProtoRtpSavp, SalVideo);
1799 if (old_stream && new_stream) {
1800 const SalStreamDescription *local_st_desc = sal_media_description_find_stream(call->localdesc, SalProtoRtpSavp, SalVideo);
1801 if (local_st_desc) {
1802 int crypto_idx = find_crypto_index_from_tag(local_st_desc->crypto, new_stream->crypto_local_tag);
1803 if (crypto_idx >= 0) {
1804 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);
1805 call->videostream_encrypted = TRUE;
1807 ms_warning("Failed to find local crypto algo with tag: %d", new_stream->crypto_local_tag);
1808 call->videostream_encrypted = FALSE;
1810 for (i = 0; i < SAL_CRYPTO_ALGO_MAX; i++) {
1811 old_stream->crypto[i].tag = new_stream->crypto[i].tag;
1812 old_stream->crypto[i].algo = new_stream->crypto[i].algo;
1813 strncpy(old_stream->crypto[i].master_key, new_stream->crypto[i].master_key, sizeof(old_stream->crypto[i].master_key) - 1);
1820 void linphone_call_update_remote_session_id_and_ver(LinphoneCall *call) {
1821 SalMediaDescription *remote_desc = sal_call_get_remote_media_description(call->op);
1823 call->remote_session_id = remote_desc->session_id;
1824 call->remote_session_ver = remote_desc->session_ver;
1828 void linphone_call_delete_ice_session(LinphoneCall *call){
1829 if (call->ice_session != NULL) {
1830 ice_session_destroy(call->ice_session);
1831 call->ice_session = NULL;
1832 if (call->audiostream != NULL) call->audiostream->ms.ice_check_list = NULL;
1833 if (call->videostream != NULL) call->videostream->ms.ice_check_list = NULL;
1834 call->stats[LINPHONE_CALL_STATS_AUDIO].ice_state = LinphoneIceStateNotActivated;
1835 call->stats[LINPHONE_CALL_STATS_VIDEO].ice_state = LinphoneIceStateNotActivated;
1840 void linphone_call_delete_upnp_session(LinphoneCall *call){
1841 if(call->upnp_session!=NULL) {
1842 linphone_upnp_session_destroy(call->upnp_session);
1843 call->upnp_session=NULL;
1848 static void linphone_call_log_fill_stats(LinphoneCallLog *log, AudioStream *st){
1849 audio_stream_get_local_rtp_stats (st,&log->local_stats);
1850 log->quality=audio_stream_get_average_quality_rating(st);
1853 void linphone_call_stop_audio_stream(LinphoneCall *call) {
1854 if (call->audiostream!=NULL) {
1855 rtp_session_unregister_event_queue(call->audiostream->ms.session,call->audiostream_app_evq);
1856 ortp_ev_queue_flush(call->audiostream_app_evq);
1857 ortp_ev_queue_destroy(call->audiostream_app_evq);
1858 call->audiostream_app_evq=NULL;
1860 if (call->audiostream->ec){
1861 const char *state_str=NULL;
1862 ms_filter_call_method(call->audiostream->ec,MS_ECHO_CANCELLER_GET_STATE_STRING,&state_str);
1864 ms_message("Writing echo canceler state, %i bytes",(int)strlen(state_str));
1865 lp_config_set_string(call->core->config,"sound","ec_state",state_str);
1868 linphone_call_log_fill_stats (call->log,call->audiostream);
1869 if (call->endpoint){
1870 linphone_call_remove_from_conf(call);
1872 audio_stream_stop(call->audiostream);
1873 call->audiostream=NULL;
1877 void linphone_call_stop_video_stream(LinphoneCall *call) {
1878 #ifdef VIDEO_ENABLED
1879 if (call->videostream!=NULL){
1880 rtp_session_unregister_event_queue(call->videostream->ms.session,call->videostream_app_evq);
1881 ortp_ev_queue_flush(call->videostream_app_evq);
1882 ortp_ev_queue_destroy(call->videostream_app_evq);
1883 call->videostream_app_evq=NULL;
1884 video_stream_stop(call->videostream);
1885 call->videostream=NULL;
1890 void linphone_call_stop_media_streams(LinphoneCall *call){
1891 linphone_call_stop_audio_stream(call);
1892 linphone_call_stop_video_stream(call);
1893 ms_event_queue_skip(call->core->msevq);
1895 if (call->audio_profile){
1896 rtp_profile_clear_all(call->audio_profile);
1897 rtp_profile_destroy(call->audio_profile);
1898 call->audio_profile=NULL;
1900 if (call->video_profile){
1901 rtp_profile_clear_all(call->video_profile);
1902 rtp_profile_destroy(call->video_profile);
1903 call->video_profile=NULL;
1909 void linphone_call_enable_echo_cancellation(LinphoneCall *call, bool_t enable) {
1910 if (call!=NULL && call->audiostream!=NULL && call->audiostream->ec){
1911 bool_t bypass_mode = !enable;
1912 ms_filter_call_method(call->audiostream->ec,MS_ECHO_CANCELLER_SET_BYPASS_MODE,&bypass_mode);
1915 bool_t linphone_call_echo_cancellation_enabled(LinphoneCall *call) {
1916 if (call!=NULL && call->audiostream!=NULL && call->audiostream->ec){
1918 ms_filter_call_method(call->audiostream->ec,MS_ECHO_CANCELLER_GET_BYPASS_MODE,&val);
1921 return linphone_core_echo_cancellation_enabled(call->core);
1925 void linphone_call_enable_echo_limiter(LinphoneCall *call, bool_t val){
1926 if (call!=NULL && call->audiostream!=NULL ) {
1928 const char *type=lp_config_get_string(call->core->config,"sound","el_type","mic");
1929 if (strcasecmp(type,"mic")==0)
1930 audio_stream_enable_echo_limiter(call->audiostream,ELControlMic);
1931 else if (strcasecmp(type,"full")==0)
1932 audio_stream_enable_echo_limiter(call->audiostream,ELControlFull);
1934 audio_stream_enable_echo_limiter(call->audiostream,ELInactive);
1939 bool_t linphone_call_echo_limiter_enabled(const LinphoneCall *call){
1940 if (call!=NULL && call->audiostream!=NULL ){
1941 return call->audiostream->el_type !=ELInactive ;
1943 return linphone_core_echo_limiter_enabled(call->core);
1948 * @addtogroup call_misc
1953 * Returns the measured sound volume played locally (received from remote).
1954 * It is expressed in dbm0.
1956 float linphone_call_get_play_volume(LinphoneCall *call){
1957 AudioStream *st=call->audiostream;
1958 if (st && st->volrecv){
1960 ms_filter_call_method(st->volrecv,MS_VOLUME_GET,&vol);
1964 return LINPHONE_VOLUME_DB_LOWEST;
1968 * Returns the measured sound volume recorded locally (sent to remote).
1969 * It is expressed in dbm0.
1971 float linphone_call_get_record_volume(LinphoneCall *call){
1972 AudioStream *st=call->audiostream;
1973 if (st && st->volsend && !call->audio_muted && call->state==LinphoneCallStreamsRunning){
1975 ms_filter_call_method(st->volsend,MS_VOLUME_GET,&vol);
1979 return LINPHONE_VOLUME_DB_LOWEST;
1983 * Obtain real-time quality rating of the call
1985 * Based on local RTP statistics and RTCP feedback, a quality rating is computed and updated
1986 * during all the duration of the call. This function returns its value at the time of the function call.
1987 * It is expected that the rating is updated at least every 5 seconds or so.
1988 * The rating is a floating point number comprised between 0 and 5.
1990 * 4-5 = good quality <br>
1991 * 3-4 = average quality <br>
1992 * 2-3 = poor quality <br>
1993 * 1-2 = very poor quality <br>
1994 * 0-1 = can't be worse, mostly unusable <br>
1996 * @returns The function returns -1 if no quality measurement is available, for example if no
1997 * active audio stream exist. Otherwise it returns the quality rating.
1999 float linphone_call_get_current_quality(LinphoneCall *call){
2000 if (call->audiostream){
2001 return audio_stream_get_quality_rating(call->audiostream);
2007 * Returns call quality averaged over all the duration of the call.
2009 * See linphone_call_get_current_quality() for more details about quality measurement.
2011 float linphone_call_get_average_quality(LinphoneCall *call){
2012 if (call->audiostream){
2013 return audio_stream_get_average_quality_rating(call->audiostream);
2019 * Access last known statistics for audio stream, for a given call.
2021 const LinphoneCallStats *linphone_call_get_audio_stats(const LinphoneCall *call) {
2022 return &call->stats[LINPHONE_CALL_STATS_AUDIO];
2026 * Access last known statistics for video stream, for a given call.
2028 const LinphoneCallStats *linphone_call_get_video_stats(const LinphoneCall *call) {
2029 return &call->stats[LINPHONE_CALL_STATS_VIDEO];
2033 * Enable recording of the call (voice-only).
2034 * This function must be used before the call parameters are assigned to the call.
2035 * The call recording can be started and paused after the call is established with
2036 * linphone_call_start_recording() and linphone_call_pause_recording().
2037 * @param cp the call parameters
2038 * @param path path and filename of the file where audio is written.
2040 void linphone_call_params_set_record_file(LinphoneCallParams *cp, const char *path){
2041 if (cp->record_file){
2042 ms_free(cp->record_file);
2043 cp->record_file=NULL;
2045 if (path) cp->record_file=ms_strdup(path);
2049 * Retrieves the path for the audio recoding of the call.
2051 const char *linphone_call_params_get_record_file(const LinphoneCallParams *cp){
2052 return cp->record_file;
2056 * Start call recording.
2057 * The output file where audio is recorded must be previously specified with linphone_call_params_set_record_file().
2059 void linphone_call_start_recording(LinphoneCall *call){
2060 if (!call->params.record_file){
2061 ms_error("linphone_call_start_recording(): no output file specified. Use linphone_call_params_set_record_file().");
2064 if (call->audiostream && !call->params.in_conference){
2065 audio_stream_mixed_record_start(call->audiostream);
2067 call->record_active=TRUE;
2071 * Stop call recording.
2073 void linphone_call_stop_recording(LinphoneCall *call){
2074 if (call->audiostream && !call->params.in_conference){
2075 audio_stream_mixed_record_stop(call->audiostream);
2077 call->record_active=FALSE;
2084 static void report_bandwidth(LinphoneCall *call, RtpSession *as, RtpSession *vs){
2085 call->stats[LINPHONE_CALL_STATS_AUDIO].download_bandwidth=(as!=NULL) ? (rtp_session_compute_recv_bandwidth(as)*1e-3) : 0;
2086 call->stats[LINPHONE_CALL_STATS_AUDIO].upload_bandwidth=(as!=NULL) ? (rtp_session_compute_send_bandwidth(as)*1e-3) : 0;
2087 call->stats[LINPHONE_CALL_STATS_VIDEO].download_bandwidth=(vs!=NULL) ? (rtp_session_compute_recv_bandwidth(vs)*1e-3) : 0;
2088 call->stats[LINPHONE_CALL_STATS_VIDEO].upload_bandwidth=(vs!=NULL) ? (rtp_session_compute_send_bandwidth(vs)*1e-3) : 0;
2089 ms_message("bandwidth usage: audio=[d=%.1f,u=%.1f] video=[d=%.1f,u=%.1f] kbit/sec",
2090 call->stats[LINPHONE_CALL_STATS_AUDIO].download_bandwidth,
2091 call->stats[LINPHONE_CALL_STATS_AUDIO].upload_bandwidth ,
2092 call->stats[LINPHONE_CALL_STATS_VIDEO].download_bandwidth,
2093 call->stats[LINPHONE_CALL_STATS_VIDEO].upload_bandwidth
2097 static void linphone_core_disconnected(LinphoneCore *lc, LinphoneCall *call){
2101 from = linphone_call_get_remote_address_as_string(call);
2104 snprintf(temp,sizeof(temp),"Remote end %s seems to have disconnected, the call is going to be closed.",from);
2109 snprintf(temp,sizeof(temp),"Remote end seems to have disconnected, the call is going to be closed.");
2111 if (lc->vtable.display_warning!=NULL)
2112 lc->vtable.display_warning(lc,temp);
2113 linphone_core_terminate_call(lc,call);
2116 static void handle_ice_events(LinphoneCall *call, OrtpEvent *ev){
2117 OrtpEventType evt=ortp_event_get_type(ev);
2118 OrtpEventData *evd=ortp_event_get_data(ev);
2121 if (evt == ORTP_EVENT_ICE_SESSION_PROCESSING_FINISHED) {
2122 switch (ice_session_state(call->ice_session)) {
2124 ice_session_select_candidates(call->ice_session);
2125 if (ice_session_role(call->ice_session) == IR_Controlling) {
2126 linphone_core_update_call(call->core, call, &call->current_params);
2130 if (ice_session_has_completed_check_list(call->ice_session) == TRUE) {
2131 ice_session_select_candidates(call->ice_session);
2132 if (ice_session_role(call->ice_session) == IR_Controlling) {
2133 /* At least one ICE session has succeeded, so perform a call update. */
2134 linphone_core_update_call(call->core, call, &call->current_params);
2141 linphone_core_update_ice_state_in_call_stats(call);
2142 } else if (evt == ORTP_EVENT_ICE_GATHERING_FINISHED) {
2144 if (evd->info.ice_processing_successful==TRUE) {
2145 ice_session_compute_candidates_foundations(call->ice_session);
2146 ice_session_eliminate_redundant_candidates(call->ice_session);
2147 ice_session_choose_default_candidates(call->ice_session);
2148 ping_time = ice_session_average_gathering_round_trip_time(call->ice_session);
2149 if (ping_time >=0) {
2150 call->ping_time=ping_time;
2153 ms_warning("No STUN answer from [%s], disabling ICE",linphone_core_get_stun_server(call->core));
2154 linphone_call_delete_ice_session(call);
2156 switch (call->state) {
2157 case LinphoneCallUpdating:
2158 linphone_core_start_update_call(call->core, call);
2160 case LinphoneCallUpdatedByRemote:
2161 linphone_core_start_accept_call_update(call->core, call);
2163 case LinphoneCallOutgoingInit:
2164 linphone_call_stop_media_streams_for_ice_gathering(call);
2165 linphone_core_proceed_with_invite_if_ready(call->core, call, NULL);
2167 case LinphoneCallIdle:
2168 linphone_call_stop_media_streams_for_ice_gathering(call);
2169 linphone_core_notify_incoming_call(call->core, call);
2174 } else if (evt == ORTP_EVENT_ICE_LOSING_PAIRS_COMPLETED) {
2175 linphone_core_start_accept_call_update(call->core, call);
2176 linphone_core_update_ice_state_in_call_stats(call);
2177 } else if (evt == ORTP_EVENT_ICE_RESTART_NEEDED) {
2178 ice_session_restart(call->ice_session);
2179 ice_session_set_role(call->ice_session, IR_Controlling);
2180 linphone_core_update_call(call->core, call, &call->current_params);
2184 void linphone_call_background_tasks(LinphoneCall *call, bool_t one_second_elapsed){
2185 LinphoneCore* lc = call->core;
2186 int disconnect_timeout = linphone_core_get_nortp_timeout(call->core);
2187 bool_t disconnected=FALSE;
2189 if (call->state==LinphoneCallStreamsRunning && one_second_elapsed){
2190 RtpSession *as=NULL,*vs=NULL;
2191 float audio_load=0, video_load=0;
2192 if (call->audiostream!=NULL){
2193 as=call->audiostream->ms.session;
2194 if (call->audiostream->ms.ticker)
2195 audio_load=ms_ticker_get_average_load(call->audiostream->ms.ticker);
2197 if (call->videostream!=NULL){
2198 if (call->videostream->ms.ticker)
2199 video_load=ms_ticker_get_average_load(call->videostream->ms.ticker);
2200 vs=call->videostream->ms.session;
2202 report_bandwidth(call,as,vs);
2203 ms_message("Thread processing load: audio=%f\tvideo=%f",audio_load,video_load);
2207 linphone_upnp_call_process(call);
2210 #ifdef VIDEO_ENABLED
2211 if (call->videostream!=NULL) {
2214 /* Ensure there is no dangling ICE check list. */
2215 if (call->ice_session == NULL) call->videostream->ms.ice_check_list = NULL;
2217 // Beware that the application queue should not depend on treatments fron the
2218 // mediastreamer queue.
2219 video_stream_iterate(call->videostream);
2221 while (call->videostream_app_evq && (NULL != (ev=ortp_ev_queue_get(call->videostream_app_evq)))){
2222 OrtpEventType evt=ortp_event_get_type(ev);
2223 OrtpEventData *evd=ortp_event_get_data(ev);
2224 if (evt == ORTP_EVENT_ZRTP_ENCRYPTION_CHANGED){
2225 linphone_call_videostream_encryption_changed(call, evd->info.zrtp_stream_encrypted);
2226 } else if (evt == ORTP_EVENT_RTCP_PACKET_RECEIVED) {
2227 call->stats[LINPHONE_CALL_STATS_VIDEO].round_trip_delay = rtp_session_get_round_trip_propagation(call->videostream->ms.session);
2228 if(call->stats[LINPHONE_CALL_STATS_VIDEO].received_rtcp != NULL)
2229 freemsg(call->stats[LINPHONE_CALL_STATS_VIDEO].received_rtcp);
2230 call->stats[LINPHONE_CALL_STATS_VIDEO].received_rtcp = evd->packet;
2232 if (lc->vtable.call_stats_updated)
2233 lc->vtable.call_stats_updated(lc, call, &call->stats[LINPHONE_CALL_STATS_VIDEO]);
2234 } else if (evt == ORTP_EVENT_RTCP_PACKET_EMITTED) {
2235 memcpy(&call->stats[LINPHONE_CALL_STATS_VIDEO].jitter_stats, rtp_session_get_jitter_stats(call->videostream->ms.session), sizeof(jitter_stats_t));
2236 if(call->stats[LINPHONE_CALL_STATS_VIDEO].sent_rtcp != NULL)
2237 freemsg(call->stats[LINPHONE_CALL_STATS_VIDEO].sent_rtcp);
2238 call->stats[LINPHONE_CALL_STATS_VIDEO].sent_rtcp = evd->packet;
2240 if (lc->vtable.call_stats_updated)
2241 lc->vtable.call_stats_updated(lc, call, &call->stats[LINPHONE_CALL_STATS_VIDEO]);
2242 } else if ((evt == ORTP_EVENT_ICE_SESSION_PROCESSING_FINISHED) || (evt == ORTP_EVENT_ICE_GATHERING_FINISHED)
2243 || (evt == ORTP_EVENT_ICE_LOSING_PAIRS_COMPLETED) || (evt == ORTP_EVENT_ICE_RESTART_NEEDED)) {
2244 handle_ice_events(call, ev);
2246 ortp_event_destroy(ev);
2250 if (call->audiostream!=NULL) {
2253 /* Ensure there is no dangling ICE check list. */
2254 if (call->ice_session == NULL) call->audiostream->ms.ice_check_list = NULL;
2256 // Beware that the application queue should not depend on treatments fron the
2257 // mediastreamer queue.
2258 audio_stream_iterate(call->audiostream);
2260 while (call->audiostream_app_evq && (NULL != (ev=ortp_ev_queue_get(call->audiostream_app_evq)))){
2261 OrtpEventType evt=ortp_event_get_type(ev);
2262 OrtpEventData *evd=ortp_event_get_data(ev);
2263 if (evt == ORTP_EVENT_ZRTP_ENCRYPTION_CHANGED){
2264 linphone_call_audiostream_encryption_changed(call, evd->info.zrtp_stream_encrypted);
2265 } else if (evt == ORTP_EVENT_ZRTP_SAS_READY) {
2266 linphone_call_audiostream_auth_token_ready(call, evd->info.zrtp_sas.sas, evd->info.zrtp_sas.verified);
2267 } else if (evt == ORTP_EVENT_RTCP_PACKET_RECEIVED) {
2268 call->stats[LINPHONE_CALL_STATS_AUDIO].round_trip_delay = rtp_session_get_round_trip_propagation(call->audiostream->ms.session);
2269 if(call->stats[LINPHONE_CALL_STATS_AUDIO].received_rtcp != NULL)
2270 freemsg(call->stats[LINPHONE_CALL_STATS_AUDIO].received_rtcp);
2271 call->stats[LINPHONE_CALL_STATS_AUDIO].received_rtcp = evd->packet;
2273 if (lc->vtable.call_stats_updated)
2274 lc->vtable.call_stats_updated(lc, call, &call->stats[LINPHONE_CALL_STATS_AUDIO]);
2275 } else if (evt == ORTP_EVENT_RTCP_PACKET_EMITTED) {
2276 memcpy(&call->stats[LINPHONE_CALL_STATS_AUDIO].jitter_stats, rtp_session_get_jitter_stats(call->audiostream->ms.session), sizeof(jitter_stats_t));
2277 if(call->stats[LINPHONE_CALL_STATS_AUDIO].sent_rtcp != NULL)
2278 freemsg(call->stats[LINPHONE_CALL_STATS_AUDIO].sent_rtcp);
2279 call->stats[LINPHONE_CALL_STATS_AUDIO].sent_rtcp = evd->packet;
2281 if (lc->vtable.call_stats_updated)
2282 lc->vtable.call_stats_updated(lc, call, &call->stats[LINPHONE_CALL_STATS_AUDIO]);
2283 } else if ((evt == ORTP_EVENT_ICE_SESSION_PROCESSING_FINISHED) || (evt == ORTP_EVENT_ICE_GATHERING_FINISHED)
2284 || (evt == ORTP_EVENT_ICE_LOSING_PAIRS_COMPLETED) || (evt == ORTP_EVENT_ICE_RESTART_NEEDED)) {
2285 handle_ice_events(call, ev);
2286 } else if (evt==ORTP_EVENT_TELEPHONE_EVENT){
2287 linphone_core_dtmf_received(lc,evd->info.telephone_event);
2289 ortp_event_destroy(ev);
2292 if (call->state==LinphoneCallStreamsRunning && one_second_elapsed && call->audiostream!=NULL && disconnect_timeout>0 )
2293 disconnected=!audio_stream_alive(call->audiostream,disconnect_timeout);
2295 linphone_core_disconnected(call->core,call);
2298 void linphone_call_log_completed(LinphoneCall *call){
2299 LinphoneCore *lc=call->core;
2301 call->log->duration=time(NULL)-call->start_time;
2303 if (call->log->status==LinphoneCallMissed){
2306 info=ortp_strdup_printf(ngettext("You have missed %i call.",
2307 "You have missed %i calls.", lc->missed_calls),
2309 if (lc->vtable.display_status!=NULL)
2310 lc->vtable.display_status(lc,info);
2313 lc->call_logs=ms_list_prepend(lc->call_logs,(void *)call->log);
2314 if (ms_list_size(lc->call_logs)>lc->max_call_logs){
2315 MSList *elem,*prevelem=NULL;
2316 /*find the last element*/
2317 for(elem=lc->call_logs;elem!=NULL;elem=elem->next){
2321 linphone_call_log_destroy((LinphoneCallLog*)elem->data);
2322 lc->call_logs=ms_list_remove_link(lc->call_logs,elem);
2324 if (lc->vtable.call_log_updated!=NULL){
2325 lc->vtable.call_log_updated(lc,call->log);
2327 call_logs_write_to_config_file(lc);
2330 LinphoneCallState linphone_call_get_transfer_state(LinphoneCall *call) {
2331 return call->transfer_state;
2334 void linphone_call_set_transfer_state(LinphoneCall* call, LinphoneCallState state) {
2335 if (state != call->transfer_state) {
2336 LinphoneCore* lc = call->core;
2337 call->transfer_state = state;
2338 if (lc->vtable.transfer_state_changed)
2339 lc->vtable.transfer_state_changed(lc, call, state);
2344 * Returns true if the call is part of the conference.
2345 * @ingroup conferencing
2347 bool_t linphone_call_is_in_conference(const LinphoneCall *call) {
2348 return call->params.in_conference;
2353 * Perform a zoom of the video displayed during a call.
2354 * @param call the call.
2355 * @param zoom_factor a floating point number describing the zoom factor. A value 1.0 corresponds to no zoom applied.
2356 * @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.
2357 * @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.
2359 * 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.
2361 void linphone_call_zoom_video(LinphoneCall* call, float zoom_factor, float* cx, float* cy) {
2362 VideoStream* vstream = call->videostream;
2363 if (vstream && vstream->output) {
2366 if (zoom_factor < 1)
2368 float halfsize = 0.5 * 1.0 / zoom_factor;
2370 if ((*cx - halfsize) < 0)
2372 if ((*cx + halfsize) > 1)
2374 if ((*cy - halfsize) < 0)
2376 if ((*cy + halfsize) > 1)
2379 zoom[0] = zoom_factor;
2382 ms_filter_call_method(vstream->output, MS_VIDEO_DISPLAY_ZOOM, &zoom);
2383 }else ms_warning("Could not apply zoom: video output wasn't activated.");