alsa.c
上传用户:kjfoods
上传日期:2020-07-06
资源大小:29949k
文件大小:37k
源码类别:

midi

开发平台:

Unix_Linux

  1. /*****************************************************************************
  2.  * alsa.c : alsa plugin for vlc
  3.  *****************************************************************************
  4.  * Copyright (C) 2000-2001 the VideoLAN team
  5.  * $Id: 9a91ae0b9db6ccb9228f231b0edc7347902be624 $
  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., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
  25.  *****************************************************************************/
  26. /*****************************************************************************
  27.  * Preamble
  28.  *****************************************************************************/
  29. #ifdef HAVE_CONFIG_H
  30. # include "config.h"
  31. #endif
  32. #include <vlc_common.h>
  33. #include <vlc_plugin.h>
  34. #include <errno.h>                                                 /* ENOMEM */
  35. #include <vlc_dialog.h>
  36. #include <vlc_aout.h>
  37. /* ALSA part
  38.    Note: we use the new API which is available since 0.9.0beta10a. */
  39. #define ALSA_PCM_NEW_HW_PARAMS_API
  40. #define ALSA_PCM_NEW_SW_PARAMS_API
  41. #include <alsa/asoundlib.h>
  42. /*#define ALSA_DEBUG*/
  43. /*****************************************************************************
  44.  * aout_sys_t: ALSA audio output method descriptor
  45.  *****************************************************************************
  46.  * This structure is part of the audio output thread descriptor.
  47.  * It describes the ALSA specific properties of an audio device.
  48.  *****************************************************************************/
  49. struct aout_sys_t
  50. {
  51.     snd_pcm_t         * p_snd_pcm;
  52.     unsigned int                 i_period_time;
  53. #ifdef ALSA_DEBUG
  54.     snd_output_t      * p_snd_stderr;
  55. #endif
  56.     int b_playing;                                         /* playing status */
  57.     mtime_t start_date;
  58.     vlc_mutex_t lock;
  59.     vlc_cond_t  wait ;
  60.     snd_pcm_status_t *p_status;
  61. };
  62. #define A52_FRAME_NB 1536
  63. /* These values are in frames.
  64.    To convert them to a number of bytes you have to multiply them by the
  65.    number of channel(s) (eg. 2 for stereo) and the size of a sample (eg.
  66.    2 for int16_t). */
  67. #define ALSA_DEFAULT_PERIOD_SIZE        1024
  68. #define ALSA_DEFAULT_BUFFER_SIZE        ( ALSA_DEFAULT_PERIOD_SIZE << 8 )
  69. #define ALSA_SPDIF_PERIOD_SIZE          A52_FRAME_NB
  70. #define ALSA_SPDIF_BUFFER_SIZE          ( ALSA_SPDIF_PERIOD_SIZE << 4 )
  71. /* Why << 4 ? --Meuuh */
  72. /* Why not ? --Bozo */
  73. /* Right. --Meuuh */
  74. #define DEFAULT_ALSA_DEVICE N_("default")
  75. /*****************************************************************************
  76.  * Local prototypes
  77.  *****************************************************************************/
  78. static int   Open         ( vlc_object_t * );
  79. static void  Close        ( vlc_object_t * );
  80. static void  Play         ( aout_instance_t * );
  81. static void* ALSAThread   ( vlc_object_t * );
  82. static void  ALSAFill     ( aout_instance_t * );
  83. static int FindDevicesCallback( vlc_object_t *p_this, char const *psz_name,
  84.                                 vlc_value_t newval, vlc_value_t oldval, void *p_unused );
  85. /*****************************************************************************
  86.  * Module descriptor
  87.  *****************************************************************************/
  88. static const char *const ppsz_devices[] = { "default" };
  89. static const char *const ppsz_devices_text[] = { N_("Default") };
  90. vlc_module_begin ()
  91.     set_shortname( "ALSA" )
  92.     set_description( N_("ALSA audio output") )
  93.     set_category( CAT_AUDIO )
  94.     set_subcategory( SUBCAT_AUDIO_AOUT )
  95.     add_string( "alsa-audio-device", DEFAULT_ALSA_DEVICE, aout_FindAndRestart,
  96.                 N_("ALSA Device Name"), NULL, false )
  97.         add_deprecated_alias( "alsadev" )   /* deprecated since 0.9.3 */
  98.         change_string_list( ppsz_devices, ppsz_devices_text, FindDevicesCallback )
  99.         change_action_add( FindDevicesCallback, N_("Refresh list") )
  100.     set_capability( "audio output", 150 )
  101.     set_callbacks( Open, Close )
  102. vlc_module_end ()
  103. /*****************************************************************************
  104.  * Probe: probe the audio device for available formats and channels
  105.  *****************************************************************************/
  106. static void Probe( aout_instance_t * p_aout,
  107.                    const char * psz_device, const char * psz_iec_device,
  108.                    int *pi_snd_pcm_format )
  109. {
  110.     struct aout_sys_t * p_sys = p_aout->output.p_sys;
  111.     vlc_value_t val, text;
  112.     int i_ret;
  113.     var_Create ( p_aout, "audio-device", VLC_VAR_INTEGER | VLC_VAR_HASCHOICE );
  114.     text.psz_string = _("Audio Device");
  115.     var_Change( p_aout, "audio-device", VLC_VAR_SETTEXT, &text, NULL );
  116.     /* We'll open the audio device in non blocking mode so we can just exit
  117.      * when it is already in use, but for the real stuff we'll still use
  118.      * the blocking mode */
  119.     /* Now test linear PCM capabilities */
  120.     if ( !(i_ret = snd_pcm_open( &p_sys->p_snd_pcm, psz_device,
  121.                                  SND_PCM_STREAM_PLAYBACK,
  122.                                  SND_PCM_NONBLOCK ) ) )
  123.     {
  124.         int i_channels;
  125.         snd_pcm_hw_params_t * p_hw;
  126.         snd_pcm_hw_params_alloca (&p_hw);
  127.         if ( snd_pcm_hw_params_any( p_sys->p_snd_pcm, p_hw ) < 0 )
  128.         {
  129.             msg_Warn( p_aout, "unable to retrieve initial hardware parameters"
  130.                               ", disabling linear PCM audio" );
  131.             snd_pcm_close( p_sys->p_snd_pcm );
  132.             var_Destroy( p_aout, "audio-device" );
  133.             return;
  134.         }
  135.         if ( snd_pcm_hw_params_set_format( p_sys->p_snd_pcm, p_hw,
  136.                                            *pi_snd_pcm_format ) < 0 )
  137.         {
  138.             int i_snd_rc = -1;
  139.             if( *pi_snd_pcm_format != SND_PCM_FORMAT_S16 )
  140.             {
  141.                 *pi_snd_pcm_format = SND_PCM_FORMAT_S16;
  142.                 i_snd_rc = snd_pcm_hw_params_set_format( p_sys->p_snd_pcm,
  143.                                                     p_hw, *pi_snd_pcm_format );
  144.             }
  145.             if ( i_snd_rc < 0 )
  146.             {
  147.                 msg_Warn( p_aout, "unable to set stream sample size and "
  148.                           "word order, disabling linear PCM audio" );
  149.                 snd_pcm_close( p_sys->p_snd_pcm );
  150.                 var_Destroy( p_aout, "audio-device" );
  151.                 return;
  152.             }
  153.         }
  154.         i_channels = aout_FormatNbChannels( &p_aout->output.output );
  155.         while ( i_channels > 0 )
  156.         {
  157.             if ( !snd_pcm_hw_params_test_channels( p_sys->p_snd_pcm, p_hw,
  158.                                                    i_channels ) )
  159.             {
  160.                 switch ( i_channels )
  161.                 {
  162.                 case 1:
  163.                     val.i_int = AOUT_VAR_MONO;
  164.                     text.psz_string = _("Mono");
  165.                     var_Change( p_aout, "audio-device",
  166.                                 VLC_VAR_ADDCHOICE, &val, &text );
  167.                     break;
  168.                 case 2:
  169.                     val.i_int = AOUT_VAR_STEREO;
  170.                     text.psz_string = _("Stereo");
  171.                     var_Change( p_aout, "audio-device",
  172.                                 VLC_VAR_ADDCHOICE, &val, &text );
  173.                     var_Set( p_aout, "audio-device", val );
  174.                     break;
  175.                 case 4:
  176.                     val.i_int = AOUT_VAR_2F2R;
  177.                     text.psz_string = _("2 Front 2 Rear");
  178.                     var_Change( p_aout, "audio-device",
  179.                                 VLC_VAR_ADDCHOICE, &val, &text );
  180.                     break;
  181.                 case 6:
  182.                     val.i_int = AOUT_VAR_5_1;
  183.                     text.psz_string = "5.1";
  184.                     var_Change( p_aout, "audio-device",
  185.                                 VLC_VAR_ADDCHOICE, &val, &text );
  186.                     break;
  187.                 }
  188.             }
  189.             --i_channels;
  190.         }
  191.         /* Special case for mono on stereo only boards */
  192.         i_channels = aout_FormatNbChannels( &p_aout->output.output );
  193.         var_Change( p_aout, "audio-device", VLC_VAR_CHOICESCOUNT, &val, NULL );
  194.         if( val.i_int <= 0 && i_channels == 1 )
  195.         {
  196.             if ( !snd_pcm_hw_params_test_channels( p_sys->p_snd_pcm, p_hw, 2 ))
  197.             {
  198.                 val.i_int = AOUT_VAR_STEREO;
  199.                 text.psz_string = (char*)N_("Stereo");
  200.                 var_Change( p_aout, "audio-device",
  201.                             VLC_VAR_ADDCHOICE, &val, &text );
  202.                 var_Set( p_aout, "audio-device", val );
  203.             }
  204.         }
  205.         /* Close the previously opened device */
  206.         snd_pcm_close( p_sys->p_snd_pcm );
  207.     }
  208.     else if ( i_ret == -EBUSY )
  209.     {
  210.         msg_Warn( p_aout, "audio device: %s is already in use", psz_device );
  211.     }
  212.     /* Test for S/PDIF device if needed */
  213.     if ( psz_iec_device )
  214.     {
  215.         /* Opening the device should be enough */
  216.         if ( !(i_ret = snd_pcm_open( &p_sys->p_snd_pcm, psz_iec_device,
  217.                                      SND_PCM_STREAM_PLAYBACK,
  218.                                      SND_PCM_NONBLOCK ) ) )
  219.         {
  220.             val.i_int = AOUT_VAR_SPDIF;
  221.             text.psz_string = (char*)N_("A/52 over S/PDIF");
  222.             var_Change( p_aout, "audio-device",
  223.                         VLC_VAR_ADDCHOICE, &val, &text );
  224.             if( config_GetInt( p_aout, "spdif" ) )
  225.                 var_Set( p_aout, "audio-device", val );
  226.             snd_pcm_close( p_sys->p_snd_pcm );
  227.         }
  228.         else if ( i_ret == -EBUSY )
  229.         {
  230.             msg_Warn( p_aout, "audio device: %s is already in use",
  231.                       psz_iec_device );
  232.         }
  233.     }
  234.     var_Change( p_aout, "audio-device", VLC_VAR_CHOICESCOUNT, &val, NULL );
  235.     if( val.i_int <= 0 )
  236.     {
  237.         /* Probe() has failed. */
  238.         msg_Dbg( p_aout, "failed to find a useable alsa configuration" );
  239.         var_Destroy( p_aout, "audio-device" );
  240.         return;
  241.     }
  242.     /* Add final settings to the variable */
  243.     var_AddCallback( p_aout, "audio-device", aout_ChannelsRestart, NULL );
  244.     var_SetBool( p_aout, "intf-change", true );
  245. }
  246. /*****************************************************************************
  247.  * Open: create a handle and open an alsa device
  248.  *****************************************************************************
  249.  * This function opens an alsa device, through the alsa API.
  250.  *
  251.  * Note: the only heap-allocated string is psz_device. All the other pointers
  252.  * are references to psz_device or to stack-allocated data.
  253.  *****************************************************************************/
  254. static int Open( vlc_object_t *p_this )
  255. {
  256.     aout_instance_t * p_aout = (aout_instance_t *)p_this;
  257.     struct aout_sys_t * p_sys;
  258.     vlc_value_t val;
  259.     char psz_default_iec_device[128]; /* Buffer used to store the default
  260.                                          S/PDIF device */
  261.     char * psz_device, * psz_iec_device; /* device names for PCM and S/PDIF
  262.                                             output */
  263.     int i_vlc_pcm_format; /* Audio format for VLC's data */
  264.     int i_snd_pcm_format; /* Audio format for ALSA's data */
  265.     snd_pcm_uframes_t i_buffer_size = 0;
  266.     snd_pcm_uframes_t i_period_size = 0;
  267.     int i_channels = 0;
  268.     snd_pcm_hw_params_t *p_hw;
  269.     snd_pcm_sw_params_t *p_sw;
  270.     int i_snd_rc = -1;
  271.     unsigned int i_old_rate;
  272.     bool b_retry = true;
  273.     /* Allocate structures */
  274.     p_aout->output.p_sys = p_sys = malloc( sizeof( aout_sys_t ) );
  275.     if( p_sys == NULL )
  276.         return VLC_ENOMEM;
  277.     p_sys->b_playing = false;
  278.     p_sys->start_date = 0;
  279.     vlc_cond_init( &p_sys->wait );
  280.     vlc_mutex_init( &p_sys->lock );
  281.     /* Get device name */
  282.     if( (psz_device = config_GetPsz( p_aout, "alsa-audio-device" )) == NULL )
  283.     {
  284.         msg_Err( p_aout, "no audio device given (maybe "default" ?)" );
  285.         dialog_Fatal( p_aout, _("No Audio Device"), "%s",
  286.                         _("No audio device name was given. You might want to " 
  287.                           "enter "default".") );
  288.         free( p_sys );
  289.         return VLC_EGENERIC;
  290.     }
  291.     /* Choose the IEC device for S/PDIF output:
  292.        if the device is overriden by the user then it will be the one
  293.        otherwise we compute the default device based on the output format. */
  294.     if( AOUT_FMT_NON_LINEAR( &p_aout->output.output )
  295.         && !strcmp( psz_device, DEFAULT_ALSA_DEVICE ) )
  296.     {
  297.         snprintf( psz_default_iec_device, sizeof(psz_default_iec_device),
  298.                   "iec958:AES0=0x%x,AES1=0x%x,AES2=0x%x,AES3=0x%x",
  299.                   IEC958_AES0_CON_EMPHASIS_NONE | IEC958_AES0_NONAUDIO,
  300.                   IEC958_AES1_CON_ORIGINAL | IEC958_AES1_CON_PCM_CODER,
  301.                   0,
  302.                   ( p_aout->output.output.i_rate == 48000 ?
  303.                     IEC958_AES3_CON_FS_48000 :
  304.                     ( p_aout->output.output.i_rate == 44100 ?
  305.                       IEC958_AES3_CON_FS_44100 : IEC958_AES3_CON_FS_32000 ) ) );
  306.         psz_iec_device = psz_default_iec_device;
  307.     }
  308.     else if( AOUT_FMT_NON_LINEAR( &p_aout->output.output ) )
  309.     {
  310.         psz_iec_device = psz_device;
  311.     }
  312.     else
  313.     {
  314.         psz_iec_device = NULL;
  315.     }
  316.     /* Choose the linear PCM format (read the comment above about FPU
  317.        and float32) */
  318.     if( vlc_CPU() & CPU_CAPABILITY_FPU )
  319.     {
  320.         i_vlc_pcm_format = VLC_FOURCC('f','l','3','2');
  321.         i_snd_pcm_format = SND_PCM_FORMAT_FLOAT;
  322.     }
  323.     else
  324.     {
  325.         i_vlc_pcm_format = AOUT_FMT_S16_NE;
  326.         i_snd_pcm_format = SND_PCM_FORMAT_S16;
  327.     }
  328.     /* If the variable doesn't exist then it's the first time we're called
  329.        and we have to probe the available audio formats and channels */
  330.     if ( var_Type( p_aout, "audio-device" ) == 0 )
  331.     {
  332.         Probe( p_aout, psz_device, psz_iec_device, &i_snd_pcm_format );
  333.     }
  334.     if ( var_Get( p_aout, "audio-device", &val ) < 0 )
  335.     {
  336.         free( p_sys );
  337.         free( psz_device );
  338.         return VLC_EGENERIC;
  339.     }
  340.     p_aout->output.output.i_format = i_vlc_pcm_format;
  341.     if ( val.i_int == AOUT_VAR_5_1 )
  342.     {
  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_physical_channels
  353.             = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT
  354.                | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT;
  355.         free( psz_device );
  356.         psz_device = strdup( "surround40" );
  357.     }
  358.     else if ( val.i_int == AOUT_VAR_STEREO )
  359.     {
  360.         p_aout->output.output.i_physical_channels
  361.             = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT;
  362.     }
  363.     else if ( val.i_int == AOUT_VAR_MONO )
  364.     {
  365.         p_aout->output.output.i_physical_channels = AOUT_CHAN_CENTER;
  366.     }
  367.     else if( val.i_int != AOUT_VAR_SPDIF )
  368.     {
  369.         /* This should not happen ! */
  370.         msg_Err( p_aout, "internal: can't find audio-device (%i)", val.i_int );
  371.         free( p_sys );
  372.         free( psz_device );
  373.         return VLC_EGENERIC;
  374.     }
  375. #ifdef ALSA_DEBUG
  376.     snd_output_stdio_attach( &p_sys->p_snd_stderr, stderr, 0 );
  377. #endif
  378.     /* Open the device */
  379.     if ( val.i_int == AOUT_VAR_SPDIF )
  380.     {
  381.         if ( ( i_snd_rc = snd_pcm_open( &p_sys->p_snd_pcm, psz_iec_device,
  382.                             SND_PCM_STREAM_PLAYBACK, 0 ) ) < 0 )
  383.         {
  384.             msg_Err( p_aout, "cannot open ALSA device `%s' (%s)",
  385.                              psz_iec_device, snd_strerror( i_snd_rc ) );
  386.             dialog_Fatal( p_aout, _("Audio output failed"),
  387.                             _("VLC could not open the ALSA device "%s" (%s)."),
  388.                             psz_iec_device, snd_strerror( i_snd_rc ) );
  389.             free( p_sys );
  390.             free( psz_device );
  391.             return VLC_EGENERIC;
  392.         }
  393.         i_buffer_size = ALSA_SPDIF_BUFFER_SIZE;
  394.         i_snd_pcm_format = SND_PCM_FORMAT_S16;
  395.         i_channels = 2;
  396.         i_vlc_pcm_format = VLC_FOURCC('s','p','d','i');
  397.         p_aout->output.i_nb_samples = i_period_size = ALSA_SPDIF_PERIOD_SIZE;
  398.         p_aout->output.output.i_bytes_per_frame = AOUT_SPDIF_SIZE;
  399.         p_aout->output.output.i_frame_length = A52_FRAME_NB;
  400.         aout_VolumeNoneInit( p_aout );
  401.     }
  402.     else
  403.     {
  404.         int i;
  405.         msg_Dbg( p_aout, "opening ALSA device `%s'", psz_device );
  406.         /* Since it seems snd_pcm_close hasn't really released the device at
  407.           the time it returns, probe if the device is available in loop for 1s.
  408.           We cannot use blocking mode since the we would wait indefinitely when
  409.           switching from a dmx device to surround51. */
  410.         for( i = 10; i >= 0; i-- )
  411.         {
  412.             if ( ( i_snd_rc = snd_pcm_open( &p_sys->p_snd_pcm, psz_device,
  413.                    SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK ) ) == -EBUSY )
  414.             {
  415.                 if( i ) msleep( 100000 /* 100ms */ );
  416.                 else
  417.                 {
  418.                     msg_Err( p_aout, "audio device: %s is already in use",
  419.                               psz_device );
  420.                     dialog_Fatal( p_aout, _("Audio output failed"),
  421.                                     _("The audio device "%s" is already in use."),
  422.                                     psz_device );
  423.                 }
  424.                 continue;
  425.             }
  426.             break;
  427.         }
  428.         if( i_snd_rc < 0 )
  429.         {
  430.             msg_Err( p_aout, "cannot open ALSA device `%s' (%s)",
  431.                              psz_device, snd_strerror( i_snd_rc ) );
  432.             dialog_Fatal( p_aout, _("Audio output failed"),
  433.                             _("VLC could not open the ALSA device "%s" (%s)."),
  434.                             psz_device, snd_strerror( i_snd_rc ) );
  435.             free( p_sys );
  436.             free( psz_device );
  437.             return VLC_EGENERIC;
  438.         }
  439.         /* We want blocking mode */
  440.         snd_pcm_nonblock( p_sys->p_snd_pcm, 0 );
  441.         i_buffer_size = ALSA_DEFAULT_BUFFER_SIZE;
  442.         i_channels = aout_FormatNbChannels( &p_aout->output.output );
  443.         p_aout->output.i_nb_samples = i_period_size = ALSA_DEFAULT_PERIOD_SIZE;
  444.         aout_VolumeSoftInit( p_aout );
  445.     }
  446.     /* Free psz_device so that all the remaining data is stack-allocated */
  447.     free( psz_device );
  448.     p_aout->output.pf_play = Play;
  449.     snd_pcm_hw_params_alloca(&p_hw);
  450.     snd_pcm_sw_params_alloca(&p_sw);
  451.     /* Due to some bugs in alsa with some drivers, we need to retry in s16l
  452.        if snd_pcm_hw_params fails in fl32 */
  453.     while ( b_retry )
  454.     {
  455.         b_retry = false;
  456.         /* Get Initial hardware parameters */
  457.         if ( ( i_snd_rc = snd_pcm_hw_params_any( p_sys->p_snd_pcm, p_hw ) ) < 0 )
  458.         {
  459.             msg_Err( p_aout, "unable to retrieve initial hardware parameters (%s)",
  460.                          snd_strerror( i_snd_rc ) );
  461.             goto error;
  462.         }
  463.         /* Set format. */
  464.         if ( ( i_snd_rc = snd_pcm_hw_params_set_format( p_sys->p_snd_pcm, p_hw,
  465.                                                     i_snd_pcm_format ) ) < 0 )
  466.         {
  467.             if( i_snd_pcm_format != SND_PCM_FORMAT_S16 )
  468.             {
  469.                 i_snd_pcm_format = SND_PCM_FORMAT_S16;
  470.                 i_snd_rc = snd_pcm_hw_params_set_format( p_sys->p_snd_pcm,
  471.                                                      p_hw, i_snd_pcm_format );
  472.             }
  473.             if ( i_snd_rc < 0 )
  474.             {
  475.                 msg_Err( p_aout, "unable to set stream sample size and "
  476.                      "word order (%s)", snd_strerror( i_snd_rc ) );
  477.                 goto error;
  478.             }
  479.         }
  480.         if( i_vlc_pcm_format != VLC_FOURCC('s','p','d','i') )
  481.         switch( i_snd_pcm_format )
  482.         {
  483.         case SND_PCM_FORMAT_FLOAT:
  484.             i_vlc_pcm_format = VLC_FOURCC('f','l','3','2');
  485.             break;
  486.         case SND_PCM_FORMAT_S16:
  487.             i_vlc_pcm_format = AOUT_FMT_S16_NE;
  488.             break;
  489.         }
  490.         p_aout->output.output.i_format = i_vlc_pcm_format;
  491.         if ( ( i_snd_rc = snd_pcm_hw_params_set_access( p_sys->p_snd_pcm, p_hw,
  492.                                     SND_PCM_ACCESS_RW_INTERLEAVED ) ) < 0 )
  493.         {
  494.             msg_Err( p_aout, "unable to set interleaved stream format (%s)",
  495.                              snd_strerror( i_snd_rc ) );
  496.             goto error;
  497.         }
  498.         /* Set channels. */
  499.         if ( ( i_snd_rc = snd_pcm_hw_params_set_channels( p_sys->p_snd_pcm, p_hw,
  500.                                                       i_channels ) ) < 0 )
  501.         {
  502.             msg_Err( p_aout, "unable to set number of output channels (%s)",
  503.                              snd_strerror( i_snd_rc ) );
  504.             goto error;
  505.         }
  506.         /* Set rate. */
  507.         i_old_rate = p_aout->output.output.i_rate;
  508. #ifdef HAVE_ALSA_NEW_API
  509.         i_snd_rc = snd_pcm_hw_params_set_rate_near( p_sys->p_snd_pcm, p_hw,
  510.                                                 &p_aout->output.output.i_rate,
  511.                                                 NULL );
  512. #else
  513.         i_snd_rc = snd_pcm_hw_params_set_rate_near( p_sys->p_snd_pcm, p_hw,
  514.                                                 p_aout->output.output.i_rate,
  515.                                                 NULL );
  516. #endif
  517.         if( i_snd_rc < 0 || p_aout->output.output.i_rate != i_old_rate )
  518.         {
  519.             msg_Warn( p_aout, "The rate %d Hz is not supported by your " 
  520.                 "hardware. Using %d Hz instead.n", i_old_rate, 
  521.                 p_aout->output.output.i_rate );
  522.         }
  523.         /* Set period size. */
  524. #ifdef HAVE_ALSA_NEW_API
  525.         if ( ( i_snd_rc = snd_pcm_hw_params_set_period_size_near( p_sys->p_snd_pcm,
  526.                                     p_hw, &i_period_size, NULL ) ) < 0 )
  527. #else
  528.         if ( ( i_snd_rc = snd_pcm_hw_params_set_period_size_near( p_sys->p_snd_pcm,
  529.                                     p_hw, i_period_size, NULL ) ) < 0 )
  530. #endif
  531.         {
  532.             msg_Err( p_aout, "unable to set period size (%s)",
  533.                          snd_strerror( i_snd_rc ) );
  534.             goto error;
  535.         }
  536.         p_aout->output.i_nb_samples = i_period_size;
  537. /* Set buffer size. */
  538. #ifdef HAVE_ALSA_NEW_API
  539.         if ( ( i_snd_rc = snd_pcm_hw_params_set_buffer_size_near( p_sys->p_snd_pcm,
  540.                                     p_hw, &i_buffer_size ) ) < 0 )
  541. #else
  542.         if ( ( i_snd_rc = snd_pcm_hw_params_set_buffer_size_near( p_sys->p_snd_pcm,
  543.                                     p_hw, i_buffer_size ) ) < 0 )
  544. #endif
  545.         {
  546.             msg_Err( p_aout, "unable to set buffer size (%s)",
  547.                          snd_strerror( i_snd_rc ) );
  548.             goto error;
  549.         }
  550.         /* Commit hardware parameters. */
  551.         if ( ( i_snd_rc = snd_pcm_hw_params( p_sys->p_snd_pcm, p_hw ) ) < 0 )
  552.         {
  553.             if ( b_retry == false &&
  554.                                 i_snd_pcm_format == SND_PCM_FORMAT_FLOAT)
  555.             {
  556.                 b_retry = true;
  557.                 i_snd_pcm_format = SND_PCM_FORMAT_S16;
  558.                 p_aout->output.output.i_format = AOUT_FMT_S16_NE;
  559.                 msg_Warn( p_aout, "unable to commit hardware configuration "
  560.                                   "with fl32 samples. Retrying with s16l (%s)",                                     snd_strerror( i_snd_rc ) );
  561.             }
  562.             else
  563.             {
  564.                 msg_Err( p_aout, "unable to commit hardware configuration (%s)",
  565.                          snd_strerror( i_snd_rc ) );
  566.                 goto error;
  567.             }
  568.         }
  569.     }
  570. #ifdef HAVE_ALSA_NEW_API
  571.     if( ( i_snd_rc = snd_pcm_hw_params_get_period_time( p_hw,
  572.                                     &p_sys->i_period_time, NULL ) ) < 0 )
  573. #else
  574.     if( ( p_sys->i_period_time =
  575.                   (int)snd_pcm_hw_params_get_period_time( p_hw, NULL ) ) < 0 )
  576. #endif
  577.     {
  578.         msg_Err( p_aout, "unable to get period time (%s)",
  579.                          snd_strerror( i_snd_rc ) );
  580.         goto error;
  581.     }
  582.     /* Get Initial software parameters */
  583.     snd_pcm_sw_params_current( p_sys->p_snd_pcm, p_sw );
  584.     i_snd_rc = snd_pcm_sw_params_set_sleep_min( p_sys->p_snd_pcm, p_sw, 0 );
  585.     i_snd_rc = snd_pcm_sw_params_set_avail_min( p_sys->p_snd_pcm, p_sw,
  586.                                                 p_aout->output.i_nb_samples );
  587.     /* start playing when one period has been written */
  588.     i_snd_rc = snd_pcm_sw_params_set_start_threshold( p_sys->p_snd_pcm, p_sw,
  589.                                                       ALSA_DEFAULT_PERIOD_SIZE);
  590.     if( i_snd_rc < 0 )
  591.     {
  592.         msg_Err( p_aout, "unable to set start threshold (%s)",
  593.                           snd_strerror( i_snd_rc ) );
  594.         goto error;
  595.     }
  596.     /* Commit software parameters. */
  597.     if ( snd_pcm_sw_params( p_sys->p_snd_pcm, p_sw ) < 0 )
  598.     {
  599.         msg_Err( p_aout, "unable to set software configuration" );
  600.         goto error;
  601.     }
  602. #ifdef ALSA_DEBUG
  603.     snd_output_printf( p_sys->p_snd_stderr, "nALSA hardware setup:nn" );
  604.     snd_pcm_dump_hw_setup( p_sys->p_snd_pcm, p_sys->p_snd_stderr );
  605.     snd_output_printf( p_sys->p_snd_stderr, "nALSA software setup:nn" );
  606.     snd_pcm_dump_sw_setup( p_sys->p_snd_pcm, p_sys->p_snd_stderr );
  607.     snd_output_printf( p_sys->p_snd_stderr, "n" );
  608. #endif
  609.     /* Create ALSA thread and wait for its readiness. */
  610.     if( vlc_thread_create( p_aout, "aout", ALSAThread,
  611.                            VLC_THREAD_PRIORITY_OUTPUT ) )
  612.     {
  613.         msg_Err( p_aout, "cannot create ALSA thread (%m)" );
  614.         goto error;
  615.     }
  616.     return 0;
  617. error:
  618.     snd_pcm_close( p_sys->p_snd_pcm );
  619. #ifdef ALSA_DEBUG
  620.     snd_output_close( p_sys->p_snd_stderr );
  621. #endif
  622.     free( p_sys );
  623.     return VLC_EGENERIC;
  624. }
  625. /*****************************************************************************
  626.  * Play: nothing to do
  627.  *****************************************************************************/
  628. static void Play( aout_instance_t *p_aout )
  629. {
  630.     if( !p_aout->output.p_sys->b_playing )
  631.     {
  632.         p_aout->output.p_sys->b_playing = 1;
  633.         /* get the playing date of the first aout buffer */
  634.         p_aout->output.p_sys->start_date =
  635.             aout_FifoFirstDate( p_aout, &p_aout->output.fifo );
  636.         /* wake up the audio output thread */
  637.         vlc_mutex_lock( &p_aout->output.p_sys->lock );
  638.         vlc_cond_signal( &p_aout->output.p_sys->wait );
  639.         vlc_mutex_unlock( &p_aout->output.p_sys->lock );
  640.     }
  641. }
  642. /*****************************************************************************
  643.  * Close: close the ALSA device
  644.  *****************************************************************************/
  645. static void Close( vlc_object_t *p_this )
  646. {
  647.     aout_instance_t *p_aout = (aout_instance_t *)p_this;
  648.     struct aout_sys_t * p_sys = p_aout->output.p_sys;
  649.     int i_snd_rc;
  650.     /* Make sure that the thread will stop once it is waken up */
  651.     vlc_object_kill( p_aout );
  652.     /* make sure the audio output thread is waken up */
  653.     vlc_mutex_lock( &p_aout->output.p_sys->lock );
  654.     vlc_cond_signal( &p_aout->output.p_sys->wait );
  655.     vlc_mutex_unlock( &p_aout->output.p_sys->lock );
  656.     /* */
  657.     vlc_thread_join( p_aout );
  658.     p_aout->b_die = false;
  659.     i_snd_rc = snd_pcm_close( p_sys->p_snd_pcm );
  660.     if( i_snd_rc > 0 )
  661.     {
  662.         msg_Err( p_aout, "failed closing ALSA device (%s)",
  663.                          snd_strerror( i_snd_rc ) );
  664.     }
  665. #ifdef ALSA_DEBUG
  666.     snd_output_close( p_sys->p_snd_stderr );
  667. #endif
  668.     free( p_sys );
  669. }
  670. /*****************************************************************************
  671.  * ALSAThread: asynchronous thread used to DMA the data to the device
  672.  *****************************************************************************/
  673. static void* ALSAThread( vlc_object_t* p_this )
  674. {
  675.     aout_instance_t * p_aout = (aout_instance_t*)p_this;
  676.     struct aout_sys_t * p_sys = p_aout->output.p_sys;
  677.     int canc = vlc_savecancel ();
  678.     p_sys->p_status = (snd_pcm_status_t *)malloc(snd_pcm_status_sizeof());
  679.     /* Wait for the exact time to start playing (avoids resampling) */
  680.     vlc_mutex_lock( &p_sys->lock );
  681.     while( !p_sys->start_date && vlc_object_alive (p_aout) )
  682.         vlc_cond_wait( &p_sys->wait, &p_sys->lock );
  683.     vlc_mutex_unlock( &p_sys->lock );
  684.     if( !vlc_object_alive (p_aout) )
  685.      goto cleanup;
  686.     mwait( p_sys->start_date - AOUT_PTS_TOLERANCE / 4 );
  687.     while ( vlc_object_alive (p_aout) )
  688.     {
  689.         ALSAFill( p_aout );
  690.     }
  691. cleanup:
  692.     snd_pcm_drop( p_sys->p_snd_pcm );
  693.     free( p_aout->output.p_sys->p_status );
  694.     vlc_restorecancel (canc);
  695.     return NULL;
  696. }
  697. /*****************************************************************************
  698.  * ALSAFill: function used to fill the ALSA buffer as much as possible
  699.  *****************************************************************************/
  700. static void ALSAFill( aout_instance_t * p_aout )
  701. {
  702.     struct aout_sys_t * p_sys = p_aout->output.p_sys;
  703.     aout_buffer_t * p_buffer;
  704.     snd_pcm_status_t * p_status = p_sys->p_status;
  705.     int i_snd_rc;
  706.     mtime_t next_date;
  707.     /* Fill in the buffer until space or audio output buffer shortage */
  708.     /* Get the status */
  709.     i_snd_rc = snd_pcm_status( p_sys->p_snd_pcm, p_status );
  710.     if( i_snd_rc < 0 )
  711.     {
  712.         msg_Err( p_aout, "cannot get device status" );
  713.         goto error;
  714.     }
  715.     /* Handle buffer underruns and get the status again */
  716.     if( snd_pcm_status_get_state( p_status ) == SND_PCM_STATE_XRUN )
  717.     {
  718.         /* Prepare the device */
  719.         i_snd_rc = snd_pcm_prepare( p_sys->p_snd_pcm );
  720.         if( i_snd_rc )
  721.         {
  722.             msg_Err( p_aout, "cannot recover from buffer underrun" );
  723.             goto error;
  724.         }
  725.         msg_Dbg( p_aout, "recovered from buffer underrun" );
  726.         /* Get the new status */
  727.         i_snd_rc = snd_pcm_status( p_sys->p_snd_pcm, p_status );
  728.         if( i_snd_rc < 0 )
  729.         {
  730.             msg_Err( p_aout, "cannot get device status after recovery" );
  731.             goto error;
  732.         }
  733.         /* Underrun, try to recover as quickly as possible */
  734.         next_date = mdate();
  735.     }
  736.     else
  737.     {
  738.         /* Here the device should be in RUNNING state, p_status is valid. */
  739.         snd_pcm_sframes_t delay = snd_pcm_status_get_delay( p_status );
  740.         if( delay == 0 ) /* workaround buggy alsa drivers */
  741.             if( snd_pcm_delay( p_sys->p_snd_pcm, &delay ) < 0 )
  742.                 delay = 0; /* FIXME: use a positive minimal delay */
  743.         int i_bytes = snd_pcm_frames_to_bytes( p_sys->p_snd_pcm, delay );
  744.         next_date = mdate() + ( (mtime_t)i_bytes * 1000000
  745.                 / p_aout->output.output.i_bytes_per_frame
  746.                 / p_aout->output.output.i_rate
  747.                 * p_aout->output.output.i_frame_length );
  748. #ifdef ALSA_DEBUG
  749.         snd_pcm_state_t state = snd_pcm_status_get_state( p_status );
  750.         if( state != SND_PCM_STATE_RUNNING )
  751.             msg_Err( p_aout, "pcm status (%d) != RUNNING", state );
  752.         msg_Dbg( p_aout, "Delay is %ld frames (%d bytes)", delay, i_bytes );
  753.         msg_Dbg( p_aout, "Bytes per frame: %d", p_aout->output.output.i_bytes_per_frame );
  754.         msg_Dbg( p_aout, "Rate: %d", p_aout->output.output.i_rate );
  755.         msg_Dbg( p_aout, "Frame length: %d", p_aout->output.output.i_frame_length );
  756.         msg_Dbg( p_aout, "Next date is in %d microseconds", (int)(next_date - mdate()) );
  757. #endif
  758.     }
  759.     p_buffer = aout_OutputNextBuffer( p_aout, next_date,
  760.            (p_aout->output.output.i_format ==  VLC_FOURCC('s','p','d','i')) );
  761.     /* Audio output buffer shortage -> stop the fill process and wait */
  762.     if( p_buffer == NULL )
  763.         goto error;
  764.     for (;;)
  765.     {
  766.         i_snd_rc = snd_pcm_writei( p_sys->p_snd_pcm, p_buffer->p_buffer,
  767.                                    p_buffer->i_nb_samples );
  768.         if( i_snd_rc != -ESTRPIPE )
  769.             break;
  770.         /* a suspend event occurred
  771.          * (stream is suspended and waiting for an application recovery) */
  772.         msg_Dbg( p_aout, "entering in suspend mode, trying to resume..." );
  773.         while( vlc_object_alive (p_aout) && vlc_object_alive (p_aout->p_libvlc) &&
  774.                ( i_snd_rc = snd_pcm_resume( p_sys->p_snd_pcm ) ) == -EAGAIN )
  775.         {
  776.             msleep( 1000000 );
  777.         }
  778.         if( i_snd_rc < 0 )
  779.             /* Device does not supprot resuming, restart it */
  780.             i_snd_rc = snd_pcm_prepare( p_sys->p_snd_pcm );
  781.     }
  782.     if( i_snd_rc < 0 )
  783.         msg_Err( p_aout, "cannot write: %s", snd_strerror( i_snd_rc ) );
  784.     aout_BufferFree( p_buffer );
  785.     return;
  786. error:
  787.     if( i_snd_rc < 0 )
  788.         msg_Err( p_aout, "ALSA error: %s", snd_strerror( i_snd_rc ) );
  789.     msleep( p_sys->i_period_time >> 1 );
  790. }
  791. static void GetDevicesForCard( module_config_t *p_item, int i_card );
  792. static void GetDevices( module_config_t *p_item );
  793. /*****************************************************************************
  794.  * config variable callback
  795.  *****************************************************************************/
  796. static int FindDevicesCallback( vlc_object_t *p_this, char const *psz_name,
  797.                                vlc_value_t newval, vlc_value_t oldval, void *p_unused )
  798. {
  799.     module_config_t *p_item;
  800.     int i;
  801.     (void)newval;
  802.     (void)oldval;
  803.     (void)p_unused;
  804.     p_item = config_FindConfig( p_this, psz_name );
  805.     if( !p_item ) return VLC_SUCCESS;
  806.     /* Clear-up the current list */
  807.     if( p_item->i_list )
  808.     {
  809.         /* Keep the first entrie */
  810.         for( i = 1; i < p_item->i_list; i++ )
  811.         {
  812.             free( (char *)p_item->ppsz_list[i] );
  813.             free( (char *)p_item->ppsz_list_text[i] );
  814.         }
  815.         /* TODO: Remove when no more needed */
  816.         p_item->ppsz_list[i] = NULL;
  817.         p_item->ppsz_list_text[i] = NULL;
  818.     }
  819.     p_item->i_list = 1;
  820.     GetDevices( p_item );
  821.     /* Signal change to the interface */
  822.     p_item->b_dirty = true;
  823.     return VLC_SUCCESS;
  824. }
  825. static void GetDevicesForCard( module_config_t *p_item, int i_card )
  826. {
  827.     int i_pcm_device = -1;
  828.     int i_err = 0;
  829.     snd_pcm_info_t *p_pcm_info;
  830.     snd_ctl_t *p_ctl;
  831.     char psz_dev[64];
  832.     char *psz_card_name;
  833.     sprintf( psz_dev, "hw:%i", i_card );
  834.     if( ( i_err = snd_ctl_open( &p_ctl, psz_dev, 0 ) ) < 0 )
  835.         return;
  836.     if( ( i_err = snd_card_get_name( i_card, &psz_card_name ) ) != 0)
  837.         psz_card_name = _("Unknown soundcard");
  838.     snd_pcm_info_alloca( &p_pcm_info );
  839.     for (;;)
  840.     {
  841.         char *psz_device, *psz_descr;
  842.         if( ( i_err = snd_ctl_pcm_next_device( p_ctl, &i_pcm_device ) ) < 0 )
  843.             i_pcm_device = -1;
  844.         if( i_pcm_device < 0 )
  845.             break;
  846.         snd_pcm_info_set_device( p_pcm_info, i_pcm_device );
  847.         snd_pcm_info_set_subdevice( p_pcm_info, 0 );
  848.         snd_pcm_info_set_stream( p_pcm_info, SND_PCM_STREAM_PLAYBACK );
  849.         if( ( i_err = snd_ctl_pcm_info( p_ctl, p_pcm_info ) ) < 0 )
  850.         {
  851.             if( i_err != -ENOENT )
  852.             {
  853.                 /*printf( "get_devices_for_card(): "
  854.                          "snd_ctl_pcm_info() "
  855.                          "failed (%d:%d): %s.n", i_card,
  856.                          i_pcm_device, snd_strerror( -i_err ) );*/
  857.             }
  858.             continue;
  859.         }
  860.         if( asprintf( &psz_device, "hw:%d,%d", i_card, i_pcm_device ) == -1 )
  861.             break;
  862.         if( asprintf( &psz_descr, "%s: %s (%s)", psz_card_name,
  863.                   snd_pcm_info_get_name(p_pcm_info), psz_device ) == -1 )
  864.         {
  865.             free( psz_device );
  866.             break;
  867.         }
  868.         p_item->ppsz_list =
  869.             (char **)realloc( p_item->ppsz_list,
  870.                               (p_item->i_list + 2) * sizeof(char *) );
  871.         p_item->ppsz_list_text =
  872.             (char **)realloc( p_item->ppsz_list_text,
  873.                               (p_item->i_list + 2) * sizeof(char *) );
  874.         p_item->ppsz_list[ p_item->i_list ] = psz_device;
  875.         p_item->ppsz_list_text[ p_item->i_list ] = psz_descr;
  876.         p_item->i_list++;
  877.         p_item->ppsz_list[ p_item->i_list ] = NULL;
  878.         p_item->ppsz_list_text[ p_item->i_list ] = NULL;
  879.     }
  880.     snd_ctl_close( p_ctl );
  881. }
  882. static void GetDevices( module_config_t *p_item )
  883. {
  884.     int i_card = -1;
  885.     int i_err = 0;
  886.     if( ( i_err = snd_card_next( &i_card ) ) != 0 )
  887.     {
  888.         /*printf( "snd_card_next() failed: %s", snd_strerror( -i_err ) );*/
  889.         return;
  890.     }
  891.     while( i_card > -1 )
  892.     {
  893.         GetDevicesForCard( p_item, i_card );
  894.         if( ( i_err = snd_card_next( &i_card ) ) != 0 )
  895.         {
  896.             /*printf( "snd_card_next() failed: %s", snd_strerror( -i_err ) );*/
  897.             break;
  898.         }
  899.     }
  900. }