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