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