[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(&params);
 
 	/* 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(&params);
 
 	/* 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