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