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