linphonecall.c 109 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 41
static void linphone_call_stats_uninit(LinphoneCallStats *stats);

Simon Morlat's avatar
Simon Morlat committed
42
#ifdef VIDEO_ENABLED
43 44 45
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
46
#endif
47

48
static bool_t generate_b64_crypto_key(int key_length, char* key_out, size_t key_out_size) {
49
	int b64_size;
50 51
	uint8_t* tmp = (uint8_t*) ms_malloc0(key_length);
	if (sal_get_random_bytes(tmp, key_length)==NULL) {
52
		ms_error("Failed to generate random key");
53
		ms_free(tmp);
54 55
		return FALSE;
	}
56

57
	b64_size = b64_encode((const char*)tmp, key_length, NULL, 0);
58 59 60 61 62 63 64 65 66 67 68
	if (b64_size == 0) {
		ms_error("Failed to get b64 result size");
		ms_free(tmp);
		return FALSE;
	}
	if (b64_size>=key_out_size){
		ms_error("Insufficient room for writing base64 SRTP key");
		ms_free(tmp);
		return FALSE;
	}
	b64_size=b64_encode((const char*)tmp, key_length, key_out, key_out_size);
69 70
	if (b64_size == 0) {
		ms_error("Failed to b64 encode key");
71
		ms_free(tmp);
72 73 74
		return FALSE;
	}
	key_out[b64_size] = '\0';
75
	ms_free(tmp);
76 77 78
	return TRUE;
}

79 80 81 82
LinphoneCore *linphone_call_get_core(const LinphoneCall *call){
	return call->core;
}

83
const char* linphone_call_get_authentication_token(LinphoneCall *call){
84
	return call->auth_token;
85 86
}

87 88 89 90 91 92 93 94
/**
 * Returns whether ZRTP authentication token is verified.
 * If not, it must be verified by users as described in ZRTP procedure.
 * Once done, the application must inform of the results with linphone_call_set_authentication_token_verified().
 * @param call the LinphoneCall
 * @return TRUE if authentication token is verifed, false otherwise.
 * @ingroup call_control
**/
95
bool_t linphone_call_get_authentication_token_verified(LinphoneCall *call){
96
	return call->auth_token_verified;
97
}
Simon Morlat's avatar
Simon Morlat committed
98

99
static bool_t linphone_call_all_streams_encrypted(const LinphoneCall *call) {
jehan's avatar
jehan committed
100 101 102 103 104
	int number_of_encrypted_stream = 0;
	int number_of_active_stream = 0;
	if (call) {
		if (call->audiostream && media_stream_get_state((MediaStream *)call->audiostream) == MSStreamStarted) {
			number_of_active_stream++;
105
			if(media_stream_secured((MediaStream *)call->audiostream))
jehan's avatar
jehan committed
106 107 108 109
				number_of_encrypted_stream++;
		}
		if (call->videostream && media_stream_get_state((MediaStream *)call->videostream) == MSStreamStarted) {
			number_of_active_stream++;
110
			if (media_stream_secured((MediaStream *)call->videostream))
jehan's avatar
jehan committed
111
				number_of_encrypted_stream++;
112
		}
113
	}
114
	return number_of_active_stream>0 && number_of_active_stream==number_of_encrypted_stream;
115 116
}

117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134
static bool_t linphone_call_all_streams_avpf_enabled(const LinphoneCall *call) {
	int nb_active_streams = 0;
	int nb_avpf_enabled_streams = 0;
	if (call) {
		if (call->audiostream && media_stream_get_state((MediaStream *)call->audiostream) == MSStreamStarted) {
			nb_active_streams++;
			if (media_stream_avpf_enabled((MediaStream *)call->audiostream))
				nb_avpf_enabled_streams++;
		}
		if (call->videostream && media_stream_get_state((MediaStream *)call->videostream) == MSStreamStarted) {
			nb_active_streams++;
			if (media_stream_avpf_enabled((MediaStream *)call->videostream))
				nb_avpf_enabled_streams++;
		}
	}
	return ((nb_active_streams > 0) && (nb_active_streams == nb_avpf_enabled_streams));
}

135 136 137
static uint16_t linphone_call_get_avpf_rr_interval(const LinphoneCall *call) {
	uint16_t rr_interval = 0;
	uint16_t stream_rr_interval;
138 139 140 141 142 143 144 145 146 147
	if (call) {
		if (call->audiostream && media_stream_get_state((MediaStream *)call->audiostream) == MSStreamStarted) {
			stream_rr_interval = media_stream_get_avpf_rr_interval((MediaStream *)call->audiostream);
			if (stream_rr_interval > rr_interval) rr_interval = stream_rr_interval;
		}
		if (call->videostream && media_stream_get_state((MediaStream *)call->videostream) == MSStreamStarted) {
			stream_rr_interval = media_stream_get_avpf_rr_interval((MediaStream *)call->videostream);
			if (stream_rr_interval > rr_interval) rr_interval = stream_rr_interval;
		}
	} else {
148
		rr_interval = 5000;
149 150 151 152
	}
	return rr_interval;
}

