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 *****************************************************************************/
32 #include <errno.h> /* ENOMEM */
33 #include <vlc_interface.h>
38 Note: we use the new API which is available since 0.9.0beta10a. */
39 #define ALSA_PCM_NEW_HW_PARAMS_API
40 #define ALSA_PCM_NEW_SW_PARAMS_API
41 #include <alsa/asoundlib.h>
43 /*****************************************************************************
44 * aout_sys_t: ALSA audio output method descriptor
45 *****************************************************************************
46 * This structure is part of the audio output thread descriptor.
47 * It describes the ALSA specific properties of an audio device.
48 *****************************************************************************/
51 snd_pcm_t * p_snd_pcm;
52 unsigned int i_period_time;
55 snd_output_t * p_snd_stderr;
58 int b_playing; /* playing status */
64 snd_pcm_status_t *p_status;
67 #define A52_FRAME_NB 1536
69 /* These values are in frames.
70 To convert them to a number of bytes you have to multiply them by the
71 number of channel(s) (eg. 2 for stereo) and the size of a sample (eg.
73 #define ALSA_DEFAULT_PERIOD_SIZE 1024
74 #define ALSA_DEFAULT_BUFFER_SIZE ( ALSA_DEFAULT_PERIOD_SIZE << 8 )
75 #define ALSA_SPDIF_PERIOD_SIZE A52_FRAME_NB
76 #define ALSA_SPDIF_BUFFER_SIZE ( ALSA_SPDIF_PERIOD_SIZE << 4 )
77 /* Why << 4 ? --Meuuh */
78 /* Why not ? --Bozo */
81 #define DEFAULT_ALSA_DEVICE N_("default")
83 /*****************************************************************************
85 *****************************************************************************/
86 static int Open ( vlc_object_t * );
87 static void Close ( vlc_object_t * );
88 static void Play ( aout_instance_t * );
89 static int ALSAThread ( aout_instance_t * );
90 static void ALSAFill ( aout_instance_t * );
91 static int FindDevicesCallback( vlc_object_t *p_this, char const *psz_name,
92 vlc_value_t newval, vlc_value_t oldval, void *p_unused );
94 /*****************************************************************************
96 *****************************************************************************/
97 static const char *ppsz_devices[] = { "default" };
98 static const char *ppsz_devices_text[] = { N_("Default") };
100 set_shortname( "ALSA" );
101 set_description( _("ALSA audio output") );
102 set_category( CAT_AUDIO );
103 set_subcategory( SUBCAT_AUDIO_AOUT );
104 add_string( "alsadev", DEFAULT_ALSA_DEVICE, aout_FindAndRestart,
105 N_("ALSA Device Name"), NULL, VLC_FALSE );
106 change_string_list( ppsz_devices, ppsz_devices_text, FindDevicesCallback );
107 change_action_add( FindDevicesCallback, N_("Refresh list") );
109 set_capability( "audio output", 150 );
110 set_callbacks( Open, Close );
113 /*****************************************************************************
114 * Probe: probe the audio device for available formats and channels
115 *****************************************************************************/
116 static void Probe( aout_instance_t * p_aout,
117 const char * psz_device, const char * psz_iec_device,
118 int *pi_snd_pcm_format )
120 struct aout_sys_t * p_sys = p_aout->output.p_sys;
121 vlc_value_t val, text;
124 var_Create ( p_aout, "audio-device", VLC_VAR_INTEGER | VLC_VAR_HASCHOICE );
125 text.psz_string = _("Audio Device");
126 var_Change( p_aout, "audio-device", VLC_VAR_SETTEXT, &text, NULL );
128 /* We'll open the audio device in non blocking mode so we can just exit
129 * when it is already in use, but for the real stuff we'll still use
130 * the blocking mode */
132 /* Now test linear PCM capabilities */
133 if ( !(i_ret = snd_pcm_open( &p_sys->p_snd_pcm, psz_device,
134 SND_PCM_STREAM_PLAYBACK,
135 SND_PCM_NONBLOCK ) ) )
138 snd_pcm_hw_params_t * p_hw;
139 snd_pcm_hw_params_alloca (&p_hw);
141 if ( snd_pcm_hw_params_any( p_sys->p_snd_pcm, p_hw ) < 0 )
143 msg_Warn( p_aout, "unable to retrieve initial hardware parameters"
144 ", disabling linear PCM audio" );
145 snd_pcm_close( p_sys->p_snd_pcm );
146 var_Destroy( p_aout, "audio-device" );
150 if ( snd_pcm_hw_params_set_format( p_sys->p_snd_pcm, p_hw,
151 *pi_snd_pcm_format ) < 0 )
155 if( *pi_snd_pcm_format != SND_PCM_FORMAT_S16 )
157 *pi_snd_pcm_format = SND_PCM_FORMAT_S16;
158 i_snd_rc = snd_pcm_hw_params_set_format( p_sys->p_snd_pcm,
159 p_hw, *pi_snd_pcm_format );
163 msg_Warn( p_aout, "unable to set stream sample size and "
164 "word order, disabling linear PCM audio" );
165 snd_pcm_close( p_sys->p_snd_pcm );
166 var_Destroy( p_aout, "audio-device" );
171 i_channels = aout_FormatNbChannels( &p_aout->output.output );
173 while ( i_channels > 0 )
175 if ( !snd_pcm_hw_params_test_channels( p_sys->p_snd_pcm, p_hw,
178 switch ( i_channels )
181 val.i_int = AOUT_VAR_MONO;
182 text.psz_string = N_("Mono");
183 var_Change( p_aout, "audio-device",
184 VLC_VAR_ADDCHOICE, &val, &text );
187 val.i_int = AOUT_VAR_STEREO;
188 text.psz_string = N_("Stereo");
189 var_Change( p_aout, "audio-device",
190 VLC_VAR_ADDCHOICE, &val, &text );
191 var_Set( p_aout, "audio-device", val );
194 val.i_int = AOUT_VAR_2F2R;
195 text.psz_string = N_("2 Front 2 Rear");
196 var_Change( p_aout, "audio-device",
197 VLC_VAR_ADDCHOICE, &val, &text );
200 val.i_int = AOUT_VAR_5_1;
201 text.psz_string = "5.1";
202 var_Change( p_aout, "audio-device",
203 VLC_VAR_ADDCHOICE, &val, &text );
211 /* Special case for mono on stereo only boards */
212 i_channels = aout_FormatNbChannels( &p_aout->output.output );
213 var_Change( p_aout, "audio-device", VLC_VAR_CHOICESCOUNT, &val, NULL );
214 if( val.i_int <= 0 && i_channels == 1 )
216 if ( !snd_pcm_hw_params_test_channels( p_sys->p_snd_pcm, p_hw, 2 ))
218 val.i_int = AOUT_VAR_STEREO;
219 text.psz_string = N_("Stereo");
220 var_Change( p_aout, "audio-device",
221 VLC_VAR_ADDCHOICE, &val, &text );
222 var_Set( p_aout, "audio-device", val );
226 /* Close the previously opened device */
227 snd_pcm_close( p_sys->p_snd_pcm );
229 else if ( i_ret == -EBUSY )
231 msg_Warn( p_aout, "audio device: %s is already in use", psz_device );
234 /* Test for S/PDIF device if needed */
235 if ( psz_iec_device )
237 /* Opening the device should be enough */
238 if ( !(i_ret = snd_pcm_open( &p_sys->p_snd_pcm, psz_iec_device,
239 SND_PCM_STREAM_PLAYBACK,
240 SND_PCM_NONBLOCK ) ) )
242 val.i_int = AOUT_VAR_SPDIF;
243 text.psz_string = N_("A/52 over S/PDIF");
244 var_Change( p_aout, "audio-device",
245 VLC_VAR_ADDCHOICE, &val, &text );
246 if( config_GetInt( p_aout, "spdif" ) )
247 var_Set( p_aout, "audio-device", val );
249 snd_pcm_close( p_sys->p_snd_pcm );
251 else if ( i_ret == -EBUSY )
253 msg_Warn( p_aout, "audio device: %s is already in use",
258 var_Change( p_aout, "audio-device", VLC_VAR_CHOICESCOUNT, &val, NULL );
261 /* Probe() has failed. */
262 msg_Dbg( p_aout, "failed to find a useable alsa configuration" );
263 var_Destroy( p_aout, "audio-device" );
267 /* Add final settings to the variable */
268 var_AddCallback( p_aout, "audio-device", aout_ChannelsRestart, NULL );
269 val.b_bool = VLC_TRUE;
270 var_Set( p_aout, "intf-change", val );
273 /*****************************************************************************
274 * Open: create a handle and open an alsa device
275 *****************************************************************************
276 * This function opens an alsa device, through the alsa API.
278 * Note: the only heap-allocated string is psz_device. All the other pointers
279 * are references to psz_device or to stack-allocated data.
280 *****************************************************************************/
281 static int Open( vlc_object_t *p_this )
283 aout_instance_t * p_aout = (aout_instance_t *)p_this;
284 struct aout_sys_t * p_sys;
287 char psz_default_iec_device[128]; /* Buffer used to store the default
289 char * psz_device, * psz_iec_device; /* device names for PCM and S/PDIF
292 int i_vlc_pcm_format; /* Audio format for VLC's data */
293 int i_snd_pcm_format; /* Audio format for ALSA's data */
295 snd_pcm_uframes_t i_buffer_size = 0;
296 snd_pcm_uframes_t i_period_size = 0;
299 snd_pcm_hw_params_t *p_hw;
300 snd_pcm_sw_params_t *p_sw;
303 unsigned int i_old_rate;
304 vlc_bool_t b_retry = VLC_TRUE;
306 /* Allocate structures */
307 p_aout->output.p_sys = p_sys = malloc( sizeof( aout_sys_t ) );
310 msg_Err( p_aout, "out of memory" );
313 p_sys->b_playing = VLC_FALSE;
314 p_sys->start_date = 0;
315 vlc_cond_init( p_aout, &p_sys->wait );
316 vlc_mutex_init( p_aout, &p_sys->lock );
318 /* Get device name */
319 if( (psz_device = config_GetPsz( p_aout, "alsadev" )) == NULL )
321 msg_Err( p_aout, "no audio device given (maybe \"default\" ?)" );
322 intf_UserFatal( p_aout, VLC_FALSE, _("No Audio Device"),
323 _("No audio device name was given. You might want to " \
324 "enter \"default\".") );
329 /* Choose the IEC device for S/PDIF output:
330 if the device is overriden by the user then it will be the one
331 otherwise we compute the default device based on the output format. */
332 if( AOUT_FMT_NON_LINEAR( &p_aout->output.output )
333 && !strcmp( psz_device, DEFAULT_ALSA_DEVICE ) )
335 snprintf( psz_default_iec_device, sizeof(psz_default_iec_device),
336 "iec958:AES0=0x%x,AES1=0x%x,AES2=0x%x,AES3=0x%x",
337 IEC958_AES0_CON_EMPHASIS_NONE | IEC958_AES0_NONAUDIO,
338 IEC958_AES1_CON_ORIGINAL | IEC958_AES1_CON_PCM_CODER,
340 ( p_aout->output.output.i_rate == 48000 ?
341 IEC958_AES3_CON_FS_48000 :
342 ( p_aout->output.output.i_rate == 44100 ?
343 IEC958_AES3_CON_FS_44100 : IEC958_AES3_CON_FS_32000 ) ) );
344 psz_iec_device = psz_default_iec_device;
346 else if( AOUT_FMT_NON_LINEAR( &p_aout->output.output ) )
348 psz_iec_device = psz_device;
352 psz_iec_device = NULL;
355 /* Choose the linear PCM format (read the comment above about FPU
357 if( vlc_CPU() & CPU_CAPABILITY_FPU )
359 i_vlc_pcm_format = VLC_FOURCC('f','l','3','2');
360 i_snd_pcm_format = SND_PCM_FORMAT_FLOAT;
364 i_vlc_pcm_format = AOUT_FMT_S16_NE;
365 i_snd_pcm_format = SND_PCM_FORMAT_S16;
368 /* If the variable doesn't exist then it's the first time we're called
369 and we have to probe the available audio formats and channels */
370 if ( var_Type( p_aout, "audio-device" ) == 0 )
372 Probe( p_aout, psz_device, psz_iec_device, &i_snd_pcm_format );
375 if ( var_Get( p_aout, "audio-device", &val ) < 0 )
382 p_aout->output.output.i_format = i_vlc_pcm_format;
383 if ( val.i_int == AOUT_VAR_5_1 )
385 p_aout->output.output.i_physical_channels
386 = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER
387 | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT
390 psz_device = strdup( "surround51" );
392 else if ( val.i_int == AOUT_VAR_2F2R )
394 p_aout->output.output.i_physical_channels
395 = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT
396 | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT;
398 psz_device = strdup( "surround40" );
400 else if ( val.i_int == AOUT_VAR_STEREO )
402 p_aout->output.output.i_physical_channels
403 = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT;
405 else if ( val.i_int == AOUT_VAR_MONO )
407 p_aout->output.output.i_physical_channels = AOUT_CHAN_CENTER;
409 else if( val.i_int != AOUT_VAR_SPDIF )
411 /* This should not happen ! */
412 msg_Err( p_aout, "internal: can't find audio-device (%i)", val.i_int );
419 snd_output_stdio_attach( &p_sys->p_snd_stderr, stderr, 0 );
422 /* Open the device */
423 if ( val.i_int == AOUT_VAR_SPDIF )
425 if ( ( i_snd_rc = snd_pcm_open( &p_sys->p_snd_pcm, psz_iec_device,
426 SND_PCM_STREAM_PLAYBACK, 0 ) ) < 0 )
428 msg_Err( p_aout, "cannot open ALSA device `%s' (%s)",
429 psz_iec_device, snd_strerror( i_snd_rc ) );
430 intf_UserFatal( p_aout, VLC_FALSE, _("Audio output failed"),
431 _("VLC could not open the ALSA device \"%s\" (%s)."),
432 psz_iec_device, snd_strerror( i_snd_rc ) );
437 i_buffer_size = ALSA_SPDIF_BUFFER_SIZE;
438 i_snd_pcm_format = SND_PCM_FORMAT_S16;
441 i_vlc_pcm_format = VLC_FOURCC('s','p','d','i');
442 p_aout->output.i_nb_samples = i_period_size = ALSA_SPDIF_PERIOD_SIZE;
443 p_aout->output.output.i_bytes_per_frame = AOUT_SPDIF_SIZE;
444 p_aout->output.output.i_frame_length = A52_FRAME_NB;
446 aout_VolumeNoneInit( p_aout );
452 msg_Dbg( p_aout, "opening ALSA device `%s'", psz_device );
454 /* Since it seems snd_pcm_close hasen't really released the device at
455 the time it returns, probe if the device is available in loop for 1s.
456 We cannot use blocking mode since the we would wait indefinitely when
457 switching from a dmx device to surround51. */
459 for( i = 10; i >= 0; i-- )
461 if ( ( i_snd_rc = snd_pcm_open( &p_sys->p_snd_pcm, psz_device,
462 SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK ) ) == -EBUSY )
464 if( i ) msleep( 100000 /* 100ms */ );
467 msg_Err( p_aout, "audio device: %s is already in use",
469 intf_UserFatal( p_aout, VLC_FALSE, _("Audio output failed"),
470 _("The audio device \"%s\" is already in use."),
479 msg_Err( p_aout, "cannot open ALSA device `%s' (%s)",
480 psz_device, snd_strerror( i_snd_rc ) );
481 intf_UserFatal( p_aout, VLC_FALSE, _("Audio output failed"),
482 _("VLC could not open the ALSA device \"%s\" (%s)."),
483 psz_device, snd_strerror( i_snd_rc ) );
489 /* We want blocking mode */
490 snd_pcm_nonblock( p_sys->p_snd_pcm, 0 );
492 i_buffer_size = ALSA_DEFAULT_BUFFER_SIZE;
493 i_channels = aout_FormatNbChannels( &p_aout->output.output );
495 p_aout->output.i_nb_samples = i_period_size = ALSA_DEFAULT_PERIOD_SIZE;
497 aout_VolumeSoftInit( p_aout );
500 /* Free psz_device so that all the remaining data is stack-allocated */
503 p_aout->output.pf_play = Play;
505 snd_pcm_hw_params_alloca(&p_hw);
506 snd_pcm_sw_params_alloca(&p_sw);
508 /* Due to some bugs in alsa with some drivers, we need to retry in s16l
509 if snd_pcm_hw_params fails in fl32 */
514 /* Get Initial hardware parameters */
515 if ( ( i_snd_rc = snd_pcm_hw_params_any( p_sys->p_snd_pcm, p_hw ) ) < 0 )
517 msg_Err( p_aout, "unable to retrieve initial hardware parameters (%s)",
518 snd_strerror( i_snd_rc ) );
523 if ( ( i_snd_rc = snd_pcm_hw_params_set_format( p_sys->p_snd_pcm, p_hw,
524 i_snd_pcm_format ) ) < 0 )
526 if( i_snd_pcm_format != SND_PCM_FORMAT_S16 )
528 i_snd_pcm_format = SND_PCM_FORMAT_S16;
529 i_snd_rc = snd_pcm_hw_params_set_format( p_sys->p_snd_pcm,
530 p_hw, i_snd_pcm_format );
534 msg_Err( p_aout, "unable to set stream sample size and "
535 "word order (%s)", snd_strerror( i_snd_rc ) );
539 if( i_vlc_pcm_format != VLC_FOURCC('s','p','d','i') )
540 switch( i_snd_pcm_format )
542 case SND_PCM_FORMAT_FLOAT:
543 i_vlc_pcm_format = VLC_FOURCC('f','l','3','2');
545 case SND_PCM_FORMAT_S16:
546 i_vlc_pcm_format = AOUT_FMT_S16_NE;
549 p_aout->output.output.i_format = i_vlc_pcm_format;
551 if ( ( i_snd_rc = snd_pcm_hw_params_set_access( p_sys->p_snd_pcm, p_hw,
552 SND_PCM_ACCESS_RW_INTERLEAVED ) ) < 0 )
554 msg_Err( p_aout, "unable to set interleaved stream format (%s)",
555 snd_strerror( i_snd_rc ) );
560 if ( ( i_snd_rc = snd_pcm_hw_params_set_channels( p_sys->p_snd_pcm, p_hw,
563 msg_Err( p_aout, "unable to set number of output channels (%s)",
564 snd_strerror( i_snd_rc ) );
569 i_old_rate = p_aout->output.output.i_rate;
570 #ifdef HAVE_ALSA_NEW_API
571 i_snd_rc = snd_pcm_hw_params_set_rate_near( p_sys->p_snd_pcm, p_hw,
572 &p_aout->output.output.i_rate,
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 if( i_snd_rc < 0 || p_aout->output.output.i_rate != i_old_rate )
581 msg_Warn( p_aout, "The rate %d Hz is not supported by your " \
582 "hardware. Using %d Hz instead.\n", i_old_rate, \
583 p_aout->output.output.i_rate );
586 /* Set buffer size. */
587 #ifdef HAVE_ALSA_NEW_API
588 if ( ( i_snd_rc = snd_pcm_hw_params_set_buffer_size_near( p_sys->p_snd_pcm,
589 p_hw, &i_buffer_size ) ) < 0 )
591 if ( ( i_snd_rc = snd_pcm_hw_params_set_buffer_size_near( p_sys->p_snd_pcm,
592 p_hw, i_buffer_size ) ) < 0 )
595 msg_Err( p_aout, "unable to set buffer size (%s)",
596 snd_strerror( i_snd_rc ) );
600 /* Set period size. */
601 #ifdef HAVE_ALSA_NEW_API
602 if ( ( i_snd_rc = snd_pcm_hw_params_set_period_size_near( p_sys->p_snd_pcm,
603 p_hw, &i_period_size, NULL ) ) < 0 )
605 if ( ( i_snd_rc = snd_pcm_hw_params_set_period_size_near( p_sys->p_snd_pcm,
606 p_hw, i_period_size, NULL ) ) < 0 )
609 msg_Err( p_aout, "unable to set period size (%s)",
610 snd_strerror( i_snd_rc ) );
613 p_aout->output.i_nb_samples = i_period_size;
615 /* Commit hardware parameters. */
616 if ( ( i_snd_rc = snd_pcm_hw_params( p_sys->p_snd_pcm, p_hw ) ) < 0 )
618 if ( b_retry == VLC_FALSE &&
619 i_snd_pcm_format == SND_PCM_FORMAT_FLOAT)
622 i_snd_pcm_format = SND_PCM_FORMAT_S16;
623 p_aout->output.output.i_format = AOUT_FMT_S16_NE;
624 msg_Warn( p_aout, "unable to commit hardware configuration "
625 "with fl32 samples. Retrying with s16l (%s)", snd_strerror( i_snd_rc ) );
629 msg_Err( p_aout, "unable to commit hardware configuration (%s)",
630 snd_strerror( i_snd_rc ) );
636 #ifdef HAVE_ALSA_NEW_API
637 if( ( i_snd_rc = snd_pcm_hw_params_get_period_time( p_hw,
638 &p_sys->i_period_time, NULL ) ) < 0 )
640 if( ( p_sys->i_period_time =
641 (int)snd_pcm_hw_params_get_period_time( p_hw, NULL ) ) < 0 )
644 msg_Err( p_aout, "unable to get period time (%s)",
645 snd_strerror( i_snd_rc ) );
649 /* Get Initial software parameters */
650 snd_pcm_sw_params_current( p_sys->p_snd_pcm, p_sw );
652 i_snd_rc = snd_pcm_sw_params_set_sleep_min( p_sys->p_snd_pcm, p_sw, 0 );
654 i_snd_rc = snd_pcm_sw_params_set_avail_min( p_sys->p_snd_pcm, p_sw,
655 p_aout->output.i_nb_samples );
656 /* start playing when one period has been written */
657 i_snd_rc = snd_pcm_sw_params_set_start_threshold( p_sys->p_snd_pcm, p_sw,
658 ALSA_DEFAULT_PERIOD_SIZE);
661 msg_Err( p_aout, "unable to set start threshold (%s)",
662 snd_strerror( i_snd_rc ) );
666 /* Commit software parameters. */
667 if ( snd_pcm_sw_params( p_sys->p_snd_pcm, p_sw ) < 0 )
669 msg_Err( p_aout, "unable to set software configuration" );
674 snd_output_printf( p_sys->p_snd_stderr, "\nALSA hardware setup:\n\n" );
675 snd_pcm_dump_hw_setup( p_sys->p_snd_pcm, p_sys->p_snd_stderr );
676 snd_output_printf( p_sys->p_snd_stderr, "\nALSA software setup:\n\n" );
677 snd_pcm_dump_sw_setup( p_sys->p_snd_pcm, p_sys->p_snd_stderr );
678 snd_output_printf( p_sys->p_snd_stderr, "\n" );
681 /* Create ALSA thread and wait for its readiness. */
682 if( vlc_thread_create( p_aout, "aout", ALSAThread,
683 VLC_THREAD_PRIORITY_OUTPUT, VLC_FALSE ) )
685 msg_Err( p_aout, "cannot create ALSA thread (%s)", strerror(errno) );
692 snd_pcm_close( p_sys->p_snd_pcm );
694 snd_output_close( p_sys->p_snd_stderr );
700 /*****************************************************************************
701 * Play: nothing to do
702 *****************************************************************************/
703 static void Play( aout_instance_t *p_aout )
705 if( !p_aout->output.p_sys->b_playing )
707 p_aout->output.p_sys->b_playing = 1;
709 /* get the playing date of the first aout buffer */
710 p_aout->output.p_sys->start_date =
711 aout_FifoFirstDate( p_aout, &p_aout->output.fifo );
713 /* wake up the audio output thread */
714 vlc_mutex_lock( &p_aout->output.p_sys->lock );
715 vlc_cond_signal( &p_aout->output.p_sys->wait );
716 vlc_mutex_unlock( &p_aout->output.p_sys->lock );
720 /*****************************************************************************
721 * Close: close the ALSA device
722 *****************************************************************************/
723 static void Close( vlc_object_t *p_this )
725 aout_instance_t *p_aout = (aout_instance_t *)p_this;
726 struct aout_sys_t * p_sys = p_aout->output.p_sys;
729 /* make sure the audio output thread is waken up */
730 vlc_mutex_lock( &p_aout->output.p_sys->lock );
731 vlc_cond_signal( &p_aout->output.p_sys->wait );
732 vlc_mutex_unlock( &p_aout->output.p_sys->lock );
734 vlc_object_kill( p_aout );
735 vlc_thread_join( p_aout );
736 p_aout->b_die = VLC_FALSE;
738 i_snd_rc = snd_pcm_close( p_sys->p_snd_pcm );
742 msg_Err( p_aout, "failed closing ALSA device (%s)",
743 snd_strerror( i_snd_rc ) );
747 snd_output_close( p_sys->p_snd_stderr );
753 /*****************************************************************************
754 * ALSAThread: asynchronous thread used to DMA the data to the device
755 *****************************************************************************/
756 static int ALSAThread( aout_instance_t * p_aout )
758 p_aout->output.p_sys->p_status =
759 (snd_pcm_status_t *)malloc(snd_pcm_status_sizeof());
761 /* Wait for the exact time to start playing (avoids resampling) */
762 vlc_mutex_lock( &p_aout->output.p_sys->lock );
763 if( !p_aout->output.p_sys->start_date )
764 vlc_cond_wait( &p_aout->output.p_sys->wait,
765 &p_aout->output.p_sys->lock );
766 vlc_mutex_unlock( &p_aout->output.p_sys->lock );
768 mwait( p_aout->output.p_sys->start_date - AOUT_PTS_TOLERANCE / 4 );
770 while ( !p_aout->b_die )
775 free( p_aout->output.p_sys->p_status );
779 /*****************************************************************************
780 * ALSAFill: function used to fill the ALSA buffer as much as possible
781 *****************************************************************************/
782 static void ALSAFill( aout_instance_t * p_aout )
784 struct aout_sys_t * p_sys = p_aout->output.p_sys;
785 aout_buffer_t * p_buffer;
786 snd_pcm_status_t * p_status = p_sys->p_status;
790 /* Fill in the buffer until space or audio output buffer shortage */
793 i_snd_rc = snd_pcm_status( p_sys->p_snd_pcm, p_status );
796 msg_Err( p_aout, "unable to get the device's status (%s)",
797 snd_strerror( i_snd_rc ) );
799 msleep( p_sys->i_period_time >> 1 );
803 /* Handle buffer underruns and reget the status */
804 if( snd_pcm_status_get_state( p_status ) == SND_PCM_STATE_XRUN )
806 /* Prepare the device */
807 i_snd_rc = snd_pcm_prepare( p_sys->p_snd_pcm );
811 msg_Dbg( p_aout, "recovered from buffer underrun" );
813 /* Reget the status */
814 i_snd_rc = snd_pcm_status( p_sys->p_snd_pcm, p_status );
817 msg_Err( p_aout, "unable to get the device's status after "
818 "recovery (%s)", snd_strerror( i_snd_rc ) );
820 msleep( p_sys->i_period_time >> 1 );
826 msg_Err( p_aout, "unable to recover from buffer underrun" );
828 msleep( p_sys->i_period_time >> 1 );
832 /* Underrun, try to recover as quickly as possible */
837 /* Here the device should be either in the RUNNING state.
838 * p_status is valid. */
841 /* This apparently does not work correctly in Alsa 1.0.11 */
842 snd_pcm_status_get_tstamp( p_status, &ts_next );
843 next_date = (mtime_t)ts_next.tv_sec * 1000000 + ts_next.tv_usec;
846 next_date += (mtime_t)snd_pcm_status_get_delay(p_status)
847 * 1000000 / p_aout->output.output.i_rate;
852 /* With screwed ALSA drivers the timestamp is always zero;
853 * use another method then */
854 snd_pcm_sframes_t delay = 0;
856 snd_pcm_delay( p_sys->p_snd_pcm, &delay );
857 next_date = mdate() + (mtime_t)(delay) * 1000000 /
858 p_aout->output.output.i_rate
859 * p_aout->output.output.i_frame_length;
863 p_buffer = aout_OutputNextBuffer( p_aout, next_date,
864 (p_aout->output.output.i_format ==
865 VLC_FOURCC('s','p','d','i')) );
867 /* Audio output buffer shortage -> stop the fill process and wait */
868 if( p_buffer == NULL )
870 msleep( p_sys->i_period_time >> 1 );
874 i_snd_rc = snd_pcm_writei( p_sys->p_snd_pcm, p_buffer->p_buffer,
875 p_buffer->i_nb_samples );
879 msg_Err( p_aout, "write failed (%s)",
880 snd_strerror( i_snd_rc ) );
883 aout_BufferFree( p_buffer );
887 static void GetDevicesForCard(module_config_t *p_item, int i_card);
888 static void GetDevices( module_config_t *p_item );
890 /*****************************************************************************
891 * config variable callback
892 *****************************************************************************/
893 static int FindDevicesCallback( vlc_object_t *p_this, char const *psz_name,
894 vlc_value_t newval, vlc_value_t oldval, void *p_unused )
896 module_config_t *p_item;
899 p_item = config_FindConfig( p_this, psz_name );
900 if( !p_item ) return VLC_SUCCESS;
902 /* Clear-up the current list */
905 /* Keep the first entrie */
906 for( i = 1; i < p_item->i_list; i++ )
908 free( (char *)p_item->ppsz_list[i] );
909 free( (char *)p_item->ppsz_list_text[i] );
911 /* TODO: Remove when no more needed */
912 p_item->ppsz_list[i] = NULL;
913 p_item->ppsz_list_text[i] = NULL;
917 GetDevices( p_item );
919 /* Signal change to the interface */
920 p_item->b_dirty = VLC_TRUE;
927 static void GetDevicesForCard(module_config_t *p_item, int i_card)
929 int i_pcm_device = -1;
931 snd_pcm_info_t *p_pcm_info;
936 sprintf(psz_dev, "hw:%i", i_card);
938 if (( i_err = snd_ctl_open(&p_ctl, psz_dev, 0)) < 0 )
943 if ((i_err = snd_card_get_name(i_card, &psz_card_name)) != 0)
945 psz_card_name = _("Unknown soundcard");
948 snd_pcm_info_alloca(&p_pcm_info);
952 char *psz_device, *psz_descr;
953 if ((i_err = snd_ctl_pcm_next_device(p_ctl, &i_pcm_device)) < 0)
957 if ( i_pcm_device < 0 )
960 snd_pcm_info_set_device(p_pcm_info, i_pcm_device);
961 snd_pcm_info_set_subdevice(p_pcm_info, 0);
962 snd_pcm_info_set_stream(p_pcm_info, SND_PCM_STREAM_PLAYBACK);
964 if ((i_err = snd_ctl_pcm_info(p_ctl, p_pcm_info)) < 0)
966 if (i_err != -ENOENT)
968 /* printf("get_devices_for_card(): "
969 "snd_ctl_pcm_info() "
970 "failed (%d:%d): %s.\n", i_card,
971 i_pcm_device, snd_strerror(-i_err));*/
976 asprintf( &psz_device, "hw:%d,%d", i_card, i_pcm_device );
977 asprintf( &psz_descr, "%s: %s (%s)", psz_card_name,
978 snd_pcm_info_get_name(p_pcm_info), psz_device );
981 (const char **)realloc( p_item->ppsz_list,
982 (p_item->i_list + 2) * sizeof(char *) );
983 p_item->ppsz_list_text =
984 (const char **)realloc( p_item->ppsz_list_text,
985 (p_item->i_list + 2) * sizeof(char *) );
986 p_item->ppsz_list[ p_item->i_list ] = psz_device;
987 p_item->ppsz_list_text[ p_item->i_list ] = psz_descr;
989 p_item->ppsz_list[ p_item->i_list ] = NULL;
990 p_item->ppsz_list_text[ p_item->i_list ] = NULL;
993 snd_ctl_close( p_ctl );
998 static void GetDevices( module_config_t *p_item )
1003 if ((i_err = snd_card_next(&i_card)) != 0)
1005 // g_warning("snd_next_card() failed: %s", snd_strerror(-err));
1011 GetDevicesForCard(p_item, i_card);
1012 if ((i_err = snd_card_next(&i_card)) != 0)
1014 // g_warning("snd_next_card() failed: %s",
1015 // snd_strerror(-err));