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(¶ms);
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