linphonecall.c 91.1 KB
Newer Older
1 2 3

/*
linphone
4
Copyright (C) 2010  Belledonne Communications SARL
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
 (simon.morlat@linphone.org)

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
*/
21 22 23
#ifdef WIN32
#include <time.h>
#endif
24 25 26 27
#include "linphonecore.h"
#include "sipsetup.h"
#include "lpconfig.h"
#include "private.h"
28
#include <ortp/event.h>
29
#include <ortp/b64.h>
Yann Diorcet's avatar
Yann Diorcet committed
30
#include <math.h>
31

32 33 34
#include "mediastreamer2/mediastream.h"
#include "mediastreamer2/msvolume.h"
#include "mediastreamer2/msequalizer.h"
35
#include "mediastreamer2/msfileplayer.h"
36
#include "mediastreamer2/msjpegwriter.h"
37
#include "mediastreamer2/mseventqueue.h"
38
#include "mediastreamer2/mssndcard.h"
39

Simon Morlat's avatar
Simon Morlat committed
40
#ifdef VIDEO_ENABLED
41 42 43
static MSWebCam *get_nowebcam_device(){
	return ms_web_cam_manager_get_cam(ms_web_cam_manager_get(),"StaticImage: Static picture");
}
Simon Morlat's avatar
Simon Morlat committed
44
#endif
45

46 47 48
static bool_t generate_b64_crypto_key(int key_length, char* key_out) {
	int b64_size;
	uint8_t* tmp = (uint8_t*) malloc(key_length);			
49
	if (ortp_crypto_get_random(tmp, key_length)!=0) {
50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66
		ms_error("Failed to generate random key");
		free(tmp);
		return FALSE;
	}
	
	b64_size = b64_encode((const char*)tmp, key_length, NULL, 0);
	if (b64_size == 0) {
		ms_error("Failed to b64 encode key");
		free(tmp);
		return FALSE;
	}
	key_out[b64_size] = '\0';
	b64_encode((const char*)tmp, key_length, key_out, 40);
	free(tmp);
	return TRUE;
}

67 68 69 70
LinphoneCore *linphone_call_get_core(const LinphoneCall *call){
	return call->core;
}

71
const char* linphone_call_get_authentication_token(LinphoneCall *call){
72
	return call->auth_token;
73 74 75
}

bool_t linphone_call_get_authentication_token_verified(LinphoneCall *call){
76
	return call->auth_token_verified;
77
}
Simon Morlat's avatar
Simon Morlat committed
78 79

static bool_t linphone_call_are_all_streams_encrypted(LinphoneCall *call) {
80
	// Check ZRTP encryption in audiostream
81
	if (!call->audiostream_encrypted) {
82 83 84 85 86
		return FALSE;
	}

#ifdef VIDEO_ENABLED
	// If video enabled, check ZRTP encryption in videostream
87 88 89 90 91
	{
		const LinphoneCallParams *params=linphone_call_get_current_params(call);
		if (params->has_video && !call->videostream_encrypted) {
			return FALSE;
		}
92 93 94 95 96 97
	}
#endif

	return TRUE;
}

98
void propagate_encryption_changed(LinphoneCall *call){
Simon Morlat's avatar
Simon Morlat committed
99
	LinphoneCore *lc=call->core;
100
	if (!linphone_call_are_all_streams_encrypted(call)) {
101
		ms_message("Some streams are not encrypted");
Simon Morlat's avatar
Simon Morlat committed
102
		call->current_params.media_encryption=LinphoneMediaEncryptionNone;
Simon Morlat's avatar
Simon Morlat committed
103 104
		if (lc->vtable.call_encryption_changed)
			lc->vtable.call_encryption_changed(call->core, call, FALSE, call->auth_token);
105
	} else {
106
		ms_message("All streams are encrypted");
Simon Morlat's avatar
Simon Morlat committed
107 108 109
		call->current_params.media_encryption=LinphoneMediaEncryptionZRTP;
		if (lc->vtable.call_encryption_changed)
			lc->vtable.call_encryption_changed(call->core, call, TRUE, call->auth_token);
110 111 112 113 114 115
	}
}

#ifdef VIDEO_ENABLED
static void linphone_call_videostream_encryption_changed(void *data, bool_t encrypted){
	LinphoneCall *call = (LinphoneCall *)data;
116 117

	ms_message("Video stream is %s", encrypted ? "encrypted" : "not encrypted");
118
	call->videostream_encrypted=encrypted;
119 120 121 122 123
	propagate_encryption_changed(call);
}
#endif

static void linphone_call_audiostream_encryption_changed(void *data, bool_t encrypted) {
124
	char status[255]={0};
Sylvain Berfini's avatar
Sylvain Berfini committed
125
	LinphoneCall *call;
126 127
	ms_message("Audio stream is %s ", encrypted ? "encrypted" : "not encrypted");

Sylvain Berfini's avatar
Sylvain Berfini committed
128
	call = (LinphoneCall *)data;
129
	call->audiostream_encrypted=encrypted;
Simon Morlat's avatar
Simon Morlat committed
130
	
131 132 133 134 135
	if (encrypted && call->core->vtable.display_status != NULL) {
		snprintf(status,sizeof(status)-1,_("Authentication token is %s"),call->auth_token);
		 call->core->vtable.display_status(call->core, status);
	}

136 137 138 139 140
	propagate_encryption_changed(call);


#ifdef VIDEO_ENABLED
	// Enable video encryption
141 142 143 144 145 146 147 148
	{
		const LinphoneCallParams *params=linphone_call_get_current_params(call);
		if (params->has_video) {
			OrtpZrtpParams params;
			ms_message("Trying to enable encryption on video stream");
			params.zid_file=NULL; //unused
			video_stream_enable_zrtp(call->videostream,call->audiostream,&params);
		}
149 150 151 152 153 154 155
	}
#endif
}


