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