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 *****************************************************************************/
36 #include <vlc_common.h>
37 #include <vlc_plugin.h>
39 #include <errno.h> /* ENOMEM */
40 #include <vlc_dialog.h>
46 Note: we use the new API which is available since 0.9.0beta10a. */
47 #define ALSA_PCM_NEW_HW_PARAMS_API
48 #define ALSA_PCM_NEW_SW_PARAMS_API
49 #include <alsa/asoundlib.h>
50 #include <alsa/version.h>
52 /*#define ALSA_DEBUG*/
54 /*****************************************************************************
55 * aout_sys_t: ALSA audio output method descriptor
56 *****************************************************************************
57 * This structure is part of the audio output thread descriptor.
58 * It describes the ALSA specific properties of an audio device.
59 *****************************************************************************/
62 snd_pcm_t * p_snd_pcm;
63 unsigned int i_period_time;
66 snd_output_t * p_snd_stderr;
74 #define A52_FRAME_NB 1536
76 /* These values are in frames.
77 To convert them to a number of bytes you have to multiply them by the
78 number of channel(s) (eg. 2 for stereo) and the size of a sample (eg.
80 #define ALSA_DEFAULT_PERIOD_SIZE 1024
81 #define ALSA_DEFAULT_BUFFER_SIZE ( ALSA_DEFAULT_PERIOD_SIZE << 8 )
82 #define ALSA_SPDIF_PERIOD_SIZE A52_FRAME_NB
83 #define ALSA_SPDIF_BUFFER_SIZE ( ALSA_SPDIF_PERIOD_SIZE << 4 )
84 /* Why << 4 ? --Meuuh */
85 /* Why not ? --Bozo */
88 #define DEFAULT_ALSA_DEVICE N_("default")
90 /*****************************************************************************
92 *****************************************************************************/
93 static int Open ( vlc_object_t * );
94 static void Close ( vlc_object_t * );
95 static void Play ( aout_instance_t * );
96 static void* ALSAThread ( void * );
97 static void ALSAFill ( aout_instance_t * );
98 static int FindDevicesCallback( vlc_object_t *p_this, char const *psz_name,
99 vlc_value_t newval, vlc_value_t oldval, void *p_unused );
100 static void GetDevicesForCard( vlc_object_t *, module_config_t *, int card );
101 static void GetDevices( vlc_object_t *, module_config_t * );
103 /*****************************************************************************
105 *****************************************************************************/
106 static const char *const ppsz_devices[] = { "default" };
107 static const char *const ppsz_devices_text[] = { N_("Default") };
109 set_shortname( "ALSA" )
110 set_description( N_("ALSA audio output") )
111 set_category( CAT_AUDIO )
112 set_subcategory( SUBCAT_AUDIO_AOUT )
113 add_string( "alsa-audio-device", DEFAULT_ALSA_DEVICE, aout_FindAndRestart,
114 N_("ALSA Device Name"), NULL, false )
115 add_deprecated_alias( "alsadev" ) /* deprecated since 0.9.3 */
116 change_string_list( ppsz_devices, ppsz_devices_text, FindDevicesCallback )
117 change_action_add( FindDevicesCallback, N_("Refresh list") )
119 set_capability( "audio output", 150 )
120 set_callbacks( Open, Close )
123 /*****************************************************************************
124 * Probe: probe the audio device for available formats and channels
125 *****************************************************************************/
126 static void Probe( aout_instance_t * p_aout,
127 const char * psz_device, const char * psz_iec_device,
128 int *pi_snd_pcm_format )
130 struct aout_sys_t * p_sys = p_aout->output.p_sys;
131 vlc_value_t val, text;
134 var_Create ( p_aout, "audio-device", VLC_VAR_INTEGER | VLC_VAR_HASCHOICE );
135 text.psz_string = _("Audio Device");
136 var_Change( p_aout, "audio-device", VLC_VAR_SETTEXT, &text, NULL );
138 /* We'll open the audio device in non blocking mode so we can just exit
139 * when it is already in use, but for the real stuff we'll still use
140 * the blocking mode */
142 /* Now test linear PCM capabilities */
143 if ( !(i_ret = snd_pcm_open( &p_sys->p_snd_pcm, psz_device,
144 SND_PCM_STREAM_PLAYBACK,
145 SND_PCM_NONBLOCK ) ) )
148 snd_pcm_hw_params_t * p_hw;
149 snd_pcm_hw_params_alloca (&p_hw);
151 if ( snd_pcm_hw_params_any( p_sys->p_snd_pcm, p_hw ) < 0 )
153 msg_Warn( p_aout, "unable to retrieve initial hardware parameters"
154 ", disabling linear PCM audio" );
155 snd_pcm_close( p_sys->p_snd_pcm );
156 var_Destroy( p_aout, "audio-device" );
160 if ( snd_pcm_hw_params_set_format( p_sys->p_snd_pcm, p_hw,
161 *pi_snd_pcm_format ) < 0 )
165 if( *pi_snd_pcm_format != SND_PCM_FORMAT_S16 )
167 *pi_snd_pcm_format = SND_PCM_FORMAT_S16;
168 i_snd_rc = snd_pcm_hw_params_set_format( p_sys->p_snd_pcm,
169 p_hw, *pi_snd_pcm_format );
173 msg_Warn( p_aout, "unable to set stream sample size and "
174 "word order, disabling linear PCM audio" );
175 snd_pcm_close( p_sys->p_snd_pcm );
176 var_Destroy( p_aout, "audio-device" );
181 i_channels = aout_FormatNbChannels( &p_aout->output.output );
183 while ( i_channels > 0 )
185 if ( !snd_pcm_hw_params_test_channels( p_sys->p_snd_pcm, p_hw,
188 switch ( i_channels )
191 val.i_int = AOUT_VAR_MONO;
192 text.psz_string = _("Mono");
193 var_Change( p_aout, "audio-device",
194 VLC_VAR_ADDCHOICE, &val, &text );
197 val.i_int = AOUT_VAR_STEREO;
198 text.psz_string = _("Stereo");
199 var_Change( p_aout, "audio-device",
200 VLC_VAR_ADDCHOICE, &val, &text );
201 var_Set( p_aout, "audio-device", val );
204 val.i_int = AOUT_VAR_2F2R;
205 text.psz_string = _("2 Front 2 Rear");
206 var_Change( p_aout, "audio-device",
207 VLC_VAR_ADDCHOICE, &val, &text );
210 val.i_int = AOUT_VAR_5_1;
211 text.psz_string = "5.1";
212 var_Change( p_aout, "audio-device",
213 VLC_VAR_ADDCHOICE, &val, &text );
221 /* Special case for mono on stereo only boards */
222 i_channels = aout_FormatNbChannels( &p_aout->output.output );
223 var_Change( p_aout, "audio-device", VLC_VAR_CHOICESCOUNT, &val, NULL );
224 if( val.i_int <= 0 && i_channels == 1 )
226 if ( !snd_pcm_hw_params_test_channels( p_sys->p_snd_pcm, p_hw, 2 ))
228 val.i_int = AOUT_VAR_STEREO;
229 text.psz_string = (char*)N_("Stereo");
230 var_Change( p_aout, "audio-device",
231 VLC_VAR_ADDCHOICE, &val, &text );
232 var_Set( p_aout, "audio-device", val );
236 /* Close the previously opened device */
237 snd_pcm_close( p_sys->p_snd_pcm );
239 else if ( i_ret == -EBUSY )
241 msg_Warn( p_aout, "audio device: %s is already in use", psz_device );
244 /* Test for S/PDIF device if needed */
245 if ( psz_iec_device )
247 /* Opening the device should be enough */
248 if ( !(i_ret = snd_pcm_open( &p_sys->p_snd_pcm, psz_iec_device,
249 SND_PCM_STREAM_PLAYBACK,
250 SND_PCM_NONBLOCK ) ) )
252 val.i_int = AOUT_VAR_SPDIF;
253 text.psz_string = (char*)N_("A/52 over S/PDIF");
254 var_Change( p_aout, "audio-device",
255 VLC_VAR_ADDCHOICE, &val, &text );
256 if( var_InheritInteger( p_aout, "spdif" ) )
257 var_Set( p_aout, "audio-device", val );
259 snd_pcm_close( p_sys->p_snd_pcm );
261 else if ( i_ret == -EBUSY )
263 msg_Warn( p_aout, "audio device: %s is already in use",
268 var_Change( p_aout, "audio-device", VLC_VAR_CHOICESCOUNT, &val, NULL );
269 #if (SND_LIB_VERSION <= 0x010015)
270 # warning Please update alsa-lib to version > 1.0.21a.
271 var_Create( p_aout->p_libvlc, "alsa-working", VLC_VAR_BOOL );
274 if( var_GetBool( p_aout->p_libvlc, "alsa-working" ) )
275 dialog_FatalWait( p_aout, "ALSA version problem",
276 "VLC failed to re-initialize your sound output device.\n"
277 "Please update alsa-lib to version 1.0.22 or higher "
278 "to fix this issue." );
281 var_SetBool( p_aout->p_libvlc, "alsa-working", true );
285 /* Probe() has failed. */
286 msg_Dbg( p_aout, "failed to find a usable ALSA configuration" );
287 var_Destroy( p_aout, "audio-device" );
288 GetDevices( VLC_OBJECT(p_aout), NULL );
292 /* Add final settings to the variable */
293 var_AddCallback( p_aout, "audio-device", aout_ChannelsRestart, NULL );
294 var_SetBool( p_aout, "intf-change", true );
297 /*****************************************************************************
298 * Open: create a handle and open an alsa device
299 *****************************************************************************
300 * This function opens an alsa device, through the alsa API.
302 * Note: the only heap-allocated string is psz_device. All the other pointers
303 * are references to psz_device or to stack-allocated data.
304 *****************************************************************************/
305 static int Open( vlc_object_t *p_this )
307 aout_instance_t * p_aout = (aout_instance_t *)p_this;
308 struct aout_sys_t * p_sys;
311 char psz_default_iec_device[128]; /* Buffer used to store the default
313 char * psz_device, * psz_iec_device; /* device names for PCM and S/PDIF
316 int i_vlc_pcm_format; /* Audio format for VLC's data */
317 int i_snd_pcm_format; /* Audio format for ALSA's data */
319 snd_pcm_uframes_t i_buffer_size = 0;
320 snd_pcm_uframes_t i_period_size = 0;
323 snd_pcm_hw_params_t *p_hw;
324 snd_pcm_sw_params_t *p_sw;
327 unsigned int i_old_rate;
330 /* Allocate structures */
331 p_aout->output.p_sys = p_sys = malloc( sizeof( aout_sys_t ) );
335 /* Get device name */
336 if( (psz_device = var_InheritString( p_aout, "alsa-audio-device" )) == NULL )
338 msg_Err( p_aout, "no audio device given (maybe \"default\" ?)" );
339 dialog_Fatal( p_aout, _("No Audio Device"), "%s",
340 _("No audio device name was given. You might want to " \
341 "enter \"default\".") );
346 /* Choose the IEC device for S/PDIF output:
347 if the device is overriden by the user then it will be the one
348 otherwise we compute the default device based on the output format. */
349 if( AOUT_FMT_NON_LINEAR( &p_aout->output.output )
350 && !strcmp( psz_device, DEFAULT_ALSA_DEVICE ) )
352 snprintf( psz_default_iec_device, sizeof(psz_default_iec_device),
353 "iec958:AES0=0x%x,AES1=0x%x,AES2=0x%x,AES3=0x%x",
354 IEC958_AES0_CON_EMPHASIS_NONE | IEC958_AES0_NONAUDIO,
355 IEC958_AES1_CON_ORIGINAL | IEC958_AES1_CON_PCM_CODER,
357 ( p_aout->output.output.i_rate == 48000 ?
358 IEC958_AES3_CON_FS_48000 :
359 ( p_aout->output.output.i_rate == 44100 ?
360 IEC958_AES3_CON_FS_44100 : IEC958_AES3_CON_FS_32000 ) ) );
361 psz_iec_device = psz_default_iec_device;
363 else if( AOUT_FMT_NON_LINEAR( &p_aout->output.output ) )
365 psz_iec_device = psz_device;
369 psz_iec_device = NULL;
372 /* Choose the linear PCM format (read the comment above about FPU
376 i_vlc_pcm_format = VLC_CODEC_FL32;
377 i_snd_pcm_format = SND_PCM_FORMAT_FLOAT;
381 i_vlc_pcm_format = VLC_CODEC_S16N;
382 i_snd_pcm_format = SND_PCM_FORMAT_S16;
385 /* If the variable doesn't exist then it's the first time we're called
386 and we have to probe the available audio formats and channels */
387 if ( var_Type( p_aout, "audio-device" ) == 0 )
389 Probe( p_aout, psz_device, psz_iec_device, &i_snd_pcm_format );
392 if ( var_Get( p_aout, "audio-device", &val ) < 0 )
399 p_aout->output.output.i_format = i_vlc_pcm_format;
400 if ( val.i_int == AOUT_VAR_5_1 )
402 p_aout->output.output.i_physical_channels
403 = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER
404 | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT
407 psz_device = strdup( "surround51" );
409 else if ( val.i_int == AOUT_VAR_2F2R )
411 p_aout->output.output.i_physical_channels
412 = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT
413 | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT;
415 psz_device = strdup( "surround40" );
417 else if ( val.i_int == AOUT_VAR_STEREO )
419 p_aout->output.output.i_physical_channels
420 = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT;
422 else if ( val.i_int == AOUT_VAR_MONO )
424 p_aout->output.output.i_physical_channels = AOUT_CHAN_CENTER;
426 else if( val.i_int != AOUT_VAR_SPDIF )
428 /* This should not happen ! */
429 msg_Err( p_aout, "internal: can't find audio-device (%i)", val.i_int );
436 snd_output_stdio_attach( &p_sys->p_snd_stderr, stderr, 0 );
439 /* Open the device */
440 if ( val.i_int == AOUT_VAR_SPDIF )
442 if ( ( i_snd_rc = snd_pcm_open( &p_sys->p_snd_pcm, psz_iec_device,
443 SND_PCM_STREAM_PLAYBACK, 0 ) ) < 0 )
445 msg_Err( p_aout, "cannot open ALSA device `%s' (%s)",
446 psz_iec_device, snd_strerror( i_snd_rc ) );
447 dialog_Fatal( p_aout, _("Audio output failed"),
448 _("VLC could not open the ALSA device \"%s\" (%s)."),
449 psz_iec_device, snd_strerror( i_snd_rc ) );
454 i_buffer_size = ALSA_SPDIF_BUFFER_SIZE;
455 i_snd_pcm_format = SND_PCM_FORMAT_S16;
458 i_vlc_pcm_format = VLC_CODEC_SPDIFL;
459 p_aout->output.i_nb_samples = i_period_size = ALSA_SPDIF_PERIOD_SIZE;
460 p_aout->output.output.i_bytes_per_frame = AOUT_SPDIF_SIZE;
461 p_aout->output.output.i_frame_length = A52_FRAME_NB;
463 aout_VolumeNoneInit( p_aout );
469 msg_Dbg( p_aout, "opening ALSA device `%s'", psz_device );
471 /* Since it seems snd_pcm_close hasn't really released the device at
472 the time it returns, probe if the device is available in loop for 1s.
473 We cannot use blocking mode since the we would wait indefinitely when
474 switching from a dmx device to surround51. */
476 for( i = 10; i >= 0; i-- )
478 if ( ( i_snd_rc = snd_pcm_open( &p_sys->p_snd_pcm, psz_device,
479 SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK ) ) == -EBUSY )
481 if( i ) msleep( 100000 /* 100ms */ );
484 msg_Err( p_aout, "audio device: %s is already in use",
486 dialog_Fatal( p_aout, _("Audio output failed"),
487 _("The audio device \"%s\" is already in use."),
496 msg_Err( p_aout, "cannot open ALSA device `%s' (%s)",
497 psz_device, snd_strerror( i_snd_rc ) );
498 dialog_Fatal( p_aout, _("Audio output failed"),
499 _("VLC could not open the ALSA device \"%s\" (%s)."),
500 psz_device, snd_strerror( i_snd_rc ) );
506 /* We want blocking mode */
507 snd_pcm_nonblock( p_sys->p_snd_pcm, 0 );
509 i_buffer_size = ALSA_DEFAULT_BUFFER_SIZE;
510 i_channels = aout_FormatNbChannels( &p_aout->output.output );
512 p_aout->output.i_nb_samples = i_period_size = ALSA_DEFAULT_PERIOD_SIZE;
514 aout_VolumeSoftInit( p_aout );
517 /* Free psz_device so that all the remaining data is stack-allocated */
520 p_aout->output.pf_play = Play;
522 snd_pcm_hw_params_alloca(&p_hw);
523 snd_pcm_sw_params_alloca(&p_sw);
525 /* Due to some bugs in alsa with some drivers, we need to retry in s16l
526 if snd_pcm_hw_params fails in fl32 */
531 /* Get Initial hardware parameters */
532 if ( ( i_snd_rc = snd_pcm_hw_params_any( p_sys->p_snd_pcm, p_hw ) ) < 0 )
534 msg_Err( p_aout, "unable to retrieve initial hardware parameters (%s)",
535 snd_strerror( i_snd_rc ) );
540 if ( ( i_snd_rc = snd_pcm_hw_params_set_format( p_sys->p_snd_pcm, p_hw,
541 i_snd_pcm_format ) ) < 0 )
543 if( i_snd_pcm_format != SND_PCM_FORMAT_S16 )
545 i_snd_pcm_format = SND_PCM_FORMAT_S16;
546 i_snd_rc = snd_pcm_hw_params_set_format( p_sys->p_snd_pcm,
547 p_hw, i_snd_pcm_format );
551 msg_Err( p_aout, "unable to set stream sample size and "
552 "word order (%s)", snd_strerror( i_snd_rc ) );
556 if( i_vlc_pcm_format != VLC_CODEC_SPDIFL )
557 switch( i_snd_pcm_format )
559 case SND_PCM_FORMAT_FLOAT:
560 i_vlc_pcm_format = VLC_CODEC_FL32;
562 case SND_PCM_FORMAT_S16:
563 i_vlc_pcm_format = VLC_CODEC_S16N;
566 p_aout->output.output.i_format = i_vlc_pcm_format;
568 if ( ( i_snd_rc = snd_pcm_hw_params_set_access( p_sys->p_snd_pcm, p_hw,
569 SND_PCM_ACCESS_RW_INTERLEAVED ) ) < 0 )
571 msg_Err( p_aout, "unable to set interleaved stream format (%s)",
572 snd_strerror( i_snd_rc ) );
577 if ( ( i_snd_rc = snd_pcm_hw_params_set_channels( p_sys->p_snd_pcm, p_hw,
580 msg_Err( p_aout, "unable to set number of output channels (%s)",
581 snd_strerror( i_snd_rc ) );
586 i_old_rate = p_aout->output.output.i_rate;
587 i_snd_rc = snd_pcm_hw_params_set_rate_near( p_sys->p_snd_pcm, p_hw,
588 &p_aout->output.output.i_rate,
590 if( i_snd_rc < 0 || p_aout->output.output.i_rate != i_old_rate )
592 msg_Warn( p_aout, "The rate %d Hz is not supported by your " \
593 "hardware. Using %d Hz instead.\n", i_old_rate, \
594 p_aout->output.output.i_rate );
597 /* Set period size. */
598 if ( ( i_snd_rc = snd_pcm_hw_params_set_period_size_near( p_sys->p_snd_pcm,
599 p_hw, &i_period_size, NULL ) ) < 0 )
601 msg_Err( p_aout, "unable to set period size (%s)",
602 snd_strerror( i_snd_rc ) );
605 p_aout->output.i_nb_samples = i_period_size;
607 /* Set buffer size. */
608 if ( ( i_snd_rc = snd_pcm_hw_params_set_buffer_size_near( p_sys->p_snd_pcm,
609 p_hw, &i_buffer_size ) ) < 0 )
611 msg_Err( p_aout, "unable to set buffer size (%s)",
612 snd_strerror( i_snd_rc ) );
616 /* Commit hardware parameters. */
617 if ( ( i_snd_rc = snd_pcm_hw_params( p_sys->p_snd_pcm, p_hw ) ) < 0 )
619 if ( b_retry == false &&
620 i_snd_pcm_format == SND_PCM_FORMAT_FLOAT)
623 i_snd_pcm_format = SND_PCM_FORMAT_S16;
624 p_aout->output.output.i_format = VLC_CODEC_S16N;
625 msg_Warn( p_aout, "unable to commit hardware configuration "
626 "with fl32 samples. Retrying with s16l (%s)", snd_strerror( i_snd_rc ) );
630 msg_Err( p_aout, "unable to commit hardware configuration (%s)",
631 snd_strerror( i_snd_rc ) );
637 if( ( i_snd_rc = snd_pcm_hw_params_get_period_time( p_hw,
638 &p_sys->i_period_time, NULL ) ) < 0 )
640 msg_Err( p_aout, "unable to get period time (%s)",
641 snd_strerror( i_snd_rc ) );
645 /* Get Initial software parameters */
646 snd_pcm_sw_params_current( p_sys->p_snd_pcm, p_sw );
648 i_snd_rc = snd_pcm_sw_params_set_sleep_min( p_sys->p_snd_pcm, p_sw, 0 );
650 i_snd_rc = snd_pcm_sw_params_set_avail_min( p_sys->p_snd_pcm, p_sw,
651 p_aout->output.i_nb_samples );
652 /* start playing when one period has been written */
653 i_snd_rc = snd_pcm_sw_params_set_start_threshold( p_sys->p_snd_pcm, p_sw,
654 ALSA_DEFAULT_PERIOD_SIZE);
657 msg_Err( p_aout, "unable to set start threshold (%s)",
658 snd_strerror( i_snd_rc ) );
662 /* Commit software parameters. */
663 if ( snd_pcm_sw_params( p_sys->p_snd_pcm, p_sw ) < 0 )
665 msg_Err( p_aout, "unable to set software configuration" );
670 snd_output_printf( p_sys->p_snd_stderr, "\nALSA hardware setup:\n\n" );
671 snd_pcm_dump_hw_setup( p_sys->p_snd_pcm, p_sys->p_snd_stderr );
672 snd_output_printf( p_sys->p_snd_stderr, "\nALSA software setup:\n\n" );
673 snd_pcm_dump_sw_setup( p_sys->p_snd_pcm, p_sys->p_snd_stderr );
674 snd_output_printf( p_sys->p_snd_stderr, "\n" );
677 p_sys->start_date = 0;
678 vlc_sem_init( &p_sys->wait, 0 );
680 /* Create ALSA thread and wait for its readiness. */
681 if( vlc_clone( &p_sys->thread, ALSAThread, p_aout,
682 VLC_THREAD_PRIORITY_OUTPUT ) )
684 msg_Err( p_aout, "cannot create ALSA thread (%m)" );
685 vlc_sem_destroy( &p_sys->wait );
692 snd_pcm_close( p_sys->p_snd_pcm );
694 snd_output_close( p_sys->p_snd_stderr );
700 static void PlayIgnore( aout_instance_t *p_aout )
701 { /* Already playing - nothing to do */
705 /*****************************************************************************
706 * Play: start playback
707 *****************************************************************************/
708 static void Play( aout_instance_t *p_aout )
710 p_aout->output.pf_play = PlayIgnore;
712 /* get the playing date of the first aout buffer */
713 p_aout->output.p_sys->start_date =
714 aout_FifoFirstDate( p_aout, &p_aout->output.fifo );
716 /* wake up the audio output thread */
717 sem_post( &p_aout->output.p_sys->wait );
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 that the thread will stop once it is waken up */
730 vlc_cancel( p_sys->thread );
731 vlc_join( p_sys->thread, NULL );
732 vlc_sem_destroy( &p_sys->wait );
735 i_snd_rc = snd_pcm_close( p_sys->p_snd_pcm );
739 msg_Err( p_aout, "failed closing ALSA device (%s)",
740 snd_strerror( i_snd_rc ) );
744 snd_output_close( p_sys->p_snd_stderr );
750 static void pcm_drop(void *pcm)
755 /*****************************************************************************
756 * ALSAThread: asynchronous thread used to DMA the data to the device
757 *****************************************************************************/
758 static void* ALSAThread( void *data )
760 aout_instance_t * p_aout = data;
761 struct aout_sys_t * p_sys = p_aout->output.p_sys;
763 /* Wait for the exact time to start playing (avoids resampling) */
764 vlc_sem_wait( &p_sys->wait );
765 mwait( p_sys->start_date - AOUT_PTS_TOLERANCE / 4 );
767 vlc_cleanup_push( pcm_drop, p_sys->p_snd_pcm );
775 /*****************************************************************************
776 * ALSAFill: function used to fill the ALSA buffer as much as possible
777 *****************************************************************************/
778 static void ALSAFill( aout_instance_t * p_aout )
780 struct aout_sys_t * p_sys = p_aout->output.p_sys;
781 snd_pcm_t *p_pcm = p_sys->p_snd_pcm;
782 snd_pcm_status_t * p_status;
786 int canc = vlc_savecancel();
787 /* Fill in the buffer until space or audio output buffer shortage */
790 snd_pcm_status_alloca(&p_status);
791 i_snd_rc = snd_pcm_status( p_pcm, p_status );
794 msg_Err( p_aout, "cannot get device status" );
798 /* Handle buffer underruns and get the status again */
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_pcm );
805 msg_Err( p_aout, "cannot recover from buffer underrun" );
809 msg_Dbg( p_aout, "recovered from buffer underrun" );
811 /* Get the new status */
812 i_snd_rc = snd_pcm_status( p_pcm, p_status );
815 msg_Err( p_aout, "cannot get device status after recovery" );
819 /* Underrun, try to recover as quickly as possible */
824 /* Here the device should be in RUNNING state, p_status is valid. */
825 snd_pcm_sframes_t delay = snd_pcm_status_get_delay( p_status );
826 if( delay == 0 ) /* workaround buggy alsa drivers */
827 if( snd_pcm_delay( p_pcm, &delay ) < 0 )
828 delay = 0; /* FIXME: use a positive minimal delay */
830 size_t i_bytes = snd_pcm_frames_to_bytes( p_pcm, delay );
831 mtime_t delay_us = CLOCK_FREQ * i_bytes
832 / p_aout->output.output.i_bytes_per_frame
833 / p_aout->output.output.i_rate
834 * p_aout->output.output.i_frame_length;
837 snd_pcm_state_t state = snd_pcm_status_get_state( p_status );
838 if( state != SND_PCM_STATE_RUNNING )
839 msg_Err( p_aout, "pcm status (%d) != RUNNING", state );
841 msg_Dbg( p_aout, "Delay is %ld frames (%zu bytes)", delay, i_bytes );
843 msg_Dbg( p_aout, "Bytes per frame: %d", p_aout->output.output.i_bytes_per_frame );
844 msg_Dbg( p_aout, "Rate: %d", p_aout->output.output.i_rate );
845 msg_Dbg( p_aout, "Frame length: %d", p_aout->output.output.i_frame_length );
846 msg_Dbg( p_aout, "Next date: in %"PRId64" microseconds", delay_us );
848 next_date = mdate() + delay_us;
851 block_t *p_buffer = aout_OutputNextBuffer( p_aout, next_date,
852 (p_aout->output.output.i_format == VLC_CODEC_SPDIFL) );
854 /* Audio output buffer shortage -> stop the fill process and wait */
855 if( p_buffer == NULL )
860 int n = snd_pcm_poll_descriptors_count(p_pcm);
861 struct pollfd ufd[n];
862 unsigned short revents;
864 snd_pcm_poll_descriptors(p_pcm, ufd, n);
867 vlc_restorecancel(canc);
869 canc = vlc_savecancel();
870 snd_pcm_poll_descriptors_revents(p_pcm, ufd, n, &revents);
874 if(revents & POLLOUT)
876 i_snd_rc = snd_pcm_writei( p_pcm, p_buffer->p_buffer,
877 p_buffer->i_nb_samples );
878 if( i_snd_rc != -ESTRPIPE )
882 /* a suspend event occurred
883 * (stream is suspended and waiting for an application recovery) */
884 msg_Dbg( p_aout, "entering in suspend mode, trying to resume..." );
886 while( ( i_snd_rc = snd_pcm_resume( p_pcm ) ) == -EAGAIN )
888 vlc_restorecancel(canc);
889 msleep(CLOCK_FREQ); /* device still suspended, wait... */
890 canc = vlc_savecancel();
894 /* Device does not support resuming, restart it */
895 i_snd_rc = snd_pcm_prepare( p_pcm );
900 msg_Err( p_aout, "cannot write: %s", snd_strerror( i_snd_rc ) );
902 vlc_restorecancel(canc);
903 block_Release( p_buffer );
908 msg_Err( p_aout, "ALSA error: %s", snd_strerror( i_snd_rc ) );
910 vlc_restorecancel(canc);
911 msleep(p_sys->i_period_time / 2);
914 /*****************************************************************************
915 * config variable callback
916 *****************************************************************************/
917 static int FindDevicesCallback( vlc_object_t *p_this, char const *psz_name,
918 vlc_value_t newval, vlc_value_t oldval, void *p_unused )
920 module_config_t *p_item;
925 p_item = config_FindConfig( p_this, psz_name );
926 if( !p_item ) return VLC_SUCCESS;
928 /* Clear-up the current list */
933 /* Keep the first entrie */
934 for( i = 1; i < p_item->i_list; i++ )
936 free( (char *)p_item->ppsz_list[i] );
937 free( (char *)p_item->ppsz_list_text[i] );
939 /* TODO: Remove when no more needed */
940 p_item->ppsz_list[i] = NULL;
941 p_item->ppsz_list_text[i] = NULL;
945 GetDevices( p_this, p_item );
947 /* Signal change to the interface */
948 p_item->b_dirty = true;
954 static void GetDevicesForCard( vlc_object_t *obj, module_config_t *p_item,
957 int i_pcm_device = -1;
959 snd_pcm_info_t *p_pcm_info;
964 sprintf( psz_dev, "hw:%i", i_card );
966 if( ( i_err = snd_ctl_open( &p_ctl, psz_dev, 0 ) ) < 0 )
969 if( ( i_err = snd_card_get_name( i_card, &psz_card_name ) ) != 0)
970 psz_card_name = _("Unknown soundcard");
972 snd_pcm_info_alloca( &p_pcm_info );
976 char *psz_device, *psz_descr;
977 if( ( i_err = snd_ctl_pcm_next_device( p_ctl, &i_pcm_device ) ) < 0 )
979 if( i_pcm_device < 0 )
982 snd_pcm_info_set_device( p_pcm_info, i_pcm_device );
983 snd_pcm_info_set_subdevice( p_pcm_info, 0 );
984 snd_pcm_info_set_stream( p_pcm_info, SND_PCM_STREAM_PLAYBACK );
986 if( ( i_err = snd_ctl_pcm_info( p_ctl, p_pcm_info ) ) < 0 )
988 if( i_err != -ENOENT )
989 msg_Err( obj, "cannot get PCM device %d:%d infos: %s", i_card,
990 i_pcm_device, snd_strerror( -i_err ) );
994 if( asprintf( &psz_device, "hw:%d,%d", i_card, i_pcm_device ) == -1 )
996 if( asprintf( &psz_descr, "%s: %s (%s)", psz_card_name,
997 snd_pcm_info_get_name(p_pcm_info), psz_device ) == -1 )
1003 msg_Dbg( obj, " %s", psz_descr );
1007 p_item->ppsz_list = xrealloc( p_item->ppsz_list,
1008 (p_item->i_list + 2) * sizeof(char *) );
1009 p_item->ppsz_list_text = xrealloc( p_item->ppsz_list_text,
1010 (p_item->i_list + 2) * sizeof(char *) );
1011 p_item->ppsz_list[ p_item->i_list ] = psz_device;
1012 p_item->ppsz_list_text[ p_item->i_list ] = psz_descr;
1014 p_item->ppsz_list[ p_item->i_list ] = NULL;
1015 p_item->ppsz_list_text[ p_item->i_list ] = NULL;
1024 snd_ctl_close( p_ctl );
1028 static void GetDevices( vlc_object_t *obj, module_config_t *p_item )
1033 msg_Dbg( obj, "Available alsa output devices:" );
1034 while( (i_err = snd_card_next( &i_card )) == 0 && i_card > -1 )
1035 GetDevicesForCard( obj, p_item, i_card );
1038 msg_Err( obj, "cannot enumerate cards: %s", snd_strerror( -i_err ) );