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