]> git.sesse.net Git - vlc/blobdiff - modules/stream_out/rtp.c
Replace strerror() with %m (or Linux DVB: strerror_r) - refs #1297
[vlc] / modules / stream_out / rtp.c
index 65c1b19bf403688457a2e5dcec6d8bda4db75f73..56c988c7d88ccd69b96d45e395863e655c590773 100644 (file)
 #define NAME_LONGTEXT N_( \
     "This is the name of the session that will be announced in the SDP " \
     "(Session Descriptor)." )
-#define DESC_TEXT N_("Session description")
+#define DESC_TEXT N_("Session descriptipn")
 #define DESC_LONGTEXT N_( \
-    "This allows you to give a broader description of the stream, that will " \
-    "be announced in the SDP (Session Descriptor)." )
+    "This allows you to give a short description with details about the stream, " \
+    "that will be announced in the SDP (Session Descriptor)." )
 #define URL_TEXT N_("Session URL")
 #define URL_LONGTEXT N_( \
     "This allows you to give an URL with more details about the stream " \
     "be announced in the SDP (Session Descriptor)." )
 #define EMAIL_TEXT N_("Session email")
 #define EMAIL_LONGTEXT N_( \
-   "This allows you to give a contact mail address for the stream, that will " \
-   "be announced in the SDP (Session Descriptor)." )
+    "This allows you to give a contact mail address for the stream, that will " \
+    "be announced in the SDP (Session Descriptor)." )
+#define PHONE_TEXT N_("Session phone number")
+#define PHONE_LONGTEXT N_( \
+    "This allows you to give a contact telephone number for the stream, that will " \
+    "be announced in the SDP (Session Descriptor)." )
+
 #define PORT_TEXT N_("Port")
 #define PORT_LONGTEXT N_( \
     "This allows you to specify the base port for the RTP streaming." )
@@ -141,6 +146,8 @@ vlc_module_begin();
                 URL_LONGTEXT, VLC_TRUE );
     add_string( SOUT_CFG_PREFIX "email", "", NULL, EMAIL_TEXT,
                 EMAIL_LONGTEXT, VLC_TRUE );
+    add_string( SOUT_CFG_PREFIX "phone", "", NULL, PHONE_TEXT,
+                PHONE_LONGTEXT, VLC_TRUE );
 
     add_integer( SOUT_CFG_PREFIX "port", 1234, NULL, PORT_TEXT,
                  PORT_LONGTEXT, VLC_TRUE );
@@ -170,7 +177,7 @@ vlc_module_end();
  *****************************************************************************/
 static const char *ppsz_sout_options[] = {
     "dst", "name", "port", "port-audio", "port-video", "*sdp", "ttl", "mux",
-    "description", "url", "email",
+    "description", "url", "email", "phone",
     "dccp", "tcp", "udplite",
     "mp4a-latm", NULL
 };
@@ -201,11 +208,6 @@ struct sout_stream_sys_t
     char    *psz_sdp;
     vlc_mutex_t  lock_sdp;
 
-    char        *psz_session_name;
-    char        *psz_session_description;
-    char        *psz_session_url;
-    char        *psz_session_email;
-
     /* SDP to disk */
     vlc_bool_t b_export_sdp_file;
     char *psz_sdp_file;
@@ -307,10 +309,6 @@ static int Open( vlc_object_t *p_this )
         return VLC_ENOMEM;
 
     p_sys->psz_destination = var_GetNonEmptyString( p_stream, SOUT_CFG_PREFIX "dst" );
-    p_sys->psz_session_name = var_GetNonEmptyString( p_stream, SOUT_CFG_PREFIX "name" );
-    p_sys->psz_session_description = var_GetNonEmptyString( p_stream, SOUT_CFG_PREFIX "description" );
-    p_sys->psz_session_url = var_GetNonEmptyString( p_stream, SOUT_CFG_PREFIX "url" );
-    p_sys->psz_session_email = var_GetNonEmptyString( p_stream, SOUT_CFG_PREFIX "email" );
 
     p_sys->i_port       = var_GetInteger( p_stream, SOUT_CFG_PREFIX "port" );
     p_sys->i_port_audio = var_GetInteger( p_stream, SOUT_CFG_PREFIX "port-audio" );
@@ -325,14 +323,6 @@ static int Open( vlc_object_t *p_this )
         p_sys->i_port_video = 0;
     }
 
