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 *****************************************************************************/
33 #include <errno.h> /* ENOMEM */
34 #include <vlc_interface.h>
39 Note: we use the new API which is available since 0.9.0beta10a. */
40 #define ALSA_PCM_NEW_HW_PARAMS_API
41 #define ALSA_PCM_NEW_SW_PARAMS_API
42 #include <alsa/asoundlib.h>
44 /*****************************************************************************
45 * aout_sys_t: ALSA audio output method descriptor
46 *****************************************************************************
47 * This structure is part of the audio output thread descriptor.
48 * It describes the ALSA specific properties of an audio device.
49 *****************************************************************************/
52 snd_pcm_t * p_snd_pcm;
53 unsigned int i_period_time;
56 snd_output_t * p_snd_stderr;
59 int b_playing; /* playing status */
65 snd_pcm_status_t *p_status;
68 #define A52_FRAME_NB 1536
70 /* These values are in frames.
71 To convert them to a number of bytes you have to multiply them by the
72 number of channel(s) (eg. 2 for stereo) and the size of a sample (eg.
74 #define ALSA_DEFAULT_PERIOD_SIZE 1024
75 #define ALSA_DEFAULT_BUFFER_SIZE ( ALSA_DEFAULT_PERIOD_SIZE << 8 )
76 #define ALSA_SPDIF_PERIOD_SIZE A52_FRAME_NB
77 #define ALSA_SPDIF_BUFFER_SIZE ( ALSA_SPDIF_PERIOD_SIZE << 4 )
78 /* Why << 4 ? --Meuuh */
79 /* Why not ? --Bozo */
82 #define DEFAULT_ALSA_DEVICE N_("default")
84 /*****************************************************************************
86 *****************************************************************************/
87 static int Open ( vlc_object_t * );
88 static void Close ( vlc_object_t * );
89 static void Play ( aout_instance_t * );
90 static int ALSAThread ( aout_instance_t * );
91 static void ALSAFill ( aout_instance_t * );
92 static int FindDevicesCallback( vlc_object_t *p_this, char const *psz_name,
93 vlc_value_t newval, vlc_value_t oldval, void *p_unused );
95 /*****************************************************************************
97 *****************************************************************************/
98 static char *ppsz_devices[] = { "default" };
99 static char *ppsz_devices_text[] = { N_("Default") };
101 set_shortname( "ALSA" );
102 set_description( _("ALSA audio output") );
103 set_category( CAT_AUDIO );
104 set_subcategory( SUBCAT_AUDIO_AOUT );
105 add_string( "alsadev", DEFAULT_ALSA_DEVICE, aout_FindAndRestart,
106 N_("ALSA Device Name"), NULL, VLC_FALSE );
107 change_string_list( ppsz_devices, ppsz_devices_text, FindDevicesCallback );
108 change_action_add( FindDevicesCallback, N_("Refresh list") );
110 set_capability( "audio output", 150 );
111 set_callbacks( Open, Close );
114 /*****************************************************************************
115 * Probe: probe the audio device for available formats and channels
116 *****************************************************************************/
117 static void Probe( aout_instance_t * p_aout,
118 const char * psz_device, const char * psz_iec_device,
119 int *pi_snd_pcm_format )
121 struct aout_sys_t * p_sys = p_aout->output.p_sys;
122 vlc_value_t val, text;
125 var_Create ( p_aout, "audio-device", VLC_VAR_INTEGER | VLC_VAR_HASCHOICE );
126 text.psz_string = _("Audio Device");
127 var_Change( p_aout, "audio-device", VLC_VAR_SETTEXT, &text, NULL );
129 /* We'll open the audio device in non blocking mode so we can just exit
130 * when it is already in use, but for the real stuff we'll still use
131 * the blocking mode */
133 /* Now test linear PCM capabilities */
134 if ( !(i_ret = snd_pcm_open( &p_sys->p_snd_pcm, psz_device,
135 SND_PCM_STREAM_PLAYBACK,
136 SND_PCM_NONBLOCK ) ) )
139 snd_pcm_hw_params_t * p_hw;
140 snd_pcm_hw_params_alloca (&p_hw);
142 if ( snd_pcm_hw_params_any( p_sys->p_snd_pcm, p_hw ) < 0 )
144 msg_Warn( p_aout, "unable to retrieve initial hardware parameters"
145 ", disabling linear PCM audio" );
146 snd_pcm_close( p_sys->p_snd_pcm );
147 var_Destroy( p_aout, "audio-device" );
151 if ( snd_pcm_hw_params_set_format( p_sys->p_snd_pcm, p_hw,
152 *pi_snd_pcm_format ) < 0 )
156 if( *pi_snd_pcm_format != SND_PCM_FORMAT_S16 )
158 *pi_snd_pcm_format = SND_PCM_FORMAT_S16;
159 i_snd_rc = snd_pcm_hw_params_set_format( p_sys->p_snd_pcm,
160 p_hw, *pi_snd_pcm_format );
164 msg_Warn( p_aout, "unable to set stream sample size and "
165 "word order, disabling linear PCM audio" );
166 snd_pcm_close( p_sys->p_snd_pcm );
167 var_Destroy( p_aout, "audio-device" );
172 i_channels = aout_FormatNbChannels( &p_aout->output.output );
174 while ( i_channels > 0 )
176 if ( !snd_pcm_hw_params_test_channels( p_sys->p_snd_pcm, p_hw,
179 switch ( i_channels )
182 val.i_int = AOUT_VAR_MONO;
183 text.psz_string = N_("Mono");
184 var_Change( p_aout, "audio-device",
185 VLC_VAR_ADDCHOICE, &val, &text );
188 val.i_int = AOUT_VAR_STEREO;
189 text.psz_string = N_("Stereo");
190 var_Change( p_aout, "audio-device",
191 VLC_VAR_ADDCHOICE, &val, &text );
192 var_Set( p_aout, "audio-device", val );
195 val.i_int = AOUT_VAR_2F2R;
196 text.psz_string = N_("2 Front 2 Rear");
197 var_Change( p_aout, "audio-device",
198 VLC_VAR_ADDCHOICE, &val, &text );
201 val.i_int = AOUT_VAR_5_1;
202 text.psz_string = "5.1";
203 var_Change( p_aout, "audio-device",
204 VLC_VAR_ADDCHOICE, &val, &text );
212 /* Special case for mono on stereo only boards */
213 i_channels = aout_FormatNbChannels( &p_aout->output.output );
214 var_Change( p_aout, "audio-device", VLC_VAR_CHOICESCOUNT, &val, NULL );
215 if( val.i_int <= 0 && i_channels == 1 )
217 if ( !snd_pcm_hw_params_test_channels( p_sys->p_snd_pcm, p_hw, 2 ))
219 val.i_int = AOUT_VAR_STEREO;
220 text.psz_string = N_("Stereo");
221 var_Change( p_aout, "audio-device",
222 VLC_VAR_ADDCHOICE, &val, &text );
223 var_Set( p_aout, "audio-device", val );
227 /* Close the previously opened device */
228 snd_pcm_close( p_sys->p_snd_pcm );
230 else if ( i_ret == -EBUSY )
232 msg_Warn( p_aout, "audio device: %s is already in use", psz_device );
235 /* Test for S/PDIF device if needed */
236 if ( psz_iec_device )
238 /* Opening the device should be enough */
239 if ( !(i_ret = snd_pcm_open( &p_sys->p_snd_pcm, psz_iec_device,
240 SND_PCM_STREAM_PLAYBACK,
241 SND_PCM_NONBLOCK ) ) )
243 val.i_int = AOUT_VAR_SPDIF;
244 text.psz_string = N_("A/52 over S/PDIF");
245 var_Change( p_aout, "audio-device",
246 VLC_VAR_ADDCHOICE, &val, &text );
247 if( config_GetInt( p_aout, "spdif" ) )
248 var_Set( p_aout, "audio-device", val );
250 snd_pcm_close( p_sys->p_snd_pcm );
252 else if ( i_ret == -EBUSY )
254 msg_Warn( p_aout, "audio device: %s is already in use",
259 var_Change( p_aout, "audio-device", VLC_VAR_CHOICESCOUNT, &val, NULL );
262 /* Probe() has failed. */
263 msg_Dbg( p_aout, "failed to find a useable alsa configuration" );
264 var_Destroy( p_aout, "audio-device" );
268 /* Add final settings to the variable */
269 var_AddCallback( p_aout, "audio-device", aout_ChannelsRestart, NULL );
270 val.b_bool = VLC_TRUE;
271 var_Set( p_aout, "intf-change", val );
274 /*****************************************************************************
275 * Open: create a handle and open an alsa device
276 *****************************************************************************
277 * This function opens an alsa device, through the alsa API.
279 * Note: the only heap-allocated string is psz_device. All the other pointers
280 * are references to psz_device or to stack-allocated data.
281 *****************************************************************************/
282 static int Open( vlc_object_t *p_this )
284 aout_instance_t * p_aout = (aout_instance_t *)p_this;
285 struct aout_sys_t * p_sys;
288 char psz_default_iec_device[128]; /* Buffer used to store the default
290 char * psz_device, * psz_iec_device; /* device names for PCM and S/PDIF
293 int i_vlc_pcm_format; /* Audio format for VLC's data */
294 int i_snd_pcm_format; /* Audio format for ALSA's data */
296 snd_pcm_uframes_t i_buffer_size = 0;
297 snd_pcm_uframes_t i_period_size = 0;
300 snd_pcm_hw_params_t *p_hw;
301 snd_pcm_sw_params_t *p_sw;
304 unsigned int i_old_rate;
305 vlc_bool_t b_retry = VLC_TRUE;
307 /* Allocate structures */
308 p_aout->output.p_sys = p_sys = malloc( sizeof( aout_sys_t ) );
311 msg_Err( p_aout, "out of memory" );
314 p_sys->b_playing = VLC_FALSE;
315 p_sys->start_date = 0;
316 vlc_cond_init( p_aout, &p_sys->wait );
317 vlc_mutex_init( p_aout, &p_sys->lock );
319 /* Get device name */
320 if( (psz_device = config_GetPsz( p_aout, "alsadev" )) == NULL )
322 msg_Err( p_aout, "no audio device given (maybe \"default\" ?)" );
323 intf_UserFatal( p_aout, VLC_FALSE, _("No Audio Device"),
324 _("No audio device name was given. You might want to " \
325 "enter \"default\".") );
330 /* Choose the IEC device for S/PDIF output:
331 if the device is overriden by the user then it will be the one
332 otherwise we compute the default device based on the output format. */
333 if( AOUT_FMT_NON_LINEAR( &p_aout->output.output )
334 && !strcmp( psz_device, DEFAULT_ALSA_DEVICE ) )
336 snprintf( psz_default_iec_device, sizeof(psz_default_iec_device),
337 "iec958:AES0=0x%x,AES1=0x%x,AES2=0x%x,AES3=0x%x",
338 IEC958_AES0_CON_EMPHASIS_NONE | IEC958_AES0_NONAUDIO,
339 IEC958_AES1_CON_ORIGINAL | IEC958_AES1_CON_PCM_CODER,
341 ( p_aout->output.output.i_rate == 48000 ?
342 IEC958_AES3_CON_FS_48000 :
343 ( p_aout->output.output.i_rate == 44100 ?
344 IEC958_AES3_CON_FS_44100 : IEC958_AES3_CON_FS_32000 ) ) );
345 psz_iec_device = psz_default_iec_device;
347 else if( AOUT_FMT_NON_LINEAR( &p_aout->output.output ) )
349 psz_iec_device = psz_device;
353 psz_iec_device = NULL;
356 /* Choose the linear PCM format (read the comment above about FPU
358 if( vlc_CPU() & CPU_CAPABILITY_FPU )
360 i_vlc_pcm_format = VLC_FOURCC('f','l','3','2');
361 i_snd_pcm_format = SND_PCM_FORMAT_FLOAT;
365 i_vlc_pcm_format = AOUT_FMT_S16_NE;
366 i_snd_pcm_format = SND_PCM_FORMAT_S16;
369 /* If the variable doesn't exist then it's the first time we're called
370 and we have to probe the available audio formats and channels */
371 if ( var_Type( p_aout, "audio-device" ) == 0 )
373 Probe( p_aout, psz_device, psz_iec_device, &i_snd_pcm_format );
376 if ( var_Get( p_aout, "audio-device", &val ) < 0 )
383 p_aout->output.output.i_format = i_vlc_pcm_format;
384 if ( val.i_int == AOUT_VAR_5_1 )
386 p_aout->output.output.i_physical_channels
387 = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER
388 | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT
391 psz_device = strdup( "surround51" );
393 else if ( val.i_int == AOUT_VAR_2F2R )
395 p_aout->output.output.i_physical_channels
396 = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT
397 | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT;
399 psz_device = strdup( "surround40" );
401 else if ( val.i_int == AOUT_VAR_STEREO )
403 p_aout->output.output.i_physical_channels
404 = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT;
406 else if ( val.i_int == AOUT_VAR_MONO )
408 p_aout->output.output.i_physical_channels = AOUT_CHAN_CENTER;
410 else if( val.i_int != AOUT_VAR_SPDIF )
412 /* This should not happen ! */
413 msg_Err( p_aout, "internal: can't find audio-device (%i)", val.i_int );
420 snd_output_stdio_attach( &p_sys->p_snd_stderr, stderr, 0 );
423 /* Open the device */
424 if ( val.i_int == AOUT_VAR_SPDIF )
426 if ( ( i_snd_rc = snd_pcm_open( &p_sys->p_snd_pcm, psz_iec_device,
427 SND_PCM_STREAM_PLAYBACK, 0 ) ) < 0 )
429 msg_Err( p_aout, "cannot open ALSA device `%s' (%s)",
430 psz_iec_device, snd_strerror( i_snd_rc ) );
431 intf_UserFatal( p_aout, VLC_FALSE, _("Audio output failed"),
432 _("VLC could not open the ALSA device \"%s\" (%s)."),
433 psz_iec_device, snd_strerror( i_snd_rc ) );
438 i_buffer_size = ALSA_SPDIF_BUFFER_SIZE;
439 i_snd_pcm_format = SND_PCM_FORMAT_S16;
442 i_vlc_pcm_format = VLC_FOURCC('s','p','d','i');
443 p_aout->output.i_nb_samples = i_period_size = ALSA_SPDIF_PERIOD_SIZE;
444 p_aout->output.output.i_bytes_per_frame = AOUT_SPDIF_SIZE;
445 p_aout->output.output.i_frame_length = A52_FRAME_NB;
447 aout_VolumeNoneInit( p_aout );
453 msg_Dbg( p_aout, "opening ALSA device `%s'", psz_device );
455 /* Since it seems snd_pcm_close hasen't really released the device at
456 the time it returns, probe if the device is available in loop for 1s.
457 We cannot use blocking mode since the we would wait indefinitely when
458 switching from a dmx device to surround51. */
460 for( i = 10; i >= 0; i-- )
462 if ( ( i_snd_rc = snd_pcm_open( &p_sys->p_snd_pcm, psz_device,
463 SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK ) ) == -EBUSY )
465 if( i ) msleep( 100000 /* 100ms */ );
468 msg_Err( p_aout, "audio device: %s is already in use",
470 intf_UserFatal( p_aout, VLC_FALSE, _("Audio output failed"),
471 _("The audio device \"%s\" is already in use."),
480 msg_Err( p_aout, "cannot open ALSA device `%s' (%s)",
481 psz_device, snd_strerror( i_snd_rc ) );
482 intf_UserFatal( p_aout, VLC_FALSE, _("Audio output failed"),
483 _("VLC could not open the ALSA device \"%s\" (%s)."),
484 psz_device, snd_strerror( i_snd_rc ) );
490 /* We want blocking mode */
491 snd_pcm_nonblock( p_sys->p_snd_pcm, 0 );
493 i_buffer_size = ALSA_DEFAULT_BUFFER_SIZE;
494 i_channels = aout_FormatNbChannels( &p_aout->output.output );
496 p_aout->output.i_nb_samples = i_period_size = ALSA_DEFAULT_PERIOD_SIZE;
498 aout_VolumeSoftInit( p_aout );
501 /* Free psz_device so that all the remaining data is stack-allocated */
504 p_aout->output.pf_play = Play;
506 snd_pcm_hw_params_alloca(&p_hw);
507 snd_pcm_sw_params_alloca(&p_sw);
509 /* Due to some bugs in alsa with some drivers, we need to retry in s16l
510 if snd_pcm_hw_params fails in fl32 */
515 /* Get Initial hardware parameters */
516 if ( ( i_snd_rc = snd_pcm_hw_params_any( p_sys->p_snd_pcm, p_hw ) ) < 0 )
518 msg_Err( p_aout, "unable to retrieve initial hardware parameters (%s)",
519 snd_strerror( i_snd_rc ) );
524 if ( ( i_snd_rc = snd_pcm_hw_params_set_format( p_sys->p_snd_pcm, p_hw,
525 i_snd_pcm_format ) ) < 0 )
527 if( i_snd_pcm_format != SND_PCM_FORMAT_S16 )
529 i_snd_pcm_format = SND_PCM_FORMAT_S16;
530 i_snd_rc = snd_pcm_hw_params_set_format( p_sys->p_snd_pcm,
531 p_hw, i_snd_pcm_format );
535 msg_Err( p_aout, "unable to set stream sample size and "
536 "word order (%s)", snd_strerror( i_snd_rc ) );
540 if( i_vlc_pcm_format != VLC_FOURCC('s','p','d','i') )
541 switch( i_snd_pcm_format )
543 case SND_PCM_FORMAT_FLOAT:
544 i_vlc_pcm_format = VLC_FOURCC('f','l','3','2');
546 case SND_PCM_FORMAT_S16:
547 i_vlc_pcm_format = AOUT_FMT_S16_NE;
550 p_aout->output.output.i_format = i_vlc_pcm_format;
552 if ( ( i_snd_rc = snd_pcm_hw_params_set_access( p_sys->p_snd_pcm, p_hw,
553 SND_PCM_ACCESS_RW_INTERLEAVED ) ) < 0 )
555 msg_Err( p_aout, "unable to set interleaved stream format (%s)",
556 snd_strerror( i_snd_rc ) );
561 if ( ( i_snd_rc = snd_pcm_hw_params_set_channels( p_sys->p_snd_pcm, p_hw,
564 msg_Err( p_aout, "unable to set number of output channels (%s)",
565 snd_strerror( i_snd_rc ) );
570 i_old_rate = p_aout->output.output.i_rate;
571 #ifdef HAVE_ALSA_NEW_API
572 i_snd_rc = snd_pcm_hw_params_set_rate_near( p_sys->p_snd_pcm, p_hw,
573 &p_aout->output.output.i_rate,
576 i_snd_rc = snd_pcm_hw_params_set_rate_near( p_sys->p_snd_pcm, p_hw,
577 p_aout->output.output.i_rate,
580 if( i_snd_rc < 0 || p_aout->output.output.i_rate != i_old_rate )
582 msg_Warn( p_aout, "The rate %d Hz is not supported by your " \
583 "hardware. Using %d Hz instead.\n", i_old_rate, \
584 p_aout->output.output.i_rate );
587 /* Set buffer size. */
588 #ifdef HAVE_ALSA_NEW_API
589 if ( ( i_snd_rc = snd_pcm_hw_params_set_buffer_size_near( p_sys->p_snd_pcm,
590 p_hw, &i_buffer_size ) ) < 0 )
592 if ( ( i_snd_rc = snd_pcm_hw_params_set_buffer_size_near( p_sys->p_snd_pcm,
593 p_hw, i_buffer_size ) ) < 0 )
596 msg_Err( p_aout, "unable to set buffer size (%s)",
597 snd_strerror( i_snd_rc ) );
601 /* Set period size. */
602 #ifdef HAVE_ALSA_NEW_API
603 if ( ( i_snd_rc = snd_pcm_hw_params_set_period_size_near( p_sys->p_snd_pcm,
604 p_hw, &i_period_size, NULL ) ) < 0 )
606 if ( ( i_snd_rc = snd_pcm_hw_params_set_period_size_near( p_sys->p_snd_pcm,
607 p_hw, i_period_size, NULL ) ) < 0 )
610 msg_Err( p_aout, "unable to set period size (%s)",
611 snd_strerror( i_snd_rc ) );
614 p_aout->output.i_nb_samples = i_period_size;
616 /* Commit hardware parameters. */
617 if ( ( i_snd_rc = snd_pcm_hw_params( p_sys->p_snd_pcm, p_hw ) ) < 0 )
619 if ( b_retry == VLC_FALSE &&
620 i_snd_pcm_format == SND_PCM_FORMAT_FLOAT)
623 i_snd_pcm_format = SND_PCM_FORMAT_S16;
624 p_aout->output.output.i_format = AOUT_FMT_S16_NE;
625 msg_Warn( p_aout, "unable to commit hardware configuration "
626 "with fl32 samples. Retrying with s16l (%s)", snd_strerror( i_snd_rc ) );
630 msg_Err( p_aout, "unable to commit hardware configuration (%s)",
631 snd_strerror( i_snd_rc ) );
637 #ifdef HAVE_ALSA_NEW_API
638 if( ( i_snd_rc = snd_pcm_hw_params_get_period_time( p_hw,
639 &p_sys->i_period_time, NULL ) ) < 0 )
641 if( ( p_sys->i_period_time =
642 (int)snd_pcm_hw_params_get_period_time( p_hw, NULL ) ) < 0 )
645 msg_Err( p_aout, "unable to get period time (%s)",
646 snd_strerror( i_snd_rc ) );
650 /* Get Initial software parameters */
651 snd_pcm_sw_params_current( p_sys->p_snd_pcm, p_sw );
653 i_snd_rc = snd_pcm_sw_params_set_sleep_min( p_sys->p_snd_pcm, p_sw, 0 );
655 i_snd_rc = snd_pcm_sw_params_set_avail_min( p_sys->p_snd_pcm, p_sw,
656 p_aout->output.i_nb_samples );
658 /* Commit software parameters. */
659 if ( snd_pcm_sw_params( p_sys->p_snd_pcm, p_sw ) < 0 )
661 msg_Err( p_aout, "unable to set software configuration" );
666 snd_output_printf( p_sys->p_snd_stderr, "\nALSA hardware setup:\n\n" );
667 snd_pcm_dump_hw_setup( p_sys->p_snd_pcm, p_sys->p_snd_stderr );
668 snd_output_printf( p_sys->p_snd_stderr, "\nALSA software setup:\n\n" );
669 snd_pcm_dump_sw_setup( p_sys->p_snd_pcm, p_sys->p_snd_stderr );
670 snd_output_printf( p_sys->p_snd_stderr, "\n" );
673 /* Create ALSA thread and wait for its readiness. */
674 if( vlc_thread_create( p_aout, "aout", ALSAThread,
675 VLC_THREAD_PRIORITY_OUTPUT, VLC_FALSE ) )
677 msg_Err( p_aout, "cannot create ALSA thread (%s)", strerror(errno) );
684 snd_pcm_close( p_sys->p_snd_pcm );
686 snd_output_close( p_sys->p_snd_stderr );
692 /*****************************************************************************
693 * Play: nothing to do
694 *****************************************************************************/
695 static void Play( aout_instance_t *p_aout )
697 if( !p_aout->output.p_sys->b_playing )
699 p_aout->output.p_sys->b_playing = 1;
701 /* get the playing date of the first aout buffer */
702 p_aout->output.p_sys->start_date =
703 aout_FifoFirstDate( p_aout, &p_aout->output.fifo );
705 /* wake up the audio output thread */
706 vlc_mutex_lock( &p_aout->output.p_sys->lock );
707 vlc_cond_signal( &p_aout->output.p_sys->wait );
708 vlc_mutex_unlock( &p_aout->output.p_sys->lock );
712 /*****************************************************************************
713 * Close: close the ALSA device
714 *****************************************************************************/
715 static void Close( vlc_object_t *p_this )
717 aout_instance_t *p_aout = (aout_instance_t *)p_this;
718 struct aout_sys_t * p_sys = p_aout->output.p_sys;
721 /* make sure the audio output thread is waken up */
722 vlc_mutex_lock( &p_aout->output.p_sys->lock );
723 vlc_cond_signal( &p_aout->output.p_sys->wait );
724 vlc_mutex_unlock( &p_aout->output.p_sys->lock );
726 vlc_object_kill( p_aout );
727 vlc_thread_join( p_aout );
728 p_aout->b_die = VLC_FALSE;
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 /*****************************************************************************
746 * ALSAThread: asynchronous thread used to DMA the data to the device
747 *****************************************************************************/
748 static int ALSAThread( aout_instance_t * p_aout )
750 p_aout->output.p_sys->p_status =
751 (snd_pcm_status_t *)malloc(snd_pcm_status_sizeof());
753 /* Wait for the exact time to start playing (avoids resampling) */
754 vlc_mutex_lock( &p_aout->output.p_sys->lock );
755 if( !p_aout->output.p_sys->start_date )
756 vlc_cond_wait( &p_aout->output.p_sys->wait,
757 &p_aout->output.p_sys->lock );
758 vlc_mutex_unlock( &p_aout->output.p_sys->lock );
760 mwait( p_aout->output.p_sys->start_date - AOUT_PTS_TOLERANCE / 4 );
762 while ( !p_aout->b_die )
767 free( p_aout->output.p_sys->p_status );
771 /*****************************************************************************
772 * ALSAFill: function used to fill the ALSA buffer as much as possible
773 *****************************************************************************/
774 static void ALSAFill( aout_instance_t * p_aout )
776 struct aout_sys_t * p_sys = p_aout->output.p_sys;
777 aout_buffer_t * p_buffer;
778 snd_pcm_status_t * p_status = p_sys->p_status;
782 /* Fill in the buffer until space or audio output buffer shortage */
785 i_snd_rc = snd_pcm_status( p_sys->p_snd_pcm, p_status );
788 msg_Err( p_aout, "unable to get the device's status (%s)",
789 snd_strerror( i_snd_rc ) );
791 msleep( p_sys->i_period_time >> 1 );
795 /* Handle buffer underruns and reget the status */
796 if( snd_pcm_status_get_state( p_status ) == SND_PCM_STATE_XRUN )
798 /* Prepare the device */
799 i_snd_rc = snd_pcm_prepare( p_sys->p_snd_pcm );
803 msg_Dbg( p_aout, "recovered from buffer underrun" );
805 /* Reget the status */
806 i_snd_rc = snd_pcm_status( p_sys->p_snd_pcm, p_status );
809 msg_Err( p_aout, "unable to get the device's status after "
810 "recovery (%s)", snd_strerror( i_snd_rc ) );
812 msleep( p_sys->i_period_time >> 1 );
818 msg_Err( p_aout, "unable to recover from buffer underrun" );
820 msleep( p_sys->i_period_time >> 1 );
824 /* Underrun, try to recover as quickly as possible */
829 /* Here the device should be either in the RUNNING state.
830 * p_status is valid. */
833 /* This apparently does not work correctly in Alsa 1.0.11 */
834 snd_pcm_status_get_tstamp( p_status, &ts_next );
835 next_date = (mtime_t)ts_next.tv_sec * 1000000 + ts_next.tv_usec;
838 next_date += (mtime_t)snd_pcm_status_get_delay(p_status)
839 * 1000000 / p_aout->output.output.i_rate;
844 /* With screwed ALSA drivers the timestamp is always zero;
845 * use another method then */
846 snd_pcm_sframes_t delay = 0;
848 snd_pcm_delay( p_sys->p_snd_pcm, &delay );
849 next_date = mdate() + (mtime_t)(delay) * 1000000 /
850 p_aout->output.output.i_rate
851 * p_aout->output.output.i_frame_length;
855 p_buffer = aout_OutputNextBuffer( p_aout, next_date,
856 (p_aout->output.output.i_format ==
857 VLC_FOURCC('s','p','d','i')) );
859 /* Audio output buffer shortage -> stop the fill process and wait */
860 if( p_buffer == NULL )
862 msleep( p_sys->i_period_time >> 1 );
866 i_snd_rc = snd_pcm_writei( p_sys->p_snd_pcm, p_buffer->p_buffer,
867 p_buffer->i_nb_samples );
871 msg_Err( p_aout, "write failed (%s)",
872 snd_strerror( i_snd_rc ) );
875 aout_BufferFree( p_buffer );
879 static void GetDevicesForCard(module_config_t *p_item, int i_card);
880 static void GetDevices( module_config_t *p_item );
882 /*****************************************************************************
883 * config variable callback
884 *****************************************************************************/
885 static int FindDevicesCallback( vlc_object_t *p_this, char const *psz_name,
886 vlc_value_t newval, vlc_value_t oldval, void *p_unused )
888 module_config_t *p_item;
891 p_item = config_FindConfig( p_this, psz_name );
892 if( !p_item ) return VLC_SUCCESS;
894 /* Clear-up the current list */
897 /* Keep the first entrie */
898 for( i = 1; i < p_item->i_list; i++ )
900 free( p_item->ppsz_list[i] );
901 free( p_item->ppsz_list_text[i] );
903 /* TODO: Remove when no more needed */
904 p_item->ppsz_list[i] = NULL;
905 p_item->ppsz_list_text[i] = NULL;
909 GetDevices( p_item );
911 /* Signal change to the interface */
912 p_item->b_dirty = VLC_TRUE;
919 static void GetDevicesForCard(module_config_t *p_item, int i_card)
921 int i_pcm_device = -1;
923 snd_pcm_info_t *p_pcm_info;
928 sprintf(psz_dev, "hw:%i", i_card);
930 if (( i_err = snd_ctl_open(&p_ctl, psz_dev, 0)) < 0 )
935 if ((i_err = snd_card_get_name(i_card, &psz_card_name)) != 0)
937 psz_card_name = _("Unknown soundcard");
940 snd_pcm_info_alloca(&p_pcm_info);
944 char *psz_device, *psz_descr;
945 if ((i_err = snd_ctl_pcm_next_device(p_ctl, &i_pcm_device)) < 0)
949 if ( i_pcm_device < 0 )
952 snd_pcm_info_set_device(p_pcm_info, i_pcm_device);
953 snd_pcm_info_set_subdevice(p_pcm_info, 0);
954 snd_pcm_info_set_stream(p_pcm_info, SND_PCM_STREAM_PLAYBACK);
956 if ((i_err = snd_ctl_pcm_info(p_ctl, p_pcm_info)) < 0)
958 if (i_err != -ENOENT)
960 /* printf("get_devices_for_card(): "
961 "snd_ctl_pcm_info() "
962 "failed (%d:%d): %s.\n", i_card,
963 i_pcm_device, snd_strerror(-i_err));*/
968 asprintf( &psz_device, "hw:%d,%d", i_card, i_pcm_device );
969 asprintf( &psz_descr, "%s: %s (%s)", psz_card_name,
970 snd_pcm_info_get_name(p_pcm_info), psz_device );
973 (char **)realloc( p_item->ppsz_list,
974 (p_item->i_list + 2) * sizeof(char *) );
975 p_item->ppsz_list_text =
976 (char **)realloc( p_item->ppsz_list_text,
977 (p_item->i_list + 2) * sizeof(char *) );
978 p_item->ppsz_list[ p_item->i_list ] = psz_device;
979 p_item->ppsz_list_text[ p_item->i_list ] = psz_descr;
981 p_item->ppsz_list[ p_item->i_list ] = NULL;
982 p_item->ppsz_list_text[ p_item->i_list ] = NULL;
985 snd_ctl_close( p_ctl );
990 static void GetDevices( module_config_t *p_item )
995 if ((i_err = snd_card_next(&i_card)) != 0)
997 // g_warning("snd_next_card() failed: %s", snd_strerror(-err));
1003 GetDevicesForCard(p_item, i_card);
1004 if ((i_err = snd_card_next(&i_card)) != 0)
1006 // g_warning("snd_next_card() failed: %s",
1007 // snd_strerror(-err));