Use the right declaration for threaded functions.
[vlc.git] / 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( "alsadev", DEFAULT_ALSA_DEVICE, aout_FindAndRestart,
112                 N_("ALSA Device Name"), NULL, false );
113         change_string_list( ppsz_devices, ppsz_devices_text, FindDevicesCallback );
114         change_action_add( FindDevicesCallback, N_("Refresh list") );
115
116     set_capability( "audio output", 150 );
117     set_callbacks( Open, Close );
118 vlc_module_end();
119
120 /*****************************************************************************
121  * Probe: probe the audio device for available formats and channels
122  *****************************************************************************/
123 static void Probe( aout_instance_t * p_aout,
124                    const char * psz_device, const char * psz_iec_device,
125                    int *pi_snd_pcm_format )
126 {
127     struct aout_sys_t * p_sys = p_aout->output.p_sys;
128     vlc_value_t val, text;
129     int i_ret;
130
131     var_Create ( p_aout, "audio-device", VLC_VAR_INTEGER | VLC_VAR_HASCHOICE );
132     text.psz_string = _("Audio Device");
133     var_Change( p_aout, "audio-device", VLC_VAR_SETTEXT, &text, NULL );
134
135     /* We'll open the audio device in non blocking mode so we can just exit
136      * when it is already in use, but for the real stuff we'll still use
137      * the blocking mode */
138
139     /* Now test linear PCM capabilities */
140     if ( !(i_ret = snd_pcm_open( &p_sys->p_snd_pcm, psz_device,
141                                  SND_PCM_STREAM_PLAYBACK,
142                                  SND_PCM_NONBLOCK ) ) )
143     {
144         int i_channels;
145         snd_pcm_hw_params_t * p_hw;
146         snd_pcm_hw_params_alloca (&p_hw);
147
148         if ( snd_pcm_hw_params_any( p_sys->p_snd_pcm, p_hw ) < 0 )
149         {
150             msg_Warn( p_aout, "unable to retrieve initial hardware parameters"
151                               ", disabling linear PCM audio" );
152             snd_pcm_close( p_sys->p_snd_pcm );
153             var_Destroy( p_aout, "audio-device" );
154             return;
155         }
156
157         if ( snd_pcm_hw_params_set_format( p_sys->p_snd_pcm, p_hw,
158                                            *pi_snd_pcm_format ) < 0 )
159         {
160             int i_snd_rc = -1;
161
162             if( *pi_snd_pcm_format != SND_PCM_FORMAT_S16 )
163             {
164                 *pi_snd_pcm_format = SND_PCM_FORMAT_S16;
165                 i_snd_rc = snd_pcm_hw_params_set_format( p_sys->p_snd_pcm,
166                                                     p_hw, *pi_snd_pcm_format );
167             }
168             if ( i_snd_rc < 0 )
169             {
170                 msg_Warn( p_aout, "unable to set stream sample size and "
171                           "word order, disabling linear PCM audio" );
172                 snd_pcm_close( p_sys->p_snd_pcm );
173                 var_Destroy( p_aout, "audio-device" );
174                 return;
175             }
176         }
177
178         i_channels = aout_FormatNbChannels( &p_aout->output.output );
179
180         while ( i_channels > 0 )
181         {
182             if ( !snd_pcm_hw_params_test_channels( p_sys->p_snd_pcm, p_hw,
183                                                    i_channels ) )
184             {
185                 switch ( i_channels )
186                 {
187                 case 1:
188                     val.i_int = AOUT_VAR_MONO;
189                     text.psz_string = N_("Mono");
190                     var_Change( p_aout, "audio-device",
191                                 VLC_VAR_ADDCHOICE, &val, &text );
192                     break;
193                 case 2:
194                     val.i_int = AOUT_VAR_STEREO;
195                     text.psz_string = N_("Stereo");
196                     var_Change( p_aout, "audio-device",
197                                 VLC_VAR_ADDCHOICE, &val, &text );
198                     var_Set( p_aout, "audio-device", val );
199                     break;
200                 case 4:
201                     val.i_int = AOUT_VAR_2F2R;
202                     text.psz_string = N_("2 Front 2 Rear");
203                     var_Change( p_aout, "audio-device",
204                                 VLC_VAR_ADDCHOICE, &val, &text );
205                     break;
206                 case 6:
207                     val.i_int = AOUT_VAR_5_1;
208                     text.psz_string = "5.1";
209                     var_Change( p_aout, "audio-device",
210                                 VLC_VAR_ADDCHOICE, &val, &text );
211                     break;
212                 }
213             }
214
215             --i_channels;
216         }
217
218         /* Special case for mono on stereo only boards */
219         i_channels = aout_FormatNbChannels( &p_aout->output.output );
220         var_Change( p_aout, "audio-device", VLC_VAR_CHOICESCOUNT, &val, NULL );
221         if( val.i_int <= 0 && i_channels == 1 )
222         {
223             if ( !snd_pcm_hw_params_test_channels( p_sys->p_snd_pcm, p_hw, 2 ))
224             {
225                 val.i_int = AOUT_VAR_STEREO;
226                 text.psz_string = N_("Stereo");
227                 var_Change( p_aout, "audio-device",
228                             VLC_VAR_ADDCHOICE, &val, &text );
229                 var_Set( p_aout, "audio-device", val );
230             }
231         }
232
233         /* Close the previously opened device */
234         snd_pcm_close( p_sys->p_snd_pcm );
235     }
236     else if ( i_ret == -EBUSY )
237     {
238         msg_Warn( p_aout, "audio device: %s is already in use", psz_device );
239     }
240
241     /* Test for S/PDIF device if needed */
242     if ( psz_iec_device )
243     {
244         /* Opening the device should be enough */
245         if ( !(i_ret = snd_pcm_open( &p_sys->p_snd_pcm, psz_iec_device,
246                                      SND_PCM_STREAM_PLAYBACK,
247                                      SND_PCM_NONBLOCK ) ) )
248         {
249             val.i_int = AOUT_VAR_SPDIF;
250             text.psz_string = N_("A/52 over S/PDIF");
251             var_Change( p_aout, "audio-device",
252                         VLC_VAR_ADDCHOICE, &val, &text );
253             if( config_GetInt( p_aout, "spdif" ) )
254                 var_Set( p_aout, "audio-device", val );
255
256             snd_pcm_close( p_sys->p_snd_pcm );
257         }
258         else if ( i_ret == -EBUSY )
259         {
260             msg_Warn( p_aout, "audio device: %s is already in use",
261                       psz_iec_device );
262         }
263     }
264
265     var_Change( p_aout, "audio-device", VLC_VAR_CHOICESCOUNT, &val, NULL );
266     if( val.i_int <= 0 )
267     {
268         /* Probe() has failed. */
269         msg_Dbg( p_aout, "failed to find a useable alsa configuration" );
270         var_Destroy( p_aout, "audio-device" );
271         return;
272     }
273
274     /* Add final settings to the variable */
275     var_AddCallback( p_aout, "audio-device", aout_ChannelsRestart, NULL );
276     val.b_bool = true;
277     var_Set( p_aout, "intf-change", val );
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_aout, &p_sys->wait );
320     vlc_mutex_init( &p_sys->lock );
321
322     /* Get device name */
323     if( (psz_device = config_GetPsz( p_aout, "alsadev" )) == NULL )
324     {
325         msg_Err( p_aout, "no audio device given (maybe \"default\" ?)" );
326         intf_UserFatal( p_aout, false, _("No Audio Device"),
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( vlc_CPU() & CPU_CAPABILITY_FPU )
362     {
363         i_vlc_pcm_format = VLC_FOURCC('f','l','3','2');
364         i_snd_pcm_format = SND_PCM_FORMAT_FLOAT;
365     }
366     else
367     {
368         i_vlc_pcm_format = AOUT_FMT_S16_NE;
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             intf_UserFatal( p_aout, false, _("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_FOURCC('s','p','d','i');
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                     intf_UserFatal( p_aout, false, _("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             intf_UserFatal( p_aout, false, _("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_FOURCC('s','p','d','i') )
544         switch( i_snd_pcm_format )
545         {
546         case SND_PCM_FORMAT_FLOAT:
547             i_vlc_pcm_format = VLC_FOURCC('f','l','3','2');
548             break;
549         case SND_PCM_FORMAT_S16:
550             i_vlc_pcm_format = AOUT_FMT_S16_NE;
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 #ifdef HAVE_ALSA_NEW_API
575         i_snd_rc = snd_pcm_hw_params_set_rate_near( p_sys->p_snd_pcm, p_hw,
576                                                 &p_aout->output.output.i_rate,
577                                                 NULL );
578 #else
579         i_snd_rc = snd_pcm_hw_params_set_rate_near( p_sys->p_snd_pcm, p_hw,
580                                                 p_aout->output.output.i_rate,
581                                                 NULL );
582 #endif
583         if( i_snd_rc < 0 || p_aout->output.output.i_rate != i_old_rate )
584         {
585             msg_Warn( p_aout, "The rate %d Hz is not supported by your " \
586                 "hardware. Using %d Hz instead.\n", i_old_rate, \
587                 p_aout->output.output.i_rate );
588         }
589
590         /* Set period size. */
591 #ifdef HAVE_ALSA_NEW_API
592         if ( ( i_snd_rc = snd_pcm_hw_params_set_period_size_near( p_sys->p_snd_pcm,
593                                     p_hw, &i_period_size, NULL ) ) < 0 )
594 #else
595         if ( ( i_snd_rc = snd_pcm_hw_params_set_period_size_near( p_sys->p_snd_pcm,
596                                     p_hw, i_period_size, NULL ) ) < 0 )
597 #endif
598         {
599             msg_Err( p_aout, "unable to set period size (%s)",
600                          snd_strerror( i_snd_rc ) );
601             goto error;
602         }
603         p_aout->output.i_nb_samples = i_period_size;
604
605 /* Set buffer size. */
606 #ifdef HAVE_ALSA_NEW_API
607         if ( ( i_snd_rc = snd_pcm_hw_params_set_buffer_size_near( p_sys->p_snd_pcm,
608                                     p_hw, &i_buffer_size ) ) < 0 )
609 #else
610         if ( ( i_snd_rc = snd_pcm_hw_params_set_buffer_size_near( p_sys->p_snd_pcm,
611                                     p_hw, i_buffer_size ) ) < 0 )
612 #endif
613         {
614             msg_Err( p_aout, "unable to set buffer size (%s)",
615                          snd_strerror( i_snd_rc ) );
616             goto error;
617         }
618
619         /* Commit hardware parameters. */
620         if ( ( i_snd_rc = snd_pcm_hw_params( p_sys->p_snd_pcm, p_hw ) ) < 0 )
621         {
622             if ( b_retry == false &&
623                                 i_snd_pcm_format == SND_PCM_FORMAT_FLOAT)
624             {
625                 b_retry = true;
626                 i_snd_pcm_format = SND_PCM_FORMAT_S16;
627                 p_aout->output.output.i_format = AOUT_FMT_S16_NE;
628                 msg_Warn( p_aout, "unable to commit hardware configuration "
629                                   "with fl32 samples. Retrying with s16l (%s)",                                     snd_strerror( i_snd_rc ) );
630             }
631             else
632             {
633                 msg_Err( p_aout, "unable to commit hardware configuration (%s)",
634                          snd_strerror( i_snd_rc ) );
635                 goto error;
636             }
637         }
638     }
639
640 #ifdef HAVE_ALSA_NEW_API
641     if( ( i_snd_rc = snd_pcm_hw_params_get_period_time( p_hw,
642                                     &p_sys->i_period_time, NULL ) ) < 0 )
643 #else
644     if( ( p_sys->i_period_time =
645                   (int)snd_pcm_hw_params_get_period_time( p_hw, NULL ) ) < 0 )
646 #endif
647     {
648         msg_Err( p_aout, "unable to get period time (%s)",
649                          snd_strerror( i_snd_rc ) );
650         goto error;
651     }
652
653     /* Get Initial software parameters */
654     snd_pcm_sw_params_current( p_sys->p_snd_pcm, p_sw );
655
656     i_snd_rc = snd_pcm_sw_params_set_sleep_min( p_sys->p_snd_pcm, p_sw, 0 );
657
658     i_snd_rc = snd_pcm_sw_params_set_avail_min( p_sys->p_snd_pcm, p_sw,
659                                                 p_aout->output.i_nb_samples );
660     /* start playing when one period has been written */
661     i_snd_rc = snd_pcm_sw_params_set_start_threshold( p_sys->p_snd_pcm, p_sw,
662                                                       ALSA_DEFAULT_PERIOD_SIZE);
663     if( i_snd_rc < 0 )
664     {
665         msg_Err( p_aout, "unable to set start threshold (%s)",
666                           snd_strerror( i_snd_rc ) );
667         goto error;
668     }
669
670     /* Commit software parameters. */
671     if ( snd_pcm_sw_params( p_sys->p_snd_pcm, p_sw ) < 0 )
672     {
673         msg_Err( p_aout, "unable to set software configuration" );
674         goto error;
675     }
676
677 #ifdef ALSA_DEBUG
678     snd_output_printf( p_sys->p_snd_stderr, "\nALSA hardware setup:\n\n" );
679     snd_pcm_dump_hw_setup( p_sys->p_snd_pcm, p_sys->p_snd_stderr );
680     snd_output_printf( p_sys->p_snd_stderr, "\nALSA software setup:\n\n" );
681     snd_pcm_dump_sw_setup( p_sys->p_snd_pcm, p_sys->p_snd_stderr );
682     snd_output_printf( p_sys->p_snd_stderr, "\n" );
683 #endif
684
685     /* Create ALSA thread and wait for its readiness. */
686     if( vlc_thread_create( p_aout, "aout", ALSAThread,
687                            VLC_THREAD_PRIORITY_OUTPUT, false ) )
688     {
689         msg_Err( p_aout, "cannot create ALSA thread (%m)" );
690         goto error;
691     }
692
693     return 0;
694
695 error:
696     snd_pcm_close( p_sys->p_snd_pcm );
697 #ifdef ALSA_DEBUG
698     snd_output_close( p_sys->p_snd_stderr );
699 #endif
700     free( p_sys );
701     return VLC_EGENERIC;
702 }
703
704 /*****************************************************************************
705  * Play: nothing to do
706  *****************************************************************************/
707 static void Play( aout_instance_t *p_aout )
708 {
709     if( !p_aout->output.p_sys->b_playing )
710     {
711         p_aout->output.p_sys->b_playing = 1;
712
713         /* get the playing date of the first aout buffer */
714         p_aout->output.p_sys->start_date =
715             aout_FifoFirstDate( p_aout, &p_aout->output.fifo );
716
717         /* wake up the audio output thread */
718         vlc_mutex_lock( &p_aout->output.p_sys->lock );
719         vlc_cond_signal( &p_aout->output.p_sys->wait );
720         vlc_mutex_unlock( &p_aout->output.p_sys->lock );
721     }
722 }
723
724 /*****************************************************************************
725  * Close: close the ALSA device
726  *****************************************************************************/
727 static void Close( vlc_object_t *p_this )
728 {
729     aout_instance_t *p_aout = (aout_instance_t *)p_this;
730     struct aout_sys_t * p_sys = p_aout->output.p_sys;
731     int i_snd_rc;
732
733     /* Make sure that the thread will stop once it is waken up */
734     vlc_object_kill( p_aout );
735
736     /* make sure the audio output thread is waken up */
737     vlc_mutex_lock( &p_aout->output.p_sys->lock );
738     vlc_cond_signal( &p_aout->output.p_sys->wait );
739     vlc_mutex_unlock( &p_aout->output.p_sys->lock );
740
741     /* */
742     vlc_thread_join( p_aout );
743     p_aout->b_die = false;
744
745     i_snd_rc = snd_pcm_close( p_sys->p_snd_pcm );
746
747     if( i_snd_rc > 0 )
748     {
749         msg_Err( p_aout, "failed closing ALSA device (%s)",
750                          snd_strerror( i_snd_rc ) );
751     }
752
753 #ifdef ALSA_DEBUG
754     snd_output_close( p_sys->p_snd_stderr );
755 #endif
756
757     free( p_sys );
758 }
759
760 /*****************************************************************************
761  * ALSAThread: asynchronous thread used to DMA the data to the device
762  *****************************************************************************/
763 static void* ALSAThread( vlc_object_t* p_this )
764 {
765     aout_instance_t * p_aout = (aout_instance_t*)p_this;
766     struct aout_sys_t * p_sys = p_aout->output.p_sys;
767     p_sys->p_status = (snd_pcm_status_t *)malloc(snd_pcm_status_sizeof());
768
769     /* Wait for the exact time to start playing (avoids resampling) */
770     vlc_mutex_lock( &p_sys->lock );
771     while( !p_sys->start_date && vlc_object_alive (p_aout) )
772         vlc_cond_wait( &p_sys->wait, &p_sys->lock );
773     vlc_mutex_unlock( &p_sys->lock );
774
775     if( !vlc_object_alive (p_aout) )
776         goto cleanup;
777
778     mwait( p_sys->start_date - AOUT_PTS_TOLERANCE / 4 );
779
780     while ( vlc_object_alive (p_aout) )
781     {
782         ALSAFill( p_aout );
783     }
784
785 cleanup:
786     snd_pcm_drop( p_sys->p_snd_pcm );
787     free( p_aout->output.p_sys->p_status );
788     return NULL;
789 }
790
791 /*****************************************************************************
792  * ALSAFill: function used to fill the ALSA buffer as much as possible
793  *****************************************************************************/
794 static void ALSAFill( aout_instance_t * p_aout )
795 {
796     struct aout_sys_t * p_sys = p_aout->output.p_sys;
797     aout_buffer_t * p_buffer;
798     snd_pcm_status_t * p_status = p_sys->p_status;
799     int i_snd_rc;
800     mtime_t next_date;
801
802     /* Fill in the buffer until space or audio output buffer shortage */
803
804     /* Get the status */
805     i_snd_rc = snd_pcm_status( p_sys->p_snd_pcm, p_status );
806     if( i_snd_rc < 0 )
807     {
808         msg_Err( p_aout, "cannot get device status" );
809         goto error;
810     }
811
812     /* Handle buffer underruns and get the status again */
813     if( snd_pcm_status_get_state( p_status ) == SND_PCM_STATE_XRUN )
814     {
815         /* Prepare the device */
816         i_snd_rc = snd_pcm_prepare( p_sys->p_snd_pcm );
817
818         if( i_snd_rc )
819         {
820             msg_Err( p_aout, "cannot recover from buffer underrun" );
821             goto error;
822         }
823
824         msg_Dbg( p_aout, "recovered from buffer underrun" );
825
826         /* Get the new status */
827         i_snd_rc = snd_pcm_status( p_sys->p_snd_pcm, p_status );
828         if( i_snd_rc < 0 )
829         {
830             msg_Err( p_aout, "cannot get device status after recovery" );
831             goto error;
832         }
833
834         /* Underrun, try to recover as quickly as possible */
835         next_date = mdate();
836     }
837     else
838     {
839         /* Here the device should be in RUNNING state, p_status is valid. */
840         snd_pcm_sframes_t delay = snd_pcm_status_get_delay( p_status );
841         if( delay == 0 ) /* workaround buggy alsa drivers */
842             if( snd_pcm_delay( p_sys->p_snd_pcm, &delay ) < 0 )
843                 delay = 0; /* FIXME: use a positive minimal delay */
844         int i_bytes = snd_pcm_frames_to_bytes( p_sys->p_snd_pcm, delay );
845         next_date = mdate() + ( (mtime_t)i_bytes * 1000000
846                 / p_aout->output.output.i_bytes_per_frame
847                 / p_aout->output.output.i_rate
848                 * p_aout->output.output.i_frame_length );
849
850 #ifdef ALSA_DEBUG
851         snd_pcm_state_t state = snd_pcm_status_get_state( p_status );
852         if( state != SND_PCM_STATE_RUNNING )
853             msg_Err( p_aout, "pcm status (%d) != RUNNING", state );
854
855         msg_Dbg( p_aout, "Delay is %ld frames (%d bytes)", delay, i_bytes );
856
857         msg_Dbg( p_aout, "Bytes per frame: %d", p_aout->output.output.i_bytes_per_frame );
858         msg_Dbg( p_aout, "Rate: %d", p_aout->output.output.i_rate );
859         msg_Dbg( p_aout, "Frame length: %d", p_aout->output.output.i_frame_length );
860
861         msg_Dbg( p_aout, "Next date is in %d microseconds", (int)(next_date - mdate()) );
862 #endif
863     }
864
865     p_buffer = aout_OutputNextBuffer( p_aout, next_date,
866            (p_aout->output.output.i_format ==  VLC_FOURCC('s','p','d','i')) );
867
868     /* Audio output buffer shortage -> stop the fill process and wait */
869     if( p_buffer == NULL )
870         goto error;
871
872     for (;;)
873     {
874         i_snd_rc = snd_pcm_writei( p_sys->p_snd_pcm, p_buffer->p_buffer,
875                                    p_buffer->i_nb_samples );
876         if( i_snd_rc != -ESTRPIPE )
877             break;
878
879         /* a suspend event occurred
880          * (stream is suspended and waiting for an application recovery) */
881         msg_Dbg( p_aout, "entering in suspend mode, trying to resume..." );
882
883         while( vlc_object_alive (p_aout) && vlc_object_alive (p_aout->p_libvlc) &&
884                ( i_snd_rc = snd_pcm_resume( p_sys->p_snd_pcm ) ) == -EAGAIN )
885         {
886             msleep( 1000000 );
887         }
888
889         if( i_snd_rc < 0 )
890             /* Device does not supprot resuming, restart it */
891             i_snd_rc = snd_pcm_prepare( p_sys->p_snd_pcm );
892
893     }
894
895     if( i_snd_rc < 0 )
896         msg_Err( p_aout, "cannot write: %s", snd_strerror( i_snd_rc ) );
897
898     aout_BufferFree( p_buffer );
899     return;
900
901 error:
902     if( i_snd_rc < 0 )
903         msg_Err( p_aout, "ALSA error: %s", snd_strerror( i_snd_rc ) );
904     msleep( p_sys->i_period_time >> 1 );
905 }
906
907 static void GetDevicesForCard( module_config_t *p_item, int i_card );
908 static void GetDevices( module_config_t *p_item );
909
910 /*****************************************************************************
911  * config variable callback
912  *****************************************************************************/
913 static int FindDevicesCallback( vlc_object_t *p_this, char const *psz_name,
914                                vlc_value_t newval, vlc_value_t oldval, void *p_unused )
915 {
916     module_config_t *p_item;
917     int i;
918
919     p_item = config_FindConfig( p_this, psz_name );
920     if( !p_item ) return VLC_SUCCESS;
921
922     /* Clear-up the current list */
923     if( p_item->i_list )
924     {
925         /* Keep the first entrie */
926         for( i = 1; i < p_item->i_list; i++ )
927         {
928             free( (char *)p_item->ppsz_list[i] );
929             free( (char *)p_item->ppsz_list_text[i] );
930         }
931         /* TODO: Remove when no more needed */
932         p_item->ppsz_list[i] = NULL;
933         p_item->ppsz_list_text[i] = NULL;
934     }
935     p_item->i_list = 1;
936
937     GetDevices( p_item );
938
939     /* Signal change to the interface */
940     p_item->b_dirty = true;
941
942     return VLC_SUCCESS;
943
944 }
945
946
947 static void GetDevicesForCard( module_config_t *p_item, int i_card )
948 {
949     int i_pcm_device = -1;
950     int i_err = 0;
951     snd_pcm_info_t *p_pcm_info;
952     snd_ctl_t *p_ctl;
953     char psz_dev[64];
954     char *psz_card_name;
955
956     sprintf( psz_dev, "hw:%i", i_card );
957
958     if( ( i_err = snd_ctl_open( &p_ctl, psz_dev, 0 ) ) < 0 )
959         return;
960
961     if( ( i_err = snd_card_get_name( i_card, &psz_card_name ) ) != 0)
962         psz_card_name = _("Unknown soundcard");
963
964     snd_pcm_info_alloca( &p_pcm_info );
965
966     for (;;)
967     {
968         char *psz_device, *psz_descr;
969         if( ( i_err = snd_ctl_pcm_next_device( p_ctl, &i_pcm_device ) ) < 0 )
970             i_pcm_device = -1;
971         if( i_pcm_device < 0 )
972             break;
973
974         snd_pcm_info_set_device( p_pcm_info, i_pcm_device );
975         snd_pcm_info_set_subdevice( p_pcm_info, 0 );
976         snd_pcm_info_set_stream( p_pcm_info, SND_PCM_STREAM_PLAYBACK );
977
978         if( ( i_err = snd_ctl_pcm_info( p_ctl, p_pcm_info ) ) < 0 )
979         {
980             if( i_err != -ENOENT )
981             {
982                 /*printf( "get_devices_for_card(): "
983                          "snd_ctl_pcm_info() "
984                          "failed (%d:%d): %s.\n", i_card,
985                          i_pcm_device, snd_strerror( -i_err ) );*/
986             }
987             continue;
988         }
989
990         asprintf( &psz_device, "hw:%d,%d", i_card, i_pcm_device );
991         asprintf( &psz_descr, "%s: %s (%s)", psz_card_name,
992                   snd_pcm_info_get_name(p_pcm_info), psz_device );
993
994         p_item->ppsz_list =
995             (const char **)realloc( p_item->ppsz_list,
996                               (p_item->i_list + 2) * sizeof(char *) );
997         p_item->ppsz_list_text =
998             (const char **)realloc( p_item->ppsz_list_text,
999                               (p_item->i_list + 2) * sizeof(char *) );
1000         p_item->ppsz_list[ p_item->i_list ] = psz_device;
1001         p_item->ppsz_list_text[ p_item->i_list ] = psz_descr;
1002         p_item->i_list++;
1003         p_item->ppsz_list[ p_item->i_list ] = NULL;
1004         p_item->ppsz_list_text[ p_item->i_list ] = NULL;
1005     }
1006
1007     snd_ctl_close( p_ctl );
1008 }
1009
1010
1011
1012 static void GetDevices( module_config_t *p_item )
1013 {
1014     int i_card = -1;
1015     int i_err = 0;
1016
1017     if( ( i_err = snd_card_next( &i_card ) ) != 0 )
1018     {
1019         /*printf( "snd_card_next() failed: %s", snd_strerror( -i_err ) );*/
1020         return;
1021     }
1022
1023     while( i_card > -1 )
1024     {
1025         GetDevicesForCard( p_item, i_card );
1026         if( ( i_err = snd_card_next( &i_card ) ) != 0 )
1027         {
1028             /*printf( "snd_card_next() failed: %s", snd_strerror( -i_err ) );*/
1029             break;
1030         }
1031     }
1032 }