linphonecall.c 160 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
#ifdef _WIN32
22 23
#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

46

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

55

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

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

87 88 89 90
LinphoneCore *linphone_call_get_core(const LinphoneCall *call){
	return call->core;
}

91
const char* linphone_call_get_authentication_token(LinphoneCall *call){
92
	return call->auth_token;
93 94
}

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

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

125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142
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));
}

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

161
static void propagate_encryption_changed(LinphoneCall *call){
162
	if (!linphone_call_all_streams_encrypted(call)) {
163
		ms_message("Some streams are not encrypted");
164
		call->current_params->media_encryption=LinphoneMediaEncryptionNone;
165
		linphone_core_notify_call_encryption_changed(call->core, call, FALSE, call->auth_token);
166
	} else {
johan's avatar
johan committed
167 168 169 170 171
		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;
		}
172
		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");
173
		linphone_core_notify_call_encryption_changed(call->core, call, TRUE, call->auth_token);
174 175 176 177
	}
}

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

Sylvain Berfini's avatar
Sylvain Berfini committed
181
	call = (LinphoneCall *)data;
182

183
	if (encrypted) {
johan's avatar
johan committed
184 185 186 187
		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);
		}
188 189
	}

190 191 192 193 194
	propagate_encryption_changed(call);


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


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

213 214
	call->auth_token=ms_strdup(auth_token);
	call->auth_token_verified=verified;
215 216 217 218

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

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

242 243
static int get_max_codec_sample_rate(const MSList *codecs){
	int max_sample_rate=0;
244 245 246
	const MSList *it;
	for(it=codecs;it!=NULL;it=it->next){
		PayloadType *pt=(PayloadType*)it->data;
247
		int sample_rate;
248

249 250 251 252 253 254 255 256
		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;
}
257

258 259 260 261 262 263 264 265 266 267 268 269
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*/
270
			}
271 272 273 274 275 276 277 278 279 280 281 282 283
		}
	}
	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;
}
284

285 286 287 288 289 290
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);
291

292 293 294 295 296
		/*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*/
297
			}
298
		}
299

300 301 302 303 304 305 306 307 308 309 310 311
		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);
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 337 338 339 340
}

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);
				}
341
			}
342 343 344 345 346 347
			ret=ms_list_append(ret,tev);
		}
	}
	return ret;
}

348 349 350 351 352 353 354 355 356 357
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;
}

358 359 360 361 362 363
typedef struct _CodecConstraints{
	int bandwidth_limit;
	int max_codecs;
	MSList *previously_used;
}CodecConstraints;

364
static MSList *make_codec_list(LinphoneCore *lc, CodecConstraints * hints, SalStreamType stype, const MSList *codecs){
365 366 367 368 369 370 371
	MSList *l=NULL;
	const MSList *it;
	int nb = 0;

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

373 374 375 376 377 378 379 380 381 382 383
		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);
384

