linphonecall.c 147 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

40
static const char EC_STATE_STORE[] = ".linphone.ecstate";
41
#define EC_STATE_MAX_LEN 1048576 // 1Mo
42

Simon Morlat's avatar
Simon Morlat committed
43
static void linphone_call_stats_uninit(LinphoneCallStats *stats);
44
static void linphone_call_get_local_ip(LinphoneCall *call, const LinphoneAddress *remote_addr);
Simon Morlat's avatar
Simon Morlat committed
45

Simon Morlat's avatar
Simon Morlat committed
46
#ifdef VIDEO_ENABLED
47
MSWebCam *get_nowebcam_device(){
48 49
	return ms_web_cam_manager_get_cam(ms_web_cam_manager_get(),"StaticImage: Static picture");
}
Simon Morlat's avatar
Simon Morlat committed
50
#endif
51

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

61
	b64_size = b64_encode((const char*)tmp, key_length, NULL, 0);
62 63 64 65 66 67 68 69 70 71 72
	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);
73 74
	if (b64_size == 0) {
		ms_error("Failed to b64 encode key");
75
		ms_free(tmp);
76 77 78
		return FALSE;
	}
	key_out[b64_size] = '\0';
79
	ms_free(tmp);
80 81 82
	return TRUE;
}

83 84 85 86
LinphoneCore *linphone_call_get_core(const LinphoneCall *call){
	return call->core;
}

87
const char* linphone_call_get_authentication_token(LinphoneCall *call){
88
	return call->auth_token;
89 90
}

91 92 93 94 95 96 97 98
/**
 * 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
**/
99
bool_t linphone_call_get_authentication_token_verified(LinphoneCall *call){
100
	return call->auth_token_verified;
101
}
Simon Morlat's avatar
Simon Morlat committed
102

103
static bool_t linphone_call_all_streams_encrypted(const LinphoneCall *call) {
jehan's avatar
jehan committed
104 105 106 107 108
	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++;
109
			if(media_stream_secured((MediaStream *)call->audiostream))
jehan's avatar
jehan committed
110 111 112 113
				number_of_encrypted_stream++;
		}
		if (call->videostream && media_stream_get_state((MediaStream *)call->videostream) == MSStreamStarted) {
			number_of_active_stream++;
114
			if (media_stream_secured((MediaStream *)call->videostream))
jehan's avatar
jehan committed
115
				number_of_encrypted_stream++;
116
		}
117
	}
118
	return number_of_active_stream>0 && number_of_active_stream==number_of_encrypted_stream;
119 120
}

121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138
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));
}

139 140 141
static uint16_t linphone_call_get_avpf_rr_interval(const LinphoneCall *call) {
	uint16_t rr_interval = 0;
	uint16_t stream_rr_interval;
142 143 144 145 146 147 148 149 150 151
	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 {
152
		rr_interval = 5000;
153 154 155 156
	}
	return rr_interval;
}

157
static void propagate_encryption_changed(LinphoneCall *call){
158
	if (!linphone_call_all_streams_encrypted(call)) {
159
		ms_message("Some streams are not encrypted");
160
		call->current_params->media_encryption=LinphoneMediaEncryptionNone;
161
		linphone_core_notify_call_encryption_changed(call->core, call, FALSE, call->auth_token);
162
	} else {
johan's avatar
johan committed
163 164 165 166 167
		if (call->auth_token) {/* ZRTP only is using auth_token */
			call->current_params->media_encryption=LinphoneMediaEncryptionZRTP;
		} else { /* otherwise it must be DTLS as SDES doesn't go through this function */
			call->current_params->media_encryption=LinphoneMediaEncryptionDTLS;
		}
168
		ms_message("All streams are encrypted key exchanged using %s", call->current_params->media_encryption==LinphoneMediaEncryptionZRTP?"ZRTP":call->current_params->media_encryption==LinphoneMediaEncryptionDTLS?"DTLS":"Unknown mechanism");
169
		linphone_core_notify_call_encryption_changed(call->core, call, TRUE, call->auth_token);
170 171 172 173
	}
}

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

Sylvain Berfini's avatar
Sylvain Berfini committed
177
	call = (LinphoneCall *)data;
178

