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>
43 Note: we use the new API which is available since 0.9.0beta10a. */
44 #define ALSA_PCM_NEW_HW_PARAMS_API
45 #define ALSA_PCM_NEW_SW_PARAMS_API
46 #include <alsa/asoundlib.h>
48 /*#define ALSA_DEBUG*/
50 /*****************************************************************************
51 * aout_sys_t: ALSA audio output method descriptor
52 *****************************************************************************
53 * This structure is part of the audio output thread descriptor.
54 * It describes the ALSA specific properties of an audio device.
55 *****************************************************************************/
58 snd_pcm_t * p_snd_pcm;
59 unsigned int i_period_time;
62 snd_output_t * p_snd_stderr;
65 int b_playing; /* playing status */
71 snd_pcm_status_t *p_status;
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 ( vlc_object_t * );
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 );
269 /* Probe() has failed. */
270 msg_Dbg( p_aout, "failed to find a usable alsa configuration" );
271 var_Destroy( p_aout, "audio-device" );
275 /* Add final settings to the variable */
276 var_AddCallback( p_aout, "audio-device", aout_ChannelsRestart, NULL );
277 var_SetBool( p_aout, "intf-change", true );
280 /*****************************************************************************
281 * Open: create a handle and open an alsa device
282 *****************************************************************************
283 * This function opens an alsa device, through the alsa API.
285 * Note: the only heap-allocated string is psz_device. All the other pointers
286 * are references to psz_device or to stack-allocated data.
287 *****************************************************************************/
288 static int Open( vlc_object_t *p_this )
290 aout_instance_t * p_aout = (aout_instance_t *)p_this;
291 struct aout_sys_t * p_sys;
294 char psz_default_iec_device[128]; /* Buffer used to store the default
296 char * psz_device, * psz_iec_device; /* device names for PCM and S/PDIF
299 int i_vlc_pcm_format; /* Audio format for VLC's data */
300 int i_snd_pcm_format; /* Audio format for ALSA's data */
302 snd_pcm_uframes_t i_buffer_size = 0;
303 snd_pcm_uframes_t i_period_size = 0;
306 snd_pcm_hw_params_t *p_hw;
307 snd_pcm_sw_params_t *p_sw;
310 unsigned int i_old_rate;
313 /* Allocate structures */
314 p_aout->output.p_sys = p_sys = malloc( sizeof( aout_sys_t ) );
317 p_sys->b_playing = false;
318 p_sys->start_date = 0;
319 vlc_cond_init( &p_sys->wait );
320 vlc_mutex_init( &p_sys->lock );
322 /* Get device name */
323 if( (psz_device = config_GetPsz( p_aout, "alsa-audio-device" )) == NULL )
325 msg_Err( p_aout, "no audio device given (maybe \"default\" ?)" );
326 dialog_Fatal( p_aout, _("No Audio Device"), "%s",
327 _("No audio device name was given. You might want to " \
328 "enter \"default\".") );
333 /* Choose the IEC device for S/PDIF output:
334 if the device is overriden by the user then it will be the one
335 otherwise we compute the default device based on the output format. */
336 if( AOUT_FMT_NON_LINEAR( &p_aout->output.output )
337 && !strcmp( psz_device, DEFAULT_ALSA_DEVICE ) )
339 snprintf( psz_default_iec_device, sizeof(psz_default_iec_device),
340 "iec958:AES0=0x%x,AES1=0x%x,AES2=0x%x,AES3=0x%x",
341 IEC958_AES0_CON_EMPHASIS_NONE | IEC958_AES0_NONAUDIO,
342 IEC958_AES1_CON_ORIGINAL | IEC958_AES1_CON_PCM_CODER,
344 ( p_aout->output.output.i_rate == 48000 ?
345 IEC958_AES3_CON_FS_48000 :
346 ( p_aout->output.output.i_rate == 44100 ?
347 IEC958_AES3_CON_FS_44100 : IEC958_AES3_CON_FS_32000 ) ) );
348 psz_iec_device = psz_default_iec_device;
350 else if( AOUT_FMT_NON_LINEAR( &p_aout->output.output ) )
352 psz_iec_device = psz_device;
356 psz_iec_device = NULL;
359 /* Choose the linear PCM format (read the comment above about FPU
361 if( vlc_CPU() & CPU_CAPABILITY_FPU )
363 i_vlc_pcm_format = VLC_CODEC_FL32;
364 i_snd_pcm_format = SND_PCM_FORMAT_FLOAT;
368 i_vlc_pcm_format = VLC_CODEC_S16N;
369 i_snd_pcm_format = SND_PCM_FORMAT_S16;
372 /* If the variable doesn't exist then it's the first time we're called
373 and we have to probe the available audio formats and channels */
374 if ( var_Type( p_aout, "audio-device" ) == 0 )
376 Probe( p_aout, psz_device, psz_iec_device, &i_snd_pcm_format );
379 if ( var_Get( p_aout, "audio-device", &val ) < 0 )
386 p_aout->output.output.i_format = i_vlc_pcm_format;
387 if ( val.i_int == AOUT_VAR_5_1 )
389 p_aout->output.output.i_physical_channels
390 = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER
391 | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT
394 psz_device = strdup( "surround51" );
396 else if ( val.i_int == AOUT_VAR_2F2R )
398 p_aout->output.output.i_physical_channels
399 = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT
400 | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT;
402 psz_device = strdup( "surround40" );
404 else if ( val.i_int == AOUT_VAR_STEREO )
406 p_aout->output.output.i_physical_channels
407 = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT;
409 else if ( val.i_int == AOUT_VAR_MONO )
411 p_aout->output.output.i_physical_channels = AOUT_CHAN_CENTER;
413 else if( val.i_int != AOUT_VAR_SPDIF )
415 /* This should not happen ! */
416 msg_Err( p_aout, "internal: can't find audio-device (%i)", val.i_int );
423 snd_output_stdio_attach( &p_sys->p_snd_stderr, stderr, 0 );
426 /* Open the device */
427 if ( val.i_int == AOUT_VAR_SPDIF )
429 if ( ( i_snd_rc = snd_pcm_open( &p_sys->p_snd_pcm, psz_iec_device,
430 SND_PCM_STREAM_PLAYBACK, 0 ) ) < 0 )
432 msg_Err( p_aout, "cannot open ALSA device `%s' (%s)",
433 psz_iec_device, snd_strerror( i_snd_rc ) );
434 dialog_Fatal( p_aout, _("Audio output failed"),
435 _("VLC could not open the ALSA device \"%s\" (%s)."),
436 psz_iec_device, snd_strerror( i_snd_rc ) );
441 i_buffer_size = ALSA_SPDIF_BUFFER_SIZE;
442 i_snd_pcm_format = SND_PCM_FORMAT_S16;
445 i_vlc_pcm_format = VLC_CODEC_SPDIFL;
446 p_aout->output.i_nb_samples = i_period_size = ALSA_SPDIF_PERIOD_SIZE;
447 p_aout->output.output.i_bytes_per_frame = AOUT_SPDIF_SIZE;
448 p_aout->output.output.i_frame_length = A52_FRAME_NB;
450 aout_VolumeNoneInit( p_aout );
456 msg_Dbg( p_aout, "opening ALSA device `%s'", psz_device );
458 /* Since it seems snd_pcm_close hasn't really released the device at
459 the time it returns, probe if the device is available in loop for 1s.
460 We cannot use blocking mode since the we would wait indefinitely when
461 switching from a dmx device to surround51. */
463 for( i = 10; i >= 0; i-- )
465 if ( ( i_snd_rc = snd_pcm_open( &p_sys->p_snd_pcm, psz_device,
466 SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK ) ) == -EBUSY )
468 if( i ) msleep( 100000 /* 100ms */ );
471 msg_Err( p_aout, "audio device: %s is already in use",
473 dialog_Fatal( p_aout, _("Audio output failed"),
474 _("The audio device \"%s\" is already in use."),
483 msg_Err( p_aout, "cannot open ALSA device `%s' (%s)",
484 psz_device, snd_strerror( i_snd_rc ) );
485 dialog_Fatal( p_aout, _("Audio output failed"),
486 _("VLC could not open the ALSA device \"%s\" (%s)."),
487 psz_device, snd_strerror( i_snd_rc ) );
493 /* We want blocking mode */
494 snd_pcm_nonblock( p_sys->p_snd_pcm, 0 );
496 i_buffer_size = ALSA_DEFAULT_BUFFER_SIZE;
497 i_channels = aout_FormatNbChannels( &p_aout->output.output );
499 p_aout->output.i_nb_samples = i_period_size = ALSA_DEFAULT_PERIOD_SIZE;
501 aout_VolumeSoftInit( p_aout );
504 /* Free psz_device so that all the remaining data is stack-allocated */
507 p_aout->output.pf_play = Play;
509 snd_pcm_hw_params_alloca(&p_hw);
510 snd_pcm_sw_params_alloca(&p_sw);
512 /* Due to some bugs in alsa with some drivers, we need to retry in s16l
513 if snd_pcm_hw_params fails in fl32 */
518 /* Get Initial hardware parameters */
519 if ( ( i_snd_rc = snd_pcm_hw_params_any( p_sys->p_snd_pcm, p_hw ) ) < 0 )
521 msg_Err( p_aout, "unable to retrieve initial hardware parameters (%s)",
522 snd_strerror( i_snd_rc ) );
527 if ( ( i_snd_rc = snd_pcm_hw_params_set_format( p_sys->p_snd_pcm, p_hw,
528 i_snd_pcm_format ) ) < 0 )
530 if( i_snd_pcm_format != SND_PCM_FORMAT_S16 )
532 i_snd_pcm_format = SND_PCM_FORMAT_S16;
533 i_snd_rc = snd_pcm_hw_params_set_format( p_sys->p_snd_pcm,
534 p_hw, i_snd_pcm_format );
538 msg_Err( p_aout, "unable to set stream sample size and "
539 "word order (%s)", snd_strerror( i_snd_rc ) );
543 if( i_vlc_pcm_format != VLC_CODEC_SPDIFL )
544 switch( i_snd_pcm_format )
546 case SND_PCM_FORMAT_FLOAT:
547 i_vlc_pcm_format = VLC_CODEC_FL32;
549 case SND_PCM_FORMAT_S16:
550 i_vlc_pcm_format = VLC_CODEC_S16N;
553 p_aout->output.output.i_format = i_vlc_pcm_format;
555 if ( ( i_snd_rc = snd_pcm_hw_params_set_access( p_sys->p_snd_pcm, p_hw,
556 SND_PCM_ACCESS_RW_INTERLEAVED ) ) < 0 )
558 msg_Err( p_aout, "unable to set interleaved stream format (%s)",
559 snd_strerror( i_snd_rc ) );
564 if ( ( i_snd_rc = snd_pcm_hw_params_set_channels( p_sys->p_snd_pcm, p_hw,
567 msg_Err( p_aout, "unable to set number of output channels (%s)",
568 snd_strerror( i_snd_rc ) );
573 i_old_rate = p_aout->output.output.i_rate;
574 i_snd_rc = snd_pcm_hw_params_set_rate_near( p_sys->p_snd_pcm, p_hw,
575 &p_aout->output.output.i_rate,
577 if( i_snd_rc < 0 || p_aout->output.output.i_rate != i_old_rate )
579 msg_Warn( p_aout, "The rate %d Hz is not supported by your " \
580 "hardware. Using %d Hz instead.\n", i_old_rate, \
581 p_aout->output.output.i_rate );
584 /* Set period size. */
585 if ( ( i_snd_rc = snd_pcm_hw_params_set_period_size_near( p_sys->p_snd_pcm,
586 p_hw, &i_period_size, NULL ) ) < 0 )
588 msg_Err( p_aout, "unable to set period size (%s)",
589 snd_strerror( i_snd_rc ) );
592 p_aout->output.i_nb_samples = i_period_size;
594 /* Set buffer size. */
595 if ( ( i_snd_rc = snd_pcm_hw_params_set_buffer_size_near( p_sys->p_snd_pcm,
596 p_hw, &i_buffer_size ) ) < 0 )
598 msg_Err( p_aout, "unable to set buffer size (%s)",
599 snd_strerror( i_snd_rc ) );
603 /* Commit hardware parameters. */
604 if ( ( i_snd_rc = snd_pcm_hw_params( p_sys->p_snd_pcm, p_hw ) ) < 0 )
606 if ( b_retry == false &&
607 i_snd_pcm_format == SND_PCM_FORMAT_FLOAT)
610 i_snd_pcm_format = SND_PCM_FORMAT_S16;
611 p_aout->output.output.i_format = VLC_CODEC_S16N;
612 msg_Warn( p_aout, "unable to commit hardware configuration "
613 "with fl32 samples. Retrying with s16l (%s)", snd_strerror( i_snd_rc ) );
617 msg_Err( p_aout, "unable to commit hardware configuration (%s)",
618 snd_strerror( i_snd_rc ) );
624 if( ( i_snd_rc = snd_pcm_hw_params_get_period_time( p_hw,
625 &p_sys->i_period_time, NULL ) ) < 0 )
627 msg_Err( p_aout, "unable to get period time (%s)",
628 snd_strerror( i_snd_rc ) );
632 /* Get Initial software parameters */
633 snd_pcm_sw_params_current( p_sys->p_snd_pcm, p_sw );
635 i_snd_rc = snd_pcm_sw_params_set_sleep_min( p_sys->p_snd_pcm, p_sw, 0 );
637 i_snd_rc = snd_pcm_sw_params_set_avail_min( p_sys->p_snd_pcm, p_sw,
638 p_aout->output.i_nb_samples );
639 /* start playing when one period has been written */
640 i_snd_rc = snd_pcm_sw_params_set_start_threshold( p_sys->p_snd_pcm, p_sw,
641 ALSA_DEFAULT_PERIOD_SIZE);
644 msg_Err( p_aout, "unable to set start threshold (%s)",
645 snd_strerror( i_snd_rc ) );
649 /* Commit software parameters. */
650 if ( snd_pcm_sw_params( p_sys->p_snd_pcm, p_sw ) < 0 )
652 msg_Err( p_aout, "unable to set software configuration" );
657 snd_output_printf( p_sys->p_snd_stderr, "\nALSA hardware setup:\n\n" );
658 snd_pcm_dump_hw_setup( p_sys->p_snd_pcm, p_sys->p_snd_stderr );
659 snd_output_printf( p_sys->p_snd_stderr, "\nALSA software setup:\n\n" );
660 snd_pcm_dump_sw_setup( p_sys->p_snd_pcm, p_sys->p_snd_stderr );
661 snd_output_printf( p_sys->p_snd_stderr, "\n" );
664 /* Create ALSA thread and wait for its readiness. */
665 if( vlc_thread_create( p_aout, "aout", ALSAThread,
666 VLC_THREAD_PRIORITY_OUTPUT ) )
668 msg_Err( p_aout, "cannot create ALSA thread (%m)" );
675 snd_pcm_close( p_sys->p_snd_pcm );
677 snd_output_close( p_sys->p_snd_stderr );
683 /*****************************************************************************
684 * Play: nothing to do
685 *****************************************************************************/
686 static void Play( aout_instance_t *p_aout )
688 if( !p_aout->output.p_sys->b_playing )
690 p_aout->output.p_sys->b_playing = 1;
692 /* get the playing date of the first aout buffer */
693 p_aout->output.p_sys->start_date =
694 aout_FifoFirstDate( p_aout, &p_aout->output.fifo );
696 /* wake up the audio output thread */
697 vlc_mutex_lock( &p_aout->output.p_sys->lock );
698 vlc_cond_signal( &p_aout->output.p_sys->wait );
699 vlc_mutex_unlock( &p_aout->output.p_sys->lock );
703 /*****************************************************************************
704 * Close: close the ALSA device
705 *****************************************************************************/
706 static void Close( vlc_object_t *p_this )
708 aout_instance_t *p_aout = (aout_instance_t *)p_this;
709 struct aout_sys_t * p_sys = p_aout->output.p_sys;
712 /* Make sure that the thread will stop once it is waken up */
713 vlc_object_kill( p_aout );
715 /* make sure the audio output thread is waken up */
716 vlc_mutex_lock( &p_aout->output.p_sys->lock );
717 vlc_cond_signal( &p_aout->output.p_sys->wait );
718 vlc_mutex_unlock( &p_aout->output.p_sys->lock );
721 vlc_thread_join( p_aout );
722 p_aout->b_die = false;
724 i_snd_rc = snd_pcm_close( p_sys->p_snd_pcm );
728 msg_Err( p_aout, "failed closing ALSA device (%s)",
729 snd_strerror( i_snd_rc ) );
733 snd_output_close( p_sys->p_snd_stderr );
739 /*****************************************************************************
740 * ALSAThread: asynchronous thread used to DMA the data to the device
741 *****************************************************************************/
742 static void* ALSAThread( vlc_object_t* p_this )
744 aout_instance_t * p_aout = (aout_instance_t*)p_this;
745 struct aout_sys_t * p_sys = p_aout->output.p_sys;
746 int canc = vlc_savecancel ();
747 p_sys->p_status = (snd_pcm_status_t *)malloc(snd_pcm_status_sizeof());
749 /* Wait for the exact time to start playing (avoids resampling) */
750 vlc_mutex_lock( &p_sys->lock );
751 while( !p_sys->start_date && vlc_object_alive (p_aout) )
752 vlc_cond_wait( &p_sys->wait, &p_sys->lock );
753 vlc_mutex_unlock( &p_sys->lock );
755 if( !vlc_object_alive (p_aout) )
758 mwait( p_sys->start_date - AOUT_PTS_TOLERANCE / 4 );
760 while ( vlc_object_alive (p_aout) )
766 snd_pcm_drop( p_sys->p_snd_pcm );
767 free( p_aout->output.p_sys->p_status );
768 vlc_restorecancel (canc);
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 aout_buffer_t * p_buffer;
779 snd_pcm_status_t * p_status = p_sys->p_status;
783 /* Fill in the buffer until space or audio output buffer shortage */
786 i_snd_rc = snd_pcm_status( p_sys->p_snd_pcm, p_status );
789 msg_Err( p_aout, "cannot get device status" );
793 /* Handle buffer underruns and get the status again */
794 if( snd_pcm_status_get_state( p_status ) == SND_PCM_STATE_XRUN )
796 /* Prepare the device */
797 i_snd_rc = snd_pcm_prepare( p_sys->p_snd_pcm );
801 msg_Err( p_aout, "cannot recover from buffer underrun" );
805 msg_Dbg( p_aout, "recovered from buffer underrun" );
807 /* Get the new status */
808 i_snd_rc = snd_pcm_status( p_sys->p_snd_pcm, p_status );
811 msg_Err( p_aout, "cannot get device status after recovery" );
815 /* Underrun, try to recover as quickly as possible */
820 /* Here the device should be in RUNNING state, p_status is valid. */
821 snd_pcm_sframes_t delay = snd_pcm_status_get_delay( p_status );
822 if( delay == 0 ) /* workaround buggy alsa drivers */
823 if( snd_pcm_delay( p_sys->p_snd_pcm, &delay ) < 0 )
824 delay = 0; /* FIXME: use a positive minimal delay */
825 int i_bytes = snd_pcm_frames_to_bytes( p_sys->p_snd_pcm, delay );
826 next_date = mdate() + ( (mtime_t)i_bytes * 1000000
827 / p_aout->output.output.i_bytes_per_frame
828 / p_aout->output.output.i_rate
829 * p_aout->output.output.i_frame_length );
832 snd_pcm_state_t state = snd_pcm_status_get_state( p_status );
833 if( state != SND_PCM_STATE_RUNNING )
834 msg_Err( p_aout, "pcm status (%d) != RUNNING", state );
836 msg_Dbg( p_aout, "Delay is %ld frames (%d bytes)", delay, i_bytes );
838 msg_Dbg( p_aout, "Bytes per frame: %d", p_aout->output.output.i_bytes_per_frame );
839 msg_Dbg( p_aout, "Rate: %d", p_aout->output.output.i_rate );
840 msg_Dbg( p_aout, "Frame length: %d", p_aout->output.output.i_frame_length );
842 msg_Dbg( p_aout, "Next date is in %d microseconds", (int)(next_date - mdate()) );
846 p_buffer = aout_OutputNextBuffer( p_aout, next_date,
847 (p_aout->output.output.i_format == VLC_CODEC_SPDIFL) );
849 /* Audio output buffer shortage -> stop the fill process and wait */
850 if( p_buffer == NULL )
855 i_snd_rc = snd_pcm_writei( p_sys->p_snd_pcm, p_buffer->p_buffer,
856 p_buffer->i_nb_samples );
857 if( i_snd_rc != -ESTRPIPE )
860 /* a suspend event occurred
861 * (stream is suspended and waiting for an application recovery) */
862 msg_Dbg( p_aout, "entering in suspend mode, trying to resume..." );
864 while( vlc_object_alive (p_aout) && vlc_object_alive (p_aout->p_libvlc) &&
865 ( i_snd_rc = snd_pcm_resume( p_sys->p_snd_pcm ) ) == -EAGAIN )
871 /* Device does not supprot resuming, restart it */
872 i_snd_rc = snd_pcm_prepare( p_sys->p_snd_pcm );
877 msg_Err( p_aout, "cannot write: %s", snd_strerror( i_snd_rc ) );
879 aout_BufferFree( p_buffer );
884 msg_Err( p_aout, "ALSA error: %s", snd_strerror( i_snd_rc ) );
885 msleep( p_sys->i_period_time >> 1 );
888 static void GetDevicesForCard( module_config_t *p_item, int i_card );
889 static void GetDevices( module_config_t *p_item );
891 /*****************************************************************************
892 * config variable callback
893 *****************************************************************************/
894 static int FindDevicesCallback( vlc_object_t *p_this, char const *psz_name,
895 vlc_value_t newval, vlc_value_t oldval, void *p_unused )
897 module_config_t *p_item;
903 p_item = config_FindConfig( p_this, psz_name );
904 if( !p_item ) return VLC_SUCCESS;
906 /* Clear-up the current list */
909 /* Keep the first entrie */
910 for( i = 1; i < p_item->i_list; i++ )
912 free( (char *)p_item->ppsz_list[i] );
913 free( (char *)p_item->ppsz_list_text[i] );
915 /* TODO: Remove when no more needed */
916 p_item->ppsz_list[i] = NULL;
917 p_item->ppsz_list_text[i] = NULL;
921 GetDevices( p_item );
923 /* Signal change to the interface */
924 p_item->b_dirty = true;
930 static void GetDevicesForCard( module_config_t *p_item, int i_card )
932 int i_pcm_device = -1;
934 snd_pcm_info_t *p_pcm_info;
939 sprintf( psz_dev, "hw:%i", i_card );
941 if( ( i_err = snd_ctl_open( &p_ctl, psz_dev, 0 ) ) < 0 )
944 if( ( i_err = snd_card_get_name( i_card, &psz_card_name ) ) != 0)
945 psz_card_name = _("Unknown soundcard");
947 snd_pcm_info_alloca( &p_pcm_info );
951 char *psz_device, *psz_descr;
952 if( ( i_err = snd_ctl_pcm_next_device( p_ctl, &i_pcm_device ) ) < 0 )
954 if( i_pcm_device < 0 )
957 snd_pcm_info_set_device( p_pcm_info, i_pcm_device );
958 snd_pcm_info_set_subdevice( p_pcm_info, 0 );
959 snd_pcm_info_set_stream( p_pcm_info, SND_PCM_STREAM_PLAYBACK );
961 if( ( i_err = snd_ctl_pcm_info( p_ctl, p_pcm_info ) ) < 0 )
963 if( i_err != -ENOENT )
965 /*printf( "get_devices_for_card(): "
966 "snd_ctl_pcm_info() "
967 "failed (%d:%d): %s.\n", i_card,
968 i_pcm_device, snd_strerror( -i_err ) );*/
973 if( asprintf( &psz_device, "hw:%d,%d", i_card, i_pcm_device ) == -1 )
975 if( asprintf( &psz_descr, "%s: %s (%s)", psz_card_name,
976 snd_pcm_info_get_name(p_pcm_info), psz_device ) == -1 )
983 (char **)realloc( p_item->ppsz_list,
984 (p_item->i_list + 2) * sizeof(char *) );
985 p_item->ppsz_list_text =
986 (char **)realloc( p_item->ppsz_list_text,
987 (p_item->i_list + 2) * sizeof(char *) );
988 p_item->ppsz_list[ p_item->i_list ] = psz_device;
989 p_item->ppsz_list_text[ p_item->i_list ] = psz_descr;
991 p_item->ppsz_list[ p_item->i_list ] = NULL;
992 p_item->ppsz_list_text[ p_item->i_list ] = NULL;
995 snd_ctl_close( p_ctl );
1000 static void GetDevices( module_config_t *p_item )
1005 if( ( i_err = snd_card_next( &i_card ) ) != 0 )
1007 /*printf( "snd_card_next() failed: %s", snd_strerror( -i_err ) );*/
1011 while( i_card > -1 )
1013 GetDevicesForCard( p_item, i_card );
1014 if( ( i_err = snd_card_next( &i_card ) ) != 0 )
1016 /*printf( "snd_card_next() failed: %s", snd_strerror( -i_err ) );*/