mediastream.c 17.7 KB
Newer Older
Ghislain MARY's avatar
Ghislain MARY committed
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 22
#include "ortp/ortp_srtp.h"
#include "ortp/b64.h"
Ghislain MARY's avatar
Ghislain MARY committed
23 24 25

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

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

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

Ghislain MARY's avatar
Ghislain MARY committed
37 38
#include <ctype.h>

39 40 41 42 43 44

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


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

Ghislain MARY's avatar
Ghislain MARY committed
51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72

#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
}

73 74 75 76 77 78 79 80
/**
 * 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.
 */
static void media_stream_change_decoder(MediaStream *stream, int payload) {
81
	RtpSession *session = stream->sessions.rtp_session;
82 83
	RtpProfile *prof = rtp_session_get_profile(session);
	PayloadType *pt = rtp_profile_get_payload(prof, payload);
84

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

90 91 92
	if (pt != NULL){
		MSFilter *dec;

93 94 95
		if (stream->type == VideoStreamType){
			/* Q: why only video ? this optimization seems relevant for audio too.*/
			if ((stream->decoder != NULL) && (stream->decoder->desc->enc_fmt != NULL)
96
			&& (strcasecmp(pt->mime_type, stream->decoder->desc->enc_fmt) == 0)) {
97 98 99
				/* Same formats behind different numbers, nothing to do. */
				return;
			}
100 101 102 103 104 105 106 107 108 109 110 111 112 113
		}

		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);
114
			ms_filter_preprocess(stream->decoder,stream->sessions.ticker);
115 116 117 118 119 120 121 122
		} else {
			ms_warning("No decoder found for %s", pt->mime_type);
		}
	} else {
		ms_warning("No payload defined with number %i", payload);
	}
}

Ghislain MARY's avatar
Ghislain MARY committed
123 124 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
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);
152
	rtp_session_set_recv_buf_size(rtpr, MAX(ms_get_mtu() , MS_MINIMAL_MTU));
Ghislain MARY's avatar
Ghislain MARY committed
153 154 155 156 157 158 159 160 161 162 163 164 165
	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);
	rtp_session_set_rtcp_report_interval(rtpr, 2500);	/* At the beginning of the session send more reports. */
	disable_checksums(rtp_session_get_rtp_socket(rtpr));
	return rtpr;
}

166
void media_stream_start_ticker(MediaStream *stream) {
Ghislain MARY's avatar
Ghislain MARY committed
167 168 169
	MSTickerParams params = {0};
	char name[16];

170
	if (stream->sessions.ticker) return;
Ghislain MARY's avatar
Ghislain MARY committed
171 172 173 174
	snprintf(name, sizeof(name) - 1, "%s MSTicker", media_stream_type_str(stream));
	name[0] = toupper(name[0]);
	params.name = name;
	params.prio = __ms_get_default_prio((stream->type == VideoStreamType) ? TRUE : FALSE);
175
	stream->sessions.ticker = ms_ticker_new_with_params(&params);
Ghislain MARY's avatar
Ghislain MARY committed
176 177
}

Ghislain MARY's avatar
Ghislain MARY committed
178
const char * media_stream_type_str(MediaStream *stream) {
Ghislain MARY's avatar
Ghislain MARY committed
179 180 181 182 183 184 185 186 187
	switch (stream->type) {
		default:
		case AudioStreamType:
			return "audio";
		case VideoStreamType:
			return "video";
	}
}

