mediastream.c 22.2 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
/*
mediastreamer2 library - modular sound and video processing and streaming
Copyright (C) 2006-2013 Belledonne Communications, Grenoble

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
#include "ortp/port.h"
22 23 24
#include "ortp/ortp_srtp.h"
#include "ortp/b64.h"

25 26 27
#include "mediastreamer2/mediastream.h"
#include "private.h"

Simon Morlat's avatar
Simon Morlat committed
28
#ifdef ORTP_HAVE_SRTP
29
#if defined(ANDROID) || (defined(WIN32) && !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP))
Simon Morlat's avatar
Simon Morlat committed
30 31 32 33 34
// Android and Windows phone don't use make install
#include <srtp_priv.h>
#else
#include <srtp/srtp_priv.h>
#endif
35

Simon Morlat's avatar
Simon Morlat committed
36 37
#endif /*ORTP_HAVE_SRTP*/

38 39
#include <ctype.h>

40 41 42 43 44 45

#ifdef HAVE_CONFIG_H
#include "mediastreamer-config.h"
#endif


46 47 48
#ifndef MS_MINIMAL_MTU
/*this is used for determining the minimum size of recv buffers for RTP packets
 Keep 1500 for maximum interoparibility*/
49
#define MS_MINIMAL_MTU 1500
50 51
#endif

52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73

#if defined(_WIN32_WCE)
time_t
ms_time(time_t *t) {
	DWORD timemillis = GetTickCount();
	if (timemillis > 0) {
		if (t != NULL) *t = timemillis / 1000;
	}
	return timemillis / 1000;
}
#endif


static void disable_checksums(ortp_socket_t sock) {
#if defined(DISABLE_CHECKSUMS) && defined(SO_NO_CHECK)
	int option = 1;
	if (setsockopt(sock, SOL_SOCKET, SO_NO_CHECK, &option, sizeof(option)) == -1) {
		ms_warning("Could not disable udp checksum: %s", strerror(errno));
	}
#endif
}

74 75 76 77 78 79
/**
 * This function must be called from the MSTicker thread:
 * it replaces one filter by another one.
 * This is a dirty hack that works anyway.
 * It would be interesting to have something that does the job
 * more easily within the MSTicker API.
80
 * return TRUE if the decoder was changed, FALSE otherwise.
81
 */
82
static bool_t media_stream_change_decoder(MediaStream *stream, int payload) {
83
	RtpSession *session = stream->sessions.rtp_session;
84 85
	RtpProfile *prof = rtp_session_get_profile(session);
	PayloadType *pt = rtp_profile_get_payload(prof, payload);
86

87 88
	if (stream->decoder == NULL){
		ms_message("media_stream_change_decoder(): ignored, no decoder.");
89
		return FALSE;
90
	}
91

92 93 94
	if (pt != NULL){
		MSFilter *dec;

Simon Morlat's avatar
Simon Morlat committed
95
		if (stream->type == MSVideo){
96
			/* Q: why only video ? A: because an audio format can be used at different rates: ex: speex/16000 speex/8000*/
97
			if ((stream->decoder != NULL) && (stream->decoder->desc->enc_fmt != NULL)
98
			&& (strcasecmp(pt->mime_type, stream->decoder->desc->enc_fmt) == 0)) {
99
				/* Same formats behind different numbers, nothing to do. */
100
				return FALSE;
101
			}
102 103 104 105 106 107 108 109 110 111 112 113 114 115
		}

		dec = ms_filter_create_decoder(pt->mime_type);
		if (dec != NULL) {
			MSFilter *nextFilter = stream->decoder->outputs[0]->next.filter;
			ms_filter_unlink(stream->rtprecv, 0, stream->decoder, 0);
			ms_filter_unlink(stream->decoder, 0, nextFilter, 0);
			ms_filter_postprocess(stream->decoder);
			ms_filter_destroy(stream->decoder);
			stream->decoder = dec;
			if (pt->recv_fmtp != NULL)
				ms_filter_call_method(stream->decoder, MS_FILTER_ADD_FMTP, (void *)pt->recv_fmtp);
			ms_filter_link(stream->rtprecv, 0, stream->decoder, 0);
			ms_filter_link(stream->decoder, 0, nextFilter, 0);
116
			ms_filter_preprocess(stream->decoder,stream->sessions.ticker);
117
			return TRUE;
118 119 120 121 122 123
		} else {
			ms_warning("No decoder found for %s", pt->mime_type);
		}
	} else {
		ms_warning("No payload defined with number %i", payload);
	}
124
	return FALSE;
125 126
}