static void linphone_call_audiostream_auth_token_ready(void *data, const char* auth_token, bool_t verified) {
	LinphoneCall *call=(LinphoneCall *)data;
156 157
	if (call->auth_token != NULL)
		ms_free(call->auth_token);
158

159 160
	call->auth_token=ms_strdup(auth_token);
	call->auth_token_verified=verified;
161 162 163 164

	ms_message("Authentication token is %s (%s)", auth_token, verified?"verified":"unverified");
}

Simon Morlat's avatar
Simon Morlat committed
165 166 167 168
void linphone_call_set_authentication_token_verified(LinphoneCall *call, bool_t verified){
	if (call->audiostream==NULL){
		ms_error("linphone_call_set_authentication_token_verified(): No audio stream");
	}
Ghislain MARY's avatar
Ghislain MARY committed
169
	if (call->audiostream->ms.zrtp_context==NULL){
Simon Morlat's avatar
Simon Morlat committed
170 171 172
		ms_error("linphone_call_set_authentication_token_verified(): No zrtp context.");
	}
	if (!call->auth_token_verified && verified){
Ghislain MARY's avatar
Ghislain MARY committed
173
		ortp_zrtp_sas_verified(call->audiostream->ms.zrtp_context);
Simon Morlat's avatar
Simon Morlat committed
174
	}else if (call->auth_token_verified && !verified){
Ghislain MARY's avatar
Ghislain MARY committed
175
		ortp_zrtp_sas_reset_verified(call->audiostream->ms.zrtp_context);
Simon Morlat's avatar
Simon Morlat committed
176 177 178 179
	}
	call->auth_token_verified=verified;
	propagate_encryption_changed(call);
}
180

181
static MSList *make_codec_list(LinphoneCore *lc, const MSList *codecs, int bandwidth_limit,int* max_sample_rate, int nb_codecs_limit){
182 183
	MSList *l=NULL;
	const MSList *it;
184
	int nb = 0;
185
	if (max_sample_rate) *max_sample_rate=0;
186 187
	for(it=codecs;it!=NULL;it=it->next){
		PayloadType *pt=(PayloadType*)it->data;
188 189
		if (pt->flags & PAYLOAD_TYPE_ENABLED){
			if (bandwidth_limit>0 && !linphone_core_is_payload_type_usable_for_bandwidth(lc,pt,bandwidth_limit)){
Simon Morlat's avatar
Simon Morlat committed
190 191
				ms_message("Codec %s/%i eliminated because of audio bandwidth constraint of %i kbit/s",
					   pt->mime_type,pt->clock_rate,bandwidth_limit);
192 193 194 195
				continue;
			}
			if (linphone_core_check_payload_type_usability(lc,pt)){
				l=ms_list_append(l,payload_type_clone(pt));
196
				nb++;
197
				if (max_sample_rate && payload_type_get_rate(pt)>*max_sample_rate) *max_sample_rate=payload_type_get_rate(pt);
198
			}
199
		}
200
		if ((nb_codecs_limit > 0) && (nb >= nb_codecs_limit)) break;
201 202 203 204
	}
	return l;
}

205
static void update_media_description_from_stun(SalMediaDescription *md, const StunCandidate *ac, const StunCandidate *vc){
206 207 208 209 210 211 212 213 214 215 216 217
	int i;
	for (i = 0; i < md->n_active_streams; i++) {
		if ((md->streams[i].type == SalAudio) && (ac->port != 0)) {
			strcpy(md->streams[0].rtp_addr,ac->addr);
			md->streams[0].rtp_port=ac->port;
			if ((ac->addr[0]!='\0' && vc->addr[0]!='\0' && strcmp(ac->addr,vc->addr)==0) || md->n_active_streams==1){
				strcpy(md->addr,ac->addr);
			}
		}
		if ((md->streams[i].type == SalVideo) && (vc->port != 0)) {
			strcpy(md->streams[1].rtp_addr,vc->addr);
			md->streams[1].rtp_port=vc->port;
218 219 220 221
		}
	}
}

