1 /*****************************************************************************
2 * alsa.c : alsa plugin for vlc
3 *****************************************************************************
4 * Copyright (C) 2000-2001 the VideoLAN team
7 * Authors: Henri Fallon <henri@videolan.org> - Original Author
8 * Jeffrey Baker <jwbaker@acm.org> - Port to ALSA 1.0 API
9 * John Paul Lorenti <jpl31@columbia.edu> - Device selection
10 * Arnaud de Bossoreille de Ribou <bozo@via.ecp.fr> - S/PDIF and aout3
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
25 *****************************************************************************/
27 /*****************************************************************************
29 *****************************************************************************/
34 #include <vlc_common.h>
35 #include <vlc_plugin.h>
37 #include <errno.h> /* ENOMEM */
38 #include <vlc_dialog.h>
44 Note: we use the new API which is available since 0.9.0beta10a. */
45 #define ALSA_PCM_NEW_HW_PARAMS_API
46 #define ALSA_PCM_NEW_SW_PARAMS_API
47 #include <alsa/asoundlib.h>
49 /*#define ALSA_DEBUG*/
51 /*****************************************************************************
52 * aout_sys_t: ALSA audio output method descriptor
53 *****************************************************************************
54 * This structure is part of the audio output thread descriptor.
55 * It describes the ALSA specific properties of an audio device.
56 *****************************************************************************/
59 snd_pcm_t * p_snd_pcm;
60 unsigned int i_period_time;
63 snd_output_t * p_snd_stderr;
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 void* ALSAThread ( void * );
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 const char *const ppsz_devices[] = { "default" };
102 static const char *const ppsz_devices_text[] = { N_("Default") };
104 set_shortname( "ALSA" )
105 set_description( N_("ALSA audio output") )
106 set_category( CAT_AUDIO )
107 set_subcategory( SUBCAT_AUDIO_AOUT )
108 add_string( "alsa-audio-device", DEFAULT_ALSA_DEVICE, aout_FindAndRestart,
109 N_("ALSA Device Name"), NULL, false )
110 add_deprecated_alias( "alsadev" ) /* deprecated since 0.9.3 */
111 change_string_list( ppsz_devices, ppsz_devices_text, FindDevicesCallback )
112 change_action_add( FindDevicesCallback, N_("Refresh list") )
114 set_capability( "audio output", 150 )
115 set_callbacks( Open, Close )
118 /*****************************************************************************
119 * Probe: probe the audio device for available formats and channels
120 *****************************************************************************/
121 static void Probe( aout_instance_t * p_aout,
122 const char * psz_device, const char * psz_iec_device,
123 int *pi_snd_pcm_format )
125 struct aout_sys_t * p_sys = p_aout->output.p_sys;
126 vlc_value_t val, text;
129 var_Create ( p_aout, "audio-device", VLC_VAR_INTEGER | VLC_VAR_HASCHOICE );
130 text.psz_string = _("Audio Device");
131 var_Change( p_aout, "audio-device", VLC_VAR_SETTEXT, &text, NULL );
133 /* We'll open the audio device in non blocking mode so we can just exit
134 * when it is already in use, but for the real stuff we'll still use
135 * the blocking mode */
137 /* Now test linear PCM capabilities */
138 if ( !(i_ret = snd_pcm_open( &p_sys->p_snd_pcm, psz_device,
139 SND_PCM_STREAM_PLAYBACK,
140 SND_PCM_NONBLOCK ) ) )
143 snd_pcm_hw_params_t * p_hw;
144 snd_pcm_hw_params_alloca (&p_hw);
146 if ( snd_pcm_hw_params_any( p_sys->p_snd_pcm, p_hw ) < 0 )
148 msg_Warn( p_aout, "unable to retrieve initial hardware parameters"
149 ", disabling linear PCM audio" );
150 snd_pcm_close( p_sys->p_snd_pcm );
151 var_Destroy( p_aout, "audio-device" );
155 if ( snd_pcm_hw_params_set_format( p_sys->p_snd_pcm, p_hw,
156 *pi_snd_pcm_format ) < 0 )
160 if( *pi_snd_pcm_format != SND_PCM_FORMAT_S16 )
162 *pi_snd_pcm_format = SND_PCM_FORMAT_S16;
163 i_snd_rc = snd_pcm_hw_params_set_format( p_sys->p_snd_pcm,
164 p_hw, *pi_snd_pcm_format );
168 msg_Warn( p_aout, "unable to set stream sample size and "
169 "word order, disabling linear PCM audio" );
170 snd_pcm_close( p_sys->p_snd_pcm );
171 var_Destroy( p_aout, "audio-device" );
176 i_channels = aout_FormatNbChannels( &p_aout->output.output );
178 while ( i_channels > 0 )
180 if ( !snd_pcm_hw_params_test_channels( p_sys->p_snd_pcm, p_hw,
183 switch ( i_channels )
186 val.i_int = AOUT_VAR_MONO;
187 text.psz_string = _("Mono");
188 var_Change( p_aout, "audio-device",
189 VLC_VAR_ADDCHOICE, &val, &text );
192 val.i_int = AOUT_VAR_STEREO;
193 text.psz_string = _("Stereo");
194 var_Change( p_aout, "audio-device",
195 VLC_VAR_ADDCHOICE, &val, &text );
196 var_Set( p_aout, "audio-device", val );
199 val.i_int = AOUT_VAR_2F2R;
200 text.psz_string = _("2 Front 2 Rear");
201 var_Change( p_aout, "audio-device",
202 VLC_VAR_ADDCHOICE, &val, &text );
205 val.i_int = AOUT_VAR_5_1;
206 text.psz_string = "5.1";
207 var_Change( p_aout, "audio-device",
208 VLC_VAR_ADDCHOICE, &val, &text );
216 /* Special case for mono on stereo only boards */
217 i_channels = aout_FormatNbChannels( &p_aout->output.output );
218 var_Change( p_aout, "audio-device", VLC_VAR_CHOICESCOUNT, &val, NULL );
219 if( val.i_int <= 0 && i_channels == 1 )
221 if ( !snd_pcm_hw_params_test_channels( p_sys->p_snd_pcm, p_hw, 2 ))
223 val.i_int = AOUT_VAR_STEREO;
224 text.psz_string = (char*)N_("Stereo");
225 var_Change( p_aout, "audio-device",
226 VLC_VAR_ADDCHOICE, &val, &text );
227 var_Set( p_aout, "audio-device", val );
231 /* Close the previously opened device */
232 snd_pcm_close( p_sys->p_snd_pcm );
234 else if ( i_ret == -EBUSY )
236 msg_Warn( p_aout, "audio device: %s is already in use", psz_device );
239 /* Test for S/PDIF device if needed */
240 if ( psz_iec_device )
242 /* Opening the device should be enough */
243 if ( !(i_ret = snd_pcm_open( &p_sys->p_snd_pcm, psz_iec_device,
244 SND_PCM_STREAM_PLAYBACK,
245 SND_PCM_NONBLOCK ) ) )
247 val.i_int = AOUT_VAR_SPDIF;
248 text.psz_string = (char*)N_("A/52 over S/PDIF");
249 var_Change( p_aout, "audio-device",
250 VLC_VAR_ADDCHOICE, &val, &text );
251 if( config_GetInt( p_aout, "spdif" ) )
252 var_Set( p_aout, "audio-device", val );
254 snd_pcm_close( p_sys->p_snd_pcm );
256 else if ( i_ret == -EBUSY )
258 msg_Warn( p_aout, "audio device: %s is already in use",
263 var_Change( p_aout, "audio-device", VLC_VAR_CHOICESCOUNT, &val, NULL );
266 /* Probe() has failed. */
267 msg_Dbg( p_aout, "failed to find a usable alsa configuration" );
268 var_Destroy( p_aout, "audio-device" );
272 /* Add final settings to the variable */
273 var_AddCallback( p_aout, "audio-device", aout_ChannelsRestart, NULL );
274 var_SetBool( p_aout, "intf-change", true );
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;
310 /* Allocate structures */
311 p_aout->output.p_sys = p_sys = malloc( sizeof( aout_sys_t ) );
315 /* Get device name */
316 if( (psz_device = config_GetPsz( p_aout, "alsa-audio-device" )) == NULL )
318 msg_Err( p_aout, "no audio device given (maybe \"default\" ?)" );
319 dialog_Fatal( p_aout, _("No Audio Device"), "%s",
320 _("No audio device name was given. You might want to " \
321 "enter \"default\".") );
326 /* Choose the IEC device for S/PDIF output:
327 if the device is overriden by the user then it will be the one
328 otherwise we compute the default device based on the output format. */
329 if( AOUT_FMT_NON_LINEAR( &p_aout->output.output )
330 && !strcmp( psz_device, DEFAULT_ALSA_DEVICE ) )
332 snprintf( psz_default_iec_device, sizeof(psz_default_iec_device),
333 "iec958:AES0=0x%x,AES1=0x%x,AES2=0x%x,AES3=0x%x",
334 IEC958_AES0_CON_EMPHASIS_NONE | IEC958_AES0_NONAUDIO,
335 IEC958_AES1_CON_ORIGINAL | IEC958_AES1_CON_PCM_CODER,
337 ( p_aout->output.output.i_rate == 48000 ?
338 IEC958_AES3_CON_FS_48000 :
339 ( p_aout->output.output.i_rate == 44100 ?
340 IEC958_AES3_CON_FS_44100 : IEC958_AES3_CON_FS_32000 ) ) );
341 psz_iec_device = psz_default_iec_device;
343 else if( AOUT_FMT_NON_LINEAR( &p_aout->output.output ) )
345 psz_iec_device = psz_device;
349 psz_iec_device = NULL;
352 /* Choose the linear PCM format (read the comment above about FPU
356 i_vlc_pcm_format = VLC_CODEC_FL32;
357 i_snd_pcm_format = SND_PCM_FORMAT_FLOAT;
361 i_vlc_pcm_format = VLC_CODEC_S16N;
362 i_snd_pcm_format = SND_PCM_FORMAT_S16;
365 /* If the variable doesn't exist then it's the first time we're called
366 and we have to probe the available audio formats and channels */
367 if ( var_Type( p_aout, "audio-device" ) == 0 )
369 Probe( p_aout, psz_device, psz_iec_device, &i_snd_pcm_format );
372 if ( var_Get( p_aout, "audio-device", &val ) < 0 )
379 p_aout->output.output.i_format = i_vlc_pcm_format;
380 if ( val.i_int == AOUT_VAR_5_1 )
382 p_aout->output.output.i_physical_channels
383 = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER
384 | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT
387 psz_device = strdup( "surround51" );
389 else if ( val.i_int == AOUT_VAR_2F2R )
391 p_aout->output.output.i_physical_channels
392 = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT
393 | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT;
395 psz_device = strdup( "surround40" );
397 else if ( val.i_int == AOUT_VAR_STEREO )
399 p_aout->output.output.i_physical_channels
400 = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT;
402 else if ( val.i_int == AOUT_VAR_MONO )
404 p_aout->output.output.i_physical_channels = AOUT_CHAN_CENTER;
406 else if( val.i_int != AOUT_VAR_SPDIF )
408 /* This should not happen ! */
409 msg_Err( p_aout, "internal: can't find audio-device (%i)", val.i_int );
416 snd_output_stdio_attach( &p_sys->p_snd_stderr, stderr, 0 );
419 /* Open the device */
420 if ( val.i_int == AOUT_VAR_SPDIF )
422 if ( ( i_snd_rc = snd_pcm_open( &p_sys->p_snd_pcm, psz_iec_device,
423 SND_PCM_STREAM_PLAYBACK, 0 ) ) < 0 )
425 msg_Err( p_aout, "cannot open ALSA device `%s' (%s)",
426 psz_iec_device, snd_strerror( i_snd_rc ) );
427 dialog_Fatal( p_aout, _("Audio output failed"),
428 _("VLC could not open the ALSA device \"%s\" (%s)."),
429 psz_iec_device, snd_strerror( i_snd_rc ) );
434 i_buffer_size = ALSA_SPDIF_BUFFER_SIZE;
435 i_snd_pcm_format = SND_PCM_FORMAT_S16;
438 i_vlc_pcm_format = VLC_CODEC_SPDIFL;
439 p_aout->output.i_nb_samples = i_period_size = ALSA_SPDIF_PERIOD_SIZE;
440 p_aout->output.output.i_bytes_per_frame = AOUT_SPDIF_SIZE;
441 p_aout->output.output.i_frame_length = A52_FRAME_NB;
443 aout_VolumeNoneInit( p_aout );
449 msg_Dbg( p_aout, "opening ALSA device `%s'", psz_device );
451 /* Since it seems snd_pcm_close hasn't really released the device at
452 the time it returns, probe if the device is available in loop for 1s.
453 We cannot use blocking mode since the we would wait indefinitely when
454 switching from a dmx device to surround51. */
456 for( i = 10; i >= 0; i-- )
458 if ( ( i_snd_rc = snd_pcm_open( &p_sys->p_snd_pcm, psz_device,
459 SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK ) ) == -EBUSY )
461 if( i ) msleep( 100000 /* 100ms */ );
464 msg_Err( p_aout, "audio device: %s is already in use",
466 dialog_Fatal( p_aout, _("Audio output failed"),
467 _("The audio device \"%s\" is already in use."),
476 msg_Err( p_aout, "cannot open ALSA device `%s' (%s)",
477 psz_device, snd_strerror( i_snd_rc ) );
478 dialog_Fatal( p_aout, _("Audio output failed"),
479 _("VLC could not open the ALSA device \"%s\" (%s)."),
480 psz_device, snd_strerror( i_snd_rc ) );
486 /* We want blocking mode */
487 snd_pcm_nonblock( p_sys->p_snd_pcm, 0 );
489 i_buffer_size = ALSA_DEFAULT_BUFFER_SIZE;
490 i_channels = aout_FormatNbChannels( &p_aout->output.output );
492 p_aout->output.i_nb_samples = i_period_size = ALSA_DEFAULT_PERIOD_SIZE;
494 aout_VolumeSoftInit( p_aout );
497 /* Free psz_device so that all the remaining data is stack-allocated */
500 p_aout->output.pf_play = Play;
502 snd_pcm_hw_params_alloca(&p_hw);
503 snd_pcm_sw_params_alloca(&p_sw);
505 /* Due to some bugs in alsa with some drivers, we need to retry in s16l
506 if snd_pcm_hw_params fails in fl32 */
511 /* Get Initial hardware parameters */
512 if ( ( i_snd_rc = snd_pcm_hw_params_any( p_sys->p_snd_pcm, p_hw ) ) < 0 )
514 msg_Err( p_aout, "unable to retrieve initial hardware parameters (%s)",
515 snd_strerror( i_snd_rc ) );
520 if ( ( i_snd_rc = snd_pcm_hw_params_set_format( p_sys->p_snd_pcm, p_hw,
521 i_snd_pcm_format ) ) < 0 )
523 if( i_snd_pcm_format != SND_PCM_FORMAT_S16 )
525 i_snd_pcm_format = SND_PCM_FORMAT_S16;
526 i_snd_rc = snd_pcm_hw_params_set_format( p_sys->p_snd_pcm,
527 p_hw, i_snd_pcm_format );
531 msg_Err( p_aout, "unable to set stream sample size and "
532 "word order (%s)", snd_strerror( i_snd_rc ) );
536 if( i_vlc_pcm_format != VLC_CODEC_SPDIFL )
537 switch( i_snd_pcm_format )
539 case SND_PCM_FORMAT_FLOAT:
540 i_vlc_pcm_format = VLC_CODEC_FL32;
542 case SND_PCM_FORMAT_S16:
543 i_vlc_pcm_format = VLC_CODEC_S16N;
546 p_aout->output.output.i_format = i_vlc_pcm_format;
548 if ( ( i_snd_rc = snd_pcm_hw_params_set_access( p_sys->p_snd_pcm, p_hw,
549 SND_PCM_ACCESS_RW_INTERLEAVED ) ) < 0 )
551 msg_Err( p_aout, "unable to set interleaved stream format (%s)",
552 snd_strerror( i_snd_rc ) );
557 if ( ( i_snd_rc = snd_pcm_hw_params_set_channels( p_sys->p_snd_pcm, p_hw,
560 msg_Err( p_aout, "unable to set number of output channels (%s)",
561 snd_strerror( i_snd_rc ) );
566 i_old_rate = p_aout->output.output.i_rate;
567 i_snd_rc = snd_pcm_hw_params_set_rate_near( p_sys->p_snd_pcm, p_hw,
568 &p_aout->output.output.i_rate,
570 if( i_snd_rc < 0 || p_aout->output.output.i_rate != i_old_rate )
572 msg_Warn( p_aout, "The rate %d Hz is not supported by your " \
573 "hardware. Using %d Hz instead.\n", i_old_rate, \
574 p_aout->output.output.i_rate );
577 /* Set period size. */
578 if ( ( i_snd_rc = snd_pcm_hw_params_set_period_size_near( p_sys->p_snd_pcm,
579 p_hw, &i_period_size, NULL ) ) < 0 )
581 msg_Err( p_aout, "unable to set period size (%s)",
582 snd_strerror( i_snd_rc ) );
585 p_aout->output.i_nb_samples = i_period_size;
587 /* Set buffer size. */
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 msg_Err( p_aout, "unable to set buffer size (%s)",
592 snd_strerror( i_snd_rc ) );
596 /* Commit hardware parameters. */
597 if ( ( i_snd_rc = snd_pcm_hw_params( p_sys->p_snd_pcm, p_hw ) ) < 0 )
599 if ( b_retry == false &&
600 i_snd_pcm_format == SND_PCM_FORMAT_FLOAT)
603 i_snd_pcm_format = SND_PCM_FORMAT_S16;
604 p_aout->output.output.i_format = VLC_CODEC_S16N;
605 msg_Warn( p_aout, "unable to commit hardware configuration "
606 "with fl32 samples. Retrying with s16l (%s)", snd_strerror( i_snd_rc ) );
610 msg_Err( p_aout, "unable to commit hardware configuration (%s)",
611 snd_strerror( i_snd_rc ) );
617 if( ( i_snd_rc = snd_pcm_hw_params_get_period_time( p_hw,
618 &p_sys->i_period_time, NULL ) ) < 0 )
620 msg_Err( p_aout, "unable to get period time (%s)",
621 snd_strerror( i_snd_rc ) );
625 /* Get Initial software parameters */
626 snd_pcm_sw_params_current( p_sys->p_snd_pcm, p_sw );
628 i_snd_rc = snd_pcm_sw_params_set_sleep_min( p_sys->p_snd_pcm, p_sw, 0 );
630 i_snd_rc = snd_pcm_sw_params_set_avail_min( p_sys->p_snd_pcm, p_sw,
631 p_aout->output.i_nb_samples );
632 /* start playing when one period has been written */
633 i_snd_rc = snd_pcm_sw_params_set_start_threshold( p_sys->p_snd_pcm, p_sw,
634 ALSA_DEFAULT_PERIOD_SIZE);
637 msg_Err( p_aout, "unable to set start threshold (%s)",
638 snd_strerror( i_snd_rc ) );
642 /* Commit software parameters. */
643 if ( snd_pcm_sw_params( p_sys->p_snd_pcm, p_sw ) < 0 )
645 msg_Err( p_aout, "unable to set software configuration" );
650 snd_output_printf( p_sys->p_snd_stderr, "\nALSA hardware setup:\n\n" );
651 snd_pcm_dump_hw_setup( p_sys->p_snd_pcm, p_sys->p_snd_stderr );
652 snd_output_printf( p_sys->p_snd_stderr, "\nALSA software setup:\n\n" );
653 snd_pcm_dump_sw_setup( p_sys->p_snd_pcm, p_sys->p_snd_stderr );
654 snd_output_printf( p_sys->p_snd_stderr, "\n" );
657 p_sys->start_date = 0;
658 vlc_sem_init( &p_sys->wait, 0 );
660 /* Create ALSA thread and wait for its readiness. */
661 if( vlc_clone( &p_sys->thread, ALSAThread, p_aout,
662 VLC_THREAD_PRIORITY_OUTPUT ) )
664 msg_Err( p_aout, "cannot create ALSA thread (%m)" );
665 vlc_sem_destroy( &p_sys->wait );
672 snd_pcm_close( p_sys->p_snd_pcm );
674 snd_output_close( p_sys->p_snd_stderr );
680 static void PlayIgnore( aout_instance_t *p_aout )
681 { /* Already playing - nothing to do */
685 /*****************************************************************************
686 * Play: start playback
687 *****************************************************************************/
688 static void Play( aout_instance_t *p_aout )
690 p_aout->output.pf_play = PlayIgnore;
692 /* get the playing date of the first aout buffer */
693 p_aout->output.p_sys->start_date =
694 aout_FifoFirstDate( p_aout, &p_aout->output.fifo );
696 /* wake up the audio output thread */
697 sem_post( &p_aout->output.p_sys->wait );
700 /*****************************************************************************
701 * Close: close the ALSA device
702 *****************************************************************************/
703 static void Close( vlc_object_t *p_this )
705 aout_instance_t *p_aout = (aout_instance_t *)p_this;
706 struct aout_sys_t * p_sys = p_aout->output.p_sys;
709 /* Make sure that the thread will stop once it is waken up */
710 vlc_cancel( p_sys->thread );
711 vlc_join( p_sys->thread, NULL );
712 vlc_sem_destroy( &p_sys->wait );
715 i_snd_rc = snd_pcm_close( p_sys->p_snd_pcm );
719 msg_Err( p_aout, "failed closing ALSA device (%s)",
720 snd_strerror( i_snd_rc ) );
724 snd_output_close( p_sys->p_snd_stderr );
730 static void pcm_drop(void *pcm)
735 /*****************************************************************************
736 * ALSAThread: asynchronous thread used to DMA the data to the device
737 *****************************************************************************/
738 static void* ALSAThread( void *data )
740 aout_instance_t * p_aout = data;
741 struct aout_sys_t * p_sys = p_aout->output.p_sys;
743 /* Wait for the exact time to start playing (avoids resampling) */
744 vlc_sem_wait( &p_sys->wait );
745 mwait( p_sys->start_date - AOUT_PTS_TOLERANCE / 4 );
747 vlc_cleanup_push( pcm_drop, p_sys->p_snd_pcm );
755 /*****************************************************************************
756 * ALSAFill: function used to fill the ALSA buffer as much as possible
757 *****************************************************************************/
758 static void ALSAFill( aout_instance_t * p_aout )
760 struct aout_sys_t * p_sys = p_aout->output.p_sys;
761 snd_pcm_t *p_pcm = p_sys->p_snd_pcm;
762 snd_pcm_status_t * p_status;
766 int canc = vlc_savecancel();
767 /* Fill in the buffer until space or audio output buffer shortage */
770 snd_pcm_status_alloca(&p_status);
771 i_snd_rc = snd_pcm_status( p_pcm, p_status );
774 msg_Err( p_aout, "cannot get device status" );
778 /* Handle buffer underruns and get the status again */
779 if( snd_pcm_status_get_state( p_status ) == SND_PCM_STATE_XRUN )
781 /* Prepare the device */
782 i_snd_rc = snd_pcm_prepare( p_pcm );
785 msg_Err( p_aout, "cannot recover from buffer underrun" );
789 msg_Dbg( p_aout, "recovered from buffer underrun" );
791 /* Get the new status */
792 i_snd_rc = snd_pcm_status( p_pcm, p_status );
795 msg_Err( p_aout, "cannot get device status after recovery" );
799 /* Underrun, try to recover as quickly as possible */
804 /* Here the device should be in RUNNING state, p_status is valid. */
805 snd_pcm_sframes_t delay = snd_pcm_status_get_delay( p_status );
806 if( delay == 0 ) /* workaround buggy alsa drivers */
807 if( snd_pcm_delay( p_pcm, &delay ) < 0 )
808 delay = 0; /* FIXME: use a positive minimal delay */
810 size_t i_bytes = snd_pcm_frames_to_bytes( p_pcm, delay );
811 mtime_t delay_us = CLOCK_FREQ * i_bytes
812 / p_aout->output.output.i_bytes_per_frame
813 / p_aout->output.output.i_rate
814 * p_aout->output.output.i_frame_length;
817 snd_pcm_state_t state = snd_pcm_status_get_state( p_status );
818 if( state != SND_PCM_STATE_RUNNING )
819 msg_Err( p_aout, "pcm status (%d) != RUNNING", state );
821 msg_Dbg( p_aout, "Delay is %ld frames (%zu bytes)", delay, i_bytes );
823 msg_Dbg( p_aout, "Bytes per frame: %d", p_aout->output.output.i_bytes_per_frame );
824 msg_Dbg( p_aout, "Rate: %d", p_aout->output.output.i_rate );
825 msg_Dbg( p_aout, "Frame length: %d", p_aout->output.output.i_frame_length );
826 msg_Dbg( p_aout, "Next date: in %"PRId64" microseconds", delay_us );
828 next_date = mdate() + delay_us;
831 block_t *p_buffer = aout_OutputNextBuffer( p_aout, next_date,
832 (p_aout->output.output.i_format == VLC_CODEC_SPDIFL) );
834 /* Audio output buffer shortage -> stop the fill process and wait */
835 if( p_buffer == NULL )
840 int n = snd_pcm_poll_descriptors_count(p_pcm);
841 struct pollfd ufd[n];
842 unsigned short revents;
844 snd_pcm_poll_descriptors(p_pcm, ufd, n);
847 vlc_restorecancel(canc);
849 canc = vlc_savecancel();
850 snd_pcm_poll_descriptors_revents(p_pcm, ufd, n, &revents);
854 if(revents & POLLOUT)
856 i_snd_rc = snd_pcm_writei( p_pcm, p_buffer->p_buffer,
857 p_buffer->i_nb_samples );
858 if( i_snd_rc != -ESTRPIPE )
862 /* a suspend event occurred
863 * (stream is suspended and waiting for an application recovery) */
864 msg_Dbg( p_aout, "entering in suspend mode, trying to resume..." );
866 while( ( i_snd_rc = snd_pcm_resume( p_pcm ) ) == -EAGAIN )
868 vlc_restorecancel(canc);
869 msleep(CLOCK_FREQ); /* device still suspended, wait... */
870 canc = vlc_savecancel();
874 /* Device does not support resuming, restart it */
875 i_snd_rc = snd_pcm_prepare( p_pcm );
880 msg_Err( p_aout, "cannot write: %s", snd_strerror( i_snd_rc ) );
882 vlc_restorecancel(canc);
883 block_Release( p_buffer );
888 msg_Err( p_aout, "ALSA error: %s", snd_strerror( i_snd_rc ) );
890 vlc_restorecancel(canc);
891 msleep(p_sys->i_period_time / 2);
894 static void GetDevicesForCard( module_config_t *p_item, int i_card );
895 static void GetDevices( module_config_t *p_item );
897 /*****************************************************************************
898 * config variable callback
899 *****************************************************************************/
900 static int FindDevicesCallback( vlc_object_t *p_this, char const *psz_name,
901 vlc_value_t newval, vlc_value_t oldval, void *p_unused )
903 module_config_t *p_item;
909 p_item = config_FindConfig( p_this, psz_name );
910 if( !p_item ) return VLC_SUCCESS;
912 /* Clear-up the current list */
915 /* Keep the first entrie */
916 for( i = 1; i < p_item->i_list; i++ )
918 free( (char *)p_item->ppsz_list[i] );
919 free( (char *)p_item->ppsz_list_text[i] );
921 /* TODO: Remove when no more needed */
922 p_item->ppsz_list[i] = NULL;
923 p_item->ppsz_list_text[i] = NULL;
927 GetDevices( p_item );
929 /* Signal change to the interface */
930 p_item->b_dirty = true;
936 static void GetDevicesForCard( module_config_t *p_item, int i_card )
938 int i_pcm_device = -1;
940 snd_pcm_info_t *p_pcm_info;
945 sprintf( psz_dev, "hw:%i", i_card );
947 if( ( i_err = snd_ctl_open( &p_ctl, psz_dev, 0 ) ) < 0 )
950 if( ( i_err = snd_card_get_name( i_card, &psz_card_name ) ) != 0)
951 psz_card_name = _("Unknown soundcard");
953 snd_pcm_info_alloca( &p_pcm_info );
957 char *psz_device, *psz_descr;
958 if( ( i_err = snd_ctl_pcm_next_device( p_ctl, &i_pcm_device ) ) < 0 )
960 if( i_pcm_device < 0 )
963 snd_pcm_info_set_device( p_pcm_info, i_pcm_device );
964 snd_pcm_info_set_subdevice( p_pcm_info, 0 );
965 snd_pcm_info_set_stream( p_pcm_info, SND_PCM_STREAM_PLAYBACK );
967 if( ( i_err = snd_ctl_pcm_info( p_ctl, p_pcm_info ) ) < 0 )
969 if( i_err != -ENOENT )
971 /*printf( "get_devices_for_card(): "
972 "snd_ctl_pcm_info() "
973 "failed (%d:%d): %s.\n", i_card,
974 i_pcm_device, snd_strerror( -i_err ) );*/
979 if( asprintf( &psz_device, "hw:%d,%d", i_card, i_pcm_device ) == -1 )
981 if( asprintf( &psz_descr, "%s: %s (%s)", psz_card_name,
982 snd_pcm_info_get_name(p_pcm_info), psz_device ) == -1 )
989 (char **)realloc( p_item->ppsz_list,
990 (p_item->i_list + 2) * sizeof(char *) );
991 p_item->ppsz_list_text =
992 (char **)realloc( p_item->ppsz_list_text,
993 (p_item->i_list + 2) * sizeof(char *) );
994 p_item->ppsz_list[ p_item->i_list ] = psz_device;
995 p_item->ppsz_list_text[ p_item->i_list ] = psz_descr;
997 p_item->ppsz_list[ p_item->i_list ] = NULL;
998 p_item->ppsz_list_text[ p_item->i_list ] = NULL;
1001 snd_ctl_close( p_ctl );
1006 static void GetDevices( module_config_t *p_item )
1011 if( ( i_err = snd_card_next( &i_card ) ) != 0 )
1013 /*printf( "snd_card_next() failed: %s", snd_strerror( -i_err ) );*/
1017 while( i_card > -1 )
1019 GetDevicesForCard( p_item, i_card );
1020 if( ( i_err = snd_card_next( &i_card ) ) != 0 )
1022 /*printf( "snd_card_next() failed: %s", snd_strerror( -i_err ) );*/