153
static void propagate_encryption_changed(LinphoneCall *call){
Simon Morlat's avatar
Simon Morlat committed
154
	LinphoneCore *lc=call->core;
155
	if (!linphone_call_all_streams_encrypted(call)) {
156
		ms_message("Some streams are not encrypted");
157
		call->current_params->media_encryption=LinphoneMediaEncryptionNone;
Simon Morlat's avatar
Simon Morlat committed
158 159
		if (lc->vtable.call_encryption_changed)
			lc->vtable.call_encryption_changed(call->core, call, FALSE, call->auth_token);
160
	} else {
161
		ms_message("All streams are encrypted");
162
		call->current_params->media_encryption=LinphoneMediaEncryptionZRTP;
Simon Morlat's avatar
Simon Morlat committed
163 164
		if (lc->vtable.call_encryption_changed)
			lc->vtable.call_encryption_changed(call->core, call, TRUE, call->auth_token);
165 166 167 168
	}
}

static void linphone_call_audiostream_encryption_changed(void *data, bool_t encrypted) {
169
	char status[255]={0};
Sylvain Berfini's avatar
Sylvain Berfini committed
170
	LinphoneCall *call;
171

Sylvain Berfini's avatar
Sylvain Berfini committed
172
	call = (LinphoneCall *)data;
173

174 175 176 177 178
	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);
	}

179 180 181 182 183
	propagate_encryption_changed(call);


#ifdef VIDEO_ENABLED
	// Enable video encryption
184 185 186 187 188 189 190 191
	{
		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);
		}
192 193 194 195 196 197 198
	}
#endif
}


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

202 203
	call->auth_token=ms_strdup(auth_token);
	call->auth_token_verified=verified;
204 205 206 207

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

208 209 210 211 212 213 214
/**
 * Set the result of ZRTP short code verification by user.
 * If remote party also does the same, it will update the ZRTP cache so that user's verification will not be required for the two users.
 * @param call the LinphoneCall
 * @param verified whether the ZRTP SAS is verified.
 * @ingroup call_control
**/
Simon Morlat's avatar
Simon Morlat committed
215 216 217 218
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");
	}
219
	if (call->audiostream->ms.sessions.zrtp_context==NULL){
Simon Morlat's avatar
Simon Morlat committed
220 221 222
		ms_error("linphone_call_set_authentication_token_verified(): No zrtp context.");
	}
	if (!call->auth_token_verified && verified){
223
		ortp_zrtp_sas_verified(call->audiostream->ms.sessions.zrtp_context);
Simon Morlat's avatar
Simon Morlat committed
224
	}else if (call->auth_token_verified && !verified){
225
		ortp_zrtp_sas_reset_verified(call->audiostream->ms.sessions.zrtp_context);
Simon Morlat's avatar
Simon Morlat committed
226 227 228 229
	}
	call->auth_token_verified=verified;
	propagate_encryption_changed(call);
}
230

231
static MSList *make_codec_list(LinphoneCore *lc, const MSList *codecs, int bandwidth_limit,int* max_sample_rate, int nb_codecs_limit){
232 233
	MSList *l=NULL;
	const MSList *it;
234
	int nb = 0;
235
	if (max_sample_rate) *max_sample_rate=0;
236 237
	for(it=codecs;it!=NULL;it=it->next){
		PayloadType *pt=(PayloadType*)it->data;
238
		if (pt->flags & PAYLOAD_TYPE_ENABLED){
239 240 241 242 243 244 245 246
			int sample_rate = payload_type_get_rate(pt);

			if( strcasecmp("G722",pt->mime_type) == 0 ){
				/* G722 spec says 8000 but the codec actually requires 16000 */
				ms_debug("Correcting sample rate for G722");
				sample_rate = 16000;
			}

247
			if (bandwidth_limit>0 && !linphone_core_is_payload_type_usable_for_bandwidth(lc,pt,bandwidth_limit)){
Simon Morlat's avatar
Simon Morlat committed
248 249
				ms_message("Codec %s/%i eliminated because of audio bandwidth constraint of %i kbit/s",
					   pt->mime_type,pt->clock_rate,bandwidth_limit);
250 251 252 253
				continue;
			}
			if (linphone_core_check_payload_type_usability(lc,pt)){
				l=ms_list_append(l,payload_type_clone(pt));
254
				nb++;
255
				if (max_sample_rate && sample_rate>*max_sample_rate) *max_sample_rate=sample_rate;
256
			}
257
		}
258
		if ((nb_codecs_limit > 0) && (nb >= nb_codecs_limit)) break;
259 260 261 262
	}
	return l;
}