385 386 387 388 389
		/*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);
390
		}
391

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

404
static void update_media_description_from_stun(SalMediaDescription *md, const StunCandidate *ac, const StunCandidate *vc){
405
	int i;
406 407
	for (i = 0; i < md->nb_streams; i++) {
		if (!sal_stream_description_active(&md->streams[i])) continue;
408 409 410
		if ((md->streams[i].type == SalAudio) && (ac->port != 0)) {
			strcpy(md->streams[0].rtp_addr,ac->addr);
			md->streams[0].rtp_port=ac->port;
411
			if ((ac->addr[0]!='\0' && vc->addr[0]!='\0' && strcmp(ac->addr,vc->addr)==0) || sal_media_description_get_nb_active_streams(md)==1){
412 413 414 415 416 417
				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;
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 443 444 445 446
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;
}
447 448 449 450 451 452 453 454 455 456 457
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;
458

459 460 461 462
		}
	}

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

469 470 471
	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) {
472
			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)) {
473 474 475 476 477 478
				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{
479 480 481 482
				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);
				}
483 484 485 486 487
			}
		}
	}
}

488 489 490 491
static void setup_rtcp_fb(LinphoneCall *call, SalMediaDescription *md) {
	MSList *pt_it;
	PayloadType *pt;
	PayloadTypeAvpfParams avpf_params;
492
	LinphoneCore *lc = call->core;
493 494
	int i;

495 496
	for (i = 0; i < md->nb_streams; i++) {
		if (!sal_stream_description_active(&md->streams[i])) continue;
497 498
		md->streams[i].rtcp_fb.generic_nack_enabled = lp_config_get_int(lc->config, "rtp", "rtcp_fb_generic_nack_enabled", 0);
		md->streams[i].rtcp_fb.tmmbr_enabled = lp_config_get_int(lc->config, "rtp", "rtcp_fb_tmmbr_enabled", 0);
499 500
		for (pt_it = md->streams[i].payloads; pt_it != NULL; pt_it = pt_it->next) {
			pt = (PayloadType *)pt_it->data;
501
			if (call->params->avpf_enabled == TRUE) {
502 503
				payload_type_set_flag(pt, PAYLOAD_TYPE_RTCP_FEEDBACK_ENABLED);
				avpf_params = payload_type_get_avpf_params(pt);
504
				avpf_params.trr_interval = call->params->avpf_rr_interval;
505 506 507 508 509 510 511 512 513
			} 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);
		}
	}
}

514 515
static void setup_rtcp_xr(LinphoneCall *call, SalMediaDescription *md) {
	LinphoneCore *lc = call->core;
516
	int i;
517

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

539 540 541 542 543
void linphone_call_increment_local_media_description(LinphoneCall *call){
	SalMediaDescription *md=call->localdesc;
	md->session_ver++;
}

544 545 546 547 548 549 550 551 552 553 554 555 556
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
}

557 558 559 560 561 562 563 564
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;
	}
}

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

568 569
	if (stream_index<2 && call->media_ports[stream_index].multicast_ip[0]!='\0'){
		if (call->dir==LinphoneCallOutgoing){
570
			/*as multicast sender, we must decide a local interface to use to send multicast, and bind to it*/
571
			bind_ip=call->media_localip;
572 573
		}
	}
574 575 576
	return bind_ip;
}

577
static const char *linphone_call_get_public_ip_for_stream(LinphoneCall *call, int stream_index){
578
	const char *public_ip=call->media_localip;
579 580

	if (stream_index<2 && call->media_ports[stream_index].multicast_ip[0]!='\0')
581 582 583 584
		public_ip=call->media_ports[stream_index].multicast_ip;
	return public_ip;
}

585 586
static void force_streams_dir_according_to_state(LinphoneCall *call, SalMediaDescription *md){
	int i;
587

588 589 590 591 592 593 594 595
	switch (call->state){
		case LinphoneCallPausing:
		case LinphoneCallPaused:
		break;
		default:
			return;
		break;
	}
596

597 598 599 600 601 602 603 604 605
	for (i=0; i<2; ++i){
		SalStreamDescription *sd = &md->streams[i];
		sd->dir = SalStreamSendOnly;
		if (sd->type == SalVideo){
			if (lp_config_get_int(call->core->config, "sip", "inactive_video_on_pause", 0)) {
				sd->dir = SalStreamInactive;
			}
		}
	}
606 607
}

608
void linphone_call_make_local_media_description(LinphoneCall *call) {
609
	MSList *l;
Simon Morlat's avatar
Simon Morlat committed
610
	SalMediaDescription *old_md=call->localdesc;
611
	int i;
612
	int nb_active_streams = 0;
613
	SalMediaDescription *md=sal_media_description_new();
614
	LinphoneAddress *addr;
615 616
	const char *subject;
	CodecConstraints codec_hints={0};
617 618 619
	LinphoneCallParams *params = call->params;
	LinphoneCore *lc = call->core;

620

jehan's avatar
jehan committed
621
	/*multicast is only set in case of outgoing call*/
622
	if (call->dir == LinphoneCallOutgoing && linphone_call_params_audio_multicast_enabled(params)) {
jehan's avatar
jehan committed
623
		md->streams[0].ttl=linphone_core_get_audio_multicast_ttl(lc);
624 625
		md->streams[0].multicast_role = SalMulticastSender;
	}
jehan's avatar
jehan committed
626

627
	if (call->dir == LinphoneCallOutgoing && linphone_call_params_video_multicast_enabled(params)) {
jehan's avatar
jehan committed
628
		md->streams[1].ttl=linphone_core_get_video_multicast_ttl(lc);
629 630
		md->streams[1].multicast_role = SalMulticastSender;
	}
jehan's avatar
jehan committed
631

632
	subject=linphone_call_params_get_session_name(params);
633

634
	linphone_core_adapt_to_network(lc,call->ping_time,params);
635

636 637 638 639 640
	if (call->dest_proxy) {
		addr=linphone_address_clone(linphone_proxy_config_get_identity_address(call->dest_proxy));
	} else {
		addr=linphone_address_new(linphone_core_get_identity(lc));
	}
641

Simon Morlat's avatar
Simon Morlat committed
642 643
	md->session_id=(old_md ? old_md->session_id : (rand() & 0xfff));
	md->session_ver=(old_md ? (old_md->session_ver+1) : (rand() & 0xfff));
644
	md->nb_streams=(call->biggestdesc ? call->biggestdesc->nb_streams : 1);
645

646 647
	/*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);
648
	strncpy(md->addr,call->media_localip,sizeof(md->addr));
jehan's avatar
jehan committed
649 650
	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
651
	if (subject) strncpy(md->name,subject,sizeof(md->name));
652

653 654
	if (params->down_bw)
		md->bandwidth=params->down_bw;
655
	else md->bandwidth=linphone_core_get_download_bandwidth(lc);
656

657
	/*set audio capabilities */
658 659
	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));
