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
88 const LinphoneCallParams *params=linphone_call_get_current_params(call);
89 if (params->has_video && !call->videostream_encrypted) {
98 void propagate_encryption_changed(LinphoneCall *call){
99 LinphoneCore *lc=call->core;
100 if (!linphone_call_are_all_streams_encrypted(call)) {
101 ms_message("Some streams are not encrypted");
102 call->current_params.media_encryption=LinphoneMediaEncryptionNone;
103 if (lc->vtable.call_encryption_changed)
104 lc->vtable.call_encryption_changed(call->core, call, FALSE, call->auth_token);
106 ms_message("All streams are encrypted");
107 call->current_params.media_encryption=LinphoneMediaEncryptionZRTP;
108 if (lc->vtable.call_encryption_changed)
109 lc->vtable.call_encryption_changed(call->core, call, TRUE, call->auth_token);
114 static void linphone_call_videostream_encryption_changed(void *data, bool_t encrypted){
115 LinphoneCall *call = (LinphoneCall *)data;
117 ms_message("Video stream is %s", encrypted ? "encrypted" : "not encrypted");
118 call->videostream_encrypted=encrypted;
119 propagate_encryption_changed(call);
123 static void linphone_call_audiostream_encryption_changed(void *data, bool_t encrypted) {
124 char status[255]={0};
125 ms_message("Audio stream is %s ", encrypted ? "encrypted" : "not encrypted");
127 LinphoneCall *call = (LinphoneCall *)data;
128 call->audiostream_encrypted=encrypted;
130 if (encrypted && call->core->vtable.display_status != NULL) {
131 snprintf(status,sizeof(status)-1,_("Authentication token is %s"),call->auth_token);
132 call->core->vtable.display_status(call->core, status);
135 propagate_encryption_changed(call);
139 // Enable video encryption
141 const LinphoneCallParams *params=linphone_call_get_current_params(call);
142 if (params->has_video) {
143 OrtpZrtpParams params;
144 ms_message("Trying to enable encryption on video stream");
145 params.zid_file=NULL; //unused
146 video_stream_enable_zrtp(call->videostream,call->audiostream,¶ms);
153 static void linphone_call_audiostream_auth_token_ready(void *data, const char* auth_token, bool_t verified) {
154 LinphoneCall *call=(LinphoneCall *)data;
155 if (call->auth_token != NULL)
156 ms_free(call->auth_token);
158 call->auth_token=ms_strdup(auth_token);
159 call->auth_token_verified=verified;
161 ms_message("Authentication token is %s (%s)", auth_token, verified?"verified":"unverified");
164 void linphone_call_set_authentication_token_verified(LinphoneCall *call, bool_t verified){
165 if (call->audiostream==NULL){
166 ms_error("linphone_call_set_authentication_token_verified(): No audio stream");
168 if (call->audiostream->ms.zrtp_context==NULL){
169 ms_error("linphone_call_set_authentication_token_verified(): No zrtp context.");
171 if (!call->auth_token_verified && verified){
172 ortp_zrtp_sas_verified(call->audiostream->ms.zrtp_context);
173 }else if (call->auth_token_verified && !verified){
174 ortp_zrtp_sas_reset_verified(call->audiostream->ms.zrtp_context);
176 call->auth_token_verified=verified;
177 propagate_encryption_changed(call);
180 static MSList *make_codec_list(LinphoneCore *lc, const MSList *codecs, int bandwidth_limit,int* max_sample_rate, int nb_codecs_limit){
184 if (max_sample_rate) *max_sample_rate=0;
185 for(it=codecs;it!=NULL;it=it->next){
186 PayloadType *pt=(PayloadType*)it->data;
187 if (pt->flags & PAYLOAD_TYPE_ENABLED){
188 if (bandwidth_limit>0 && !linphone_core_is_payload_type_usable_for_bandwidth(lc,pt,bandwidth_limit)){
189 ms_message("Codec %s/%i eliminated because of audio bandwidth constraint.",pt->mime_type,pt->clock_rate);
192 if (linphone_core_check_payload_type_usability(lc,pt)){
193 l=ms_list_append(l,payload_type_clone(pt));
195 if (max_sample_rate && payload_type_get_rate(pt)>*max_sample_rate) *max_sample_rate=payload_type_get_rate(pt);
198 if ((nb_codecs_limit > 0) && (nb >= nb_codecs_limit)) break;
203 static void update_media_description_from_stun(SalMediaDescription *md, const StunCandidate *ac, const StunCandidate *vc){
205 for (i = 0; i < md->n_active_streams; i++) {
206 if ((md->streams[i].type == SalAudio) && (ac->port != 0)) {
207 strcpy(md->streams[0].rtp_addr,ac->addr);
208 md->streams[0].rtp_port=ac->port;
209 if ((ac->addr[0]!='\0' && vc->addr[0]!='\0' && strcmp(ac->addr,vc->addr)==0) || md->n_active_streams==1){
210 strcpy(md->addr,ac->addr);
213 if ((md->streams[i].type == SalVideo) && (vc->port != 0)) {
214 strcpy(md->streams[1].rtp_addr,vc->addr);
215 md->streams[1].rtp_port=vc->port;
220 void linphone_call_make_local_media_description(LinphoneCore *lc, LinphoneCall *call){
223 SalMediaDescription *old_md=call->localdesc;
225 const char *me=linphone_core_get_identity(lc);
226 LinphoneAddress *addr=linphone_address_new(me);
227 const char *username=linphone_address_get_username (addr);
228 SalMediaDescription *md=sal_media_description_new();
229 bool_t keep_srtp_keys=lp_config_get_int(lc->config,"sip","keep_srtp_keys",0);
231 linphone_core_adapt_to_network(lc,call->ping_time,&call->params);
233 md->session_id=(old_md ? old_md->session_id : (rand() & 0xfff));
234 md->session_ver=(old_md ? (old_md->session_ver+1) : (rand() & 0xfff));
235 md->n_total_streams=(old_md ? old_md->n_total_streams : 1);
236 md->n_active_streams=1;
237 strncpy(md->addr,call->localip,sizeof(md->addr));
238 strncpy(md->username,username,sizeof(md->username));
240 if (call->params.down_bw)
241 md->bandwidth=call->params.down_bw;
242 else md->bandwidth=linphone_core_get_download_bandwidth(lc);
244 /*set audio capabilities */
245 strncpy(md->streams[0].rtp_addr,call->localip,sizeof(md->streams[0].rtp_addr));
246 strncpy(md->streams[0].rtcp_addr,call->localip,sizeof(md->streams[0].rtcp_addr));
247 md->streams[0].rtp_port=call->audio_port;
248 md->streams[0].rtcp_port=call->audio_port+1;
249 md->streams[0].proto=(call->params.media_encryption == LinphoneMediaEncryptionSRTP) ?
250 SalProtoRtpSavp : SalProtoRtpAvp;
251 md->streams[0].type=SalAudio;
252 if (call->params.down_ptime)
253 md->streams[0].ptime=call->params.down_ptime;
255 md->streams[0].ptime=linphone_core_get_download_ptime(lc);
256 l=make_codec_list(lc,lc->codecs_conf.audio_codecs,call->params.audio_bw,&md->streams[0].max_rate,-1);
257 pt=payload_type_clone(rtp_profile_get_payload_from_mime(lc->default_profile,"telephone-event"));
258 l=ms_list_append(l,pt);
259 md->streams[0].payloads=l;
261 if (call->params.has_video){
262 md->n_active_streams++;
263 md->streams[1].rtp_port=call->video_port;
264 md->streams[1].rtcp_port=call->video_port+1;
265 md->streams[1].proto=md->streams[0].proto;
266 md->streams[1].type=SalVideo;
267 l=make_codec_list(lc,lc->codecs_conf.video_codecs,0,NULL,-1);
268 md->streams[1].payloads=l;
270 if (md->n_total_streams < md->n_active_streams)
271 md->n_total_streams = md->n_active_streams;
273 /* Deactivate inactive streams. */
274 for (i = md->n_active_streams; i < md->n_total_streams; i++) {
275 md->streams[i].rtp_port = 0;
276 md->streams[i].rtcp_port = 0;
277 md->streams[i].proto = SalProtoRtpAvp;
278 md->streams[i].type = old_md->streams[i].type;
279 md->streams[i].dir = SalStreamInactive;
280 l = make_codec_list(lc, lc->codecs_conf.video_codecs, 0, NULL, 1);
281 md->streams[i].payloads = l;
284 for(i=0; i<md->n_active_streams; i++) {
285 if (md->streams[i].proto == SalProtoRtpSavp) {
286 if (keep_srtp_keys && old_md && old_md->streams[i].proto==SalProtoRtpSavp){
288 for(j=0;j<SAL_CRYPTO_ALGO_MAX;++j){
289 memcpy(&md->streams[i].crypto[j],&old_md->streams[i].crypto[j],sizeof(SalSrtpCryptoAlgo));
292 md->streams[i].crypto[0].tag = 1;
293 md->streams[i].crypto[0].algo = AES_128_SHA1_80;
294 if (!generate_b64_crypto_key(30, md->streams[i].crypto[0].master_key))
295 md->streams[i].crypto[0].algo = 0;
296 md->streams[i].crypto[1].tag = 2;
297 md->streams[i].crypto[1].algo = AES_128_SHA1_32;
298 if (!generate_b64_crypto_key(30, md->streams[i].crypto[1].master_key))
299 md->streams[i].crypto[1].algo = 0;
300 md->streams[i].crypto[2].algo = 0;
304 update_media_description_from_stun(md,&call->ac,&call->vc);
305 if (call->ice_session != NULL) {
306 linphone_core_update_local_media_description_from_ice(md, call->ice_session);
307 linphone_core_update_ice_state_in_call_stats(call);
310 if(call->upnp_session != NULL) {
311 linphone_core_update_local_media_description_from_upnp(md, call->upnp_session);
312 linphone_core_update_upnp_state_in_call_stats(call);
315 linphone_address_destroy(addr);
317 if (old_md) sal_media_description_unref(old_md);
320 static int find_port_offset(LinphoneCore *lc, SalStreamType type){
325 bool_t already_used=FALSE;
326 for(offset=0;offset<100;offset+=2){
330 tried_port=linphone_core_get_audio_port (lc)+offset;
333 tried_port=linphone_core_get_video_port (lc)+offset;
337 for(elem=lc->calls;elem!=NULL;elem=elem->next){
338 LinphoneCall *call=(LinphoneCall*)elem->data;
342 existing_port = call->audio_port;
345 existing_port = call->video_port;
348 if (existing_port==tried_port) {
353 if (!already_used) break;
356 ms_error("Could not find any free port !");
362 static int select_random_port(LinphoneCore *lc, SalStreamType type) {
366 int existing_port = 0;
367 int min_port = 0, max_port = 0;
368 bool_t already_used = FALSE;
373 linphone_core_get_audio_port_range(lc, &min_port, &max_port);
376 linphone_core_get_video_port_range(lc, &min_port, &max_port);
379 tried_port = (rand() % (max_port - min_port) + min_port) & ~0x1;
380 if (tried_port < min_port) tried_port = min_port + 2;
381 for (nb_tries = 0; nb_tries < 100; nb_tries++) {
382 for (elem = lc->calls; elem != NULL; elem = elem->next) {
383 LinphoneCall *call = (LinphoneCall *)elem->data;
387 existing_port = call->audio_port;
390 existing_port = call->video_port;
393 if (existing_port == tried_port) {
398 if (!already_used) break;
400 if (nb_tries == 100) {
401 ms_error("Could not find any free port!");
407 static void linphone_call_init_common(LinphoneCall *call, LinphoneAddress *from, LinphoneAddress *to){
409 int min_port, max_port;
410 call->magic=linphone_call_magic;
412 call->state=LinphoneCallIdle;
413 call->transfer_state = LinphoneCallIdle;
414 call->start_time=time(NULL);
415 call->media_start_time=0;
416 call->log=linphone_call_log_new(call, from, to);
417 call->owns_call_log=TRUE;
418 linphone_core_notify_all_friends(call->core,LinphoneStatusOnThePhone);
419 linphone_core_get_audio_port_range(call->core, &min_port, &max_port);
420 if (min_port == max_port) {
421 /* Used fixed RTP audio port. */
422 port_offset=find_port_offset (call->core, SalAudio);
423 if (port_offset==-1) return;
424 call->audio_port=linphone_core_get_audio_port(call->core)+port_offset;
426 /* Select random RTP audio port in the specified range. */
427 call->audio_port = select_random_port(call->core, SalAudio);
429 linphone_core_get_video_port_range(call->core, &min_port, &max_port);
430 if (min_port == max_port) {
431 /* Used fixed RTP video port. */
432 port_offset=find_port_offset (call->core, SalVideo);
433 if (port_offset==-1) return;
434 call->video_port=linphone_core_get_video_port(call->core)+port_offset;
436 /* Select random RTP video port in the specified range. */
437 call->video_port = select_random_port(call->core, SalVideo);
439 linphone_call_init_stats(&call->stats[LINPHONE_CALL_STATS_AUDIO], LINPHONE_CALL_STATS_AUDIO);
440 linphone_call_init_stats(&call->stats[LINPHONE_CALL_STATS_VIDEO], LINPHONE_CALL_STATS_VIDEO);
443 void linphone_call_init_stats(LinphoneCallStats *stats, int type) {
445 stats->received_rtcp = NULL;
446 stats->sent_rtcp = NULL;
447 stats->ice_state = LinphoneIceStateNotActivated;
449 stats->upnp_state = LinphoneUpnpStateIdle;
451 stats->upnp_state = LinphoneUpnpStateNotAvailable;
456 static void discover_mtu(LinphoneCore *lc, const char *remote){
458 if (lc->net_conf.mtu==0 ){
459 /*attempt to discover mtu*/
460 mtu=ms_discover_mtu(remote);
463 ms_message("Discovered mtu is %i, RTP payload max size is %i",
464 mtu, ms_get_payload_max_size());
469 LinphoneCall * linphone_call_new_outgoing(struct _LinphoneCore *lc, LinphoneAddress *from, LinphoneAddress *to, const LinphoneCallParams *params)
471 LinphoneCall *call=ms_new0(LinphoneCall,1);
472 call->dir=LinphoneCallOutgoing;
473 call->op=sal_op_new(lc->sal);
474 sal_op_set_user_pointer(call->op,call);
476 linphone_core_get_local_ip(lc,NULL,call->localip);
477 linphone_call_init_common(call,from,to);
478 _linphone_call_params_copy(&call->params,params);
479 sal_op_set_custom_header(call->op,call->params.custom_headers);
480 call->params.custom_headers=NULL;
482 if (linphone_core_get_firewall_policy(call->core) == LinphonePolicyUseIce) {
483 call->ice_session = ice_session_new();
484 ice_session_set_role(call->ice_session, IR_Controlling);
486 if (linphone_core_get_firewall_policy(call->core) == LinphonePolicyUseStun) {
487 call->ping_time=linphone_core_run_stun_tests(call->core,call);
490 if (linphone_core_get_firewall_policy(call->core) == LinphonePolicyUseUpnp) {
491 if(!lc->rtp_conf.disable_upnp) {
492 call->upnp_session = linphone_upnp_session_new(call);
496 call->camera_active=params->has_video;
498 discover_mtu(lc,linphone_address_get_domain (to));
499 if (params->referer){
500 sal_call_set_referer(call->op,params->referer->op);
501 call->referer=linphone_call_ref(params->referer);
506 LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *from, LinphoneAddress *to, SalOp *op){
507 LinphoneCall *call=ms_new0(LinphoneCall,1);
509 const SalMediaDescription *md;
511 call->dir=LinphoneCallIncoming;
512 sal_op_set_user_pointer(op,call);
516 if (lc->sip_conf.ping_with_options){
518 if (lc->upnp != NULL && linphone_core_get_firewall_policy(lc)==LinphonePolicyUseUpnp &&
519 linphone_upnp_context_get_state(lc->upnp) == LinphoneUpnpStateOk) {
523 /*the following sends an option request back to the caller so that
524 we get a chance to discover our nat'd address before answering.*/
525 call->ping_op=sal_op_new(lc->sal);
526 from_str=linphone_address_as_string_uri_only(from);
527 sal_op_set_route(call->ping_op,sal_op_get_network_origin(op));
528 sal_op_set_user_pointer(call->ping_op,call);
529 sal_ping(call->ping_op,linphone_core_find_best_identity(lc,from,NULL),from_str);
534 linphone_address_clean(from);
535 linphone_core_get_local_ip(lc,NULL,call->localip);
536 linphone_call_init_common(call, from, to);
537 call->log->call_id=ms_strdup(sal_op_get_call_id(op)); /*must be known at that time*/
538 linphone_core_init_default_params(lc, &call->params);
539 md=sal_call_get_remote_media_description(op);
540 call->params.has_video &= !!lc->video_policy.automatically_accept;
542 // It is licit to receive an INVITE without SDP
543 // In this case WE chose the media parameters according to policy.
544 call->params.has_video &= linphone_core_media_description_contains_video_stream(md);
546 switch (linphone_core_get_firewall_policy(call->core)) {
547 case LinphonePolicyUseIce:
548 call->ice_session = ice_session_new();
549 ice_session_set_role(call->ice_session, IR_Controlled);
550 linphone_core_update_ice_from_remote_media_description(call, sal_call_get_remote_media_description(op));
551 if (call->ice_session != NULL) {
552 linphone_call_init_media_streams(call);
553 linphone_call_start_media_streams_for_ice_gathering(call);
554 if (linphone_core_gather_ice_candidates(call->core,call)<0) {
555 /* Ice candidates gathering failed, proceed with the call anyway. */
556 linphone_call_delete_ice_session(call);
557 linphone_call_stop_media_streams_for_ice_gathering(call);
561 case LinphonePolicyUseStun:
562 call->ping_time=linphone_core_run_stun_tests(call->core,call);
563 /* No break to also destroy ice session in this case. */
565 case LinphonePolicyUseUpnp:
567 if(!lc->rtp_conf.disable_upnp) {
568 call->upnp_session = linphone_upnp_session_new(call);
569 if (call->upnp_session != NULL) {
570 linphone_call_init_media_streams(call);
571 if (linphone_core_update_upnp_from_remote_media_description(call, sal_call_get_remote_media_description(op))<0) {
572 /* uPnP port mappings failed, proceed with the call anyway. */
573 linphone_call_delete_upnp_session(call);
582 call->camera_active=call->params.has_video;
584 discover_mtu(lc,linphone_address_get_domain(from));
588 /* this function is called internally to get rid of a call.
589 It performs the following tasks:
590 - remove the call from the internal list of calls
591 - update the call logs accordingly
594 static void linphone_call_set_terminated(LinphoneCall *call){
595 LinphoneCore *lc=call->core;
597 linphone_core_update_allocated_audio_bandwidth(lc);
599 call->owns_call_log=FALSE;
600 linphone_call_log_completed(call);
603 if (call == lc->current_call){
604 ms_message("Resetting the current call");
605 lc->current_call=NULL;
608 if (linphone_core_del_call(lc,call) != 0){
609 ms_error("Could not remove the call from the list !!!");
612 if (ms_list_size(lc->calls)==0)
613 linphone_core_notify_all_friends(lc,lc->presence_mode);
615 linphone_core_conference_check_uninit(lc);
616 if (call->ringing_beep){
617 linphone_core_stop_dtmf(lc);
618 call->ringing_beep=FALSE;
621 linphone_call_unref(call->referer);
626 void linphone_call_fix_call_parameters(LinphoneCall *call){
627 call->params.has_video=call->current_params.has_video;
628 call->params.media_encryption=call->current_params.media_encryption;
631 const char *linphone_call_state_to_string(LinphoneCallState cs){
633 case LinphoneCallIdle:
634 return "LinphoneCallIdle";
635 case LinphoneCallIncomingReceived:
636 return "LinphoneCallIncomingReceived";
637 case LinphoneCallOutgoingInit:
638 return "LinphoneCallOutgoingInit";
639 case LinphoneCallOutgoingProgress:
640 return "LinphoneCallOutgoingProgress";
641 case LinphoneCallOutgoingRinging:
642 return "LinphoneCallOutgoingRinging";
643 case LinphoneCallOutgoingEarlyMedia:
644 return "LinphoneCallOutgoingEarlyMedia";
645 case LinphoneCallConnected:
646 return "LinphoneCallConnected";
647 case LinphoneCallStreamsRunning:
648 return "LinphoneCallStreamsRunning";
649 case LinphoneCallPausing:
650 return "LinphoneCallPausing";
651 case LinphoneCallPaused:
652 return "LinphoneCallPaused";
653 case LinphoneCallResuming:
654 return "LinphoneCallResuming";
655 case LinphoneCallRefered:
656 return "LinphoneCallRefered";
657 case LinphoneCallError:
658 return "LinphoneCallError";
659 case LinphoneCallEnd:
660 return "LinphoneCallEnd";
661 case LinphoneCallPausedByRemote:
662 return "LinphoneCallPausedByRemote";
663 case LinphoneCallUpdatedByRemote:
664 return "LinphoneCallUpdatedByRemote";
665 case LinphoneCallIncomingEarlyMedia:
666 return "LinphoneCallIncomingEarlyMedia";
667 case LinphoneCallUpdating:
668 return "LinphoneCallUpdating";
669 case LinphoneCallReleased:
670 return "LinphoneCallReleased";
672 return "undefined state";
675 void linphone_call_set_state(LinphoneCall *call, LinphoneCallState cstate, const char *message){
676 LinphoneCore *lc=call->core;
678 if (call->state!=cstate){
679 if (call->state==LinphoneCallEnd || call->state==LinphoneCallError){
680 if (cstate!=LinphoneCallReleased){
681 ms_warning("Spurious call state change from %s to %s, ignored.",linphone_call_state_to_string(call->state),
682 linphone_call_state_to_string(cstate));
686 ms_message("Call %p: moving from state %s to %s",call,linphone_call_state_to_string(call->state),
687 linphone_call_state_to_string(cstate));
688 if (cstate!=LinphoneCallRefered){
689 /*LinphoneCallRefered is rather an event, not a state.
690 Indeed it does not change the state of the call (still paused or running)*/
693 if (cstate==LinphoneCallEnd || cstate==LinphoneCallError){
694 switch(call->reason){
695 case LinphoneReasonDeclined:
696 call->log->status=LinphoneCallDeclined;
698 case LinphoneReasonNotAnswered:
699 call->log->status=LinphoneCallMissed;
704 linphone_call_set_terminated (call);
706 if (cstate == LinphoneCallConnected) {
707 call->log->status=LinphoneCallSuccess;
708 call->media_start_time=time(NULL);
711 if (lc->vtable.call_state_changed)
712 lc->vtable.call_state_changed(lc,call,cstate,message);
713 if (cstate==LinphoneCallReleased){
714 if (call->op!=NULL) {
715 /* so that we cannot have anymore upcalls for SAL
716 concerning this call*/
717 sal_op_release(call->op);
720 linphone_call_unref(call);
725 static void linphone_call_destroy(LinphoneCall *obj)
728 linphone_call_delete_upnp_session(obj);
730 linphone_call_delete_ice_session(obj);
732 sal_op_release(obj->op);
735 if (obj->resultdesc!=NULL) {
736 sal_media_description_unref(obj->resultdesc);
737 obj->resultdesc=NULL;
739 if (obj->localdesc!=NULL) {
740 sal_media_description_unref(obj->localdesc);
744 sal_op_release(obj->ping_op);
747 ms_free(obj->refer_to);
749 if (obj->owns_call_log)
750 linphone_call_log_destroy(obj->log);
751 if (obj->auth_token) {
752 ms_free(obj->auth_token);
754 linphone_call_params_uninit(&obj->params);
759 * @addtogroup call_control
764 * Increments the call 's reference count.
765 * An application that wishes to retain a pointer to call object
766 * must use this function to unsure the pointer remains
767 * valid. Once the application no more needs this pointer,
768 * it must call linphone_call_unref().
770 LinphoneCall * linphone_call_ref(LinphoneCall *obj){
776 * Decrements the call object reference count.
777 * See linphone_call_ref().
779 void linphone_call_unref(LinphoneCall *obj){
782 linphone_call_destroy(obj);
787 * Returns current parameters associated to the call.
789 const LinphoneCallParams * linphone_call_get_current_params(LinphoneCall *call){
790 if (call->params.record_file)
791 call->current_params.record_file=call->params.record_file;
792 return &call->current_params;
795 static bool_t is_video_active(const SalStreamDescription *sd){
796 return sd->rtp_port!=0 && sd->dir!=SalStreamInactive;
800 * Returns call parameters proposed by remote.
802 * This is useful when receiving an incoming call, to know whether the remote party
803 * supports video, encryption or whatever.
805 const LinphoneCallParams * linphone_call_get_remote_params(LinphoneCall *call){
806 LinphoneCallParams *cp=&call->remote_params;
807 memset(cp,0,sizeof(*cp));
809 SalMediaDescription *md=sal_call_get_remote_media_description(call->op);
811 SalStreamDescription *asd,*vsd,*secure_asd,*secure_vsd;
813 asd=sal_media_description_find_stream(md,SalProtoRtpAvp,SalAudio);
814 vsd=sal_media_description_find_stream(md,SalProtoRtpAvp,SalVideo);
815 secure_asd=sal_media_description_find_stream(md,SalProtoRtpSavp,SalAudio);
816 secure_vsd=sal_media_description_find_stream(md,SalProtoRtpSavp,SalVideo);
818 cp->has_video=is_video_active(secure_vsd);
819 if (secure_asd || asd==NULL)
820 cp->media_encryption=LinphoneMediaEncryptionSRTP;
822 cp->has_video=is_video_active(vsd);
825 if (md->bandwidth>0 && md->bandwidth<=linphone_core_get_edge_bw(call->core)){
826 cp->low_bandwidth=TRUE;
829 cp->custom_headers=(SalCustomHeader*)sal_op_get_custom_header(call->op);
837 * Returns the remote address associated to this call
840 const LinphoneAddress * linphone_call_get_remote_address(const LinphoneCall *call){
841 return call->dir==LinphoneCallIncoming ? call->log->from : call->log->to;
845 * Returns the remote address associated to this call as a string.
847 * The result string must be freed by user using ms_free().
849 char *linphone_call_get_remote_address_as_string(const LinphoneCall *call){
850 return linphone_address_as_string(linphone_call_get_remote_address(call));
854 * Retrieves the call's current state.
856 LinphoneCallState linphone_call_get_state(const LinphoneCall *call){
861 * Returns the reason for a call termination (either error or normal termination)
863 LinphoneReason linphone_call_get_reason(const LinphoneCall *call){
868 * Get the user_pointer in the LinphoneCall
870 * @ingroup call_control
872 * return user_pointer an opaque user pointer that can be retrieved at any time
874 void *linphone_call_get_user_pointer(LinphoneCall *call)
876 return call->user_pointer;
880 * Set the user_pointer in the LinphoneCall
882 * @ingroup call_control
884 * the user_pointer is an opaque user pointer that can be retrieved at any time in the LinphoneCall
886 void linphone_call_set_user_pointer(LinphoneCall *call, void *user_pointer)
888 call->user_pointer = user_pointer;
892 * Returns the call log associated to this call.
894 LinphoneCallLog *linphone_call_get_call_log(const LinphoneCall *call){
899 * Returns the refer-to uri (if the call was transfered).
901 const char *linphone_call_get_refer_to(const LinphoneCall *call){
902 return call->refer_to;
906 * Returns direction of the call (incoming or outgoing).
908 LinphoneCallDir linphone_call_get_dir(const LinphoneCall *call){
909 return call->log->dir;
913 * Returns the far end's user agent description string, if available.
915 const char *linphone_call_get_remote_user_agent(LinphoneCall *call){
917 return sal_op_get_remote_ua (call->op);
923 * Returns the far end's sip contact as a string, if available.
925 const char *linphone_call_get_remote_contact(LinphoneCall *call){
927 return sal_op_get_remote_contact(call->op);
933 * Returns true if this calls has received a transfer that has not been
935 * Pending transfers are executed when this call is being paused or closed,
936 * locally or by remote endpoint.
937 * If the call is already paused while receiving the transfer request, the
938 * transfer immediately occurs.
940 bool_t linphone_call_has_transfer_pending(const LinphoneCall *call){
941 return call->refer_pending;
945 * Returns call's duration in seconds.
947 int linphone_call_get_duration(const LinphoneCall *call){
948 if (call->media_start_time==0) return 0;
949 return time(NULL)-call->media_start_time;
953 * Returns the call object this call is replacing, if any.
954 * Call replacement can occur during call transfers.
955 * By default, the core automatically terminates the replaced call and accept the new one.
956 * This function allows the application to know whether a new incoming call is a one that replaces another one.
958 LinphoneCall *linphone_call_get_replaced_call(LinphoneCall *call){
959 SalOp *op=sal_call_get_replaces(call->op);
961 return (LinphoneCall*)sal_op_get_user_pointer(op);
967 * Indicate whether camera input should be sent to remote end.
969 void linphone_call_enable_camera (LinphoneCall *call, bool_t enable){
971 if (call->videostream!=NULL && call->videostream->ms.ticker!=NULL){
972 LinphoneCore *lc=call->core;
973 MSWebCam *nowebcam=get_nowebcam_device();
974 if (call->camera_active!=enable && lc->video_conf.device!=nowebcam){
975 video_stream_change_camera(call->videostream,
976 enable ? lc->video_conf.device : nowebcam);
979 call->camera_active=enable;
985 * Request remote side to send us a Video Fast Update.
987 void linphone_call_send_vfu_request(LinphoneCall *call)
989 if (LinphoneCallStreamsRunning == linphone_call_get_state(call))
990 sal_call_send_vfu_request(call->op);
996 * Take a photo of currently received video and write it into a jpeg file.
998 int linphone_call_take_video_snapshot(LinphoneCall *call, const char *file){
1000 if (call->videostream!=NULL && call->videostream->jpegwriter!=NULL){
1001 return ms_filter_call_method(call->videostream->jpegwriter,MS_JPEG_WRITER_TAKE_SNAPSHOT,(void*)file);
1003 ms_warning("Cannot take snapshot: no currently running video stream on this call.");
1010 * Returns TRUE if camera pictures are sent to the remote party.
1012 bool_t linphone_call_camera_enabled (const LinphoneCall *call){
1013 return call->camera_active;
1017 * Enable video stream.
1019 void linphone_call_params_enable_video(LinphoneCallParams *cp, bool_t enabled){
1020 cp->has_video=enabled;
1024 * Returns the audio codec used in the call, described as a PayloadType structure.
1026 const PayloadType* linphone_call_params_get_used_audio_codec(const LinphoneCallParams *cp) {
1027 return cp->audio_codec;
1032 * Returns the video codec used in the call, described as a PayloadType structure.
1034 const PayloadType* linphone_call_params_get_used_video_codec(const LinphoneCallParams *cp) {
1035 return cp->video_codec;
1039 * @ingroup call_control
1040 * Use to know if this call has been configured in low bandwidth mode.
1041 * This mode can be automatically discovered thanks to a stun server when activate_edge_workarounds=1 in section [net] of configuration file.
1042 * An application that would have reliable way to know network capacity may not use activate_edge_workarounds=1 but instead manually configure
1043 * low bandwidth mode with linphone_call_params_enable_low_bandwidth().
1044 * <br> When enabled, this param may transform a call request with video in audio only mode.
1045 * @return TRUE if low bandwidth has been configured/detected
1047 bool_t linphone_call_params_low_bandwidth_enabled(const LinphoneCallParams *cp) {
1048 return cp->low_bandwidth;
1052 * @ingroup call_control
1053 * Indicate low bandwith mode.
1054 * 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
1055 * 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
1056 * that it is achievable by the codec selected after SDP handshake. Video is automatically disabled.
1059 void linphone_call_params_enable_low_bandwidth(LinphoneCallParams *cp, bool_t enabled){
1060 cp->low_bandwidth=enabled;
1064 * Returns whether video is enabled.
1066 bool_t linphone_call_params_video_enabled(const LinphoneCallParams *cp){
1067 return cp->has_video;
1071 * Returns kind of media encryption selected for the call.
1073 enum LinphoneMediaEncryption linphone_call_params_get_media_encryption(const LinphoneCallParams *cp) {
1074 return cp->media_encryption;
1078 * Set requested media encryption for a call.
1080 void linphone_call_params_set_media_encryption(LinphoneCallParams *cp, enum LinphoneMediaEncryption e) {
1081 cp->media_encryption = e;
1086 * Enable sending of real early media (during outgoing calls).
1088 void linphone_call_params_enable_early_media_sending(LinphoneCallParams *cp, bool_t enabled){
1089 cp->real_early_media=enabled;
1093 * Indicates whether sending of early media was enabled.
1095 bool_t linphone_call_params_early_media_sending_enabled(const LinphoneCallParams *cp){
1096 return cp->real_early_media;
1100 * Returns true if the call is part of the locally managed conference.
1102 bool_t linphone_call_params_local_conference_mode(const LinphoneCallParams *cp){
1103 return cp->in_conference;
1107 * Refine bandwidth settings for this call by setting a bandwidth limit for audio streams.
1108 * As a consequence, codecs whose bitrates are not compatible with this limit won't be used.
1110 void linphone_call_params_set_audio_bandwidth_limit(LinphoneCallParams *cp, int bandwidth){
1111 cp->audio_bw=bandwidth;
1114 void linphone_call_params_add_custom_header(LinphoneCallParams *params, const char *header_name, const char *header_value){
1115 params->custom_headers=sal_custom_header_append(params->custom_headers,header_name,header_value);
1118 const char *linphone_call_params_get_custom_header(const LinphoneCallParams *params, const char *header_name){
1119 return sal_custom_header_find(params->custom_headers,header_name);
1122 void _linphone_call_params_copy(LinphoneCallParams *ncp, const LinphoneCallParams *cp){
1123 memcpy(ncp,cp,sizeof(LinphoneCallParams));
1124 if (cp->record_file) ncp->record_file=ms_strdup(cp->record_file);
1126 * The management of the custom headers is not optimal. We copy everything while ref counting would be more efficient.
1128 if (cp->custom_headers) ncp->custom_headers=sal_custom_header_clone(cp->custom_headers);
1132 * Copy existing LinphoneCallParams to a new LinphoneCallParams object.
1134 LinphoneCallParams * linphone_call_params_copy(const LinphoneCallParams *cp){
1135 LinphoneCallParams *ncp=ms_new0(LinphoneCallParams,1);
1136 _linphone_call_params_copy(ncp,cp);
1140 void linphone_call_params_uninit(LinphoneCallParams *p){
1141 if (p->record_file) ms_free(p->record_file);
1142 if (p->custom_headers) sal_custom_header_free(p->custom_headers);
1146 * Destroy LinphoneCallParams.
1148 void linphone_call_params_destroy(LinphoneCallParams *p){
1149 linphone_call_params_uninit(p);
1159 #ifdef TEST_EXT_RENDERER
1160 static void rendercb(void *data, const MSPicture *local, const MSPicture *remote){
1161 ms_message("rendercb, local buffer=%p, remote buffer=%p",
1162 local ? local->planes[0] : NULL, remote? remote->planes[0] : NULL);
1166 #ifdef VIDEO_ENABLED
1167 static void video_stream_event_cb(void *user_pointer, const MSFilter *f, const unsigned int event_id, const void *args){
1168 LinphoneCall* call = (LinphoneCall*) user_pointer;
1169 ms_warning("In linphonecall.c: video_stream_event_cb");
1171 case MS_VIDEO_DECODER_DECODING_ERRORS:
1172 ms_warning("Case is MS_VIDEO_DECODER_DECODING_ERRORS");
1173 linphone_call_send_vfu_request(call);
1175 case MS_VIDEO_DECODER_FIRST_IMAGE_DECODED:
1176 ms_message("First video frame decoded successfully");
1177 if (call->nextVideoFrameDecoded._func != NULL)
1178 call->nextVideoFrameDecoded._func(call, call->nextVideoFrameDecoded._user_data);
1181 ms_warning("Unhandled event %i", event_id);
1187 void linphone_call_set_next_video_frame_decoded_callback(LinphoneCall *call, LinphoneCallCbFunc cb, void* user_data) {
1188 call->nextVideoFrameDecoded._func = cb;
1189 call->nextVideoFrameDecoded._user_data = user_data;
1190 #ifdef VIDEO_ENABLED
1191 ms_filter_call_method_noarg(call->videostream->ms.decoder, MS_VIDEO_DECODER_RESET_FIRST_IMAGE_NOTIFICATION);
1195 void linphone_call_init_audio_stream(LinphoneCall *call){
1196 LinphoneCore *lc=call->core;
1197 AudioStream *audiostream;
1200 if (call->audiostream != NULL) return;
1201 call->audiostream=audiostream=audio_stream_new(call->audio_port,call->audio_port+1,linphone_core_ipv6_enabled(lc));
1202 dscp=linphone_core_get_audio_dscp(lc);
1204 audio_stream_set_dscp(audiostream,dscp);
1205 if (linphone_core_echo_limiter_enabled(lc)){
1206 const char *type=lp_config_get_string(lc->config,"sound","el_type","mic");
1207 if (strcasecmp(type,"mic")==0)
1208 audio_stream_enable_echo_limiter(audiostream,ELControlMic);
1209 else if (strcasecmp(type,"full")==0)
1210 audio_stream_enable_echo_limiter(audiostream,ELControlFull);
1212 audio_stream_enable_gain_control(audiostream,TRUE);
1213 if (linphone_core_echo_cancellation_enabled(lc)){
1214 int len,delay,framesize;
1215 const char *statestr=lp_config_get_string(lc->config,"sound","ec_state",NULL);
1216 len=lp_config_get_int(lc->config,"sound","ec_tail_len",0);
1217 delay=lp_config_get_int(lc->config,"sound","ec_delay",0);
1218 framesize=lp_config_get_int(lc->config,"sound","ec_framesize",0);
1219 audio_stream_set_echo_canceller_params(audiostream,len,delay,framesize);
1220 if (statestr && audiostream->ec){
1221 ms_filter_call_method(audiostream->ec,MS_ECHO_CANCELLER_SET_STATE_STRING,(void*)statestr);
1224 audio_stream_enable_automatic_gain_control(audiostream,linphone_core_agc_enabled(lc));
1226 int enabled=lp_config_get_int(lc->config,"sound","noisegate",0);
1227 audio_stream_enable_noise_gate(audiostream,enabled);
1230 audio_stream_set_features(audiostream,linphone_core_get_audio_features(lc));
1233 RtpTransport *artp=lc->rtptf->audio_rtp_func(lc->rtptf->audio_rtp_func_data, call->audio_port);
1234 RtpTransport *artcp=lc->rtptf->audio_rtcp_func(lc->rtptf->audio_rtcp_func_data, call->audio_port+1);
1235 rtp_session_set_transports(audiostream->ms.session,artp,artcp);
1237 if ((linphone_core_get_firewall_policy(lc) == LinphonePolicyUseIce) && (call->ice_session != NULL)){
1238 rtp_session_set_pktinfo(audiostream->ms.session, TRUE);
1239 rtp_session_set_symmetric_rtp(audiostream->ms.session, FALSE);
1240 if (ice_session_check_list(call->ice_session, 0) == NULL) {
1241 ice_session_add_check_list(call->ice_session, ice_check_list_new());
1243 audiostream->ms.ice_check_list = ice_session_check_list(call->ice_session, 0);
1244 ice_check_list_set_rtp_session(audiostream->ms.ice_check_list, audiostream->ms.session);
1247 call->audiostream_app_evq = ortp_ev_queue_new();
1248 rtp_session_register_event_queue(audiostream->ms.session,call->audiostream_app_evq);
1251 void linphone_call_init_video_stream(LinphoneCall *call){
1252 #ifdef VIDEO_ENABLED
1253 LinphoneCore *lc=call->core;
1255 if (!call->params.has_video) {
1256 linphone_call_stop_video_stream(call);
1259 if (call->videostream != NULL) return;
1260 if ((lc->video_conf.display || lc->video_conf.capture) && call->params.has_video){
1261 int video_recv_buf_size=lp_config_get_int(lc->config,"video","recv_buf_size",0);
1262 int dscp=linphone_core_get_video_dscp(lc);
1264 call->videostream=video_stream_new(call->video_port,call->video_port+1,linphone_core_ipv6_enabled(lc));
1266 video_stream_set_dscp(call->videostream,dscp);
1267 video_stream_enable_display_filter_auto_rotate(call->videostream, lp_config_get_int(lc->config,"video","display_filter_auto_rotate",0));
1268 if (video_recv_buf_size>0) rtp_session_set_recv_buf_size(call->videostream->ms.session,video_recv_buf_size);
1270 if( lc->video_conf.displaytype != NULL)
1271 video_stream_set_display_filter_name(call->videostream,lc->video_conf.displaytype);
1272 video_stream_set_event_callback(call->videostream,video_stream_event_cb, call);
1274 RtpTransport *vrtp=lc->rtptf->video_rtp_func(lc->rtptf->video_rtp_func_data, call->video_port);
1275 RtpTransport *vrtcp=lc->rtptf->video_rtcp_func(lc->rtptf->video_rtcp_func_data, call->video_port+1);
1276 rtp_session_set_transports(call->videostream->ms.session,vrtp,vrtcp);
1278 if ((linphone_core_get_firewall_policy(lc) == LinphonePolicyUseIce) && (call->ice_session != NULL)){
1279 rtp_session_set_pktinfo(call->videostream->ms.session, TRUE);
1280 rtp_session_set_symmetric_rtp(call->videostream->ms.session, FALSE);
1281 if (ice_session_check_list(call->ice_session, 1) == NULL) {
1282 ice_session_add_check_list(call->ice_session, ice_check_list_new());
1284 call->videostream->ms.ice_check_list = ice_session_check_list(call->ice_session, 1);
1285 ice_check_list_set_rtp_session(call->videostream->ms.ice_check_list, call->videostream->ms.session);
1287 call->videostream_app_evq = ortp_ev_queue_new();
1288 rtp_session_register_event_queue(call->videostream->ms.session,call->videostream_app_evq);
1289 #ifdef TEST_EXT_RENDERER
1290 video_stream_set_render_callback(call->videostream,rendercb,NULL);
1294 call->videostream=NULL;
1298 void linphone_call_init_media_streams(LinphoneCall *call){
1299 linphone_call_init_audio_stream(call);
1300 linphone_call_init_video_stream(call);
1304 static int dtmf_tab[16]={'0','1','2','3','4','5','6','7','8','9','*','#','A','B','C','D'};
1306 static void linphone_core_dtmf_received(LinphoneCore *lc, int dtmf){
1307 if (dtmf<0 || dtmf>15){
1308 ms_warning("Bad dtmf value %i",dtmf);
1311 if (lc->vtable.dtmf_received != NULL)
1312 lc->vtable.dtmf_received(lc, linphone_core_get_current_call(lc), dtmf_tab[dtmf]);
1315 static void parametrize_equalizer(LinphoneCore *lc, AudioStream *st){
1317 MSFilter *f=st->equalizer;
1318 int enabled=lp_config_get_int(lc->config,"sound","eq_active",0);
1319 const char *gains=lp_config_get_string(lc->config,"sound","eq_gains",NULL);
1320 ms_filter_call_method(f,MS_EQUALIZER_SET_ACTIVE,&enabled);
1326 if (sscanf(gains,"%f:%f:%f %n",&g.frequency,&g.gain,&g.width,&bytes)==3){
1327 ms_message("Read equalizer gains: %f(~%f) --> %f",g.frequency,g.width,g.gain);
1328 ms_filter_call_method(f,MS_EQUALIZER_SET_GAIN,&g);
1337 void _post_configure_audio_stream(AudioStream *st, LinphoneCore *lc, bool_t muted){
1338 float mic_gain=lc->sound_conf.soft_mic_lev;
1341 float ng_thres=lp_config_get_float(lc->config,"sound","ng_thres",0.05);
1342 float ng_floorgain=lp_config_get_float(lc->config,"sound","ng_floorgain",0);
1343 int dc_removal=lp_config_get_int(lc->config,"sound","dc_removal",0);
1346 linphone_core_set_mic_gain_db (lc, mic_gain);
1348 audio_stream_set_mic_gain(st,0);
1350 recv_gain = lc->sound_conf.soft_play_lev;
1351 if (recv_gain != 0) {
1352 linphone_core_set_playback_gain_db (lc,recv_gain);
1356 ms_filter_call_method(st->volsend,MS_VOLUME_REMOVE_DC,&dc_removal);
1357 float speed=lp_config_get_float(lc->config,"sound","el_speed",-1);
1358 thres=lp_config_get_float(lc->config,"sound","el_thres",-1);
1359 float force=lp_config_get_float(lc->config,"sound","el_force",-1);
1360 int sustain=lp_config_get_int(lc->config,"sound","el_sustain",-1);
1361 float transmit_thres=lp_config_get_float(lc->config,"sound","el_transmit_thres",-1);
1364 if (speed==-1) speed=0.03;
1365 if (force==-1) force=25;
1366 ms_filter_call_method(f,MS_VOLUME_SET_EA_SPEED,&speed);
1367 ms_filter_call_method(f,MS_VOLUME_SET_EA_FORCE,&force);
1369 ms_filter_call_method(f,MS_VOLUME_SET_EA_THRESHOLD,&thres);
1371 ms_filter_call_method(f,MS_VOLUME_SET_EA_SUSTAIN,&sustain);
1372 if (transmit_thres!=-1)
1373 ms_filter_call_method(f,MS_VOLUME_SET_EA_TRANSMIT_THRESHOLD,&transmit_thres);
1375 ms_filter_call_method(st->volsend,MS_VOLUME_SET_NOISE_GATE_THRESHOLD,&ng_thres);
1376 ms_filter_call_method(st->volsend,MS_VOLUME_SET_NOISE_GATE_FLOORGAIN,&ng_floorgain);
1379 /* parameters for a limited noise-gate effect, using echo limiter threshold */
1380 float floorgain = 1/pow(10,(mic_gain)/10);
1381 int spk_agc=lp_config_get_int(lc->config,"sound","speaker_agc_enabled",0);
1382 ms_filter_call_method(st->volrecv, MS_VOLUME_ENABLE_AGC, &spk_agc);
1383 ms_filter_call_method(st->volrecv,MS_VOLUME_SET_NOISE_GATE_THRESHOLD,&ng_thres);
1384 ms_filter_call_method(st->volrecv,MS_VOLUME_SET_NOISE_GATE_FLOORGAIN,&floorgain);
1386 parametrize_equalizer(lc,st);
1389 static void post_configure_audio_streams(LinphoneCall*call){
1390 AudioStream *st=call->audiostream;
1391 LinphoneCore *lc=call->core;
1392 _post_configure_audio_stream(st,lc,call->audio_muted);
1393 if (lc->vtable.dtmf_received!=NULL){
1394 audio_stream_play_received_dtmfs(call->audiostream,FALSE);
1396 if (call->record_active)
1397 linphone_call_start_recording(call);
1400 static RtpProfile *make_profile(LinphoneCall *call, const SalMediaDescription *md, const SalStreamDescription *desc, int *used_pt){
1403 RtpProfile *prof=rtp_profile_new("Call profile");
1406 LinphoneCore *lc=call->core;
1408 const LinphoneCallParams *params=&call->params;
1411 for(elem=desc->payloads;elem!=NULL;elem=elem->next){
1412 PayloadType *pt=(PayloadType*)elem->data;
1415 if ((pt->flags & PAYLOAD_TYPE_FLAG_CAN_SEND) && first) {
1416 if (desc->type==SalAudio){
1417 linphone_core_update_allocated_audio_bandwidth_in_call(call,pt);
1418 if (params->up_ptime)
1419 up_ptime=params->up_ptime;
1420 else up_ptime=linphone_core_get_upload_ptime(lc);
1422 *used_pt=payload_type_get_number(pt);
1425 if (desc->bandwidth>0) remote_bw=desc->bandwidth;
1426 else if (md->bandwidth>0) {
1427 /*case where b=AS is given globally, not per stream*/
1428 remote_bw=md->bandwidth;
1429 if (desc->type==SalVideo){
1430 remote_bw=get_video_bandwidth(remote_bw,call->audio_bw);
1434 if (desc->type==SalAudio){
1435 int audio_bw=call->audio_bw;
1437 if (params->up_bw< audio_bw)
1438 audio_bw=params->up_bw;
1440 bw=get_min_bandwidth(audio_bw,remote_bw);
1441 }else bw=get_min_bandwidth(get_video_bandwidth(linphone_core_get_upload_bandwidth (lc),call->audio_bw),remote_bw);
1442 if (bw>0) pt->normal_bitrate=bw*1000;
1443 else if (desc->type==SalAudio){
1444 pt->normal_bitrate=-1;
1447 up_ptime=desc->ptime;
1451 snprintf(tmp,sizeof(tmp),"ptime=%i",up_ptime);
1452 payload_type_append_send_fmtp(pt,tmp);
1454 number=payload_type_get_number(pt);
1455 if (rtp_profile_get_payload(prof,number)!=NULL){
1456 ms_warning("A payload type with number %i already exists in profile !",number);
1458 rtp_profile_set_payload(prof,number,pt);
1464 static void setup_ring_player(LinphoneCore *lc, LinphoneCall *call){
1465 int pause_time=3000;
1466 audio_stream_play(call->audiostream,lc->sound_conf.ringback_tone);
1467 ms_filter_call_method(call->audiostream->soundread,MS_FILE_PLAYER_LOOP,&pause_time);
1470 static bool_t linphone_call_sound_resources_available(LinphoneCall *call){
1471 LinphoneCore *lc=call->core;
1472 LinphoneCall *current=linphone_core_get_current_call(lc);
1473 return !linphone_core_is_in_conference(lc) &&
1474 (current==NULL || current==call);
1476 static int find_crypto_index_from_tag(const SalSrtpCryptoAlgo crypto[],unsigned char tag) {
1478 for(i=0; i<SAL_CRYPTO_ALGO_MAX; i++) {
1479 if (crypto[i].tag == tag) {
1485 static void linphone_call_start_audio_stream(LinphoneCall *call, const char *cname, bool_t muted, bool_t send_ringbacktone, bool_t use_arc){
1486 LinphoneCore *lc=call->core;
1488 char rtcp_tool[128]={0};
1489 snprintf(rtcp_tool,sizeof(rtcp_tool)-1,"%s-%s",linphone_core_get_user_agent_name(),linphone_core_get_user_agent_version());
1490 /* look for savp stream first */
1491 const SalStreamDescription *stream=sal_media_description_find_stream(call->resultdesc,
1492 SalProtoRtpSavp,SalAudio);
1493 /* no savp audio stream, use avp */
1495 stream=sal_media_description_find_stream(call->resultdesc,
1496 SalProtoRtpAvp,SalAudio);
1498 if (stream && stream->dir!=SalStreamInactive && stream->rtp_port!=0){
1499 MSSndCard *playcard=lc->sound_conf.lsd_card ?
1500 lc->sound_conf.lsd_card : lc->sound_conf.play_sndcard;
1501 MSSndCard *captcard=lc->sound_conf.capt_sndcard;
1502 const char *playfile=lc->play_file;
1503 const char *recfile=lc->rec_file;
1504 call->audio_profile=make_profile(call,call->resultdesc,stream,&used_pt);
1508 call->current_params.audio_codec = rtp_profile_get_payload(call->audio_profile, used_pt);
1509 if (playcard==NULL) {
1510 ms_warning("No card defined for playback !");
1512 if (captcard==NULL) {
1513 ms_warning("No card defined for capture !");
1515 /*Replace soundcard filters by inactive file players or recorders
1516 when placed in recvonly or sendonly mode*/
1517 if (stream->rtp_port==0 || stream->dir==SalStreamRecvOnly){
1520 }else if (stream->dir==SalStreamSendOnly){
1524 /*And we will eventually play "playfile" if set by the user*/
1527 if (send_ringbacktone){
1529 playfile=NULL;/* it is setup later*/
1531 /*if playfile are supplied don't use soundcards*/
1532 if (lc->use_files) {
1536 if (call->params.in_conference){
1537 /* first create the graph without soundcard resources*/
1538 captcard=playcard=NULL;
1540 if (!linphone_call_sound_resources_available(call)){
1541 ms_message("Sound resources are used by another call, not using soundcard.");
1542 captcard=playcard=NULL;
1544 use_ec=captcard==NULL ? FALSE : linphone_core_echo_cancellation_enabled(lc);
1545 if (playcard && stream->max_rate>0) ms_snd_card_set_preferred_sample_rate(playcard, stream->max_rate);
1546 if (captcard && stream->max_rate>0) ms_snd_card_set_preferred_sample_rate(captcard, stream->max_rate);
1547 audio_stream_enable_adaptive_bitrate_control(call->audiostream,use_arc);
1548 audio_stream_enable_adaptive_jittcomp(call->audiostream, linphone_core_audio_adaptive_jittcomp_enabled(lc));
1549 if (!call->params.in_conference && call->params.record_file)
1550 audio_stream_mixed_record_open(call->audiostream,call->params.record_file);
1551 audio_stream_start_full(
1553 call->audio_profile,
1554 stream->rtp_addr[0]!='\0' ? stream->rtp_addr : call->resultdesc->addr,
1556 stream->rtcp_addr[0]!='\0' ? stream->rtcp_addr : call->resultdesc->addr,
1557 linphone_core_rtcp_enabled(lc) ? (stream->rtcp_port) : 0,
1559 linphone_core_get_audio_jittcomp(lc),
1566 post_configure_audio_streams(call);
1567 if (muted && !send_ringbacktone){
1568 audio_stream_set_mic_gain(call->audiostream,0);
1570 if (stream->dir==SalStreamSendOnly && playfile!=NULL){
1572 ms_filter_call_method(call->audiostream->soundread,MS_FILE_PLAYER_LOOP,&pause_time);
1574 if (send_ringbacktone){
1575 setup_ring_player(lc,call);
1577 audio_stream_set_rtcp_information(call->audiostream, cname, rtcp_tool);
1579 /* valid local tags are > 0 */
1580 if (stream->proto == SalProtoRtpSavp) {
1581 const SalStreamDescription *local_st_desc=sal_media_description_find_stream(call->localdesc,
1582 SalProtoRtpSavp,SalAudio);
1583 int crypto_idx = find_crypto_index_from_tag(local_st_desc->crypto, stream->crypto_local_tag);
1585 if (crypto_idx >= 0) {
1586 audio_stream_enable_srtp(
1588 stream->crypto[0].algo,
1589 local_st_desc->crypto[crypto_idx].master_key,
1590 stream->crypto[0].master_key);
1591 call->audiostream_encrypted=TRUE;
1593 ms_warning("Failed to find local crypto algo with tag: %d", stream->crypto_local_tag);
1594 call->audiostream_encrypted=FALSE;
1596 }else call->audiostream_encrypted=FALSE;
1597 if (call->params.in_conference){
1598 /*transform the graph to connect it to the conference filter */
1599 bool_t mute=stream->dir==SalStreamRecvOnly;
1600 linphone_call_add_to_conf(call, mute);
1602 call->current_params.in_conference=call->params.in_conference;
1603 call->current_params.low_bandwidth=call->params.low_bandwidth;
1604 }else ms_warning("No audio stream accepted ?");
1608 static void linphone_call_start_video_stream(LinphoneCall *call, const char *cname,bool_t all_inputs_muted){
1609 #ifdef VIDEO_ENABLED
1610 LinphoneCore *lc=call->core;
1612 /* look for savp stream first */
1613 const SalStreamDescription *vstream=sal_media_description_find_stream(call->resultdesc,
1614 SalProtoRtpSavp,SalVideo);
1615 char rtcp_tool[128]={0};
1616 snprintf(rtcp_tool,sizeof(rtcp_tool)-1,"%s-%s",linphone_core_get_user_agent_name(),linphone_core_get_user_agent_version());
1618 /* no savp audio stream, use avp */
1620 vstream=sal_media_description_find_stream(call->resultdesc,
1621 SalProtoRtpAvp,SalVideo);
1623 /* shutdown preview */
1624 if (lc->previewstream!=NULL) {
1625 video_preview_stop(lc->previewstream);
1626 lc->previewstream=NULL;
1629 if (vstream!=NULL && vstream->dir!=SalStreamInactive && vstream->rtp_port!=0) {
1630 const char *rtp_addr=vstream->rtp_addr[0]!='\0' ? vstream->rtp_addr : call->resultdesc->addr;
1631 const char *rtcp_addr=vstream->rtcp_addr[0]!='\0' ? vstream->rtcp_addr : call->resultdesc->addr;
1632 call->video_profile=make_profile(call,call->resultdesc,vstream,&used_pt);
1634 VideoStreamDir dir=VideoStreamSendRecv;
1635 MSWebCam *cam=lc->video_conf.device;
1636 bool_t is_inactive=FALSE;
1638 call->current_params.video_codec = rtp_profile_get_payload(call->video_profile, used_pt);
1639 call->current_params.has_video=TRUE;
1641 video_stream_enable_adaptive_bitrate_control(call->videostream,
1642 linphone_core_adaptive_rate_control_enabled(lc));
1643 video_stream_enable_adaptive_jittcomp(call->videostream, linphone_core_video_adaptive_jittcomp_enabled(lc));
1644 video_stream_set_sent_video_size(call->videostream,linphone_core_get_preferred_video_size(lc));
1645 video_stream_enable_self_view(call->videostream,lc->video_conf.selfview);
1646 if (lc->video_window_id!=0)
1647 video_stream_set_native_window_id(call->videostream,lc->video_window_id);
1648 if (lc->preview_window_id!=0)
1649 video_stream_set_native_preview_window_id (call->videostream,lc->preview_window_id);
1650 video_stream_use_preview_video_window (call->videostream,lc->use_preview_window);
1652 if (vstream->dir==SalStreamSendOnly && lc->video_conf.capture ){
1653 cam=get_nowebcam_device();
1654 dir=VideoStreamSendOnly;
1655 }else if (vstream->dir==SalStreamRecvOnly && lc->video_conf.display ){
1656 dir=VideoStreamRecvOnly;
1657 }else if (vstream->dir==SalStreamSendRecv){
1658 if (lc->video_conf.display && lc->video_conf.capture)
1659 dir=VideoStreamSendRecv;
1660 else if (lc->video_conf.display)
1661 dir=VideoStreamRecvOnly;
1663 dir=VideoStreamSendOnly;
1665 ms_warning("video stream is inactive.");
1666 /*either inactive or incompatible with local capabilities*/
1669 if (call->camera_active==FALSE || all_inputs_muted){
1670 cam=get_nowebcam_device();
1673 call->log->video_enabled = TRUE;
1674 video_stream_set_direction (call->videostream, dir);
1675 ms_message("%s lc rotation:%d\n", __FUNCTION__, lc->device_rotation);
1676 video_stream_set_device_rotation(call->videostream, lc->device_rotation);
1677 video_stream_start(call->videostream,
1678 call->video_profile, rtp_addr, vstream->rtp_port,
1679 rtcp_addr, linphone_core_rtcp_enabled(lc) ? (vstream->rtcp_port) : 0,
1680 used_pt, linphone_core_get_video_jittcomp(lc), cam);
1681 video_stream_set_rtcp_information(call->videostream, cname,rtcp_tool);
1684 if (vstream->proto == SalProtoRtpSavp) {
1685 const SalStreamDescription *local_st_desc=sal_media_description_find_stream(call->localdesc,
1686 SalProtoRtpSavp,SalVideo);
1688 video_stream_enable_strp(
1690 vstream->crypto[0].algo,
1691 local_st_desc->crypto[0].master_key,
1692 vstream->crypto[0].master_key
1694 call->videostream_encrypted=TRUE;
1696 call->videostream_encrypted=FALSE;
1698 }else ms_warning("No video stream accepted.");
1700 ms_warning("No valid video stream defined.");
1705 void linphone_call_start_media_streams(LinphoneCall *call, bool_t all_inputs_muted, bool_t send_ringbacktone){
1706 LinphoneCore *lc=call->core;
1708 LinphoneAddress *me=linphone_core_get_primary_contact_parsed(lc);
1710 bool_t use_arc=linphone_core_adaptive_rate_control_enabled(lc);
1711 #ifdef VIDEO_ENABLED
1712 const SalStreamDescription *vstream=sal_media_description_find_stream(call->resultdesc,
1713 SalProtoRtpAvp,SalVideo);
1716 call->current_params.audio_codec = NULL;
1717 call->current_params.video_codec = NULL;
1719 if ((call->audiostream == NULL) && (call->videostream == NULL)) {
1720 ms_fatal("start_media_stream() called without prior init !");
1723 cname=linphone_address_as_string_uri_only(me);
1725 #if defined(VIDEO_ENABLED)
1726 if (vstream!=NULL && vstream->dir!=SalStreamInactive && vstream->payloads!=NULL){
1727 /*when video is used, do not make adaptive rate control on audio, it is stupid.*/
1731 if (call->audiostream!=NULL) {
1732 linphone_call_start_audio_stream(call,cname,all_inputs_muted,send_ringbacktone,use_arc);
1734 call->current_params.has_video=FALSE;
1735 if (call->videostream!=NULL) {
1736 linphone_call_start_video_stream(call,cname,all_inputs_muted);
1739 call->all_muted=all_inputs_muted;
1740 call->playing_ringbacktone=send_ringbacktone;
1741 call->up_bw=linphone_core_get_upload_bandwidth(lc);
1743 if (call->params.media_encryption==LinphoneMediaEncryptionZRTP) {
1744 OrtpZrtpParams params;
1745 /*will be set later when zrtp is activated*/
1746 call->current_params.media_encryption=LinphoneMediaEncryptionNone;
1748 params.zid_file=lc->zrtp_secrets_cache;
1749 audio_stream_enable_zrtp(call->audiostream,¶ms);
1750 }else if (call->params.media_encryption==LinphoneMediaEncryptionSRTP){
1751 call->current_params.media_encryption=linphone_call_are_all_streams_encrypted(call) ?
1752 LinphoneMediaEncryptionSRTP : LinphoneMediaEncryptionNone;
1755 /*also reflect the change if the "wished" params, in order to avoid to propose SAVP or video again
1756 * further in the call, for example during pause,resume, conferencing reINVITEs*/
1757 linphone_call_fix_call_parameters(call);
1758 if ((call->ice_session != NULL) && (ice_session_state(call->ice_session) != IS_Completed)) {
1759 ice_session_start_connectivity_checks(call->ice_session);
1765 linphone_address_destroy(me);
1768 void linphone_call_start_media_streams_for_ice_gathering(LinphoneCall *call){
1769 audio_stream_prepare_sound(call->audiostream, NULL, NULL);
1770 #ifdef VIDEO_ENABLED
1771 if (call->videostream) {
1772 video_stream_prepare_video(call->videostream);
1777 void linphone_call_stop_media_streams_for_ice_gathering(LinphoneCall *call){
1778 audio_stream_unprepare_sound(call->audiostream);
1779 #ifdef VIDEO_ENABLED
1780 if (call->videostream) {
1781 video_stream_unprepare_video(call->videostream);
1786 void linphone_call_update_crypto_parameters(LinphoneCall *call, SalMediaDescription *old_md, SalMediaDescription *new_md) {
1787 SalStreamDescription *old_stream;
1788 SalStreamDescription *new_stream;
1791 old_stream = sal_media_description_find_stream(old_md, SalProtoRtpSavp, SalAudio);
1792 new_stream = sal_media_description_find_stream(new_md, SalProtoRtpSavp, SalAudio);
1793 if (old_stream && new_stream) {
1794 const SalStreamDescription *local_st_desc = sal_media_description_find_stream(call->localdesc, SalProtoRtpSavp, SalAudio);
1795 if (local_st_desc) {
1796 int crypto_idx = find_crypto_index_from_tag(local_st_desc->crypto, new_stream->crypto_local_tag);
1797 if (crypto_idx >= 0) {
1798 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);
1799 call->audiostream_encrypted = TRUE;
1801 ms_warning("Failed to find local crypto algo with tag: %d", new_stream->crypto_local_tag);
1802 call->audiostream_encrypted = FALSE;
1804 for (i = 0; i < SAL_CRYPTO_ALGO_MAX; i++) {
1805 old_stream->crypto[i].tag = new_stream->crypto[i].tag;
1806 old_stream->crypto[i].algo = new_stream->crypto[i].algo;
1807 strncpy(old_stream->crypto[i].master_key, new_stream->crypto[i].master_key, sizeof(old_stream->crypto[i].master_key) - 1);
1812 #ifdef VIDEO_ENABLED
1813 old_stream = sal_media_description_find_stream(old_md, SalProtoRtpSavp, SalVideo);
1814 new_stream = sal_media_description_find_stream(new_md, SalProtoRtpSavp, SalVideo);
1815 if (old_stream && new_stream) {
1816 const SalStreamDescription *local_st_desc = sal_media_description_find_stream(call->localdesc, SalProtoRtpSavp, SalVideo);
1817 if (local_st_desc) {
1818 int crypto_idx = find_crypto_index_from_tag(local_st_desc->crypto, new_stream->crypto_local_tag);
1819 if (crypto_idx >= 0) {
1820 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);
1821 call->videostream_encrypted = TRUE;
1823 ms_warning("Failed to find local crypto algo with tag: %d", new_stream->crypto_local_tag);
1824 call->videostream_encrypted = FALSE;
1826 for (i = 0; i < SAL_CRYPTO_ALGO_MAX; i++) {
1827 old_stream->crypto[i].tag = new_stream->crypto[i].tag;
1828 old_stream->crypto[i].algo = new_stream->crypto[i].algo;
1829 strncpy(old_stream->crypto[i].master_key, new_stream->crypto[i].master_key, sizeof(old_stream->crypto[i].master_key) - 1);
1836 void linphone_call_update_remote_session_id_and_ver(LinphoneCall *call) {
1837 SalMediaDescription *remote_desc = sal_call_get_remote_media_description(call->op);
1839 call->remote_session_id = remote_desc->session_id;
1840 call->remote_session_ver = remote_desc->session_ver;
1844 void linphone_call_delete_ice_session(LinphoneCall *call){
1845 if (call->ice_session != NULL) {
1846 ice_session_destroy(call->ice_session);
1847 call->ice_session = NULL;
1848 if (call->audiostream != NULL) call->audiostream->ms.ice_check_list = NULL;
1849 if (call->videostream != NULL) call->videostream->ms.ice_check_list = NULL;
1850 call->stats[LINPHONE_CALL_STATS_AUDIO].ice_state = LinphoneIceStateNotActivated;
1851 call->stats[LINPHONE_CALL_STATS_VIDEO].ice_state = LinphoneIceStateNotActivated;
1856 void linphone_call_delete_upnp_session(LinphoneCall *call){
1857 if(call->upnp_session!=NULL) {
1858 linphone_upnp_session_destroy(call->upnp_session);
1859 call->upnp_session=NULL;
1864 static void linphone_call_log_fill_stats(LinphoneCallLog *log, MediaStream *st){
1865 float quality=media_stream_get_average_quality_rating(st);
1867 if (log->quality!=-1){
1868 log->quality*=quality/5.0;
1869 }else log->quality=quality;
1873 void linphone_call_stop_audio_stream(LinphoneCall *call) {
1874 if (call->audiostream!=NULL) {
1875 rtp_session_unregister_event_queue(call->audiostream->ms.session,call->audiostream_app_evq);
1876 ortp_ev_queue_flush(call->audiostream_app_evq);
1877 ortp_ev_queue_destroy(call->audiostream_app_evq);
1878 call->audiostream_app_evq=NULL;
1880 if (call->audiostream->ec){
1881 const char *state_str=NULL;
1882 ms_filter_call_method(call->audiostream->ec,MS_ECHO_CANCELLER_GET_STATE_STRING,&state_str);
1884 ms_message("Writing echo canceler state, %i bytes",(int)strlen(state_str));
1885 lp_config_set_string(call->core->config,"sound","ec_state",state_str);
1888 audio_stream_get_local_rtp_stats(call->audiostream,&call->log->local_stats);
1889 linphone_call_log_fill_stats (call->log,(MediaStream*)call->audiostream);
1890 if (call->endpoint){
1891 linphone_call_remove_from_conf(call);
1893 audio_stream_stop(call->audiostream);
1894 call->audiostream=NULL;
1898 void linphone_call_stop_video_stream(LinphoneCall *call) {
1899 #ifdef VIDEO_ENABLED
1900 if (call->videostream!=NULL){
1901 rtp_session_unregister_event_queue(call->videostream->ms.session,call->videostream_app_evq);
1902 ortp_ev_queue_flush(call->videostream_app_evq);
1903 ortp_ev_queue_destroy(call->videostream_app_evq);
1904 call->videostream_app_evq=NULL;
1905 linphone_call_log_fill_stats(call->log,(MediaStream*)call->videostream);
1906 video_stream_stop(call->videostream);
1907 call->videostream=NULL;
1912 void linphone_call_stop_media_streams(LinphoneCall *call){
1913 linphone_call_stop_audio_stream(call);
1914 linphone_call_stop_video_stream(call);
1915 ms_event_queue_skip(call->core->msevq);
1917 if (call->audio_profile){
1918 rtp_profile_clear_all(call->audio_profile);
1919 rtp_profile_destroy(call->audio_profile);
1920 call->audio_profile=NULL;
1922 if (call->video_profile){
1923 rtp_profile_clear_all(call->video_profile);
1924 rtp_profile_destroy(call->video_profile);
1925 call->video_profile=NULL;
1931 void linphone_call_enable_echo_cancellation(LinphoneCall *call, bool_t enable) {
1932 if (call!=NULL && call->audiostream!=NULL && call->audiostream->ec){
1933 bool_t bypass_mode = !enable;
1934 ms_filter_call_method(call->audiostream->ec,MS_ECHO_CANCELLER_SET_BYPASS_MODE,&bypass_mode);
1937 bool_t linphone_call_echo_cancellation_enabled(LinphoneCall *call) {
1938 if (call!=NULL && call->audiostream!=NULL && call->audiostream->ec){
1940 ms_filter_call_method(call->audiostream->ec,MS_ECHO_CANCELLER_GET_BYPASS_MODE,&val);
1943 return linphone_core_echo_cancellation_enabled(call->core);
1947 void linphone_call_enable_echo_limiter(LinphoneCall *call, bool_t val){
1948 if (call!=NULL && call->audiostream!=NULL ) {
1950 const char *type=lp_config_get_string(call->core->config,"sound","el_type","mic");
1951 if (strcasecmp(type,"mic")==0)
1952 audio_stream_enable_echo_limiter(call->audiostream,ELControlMic);
1953 else if (strcasecmp(type,"full")==0)
1954 audio_stream_enable_echo_limiter(call->audiostream,ELControlFull);
1956 audio_stream_enable_echo_limiter(call->audiostream,ELInactive);
1961 bool_t linphone_call_echo_limiter_enabled(const LinphoneCall *call){
1962 if (call!=NULL && call->audiostream!=NULL ){
1963 return call->audiostream->el_type !=ELInactive ;
1965 return linphone_core_echo_limiter_enabled(call->core);
1970 * @addtogroup call_misc
1975 * Returns the measured sound volume played locally (received from remote).
1976 * It is expressed in dbm0.
1978 float linphone_call_get_play_volume(LinphoneCall *call){
1979 AudioStream *st=call->audiostream;
1980 if (st && st->volrecv){
1982 ms_filter_call_method(st->volrecv,MS_VOLUME_GET,&vol);
1986 return LINPHONE_VOLUME_DB_LOWEST;
1990 * Returns the measured sound volume recorded locally (sent to remote).
1991 * It is expressed in dbm0.
1993 float linphone_call_get_record_volume(LinphoneCall *call){
1994 AudioStream *st=call->audiostream;
1995 if (st && st->volsend && !call->audio_muted && call->state==LinphoneCallStreamsRunning){
1997 ms_filter_call_method(st->volsend,MS_VOLUME_GET,&vol);
2001 return LINPHONE_VOLUME_DB_LOWEST;
2005 * Obtain real-time quality rating of the call
2007 * Based on local RTP statistics and RTCP feedback, a quality rating is computed and updated
2008 * during all the duration of the call. This function returns its value at the time of the function call.
2009 * It is expected that the rating is updated at least every 5 seconds or so.
2010 * The rating is a floating point number comprised between 0 and 5.
2012 * 4-5 = good quality <br>
2013 * 3-4 = average quality <br>
2014 * 2-3 = poor quality <br>
2015 * 1-2 = very poor quality <br>
2016 * 0-1 = can't be worse, mostly unusable <br>
2018 * @returns The function returns -1 if no quality measurement is available, for example if no
2019 * active audio stream exist. Otherwise it returns the quality rating.
2021 float linphone_call_get_current_quality(LinphoneCall *call){
2022 float audio_rating=-1;
2023 float video_rating=-1;
2025 if (call->audiostream){
2026 audio_rating=media_stream_get_quality_rating((MediaStream*)call->audiostream)/5.0;
2028 if (call->videostream){
2029 video_rating=media_stream_get_quality_rating((MediaStream*)call->videostream)/5.0;
2031 if (audio_rating<0 && video_rating<0) result=-1;
2032 else if (audio_rating<0) result=video_rating*5.0;
2033 else if (video_rating<0) result=audio_rating*5.0;
2034 else result=audio_rating*video_rating*5.0;
2039 * Returns call quality averaged over all the duration of the call.
2041 * See linphone_call_get_current_quality() for more details about quality measurement.
2043 float linphone_call_get_average_quality(LinphoneCall *call){
2044 if (call->audiostream){
2045 return audio_stream_get_average_quality_rating(call->audiostream);
2050 static void update_local_stats(LinphoneCallStats *stats, MediaStream *stream){
2051 const MSQualityIndicator *qi=media_stream_get_quality_indicator(stream);
2053 stats->local_late_rate=ms_quality_indicator_get_local_late_rate(qi);
2054 stats->local_loss_rate=ms_quality_indicator_get_local_loss_rate(qi);
2059 * Access last known statistics for audio stream, for a given call.
2061 const LinphoneCallStats *linphone_call_get_audio_stats(LinphoneCall *call) {
2062 LinphoneCallStats *stats=&call->stats[LINPHONE_CALL_STATS_AUDIO];
2063 if (call->audiostream){
2064 update_local_stats(stats,(MediaStream*)call->audiostream);
2070 * Access last known statistics for video stream, for a given call.
2072 const LinphoneCallStats *linphone_call_get_video_stats(LinphoneCall *call) {
2073 LinphoneCallStats *stats=&call->stats[LINPHONE_CALL_STATS_VIDEO];
2074 if (call->videostream){
2075 update_local_stats(stats,(MediaStream*)call->videostream);
2081 * Enable recording of the call (voice-only).
2082 * This function must be used before the call parameters are assigned to the call.
2083 * The call recording can be started and paused after the call is established with
2084 * linphone_call_start_recording() and linphone_call_pause_recording().
2085 * @param cp the call parameters
2086 * @param path path and filename of the file where audio is written.
2088 void linphone_call_params_set_record_file(LinphoneCallParams *cp, const char *path){
2089 if (cp->record_file){
2090 ms_free(cp->record_file);
2091 cp->record_file=NULL;
2093 if (path) cp->record_file=ms_strdup(path);
2097 * Retrieves the path for the audio recoding of the call.
2099 const char *linphone_call_params_get_record_file(const LinphoneCallParams *cp){
2100 return cp->record_file;
2104 * Start call recording.
2105 * The output file where audio is recorded must be previously specified with linphone_call_params_set_record_file().
2107 void linphone_call_start_recording(LinphoneCall *call){
2108 if (!call->params.record_file){
2109 ms_error("linphone_call_start_recording(): no output file specified. Use linphone_call_params_set_record_file().");
2112 if (call->audiostream && !call->params.in_conference){
2113 audio_stream_mixed_record_start(call->audiostream);
2115 call->record_active=TRUE;
2119 * Stop call recording.
2121 void linphone_call_stop_recording(LinphoneCall *call){
2122 if (call->audiostream && !call->params.in_conference){
2123 audio_stream_mixed_record_stop(call->audiostream);
2125 call->record_active=FALSE;
2132 static void report_bandwidth(LinphoneCall *call, RtpSession *as, RtpSession *vs){
2133 call->stats[LINPHONE_CALL_STATS_AUDIO].download_bandwidth=(as!=NULL) ? (rtp_session_compute_recv_bandwidth(as)*1e-3) : 0;
2134 call->stats[LINPHONE_CALL_STATS_AUDIO].upload_bandwidth=(as!=NULL) ? (rtp_session_compute_send_bandwidth(as)*1e-3) : 0;
2135 call->stats[LINPHONE_CALL_STATS_VIDEO].download_bandwidth=(vs!=NULL) ? (rtp_session_compute_recv_bandwidth(vs)*1e-3) : 0;
2136 call->stats[LINPHONE_CALL_STATS_VIDEO].upload_bandwidth=(vs!=NULL) ? (rtp_session_compute_send_bandwidth(vs)*1e-3) : 0;
2137 ms_message("bandwidth usage: audio=[d=%.1f,u=%.1f] video=[d=%.1f,u=%.1f] kbit/sec",
2138 call->stats[LINPHONE_CALL_STATS_AUDIO].download_bandwidth,
2139 call->stats[LINPHONE_CALL_STATS_AUDIO].upload_bandwidth ,
2140 call->stats[LINPHONE_CALL_STATS_VIDEO].download_bandwidth,
2141 call->stats[LINPHONE_CALL_STATS_VIDEO].upload_bandwidth
2145 static void linphone_core_disconnected(LinphoneCore *lc, LinphoneCall *call){
2149 from = linphone_call_get_remote_address_as_string(call);
2152 snprintf(temp,sizeof(temp),"Remote end %s seems to have disconnected, the call is going to be closed.",from);
2157 snprintf(temp,sizeof(temp),"Remote end seems to have disconnected, the call is going to be closed.");
2159 if (lc->vtable.display_warning!=NULL)
2160 lc->vtable.display_warning(lc,temp);
2161 linphone_core_terminate_call(lc,call);
2162 linphone_core_play_named_tone(lc,LinphoneToneCallFailed);
2165 static void handle_ice_events(LinphoneCall *call, OrtpEvent *ev){
2166 OrtpEventType evt=ortp_event_get_type(ev);
2167 OrtpEventData *evd=ortp_event_get_data(ev);
2170 if (evt == ORTP_EVENT_ICE_SESSION_PROCESSING_FINISHED) {
2171 switch (ice_session_state(call->ice_session)) {
2173 ice_session_select_candidates(call->ice_session);
2174 if (ice_session_role(call->ice_session) == IR_Controlling) {
2175 linphone_core_update_call(call->core, call, &call->current_params);
2179 if (ice_session_has_completed_check_list(call->ice_session) == TRUE) {
2180 ice_session_select_candidates(call->ice_session);
2181 if (ice_session_role(call->ice_session) == IR_Controlling) {
2182 /* At least one ICE session has succeeded, so perform a call update. */
2183 linphone_core_update_call(call->core, call, &call->current_params);
2190 linphone_core_update_ice_state_in_call_stats(call);
2191 } else if (evt == ORTP_EVENT_ICE_GATHERING_FINISHED) {
2193 if (evd->info.ice_processing_successful==TRUE) {
2194 ice_session_compute_candidates_foundations(call->ice_session);
2195 ice_session_eliminate_redundant_candidates(call->ice_session);
2196 ice_session_choose_default_candidates(call->ice_session);
2197 ping_time = ice_session_average_gathering_round_trip_time(call->ice_session);
2198 if (ping_time >=0) {
2199 call->ping_time=ping_time;
2202 ms_warning("No STUN answer from [%s], disabling ICE",linphone_core_get_stun_server(call->core));
2203 linphone_call_delete_ice_session(call);
2205 switch (call->state) {
2206 case LinphoneCallUpdating:
2207 linphone_core_start_update_call(call->core, call);
2209 case LinphoneCallUpdatedByRemote:
2210 linphone_core_start_accept_call_update(call->core, call);
2212 case LinphoneCallOutgoingInit:
2213 linphone_call_stop_media_streams_for_ice_gathering(call);
2214 linphone_core_proceed_with_invite_if_ready(call->core, call, NULL);
2216 case LinphoneCallIdle:
2217 linphone_call_stop_media_streams_for_ice_gathering(call);
2218 linphone_core_notify_incoming_call(call->core, call);
2223 } else if (evt == ORTP_EVENT_ICE_LOSING_PAIRS_COMPLETED) {
2224 linphone_core_start_accept_call_update(call->core, call);
2225 linphone_core_update_ice_state_in_call_stats(call);
2226 } else if (evt == ORTP_EVENT_ICE_RESTART_NEEDED) {
2227 ice_session_restart(call->ice_session);
2228 ice_session_set_role(call->ice_session, IR_Controlling);
2229 linphone_core_update_call(call->core, call, &call->current_params);
2233 void linphone_call_background_tasks(LinphoneCall *call, bool_t one_second_elapsed){
2234 LinphoneCore* lc = call->core;
2235 int disconnect_timeout = linphone_core_get_nortp_timeout(call->core);
2236 bool_t disconnected=FALSE;
2238 if (call->state==LinphoneCallStreamsRunning && one_second_elapsed){
2239 RtpSession *as=NULL,*vs=NULL;
2240 float audio_load=0, video_load=0;
2241 if (call->audiostream!=NULL){
2242 as=call->audiostream->ms.session;
2243 if (call->audiostream->ms.ticker)
2244 audio_load=ms_ticker_get_average_load(call->audiostream->ms.ticker);
2246 if (call->videostream!=NULL){
2247 if (call->videostream->ms.ticker)
2248 video_load=ms_ticker_get_average_load(call->videostream->ms.ticker);
2249 vs=call->videostream->ms.session;
2251 report_bandwidth(call,as,vs);
2252 ms_message("Thread processing load: audio=%f\tvideo=%f",audio_load,video_load);
2256 linphone_upnp_call_process(call);
2259 #ifdef VIDEO_ENABLED
2260 if (call->videostream!=NULL) {
2263 /* Ensure there is no dangling ICE check list. */
2264 if (call->ice_session == NULL) call->videostream->ms.ice_check_list = NULL;
2266 // Beware that the application queue should not depend on treatments fron the
2267 // mediastreamer queue.
2268 video_stream_iterate(call->videostream);
2270 while (call->videostream_app_evq && (NULL != (ev=ortp_ev_queue_get(call->videostream_app_evq)))){
2271 OrtpEventType evt=ortp_event_get_type(ev);
2272 OrtpEventData *evd=ortp_event_get_data(ev);
2273 if (evt == ORTP_EVENT_ZRTP_ENCRYPTION_CHANGED){
2274 linphone_call_videostream_encryption_changed(call, evd->info.zrtp_stream_encrypted);
2275 } else if (evt == ORTP_EVENT_RTCP_PACKET_RECEIVED) {
2276 call->stats[LINPHONE_CALL_STATS_VIDEO].round_trip_delay = rtp_session_get_round_trip_propagation(call->videostream->ms.session);
2277 if(call->stats[LINPHONE_CALL_STATS_VIDEO].received_rtcp != NULL)
2278 freemsg(call->stats[LINPHONE_CALL_STATS_VIDEO].received_rtcp);
2279 call->stats[LINPHONE_CALL_STATS_VIDEO].received_rtcp = evd->packet;
2281 update_local_stats(&call->stats[LINPHONE_CALL_STATS_VIDEO],(MediaStream*)call->videostream);
2282 if (lc->vtable.call_stats_updated)
2283 lc->vtable.call_stats_updated(lc, call, &call->stats[LINPHONE_CALL_STATS_VIDEO]);
2284 } else if (evt == ORTP_EVENT_RTCP_PACKET_EMITTED) {
2285 memcpy(&call->stats[LINPHONE_CALL_STATS_VIDEO].jitter_stats, rtp_session_get_jitter_stats(call->videostream->ms.session), sizeof(jitter_stats_t));
2286 if(call->stats[LINPHONE_CALL_STATS_VIDEO].sent_rtcp != NULL)
2287 freemsg(call->stats[LINPHONE_CALL_STATS_VIDEO].sent_rtcp);
2288 call->stats[LINPHONE_CALL_STATS_VIDEO].sent_rtcp = evd->packet;
2290 update_local_stats(&call->stats[LINPHONE_CALL_STATS_VIDEO],(MediaStream*)call->videostream);
2291 if (lc->vtable.call_stats_updated)
2292 lc->vtable.call_stats_updated(lc, call, &call->stats[LINPHONE_CALL_STATS_VIDEO]);
2293 } else if ((evt == ORTP_EVENT_ICE_SESSION_PROCESSING_FINISHED) || (evt == ORTP_EVENT_ICE_GATHERING_FINISHED)
2294 || (evt == ORTP_EVENT_ICE_LOSING_PAIRS_COMPLETED) || (evt == ORTP_EVENT_ICE_RESTART_NEEDED)) {
2295 handle_ice_events(call, ev);
2297 ortp_event_destroy(ev);
2301 if (call->audiostream!=NULL) {
2304 /* Ensure there is no dangling ICE check list. */
2305 if (call->ice_session == NULL) call->audiostream->ms.ice_check_list = NULL;
2307 // Beware that the application queue should not depend on treatments fron the
2308 // mediastreamer queue.
2309 audio_stream_iterate(call->audiostream);
2311 while (call->audiostream_app_evq && (NULL != (ev=ortp_ev_queue_get(call->audiostream_app_evq)))){
2312 OrtpEventType evt=ortp_event_get_type(ev);
2313 OrtpEventData *evd=ortp_event_get_data(ev);
2314 if (evt == ORTP_EVENT_ZRTP_ENCRYPTION_CHANGED){
2315 linphone_call_audiostream_encryption_changed(call, evd->info.zrtp_stream_encrypted);
2316 } else if (evt == ORTP_EVENT_ZRTP_SAS_READY) {
2317 linphone_call_audiostream_auth_token_ready(call, evd->info.zrtp_sas.sas, evd->info.zrtp_sas.verified);
2318 } else if (evt == ORTP_EVENT_RTCP_PACKET_RECEIVED) {
2319 call->stats[LINPHONE_CALL_STATS_AUDIO].round_trip_delay = rtp_session_get_round_trip_propagation(call->audiostream->ms.session);
2320 if(call->stats[LINPHONE_CALL_STATS_AUDIO].received_rtcp != NULL)
2321 freemsg(call->stats[LINPHONE_CALL_STATS_AUDIO].received_rtcp);
2322 call->stats[LINPHONE_CALL_STATS_AUDIO].received_rtcp = evd->packet;
2324 update_local_stats(&call->stats[LINPHONE_CALL_STATS_AUDIO],(MediaStream*)call->audiostream);
2325 if (lc->vtable.call_stats_updated)
2326 lc->vtable.call_stats_updated(lc, call, &call->stats[LINPHONE_CALL_STATS_AUDIO]);
2327 } else if (evt == ORTP_EVENT_RTCP_PACKET_EMITTED) {
2328 memcpy(&call->stats[LINPHONE_CALL_STATS_AUDIO].jitter_stats, rtp_session_get_jitter_stats(call->audiostream->ms.session), sizeof(jitter_stats_t));
2329 if(call->stats[LINPHONE_CALL_STATS_AUDIO].sent_rtcp != NULL)
2330 freemsg(call->stats[LINPHONE_CALL_STATS_AUDIO].sent_rtcp);
2331 call->stats[LINPHONE_CALL_STATS_AUDIO].sent_rtcp = evd->packet;
2333 update_local_stats(&call->stats[LINPHONE_CALL_STATS_AUDIO],(MediaStream*)call->audiostream);
2334 if (lc->vtable.call_stats_updated)
2335 lc->vtable.call_stats_updated(lc, call, &call->stats[LINPHONE_CALL_STATS_AUDIO]);
2336 } else if ((evt == ORTP_EVENT_ICE_SESSION_PROCESSING_FINISHED) || (evt == ORTP_EVENT_ICE_GATHERING_FINISHED)
2337 || (evt == ORTP_EVENT_ICE_LOSING_PAIRS_COMPLETED) || (evt == ORTP_EVENT_ICE_RESTART_NEEDED)) {
2338 handle_ice_events(call, ev);
2339 } else if (evt==ORTP_EVENT_TELEPHONE_EVENT){
2340 linphone_core_dtmf_received(lc,evd->info.telephone_event);
2342 ortp_event_destroy(ev);
2345 if (call->state==LinphoneCallStreamsRunning && one_second_elapsed && call->audiostream!=NULL && disconnect_timeout>0 )
2346 disconnected=!audio_stream_alive(call->audiostream,disconnect_timeout);
2348 linphone_core_disconnected(call->core,call);
2351 void linphone_call_log_completed(LinphoneCall *call){
2352 LinphoneCore *lc=call->core;
2354 call->log->duration=time(NULL)-call->start_time;
2356 if (call->log->status==LinphoneCallMissed){
2359 info=ortp_strdup_printf(ngettext("You have missed %i call.",
2360 "You have missed %i calls.", lc->missed_calls),
2362 if (lc->vtable.display_status!=NULL)
2363 lc->vtable.display_status(lc,info);
2366 lc->call_logs=ms_list_prepend(lc->call_logs,(void *)call->log);
2367 if (ms_list_size(lc->call_logs)>lc->max_call_logs){
2368 MSList *elem,*prevelem=NULL;
2369 /*find the last element*/
2370 for(elem=lc->call_logs;elem!=NULL;elem=elem->next){
2374 linphone_call_log_destroy((LinphoneCallLog*)elem->data);
2375 lc->call_logs=ms_list_remove_link(lc->call_logs,elem);
2377 if (lc->vtable.call_log_updated!=NULL){
2378 lc->vtable.call_log_updated(lc,call->log);
2380 call_logs_write_to_config_file(lc);
2383 LinphoneCallState linphone_call_get_transfer_state(LinphoneCall *call) {
2384 return call->transfer_state;
2387 void linphone_call_set_transfer_state(LinphoneCall* call, LinphoneCallState state) {
2388 if (state != call->transfer_state) {
2389 LinphoneCore* lc = call->core;
2390 call->transfer_state = state;
2391 if (lc->vtable.transfer_state_changed)
2392 lc->vtable.transfer_state_changed(lc, call, state);
2397 * Returns true if the call is part of the conference.
2398 * @ingroup conferencing
2400 bool_t linphone_call_is_in_conference(const LinphoneCall *call) {
2401 return call->params.in_conference;
2406 * Perform a zoom of the video displayed during a call.
2407 * @param call the call.
2408 * @param zoom_factor a floating point number describing the zoom factor. A value 1.0 corresponds to no zoom applied.
2409 * @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.
2410 * @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.
2412 * 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.
2414 void linphone_call_zoom_video(LinphoneCall* call, float zoom_factor, float* cx, float* cy) {
2415 VideoStream* vstream = call->videostream;
2416 if (vstream && vstream->output) {
2419 if (zoom_factor < 1)
2421 float halfsize = 0.5 * 1.0 / zoom_factor;
2423 if ((*cx - halfsize) < 0)
2425 if ((*cx + halfsize) > 1)
2427 if ((*cy - halfsize) < 0)
2429 if ((*cy + halfsize) > 1)
2432 zoom[0] = zoom_factor;
2435 ms_filter_call_method(vstream->output, MS_VIDEO_DISPLAY_ZOOM, &zoom);
2436 }else ms_warning("Could not apply zoom: video output wasn't activated.");