263
static void update_media_description_from_stun(SalMediaDescription *md, const StunCandidate *ac, const StunCandidate *vc){
264
	int i;
265 266
	for (i = 0; i < md->nb_streams; i++) {
		if (!sal_stream_description_active(&md->streams[i])) continue;
267 268 269
		if ((md->streams[i].type == SalAudio) && (ac->port != 0)) {
			strcpy(md->streams[0].rtp_addr,ac->addr);
			md->streams[0].rtp_port=ac->port;
270
			if ((ac->addr[0]!='\0' && vc->addr[0]!='\0' && strcmp(ac->addr,vc->addr)==0) || sal_media_description_get_nb_active_streams(md)==1){
271 272 273 274 275 276
				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;
277 278 279 280
		}
	}
}

281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306
static int setup_encryption_key(SalSrtpCryptoAlgo *crypto, MSCryptoSuite suite, unsigned int tag){
	int keylen=0;
	crypto->tag=tag;
	crypto->algo=suite;
	switch(suite){
		case MS_AES_128_SHA1_80:
		case MS_AES_128_SHA1_32:
		case MS_AES_128_NO_AUTH:
		case MS_NO_CIPHER_SHA1_80: /*not sure for this one*/
			keylen=30;
		break;
		case MS_AES_256_SHA1_80:
		case MS_AES_256_SHA1_32:
			keylen=46;
		break;
		case MS_CRYPTO_SUITE_INVALID:
		break;
	}
	if (keylen==0 || !generate_b64_crypto_key(30, crypto->master_key, SAL_SRTP_KEY_SIZE)){
		ms_error("Could not generate SRTP key.");
		crypto->algo = 0;
		return -1;
	}
	return 0;
}

307 308
static void setup_encryption_keys(LinphoneCall *call, SalMediaDescription *md){
	LinphoneCore *lc=call->core;
309
	int i,j;
310
	SalMediaDescription *old_md=call->localdesc;
311
	bool_t keep_srtp_keys=lp_config_get_int(lc->config,"sip","keep_srtp_keys",1);
312

313 314 315
	for(i=0; i<md->nb_streams; i++) {
		if (!sal_stream_description_active(&md->streams[i])) continue;
		if (sal_stream_description_has_srtp(&md->streams[i]) == TRUE) {
316
			if (keep_srtp_keys && old_md && (sal_stream_description_active(&old_md->streams[i]) == TRUE) && (sal_stream_description_has_srtp(&old_md->streams[i]) == TRUE)) {
317 318 319 320 321 322
				int j;
				ms_message("Keeping same crypto keys.");
				for(j=0;j<SAL_CRYPTO_ALGO_MAX;++j){
					memcpy(&md->streams[i].crypto[j],&old_md->streams[i].crypto[j],sizeof(SalSrtpCryptoAlgo));
				}
			}else{
323 324 325 326
				const MSCryptoSuite *suites=linphone_core_get_srtp_crypto_suites(lc);
				for(j=0;suites!=NULL && suites[j]!=MS_CRYPTO_SUITE_INVALID && j<SAL_CRYPTO_ALGO_MAX;++j){
					setup_encryption_key(&md->streams[i].crypto[j],suites[j],j+1);
				}
327 328 329 330 331
			}
		}
	}
}

332 333 334 335 336 337
static void setup_rtcp_fb(LinphoneCall *call, SalMediaDescription *md) {
	MSList *pt_it;
	PayloadType *pt;
	PayloadTypeAvpfParams avpf_params;
	int i;

338 339
	for (i = 0; i < md->nb_streams; i++) {
		if (!sal_stream_description_active(&md->streams[i])) continue;
340 341
		for (pt_it = md->streams[i].payloads; pt_it != NULL; pt_it = pt_it->next) {
			pt = (PayloadType *)pt_it->data;
342
			if (call->params->avpf_enabled == TRUE) {
343 344
				payload_type_set_flag(pt, PAYLOAD_TYPE_RTCP_FEEDBACK_ENABLED);
				avpf_params = payload_type_get_avpf_params(pt);
345
				avpf_params.trr_interval = call->params->avpf_rr_interval;
346 347 348 349 350 351 352 353 354
			} else {
				payload_type_unset_flag(pt, PAYLOAD_TYPE_RTCP_FEEDBACK_ENABLED);
				memset(&avpf_params, 0, sizeof(avpf_params));
			}
			payload_type_set_avpf_params(pt, avpf_params);
		}
	}
}

355 356
static void setup_rtcp_xr(LinphoneCall *call, SalMediaDescription *md) {
	LinphoneCore *lc = call->core;
357
	int i;
358 359 360 361

	md->rtcp_xr.enabled = lp_config_get_int(lc->config, "rtp", "rtcp_xr_enabled", 0);
	if (md->rtcp_xr.enabled == TRUE) {
		const char *rcvr_rtt_mode = lp_config_get_string(lc->config, "rtp", "rtcp_xr_rcvr_rtt_mode", "none");
362 363 364 365
		if (strcasecmp(rcvr_rtt_mode, "all") == 0) md->rtcp_xr.rcvr_rtt_mode = OrtpRtcpXrRcvrRttAll;
		else if (strcasecmp(rcvr_rtt_mode, "sender") == 0) md->rtcp_xr.rcvr_rtt_mode = OrtpRtcpXrRcvrRttSender;
		else md->rtcp_xr.rcvr_rtt_mode = OrtpRtcpXrRcvrRttNone;
		if (md->rtcp_xr.rcvr_rtt_mode != OrtpRtcpXrRcvrRttNone) {
366 367 368 369
			md->rtcp_xr.rcvr_rtt_max_size = lp_config_get_int(lc->config, "rtp", "rtcp_xr_rcvr_rtt_max_size", 0);
		}
		md->rtcp_xr.stat_summary_enabled = lp_config_get_int(lc->config, "rtp", "rtcp_xr_stat_summary_enabled", 0);
		if (md->rtcp_xr.stat_summary_enabled == TRUE) {
370
			md->rtcp_xr.stat_summary_flags = OrtpRtcpXrStatSummaryLoss | OrtpRtcpXrStatSummaryDup | OrtpRtcpXrStatSummaryJitt | OrtpRtcpXrStatSummaryTTL;
371 372 373
		}
		md->rtcp_xr.voip_metrics_enabled = lp_config_get_int(lc->config, "rtp", "rtcp_xr_voip_metrics_enabled", 0);
	}
374 375
	for (i = 0; i < md->nb_streams; i++) {
		if (!sal_stream_description_active(&md->streams[i])) continue;
376 377
		memcpy(&md->streams[i].rtcp_xr, &md->rtcp_xr, sizeof(md->streams[i].rtcp_xr));
	}
378 379
}

380 381 382 383 384
void linphone_call_increment_local_media_description(LinphoneCall *call){
	SalMediaDescription *md=call->localdesc;
	md->session_ver++;
}

Simon Morlat's avatar
Simon Morlat committed
385
void linphone_call_make_local_media_description(LinphoneCore *lc, LinphoneCall *call){
386 387
	MSList *l;
	PayloadType *pt;
Simon Morlat's avatar
Simon Morlat committed
388
	SalMediaDescription *old_md=call->localdesc;
389
	int i;
390
	int nb_active_streams = 0;
391
	const char *me;
392
	SalMediaDescription *md=sal_media_description_new();
393
	LinphoneAddress *addr;
394
	char* local_ip=call->localip;
395
	const char *subject=linphone_call_params_get_session_name(call->params);
396

397
	linphone_core_adapt_to_network(lc,call->ping_time,call->params);
398

399 400
	if (call->dest_proxy)
		me=linphone_proxy_config_get_identity(call->dest_proxy);
401
	else
402 403
		me=linphone_core_get_identity(lc);
	addr=linphone_address_new(me);
404

Simon Morlat's avatar
Simon Morlat committed
405 406
	md->session_id=(old_md ? old_md->session_id : (rand() & 0xfff));
	md->session_ver=(old_md ? (old_md->session_ver+1) : (rand() & 0xfff));
407
	md->nb_streams=(call->biggestdesc ? call->biggestdesc->nb_streams : 1);
408

jehan's avatar
jehan committed
409
	strncpy(md->addr,local_ip,sizeof(md->addr));
410
	strncpy(md->username,linphone_address_get_username(addr),sizeof(md->username));
Simon Morlat's avatar
Simon Morlat committed
411
	if (subject) strncpy(md->name,subject,sizeof(md->name));
412

413 414
	if (call->params->down_bw)
		md->bandwidth=call->params->down_bw;
415
	else md->bandwidth=linphone_core_get_download_bandwidth(lc);
416

417
	/*set audio capabilities */
jehan's avatar
jehan committed
418 419
	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));
