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::
AudioTypeMux()41 AudioTypeMux()
42 {
43 }
44
45 // Destructor
46 AudioTypeMux::
~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::
CanConvert(AudioHdr) const54 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::
Convert(AudioBuffer * & inbuf,AudioHdr outhdr)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::
Flush(AudioBuffer * &)231 Flush(
232 AudioBuffer*& /* buf */)
233 {
234 return (AUDIO_SUCCESS);
235 }
236