127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155
MSTickerPrio __ms_get_default_prio(bool_t is_video) {
	const char *penv;

	if (is_video) {
#ifdef __ios
		return MS_TICKER_PRIO_HIGH;
#else
		return MS_TICKER_PRIO_NORMAL;
#endif
	}

	penv = getenv("MS_AUDIO_PRIO");
	if (penv) {
		if (strcasecmp(penv, "NORMAL") == 0) return MS_TICKER_PRIO_NORMAL;
		if (strcasecmp(penv, "HIGH") == 0) return MS_TICKER_PRIO_HIGH;
		if (strcasecmp(penv, "REALTIME") == 0) return MS_TICKER_PRIO_REALTIME;
		ms_error("Undefined priority %s", penv);
	}
#ifdef __linux
	return MS_TICKER_PRIO_REALTIME;
#else
	return MS_TICKER_PRIO_HIGH;
#endif
}

RtpSession * create_duplex_rtpsession(int loc_rtp_port, int loc_rtcp_port, bool_t ipv6) {
	RtpSession *rtpr;

	rtpr = rtp_session_new(RTP_SESSION_SENDRECV);
156
	rtp_session_set_recv_buf_size(rtpr, MAX(ms_get_mtu() , MS_MINIMAL_MTU));
157 158 159 160 161 162 163 164
	rtp_session_set_scheduling_mode(rtpr, 0);
	rtp_session_set_blocking_mode(rtpr, 0);
	rtp_session_enable_adaptive_jitter_compensation(rtpr, TRUE);
	rtp_session_set_symmetric_rtp(rtpr, TRUE);
	rtp_session_set_local_addr(rtpr, ipv6 ? "::" : "0.0.0.0", loc_rtp_port, loc_rtcp_port);
	rtp_session_signal_connect(rtpr, "timestamp_jump", (RtpCallback)rtp_session_resync, (long)NULL);
	rtp_session_signal_connect(rtpr, "ssrc_changed", (RtpCallback)rtp_session_resync, (long)NULL);
	rtp_session_set_ssrc_changed_threshold(rtpr, 0);
165
	rtp_session_set_rtcp_report_interval(rtpr, 2500);	/* At the beginning of the session send more reports. */
166 167 168 169
	disable_checksums(rtp_session_get_rtp_socket(rtpr));
	return rtpr;
}

170
void media_stream_start_ticker(MediaStream *stream) {
171
	MSTickerParams params = {0};
172
	char name[32] = {0};
173

174
	if (stream->sessions.ticker) return;
175 176 177
	snprintf(name, sizeof(name) - 1, "%s MSTicker", media_stream_type_str(stream));
	name[0] = toupper(name[0]);
	params.name = name;
Simon Morlat's avatar
Simon Morlat committed
178
	params.prio = __ms_get_default_prio((stream->type == MSVideo) ? TRUE : FALSE);
179
	stream->sessions.ticker = ms_ticker_new_with_params(&params);
180 181
}

Ghislain MARY's avatar
Ghislain MARY committed
182
const char * media_stream_type_str(MediaStream *stream) {
Simon Morlat's avatar
Simon Morlat committed
183
	return ms_format_type_to_string(stream->type);
184 185
}

186 187 188 189 190
void ms_media_stream_sessions_uninit(MSMediaStreamSessions *sessions){
	if (sessions->srtp_session) {
		ortp_srtp_dealloc(sessions->srtp_session);
		sessions->srtp_session=NULL;
	}
191 192 193 194
	if (sessions->rtp_session) {
		rtp_session_destroy(sessions->rtp_session);
		sessions->rtp_session=NULL;
	}
195
	if (sessions->zrtp_context != NULL) {
196
		ms_zrtp_context_destroy(sessions->zrtp_context);
197 198 199 200 201 202 203 204
		sessions->zrtp_context = NULL;
	}
	if (sessions->ticker){
		ms_ticker_destroy(sessions->ticker);
		sessions->ticker=NULL;
	}
}