660
	strncpy(md->streams[0].name,"Audio",sizeof(md->streams[0].name)-1);
661 662
	md->streams[0].rtp_port=call->media_ports[0].rtp_port;
	md->streams[0].rtcp_port=call->media_ports[0].rtcp_port;
663 664
	md->streams[0].proto=get_proto_from_call_params(params);
	md->streams[0].dir=get_audio_dir_from_call_params(params);
665
	md->streams[0].type=SalAudio;
666 667
	if (params->down_ptime)
		md->streams[0].ptime=params->down_ptime;
668
	else
669
		md->streams[0].ptime=linphone_core_get_download_ptime(lc);
670
	codec_hints.bandwidth_limit=params->audio_bw;
671 672
	codec_hints.max_codecs=-1;
	codec_hints.previously_used=old_md ? old_md->streams[0].already_assigned_payloads : NULL;
673
	l=make_codec_list(lc, &codec_hints, SalAudio, lc->codecs_conf.audio_codecs);
674
	md->streams[0].max_rate=get_max_codec_sample_rate(l);
675
	md->streams[0].payloads=l;
676 677 678 679 680 681 682 683
	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);
684
	nb_active_streams++;
685

686
	if (params->has_video && (!params->internal_call_update || !call->current_params->video_declined)){
687 688
		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));
689
		strncpy(md->streams[1].name,"Video",sizeof(md->streams[1].name)-1);
690 691
		md->streams[1].rtp_port=call->media_ports[1].rtp_port;
		md->streams[1].rtcp_port=call->media_ports[1].rtcp_port;
692
		md->streams[1].proto=md->streams[0].proto;
693
		md->streams[1].dir=get_video_dir_from_call_params(params);
694
		md->streams[1].type=SalVideo;
695 696 697
		codec_hints.bandwidth_limit=0;
		codec_hints.max_codecs=-1;
		codec_hints.previously_used=old_md ? old_md->streams[1].already_assigned_payloads : NULL;
698
		l=make_codec_list(lc, &codec_hints, SalVideo, lc->codecs_conf.video_codecs);
699
		md->streams[1].payloads=l;
700 701
		if (call->videostream && call->videostream->ms.sessions.rtp_session) {
			char* me = linphone_address_as_string_uri_only(call->me);
jehan's avatar
jehan committed
702 703
			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));
704 705 706 707
			ms_free(me);
		}
		else
			ms_warning("Cannot get video local ssrc for call [%p]",call);
708
		nb_active_streams++;
709 710
	} else {
		ms_message("Don't put video stream on local offer for call [%p]",call);
711
	}
712 713 714

	if (md->nb_streams < nb_active_streams)
		md->nb_streams = nb_active_streams;
715 716

	/* Deactivate inactive streams. */
717
	for (i = nb_active_streams; i < md->nb_streams; i++) {
718 719
		md->streams[i].rtp_port = 0;
		md->streams[i].rtcp_port = 0;
720 721
		md->streams[i].proto = call->biggestdesc->streams[i].proto;
		md->streams[i].type = call->biggestdesc->streams[i].type;
722
		md->streams[i].dir = SalStreamInactive;
723 724 725
		codec_hints.bandwidth_limit=0;
		codec_hints.max_codecs=1;
		codec_hints.previously_used=NULL;
726
		l = make_codec_list(lc, &codec_hints, SalVideo, lc->codecs_conf.video_codecs);
727 728
		md->streams[i].payloads = l;
	}