420
	strncpy(md->streams[0].name,"Audio",sizeof(md->streams[0].name)-1);
421 422
	md->streams[0].rtp_port=call->media_ports[0].rtp_port;
	md->streams[0].rtcp_port=call->media_ports[0].rtcp_port;
423
	md->streams[0].proto=get_proto_from_call_params(call->params);
424
	md->streams[0].type=SalAudio;
425 426
	if (call->params->down_ptime)
		md->streams[0].ptime=call->params->down_ptime;
427
	else
428
		md->streams[0].ptime=linphone_core_get_download_ptime(lc);
429
	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
430
	pt=payload_type_clone(rtp_profile_get_payload_from_mime(lc->default_profile,"telephone-event"));
431 432
	l=ms_list_append(l,pt);
	md->streams[0].payloads=l;
433
	nb_active_streams++;
434

435
	if (call->params->has_video){
436 437 438
		strncpy(md->streams[1].rtp_addr,local_ip,sizeof(md->streams[1].rtp_addr));
		strncpy(md->streams[1].rtcp_addr,local_ip,sizeof(md->streams[1].rtcp_addr));
		strncpy(md->streams[1].name,"Video",sizeof(md->streams[1].name)-1);
439 440
		md->streams[1].rtp_port=call->media_ports[1].rtp_port;
		md->streams[1].rtcp_port=call->media_ports[1].rtcp_port;
441
		md->streams[1].proto=md->streams[0].proto;
442
		md->streams[1].type=SalVideo;
443
		l=make_codec_list(lc,lc->codecs_conf.video_codecs,0,NULL,-1);
444
		md->streams[1].payloads=l;
445
		nb_active_streams++;
446
	}
