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