ALSA audio output v3.01 is out !

parent ad830330
...@@ -2,11 +2,12 @@ ...@@ -2,11 +2,12 @@
* alsa.c : alsa plugin for vlc * alsa.c : alsa plugin for vlc
***************************************************************************** *****************************************************************************
* Copyright (C) 2000-2001 VideoLAN * Copyright (C) 2000-2001 VideoLAN
* $Id: alsa.c,v 1.1 2002/08/07 21:36:55 massiot Exp $ * $Id: alsa.c,v 1.2 2002/08/14 10:50:12 bozo Exp $
* *
* Authors: Henri Fallon <henri@videolan.org> - Original Author * Authors: Henri Fallon <henri@videolan.org> - Original Author
* Jeffrey Baker <jwbaker@acm.org> - Port to ALSA 1.0 API * Jeffrey Baker <jwbaker@acm.org> - Port to ALSA 1.0 API
* John Paul Lorenti <jpl31@columbia.edu> - Device selection * John Paul Lorenti <jpl31@columbia.edu> - Device selection
* Arnaud de Bossoreille de Ribou <bozo@via.ecp.fr> - S/PDIF and aout3
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
...@@ -31,61 +32,66 @@ ...@@ -31,61 +32,66 @@
#include <stdlib.h> /* calloc(), malloc(), free() */ #include <stdlib.h> /* calloc(), malloc(), free() */
#include <vlc/vlc.h> #include <vlc/vlc.h>
#include <vlc/aout.h> #include <vlc/aout.h>
#include "aout_internal.h"
/* ALSA part */
#include <alsa/asoundlib.h> #include <alsa/asoundlib.h>
/*****************************************************************************
* aout_sys_t: ALSA audio output method descriptor
*****************************************************************************
* This structure is part of the audio output thread descriptor.
* It describes the ALSA specific properties of an audio device.
*****************************************************************************/
struct aout_sys_t
{
snd_pcm_t * p_snd_pcm;
snd_pcm_sframes_t i_buffer_size;
int i_period_time;
volatile vlc_bool_t b_initialized;
#ifdef DEBUG
snd_output_t * p_snd_stderr;
#endif
};
/* These values are in frames.
* To convert them to a numer of bytes you have to multiply them by the
* number of channel(s) (eg. 2 for stereo) and the size of a sample (eg.
* 2 for s16). */
#define ALSA_DEFAULT_PERIOD_SIZE 2048
#define ALSA_DEFAULT_BUFFER_SIZE ( ALSA_DEFAULT_PERIOD_SIZE << 4 )
#define ALSA_SPDIF_PERIOD_SIZE 1536
#define ALSA_SPDIF_BUFFER_SIZE ( ALSA_SPDIF_PERIOD_SIZE << 4 )
/***************************************************************************** /*****************************************************************************
* Local prototypes * Local prototypes
*****************************************************************************/ *****************************************************************************/
static int Open ( vlc_object_t * ); static int Open ( vlc_object_t * );
static void Close ( vlc_object_t * ); static void Close ( vlc_object_t * );
static int SetFormat ( aout_thread_t * ); static int SetFormat ( aout_instance_t * );
static int GetBufInfo ( aout_thread_t *, int ); static void Play ( aout_instance_t *,
static void Play ( aout_thread_t *, byte_t *, int ); aout_buffer_t * );
static void HandleXrun ( aout_thread_t *); static int ALSAThread ( aout_instance_t * );
static void ALSAFill ( aout_instance_t * );
/***************************************************************************** /*****************************************************************************
* Module descriptor * Module descriptor
*****************************************************************************/ *****************************************************************************/
vlc_module_begin(); vlc_module_begin();
add_category_hint( N_("Device"), NULL ); add_category_hint( N_("Audio"), NULL );
add_string( "alsa-device", NULL, NULL, N_("Name"), NULL ); add_string( "alsa-device", NULL, NULL, N_("Name"), NULL );
set_description( _("ALSA audio module") ); set_description( _("ALSA audio module") );
set_capability( "audio output", 50 ); set_capability( "audio output", 50 );
set_callbacks( Open, Close ); set_callbacks( Open, Close );
vlc_module_end(); vlc_module_end();
/*****************************************************************************
* Preamble
*****************************************************************************/
typedef struct alsa_device_t
{
int i_num;
} alsa_device_t;
typedef struct alsa_card_t
{
int i_num;
} alsa_card_t;
/* here we store plugin dependant informations */
struct aout_sys_t
{
snd_pcm_t * p_alsa_handle;
unsigned long buffer_time;
unsigned long period_time;
unsigned long chunk_size;
unsigned long buffer_size;
unsigned long rate;
unsigned int bytes_per_sample;
unsigned int samples_per_frame;
unsigned int bytes_per_frame;
};
/***************************************************************************** /*****************************************************************************
* Open: create a handle and open an alsa device * Open: create a handle and open an alsa device
***************************************************************************** *****************************************************************************
...@@ -93,24 +99,26 @@ struct aout_sys_t ...@@ -93,24 +99,26 @@ struct aout_sys_t
*****************************************************************************/ *****************************************************************************/
static int Open( vlc_object_t *p_this ) static int Open( vlc_object_t *p_this )
{ {
aout_thread_t *p_aout = (aout_thread_t *)p_this; aout_instance_t * p_aout = (aout_instance_t *)p_this;
struct aout_sys_t * p_sys;
char * psz_device;
/* Allows user to choose which ALSA device to use */ /* Allows user to choose which ALSA device to use */
char psz_alsadev[128]; char psz_alsadev[128];
char *psz_device, *psz_userdev; char * psz_userdev;
int i_ret; int i_snd_rc;
/* Allocate structures */ /* Allocate structures */
p_aout->p_sys = malloc( sizeof( aout_sys_t ) ); p_aout->output.p_sys = p_sys = malloc( sizeof( aout_sys_t ) );
if( p_aout->p_sys == NULL ) if( p_sys == NULL )
{ {
msg_Err( p_aout, "out of memory" ); msg_Err( p_aout, "out of memory" );
return -1; return -1;
} }
p_aout->pf_setformat = SetFormat; #ifdef DEBUG
p_aout->pf_getbufinfo = GetBufInfo; snd_output_stdio_attach( &p_sys->p_snd_stderr, stderr, 0 );
p_aout->pf_play = Play; #endif
/* Read in ALSA device preferences from configuration */ /* Read in ALSA device preferences from configuration */
psz_userdev = config_GetPsz( p_aout, "alsa-device" ); psz_userdev = config_GetPsz( p_aout, "alsa-device" );
...@@ -122,11 +130,7 @@ static int Open( vlc_object_t *p_this ) ...@@ -122,11 +130,7 @@ static int Open( vlc_object_t *p_this )
else else
{ {
/* Use the internal logic to decide on the device name */ /* Use the internal logic to decide on the device name */
if( p_aout->i_format != AOUT_FMT_A52 ) if ( p_aout->output.output.i_format == AOUT_FMT_SPDIF )
{
psz_device = "default";
}
else
{ {
unsigned char s[4]; unsigned char s[4];
s[0] = IEC958_AES0_CON_EMPHASIS_NONE | IEC958_AES0_NONAUDIO; s[0] = IEC958_AES0_CON_EMPHASIS_NONE | IEC958_AES0_NONAUDIO;
...@@ -137,21 +141,28 @@ static int Open( vlc_object_t *p_this ) ...@@ -137,21 +141,28 @@ static int Open( vlc_object_t *p_this )
"iec958:AES0=0x%x,AES1=0x%x,AES2=0x%x,AES3=0x%x", "iec958:AES0=0x%x,AES1=0x%x,AES2=0x%x,AES3=0x%x",
s[0], s[1], s[2], s[3] ); s[0], s[1], s[2], s[3] );
psz_device = psz_alsadev; psz_device = psz_alsadev;
p_sys->i_buffer_size = ALSA_SPDIF_BUFFER_SIZE;
p_aout->output.i_nb_samples = ALSA_SPDIF_PERIOD_SIZE;
}
else
{
psz_device = "default";
p_sys->i_buffer_size = ALSA_DEFAULT_BUFFER_SIZE;
p_aout->output.i_nb_samples = ALSA_DEFAULT_PERIOD_SIZE;
} }
} }
/* Open device */ /* Open device */
i_ret = snd_pcm_open( &(p_aout->p_sys->p_alsa_handle), i_snd_rc = snd_pcm_open( &p_sys->p_snd_pcm, psz_device,
psz_device, SND_PCM_STREAM_PLAYBACK, 0); SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK);
if( i_ret != 0 ) if( i_snd_rc < 0 )
{ {
msg_Err( p_aout, "cannot open ALSA device `%s' (%s)", msg_Err( p_aout, "cannot open ALSA device `%s' (%s)",
psz_device, snd_strerror(i_ret) ); psz_device, snd_strerror(i_snd_rc) );
if( psz_userdev ) if( psz_userdev )
{
free( psz_userdev ); free( psz_userdev );
} free( p_sys );
p_sys->p_snd_pcm = NULL;
return -1; return -1;
} }
...@@ -160,6 +171,20 @@ static int Open( vlc_object_t *p_this ) ...@@ -160,6 +171,20 @@ static int Open( vlc_object_t *p_this )
free( psz_userdev ); free( psz_userdev );
} }
/* Create ALSA thread and wait for its readiness. */
p_sys->b_initialized = VLC_FALSE;
if( vlc_thread_create( p_aout, "aout", ALSAThread, VLC_FALSE ) )
{
msg_Err( p_aout, "cannot create ALSA thread (%s)", strerror(errno) );
if( psz_userdev )
free( psz_userdev );
free( p_sys );
return -1;
}
p_aout->output.pf_setformat = SetFormat;
p_aout->output.pf_play = Play;
return 0; return 0;
} }
...@@ -169,9 +194,11 @@ static int Open( vlc_object_t *p_this ) ...@@ -169,9 +194,11 @@ static int Open( vlc_object_t *p_this )
* This function prepares the device, sets the rate, format, the mode * This function prepares the device, sets the rate, format, the mode
* ( "play as soon as you have data" ), and buffer information. * ( "play as soon as you have data" ), and buffer information.
*****************************************************************************/ *****************************************************************************/
static int SetFormat( aout_thread_t *p_aout ) static int SetFormat( aout_instance_t * p_aout )
{ {
int i_rv; struct aout_sys_t * p_sys = p_aout->output.p_sys;
int i_snd_rc;
int i_format; int i_format;
snd_pcm_hw_params_t *p_hw; snd_pcm_hw_params_t *p_hw;
...@@ -180,241 +207,257 @@ static int SetFormat( aout_thread_t *p_aout ) ...@@ -180,241 +207,257 @@ static int SetFormat( aout_thread_t *p_aout )
snd_pcm_hw_params_alloca(&p_hw); snd_pcm_hw_params_alloca(&p_hw);
snd_pcm_sw_params_alloca(&p_sw); snd_pcm_sw_params_alloca(&p_sw);
/* default value for snd_pcm_hw_params_set_buffer_time_near() */ switch (p_aout->output.output.i_format)
p_aout->p_sys->buffer_time = AOUT_BUFFER_DURATION;
switch (p_aout->i_format)
{ {
case AOUT_FMT_S16_LE: case AOUT_FMT_MU_LAW: i_format = SND_PCM_FORMAT_MU_LAW; break;
i_format = SND_PCM_FORMAT_S16_LE; case AOUT_FMT_A_LAW: i_format = SND_PCM_FORMAT_A_LAW; break;
p_aout->p_sys->bytes_per_sample = 2; case AOUT_FMT_IMA_ADPCM: i_format = SND_PCM_FORMAT_IMA_ADPCM; break;
break; case AOUT_FMT_U8: i_format = SND_PCM_FORMAT_U8; break;
case AOUT_FMT_S16_LE: i_format = SND_PCM_FORMAT_S16_LE; break;
case AOUT_FMT_A52: case AOUT_FMT_S16_BE: i_format = SND_PCM_FORMAT_S16_BE; break;
i_format = SND_PCM_FORMAT_S16_LE; case AOUT_FMT_S8: i_format = SND_PCM_FORMAT_S8; break;
p_aout->p_sys->bytes_per_sample = 2; case AOUT_FMT_U16_LE: i_format = SND_PCM_FORMAT_U16_LE; break;
/* buffer_time must be 500000 to avoid a system crash */ case AOUT_FMT_U16_BE: i_format = SND_PCM_FORMAT_U16_BE; break;
p_aout->p_sys->buffer_time = 500000; case AOUT_FMT_FLOAT32: i_format = SND_PCM_FORMAT_FLOAT; break;
break; case AOUT_FMT_FIXED32:
default: default:
i_format = SND_PCM_FORMAT_S16_BE; msg_Err( p_aout, "audio output format 0x%x not supported",
p_aout->p_sys->bytes_per_sample = 2; p_aout->output.output.i_format );
return -1;
break; break;
} }
p_aout->p_sys->samples_per_frame = p_aout->i_channels; i_snd_rc = snd_pcm_hw_params_any( p_sys->p_snd_pcm, p_hw );
p_aout->p_sys->bytes_per_frame = p_aout->p_sys->samples_per_frame * if( i_snd_rc < 0 )
p_aout->p_sys->bytes_per_sample;
i_rv = snd_pcm_hw_params_any( p_aout->p_sys->p_alsa_handle, p_hw );
if( i_rv < 0 )
{ {
msg_Err( p_aout, "unable to retrieve initial parameters" ); msg_Err( p_aout, "unable to retrieve initial hardware parameters" );
return -1; return -1;
} }
i_rv = snd_pcm_hw_params_set_access( p_aout->p_sys->p_alsa_handle, p_hw, i_snd_rc = snd_pcm_hw_params_set_access( p_sys->p_snd_pcm, p_hw,
SND_PCM_ACCESS_RW_INTERLEAVED ); SND_PCM_ACCESS_RW_INTERLEAVED );
if( i_rv < 0 ) if( i_snd_rc < 0 )
{ {
msg_Err( p_aout, "unable to set interleaved stream format" ); msg_Err( p_aout, "unable to set interleaved stream format" );
return -1; return -1;
} }
i_rv = snd_pcm_hw_params_set_format( p_aout->p_sys->p_alsa_handle, i_snd_rc = snd_pcm_hw_params_set_format( p_sys->p_snd_pcm, p_hw, i_format );
p_hw, i_format ); if( i_snd_rc < 0 )
if( i_rv < 0 )
{ {
msg_Err( p_aout, "unable to set stream sample size and word order" ); msg_Err( p_aout, "unable to set stream sample size and word order" );
return -1; return -1;
} }
i_rv = snd_pcm_hw_params_set_channels( p_aout->p_sys->p_alsa_handle, p_hw, i_snd_rc = snd_pcm_hw_params_set_channels( p_sys->p_snd_pcm, p_hw,
p_aout->i_channels ); p_aout->output.output.i_channels );
if( i_rv < 0 ) if( i_snd_rc < 0 )
{ {
msg_Err( p_aout, "unable to set number of output channels" ); msg_Err( p_aout, "unable to set number of output channels" );
return -1; return -1;
} }
i_rv = snd_pcm_hw_params_set_rate_near( p_aout->p_sys->p_alsa_handle, p_hw, i_snd_rc = snd_pcm_hw_params_set_rate( p_sys->p_snd_pcm, p_hw,
p_aout->i_rate, 0 ); p_aout->output.output.i_rate, 0 );
if( i_rv < 0 ) if( i_snd_rc < 0 )
{ {
msg_Err( p_aout, "unable to set sample rate" ); msg_Err( p_aout, "unable to set sample rate" );
return -1; return -1;
} }
p_aout->p_sys->rate = i_rv;
i_rv = snd_pcm_hw_params_set_buffer_time_near( p_aout->p_sys->p_alsa_handle, i_snd_rc = snd_pcm_hw_params_set_buffer_size_near( p_sys->p_snd_pcm, p_hw,
p_hw, p_sys->i_buffer_size );
p_aout->p_sys->buffer_time, if( i_snd_rc < 0 )
0 );
if( i_rv < 0 )
{ {
msg_Err( p_aout, "unable to set buffer time" ); msg_Err( p_aout, "unable to set buffer time" );
return -1; return -1;
} }
p_aout->p_sys->buffer_time = i_rv; p_sys->i_buffer_size = i_snd_rc;
i_rv = snd_pcm_hw_params_set_period_time_near( p_aout->p_sys->p_alsa_handle, i_snd_rc = snd_pcm_hw_params_set_period_size_near(
p_hw, p_aout->p_sys->buffer_time / p_aout->p_sys->bytes_per_frame, 0 ); p_sys->p_snd_pcm, p_hw, p_aout->output.i_nb_samples, 0 );
if( i_rv < 0 ) if( i_snd_rc < 0 )
{ {
msg_Err( p_aout, "unable to set period time" ); msg_Err( p_aout, "unable to set period size" );
return -1; return -1;
} }
p_aout->p_sys->period_time = i_rv; p_aout->output.i_nb_samples = i_snd_rc;
p_sys->i_period_time = snd_pcm_hw_params_get_period_time( p_hw, 0 );
i_rv = snd_pcm_hw_params(p_aout->p_sys->p_alsa_handle, p_hw); i_snd_rc = snd_pcm_hw_params( p_sys->p_snd_pcm, p_hw );
if (i_rv < 0) if (i_snd_rc < 0)
{ {
msg_Err( p_aout, "unable to set hardware configuration" ); msg_Err( p_aout, "unable to set hardware configuration" );
return -1; return -1;
} }
p_aout->p_sys->chunk_size = snd_pcm_hw_params_get_period_size( p_hw, 0 ); snd_pcm_sw_params_current( p_sys->p_snd_pcm, p_sw );
p_aout->p_sys->buffer_size = snd_pcm_hw_params_get_buffer_size( p_hw ); i_snd_rc = snd_pcm_sw_params_set_sleep_min( p_sys->p_snd_pcm, p_sw, 0 );
snd_pcm_sw_params_current( p_aout->p_sys->p_alsa_handle, p_sw ); i_snd_rc = snd_pcm_sw_params_set_avail_min( p_sys->p_snd_pcm, p_sw,
i_rv = snd_pcm_sw_params_set_sleep_min( p_aout->p_sys->p_alsa_handle, p_sw, p_aout->output.i_nb_samples );
0 );
i_rv = snd_pcm_sw_params_set_avail_min( p_aout->p_sys->p_alsa_handle, p_sw, i_snd_rc = snd_pcm_sw_params( p_sys->p_snd_pcm, p_sw );
p_aout->p_sys->chunk_size ); if( i_snd_rc < 0 )
/* Worked with the CVS version but not with 0.9beta3
i_rv = snd_pcm_sw_params_set_start_threshold( p_aout->p_sys->p_alsa_handle,
p_sw, p_aout->p_sys->buffer_size );
i_rv = snd_pcm_sw_params_set_stop_threshold( p_aout->p_sys->p_alsa_handle,
p_sw, p_aout->p_sys->buffer_size);
*/
i_rv = snd_pcm_sw_params( p_aout->p_sys->p_alsa_handle, p_sw );
if( i_rv < 0 )
{ {
msg_Err( p_aout, "unable to set software configuration" ); msg_Err( p_aout, "unable to set software configuration" );
return -1; return -1;
} }
#ifdef DEBUG
snd_output_printf( p_sys->p_snd_stderr, "\nALSA hardware setup:\n\n" );
snd_pcm_dump_hw_setup( p_sys->p_snd_pcm, p_sys->p_snd_stderr );
snd_output_printf( p_sys->p_snd_stderr, "\nALSA software setup:\n\n" );
snd_pcm_dump_sw_setup( p_sys->p_snd_pcm, p_sys->p_snd_stderr );
snd_output_printf( p_sys->p_snd_stderr, "\n" );
#endif
p_sys->b_initialized = VLC_TRUE;
return 0; return 0;
} }
/***************************************************************************** /*****************************************************************************
* HandleXrun : reprepare the output * Play: queue a buffer for playing by ALSAThread
*****************************************************************************
* When buffer gets empty, the driver goes in "Xrun" state, where it needs
* to be reprepared before playing again
*****************************************************************************/ *****************************************************************************/
static void HandleXrun(aout_thread_t *p_aout) static void Play( aout_instance_t *p_aout, aout_buffer_t * p_buffer )
{ {
int i_rv; aout_FifoPush( p_aout, &p_aout->output.fifo, p_buffer );
msg_Err( p_aout, "resetting output after buffer underrun" );
// i_rv = snd_pcm_reset( p_aout->p_sys->p_alsa_handle );
i_rv = snd_pcm_prepare( p_aout->p_sys->p_alsa_handle );
if( i_rv < 0 )
{
msg_Err( p_aout, "unable to recover from buffer underrun (%s)",
snd_strerror( i_rv ) );
}
} }
/***************************************************************************** /*****************************************************************************
* BufInfo: buffer status query * Close: close the Alsa device
*****************************************************************************
* This function returns the number of used byte in the queue.
* It also deals with errors : indeed if the device comes to run out
* of data to play, it switches to the "underrun" status. It has to
* be flushed and re-prepared
*****************************************************************************/ *****************************************************************************/
static int GetBufInfo( aout_thread_t *p_aout, int i_buffer_limit ) static void Close( vlc_object_t *p_this )
{ {
snd_pcm_status_t *p_status; aout_instance_t *p_aout = (aout_instance_t *)p_this;
int i_alsa_get_status_returns; struct aout_sys_t * p_sys = p_aout->output.p_sys;
int i_snd_rc;
snd_pcm_status_alloca( &p_status ); p_aout->b_die = 1;
vlc_thread_join( p_aout );
i_alsa_get_status_returns = snd_pcm_status( p_aout->p_sys->p_alsa_handle, if( p_sys->p_snd_pcm )
p_status ); {
i_snd_rc = snd_pcm_close( p_sys->p_snd_pcm );
if( i_alsa_get_status_returns ) if( i_snd_rc > 0 )
{ {
msg_Err( p_aout, "failed getting alsa buffer info (%s)", msg_Err( p_aout, "failed closing ALSA device (%s)",
snd_strerror ( i_alsa_get_status_returns ) ); snd_strerror( i_snd_rc ) );
return ( -1 ); }
} }
switch( snd_pcm_status_get_state( p_status ) ) free( p_sys );
}
/*****************************************************************************
* ALSAThread: asynchronous thread used to DMA the data to the device
*****************************************************************************/
static int ALSAThread( aout_instance_t * p_aout )
{
struct aout_sys_t * p_sys = p_aout->output.p_sys;
while ( !p_aout->b_die )
{ {
case SND_PCM_STATE_XRUN : if( !p_sys->b_initialized )
HandleXrun( p_aout ); {
break; msleep( THREAD_SLEEP );
continue;
}
case SND_PCM_STATE_OPEN: ALSAFill( p_aout );
case SND_PCM_STATE_PREPARED:
case SND_PCM_STATE_RUNNING:
break;
default: msleep( p_sys->i_period_time );
msg_Err( p_aout, "unhandled condition %i",
snd_pcm_status_get_state( p_status ) );
break;
} }
return snd_pcm_status_get_avail(p_status) * p_aout->p_sys->bytes_per_frame; return 0;
} }
/***************************************************************************** /*****************************************************************************
* Play : plays a sample * ALSAFill: function used to fill the ALSA buffer as much as possible
*****************************************************************************
* Plays a sample using the snd_pcm_writei function from the alsa API
*****************************************************************************/ *****************************************************************************/
static void Play( aout_thread_t *p_aout, byte_t *buffer, int i_size ) static void ALSAFill( aout_instance_t * p_aout )
{ {
snd_pcm_uframes_t tot_frames; struct aout_sys_t * p_sys = p_aout->output.p_sys;
snd_pcm_uframes_t frames_left;
snd_pcm_uframes_t rv;
tot_frames = i_size / p_aout->p_sys->bytes_per_frame; aout_buffer_t * p_buffer;
frames_left = tot_frames; mtime_t next_date = 0;
snd_pcm_status_t * p_status;
snd_timestamp_t ts_next;
int i_snd_rc, i_size;
byte_t * p_bytes;
snd_pcm_uframes_t i_avail;
snd_pcm_status_alloca( &p_status );
while( frames_left > 0 ) i_snd_rc = snd_pcm_wait( p_sys->p_snd_pcm, THREAD_SLEEP );
if( i_snd_rc < 0 )
{ {
rv = snd_pcm_writei( p_aout->p_sys->p_alsa_handle, buffer + msg_Err( p_aout, "alsa device not ready !!! (%s)",
(tot_frames - frames_left) * snd_strerror( i_snd_rc ) );
p_aout->p_sys->bytes_per_frame, frames_left ); return;
}
if( (signed int) rv < 0 ) while( VLC_TRUE )
{
i_snd_rc = snd_pcm_status( p_sys->p_snd_pcm, p_status );
if( i_snd_rc < 0 )
{ {
msg_Err( p_aout, "failed writing to output (%s)", msg_Err( p_aout, "unable to get the device's status (%s)",
snd_strerror( rv ) ); snd_strerror( i_snd_rc ) );
return; return;
} }
frames_left -= rv; if( snd_pcm_status_get_state( p_status ) == SND_PCM_STATE_XRUN )
{
i_snd_rc = snd_pcm_prepare( p_sys->p_snd_pcm );
if( i_snd_rc == 0 )
{
msg_Err( p_aout, "recovered from buffer underrun" );
next_date = mdate();
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 ) );
return;
}
}
else
{
msg_Err( p_aout, "unable to recover from buffer underrun" );
return;
}
} }
}
/***************************************************************************** i_avail = snd_pcm_status_get_avail( p_status );
* Close: close the Alsa device if( i_avail >= p_aout->output.i_nb_samples )
*****************************************************************************/ {
static void Close( vlc_object_t *p_this ) snd_pcm_status_get_tstamp( p_status, &ts_next );
{ next_date = (mtime_t)ts_next.tv_sec * 1000000 + ts_next.tv_usec;
aout_thread_t *p_aout = (aout_thread_t *)p_this;
int i_close_returns; p_buffer = aout_OutputNextBuffer( p_aout, next_date, 0 );
if( p_buffer == NULL )
return;
p_bytes = p_buffer->p_buffer;
i_close_returns = snd_pcm_close( p_aout->p_sys->p_alsa_handle ); i_snd_rc = snd_pcm_writei( p_sys->p_snd_pcm, p_bytes,
p_buffer->i_nb_samples );
if( i_close_returns ) if( i_snd_rc < 0 )
{ {
msg_Err( p_aout, "failed closing ALSA device (%s)", msg_Err( p_aout, "write failed (%s)",
snd_strerror( i_close_returns ) ); snd_strerror( i_snd_rc ) );
}
else
{
aout_BufferFree( p_buffer );
}
}
} }
free( p_aout->p_sys );
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment