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 );
101 /*****************************************************************************
103 *****************************************************************************/
104 static const char *const ppsz_devices[] = { "default" };
105 static const char *const ppsz_devices_text[] = { N_("Default") };
107 set_shortname( "ALSA" )
108 set_description( N_("ALSA audio output") )
109 set_category( CAT_AUDIO )
110 set_subcategory( SUBCAT_AUDIO_AOUT )
111 add_string( "alsa-audio-device", DEFAULT_ALSA_DEVICE, aout_FindAndRestart,
112 N_("ALSA Device Name"), NULL, false )
113 add_deprecated_alias( "alsadev" ) /* deprecated since 0.9.3 */
114 change_string_list( ppsz_devices, ppsz_devices_text, FindDevicesCallback )
115 change_action_add( FindDevicesCallback, N_("Refresh list") )
117 set_capability( "audio output", 150 )
118 set_callbacks( Open, Close )
121 /*****************************************************************************
122 * Probe: probe the audio device for available formats and channels
123 *****************************************************************************/
124 static void Probe( aout_instance_t * p_aout,
125 const char * psz_device, const char * psz_iec_device,
126 int *pi_snd_pcm_format )
128 struct aout_sys_t * p_sys = p_aout->output.p_sys;
129 vlc_value_t val, text;
132 var_Create ( p_aout, "audio-device", VLC_VAR_INTEGER | VLC_VAR_HASCHOICE );
133 text.psz_string = _("Audio Device");
134 var_Change( p_aout, "audio-device", VLC_VAR_SETTEXT, &text, NULL );
136 /* We'll open the audio device in non blocking mode so we can just exit
137 * when it is already in use, but for the real stuff we'll still use
138 * the blocking mode */
140 /* Now test linear PCM capabilities */
141 if ( !(i_ret = snd_pcm_open( &p_sys->p_snd_pcm, psz_device,
142 SND_PCM_STREAM_PLAYBACK,
143 SND_PCM_NONBLOCK ) ) )
146 snd_pcm_hw_params_t * p_hw;
147 snd_pcm_hw_params_alloca (&p_hw);
149 if ( snd_pcm_hw_params_any( p_sys->p_snd_pcm, p_hw ) < 0 )
151 msg_Warn( p_aout, "unable to retrieve initial hardware parameters"
152 ", disabling linear PCM audio" );
153 snd_pcm_close( p_sys->p_snd_pcm );
154 var_Destroy( p_aout, "audio-device" );
158 if ( snd_pcm_hw_params_set_format( p_sys->p_snd_pcm, p_hw,
159 *pi_snd_pcm_format ) < 0 )
163 if( *pi_snd_pcm_format != SND_PCM_FORMAT_S16 )
165 *pi_snd_pcm_format = SND_PCM_FORMAT_S16;
166 i_snd_rc = snd_pcm_hw_params_set_format( p_sys->p_snd_pcm,
167 p_hw, *pi_snd_pcm_format );
171 msg_Warn( p_aout, "unable to set stream sample size and "
172 "word order, disabling linear PCM audio" );
173 snd_pcm_close( p_sys->p_snd_pcm );
174 var_Destroy( p_aout, "audio-device" );
179 i_channels = aout_FormatNbChannels( &p_aout->output.output );
181 while ( i_channels > 0 )
183 if ( !snd_pcm_hw_params_test_channels( p_sys->p_snd_pcm, p_hw,
186 switch ( i_channels )
189 val.i_int = AOUT_VAR_MONO;
190 text.psz_string = _("Mono");
191 var_Change( p_aout, "audio-device",
192 VLC_VAR_ADDCHOICE, &val, &text );
195 val.i_int = AOUT_VAR_STEREO;
196 text.psz_string = _("Stereo");
197 var_Change( p_aout, "audio-device",
198 VLC_VAR_ADDCHOICE, &val, &text );
199 var_Set( p_aout, "audio-device", val );
202 val.i_int = AOUT_VAR_2F2R;
203 text.psz_string = _("2 Front 2 Rear");
204 var_Change( p_aout, "audio-device",
205 VLC_VAR_ADDCHOICE, &val, &text );
208 val.i_int = AOUT_VAR_5_1;
209 text.psz_string = "5.1";
210 var_Change( p_aout, "audio-device",
211 VLC_VAR_ADDCHOICE, &val, &text );
219 /* Special case for mono on stereo only boards */
220 i_channels = aout_FormatNbChannels( &p_aout->output.output );
221 var_Change( p_aout, "audio-device", VLC_VAR_CHOICESCOUNT, &val, NULL );
222 if( val.i_int <= 0 && i_channels == 1 )
224 if ( !snd_pcm_hw_params_test_channels( p_sys->p_snd_pcm, p_hw, 2 ))
226 val.i_int = AOUT_VAR_STEREO;
227 text.psz_string = (char*)N_("Stereo");
228 var_Change( p_aout, "audio-device",
229 VLC_VAR_ADDCHOICE, &val, &text );
230 var_Set( p_aout, "audio-device", val );
234 /* Close the previously opened device */
235 snd_pcm_close( p_sys->p_snd_pcm );
237 else if ( i_ret == -EBUSY )
239 msg_Warn( p_aout, "audio device: %s is already in use", psz_device );
242 /* Test for S/PDIF device if needed */
243 if ( psz_iec_device )
245 /* Opening the device should be enough */
246 if ( !(i_ret = snd_pcm_open( &p_sys->p_snd_pcm, psz_iec_device,
247 SND_PCM_STREAM_PLAYBACK,
248 SND_PCM_NONBLOCK ) ) )
250 val.i_int = AOUT_VAR_SPDIF;
251 text.psz_string = (char*)N_("A/52 over S/PDIF");
252 var_Change( p_aout, "audio-device",
253 VLC_VAR_ADDCHOICE, &val, &text );
254 if( config_GetInt( p_aout, "spdif" ) )
255 var_Set( p_aout, "audio-device", val );
257 snd_pcm_close( p_sys->p_snd_pcm );
259 else if ( i_ret == -EBUSY )
261 msg_Warn( p_aout, "audio device: %s is already in use",
266 var_Change( p_aout, "audio-device", VLC_VAR_CHOICESCOUNT, &val, NULL );
267 #if (SND_LIB_VERSION <= 0x010015)
268 # warning Please update alsa-lib to version > 1.0.21a.
269 var_Create( p_aout->p_libvlc, "alsa-working", VLC_VAR_BOOL );
272 if( var_GetBool( p_aout->p_libvlc, "alsa-working" ) )
273 dialog_FatalWait( p_aout, "ALSA version problem",
274 "VLC failed to re-initialize your sound output device.\n"
275 "Please update alsa-lib to version 1.0.22 or higher "
276 "to fix this issue." );
279 var_SetBool( p_aout->p_libvlc, "alsa-working", true );
283 /* Probe() has failed. */
284 msg_Dbg( p_aout, "failed to find a usable ALSA configuration" );
285 var_Destroy( p_aout, "audio-device" );
289 /* Add final settings to the variable */
290 var_AddCallback( p_aout, "audio-device", aout_ChannelsRestart, NULL );
291 var_SetBool( p_aout, "intf-change", true );
294 /*****************************************************************************
295 * Open: create a handle and open an alsa device
296 *****************************************************************************
297 * This function opens an alsa device, through the alsa API.
299 * Note: the only heap-allocated string is psz_device. All the other pointers
300 * are references to psz_device or to stack-allocated data.
301 *****************************************************************************/
302 static int Open( vlc_object_t *p_this )
304 aout_instance_t * p_aout = (aout_instance_t *)p_this;
305 struct aout_sys_t * p_sys;
308 char psz_default_iec_device[128]; /* Buffer used to store the default
310 char * psz_device, * psz_iec_device; /* device names for PCM and S/PDIF
313 int i_vlc_pcm_format; /* Audio format for VLC's data */
314 int i_snd_pcm_format; /* Audio format for ALSA's data */
316 snd_pcm_uframes_t i_buffer_size = 0;
317 snd_pcm_uframes_t i_period_size = 0;
320 snd_pcm_hw_params_t *p_hw;
321 snd_pcm_sw_params_t *p_sw;
324 unsigned int i_old_rate;
327 /* Allocate structures */
328 p_aout->output.p_sys = p_sys = malloc( sizeof( aout_sys_t ) );
332 /* Get device name */
333 if( (psz_device = config_GetPsz( p_aout, "alsa-audio-device" )) == NULL )
335 msg_Err( p_aout, "no audio device given (maybe \"default\" ?)" );
336 dialog_Fatal( p_aout, _("No Audio Device"), "%s",
337 _("No audio device name was given. You might want to " \
338 "enter \"default\".") );
343 /* Choose the IEC device for S/PDIF output:
344 if the device is overriden by the user then it will be the one
345 otherwise we compute the default device based on the output format. */
346 if( AOUT_FMT_NON_LINEAR( &p_aout->output.output )
347 && !strcmp( psz_device, DEFAULT_ALSA_DEVICE ) )
349 snprintf( psz_default_iec_device, sizeof(psz_default_iec_device),
350 "iec958:AES0=0x%x,AES1=0x%x,AES2=0x%x,AES3=0x%x",
351 IEC958_AES0_CON_EMPHASIS_NONE | IEC958_AES0_NONAUDIO,
352 IEC958_AES1_CON_ORIGINAL | IEC958_AES1_CON_PCM_CODER,
354 ( p_aout->output.output.i_rate == 48000 ?
355 IEC958_AES3_CON_FS_48000 :
356 ( p_aout->output.output.i_rate == 44100 ?
357 IEC958_AES3_CON_FS_44100 : IEC958_AES3_CON_FS_32000 ) ) );
358 psz_iec_device = psz_default_iec_device;
360 else if( AOUT_FMT_NON_LINEAR( &p_aout->output.output ) )
362 psz_iec_device = psz_device;
366 psz_iec_device = NULL;
369 /* Choose the linear PCM format (read the comment above about FPU
373 i_vlc_pcm_format = VLC_CODEC_FL32;
374 i_snd_pcm_format = SND_PCM_FORMAT_FLOAT;
378 i_vlc_pcm_format = VLC_CODEC_S16N;
379 i_snd_pcm_format = SND_PCM_FORMAT_S16;
382 /* If the variable doesn't exist then it's the first time we're called
383 and we have to probe the available audio formats and channels */
384 if ( var_Type( p_aout, "audio-device" ) == 0 )
386 Probe( p_aout, psz_device, psz_iec_device, &i_snd_pcm_format );
389 if ( var_Get( p_aout, "audio-device", &val ) < 0 )
396 p_aout->output.output.i_format = i_vlc_pcm_format;
397 if ( val.i_int == AOUT_VAR_5_1 )
399 p_aout->output.output.i_physical_channels
400 = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER
401 | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT
404 psz_device = strdup( "surround51" );
406 else if ( val.i_int == AOUT_VAR_2F2R )
408 p_aout->output.output.i_physical_channels
409 = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT
410 | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT;
412 psz_device = strdup( "surround40" );
414 else if ( val.i_int == AOUT_VAR_STEREO )
416 p_aout->output.output.i_physical_channels
417 = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT;
419 else if ( val.i_int == AOUT_VAR_MONO )
421 p_aout->output.output.i_physical_channels = AOUT_CHAN_CENTER;
423 else if( val.i_int != AOUT_VAR_SPDIF )
425 /* This should not happen ! */
426 msg_Err( p_aout, "internal: can't find audio-device (%i)", val.i_int );
433 snd_output_stdio_attach( &p_sys->p_snd_stderr, stderr, 0 );
436 /* Open the device */
437 if ( val.i_int == AOUT_VAR_SPDIF )
439 if ( ( i_snd_rc = snd_pcm_open( &p_sys->p_snd_pcm, psz_iec_device,
440 SND_PCM_STREAM_PLAYBACK, 0 ) ) < 0 )
442 msg_Err( p_aout, "cannot open ALSA device `%s' (%s)",
443 psz_iec_device, snd_strerror( i_snd_rc ) );
444 dialog_Fatal( p_aout, _("Audio output failed"),
445 _("VLC could not open the ALSA device \"%s\" (%s)."),
446 psz_iec_device, snd_strerror( i_snd_rc ) );
451 i_buffer_size = ALSA_SPDIF_BUFFER_SIZE;
452 i_snd_pcm_format = SND_PCM_FORMAT_S16;
455 i_vlc_pcm_format = VLC_CODEC_SPDIFL;
456 p_aout->output.i_nb_samples = i_period_size = ALSA_SPDIF_PERIOD_SIZE;
457 p_aout->output.output.i_bytes_per_frame = AOUT_SPDIF_SIZE;
458 p_aout->output.output.i_frame_length = A52_FRAME_NB;
460 aout_VolumeNoneInit( p_aout );
466 msg_Dbg( p_aout, "opening ALSA device `%s'", psz_device );
468 /* Since it seems snd_pcm_close hasn't really released the device at
469 the time it returns, probe if the device is available in loop for 1s.
470 We cannot use blocking mode since the we would wait indefinitely when
471 switching from a dmx device to surround51. */
473 for( i = 10; i >= 0; i-- )
475 if ( ( i_snd_rc = snd_pcm_open( &p_sys->p_snd_pcm, psz_device,
476 SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK ) ) == -EBUSY )
478 if( i ) msleep( 100000 /* 100ms */ );
481 msg_Err( p_aout, "audio device: %s is already in use",
483 dialog_Fatal( p_aout, _("Audio output failed"),
484 _("The audio device \"%s\" is already in use."),
493 msg_Err( p_aout, "cannot open ALSA device `%s' (%s)",
494 psz_device, snd_strerror( i_snd_rc ) );
495 dialog_Fatal( p_aout, _("Audio output failed"),
496 _("VLC could not open the ALSA device \"%s\" (%s)."),
497 psz_device, snd_strerror( i_snd_rc ) );
503 /* We want blocking mode */
504 snd_pcm_nonblock( p_sys->p_snd_pcm, 0 );
506 i_buffer_size = ALSA_DEFAULT_BUFFER_SIZE;
507 i_channels = aout_FormatNbChannels( &p_aout->output.output );
509 p_aout->output.i_nb_samples = i_period_size = ALSA_DEFAULT_PERIOD_SIZE;
511 aout_VolumeSoftInit( p_aout );
514 /* Free psz_device so that all the remaining data is stack-allocated */
517 p_aout->output.pf_play = Play;
519 snd_pcm_hw_params_alloca(&p_hw);
520 snd_pcm_sw_params_alloca(&p_sw);
522 /* Due to some bugs in alsa with some drivers, we need to retry in s16l
523 if snd_pcm_hw_params fails in fl32 */
528 /* Get Initial hardware parameters */
529 if ( ( i_snd_rc = snd_pcm_hw_params_any( p_sys->p_snd_pcm, p_hw ) ) < 0 )
531 msg_Err( p_aout, "unable to retrieve initial hardware parameters (%s)",
532 snd_strerror( i_snd_rc ) );
537 if ( ( i_snd_rc = snd_pcm_hw_params_set_format( p_sys->p_snd_pcm, p_hw,
538 i_snd_pcm_format ) ) < 0 )
540 if( i_snd_pcm_format != SND_PCM_FORMAT_S16 )
542 i_snd_pcm_format = SND_PCM_FORMAT_S16;
543 i_snd_rc = snd_pcm_hw_params_set_format( p_sys->p_snd_pcm,
544 p_hw, i_snd_pcm_format );
548 msg_Err( p_aout, "unable to set stream sample size and "
549 "word order (%s)", snd_strerror( i_snd_rc ) );
553 if( i_vlc_pcm_format != VLC_CODEC_SPDIFL )
554 switch( i_snd_pcm_format )
556 case SND_PCM_FORMAT_FLOAT:
557 i_vlc_pcm_format = VLC_CODEC_FL32;
559 case SND_PCM_FORMAT_S16:
560 i_vlc_pcm_format = VLC_CODEC_S16N;
563 p_aout->output.output.i_format = i_vlc_pcm_format;
565 if ( ( i_snd_rc = snd_pcm_hw_params_set_access( p_sys->p_snd_pcm, p_hw,
566 SND_PCM_ACCESS_RW_INTERLEAVED ) ) < 0 )
568 msg_Err( p_aout, "unable to set interleaved stream format (%s)",
569 snd_strerror( i_snd_rc ) );
574 if ( ( i_snd_rc = snd_pcm_hw_params_set_channels( p_sys->p_snd_pcm, p_hw,
577 msg_Err( p_aout, "unable to set number of output channels (%s)",
578 snd_strerror( i_snd_rc ) );
583 i_old_rate = p_aout->output.output.i_rate;
584 i_snd_rc = snd_pcm_hw_params_set_rate_near( p_sys->p_snd_pcm, p_hw,
585 &p_aout->output.output.i_rate,
587 if( i_snd_rc < 0 || p_aout->output.output.i_rate != i_old_rate )
589 msg_Warn( p_aout, "The rate %d Hz is not supported by your " \
590 "hardware. Using %d Hz instead.\n", i_old_rate, \
591 p_aout->output.output.i_rate );
594 /* Set period size. */
595 if ( ( i_snd_rc = snd_pcm_hw_params_set_period_size_near( p_sys->p_snd_pcm,
596 p_hw, &i_period_size, NULL ) ) < 0 )
598 msg_Err( p_aout, "unable to set period size (%s)",
599 snd_strerror( i_snd_rc ) );
602 p_aout->output.i_nb_samples = i_period_size;
604 /* Set buffer size. */
605 if ( ( i_snd_rc = snd_pcm_hw_params_set_buffer_size_near( p_sys->p_snd_pcm,
606 p_hw, &i_buffer_size ) ) < 0 )
608 msg_Err( p_aout, "unable to set buffer size (%s)",
609 snd_strerror( i_snd_rc ) );
613 /* Commit hardware parameters. */
614 if ( ( i_snd_rc = snd_pcm_hw_params( p_sys->p_snd_pcm, p_hw ) ) < 0 )
616 if ( b_retry == false &&
617 i_snd_pcm_format == SND_PCM_FORMAT_FLOAT)
620 i_snd_pcm_format = SND_PCM_FORMAT_S16;
621 p_aout->output.output.i_format = VLC_CODEC_S16N;
622 msg_Warn( p_aout, "unable to commit hardware configuration "
623 "with fl32 samples. Retrying with s16l (%s)", snd_strerror( i_snd_rc ) );
627 msg_Err( p_aout, "unable to commit hardware configuration (%s)",
628 snd_strerror( i_snd_rc ) );
634 if( ( i_snd_rc = snd_pcm_hw_params_get_period_time( p_hw,
635 &p_sys->i_period_time, NULL ) ) < 0 )
637 msg_Err( p_aout, "unable to get period time (%s)",
638 snd_strerror( i_snd_rc ) );
642 /* Get Initial software parameters */
643 snd_pcm_sw_params_current( p_sys->p_snd_pcm, p_sw );
645 i_snd_rc = snd_pcm_sw_params_set_sleep_min( p_sys->p_snd_pcm, p_sw, 0 );
647 i_snd_rc = snd_pcm_sw_params_set_avail_min( p_sys->p_snd_pcm, p_sw,
648 p_aout->output.i_nb_samples );
649 /* start playing when one period has been written */
650 i_snd_rc = snd_pcm_sw_params_set_start_threshold( p_sys->p_snd_pcm, p_sw,
651 ALSA_DEFAULT_PERIOD_SIZE);
654 msg_Err( p_aout, "unable to set start threshold (%s)",
655 snd_strerror( i_snd_rc ) );
659 /* Commit software parameters. */
660 if ( snd_pcm_sw_params( p_sys->p_snd_pcm, p_sw ) < 0 )
662 msg_Err( p_aout, "unable to set software configuration" );
667 snd_output_printf( p_sys->p_snd_stderr, "\nALSA hardware setup:\n\n" );
668 snd_pcm_dump_hw_setup( p_sys->p_snd_pcm, p_sys->p_snd_stderr );
669 snd_output_printf( p_sys->p_snd_stderr, "\nALSA software setup:\n\n" );
670 snd_pcm_dump_sw_setup( p_sys->p_snd_pcm, p_sys->p_snd_stderr );
671 snd_output_printf( p_sys->p_snd_stderr, "\n" );
674 p_sys->start_date = 0;
675 vlc_sem_init( &p_sys->wait, 0 );
677 /* Create ALSA thread and wait for its readiness. */
678 if( vlc_clone( &p_sys->thread, ALSAThread, p_aout,
679 VLC_THREAD_PRIORITY_OUTPUT ) )
681 msg_Err( p_aout, "cannot create ALSA thread (%m)" );
682 vlc_sem_destroy( &p_sys->wait );
689 snd_pcm_close( p_sys->p_snd_pcm );
691 snd_output_close( p_sys->p_snd_stderr );
697 static void PlayIgnore( aout_instance_t *p_aout )
698 { /* Already playing - nothing to do */
702 /*****************************************************************************
703 * Play: start playback
704 *****************************************************************************/
705 static void Play( aout_instance_t *p_aout )
707 p_aout->output.pf_play = PlayIgnore;
709 /* get the playing date of the first aout buffer */
710 p_aout->output.p_sys->start_date =
711 aout_FifoFirstDate( p_aout, &p_aout->output.fifo );
713 /* wake up the audio output thread */
714 sem_post( &p_aout->output.p_sys->wait );
717 /*****************************************************************************
718 * Close: close the ALSA device
719 *****************************************************************************/
720 static void Close( vlc_object_t *p_this )
722 aout_instance_t *p_aout = (aout_instance_t *)p_this;
723 struct aout_sys_t * p_sys = p_aout->output.p_sys;
726 /* Make sure that the thread will stop once it is waken up */
727 vlc_cancel( p_sys->thread );
728 vlc_join( p_sys->thread, NULL );
729 vlc_sem_destroy( &p_sys->wait );
732 i_snd_rc = snd_pcm_close( p_sys->p_snd_pcm );
736 msg_Err( p_aout, "failed closing ALSA device (%s)",
737 snd_strerror( i_snd_rc ) );
741 snd_output_close( p_sys->p_snd_stderr );
747 static void pcm_drop(void *pcm)
752 /*****************************************************************************
753 * ALSAThread: asynchronous thread used to DMA the data to the device
754 *****************************************************************************/
755 static void* ALSAThread( void *data )
757 aout_instance_t * p_aout = data;
758 struct aout_sys_t * p_sys = p_aout->output.p_sys;
760 /* Wait for the exact time to start playing (avoids resampling) */
761 vlc_sem_wait( &p_sys->wait );
762 mwait( p_sys->start_date - AOUT_PTS_TOLERANCE / 4 );
764 vlc_cleanup_push( pcm_drop, p_sys->p_snd_pcm );
772 /*****************************************************************************
773 * ALSAFill: function used to fill the ALSA buffer as much as possible
774 *****************************************************************************/
775 static void ALSAFill( aout_instance_t * p_aout )
777 struct aout_sys_t * p_sys = p_aout->output.p_sys;
778 snd_pcm_t *p_pcm = p_sys->p_snd_pcm;
779 snd_pcm_status_t * p_status;
783 int canc = vlc_savecancel();
784 /* Fill in the buffer until space or audio output buffer shortage */
787 snd_pcm_status_alloca(&p_status);
788 i_snd_rc = snd_pcm_status( p_pcm, p_status );
791 msg_Err( p_aout, "cannot get device status" );
795 /* Handle buffer underruns and get the status again */
796 if( snd_pcm_status_get_state( p_status ) == SND_PCM_STATE_XRUN )
798 /* Prepare the device */
799 i_snd_rc = snd_pcm_prepare( p_pcm );
802 msg_Err( p_aout, "cannot recover from buffer underrun" );
806 msg_Dbg( p_aout, "recovered from buffer underrun" );
808 /* Get the new status */
809 i_snd_rc = snd_pcm_status( p_pcm, p_status );
812 msg_Err( p_aout, "cannot get device status after recovery" );
816 /* Underrun, try to recover as quickly as possible */
821 /* Here the device should be in RUNNING state, p_status is valid. */
822 snd_pcm_sframes_t delay = snd_pcm_status_get_delay( p_status );
823 if( delay == 0 ) /* workaround buggy alsa drivers */
824 if( snd_pcm_delay( p_pcm, &delay ) < 0 )
825 delay = 0; /* FIXME: use a positive minimal delay */
827 size_t i_bytes = snd_pcm_frames_to_bytes( p_pcm, delay );
828 mtime_t delay_us = CLOCK_FREQ * i_bytes
829 / p_aout->output.output.i_bytes_per_frame
830 / p_aout->output.output.i_rate
831 * p_aout->output.output.i_frame_length;
834 snd_pcm_state_t state = snd_pcm_status_get_state( p_status );
835 if( state != SND_PCM_STATE_RUNNING )
836 msg_Err( p_aout, "pcm status (%d) != RUNNING", state );
838 msg_Dbg( p_aout, "Delay is %ld frames (%zu bytes)", delay, i_bytes );
840 msg_Dbg( p_aout, "Bytes per frame: %d", p_aout->output.output.i_bytes_per_frame );
841 msg_Dbg( p_aout, "Rate: %d", p_aout->output.output.i_rate );
842 msg_Dbg( p_aout, "Frame length: %d", p_aout->output.output.i_frame_length );
843 msg_Dbg( p_aout, "Next date: in %"PRId64" microseconds", delay_us );
845 next_date = mdate() + delay_us;
848 block_t *p_buffer = aout_OutputNextBuffer( p_aout, next_date,
849 (p_aout->output.output.i_format == VLC_CODEC_SPDIFL) );
851 /* Audio output buffer shortage -> stop the fill process and wait */
852 if( p_buffer == NULL )
857 int n = snd_pcm_poll_descriptors_count(p_pcm);
858 struct pollfd ufd[n];
859 unsigned short revents;
861 snd_pcm_poll_descriptors(p_pcm, ufd, n);
864 vlc_restorecancel(canc);
866 canc = vlc_savecancel();
867 snd_pcm_poll_descriptors_revents(p_pcm, ufd, n, &revents);
871 if(revents & POLLOUT)
873 i_snd_rc = snd_pcm_writei( p_pcm, p_buffer->p_buffer,
874 p_buffer->i_nb_samples );
875 if( i_snd_rc != -ESTRPIPE )
879 /* a suspend event occurred
880 * (stream is suspended and waiting for an application recovery) */
881 msg_Dbg( p_aout, "entering in suspend mode, trying to resume..." );
883 while( ( i_snd_rc = snd_pcm_resume( p_pcm ) ) == -EAGAIN )
885 vlc_restorecancel(canc);
886 msleep(CLOCK_FREQ); /* device still suspended, wait... */
887 canc = vlc_savecancel();
891 /* Device does not support resuming, restart it */
892 i_snd_rc = snd_pcm_prepare( p_pcm );
897 msg_Err( p_aout, "cannot write: %s", snd_strerror( i_snd_rc ) );
899 vlc_restorecancel(canc);
900 block_Release( p_buffer );
905 msg_Err( p_aout, "ALSA error: %s", snd_strerror( i_snd_rc ) );
907 vlc_restorecancel(canc);
908 msleep(p_sys->i_period_time / 2);
911 static void GetDevicesForCard( module_config_t *p_item, int i_card );
912 static void GetDevices( module_config_t *p_item );
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;
926 p_item = config_FindConfig( p_this, psz_name );
927 if( !p_item ) return VLC_SUCCESS;
929 /* Clear-up the current list */
932 /* Keep the first entrie */
933 for( i = 1; i < p_item->i_list; i++ )
935 free( (char *)p_item->ppsz_list[i] );
936 free( (char *)p_item->ppsz_list_text[i] );
938 /* TODO: Remove when no more needed */
939 p_item->ppsz_list[i] = NULL;
940 p_item->ppsz_list_text[i] = NULL;
944 GetDevices( p_item );
946 /* Signal change to the interface */
947 p_item->b_dirty = true;
953 static void GetDevicesForCard( module_config_t *p_item, int i_card )
955 int i_pcm_device = -1;
957 snd_pcm_info_t *p_pcm_info;
962 sprintf( psz_dev, "hw:%i", i_card );
964 if( ( i_err = snd_ctl_open( &p_ctl, psz_dev, 0 ) ) < 0 )
967 if( ( i_err = snd_card_get_name( i_card, &psz_card_name ) ) != 0)
968 psz_card_name = _("Unknown soundcard");
970 snd_pcm_info_alloca( &p_pcm_info );
974 char *psz_device, *psz_descr;
975 if( ( i_err = snd_ctl_pcm_next_device( p_ctl, &i_pcm_device ) ) < 0 )
977 if( i_pcm_device < 0 )
980 snd_pcm_info_set_device( p_pcm_info, i_pcm_device );
981 snd_pcm_info_set_subdevice( p_pcm_info, 0 );
982 snd_pcm_info_set_stream( p_pcm_info, SND_PCM_STREAM_PLAYBACK );
984 if( ( i_err = snd_ctl_pcm_info( p_ctl, p_pcm_info ) ) < 0 )
986 if( i_err != -ENOENT )
988 /*printf( "get_devices_for_card(): "
989 "snd_ctl_pcm_info() "
990 "failed (%d:%d): %s.\n", i_card,
991 i_pcm_device, snd_strerror( -i_err ) );*/
996 if( asprintf( &psz_device, "hw:%d,%d", i_card, i_pcm_device ) == -1 )
998 if( asprintf( &psz_descr, "%s: %s (%s)", psz_card_name,
999 snd_pcm_info_get_name(p_pcm_info), psz_device ) == -1 )
1005 p_item->ppsz_list = xrealloc( p_item->ppsz_list,
1006 (p_item->i_list + 2) * sizeof(char *) );
1007 p_item->ppsz_list_text = xrealloc( p_item->ppsz_list_text,
1008 (p_item->i_list + 2) * sizeof(char *) );
1009 p_item->ppsz_list[ p_item->i_list ] = psz_device;
1010 p_item->ppsz_list_text[ p_item->i_list ] = psz_descr;
1012 p_item->ppsz_list[ p_item->i_list ] = NULL;
1013 p_item->ppsz_list_text[ p_item->i_list ] = NULL;
1016 snd_ctl_close( p_ctl );
1021 static void GetDevices( module_config_t *p_item )
1026 if( ( i_err = snd_card_next( &i_card ) ) != 0 )
1028 /*printf( "snd_card_next() failed: %s", snd_strerror( -i_err ) );*/
1032 while( i_card > -1 )
1034 GetDevicesForCard( p_item, i_card );
1035 if( ( i_err = snd_card_next( &i_card ) ) != 0 )
1037 /*printf( "snd_card_next() failed: %s", snd_strerror( -i_err ) );*/