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