447 448 449

	if (md->nb_streams < nb_active_streams)
		md->nb_streams = nb_active_streams;
450 451

	/* Deactivate inactive streams. */
452
	for (i = nb_active_streams; i < md->nb_streams; i++) {
453 454
		md->streams[i].rtp_port = 0;
		md->streams[i].rtcp_port = 0;
455 456
		md->streams[i].proto = call->biggestdesc->streams[i].proto;
		md->streams[i].type = call->biggestdesc->streams[i].type;
457 458 459 460 461
		md->streams[i].dir = SalStreamInactive;
		l = make_codec_list(lc, lc->codecs_conf.video_codecs, 0, NULL, 1);
		md->streams[i].payloads = l;
	}

462
	setup_encryption_keys(call,md);
463
	setup_rtcp_fb(call, md);
464
	setup_rtcp_xr(call, md);
465

466
	update_media_description_from_stun(md,&call->ac,&call->vc);
467 468
	if (call->ice_session != NULL) {
		linphone_core_update_local_media_description_from_ice(md, call->ice_session);
469
		linphone_core_update_ice_state_in_call_stats(call);
470
	}
Yann Diorcet's avatar
Yann Diorcet committed
471 472 473
#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
474
		linphone_core_update_upnp_state_in_call_stats(call);
Yann Diorcet's avatar
Yann Diorcet committed
475
	}
476
#endif  //BUILD_UPNP
477
	linphone_address_destroy(addr);
Simon Morlat's avatar
Simon Morlat committed
478
	call->localdesc=md;
479 480 481 482
	if (old_md){
		call->localdesc_changed=sal_media_description_equals(md,old_md);
		sal_media_description_unref(old_md);
	}
483 484
}

485
static int find_port_offset(LinphoneCore *lc, int stream_index, int base_port){
486 487
	int offset;
	MSList *elem;
488 489
	int tried_port;
	int existing_port;
490
	bool_t already_used=FALSE;
491

492
	for(offset=0;offset<100;offset+=2){
493
		tried_port=base_port+offset;
494 495 496
		already_used=FALSE;
		for(elem=lc->calls;elem!=NULL;elem=elem->next){
			LinphoneCall *call=(LinphoneCall*)elem->data;
497
			existing_port=call->media_ports[stream_index].rtp_port;
498
			if (existing_port==tried_port) {
499 500 501 502 503 504 505 506 507 508 509 510 511
				already_used=TRUE;
				break;
			}
		}
		if (!already_used) break;
	}
	if (offset==100){
		ms_error("Could not find any free port !");
		return -1;
	}
	return offset;
}

512
static int select_random_port(LinphoneCore *lc, int stream_index, int min_port, int max_port) {
513 514 515 516 517 518 519 520 521 522 523
	MSList *elem;
	int nb_tries;
	int tried_port = 0;
	int existing_port = 0;
	bool_t already_used = FALSE;

	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;
524
			existing_port=call->media_ports[stream_index].rtp_port;
525 526 527 528 529 530 531 532 533 534 535 536 537 538
			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;
}

