]> git.sesse.net Git - vlc/blobdiff - modules/access_output/udp.c
get rid of confusing --sout-udp-ttl and unneded warning message
[vlc] / modules / access_output / udp.c
index cc32019f359336f929b17236e8e49ad93df9a4cf..12230dfe0395eaa40a02806d56c58c577d6c04ee 100644 (file)
@@ -1,7 +1,7 @@
 /*****************************************************************************
  * udp.c
  *****************************************************************************
- * Copyright (C) 2001, 2002 VideoLAN
+ * Copyright (C) 2001-2005 the VideoLAN team
  * $Id$
  *
  * Authors: Laurent Aimar <fenrir@via.ecp.fr>
 
 #include "network.h"
 
+#define MAX_EMPTY_BLOCKS 200
+
+#if defined(WIN32) || defined(UNDER_CE)
+# define WINSOCK_STRERROR_SIZE 20
+static const char *winsock_strerror( char *buf )
+{
+    snprintf( buf, WINSOCK_STRERROR_SIZE, "Winsock error %d",
+              WSAGetLastError( ) );
+    buf[WINSOCK_STRERROR_SIZE - 1] = '\0';
+    return buf;
+}
+#endif
 
 /*****************************************************************************
  * Module descriptor
@@ -65,20 +77,12 @@ static void Close( vlc_object_t * );
     "Allows you to modify the default caching value for UDP streams. This " \
     "value should be set in millisecond units." )
 
-#define TTL_TEXT N_("Time To Live")
-#define TTL_LONGTEXT N_("Allows you to define the time to live of the " \
-                        "outgoing stream.")
-
 #define GROUP_TEXT N_("Group packets")
 #define GROUP_LONGTEXT N_("Packets can be sent one by one at the right time " \
                           "or by groups. This allows you to give the number " \
                           "of packets that will be sent at a time. It " \
                           "helps reducing the scheduling load on " \
                           "heavily-loaded systems." )
-#define LATE_TEXT N_("Late delay (ms)" )
-#define LATE_LONGTEXT N_("Late packets are dropped. This allows you to give " \
-                       "the time (in milliseconds) a packet is allowed to be" \
-                       " late.")
 #define RAW_TEXT N_("Raw write")
 #define RAW_LONGTEXT N_("If you enable this option, packets will be sent " \
                        "directly, without trying to fill the MTU (ie, " \
@@ -87,13 +91,13 @@ static void Close( vlc_object_t * );
 
 vlc_module_begin();
     set_description( _("UDP stream output") );
+    set_shortname( N_( "UDP" ) );
+    set_category( CAT_SOUT );
+    set_subcategory( SUBCAT_SOUT_ACO );
     add_integer( SOUT_CFG_PREFIX "caching", DEFAULT_PTS_DELAY / 1000, NULL, CACHING_TEXT, CACHING_LONGTEXT, VLC_TRUE );
-    add_integer( SOUT_CFG_PREFIX "ttl", 0, NULL,TTL_TEXT, TTL_LONGTEXT,
-                                 VLC_TRUE );
     add_integer( SOUT_CFG_PREFIX "group", 1, NULL, GROUP_TEXT, GROUP_LONGTEXT,
                                  VLC_TRUE );
-    add_integer( SOUT_CFG_PREFIX "late", 0, NULL, LATE_TEXT, LATE_LONGTEXT,
-                                 VLC_TRUE );
+    add_suppressed_integer( SOUT_CFG_PREFIX "late" );
     add_bool( SOUT_CFG_PREFIX "raw",  0, NULL, RAW_TEXT, RAW_LONGTEXT,
                                  VLC_TRUE );
 
@@ -109,9 +113,7 @@ vlc_module_end();
 
 static const char *ppsz_sout_options[] = {
     "caching",
-    "ttl",
     "group",
-    "late",
     "raw",
     NULL
 };
@@ -134,9 +136,12 @@ typedef struct sout_access_thread_t
     int         i_handle;
 
     int64_t     i_caching;
-    int64_t     i_late;
     int         i_group;
 
+    vlc_mutex_t blocks_lock;
+    block_t     *p_empty_blocks;
+    int         i_empty_depth;
+
 } sout_access_thread_t;
 
 struct sout_access_out_sys_t
@@ -187,8 +192,6 @@ static int Open( vlc_object_t *p_this )
     if( p_access->psz_access != NULL &&
         !strcmp( p_access->psz_access, "rtp" ) )
     {
-        msg_Warn( p_access, "be careful that rtp output only works with ts "
-                  "payload (not an error)" );
         p_sys->b_rtpts = 1;
     }
     else
@@ -235,25 +238,39 @@ static int Open( vlc_object_t *p_this )
     p_sys->p_thread->b_die  = 0;
     p_sys->p_thread->b_error= 0;
     p_sys->p_thread->p_fifo = block_FifoNew( p_access );
+    p_sys->p_thread->p_empty_blocks = NULL;
+    p_sys->p_thread->i_empty_depth = 0;
+    vlc_mutex_init( p_access, &p_sys->p_thread->blocks_lock );
 
-    socket_desc.i_type = NETWORK_UDP;
+    /* FIXME: use net_OpenUDP API */
     socket_desc.psz_server_addr = psz_dst_addr;
     socket_desc.i_server_port   = i_dst_port;
     socket_desc.psz_bind_addr   = "";
     socket_desc.i_bind_port     = 0;
