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::
AudioTypeMux()39 AudioTypeMux()
40 {
41 }
42
43 // Destructor
44 AudioTypeMux::
~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::
CanConvert(AudioHdr) const52 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::
Convert(AudioBuffer * & inbuf,AudioHdr outhdr)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 err = multibuf[i]->SetHeader(outhdr);
130 if (err != AUDIO_SUCCESS) {
131 delete multibuf[i];
132 cleanup: while (--i >= 0) {
133 delete multibuf[i];
134 }
135 delete multibuf;
136 return (err);
137 }
138 }
139 multibuf[i] = NULL;
140
141 for (i = 0; i < channels; i++) {
142 // Get output pointer and input channel pointer
143 out = (unsigned char *)multibuf[i]->GetAddress();
144 in = (unsigned char *)inbuf->GetAddress();
145 in += (i * unitsz);
146
147 // Copy a sample unit and bump the input pointer
148 for (j = 0; j < nsamps; j++) {
149 for (k = 0; k < unitsz; k++) {
150 *out++ = *in++;
151 }
152 in += ((channels - 1) * unitsz);
153 }
154
155 // Set the valid data length
156 multibuf[i]->SetLength(length);
157 }
158 // Release the input buffer
159 inbuf->Reference();
160 inbuf->Dereference();
161
162 // Return the array pointer (callers beware!)
163 inbuf = (AudioBuffer*) multibuf;
164
165 } else {
166 // Multiplex several mono channels into multi-channel data
167
168 // Allocate an output buffer
169 outbuf = new AudioBuffer(length,
170 "(Multiplex conversion buffer)");
171 if (outbuf == 0)
172 return (AUDIO_UNIXERROR);
173 err = outbuf->SetHeader(outhdr);
174 if (err != AUDIO_SUCCESS) {
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::
Flush(AudioBuffer * &)231 Flush(
232 AudioBuffer*& /* buf */)
233 {
234 return (AUDIO_SUCCESS);
235 }
236