]> git.sesse.net Git - vlc/blobdiff - modules/audio_output/oss.c
* modules/audio_output/oss.c: when now set the fragment size of the OSS device
[vlc] / modules / audio_output / oss.c
index 9204b1569fb8a2137a9175de0b09db92f1b938ba..736ebfbb06458ea76a9dc1ff9adab0bd342f6ecb 100644 (file)
@@ -2,7 +2,7 @@
  * oss.c : OSS /dev/dsp module for vlc
  *****************************************************************************
  * Copyright (C) 2000-2002 VideoLAN
- * $Id: oss.c,v 1.30 2002/10/20 12:23:47 massiot Exp $
+ * $Id: oss.c,v 1.32 2002/10/25 15:21:42 gbazin Exp $
  *
  * Authors: Michel Kaempf <maxx@via.ecp.fr>
  *          Samuel Hocevar <sam@zoy.org>
  *****************************************************************************/
 struct aout_sys_t
 {
-    int                   i_fd;
+    int i_fd;
+    int b_workaround_buggy_driver;
+    int i_fragstotal;
+    mtime_t max_buffer_duration;
 };
 
 /* This must be a power of 2. */
 #define FRAME_SIZE 1024
-#define FRAME_COUNT 8
+#define FRAME_COUNT 4
 #define A52_FRAME_NB 1536
 
 /*****************************************************************************
@@ -78,13 +81,22 @@ static void Close        ( vlc_object_t * );
 static void Play         ( aout_instance_t * );
 static int  OSSThread    ( aout_instance_t * );
 
+static mtime_t BufferDuration( aout_instance_t * p_aout );
+
 /*****************************************************************************
  * Module descriptor
  *****************************************************************************/
+#define BUGGY_TEXT N_("Try to work around buggy OSS drivers")
+#define BUGGY_LONGTEXT N_( \
+    "Some buggy OSS drivers just don't like when their internal buffers " \
+    "are completely filled (the sound gets heavily hashed). If you have one " \
+    "of these drivers, then you need to enable this option." )
+
 vlc_module_begin();
     add_category_hint( N_("OSS"), NULL );
     add_file( "dspdev", "/dev/dsp", aout_FindAndRestart,
               N_("OSS dsp device"), NULL );
+    add_bool( "oss-buggy", 0, NULL, BUGGY_TEXT, BUGGY_LONGTEXT );
     set_description( _("Linux OSS /dev/dsp module") );
     set_capability( "audio output", 100 );
     add_shortcut( "oss" );
@@ -120,14 +132,14 @@ static int Open( vlc_object_t *p_this )
     }
 
     /* Open the sound device */
-    if( (p_sys->i_fd = open( psz_device, O_WRONLY )) < 0 )
+    p_sys->i_fd = open( psz_device, O_WRONLY );
+    free( psz_device );
+    if( p_sys->i_fd < 0 )
     {
         msg_Err( p_aout, "cannot open audio device (%s)", psz_device );
-        free( psz_device );
         free( p_sys );
         return VLC_EGENERIC;
     }
-    free( psz_device );
 
     p_aout->output.pf_play = Play;
 
@@ -167,6 +179,7 @@ static int Open( vlc_object_t *p_this )
         int i_frame_size, i_fragments;
         int i_rate;
         int i_nb_channels;
+        audio_buf_info audio_buf;
 
         if( ioctl( p_sys->i_fd, SNDCTL_DSP_SETFMT, &i_format ) < 0 )
         {
@@ -204,26 +217,6 @@ static int Open( vlc_object_t *p_this )
             return VLC_EGENERIC;
         }
 