179
	if (encrypted) {
johan's avatar
johan committed
180 181 182 183
		if (call->params->media_encryption==LinphoneMediaEncryptionZRTP) { /* if encryption is DTLS, no status to be displayed */
			snprintf(status,sizeof(status)-1,_("Authentication token is %s"),call->auth_token);
			linphone_core_notify_display_status(call->core, status);
		}
184 185
	}

186 187 188 189 190
	propagate_encryption_changed(call);


#ifdef VIDEO_ENABLED
	// Enable video encryption
191 192 193
	{
		const LinphoneCallParams *params=linphone_call_get_current_params(call);
		if (params->has_video) {
194
			MSZrtpParams params;
195 196 197 198
			ms_message("Trying to enable encryption on video stream");
			params.zid_file=NULL; //unused
			video_stream_enable_zrtp(call->videostream,call->audiostream,&params);
		}
199 200 201 202 203 204 205
	}
#endif
}


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

209 210
	call->auth_token=ms_strdup(auth_token);
	call->auth_token_verified=verified;
211 212 213 214

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

215 216 217 218 219 220 221
/**
 * 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
222 223 224 225
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");
	}
226
	if (call->audiostream->ms.sessions.zrtp_context==NULL){
Simon Morlat's avatar
Simon Morlat committed
227 228 229
		ms_error("linphone_call_set_authentication_token_verified(): No zrtp context.");
	}
	if (!call->auth_token_verified && verified){
230
		ms_zrtp_sas_verified(call->audiostream->ms.sessions.zrtp_context);
Simon Morlat's avatar
Simon Morlat committed
231
	}else if (call->auth_token_verified && !verified){
232
		ms_zrtp_sas_reset_verified(call->audiostream->ms.sessions.zrtp_context);
Simon Morlat's avatar
Simon Morlat committed
233 234 235 236
	}
	call->auth_token_verified=verified;
	propagate_encryption_changed(call);
}
237

238 239
static int get_max_codec_sample_rate(const MSList *codecs){
	int max_sample_rate=0;
240 241 242
	const MSList *it;
	for(it=codecs;it!=NULL;it=it->next){
		PayloadType *pt=(PayloadType*)it->data;
243
		int sample_rate;
244

245 246 247 248 249 250 251 252
		if( strcasecmp("G722",pt->mime_type) == 0 ){
			/* G722 spec says 8000 but the codec actually requires 16000 */
			sample_rate = 16000;
		}else sample_rate=pt->clock_rate;
		if (sample_rate>max_sample_rate) max_sample_rate=sample_rate;
	}
	return max_sample_rate;
}
253

254 255 256 257 258 259 260 261 262 263 264 265
static int find_payload_type_number(const MSList *assigned, const PayloadType *pt){
	const MSList *elem;
	const PayloadType *candidate=NULL;
	for(elem=assigned;elem!=NULL;elem=elem->next){
		const PayloadType *it=(const PayloadType*)elem->data;
		if ((strcasecmp(pt->mime_type, payload_type_get_mime(it)) == 0)
			&& (it->clock_rate==pt->clock_rate)
			&& (it->channels==pt->channels || pt->channels<=0)) {
			candidate=it;
			if ((it->recv_fmtp!=NULL && pt->recv_fmtp!=NULL && strcasecmp(it->recv_fmtp, pt->recv_fmtp)==0)
				|| (it->recv_fmtp==NULL && pt->recv_fmtp==NULL)){
				break;/*exact match*/
266
			}
267 268 269 270 271 272 273 274 275 276 277 278 279
		}
	}
	return candidate ? payload_type_get_number(candidate) : -1;
}

bool_t is_payload_type_number_available(const MSList *l, int number, const PayloadType *ignore){
	const MSList *elem;
	for (elem=l; elem!=NULL; elem=elem->next){
		const PayloadType *pt=(PayloadType*)elem->data;
		if (pt!=ignore && payload_type_get_number(pt)==number) return FALSE;
	}
	return TRUE;
}
280