539 540 541 542 543 544
static void port_config_set_random(LinphoneCall *call, int stream_index){
	call->media_ports[stream_index].rtp_port=-1;
	call->media_ports[stream_index].rtcp_port=-1;
}

static void port_config_set(LinphoneCall *call, int stream_index, int min_port, int max_port){
545
	int port_offset;
546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563
	if (min_port>0 && max_port>0){
		if (min_port == max_port) {
			/* Used fixed RTP audio port. */
			port_offset=find_port_offset(call->core, stream_index, min_port);
			if (port_offset==-1) {
				port_config_set_random(call, stream_index);
				return;
			}
			call->media_ports[stream_index].rtp_port=min_port+port_offset;
		} else {
			/* Select random RTP audio port in the specified range. */
			call->media_ports[stream_index].rtp_port = select_random_port(call->core, stream_index, min_port, max_port);
		}
		call->media_ports[stream_index].rtcp_port=call->media_ports[stream_index].rtp_port+1;
	}else port_config_set_random(call,stream_index);
}

static void linphone_call_init_common(LinphoneCall *call, LinphoneAddress *from, LinphoneAddress *to){
564
	int min_port, max_port;
565
	ms_message("New LinphoneCall [%p] initialized (LinphoneCore version: %s)",call,linphone_core_get_version());
566
	call->state=LinphoneCallIdle;
567
	call->transfer_state = LinphoneCallIdle;
568
	call->media_start_time=0;
569
	call->log=linphone_call_log_new(call->dir, from, to);
570
	call->camera_enabled=TRUE;
571 572
	call->current_params = linphone_call_params_new();
	call->current_params->media_encryption=LinphoneMediaEncryptionNone;
573

574
	linphone_core_get_audio_port_range(call->core, &min_port, &max_port);
575
	port_config_set(call,0,min_port,max_port);
576

577
	linphone_core_get_video_port_range(call->core, &min_port, &max_port);
578
	port_config_set(call,1,min_port,max_port);
579

Yann Diorcet's avatar
Yann Diorcet committed
580 581 582
	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);
}
583

Yann Diorcet's avatar
Yann Diorcet committed
584
void linphone_call_init_stats(LinphoneCallStats *stats, int type) {
Yann Diorcet's avatar
Yann Diorcet committed
585
	stats->type = type;
Yann Diorcet's avatar
Yann Diorcet committed
586 587
	stats->received_rtcp = NULL;
	stats->sent_rtcp = NULL;
588
	stats->ice_state = LinphoneIceStateNotActivated;
Yann Diorcet's avatar
Yann Diorcet committed
589 590 591 592 593
#ifdef BUILD_UPNP
	stats->upnp_state = LinphoneUpnpStateIdle;
#else
	stats->upnp_state = LinphoneUpnpStateNotAvailable;
#endif //BUILD_UPNP
594 595
}

596

597 598 599 600 601 602 603 604 605 606 607 608 609
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
610 611 612 613
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);
614 615 616 617 618
	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);
	if (call->params->privacy != LinphonePrivacyDefault)
		sal_op_set_privacy(call->op,(SalPrivacyMask)call->params->privacy);
jehan's avatar
jehan committed
619
	/*else privacy might be set by proxy */
Simon Morlat's avatar
Simon Morlat committed
620 621
}

622 623 624 625
/*
 * Choose IP version we are going to use for RTP socket.
 * The algorithm is as follows:
 * - if ipv6 is disabled at the core level, it is always AF_INET
626
 * - Otherwise, if the destination address for the call is an IPv6 address, use IPv6.
627 628 629 630 631 632 633 634 635 636 637 638 639 640
 * - Otherwise, if the call is done through a known proxy config, then use the information obtained during REGISTER
 * to know if IPv6 is supported by the server.
**/
static void linphone_call_outgoing_select_ip_version(LinphoneCall *call, LinphoneAddress *to, LinphoneProxyConfig *cfg){
	if (linphone_core_ipv6_enabled(call->core)){
		call->af=AF_INET;
		if (sal_address_is_ipv6((SalAddress*)to)){
			call->af=AF_INET6;
		}else if (cfg && cfg->op){
			call->af=sal_op_is_ipv6(cfg->op) ? AF_INET6 : AF_INET;
		}
	}else call->af=AF_INET;
}

641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674
/**
 * Fill the local ip that routes to the internet according to the destination, or guess it by other special means (upnp).
 */
