1/* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22/* 23 * Copyright (c) 1992-2001 by Sun Microsystems, Inc. 24 * All rights reserved. 25 */ 26 27#pragma ident "%Z%%M% %I% %E% SMI" 28 29#include <stdlib.h> 30#include <memory.h> 31#include <math.h> 32 33#include <AudioTypeMux.h> 34 35// This is a conversion class for channel multiplex/demultiplex 36 37// class AudioTypeMux methods 38 39// Constructor 40AudioTypeMux:: 41AudioTypeMux() 42{ 43} 44 45// Destructor 46AudioTypeMux:: 47~AudioTypeMux() 48{ 49} 50 51// Test conversion possibilities. 52// Return TRUE if conversion to/from the specified type is possible. 53Boolean AudioTypeMux:: 54CanConvert( 55 AudioHdr /* h */) const // target header 56{ 57 // XXX - The test is whether we're converting 1->many or many->1 58 // This routine needs a to/from argument. 59 // XXX - What if the format doesn't have fixed-size sample units? 60 return (TRUE); 61} 62 63// Multiplex or demultiplex. 64// The buffer pointer should be a NULL-terminated array of buffers if 1-channel 65AudioError AudioTypeMux:: 66Convert( 67 AudioBuffer*& inbuf, // data buffer to process 68 AudioHdr outhdr) // target header 69{ 70 AudioBuffer* outbuf; 71 AudioBuffer** multibuf; 72 AudioHdr inhdr; 73 Double length; 74 unsigned int channels; 75 size_t nsamps; 76 size_t nbytes; 77 size_t unitsz; 78 unsigned char **inptrs; 79 unsigned char *in; 80 unsigned char *out; 81 int i; 82 int j; 83 int k; 84 AudioError err; 85 86 channels = outhdr.channels; 87 if (channels == 1) { 88 inhdr = inbuf->GetHeader(); // Demux multi-channel data 89 length = inbuf->GetLength(); 90 } else { 91 multibuf = (AudioBuffer**) inbuf; // Mux multiple buffers 92 inhdr = multibuf[0]->GetHeader(); 93 length = multibuf[0]->GetLength(); 94 } 95 96 // Make sure we're not being asked to do the impossible or trivial 97 if ((err = inhdr.Validate())) 98 return (err); 99 if ((inhdr.sample_rate != outhdr.sample_rate) || 100 (inhdr.encoding != outhdr.encoding) || 101 (inhdr.samples_per_unit != outhdr.samples_per_unit) || 102 (inhdr.bytes_per_unit != outhdr.bytes_per_unit)) 103 return (AUDIO_ERR_HDRINVAL); 104 if (inhdr.channels == outhdr.channels) 105 return (AUDIO_SUCCESS); 106 if ((inhdr.channels != 1) && (outhdr.channels != 1)) 107 return (AUDIO_ERR_HDRINVAL); 108 if (Undefined(length)) 109 return (AUDIO_ERR_BADARG); 110 111 // Get the number of sample frames and the size of each 112 nsamps = (size_t)inhdr.Time_to_Samples(length); 113 nbytes = (size_t)inhdr.FrameLength(); 114 unitsz = (size_t)inhdr.bytes_per_unit; 115 116 // Figure out if we're multiplexing or demultiplexing 117 if (channels == 1) { 118 // Demultiplex multi-channel data into several mono channels 119 120 // Allocate buffer pointer array and each buffer 121 channels = inhdr.channels; 122 multibuf = (AudioBuffer**) 123 calloc((channels + 1), sizeof (AudioBuffer*)); 124 for (i = 0; i < channels; i++) { 125 multibuf[i] = new AudioBuffer(length, 126 "(Demultiplex conversion buffer)"); 127 if (multibuf[i] == 0) { 128 err = AUDIO_UNIXERROR; 129 goto cleanup; 130 } 131 if (err = multibuf[i]->SetHeader(outhdr)) { 132 delete multibuf[i]; 133cleanup: while (--i >= 0) { 134 delete multibuf[i]; 135 } 136 delete multibuf; 137 return (err); 138 } 139 } 140 multibuf[i] = NULL; 141 142 for (i = 0; i < channels; i++) { 143 // Get output pointer and input channel pointer 144 out = (unsigned char *)multibuf[i]->GetAddress(); 145 in = (unsigned char *)inbuf->GetAddress(); 146 in += (i * unitsz); 147 148 // Copy a sample unit and bump the input pointer 149 for (j = 0; j < nsamps; j++) { 150 for (k = 0; k < unitsz; k++) { 151 *out++ = *in++; 152 } 153 in += ((channels - 1) * unitsz); 154 } 155 156 // Set the valid data length 157 multibuf[i]->SetLength(length); 158 } 159 // Release the input buffer 160 inbuf->Reference(); 161 inbuf->Dereference(); 162 163 // Return the array pointer (callers beware!) 164 inbuf = (AudioBuffer*) multibuf; 165 166 } else { 167 // Multiplex several mono channels into multi-channel data 168 169 // Allocate an output buffer 170 outbuf = new AudioBuffer(length, 171 "(Multiplex conversion buffer)"); 172 if (outbuf == 0) 173 return (AUDIO_UNIXERROR); 174 if (err = outbuf->SetHeader(outhdr)) { 175 delete outbuf; 176 return (err); 177 } 178 179 // Verify the input pointer is an array of buffer pointers 180 multibuf = (AudioBuffer**) inbuf; 181 for (channels = 0; ; channels++) { 182 // Look for NULL termination 183 if (multibuf[channels] == NULL) 184 break; 185 if (!multibuf[channels]->isBuffer()) 186 return (AUDIO_ERR_BADARG); 187 } 188 if (channels != outhdr.channels) 189 return (AUDIO_ERR_BADARG); 190 191 // Allocate a bunch of input pointers 192 inptrs = (unsigned char **) 193 calloc(channels, sizeof (unsigned char *)); 194 for (i = 0; i < channels; i++) { 195 inptrs[i] = (unsigned char *) multibuf[i]->GetAddress(); 196 } 197 198 // Get output pointer 199 out = (unsigned char *)outbuf->GetAddress(); 200 201 for (i = 0; i < nsamps; i++) { 202 // Copy a sample frame from each input buffer 203 for (j = 0; j < channels; j++) { 204 in = inptrs[j]; 205 for (k = 0; k < nbytes; k++) { 206 *out++ = *in++; 207 } 208 inptrs[j] = in; 209 } 210 } 211 // Set the valid data length 212 outbuf->SetLength(length); 213 214 // Release the input buffers and pointer arrays 215 for (i = 0; i < channels; i++) { 216 multibuf[i]->Reference(); 217 multibuf[i]->Dereference(); 218 multibuf[i] = NULL; 219 } 220 delete multibuf; 221 delete inptrs; 222 223 // Set the valid data length and return the new pointer 224 outbuf->SetLength(length); 225 inbuf = outbuf; 226 } 227 return (AUDIO_SUCCESS); 228} 229 230AudioError AudioTypeMux:: 231Flush( 232 AudioBuffer*& /* buf */) 233{ 234 return (AUDIO_SUCCESS); 235} 236