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_interface.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 = (char*)N_("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 = (char*)N_("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 = (char*)N_("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 = (char*)"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 useable 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 );
278 var_Set( p_aout, "intf-change", val );
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 intf_UserFatal( p_aout, false, _("No Audio Device"),
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
362 if( vlc_CPU() & CPU_CAPABILITY_FPU )
364 i_vlc_pcm_format = VLC_FOURCC('f','l','3','2');
365 i_snd_pcm_format = SND_PCM_FORMAT_FLOAT;
369 i_vlc_pcm_format = AOUT_FMT_S16_NE;
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 intf_UserFatal( p_aout, false, _("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_FOURCC('s','p','d','i');
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 intf_UserFatal( p_aout, false, _("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 intf_UserFatal( p_aout, false, _("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_FOURCC('s','p','d','i') )
545 switch( i_snd_pcm_format )
547 case SND_PCM_FORMAT_FLOAT:
548 i_vlc_pcm_format = VLC_FOURCC('f','l','3','2');
550 case SND_PCM_FORMAT_S16:
551 i_vlc_pcm_format = AOUT_FMT_S16_NE;
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 #ifdef HAVE_ALSA_NEW_API
576 i_snd_rc = snd_pcm_hw_params_set_rate_near( p_sys->p_snd_pcm, p_hw,
577 &p_aout->output.output.i_rate,
580 i_snd_rc = snd_pcm_hw_params_set_rate_near( p_sys->p_snd_pcm, p_hw,
581 p_aout->output.output.i_rate,
584 if( i_snd_rc < 0 || p_aout->output.output.i_rate != i_old_rate )
586 msg_Warn( p_aout, "The rate %d Hz is not supported by your " \
587 "hardware. Using %d Hz instead.\n", i_old_rate, \
588 p_aout->output.output.i_rate );
591 /* Set period size. */
592 #ifdef HAVE_ALSA_NEW_API
593 if ( ( i_snd_rc = snd_pcm_hw_params_set_period_size_near( p_sys->p_snd_pcm,
594 p_hw, &i_period_size, NULL ) ) < 0 )
596 if ( ( i_snd_rc = snd_pcm_hw_params_set_period_size_near( p_sys->p_snd_pcm,
597 p_hw, i_period_size, NULL ) ) < 0 )
600 msg_Err( p_aout, "unable to set period size (%s)",
601 snd_strerror( i_snd_rc ) );
604 p_aout->output.i_nb_samples = i_period_size;
606 /* Set buffer size. */
607 #ifdef HAVE_ALSA_NEW_API
608 if ( ( i_snd_rc = snd_pcm_hw_params_set_buffer_size_near( p_sys->p_snd_pcm,
609 p_hw, &i_buffer_size ) ) < 0 )
611 if ( ( i_snd_rc = snd_pcm_hw_params_set_buffer_size_near( p_sys->p_snd_pcm,
612 p_hw, i_buffer_size ) ) < 0 )
615 msg_Err( p_aout, "unable to set buffer size (%s)",
616 snd_strerror( i_snd_rc ) );
620 /* Commit hardware parameters. */
621 if ( ( i_snd_rc = snd_pcm_hw_params( p_sys->p_snd_pcm, p_hw ) ) < 0 )
623 if ( b_retry == false &&
624 i_snd_pcm_format == SND_PCM_FORMAT_FLOAT)
627 i_snd_pcm_format = SND_PCM_FORMAT_S16;
628 p_aout->output.output.i_format = AOUT_FMT_S16_NE;
629 msg_Warn( p_aout, "unable to commit hardware configuration "
630 "with fl32 samples. Retrying with s16l (%s)", snd_strerror( i_snd_rc ) );
634 msg_Err( p_aout, "unable to commit hardware configuration (%s)",
635 snd_strerror( i_snd_rc ) );
641 #ifdef HAVE_ALSA_NEW_API
642 if( ( i_snd_rc = snd_pcm_hw_params_get_period_time( p_hw,
643 &p_sys->i_period_time, NULL ) ) < 0 )
645 if( ( p_sys->i_period_time =
646 (int)snd_pcm_hw_params_get_period_time( p_hw, NULL ) ) < 0 )
649 msg_Err( p_aout, "unable to get period time (%s)",
650 snd_strerror( i_snd_rc ) );
654 /* Get Initial software parameters */
655 snd_pcm_sw_params_current( p_sys->p_snd_pcm, p_sw );
657 i_snd_rc = snd_pcm_sw_params_set_sleep_min( p_sys->p_snd_pcm, p_sw, 0 );
659 i_snd_rc = snd_pcm_sw_params_set_avail_min( p_sys->p_snd_pcm, p_sw,
660 p_aout->output.i_nb_samples );
661 /* start playing when one period has been written */
662 i_snd_rc = snd_pcm_sw_params_set_start_threshold( p_sys->p_snd_pcm, p_sw,
663 ALSA_DEFAULT_PERIOD_SIZE);
666 msg_Err( p_aout, "unable to set start threshold (%s)",
667 snd_strerror( i_snd_rc ) );
671 /* Commit software parameters. */
672 if ( snd_pcm_sw_params( p_sys->p_snd_pcm, p_sw ) < 0 )
674 msg_Err( p_aout, "unable to set software configuration" );
679 snd_output_printf( p_sys->p_snd_stderr, "\nALSA hardware setup:\n\n" );
680 snd_pcm_dump_hw_setup( p_sys->p_snd_pcm, p_sys->p_snd_stderr );
681 snd_output_printf( p_sys->p_snd_stderr, "\nALSA software setup:\n\n" );
682 snd_pcm_dump_sw_setup( p_sys->p_snd_pcm, p_sys->p_snd_stderr );
683 snd_output_printf( p_sys->p_snd_stderr, "\n" );
686 /* Create ALSA thread and wait for its readiness. */
687 if( vlc_thread_create( p_aout, "aout", ALSAThread,
688 VLC_THREAD_PRIORITY_OUTPUT, false ) )
690 msg_Err( p_aout, "cannot create ALSA thread (%m)" );
697 snd_pcm_close( p_sys->p_snd_pcm );
699 snd_output_close( p_sys->p_snd_stderr );
705 /*****************************************************************************
706 * Play: nothing to do
707 *****************************************************************************/
708 static void Play( aout_instance_t *p_aout )
710 if( !p_aout->output.p_sys->b_playing )
712 p_aout->output.p_sys->b_playing = 1;
714 /* get the playing date of the first aout buffer */
715 p_aout->output.p_sys->start_date =
716 aout_FifoFirstDate( p_aout, &p_aout->output.fifo );
718 /* wake up the audio output thread */
719 vlc_mutex_lock( &p_aout->output.p_sys->lock );
720 vlc_cond_signal( &p_aout->output.p_sys->wait );
721 vlc_mutex_unlock( &p_aout->output.p_sys->lock );
725 /*****************************************************************************
726 * Close: close the ALSA device
727 *****************************************************************************/
728 static void Close( vlc_object_t *p_this )
730 aout_instance_t *p_aout = (aout_instance_t *)p_this;
731 struct aout_sys_t * p_sys = p_aout->output.p_sys;
734 /* Make sure that the thread will stop once it is waken up */
735 vlc_object_kill( p_aout );
737 /* make sure the audio output thread is waken up */
738 vlc_mutex_lock( &p_aout->output.p_sys->lock );
739 vlc_cond_signal( &p_aout->output.p_sys->wait );
740 vlc_mutex_unlock( &p_aout->output.p_sys->lock );
743 vlc_thread_join( p_aout );
744 p_aout->b_die = false;
746 i_snd_rc = snd_pcm_close( p_sys->p_snd_pcm );
750 msg_Err( p_aout, "failed closing ALSA device (%s)",
751 snd_strerror( i_snd_rc ) );
755 snd_output_close( p_sys->p_snd_stderr );
761 /*****************************************************************************
762 * ALSAThread: asynchronous thread used to DMA the data to the device
763 *****************************************************************************/
764 static void* ALSAThread( vlc_object_t* p_this )
766 aout_instance_t * p_aout = (aout_instance_t*)p_this;
767 struct aout_sys_t * p_sys = p_aout->output.p_sys;
768 int canc = vlc_savecancel ();
769 p_sys->p_status = (snd_pcm_status_t *)malloc(snd_pcm_status_sizeof());
771 /* Wait for the exact time to start playing (avoids resampling) */
772 vlc_mutex_lock( &p_sys->lock );
773 while( !p_sys->start_date && vlc_object_alive (p_aout) )
774 vlc_cond_wait( &p_sys->wait, &p_sys->lock );
775 vlc_mutex_unlock( &p_sys->lock );
777 if( !vlc_object_alive (p_aout) )
780 mwait( p_sys->start_date - AOUT_PTS_TOLERANCE / 4 );
782 while ( vlc_object_alive (p_aout) )
788 snd_pcm_drop( p_sys->p_snd_pcm );
789 free( p_aout->output.p_sys->p_status );
790 vlc_restorecancel (canc);
794 /*****************************************************************************
795 * ALSAFill: function used to fill the ALSA buffer as much as possible
796 *****************************************************************************/
797 static void ALSAFill( aout_instance_t * p_aout )
799 struct aout_sys_t * p_sys = p_aout->output.p_sys;
800 aout_buffer_t * p_buffer;
801 snd_pcm_status_t * p_status = p_sys->p_status;
805 /* Fill in the buffer until space or audio output buffer shortage */
808 i_snd_rc = snd_pcm_status( p_sys->p_snd_pcm, p_status );
811 msg_Err( p_aout, "cannot get device status" );
815 /* Handle buffer underruns and get the status again */
816 if( snd_pcm_status_get_state( p_status ) == SND_PCM_STATE_XRUN )
818 /* Prepare the device */
819 i_snd_rc = snd_pcm_prepare( p_sys->p_snd_pcm );
823 msg_Err( p_aout, "cannot recover from buffer underrun" );
827 msg_Dbg( p_aout, "recovered from buffer underrun" );
829 /* Get the new status */
830 i_snd_rc = snd_pcm_status( p_sys->p_snd_pcm, p_status );
833 msg_Err( p_aout, "cannot get device status after recovery" );
837 /* Underrun, try to recover as quickly as possible */
842 /* Here the device should be in RUNNING state, p_status is valid. */
843 snd_pcm_sframes_t delay = snd_pcm_status_get_delay( p_status );
844 if( delay == 0 ) /* workaround buggy alsa drivers */
845 if( snd_pcm_delay( p_sys->p_snd_pcm, &delay ) < 0 )
846 delay = 0; /* FIXME: use a positive minimal delay */
847 int i_bytes = snd_pcm_frames_to_bytes( p_sys->p_snd_pcm, delay );
848 next_date = mdate() + ( (mtime_t)i_bytes * 1000000
849 / p_aout->output.output.i_bytes_per_frame
850 / p_aout->output.output.i_rate
851 * p_aout->output.output.i_frame_length );
854 snd_pcm_state_t state = snd_pcm_status_get_state( p_status );
855 if( state != SND_PCM_STATE_RUNNING )
856 msg_Err( p_aout, "pcm status (%d) != RUNNING", state );
858 msg_Dbg( p_aout, "Delay is %ld frames (%d bytes)", delay, i_bytes );
860 msg_Dbg( p_aout, "Bytes per frame: %d", p_aout->output.output.i_bytes_per_frame );
861 msg_Dbg( p_aout, "Rate: %d", p_aout->output.output.i_rate );
862 msg_Dbg( p_aout, "Frame length: %d", p_aout->output.output.i_frame_length );
864 msg_Dbg( p_aout, "Next date is in %d microseconds", (int)(next_date - mdate()) );
868 p_buffer = aout_OutputNextBuffer( p_aout, next_date,
869 (p_aout->output.output.i_format == VLC_FOURCC('s','p','d','i')) );
871 /* Audio output buffer shortage -> stop the fill process and wait */
872 if( p_buffer == NULL )
877 i_snd_rc = snd_pcm_writei( p_sys->p_snd_pcm, p_buffer->p_buffer,
878 p_buffer->i_nb_samples );
879 if( i_snd_rc != -ESTRPIPE )
882 /* a suspend event occurred
883 * (stream is suspended and waiting for an application recovery) */
884 msg_Dbg( p_aout, "entering in suspend mode, trying to resume..." );
886 while( vlc_object_alive (p_aout) && vlc_object_alive (p_aout->p_libvlc) &&
887 ( i_snd_rc = snd_pcm_resume( p_sys->p_snd_pcm ) ) == -EAGAIN )
893 /* Device does not supprot resuming, restart it */
894 i_snd_rc = snd_pcm_prepare( p_sys->p_snd_pcm );
899 msg_Err( p_aout, "cannot write: %s", snd_strerror( i_snd_rc ) );
901 aout_BufferFree( p_buffer );
906 msg_Err( p_aout, "ALSA error: %s", snd_strerror( i_snd_rc ) );
907 msleep( p_sys->i_period_time >> 1 );
910 static void GetDevicesForCard( module_config_t *p_item, int i_card );
911 static void GetDevices( module_config_t *p_item );
913 /*****************************************************************************
914 * config variable callback
915 *****************************************************************************/
916 static int FindDevicesCallback( vlc_object_t *p_this, char const *psz_name,
917 vlc_value_t newval, vlc_value_t oldval, void *p_unused )
919 module_config_t *p_item;
925 p_item = config_FindConfig( p_this, psz_name );
926 if( !p_item ) return VLC_SUCCESS;
928 /* Clear-up the current list */
931 /* Keep the first entrie */
932 for( i = 1; i < p_item->i_list; i++ )
934 free( (char *)p_item->ppsz_list[i] );
935 free( (char *)p_item->ppsz_list_text[i] );
937 /* TODO: Remove when no more needed */
938 p_item->ppsz_list[i] = NULL;
939 p_item->ppsz_list_text[i] = NULL;
943 GetDevices( p_item );
945 /* Signal change to the interface */
946 p_item->b_dirty = true;
952 static void GetDevicesForCard( module_config_t *p_item, int i_card )
954 int i_pcm_device = -1;
956 snd_pcm_info_t *p_pcm_info;
961 sprintf( psz_dev, "hw:%i", i_card );
963 if( ( i_err = snd_ctl_open( &p_ctl, psz_dev, 0 ) ) < 0 )
966 if( ( i_err = snd_card_get_name( i_card, &psz_card_name ) ) != 0)
967 psz_card_name = _("Unknown soundcard");
969 snd_pcm_info_alloca( &p_pcm_info );
973 char *psz_device, *psz_descr;
974 if( ( i_err = snd_ctl_pcm_next_device( p_ctl, &i_pcm_device ) ) < 0 )
976 if( i_pcm_device < 0 )
979 snd_pcm_info_set_device( p_pcm_info, i_pcm_device );
980 snd_pcm_info_set_subdevice( p_pcm_info, 0 );
981 snd_pcm_info_set_stream( p_pcm_info, SND_PCM_STREAM_PLAYBACK );
983 if( ( i_err = snd_ctl_pcm_info( p_ctl, p_pcm_info ) ) < 0 )
985 if( i_err != -ENOENT )
987 /*printf( "get_devices_for_card(): "
988 "snd_ctl_pcm_info() "
989 "failed (%d:%d): %s.\n", i_card,
990 i_pcm_device, snd_strerror( -i_err ) );*/
995 if( asprintf( &psz_device, "hw:%d,%d", i_card, i_pcm_device ) == -1 )
997 if( asprintf( &psz_descr, "%s: %s (%s)", psz_card_name,
998 snd_pcm_info_get_name(p_pcm_info), psz_device ) == -1 )
1005 (char **)realloc( p_item->ppsz_list,
1006 (p_item->i_list + 2) * sizeof(char *) );
1007 p_item->ppsz_list_text =
1008 (char **)realloc( p_item->ppsz_list_text,
1009 (p_item->i_list + 2) * sizeof(char *) );
1010 p_item->ppsz_list[ p_item->i_list ] = psz_device;
1011 p_item->ppsz_list_text[ p_item->i_list ] = psz_descr;
1013 p_item->ppsz_list[ p_item->i_list ] = NULL;
1014 p_item->ppsz_list_text[ p_item->i_list ] = NULL;
1017 snd_ctl_close( p_ctl );
1022 static void GetDevices( module_config_t *p_item )
1027 if( ( i_err = snd_card_next( &i_card ) ) != 0 )
1029 /*printf( "snd_card_next() failed: %s", snd_strerror( -i_err ) );*/
1033 while( i_card > -1 )
1035 GetDevicesForCard( p_item, i_card );
1036 if( ( i_err = snd_card_next( &i_card ) ) != 0 )
1038 /*printf( "snd_card_next() failed: %s", snd_strerror( -i_err ) );*/