Contrib: upnp/win32, remove strerror use, and other small hacks...
[vlc/asuraparaju-public.git] / modules / audio_output / alsa.c
blob448951333da224e9582195aac87fd4575311a0a8
1 /*****************************************************************************
2 * alsa.c : alsa plugin for vlc
3 *****************************************************************************
4 * Copyright (C) 2000-2001 the VideoLAN team
5 * $Id$
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
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.
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.
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 *****************************************************************************/
27 /*****************************************************************************
28 * Preamble
29 *****************************************************************************/
30 #ifdef HAVE_CONFIG_H
31 # include "config.h"
32 #endif
34 #include <assert.h>
36 #include <vlc_common.h>
37 #include <vlc_plugin.h>
39 #include <errno.h> /* ENOMEM */
40 #include <vlc_dialog.h>
42 #include <vlc_aout.h>
43 #include <vlc_cpu.h>
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>
52 /*#define ALSA_DEBUG*/
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
62 snd_pcm_t * p_snd_pcm;
63 unsigned int i_period_time;
65 #ifdef ALSA_DEBUG
66 snd_output_t * p_snd_stderr;
67 #endif
69 mtime_t start_date;
70 vlc_thread_t thread;
71 vlc_sem_t wait;
74 #define A52_FRAME_NB 1536
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 */
88 #define DEFAULT_ALSA_DEVICE N_("default")
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 * );
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") )
119 set_capability( "audio output", 150 )
120 set_callbacks( Open, Close )
121 vlc_module_end ()
123 /*****************************************************************************
124 * Probe: probe the audio device for available formats and channels
125 *****************************************************************************/
126 static int Probe( aout_instance_t * p_aout,
127 const char * psz_device, const char * psz_iec_device,
128 int *pi_snd_pcm_format )
130 struct aout_sys_t * p_sys = p_aout->output.p_sys;
131 vlc_value_t val, text;
132 int i_ret;
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 );
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 */
142 /* Now test linear PCM capabilities */
143 i_ret = snd_pcm_open( &p_sys->p_snd_pcm, psz_device,
144 SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK );
145 if( i_ret == 0 )
147 int i_channels;
148 snd_pcm_hw_params_t * p_hw;
149 snd_pcm_hw_params_alloca (&p_hw);
151 if ( snd_pcm_hw_params_any( p_sys->p_snd_pcm, p_hw ) < 0 )
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 VLC_EGENERIC;
160 if ( snd_pcm_hw_params_set_format( p_sys->p_snd_pcm, p_hw,
161 *pi_snd_pcm_format ) < 0 )
163 int i_snd_rc = -1;
165 if( *pi_snd_pcm_format != SND_PCM_FORMAT_S16 )
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 );
171 if ( i_snd_rc < 0 )
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 VLC_EGENERIC;
181 i_channels = aout_FormatNbChannels( &p_aout->output.output );
183 while ( i_channels > 0 )
185 if ( !snd_pcm_hw_params_test_channels( p_sys->p_snd_pcm, p_hw,
186 i_channels ) )
188 switch ( i_channels )
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 = (char *)"5.1";
212 var_Change( p_aout, "audio-device",
213 VLC_VAR_ADDCHOICE, &val, &text );
214 break;
218 --i_channels;
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 )
226 if ( !snd_pcm_hw_params_test_channels( p_sys->p_snd_pcm, p_hw, 2 ))
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 );
236 /* Close the previously opened device */
237 snd_pcm_close( p_sys->p_snd_pcm );
239 else if ( i_ret == -EBUSY )
241 msg_Warn( p_aout, "audio device: %s is already in use", psz_device );
244 /* Test for S/PDIF device if needed */
245 if ( psz_iec_device )
247 /* Opening the device should be enough */
248 i_ret = snd_pcm_open( &p_sys->p_snd_pcm, psz_iec_device,
249 SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK );
250 if( i_ret == 0 )
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 );
259 snd_pcm_close( p_sys->p_snd_pcm );
261 else if ( i_ret == -EBUSY )
263 msg_Warn( p_aout, "audio device: %s is already in use",
264 psz_iec_device );
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 )
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." );
280 else
281 var_SetBool( p_aout->p_libvlc, "alsa-working", true );
282 #endif
283 if( val.i_int <= 0 )
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" ) )
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." );
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 VLC_EGENERIC;
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 return VLC_SUCCESS;
310 /*****************************************************************************
311 * Open: create a handle and open an alsa device
312 *****************************************************************************
313 * This function opens an alsa device, through the alsa API.
315 * Note: the only heap-allocated string is psz_device. All the other pointers
316 * are references to psz_device or to stack-allocated data.
317 *****************************************************************************/
318 static int Open( vlc_object_t *p_this )
320 aout_instance_t * p_aout = (aout_instance_t *)p_this;
322 /* Allocate structures */
323 aout_sys_t * p_sys = malloc( sizeof( aout_sys_t ) );
324 if( p_sys == NULL )
325 return VLC_ENOMEM;
326 p_aout->output.p_sys = p_sys;
328 /* Get device name */
329 char *psz_device = var_InheritString( p_aout, "alsa-audio-device" );
330 if( unlikely(psz_device == NULL) )
332 psz_device = strdup( DEFAULT_ALSA_DEVICE );
333 if( unlikely(psz_device == NULL) )
335 free( p_sys );
336 return VLC_ENOMEM;
340 /* Choose the IEC device for S/PDIF output:
341 if the device is overriden by the user then it will be the one
342 otherwise we compute the default device based on the output format. */
343 char *psz_iec_device = NULL;
344 if( AOUT_FMT_NON_LINEAR( &p_aout->output.output ) )
346 if( !strcmp( psz_device, DEFAULT_ALSA_DEVICE ) )
348 unsigned aes3;
350 switch( p_aout->output.output.i_rate )
352 case 48000:
353 aes3 = IEC958_AES3_CON_FS_48000;
354 break;
355 case 44100:
356 aes3 = IEC958_AES3_CON_FS_44100;
357 break;
358 default:
359 aes3 = IEC958_AES3_CON_FS_32000;
360 break;
363 if( asprintf( &psz_iec_device,
364 "iec958:AES0=0x%x,AES1=0x%x,AES2=0x%x,AES3=0x%x",
365 IEC958_AES0_CON_EMPHASIS_NONE | IEC958_AES0_NONAUDIO,
366 IEC958_AES1_CON_ORIGINAL | IEC958_AES1_CON_PCM_CODER,
367 0, aes3 ) == -1 )
369 free( psz_device );
370 free( p_sys );
371 return VLC_ENOMEM;
374 else
375 psz_iec_device = strdup( psz_device );
378 /* Choose the linear PCM format (read the comment above about FPU
379 and float32) */
380 int i_snd_pcm_format; /* Audio format for ALSA's data */
381 if( HAVE_FPU )
382 i_snd_pcm_format = SND_PCM_FORMAT_FLOAT;
383 else
384 i_snd_pcm_format = SND_PCM_FORMAT_S16;
386 /* If the variable doesn't exist then it's the first time we're called
387 and we have to probe the available audio formats and channels */
388 if( var_Type( p_aout, "audio-device" ) == 0
389 && Probe( p_aout, psz_device, psz_iec_device, &i_snd_pcm_format ) )
391 free( psz_iec_device );
392 free( psz_device );
393 free( p_sys );
394 return VLC_EGENERIC;
397 bool spdif = false;
398 switch( var_GetInteger( p_aout, "audio-device") )
400 case AOUT_VAR_5_1:
401 p_aout->output.output.i_physical_channels
402 = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER
403 | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT
404 | AOUT_CHAN_LFE;
405 free( psz_device );
406 psz_device = strdup( "surround51" );
407 break;
408 case AOUT_VAR_2F2R:
409 p_aout->output.output.i_physical_channels
410 = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT
411 | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT;
412 free( psz_device );
413 psz_device = strdup( "surround40" );
414 break;
415 case AOUT_VAR_STEREO:
416 p_aout->output.output.i_physical_channels
417 = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT;
418 break;
419 case AOUT_VAR_MONO:
420 p_aout->output.output.i_physical_channels = AOUT_CHAN_CENTER;
421 break;
422 case AOUT_VAR_SPDIF:
423 spdif = true;
424 free( psz_device );
425 psz_device = psz_iec_device;
426 psz_iec_device = NULL;
427 break;
428 default:
429 /* This should not happen ! */
430 msg_Err( p_aout, "cannot find audio-device" );
431 free( psz_iec_device );
432 free( psz_device );
433 free( p_sys );
434 return VLC_EGENERIC;
437 #ifdef ALSA_DEBUG
438 snd_output_stdio_attach( &p_sys->p_snd_stderr, stderr, 0 );
439 #endif
441 /* Open the device */
442 msg_Dbg( p_aout, "opening ALSA device `%s'", psz_device );
443 for( unsigned i = 10; i; i-- )
445 int val = snd_pcm_open( &p_sys->p_snd_pcm, psz_device,
446 SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK );
447 if( val == 0 )
448 break; /* success! */
450 if( val != -EBUSY )
452 msg_Err( p_aout, "cannot open ALSA device `%s' (%s)",
453 psz_device, snd_strerror( val ) );
454 dialog_Fatal( p_aout, _("Audio output failed"),
455 _("VLC could not open the ALSA device \"%s\" (%s)."),
456 psz_device, snd_strerror( val ) );
457 free( psz_device );
458 free( p_sys );
459 return VLC_EGENERIC;
462 /* Since it seems snd_pcm_close hasn't really released the device at
463 the time it returns, probe if the device is available in loop for 1s.
464 We cannot use blocking mode since the we would wait indefinitely when
465 switching from a dmx device to surround51. */
466 if( i == 1 )
468 msg_Err( p_aout, "audio device %s is already in use",
469 psz_device );
470 dialog_Fatal( p_aout, _("Audio output failed"),
471 _("The audio device \"%s\" is already in use."),
472 psz_device );
473 free( psz_device );
474 free( p_sys );
475 return VLC_EGENERIC;
477 msleep( CLOCK_FREQ / 10 );
479 free( psz_device );
481 /* We want blocking mode */
482 snd_pcm_nonblock( p_sys->p_snd_pcm, 0 );
484 snd_pcm_uframes_t i_buffer_size;
485 snd_pcm_uframes_t i_period_size;
486 int i_channels;
488 if( spdif )
490 i_buffer_size = ALSA_SPDIF_BUFFER_SIZE;
491 i_snd_pcm_format = SND_PCM_FORMAT_S16;
492 i_channels = 2;
494 p_aout->output.i_nb_samples = i_period_size = ALSA_SPDIF_PERIOD_SIZE;
495 p_aout->output.output.i_bytes_per_frame = AOUT_SPDIF_SIZE;
496 p_aout->output.output.i_frame_length = A52_FRAME_NB;
498 aout_VolumeNoneInit( p_aout );
500 else
502 i_buffer_size = ALSA_DEFAULT_BUFFER_SIZE;
503 i_channels = aout_FormatNbChannels( &p_aout->output.output );
505 p_aout->output.i_nb_samples = i_period_size = ALSA_DEFAULT_PERIOD_SIZE;
507 aout_VolumeSoftInit( p_aout );
510 p_aout->output.pf_play = Play;
512 snd_pcm_hw_params_t *p_hw;
513 snd_pcm_sw_params_t *p_sw;
515 snd_pcm_hw_params_alloca(&p_hw);
516 snd_pcm_sw_params_alloca(&p_sw);
518 /* Due to some bugs in alsa with some drivers, we need to retry in s16l
519 if snd_pcm_hw_params fails in fl32 */
520 int val;
521 retry:
522 /* Get Initial hardware parameters */
523 val = snd_pcm_hw_params_any( p_sys->p_snd_pcm, p_hw );
524 if( val < 0 )
526 msg_Err( p_aout, "unable to retrieve hardware parameters (%s)",
527 snd_strerror( val ) );
528 goto error;
531 /* Set format. */
532 val = snd_pcm_hw_params_set_format( p_sys->p_snd_pcm, p_hw,
533 i_snd_pcm_format );
534 if( val < 0 )
536 if( i_snd_pcm_format != SND_PCM_FORMAT_S16 )
538 i_snd_pcm_format = SND_PCM_FORMAT_S16;
539 val = snd_pcm_hw_params_set_format( p_sys->p_snd_pcm,
540 p_hw, i_snd_pcm_format );
542 if ( val < 0 )
544 msg_Err( p_aout, "unable to set stream sample size and "
545 "word order (%s)", snd_strerror( val ) );
546 goto error;
550 vlc_fourcc_t i_vlc_pcm_format;
551 if( spdif )
552 i_vlc_pcm_format = VLC_CODEC_SPDIFL;
553 else
554 switch( i_snd_pcm_format )
556 case SND_PCM_FORMAT_FLOAT:
557 i_vlc_pcm_format = VLC_CODEC_FL32;
558 break;
559 case SND_PCM_FORMAT_S16:
560 i_vlc_pcm_format = VLC_CODEC_S16N;
561 break;
562 default:
563 assert(0);
565 p_aout->output.output.i_format = i_vlc_pcm_format;
567 val = snd_pcm_hw_params_set_access( p_sys->p_snd_pcm, p_hw,
568 SND_PCM_ACCESS_RW_INTERLEAVED );
569 if( val < 0 )
571 msg_Err( p_aout, "unable to set interleaved stream format (%s)",
572 snd_strerror( val ) );
573 goto error;
576 /* Set channels. */
577 val = snd_pcm_hw_params_set_channels( p_sys->p_snd_pcm, p_hw, i_channels );
578 if( val < 0 )
580 msg_Err( p_aout, "unable to set number of output channels (%s)",
581 snd_strerror( val ) );
582 goto error;
585 /* Set rate. */
586 unsigned i_old_rate = p_aout->output.output.i_rate;
587 val = snd_pcm_hw_params_set_rate_near( p_sys->p_snd_pcm, p_hw,
588 &p_aout->output.output.i_rate,
589 NULL );
590 if( val < 0 || p_aout->output.output.i_rate != i_old_rate )
592 msg_Warn( p_aout, "The rate %d Hz is not supported by your " \
593 "hardware. Using %d Hz instead.\n", i_old_rate, \
594 p_aout->output.output.i_rate );
597 /* Set period size. */
598 val = snd_pcm_hw_params_set_period_size_near( p_sys->p_snd_pcm, p_hw,
599 &i_period_size, NULL );
600 if( val < 0 )
602 msg_Err( p_aout, "unable to set period size (%s)",
603 snd_strerror( val ) );
604 goto error;
606 p_aout->output.i_nb_samples = i_period_size;
608 /* Set buffer size. */
609 val = snd_pcm_hw_params_set_buffer_size_near( p_sys->p_snd_pcm, p_hw,
610 &i_buffer_size );
611 if( val )
613 msg_Err( p_aout, "unable to set buffer size (%s)",
614 snd_strerror( val ) );
615 goto error;
618 /* Commit hardware parameters. */
619 val = snd_pcm_hw_params( p_sys->p_snd_pcm, p_hw );
620 if( val < 0 )
622 if( i_snd_pcm_format == SND_PCM_FORMAT_FLOAT )
624 i_snd_pcm_format = SND_PCM_FORMAT_S16;
625 p_aout->output.output.i_format = VLC_CODEC_S16N;
626 msg_Warn( p_aout, "unable to commit hardware configuration "
627 "with fl32 samples (%s). Retrying with s16l.",
628 snd_strerror( val ) );
629 goto retry;
631 msg_Err( p_aout, "unable to commit hardware configuration (%s)",
632 snd_strerror( val ) );
633 goto error;
636 val = snd_pcm_hw_params_get_period_time( p_hw, &p_sys->i_period_time,
637 NULL );
638 if( val < 0 )
640 msg_Err( p_aout, "unable to get period time (%s)",
641 snd_strerror( val ) );
642 goto error;
645 /* Get Initial software parameters */
646 snd_pcm_sw_params_current( p_sys->p_snd_pcm, p_sw );
648 snd_pcm_sw_params_set_avail_min( p_sys->p_snd_pcm, p_sw,
649 p_aout->output.i_nb_samples );
650 /* start playing when one period has been written */
651 val = snd_pcm_sw_params_set_start_threshold( p_sys->p_snd_pcm, p_sw,
652 ALSA_DEFAULT_PERIOD_SIZE);
653 if( val < 0 )
655 msg_Err( p_aout, "unable to set start threshold (%s)",
656 snd_strerror( val ) );
657 goto error;
660 /* Commit software parameters. */
661 if ( snd_pcm_sw_params( p_sys->p_snd_pcm, p_sw ) < 0 )
663 msg_Err( p_aout, "unable to set software configuration" );
664 goto error;
667 #ifdef ALSA_DEBUG
668 snd_output_printf( p_sys->p_snd_stderr, "\nALSA hardware setup:\n\n" );
669 snd_pcm_dump_hw_setup( p_sys->p_snd_pcm, p_sys->p_snd_stderr );
670 snd_output_printf( p_sys->p_snd_stderr, "\nALSA software setup:\n\n" );
671 snd_pcm_dump_sw_setup( p_sys->p_snd_pcm, p_sys->p_snd_stderr );
672 snd_output_printf( p_sys->p_snd_stderr, "\n" );
673 #endif
675 p_sys->start_date = 0;
676 vlc_sem_init( &p_sys->wait, 0 );
678 /* Create ALSA thread and wait for its readiness. */
679 if( vlc_clone( &p_sys->thread, ALSAThread, p_aout,
680 VLC_THREAD_PRIORITY_OUTPUT ) )
682 msg_Err( p_aout, "cannot create ALSA thread (%m)" );
683 vlc_sem_destroy( &p_sys->wait );
684 goto error;
687 return 0;
689 error:
690 snd_pcm_close( p_sys->p_snd_pcm );
691 #ifdef ALSA_DEBUG
692 snd_output_close( p_sys->p_snd_stderr );
693 #endif
694 free( p_sys );
695 return VLC_EGENERIC;
698 static void PlayIgnore( aout_instance_t *p_aout )
699 { /* Already playing - nothing to do */
700 (void) p_aout;
703 /*****************************************************************************
704 * Play: start playback
705 *****************************************************************************/
706 static void Play( aout_instance_t *p_aout )
708 p_aout->output.pf_play = PlayIgnore;
710 /* get the playing date of the first aout buffer */
711 p_aout->output.p_sys->start_date =
712 aout_FifoFirstDate( p_aout, &p_aout->output.fifo );
714 /* wake up the audio output thread */
715 sem_post( &p_aout->output.p_sys->wait );
718 /*****************************************************************************
719 * Close: close the ALSA device
720 *****************************************************************************/
721 static void Close( vlc_object_t *p_this )
723 aout_instance_t *p_aout = (aout_instance_t *)p_this;
724 struct aout_sys_t * p_sys = p_aout->output.p_sys;
726 /* Make sure that the thread will stop once it is waken up */
727 vlc_cancel( p_sys->thread );
728 vlc_join( p_sys->thread, NULL );
729 vlc_sem_destroy( &p_sys->wait );
731 snd_pcm_close( p_sys->p_snd_pcm );
732 #ifdef ALSA_DEBUG
733 snd_output_close( p_sys->p_snd_stderr );
734 #endif
735 free( p_sys );
738 static void pcm_drop(void *pcm)
740 snd_pcm_drop(pcm);
743 /*****************************************************************************
744 * ALSAThread: asynchronous thread used to DMA the data to the device
745 *****************************************************************************/
746 static void* ALSAThread( void *data )
748 aout_instance_t * p_aout = data;
749 struct aout_sys_t * p_sys = p_aout->output.p_sys;
751 /* Wait for the exact time to start playing (avoids resampling) */
752 vlc_sem_wait( &p_sys->wait );
753 mwait( p_sys->start_date - AOUT_PTS_TOLERANCE / 4 );
755 vlc_cleanup_push( pcm_drop, p_sys->p_snd_pcm );
756 for(;;)
757 ALSAFill( p_aout );
759 assert(0);
760 vlc_cleanup_pop();
763 /*****************************************************************************
764 * ALSAFill: function used to fill the ALSA buffer as much as possible
765 *****************************************************************************/
766 static void ALSAFill( aout_instance_t * p_aout )
768 struct aout_sys_t * p_sys = p_aout->output.p_sys;
769 snd_pcm_t *p_pcm = p_sys->p_snd_pcm;
770 snd_pcm_status_t * p_status;
771 int i_snd_rc;
772 mtime_t next_date;
774 int canc = vlc_savecancel();
775 /* Fill in the buffer until space or audio output buffer shortage */
777 /* Get the status */
778 snd_pcm_status_alloca(&p_status);
779 i_snd_rc = snd_pcm_status( p_pcm, p_status );
780 if( i_snd_rc < 0 )
782 msg_Err( p_aout, "cannot get device status" );
783 goto error;
786 /* Handle buffer underruns and get the status again */
787 if( snd_pcm_status_get_state( p_status ) == SND_PCM_STATE_XRUN )
789 /* Prepare the device */
790 i_snd_rc = snd_pcm_prepare( p_pcm );
791 if( i_snd_rc )
793 msg_Err( p_aout, "cannot recover from buffer underrun" );
794 goto error;
797 msg_Dbg( p_aout, "recovered from buffer underrun" );
799 /* Get the new status */
800 i_snd_rc = snd_pcm_status( p_pcm, p_status );
801 if( i_snd_rc < 0 )
803 msg_Err( p_aout, "cannot get device status after recovery" );
804 goto error;
807 /* Underrun, try to recover as quickly as possible */
808 next_date = mdate();
810 else
812 /* Here the device should be in RUNNING state, p_status is valid. */
813 snd_pcm_sframes_t delay = snd_pcm_status_get_delay( p_status );
814 if( delay == 0 ) /* workaround buggy alsa drivers */
815 if( snd_pcm_delay( p_pcm, &delay ) < 0 )
816 delay = 0; /* FIXME: use a positive minimal delay */
818 size_t i_bytes = snd_pcm_frames_to_bytes( p_pcm, delay );
819 mtime_t delay_us = CLOCK_FREQ * i_bytes
820 / p_aout->output.output.i_bytes_per_frame
821 / p_aout->output.output.i_rate
822 * p_aout->output.output.i_frame_length;
824 #ifdef ALSA_DEBUG
825 snd_pcm_state_t state = snd_pcm_status_get_state( p_status );
826 if( state != SND_PCM_STATE_RUNNING )
827 msg_Err( p_aout, "pcm status (%d) != RUNNING", state );
829 msg_Dbg( p_aout, "Delay is %ld frames (%zu bytes)", delay, i_bytes );
831 msg_Dbg( p_aout, "Bytes per frame: %d", p_aout->output.output.i_bytes_per_frame );
832 msg_Dbg( p_aout, "Rate: %d", p_aout->output.output.i_rate );
833 msg_Dbg( p_aout, "Frame length: %d", p_aout->output.output.i_frame_length );
834 msg_Dbg( p_aout, "Next date: in %"PRId64" microseconds", delay_us );
835 #endif
836 next_date = mdate() + delay_us;
839 block_t *p_buffer = aout_OutputNextBuffer( p_aout, next_date,
840 (p_aout->output.output.i_format == VLC_CODEC_SPDIFL) );
842 /* Audio output buffer shortage -> stop the fill process and wait */
843 if( p_buffer == NULL )
844 goto error;
846 block_cleanup_push( p_buffer );
847 for (;;)
849 int n = snd_pcm_poll_descriptors_count(p_pcm);
850 struct pollfd ufd[n];
851 unsigned short revents;
853 snd_pcm_poll_descriptors(p_pcm, ufd, n);
856 vlc_restorecancel(canc);
857 poll(ufd, n, -1);
858 canc = vlc_savecancel();
859 snd_pcm_poll_descriptors_revents(p_pcm, ufd, n, &revents);
861 while(!revents);
863 if(revents & POLLOUT)
865 i_snd_rc = snd_pcm_writei( p_pcm, p_buffer->p_buffer,
866 p_buffer->i_nb_samples );
867 if( i_snd_rc != -ESTRPIPE )
868 break;
871 /* a suspend event occurred
872 * (stream is suspended and waiting for an application recovery) */
873 msg_Dbg( p_aout, "entering in suspend mode, trying to resume..." );
875 while( ( i_snd_rc = snd_pcm_resume( p_pcm ) ) == -EAGAIN )
877 vlc_restorecancel(canc);
878 msleep(CLOCK_FREQ); /* device still suspended, wait... */
879 canc = vlc_savecancel();
882 if( i_snd_rc < 0 )
883 /* Device does not support resuming, restart it */
884 i_snd_rc = snd_pcm_prepare( p_pcm );
888 if( i_snd_rc < 0 )
889 msg_Err( p_aout, "cannot write: %s", snd_strerror( i_snd_rc ) );
891 vlc_restorecancel(canc);
892 vlc_cleanup_run();
893 return;
895 error:
896 if( i_snd_rc < 0 )
897 msg_Err( p_aout, "ALSA error: %s", snd_strerror( i_snd_rc ) );
899 vlc_restorecancel(canc);
900 msleep(p_sys->i_period_time / 2);
903 /*****************************************************************************
904 * config variable callback
905 *****************************************************************************/
906 static int FindDevicesCallback( vlc_object_t *p_this, char const *psz_name,
907 vlc_value_t newval, vlc_value_t oldval, void *p_unused )
909 module_config_t *p_item;
910 (void)newval;
911 (void)oldval;
912 (void)p_unused;
914 p_item = config_FindConfig( p_this, psz_name );
915 if( !p_item ) return VLC_SUCCESS;
917 /* Clear-up the current list */
918 if( p_item->i_list )
920 int i;
922 /* Keep the first entrie */
923 for( i = 1; i < p_item->i_list; i++ )
925 free( (char *)p_item->ppsz_list[i] );
926 free( (char *)p_item->ppsz_list_text[i] );
928 /* TODO: Remove when no more needed */
929 p_item->ppsz_list[i] = NULL;
930 p_item->ppsz_list_text[i] = NULL;
932 p_item->i_list = 1;
934 GetDevices( p_this, p_item );
936 /* Signal change to the interface */
937 p_item->b_dirty = true;
939 return VLC_SUCCESS;
943 static void GetDevicesForCard( vlc_object_t *obj, module_config_t *p_item,
944 int i_card )
946 int i_pcm_device = -1;
947 int i_err = 0;
948 snd_pcm_info_t *p_pcm_info;
949 snd_ctl_t *p_ctl;
950 char psz_dev[4 + 3 * sizeof(int)];
951 char *psz_card_name;
953 snprintf( psz_dev, sizeof (psz_dev), "hw:%u", i_card );
955 if( ( i_err = snd_ctl_open( &p_ctl, psz_dev, 0 ) ) < 0 )
956 return;
958 if( ( i_err = snd_card_get_name( i_card, &psz_card_name ) ) != 0)
959 psz_card_name = _("Unknown soundcard");
961 snd_pcm_info_alloca( &p_pcm_info );
963 for (;;)
965 char *psz_device, *psz_descr;
966 if( ( i_err = snd_ctl_pcm_next_device( p_ctl, &i_pcm_device ) ) < 0 )
967 i_pcm_device = -1;
968 if( i_pcm_device < 0 )
969 break;
971 snd_pcm_info_set_device( p_pcm_info, i_pcm_device );
972 snd_pcm_info_set_subdevice( p_pcm_info, 0 );
973 snd_pcm_info_set_stream( p_pcm_info, SND_PCM_STREAM_PLAYBACK );
975 if( ( i_err = snd_ctl_pcm_info( p_ctl, p_pcm_info ) ) < 0 )
977 if( i_err != -ENOENT )
978 msg_Err( obj, "cannot get PCM device %d:%d infos: %s", i_card,
979 i_pcm_device, snd_strerror( -i_err ) );
980 continue;
983 if( asprintf( &psz_device, "plughw:%u,%u", i_card, i_pcm_device ) == -1 )
984 continue;
985 if( asprintf( &psz_descr, "%s: %s (%s)", psz_card_name,
986 snd_pcm_info_get_name(p_pcm_info), psz_device ) == -1 )
988 free( psz_device );
989 continue;
992 msg_Dbg( obj, " %s", psz_descr );
994 if( p_item )
996 p_item->ppsz_list = xrealloc( p_item->ppsz_list,
997 (p_item->i_list + 2) * sizeof(char *) );
998 p_item->ppsz_list_text = xrealloc( p_item->ppsz_list_text,
999 (p_item->i_list + 2) * sizeof(char *) );
1000 p_item->ppsz_list[ p_item->i_list ] = psz_device;
1001 p_item->ppsz_list_text[ p_item->i_list ] = psz_descr;
1002 p_item->i_list++;
1003 p_item->ppsz_list[ p_item->i_list ] = NULL;
1004 p_item->ppsz_list_text[ p_item->i_list ] = NULL;
1006 else
1008 free( psz_device );
1009 free( psz_descr );
1013 snd_ctl_close( p_ctl );
1017 static void GetDevices( vlc_object_t *obj, module_config_t *p_item )
1019 int i_card = -1;
1020 int i_err;
1022 msg_Dbg( obj, "Available alsa output devices:" );
1023 while( (i_err = snd_card_next( &i_card )) == 0 && i_card > -1 )
1024 GetDevicesForCard( obj, p_item, i_card );
1026 if( i_err )
1027 msg_Err( obj, "cannot enumerate cards: %s", snd_strerror( -i_err ) );