static void linphone_call_get_local_ip(LinphoneCall *call, const LinphoneAddress *remote_addr){
	const char *ip;
	int af = call->af;
	const char *dest = NULL;
	if (call->dest_proxy == NULL) {
		struct addrinfo hints;
		struct addrinfo *res = NULL;
		int err;
		const char *domain = linphone_address_get_domain(remote_addr);
		memset(&hints, 0, sizeof(hints));
		hints.ai_family = AF_UNSPEC;
		hints.ai_socktype = SOCK_DGRAM;
		hints.ai_flags = AI_NUMERICHOST;
		err = getaddrinfo(domain, NULL, &hints, &res);
		if (err == 0) {
			dest = domain;
		}
	}
	if (linphone_core_get_firewall_policy(call->core)==LinphonePolicyUseNatAddress
		&& (ip=linphone_core_get_nat_address_resolved(call->core))!=NULL){
		strncpy(call->localip,ip,LINPHONE_IPADDR_SIZE);
		return;
	}
#ifdef BUILD_UPNP
	else if (call->core->upnp != NULL && linphone_core_get_firewall_policy(call->core)==LinphonePolicyUseUpnp &&
			linphone_upnp_context_get_state(call->core->upnp) == LinphoneUpnpStateOk) {
		ip = linphone_upnp_context_get_external_ipaddress(call->core->upnp);
		strncpy(call->localip,ip,LINPHONE_IPADDR_SIZE);
		return;
	}
#endif //BUILD_UPNP
Ghislain MARY's avatar
Ghislain MARY committed
675
	linphone_core_get_local_ip(call->core, af, dest, call->localip);
676 677
}

678 679 680 681 682 683 684 685 686 687 688
static void linphone_call_destroy(LinphoneCall *obj);

BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(LinphoneCall);

BELLE_SIP_INSTANCIATE_VPTR(LinphoneCall, belle_sip_object_t,
	(belle_sip_object_destroy_t)linphone_call_destroy,
	NULL, // clone
	NULL, // marshal
	FALSE
);

Simon Morlat's avatar
Simon Morlat committed
689
LinphoneCall * linphone_call_new_outgoing(struct _LinphoneCore *lc, LinphoneAddress *from, LinphoneAddress *to, const LinphoneCallParams *params, LinphoneProxyConfig *cfg){
690
	LinphoneCall *call = belle_sip_object_new(LinphoneCall);
691

692 693
	call->dir=LinphoneCallOutgoing;
	call->core=lc;
694
	linphone_call_outgoing_select_ip_version(call,to,cfg);
695
	linphone_call_get_local_ip(call, to);
696
	linphone_call_init_common(call,from,to);
697
	call->params = linphone_call_params_copy(params);
698

699
	if (linphone_core_get_firewall_policy(call->core) == LinphonePolicyUseIce) {
700 701
		call->ice_session = ice_session_new();
		ice_session_set_role(call->ice_session, IR_Controlling);
702
	}
703
	if (linphone_core_get_firewall_policy(call->core) == LinphonePolicyUseStun) {
704
		call->ping_time=linphone_core_run_stun_tests(call->core,call);
705
	}
Yann Diorcet's avatar
Yann Diorcet committed
706 707
#ifdef BUILD_UPNP
	if (linphone_core_get_firewall_policy(call->core) == LinphonePolicyUseUpnp) {
708 709 710
		if(!lc->rtp_conf.disable_upnp) {
			call->upnp_session = linphone_upnp_session_new(call);
		}
Yann Diorcet's avatar
Yann Diorcet committed
711 712
	}
#endif //BUILD_UPNP
713

714
	discover_mtu(lc,linphone_address_get_domain (to));
715
	if (params->referer){
716
		call->referer=linphone_call_ref(params->referer);
717
	}
Simon Morlat's avatar
Simon Morlat committed
718 719
	call->dest_proxy=cfg;
	linphone_call_create_op(call);
720 721 722
	return call;
}

723 724 725 726 727 728
static void linphone_call_incoming_select_ip_version(LinphoneCall *call){
	if (linphone_core_ipv6_enabled(call->core)){
		call->af=sal_op_is_ipv6(call->op) ? AF_INET6 : AF_INET;
	}else call->af=AF_INET;
}

729 730 731 732
/**
 * Fix call parameters on incoming call to eg. enable AVPF if the incoming call propose it and it is not enabled locally.
 */