281 282 283 284 285 286
static void linphone_core_assign_payload_type_numbers(LinphoneCore *lc, MSList *codecs){
	MSList *elem;
	int dyn_number=lc->codecs_conf.dyn_pt;
	for (elem=codecs; elem!=NULL; elem=elem->next){
		PayloadType *pt=(PayloadType*)elem->data;
		int number=payload_type_get_number(pt);
287

288 289 290 291 292
		/*check if number is duplicated: it could be the case if the remote forced us to use a mapping with a previous offer*/
		if (number!=-1 && !(pt->flags & PAYLOAD_TYPE_FROZEN_NUMBER)){
			if (!is_payload_type_number_available(codecs, number, pt)){
				ms_message("Reassigning payload type %i %s/%i because already offered.", number, pt->mime_type, pt->clock_rate);
				number=-1; /*need to be re-assigned*/
293
			}
294
		}
295

296 297 298 299 300 301 302 303 304 305 306 307
		if (number==-1){
			while(dyn_number<127){
				if (is_payload_type_number_available(codecs, dyn_number, NULL)){
					payload_type_set_number(pt, dyn_number);
					dyn_number++;
					break;
				}
				dyn_number++;
			}
			if (dyn_number==127){
				ms_error("Too many payload types configured ! codec %s/%i is disabled.", pt->mime_type, pt->clock_rate);
				payload_type_set_enable(pt, FALSE);
308
			}
309 310
		}
	}
311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336
}

static bool_t has_telephone_event_at_rate(const MSList *tev, int rate){
	const MSList *it;
	for(it=tev;it!=NULL;it=it->next){
		const PayloadType *pt=(PayloadType*)it->data;
		if (pt->clock_rate==rate) return TRUE;
	}
	return FALSE;
}

static MSList * create_telephone_events(LinphoneCore *lc, const MSList *codecs){
	const MSList *it;
	MSList *ret=NULL;
	for(it=codecs;it!=NULL;it=it->next){
		const PayloadType *pt=(PayloadType*)it->data;
		if (!has_telephone_event_at_rate(ret,pt->clock_rate)){
			PayloadType *tev=payload_type_clone(&payload_type_telephone_event);
			tev->clock_rate=pt->clock_rate;
			/*let it choose the number dynamically as for normal codecs*/
			payload_type_set_number(tev, -1);
			if (ret==NULL){
				/*But for first telephone-event, prefer the number that was configured in the core*/
				if (is_payload_type_number_available(codecs, lc->codecs_conf.telephone_event_pt, NULL)){
					payload_type_set_number(tev, lc->codecs_conf.telephone_event_pt);
				}
337
			}
338 339 340 341 342 343
			ret=ms_list_append(ret,tev);
		}
	}
	return ret;
}

344 345 346 347 348 349 350 351 352 353
static MSList *create_special_payload_types(LinphoneCore *lc, const MSList *codecs){
	MSList *ret=create_telephone_events(lc, codecs);
	if (linphone_core_generic_confort_noise_enabled(lc)){
		PayloadType *cn=payload_type_clone(&payload_type_cn);
		payload_type_set_number(cn, 13);
		ret=ms_list_append(ret, cn);
	}
	return ret;
}

354 355 356 357 358 359
typedef struct _CodecConstraints{
	int bandwidth_limit;
	int max_codecs;
	MSList *previously_used;
}CodecConstraints;

360
static MSList *make_codec_list(LinphoneCore *lc, CodecConstraints * hints, SalStreamType stype, const MSList *codecs){
361 362 363 364 365 366 367
	MSList *l=NULL;
	const MSList *it;
	int nb = 0;

	for(it=codecs;it!=NULL;it=it->next){
		PayloadType *pt=(PayloadType*)it->data;
		int num;
368

369 370 371 372 373 374 375 376 377 378 379
		if (!(pt->flags & PAYLOAD_TYPE_ENABLED))
			continue;
		if (hints->bandwidth_limit>0 && !linphone_core_is_payload_type_usable_for_bandwidth(lc,pt,hints->bandwidth_limit)){
			ms_message("Codec %s/%i eliminated because of audio bandwidth constraint of %i kbit/s",
					pt->mime_type,pt->clock_rate,hints->bandwidth_limit);
			continue;
		}
		if (!linphone_core_check_payload_type_usability(lc,pt)){
			continue;
		}
		pt=payload_type_clone(pt);
380

381 382 383 384 385
		/*look for a previously assigned number for this codec*/
		num=find_payload_type_number(hints->previously_used, pt);
		if (num!=-1){
			payload_type_set_number(pt,num);
			payload_type_set_flag(pt, PAYLOAD_TYPE_FROZEN_NUMBER);
386
		}
387

388 389 390
		l=ms_list_append(l, pt);
		nb++;
		if ((hints->max_codecs > 0) && (nb >= hints->max_codecs)) break;
391
	}
392 393 394 395
	if (stype==SalAudio){
		MSList *specials=create_special_payload_types(lc,l);
		l=ms_list_concat(l,specials);
	}
396
	linphone_core_assign_payload_type_numbers(lc, l);
397 398 399
	return l;
}

