1 /*
2 mediastreamer2 library - modular sound and video processing and streaming
3 Copyright (C) 2006-2013 Belledonne Communications, Grenoble
4 
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License
7 as published by the Free Software Foundation; either version 2
8 of the License, or (at your option) any later version.
9 
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU General Public License for more details.
14 
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
18 */
19 
20 
21 #ifdef HAVE_CONFIG_H
22 #include "mediastreamer-config.h"
23 #endif
24 
25 #include "ortp/port.h"
26 #include "mediastreamer2/mediastream.h"
27 #include "mediastreamer2/msrtp.h"
28 #include "private.h"
29 #include <ctype.h>
30 
31 #if __APPLE__
32 #include "TargetConditionals.h"
33 #endif
34 
35 #ifndef MS_MINIMAL_MTU
36 /*this is used for determining the minimum size of recv buffers for RTP packets
37  Keep 1500 for maximum interoparibility*/
38 #define MS_MINIMAL_MTU 1500
39 #endif
40 
41 
42 #if defined(_WIN32_WCE)
43 time_t
ms_time(time_t * t)44 ms_time(time_t *t) {
45 	DWORD timemillis = GetTickCount();
46 	if (timemillis > 0) {
47 		if (t != NULL) *t = timemillis / 1000;
48 	}
49 	return timemillis / 1000;
50 }
51 #endif
52 
53 static void tmmbr_received(const OrtpEventData *evd, void *user_pointer);
54 
55 
disable_checksums(ortp_socket_t sock)56 static void disable_checksums(ortp_socket_t sock) {
57 #if defined(DISABLE_CHECKSUMS) && defined(SO_NO_CHECK)
58 	int option = 1;
59 	if (setsockopt(sock, SOL_SOCKET, SO_NO_CHECK, &option, sizeof(option)) == -1) {
60 		ms_warning("Could not disable udp checksum: %s", strerror(errno));
61 	}
62 #endif
63 }
64 
_ms_ticker_prio_from_env(const char * penv,MSTickerPrio * prio)65 static int _ms_ticker_prio_from_env(const char *penv, MSTickerPrio *prio) {
66 	if (strcasecmp(penv, "NORMAL") == 0) {
67 		*prio = MS_TICKER_PRIO_NORMAL;
68 		return 0;
69 	}
70 	if (strcasecmp(penv, "HIGH") == 0) {
71 		*prio = MS_TICKER_PRIO_HIGH;
72 		return 0;
73 	}
74 	if (strcasecmp(penv, "REALTIME") == 0) {
75 		*prio = MS_TICKER_PRIO_REALTIME;
76 		return 0;
77 	}
78 	ms_error("Undefined priority %s", penv);
79 	return -1;
80 }
81 
__ms_get_default_prio(bool_t is_video)82 MSTickerPrio __ms_get_default_prio(bool_t is_video) {
83 	const char *penv = NULL;
84 	MSTickerPrio prio;
85 
86 	if (is_video) {
87 #ifndef MS2_WINDOWS_UNIVERSAL
88 		penv = getenv("MS_VIDEO_PRIO");
89 #endif
90 		if(penv && _ms_ticker_prio_from_env(penv, &prio) == 0) return prio;
91 
92 #if TARGET_OS_IPHONE
93 		return MS_TICKER_PRIO_HIGH;
94 #else
95 		return MS_TICKER_PRIO_NORMAL;
96 #endif
97 	} else {
98 #ifndef MS2_WINDOWS_UNIVERSAL
99 		penv = getenv("MS_AUDIO_PRIO");
100 #endif
101 		if (penv && _ms_ticker_prio_from_env(penv, &prio) == 0) return prio;
102 
103 		return MS_TICKER_PRIO_HIGH;
104 
105 	}
106 }
107 
media_stream_init(MediaStream * stream,MSFactory * factory,const MSMediaStreamSessions * sessions)108 void media_stream_init(MediaStream *stream, MSFactory *factory, const MSMediaStreamSessions *sessions) {
109 	stream->sessions = *sessions;
110 
111 	stream->evd = ortp_ev_dispatcher_new(stream->sessions.rtp_session);
112 	stream->evq = ortp_ev_queue_new();
113 	stream->factory = factory; /*the factory is used later to instanciate everything in mediastreamer2.*/
114 	rtp_session_register_event_queue(stream->sessions.rtp_session, stream->evq);
115 
116 	/*we give to the zrtp and dtls sessions a backpointer to all the stream sessions*/
117 	if (sessions->zrtp_context != NULL) {
118 		ms_zrtp_set_stream_sessions(sessions->zrtp_context, &stream->sessions);
119 	}
120 	if (sessions->dtls_context != NULL) {
121 		ms_dtls_srtp_set_stream_sessions(sessions->dtls_context, &stream->sessions);
122 	}
123 	ortp_ev_dispatcher_connect(stream->evd
124 								, ORTP_EVENT_RTCP_PACKET_RECEIVED
125 								, RTCP_RTPFB
126 								, (OrtpEvDispatcherCb)tmmbr_received
127 								, stream);
128 }
129 
ms_create_duplex_rtp_session(const char * local_ip,int loc_rtp_port,int loc_rtcp_port,int mtu)130 RtpSession * ms_create_duplex_rtp_session(const char* local_ip, int loc_rtp_port, int loc_rtcp_port, int mtu) {
131 	RtpSession *rtpr;
132 
133 	rtpr = rtp_session_new(RTP_SESSION_SENDRECV);
134 	rtp_session_set_recv_buf_size(rtpr, MAX(mtu , MS_MINIMAL_MTU));
135 	rtp_session_set_scheduling_mode(rtpr, 0);
136 	rtp_session_set_blocking_mode(rtpr, 0);
137 	rtp_session_enable_adaptive_jitter_compensation(rtpr, TRUE);
138 	rtp_session_set_symmetric_rtp(rtpr, TRUE);
139 	rtp_session_set_local_addr(rtpr, local_ip, loc_rtp_port, loc_rtcp_port);
140 	rtp_session_signal_connect(rtpr, "timestamp_jump", (RtpCallback)rtp_session_resync, NULL);
141 	rtp_session_signal_connect(rtpr, "ssrc_changed", (RtpCallback)rtp_session_resync, NULL);
142 	rtp_session_set_ssrc_changed_threshold(rtpr, 0);
143 	rtp_session_set_rtcp_report_interval(rtpr, 2500);	/* At the beginning of the session send more reports. */
144 	rtp_session_set_multicast_loopback(rtpr,TRUE); /*very useful, specially for testing purposes*/
145 	rtp_session_set_send_ts_offset(rtpr, (uint32_t)bctbx_random());
146 	rtp_session_enable_avpf_feature(rtpr, ORTP_AVPF_FEATURE_TMMBR, TRUE);
147 	disable_checksums(rtp_session_get_rtp_socket(rtpr));
148 	return rtpr;
149 }
150 
media_stream_join_multicast_group(MediaStream * stream,const char * ip)151 int media_stream_join_multicast_group(MediaStream *stream, const char *ip){
152 	return rtp_session_join_multicast_group(stream->sessions.rtp_session,ip);
153 }
154 
media_stream_start_ticker(MediaStream * stream)155 void media_stream_start_ticker(MediaStream *stream) {
156 	MSTickerParams params = {0};
157 	char name[32] = {0};
158 
159 	if (stream->sessions.ticker) return;
160 	snprintf(name, sizeof(name) - 1, "%s MSTicker", media_stream_type_str(stream));
161 	name[0] = toupper(name[0]);
162 	params.name = name;
163 	params.prio = __ms_get_default_prio((stream->type == MSVideo) ? TRUE : FALSE);
164 	stream->sessions.ticker = ms_ticker_new_with_params(&params);
165 }
166 
media_stream_type_str(MediaStream * stream)167 const char * media_stream_type_str(MediaStream *stream) {
168 	return ms_format_type_to_string(stream->type);
169 }
170 
ms_media_stream_sessions_uninit(MSMediaStreamSessions * sessions)171 void ms_media_stream_sessions_uninit(MSMediaStreamSessions *sessions){
172 	if (sessions->srtp_context) {
173 		ms_srtp_context_delete(sessions->srtp_context);
174 		sessions->srtp_context=NULL;
175 	}
176 	if (sessions->rtp_session) {
177 		rtp_session_destroy(sessions->rtp_session);
178 		sessions->rtp_session=NULL;
179 	}
180 	if (sessions->zrtp_context != NULL) {
181 		ms_zrtp_context_destroy(sessions->zrtp_context);
182 		sessions->zrtp_context = NULL;
183 	}
184 	if (sessions->dtls_context != NULL) {
185 		ms_dtls_srtp_context_destroy(sessions->dtls_context);
186 		sessions->dtls_context = NULL;
187 	}
188 	if (sessions->ticker){
189 		ms_ticker_destroy(sessions->ticker);
190 		sessions->ticker=NULL;
191 	}
192 }
193 
media_stream_free(MediaStream * stream)194 void media_stream_free(MediaStream *stream) {
195 	ortp_ev_dispatcher_disconnect(stream->evd, ORTP_EVENT_RTCP_PACKET_RECEIVED, RTCP_RTPFB, (OrtpEvDispatcherCb)tmmbr_received);
196 	if (stream->sessions.zrtp_context != NULL) {
197 		ms_zrtp_set_stream_sessions(stream->sessions.zrtp_context, NULL);
198 	}
199 	if (stream->sessions.dtls_context != NULL) {
200 		ms_dtls_srtp_set_stream_sessions(stream->sessions.dtls_context, NULL);
201 	}
202 
203 	if (stream->sessions.rtp_session != NULL) rtp_session_unregister_event_queue(stream->sessions.rtp_session, stream->evq);
204 	if (stream->evq != NULL) ortp_ev_queue_destroy(stream->evq);
205 	if (stream->evd != NULL) ortp_ev_dispatcher_destroy(stream->evd);
206 	if (stream->owns_sessions) ms_media_stream_sessions_uninit(&stream->sessions);
207 	if (stream->rc != NULL) ms_bitrate_controller_destroy(stream->rc);
208 	if (stream->rtpsend != NULL) ms_filter_destroy(stream->rtpsend);
209 	if (stream->rtprecv != NULL) ms_filter_destroy(stream->rtprecv);
210 	if (stream->encoder != NULL) ms_filter_destroy(stream->encoder);
211 	if (stream->decoder != NULL) ms_filter_destroy(stream->decoder);
212 	if (stream->voidsink != NULL) ms_filter_destroy(stream->voidsink);
213 	if (stream->qi) ms_quality_indicator_destroy(stream->qi);
214 }
215 
media_stream_started(MediaStream * stream)216 bool_t media_stream_started(MediaStream *stream) {
217 	return stream->start_time != 0;
218 }
219 
media_stream_set_rtcp_information(MediaStream * stream,const char * cname,const char * tool)220 void media_stream_set_rtcp_information(MediaStream *stream, const char *cname, const char *tool) {
221 	if (stream->sessions.rtp_session != NULL) {
222 		rtp_session_set_source_description(stream->sessions.rtp_session, cname, NULL, NULL, NULL, NULL, tool, NULL);
223 	}
224 }
225 
media_stream_get_local_rtp_stats(MediaStream * stream,rtp_stats_t * lstats)226 void media_stream_get_local_rtp_stats(MediaStream *stream, rtp_stats_t *lstats) {
227 	if (stream->sessions.rtp_session) {
228 		const rtp_stats_t *stats = rtp_session_get_stats(stream->sessions.rtp_session);
229 		memcpy(lstats, stats, sizeof(*stats));
230 	} else memset(lstats, 0, sizeof(rtp_stats_t));
231 }
232 
media_stream_set_dscp(MediaStream * stream,int dscp)233 int media_stream_set_dscp(MediaStream *stream, int dscp) {
234 	ms_message("Setting DSCP to %i for %s stream.", dscp, media_stream_type_str(stream));
235 	return rtp_session_set_dscp(stream->sessions.rtp_session, dscp);
236 }
237 
media_stream_enable_adaptive_bitrate_control(MediaStream * stream,bool_t enabled)238 void media_stream_enable_adaptive_bitrate_control(MediaStream *stream, bool_t enabled) {
239 	stream->rc_enable = enabled;
240 }
241 
media_stream_set_adaptive_bitrate_algorithm(MediaStream * stream,MSQosAnalyzerAlgorithm algorithm)242 void media_stream_set_adaptive_bitrate_algorithm(MediaStream *stream, MSQosAnalyzerAlgorithm algorithm) {
243 	stream->rc_algorithm = algorithm;
244 }
245 
media_stream_enable_adaptive_jittcomp(MediaStream * stream,bool_t enabled)246 void media_stream_enable_adaptive_jittcomp(MediaStream *stream, bool_t enabled) {
247 	rtp_session_enable_adaptive_jitter_compensation(stream->sessions.rtp_session, enabled);
248 }
249 
media_stream_enable_dtls(MediaStream * stream,MSDtlsSrtpParams * params)250 void media_stream_enable_dtls(MediaStream *stream, MSDtlsSrtpParams *params){
251 	if (stream->sessions.dtls_context==NULL) {
252 		ms_message("Start DTLS media stream context in stream session [%p]", &(stream->sessions));
253 		stream->sessions.dtls_context=ms_dtls_srtp_context_new(&(stream->sessions), params);
254 	}
255 }
256 
media_stream_set_ice_check_list(MediaStream * stream,IceCheckList * cl)257 void media_stream_set_ice_check_list(MediaStream *stream, IceCheckList *cl) {
258 	bool_t stun_enabled = TRUE;
259 	stream->ice_check_list = cl;
260 	if (stream->ice_check_list != NULL) {
261 		ice_check_list_set_rtp_session(stream->ice_check_list, stream->sessions.rtp_session);
262 		stun_enabled = FALSE;
263 	}
264 	if (stream->rtpsend != NULL) {
265 		ms_filter_call_method(stream->rtpsend, MS_RTP_SEND_ENABLE_STUN, &stun_enabled);
266 	}
267 }
268 
media_stream_dtls_supported(void)269 bool_t media_stream_dtls_supported(void){
270 	return ms_dtls_srtp_available();
271 }
272 
273 /*deprecated*/
media_stream_enable_srtp(MediaStream * stream,MSCryptoSuite suite,const char * snd_key,const char * rcv_key)274 bool_t media_stream_enable_srtp(MediaStream *stream, MSCryptoSuite suite, const char *snd_key, const char *rcv_key) {
275 	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;
276 }
277 
media_stream_get_quality_indicator(MediaStream * stream)278 const MSQualityIndicator *media_stream_get_quality_indicator(MediaStream *stream){
279 	return stream->qi;
280 }
281 
ms_is_ipv6(const char * remote)282 bool_t ms_is_ipv6(const char *remote) {
283 	bool_t ret = FALSE;
284 	struct addrinfo hints, *res0;
285 	int err;
286 
287 	memset(&hints, 0, sizeof(hints));
288 	hints.ai_family = PF_UNSPEC;
289 	hints.ai_socktype = SOCK_DGRAM;
290 	hints.ai_flags = AI_NUMERICHOST;
291 	err = getaddrinfo(remote,"8000", &hints, &res0);
292 	if (err != 0) {
293 		ms_warning("ms_is_ipv6(%s): %s", remote, gai_strerror(err));
294 		return FALSE;
295 	}
296 	ret = (res0->ai_addr->sa_family == AF_INET6);
297 	freeaddrinfo(res0);
298 	return ret;
299 }
300 
ms_is_multicast_addr(const struct sockaddr * addr)301 bool_t ms_is_multicast_addr(const struct sockaddr *addr) {
302 	return ortp_is_multicast_addr(addr);
303 }
304 
ms_is_multicast(const char * address)305 bool_t ms_is_multicast(const char *address) {
306 	bool_t ret = FALSE;
307 	struct addrinfo hints, *res0;
308 	int err;
309 
310 	memset(&hints, 0, sizeof(hints));
311 	hints.ai_family = PF_UNSPEC;
312 	hints.ai_socktype = SOCK_DGRAM;
313 	hints.ai_flags = AI_NUMERICHOST;
314 	err = getaddrinfo(address,"8000", &hints, &res0);
315 	if (err != 0) {
316 		ms_warning("ms_is_multicast(%s): %s", address, gai_strerror(err));
317 		return FALSE;
318 	}
319 	ret = ms_is_multicast_addr(res0->ai_addr);
320 
321 	freeaddrinfo(res0);
322 	return ret;
323 }
324 
media_stream_process_rtcp(MediaStream * stream,mblk_t * m,time_t curtime)325 static void media_stream_process_rtcp(MediaStream *stream, mblk_t *m, time_t curtime){
326 	stream->last_packet_time=curtime;
327 	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":""));
328 	do{
329 		if (stream->rc_enable && stream->rc) ms_bitrate_controller_process_rtcp(stream->rc,m);
330 		if (stream->qi) ms_quality_indicator_update_from_feedback(stream->qi,m);
331 		stream->process_rtcp(stream,m);
332 	}while(rtcp_next_packet(m));
333 }
334 
media_stream_iterate(MediaStream * stream)335 void media_stream_iterate(MediaStream *stream){
336 	time_t curtime=ms_time(NULL);
337 
338 	if (stream->ice_check_list) ice_check_list_process(stream->ice_check_list,stream->sessions.rtp_session);
339 	/*we choose to update the quality indicator as much as possible, since local statistics can be computed realtime. */
340 	if (stream->state==MSStreamStarted){
341 		if (stream->is_beginning && (curtime-stream->start_time>15)){
342 			rtp_session_set_rtcp_report_interval(stream->sessions.rtp_session,5000);
343 			stream->is_beginning=FALSE;
344 		}
345 		if (stream->qi && curtime>stream->last_iterate_time) ms_quality_indicator_update_local(stream->qi);
346 	}
347 	stream->last_iterate_time=curtime;
348 
349 	if (stream->rc) ms_bitrate_controller_update(stream->rc);
350 
351 	if (stream->evd) {
352 		ortp_ev_dispatcher_iterate(stream->evd);
353 	}
354 
355 	if (stream->evq){
356 		OrtpEvent *ev=NULL;
357 
358 		while ((ev=ortp_ev_queue_get(stream->evq))!=NULL){
359 			OrtpEventType evt=ortp_event_get_type(ev);
360 			if (evt==ORTP_EVENT_RTCP_PACKET_RECEIVED){
361 				mblk_t *m=ortp_event_get_data(ev)->packet;
362 				media_stream_process_rtcp(stream,m,curtime);
363 			}else if (evt==ORTP_EVENT_RTCP_PACKET_EMITTED){
364 				ms_message("%s_stream_iterate[%p], local statistics available:"
365 							"\n\tLocal current jitter buffer size: %5.1fms",
366 					media_stream_type_str(stream), stream, rtp_session_get_jitter_stats(stream->sessions.rtp_session)->jitter_buffer_size_ms);
367 			} else if (evt==ORTP_EVENT_STUN_PACKET_RECEIVED && stream->ice_check_list){
368 				ice_handle_stun_packet(stream->ice_check_list,stream->sessions.rtp_session,ortp_event_get_data(ev));
369 			} else if ((evt == ORTP_EVENT_ZRTP_ENCRYPTION_CHANGED) || (evt == ORTP_EVENT_DTLS_ENCRYPTION_CHANGED)) {
370 				ms_message("%s_stream_iterate[%p]: is %s ",media_stream_type_str(stream) , stream, media_stream_secured(stream) ? "encrypted" : "not encrypted");
371 			}
372 			ortp_event_destroy(ev);
373 		}
374 	}
375 }
376 
media_stream_alive(MediaStream * ms,int timeout)377 bool_t media_stream_alive(MediaStream *ms, int timeout){
378 	const rtp_stats_t *stats;
379 
380 	if (ms->state!=MSStreamStarted){
381 		return TRUE;
382 	}
383 	stats=rtp_session_get_stats(ms->sessions.rtp_session);
384 	if (stats->recv!=0){
385 		if (stats->recv!=ms->last_packet_count){
386 			ms->last_packet_count=stats->recv;
387 			ms->last_packet_time=ms_time(NULL);
388 		}
389 	}
390 	if (ms_time(NULL)-ms->last_packet_time>timeout){
391 		/* more than timeout seconds of inactivity*/
392 		return FALSE;
393 	}
394 	return TRUE;
395 }
396 
media_stream_get_quality_rating(MediaStream * stream)397 float media_stream_get_quality_rating(MediaStream *stream){
398 	if (stream->qi){
399 		return ms_quality_indicator_get_rating(stream->qi);
400 	}
401 	return -1;
402 }
403 
media_stream_get_average_quality_rating(MediaStream * stream)404 float media_stream_get_average_quality_rating(MediaStream *stream){
405 	if (stream->qi){
406 		return ms_quality_indicator_get_average_rating(stream->qi);
407 	}
408 	return -1;
409 }
410 
media_stream_get_lq_quality_rating(MediaStream * stream)411 float media_stream_get_lq_quality_rating(MediaStream *stream) {
412 	if (stream->qi) {
413 		return ms_quality_indicator_get_lq_rating(stream->qi);
414 	}
415 	return -1;
416 }
417 
media_stream_get_average_lq_quality_rating(MediaStream * stream)418 float media_stream_get_average_lq_quality_rating(MediaStream *stream) {
419 	if (stream->qi) {
420 		return ms_quality_indicator_get_average_lq_rating(stream->qi);
421 	}
422 	return -1;
423 }
424 
media_stream_set_target_network_bitrate(MediaStream * stream,int target_bitrate)425 int media_stream_set_target_network_bitrate(MediaStream *stream,int target_bitrate) {
426 	stream->target_bitrate=target_bitrate;
427 	return 0;
428 }
429 
media_stream_get_target_network_bitrate(const MediaStream * stream)430 int media_stream_get_target_network_bitrate(const MediaStream *stream) {
431 	return stream->target_bitrate;
432 }
433 
media_stream_get_up_bw(const MediaStream * stream)434 float media_stream_get_up_bw(const MediaStream *stream) {
435 	return rtp_session_get_rtp_send_bandwidth(stream->sessions.rtp_session);
436 }
437 
media_stream_get_down_bw(const MediaStream * stream)438 float media_stream_get_down_bw(const MediaStream *stream) {
439 	return rtp_session_get_rtp_recv_bandwidth(stream->sessions.rtp_session);
440 }
441 
media_stream_get_rtcp_up_bw(const MediaStream * stream)442 float media_stream_get_rtcp_up_bw(const MediaStream *stream) {
443 	return rtp_session_get_rtcp_send_bandwidth(stream->sessions.rtp_session);
444 }
445 
media_stream_get_rtcp_down_bw(const MediaStream * stream)446 float media_stream_get_rtcp_down_bw(const MediaStream *stream) {
447 	return rtp_session_get_rtcp_recv_bandwidth(stream->sessions.rtp_session);
448 }
449 
media_stream_reclaim_sessions(MediaStream * stream,MSMediaStreamSessions * sessions)450 void media_stream_reclaim_sessions(MediaStream *stream, MSMediaStreamSessions *sessions){
451 	memcpy(sessions,&stream->sessions, sizeof(MSMediaStreamSessions));
452 	stream->owns_sessions=FALSE;
453 }
454 
media_stream_secured(const MediaStream * stream)455 bool_t media_stream_secured (const MediaStream *stream) {
456 	if (stream->state != MSStreamStarted)
457 		return FALSE;
458 
459 	switch (stream->type) {
460 		case MSAudio:
461 		case MSText:
462 			/*fixme need also audio stream direction to be more precise*/
463 			return ms_media_stream_sessions_secured(&stream->sessions, MediaStreamSendRecv);
464 		case MSVideo:{
465 			VideoStream *vs = (VideoStream*)stream;
466 			return ms_media_stream_sessions_secured(&stream->sessions, vs->dir);
467 		}
468 		case MSUnknownMedia:
469 		break;
470 	}
471 	return FALSE;
472 }
473 
media_stream_avpf_enabled(const MediaStream * stream)474 bool_t media_stream_avpf_enabled(const MediaStream *stream) {
475 	return rtp_session_avpf_enabled(stream->sessions.rtp_session);
476 }
477 
media_stream_get_avpf_rr_interval(const MediaStream * stream)478 uint16_t media_stream_get_avpf_rr_interval(const MediaStream *stream) {
479 	return rtp_session_get_avpf_rr_interval(stream->sessions.rtp_session);
480 }
481 
media_stream_get_state(const MediaStream * stream)482 MSStreamState media_stream_get_state(const MediaStream *stream) {
483 	return stream->state;
484 }
485 
media_stream_get_rtp_session(const MediaStream * stream)486 RtpSession * media_stream_get_rtp_session(const MediaStream *stream) {
487 	return stream->sessions.rtp_session;
488 }
489 
490 #define keywordcmp(key,b) strncmp(key,b,sizeof(key))
491 
492 /* see  http://www.iana.org/assignments/sdp-security-descriptions/sdp-security-descriptions.xhtml#sdp-security-descriptions-3 */
493 
494 
495 
ms_crypto_suite_build_from_name_params(const MSCryptoSuiteNameParams * descrption)496 MSCryptoSuite ms_crypto_suite_build_from_name_params(const MSCryptoSuiteNameParams *descrption){
497 	const char *name=descrption->name, *parameters=descrption->params;
498 	if (keywordcmp ( "AES_CM_128_HMAC_SHA1_80",name ) == 0 ){
499 		if (parameters && strstr(parameters,"UNENCRYPTED_SRTP")) return MS_NO_CIPHER_SHA1_80;
500 		else if (parameters && strstr(parameters,"UNAUTHENTICATED_SRTP")) return MS_AES_128_NO_AUTH;
501 		else return MS_AES_128_SHA1_80;
502 	}else if ( keywordcmp ( "AES_CM_128_HMAC_SHA1_32",name ) == 0 ){
503 		if (parameters && strstr(parameters,"UNENCRYPTED_SRTP")) goto error;
504 		if (parameters && strstr(parameters,"UNAUTHENTICATED_SRTP")) return MS_AES_128_NO_AUTH;
505 		else return MS_AES_128_SHA1_32;
506 	}else if ( keywordcmp ("AES_256_CM_HMAC_SHA1_32", name) == 0 ){
507 		if (parameters && strstr(parameters,"UNENCRYPTED_SRTP")) goto error;
508 		if (parameters && strstr(parameters,"UNAUTHENTICATED_SRTP")) goto error;
509 		return MS_AES_256_SHA1_32;
510 	}else if ( keywordcmp ("AES_256_CM_HMAC_SHA1_80", name) == 0 ){
511 		if (parameters && strstr(parameters,"UNENCRYPTED_SRTP")) goto error;
512 		if (parameters && strstr(parameters,"UNAUTHENTICATED_SRTP")) goto error;
513 		return MS_AES_256_SHA1_80;
514 	}else if ( keywordcmp ("AES_CM_256_HMAC_SHA1_80", name) == 0 ){
515         if (parameters && strstr(parameters,"UNENCRYPTED_SRTP")) goto error;
516         if (parameters && strstr(parameters,"UNAUTHENTICATED_SRTP")) goto error;
517         return MS_AES_CM_256_SHA1_80;
518     }
519 error:
520     ms_error("Unsupported crypto suite '%s' with parameters '%s'",name, parameters ? parameters : "");
521     return MS_CRYPTO_SUITE_INVALID;
522 }
523 
ms_crypto_suite_to_name_params(MSCryptoSuite cs,MSCryptoSuiteNameParams * params)524 int ms_crypto_suite_to_name_params(MSCryptoSuite cs, MSCryptoSuiteNameParams *params ){
525      params->name=NULL;
526      params->params=NULL;
527      switch(cs){
528         case MS_CRYPTO_SUITE_INVALID:
529      		break;
530         case MS_AES_128_SHA1_80:
531      		params->name= "AES_CM_128_HMAC_SHA1_80";
532      		break;
533      	case MS_AES_128_SHA1_32:
534      		params->name="AES_CM_128_HMAC_SHA1_32";
535      		break;
536      	case MS_AES_128_NO_AUTH:
537      		params->name="AES_CM_128_HMAC_SHA1_80";
538      		params->params="UNAUTHENTICATED_SRTP";
539      		break;
540      	case MS_NO_CIPHER_SHA1_80:
541      		params->name="AES_CM_128_HMAC_SHA1_80";
542      		params->params="UNENCRYPTED_SRTP UNENCRYPTED_SRTCP";
543      		break;
544      	case MS_AES_256_SHA1_80:
545      		params->name="AES_256_CM_HMAC_SHA1_80";
546      		break;
547      	case MS_AES_CM_256_SHA1_80:
548      	    params->name="AES_CM_256_HMAC_SHA1_80";
549      	    break;
550      	case MS_AES_256_SHA1_32:
551      		params->name= "AES_256_CM_HMAC_SHA1_32";
552      		break;
553      }
554      if (params->name==NULL) return -1;
555      return 0;
556 }
557 
media_stream_get_event_dispatcher(const MediaStream * stream)558 OrtpEvDispatcher* media_stream_get_event_dispatcher(const MediaStream *stream) {
559 	return stream->evd;
560 }
561 
ms_resource_type_to_string(MSResourceType type)562 const char *ms_resource_type_to_string(MSResourceType type){
563 	switch(type){
564 		case MSResourceDefault:
565 			return "MSResourceDefault";
566 		case MSResourceInvalid:
567 			return "MSResourceInvalid";
568 		case MSResourceCamera:
569 			return "MSResourceCamera";
570 		case MSResourceFile:
571 			return "MSResourceFile";
572 		case MSResourceRtp:
573 			return "MSResourceRtp";
574 		case MSResourceSoundcard:
575 			return "MSResourceSoundcard";
576 	}
577 	return "INVALID";
578 }
579 
ms_media_resource_is_consistent(const MSMediaResource * r)580 bool_t ms_media_resource_is_consistent(const MSMediaResource *r){
581 	switch(r->type){
582 		case MSResourceCamera:
583 		case MSResourceRtp:
584 		case MSResourceSoundcard:
585 			if (r->resource_arg == NULL){
586 				ms_error("No resource argument specified for resource type %s", ms_resource_type_to_string(r->type));
587 				return FALSE;
588 			}
589 			return TRUE;
590 		break;
591 		case MSResourceFile:
592 			/*setting up file player/recorder without specifying the file to play immediately is allowed*/
593 		case MSResourceDefault:
594 			return TRUE;
595 		case MSResourceInvalid:
596 			ms_error("Invalid resource type specified");
597 			return FALSE;
598 	}
599 	ms_error("Unsupported media resource type [%i]", (int)r->type);
600 	return FALSE;
601 }
602 
ms_media_stream_io_is_consistent(const MSMediaStreamIO * io)603 bool_t ms_media_stream_io_is_consistent(const MSMediaStreamIO *io){
604 	return ms_media_resource_is_consistent(&io->input) && ms_media_resource_is_consistent(&io->output);
605 }
606 
607 /*stubs*/
608 #ifndef VIDEO_ENABLED
video_stream_open_player(VideoStream * stream,MSFilter * sink)609 void video_stream_open_player(VideoStream *stream, MSFilter *sink){
610 }
611 
video_stream_close_player(VideoStream * stream)612 void video_stream_close_player(VideoStream *stream){
613 }
614 
video_stream_get_default_video_renderer(void)615 const char *video_stream_get_default_video_renderer(void){
616 	return NULL;
617 }
618 
ms_mire_webcam_desc_get(void)619 MSWebCamDesc *ms_mire_webcam_desc_get(void){
620 	return NULL;
621 }
622 
623 #endif
624 
625 
apply_bitrate_limit(MediaStream * obj,int br_limit)626 static void apply_bitrate_limit(MediaStream *obj, int br_limit){
627 	int previous_br_limit = rtp_session_get_target_upload_bandwidth(obj->sessions.rtp_session);
628 	if (!obj->encoder){
629 		ms_warning("TMMNR not applicable because no encoder for this stream.");
630 		return;
631 	}
632 	if (previous_br_limit == br_limit) {
633 		ms_message("Previous bitrate limit was already %i, skipping...", br_limit);
634 		return;
635 	}
636 
637 	if (ms_filter_call_method(obj->encoder,MS_FILTER_SET_BITRATE, &br_limit) != 0){
638 		ms_warning("Failed to apply bitrate constraint to %s", obj->encoder->desc->name);
639 	}
640 
641 	media_stream_set_target_network_bitrate(obj, br_limit);
642 	rtp_session_set_target_upload_bandwidth(obj->sessions.rtp_session, br_limit);
643 
644 #ifdef VIDEO_ENABLED
645 	if (obj->type == MSVideo) {
646 		MSVideoConfiguration *vconf_list = NULL;
647 		MSVideoSize vsize;
648 		MSVideoConfiguration vconf1, vconf2;
649 
650 		ms_filter_call_method(obj->encoder, MS_VIDEO_ENCODER_GET_CONFIGURATION_LIST, &vconf_list);
651 		ms_filter_call_method(obj->encoder, MS_FILTER_GET_VIDEO_SIZE, &vsize);
652 
653 		vconf1 = ms_video_find_best_configuration_for_size_and_bitrate(vconf_list, vsize, ms_factory_get_cpu_count(obj->factory), previous_br_limit);
654 		vconf2 = ms_video_find_best_configuration_for_size_and_bitrate(vconf_list, vsize, ms_factory_get_cpu_count(obj->factory), br_limit);
655 		if (vconf1.required_bitrate != vconf2.required_bitrate || vconf1.bitrate_limit != vconf2.bitrate_limit) {
656 			ms_message("VideoStream[%p]: bitrate update will change video configuration, recreate graph", obj);
657 			video_stream_recreate_graph((VideoStream *)obj);
658 		} else {
659 			int new_bitrate_limit = br_limit < vconf1.bitrate_limit ? br_limit : vconf1.bitrate_limit;
660 			ms_message("VideoStream[%p]: bitrate update won't change video configuration, update limit to %i", obj, new_bitrate_limit);
661 			if (ms_filter_call_method(obj->encoder,MS_FILTER_SET_BITRATE, &new_bitrate_limit) != 0){
662 				ms_warning("Failed to apply bitrate constraint to %s", obj->encoder->desc->name);
663 			}
664 		}
665 	}
666 #endif
667 }
668 
tmmbr_received(const OrtpEventData * evd,void * user_pointer)669 static void tmmbr_received(const OrtpEventData *evd, void *user_pointer) {
670 	MediaStream *ms = (MediaStream *)user_pointer;
671 	switch (rtcp_RTPFB_get_type(evd->packet)) {
672 		case RTCP_RTPFB_TMMBR: {
673 			int tmmbr_mxtbr = (int)rtcp_RTPFB_tmmbr_get_max_bitrate(evd->packet);
674 
675 			ms_message("MediaStream[%p]: received a TMMBR for bitrate %i kbits/s"
676 						, ms, (int)(tmmbr_mxtbr/1000));
677 			apply_bitrate_limit(ms, tmmbr_mxtbr);
678 			break;
679 		}
680 		default:
681 			break;
682 	}
683 }
684 
685 
686 
687