-    if( !p_sys->psz_session_name )
-    {
-        if( p_sys->psz_destination )
-            p_sys->psz_session_name = strdup( p_sys->psz_destination );
-        else
-           p_sys->psz_session_name = strdup( "NONE" );
-    }
-
     for( p_cfg = p_stream->p_cfg; p_cfg != NULL; p_cfg = p_cfg->p_next )
     {
         if( !strcmp( p_cfg->psz_name, "sdp" )
@@ -545,10 +535,6 @@ static void Close( vlc_object_t * p_this )
     if( p_sys->p_httpd_host )
         httpd_HostDelete( p_sys->p_httpd_host );
 
-    free( p_sys->psz_session_name );
-    free( p_sys->psz_session_description );
-    free( p_sys->psz_session_url );
-    free( p_sys->psz_session_email );
     free( p_sys->psz_sdp );
 
     if( p_sys->b_export_sdp_file )
@@ -639,19 +625,6 @@ out:
 /*****************************************************************************
  * SDPGenerate
  *****************************************************************************/
-        /* FIXME  http://www.faqs.org/rfcs/rfc2327.html
-           All text fields should be UTF-8 encoded. Use global a:charset to announce this.
-           o= - should be local username (no spaces allowed)
-           o= time should be hashed with some other value to garantue uniqueness
-           o= we need IP6 support?
-           o= don't use the localhost address. use fully qualified domain name or IP4 address
-           p= international phone number (pass via vars?)
-           c= IP6 support
-           a= recvonly (missing)
-           a= type:broadcast (missing)
-           a= charset: (normally charset should be UTF-8, this can be used to override s= and i=)
-           a= x-plgroup: (missing)
-           RTP packets need to get the correct src IP address  */
 /*static*/
 char *SDPGenerate( const sout_stream_t *p_stream, const char *rtsp_url )
 {
@@ -699,35 +672,49 @@ char *SDPGenerate( const sout_stream_t *p_stream, const char *rtsp_url )
         dstlen = sizeof( struct sockaddr_in );
     }
 
-    psz_sdp = sdp_Start( p_sys->psz_session_name,
-                         p_sys->psz_session_description,
-                         p_sys->psz_session_url, p_sys->psz_session_email,
-                         NULL, NULL, 0, (struct sockaddr *)&dst, dstlen );
+    psz_sdp = vlc_sdp_Start( VLC_OBJECT( p_stream ), SOUT_CFG_PREFIX,
+                             NULL, 0, (struct sockaddr *)&dst, dstlen );
     if( psz_sdp == NULL )
         return NULL;
 
     /* TODO: a=source-filter */
 
+    if( rtsp_url != NULL )
+        sdp_AddAttribute ( &psz_sdp, "control", "%s", rtsp_url );
+
     /* FIXME: locking?! */
     for( i = 0; i < p_sys->i_es; i++ )
     {
         sout_stream_id_t *id = p_sys->es[i];
         const char *mime_major; /* major MIME type */
 
-        if( id->i_cat == AUDIO_ES )
-            mime_major = "audio";
-        else
-        if( id->i_cat == VIDEO_ES )
-            mime_major = "video";
-        else
-            continue;
+        switch( id->i_cat )
+        {
+            case VIDEO_ES:
+                mime_major = "video";
+                break;
+            case AUDIO_ES:
+                mime_major = "audio";
+                break;
+            case SPU_ES:
+                mime_major = "text";
+                break;
+            default:
+                continue;
+        }
 
         sdp_AddMedia( &psz_sdp, mime_major, "RTP/AVP", inclport * id->i_port,
                       id->i_payload_type, VLC_FALSE, id->i_bitrate,
                       id->psz_rtpmap, id->psz_fmtp);
 
         if( rtsp_url != NULL )
-            sdp_AddAttribute ( &psz_sdp, "control", "/trackID=%d", i );
+        {
+            assert( strlen( rtsp_url ) > 0 );
+            vlc_bool_t addslash = ( rtsp_url[strlen( rtsp_url ) - 1] != '/' );
+            sdp_AddAttribute ( &psz_sdp, "control",
+                               addslash ? "%s/trackID=%u" : "%strackID=%u",
+                               rtsp_url, i );
+        }
     }
 
     return psz_sdp;
@@ -747,6 +734,7 @@ static int rtp_packetize_mp4a_latm ( sout_stream_t *, sout_stream_id_t *, block_
 static int rtp_packetize_h263 ( sout_stream_t *, sout_stream_id_t *, block_t * );
 static int rtp_packetize_h264 ( sout_stream_t *, sout_stream_id_t *, block_t * );
 static int rtp_packetize_amr  ( sout_stream_t *, sout_stream_id_t *, block_t * );
+static int rtp_packetize_t140 ( sout_stream_t *, sout_stream_id_t *, block_t * );
 
 static void sprintf_hexa( char *s, uint8_t *p_data, int i_data )
 {
@@ -1072,6 +1060,11 @@ static sout_stream_id_t *Add( sout_stream_t *p_stream, es_format_t *p_fmt )
             id->i_clock_rate = p_fmt->audio.i_rate;
             id->pf_packetize = rtp_packetize_amr;
             break;
+        case VLC_FOURCC( 't', '1', '4', '0' ):
+            id->psz_rtpmap = strdup( "t140/1000" );
+            id->i_clock_rate = 1000;
+            id->pf_packetize = rtp_packetize_t140;
+            break;
 
         default:
             msg_Err( p_stream, "cannot add this stream (unsupported "
@@ -1126,6 +1119,7 @@ static int Del( sout_stream_t *p_stream, sout_stream_id_t *id )
     sout_stream_sys_t *p_sys = p_stream->p_sys;
 
     vlc_object_kill( id );
+    block_FifoWake( id->p_fifo );
 
     vlc_mutex_lock( &p_sys->lock_es );
     TAB_REMOVE( p_sys->i_es, p_sys->es, id );
@@ -1187,25 +1181,24 @@ static int SapSetup( sout_stream_t *p_stream )
 {
     sout_stream_sys_t *p_sys = p_stream->p_sys;
     sout_instance_t   *p_sout = p_stream->p_sout;
-    announce_method_t *p_method = sout_SAPMethod();
 
     /* Remove the previous session */
     if( p_sys->p_session != NULL)
     {
         sout_AnnounceUnRegister( p_sout, p_sys->p_session);
-        sout_AnnounceSessionDestroy( p_sys->p_session );
         p_sys->p_session = NULL;
     }
 
     if( ( p_sys->i_es > 0 || p_sys->p_mux ) && p_sys->psz_sdp && *p_sys->psz_sdp )
     {
+        announce_method_t *p_method = sout_SAPMethod();
         p_sys->p_session = sout_AnnounceRegisterSDP( p_sout, SOUT_CFG_PREFIX,
                                                      p_sys->psz_sdp,
                                                      p_sys->psz_destination,
                                                      p_method );
+        sout_MethodRelease( p_method );
     }
 
-    sout_MethodRelease( p_method );
     return VLC_SUCCESS;
 }
 
@@ -1219,8 +1212,8 @@ static int FileSetup( sout_stream_t *p_stream )
 
     if( ( f = utf8_fopen( p_sys->psz_sdp_file, "wt" ) ) == NULL )
     {
-        msg_Err( p_stream, "cannot open file '%s' (%s)",
-                 p_sys->psz_sdp_file, strerror(errno) );
+        msg_Err( p_stream, "cannot open file '%s' (%m)",
+                 p_sys->psz_sdp_file );
         return VLC_EGENERIC;
     }
 
@@ -1303,6 +1296,9 @@ static void ThreadSend( vlc_object_t *p_this )
     while( !id->b_die )
     {
         block_t *out = block_FifoGet( id->p_fifo );
+        if( out == NULL )
+            continue; /* Forced wakeup */
+
         mtime_t  i_date = out->i_dts + i_caching;
         ssize_t  len = out->i_buffer;
 
@@ -1997,6 +1993,52 @@ static int rtp_packetize_amr( sout_stream_t *p_stream, sout_stream_id_t *id,
     return VLC_SUCCESS;
 }
 
+static int rtp_packetize_t140( sout_stream_t *p_stream, sout_stream_id_t *id,
+                               block_t *in )
+{
+    const size_t   i_max  = id->i_mtu - 12;
+    const uint8_t *p_data = in->p_buffer;
+    size_t         i_data = in->i_buffer;
+
+    for( unsigned i_packet = 0; i_data > 0; i_packet++ )
+    {
+        size_t i_payload = i_data;
+
+        /* Make sure we stop on an UTF-8 character boundary
+         * (assuming the input is valid UTF-8) */
+        if( i_data > i_max )
+        {
+            i_payload = i_max;
+
+            while( ( p_data[i_payload] & 0xC0 ) == 0x80 )
+            {
+                if( i_payload == 0 )
+                    return VLC_SUCCESS; /* fishy input! */
+
+                i_payload--;
+            }
+        }
+
+        block_t *out = block_New( p_stream, 12 + i_payload );
+        if( out == NULL )
+            return VLC_SUCCESS;
+
+        rtp_packetize_common( id, out, 0, in->i_pts + i_packet );
+        memcpy( out->p_buffer + 12, p_data, i_payload );
+
+        out->i_buffer = 12 + i_payload;
+        out->i_dts    = out->i_pts;
+        out->i_length = 0;
+
+        rtp_packetize_send( id, out );
+
+        p_data += i_payload;
+        i_data -= i_payload;
+    }
+
+    return VLC_SUCCESS;
+}
+
 /*****************************************************************************
  * Non-RTP mux
  *****************************************************************************/