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 */
72 snd_pcm_status_t *p_status;
75 #define A52_FRAME_NB 1536
77 /* These values are in frames.
78 To convert them to a number of bytes you have to multiply them by the
79 number of channel(s) (eg. 2 for stereo) and the size of a sample (eg.
81 #define ALSA_DEFAULT_PERIOD_SIZE 1024
82 #define ALSA_DEFAULT_BUFFER_SIZE ( ALSA_DEFAULT_PERIOD_SIZE << 8 )
83 #define ALSA_SPDIF_PERIOD_SIZE A52_FRAME_NB
84 #define ALSA_SPDIF_BUFFER_SIZE ( ALSA_SPDIF_PERIOD_SIZE << 4 )
85 /* Why << 4 ? --Meuuh */
86 /* Why not ? --Bozo */
89 #define DEFAULT_ALSA_DEVICE N_("default")
91 /*****************************************************************************
93 *****************************************************************************/
94 static int Open ( vlc_object_t * );
95 static void Close ( vlc_object_t * );
96 static void Play ( aout_instance_t * );
97 static void* ALSAThread ( vlc_object_t * );
98 static void ALSAFill ( aout_instance_t * );
99 static int FindDevicesCallback( vlc_object_t *p_this, char const *psz_name,
100 vlc_value_t newval, vlc_value_t oldval, void *p_unused );
102 /*****************************************************************************
104 *****************************************************************************/
105 static const char *const ppsz_devices[] = { "default" };
106 static const char *const ppsz_devices_text[] = { N_("Default") };
108 set_shortname( "ALSA" )
109 set_description( N_("ALSA audio output") )
110 set_category( CAT_AUDIO )
111 set_subcategory( SUBCAT_AUDIO_AOUT )
112 add_string( "alsa-audio-device", DEFAULT_ALSA_DEVICE, aout_FindAndRestart,
113 N_("ALSA Device Name"), NULL, false )
114 add_deprecated_alias( "alsadev" ) /* deprecated since 0.9.3 */
115 change_string_list( ppsz_devices, ppsz_devices_text, FindDevicesCallback )
116 change_action_add( FindDevicesCallback, N_("Refresh list") )
118 set_capability( "audio output", 150 )
119 set_callbacks( Open, Close )
122 /*****************************************************************************
123 * Probe: probe the audio device for available formats and channels
124 *****************************************************************************/
125 static void Probe( aout_instance_t * p_aout,
126 const char * psz_device, const char * psz_iec_device,
127 int *pi_snd_pcm_format )
129 struct aout_sys_t * p_sys = p_aout->output.p_sys;
130 vlc_value_t val, text;
133 var_Create ( p_aout, "audio-device", VLC_VAR_INTEGER | VLC_VAR_HASCHOICE );
134 text.psz_string = _("Audio Device");
135 var_Change( p_aout, "audio-device", VLC_VAR_SETTEXT, &text, NULL );
137 /* We'll open the audio device in non blocking mode so we can just exit
138 * when it is already in use, but for the real stuff we'll still use
139 * the blocking mode */
141 /* Now test linear PCM capabilities */
142 if ( !(i_ret = snd_pcm_open( &p_sys->p_snd_pcm, psz_device,
143 SND_PCM_STREAM_PLAYBACK,
144 SND_PCM_NONBLOCK ) ) )
147 snd_pcm_hw_params_t * p_hw;
148 snd_pcm_hw_params_alloca (&p_hw);
150 if ( snd_pcm_hw_params_any( p_sys->p_snd_pcm, p_hw ) < 0 )
152 msg_Warn( p_aout, "unable to retrieve initial hardware parameters"
153 ", disabling linear PCM audio" );
154 snd_pcm_close( p_sys->p_snd_pcm );
155 var_Destroy( p_aout, "audio-device" );
159 if ( snd_pcm_hw_params_set_format( p_sys->p_snd_pcm, p_hw,
160 *pi_snd_pcm_format ) < 0 )
164 if( *pi_snd_pcm_format != SND_PCM_FORMAT_S16 )
166 *pi_snd_pcm_format = SND_PCM_FORMAT_S16;
167 i_snd_rc = snd_pcm_hw_params_set_format( p_sys->p_snd_pcm,
168 p_hw, *pi_snd_pcm_format );
172 msg_Warn( p_aout, "unable to set stream sample size and "
173 "word order, disabling linear PCM audio" );
174 snd_pcm_close( p_sys->p_snd_pcm );
175 var_Destroy( p_aout, "audio-device" );
180 i_channels = aout_FormatNbChannels( &p_aout->output.output );
182 while ( i_channels > 0 )
184 if ( !snd_pcm_hw_params_test_channels( p_sys->p_snd_pcm, p_hw,
187 switch ( i_channels )
190 val.i_int = AOUT_VAR_MONO;
191 text.psz_string = _("Mono");
192 var_Change( p_aout, "audio-device",
193 VLC_VAR_ADDCHOICE, &val, &text );
196 val.i_int = AOUT_VAR_STEREO;
197 text.psz_string = _("Stereo");
198 var_Change( p_aout, "audio-device",
199 VLC_VAR_ADDCHOICE, &val, &text );
200 var_Set( p_aout, "audio-device", val );
203 val.i_int = AOUT_VAR_2F2R;
204 text.psz_string = _("2 Front 2 Rear");
205 var_Change( p_aout, "audio-device",
206 VLC_VAR_ADDCHOICE, &val, &text );
209 val.i_int = AOUT_VAR_5_1;
210 text.psz_string = "5.1";
211 var_Change( p_aout, "audio-device",
212 VLC_VAR_ADDCHOICE, &val, &text );
220 /* Special case for mono on stereo only boards */
221 i_channels = aout_FormatNbChannels( &p_aout->output.output );
222 var_Change( p_aout, "audio-device", VLC_VAR_CHOICESCOUNT, &val, NULL );
223 if( val.i_int <= 0 && i_channels == 1 )
225 if ( !snd_pcm_hw_params_test_channels( p_sys->p_snd_pcm, p_hw, 2 ))
227 val.i_int = AOUT_VAR_STEREO;
228 text.psz_string = (char*)N_("Stereo");
229 var_Change( p_aout, "audio-device",
230 VLC_VAR_ADDCHOICE, &val, &text );
231 var_Set( p_aout, "audio-device", val );
235 /* Close the previously opened device */
236 snd_pcm_close( p_sys->p_snd_pcm );
238 else if ( i_ret == -EBUSY )
240 msg_Warn( p_aout, "audio device: %s is already in use", psz_device );
243 /* Test for S/PDIF device if needed */
244 if ( psz_iec_device )
246 /* Opening the device should be enough */
247 if ( !(i_ret = snd_pcm_open( &p_sys->p_snd_pcm, psz_iec_device,
248 SND_PCM_STREAM_PLAYBACK,
249 SND_PCM_NONBLOCK ) ) )
251 val.i_int = AOUT_VAR_SPDIF;
252 text.psz_string = (char*)N_("A/52 over S/PDIF");
253 var_Change( p_aout, "audio-device",
254 VLC_VAR_ADDCHOICE, &val, &text );
255 if( config_GetInt( p_aout, "spdif" ) )
256 var_Set( p_aout, "audio-device", val );
258 snd_pcm_close( p_sys->p_snd_pcm );
260 else if ( i_ret == -EBUSY )
262 msg_Warn( p_aout, "audio device: %s is already in use",
267 var_Change( p_aout, "audio-device", VLC_VAR_CHOICESCOUNT, &val, NULL );
270 /* Probe() has failed. */
271 msg_Dbg( p_aout, "failed to find a usable alsa configuration" );
272 var_Destroy( p_aout, "audio-device" );
276 /* Add final settings to the variable */
277 var_AddCallback( p_aout, "audio-device", aout_ChannelsRestart, NULL );
278 var_SetBool( p_aout, "intf-change", true );
281 /*****************************************************************************
282 * Open: create a handle and open an alsa device
283 *****************************************************************************
284 * This function opens an alsa device, through the alsa API.
286 * Note: the only heap-allocated string is psz_device. All the other pointers
287 * are references to psz_device or to stack-allocated data.
288 *****************************************************************************/
289 static int Open( vlc_object_t *p_this )
291 aout_instance_t * p_aout = (aout_instance_t *)p_this;
292 struct aout_sys_t * p_sys;
295 char psz_default_iec_device[128]; /* Buffer used to store the default
297 char * psz_device, * psz_iec_device; /* device names for PCM and S/PDIF
300 int i_vlc_pcm_format; /* Audio format for VLC's data */
301 int i_snd_pcm_format; /* Audio format for ALSA's data */
303 snd_pcm_uframes_t i_buffer_size = 0;
304 snd_pcm_uframes_t i_period_size = 0;
307 snd_pcm_hw_params_t *p_hw;
308 snd_pcm_sw_params_t *p_sw;
311 unsigned int i_old_rate;
314 /* Allocate structures */
315 p_aout->output.p_sys = p_sys = malloc( sizeof( aout_sys_t ) );
318 p_sys->b_playing = false;
319 p_sys->start_date = 0;
320 vlc_cond_init( &p_sys->wait );
321 vlc_mutex_init( &p_sys->lock );
323 /* Get device name */
324 if( (psz_device = config_GetPsz( p_aout, "alsa-audio-device" )) == NULL )
326 msg_Err( p_aout, "no audio device given (maybe \"default\" ?)" );
327 dialog_Fatal( p_aout, _("No Audio Device"), "%s",
328 _("No audio device name was given. You might want to " \
329 "enter \"default\".") );
334 /* Choose the IEC device for S/PDIF output:
335 if the device is overriden by the user then it will be the one
336 otherwise we compute the default device based on the output format. */
337 if( AOUT_FMT_NON_LINEAR( &p_aout->output.output )
338 && !strcmp( psz_device, DEFAULT_ALSA_DEVICE ) )
340 snprintf( psz_default_iec_device, sizeof(psz_default_iec_device),
341 "iec958:AES0=0x%x,AES1=0x%x,AES2=0x%x,AES3=0x%x",
342 IEC958_AES0_CON_EMPHASIS_NONE | IEC958_AES0_NONAUDIO,
343 IEC958_AES1_CON_ORIGINAL | IEC958_AES1_CON_PCM_CODER,
345 ( p_aout->output.output.i_rate == 48000 ?
346 IEC958_AES3_CON_FS_48000 :
347 ( p_aout->output.output.i_rate == 44100 ?
348 IEC958_AES3_CON_FS_44100 : IEC958_AES3_CON_FS_32000 ) ) );
349 psz_iec_device = psz_default_iec_device;
351 else if( AOUT_FMT_NON_LINEAR( &p_aout->output.output ) )
353 psz_iec_device = psz_device;
357 psz_iec_device = NULL;
360 /* Choose the linear PCM format (read the comment above about FPU
364 i_vlc_pcm_format = VLC_CODEC_FL32;
365 i_snd_pcm_format = SND_PCM_FORMAT_FLOAT;
369 i_vlc_pcm_format = VLC_CODEC_S16N;
370 i_snd_pcm_format = SND_PCM_FORMAT_S16;
373 /* If the variable doesn't exist then it's the first time we're called
374 and we have to probe the available audio formats and channels */
375 if ( var_Type( p_aout, "audio-device" ) == 0 )
377 Probe( p_aout, psz_device, psz_iec_device, &i_snd_pcm_format );
380 if ( var_Get( p_aout, "audio-device", &val ) < 0 )
387 p_aout->output.output.i_format = i_vlc_pcm_format;
388 if ( val.i_int == AOUT_VAR_5_1 )
390 p_aout->output.output.i_physical_channels
391 = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER
392 | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT
395 psz_device = strdup( "surround51" );
397 else if ( val.i_int == AOUT_VAR_2F2R )
399 p_aout->output.output.i_physical_channels
400 = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT
401 | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT;
403 psz_device = strdup( "surround40" );
405 else if ( val.i_int == AOUT_VAR_STEREO )
407 p_aout->output.output.i_physical_channels
408 = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT;
410 else if ( val.i_int == AOUT_VAR_MONO )
412 p_aout->output.output.i_physical_channels = AOUT_CHAN_CENTER;
414 else if( val.i_int != AOUT_VAR_SPDIF )
416 /* This should not happen ! */
417 msg_Err( p_aout, "internal: can't find audio-device (%i)", val.i_int );
424 snd_output_stdio_attach( &p_sys->p_snd_stderr, stderr, 0 );
427 /* Open the device */
428 if ( val.i_int == AOUT_VAR_SPDIF )
430 if ( ( i_snd_rc = snd_pcm_open( &p_sys->p_snd_pcm, psz_iec_device,
431 SND_PCM_STREAM_PLAYBACK, 0 ) ) < 0 )
433 msg_Err( p_aout, "cannot open ALSA device `%s' (%s)",
434 psz_iec_device, snd_strerror( i_snd_rc ) );
435 dialog_Fatal( p_aout, _("Audio output failed"),
436 _("VLC could not open the ALSA device \"%s\" (%s)."),
437 psz_iec_device, snd_strerror( i_snd_rc ) );
442 i_buffer_size = ALSA_SPDIF_BUFFER_SIZE;
443 i_snd_pcm_format = SND_PCM_FORMAT_S16;
446 i_vlc_pcm_format = VLC_CODEC_SPDIFL;
447 p_aout->output.i_nb_samples = i_period_size = ALSA_SPDIF_PERIOD_SIZE;
448 p_aout->output.output.i_bytes_per_frame = AOUT_SPDIF_SIZE;
449 p_aout->output.output.i_frame_length = A52_FRAME_NB;
451 aout_VolumeNoneInit( p_aout );
457 msg_Dbg( p_aout, "opening ALSA device `%s'", psz_device );
459 /* Since it seems snd_pcm_close hasn't really released the device at
460 the time it returns, probe if the device is available in loop for 1s.
461 We cannot use blocking mode since the we would wait indefinitely when
462 switching from a dmx device to surround51. */
464 for( i = 10; i >= 0; i-- )
466 if ( ( i_snd_rc = snd_pcm_open( &p_sys->p_snd_pcm, psz_device,
467 SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK ) ) == -EBUSY )
469 if( i ) msleep( 100000 /* 100ms */ );
472 msg_Err( p_aout, "audio device: %s is already in use",
474 dialog_Fatal( p_aout, _("Audio output failed"),
475 _("The audio device \"%s\" is already in use."),
484 msg_Err( p_aout, "cannot open ALSA device `%s' (%s)",
485 psz_device, snd_strerror( i_snd_rc ) );
486 dialog_Fatal( p_aout, _("Audio output failed"),
487 _("VLC could not open the ALSA device \"%s\" (%s)."),
488 psz_device, snd_strerror( i_snd_rc ) );
494 /* We want blocking mode */
495 snd_pcm_nonblock( p_sys->p_snd_pcm, 0 );
497 i_buffer_size = ALSA_DEFAULT_BUFFER_SIZE;
498 i_channels = aout_FormatNbChannels( &p_aout->output.output );
500 p_aout->output.i_nb_samples = i_period_size = ALSA_DEFAULT_PERIOD_SIZE;
502 aout_VolumeSoftInit( p_aout );
505 /* Free psz_device so that all the remaining data is stack-allocated */
508 p_aout->output.pf_play = Play;
510 snd_pcm_hw_params_alloca(&p_hw);
511 snd_pcm_sw_params_alloca(&p_sw);
513 /* Due to some bugs in alsa with some drivers, we need to retry in s16l
514 if snd_pcm_hw_params fails in fl32 */
519 /* Get Initial hardware parameters */
520 if ( ( i_snd_rc = snd_pcm_hw_params_any( p_sys->p_snd_pcm, p_hw ) ) < 0 )
522 msg_Err( p_aout, "unable to retrieve initial hardware parameters (%s)",
523 snd_strerror( i_snd_rc ) );
528 if ( ( i_snd_rc = snd_pcm_hw_params_set_format( p_sys->p_snd_pcm, p_hw,
529 i_snd_pcm_format ) ) < 0 )
531 if( i_snd_pcm_format != SND_PCM_FORMAT_S16 )
533 i_snd_pcm_format = SND_PCM_FORMAT_S16;
534 i_snd_rc = snd_pcm_hw_params_set_format( p_sys->p_snd_pcm,
535 p_hw, i_snd_pcm_format );
539 msg_Err( p_aout, "unable to set stream sample size and "
540 "word order (%s)", snd_strerror( i_snd_rc ) );
544 if( i_vlc_pcm_format != VLC_CODEC_SPDIFL )
545 switch( i_snd_pcm_format )
547 case SND_PCM_FORMAT_FLOAT:
548 i_vlc_pcm_format = VLC_CODEC_FL32;
550 case SND_PCM_FORMAT_S16:
551 i_vlc_pcm_format = VLC_CODEC_S16N;
554 p_aout->output.output.i_format = i_vlc_pcm_format;
556 if ( ( i_snd_rc = snd_pcm_hw_params_set_access( p_sys->p_snd_pcm, p_hw,
557 SND_PCM_ACCESS_RW_INTERLEAVED ) ) < 0 )
559 msg_Err( p_aout, "unable to set interleaved stream format (%s)",
560 snd_strerror( i_snd_rc ) );
565 if ( ( i_snd_rc = snd_pcm_hw_params_set_channels( p_sys->p_snd_pcm, p_hw,
568 msg_Err( p_aout, "unable to set number of output channels (%s)",
569 snd_strerror( i_snd_rc ) );
574 i_old_rate = p_aout->output.output.i_rate;
575 i_snd_rc = snd_pcm_hw_params_set_rate_near( p_sys->p_snd_pcm, p_hw,
576 &p_aout->output.output.i_rate,
578 if( i_snd_rc < 0 || p_aout->output.output.i_rate != i_old_rate )
580 msg_Warn( p_aout, "The rate %d Hz is not supported by your " \
581 "hardware. Using %d Hz instead.\n", i_old_rate, \
582 p_aout->output.output.i_rate );
585 /* Set period size. */
586 if ( ( i_snd_rc = snd_pcm_hw_params_set_period_size_near( p_sys->p_snd_pcm,
587 p_hw, &i_period_size, NULL ) ) < 0 )
589 msg_Err( p_aout, "unable to set period size (%s)",
590 snd_strerror( i_snd_rc ) );
593 p_aout->output.i_nb_samples = i_period_size;
595 /* Set buffer size. */
596 if ( ( i_snd_rc = snd_pcm_hw_params_set_buffer_size_near( p_sys->p_snd_pcm,
597 p_hw, &i_buffer_size ) ) < 0 )
599 msg_Err( p_aout, "unable to set buffer size (%s)",
600 snd_strerror( i_snd_rc ) );
604 /* Commit hardware parameters. */
605 if ( ( i_snd_rc = snd_pcm_hw_params( p_sys->p_snd_pcm, p_hw ) ) < 0 )
607 if ( b_retry == false &&
608 i_snd_pcm_format == SND_PCM_FORMAT_FLOAT)
611 i_snd_pcm_format = SND_PCM_FORMAT_S16;
612 p_aout->output.output.i_format = VLC_CODEC_S16N;
613 msg_Warn( p_aout, "unable to commit hardware configuration "
614 "with fl32 samples. Retrying with s16l (%s)", snd_strerror( i_snd_rc ) );
618 msg_Err( p_aout, "unable to commit hardware configuration (%s)",
619 snd_strerror( i_snd_rc ) );
625 if( ( i_snd_rc = snd_pcm_hw_params_get_period_time( p_hw,
626 &p_sys->i_period_time, NULL ) ) < 0 )
628 msg_Err( p_aout, "unable to get period time (%s)",
629 snd_strerror( i_snd_rc ) );
633 /* Get Initial software parameters */
634 snd_pcm_sw_params_current( p_sys->p_snd_pcm, p_sw );
636 i_snd_rc = snd_pcm_sw_params_set_sleep_min( p_sys->p_snd_pcm, p_sw, 0 );
638 i_snd_rc = snd_pcm_sw_params_set_avail_min( p_sys->p_snd_pcm, p_sw,
639 p_aout->output.i_nb_samples );
640 /* start playing when one period has been written */
641 i_snd_rc = snd_pcm_sw_params_set_start_threshold( p_sys->p_snd_pcm, p_sw,
642 ALSA_DEFAULT_PERIOD_SIZE);
645 msg_Err( p_aout, "unable to set start threshold (%s)",
646 snd_strerror( i_snd_rc ) );
650 /* Commit software parameters. */
651 if ( snd_pcm_sw_params( p_sys->p_snd_pcm, p_sw ) < 0 )
653 msg_Err( p_aout, "unable to set software configuration" );
658 snd_output_printf( p_sys->p_snd_stderr, "\nALSA hardware setup:\n\n" );
659 snd_pcm_dump_hw_setup( p_sys->p_snd_pcm, p_sys->p_snd_stderr );
660 snd_output_printf( p_sys->p_snd_stderr, "\nALSA software setup:\n\n" );
661 snd_pcm_dump_sw_setup( p_sys->p_snd_pcm, p_sys->p_snd_stderr );
662 snd_output_printf( p_sys->p_snd_stderr, "\n" );
665 /* Create ALSA thread and wait for its readiness. */
666 if( vlc_thread_create( p_aout, "aout", ALSAThread,
667 VLC_THREAD_PRIORITY_OUTPUT ) )
669 msg_Err( p_aout, "cannot create ALSA thread (%m)" );
676 snd_pcm_close( p_sys->p_snd_pcm );
678 snd_output_close( p_sys->p_snd_stderr );
684 /*****************************************************************************
685 * Play: nothing to do
686 *****************************************************************************/
687 static void Play( aout_instance_t *p_aout )
689 if( !p_aout->output.p_sys->b_playing )
691 p_aout->output.p_sys->b_playing = true;
693 /* get the playing date of the first aout buffer */
694 vlc_mutex_lock( &p_aout->output.p_sys->lock );
695 p_aout->output.p_sys->start_date =
696 aout_FifoFirstDate( p_aout, &p_aout->output.fifo );
698 /* wake up the audio output thread */
699 vlc_cond_signal( &p_aout->output.p_sys->wait );
700 vlc_mutex_unlock( &p_aout->output.p_sys->lock );
704 /*****************************************************************************
705 * Close: close the ALSA device
706 *****************************************************************************/
707 static void Close( vlc_object_t *p_this )
709 aout_instance_t *p_aout = (aout_instance_t *)p_this;
710 struct aout_sys_t * p_sys = p_aout->output.p_sys;
713 /* Make sure that the thread will stop once it is waken up */
714 vlc_object_kill( p_aout );
716 /* make sure the audio output thread is waken up */
717 vlc_mutex_lock( &p_aout->output.p_sys->lock );
718 vlc_cond_signal( &p_aout->output.p_sys->wait );
719 vlc_mutex_unlock( &p_aout->output.p_sys->lock );
722 vlc_thread_join( p_aout );
723 p_aout->b_die = false;
725 i_snd_rc = snd_pcm_close( p_sys->p_snd_pcm );
729 msg_Err( p_aout, "failed closing ALSA device (%s)",
730 snd_strerror( i_snd_rc ) );
734 snd_output_close( p_sys->p_snd_stderr );
740 /*****************************************************************************
741 * ALSAThread: asynchronous thread used to DMA the data to the device
742 *****************************************************************************/
743 static void* ALSAThread( vlc_object_t* p_this )
745 aout_instance_t * p_aout = (aout_instance_t*)p_this;
746 struct aout_sys_t * p_sys = p_aout->output.p_sys;
747 int canc = vlc_savecancel ();
748 p_sys->p_status = (snd_pcm_status_t *)malloc(snd_pcm_status_sizeof());
750 /* Wait for the exact time to start playing (avoids resampling) */
751 vlc_mutex_lock( &p_sys->lock );
752 while( !p_sys->start_date && vlc_object_alive (p_aout) )
753 vlc_cond_wait( &p_sys->wait, &p_sys->lock );
754 vlc_mutex_unlock( &p_sys->lock );
756 if( !vlc_object_alive (p_aout) )
759 mwait( p_sys->start_date - AOUT_PTS_TOLERANCE / 4 );
761 while ( vlc_object_alive (p_aout) )
767 snd_pcm_drop( p_sys->p_snd_pcm );
768 free( p_aout->output.p_sys->p_status );
769 vlc_restorecancel (canc);
773 /*****************************************************************************
774 * ALSAFill: function used to fill the ALSA buffer as much as possible
775 *****************************************************************************/
776 static void ALSAFill( aout_instance_t * p_aout )
778 struct aout_sys_t * p_sys = p_aout->output.p_sys;
779 aout_buffer_t * p_buffer;
780 snd_pcm_status_t * p_status = p_sys->p_status;
784 /* Fill in the buffer until space or audio output buffer shortage */
787 i_snd_rc = snd_pcm_status( p_sys->p_snd_pcm, p_status );
790 msg_Err( p_aout, "cannot get device status" );
794 /* Handle buffer underruns and get the status again */
795 if( snd_pcm_status_get_state( p_status ) == SND_PCM_STATE_XRUN )
797 /* Prepare the device */
798 i_snd_rc = snd_pcm_prepare( p_sys->p_snd_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_sys->p_snd_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_sys->p_snd_pcm, &delay ) < 0 )
825 delay = 0; /* FIXME: use a positive minimal delay */
826 int i_bytes = snd_pcm_frames_to_bytes( p_sys->p_snd_pcm, delay );
827 next_date = mdate() + ( (mtime_t)i_bytes * 1000000
828 / p_aout->output.output.i_bytes_per_frame
829 / p_aout->output.output.i_rate
830 * p_aout->output.output.i_frame_length );
833 snd_pcm_state_t state = snd_pcm_status_get_state( p_status );
834 if( state != SND_PCM_STATE_RUNNING )
835 msg_Err( p_aout, "pcm status (%d) != RUNNING", state );
837 msg_Dbg( p_aout, "Delay is %ld frames (%d bytes)", delay, i_bytes );
839 msg_Dbg( p_aout, "Bytes per frame: %d", p_aout->output.output.i_bytes_per_frame );
840 msg_Dbg( p_aout, "Rate: %d", p_aout->output.output.i_rate );
841 msg_Dbg( p_aout, "Frame length: %d", p_aout->output.output.i_frame_length );
843 msg_Dbg( p_aout, "Next date is in %d microseconds", (int)(next_date - mdate()) );
847 p_buffer = aout_OutputNextBuffer( p_aout, next_date,
848 (p_aout->output.output.i_format == VLC_CODEC_SPDIFL) );
850 /* Audio output buffer shortage -> stop the fill process and wait */
851 if( p_buffer == NULL )
856 i_snd_rc = snd_pcm_writei( p_sys->p_snd_pcm, p_buffer->p_buffer,
857 p_buffer->i_nb_samples );
858 if( i_snd_rc != -ESTRPIPE )
861 /* a suspend event occurred
862 * (stream is suspended and waiting for an application recovery) */
863 msg_Dbg( p_aout, "entering in suspend mode, trying to resume..." );
865 while( vlc_object_alive (p_aout) && vlc_object_alive (p_aout->p_libvlc) &&
866 ( i_snd_rc = snd_pcm_resume( p_sys->p_snd_pcm ) ) == -EAGAIN )
872 /* Device does not supprot resuming, restart it */
873 i_snd_rc = snd_pcm_prepare( p_sys->p_snd_pcm );
878 msg_Err( p_aout, "cannot write: %s", snd_strerror( i_snd_rc ) );
880 aout_BufferFree( p_buffer );
885 msg_Err( p_aout, "ALSA error: %s", snd_strerror( i_snd_rc ) );
886 msleep( p_sys->i_period_time >> 1 );
889 static void GetDevicesForCard( module_config_t *p_item, int i_card );
890 static void GetDevices( module_config_t *p_item );
892 /*****************************************************************************
893 * config variable callback
894 *****************************************************************************/
895 static int FindDevicesCallback( vlc_object_t *p_this, char const *psz_name,
896 vlc_value_t newval, vlc_value_t oldval, void *p_unused )
898 module_config_t *p_item;
904 p_item = config_FindConfig( p_this, psz_name );
905 if( !p_item ) return VLC_SUCCESS;
907 /* Clear-up the current list */
910 /* Keep the first entrie */
911 for( i = 1; i < p_item->i_list; i++ )
913 free( (char *)p_item->ppsz_list[i] );
914 free( (char *)p_item->ppsz_list_text[i] );
916 /* TODO: Remove when no more needed */
917 p_item->ppsz_list[i] = NULL;
918 p_item->ppsz_list_text[i] = NULL;
922 GetDevices( p_item );
924 /* Signal change to the interface */
925 p_item->b_dirty = true;
931 static void GetDevicesForCard( module_config_t *p_item, int i_card )
933 int i_pcm_device = -1;
935 snd_pcm_info_t *p_pcm_info;
940 sprintf( psz_dev, "hw:%i", i_card );
942 if( ( i_err = snd_ctl_open( &p_ctl, psz_dev, 0 ) ) < 0 )
945 if( ( i_err = snd_card_get_name( i_card, &psz_card_name ) ) != 0)
946 psz_card_name = _("Unknown soundcard");
948 snd_pcm_info_alloca( &p_pcm_info );
952 char *psz_device, *psz_descr;
953 if( ( i_err = snd_ctl_pcm_next_device( p_ctl, &i_pcm_device ) ) < 0 )
955 if( i_pcm_device < 0 )
958 snd_pcm_info_set_device( p_pcm_info, i_pcm_device );
959 snd_pcm_info_set_subdevice( p_pcm_info, 0 );
960 snd_pcm_info_set_stream( p_pcm_info, SND_PCM_STREAM_PLAYBACK );
962 if( ( i_err = snd_ctl_pcm_info( p_ctl, p_pcm_info ) ) < 0 )
964 if( i_err != -ENOENT )
966 /*printf( "get_devices_for_card(): "
967 "snd_ctl_pcm_info() "
968 "failed (%d:%d): %s.\n", i_card,
969 i_pcm_device, snd_strerror( -i_err ) );*/
974 if( asprintf( &psz_device, "hw:%d,%d", i_card, i_pcm_device ) == -1 )
976 if( asprintf( &psz_descr, "%s: %s (%s)", psz_card_name,
977 snd_pcm_info_get_name(p_pcm_info), psz_device ) == -1 )
984 (char **)realloc( p_item->ppsz_list,
985 (p_item->i_list + 2) * sizeof(char *) );
986 p_item->ppsz_list_text =
987 (char **)realloc( p_item->ppsz_list_text,
988 (p_item->i_list + 2) * sizeof(char *) );
989 p_item->ppsz_list[ p_item->i_list ] = psz_device;
990 p_item->ppsz_list_text[ p_item->i_list ] = psz_descr;
992 p_item->ppsz_list[ p_item->i_list ] = NULL;
993 p_item->ppsz_list_text[ p_item->i_list ] = NULL;
996 snd_ctl_close( p_ctl );
1001 static void GetDevices( module_config_t *p_item )
1006 if( ( i_err = snd_card_next( &i_card ) ) != 0 )
1008 /*printf( "snd_card_next() failed: %s", snd_strerror( -i_err ) );*/
1012 while( i_card > -1 )
1014 GetDevicesForCard( p_item, i_card );
1015 if( ( i_err = snd_card_next( &i_card ) ) != 0 )
1017 /*printf( "snd_card_next() failed: %s", snd_strerror( -i_err ) );*/