]> git.sesse.net Git - vlc/blobdiff - modules/stream_out/rtp.c
Ue var_Get(Time|Address) when applicable.
[vlc] / modules / stream_out / rtp.c
index 9c572166e78b39c2f23ceee86d99f82fc37f6cae..c496ee34be6a96527b94e517f7bdfac9096fc208 100644 (file)
@@ -167,47 +167,47 @@ vlc_module_begin ()
     set_subcategory( SUBCAT_SOUT_STREAM )
 
     add_string( SOUT_CFG_PREFIX "dst", "", NULL, DEST_TEXT,
-                DEST_LONGTEXT, true );
+                DEST_LONGTEXT, true )
     add_string( SOUT_CFG_PREFIX "sdp", "", NULL, SDP_TEXT,
-                SDP_LONGTEXT, true );
+                SDP_LONGTEXT, true )
     add_string( SOUT_CFG_PREFIX "mux", "", NULL, MUX_TEXT,
-                MUX_LONGTEXT, true );
+                MUX_LONGTEXT, true )
     add_bool( SOUT_CFG_PREFIX "sap", false, NULL, SAP_TEXT, SAP_LONGTEXT,
-              true );
+              true )
 
     add_string( SOUT_CFG_PREFIX "name", "", NULL, NAME_TEXT,
-                NAME_LONGTEXT, true );
+                NAME_LONGTEXT, true )
     add_string( SOUT_CFG_PREFIX "description", "", NULL, DESC_TEXT,
-                DESC_LONGTEXT, true );
+                DESC_LONGTEXT, true )
     add_string( SOUT_CFG_PREFIX "url", "", NULL, URL_TEXT,
-                URL_LONGTEXT, true );
+                URL_LONGTEXT, true )
     add_string( SOUT_CFG_PREFIX "email", "", NULL, EMAIL_TEXT,
-                EMAIL_LONGTEXT, true );
+                EMAIL_LONGTEXT, true )
     add_string( SOUT_CFG_PREFIX "phone", "", NULL, PHONE_TEXT,
-                PHONE_LONGTEXT, true );
+                PHONE_LONGTEXT, true )
 
     add_string( SOUT_CFG_PREFIX "proto", "udp", NULL, PROTO_TEXT,
-                PROTO_LONGTEXT, false );
-        change_string_list( ppsz_protos, ppsz_protocols, NULL );
+                PROTO_LONGTEXT, false )
+        change_string_list( ppsz_protos, ppsz_protocols, NULL )
     add_integer( SOUT_CFG_PREFIX "port", 5004, NULL, PORT_TEXT,
-                 PORT_LONGTEXT, true );
+                 PORT_LONGTEXT, true )
     add_integer( SOUT_CFG_PREFIX "port-audio", 0, NULL, PORT_AUDIO_TEXT,
-                 PORT_AUDIO_LONGTEXT, true );
+                 PORT_AUDIO_LONGTEXT, true )
     add_integer( SOUT_CFG_PREFIX "port-video", 0, NULL, PORT_VIDEO_TEXT,
-                 PORT_VIDEO_LONGTEXT, true );
+                 PORT_VIDEO_LONGTEXT, true )
 
     add_integer( SOUT_CFG_PREFIX "ttl", -1, NULL, TTL_TEXT,
-                 TTL_LONGTEXT, true );
+                 TTL_LONGTEXT, true )
     add_bool( SOUT_CFG_PREFIX "rtcp-mux", false, NULL,
-              RTCP_MUX_TEXT, RTCP_MUX_LONGTEXT, false );
+              RTCP_MUX_TEXT, RTCP_MUX_LONGTEXT, false )
 
     add_string( SOUT_CFG_PREFIX "key", "", NULL,
-                SRTP_KEY_TEXT, SRTP_KEY_LONGTEXT, false );
+                SRTP_KEY_TEXT, SRTP_KEY_LONGTEXT, false )
     add_string( SOUT_CFG_PREFIX "salt", "", NULL,
-                SRTP_SALT_TEXT, SRTP_SALT_LONGTEXT, false );
+                SRTP_SALT_TEXT, SRTP_SALT_LONGTEXT, false )
 
     add_bool( SOUT_CFG_PREFIX "mp4a-latm", 0, NULL, RFC3016_TEXT,
-                 RFC3016_LONGTEXT, false );
+                 RFC3016_LONGTEXT, false )
 
     set_callbacks( Open, Close )
 vlc_module_end ()