Simon Morlat's avatar
Simon Morlat committed
222
void linphone_call_make_local_media_description(LinphoneCore *lc, LinphoneCall *call){
223 224
	MSList *l;
	PayloadType *pt;
Simon Morlat's avatar
Simon Morlat committed
225
	SalMediaDescription *old_md=call->localdesc;
226
	int i;
227
	const char *me;
228
	SalMediaDescription *md=sal_media_description_new();
229
	LinphoneAddress *addr;
Simon Morlat's avatar
Simon Morlat committed
230
	bool_t keep_srtp_keys=lp_config_get_int(lc->config,"sip","keep_srtp_keys",0);
231
	char* local_ip=call->localip;
232

233
	linphone_core_adapt_to_network(lc,call->ping_time,&call->params);
234

235 236 237 238 239 240
	if (call->dest_proxy)
		me=linphone_proxy_config_get_identity(call->dest_proxy);
	else 
		me=linphone_core_get_identity(lc);
	addr=linphone_address_new(me);
	
Simon Morlat's avatar
Simon Morlat committed
241 242
	md->session_id=(old_md ? old_md->session_id : (rand() & 0xfff));
	md->session_ver=(old_md ? (old_md->session_ver+1) : (rand() & 0xfff));
243 244
	md->n_total_streams=(old_md ? old_md->n_total_streams : 1);
	md->n_active_streams=1;
jehan's avatar
jehan committed
245
	strncpy(md->addr,local_ip,sizeof(md->addr));
246
	strncpy(md->username,linphone_address_get_username(addr),sizeof(md->username));
247 248 249 250
	
	if (call->params.down_bw)
		md->bandwidth=call->params.down_bw;
	else md->bandwidth=linphone_core_get_download_bandwidth(lc);
251

252
	/*set audio capabilities */
jehan's avatar
jehan committed
253 254
	strncpy(md->streams[0].rtp_addr,local_ip,sizeof(md->streams[0].rtp_addr));
	strncpy(md->streams[0].rtcp_addr,local_ip,sizeof(md->streams[0].rtcp_addr));
255
	md->streams[0].rtp_port=call->audio_port;
256
	md->streams[0].rtcp_port=call->audio_port+1;
257 258
	md->streams[0].proto=(call->params.media_encryption == LinphoneMediaEncryptionSRTP) ? 
		SalProtoRtpSavp : SalProtoRtpAvp;
259
	md->streams[0].type=SalAudio;
260 261 262
	if (call->params.down_ptime)
		md->streams[0].ptime=call->params.down_ptime;
	else
263
		md->streams[0].ptime=linphone_core_get_download_ptime(lc);
264
	l=make_codec_list(lc,lc->codecs_conf.audio_codecs,call->params.audio_bw,&md->streams[0].max_rate,-1);
Simon Morlat's avatar
Simon Morlat committed
265
	pt=payload_type_clone(rtp_profile_get_payload_from_mime(lc->default_profile,"telephone-event"));
266 267 268
	l=ms_list_append(l,pt);
	md->streams[0].payloads=l;

Simon Morlat's avatar
Simon Morlat committed
269
	if (call->params.has_video){
270
		md->n_active_streams++;
271
		md->streams[1].rtp_port=call->video_port;
272
		md->streams[1].rtcp_port=call->video_port+1;
273
		md->streams[1].proto=md->streams[0].proto;
274
		md->streams[1].type=SalVideo;
275
		l=make_codec_list(lc,lc->codecs_conf.video_codecs,0,NULL,-1);
276 277
		md->streams[1].payloads=l;
	}
278 279 280 281 282 283 284 285 286 287 288 289 290 291 292
	if (md->n_total_streams < md->n_active_streams)
		md->n_total_streams = md->n_active_streams;

	/* Deactivate inactive streams. */
	for (i = md->n_active_streams; i < md->n_total_streams; i++) {
		md->streams[i].rtp_port = 0;
		md->streams[i].rtcp_port = 0;
		md->streams[i].proto = SalProtoRtpAvp;
		md->streams[i].type = old_md->streams[i].type;
		md->streams[i].dir = SalStreamInactive;
		l = make_codec_list(lc, lc->codecs_conf.video_codecs, 0, NULL, 1);
		md->streams[i].payloads = l;
	}

	for(i=0; i<md->n_active_streams; i++) {
293
		if (md->streams[i].proto == SalProtoRtpSavp) {
Simon Morlat's avatar
Simon Morlat committed
294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309
			if (keep_srtp_keys && old_md && old_md->streams[i].proto==SalProtoRtpSavp){
				int j;
				for(j=0;j<SAL_CRYPTO_ALGO_MAX;++j){
					memcpy(&md->streams[i].crypto[j],&old_md->streams[i].crypto[j],sizeof(SalSrtpCryptoAlgo));
				}
			}else{
				md->streams[i].crypto[0].tag = 1;
				md->streams[i].crypto[0].algo = AES_128_SHA1_80;
				if (!generate_b64_crypto_key(30, md->streams[i].crypto[0].master_key))
					md->streams[i].crypto[0].algo = 0;
				md->streams[i].crypto[1].tag = 2;
				md->streams[i].crypto[1].algo = AES_128_SHA1_32;
				if (!generate_b64_crypto_key(30, md->streams[i].crypto[1].master_key))
					md->streams[i].crypto[1].algo = 0;
				md->streams[i].crypto[2].algo = 0;
			}
310
		}
311
	}
312
	update_media_description_from_stun(md,&call->ac,&call->vc);
313 314
	if (call->ice_session != NULL) {
		linphone_core_update_local_media_description_from_ice(md, call->ice_session);
315
		linphone_core_update_ice_state_in_call_stats(call);
316
	}
Yann Diorcet's avatar
Yann Diorcet committed
317 318 319
#ifdef BUILD_UPNP
	if(call->upnp_session != NULL) {
		linphone_core_update_local_media_description_from_upnp(md, call->upnp_session);
Yann Diorcet's avatar
Yann Diorcet committed
320
		linphone_core_update_upnp_state_in_call_stats(call);
Yann Diorcet's avatar
Yann Diorcet committed
321
	}
322
#endif  //BUILD_UPNP
323
	linphone_address_destroy(addr);
Simon Morlat's avatar
Simon Morlat committed
324 325
	call->localdesc=md;
	if (old_md) sal_media_description_unref(old_md);
326 327
}

