[PATCH] work with ALSA 1.0 API

Jeffrey W. Baker jwbaker at acm.org
Thu May 10 07:17:40 CEST 2001


Hello,

I have finished my patch for vlc to use the latest ALSA API.  The output
of "cvs diff -u" in plugins/alsa is attached.  I have tested it on a
couple of streams and it works fine.  I hope you will apply it.

Regards,
Jeffrey


-- Attached file included as plaintext by Listar --
-- File: vlc-alsa-patch
-- Desc: Patch to plugins/alsa/aout_alsa.c

Index: aout_alsa.c
===================================================================
RCS file: /var/cvs/videolan/vlc/plugins/alsa/aout_alsa.c,v
retrieving revision 1.14
diff -u -r1.14 aout_alsa.c
--- aout_alsa.c	2001/05/06 04:32:02	1.14
+++ aout_alsa.c	2001/05/10 05:14:45
@@ -4,7 +4,8 @@
  * Copyright (C) 2000 VideoLAN
  * $Id: aout_alsa.c,v 1.14 2001/05/06 04:32:02 sam Exp $
  *
- * Authors: Henri Fallon <henri at videolan.org>
+ * Authors: Henri Fallon <henri at videolan.org> - Original Author
+ *          Jeffrey Baker <jwbaker at acm.org> - Port to ALSA 1.0 API
  * 
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -64,37 +65,17 @@
 
 typedef struct aout_sys_s
 {
-    snd_pcm_t         * p_alsa_handle;
-    alsa_device_t       s_alsa_device;
-    alsa_card_t         s_alsa_card;
-    snd_pcm_channel_params_t s_alsa_channel_params;
-    snd_pcm_format_t    s_alsa_format;
+    snd_pcm_t   * p_alsa_handle;
+    unsigned long buffer_time;
+    unsigned long period_time;
+    unsigned long chunk_size;
+    unsigned long buffer_size;
+    unsigned long rate;
+    unsigned int  bytes_per_sample;
+    unsigned int  samples_per_frame;
+    unsigned int  bytes_per_frame;
 } aout_sys_t;
 
