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 #include <stdlib.h> 28 #include <memory.h> 29 #include <math.h> 30 31 #include <AudioTypeMux.h> 32 33 // This is a conversion class for channel multiplex/demultiplex 34 35 // class AudioTypeMux methods 36 37 // Constructor 38 AudioTypeMux:: 39 AudioTypeMux() 40 { 41 } 42 43 // Destructor 44 AudioTypeMux:: 45 ~AudioTypeMux() 46 { 47 } 48 49 // Test conversion possibilities. 50 // Return TRUE if conversion to/from the specified type is possible. 51 Boolean AudioTypeMux:: 52 CanConvert( 53 AudioHdr /* h */) const // target header 54 { 55 // XXX - The test is whether we're converting 1->many or many->1 56 // This routine needs a to/from argument. 57 // XXX - What if the format doesn't have fixed-size sample units? 58 return (TRUE); 59 } 60 61 // Multiplex or demultiplex. 62 // The buffer pointer should be a NULL-terminated array of buffers if 1-channel 63 AudioError AudioTypeMux:: 64 Convert( 65 AudioBuffer*& inbuf, // data buffer to process 66 AudioHdr outhdr) // target header 67 { 68 AudioBuffer* outbuf; 69 AudioBuffer** multibuf; 70 AudioHdr inhdr; 71 Double length; 72 unsigned int channels; 73 size_t nsamps; 74 size_t nbytes; 75 size_t unitsz; 76 unsigned char **inptrs; 77 unsigned char *in; 78 unsigned char *out; 79 int i; 80 int j; 81 int k; 82 AudioError err; 83 84 channels = outhdr.channels; 85 if (channels == 1) { 86 inhdr = inbuf->GetHeader(); // Demux multi-channel data 87 length = inbuf->GetLength(); 88 } else { 89 multibuf = (AudioBuffer**) inbuf; // Mux multiple buffers 90 inhdr = multibuf[0]->GetHeader(); 91 length = multibuf[0]->GetLength(); 92 } 93 94 // Make sure we're not being asked to do the impossible or trivial 95 if ((err = inhdr.Validate())) 96 return (err); 97 if ((inhdr.sample_rate != outhdr.sample_rate) || 98 (inhdr.encoding != outhdr.encoding) || 99 (inhdr.samples_per_unit != outhdr.samples_per_unit) || 100 (inhdr.bytes_per_unit != outhdr.bytes_per_unit)) 101 return (AUDIO_ERR_HDRINVAL); 102 if (inhdr.channels == outhdr.channels) 103 return (AUDIO_SUCCESS); 104 if ((inhdr.channels != 1) && (outhdr.channels != 1)) 105 return (AUDIO_ERR_HDRINVAL); 106 if (Undefined(length)) 107 return (AUDIO_ERR_BADARG); 108 109 // Get the number of sample frames and the size of each 110 nsamps = (size_t)inhdr.Time_to_Samples(length); 111 nbytes = (size_t)inhdr.FrameLength(); 112 unitsz = (size_t)inhdr.bytes_per_unit; 113 114 // Figure out if we're multiplexing or demultiplexing 115 if (channels == 1) { 116 // Demultiplex multi-channel data into several mono channels 117 118 // Allocate buffer pointer array and each buffer 119 channels = inhdr.channels; 120 multibuf = (AudioBuffer**) 121 calloc((channels + 1), sizeof (AudioBuffer*)); 122 for (i = 0; i < channels; i++) { 123 multibuf[i] = new AudioBuffer(length, 124 "(Demultiplex conversion buffer)"); 125 if (multibuf[i] == 0) { 126 err = AUDIO_UNIXERROR; 127 goto cleanup; 128 } 129 if (err = multibuf[i]->SetHeader(outhdr)) { 130 delete multibuf[i]; 131 cleanup: while (--i >= 0) { 132 delete multibuf[i]; 133 } 134 delete multibuf; 135 return (err); 136 } 137 } 138 multibuf[i] = NULL; 139 140 for (i = 0; i < channels; i++) { 141 // Get output pointer and input channel pointer 142 out = (unsigned char *)multibuf[i]->GetAddress(); 143 in = (unsigned char *)inbuf->GetAddress(); 144 in += (i * unitsz); 145 146 // Copy a sample unit and bump the input pointer 147 for (j = 0; j < nsamps; j++) { 148 for (k = 0; k < unitsz; k++) { 149 *out++ = *in++; 150 } 151 in += ((channels - 1) * unitsz); 152 } 153 154 // Set the valid data length 155 multibuf[i]->SetLength(length); 156 } 157 // Release the input buffer 158 inbuf->Reference(); 159 inbuf->Dereference(); 160 161 // Return the array pointer (callers beware!) 162 inbuf = (AudioBuffer*) multibuf; 163 164 } else { 165 // Multiplex several mono channels into multi-channel data 166 167 // Allocate an output buffer 168 outbuf = new AudioBuffer(length, 169 "(Multiplex conversion buffer)"); 170 if (outbuf == 0) 171 return (AUDIO_UNIXERROR); 172 if (err = outbuf->SetHeader(outhdr)) { 173 delete outbuf; 174 return (err); 175 } 176 177 // Verify the input pointer is an array of buffer pointers 178 multibuf = (AudioBuffer**) inbuf; 179 for (channels = 0; ; channels++) { 180 // Look for NULL termination 181 if (multibuf[channels] == NULL) 182 break; 183 if (!multibuf[channels]->isBuffer()) 184 return (AUDIO_ERR_BADARG); 185 } 186 if (channels != outhdr.channels) 187 return (AUDIO_ERR_BADARG); 188 189 // Allocate a bunch of input pointers 190 inptrs = (unsigned char **) 191 calloc(channels, sizeof (unsigned char *)); 192 for (i = 0; i < channels; i++) { 193 inptrs[i] = (unsigned char *) multibuf[i]->GetAddress(); 194 } 195 196 // Get output pointer 197 out = (unsigned char *)outbuf->GetAddress(); 198 199 for (i = 0; i < nsamps; i++) { 200 // Copy a sample frame from each input buffer 201 for (j = 0; j < channels; j++) { 202 in = inptrs[j]; 203 for (k = 0; k < nbytes; k++) { 204 *out++ = *in++; 205 } 206 inptrs[j] = in; 207 } 208 } 209 // Set the valid data length 210 outbuf->SetLength(length); 211 212 // Release the input buffers and pointer arrays 213 for (i = 0; i < channels; i++) { 214 multibuf[i]->Reference(); 215 multibuf[i]->Dereference(); 216 multibuf[i] = NULL; 217 } 218 delete multibuf; 219 delete inptrs; 220 221 // Set the valid data length and return the new pointer 222 outbuf->SetLength(length); 223 inbuf = outbuf; 224 } 225 return (AUDIO_SUCCESS); 226 } 227 228 AudioError AudioTypeMux:: 229 Flush( 230 AudioBuffer*& /* buf */) 231 { 232 return (AUDIO_SUCCESS); 233 } 234