205
void media_stream_free(MediaStream *stream) {
206 207
	if (stream->sessions.rtp_session != NULL){
		rtp_session_unregister_event_queue(stream->sessions.rtp_session, stream->evq);
208
	}
209 210
	if (stream->owns_sessions){
		ms_media_stream_sessions_uninit(&stream->sessions);
211 212 213 214 215 216 217 218
	}
	if (stream->evq) ortp_ev_queue_destroy(stream->evq);
	if (stream->rc != NULL) ms_bitrate_controller_destroy(stream->rc);
	if (stream->rtpsend != NULL) ms_filter_destroy(stream->rtpsend);
	if (stream->rtprecv != NULL) ms_filter_destroy(stream->rtprecv);
	if (stream->encoder != NULL) ms_filter_destroy(stream->encoder);
	if (stream->decoder != NULL) ms_filter_destroy(stream->decoder);
	if (stream->voidsink != NULL) ms_filter_destroy(stream->voidsink);
219
	if (stream->qi) ms_quality_indicator_destroy(stream->qi);
220

221 222 223
}

void media_stream_set_rtcp_information(MediaStream *stream, const char *cname, const char *tool) {
224 225
	if (stream->sessions.rtp_session != NULL) {
		rtp_session_set_source_description(stream->sessions.rtp_session, cname, NULL, NULL, NULL, NULL, tool, NULL);
226 227 228 229
	}
}

void media_stream_get_local_rtp_stats(MediaStream *stream, rtp_stats_t *lstats) {
230 231
	if (stream->sessions.rtp_session) {
		const rtp_stats_t *stats = rtp_session_get_stats(stream->sessions.rtp_session);
232 233 234 235 236 237
		memcpy(lstats, stats, sizeof(*stats));
	} else memset(lstats, 0, sizeof(rtp_stats_t));
}

int media_stream_set_dscp(MediaStream *stream, int dscp) {
	ms_message("Setting DSCP to %i for %s stream.", dscp, media_stream_type_str(stream));
238
	return rtp_session_set_dscp(stream->sessions.rtp_session, dscp);
239 240 241
}

void media_stream_enable_adaptive_bitrate_control(MediaStream *stream, bool_t enabled) {
242 243 244 245 246
	stream->rc_enable = enabled;
}

void media_stream_set_adaptive_bitrate_algorithm(MediaStream *stream, MSQosAnalyzerAlgorithm algorithm) {
	stream->rc_algorithm = algorithm;
247 248 249
}

void media_stream_enable_adaptive_jittcomp(MediaStream *stream, bool_t enabled) {
250
	rtp_session_enable_adaptive_jitter_compensation(stream->sessions.rtp_session, enabled);
251 252
}

253 254 255 256 257 258 259
#ifdef ORTP_HAVE_SRTP

static int check_srtp_session_created(MediaStream *stream){
	if (stream->sessions.srtp_session==NULL){
		err_status_t err;
		srtp_t session;
		RtpTransport *rtp=NULL,*rtcp=NULL;
260
		RtpTransportModifier *rtp_modifier, *rtcp_modifier;
261

262 263 264 265 266 267
		err = ortp_srtp_create(&session, NULL);
		if (err != 0) {
			ms_error("Failed to create srtp session (%d)", err);
			return -1;
		}
		stream->sessions.srtp_session=session;
268 269 270 271 272 273 274 275 276
		srtp_transport_modifier_new(session,&rtp_modifier,&rtcp_modifier);
		rtp_session_get_transports(stream->sessions.rtp_session,&rtp,&rtcp);
		/*if transports are set, we assume they are meta transporters, otherwise create them*/
		if (rtp==NULL&&rtcp==NULL){
			meta_rtp_transport_new(&rtp, TRUE, NULL, 0);
			meta_rtp_transport_new(&rtcp, FALSE, NULL, 0);
		}
		meta_rtp_transport_append_modifier(rtp, rtp_modifier);
		meta_rtp_transport_append_modifier(rtcp, rtcp_modifier);
277
		rtp_session_set_transports(stream->sessions.rtp_session,rtp,rtcp);
jehan's avatar
jehan committed
278
		stream->sessions.is_secured=TRUE;
279 280 281
	}
	return 0;
}
282