@@ -247,7 +247,6 @@ struct sout_stream_sys_t
     vlc_mutex_t  lock_sdp;
 
     /* SDP to disk */
-    bool b_export_sdp_file;
     char *psz_sdp_file;
 
     /* SDP via SAP */
@@ -352,8 +351,6 @@ static int Open( vlc_object_t *p_this )
     p_sys->i_port_video = var_GetInteger( p_stream, SOUT_CFG_PREFIX "port-video" );
     p_sys->rtcp_mux     = var_GetBool( p_stream, SOUT_CFG_PREFIX "rtcp-mux" );
 
-    p_sys->psz_sdp_file = NULL;
-
     if( p_sys->i_port_audio && p_sys->i_port_video == p_sys->i_port_audio )
     {
         msg_Err( p_stream, "audio and video RTP port must be distinct" );
@@ -446,8 +443,8 @@ static int Open( vlc_object_t *p_this )
     p_sys->psz_sdp = NULL;
 
     p_sys->b_export_sap = false;
-    p_sys->b_export_sdp_file = false;
     p_sys->p_session = NULL;
+    p_sys->psz_sdp_file = NULL;
 
     p_sys->p_httpd_host = NULL;
     p_sys->p_httpd_file = NULL;
@@ -566,10 +563,11 @@ static void Close( vlc_object_t * p_this )
     if( p_sys->p_mux )
     {
         assert( p_sys->i_es == 1 );
-        Del( p_stream, p_sys->es[0] );
 
         sout_MuxDelete( p_sys->p_mux );
+        Del( p_stream, p_sys->es[0] );
         sout_AccessOutDelete( p_sys->p_grab );
+
         if( p_sys->packet )
         {
             block_Release( p_sys->packet );
@@ -595,7 +593,7 @@ static void Close( vlc_object_t * p_this )
 
     free( p_sys->psz_sdp );
 
-    if( p_sys->b_export_sdp_file )
+    if( p_sys->psz_sdp_file != NULL )
     {
 #ifdef HAVE_UNISTD_H
         unlink( p_sys->psz_sdp_file );
@@ -657,16 +655,19 @@ static void SDPHandleUrl( sout_stream_t *p_stream, const char *psz_url )
     }
     else if( url.psz_protocol && !strcasecmp( url.psz_protocol, "file" ) )
     {
-        if( p_sys->b_export_sdp_file )
+        if( p_sys->psz_sdp_file != NULL )
         {
             msg_Err( p_stream, "you can use sdp=file:// only once" );
             goto out;
         }
-        p_sys->b_export_sdp_file = true;
         psz_url = &psz_url[5];
         if( psz_url[0] == '/' && psz_url[1] == '/' )
             psz_url += 2;
         p_sys->psz_sdp_file = strdup( psz_url );
+        if( p_sys->psz_sdp_file == NULL )
+            goto out;
+        decode_URI( p_sys->psz_sdp_file ); /* FIXME? */
+        FileSetup( p_stream );
     }
     else
     {
@@ -853,10 +854,8 @@ static sout_stream_id_t *Add( sout_stream_t *p_stream, es_format_t *p_fmt )
      * mux (TS/PS), then p_fmt is NULL. */
     sout_stream_sys_t *p_sys = p_stream->p_sys;
     sout_stream_id_t  *id;
-    int               i_port, cscov = -1;
+    int               cscov = -1;
     char              *psz_sdp;
-    int               i_port_audio_option = var_GetInteger( p_stream, "port-audio" );
-    int               i_port_video_option = var_GetInteger( p_stream, "port-video" );
 
     if (0xffffffff == p_sys->payload_bitmap)
     {
@@ -864,38 +863,41 @@ static sout_stream_id_t *Add( sout_stream_t *p_stream, es_format_t *p_fmt )
         return NULL;
     }
 
-    id = vlc_object_create( p_stream, sizeof( sout_stream_id_t ) );
-    if( id == NULL )
-        return NULL;
-    vlc_object_attach( id, p_stream );
-
     /* Choose the port */
-    i_port = 0;
+    uint16_t i_port = 0;
     if( p_fmt == NULL )
         ;
     else
     if( p_fmt->i_cat == AUDIO_ES && p_sys->i_port_audio > 0 )
-    {
         i_port = p_sys->i_port_audio;
-        p_sys->i_port_audio = 0;
-    }
     else
     if( p_fmt->i_cat == VIDEO_ES && p_sys->i_port_video > 0 )
-    {
         i_port = p_sys->i_port_video;
-        p_sys->i_port_video = 0;
-    }
 
-    while( i_port == 0 )
+    /* We do not need the ES lock (p_sys->lock_es) here, because this is the
+     * only one thread that can *modify* the ES table. The ES lock protects
+     * the other threads from our modifications (TAB_APPEND, TAB_REMOVE). */
+    for (int i = 0; i_port && (i < p_sys->i_es); i++)
+         if (i_port == p_sys->es[i]->i_port)
+             i_port = 0; /* Port already in use! */
+    for (uint16_t p = p_sys->i_port; i_port == 0; p += 2)
     {
-        if( p_sys->i_port != i_port_audio_option
-         && p_sys->i_port != i_port_video_option )
+        if (p == 0)
         {
-            i_port = p_sys->i_port;
+            msg_Err (p_stream, "too many RTP elementary streams");
+            return NULL;
         }
-        p_sys->i_port += 2;
+        i_port = p;
+        for (int i = 0; i_port && (i < p_sys->i_es); i++)
+             if (p == p_sys->es[i]->i_port)
+                 i_port = 0;
     }
 
+    id = vlc_object_create( p_stream, sizeof( sout_stream_id_t ) );
+    if( id == NULL )
+        return NULL;
+    vlc_object_attach( id, p_stream );
+
     id->p_stream   = p_stream;
 
     /* Look for free dymanic payload type */
@@ -1030,21 +1032,21 @@ static sout_stream_id_t *Add( sout_stream_t *p_stream, es_format_t *p_fmt )
     else
     switch( p_fmt->i_codec )
     {
-        case VLC_FOURCC( 'u', 'l', 'a', 'w' ):
+        case VLC_CODEC_MULAW:
             if( p_fmt->audio.i_channels == 1 && p_fmt->audio.i_rate == 8000 )
                 id->i_payload_type = 0;
             id->psz_enc = "PCMU";
             id->pf_packetize = rtp_packetize_split;
             rtp_set_ptime (id, 20, 1);
             break;
-        case VLC_FOURCC( 'a', 'l', 'a', 'w' ):
+        case VLC_CODEC_ALAW:
             if( p_fmt->audio.i_channels == 1 && p_fmt->audio.i_rate == 8000 )
                 id->i_payload_type = 8;
             id->psz_enc = "PCMA";
             id->pf_packetize = rtp_packetize_split;
             rtp_set_ptime (id, 20, 1);
             break;
-        case VLC_FOURCC( 's', '1', '6', 'b' ):
+        case VLC_CODEC_S16B:
             if( p_fmt->audio.i_channels == 1 && p_fmt->audio.i_rate == 44100 )
             {
                 id->i_payload_type = 11;
@@ -1058,25 +1060,23 @@ static sout_stream_id_t *Add( sout_stream_t *p_stream, es_format_t *p_fmt )
             id->pf_packetize = rtp_packetize_split;
             rtp_set_ptime (id, 20, 2);
             break;
-        case VLC_FOURCC( 'u', '8', ' ', ' ' ):
+        case VLC_CODEC_U8:
             id->psz_enc = "L8";
             id->pf_packetize = rtp_packetize_split;
             rtp_set_ptime (id, 20, 1);
             break;
-        case VLC_FOURCC( 'm', 'p', 'g', 'a' ):
-        case VLC_FOURCC( 'm', 'p', '3', ' ' ):
+        case VLC_CODEC_MPGA:
             id->i_payload_type = 14;
             id->psz_enc = "MPA";
             id->i_clock_rate = 90000; /* not 44100 */
             id->pf_packetize = rtp_packetize_mpa;
             break;
-        case VLC_FOURCC( 'm', 'p', 'g', 'v' ):
+        case VLC_CODEC_MPGV:
             id->i_payload_type = 32;
             id->psz_enc = "MPV";
             id->pf_packetize = rtp_packetize_mpv;
             break;
-        case VLC_FOURCC( 'G', '7', '2', '6' ):
-        case VLC_FOURCC( 'g', '7', '2', '6' ):
+        case VLC_CODEC_ADPCM_G726:
             switch( p_fmt->i_bitrate / 1000 )
             {
             case 16:
@@ -1095,17 +1095,21 @@ static sout_stream_id_t *Add( sout_stream_t *p_stream, es_format_t *p_fmt )
                 id->psz_enc = "G726-40";
                 id->pf_packetize = rtp_packetize_g726_40;
                 break;
+            default:
+                msg_Err( p_stream, "cannot add this stream (unsupported "
+                         "G.726 bit rate: %u)", p_fmt->i_bitrate );
+                goto error;
             }
             break;
-        case VLC_FOURCC( 'a', '5', '2', ' ' ):
+        case VLC_CODEC_A52:
             id->psz_enc = "ac3";
             id->pf_packetize = rtp_packetize_ac3;
             break;
-        case VLC_FOURCC( 'H', '2', '6', '3' ):
+        case VLC_CODEC_H263:
             id->psz_enc = "H263-1998";
             id->pf_packetize = rtp_packetize_h263;
             break;
-        case VLC_FOURCC( 'h', '2', '6', '4' ):
+        case VLC_CODEC_H264:
             id->psz_enc = "H264";
             id->pf_packetize = rtp_packetize_h264;
             id->psz_fmtp = NULL;
@@ -1164,7 +1168,7 @@ static sout_stream_id_t *Add( sout_stream_t *p_stream, es_format_t *p_fmt )
                 id->psz_fmtp = strdup( "packetization-mode=1" );
             break;
 
-        case VLC_FOURCC( 'm', 'p', '4', 'v' ):
+        case VLC_CODEC_MP4V:
         {
             char hexa[2*p_fmt->i_extra +1];
 
@@ -1179,7 +1183,7 @@ static sout_stream_id_t *Add( sout_stream_t *p_stream, es_format_t *p_fmt )
             }
             break;
         }
-        case VLC_FOURCC( 'm', 'p', '4', 'a' ):
+        case VLC_CODEC_MP4A:
         {
             if(!p_sys->b_latm)
             {
@@ -1224,21 +1228,21 @@ static sout_stream_id_t *Add( sout_stream_t *p_stream, es_format_t *p_fmt )
             }
             break;
         }
-        case VLC_FOURCC( 's', 'a', 'm', 'r' ):
+        case VLC_CODEC_AMR_NB:
             id->psz_enc = "AMR";
             id->psz_fmtp = strdup( "octet-align=1" );
             id->pf_packetize = rtp_packetize_amr;
             break;
-        case VLC_FOURCC( 's', 'a', 'w', 'b' ):
+        case VLC_CODEC_AMR_WB:
             id->psz_enc = "AMR-WB";
             id->psz_fmtp = strdup( "octet-align=1" );
             id->pf_packetize = rtp_packetize_amr;
             break;
-        case VLC_FOURCC( 's', 'p', 'x', ' ' ):
+        case VLC_CODEC_SPEEX:
             id->psz_enc = "SPEEX";
             id->pf_packetize = rtp_packetize_spx;
             break;
-        case VLC_FOURCC( 't', '1', '4', '0' ):
+        case VLC_CODEC_ITU_T140:
             id->psz_enc = "t140" ;
             id->i_clock_rate = 1000;
             id->pf_packetize = rtp_packetize_t140;
@@ -1246,7 +1250,7 @@ static sout_stream_id_t *Add( sout_stream_t *p_stream, es_format_t *p_fmt )
 
         default:
             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 );
             goto error;
     }
     if (id->i_payload_type >= 96)
@@ -1287,7 +1291,7 @@ static sout_stream_id_t *Add( sout_stream_t *p_stream, es_format_t *p_fmt )
 
     /* Update SDP (sap/file) */
     if( p_sys->b_export_sap ) SapSetup( p_stream );
-    if( p_sys->b_export_sdp_file ) FileSetup( p_stream );
+    if( p_sys->psz_sdp_file != NULL ) FileSetup( p_stream );
 
     return id;
 
@@ -1311,11 +1315,6 @@ static int Del( sout_stream_t *p_stream, sout_stream_id_t *id )
     TAB_REMOVE( p_sys->i_es, p_sys->es, id );
     vlc_mutex_unlock( &p_sys->lock_es );
 
-    /* Release port */
-    if( id->i_port == var_GetInteger( p_stream, "port-audio" ) )
-        p_sys->i_port_audio = id->i_port;
-    if( id->i_port == var_GetInteger( p_stream, "port-video" ) )
-        p_sys->i_port_video = id->i_port;
     /* Release dynamic payload type */
     if (id->i_payload_type >= 96)
         p_sys->payload_bitmap &= ~(1 << (id->i_payload_type - 96));
@@ -1335,7 +1334,7 @@ static int Del( sout_stream_t *p_stream, sout_stream_id_t *id )
 
     /* Update SDP (sap/file) */
     if( p_sys->b_export_sap && !p_sys->p_mux ) SapSetup( p_stream );
-    if( p_sys->b_export_sdp_file ) FileSetup( p_stream );
+    if( p_sys->psz_sdp_file != NULL ) FileSetup( p_stream );
 
     vlc_object_detach( id );
     vlc_object_release( id );
@@ -1398,6 +1397,9 @@ static int FileSetup( sout_stream_t *p_stream )
     sout_stream_sys_t *p_sys = p_stream->p_sys;
     FILE            *f;
 
+    if( p_sys->psz_sdp == NULL )
+        return VLC_EGENERIC; /* too early */
+
     if( ( f = utf8_fopen( p_sys->psz_sdp_file, "wt" ) ) == NULL )
     {
         msg_Err( p_stream, "cannot open file '%s' (%m)",
@@ -1468,6 +1470,16 @@ static int  HttpCallback( httpd_file_sys_t *p_args,
  ****************************************************************************/
 static void* ThreadSend( vlc_object_t *p_this )
 {
+#ifdef WIN32
+# define ECONNREFUSED WSAECONNREFUSED
+# define ENOPROTOOPT  WSAENOPROTOOPT
+# define EHOSTUNREACH WSAEHOSTUNREACH
+# define ENETUNREACH  WSAENETUNREACH
+# define ENETDOWN     WSAENETDOWN
+# define ENOBUFS      WSAENOBUFS
+# define EAGAIN       WSAEWOULDBLOCK
+# define EWOULDBLOCK  WSAEWOULDBLOCK
+#endif
     sout_stream_id_t *id = (sout_stream_id_t *)p_this;
     unsigned i_caching = id->i_caching;
 
@@ -1516,9 +1528,27 @@ static void* ThreadSend( vlc_object_t *p_this )
 
             if( send( id->sinkv[i].rtp_fd, out->p_buffer, len, 0 ) >= 0 )
                 continue;
-            /* Retry sending to root out soft-errors */
-            if( send( id->sinkv[i].rtp_fd, out->p_buffer, len, 0 ) >= 0 )
-                continue;
+            switch( net_errno )
+            {
+                /* Soft errors (e.g. ICMP): */
+                case ECONNREFUSED: /* Port unreachable */
+                case ENOPROTOOPT:
+#ifdef EPROTO
+                case EPROTO:       /* Protocol unreachable */
+#endif
+                case EHOSTUNREACH: /* Host unreachable */
+                case ENETUNREACH:  /* Network unreachable */
+                case ENETDOWN:     /* Entire network down */
+                    send( id->sinkv[i].rtp_fd, out->p_buffer, len, 0 );
+                /* Transient congestion: */
+                case ENOMEM: /* out of socket buffers */
+                case ENOBUFS:
+                case EAGAIN:
+#if (EAGAIN != EWOULDBLOCK)
+                case EWOULDBLOCK:
+#endif
+                    continue;
+            }
 
             deadv[deadc++] = id->sinkv[i].rtp_fd;
         }
@@ -1609,7 +1639,7 @@ unsigned rtp_get_num( const sout_stream_id_t *id )
 void rtp_packetize_common( sout_stream_id_t *id, block_t *out,
                            int b_marker, int64_t i_pts )
 {
-    uint32_t i_timestamp = i_pts * (int64_t)id->i_clock_rate / INT64_C(1000000);
+    uint32_t i_timestamp = i_pts * (int64_t)id->i_clock_rate / CLOCK_FREQ;
 
     out->p_buffer[0] = 0x80;
     out->p_buffer[1] = (b_marker?0x80:0x00)|id->i_payload_type;