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