188 189
void ms_media_stream_sessions_uninit(MSMediaStreamSessions *sessions){
	if (sessions->srtp_session) {
190
		RtpTransport *rtptr=NULL,*rtcptr=NULL;
191
		ortp_srtp_dealloc(sessions->srtp_session);
192 193 194 195 196 197
		if (sessions->rtp_session){
			rtp_session_get_transports(sessions->rtp_session,&rtptr,&rtcptr);
			rtp_session_set_transports(sessions->rtp_session,NULL,NULL);
			if (rtptr) srtp_transport_destroy(rtptr);
			if (rtcptr) srtp_transport_destroy(rtcptr);
		}
198 199
		sessions->srtp_session=NULL;
	}
200 201 202 203
	if (sessions->rtp_session) {
		rtp_session_destroy(sessions->rtp_session);
		sessions->rtp_session=NULL;
	}
204 205 206 207 208 209 210 211 212 213
	if (sessions->zrtp_context != NULL) {
		ortp_zrtp_context_destroy(sessions->zrtp_context);
		sessions->zrtp_context = NULL;
	}
	if (sessions->ticker){
		ms_ticker_destroy(sessions->ticker);
		sessions->ticker=NULL;
	}
}

Ghislain MARY's avatar
Ghislain MARY committed
214
void media_stream_free(MediaStream *stream) {
215 216
	if (stream->sessions.rtp_session != NULL){
		rtp_session_unregister_event_queue(stream->sessions.rtp_session, stream->evq);
Ghislain MARY's avatar
Ghislain MARY committed
217
	}
218 219
	if (stream->owns_sessions){
		ms_media_stream_sessions_uninit(&stream->sessions);
Ghislain MARY's avatar
Ghislain MARY committed
220 221 222 223 224 225 226 227
	}
	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);
228
	if (stream->qi) ms_quality_indicator_destroy(stream->qi);
229

Ghislain MARY's avatar
Ghislain MARY committed
230 231 232
}

void media_stream_set_rtcp_information(MediaStream *stream, const char *cname, const char *tool) {
233 234
	if (stream->sessions.rtp_session != NULL) {
		rtp_session_set_source_description(stream->sessions.rtp_session, cname, NULL, NULL, NULL, NULL, tool, NULL);
Ghislain MARY's avatar
Ghislain MARY committed
235 236 237 238
	}
}

void media_stream_get_local_rtp_stats(MediaStream *stream, rtp_stats_t *lstats) {
239 240
	if (stream->sessions.rtp_session) {
		const rtp_stats_t *stats = rtp_session_get_stats(stream->sessions.rtp_session);
Ghislain MARY's avatar
Ghislain MARY committed
241 242 243 244 245 246
		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));
247
	return rtp_session_set_dscp(stream->sessions.rtp_session, dscp);
Ghislain MARY's avatar
Ghislain MARY committed
248 249 250 251 252 253 254
}

void media_stream_enable_adaptive_bitrate_control(MediaStream *stream, bool_t enabled) {
	stream->use_rc = enabled;
}

void media_stream_enable_adaptive_jittcomp(MediaStream *stream, bool_t enabled) {
255
	rtp_session_enable_adaptive_jitter_compensation(stream->sessions.rtp_session, enabled);
Ghislain MARY's avatar
Ghislain MARY committed
256 257
}

258 259 260 261 262 263 264
#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;
265

266 267 268 269 270 271 272 273
		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;
		srtp_transport_new(session,&rtp,&rtcp);
		rtp_session_set_transports(stream->sessions.rtp_session,rtp,rtcp);
jehan's avatar
jehan committed
274
		stream->sessions.is_secured=TRUE;
275 276 277
	}
	return 0;
}
Ghislain MARY's avatar
Ghislain MARY committed
278

jehan's avatar
jehan committed
279
static bool_t add_srtp_stream(srtp_t srtp, MSCryptoSuite suite, uint32_t ssrc, const char* b64_key, bool_t inbound)
280 281 282 283 284 285 286
{
	srtp_policy_t policy;
	uint8_t* key;
	int key_size;
	err_status_t err;
	unsigned b64_key_length = strlen(b64_key);
	ssrc_t ssrc_conf;
287

288
	memset(&policy,0,sizeof(policy));
289

290
	switch(suite){
jehan's avatar
jehan committed
291
		case MS_AES_128_SHA1_32:
292 293 294 295
			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
296
		case MS_AES_128_NO_AUTH:
297 298 299 300
			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
301
		case MS_NO_CIPHER_SHA1_80:
302 303 304
			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
305
		case MS_AES_128_SHA1_80: /*default mode*/
306 307 308
			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
309
		case MS_AES_256_SHA1_80:
310 311 312
			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
313
		case MS_AES_256_SHA1_32:
314 315 316
			crypto_policy_set_aes_cm_256_hmac_sha1_32(&policy.rtp);
			crypto_policy_set_aes_cm_256_hmac_sha1_32(&policy.rtcp);
			break;
Ghislain MARY's avatar
Ghislain MARY committed
317
	}
318 319 320 321 322 323 324 325 326 327 328 329
	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);
		return -1;
