mediastream.c 19.1 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.
*/


jehan's avatar
jehan committed
21 22 23
#ifdef HAVE_CONFIG_H
#include "mediastreamer-config.h"
#endif
24

jehan's avatar
jehan committed
25
#include "ortp/port.h"
Ghislain MARY's avatar
Ghislain MARY committed
26 27
#include "mediastreamer2/mediastream.h"
#include "private.h"
Ghislain MARY's avatar
Ghislain MARY committed
28 29
#include <ctype.h>

30 31


32 33 34
#ifndef MS_MINIMAL_MTU
/*this is used for determining the minimum size of recv buffers for RTP packets
 Keep 1500 for maximum interoparibility*/
35
#define MS_MINIMAL_MTU 1500
36 37
#endif

Ghislain MARY's avatar
Ghislain MARY committed
38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59

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

60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76
static int _ms_ticker_prio_from_env(const char *penv, MSTickerPrio *prio) {
	if (strcasecmp(penv, "NORMAL") == 0) {
		*prio = MS_TICKER_PRIO_NORMAL;
		return 0;
	}
	if (strcasecmp(penv, "HIGH") == 0) {
		*prio = MS_TICKER_PRIO_HIGH;
		return 0;
	}
	if (strcasecmp(penv, "REALTIME") == 0) {
		*prio = MS_TICKER_PRIO_REALTIME;
		return 0;
	}
	ms_error("Undefined priority %s", penv);
	return -1;
}

Ghislain MARY's avatar
Ghislain MARY committed
77
MSTickerPrio __ms_get_default_prio(bool_t is_video) {
78
	const char *penv = NULL;
79
	MSTickerPrio prio;
Ghislain MARY's avatar
Ghislain MARY committed
80 81

	if (is_video) {
82
#ifndef MS2_WINDOWS_UNIVERSAL
83
		penv = getenv("MS_VIDEO_PRIO");
84
#endif
85
		if(penv && _ms_ticker_prio_from_env(penv, &prio) == 0) return prio;
86

Ghislain MARY's avatar
Ghislain MARY committed
87 88 89 90 91
#ifdef __ios
		return MS_TICKER_PRIO_HIGH;
#else
		return MS_TICKER_PRIO_NORMAL;
#endif
92
	} else {
93
#ifndef MS2_WINDOWS_UNIVERSAL
94
		penv = getenv("MS_AUDIO_PRIO");
95
#endif
96
		if (penv && _ms_ticker_prio_from_env(penv, &prio) == 0) return prio;
97

98
		return MS_TICKER_PRIO_HIGH;
99

100
	}
Ghislain MARY's avatar
Ghislain MARY committed
101 102
}

103
void media_stream_init(MediaStream *stream, MSFactory *factory) {
104 105
	stream->evd = ortp_ev_dispatcher_new(stream->sessions.rtp_session);
	stream->evq = ortp_ev_queue_new();
106
	stream->factory = factory; /*the factory is used later to instanciate everything in mediastreamer2.*/
107 108 109
	rtp_session_register_event_queue(stream->sessions.rtp_session, stream->evq);
}

110
RtpSession * ms_create_duplex_rtp_session(const char* local_ip, int loc_rtp_port, int loc_rtcp_port) {
Ghislain MARY's avatar
Ghislain MARY committed
111 112 113
	RtpSession *rtpr;

	rtpr = rtp_session_new(RTP_SESSION_SENDRECV);
114
	rtp_session_set_recv_buf_size(rtpr, MAX(ms_get_mtu() , MS_MINIMAL_MTU));
Ghislain MARY's avatar
Ghislain MARY committed
115 116 117 118
	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);
jehan's avatar
jehan committed
119
	rtp_session_set_local_addr(rtpr, local_ip, loc_rtp_port, loc_rtcp_port);
Ghislain MARY's avatar
Ghislain MARY committed
120 121
	rtp_session_signal_connect(rtpr, "timestamp_jump", (RtpCallback)rtp_session_resync, NULL);
	rtp_session_signal_connect(rtpr, "ssrc_changed", (RtpCallback)rtp_session_resync, NULL);
