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