4 Copyright (C) 2010 Belledonne Communications SARL
5 (simon.morlat@linphone.org)
7 This program is free software; you can redistribute it and/or
8 modify it under the terms of the GNU General Public License
9 as published by the Free Software Foundation; either version 2
10 of the License, or (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24 #include "linphonecore.h"
28 #include <ortp/event.h>
32 #include "mediastreamer2/mediastream.h"
33 #include "mediastreamer2/msvolume.h"
34 #include "mediastreamer2/msequalizer.h"
35 #include "mediastreamer2/msfileplayer.h"
36 #include "mediastreamer2/msjpegwriter.h"
37 #include "mediastreamer2/mseventqueue.h"
38 #include "mediastreamer2/mssndcard.h"
41 static MSWebCam *get_nowebcam_device(){
42 return ms_web_cam_manager_get_cam(ms_web_cam_manager_get(),"StaticImage: Static picture");
46 static bool_t generate_b64_crypto_key(int key_length, char* key_out) {
48 uint8_t* tmp = (uint8_t*) malloc(key_length);
49 if (ortp_crypto_get_random(tmp, key_length)!=0) {
50 ms_error("Failed to generate random key");
55 b64_size = b64_encode((const char*)tmp, key_length, NULL, 0);
57 ms_error("Failed to b64 encode key");
61 key_out[b64_size] = '\0';
62 b64_encode((const char*)tmp, key_length, key_out, 40);
67 LinphoneCore *linphone_call_get_core(const LinphoneCall *call){
71 const char* linphone_call_get_authentication_token(LinphoneCall *call){
72 return call->auth_token;
75 bool_t linphone_call_get_authentication_token_verified(LinphoneCall *call){
76 return call->auth_token_verified;
79 static bool_t linphone_call_are_all_streams_encrypted(LinphoneCall *call) {
80 // Check ZRTP encryption in audiostream
81 if (!call->audiostream_encrypted) {
86 // If video enabled, check ZRTP encryption in videostream
87 const LinphoneCallParams *params=linphone_call_get_current_params(call);
88 if (params->has_video && !call->videostream_encrypted) {
96 void propagate_encryption_changed(LinphoneCall *call){
97 LinphoneCore *lc=call->core;
98 if (!linphone_call_are_all_streams_encrypted(call)) {
99 ms_message("Some streams are not encrypted");
100 call->current_params.media_encryption=LinphoneMediaEncryptionNone;
101 if (lc->vtable.call_encryption_changed)
102 lc->vtable.call_encryption_changed(call->core, call, FALSE, call->auth_token);
104 ms_message("All streams are encrypted");
105 call->current_params.media_encryption=LinphoneMediaEncryptionZRTP;
106 if (lc->vtable.call_encryption_changed)
107 lc->vtable.call_encryption_changed(call->core, call, TRUE, call->auth_token);
112 static void linphone_call_videostream_encryption_changed(void *data, bool_t encrypted){
113 ms_message("Video stream is %s", encrypted ? "encrypted" : "not encrypted");
115 LinphoneCall *call = (LinphoneCall *)data;
116 call->videostream_encrypted=encrypted;
117 propagate_encryption_changed(call);
121 static void linphone_call_audiostream_encryption_changed(void *data, bool_t encrypted) {
122 char status[255]={0};
123 ms_message("Audio stream is %s ", encrypted ? "encrypted" : "not encrypted");
125 LinphoneCall *call = (LinphoneCall *)data;
126 call->audiostream_encrypted=encrypted;
128 if (encrypted && call->core->vtable.display_status != NULL) {
129 snprintf(status,sizeof(status)-1,_("Authentication token is %s"),call->auth_token);
130 call->core->vtable.display_status(call->core, status);
133 propagate_encryption_changed(call);
137 // Enable video encryption
138 const LinphoneCallParams *params=linphone_call_get_current_params(call);
139 if (params->has_video) {
140 ms_message("Trying to enable encryption on video stream");
141 OrtpZrtpParams params;
142 params.zid_file=NULL; //unused
143 video_stream_enable_zrtp(call->videostream,call->audiostream,¶ms);
149 static void linphone_call_audiostream_auth_token_ready(void *data, const char* auth_token, bool_t verified) {
150 LinphoneCall *call=(LinphoneCall *)data;
151 if (call->auth_token != NULL)
152 ms_free(call->auth_token);
154 call->auth_token=ms_strdup(auth_token);
155 call->auth_token_verified=verified;
157 ms_message("Authentication token is %s (%s)", auth_token, verified?"verified":"unverified");
160 void linphone_call_set_authentication_token_verified(LinphoneCall *call, bool_t verified){
161 if (call->audiostream==NULL){
162 ms_error("linphone_call_set_authentication_token_verified(): No audio stream");
164 if (call->audiostream->ms.zrtp_context==NULL){
165 ms_error("linphone_call_set_authentication_token_verified(): No zrtp context.");
167 if (!call->auth_token_verified && verified){
168 ortp_zrtp_sas_verified(call->audiostream->ms.zrtp_context);
169 }else if (call->auth_token_verified && !verified){
170 ortp_zrtp_sas_reset_verified(call->audiostream->ms.zrtp_context);
172 call->auth_token_verified=verified;
173 propagate_encryption_changed(call);
176 static MSList *make_codec_list(LinphoneCore *lc, const MSList *codecs, int bandwidth_limit,int* max_sample_rate, int nb_codecs_limit){
180 if (max_sample_rate) *max_sample_rate=0;
181 for(it=codecs;it!=NULL;it=it->next){
182 PayloadType *pt=(PayloadType*)it->data;
183 if (pt->flags & PAYLOAD_TYPE_ENABLED){
184 if (bandwidth_limit>0 && !linphone_core_is_payload_type_usable_for_bandwidth(lc,pt,bandwidth_limit)){
185 ms_message("Codec %s/%i eliminated because of audio bandwidth constraint.",pt->mime_type,pt->clock_rate);
188 if (linphone_core_check_payload_type_usability(lc,pt)){
189 l=ms_list_append(l,payload_type_clone(pt));
191 if (max_sample_rate && payload_type_get_rate(pt)>*max_sample_rate) *max_sample_rate=payload_type_get_rate(pt);
194 if ((nb_codecs_limit > 0) && (nb >= nb_codecs_limit)) break;
199 static void update_media_description_from_stun(SalMediaDescription *md, const StunCandidate *ac, const StunCandidate *vc){
201 for (i = 0; i < md->n_active_streams; i++) {
202 if ((md->streams[i].type == SalAudio) && (ac->port != 0)) {
203 strcpy(md->streams[0].rtp_addr,ac->addr);
204 md->streams[0].rtp_port=ac->port;
205 if ((ac->addr[0]!='\0' && vc->addr[0]!='\0' && strcmp(ac->addr,vc->addr)==0) || md->n_active_streams==1){
206 strcpy(md->addr,ac->addr);
209 if ((md->streams[i].type == SalVideo) && (vc->port != 0)) {
210 strcpy(md->streams[1].rtp_addr,vc->addr);
211 md->streams[1].rtp_port=vc->port;
216 void linphone_call_make_local_media_description(LinphoneCore *lc, LinphoneCall *call){
219 SalMediaDescription *old_md=call->localdesc;
221 const char *me=linphone_core_get_identity(lc);
222 LinphoneAddress *addr=linphone_address_new(me);
223 const char *username=linphone_address_get_username (addr);
224 SalMediaDescription *md=sal_media_description_new();
225 bool_t keep_srtp_keys=lp_config_get_int(lc->config,"sip","keep_srtp_keys",0);
227 linphone_core_adapt_to_network(lc,call->ping_time,&call->params);
229 md->session_id=(old_md ? old_md->session_id : (rand() & 0xfff));
230 md->session_ver=(old_md ? (old_md->session_ver+1) : (rand() & 0xfff));
231 md->n_total_streams=(old_md ? old_md->n_total_streams : 1);
232 md->n_active_streams=1;
233 strncpy(md->addr,call->localip,sizeof(md->addr));
234 strncpy(md->username,username,sizeof(md->username));
236 if (call->params.down_bw)
237 md->bandwidth=call->params.down_bw;
238 else md->bandwidth=linphone_core_get_download_bandwidth(lc);
240 /*set audio capabilities */
241 strncpy(md->streams[0].rtp_addr,call->localip,sizeof(md->streams[0].rtp_addr));
242 strncpy(md->streams[0].rtcp_addr,call->localip,sizeof(md->streams[0].rtcp_addr));
243 md->streams[0].rtp_port=call->audio_port;
244 md->streams[0].rtcp_port=call->audio_port+1;
245 md->streams[0].proto=(call->params.media_encryption == LinphoneMediaEncryptionSRTP) ?
246 SalProtoRtpSavp : SalProtoRtpAvp;
247 md->streams[0].type=SalAudio;
248 if (call->params.down_ptime)
249 md->streams[0].ptime=call->params.down_ptime;
251 md->streams[0].ptime=linphone_core_get_download_ptime(lc);
252 l=make_codec_list(lc,lc->codecs_conf.audio_codecs,call->params.audio_bw,&md->streams[0].max_rate,-1);
253 pt=payload_type_clone(rtp_profile_get_payload_from_mime(lc->default_profile,"telephone-event"));
254 l=ms_list_append(l,pt);
255 md->streams[0].payloads=l;
257 if (call->params.has_video){
258 md->n_active_streams++;
259 md->streams[1].rtp_port=call->video_port;
260 md->streams[1].rtcp_port=call->video_port+1;
261 md->streams[1].proto=md->streams[0].proto;
262 md->streams[1].type=SalVideo;
263 l=make_codec_list(lc,lc->codecs_conf.video_codecs,0,NULL,-1);
264 md->streams[1].payloads=l;
266 if (md->n_total_streams < md->n_active_streams)
267 md->n_total_streams = md->n_active_streams;
269 /* Deactivate inactive streams. */
270 for (i = md->n_active_streams; i < md->n_total_streams; i++) {
271 md->streams[i].rtp_port = 0;
272 md->streams[i].rtcp_port = 0;
273 md->streams[i].proto = SalProtoRtpAvp;
274 md->streams[i].type = old_md->streams[i].type;
275 md->streams[i].dir = SalStreamInactive;
276 l = make_codec_list(lc, lc->codecs_conf.video_codecs, 0, NULL, 1);
277 md->streams[i].payloads = l;
280 for(i=0; i<md->n_active_streams; i++) {
281 if (md->streams[i].proto == SalProtoRtpSavp) {
282 if (keep_srtp_keys && old_md && old_md->streams[i].proto==SalProtoRtpSavp){
284 for(j=0;j<SAL_CRYPTO_ALGO_MAX;++j){
285 memcpy(&md->streams[i].crypto[j],&old_md->streams[i].crypto[j],sizeof(SalSrtpCryptoAlgo));
288 md->streams[i].crypto[0].tag = 1;
289 md->streams[i].crypto[0].algo = AES_128_SHA1_80;
290 if (!generate_b64_crypto_key(30, md->streams[i].crypto[0].master_key))
291 md->streams[i].crypto[0].algo = 0;
292 md->streams[i].crypto[1].tag = 2;
293 md->streams[i].crypto[1].algo = AES_128_SHA1_32;
294 if (!generate_b64_crypto_key(30, md->streams[i].crypto[1].master_key))
295 md->streams[i].crypto[1].algo = 0;
296 md->streams[i].crypto[2].algo = 0;
300 update_media_description_from_stun(md,&call->ac,&call->vc);
301 if (call->ice_session != NULL) {
302 linphone_core_update_local_media_description_from_ice(md, call->ice_session);
303 linphone_core_update_ice_state_in_call_stats(call);
306 if(call->upnp_session != NULL) {
307 linphone_core_update_local_media_description_from_upnp(md, call->upnp_session);
308 linphone_core_update_upnp_state_in_call_stats(call);
311 linphone_address_destroy(addr);
313 if (old_md) sal_media_description_unref(old_md);
316 static int find_port_offset(LinphoneCore *lc, SalStreamType type){
321 bool_t already_used=FALSE;
322 for(offset=0;offset<100;offset+=2){
326 tried_port=linphone_core_get_audio_port (lc)+offset;
329 tried_port=linphone_core_get_video_port (lc)+offset;
333 for(elem=lc->calls;elem!=NULL;elem=elem->next){
334 LinphoneCall *call=(LinphoneCall*)elem->data;
338 existing_port = call->audio_port;
341 existing_port = call->video_port;
344 if (existing_port==tried_port) {
349 if (!already_used) break;
352 ms_error("Could not find any free port !");
358 static int select_random_port(LinphoneCore *lc, SalStreamType type) {
362 int existing_port = 0;
363 int min_port = 0, max_port = 0;
364 bool_t already_used = FALSE;
369 linphone_core_get_audio_port_range(lc, &min_port, &max_port);
372 linphone_core_get_video_port_range(lc, &min_port, &max_port);
375 tried_port = (rand() % (max_port - min_port) + min_port) & ~0x1;
376 if (tried_port < min_port) tried_port = min_port + 2;
377 for (nb_tries = 0; nb_tries < 100; nb_tries++) {
378 for (elem = lc->calls; elem != NULL; elem = elem->next) {
379 LinphoneCall *call = (LinphoneCall *)elem->data;
383 existing_port = call->audio_port;
386 existing_port = call->video_port;
389 if (existing_port == tried_port) {
394 if (!already_used) break;
396 if (nb_tries == 100) {
397 ms_error("Could not find any free port!");
403 static void linphone_call_init_common(LinphoneCall *call, LinphoneAddress *from, LinphoneAddress *to){
405 int min_port, max_port;
406 call->magic=linphone_call_magic;
408 call->state=LinphoneCallIdle;
409 call->transfer_state = LinphoneCallIdle;
410 call->start_time=time(NULL);
411 call->media_start_time=0;
412 call->log=linphone_call_log_new(call, from, to);
413 call->owns_call_log=TRUE;
414 linphone_core_notify_all_friends(call->core,LinphoneStatusOnThePhone);
415 linphone_core_get_audio_port_range(call->core, &min_port, &max_port);
416 if (min_port == max_port) {
417 /* Used fixed RTP audio port. */
418 port_offset=find_port_offset (call->core, SalAudio);
419 if (port_offset==-1) return;
420 call->audio_port=linphone_core_get_audio_port(call->core)+port_offset;
422 /* Select random RTP audio port in the specified range. */
423 call->audio_port = select_random_port(call->core, SalAudio);
425 linphone_core_get_video_port_range(call->core, &min_port, &max_port);
426 if (min_port == max_port) {
427 /* Used fixed RTP video port. */
428 port_offset=find_port_offset (call->core, SalVideo);
429 if (port_offset==-1) return;
430 call->video_port=linphone_core_get_video_port(call->core)+port_offset;
432 /* Select random RTP video port in the specified range. */
433 call->video_port = select_random_port(call->core, SalVideo);
435 linphone_call_init_stats(&call->stats[LINPHONE_CALL_STATS_AUDIO], LINPHONE_CALL_STATS_AUDIO);
436 linphone_call_init_stats(&call->stats[LINPHONE_CALL_STATS_VIDEO], LINPHONE_CALL_STATS_VIDEO);
439 void linphone_call_init_stats(LinphoneCallStats *stats, int type) {
441 stats->received_rtcp = NULL;
442 stats->sent_rtcp = NULL;
443 stats->ice_state = LinphoneIceStateNotActivated;
445 stats->upnp_state = LinphoneUpnpStateIdle;
447 stats->upnp_state = LinphoneUpnpStateNotAvailable;
452 static void discover_mtu(LinphoneCore *lc, const char *remote){
454 if (lc->net_conf.mtu==0 ){
455 /*attempt to discover mtu*/
456 mtu=ms_discover_mtu(remote);
459 ms_message("Discovered mtu is %i, RTP payload max size is %i",
460 mtu, ms_get_payload_max_size());
465 LinphoneCall * linphone_call_new_outgoing(struct _LinphoneCore *lc, LinphoneAddress *from, LinphoneAddress *to, const LinphoneCallParams *params)
467 LinphoneCall *call=ms_new0(LinphoneCall,1);
468 call->dir=LinphoneCallOutgoing;
469 call->op=sal_op_new(lc->sal);
470 sal_op_set_user_pointer(call->op,call);
472 linphone_core_get_local_ip(lc,linphone_address_get_domain(to),call->localip);
473 linphone_call_init_common(call,from,to);
474 _linphone_call_params_copy(&call->params,params);
475 sal_op_set_custom_header(call->op,call->params.custom_headers);
476 call->params.custom_headers=NULL;
478 if (linphone_core_get_firewall_policy(call->core) == LinphonePolicyUseIce) {
479 call->ice_session = ice_session_new();
480 ice_session_set_role(call->ice_session, IR_Controlling);
482 if (linphone_core_get_firewall_policy(call->core) == LinphonePolicyUseStun) {
483 call->ping_time=linphone_core_run_stun_tests(call->core,call);
486 if (linphone_core_get_firewall_policy(call->core) == LinphonePolicyUseUpnp) {
487 call->upnp_session = linphone_upnp_session_new(call);
490 call->camera_active=params->has_video;
492 discover_mtu(lc,linphone_address_get_domain (to));
493 if (params->referer){
494 sal_call_set_referer(call->op,params->referer->op);
495 call->referer=linphone_call_ref(params->referer);
500 LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *from, LinphoneAddress *to, SalOp *op){
501 LinphoneCall *call=ms_new0(LinphoneCall,1);
503 const SalMediaDescription *md;
505 call->dir=LinphoneCallIncoming;
506 sal_op_set_user_pointer(op,call);
510 if (lc->sip_conf.ping_with_options){
511 /*the following sends an option request back to the caller so that
512 we get a chance to discover our nat'd address before answering.*/
513 call->ping_op=sal_op_new(lc->sal);
514 from_str=linphone_address_as_string_uri_only(from);
515 sal_op_set_route(call->ping_op,sal_op_get_network_origin(op));
516 sal_op_set_user_pointer(call->ping_op,call);
517 sal_ping(call->ping_op,linphone_core_find_best_identity(lc,from,NULL),from_str);
521 linphone_address_clean(from);
522 linphone_core_get_local_ip(lc,linphone_address_get_domain(from),call->localip);
523 linphone_call_init_common(call, from, to);
524 call->log->call_id=ms_strdup(sal_op_get_call_id(op)); /*must be known at that time*/
525 linphone_core_init_default_params(lc, &call->params);
526 md=sal_call_get_remote_media_description(op);
527 call->params.has_video &= !!lc->video_policy.automatically_accept;
529 // It is licit to receive an INVITE without SDP
530 // In this case WE chose the media parameters according to policy.
531 call->params.has_video &= linphone_core_media_description_contains_video_stream(md);
533 switch (linphone_core_get_firewall_policy(call->core)) {
534 case LinphonePolicyUseIce:
535 call->ice_session = ice_session_new();
536 ice_session_set_role(call->ice_session, IR_Controlled);
537 linphone_core_update_ice_from_remote_media_description(call, sal_call_get_remote_media_description(op));
538 if (call->ice_session != NULL) {
539 linphone_call_init_media_streams(call);
540 linphone_call_start_media_streams_for_ice_gathering(call);
541 if (linphone_core_gather_ice_candidates(call->core,call)<0) {
542 /* Ice candidates gathering failed, proceed with the call anyway. */
543 linphone_call_delete_ice_session(call);
544 linphone_call_stop_media_streams_for_ice_gathering(call);
548 case LinphonePolicyUseStun:
549 call->ping_time=linphone_core_run_stun_tests(call->core,call);
550 /* No break to also destroy ice session in this case. */
552 case LinphonePolicyUseUpnp:
554 call->upnp_session = linphone_upnp_session_new(call);
555 if (call->upnp_session != NULL) {
556 linphone_call_init_media_streams(call);
557 if (linphone_core_update_upnp_from_remote_media_description(call, sal_call_get_remote_media_description(op))<0) {
558 /* uPnP port mappings failed, proceed with the call anyway. */
559 linphone_call_delete_upnp_session(call);
567 call->camera_active=call->params.has_video;
569 discover_mtu(lc,linphone_address_get_domain(from));
573 /* this function is called internally to get rid of a call.
574 It performs the following tasks:
575 - remove the call from the internal list of calls
576 - update the call logs accordingly
579 static void linphone_call_set_terminated(LinphoneCall *call){
580 LinphoneCore *lc=call->core;
582 linphone_core_update_allocated_audio_bandwidth(lc);
584 call->owns_call_log=FALSE;
585 linphone_call_log_completed(call);
588 if (call == lc->current_call){
589 ms_message("Resetting the current call");
590 lc->current_call=NULL;
593 if (linphone_core_del_call(lc,call) != 0){
594 ms_error("Could not remove the call from the list !!!");
597 if (ms_list_size(lc->calls)==0)
598 linphone_core_notify_all_friends(lc,lc->presence_mode);
600 linphone_core_conference_check_uninit(lc);
601 if (call->ringing_beep){
602 linphone_core_stop_dtmf(lc);
603 call->ringing_beep=FALSE;
606 linphone_call_unref(call->referer);
611 void linphone_call_fix_call_parameters(LinphoneCall *call){
612 call->params.has_video=call->current_params.has_video;
613 call->params.media_encryption=call->current_params.media_encryption;
616 const char *linphone_call_state_to_string(LinphoneCallState cs){
618 case LinphoneCallIdle:
619 return "LinphoneCallIdle";
620 case LinphoneCallIncomingReceived:
621 return "LinphoneCallIncomingReceived";
622 case LinphoneCallOutgoingInit:
623 return "LinphoneCallOutgoingInit";
624 case LinphoneCallOutgoingProgress:
625 return "LinphoneCallOutgoingProgress";
626 case LinphoneCallOutgoingRinging:
627 return "LinphoneCallOutgoingRinging";
628 case LinphoneCallOutgoingEarlyMedia:
629 return "LinphoneCallOutgoingEarlyMedia";
630 case LinphoneCallConnected:
631 return "LinphoneCallConnected";
632 case LinphoneCallStreamsRunning:
633 return "LinphoneCallStreamsRunning";
634 case LinphoneCallPausing:
635 return "LinphoneCallPausing";
636 case LinphoneCallPaused:
637 return "LinphoneCallPaused";
638 case LinphoneCallResuming:
639 return "LinphoneCallResuming";
640 case LinphoneCallRefered:
641 return "LinphoneCallRefered";
642 case LinphoneCallError:
643 return "LinphoneCallError";
644 case LinphoneCallEnd:
645 return "LinphoneCallEnd";
646 case LinphoneCallPausedByRemote:
647 return "LinphoneCallPausedByRemote";
648 case LinphoneCallUpdatedByRemote:
649 return "LinphoneCallUpdatedByRemote";
650 case LinphoneCallIncomingEarlyMedia:
651 return "LinphoneCallIncomingEarlyMedia";
652 case LinphoneCallUpdating:
653 return "LinphoneCallUpdating";
654 case LinphoneCallReleased:
655 return "LinphoneCallReleased";
657 return "undefined state";
660 void linphone_call_set_state(LinphoneCall *call, LinphoneCallState cstate, const char *message){
661 LinphoneCore *lc=call->core;
663 if (call->state!=cstate){
664 if (call->state==LinphoneCallEnd || call->state==LinphoneCallError){
665 if (cstate!=LinphoneCallReleased){
666 ms_warning("Spurious call state change from %s to %s, ignored.",linphone_call_state_to_string(call->state),
667 linphone_call_state_to_string(cstate));
671 ms_message("Call %p: moving from state %s to %s",call,linphone_call_state_to_string(call->state),
672 linphone_call_state_to_string(cstate));
673 if (cstate!=LinphoneCallRefered){
674 /*LinphoneCallRefered is rather an event, not a state.
675 Indeed it does not change the state of the call (still paused or running)*/
678 if (cstate==LinphoneCallEnd || cstate==LinphoneCallError){
679 switch(call->reason){
680 case LinphoneReasonDeclined:
681 call->log->status=LinphoneCallDeclined;
683 case LinphoneReasonNotAnswered:
684 call->log->status=LinphoneCallMissed;
689 linphone_call_set_terminated (call);
691 if (cstate == LinphoneCallConnected) {
692 call->log->status=LinphoneCallSuccess;
693 call->media_start_time=time(NULL);
696 if (lc->vtable.call_state_changed)
697 lc->vtable.call_state_changed(lc,call,cstate,message);
698 if (cstate==LinphoneCallReleased){
699 if (call->op!=NULL) {
700 /* so that we cannot have anymore upcalls for SAL
701 concerning this call*/
702 sal_op_release(call->op);
705 linphone_call_unref(call);
710 static void linphone_call_destroy(LinphoneCall *obj)
713 linphone_call_delete_upnp_session(obj);
715 linphone_call_delete_ice_session(obj);
717 sal_op_release(obj->op);
720 if (obj->resultdesc!=NULL) {
721 sal_media_description_unref(obj->resultdesc);
722 obj->resultdesc=NULL;
724 if (obj->localdesc!=NULL) {
725 sal_media_description_unref(obj->localdesc);
729 sal_op_release(obj->ping_op);
732 ms_free(obj->refer_to);
734 if (obj->owns_call_log)
735 linphone_call_log_destroy(obj->log);
736 if (obj->auth_token) {
737 ms_free(obj->auth_token);
739 linphone_call_params_uninit(&obj->params);
744 * @addtogroup call_control
749 * Increments the call 's reference count.
750 * An application that wishes to retain a pointer to call object
751 * must use this function to unsure the pointer remains
752 * valid. Once the application no more needs this pointer,
753 * it must call linphone_call_unref().
755 LinphoneCall * linphone_call_ref(LinphoneCall *obj){
761 * Decrements the call object reference count.
762 * See linphone_call_ref().
764 void linphone_call_unref(LinphoneCall *obj){
767 linphone_call_destroy(obj);
772 * Returns current parameters associated to the call.
774 const LinphoneCallParams * linphone_call_get_current_params(LinphoneCall *call){
775 if (call->params.record_file)
776 call->current_params.record_file=call->params.record_file;
777 return &call->current_params;
780 static bool_t is_video_active(const SalStreamDescription *sd){
781 return sd->rtp_port!=0 && sd->dir!=SalStreamInactive;
785 * Returns call parameters proposed by remote.
787 * This is useful when receiving an incoming call, to know whether the remote party
788 * supports video, encryption or whatever.
790 const LinphoneCallParams * linphone_call_get_remote_params(LinphoneCall *call){
791 LinphoneCallParams *cp=&call->remote_params;
792 memset(cp,0,sizeof(*cp));
794 SalMediaDescription *md=sal_call_get_remote_media_description(call->op);
796 SalStreamDescription *asd,*vsd,*secure_asd,*secure_vsd;
798 asd=sal_media_description_find_stream(md,SalProtoRtpAvp,SalAudio);
799 vsd=sal_media_description_find_stream(md,SalProtoRtpAvp,SalVideo);
800 secure_asd=sal_media_description_find_stream(md,SalProtoRtpSavp,SalAudio);
801 secure_vsd=sal_media_description_find_stream(md,SalProtoRtpSavp,SalVideo);
803 cp->has_video=is_video_active(secure_vsd);
804 if (secure_asd || asd==NULL)
805 cp->media_encryption=LinphoneMediaEncryptionSRTP;
807 cp->has_video=is_video_active(vsd);
810 if (md->bandwidth>0 && md->bandwidth<=linphone_core_get_edge_bw(call->core)){
811 cp->low_bandwidth=TRUE;
814 cp->custom_headers=(SalCustomHeader*)sal_op_get_custom_header(call->op);
822 * Returns the remote address associated to this call
825 const LinphoneAddress * linphone_call_get_remote_address(const LinphoneCall *call){
826 return call->dir==LinphoneCallIncoming ? call->log->from : call->log->to;
830 * Returns the remote address associated to this call as a string.
832 * The result string must be freed by user using ms_free().
834 char *linphone_call_get_remote_address_as_string(const LinphoneCall *call){
835 return linphone_address_as_string(linphone_call_get_remote_address(call));
839 * Retrieves the call's current state.
841 LinphoneCallState linphone_call_get_state(const LinphoneCall *call){
846 * Returns the reason for a call termination (either error or normal termination)
848 LinphoneReason linphone_call_get_reason(const LinphoneCall *call){
853 * Get the user_pointer in the LinphoneCall
855 * @ingroup call_control
857 * return user_pointer an opaque user pointer that can be retrieved at any time
859 void *linphone_call_get_user_pointer(LinphoneCall *call)
861 return call->user_pointer;
865 * Set the user_pointer in the LinphoneCall
867 * @ingroup call_control
869 * the user_pointer is an opaque user pointer that can be retrieved at any time in the LinphoneCall
871 void linphone_call_set_user_pointer(LinphoneCall *call, void *user_pointer)
873 call->user_pointer = user_pointer;
877 * Returns the call log associated to this call.
879 LinphoneCallLog *linphone_call_get_call_log(const LinphoneCall *call){
884 * Returns the refer-to uri (if the call was transfered).
886 const char *linphone_call_get_refer_to(const LinphoneCall *call){
887 return call->refer_to;
891 * Returns direction of the call (incoming or outgoing).
893 LinphoneCallDir linphone_call_get_dir(const LinphoneCall *call){
894 return call->log->dir;
898 * Returns the far end's user agent description string, if available.
900 const char *linphone_call_get_remote_user_agent(LinphoneCall *call){
902 return sal_op_get_remote_ua (call->op);
908 * Returns the far end's sip contact as a string, if available.
910 const char *linphone_call_get_remote_contact(LinphoneCall *call){
912 return sal_op_get_remote_contact(call->op);
918 * Returns true if this calls has received a transfer that has not been
920 * Pending transfers are executed when this call is being paused or closed,
921 * locally or by remote endpoint.
922 * If the call is already paused while receiving the transfer request, the
923 * transfer immediately occurs.
925 bool_t linphone_call_has_transfer_pending(const LinphoneCall *call){
926 return call->refer_pending;
930 * Returns call's duration in seconds.
932 int linphone_call_get_duration(const LinphoneCall *call){
933 if (call->media_start_time==0) return 0;
934 return time(NULL)-call->media_start_time;
938 * Returns the call object this call is replacing, if any.
939 * Call replacement can occur during call transfers.
940 * By default, the core automatically terminates the replaced call and accept the new one.
941 * This function allows the application to know whether a new incoming call is a one that replaces another one.
943 LinphoneCall *linphone_call_get_replaced_call(LinphoneCall *call){
944 SalOp *op=sal_call_get_replaces(call->op);
946 return (LinphoneCall*)sal_op_get_user_pointer(op);
952 * Indicate whether camera input should be sent to remote end.
954 void linphone_call_enable_camera (LinphoneCall *call, bool_t enable){
956 if (call->videostream!=NULL && call->videostream->ms.ticker!=NULL){
957 LinphoneCore *lc=call->core;
958 MSWebCam *nowebcam=get_nowebcam_device();
959 if (call->camera_active!=enable && lc->video_conf.device!=nowebcam){
960 video_stream_change_camera(call->videostream,
961 enable ? lc->video_conf.device : nowebcam);
964 call->camera_active=enable;
970 * Request remote side to send us a Video Fast Update.
972 void linphone_call_send_vfu_request(LinphoneCall *call)
974 if (LinphoneCallStreamsRunning == linphone_call_get_state(call))
975 sal_call_send_vfu_request(call->op);
981 * Take a photo of currently received video and write it into a jpeg file.
983 int linphone_call_take_video_snapshot(LinphoneCall *call, const char *file){
985 if (call->videostream!=NULL && call->videostream->jpegwriter!=NULL){
986 return ms_filter_call_method(call->videostream->jpegwriter,MS_JPEG_WRITER_TAKE_SNAPSHOT,(void*)file);
988 ms_warning("Cannot take snapshot: no currently running video stream on this call.");
995 * Returns TRUE if camera pictures are sent to the remote party.
997 bool_t linphone_call_camera_enabled (const LinphoneCall *call){
998 return call->camera_active;
1002 * Enable video stream.
1004 void linphone_call_params_enable_video(LinphoneCallParams *cp, bool_t enabled){
1005 cp->has_video=enabled;
1009 * Returns the audio codec used in the call, described as a PayloadType structure.
1011 const PayloadType* linphone_call_params_get_used_audio_codec(const LinphoneCallParams *cp) {
1012 return cp->audio_codec;
1017 * Returns the video codec used in the call, described as a PayloadType structure.
1019 const PayloadType* linphone_call_params_get_used_video_codec(const LinphoneCallParams *cp) {
1020 return cp->video_codec;
1024 * @ingroup call_control
1025 * Use to know if this call has been configured in low bandwidth mode.
1026 * This mode can be automatically discovered thanks to a stun server when activate_edge_workarounds=1 in section [net] of configuration file.
1027 * An application that would have reliable way to know network capacity may not use activate_edge_workarounds=1 but instead manually configure
1028 * low bandwidth mode with linphone_call_params_enable_low_bandwidth().
1029 * <br> When enabled, this param may transform a call request with video in audio only mode.
1030 * @return TRUE if low bandwidth has been configured/detected
1032 bool_t linphone_call_params_low_bandwidth_enabled(const LinphoneCallParams *cp) {
1033 return cp->low_bandwidth;
1037 * @ingroup call_control
1038 * Indicate low bandwith mode.
1039 * 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
1040 * 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
1041 * that it is achievable by the codec selected after SDP handshake. Video is automatically disabled.
1044 void linphone_call_params_enable_low_bandwidth(LinphoneCallParams *cp, bool_t enabled){
1045 cp->low_bandwidth=enabled;
1049 * Returns whether video is enabled.
1051 bool_t linphone_call_params_video_enabled(const LinphoneCallParams *cp){
1052 return cp->has_video;
1056 * Returns kind of media encryption selected for the call.
1058 enum LinphoneMediaEncryption linphone_call_params_get_media_encryption(const LinphoneCallParams *cp) {
1059 return cp->media_encryption;
1063 * Set requested media encryption for a call.
1065 void linphone_call_params_set_media_encryption(LinphoneCallParams *cp, enum LinphoneMediaEncryption e) {
1066 cp->media_encryption = e;
1071 * Enable sending of real early media (during outgoing calls).
1073 void linphone_call_params_enable_early_media_sending(LinphoneCallParams *cp, bool_t enabled){
1074 cp->real_early_media=enabled;
1078 * Indicates whether sending of early media was enabled.
1080 bool_t linphone_call_params_early_media_sending_enabled(const LinphoneCallParams *cp){
1081 return cp->real_early_media;
1085 * Returns true if the call is part of the locally managed conference.
1087 bool_t linphone_call_params_local_conference_mode(const LinphoneCallParams *cp){
1088 return cp->in_conference;
1092 * Refine bandwidth settings for this call by setting a bandwidth limit for audio streams.
1093 * As a consequence, codecs whose bitrates are not compatible with this limit won't be used.
1095 void linphone_call_params_set_audio_bandwidth_limit(LinphoneCallParams *cp, int bandwidth){
1096 cp->audio_bw=bandwidth;
1099 void linphone_call_params_add_custom_header(LinphoneCallParams *params, const char *header_name, const char *header_value){
1100 params->custom_headers=sal_custom_header_append(params->custom_headers,header_name,header_value);
1103 const char *linphone_call_params_get_custom_header(const LinphoneCallParams *params, const char *header_name){
1104 return sal_custom_header_find(params->custom_headers,header_name);
1107 void _linphone_call_params_copy(LinphoneCallParams *ncp, const LinphoneCallParams *cp){
1108 memcpy(ncp,cp,sizeof(LinphoneCallParams));
1109 if (cp->record_file) ncp->record_file=ms_strdup(cp->record_file);
1111 * The management of the custom headers is not optimal. We copy everything while ref counting would be more efficient.
1113 if (cp->custom_headers) ncp->custom_headers=sal_custom_header_clone(cp->custom_headers);
1117 * Copy existing LinphoneCallParams to a new LinphoneCallParams object.
1119 LinphoneCallParams * linphone_call_params_copy(const LinphoneCallParams *cp){
1120 LinphoneCallParams *ncp=ms_new0(LinphoneCallParams,1);
1121 _linphone_call_params_copy(ncp,cp);
1125 void linphone_call_params_uninit(LinphoneCallParams *p){
1126 if (p->record_file) ms_free(p->record_file);
1127 if (p->custom_headers) sal_custom_header_free(p->custom_headers);
1131 * Destroy LinphoneCallParams.
1133 void linphone_call_params_destroy(LinphoneCallParams *p){
1134 linphone_call_params_uninit(p);
1144 #ifdef TEST_EXT_RENDERER
1145 static void rendercb(void *data, const MSPicture *local, const MSPicture *remote){
1146 ms_message("rendercb, local buffer=%p, remote buffer=%p",
1147 local ? local->planes[0] : NULL, remote? remote->planes[0] : NULL);
1151 #ifdef VIDEO_ENABLED
1152 static void video_stream_event_cb(void *user_pointer, const MSFilter *f, const unsigned int event_id, const void *args){
1153 LinphoneCall* call = (LinphoneCall*) user_pointer;
1154 ms_warning("In linphonecall.c: video_stream_event_cb");
1156 case MS_VIDEO_DECODER_DECODING_ERRORS:
1157 ms_warning("Case is MS_VIDEO_DECODER_DECODING_ERRORS");
1158 linphone_call_send_vfu_request(call);
1160 case MS_VIDEO_DECODER_FIRST_IMAGE_DECODED:
1161 ms_message("First video frame decoded successfully");
1162 if (call->nextVideoFrameDecoded._func != NULL)
1163 call->nextVideoFrameDecoded._func(call, call->nextVideoFrameDecoded._user_data);
1166 ms_warning("Unhandled event %i", event_id);
1172 void linphone_call_set_next_video_frame_decoded_callback(LinphoneCall *call, LinphoneCallCbFunc cb, void* user_data) {
1173 call->nextVideoFrameDecoded._func = cb;
1174 call->nextVideoFrameDecoded._user_data = user_data;
1175 #ifdef VIDEO_ENABLED
1176 ms_filter_call_method_noarg(call->videostream->ms.decoder, MS_VIDEO_DECODER_RESET_FIRST_IMAGE_NOTIFICATION);
1180 void linphone_call_init_audio_stream(LinphoneCall *call){
1181 LinphoneCore *lc=call->core;
1182 AudioStream *audiostream;
1185 if (call->audiostream != NULL) return;
1186 call->audiostream=audiostream=audio_stream_new(call->audio_port,call->audio_port+1,linphone_core_ipv6_enabled(lc));
1187 dscp=linphone_core_get_audio_dscp(lc);
1189 audio_stream_set_dscp(audiostream,dscp);
1190 if (linphone_core_echo_limiter_enabled(lc)){
1191 const char *type=lp_config_get_string(lc->config,"sound","el_type","mic");
1192 if (strcasecmp(type,"mic")==0)
1193 audio_stream_enable_echo_limiter(audiostream,ELControlMic);
1194 else if (strcasecmp(type,"full")==0)
1195 audio_stream_enable_echo_limiter(audiostream,ELControlFull);
1197 audio_stream_enable_gain_control(audiostream,TRUE);
1198 if (linphone_core_echo_cancellation_enabled(lc)){
1199 int len,delay,framesize;
1200 const char *statestr=lp_config_get_string(lc->config,"sound","ec_state",NULL);
1201 len=lp_config_get_int(lc->config,"sound","ec_tail_len",0);
1202 delay=lp_config_get_int(lc->config,"sound","ec_delay",0);
1203 framesize=lp_config_get_int(lc->config,"sound","ec_framesize",0);
1204 audio_stream_set_echo_canceller_params(audiostream,len,delay,framesize);
1205 if (statestr && audiostream->ec){
1206 ms_filter_call_method(audiostream->ec,MS_ECHO_CANCELLER_SET_STATE_STRING,(void*)statestr);
1209 audio_stream_enable_automatic_gain_control(audiostream,linphone_core_agc_enabled(lc));
1211 int enabled=lp_config_get_int(lc->config,"sound","noisegate",0);
1212 audio_stream_enable_noise_gate(audiostream,enabled);
1215 audio_stream_set_features(audiostream,linphone_core_get_audio_features(lc));
1218 RtpTransport *artp=lc->rtptf->audio_rtp_func(lc->rtptf->audio_rtp_func_data, call->audio_port);
1219 RtpTransport *artcp=lc->rtptf->audio_rtcp_func(lc->rtptf->audio_rtcp_func_data, call->audio_port+1);
1220 rtp_session_set_transports(audiostream->ms.session,artp,artcp);
1222 if ((linphone_core_get_firewall_policy(lc) == LinphonePolicyUseIce) && (call->ice_session != NULL)){
1223 rtp_session_set_pktinfo(audiostream->ms.session, TRUE);
1224 rtp_session_set_symmetric_rtp(audiostream->ms.session, FALSE);
1225 if (ice_session_check_list(call->ice_session, 0) == NULL) {
1226 ice_session_add_check_list(call->ice_session, ice_check_list_new());
1228 audiostream->ms.ice_check_list = ice_session_check_list(call->ice_session, 0);
1229 ice_check_list_set_rtp_session(audiostream->ms.ice_check_list, audiostream->ms.session);
1232 call->audiostream_app_evq = ortp_ev_queue_new();
1233 rtp_session_register_event_queue(audiostream->ms.session,call->audiostream_app_evq);
1236 void linphone_call_init_video_stream(LinphoneCall *call){
1237 #ifdef VIDEO_ENABLED
1238 LinphoneCore *lc=call->core;
1240 if (!call->params.has_video) {
1241 linphone_call_stop_video_stream(call);
1244 if (call->videostream != NULL) return;
1245 if ((lc->video_conf.display || lc->video_conf.capture) && call->params.has_video){
1246 int video_recv_buf_size=lp_config_get_int(lc->config,"video","recv_buf_size",0);
1247 int dscp=linphone_core_get_video_dscp(lc);
1249 call->videostream=video_stream_new(call->video_port,call->video_port+1,linphone_core_ipv6_enabled(lc));
1251 video_stream_set_dscp(call->videostream,dscp);
1252 video_stream_enable_display_filter_auto_rotate(call->videostream, lp_config_get_int(lc->config,"video","display_filter_auto_rotate",0));
1253 if (video_recv_buf_size>0) rtp_session_set_recv_buf_size(call->videostream->ms.session,video_recv_buf_size);
1255 if( lc->video_conf.displaytype != NULL)
1256 video_stream_set_display_filter_name(call->videostream,lc->video_conf.displaytype);
1257 video_stream_set_event_callback(call->videostream,video_stream_event_cb, call);
1259 RtpTransport *vrtp=lc->rtptf->video_rtp_func(lc->rtptf->video_rtp_func_data, call->video_port);
1260 RtpTransport *vrtcp=lc->rtptf->video_rtcp_func(lc->rtptf->video_rtcp_func_data, call->video_port+1);
1261 rtp_session_set_transports(call->videostream->ms.session,vrtp,vrtcp);
1263 if ((linphone_core_get_firewall_policy(lc) == LinphonePolicyUseIce) && (call->ice_session != NULL)){
1264 rtp_session_set_pktinfo(call->videostream->ms.session, TRUE);
1265 rtp_session_set_symmetric_rtp(call->videostream->ms.session, FALSE);
1266 if (ice_session_check_list(call->ice_session, 1) == NULL) {
1267 ice_session_add_check_list(call->ice_session, ice_check_list_new());
1269 call->videostream->ms.ice_check_list = ice_session_check_list(call->ice_session, 1);
1270 ice_check_list_set_rtp_session(call->videostream->ms.ice_check_list, call->videostream->ms.session);
1272 call->videostream_app_evq = ortp_ev_queue_new();
1273 rtp_session_register_event_queue(call->videostream->ms.session,call->videostream_app_evq);
1274 #ifdef TEST_EXT_RENDERER
1275 video_stream_set_render_callback(call->videostream,rendercb,NULL);
1279 call->videostream=NULL;
1283 void linphone_call_init_media_streams(LinphoneCall *call){
1284 linphone_call_init_audio_stream(call);
1285 linphone_call_init_video_stream(call);
1289 static int dtmf_tab[16]={'0','1','2','3','4','5','6','7','8','9','*','#','A','B','C','D'};
1291 static void linphone_core_dtmf_received(LinphoneCore *lc, int dtmf){
1292 if (dtmf<0 || dtmf>15){
1293 ms_warning("Bad dtmf value %i",dtmf);
1296 if (lc->vtable.dtmf_received != NULL)
1297 lc->vtable.dtmf_received(lc, linphone_core_get_current_call(lc), dtmf_tab[dtmf]);
1300 static void parametrize_equalizer(LinphoneCore *lc, AudioStream *st){
1302 MSFilter *f=st->equalizer;
1303 int enabled=lp_config_get_int(lc->config,"sound","eq_active",0);
1304 const char *gains=lp_config_get_string(lc->config,"sound","eq_gains",NULL);
1305 ms_filter_call_method(f,MS_EQUALIZER_SET_ACTIVE,&enabled);
1311 if (sscanf(gains,"%f:%f:%f %n",&g.frequency,&g.gain,&g.width,&bytes)==3){
1312 ms_message("Read equalizer gains: %f(~%f) --> %f",g.frequency,g.width,g.gain);
1313 ms_filter_call_method(f,MS_EQUALIZER_SET_GAIN,&g);
1322 void _post_configure_audio_stream(AudioStream *st, LinphoneCore *lc, bool_t muted){
1323 float mic_gain=lc->sound_conf.soft_mic_lev;
1326 float ng_thres=lp_config_get_float(lc->config,"sound","ng_thres",0.05);
1327 float ng_floorgain=lp_config_get_float(lc->config,"sound","ng_floorgain",0);
1328 int dc_removal=lp_config_get_int(lc->config,"sound","dc_removal",0);
1331 linphone_core_set_mic_gain_db (lc, mic_gain);
1333 audio_stream_set_mic_gain(st,0);
1335 recv_gain = lc->sound_conf.soft_play_lev;
1336 if (recv_gain != 0) {
1337 linphone_core_set_playback_gain_db (lc,recv_gain);
1341 ms_filter_call_method(st->volsend,MS_VOLUME_REMOVE_DC,&dc_removal);
1342 float speed=lp_config_get_float(lc->config,"sound","el_speed",-1);
1343 thres=lp_config_get_float(lc->config,"sound","el_thres",-1);
1344 float force=lp_config_get_float(lc->config,"sound","el_force",-1);
1345 int sustain=lp_config_get_int(lc->config,"sound","el_sustain",-1);
1346 float transmit_thres=lp_config_get_float(lc->config,"sound","el_transmit_thres",-1);
1349 if (speed==-1) speed=0.03;
1350 if (force==-1) force=25;
1351 ms_filter_call_method(f,MS_VOLUME_SET_EA_SPEED,&speed);
1352 ms_filter_call_method(f,MS_VOLUME_SET_EA_FORCE,&force);
1354 ms_filter_call_method(f,MS_VOLUME_SET_EA_THRESHOLD,&thres);
1356 ms_filter_call_method(f,MS_VOLUME_SET_EA_SUSTAIN,&sustain);
1357 if (transmit_thres!=-1)
1358 ms_filter_call_method(f,MS_VOLUME_SET_EA_TRANSMIT_THRESHOLD,&transmit_thres);
1360 ms_filter_call_method(st->volsend,MS_VOLUME_SET_NOISE_GATE_THRESHOLD,&ng_thres);
1361 ms_filter_call_method(st->volsend,MS_VOLUME_SET_NOISE_GATE_FLOORGAIN,&ng_floorgain);
1364 /* parameters for a limited noise-gate effect, using echo limiter threshold */
1365 float floorgain = 1/pow(10,(mic_gain)/10);
1366 int spk_agc=lp_config_get_int(lc->config,"sound","speaker_agc_enabled",0);
1367 ms_filter_call_method(st->volrecv, MS_VOLUME_ENABLE_AGC, &spk_agc);
1368 ms_filter_call_method(st->volrecv,MS_VOLUME_SET_NOISE_GATE_THRESHOLD,&ng_thres);
1369 ms_filter_call_method(st->volrecv,MS_VOLUME_SET_NOISE_GATE_FLOORGAIN,&floorgain);
1371 parametrize_equalizer(lc,st);
1374 static void post_configure_audio_streams(LinphoneCall*call){
1375 AudioStream *st=call->audiostream;
1376 LinphoneCore *lc=call->core;
1377 _post_configure_audio_stream(st,lc,call->audio_muted);
1378 if (lc->vtable.dtmf_received!=NULL){
1379 audio_stream_play_received_dtmfs(call->audiostream,FALSE);
1381 if (call->record_active)
1382 linphone_call_start_recording(call);
1385 static RtpProfile *make_profile(LinphoneCall *call, const SalMediaDescription *md, const SalStreamDescription *desc, int *used_pt){
1388 RtpProfile *prof=rtp_profile_new("Call profile");
1391 LinphoneCore *lc=call->core;
1393 const LinphoneCallParams *params=&call->params;
1396 for(elem=desc->payloads;elem!=NULL;elem=elem->next){
1397 PayloadType *pt=(PayloadType*)elem->data;
1400 if ((pt->flags & PAYLOAD_TYPE_FLAG_CAN_SEND) && first) {
1401 if (desc->type==SalAudio){
1402 linphone_core_update_allocated_audio_bandwidth_in_call(call,pt);
1403 if (params->up_ptime)
1404 up_ptime=params->up_ptime;
1405 else up_ptime=linphone_core_get_upload_ptime(lc);
1407 *used_pt=payload_type_get_number(pt);
1410 if (desc->bandwidth>0) remote_bw=desc->bandwidth;
1411 else if (md->bandwidth>0) {
1412 /*case where b=AS is given globally, not per stream*/
1413 remote_bw=md->bandwidth;
1414 if (desc->type==SalVideo){
1415 remote_bw=get_video_bandwidth(remote_bw,call->audio_bw);
1419 if (desc->type==SalAudio){
1420 int audio_bw=call->audio_bw;
1422 if (params->up_bw< audio_bw)
1423 audio_bw=params->up_bw;
1425 bw=get_min_bandwidth(audio_bw,remote_bw);
1426 }else bw=get_min_bandwidth(get_video_bandwidth(linphone_core_get_upload_bandwidth (lc),call->audio_bw),remote_bw);
1427 if (bw>0) pt->normal_bitrate=bw*1000;
1428 else if (desc->type==SalAudio){
1429 pt->normal_bitrate=-1;
1432 up_ptime=desc->ptime;
1436 snprintf(tmp,sizeof(tmp),"ptime=%i",up_ptime);
1437 payload_type_append_send_fmtp(pt,tmp);
1439 number=payload_type_get_number(pt);
1440 if (rtp_profile_get_payload(prof,number)!=NULL){
1441 ms_warning("A payload type with number %i already exists in profile !",number);
1443 rtp_profile_set_payload(prof,number,pt);
1449 static void setup_ring_player(LinphoneCore *lc, LinphoneCall *call){
1450 int pause_time=3000;
1451 audio_stream_play(call->audiostream,lc->sound_conf.ringback_tone);
1452 ms_filter_call_method(call->audiostream->soundread,MS_FILE_PLAYER_LOOP,&pause_time);
1455 static bool_t linphone_call_sound_resources_available(LinphoneCall *call){
1456 LinphoneCore *lc=call->core;
1457 LinphoneCall *current=linphone_core_get_current_call(lc);
1458 return !linphone_core_is_in_conference(lc) &&
1459 (current==NULL || current==call);
1461 static int find_crypto_index_from_tag(const SalSrtpCryptoAlgo crypto[],unsigned char tag) {
1463 for(i=0; i<SAL_CRYPTO_ALGO_MAX; i++) {
1464 if (crypto[i].tag == tag) {
1470 static void linphone_call_start_audio_stream(LinphoneCall *call, const char *cname, bool_t muted, bool_t send_ringbacktone, bool_t use_arc){
1471 LinphoneCore *lc=call->core;
1473 char rtcp_tool[128]={0};
1474 snprintf(rtcp_tool,sizeof(rtcp_tool)-1,"%s-%s",linphone_core_get_user_agent_name(),linphone_core_get_user_agent_version());
1475 /* look for savp stream first */
1476 const SalStreamDescription *stream=sal_media_description_find_stream(call->resultdesc,
1477 SalProtoRtpSavp,SalAudio);
1478 /* no savp audio stream, use avp */
1480 stream=sal_media_description_find_stream(call->resultdesc,
1481 SalProtoRtpAvp,SalAudio);
1483 if (stream && stream->dir!=SalStreamInactive && stream->rtp_port!=0){
1484 MSSndCard *playcard=lc->sound_conf.lsd_card ?
1485 lc->sound_conf.lsd_card : lc->sound_conf.play_sndcard;
1486 MSSndCard *captcard=lc->sound_conf.capt_sndcard;
1487 const char *playfile=lc->play_file;
1488 const char *recfile=lc->rec_file;
1489 call->audio_profile=make_profile(call,call->resultdesc,stream,&used_pt);
1493 call->current_params.audio_codec = rtp_profile_get_payload(call->audio_profile, used_pt);
1494 if (playcard==NULL) {
1495 ms_warning("No card defined for playback !");
1497 if (captcard==NULL) {
1498 ms_warning("No card defined for capture !");
1500 /*Replace soundcard filters by inactive file players or recorders
1501 when placed in recvonly or sendonly mode*/
1502 if (stream->rtp_port==0 || stream->dir==SalStreamRecvOnly){
1505 }else if (stream->dir==SalStreamSendOnly){
1509 /*And we will eventually play "playfile" if set by the user*/
1512 if (send_ringbacktone){
1514 playfile=NULL;/* it is setup later*/
1516 /*if playfile are supplied don't use soundcards*/
1517 if (lc->use_files) {
1521 if (call->params.in_conference){
1522 /* first create the graph without soundcard resources*/
1523 captcard=playcard=NULL;
1525 if (!linphone_call_sound_resources_available(call)){
1526 ms_message("Sound resources are used by another call, not using soundcard.");
1527 captcard=playcard=NULL;
1529 use_ec=captcard==NULL ? FALSE : linphone_core_echo_cancellation_enabled(lc);
1530 if (playcard && stream->max_rate>0) ms_snd_card_set_preferred_sample_rate(playcard, stream->max_rate);
1531 if (captcard && stream->max_rate>0) ms_snd_card_set_preferred_sample_rate(captcard, stream->max_rate);
1532 audio_stream_enable_adaptive_bitrate_control(call->audiostream,use_arc);
1533 audio_stream_enable_adaptive_jittcomp(call->audiostream, linphone_core_audio_adaptive_jittcomp_enabled(lc));
1534 if (!call->params.in_conference && call->params.record_file)
1535 audio_stream_mixed_record_open(call->audiostream,call->params.record_file);
1536 audio_stream_start_full(
1538 call->audio_profile,
1539 stream->rtp_addr[0]!='\0' ? stream->rtp_addr : call->resultdesc->addr,
1541 stream->rtcp_addr[0]!='\0' ? stream->rtcp_addr : call->resultdesc->addr,
1542 linphone_core_rtcp_enabled(lc) ? (stream->rtcp_port) : 0,
1544 linphone_core_get_audio_jittcomp(lc),
1551 post_configure_audio_streams(call);
1552 if (muted && !send_ringbacktone){
1553 audio_stream_set_mic_gain(call->audiostream,0);
1555 if (stream->dir==SalStreamSendOnly && playfile!=NULL){
1557 ms_filter_call_method(call->audiostream->soundread,MS_FILE_PLAYER_LOOP,&pause_time);
1559 if (send_ringbacktone){
1560 setup_ring_player(lc,call);
1562 audio_stream_set_rtcp_information(call->audiostream, cname, rtcp_tool);
1564 /* valid local tags are > 0 */
1565 if (stream->proto == SalProtoRtpSavp) {
1566 const SalStreamDescription *local_st_desc=sal_media_description_find_stream(call->localdesc,
1567 SalProtoRtpSavp,SalAudio);
1568 int crypto_idx = find_crypto_index_from_tag(local_st_desc->crypto, stream->crypto_local_tag);
1570 if (crypto_idx >= 0) {
1571 audio_stream_enable_srtp(
1573 stream->crypto[0].algo,
1574 local_st_desc->crypto[crypto_idx].master_key,
1575 stream->crypto[0].master_key);
1576 call->audiostream_encrypted=TRUE;
1578 ms_warning("Failed to find local crypto algo with tag: %d", stream->crypto_local_tag);
1579 call->audiostream_encrypted=FALSE;
1581 }else call->audiostream_encrypted=FALSE;
1582 if (call->params.in_conference){
1583 /*transform the graph to connect it to the conference filter */
1584 bool_t mute=stream->dir==SalStreamRecvOnly;
1585 linphone_call_add_to_conf(call, mute);
1587 call->current_params.in_conference=call->params.in_conference;
1588 call->current_params.low_bandwidth=call->params.low_bandwidth;
1589 }else ms_warning("No audio stream accepted ?");
1593 static void linphone_call_start_video_stream(LinphoneCall *call, const char *cname,bool_t all_inputs_muted){
1594 #ifdef VIDEO_ENABLED
1595 LinphoneCore *lc=call->core;
1597 /* look for savp stream first */
1598 const SalStreamDescription *vstream=sal_media_description_find_stream(call->resultdesc,
1599 SalProtoRtpSavp,SalVideo);
1600 char rtcp_tool[128]={0};
1601 snprintf(rtcp_tool,sizeof(rtcp_tool)-1,"%s-%s",linphone_core_get_user_agent_name(),linphone_core_get_user_agent_version());
1603 /* no savp audio stream, use avp */
1605 vstream=sal_media_description_find_stream(call->resultdesc,
1606 SalProtoRtpAvp,SalVideo);
1608 /* shutdown preview */
1609 if (lc->previewstream!=NULL) {
1610 video_preview_stop(lc->previewstream);
1611 lc->previewstream=NULL;
1614 if (vstream!=NULL && vstream->dir!=SalStreamInactive && vstream->rtp_port!=0) {
1615 const char *rtp_addr=vstream->rtp_addr[0]!='\0' ? vstream->rtp_addr : call->resultdesc->addr;
1616 const char *rtcp_addr=vstream->rtcp_addr[0]!='\0' ? vstream->rtcp_addr : call->resultdesc->addr;
1617 call->video_profile=make_profile(call,call->resultdesc,vstream,&used_pt);
1619 call->current_params.video_codec = rtp_profile_get_payload(call->video_profile, used_pt);
1620 VideoStreamDir dir=VideoStreamSendRecv;
1621 MSWebCam *cam=lc->video_conf.device;
1622 bool_t is_inactive=FALSE;
1624 call->current_params.has_video=TRUE;
1626 video_stream_enable_adaptive_bitrate_control(call->videostream,
1627 linphone_core_adaptive_rate_control_enabled(lc));
1628 video_stream_enable_adaptive_jittcomp(call->videostream, linphone_core_video_adaptive_jittcomp_enabled(lc));
1629 video_stream_set_sent_video_size(call->videostream,linphone_core_get_preferred_video_size(lc));
1630 video_stream_enable_self_view(call->videostream,lc->video_conf.selfview);
1631 if (lc->video_window_id!=0)
1632 video_stream_set_native_window_id(call->videostream,lc->video_window_id);
1633 if (lc->preview_window_id!=0)
1634 video_stream_set_native_preview_window_id (call->videostream,lc->preview_window_id);
1635 video_stream_use_preview_video_window (call->videostream,lc->use_preview_window);
1637 if (vstream->dir==SalStreamSendOnly && lc->video_conf.capture ){
1638 cam=get_nowebcam_device();
1639 dir=VideoStreamSendOnly;
1640 }else if (vstream->dir==SalStreamRecvOnly && lc->video_conf.display ){
1641 dir=VideoStreamRecvOnly;
1642 }else if (vstream->dir==SalStreamSendRecv){
1643 if (lc->video_conf.display && lc->video_conf.capture)
1644 dir=VideoStreamSendRecv;
1645 else if (lc->video_conf.display)
1646 dir=VideoStreamRecvOnly;
1648 dir=VideoStreamSendOnly;
1650 ms_warning("video stream is inactive.");
1651 /*either inactive or incompatible with local capabilities*/
1654 if (call->camera_active==FALSE || all_inputs_muted){
1655 cam=get_nowebcam_device();
1658 call->log->video_enabled = TRUE;
1659 video_stream_set_direction (call->videostream, dir);
1660 ms_message("%s lc rotation:%d\n", __FUNCTION__, lc->device_rotation);
1661 video_stream_set_device_rotation(call->videostream, lc->device_rotation);
1662 video_stream_start(call->videostream,
1663 call->video_profile, rtp_addr, vstream->rtp_port,
1664 rtcp_addr, linphone_core_rtcp_enabled(lc) ? (vstream->rtcp_port) : 0,
1665 used_pt, linphone_core_get_video_jittcomp(lc), cam);
1666 video_stream_set_rtcp_information(call->videostream, cname,rtcp_tool);
1669 if (vstream->proto == SalProtoRtpSavp) {
1670 const SalStreamDescription *local_st_desc=sal_media_description_find_stream(call->localdesc,
1671 SalProtoRtpSavp,SalVideo);
1673 video_stream_enable_strp(
1675 vstream->crypto[0].algo,
1676 local_st_desc->crypto[0].master_key,
1677 vstream->crypto[0].master_key
1679 call->videostream_encrypted=TRUE;
1681 call->videostream_encrypted=FALSE;
1683 }else ms_warning("No video stream accepted.");
1685 ms_warning("No valid video stream defined.");
1690 void linphone_call_start_media_streams(LinphoneCall *call, bool_t all_inputs_muted, bool_t send_ringbacktone){
1691 LinphoneCore *lc=call->core;
1693 call->current_params.audio_codec = NULL;
1694 call->current_params.video_codec = NULL;
1696 LinphoneAddress *me=linphone_core_get_primary_contact_parsed(lc);
1698 bool_t use_arc=linphone_core_adaptive_rate_control_enabled(lc);
1699 #ifdef VIDEO_ENABLED
1700 const SalStreamDescription *vstream=sal_media_description_find_stream(call->resultdesc,
1701 SalProtoRtpAvp,SalVideo);
1704 if ((call->audiostream == NULL) && (call->videostream == NULL)) {
1705 ms_fatal("start_media_stream() called without prior init !");
1708 cname=linphone_address_as_string_uri_only(me);
1710 #if defined(VIDEO_ENABLED)
1711 if (vstream!=NULL && vstream->dir!=SalStreamInactive && vstream->payloads!=NULL){
1712 /*when video is used, do not make adaptive rate control on audio, it is stupid.*/
1716 if (call->audiostream!=NULL) {
1717 linphone_call_start_audio_stream(call,cname,all_inputs_muted,send_ringbacktone,use_arc);
1719 call->current_params.has_video=FALSE;
1720 if (call->videostream!=NULL) {
1721 linphone_call_start_video_stream(call,cname,all_inputs_muted);
1724 call->all_muted=all_inputs_muted;
1725 call->playing_ringbacktone=send_ringbacktone;
1726 call->up_bw=linphone_core_get_upload_bandwidth(lc);
1728 if (call->params.media_encryption==LinphoneMediaEncryptionZRTP) {
1729 OrtpZrtpParams params;
1730 /*will be set later when zrtp is activated*/
1731 call->current_params.media_encryption=LinphoneMediaEncryptionNone;
1733 params.zid_file=lc->zrtp_secrets_cache;
1734 audio_stream_enable_zrtp(call->audiostream,¶ms);
1735 }else if (call->params.media_encryption==LinphoneMediaEncryptionSRTP){
1736 call->current_params.media_encryption=linphone_call_are_all_streams_encrypted(call) ?
1737 LinphoneMediaEncryptionSRTP : LinphoneMediaEncryptionNone;
1740 /*also reflect the change if the "wished" params, in order to avoid to propose SAVP or video again
1741 * further in the call, for example during pause,resume, conferencing reINVITEs*/
1742 linphone_call_fix_call_parameters(call);
1743 if ((call->ice_session != NULL) && (ice_session_state(call->ice_session) != IS_Completed)) {
1744 ice_session_start_connectivity_checks(call->ice_session);
1750 linphone_address_destroy(me);
1753 void linphone_call_start_media_streams_for_ice_gathering(LinphoneCall *call){
1754 audio_stream_prepare_sound(call->audiostream, NULL, NULL);
1755 #ifdef VIDEO_ENABLED
1756 if (call->videostream) {
1757 video_stream_prepare_video(call->videostream);
1762 void linphone_call_stop_media_streams_for_ice_gathering(LinphoneCall *call){
1763 audio_stream_unprepare_sound(call->audiostream);
1764 #ifdef VIDEO_ENABLED
1765 if (call->videostream) {
1766 video_stream_unprepare_video(call->videostream);
1771 void linphone_call_update_crypto_parameters(LinphoneCall *call, SalMediaDescription *old_md, SalMediaDescription *new_md) {
1772 SalStreamDescription *old_stream;
1773 SalStreamDescription *new_stream;
1776 old_stream = sal_media_description_find_stream(old_md, SalProtoRtpSavp, SalAudio);
1777 new_stream = sal_media_description_find_stream(new_md, SalProtoRtpSavp, SalAudio);
1778 if (old_stream && new_stream) {
1779 const SalStreamDescription *local_st_desc = sal_media_description_find_stream(call->localdesc, SalProtoRtpSavp, SalAudio);
1780 if (local_st_desc) {
1781 int crypto_idx = find_crypto_index_from_tag(local_st_desc->crypto, new_stream->crypto_local_tag);
1782 if (crypto_idx >= 0) {
1783 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);
1784 call->audiostream_encrypted = TRUE;
1786 ms_warning("Failed to find local crypto algo with tag: %d", new_stream->crypto_local_tag);
1787 call->audiostream_encrypted = FALSE;
1789 for (i = 0; i < SAL_CRYPTO_ALGO_MAX; i++) {
1790 old_stream->crypto[i].tag = new_stream->crypto[i].tag;
1791 old_stream->crypto[i].algo = new_stream->crypto[i].algo;
1792 strncpy(old_stream->crypto[i].master_key, new_stream->crypto[i].master_key, sizeof(old_stream->crypto[i].master_key) - 1);
1797 #ifdef VIDEO_ENABLED
1798 old_stream = sal_media_description_find_stream(old_md, SalProtoRtpSavp, SalVideo);
1799 new_stream = sal_media_description_find_stream(new_md, SalProtoRtpSavp, SalVideo);
1800 if (old_stream && new_stream) {
1801 const SalStreamDescription *local_st_desc = sal_media_description_find_stream(call->localdesc, SalProtoRtpSavp, SalVideo);
1802 if (local_st_desc) {
1803 int crypto_idx = find_crypto_index_from_tag(local_st_desc->crypto, new_stream->crypto_local_tag);
1804 if (crypto_idx >= 0) {
1805 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);
1806 call->videostream_encrypted = TRUE;
1808 ms_warning("Failed to find local crypto algo with tag: %d", new_stream->crypto_local_tag);
1809 call->videostream_encrypted = FALSE;
1811 for (i = 0; i < SAL_CRYPTO_ALGO_MAX; i++) {
1812 old_stream->crypto[i].tag = new_stream->crypto[i].tag;
1813 old_stream->crypto[i].algo = new_stream->crypto[i].algo;
1814 strncpy(old_stream->crypto[i].master_key, new_stream->crypto[i].master_key, sizeof(old_stream->crypto[i].master_key) - 1);
1821 void linphone_call_update_remote_session_id_and_ver(LinphoneCall *call) {
1822 SalMediaDescription *remote_desc = sal_call_get_remote_media_description(call->op);
1824 call->remote_session_id = remote_desc->session_id;
1825 call->remote_session_ver = remote_desc->session_ver;
1829 void linphone_call_delete_ice_session(LinphoneCall *call){
1830 if (call->ice_session != NULL) {
1831 ice_session_destroy(call->ice_session);
1832 call->ice_session = NULL;
1833 if (call->audiostream != NULL) call->audiostream->ms.ice_check_list = NULL;
1834 if (call->videostream != NULL) call->videostream->ms.ice_check_list = NULL;
1835 call->stats[LINPHONE_CALL_STATS_AUDIO].ice_state = LinphoneIceStateNotActivated;
1836 call->stats[LINPHONE_CALL_STATS_VIDEO].ice_state = LinphoneIceStateNotActivated;
1841 void linphone_call_delete_upnp_session(LinphoneCall *call){
1842 if(call->upnp_session!=NULL) {
1843 linphone_upnp_session_destroy(call->upnp_session);
1844 call->upnp_session=NULL;
1849 static void linphone_call_log_fill_stats(LinphoneCallLog *log, AudioStream *st){
1850 audio_stream_get_local_rtp_stats (st,&log->local_stats);
1851 log->quality=audio_stream_get_average_quality_rating(st);
1854 void linphone_call_stop_audio_stream(LinphoneCall *call) {
1855 if (call->audiostream!=NULL) {
1856 rtp_session_unregister_event_queue(call->audiostream->ms.session,call->audiostream_app_evq);
1857 ortp_ev_queue_flush(call->audiostream_app_evq);
1858 ortp_ev_queue_destroy(call->audiostream_app_evq);
1859 call->audiostream_app_evq=NULL;
1861 if (call->audiostream->ec){
1862 const char *state_str=NULL;
1863 ms_filter_call_method(call->audiostream->ec,MS_ECHO_CANCELLER_GET_STATE_STRING,&state_str);
1865 ms_message("Writing echo canceler state, %i bytes",(int)strlen(state_str));
1866 lp_config_set_string(call->core->config,"sound","ec_state",state_str);
1869 linphone_call_log_fill_stats (call->log,call->audiostream);
1870 if (call->endpoint){
1871 linphone_call_remove_from_conf(call);
1873 audio_stream_stop(call->audiostream);
1874 call->audiostream=NULL;
1878 void linphone_call_stop_video_stream(LinphoneCall *call) {
1879 #ifdef VIDEO_ENABLED
1880 if (call->videostream!=NULL){
1881 rtp_session_unregister_event_queue(call->videostream->ms.session,call->videostream_app_evq);
1882 ortp_ev_queue_flush(call->videostream_app_evq);
1883 ortp_ev_queue_destroy(call->videostream_app_evq);
1884 call->videostream_app_evq=NULL;
1885 video_stream_stop(call->videostream);
1886 call->videostream=NULL;
1891 void linphone_call_stop_media_streams(LinphoneCall *call){
1892 linphone_call_stop_audio_stream(call);
1893 linphone_call_stop_video_stream(call);
1894 ms_event_queue_skip(call->core->msevq);
1896 if (call->audio_profile){
1897 rtp_profile_clear_all(call->audio_profile);
1898 rtp_profile_destroy(call->audio_profile);
1899 call->audio_profile=NULL;
1901 if (call->video_profile){
1902 rtp_profile_clear_all(call->video_profile);
1903 rtp_profile_destroy(call->video_profile);
1904 call->video_profile=NULL;
1910 void linphone_call_enable_echo_cancellation(LinphoneCall *call, bool_t enable) {
1911 if (call!=NULL && call->audiostream!=NULL && call->audiostream->ec){
1912 bool_t bypass_mode = !enable;
1913 ms_filter_call_method(call->audiostream->ec,MS_ECHO_CANCELLER_SET_BYPASS_MODE,&bypass_mode);
1916 bool_t linphone_call_echo_cancellation_enabled(LinphoneCall *call) {
1917 if (call!=NULL && call->audiostream!=NULL && call->audiostream->ec){
1919 ms_filter_call_method(call->audiostream->ec,MS_ECHO_CANCELLER_GET_BYPASS_MODE,&val);
1922 return linphone_core_echo_cancellation_enabled(call->core);
1926 void linphone_call_enable_echo_limiter(LinphoneCall *call, bool_t val){
1927 if (call!=NULL && call->audiostream!=NULL ) {
1929 const char *type=lp_config_get_string(call->core->config,"sound","el_type","mic");
1930 if (strcasecmp(type,"mic")==0)
1931 audio_stream_enable_echo_limiter(call->audiostream,ELControlMic);
1932 else if (strcasecmp(type,"full")==0)
1933 audio_stream_enable_echo_limiter(call->audiostream,ELControlFull);
1935 audio_stream_enable_echo_limiter(call->audiostream,ELInactive);
1940 bool_t linphone_call_echo_limiter_enabled(const LinphoneCall *call){
1941 if (call!=NULL && call->audiostream!=NULL ){
1942 return call->audiostream->el_type !=ELInactive ;
1944 return linphone_core_echo_limiter_enabled(call->core);
1949 * @addtogroup call_misc
1954 * Returns the measured sound volume played locally (received from remote).
1955 * It is expressed in dbm0.
1957 float linphone_call_get_play_volume(LinphoneCall *call){
1958 AudioStream *st=call->audiostream;
1959 if (st && st->volrecv){
1961 ms_filter_call_method(st->volrecv,MS_VOLUME_GET,&vol);
1965 return LINPHONE_VOLUME_DB_LOWEST;
1969 * Returns the measured sound volume recorded locally (sent to remote).
1970 * It is expressed in dbm0.
1972 float linphone_call_get_record_volume(LinphoneCall *call){
1973 AudioStream *st=call->audiostream;
1974 if (st && st->volsend && !call->audio_muted && call->state==LinphoneCallStreamsRunning){
1976 ms_filter_call_method(st->volsend,MS_VOLUME_GET,&vol);
1980 return LINPHONE_VOLUME_DB_LOWEST;
1984 * Obtain real-time quality rating of the call
1986 * Based on local RTP statistics and RTCP feedback, a quality rating is computed and updated
1987 * during all the duration of the call. This function returns its value at the time of the function call.
1988 * It is expected that the rating is updated at least every 5 seconds or so.
1989 * The rating is a floating point number comprised between 0 and 5.
1991 * 4-5 = good quality <br>
1992 * 3-4 = average quality <br>
1993 * 2-3 = poor quality <br>
1994 * 1-2 = very poor quality <br>
1995 * 0-1 = can't be worse, mostly unusable <br>
1997 * @returns The function returns -1 if no quality measurement is available, for example if no
1998 * active audio stream exist. Otherwise it returns the quality rating.
2000 float linphone_call_get_current_quality(LinphoneCall *call){
2001 if (call->audiostream){
2002 return audio_stream_get_quality_rating(call->audiostream);
2008 * Returns call quality averaged over all the duration of the call.
2010 * See linphone_call_get_current_quality() for more details about quality measurement.
2012 float linphone_call_get_average_quality(LinphoneCall *call){
2013 if (call->audiostream){
2014 return audio_stream_get_average_quality_rating(call->audiostream);
2020 * Access last known statistics for audio stream, for a given call.
2022 const LinphoneCallStats *linphone_call_get_audio_stats(const LinphoneCall *call) {
2023 return &call->stats[LINPHONE_CALL_STATS_AUDIO];
2027 * Access last known statistics for video stream, for a given call.
2029 const LinphoneCallStats *linphone_call_get_video_stats(const LinphoneCall *call) {
2030 return &call->stats[LINPHONE_CALL_STATS_VIDEO];
2034 * Enable recording of the call (voice-only).
2035 * This function must be used before the call parameters are assigned to the call.
2036 * The call recording can be started and paused after the call is established with
2037 * linphone_call_start_recording() and linphone_call_pause_recording().
2038 * @param cp the call parameters
2039 * @param path path and filename of the file where audio is written.
2041 void linphone_call_params_set_record_file(LinphoneCallParams *cp, const char *path){
2042 if (cp->record_file){
2043 ms_free(cp->record_file);
2044 cp->record_file=NULL;
2046 if (path) cp->record_file=ms_strdup(path);
2050 * Retrieves the path for the audio recoding of the call.
2052 const char *linphone_call_params_get_record_file(const LinphoneCallParams *cp){
2053 return cp->record_file;
2057 * Start call recording.
2058 * The output file where audio is recorded must be previously specified with linphone_call_params_set_record_file().
2060 void linphone_call_start_recording(LinphoneCall *call){
2061 if (!call->params.record_file){
2062 ms_error("linphone_call_start_recording(): no output file specified. Use linphone_call_params_set_record_file().");
2065 if (call->audiostream && !call->params.in_conference){
2066 audio_stream_mixed_record_start(call->audiostream);
2068 call->record_active=TRUE;
2072 * Stop call recording.
2074 void linphone_call_stop_recording(LinphoneCall *call){
2075 if (call->audiostream && !call->params.in_conference){
2076 audio_stream_mixed_record_stop(call->audiostream);
2078 call->record_active=FALSE;
2085 static void report_bandwidth(LinphoneCall *call, RtpSession *as, RtpSession *vs){
2086 call->stats[LINPHONE_CALL_STATS_AUDIO].download_bandwidth=(as!=NULL) ? (rtp_session_compute_recv_bandwidth(as)*1e-3) : 0;
2087 call->stats[LINPHONE_CALL_STATS_AUDIO].upload_bandwidth=(as!=NULL) ? (rtp_session_compute_send_bandwidth(as)*1e-3) : 0;
2088 call->stats[LINPHONE_CALL_STATS_VIDEO].download_bandwidth=(vs!=NULL) ? (rtp_session_compute_recv_bandwidth(vs)*1e-3) : 0;
2089 call->stats[LINPHONE_CALL_STATS_VIDEO].upload_bandwidth=(vs!=NULL) ? (rtp_session_compute_send_bandwidth(vs)*1e-3) : 0;
2090 ms_message("bandwidth usage: audio=[d=%.1f,u=%.1f] video=[d=%.1f,u=%.1f] kbit/sec",
2091 call->stats[LINPHONE_CALL_STATS_AUDIO].download_bandwidth,
2092 call->stats[LINPHONE_CALL_STATS_AUDIO].upload_bandwidth ,
2093 call->stats[LINPHONE_CALL_STATS_VIDEO].download_bandwidth,
2094 call->stats[LINPHONE_CALL_STATS_VIDEO].upload_bandwidth
2098 static void linphone_core_disconnected(LinphoneCore *lc, LinphoneCall *call){
2102 from = linphone_call_get_remote_address_as_string(call);
2105 snprintf(temp,sizeof(temp),"Remote end %s seems to have disconnected, the call is going to be closed.",from);
2110 snprintf(temp,sizeof(temp),"Remote end seems to have disconnected, the call is going to be closed.");
2112 if (lc->vtable.display_warning!=NULL)
2113 lc->vtable.display_warning(lc,temp);
2114 linphone_core_terminate_call(lc,call);
2117 static void handle_ice_events(LinphoneCall *call, OrtpEvent *ev){
2118 OrtpEventType evt=ortp_event_get_type(ev);
2119 OrtpEventData *evd=ortp_event_get_data(ev);
2122 if (evt == ORTP_EVENT_ICE_SESSION_PROCESSING_FINISHED) {
2123 switch (ice_session_state(call->ice_session)) {
2125 ice_session_select_candidates(call->ice_session);
2126 if (ice_session_role(call->ice_session) == IR_Controlling) {
2127 linphone_core_update_call(call->core, call, &call->current_params);
2131 if (ice_session_has_completed_check_list(call->ice_session) == TRUE) {
2132 ice_session_select_candidates(call->ice_session);
2133 if (ice_session_role(call->ice_session) == IR_Controlling) {
2134 /* At least one ICE session has succeeded, so perform a call update. */
2135 linphone_core_update_call(call->core, call, &call->current_params);
2142 linphone_core_update_ice_state_in_call_stats(call);
2143 } else if (evt == ORTP_EVENT_ICE_GATHERING_FINISHED) {
2145 if (evd->info.ice_processing_successful==TRUE) {
2146 ice_session_compute_candidates_foundations(call->ice_session);
2147 ice_session_eliminate_redundant_candidates(call->ice_session);
2148 ice_session_choose_default_candidates(call->ice_session);
2149 ping_time = ice_session_average_gathering_round_trip_time(call->ice_session);
2150 if (ping_time >=0) {
2151 call->ping_time=ping_time;
2154 ms_warning("No STUN answer from [%s], disabling ICE",linphone_core_get_stun_server(call->core));
2155 linphone_call_delete_ice_session(call);
2157 switch (call->state) {
2158 case LinphoneCallUpdating:
2159 linphone_core_start_update_call(call->core, call);
2161 case LinphoneCallUpdatedByRemote:
2162 linphone_core_start_accept_call_update(call->core, call);
2164 case LinphoneCallOutgoingInit:
2165 linphone_call_stop_media_streams_for_ice_gathering(call);
2166 linphone_core_proceed_with_invite_if_ready(call->core, call, NULL);
2168 case LinphoneCallIdle:
2169 linphone_call_stop_media_streams_for_ice_gathering(call);
2170 linphone_core_notify_incoming_call(call->core, call);
2175 } else if (evt == ORTP_EVENT_ICE_LOSING_PAIRS_COMPLETED) {
2176 linphone_core_start_accept_call_update(call->core, call);
2177 linphone_core_update_ice_state_in_call_stats(call);
2178 } else if (evt == ORTP_EVENT_ICE_RESTART_NEEDED) {
2179 ice_session_restart(call->ice_session);
2180 ice_session_set_role(call->ice_session, IR_Controlling);
2181 linphone_core_update_call(call->core, call, &call->current_params);
2185 void linphone_call_background_tasks(LinphoneCall *call, bool_t one_second_elapsed){
2186 LinphoneCore* lc = call->core;
2187 int disconnect_timeout = linphone_core_get_nortp_timeout(call->core);
2188 bool_t disconnected=FALSE;
2190 if (call->state==LinphoneCallStreamsRunning && one_second_elapsed){
2191 RtpSession *as=NULL,*vs=NULL;
2192 float audio_load=0, video_load=0;
2193 if (call->audiostream!=NULL){
2194 as=call->audiostream->ms.session;
2195 if (call->audiostream->ms.ticker)
2196 audio_load=ms_ticker_get_average_load(call->audiostream->ms.ticker);
2198 if (call->videostream!=NULL){
2199 if (call->videostream->ms.ticker)
2200 video_load=ms_ticker_get_average_load(call->videostream->ms.ticker);
2201 vs=call->videostream->ms.session;
2203 report_bandwidth(call,as,vs);
2204 ms_message("Thread processing load: audio=%f\tvideo=%f",audio_load,video_load);
2208 linphone_upnp_call_process(call);
2211 #ifdef VIDEO_ENABLED
2212 if (call->videostream!=NULL) {
2215 /* Ensure there is no dangling ICE check list. */
2216 if (call->ice_session == NULL) call->videostream->ms.ice_check_list = NULL;
2218 // Beware that the application queue should not depend on treatments fron the
2219 // mediastreamer queue.
2220 video_stream_iterate(call->videostream);
2222 while (call->videostream_app_evq && (NULL != (ev=ortp_ev_queue_get(call->videostream_app_evq)))){
2223 OrtpEventType evt=ortp_event_get_type(ev);
2224 OrtpEventData *evd=ortp_event_get_data(ev);
2225 if (evt == ORTP_EVENT_ZRTP_ENCRYPTION_CHANGED){
2226 linphone_call_videostream_encryption_changed(call, evd->info.zrtp_stream_encrypted);
2227 } else if (evt == ORTP_EVENT_RTCP_PACKET_RECEIVED) {
2228 call->stats[LINPHONE_CALL_STATS_VIDEO].round_trip_delay = rtp_session_get_round_trip_propagation(call->videostream->ms.session);
2229 if(call->stats[LINPHONE_CALL_STATS_VIDEO].received_rtcp != NULL)
2230 freemsg(call->stats[LINPHONE_CALL_STATS_VIDEO].received_rtcp);
2231 call->stats[LINPHONE_CALL_STATS_VIDEO].received_rtcp = evd->packet;
2233 if (lc->vtable.call_stats_updated)
2234 lc->vtable.call_stats_updated(lc, call, &call->stats[LINPHONE_CALL_STATS_VIDEO]);
2235 } else if (evt == ORTP_EVENT_RTCP_PACKET_EMITTED) {
2236 memcpy(&call->stats[LINPHONE_CALL_STATS_VIDEO].jitter_stats, rtp_session_get_jitter_stats(call->videostream->ms.session), sizeof(jitter_stats_t));
2237 if(call->stats[LINPHONE_CALL_STATS_VIDEO].sent_rtcp != NULL)
2238 freemsg(call->stats[LINPHONE_CALL_STATS_VIDEO].sent_rtcp);
2239 call->stats[LINPHONE_CALL_STATS_VIDEO].sent_rtcp = evd->packet;
2241 if (lc->vtable.call_stats_updated)
2242 lc->vtable.call_stats_updated(lc, call, &call->stats[LINPHONE_CALL_STATS_VIDEO]);
2243 } else if ((evt == ORTP_EVENT_ICE_SESSION_PROCESSING_FINISHED) || (evt == ORTP_EVENT_ICE_GATHERING_FINISHED)
2244 || (evt == ORTP_EVENT_ICE_LOSING_PAIRS_COMPLETED) || (evt == ORTP_EVENT_ICE_RESTART_NEEDED)) {
2245 handle_ice_events(call, ev);
2247 ortp_event_destroy(ev);
2251 if (call->audiostream!=NULL) {
2254 /* Ensure there is no dangling ICE check list. */
2255 if (call->ice_session == NULL) call->audiostream->ms.ice_check_list = NULL;
2257 // Beware that the application queue should not depend on treatments fron the
2258 // mediastreamer queue.
2259 audio_stream_iterate(call->audiostream);
2261 while (call->audiostream_app_evq && (NULL != (ev=ortp_ev_queue_get(call->audiostream_app_evq)))){
2262 OrtpEventType evt=ortp_event_get_type(ev);
2263 OrtpEventData *evd=ortp_event_get_data(ev);
2264 if (evt == ORTP_EVENT_ZRTP_ENCRYPTION_CHANGED){
2265 linphone_call_audiostream_encryption_changed(call, evd->info.zrtp_stream_encrypted);
2266 } else if (evt == ORTP_EVENT_ZRTP_SAS_READY) {
2267 linphone_call_audiostream_auth_token_ready(call, evd->info.zrtp_sas.sas, evd->info.zrtp_sas.verified);
2268 } else if (evt == ORTP_EVENT_RTCP_PACKET_RECEIVED) {
2269 call->stats[LINPHONE_CALL_STATS_AUDIO].round_trip_delay = rtp_session_get_round_trip_propagation(call->audiostream->ms.session);
2270 if(call->stats[LINPHONE_CALL_STATS_AUDIO].received_rtcp != NULL)
2271 freemsg(call->stats[LINPHONE_CALL_STATS_AUDIO].received_rtcp);
2272 call->stats[LINPHONE_CALL_STATS_AUDIO].received_rtcp = evd->packet;
2274 if (lc->vtable.call_stats_updated)
2275 lc->vtable.call_stats_updated(lc, call, &call->stats[LINPHONE_CALL_STATS_AUDIO]);
2276 } else if (evt == ORTP_EVENT_RTCP_PACKET_EMITTED) {
2277 memcpy(&call->stats[LINPHONE_CALL_STATS_AUDIO].jitter_stats, rtp_session_get_jitter_stats(call->audiostream->ms.session), sizeof(jitter_stats_t));
2278 if(call->stats[LINPHONE_CALL_STATS_AUDIO].sent_rtcp != NULL)
2279 freemsg(call->stats[LINPHONE_CALL_STATS_AUDIO].sent_rtcp);
2280 call->stats[LINPHONE_CALL_STATS_AUDIO].sent_rtcp = evd->packet;
2282 if (lc->vtable.call_stats_updated)
2283 lc->vtable.call_stats_updated(lc, call, &call->stats[LINPHONE_CALL_STATS_AUDIO]);
2284 } else if ((evt == ORTP_EVENT_ICE_SESSION_PROCESSING_FINISHED) || (evt == ORTP_EVENT_ICE_GATHERING_FINISHED)
2285 || (evt == ORTP_EVENT_ICE_LOSING_PAIRS_COMPLETED) || (evt == ORTP_EVENT_ICE_RESTART_NEEDED)) {
2286 handle_ice_events(call, ev);
2287 } else if (evt==ORTP_EVENT_TELEPHONE_EVENT){
2288 linphone_core_dtmf_received(lc,evd->info.telephone_event);
2290 ortp_event_destroy(ev);
2293 if (call->state==LinphoneCallStreamsRunning && one_second_elapsed && call->audiostream!=NULL && disconnect_timeout>0 )
2294 disconnected=!audio_stream_alive(call->audiostream,disconnect_timeout);
2296 linphone_core_disconnected(call->core,call);
2299 void linphone_call_log_completed(LinphoneCall *call){
2300 LinphoneCore *lc=call->core;
2302 call->log->duration=time(NULL)-call->start_time;
2304 if (call->log->status==LinphoneCallMissed){
2307 info=ortp_strdup_printf(ngettext("You have missed %i call.",
2308 "You have missed %i calls.", lc->missed_calls),
2310 if (lc->vtable.display_status!=NULL)
2311 lc->vtable.display_status(lc,info);
2314 lc->call_logs=ms_list_prepend(lc->call_logs,(void *)call->log);
2315 if (ms_list_size(lc->call_logs)>lc->max_call_logs){
2316 MSList *elem,*prevelem=NULL;
2317 /*find the last element*/
2318 for(elem=lc->call_logs;elem!=NULL;elem=elem->next){
2322 linphone_call_log_destroy((LinphoneCallLog*)elem->data);
2323 lc->call_logs=ms_list_remove_link(lc->call_logs,elem);
2325 if (lc->vtable.call_log_updated!=NULL){
2326 lc->vtable.call_log_updated(lc,call->log);
2328 call_logs_write_to_config_file(lc);
2331 LinphoneCallState linphone_call_get_transfer_state(LinphoneCall *call) {
2332 return call->transfer_state;
2335 void linphone_call_set_transfer_state(LinphoneCall* call, LinphoneCallState state) {
2336 if (state != call->transfer_state) {
2337 LinphoneCore* lc = call->core;
2338 call->transfer_state = state;
2339 if (lc->vtable.transfer_state_changed)
2340 lc->vtable.transfer_state_changed(lc, call, state);
2345 * Returns true if the call is part of the conference.
2346 * @ingroup conferencing
2348 bool_t linphone_call_is_in_conference(const LinphoneCall *call) {
2349 return call->params.in_conference;
2354 * Perform a zoom of the video displayed during a call.
2355 * @param call the call.
2356 * @param zoom_factor a floating point number describing the zoom factor. A value 1.0 corresponds to no zoom applied.
2357 * @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.
2358 * @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.
2360 * 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.
2362 void linphone_call_zoom_video(LinphoneCall* call, float zoom_factor, float* cx, float* cy) {
2363 VideoStream* vstream = call->videostream;
2364 if (vstream && vstream->output) {
2367 if (zoom_factor < 1)
2369 float halfsize = 0.5 * 1.0 / zoom_factor;
2371 if ((*cx - halfsize) < 0)
2373 if ((*cx + halfsize) > 1)
2375 if ((*cy - halfsize) < 0)
2377 if ((*cy + halfsize) > 1)
2380 zoom[0] = zoom_factor;
2383 ms_filter_call_method(vstream->output, MS_VIDEO_DISPLAY_ZOOM, &zoom);
2384 }else ms_warning("Could not apply zoom: video output wasn't activated.");