]> git.sesse.net Git - vlc/blob - modules/audio_output/alsa.c
4ebcdf3f0712acd35b9031088890d29f85ec8ba3
[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., 59 Temple Place - Suite 330, Boston, MA  02111, 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     p_sys->p_status = (snd_pcm_status_t *)malloc(snd_pcm_status_sizeof());
319     vlc_cond_init( p_aout, &p_sys->wait );
320     vlc_mutex_init( p_aout, &p_sys->lock );
321
322     /* Get device name */
323     if( (psz_device = config_GetPsz( p_aout, "alsadev" )) == NULL )
324     {
325         msg_Err( p_aout, "no audio device given (maybe \"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( p_aout->p_libvlc->i_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             free( p_sys );
432             free( psz_device );
433             return VLC_EGENERIC;
434         }
435         i_buffer_size = ALSA_SPDIF_BUFFER_SIZE;
436         i_snd_pcm_format = SND_PCM_FORMAT_S16;
437         i_channels = 2;
438
439         i_vlc_pcm_format = VLC_FOURCC('s','p','d','i');
440         p_aout->output.i_nb_samples = i_period_size = ALSA_SPDIF_PERIOD_SIZE;
441         p_aout->output.output.i_bytes_per_frame = AOUT_SPDIF_SIZE;
442         p_aout->output.output.i_frame_length = A52_FRAME_NB;
443
444         aout_VolumeNoneInit( p_aout );
445     }
446     else
447     {
448         int i;
449
450         msg_Dbg( p_aout, "opening ALSA device `%s'", psz_device );
451
452         /* Since it seems snd_pcm_close hasen't really released the device at
453           the time it returns, probe if the device is available in loop for 1s.
454           We cannot use blocking mode since the we would wait indefinitely when
455           switching from a dmx device to surround51. */
456
457         for( i = 10; i >= 0; i-- )
458         {
459             if ( ( i_snd_rc = snd_pcm_open( &p_sys->p_snd_pcm, psz_device,
460                    SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK ) ) == -EBUSY )
461             {
462                 if( i ) msleep( 100000 /* 100ms */ );
463                 else msg_Err( p_aout, "audio device: %s is already in use",
464                               psz_device );
465                 continue;
466             }
467             break;
468         }
469         if( i_snd_rc < 0 )
470         {
471             msg_Err( p_aout, "cannot open ALSA device `%s' (%s)",
472                              psz_device, snd_strerror( i_snd_rc ) );
473             free( p_sys );
474             free( psz_device );
475             return VLC_EGENERIC;
476         }
477
478         /* We want blocking mode */
479         snd_pcm_nonblock( p_sys->p_snd_pcm, 0 );
480
481         i_buffer_size = ALSA_DEFAULT_BUFFER_SIZE;
482         i_channels = aout_FormatNbChannels( &p_aout->output.output );
483
484         p_aout->output.i_nb_samples = i_period_size = ALSA_DEFAULT_PERIOD_SIZE;
485
486         aout_VolumeSoftInit( p_aout );
487     }
488
489     /* Free psz_device so that all the remaining data is stack-allocated */
490     free( psz_device );
491
492     p_aout->output.pf_play = Play;
493
494     snd_pcm_hw_params_alloca(&p_hw);
495     snd_pcm_sw_params_alloca(&p_sw);
496
497     /* Due to some bugs in alsa with some drivers, we need to retry in s16l
498        if snd_pcm_hw_params fails in fl32 */
499     while ( b_retry )
500     {
501         b_retry = VLC_FALSE;
502
503         /* Get Initial hardware parameters */
504         if ( ( i_snd_rc = snd_pcm_hw_params_any( p_sys->p_snd_pcm, p_hw ) ) < 0 )
505         {
506             msg_Err( p_aout, "unable to retrieve initial hardware parameters (%s)",
507                          snd_strerror( i_snd_rc ) );
508             goto error;
509         }
510
511         /* Set format. */
512         if ( ( i_snd_rc = snd_pcm_hw_params_set_format( p_sys->p_snd_pcm, p_hw,
513                                                     i_snd_pcm_format ) ) < 0 )
514         {
515             if( i_snd_pcm_format != SND_PCM_FORMAT_S16 )
516             {
517                 i_snd_pcm_format = SND_PCM_FORMAT_S16;
518                 i_snd_rc = snd_pcm_hw_params_set_format( p_sys->p_snd_pcm,
519                                                      p_hw, i_snd_pcm_format );
520             }
521             if ( i_snd_rc < 0 )
522             {
523                 msg_Err( p_aout, "unable to set stream sample size and "
524                      "word order (%s)", snd_strerror( i_snd_rc ) );
525                 goto error;
526             }
527         }
528         if( i_vlc_pcm_format != VLC_FOURCC('s','p','d','i') )
529         switch( i_snd_pcm_format )
530         {
531         case SND_PCM_FORMAT_FLOAT:
532             i_vlc_pcm_format = VLC_FOURCC('f','l','3','2');
533             break;
534         case SND_PCM_FORMAT_S16:
535             i_vlc_pcm_format = AOUT_FMT_S16_NE;
536             break;
537         }
538         p_aout->output.output.i_format = i_vlc_pcm_format;
539
540         if ( ( i_snd_rc = snd_pcm_hw_params_set_access( p_sys->p_snd_pcm, p_hw,
541                                     SND_PCM_ACCESS_RW_INTERLEAVED ) ) < 0 )
542         {
543             msg_Err( p_aout, "unable to set interleaved stream format (%s)",
544                              snd_strerror( i_snd_rc ) );
545             goto error;
546         }
547
548         /* Set channels. */
549         if ( ( i_snd_rc = snd_pcm_hw_params_set_channels( p_sys->p_snd_pcm, p_hw,
550                                                       i_channels ) ) < 0 )
551         {
552             msg_Err( p_aout, "unable to set number of output channels (%s)",
553                              snd_strerror( i_snd_rc ) );
554             goto error;
555         }
556
557         /* Set rate. */
558         i_old_rate = p_aout->output.output.i_rate;
559 #ifdef HAVE_ALSA_NEW_API
560         i_snd_rc = snd_pcm_hw_params_set_rate_near( p_sys->p_snd_pcm, p_hw,
561                                                 &p_aout->output.output.i_rate,
562                                                 NULL );
563 #else
564         i_snd_rc = snd_pcm_hw_params_set_rate_near( p_sys->p_snd_pcm, p_hw,
565                                                 p_aout->output.output.i_rate,
566                                                 NULL );
567 #endif
568         if( i_snd_rc < 0 || p_aout->output.output.i_rate != i_old_rate )
569         {
570             msg_Warn( p_aout, "The rate %d Hz is not supported by your hardware. "
571                   "Using %d Hz instead.\n", i_old_rate,
572                   p_aout->output.output.i_rate );
573         }
574
575         /* Set buffer size. */
576 #ifdef HAVE_ALSA_NEW_API
577         if ( ( i_snd_rc = snd_pcm_hw_params_set_buffer_size_near( p_sys->p_snd_pcm,
578                                     p_hw, &i_buffer_size ) ) < 0 )
579 #else
580         if ( ( i_snd_rc = snd_pcm_hw_params_set_buffer_size_near( p_sys->p_snd_pcm,
581                                     p_hw, i_buffer_size ) ) < 0 )
582 #endif
583         {
584             msg_Err( p_aout, "unable to set buffer size (%s)",
585                          snd_strerror( i_snd_rc ) );
586             goto error;
587         }
588
589         /* Set period size. */
590 #ifdef HAVE_ALSA_NEW_API
591         if ( ( i_snd_rc = snd_pcm_hw_params_set_period_size_near( p_sys->p_snd_pcm,
592                                     p_hw, &i_period_size, NULL ) ) < 0 )
593 #else
594         if ( ( i_snd_rc = snd_pcm_hw_params_set_period_size_near( p_sys->p_snd_pcm,
595                                     p_hw, i_period_size, NULL ) ) < 0 )
596 #endif
597         {
598             msg_Err( p_aout, "unable to set period size (%s)",
599                          snd_strerror( i_snd_rc ) );
600             goto error;
601         }
602         p_aout->output.i_nb_samples = i_period_size;
603
604         /* Commit hardware parameters. */
605         if ( ( i_snd_rc = snd_pcm_hw_params( p_sys->p_snd_pcm, p_hw ) ) < 0 )
606         {
607             if ( b_retry == VLC_FALSE &&
608                                 i_snd_pcm_format == SND_PCM_FORMAT_FLOAT)
609             {
610                 b_retry = VLC_TRUE;
611                 i_snd_pcm_format = SND_PCM_FORMAT_S16;
612                 p_aout->output.output.i_format = AOUT_FMT_S16_NE;
613                 msg_Warn( p_aout, "unable to commit hardware configuration "
614                                   "with fl32 samples. Retrying with s16l (%s)",                                     snd_strerror( i_snd_rc ) );
615             }
616             else
617             {
618                 msg_Err( p_aout, "unable to commit hardware configuration (%s)",
619                          snd_strerror( i_snd_rc ) );
620                 goto error;
621             }
622         }
623     }
624
625 #ifdef HAVE_ALSA_NEW_API
626     if( ( i_snd_rc = snd_pcm_hw_params_get_period_time( p_hw,
627                                     &p_sys->i_period_time, NULL ) ) < 0 )
628 #else
629     if( ( p_sys->i_period_time =
630                   (int)snd_pcm_hw_params_get_period_time( p_hw, NULL ) ) < 0 )
631 #endif
632     {
633         msg_Err( p_aout, "unable to get period time (%s)",
634                          snd_strerror( i_snd_rc ) );
635         goto error;
636     }
637
638     /* Get Initial software parameters */
639     snd_pcm_sw_params_current( p_sys->p_snd_pcm, p_sw );
640
641     i_snd_rc = snd_pcm_sw_params_set_sleep_min( p_sys->p_snd_pcm, p_sw, 0 );
642
643     i_snd_rc = snd_pcm_sw_params_set_avail_min( p_sys->p_snd_pcm, p_sw,
644                                                 p_aout->output.i_nb_samples );
645
646     /* Commit software parameters. */
647     if ( snd_pcm_sw_params( p_sys->p_snd_pcm, p_sw ) < 0 )
648     {
649         msg_Err( p_aout, "unable to set software configuration" );
650         goto error;
651     }
652
653 #ifdef ALSA_DEBUG
654     snd_output_printf( p_sys->p_snd_stderr, "\nALSA hardware setup:\n\n" );
655     snd_pcm_dump_hw_setup( p_sys->p_snd_pcm, p_sys->p_snd_stderr );
656     snd_output_printf( p_sys->p_snd_stderr, "\nALSA software setup:\n\n" );
657     snd_pcm_dump_sw_setup( p_sys->p_snd_pcm, p_sys->p_snd_stderr );
658     snd_output_printf( p_sys->p_snd_stderr, "\n" );
659 #endif
660
661     /* Create ALSA thread and wait for its readiness. */
662     if( vlc_thread_create( p_aout, "aout", ALSAThread,
663                            VLC_THREAD_PRIORITY_OUTPUT, VLC_FALSE ) )
664     {
665         msg_Err( p_aout, "cannot create ALSA thread (%s)", strerror(errno) );
666         goto error;
667     }
668
669     return 0;
670
671 error:
672     snd_pcm_close( p_sys->p_snd_pcm );
673 #ifdef ALSA_DEBUG
674     snd_output_close( p_sys->p_snd_stderr );
675 #endif
676     free( p_sys );
677     return VLC_EGENERIC;
678 }
679
680 /*****************************************************************************
681  * Play: nothing to do
682  *****************************************************************************/
683 static void Play( aout_instance_t *p_aout )
684 {
685     if( !p_aout->output.p_sys->b_playing )
686     {
687         p_aout->output.p_sys->b_playing = 1;
688
689         /* get the playing date of the first aout buffer */
690         p_aout->output.p_sys->start_date =
691             aout_FifoFirstDate( p_aout, &p_aout->output.fifo );
692
693         /* wake up the audio output thread */
694         vlc_mutex_lock( &p_aout->output.p_sys->lock );
695         vlc_cond_signal( &p_aout->output.p_sys->wait );
696         vlc_mutex_unlock( &p_aout->output.p_sys->lock );
697     }
698 }
699
700 /*****************************************************************************
701  * Close: close the ALSA device
702  *****************************************************************************/
703 static void Close( vlc_object_t *p_this )
704 {
705     aout_instance_t *p_aout = (aout_instance_t *)p_this;
706     struct aout_sys_t * p_sys = p_aout->output.p_sys;
707     int i_snd_rc;
708
709     /* make sure the audio output thread is waken up */
710     vlc_mutex_lock( &p_aout->output.p_sys->lock );
711     vlc_cond_signal( &p_aout->output.p_sys->wait );
712     vlc_mutex_unlock( &p_aout->output.p_sys->lock );
713
714     p_aout->b_die = VLC_TRUE;
715     vlc_thread_join( p_aout );
716     p_aout->b_die = VLC_FALSE;
717
718     i_snd_rc = snd_pcm_close( p_sys->p_snd_pcm );
719
720     if( i_snd_rc > 0 )
721     {
722         msg_Err( p_aout, "failed closing ALSA device (%s)",
723                          snd_strerror( i_snd_rc ) );
724     }
725
726 #ifdef ALSA_DEBUG
727     snd_output_close( p_sys->p_snd_stderr );
728 #endif
729
730     free( p_sys->p_status );
731     free( p_sys );
732 }
733
734 /*****************************************************************************
735  * ALSAThread: asynchronous thread used to DMA the data to the device
736  *****************************************************************************/
737 static int ALSAThread( aout_instance_t * p_aout )
738 {
739     /* Wait for the exact time to start playing (avoids resampling) */
740     vlc_mutex_lock( &p_aout->output.p_sys->lock );
741     if( !p_aout->output.p_sys->start_date )
742         vlc_cond_wait( &p_aout->output.p_sys->wait,
743                        &p_aout->output.p_sys->lock );
744     vlc_mutex_unlock( &p_aout->output.p_sys->lock );
745
746     mwait( p_aout->output.p_sys->start_date - AOUT_PTS_TOLERANCE / 4 );
747
748     while ( !p_aout->b_die )
749     {
750         ALSAFill( p_aout );
751     }
752
753     return 0;
754 }
755
756 /*****************************************************************************
757  * ALSAFill: function used to fill the ALSA buffer as much as possible
758  *****************************************************************************/
759 static void ALSAFill( aout_instance_t * p_aout )
760 {
761     struct aout_sys_t * p_sys = p_aout->output.p_sys;
762
763     aout_buffer_t * p_buffer;
764     snd_pcm_status_t * p_status = p_sys->p_status;
765     snd_timestamp_t ts_next;
766     int i_snd_rc;
767     mtime_t next_date;
768
769     /* Fill in the buffer until space or audio output buffer shortage */
770     {
771         /* Get the status */
772         i_snd_rc = snd_pcm_status( p_sys->p_snd_pcm, p_status );
773         if( i_snd_rc < 0 )
774         {
775             msg_Err( p_aout, "unable to get the device's status (%s)",
776                              snd_strerror( i_snd_rc ) );
777
778             msleep( p_sys->i_period_time >> 1 );
779             return;
780         }
781
782         /* Handle buffer underruns and reget the status */
783         if( snd_pcm_status_get_state( p_status ) == SND_PCM_STATE_XRUN )
784         {
785             /* Prepare the device */
786             i_snd_rc = snd_pcm_prepare( p_sys->p_snd_pcm );
787
788             if( i_snd_rc == 0 )
789             {
790                 msg_Warn( p_aout, "recovered from buffer underrun" );
791
792                 /* Reget the status */
793                 i_snd_rc = snd_pcm_status( p_sys->p_snd_pcm, p_status );
794                 if( i_snd_rc < 0 )
795                 {
796                     msg_Err( p_aout, "unable to get the device's status after "
797                              "recovery (%s)", snd_strerror( i_snd_rc ) );
798
799                     msleep( p_sys->i_period_time >> 1 );
800                     return;
801                 }
802             }
803             else
804             {
805                 msg_Err( p_aout, "unable to recover from buffer underrun" );
806
807                 msleep( p_sys->i_period_time >> 1 );
808                 return;
809             }
810
811             /* Underrun, try to recover as quickly as possible */
812             next_date = mdate();
813         }
814         else
815         {
816             /* Here the device should be either in the RUNNING state.
817              * p_status is valid. */
818
819             snd_pcm_status_get_tstamp( p_status, &ts_next );
820             next_date = (mtime_t)ts_next.tv_sec * 1000000 + ts_next.tv_usec;
821             if( next_date )
822             {
823                 next_date += (mtime_t)snd_pcm_status_get_delay(p_status)
824                         * 1000000 / p_aout->output.output.i_rate;
825             }
826             else
827             {
828                 /* With screwed ALSA drivers the timestamp is always zero;
829                  * use another method then */
830                 snd_pcm_sframes_t delay;
831                 ssize_t i_bytes = 0;
832
833                 if( !snd_pcm_delay( p_sys->p_snd_pcm, &delay ) )
834                 {
835                     i_bytes = snd_pcm_frames_to_bytes(p_sys->p_snd_pcm, delay);
836                 }
837                 next_date = mdate() + (mtime_t)i_bytes * 1000000
838                         / p_aout->output.output.i_bytes_per_frame
839                         / p_aout->output.output.i_rate
840                         * p_aout->output.output.i_frame_length;
841             }
842         }
843
844         p_buffer = aout_OutputNextBuffer( p_aout, next_date,
845                         (p_aout->output.output.i_format ==
846                          VLC_FOURCC('s','p','d','i')) );
847
848         /* Audio output buffer shortage -> stop the fill process and wait */
849         if( p_buffer == NULL )
850         {
851             msleep( p_sys->i_period_time >> 1 );
852             return;
853         }
854
855         i_snd_rc = snd_pcm_writei( p_sys->p_snd_pcm, p_buffer->p_buffer,
856                                    p_buffer->i_nb_samples );
857
858         if( i_snd_rc < 0 )
859         {
860             msg_Err( p_aout, "write failed (%s)",
861                              snd_strerror( i_snd_rc ) );
862         }
863
864         aout_BufferFree( p_buffer );
865     }
866 }
867
868 static void GetDevicesForCard(module_config_t *p_item, int i_card);
869 static void GetDevices( module_config_t *p_item );
870
871 /*****************************************************************************
872  * config variable callback
873  *****************************************************************************/
874 static int FindDevicesCallback( vlc_object_t *p_this, char const *psz_name,
875                                vlc_value_t newval, vlc_value_t oldval, void *p_unused )
876 {
877     module_config_t *p_item;
878     int i;
879
880     p_item = config_FindConfig( p_this, psz_name );
881     if( !p_item ) return VLC_SUCCESS;
882
883     /* Clear-up the current list */
884     if( p_item->i_list )
885     {
886         /* Keep the first entrie */
887         for( i = 1; i < p_item->i_list; i++ )
888         {
889             free( p_item->ppsz_list[i] );
890             free( p_item->ppsz_list_text[i] );
891         }
892         /* TODO: Remove when no more needed */
893         p_item->ppsz_list[i] = NULL;
894         p_item->ppsz_list_text[i] = NULL;
895     }
896     p_item->i_list = 1;
897
898     GetDevices( p_item );
899
900     /* Signal change to the interface */
901     p_item->b_dirty = VLC_TRUE;
902
903     return VLC_SUCCESS;
904
905 }
906
907
908 static void GetDevicesForCard(module_config_t *p_item, int i_card)
909 {
910     int i_pcm_device = -1;
911     int i_err = 0;
912     snd_pcm_info_t *p_pcm_info;
913     snd_ctl_t *p_ctl;
914     char psz_dev[64];
915     char *psz_card_name;
916     
917     sprintf(psz_dev, "hw:%i", i_card);
918     
919     if (( i_err = snd_ctl_open(&p_ctl, psz_dev, 0)) < 0 )
920     {
921         return;
922     }
923     
924     if ((i_err = snd_card_get_name(i_card, &psz_card_name)) != 0)
925     {
926         psz_card_name = _("Unknown soundcard");
927     }
928
929     snd_pcm_info_alloca(&p_pcm_info);
930
931     for (;;)
932     {
933         char *psz_device, *psz_descr;
934         if ((i_err = snd_ctl_pcm_next_device(p_ctl, &i_pcm_device)) < 0)
935         {
936             i_pcm_device = -1;
937         }
938         if ( i_pcm_device < 0 )
939             break;
940
941         snd_pcm_info_set_device(p_pcm_info, i_pcm_device);
942         snd_pcm_info_set_subdevice(p_pcm_info, 0);
943         snd_pcm_info_set_stream(p_pcm_info, SND_PCM_STREAM_PLAYBACK);
944
945         if ((i_err = snd_ctl_pcm_info(p_ctl, p_pcm_info)) < 0)
946         {
947             if (i_err != -ENOENT)
948             {
949 /*                printf("get_devices_for_card(): "
950                          "snd_ctl_pcm_info() "
951                          "failed (%d:%d): %s.\n", i_card,
952                          i_pcm_device, snd_strerror(-i_err));*/
953             }
954             continue;
955         }
956
957         asprintf( &psz_device, "hw:%d,%d", i_card, i_pcm_device );
958         asprintf( &psz_descr, "%s: %s (%s)", psz_card_name,
959                   snd_pcm_info_get_name(p_pcm_info), psz_device );
960
961         p_item->ppsz_list =
962             (char **)realloc( p_item->ppsz_list,
963                               (p_item->i_list + 2) * sizeof(char *) );
964         p_item->ppsz_list_text =
965             (char **)realloc( p_item->ppsz_list_text,
966                               (p_item->i_list + 2) * sizeof(char *) );
967         p_item->ppsz_list[ p_item->i_list ] = psz_device;
968         p_item->ppsz_list_text[ p_item->i_list ] = psz_descr;
969         p_item->i_list++;
970         p_item->ppsz_list[ p_item->i_list ] = NULL;
971         p_item->ppsz_list_text[ p_item->i_list ] = NULL;
972                 
973     }
974
975     snd_ctl_close( p_ctl );
976 }
977
978
979
980 static void GetDevices( module_config_t *p_item )
981 {
982     int i_card = -1;
983     int i_err = 0;
984     
985     if ((i_err = snd_card_next(&i_card)) != 0)
986     {
987 //        g_warning("snd_next_card() failed: %s", snd_strerror(-err));
988         return;
989     }
990     
991     while (i_card > -1)
992     {
993         GetDevicesForCard(p_item, i_card);
994         if ((i_err = snd_card_next(&i_card)) != 0)
995         {
996 //            g_warning("snd_next_card() failed: %s",
997 //                  snd_strerror(-err));
998             break;
999         }
1000     }
1001 }