330
	}
331 332
	if (!inbound)
		policy.allow_repeat_tx=1; /*necessary for telephone-events*/
333

334 335 336
	/*ssrc_conf.type=inbound ? ssrc_any_inbound : ssrc_specific;*/
	ssrc_conf.type=ssrc_specific;
	ssrc_conf.value=ssrc;
337

338 339 340
	policy.ssrc = ssrc_conf;
	policy.key = key;
	policy.next = NULL;
341

342 343 344 345 346 347
	err = srtp_add_stream(srtp, &policy);
	if (err != err_status_ok) {
		ortp_error("Failed to add stream to srtp session (%d)", err);
		ortp_free(key);
		return -1;
	}
348

349 350 351
	ortp_free(key);
	return 0;
}
Ghislain MARY's avatar
Ghislain MARY committed
352

353 354 355 356 357 358 359 360 361
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
Ghislain MARY's avatar
Ghislain MARY committed
362

363 364 365 366 367 368 369
#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
370
	return _ORTP_HAVE_SRTP & ortp_srtp_supported();
371 372
}

jehan's avatar
jehan committed
373
int media_stream_set_srtp_recv_key(MediaStream *stream, MSCryptoSuite suite, const char* key){
374

jehan's avatar
jehan committed
375
	if (!media_stream_srtp_supported()) {
376 377 378 379 380 381 382
		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;
383

384 385 386 387 388 389
		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));
390

391 392 393 394 395 396 397 398 399 400 401 402
		/*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);
		return add_srtp_stream(stream->sessions.srtp_session,suite,ssrc,key,TRUE);
	}
#else
	return -1;
#endif
}

jehan's avatar
jehan committed
403
int media_stream_set_srtp_send_key(MediaStream *stream, MSCryptoSuite suite, const char* key){
404

jehan's avatar
jehan committed
405
	if (!media_stream_srtp_supported()) {
406 407 408
		ms_error("ortp srtp support disabled in oRTP or mediastreamer2");
		return -1;
	}
409

410 411 412 413
#ifdef ORTP_HAVE_SRTP
	{
		uint32_t ssrc;
		bool_t updated=FALSE;
414

415 416
		if (check_srtp_session_created(stream)==-1)
			return -1;
417

418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433
		/*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);
		return add_srtp_stream(stream->sessions.srtp_session,suite,ssrc,key,FALSE);
	}
#else
	return -1;
#endif
}

/*deprecated*/
jehan's avatar
jehan committed
434
bool_t media_stream_enable_srtp(MediaStream *stream, MSCryptoSuite suite, const char *snd_key, const char *rcv_key) {
435
	return media_stream_set_srtp_recv_key(stream,suite,rcv_key)==0 && media_stream_set_srtp_send_key(stream,suite,snd_key)==0;
Ghislain MARY's avatar
Ghislain MARY committed
436 437
}

438 439 440 441
const MSQualityIndicator *media_stream_get_quality_indicator(MediaStream *stream){
	return stream->qi;
}

Ghislain MARY's avatar
Ghislain MARY committed
442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458
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;
}
459

460
void mediastream_payload_type_changed(RtpSession *session, unsigned long data) {
461
	MediaStream *stream = (MediaStream *)data;
462
	int pt = rtp_session_get_recv_payload_type(stream->sessions.rtp_session);
463 464
	media_stream_change_decoder(stream, pt);
}
465 466 467