400
static void update_media_description_from_stun(SalMediaDescription *md, const StunCandidate *ac, const StunCandidate *vc){
401
	int i;
402 403
	for (i = 0; i < md->nb_streams; i++) {
		if (!sal_stream_description_active(&md->streams[i])) continue;
404 405 406
		if ((md->streams[i].type == SalAudio) && (ac->port != 0)) {
			strcpy(md->streams[0].rtp_addr,ac->addr);
			md->streams[0].rtp_port=ac->port;
407
			if ((ac->addr[0]!='\0' && vc->addr[0]!='\0' && strcmp(ac->addr,vc->addr)==0) || sal_media_description_get_nb_active_streams(md)==1){
408 409 410 411 412 413
				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;
414 415 416 417
		}
	}
}

418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442
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;
}
443 444 445 446 447 448 449 450 451 452 453
static void setup_dtls_keys(LinphoneCall *call, SalMediaDescription *md){
	int i;
	for(i=0; i<md->nb_streams; i++) {
		if (!sal_stream_description_active(&md->streams[i])) continue;
		/* if media encryption is set to DTLS check presence of fingerprint in the call which shall have been set at stream init but it may have failed when retrieving certificate resulting in no fingerprint present and then DTLS not usable */
		if (sal_stream_description_has_dtls(&md->streams[i]) == TRUE) {
			strncpy(md->streams[i].dtls_fingerprint, call->dtls_certificate_fingerprint, sizeof(md->streams[i].dtls_fingerprint)); /* get the self fingerprint from call(it's computed at stream init) */
			md->streams[i].dtls_role = SalDtlsRoleUnset; /* if we are offering, SDP will have actpass setup attribute when role is unset, if we are responding the result mediadescription will be set to SalDtlsRoleIsClient */
		} else {
			md->streams[i].dtls_fingerprint[0] = '\0';
			md->streams[i].dtls_role = SalDtlsRoleInvalid;
454

455 456 457 458
		}
	}

}
459 460
static void setup_encryption_keys(LinphoneCall *call, SalMediaDescription *md){
	LinphoneCore *lc=call->core;
461
	int i,j;
462
	SalMediaDescription *old_md=call->localdesc;
463
	bool_t keep_srtp_keys=lp_config_get_int(lc->config,"sip","keep_srtp_keys",1);
464

465 466 467
	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) {
468
			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)) {
469 470 471 472 473 474
				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{
475 476 477 478
				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);
				}
479 480 481 482 483
			}
		}
	}
}

484 485 486 487 488 489
static void setup_rtcp_fb(LinphoneCall *call, SalMediaDescription *md) {
	MSList *pt_it;
	PayloadType *pt;
	PayloadTypeAvpfParams avpf_params;
	int i;

490 491
	for (i = 0; i < md->nb_streams; i++) {
		if (!sal_stream_description_active(&md->streams[i])) continue;
492 493
		for (pt_it = md->streams[i].payloads; pt_it != NULL; pt_it = pt_it->next) {
			pt = (PayloadType *)pt_it->data;
494
			if (call->params->avpf_enabled == TRUE) {
495 496
				payload_type_set_flag(pt, PAYLOAD_TYPE_RTCP_FEEDBACK_ENABLED);
				avpf_params = payload_type_get_avpf_params(pt);
497
				avpf_params.trr_interval = call->params->avpf_rr_interval;
498 499 500 501 502 503 504 505 506
			} 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);
		}
	}
}

