]> git.sesse.net Git - vlc/blob - modules/audio_output/alsa.c
FSF address change.
[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 <errno.h>                                                 /* ENOMEM */
31 #include <string.h>                                            /* strerror() */
32 #include <stdlib.h>                            /* calloc(), malloc(), free() */
33
34 #include <vlc/vlc.h>
35
36 #include <vlc/aout.h>
37
38 #include "aout_internal.h"
39
40 /* ALSA part
41    Note: we use the new API which is available since 0.9.0beta10a. */
42 #define ALSA_PCM_NEW_HW_PARAMS_API
43 #define ALSA_PCM_NEW_SW_PARAMS_API
44 #include <alsa/asoundlib.h>
45
46 /*****************************************************************************
47  * aout_sys_t: ALSA audio output method descriptor
48  *****************************************************************************
49  * This structure is part of the audio output thread descriptor.
50  * It describes the ALSA specific properties of an audio device.
51  *****************************************************************************/
52 struct aout_sys_t
53 {
54     snd_pcm_t         * p_snd_pcm;
55     unsigned int                 i_period_time;
56
57 #ifdef ALSA_DEBUG
58     snd_output_t      * p_snd_stderr;
59 #endif
60
61     int b_playing;                                         /* playing status */
62     mtime_t start_date;
63
64     vlc_mutex_t lock;
65     vlc_cond_t  wait ;
66
67     snd_pcm_status_t *p_status;
68 };
69
70 #define A52_FRAME_NB 1536
71
72 /* These values are in frames.
73    To convert them to a number of bytes you have to multiply them by the
74    number of channel(s) (eg. 2 for stereo) and the size of a sample (eg.
75    2 for int16_t). */
76 #define ALSA_DEFAULT_PERIOD_SIZE        1024
77 #define ALSA_DEFAULT_BUFFER_SIZE        ( ALSA_DEFAULT_PERIOD_SIZE << 8 )
78 #define ALSA_SPDIF_PERIOD_SIZE          A52_FRAME_NB
79 #define ALSA_SPDIF_BUFFER_SIZE          ( ALSA_SPDIF_PERIOD_SIZE << 4 )
80 /* Why << 4 ? --Meuuh */
81 /* Why not ? --Bozo */
82 /* Right. --Meuuh */
83
84 #define DEFAULT_ALSA_DEVICE N_("default")
85
86 /*****************************************************************************
87  * Local prototypes
88  *****************************************************************************/
89 static int  Open         ( vlc_object_t * );
90 static void Close        ( vlc_object_t * );
91 static void Play         ( aout_instance_t * );
92 static int  ALSAThread   ( aout_instance_t * );
93 static void ALSAFill     ( aout_instance_t * );
94 static int FindDevicesCallback( vlc_object_t *p_this, char const *psz_name,
95                                 vlc_value_t newval, vlc_value_t oldval, void *p_unused );
96
97 /*****************************************************************************
98  * Module descriptor
99  *****************************************************************************/
100 static char *ppsz_devices[] = { "default" };
101 static char *ppsz_devices_text[] = { N_("Default") };
102 vlc_module_begin();
103     set_shortname( "ALSA" );
104     set_description( _("ALSA audio output") );
105     set_category( CAT_AUDIO );
106     set_subcategory( SUBCAT_AUDIO_AOUT );
107     add_string( "alsadev", DEFAULT_ALSA_DEVICE, aout_FindAndRestart,
108                 N_("ALSA Device Name"), NULL, VLC_FALSE );
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 = N_("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         free( p_sys );
326         return VLC_EGENERIC;
327     }
328
329     /* Choose the IEC device for S/PDIF output:
330        if the device is overriden by the user then it will be the one
331        otherwise we compute the default device based on the output format. */
332     if( AOUT_FMT_NON_LINEAR( &p_aout->output.output )
333         && !strcmp( psz_device, DEFAULT_ALSA_DEVICE ) )
334     {
335         snprintf( psz_default_iec_device, sizeof(psz_default_iec_device),
336                   "iec958:AES0=0x%x,AES1=0x%x,AES2=0x%x,AES3=0x%x",
337                   IEC958_AES0_CON_EMPHASIS_NONE | IEC958_AES0_NONAUDIO,
338                   IEC958_AES1_CON_ORIGINAL | IEC958_AES1_CON_PCM_CODER,
339                   0,
340                   ( p_aout->output.output.i_rate == 48000 ?
341                     IEC958_AES3_CON_FS_48000 :
342                     ( p_aout->output.output.i_rate == 44100 ?
343                       IEC958_AES3_CON_FS_44100 : IEC958_AES3_CON_FS_32000 ) ) );
344         psz_iec_device = psz_default_iec_device;
345     }
346     else if( AOUT_FMT_NON_LINEAR( &p_aout->output.output ) )
347     {
348         psz_iec_device = psz_device;
349     }
350     else
351     {
352         psz_iec_device = NULL;
353     }
354
355     /* Choose the linear PCM format (read the comment above about FPU
356        and float32) */
357     if( p_aout->p_libvlc->i_cpu & CPU_CAPABILITY_FPU )
358     {
359         i_vlc_pcm_format = VLC_FOURCC('f','l','3','2');
360         i_snd_pcm_format = SND_PCM_FORMAT_FLOAT;
361     }
362     else
363     {
364         i_vlc_pcm_format = AOUT_FMT_S16_NE;
365         i_snd_pcm_format = SND_PCM_FORMAT_S16;
366     }
367
368     /* If the variable doesn't exist then it's the first time we're called
369        and we have to probe the available audio formats and channels */
370     if ( var_Type( p_aout, "audio-device" ) == 0 )
371     {
372         Probe( p_aout, psz_device, psz_iec_device, &i_snd_pcm_format );
373     }
374
375     if ( var_Get( p_aout, "audio-device", &val ) < 0 )
376     {
377         free( p_sys );
378         free( psz_device );
379         return VLC_EGENERIC;
380     }
381
382     p_aout->output.output.i_format = i_vlc_pcm_format;
383     if ( val.i_int == AOUT_VAR_5_1 )
384     {
385         p_aout->output.output.i_physical_channels
386             = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER
387                | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT
388                | AOUT_CHAN_LFE;
389         free( psz_device );
390         psz_device = strdup( "surround51" );
391     }
392     else if ( val.i_int == AOUT_VAR_2F2R )
393     {
394         p_aout->output.output.i_physical_channels
395             = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT
396                | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT;
397         free( psz_device );
398         psz_device = strdup( "surround40" );
399     }
400     else if ( val.i_int == AOUT_VAR_STEREO )
401     {
402         p_aout->output.output.i_physical_channels
403             = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT;
404     }
405     else if ( val.i_int == AOUT_VAR_MONO )
406     {
407         p_aout->output.output.i_physical_channels = AOUT_CHAN_CENTER;
408     }
409     else if( val.i_int != AOUT_VAR_SPDIF )
410     {
411         /* This should not happen ! */
412         msg_Err( p_aout, "internal: can't find audio-device (%i)", val.i_int );
413         free( p_sys );
414         free( psz_device );
415         return VLC_EGENERIC;
416     }
417
418 #ifdef ALSA_DEBUG
419     snd_output_stdio_attach( &p_sys->p_snd_stderr, stderr, 0 );
420 #endif
421
422     /* Open the device */
423     if ( val.i_int == AOUT_VAR_SPDIF )
424     {
425         if ( ( i_snd_rc = snd_pcm_open( &p_sys->p_snd_pcm, psz_iec_device,
426                             SND_PCM_STREAM_PLAYBACK, 0 ) ) < 0 )
427         {
428             msg_Err( p_aout, "cannot open ALSA device `%s' (%s)",
429                              psz_iec_device, snd_strerror( i_snd_rc ) );
430             free( p_sys );
431             free( psz_device );
432             return VLC_EGENERIC;
433         }
434         i_buffer_size = ALSA_SPDIF_BUFFER_SIZE;
435         i_snd_pcm_format = SND_PCM_FORMAT_S16;
436         i_channels = 2;
437
438         i_vlc_pcm_format = VLC_FOURCC('s','p','d','i');
439         p_aout->output.i_nb_samples = i_period_size = ALSA_SPDIF_PERIOD_SIZE;
440         p_aout->output.output.i_bytes_per_frame = AOUT_SPDIF_SIZE;
441         p_aout->output.output.i_frame_length = A52_FRAME_NB;
442
443         aout_VolumeNoneInit( p_aout );
444     }
445     else
446     {
447         int i;
448
449         msg_Dbg( p_aout, "opening ALSA device `%s'", psz_device );
450
451         /* Since it seems snd_pcm_close hasen't really released the device at
452           the time it returns, probe if the device is available in loop for 1s.
453           We cannot use blocking mode since the we would wait indefinitely when
454           switching from a dmx device to surround51. */
455
456         for( i = 10; i >= 0; i-- )
457         {
458             if ( ( i_snd_rc = snd_pcm_open( &p_sys->p_snd_pcm, psz_device,
459                    SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK ) ) == -EBUSY )
460             {
461                 if( i ) msleep( 100000 /* 100ms */ );
462                 else msg_Err( p_aout, "audio device: %s is already in use",
463                               psz_device );
464                 continue;
465             }
466             break;
467         }
468         if( i_snd_rc < 0 )
469         {
470             msg_Err( p_aout, "cannot open ALSA device `%s' (%s)",
471                              psz_device, snd_strerror( i_snd_rc ) );
472             free( p_sys );
473             free( psz_device );
474             return VLC_EGENERIC;
475         }
476
477         /* We want blocking mode */
478         snd_pcm_nonblock( p_sys->p_snd_pcm, 0 );
479
480         i_buffer_size = ALSA_DEFAULT_BUFFER_SIZE;
481         i_channels = aout_FormatNbChannels( &p_aout->output.output );
482
483         p_aout->output.i_nb_samples = i_period_size = ALSA_DEFAULT_PERIOD_SIZE;
484
485         aout_VolumeSoftInit( p_aout );
486     }
487
488     /* Free psz_device so that all the remaining data is stack-allocated */
489     free( psz_device );
490
491     p_aout->output.pf_play = Play;
492
493     snd_pcm_hw_params_alloca(&p_hw);
494     snd_pcm_sw_params_alloca(&p_sw);
495
496     /* Due to some bugs in alsa with some drivers, we need to retry in s16l
497        if snd_pcm_hw_params fails in fl32 */
498     while ( b_retry )
499     {
500         b_retry = VLC_FALSE;
501
502         /* Get Initial hardware parameters */
503         if ( ( i_snd_rc = snd_pcm_hw_params_any( p_sys->p_snd_pcm, p_hw ) ) < 0 )
504         {
505             msg_Err( p_aout, "unable to retrieve initial hardware parameters (%s)",
506                          snd_strerror( i_snd_rc ) );
507             goto error;
508         }
509
510         /* Set format. */
511         if ( ( i_snd_rc = snd_pcm_hw_params_set_format( p_sys->p_snd_pcm, p_hw,
512                                                     i_snd_pcm_format ) ) < 0 )
513         {
514             if( i_snd_pcm_format != SND_PCM_FORMAT_S16 )
515             {
516                 i_snd_pcm_format = SND_PCM_FORMAT_S16;
517                 i_snd_rc = snd_pcm_hw_params_set_format( p_sys->p_snd_pcm,
518                                                      p_hw, i_snd_pcm_format );
519             }
520             if ( i_snd_rc < 0 )
521             {
522                 msg_Err( p_aout, "unable to set stream sample size and "
523                      "word order (%s)", snd_strerror( i_snd_rc ) );
524                 goto error;
525             }
526         }
527         if( i_vlc_pcm_format != VLC_FOURCC('s','p','d','i') )
528         switch( i_snd_pcm_format )
529         {
530         case SND_PCM_FORMAT_FLOAT:
531             i_vlc_pcm_format = VLC_FOURCC('f','l','3','2');
532             break;
533         case SND_PCM_FORMAT_S16:
534             i_vlc_pcm_format = AOUT_FMT_S16_NE;
535             break;
536         }
537         p_aout->output.output.i_format = i_vlc_pcm_format;
538
539         if ( ( i_snd_rc = snd_pcm_hw_params_set_access( p_sys->p_snd_pcm, p_hw,
540                                     SND_PCM_ACCESS_RW_INTERLEAVED ) ) < 0 )
541         {
542             msg_Err( p_aout, "unable to set interleaved stream format (%s)",
543                              snd_strerror( i_snd_rc ) );
544             goto error;
545         }
546
547         /* Set channels. */
548         if ( ( i_snd_rc = snd_pcm_hw_params_set_channels( p_sys->p_snd_pcm, p_hw,
549                                                       i_channels ) ) < 0 )
550         {
551             msg_Err( p_aout, "unable to set number of output channels (%s)",
552                              snd_strerror( i_snd_rc ) );
553             goto error;
554         }
555
556         /* Set rate. */
557         i_old_rate = p_aout->output.output.i_rate;
558 #ifdef HAVE_ALSA_NEW_API
559         i_snd_rc = snd_pcm_hw_params_set_rate_near( p_sys->p_snd_pcm, p_hw,
560                                                 &p_aout->output.output.i_rate,
561                                                 NULL );
562 #else
563         i_snd_rc = snd_pcm_hw_params_set_rate_near( p_sys->p_snd_pcm, p_hw,
564                                                 p_aout->output.output.i_rate,
565                                                 NULL );
566 #endif
567         if( i_snd_rc < 0 || p_aout->output.output.i_rate != i_old_rate )
568         {
569             msg_Warn( p_aout, "The rate %d Hz is not supported by your hardware. "
570                   "Using %d Hz instead.\n", i_old_rate,
571                   p_aout->output.output.i_rate );
572         }
573
574         /* Set buffer size. */
575 #ifdef HAVE_ALSA_NEW_API
576         if ( ( i_snd_rc = snd_pcm_hw_params_set_buffer_size_near( p_sys->p_snd_pcm,
577                                     p_hw, &i_buffer_size ) ) < 0 )
578 #else
579         if ( ( i_snd_rc = snd_pcm_hw_params_set_buffer_size_near( p_sys->p_snd_pcm,
580                                     p_hw, i_buffer_size ) ) < 0 )
581 #endif
582         {
583             msg_Err( p_aout, "unable to set buffer size (%s)",
584                          snd_strerror( i_snd_rc ) );
585             goto error;
586         }
587
588         /* Set period size. */
589 #ifdef HAVE_ALSA_NEW_API
590         if ( ( i_snd_rc = snd_pcm_hw_params_set_period_size_near( p_sys->p_snd_pcm,
591                                     p_hw, &i_period_size, NULL ) ) < 0 )
592 #else
593         if ( ( i_snd_rc = snd_pcm_hw_params_set_period_size_near( p_sys->p_snd_pcm,
594                                     p_hw, i_period_size, NULL ) ) < 0 )
595 #endif
596         {
597             msg_Err( p_aout, "unable to set period size (%s)",
598                          snd_strerror( i_snd_rc ) );
599             goto error;
600         }
601         p_aout->output.i_nb_samples = i_period_size;
602
603         /* Commit hardware parameters. */
604         if ( ( i_snd_rc = snd_pcm_hw_params( p_sys->p_snd_pcm, p_hw ) ) < 0 )
605         {
606             if ( b_retry == VLC_FALSE &&
607                                 i_snd_pcm_format == SND_PCM_FORMAT_FLOAT)
608             {
609                 b_retry = VLC_TRUE;
610                 i_snd_pcm_format = SND_PCM_FORMAT_S16;
611                 p_aout->output.output.i_format = AOUT_FMT_S16_NE;
612                 msg_Warn( p_aout, "unable to commit hardware configuration "
613                                   "with fl32 samples. Retrying with s16l (%s)",                                     snd_strerror( i_snd_rc ) );
614             }
615             else
616             {
617                 msg_Err( p_aout, "unable to commit hardware configuration (%s)",
618                          snd_strerror( i_snd_rc ) );
619                 goto error;
620             }
621         }
622     }
623
624 #ifdef HAVE_ALSA_NEW_API
625     if( ( i_snd_rc = snd_pcm_hw_params_get_period_time( p_hw,
626                                     &p_sys->i_period_time, NULL ) ) < 0 )
627 #else
628     if( ( p_sys->i_period_time =
629                   (int)snd_pcm_hw_params_get_period_time( p_hw, NULL ) ) < 0 )
630 #endif
631     {
632         msg_Err( p_aout, "unable to get period time (%s)",
633                          snd_strerror( i_snd_rc ) );
634         goto error;
635     }
636
637     /* Get Initial software parameters */
638     snd_pcm_sw_params_current( p_sys->p_snd_pcm, p_sw );
639
640     i_snd_rc = snd_pcm_sw_params_set_sleep_min( p_sys->p_snd_pcm, p_sw, 0 );
641
642     i_snd_rc = snd_pcm_sw_params_set_avail_min( p_sys->p_snd_pcm, p_sw,
643                                                 p_aout->output.i_nb_samples );
644
645     /* Commit software parameters. */
646     if ( snd_pcm_sw_params( p_sys->p_snd_pcm, p_sw ) < 0 )
647     {
648         msg_Err( p_aout, "unable to set software configuration" );
649         goto error;
650     }
651
652 #ifdef ALSA_DEBUG
653     snd_output_printf( p_sys->p_snd_stderr, "\nALSA hardware setup:\n\n" );
654     snd_pcm_dump_hw_setup( p_sys->p_snd_pcm, p_sys->p_snd_stderr );
655     snd_output_printf( p_sys->p_snd_stderr, "\nALSA software setup:\n\n" );
656     snd_pcm_dump_sw_setup( p_sys->p_snd_pcm, p_sys->p_snd_stderr );
657     snd_output_printf( p_sys->p_snd_stderr, "\n" );
658 #endif
659
660     /* Create ALSA thread and wait for its readiness. */
661     if( vlc_thread_create( p_aout, "aout", ALSAThread,
662                            VLC_THREAD_PRIORITY_OUTPUT, VLC_FALSE ) )
663     {
664         msg_Err( p_aout, "cannot create ALSA thread (%s)", strerror(errno) );
665         goto error;
666     }
667
668     return 0;
669
670 error:
671     snd_pcm_close( p_sys->p_snd_pcm );
672 #ifdef ALSA_DEBUG
673     snd_output_close( p_sys->p_snd_stderr );
674 #endif
675     free( p_sys );
676     return VLC_EGENERIC;
677 }
678
679 /*****************************************************************************
680  * Play: nothing to do
681  *****************************************************************************/
682 static void Play( aout_instance_t *p_aout )
683 {
684     if( !p_aout->output.p_sys->b_playing )
685     {
686         p_aout->output.p_sys->b_playing = 1;
687
688         /* get the playing date of the first aout buffer */
689         p_aout->output.p_sys->start_date =
690             aout_FifoFirstDate( p_aout, &p_aout->output.fifo );
691
692         /* wake up the audio output thread */
693         vlc_mutex_lock( &p_aout->output.p_sys->lock );
694         vlc_cond_signal( &p_aout->output.p_sys->wait );
695         vlc_mutex_unlock( &p_aout->output.p_sys->lock );
696     }
697 }
698
699 /*****************************************************************************
700  * Close: close the ALSA device
701  *****************************************************************************/
702 static void Close( vlc_object_t *p_this )
703 {
704     aout_instance_t *p_aout = (aout_instance_t *)p_this;
705     struct aout_sys_t * p_sys = p_aout->output.p_sys;
706     int i_snd_rc;
707
708     /* make sure the audio output thread is waken up */
709     vlc_mutex_lock( &p_aout->output.p_sys->lock );
710     vlc_cond_signal( &p_aout->output.p_sys->wait );
711     vlc_mutex_unlock( &p_aout->output.p_sys->lock );
712
713     p_aout->b_die = VLC_TRUE;
714     vlc_thread_join( p_aout );
715     p_aout->b_die = VLC_FALSE;
716
717     i_snd_rc = snd_pcm_close( p_sys->p_snd_pcm );
718
719     if( i_snd_rc > 0 )
720     {
721         msg_Err( p_aout, "failed closing ALSA device (%s)",
722                          snd_strerror( i_snd_rc ) );
723     }
724
725 #ifdef ALSA_DEBUG
726     snd_output_close( p_sys->p_snd_stderr );
727 #endif
728
729     free( p_sys );
730 }
731
732 /*****************************************************************************
733  * ALSAThread: asynchronous thread used to DMA the data to the device
734  *****************************************************************************/
735 static int ALSAThread( aout_instance_t * p_aout )
736 {
737     p_aout->output.p_sys->p_status =
738         (snd_pcm_status_t *)malloc(snd_pcm_status_sizeof());
739
740     /* Wait for the exact time to start playing (avoids resampling) */
741     vlc_mutex_lock( &p_aout->output.p_sys->lock );
742     if( !p_aout->output.p_sys->start_date )
743         vlc_cond_wait( &p_aout->output.p_sys->wait,
744                        &p_aout->output.p_sys->lock );
745     vlc_mutex_unlock( &p_aout->output.p_sys->lock );
746
747     mwait( p_aout->output.p_sys->start_date - AOUT_PTS_TOLERANCE / 4 );
748
749     while ( !p_aout->b_die )
750     {
751         ALSAFill( p_aout );
752     }
753
754     free( p_aout->output.p_sys->p_status );
755     return 0;
756 }
757
758 /*****************************************************************************
759  * ALSAFill: function used to fill the ALSA buffer as much as possible
760  *****************************************************************************/
761 static void ALSAFill( aout_instance_t * p_aout )
762 {
763     struct aout_sys_t * p_sys = p_aout->output.p_sys;
764
765     aout_buffer_t * p_buffer;
766     snd_pcm_status_t * p_status = p_sys->p_status;
767     snd_timestamp_t ts_next;
768     int i_snd_rc;
769     mtime_t next_date;
770
771     /* Fill in the buffer until space or audio output buffer shortage */
772     {
773         /* Get the status */
774         i_snd_rc = snd_pcm_status( p_sys->p_snd_pcm, p_status );
775         if( i_snd_rc < 0 )
776         {
777             msg_Err( p_aout, "unable to get the device's status (%s)",
778                              snd_strerror( i_snd_rc ) );
779
780             msleep( p_sys->i_period_time >> 1 );
781             return;
782         }
783
784         /* Handle buffer underruns and reget the status */
785         if( snd_pcm_status_get_state( p_status ) == SND_PCM_STATE_XRUN )
786         {
787             /* Prepare the device */
788             i_snd_rc = snd_pcm_prepare( p_sys->p_snd_pcm );
789
790             if( i_snd_rc == 0 )
791             {
792                 msg_Dbg( p_aout, "recovered from buffer underrun" );
793
794                 /* Reget 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, "unable to get the device's status after "
799                              "recovery (%s)", snd_strerror( i_snd_rc ) );
800
801                     msleep( p_sys->i_period_time >> 1 );
802                     return;
803                 }
804             }
805             else
806             {
807                 msg_Err( p_aout, "unable to recover from buffer underrun" );
808
809                 msleep( p_sys->i_period_time >> 1 );
810                 return;
811             }
812
813             /* Underrun, try to recover as quickly as possible */
814             next_date = mdate();
815         }
816         else
817         {
818             /* Here the device should be either in the RUNNING state.
819              * p_status is valid. */
820
821             snd_pcm_status_get_tstamp( p_status, &ts_next );
822             next_date = (mtime_t)ts_next.tv_sec * 1000000 + ts_next.tv_usec;
823             if( next_date )
824             {
825                 next_date += (mtime_t)snd_pcm_status_get_delay(p_status)
826                         * 1000000 / p_aout->output.output.i_rate;
827             }
828             else
829             {
830                 /* With screwed ALSA drivers the timestamp is always zero;
831                  * use another method then */
832                 snd_pcm_sframes_t delay;
833                 ssize_t i_bytes = 0;
834
835                 if( !snd_pcm_delay( p_sys->p_snd_pcm, &delay ) )
836                 {
837                     i_bytes = snd_pcm_frames_to_bytes(p_sys->p_snd_pcm, delay);
838                 }
839                 next_date = mdate() + (mtime_t)i_bytes * 1000000
840                         / p_aout->output.output.i_bytes_per_frame
841                         / p_aout->output.output.i_rate
842                         * p_aout->output.output.i_frame_length;
843             }
844         }
845
846         p_buffer = aout_OutputNextBuffer( p_aout, next_date,
847                         (p_aout->output.output.i_format ==
848                          VLC_FOURCC('s','p','d','i')) );
849
850         /* Audio output buffer shortage -> stop the fill process and wait */
851         if( p_buffer == NULL )
852         {
853             msleep( p_sys->i_period_time >> 1 );
854             return;
855         }
856
857         i_snd_rc = snd_pcm_writei( p_sys->p_snd_pcm, p_buffer->p_buffer,
858                                    p_buffer->i_nb_samples );
859
860         if( i_snd_rc < 0 )
861         {
862             msg_Err( p_aout, "write failed (%s)",
863                              snd_strerror( i_snd_rc ) );
864         }
865
866         aout_BufferFree( p_buffer );
867     }
868 }
869
870 static void GetDevicesForCard(module_config_t *p_item, int i_card);
871 static void GetDevices( module_config_t *p_item );
872
873 /*****************************************************************************
874  * config variable callback
875  *****************************************************************************/
876 static int FindDevicesCallback( vlc_object_t *p_this, char const *psz_name,
877                                vlc_value_t newval, vlc_value_t oldval, void *p_unused )
878 {
879     module_config_t *p_item;
880     int i;
881
882     p_item = config_FindConfig( p_this, psz_name );
883     if( !p_item ) return VLC_SUCCESS;
884
885     /* Clear-up the current list */
886     if( p_item->i_list )
887     {
888         /* Keep the first entrie */
889         for( i = 1; i < p_item->i_list; i++ )
890         {
891             free( p_item->ppsz_list[i] );
892             free( p_item->ppsz_list_text[i] );
893         }
894         /* TODO: Remove when no more needed */
895         p_item->ppsz_list[i] = NULL;
896         p_item->ppsz_list_text[i] = NULL;
897     }
898     p_item->i_list = 1;
899
900     GetDevices( p_item );
901
902     /* Signal change to the interface */
903     p_item->b_dirty = VLC_TRUE;
904
905     return VLC_SUCCESS;
906
907 }
908
909
910 static void GetDevicesForCard(module_config_t *p_item, int i_card)
911 {
912     int i_pcm_device = -1;
913     int i_err = 0;
914     snd_pcm_info_t *p_pcm_info;
915     snd_ctl_t *p_ctl;
916     char psz_dev[64];
917     char *psz_card_name;
918     
919     sprintf(psz_dev, "hw:%i", i_card);
920     
921     if (( i_err = snd_ctl_open(&p_ctl, psz_dev, 0)) < 0 )
922     {
923         return;
924     }
925     
926     if ((i_err = snd_card_get_name(i_card, &psz_card_name)) != 0)
927     {
928         psz_card_name = _("Unknown soundcard");
929     }
930
931     snd_pcm_info_alloca(&p_pcm_info);
932
933     for (;;)
934     {
935         char *psz_device, *psz_descr;
936         if ((i_err = snd_ctl_pcm_next_device(p_ctl, &i_pcm_device)) < 0)
937         {
938             i_pcm_device = -1;
939         }
940         if ( i_pcm_device < 0 )
941             break;
942
943         snd_pcm_info_set_device(p_pcm_info, i_pcm_device);
944         snd_pcm_info_set_subdevice(p_pcm_info, 0);
945         snd_pcm_info_set_stream(p_pcm_info, SND_PCM_STREAM_PLAYBACK);
946
947         if ((i_err = snd_ctl_pcm_info(p_ctl, p_pcm_info)) < 0)
948         {
949             if (i_err != -ENOENT)
950             {
951 /*                printf("get_devices_for_card(): "
952                          "snd_ctl_pcm_info() "
953                          "failed (%d:%d): %s.\n", i_card,
954                          i_pcm_device, snd_strerror(-i_err));*/
955             }
956             continue;
957         }
958
959         asprintf( &psz_device, "hw:%d,%d", i_card, i_pcm_device );
960         asprintf( &psz_descr, "%s: %s (%s)", psz_card_name,
961                   snd_pcm_info_get_name(p_pcm_info), psz_device );
962
963         p_item->ppsz_list =
964             (char **)realloc( p_item->ppsz_list,
965                               (p_item->i_list + 2) * sizeof(char *) );
966         p_item->ppsz_list_text =
967             (char **)realloc( p_item->ppsz_list_text,
968                               (p_item->i_list + 2) * sizeof(char *) );
969         p_item->ppsz_list[ p_item->i_list ] = psz_device;
970         p_item->ppsz_list_text[ p_item->i_list ] = psz_descr;
971         p_item->i_list++;
972         p_item->ppsz_list[ p_item->i_list ] = NULL;
973         p_item->ppsz_list_text[ p_item->i_list ] = NULL;
974                 
975     }
976
977     snd_ctl_close( p_ctl );
978 }
979
980
981
982 static void GetDevices( module_config_t *p_item )
983 {
984     int i_card = -1;
985     int i_err = 0;
986     
987     if ((i_err = snd_card_next(&i_card)) != 0)
988     {
989 //        g_warning("snd_next_card() failed: %s", snd_strerror(-err));
990         return;
991     }
992     
993     while (i_card > -1)
994     {
995         GetDevicesForCard(p_item, i_card);
996         if ((i_err = snd_card_next(&i_card)) != 0)
997         {
998 //            g_warning("snd_next_card() failed: %s",
999 //                  snd_strerror(-err));
1000             break;
1001         }
1002     }
1003 }