Ghislain MARY's avatar
Ghislain MARY committed
122
	rtp_session_set_ssrc_changed_threshold(rtpr, 0);
123
	rtp_session_set_rtcp_report_interval(rtpr, 2500);	/* At the beginning of the session send more reports. */
jehan's avatar
jehan committed
124
	rtp_session_set_multicast_loopback(rtpr,TRUE); /*very useful, specially for testing purposes*/
Ghislain MARY's avatar
Ghislain MARY committed
125 126 127 128
	disable_checksums(rtp_session_get_rtp_socket(rtpr));
	return rtpr;
}

129 130 131 132
int media_stream_join_multicast_group(MediaStream *stream, const char *ip){
	return rtp_session_join_multicast_group(stream->sessions.rtp_session,ip);
}

133
void media_stream_start_ticker(MediaStream *stream) {
Ghislain MARY's avatar
Ghislain MARY committed
134
	MSTickerParams params = {0};
135
	char name[32] = {0};
Ghislain MARY's avatar
Ghislain MARY committed
136

137
	if (stream->sessions.ticker) return;
Ghislain MARY's avatar
Ghislain MARY committed
138 139 140
	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
141
	params.prio = __ms_get_default_prio((stream->type == MSVideo) ? TRUE : FALSE);
142
	stream->sessions.ticker = ms_ticker_new_with_params(&params);
Ghislain MARY's avatar
Ghislain MARY committed
143 144
}

Ghislain MARY's avatar
Ghislain MARY committed
145
const char * media_stream_type_str(MediaStream *stream) {
Simon Morlat's avatar
Simon Morlat committed
146
	return ms_format_type_to_string(stream->type);
Ghislain MARY's avatar
Ghislain MARY committed
147 148
}

149
void ms_media_stream_sessions_uninit(MSMediaStreamSessions *sessions){
150 151 152
	if (sessions->srtp_context) {
		ms_srtp_context_delete(sessions->srtp_context);
		sessions->srtp_context=NULL;
153
	}
154 155 156 157
	if (sessions->rtp_session) {
		rtp_session_destroy(sessions->rtp_session);
		sessions->rtp_session=NULL;
	}
158
	if (sessions->zrtp_context != NULL) {
159
		ms_zrtp_context_destroy(sessions->zrtp_context);
160 161
		sessions->zrtp_context = NULL;
	}
johan's avatar
johan committed
162 163 164 165
	if (sessions->dtls_context != NULL) {
		ms_dtls_srtp_context_destroy(sessions->dtls_context);
		sessions->dtls_context = NULL;
	}
166 167 168 169 170 171
	if (sessions->ticker){
		ms_ticker_destroy(sessions->ticker);
		sessions->ticker=NULL;
	}
}

Ghislain MARY's avatar
Ghislain MARY committed
172
void media_stream_free(MediaStream *stream) {
173 174 175 176
	if (stream->sessions.rtp_session != NULL) rtp_session_unregister_event_queue(stream->sessions.rtp_session, stream->evq);
	if (stream->evq != NULL) ortp_ev_queue_destroy(stream->evq);
	if (stream->evd != NULL) ortp_ev_dispatcher_destroy(stream->evd);
	if (stream->owns_sessions) ms_media_stream_sessions_uninit(&stream->sessions);
Ghislain MARY's avatar
Ghislain MARY committed
177 178 179 180 181 182
	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);
183
	if (stream->qi) ms_quality_indicator_destroy(stream->qi);
184
}
185

186 187
bool_t media_stream_started(MediaStream *stream) {
	return stream->start_time != 0;
Ghislain MARY's avatar
Ghislain MARY committed
188 189 190
}

void media_stream_set_rtcp_information(MediaStream *stream, const char *cname, const char *tool) {
191 192
	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
193 194 195 196
	}
}

void media_stream_get_local_rtp_stats(MediaStream *stream, rtp_stats_t *lstats) {
197 198
	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
199 200 201 202 203 204
		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));
205
	return rtp_session_set_dscp(stream->sessions.rtp_session, dscp);
Ghislain MARY's avatar
Ghislain MARY committed
206 207 208
}