283
static int add_srtp_stream(srtp_t srtp, MSCryptoSuite suite, uint32_t ssrc, const char* b64_key, bool_t keyisb64, bool_t inbound)
284 285 286 287 288
{
	srtp_policy_t policy;
	uint8_t* key;
	int key_size;
	err_status_t err;
289
	unsigned b64_key_length;
290
	ssrc_t ssrc_conf;
291

292
	memset(&policy,0,sizeof(policy));
293

294
	switch(suite){
jehan's avatar
jehan committed
295
		case MS_AES_128_SHA1_32:
296 297 298 299
			crypto_policy_set_aes_cm_128_hmac_sha1_32(&policy.rtp);
			// srtp doc says: not adapted to rtcp...
			crypto_policy_set_aes_cm_128_hmac_sha1_32(&policy.rtcp);
			break;
jehan's avatar
jehan committed
300
		case MS_AES_128_NO_AUTH:
301 302 303 304
			crypto_policy_set_aes_cm_128_null_auth(&policy.rtp);
			// srtp doc says: not adapted to rtcp...
			crypto_policy_set_aes_cm_128_null_auth(&policy.rtcp);
			break;
jehan's avatar
jehan committed
305
		case MS_NO_CIPHER_SHA1_80:
306 307 308
			crypto_policy_set_null_cipher_hmac_sha1_80(&policy.rtp);
			crypto_policy_set_null_cipher_hmac_sha1_80(&policy.rtcp);
			break;
jehan's avatar
jehan committed
309
		case MS_AES_128_SHA1_80: /*default mode*/
310 311 312
			crypto_policy_set_aes_cm_128_hmac_sha1_80(&policy.rtp);
			crypto_policy_set_aes_cm_128_hmac_sha1_80(&policy.rtcp);
			break;
jehan's avatar
jehan committed
313
		case MS_AES_256_SHA1_80:
314 315 316
			crypto_policy_set_aes_cm_256_hmac_sha1_80(&policy.rtp);
			crypto_policy_set_aes_cm_256_hmac_sha1_80(&policy.rtcp);
			break;
jehan's avatar
jehan committed
317
		case MS_AES_256_SHA1_32:
318 319 320
			crypto_policy_set_aes_cm_256_hmac_sha1_32(&policy.rtp);
			crypto_policy_set_aes_cm_256_hmac_sha1_32(&policy.rtcp);
			break;
321 322 323
		case MS_CRYPTO_SUITE_INVALID:
			return -1;
			break;
324
	}
325 326 327 328 329 330 331 332 333 334 335 336 337 338

	if (keyisb64==TRUE) {
		b64_key_length = strlen(b64_key);
		key_size = b64_decode(b64_key, b64_key_length, 0, 0);
		if (key_size != policy.rtp.cipher_key_len) {
			ortp_error("Key size (%d) doesn't match the selected srtp profile (required %d)",
				key_size,
				policy.rtp.cipher_key_len);
				return -1;
		}
		key = (uint8_t*) ortp_malloc0(key_size+2); /*srtp uses padding*/
		if (b64_decode(b64_key, b64_key_length, key, key_size) != key_size) {
			ortp_error("Error decoding key");
			ortp_free(key);
339
			return -1;
340 341 342
		}
	} else {
		key=(uint8_t *)b64_key;
343
	}
344 345
	if (!inbound)
		policy.allow_repeat_tx=1; /*necessary for telephone-events*/
346

347 348 349
	/*ssrc_conf.type=inbound ? ssrc_any_inbound : ssrc_specific;*/
	ssrc_conf.type=ssrc_specific;
	ssrc_conf.value=ssrc;
350

351 352 353
	policy.ssrc = ssrc_conf;
	policy.key = key;
	policy.next = NULL;
354

355 356 357
	err = srtp_add_stream(srtp, &policy);
	if (err != err_status_ok) {
		ortp_error("Failed to add stream to srtp session (%d)", err);
358 359 360
		if (keyisb64==TRUE) {
			ortp_free(key);
		}
361 362
		return -1;
	}
363

364 365 366
	if (keyisb64==TRUE) {
		ortp_free(key);
	}
367 368
	return 0;
}
369