-/*****************************************************************************
- * Local prototypes
- *****************************************************************************/
-static int     aout_Probe       ( probedata_t *p_data );
-static int     aout_Open        ( aout_thread_t *p_aout );
-static int     aout_SetFormat   ( aout_thread_t *p_aout );
-static long    aout_GetBufInfo  ( aout_thread_t *p_aout, long l_buffer_info );
-static void    aout_Play        ( aout_thread_t *p_aout,
-                                          byte_t *buffer, int i_size );
-static void    aout_Close       ( aout_thread_t *p_aout );
-
-/*****************************************************************************
- * Functions exported as capabilities. They are declared as static so that
- * we don't pollute the namespace too much.
- *****************************************************************************/
-void _M( aout_getfunctions )( function_list_t * p_function_list )
-{
-    p_function_list->pf_probe = aout_Probe;
-    p_function_list->functions.aout.pf_open = aout_Open;
-    p_function_list->functions.aout.pf_setformat = aout_SetFormat;
-    p_function_list->functions.aout.pf_getbufinfo = aout_GetBufInfo;
-    p_function_list->functions.aout.pf_play = aout_Play;
-    p_function_list->functions.aout.pf_close = aout_Close;
-}
 
 /*****************************************************************************
  * aout_Probe: probes the audio device and return a score
@@ -104,19 +85,11 @@
  *****************************************************************************/
 static int aout_Probe( probedata_t *p_data )
 {
-    int i_open_return,i_close_return;
+    int i_open_return, i_close_return;
     aout_sys_t local_sys;
-    /* This is the same as the beginning of the aout_Open */
     
-    /* Initialize  */
-    local_sys.s_alsa_device.i_num = 0;
-    local_sys.s_alsa_card.i_num = 0;
-
     /* Open device */
-    i_open_return = snd_pcm_open( &(local_sys.p_alsa_handle),
-                     local_sys.s_alsa_card.i_num,
-                     local_sys.s_alsa_device.i_num,
-                     SND_PCM_OPEN_PLAYBACK );
+    i_open_return = snd_pcm_open(&(local_sys.p_alsa_handle), "plug:0,0", SND_PCM_STREAM_PLAYBACK, 0);
     if( i_open_return )
     {
         /* Score is zero */
@@ -124,9 +97,9 @@
     }
 
     /* Close it */
-    i_close_return = snd_pcm_close ( local_sys.p_alsa_handle );
+    i_close_return = snd_pcm_close(local_sys.p_alsa_handle);
     
-    if( i_close_return )
+    if (i_close_return)
     {
         intf_ErrMsg( "Error closing alsa device in aout_probe; exit=%i",
                      i_close_return );
@@ -162,20 +135,14 @@
         return( 1 );
     }
 
-    /* Initialize  */
-    p_aout->p_sys->s_alsa_device.i_num = 0;
-    p_aout->p_sys->s_alsa_card.i_num = 0;
-    /* FIXME : why not other format ? */
-    p_aout->i_format = AOUT_FMT_S16_LE;   
-    /* FIXME : why always 2 channels ?*/
-    p_aout->i_channels = 2;
-    p_aout->l_rate = main_GetIntVariable( AOUT_RATE_VAR, AOUT_RATE_DEFAULT );
-    
+    p_aout->i_format   = AOUT_FORMAT_DEFAULT;
+    p_aout->i_channels = 1 + main_GetIntVariable( AOUT_STEREO_VAR,
+                                                  AOUT_STEREO_DEFAULT );
+    p_aout->l_rate     = main_GetIntVariable( AOUT_RATE_VAR,
+                                              AOUT_RATE_DEFAULT );
+
     /* Open device */
-    if( ( i_open_returns = snd_pcm_open( &(p_aout->p_sys->p_alsa_handle),
-                p_aout->p_sys->s_alsa_card.i_num,
-                p_aout->p_sys->s_alsa_device.i_num,
-                SND_PCM_OPEN_PLAYBACK ) ) )
+    if( ( i_open_returns = snd_pcm_open(&(p_aout->p_sys->p_alsa_handle), "plug:0,0", SND_PCM_STREAM_PLAYBACK, 0) ) )
     {
         intf_ErrMsg( "Could not open alsa device; exit = %i",
                       i_open_returns );
@@ -196,88 +163,119 @@
  *****************************************************************************/
 static int aout_SetFormat( aout_thread_t *p_aout )
 {
+    
+    int rv;
+    int format;
     
-    int i_set_param_returns;
-    int i_prepare_playback_returns;
-    int i_playback_go_returns;
-
-    /* Fill with zeros */
-    memset( &p_aout->p_sys->s_alsa_channel_params,0,
-            sizeof( p_aout->p_sys->s_alsa_channel_params ) );
-    
-    /* Fill the s_alsa_channel_params structure */
-
-    /* Tranfer mode and direction*/    
-    p_aout->p_sys->s_alsa_channel_params.channel = SND_PCM_CHANNEL_PLAYBACK ;
-    p_aout->p_sys->s_alsa_channel_params.mode = SND_PCM_MODE_STREAM;
-    
-    /* Format and rate */
-    p_aout->p_sys->s_alsa_channel_params.format.interleave = 1;
-    if( p_aout->i_format == AOUT_FMT_S16_LE )
-        p_aout->p_sys->s_alsa_channel_params.format.format = 
-            SND_PCM_SFMT_S16_LE;
+    snd_pcm_hw_params_t *hw;
+    snd_pcm_sw_params_t *sw;
+    
+    snd_pcm_hw_params_alloca(&hw);
+    snd_pcm_sw_params_alloca(&sw);
+
+    switch (p_aout->i_format) {
+        case AOUT_FMT_S16_LE:
+            format = SND_PCM_FORMAT_S16_LE;
+            p_aout->p_sys->bytes_per_sample = 2;
+            break;
+        
+        default:
+            format = SND_PCM_FORMAT_S16_BE;
+            p_aout->p_sys->bytes_per_sample = 2;
+            break;
+    }
+
+    p_aout->p_sys->samples_per_frame = p_aout->i_channels;
+    p_aout->p_sys->bytes_per_frame = p_aout->p_sys->samples_per_frame * p_aout->p_sys->bytes_per_sample;
+
+    rv = snd_pcm_hw_params_any(p_aout->p_sys->p_alsa_handle, hw);
+    if (rv < 0) {
+        intf_ErrMsg("ALSA PLUGIN: Unable to retrieve initial parameters.");
+        return(-1);
+    }
+    
+    rv = snd_pcm_hw_params_set_access(p_aout->p_sys->p_alsa_handle, hw, SND_PCM_ACCESS_RW_INTERLEAVED);
+    if (rv < 0) {
+        intf_ErrMsg("ALSA PLUGIN: Unable to set interleaved stream format.");
+        return(-1);
+    }
+    
+    rv = snd_pcm_hw_params_set_format(p_aout->p_sys->p_alsa_handle, hw, format);
+    if (rv < 0) {
+        intf_ErrMsg("ALSA PLUGIN: Unable to set stream sample size and word order.");
+        return(-1);
+    }
+
+    rv = snd_pcm_hw_params_set_channels(p_aout->p_sys->p_alsa_handle, hw, p_aout->i_channels);
+    if (rv < 0) {
+        intf_ErrMsg("ALSA PLUGIN: Unable to set number of output channels.");
+        return(-1);
+    }
+    
+    rv = snd_pcm_hw_params_set_rate_near(p_aout->p_sys->p_alsa_handle, hw, p_aout->l_rate, 0);
+    if (rv < 0) {
+        intf_ErrMsg("ALSA PLUGIN: Unable to set sample rate.");
+        return(-1);
+    }
+    else 
+        p_aout->p_sys->rate = rv;    
+        
+    rv = snd_pcm_hw_params_set_buffer_time_near(p_aout->p_sys->p_alsa_handle, hw, AOUT_BUFFER_DURATION, 0);
+    if (rv < 0) {
+        intf_ErrMsg("ALSA PLUGIN: Unable to set buffer time.");
+        return(-1);
+    }
     else
-        p_aout->p_sys->s_alsa_channel_params.format.format = 
-            SND_PCM_SFMT_S16_BE;
-    p_aout->p_sys->s_alsa_channel_params.format.rate = p_aout->l_rate;
-    p_aout->p_sys->s_alsa_channel_params.format.voices = p_aout->i_channels ;
-    
-    /* When to start playing and when to stop */
-    p_aout->p_sys->s_alsa_channel_params.start_mode = SND_PCM_START_DATA;
-    p_aout->p_sys->s_alsa_channel_params.stop_mode = SND_PCM_STOP_STOP;
-
-    /* Buffer information . I have chosen the stream mode here
-     * instead of the block mode. I don't know whether i'm wrong 
-     * but it seemed more logical */
-    /* TODO : find the best value to put here. Probably depending
-     * on many parameters */
-    p_aout->p_sys->s_alsa_channel_params.buf.stream.queue_size = 131072; 
-    
-    p_aout->p_sys->s_alsa_channel_params.buf.stream.fill = SND_PCM_FILL_NONE ;
-    p_aout->p_sys->s_alsa_channel_params.buf.stream.max_fill = 0 ; 
-  
-    /* Now we pass this to the driver */
-    i_set_param_returns = snd_pcm_channel_params( 
-            p_aout->p_sys->p_alsa_handle, 
-            &(p_aout->p_sys->s_alsa_channel_params) );
+        p_aout->p_sys->buffer_time = rv;
     
-    if( i_set_param_returns )
-    {
-        intf_ErrMsg( "ALSA_PLUGIN : Unable to set parameters; exit = %i",
-                     i_set_param_returns );
-        intf_ErrMsg( "This means : %s",
-                     snd_strerror( i_set_param_returns ) );
-        return( -1 );
+    rv = snd_pcm_hw_params_set_period_time_near(p_aout->p_sys->p_alsa_handle, hw, p_aout->p_sys->buffer_time / p_aout->p_sys->bytes_per_frame, 0);
+    if (rv < 0) {
+        intf_ErrMsg("ALSA PLUGIN: Unable to set period time.");
+        return(-1);
+    }
+    else
+        p_aout->p_sys->period_time = rv;
+    
+    rv = snd_pcm_hw_params(p_aout->p_sys->p_alsa_handle, hw);
+    if (rv < 0) {
+        intf_ErrMsg("ALSA PLUGIN: Unable to install configuration into hardware.");
+        return(-1);
     }
+    
+    p_aout->p_sys->chunk_size = snd_pcm_hw_params_get_period_size(hw, 0);
+	p_aout->p_sys->buffer_size = snd_pcm_hw_params_get_buffer_size(hw);
 
-    /* we shall now prepare the channel */
-    i_prepare_playback_returns = 
-        snd_pcm_playback_prepare( p_aout->p_sys->p_alsa_handle );
+	snd_pcm_sw_params_current(p_aout->p_sys->p_alsa_handle, sw);
+	rv = snd_pcm_sw_params_set_sleep_min(p_aout->p_sys->p_alsa_handle, sw, 0);
 
-    if( i_prepare_playback_returns )
-    {
-        intf_ErrMsg( "ALSA_PLUGIN : Unable to prepare channel : exit = %i",
-                      i_prepare_playback_returns );
-        intf_ErrMsg( "This means : %s",
-                      snd_strerror( i_set_param_returns ) );
+	rv = snd_pcm_sw_params_set_avail_min(p_aout->p_sys->p_alsa_handle, sw, p_aout->p_sys->chunk_size);
 
-        return( -1 );
-    }
-    
-   /* then we may go */
-   i_playback_go_returns =
-       snd_pcm_playback_go( p_aout->p_sys->p_alsa_handle );
-    if( i_playback_go_returns )
-    {
-        intf_ErrMsg( "ALSA_PLUGIN : Unable to prepare channel (bis) : "
-                "exit  = %i", i_playback_go_returns );
-        intf_ErrMsg( "This means : %s",
-                snd_strerror( i_set_param_returns ) );
-        return( -1 );
-    }
+	rv = snd_pcm_sw_params_set_start_threshold(p_aout->p_sys->p_alsa_handle, sw, p_aout->p_sys->buffer_size);
+	
+    rv = snd_pcm_sw_params_set_stop_threshold(p_aout->p_sys->p_alsa_handle, sw, p_aout->p_sys->buffer_size);
+
+	rv = snd_pcm_sw_params(p_aout->p_sys->p_alsa_handle, sw);
+    if (rv < 0) {
+		intf_ErrMsg("ALSA PLUGIN: Unable to install configuration into software.");
+        return(-1);
+	}
+
+
     return( 0 );
 }
 
+static void aout_HandleXrun(aout_thread_t *p_aout)
+{
+    int rv;
+
+    intf_ErrMsg("ALSA PLUGIN: resetting output after buffer underrun.");
+    
+    rv = snd_pcm_prepare(p_aout->p_sys->p_alsa_handle);
+    if (rv < 0)
+        intf_ErrMsg("ALSA PLUGIN: Unable to recover from buffer underrun: %s", snd_strerror(rv));
+}
+
+
 /*****************************************************************************
  * aout_BufInfo: buffer status query
  *****************************************************************************
@@ -288,14 +286,13 @@
  *****************************************************************************/
 static long aout_GetBufInfo( aout_thread_t *p_aout, long l_buffer_limit )
 {
-    snd_pcm_channel_status_t alsa_channel_status;
+    snd_pcm_status_t *status;
     int i_alsa_get_status_returns;
     
-    memset(&alsa_channel_status, 0, sizeof( alsa_channel_status ) );
-   
-    i_alsa_get_status_returns = snd_pcm_channel_status( 
-            p_aout->p_sys->p_alsa_handle, &alsa_channel_status );
+    snd_pcm_status_alloca(&status);
 
+    i_alsa_get_status_returns = snd_pcm_status(p_aout->p_sys->p_alsa_handle, status);
+
     if( i_alsa_get_status_returns )
     {
         intf_ErrMsg ( "Error getting alsa buffer info; exit=%i",
@@ -305,25 +302,23 @@
         return ( -1 );
     }
 
-    switch( alsa_channel_status.status )
+    switch(snd_pcm_status_get_state(status))
     {
-    case SND_PCM_STATUS_NOTREADY : intf_ErrMsg("Status NOT READY");
-                                   break;
-    case SND_PCM_STATUS_UNDERRUN : {
-
-         int i_prepare_returns;
-         intf_ErrMsg( "Status UNDERRUN ... reseting queue ");
-         i_prepare_returns = snd_pcm_playback_prepare( 
-                             p_aout->p_sys->p_alsa_handle );
-         if ( i_prepare_returns )
-         {
-             intf_ErrMsg( "Error : could not flush : %i", i_prepare_returns );
-             intf_ErrMsg( "This means : %s", snd_strerror(i_prepare_returns) );
-         }
-         break;
-                                   }
+        case SND_PCM_STATE_XRUN :
+            aout_HandleXrun(p_aout);
+            break;
+
+        case SND_PCM_STATE_OPEN:
+        case SND_PCM_STATE_PREPARED:
+        case SND_PCM_STATE_RUNNING:
+            break;
+            
+        default:
+            intf_ErrMsg("ALSA PLUGIN: Encountered unhandled condition %i!", snd_pcm_status_get_state(status));
+            break;
     } 
-    return(  alsa_channel_status.count );
+
+    return(snd_pcm_status_get_avail(status) * p_aout->p_sys->bytes_per_frame);
 }
 
 /*****************************************************************************
@@ -333,15 +328,24 @@
  *****************************************************************************/
 static void aout_Play( aout_thread_t *p_aout, byte_t *buffer, int i_size )
 {
-    int i_write_returns;
+    snd_pcm_uframes_t tot_frames;
+    snd_pcm_uframes_t frames_left;
+    snd_pcm_uframes_t rv;
+    
+    tot_frames = i_size / p_aout->p_sys->bytes_per_frame;
+    frames_left = tot_frames;
+
+    while (frames_left > 0)
+    {        
+        rv = snd_pcm_writei(p_aout->p_sys->p_alsa_handle, buffer + (tot_frames - frames_left) * p_aout->p_sys->bytes_per_frame, frames_left);
+
+        if ((signed int) rv < 0)
+        {
+            intf_ErrMsg("ALSA PLUGIN: error writing to output: %s", snd_strerror(rv));
+            return;
+        }
 
-    i_write_returns = (int) snd_pcm_write (
-            p_aout->p_sys->p_alsa_handle, (void *) buffer, (size_t) i_size );
-
-    if( i_write_returns <= 0 )
-    {
-        intf_ErrMsg ( "Error writing blocks; exit=%i", i_write_returns );
-        intf_ErrMsg ( "This means : %s", snd_strerror( i_write_returns ) );
+        frames_left -= rv;
     }
 }
 
@@ -364,3 +368,16 @@
     intf_DbgMsg( "Alsa plugin : Alsa device closed");
 }
 
+/*****************************************************************************
+ * Functions exported as capabilities. They are declared as static so that
+ * we don't pollute the namespace too much.
+ *****************************************************************************/
+void _M( aout_getfunctions )( function_list_t * p_function_list )
+{
+    p_function_list->pf_probe = aout_Probe;
+    p_function_list->functions.aout.pf_open = aout_Open;
+    p_function_list->functions.aout.pf_setformat = aout_SetFormat;
+    p_function_list->functions.aout.pf_getbufinfo = aout_GetBufInfo;
+    p_function_list->functions.aout.pf_play = aout_Play;
+    p_function_list->functions.aout.pf_close = aout_Close;
+}




More information about the vlc-devel mailing list