]> git.sesse.net Git - vlc/blob - modules/audio_output/alsa.c
Removes trailing spaces. Removes tabs.
[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 const char *ppsz_devices[] = { "default" };
98 static const 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     /* start playing when one period has been written */
657     i_snd_rc = snd_pcm_sw_params_set_start_threshold( p_sys->p_snd_pcm, p_sw,
658                                                       ALSA_DEFAULT_PERIOD_SIZE);
659     if( i_snd_rc < 0 )
660     {
661         msg_Err( p_aout, "unable to set start threshold (%s)",
662                           snd_strerror( i_snd_rc ) );
663         goto error;
664     }
665
666     /* Commit software parameters. */
667     if ( snd_pcm_sw_params( p_sys->p_snd_pcm, p_sw ) < 0 )
668     {
669         msg_Err( p_aout, "unable to set software configuration" );
670         goto error;
671     }
672
673 #ifdef ALSA_DEBUG
674     snd_output_printf( p_sys->p_snd_stderr, "\nALSA hardware setup:\n\n" );
675     snd_pcm_dump_hw_setup( p_sys->p_snd_pcm, p_sys->p_snd_stderr );
676     snd_output_printf( p_sys->p_snd_stderr, "\nALSA software setup:\n\n" );
677     snd_pcm_dump_sw_setup( p_sys->p_snd_pcm, p_sys->p_snd_stderr );
678     snd_output_printf( p_sys->p_snd_stderr, "\n" );
679 #endif
680
681     /* Create ALSA thread and wait for its readiness. */
682     if( vlc_thread_create( p_aout, "aout", ALSAThread,
683                            VLC_THREAD_PRIORITY_OUTPUT, VLC_FALSE ) )
684     {
685         msg_Err( p_aout, "cannot create ALSA thread (%s)", strerror(errno) );
686         goto error;
687     }
688
689     return 0;
690
691 error:
692     snd_pcm_close( p_sys->p_snd_pcm );
693 #ifdef ALSA_DEBUG
694     snd_output_close( p_sys->p_snd_stderr );
695 #endif
696     free( p_sys );
697     return VLC_EGENERIC;
698 }
699
700 /*****************************************************************************
701  * Play: nothing to do
702  *****************************************************************************/
703 static void Play( aout_instance_t *p_aout )
704 {
705     if( !p_aout->output.p_sys->b_playing )
706     {
707         p_aout->output.p_sys->b_playing = 1;
708
709         /* get the playing date of the first aout buffer */
710         p_aout->output.p_sys->start_date =
711             aout_FifoFirstDate( p_aout, &p_aout->output.fifo );
712
713         /* wake up the audio output thread */
714         vlc_mutex_lock( &p_aout->output.p_sys->lock );
715         vlc_cond_signal( &p_aout->output.p_sys->wait );
716         vlc_mutex_unlock( &p_aout->output.p_sys->lock );
717     }
718 }
719
720 /*****************************************************************************
721  * Close: close the ALSA device
722  *****************************************************************************/
723 static void Close( vlc_object_t *p_this )
724 {
725     aout_instance_t *p_aout = (aout_instance_t *)p_this;
726     struct aout_sys_t * p_sys = p_aout->output.p_sys;
727     int i_snd_rc;
728
729     /* make sure the audio output thread is waken up */
730     vlc_mutex_lock( &p_aout->output.p_sys->lock );
731     vlc_cond_signal( &p_aout->output.p_sys->wait );
732     vlc_mutex_unlock( &p_aout->output.p_sys->lock );
733
734     vlc_object_kill( p_aout );
735     vlc_thread_join( p_aout );
736     p_aout->b_die = VLC_FALSE;
737
738     i_snd_rc = snd_pcm_close( p_sys->p_snd_pcm );
739
740     if( i_snd_rc > 0 )
741     {
742         msg_Err( p_aout, "failed closing ALSA device (%s)",
743                          snd_strerror( i_snd_rc ) );
744     }
745
746 #ifdef ALSA_DEBUG
747     snd_output_close( p_sys->p_snd_stderr );
748 #endif
749
750     free( p_sys );
751 }
752
753 /*****************************************************************************
754  * ALSAThread: asynchronous thread used to DMA the data to the device
755  *****************************************************************************/
756 static int ALSAThread( aout_instance_t * p_aout )
757 {
758     p_aout->output.p_sys->p_status =
759         (snd_pcm_status_t *)malloc(snd_pcm_status_sizeof());
760
761     /* Wait for the exact time to start playing (avoids resampling) */
762     vlc_mutex_lock( &p_aout->output.p_sys->lock );
763     if( !p_aout->output.p_sys->start_date )
764         vlc_cond_wait( &p_aout->output.p_sys->wait,
765                        &p_aout->output.p_sys->lock );
766     vlc_mutex_unlock( &p_aout->output.p_sys->lock );
767
768     mwait( p_aout->output.p_sys->start_date - AOUT_PTS_TOLERANCE / 4 );
769
770     while ( !p_aout->b_die )
771     {
772         ALSAFill( p_aout );
773     }
774
775     free( p_aout->output.p_sys->p_status );
776     return 0;
777 }
778
779 /*****************************************************************************
780  * ALSAFill: function used to fill the ALSA buffer as much as possible
781  *****************************************************************************/
782 static void ALSAFill( aout_instance_t * p_aout )
783 {
784     struct aout_sys_t * p_sys = p_aout->output.p_sys;
785     aout_buffer_t * p_buffer;
786     snd_pcm_status_t * p_status = p_sys->p_status;
787     int i_snd_rc;
788     mtime_t next_date;
789
790     /* Fill in the buffer until space or audio output buffer shortage */
791     {
792         /* Get the status */
793         i_snd_rc = snd_pcm_status( p_sys->p_snd_pcm, p_status );
794         if( i_snd_rc < 0 )
795         {
796             msg_Err( p_aout, "unable to get the device's status (%s)",
797                              snd_strerror( i_snd_rc ) );
798
799             msleep( p_sys->i_period_time >> 1 );
800             return;
801         }
802
803         /* Handle buffer underruns and reget the status */
804         if( snd_pcm_status_get_state( p_status ) == SND_PCM_STATE_XRUN )
805         {
806             /* Prepare the device */
807             i_snd_rc = snd_pcm_prepare( p_sys->p_snd_pcm );
808
809             if( i_snd_rc == 0 )
810             {
811                 msg_Dbg( p_aout, "recovered from buffer underrun" );
812
813                 /* Reget the status */
814                 i_snd_rc = snd_pcm_status( p_sys->p_snd_pcm, p_status );
815                 if( i_snd_rc < 0 )
816                 {
817                     msg_Err( p_aout, "unable to get the device's status after "
818                              "recovery (%s)", snd_strerror( i_snd_rc ) );
819
820                     msleep( p_sys->i_period_time >> 1 );
821                     return;
822                 }
823             }
824             else
825             {
826                 msg_Err( p_aout, "unable to recover from buffer underrun" );
827
828                 msleep( p_sys->i_period_time >> 1 );
829                 return;
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 either in the RUNNING state.
838              * p_status is valid. */
839
840 #if 0
841     /* This apparently does not work correctly in Alsa 1.0.11 */
842             snd_pcm_status_get_tstamp( p_status, &ts_next );
843             next_date = (mtime_t)ts_next.tv_sec * 1000000 + ts_next.tv_usec;
844             if( next_date )
845             {
846                 next_date += (mtime_t)snd_pcm_status_get_delay(p_status)
847                         * 1000000 / p_aout->output.output.i_rate;
848             }
849             else
850 #endif
851             {
852                 /* With screwed ALSA drivers the timestamp is always zero;
853                  * use another method then */
854                 snd_pcm_sframes_t delay = 0;
855
856                 snd_pcm_delay( p_sys->p_snd_pcm, &delay );
857                 next_date = mdate() + (mtime_t)(delay) * 1000000 /
858                           p_aout->output.output.i_rate
859                         * p_aout->output.output.i_frame_length;
860             }
861         }
862
863         p_buffer = aout_OutputNextBuffer( p_aout, next_date,
864                         (p_aout->output.output.i_format ==
865                          VLC_FOURCC('s','p','d','i')) );
866
867         /* Audio output buffer shortage -> stop the fill process and wait */
868         if( p_buffer == NULL )
869         {
870             msleep( p_sys->i_period_time >> 1 );
871             return;
872         }
873
874         i_snd_rc = snd_pcm_writei( p_sys->p_snd_pcm, p_buffer->p_buffer,
875                                    p_buffer->i_nb_samples );
876
877         if( i_snd_rc < 0 )
878         {
879             msg_Err( p_aout, "write failed (%s)",
880                              snd_strerror( i_snd_rc ) );
881         }
882
883         aout_BufferFree( p_buffer );
884     }
885 }
886
887 static void GetDevicesForCard(module_config_t *p_item, int i_card);
888 static void GetDevices( module_config_t *p_item );
889
890 /*****************************************************************************
891  * config variable callback
892  *****************************************************************************/
893 static int FindDevicesCallback( vlc_object_t *p_this, char const *psz_name,
894                                vlc_value_t newval, vlc_value_t oldval, void *p_unused )
895 {
896     module_config_t *p_item;
897     int i;
898
899     p_item = config_FindConfig( p_this, psz_name );
900     if( !p_item ) return VLC_SUCCESS;
901
902     /* Clear-up the current list */
903     if( p_item->i_list )
904     {
905         /* Keep the first entrie */
906         for( i = 1; i < p_item->i_list; i++ )
907         {
908             free( (char *)p_item->ppsz_list[i] );
909             free( (char *)p_item->ppsz_list_text[i] );
910         }
911         /* TODO: Remove when no more needed */
912         p_item->ppsz_list[i] = NULL;
913         p_item->ppsz_list_text[i] = NULL;
914     }
915     p_item->i_list = 1;
916
917     GetDevices( p_item );
918
919     /* Signal change to the interface */
920     p_item->b_dirty = VLC_TRUE;
921
922     return VLC_SUCCESS;
923
924 }
925
926
927 static void GetDevicesForCard(module_config_t *p_item, int i_card)
928 {
929     int i_pcm_device = -1;
930     int i_err = 0;
931     snd_pcm_info_t *p_pcm_info;
932     snd_ctl_t *p_ctl;
933     char psz_dev[64];
934     char *psz_card_name;
935  
936     sprintf(psz_dev, "hw:%i", i_card);
937  
938     if (( i_err = snd_ctl_open(&p_ctl, psz_dev, 0)) < 0 )
939     {
940         return;
941     }
942  
943     if ((i_err = snd_card_get_name(i_card, &psz_card_name)) != 0)
944     {
945         psz_card_name = _("Unknown soundcard");
946     }
947
948     snd_pcm_info_alloca(&p_pcm_info);
949
950     for (;;)
951     {
952         char *psz_device, *psz_descr;
953         if ((i_err = snd_ctl_pcm_next_device(p_ctl, &i_pcm_device)) < 0)
954         {
955             i_pcm_device = -1;
956         }
957         if ( i_pcm_device < 0 )
958             break;
959
960         snd_pcm_info_set_device(p_pcm_info, i_pcm_device);
961         snd_pcm_info_set_subdevice(p_pcm_info, 0);
962         snd_pcm_info_set_stream(p_pcm_info, SND_PCM_STREAM_PLAYBACK);
963
964         if ((i_err = snd_ctl_pcm_info(p_ctl, p_pcm_info)) < 0)
965         {
966             if (i_err != -ENOENT)
967             {
968 /*                printf("get_devices_for_card(): "
969                          "snd_ctl_pcm_info() "
970                          "failed (%d:%d): %s.\n", i_card,
971                          i_pcm_device, snd_strerror(-i_err));*/
972             }
973             continue;
974         }
975
976         asprintf( &psz_device, "hw:%d,%d", i_card, i_pcm_device );
977         asprintf( &psz_descr, "%s: %s (%s)", psz_card_name,
978                   snd_pcm_info_get_name(p_pcm_info), psz_device );
979
980         p_item->ppsz_list =
981             (const char **)realloc( p_item->ppsz_list,
982                               (p_item->i_list + 2) * sizeof(char *) );
983         p_item->ppsz_list_text =
984             (const char **)realloc( p_item->ppsz_list_text,
985                               (p_item->i_list + 2) * sizeof(char *) );
986         p_item->ppsz_list[ p_item->i_list ] = psz_device;
987         p_item->ppsz_list_text[ p_item->i_list ] = psz_descr;
988         p_item->i_list++;
989         p_item->ppsz_list[ p_item->i_list ] = NULL;
990         p_item->ppsz_list_text[ p_item->i_list ] = NULL;
991     }
992
993     snd_ctl_close( p_ctl );
994 }
995
996
997
998 static void GetDevices( module_config_t *p_item )
999 {
1000     int i_card = -1;
1001     int i_err = 0;
1002  
1003     if ((i_err = snd_card_next(&i_card)) != 0)
1004     {
1005 //        g_warning("snd_next_card() failed: %s", snd_strerror(-err));
1006         return;
1007     }
1008  
1009     while (i_card > -1)
1010     {
1011         GetDevicesForCard(p_item, i_card);
1012         if ((i_err = snd_card_next(&i_card)) != 0)
1013         {
1014 //            g_warning("snd_next_card() failed: %s",
1015 //                  snd_strerror(-err));
1016             break;
1017         }
1018     }
1019 }