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