[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