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