void media_stream_iterate(MediaStream *stream){
	time_t curtime=ms_time(NULL);
468

469
	if (stream->ice_check_list) ice_check_list_process(stream->ice_check_list,stream->sessions.rtp_session);
470
	/*we choose to update the quality indicator as much as possible, since local statistics can be computed realtime. */
Simon Morlat's avatar
Simon Morlat committed
471 472 473 474 475 476 477
	if (stream->state==MSStreamStarted){
		if (stream->is_beginning && (curtime-stream->start_time>15)){
			rtp_session_set_rtcp_report_interval(stream->sessions.rtp_session,5000);
			stream->is_beginning=FALSE;
		}
		if (stream->qi && curtime>stream->last_iterate_time) ms_quality_indicator_update_local(stream->qi);
	}
478
	stream->last_iterate_time=curtime;
jehan's avatar
jehan committed
479
	if (stream->evq){
jehan's avatar
jehan committed
480 481 482
		OrtpEvent *ev=NULL;

		while ((ev=ortp_ev_queue_get(stream->evq))!=NULL){
jehan's avatar
jehan committed
483 484
			OrtpEventType evt=ortp_event_get_type(ev);
			if (evt==ORTP_EVENT_RTCP_PACKET_RECEIVED){
jehan's avatar
jehan committed
485
				mblk_t *m=ortp_event_get_data(ev)->packet;
486
				ms_message("%s_stream_iterate[%p]: receiving [%p] RTCP %s%s",media_stream_type_str(stream),stream,m,(rtcp_is_SR(m)?"SR":""),(rtcp_is_RR(m)?"RR":""));
jehan's avatar
jehan committed
487
				stream->process_rtcp(stream,m);
jehan's avatar
jehan committed
488
			}else if (evt==ORTP_EVENT_RTCP_PACKET_EMITTED){
Simon Morlat's avatar
Simon Morlat committed
489
				ms_message("%s_stream_iterate[%p]: local statistics available\n\tLocal's current jitter buffer size:%f ms",
490
					media_stream_type_str(stream), stream, rtp_session_get_jitter_stats(stream->sessions.rtp_session)->jitter_buffer_size_ms);
jehan's avatar
jehan committed
491
			}else if ((evt==ORTP_EVENT_STUN_PACKET_RECEIVED)&&(stream->ice_check_list)){
492
				ice_handle_stun_packet(stream->ice_check_list,stream->sessions.rtp_session,ortp_event_get_data(ev));
jehan's avatar
jehan committed
493 494 495
			} else if (evt == ORTP_EVENT_ZRTP_ENCRYPTION_CHANGED) {
				OrtpEventData *evd=ortp_event_get_data(ev);
				stream->sessions.is_secured=evd->info.zrtp_stream_encrypted;
496
				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
497 498 499 500
			}
			ortp_event_destroy(ev);
		}
	}
501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516
}

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;
}

517 518 519 520 521 522 523 524 525 526 527 528 529 530
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
531 532 533 534 535 536 537 538
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;
}
539

540
float media_stream_get_up_bw(const MediaStream *stream) {
Simon Morlat's avatar
Simon Morlat committed
541
	return rtp_session_get_send_bandwidth(stream->sessions.rtp_session);
jehan's avatar
jehan committed
542 543
}

544
float media_stream_get_down_bw(const MediaStream *stream) {
Simon Morlat's avatar
Simon Morlat committed
545
	return rtp_session_get_recv_bandwidth(stream->sessions.rtp_session);
jehan's avatar
jehan committed
546
}
547 548 549 550 551

void media_stream_reclaim_sessions(MediaStream *stream, MSMediaStreamSessions *sessions){
	memcpy(sessions,&stream->sessions, sizeof(MSMediaStreamSessions));
	stream->owns_sessions=FALSE;
}
jehan's avatar
jehan committed
552 553 554 555 556 557
bool_t media_stream_is_secured (const MediaStream *stream) {
	return stream->sessions.is_secured;
}
MSStreamState media_stream_get_state(const MediaStream *stream) {
	return stream->state;
}