void media_stream_enable_adaptive_bitrate_control(MediaStream *stream, bool_t enabled) {
209 210 211 212 213
	stream->rc_enable = enabled;
}

void media_stream_set_adaptive_bitrate_algorithm(MediaStream *stream, MSQosAnalyzerAlgorithm algorithm) {
	stream->rc_algorithm = algorithm;
Ghislain MARY's avatar
Ghislain MARY committed
214 215 216
}

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

220 221 222 223 224 225 226
void media_stream_enable_dtls(MediaStream *stream, MSDtlsSrtpParams *params){
	if (stream->sessions.dtls_context==NULL) {
		ms_message("Start DTLS media stream context in stream session [%p]", &(stream->sessions));
		stream->sessions.dtls_context=ms_dtls_srtp_context_new(&(stream->sessions), params);
	}
}

johan's avatar
johan committed
227
bool_t media_stream_dtls_supported(void){
johan's avatar
johan committed
228
	return ms_dtls_srtp_available();
johan's avatar
johan committed
229 230
}

231
/*deprecated*/
jehan's avatar
jehan committed
232
bool_t media_stream_enable_srtp(MediaStream *stream, MSCryptoSuite suite, const char *snd_key, const char *rcv_key) {
233
	return ms_media_stream_sessions_set_srtp_recv_key_b64(&stream->sessions,suite,rcv_key)==0 && ms_media_stream_sessions_set_srtp_send_key_b64(&stream->sessions,suite,snd_key)==0;
Ghislain MARY's avatar
Ghislain MARY committed
234 235
}

236 237 238 239
const MSQualityIndicator *media_stream_get_quality_indicator(MediaStream *stream){
	return stream->qi;
}

Ghislain MARY's avatar
Ghislain MARY committed
240 241 242 243 244 245 246 247
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;
248
	hints.ai_flags = AI_NUMERICHOST;
Ghislain MARY's avatar
Ghislain MARY committed
249 250
	err = getaddrinfo(remote,"8000", &hints, &res0);
	if (err != 0) {
Simon Morlat's avatar
Simon Morlat committed
251
		ms_warning("ms_is_ipv6(%s): %s", remote, gai_strerror(err));
Ghislain MARY's avatar
Ghislain MARY committed
252 253 254 255 256 257
		return FALSE;
	}
	ret = (res0->ai_addr->sa_family == AF_INET6);
	freeaddrinfo(res0);
	return ret;
}
258

jehan's avatar
jehan committed
259 260 261 262 263 264 265 266 267 268 269 270
bool_t ms_is_multicast_addr(const struct sockaddr *addr) {

	switch (addr->sa_family) {
		case AF_INET:
			return IN_MULTICAST(ntohl(((struct sockaddr_in *) addr)->sin_addr.s_addr));
		case AF_INET6:
			return IN6_IS_ADDR_MULTICAST(&(((struct sockaddr_in6 *) addr)->sin6_addr));
		default:
			return FALSE;
	}

}
271

jehan's avatar
jehan committed
272 273 274 275 276 277 278 279
bool_t ms_is_multicast(const char *address) {
	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;
280
	hints.ai_flags = AI_NUMERICHOST;
jehan's avatar
jehan committed
281 282
	err = getaddrinfo(address,"8000", &hints, &res0);
	if (err != 0) {
Simon Morlat's avatar
Simon Morlat committed
283
		ms_warning("ms_is_multicast(%s): %s", address, gai_strerror(err));
jehan's avatar
jehan committed
284 285 286 287 288 289
		return FALSE;
	}
	ret = ms_is_multicast_addr(res0->ai_addr);

	freeaddrinfo(res0);
	return ret;
290
}
291

292 293 294 295
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{
296
		if (stream->rc_enable && stream->rc) ms_bitrate_controller_process_rtcp(stream->rc,m);
297
		if (stream->qi) ms_quality_indicator_update_from_feedback(stream->qi,m);
298 299 300 301
		stream->process_rtcp(stream,m);
	}while(rtcp_next_packet(m));
}

