[xiph-commits] r16876 - in trunk/ao: include/ao src/plugins/alsa
xiphmont at svn.xiph.org
xiphmont at svn.xiph.org
Fri Feb 5 15:13:04 PST 2010
Author: xiphmont
Date: 2010-02-05 15:13:04 -0800 (Fri, 05 Feb 2010)
New Revision: 16876
Modified:
trunk/ao/include/ao/ao_private.h
trunk/ao/src/plugins/alsa/ao_alsa.c
Log:
It turns out that ALSA lets you open devices that have a config entry
but otherwise don't exist. Try to configure immediately after open;
this is the step that actually fails for nonexistant devices.
Also, eliminate printing errors if -q; exit status is enough.
Modified: trunk/ao/include/ao/ao_private.h
===================================================================
--- trunk/ao/include/ao/ao_private.h 2010-02-05 16:07:09 UTC (rev 16875)
+++ trunk/ao/include/ao/ao_private.h 2010-02-05 23:13:04 UTC (rev 16876)
@@ -148,10 +148,12 @@
}
#define aerror(format, args...) { \
- if(strcmp(format,"\n")){ \
- fprintf(stderr,"ao_%s ERROR: " format,device->funcs->driver_info()->short_name,## args); \
- }else{ \
- fprintf(stderr,"\n"); \
+ if(device->verbose>=0){ \
+ if(strcmp(format,"\n")){ \
+ fprintf(stderr,"ao_%s ERROR: " format,device->funcs->driver_info()->short_name,## args); \
+ }else{ \
+ fprintf(stderr,"\n"); \
+ } \
} \
}
Modified: trunk/ao/src/plugins/alsa/ao_alsa.c
===================================================================
--- trunk/ao/src/plugins/alsa/ao_alsa.c 2010-02-05 16:07:09 UTC (rev 16875)
+++ trunk/ao/src/plugins/alsa/ao_alsa.c 2010-02-05 23:13:04 UTC (rev 16876)
@@ -94,12 +94,10 @@
snd_pcm_t *pcm_handle;
unsigned int buffer_time;
unsigned int period_time;
- snd_pcm_uframes_t buffer_size;
snd_pcm_uframes_t period_size;
int sample_size;
snd_pcm_format_t bitformat;
char *dev;
- char *cmd;
ao_alsa_writei_t * writei;
snd_pcm_access_t access_mask;
} ao_alsa_internal;
@@ -206,12 +204,11 @@
return ret;
}
-
/* setup alsa data format and buffer geometry */
-static inline int alsa_set_hwparams(ao_alsa_internal *internal,
- ao_sample_format *format,
- ao_device *device)
+static inline int alsa_set_hwparams(ao_device *device,
+ ao_sample_format *format)
{
+ ao_alsa_internal *internal = (ao_alsa_internal *) device->internal;
snd_pcm_hw_params_t *params;
int err;
unsigned int rate = format->rate;
@@ -220,52 +217,59 @@
snd_pcm_hw_params_alloca(¶ms);
/* fetch all possible hardware parameters */
- internal->cmd = "snd_pcm_hw_params_any";
err = snd_pcm_hw_params_any(internal->pcm_handle, params);
- if (err < 0)
- return err;
+ if (err < 0){
+ adebug("snd_pcm_hw_params_any() failed.\n"
+ " Device exists but no matching hardware?\n");
+ return err;
+ }
/* set the access type */
- internal->cmd = "snd_pcm_hw_params_set_access";
err = snd_pcm_hw_params_set_access(internal->pcm_handle,
params, internal->access_mask);
- if (err < 0)
- return err;
+ if (err < 0){
+ adebug("snd_pcm_hw_params_set_access() failed.\n");
+ return err;
+ }
/* set the sample bitformat */
- internal->cmd = "snd_pcm_hw_params_set_format";
err = snd_pcm_hw_params_set_format(internal->pcm_handle,
params, internal->bitformat);
- if (err < 0)
- return err;
+ if (err < 0){
+ adebug("snd_pcm_hw_params_set_format() failed.\n");
+ return err;
+ }
/* set the number of channels */
- internal->cmd = "snd_pcm_hw_params_set_channels";
err = snd_pcm_hw_params_set_channels(internal->pcm_handle,
params, (unsigned int)format->channels);
- if (err < 0)
- return err;
+ if (err < 0){
+ adebug("snd_pcm_hw_params_set_channels() failed.\n");
+ return err;
+ }
/* save the sample size in bytes for posterity */
internal->sample_size = format->bits * format->channels / 8;
/* set the sample rate */
- internal->cmd = "snd_pcm_hw_params_set_rate_near";
err = snd_pcm_hw_params_set_rate_near(internal->pcm_handle,
params, &rate, 0);
- if (err < 0)
- return err;
+ if (err < 0){
+ adebug("snd_pcm_hw_params_set_rate_near() failed.\n");
+ return err;
+ }
if (rate > 1.05 * format->rate || rate < 0.95 * format->rate) {
awarn("sample rate %i not supported "
"by the hardware, using %u\n", format->rate, rate);
}
/* set the length of the hardware sample buffer in microseconds */
- internal->cmd = "snd_pcm_hw_params_set_buffer_time_near";
err = snd_pcm_hw_params_set_buffer_time_near(internal->pcm_handle,
params, &(internal->buffer_time), 0);
- if (err < 0)
- return err;
+ if (err < 0){
+ adebug("snd_pcm_hw_params_set_buffer_time_near() failed.\n");
+ return err;
+ }
/* calculate a period time of one half sample time */
if ((internal->period_time == 0) && (rate > 0))
@@ -273,39 +277,36 @@
1000000 * AO_ALSA_SAMPLE_XFER / rate;
/* set the time per hardware sample transfer */
- internal->cmd = "snd_pcm_hw_params_set_period_time_near";
err = snd_pcm_hw_params_set_period_time_near(internal->pcm_handle,
params, &(internal->period_time), 0);
- if (err < 0)
- return err;
+ if (err < 0){
+ adebug("snd_pcm_hw_params_set_period_time_near() failed.\n");
+ return err;
+ }
/* commit the params structure to the hardware via ALSA */
- internal->cmd = "snd_pcm_hw_params";
err = snd_pcm_hw_params(internal->pcm_handle, params);
- if (err < 0)
- return err;
+ if (err < 0){
+ adebug("snd_pcm_hw_params() failed.\n");
+ return err;
+ }
/* save the period size in frames for posterity */
- internal->cmd = "snd_pcm_hw_get_period_size";
- err = snd_pcm_hw_params_get_period_size(params,
+ err = snd_pcm_hw_params_get_period_size(params,
&(internal->period_size), 0);
- if (err < 0)
- return err;
+ if (err < 0){
+ adebug("snd_pcm_hw_params_get_period_size() failed.\n");
+ return err;
+ }
- /* save the buffer size in frames for posterity */
- internal->cmd = "snd_pcm_hw_get_buffer_size";
- err = snd_pcm_hw_params_get_buffer_size(params,
- &(internal->buffer_size));
- if (err < 0)
- return err;
-
return 1;
}
/* setup alsa data transfer behavior */
-static inline int alsa_set_swparams(ao_alsa_internal *internal)
+static inline int alsa_set_swparams(ao_device *device)
{
+ ao_alsa_internal *internal = (ao_alsa_internal *) device->internal;
snd_pcm_sw_params_t *params;
int err;
@@ -313,63 +314,114 @@
snd_pcm_sw_params_alloca(¶ms);
/* fetch the current software parameters */
- internal->cmd = "snd_pcm_sw_params_current";
err = snd_pcm_sw_params_current(internal->pcm_handle, params);
- if (err < 0)
- return err;
+ if (err < 0){
+ adebug("snd_pcm_sw_params_current() failed.\n");
+ return err;
+ }
/* allow transfers to start when there is one period */
- internal->cmd = "snd_pcm_sw_params_set_start_threshold";
err = snd_pcm_sw_params_set_start_threshold(internal->pcm_handle,
params, internal->period_size);
- if (err < 0)
- return err;
+ if (err < 0){
+ adebug("snd_pcm_sw_params_set_start_threshold() failed.\n");
+ return err;
+ }
/* require a minimum of one full transfer in the buffer */
- internal->cmd = "snd_pcm_sw_params_set_avail_min";
err = snd_pcm_sw_params_set_avail_min(internal->pcm_handle, params,
internal->period_size);
- if (err < 0)
- return err;
+ if (err < 0){
+ adebug("snd_pcm_sw_params_set_avail_min() failed.\n");
+ return err;
+ }
/* do not align transfers; this is obsolete/deprecated in ALSA
1.x where the transfer alignemnt is always 1 (except for
buggy drivers like VIA 82xx which still demand aligned
transfers regardless of setting, in violation of the ALSA
API docs) */
- internal->cmd = "snd_pcm_sw_params_set_xfer_align";
err = snd_pcm_sw_params_set_xfer_align(internal->pcm_handle, params, 1);
- if (err < 0)
- return err;
+ if (err < 0){
+ adebug("snd_pcm_sw_params_set_xfer_align() failed.\n");
+ return err;
+ }
- /* force a work-ahead silence buffer; this is an attempted
- fix, again for VIA 82xx, where non-MMIO transfers will
- buffer into period-size transfers, but the last transfer is
- usually undersized and playback falls off the end of the
- submitted data. */
+ /* force a work-ahead silence buffer; this is a fix, again for
+ VIA 82xx, where non-MMIO transfers will buffer into
+ period-size transfers, but the last transfer is usually
+ undersized and playback falls off the end of the submitted
+ data. */
{
snd_pcm_uframes_t boundary;
- internal->cmd = "snd_pcm_sw_params_get_boundary";
err = snd_pcm_sw_params_get_boundary(params,&boundary);
- if (err < 0)
+ if (err < 0){
+ adebug("snd_pcm_sw_params_get_boundary() failed.\n");
return err;
-
- internal->cmd = "snd_pcm_sw_params_set_silence_size";
+ }
err = snd_pcm_sw_params_set_silence_size(internal->pcm_handle, params, boundary);
- if (err < 0)
+ if (err < 0){
+ adebug("snd_pcm_sw_params_set_silence_size() failed.\n");
return err;
+ }
}
/* commit the params structure to ALSA */
- internal->cmd = "snd_pcm_sw_params";
err = snd_pcm_sw_params(internal->pcm_handle, params);
- if (err < 0)
- return err;
+ if (err < 0){
+ adebug("snd_pcm_sw_params() failed.\n");
+ return err;
+ }
return 1;
}
+/* Devices declared in the alsa configuration will usually open
+ without error, even if there's no underlying hardware to support
+ them, eg, opening a 5.1 surround device on setero hardware. The
+ device won't 'fail' until there's an attempt to configure it. */
+
+static inline int alsa_test_open(ao_device *device,
+ char *dev,
+ ao_sample_format *format)
+{
+ ao_alsa_internal *internal = (ao_alsa_internal *) device->internal;
+ snd_pcm_hw_params_t *params;
+ int err;
+
+ adebug("Trying to open ALSA device '%s'\n",dev);
+
+ err = snd_pcm_open(&(internal->pcm_handle), dev,
+ SND_PCM_STREAM_PLAYBACK, 0);
+
+ if(err){
+ adebug("Unable to open ALSA device '%s'\n",dev);
+ return err;
+ }
+
+ /* try to set up hw params */
+ err = alsa_set_hwparams(device,format);
+ if(err<0){
+ adebug("Unable to open ALSA device '%s'\n",dev);
+ snd_pcm_close(internal->pcm_handle);
+ internal->pcm_handle = NULL;
+ return err;
+ }
+
+ /* try to set up sw params */
+ err = alsa_set_swparams(device);
+ if(err<0){
+ adebug("Unable to open ALSA device '%s'\n",dev);
+ snd_pcm_close(internal->pcm_handle);
+ internal->pcm_handle = NULL;
+ return err;
+ }
+
+ /* success! */
+ return 0;
+}
+
/* prepare the audio device for playback */
int ao_plugin_open(ao_device *device, ao_sample_format *format)
{
@@ -379,13 +431,14 @@
/* Get the ALSA bitformat first to make sure it's valid */
err = alsa_get_sample_bitformat(format->bits,
device->client_byte_format == AO_FMT_BIG,device);
- if (err < 0)
- goto error;
+ if (err < 0){
+ aerror("Invalid byte format\n");
+ return 0;
+ }
internal->bitformat = err;
/* Open the ALSA device */
- internal->cmd = "snd_pcm_open";
err=0;
if(!internal->dev){
char *tmp=NULL;
@@ -396,81 +449,64 @@
default:
case 8:
case 7:
- err = snd_pcm_open(&(internal->pcm_handle), tmp="surround71",
- SND_PCM_STREAM_PLAYBACK, 0);
+ err = alsa_test_open(device, tmp="surround71", format);
break;
case 4:
case 3:
- err = snd_pcm_open(&(internal->pcm_handle), tmp="surround40",
- SND_PCM_STREAM_PLAYBACK, 0);
+ err = alsa_test_open(device, tmp="surround40", format);
if(err==0)break;
case 6:
case 5:
- err = snd_pcm_open(&(internal->pcm_handle), tmp="surround51",
- SND_PCM_STREAM_PLAYBACK, 0);
+ err = alsa_test_open(device, tmp="surround51", format);
case 1:
case 2:
break;
}
if(err){
- awarn("Unable to open ALSA surround device '%s'\n"
- " trying default device...\n",tmp);
+ awarn("Unable to open surround playback. Trying default device...\n");
tmp=NULL;
}
+
if(!tmp)
- err = snd_pcm_open(&(internal->pcm_handle), tmp="default",
- SND_PCM_STREAM_PLAYBACK, 0);
+ err = alsa_test_open(device, tmp="default", format);
+
internal->dev=strdup(tmp);
}else
- err = snd_pcm_open(&(internal->pcm_handle), internal->dev,
- SND_PCM_STREAM_PLAYBACK, 0);
+ err = alsa_test_open(device, internal->dev, format);
+
if (err < 0) {
- internal->pcm_handle = NULL;
- goto error;
+ aerror("Unable to open ALSA device '%s' for playback => %s\n",
+ internal->dev, snd_strerror(err));
+ return 0;
}
- /* Set up the hardware parameters, ie sample and buffer specs */
- err = alsa_set_hwparams(internal, format, device);
- if (err < 0)
- goto error;
+ adebug("Using ALSA device '%s'\n",internal->dev);
- /* Set up the software parameters, ie de-buffering specs */
- err = alsa_set_swparams(internal);
- if (err < 0)
- goto error;
-
/* alsa's endinness will be the same as the application's */
if (format->bits > 8)
device->driver_byte_format = device->client_byte_format;
- if(device->verbose>0)
- fprintf(stderr,"Using alsa device '%s'\n", internal->dev);
-
if(!device->output_matrix){
- if(!strncasecmp(internal->dev,"plug:",5))
- if(format->channels>2 && device->verbose>=0)
- awarn("No way to determine hardware channel mapping of\n"
- "ALSA 'plug:' devices.\n");
if(!strcasecmp(internal->dev,"default")){
- if(format->channels>2 && device->verbose>=0)
+ /* default device */
+ if(format->channels>2)
awarn("ALSA 'default' device plays only L,R channels.\n");
device->output_matrix=strdup("L,R");
- }else
- device->output_matrix=strdup("L,R,BL,BR,C,LFE,SL,SR");
+ }else{
+ if(strncasecmp(internal->dev,"surround",8)){
+ if(format->channels>2 && device->verbose>=0)
+ awarn("No way to determine hardware %d channel mapping of\n"
+ "ALSA device '%s'.\n",format->channels, internal->dev);
+ device->output_matrix=strdup("L,R");
+ }else{
+ device->output_matrix=strdup("L,R,BL,BR,C,LFE,SL,SR");
+ }
+ }
}
return 1;
-
-error:
- aerror("%s => %s\n",
- internal->cmd, snd_strerror(err));
- if (internal->pcm_handle) {
- snd_pcm_close(internal->pcm_handle);
- internal->pcm_handle = NULL;
- }
- return 0;
}
@@ -481,19 +517,16 @@
/* FIXME: underrun length detection */
adebug("underrun, restarting...\n");
/* output buffer underrun */
- internal->cmd = "underrun recovery: snd_pcm_prepare";
err = snd_pcm_prepare(internal->pcm_handle);
if (err < 0)
return err;
} else if (err == -ESTRPIPE) {
/* application was suspended, wait until suspend flag clears */
- internal->cmd = "suspend recovery: snd_pcm_prepare";
while ((err = snd_pcm_resume(internal->pcm_handle)) == -EAGAIN)
sleep (1);
if (err < 0) {
/* unable to wake up pcm device, restart it */
- internal->cmd = "suspend recovery: snd_pcm_prepare";
err = snd_pcm_prepare(internal->pcm_handle);
if (err < 0)
return err;
@@ -580,8 +613,6 @@
free (internal->dev);
else
awarn("ao_plugin_device_clear called with uninitialized ao_device->internal->dev\n");
- if (internal->cmd)
- internal->cmd = NULL;
free(device->internal);
} else
More information about the commits
mailing list