328
static int find_port_offset(LinphoneCore *lc, SalStreamType type){
329 330
	int offset;
	MSList *elem;
331 332
	int tried_port;
	int existing_port;
333
	bool_t already_used=FALSE;
334
	for(offset=0;offset<100;offset+=2){
335 336 337 338 339 340 341 342 343
		switch (type) {
			default:
			case SalAudio:
				tried_port=linphone_core_get_audio_port (lc)+offset;
				break;
			case SalVideo:
				tried_port=linphone_core_get_video_port (lc)+offset;
				break;
		}
344 345 346
		already_used=FALSE;
		for(elem=lc->calls;elem!=NULL;elem=elem->next){
			LinphoneCall *call=(LinphoneCall*)elem->data;
347 348 349 350 351 352 353 354 355 356
			switch (type) {
				default:
				case SalAudio:
					existing_port = call->audio_port;
					break;
				case SalVideo:
					existing_port = call->video_port;
					break;
			}
			if (existing_port==tried_port) {
357 358 359 360 361 362 363 364 365 366 367 368 369
				already_used=TRUE;
				break;
			}
		}
		if (!already_used) break;
	}
	if (offset==100){
		ms_error("Could not find any free port !");
		return -1;
	}
	return offset;
}

370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414
static int select_random_port(LinphoneCore *lc, SalStreamType type) {
	MSList *elem;
	int nb_tries;
	int tried_port = 0;
	int existing_port = 0;
	int min_port = 0, max_port = 0;
	bool_t already_used = FALSE;

	switch (type) {
		default:
		case SalAudio:
			linphone_core_get_audio_port_range(lc, &min_port, &max_port);
			break;
		case SalVideo:
			linphone_core_get_video_port_range(lc, &min_port, &max_port);
			break;
	}
	tried_port = (rand() % (max_port - min_port) + min_port) & ~0x1;
	if (tried_port < min_port) tried_port = min_port + 2;
	for (nb_tries = 0; nb_tries < 100; nb_tries++) {
		for (elem = lc->calls; elem != NULL; elem = elem->next) {
			LinphoneCall *call = (LinphoneCall *)elem->data;
			switch (type) {
				default:
				case SalAudio:
					existing_port = call->audio_port;
					break;
				case SalVideo:
					existing_port = call->video_port;
					break;
			}
			if (existing_port == tried_port) {
				already_used = TRUE;
				break;
			}
		}
		if (!already_used) break;
	}
	if (nb_tries == 100) {
		ms_error("Could not find any free port!");
		return -1;
	}
	return tried_port;
}

415
static void linphone_call_init_common(LinphoneCall *call, LinphoneAddress *from, LinphoneAddress *to){
416
	LinphonePresenceModel *model;
417
	int port_offset;
418
	int min_port, max_port;
419

420
	call->magic=linphone_call_magic;
421
	call->refcnt=1;
422
	call->state=LinphoneCallIdle;
423
	call->transfer_state = LinphoneCallIdle;
424 425 426
	call->start_time=time(NULL);
	call->media_start_time=0;
	call->log=linphone_call_log_new(call, from, to);
427
	call->owns_call_log=TRUE;
428 429
	model = linphone_presence_model_new_with_activity(LinphonePresenceActivityOnThePhone, NULL);
	linphone_core_notify_all_friends(call->core,model);
430
	linphone_presence_model_unref(model);
431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450
	linphone_core_get_audio_port_range(call->core, &min_port, &max_port);
	if (min_port == max_port) {
		/* Used fixed RTP audio port. */
		port_offset=find_port_offset (call->core, SalAudio);
		if (port_offset==-1) return;
		call->audio_port=linphone_core_get_audio_port(call->core)+port_offset;
	} else {
		/* Select random RTP audio port in the specified range. */
		call->audio_port = select_random_port(call->core, SalAudio);
	}
	linphone_core_get_video_port_range(call->core, &min_port, &max_port);
	if (min_port == max_port) {
		/* Used fixed RTP video port. */
		port_offset=find_port_offset (call->core, SalVideo);
		if (port_offset==-1) return;
		call->video_port=linphone_core_get_video_port(call->core)+port_offset;
	} else {
		/* Select random RTP video port in the specified range. */
		call->video_port = select_random_port(call->core, SalVideo);
	}
Yann Diorcet's avatar
Yann Diorcet committed
451 452 453
	linphone_call_init_stats(&call->stats[LINPHONE_CALL_STATS_AUDIO], LINPHONE_CALL_STATS_AUDIO);
	linphone_call_init_stats(&call->stats[LINPHONE_CALL_STATS_VIDEO], LINPHONE_CALL_STATS_VIDEO);
}
454

Yann Diorcet's avatar
Yann Diorcet committed
455
void linphone_call_init_stats(LinphoneCallStats *stats, int type) {
Yann Diorcet's avatar
Yann Diorcet committed
456
	stats->type = type;
Yann Diorcet's avatar
Yann Diorcet committed
457 458
	stats->received_rtcp = NULL;
	stats->sent_rtcp = NULL;
459
	stats->ice_state = LinphoneIceStateNotActivated;
Yann Diorcet's avatar
Yann Diorcet committed
460 461 462 463 464
#ifdef BUILD_UPNP
	stats->upnp_state = LinphoneUpnpStateIdle;
#else
	stats->upnp_state = LinphoneUpnpStateNotAvailable;
#endif //BUILD_UPNP
465 466
}

467

468 469 470 471 472 473 474 475 476 477 478 479 480
static void discover_mtu(LinphoneCore *lc, const char *remote){
	int mtu;
	if (lc->net_conf.mtu==0	){
		/*attempt to discover mtu*/
		mtu=ms_discover_mtu(remote);
		if (mtu>0){
			ms_set_mtu(mtu);
			ms_message("Discovered mtu is %i, RTP payload max size is %i",
				mtu, ms_get_payload_max_size());
		}
	}
}

Simon Morlat's avatar
Simon Morlat committed
481 482 483 484 485 486 487
void linphone_call_create_op(LinphoneCall *call){
	if (call->op) sal_op_release(call->op);
	call->op=sal_op_new(call->core->sal);
	sal_op_set_user_pointer(call->op,call);
	if (call->params.referer)
		sal_call_set_referer(call->op,call->params.referer->op);
	linphone_configure_op(call->core,call->op,call->log->to,call->params.custom_headers,FALSE);
jehan's avatar
jehan committed
488 489 490
	if (call->params.privacy != LinphonePrivacyDefault)
		sal_op_set_privacy(call->op,(SalPrivacyMask)call->params.privacy);
	/*else privacy might be set by proxy */
Simon Morlat's avatar
Simon Morlat committed
491 492 493
}

LinphoneCall * linphone_call_new_outgoing(struct _LinphoneCore *lc, LinphoneAddress *from, LinphoneAddress *to, const LinphoneCallParams *params, LinphoneProxyConfig *cfg){
494
	LinphoneCall *call=ms_new0(LinphoneCall,1);
Simon Morlat's avatar
Simon Morlat committed
495
	
496 497
	call->dir=LinphoneCallOutgoing;
	call->core=lc;
498
	linphone_core_get_local_ip(lc,NULL,call->localip);
499
	linphone_call_init_common(call,from,to);
Simon Morlat's avatar
Simon Morlat committed
500
	_linphone_call_params_copy(&call->params,params);
501
	
502
	if (linphone_core_get_firewall_policy(call->core) == LinphonePolicyUseIce) {
503 504
		call->ice_session = ice_session_new();
		ice_session_set_role(call->ice_session, IR_Controlling);
505
	}
506
	if (linphone_core_get_firewall_policy(call->core) == LinphonePolicyUseStun) {
507
		call->ping_time=linphone_core_run_stun_tests(call->core,call);
508
	}
Yann Diorcet's avatar
Yann Diorcet committed
509 510
#ifdef BUILD_UPNP
	if (linphone_core_get_firewall_policy(call->core) == LinphonePolicyUseUpnp) {
511 512 513
		if(!lc->rtp_conf.disable_upnp) {
			call->upnp_session = linphone_upnp_session_new(call);
		}
Yann Diorcet's avatar
Yann Diorcet committed
514 515
	}
#endif //BUILD_UPNP
516 517
	call->camera_active=params->has_video;
	
518
	discover_mtu(lc,linphone_address_get_domain (to));
519
	if (params->referer){
520
		call->referer=linphone_call_ref(params->referer);
521
	}
Simon Morlat's avatar
Simon Morlat committed
522 523
	call->dest_proxy=cfg;
	linphone_call_create_op(call);
524 525 526 527 528
	return call;
}

LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *from, LinphoneAddress *to, SalOp *op){
	LinphoneCall *call=ms_new0(LinphoneCall,1);
529
	char *from_str;
530
	const SalMediaDescription *md;
531 532 533 534 535 536

	call->dir=LinphoneCallIncoming;
	sal_op_set_user_pointer(op,call);
	call->op=op;
	call->core=lc;

jehan's avatar
jehan committed
537

538
	if (lc->sip_conf.ping_with_options){
539 540 541 542 543 544 545 546 547 548 549 550
#ifdef BUILD_UPNP
		if (lc->upnp != NULL && linphone_core_get_firewall_policy(lc)==LinphonePolicyUseUpnp &&
			linphone_upnp_context_get_state(lc->upnp) == LinphoneUpnpStateOk) {
#else //BUILD_UPNP
		{
#endif //BUILD_UPNP
			/*the following sends an option request back to the caller so that
			 we get a chance to discover our nat'd address before answering.*/
			call->ping_op=sal_op_new(lc->sal);
			from_str=linphone_address_as_string_uri_only(from);
			sal_op_set_route(call->ping_op,sal_op_get_network_origin(op));
			sal_op_set_user_pointer(call->ping_op,call);
551
			sal_ping(call->ping_op,linphone_core_find_best_identity(lc,from),from_str);
552 553
			ms_free(from_str);
		}
554
	}
555

556
	linphone_address_clean(from);
557
	linphone_core_get_local_ip(lc,NULL,call->localip);
558
	linphone_call_init_common(call, from, to);
jehan's avatar
jehan committed
559
	call->log->call_id=ms_strdup(sal_op_get_call_id(op)); /*must be known at that time*/
560
	linphone_core_init_default_params(lc, &call->params);
jehan's avatar
jehan committed
561 562 563
	/*set privacy*/
	call->current_params.privacy=(LinphonePrivacyMask)sal_op_get_privacy(call->op);

564
	md=sal_call_get_remote_media_description(op);
565
	call->params.has_video &= !!lc->video_policy.automatically_accept;
566 567 568 569 570
	if (md) {
		// It is licit to receive an INVITE without SDP
		// In this case WE chose the media parameters according to policy.
		call->params.has_video &= linphone_core_media_description_contains_video_stream(md);
	}
571 572
	switch (linphone_core_get_firewall_policy(call->core)) {
		case LinphonePolicyUseIce:
573 574 575
			call->ice_session = ice_session_new();
			ice_session_set_role(call->ice_session, IR_Controlled);
			linphone_core_update_ice_from_remote_media_description(call, sal_call_get_remote_media_description(op));
576 577 578 579 580 581
			if (call->ice_session != NULL) {
				linphone_call_init_media_streams(call);
				linphone_call_start_media_streams_for_ice_gathering(call);
				if (linphone_core_gather_ice_candidates(call->core,call)<0) {
					/* Ice candidates gathering failed, proceed with the call anyway. */
					linphone_call_delete_ice_session(call);
582
					linphone_call_stop_media_streams_for_ice_gathering(call);
583
				}
584
			}
585
			break;
586
		case LinphonePolicyUseStun:
587
			call->ping_time=linphone_core_run_stun_tests(call->core,call);
588
			/* No break to also destroy ice session in this case. */
Yann Diorcet's avatar
Yann Diorcet committed
589 590 591
			break;
		case LinphonePolicyUseUpnp:
#ifdef BUILD_UPNP
592 593 594 595 596 597 598 599
			if(!lc->rtp_conf.disable_upnp) {
				call->upnp_session = linphone_upnp_session_new(call);
				if (call->upnp_session != NULL) {
					linphone_call_init_media_streams(call);
					if (linphone_core_update_upnp_from_remote_media_description(call, sal_call_get_remote_media_description(op))<0) {
						/* uPnP port mappings failed, proceed with the call anyway. */
						linphone_call_delete_upnp_session(call);
					}
600
				}
Yann Diorcet's avatar
Yann Diorcet committed
601 602 603
			}
#endif //BUILD_UPNP
			break;
604 605 606
		default:
			break;
	}
607 608
	call->camera_active=call->params.has_video;
	
609 610 611 612
	discover_mtu(lc,linphone_address_get_domain(from));
	return call;
}

Simon Morlat's avatar
Simon Morlat committed
613 614 615 616 617 618
/* this function is called internally to get rid of a call.
 It performs the following tasks:
 - remove the call from the internal list of calls
 - update the call logs accordingly
*/

619
static void linphone_call_set_terminated(LinphoneCall *call){
Simon Morlat's avatar
Simon Morlat committed
620
	LinphoneCore *lc=call->core;
621

Simon Morlat's avatar
Simon Morlat committed
622
	linphone_core_update_allocated_audio_bandwidth(lc);
623

624
	call->owns_call_log=FALSE;
625
	linphone_call_log_completed(call);
626 627


628 629 630
	if (call == lc->current_call){
		ms_message("Resetting the current call");
		lc->current_call=NULL;
631 632 633 634
	}

	if (linphone_core_del_call(lc,call) != 0){
		ms_error("Could not remove the call from the list !!!");
Simon Morlat's avatar
Simon Morlat committed
635
	}
636

637
	if (ms_list_size(lc->calls)==0)
638
		linphone_core_notify_all_friends(lc,lc->presence_model);
639

640
	linphone_core_conference_check_uninit(lc);
641 642 643 644
	if (call->ringing_beep){
		linphone_core_stop_dtmf(lc);
		call->ringing_beep=FALSE;
	}
645 646
}

647 648 649 650 651
void linphone_call_fix_call_parameters(LinphoneCall *call){
	call->params.has_video=call->current_params.has_video;
	call->params.media_encryption=call->current_params.media_encryption;
}

652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678
const char *linphone_call_state_to_string(LinphoneCallState cs){
	switch (cs){
		case LinphoneCallIdle:
			return "LinphoneCallIdle";
		case LinphoneCallIncomingReceived:
			return "LinphoneCallIncomingReceived";
		case LinphoneCallOutgoingInit:
			return "LinphoneCallOutgoingInit";
		case LinphoneCallOutgoingProgress:
			return "LinphoneCallOutgoingProgress";
		case LinphoneCallOutgoingRinging:
			return "LinphoneCallOutgoingRinging";
		case LinphoneCallOutgoingEarlyMedia:
			return "LinphoneCallOutgoingEarlyMedia";
		case LinphoneCallConnected:
			return "LinphoneCallConnected";
		case LinphoneCallStreamsRunning:
			return "LinphoneCallStreamsRunning";
		case LinphoneCallPausing:
			return "LinphoneCallPausing";
		case LinphoneCallPaused:
			return "LinphoneCallPaused";
		case LinphoneCallResuming:
			return "LinphoneCallResuming";
		case LinphoneCallRefered:
			return "LinphoneCallRefered";
		case LinphoneCallError:
Simon Morlat's avatar
Simon Morlat committed
679
			return "LinphoneCallError";
680 681 682 683
		case LinphoneCallEnd:
			return "LinphoneCallEnd";
		case LinphoneCallPausedByRemote:
			return "LinphoneCallPausedByRemote";
684 685
		case LinphoneCallUpdatedByRemote:
			return "LinphoneCallUpdatedByRemote";
686 687
		case LinphoneCallIncomingEarlyMedia:
			return "LinphoneCallIncomingEarlyMedia";
688 689
		case LinphoneCallUpdating:
			return "LinphoneCallUpdating";
690 691
		case LinphoneCallReleased:
			return "LinphoneCallReleased";
692 693 694 695
	}
	return "undefined state";
}

696 697
void linphone_call_set_state(LinphoneCall *call, LinphoneCallState cstate, const char *message){
	LinphoneCore *lc=call->core;
698

699
	if (call->state!=cstate){
700
		call->prevstate=call->state;
701 702 703
		if (call->state==LinphoneCallEnd || call->state==LinphoneCallError){
			if (cstate!=LinphoneCallReleased){
				ms_warning("Spurious call state change from %s to %s, ignored.",linphone_call_state_to_string(call->state),
704
				   linphone_call_state_to_string(cstate));
705 706 707
				return;
			}
		}
708 709
		ms_message("Call %p: moving from state %s to %s",call,linphone_call_state_to_string(call->state),
		           linphone_call_state_to_string(cstate));
710 711 712 713 714
		if (cstate!=LinphoneCallRefered){
			/*LinphoneCallRefered is rather an event, not a state.
			 Indeed it does not change the state of the call (still paused or running)*/
			call->state=cstate;
		}
715
		if (cstate==LinphoneCallEnd || cstate==LinphoneCallError){
Yann Diorcet's avatar
Yann Diorcet committed
716
			switch(call->reason){
717 718
				case LinphoneReasonDeclined:
					call->log->status=LinphoneCallDeclined;
jehan's avatar
jehan committed
719
					break;
720 721 722 723 724
				case LinphoneReasonNotAnswered:
					call->log->status=LinphoneCallMissed;
				break;
				default:
				break;
725
			}
726
			linphone_call_set_terminated(call);
727
		}
728 729
		if (cstate == LinphoneCallConnected) {
			call->log->status=LinphoneCallSuccess;
730
			call->media_start_time=time(NULL);
731
		}
732

733 734
		if (lc->vtable.call_state_changed)
			lc->vtable.call_state_changed(lc,call,cstate,message);
735 736 737 738 739 740 741
		if (cstate==LinphoneCallReleased){
			if (call->op!=NULL) {
				/* so that we cannot have anymore upcalls for SAL
				 concerning this call*/
				sal_op_release(call->op);
				call->op=NULL;
			}
742
			/*it is necessary to reset pointers to other call to prevent circular references that would result in memory never freed.*/
743 744 745
			if (call->referer){
				linphone_call_unref(call->referer);
				call->referer=NULL;
746 747 748 749 750
			}
			if (call->transfer_target){
				linphone_call_unref(call->transfer_target);
				call->transfer_target=NULL;
			}
751
			linphone_call_unref(call);
752
		}
753 754 755
	}
}

756 757
static void linphone_call_destroy(LinphoneCall *obj)
{
Simon Morlat's avatar
Simon Morlat committed
758
	ms_message("Call [%p] freed.",obj);
Yann Diorcet's avatar
Yann Diorcet committed
759 760 761
#ifdef BUILD_UPNP
	linphone_call_delete_upnp_session(obj);
#endif //BUILD_UPNP
762
	linphone_call_delete_ice_session(obj);
763 764 765 766 767 768 769 770 771 772 773 774 775 776 777
	if (obj->op!=NULL) {
		sal_op_release(obj->op);
		obj->op=NULL;
	}
	if (obj->resultdesc!=NULL) {
		sal_media_description_unref(obj->resultdesc);
		obj->resultdesc=NULL;
	}
	if (obj->localdesc!=NULL) {
		sal_media_description_unref(obj->localdesc);
		obj->localdesc=NULL;
	}
	if (obj->ping_op) {
		sal_op_release(obj->ping_op);
	}
778 779 780
	if (obj->refer_to){
		ms_free(obj->refer_to);
	}
781 782 783
	if (obj->referer){
		linphone_call_unref(obj->referer);
		obj->referer=NULL;
784 785 786 787
	}
	if (obj->transfer_target){
		linphone_call_unref(obj->transfer_target);
	}
788 789
	if (obj->owns_call_log)
		linphone_call_log_destroy(obj->log);
790 791 792
	if (obj->auth_token) {
		ms_free(obj->auth_token);
	}
793
	linphone_call_params_uninit(&obj->params);
794
	linphone_call_params_uninit(&obj->current_params);
795 796 797
	ms_free(obj);
}

Simon Morlat's avatar
Simon Morlat committed
798
/**
Simon Morlat's avatar
Simon Morlat committed
799
 * @addtogroup call_control
Simon Morlat's avatar
Simon Morlat committed
800 801 802 803 804 805 806 807 808 809
 * @{
**/

/**
 * Increments the call 's reference count.
 * An application that wishes to retain a pointer to call object
 * must use this function to unsure the pointer remains
 * valid. Once the application no more needs this pointer,
 * it must call linphone_call_unref().
**/
810
LinphoneCall * linphone_call_ref(LinphoneCall *obj){
811
	obj->refcnt++;
812
	return obj;
813 814
}

Simon Morlat's avatar
Simon Morlat committed
815 816 817 818
/**
 * Decrements the call object reference count.
 * See linphone_call_ref().
**/
819 820
void linphone_call_unref(LinphoneCall *obj){
	obj->refcnt--;
Simon Morlat's avatar
Simon Morlat committed
821
	if (obj->refcnt==0){
822
		linphone_call_destroy(obj);
Simon Morlat's avatar
Simon Morlat committed
823
	}
824 825
}

826 827 828
/**
 * Returns current parameters associated to the call.
**/
Simon Morlat's avatar
Simon Morlat committed
829
const LinphoneCallParams * linphone_call_get_current_params(LinphoneCall *call){
jehan's avatar
jehan committed
830
#ifdef VIDEO_ENABLED
831
	VideoStream *vstream;
jehan's avatar
jehan committed
832
#endif
833 834 835 836 837 838 839 840 841 842
	MS_VIDEO_SIZE_ASSIGN(call->current_params.sent_vsize, UNKNOWN);
	MS_VIDEO_SIZE_ASSIGN(call->current_params.recv_vsize, UNKNOWN);
#ifdef VIDEO_ENABLED
	vstream = call->videostream;
	if (vstream != NULL) {
		call->current_params.sent_vsize = video_stream_get_sent_video_size(vstream);
		call->current_params.recv_vsize = video_stream_get_received_video_size(vstream);
	}
#endif

843
	return &call->current_params;
844 845
}

846
static bool_t is_video_active(const SalStreamDescription *sd){
847
	return sd->rtp_port!=0 && sd->dir!=SalStreamInactive;
848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874
}

/**
 * Returns call parameters proposed by remote.
 * 
 * This is useful when receiving an incoming call, to know whether the remote party
 * supports video, encryption or whatever.
**/
const LinphoneCallParams * linphone_call_get_remote_params(LinphoneCall *call){
	LinphoneCallParams *cp=&call->remote_params;
	memset(cp,0,sizeof(*cp));
	if (call->op){
		SalMediaDescription *md=sal_call_get_remote_media_description(call->op);
		if (md){
			SalStreamDescription *asd,*vsd,*secure_asd,*secure_vsd;

			asd=sal_media_description_find_stream(md,SalProtoRtpAvp,SalAudio);
			vsd=sal_media_description_find_stream(md,SalProtoRtpAvp,SalVideo);
			secure_asd=sal_media_description_find_stream(md,SalProtoRtpSavp,SalAudio);
			secure_vsd=sal_media_description_find_stream(md,SalProtoRtpSavp,SalVideo);
			if (secure_vsd){
				cp->has_video=is_video_active(secure_vsd);
				if (secure_asd || asd==NULL)
					cp->media_encryption=LinphoneMediaEncryptionSRTP;
			}else if (vsd){
				cp->has_video=is_video_active(vsd);
			}
875 876 877 878 879
			if (!cp->has_video){
				if (md->bandwidth>0 && md->bandwidth<=linphone_core_get_edge_bw(call->core)){
					cp->low_bandwidth=TRUE;
				}
			}
880
		}
881 882
		cp->custom_headers=(SalCustomHeader*)sal_op_get_recv_custom_header(call->op);
		return cp;
883 884 885 886
	}
	return NULL;
}

Simon Morlat's avatar
Simon Morlat committed
887 888 889 890
/**
 * Returns the remote address associated to this call
 *
**/
891 892 893 894
const LinphoneAddress * linphone_call_get_remote_address(const LinphoneCall *call){
	return call->dir==LinphoneCallIncoming ? call->log->from : call->log->to;
}

Simon Morlat's avatar
Simon Morlat committed
895 896 897 898 899
/**
 * Returns the remote address associated to this call as a string.
 *
 * The result string must be freed by user using ms_free().
**/
900 901 902 903
char *linphone_call_get_remote_address_as_string(const LinphoneCall *call){
	return linphone_address_as_string(linphone_call_get_remote_address(call));
}

Simon Morlat's avatar
Simon Morlat committed
904 905 906
/**
 * Retrieves the call's current state.
**/
907 908 909 910
LinphoneCallState linphone_call_get_state(const LinphoneCall *call){
	return call->state;
}

911 912 913 914 915 916