302 303
void media_stream_iterate(MediaStream *stream){
	time_t curtime=ms_time(NULL);
304

305
	if (stream->ice_check_list) ice_check_list_process(stream->ice_check_list,stream->sessions.rtp_session);
306
	/*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
307
	if (stream->state==MSStreamStarted){
308 309 310 311
		if (stream->is_beginning && (curtime-stream->start_time>15)){
			rtp_session_set_rtcp_report_interval(stream->sessions.rtp_session,5000);
			stream->is_beginning=FALSE;
		}
Simon Morlat's avatar
Simon Morlat committed
312 313
		if (stream->qi && curtime>stream->last_iterate_time) ms_quality_indicator_update_local(stream->qi);
	}
314
	stream->last_iterate_time=curtime;
315 316 317

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

318 319 320 321
	if (stream->evd) {
		ortp_ev_dispatcher_iterate(stream->evd);
	}

jehan's avatar
jehan committed
322
	if (stream->evq){
jehan's avatar
jehan committed
323 324 325
		OrtpEvent *ev=NULL;

		while ((ev=ortp_ev_queue_get(stream->evq))!=NULL){
jehan's avatar
jehan committed
326 327
			OrtpEventType evt=ortp_event_get_type(ev);
			if (evt==ORTP_EVENT_RTCP_PACKET_RECEIVED){
jehan's avatar
jehan committed
328
				mblk_t *m=ortp_event_get_data(ev)->packet;
329
				media_stream_process_rtcp(stream,m,curtime);
jehan's avatar
jehan committed
330
			}else if (evt==ORTP_EVENT_RTCP_PACKET_EMITTED){
331
				ms_message("%s_stream_iterate[%p], local statistics available:"
332
							"\n\tLocal current jitter buffer size: %5.1fms",
333
					media_stream_type_str(stream), stream, rtp_session_get_jitter_stats(stream->sessions.rtp_session)->jitter_buffer_size_ms);
334 335 336 337 338 339 340
			} else if (evt==ORTP_EVENT_STUN_PACKET_RECEIVED){
				if (stream->ice_check_list) {
						ice_handle_stun_packet(stream->ice_check_list,stream->sessions.rtp_session,ortp_event_get_data(ev));
				} else if (rtp_session_get_symmetric_rtp(stream->sessions.rtp_session)){
					/*try to know if we can trust stun packets for symetric rtp*/
					rtp_stats_t stats;
					media_stream_get_local_rtp_stats(stream, &stats);
341
					if (stats.packet_recv == 0 && !ms_is_multicast_addr((const struct sockaddr *)&stream->sessions.rtp_session->rtp.gs.rem_addr)) {
342 343
						memcpy(&stream->sessions.rtp_session->rtp.gs.rem_addr,&ortp_event_get_data(ev)->source_addr,ortp_event_get_data(ev)->source_addrlen);
						ms_message("stun packet received but no rtp yet for stream [%p], switching rtp destination address",stream);
344 345
					}
				}
346 347
			} else if ((evt == ORTP_EVENT_ZRTP_ENCRYPTION_CHANGED) || (evt == ORTP_EVENT_DTLS_ENCRYPTION_CHANGED)) {
				ms_message("%s_stream_iterate[%p]: is %s ",media_stream_type_str(stream) , stream, media_stream_secured(stream) ? "encrypted" : "not encrypted");
jehan's avatar
jehan committed
348 349 350 351
			}
			ortp_event_destroy(ev);
		}
	}
352 353
}

354
bool_t media_stream_alive(MediaStream *ms, int timeout){
355
	const rtp_stats_t *stats;
356

357 358 359 360
	if (ms->state!=MSStreamStarted){
		return TRUE;
	}
	stats=rtp_session_get_stats(ms->sessions.rtp_session);
361 362 363 364 365 366 367 368 369 370 371 372 373
	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;
}

374 375 376 377 378 379 380 381 382 383 384 385 386 387
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;
}

388 389 390 391 392 393 394 395 396 397 398 399 400 401
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
402 403 404 405 406 407 408 409
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;
}
410

411
float media_stream_get_up_bw(const MediaStream *stream) {
412
	return rtp_session_get_rtp_send_bandwidth(stream->sessions.rtp_session);
jehan's avatar
jehan committed
413 414
}

