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., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
25 *****************************************************************************/
27 /*****************************************************************************
29 *****************************************************************************/
30 #include <errno.h> /* ENOMEM */
31 #include <string.h> /* strerror() */
32 #include <stdlib.h> /* calloc(), malloc(), free() */
38 #include "aout_internal.h"
41 Note: we use the new API which is available since 0.9.0beta10a. */
42 #define ALSA_PCM_NEW_HW_PARAMS_API
43 #define ALSA_PCM_NEW_SW_PARAMS_API
44 #include <alsa/asoundlib.h>
46 /*****************************************************************************
47 * aout_sys_t: ALSA audio output method descriptor
48 *****************************************************************************
49 * This structure is part of the audio output thread descriptor.
50 * It describes the ALSA specific properties of an audio device.
51 *****************************************************************************/
54 snd_pcm_t * p_snd_pcm;
55 unsigned int i_period_time;
58 snd_output_t * p_snd_stderr;
61 int b_playing; /* playing status */
67 snd_pcm_status_t *p_status;
70 #define A52_FRAME_NB 1536
72 /* These values are in frames.
73 To convert them to a number of bytes you have to multiply them by the
74 number of channel(s) (eg. 2 for stereo) and the size of a sample (eg.
76 #define ALSA_DEFAULT_PERIOD_SIZE 1024
77 #define ALSA_DEFAULT_BUFFER_SIZE ( ALSA_DEFAULT_PERIOD_SIZE << 8 )
78 #define ALSA_SPDIF_PERIOD_SIZE A52_FRAME_NB
79 #define ALSA_SPDIF_BUFFER_SIZE ( ALSA_SPDIF_PERIOD_SIZE << 4 )
80 /* Why << 4 ? --Meuuh */
81 /* Why not ? --Bozo */
84 #define DEFAULT_ALSA_DEVICE N_("default")
86 /*****************************************************************************
88 *****************************************************************************/
89 static int Open ( vlc_object_t * );
90 static void Close ( vlc_object_t * );
91 static void Play ( aout_instance_t * );
92 static int ALSAThread ( aout_instance_t * );
93 static void ALSAFill ( aout_instance_t * );
94 static int FindDevicesCallback( vlc_object_t *p_this, char const *psz_name,
95 vlc_value_t newval, vlc_value_t oldval, void *p_unused );
97 /*****************************************************************************
99 *****************************************************************************/
100 static char *ppsz_devices[] = { "default" };
101 static char *ppsz_devices_text[] = { N_("Default") };
103 set_shortname( "ALSA" );
104 set_description( _("ALSA audio output") );
105 set_category( CAT_AUDIO );
106 set_subcategory( SUBCAT_AUDIO_AOUT );
107 add_string( "alsadev", DEFAULT_ALSA_DEVICE, aout_FindAndRestart,
108 N_("ALSA Device Name"), NULL, VLC_FALSE );
109 change_string_list( ppsz_devices, ppsz_devices_text, FindDevicesCallback );
110 change_action_add( FindDevicesCallback, N_("Refresh list") );
112 set_capability( "audio output", 150 );
113 set_callbacks( Open, Close );
116 /*****************************************************************************
117 * Probe: probe the audio device for available formats and channels
118 *****************************************************************************/
119 static void Probe( aout_instance_t * p_aout,
120 const char * psz_device, const char * psz_iec_device,
121 int *pi_snd_pcm_format )
123 struct aout_sys_t * p_sys = p_aout->output.p_sys;
124 vlc_value_t val, text;
127 var_Create ( p_aout, "audio-device", VLC_VAR_INTEGER | VLC_VAR_HASCHOICE );
128 text.psz_string = _("Audio Device");
129 var_Change( p_aout, "audio-device", VLC_VAR_SETTEXT, &text, NULL );
131 /* We'll open the audio device in non blocking mode so we can just exit
132 * when it is already in use, but for the real stuff we'll still use
133 * the blocking mode */
135 /* Now test linear PCM capabilities */
136 if ( !(i_ret = snd_pcm_open( &p_sys->p_snd_pcm, psz_device,
137 SND_PCM_STREAM_PLAYBACK,
138 SND_PCM_NONBLOCK ) ) )
141 snd_pcm_hw_params_t * p_hw;
142 snd_pcm_hw_params_alloca (&p_hw);
144 if ( snd_pcm_hw_params_any( p_sys->p_snd_pcm, p_hw ) < 0 )
146 msg_Warn( p_aout, "unable to retrieve initial hardware parameters"
147 ", disabling linear PCM audio" );
148 snd_pcm_close( p_sys->p_snd_pcm );
149 var_Destroy( p_aout, "audio-device" );
153 if ( snd_pcm_hw_params_set_format( p_sys->p_snd_pcm, p_hw,
154 *pi_snd_pcm_format ) < 0 )
158 if( *pi_snd_pcm_format != SND_PCM_FORMAT_S16 )
160 *pi_snd_pcm_format = SND_PCM_FORMAT_S16;
161 i_snd_rc = snd_pcm_hw_params_set_format( p_sys->p_snd_pcm,
162 p_hw, *pi_snd_pcm_format );
166 msg_Warn( p_aout, "unable to set stream sample size and "
167 "word order, disabling linear PCM audio" );
168 snd_pcm_close( p_sys->p_snd_pcm );
169 var_Destroy( p_aout, "audio-device" );
174 i_channels = aout_FormatNbChannels( &p_aout->output.output );
176 while ( i_channels > 0 )
178 if ( !snd_pcm_hw_params_test_channels( p_sys->p_snd_pcm, p_hw,
181 switch ( i_channels )
184 val.i_int = AOUT_VAR_MONO;
185 text.psz_string = N_("Mono");
186 var_Change( p_aout, "audio-device",
187 VLC_VAR_ADDCHOICE, &val, &text );
190 val.i_int = AOUT_VAR_STEREO;
191 text.psz_string = N_("Stereo");
192 var_Change( p_aout, "audio-device",
193 VLC_VAR_ADDCHOICE, &val, &text );
194 var_Set( p_aout, "audio-device", val );
197 val.i_int = AOUT_VAR_2F2R;
198 text.psz_string = N_("2 Front 2 Rear");
199 var_Change( p_aout, "audio-device",
200 VLC_VAR_ADDCHOICE, &val, &text );
203 val.i_int = AOUT_VAR_5_1;
204 text.psz_string = N_("5.1");
205 var_Change( p_aout, "audio-device",
206 VLC_VAR_ADDCHOICE, &val, &text );
214 /* Special case for mono on stereo only boards */
215 i_channels = aout_FormatNbChannels( &p_aout->output.output );
216 var_Change( p_aout, "audio-device", VLC_VAR_CHOICESCOUNT, &val, NULL );
217 if( val.i_int <= 0 && i_channels == 1 )
219 if ( !snd_pcm_hw_params_test_channels( p_sys->p_snd_pcm, p_hw, 2 ))
221 val.i_int = AOUT_VAR_STEREO;
222 text.psz_string = N_("Stereo");
223 var_Change( p_aout, "audio-device",
224 VLC_VAR_ADDCHOICE, &val, &text );
225 var_Set( p_aout, "audio-device", val );
229 /* Close the previously opened device */
230 snd_pcm_close( p_sys->p_snd_pcm );
232 else if ( i_ret == -EBUSY )
234 msg_Warn( p_aout, "audio device: %s is already in use", psz_device );
237 /* Test for S/PDIF device if needed */
238 if ( psz_iec_device )
240 /* Opening the device should be enough */
241 if ( !(i_ret = snd_pcm_open( &p_sys->p_snd_pcm, psz_iec_device,
242 SND_PCM_STREAM_PLAYBACK,
243 SND_PCM_NONBLOCK ) ) )
245 val.i_int = AOUT_VAR_SPDIF;
246 text.psz_string = N_("A/52 over S/PDIF");
247 var_Change( p_aout, "audio-device",
248 VLC_VAR_ADDCHOICE, &val, &text );
249 if( config_GetInt( p_aout, "spdif" ) )
250 var_Set( p_aout, "audio-device", val );
252 snd_pcm_close( p_sys->p_snd_pcm );
254 else if ( i_ret == -EBUSY )
256 msg_Warn( p_aout, "audio device: %s is already in use",
261 var_Change( p_aout, "audio-device", VLC_VAR_CHOICESCOUNT, &val, NULL );
264 /* Probe() has failed. */
265 msg_Dbg( p_aout, "failed to find a useable alsa configuration" );
266 var_Destroy( p_aout, "audio-device" );
270 /* Add final settings to the variable */
271 var_AddCallback( p_aout, "audio-device", aout_ChannelsRestart, NULL );
272 val.b_bool = VLC_TRUE;
273 var_Set( p_aout, "intf-change", val );
276 /*****************************************************************************
277 * Open: create a handle and open an alsa device
278 *****************************************************************************
279 * This function opens an alsa device, through the alsa API.
281 * Note: the only heap-allocated string is psz_device. All the other pointers
282 * are references to psz_device or to stack-allocated data.
283 *****************************************************************************/
284 static int Open( vlc_object_t *p_this )
286 aout_instance_t * p_aout = (aout_instance_t *)p_this;
287 struct aout_sys_t * p_sys;
290 char psz_default_iec_device[128]; /* Buffer used to store the default
292 char * psz_device, * psz_iec_device; /* device names for PCM and S/PDIF
295 int i_vlc_pcm_format; /* Audio format for VLC's data */
296 int i_snd_pcm_format; /* Audio format for ALSA's data */
298 snd_pcm_uframes_t i_buffer_size = 0;
299 snd_pcm_uframes_t i_period_size = 0;
302 snd_pcm_hw_params_t *p_hw;
303 snd_pcm_sw_params_t *p_sw;
306 unsigned int i_old_rate;
307 vlc_bool_t b_retry = VLC_TRUE;
309 /* Allocate structures */
310 p_aout->output.p_sys = p_sys = malloc( sizeof( aout_sys_t ) );
313 msg_Err( p_aout, "out of memory" );
316 p_sys->b_playing = VLC_FALSE;
317 p_sys->start_date = 0;
318 vlc_cond_init( p_aout, &p_sys->wait );
319 vlc_mutex_init( p_aout, &p_sys->lock );
321 /* Get device name */
322 if( (psz_device = config_GetPsz( p_aout, "alsadev" )) == NULL )
324 msg_Err( p_aout, "no audio device given (maybe \"default\" ?)" );
329 p_sys->p_status = (snd_pcm_status_t *)malloc(snd_pcm_status_sizeof());
331 /* Choose the IEC device for S/PDIF output:
332 if the device is overriden by the user then it will be the one
333 otherwise we compute the default device based on the output format. */
334 if( AOUT_FMT_NON_LINEAR( &p_aout->output.output )
335 && !strcmp( psz_device, DEFAULT_ALSA_DEVICE ) )
337 snprintf( psz_default_iec_device, sizeof(psz_default_iec_device),
338 "iec958:AES0=0x%x,AES1=0x%x,AES2=0x%x,AES3=0x%x",
339 IEC958_AES0_CON_EMPHASIS_NONE | IEC958_AES0_NONAUDIO,
340 IEC958_AES1_CON_ORIGINAL | IEC958_AES1_CON_PCM_CODER,
342 ( p_aout->output.output.i_rate == 48000 ?
343 IEC958_AES3_CON_FS_48000 :
344 ( p_aout->output.output.i_rate == 44100 ?
345 IEC958_AES3_CON_FS_44100 : IEC958_AES3_CON_FS_32000 ) ) );
346 psz_iec_device = psz_default_iec_device;
348 else if( AOUT_FMT_NON_LINEAR( &p_aout->output.output ) )
350 psz_iec_device = psz_device;
354 psz_iec_device = NULL;
357 /* Choose the linear PCM format (read the comment above about FPU
359 if( p_aout->p_libvlc->i_cpu & CPU_CAPABILITY_FPU )
361 i_vlc_pcm_format = VLC_FOURCC('f','l','3','2');
362 i_snd_pcm_format = SND_PCM_FORMAT_FLOAT;
366 i_vlc_pcm_format = AOUT_FMT_S16_NE;
367 i_snd_pcm_format = SND_PCM_FORMAT_S16;
370 /* If the variable doesn't exist then it's the first time we're called
371 and we have to probe the available audio formats and channels */
372 if ( var_Type( p_aout, "audio-device" ) == 0 )
374 Probe( p_aout, psz_device, psz_iec_device, &i_snd_pcm_format );
377 if ( var_Get( p_aout, "audio-device", &val ) < 0 )
379 free( p_sys->p_status );
385 p_aout->output.output.i_format = i_vlc_pcm_format;
386 if ( val.i_int == AOUT_VAR_5_1 )
388 p_aout->output.output.i_physical_channels
389 = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER
390 | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT
393 psz_device = strdup( "surround51" );
395 else if ( val.i_int == AOUT_VAR_2F2R )
397 p_aout->output.output.i_physical_channels
398 = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT
399 | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT;
401 psz_device = strdup( "surround40" );
403 else if ( val.i_int == AOUT_VAR_STEREO )
405 p_aout->output.output.i_physical_channels
406 = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT;
408 else if ( val.i_int == AOUT_VAR_MONO )
410 p_aout->output.output.i_physical_channels = AOUT_CHAN_CENTER;
412 else if( val.i_int != AOUT_VAR_SPDIF )
414 /* This should not happen ! */
415 msg_Err( p_aout, "internal: can't find audio-device (%i)", val.i_int );
416 free( p_sys->p_status );
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 free( p_sys->p_status );
439 i_buffer_size = ALSA_SPDIF_BUFFER_SIZE;
440 i_snd_pcm_format = SND_PCM_FORMAT_S16;
443 i_vlc_pcm_format = VLC_FOURCC('s','p','d','i');
444 p_aout->output.i_nb_samples = i_period_size = ALSA_SPDIF_PERIOD_SIZE;
445 p_aout->output.output.i_bytes_per_frame = AOUT_SPDIF_SIZE;
446 p_aout->output.output.i_frame_length = A52_FRAME_NB;
448 aout_VolumeNoneInit( p_aout );
454 msg_Dbg( p_aout, "opening ALSA device `%s'", psz_device );
456 /* Since it seems snd_pcm_close hasen't really released the device at
457 the time it returns, probe if the device is available in loop for 1s.
458 We cannot use blocking mode since the we would wait indefinitely when
459 switching from a dmx device to surround51. */
461 for( i = 10; i >= 0; i-- )
463 if ( ( i_snd_rc = snd_pcm_open( &p_sys->p_snd_pcm, psz_device,
464 SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK ) ) == -EBUSY )
466 if( i ) msleep( 100000 /* 100ms */ );
467 else msg_Err( p_aout, "audio device: %s is already in use",
475 msg_Err( p_aout, "cannot open ALSA device `%s' (%s)",
476 psz_device, snd_strerror( i_snd_rc ) );
477 free( p_sys->p_status );
483 /* We want blocking mode */
484 snd_pcm_nonblock( p_sys->p_snd_pcm, 0 );
486 i_buffer_size = ALSA_DEFAULT_BUFFER_SIZE;
487 i_channels = aout_FormatNbChannels( &p_aout->output.output );
489 p_aout->output.i_nb_samples = i_period_size = ALSA_DEFAULT_PERIOD_SIZE;
491 aout_VolumeSoftInit( p_aout );
494 /* Free psz_device so that all the remaining data is stack-allocated */
497 p_aout->output.pf_play = Play;
499 snd_pcm_hw_params_alloca(&p_hw);
500 snd_pcm_sw_params_alloca(&p_sw);
502 /* Due to some bugs in alsa with some drivers, we need to retry in s16l
503 if snd_pcm_hw_params fails in fl32 */
508 /* Get Initial hardware parameters */
509 if ( ( i_snd_rc = snd_pcm_hw_params_any( p_sys->p_snd_pcm, p_hw ) ) < 0 )
511 msg_Err( p_aout, "unable to retrieve initial hardware parameters (%s)",
512 snd_strerror( i_snd_rc ) );
517 if ( ( i_snd_rc = snd_pcm_hw_params_set_format( p_sys->p_snd_pcm, p_hw,
518 i_snd_pcm_format ) ) < 0 )
520 if( i_snd_pcm_format != SND_PCM_FORMAT_S16 )
522 i_snd_pcm_format = SND_PCM_FORMAT_S16;
523 i_snd_rc = snd_pcm_hw_params_set_format( p_sys->p_snd_pcm,
524 p_hw, i_snd_pcm_format );
528 msg_Err( p_aout, "unable to set stream sample size and "
529 "word order (%s)", snd_strerror( i_snd_rc ) );
533 if( i_vlc_pcm_format != VLC_FOURCC('s','p','d','i') )
534 switch( i_snd_pcm_format )
536 case SND_PCM_FORMAT_FLOAT:
537 i_vlc_pcm_format = VLC_FOURCC('f','l','3','2');
539 case SND_PCM_FORMAT_S16:
540 i_vlc_pcm_format = AOUT_FMT_S16_NE;
543 p_aout->output.output.i_format = i_vlc_pcm_format;
545 if ( ( i_snd_rc = snd_pcm_hw_params_set_access( p_sys->p_snd_pcm, p_hw,
546 SND_PCM_ACCESS_RW_INTERLEAVED ) ) < 0 )
548 msg_Err( p_aout, "unable to set interleaved stream format (%s)",
549 snd_strerror( i_snd_rc ) );
554 if ( ( i_snd_rc = snd_pcm_hw_params_set_channels( p_sys->p_snd_pcm, p_hw,
557 msg_Err( p_aout, "unable to set number of output channels (%s)",
558 snd_strerror( i_snd_rc ) );
563 i_old_rate = p_aout->output.output.i_rate;
564 #ifdef HAVE_ALSA_NEW_API
565 i_snd_rc = snd_pcm_hw_params_set_rate_near( p_sys->p_snd_pcm, p_hw,
566 &p_aout->output.output.i_rate,
569 i_snd_rc = snd_pcm_hw_params_set_rate_near( p_sys->p_snd_pcm, p_hw,
570 p_aout->output.output.i_rate,
573 if( i_snd_rc < 0 || p_aout->output.output.i_rate != i_old_rate )
575 msg_Warn( p_aout, "The rate %d Hz is not supported by your hardware. "
576 "Using %d Hz instead.\n", i_old_rate,
577 p_aout->output.output.i_rate );
580 /* Set buffer size. */
581 #ifdef HAVE_ALSA_NEW_API
582 if ( ( i_snd_rc = snd_pcm_hw_params_set_buffer_size_near( p_sys->p_snd_pcm,
583 p_hw, &i_buffer_size ) ) < 0 )
585 if ( ( i_snd_rc = snd_pcm_hw_params_set_buffer_size_near( p_sys->p_snd_pcm,
586 p_hw, i_buffer_size ) ) < 0 )
589 msg_Err( p_aout, "unable to set buffer size (%s)",
590 snd_strerror( i_snd_rc ) );
594 /* Set period size. */
595 #ifdef HAVE_ALSA_NEW_API
596 if ( ( i_snd_rc = snd_pcm_hw_params_set_period_size_near( p_sys->p_snd_pcm,
597 p_hw, &i_period_size, NULL ) ) < 0 )
599 if ( ( i_snd_rc = snd_pcm_hw_params_set_period_size_near( p_sys->p_snd_pcm,
600 p_hw, i_period_size, NULL ) ) < 0 )
603 msg_Err( p_aout, "unable to set period size (%s)",
604 snd_strerror( i_snd_rc ) );
607 p_aout->output.i_nb_samples = i_period_size;
609 /* Commit hardware parameters. */
610 if ( ( i_snd_rc = snd_pcm_hw_params( p_sys->p_snd_pcm, p_hw ) ) < 0 )
612 if ( b_retry == VLC_FALSE &&
613 i_snd_pcm_format == SND_PCM_FORMAT_FLOAT)
616 i_snd_pcm_format = SND_PCM_FORMAT_S16;
617 p_aout->output.output.i_format = AOUT_FMT_S16_NE;
618 msg_Warn( p_aout, "unable to commit hardware configuration "
619 "with fl32 samples. Retrying with s16l (%s)", snd_strerror( i_snd_rc ) );
623 msg_Err( p_aout, "unable to commit hardware configuration (%s)",
624 snd_strerror( i_snd_rc ) );
630 #ifdef HAVE_ALSA_NEW_API
631 if( ( i_snd_rc = snd_pcm_hw_params_get_period_time( p_hw,
632 &p_sys->i_period_time, NULL ) ) < 0 )
634 if( ( p_sys->i_period_time =
635 (int)snd_pcm_hw_params_get_period_time( p_hw, NULL ) ) < 0 )
638 msg_Err( p_aout, "unable to get period time (%s)",
639 snd_strerror( i_snd_rc ) );
643 /* Get Initial software parameters */
644 snd_pcm_sw_params_current( p_sys->p_snd_pcm, p_sw );
646 i_snd_rc = snd_pcm_sw_params_set_sleep_min( p_sys->p_snd_pcm, p_sw, 0 );
648 i_snd_rc = snd_pcm_sw_params_set_avail_min( p_sys->p_snd_pcm, p_sw,
649 p_aout->output.i_nb_samples );
651 /* Commit software parameters. */
652 if ( snd_pcm_sw_params( p_sys->p_snd_pcm, p_sw ) < 0 )
654 msg_Err( p_aout, "unable to set software configuration" );
659 snd_output_printf( p_sys->p_snd_stderr, "\nALSA hardware setup:\n\n" );
660 snd_pcm_dump_hw_setup( p_sys->p_snd_pcm, p_sys->p_snd_stderr );
661 snd_output_printf( p_sys->p_snd_stderr, "\nALSA software setup:\n\n" );
662 snd_pcm_dump_sw_setup( p_sys->p_snd_pcm, p_sys->p_snd_stderr );
663 snd_output_printf( p_sys->p_snd_stderr, "\n" );
666 /* Create ALSA thread and wait for its readiness. */
667 if( vlc_thread_create( p_aout, "aout", ALSAThread,
668 VLC_THREAD_PRIORITY_OUTPUT, VLC_FALSE ) )
670 msg_Err( p_aout, "cannot create ALSA thread (%s)", strerror(errno) );
677 snd_pcm_close( p_sys->p_snd_pcm );
679 snd_output_close( p_sys->p_snd_stderr );
681 free( p_sys->p_status );
686 /*****************************************************************************
687 * Play: nothing to do
688 *****************************************************************************/
689 static void Play( aout_instance_t *p_aout )
691 if( !p_aout->output.p_sys->b_playing )
693 p_aout->output.p_sys->b_playing = 1;
695 /* get the playing date of the first aout buffer */
696 p_aout->output.p_sys->start_date =
697 aout_FifoFirstDate( p_aout, &p_aout->output.fifo );
699 /* wake up the audio output thread */
700 vlc_mutex_lock( &p_aout->output.p_sys->lock );
701 vlc_cond_signal( &p_aout->output.p_sys->wait );
702 vlc_mutex_unlock( &p_aout->output.p_sys->lock );
706 /*****************************************************************************
707 * Close: close the ALSA device
708 *****************************************************************************/
709 static void Close( vlc_object_t *p_this )
711 aout_instance_t *p_aout = (aout_instance_t *)p_this;
712 struct aout_sys_t * p_sys = p_aout->output.p_sys;
715 /* make sure the audio output thread is waken up */
716 vlc_mutex_lock( &p_aout->output.p_sys->lock );
717 vlc_cond_signal( &p_aout->output.p_sys->wait );
718 vlc_mutex_unlock( &p_aout->output.p_sys->lock );
720 p_aout->b_die = VLC_TRUE;
721 vlc_thread_join( p_aout );
722 p_aout->b_die = VLC_FALSE;
724 i_snd_rc = snd_pcm_close( p_sys->p_snd_pcm );
728 msg_Err( p_aout, "failed closing ALSA device (%s)",
729 snd_strerror( i_snd_rc ) );
733 snd_output_close( p_sys->p_snd_stderr );
736 free( p_sys->p_status );
740 /*****************************************************************************
741 * ALSAThread: asynchronous thread used to DMA the data to the device
742 *****************************************************************************/
743 static int ALSAThread( aout_instance_t * p_aout )
745 /* Wait for the exact time to start playing (avoids resampling) */
746 vlc_mutex_lock( &p_aout->output.p_sys->lock );
747 if( !p_aout->output.p_sys->start_date )
748 vlc_cond_wait( &p_aout->output.p_sys->wait,
749 &p_aout->output.p_sys->lock );
750 vlc_mutex_unlock( &p_aout->output.p_sys->lock );
752 mwait( p_aout->output.p_sys->start_date - AOUT_PTS_TOLERANCE / 4 );
754 while ( !p_aout->b_die )
762 /*****************************************************************************
763 * ALSAFill: function used to fill the ALSA buffer as much as possible
764 *****************************************************************************/
765 static void ALSAFill( aout_instance_t * p_aout )
767 struct aout_sys_t * p_sys = p_aout->output.p_sys;
769 aout_buffer_t * p_buffer;
770 snd_pcm_status_t * p_status = p_sys->p_status;
771 snd_timestamp_t ts_next;
775 /* Fill in the buffer until space or audio output buffer shortage */
778 i_snd_rc = snd_pcm_status( p_sys->p_snd_pcm, p_status );
781 msg_Err( p_aout, "unable to get the device's status (%s)",
782 snd_strerror( i_snd_rc ) );
784 msleep( p_sys->i_period_time >> 1 );
788 /* Handle buffer underruns and reget the status */
789 if( snd_pcm_status_get_state( p_status ) == SND_PCM_STATE_XRUN )
791 /* Prepare the device */
792 i_snd_rc = snd_pcm_prepare( p_sys->p_snd_pcm );
796 msg_Warn( p_aout, "recovered from buffer underrun" );
798 /* Reget the status */
799 i_snd_rc = snd_pcm_status( p_sys->p_snd_pcm, p_status );
802 msg_Err( p_aout, "unable to get the device's status after "
803 "recovery (%s)", snd_strerror( i_snd_rc ) );
805 msleep( p_sys->i_period_time >> 1 );
811 msg_Err( p_aout, "unable to recover from buffer underrun" );
813 msleep( p_sys->i_period_time >> 1 );
817 /* Underrun, try to recover as quickly as possible */
822 /* Here the device should be either in the RUNNING state.
823 * p_status is valid. */
825 snd_pcm_status_get_tstamp( p_status, &ts_next );
826 next_date = (mtime_t)ts_next.tv_sec * 1000000 + ts_next.tv_usec;
829 next_date += (mtime_t)snd_pcm_status_get_delay(p_status)
830 * 1000000 / p_aout->output.output.i_rate;
834 /* With screwed ALSA drivers the timestamp is always zero;
835 * use another method then */
836 snd_pcm_sframes_t delay;
839 if( !snd_pcm_delay( p_sys->p_snd_pcm, &delay ) )
841 i_bytes = snd_pcm_frames_to_bytes(p_sys->p_snd_pcm, delay);
843 next_date = mdate() + (mtime_t)i_bytes * 1000000
844 / p_aout->output.output.i_bytes_per_frame
845 / p_aout->output.output.i_rate
846 * p_aout->output.output.i_frame_length;
850 p_buffer = aout_OutputNextBuffer( p_aout, next_date,
851 (p_aout->output.output.i_format ==
852 VLC_FOURCC('s','p','d','i')) );
854 /* Audio output buffer shortage -> stop the fill process and wait */
855 if( p_buffer == NULL )
857 msleep( p_sys->i_period_time >> 1 );
861 i_snd_rc = snd_pcm_writei( p_sys->p_snd_pcm, p_buffer->p_buffer,
862 p_buffer->i_nb_samples );
866 msg_Err( p_aout, "write failed (%s)",
867 snd_strerror( i_snd_rc ) );
870 aout_BufferFree( p_buffer );
874 static void GetDevicesForCard(module_config_t *p_item, int i_card);
875 static void GetDevices( module_config_t *p_item );
877 /*****************************************************************************
878 * config variable callback
879 *****************************************************************************/
880 static int FindDevicesCallback( vlc_object_t *p_this, char const *psz_name,
881 vlc_value_t newval, vlc_value_t oldval, void *p_unused )
883 module_config_t *p_item;
886 p_item = config_FindConfig( p_this, psz_name );
887 if( !p_item ) return VLC_SUCCESS;
889 /* Clear-up the current list */
892 /* Keep the first entrie */
893 for( i = 1; i < p_item->i_list; i++ )
895 free( p_item->ppsz_list[i] );
896 free( p_item->ppsz_list_text[i] );
898 /* TODO: Remove when no more needed */
899 p_item->ppsz_list[i] = NULL;
900 p_item->ppsz_list_text[i] = NULL;
904 GetDevices( p_item );
906 /* Signal change to the interface */
907 p_item->b_dirty = VLC_TRUE;
914 static void GetDevicesForCard(module_config_t *p_item, int i_card)
916 int i_pcm_device = -1;
918 snd_pcm_info_t *p_pcm_info;
923 sprintf(psz_dev, "hw:%i", i_card);
925 if (( i_err = snd_ctl_open(&p_ctl, psz_dev, 0)) < 0 )
930 if ((i_err = snd_card_get_name(i_card, &psz_card_name)) != 0)
932 psz_card_name = _("Unknown soundcard");
935 snd_pcm_info_alloca(&p_pcm_info);
939 char *psz_device, *psz_descr;
940 if ((i_err = snd_ctl_pcm_next_device(p_ctl, &i_pcm_device)) < 0)
944 if ( i_pcm_device < 0 )
947 snd_pcm_info_set_device(p_pcm_info, i_pcm_device);
948 snd_pcm_info_set_subdevice(p_pcm_info, 0);
949 snd_pcm_info_set_stream(p_pcm_info, SND_PCM_STREAM_PLAYBACK);
951 if ((i_err = snd_ctl_pcm_info(p_ctl, p_pcm_info)) < 0)
953 if (i_err != -ENOENT)
955 /* printf("get_devices_for_card(): "
956 "snd_ctl_pcm_info() "
957 "failed (%d:%d): %s.\n", i_card,
958 i_pcm_device, snd_strerror(-i_err));*/
963 asprintf( &psz_device, "hw:%d,%d", i_card, i_pcm_device );
964 asprintf( &psz_descr, "%s: %s (%s)", psz_card_name,
965 snd_pcm_info_get_name(p_pcm_info), psz_device );
968 (char **)realloc( p_item->ppsz_list,
969 (p_item->i_list + 2) * sizeof(char *) );
970 p_item->ppsz_list_text =
971 (char **)realloc( p_item->ppsz_list_text,
972 (p_item->i_list + 2) * sizeof(char *) );
973 p_item->ppsz_list[ p_item->i_list ] = psz_device;
974 p_item->ppsz_list_text[ p_item->i_list ] = psz_descr;
976 p_item->ppsz_list[ p_item->i_list ] = NULL;
977 p_item->ppsz_list_text[ p_item->i_list ] = NULL;
981 snd_ctl_close( p_ctl );
986 static void GetDevices( module_config_t *p_item )
991 if ((i_err = snd_card_next(&i_card)) != 0)
993 // g_warning("snd_next_card() failed: %s", snd_strerror(-err));
999 GetDevicesForCard(p_item, i_card);
1000 if ((i_err = snd_card_next(&i_card)) != 0)
1002 // g_warning("snd_next_card() failed: %s",
1003 // snd_strerror(-err));