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