]> git.sesse.net Git - vlc/blobdiff - modules/audio_output/oss.c
ALSA: remove variable callback (refs #5273)
[vlc] / modules / audio_output / oss.c
index 03ef538b7f9d55b18f9c8e14696c4ba96b8469a6..54d4865b13f04bacc4008ae1acb79823fae573fc 100644 (file)
@@ -70,6 +70,7 @@
  *****************************************************************************/
 struct aout_sys_t
 {
+    aout_packet_t packet;
     int i_fd;
     int i_fragstotal;
     mtime_t max_buffer_duration;
@@ -86,10 +87,10 @@ struct aout_sys_t
 static int  Open         ( vlc_object_t * );
 static void Close        ( vlc_object_t * );
 
-static void Play         ( aout_instance_t * );
+static void Play         ( audio_output_t *, block_t * );
 static void* OSSThread   ( void * );
 
-static mtime_t BufferDuration( aout_instance_t * p_aout );
+static mtime_t BufferDuration( audio_output_t * p_aout );
 
 /*****************************************************************************
  * Module descriptor
@@ -102,7 +103,6 @@ vlc_module_begin ()
     set_subcategory( SUBCAT_AUDIO_AOUT )
     add_loadfile( "oss-audio-device", "/dev/dsp",
                   N_("OSS DSP device"), NULL, false )
-        add_deprecated_alias( "dspdev" )   /* deprecated since 0.9.3 */
 
     set_capability( "audio output", 100 )
     add_shortcut( "oss" )
@@ -112,9 +112,9 @@ vlc_module_end ()
 /*****************************************************************************
  * Probe: probe the audio device for available formats and channels
  *****************************************************************************/
-static void Probe( aout_instance_t * p_aout )
+static void Probe( audio_output_t * p_aout )
 {
-    struct aout_sys_t * p_sys = p_aout->output.p_sys;
+    struct aout_sys_t * p_sys = p_aout->sys;
     vlc_value_t val, text;
     int i_format, i_nb_channels;
 
@@ -124,7 +124,7 @@ static void Probe( aout_instance_t * p_aout )
 
     /* Test for multi-channel. */
 #ifdef SNDCTL_DSP_GETCHANNELMASK
-    if ( aout_FormatNbChannels( &p_aout->output.output ) > 2 )
+    if ( aout_FormatNbChannels( &p_aout->format ) > 2 )
     {
         /* Check that the device supports this. */
 
@@ -151,7 +151,7 @@ static void Probe( aout_instance_t * p_aout )
             }
 
             if ( (i_chanmask & (DSP_BIND_SURR | DSP_BIND_CENTER_LFE))
-                  && (p_aout->output.output.i_physical_channels ==
+                  && (p_aout->format.i_physical_channels ==
                        (AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER
                          | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT
                          | AOUT_CHAN_LFE)) )
@@ -163,7 +163,7 @@ static void Probe( aout_instance_t * p_aout )
             }
 
             if ( (i_chanmask & DSP_BIND_SURR)
-                  && (p_aout->output.output.i_physical_channels &
+                  && (p_aout->format.i_physical_channels &
                        (AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT
                          | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT)) )
             {
@@ -214,7 +214,7 @@ static void Probe( aout_instance_t * p_aout )
         val.i_int = AOUT_VAR_MONO;
         text.psz_string = _("Mono");
         var_Change( p_aout, "audio-device", VLC_VAR_ADDCHOICE, &val, &text );
-        if ( p_aout->output.output.i_physical_channels == AOUT_CHAN_CENTER )
+        if ( p_aout->format.i_physical_channels == AOUT_CHAN_CENTER )
         {
             var_Set( p_aout, "audio-device", val );
         }
@@ -228,7 +228,7 @@ static void Probe( aout_instance_t * p_aout )
     }
 
     /* Test for spdif. */
-    if ( AOUT_FMT_NON_LINEAR( &p_aout->output.output ) )
+    if ( AOUT_FMT_SPDIF( &p_aout->format ) )
     {
         i_format = AFMT_AC3;
 
@@ -260,13 +260,13 @@ static void Probe( aout_instance_t * p_aout )
  *****************************************************************************/
 static int Open( vlc_object_t *p_this )
 {
-    aout_instance_t * p_aout = (aout_instance_t *)p_this;
+    audio_output_t * p_aout = (audio_output_t *)p_this;
     struct aout_sys_t * p_sys;
     char * psz_device;
     vlc_value_t val;
 
     /* Allocate structure */
-    p_aout->output.p_sys = p_sys = malloc( sizeof( aout_sys_t ) );
+    p_aout->sys = p_sys = malloc( sizeof( aout_sys_t ) );
     if( p_sys == NULL )
         return VLC_ENOMEM;
 
@@ -298,8 +298,9 @@ static int Open( vlc_object_t *p_this )
 
     free( psz_device );
 
-    p_aout->output.pf_play = Play;
-    p_aout->output.pf_pause = NULL;
+    p_aout->pf_play = aout_PacketPlay;
+    p_aout->pf_pause = aout_PacketPause;
+    p_aout->pf_flush = aout_PacketFlush;
 
     if ( var_Type( p_aout, "audio-device" ) == 0 )
     {
@@ -316,33 +317,33 @@ static int Open( vlc_object_t *p_this )
 
     if ( val.i_int == AOUT_VAR_SPDIF )
     {
-        p_aout->output.output.i_format = VLC_CODEC_SPDIFL;
+        p_aout->format.i_format = VLC_CODEC_SPDIFL;
     }
     else if ( val.i_int == AOUT_VAR_5_1 )
     {
-        p_aout->output.output.i_format = VLC_CODEC_S16N;
-        p_aout->output.output.i_physical_channels
+        p_aout->format.i_format = VLC_CODEC_S16N;
+        p_aout->format.i_physical_channels
             = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER
                | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT
                | AOUT_CHAN_LFE;
     }
     else if ( val.i_int == AOUT_VAR_2F2R )
     {
-        p_aout->output.output.i_format = VLC_CODEC_S16N;
-        p_aout->output.output.i_physical_channels
+        p_aout->format.i_format = VLC_CODEC_S16N;
+        p_aout->format.i_physical_channels
             = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT
                | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT;
     }
     else if ( val.i_int == AOUT_VAR_STEREO )
     {
-        p_aout->output.output.i_format = VLC_CODEC_S16N;
-        p_aout->output.output.i_physical_channels
+        p_aout->format.i_format = VLC_CODEC_S16N;
+        p_aout->format.i_physical_channels
             = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT;
     }
     else if ( val.i_int == AOUT_VAR_MONO )
     {
-        p_aout->output.output.i_format = VLC_CODEC_S16N;
-        p_aout->output.output.i_physical_channels = AOUT_CHAN_CENTER;
+        p_aout->format.i_format = VLC_CODEC_S16N;
+        p_aout->format.i_physical_channels = AOUT_CHAN_CENTER;
     }
     else
     {
@@ -366,7 +367,7 @@ static int Open( vlc_object_t *p_this )
     }
 
     /* Set the output format */
-    if ( AOUT_FMT_NON_LINEAR( &p_aout->output.output ) )
+    if ( AOUT_FMT_SPDIF( &p_aout->format ) )
     {
         int i_format = AFMT_AC3;
 
@@ -379,15 +380,14 @@ static int Open( vlc_object_t *p_this )
             return VLC_EGENERIC;
         }
 
-        p_aout->output.output.i_format = VLC_CODEC_SPDIFL;
-        p_aout->output.i_nb_samples = A52_FRAME_NB;
-        p_aout->output.output.i_bytes_per_frame = AOUT_SPDIF_SIZE;
-        p_aout->output.output.i_frame_length = A52_FRAME_NB;
+        p_aout->format.i_format = VLC_CODEC_SPDIFL;
+        p_aout->format.i_bytes_per_frame = AOUT_SPDIF_SIZE;
+        p_aout->format.i_frame_length = A52_FRAME_NB;
 
+        aout_PacketInit( p_aout, &p_sys->packet, A52_FRAME_NB );
         aout_VolumeNoneInit( p_aout );
     }
-
-    if ( !AOUT_FMT_NON_LINEAR( &p_aout->output.output ) )
+    else
     {
         unsigned int i_format = AFMT_S16_NE;
         unsigned int i_frame_size, i_fragments;
@@ -406,22 +406,22 @@ static int Open( vlc_object_t *p_this )
         switch ( i_format )
         {
         case AFMT_U8:
-            p_aout->output.output.i_format = VLC_CODEC_U8;
+            p_aout->format.i_format = VLC_CODEC_U8;
             break;
         case AFMT_S8:
-            p_aout->output.output.i_format = VLC_CODEC_S8;
+            p_aout->format.i_format = VLC_CODEC_S8;
             break;
         case AFMT_U16_LE:
-            p_aout->output.output.i_format = VLC_CODEC_U16L;
+            p_aout->format.i_format = VLC_CODEC_U16L;
             break;
         case AFMT_S16_LE:
-            p_aout->output.output.i_format = VLC_CODEC_S16L;
+            p_aout->format.i_format = VLC_CODEC_S16L;
             break;
         case AFMT_U16_BE:
-            p_aout->output.output.i_format = VLC_CODEC_U16B;
+            p_aout->format.i_format = VLC_CODEC_U16B;
             break;
         case AFMT_S16_BE:
-            p_aout->output.output.i_format = VLC_CODEC_S16B;
+            p_aout->format.i_format = VLC_CODEC_S16B;
             break;
         default:
             msg_Err( p_aout, "OSS fell back to an unknown format (%d)",
@@ -431,41 +431,41 @@ static int Open( vlc_object_t *p_this )
             return VLC_EGENERIC;
         }
 
-        i_nb_channels = aout_FormatNbChannels( &p_aout->output.output );
+        i_nb_channels = aout_FormatNbChannels( &p_aout->format );
 
         /* Set the number of channels */
         if( ioctl( p_sys->i_fd, SNDCTL_DSP_CHANNELS, &i_nb_channels ) < 0 ||
-            i_nb_channels != aout_FormatNbChannels( &p_aout->output.output ) )
+            i_nb_channels != aout_FormatNbChannels( &p_aout->format ) )
         {
             msg_Err( p_aout, "cannot set number of audio channels (%s)",
-                     aout_FormatPrintChannels( &p_aout->output.output) );
+                     aout_FormatPrintChannels( &p_aout->format) );
             close( p_sys->i_fd );
             free( p_sys );
             return VLC_EGENERIC;
         }
 
         /* Set the output rate */
-        i_rate = p_aout->output.output.i_rate;
+        i_rate = p_aout->format.i_rate;
         if( ioctl( p_sys->i_fd, SNDCTL_DSP_SPEED, &i_rate ) < 0 )
         {
             msg_Err( p_aout, "cannot set audio output rate (%i)",
-                             p_aout->output.output.i_rate );
+                             p_aout->format.i_rate );
             close( p_sys->i_fd );
             free( p_sys );
             return VLC_EGENERIC;
         }
 
-        if( i_rate != p_aout->output.output.i_rate )
+        if( i_rate != p_aout->format.i_rate )
         {
-            p_aout->output.output.i_rate = i_rate;
+            p_aout->format.i_rate = i_rate;
         }
 
         /* Set the fragment size */
-        aout_FormatPrepare( &p_aout->output.output );
+        aout_FormatPrepare( &p_aout->format );
 
         /* i_fragment = xxxxyyyy where: xxxx        is fragtotal
          *                              1 << yyyy   is fragsize */
-        i_frame_size = ((uint64_t)p_aout->output.output.i_bytes_per_frame * p_aout->output.output.i_rate * 65536) / (48000 * 2 * 2) / FRAME_COUNT;
+        i_frame_size = ((uint64_t)p_aout->format.i_bytes_per_frame * p_aout->format.i_rate * 65536) / (48000 * 2 * 2) / FRAME_COUNT;
         i_fragments = 4;
         while( i_fragments < 12 && (1U << i_fragments) < i_frame_size )
         {
@@ -484,22 +484,19 @@ static int Open( vlc_object_t *p_this )
             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;
+        /* Number of fragments actually allocated */
+        p_aout->sys->i_fragstotal = audio_buf.fragstotal;
 
-            p_aout->output.i_nb_samples = audio_buf.fragsize /
-                p_aout->output.output.i_bytes_per_frame;
-        }
+        /* Maximum duration the soundcard's buffer can hold */
+        p_aout->sys->max_buffer_duration =
+                (mtime_t)audio_buf.fragstotal * audio_buf.fragsize * 1000000
+                / p_aout->format.i_bytes_per_frame
+                / p_aout->format.i_rate
+                * p_aout->format.i_frame_length;
 
+        aout_PacketInit( p_aout, &p_sys->packet,
+                         audio_buf.fragsize/p_aout->format.i_bytes_per_frame );
         aout_VolumeSoftInit( p_aout );
     }
 
@@ -509,6 +506,7 @@ static int Open( vlc_object_t *p_this )
     {
         msg_Err( p_aout, "cannot create OSS thread (%m)" );
         close( p_sys->i_fd );
+        aout_PacketDestroy( p_aout );
         free( p_sys );
         return VLC_ENOMEM;
     }
@@ -516,21 +514,13 @@ static int Open( vlc_object_t *p_this )
     return VLC_SUCCESS;
 }
 
-/*****************************************************************************
- * Play: nothing to do
- *****************************************************************************/
-static void Play( aout_instance_t *p_aout )
-{
-    VLC_UNUSED(p_aout);
-}
-
 /*****************************************************************************
  * Close: close the DSP audio device
  *****************************************************************************/
 static void Close( vlc_object_t * p_this )
 {
-    aout_instance_t *p_aout = (aout_instance_t *)p_this;
-    struct aout_sys_t * p_sys = p_aout->output.p_sys;
+    audio_output_t *p_aout = (audio_output_t *)p_this;
+    struct aout_sys_t * p_sys = p_aout->sys;
 
     vlc_cancel( p_sys->thread );
     vlc_join( p_sys->thread, NULL );
@@ -539,6 +529,7 @@ static void Close( vlc_object_t * p_this )
     ioctl( p_sys->i_fd, SNDCTL_DSP_RESET, NULL );
     close( p_sys->i_fd );
 
+    aout_PacketDestroy( p_aout );
     free( p_sys );
 }
 
@@ -547,27 +538,34 @@ static void Close( vlc_object_t * p_this )
  *****************************************************************************
  * This function returns the duration in microseconds of the current buffer.
  *****************************************************************************/
-static mtime_t BufferDuration( aout_instance_t * p_aout )
+static mtime_t BufferDuration( audio_output_t * p_aout )
 {
-    struct aout_sys_t * p_sys = p_aout->output.p_sys;
+    struct aout_sys_t * p_sys = p_aout->sys;
     audio_buf_info audio_buf;
     int i_bytes;
 
-    /* Fill the audio_buf_info structure:
-     * - fragstotal: total number of fragments allocated
-     * - fragsize: size of a fragment in bytes
-     * - bytes: available space in bytes (includes partially used fragments)
-     * Note! 'bytes' could be more than fragments*fragsize */
-    ioctl( p_sys->i_fd, SNDCTL_DSP_GETOSPACE, &audio_buf );
+#ifdef SNDCTL_DSP_GETODELAY
+    if ( ioctl( p_sys->i_fd, SNDCTL_DSP_GETODELAY, &i_bytes ) < 0 )
+#endif
+    {
+        /* Fall back to GETOSPACE and approximate latency. */
 
-    /* calculate number of available fragments (not partially used ones) */
-    i_bytes = (audio_buf.fragstotal * audio_buf.fragsize) - audio_buf.bytes;
+        /* Fill the audio_buf_info structure:
+         * - fragstotal: total number of fragments allocated
+         * - fragsize: size of a fragment in bytes
+         * - bytes: available space in bytes (includes partially used fragments)
+         * Note! 'bytes' could be more than fragments*fragsize */
+        ioctl( p_sys->i_fd, SNDCTL_DSP_GETOSPACE, &audio_buf );
+
+        /* calculate number of available fragments (not partially used ones) */
+        i_bytes = (audio_buf.fragstotal * audio_buf.fragsize) - audio_buf.bytes;
+    }
 
     /* Return the fragment duration */
     return (mtime_t)i_bytes * 1000000
-            / p_aout->output.output.i_bytes_per_frame
-            / p_aout->output.output.i_rate
-            * p_aout->output.output.i_frame_length;
+            / p_aout->format.i_bytes_per_frame
+            / p_aout->format.i_rate
+            * p_aout->format.i_frame_length;
 }
 
 typedef struct
@@ -590,8 +588,8 @@ static void OSSThreadCleanup( void *data )
  *****************************************************************************/
 static void* OSSThread( void *obj )
 {
-    aout_instance_t * p_aout = (aout_instance_t*)obj;
-    struct aout_sys_t * p_sys = p_aout->output.p_sys;
+    audio_output_t * p_aout = (audio_output_t*)obj;
+    struct aout_sys_t * p_sys = p_aout->sys;
     mtime_t next_date = 0;
 
     for( ;; )
@@ -599,24 +597,23 @@ static void* OSSThread( void *obj )
         aout_buffer_t * p_buffer = NULL;
 
         int canc = vlc_savecancel ();
-        if ( p_aout->output.output.i_format != VLC_CODEC_SPDIFL )
+        if ( p_aout->format.i_format != VLC_CODEC_SPDIFL )
         {
             mtime_t buffered = BufferDuration( p_aout );
 
             /* Next buffer will be played at mdate() + buffered */
-            p_buffer = aout_OutputNextBuffer( p_aout, mdate() + buffered,
-                                              false );
+            p_buffer = aout_PacketNext( p_aout, mdate() + buffered );
 
             if( p_buffer == NULL &&
-                buffered > ( p_aout->output.p_sys->max_buffer_duration
-                             / p_aout->output.p_sys->i_fragstotal ) )
+                buffered > ( p_aout->sys->max_buffer_duration
+                             / p_aout->sys->i_fragstotal ) )
             {
                 vlc_restorecancel (canc);
                 /* If we have at least a fragment full, then we can wait a
                  * little and retry to get a new audio buffer instead of
                  * playing a blank sample */
-                msleep( ( p_aout->output.p_sys->max_buffer_duration
-                          / p_aout->output.p_sys->i_fragstotal / 2 ) );
+                msleep( ( p_aout->sys->max_buffer_duration
+                          / p_aout->sys->i_fragstotal / 2 ) );
                 continue;
             }
         }
@@ -633,7 +630,7 @@ static void* OSSThread( void *obj )
             else
             {
                 mtime_t delay = next_date - mdate();
-                if( delay > AOUT_PTS_TOLERANCE )
+                if( delay > AOUT_MAX_PTS_ADVANCE )
                 {
                     msleep( delay / 2 );
                 }
@@ -642,7 +639,7 @@ static void* OSSThread( void *obj )
             for( ;; )
             {
                 canc = vlc_savecancel ();
-                p_buffer = aout_OutputNextBuffer( p_aout, next_date, true );
+                p_buffer = aout_PacketNext( p_aout, next_date );
                 if ( p_buffer )
                     break;
                 vlc_restorecancel (canc);
@@ -664,8 +661,8 @@ static void* OSSThread( void *obj )
         }
         else
         {
-            i_size = FRAME_SIZE / p_aout->output.output.i_frame_length
-                      * p_aout->output.output.i_bytes_per_frame;
+            i_size = FRAME_SIZE / p_aout->format.i_frame_length
+                      * p_aout->format.i_bytes_per_frame;
             p_bytes = malloc( i_size );
             memset( p_bytes, 0, i_size );
             next_date = 0;