void linphone_call_set_compatible_incoming_call_parameters(LinphoneCall *call, const SalMediaDescription *md) {
733
	call->params->has_video &= linphone_core_media_description_contains_video_stream(md);
734 735

	/* Handle AVPF and SRTP. */
736 737
	call->params->avpf_enabled = sal_media_description_has_avpf(md);
	if (call->params->avpf_enabled == TRUE) {
738
		if (call->dest_proxy != NULL) {
739
			call->params->avpf_rr_interval = linphone_proxy_config_get_avpf_rr_interval(call->dest_proxy) * 1000;
740
		} else {
741
			call->params->avpf_rr_interval = 5000;
742 743 744
		}
	}
	if ((sal_media_description_has_srtp(md) == TRUE) && (media_stream_srtp_supported() == TRUE)) {
745
		call->params->media_encryption = LinphoneMediaEncryptionSRTP;
746 747 748
	}
}

749
LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *from, LinphoneAddress *to, SalOp *op){
750
	LinphoneCall *call = belle_sip_object_new(LinphoneCall);
751
	const SalMediaDescription *md;
Simon Morlat's avatar
Simon Morlat committed
752
	LinphoneFirewallPolicy fpol;
753 754 755 756 757

	call->dir=LinphoneCallIncoming;
	sal_op_set_user_pointer(op,call);
	call->op=op;
	call->core=lc;
758
	linphone_call_incoming_select_ip_version(call);
jehan's avatar
jehan committed
759

760
	if (lc->sip_conf.ping_with_options){
761 762 763 764 765 766 767 768 769
#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);
770 771 772

			linphone_configure_op(lc, call->ping_op, from, NULL, FALSE);

773 774
			sal_op_set_route(call->ping_op,sal_op_get_network_origin(op));
			sal_op_set_user_pointer(call->ping_op,call);
775 776

			sal_ping(call->ping_op,sal_op_get_from(call->ping_op), sal_op_get_to(call->ping_op));
777
		}
778
	}
779

780
	linphone_address_clean(from);
781
	linphone_call_get_local_ip(call, from);
782
	linphone_call_init_common(call, from, to);
783
	call->params = linphone_call_params_new();
jehan's avatar
jehan committed
784
	call->log->call_id=ms_strdup(sal_op_get_call_id(op)); /*must be known at that time*/
785
	call->dest_proxy = linphone_core_lookup_known_proxy(call->core, to);
786
	linphone_core_init_default_params(lc, call->params);
787

788 789
	/*
	 * Initialize call parameters according to incoming call parameters. This is to avoid to ask later (during reINVITEs) for features that the remote
790
	 * end apparently does not support. This features are: privacy, video
791
	 */
jehan's avatar
jehan committed
792
	/*set privacy*/
793
	call->current_params->privacy=(LinphonePrivacyMask)sal_op_get_privacy(call->op);
794
	/*set video support */
795
	md=sal_call_get_remote_media_description(op);
796
	call->params->has_video = lc->video_policy.automatically_accept;
797 798 799
	if (md) {
		// It is licit to receive an INVITE without SDP
		// In this case WE chose the media parameters according to policy.
800
		linphone_call_set_compatible_incoming_call_parameters(call, md);
801
	}
Simon Morlat's avatar
Simon Morlat committed
802
	fpol=linphone_core_get_firewall_policy(call->core);
803
	/*create the ice session now if ICE is required*/
Simon Morlat's avatar
Simon Morlat committed
804 805 806 807 808 809 810 811
	if (fpol==LinphonePolicyUseIce){
		if (md){
			call->ice_session = ice_session_new();
			ice_session_set_role(call->ice_session, IR_Controlled);
		}else{
			fpol=LinphonePolicyNoFirewall;
			ms_warning("ICE not supported for incoming INVITE without SDP.");
		}
812 813 814
	}
	/*reserve the sockets immediately*/
	linphone_call_init_media_streams(call);
Simon Morlat's avatar
Simon Morlat committed
815
	switch (fpol) {
816
		case LinphonePolicyUseIce:
Simon Morlat's avatar
Simon Morlat committed
817
			linphone_call_prepare_ice(call,TRUE);
818
			break;
819
		case LinphonePolicyUseStun:
820
			call->ping_time=linphone_core_run_stun_tests(call->core,call);
821
			/* No break to also destroy ice session in this case. */
Yann Diorcet's avatar
Yann Diorcet committed
822 823 824
			break;
		case LinphonePolicyUseUpnp:
#ifdef BUILD_UPNP
825 826 827 828 829 830 831
			if(!lc->rtp_conf.disable_upnp) {
				call->upnp_session = linphone_upnp_session_new(call);
				if (call->upnp_session != NULL) {
					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);
					}
832
				}
Yann Diorcet's avatar
Yann Diorcet committed
833 834 835
			}
#endif //BUILD_UPNP
			break;
836 837 838
		default:
			break;
	}
839

840 841 842 843
	discover_mtu(lc,linphone_address_get_domain(from));
	return call;
}