-
-    var_Get( p_access, SOUT_CFG_PREFIX "ttl", &val );
-    socket_desc.i_ttl = val.i_int;
+    socket_desc.i_handle        = -1;
+    socket_desc.v6only          = 0;
+    socket_desc.i_ttl           = 0;
 
     p_sys->p_thread->p_private = (void*)&socket_desc;
-    if( !( p_network = module_Need( p_sys->p_thread, "network", NULL, 0 ) ) )
+    p_network = module_Need( p_sys->p_thread, "network", "ipv4", VLC_TRUE );
+    if( p_network != NULL )
+        module_Unneed( p_sys->p_thread, p_network );
+
+    if( socket_desc.i_handle == -1 )
     {
-        msg_Err( p_access, "failed to open a connection (udp)" );
-        return VLC_EGENERIC;
+        p_network = module_Need( p_sys->p_thread, "network", "ipv6", VLC_TRUE );
+        if( p_network != NULL )
+            module_Unneed( p_sys->p_thread, p_network );
+
+        if( socket_desc.i_handle == -1 )
+        {
+            msg_Err( p_access, "failed to open a connection (udp)" );
+            return VLC_EGENERIC;
+        }
     }
-    module_Unneed( p_sys->p_thread, p_network );
 
     p_sys->p_thread->i_handle = socket_desc.i_handle;
+    net_StopRecv( socket_desc.i_handle );
 
     var_Get( p_access, SOUT_CFG_PREFIX "caching", &val );
     p_sys->p_thread->i_caching = (int64_t)val.i_int * 1000;
@@ -261,18 +278,10 @@ static int Open( vlc_object_t *p_this )
     var_Get( p_access, SOUT_CFG_PREFIX "group", &val );
     p_sys->p_thread->i_group = val.i_int;
 
-    var_Get( p_access, SOUT_CFG_PREFIX "late", &val );
-    p_sys->p_thread->i_late = (int64_t)val.i_int * 1000;
-
     p_sys->i_mtu = socket_desc.i_mtu;
 
-#ifdef WIN32
     if( vlc_thread_create( p_sys->p_thread, "sout write thread", ThreadWrite,
                            VLC_THREAD_PRIORITY_HIGHEST, VLC_FALSE ) )
-#else
-    if( vlc_thread_create( p_sys->p_thread, "sout write thread", ThreadWrite,
-                           VLC_THREAD_PRIORITY_OUTPUT, VLC_FALSE ) )
-#endif
     {
         msg_Err( p_access->p_sout, "cannot spawn sout access thread" );
         vlc_object_destroy( p_sys->p_thread );
@@ -317,6 +326,7 @@ static void Close( vlc_object_t * p_this )
         p_dummy->i_dts = 0;
         p_dummy->i_pts = 0;
         p_dummy->i_length = 0;
+        memset( p_dummy->p_buffer, 0, p_dummy->i_buffer );
         block_FifoPut( p_sys->p_thread->p_fifo, p_dummy );
     }
     vlc_thread_join( p_sys->p_thread );
