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