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 			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::
Flush(AudioBuffer * &)229 Flush(
230 	AudioBuffer*&	/* buf */)
231 {
232 	return (AUDIO_SUCCESS);
233 }
234