alsa.c
上传用户:riyaled888
上传日期:2009-03-27
资源大小:7338k
文件大小:29k
源码类别:

多媒体

开发平台:

MultiPlatform

  1. /*****************************************************************************
  2.  * alsa.c : alsa plugin for vlc
  3.  *****************************************************************************
  4.  * Copyright (C) 2000-2001 VideoLAN
  5.  * $Id: alsa.c 8485 2004-08-21 13:54:36Z asmax $
  6.  *
  7.  * Authors: Henri Fallon <henri@videolan.org> - Original Author
  8.  *          Jeffrey Baker <jwbaker@acm.org> - Port to ALSA 1.0 API
  9.  *          John Paul Lorenti <jpl31@columbia.edu> - Device selection
  10.  *          Arnaud de Bossoreille de Ribou <bozo@via.ecp.fr> - S/PDIF and aout3
  11.  *
  12.  * This program is free software; you can redistribute it and/or modify
  13.  * it under the terms of the GNU General Public License as published by
  14.  * the Free Software Foundation; either version 2 of the License, or
  15.  * (at your option) any later version.
  16.  *
  17.  * This program is distributed in the hope that it will be useful,
  18.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  19.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  20.  * GNU General Public License for more details.
  21.  *
  22.  * You should have received a copy of the GNU General Public License
  23.  * along with this program; if not, write to the Free Software
  24.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
  25.  *****************************************************************************/
  26. /*****************************************************************************
  27.  * Preamble
  28.  *****************************************************************************/
  29. #include <errno.h>                                                 /* ENOMEM */
  30. #include <string.h>                                            /* strerror() */
  31. #include <stdlib.h>                            /* calloc(), malloc(), free() */
  32. #include <vlc/vlc.h>
  33. #include <vlc/aout.h>
  34. #include "aout_internal.h"
  35. /* ALSA part
  36.    Note: we use the new API which is available since 0.9.0beta10a. */
  37. #define ALSA_PCM_NEW_HW_PARAMS_API
  38. #define ALSA_PCM_NEW_SW_PARAMS_API
  39. #include <alsa/asoundlib.h>
  40. /*****************************************************************************
  41.  * aout_sys_t: ALSA audio output method descriptor
  42.  *****************************************************************************
  43.  * This structure is part of the audio output thread descriptor.
  44.  * It describes the ALSA specific properties of an audio device.
  45.  *****************************************************************************/
  46. struct aout_sys_t
  47. {
  48.     snd_pcm_t         * p_snd_pcm;
  49.     int                 i_period_time;
  50. #ifdef ALSA_DEBUG
  51.     snd_output_t      * p_snd_stderr;
  52. #endif
  53.     int b_playing;                                         /* playing status */
  54.     mtime_t start_date;
  55.     vlc_mutex_t lock;
  56.     vlc_cond_t  wait ;
  57.     snd_pcm_status_t *p_status;
  58. };
  59. #define A52_FRAME_NB 1536
  60. /* These values are in frames.
  61.    To convert them to a number of bytes you have to multiply them by the
  62.    number of channel(s) (eg. 2 for stereo) and the size of a sample (eg.
  63.    2 for int16_t). */
  64. #define ALSA_DEFAULT_PERIOD_SIZE        1024
  65. #define ALSA_DEFAULT_BUFFER_SIZE        ( ALSA_DEFAULT_PERIOD_SIZE << 8 )
  66. #define ALSA_SPDIF_PERIOD_SIZE          A52_FRAME_NB
  67. #define ALSA_SPDIF_BUFFER_SIZE          ( ALSA_SPDIF_PERIOD_SIZE << 4 )
  68. /* Why << 4 ? --Meuuh */
  69. /* Why not ? --Bozo */
  70. /* Right. --Meuuh */
  71. #define DEFAULT_ALSA_DEVICE N_("default")
  72. /*****************************************************************************
  73.  * Local prototypes
  74.  *****************************************************************************/
  75. static int  Open         ( vlc_object_t * );
  76. static void Close        ( vlc_object_t * );
  77. static void Play         ( aout_instance_t * );
  78. static int  ALSAThread   ( aout_instance_t * );
  79. static void ALSAFill     ( aout_instance_t * );
  80. /*****************************************************************************
  81.  * Module descriptor
  82.  *****************************************************************************/
  83. vlc_module_begin();
  84.     set_description( _("ALSA audio output") );
  85.     add_string( "alsadev", DEFAULT_ALSA_DEVICE, aout_FindAndRestart,
  86.                 N_("ALSA Device Name"), NULL, VLC_FALSE );
  87.     set_capability( "audio output", 150 );
  88.     set_callbacks( Open, Close );
  89. vlc_module_end();
  90. /*****************************************************************************
  91.  * Probe: probe the audio device for available formats and channels
  92.  *****************************************************************************/
  93. static void Probe( aout_instance_t * p_aout,
  94.                    const char * psz_device, const char * psz_iec_device,
  95.                    int *pi_snd_pcm_format )
  96. {
  97.     struct aout_sys_t * p_sys = p_aout->output.p_sys;
  98.     vlc_value_t val, text;
  99.     int i_ret;
  100.     var_Create ( p_aout, "audio-device", VLC_VAR_INTEGER | VLC_VAR_HASCHOICE );
  101.     text.psz_string = _("Audio Device");
  102.     var_Change( p_aout, "audio-device", VLC_VAR_SETTEXT, &text, NULL );
  103.     /* We'll open the audio device in non blocking mode so we can just exit
  104.      * when it is already in use, but for the real stuff we'll still use
  105.      * the blocking mode */
  106.     /* Now test linear PCM capabilities */
  107.     if ( !(i_ret = snd_pcm_open( &p_sys->p_snd_pcm, psz_device,
  108.                                  SND_PCM_STREAM_PLAYBACK,
  109.                                  SND_PCM_NONBLOCK ) ) )
  110.     {
  111.         int i_channels;
  112.         snd_pcm_hw_params_t * p_hw;
  113.         snd_pcm_hw_params_alloca (&p_hw);
  114.         if ( snd_pcm_hw_params_any( p_sys->p_snd_pcm, p_hw ) < 0 )
  115.         {
  116.             msg_Warn( p_aout, "unable to retrieve initial hardware parameters"
  117.                               ", disabling linear PCM audio" );
  118.             snd_pcm_close( p_sys->p_snd_pcm );
  119.             var_Destroy( p_aout, "audio-device" );
  120.             return;
  121.         }
  122.         if ( snd_pcm_hw_params_set_format( p_sys->p_snd_pcm, p_hw,
  123.                                            *pi_snd_pcm_format ) < 0 )
  124.         {
  125.             if( *pi_snd_pcm_format != SND_PCM_FORMAT_S16 )
  126.             {
  127.                 *pi_snd_pcm_format = SND_PCM_FORMAT_S16;
  128.                 if ( snd_pcm_hw_params_set_format( p_sys->p_snd_pcm, p_hw,
  129.                                                    *pi_snd_pcm_format ) < 0 )
  130.                 {
  131.                     msg_Warn( p_aout, "unable to set stream sample size and "
  132.                               "word order, disabling linear PCM audio" );
  133.                     snd_pcm_close( p_sys->p_snd_pcm );
  134.                     var_Destroy( p_aout, "audio-device" );
  135.                     return;
  136.                 }
  137.             }
  138.         }
  139.         i_channels = aout_FormatNbChannels( &p_aout->output.output );
  140.         while ( i_channels > 0 )
  141.         {
  142.             if ( !snd_pcm_hw_params_test_channels( p_sys->p_snd_pcm, p_hw,
  143.                                                    i_channels ) )
  144.             {
  145.                 switch ( i_channels )
  146.                 {
  147.                 case 1:
  148.                     val.i_int = AOUT_VAR_MONO;
  149.                     text.psz_string = N_("Mono");
  150.                     var_Change( p_aout, "audio-device",
  151.                                 VLC_VAR_ADDCHOICE, &val, &text );
  152.                     break;
  153.                 case 2:
  154.                     val.i_int = AOUT_VAR_STEREO;
  155.                     text.psz_string = N_("Stereo");
  156.                     var_Change( p_aout, "audio-device",
  157.                                 VLC_VAR_ADDCHOICE, &val, &text );
  158.                     var_Set( p_aout, "audio-device", val );
  159.                     break;
  160.                 case 4:
  161.                     val.i_int = AOUT_VAR_2F2R;
  162.                     text.psz_string = N_("2 Front 2 Rear");
  163.                     var_Change( p_aout, "audio-device",
  164.                                 VLC_VAR_ADDCHOICE, &val, &text );
  165.                     break;
  166.                 case 6:
  167.                     val.i_int = AOUT_VAR_5_1;
  168.                     text.psz_string = N_("5.1");
  169.                     var_Change( p_aout, "audio-device",
  170.                                 VLC_VAR_ADDCHOICE, &val, &text );
  171.                     break;
  172.                 }
  173.             }
  174.             --i_channels;
  175.         }
  176.         /* Special case for mono on stereo only boards */
  177.         i_channels = aout_FormatNbChannels( &p_aout->output.output );        
  178.         var_Change( p_aout, "audio-device", VLC_VAR_CHOICESCOUNT, &val, NULL );
  179.         if( val.i_int <= 0 && i_channels == 1 )
  180.         {
  181.             if ( !snd_pcm_hw_params_test_channels( p_sys->p_snd_pcm, p_hw, 2 ))
  182.             {
  183.                 val.i_int = AOUT_VAR_STEREO;
  184.                 text.psz_string = N_("Stereo");
  185.                 var_Change( p_aout, "audio-device",
  186.                             VLC_VAR_ADDCHOICE, &val, &text );
  187.                 var_Set( p_aout, "audio-device", val );
  188.             }
  189.         }
  190.         
  191.         /* Close the previously opened device */
  192.         snd_pcm_close( p_sys->p_snd_pcm );
  193.     }
  194.     else if ( i_ret == -EBUSY )
  195.     {
  196.         msg_Warn( p_aout, "audio device: %s is already in use", psz_device );
  197.     }
  198.     /* Test for S/PDIF device if needed */
  199.     if ( psz_iec_device )
  200.     {
  201.         /* Opening the device should be enough */
  202.         if ( !(i_ret = snd_pcm_open( &p_sys->p_snd_pcm, psz_iec_device,
  203.                                      SND_PCM_STREAM_PLAYBACK,
  204.                                      SND_PCM_NONBLOCK ) ) )
  205.         {
  206.             val.i_int = AOUT_VAR_SPDIF;
  207.             text.psz_string = N_("A/52 over S/PDIF");
  208.             var_Change( p_aout, "audio-device",
  209.                         VLC_VAR_ADDCHOICE, &val, &text );
  210.             if( config_GetInt( p_aout, "spdif" ) )
  211.                 var_Set( p_aout, "audio-device", val );
  212.             snd_pcm_close( p_sys->p_snd_pcm );
  213.         }
  214.         else if ( i_ret == -EBUSY )
  215.         {
  216.             msg_Warn( p_aout, "audio device: %s is already in use",
  217.                       psz_iec_device );
  218.         }
  219.     }
  220.     var_Change( p_aout, "audio-device", VLC_VAR_CHOICESCOUNT, &val, NULL );
  221.     if( val.i_int <= 0 )
  222.     {
  223.         /* Probe() has failed. */
  224.         msg_Dbg( p_aout, "failed to find a useable alsa configuration" );
  225.         var_Destroy( p_aout, "audio-device" );
  226.         return;
  227.     }
  228.     /* Add final settings to the variable */
  229.     var_AddCallback( p_aout, "audio-device", aout_ChannelsRestart, NULL );
  230.     val.b_bool = VLC_TRUE;
  231.     var_Set( p_aout, "intf-change", val );
  232. }
  233. /*****************************************************************************
  234.  * Open: create a handle and open an alsa device
  235.  *****************************************************************************
  236.  * This function opens an alsa device, through the alsa API.
  237.  *
  238.  * Note: the only heap-allocated string is psz_device. All the other pointers
  239.  * are references to psz_device or to stack-allocated data.
  240.  *****************************************************************************/
  241. static int Open( vlc_object_t *p_this )
  242. {
  243.     aout_instance_t * p_aout = (aout_instance_t *)p_this;
  244.     struct aout_sys_t * p_sys;
  245.     vlc_value_t val;
  246.     char psz_default_iec_device[128]; /* Buffer used to store the default
  247.                                          S/PDIF device */
  248.     char * psz_device, * psz_iec_device; /* device names for PCM and S/PDIF
  249.                                             output */
  250.     int i_vlc_pcm_format; /* Audio format for VLC's data */
  251.     int i_snd_pcm_format; /* Audio format for ALSA's data */
  252.     snd_pcm_uframes_t i_buffer_size = 0;
  253.     snd_pcm_uframes_t i_period_size = 0;
  254.     int i_channels = 0;
  255.     snd_pcm_hw_params_t *p_hw;
  256.     snd_pcm_sw_params_t *p_sw;
  257.     int i_snd_rc = -1;
  258.     int i_old_rate;
  259.     /* Allocate structures */
  260.     p_aout->output.p_sys = p_sys = malloc( sizeof( aout_sys_t ) );
  261.     if( p_sys == NULL )
  262.     {
  263.         msg_Err( p_aout, "out of memory" );
  264.         return VLC_ENOMEM;
  265.     }
  266.     p_sys->b_playing = VLC_FALSE;
  267.     p_sys->start_date = 0;
  268.     p_sys->p_status = (snd_pcm_status_t *)malloc(snd_pcm_status_sizeof());
  269.     vlc_cond_init( p_aout, &p_sys->wait );
  270.     vlc_mutex_init( p_aout, &p_sys->lock );
  271.     /* Get device name */
  272.     if( (psz_device = config_GetPsz( p_aout, "alsadev" )) == NULL )
  273.     {
  274.         msg_Err( p_aout, "no audio device given (maybe "default" ?)" );
  275.         free( p_sys );
  276.         return VLC_EGENERIC;
  277.     }
  278.     /* Choose the IEC device for S/PDIF output:
  279.        if the device is overriden by the user then it will be the one
  280.        otherwise we compute the default device based on the output format. */
  281.     if( AOUT_FMT_NON_LINEAR( &p_aout->output.output )
  282.         && !strcmp( psz_device, DEFAULT_ALSA_DEVICE ) )
  283.     {
  284.         snprintf( psz_default_iec_device, sizeof(psz_default_iec_device),
  285.                   "iec958:AES0=0x%x,AES1=0x%x,AES2=0x%x,AES3=0x%x",
  286.                   IEC958_AES0_CON_EMPHASIS_NONE | IEC958_AES0_NONAUDIO,
  287.                   IEC958_AES1_CON_ORIGINAL | IEC958_AES1_CON_PCM_CODER,
  288.                   0,
  289.                   ( p_aout->output.output.i_rate == 48000 ?
  290.                     IEC958_AES3_CON_FS_48000 :
  291.                     ( p_aout->output.output.i_rate == 44100 ?
  292.                       IEC958_AES3_CON_FS_44100 : IEC958_AES3_CON_FS_32000 ) ) );
  293.         psz_iec_device = psz_default_iec_device;
  294.     }
  295.     else if( AOUT_FMT_NON_LINEAR( &p_aout->output.output ) )
  296.     {
  297.         psz_iec_device = psz_device;
  298.     }
  299.     else
  300.     {
  301.         psz_iec_device = NULL;
  302.     }
  303.     /* Choose the linear PCM format (read the comment above about FPU
  304.        and float32) */
  305.     if( p_aout->p_libvlc->i_cpu & CPU_CAPABILITY_FPU )
  306.     {
  307.         i_vlc_pcm_format = VLC_FOURCC('f','l','3','2');
  308.         i_snd_pcm_format = SND_PCM_FORMAT_FLOAT;
  309.     }
  310.     else
  311.     {
  312.         i_vlc_pcm_format = AOUT_FMT_S16_NE;
  313.         i_snd_pcm_format = SND_PCM_FORMAT_S16;
  314.     }
  315.     /* If the variable doesn't exist then it's the first time we're called
  316.        and we have to probe the available audio formats and channels */
  317.     if ( var_Type( p_aout, "audio-device" ) == 0 )
  318.     {
  319.         Probe( p_aout, psz_device, psz_iec_device, &i_snd_pcm_format );
  320.         switch( i_snd_pcm_format )
  321.         {
  322.         case SND_PCM_FORMAT_FLOAT:
  323.             i_vlc_pcm_format = VLC_FOURCC('f','l','3','2');
  324.             break;
  325.         case SND_PCM_FORMAT_S16:
  326.             i_vlc_pcm_format = AOUT_FMT_S16_NE;
  327.             break;
  328.         }
  329.     }
  330.     if ( var_Get( p_aout, "audio-device", &val ) < 0 )
  331.     {
  332.         free( p_sys );
  333.         free( psz_device );
  334.         return VLC_EGENERIC;
  335.     }
  336.     if ( val.i_int == AOUT_VAR_SPDIF )
  337.     {
  338.         p_aout->output.output.i_format = VLC_FOURCC('s','p','d','i');
  339.     }
  340.     else if ( val.i_int == AOUT_VAR_5_1 )
  341.     {
  342.         p_aout->output.output.i_format = i_vlc_pcm_format;
  343.         p_aout->output.output.i_physical_channels
  344.             = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER
  345.                | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT
  346.                | AOUT_CHAN_LFE;
  347.         free( psz_device );
  348.         psz_device = strdup( "surround51" );
  349.     }
  350.     else if ( val.i_int == AOUT_VAR_2F2R )
  351.     {
  352.         p_aout->output.output.i_format = i_vlc_pcm_format;
  353.         p_aout->output.output.i_physical_channels
  354.             = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT
  355.                | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT;
  356.         free( psz_device );
  357.         psz_device = strdup( "surround40" );
  358.     }
  359.     else if ( val.i_int == AOUT_VAR_STEREO )
  360.     {
  361.         p_aout->output.output.i_format = i_vlc_pcm_format;
  362.         p_aout->output.output.i_physical_channels
  363.             = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT;
  364.     }
  365.     else if ( val.i_int == AOUT_VAR_MONO )
  366.     {
  367.         p_aout->output.output.i_format = i_vlc_pcm_format;
  368.         p_aout->output.output.i_physical_channels = AOUT_CHAN_CENTER;
  369.     }
  370.     else
  371.     {
  372.         /* This should not happen ! */
  373.         msg_Err( p_aout, "internal: can't find audio-device (%i)", val.i_int );
  374.         free( p_sys );
  375.         return VLC_EGENERIC;
  376.     }
  377. #ifdef ALSA_DEBUG
  378.     snd_output_stdio_attach( &p_sys->p_snd_stderr, stderr, 0 );
  379. #endif
  380.     /* Open the device */
  381.     if ( AOUT_FMT_NON_LINEAR( &p_aout->output.output ) )
  382.     {
  383.         if ( ( i_snd_rc = snd_pcm_open( &p_sys->p_snd_pcm, psz_iec_device,
  384.                             SND_PCM_STREAM_PLAYBACK, 0 ) ) < 0 )
  385.         {
  386.             msg_Err( p_aout, "cannot open ALSA device `%s' (%s)",
  387.                              psz_iec_device, snd_strerror( i_snd_rc ) );
  388.             free( p_sys );
  389.             free( psz_device );
  390.             return VLC_EGENERIC;
  391.         }
  392.         i_buffer_size = ALSA_SPDIF_BUFFER_SIZE;
  393.         i_snd_pcm_format = SND_PCM_FORMAT_S16;
  394.         i_channels = 2;
  395.         p_aout->output.i_nb_samples = i_period_size = ALSA_SPDIF_PERIOD_SIZE;
  396.         p_aout->output.output.i_bytes_per_frame = AOUT_SPDIF_SIZE;
  397.         p_aout->output.output.i_frame_length = A52_FRAME_NB;
  398.         aout_VolumeNoneInit( p_aout );
  399.     }
  400.     else
  401.     {
  402.         msg_Dbg( p_aout, "opening ALSA device `%s'", psz_device );
  403.         if ( ( i_snd_rc = snd_pcm_open( &p_sys->p_snd_pcm, psz_device,
  404.                             SND_PCM_STREAM_PLAYBACK, 0 ) ) < 0 )
  405.         {
  406.             msg_Err( p_aout, "cannot open ALSA device `%s' (%s)",
  407.                              psz_device, snd_strerror( i_snd_rc ) );
  408.             free( p_sys );
  409.             free( psz_device );
  410.             return VLC_EGENERIC;
  411.         }
  412.         i_buffer_size = ALSA_DEFAULT_BUFFER_SIZE;
  413.         i_channels = aout_FormatNbChannels( &p_aout->output.output );
  414.         p_aout->output.i_nb_samples = i_period_size = ALSA_DEFAULT_PERIOD_SIZE;
  415.         aout_VolumeSoftInit( p_aout );
  416.     }
  417.     /* Free psz_device so that all the remaining data is stack-allocated */
  418.     free( psz_device );
  419.     p_aout->output.pf_play = Play;
  420.     snd_pcm_hw_params_alloca(&p_hw);
  421.     snd_pcm_sw_params_alloca(&p_sw);
  422.     /* Get Initial hardware parameters */
  423.     if ( ( i_snd_rc = snd_pcm_hw_params_any( p_sys->p_snd_pcm, p_hw ) ) < 0 )
  424.     {
  425.         msg_Err( p_aout, "unable to retrieve initial hardware parameters (%s)",
  426.                          snd_strerror( i_snd_rc ) );
  427.         goto error;
  428.     }
  429.     /* Set format. */
  430.     if ( ( i_snd_rc = snd_pcm_hw_params_set_format( p_sys->p_snd_pcm, p_hw,
  431.                                                     i_snd_pcm_format ) ) < 0 )
  432.     {
  433.         msg_Err( p_aout, "unable to set stream sample size and word order (%s)",
  434.                          snd_strerror( i_snd_rc ) );
  435.         goto error;
  436.     }
  437.     if ( ( i_snd_rc = snd_pcm_hw_params_set_access( p_sys->p_snd_pcm, p_hw,
  438.                                     SND_PCM_ACCESS_RW_INTERLEAVED ) ) < 0 )
  439.     {
  440.         msg_Err( p_aout, "unable to set interleaved stream format (%s)",
  441.                          snd_strerror( i_snd_rc ) );
  442.         goto error;
  443.     }
  444.     /* Set channels. */
  445.     if ( ( i_snd_rc = snd_pcm_hw_params_set_channels( p_sys->p_snd_pcm, p_hw,
  446.                                                       i_channels ) ) < 0 )
  447.     {
  448.         msg_Err( p_aout, "unable to set number of output channels (%s)",
  449.                          snd_strerror( i_snd_rc ) );
  450.         goto error;
  451.     }
  452.     /* Set rate. */
  453.     i_old_rate = p_aout->output.output.i_rate;
  454. #ifdef HAVE_ALSA_NEW_API
  455.     i_snd_rc = snd_pcm_hw_params_set_rate_near( p_sys->p_snd_pcm, p_hw,
  456.                                                 &p_aout->output.output.i_rate,
  457.                                                 NULL );
  458. #else
  459.     i_snd_rc = snd_pcm_hw_params_set_rate_near( p_sys->p_snd_pcm, p_hw,
  460.                                                 p_aout->output.output.i_rate,
  461.                                                 NULL );
  462. #endif
  463.     if( i_snd_rc < 0 || p_aout->output.output.i_rate != i_old_rate )
  464.     {
  465.         msg_Warn( p_aout, "The rate %d Hz is not supported by your hardware. "
  466.                   "Using %d Hz instead.n", i_old_rate,
  467.                   p_aout->output.output.i_rate );
  468.     }
  469.     /* Set buffer size. */
  470. #ifdef HAVE_ALSA_NEW_API
  471.     if ( ( i_snd_rc = snd_pcm_hw_params_set_buffer_size_near( p_sys->p_snd_pcm,
  472.                                     p_hw, &i_buffer_size ) ) < 0 )
  473. #else
  474.     if ( ( i_snd_rc = snd_pcm_hw_params_set_buffer_size_near( p_sys->p_snd_pcm,
  475.                                     p_hw, i_buffer_size ) ) < 0 )
  476. #endif
  477.     {
  478.         msg_Err( p_aout, "unable to set buffer size (%s)",
  479.                          snd_strerror( i_snd_rc ) );
  480.         goto error;
  481.     }
  482.     /* Set period size. */
  483. #ifdef HAVE_ALSA_NEW_API
  484.     if ( ( i_snd_rc = snd_pcm_hw_params_set_period_size_near( p_sys->p_snd_pcm,
  485.                                     p_hw, &i_period_size, NULL ) ) < 0 )
  486. #else
  487.     if ( ( i_snd_rc = snd_pcm_hw_params_set_period_size_near( p_sys->p_snd_pcm,
  488.                                     p_hw, i_period_size, NULL ) ) < 0 )
  489. #endif
  490.     {
  491.         msg_Err( p_aout, "unable to set period size (%s)",
  492.                          snd_strerror( i_snd_rc ) );
  493.         goto error;
  494.     }
  495.     p_aout->output.i_nb_samples = i_period_size;
  496.     /* Commit hardware parameters. */
  497.     if ( ( i_snd_rc = snd_pcm_hw_params( p_sys->p_snd_pcm, p_hw ) ) < 0 )
  498.     {
  499.         msg_Err( p_aout, "unable to commit hardware configuration (%s)",
  500.                          snd_strerror( i_snd_rc ) );
  501.         goto error;
  502.     }
  503. #ifdef HAVE_ALSA_NEW_API
  504.     if( ( i_snd_rc = snd_pcm_hw_params_get_period_time( p_hw,
  505.                                     &p_sys->i_period_time, NULL ) ) < 0 )
  506. #else
  507.     if( ( p_sys->i_period_time =
  508.                   snd_pcm_hw_params_get_period_time( p_hw, NULL ) ) < 0 )
  509. #endif
  510.     {
  511.         msg_Err( p_aout, "unable to get period time (%s)",
  512.                          snd_strerror( i_snd_rc ) );
  513.         goto error;
  514.     }
  515.     /* Get Initial software parameters */
  516.     snd_pcm_sw_params_current( p_sys->p_snd_pcm, p_sw );
  517.     i_snd_rc = snd_pcm_sw_params_set_sleep_min( p_sys->p_snd_pcm, p_sw, 0 );
  518.     i_snd_rc = snd_pcm_sw_params_set_avail_min( p_sys->p_snd_pcm, p_sw,
  519.                                                 p_aout->output.i_nb_samples );
  520.     /* Commit software parameters. */
  521.     if ( snd_pcm_sw_params( p_sys->p_snd_pcm, p_sw ) < 0 )
  522.     {
  523.         msg_Err( p_aout, "unable to set software configuration" );
  524.         goto error;
  525.     }
  526. #ifdef ALSA_DEBUG
  527.     snd_output_printf( p_sys->p_snd_stderr, "nALSA hardware setup:nn" );
  528.     snd_pcm_dump_hw_setup( p_sys->p_snd_pcm, p_sys->p_snd_stderr );
  529.     snd_output_printf( p_sys->p_snd_stderr, "nALSA software setup:nn" );
  530.     snd_pcm_dump_sw_setup( p_sys->p_snd_pcm, p_sys->p_snd_stderr );
  531.     snd_output_printf( p_sys->p_snd_stderr, "n" );
  532. #endif
  533.     /* Create ALSA thread and wait for its readiness. */
  534.     if( vlc_thread_create( p_aout, "aout", ALSAThread,
  535.                            VLC_THREAD_PRIORITY_OUTPUT, VLC_FALSE ) )
  536.     {
  537.         msg_Err( p_aout, "cannot create ALSA thread (%s)", strerror(errno) );
  538.         goto error;
  539.     }
  540.     return 0;
  541. error:
  542.     snd_pcm_close( p_sys->p_snd_pcm );
  543. #ifdef ALSA_DEBUG
  544.     snd_output_close( p_sys->p_snd_stderr );
  545. #endif
  546.     free( p_sys );
  547.     return VLC_EGENERIC;
  548. }
  549. /*****************************************************************************
  550.  * Play: nothing to do
  551.  *****************************************************************************/
  552. static void Play( aout_instance_t *p_aout )
  553. {
  554.     if( !p_aout->output.p_sys->b_playing )
  555.     {
  556.         p_aout->output.p_sys->b_playing = 1;
  557.         /* get the playing date of the first aout buffer */
  558.         p_aout->output.p_sys->start_date =
  559.             aout_FifoFirstDate( p_aout, &p_aout->output.fifo );
  560.         /* wake up the audio output thread */
  561.         vlc_mutex_lock( &p_aout->output.p_sys->lock );
  562.         vlc_cond_signal( &p_aout->output.p_sys->wait );
  563.         vlc_mutex_unlock( &p_aout->output.p_sys->lock );
  564.     }
  565. }
  566. /*****************************************************************************
  567.  * Close: close the ALSA device
  568.  *****************************************************************************/
  569. static void Close( vlc_object_t *p_this )
  570. {
  571.     aout_instance_t *p_aout = (aout_instance_t *)p_this;
  572.     struct aout_sys_t * p_sys = p_aout->output.p_sys;
  573.     int i_snd_rc;
  574.     /* make sure the audio output thread is waken up */
  575.     vlc_mutex_lock( &p_aout->output.p_sys->lock );
  576.     vlc_cond_signal( &p_aout->output.p_sys->wait );
  577.     vlc_mutex_unlock( &p_aout->output.p_sys->lock );
  578.     p_aout->b_die = VLC_TRUE;
  579.     vlc_thread_join( p_aout );
  580.     p_aout->b_die = VLC_FALSE;
  581.     i_snd_rc = snd_pcm_close( p_sys->p_snd_pcm );
  582.     if( i_snd_rc > 0 )
  583.     {
  584.         msg_Err( p_aout, "failed closing ALSA device (%s)",
  585.                          snd_strerror( i_snd_rc ) );
  586.     }
  587. #ifdef ALSA_DEBUG
  588.     snd_output_close( p_sys->p_snd_stderr );
  589. #endif
  590.     free( p_sys->p_status );
  591.     free( p_sys );
  592. }
  593. /*****************************************************************************
  594.  * ALSAThread: asynchronous thread used to DMA the data to the device
  595.  *****************************************************************************/
  596. static int ALSAThread( aout_instance_t * p_aout )
  597. {
  598.     /* Wait for the exact time to start playing (avoids resampling) */
  599.     vlc_mutex_lock( &p_aout->output.p_sys->lock );
  600.     if( !p_aout->output.p_sys->start_date )
  601.         vlc_cond_wait( &p_aout->output.p_sys->wait,
  602.                        &p_aout->output.p_sys->lock );
  603.     vlc_mutex_unlock( &p_aout->output.p_sys->lock );
  604.     mwait( p_aout->output.p_sys->start_date - AOUT_PTS_TOLERANCE / 4 );
  605.     while ( !p_aout->b_die )
  606.     {
  607.         ALSAFill( p_aout );
  608.     }
  609.     return 0;
  610. }
  611. /*****************************************************************************
  612.  * ALSAFill: function used to fill the ALSA buffer as much as possible
  613.  *****************************************************************************/
  614. static void ALSAFill( aout_instance_t * p_aout )
  615. {
  616.     struct aout_sys_t * p_sys = p_aout->output.p_sys;
  617.     aout_buffer_t * p_buffer;
  618.     snd_pcm_status_t * p_status = p_sys->p_status;
  619.     snd_timestamp_t ts_next;
  620.     int i_snd_rc;
  621.     mtime_t next_date;
  622.     /* Fill in the buffer until space or audio output buffer shortage */
  623.     {
  624.         /* Get the status */
  625.         i_snd_rc = snd_pcm_status( p_sys->p_snd_pcm, p_status );
  626.         if( i_snd_rc < 0 )
  627.         {
  628.             msg_Err( p_aout, "unable to get the device's status (%s)",
  629.                              snd_strerror( i_snd_rc ) );
  630.             msleep( p_sys->i_period_time >> 1 );
  631.             return;
  632.         }
  633.         /* Handle buffer underruns and reget the status */
  634.         if( snd_pcm_status_get_state( p_status ) == SND_PCM_STATE_XRUN )
  635.         {
  636.             /* Prepare the device */
  637.             i_snd_rc = snd_pcm_prepare( p_sys->p_snd_pcm );
  638.             if( i_snd_rc == 0 )
  639.             {
  640.                 msg_Warn( p_aout, "recovered from buffer underrun" );
  641.                 /* Reget the status */
  642.                 i_snd_rc = snd_pcm_status( p_sys->p_snd_pcm, p_status );
  643.                 if( i_snd_rc < 0 )
  644.                 {
  645.                     msg_Err( p_aout, "unable to get the device's status after "
  646.                              "recovery (%s)", snd_strerror( i_snd_rc ) );
  647.                     msleep( p_sys->i_period_time >> 1 );
  648.                     return;
  649.                 }
  650.             }
  651.             else
  652.             {
  653.                 msg_Err( p_aout, "unable to recover from buffer underrun" );
  654.                 msleep( p_sys->i_period_time >> 1 );
  655.                 return;
  656.             }
  657.             /* Underrun, try to recover as quickly as possible */
  658.             next_date = mdate();
  659.         }
  660.         else
  661.         {
  662.             /* Here the device should be either in the RUNNING state.
  663.              * p_status is valid. */
  664.             snd_pcm_status_get_tstamp( p_status, &ts_next );
  665.             next_date = (mtime_t)ts_next.tv_sec * 1000000 + ts_next.tv_usec;
  666.             if( next_date )
  667.             {
  668.                 next_date += (mtime_t)snd_pcm_status_get_delay(p_status)
  669.                         * 1000000 / p_aout->output.output.i_rate;
  670.             }
  671.             else
  672.             {
  673.                 /* With screwed ALSA drivers the timestamp is always zero;
  674.                  * use another method then */
  675.                 snd_pcm_sframes_t delay;
  676.                 ssize_t i_bytes = 0;
  677.                 if( !snd_pcm_delay( p_sys->p_snd_pcm, &delay ) )
  678.                 {
  679.                     i_bytes = snd_pcm_frames_to_bytes(p_sys->p_snd_pcm, delay);
  680.                 }
  681.                 next_date = mdate() + (mtime_t)i_bytes * 1000000
  682.                         / p_aout->output.output.i_bytes_per_frame
  683.                         / p_aout->output.output.i_rate
  684.                         * p_aout->output.output.i_frame_length;
  685.             }
  686.         }
  687.         p_buffer = aout_OutputNextBuffer( p_aout, next_date,
  688.                         (p_aout->output.output.i_format ==
  689.                          VLC_FOURCC('s','p','d','i')) );
  690.         /* Audio output buffer shortage -> stop the fill process and wait */
  691.         if( p_buffer == NULL )
  692.         {
  693.             msleep( p_sys->i_period_time >> 1 );
  694.             return;
  695.         }
  696.         i_snd_rc = snd_pcm_writei( p_sys->p_snd_pcm, p_buffer->p_buffer,
  697.                                    p_buffer->i_nb_samples );
  698.         if( i_snd_rc < 0 )
  699.         {
  700.             msg_Err( p_aout, "write failed (%s)",
  701.                              snd_strerror( i_snd_rc ) );
  702.         }
  703.         aout_BufferFree( p_buffer );
  704.     }
  705. }