@@ -324,6 +334,13 @@ static void Close( vlc_object_t * p_this )
     block_FifoRelease( p_sys->p_thread->p_fifo );
 
     if( p_sys->p_buffer ) block_Release( p_sys->p_buffer );
+    while ( p_sys->p_thread->p_empty_blocks != NULL )
+    {
+        block_t *p_next = p_sys->p_thread->p_empty_blocks->p_next;
+        block_Release( p_sys->p_thread->p_empty_blocks );
+        p_sys->p_thread->p_empty_blocks = p_next;
+    }
+    vlc_mutex_destroy( &p_sys->p_thread->blocks_lock );
 
     net_Close( p_sys->p_thread->i_handle );
 
@@ -357,6 +374,12 @@ static int Write( sout_access_out_t *p_access, block_t *p_buffer )
         if( p_sys->p_buffer &&
             p_sys->p_buffer->i_buffer + p_buffer->i_buffer > p_sys->i_mtu )
         {
+            if( p_sys->p_buffer->i_dts + p_sys->p_thread->i_caching < mdate() )
+            {
+                msg_Dbg( p_access, "late packet for udp input (" I64Fd ")",
+                         mdate() - p_sys->p_buffer->i_dts
+                          - p_sys->p_thread->i_caching );
+            }
             block_FifoPut( p_sys->p_thread->p_fifo, p_sys->p_buffer );
             p_sys->p_buffer = NULL;
         }
@@ -379,10 +402,23 @@ static int Write( sout_access_out_t *p_access, block_t *p_buffer )
             p_sys->p_buffer->i_buffer += i_write;
             p_buffer->p_buffer += i_write;
             p_buffer->i_buffer -= i_write;
+            if ( p_buffer->i_flags & BLOCK_FLAG_CLOCK )
+            {
+                if ( p_sys->p_buffer->i_flags & BLOCK_FLAG_CLOCK )
+                    msg_Warn( p_access, "putting two PCRs at once" );
+                p_sys->p_buffer->i_flags |= BLOCK_FLAG_CLOCK;
+            }
 
             if( p_sys->p_buffer->i_buffer == p_sys->i_mtu || i_packets > 1 )
             {
                 /* Flush */
+                if( p_sys->p_buffer->i_dts + p_sys->p_thread->i_caching
+                      < mdate() )
+                {
+                    msg_Dbg( p_access, "late packet for udp input (" I64Fd ")",
+                             mdate() - p_sys->p_buffer->i_dts
+                              - p_sys->p_thread->i_caching );
+                }
                 block_FifoPut( p_sys->p_thread->p_fifo, p_sys->p_buffer );
                 p_sys->p_buffer = NULL;
             }
@@ -425,7 +461,34 @@ static block_t *NewUDPPacket( sout_access_out_t *p_access, mtime_t i_dts)
     sout_access_out_sys_t *p_sys = p_access->p_sys;
     block_t *p_buffer;
 
-    p_buffer = block_New( p_access->p_sout, p_sys->i_mtu );
+    vlc_mutex_lock( &p_sys->p_thread->blocks_lock );
+    while ( p_sys->p_thread->i_empty_depth > MAX_EMPTY_BLOCKS )
+    {
+        p_buffer = p_sys->p_thread->p_empty_blocks;
+        p_sys->p_thread->p_empty_blocks =
+                    p_sys->p_thread->p_empty_blocks->p_next;
+        p_sys->p_thread->i_empty_depth--;
+        vlc_mutex_unlock( &p_sys->p_thread->blocks_lock );
+        block_Release( p_buffer );
+        vlc_mutex_lock( &p_sys->p_thread->blocks_lock );
+    }
+    p_buffer = p_sys->p_thread->p_empty_blocks;
+    if ( p_buffer != NULL )
+    {
+        p_sys->p_thread->p_empty_blocks =
+                    p_sys->p_thread->p_empty_blocks->p_next;
+        p_sys->p_thread->i_empty_depth--;
+        vlc_mutex_unlock( &p_sys->p_thread->blocks_lock );
+        p_buffer->p_next = NULL;
+        p_buffer->i_flags = 0;
+        p_buffer = block_Realloc( p_buffer, 0, p_sys->i_mtu );
+    }
+    else
+    {
+        vlc_mutex_unlock( &p_sys->p_thread->blocks_lock );
+        p_buffer = block_New( p_access->p_sout, p_sys->i_mtu );
+    }
+
     p_buffer->i_dts = i_dts;
     p_buffer->i_buffer = 0;
 
