1 /*****************************************************************************
2 * alsa.c : alsa plugin for vlc
3 *****************************************************************************
4 * Copyright (C) 2000-2001 the VideoLAN team
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 /*****************************************************************************
29 *****************************************************************************/
34 #include <vlc_common.h>
35 #include <vlc_plugin.h>
37 #include <errno.h> /* ENOMEM */
38 #include <vlc_dialog.h>
44 Note: we use the new API which is available since 0.9.0beta10a. */
45 #define ALSA_PCM_NEW_HW_PARAMS_API
46 #define ALSA_PCM_NEW_SW_PARAMS_API
47 #include <alsa/asoundlib.h>
48 #include <alsa/version.h>
50 /*#define ALSA_DEBUG*/
52 /*****************************************************************************
53 * aout_sys_t: ALSA audio output method descriptor
54 *****************************************************************************
55 * This structure is part of the audio output thread descriptor.
56 * It describes the ALSA specific properties of an audio device.
57 *****************************************************************************/
60 snd_pcm_t * p_snd_pcm;
61 unsigned int i_period_time;
64 snd_output_t * p_snd_stderr;
72 #define A52_FRAME_NB 1536
74 /* These values are in frames.
75 To convert them to a number of bytes you have to multiply them by the
76 number of channel(s) (eg. 2 for stereo) and the size of a sample (eg.
78 #define ALSA_DEFAULT_PERIOD_SIZE 1024
79 #define ALSA_DEFAULT_BUFFER_SIZE ( ALSA_DEFAULT_PERIOD_SIZE << 8 )
80 #define ALSA_SPDIF_PERIOD_SIZE A52_FRAME_NB
81 #define ALSA_SPDIF_BUFFER_SIZE ( ALSA_SPDIF_PERIOD_SIZE << 4 )
82 /* Why << 4 ? --Meuuh */
83 /* Why not ? --Bozo */
86 #define DEFAULT_ALSA_DEVICE N_("default")
88 /*****************************************************************************
90 *****************************************************************************/
91 static int Open ( vlc_object_t * );
92 static void Close ( vlc_object_t * );
93 static void Play ( aout_instance_t * );
94 static void* ALSAThread ( void * );
95 static void ALSAFill ( aout_instance_t * );
96 static int FindDevicesCallback( vlc_object_t *p_this, char const *psz_name,
97 vlc_value_t newval, vlc_value_t oldval, void *p_unused );
99 /*****************************************************************************
101 *****************************************************************************/
102 static const char *const ppsz_devices[] = { "default" };
103 static const char *const ppsz_devices_text[] = { N_("Default") };
105 set_shortname( "ALSA" )
106 set_description( N_("ALSA audio output") )
107 set_category( CAT_AUDIO )
108 set_subcategory( SUBCAT_AUDIO_AOUT )
109 add_string( "alsa-audio-device", DEFAULT_ALSA_DEVICE, aout_FindAndRestart,
110 N_("ALSA Device Name"), NULL, false )
111 add_deprecated_alias( "alsadev" ) /* deprecated since 0.9.3 */
112 change_string_list( ppsz_devices, ppsz_devices_text, FindDevicesCallback )
113 change_action_add( FindDevicesCallback, N_("Refresh list") )
115 set_capability( "audio output", 150 )
116 set_callbacks( Open, Close )
119 /*****************************************************************************
120 * Probe: probe the audio device for available formats and channels
121 *****************************************************************************/
122 static void Probe( aout_instance_t * p_aout,
123 const char * psz_device, const char * psz_iec_device,
124 int *pi_snd_pcm_format )
126 struct aout_sys_t * p_sys = p_aout->output.p_sys;
127 vlc_value_t val, text;
130 var_Create ( p_aout, "audio-device", VLC_VAR_INTEGER | VLC_VAR_HASCHOICE );
131 text.psz_string = _("Audio Device");
132 var_Change( p_aout, "audio-device", VLC_VAR_SETTEXT, &text, NULL );
134 /* We'll open the audio device in non blocking mode so we can just exit
135 * when it is already in use, but for the real stuff we'll still use
136 * the blocking mode */
138 /* Now test linear PCM capabilities */
139 if ( !(i_ret = snd_pcm_open( &p_sys->p_snd_pcm, psz_device,
140 SND_PCM_STREAM_PLAYBACK,
141 SND_PCM_NONBLOCK ) ) )
144 snd_pcm_hw_params_t * p_hw;
145 snd_pcm_hw_params_alloca (&p_hw);
147 if ( snd_pcm_hw_params_any( p_sys->p_snd_pcm, p_hw ) < 0 )
149 msg_Warn( p_aout, "unable to retrieve initial hardware parameters"
150 ", disabling linear PCM audio" );
151 snd_pcm_close( p_sys->p_snd_pcm );
152 var_Destroy( p_aout, "audio-device" );
156 if ( snd_pcm_hw_params_set_format( p_sys->p_snd_pcm, p_hw,
157 *pi_snd_pcm_format ) < 0 )
161 if( *pi_snd_pcm_format != SND_PCM_FORMAT_S16 )
163 *pi_snd_pcm_format = SND_PCM_FORMAT_S16;
164 i_snd_rc = snd_pcm_hw_params_set_format( p_sys->p_snd_pcm,
165 p_hw, *pi_snd_pcm_format );
169 msg_Warn( p_aout, "unable to set stream sample size and "
170 "word order, disabling linear PCM audio" );
171 snd_pcm_close( p_sys->p_snd_pcm );
172 var_Destroy( p_aout, "audio-device" );
177 i_channels = aout_FormatNbChannels( &p_aout->output.output );
179 while ( i_channels > 0 )
181 if ( !snd_pcm_hw_params_test_channels( p_sys->p_snd_pcm, p_hw,
184 switch ( i_channels )
187 val.i_int = AOUT_VAR_MONO;
188 text.psz_string = _("Mono");
189 var_Change( p_aout, "audio-device",
190 VLC_VAR_ADDCHOICE, &val, &text );
193 val.i_int = AOUT_VAR_STEREO;
194 text.psz_string = _("Stereo");
195 var_Change( p_aout, "audio-device",
196 VLC_VAR_ADDCHOICE, &val, &text );
197 var_Set( p_aout, "audio-device", val );
200 val.i_int = AOUT_VAR_2F2R;
201 text.psz_string = _("2 Front 2 Rear");
202 var_Change( p_aout, "audio-device",
203 VLC_VAR_ADDCHOICE, &val, &text );
206 val.i_int = AOUT_VAR_5_1;
207 text.psz_string = "5.1";
208 var_Change( p_aout, "audio-device",
209 VLC_VAR_ADDCHOICE, &val, &text );
217 /* Special case for mono on stereo only boards */
218 i_channels = aout_FormatNbChannels( &p_aout->output.output );
219 var_Change( p_aout, "audio-device", VLC_VAR_CHOICESCOUNT, &val, NULL );
220 if( val.i_int <= 0 && i_channels == 1 )
222 if ( !snd_pcm_hw_params_test_channels( p_sys->p_snd_pcm, p_hw, 2 ))
224 val.i_int = AOUT_VAR_STEREO;
225 text.psz_string = (char*)N_("Stereo");
226 var_Change( p_aout, "audio-device",
227 VLC_VAR_ADDCHOICE, &val, &text );
228 var_Set( p_aout, "audio-device", val );
232 /* Close the previously opened device */
233 snd_pcm_close( p_sys->p_snd_pcm );
235 else if ( i_ret == -EBUSY )
237 msg_Warn( p_aout, "audio device: %s is already in use", psz_device );
240 /* Test for S/PDIF device if needed */
241 if ( psz_iec_device )
243 /* Opening the device should be enough */
244 if ( !(i_ret = snd_pcm_open( &p_sys->p_snd_pcm, psz_iec_device,
245 SND_PCM_STREAM_PLAYBACK,
246 SND_PCM_NONBLOCK ) ) )
248 val.i_int = AOUT_VAR_SPDIF;
249 text.psz_string = (char*)N_("A/52 over S/PDIF");
250 var_Change( p_aout, "audio-device",
251 VLC_VAR_ADDCHOICE, &val, &text );
252 if( config_GetInt( p_aout, "spdif" ) )
253 var_Set( p_aout, "audio-device", val );
255 snd_pcm_close( p_sys->p_snd_pcm );
257 else if ( i_ret == -EBUSY )
259 msg_Warn( p_aout, "audio device: %s is already in use",
264 var_Change( p_aout, "audio-device", VLC_VAR_CHOICESCOUNT, &val, NULL );
265 #if (SND_LIB_VERSION <= 0x010015)
266 # warning Please update alsa-lib to version > 1.0.21a.
267 var_Create( p_aout->p_libvlc, "alsa-working", VLC_VAR_BOOL );
270 if( var_GetBool( p_aout->p_libvlc, "alsa-working" ) )
271 dialog_FatalWait( p_aout, "ALSA version problem",
272 "VLC failed to re-initialize your sound output device.\n"
273 "Please update alsa-lib to version 1.0.22 or higher "
274 "to fix this issue." );
277 var_SetBool( p_aout->p_libvlc, "alsa-working", true );
281 /* Probe() has failed. */
282 msg_Dbg( p_aout, "failed to find a usable ALSA configuration" );
283 var_Destroy( p_aout, "audio-device" );
287 /* Add final settings to the variable */
288 var_AddCallback( p_aout, "audio-device", aout_ChannelsRestart, NULL );
289 var_SetBool( p_aout, "intf-change", true );
292 /*****************************************************************************
293 * Open: create a handle and open an alsa device
294 *****************************************************************************
295 * This function opens an alsa device, through the alsa API.
297 * Note: the only heap-allocated string is psz_device. All the other pointers
298 * are references to psz_device or to stack-allocated data.
299 *****************************************************************************/
300 static int Open( vlc_object_t *p_this )
302 aout_instance_t * p_aout = (aout_instance_t *)p_this;
303 struct aout_sys_t * p_sys;
306 char psz_default_iec_device[128]; /* Buffer used to store the default
308 char * psz_device, * psz_iec_device; /* device names for PCM and S/PDIF
311 int i_vlc_pcm_format; /* Audio format for VLC's data */
312 int i_snd_pcm_format; /* Audio format for ALSA's data */
314 snd_pcm_uframes_t i_buffer_size = 0;
315 snd_pcm_uframes_t i_period_size = 0;
318 snd_pcm_hw_params_t *p_hw;
319 snd_pcm_sw_params_t *p_sw;
322 unsigned int i_old_rate;
325 /* Allocate structures */
326 p_aout->output.p_sys = p_sys = malloc( sizeof( aout_sys_t ) );
330 /* Get device name */
331 if( (psz_device = config_GetPsz( p_aout, "alsa-audio-device" )) == NULL )
333 msg_Err( p_aout, "no audio device given (maybe \"default\" ?)" );
334 dialog_Fatal( p_aout, _("No Audio Device"), "%s",
335 _("No audio device name was given. You might want to " \
336 "enter \"default\".") );
341 /* Choose the IEC device for S/PDIF output:
342 if the device is overriden by the user then it will be the one
343 otherwise we compute the default device based on the output format. */
344 if( AOUT_FMT_NON_LINEAR( &p_aout->output.output )
345 && !strcmp( psz_device, DEFAULT_ALSA_DEVICE ) )
347 snprintf( psz_default_iec_device, sizeof(psz_default_iec_device),
348 "iec958:AES0=0x%x,AES1=0x%x,AES2=0x%x,AES3=0x%x",
349 IEC958_AES0_CON_EMPHASIS_NONE | IEC958_AES0_NONAUDIO,
350 IEC958_AES1_CON_ORIGINAL | IEC958_AES1_CON_PCM_CODER,
352 ( p_aout->output.output.i_rate == 48000 ?
353 IEC958_AES3_CON_FS_48000 :
354 ( p_aout->output.output.i_rate == 44100 ?
355 IEC958_AES3_CON_FS_44100 : IEC958_AES3_CON_FS_32000 ) ) );
356 psz_iec_device = psz_default_iec_device;
358 else if( AOUT_FMT_NON_LINEAR( &p_aout->output.output ) )
360 psz_iec_device = psz_device;
364 psz_iec_device = NULL;
367 /* Choose the linear PCM format (read the comment above about FPU
371 i_vlc_pcm_format = VLC_CODEC_FL32;
372 i_snd_pcm_format = SND_PCM_FORMAT_FLOAT;
376 i_vlc_pcm_format = VLC_CODEC_S16N;
377 i_snd_pcm_format = SND_PCM_FORMAT_S16;
380 /* If the variable doesn't exist then it's the first time we're called
381 and we have to probe the available audio formats and channels */
382 if ( var_Type( p_aout, "audio-device" ) == 0 )
384 Probe( p_aout, psz_device, psz_iec_device, &i_snd_pcm_format );
387 if ( var_Get( p_aout, "audio-device", &val ) < 0 )
394 p_aout->output.output.i_format = i_vlc_pcm_format;
395 if ( val.i_int == AOUT_VAR_5_1 )
397 p_aout->output.output.i_physical_channels
398 = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER
399 | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT
402 psz_device = strdup( "surround51" );
404 else if ( val.i_int == AOUT_VAR_2F2R )
406 p_aout->output.output.i_physical_channels
407 = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT
408 | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT;
410 psz_device = strdup( "surround40" );
412 else if ( val.i_int == AOUT_VAR_STEREO )
414 p_aout->output.output.i_physical_channels
415 = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT;
417 else if ( val.i_int == AOUT_VAR_MONO )
419 p_aout->output.output.i_physical_channels = AOUT_CHAN_CENTER;
421 else if( val.i_int != AOUT_VAR_SPDIF )
423 /* This should not happen ! */
424 msg_Err( p_aout, "internal: can't find audio-device (%i)", val.i_int );
431 snd_output_stdio_attach( &p_sys->p_snd_stderr, stderr, 0 );
434 /* Open the device */
435 if ( val.i_int == AOUT_VAR_SPDIF )
437 if ( ( i_snd_rc = snd_pcm_open( &p_sys->p_snd_pcm, psz_iec_device,
438 SND_PCM_STREAM_PLAYBACK, 0 ) ) < 0 )
440 msg_Err( p_aout, "cannot open ALSA device `%s' (%s)",
441 psz_iec_device, snd_strerror( i_snd_rc ) );
442 dialog_Fatal( p_aout, _("Audio output failed"),
443 _("VLC could not open the ALSA device \"%s\" (%s)."),
444 psz_iec_device, snd_strerror( i_snd_rc ) );
449 i_buffer_size = ALSA_SPDIF_BUFFER_SIZE;
450 i_snd_pcm_format = SND_PCM_FORMAT_S16;
453 i_vlc_pcm_format = VLC_CODEC_SPDIFL;
454 p_aout->output.i_nb_samples = i_period_size = ALSA_SPDIF_PERIOD_SIZE;
455 p_aout->output.output.i_bytes_per_frame = AOUT_SPDIF_SIZE;
456 p_aout->output.output.i_frame_length = A52_FRAME_NB;
458 aout_VolumeNoneInit( p_aout );
464 msg_Dbg( p_aout, "opening ALSA device `%s'", psz_device );
466 /* Since it seems snd_pcm_close hasn't really released the device at
467 the time it returns, probe if the device is available in loop for 1s.
468 We cannot use blocking mode since the we would wait indefinitely when
469 switching from a dmx device to surround51. */
471 for( i = 10; i >= 0; i-- )
473 if ( ( i_snd_rc = snd_pcm_open( &p_sys->p_snd_pcm, psz_device,
474 SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK ) ) == -EBUSY )
476 if( i ) msleep( 100000 /* 100ms */ );
479 msg_Err( p_aout, "audio device: %s is already in use",
481 dialog_Fatal( p_aout, _("Audio output failed"),
482 _("The audio device \"%s\" is already in use."),
491 msg_Err( p_aout, "cannot open ALSA device `%s' (%s)",
492 psz_device, snd_strerror( i_snd_rc ) );
493 dialog_Fatal( p_aout, _("Audio output failed"),
494 _("VLC could not open the ALSA device \"%s\" (%s)."),
495 psz_device, snd_strerror( i_snd_rc ) );
501 /* We want blocking mode */
502 snd_pcm_nonblock( p_sys->p_snd_pcm, 0 );
504 i_buffer_size = ALSA_DEFAULT_BUFFER_SIZE;
505 i_channels = aout_FormatNbChannels( &p_aout->output.output );
507 p_aout->output.i_nb_samples = i_period_size = ALSA_DEFAULT_PERIOD_SIZE;
509 aout_VolumeSoftInit( p_aout );
512 /* Free psz_device so that all the remaining data is stack-allocated */
515 p_aout->output.pf_play = Play;
517 snd_pcm_hw_params_alloca(&p_hw);
518 snd_pcm_sw_params_alloca(&p_sw);
520 /* Due to some bugs in alsa with some drivers, we need to retry in s16l
521 if snd_pcm_hw_params fails in fl32 */
526 /* Get Initial hardware parameters */
527 if ( ( i_snd_rc = snd_pcm_hw_params_any( p_sys->p_snd_pcm, p_hw ) ) < 0 )
529 msg_Err( p_aout, "unable to retrieve initial hardware parameters (%s)",
530 snd_strerror( i_snd_rc ) );
535 if ( ( i_snd_rc = snd_pcm_hw_params_set_format( p_sys->p_snd_pcm, p_hw,
536 i_snd_pcm_format ) ) < 0 )
538 if( i_snd_pcm_format != SND_PCM_FORMAT_S16 )
540 i_snd_pcm_format = SND_PCM_FORMAT_S16;
541 i_snd_rc = snd_pcm_hw_params_set_format( p_sys->p_snd_pcm,
542 p_hw, i_snd_pcm_format );
546 msg_Err( p_aout, "unable to set stream sample size and "
547 "word order (%s)", snd_strerror( i_snd_rc ) );
551 if( i_vlc_pcm_format != VLC_CODEC_SPDIFL )
552 switch( i_snd_pcm_format )
554 case SND_PCM_FORMAT_FLOAT:
555 i_vlc_pcm_format = VLC_CODEC_FL32;
557 case SND_PCM_FORMAT_S16:
558 i_vlc_pcm_format = VLC_CODEC_S16N;
561 p_aout->output.output.i_format = i_vlc_pcm_format;
563 if ( ( i_snd_rc = snd_pcm_hw_params_set_access( p_sys->p_snd_pcm, p_hw,
564 SND_PCM_ACCESS_RW_INTERLEAVED ) ) < 0 )
566 msg_Err( p_aout, "unable to set interleaved stream format (%s)",
567 snd_strerror( i_snd_rc ) );
572 if ( ( i_snd_rc = snd_pcm_hw_params_set_channels( p_sys->p_snd_pcm, p_hw,
575 msg_Err( p_aout, "unable to set number of output channels (%s)",
576 snd_strerror( i_snd_rc ) );
581 i_old_rate = p_aout->output.output.i_rate;
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,
585 if( i_snd_rc < 0 || p_aout->output.output.i_rate != i_old_rate )
587 msg_Warn( p_aout, "The rate %d Hz is not supported by your " \
588 "hardware. Using %d Hz instead.\n", i_old_rate, \
589 p_aout->output.output.i_rate );
592 /* Set period size. */
593 if ( ( i_snd_rc = snd_pcm_hw_params_set_period_size_near( p_sys->p_snd_pcm,
594 p_hw, &i_period_size, NULL ) ) < 0 )
596 msg_Err( p_aout, "unable to set period size (%s)",
597 snd_strerror( i_snd_rc ) );
600 p_aout->output.i_nb_samples = i_period_size;
602 /* Set buffer size. */
603 if ( ( i_snd_rc = snd_pcm_hw_params_set_buffer_size_near( p_sys->p_snd_pcm,
604 p_hw, &i_buffer_size ) ) < 0 )
606 msg_Err( p_aout, "unable to set buffer size (%s)",
607 snd_strerror( i_snd_rc ) );
611 /* Commit hardware parameters. */
612 if ( ( i_snd_rc = snd_pcm_hw_params( p_sys->p_snd_pcm, p_hw ) ) < 0 )
614 if ( b_retry == false &&
615 i_snd_pcm_format == SND_PCM_FORMAT_FLOAT)
618 i_snd_pcm_format = SND_PCM_FORMAT_S16;
619 p_aout->output.output.i_format = VLC_CODEC_S16N;
620 msg_Warn( p_aout, "unable to commit hardware configuration "
621 "with fl32 samples. Retrying with s16l (%s)", snd_strerror( i_snd_rc ) );
625 msg_Err( p_aout, "unable to commit hardware configuration (%s)",
626 snd_strerror( i_snd_rc ) );
632 if( ( i_snd_rc = snd_pcm_hw_params_get_period_time( p_hw,
633 &p_sys->i_period_time, NULL ) ) < 0 )
635 msg_Err( p_aout, "unable to get period time (%s)",
636 snd_strerror( i_snd_rc ) );
640 /* Get Initial software parameters */
641 snd_pcm_sw_params_current( p_sys->p_snd_pcm, p_sw );
643 i_snd_rc = snd_pcm_sw_params_set_sleep_min( p_sys->p_snd_pcm, p_sw, 0 );
645 i_snd_rc = snd_pcm_sw_params_set_avail_min( p_sys->p_snd_pcm, p_sw,
646 p_aout->output.i_nb_samples );
647 /* start playing when one period has been written */
648 i_snd_rc = snd_pcm_sw_params_set_start_threshold( p_sys->p_snd_pcm, p_sw,
649 ALSA_DEFAULT_PERIOD_SIZE);
652 msg_Err( p_aout, "unable to set start threshold (%s)",
653 snd_strerror( i_snd_rc ) );
657 /* Commit software parameters. */
658 if ( snd_pcm_sw_params( p_sys->p_snd_pcm, p_sw ) < 0 )
660 msg_Err( p_aout, "unable to set software configuration" );
665 snd_output_printf( p_sys->p_snd_stderr, "\nALSA hardware setup:\n\n" );
666 snd_pcm_dump_hw_setup( p_sys->p_snd_pcm, p_sys->p_snd_stderr );
667 snd_output_printf( p_sys->p_snd_stderr, "\nALSA software setup:\n\n" );
668 snd_pcm_dump_sw_setup( p_sys->p_snd_pcm, p_sys->p_snd_stderr );
669 snd_output_printf( p_sys->p_snd_stderr, "\n" );
672 p_sys->start_date = 0;
673 vlc_sem_init( &p_sys->wait, 0 );
675 /* Create ALSA thread and wait for its readiness. */
676 if( vlc_clone( &p_sys->thread, ALSAThread, p_aout,
677 VLC_THREAD_PRIORITY_OUTPUT ) )
679 msg_Err( p_aout, "cannot create ALSA thread (%m)" );
680 vlc_sem_destroy( &p_sys->wait );
687 snd_pcm_close( p_sys->p_snd_pcm );
689 snd_output_close( p_sys->p_snd_stderr );
695 static void PlayIgnore( aout_instance_t *p_aout )
696 { /* Already playing - nothing to do */
700 /*****************************************************************************
701 * Play: start playback
702 *****************************************************************************/
703 static void Play( aout_instance_t *p_aout )
705 p_aout->output.pf_play = PlayIgnore;
707 /* get the playing date of the first aout buffer */
708 p_aout->output.p_sys->start_date =
709 aout_FifoFirstDate( p_aout, &p_aout->output.fifo );
711 /* wake up the audio output thread */
712 sem_post( &p_aout->output.p_sys->wait );
715 /*****************************************************************************
716 * Close: close the ALSA device
717 *****************************************************************************/
718 static void Close( vlc_object_t *p_this )
720 aout_instance_t *p_aout = (aout_instance_t *)p_this;
721 struct aout_sys_t * p_sys = p_aout->output.p_sys;
724 /* Make sure that the thread will stop once it is waken up */
725 vlc_cancel( p_sys->thread );
726 vlc_join( p_sys->thread, NULL );
727 vlc_sem_destroy( &p_sys->wait );
730 i_snd_rc = snd_pcm_close( p_sys->p_snd_pcm );
734 msg_Err( p_aout, "failed closing ALSA device (%s)",
735 snd_strerror( i_snd_rc ) );
739 snd_output_close( p_sys->p_snd_stderr );
745 static void pcm_drop(void *pcm)
750 /*****************************************************************************
751 * ALSAThread: asynchronous thread used to DMA the data to the device
752 *****************************************************************************/
753 static void* ALSAThread( void *data )
755 aout_instance_t * p_aout = data;
756 struct aout_sys_t * p_sys = p_aout->output.p_sys;
758 /* Wait for the exact time to start playing (avoids resampling) */
759 vlc_sem_wait( &p_sys->wait );
760 mwait( p_sys->start_date - AOUT_PTS_TOLERANCE / 4 );
762 vlc_cleanup_push( pcm_drop, p_sys->p_snd_pcm );
770 /*****************************************************************************
771 * ALSAFill: function used to fill the ALSA buffer as much as possible
772 *****************************************************************************/
773 static void ALSAFill( aout_instance_t * p_aout )
775 struct aout_sys_t * p_sys = p_aout->output.p_sys;
776 snd_pcm_t *p_pcm = p_sys->p_snd_pcm;
777 snd_pcm_status_t * p_status;
781 int canc = vlc_savecancel();
782 /* Fill in the buffer until space or audio output buffer shortage */
785 snd_pcm_status_alloca(&p_status);
786 i_snd_rc = snd_pcm_status( p_pcm, p_status );
789 msg_Err( p_aout, "cannot get device status" );
793 /* Handle buffer underruns and get the status again */
794 if( snd_pcm_status_get_state( p_status ) == SND_PCM_STATE_XRUN )
796 /* Prepare the device */
797 i_snd_rc = snd_pcm_prepare( p_pcm );
800 msg_Err( p_aout, "cannot recover from buffer underrun" );
804 msg_Dbg( p_aout, "recovered from buffer underrun" );
806 /* Get the new status */
807 i_snd_rc = snd_pcm_status( p_pcm, p_status );
810 msg_Err( p_aout, "cannot get device status after recovery" );
814 /* Underrun, try to recover as quickly as possible */
819 /* Here the device should be in RUNNING state, p_status is valid. */
820 snd_pcm_sframes_t delay = snd_pcm_status_get_delay( p_status );
821 if( delay == 0 ) /* workaround buggy alsa drivers */
822 if( snd_pcm_delay( p_pcm, &delay ) < 0 )
823 delay = 0; /* FIXME: use a positive minimal delay */
825 size_t i_bytes = snd_pcm_frames_to_bytes( p_pcm, delay );
826 mtime_t delay_us = CLOCK_FREQ * i_bytes
827 / p_aout->output.output.i_bytes_per_frame
828 / p_aout->output.output.i_rate
829 * p_aout->output.output.i_frame_length;
832 snd_pcm_state_t state = snd_pcm_status_get_state( p_status );
833 if( state != SND_PCM_STATE_RUNNING )
834 msg_Err( p_aout, "pcm status (%d) != RUNNING", state );
836 msg_Dbg( p_aout, "Delay is %ld frames (%zu bytes)", delay, i_bytes );
838 msg_Dbg( p_aout, "Bytes per frame: %d", p_aout->output.output.i_bytes_per_frame );
839 msg_Dbg( p_aout, "Rate: %d", p_aout->output.output.i_rate );
840 msg_Dbg( p_aout, "Frame length: %d", p_aout->output.output.i_frame_length );
841 msg_Dbg( p_aout, "Next date: in %"PRId64" microseconds", delay_us );
843 next_date = mdate() + delay_us;
846 block_t *p_buffer = aout_OutputNextBuffer( p_aout, next_date,
847 (p_aout->output.output.i_format == VLC_CODEC_SPDIFL) );
849 /* Audio output buffer shortage -> stop the fill process and wait */
850 if( p_buffer == NULL )
855 int n = snd_pcm_poll_descriptors_count(p_pcm);
856 struct pollfd ufd[n];
857 unsigned short revents;
859 snd_pcm_poll_descriptors(p_pcm, ufd, n);
862 vlc_restorecancel(canc);
864 canc = vlc_savecancel();
865 snd_pcm_poll_descriptors_revents(p_pcm, ufd, n, &revents);
869 if(revents & POLLOUT)
871 i_snd_rc = snd_pcm_writei( p_pcm, p_buffer->p_buffer,
872 p_buffer->i_nb_samples );
873 if( i_snd_rc != -ESTRPIPE )
877 /* a suspend event occurred
878 * (stream is suspended and waiting for an application recovery) */
879 msg_Dbg( p_aout, "entering in suspend mode, trying to resume..." );
881 while( ( i_snd_rc = snd_pcm_resume( p_pcm ) ) == -EAGAIN )
883 vlc_restorecancel(canc);
884 msleep(CLOCK_FREQ); /* device still suspended, wait... */
885 canc = vlc_savecancel();
889 /* Device does not support resuming, restart it */
890 i_snd_rc = snd_pcm_prepare( p_pcm );
895 msg_Err( p_aout, "cannot write: %s", snd_strerror( i_snd_rc ) );
897 vlc_restorecancel(canc);
898 block_Release( p_buffer );
903 msg_Err( p_aout, "ALSA error: %s", snd_strerror( i_snd_rc ) );
905 vlc_restorecancel(canc);
906 msleep(p_sys->i_period_time / 2);
909 static void GetDevicesForCard( module_config_t *p_item, int i_card );
910 static void GetDevices( module_config_t *p_item );
912 /*****************************************************************************
913 * config variable callback
914 *****************************************************************************/
915 static int FindDevicesCallback( vlc_object_t *p_this, char const *psz_name,
916 vlc_value_t newval, vlc_value_t oldval, void *p_unused )
918 module_config_t *p_item;
924 p_item = config_FindConfig( p_this, psz_name );
925 if( !p_item ) return VLC_SUCCESS;
927 /* Clear-up the current list */
930 /* Keep the first entrie */
931 for( i = 1; i < p_item->i_list; i++ )
933 free( (char *)p_item->ppsz_list[i] );
934 free( (char *)p_item->ppsz_list_text[i] );
936 /* TODO: Remove when no more needed */
937 p_item->ppsz_list[i] = NULL;
938 p_item->ppsz_list_text[i] = NULL;
942 GetDevices( p_item );
944 /* Signal change to the interface */
945 p_item->b_dirty = true;
951 static void GetDevicesForCard( module_config_t *p_item, int i_card )
953 int i_pcm_device = -1;
955 snd_pcm_info_t *p_pcm_info;
960 sprintf( psz_dev, "hw:%i", i_card );
962 if( ( i_err = snd_ctl_open( &p_ctl, psz_dev, 0 ) ) < 0 )
965 if( ( i_err = snd_card_get_name( i_card, &psz_card_name ) ) != 0)
966 psz_card_name = _("Unknown soundcard");
968 snd_pcm_info_alloca( &p_pcm_info );
972 char *psz_device, *psz_descr;
973 if( ( i_err = snd_ctl_pcm_next_device( p_ctl, &i_pcm_device ) ) < 0 )
975 if( i_pcm_device < 0 )
978 snd_pcm_info_set_device( p_pcm_info, i_pcm_device );
979 snd_pcm_info_set_subdevice( p_pcm_info, 0 );
980 snd_pcm_info_set_stream( p_pcm_info, SND_PCM_STREAM_PLAYBACK );
982 if( ( i_err = snd_ctl_pcm_info( p_ctl, p_pcm_info ) ) < 0 )
984 if( i_err != -ENOENT )
986 /*printf( "get_devices_for_card(): "
987 "snd_ctl_pcm_info() "
988 "failed (%d:%d): %s.\n", i_card,
989 i_pcm_device, snd_strerror( -i_err ) );*/
994 if( asprintf( &psz_device, "hw:%d,%d", i_card, i_pcm_device ) == -1 )
996 if( asprintf( &psz_descr, "%s: %s (%s)", psz_card_name,
997 snd_pcm_info_get_name(p_pcm_info), psz_device ) == -1 )
1004 (char **)realloc( p_item->ppsz_list,
1005 (p_item->i_list + 2) * sizeof(char *) );
1006 p_item->ppsz_list_text =
1007 (char **)realloc( p_item->ppsz_list_text,
1008 (p_item->i_list + 2) * sizeof(char *) );
1009 p_item->ppsz_list[ p_item->i_list ] = psz_device;
1010 p_item->ppsz_list_text[ p_item->i_list ] = psz_descr;
1012 p_item->ppsz_list[ p_item->i_list ] = NULL;
1013 p_item->ppsz_list_text[ p_item->i_list ] = NULL;
1016 snd_ctl_close( p_ctl );
1021 static void GetDevices( module_config_t *p_item )
1026 if( ( i_err = snd_card_next( &i_card ) ) != 0 )
1028 /*printf( "snd_card_next() failed: %s", snd_strerror( -i_err ) );*/
1032 while( i_card > -1 )
1034 GetDevicesForCard( p_item, i_card );
1035 if( ( i_err = snd_card_next( &i_card ) ) != 0 )
1037 /*printf( "snd_card_next() failed: %s", snd_strerror( -i_err ) );*/