507 508
static void setup_rtcp_xr(LinphoneCall *call, SalMediaDescription *md) {
	LinphoneCore *lc = call->core;
509
	int i;
510

Simon Morlat's avatar
Simon Morlat committed
511
	md->rtcp_xr.enabled = lp_config_get_int(lc->config, "rtp", "rtcp_xr_enabled", 1);
512
	if (md->rtcp_xr.enabled == TRUE) {
Simon Morlat's avatar
Simon Morlat committed
513
		const char *rcvr_rtt_mode = lp_config_get_string(lc->config, "rtp", "rtcp_xr_rcvr_rtt_mode", "all");
514 515 516 517
		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) {
Simon Morlat's avatar
Simon Morlat committed
518
			md->rtcp_xr.rcvr_rtt_max_size = lp_config_get_int(lc->config, "rtp", "rtcp_xr_rcvr_rtt_max_size", 10000);
519
		}
Simon Morlat's avatar
Simon Morlat committed
520
		md->rtcp_xr.stat_summary_enabled = lp_config_get_int(lc->config, "rtp", "rtcp_xr_stat_summary_enabled", 1);
521
		if (md->rtcp_xr.stat_summary_enabled == TRUE) {
522
			md->rtcp_xr.stat_summary_flags = OrtpRtcpXrStatSummaryLoss | OrtpRtcpXrStatSummaryDup | OrtpRtcpXrStatSummaryJitt | OrtpRtcpXrStatSummaryTTL;
523
		}
Simon Morlat's avatar
Simon Morlat committed
524
		md->rtcp_xr.voip_metrics_enabled = lp_config_get_int(lc->config, "rtp", "rtcp_xr_voip_metrics_enabled", 1);
525
	}
526 527
	for (i = 0; i < md->nb_streams; i++) {
		if (!sal_stream_description_active(&md->streams[i])) continue;
528 529
		memcpy(&md->streams[i].rtcp_xr, &md->rtcp_xr, sizeof(md->streams[i].rtcp_xr));
	}
530 531
}

532 533 534 535 536
void linphone_call_increment_local_media_description(LinphoneCall *call){
	SalMediaDescription *md=call->localdesc;
	md->session_ver++;
}

537 538 539 540 541 542 543 544 545 546 547 548 549
void linphone_call_update_local_media_description_from_ice_or_upnp(LinphoneCall *call){
	if (call->ice_session != NULL) {
		_update_local_media_description_from_ice(call->localdesc, call->ice_session);
		linphone_core_update_ice_state_in_call_stats(call);
	}
#ifdef BUILD_UPNP
	if(call->upnp_session != NULL) {
		linphone_core_update_local_media_description_from_upnp(call->localdesc, call->upnp_session);
		linphone_core_update_upnp_state_in_call_stats(call);
	}
#endif  //BUILD_UPNP
}

550 551 552 553 554 555 556 557
static void transfer_already_assigned_payload_types(SalMediaDescription *old, SalMediaDescription *md){
	int i;
	for(i=0;i<old->nb_streams;++i){
		md->streams[i].already_assigned_payloads=old->streams[i].already_assigned_payloads;
		old->streams[i].already_assigned_payloads=NULL;
	}
}

558
static const char *linphone_call_get_bind_ip_for_stream(LinphoneCall *call, int stream_index){
559
	const char *bind_ip = lp_config_get_string(call->core->config,"rtp","bind_address",call->af==AF_INET6 ? "::0" : "0.0.0.0");
560

561 562
	if (stream_index<2 && call->media_ports[stream_index].multicast_ip[0]!='\0'){
		if (call->dir==LinphoneCallOutgoing){
563
			/*as multicast sender, we must decide a local interface to use to send multicast, and bind to it*/
564
			bind_ip=call->media_localip;
565 566
		}
	}
567 568 569
	return bind_ip;
}

570
static const char *linphone_call_get_public_ip_for_stream(LinphoneCall *call, int stream_index){
571
	const char *public_ip=call->media_localip;
572 573

	if (stream_index<2 && call->media_ports[stream_index].multicast_ip[0]!='\0')
574 575 576 577
		public_ip=call->media_ports[stream_index].multicast_ip;
	return public_ip;
}

578 579 580 581 582
void linphone_call_make_local_media_description(LinphoneCore *lc, LinphoneCall *call) {
	linphone_call_make_local_media_description_with_params(lc, call, call->params);
}

