[xiph-commits] r16802 - in trunk/ao: . doc include/ao src src/plugins/alsa09

xiphmont at svn.xiph.org xiphmont at svn.xiph.org
Sun Jan 24 23:17:41 PST 2010


Author: xiphmont
Date: 2010-01-24 23:17:41 -0800 (Sun, 24 Jan 2010)
New Revision: 16802

Modified:
   trunk/ao/Makefile.am
   trunk/ao/doc/ao_sample_format.html
   trunk/ao/include/ao/ao_private.h
   trunk/ao/src/audio_out.c
   trunk/ao/src/plugins/alsa09/ao_alsa09.c
Log:
Ongoing channel matrixing support work; first cut of negotiation code is 
in place with hardware mappings for ALSA driver.  Sample swapping not 
yet in place.



Modified: trunk/ao/Makefile.am
===================================================================
--- trunk/ao/Makefile.am	2010-01-24 16:52:06 UTC (rev 16801)
+++ trunk/ao/Makefile.am	2010-01-25 07:17:41 UTC (rev 16802)
@@ -15,7 +15,9 @@
 EXTRA_DIST = README AUTHORS CHANGES COPYING libao.spec ao.m4 acinclude.m4 ao.pc.in $(man_MANS)
 
 debug:
+	$(MAKE) clean
 	$(MAKE) all CFLAGS="@DEBUG@"
 
 profile:
+	$(MAKE) clean
 	$(MAKE) all CFLAGS="@PROFILE@"

Modified: trunk/ao/doc/ao_sample_format.html
===================================================================
--- trunk/ao/doc/ao_sample_format.html	2010-01-24 16:52:06 UTC (rev 16801)
+++ trunk/ao/doc/ao_sample_format.html	2010-01-25 07:17:41 UTC (rev 16802)
@@ -61,7 +61,7 @@
 <li>SL - Side Left speaker, located directly to the listener's left side.  The Side Left speaker is also referred to as 'Left Surround Direct' (primarily by Apple) or 'Surround Left' (primarily by Dolby) </li>
 <li>SR - Side Right speaker, located directly to the listener's right side.  The Side Right speaker is also referred to as 'Right Surround Direct' (primarily by Apple) or 'Surround Right' (primarily by Dolby) </li>
 <li>LFE - Low Frequency Effect (subwoofer) channel.  This is channel is usually lowpassed and meant only for bass, though in some recent formats it is a discrete, full-range channel.  Microsoft calls this the 'Low Frequency' channel.
-<li>A1, A2, A3, A4 - 'auxiliary' channels, not mapped to a location.  Intended to be unmatrixed channels directly passed through to the driver for driver-specific use.</li>
+<li>A1, A2, A3, A4 - 'auxiliary' channels, not mapped to a location.  Intended for driver-specific use.</li>
 <li>U - Unused channel, to be dropped in the driver and not output to any speaker.</li>
 </ul>
 

Modified: trunk/ao/include/ao/ao_private.h
===================================================================
--- trunk/ao/include/ao/ao_private.h	2010-01-24 16:52:06 UTC (rev 16801)
+++ trunk/ao/include/ao/ao_private.h	2010-01-25 07:17:41 UTC (rev 16802)
@@ -73,9 +73,13 @@
 	int  driver_byte_format;
 	char *swap_buffer;
 	int  swap_buffer_size; /* Bytes allocated to swap_buffer */
+
+        int output_channels;
         char *output_matrix;
         int  *permute_channels;
 	void *internal; /* Pointer to driver-specific data */
+
+        int verbose;
 };
 
 struct ao_functions {

Modified: trunk/ao/src/audio_out.c
===================================================================
--- trunk/ao/src/audio_out.c	2010-01-24 16:52:06 UTC (rev 16801)
+++ trunk/ao/src/audio_out.c	2010-01-25 07:17:41 UTC (rev 16802)
@@ -27,6 +27,7 @@
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
+#include <ctype.h>
 #include <limits.h>
 #if defined HAVE_DLFCN_H && defined HAVE_DLOPEN
 # include <dlfcn.h>
@@ -419,6 +420,9 @@
 		device->swap_buffer = NULL;
 		device->swap_buffer_size = 0;
 		device->internal = NULL;
+                device->output_channels = format->channels;
+                device->permute_channels = NULL;
+                device->output_matrix = NULL;
 	}
 
 	return device;
@@ -457,7 +461,85 @@
 	}
 }
 
