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 *****************************************************************************/
30 #include <errno.h> /* ENOMEM */
31 #include <string.h> /* strerror() */
32 #include <stdlib.h> /* calloc(), malloc(), free() */
37 #include <vlc_interaction.h>
39 #include "aout_internal.h"
42 Note: we use the new API which is available since 0.9.0beta10a. */
43 #define ALSA_PCM_NEW_HW_PARAMS_API
44 #define ALSA_PCM_NEW_SW_PARAMS_API
45 #include <alsa/asoundlib.h>
47 /*****************************************************************************
48 * aout_sys_t: ALSA audio output method descriptor
49 *****************************************************************************
50 * This structure is part of the audio output thread descriptor.
51 * It describes the ALSA specific properties of an audio device.
52 *****************************************************************************/
55 snd_pcm_t * p_snd_pcm;
56 unsigned int i_period_time;
59 snd_output_t * p_snd_stderr;
62 int b_playing; /* playing status */
68 snd_pcm_status_t *p_status;
71 #define A52_FRAME_NB 1536
73 /* These values are in frames.
74 To convert them to a number of bytes you have to multiply them by the
75 number of channel(s) (eg. 2 for stereo) and the size of a sample (eg.
77 #define ALSA_DEFAULT_PERIOD_SIZE 1024
78 #define ALSA_DEFAULT_BUFFER_SIZE ( ALSA_DEFAULT_PERIOD_SIZE << 8 )
79 #define ALSA_SPDIF_PERIOD_SIZE A52_FRAME_NB
80 #define ALSA_SPDIF_BUFFER_SIZE ( ALSA_SPDIF_PERIOD_SIZE << 4 )
81 /* Why << 4 ? --Meuuh */
82 /* Why not ? --Bozo */
85 #define DEFAULT_ALSA_DEVICE N_("default")
87 /*****************************************************************************
89 *****************************************************************************/
90 static int Open ( vlc_object_t * );
91 static void Close ( vlc_object_t * );
92 static void Play ( aout_instance_t * );
93 static int ALSAThread ( aout_instance_t * );
94 static void ALSAFill ( aout_instance_t * );
95 static int FindDevicesCallback( vlc_object_t *p_this, char const *psz_name,
96 vlc_value_t newval, vlc_value_t oldval, void *p_unused );
98 /*****************************************************************************
100 *****************************************************************************/
101 static char *ppsz_devices[] = { "default" };
102 static char *ppsz_devices_text[] = { N_("Default") };
104 set_shortname( "ALSA" );
105 set_description( _("ALSA audio output") );
106 set_category( CAT_AUDIO );
107 set_subcategory( SUBCAT_AUDIO_AOUT );
108 add_string( "alsadev", DEFAULT_ALSA_DEVICE, aout_FindAndRestart,
109 N_("ALSA Device Name"), NULL, VLC_FALSE );
110 change_string_list( ppsz_devices, ppsz_devices_text, FindDevicesCallback );
111 change_action_add( FindDevicesCallback, N_("Refresh list") );
113 set_capability( "audio output", 150 );
114 set_callbacks( Open, Close );
117 /*****************************************************************************
118 * Probe: probe the audio device for available formats and channels
119 *****************************************************************************/
120 static void Probe( aout_instance_t * p_aout,
121 const char * psz_device, const char * psz_iec_device,
122 int *pi_snd_pcm_format )
124 struct aout_sys_t * p_sys = p_aout->output.p_sys;
125 vlc_value_t val, text;
128 var_Create ( p_aout, "audio-device", VLC_VAR_INTEGER | VLC_VAR_HASCHOICE );
129 text.psz_string = _("Audio Device");
130 var_Change( p_aout, "audio-device", VLC_VAR_SETTEXT, &text, NULL );
132 /* We'll open the audio device in non blocking mode so we can just exit
133 * when it is already in use, but for the real stuff we'll still use
134 * the blocking mode */
136 /* Now test linear PCM capabilities */
137 if ( !(i_ret = snd_pcm_open( &p_sys->p_snd_pcm, psz_device,
138 SND_PCM_STREAM_PLAYBACK,
139 SND_PCM_NONBLOCK ) ) )
142 snd_pcm_hw_params_t * p_hw;
143 snd_pcm_hw_params_alloca (&p_hw);
145 if ( snd_pcm_hw_params_any( p_sys->p_snd_pcm, p_hw ) < 0 )
147 msg_Warn( p_aout, "unable to retrieve initial hardware parameters"
148 ", disabling linear PCM audio" );
149 snd_pcm_close( p_sys->p_snd_pcm );
150 var_Destroy( p_aout, "audio-device" );
154 if ( snd_pcm_hw_params_set_format( p_sys->p_snd_pcm, p_hw,
155 *pi_snd_pcm_format ) < 0 )
159 if( *pi_snd_pcm_format != SND_PCM_FORMAT_S16 )
161 *pi_snd_pcm_format = SND_PCM_FORMAT_S16;
162 i_snd_rc = snd_pcm_hw_params_set_format( p_sys->p_snd_pcm,
163 p_hw, *pi_snd_pcm_format );
167 msg_Warn( p_aout, "unable to set stream sample size and "
168 "word order, disabling linear PCM audio" );
169 snd_pcm_close( p_sys->p_snd_pcm );
170 var_Destroy( p_aout, "audio-device" );
175 i_channels = aout_FormatNbChannels( &p_aout->output.output );
177 while ( i_channels > 0 )
179 if ( !snd_pcm_hw_params_test_channels( p_sys->p_snd_pcm, p_hw,
182 switch ( i_channels )
185 val.i_int = AOUT_VAR_MONO;
186 text.psz_string = N_("Mono");
187 var_Change( p_aout, "audio-device",
188 VLC_VAR_ADDCHOICE, &val, &text );
191 val.i_int = AOUT_VAR_STEREO;
192 text.psz_string = N_("Stereo");
193 var_Change( p_aout, "audio-device",
194 VLC_VAR_ADDCHOICE, &val, &text );
195 var_Set( p_aout, "audio-device", val );
198 val.i_int = AOUT_VAR_2F2R;
199 text.psz_string = N_("2 Front 2 Rear");
200 var_Change( p_aout, "audio-device",
201 VLC_VAR_ADDCHOICE, &val, &text );
204 val.i_int = AOUT_VAR_5_1;
205 text.psz_string = "5.1";
206 var_Change( p_aout, "audio-device",
207 VLC_VAR_ADDCHOICE, &val, &text );
215 /* Special case for mono on stereo only boards */
216 i_channels = aout_FormatNbChannels( &p_aout->output.output );
217 var_Change( p_aout, "audio-device", VLC_VAR_CHOICESCOUNT, &val, NULL );
218 if( val.i_int <= 0 && i_channels == 1 )
220 if ( !snd_pcm_hw_params_test_channels( p_sys->p_snd_pcm, p_hw, 2 ))
222 val.i_int = AOUT_VAR_STEREO;
223 text.psz_string = N_("Stereo");
224 var_Change( p_aout, "audio-device",
225 VLC_VAR_ADDCHOICE, &val, &text );
226 var_Set( p_aout, "audio-device", val );
230 /* Close the previously opened device */
231 snd_pcm_close( p_sys->p_snd_pcm );
233 else if ( i_ret == -EBUSY )
235 msg_Warn( p_aout, "audio device: %s is already in use", psz_device );
238 /* Test for S/PDIF device if needed */
239 if ( psz_iec_device )
241 /* Opening the device should be enough */
242 if ( !(i_ret = snd_pcm_open( &p_sys->p_snd_pcm, psz_iec_device,
243 SND_PCM_STREAM_PLAYBACK,
244 SND_PCM_NONBLOCK ) ) )
246 val.i_int = AOUT_VAR_SPDIF;
247 text.psz_string = N_("A/52 over S/PDIF");
248 var_Change( p_aout, "audio-device",
249 VLC_VAR_ADDCHOICE, &val, &text );
250 if( config_GetInt( p_aout, "spdif" ) )
251 var_Set( p_aout, "audio-device", val );
253 snd_pcm_close( p_sys->p_snd_pcm );
255 else if ( i_ret == -EBUSY )
257 msg_Warn( p_aout, "audio device: %s is already in use",
262 var_Change( p_aout, "audio-device", VLC_VAR_CHOICESCOUNT, &val, NULL );
265 /* Probe() has failed. */
266 msg_Dbg( p_aout, "failed to find a useable alsa configuration" );
267 var_Destroy( p_aout, "audio-device" );
271 /* Add final settings to the variable */
272 var_AddCallback( p_aout, "audio-device", aout_ChannelsRestart, NULL );
273 val.b_bool = VLC_TRUE;
274 var_Set( p_aout, "intf-change", val );
277 /*****************************************************************************
278 * Open: create a handle and open an alsa device
279 *****************************************************************************
280 * This function opens an alsa device, through the alsa API.
282 * Note: the only heap-allocated string is psz_device. All the other pointers
283 * are references to psz_device or to stack-allocated data.
284 *****************************************************************************/
285 static int Open( vlc_object_t *p_this )
287 aout_instance_t * p_aout = (aout_instance_t *)p_this;
288 struct aout_sys_t * p_sys;
291 char psz_default_iec_device[128]; /* Buffer used to store the default
293 char * psz_device, * psz_iec_device; /* device names for PCM and S/PDIF
296 int i_vlc_pcm_format; /* Audio format for VLC's data */
297 int i_snd_pcm_format; /* Audio format for ALSA's data */
299 snd_pcm_uframes_t i_buffer_size = 0;
300 snd_pcm_uframes_t i_period_size = 0;
303 snd_pcm_hw_params_t *p_hw;
304 snd_pcm_sw_params_t *p_sw;
307 unsigned int i_old_rate;
308 vlc_bool_t b_retry = VLC_TRUE;
310 /* Allocate structures */
311 p_aout->output.p_sys = p_sys = malloc( sizeof( aout_sys_t ) );
314 msg_Err( p_aout, "out of memory" );
317 p_sys->b_playing = VLC_FALSE;
318 p_sys->start_date = 0;
319 vlc_cond_init( p_aout, &p_sys->wait );
320 vlc_mutex_init( p_aout, &p_sys->lock );
322 /* Get device name */
323 if( (psz_device = config_GetPsz( p_aout, "alsadev" )) == NULL )
325 msg_Err( p_aout, "no audio device given (maybe \"default\" ?)" );
326 intf_UserFatal( p_aout, VLC_FALSE, _("No Audio Device"),
327 _("No audio device name was given. You might want to " \
328 "enter \"default\".") );
333 /* Choose the IEC device for S/PDIF output:
334 if the device is overriden by the user then it will be the one
335 otherwise we compute the default device based on the output format. */
336 if( AOUT_FMT_NON_LINEAR( &p_aout->output.output )
337 && !strcmp( psz_device, DEFAULT_ALSA_DEVICE ) )
339 snprintf( psz_default_iec_device, sizeof(psz_default_iec_device),
340 "iec958:AES0=0x%x,AES1=0x%x,AES2=0x%x,AES3=0x%x",
341 IEC958_AES0_CON_EMPHASIS_NONE | IEC958_AES0_NONAUDIO,
342 IEC958_AES1_CON_ORIGINAL | IEC958_AES1_CON_PCM_CODER,
344 ( p_aout->output.output.i_rate == 48000 ?
345 IEC958_AES3_CON_FS_48000 :
346 ( p_aout->output.output.i_rate == 44100 ?
347 IEC958_AES3_CON_FS_44100 : IEC958_AES3_CON_FS_32000 ) ) );
348 psz_iec_device = psz_default_iec_device;
350 else if( AOUT_FMT_NON_LINEAR( &p_aout->output.output ) )
352 psz_iec_device = psz_device;
356 psz_iec_device = NULL;
359 /* Choose the linear PCM format (read the comment above about FPU
361 if( p_aout->p_libvlc->i_cpu & CPU_CAPABILITY_FPU )
363 i_vlc_pcm_format = VLC_FOURCC('f','l','3','2');
364 i_snd_pcm_format = SND_PCM_FORMAT_FLOAT;
368 i_vlc_pcm_format = AOUT_FMT_S16_NE;
369 i_snd_pcm_format = SND_PCM_FORMAT_S16;
372 /* If the variable doesn't exist then it's the first time we're called
373 and we have to probe the available audio formats and channels */
374 if ( var_Type( p_aout, "audio-device" ) == 0 )
376 Probe( p_aout, psz_device, psz_iec_device, &i_snd_pcm_format );
379 if ( var_Get( p_aout, "audio-device", &val ) < 0 )
386 p_aout->output.output.i_format = i_vlc_pcm_format;
387 if ( val.i_int == AOUT_VAR_5_1 )
389 p_aout->output.output.i_physical_channels
390 = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER
391 | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT
394 psz_device = strdup( "surround51" );
396 else if ( val.i_int == AOUT_VAR_2F2R )
398 p_aout->output.output.i_physical_channels
399 = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT
400 | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT;
402 psz_device = strdup( "surround40" );
404 else if ( val.i_int == AOUT_VAR_STEREO )
406 p_aout->output.output.i_physical_channels
407 = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT;
409 else if ( val.i_int == AOUT_VAR_MONO )
411 p_aout->output.output.i_physical_channels = AOUT_CHAN_CENTER;
413 else if( val.i_int != AOUT_VAR_SPDIF )
415 /* This should not happen ! */
416 msg_Err( p_aout, "internal: can't find audio-device (%i)", val.i_int );
423 snd_output_stdio_attach( &p_sys->p_snd_stderr, stderr, 0 );
426 /* Open the device */
427 if ( val.i_int == AOUT_VAR_SPDIF )
429 if ( ( i_snd_rc = snd_pcm_open( &p_sys->p_snd_pcm, psz_iec_device,
430 SND_PCM_STREAM_PLAYBACK, 0 ) ) < 0 )
432 msg_Err( p_aout, "cannot open ALSA device `%s' (%s)",
433 psz_iec_device, snd_strerror( i_snd_rc ) );
434 intf_UserFatal( p_aout, VLC_FALSE, _("Audio output failed"),
435 _("VLC could not open the ALSA device \"%s\" (%s)."),
436 psz_iec_device, snd_strerror( i_snd_rc ) );
441 i_buffer_size = ALSA_SPDIF_BUFFER_SIZE;
442 i_snd_pcm_format = SND_PCM_FORMAT_S16;
445 i_vlc_pcm_format = VLC_FOURCC('s','p','d','i');
446 p_aout->output.i_nb_samples = i_period_size = ALSA_SPDIF_PERIOD_SIZE;
447 p_aout->output.output.i_bytes_per_frame = AOUT_SPDIF_SIZE;
448 p_aout->output.output.i_frame_length = A52_FRAME_NB;
450 aout_VolumeNoneInit( p_aout );
456 msg_Dbg( p_aout, "opening ALSA device `%s'", psz_device );
458 /* Since it seems snd_pcm_close hasen't really released the device at
459 the time it returns, probe if the device is available in loop for 1s.
460 We cannot use blocking mode since the we would wait indefinitely when
461 switching from a dmx device to surround51. */
463 for( i = 10; i >= 0; i-- )
465 if ( ( i_snd_rc = snd_pcm_open( &p_sys->p_snd_pcm, psz_device,
466 SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK ) ) == -EBUSY )
468 if( i ) msleep( 100000 /* 100ms */ );
471 msg_Err( p_aout, "audio device: %s is already in use",
473 intf_UserFatal( p_aout, VLC_FALSE, _("Audio output failed"),
474 _("The audio device \"%s\" is already in use."),
483 msg_Err( p_aout, "cannot open ALSA device `%s' (%s)",
484 psz_device, snd_strerror( i_snd_rc ) );
485 intf_UserFatal( p_aout, VLC_FALSE, _("Audio output failed"),
486 _("VLC could not open the ALSA device \"%s\" (%s)."),
487 psz_device, snd_strerror( i_snd_rc ) );
493 /* We want blocking mode */
494 snd_pcm_nonblock( p_sys->p_snd_pcm, 0 );
496 i_buffer_size = ALSA_DEFAULT_BUFFER_SIZE;
497 i_channels = aout_FormatNbChannels( &p_aout->output.output );
499 p_aout->output.i_nb_samples = i_period_size = ALSA_DEFAULT_PERIOD_SIZE;
501 aout_VolumeSoftInit( p_aout );
504 /* Free psz_device so that all the remaining data is stack-allocated */
507 p_aout->output.pf_play = Play;
509 snd_pcm_hw_params_alloca(&p_hw);
510 snd_pcm_sw_params_alloca(&p_sw);
512 /* Due to some bugs in alsa with some drivers, we need to retry in s16l
513 if snd_pcm_hw_params fails in fl32 */
518 /* Get Initial hardware parameters */
519 if ( ( i_snd_rc = snd_pcm_hw_params_any( p_sys->p_snd_pcm, p_hw ) ) < 0 )
521 msg_Err( p_aout, "unable to retrieve initial hardware parameters (%s)",
522 snd_strerror( i_snd_rc ) );
527 if ( ( i_snd_rc = snd_pcm_hw_params_set_format( p_sys->p_snd_pcm, p_hw,
528 i_snd_pcm_format ) ) < 0 )
530 if( i_snd_pcm_format != SND_PCM_FORMAT_S16 )
532 i_snd_pcm_format = SND_PCM_FORMAT_S16;
533 i_snd_rc = snd_pcm_hw_params_set_format( p_sys->p_snd_pcm,
534 p_hw, i_snd_pcm_format );
538 msg_Err( p_aout, "unable to set stream sample size and "
539 "word order (%s)", snd_strerror( i_snd_rc ) );
543 if( i_vlc_pcm_format != VLC_FOURCC('s','p','d','i') )
544 switch( i_snd_pcm_format )
546 case SND_PCM_FORMAT_FLOAT:
547 i_vlc_pcm_format = VLC_FOURCC('f','l','3','2');
549 case SND_PCM_FORMAT_S16:
550 i_vlc_pcm_format = AOUT_FMT_S16_NE;
553 p_aout->output.output.i_format = i_vlc_pcm_format;
555 if ( ( i_snd_rc = snd_pcm_hw_params_set_access( p_sys->p_snd_pcm, p_hw,
556 SND_PCM_ACCESS_RW_INTERLEAVED ) ) < 0 )
558 msg_Err( p_aout, "unable to set interleaved stream format (%s)",
559 snd_strerror( i_snd_rc ) );
564 if ( ( i_snd_rc = snd_pcm_hw_params_set_channels( p_sys->p_snd_pcm, p_hw,
567 msg_Err( p_aout, "unable to set number of output channels (%s)",
568 snd_strerror( i_snd_rc ) );
573 i_old_rate = p_aout->output.output.i_rate;
574 #ifdef HAVE_ALSA_NEW_API
575 i_snd_rc = snd_pcm_hw_params_set_rate_near( p_sys->p_snd_pcm, p_hw,
576 &p_aout->output.output.i_rate,
579 i_snd_rc = snd_pcm_hw_params_set_rate_near( p_sys->p_snd_pcm, p_hw,
580 p_aout->output.output.i_rate,
583 if( i_snd_rc < 0 || p_aout->output.output.i_rate != i_old_rate )
585 msg_Warn( p_aout, "The rate %d Hz is not supported by your " \
586 "hardware. Using %d Hz instead.\n", i_old_rate, \
587 p_aout->output.output.i_rate );
590 /* Set buffer size. */
591 #ifdef HAVE_ALSA_NEW_API
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 )
595 if ( ( i_snd_rc = snd_pcm_hw_params_set_buffer_size_near( p_sys->p_snd_pcm,
596 p_hw, i_buffer_size ) ) < 0 )
599 msg_Err( p_aout, "unable to set buffer size (%s)",
600 snd_strerror( i_snd_rc ) );
604 /* Set period size. */
605 #ifdef HAVE_ALSA_NEW_API
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 )
609 if ( ( i_snd_rc = snd_pcm_hw_params_set_period_size_near( p_sys->p_snd_pcm,
610 p_hw, i_period_size, NULL ) ) < 0 )
613 msg_Err( p_aout, "unable to set period size (%s)",
614 snd_strerror( i_snd_rc ) );
617 p_aout->output.i_nb_samples = i_period_size;
619 /* Commit hardware parameters. */
620 if ( ( i_snd_rc = snd_pcm_hw_params( p_sys->p_snd_pcm, p_hw ) ) < 0 )
622 if ( b_retry == VLC_FALSE &&
623 i_snd_pcm_format == SND_PCM_FORMAT_FLOAT)
626 i_snd_pcm_format = SND_PCM_FORMAT_S16;
627 p_aout->output.output.i_format = AOUT_FMT_S16_NE;
628 msg_Warn( p_aout, "unable to commit hardware configuration "
629 "with fl32 samples. Retrying with s16l (%s)", snd_strerror( i_snd_rc ) );
633 msg_Err( p_aout, "unable to commit hardware configuration (%s)",
634 snd_strerror( i_snd_rc ) );
640 #ifdef HAVE_ALSA_NEW_API
641 if( ( i_snd_rc = snd_pcm_hw_params_get_period_time( p_hw,
642 &p_sys->i_period_time, NULL ) ) < 0 )
644 if( ( p_sys->i_period_time =
645 (int)snd_pcm_hw_params_get_period_time( p_hw, NULL ) ) < 0 )
648 msg_Err( p_aout, "unable to get period time (%s)",
649 snd_strerror( i_snd_rc ) );
653 /* Get Initial software parameters */
654 snd_pcm_sw_params_current( p_sys->p_snd_pcm, p_sw );
656 i_snd_rc = snd_pcm_sw_params_set_sleep_min( p_sys->p_snd_pcm, p_sw, 0 );
658 i_snd_rc = snd_pcm_sw_params_set_avail_min( p_sys->p_snd_pcm, p_sw,
659 p_aout->output.i_nb_samples );
661 /* Commit software parameters. */
662 if ( snd_pcm_sw_params( p_sys->p_snd_pcm, p_sw ) < 0 )
664 msg_Err( p_aout, "unable to set software configuration" );
669 snd_output_printf( p_sys->p_snd_stderr, "\nALSA hardware setup:\n\n" );
670 snd_pcm_dump_hw_setup( p_sys->p_snd_pcm, p_sys->p_snd_stderr );
671 snd_output_printf( p_sys->p_snd_stderr, "\nALSA software setup:\n\n" );
672 snd_pcm_dump_sw_setup( p_sys->p_snd_pcm, p_sys->p_snd_stderr );
673 snd_output_printf( p_sys->p_snd_stderr, "\n" );
676 /* Create ALSA thread and wait for its readiness. */
677 if( vlc_thread_create( p_aout, "aout", ALSAThread,
678 VLC_THREAD_PRIORITY_OUTPUT, VLC_FALSE ) )
680 msg_Err( p_aout, "cannot create ALSA thread (%s)", strerror(errno) );
687 snd_pcm_close( p_sys->p_snd_pcm );
689 snd_output_close( p_sys->p_snd_stderr );
695 /*****************************************************************************
696 * Play: nothing to do
697 *****************************************************************************/
698 static void Play( aout_instance_t *p_aout )
700 if( !p_aout->output.p_sys->b_playing )
702 p_aout->output.p_sys->b_playing = 1;
704 /* get the playing date of the first aout buffer */
705 p_aout->output.p_sys->start_date =
706 aout_FifoFirstDate( p_aout, &p_aout->output.fifo );
708 /* wake up the audio output thread */
709 vlc_mutex_lock( &p_aout->output.p_sys->lock );
710 vlc_cond_signal( &p_aout->output.p_sys->wait );
711 vlc_mutex_unlock( &p_aout->output.p_sys->lock );
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 the audio output thread is waken up */
725 vlc_mutex_lock( &p_aout->output.p_sys->lock );
726 vlc_cond_signal( &p_aout->output.p_sys->wait );
727 vlc_mutex_unlock( &p_aout->output.p_sys->lock );
729 p_aout->b_die = VLC_TRUE;
730 vlc_thread_join( p_aout );
731 p_aout->b_die = VLC_FALSE;
733 i_snd_rc = snd_pcm_close( p_sys->p_snd_pcm );
737 msg_Err( p_aout, "failed closing ALSA device (%s)",
738 snd_strerror( i_snd_rc ) );
742 snd_output_close( p_sys->p_snd_stderr );
748 /*****************************************************************************
749 * ALSAThread: asynchronous thread used to DMA the data to the device
750 *****************************************************************************/
751 static int ALSAThread( aout_instance_t * p_aout )
753 p_aout->output.p_sys->p_status =
754 (snd_pcm_status_t *)malloc(snd_pcm_status_sizeof());
756 /* Wait for the exact time to start playing (avoids resampling) */
757 vlc_mutex_lock( &p_aout->output.p_sys->lock );
758 if( !p_aout->output.p_sys->start_date )
759 vlc_cond_wait( &p_aout->output.p_sys->wait,
760 &p_aout->output.p_sys->lock );
761 vlc_mutex_unlock( &p_aout->output.p_sys->lock );
763 mwait( p_aout->output.p_sys->start_date - AOUT_PTS_TOLERANCE / 4 );
765 while ( !p_aout->b_die )
770 free( p_aout->output.p_sys->p_status );
774 /*****************************************************************************
775 * ALSAFill: function used to fill the ALSA buffer as much as possible
776 *****************************************************************************/
777 static void ALSAFill( aout_instance_t * p_aout )
779 struct aout_sys_t * p_sys = p_aout->output.p_sys;
780 aout_buffer_t * p_buffer;
781 snd_pcm_status_t * p_status = p_sys->p_status;
785 /* Fill in the buffer until space or audio output buffer shortage */
788 i_snd_rc = snd_pcm_status( p_sys->p_snd_pcm, p_status );
791 msg_Err( p_aout, "unable to get the device's status (%s)",
792 snd_strerror( i_snd_rc ) );
794 msleep( p_sys->i_period_time >> 1 );
798 /* Handle buffer underruns and reget the status */
799 if( snd_pcm_status_get_state( p_status ) == SND_PCM_STATE_XRUN )
801 /* Prepare the device */
802 i_snd_rc = snd_pcm_prepare( p_sys->p_snd_pcm );
806 msg_Dbg( p_aout, "recovered from buffer underrun" );
808 /* Reget the status */
809 i_snd_rc = snd_pcm_status( p_sys->p_snd_pcm, p_status );
812 msg_Err( p_aout, "unable to get the device's status after "
813 "recovery (%s)", snd_strerror( i_snd_rc ) );
815 msleep( p_sys->i_period_time >> 1 );
821 msg_Err( p_aout, "unable to recover from buffer underrun" );
823 msleep( p_sys->i_period_time >> 1 );
827 /* Underrun, try to recover as quickly as possible */
832 /* Here the device should be either in the RUNNING state.
833 * p_status is valid. */
836 /* This apparently does not work correctly in Alsa 1.0.11 */
837 snd_pcm_status_get_tstamp( p_status, &ts_next );
838 next_date = (mtime_t)ts_next.tv_sec * 1000000 + ts_next.tv_usec;
841 next_date += (mtime_t)snd_pcm_status_get_delay(p_status)
842 * 1000000 / p_aout->output.output.i_rate;
847 /* With screwed ALSA drivers the timestamp is always zero;
848 * use another method then */
849 snd_pcm_sframes_t delay = 0;
851 snd_pcm_delay( p_sys->p_snd_pcm, &delay );
852 next_date = mdate() + (mtime_t)(delay) * 1000000 /
853 p_aout->output.output.i_rate
854 * p_aout->output.output.i_frame_length;
858 p_buffer = aout_OutputNextBuffer( p_aout, next_date,
859 (p_aout->output.output.i_format ==
860 VLC_FOURCC('s','p','d','i')) );
862 /* Audio output buffer shortage -> stop the fill process and wait */
863 if( p_buffer == NULL )
865 msleep( p_sys->i_period_time >> 1 );
869 i_snd_rc = snd_pcm_writei( p_sys->p_snd_pcm, p_buffer->p_buffer,
870 p_buffer->i_nb_samples );
874 msg_Err( p_aout, "write failed (%s)",
875 snd_strerror( i_snd_rc ) );
878 aout_BufferFree( p_buffer );
882 static void GetDevicesForCard(module_config_t *p_item, int i_card);
883 static void GetDevices( module_config_t *p_item );
885 /*****************************************************************************
886 * config variable callback
887 *****************************************************************************/
888 static int FindDevicesCallback( vlc_object_t *p_this, char const *psz_name,
889 vlc_value_t newval, vlc_value_t oldval, void *p_unused )
891 module_config_t *p_item;
894 p_item = config_FindConfig( p_this, psz_name );
895 if( !p_item ) return VLC_SUCCESS;
897 /* Clear-up the current list */
900 /* Keep the first entrie */
901 for( i = 1; i < p_item->i_list; i++ )
903 free( p_item->ppsz_list[i] );
904 free( p_item->ppsz_list_text[i] );
906 /* TODO: Remove when no more needed */
907 p_item->ppsz_list[i] = NULL;
908 p_item->ppsz_list_text[i] = NULL;
912 GetDevices( p_item );
914 /* Signal change to the interface */
915 p_item->b_dirty = VLC_TRUE;
922 static void GetDevicesForCard(module_config_t *p_item, int i_card)
924 int i_pcm_device = -1;
926 snd_pcm_info_t *p_pcm_info;
931 sprintf(psz_dev, "hw:%i", i_card);
933 if (( i_err = snd_ctl_open(&p_ctl, psz_dev, 0)) < 0 )
938 if ((i_err = snd_card_get_name(i_card, &psz_card_name)) != 0)
940 psz_card_name = _("Unknown soundcard");
943 snd_pcm_info_alloca(&p_pcm_info);
947 char *psz_device, *psz_descr;
948 if ((i_err = snd_ctl_pcm_next_device(p_ctl, &i_pcm_device)) < 0)
952 if ( i_pcm_device < 0 )
955 snd_pcm_info_set_device(p_pcm_info, i_pcm_device);
956 snd_pcm_info_set_subdevice(p_pcm_info, 0);
957 snd_pcm_info_set_stream(p_pcm_info, SND_PCM_STREAM_PLAYBACK);
959 if ((i_err = snd_ctl_pcm_info(p_ctl, p_pcm_info)) < 0)
961 if (i_err != -ENOENT)
963 /* printf("get_devices_for_card(): "
964 "snd_ctl_pcm_info() "
965 "failed (%d:%d): %s.\n", i_card,
966 i_pcm_device, snd_strerror(-i_err));*/
971 asprintf( &psz_device, "hw:%d,%d", i_card, i_pcm_device );
972 asprintf( &psz_descr, "%s: %s (%s)", psz_card_name,
973 snd_pcm_info_get_name(p_pcm_info), psz_device );
976 (char **)realloc( p_item->ppsz_list,
977 (p_item->i_list + 2) * sizeof(char *) );
978 p_item->ppsz_list_text =
979 (char **)realloc( p_item->ppsz_list_text,
980 (p_item->i_list + 2) * sizeof(char *) );
981 p_item->ppsz_list[ p_item->i_list ] = psz_device;
982 p_item->ppsz_list_text[ p_item->i_list ] = psz_descr;
984 p_item->ppsz_list[ p_item->i_list ] = NULL;
985 p_item->ppsz_list_text[ p_item->i_list ] = NULL;
989 snd_ctl_close( p_ctl );
994 static void GetDevices( module_config_t *p_item )
999 if ((i_err = snd_card_next(&i_card)) != 0)
1001 // g_warning("snd_next_card() failed: %s", snd_strerror(-err));
1007 GetDevicesForCard(p_item, i_card);
1008 if ((i_err = snd_card_next(&i_card)) != 0)
1010 // g_warning("snd_next_card() failed: %s",
1011 // snd_strerror(-err));