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