Commit b3790080 authored by Rémi Denis-Courmont's avatar Rémi Denis-Courmont

Partial support for RTP over connection-oriented media

parent d6de4f03
...@@ -44,6 +44,15 @@ ...@@ -44,6 +44,15 @@
# include <fcntl.h> # include <fcntl.h>
# include <sys/stat.h> # include <sys/stat.h>
#endif #endif
#ifdef HAVE_LINUX_DCCP_H
# include <linux/dccp.h>
#endif
#ifndef IPPROTO_DCCP
# define IPPROTO_DCCP 33
#endif
#ifndef IPPROTO_UDPLITE
# define IPPROTO_UDPLITE 136
#endif
#include <errno.h> #include <errno.h>
...@@ -283,6 +292,7 @@ struct sout_stream_id_t ...@@ -283,6 +292,7 @@ struct sout_stream_id_t
int sinkc; int sinkc;
rtp_sink_t *sinkv; rtp_sink_t *sinkv;
rtsp_stream_id_t *rtsp_id; rtsp_stream_id_t *rtsp_id;
int *listen_fd;
block_fifo_t *p_fifo; block_fifo_t *p_fifo;
int64_t i_caching; int64_t i_caching;
...@@ -347,22 +357,20 @@ static int Open( vlc_object_t *p_this ) ...@@ -347,22 +357,20 @@ static int Open( vlc_object_t *p_this )
/* Transport protocol */ /* Transport protocol */
p_sys->proto = IPPROTO_UDP; p_sys->proto = IPPROTO_UDP;
#if 0
if( var_GetBool( p_stream, SOUT_CFG_PREFIX "dccp" ) ) if( var_GetBool( p_stream, SOUT_CFG_PREFIX "dccp" ) )
{ {
p_sys->sotype = SOCK_DCCP; p_sys->proto = IPPROTO_DCCP;
p_sys->proto = 33 /*IPPROTO_DCCP*/;
} }
#if 0
else else
if( var_GetBool( p_stream, SOUT_CFG_PREFIX "tcp" ) ) if( var_GetBool( p_stream, SOUT_CFG_PREFIX "tcp" ) )
{ {
p_sys->sotype = SOCK_STREAM;
p_sys->proto = IPPROTO_TCP; p_sys->proto = IPPROTO_TCP;
} }
else else
#endif #endif
if( var_GetBool( p_stream, SOUT_CFG_PREFIX "udplite" ) ) if( var_GetBool( p_stream, SOUT_CFG_PREFIX "udplite" ) )
p_sys->proto = 136 /*IPPROTO_UDPLITE*/; p_sys->proto = IPPROTO_UDPLITE;
if( ( p_sys->psz_destination == NULL ) && !b_rtsp ) if( ( p_sys->psz_destination == NULL ) && !b_rtsp )
{ {
...@@ -656,8 +664,12 @@ char *SDPGenerate( const sout_stream_t *p_stream, const char *rtsp_url ) ...@@ -656,8 +664,12 @@ char *SDPGenerate( const sout_stream_t *p_stream, const char *rtsp_url )
/* Oh boy, this is really ugly! (+ race condition on lock_es) */ /* Oh boy, this is really ugly! (+ race condition on lock_es) */
dstlen = sizeof( dst ); dstlen = sizeof( dst );
getpeername( p_sys->es[0]->sinkv[0].rtp_fd, (struct sockaddr *)&dst, if( p_sys->es[0]->listen_fd != NULL )
&dstlen ); getsockname( p_sys->es[0]->listen_fd[0],
(struct sockaddr *)&dst, &dstlen );
else
getpeername( p_sys->es[0]->sinkv[0].rtp_fd,
(struct sockaddr *)&dst, &dstlen );
} }
else else
{ {
...@@ -687,23 +699,47 @@ char *SDPGenerate( const sout_stream_t *p_stream, const char *rtsp_url ) ...@@ -687,23 +699,47 @@ char *SDPGenerate( const sout_stream_t *p_stream, const char *rtsp_url )
{ {
sout_stream_id_t *id = p_sys->es[i]; sout_stream_id_t *id = p_sys->es[i];
const char *mime_major; /* major MIME type */ const char *mime_major; /* major MIME type */
const char *proto = "RTP/AVP"; /* protocol */
const char *scode; /* DCCP service code */
switch( id->i_cat ) switch( id->i_cat )
{ {
case VIDEO_ES: case VIDEO_ES:
mime_major = "video"; mime_major = "video";
scode = "SC:RTPV";
break; break;
case AUDIO_ES: case AUDIO_ES:
mime_major = "audio"; mime_major = "audio";
scode = "SC:RTPA";
break; break;
case SPU_ES: case SPU_ES:
mime_major = "text"; mime_major = "text";
scode = "SC:RTPT";
break; break;
default: default:
mime_major = "application";
scode = "SC:RTPO";
break;
}
if( rtsp_url == NULL )
{
switch( p_sys->proto )
{
case IPPROTO_UDP:
break;
case IPPROTO_TCP:
proto = "TCP/RTP/AVP";
break;
case IPPROTO_DCCP:
proto = "DCCP/RTP/AVP";
break;
case IPPROTO_UDPLITE:
continue; continue;
} }
}
sdp_AddMedia( &psz_sdp, mime_major, "RTP/AVP", inclport * id->i_port, sdp_AddMedia( &psz_sdp, mime_major, proto, inclport * id->i_port,
id->i_payload_type, VLC_FALSE, id->i_bitrate, id->i_payload_type, VLC_FALSE, id->i_bitrate,
id->psz_rtpmap, id->psz_fmtp); id->psz_rtpmap, id->psz_fmtp);
...@@ -715,6 +751,13 @@ char *SDPGenerate( const sout_stream_t *p_stream, const char *rtsp_url ) ...@@ -715,6 +751,13 @@ char *SDPGenerate( const sout_stream_t *p_stream, const char *rtsp_url )
addslash ? "%s/trackID=%u" : "%strackID=%u", addslash ? "%s/trackID=%u" : "%strackID=%u",
rtsp_url, i ); rtsp_url, i );
} }
else
{
if( id->listen_fd != NULL )
sdp_AddAttribute( &psz_sdp, "setup", "passive" );
if( p_sys->proto == IPPROTO_DCCP )
sdp_AddAttribute( &psz_sdp, "dccp-service-code", scode );
}
} }
return psz_sdp; return psz_sdp;
...@@ -763,6 +806,7 @@ static sout_stream_id_t *Add( sout_stream_t *p_stream, es_format_t *p_fmt ) ...@@ -763,6 +806,7 @@ static sout_stream_id_t *Add( sout_stream_t *p_stream, es_format_t *p_fmt )
id = vlc_object_create( p_stream, sizeof( sout_stream_id_t ) ); id = vlc_object_create( p_stream, sizeof( sout_stream_id_t ) );
if( id == NULL ) if( id == NULL )
return NULL; return NULL;
vlc_object_attach( id, p_stream );
/* Choose the port */ /* Choose the port */
i_port = 0; i_port = 0;
...@@ -829,35 +873,40 @@ static sout_stream_id_t *Add( sout_stream_t *p_stream, es_format_t *p_fmt ) ...@@ -829,35 +873,40 @@ static sout_stream_id_t *Add( sout_stream_t *p_stream, es_format_t *p_fmt )
id->sinkc = 0; id->sinkc = 0;
id->sinkv = NULL; id->sinkv = NULL;
id->rtsp_id = NULL; id->rtsp_id = NULL;
id->p_fifo = NULL;
id->listen_fd = NULL;
id->i_caching = id->i_caching =
(int64_t)1000 * var_GetInteger( p_stream, SOUT_CFG_PREFIX "caching"); (int64_t)1000 * var_GetInteger( p_stream, SOUT_CFG_PREFIX "caching");
id->p_fifo = block_FifoNew( p_stream );
if( vlc_thread_create( id, "RTP send thread", ThreadSend, if( p_sys->psz_destination != NULL )
VLC_THREAD_PRIORITY_HIGHEST, VLC_FALSE ) ) switch( p_sys->proto )
{ {
vlc_mutex_destroy( &id->lock_sink ); case IPPROTO_TCP:
vlc_object_destroy( id ); case IPPROTO_DCCP:
return NULL; id->listen_fd = net_Listen( VLC_OBJECT(p_stream),
p_sys->psz_destination, i_port,
p_sys->proto );
if( id->listen_fd == NULL )
{
msg_Err( p_stream, "passive COMEDIA RTP socket failed" );
goto error;
} }
break;
if( p_sys->psz_destination != NULL ) default:
{ {
int ttl = (p_sys->i_ttl > 0) ? p_sys->i_ttl : -1; int ttl = (p_sys->i_ttl > 0) ? p_sys->i_ttl : -1;
int fd = net_ConnectDgram( p_stream, p_sys->psz_destination, int fd = net_ConnectDgram( p_stream, p_sys->psz_destination,
i_port, ttl, p_sys->proto ); i_port, ttl, p_sys->proto );
if( fd == -1 ) if( fd == -1 )
{ {
msg_Err( p_stream, "cannot create RTP socket" ); msg_Err( p_stream, "cannot create RTP socket" );
vlc_thread_join( id ); goto error;
vlc_mutex_destroy( &id->lock_sink );
vlc_object_destroy( id );
return NULL;
} }
rtp_add_sink( id, fd ); rtp_add_sink( id, fd );
} }
}
if( p_fmt == NULL ) if( p_fmt == NULL )
{ {
...@@ -1069,12 +1118,7 @@ static sout_stream_id_t *Add( sout_stream_t *p_stream, es_format_t *p_fmt ) ...@@ -1069,12 +1118,7 @@ static sout_stream_id_t *Add( sout_stream_t *p_stream, es_format_t *p_fmt )
default: default:
msg_Err( p_stream, "cannot add this stream (unsupported " msg_Err( p_stream, "cannot add this stream (unsupported "
"codec:%4.4s)", (char*)&p_fmt->i_codec ); "codec:%4.4s)", (char*)&p_fmt->i_codec );
if( id->sinkc > 0 ) goto error;
rtp_del_sink( id, id->sinkv[0].rtp_fd );
vlc_thread_join( id );
vlc_mutex_destroy( &id->lock_sink );
vlc_object_destroy( id );
return NULL;
} }
if( cscov != -1 ) if( cscov != -1 )
...@@ -1090,6 +1134,11 @@ static sout_stream_id_t *Add( sout_stream_t *p_stream, es_format_t *p_fmt ) ...@@ -1090,6 +1134,11 @@ static sout_stream_id_t *Add( sout_stream_t *p_stream, es_format_t *p_fmt )
p_sys->psz_destination, p_sys->psz_destination,
p_sys->i_ttl, id->i_port, id->i_port + 1 ); p_sys->i_ttl, id->i_port, id->i_port + 1 );
id->p_fifo = block_FifoNew( p_stream );
if( vlc_thread_create( id, "RTP send thread", ThreadSend,
VLC_THREAD_PRIORITY_HIGHEST, VLC_FALSE ) )
goto error;
/* Update p_sys context */ /* Update p_sys context */
vlc_mutex_lock( &p_sys->lock_es ); vlc_mutex_lock( &p_sys->lock_es );
TAB_APPEND( p_sys->i_es, p_sys->es, id ); TAB_APPEND( p_sys->i_es, p_sys->es, id );
...@@ -1110,16 +1159,24 @@ static sout_stream_id_t *Add( sout_stream_t *p_stream, es_format_t *p_fmt ) ...@@ -1110,16 +1159,24 @@ static sout_stream_id_t *Add( sout_stream_t *p_stream, es_format_t *p_fmt )
if( p_sys->b_export_sap ) SapSetup( p_stream ); if( p_sys->b_export_sap ) SapSetup( p_stream );
if( p_sys->b_export_sdp_file ) FileSetup( p_stream ); if( p_sys->b_export_sdp_file ) FileSetup( p_stream );
vlc_object_attach( id, p_stream );
return id; return id;
error:
Del( p_stream, id );
return NULL;
} }
static int Del( sout_stream_t *p_stream, sout_stream_id_t *id ) static int Del( sout_stream_t *p_stream, sout_stream_id_t *id )
{ {
sout_stream_sys_t *p_sys = p_stream->p_sys; sout_stream_sys_t *p_sys = p_stream->p_sys;
if( id->p_fifo != NULL )
{
vlc_object_kill( id ); vlc_object_kill( id );
block_FifoWake( id->p_fifo ); block_FifoWake( id->p_fifo );
vlc_thread_join( id );
block_FifoRelease( id->p_fifo );
}
vlc_mutex_lock( &p_sys->lock_es ); vlc_mutex_lock( &p_sys->lock_es );
TAB_REMOVE( p_sys->i_es, p_sys->es, id ); TAB_REMOVE( p_sys->i_es, p_sys->es, id );
...@@ -1141,10 +1198,10 @@ static int Del( sout_stream_t *p_stream, sout_stream_id_t *id ) ...@@ -1141,10 +1198,10 @@ static int Del( sout_stream_t *p_stream, sout_stream_id_t *id )
RtspDelId( p_sys->rtsp, id->rtsp_id ); RtspDelId( p_sys->rtsp, id->rtsp_id );
if( id->sinkc > 0 ) if( id->sinkc > 0 )
rtp_del_sink( id, id->sinkv[0].rtp_fd ); /* sink for explicit dst= */ rtp_del_sink( id, id->sinkv[0].rtp_fd ); /* sink for explicit dst= */
if( id->listen_fd != NULL )
net_ListenClose( id->listen_fd );
vlc_thread_join( id );
vlc_mutex_destroy( &id->lock_sink ); vlc_mutex_destroy( &id->lock_sink );
block_FifoRelease( id->p_fifo );
/* Update SDP (sap/file) */ /* Update SDP (sap/file) */
if( p_sys->b_export_sap && !p_sys->p_mux ) SapSetup( p_stream ); if( p_sys->b_export_sap && !p_sys->p_mux ) SapSetup( p_stream );
...@@ -1311,6 +1368,11 @@ static void ThreadSend( vlc_object_t *p_this ) ...@@ -1311,6 +1368,11 @@ static void ThreadSend( vlc_object_t *p_this )
mwait( i_date ); mwait( i_date );
vlc_mutex_lock( &id->lock_sink ); vlc_mutex_lock( &id->lock_sink );
#if 0
unsigned deadc = 0; /* How many dead sockets? */
int deadv[id->sinkc]; /* Dead sockets list */
#endif
for( int i = 0; i < id->sinkc; i++ ) for( int i = 0; i < id->sinkc; i++ )
{ {
SendRTCP( id->sinkv[i].rtcp, out ); SendRTCP( id->sinkv[i].rtcp, out );
...@@ -1324,7 +1386,8 @@ static void ThreadSend( vlc_object_t *p_this ) ...@@ -1324,7 +1386,8 @@ static void ThreadSend( vlc_object_t *p_this )
/* splice failed */ /* splice failed */
splice( fd[2], NULL, fd[4], NULL, len, 0 ); splice( fd[2], NULL, fd[4], NULL, len, 0 );
#endif #endif
send( id->sinkv[i].rtp_fd, out->p_buffer, len, 0 ); if( send( id->sinkv[i].rtp_fd, out->p_buffer, len, 0 ) < 0 )
/*deadv[deadc++] = id->sinkv[i].rtp_fd*/;
} }
vlc_mutex_unlock( &id->lock_sink ); vlc_mutex_unlock( &id->lock_sink );
...@@ -1332,6 +1395,24 @@ static void ThreadSend( vlc_object_t *p_this ) ...@@ -1332,6 +1395,24 @@ static void ThreadSend( vlc_object_t *p_this )
#ifdef HAVE_TEE #ifdef HAVE_TEE
splice( fd[0], NULL, fd[4], NULL, len, 0 ); splice( fd[0], NULL, fd[4], NULL, len, 0 );
#endif #endif
#if 0
for( unsigned i = 0; i < deadc; i++ )
{
msg_Dbg( id, "removing socket %d", deadv[i] );
rtp_del_sink( id, deadv[i] );
}
#endif
/* Hopefully we won't overflow the SO_MAXCONN accept queue */
while( id->listen_fd != NULL )
{
int fd = net_Accept( id, id->listen_fd, 0 );
if( fd == -1 )
break;
msg_Dbg( id, "adding socket %d", fd );
rtp_add_sink( id, fd );
}
} }
#ifdef HAVE_TEE #ifdef HAVE_TEE
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment