]> git.sesse.net Git - vlc/blob - modules/audio_output/alsa.c
alsa: fix a memory leak.
[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_InheritBool( 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_Fatal( 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 #if (SND_LIB_VERSION <= 0x010017)
287 # warning Please update alsa-lib to version > 1.0.23.
288         var_Create( p_aout->p_libvlc, "alsa-broken", VLC_VAR_BOOL );
289         if( !var_GetBool( p_aout->p_libvlc, "alsa-broken" ) )
290         {
291             var_SetBool( p_aout->p_libvlc, "alsa-broken", true );
292             dialog_Fatal( p_aout, "Potential ALSA version problem",
293                 "VLC failed to initialize your sound output device (if any).\n"
294                 "Please update alsa-lib to version 1.0.24 or higher "
295                 "to try to fix this issue." );
296         }
297 #endif
298         msg_Dbg( p_aout, "failed to find a usable ALSA configuration" );
299         var_Destroy( p_aout, "audio-device" );
300         GetDevices( VLC_OBJECT(p_aout), NULL );
301         return;
302     }
303
304     /* Add final settings to the variable */
305     var_AddCallback( p_aout, "audio-device", aout_ChannelsRestart, NULL );
306     var_SetBool( p_aout, "intf-change", true );
307 }
308
309 /*****************************************************************************
310  * Open: create a handle and open an alsa device
311  *****************************************************************************
312  * This function opens an alsa device, through the alsa API.
313  *
314  * Note: the only heap-allocated string is psz_device. All the other pointers
315  * are references to psz_device or to stack-allocated data.
316  *****************************************************************************/
317 static int Open( vlc_object_t *p_this )
318 {
319     aout_instance_t * p_aout = (aout_instance_t *)p_this;
320     struct aout_sys_t * p_sys;
321     vlc_value_t val;
322
323     char psz_default_iec_device[128]; /* Buffer used to store the default
324                                          S/PDIF device */
325     char * psz_device, * psz_iec_device; /* device names for PCM and S/PDIF
326                                             output */
327
328     int i_vlc_pcm_format; /* Audio format for VLC's data */
329     int i_snd_pcm_format; /* Audio format for ALSA's data */
330
331     snd_pcm_uframes_t i_buffer_size = 0;
332     snd_pcm_uframes_t i_period_size = 0;
333     int i_channels = 0;
334
335     snd_pcm_hw_params_t *p_hw;
336     snd_pcm_sw_params_t *p_sw;
337
338     int i_snd_rc = -1;
339     unsigned int i_old_rate;
340     bool b_retry = true;
341
342     /* Allocate structures */
343     p_aout->output.p_sys = p_sys = malloc( sizeof( aout_sys_t ) );
344     if( p_sys == NULL )
345         return VLC_ENOMEM;
346
347     /* Get device name */
348     if( (psz_device = var_InheritString( p_aout, "alsa-audio-device" )) == NULL )
349     {
350         msg_Err( p_aout, "no audio device given (maybe \"default\" ?)" );
351         dialog_Fatal( p_aout, _("No Audio Device"), "%s",
352                         _("No audio device name was given. You might want to " \
353                           "enter \"default\".") );
354         free( p_sys );
355         return VLC_EGENERIC;
356     }
357
358     /* Choose the IEC device for S/PDIF output:
359        if the device is overriden by the user then it will be the one
360        otherwise we compute the default device based on the output format. */
361     if( AOUT_FMT_NON_LINEAR( &p_aout->output.output )
362         && !strcmp( psz_device, DEFAULT_ALSA_DEVICE ) )
363     {
364         snprintf( psz_default_iec_device, sizeof(psz_default_iec_device),
365                   "iec958:AES0=0x%x,AES1=0x%x,AES2=0x%x,AES3=0x%x",
366                   IEC958_AES0_CON_EMPHASIS_NONE | IEC958_AES0_NONAUDIO,
367                   IEC958_AES1_CON_ORIGINAL | IEC958_AES1_CON_PCM_CODER,
368                   0,
369                   ( p_aout->output.output.i_rate == 48000 ?
370                     IEC958_AES3_CON_FS_48000 :
371                     ( p_aout->output.output.i_rate == 44100 ?
372                       IEC958_AES3_CON_FS_44100 : IEC958_AES3_CON_FS_32000 ) ) );
373         psz_iec_device = psz_default_iec_device;
374     }
375     else if( AOUT_FMT_NON_LINEAR( &p_aout->output.output ) )
376     {
377         psz_iec_device = psz_device;
378     }
379     else
380     {
381         psz_iec_device = NULL;
382     }
383
384     /* Choose the linear PCM format (read the comment above about FPU
385        and float32) */
386     if( HAVE_FPU )
387     {
388         i_vlc_pcm_format = VLC_CODEC_FL32;
389         i_snd_pcm_format = SND_PCM_FORMAT_FLOAT;
390     }
391     else
392     {
393         i_vlc_pcm_format = VLC_CODEC_S16N;
394         i_snd_pcm_format = SND_PCM_FORMAT_S16;
395     }
396
397     /* If the variable doesn't exist then it's the first time we're called
398        and we have to probe the available audio formats and channels */
399     if ( var_Type( p_aout, "audio-device" ) == 0 )
400     {
401         Probe( p_aout, psz_device, psz_iec_device, &i_snd_pcm_format );
402     }
403
404     if ( var_Get( p_aout, "audio-device", &val ) < 0 )
405     {
406         free( p_sys );
407         free( psz_device );
408         return VLC_EGENERIC;
409     }
410
411     p_aout->output.output.i_format = i_vlc_pcm_format;
412     if ( val.i_int == AOUT_VAR_5_1 )
413     {
414         p_aout->output.output.i_physical_channels
415             = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER
416                | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT
417                | AOUT_CHAN_LFE;
418         free( psz_device );
419         psz_device = strdup( "surround51" );
420     }
421     else if ( val.i_int == AOUT_VAR_2F2R )
422     {
423         p_aout->output.output.i_physical_channels
424             = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT
425                | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT;
426         free( psz_device );
427         psz_device = strdup( "surround40" );
428     }
429     else if ( val.i_int == AOUT_VAR_STEREO )
430     {
431         p_aout->output.output.i_physical_channels
432             = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT;
433     }
434     else if ( val.i_int == AOUT_VAR_MONO )
435     {
436         p_aout->output.output.i_physical_channels = AOUT_CHAN_CENTER;
437     }
438     else if( val.i_int != AOUT_VAR_SPDIF )
439     {
440         /* This should not happen ! */
441         msg_Err( p_aout, "internal: can't find audio-device (%i)", val.i_int );
442         free( p_sys );
443         free( psz_device );
444         return VLC_EGENERIC;
445     }
446
447 #ifdef ALSA_DEBUG
448     snd_output_stdio_attach( &p_sys->p_snd_stderr, stderr, 0 );
449 #endif
450
451     /* Open the device */
452     if ( val.i_int == AOUT_VAR_SPDIF )
453     {
454         if ( ( i_snd_rc = snd_pcm_open( &p_sys->p_snd_pcm, psz_iec_device,
455                             SND_PCM_STREAM_PLAYBACK, 0 ) ) < 0 )
456         {
457             msg_Err( p_aout, "cannot open ALSA device `%s' (%s)",
458                              psz_iec_device, snd_strerror( i_snd_rc ) );
459             dialog_Fatal( p_aout, _("Audio output failed"),
460                             _("VLC could not open the ALSA device \"%s\" (%s)."),
461                             psz_iec_device, snd_strerror( i_snd_rc ) );
462             free( p_sys );
463             free( psz_device );
464             return VLC_EGENERIC;
465         }
466         i_buffer_size = ALSA_SPDIF_BUFFER_SIZE;
467         i_snd_pcm_format = SND_PCM_FORMAT_S16;
468         i_channels = 2;
469
470         i_vlc_pcm_format = VLC_CODEC_SPDIFL;
471         p_aout->output.i_nb_samples = i_period_size = ALSA_SPDIF_PERIOD_SIZE;
472         p_aout->output.output.i_bytes_per_frame = AOUT_SPDIF_SIZE;
473         p_aout->output.output.i_frame_length = A52_FRAME_NB;
474
475         aout_VolumeNoneInit( p_aout );
476     }
477     else
478     {
479         int i;
480
481         msg_Dbg( p_aout, "opening ALSA device `%s'", psz_device );
482
483         /* Since it seems snd_pcm_close hasn't really released the device at
484           the time it returns, probe if the device is available in loop for 1s.
485           We cannot use blocking mode since the we would wait indefinitely when
486           switching from a dmx device to surround51. */
487
488         for( i = 10; i >= 0; i-- )
489         {
490             if ( ( i_snd_rc = snd_pcm_open( &p_sys->p_snd_pcm, psz_device,
491                    SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK ) ) == -EBUSY )
492             {
493                 if( i ) msleep( 100000 /* 100ms */ );
494                 else
495                 {
496                     msg_Err( p_aout, "audio device: %s is already in use",
497                               psz_device );
498                     dialog_Fatal( p_aout, _("Audio output failed"),
499                                     _("The audio device \"%s\" is already in use."),
500                                     psz_device );
501                 }
502                 continue;
503             }
504             break;
505         }
506         if( i_snd_rc < 0 )
507         {
508             msg_Err( p_aout, "cannot open ALSA device `%s' (%s)",
509                              psz_device, snd_strerror( i_snd_rc ) );
510             dialog_Fatal( p_aout, _("Audio output failed"),
511                             _("VLC could not open the ALSA device \"%s\" (%s)."),
512                             psz_device, snd_strerror( i_snd_rc ) );
513             free( p_sys );
514             free( psz_device );
515             return VLC_EGENERIC;
516         }
517
518         /* We want blocking mode */
519         snd_pcm_nonblock( p_sys->p_snd_pcm, 0 );
520
521         i_buffer_size = ALSA_DEFAULT_BUFFER_SIZE;
522         i_channels = aout_FormatNbChannels( &p_aout->output.output );
523
524         p_aout->output.i_nb_samples = i_period_size = ALSA_DEFAULT_PERIOD_SIZE;
525
526         aout_VolumeSoftInit( p_aout );
527     }
528
529     /* Free psz_device so that all the remaining data is stack-allocated */
530     free( psz_device );
531
532     p_aout->output.pf_play = Play;
533
534     snd_pcm_hw_params_alloca(&p_hw);
535     snd_pcm_sw_params_alloca(&p_sw);
536
537     /* Due to some bugs in alsa with some drivers, we need to retry in s16l
538        if snd_pcm_hw_params fails in fl32 */
539     while ( b_retry )
540     {
541         b_retry = false;
542
543         /* Get Initial hardware parameters */
544         if ( ( i_snd_rc = snd_pcm_hw_params_any( p_sys->p_snd_pcm, p_hw ) ) < 0 )
545         {
546             msg_Err( p_aout, "unable to retrieve initial hardware parameters (%s)",
547                          snd_strerror( i_snd_rc ) );
548             goto error;
549         }
550
551         /* Set format. */
552         if ( ( i_snd_rc = snd_pcm_hw_params_set_format( p_sys->p_snd_pcm, p_hw,
553                                                     i_snd_pcm_format ) ) < 0 )
554         {
555             if( i_snd_pcm_format != SND_PCM_FORMAT_S16 )
556             {
557                 i_snd_pcm_format = SND_PCM_FORMAT_S16;
558                 i_snd_rc = snd_pcm_hw_params_set_format( p_sys->p_snd_pcm,
559                                                      p_hw, i_snd_pcm_format );
560             }
561             if ( i_snd_rc < 0 )
562             {
563                 msg_Err( p_aout, "unable to set stream sample size and "
564                      "word order (%s)", snd_strerror( i_snd_rc ) );
565                 goto error;
566             }
567         }
568         if( i_vlc_pcm_format != VLC_CODEC_SPDIFL )
569         switch( i_snd_pcm_format )
570         {
571         case SND_PCM_FORMAT_FLOAT:
572             i_vlc_pcm_format = VLC_CODEC_FL32;
573             break;
574         case SND_PCM_FORMAT_S16:
575             i_vlc_pcm_format = VLC_CODEC_S16N;
576             break;
577         }
578         p_aout->output.output.i_format = i_vlc_pcm_format;
579
580         if ( ( i_snd_rc = snd_pcm_hw_params_set_access( p_sys->p_snd_pcm, p_hw,
581                                     SND_PCM_ACCESS_RW_INTERLEAVED ) ) < 0 )
582         {
583             msg_Err( p_aout, "unable to set interleaved stream format (%s)",
584                              snd_strerror( i_snd_rc ) );
585             goto error;
586         }
587
588         /* Set channels. */
589         if ( ( i_snd_rc = snd_pcm_hw_params_set_channels( p_sys->p_snd_pcm, p_hw,
590                                                       i_channels ) ) < 0 )
591         {
592             msg_Err( p_aout, "unable to set number of output channels (%s)",
593                              snd_strerror( i_snd_rc ) );
594             goto error;
595         }
596
597         /* Set rate. */
598         i_old_rate = p_aout->output.output.i_rate;
599         i_snd_rc = snd_pcm_hw_params_set_rate_near( p_sys->p_snd_pcm, p_hw,
600                                                 &p_aout->output.output.i_rate,
601                                                 NULL );
602         if( i_snd_rc < 0 || p_aout->output.output.i_rate != i_old_rate )
603         {
604             msg_Warn( p_aout, "The rate %d Hz is not supported by your " \
605                 "hardware. Using %d Hz instead.\n", i_old_rate, \
606                 p_aout->output.output.i_rate );
607         }
608
609         /* Set period size. */
610         if ( ( i_snd_rc = snd_pcm_hw_params_set_period_size_near( p_sys->p_snd_pcm,
611                                     p_hw, &i_period_size, NULL ) ) < 0 )
612         {
613             msg_Err( p_aout, "unable to set period size (%s)",
614                          snd_strerror( i_snd_rc ) );
615             goto error;
616         }
617         p_aout->output.i_nb_samples = i_period_size;
618
619 /* Set buffer size. */
620         if ( ( i_snd_rc = snd_pcm_hw_params_set_buffer_size_near( p_sys->p_snd_pcm,
621                                     p_hw, &i_buffer_size ) ) < 0 )
622         {
623             msg_Err( p_aout, "unable to set buffer size (%s)",
624                          snd_strerror( i_snd_rc ) );
625             goto error;
626         }
627
628         /* Commit hardware parameters. */
629         if ( ( i_snd_rc = snd_pcm_hw_params( p_sys->p_snd_pcm, p_hw ) ) < 0 )
630         {
631             if ( b_retry == false &&
632                                 i_snd_pcm_format == SND_PCM_FORMAT_FLOAT)
633             {
634                 b_retry = true;
635                 i_snd_pcm_format = SND_PCM_FORMAT_S16;
636                 p_aout->output.output.i_format = VLC_CODEC_S16N;
637                 msg_Warn( p_aout, "unable to commit hardware configuration "
638                                   "with fl32 samples. Retrying with s16l (%s)",                                     snd_strerror( i_snd_rc ) );
639             }
640             else
641             {
642                 msg_Err( p_aout, "unable to commit hardware configuration (%s)",
643                          snd_strerror( i_snd_rc ) );
644                 goto error;
645             }
646         }
647     }
648
649     if( ( i_snd_rc = snd_pcm_hw_params_get_period_time( p_hw,
650                                     &p_sys->i_period_time, NULL ) ) < 0 )
651     {
652         msg_Err( p_aout, "unable to get period time (%s)",
653                          snd_strerror( i_snd_rc ) );
654         goto error;
655     }
656
657     /* Get Initial software parameters */
658     snd_pcm_sw_params_current( p_sys->p_snd_pcm, p_sw );
659
660     i_snd_rc = snd_pcm_sw_params_set_sleep_min( p_sys->p_snd_pcm, p_sw, 0 );
661
662     i_snd_rc = snd_pcm_sw_params_set_avail_min( p_sys->p_snd_pcm, p_sw,
663                                                 p_aout->output.i_nb_samples );
664     /* start playing when one period has been written */
665     i_snd_rc = snd_pcm_sw_params_set_start_threshold( p_sys->p_snd_pcm, p_sw,
666                                                       ALSA_DEFAULT_PERIOD_SIZE);
667     if( i_snd_rc < 0 )
668     {
669         msg_Err( p_aout, "unable to set start threshold (%s)",
670                           snd_strerror( i_snd_rc ) );
671         goto error;
672     }
673
674     /* Commit software parameters. */
675     if ( snd_pcm_sw_params( p_sys->p_snd_pcm, p_sw ) < 0 )
676     {
677         msg_Err( p_aout, "unable to set software configuration" );
678         goto error;
679     }
680
681 #ifdef ALSA_DEBUG
682     snd_output_printf( p_sys->p_snd_stderr, "\nALSA hardware setup:\n\n" );
683     snd_pcm_dump_hw_setup( p_sys->p_snd_pcm, p_sys->p_snd_stderr );
684     snd_output_printf( p_sys->p_snd_stderr, "\nALSA software setup:\n\n" );
685     snd_pcm_dump_sw_setup( p_sys->p_snd_pcm, p_sys->p_snd_stderr );
686     snd_output_printf( p_sys->p_snd_stderr, "\n" );
687 #endif
688
689     p_sys->start_date = 0;
690     vlc_sem_init( &p_sys->wait, 0 );
691
692     /* Create ALSA thread and wait for its readiness. */
693     if( vlc_clone( &p_sys->thread, ALSAThread, p_aout,
694                    VLC_THREAD_PRIORITY_OUTPUT ) )
695     {
696         msg_Err( p_aout, "cannot create ALSA thread (%m)" );
697         vlc_sem_destroy( &p_sys->wait );
698         goto error;
699     }
700
701     return 0;
702
703 error:
704     snd_pcm_close( p_sys->p_snd_pcm );
705 #ifdef ALSA_DEBUG
706     snd_output_close( p_sys->p_snd_stderr );
707 #endif
708     free( p_sys );
709     return VLC_EGENERIC;
710 }
711
712 static void PlayIgnore( aout_instance_t *p_aout )
713 {   /* Already playing - nothing to do */
714     (void) p_aout;
715 }
716
717 /*****************************************************************************
718  * Play: start playback
719  *****************************************************************************/
720 static void Play( aout_instance_t *p_aout )
721 {
722     p_aout->output.pf_play = PlayIgnore;
723
724     /* get the playing date of the first aout buffer */
725     p_aout->output.p_sys->start_date =
726         aout_FifoFirstDate( p_aout, &p_aout->output.fifo );
727
728     /* wake up the audio output thread */
729     sem_post( &p_aout->output.p_sys->wait );
730 }
731
732 /*****************************************************************************
733  * Close: close the ALSA device
734  *****************************************************************************/
735 static void Close( vlc_object_t *p_this )
736 {
737     aout_instance_t *p_aout = (aout_instance_t *)p_this;
738     struct aout_sys_t * p_sys = p_aout->output.p_sys;
739     int i_snd_rc;
740
741     /* Make sure that the thread will stop once it is waken up */
742     vlc_cancel( p_sys->thread );
743     vlc_join( p_sys->thread, NULL );
744     vlc_sem_destroy( &p_sys->wait );
745
746     /* */
747     i_snd_rc = snd_pcm_close( p_sys->p_snd_pcm );
748
749     if( i_snd_rc > 0 )
750     {
751         msg_Err( p_aout, "failed closing ALSA device (%s)",
752                          snd_strerror( i_snd_rc ) );
753     }
754
755 #ifdef ALSA_DEBUG
756     snd_output_close( p_sys->p_snd_stderr );
757 #endif
758
759     free( p_sys );
760 }
761
762 static void pcm_drop(void *pcm)
763 {
764     snd_pcm_drop(pcm);
765 }
766
767 /*****************************************************************************
768  * ALSAThread: asynchronous thread used to DMA the data to the device
769  *****************************************************************************/
770 static void* ALSAThread( void *data )
771 {
772     aout_instance_t * p_aout = data;
773     struct aout_sys_t * p_sys = p_aout->output.p_sys;
774
775     /* Wait for the exact time to start playing (avoids resampling) */
776     vlc_sem_wait( &p_sys->wait );
777     mwait( p_sys->start_date - AOUT_PTS_TOLERANCE / 4 );
778
779     vlc_cleanup_push( pcm_drop, p_sys->p_snd_pcm );
780     for(;;)
781         ALSAFill( p_aout );
782
783     assert(0);
784     vlc_cleanup_pop();
785 }
786
787 /*****************************************************************************
788  * ALSAFill: function used to fill the ALSA buffer as much as possible
789  *****************************************************************************/
790 static void ALSAFill( aout_instance_t * p_aout )
791 {
792     struct aout_sys_t * p_sys = p_aout->output.p_sys;
793     snd_pcm_t *p_pcm = p_sys->p_snd_pcm;
794     snd_pcm_status_t * p_status;
795     int i_snd_rc;
796     mtime_t next_date;
797
798     int canc = vlc_savecancel();
799     /* Fill in the buffer until space or audio output buffer shortage */
800
801     /* Get the status */
802     snd_pcm_status_alloca(&p_status);
803     i_snd_rc = snd_pcm_status( p_pcm, p_status );
804     if( i_snd_rc < 0 )
805     {
806         msg_Err( p_aout, "cannot get device status" );
807         goto error;
808     }
809
810     /* Handle buffer underruns and get the status again */
811     if( snd_pcm_status_get_state( p_status ) == SND_PCM_STATE_XRUN )
812     {
813         /* Prepare the device */
814         i_snd_rc = snd_pcm_prepare( p_pcm );
815         if( i_snd_rc )
816         {
817             msg_Err( p_aout, "cannot recover from buffer underrun" );
818             goto error;
819         }
820
821         msg_Dbg( p_aout, "recovered from buffer underrun" );
822
823         /* Get the new status */
824         i_snd_rc = snd_pcm_status( p_pcm, p_status );
825         if( i_snd_rc < 0 )
826         {
827             msg_Err( p_aout, "cannot get device status after recovery" );
828             goto error;
829         }
830
831         /* Underrun, try to recover as quickly as possible */
832         next_date = mdate();
833     }
834     else
835     {
836         /* Here the device should be in RUNNING state, p_status is valid. */
837         snd_pcm_sframes_t delay = snd_pcm_status_get_delay( p_status );
838         if( delay == 0 ) /* workaround buggy alsa drivers */
839             if( snd_pcm_delay( p_pcm, &delay ) < 0 )
840                 delay = 0; /* FIXME: use a positive minimal delay */
841
842         size_t i_bytes = snd_pcm_frames_to_bytes( p_pcm, delay );
843         mtime_t delay_us = CLOCK_FREQ * i_bytes
844                 / p_aout->output.output.i_bytes_per_frame
845                 / p_aout->output.output.i_rate
846                 * p_aout->output.output.i_frame_length;
847
848 #ifdef ALSA_DEBUG
849         snd_pcm_state_t state = snd_pcm_status_get_state( p_status );
850         if( state != SND_PCM_STATE_RUNNING )
851             msg_Err( p_aout, "pcm status (%d) != RUNNING", state );
852
853         msg_Dbg( p_aout, "Delay is %ld frames (%zu bytes)", delay, i_bytes );
854
855         msg_Dbg( p_aout, "Bytes per frame: %d", p_aout->output.output.i_bytes_per_frame );
856         msg_Dbg( p_aout, "Rate: %d", p_aout->output.output.i_rate );
857         msg_Dbg( p_aout, "Frame length: %d", p_aout->output.output.i_frame_length );
858         msg_Dbg( p_aout, "Next date: in %"PRId64" microseconds", delay_us );
859 #endif
860         next_date = mdate() + delay_us;
861     }
862
863     block_t *p_buffer = aout_OutputNextBuffer( p_aout, next_date,
864            (p_aout->output.output.i_format ==  VLC_CODEC_SPDIFL) );
865
866     /* Audio output buffer shortage -> stop the fill process and wait */
867     if( p_buffer == NULL )
868         goto error;
869
870     block_cleanup_push( p_buffer );
871     for (;;)
872     {
873         int n = snd_pcm_poll_descriptors_count(p_pcm);
874         struct pollfd ufd[n];
875         unsigned short revents;
876
877         snd_pcm_poll_descriptors(p_pcm, ufd, n);
878         do
879         {
880             vlc_restorecancel(canc);
881             poll(ufd, n, -1);
882             canc = vlc_savecancel();
883             snd_pcm_poll_descriptors_revents(p_pcm, ufd, n, &revents);
884         }
885         while(!revents);
886
887         if(revents & POLLOUT)
888         {
889             i_snd_rc = snd_pcm_writei( p_pcm, p_buffer->p_buffer,
890                                        p_buffer->i_nb_samples );
891             if( i_snd_rc != -ESTRPIPE )
892                 break;
893         }
894
895         /* a suspend event occurred
896          * (stream is suspended and waiting for an application recovery) */
897         msg_Dbg( p_aout, "entering in suspend mode, trying to resume..." );
898
899         while( ( i_snd_rc = snd_pcm_resume( p_pcm ) ) == -EAGAIN )
900         {
901             vlc_restorecancel(canc);
902             msleep(CLOCK_FREQ); /* device still suspended, wait... */
903             canc = vlc_savecancel();
904         }
905
906         if( i_snd_rc < 0 )
907             /* Device does not support resuming, restart it */
908             i_snd_rc = snd_pcm_prepare( p_pcm );
909
910     }
911
912     if( i_snd_rc < 0 )
913         msg_Err( p_aout, "cannot write: %s", snd_strerror( i_snd_rc ) );
914
915     vlc_restorecancel(canc);
916     vlc_cleanup_run();
917     return;
918
919 error:
920     if( i_snd_rc < 0 )
921         msg_Err( p_aout, "ALSA error: %s", snd_strerror( i_snd_rc ) );
922
923     vlc_restorecancel(canc);
924     msleep(p_sys->i_period_time / 2);
925 }
926
927 /*****************************************************************************
928  * config variable callback
929  *****************************************************************************/
930 static int FindDevicesCallback( vlc_object_t *p_this, char const *psz_name,
931                                vlc_value_t newval, vlc_value_t oldval, void *p_unused )
932 {
933     module_config_t *p_item;
934     (void)newval;
935     (void)oldval;
936     (void)p_unused;
937
938     p_item = config_FindConfig( p_this, psz_name );
939     if( !p_item ) return VLC_SUCCESS;
940
941     /* Clear-up the current list */
942     if( p_item->i_list )
943     {
944         int i;
945
946         /* Keep the first entrie */
947         for( i = 1; i < p_item->i_list; i++ )
948         {
949             free( (char *)p_item->ppsz_list[i] );
950             free( (char *)p_item->ppsz_list_text[i] );
951         }
952         /* TODO: Remove when no more needed */
953         p_item->ppsz_list[i] = NULL;
954         p_item->ppsz_list_text[i] = NULL;
955     }
956     p_item->i_list = 1;
957
958     GetDevices( p_this, p_item );
959
960     /* Signal change to the interface */
961     p_item->b_dirty = true;
962
963     return VLC_SUCCESS;
964 }
965
966
967 static void GetDevicesForCard( vlc_object_t *obj, module_config_t *p_item,
968                                int i_card )
969 {
970     int i_pcm_device = -1;
971     int i_err = 0;
972     snd_pcm_info_t *p_pcm_info;
973     snd_ctl_t *p_ctl;
974     char psz_dev[64];
975     char *psz_card_name;
976
977     sprintf( psz_dev, "hw:%i", i_card );
978
979     if( ( i_err = snd_ctl_open( &p_ctl, psz_dev, 0 ) ) < 0 )
980         return;
981
982     if( ( i_err = snd_card_get_name( i_card, &psz_card_name ) ) != 0)
983         psz_card_name = _("Unknown soundcard");
984
985     snd_pcm_info_alloca( &p_pcm_info );
986
987     for (;;)
988     {
989         char *psz_device, *psz_descr;
990         if( ( i_err = snd_ctl_pcm_next_device( p_ctl, &i_pcm_device ) ) < 0 )
991             i_pcm_device = -1;
992         if( i_pcm_device < 0 )
993             break;
994
995         snd_pcm_info_set_device( p_pcm_info, i_pcm_device );
996         snd_pcm_info_set_subdevice( p_pcm_info, 0 );
997         snd_pcm_info_set_stream( p_pcm_info, SND_PCM_STREAM_PLAYBACK );
998
999         if( ( i_err = snd_ctl_pcm_info( p_ctl, p_pcm_info ) ) < 0 )
1000         {
1001             if( i_err != -ENOENT )
1002                 msg_Err( obj, "cannot get PCM device %d:%d infos: %s", i_card,
1003                          i_pcm_device, snd_strerror( -i_err ) );
1004             continue;
1005         }
1006
1007         if( asprintf( &psz_device, "hw:%d,%d", i_card, i_pcm_device ) == -1 )
1008             break;
1009         if( asprintf( &psz_descr, "%s: %s (%s)", psz_card_name,
1010                   snd_pcm_info_get_name(p_pcm_info), psz_device ) == -1 )
1011         {
1012             free( psz_device );
1013             break;
1014         }
1015
1016         msg_Dbg( obj, "  %s", psz_descr );
1017
1018         if( p_item )
1019         {
1020             p_item->ppsz_list = xrealloc( p_item->ppsz_list,
1021                                   (p_item->i_list + 2) * sizeof(char *) );
1022             p_item->ppsz_list_text = xrealloc( p_item->ppsz_list_text,
1023                                   (p_item->i_list + 2) * sizeof(char *) );
1024             p_item->ppsz_list[ p_item->i_list ] = psz_device;
1025             p_item->ppsz_list_text[ p_item->i_list ] = psz_descr;
1026             p_item->i_list++;
1027             p_item->ppsz_list[ p_item->i_list ] = NULL;
1028             p_item->ppsz_list_text[ p_item->i_list ] = NULL;
1029         }
1030         else
1031         {
1032             free( psz_device );
1033             free( psz_descr );
1034         }
1035     }
1036
1037     snd_ctl_close( p_ctl );
1038 }
1039
1040
1041 static void GetDevices( vlc_object_t *obj, module_config_t *p_item )
1042 {
1043     int i_card = -1;
1044     int i_err;
1045
1046     msg_Dbg( obj, "Available alsa output devices:" );
1047     while( (i_err = snd_card_next( &i_card )) == 0 && i_card > -1 )
1048         GetDevicesForCard( obj, p_item, i_card );
1049
1050     if( i_err )
1051         msg_Err( obj, "cannot enumerate cards: %s", snd_strerror( -i_err ) );
1052 }