void linphone_call_make_local_media_description_with_params(LinphoneCore *lc, LinphoneCall *call, LinphoneCallParams *params) {
583
	MSList *l;
Simon Morlat's avatar
Simon Morlat committed
584
	SalMediaDescription *old_md=call->localdesc;
585
	int i;
586
	int nb_active_streams = 0;
587
	const char *me;
588
	SalMediaDescription *md=sal_media_description_new();
589
	LinphoneAddress *addr;
590 591
	const char *subject;
	CodecConstraints codec_hints={0};
592

jehan's avatar
jehan committed
593 594 595
	/*multicast is only set in case of outgoing call*/
	if (call->dir == LinphoneCallOutgoing && linphone_core_audio_multicast_enabled(lc)) {
		md->streams[0].ttl=linphone_core_get_audio_multicast_ttl(lc);
596 597
		md->streams[0].multicast_role = SalMulticastSender;
	}
jehan's avatar
jehan committed
598 599 600

	if (call->dir == LinphoneCallOutgoing && linphone_core_video_multicast_enabled(lc)) {
		md->streams[1].ttl=linphone_core_get_video_multicast_ttl(lc);
601 602
		md->streams[1].multicast_role = SalMulticastSender;
	}
jehan's avatar
jehan committed
603

604
	subject=linphone_call_params_get_session_name(params);
605

606
	linphone_core_adapt_to_network(lc,call->ping_time,params);
607

608 609
	if (call->dest_proxy)
		me=linphone_proxy_config_get_identity(call->dest_proxy);
610
	else
611 612
		me=linphone_core_get_identity(lc);
	addr=linphone_address_new(me);
613

Simon Morlat's avatar
Simon Morlat committed
614 615
	md->session_id=(old_md ? old_md->session_id : (rand() & 0xfff));
	md->session_ver=(old_md ? (old_md->session_ver+1) : (rand() & 0xfff));
616
	md->nb_streams=(call->biggestdesc ? call->biggestdesc->nb_streams : 1);
617

618 619
	/*re-check local ip address each time we make a new offer, because it may change in case of network reconnection*/
	linphone_call_get_local_ip(call, call->dir == LinphoneCallOutgoing ?  call->log->to : call->log->from);
620
	strncpy(md->addr,call->media_localip,sizeof(md->addr));
jehan's avatar
jehan committed
621 622
	if (linphone_address_get_username(addr)) /*might be null in case of identity without userinfo*/
		strncpy(md->username,linphone_address_get_username(addr),sizeof(md->username));
Simon Morlat's avatar
Simon Morlat committed
623
	if (subject) strncpy(md->name,subject,sizeof(md->name));
624

625 626
	if (params->down_bw)
		md->bandwidth=params->down_bw;
627
	else md->bandwidth=linphone_core_get_download_bandwidth(lc);
628

629
	/*set audio capabilities */
630 631
	strncpy(md->streams[0].rtp_addr,linphone_call_get_public_ip_for_stream(call,0),sizeof(md->streams[0].rtp_addr));
	strncpy(md->streams[0].rtcp_addr,linphone_call_get_public_ip_for_stream(call,0),sizeof(md->streams[0].rtcp_addr));
632
	strncpy(md->streams[0].name,"Audio",sizeof(md->streams[0].name)-1);
633 634
	md->streams[0].rtp_port=call->media_ports[0].rtp_port;
	md->streams[0].rtcp_port=call->media_ports[0].rtcp_port;
635 636
	md->streams[0].proto=get_proto_from_call_params(params);
	md->streams[0].dir=get_audio_dir_from_call_params(params);
637
	md->streams[0].type=SalAudio;
638 639
	if (params->down_ptime)
		md->streams[0].ptime=params->down_ptime;
640
	else
641
		md->streams[0].ptime=linphone_core_get_download_ptime(lc);
642
	codec_hints.bandwidth_limit=params->audio_bw;
643 644
	codec_hints.max_codecs=-1;
	codec_hints.previously_used=old_md ? old_md->streams[0].already_assigned_payloads : NULL;
645
	l=make_codec_list(lc, &codec_hints, SalAudio, lc->codecs_conf.audio_codecs);
646
	md->streams[0].max_rate=get_max_codec_sample_rate(l);
647
	md->streams[0].payloads=l;
648 649 650 651 652 653 654 655
	if (call->audiostream && call->audiostream->ms.sessions.rtp_session) {
		char* me = linphone_address_as_string_uri_only(call->me);
		md->streams[0].rtp_ssrc=rtp_session_get_send_ssrc(call->audiostream->ms.sessions.rtp_session);
		strncpy(md->streams[0].rtcp_cname,me,sizeof(md->streams[0].rtcp_cname));
		ms_free(me);
	}
	else
		ms_warning("Cannot get audio local ssrc for call [%p]",call);
656
	nb_active_streams++;
657

658
	if (params->has_video && (!params->internal_call_update || !call->current_params->video_declined)){
659 660
		strncpy(md->streams[1].rtp_addr,linphone_call_get_public_ip_for_stream(call,1),sizeof(md->streams[1].rtp_addr));
		strncpy(md->streams[1].rtcp_addr,linphone_call_get_public_ip_for_stream(call,1),sizeof(md->streams[1].rtcp_addr));
661
		strncpy(md->streams[1].name,"Video",sizeof(md->streams[1].name)-1);
662 663
		md->streams[1].rtp_port=call->media_ports[1].rtp_port;
		md->streams[1].rtcp_port=call->media_ports[1].rtcp_port;
664
		md->streams[1].proto=md->streams[0].proto;
665
		md->streams[1].dir=get_video_dir_from_call_params(params);
666
		md->streams[1].type=SalVideo;
667 668 669
		codec_hints.bandwidth_limit=0;
		codec_hints.max_codecs=-1;
		codec_hints.previously_used=old_md ? old_md->streams[1].already_assigned_payloads : NULL;
670
		l=make_codec_list(lc, &codec_hints, SalVideo, lc->codecs_conf.video_codecs);
671
		md->streams[1].payloads=l;
672 673
		if (call->videostream && call->videostream->ms.sessions.rtp_session) {
			char* me = linphone_address_as_string_uri_only(call->me);
jehan's avatar
jehan committed
674 675
			md->streams[1].rtp_ssrc=rtp_session_get_send_ssrc(call->videostream->ms.sessions.rtp_session);
			strncpy(md->streams[1].rtcp_cname,me,sizeof(md->streams[1].rtcp_cname));
676 677 678 679
			ms_free(me);
		}
		else
			ms_warning("Cannot get video local ssrc for call [%p]",call);
680
		nb_active_streams++;
681 682
	} else {
		ms_message("Don't put video stream on local offer for call [%p]",call);
683
	}
684 685 686

	if (md->nb_streams < nb_active_streams)
		md->nb_streams = nb_active_streams;
687 688

	/* Deactivate inactive streams. */
689
	for (i = nb_active_streams; i < md->nb_streams; i++) {
690 691
		md->streams[i].rtp_port = 0;
		md->streams[i].rtcp_port = 0;
692 693
		md->streams[i].proto = call->biggestdesc->streams[i].proto;
		md->streams[i].type = call->biggestdesc->streams[i].type;
694
		md->streams[i].dir = SalStreamInactive;
695 696 697
		codec_hints.bandwidth_limit=0;
		codec_hints.max_codecs=1;
		codec_hints.previously_used=NULL;
698
		l = make_codec_list(lc, &codec_hints, SalVideo, lc->codecs_conf.video_codecs);
699 700
		md->streams[i].payloads = l;
	}
701
	setup_encryption_keys(call,md);
702
	setup_dtls_keys(call,md);
703
	setup_rtcp_fb(call, md);
704
	setup_rtcp_xr(call, md);
705

706
	update_media_description_from_stun(md,&call->ac,&call->vc);
Simon Morlat's avatar
Simon Morlat committed
707
	call->localdesc=md;
708 709
	linphone_call_update_local_media_description_from_ice_or_upnp(call);
	linphone_address_destroy(addr);
710
	if (old_md){
711
		transfer_already_assigned_payload_types(old_md,md);
712 713 714
		call->localdesc_changed=sal_media_description_equals(md,old_md);
		sal_media_description_unref(old_md);
	}
715 716
}

