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){
512 if (lc->upnp != NULL && linphone_core_get_firewall_policy(lc)==LinphonePolicyUseUpnp &&
513 linphone_upnp_context_get_state(lc->upnp) == LinphoneUpnpStateOk) {
517 /*the following sends an option request back to the caller so that
518 we get a chance to discover our nat'd address before answering.*/
519 call->ping_op=sal_op_new(lc->sal);
520 from_str=linphone_address_as_string_uri_only(from);
521 sal_op_set_route(call->ping_op,sal_op_get_network_origin(op));
522 sal_op_set_user_pointer(call->ping_op,call);
523 sal_ping(call->ping_op,linphone_core_find_best_identity(lc,from,NULL),from_str);
528 linphone_address_clean(from);
529 linphone_core_get_local_ip(lc,linphone_address_get_domain(from),call->localip);
530 linphone_call_init_common(call, from, to);
531 call->log->call_id=ms_strdup(sal_op_get_call_id(op)); /*must be known at that time*/
532 linphone_core_init_default_params(lc, &call->params);
533 md=sal_call_get_remote_media_description(op);
534 call->params.has_video &= !!lc->video_policy.automatically_accept;
536 // It is licit to receive an INVITE without SDP
537 // In this case WE chose the media parameters according to policy.
538 call->params.has_video &= linphone_core_media_description_contains_video_stream(md);
540 switch (linphone_core_get_firewall_policy(call->core)) {
541 case LinphonePolicyUseIce:
542 call->ice_session = ice_session_new();
543 ice_session_set_role(call->ice_session, IR_Controlled);
544 linphone_core_update_ice_from_remote_media_description(call, sal_call_get_remote_media_description(op));
545 if (call->ice_session != NULL) {
546 linphone_call_init_media_streams(call);
547 linphone_call_start_media_streams_for_ice_gathering(call);
548 if (linphone_core_gather_ice_candidates(call->core,call)<0) {
549 /* Ice candidates gathering failed, proceed with the call anyway. */
550 linphone_call_delete_ice_session(call);
551 linphone_call_stop_media_streams_for_ice_gathering(call);
555 case LinphonePolicyUseStun:
556 call->ping_time=linphone_core_run_stun_tests(call->core,call);
557 /* No break to also destroy ice session in this case. */
559 case LinphonePolicyUseUpnp:
561 call->upnp_session = linphone_upnp_session_new(call);
562 if (call->upnp_session != NULL) {
563 linphone_call_init_media_streams(call);
564 if (linphone_core_update_upnp_from_remote_media_description(call, sal_call_get_remote_media_description(op))<0) {
565 /* uPnP port mappings failed, proceed with the call anyway. */
566 linphone_call_delete_upnp_session(call);
574 call->camera_active=call->params.has_video;
576 discover_mtu(lc,linphone_address_get_domain(from));
580 /* this function is called internally to get rid of a call.
581 It performs the following tasks:
582 - remove the call from the internal list of calls
583 - update the call logs accordingly
586 static void linphone_call_set_terminated(LinphoneCall *call){
587 LinphoneCore *lc=call->core;
589 linphone_core_update_allocated_audio_bandwidth(lc);
591 call->owns_call_log=FALSE;
592 linphone_call_log_completed(call);
595 if (call == lc->current_call){
596 ms_message("Resetting the current call");
597 lc->current_call=NULL;
600 if (linphone_core_del_call(lc,call) != 0){
601 ms_error("Could not remove the call from the list !!!");
604 if (ms_list_size(lc->calls)==0)
605 linphone_core_notify_all_friends(lc,lc->presence_mode);
607 linphone_core_conference_check_uninit(lc);
608 if (call->ringing_beep){
609 linphone_core_stop_dtmf(lc);
610 call->ringing_beep=FALSE;
613 linphone_call_unref(call->referer);
618 void linphone_call_fix_call_parameters(LinphoneCall *call){
619 call->params.has_video=call->current_params.has_video;
620 call->params.media_encryption=call->current_params.media_encryption;
623 const char *linphone_call_state_to_string(LinphoneCallState cs){
625 case LinphoneCallIdle:
626 return "LinphoneCallIdle";
627 case LinphoneCallIncomingReceived:
628 return "LinphoneCallIncomingReceived";
629 case LinphoneCallOutgoingInit:
630 return "LinphoneCallOutgoingInit";
631 case LinphoneCallOutgoingProgress:
632 return "LinphoneCallOutgoingProgress";
633 case LinphoneCallOutgoingRinging:
634 return "LinphoneCallOutgoingRinging";
635 case LinphoneCallOutgoingEarlyMedia:
636 return "LinphoneCallOutgoingEarlyMedia";
637 case LinphoneCallConnected:
638 return "LinphoneCallConnected";
639 case LinphoneCallStreamsRunning:
640 return "LinphoneCallStreamsRunning";
641 case LinphoneCallPausing:
642 return "LinphoneCallPausing";
643 case LinphoneCallPaused:
644 return "LinphoneCallPaused";
645 case LinphoneCallResuming:
646 return "LinphoneCallResuming";
647 case LinphoneCallRefered:
648 return "LinphoneCallRefered";
649 case LinphoneCallError:
650 return "LinphoneCallError";
651 case LinphoneCallEnd:
652 return "LinphoneCallEnd";
653 case LinphoneCallPausedByRemote:
654 return "LinphoneCallPausedByRemote";
655 case LinphoneCallUpdatedByRemote:
656 return "LinphoneCallUpdatedByRemote";
657 case LinphoneCallIncomingEarlyMedia:
658 return "LinphoneCallIncomingEarlyMedia";
659 case LinphoneCallUpdating:
660 return "LinphoneCallUpdating";
661 case LinphoneCallReleased:
662 return "LinphoneCallReleased";
664 return "undefined state";
667 void linphone_call_set_state(LinphoneCall *call, LinphoneCallState cstate, const char *message){
668 LinphoneCore *lc=call->core;
670 if (call->state!=cstate){
671 if (call->state==LinphoneCallEnd || call->state==LinphoneCallError){
672 if (cstate!=LinphoneCallReleased){
673 ms_warning("Spurious call state change from %s to %s, ignored.",linphone_call_state_to_string(call->state),
674 linphone_call_state_to_string(cstate));
678 ms_message("Call %p: moving from state %s to %s",call,linphone_call_state_to_string(call->state),
679 linphone_call_state_to_string(cstate));
680 if (cstate!=LinphoneCallRefered){
681 /*LinphoneCallRefered is rather an event, not a state.
682 Indeed it does not change the state of the call (still paused or running)*/
685 if (cstate==LinphoneCallEnd || cstate==LinphoneCallError){
686 switch(call->reason){
687 case LinphoneReasonDeclined:
688 call->log->status=LinphoneCallDeclined;
690 case LinphoneReasonNotAnswered:
691 call->log->status=LinphoneCallMissed;
696 linphone_call_set_terminated (call);
698 if (cstate == LinphoneCallConnected) {
699 call->log->status=LinphoneCallSuccess;
700 call->media_start_time=time(NULL);
703 if (lc->vtable.call_state_changed)
704 lc->vtable.call_state_changed(lc,call,cstate,message);
705 if (cstate==LinphoneCallReleased){
706 if (call->op!=NULL) {
707 /* so that we cannot have anymore upcalls for SAL
708 concerning this call*/
709 sal_op_release(call->op);
712 linphone_call_unref(call);
717 static void linphone_call_destroy(LinphoneCall *obj)
720 linphone_call_delete_upnp_session(obj);
722 linphone_call_delete_ice_session(obj);
724 sal_op_release(obj->op);
727 if (obj->resultdesc!=NULL) {
728 sal_media_description_unref(obj->resultdesc);
729 obj->resultdesc=NULL;
731 if (obj->localdesc!=NULL) {
732 sal_media_description_unref(obj->localdesc);
736 sal_op_release(obj->ping_op);
739 ms_free(obj->refer_to);
741 if (obj->owns_call_log)
742 linphone_call_log_destroy(obj->log);
743 if (obj->auth_token) {
744 ms_free(obj->auth_token);
746 linphone_call_params_uninit(&obj->params);
751 * @addtogroup call_control
756 * Increments the call 's reference count.
757 * An application that wishes to retain a pointer to call object
758 * must use this function to unsure the pointer remains
759 * valid. Once the application no more needs this pointer,
760 * it must call linphone_call_unref().
762 LinphoneCall * linphone_call_ref(LinphoneCall *obj){
768 * Decrements the call object reference count.
769 * See linphone_call_ref().
771 void linphone_call_unref(LinphoneCall *obj){
774 linphone_call_destroy(obj);
779 * Returns current parameters associated to the call.
781 const LinphoneCallParams * linphone_call_get_current_params(LinphoneCall *call){
782 if (call->params.record_file)
783 call->current_params.record_file=call->params.record_file;
784 return &call->current_params;
787 static bool_t is_video_active(const SalStreamDescription *sd){
788 return sd->rtp_port!=0 && sd->dir!=SalStreamInactive;
792 * Returns call parameters proposed by remote.
794 * This is useful when receiving an incoming call, to know whether the remote party
795 * supports video, encryption or whatever.
797 const LinphoneCallParams * linphone_call_get_remote_params(LinphoneCall *call){
798 LinphoneCallParams *cp=&call->remote_params;
799 memset(cp,0,sizeof(*cp));
801 SalMediaDescription *md=sal_call_get_remote_media_description(call->op);
803 SalStreamDescription *asd,*vsd,*secure_asd,*secure_vsd;
805 asd=sal_media_description_find_stream(md,SalProtoRtpAvp,SalAudio);
806 vsd=sal_media_description_find_stream(md,SalProtoRtpAvp,SalVideo);
807 secure_asd=sal_media_description_find_stream(md,SalProtoRtpSavp,SalAudio);
808 secure_vsd=sal_media_description_find_stream(md,SalProtoRtpSavp,SalVideo);
810 cp->has_video=is_video_active(secure_vsd);
811 if (secure_asd || asd==NULL)
812 cp->media_encryption=LinphoneMediaEncryptionSRTP;
814 cp->has_video=is_video_active(vsd);
817 if (md->bandwidth>0 && md->bandwidth<=linphone_core_get_edge_bw(call->core)){
818 cp->low_bandwidth=TRUE;
821 cp->custom_headers=(SalCustomHeader*)sal_op_get_custom_header(call->op);
829 * Returns the remote address associated to this call
832 const LinphoneAddress * linphone_call_get_remote_address(const LinphoneCall *call){
833 return call->dir==LinphoneCallIncoming ? call->log->from : call->log->to;
837 * Returns the remote address associated to this call as a string.
839 * The result string must be freed by user using ms_free().
841 char *linphone_call_get_remote_address_as_string(const LinphoneCall *call){
842 return linphone_address_as_string(linphone_call_get_remote_address(call));
846 * Retrieves the call's current state.
848 LinphoneCallState linphone_call_get_state(const LinphoneCall *call){
853 * Returns the reason for a call termination (either error or normal termination)
855 LinphoneReason linphone_call_get_reason(const LinphoneCall *call){
860 * Get the user_pointer in the LinphoneCall
862 * @ingroup call_control
864 * return user_pointer an opaque user pointer that can be retrieved at any time
866 void *linphone_call_get_user_pointer(LinphoneCall *call)
868 return call->user_pointer;
872 * Set the user_pointer in the LinphoneCall
874 * @ingroup call_control
876 * the user_pointer is an opaque user pointer that can be retrieved at any time in the LinphoneCall
878 void linphone_call_set_user_pointer(LinphoneCall *call, void *user_pointer)
880 call->user_pointer = user_pointer;
884 * Returns the call log associated to this call.
886 LinphoneCallLog *linphone_call_get_call_log(const LinphoneCall *call){
891 * Returns the refer-to uri (if the call was transfered).
893 const char *linphone_call_get_refer_to(const LinphoneCall *call){
894 return call->refer_to;
898 * Returns direction of the call (incoming or outgoing).
900 LinphoneCallDir linphone_call_get_dir(const LinphoneCall *call){
901 return call->log->dir;
905 * Returns the far end's user agent description string, if available.
907 const char *linphone_call_get_remote_user_agent(LinphoneCall *call){
909 return sal_op_get_remote_ua (call->op);
915 * Returns the far end's sip contact as a string, if available.
917 const char *linphone_call_get_remote_contact(LinphoneCall *call){
919 return sal_op_get_remote_contact(call->op);
925 * Returns true if this calls has received a transfer that has not been
927 * Pending transfers are executed when this call is being paused or closed,
928 * locally or by remote endpoint.
929 * If the call is already paused while receiving the transfer request, the
930 * transfer immediately occurs.
932 bool_t linphone_call_has_transfer_pending(const LinphoneCall *call){
933 return call->refer_pending;
937 * Returns call's duration in seconds.
939 int linphone_call_get_duration(const LinphoneCall *call){
940 if (call->media_start_time==0) return 0;
941 return time(NULL)-call->media_start_time;
945 * Returns the call object this call is replacing, if any.
946 * Call replacement can occur during call transfers.
947 * By default, the core automatically terminates the replaced call and accept the new one.
948 * This function allows the application to know whether a new incoming call is a one that replaces another one.
950 LinphoneCall *linphone_call_get_replaced_call(LinphoneCall *call){
951 SalOp *op=sal_call_get_replaces(call->op);
953 return (LinphoneCall*)sal_op_get_user_pointer(op);
959 * Indicate whether camera input should be sent to remote end.
961 void linphone_call_enable_camera (LinphoneCall *call, bool_t enable){
963 if (call->videostream!=NULL && call->videostream->ms.ticker!=NULL){
964 LinphoneCore *lc=call->core;
965 MSWebCam *nowebcam=get_nowebcam_device();
966 if (call->camera_active!=enable && lc->video_conf.device!=nowebcam){
967 video_stream_change_camera(call->videostream,
968 enable ? lc->video_conf.device : nowebcam);
971 call->camera_active=enable;
977 * Request remote side to send us a Video Fast Update.
979 void linphone_call_send_vfu_request(LinphoneCall *call)
981 if (LinphoneCallStreamsRunning == linphone_call_get_state(call))
982 sal_call_send_vfu_request(call->op);
988 * Take a photo of currently received video and write it into a jpeg file.
990 int linphone_call_take_video_snapshot(LinphoneCall *call, const char *file){
992 if (call->videostream!=NULL && call->videostream->jpegwriter!=NULL){
993 return ms_filter_call_method(call->videostream->jpegwriter,MS_JPEG_WRITER_TAKE_SNAPSHOT,(void*)file);
995 ms_warning("Cannot take snapshot: no currently running video stream on this call.");
1002 * Returns TRUE if camera pictures are sent to the remote party.
1004 bool_t linphone_call_camera_enabled (const LinphoneCall *call){
1005 return call->camera_active;
1009 * Enable video stream.
1011 void linphone_call_params_enable_video(LinphoneCallParams *cp, bool_t enabled){
1012 cp->has_video=enabled;
1016 * Returns the audio codec used in the call, described as a PayloadType structure.
1018 const PayloadType* linphone_call_params_get_used_audio_codec(const LinphoneCallParams *cp) {
1019 return cp->audio_codec;
1024 * Returns the video codec used in the call, described as a PayloadType structure.
1026 const PayloadType* linphone_call_params_get_used_video_codec(const LinphoneCallParams *cp) {
1027 return cp->video_codec;
1031 * @ingroup call_control
1032 * Use to know if this call has been configured in low bandwidth mode.
1033 * This mode can be automatically discovered thanks to a stun server when activate_edge_workarounds=1 in section [net] of configuration file.
1034 * An application that would have reliable way to know network capacity may not use activate_edge_workarounds=1 but instead manually configure
1035 * low bandwidth mode with linphone_call_params_enable_low_bandwidth().
1036 * <br> When enabled, this param may transform a call request with video in audio only mode.
1037 * @return TRUE if low bandwidth has been configured/detected
1039 bool_t linphone_call_params_low_bandwidth_enabled(const LinphoneCallParams *cp) {
1040 return cp->low_bandwidth;
1044 * @ingroup call_control
1045 * Indicate low bandwith mode.
1046 * 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
1047 * 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
1048 * that it is achievable by the codec selected after SDP handshake. Video is automatically disabled.
1051 void linphone_call_params_enable_low_bandwidth(LinphoneCallParams *cp, bool_t enabled){
1052 cp->low_bandwidth=enabled;
1056 * Returns whether video is enabled.
1058 bool_t linphone_call_params_video_enabled(const LinphoneCallParams *cp){
1059 return cp->has_video;
1063 * Returns kind of media encryption selected for the call.
1065 enum LinphoneMediaEncryption linphone_call_params_get_media_encryption(const LinphoneCallParams *cp) {
1066 return cp->media_encryption;
1070 * Set requested media encryption for a call.
1072 void linphone_call_params_set_media_encryption(LinphoneCallParams *cp, enum LinphoneMediaEncryption e) {
1073 cp->media_encryption = e;
1078 * Enable sending of real early media (during outgoing calls).
1080 void linphone_call_params_enable_early_media_sending(LinphoneCallParams *cp, bool_t enabled){
1081 cp->real_early_media=enabled;
1085 * Indicates whether sending of early media was enabled.
1087 bool_t linphone_call_params_early_media_sending_enabled(const LinphoneCallParams *cp){
1088 return cp->real_early_media;
1092 * Returns true if the call is part of the locally managed conference.
1094 bool_t linphone_call_params_local_conference_mode(const LinphoneCallParams *cp){
1095 return cp->in_conference;
1099 * Refine bandwidth settings for this call by setting a bandwidth limit for audio streams.
1100 * As a consequence, codecs whose bitrates are not compatible with this limit won't be used.
1102 void linphone_call_params_set_audio_bandwidth_limit(LinphoneCallParams *cp, int bandwidth){
1103 cp->audio_bw=bandwidth;
1106 void linphone_call_params_add_custom_header(LinphoneCallParams *params, const char *header_name, const char *header_value){
1107 params->custom_headers=sal_custom_header_append(params->custom_headers,header_name,header_value);
1110 const char *linphone_call_params_get_custom_header(const LinphoneCallParams *params, const char *header_name){
1111 return sal_custom_header_find(params->custom_headers,header_name);
1114 void _linphone_call_params_copy(LinphoneCallParams *ncp, const LinphoneCallParams *cp){
1115 memcpy(ncp,cp,sizeof(LinphoneCallParams));
1116 if (cp->record_file) ncp->record_file=ms_strdup(cp->record_file);
1118 * The management of the custom headers is not optimal. We copy everything while ref counting would be more efficient.
1120 if (cp->custom_headers) ncp->custom_headers=sal_custom_header_clone(cp->custom_headers);
1124 * Copy existing LinphoneCallParams to a new LinphoneCallParams object.
1126 LinphoneCallParams * linphone_call_params_copy(const LinphoneCallParams *cp){
1127 LinphoneCallParams *ncp=ms_new0(LinphoneCallParams,1);
1128 _linphone_call_params_copy(ncp,cp);
1132 void linphone_call_params_uninit(LinphoneCallParams *p){
1133 if (p->record_file) ms_free(p->record_file);
1134 if (p->custom_headers) sal_custom_header_free(p->custom_headers);
1138 * Destroy LinphoneCallParams.
1140 void linphone_call_params_destroy(LinphoneCallParams *p){
1141 linphone_call_params_uninit(p);
1151 #ifdef TEST_EXT_RENDERER
1152 static void rendercb(void *data, const MSPicture *local, const MSPicture *remote){
1153 ms_message("rendercb, local buffer=%p, remote buffer=%p",
1154 local ? local->planes[0] : NULL, remote? remote->planes[0] : NULL);
1158 #ifdef VIDEO_ENABLED
1159 static void video_stream_event_cb(void *user_pointer, const MSFilter *f, const unsigned int event_id, const void *args){
1160 LinphoneCall* call = (LinphoneCall*) user_pointer;
1161 ms_warning("In linphonecall.c: video_stream_event_cb");
1163 case MS_VIDEO_DECODER_DECODING_ERRORS:
1164 ms_warning("Case is MS_VIDEO_DECODER_DECODING_ERRORS");
1165 linphone_call_send_vfu_request(call);
1167 case MS_VIDEO_DECODER_FIRST_IMAGE_DECODED:
1168 ms_message("First video frame decoded successfully");
1169 if (call->nextVideoFrameDecoded._func != NULL)
1170 call->nextVideoFrameDecoded._func(call, call->nextVideoFrameDecoded._user_data);
1173 ms_warning("Unhandled event %i", event_id);
1179 void linphone_call_set_next_video_frame_decoded_callback(LinphoneCall *call, LinphoneCallCbFunc cb, void* user_data) {
1180 call->nextVideoFrameDecoded._func = cb;
1181 call->nextVideoFrameDecoded._user_data = user_data;
1182 #ifdef VIDEO_ENABLED
1183 ms_filter_call_method_noarg(call->videostream->ms.decoder, MS_VIDEO_DECODER_RESET_FIRST_IMAGE_NOTIFICATION);
1187 void linphone_call_init_audio_stream(LinphoneCall *call){
1188 LinphoneCore *lc=call->core;
1189 AudioStream *audiostream;
1192 if (call->audiostream != NULL) return;
1193 call->audiostream=audiostream=audio_stream_new(call->audio_port,call->audio_port+1,linphone_core_ipv6_enabled(lc));
1194 dscp=linphone_core_get_audio_dscp(lc);
1196 audio_stream_set_dscp(audiostream,dscp);
1197 if (linphone_core_echo_limiter_enabled(lc)){
1198 const char *type=lp_config_get_string(lc->config,"sound","el_type","mic");
1199 if (strcasecmp(type,"mic")==0)
1200 audio_stream_enable_echo_limiter(audiostream,ELControlMic);
1201 else if (strcasecmp(type,"full")==0)
1202 audio_stream_enable_echo_limiter(audiostream,ELControlFull);
1204 audio_stream_enable_gain_control(audiostream,TRUE);
1205 if (linphone_core_echo_cancellation_enabled(lc)){
1206 int len,delay,framesize;
1207 const char *statestr=lp_config_get_string(lc->config,"sound","ec_state",NULL);
1208 len=lp_config_get_int(lc->config,"sound","ec_tail_len",0);
1209 delay=lp_config_get_int(lc->config,"sound","ec_delay",0);
1210 framesize=lp_config_get_int(lc->config,"sound","ec_framesize",0);
1211 audio_stream_set_echo_canceller_params(audiostream,len,delay,framesize);
1212 if (statestr && audiostream->ec){
1213 ms_filter_call_method(audiostream->ec,MS_ECHO_CANCELLER_SET_STATE_STRING,(void*)statestr);
1216 audio_stream_enable_automatic_gain_control(audiostream,linphone_core_agc_enabled(lc));
1218 int enabled=lp_config_get_int(lc->config,"sound","noisegate",0);
1219 audio_stream_enable_noise_gate(audiostream,enabled);
1222 audio_stream_set_features(audiostream,linphone_core_get_audio_features(lc));
1225 RtpTransport *artp=lc->rtptf->audio_rtp_func(lc->rtptf->audio_rtp_func_data, call->audio_port);
1226 RtpTransport *artcp=lc->rtptf->audio_rtcp_func(lc->rtptf->audio_rtcp_func_data, call->audio_port+1);
1227 rtp_session_set_transports(audiostream->ms.session,artp,artcp);
1229 if ((linphone_core_get_firewall_policy(lc) == LinphonePolicyUseIce) && (call->ice_session != NULL)){
1230 rtp_session_set_pktinfo(audiostream->ms.session, TRUE);
1231 rtp_session_set_symmetric_rtp(audiostream->ms.session, FALSE);
1232 if (ice_session_check_list(call->ice_session, 0) == NULL) {
1233 ice_session_add_check_list(call->ice_session, ice_check_list_new());
1235 audiostream->ms.ice_check_list = ice_session_check_list(call->ice_session, 0);
1236 ice_check_list_set_rtp_session(audiostream->ms.ice_check_list, audiostream->ms.session);
1239 call->audiostream_app_evq = ortp_ev_queue_new();
1240 rtp_session_register_event_queue(audiostream->ms.session,call->audiostream_app_evq);
1243 void linphone_call_init_video_stream(LinphoneCall *call){
1244 #ifdef VIDEO_ENABLED
1245 LinphoneCore *lc=call->core;
1247 if (!call->params.has_video) {
1248 linphone_call_stop_video_stream(call);
1251 if (call->videostream != NULL) return;
1252 if ((lc->video_conf.display || lc->video_conf.capture) && call->params.has_video){
1253 int video_recv_buf_size=lp_config_get_int(lc->config,"video","recv_buf_size",0);
1254 int dscp=linphone_core_get_video_dscp(lc);
1256 call->videostream=video_stream_new(call->video_port,call->video_port+1,linphone_core_ipv6_enabled(lc));
1258 video_stream_set_dscp(call->videostream,dscp);
1259 video_stream_enable_display_filter_auto_rotate(call->videostream, lp_config_get_int(lc->config,"video","display_filter_auto_rotate",0));
1260 if (video_recv_buf_size>0) rtp_session_set_recv_buf_size(call->videostream->ms.session,video_recv_buf_size);
1262 if( lc->video_conf.displaytype != NULL)
1263 video_stream_set_display_filter_name(call->videostream,lc->video_conf.displaytype);
1264 video_stream_set_event_callback(call->videostream,video_stream_event_cb, call);
1266 RtpTransport *vrtp=lc->rtptf->video_rtp_func(lc->rtptf->video_rtp_func_data, call->video_port);
1267 RtpTransport *vrtcp=lc->rtptf->video_rtcp_func(lc->rtptf->video_rtcp_func_data, call->video_port+1);
1268 rtp_session_set_transports(call->videostream->ms.session,vrtp,vrtcp);
1270 if ((linphone_core_get_firewall_policy(lc) == LinphonePolicyUseIce) && (call->ice_session != NULL)){
1271 rtp_session_set_pktinfo(call->videostream->ms.session, TRUE);
1272 rtp_session_set_symmetric_rtp(call->videostream->ms.session, FALSE);
1273 if (ice_session_check_list(call->ice_session, 1) == NULL) {
1274 ice_session_add_check_list(call->ice_session, ice_check_list_new());
1276 call->videostream->ms.ice_check_list = ice_session_check_list(call->ice_session, 1);
1277 ice_check_list_set_rtp_session(call->videostream->ms.ice_check_list, call->videostream->ms.session);
1279 call->videostream_app_evq = ortp_ev_queue_new();
1280 rtp_session_register_event_queue(call->videostream->ms.session,call->videostream_app_evq);
1281 #ifdef TEST_EXT_RENDERER
1282 video_stream_set_render_callback(call->videostream,rendercb,NULL);
1286 call->videostream=NULL;
1290 void linphone_call_init_media_streams(LinphoneCall *call){
1291 linphone_call_init_audio_stream(call);
1292 linphone_call_init_video_stream(call);
1296 static int dtmf_tab[16]={'0','1','2','3','4','5','6','7','8','9','*','#','A','B','C','D'};
1298 static void linphone_core_dtmf_received(LinphoneCore *lc, int dtmf){
1299 if (dtmf<0 || dtmf>15){
1300 ms_warning("Bad dtmf value %i",dtmf);
1303 if (lc->vtable.dtmf_received != NULL)
1304 lc->vtable.dtmf_received(lc, linphone_core_get_current_call(lc), dtmf_tab[dtmf]);
1307 static void parametrize_equalizer(LinphoneCore *lc, AudioStream *st){
1309 MSFilter *f=st->equalizer;
1310 int enabled=lp_config_get_int(lc->config,"sound","eq_active",0);
1311 const char *gains=lp_config_get_string(lc->config,"sound","eq_gains",NULL);
1312 ms_filter_call_method(f,MS_EQUALIZER_SET_ACTIVE,&enabled);
1318 if (sscanf(gains,"%f:%f:%f %n",&g.frequency,&g.gain,&g.width,&bytes)==3){
1319 ms_message("Read equalizer gains: %f(~%f) --> %f",g.frequency,g.width,g.gain);
1320 ms_filter_call_method(f,MS_EQUALIZER_SET_GAIN,&g);
1329 void _post_configure_audio_stream(AudioStream *st, LinphoneCore *lc, bool_t muted){
1330 float mic_gain=lc->sound_conf.soft_mic_lev;
1333 float ng_thres=lp_config_get_float(lc->config,"sound","ng_thres",0.05);
1334 float ng_floorgain=lp_config_get_float(lc->config,"sound","ng_floorgain",0);
1335 int dc_removal=lp_config_get_int(lc->config,"sound","dc_removal",0);
1338 linphone_core_set_mic_gain_db (lc, mic_gain);
1340 audio_stream_set_mic_gain(st,0);
1342 recv_gain = lc->sound_conf.soft_play_lev;
1343 if (recv_gain != 0) {
1344 linphone_core_set_playback_gain_db (lc,recv_gain);
1348 ms_filter_call_method(st->volsend,MS_VOLUME_REMOVE_DC,&dc_removal);
1349 float speed=lp_config_get_float(lc->config,"sound","el_speed",-1);
1350 thres=lp_config_get_float(lc->config,"sound","el_thres",-1);
1351 float force=lp_config_get_float(lc->config,"sound","el_force",-1);
1352 int sustain=lp_config_get_int(lc->config,"sound","el_sustain",-1);
1353 float transmit_thres=lp_config_get_float(lc->config,"sound","el_transmit_thres",-1);
1356 if (speed==-1) speed=0.03;
1357 if (force==-1) force=25;
1358 ms_filter_call_method(f,MS_VOLUME_SET_EA_SPEED,&speed);
1359 ms_filter_call_method(f,MS_VOLUME_SET_EA_FORCE,&force);
1361 ms_filter_call_method(f,MS_VOLUME_SET_EA_THRESHOLD,&thres);
1363 ms_filter_call_method(f,MS_VOLUME_SET_EA_SUSTAIN,&sustain);
1364 if (transmit_thres!=-1)
1365 ms_filter_call_method(f,MS_VOLUME_SET_EA_TRANSMIT_THRESHOLD,&transmit_thres);
1367 ms_filter_call_method(st->volsend,MS_VOLUME_SET_NOISE_GATE_THRESHOLD,&ng_thres);
1368 ms_filter_call_method(st->volsend,MS_VOLUME_SET_NOISE_GATE_FLOORGAIN,&ng_floorgain);
1371 /* parameters for a limited noise-gate effect, using echo limiter threshold */
1372 float floorgain = 1/pow(10,(mic_gain)/10);
1373 int spk_agc=lp_config_get_int(lc->config,"sound","speaker_agc_enabled",0);
1374 ms_filter_call_method(st->volrecv, MS_VOLUME_ENABLE_AGC, &spk_agc);
1375 ms_filter_call_method(st->volrecv,MS_VOLUME_SET_NOISE_GATE_THRESHOLD,&ng_thres);
1376 ms_filter_call_method(st->volrecv,MS_VOLUME_SET_NOISE_GATE_FLOORGAIN,&floorgain);
1378 parametrize_equalizer(lc,st);
1381 static void post_configure_audio_streams(LinphoneCall*call){
1382 AudioStream *st=call->audiostream;
1383 LinphoneCore *lc=call->core;
1384 _post_configure_audio_stream(st,lc,call->audio_muted);
1385 if (lc->vtable.dtmf_received!=NULL){
1386 audio_stream_play_received_dtmfs(call->audiostream,FALSE);
1388 if (call->record_active)
1389 linphone_call_start_recording(call);
1392 static RtpProfile *make_profile(LinphoneCall *call, const SalMediaDescription *md, const SalStreamDescription *desc, int *used_pt){
1395 RtpProfile *prof=rtp_profile_new("Call profile");
1398 LinphoneCore *lc=call->core;
1400 const LinphoneCallParams *params=&call->params;
1403 for(elem=desc->payloads;elem!=NULL;elem=elem->next){
1404 PayloadType *pt=(PayloadType*)elem->data;
1407 if ((pt->flags & PAYLOAD_TYPE_FLAG_CAN_SEND) && first) {
1408 if (desc->type==SalAudio){
1409 linphone_core_update_allocated_audio_bandwidth_in_call(call,pt);
1410 if (params->up_ptime)
1411 up_ptime=params->up_ptime;
1412 else up_ptime=linphone_core_get_upload_ptime(lc);
1414 *used_pt=payload_type_get_number(pt);
1417 if (desc->bandwidth>0) remote_bw=desc->bandwidth;
1418 else if (md->bandwidth>0) {
1419 /*case where b=AS is given globally, not per stream*/
1420 remote_bw=md->bandwidth;
1421 if (desc->type==SalVideo){
1422 remote_bw=get_video_bandwidth(remote_bw,call->audio_bw);
1426 if (desc->type==SalAudio){
1427 int audio_bw=call->audio_bw;
1429 if (params->up_bw< audio_bw)
1430 audio_bw=params->up_bw;
1432 bw=get_min_bandwidth(audio_bw,remote_bw);
1433 }else bw=get_min_bandwidth(get_video_bandwidth(linphone_core_get_upload_bandwidth (lc),call->audio_bw),remote_bw);
1434 if (bw>0) pt->normal_bitrate=bw*1000;
1435 else if (desc->type==SalAudio){
1436 pt->normal_bitrate=-1;
1439 up_ptime=desc->ptime;
1443 snprintf(tmp,sizeof(tmp),"ptime=%i",up_ptime);
1444 payload_type_append_send_fmtp(pt,tmp);
1446 number=payload_type_get_number(pt);
1447 if (rtp_profile_get_payload(prof,number)!=NULL){
1448 ms_warning("A payload type with number %i already exists in profile !",number);
1450 rtp_profile_set_payload(prof,number,pt);
1456 static void setup_ring_player(LinphoneCore *lc, LinphoneCall *call){
1457 int pause_time=3000;
1458 audio_stream_play(call->audiostream,lc->sound_conf.ringback_tone);
1459 ms_filter_call_method(call->audiostream->soundread,MS_FILE_PLAYER_LOOP,&pause_time);
1462 static bool_t linphone_call_sound_resources_available(LinphoneCall *call){
1463 LinphoneCore *lc=call->core;
1464 LinphoneCall *current=linphone_core_get_current_call(lc);
1465 return !linphone_core_is_in_conference(lc) &&
1466 (current==NULL || current==call);
1468 static int find_crypto_index_from_tag(const SalSrtpCryptoAlgo crypto[],unsigned char tag) {
1470 for(i=0; i<SAL_CRYPTO_ALGO_MAX; i++) {
1471 if (crypto[i].tag == tag) {
1477 static void linphone_call_start_audio_stream(LinphoneCall *call, const char *cname, bool_t muted, bool_t send_ringbacktone, bool_t use_arc){
1478 LinphoneCore *lc=call->core;
1480 char rtcp_tool[128]={0};
1481 snprintf(rtcp_tool,sizeof(rtcp_tool)-1,"%s-%s",linphone_core_get_user_agent_name(),linphone_core_get_user_agent_version());
1482 /* look for savp stream first */
1483 const SalStreamDescription *stream=sal_media_description_find_stream(call->resultdesc,
1484 SalProtoRtpSavp,SalAudio);
1485 /* no savp audio stream, use avp */
1487 stream=sal_media_description_find_stream(call->resultdesc,
1488 SalProtoRtpAvp,SalAudio);
1490 if (stream && stream->dir!=SalStreamInactive && stream->rtp_port!=0){
1491 MSSndCard *playcard=lc->sound_conf.lsd_card ?
1492 lc->sound_conf.lsd_card : lc->sound_conf.play_sndcard;
1493 MSSndCard *captcard=lc->sound_conf.capt_sndcard;
1494 const char *playfile=lc->play_file;
1495 const char *recfile=lc->rec_file;
1496 call->audio_profile=make_profile(call,call->resultdesc,stream,&used_pt);
1500 call->current_params.audio_codec = rtp_profile_get_payload(call->audio_profile, used_pt);
1501 if (playcard==NULL) {
1502 ms_warning("No card defined for playback !");
1504 if (captcard==NULL) {
1505 ms_warning("No card defined for capture !");
1507 /*Replace soundcard filters by inactive file players or recorders
1508 when placed in recvonly or sendonly mode*/
1509 if (stream->rtp_port==0 || stream->dir==SalStreamRecvOnly){
1512 }else if (stream->dir==SalStreamSendOnly){
1516 /*And we will eventually play "playfile" if set by the user*/
1519 if (send_ringbacktone){
1521 playfile=NULL;/* it is setup later*/
1523 /*if playfile are supplied don't use soundcards*/
1524 if (lc->use_files) {
1528 if (call->params.in_conference){
1529 /* first create the graph without soundcard resources*/
1530 captcard=playcard=NULL;
1532 if (!linphone_call_sound_resources_available(call)){
1533 ms_message("Sound resources are used by another call, not using soundcard.");
1534 captcard=playcard=NULL;
1536 use_ec=captcard==NULL ? FALSE : linphone_core_echo_cancellation_enabled(lc);
1537 if (playcard && stream->max_rate>0) ms_snd_card_set_preferred_sample_rate(playcard, stream->max_rate);
1538 if (captcard && stream->max_rate>0) ms_snd_card_set_preferred_sample_rate(captcard, stream->max_rate);
1539 audio_stream_enable_adaptive_bitrate_control(call->audiostream,use_arc);
1540 audio_stream_enable_adaptive_jittcomp(call->audiostream, linphone_core_audio_adaptive_jittcomp_enabled(lc));
1541 if (!call->params.in_conference && call->params.record_file)
1542 audio_stream_mixed_record_open(call->audiostream,call->params.record_file);
1543 audio_stream_start_full(
1545 call->audio_profile,
1546 stream->rtp_addr[0]!='\0' ? stream->rtp_addr : call->resultdesc->addr,
1548 stream->rtcp_addr[0]!='\0' ? stream->rtcp_addr : call->resultdesc->addr,
1549 linphone_core_rtcp_enabled(lc) ? (stream->rtcp_port) : 0,
1551 linphone_core_get_audio_jittcomp(lc),
1558 post_configure_audio_streams(call);
1559 if (muted && !send_ringbacktone){
1560 audio_stream_set_mic_gain(call->audiostream,0);
1562 if (stream->dir==SalStreamSendOnly && playfile!=NULL){
1564 ms_filter_call_method(call->audiostream->soundread,MS_FILE_PLAYER_LOOP,&pause_time);
1566 if (send_ringbacktone){
1567 setup_ring_player(lc,call);
1569 audio_stream_set_rtcp_information(call->audiostream, cname, rtcp_tool);
1571 /* valid local tags are > 0 */
1572 if (stream->proto == SalProtoRtpSavp) {
1573 const SalStreamDescription *local_st_desc=sal_media_description_find_stream(call->localdesc,
1574 SalProtoRtpSavp,SalAudio);
1575 int crypto_idx = find_crypto_index_from_tag(local_st_desc->crypto, stream->crypto_local_tag);
1577 if (crypto_idx >= 0) {
1578 audio_stream_enable_srtp(
1580 stream->crypto[0].algo,
1581 local_st_desc->crypto[crypto_idx].master_key,
1582 stream->crypto[0].master_key);
1583 call->audiostream_encrypted=TRUE;
1585 ms_warning("Failed to find local crypto algo with tag: %d", stream->crypto_local_tag);
1586 call->audiostream_encrypted=FALSE;
1588 }else call->audiostream_encrypted=FALSE;
1589 if (call->params.in_conference){
1590 /*transform the graph to connect it to the conference filter */
1591 bool_t mute=stream->dir==SalStreamRecvOnly;
1592 linphone_call_add_to_conf(call, mute);
1594 call->current_params.in_conference=call->params.in_conference;
1595 call->current_params.low_bandwidth=call->params.low_bandwidth;
1596 }else ms_warning("No audio stream accepted ?");
1600 static void linphone_call_start_video_stream(LinphoneCall *call, const char *cname,bool_t all_inputs_muted){
1601 #ifdef VIDEO_ENABLED
1602 LinphoneCore *lc=call->core;
1604 /* look for savp stream first */
1605 const SalStreamDescription *vstream=sal_media_description_find_stream(call->resultdesc,
1606 SalProtoRtpSavp,SalVideo);
1607 char rtcp_tool[128]={0};
1608 snprintf(rtcp_tool,sizeof(rtcp_tool)-1,"%s-%s",linphone_core_get_user_agent_name(),linphone_core_get_user_agent_version());
1610 /* no savp audio stream, use avp */
1612 vstream=sal_media_description_find_stream(call->resultdesc,
1613 SalProtoRtpAvp,SalVideo);
1615 /* shutdown preview */
1616 if (lc->previewstream!=NULL) {
1617 video_preview_stop(lc->previewstream);
1618 lc->previewstream=NULL;
1621 if (vstream!=NULL && vstream->dir!=SalStreamInactive && vstream->rtp_port!=0) {
1622 const char *rtp_addr=vstream->rtp_addr[0]!='\0' ? vstream->rtp_addr : call->resultdesc->addr;
1623 const char *rtcp_addr=vstream->rtcp_addr[0]!='\0' ? vstream->rtcp_addr : call->resultdesc->addr;
1624 call->video_profile=make_profile(call,call->resultdesc,vstream,&used_pt);
1626 call->current_params.video_codec = rtp_profile_get_payload(call->video_profile, used_pt);
1627 VideoStreamDir dir=VideoStreamSendRecv;
1628 MSWebCam *cam=lc->video_conf.device;
1629 bool_t is_inactive=FALSE;
1631 call->current_params.has_video=TRUE;
1633 video_stream_enable_adaptive_bitrate_control(call->videostream,
1634 linphone_core_adaptive_rate_control_enabled(lc));
1635 video_stream_enable_adaptive_jittcomp(call->videostream, linphone_core_video_adaptive_jittcomp_enabled(lc));
1636 video_stream_set_sent_video_size(call->videostream,linphone_core_get_preferred_video_size(lc));
1637 video_stream_enable_self_view(call->videostream,lc->video_conf.selfview);
1638 if (lc->video_window_id!=0)
1639 video_stream_set_native_window_id(call->videostream,lc->video_window_id);
1640 if (lc->preview_window_id!=0)
1641 video_stream_set_native_preview_window_id (call->videostream,lc->preview_window_id);
1642 video_stream_use_preview_video_window (call->videostream,lc->use_preview_window);
1644 if (vstream->dir==SalStreamSendOnly && lc->video_conf.capture ){
1645 cam=get_nowebcam_device();
1646 dir=VideoStreamSendOnly;
1647 }else if (vstream->dir==SalStreamRecvOnly && lc->video_conf.display ){
1648 dir=VideoStreamRecvOnly;
1649 }else if (vstream->dir==SalStreamSendRecv){
1650 if (lc->video_conf.display && lc->video_conf.capture)
1651 dir=VideoStreamSendRecv;
1652 else if (lc->video_conf.display)
1653 dir=VideoStreamRecvOnly;
1655 dir=VideoStreamSendOnly;
1657 ms_warning("video stream is inactive.");
1658 /*either inactive or incompatible with local capabilities*/
1661 if (call->camera_active==FALSE || all_inputs_muted){
1662 cam=get_nowebcam_device();
1665 call->log->video_enabled = TRUE;
1666 video_stream_set_direction (call->videostream, dir);
1667 ms_message("%s lc rotation:%d\n", __FUNCTION__, lc->device_rotation);
1668 video_stream_set_device_rotation(call->videostream, lc->device_rotation);
1669 video_stream_start(call->videostream,
1670 call->video_profile, rtp_addr, vstream->rtp_port,
1671 rtcp_addr, linphone_core_rtcp_enabled(lc) ? (vstream->rtcp_port) : 0,
1672 used_pt, linphone_core_get_video_jittcomp(lc), cam);
1673 video_stream_set_rtcp_information(call->videostream, cname,rtcp_tool);
1676 if (vstream->proto == SalProtoRtpSavp) {
1677 const SalStreamDescription *local_st_desc=sal_media_description_find_stream(call->localdesc,
1678 SalProtoRtpSavp,SalVideo);
1680 video_stream_enable_strp(
1682 vstream->crypto[0].algo,
1683 local_st_desc->crypto[0].master_key,
1684 vstream->crypto[0].master_key
1686 call->videostream_encrypted=TRUE;
1688 call->videostream_encrypted=FALSE;
1690 }else ms_warning("No video stream accepted.");
1692 ms_warning("No valid video stream defined.");
1697 void linphone_call_start_media_streams(LinphoneCall *call, bool_t all_inputs_muted, bool_t send_ringbacktone){
1698 LinphoneCore *lc=call->core;
1700 call->current_params.audio_codec = NULL;
1701 call->current_params.video_codec = NULL;
1703 LinphoneAddress *me=linphone_core_get_primary_contact_parsed(lc);
1705 bool_t use_arc=linphone_core_adaptive_rate_control_enabled(lc);
1706 #ifdef VIDEO_ENABLED
1707 const SalStreamDescription *vstream=sal_media_description_find_stream(call->resultdesc,
1708 SalProtoRtpAvp,SalVideo);
1711 if ((call->audiostream == NULL) && (call->videostream == NULL)) {
1712 ms_fatal("start_media_stream() called without prior init !");
1715 cname=linphone_address_as_string_uri_only(me);
1717 #if defined(VIDEO_ENABLED)
1718 if (vstream!=NULL && vstream->dir!=SalStreamInactive && vstream->payloads!=NULL){
1719 /*when video is used, do not make adaptive rate control on audio, it is stupid.*/
1723 if (call->audiostream!=NULL) {
1724 linphone_call_start_audio_stream(call,cname,all_inputs_muted,send_ringbacktone,use_arc);
1726 call->current_params.has_video=FALSE;
1727 if (call->videostream!=NULL) {
1728 linphone_call_start_video_stream(call,cname,all_inputs_muted);
1731 call->all_muted=all_inputs_muted;
1732 call->playing_ringbacktone=send_ringbacktone;
1733 call->up_bw=linphone_core_get_upload_bandwidth(lc);
1735 if (call->params.media_encryption==LinphoneMediaEncryptionZRTP) {
1736 OrtpZrtpParams params;
1737 /*will be set later when zrtp is activated*/
1738 call->current_params.media_encryption=LinphoneMediaEncryptionNone;
1740 params.zid_file=lc->zrtp_secrets_cache;
1741 audio_stream_enable_zrtp(call->audiostream,¶ms);
1742 }else if (call->params.media_encryption==LinphoneMediaEncryptionSRTP){
1743 call->current_params.media_encryption=linphone_call_are_all_streams_encrypted(call) ?
1744 LinphoneMediaEncryptionSRTP : LinphoneMediaEncryptionNone;
1747 /*also reflect the change if the "wished" params, in order to avoid to propose SAVP or video again
1748 * further in the call, for example during pause,resume, conferencing reINVITEs*/
1749 linphone_call_fix_call_parameters(call);
1750 if ((call->ice_session != NULL) && (ice_session_state(call->ice_session) != IS_Completed)) {
1751 ice_session_start_connectivity_checks(call->ice_session);
1757 linphone_address_destroy(me);
1760 void linphone_call_start_media_streams_for_ice_gathering(LinphoneCall *call){
1761 audio_stream_prepare_sound(call->audiostream, NULL, NULL);
1762 #ifdef VIDEO_ENABLED
1763 if (call->videostream) {
1764 video_stream_prepare_video(call->videostream);
1769 void linphone_call_stop_media_streams_for_ice_gathering(LinphoneCall *call){
1770 audio_stream_unprepare_sound(call->audiostream);
1771 #ifdef VIDEO_ENABLED
1772 if (call->videostream) {
1773 video_stream_unprepare_video(call->videostream);
1778 void linphone_call_update_crypto_parameters(LinphoneCall *call, SalMediaDescription *old_md, SalMediaDescription *new_md) {
1779 SalStreamDescription *old_stream;
1780 SalStreamDescription *new_stream;
1783 old_stream = sal_media_description_find_stream(old_md, SalProtoRtpSavp, SalAudio);
1784 new_stream = sal_media_description_find_stream(new_md, SalProtoRtpSavp, SalAudio);
1785 if (old_stream && new_stream) {
1786 const SalStreamDescription *local_st_desc = sal_media_description_find_stream(call->localdesc, SalProtoRtpSavp, SalAudio);
1787 if (local_st_desc) {
1788 int crypto_idx = find_crypto_index_from_tag(local_st_desc->crypto, new_stream->crypto_local_tag);
1789 if (crypto_idx >= 0) {
1790 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);
1791 call->audiostream_encrypted = TRUE;
1793 ms_warning("Failed to find local crypto algo with tag: %d", new_stream->crypto_local_tag);
1794 call->audiostream_encrypted = FALSE;
1796 for (i = 0; i < SAL_CRYPTO_ALGO_MAX; i++) {
1797 old_stream->crypto[i].tag = new_stream->crypto[i].tag;
1798 old_stream->crypto[i].algo = new_stream->crypto[i].algo;
1799 strncpy(old_stream->crypto[i].master_key, new_stream->crypto[i].master_key, sizeof(old_stream->crypto[i].master_key) - 1);
1804 #ifdef VIDEO_ENABLED
1805 old_stream = sal_media_description_find_stream(old_md, SalProtoRtpSavp, SalVideo);
1806 new_stream = sal_media_description_find_stream(new_md, SalProtoRtpSavp, SalVideo);
1807 if (old_stream && new_stream) {
1808 const SalStreamDescription *local_st_desc = sal_media_description_find_stream(call->localdesc, SalProtoRtpSavp, SalVideo);
1809 if (local_st_desc) {
1810 int crypto_idx = find_crypto_index_from_tag(local_st_desc->crypto, new_stream->crypto_local_tag);
1811 if (crypto_idx >= 0) {
1812 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);
1813 call->videostream_encrypted = TRUE;
1815 ms_warning("Failed to find local crypto algo with tag: %d", new_stream->crypto_local_tag);
1816 call->videostream_encrypted = FALSE;
1818 for (i = 0; i < SAL_CRYPTO_ALGO_MAX; i++) {
1819 old_stream->crypto[i].tag = new_stream->crypto[i].tag;
1820 old_stream->crypto[i].algo = new_stream->crypto[i].algo;
1821 strncpy(old_stream->crypto[i].master_key, new_stream->crypto[i].master_key, sizeof(old_stream->crypto[i].master_key) - 1);
1828 void linphone_call_update_remote_session_id_and_ver(LinphoneCall *call) {
1829 SalMediaDescription *remote_desc = sal_call_get_remote_media_description(call->op);
1831 call->remote_session_id = remote_desc->session_id;
1832 call->remote_session_ver = remote_desc->session_ver;
1836 void linphone_call_delete_ice_session(LinphoneCall *call){
1837 if (call->ice_session != NULL) {
1838 ice_session_destroy(call->ice_session);
1839 call->ice_session = NULL;
1840 if (call->audiostream != NULL) call->audiostream->ms.ice_check_list = NULL;
1841 if (call->videostream != NULL) call->videostream->ms.ice_check_list = NULL;
1842 call->stats[LINPHONE_CALL_STATS_AUDIO].ice_state = LinphoneIceStateNotActivated;
1843 call->stats[LINPHONE_CALL_STATS_VIDEO].ice_state = LinphoneIceStateNotActivated;
1848 void linphone_call_delete_upnp_session(LinphoneCall *call){
1849 if(call->upnp_session!=NULL) {
1850 linphone_upnp_session_destroy(call->upnp_session);
1851 call->upnp_session=NULL;
1856 static void linphone_call_log_fill_stats(LinphoneCallLog *log, AudioStream *st){
1857 audio_stream_get_local_rtp_stats (st,&log->local_stats);
1858 log->quality=audio_stream_get_average_quality_rating(st);
1861 void linphone_call_stop_audio_stream(LinphoneCall *call) {
1862 if (call->audiostream!=NULL) {
1863 rtp_session_unregister_event_queue(call->audiostream->ms.session,call->audiostream_app_evq);
1864 ortp_ev_queue_flush(call->audiostream_app_evq);
1865 ortp_ev_queue_destroy(call->audiostream_app_evq);
1866 call->audiostream_app_evq=NULL;
1868 if (call->audiostream->ec){
1869 const char *state_str=NULL;
1870 ms_filter_call_method(call->audiostream->ec,MS_ECHO_CANCELLER_GET_STATE_STRING,&state_str);
1872 ms_message("Writing echo canceler state, %i bytes",(int)strlen(state_str));
1873 lp_config_set_string(call->core->config,"sound","ec_state",state_str);
1876 linphone_call_log_fill_stats (call->log,call->audiostream);
1877 if (call->endpoint){
1878 linphone_call_remove_from_conf(call);
1880 audio_stream_stop(call->audiostream);
1881 call->audiostream=NULL;
1885 void linphone_call_stop_video_stream(LinphoneCall *call) {
1886 #ifdef VIDEO_ENABLED
1887 if (call->videostream!=NULL){
1888 rtp_session_unregister_event_queue(call->videostream->ms.session,call->videostream_app_evq);
1889 ortp_ev_queue_flush(call->videostream_app_evq);
1890 ortp_ev_queue_destroy(call->videostream_app_evq);
1891 call->videostream_app_evq=NULL;
1892 video_stream_stop(call->videostream);
1893 call->videostream=NULL;
1898 void linphone_call_stop_media_streams(LinphoneCall *call){
1899 linphone_call_stop_audio_stream(call);
1900 linphone_call_stop_video_stream(call);
1901 ms_event_queue_skip(call->core->msevq);
1903 if (call->audio_profile){
1904 rtp_profile_clear_all(call->audio_profile);
1905 rtp_profile_destroy(call->audio_profile);
1906 call->audio_profile=NULL;
1908 if (call->video_profile){
1909 rtp_profile_clear_all(call->video_profile);
1910 rtp_profile_destroy(call->video_profile);
1911 call->video_profile=NULL;
1917 void linphone_call_enable_echo_cancellation(LinphoneCall *call, bool_t enable) {
1918 if (call!=NULL && call->audiostream!=NULL && call->audiostream->ec){
1919 bool_t bypass_mode = !enable;
1920 ms_filter_call_method(call->audiostream->ec,MS_ECHO_CANCELLER_SET_BYPASS_MODE,&bypass_mode);
1923 bool_t linphone_call_echo_cancellation_enabled(LinphoneCall *call) {
1924 if (call!=NULL && call->audiostream!=NULL && call->audiostream->ec){
1926 ms_filter_call_method(call->audiostream->ec,MS_ECHO_CANCELLER_GET_BYPASS_MODE,&val);
1929 return linphone_core_echo_cancellation_enabled(call->core);
1933 void linphone_call_enable_echo_limiter(LinphoneCall *call, bool_t val){
1934 if (call!=NULL && call->audiostream!=NULL ) {
1936 const char *type=lp_config_get_string(call->core->config,"sound","el_type","mic");
1937 if (strcasecmp(type,"mic")==0)
1938 audio_stream_enable_echo_limiter(call->audiostream,ELControlMic);
1939 else if (strcasecmp(type,"full")==0)
1940 audio_stream_enable_echo_limiter(call->audiostream,ELControlFull);
1942 audio_stream_enable_echo_limiter(call->audiostream,ELInactive);
1947 bool_t linphone_call_echo_limiter_enabled(const LinphoneCall *call){
1948 if (call!=NULL && call->audiostream!=NULL ){
1949 return call->audiostream->el_type !=ELInactive ;
1951 return linphone_core_echo_limiter_enabled(call->core);
1956 * @addtogroup call_misc
1961 * Returns the measured sound volume played locally (received from remote).
1962 * It is expressed in dbm0.
1964 float linphone_call_get_play_volume(LinphoneCall *call){
1965 AudioStream *st=call->audiostream;
1966 if (st && st->volrecv){
1968 ms_filter_call_method(st->volrecv,MS_VOLUME_GET,&vol);
1972 return LINPHONE_VOLUME_DB_LOWEST;
1976 * Returns the measured sound volume recorded locally (sent to remote).
1977 * It is expressed in dbm0.
1979 float linphone_call_get_record_volume(LinphoneCall *call){
1980 AudioStream *st=call->audiostream;
1981 if (st && st->volsend && !call->audio_muted && call->state==LinphoneCallStreamsRunning){
1983 ms_filter_call_method(st->volsend,MS_VOLUME_GET,&vol);
1987 return LINPHONE_VOLUME_DB_LOWEST;
1991 * Obtain real-time quality rating of the call
1993 * Based on local RTP statistics and RTCP feedback, a quality rating is computed and updated
1994 * during all the duration of the call. This function returns its value at the time of the function call.
1995 * It is expected that the rating is updated at least every 5 seconds or so.
1996 * The rating is a floating point number comprised between 0 and 5.
1998 * 4-5 = good quality <br>
1999 * 3-4 = average quality <br>
2000 * 2-3 = poor quality <br>
2001 * 1-2 = very poor quality <br>
2002 * 0-1 = can't be worse, mostly unusable <br>
2004 * @returns The function returns -1 if no quality measurement is available, for example if no
2005 * active audio stream exist. Otherwise it returns the quality rating.
2007 float linphone_call_get_current_quality(LinphoneCall *call){
2008 if (call->audiostream){
2009 return audio_stream_get_quality_rating(call->audiostream);
2015 * Returns call quality averaged over all the duration of the call.
2017 * See linphone_call_get_current_quality() for more details about quality measurement.
2019 float linphone_call_get_average_quality(LinphoneCall *call){
2020 if (call->audiostream){
2021 return audio_stream_get_average_quality_rating(call->audiostream);
2027 * Access last known statistics for audio stream, for a given call.
2029 const LinphoneCallStats *linphone_call_get_audio_stats(const LinphoneCall *call) {
2030 return &call->stats[LINPHONE_CALL_STATS_AUDIO];
2034 * Access last known statistics for video stream, for a given call.
2036 const LinphoneCallStats *linphone_call_get_video_stats(const LinphoneCall *call) {
2037 return &call->stats[LINPHONE_CALL_STATS_VIDEO];
2041 * Enable recording of the call (voice-only).
2042 * This function must be used before the call parameters are assigned to the call.
2043 * The call recording can be started and paused after the call is established with
2044 * linphone_call_start_recording() and linphone_call_pause_recording().
2045 * @param cp the call parameters
2046 * @param path path and filename of the file where audio is written.
2048 void linphone_call_params_set_record_file(LinphoneCallParams *cp, const char *path){
2049 if (cp->record_file){
2050 ms_free(cp->record_file);
2051 cp->record_file=NULL;
2053 if (path) cp->record_file=ms_strdup(path);
2057 * Retrieves the path for the audio recoding of the call.
2059 const char *linphone_call_params_get_record_file(const LinphoneCallParams *cp){
2060 return cp->record_file;
2064 * Start call recording.
2065 * The output file where audio is recorded must be previously specified with linphone_call_params_set_record_file().
2067 void linphone_call_start_recording(LinphoneCall *call){
2068 if (!call->params.record_file){
2069 ms_error("linphone_call_start_recording(): no output file specified. Use linphone_call_params_set_record_file().");
2072 if (call->audiostream && !call->params.in_conference){
2073 audio_stream_mixed_record_start(call->audiostream);
2075 call->record_active=TRUE;
2079 * Stop call recording.
2081 void linphone_call_stop_recording(LinphoneCall *call){
2082 if (call->audiostream && !call->params.in_conference){
2083 audio_stream_mixed_record_stop(call->audiostream);
2085 call->record_active=FALSE;
2092 static void report_bandwidth(LinphoneCall *call, RtpSession *as, RtpSession *vs){
2093 call->stats[LINPHONE_CALL_STATS_AUDIO].download_bandwidth=(as!=NULL) ? (rtp_session_compute_recv_bandwidth(as)*1e-3) : 0;
2094 call->stats[LINPHONE_CALL_STATS_AUDIO].upload_bandwidth=(as!=NULL) ? (rtp_session_compute_send_bandwidth(as)*1e-3) : 0;
2095 call->stats[LINPHONE_CALL_STATS_VIDEO].download_bandwidth=(vs!=NULL) ? (rtp_session_compute_recv_bandwidth(vs)*1e-3) : 0;
2096 call->stats[LINPHONE_CALL_STATS_VIDEO].upload_bandwidth=(vs!=NULL) ? (rtp_session_compute_send_bandwidth(vs)*1e-3) : 0;
2097 ms_message("bandwidth usage: audio=[d=%.1f,u=%.1f] video=[d=%.1f,u=%.1f] kbit/sec",
2098 call->stats[LINPHONE_CALL_STATS_AUDIO].download_bandwidth,
2099 call->stats[LINPHONE_CALL_STATS_AUDIO].upload_bandwidth ,
2100 call->stats[LINPHONE_CALL_STATS_VIDEO].download_bandwidth,
2101 call->stats[LINPHONE_CALL_STATS_VIDEO].upload_bandwidth
2105 static void linphone_core_disconnected(LinphoneCore *lc, LinphoneCall *call){
2109 from = linphone_call_get_remote_address_as_string(call);
2112 snprintf(temp,sizeof(temp),"Remote end %s seems to have disconnected, the call is going to be closed.",from);
2117 snprintf(temp,sizeof(temp),"Remote end seems to have disconnected, the call is going to be closed.");
2119 if (lc->vtable.display_warning!=NULL)
2120 lc->vtable.display_warning(lc,temp);
2121 linphone_core_terminate_call(lc,call);
2124 static void handle_ice_events(LinphoneCall *call, OrtpEvent *ev){
2125 OrtpEventType evt=ortp_event_get_type(ev);
2126 OrtpEventData *evd=ortp_event_get_data(ev);
2129 if (evt == ORTP_EVENT_ICE_SESSION_PROCESSING_FINISHED) {
2130 switch (ice_session_state(call->ice_session)) {
2132 ice_session_select_candidates(call->ice_session);
2133 if (ice_session_role(call->ice_session) == IR_Controlling) {
2134 linphone_core_update_call(call->core, call, &call->current_params);
2138 if (ice_session_has_completed_check_list(call->ice_session) == TRUE) {
2139 ice_session_select_candidates(call->ice_session);
2140 if (ice_session_role(call->ice_session) == IR_Controlling) {
2141 /* At least one ICE session has succeeded, so perform a call update. */
2142 linphone_core_update_call(call->core, call, &call->current_params);
2149 linphone_core_update_ice_state_in_call_stats(call);
2150 } else if (evt == ORTP_EVENT_ICE_GATHERING_FINISHED) {
2152 if (evd->info.ice_processing_successful==TRUE) {
2153 ice_session_compute_candidates_foundations(call->ice_session);
2154 ice_session_eliminate_redundant_candidates(call->ice_session);
2155 ice_session_choose_default_candidates(call->ice_session);
2156 ping_time = ice_session_average_gathering_round_trip_time(call->ice_session);
2157 if (ping_time >=0) {
2158 call->ping_time=ping_time;
2161 ms_warning("No STUN answer from [%s], disabling ICE",linphone_core_get_stun_server(call->core));
2162 linphone_call_delete_ice_session(call);
2164 switch (call->state) {
2165 case LinphoneCallUpdating:
2166 linphone_core_start_update_call(call->core, call);
2168 case LinphoneCallUpdatedByRemote:
2169 linphone_core_start_accept_call_update(call->core, call);
2171 case LinphoneCallOutgoingInit:
2172 linphone_call_stop_media_streams_for_ice_gathering(call);
2173 linphone_core_proceed_with_invite_if_ready(call->core, call, NULL);
2175 case LinphoneCallIdle:
2176 linphone_call_stop_media_streams_for_ice_gathering(call);
2177 linphone_core_notify_incoming_call(call->core, call);
2182 } else if (evt == ORTP_EVENT_ICE_LOSING_PAIRS_COMPLETED) {
2183 linphone_core_start_accept_call_update(call->core, call);
2184 linphone_core_update_ice_state_in_call_stats(call);
2185 } else if (evt == ORTP_EVENT_ICE_RESTART_NEEDED) {
2186 ice_session_restart(call->ice_session);
2187 ice_session_set_role(call->ice_session, IR_Controlling);
2188 linphone_core_update_call(call->core, call, &call->current_params);
2192 void linphone_call_background_tasks(LinphoneCall *call, bool_t one_second_elapsed){
2193 LinphoneCore* lc = call->core;
2194 int disconnect_timeout = linphone_core_get_nortp_timeout(call->core);
2195 bool_t disconnected=FALSE;
2197 if (call->state==LinphoneCallStreamsRunning && one_second_elapsed){
2198 RtpSession *as=NULL,*vs=NULL;
2199 float audio_load=0, video_load=0;
2200 if (call->audiostream!=NULL){
2201 as=call->audiostream->ms.session;
2202 if (call->audiostream->ms.ticker)
2203 audio_load=ms_ticker_get_average_load(call->audiostream->ms.ticker);
2205 if (call->videostream!=NULL){
2206 if (call->videostream->ms.ticker)
2207 video_load=ms_ticker_get_average_load(call->videostream->ms.ticker);
2208 vs=call->videostream->ms.session;
2210 report_bandwidth(call,as,vs);
2211 ms_message("Thread processing load: audio=%f\tvideo=%f",audio_load,video_load);
2215 linphone_upnp_call_process(call);
2218 #ifdef VIDEO_ENABLED
2219 if (call->videostream!=NULL) {
2222 /* Ensure there is no dangling ICE check list. */
2223 if (call->ice_session == NULL) call->videostream->ms.ice_check_list = NULL;
2225 // Beware that the application queue should not depend on treatments fron the
2226 // mediastreamer queue.
2227 video_stream_iterate(call->videostream);
2229 while (call->videostream_app_evq && (NULL != (ev=ortp_ev_queue_get(call->videostream_app_evq)))){
2230 OrtpEventType evt=ortp_event_get_type(ev);
2231 OrtpEventData *evd=ortp_event_get_data(ev);
2232 if (evt == ORTP_EVENT_ZRTP_ENCRYPTION_CHANGED){
2233 linphone_call_videostream_encryption_changed(call, evd->info.zrtp_stream_encrypted);
2234 } else if (evt == ORTP_EVENT_RTCP_PACKET_RECEIVED) {
2235 call->stats[LINPHONE_CALL_STATS_VIDEO].round_trip_delay = rtp_session_get_round_trip_propagation(call->videostream->ms.session);
2236 if(call->stats[LINPHONE_CALL_STATS_VIDEO].received_rtcp != NULL)
2237 freemsg(call->stats[LINPHONE_CALL_STATS_VIDEO].received_rtcp);
2238 call->stats[LINPHONE_CALL_STATS_VIDEO].received_rtcp = evd->packet;
2240 if (lc->vtable.call_stats_updated)
2241 lc->vtable.call_stats_updated(lc, call, &call->stats[LINPHONE_CALL_STATS_VIDEO]);
2242 } else if (evt == ORTP_EVENT_RTCP_PACKET_EMITTED) {
2243 memcpy(&call->stats[LINPHONE_CALL_STATS_VIDEO].jitter_stats, rtp_session_get_jitter_stats(call->videostream->ms.session), sizeof(jitter_stats_t));
2244 if(call->stats[LINPHONE_CALL_STATS_VIDEO].sent_rtcp != NULL)
2245 freemsg(call->stats[LINPHONE_CALL_STATS_VIDEO].sent_rtcp);
2246 call->stats[LINPHONE_CALL_STATS_VIDEO].sent_rtcp = evd->packet;
2248 if (lc->vtable.call_stats_updated)
2249 lc->vtable.call_stats_updated(lc, call, &call->stats[LINPHONE_CALL_STATS_VIDEO]);
2250 } else if ((evt == ORTP_EVENT_ICE_SESSION_PROCESSING_FINISHED) || (evt == ORTP_EVENT_ICE_GATHERING_FINISHED)
2251 || (evt == ORTP_EVENT_ICE_LOSING_PAIRS_COMPLETED) || (evt == ORTP_EVENT_ICE_RESTART_NEEDED)) {
2252 handle_ice_events(call, ev);
2254 ortp_event_destroy(ev);
2258 if (call->audiostream!=NULL) {
2261 /* Ensure there is no dangling ICE check list. */
2262 if (call->ice_session == NULL) call->audiostream->ms.ice_check_list = NULL;
2264 // Beware that the application queue should not depend on treatments fron the
2265 // mediastreamer queue.
2266 audio_stream_iterate(call->audiostream);
2268 while (call->audiostream_app_evq && (NULL != (ev=ortp_ev_queue_get(call->audiostream_app_evq)))){
2269 OrtpEventType evt=ortp_event_get_type(ev);
2270 OrtpEventData *evd=ortp_event_get_data(ev);
2271 if (evt == ORTP_EVENT_ZRTP_ENCRYPTION_CHANGED){
2272 linphone_call_audiostream_encryption_changed(call, evd->info.zrtp_stream_encrypted);
2273 } else if (evt == ORTP_EVENT_ZRTP_SAS_READY) {
2274 linphone_call_audiostream_auth_token_ready(call, evd->info.zrtp_sas.sas, evd->info.zrtp_sas.verified);
2275 } else if (evt == ORTP_EVENT_RTCP_PACKET_RECEIVED) {
2276 call->stats[LINPHONE_CALL_STATS_AUDIO].round_trip_delay = rtp_session_get_round_trip_propagation(call->audiostream->ms.session);
2277 if(call->stats[LINPHONE_CALL_STATS_AUDIO].received_rtcp != NULL)
2278 freemsg(call->stats[LINPHONE_CALL_STATS_AUDIO].received_rtcp);
2279 call->stats[LINPHONE_CALL_STATS_AUDIO].received_rtcp = evd->packet;
2281 if (lc->vtable.call_stats_updated)
2282 lc->vtable.call_stats_updated(lc, call, &call->stats[LINPHONE_CALL_STATS_AUDIO]);
2283 } else if (evt == ORTP_EVENT_RTCP_PACKET_EMITTED) {
2284 memcpy(&call->stats[LINPHONE_CALL_STATS_AUDIO].jitter_stats, rtp_session_get_jitter_stats(call->audiostream->ms.session), sizeof(jitter_stats_t));
2285 if(call->stats[LINPHONE_CALL_STATS_AUDIO].sent_rtcp != NULL)
2286 freemsg(call->stats[LINPHONE_CALL_STATS_AUDIO].sent_rtcp);
2287 call->stats[LINPHONE_CALL_STATS_AUDIO].sent_rtcp = evd->packet;
2289 if (lc->vtable.call_stats_updated)
2290 lc->vtable.call_stats_updated(lc, call, &call->stats[LINPHONE_CALL_STATS_AUDIO]);
2291 } else if ((evt == ORTP_EVENT_ICE_SESSION_PROCESSING_FINISHED) || (evt == ORTP_EVENT_ICE_GATHERING_FINISHED)
2292 || (evt == ORTP_EVENT_ICE_LOSING_PAIRS_COMPLETED) || (evt == ORTP_EVENT_ICE_RESTART_NEEDED)) {
2293 handle_ice_events(call, ev);
2294 } else if (evt==ORTP_EVENT_TELEPHONE_EVENT){
2295 linphone_core_dtmf_received(lc,evd->info.telephone_event);
2297 ortp_event_destroy(ev);
2300 if (call->state==LinphoneCallStreamsRunning && one_second_elapsed && call->audiostream!=NULL && disconnect_timeout>0 )
2301 disconnected=!audio_stream_alive(call->audiostream,disconnect_timeout);
2303 linphone_core_disconnected(call->core,call);
2306 void linphone_call_log_completed(LinphoneCall *call){
2307 LinphoneCore *lc=call->core;
2309 call->log->duration=time(NULL)-call->start_time;
2311 if (call->log->status==LinphoneCallMissed){
2314 info=ortp_strdup_printf(ngettext("You have missed %i call.",
2315 "You have missed %i calls.", lc->missed_calls),
2317 if (lc->vtable.display_status!=NULL)
2318 lc->vtable.display_status(lc,info);
2321 lc->call_logs=ms_list_prepend(lc->call_logs,(void *)call->log);
2322 if (ms_list_size(lc->call_logs)>lc->max_call_logs){
2323 MSList *elem,*prevelem=NULL;
2324 /*find the last element*/
2325 for(elem=lc->call_logs;elem!=NULL;elem=elem->next){
2329 linphone_call_log_destroy((LinphoneCallLog*)elem->data);
2330 lc->call_logs=ms_list_remove_link(lc->call_logs,elem);
2332 if (lc->vtable.call_log_updated!=NULL){
2333 lc->vtable.call_log_updated(lc,call->log);
2335 call_logs_write_to_config_file(lc);
2338 LinphoneCallState linphone_call_get_transfer_state(LinphoneCall *call) {
2339 return call->transfer_state;
2342 void linphone_call_set_transfer_state(LinphoneCall* call, LinphoneCallState state) {
2343 if (state != call->transfer_state) {
2344 LinphoneCore* lc = call->core;
2345 call->transfer_state = state;
2346 if (lc->vtable.transfer_state_changed)
2347 lc->vtable.transfer_state_changed(lc, call, state);
2352 * Returns true if the call is part of the conference.
2353 * @ingroup conferencing
2355 bool_t linphone_call_is_in_conference(const LinphoneCall *call) {
2356 return call->params.in_conference;
2361 * Perform a zoom of the video displayed during a call.
2362 * @param call the call.
2363 * @param zoom_factor a floating point number describing the zoom factor. A value 1.0 corresponds to no zoom applied.
2364 * @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.
2365 * @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.
2367 * 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.
2369 void linphone_call_zoom_video(LinphoneCall* call, float zoom_factor, float* cx, float* cy) {
2370 VideoStream* vstream = call->videostream;
2371 if (vstream && vstream->output) {
2374 if (zoom_factor < 1)
2376 float halfsize = 0.5 * 1.0 / zoom_factor;
2378 if ((*cx - halfsize) < 0)
2380 if ((*cx + halfsize) > 1)
2382 if ((*cy - halfsize) < 0)
2384 if ((*cy + halfsize) > 1)
2387 zoom[0] = zoom_factor;
2390 ms_filter_call_method(vstream->output, MS_VIDEO_DISPLAY_ZOOM, &zoom);
2391 }else ms_warning("Could not apply zoom: video output wasn't activated.");