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 if (linphone_core_get_firewall_policy(call->core) == LinphonePolicyUseIce) {
476 call->ice_session = ice_session_new();
477 ice_session_set_role(call->ice_session, IR_Controlling);
479 if (linphone_core_get_firewall_policy(call->core) == LinphonePolicyUseStun) {
480 call->ping_time=linphone_core_run_stun_tests(call->core,call);
483 if (linphone_core_get_firewall_policy(call->core) == LinphonePolicyUseUpnp) {
484 call->upnp_session = linphone_upnp_session_new(call);
487 call->camera_active=params->has_video;
489 discover_mtu(lc,linphone_address_get_domain (to));
490 if (params->referer){
491 sal_call_set_referer(call->op,params->referer->op);
492 call->referer=linphone_call_ref(params->referer);
497 LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *from, LinphoneAddress *to, SalOp *op){
498 LinphoneCall *call=ms_new0(LinphoneCall,1);
500 const SalMediaDescription *md;
502 call->dir=LinphoneCallIncoming;
503 sal_op_set_user_pointer(op,call);
507 if (lc->sip_conf.ping_with_options){
508 /*the following sends an option request back to the caller so that
509 we get a chance to discover our nat'd address before answering.*/
510 call->ping_op=sal_op_new(lc->sal);
511 from_str=linphone_address_as_string_uri_only(from);
512 sal_op_set_route(call->ping_op,sal_op_get_network_origin(op));
513 sal_op_set_user_pointer(call->ping_op,call);
514 sal_ping(call->ping_op,linphone_core_find_best_identity(lc,from,NULL),from_str);
518 linphone_address_clean(from);
519 linphone_core_get_local_ip(lc,linphone_address_get_domain(from),call->localip);
520 linphone_call_init_common(call, from, to);
521 call->log->call_id=ms_strdup(sal_op_get_call_id(op)); /*must be known at that time*/
522 linphone_core_init_default_params(lc, &call->params);
523 md=sal_call_get_remote_media_description(op);
524 call->params.has_video &= !!lc->video_policy.automatically_accept;
526 // It is licit to receive an INVITE without SDP
527 // In this case WE chose the media parameters according to policy.
528 call->params.has_video &= linphone_core_media_description_contains_video_stream(md);
530 switch (linphone_core_get_firewall_policy(call->core)) {
531 case LinphonePolicyUseIce:
532 call->ice_session = ice_session_new();
533 ice_session_set_role(call->ice_session, IR_Controlled);
534 linphone_core_update_ice_from_remote_media_description(call, sal_call_get_remote_media_description(op));
535 if (call->ice_session != NULL) {
536 linphone_call_init_media_streams(call);
537 linphone_call_start_media_streams_for_ice_gathering(call);
538 if (linphone_core_gather_ice_candidates(call->core,call)<0) {
539 /* Ice candidates gathering failed, proceed with the call anyway. */
540 linphone_call_delete_ice_session(call);
541 linphone_call_stop_media_streams_for_ice_gathering(call);
545 case LinphonePolicyUseStun:
546 call->ping_time=linphone_core_run_stun_tests(call->core,call);
547 /* No break to also destroy ice session in this case. */
549 case LinphonePolicyUseUpnp:
551 call->upnp_session = linphone_upnp_session_new(call);
552 if (call->upnp_session != NULL) {
553 linphone_call_init_media_streams(call);
554 if (linphone_core_update_upnp_from_remote_media_description(call, sal_call_get_remote_media_description(op))<0) {
555 /* uPnP port mappings failed, proceed with the call anyway. */
556 linphone_call_delete_upnp_session(call);
564 call->camera_active=call->params.has_video;
566 discover_mtu(lc,linphone_address_get_domain(from));
570 /* this function is called internally to get rid of a call.
571 It performs the following tasks:
572 - remove the call from the internal list of calls
573 - update the call logs accordingly
576 static void linphone_call_set_terminated(LinphoneCall *call){
577 LinphoneCore *lc=call->core;
579 linphone_core_update_allocated_audio_bandwidth(lc);
581 call->owns_call_log=FALSE;
582 linphone_call_log_completed(call);
585 if (call == lc->current_call){
586 ms_message("Resetting the current call");
587 lc->current_call=NULL;
590 if (linphone_core_del_call(lc,call) != 0){
591 ms_error("Could not remove the call from the list !!!");
594 if (ms_list_size(lc->calls)==0)
595 linphone_core_notify_all_friends(lc,lc->presence_mode);
597 linphone_core_conference_check_uninit(lc);
598 if (call->ringing_beep){
599 linphone_core_stop_dtmf(lc);
600 call->ringing_beep=FALSE;
603 linphone_call_unref(call->referer);
608 void linphone_call_fix_call_parameters(LinphoneCall *call){
609 call->params.has_video=call->current_params.has_video;
610 call->params.media_encryption=call->current_params.media_encryption;
613 const char *linphone_call_state_to_string(LinphoneCallState cs){
615 case LinphoneCallIdle:
616 return "LinphoneCallIdle";
617 case LinphoneCallIncomingReceived:
618 return "LinphoneCallIncomingReceived";
619 case LinphoneCallOutgoingInit:
620 return "LinphoneCallOutgoingInit";
621 case LinphoneCallOutgoingProgress:
622 return "LinphoneCallOutgoingProgress";
623 case LinphoneCallOutgoingRinging:
624 return "LinphoneCallOutgoingRinging";
625 case LinphoneCallOutgoingEarlyMedia:
626 return "LinphoneCallOutgoingEarlyMedia";
627 case LinphoneCallConnected:
628 return "LinphoneCallConnected";
629 case LinphoneCallStreamsRunning:
630 return "LinphoneCallStreamsRunning";
631 case LinphoneCallPausing:
632 return "LinphoneCallPausing";
633 case LinphoneCallPaused:
634 return "LinphoneCallPaused";
635 case LinphoneCallResuming:
636 return "LinphoneCallResuming";
637 case LinphoneCallRefered:
638 return "LinphoneCallRefered";
639 case LinphoneCallError:
640 return "LinphoneCallError";
641 case LinphoneCallEnd:
642 return "LinphoneCallEnd";
643 case LinphoneCallPausedByRemote:
644 return "LinphoneCallPausedByRemote";
645 case LinphoneCallUpdatedByRemote:
646 return "LinphoneCallUpdatedByRemote";
647 case LinphoneCallIncomingEarlyMedia:
648 return "LinphoneCallIncomingEarlyMedia";
649 case LinphoneCallUpdating:
650 return "LinphoneCallUpdating";
651 case LinphoneCallReleased:
652 return "LinphoneCallReleased";
654 return "undefined state";
657 void linphone_call_set_state(LinphoneCall *call, LinphoneCallState cstate, const char *message){
658 LinphoneCore *lc=call->core;
660 if (call->state!=cstate){
661 if (call->state==LinphoneCallEnd || call->state==LinphoneCallError){
662 if (cstate!=LinphoneCallReleased){
663 ms_warning("Spurious call state change from %s to %s, ignored.",linphone_call_state_to_string(call->state),
664 linphone_call_state_to_string(cstate));
668 ms_message("Call %p: moving from state %s to %s",call,linphone_call_state_to_string(call->state),
669 linphone_call_state_to_string(cstate));
670 if (cstate!=LinphoneCallRefered){
671 /*LinphoneCallRefered is rather an event, not a state.
672 Indeed it does not change the state of the call (still paused or running)*/
675 if (cstate==LinphoneCallEnd || cstate==LinphoneCallError){
676 switch(call->reason){
677 case LinphoneReasonDeclined:
678 call->log->status=LinphoneCallDeclined;
680 case LinphoneReasonNotAnswered:
681 call->log->status=LinphoneCallMissed;
686 linphone_call_set_terminated (call);
688 if (cstate == LinphoneCallConnected) {
689 call->log->status=LinphoneCallSuccess;
690 call->media_start_time=time(NULL);
693 if (lc->vtable.call_state_changed)
694 lc->vtable.call_state_changed(lc,call,cstate,message);
695 if (cstate==LinphoneCallReleased){
696 if (call->op!=NULL) {
697 /* so that we cannot have anymore upcalls for SAL
698 concerning this call*/
699 sal_op_release(call->op);
702 linphone_call_unref(call);
707 static void linphone_call_destroy(LinphoneCall *obj)
710 linphone_call_delete_upnp_session(obj);
712 linphone_call_delete_ice_session(obj);
714 sal_op_release(obj->op);
717 if (obj->resultdesc!=NULL) {
718 sal_media_description_unref(obj->resultdesc);
719 obj->resultdesc=NULL;
721 if (obj->localdesc!=NULL) {
722 sal_media_description_unref(obj->localdesc);
726 sal_op_release(obj->ping_op);
729 ms_free(obj->refer_to);
731 if (obj->owns_call_log)
732 linphone_call_log_destroy(obj->log);
733 if (obj->auth_token) {
734 ms_free(obj->auth_token);
736 if (obj->params.record_file)
737 ms_free(obj->params.record_file);
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;
820 * Returns the remote address associated to this call
823 const LinphoneAddress * linphone_call_get_remote_address(const LinphoneCall *call){
824 return call->dir==LinphoneCallIncoming ? call->log->from : call->log->to;
828 * Returns the remote address associated to this call as a string.
830 * The result string must be freed by user using ms_free().
832 char *linphone_call_get_remote_address_as_string(const LinphoneCall *call){
833 return linphone_address_as_string(linphone_call_get_remote_address(call));
837 * Retrieves the call's current state.
839 LinphoneCallState linphone_call_get_state(const LinphoneCall *call){
844 * Returns the reason for a call termination (either error or normal termination)
846 LinphoneReason linphone_call_get_reason(const LinphoneCall *call){
851 * Get the user_pointer in the LinphoneCall
853 * @ingroup call_control
855 * return user_pointer an opaque user pointer that can be retrieved at any time
857 void *linphone_call_get_user_pointer(LinphoneCall *call)
859 return call->user_pointer;
863 * Set the user_pointer in the LinphoneCall
865 * @ingroup call_control
867 * the user_pointer is an opaque user pointer that can be retrieved at any time in the LinphoneCall
869 void linphone_call_set_user_pointer(LinphoneCall *call, void *user_pointer)
871 call->user_pointer = user_pointer;
875 * Returns the call log associated to this call.
877 LinphoneCallLog *linphone_call_get_call_log(const LinphoneCall *call){
882 * Returns the refer-to uri (if the call was transfered).
884 const char *linphone_call_get_refer_to(const LinphoneCall *call){
885 return call->refer_to;
889 * Returns direction of the call (incoming or outgoing).
891 LinphoneCallDir linphone_call_get_dir(const LinphoneCall *call){
892 return call->log->dir;
896 * Returns the far end's user agent description string, if available.
898 const char *linphone_call_get_remote_user_agent(LinphoneCall *call){
900 return sal_op_get_remote_ua (call->op);
906 * Returns the far end's sip contact as a string, if available.
908 const char *linphone_call_get_remote_contact(LinphoneCall *call){
910 return sal_op_get_remote_contact(call->op);
916 * Returns true if this calls has received a transfer that has not been
918 * Pending transfers are executed when this call is being paused or closed,
919 * locally or by remote endpoint.
920 * If the call is already paused while receiving the transfer request, the
921 * transfer immediately occurs.
923 bool_t linphone_call_has_transfer_pending(const LinphoneCall *call){
924 return call->refer_pending;
928 * Returns call's duration in seconds.
930 int linphone_call_get_duration(const LinphoneCall *call){
931 if (call->media_start_time==0) return 0;
932 return time(NULL)-call->media_start_time;
936 * Returns the call object this call is replacing, if any.
937 * Call replacement can occur during call transfers.
938 * By default, the core automatically terminates the replaced call and accept the new one.
939 * This function allows the application to know whether a new incoming call is a one that replaces another one.
941 LinphoneCall *linphone_call_get_replaced_call(LinphoneCall *call){
942 SalOp *op=sal_call_get_replaces(call->op);
944 return (LinphoneCall*)sal_op_get_user_pointer(op);
950 * Indicate whether camera input should be sent to remote end.
952 void linphone_call_enable_camera (LinphoneCall *call, bool_t enable){
954 if (call->videostream!=NULL && call->videostream->ms.ticker!=NULL){
955 LinphoneCore *lc=call->core;
956 MSWebCam *nowebcam=get_nowebcam_device();
957 if (call->camera_active!=enable && lc->video_conf.device!=nowebcam){
958 video_stream_change_camera(call->videostream,
959 enable ? lc->video_conf.device : nowebcam);
962 call->camera_active=enable;
967 * Take a photo of currently received video and write it into a jpeg file.
969 int linphone_call_take_video_snapshot(LinphoneCall *call, const char *file){
971 if (call->videostream!=NULL && call->videostream->jpegwriter!=NULL){
972 return ms_filter_call_method(call->videostream->jpegwriter,MS_JPEG_WRITER_TAKE_SNAPSHOT,(void*)file);
974 ms_warning("Cannot take snapshot: no currently running video stream on this call.");
981 * Returns TRUE if camera pictures are sent to the remote party.
983 bool_t linphone_call_camera_enabled (const LinphoneCall *call){
984 return call->camera_active;
988 * Enable video stream.
990 void linphone_call_params_enable_video(LinphoneCallParams *cp, bool_t enabled){
991 cp->has_video=enabled;
995 * Returns the audio codec used in the call, described as a PayloadType structure.
997 const PayloadType* linphone_call_params_get_used_audio_codec(const LinphoneCallParams *cp) {
998 return cp->audio_codec;
1003 * Returns the video codec used in the call, described as a PayloadType structure.
1005 const PayloadType* linphone_call_params_get_used_video_codec(const LinphoneCallParams *cp) {
1006 return cp->video_codec;
1010 * @ingroup call_control
1011 * Use to know if this call has been configured in low bandwidth mode.
1012 * This mode can be automatically discovered thanks to a stun server when activate_edge_workarounds=1 in section [net] of configuration file.
1013 * An application that would have reliable way to know network capacity may not use activate_edge_workarounds=1 but instead manually configure
1014 * low bandwidth mode with linphone_call_params_enable_low_bandwidth().
1015 * <br> When enabled, this param may transform a call request with video in audio only mode.
1016 * @return TRUE if low bandwidth has been configured/detected
1018 bool_t linphone_call_params_low_bandwidth_enabled(const LinphoneCallParams *cp) {
1019 return cp->low_bandwidth;
1023 * @ingroup call_control
1024 * Indicate low bandwith mode.
1025 * 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
1026 * 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
1027 * that it is achievable by the codec selected after SDP handshake. Video is automatically disabled.
1030 void linphone_call_params_enable_low_bandwidth(LinphoneCallParams *cp, bool_t enabled){
1031 cp->low_bandwidth=enabled;
1035 * Returns whether video is enabled.
1037 bool_t linphone_call_params_video_enabled(const LinphoneCallParams *cp){
1038 return cp->has_video;
1041 enum LinphoneMediaEncryption linphone_call_params_get_media_encryption(const LinphoneCallParams *cp) {
1042 return cp->media_encryption;
1045 void linphone_call_params_set_media_encryption(LinphoneCallParams *cp, enum LinphoneMediaEncryption e) {
1046 cp->media_encryption = e;
1051 * Enable sending of real early media (during outgoing calls).
1053 void linphone_call_params_enable_early_media_sending(LinphoneCallParams *cp, bool_t enabled){
1054 cp->real_early_media=enabled;
1057 bool_t linphone_call_params_early_media_sending_enabled(const LinphoneCallParams *cp){
1058 return cp->real_early_media;
1062 * Returns true if the call is part of the locally managed conference.
1064 bool_t linphone_call_params_local_conference_mode(const LinphoneCallParams *cp){
1065 return cp->in_conference;
1069 * Refine bandwidth settings for this call by setting a bandwidth limit for audio streams.
1070 * As a consequence, codecs whose bitrates are not compatible with this limit won't be used.
1072 void linphone_call_params_set_audio_bandwidth_limit(LinphoneCallParams *cp, int bandwidth){
1073 cp->audio_bw=bandwidth;
1076 #ifdef VIDEO_ENABLED
1078 * Request remote side to send us a Video Fast Update.
1080 void linphone_call_send_vfu_request(LinphoneCall *call)
1082 if (LinphoneCallStreamsRunning == linphone_call_get_state(call))
1083 sal_call_send_vfu_request(call->op);
1088 void _linphone_call_params_copy(LinphoneCallParams *ncp, const LinphoneCallParams *cp){
1089 memcpy(ncp,cp,sizeof(LinphoneCallParams));
1090 if (cp->record_file) ncp->record_file=ms_strdup(cp->record_file);
1096 LinphoneCallParams * linphone_call_params_copy(const LinphoneCallParams *cp){
1097 LinphoneCallParams *ncp=ms_new0(LinphoneCallParams,1);
1098 _linphone_call_params_copy(ncp,cp);
1105 void linphone_call_params_destroy(LinphoneCallParams *p){
1106 if (p->record_file) ms_free(p->record_file);
1115 #ifdef TEST_EXT_RENDERER
1116 static void rendercb(void *data, const MSPicture *local, const MSPicture *remote){
1117 ms_message("rendercb, local buffer=%p, remote buffer=%p",
1118 local ? local->planes[0] : NULL, remote? remote->planes[0] : NULL);
1122 #ifdef VIDEO_ENABLED
1123 static void video_stream_event_cb(void *user_pointer, const MSFilter *f, const unsigned int event_id, const void *args){
1124 LinphoneCall* call = (LinphoneCall*) user_pointer;
1125 ms_warning("In linphonecall.c: video_stream_event_cb");
1127 case MS_VIDEO_DECODER_DECODING_ERRORS:
1128 ms_warning("Case is MS_VIDEO_DECODER_DECODING_ERRORS");
1129 linphone_call_send_vfu_request(call);
1131 case MS_VIDEO_DECODER_FIRST_IMAGE_DECODED:
1132 ms_message("First video frame decoded successfully");
1133 if (call->nextVideoFrameDecoded._func != NULL)
1134 call->nextVideoFrameDecoded._func(call, call->nextVideoFrameDecoded._user_data);
1137 ms_warning("Unhandled event %i", event_id);
1143 void linphone_call_set_next_video_frame_decoded_callback(LinphoneCall *call, LinphoneCallCbFunc cb, void* user_data) {
1144 call->nextVideoFrameDecoded._func = cb;
1145 call->nextVideoFrameDecoded._user_data = user_data;
1146 #ifdef VIDEO_ENABLED
1147 ms_filter_call_method_noarg(call->videostream->ms.decoder, MS_VIDEO_DECODER_RESET_FIRST_IMAGE_NOTIFICATION);
1151 void linphone_call_init_audio_stream(LinphoneCall *call){
1152 LinphoneCore *lc=call->core;
1153 AudioStream *audiostream;
1156 if (call->audiostream != NULL) return;
1157 call->audiostream=audiostream=audio_stream_new(call->audio_port,call->audio_port+1,linphone_core_ipv6_enabled(lc));
1158 dscp=linphone_core_get_audio_dscp(lc);
1160 audio_stream_set_dscp(audiostream,dscp);
1161 if (linphone_core_echo_limiter_enabled(lc)){
1162 const char *type=lp_config_get_string(lc->config,"sound","el_type","mic");
1163 if (strcasecmp(type,"mic")==0)
1164 audio_stream_enable_echo_limiter(audiostream,ELControlMic);
1165 else if (strcasecmp(type,"full")==0)
1166 audio_stream_enable_echo_limiter(audiostream,ELControlFull);
1168 audio_stream_enable_gain_control(audiostream,TRUE);
1169 if (linphone_core_echo_cancellation_enabled(lc)){
1170 int len,delay,framesize;
1171 const char *statestr=lp_config_get_string(lc->config,"sound","ec_state",NULL);
1172 len=lp_config_get_int(lc->config,"sound","ec_tail_len",0);
1173 delay=lp_config_get_int(lc->config,"sound","ec_delay",0);
1174 framesize=lp_config_get_int(lc->config,"sound","ec_framesize",0);
1175 audio_stream_set_echo_canceller_params(audiostream,len,delay,framesize);
1176 if (statestr && audiostream->ec){
1177 ms_filter_call_method(audiostream->ec,MS_ECHO_CANCELLER_SET_STATE_STRING,(void*)statestr);
1180 audio_stream_enable_automatic_gain_control(audiostream,linphone_core_agc_enabled(lc));
1182 int enabled=lp_config_get_int(lc->config,"sound","noisegate",0);
1183 audio_stream_enable_noise_gate(audiostream,enabled);
1186 audio_stream_set_features(audiostream,linphone_core_get_audio_features(lc));
1189 RtpTransport *artp=lc->rtptf->audio_rtp_func(lc->rtptf->audio_rtp_func_data, call->audio_port);
1190 RtpTransport *artcp=lc->rtptf->audio_rtcp_func(lc->rtptf->audio_rtcp_func_data, call->audio_port+1);
1191 rtp_session_set_transports(audiostream->ms.session,artp,artcp);
1193 if ((linphone_core_get_firewall_policy(lc) == LinphonePolicyUseIce) && (call->ice_session != NULL)){
1194 rtp_session_set_pktinfo(audiostream->ms.session, TRUE);
1195 rtp_session_set_symmetric_rtp(audiostream->ms.session, FALSE);
1196 if (ice_session_check_list(call->ice_session, 0) == NULL) {
1197 ice_session_add_check_list(call->ice_session, ice_check_list_new());
1199 audiostream->ms.ice_check_list = ice_session_check_list(call->ice_session, 0);
1200 ice_check_list_set_rtp_session(audiostream->ms.ice_check_list, audiostream->ms.session);
1203 call->audiostream_app_evq = ortp_ev_queue_new();
1204 rtp_session_register_event_queue(audiostream->ms.session,call->audiostream_app_evq);
1207 void linphone_call_init_video_stream(LinphoneCall *call){
1208 #ifdef VIDEO_ENABLED
1209 LinphoneCore *lc=call->core;
1211 if (!call->params.has_video) {
1212 linphone_call_stop_video_stream(call);
1215 if (call->videostream != NULL) return;
1216 if ((lc->video_conf.display || lc->video_conf.capture) && call->params.has_video){
1217 int video_recv_buf_size=lp_config_get_int(lc->config,"video","recv_buf_size",0);
1218 int dscp=linphone_core_get_video_dscp(lc);
1220 call->videostream=video_stream_new(call->video_port,call->video_port+1,linphone_core_ipv6_enabled(lc));
1222 video_stream_set_dscp(call->videostream,dscp);
1223 video_stream_enable_display_filter_auto_rotate(call->videostream, lp_config_get_int(lc->config,"video","display_filter_auto_rotate",0));
1224 if (video_recv_buf_size>0) rtp_session_set_recv_buf_size(call->videostream->ms.session,video_recv_buf_size);
1226 if( lc->video_conf.displaytype != NULL)
1227 video_stream_set_display_filter_name(call->videostream,lc->video_conf.displaytype);
1228 video_stream_set_event_callback(call->videostream,video_stream_event_cb, call);
1230 RtpTransport *vrtp=lc->rtptf->video_rtp_func(lc->rtptf->video_rtp_func_data, call->video_port);
1231 RtpTransport *vrtcp=lc->rtptf->video_rtcp_func(lc->rtptf->video_rtcp_func_data, call->video_port+1);
1232 rtp_session_set_transports(call->videostream->ms.session,vrtp,vrtcp);
1234 if ((linphone_core_get_firewall_policy(lc) == LinphonePolicyUseIce) && (call->ice_session != NULL)){
1235 rtp_session_set_pktinfo(call->videostream->ms.session, TRUE);
1236 rtp_session_set_symmetric_rtp(call->videostream->ms.session, FALSE);
1237 if (ice_session_check_list(call->ice_session, 1) == NULL) {
1238 ice_session_add_check_list(call->ice_session, ice_check_list_new());
1240 call->videostream->ms.ice_check_list = ice_session_check_list(call->ice_session, 1);
1241 ice_check_list_set_rtp_session(call->videostream->ms.ice_check_list, call->videostream->ms.session);
1243 call->videostream_app_evq = ortp_ev_queue_new();
1244 rtp_session_register_event_queue(call->videostream->ms.session,call->videostream_app_evq);
1245 #ifdef TEST_EXT_RENDERER
1246 video_stream_set_render_callback(call->videostream,rendercb,NULL);
1250 call->videostream=NULL;
1254 void linphone_call_init_media_streams(LinphoneCall *call){
1255 linphone_call_init_audio_stream(call);
1256 linphone_call_init_video_stream(call);
1260 static int dtmf_tab[16]={'0','1','2','3','4','5','6','7','8','9','*','#','A','B','C','D'};
1262 static void linphone_core_dtmf_received(LinphoneCore *lc, int dtmf){
1263 if (dtmf<0 || dtmf>15){
1264 ms_warning("Bad dtmf value %i",dtmf);
1267 if (lc->vtable.dtmf_received != NULL)
1268 lc->vtable.dtmf_received(lc, linphone_core_get_current_call(lc), dtmf_tab[dtmf]);
1271 static void parametrize_equalizer(LinphoneCore *lc, AudioStream *st){
1273 MSFilter *f=st->equalizer;
1274 int enabled=lp_config_get_int(lc->config,"sound","eq_active",0);
1275 const char *gains=lp_config_get_string(lc->config,"sound","eq_gains",NULL);
1276 ms_filter_call_method(f,MS_EQUALIZER_SET_ACTIVE,&enabled);
1282 if (sscanf(gains,"%f:%f:%f %n",&g.frequency,&g.gain,&g.width,&bytes)==3){
1283 ms_message("Read equalizer gains: %f(~%f) --> %f",g.frequency,g.width,g.gain);
1284 ms_filter_call_method(f,MS_EQUALIZER_SET_GAIN,&g);
1293 void _post_configure_audio_stream(AudioStream *st, LinphoneCore *lc, bool_t muted){
1294 float mic_gain=lc->sound_conf.soft_mic_lev;
1297 float ng_thres=lp_config_get_float(lc->config,"sound","ng_thres",0.05);
1298 float ng_floorgain=lp_config_get_float(lc->config,"sound","ng_floorgain",0);
1299 int dc_removal=lp_config_get_int(lc->config,"sound","dc_removal",0);
1302 linphone_core_set_mic_gain_db (lc, mic_gain);
1304 audio_stream_set_mic_gain(st,0);
1306 recv_gain = lc->sound_conf.soft_play_lev;
1307 if (recv_gain != 0) {
1308 linphone_core_set_playback_gain_db (lc,recv_gain);
1312 ms_filter_call_method(st->volsend,MS_VOLUME_REMOVE_DC,&dc_removal);
1313 float speed=lp_config_get_float(lc->config,"sound","el_speed",-1);
1314 thres=lp_config_get_float(lc->config,"sound","el_thres",-1);
1315 float force=lp_config_get_float(lc->config,"sound","el_force",-1);
1316 int sustain=lp_config_get_int(lc->config,"sound","el_sustain",-1);
1317 float transmit_thres=lp_config_get_float(lc->config,"sound","el_transmit_thres",-1);
1320 if (speed==-1) speed=0.03;
1321 if (force==-1) force=25;
1322 ms_filter_call_method(f,MS_VOLUME_SET_EA_SPEED,&speed);
1323 ms_filter_call_method(f,MS_VOLUME_SET_EA_FORCE,&force);
1325 ms_filter_call_method(f,MS_VOLUME_SET_EA_THRESHOLD,&thres);
1327 ms_filter_call_method(f,MS_VOLUME_SET_EA_SUSTAIN,&sustain);
1328 if (transmit_thres!=-1)
1329 ms_filter_call_method(f,MS_VOLUME_SET_EA_TRANSMIT_THRESHOLD,&transmit_thres);
1331 ms_filter_call_method(st->volsend,MS_VOLUME_SET_NOISE_GATE_THRESHOLD,&ng_thres);
1332 ms_filter_call_method(st->volsend,MS_VOLUME_SET_NOISE_GATE_FLOORGAIN,&ng_floorgain);
1335 /* parameters for a limited noise-gate effect, using echo limiter threshold */
1336 float floorgain = 1/pow(10,(mic_gain)/10);
1337 int spk_agc=lp_config_get_int(lc->config,"sound","speaker_agc_enabled",0);
1338 ms_filter_call_method(st->volrecv, MS_VOLUME_ENABLE_AGC, &spk_agc);
1339 ms_filter_call_method(st->volrecv,MS_VOLUME_SET_NOISE_GATE_THRESHOLD,&ng_thres);
1340 ms_filter_call_method(st->volrecv,MS_VOLUME_SET_NOISE_GATE_FLOORGAIN,&floorgain);
1342 parametrize_equalizer(lc,st);
1345 static void post_configure_audio_streams(LinphoneCall*call){
1346 AudioStream *st=call->audiostream;
1347 LinphoneCore *lc=call->core;
1348 _post_configure_audio_stream(st,lc,call->audio_muted);
1349 if (lc->vtable.dtmf_received!=NULL){
1350 audio_stream_play_received_dtmfs(call->audiostream,FALSE);
1352 if (call->record_active)
1353 linphone_call_start_recording(call);
1356 static RtpProfile *make_profile(LinphoneCall *call, const SalMediaDescription *md, const SalStreamDescription *desc, int *used_pt){
1359 RtpProfile *prof=rtp_profile_new("Call profile");
1362 LinphoneCore *lc=call->core;
1364 const LinphoneCallParams *params=&call->params;
1367 for(elem=desc->payloads;elem!=NULL;elem=elem->next){
1368 PayloadType *pt=(PayloadType*)elem->data;
1371 if ((pt->flags & PAYLOAD_TYPE_FLAG_CAN_SEND) && first) {
1372 if (desc->type==SalAudio){
1373 linphone_core_update_allocated_audio_bandwidth_in_call(call,pt);
1374 if (params->up_ptime)
1375 up_ptime=params->up_ptime;
1376 else up_ptime=linphone_core_get_upload_ptime(lc);
1378 *used_pt=payload_type_get_number(pt);
1381 if (desc->bandwidth>0) remote_bw=desc->bandwidth;
1382 else if (md->bandwidth>0) {
1383 /*case where b=AS is given globally, not per stream*/
1384 remote_bw=md->bandwidth;
1385 if (desc->type==SalVideo){
1386 remote_bw=get_video_bandwidth(remote_bw,call->audio_bw);
1390 if (desc->type==SalAudio){
1391 int audio_bw=call->audio_bw;
1393 if (params->up_bw< audio_bw)
1394 audio_bw=params->up_bw;
1396 bw=get_min_bandwidth(audio_bw,remote_bw);
1397 }else bw=get_min_bandwidth(get_video_bandwidth(linphone_core_get_upload_bandwidth (lc),call->audio_bw),remote_bw);
1398 if (bw>0) pt->normal_bitrate=bw*1000;
1399 else if (desc->type==SalAudio){
1400 pt->normal_bitrate=-1;
1403 up_ptime=desc->ptime;
1407 snprintf(tmp,sizeof(tmp),"ptime=%i",up_ptime);
1408 payload_type_append_send_fmtp(pt,tmp);
1410 number=payload_type_get_number(pt);
1411 if (rtp_profile_get_payload(prof,number)!=NULL){
1412 ms_warning("A payload type with number %i already exists in profile !",number);
1414 rtp_profile_set_payload(prof,number,pt);
1420 static void setup_ring_player(LinphoneCore *lc, LinphoneCall *call){
1421 int pause_time=3000;
1422 audio_stream_play(call->audiostream,lc->sound_conf.ringback_tone);
1423 ms_filter_call_method(call->audiostream->soundread,MS_FILE_PLAYER_LOOP,&pause_time);
1426 static bool_t linphone_call_sound_resources_available(LinphoneCall *call){
1427 LinphoneCore *lc=call->core;
1428 LinphoneCall *current=linphone_core_get_current_call(lc);
1429 return !linphone_core_is_in_conference(lc) &&
1430 (current==NULL || current==call);
1432 static int find_crypto_index_from_tag(const SalSrtpCryptoAlgo crypto[],unsigned char tag) {
1434 for(i=0; i<SAL_CRYPTO_ALGO_MAX; i++) {
1435 if (crypto[i].tag == tag) {
1441 static void linphone_call_start_audio_stream(LinphoneCall *call, const char *cname, bool_t muted, bool_t send_ringbacktone, bool_t use_arc){
1442 LinphoneCore *lc=call->core;
1444 char rtcp_tool[128]={0};
1445 snprintf(rtcp_tool,sizeof(rtcp_tool)-1,"%s-%s",linphone_core_get_user_agent_name(),linphone_core_get_user_agent_version());
1446 /* look for savp stream first */
1447 const SalStreamDescription *stream=sal_media_description_find_stream(call->resultdesc,
1448 SalProtoRtpSavp,SalAudio);
1449 /* no savp audio stream, use avp */
1451 stream=sal_media_description_find_stream(call->resultdesc,
1452 SalProtoRtpAvp,SalAudio);
1454 if (stream && stream->dir!=SalStreamInactive && stream->rtp_port!=0){
1455 MSSndCard *playcard=lc->sound_conf.lsd_card ?
1456 lc->sound_conf.lsd_card : lc->sound_conf.play_sndcard;
1457 MSSndCard *captcard=lc->sound_conf.capt_sndcard;
1458 const char *playfile=lc->play_file;
1459 const char *recfile=lc->rec_file;
1460 call->audio_profile=make_profile(call,call->resultdesc,stream,&used_pt);
1464 call->current_params.audio_codec = rtp_profile_get_payload(call->audio_profile, used_pt);
1465 if (playcard==NULL) {
1466 ms_warning("No card defined for playback !");
1468 if (captcard==NULL) {
1469 ms_warning("No card defined for capture !");
1471 /*Replace soundcard filters by inactive file players or recorders
1472 when placed in recvonly or sendonly mode*/
1473 if (stream->rtp_port==0 || stream->dir==SalStreamRecvOnly){
1476 }else if (stream->dir==SalStreamSendOnly){
1480 /*And we will eventually play "playfile" if set by the user*/
1483 if (send_ringbacktone){
1485 playfile=NULL;/* it is setup later*/
1487 /*if playfile are supplied don't use soundcards*/
1488 if (lc->use_files) {
1492 if (call->params.in_conference){
1493 /* first create the graph without soundcard resources*/
1494 captcard=playcard=NULL;
1496 if (!linphone_call_sound_resources_available(call)){
1497 ms_message("Sound resources are used by another call, not using soundcard.");
1498 captcard=playcard=NULL;
1500 use_ec=captcard==NULL ? FALSE : linphone_core_echo_cancellation_enabled(lc);
1501 if (playcard && stream->max_rate>0) ms_snd_card_set_preferred_sample_rate(playcard, stream->max_rate);
1502 if (captcard && stream->max_rate>0) ms_snd_card_set_preferred_sample_rate(captcard, stream->max_rate);
1503 audio_stream_enable_adaptive_bitrate_control(call->audiostream,use_arc);
1504 audio_stream_enable_adaptive_jittcomp(call->audiostream, linphone_core_audio_adaptive_jittcomp_enabled(lc));
1505 if (!call->params.in_conference && call->params.record_file)
1506 audio_stream_mixed_record_open(call->audiostream,call->params.record_file);
1507 audio_stream_start_full(
1509 call->audio_profile,
1510 stream->rtp_addr[0]!='\0' ? stream->rtp_addr : call->resultdesc->addr,
1512 stream->rtcp_addr[0]!='\0' ? stream->rtcp_addr : call->resultdesc->addr,
1513 linphone_core_rtcp_enabled(lc) ? (stream->rtcp_port) : 0,
1515 linphone_core_get_audio_jittcomp(lc),
1522 post_configure_audio_streams(call);
1523 if (muted && !send_ringbacktone){
1524 audio_stream_set_mic_gain(call->audiostream,0);
1526 if (stream->dir==SalStreamSendOnly && playfile!=NULL){
1528 ms_filter_call_method(call->audiostream->soundread,MS_FILE_PLAYER_LOOP,&pause_time);
1530 if (send_ringbacktone){
1531 setup_ring_player(lc,call);
1533 audio_stream_set_rtcp_information(call->audiostream, cname, rtcp_tool);
1535 /* valid local tags are > 0 */
1536 if (stream->proto == SalProtoRtpSavp) {
1537 const SalStreamDescription *local_st_desc=sal_media_description_find_stream(call->localdesc,
1538 SalProtoRtpSavp,SalAudio);
1539 int crypto_idx = find_crypto_index_from_tag(local_st_desc->crypto, stream->crypto_local_tag);
1541 if (crypto_idx >= 0) {
1542 audio_stream_enable_srtp(
1544 stream->crypto[0].algo,
1545 local_st_desc->crypto[crypto_idx].master_key,
1546 stream->crypto[0].master_key);
1547 call->audiostream_encrypted=TRUE;
1549 ms_warning("Failed to find local crypto algo with tag: %d", stream->crypto_local_tag);
1550 call->audiostream_encrypted=FALSE;
1552 }else call->audiostream_encrypted=FALSE;
1553 if (call->params.in_conference){
1554 /*transform the graph to connect it to the conference filter */
1555 bool_t mute=stream->dir==SalStreamRecvOnly;
1556 linphone_call_add_to_conf(call, mute);
1558 call->current_params.in_conference=call->params.in_conference;
1559 call->current_params.low_bandwidth=call->params.low_bandwidth;
1560 }else ms_warning("No audio stream accepted ?");
1564 static void linphone_call_start_video_stream(LinphoneCall *call, const char *cname,bool_t all_inputs_muted){
1565 #ifdef VIDEO_ENABLED
1566 LinphoneCore *lc=call->core;
1568 /* look for savp stream first */
1569 const SalStreamDescription *vstream=sal_media_description_find_stream(call->resultdesc,
1570 SalProtoRtpSavp,SalVideo);
1571 char rtcp_tool[128]={0};
1572 snprintf(rtcp_tool,sizeof(rtcp_tool)-1,"%s-%s",linphone_core_get_user_agent_name(),linphone_core_get_user_agent_version());
1574 /* no savp audio stream, use avp */
1576 vstream=sal_media_description_find_stream(call->resultdesc,
1577 SalProtoRtpAvp,SalVideo);
1579 /* shutdown preview */
1580 if (lc->previewstream!=NULL) {
1581 video_preview_stop(lc->previewstream);
1582 lc->previewstream=NULL;
1585 if (vstream!=NULL && vstream->dir!=SalStreamInactive && vstream->rtp_port!=0) {
1586 const char *rtp_addr=vstream->rtp_addr[0]!='\0' ? vstream->rtp_addr : call->resultdesc->addr;
1587 const char *rtcp_addr=vstream->rtcp_addr[0]!='\0' ? vstream->rtcp_addr : call->resultdesc->addr;
1588 call->video_profile=make_profile(call,call->resultdesc,vstream,&used_pt);
1590 call->current_params.video_codec = rtp_profile_get_payload(call->video_profile, used_pt);
1591 VideoStreamDir dir=VideoStreamSendRecv;
1592 MSWebCam *cam=lc->video_conf.device;
1593 bool_t is_inactive=FALSE;
1595 call->current_params.has_video=TRUE;
1597 video_stream_enable_adaptive_bitrate_control(call->videostream,
1598 linphone_core_adaptive_rate_control_enabled(lc));
1599 video_stream_enable_adaptive_jittcomp(call->videostream, linphone_core_video_adaptive_jittcomp_enabled(lc));
1600 video_stream_set_sent_video_size(call->videostream,linphone_core_get_preferred_video_size(lc));
1601 video_stream_enable_self_view(call->videostream,lc->video_conf.selfview);
1602 if (lc->video_window_id!=0)
1603 video_stream_set_native_window_id(call->videostream,lc->video_window_id);
1604 if (lc->preview_window_id!=0)
1605 video_stream_set_native_preview_window_id (call->videostream,lc->preview_window_id);
1606 video_stream_use_preview_video_window (call->videostream,lc->use_preview_window);
1608 if (vstream->dir==SalStreamSendOnly && lc->video_conf.capture ){
1609 cam=get_nowebcam_device();
1610 dir=VideoStreamSendOnly;
1611 }else if (vstream->dir==SalStreamRecvOnly && lc->video_conf.display ){
1612 dir=VideoStreamRecvOnly;
1613 }else if (vstream->dir==SalStreamSendRecv){
1614 if (lc->video_conf.display && lc->video_conf.capture)
1615 dir=VideoStreamSendRecv;
1616 else if (lc->video_conf.display)
1617 dir=VideoStreamRecvOnly;
1619 dir=VideoStreamSendOnly;
1621 ms_warning("video stream is inactive.");
1622 /*either inactive or incompatible with local capabilities*/
1625 if (call->camera_active==FALSE || all_inputs_muted){
1626 cam=get_nowebcam_device();
1629 call->log->video_enabled = TRUE;
1630 video_stream_set_direction (call->videostream, dir);
1631 ms_message("%s lc rotation:%d\n", __FUNCTION__, lc->device_rotation);
1632 video_stream_set_device_rotation(call->videostream, lc->device_rotation);
1633 video_stream_start(call->videostream,
1634 call->video_profile, rtp_addr, vstream->rtp_port,
1635 rtcp_addr, linphone_core_rtcp_enabled(lc) ? (vstream->rtcp_port) : 0,
1636 used_pt, linphone_core_get_video_jittcomp(lc), cam);
1637 video_stream_set_rtcp_information(call->videostream, cname,rtcp_tool);
1640 if (vstream->proto == SalProtoRtpSavp) {
1641 const SalStreamDescription *local_st_desc=sal_media_description_find_stream(call->localdesc,
1642 SalProtoRtpSavp,SalVideo);
1644 video_stream_enable_strp(
1646 vstream->crypto[0].algo,
1647 local_st_desc->crypto[0].master_key,
1648 vstream->crypto[0].master_key
1650 call->videostream_encrypted=TRUE;
1652 call->videostream_encrypted=FALSE;
1654 }else ms_warning("No video stream accepted.");
1656 ms_warning("No valid video stream defined.");
1661 void linphone_call_start_media_streams(LinphoneCall *call, bool_t all_inputs_muted, bool_t send_ringbacktone){
1662 LinphoneCore *lc=call->core;
1664 call->current_params.audio_codec = NULL;
1665 call->current_params.video_codec = NULL;
1667 LinphoneAddress *me=linphone_core_get_primary_contact_parsed(lc);
1669 bool_t use_arc=linphone_core_adaptive_rate_control_enabled(lc);
1670 #ifdef VIDEO_ENABLED
1671 const SalStreamDescription *vstream=sal_media_description_find_stream(call->resultdesc,
1672 SalProtoRtpAvp,SalVideo);
1675 if ((call->audiostream == NULL) && (call->videostream == NULL)) {
1676 ms_fatal("start_media_stream() called without prior init !");
1679 cname=linphone_address_as_string_uri_only(me);
1681 #if defined(VIDEO_ENABLED)
1682 if (vstream!=NULL && vstream->dir!=SalStreamInactive && vstream->payloads!=NULL){
1683 /*when video is used, do not make adaptive rate control on audio, it is stupid.*/
1687 if (call->audiostream!=NULL) {
1688 linphone_call_start_audio_stream(call,cname,all_inputs_muted,send_ringbacktone,use_arc);
1690 call->current_params.has_video=FALSE;
1691 if (call->videostream!=NULL) {
1692 linphone_call_start_video_stream(call,cname,all_inputs_muted);
1695 call->all_muted=all_inputs_muted;
1696 call->playing_ringbacktone=send_ringbacktone;
1697 call->up_bw=linphone_core_get_upload_bandwidth(lc);
1699 if (call->params.media_encryption==LinphoneMediaEncryptionZRTP) {
1700 OrtpZrtpParams params;
1701 /*will be set later when zrtp is activated*/
1702 call->current_params.media_encryption=LinphoneMediaEncryptionNone;
1704 params.zid_file=lc->zrtp_secrets_cache;
1705 audio_stream_enable_zrtp(call->audiostream,¶ms);
1706 }else if (call->params.media_encryption==LinphoneMediaEncryptionSRTP){
1707 call->current_params.media_encryption=linphone_call_are_all_streams_encrypted(call) ?
1708 LinphoneMediaEncryptionSRTP : LinphoneMediaEncryptionNone;
1711 /*also reflect the change if the "wished" params, in order to avoid to propose SAVP or video again
1712 * further in the call, for example during pause,resume, conferencing reINVITEs*/
1713 linphone_call_fix_call_parameters(call);
1714 if ((call->ice_session != NULL) && (ice_session_state(call->ice_session) != IS_Completed)) {
1715 ice_session_start_connectivity_checks(call->ice_session);
1721 linphone_address_destroy(me);
1724 void linphone_call_start_media_streams_for_ice_gathering(LinphoneCall *call){
1725 audio_stream_prepare_sound(call->audiostream, NULL, NULL);
1726 #ifdef VIDEO_ENABLED
1727 if (call->videostream) {
1728 video_stream_prepare_video(call->videostream);
1733 void linphone_call_stop_media_streams_for_ice_gathering(LinphoneCall *call){
1734 audio_stream_unprepare_sound(call->audiostream);
1735 #ifdef VIDEO_ENABLED
1736 if (call->videostream) {
1737 video_stream_unprepare_video(call->videostream);
1742 void linphone_call_update_crypto_parameters(LinphoneCall *call, SalMediaDescription *old_md, SalMediaDescription *new_md) {
1743 SalStreamDescription *old_stream;
1744 SalStreamDescription *new_stream;
1747 old_stream = sal_media_description_find_stream(old_md, SalProtoRtpSavp, SalAudio);
1748 new_stream = sal_media_description_find_stream(new_md, SalProtoRtpSavp, SalAudio);
1749 if (old_stream && new_stream) {
1750 const SalStreamDescription *local_st_desc = sal_media_description_find_stream(call->localdesc, SalProtoRtpSavp, SalAudio);
1751 if (local_st_desc) {
1752 int crypto_idx = find_crypto_index_from_tag(local_st_desc->crypto, new_stream->crypto_local_tag);
1753 if (crypto_idx >= 0) {
1754 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);
1755 call->audiostream_encrypted = TRUE;
1757 ms_warning("Failed to find local crypto algo with tag: %d", new_stream->crypto_local_tag);
1758 call->audiostream_encrypted = FALSE;
1760 for (i = 0; i < SAL_CRYPTO_ALGO_MAX; i++) {
1761 old_stream->crypto[i].tag = new_stream->crypto[i].tag;
1762 old_stream->crypto[i].algo = new_stream->crypto[i].algo;
1763 strncpy(old_stream->crypto[i].master_key, new_stream->crypto[i].master_key, sizeof(old_stream->crypto[i].master_key) - 1);
1768 #ifdef VIDEO_ENABLED
1769 old_stream = sal_media_description_find_stream(old_md, SalProtoRtpSavp, SalVideo);
1770 new_stream = sal_media_description_find_stream(new_md, SalProtoRtpSavp, SalVideo);
1771 if (old_stream && new_stream) {
1772 const SalStreamDescription *local_st_desc = sal_media_description_find_stream(call->localdesc, SalProtoRtpSavp, SalVideo);
1773 if (local_st_desc) {
1774 int crypto_idx = find_crypto_index_from_tag(local_st_desc->crypto, new_stream->crypto_local_tag);
1775 if (crypto_idx >= 0) {
1776 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);
1777 call->videostream_encrypted = TRUE;
1779 ms_warning("Failed to find local crypto algo with tag: %d", new_stream->crypto_local_tag);
1780 call->videostream_encrypted = FALSE;
1782 for (i = 0; i < SAL_CRYPTO_ALGO_MAX; i++) {
1783 old_stream->crypto[i].tag = new_stream->crypto[i].tag;
1784 old_stream->crypto[i].algo = new_stream->crypto[i].algo;
1785 strncpy(old_stream->crypto[i].master_key, new_stream->crypto[i].master_key, sizeof(old_stream->crypto[i].master_key) - 1);
1792 void linphone_call_update_remote_session_id_and_ver(LinphoneCall *call) {
1793 SalMediaDescription *remote_desc = sal_call_get_remote_media_description(call->op);
1795 call->remote_session_id = remote_desc->session_id;
1796 call->remote_session_ver = remote_desc->session_ver;
1800 void linphone_call_delete_ice_session(LinphoneCall *call){
1801 if (call->ice_session != NULL) {
1802 ice_session_destroy(call->ice_session);
1803 call->ice_session = NULL;
1804 if (call->audiostream != NULL) call->audiostream->ms.ice_check_list = NULL;
1805 if (call->videostream != NULL) call->videostream->ms.ice_check_list = NULL;
1806 call->stats[LINPHONE_CALL_STATS_AUDIO].ice_state = LinphoneIceStateNotActivated;
1807 call->stats[LINPHONE_CALL_STATS_VIDEO].ice_state = LinphoneIceStateNotActivated;
1812 void linphone_call_delete_upnp_session(LinphoneCall *call){
1813 if(call->upnp_session!=NULL) {
1814 linphone_upnp_session_destroy(call->upnp_session);
1815 call->upnp_session=NULL;
1820 static void linphone_call_log_fill_stats(LinphoneCallLog *log, AudioStream *st){
1821 audio_stream_get_local_rtp_stats (st,&log->local_stats);
1822 log->quality=audio_stream_get_average_quality_rating(st);
1825 void linphone_call_stop_audio_stream(LinphoneCall *call) {
1826 if (call->audiostream!=NULL) {
1827 rtp_session_unregister_event_queue(call->audiostream->ms.session,call->audiostream_app_evq);
1828 ortp_ev_queue_flush(call->audiostream_app_evq);
1829 ortp_ev_queue_destroy(call->audiostream_app_evq);
1830 call->audiostream_app_evq=NULL;
1832 if (call->audiostream->ec){
1833 const char *state_str=NULL;
1834 ms_filter_call_method(call->audiostream->ec,MS_ECHO_CANCELLER_GET_STATE_STRING,&state_str);
1836 ms_message("Writing echo canceler state, %i bytes",(int)strlen(state_str));
1837 lp_config_set_string(call->core->config,"sound","ec_state",state_str);
1840 linphone_call_log_fill_stats (call->log,call->audiostream);
1841 if (call->endpoint){
1842 linphone_call_remove_from_conf(call);
1844 audio_stream_stop(call->audiostream);
1845 call->audiostream=NULL;
1849 void linphone_call_stop_video_stream(LinphoneCall *call) {
1850 #ifdef VIDEO_ENABLED
1851 if (call->videostream!=NULL){
1852 rtp_session_unregister_event_queue(call->videostream->ms.session,call->videostream_app_evq);
1853 ortp_ev_queue_flush(call->videostream_app_evq);
1854 ortp_ev_queue_destroy(call->videostream_app_evq);
1855 call->videostream_app_evq=NULL;
1856 video_stream_stop(call->videostream);
1857 call->videostream=NULL;
1862 void linphone_call_stop_media_streams(LinphoneCall *call){
1863 linphone_call_stop_audio_stream(call);
1864 linphone_call_stop_video_stream(call);
1865 ms_event_queue_skip(call->core->msevq);
1867 if (call->audio_profile){
1868 rtp_profile_clear_all(call->audio_profile);
1869 rtp_profile_destroy(call->audio_profile);
1870 call->audio_profile=NULL;
1872 if (call->video_profile){
1873 rtp_profile_clear_all(call->video_profile);
1874 rtp_profile_destroy(call->video_profile);
1875 call->video_profile=NULL;
1881 void linphone_call_enable_echo_cancellation(LinphoneCall *call, bool_t enable) {
1882 if (call!=NULL && call->audiostream!=NULL && call->audiostream->ec){
1883 bool_t bypass_mode = !enable;
1884 ms_filter_call_method(call->audiostream->ec,MS_ECHO_CANCELLER_SET_BYPASS_MODE,&bypass_mode);
1887 bool_t linphone_call_echo_cancellation_enabled(LinphoneCall *call) {
1888 if (call!=NULL && call->audiostream!=NULL && call->audiostream->ec){
1890 ms_filter_call_method(call->audiostream->ec,MS_ECHO_CANCELLER_GET_BYPASS_MODE,&val);
1893 return linphone_core_echo_cancellation_enabled(call->core);
1897 void linphone_call_enable_echo_limiter(LinphoneCall *call, bool_t val){
1898 if (call!=NULL && call->audiostream!=NULL ) {
1900 const char *type=lp_config_get_string(call->core->config,"sound","el_type","mic");
1901 if (strcasecmp(type,"mic")==0)
1902 audio_stream_enable_echo_limiter(call->audiostream,ELControlMic);
1903 else if (strcasecmp(type,"full")==0)
1904 audio_stream_enable_echo_limiter(call->audiostream,ELControlFull);
1906 audio_stream_enable_echo_limiter(call->audiostream,ELInactive);
1911 bool_t linphone_call_echo_limiter_enabled(const LinphoneCall *call){
1912 if (call!=NULL && call->audiostream!=NULL ){
1913 return call->audiostream->el_type !=ELInactive ;
1915 return linphone_core_echo_limiter_enabled(call->core);
1920 * @addtogroup call_misc
1925 * Returns the measured sound volume played locally (received from remote).
1926 * It is expressed in dbm0.
1928 float linphone_call_get_play_volume(LinphoneCall *call){
1929 AudioStream *st=call->audiostream;
1930 if (st && st->volrecv){
1932 ms_filter_call_method(st->volrecv,MS_VOLUME_GET,&vol);
1936 return LINPHONE_VOLUME_DB_LOWEST;
1940 * Returns the measured sound volume recorded locally (sent to remote).
1941 * It is expressed in dbm0.
1943 float linphone_call_get_record_volume(LinphoneCall *call){
1944 AudioStream *st=call->audiostream;
1945 if (st && st->volsend && !call->audio_muted && call->state==LinphoneCallStreamsRunning){
1947 ms_filter_call_method(st->volsend,MS_VOLUME_GET,&vol);
1951 return LINPHONE_VOLUME_DB_LOWEST;
1955 * Obtain real-time quality rating of the call
1957 * Based on local RTP statistics and RTCP feedback, a quality rating is computed and updated
1958 * during all the duration of the call. This function returns its value at the time of the function call.
1959 * It is expected that the rating is updated at least every 5 seconds or so.
1960 * The rating is a floating point number comprised between 0 and 5.
1962 * 4-5 = good quality <br>
1963 * 3-4 = average quality <br>
1964 * 2-3 = poor quality <br>
1965 * 1-2 = very poor quality <br>
1966 * 0-1 = can't be worse, mostly unusable <br>
1968 * @returns The function returns -1 if no quality measurement is available, for example if no
1969 * active audio stream exist. Otherwise it returns the quality rating.
1971 float linphone_call_get_current_quality(LinphoneCall *call){
1972 if (call->audiostream){
1973 return audio_stream_get_quality_rating(call->audiostream);
1979 * Returns call quality averaged over all the duration of the call.
1981 * See linphone_call_get_current_quality() for more details about quality measurement.
1983 float linphone_call_get_average_quality(LinphoneCall *call){
1984 if (call->audiostream){
1985 return audio_stream_get_average_quality_rating(call->audiostream);
1991 * Access last known statistics for audio stream, for a given call.
1993 const LinphoneCallStats *linphone_call_get_audio_stats(const LinphoneCall *call) {
1994 return &call->stats[LINPHONE_CALL_STATS_AUDIO];
1998 * Access last known statistics for video stream, for a given call.
2000 const LinphoneCallStats *linphone_call_get_video_stats(const LinphoneCall *call) {
2001 return &call->stats[LINPHONE_CALL_STATS_VIDEO];
2005 * Enable recording of the call (voice-only).
2006 * This function must be used before the call parameters are assigned to the call.
2007 * The call recording can be started and paused after the call is established with
2008 * linphone_call_start_recording() and linphone_call_pause_recording().
2009 * @param cp the call parameters
2010 * @param path path and filename of the file where audio is written.
2012 void linphone_call_params_set_record_file(LinphoneCallParams *cp, const char *path){
2013 if (cp->record_file){
2014 ms_free(cp->record_file);
2015 cp->record_file=NULL;
2017 if (path) cp->record_file=ms_strdup(path);
2021 * Retrieves the path for the audio recoding of the call.
2023 const char *linphone_call_params_get_record_file(const LinphoneCallParams *cp){
2024 return cp->record_file;
2028 * Start call recording.
2029 * The output file where audio is recorded must be previously specified with linphone_call_params_set_record_file().
2031 void linphone_call_start_recording(LinphoneCall *call){
2032 if (!call->params.record_file){
2033 ms_error("linphone_call_start_recording(): no output file specified. Use linphone_call_params_set_record_file().");
2036 if (call->audiostream && !call->params.in_conference){
2037 audio_stream_mixed_record_start(call->audiostream);
2039 call->record_active=TRUE;
2043 * Stop call recording.
2045 void linphone_call_stop_recording(LinphoneCall *call){
2046 if (call->audiostream && !call->params.in_conference){
2047 audio_stream_mixed_record_stop(call->audiostream);
2049 call->record_active=FALSE;
2056 static void report_bandwidth(LinphoneCall *call, RtpSession *as, RtpSession *vs){
2057 call->stats[LINPHONE_CALL_STATS_AUDIO].download_bandwidth=(as!=NULL) ? (rtp_session_compute_recv_bandwidth(as)*1e-3) : 0;
2058 call->stats[LINPHONE_CALL_STATS_AUDIO].upload_bandwidth=(as!=NULL) ? (rtp_session_compute_send_bandwidth(as)*1e-3) : 0;
2059 call->stats[LINPHONE_CALL_STATS_VIDEO].download_bandwidth=(vs!=NULL) ? (rtp_session_compute_recv_bandwidth(vs)*1e-3) : 0;
2060 call->stats[LINPHONE_CALL_STATS_VIDEO].upload_bandwidth=(vs!=NULL) ? (rtp_session_compute_send_bandwidth(vs)*1e-3) : 0;
2061 ms_message("bandwidth usage: audio=[d=%.1f,u=%.1f] video=[d=%.1f,u=%.1f] kbit/sec",
2062 call->stats[LINPHONE_CALL_STATS_AUDIO].download_bandwidth,
2063 call->stats[LINPHONE_CALL_STATS_AUDIO].upload_bandwidth ,
2064 call->stats[LINPHONE_CALL_STATS_VIDEO].download_bandwidth,
2065 call->stats[LINPHONE_CALL_STATS_VIDEO].upload_bandwidth
2069 static void linphone_core_disconnected(LinphoneCore *lc, LinphoneCall *call){
2073 from = linphone_call_get_remote_address_as_string(call);
2076 snprintf(temp,sizeof(temp),"Remote end %s seems to have disconnected, the call is going to be closed.",from);
2081 snprintf(temp,sizeof(temp),"Remote end seems to have disconnected, the call is going to be closed.");
2083 if (lc->vtable.display_warning!=NULL)
2084 lc->vtable.display_warning(lc,temp);
2085 linphone_core_terminate_call(lc,call);
2088 static void handle_ice_events(LinphoneCall *call, OrtpEvent *ev){
2089 OrtpEventType evt=ortp_event_get_type(ev);
2090 OrtpEventData *evd=ortp_event_get_data(ev);
2093 if (evt == ORTP_EVENT_ICE_SESSION_PROCESSING_FINISHED) {
2094 switch (ice_session_state(call->ice_session)) {
2096 ice_session_select_candidates(call->ice_session);
2097 if (ice_session_role(call->ice_session) == IR_Controlling) {
2098 linphone_core_update_call(call->core, call, &call->current_params);
2102 if (ice_session_has_completed_check_list(call->ice_session) == TRUE) {
2103 ice_session_select_candidates(call->ice_session);
2104 if (ice_session_role(call->ice_session) == IR_Controlling) {
2105 /* At least one ICE session has succeeded, so perform a call update. */
2106 linphone_core_update_call(call->core, call, &call->current_params);
2113 linphone_core_update_ice_state_in_call_stats(call);
2114 } else if (evt == ORTP_EVENT_ICE_GATHERING_FINISHED) {
2116 if (evd->info.ice_processing_successful==TRUE) {
2117 ice_session_compute_candidates_foundations(call->ice_session);
2118 ice_session_eliminate_redundant_candidates(call->ice_session);
2119 ice_session_choose_default_candidates(call->ice_session);
2120 ping_time = ice_session_average_gathering_round_trip_time(call->ice_session);
2121 if (ping_time >=0) {
2122 call->ping_time=ping_time;
2125 ms_warning("No STUN answer from [%s], disabling ICE",linphone_core_get_stun_server(call->core));
2126 linphone_call_delete_ice_session(call);
2128 switch (call->state) {
2129 case LinphoneCallUpdating:
2130 linphone_core_start_update_call(call->core, call);
2132 case LinphoneCallUpdatedByRemote:
2133 linphone_core_start_accept_call_update(call->core, call);
2135 case LinphoneCallOutgoingInit:
2136 linphone_call_stop_media_streams_for_ice_gathering(call);
2137 linphone_core_proceed_with_invite_if_ready(call->core, call, NULL);
2139 case LinphoneCallIdle:
2140 linphone_call_stop_media_streams_for_ice_gathering(call);
2141 linphone_core_notify_incoming_call(call->core, call);
2146 } else if (evt == ORTP_EVENT_ICE_LOSING_PAIRS_COMPLETED) {
2147 linphone_core_start_accept_call_update(call->core, call);
2148 linphone_core_update_ice_state_in_call_stats(call);
2149 } else if (evt == ORTP_EVENT_ICE_RESTART_NEEDED) {
2150 ice_session_restart(call->ice_session);
2151 ice_session_set_role(call->ice_session, IR_Controlling);
2152 linphone_core_update_call(call->core, call, &call->current_params);
2156 void linphone_call_background_tasks(LinphoneCall *call, bool_t one_second_elapsed){
2157 LinphoneCore* lc = call->core;
2158 int disconnect_timeout = linphone_core_get_nortp_timeout(call->core);
2159 bool_t disconnected=FALSE;
2161 if (call->state==LinphoneCallStreamsRunning && one_second_elapsed){
2162 RtpSession *as=NULL,*vs=NULL;
2163 float audio_load=0, video_load=0;
2164 if (call->audiostream!=NULL){
2165 as=call->audiostream->ms.session;
2166 if (call->audiostream->ms.ticker)
2167 audio_load=ms_ticker_get_average_load(call->audiostream->ms.ticker);
2169 if (call->videostream!=NULL){
2170 if (call->videostream->ms.ticker)
2171 video_load=ms_ticker_get_average_load(call->videostream->ms.ticker);
2172 vs=call->videostream->ms.session;
2174 report_bandwidth(call,as,vs);
2175 ms_message("Thread processing load: audio=%f\tvideo=%f",audio_load,video_load);
2179 linphone_upnp_call_process(call);
2182 #ifdef VIDEO_ENABLED
2183 if (call->videostream!=NULL) {
2186 /* Ensure there is no dangling ICE check list. */
2187 if (call->ice_session == NULL) call->videostream->ms.ice_check_list = NULL;
2189 // Beware that the application queue should not depend on treatments fron the
2190 // mediastreamer queue.
2191 video_stream_iterate(call->videostream);
2193 while (call->videostream_app_evq && (NULL != (ev=ortp_ev_queue_get(call->videostream_app_evq)))){
2194 OrtpEventType evt=ortp_event_get_type(ev);
2195 OrtpEventData *evd=ortp_event_get_data(ev);
2196 if (evt == ORTP_EVENT_ZRTP_ENCRYPTION_CHANGED){
2197 linphone_call_videostream_encryption_changed(call, evd->info.zrtp_stream_encrypted);
2198 } else if (evt == ORTP_EVENT_RTCP_PACKET_RECEIVED) {
2199 call->stats[LINPHONE_CALL_STATS_VIDEO].round_trip_delay = rtp_session_get_round_trip_propagation(call->videostream->ms.session);
2200 if(call->stats[LINPHONE_CALL_STATS_VIDEO].received_rtcp != NULL)
2201 freemsg(call->stats[LINPHONE_CALL_STATS_VIDEO].received_rtcp);
2202 call->stats[LINPHONE_CALL_STATS_VIDEO].received_rtcp = evd->packet;
2204 if (lc->vtable.call_stats_updated)
2205 lc->vtable.call_stats_updated(lc, call, &call->stats[LINPHONE_CALL_STATS_VIDEO]);
2206 } else if (evt == ORTP_EVENT_RTCP_PACKET_EMITTED) {
2207 memcpy(&call->stats[LINPHONE_CALL_STATS_VIDEO].jitter_stats, rtp_session_get_jitter_stats(call->videostream->ms.session), sizeof(jitter_stats_t));
2208 if(call->stats[LINPHONE_CALL_STATS_VIDEO].sent_rtcp != NULL)
2209 freemsg(call->stats[LINPHONE_CALL_STATS_VIDEO].sent_rtcp);
2210 call->stats[LINPHONE_CALL_STATS_VIDEO].sent_rtcp = evd->packet;
2212 if (lc->vtable.call_stats_updated)
2213 lc->vtable.call_stats_updated(lc, call, &call->stats[LINPHONE_CALL_STATS_VIDEO]);
2214 } else if ((evt == ORTP_EVENT_ICE_SESSION_PROCESSING_FINISHED) || (evt == ORTP_EVENT_ICE_GATHERING_FINISHED)
2215 || (evt == ORTP_EVENT_ICE_LOSING_PAIRS_COMPLETED) || (evt == ORTP_EVENT_ICE_RESTART_NEEDED)) {
2216 handle_ice_events(call, ev);
2218 ortp_event_destroy(ev);
2222 if (call->audiostream!=NULL) {
2225 /* Ensure there is no dangling ICE check list. */
2226 if (call->ice_session == NULL) call->audiostream->ms.ice_check_list = NULL;
2228 // Beware that the application queue should not depend on treatments fron the
2229 // mediastreamer queue.
2230 audio_stream_iterate(call->audiostream);
2232 while (call->audiostream_app_evq && (NULL != (ev=ortp_ev_queue_get(call->audiostream_app_evq)))){
2233 OrtpEventType evt=ortp_event_get_type(ev);
2234 OrtpEventData *evd=ortp_event_get_data(ev);
2235 if (evt == ORTP_EVENT_ZRTP_ENCRYPTION_CHANGED){
2236 linphone_call_audiostream_encryption_changed(call, evd->info.zrtp_stream_encrypted);
2237 } else if (evt == ORTP_EVENT_ZRTP_SAS_READY) {
2238 linphone_call_audiostream_auth_token_ready(call, evd->info.zrtp_sas.sas, evd->info.zrtp_sas.verified);
2239 } else if (evt == ORTP_EVENT_RTCP_PACKET_RECEIVED) {
2240 call->stats[LINPHONE_CALL_STATS_AUDIO].round_trip_delay = rtp_session_get_round_trip_propagation(call->audiostream->ms.session);
2241 if(call->stats[LINPHONE_CALL_STATS_AUDIO].received_rtcp != NULL)
2242 freemsg(call->stats[LINPHONE_CALL_STATS_AUDIO].received_rtcp);
2243 call->stats[LINPHONE_CALL_STATS_AUDIO].received_rtcp = evd->packet;
2245 if (lc->vtable.call_stats_updated)
2246 lc->vtable.call_stats_updated(lc, call, &call->stats[LINPHONE_CALL_STATS_AUDIO]);
2247 } else if (evt == ORTP_EVENT_RTCP_PACKET_EMITTED) {
2248 memcpy(&call->stats[LINPHONE_CALL_STATS_AUDIO].jitter_stats, rtp_session_get_jitter_stats(call->audiostream->ms.session), sizeof(jitter_stats_t));
2249 if(call->stats[LINPHONE_CALL_STATS_AUDIO].sent_rtcp != NULL)
2250 freemsg(call->stats[LINPHONE_CALL_STATS_AUDIO].sent_rtcp);
2251 call->stats[LINPHONE_CALL_STATS_AUDIO].sent_rtcp = evd->packet;
2253 if (lc->vtable.call_stats_updated)
2254 lc->vtable.call_stats_updated(lc, call, &call->stats[LINPHONE_CALL_STATS_AUDIO]);
2255 } else if ((evt == ORTP_EVENT_ICE_SESSION_PROCESSING_FINISHED) || (evt == ORTP_EVENT_ICE_GATHERING_FINISHED)
2256 || (evt == ORTP_EVENT_ICE_LOSING_PAIRS_COMPLETED) || (evt == ORTP_EVENT_ICE_RESTART_NEEDED)) {
2257 handle_ice_events(call, ev);
2258 } else if (evt==ORTP_EVENT_TELEPHONE_EVENT){
2259 linphone_core_dtmf_received(lc,evd->info.telephone_event);
2261 ortp_event_destroy(ev);
2264 if (call->state==LinphoneCallStreamsRunning && one_second_elapsed && call->audiostream!=NULL && disconnect_timeout>0 )
2265 disconnected=!audio_stream_alive(call->audiostream,disconnect_timeout);
2267 linphone_core_disconnected(call->core,call);
2270 void linphone_call_log_completed(LinphoneCall *call){
2271 LinphoneCore *lc=call->core;
2273 call->log->duration=time(NULL)-call->start_time;
2275 if (call->log->status==LinphoneCallMissed){
2278 info=ortp_strdup_printf(ngettext("You have missed %i call.",
2279 "You have missed %i calls.", lc->missed_calls),
2281 if (lc->vtable.display_status!=NULL)
2282 lc->vtable.display_status(lc,info);
2285 lc->call_logs=ms_list_prepend(lc->call_logs,(void *)call->log);
2286 if (ms_list_size(lc->call_logs)>lc->max_call_logs){
2287 MSList *elem,*prevelem=NULL;
2288 /*find the last element*/
2289 for(elem=lc->call_logs;elem!=NULL;elem=elem->next){
2293 linphone_call_log_destroy((LinphoneCallLog*)elem->data);
2294 lc->call_logs=ms_list_remove_link(lc->call_logs,elem);
2296 if (lc->vtable.call_log_updated!=NULL){
2297 lc->vtable.call_log_updated(lc,call->log);
2299 call_logs_write_to_config_file(lc);
2302 LinphoneCallState linphone_call_get_transfer_state(LinphoneCall *call) {
2303 return call->transfer_state;
2306 void linphone_call_set_transfer_state(LinphoneCall* call, LinphoneCallState state) {
2307 if (state != call->transfer_state) {
2308 LinphoneCore* lc = call->core;
2309 call->transfer_state = state;
2310 if (lc->vtable.transfer_state_changed)
2311 lc->vtable.transfer_state_changed(lc, call, state);
2316 * Returns true if the call is part of the conference.
2317 * @ingroup conferencing
2319 bool_t linphone_call_is_in_conference(const LinphoneCall *call) {
2320 return call->params.in_conference;
2325 * Perform a zoom of the video displayed during a call.
2326 * @param call the call.
2327 * @param zoom_factor a floating point number describing the zoom factor. A value 1.0 corresponds to no zoom applied.
2328 * @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.
2329 * @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.
2331 * 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.
2333 void linphone_call_zoom_video(LinphoneCall* call, float zoom_factor, float* cx, float* cy) {
2334 VideoStream* vstream = call->videostream;
2335 if (vstream && vstream->output) {
2338 if (zoom_factor < 1)
2340 float halfsize = 0.5 * 1.0 / zoom_factor;
2342 if ((*cx - halfsize) < 0)
2344 if ((*cx + halfsize) > 1)
2346 if ((*cy - halfsize) < 0)
2348 if ((*cy + halfsize) > 1)
2351 zoom[0] = zoom_factor;
2354 ms_filter_call_method(vstream->output, MS_VIDEO_DISPLAY_ZOOM, &zoom);
2355 }else ms_warning("Could not apply zoom: video output wasn't activated.");