717
static int find_port_offset(LinphoneCore *lc, int stream_index, int base_port){
718 719
	int offset;
	MSList *elem;
720 721
	int tried_port;
	int existing_port;
722
	bool_t already_used=FALSE;
723

724
	for(offset=0;offset<100;offset+=2){
725
		tried_port=base_port+offset;
726 727 728
		already_used=FALSE;
		for(elem=lc->calls;elem!=NULL;elem=elem->next){
			LinphoneCall *call=(LinphoneCall*)elem->data;
729
			existing_port=call->media_ports[stream_index].rtp_port;
730
			if (existing_port==tried_port) {
731 732 733 734 735 736 737 738 739 740 741 742 743
				already_used=TRUE;
				break;
			}
		}
		if (!already_used) break;
	}
	if (offset==100){
		ms_error("Could not find any free port !");
		return -1;
	}
	return offset;
}

744
static int select_random_port(LinphoneCore *lc, int stream_index, int min_port, int max_port) {
745 746 747 748 749 750 751 752 753 754 755
	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;
756
			existing_port=call->media_ports[stream_index].rtp_port;
757 758 759 760 761 762 763 764 765 766 767 768 769 770
			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;
}

771 772 773 774 775 776
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){
777
	int port_offset;
778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795
	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){
796
	int min_port, max_port;
797
	ms_message("New LinphoneCall [%p] initialized (LinphoneCore version: %s)",call,linphone_core_get_version());
798
	call->state=LinphoneCallIdle;
799
	call->transfer_state = LinphoneCallIdle;
800
	call->log=linphone_call_log_new(call->dir, from, to);
801
	call->camera_enabled=TRUE;
802 803
	call->current_params = linphone_call_params_new();
	call->current_params->media_encryption=LinphoneMediaEncryptionNone;
johan's avatar
johan committed
804
	call->dtls_certificate_fingerprint = NULL;
jehan's avatar
jehan committed
805 806 807 808 809
	if (call->dir == LinphoneCallIncoming)
		call->me=to;
	 else
		call->me=from;
	linphone_address_ref(call->me);
810

811
	linphone_core_get_audio_port_range(call->core, &min_port, &max_port);
812
	port_config_set(call,0,min_port,max_port);
813

814
	linphone_core_get_video_port_range(call->core, &min_port, &max_port);
815
	port_config_set(call,1,min_port,max_port);
816

817 818 819 820 821 822 823 824 825 826
	if (call->dir==LinphoneCallOutgoing){
		if ( linphone_core_audio_multicast_enabled(call->core)){
			strncpy(call->media_ports[0].multicast_ip,
				linphone_core_get_audio_multicast_addr(call->core), sizeof(call->media_ports[0].multicast_ip));
		}
		if ( linphone_core_video_multicast_enabled(call->core)){
			strncpy(call->media_ports[1].multicast_ip,
				linphone_core_get_video_multicast_addr(call->core), sizeof(call->media_ports[1].multicast_ip));
		}
	}
827

Yann Diorcet's avatar
Yann Diorcet committed
828 829
	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);
830 831 832
#ifdef VIDEO_ENABLED
	call->cam = call->core->video_conf.device;
#endif
Yann Diorcet's avatar
Yann Diorcet committed
833
}
834

Yann Diorcet's avatar
Yann Diorcet committed
835
void linphone_call_init_stats(LinphoneCallStats *stats, int type) {
Yann Diorcet's avatar
Yann Diorcet committed
836
	stats->type = type;
Yann Diorcet's avatar
Yann Diorcet committed
837 838
	stats->received_rtcp = NULL;
	stats->sent_rtcp = NULL;
839
	stats->ice_state = LinphoneIceStateNotActivated;
Yann Diorcet's avatar
Yann Diorcet committed
840 841 842 843 844
#ifdef BUILD_UPNP
	stats->upnp_state = LinphoneUpnpStateIdle;
#else
	stats->upnp_state = LinphoneUpnpStateNotAvailable;
#endif //BUILD_UPNP
845 846
}

847

848 849 850 851 852 853 854 855 856 857 858 859 860
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
861 862 863 864
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);
865 866 867 868 869
	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
870
	/*else privacy might be set by proxy */
Simon Morlat's avatar
Simon Morlat committed
871 872
}

873 874 875 876
/*
 * 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