@@ -466,6 +529,10 @@ static void ThreadWrite( vlc_object_t *p_this )
     mtime_t              i_date_last = -1;
     mtime_t              i_to_send = p_thread->i_group;
     int                  i_dropped_packets = 0;
+#if defined(WIN32) || defined(UNDER_CE)
+    char strerror_buf[WINSOCK_STRERROR_SIZE];
+# define strerror( x ) winsock_strerror( strerror_buf )
+#endif
 
     while( !p_thread->b_die )
     {
@@ -483,45 +550,35 @@ static void ThreadWrite( vlc_object_t *p_this )
                     msg_Dbg( p_thread, "mmh, hole ("I64Fd" > 2s) -> drop",
                              i_date - i_date_last );
 
-                block_Release( p_pk  );
-                i_date_last = i_date;
-                i_dropped_packets++;
-                continue;
-            }
-            else if( i_date - i_date_last < 0 )
-            {
-                if( !i_dropped_packets )
-                    msg_Dbg( p_thread, "mmh, packets in the past ("I64Fd")"
-                             " -> drop", i_date - i_date_last );
+                vlc_mutex_lock( &p_thread->blocks_lock );
+                p_pk->p_next = p_thread->p_empty_blocks;
+                p_thread->p_empty_blocks = p_pk;
+                p_thread->i_empty_depth++;
+                vlc_mutex_unlock( &p_thread->blocks_lock );
 
-                block_Release( p_pk  );
                 i_date_last = i_date;
                 i_dropped_packets++;
                 continue;
             }
-        }
-
-        i_sent = mdate();
-        if( p_thread->i_late > 0 && i_sent > i_date + p_thread->i_late )
-        {
-            if( !i_dropped_packets )
+            else if( i_date - i_date_last < -1000 )
             {
-                msg_Dbg( p_thread, "late packet to send (" I64Fd ") -> drop",
-                         i_sent - i_date );
+                if( !i_dropped_packets )
+                    msg_Dbg( p_thread, "mmh, packets in the past ("I64Fd")",
+                             i_date_last - i_date );
             }
-            block_Release( p_pk  );
-            i_date_last = i_date;
-            i_dropped_packets++;
-            continue;
         }
 
         i_to_send--;
-        if ( !i_to_send )
+        if( !i_to_send || (p_pk->i_flags & BLOCK_FLAG_CLOCK) )
         {
             mwait( i_date );
             i_to_send = p_thread->i_group;
         }
-        send( p_thread->i_handle, p_pk->p_buffer, p_pk->i_buffer, 0 );
+        if( send( p_thread->i_handle, p_pk->p_buffer, p_pk->i_buffer, 0 )
+              == -1 )
+        {
+            msg_Warn( p_thread, "send error: %s", strerror(errno) );
+        }
 
         if( i_dropped_packets )
         {
@@ -529,7 +586,7 @@ static void ThreadWrite( vlc_object_t *p_this )
             i_dropped_packets = 0;
         }
 
-#if 0
+#if 1
         i_sent = mdate();
         if ( i_sent > i_date + 20000 )
         {
@@ -538,7 +595,12 @@ static void ThreadWrite( vlc_object_t *p_this )
         }
 #endif
 
-        block_Release( p_pk  );
+        vlc_mutex_lock( &p_thread->blocks_lock );
+        p_pk->p_next = p_thread->p_empty_blocks;
+        p_thread->p_empty_blocks = p_pk;
+        p_thread->i_empty_depth++;
+        vlc_mutex_unlock( &p_thread->blocks_lock );
+
         i_date_last = i_date;
     }
 }