+/* the channel locations we know right now. code below assumes M is in slot 0 */
+static char *mnemonics[]={
+  "M","L","C","R","CL","CR","SL","SR","BL","BC","BR","LFE","U",
+  "A1","A2","A3","A4","A5","A6","A7","A8","A9",NULL
+};
 
+/* Check the requested maxtrix string for syntax and mnemonics */
+static char *_sanitize_matrix(char *matrix,int quiet){
+  if(matrix){
+    char *ret = calloc(strlen(matrix)+1,1); /* can only get smaller */
+    char *p=matrix;
+    int count=0;
+    while(1){
+      char *h,*t;
+      int m=0;
+
+      /* trim leading space */
+      while(*p && isspace(*p))p++;
+
+      /* search for seperator */
+      h=p;
+      while(*h && *h!=',')h++;
+
+      /* trim trailing space */
+      t=h;
+      while(t>p && isspace(*(t-1)))t--;
+
+      while(mnemonics[m]){
+        if(t-p && !strncmp(mnemonics[m],p,t-p)){
+          if(count)strcat(ret,",");
+          strcat(ret,mnemonics[m]);
+          break;
+        }
+        m++;
+      }
+      if(!mnemonics[m]){
+        /* unrecognized channel mnemonic */
+        if(!quiet){
+          int i;
+          fprintf(stderr,"\nUnrecognized channel name \"");
+          for(i=0;i<t-p;i++)fputc(p[i],stderr);
+          fprintf(stderr,"\" in channel matrix \"%s\"\n",matrix);
+        }
+        free(ret);
+        return NULL;
+      }
+      count++;
+      if(!*h)break;
+      p=h+1;
+    }
+    return ret;
+  }else
+    return NULL;
+}
+
+static int _find_channel(int needle, char *haystack){
+  char *p=haystack;
+  int count=0;
+  while(1){
+    char *h;
+    int m=0;
+
+    /* search for seperator */
+    h=p;
+    while(*h && *h!=',')h++;
+
+    while(mnemonics[m]){
+      if(!strncmp(mnemonics[needle],p,h-p))break;
+      m++;
+    }
+    if(mnemonics[m])
+      return count;
+    count++;
+    if(!*h)break;
+    p=h+1;
+  }
+  return -1;
+}
+
 /* Open a device.  If this is a live device, file == NULL. */
 static ao_device* _open_device(int driver_id, ao_sample_format *format,
 			       ao_option *options, FILE *file)
@@ -466,6 +548,7 @@
 	driver_list *driver;
 	ao_device *device;
 	int result;
+        ao_sample_format sformat=*format;
 
 	/* Get driver id */
 	if ( (driver = _get_driver(driver_id)) == NULL ) {
@@ -508,8 +591,15 @@
           if(!strcmp(options->key,"matrix")){
             /* explicitly set the output matrix to the requested
                string; devices must not override. */
-            _sanitize_matrix(options->value);
-            device->output_matrix = strdup(options->value);
+            device->output_matrix = _sanitize_matrix(options->value, device->verbose==-1);
+            if(!device->output_matrix){
+              errno = AO_EBADOPTION;
+              return NULL;
+            }
+          }else if(!strcmp(options->key,"verbose")){
+            device->verbose=1;
+          }else if(!strcmp(options->key,"quiet")){
+            device->verbose=-1;
           }else{
             if (!funcs->set_option(device, options->key, options->value)) {
               /* Problem setting options */
@@ -522,19 +612,82 @@
           options = options->next;
 	}
 
+        /* also sanitize the format input channel matrix */
+        if(format->matrix){
+          sformat.matrix = _sanitize_matrix(format->matrix, device->verbose==-1);
+          if(!sformat.matrix && device->verbose>=0)
+            fprintf(stderr,"Input channel matrix invalid; ignoring.\n");
+        }
+
 	/* Open the device */
-	result = funcs->open(device, format);
+	result = funcs->open(device, &sformat);
 	if (!result) {
+                if(sformat.matrix)free(sformat.matrix);
 		funcs->device_clear(device);
 		free(device);
 		errno = AO_EOPENDEVICE;
 		return NULL; /* Couldn't open device */
 	}
 
-        /* set permuatation vector */
+        /* resolve channel mapping request if any */
+        if(sformat.matrix){
+          if(!device->output_matrix){
+            if(device->verbose>=0)
+              fprintf(stderr,"\nOutput driver %s does not support channel matrixing;\n"
+                      "continuing without routing channels to specific locations.\n\n",
+                      info_table[device->driver_id]->short_name);
+          }else{
 
+            /* walk thorugh the output matrix, match outputs to inputs */
+            char *op=device->output_matrix;
+            int count=0;
+            device->permute_channels = calloc(device->output_channels,sizeof(int));
 
+            if(device->verbose>0)
+              fprintf(stderr,"\n");
 
+            while(count<device->output_channels){
+              int m=0,mm;
+              char *h=op;
+
+              if(op){
+                /* find mnemonic offset of output channel */
+                while(*h && *h!=',')h++;
+                while(mnemonics[m]){
+                  if(!strncmp(mnemonics[m],op,h-op))
+                    break;
+                  m++;
+                }
+                mm=m;
+
+                /* find match in input if any */
+                device->permute_channels[count] = _find_channel(m,sformat.matrix);
+                if(device->permute_channels[count] == -1 && sformat.channels == 1){
+                  device->permute_channels[count] = _find_channel(0,sformat.matrix);
+                  mm=0;
+                }
+              }else
+                device->permute_channels[count] = -1;
+
+              /* display resulting mapping for now */
+              if(device->verbose>0)
+                if(device->permute_channels[count]>=0){
+                  fprintf(stderr,"Output %d (%s)\t <- input %d (%s)\n",
+                          count,mnemonics[m],device->permute_channels[count],
+                          mnemonics[mm]);
+                }else{
+                  fprintf(stderr,"Output %d (%s)\t <- none\n",
+                          count,mnemonics[m]);
+                }
+              count++;
+              if(!h)
+                op=NULL;
+              else
+                op=h+1;
+            }
+          }
+        }
+
 	/* Resolve actual driver byte format */
 	device->driver_byte_format =
 		_real_byte_format(device->driver_byte_format);
@@ -543,19 +696,21 @@
 	if (format->bits == 16 &&
 	    device->client_byte_format != device->driver_byte_format) {
 
-	  fprintf(stderr,
-		  "n\n\n\n-------------------------\n"
-		  "big : %d\n"
-		  "device->client_byte_format:%d\n"
-		  "device->driver_byte_format:%d\n"
-		  "--------------------------\n",
-		  ao_is_big_endian(),device->client_byte_format,device->driver_byte_format);
+          if(device->verbose>0)
+            fprintf(stderr,
+                    "n\n\n\n-------------------------\n"
+                    "big : %d\n"
+                    "device->client_byte_format:%d\n"
+                    "device->driver_byte_format:%d\n"
+                    "--------------------------\n",
+                    ao_is_big_endian(),device->client_byte_format,device->driver_byte_format);
 
 		result = _realloc_swap_buffer(device, DEF_SWAP_BUF_SIZE);
 
 		if (!result) {
 
-			device->funcs->close(device);
+			if(sformat.matrix)free(sformat.matrix);
+                        device->funcs->close(device);
 			device->funcs->device_clear(device);
 			free(device);
 			errno = AO_EFAIL;
@@ -564,6 +719,7 @@
 	}
 
 	/* If we made it this far, everything is OK. */
+        if(sformat.matrix)free(sformat.matrix);
 	return device;
 }
 
@@ -624,7 +780,7 @@
 	if (op == NULL) return 0;
 
 	op->key = strdup(key);
-	op->value = strdup(value);
+	op->value = strdup(value?value:"");
 	op->next = NULL;
 
 	if ((list = *options) != NULL) {
@@ -743,7 +899,8 @@
 
 		if (device->swap_buffer != NULL)
 			free(device->swap_buffer);
-
+                if (device->output_matrix != NULL)
+                        free(device->output_matrix);
 		free(device);
 	}
 

Modified: trunk/ao/src/plugins/alsa09/ao_alsa09.c
===================================================================
--- trunk/ao/src/plugins/alsa09/ao_alsa09.c	2010-01-24 16:52:06 UTC (rev 16801)
+++ trunk/ao/src/plugins/alsa09/ao_alsa09.c	2010-01-25 07:17:41 UTC (rev 16802)
@@ -385,6 +385,9 @@
 	if (format->bits > 8)
 		device->driver_byte_format = device->client_byte_format;
 
+        if(!device->output_matrix)
+          device->output_matrix=strdup("L,R,BL,BR,C,LFE,SL,SR");
+
 	return 1;
 
 error:



More information about the commits mailing list