1 /*****************************************************************************
2 * rtp.c: rtp stream output module
3 *****************************************************************************
4 * Copyright (C) 2003-2004 the VideoLAN team
5 * Copyright © 2007-2008 Rémi Denis-Courmont
7 * Authors: Laurent Aimar <fenrir@via.ecp.fr>
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22 *****************************************************************************/
24 /*****************************************************************************
26 *****************************************************************************/
32 #include <vlc_common.h>
33 #include <vlc_plugin.h>
35 #include <vlc_block.h>
37 #include <vlc_httpd.h>
39 #include <vlc_network.h>
41 #include <vlc_strings.h>
50 # include <sys/types.h>
53 #ifdef HAVE_ARPA_INET_H
54 # include <arpa/inet.h>
56 #ifdef HAVE_LINUX_DCCP_H
57 # include <linux/dccp.h>
60 # define IPPROTO_DCCP 33
62 #ifndef IPPROTO_UDPLITE
63 # define IPPROTO_UDPLITE 136
70 /*****************************************************************************
72 *****************************************************************************/
74 #define DEST_TEXT N_("Destination")
75 #define DEST_LONGTEXT N_( \
76 "This is the output URL that will be used." )
77 #define SDP_TEXT N_("SDP")
78 #define SDP_LONGTEXT N_( \
79 "This allows you to specify how the SDP (Session Descriptor) for this RTP "\
80 "session will be made available. You must use an url: http://location to " \
81 "access the SDP via HTTP, rtsp://location for RTSP access, and sap:// " \
82 "for the SDP to be announced via SAP." )
83 #define SAP_TEXT N_("SAP announcing")
84 #define SAP_LONGTEXT N_("Announce this session with SAP.")
85 #define MUX_TEXT N_("Muxer")
86 #define MUX_LONGTEXT N_( \
87 "This allows you to specify the muxer used for the streaming output. " \
88 "Default is to use no muxer (standard RTP stream)." )
90 #define NAME_TEXT N_("Session name")
91 #define NAME_LONGTEXT N_( \
92 "This is the name of the session that will be announced in the SDP " \
93 "(Session Descriptor)." )
94 #define DESC_TEXT N_("Session description")
95 #define DESC_LONGTEXT N_( \
96 "This allows you to give a short description with details about the stream, " \
97 "that will be announced in the SDP (Session Descriptor)." )
98 #define URL_TEXT N_("Session URL")
99 #define URL_LONGTEXT N_( \
100 "This allows you to give an URL with more details about the stream " \
101 "(often the website of the streaming organization), that will " \
102 "be announced in the SDP (Session Descriptor)." )
103 #define EMAIL_TEXT N_("Session email")
104 #define EMAIL_LONGTEXT N_( \
105 "This allows you to give a contact mail address for the stream, that will " \
106 "be announced in the SDP (Session Descriptor)." )
107 #define PHONE_TEXT N_("Session phone number")
108 #define PHONE_LONGTEXT N_( \
109 "This allows you to give a contact telephone number for the stream, that will " \
110 "be announced in the SDP (Session Descriptor)." )
112 #define PORT_TEXT N_("Port")
113 #define PORT_LONGTEXT N_( \
114 "This allows you to specify the base port for the RTP streaming." )
115 #define PORT_AUDIO_TEXT N_("Audio port")
116 #define PORT_AUDIO_LONGTEXT N_( \
117 "This allows you to specify the default audio port for the RTP streaming." )
118 #define PORT_VIDEO_TEXT N_("Video port")
119 #define PORT_VIDEO_LONGTEXT N_( \
120 "This allows you to specify the default video port for the RTP streaming." )
122 #define TTL_TEXT N_("Hop limit (TTL)")
123 #define TTL_LONGTEXT N_( \
124 "This is the hop limit (also known as \"Time-To-Live\" or TTL) of " \
125 "the multicast packets sent by the stream output (-1 = use operating " \
126 "system built-in default).")
128 #define RTCP_MUX_TEXT N_("RTP/RTCP multiplexing")
129 #define RTCP_MUX_LONGTEXT N_( \
130 "This sends and receives RTCP packet multiplexed over the same port " \
133 #define CACHING_TEXT N_("Caching value (ms)")
134 #define CACHING_LONGTEXT N_( \
135 "Default caching value for outbound RTP streams. This " \
136 "value should be set in milliseconds." )
138 #define PROTO_TEXT N_("Transport protocol")
139 #define PROTO_LONGTEXT N_( \
140 "This selects which transport protocol to use for RTP." )
142 #define SRTP_KEY_TEXT N_("SRTP key (hexadecimal)")
143 #define SRTP_KEY_LONGTEXT N_( \
144 "RTP packets will be integrity-protected and ciphered "\
145 "with this Secure RTP master shared secret key.")
147 #define SRTP_SALT_TEXT N_("SRTP salt (hexadecimal)")
148 #define SRTP_SALT_LONGTEXT N_( \
149 "Secure RTP requires a (non-secret) master salt value.")
151 static const char *const ppsz_protos
[] = {
152 "dccp", "sctp", "tcp", "udp", "udplite",
155 static const char *const ppsz_protocols
[] = {
156 "DCCP", "SCTP", "TCP", "UDP", "UDP-Lite",
159 #define RFC3016_TEXT N_("MP4A LATM")
160 #define RFC3016_LONGTEXT N_( \
161 "This allows you to stream MPEG4 LATM audio streams (see RFC3016)." )
163 static int Open ( vlc_object_t
* );
164 static void Close( vlc_object_t
* );
166 #define SOUT_CFG_PREFIX "sout-rtp-"
167 #define MAX_EMPTY_BLOCKS 200
170 set_shortname( N_("RTP"))
171 set_description( N_("RTP stream output") )
172 set_capability( "sout stream", 0 )
173 add_shortcut( "rtp" )
174 set_category( CAT_SOUT
)
175 set_subcategory( SUBCAT_SOUT_STREAM
)
177 add_string( SOUT_CFG_PREFIX
"dst", "", NULL
, DEST_TEXT
,
178 DEST_LONGTEXT
, true )
179 add_string( SOUT_CFG_PREFIX
"sdp", "", NULL
, SDP_TEXT
,
181 add_string( SOUT_CFG_PREFIX
"mux", "", NULL
, MUX_TEXT
,
183 add_bool( SOUT_CFG_PREFIX
"sap", false, NULL
, SAP_TEXT
, SAP_LONGTEXT
,
186 add_string( SOUT_CFG_PREFIX
"name", "", NULL
, NAME_TEXT
,
187 NAME_LONGTEXT
, true )
188 add_string( SOUT_CFG_PREFIX
"description", "", NULL
, DESC_TEXT
,
189 DESC_LONGTEXT
, true )
190 add_string( SOUT_CFG_PREFIX
"url", "", NULL
, URL_TEXT
,
192 add_string( SOUT_CFG_PREFIX
"email", "", NULL
, EMAIL_TEXT
,
193 EMAIL_LONGTEXT
, true )
194 add_string( SOUT_CFG_PREFIX
"phone", "", NULL
, PHONE_TEXT
,
195 PHONE_LONGTEXT
, true )
197 add_string( SOUT_CFG_PREFIX
"proto", "udp", NULL
, PROTO_TEXT
,
198 PROTO_LONGTEXT
, false )
199 change_string_list( ppsz_protos
, ppsz_protocols
, NULL
)
200 add_integer( SOUT_CFG_PREFIX
"port", 5004, NULL
, PORT_TEXT
,
201 PORT_LONGTEXT
, true )
202 add_integer( SOUT_CFG_PREFIX
"port-audio", 0, NULL
, PORT_AUDIO_TEXT
,
203 PORT_AUDIO_LONGTEXT
, true )
204 add_integer( SOUT_CFG_PREFIX
"port-video", 0, NULL
, PORT_VIDEO_TEXT
,
205 PORT_VIDEO_LONGTEXT
, true )
207 add_integer( SOUT_CFG_PREFIX
"ttl", -1, NULL
, TTL_TEXT
,
209 add_bool( SOUT_CFG_PREFIX
"rtcp-mux", false, NULL
,
210 RTCP_MUX_TEXT
, RTCP_MUX_LONGTEXT
, false )
211 add_integer( SOUT_CFG_PREFIX
"caching", DEFAULT_PTS_DELAY
/ 1000, NULL
,
212 CACHING_TEXT
, CACHING_LONGTEXT
, true )
215 add_string( SOUT_CFG_PREFIX
"key", "", NULL
,
216 SRTP_KEY_TEXT
, SRTP_KEY_LONGTEXT
, false )
217 add_string( SOUT_CFG_PREFIX
"salt", "", NULL
,
218 SRTP_SALT_TEXT
, SRTP_SALT_LONGTEXT
, false )
221 add_bool( SOUT_CFG_PREFIX
"mp4a-latm", false, NULL
, RFC3016_TEXT
,
222 RFC3016_LONGTEXT
, false )
224 set_callbacks( Open
, Close
)
227 /*****************************************************************************
228 * Exported prototypes
229 *****************************************************************************/
230 static const char *const ppsz_sout_options
[] = {
231 "dst", "name", "port", "port-audio", "port-video", "*sdp", "ttl", "mux",
232 "sap", "description", "url", "email", "phone",
233 "proto", "rtcp-mux", "caching", "key", "salt",
237 static sout_stream_id_t
*Add ( sout_stream_t
*, es_format_t
* );
238 static int Del ( sout_stream_t
*, sout_stream_id_t
* );
239 static int Send( sout_stream_t
*, sout_stream_id_t
*,
241 static sout_stream_id_t
*MuxAdd ( sout_stream_t
*, es_format_t
* );
242 static int MuxDel ( sout_stream_t
*, sout_stream_id_t
* );
243 static int MuxSend( sout_stream_t
*, sout_stream_id_t
*,
246 static sout_access_out_t
*GrabberCreate( sout_stream_t
*p_sout
);
247 static void* ThreadSend( void * );
248 static void *rtp_listen_thread( void * );
250 static void SDPHandleUrl( sout_stream_t
*, const char * );
252 static int SapSetup( sout_stream_t
*p_stream
);
253 static int FileSetup( sout_stream_t
*p_stream
);
254 static int HttpSetup( sout_stream_t
*p_stream
, const vlc_url_t
* );
256 struct sout_stream_sys_t
260 vlc_mutex_t lock_sdp
;
267 session_descriptor_t
*p_session
;
270 httpd_host_t
*p_httpd_host
;
271 httpd_file_t
*p_httpd_file
;
276 /* RTSP NPT and timestamp computations */
277 mtime_t i_npt_zero
; /* when NPT=0 packet is sent */
278 int64_t i_pts_zero
; /* predicts PTS of NPT=0 packet */
279 int64_t i_pts_offset
; /* matches actual PTS to prediction */
283 char *psz_destination
;
284 uint32_t payload_bitmap
;
286 uint16_t i_port_audio
;
287 uint16_t i_port_video
;
293 /* in case we do TS/PS over rtp */
295 sout_access_out_t
*p_grab
;
301 sout_stream_id_t
**es
;
304 typedef int (*pf_rtp_packetizer_t
)( sout_stream_id_t
*, block_t
* );
306 typedef struct rtp_sink_t
312 struct sout_stream_id_t
314 sout_stream_t
*p_stream
;
317 uint8_t i_payload_type
;
319 uint32_t i_ts_offset
;
323 uint16_t i_seq_sent_next
;
334 /* Packetizer specific fields */
337 srtp_session_t
*srtp
;
339 pf_rtp_packetizer_t pf_packetize
;
343 vlc_mutex_t lock_sink
;
346 rtsp_stream_id_t
*rtsp_id
;
352 block_fifo_t
*p_fifo
;
356 /*****************************************************************************
358 *****************************************************************************/
359 static int Open( vlc_object_t
*p_this
)
361 sout_stream_t
*p_stream
= (sout_stream_t
*)p_this
;
362 sout_instance_t
*p_sout
= p_stream
->p_sout
;
363 sout_stream_sys_t
*p_sys
= NULL
;
364 config_chain_t
*p_cfg
= NULL
;
368 config_ChainParse( p_stream
, SOUT_CFG_PREFIX
,
369 ppsz_sout_options
, p_stream
->p_cfg
);
371 p_sys
= malloc( sizeof( sout_stream_sys_t
) );
375 p_sys
->psz_destination
= var_GetNonEmptyString( p_stream
, SOUT_CFG_PREFIX
"dst" );
377 p_sys
->i_port
= var_GetInteger( p_stream
, SOUT_CFG_PREFIX
"port" );
378 p_sys
->i_port_audio
= var_GetInteger( p_stream
, SOUT_CFG_PREFIX
"port-audio" );
379 p_sys
->i_port_video
= var_GetInteger( p_stream
, SOUT_CFG_PREFIX
"port-video" );
380 p_sys
->rtcp_mux
= var_GetBool( p_stream
, SOUT_CFG_PREFIX
"rtcp-mux" );
382 if( p_sys
->i_port_audio
&& p_sys
->i_port_video
== p_sys
->i_port_audio
)
384 msg_Err( p_stream
, "audio and video RTP port must be distinct" );
385 free( p_sys
->psz_destination
);
390 for( p_cfg
= p_stream
->p_cfg
; p_cfg
!= NULL
; p_cfg
= p_cfg
->p_next
)
392 if( !strcmp( p_cfg
->psz_name
, "sdp" )
393 && ( p_cfg
->psz_value
!= NULL
)
394 && !strncasecmp( p_cfg
->psz_value
, "rtsp:", 5 ) )
402 psz
= var_GetNonEmptyString( p_stream
, SOUT_CFG_PREFIX
"sdp" );
405 if( !strncasecmp( psz
, "rtsp:", 5 ) )
411 /* Transport protocol */
412 p_sys
->proto
= IPPROTO_UDP
;
413 psz
= var_GetNonEmptyString (p_stream
, SOUT_CFG_PREFIX
"proto");
415 if ((psz
== NULL
) || !strcasecmp (psz
, "udp"))
416 (void)0; /* default */
418 if (!strcasecmp (psz
, "dccp"))
420 p_sys
->proto
= IPPROTO_DCCP
;
421 p_sys
->rtcp_mux
= true; /* Force RTP/RTCP mux */
425 if (!strcasecmp (psz
, "sctp"))
427 p_sys
->proto
= IPPROTO_TCP
;
428 p_sys
->rtcp_mux
= true; /* Force RTP/RTCP mux */
433 if (!strcasecmp (psz
, "tcp"))
435 p_sys
->proto
= IPPROTO_TCP
;
436 p_sys
->rtcp_mux
= true; /* Force RTP/RTCP mux */
440 if (!strcasecmp (psz
, "udplite") || !strcasecmp (psz
, "udp-lite"))
441 p_sys
->proto
= IPPROTO_UDPLITE
;
443 msg_Warn (p_this
, "unknown or unsupported transport protocol \"%s\"",
446 var_Create (p_this
, "dccp-service", VLC_VAR_STRING
);
448 if( ( p_sys
->psz_destination
== NULL
) && !b_rtsp
)
450 msg_Err( p_stream
, "missing destination and not in RTSP mode" );
455 p_sys
->i_ttl
= var_GetInteger( p_stream
, SOUT_CFG_PREFIX
"ttl" );
456 if( p_sys
->i_ttl
== -1 )
458 /* Normally, we should let the default hop limit up to the core,
459 * but we have to know it to write our RTSP headers properly,
460 * which is why we ask the core. FIXME: broken when neither
461 * sout-rtp-ttl nor ttl are set. */
462 p_sys
->i_ttl
= var_InheritInteger( p_stream
, "ttl" );
465 p_sys
->b_latm
= var_GetBool( p_stream
, SOUT_CFG_PREFIX
"mp4a-latm" );
467 /* NPT=0 time will be determined when we packetize the first packet
468 * (of any ES). But we want to be able to report rtptime in RTSP
469 * without waiting. So until then, we use an arbitrary reference
470 * PTS for timestamp computations, and then actual PTS will catch
471 * up using offsets. */
472 p_sys
->i_npt_zero
= VLC_TS_INVALID
;
473 p_sys
->i_pts_zero
= mdate(); /* arbitrary value, could probably be
475 p_sys
->payload_bitmap
= 0xFFFFFFFF;
479 p_sys
->psz_sdp
= NULL
;
481 p_sys
->b_export_sap
= false;
482 p_sys
->p_session
= NULL
;
483 p_sys
->psz_sdp_file
= NULL
;
485 p_sys
->p_httpd_host
= NULL
;
486 p_sys
->p_httpd_file
= NULL
;
488 p_stream
->p_sys
= p_sys
;
490 vlc_mutex_init( &p_sys
->lock_sdp
);
491 vlc_mutex_init( &p_sys
->lock_ts
);
492 vlc_mutex_init( &p_sys
->lock_es
);
494 psz
= var_GetNonEmptyString( p_stream
, SOUT_CFG_PREFIX
"mux" );
497 sout_stream_id_t
*id
;
499 /* Check muxer type */
500 if( strncasecmp( psz
, "ps", 2 )
501 && strncasecmp( psz
, "mpeg1", 5 )
502 && strncasecmp( psz
, "ts", 2 ) )
504 msg_Err( p_stream
, "unsupported muxer type for RTP (only TS/PS)" );
506 vlc_mutex_destroy( &p_sys
->lock_sdp
);
507 vlc_mutex_destroy( &p_sys
->lock_es
);
508 free( p_sys
->psz_destination
);
513 p_sys
->p_grab
= GrabberCreate( p_stream
);
514 p_sys
->p_mux
= sout_MuxNew( p_sout
, psz
, p_sys
->p_grab
);
517 if( p_sys
->p_mux
== NULL
)
519 msg_Err( p_stream
, "cannot create muxer" );
520 sout_AccessOutDelete( p_sys
->p_grab
);
521 vlc_mutex_destroy( &p_sys
->lock_sdp
);
522 vlc_mutex_destroy( &p_sys
->lock_es
);
523 free( p_sys
->psz_destination
);
528 id
= Add( p_stream
, NULL
);
531 sout_MuxDelete( p_sys
->p_mux
);
532 sout_AccessOutDelete( p_sys
->p_grab
);
533 vlc_mutex_destroy( &p_sys
->lock_sdp
);
534 vlc_mutex_destroy( &p_sys
->lock_es
);
535 free( p_sys
->psz_destination
);
540 p_sys
->packet
= NULL
;
542 p_stream
->pf_add
= MuxAdd
;
543 p_stream
->pf_del
= MuxDel
;
544 p_stream
->pf_send
= MuxSend
;
549 p_sys
->p_grab
= NULL
;
551 p_stream
->pf_add
= Add
;
552 p_stream
->pf_del
= Del
;
553 p_stream
->pf_send
= Send
;
556 if( var_GetBool( p_stream
, SOUT_CFG_PREFIX
"sap" ) )
557 SDPHandleUrl( p_stream
, "sap" );
559 psz
= var_GetNonEmptyString( p_stream
, SOUT_CFG_PREFIX
"sdp" );
562 config_chain_t
*p_cfg
;
564 SDPHandleUrl( p_stream
, psz
);
566 for( p_cfg
= p_stream
->p_cfg
; p_cfg
!= NULL
; p_cfg
= p_cfg
->p_next
)
568 if( !strcmp( p_cfg
->psz_name
, "sdp" ) )
570 if( p_cfg
->psz_value
== NULL
|| *p_cfg
->psz_value
== '\0' )
573 /* needed both :sout-rtp-sdp= and rtp{sdp=} can be used */
574 if( !strcmp( p_cfg
->psz_value
, psz
) )
577 SDPHandleUrl( p_stream
, p_cfg
->psz_value
);
583 /* update p_sout->i_out_pace_nocontrol */
584 p_stream
->p_sout
->i_out_pace_nocontrol
++;
589 /*****************************************************************************
591 *****************************************************************************/
592 static void Close( vlc_object_t
* p_this
)
594 sout_stream_t
*p_stream
= (sout_stream_t
*)p_this
;
595 sout_stream_sys_t
*p_sys
= p_stream
->p_sys
;
597 /* update p_sout->i_out_pace_nocontrol */
598 p_stream
->p_sout
->i_out_pace_nocontrol
--;
602 assert( p_sys
->i_es
== 1 );
604 sout_MuxDelete( p_sys
->p_mux
);
605 Del( p_stream
, p_sys
->es
[0] );
606 sout_AccessOutDelete( p_sys
->p_grab
);
610 block_Release( p_sys
->packet
);
612 if( p_sys
->b_export_sap
)
615 SapSetup( p_stream
);
619 if( p_sys
->rtsp
!= NULL
)
620 RtspUnsetup( p_sys
->rtsp
);
622 vlc_mutex_destroy( &p_sys
->lock_sdp
);
623 vlc_mutex_destroy( &p_sys
->lock_ts
);
624 vlc_mutex_destroy( &p_sys
->lock_es
);
626 if( p_sys
->p_httpd_file
)
627 httpd_FileDelete( p_sys
->p_httpd_file
);
629 if( p_sys
->p_httpd_host
)
630 httpd_HostDelete( p_sys
->p_httpd_host
);
632 free( p_sys
->psz_sdp
);
634 if( p_sys
->psz_sdp_file
!= NULL
)
637 unlink( p_sys
->psz_sdp_file
);
639 free( p_sys
->psz_sdp_file
);
641 free( p_sys
->psz_destination
);
645 /*****************************************************************************
647 *****************************************************************************/
648 static void SDPHandleUrl( sout_stream_t
*p_stream
, const char *psz_url
)
650 sout_stream_sys_t
*p_sys
= p_stream
->p_sys
;
653 vlc_UrlParse( &url
, psz_url
, 0 );
654 if( url
.psz_protocol
&& !strcasecmp( url
.psz_protocol
, "http" ) )
656 if( p_sys
->p_httpd_file
)
658 msg_Err( p_stream
, "you can use sdp=http:// only once" );
662 if( HttpSetup( p_stream
, &url
) )
664 msg_Err( p_stream
, "cannot export SDP as HTTP" );
667 else if( url
.psz_protocol
&& !strcasecmp( url
.psz_protocol
, "rtsp" ) )
669 if( p_sys
->rtsp
!= NULL
)
671 msg_Err( p_stream
, "you can use sdp=rtsp:// only once" );
675 /* FIXME test if destination is multicast or no destination at all */
676 p_sys
->rtsp
= RtspSetup( p_stream
, &url
);
677 if( p_sys
->rtsp
== NULL
)
678 msg_Err( p_stream
, "cannot export SDP as RTSP" );
680 if( p_sys
->p_mux
!= NULL
)
682 sout_stream_id_t
*id
= p_sys
->es
[0];
683 rtsp_stream_id_t
*rtsp_id
= RtspAddId( p_sys
->rtsp
, id
, GetDWBE( id
->ssrc
),
684 p_sys
->psz_destination
, p_sys
->i_ttl
,
685 id
->i_port
, id
->i_port
+ 1 );
686 vlc_mutex_lock( &p_sys
->lock_es
);
687 id
->rtsp_id
= rtsp_id
;
688 vlc_mutex_unlock( &p_sys
->lock_es
);
691 else if( ( url
.psz_protocol
&& !strcasecmp( url
.psz_protocol
, "sap" ) ) ||
692 ( url
.psz_host
&& !strcasecmp( url
.psz_host
, "sap" ) ) )
694 p_sys
->b_export_sap
= true;
695 SapSetup( p_stream
);
697 else if( url
.psz_protocol
&& !strcasecmp( url
.psz_protocol
, "file" ) )
699 if( p_sys
->psz_sdp_file
!= NULL
)
701 msg_Err( p_stream
, "you can use sdp=file:// only once" );
704 p_sys
->psz_sdp_file
= make_path( psz_url
);
705 if( p_sys
->psz_sdp_file
== NULL
)
707 FileSetup( p_stream
);
711 msg_Warn( p_stream
, "unknown protocol for SDP (%s)",
716 vlc_UrlClean( &url
);
719 /*****************************************************************************
721 *****************************************************************************/
723 char *SDPGenerate( sout_stream_t
*p_stream
, const char *rtsp_url
)
725 sout_stream_sys_t
*p_sys
= p_stream
->p_sys
;
726 char *psz_sdp
= NULL
;
727 struct sockaddr_storage dst
;
731 * When we have a fixed destination (typically when we do multicast),
732 * we need to put the actual port numbers in the SDP.
733 * When there is no fixed destination, we only support RTSP unicast
734 * on-demand setup, so we should rather let the clients decide which ports
736 * When there is both a fixed destination and RTSP unicast, we need to
737 * put port numbers used by the fixed destination, otherwise the SDP would
738 * become totally incorrect for multicast use. It should be noted that
739 * port numbers from SDP with RTSP are only "recommendation" from the
740 * server to the clients (per RFC2326), so only broken clients will fail
741 * to handle this properly. There is no solution but to use two differents
742 * output chain with two different RTSP URLs if you need to handle this
747 vlc_mutex_lock( &p_sys
->lock_es
);
748 if( unlikely(p_sys
->i_es
== 0 || (rtsp_url
!= NULL
&& !p_sys
->es
[0]->rtsp_id
)) )
749 goto out
; /* hmm... */
751 if( p_sys
->psz_destination
!= NULL
)
755 /* Oh boy, this is really ugly! */
756 dstlen
= sizeof( dst
);
757 if( p_sys
->es
[0]->listen
.fd
!= NULL
)
758 getsockname( p_sys
->es
[0]->listen
.fd
[0],
759 (struct sockaddr
*)&dst
, &dstlen
);
761 getpeername( p_sys
->es
[0]->sinkv
[0].rtp_fd
,
762 (struct sockaddr
*)&dst
, &dstlen
);
768 /* Check against URL format rtsp://[<ipv6>]:<port>/<path> */
769 bool ipv6
= rtsp_url
!= NULL
&& strlen( rtsp_url
) > 7
770 && rtsp_url
[7] == '[';
772 /* Dummy destination address for RTSP */
773 dstlen
= ipv6
? sizeof( struct sockaddr_in6
)
774 : sizeof( struct sockaddr_in
);
775 memset (&dst
, 0, dstlen
);
776 dst
.ss_family
= ipv6
? AF_INET6
: AF_INET
;
782 psz_sdp
= vlc_sdp_Start( VLC_OBJECT( p_stream
), SOUT_CFG_PREFIX
,
783 NULL
, 0, (struct sockaddr
*)&dst
, dstlen
);
784 if( psz_sdp
== NULL
)
787 /* TODO: a=source-filter */
788 if( p_sys
->rtcp_mux
)
789 sdp_AddAttribute( &psz_sdp
, "rtcp-mux", NULL
);
791 if( rtsp_url
!= NULL
)
792 sdp_AddAttribute ( &psz_sdp
, "control", "%s", rtsp_url
);
794 const char *proto
= "RTP/AVP"; /* protocol */
795 if( rtsp_url
== NULL
)
797 switch( p_sys
->proto
)
802 proto
= "TCP/RTP/AVP";
805 proto
= "DCCP/RTP/AVP";
807 case IPPROTO_UDPLITE
:
812 for( i
= 0; i
< p_sys
->i_es
; i
++ )
814 sout_stream_id_t
*id
= p_sys
->es
[i
];
815 const char *mime_major
; /* major MIME type */
820 mime_major
= "video";
823 mime_major
= "audio";
832 sdp_AddMedia( &psz_sdp
, mime_major
, proto
, inclport
* id
->i_port
,
833 id
->i_payload_type
, false, id
->i_bitrate
,
834 id
->psz_enc
, id
->i_clock_rate
, id
->i_channels
,
837 /* cf RFC4566 §5.14 */
838 if( inclport
&& !p_sys
->rtcp_mux
&& (id
->i_port
& 1) )
839 sdp_AddAttribute ( &psz_sdp
, "rtcp", "%u", id
->i_port
+ 1 );
841 if( rtsp_url
!= NULL
)
843 char *track_url
= RtspAppendTrackPath( id
->rtsp_id
, rtsp_url
);
844 if( track_url
!= NULL
)
846 sdp_AddAttribute ( &psz_sdp
, "control", "%s", track_url
);
852 if( id
->listen
.fd
!= NULL
)
853 sdp_AddAttribute( &psz_sdp
, "setup", "passive" );
854 if( p_sys
->proto
== IPPROTO_DCCP
)
855 sdp_AddAttribute( &psz_sdp
, "dccp-service-code",
856 "SC:RTP%c", toupper( mime_major
[0] ) );
860 vlc_mutex_unlock( &p_sys
->lock_es
);
864 /*****************************************************************************
866 *****************************************************************************/
868 static void sprintf_hexa( char *s
, uint8_t *p_data
, int i_data
)
870 static const char hex
[16] = "0123456789abcdef";
872 for( int i
= 0; i
< i_data
; i
++ )
874 s
[2*i
+0] = hex
[(p_data
[i
]>>4)&0xf];
875 s
[2*i
+1] = hex
[(p_data
[i
] )&0xf];
881 * Shrink the MTU down to a fixed packetization time (for audio).
884 rtp_set_ptime (sout_stream_id_t
*id
, unsigned ptime_ms
, size_t bytes
)
886 /* Samples per second */
887 size_t spl
= (id
->i_clock_rate
- 1) * ptime_ms
/ 1000 + 1;
888 bytes
*= id
->i_channels
;
891 if (spl
< rtp_mtu (id
)) /* MTU is big enough for ptime */
892 id
->i_mtu
= 12 + spl
;
893 else /* MTU is too small for ptime, align to a sample boundary */
894 id
->i_mtu
= 12 + (((id
->i_mtu
- 12) / bytes
) * bytes
);
897 uint32_t rtp_compute_ts( const sout_stream_id_t
*id
, int64_t i_pts
)
899 /* NOTE: this plays nice with offsets because the calculations are
901 return i_pts
* (int64_t)id
->i_clock_rate
/ CLOCK_FREQ
;
904 /** Add an ES as a new RTP stream */
905 static sout_stream_id_t
*Add( sout_stream_t
*p_stream
, es_format_t
*p_fmt
)
907 /* NOTE: As a special case, if we use a non-RTP
908 * mux (TS/PS), then p_fmt is NULL. */
909 sout_stream_sys_t
*p_sys
= p_stream
->p_sys
;
912 if (0 == p_sys
->payload_bitmap
)
914 msg_Err (p_stream
, "too many RTP elementary streams");
918 sout_stream_id_t
*id
= malloc( sizeof( *id
) );
919 if( unlikely(id
== NULL
) )
921 id
->p_stream
= p_stream
;
923 /* Look for free dymanic payload type */
924 id
->i_payload_type
= 96 + clz32 (p_sys
->payload_bitmap
);
925 assert (id
->i_payload_type
< 128);
927 vlc_rand_bytes (&id
->i_sequence
, sizeof (id
->i_sequence
));
928 vlc_rand_bytes (id
->ssrc
, sizeof (id
->ssrc
));
932 id
->i_clock_rate
= 90000; /* most common case for video */
936 id
->i_cat
= p_fmt
->i_cat
;
937 if( p_fmt
->i_cat
== AUDIO_ES
)
939 id
->i_clock_rate
= p_fmt
->audio
.i_rate
;
940 id
->i_channels
= p_fmt
->audio
.i_channels
;
942 id
->i_bitrate
= p_fmt
->i_bitrate
/1000; /* Stream bitrate in kbps */
946 id
->i_cat
= VIDEO_ES
;
950 id
->i_mtu
= var_InheritInteger( p_stream
, "mtu" );
951 if( id
->i_mtu
<= 12 + 16 )
952 id
->i_mtu
= 576 - 20 - 8; /* pessimistic */
953 msg_Dbg( p_stream
, "maximum RTP packet size: %d bytes", id
->i_mtu
);
955 id
->pf_packetize
= NULL
;
960 vlc_mutex_init( &id
->lock_sink
);
965 id
->listen
.fd
= NULL
;
968 (int64_t)1000 * var_GetInteger( p_stream
, SOUT_CFG_PREFIX
"caching");
971 char *key
= var_CreateGetNonEmptyString (p_stream
, SOUT_CFG_PREFIX
"key");
974 id
->srtp
= srtp_create (SRTP_ENCR_AES_CM
, SRTP_AUTH_HMAC_SHA1
, 10,
975 SRTP_PRF_AES_CM
, SRTP_RCC_MODE1
);
976 if (id
->srtp
== NULL
)
982 char *salt
= var_CreateGetNonEmptyString (p_stream
, SOUT_CFG_PREFIX
"salt");
983 errno
= srtp_setkeystring (id
->srtp
, key
, salt
? salt
: "");
988 msg_Err (p_stream
, "bad SRTP key/salt combination (%m)");
991 id
->i_sequence
= 0; /* FIXME: awful hack for libvlc_srtp */
995 id
->i_seq_sent_next
= id
->i_sequence
;
997 if( p_sys
->psz_destination
!= NULL
)
999 /* Choose the port */
1000 uint16_t i_port
= 0;
1004 if( p_fmt
->i_cat
== AUDIO_ES
&& p_sys
->i_port_audio
> 0 )
1005 i_port
= p_sys
->i_port_audio
;
1007 if( p_fmt
->i_cat
== VIDEO_ES
&& p_sys
->i_port_video
> 0 )
1008 i_port
= p_sys
->i_port_video
;
1010 /* We do not need the ES lock (p_sys->lock_es) here, because
1011 * this is the only one thread that can *modify* the ES table.
1012 * The ES lock protects the other threads from our modifications
1013 * (TAB_APPEND, TAB_REMOVE). */
1014 for (int i
= 0; i_port
&& (i
< p_sys
->i_es
); i
++)
1015 if (i_port
== p_sys
->es
[i
]->i_port
)
1016 i_port
= 0; /* Port already in use! */
1017 for (uint16_t p
= p_sys
->i_port
; i_port
== 0; p
+= 2)
1021 msg_Err (p_stream
, "too many RTP elementary streams");
1025 for (int i
= 0; i_port
&& (i
< p_sys
->i_es
); i
++)
1026 if (p
== p_sys
->es
[i
]->i_port
)
1030 id
->i_port
= i_port
;
1032 int type
= SOCK_STREAM
;
1034 switch( p_sys
->proto
)
1042 case VIDEO_ES
: code
= "RTPV"; break;
1043 case AUDIO_ES
: code
= "RTPARTPV"; break;
1044 case SPU_ES
: code
= "RTPTRTPV"; break;
1045 default: code
= "RTPORTPV"; break;
1047 var_SetString (p_stream
, "dccp-service", code
);
1049 } /* fall through */
1052 id
->listen
.fd
= net_Listen( VLC_OBJECT(p_stream
),
1053 p_sys
->psz_destination
, i_port
,
1054 type
, p_sys
->proto
);
1055 if( id
->listen
.fd
== NULL
)
1057 msg_Err( p_stream
, "passive COMEDIA RTP socket failed" );
1060 if( vlc_clone( &id
->listen
.thread
, rtp_listen_thread
, id
,
1061 VLC_THREAD_PRIORITY_LOW
) )
1063 net_ListenClose( id
->listen
.fd
);
1064 id
->listen
.fd
= NULL
;
1071 int ttl
= (p_sys
->i_ttl
>= 0) ? p_sys
->i_ttl
: -1;
1072 int fd
= net_ConnectDgram( p_stream
, p_sys
->psz_destination
,
1073 i_port
, ttl
, p_sys
->proto
);
1076 msg_Err( p_stream
, "cannot create RTP socket" );
1079 /* Ignore any unexpected incoming packet (including RTCP-RR
1080 * packets in case of rtcp-mux) */
1081 setsockopt (fd
, SOL_SOCKET
, SO_RCVBUF
, &(int){ 0 },
1083 rtp_add_sink( id
, fd
, p_sys
->rtcp_mux
, NULL
);
1090 char *psz
= var_GetNonEmptyString( p_stream
, SOUT_CFG_PREFIX
"mux" );
1092 if( psz
== NULL
) /* Uho! */
1095 if( strncmp( psz
, "ts", 2 ) == 0 )
1097 id
->i_payload_type
= 33;
1098 id
->psz_enc
= "MP2T";
1102 id
->psz_enc
= "MP2P";
1107 switch( p_fmt
->i_codec
)
1109 case VLC_CODEC_MULAW
:
1110 if( p_fmt
->audio
.i_channels
== 1 && p_fmt
->audio
.i_rate
== 8000 )
1111 id
->i_payload_type
= 0;
1112 id
->psz_enc
= "PCMU";
1113 id
->pf_packetize
= rtp_packetize_split
;
1114 rtp_set_ptime (id
, 20, 1);
1116 case VLC_CODEC_ALAW
:
1117 if( p_fmt
->audio
.i_channels
== 1 && p_fmt
->audio
.i_rate
== 8000 )
1118 id
->i_payload_type
= 8;
1119 id
->psz_enc
= "PCMA";
1120 id
->pf_packetize
= rtp_packetize_split
;
1121 rtp_set_ptime (id
, 20, 1);
1123 case VLC_CODEC_S16B
:
1124 case VLC_CODEC_S16L
:
1125 if( p_fmt
->audio
.i_channels
== 1 && p_fmt
->audio
.i_rate
== 44100 )
1127 id
->i_payload_type
= 11;
1129 else if( p_fmt
->audio
.i_channels
== 2 &&
1130 p_fmt
->audio
.i_rate
== 44100 )
1132 id
->i_payload_type
= 10;
1134 id
->psz_enc
= "L16";
1135 if( p_fmt
->i_codec
== VLC_CODEC_S16B
)
1136 id
->pf_packetize
= rtp_packetize_split
;
1138 id
->pf_packetize
= rtp_packetize_swab
;
1139 rtp_set_ptime (id
, 20, 2);
1143 id
->pf_packetize
= rtp_packetize_split
;
1144 rtp_set_ptime (id
, 20, 1);
1146 case VLC_CODEC_MPGA
:
1147 id
->i_payload_type
= 14;
1148 id
->psz_enc
= "MPA";
1149 id
->i_clock_rate
= 90000; /* not 44100 */
1150 id
->pf_packetize
= rtp_packetize_mpa
;
1152 case VLC_CODEC_MPGV
:
1153 id
->i_payload_type
= 32;
1154 id
->psz_enc
= "MPV";
1155 id
->pf_packetize
= rtp_packetize_mpv
;
1157 case VLC_CODEC_ADPCM_G726
:
1158 switch( p_fmt
->i_bitrate
/ 1000 )
1161 id
->psz_enc
= "G726-16";
1162 id
->pf_packetize
= rtp_packetize_g726_16
;
1165 id
->psz_enc
= "G726-24";
1166 id
->pf_packetize
= rtp_packetize_g726_24
;
1169 id
->psz_enc
= "G726-32";
1170 id
->pf_packetize
= rtp_packetize_g726_32
;
1173 id
->psz_enc
= "G726-40";
1174 id
->pf_packetize
= rtp_packetize_g726_40
;
1177 msg_Err( p_stream
, "cannot add this stream (unsupported "
1178 "G.726 bit rate: %u)", p_fmt
->i_bitrate
);
1183 id
->psz_enc
= "ac3";
1184 id
->pf_packetize
= rtp_packetize_ac3
;
1186 case VLC_CODEC_H263
:
1187 id
->psz_enc
= "H263-1998";
1188 id
->pf_packetize
= rtp_packetize_h263
;
1190 case VLC_CODEC_H264
:
1191 id
->psz_enc
= "H264";
1192 id
->pf_packetize
= rtp_packetize_h264
;
1193 id
->psz_fmtp
= NULL
;
1195 if( p_fmt
->i_extra
> 0 )
1197 uint8_t *p_buffer
= p_fmt
->p_extra
;
1198 int i_buffer
= p_fmt
->i_extra
;
1199 char *p_64_sps
= NULL
;
1200 char *p_64_pps
= NULL
;
1203 while( i_buffer
> 4 )
1208 while( p_buffer
[0] != 0 || p_buffer
[1] != 0 ||
1213 if( i_buffer
== 0 ) break;
1216 if( i_buffer
< 4 || memcmp(p_buffer
, "\x00\x00\x01", 3 ) )
1218 msg_Dbg( p_stream
, "No startcode found..");
1224 const int i_nal_type
= p_buffer
[0]&0x1f;
1226 msg_Dbg( p_stream
, "we found a startcode for NAL with TYPE:%d", i_nal_type
);
1229 for( i_offset
= 0; i_offset
+2 < i_buffer
; i_offset
++)
1231 if( !memcmp(p_buffer
+ i_offset
, "\x00\x00\x01", 3 ) )
1233 /* we found another startcode */
1234 while( i_offset
> 0 && 0 == p_buffer
[ i_offset
- 1 ] )
1243 msg_Dbg( p_stream
, "No-info found in nal ");
1247 if( i_nal_type
== 7 )
1250 p_64_sps
= vlc_b64_encode_binary( p_buffer
, i_size
);
1251 /* XXX: nothing ensures that i_size >= 4 ?? */
1252 sprintf_hexa( hexa
, &p_buffer
[1], 3 );
1254 else if( i_nal_type
== 8 )
1257 p_64_pps
= vlc_b64_encode_binary( p_buffer
, i_size
);
1263 if( p_64_sps
&& p_64_pps
&&
1264 ( asprintf( &id
->psz_fmtp
,
1265 "packetization-mode=1;profile-level-id=%s;"
1266 "sprop-parameter-sets=%s,%s;", hexa
, p_64_sps
,
1267 p_64_pps
) == -1 ) )
1268 id
->psz_fmtp
= NULL
;
1273 id
->psz_fmtp
= strdup( "packetization-mode=1" );
1276 case VLC_CODEC_MP4V
:
1278 id
->psz_enc
= "MP4V-ES";
1279 id
->pf_packetize
= rtp_packetize_split
;
1280 if( p_fmt
->i_extra
> 0 )
1282 char hexa
[2*p_fmt
->i_extra
+1];
1283 sprintf_hexa( hexa
, p_fmt
->p_extra
, p_fmt
->i_extra
);
1284 if( asprintf( &id
->psz_fmtp
,
1285 "profile-level-id=3; config=%s;", hexa
) == -1 )
1286 id
->psz_fmtp
= NULL
;
1290 case VLC_CODEC_MP4A
:
1294 char hexa
[2*p_fmt
->i_extra
+1];
1296 id
->psz_enc
= "mpeg4-generic";
1297 id
->pf_packetize
= rtp_packetize_mp4a
;
1298 sprintf_hexa( hexa
, p_fmt
->p_extra
, p_fmt
->i_extra
);
1299 if( asprintf( &id
->psz_fmtp
,
1300 "streamtype=5; profile-level-id=15; "
1301 "mode=AAC-hbr; config=%s; SizeLength=13; "
1302 "IndexLength=3; IndexDeltaLength=3; Profile=1;",
1304 id
->psz_fmtp
= NULL
;
1310 unsigned char config
[6];
1311 unsigned int aacsrates
[15] = {
1312 96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050,
1313 16000, 12000, 11025, 8000, 7350, 0, 0 };
1315 for( i
= 0; i
< 15; i
++ )
1316 if( p_fmt
->audio
.i_rate
== aacsrates
[i
] )
1322 config
[3]=p_fmt
->audio
.i_channels
<<4;
1326 id
->psz_enc
= "MP4A-LATM";
1327 id
->pf_packetize
= rtp_packetize_mp4a_latm
;
1328 sprintf_hexa( hexa
, config
, 6 );
1329 if( asprintf( &id
->psz_fmtp
, "profile-level-id=15; "
1330 "object=2; cpresent=0; config=%s", hexa
) == -1 )
1331 id
->psz_fmtp
= NULL
;
1335 case VLC_CODEC_AMR_NB
:
1336 id
->psz_enc
= "AMR";
1337 id
->psz_fmtp
= strdup( "octet-align=1" );
1338 id
->pf_packetize
= rtp_packetize_amr
;
1340 case VLC_CODEC_AMR_WB
:
1341 id
->psz_enc
= "AMR-WB";
1342 id
->psz_fmtp
= strdup( "octet-align=1" );
1343 id
->pf_packetize
= rtp_packetize_amr
;
1345 case VLC_CODEC_SPEEX
:
1346 id
->psz_enc
= "SPEEX";
1347 id
->pf_packetize
= rtp_packetize_spx
;
1349 case VLC_CODEC_ITU_T140
:
1350 id
->psz_enc
= "t140" ;
1351 id
->i_clock_rate
= 1000;
1352 id
->pf_packetize
= rtp_packetize_t140
;
1356 msg_Err( p_stream
, "cannot add this stream (unsupported "
1357 "codec: %4.4s)", (char*)&p_fmt
->i_codec
);
1360 if (id
->i_payload_type
>= 96)
1361 /* Mark dynamic payload type in use */
1362 p_sys
->payload_bitmap
&= ~(1 << (127 - id
->i_payload_type
));
1364 #if 0 /* No payload formats sets this at the moment */
1367 cscov
+= 8 /* UDP */ + 12 /* RTP */;
1369 net_SetCSCov( id
->sinkv
[0].rtp_fd
, cscov
, -1 );
1372 vlc_mutex_lock( &p_sys
->lock_ts
);
1373 id
->b_ts_init
= ( p_sys
->i_npt_zero
!= VLC_TS_INVALID
);
1374 vlc_mutex_unlock( &p_sys
->lock_ts
);
1376 id
->i_ts_offset
= rtp_compute_ts( id
, p_sys
->i_pts_offset
);
1378 if( p_sys
->rtsp
!= NULL
)
1379 id
->rtsp_id
= RtspAddId( p_sys
->rtsp
, id
,
1380 GetDWBE( id
->ssrc
),
1381 p_sys
->psz_destination
,
1382 p_sys
->i_ttl
, id
->i_port
, id
->i_port
+ 1 );
1384 id
->p_fifo
= block_FifoNew();
1385 if( unlikely(id
->p_fifo
== NULL
) )
1387 if( vlc_clone( &id
->thread
, ThreadSend
, id
, VLC_THREAD_PRIORITY_HIGHEST
) )
1389 block_FifoRelease( id
->p_fifo
);
1394 /* Update p_sys context */
1395 vlc_mutex_lock( &p_sys
->lock_es
);
1396 TAB_APPEND( p_sys
->i_es
, p_sys
->es
, id
);
1397 vlc_mutex_unlock( &p_sys
->lock_es
);
1399 psz_sdp
= SDPGenerate( p_stream
, NULL
);
1401 vlc_mutex_lock( &p_sys
->lock_sdp
);
1402 free( p_sys
->psz_sdp
);
1403 p_sys
->psz_sdp
= psz_sdp
;
1404 vlc_mutex_unlock( &p_sys
->lock_sdp
);
1406 msg_Dbg( p_stream
, "sdp=\n%s", p_sys
->psz_sdp
);
1408 /* Update SDP (sap/file) */
1409 if( p_sys
->b_export_sap
) SapSetup( p_stream
);
1410 if( p_sys
->psz_sdp_file
!= NULL
) FileSetup( p_stream
);
1415 Del( p_stream
, id
);
1419 static int Del( sout_stream_t
*p_stream
, sout_stream_id_t
*id
)
1421 sout_stream_sys_t
*p_sys
= p_stream
->p_sys
;
1423 vlc_mutex_lock( &p_sys
->lock_es
);
1424 TAB_REMOVE( p_sys
->i_es
, p_sys
->es
, id
);
1425 vlc_mutex_unlock( &p_sys
->lock_es
);
1427 if( likely(id
->p_fifo
!= NULL
) )
1429 vlc_cancel( id
->thread
);
1430 vlc_join( id
->thread
, NULL
);
1431 block_FifoRelease( id
->p_fifo
);
1434 /* Release dynamic payload type */
1435 if (id
->i_payload_type
>= 96)
1436 p_sys
->payload_bitmap
|= 1 << (127 - id
->i_payload_type
);
1438 free( id
->psz_fmtp
);
1441 RtspDelId( p_sys
->rtsp
, id
->rtsp_id
);
1442 if( id
->listen
.fd
!= NULL
)
1444 vlc_cancel( id
->listen
.thread
);
1445 vlc_join( id
->listen
.thread
, NULL
);
1446 net_ListenClose( id
->listen
.fd
);
1448 /* Delete remaining sinks (incoming connections or explicit
1450 while( id
->sinkc
> 0 )
1451 rtp_del_sink( id
, id
->sinkv
[0].rtp_fd
);
1453 if( id
->srtp
!= NULL
)
1454 srtp_destroy( id
->srtp
);
1457 vlc_mutex_destroy( &id
->lock_sink
);
1459 /* Update SDP (sap/file) */
1460 if( p_sys
->b_export_sap
&& !p_sys
->p_mux
) SapSetup( p_stream
);
1461 if( p_sys
->psz_sdp_file
!= NULL
) FileSetup( p_stream
);
1467 static int Send( sout_stream_t
*p_stream
, sout_stream_id_t
*id
,
1472 assert( p_stream
->p_sys
->p_mux
== NULL
);
1475 while( p_buffer
!= NULL
)
1477 p_next
= p_buffer
->p_next
;
1478 if( id
->pf_packetize( id
, p_buffer
) )
1481 block_Release( p_buffer
);
1487 /****************************************************************************
1489 ****************************************************************************/
1490 static int SapSetup( sout_stream_t
*p_stream
)
1492 sout_stream_sys_t
*p_sys
= p_stream
->p_sys
;
1493 sout_instance_t
*p_sout
= p_stream
->p_sout
;
1495 /* Remove the previous session */
1496 if( p_sys
->p_session
!= NULL
)
1498 sout_AnnounceUnRegister( p_sout
, p_sys
->p_session
);
1499 p_sys
->p_session
= NULL
;
1502 if( ( p_sys
->i_es
> 0 || p_sys
->p_mux
) && p_sys
->psz_sdp
&& *p_sys
->psz_sdp
)
1504 announce_method_t
*p_method
= sout_SAPMethod();
1505 p_sys
->p_session
= sout_AnnounceRegisterSDP( p_sout
,
1507 p_sys
->psz_destination
,
1509 sout_MethodRelease( p_method
);
1515 /****************************************************************************
1517 ****************************************************************************/
1518 static int FileSetup( sout_stream_t
*p_stream
)
1520 sout_stream_sys_t
*p_sys
= p_stream
->p_sys
;
1523 if( p_sys
->psz_sdp
== NULL
)
1524 return VLC_EGENERIC
; /* too early */
1526 if( ( f
= vlc_fopen( p_sys
->psz_sdp_file
, "wt" ) ) == NULL
)
1528 msg_Err( p_stream
, "cannot open file '%s' (%m)",
1529 p_sys
->psz_sdp_file
);
1530 return VLC_EGENERIC
;
1533 fputs( p_sys
->psz_sdp
, f
);
1539 /****************************************************************************
1541 ****************************************************************************/
1542 static int HttpCallback( httpd_file_sys_t
*p_args
,
1543 httpd_file_t
*, uint8_t *p_request
,
1544 uint8_t **pp_data
, int *pi_data
);
1546 static int HttpSetup( sout_stream_t
*p_stream
, const vlc_url_t
*url
)
1548 sout_stream_sys_t
*p_sys
= p_stream
->p_sys
;
1550 p_sys
->p_httpd_host
= httpd_HostNew( VLC_OBJECT(p_stream
), url
->psz_host
,
1551 url
->i_port
> 0 ? url
->i_port
: 80 );
1552 if( p_sys
->p_httpd_host
)
1554 p_sys
->p_httpd_file
= httpd_FileNew( p_sys
->p_httpd_host
,
1555 url
->psz_path
? url
->psz_path
: "/",
1558 HttpCallback
, (void*)p_sys
);
1560 if( p_sys
->p_httpd_file
== NULL
)
1562 return VLC_EGENERIC
;
1567 static int HttpCallback( httpd_file_sys_t
*p_args
,
1568 httpd_file_t
*f
, uint8_t *p_request
,
1569 uint8_t **pp_data
, int *pi_data
)
1571 VLC_UNUSED(f
); VLC_UNUSED(p_request
);
1572 sout_stream_sys_t
*p_sys
= (sout_stream_sys_t
*)p_args
;
1574 vlc_mutex_lock( &p_sys
->lock_sdp
);
1575 if( p_sys
->psz_sdp
&& *p_sys
->psz_sdp
)
1577 *pi_data
= strlen( p_sys
->psz_sdp
);
1578 *pp_data
= malloc( *pi_data
);
1579 memcpy( *pp_data
, p_sys
->psz_sdp
, *pi_data
);
1586 vlc_mutex_unlock( &p_sys
->lock_sdp
);
1591 /****************************************************************************
1593 ****************************************************************************/
1594 static void* ThreadSend( void *data
)
1597 # define ECONNREFUSED WSAECONNREFUSED
1598 # define ENOPROTOOPT WSAENOPROTOOPT
1599 # define EHOSTUNREACH WSAEHOSTUNREACH
1600 # define ENETUNREACH WSAENETUNREACH
1601 # define ENETDOWN WSAENETDOWN
1602 # define ENOBUFS WSAENOBUFS
1603 # define EAGAIN WSAEWOULDBLOCK
1604 # define EWOULDBLOCK WSAEWOULDBLOCK
1606 sout_stream_id_t
*id
= data
;
1607 unsigned i_caching
= id
->i_caching
;
1611 block_t
*out
= block_FifoGet( id
->p_fifo
);
1612 block_cleanup_push (out
);
1616 { /* FIXME: this is awfully inefficient */
1617 size_t len
= out
->i_buffer
;
1618 out
= block_Realloc( out
, 0, len
+ 10 );
1619 out
->i_buffer
= len
;
1621 int canc
= vlc_savecancel ();
1622 int val
= srtp_send( id
->srtp
, out
->p_buffer
, &len
, len
+ 10 );
1623 vlc_restorecancel (canc
);
1627 msg_Dbg( id
->p_stream
, "SRTP sending error: %m" );
1628 block_Release( out
);
1632 out
->i_buffer
= len
;
1636 mwait (out
->i_dts
+ i_caching
);
1641 ssize_t len
= out
->i_buffer
;
1642 int canc
= vlc_savecancel ();
1644 vlc_mutex_lock( &id
->lock_sink
);
1645 unsigned deadc
= 0; /* How many dead sockets? */
1646 int deadv
[id
->sinkc
]; /* Dead sockets list */
1648 for( int i
= 0; i
< id
->sinkc
; i
++ )
1651 if( !id
->srtp
) /* FIXME: SRTCP support */
1653 SendRTCP( id
->sinkv
[i
].rtcp
, out
);
1655 if( send( id
->sinkv
[i
].rtp_fd
, out
->p_buffer
, len
, 0 ) >= 0 )
1659 /* Soft errors (e.g. ICMP): */
1660 case ECONNREFUSED
: /* Port unreachable */
1663 case EPROTO
: /* Protocol unreachable */
1665 case EHOSTUNREACH
: /* Host unreachable */
1666 case ENETUNREACH
: /* Network unreachable */
1667 case ENETDOWN
: /* Entire network down */
1668 send( id
->sinkv
[i
].rtp_fd
, out
->p_buffer
, len
, 0 );
1669 /* Transient congestion: */
1670 case ENOMEM
: /* out of socket buffers */
1673 #if (EAGAIN != EWOULDBLOCK)
1679 deadv
[deadc
++] = id
->sinkv
[i
].rtp_fd
;
1681 id
->i_seq_sent_next
= ntohs(((uint16_t *) out
->p_buffer
)[1]) + 1;
1682 vlc_mutex_unlock( &id
->lock_sink
);
1683 block_Release( out
);
1685 for( unsigned i
= 0; i
< deadc
; i
++ )
1687 msg_Dbg( id
->p_stream
, "removing socket %d", deadv
[i
] );
1688 rtp_del_sink( id
, deadv
[i
] );
1690 vlc_restorecancel (canc
);
1696 /* This thread dequeues incoming connections (DCCP streaming) */
1697 static void *rtp_listen_thread( void *data
)
1699 sout_stream_id_t
*id
= data
;
1701 assert( id
->listen
.fd
!= NULL
);
1705 int fd
= net_Accept( id
->p_stream
, id
->listen
.fd
);
1708 int canc
= vlc_savecancel( );
1709 rtp_add_sink( id
, fd
, true, NULL
);
1710 vlc_restorecancel( canc
);
1717 int rtp_add_sink( sout_stream_id_t
*id
, int fd
, bool rtcp_mux
, uint16_t *seq
)
1719 rtp_sink_t sink
= { fd
, NULL
};
1720 sink
.rtcp
= OpenRTCP( VLC_OBJECT( id
->p_stream
), fd
, IPPROTO_UDP
,
1722 if( sink
.rtcp
== NULL
)
1723 msg_Err( id
->p_stream
, "RTCP failed!" );
1725 vlc_mutex_lock( &id
->lock_sink
);
1726 INSERT_ELEM( id
->sinkv
, id
->sinkc
, id
->sinkc
, sink
);
1728 *seq
= id
->i_seq_sent_next
;
1729 vlc_mutex_unlock( &id
->lock_sink
);
1733 void rtp_del_sink( sout_stream_id_t
*id
, int fd
)
1735 rtp_sink_t sink
= { fd
, NULL
};
1737 /* NOTE: must be safe to use if fd is not included */
1738 vlc_mutex_lock( &id
->lock_sink
);
1739 for( int i
= 0; i
< id
->sinkc
; i
++ )
1741 if (id
->sinkv
[i
].rtp_fd
== fd
)
1743 sink
= id
->sinkv
[i
];
1744 REMOVE_ELEM( id
->sinkv
, id
->sinkc
, i
);
1748 vlc_mutex_unlock( &id
->lock_sink
);
1750 CloseRTCP( sink
.rtcp
);
1751 net_Close( sink
.rtp_fd
);
1754 uint16_t rtp_get_seq( sout_stream_id_t
*id
)
1756 /* This will return values for the next packet. */
1759 vlc_mutex_lock( &id
->lock_sink
);
1760 seq
= id
->i_seq_sent_next
;
1761 vlc_mutex_unlock( &id
->lock_sink
);
1766 /* Return a timestamp corresponding to packets being sent now, and that
1767 * can be passed to rtp_compute_ts() to get rtptime values for each ES. */
1768 int64_t rtp_get_ts( const sout_stream_t
*p_stream
)
1770 sout_stream_sys_t
*p_sys
= p_stream
->p_sys
;
1772 vlc_mutex_lock( &p_sys
->lock_ts
);
1773 i_npt_zero
= p_sys
->i_npt_zero
;
1774 vlc_mutex_unlock( &p_sys
->lock_ts
);
1776 if( i_npt_zero
== VLC_TS_INVALID
)
1777 return p_sys
->i_pts_zero
;
1779 mtime_t now
= mdate();
1780 if( now
< i_npt_zero
)
1781 return p_sys
->i_pts_zero
;
1783 return p_sys
->i_pts_zero
+ (now
- i_npt_zero
);
1786 void rtp_packetize_common( sout_stream_id_t
*id
, block_t
*out
,
1787 int b_marker
, int64_t i_pts
)
1789 if( !id
->b_ts_init
)
1791 sout_stream_sys_t
*p_sys
= id
->p_stream
->p_sys
;
1792 vlc_mutex_lock( &p_sys
->lock_ts
);
1793 if( p_sys
->i_npt_zero
== VLC_TS_INVALID
)
1795 /* This is the first packet of any ES. We initialize the
1796 * NPT=0 time reference, and the offset to match the
1797 * arbitrary PTS reference. */
1798 p_sys
->i_npt_zero
= i_pts
+ id
->i_caching
;
1799 p_sys
->i_pts_offset
= p_sys
->i_pts_zero
- i_pts
;
1801 vlc_mutex_unlock( &p_sys
->lock_ts
);
1803 /* And in any case this is the first packet of this ES, so we
1804 * initialize the offset for this ES. */
1805 id
->i_ts_offset
= rtp_compute_ts( id
, p_sys
->i_pts_offset
);
1806 id
->b_ts_init
= true;
1809 uint32_t i_timestamp
= rtp_compute_ts( id
, i_pts
) + id
->i_ts_offset
;
1811 out
->p_buffer
[0] = 0x80;
1812 out
->p_buffer
[1] = (b_marker
?0x80:0x00)|id
->i_payload_type
;
1813 out
->p_buffer
[2] = ( id
->i_sequence
>> 8)&0xff;
1814 out
->p_buffer
[3] = ( id
->i_sequence
)&0xff;
1815 out
->p_buffer
[4] = ( i_timestamp
>> 24 )&0xff;
1816 out
->p_buffer
[5] = ( i_timestamp
>> 16 )&0xff;
1817 out
->p_buffer
[6] = ( i_timestamp
>> 8 )&0xff;
1818 out
->p_buffer
[7] = ( i_timestamp
)&0xff;
1820 memcpy( out
->p_buffer
+ 8, id
->ssrc
, 4 );
1826 void rtp_packetize_send( sout_stream_id_t
*id
, block_t
*out
)
1828 block_FifoPut( id
->p_fifo
, out
);
1832 * @return configured max RTP payload size (including payload type-specific
1833 * headers, excluding RTP and transport headers)
1835 size_t rtp_mtu (const sout_stream_id_t
*id
)
1837 return id
->i_mtu
- 12;
1840 /*****************************************************************************
1842 *****************************************************************************/
1844 /** Add an ES to a non-RTP muxed stream */
1845 static sout_stream_id_t
*MuxAdd( sout_stream_t
*p_stream
, es_format_t
*p_fmt
)
1847 sout_input_t
*p_input
;
1848 sout_mux_t
*p_mux
= p_stream
->p_sys
->p_mux
;
1849 assert( p_mux
!= NULL
);
1851 p_input
= sout_MuxAddStream( p_mux
, p_fmt
);
1852 if( p_input
== NULL
)
1854 msg_Err( p_stream
, "cannot add this stream to the muxer" );
1858 return (sout_stream_id_t
*)p_input
;
1862 static int MuxSend( sout_stream_t
*p_stream
, sout_stream_id_t
*id
,
1865 sout_mux_t
*p_mux
= p_stream
->p_sys
->p_mux
;
1866 assert( p_mux
!= NULL
);
1868 sout_MuxSendBuffer( p_mux
, (sout_input_t
*)id
, p_buffer
);
1873 /** Remove an ES from a non-RTP muxed stream */
1874 static int MuxDel( sout_stream_t
*p_stream
, sout_stream_id_t
*id
)
1876 sout_mux_t
*p_mux
= p_stream
->p_sys
->p_mux
;
1877 assert( p_mux
!= NULL
);
1879 sout_MuxDeleteStream( p_mux
, (sout_input_t
*)id
);
1884 static ssize_t
AccessOutGrabberWriteBuffer( sout_stream_t
*p_stream
,
1885 const block_t
*p_buffer
)
1887 sout_stream_sys_t
*p_sys
= p_stream
->p_sys
;
1888 sout_stream_id_t
*id
= p_sys
->es
[0];
1890 int64_t i_dts
= p_buffer
->i_dts
;
1892 uint8_t *p_data
= p_buffer
->p_buffer
;
1893 size_t i_data
= p_buffer
->i_buffer
;
1894 size_t i_max
= id
->i_mtu
- 12;
1896 size_t i_packet
= ( p_buffer
->i_buffer
+ i_max
- 1 ) / i_max
;
1902 /* output complete packet */
1903 if( p_sys
->packet
&&
1904 p_sys
->packet
->i_buffer
+ i_data
> i_max
)
1906 rtp_packetize_send( id
, p_sys
->packet
);
1907 p_sys
->packet
= NULL
;
1910 if( p_sys
->packet
== NULL
)
1912 /* allocate a new packet */
1913 p_sys
->packet
= block_New( p_stream
, id
->i_mtu
);
1914 rtp_packetize_common( id
, p_sys
->packet
, 1, i_dts
);
1915 p_sys
->packet
->i_dts
= i_dts
;
1916 p_sys
->packet
->i_length
= p_buffer
->i_length
/ i_packet
;
1917 i_dts
+= p_sys
->packet
->i_length
;
1920 i_size
= __MIN( i_data
,
1921 (unsigned)(id
->i_mtu
- p_sys
->packet
->i_buffer
) );
1923 memcpy( &p_sys
->packet
->p_buffer
[p_sys
->packet
->i_buffer
],
1926 p_sys
->packet
->i_buffer
+= i_size
;
1935 static ssize_t
AccessOutGrabberWrite( sout_access_out_t
*p_access
,
1938 sout_stream_t
*p_stream
= (sout_stream_t
*)p_access
->p_sys
;
1944 AccessOutGrabberWriteBuffer( p_stream
, p_buffer
);
1946 p_next
= p_buffer
->p_next
;
1947 block_Release( p_buffer
);
1955 static sout_access_out_t
*GrabberCreate( sout_stream_t
*p_stream
)
1957 sout_access_out_t
*p_grab
;
1959 p_grab
= vlc_object_create( p_stream
->p_sout
, sizeof( *p_grab
) );
1960 if( p_grab
== NULL
)
1963 p_grab
->p_module
= NULL
;
1964 p_grab
->psz_access
= strdup( "grab" );
1965 p_grab
->p_cfg
= NULL
;
1966 p_grab
->psz_path
= strdup( "" );
1967 p_grab
->p_sys
= (sout_access_out_sys_t
*)p_stream
;
1968 p_grab
->pf_seek
= NULL
;
1969 p_grab
->pf_write
= AccessOutGrabberWrite
;
1970 vlc_object_attach( p_grab
, p_stream
);