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 40 AudioTypeMux:: 41 AudioTypeMux() 42 { 43 } 44 45 // Destructor 46 AudioTypeMux:: 47 ~AudioTypeMux() 48 { 49 } 50 51 // Test conversion possibilities. 52 // Return TRUE if conversion to/from the specified type is possible. 53 Boolean AudioTypeMux:: 54 CanConvert( 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 65 AudioError AudioTypeMux:: 66 Convert( 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]; 133 cleanup: 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 230 AudioError AudioTypeMux:: 231 Flush( 232 AudioBuffer*& /* buf */) 233 { 234 return (AUDIO_SUCCESS); 235 } 236