-        p_aout->output.output.i_format = AOUT_FMT_S16_NE;
-        p_aout->output.i_nb_samples = FRAME_SIZE;
-
-        aout_VolumeSoftInit( p_aout );
-
-        /* Set the fragment size
-         * i_fragment = xxxxyyyy where: xxxx        is fragtotal
-         *                              1 << yyyy   is fragsize */
-        i_fragments = 0;
-        i_frame_size = FRAME_SIZE;
-        while( i_frame_size >>= 1 )
-        {
-            ++i_fragments;
-        }
-        i_fragments |= FRAME_COUNT << 16;
-        if( ioctl( p_sys->i_fd, SNDCTL_DSP_SETFRAGMENT, &i_fragments ) < 0 )
-        {
-            msg_Warn( p_aout, "cannot set fragment size (%.8x)", i_fragments );
-        }
-
         /* These cases are desperate because of the OSS API and A/52 spec. */
         switch ( p_aout->output.output.i_channels )
         {
@@ -333,6 +326,48 @@ static int Open( vlc_object_t *p_this )
         {
             p_aout->output.output.i_rate = i_rate;
         }
+
+        /* Set the fragment size */
+        aout_FormatPrepare( &p_aout->output.output );
+
+        /* i_fragment = xxxxyyyy where: xxxx        is fragtotal
+         *                              1 << yyyy   is fragsize */
+        i_fragments = 0;
+        i_frame_size = FRAME_SIZE * p_aout->output.output.i_bytes_per_frame;
+        while( i_frame_size >>= 1 )
+        {
+            ++i_fragments;
+        }
+        i_fragments |= FRAME_COUNT << 16;
+        if( ioctl( p_sys->i_fd, SNDCTL_DSP_SETFRAGMENT, &i_fragments ) < 0 )
+        {
+            msg_Warn( p_aout, "cannot set fragment size (%.8x)", i_fragments );
+        }
+
+        if( ioctl( p_sys->i_fd, SNDCTL_DSP_GETOSPACE, &audio_buf ) < 0 )
+        {
+            msg_Warn( p_aout, "cannot get fragment size" );
+            close( p_sys->i_fd );
+            free( p_sys );
+            return VLC_EGENERIC;
+        }
+       else
+        {
+            /* Number of fragments actually allocated */
+            p_aout->output.p_sys->i_fragstotal = audio_buf.fragstotal;
+
+            /* Maximum duration the soundcard's buffer can hold */
+            p_aout->output.p_sys->max_buffer_duration =
+                (mtime_t)audio_buf.fragstotal * audio_buf.fragsize * 1000000
+                / p_aout->output.output.i_bytes_per_frame
+                / p_aout->output.output.i_rate
+                * p_aout->output.output.i_frame_length;
+
+            p_aout->output.i_nb_samples = audio_buf.fragsize /
+                p_aout->output.output.i_bytes_per_frame;
+        }
+
+        aout_VolumeSoftInit( p_aout );
     }
 
     /* Create OSS thread and wait for its readiness. */
@@ -341,11 +376,13 @@ static int Open( vlc_object_t *p_this )
     {
         msg_Err( p_aout, "cannot create OSS thread (%s)", strerror(errno) );
         close( p_sys->i_fd );
-        free( psz_device );
         free( p_sys );
         return VLC_ETHREAD;
     }
 
+    p_aout->output.p_sys->b_workaround_buggy_driver =
+        config_GetInt( p_aout, "oss-buggy" );
+
     return VLC_SUCCESS;
 }
 
@@ -374,7 +411,6 @@ static void Close( vlc_object_t * p_this )
     free( p_sys );
 }
 
-
 /*****************************************************************************
  * BufferDuration: buffer status query
  *****************************************************************************
@@ -421,11 +457,18 @@ static int OSSThread( aout_instance_t * p_aout )
         {
             mtime_t buffered = BufferDuration( p_aout );
 
-            /* Wait a bit - we don't want our buffer to be full */
-            while( buffered > AOUT_PTS_TOLERANCE * 2 )
+            if( p_aout->output.p_sys->b_workaround_buggy_driver )
             {
-                msleep( buffered / 2 - 10000 );
-                buffered = BufferDuration( p_aout );
+#define i_fragstotal p_aout->output.p_sys->i_fragstotal
+                /* Wait a bit - we don't want our buffer to be full */
+                if( buffered > (p_aout->output.p_sys->max_buffer_duration
+                                / i_fragstotal * (i_fragstotal - 1)) )
+                {
+                    msleep((p_aout->output.p_sys->max_buffer_duration
+                                / i_fragstotal ));
+                    buffered = BufferDuration( p_aout );
+                }
+#undef i_fragstotal
             }
 
             if( !next_date )