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