370 371 372 373 374 375 376 377 378
static uint32_t find_other_ssrc(srtp_t srtp, uint32_t ssrc){
	srtp_stream_ctx_t *stream;
	for (stream=srtp->stream_list;stream!=NULL;stream=stream->next){
		if (stream->ssrc!=ssrc) return stream->ssrc;
	}
	return 0;
}

#endif
379

380 381 382 383 384 385 386
#ifdef ORTP_HAVE_SRTP
#define _ORTP_HAVE_SRTP 1
#else
#define _ORTP_HAVE_SRTP 0
#endif

bool_t media_stream_srtp_supported(void){
jehan's avatar
jehan committed
387
	return _ORTP_HAVE_SRTP & ortp_srtp_supported();
388 389
}

390
int media_stream_set_srtp_recv_key(MediaStream *stream, MSCryptoSuite suite, const char* key, bool_t keyisb64){
391

jehan's avatar
jehan committed
392
	if (!media_stream_srtp_supported()) {
393 394 395 396 397 398 399
		ms_error("ortp srtp support disabled in oRTP or mediastreamer2");
		return -1;
	}
#ifdef ORTP_HAVE_SRTP
	{
		uint32_t ssrc,send_ssrc;
		bool_t updated=FALSE;
400

401 402 403 404 405 406
		if (check_srtp_session_created(stream)==-1)
			return -1;

		/*check if a previous key was configured, in which case remove it*/
		send_ssrc=rtp_session_get_send_ssrc(stream->sessions.rtp_session);
		ssrc=find_other_ssrc(stream->sessions.srtp_session,htonl(send_ssrc));
407

408 409 410 411 412
		/*careful: remove_stream takes the SSRC in network byte order...*/
		if (ortp_srtp_remove_stream(stream->sessions.srtp_session,ssrc)==0)
			updated=TRUE;
		ssrc=rtp_session_get_recv_ssrc(stream->sessions.rtp_session);
		ms_message("media_stream_set_srtp_recv_key(): %s key %s",updated ? "changing to" : "starting with", key);
413
		return add_srtp_stream(stream->sessions.srtp_session,suite,ssrc,key,keyisb64,TRUE);
414 415 416 417 418 419
	}
#else
	return -1;
#endif
}

420
int media_stream_set_srtp_send_key(MediaStream *stream, MSCryptoSuite suite, const char* key, bool_t keyisb64){
421

jehan's avatar
jehan committed
422
	if (!media_stream_srtp_supported()) {
423 424 425
		ms_error("ortp srtp support disabled in oRTP or mediastreamer2");
		return -1;
	}
426

427 428 429 430
#ifdef ORTP_HAVE_SRTP
	{
		uint32_t ssrc;
		bool_t updated=FALSE;
431

432 433
		if (check_srtp_session_created(stream)==-1)
			return -1;
434

435 436 437 438 439 440 441 442
		/*check if a previous key was configured, in which case remove it*/
		ssrc=rtp_session_get_send_ssrc(stream->sessions.rtp_session);
		if (ssrc!=0){
			/*careful: remove_stream takes the SSRC in network byte order...*/
			if (ortp_srtp_remove_stream(stream->sessions.srtp_session,htonl(ssrc))==0)
				updated=TRUE;
		}
		ms_message("media_stream_set_srtp_send_key(): %s key %s",updated ? "changing to" : "starting with", key);
443
		return add_srtp_stream(stream->sessions.srtp_session,suite,ssrc,key,keyisb64,FALSE);
444 445 446 447 448 449 450
	}
#else
	return -1;
#endif
}

