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;
66 bool b_playing; /* playing status */
73 #define A52_FRAME_NB 1536
75 /* These values are in frames.
76 To convert them to a number of bytes you have to multiply them by the
77 number of channel(s) (eg. 2 for stereo) and the size of a sample (eg.
79 #define ALSA_DEFAULT_PERIOD_SIZE 1024
80 #define ALSA_DEFAULT_BUFFER_SIZE ( ALSA_DEFAULT_PERIOD_SIZE << 8 )
81 #define ALSA_SPDIF_PERIOD_SIZE A52_FRAME_NB
82 #define ALSA_SPDIF_BUFFER_SIZE ( ALSA_SPDIF_PERIOD_SIZE << 4 )
83 /* Why << 4 ? --Meuuh */
84 /* Why not ? --Bozo */
87 #define DEFAULT_ALSA_DEVICE N_("default")
89 /*****************************************************************************
91 *****************************************************************************/
92 static int Open ( vlc_object_t * );
93 static void Close ( vlc_object_t * );
94 static void Play ( aout_instance_t * );
95 static void* ALSAThread ( vlc_object_t * );
96 static void ALSAFill ( aout_instance_t * );
97 static int FindDevicesCallback( vlc_object_t *p_this, char const *psz_name,
98 vlc_value_t newval, vlc_value_t oldval, void *p_unused );
100 /*****************************************************************************
102 *****************************************************************************/
103 static const char *const ppsz_devices[] = { "default" };
104 static const char *const ppsz_devices_text[] = { N_("Default") };
106 set_shortname( "ALSA" )
107 set_description( N_("ALSA audio output") )
108 set_category( CAT_AUDIO )
109 set_subcategory( SUBCAT_AUDIO_AOUT )
110 add_string( "alsa-audio-device", DEFAULT_ALSA_DEVICE, aout_FindAndRestart,
111 N_("ALSA Device Name"), NULL, false )
112 add_deprecated_alias( "alsadev" ) /* deprecated since 0.9.3 */
113 change_string_list( ppsz_devices, ppsz_devices_text, FindDevicesCallback )
114 change_action_add( FindDevicesCallback, N_("Refresh list") )
116 set_capability( "audio output", 150 )
117 set_callbacks( Open, Close )
120 /*****************************************************************************
121 * Probe: probe the audio device for available formats and channels
122 *****************************************************************************/
123 static void Probe( aout_instance_t * p_aout,
124 const char * psz_device, const char * psz_iec_device,
125 int *pi_snd_pcm_format )
127 struct aout_sys_t * p_sys = p_aout->output.p_sys;
128 vlc_value_t val, text;
131 var_Create ( p_aout, "audio-device", VLC_VAR_INTEGER | VLC_VAR_HASCHOICE );
132 text.psz_string = _("Audio Device");
133 var_Change( p_aout, "audio-device", VLC_VAR_SETTEXT, &text, NULL );
135 /* We'll open the audio device in non blocking mode so we can just exit
136 * when it is already in use, but for the real stuff we'll still use
137 * the blocking mode */
139 /* Now test linear PCM capabilities */
140 if ( !(i_ret = snd_pcm_open( &p_sys->p_snd_pcm, psz_device,
141 SND_PCM_STREAM_PLAYBACK,
142 SND_PCM_NONBLOCK ) ) )
145 snd_pcm_hw_params_t * p_hw;
146 snd_pcm_hw_params_alloca (&p_hw);
148 if ( snd_pcm_hw_params_any( p_sys->p_snd_pcm, p_hw ) < 0 )
150 msg_Warn( p_aout, "unable to retrieve initial hardware parameters"
151 ", disabling linear PCM audio" );
152 snd_pcm_close( p_sys->p_snd_pcm );
153 var_Destroy( p_aout, "audio-device" );
157 if ( snd_pcm_hw_params_set_format( p_sys->p_snd_pcm, p_hw,
158 *pi_snd_pcm_format ) < 0 )
162 if( *pi_snd_pcm_format != SND_PCM_FORMAT_S16 )
164 *pi_snd_pcm_format = SND_PCM_FORMAT_S16;
165 i_snd_rc = snd_pcm_hw_params_set_format( p_sys->p_snd_pcm,
166 p_hw, *pi_snd_pcm_format );
170 msg_Warn( p_aout, "unable to set stream sample size and "
171 "word order, disabling linear PCM audio" );
172 snd_pcm_close( p_sys->p_snd_pcm );
173 var_Destroy( p_aout, "audio-device" );
178 i_channels = aout_FormatNbChannels( &p_aout->output.output );
180 while ( i_channels > 0 )
182 if ( !snd_pcm_hw_params_test_channels( p_sys->p_snd_pcm, p_hw,
185 switch ( i_channels )
188 val.i_int = AOUT_VAR_MONO;
189 text.psz_string = _("Mono");
190 var_Change( p_aout, "audio-device",
191 VLC_VAR_ADDCHOICE, &val, &text );
194 val.i_int = AOUT_VAR_STEREO;
195 text.psz_string = _("Stereo");
196 var_Change( p_aout, "audio-device",
197 VLC_VAR_ADDCHOICE, &val, &text );
198 var_Set( p_aout, "audio-device", val );
201 val.i_int = AOUT_VAR_2F2R;
202 text.psz_string = _("2 Front 2 Rear");
203 var_Change( p_aout, "audio-device",
204 VLC_VAR_ADDCHOICE, &val, &text );
207 val.i_int = AOUT_VAR_5_1;
208 text.psz_string = "5.1";
209 var_Change( p_aout, "audio-device",
210 VLC_VAR_ADDCHOICE, &val, &text );
218 /* Special case for mono on stereo only boards */
219 i_channels = aout_FormatNbChannels( &p_aout->output.output );
220 var_Change( p_aout, "audio-device", VLC_VAR_CHOICESCOUNT, &val, NULL );
221 if( val.i_int <= 0 && i_channels == 1 )
223 if ( !snd_pcm_hw_params_test_channels( p_sys->p_snd_pcm, p_hw, 2 ))
225 val.i_int = AOUT_VAR_STEREO;
226 text.psz_string = (char*)N_("Stereo");
227 var_Change( p_aout, "audio-device",
228 VLC_VAR_ADDCHOICE, &val, &text );
229 var_Set( p_aout, "audio-device", val );
233 /* Close the previously opened device */
234 snd_pcm_close( p_sys->p_snd_pcm );
236 else if ( i_ret == -EBUSY )
238 msg_Warn( p_aout, "audio device: %s is already in use", psz_device );
241 /* Test for S/PDIF device if needed */
242 if ( psz_iec_device )
244 /* Opening the device should be enough */
245 if ( !(i_ret = snd_pcm_open( &p_sys->p_snd_pcm, psz_iec_device,
246 SND_PCM_STREAM_PLAYBACK,
247 SND_PCM_NONBLOCK ) ) )
249 val.i_int = AOUT_VAR_SPDIF;
250 text.psz_string = (char*)N_("A/52 over S/PDIF");
251 var_Change( p_aout, "audio-device",
252 VLC_VAR_ADDCHOICE, &val, &text );
253 if( config_GetInt( p_aout, "spdif" ) )
254 var_Set( p_aout, "audio-device", val );
256 snd_pcm_close( p_sys->p_snd_pcm );
258 else if ( i_ret == -EBUSY )
260 msg_Warn( p_aout, "audio device: %s is already in use",
265 var_Change( p_aout, "audio-device", VLC_VAR_CHOICESCOUNT, &val, NULL );
268 /* Probe() has failed. */
269 msg_Dbg( p_aout, "failed to find a usable alsa configuration" );
270 var_Destroy( p_aout, "audio-device" );
274 /* Add final settings to the variable */
275 var_AddCallback( p_aout, "audio-device", aout_ChannelsRestart, NULL );
276 var_SetBool( p_aout, "intf-change", true );
279 /*****************************************************************************
280 * Open: create a handle and open an alsa device
281 *****************************************************************************
282 * This function opens an alsa device, through the alsa API.
284 * Note: the only heap-allocated string is psz_device. All the other pointers
285 * are references to psz_device or to stack-allocated data.
286 *****************************************************************************/
287 static int Open( vlc_object_t *p_this )
289 aout_instance_t * p_aout = (aout_instance_t *)p_this;
290 struct aout_sys_t * p_sys;
293 char psz_default_iec_device[128]; /* Buffer used to store the default
295 char * psz_device, * psz_iec_device; /* device names for PCM and S/PDIF
298 int i_vlc_pcm_format; /* Audio format for VLC's data */
299 int i_snd_pcm_format; /* Audio format for ALSA's data */
301 snd_pcm_uframes_t i_buffer_size = 0;
302 snd_pcm_uframes_t i_period_size = 0;
305 snd_pcm_hw_params_t *p_hw;
306 snd_pcm_sw_params_t *p_sw;
309 unsigned int i_old_rate;
312 /* Allocate structures */
313 p_aout->output.p_sys = p_sys = malloc( sizeof( aout_sys_t ) );
316 p_sys->b_playing = false;
317 p_sys->start_date = 0;
318 vlc_cond_init( &p_sys->wait );
319 vlc_mutex_init( &p_sys->lock );
321 /* Get device name */
322 if( (psz_device = config_GetPsz( p_aout, "alsa-audio-device" )) == NULL )
324 msg_Err( p_aout, "no audio device given (maybe \"default\" ?)" );
325 dialog_Fatal( p_aout, _("No Audio Device"), "%s",
326 _("No audio device name was given. You might want to " \
327 "enter \"default\".") );
332 /* Choose the IEC device for S/PDIF output:
333 if the device is overriden by the user then it will be the one
334 otherwise we compute the default device based on the output format. */
335 if( AOUT_FMT_NON_LINEAR( &p_aout->output.output )
336 && !strcmp( psz_device, DEFAULT_ALSA_DEVICE ) )
338 snprintf( psz_default_iec_device, sizeof(psz_default_iec_device),
339 "iec958:AES0=0x%x,AES1=0x%x,AES2=0x%x,AES3=0x%x",
340 IEC958_AES0_CON_EMPHASIS_NONE | IEC958_AES0_NONAUDIO,
341 IEC958_AES1_CON_ORIGINAL | IEC958_AES1_CON_PCM_CODER,
343 ( p_aout->output.output.i_rate == 48000 ?
344 IEC958_AES3_CON_FS_48000 :
345 ( p_aout->output.output.i_rate == 44100 ?
346 IEC958_AES3_CON_FS_44100 : IEC958_AES3_CON_FS_32000 ) ) );
347 psz_iec_device = psz_default_iec_device;
349 else if( AOUT_FMT_NON_LINEAR( &p_aout->output.output ) )
351 psz_iec_device = psz_device;
355 psz_iec_device = NULL;
358 /* Choose the linear PCM format (read the comment above about FPU
362 i_vlc_pcm_format = VLC_CODEC_FL32;
363 i_snd_pcm_format = SND_PCM_FORMAT_FLOAT;
367 i_vlc_pcm_format = VLC_CODEC_S16N;
368 i_snd_pcm_format = SND_PCM_FORMAT_S16;
371 /* If the variable doesn't exist then it's the first time we're called
372 and we have to probe the available audio formats and channels */
373 if ( var_Type( p_aout, "audio-device" ) == 0 )
375 Probe( p_aout, psz_device, psz_iec_device, &i_snd_pcm_format );
378 if ( var_Get( p_aout, "audio-device", &val ) < 0 )
385 p_aout->output.output.i_format = i_vlc_pcm_format;
386 if ( val.i_int == AOUT_VAR_5_1 )
388 p_aout->output.output.i_physical_channels
389 = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER
390 | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT
393 psz_device = strdup( "surround51" );
395 else if ( val.i_int == AOUT_VAR_2F2R )
397 p_aout->output.output.i_physical_channels
398 = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT
399 | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT;
401 psz_device = strdup( "surround40" );
403 else if ( val.i_int == AOUT_VAR_STEREO )
405 p_aout->output.output.i_physical_channels
406 = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT;
408 else if ( val.i_int == AOUT_VAR_MONO )
410 p_aout->output.output.i_physical_channels = AOUT_CHAN_CENTER;
412 else if( val.i_int != AOUT_VAR_SPDIF )
414 /* This should not happen ! */
415 msg_Err( p_aout, "internal: can't find audio-device (%i)", val.i_int );
422 snd_output_stdio_attach( &p_sys->p_snd_stderr, stderr, 0 );
425 /* Open the device */
426 if ( val.i_int == AOUT_VAR_SPDIF )
428 if ( ( i_snd_rc = snd_pcm_open( &p_sys->p_snd_pcm, psz_iec_device,
429 SND_PCM_STREAM_PLAYBACK, 0 ) ) < 0 )
431 msg_Err( p_aout, "cannot open ALSA device `%s' (%s)",
432 psz_iec_device, snd_strerror( i_snd_rc ) );
433 dialog_Fatal( p_aout, _("Audio output failed"),
434 _("VLC could not open the ALSA device \"%s\" (%s)."),
435 psz_iec_device, snd_strerror( i_snd_rc ) );
440 i_buffer_size = ALSA_SPDIF_BUFFER_SIZE;
441 i_snd_pcm_format = SND_PCM_FORMAT_S16;
444 i_vlc_pcm_format = VLC_CODEC_SPDIFL;
445 p_aout->output.i_nb_samples = i_period_size = ALSA_SPDIF_PERIOD_SIZE;
446 p_aout->output.output.i_bytes_per_frame = AOUT_SPDIF_SIZE;
447 p_aout->output.output.i_frame_length = A52_FRAME_NB;
449 aout_VolumeNoneInit( p_aout );
455 msg_Dbg( p_aout, "opening ALSA device `%s'", psz_device );
457 /* Since it seems snd_pcm_close hasn't really released the device at
458 the time it returns, probe if the device is available in loop for 1s.
459 We cannot use blocking mode since the we would wait indefinitely when
460 switching from a dmx device to surround51. */
462 for( i = 10; i >= 0; i-- )
464 if ( ( i_snd_rc = snd_pcm_open( &p_sys->p_snd_pcm, psz_device,
465 SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK ) ) == -EBUSY )
467 if( i ) msleep( 100000 /* 100ms */ );
470 msg_Err( p_aout, "audio device: %s is already in use",
472 dialog_Fatal( p_aout, _("Audio output failed"),
473 _("The audio device \"%s\" is already in use."),
482 msg_Err( p_aout, "cannot open ALSA device `%s' (%s)",
483 psz_device, snd_strerror( i_snd_rc ) );
484 dialog_Fatal( p_aout, _("Audio output failed"),
485 _("VLC could not open the ALSA device \"%s\" (%s)."),
486 psz_device, snd_strerror( i_snd_rc ) );
492 /* We want blocking mode */
493 snd_pcm_nonblock( p_sys->p_snd_pcm, 0 );
495 i_buffer_size = ALSA_DEFAULT_BUFFER_SIZE;
496 i_channels = aout_FormatNbChannels( &p_aout->output.output );
498 p_aout->output.i_nb_samples = i_period_size = ALSA_DEFAULT_PERIOD_SIZE;
500 aout_VolumeSoftInit( p_aout );
503 /* Free psz_device so that all the remaining data is stack-allocated */
506 p_aout->output.pf_play = Play;
508 snd_pcm_hw_params_alloca(&p_hw);
509 snd_pcm_sw_params_alloca(&p_sw);
511 /* Due to some bugs in alsa with some drivers, we need to retry in s16l
512 if snd_pcm_hw_params fails in fl32 */
517 /* Get Initial hardware parameters */
518 if ( ( i_snd_rc = snd_pcm_hw_params_any( p_sys->p_snd_pcm, p_hw ) ) < 0 )
520 msg_Err( p_aout, "unable to retrieve initial hardware parameters (%s)",
521 snd_strerror( i_snd_rc ) );
526 if ( ( i_snd_rc = snd_pcm_hw_params_set_format( p_sys->p_snd_pcm, p_hw,
527 i_snd_pcm_format ) ) < 0 )
529 if( i_snd_pcm_format != SND_PCM_FORMAT_S16 )
531 i_snd_pcm_format = SND_PCM_FORMAT_S16;
532 i_snd_rc = snd_pcm_hw_params_set_format( p_sys->p_snd_pcm,
533 p_hw, i_snd_pcm_format );
537 msg_Err( p_aout, "unable to set stream sample size and "
538 "word order (%s)", snd_strerror( i_snd_rc ) );
542 if( i_vlc_pcm_format != VLC_CODEC_SPDIFL )
543 switch( i_snd_pcm_format )
545 case SND_PCM_FORMAT_FLOAT:
546 i_vlc_pcm_format = VLC_CODEC_FL32;
548 case SND_PCM_FORMAT_S16:
549 i_vlc_pcm_format = VLC_CODEC_S16N;
552 p_aout->output.output.i_format = i_vlc_pcm_format;
554 if ( ( i_snd_rc = snd_pcm_hw_params_set_access( p_sys->p_snd_pcm, p_hw,
555 SND_PCM_ACCESS_RW_INTERLEAVED ) ) < 0 )
557 msg_Err( p_aout, "unable to set interleaved stream format (%s)",
558 snd_strerror( i_snd_rc ) );
563 if ( ( i_snd_rc = snd_pcm_hw_params_set_channels( p_sys->p_snd_pcm, p_hw,
566 msg_Err( p_aout, "unable to set number of output channels (%s)",
567 snd_strerror( i_snd_rc ) );
572 i_old_rate = p_aout->output.output.i_rate;
573 i_snd_rc = snd_pcm_hw_params_set_rate_near( p_sys->p_snd_pcm, p_hw,
574 &p_aout->output.output.i_rate,
576 if( i_snd_rc < 0 || p_aout->output.output.i_rate != i_old_rate )
578 msg_Warn( p_aout, "The rate %d Hz is not supported by your " \
579 "hardware. Using %d Hz instead.\n", i_old_rate, \
580 p_aout->output.output.i_rate );
583 /* Set period size. */
584 if ( ( i_snd_rc = snd_pcm_hw_params_set_period_size_near( p_sys->p_snd_pcm,
585 p_hw, &i_period_size, NULL ) ) < 0 )
587 msg_Err( p_aout, "unable to set period size (%s)",
588 snd_strerror( i_snd_rc ) );
591 p_aout->output.i_nb_samples = i_period_size;
593 /* Set buffer size. */
594 if ( ( i_snd_rc = snd_pcm_hw_params_set_buffer_size_near( p_sys->p_snd_pcm,
595 p_hw, &i_buffer_size ) ) < 0 )
597 msg_Err( p_aout, "unable to set buffer size (%s)",
598 snd_strerror( i_snd_rc ) );
602 /* Commit hardware parameters. */
603 if ( ( i_snd_rc = snd_pcm_hw_params( p_sys->p_snd_pcm, p_hw ) ) < 0 )
605 if ( b_retry == false &&
606 i_snd_pcm_format == SND_PCM_FORMAT_FLOAT)
609 i_snd_pcm_format = SND_PCM_FORMAT_S16;
610 p_aout->output.output.i_format = VLC_CODEC_S16N;
611 msg_Warn( p_aout, "unable to commit hardware configuration "
612 "with fl32 samples. Retrying with s16l (%s)", snd_strerror( i_snd_rc ) );
616 msg_Err( p_aout, "unable to commit hardware configuration (%s)",
617 snd_strerror( i_snd_rc ) );
623 if( ( i_snd_rc = snd_pcm_hw_params_get_period_time( p_hw,
624 &p_sys->i_period_time, NULL ) ) < 0 )
626 msg_Err( p_aout, "unable to get period time (%s)",
627 snd_strerror( i_snd_rc ) );
631 /* Get Initial software parameters */
632 snd_pcm_sw_params_current( p_sys->p_snd_pcm, p_sw );
634 i_snd_rc = snd_pcm_sw_params_set_sleep_min( p_sys->p_snd_pcm, p_sw, 0 );
636 i_snd_rc = snd_pcm_sw_params_set_avail_min( p_sys->p_snd_pcm, p_sw,
637 p_aout->output.i_nb_samples );
638 /* start playing when one period has been written */
639 i_snd_rc = snd_pcm_sw_params_set_start_threshold( p_sys->p_snd_pcm, p_sw,
640 ALSA_DEFAULT_PERIOD_SIZE);
643 msg_Err( p_aout, "unable to set start threshold (%s)",
644 snd_strerror( i_snd_rc ) );
648 /* Commit software parameters. */
649 if ( snd_pcm_sw_params( p_sys->p_snd_pcm, p_sw ) < 0 )
651 msg_Err( p_aout, "unable to set software configuration" );
656 snd_output_printf( p_sys->p_snd_stderr, "\nALSA hardware setup:\n\n" );
657 snd_pcm_dump_hw_setup( p_sys->p_snd_pcm, p_sys->p_snd_stderr );
658 snd_output_printf( p_sys->p_snd_stderr, "\nALSA software setup:\n\n" );
659 snd_pcm_dump_sw_setup( p_sys->p_snd_pcm, p_sys->p_snd_stderr );
660 snd_output_printf( p_sys->p_snd_stderr, "\n" );
663 /* Create ALSA thread and wait for its readiness. */
664 if( vlc_thread_create( p_aout, "aout", ALSAThread,
665 VLC_THREAD_PRIORITY_OUTPUT ) )
667 msg_Err( p_aout, "cannot create ALSA thread (%m)" );
674 snd_pcm_close( p_sys->p_snd_pcm );
676 snd_output_close( p_sys->p_snd_stderr );
682 /*****************************************************************************
683 * Play: nothing to do
684 *****************************************************************************/
685 static void Play( aout_instance_t *p_aout )
687 if( !p_aout->output.p_sys->b_playing )
689 p_aout->output.p_sys->b_playing = true;
691 /* get the playing date of the first aout buffer */
692 vlc_mutex_lock( &p_aout->output.p_sys->lock );
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 vlc_cond_signal( &p_aout->output.p_sys->wait );
698 vlc_mutex_unlock( &p_aout->output.p_sys->lock );
702 /*****************************************************************************
703 * Close: close the ALSA device
704 *****************************************************************************/
705 static void Close( vlc_object_t *p_this )
707 aout_instance_t *p_aout = (aout_instance_t *)p_this;
708 struct aout_sys_t * p_sys = p_aout->output.p_sys;
711 /* Make sure that the thread will stop once it is waken up */
712 vlc_object_kill( p_aout );
714 /* make sure the audio output thread is waken up */
715 vlc_mutex_lock( &p_aout->output.p_sys->lock );
716 vlc_cond_signal( &p_aout->output.p_sys->wait );
717 vlc_mutex_unlock( &p_aout->output.p_sys->lock );
720 vlc_thread_join( p_aout );
721 p_aout->b_die = false;
723 i_snd_rc = snd_pcm_close( p_sys->p_snd_pcm );
727 msg_Err( p_aout, "failed closing ALSA device (%s)",
728 snd_strerror( i_snd_rc ) );
732 snd_output_close( p_sys->p_snd_stderr );
738 /*****************************************************************************
739 * ALSAThread: asynchronous thread used to DMA the data to the device
740 *****************************************************************************/
741 static void* ALSAThread( vlc_object_t* p_this )
743 aout_instance_t * p_aout = (aout_instance_t*)p_this;
744 struct aout_sys_t * p_sys = p_aout->output.p_sys;
745 int canc = vlc_savecancel ();
747 /* Wait for the exact time to start playing (avoids resampling) */
748 vlc_mutex_lock( &p_sys->lock );
749 while( !p_sys->start_date && vlc_object_alive (p_aout) )
750 vlc_cond_wait( &p_sys->wait, &p_sys->lock );
751 vlc_mutex_unlock( &p_sys->lock );
753 if( !vlc_object_alive (p_aout) )
756 mwait( p_sys->start_date - AOUT_PTS_TOLERANCE / 4 );
758 while ( vlc_object_alive (p_aout) )
764 snd_pcm_drop( p_sys->p_snd_pcm );
765 vlc_restorecancel (canc);
769 /*****************************************************************************
770 * ALSAFill: function used to fill the ALSA buffer as much as possible
771 *****************************************************************************/
772 static void ALSAFill( aout_instance_t * p_aout )
774 struct aout_sys_t * p_sys = p_aout->output.p_sys;
775 aout_buffer_t * p_buffer;
776 snd_pcm_status_t * p_status;
780 /* Fill in the buffer until space or audio output buffer shortage */
783 snd_pcm_status_alloca(&p_status);
784 i_snd_rc = snd_pcm_status( p_sys->p_snd_pcm, p_status );
787 msg_Err( p_aout, "cannot get device status" );
791 /* Handle buffer underruns and get the status again */
792 if( snd_pcm_status_get_state( p_status ) == SND_PCM_STATE_XRUN )
794 /* Prepare the device */
795 i_snd_rc = snd_pcm_prepare( p_sys->p_snd_pcm );
799 msg_Err( p_aout, "cannot recover from buffer underrun" );
803 msg_Dbg( p_aout, "recovered from buffer underrun" );
805 /* Get the new status */
806 i_snd_rc = snd_pcm_status( p_sys->p_snd_pcm, p_status );
809 msg_Err( p_aout, "cannot get device status after recovery" );
813 /* Underrun, try to recover as quickly as possible */
818 /* Here the device should be in RUNNING state, p_status is valid. */
819 snd_pcm_sframes_t delay = snd_pcm_status_get_delay( p_status );
820 if( delay == 0 ) /* workaround buggy alsa drivers */
821 if( snd_pcm_delay( p_sys->p_snd_pcm, &delay ) < 0 )
822 delay = 0; /* FIXME: use a positive minimal delay */
823 int i_bytes = snd_pcm_frames_to_bytes( p_sys->p_snd_pcm, delay );
824 next_date = mdate() + ( (mtime_t)i_bytes * 1000000
825 / p_aout->output.output.i_bytes_per_frame
826 / p_aout->output.output.i_rate
827 * p_aout->output.output.i_frame_length );
830 snd_pcm_state_t state = snd_pcm_status_get_state( p_status );
831 if( state != SND_PCM_STATE_RUNNING )
832 msg_Err( p_aout, "pcm status (%d) != RUNNING", state );
834 msg_Dbg( p_aout, "Delay is %ld frames (%d bytes)", delay, i_bytes );
836 msg_Dbg( p_aout, "Bytes per frame: %d", p_aout->output.output.i_bytes_per_frame );
837 msg_Dbg( p_aout, "Rate: %d", p_aout->output.output.i_rate );
838 msg_Dbg( p_aout, "Frame length: %d", p_aout->output.output.i_frame_length );
840 msg_Dbg( p_aout, "Next date is in %d microseconds", (int)(next_date - mdate()) );
844 p_buffer = aout_OutputNextBuffer( p_aout, next_date,
845 (p_aout->output.output.i_format == VLC_CODEC_SPDIFL) );
847 /* Audio output buffer shortage -> stop the fill process and wait */
848 if( p_buffer == NULL )
853 i_snd_rc = snd_pcm_writei( p_sys->p_snd_pcm, p_buffer->p_buffer,
854 p_buffer->i_nb_samples );
855 if( i_snd_rc != -ESTRPIPE )
858 /* a suspend event occurred
859 * (stream is suspended and waiting for an application recovery) */
860 msg_Dbg( p_aout, "entering in suspend mode, trying to resume..." );
862 while( vlc_object_alive (p_aout) && vlc_object_alive (p_aout->p_libvlc) &&
863 ( i_snd_rc = snd_pcm_resume( p_sys->p_snd_pcm ) ) == -EAGAIN )
869 /* Device does not supprot resuming, restart it */
870 i_snd_rc = snd_pcm_prepare( p_sys->p_snd_pcm );
875 msg_Err( p_aout, "cannot write: %s", snd_strerror( i_snd_rc ) );
877 aout_BufferFree( p_buffer );
882 msg_Err( p_aout, "ALSA error: %s", snd_strerror( i_snd_rc ) );
883 msleep( p_sys->i_period_time >> 1 );
886 static void GetDevicesForCard( module_config_t *p_item, int i_card );
887 static void GetDevices( module_config_t *p_item );
889 /*****************************************************************************
890 * config variable callback
891 *****************************************************************************/
892 static int FindDevicesCallback( vlc_object_t *p_this, char const *psz_name,
893 vlc_value_t newval, vlc_value_t oldval, void *p_unused )
895 module_config_t *p_item;
901 p_item = config_FindConfig( p_this, psz_name );
902 if( !p_item ) return VLC_SUCCESS;
904 /* Clear-up the current list */
907 /* Keep the first entrie */
908 for( i = 1; i < p_item->i_list; i++ )
910 free( (char *)p_item->ppsz_list[i] );
911 free( (char *)p_item->ppsz_list_text[i] );
913 /* TODO: Remove when no more needed */
914 p_item->ppsz_list[i] = NULL;
915 p_item->ppsz_list_text[i] = NULL;
919 GetDevices( p_item );
921 /* Signal change to the interface */
922 p_item->b_dirty = true;
928 static void GetDevicesForCard( module_config_t *p_item, int i_card )
930 int i_pcm_device = -1;
932 snd_pcm_info_t *p_pcm_info;
937 sprintf( psz_dev, "hw:%i", i_card );
939 if( ( i_err = snd_ctl_open( &p_ctl, psz_dev, 0 ) ) < 0 )
942 if( ( i_err = snd_card_get_name( i_card, &psz_card_name ) ) != 0)
943 psz_card_name = _("Unknown soundcard");
945 snd_pcm_info_alloca( &p_pcm_info );
949 char *psz_device, *psz_descr;
950 if( ( i_err = snd_ctl_pcm_next_device( p_ctl, &i_pcm_device ) ) < 0 )
952 if( i_pcm_device < 0 )
955 snd_pcm_info_set_device( p_pcm_info, i_pcm_device );
956 snd_pcm_info_set_subdevice( p_pcm_info, 0 );
957 snd_pcm_info_set_stream( p_pcm_info, SND_PCM_STREAM_PLAYBACK );
959 if( ( i_err = snd_ctl_pcm_info( p_ctl, p_pcm_info ) ) < 0 )
961 if( i_err != -ENOENT )
963 /*printf( "get_devices_for_card(): "
964 "snd_ctl_pcm_info() "
965 "failed (%d:%d): %s.\n", i_card,
966 i_pcm_device, snd_strerror( -i_err ) );*/
971 if( asprintf( &psz_device, "hw:%d,%d", i_card, i_pcm_device ) == -1 )
973 if( asprintf( &psz_descr, "%s: %s (%s)", psz_card_name,
974 snd_pcm_info_get_name(p_pcm_info), psz_device ) == -1 )
981 (char **)realloc( p_item->ppsz_list,
982 (p_item->i_list + 2) * sizeof(char *) );
983 p_item->ppsz_list_text =
984 (char **)realloc( p_item->ppsz_list_text,
985 (p_item->i_list + 2) * sizeof(char *) );
986 p_item->ppsz_list[ p_item->i_list ] = psz_device;
987 p_item->ppsz_list_text[ p_item->i_list ] = psz_descr;
989 p_item->ppsz_list[ p_item->i_list ] = NULL;
990 p_item->ppsz_list_text[ p_item->i_list ] = NULL;
993 snd_ctl_close( p_ctl );
998 static void GetDevices( module_config_t *p_item )
1003 if( ( i_err = snd_card_next( &i_card ) ) != 0 )
1005 /*printf( "snd_card_next() failed: %s", snd_strerror( -i_err ) );*/
1009 while( i_card > -1 )
1011 GetDevicesForCard( p_item, i_card );
1012 if( ( i_err = snd_card_next( &i_card ) ) != 0 )
1014 /*printf( "snd_card_next() failed: %s", snd_strerror( -i_err ) );*/