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