/*deprecated*/
jehan's avatar
jehan committed
451
bool_t media_stream_enable_srtp(MediaStream *stream, MSCryptoSuite suite, const char *snd_key, const char *rcv_key) {
452
	return media_stream_set_srtp_recv_key(stream,suite,rcv_key,TRUE)==0 && media_stream_set_srtp_send_key(stream,suite,snd_key,TRUE)==0;
453 454
}

455 456 457 458
const MSQualityIndicator *media_stream_get_quality_indicator(MediaStream *stream){
	return stream->qi;
}

459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475
bool_t ms_is_ipv6(const char *remote) {
	bool_t ret = FALSE;
	struct addrinfo hints, *res0;
	int err;

	memset(&hints, 0, sizeof(hints));
	hints.ai_family = PF_UNSPEC;
	hints.ai_socktype = SOCK_DGRAM;
	err = getaddrinfo(remote,"8000", &hints, &res0);
	if (err != 0) {
		ms_warning("get_local_addr_for: %s", gai_strerror(err));
		return FALSE;
	}
	ret = (res0->ai_addr->sa_family == AF_INET6);
	freeaddrinfo(res0);
	return ret;
}
476

477
bool_t mediastream_payload_type_changed(RtpSession *session, unsigned long data) {
478
	MediaStream *stream = (MediaStream *)data;
479
	int pt = rtp_session_get_recv_payload_type(stream->sessions.rtp_session);
480
	return media_stream_change_decoder(stream, pt);
481
}
482

483 484 485 486
static void media_stream_process_rtcp(MediaStream *stream, mblk_t *m, time_t curtime){
	stream->last_packet_time=curtime;
	ms_message("%s stream [%p]: receiving RTCP %s%s",media_stream_type_str(stream),stream,(rtcp_is_SR(m)?"SR":""),(rtcp_is_RR(m)?"RR":""));
	do{
487
		if (stream->rc_enable&&stream->rc) ms_bitrate_controller_process_rtcp(stream->rc,m);
488
		if (stream->qi) ms_quality_indicator_update_from_feedback(stream->qi,m);
489 490
		stream->process_rtcp(stream,m);
	}while(rtcp_next_packet(m));
491

492 493
}

494 495
void media_stream_iterate(MediaStream *stream){
	time_t curtime=ms_time(NULL);
496

497
	if (stream->ice_check_list) ice_check_list_process(stream->ice_check_list,stream->sessions.rtp_session);
498
	/*we choose to update the quality indicator as much as possible, since local statistics can be computed realtime. */
499
	if (stream->state==MSStreamStarted){
500 501 502 503
		if (stream->is_beginning && (curtime-stream->start_time>15)){
			rtp_session_set_rtcp_report_interval(stream->sessions.rtp_session,5000);
			stream->is_beginning=FALSE;
		}
504 505
		if (stream->qi && curtime>stream->last_iterate_time) ms_quality_indicator_update_local(stream->qi);
	}
506
	stream->last_iterate_time=curtime;
507 508 509

	if (stream->rc) ms_bitrate_controller_update(stream->rc);

jehan's avatar
jehan committed
510
	if (stream->evq){
jehan's avatar
jehan committed
511 512 513
		OrtpEvent *ev=NULL;

		while ((ev=ortp_ev_queue_get(stream->evq))!=NULL){
jehan's avatar
jehan committed
514 515
			OrtpEventType evt=ortp_event_get_type(ev);
			if (evt==ORTP_EVENT_RTCP_PACKET_RECEIVED){
jehan's avatar
jehan committed
516
				mblk_t *m=ortp_event_get_data(ev)->packet;
517
				media_stream_process_rtcp(stream,m,curtime);
jehan's avatar
jehan committed
518
			}else if (evt==ORTP_EVENT_RTCP_PACKET_EMITTED){
Simon Morlat's avatar
Simon Morlat committed
519
				ms_message("%s_stream_iterate[%p]: local statistics available\n\tLocal's current jitter buffer size:%f ms",
520
					media_stream_type_str(stream), stream, rtp_session_get_jitter_stats(stream->sessions.rtp_session)->jitter_buffer_size_ms);
jehan's avatar
jehan committed
521
			}else if ((evt==ORTP_EVENT_STUN_PACKET_RECEIVED)&&(stream->ice_check_list)){
522
				ice_handle_stun_packet(stream->ice_check_list,stream->sessions.rtp_session,ortp_event_get_data(ev));
jehan's avatar
jehan committed
523 524 525
			} else if (evt == ORTP_EVENT_ZRTP_ENCRYPTION_CHANGED) {
				OrtpEventData *evd=ortp_event_get_data(ev);
				stream->sessions.is_secured=evd->info.zrtp_stream_encrypted;
526
				ms_message("%s_stream_iterate[%p]: is %s ",media_stream_type_str(stream) , stream, stream->sessions.is_secured ? "encrypted" : "not encrypted");
jehan's avatar
jehan committed
527 528 529 530
			}
			ortp_event_destroy(ev);
		}
	}
531 532
}

