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