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>
45 #include <vlc_memory.h>
48 Note: we use the new API which is available since 0.9.0beta10a. */
49 #define ALSA_PCM_NEW_HW_PARAMS_API
50 #define ALSA_PCM_NEW_SW_PARAMS_API
51 #include <alsa/asoundlib.h>
52 #include <alsa/version.h>
54 /*#define ALSA_DEBUG*/
56 /*****************************************************************************
57 * aout_sys_t: ALSA audio output method descriptor
58 *****************************************************************************
59 * This structure is part of the audio output thread descriptor.
60 * It describes the ALSA specific properties of an audio device.
61 *****************************************************************************/
64 snd_pcm_t * p_snd_pcm;
65 unsigned int i_period_time;
68 snd_output_t * p_snd_stderr;
76 #define A52_FRAME_NB 1536
78 /* These values are in frames.
79 To convert them to a number of bytes you have to multiply them by the
80 number of channel(s) (eg. 2 for stereo) and the size of a sample (eg.
82 #define ALSA_DEFAULT_PERIOD_SIZE 1024
83 #define ALSA_DEFAULT_BUFFER_SIZE ( ALSA_DEFAULT_PERIOD_SIZE << 8 )
84 #define ALSA_SPDIF_PERIOD_SIZE A52_FRAME_NB
85 #define ALSA_SPDIF_BUFFER_SIZE ( ALSA_SPDIF_PERIOD_SIZE << 4 )
86 /* Why << 4 ? --Meuuh */
87 /* Why not ? --Bozo */
90 #define DEFAULT_ALSA_DEVICE N_("default")
92 /*****************************************************************************
94 *****************************************************************************/
95 static int Open ( vlc_object_t * );
96 static void Close ( vlc_object_t * );
97 static void Play ( aout_instance_t * );
98 static void* ALSAThread ( void * );
99 static void ALSAFill ( aout_instance_t * );
100 static int FindDevicesCallback( vlc_object_t *p_this, char const *psz_name,
101 vlc_value_t newval, vlc_value_t oldval, void *p_unused );
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( config_GetInt( 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" );
291 /* Add final settings to the variable */
292 var_AddCallback( p_aout, "audio-device", aout_ChannelsRestart, NULL );
293 var_SetBool( p_aout, "intf-change", true );
296 /*****************************************************************************
297 * Open: create a handle and open an alsa device
298 *****************************************************************************
299 * This function opens an alsa device, through the alsa API.
301 * Note: the only heap-allocated string is psz_device. All the other pointers
302 * are references to psz_device or to stack-allocated data.
303 *****************************************************************************/
304 static int Open( vlc_object_t *p_this )
306 aout_instance_t * p_aout = (aout_instance_t *)p_this;
307 struct aout_sys_t * p_sys;
310 char psz_default_iec_device[128]; /* Buffer used to store the default
312 char * psz_device, * psz_iec_device; /* device names for PCM and S/PDIF
315 int i_vlc_pcm_format; /* Audio format for VLC's data */
316 int i_snd_pcm_format; /* Audio format for ALSA's data */
318 snd_pcm_uframes_t i_buffer_size = 0;
319 snd_pcm_uframes_t i_period_size = 0;
322 snd_pcm_hw_params_t *p_hw;
323 snd_pcm_sw_params_t *p_sw;
326 unsigned int i_old_rate;
329 /* Allocate structures */
330 p_aout->output.p_sys = p_sys = malloc( sizeof( aout_sys_t ) );
334 /* Get device name */
335 if( (psz_device = config_GetPsz( p_aout, "alsa-audio-device" )) == NULL )
337 msg_Err( p_aout, "no audio device given (maybe \"default\" ?)" );
338 dialog_Fatal( p_aout, _("No Audio Device"), "%s",
339 _("No audio device name was given. You might want to " \
340 "enter \"default\".") );
345 /* Choose the IEC device for S/PDIF output:
346 if the device is overriden by the user then it will be the one
347 otherwise we compute the default device based on the output format. */
348 if( AOUT_FMT_NON_LINEAR( &p_aout->output.output )
349 && !strcmp( psz_device, DEFAULT_ALSA_DEVICE ) )
351 snprintf( psz_default_iec_device, sizeof(psz_default_iec_device),
352 "iec958:AES0=0x%x,AES1=0x%x,AES2=0x%x,AES3=0x%x",
353 IEC958_AES0_CON_EMPHASIS_NONE | IEC958_AES0_NONAUDIO,
354 IEC958_AES1_CON_ORIGINAL | IEC958_AES1_CON_PCM_CODER,
356 ( p_aout->output.output.i_rate == 48000 ?
357 IEC958_AES3_CON_FS_48000 :
358 ( p_aout->output.output.i_rate == 44100 ?
359 IEC958_AES3_CON_FS_44100 : IEC958_AES3_CON_FS_32000 ) ) );
360 psz_iec_device = psz_default_iec_device;
362 else if( AOUT_FMT_NON_LINEAR( &p_aout->output.output ) )
364 psz_iec_device = psz_device;
368 psz_iec_device = NULL;
371 /* Choose the linear PCM format (read the comment above about FPU
375 i_vlc_pcm_format = VLC_CODEC_FL32;
376 i_snd_pcm_format = SND_PCM_FORMAT_FLOAT;
380 i_vlc_pcm_format = VLC_CODEC_S16N;
381 i_snd_pcm_format = SND_PCM_FORMAT_S16;
384 /* If the variable doesn't exist then it's the first time we're called
385 and we have to probe the available audio formats and channels */
386 if ( var_Type( p_aout, "audio-device" ) == 0 )
388 Probe( p_aout, psz_device, psz_iec_device, &i_snd_pcm_format );
391 if ( var_Get( p_aout, "audio-device", &val ) < 0 )
398 p_aout->output.output.i_format = i_vlc_pcm_format;
399 if ( val.i_int == AOUT_VAR_5_1 )
401 p_aout->output.output.i_physical_channels
402 = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER
403 | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT
406 psz_device = strdup( "surround51" );
408 else if ( val.i_int == AOUT_VAR_2F2R )
410 p_aout->output.output.i_physical_channels
411 = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT
412 | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT;
414 psz_device = strdup( "surround40" );
416 else if ( val.i_int == AOUT_VAR_STEREO )
418 p_aout->output.output.i_physical_channels
419 = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT;
421 else if ( val.i_int == AOUT_VAR_MONO )
423 p_aout->output.output.i_physical_channels = AOUT_CHAN_CENTER;
425 else if( val.i_int != AOUT_VAR_SPDIF )
427 /* This should not happen ! */
428 msg_Err( p_aout, "internal: can't find audio-device (%i)", val.i_int );
435 snd_output_stdio_attach( &p_sys->p_snd_stderr, stderr, 0 );
438 /* Open the device */
439 if ( val.i_int == AOUT_VAR_SPDIF )
441 if ( ( i_snd_rc = snd_pcm_open( &p_sys->p_snd_pcm, psz_iec_device,
442 SND_PCM_STREAM_PLAYBACK, 0 ) ) < 0 )
444 msg_Err( p_aout, "cannot open ALSA device `%s' (%s)",
445 psz_iec_device, snd_strerror( i_snd_rc ) );
446 dialog_Fatal( p_aout, _("Audio output failed"),
447 _("VLC could not open the ALSA device \"%s\" (%s)."),
448 psz_iec_device, snd_strerror( i_snd_rc ) );
453 i_buffer_size = ALSA_SPDIF_BUFFER_SIZE;
454 i_snd_pcm_format = SND_PCM_FORMAT_S16;
457 i_vlc_pcm_format = VLC_CODEC_SPDIFL;
458 p_aout->output.i_nb_samples = i_period_size = ALSA_SPDIF_PERIOD_SIZE;
459 p_aout->output.output.i_bytes_per_frame = AOUT_SPDIF_SIZE;
460 p_aout->output.output.i_frame_length = A52_FRAME_NB;
462 aout_VolumeNoneInit( p_aout );
468 msg_Dbg( p_aout, "opening ALSA device `%s'", psz_device );
470 /* Since it seems snd_pcm_close hasn't really released the device at
471 the time it returns, probe if the device is available in loop for 1s.
472 We cannot use blocking mode since the we would wait indefinitely when
473 switching from a dmx device to surround51. */
475 for( i = 10; i >= 0; i-- )
477 if ( ( i_snd_rc = snd_pcm_open( &p_sys->p_snd_pcm, psz_device,
478 SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK ) ) == -EBUSY )
480 if( i ) msleep( 100000 /* 100ms */ );
483 msg_Err( p_aout, "audio device: %s is already in use",
485 dialog_Fatal( p_aout, _("Audio output failed"),
486 _("The audio device \"%s\" is already in use."),
495 msg_Err( p_aout, "cannot open ALSA device `%s' (%s)",
496 psz_device, snd_strerror( i_snd_rc ) );
497 dialog_Fatal( p_aout, _("Audio output failed"),
498 _("VLC could not open the ALSA device \"%s\" (%s)."),
499 psz_device, snd_strerror( i_snd_rc ) );
505 /* We want blocking mode */
506 snd_pcm_nonblock( p_sys->p_snd_pcm, 0 );
508 i_buffer_size = ALSA_DEFAULT_BUFFER_SIZE;
509 i_channels = aout_FormatNbChannels( &p_aout->output.output );
511 p_aout->output.i_nb_samples = i_period_size = ALSA_DEFAULT_PERIOD_SIZE;
513 aout_VolumeSoftInit( p_aout );
516 /* Free psz_device so that all the remaining data is stack-allocated */
519 p_aout->output.pf_play = Play;
521 snd_pcm_hw_params_alloca(&p_hw);
522 snd_pcm_sw_params_alloca(&p_sw);
524 /* Due to some bugs in alsa with some drivers, we need to retry in s16l
525 if snd_pcm_hw_params fails in fl32 */
530 /* Get Initial hardware parameters */
531 if ( ( i_snd_rc = snd_pcm_hw_params_any( p_sys->p_snd_pcm, p_hw ) ) < 0 )
533 msg_Err( p_aout, "unable to retrieve initial hardware parameters (%s)",
534 snd_strerror( i_snd_rc ) );
539 if ( ( i_snd_rc = snd_pcm_hw_params_set_format( p_sys->p_snd_pcm, p_hw,
540 i_snd_pcm_format ) ) < 0 )
542 if( i_snd_pcm_format != SND_PCM_FORMAT_S16 )
544 i_snd_pcm_format = SND_PCM_FORMAT_S16;
545 i_snd_rc = snd_pcm_hw_params_set_format( p_sys->p_snd_pcm,
546 p_hw, i_snd_pcm_format );
550 msg_Err( p_aout, "unable to set stream sample size and "
551 "word order (%s)", snd_strerror( i_snd_rc ) );
555 if( i_vlc_pcm_format != VLC_CODEC_SPDIFL )
556 switch( i_snd_pcm_format )
558 case SND_PCM_FORMAT_FLOAT:
559 i_vlc_pcm_format = VLC_CODEC_FL32;
561 case SND_PCM_FORMAT_S16:
562 i_vlc_pcm_format = VLC_CODEC_S16N;
565 p_aout->output.output.i_format = i_vlc_pcm_format;
567 if ( ( i_snd_rc = snd_pcm_hw_params_set_access( p_sys->p_snd_pcm, p_hw,
568 SND_PCM_ACCESS_RW_INTERLEAVED ) ) < 0 )
570 msg_Err( p_aout, "unable to set interleaved stream format (%s)",
571 snd_strerror( i_snd_rc ) );
576 if ( ( i_snd_rc = snd_pcm_hw_params_set_channels( p_sys->p_snd_pcm, p_hw,
579 msg_Err( p_aout, "unable to set number of output channels (%s)",
580 snd_strerror( i_snd_rc ) );
585 i_old_rate = p_aout->output.output.i_rate;
586 i_snd_rc = snd_pcm_hw_params_set_rate_near( p_sys->p_snd_pcm, p_hw,
587 &p_aout->output.output.i_rate,
589 if( i_snd_rc < 0 || p_aout->output.output.i_rate != i_old_rate )
591 msg_Warn( p_aout, "The rate %d Hz is not supported by your " \
592 "hardware. Using %d Hz instead.\n", i_old_rate, \
593 p_aout->output.output.i_rate );
596 /* Set period size. */
597 if ( ( i_snd_rc = snd_pcm_hw_params_set_period_size_near( p_sys->p_snd_pcm,
598 p_hw, &i_period_size, NULL ) ) < 0 )
600 msg_Err( p_aout, "unable to set period size (%s)",
601 snd_strerror( i_snd_rc ) );
604 p_aout->output.i_nb_samples = i_period_size;
606 /* Set buffer size. */
607 if ( ( i_snd_rc = snd_pcm_hw_params_set_buffer_size_near( p_sys->p_snd_pcm,
608 p_hw, &i_buffer_size ) ) < 0 )
610 msg_Err( p_aout, "unable to set buffer size (%s)",
611 snd_strerror( i_snd_rc ) );
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 == 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 = VLC_CODEC_S16N;
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 if( ( i_snd_rc = snd_pcm_hw_params_get_period_time( p_hw,
637 &p_sys->i_period_time, NULL ) ) < 0 )
639 msg_Err( p_aout, "unable to get period time (%s)",
640 snd_strerror( i_snd_rc ) );
644 /* Get Initial software parameters */
645 snd_pcm_sw_params_current( p_sys->p_snd_pcm, p_sw );
647 i_snd_rc = snd_pcm_sw_params_set_sleep_min( p_sys->p_snd_pcm, p_sw, 0 );
649 i_snd_rc = snd_pcm_sw_params_set_avail_min( p_sys->p_snd_pcm, p_sw,
650 p_aout->output.i_nb_samples );
651 /* start playing when one period has been written */
652 i_snd_rc = snd_pcm_sw_params_set_start_threshold( p_sys->p_snd_pcm, p_sw,
653 ALSA_DEFAULT_PERIOD_SIZE);
656 msg_Err( p_aout, "unable to set start threshold (%s)",
657 snd_strerror( i_snd_rc ) );
661 /* Commit software parameters. */
662 if ( snd_pcm_sw_params( p_sys->p_snd_pcm, p_sw ) < 0 )
664 msg_Err( p_aout, "unable to set software configuration" );
669 snd_output_printf( p_sys->p_snd_stderr, "\nALSA hardware setup:\n\n" );
670 snd_pcm_dump_hw_setup( p_sys->p_snd_pcm, p_sys->p_snd_stderr );
671 snd_output_printf( p_sys->p_snd_stderr, "\nALSA software setup:\n\n" );
672 snd_pcm_dump_sw_setup( p_sys->p_snd_pcm, p_sys->p_snd_stderr );
673 snd_output_printf( p_sys->p_snd_stderr, "\n" );
676 p_sys->start_date = 0;
677 vlc_sem_init( &p_sys->wait, 0 );
679 /* Create ALSA thread and wait for its readiness. */
680 if( vlc_clone( &p_sys->thread, ALSAThread, p_aout,
681 VLC_THREAD_PRIORITY_OUTPUT ) )
683 msg_Err( p_aout, "cannot create ALSA thread (%m)" );
684 vlc_sem_destroy( &p_sys->wait );
691 snd_pcm_close( p_sys->p_snd_pcm );
693 snd_output_close( p_sys->p_snd_stderr );
699 static void PlayIgnore( aout_instance_t *p_aout )
700 { /* Already playing - nothing to do */
704 /*****************************************************************************
705 * Play: start playback
706 *****************************************************************************/
707 static void Play( aout_instance_t *p_aout )
709 p_aout->output.pf_play = PlayIgnore;
711 /* get the playing date of the first aout buffer */
712 p_aout->output.p_sys->start_date =
713 aout_FifoFirstDate( p_aout, &p_aout->output.fifo );
715 /* wake up the audio output thread */
716 sem_post( &p_aout->output.p_sys->wait );
719 /*****************************************************************************
720 * Close: close the ALSA device
721 *****************************************************************************/
722 static void Close( vlc_object_t *p_this )
724 aout_instance_t *p_aout = (aout_instance_t *)p_this;
725 struct aout_sys_t * p_sys = p_aout->output.p_sys;
728 /* Make sure that the thread will stop once it is waken up */
729 vlc_cancel( p_sys->thread );
730 vlc_join( p_sys->thread, NULL );
731 vlc_sem_destroy( &p_sys->wait );
734 i_snd_rc = snd_pcm_close( p_sys->p_snd_pcm );
738 msg_Err( p_aout, "failed closing ALSA device (%s)",
739 snd_strerror( i_snd_rc ) );
743 snd_output_close( p_sys->p_snd_stderr );
749 static void pcm_drop(void *pcm)
754 /*****************************************************************************
755 * ALSAThread: asynchronous thread used to DMA the data to the device
756 *****************************************************************************/
757 static void* ALSAThread( void *data )
759 aout_instance_t * p_aout = data;
760 struct aout_sys_t * p_sys = p_aout->output.p_sys;
762 /* Wait for the exact time to start playing (avoids resampling) */
763 vlc_sem_wait( &p_sys->wait );
764 mwait( p_sys->start_date - AOUT_PTS_TOLERANCE / 4 );
766 vlc_cleanup_push( pcm_drop, p_sys->p_snd_pcm );
774 /*****************************************************************************
775 * ALSAFill: function used to fill the ALSA buffer as much as possible
776 *****************************************************************************/
777 static void ALSAFill( aout_instance_t * p_aout )
779 struct aout_sys_t * p_sys = p_aout->output.p_sys;
780 snd_pcm_t *p_pcm = p_sys->p_snd_pcm;
781 snd_pcm_status_t * p_status;
785 int canc = vlc_savecancel();
786 /* Fill in the buffer until space or audio output buffer shortage */
789 snd_pcm_status_alloca(&p_status);
790 i_snd_rc = snd_pcm_status( p_pcm, p_status );
793 msg_Err( p_aout, "cannot get device status" );
797 /* Handle buffer underruns and get the status again */
798 if( snd_pcm_status_get_state( p_status ) == SND_PCM_STATE_XRUN )
800 /* Prepare the device */
801 i_snd_rc = snd_pcm_prepare( p_pcm );
804 msg_Err( p_aout, "cannot recover from buffer underrun" );
808 msg_Dbg( p_aout, "recovered from buffer underrun" );
810 /* Get the new status */
811 i_snd_rc = snd_pcm_status( p_pcm, p_status );
814 msg_Err( p_aout, "cannot get device status after recovery" );
818 /* Underrun, try to recover as quickly as possible */
823 /* Here the device should be in RUNNING state, p_status is valid. */
824 snd_pcm_sframes_t delay = snd_pcm_status_get_delay( p_status );
825 if( delay == 0 ) /* workaround buggy alsa drivers */
826 if( snd_pcm_delay( p_pcm, &delay ) < 0 )
827 delay = 0; /* FIXME: use a positive minimal delay */
829 size_t i_bytes = snd_pcm_frames_to_bytes( p_pcm, delay );
830 mtime_t delay_us = CLOCK_FREQ * i_bytes
831 / p_aout->output.output.i_bytes_per_frame
832 / p_aout->output.output.i_rate
833 * p_aout->output.output.i_frame_length;
836 snd_pcm_state_t state = snd_pcm_status_get_state( p_status );
837 if( state != SND_PCM_STATE_RUNNING )
838 msg_Err( p_aout, "pcm status (%d) != RUNNING", state );
840 msg_Dbg( p_aout, "Delay is %ld frames (%zu bytes)", delay, i_bytes );
842 msg_Dbg( p_aout, "Bytes per frame: %d", p_aout->output.output.i_bytes_per_frame );
843 msg_Dbg( p_aout, "Rate: %d", p_aout->output.output.i_rate );
844 msg_Dbg( p_aout, "Frame length: %d", p_aout->output.output.i_frame_length );
845 msg_Dbg( p_aout, "Next date: in %"PRId64" microseconds", delay_us );
847 next_date = mdate() + delay_us;
850 block_t *p_buffer = aout_OutputNextBuffer( p_aout, next_date,
851 (p_aout->output.output.i_format == VLC_CODEC_SPDIFL) );
853 /* Audio output buffer shortage -> stop the fill process and wait */
854 if( p_buffer == NULL )
859 int n = snd_pcm_poll_descriptors_count(p_pcm);
860 struct pollfd ufd[n];
861 unsigned short revents;
863 snd_pcm_poll_descriptors(p_pcm, ufd, n);
866 vlc_restorecancel(canc);
868 canc = vlc_savecancel();
869 snd_pcm_poll_descriptors_revents(p_pcm, ufd, n, &revents);
873 if(revents & POLLOUT)
875 i_snd_rc = snd_pcm_writei( p_pcm, p_buffer->p_buffer,
876 p_buffer->i_nb_samples );
877 if( i_snd_rc != -ESTRPIPE )
881 /* a suspend event occurred
882 * (stream is suspended and waiting for an application recovery) */
883 msg_Dbg( p_aout, "entering in suspend mode, trying to resume..." );
885 while( ( i_snd_rc = snd_pcm_resume( p_pcm ) ) == -EAGAIN )
887 vlc_restorecancel(canc);
888 msleep(CLOCK_FREQ); /* device still suspended, wait... */
889 canc = vlc_savecancel();
893 /* Device does not support resuming, restart it */
894 i_snd_rc = snd_pcm_prepare( p_pcm );
899 msg_Err( p_aout, "cannot write: %s", snd_strerror( i_snd_rc ) );
901 vlc_restorecancel(canc);
902 block_Release( p_buffer );
907 msg_Err( p_aout, "ALSA error: %s", snd_strerror( i_snd_rc ) );
909 vlc_restorecancel(canc);
910 msleep(p_sys->i_period_time / 2);
913 static void GetDevicesForCard( module_config_t *p_item, int i_card );
914 static void GetDevices( module_config_t *p_item );
916 /*****************************************************************************
917 * config variable callback
918 *****************************************************************************/
919 static int FindDevicesCallback( vlc_object_t *p_this, char const *psz_name,
920 vlc_value_t newval, vlc_value_t oldval, void *p_unused )
922 module_config_t *p_item;
928 p_item = config_FindConfig( p_this, psz_name );
929 if( !p_item ) return VLC_SUCCESS;
931 /* Clear-up the current list */
934 /* Keep the first entrie */
935 for( i = 1; i < p_item->i_list; i++ )
937 free( (char *)p_item->ppsz_list[i] );
938 free( (char *)p_item->ppsz_list_text[i] );
940 /* TODO: Remove when no more needed */
941 p_item->ppsz_list[i] = NULL;
942 p_item->ppsz_list_text[i] = NULL;
946 GetDevices( p_item );
948 /* Signal change to the interface */
949 p_item->b_dirty = true;
955 static void GetDevicesForCard( module_config_t *p_item, int i_card )
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 )
990 /*printf( "get_devices_for_card(): "
991 "snd_ctl_pcm_info() "
992 "failed (%d:%d): %s.\n", i_card,
993 i_pcm_device, snd_strerror( -i_err ) );*/
998 if( asprintf( &psz_device, "hw:%d,%d", i_card, i_pcm_device ) == -1 )
1000 if( asprintf( &psz_descr, "%s: %s (%s)", psz_card_name,
1001 snd_pcm_info_get_name(p_pcm_info), psz_device ) == -1 )
1007 p_item->ppsz_list = realloc_or_free( p_item->ppsz_list,
1008 (p_item->i_list + 2) * sizeof(char *) );
1009 assert( p_item->ppsz_list );
1010 p_item->ppsz_list_text = realloc_or_free( p_item->ppsz_list_text,
1011 (p_item->i_list + 2) * sizeof(char *) );
1012 assert( p_item->ppsz_list_text );
1013 p_item->ppsz_list[ p_item->i_list ] = psz_device;
1014 p_item->ppsz_list_text[ p_item->i_list ] = psz_descr;
1016 p_item->ppsz_list[ p_item->i_list ] = NULL;
1017 p_item->ppsz_list_text[ p_item->i_list ] = NULL;
1020 snd_ctl_close( p_ctl );
1025 static void GetDevices( module_config_t *p_item )
1030 if( ( i_err = snd_card_next( &i_card ) ) != 0 )
1032 /*printf( "snd_card_next() failed: %s", snd_strerror( -i_err ) );*/
1036 while( i_card > -1 )
1038 GetDevicesForCard( p_item, i_card );
1039 if( ( i_err = snd_card_next( &i_card ) ) != 0 )
1041 /*printf( "snd_card_next() failed: %s", snd_strerror( -i_err ) );*/