533
bool_t media_stream_alive(MediaStream *ms, int timeout){
534 535 536 537 538 539
	const rtp_stats_t *stats;
	
	if (ms->state!=MSStreamStarted){
		return TRUE;
	}
	stats=rtp_session_get_stats(ms->sessions.rtp_session);
540 541 542 543 544 545 546 547 548 549 550 551 552
	if (stats->recv!=0){
		if (stats->recv!=ms->last_packet_count){
			ms->last_packet_count=stats->recv;
			ms->last_packet_time=ms_time(NULL);
		}
	}
	if (ms_time(NULL)-ms->last_packet_time>timeout){
		/* more than timeout seconds of inactivity*/
		return FALSE;
	}
	return TRUE;
}

553 554 555 556 557 558 559 560 561 562 563 564 565 566
float media_stream_get_quality_rating(MediaStream *stream){
	if (stream->qi){
		return ms_quality_indicator_get_rating(stream->qi);
	}
	return -1;
}

float media_stream_get_average_quality_rating(MediaStream *stream){
	if (stream->qi){
		return ms_quality_indicator_get_average_rating(stream->qi);
	}
	return -1;
}

567 568 569 570 571 572 573 574 575 576 577 578 579 580
float media_stream_get_lq_quality_rating(MediaStream *stream) {
	if (stream->qi) {
		return ms_quality_indicator_get_lq_rating(stream->qi);
	}
	return -1;
}

float media_stream_get_average_lq_quality_rating(MediaStream *stream) {
	if (stream->qi) {
		return ms_quality_indicator_get_average_lq_rating(stream->qi);
	}
	return -1;
}

jehan's avatar
jehan committed
581 582 583 584 585 586 587 588
int media_stream_set_target_network_bitrate(MediaStream *stream,int target_bitrate) {
	stream->target_bitrate=target_bitrate;
	return 0;
}

int media_stream_get_target_network_bitrate(const MediaStream *stream) {
	return stream->target_bitrate;
}
589

590
float media_stream_get_up_bw(const MediaStream *stream) {
591
	return rtp_session_get_send_bandwidth(stream->sessions.rtp_session);
jehan's avatar
jehan committed
592 593
}

594
float media_stream_get_down_bw(const MediaStream *stream) {
595
	return rtp_session_get_recv_bandwidth(stream->sessions.rtp_session);
jehan's avatar
jehan committed
596
}
597 598 599 600 601

void media_stream_reclaim_sessions(MediaStream *stream, MSMediaStreamSessions *sessions){
	memcpy(sessions,&stream->sessions, sizeof(MSMediaStreamSessions));
	stream->owns_sessions=FALSE;
}
602 603

bool_t media_stream_secured (const MediaStream *stream) {
jehan's avatar
jehan committed
604 605
	return stream->sessions.is_secured;
}
606 607 608 609 610

bool_t media_stream_avpf_enabled(const MediaStream *stream) {
	return rtp_session_avpf_enabled(stream->sessions.rtp_session);
}

611
uint16_t media_stream_get_avpf_rr_interval(const MediaStream *stream) {
612 613 614
	return rtp_session_get_avpf_rr_interval(stream->sessions.rtp_session);
}

