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