/*****************************************************************************
* Preamble
*****************************************************************************/
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
#include <vlc/vlc.h>
+#include <vlc_plugin.h>
#include <errno.h> /* ENOMEM */
#include <vlc_interface.h>
#define ALSA_PCM_NEW_SW_PARAMS_API
#include <alsa/asoundlib.h>
+/*#define ALSA_DEBUG*/
+
/*****************************************************************************
* aout_sys_t: ALSA audio output method descriptor
*****************************************************************************
set_category( CAT_AUDIO );
set_subcategory( SUBCAT_AUDIO_AOUT );
add_string( "alsadev", DEFAULT_ALSA_DEVICE, aout_FindAndRestart,
- N_("ALSA Device Name"), NULL, VLC_FALSE );
+ N_("ALSA Device Name"), NULL, false );
change_string_list( ppsz_devices, ppsz_devices_text, FindDevicesCallback );
change_action_add( FindDevicesCallback, N_("Refresh list") );
/* Add final settings to the variable */
var_AddCallback( p_aout, "audio-device", aout_ChannelsRestart, NULL );
- val.b_bool = VLC_TRUE;
+ val.b_bool = true;
var_Set( p_aout, "intf-change", val );
}
int i_snd_rc = -1;
unsigned int i_old_rate;
- vlc_bool_t b_retry = VLC_TRUE;
+ bool b_retry = true;
/* Allocate structures */
p_aout->output.p_sys = p_sys = malloc( sizeof( aout_sys_t ) );
msg_Err( p_aout, "out of memory" );
return VLC_ENOMEM;
}
- p_sys->b_playing = VLC_FALSE;
+ p_sys->b_playing = false;
p_sys->start_date = 0;
vlc_cond_init( p_aout, &p_sys->wait );
- vlc_mutex_init( p_aout, &p_sys->lock );
+ vlc_mutex_init( &p_sys->lock );
/* Get device name */
if( (psz_device = config_GetPsz( p_aout, "alsadev" )) == NULL )
{
msg_Err( p_aout, "no audio device given (maybe \"default\" ?)" );
- intf_UserFatal( p_aout, VLC_FALSE, _("No Audio Device"),
+ intf_UserFatal( p_aout, false, _("No Audio Device"),
_("No audio device name was given. You might want to " \
"enter \"default\".") );
free( p_sys );
{
msg_Err( p_aout, "cannot open ALSA device `%s' (%s)",
psz_iec_device, snd_strerror( i_snd_rc ) );
- intf_UserFatal( p_aout, VLC_FALSE, _("Audio output failed"),
+ intf_UserFatal( p_aout, false, _("Audio output failed"),
_("VLC could not open the ALSA device \"%s\" (%s)."),
psz_iec_device, snd_strerror( i_snd_rc ) );
free( p_sys );
{
msg_Err( p_aout, "audio device: %s is already in use",
psz_device );
- intf_UserFatal( p_aout, VLC_FALSE, _("Audio output failed"),
+ intf_UserFatal( p_aout, false, _("Audio output failed"),
_("The audio device \"%s\" is already in use."),
psz_device );
}
{
msg_Err( p_aout, "cannot open ALSA device `%s' (%s)",
psz_device, snd_strerror( i_snd_rc ) );
- intf_UserFatal( p_aout, VLC_FALSE, _("Audio output failed"),
+ intf_UserFatal( p_aout, false, _("Audio output failed"),
_("VLC could not open the ALSA device \"%s\" (%s)."),
psz_device, snd_strerror( i_snd_rc ) );
free( p_sys );
if snd_pcm_hw_params fails in fl32 */
while ( b_retry )
{
- b_retry = VLC_FALSE;
+ b_retry = false;
/* Get Initial hardware parameters */
if ( ( i_snd_rc = snd_pcm_hw_params_any( p_sys->p_snd_pcm, p_hw ) ) < 0 )
p_aout->output.output.i_rate );
}
- /* Set buffer size. */
+ /* Set period size. */
#ifdef HAVE_ALSA_NEW_API
- if ( ( i_snd_rc = snd_pcm_hw_params_set_buffer_size_near( p_sys->p_snd_pcm,
- p_hw, &i_buffer_size ) ) < 0 )
+ if ( ( i_snd_rc = snd_pcm_hw_params_set_period_size_near( p_sys->p_snd_pcm,
+ p_hw, &i_period_size, NULL ) ) < 0 )
#else
- if ( ( i_snd_rc = snd_pcm_hw_params_set_buffer_size_near( p_sys->p_snd_pcm,
- p_hw, i_buffer_size ) ) < 0 )
+ if ( ( i_snd_rc = snd_pcm_hw_params_set_period_size_near( p_sys->p_snd_pcm,
+ p_hw, i_period_size, NULL ) ) < 0 )
#endif
{
- msg_Err( p_aout, "unable to set buffer size (%s)",
+ msg_Err( p_aout, "unable to set period size (%s)",
snd_strerror( i_snd_rc ) );
goto error;
}
+ p_aout->output.i_nb_samples = i_period_size;
- /* Set period size. */
+/* Set buffer size. */
#ifdef HAVE_ALSA_NEW_API
- if ( ( i_snd_rc = snd_pcm_hw_params_set_period_size_near( p_sys->p_snd_pcm,
- p_hw, &i_period_size, NULL ) ) < 0 )
+ if ( ( i_snd_rc = snd_pcm_hw_params_set_buffer_size_near( p_sys->p_snd_pcm,
+ p_hw, &i_buffer_size ) ) < 0 )
#else
- if ( ( i_snd_rc = snd_pcm_hw_params_set_period_size_near( p_sys->p_snd_pcm,
- p_hw, i_period_size, NULL ) ) < 0 )
+ if ( ( i_snd_rc = snd_pcm_hw_params_set_buffer_size_near( p_sys->p_snd_pcm,
+ p_hw, i_buffer_size ) ) < 0 )
#endif
{
- msg_Err( p_aout, "unable to set period size (%s)",
+ msg_Err( p_aout, "unable to set buffer size (%s)",
snd_strerror( i_snd_rc ) );
goto error;
}
- p_aout->output.i_nb_samples = i_period_size;
/* Commit hardware parameters. */
if ( ( i_snd_rc = snd_pcm_hw_params( p_sys->p_snd_pcm, p_hw ) ) < 0 )
{
- if ( b_retry == VLC_FALSE &&
+ if ( b_retry == false &&
i_snd_pcm_format == SND_PCM_FORMAT_FLOAT)
{
- b_retry = VLC_TRUE;
+ b_retry = true;
i_snd_pcm_format = SND_PCM_FORMAT_S16;
p_aout->output.output.i_format = AOUT_FMT_S16_NE;
msg_Warn( p_aout, "unable to commit hardware configuration "
/* Create ALSA thread and wait for its readiness. */
if( vlc_thread_create( p_aout, "aout", ALSAThread,
- VLC_THREAD_PRIORITY_OUTPUT, VLC_FALSE ) )
+ VLC_THREAD_PRIORITY_OUTPUT, false ) )
{
msg_Err( p_aout, "cannot create ALSA thread (%m)" );
goto error;
vlc_object_kill( p_aout );
vlc_thread_join( p_aout );
- p_aout->b_die = VLC_FALSE;
+ p_aout->b_die = false;
i_snd_rc = snd_pcm_close( p_sys->p_snd_pcm );
/* Wait for the exact time to start playing (avoids resampling) */
vlc_mutex_lock( &p_sys->lock );
- while( !p_sys->start_date )
+ while( !p_sys->start_date && !p_aout->b_die )
vlc_cond_wait( &p_sys->wait, &p_sys->lock );
vlc_mutex_unlock( &p_sys->lock );
+ if( p_aout->b_die )
+ goto cleanup;
+
mwait( p_sys->start_date - AOUT_PTS_TOLERANCE / 4 );
while ( !p_aout->b_die )
ALSAFill( p_aout );
}
+cleanup:
snd_pcm_drop( p_sys->p_snd_pcm );
free( p_aout->output.p_sys->p_status );
return 0;
mtime_t next_date;
/* Fill in the buffer until space or audio output buffer shortage */
+
+ /* Get the status */
+ i_snd_rc = snd_pcm_status( p_sys->p_snd_pcm, p_status );
+ if( i_snd_rc < 0 )
{
- /* Get the status */
- i_snd_rc = snd_pcm_status( p_sys->p_snd_pcm, p_status );
- if( i_snd_rc < 0 )
- {
- msg_Err( p_aout, "unable to get the device's status (%s)",
- snd_strerror( i_snd_rc ) );
+ msg_Err( p_aout, "cannot get device status" );
+ goto error;
+ }
- msleep( p_sys->i_period_time >> 1 );
- return;
+ /* Handle buffer underruns and get the status again */
+ if( snd_pcm_status_get_state( p_status ) == SND_PCM_STATE_XRUN )
+ {
+ /* Prepare the device */
+ i_snd_rc = snd_pcm_prepare( p_sys->p_snd_pcm );
+
+ if( i_snd_rc )
+ {
+ msg_Err( p_aout, "cannot recover from buffer underrun" );
+ goto error;
}
- /* Handle buffer underruns and get the status again */
- if( snd_pcm_status_get_state( p_status ) == SND_PCM_STATE_XRUN )
+ msg_Dbg( p_aout, "recovered from buffer underrun" );
+
+ /* Get the new status */
+ i_snd_rc = snd_pcm_status( p_sys->p_snd_pcm, p_status );
+ if( i_snd_rc < 0 )
{
- /* Prepare the device */
- i_snd_rc = snd_pcm_prepare( p_sys->p_snd_pcm );
+ msg_Err( p_aout, "cannot get device status after recovery" );
+ goto error;
+ }
- if( i_snd_rc == 0 )
- {
- msg_Dbg( p_aout, "recovered from buffer underrun" );
+ /* Underrun, try to recover as quickly as possible */
+ next_date = mdate();
+ }
+ else
+ {
+ /* Here the device should be in RUNNING state, p_status is valid. */
+ snd_pcm_sframes_t delay = snd_pcm_status_get_delay( p_status );
+ if( delay == 0 ) /* workaround buggy alsa drivers */
+ if( snd_pcm_delay( p_sys->p_snd_pcm, &delay ) < 0 )
+ delay = 0; /* FIXME: use a positive minimal delay */
+ int i_bytes = snd_pcm_frames_to_bytes( p_sys->p_snd_pcm, delay );
+ next_date = mdate() + ( (mtime_t)i_bytes * 1000000
+ / p_aout->output.output.i_bytes_per_frame
+ / p_aout->output.output.i_rate
+ * p_aout->output.output.i_frame_length );
- /* Get the new status */
- i_snd_rc = snd_pcm_status( p_sys->p_snd_pcm, p_status );
- if( i_snd_rc < 0 )
- {
- msg_Err( p_aout, "unable to get the device's status after "
- "recovery (%s)", snd_strerror( i_snd_rc ) );
+#ifdef ALSA_DEBUG
+ snd_pcm_state_t state = snd_pcm_status_get_state( p_status );
+ if( state != SND_PCM_STATE_RUNNING )
+ msg_Err( p_aout, "pcm status (%d) != RUNNING", state );
- msleep( p_sys->i_period_time >> 1 );
- return;
- }
- }
- else
- {
- msg_Err( p_aout, "unable to recover from buffer underrun" );
+ msg_Dbg( p_aout, "Delay is %ld frames (%d bytes)", delay, i_bytes );
- msleep( p_sys->i_period_time >> 1 );
- return;
- }
+ msg_Dbg( p_aout, "Bytes per frame: %d", p_aout->output.output.i_bytes_per_frame );
+ msg_Dbg( p_aout, "Rate: %d", p_aout->output.output.i_rate );
+ msg_Dbg( p_aout, "Frame length: %d", p_aout->output.output.i_frame_length );
- /* Underrun, try to recover as quickly as possible */
- next_date = mdate();
- }
- else
- {
- /* Here the device should be in RUNNING state.
- * p_status is valid. */
-
-#if 0
- /* This apparently does not work correctly in Alsa 1.0.11 */
- snd_pcm_status_get_tstamp( p_status, &ts_next );
- next_date = (mtime_t)ts_next.tv_sec * 1000000 + ts_next.tv_usec;
- if( next_date )
- {
- next_date += (mtime_t)snd_pcm_status_get_delay(p_status)
- * 1000000 / p_aout->output.output.i_rate;
- }
- else
+ msg_Dbg( p_aout, "Next date is in %d microseconds", (int)(next_date - mdate()) );
#endif
- {
- /* With screwed ALSA drivers the timestamp is always zero;
- * use another method then */
- snd_pcm_sframes_t delay = 0;
-
- snd_pcm_delay( p_sys->p_snd_pcm, &delay );
- next_date = mdate() + (mtime_t)(delay) * 1000000 /
- p_aout->output.output.i_rate
- * p_aout->output.output.i_frame_length;
- }
- }
+ }
- p_buffer = aout_OutputNextBuffer( p_aout, next_date,
- (p_aout->output.output.i_format ==
- VLC_FOURCC('s','p','d','i')) );
+ p_buffer = aout_OutputNextBuffer( p_aout, next_date,
+ (p_aout->output.output.i_format == VLC_FOURCC('s','p','d','i')) );
- /* Audio output buffer shortage -> stop the fill process and wait */
- if( p_buffer == NULL )
- {
- msleep( p_sys->i_period_time >> 1 );
- return;
- }
+ /* Audio output buffer shortage -> stop the fill process and wait */
+ if( p_buffer == NULL )
+ goto error;
+
+ for (;;)
+ {
+ i_snd_rc = snd_pcm_writei( p_sys->p_snd_pcm, p_buffer->p_buffer,
+ p_buffer->i_nb_samples );
+ if( i_snd_rc != -ESTRPIPE )
+ break;
+
+ /* a suspend event occurred
+ * (stream is suspended and waiting for an application recovery) */
+ msg_Dbg( p_aout, "entering in suspend mode, trying to resume..." );
- for (;;)
+ while( !p_aout->b_die && !p_aout->p_libvlc->b_die &&
+ ( i_snd_rc = snd_pcm_resume( p_sys->p_snd_pcm ) ) == -EAGAIN )
{
- i_snd_rc = snd_pcm_writei( p_sys->p_snd_pcm, p_buffer->p_buffer,
- p_buffer->i_nb_samples );
- if( i_snd_rc != -ESTRPIPE )
- break;
-
- /* a suspend event occurred
- * (stream is suspended and waiting for an application recovery) */
- msg_Dbg( p_aout, "entering in suspend mode, trying to resume..." );
-
- while( !p_aout->b_die && !p_aout->p_libvlc->b_die &&
- ( i_snd_rc = snd_pcm_resume( p_sys->p_snd_pcm ) ) == -EAGAIN )
- msleep( 100000 );
-
- if( i_snd_rc < 0 )
- /* Device does not supprot resuming, restart it */
- i_snd_rc = snd_pcm_prepare( p_sys->p_snd_pcm );
+ msleep( 1000000 );
}
if( i_snd_rc < 0 )
- {
- msg_Err( p_aout, "write failed (%s)",
- snd_strerror( i_snd_rc ) );
- }
+ /* Device does not supprot resuming, restart it */
+ i_snd_rc = snd_pcm_prepare( p_sys->p_snd_pcm );
- aout_BufferFree( p_buffer );
}
+
+ if( i_snd_rc < 0 )
+ msg_Err( p_aout, "cannot write: %s", snd_strerror( i_snd_rc ) );
+
+ aout_BufferFree( p_buffer );
+ return;
+
+error:
+ if( i_snd_rc < 0 )
+ msg_Err( p_aout, "ALSA error: %s", snd_strerror( i_snd_rc ) );
+ msleep( p_sys->i_period_time >> 1 );
}
static void GetDevicesForCard( module_config_t *p_item, int i_card );
GetDevices( p_item );
/* Signal change to the interface */
- p_item->b_dirty = VLC_TRUE;
+ p_item->b_dirty = true;
return VLC_SUCCESS;