[xiph-commits] r18883 - trunk/ao/src/plugins/alsa
xiphmont at svn.xiph.org
xiphmont at svn.xiph.org
Thu Mar 14 06:35:29 PDT 2013
Author: xiphmont
Date: 2013-03-14 06:35:29 -0700 (Thu, 14 Mar 2013)
New Revision: 18883
Modified:
trunk/ao/src/plugins/alsa/ao_alsa.c
Log:
Add logic to ALSA driver such that it also tries greater bitdepths if device open fails with the requested depth.
Modified: trunk/ao/src/plugins/alsa/ao_alsa.c
===================================================================
--- trunk/ao/src/plugins/alsa/ao_alsa.c 2013-03-14 12:35:24 UTC (rev 18882)
+++ trunk/ao/src/plugins/alsa/ao_alsa.c 2013-03-14 13:35:29 UTC (rev 18883)
@@ -95,7 +95,8 @@
int sample_size;
unsigned int sample_rate;
snd_pcm_format_t bitformat;
- char *pad_24_to_32;
+ char *padbuffer;
+ int padoutw;
char *dev;
int id;
ao_alsa_writei_t * writei;
@@ -204,7 +205,7 @@
int ret;
switch (bitwidth) {
- case 8 : ret = SND_PCM_FORMAT_S8;
+ case 8 : ret = SND_PCM_FORMAT_U8;
break;
case 16 : ret = SND_PCM_FORMAT_S16;
break;
@@ -326,8 +327,38 @@
err = snd_pcm_hw_params_set_format(internal->pcm_handle,
params, internal->bitformat);
if (err < 0){
- adebug("snd_pcm_hw_params_set_format() failed.\n");
- return err;
+
+ /* the device may support a greater bit-depth than the one
+ requested. */
+ switch(internal->bitformat){
+ case SND_PCM_FORMAT_U8:
+ if (!snd_pcm_hw_params_set_format(internal->pcm_handle,
+ params, SND_PCM_FORMAT_S16)){
+ adebug("snd_pcm_hw_params_set_format() unable to open %d bit playback.\n",format->bits);
+ adebug("snd_pcm_hw_params_set_format() using 16 bit playback instead.\n");
+ format->bits = 16;
+ break;
+ }
+ case SND_PCM_FORMAT_S16:
+ if (!snd_pcm_hw_params_set_format(internal->pcm_handle,
+ params, SND_PCM_FORMAT_S24)){
+ adebug("snd_pcm_hw_params_set_format() unable to open %d bit playback.\n",format->bits);
+ adebug("snd_pcm_hw_params_set_format() using 24 bit playback instead.\n");
+ format->bits = 24;
+ break;
+ }
+ case SND_PCM_FORMAT_S24:
+ if (!snd_pcm_hw_params_set_format(internal->pcm_handle,
+ params, SND_PCM_FORMAT_S32)){
+ adebug("snd_pcm_hw_params_set_format() unable to open %d bit playback.\n",format->bits);
+ adebug("snd_pcm_hw_params_set_format() using 32 bit playback instead.\n");
+ format->bits = 32;
+ break;
+ }
+ case SND_PCM_FORMAT_S32:
+ adebug("snd_pcm_hw_params_set_format() failed.\n");
+ return err;
+ }
}
/* set the number of channels */
@@ -338,9 +369,6 @@
return err;
}
- /* save the sample size in bytes for posterity */
- internal->sample_size = format->bits * device->output_channels / 8;
-
/* set the sample rate */
err = snd_pcm_hw_params_set_rate_near(internal->pcm_handle,
params, &rate, 0);
@@ -551,7 +579,7 @@
int ao_plugin_open(ao_device *device, ao_sample_format *format)
{
ao_alsa_internal *internal = (ao_alsa_internal *) device->internal;
- int err;
+ int err,prebits;
/* Get the ALSA bitformat first to make sure it's valid */
err = alsa_get_sample_bitformat(format->bits,
@@ -563,11 +591,15 @@
internal->bitformat = err;
- /* Alsa can only use padded formatting */
- if(format->bits>16 && format->bits<=24)
- internal->pad_24_to_32 = calloc(4096,1);
- else
- internal->pad_24_to_32 = 0;
+ /* Alsa can only use padded 24 bit formatting */
+ if(format->bits>16 && format->bits<=24){
+ internal->padbuffer = calloc(4096,1);
+ internal->padoutw = 32;
+ }else{
+ internal->padbuffer = 0;
+ internal->padoutw = 0;
+ }
+ prebits = format->bits;
/* Open the ALSA device */
err=0;
@@ -621,6 +653,12 @@
return 0;
}
+ if(prebits != format->bits){
+ internal->padbuffer = calloc(4096,1);
+ internal->padoutw = (format->bits+7)/8;
+ format->bits=prebits;
+ }
+
adebug("Using ALSA device '%s'\n",internal->dev);
{
snd_pcm_sframes_t sframes;
@@ -631,6 +669,9 @@
}
}
+ /* save the sample size in bytes for posterity */
+ internal->sample_size = format->bits * device->output_channels / 8;
+
/* alsa's endinness will be the same as the application's */
if (format->bits > 8)
device->driver_byte_format = device->client_byte_format;
@@ -724,30 +765,50 @@
ao_alsa_internal *internal = (ao_alsa_internal *) device->internal;
int endianp = ao_is_big_endian();
- /* eventually the 24 bit padding should be at a higher layer
- where we're doing other permutation/swizzling, but for now
- only ALSA has need of this... */
- if(internal->pad_24_to_32){
- /* pad and forward ~ a page at a time; must not hang on fractional frames*/
- while(num_bytes>=internal->sample_size){
- char *d = internal->pad_24_to_32;
- int len4 = 4096/(4*device->output_channels);
- int len3 = num_bytes/internal->sample_size;
- int i;
- if(len4>len3)len4=len3;
- len4*=device->output_channels;
+ /* the bit padding should be at a higher layer where we're doing
+ other permutation/swizzling, but for now only ALSA has need of
+ this, and moving it up will require a plugin API change */
- if(endianp)++d;
+ if(internal->padbuffer){
+ /* pad and forward ~ a page at a time; must not hang on fractional frames */
+ int ibytewidth = internal->sample_size / device->output_channels;
+ int obytewidth = internal->padoutw;
+ int istride = internal->sample_size;
+ int ostride = obytewidth*device->output_channels;
- for(i=0;i<len4;i++){
- memcpy(d,output_samples,3);
- d+=4;
- output_samples+=3;
+ while(num_bytes >= internal->sample_size){
+ int oframes = 4096/(obytewidth*device->output_channels);
+ int iframes = num_bytes/internal->sample_size;
+ int frames = oframes<iframes ? oframes : iframes;
+ int obytes = frames * obytewidth * device->output_channels;
+ int ibytes = frames * ibytewidth * device->output_channels;
+ int i,j;
+
+ /* copy */
+ for(j=0;j<ibytewidth;j++){
+ const char *s = output_samples + j;
+ char *d = internal->padbuffer + (endianp ? j : obytewidth-ibytewidth+j);
+ for(i=0;i<frames*device->output_channels;i++){
+ *d = *s;
+ s+=ibytewidth;
+ d+=obytewidth;
+ }
}
- if(!ao_plugin_playi(device,internal->pad_24_to_32,len4*4,4*device->output_channels))
+ /* pad */
+ for(;j<obytewidth;j++){
+ char *d = internal->padbuffer + (endianp ? j : j-ibytewidth);
+ for(i=0;i<frames*device->output_channels;i++){
+ *d = 0;
+ d+=obytewidth;
+ }
+ }
+
+ if(!ao_plugin_playi(device,internal->padbuffer,obytes,obytewidth*device->output_channels))
return 0;
- num_bytes-=len4*3;
+
+ num_bytes-=frames*internal->sample_size;
+ output_samples+=frames*internal->sample_size;
}
return 1;
}else
@@ -819,8 +880,8 @@
free (internal->dev);
else
awarn("ao_plugin_device_clear called with uninitialized ao_device->internal->dev\n");
- if (internal->pad_24_to_32)
- free (internal->pad_24_to_32);
+ if (internal->padbuffer)
+ free (internal->padbuffer);
free(internal);
device->internal=NULL;
} else
More information about the commits
mailing list