[xiph-commits] r16982 - in trunk/ao: include/ao src src/plugins/alsa src/plugins/arts src/plugins/esd src/plugins/irix src/plugins/macosx src/plugins/nas src/plugins/oss src/plugins/pulse src/plugins/sun
xiphmont at svn.xiph.org
xiphmont at svn.xiph.org
Thu Mar 18 12:50:05 PDT 2010
Author: xiphmont
Date: 2010-03-18 12:50:04 -0700 (Thu, 18 Mar 2010)
New Revision: 16982
Modified:
trunk/ao/include/ao/ao.h
trunk/ao/include/ao/ao_private.h
trunk/ao/src/ao_aixs.c
trunk/ao/src/ao_au.c
trunk/ao/src/ao_null.c
trunk/ao/src/ao_raw.c
trunk/ao/src/ao_wav.c
trunk/ao/src/ao_wmm.c
trunk/ao/src/audio_out.c
trunk/ao/src/plugins/alsa/ao_alsa.c
trunk/ao/src/plugins/arts/ao_arts.c
trunk/ao/src/plugins/esd/ao_esd.c
trunk/ao/src/plugins/irix/ao_irix.c
trunk/ao/src/plugins/macosx/ao_macosx.c
trunk/ao/src/plugins/nas/ao_nas.c
trunk/ao/src/plugins/oss/ao_oss.c
trunk/ao/src/plugins/pulse/ao_pulse.c
trunk/ao/src/plugins/sun/ao_sun.c
Log:
Centralize most of the channel matrix setup processing that drivers were doing independently.
Update Windows WMM driver to support matrixing
Modified: trunk/ao/include/ao/ao.h
===================================================================
--- trunk/ao/include/ao/ao.h 2010-03-17 15:54:34 UTC (rev 16981)
+++ trunk/ao/include/ao/ao.h 2010-03-18 19:50:04 UTC (rev 16982)
@@ -50,6 +50,7 @@
#define AO_EOPENDEVICE 5
#define AO_EOPENFILE 6
#define AO_EFILEEXISTS 7
+#define AO_EBADFORMAT 8
#define AO_EFAIL 100
Modified: trunk/ao/include/ao/ao_private.h
===================================================================
--- trunk/ao/include/ao/ao_private.h 2010-03-17 15:54:34 UTC (rev 16981)
+++ trunk/ao/include/ao/ao_private.h 2010-03-18 19:50:04 UTC (rev 16982)
@@ -63,14 +63,21 @@
char *default_driver;
} ao_config;
+typedef enum {
+ AO_OUTPUT_MATRIX_UNDEFINED=0, /* matrix unset */
+ AO_OUTPUT_MATRIX_FIXED=1, /* fixed, immutable channel order, eg, ALSA */
+ AO_OUTPUT_MATRIX_COLLAPSIBLE=2, /* fixed order but only used channels sent, eg MACOS */
+ AO_OUTPUT_MATRIX_PERMUTABLE=3, /* channel map is fully permutable. eg Pulse */
+} ao_outorder;
+
struct ao_device {
int type; /* live output or file output? */
int driver_id;
ao_functions *funcs;
FILE *file; /* File for output if this is a file driver */
- /* input not necessarily == output. Right now, byte order and
- channel mappings may be altered. */
+ /* input not necessarily == output. Right now, byte order, channel
+ count, and channel mappings may be altered. */
int client_byte_format;
int machine_byte_format;
@@ -82,10 +89,34 @@
int output_channels;
int bytewidth;
int rate;
- char *output_matrix;
- int *permute_channels;
- void *internal; /* Pointer to driver-specific data */
+ ao_outorder output_matrix_order;
+ char *output_matrix; /* physical output channel
+ ordering/numbering matrix set by
+ driver if there's a channel
+ name->number mapping useful to the
+ backend driver in some way. Eg,
+ Pulse has fully permutable input
+ channel masks, but specific channels
+ locations (eg, 'Center') still have
+ assigned numbers even if not a
+ specific slot int he input
+ interleave. */
+ int output_mask;
+ int *input_map; /* input permutation mapping from each
+ input channel to a location in the
+ output_matrix. Made by ao_open,
+ intended for convenience use by
+ driver in device open. */
+
+ char *inter_matrix; /* channel matrix as presented to the
+ backend API */
+ int *inter_permute; /* maps from each channel in the
+ inter_matrix back to an input channel
+ (if any) */
+
+ void *internal; /* Pointer to driver-specific data */
+
int verbose;
};
Modified: trunk/ao/src/ao_aixs.c
===================================================================
--- trunk/ao/src/ao_aixs.c 2010-03-17 15:54:34 UTC (rev 16981)
+++ trunk/ao/src/ao_aixs.c 2010-03-18 19:50:04 UTC (rev 16982)
@@ -108,6 +108,7 @@
}
device->internal = internal;
+ device->output_matrix_order = AO_OUTPUT_MATRIX_FIXED;
return 1; /* Memory alloc successful */
}
@@ -140,7 +141,7 @@
init.srate = format->rate;
init.bits_per_sample = format->bits;
- init.channels = format->channels;
+ init.channels = device->output_channels;
init.mode = AUDIO_PCM;
init.flags = AUDIO_BIG_ENDIAN | AUDIO_TWOS_COMPLEMENT;
init.operation = AUDIO_PLAY;
@@ -174,11 +175,10 @@
}
device->driver_byte_format = AO_FMT_NATIVE;
-
- if(!device->output_matrix){
- /* set up out matrix such that users are warned about > stereo playback */
- if(format->channels<=2)
- device->output_matrix=strdup("L,R");
+ if(!device->inter_matrix){
+ /* set up matrix such that users are warned about > stereo playback */
+ if(device->output_channels<=2)
+ device->inter_matrix=strdup("L,R");
//else no matrix, which results in a warning
}
Modified: trunk/ao/src/ao_au.c
===================================================================
--- trunk/ao/src/ao_au.c 2010-03-17 15:54:34 UTC (rev 16981)
+++ trunk/ao/src/ao_au.c 2010-03-18 19:50:04 UTC (rev 16982)
@@ -112,6 +112,7 @@
memset(&(internal->au), 0, sizeof(internal->au));
device->internal = internal;
+ device->output_matrix_order = AO_OUTPUT_MATRIX_FIXED;
return 1; /* Memory alloc successful */
}
@@ -134,7 +135,7 @@
/* Fill out the header */
internal->au.magic = AUDIO_FILE_MAGIC;
- internal->au.channels = format->channels;
+ internal->au.channels = device->output_channels;
if (format->bits == 8)
internal->au.encoding = AUDIO_FILE_ENCODING_LINEAR_8;
else if (format->bits == 16)
@@ -168,13 +169,14 @@
return 0; /* Error writing header */
}
- if(!device->output_matrix){
- /* set up out matrix such that users are warned about > stereo playback */
- if(format->channels<=2)
- device->output_matrix=strdup("L,R");
+ if(!device->inter_matrix){
+ /* set up matrix such that users are warned about > stereo playback */
+ if(device->output_channels<=2)
+ device->inter_matrix=strdup("L,R");
//else no matrix, which results in a warning
}
+
return 1;
}
Modified: trunk/ao/src/ao_null.c
===================================================================
--- trunk/ao/src/ao_null.c 2010-03-17 15:54:34 UTC (rev 16981)
+++ trunk/ao/src/ao_null.c 2010-03-18 19:50:04 UTC (rev 16982)
@@ -77,6 +77,7 @@
internal->byte_counter = 0;
device->internal = internal;
+ device->output_matrix_order = AO_OUTPUT_MATRIX_FIXED;
return 1; /* Memory alloc successful */
}
@@ -97,9 +98,10 @@
/* Use whatever format the client requested */
device->driver_byte_format = device->client_byte_format;
- if(!device->output_matrix){
- /* all channels 'unavailable' */
- device->output_matrix=strdup("X");
+ if(!device->inter_matrix){
+ /* by default, we want inter == in */
+ if(format->matrix)
+ device->inter_matrix = strdup(format->matrix);
}
return 1;
@@ -121,7 +123,7 @@
{
ao_null_internal *internal = (ao_null_internal *) device->internal;
- adebug("%ld bytes sent to null device.\n");
+ adebug("%ld bytes sent to null device.\n", internal->byte_counter);
return 1;
}
Modified: trunk/ao/src/ao_raw.c
===================================================================
--- trunk/ao/src/ao_raw.c 2010-03-17 15:54:34 UTC (rev 16981)
+++ trunk/ao/src/ao_raw.c 2010-03-18 19:50:04 UTC (rev 16982)
@@ -77,6 +77,7 @@
internal->byte_order = AO_FMT_NATIVE;
device->internal = internal;
+ device->output_matrix_order = AO_OUTPUT_MATRIX_FIXED;
return 1; /* Memory alloc successful */
}
@@ -107,11 +108,11 @@
device->driver_byte_format = internal->byte_order;
- if(!device->output_matrix){
- /* by default, out == in */
- if(format->matrix)
- device->output_matrix = strdup(format->matrix);
- }
+ //if(!device->inter_matrix){
+ ///* by default, inter == in */
+ //if(format->matrix)
+ // device->inter_matrix = strdup(format->matrix);
+ //}
return 1;
}
Modified: trunk/ao/src/ao_wav.c
===================================================================
--- trunk/ao/src/ao_wav.c 2010-03-17 15:54:34 UTC (rev 16981)
+++ trunk/ao/src/ao_wav.c 2010-03-18 19:50:04 UTC (rev 16982)
@@ -134,6 +134,8 @@
memset(&(internal->wave), 0, sizeof(internal->wave));
device->internal = internal;
+ device->output_matrix = strdup("L,R,C,LFE,BL,BR,CL,CR,BC,SL,SR");
+ device->output_matrix_order = AO_OUTPUT_MATRIX_COLLAPSIBLE;
return 1; /* Memory alloc successful */
}
@@ -145,51 +147,6 @@
return 1; /* No options! */
}
-static char *map[]={
- "L","R","C","LFE","BL","BR","CL","CR","BC","SL","SR",NULL
-};
-#define SPEAKER_RESERVED 0x80000000
-
-static unsigned int _matrix_to_channelmask(char *matrix){
- unsigned int ret=0;
- char *p=matrix;
- while(1){
- char *h=p;
- int m=0;
-
- /* search for seperator */
- while(*h && *h!=',')h++;
-
- while(map[m]){
- if(h-p && !strncmp(map[m],p,h-p) &&
- strlen(map[m])==h-p)
- break;
- m++;
- }
- if(map[m])
- ret |= (1<<m);
- if(!*h)break;
- p=h+1;
- }
- return ret;
-}
-
-static char *_channelmask_to_matrix(unsigned int mask){
- int m=0;
- int count=0;
- char buffer[80]={0};
- while(map[m]){
- if(mask & (1<<m)){
- if(count)
- strcat(buffer,",");
- strcat(buffer,map[m]);
- count++;
- }
- m++;
- }
- return strdup(buffer);
-}
-
static int ao_wav_open(ao_device *device, ao_sample_format *format)
{
ao_wav_internal *internal = (ao_wav_internal *) device->internal;
@@ -197,7 +154,7 @@
int size = 0x7fffffff; /* Use a bogus size initially */
/* Store information */
- internal->wave.common.wChannels = format->channels;
+ internal->wave.common.wChannels = device->output_channels;
internal->wave.common.wBitsPerSample = ((format->bits+7)>>3)<<3;
internal->wave.common.wValidBitsPerSample = format->bits;
internal->wave.common.dwSamplesPerSec = format->rate;
@@ -223,20 +180,8 @@
(internal->wave.common.wBitsPerSample >> 3);
internal->wave.common.cbSize = 22;
internal->wave.common.subFormat = WAVE_FORMAT_PCM;
+ internal->wave.common.dwChannelMask=device->output_mask;
- /* contruct channel mask; WAV is capable of expressing any
- channel format currently representable in libao */
- if(format->matrix){
- if(device->output_matrix){
- internal->wave.common.dwChannelMask=_matrix_to_channelmask(device->output_matrix);
- }else{
- internal->wave.common.dwChannelMask=_matrix_to_channelmask(format->matrix);
- device->output_matrix = _channelmask_to_matrix(internal->wave.common.dwChannelMask);
- }
- }else{
- internal->wave.common.dwChannelMask=0;
- }
-
strncpy(internal->wave.data.id, "data",4);
internal->wave.data.len = size - WAV_HEADER_LEN;
Modified: trunk/ao/src/ao_wmm.c
===================================================================
--- trunk/ao/src/ao_wmm.c 2010-03-17 15:54:34 UTC (rev 16981)
+++ trunk/ao/src/ao_wmm.c 2010-03-18 19:50:04 UTC (rev 16982)
@@ -196,44 +196,12 @@
res = internal != NULL;
+ device->output_matrix = strdup("L,R,C,LFE,BL,BR,CL,CR,BC,SL,SR");
+ device->output_matrix_order = AO_OUTPUT_MATRIX_COLLAPSIBLE;
+
return res;
}
-#if 0
-static void CALLBACK
-waveOutProc(HWAVEOUT hwo,
- UINT uMsg, DWORD_PTR dwInstance,
- DWORD_PTR dwParam1, DWORD_PTR dwParam2)
-{
- ao_device *device = (ao_device *) dwInstance;
- ao_wmm_internal *internal = (ao_wmm_internal *) device->internal;
-
- switch (uMsg) {
-
- case WOM_OPEN:
- /* Sent when the device is opened using the waveOutOpen function. */
- break;
-
- case WOM_CLOSE:
- /* Sent when the device is closed using the waveOutClose function. */
- break;
-
- case WOM_DONE:
- /* Sent when the device driver is finished with a data block sent
- using the waveOutWrite function. */
- {
- LPWAVEHDR lpwvhdr = (LPWAVEHDR) dwParam1;
- int me = lpwvhdr - internal->wh;
- lpwvhdr->dwBytesRecorded = 0;
- }
- break;
-
- default:
- break;
- }
-}
-#endif
-
static int _ao_open_device(ao_device *device)
{
ao_wmm_internal *internal = (ao_wmm_internal *) device->internal;
@@ -421,10 +389,10 @@
{
ao_wmm_internal *internal = (ao_wmm_internal *) device->internal;
int res = 0;
- WAVEFORMATEX wavefmt;
+ WAVEFORMATEXTENSIBLE wavefmt;
adebug("open() channels=%d, bits=%d, rate=%d, format %d(%s)\n",
- format->channels,format->bits,format->rate,format->byte_format,
+ device->output_channels,format->bits,format->rate,format->byte_format,
format->byte_format==AO_FMT_LITTLE
?"little"
:(format->byte_format==AO_FMT_NATIVE
@@ -440,26 +408,22 @@
format->byte_format = AO_FMT_LITTLE;
device->driver_byte_format = AO_FMT_LITTLE;
- if (! (format->channels == 1 || format->channels == 2) ||
- ! (format->bits == 8 || format->bits == 16) ||
- ! (format->rate >= 6000 && format->rate <= 50000)
- ) {
- aerror("open() => unable to handle input format\n");
- goto error;
- }
-
/* $$$ WMM 8 bit samples are unsigned... Not sure for ao ... */
/* Yes, ao 8 bit PCM is unsigned -- Monty */
/* Make sample format */
memset(&wavefmt,0,sizeof(wavefmt));
- wavefmt.wFormatTag = WAVE_FORMAT_PCM;
- wavefmt.nChannels = format->channels;
- wavefmt.wBitsPerSample = format->bits;
- wavefmt.nSamplesPerSec = format->rate;
- wavefmt.nBlockAlign = ((wavefmt.wBitsPerSample+7)>>3)*wavefmt.nChannels;
- wavefmt.nAvgBytesPerSec = wavefmt.nSamplesPerSec*wavefmt.nBlockAlign;
- wavefmt.cbSize = 0;
+ wavefmt.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
+ wavefmt.nChannels = device->output_channels;
+ wavefmt.wBitsPerSample = (((format->bits+7)>>3)<<3);
+ wavefmt.nSamplesPerSec = format->rate;
+ wavefmt.nBlockAlign = (wavefmt.wBitsPerSample>>3)*wavefmt.nChannels;
+ wavefmt.nAvgBytesPerSec = wavefmt.nSamplesPerSec*wavefmt.nBlockAlign;
+ wavefmt.cbSize = 22;
+ wavefmt.wValidBitsPerSample = format->bits;
+ wavefmt.subFormat = WAVE_FORMAT_PCM;
+ wavefmt.dwChannelMask = device->output_mask;
+
internal->wavefmt = wavefmt;
/* $$$ later this should be optionnal parms */
Modified: trunk/ao/src/audio_out.c
===================================================================
--- trunk/ao/src/audio_out.c 2010-03-17 15:54:34 UTC (rev 16981)
+++ trunk/ao/src/audio_out.c 2010-03-18 19:50:04 UTC (rev 16982)
@@ -424,7 +424,7 @@
device->swap_buffer_size = 0;
device->internal = NULL;
device->output_channels = format->channels;
- device->permute_channels = NULL;
+ device->inter_permute = NULL;
device->output_matrix = NULL;
}
@@ -585,7 +585,8 @@
/* the channel locations we know right now. code below assumes U is in slot 0, X in 1, M in 2 */
static char *mnemonics[]={
- "U","X","M",
+ "X",
+ "M",
"L","C","R","CL","CR","SL","SR","BL","BC","BR","LFE",
"A1","A2","A3","A4","A5","A6","A7","A8","A9","A10",
"A11","A12","A13","A14","A15","A16","A17","A18","A19","A20",
@@ -593,13 +594,13 @@
"A31","A32",NULL
};
-/* Check the requested maxtrix string for syntax and mnemonics */
-static char *_sanitize_matrix(char *matrix, ao_device *device){
+/* Check the requested matrix string for syntax and mnemonics */
+static char *_sanitize_matrix(int maxchannels, char *matrix, ao_device *device){
if(matrix){
char *ret = calloc(strlen(matrix)+1,1); /* can only get smaller */
char *p=matrix;
int count=0;
- while(1){
+ while(count<maxchannels){
char *h,*t;
int m=0;
@@ -633,8 +634,8 @@
}
free(ret);
return NULL;
- }
- count++;
+ }else
+ count++;
if(!*h)break;
p=h+1;
}
@@ -646,6 +647,10 @@
static int _find_channel(int needle, char *haystack){
char *p=haystack;
int count=0;
+
+ /* X does not map to anything, including X! */
+ if(needle==0) return -1;
+
while(1){
char *h;
int m=0;
@@ -668,20 +673,192 @@
return -1;
}
+static char **_tokenize_matrix(char *matrix){
+ char **ret=NULL;
+ char *p=matrix;
+ int count=0;
+ while(1){
+ char *h,*t;
+
+ /* 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--;
+
+ count++;
+ if(!*h)break;
+ p=h+1;
+ }
+
+ ret = calloc(count+1,sizeof(*ret));
+
+ p=matrix;
+ count=0;
+ while(1){
+ char *h,*t;
+
+ /* 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--;
+
+ ret[count++] = strndup(p,t-p);
+ if(!*h)break;
+ p=h+1;
+ }
+
+ return ret;
+
+}
+
+static void _free_map(char **m){
+ char **in=m;
+ while(m && *m){
+ free(*m);
+ m++;
+ }
+ if(in)free(in);
+}
+
+static unsigned int _matrix_to_channelmask(int ch, char *matrix, char *premap, int **mout){
+ unsigned int ret=0;
+ char *p=matrix;
+ int *perm=(*mout=malloc(ch*sizeof(*mout)));
+ int i;
+ char **map = _tokenize_matrix(premap);
+
+ for(i=0;i<ch;i++) perm[i] = -1;
+ i=0;
+
+ while(1){
+ char *h=p;
+ int m=0;
+
+ /* search for seperator */
+ while(*h && *h!=',')h++;
+
+ while(map[m]){
+ if(h-p && !strncmp(map[m],p,h-p) &&
+ strlen(map[m])==h-p)
+ break;
+ m++;
+ }
+ /* X is a placeholder, X does not map to X */
+ if(map[m] && strcmp(map[m],"X")){
+ ret |= (1<<m);
+ perm[i] = m;
+ }
+ if(!*h)break;
+ p=h+1;
+ i++;
+ }
+
+ _free_map(map);
+ return ret;
+}
+
+static char *_channelmask_to_matrix(unsigned int mask, char *premap){
+ int m=0;
+ int count=0;
+ char buffer[257]={0};
+ char **map = _tokenize_matrix(premap);
+
+ while(map[m]){
+ if(mask & (1<<m)){
+ if(count)
+ strcat(buffer,",");
+ strcat(buffer,map[m]);
+ count++;
+ }
+ m++;
+ }
+ _free_map(map);
+ return strdup(buffer);
+}
+
+static int _channelmask_bits(unsigned int mask){
+ int count=0;
+ while(mask){
+ if(mask&1)count++;
+ mask/=2;
+ }
+ return count;
+}
+
+static int _channelmask_maxbit(unsigned int mask){
+ int count=0;
+ int max=-1;
+ while(mask){
+ if(mask&1)max=count;
+ mask/=2;
+ count++;
+ }
+ return max;
+}
+
+static char *_matrix_intersect(char *matrix,char *premap){
+ char *p=matrix;
+ char buffer[257]={0};
+ int count=0;
+ char **map = _tokenize_matrix(premap);
+
+ while(1){
+ char *h=p;
+ int m=0;
+
+ /* search for seperator */
+ while(*h && *h!=',')h++;
+
+ while(map[m]){
+ if(h-p && !strncmp(map[m],p,h-p) &&
+ strlen(map[m])==h-p)
+ break;
+ m++;
+ }
+ /* X is a placeholder, X does not map to X */
+ if(map[m] && strcmp(map[m],"X")){
+ if(count)
+ strcat(buffer,",");
+ strcat(buffer,map[m]);
+ count++;
+ }
+
+ if(!*h)break;
+ p=h+1;
+ }
+
+ _free_map(map);
+ return strdup(buffer);
+}
+
+
/* 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)
{
ao_functions *funcs;
driver_list *driver;
- ao_device *device;
+ ao_device *device=NULL;
int result;
ao_sample_format sformat=*format;
+ sformat.matrix=NULL;
/* Get driver id */
if ( (driver = _get_driver(driver_id)) == NULL ) {
errno = AO_ENODRIVER;
- return NULL; /* No driver exists */
+ goto error;
}
funcs = driver->functions;
@@ -691,39 +868,46 @@
funcs->driver_info()->type != AO_TYPE_LIVE) {
errno = AO_ENOTLIVE;
- return NULL;
+ goto error;
} else if (file != NULL &&
funcs->driver_info()->type != AO_TYPE_FILE) {
errno = AO_ENOTFILE;
- return NULL;
+ goto error;
}
/* Make a new device structure */
if ( (device = _create_device(driver_id, driver,
format, file)) == NULL ) {
errno = AO_EFAIL;
- return NULL; /* Couldn't alloc device */
+ goto error;
}
- /* Initialize the device memory */
+ /* Initialize the device memory; get static channel mapping */
if (!funcs->device_init(device)) {
- free(device);
errno = AO_EFAIL;
- return NULL; /* Couldn't init internal memory */
+ goto error;
}
/* Load options */
while (options != NULL) {
- /* The output matrix option is handled for the drivers here */
if(!strcmp(options->key,"matrix")){
+ /* If a driver has a static channel mapping mechanism
+ (physically constant channel mapping, or at least an
+ unvarying set of constants for mapping channels), the
+ output_matrix is already set. An app/user specified
+ output mapping trumps. */
+ if(device->output_matrix)
+ free(device->output_matrix);
/* explicitly set the output matrix to the requested
string; devices must not override. */
- device->output_matrix = _sanitize_matrix(options->value, device);
+ device->output_matrix = _sanitize_matrix(32, options->value, device);
if(!device->output_matrix){
+ aerror("Empty or inavlid output matrix\n");
errno = AO_EBADOPTION;
- return NULL;
+ goto error;
}
+ adebug("Sanitized device output matrix: %s\n",device->output_matrix);
}else if(!strcmp(options->key,"debug")){
device->verbose=2;
}else if(!strcmp(options->key,"verbose")){
@@ -733,9 +917,8 @@
}else{
if (!funcs->set_option(device, options->key, options->value)) {
/* Problem setting options */
- free(device);
errno = AO_EOPENDEVICE;
- return NULL;
+ goto error;
}
}
@@ -744,12 +927,96 @@
/* also sanitize the format input channel matrix */
if(format->matrix){
- sformat.matrix = _sanitize_matrix(format->matrix, device);
+ sformat.matrix = _sanitize_matrix(format->channels, format->matrix, device);
if(!sformat.matrix)
awarn("Input channel matrix invalid; ignoring.\n");
}
- /* set up any other housekeeping */
+ /* If device init was able to declare a static channel mapping
+ mechanism, reconcile it to the input now. Odd drivers that
+ need to communicate with a backend device to determine
+ channel mapping strategy can still bypass this mechanism
+ entirely. Also, drivers like ALSA may need to adjust
+ strategy depending on what device is successfully opened,
+ etc, but this still saves work later. */
+
+ if(device->output_matrix && sformat.matrix){
+ switch(device->output_matrix_order){
+ case AO_OUTPUT_MATRIX_FIXED:
+ /* Backend channel ordering is immutable and unused
+ channels must still be sent. Look for the highest
+ channel number we are able to map from the input
+ matrix. */
+ {
+ unsigned int mask = _matrix_to_channelmask(sformat.channels,sformat.matrix,
+ device->output_matrix,
+ &device->input_map);
+ int max = _channelmask_maxbit(mask);
+ if(max<0){
+ aerror("Unable to map any channels from input matrix to output");
+ errno = AO_EBADFORMAT;
+ goto error;
+ }
+ device->output_channels = max+1;
+ device->output_mask = mask;
+ device->inter_matrix = strdup(device->output_matrix);
+ }
+ break;
+
+ case AO_OUTPUT_MATRIX_COLLAPSIBLE:
+ /* the ordering of channels submitted to the backend is
+ fixed, but only the channels in use should be present
+ in the audio stream */
+ {
+ unsigned int mask = _matrix_to_channelmask(sformat.channels,sformat.matrix,
+ device->output_matrix,
+ &device->input_map);
+ int channels = _channelmask_bits(mask);
+ if(channels<0){
+ aerror("Unable to map any channels from input matrix to output");
+ errno = AO_EBADFORMAT;
+ goto error;
+ }
+ device->output_channels = channels;
+ device->output_mask = mask;
+ device->inter_matrix = _channelmask_to_matrix(mask,device->output_matrix);
+ }
+ break;
+
+ case AO_OUTPUT_MATRIX_PERMUTABLE:
+ /* The ordering of channels is freeform. Only the
+ channels in use should be sent, and they may be sent in
+ any order. If possible, leave the input ordering
+ unchanged */
+ {
+ unsigned int mask = _matrix_to_channelmask(sformat.channels,sformat.matrix,
+ device->output_matrix,
+ &device->input_map);
+ int channels = _channelmask_bits(mask);
+ if(channels<0){
+ aerror("Unable to map any channels from input matrix to output");
+ errno = AO_EBADFORMAT;
+ goto error;
+ }
+ device->output_channels = channels;
+ device->output_mask = mask;
+ device->inter_matrix = _matrix_intersect(sformat.matrix,device->output_matrix);
+ }
+ break;
+
+ default:
+ aerror("Driver backend failed to set output ordering.\n");
+ errno = AO_EFAIL;
+ goto error;
+ }
+
+ adebug("Channel order submitted to backend: %s\n",device->inter_matrix);
+
+ }else{
+ device->output_channels = sformat.channels;
+ }
+
+ /* other housekeeping */
device->input_channels = sformat.channels;
device->bytewidth = (sformat.bits+7)>>3;
device->rate = sformat.rate;
@@ -757,34 +1024,34 @@
/* Open the device */
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 */
+ errno = AO_EOPENDEVICE;
+ goto error;
}
- /* resolve channel mapping request if any */
+ /* set up permutation based on finalized inter_matrix mapping */
+ /* The only way device->output_channels could be zero here is
+ if the driver has opted to ouput no channels (eg, the null
+ driver). */
if(sformat.matrix){
- if(!device->output_matrix){
- awarn("Driver %s does not support channel matrixing;\n"
+ if(!device->inter_matrix){
+ awarn("Driver %s does not support automatic channel mapping;\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;
+ /* walk thorugh the inter matrix, match channles */
+ char *op=device->inter_matrix;
int count=0;
- device->permute_channels = calloc(device->output_channels,sizeof(int));
+ device->inter_permute = calloc(device->output_channels,sizeof(int));
averbose("\n");
while(count<device->output_channels){
- int m=1,mm;
+ int m=0,mm;
char *h=op;
if(*op){
- /* find mnemonic offset of output channel */
+ /* find mnemonic offset of inter channel */
while(*h && *h!=',')h++;
while(mnemonics[m]){
if(!strncmp(mnemonics[m],op,h-op))
@@ -794,22 +1061,22 @@
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(2,sformat.matrix);
- mm=2;
+ device->inter_permute[count] = _find_channel(m,sformat.matrix);
+ if(device->inter_permute[count] == -1 && sformat.channels == 1){
+ device->inter_permute[count] = _find_channel(1,sformat.matrix);
+ mm=1;
}
}else
- device->permute_channels[count] = -1;
+ device->inter_permute[count] = -1;
/* display resulting mapping for now */
- if(device->permute_channels[count]>=0){
- averbose("Output %d (%s)\t <- input %d (%s)\n",
- count,mnemonics[m],device->permute_channels[count],
- mnemonics[mm]);
+ if(device->inter_permute[count]>=0){
+ averbose("input %d (%s)\t -> backend %d (%s)\n",
+ device->inter_permute[count], mnemonics[mm],
+ count,mnemonics[m]);
}else{
- averbose("Output %d (%s)\t %s\n",
- count,mnemonics[m],(m==1?"unmapped":"<- none"));
+ averbose(" \t backend %d (%s)\n",
+ count,mnemonics[m]);
}
count++;
op=h;
@@ -821,13 +1088,13 @@
}
/* if there's no actual permutation to do, release the permutation vector */
- if(device->permute_channels && device->output_channels == device->input_channels){
+ if(device->inter_permute && device->output_channels == device->input_channels){
int i;
for(i=0;i<device->output_channels;i++)
- if(device->permute_channels[i]!=i)break;
+ if(device->inter_permute[i]!=i)break;
if(i==device->output_channels){
- free(device->permute_channels);
- device->permute_channels=NULL;
+ free(device->inter_permute);
+ device->inter_permute=NULL;
}
}
@@ -846,7 +1113,7 @@
if ( (device->bytewidth>1 &&
device->client_byte_format != device->driver_byte_format) ||
- device->permute_channels){
+ device->inter_permute){
result = _realloc_swap_buffer(device, DEF_SWAP_BUF_SIZE);
@@ -864,6 +1131,12 @@
/* If we made it this far, everything is OK. */
if(sformat.matrix)free(sformat.matrix);
return device;
+
+ error:
+ if(sformat.matrix)
+ free(sformat.matrix);
+ ao_close(device);
+ return NULL;
}
@@ -1016,7 +1289,7 @@
int swap = (device->bytewidth>1 &&
device->client_byte_format != device->driver_byte_format);
for(i=0;i<device->output_channels;i++){
- int ic = device->permute_channels ? device->permute_channels[i] : i;
+ int ic = device->inter_permute ? device->inter_permute[i] : i;
if(ic==-1){
_buffer_zero(device->swap_buffer,i,device->bytewidth,device->output_channels,
out_bytes);
@@ -1058,6 +1331,12 @@
free(device->swap_buffer);
if (device->output_matrix != NULL)
free(device->output_matrix);
+ if (device->input_map != NULL)
+ free(device->input_map);
+ if (device->inter_matrix != NULL)
+ free(device->inter_matrix);
+ if (device->inter_permute != NULL)
+ free(device->inter_permute);
free(device);
}
Modified: trunk/ao/src/plugins/alsa/ao_alsa.c
===================================================================
--- trunk/ao/src/plugins/alsa/ao_alsa.c 2010-03-17 15:54:34 UTC (rev 16981)
+++ trunk/ao/src/plugins/alsa/ao_alsa.c 2010-03-18 19:50:04 UTC (rev 16982)
@@ -145,6 +145,8 @@
internal->access_mask = AO_ALSA_ACCESS_MASK;
device->internal = internal;
+ device->output_matrix = strdup("L,R,BL,BR,C,LFE,SL,SR");
+ device->output_matrix_order = AO_OUTPUT_MATRIX_FIXED;
return 1;
}
@@ -242,14 +244,14 @@
/* set the number of channels */
err = snd_pcm_hw_params_set_channels(internal->pcm_handle,
- params, (unsigned int)format->channels);
+ params, (unsigned int)device->output_channels);
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;
+ internal->sample_size = format->bits * device->output_channels / 8;
/* set the sample rate */
err = snd_pcm_hw_params_set_rate_near(internal->pcm_handle,
@@ -400,6 +402,17 @@
return err;
}
+ /* this is a hack and fragile if the exact device detection code
+ flow changes! Nevertheless, this is a useful warning for users.
+ Never fail silently if we can help it! */
+ if(!strcasecmp(dev,"default")){
+ /* default device */
+ if(device->output_channels>2){
+ awarn("ALSA 'default' device plays only channels 0,1.\n");
+ device->output_channels=2;
+ }
+ }
+
/* try to set up hw params */
err = alsa_set_hwparams(device,format);
if(err<0){
@@ -445,7 +458,7 @@
/* we don't try just 'default' as it's a plug device that
will accept any number of channels but usually plays back
everything as stereo. */
- switch(format->channels){
+ switch(device->output_channels){
default:
case 8:
case 7:
@@ -488,20 +501,15 @@
if (format->bits > 8)
device->driver_byte_format = device->client_byte_format;
- if(!device->output_matrix){
- if(!strcasecmp(internal->dev,"default")){
- /* default device */
- if(format->channels>2)
- awarn("ALSA 'default' device plays only L,R channels.\n");
- device->output_matrix=strdup("L,R");
- }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");
+ if(strcasecmp(internal->dev,"default")){
+ if(strncasecmp(internal->dev,"surround",8)){
+ if(device->output_channels>2 && device->verbose>=0){
+ awarn("No way to determine hardware %d channel mapping of\n"
+ "ALSA device '%s'.\n",device->output_channels, internal->dev);
+ if(device->inter_matrix){
+ free(device->inter_matrix);
+ device->inter_matrix=NULL;
+ }
}
}
}
@@ -591,8 +599,7 @@
snd_pcm_drain(internal->pcm_handle);
snd_pcm_close(internal->pcm_handle);
internal->pcm_handle=NULL;
- } else
- awarn("ao_plugin_close called with uninitialized ao_device->internal->pcm_handle\n");
+ }
} else
awarn("ao_plugin_close called with uninitialized ao_device->internal\n");
} else
Modified: trunk/ao/src/plugins/arts/ao_arts.c
===================================================================
--- trunk/ao/src/plugins/arts/ao_arts.c 2010-03-17 15:54:34 UTC (rev 16981)
+++ trunk/ao/src/plugins/arts/ao_arts.c 2010-03-18 19:50:04 UTC (rev 16982)
@@ -133,6 +133,8 @@
return 0; /* Could not initialize device memory */
device->internal = internal;
+ device->output_matrix_order = AO_OUTPUT_MATRIX_FIXED;
+ device->output_matrix=strdup("L,R");
return 1; /* Memory alloc successful */
}
@@ -167,7 +169,7 @@
ao_arts_internal *internal = (ao_arts_internal *) device->internal;
int errorcode=0;
- if(format->channels<1 || format->channels>2){
+ if(device->output_channels<1 || device->output_channels>2){
/* the docs aren't kidding here--- feed it more than 2
channels and the server simply stops answering; the
connection freezes. */
@@ -197,7 +199,7 @@
device->driver_byte_format = AO_FMT_NATIVE;
internal->stream = arts_play_stream(format->rate,
format->bits,
- format->channels,
+ device->output_channels,
"libao stream");
if(!internal->stream){
@@ -231,9 +233,6 @@
server_open_count++;
pthread_mutex_unlock(&mutex);
- if(!device->output_matrix)
- device->output_matrix=strdup("L,R");
-
adebug("thread %p: playback stream created!\n",internal->stream);
adebug("thread %p: buffer size = %d bytes\n",internal->stream,internal->buffersize);
return 1;
Modified: trunk/ao/src/plugins/esd/ao_esd.c
===================================================================
--- trunk/ao/src/plugins/esd/ao_esd.c 2010-03-17 15:54:34 UTC (rev 16981)
+++ trunk/ao/src/plugins/esd/ao_esd.c 2010-03-18 19:50:04 UTC (rev 16982)
@@ -133,6 +133,8 @@
internal->host = NULL;
device->internal = internal;
+ device->output_matrix_order = AO_OUTPUT_MATRIX_FIXED;
+ device->output_matrix=strdup("L,R");
return 1; /* Memory alloc successful */
}
@@ -167,7 +169,7 @@
default : return 0;
}
- switch (format->channels)
+ switch (device->output_channels)
{
case 1 : esd_channels = ESD_MONO;
break;
@@ -186,10 +188,6 @@
device->driver_byte_format = AO_FMT_NATIVE;
- /* ESD restricted to stereo only */
- if(!device->output_matrix)
- device->output_matrix=strdup("L,R");
-
return 1;
}
Modified: trunk/ao/src/plugins/irix/ao_irix.c
===================================================================
--- trunk/ao/src/plugins/irix/ao_irix.c 2010-03-17 15:54:34 UTC (rev 16981)
+++ trunk/ao/src/plugins/irix/ao_irix.c 2010-03-18 19:50:04 UTC (rev 16982)
@@ -100,6 +100,7 @@
internal->channels = 2;
device->internal = internal;
+ device->output_matrix_order = AO_OUTPUT_MATRIX_FIXED;
/* Device-specific initialization was successful. */
return 1;
@@ -124,13 +125,13 @@
return 0;
}
- if (alSetChannels(internal->alconfig, format->channels) < 0) {
+ if (alSetChannels(internal->alconfig, device->output_channels) < 0) {
aerror("alSetChannels(%d) failed: %s\n",
- format->channels, alGetErrorString(oserror()));
+ device->output_channels, alGetErrorString(oserror()));
return 0;
}
- internal->channels = format->channels;
+ internal->channels = device->output_channels;
if (alSetDevice(internal->alconfig, dev) < 0) {
aerror("alSetDevice failed: %s\n",
@@ -191,15 +192,13 @@
}
device->driver_byte_format = AO_FMT_NATIVE;
-
- if(!device->output_matrix){
- /* set up out matrix such that users are warned about > stereo playback */
- if(format->channels<=2)
- device->output_matrix=strdup("L,R");
+ if(!device->inter_matrix){
+ /* set up matrix such that users are warned about > stereo playback */
+ if(device->output_channels<=2)
+ device->inter_matrix=strdup("L,R");
//else no matrix, which results in a warning
}
-
return 1;
}
Modified: trunk/ao/src/plugins/macosx/ao_macosx.c
===================================================================
--- trunk/ao/src/plugins/macosx/ao_macosx.c 2010-03-17 15:54:34 UTC (rev 16981)
+++ trunk/ao/src/plugins/macosx/ao_macosx.c 2010-03-18 19:50:04 UTC (rev 16982)
@@ -198,11 +198,11 @@
internal->device = device;
device->internal = internal;
-
+ device->output_matrix_order = AO_OUTPUT_MATRIX_COLLAPSIBLE;
+ device->output_matrix = strdup("L,R,C,LFE,BL,BR,CL,CR,BC,SL,SR");
return 1; /* Memory alloc successful */
}
-
int ao_plugin_set_option(ao_device *device, const char *key, const char *value)
{
ao_macosx_internal *internal = (ao_macosx_internal *) device->internal;
@@ -216,54 +216,10 @@
}
internal->buffer_time = buffer;
}
-
+
return 1;
}
-static char *map[]={
- "L","R","C","LFE","BL","BR","CL","CR","BC","SL","SR",NULL
-};
-
-static unsigned int _matrix_to_channelmask(char *matrix){
- unsigned int ret=0;
- char *p=matrix;
- while(1){
- char *h=p;
- int m=0;
-
- /* search for seperator */
- while(*h && *h!=',')h++;
-
- while(map[m]){
- if(h-p && !strncmp(map[m],p,h-p) &&
- strlen(map[m])==h-p)
- break;
- m++;
- }
- if(map[m])
- ret |= (1<<m);
- if(!*h)break;
- p=h+1;
- }
- return ret;
-}
-
-static char *_channelmask_to_matrix(unsigned int mask){
- int m=0;
- int count=0;
- char buffer[80]={0};
- while(map[m]){
- if(mask & (1<<m)){
- if(count)
- strcat(buffer,",");
- strcat(buffer,map[m]);
- count++;
- }
- m++;
- }
- return strdup(buffer);
-}
-
int ao_plugin_open(ao_device *device, ao_sample_format *format)
{
ao_macosx_internal *internal = (ao_macosx_internal *) device->internal;
@@ -313,7 +269,7 @@
if (format->bits > 8)
requestedDesc.mFormatFlags |= kAudioFormatFlagIsSignedInteger;
- requestedDesc.mChannelsPerFrame = format->channels;
+ requestedDesc.mChannelsPerFrame = device->output_channels;
requestedDesc.mSampleRate = format->rate;
requestedDesc.mBitsPerChannel = format->bits;
requestedDesc.mFramesPerPacket = 1;
@@ -350,8 +306,8 @@
aerror("Unable to set output sample rate\n");
return 0;
}
- if(requestedDesc.mChannelsPerFrame != format->channels){
- aerror("Could not configure %d channel output\n",format->channels);
+ if(requestedDesc.mChannelsPerFrame != device->output_channels){
+ aerror("Could not configure %d channel output\n",device->output_channels);
return 0;
}
if(requestedDesc.mBitsPerChannel != format->bits){
@@ -366,7 +322,7 @@
aerror("Could not configure integer sample output\n");
return 0;
}
- if((requestedDesc.mFormatFlags & kAudioFormatFlagsNativeEndian) !=
+ if((requestedDesc.mFormatFlags & kAudioFormatFlagsNativeEndian) !=
kAudioFormatFlagsNativeEndian){
aerror("Could not configure output endianness\n");
return 0;
@@ -391,18 +347,12 @@
/* set the channel mapping. MacOSX AUHAL is capable of mapping any
channel format currently representable in the libao matrix. */
- if(format->matrix){
+ if(device->output_mask){
AudioChannelLayout layout;
memset(&layout,0,sizeof(layout));
layout.mChannelLayoutTag = kAudioChannelLayoutTag_UseChannelBitmap;
-
- if(device->output_matrix){
- layout.mChannelBitmap = _matrix_to_channelmask(device->output_matrix);
- }else{
- layout.mChannelBitmap = _matrix_to_channelmask(format->matrix);
- device->output_matrix = _channelmask_to_matrix(layout.mChannelBitmap);
- }
+ layout.mChannelBitmap = device->output_mask;
result = AudioUnitSetProperty(internal->outputAudioUnit,
kAudioUnitProperty_AudioChannelLayout,
@@ -415,8 +365,8 @@
/* Set the audio callback */
input.inputProc = (AURenderCallback) audioCallback;
input.inputProcRefCon = internal;
-
- result = AudioUnitSetProperty( internal->outputAudioUnit,
+
+ result = AudioUnitSetProperty( internal->outputAudioUnit,
kAudioUnitProperty_SetRenderCallback,
kAudioUnitScope_Input,
0, &input, sizeof( input ));
@@ -437,7 +387,7 @@
we allocate the buffer here instead of ao_plugin_device_init() */
internal->bufferByteCount = (internal->buffer_time * format->rate / 1000) *
- (format->channels * format->bits / 8);
+ (device->output_channels * format->bits / 8);
internal->firstValidByteOffset = 0;
internal->validByteCount = 0;
@@ -451,7 +401,7 @@
/* limited to stereo for now */
//if(!device->output_matrix)
//device->output_matrix=strdup("L,R");
-
+
return 1;
}
@@ -465,7 +415,7 @@
unsigned int firstEmptyByteOffset, emptyByteCount;
while (num_bytes) {
-
+
// Get a consistent set of data about the available space in the queue,
// figure out the maximum number of bytes we can copy in this chunk,
// and claim that amount of space
Modified: trunk/ao/src/plugins/nas/ao_nas.c
===================================================================
--- trunk/ao/src/plugins/nas/ao_nas.c 2010-03-17 15:54:34 UTC (rev 16981)
+++ trunk/ao/src/plugins/nas/ao_nas.c 2010-03-18 19:50:04 UTC (rev 16982)
@@ -107,6 +107,8 @@
internal->buf_free = 0;
device->internal = internal;
+ device->output_matrix_order = AO_OUTPUT_MATRIX_FIXED;
+
return 1; /* Memory alloc successful */
}
@@ -163,7 +165,7 @@
if ((AuDeviceKind(AuServerDevice(internal->aud, i)) ==
AuComponentKindPhysicalOutput) &&
(AuDeviceNumTracks(AuServerDevice(internal->aud, i)) ==
- format->channels))
+ device->output_channels))
break;
if ((i == AuServerNumDevices(internal->aud)) ||
@@ -177,7 +179,7 @@
/* set up flow */
AuMakeElementImportClient(&elms[0], format->rate,
- nas_format, format->channels, AuTrue,
+ nas_format, device->output_channels, AuTrue,
internal->buf_size, internal->buf_size / 2,
0, 0);
AuMakeElementExportDevice(&elms[1], 0, internal->dev,
@@ -187,10 +189,10 @@
device->driver_byte_format = AO_FMT_NATIVE;
- if(!device->output_matrix){
+ if(!device->inter_matrix){
/* set up out matrix such that users are warned about > stereo playback */
- if(format->channels<=2)
- device->output_matrix=strdup("L,R");
+ if(device->output_channels<=2)
+ device->inter_matrix=strdup("L,R");
//else no matrix, which results in a warning
}
Modified: trunk/ao/src/plugins/oss/ao_oss.c
===================================================================
--- trunk/ao/src/plugins/oss/ao_oss.c 2010-03-17 15:54:34 UTC (rev 16981)
+++ trunk/ao/src/plugins/oss/ao_oss.c 2010-03-18 19:50:04 UTC (rev 16982)
@@ -169,6 +169,8 @@
internal->dev = NULL;
device->internal = internal;
+ device->output_matrix_order = AO_OUTPUT_MATRIX_FIXED;
+ device->output_matrix=strdup("L,R");
return 1; /* Memory alloc successful */
}
@@ -216,21 +218,21 @@
/* Now set all of the parameters */
- switch (format->channels)
+ switch (device->output_channels)
{
case 1: tmp = 0;
break;
case 2: tmp = 1;
break;
default:aerror("Unsupported number of channels: %d.",
- format->channels);
+ device->output_channels);
goto ERR;
}
if (ioctl(internal->fd,SNDCTL_DSP_STEREO,&tmp) < 0 ||
- tmp+1 != format->channels) {
+ tmp+1 != device->output_channels) {
aerror("cannot set channels to %d\n",
- format->channels);
+ device->output_channels);
goto ERR;
}
@@ -282,10 +284,6 @@
internal->buf_size=1024;
}
- /* limited to stereo */
- if(!device->output_matrix)
- device->output_matrix=strdup("L,R");
-
return 1; /* Open successful */
ERR:
Modified: trunk/ao/src/plugins/pulse/ao_pulse.c
===================================================================
--- trunk/ao/src/plugins/pulse/ao_pulse.c 2010-03-17 15:54:34 UTC (rev 16981)
+++ trunk/ao/src/plugins/pulse/ao_pulse.c 2010-03-18 19:50:04 UTC (rev 16982)
@@ -138,8 +138,14 @@
internal->simple = NULL;
internal->server = NULL;
internal->sink = NULL;
- device->internal = internal;
+ device->internal = internal;
+ device->output_matrix_order = AO_OUTPUT_MATRIX_PERMUTABLE;
+ device->output_matrix = strdup("L,R,C,BC,BL,BR,LFE,CL,CR,SL,SR,"
+ "A0,A1,A2,A3,A4,A5,A6,A7,A8,A9,"
+ "A10,A11,A12,A13,A14,A15,A16,A17,A18,A19,"
+ "A20,A21,A22,A23,A24,A25,A26,A27,A28,A29,"
+ "A30,A31");
return 1;
}
@@ -159,65 +165,6 @@
return 1;
}
-
-pa_channel_position_t default_map[]={
- PA_CHANNEL_POSITION_FRONT_LEFT,
- PA_CHANNEL_POSITION_FRONT_RIGHT,
- PA_CHANNEL_POSITION_REAR_LEFT,
- PA_CHANNEL_POSITION_REAR_RIGHT,
- PA_CHANNEL_POSITION_FRONT_CENTER,
- PA_CHANNEL_POSITION_LFE,
- PA_CHANNEL_POSITION_SIDE_LEFT,
- PA_CHANNEL_POSITION_SIDE_RIGHT,
- PA_CHANNEL_POSITION_AUX0,
- PA_CHANNEL_POSITION_AUX1,
- PA_CHANNEL_POSITION_AUX2,
- PA_CHANNEL_POSITION_AUX3,
- PA_CHANNEL_POSITION_AUX4,
- PA_CHANNEL_POSITION_AUX5,
- PA_CHANNEL_POSITION_AUX6,
- PA_CHANNEL_POSITION_AUX7,
- PA_CHANNEL_POSITION_AUX8,
- PA_CHANNEL_POSITION_AUX9,
- PA_CHANNEL_POSITION_AUX10,
- PA_CHANNEL_POSITION_AUX11,
- PA_CHANNEL_POSITION_AUX12,
- PA_CHANNEL_POSITION_AUX13,
- PA_CHANNEL_POSITION_AUX14,
- PA_CHANNEL_POSITION_AUX15,
- PA_CHANNEL_POSITION_AUX16,
- PA_CHANNEL_POSITION_AUX17,
- PA_CHANNEL_POSITION_AUX18,
- PA_CHANNEL_POSITION_AUX19,
- PA_CHANNEL_POSITION_AUX20,
- PA_CHANNEL_POSITION_AUX21,
- PA_CHANNEL_POSITION_AUX22,
- PA_CHANNEL_POSITION_AUX23,
- PA_CHANNEL_POSITION_AUX23};
-
-typedef struct {
- char *from;
- pa_channel_position_t to;
-} translate;
-
-translate trans[]={
- {"M",PA_CHANNEL_POSITION_MONO},
- {"L",PA_CHANNEL_POSITION_FRONT_LEFT},
- {"R",PA_CHANNEL_POSITION_FRONT_RIGHT},
- {"C",PA_CHANNEL_POSITION_FRONT_CENTER},
- {"BL",PA_CHANNEL_POSITION_REAR_LEFT},
- {"BR",PA_CHANNEL_POSITION_REAR_RIGHT},
- {"BC",PA_CHANNEL_POSITION_REAR_CENTER},
- {"SL",PA_CHANNEL_POSITION_SIDE_LEFT},
- {"SR",PA_CHANNEL_POSITION_SIDE_RIGHT},
- {"LFE",PA_CHANNEL_POSITION_LFE},
- {"U",PA_CHANNEL_POSITION_INVALID},
- {"X",PA_CHANNEL_POSITION_INVALID},
- {"CL",PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER},
- {"CR",PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER},
- {NULL,PA_CHANNEL_POSITION_INVALID}
-};
-
int ao_plugin_open(ao_device *device, ao_sample_format *format) {
char *p=NULL, t[256], t2[256];
const char *fn = NULL;
@@ -238,10 +185,10 @@
else
return 0;
- if (format->channels <= 0 || format->channels > PA_CHANNELS_MAX)
- return 0;
+ if (device->output_channels <= 0 || device->output_channels > PA_CHANNELS_MAX)
+ return 0;
- ss.channels = format->channels;
+ ss.channels = device->output_channels;
ss.rate = format->rate;
disable_sigpipe();
@@ -266,67 +213,21 @@
pa_xfree(p);
p = NULL;
- if(!device->output_matrix){
- if(format->matrix){
- /* request a matrix similar/identical to the input format; let
- Pulse do the conversion work */
- int i;
- char *p=format->matrix,*h;
- char buffer[129]={0};
- usemap=1;
- pa_channel_map_init(&map);
- map.channels=format->channels;
+ if(device->input_map){
+ int i;
+ pa_channel_map_init(&map);
+ map.channels=device->output_channels;
- for(i=0;i<format->channels;i++){
- int m=0;
- h=p;
- while(*h && *h!=',')h++;
- while(trans[m].from){
- if(h-p && !strncmp(trans[m].from,p,h-p) &&
- strlen(trans[m].from)==h-p)
- break;
- m++;
- }
- if(i)strcat(buffer,",");
- if(trans[m].from){
- map.map[i] = trans[m].to;
- strcat(buffer,trans[m].from);
- }else{
- map.map[i] = PA_CHANNEL_POSITION_INVALID;
- strcat(buffer,"X");
- }
-
- p=h;
- if(*h)p++;
+ for(i=0;i<device->output_channels;i++){
+ if(device->input_map[i]==-1){
+ map.map[i] = PA_CHANNEL_POSITION_INVALID;
+ }else{
+ map.map[i] = device->input_map[i];
}
-
- device->output_matrix = strdup(buffer);
-
- }else{
- if(format->channels <= 32){
- /* set up a channel mapping similar to ALSA */
- if(format->channels == 1 ){
- usemap=1;
- pa_channel_map_init(&map);
- map.channels=1;
- map.map[0] = PA_CHANNEL_POSITION_MONO;
- device->output_matrix=strdup("M");
- }else{
- int i;
- usemap=1;
- pa_channel_map_init(&map);
- map.channels=format->channels;
- for(i=0;i<format->channels;i++)
- map.map[i] = default_map[i];
- device->output_matrix=strdup("L,R,BL,BR,C,LFE,SL,SR,"
- "A1,A2,A3,A4,A5,A6,A7,A8,A9,A10,"
- "A11,A12,A13,A14,A15,A16,A17,A18,A19,A20,"
- "A21,A22,A23,A4");
- }
- }
}
}
+
if (!(internal->simple = pa_simple_new(internal->server, fn ? t : "libao", PA_STREAM_PLAYBACK, internal->sink, fn ? t2 : "libao playback stream", &ss, &map, NULL, NULL)))
return 0;
Modified: trunk/ao/src/plugins/sun/ao_sun.c
===================================================================
--- trunk/ao/src/plugins/sun/ao_sun.c 2010-03-17 15:54:34 UTC (rev 16981)
+++ trunk/ao/src/plugins/sun/ao_sun.c 2010-03-18 19:50:04 UTC (rev 16982)
@@ -125,6 +125,7 @@
}
device->internal = internal;
+ device->output_matrix_order = AO_OUTPUT_MATRIX_FIXED;
return 1; /* Memory alloc successful */
}
@@ -160,7 +161,7 @@
info.play.encoding = AUDIO_ENCODING_SLINEAR;
info.play.precision = format->bits;
info.play.sample_rate = format->rate;
- info.play.channels = format->channels;
+ info.play.channels = device->output_channels;
if (ioctl(internal->fd, AUDIO_SETINFO, &info) < 0) {
close(internal->fd);
@@ -169,10 +170,10 @@
device->driver_byte_format = AO_FMT_NATIVE;
- if(!device->output_matrix){
+ if(!device->inter_matrix){
/* set up out matrix such that users are warned about > stereo playback */
- if(format->channels<=2)
- device->output_matrix=strdup("L,R");
+ if(device->output_channels<=2)
+ device->inter_matrix=strdup("L,R");
//else no matrix, which results in a warning
}
More information about the commits
mailing list