729
	setup_encryption_keys(call,md);
730
	setup_dtls_keys(call,md);
731
	setup_rtcp_fb(call, md);
732
	setup_rtcp_xr(call, md);
733

734
	update_media_description_from_stun(md,&call->ac,&call->vc);
Simon Morlat's avatar
Simon Morlat committed
735
	call->localdesc=md;
736 737
	linphone_call_update_local_media_description_from_ice_or_upnp(call);
	linphone_address_destroy(addr);
738
	if (old_md){
739
		transfer_already_assigned_payload_types(old_md,md);
740 741 742
		call->localdesc_changed=sal_media_description_equals(md,old_md);
		sal_media_description_unref(old_md);
	}
743
	force_streams_dir_according_to_state(call, md);
744 745
}

746
static int find_port_offset(LinphoneCore *lc, int stream_index, int base_port){
747 748
	int offset;
	MSList *elem;
749 750
	int tried_port;
	int existing_port;
751
	bool_t already_used=FALSE;
752

753
	for(offset=0;offset<100;offset+=2){
754
		tried_port=base_port+offset;
755 756 757
		already_used=FALSE;
		for(elem=lc->calls;elem!=NULL;elem=elem->next){
			LinphoneCall *call=(LinphoneCall*)elem->data;
758
			existing_port=call->media_ports[stream_index].rtp_port;
759
			if (existing_port==tried_port) {
760 761 762 763 764 765 766 767 768 769 770 771 772
				already_used=TRUE;
				break;
			}
		}
		if (!already_used) break;
	}
	if (offset==100){
		ms_error("Could not find any free port !");
		return -1;
	}
	return offset;
}

773
static int select_random_port(LinphoneCore *lc, int stream_index, int min_port, int max_port) {
774 775 776 777 778 779
	MSList *elem;
	int nb_tries;
	int tried_port = 0;
	int existing_port = 0;
	bool_t already_used = FALSE;

780
	tried_port = (ortp_random() % (max_port - min_port) + min_port) & ~0x1;
781 782 783 784
	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;
785
			existing_port=call->media_ports[stream_index].rtp_port;
786 787 788 789 790 791 792 793 794 795 796 797 798 799
			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;
}

800 801 802 803 804 805
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){
806
	int port_offset;
807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824
	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){
825
	int min_port, max_port;
826
	ms_message("New LinphoneCall [%p] initialized (LinphoneCore version: %s)",call,linphone_core_get_version());
827
	call->state=LinphoneCallIdle;
828
	call->transfer_state = LinphoneCallIdle;
829
	call->log=linphone_call_log_new(call->dir, from, to);
830
	call->camera_enabled=TRUE;
831 832
	call->current_params = linphone_call_params_new();
	call->current_params->media_encryption=LinphoneMediaEncryptionNone;
johan's avatar
johan committed
833
	call->dtls_certificate_fingerprint = NULL;
jehan's avatar
jehan committed
834 835 836 837 838
	if (call->dir == LinphoneCallIncoming)
		call->me=to;
	 else
		call->me=from;
	linphone_address_ref(call->me);
839

840
	linphone_core_get_audio_port_range(call->core, &min_port, &max_port);
841
	port_config_set(call,0,min_port,max_port);
842

843
	linphone_core_get_video_port_range(call->core, &min_port, &max_port);
844
	port_config_set(call,1,min_port,max_port);
845

Yann Diorcet's avatar
Yann Diorcet committed
846 847 848
	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);
}
849

Yann Diorcet's avatar
Yann Diorcet committed
850
void linphone_call_init_stats(LinphoneCallStats *stats, int type) {
Yann Diorcet's avatar
Yann Diorcet committed
851
	stats->type = type;
Yann Diorcet's avatar
Yann Diorcet committed
852 853
	stats->received_rtcp = NULL;
	stats->sent_rtcp = NULL;
854
	stats->ice_state = LinphoneIceStateNotActivated;
Yann Diorcet's avatar
Yann Diorcet committed
855 856 857 858 859
#ifdef BUILD_UPNP
	stats->upnp_state = LinphoneUpnpStateIdle;
#else
	stats->upnp_state = LinphoneUpnpStateNotAvailable;
#endif //BUILD_UPNP