jehan's avatar
jehan committed
615 616 617
MSStreamState media_stream_get_state(const MediaStream *stream) {
	return stream->state;
}
618

619 620 621 622
RtpSession * media_stream_get_rtp_session(const MediaStream *stream) {
	return stream->sessions.rtp_session;
}

623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663
#define keywordcmp(key,b) strncmp(key,b,sizeof(key))

/* see  http://www.iana.org/assignments/sdp-security-descriptions/sdp-security-descriptions.xhtml#sdp-security-descriptions-3 */



MSCryptoSuite ms_crypto_suite_build_from_name_params(const MSCryptoSuiteNameParams *descrption){
	const char *name=descrption->name, *parameters=descrption->params;
	if (keywordcmp ( "AES_CM_128_HMAC_SHA1_80",name ) == 0 ){
		if (parameters && strstr(parameters,"UNENCRYPTED_SRTP")) return MS_NO_CIPHER_SHA1_80;
		else if (parameters && strstr(parameters,"UNAUTHENTICATED_SRTP")) return MS_AES_128_NO_AUTH;
		else return MS_AES_128_SHA1_80;
	}else if ( keywordcmp ( "AES_CM_128_HMAC_SHA1_32",name ) == 0 ){
		if (parameters && strstr(parameters,"UNENCRYPTED_SRTP")) goto error;
		if (parameters && strstr(parameters,"UNAUTHENTICATED_SRTP")) return MS_AES_128_NO_AUTH;
		else return MS_AES_128_SHA1_32;
	}else if ( keywordcmp ( "AES_CM_256_HMAC_SHA1_32",name ) == 0 ){
		if (parameters && strstr(parameters,"UNENCRYPTED_SRTP")) goto error;
		if (parameters && strstr(parameters,"UNAUTHENTICATED_SRTP")) goto error;
		return MS_AES_256_SHA1_32;
	}else if ( keywordcmp ( "AES_CM_256_HMAC_SHA1_80",name ) == 0 ){
		if (parameters && strstr(parameters,"UNENCRYPTED_SRTP")) goto error;
		if (parameters && strstr(parameters,"UNAUTHENTICATED_SRTP")) goto error;
		return MS_AES_256_SHA1_80;
	}
error:
	ms_error("Unsupported crypto suite '%s' with parameters '%s'",name, parameters ? parameters : "");
	return MS_CRYPTO_SUITE_INVALID;
}

int ms_crypto_suite_to_name_params(MSCryptoSuite cs, MSCryptoSuiteNameParams *params ){
	params->name=NULL;
	params->params=NULL;
	switch(cs){
		case MS_CRYPTO_SUITE_INVALID:
			break;
		case MS_AES_128_SHA1_80:
			params->name= "AES_CM_128_HMAC_SHA1_80";
			break;
		case MS_AES_128_SHA1_32:
			params->name="AES_CM_128_HMAC_SHA1_32";
664
			break;
665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682
		case MS_AES_128_NO_AUTH:
			params->name="AES_CM_128_HMAC_SHA1_80";
			params->params="UNAUTHENTICATED_SRTP";
			break;
		case MS_NO_CIPHER_SHA1_80:
			params->name="AES_CM_128_HMAC_SHA1_80";
			params->params="UNENCRYPTED_SRTP UNENCRYPTED_SRTCP";
			break;
		case MS_AES_256_SHA1_80:
			params->name="AES_CM_256_HMAC_SHA1_80";
			break;
		case MS_AES_256_SHA1_32:
			params->name="AES_CM_256_HMAC_SHA1_32";
			break;
	}
	if (params->name==NULL) return -1;
	return 0;
}
Simon Morlat's avatar
Simon Morlat committed
683

684 685 686 687 688 689 690
/*stubs*/
#ifndef VIDEO_ENABLED
void video_stream_open_player(VideoStream *stream, MSFilter *sink){
}

void video_stream_close_player(VideoStream *stream){
}
Simon Morlat's avatar
Simon Morlat committed
691 692 693 694

const char *video_stream_get_default_video_renderer(void){
	return NULL;
}
695
#endif
696