415
float media_stream_get_down_bw(const MediaStream *stream) {
416 417 418 419 420 421 422 423 424
	return rtp_session_get_rtp_recv_bandwidth(stream->sessions.rtp_session);
}

float media_stream_get_rtcp_up_bw(const MediaStream *stream) {
	return rtp_session_get_rtcp_send_bandwidth(stream->sessions.rtp_session);
}

float media_stream_get_rtcp_down_bw(const MediaStream *stream) {
	return rtp_session_get_rtcp_recv_bandwidth(stream->sessions.rtp_session);
jehan's avatar
jehan committed
425
}
426 427 428 429 430

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

bool_t media_stream_secured (const MediaStream *stream) {
433 434 435 436 437
	if (stream->state != MSStreamStarted)
		return FALSE;

	switch (stream->type) {
	case MSAudio:
Sylvain Berfini's avatar
Sylvain Berfini committed
438
	case MSText:
439
		/*fixme need also audio stream direction to be more precise*/
440
		return ms_media_stream_sessions_secured(&stream->sessions, MediaStreamSendRecv);
441 442
	case MSVideo:{
		VideoStream *vs = (VideoStream*)stream;
443
		return ms_media_stream_sessions_secured(&stream->sessions, vs->dir);
444 445
	}
	}
François Grisez's avatar
François Grisez committed
446
	return FALSE;
jehan's avatar
jehan committed
447
}
448 449 450 451 452

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

453
uint16_t media_stream_get_avpf_rr_interval(const MediaStream *stream) {
454 455 456
	return rtp_session_get_avpf_rr_interval(stream->sessions.rtp_session);
}

jehan's avatar
jehan committed
457 458 459
MSStreamState media_stream_get_state(const MediaStream *stream) {
	return stream->state;
}
Simon Morlat's avatar
Simon Morlat committed
460

461 462 463 464
RtpSession * media_stream_get_rtp_session(const MediaStream *stream) {
	return stream->sessions.rtp_session;
}

Simon Morlat's avatar
Simon Morlat committed
465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505
#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";
506
			break;
Simon Morlat's avatar
Simon Morlat committed
507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524
		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
525

526 527 528 529
OrtpEvDispatcher* media_stream_get_event_dispatcher(const MediaStream *stream) {
	return stream->evd;
}

530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574
const char *ms_resource_type_to_string(MSResourceType type){
	switch(type){
		case MSResourceDefault:
			return "MSResourceDefault";
		case MSResourceInvalid:
			return "MSResourceInvalid";
		case MSResourceCamera:
			return "MSResourceCamera";
		case MSResourceFile:
			return "MSResourceFile";
		case MSResourceRtp:
			return "MSResourceRtp";
		case MSResourceSoundcard:
			return "MSResourceSoundcard";
	}
	return "INVALID";
}

bool_t ms_media_resource_is_consistent(const MSMediaResource *r){
	switch(r->type){
		case MSResourceCamera:
		case MSResourceRtp:
		case MSResourceSoundcard:
			if (r->resource_arg == NULL){
				ms_error("No resource argument specified for resource type %s", ms_resource_type_to_string(r->type));
				return FALSE;
			}
			return TRUE;
		break;
		case MSResourceFile:
			/*setting up file player/recorder without specifying the file to play immediately is allowed*/
		case MSResourceDefault:
			return TRUE;
		case MSResourceInvalid:
			ms_error("Invalid resource type specified");
			return FALSE;
	}
	ms_error("Unsupported media resource type [%i]", (int)r->type);  
	return FALSE;
}

bool_t ms_media_stream_io_is_consistent(const MSMediaStreamIO *io){
	return ms_media_resource_is_consistent(&io->input) && ms_media_resource_is_consistent(&io->output);
}

575 576 577 578 579 580 581
/*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
582 583 584 585

const char *video_stream_get_default_video_renderer(void){
	return NULL;
}
586 587 588 589 590

MSWebCamDesc *ms_mire_webcam_desc_get(void){
	return NULL;
}

591
#endif
Simon Morlat's avatar
Simon Morlat committed
592