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 <AudioTypeG72X.h>
32 
33 // class AudioTypeG72X methods
34 // G.721 & G.723 compress/decompress
35 
36 // Constructor
37 AudioTypeG72X::
AudioTypeG72X()38 AudioTypeG72X()
39 {
40 	initialized = FALSE;
41 }
42 
43 // Destructor
44 AudioTypeG72X::
~AudioTypeG72X()45 ~AudioTypeG72X()
46 {
47 }
48 
49 // Test conversion possibilities.
50 // Return TRUE if conversion to/from the specified type is possible.
51 Boolean AudioTypeG72X::
CanConvert(AudioHdr h) const52 CanConvert(
53 	AudioHdr	h) const		// target header
54 {
55 	// g72x conversion code handles mono 16-bit pcm, ulaw, alaw
56 	if (h.channels != 1)
57 		return (FALSE);
58 
59 	switch (h.encoding) {
60 	case LINEAR:
61 		if ((h.samples_per_unit != 1) ||
62 		    (h.bytes_per_unit != 2))
63 			return (FALSE);
64 		break;
65 	case ALAW:
66 	case ULAW:
67 		if ((h.samples_per_unit != 1) ||
68 		    (h.bytes_per_unit != 1))
69 			return (FALSE);
70 		break;
71 	case G721:
72 		if ((h.samples_per_unit != 2) ||
73 		    (h.bytes_per_unit != 1))
74 			return (FALSE);
75 		break;
76 	case G723:
77 		if (h.samples_per_unit != 8)
78 			return (FALSE);
79 
80 		// XXX - 5-bit G.722 not supported yet
81 		if (h.bytes_per_unit != 3)
82 			return (FALSE);
83 		break;
84 	case FLOAT:
85 	default:
86 		return (FALSE);
87 	}
88 	return (TRUE);
89 }
90 
91 // Convert buffer to the specified type
92 // May replace the buffer with a new one, if necessary
93 AudioError AudioTypeG72X::
Convert(AudioBuffer * & inbuf,AudioHdr outhdr)94 Convert(
95 	AudioBuffer*&	inbuf,			// data buffer to process
96 	AudioHdr	outhdr)			// target header
97 {
98 	AudioBuffer*	outbuf;
99 	AudioHdr	inhdr;
100 	Audio_hdr	chdr;	// C struct for g72x convert code
101 	Double		length;
102 	Double		pad;
103 	size_t		nbytes;
104 	int		cnt;
105 	unsigned char	*inptr;
106 	unsigned char	*outptr;
107 	AudioError	err;
108 
109 	inhdr = inbuf->GetHeader();
110 	length = inbuf->GetLength();
111 
112 	if (Undefined(length)) {
113 		return (AUDIO_ERR_BADARG);
114 	}
115 
116 	// Make sure we're not being asked to do the impossible
117 	if ((err = inhdr.Validate()) || (err = outhdr.Validate())) {
118 		return (err);
119 	}
120 
121 	if (!CanConvert(inhdr) || !CanConvert(outhdr) ||
122 	    (inhdr.sample_rate != outhdr.sample_rate) ||
123 	    (inhdr.channels != outhdr.channels))
124 		return (AUDIO_ERR_HDRINVAL);
125 
126 	// if conversion is a no-op, just return success
127 	if ((inhdr.encoding == outhdr.encoding) &&
128 	    (inhdr.bytes_per_unit == outhdr.bytes_per_unit)) {
129 		return (AUDIO_SUCCESS);
130 	}
131 
132 	// Add some padding to the output buffer
133 	pad = outhdr.Samples_to_Time(
134 	    4 * outhdr.bytes_per_unit * outhdr.channels);
135 
136 	// Allocate a new buffer
137 	outbuf = new AudioBuffer(length + pad, "(G72x conversion buffer)");
138 	if (outbuf == 0)
139 		return (AUDIO_UNIXERROR);
140 	if (err = outbuf->SetHeader(outhdr)) {
141 		delete outbuf;
142 		return (err);
143 	}
144 
145 	// Convert from the input type to the output type
146 	inptr = (unsigned char *)inbuf->GetAddress();
147 	outptr = (unsigned char *)outbuf->GetAddress();
148 	nbytes = (size_t)inhdr.Time_to_Bytes(length);
149 	if (nbytes == 0)
150 		goto cleanup;
151 
152 	switch (inhdr.encoding) {
153 	case ALAW:
154 	case ULAW:
155 	case LINEAR:
156 		switch (outhdr.encoding) {
157 		case G721:
158 			chdr = (Audio_hdr)inhdr;
159 			if (!initialized) {
160 				g721_init_state(&g72x_state);
161 				initialized = TRUE;
162 			}
163 			err = g721_encode((void*)inptr, nbytes, &chdr,
164 			    outptr, &cnt, &g72x_state);
165 			length = outhdr.Bytes_to_Time(cnt);
166 			break;
167 		case G723:
168 			chdr = (Audio_hdr)inhdr;
169 			if (!initialized) {
170 				g723_init_state(&g72x_state);
171 				initialized = TRUE;
172 			}
173 			err = g723_encode((void*)inptr, nbytes, &chdr,
174 			    outptr, &cnt, &g72x_state);
175 			length = outhdr.Bytes_to_Time(cnt);
176 			break;
177 		default:
178 			err = AUDIO_ERR_HDRINVAL; break;
179 		}
180 		break;
181 	case G721:
182 		switch (outhdr.encoding) {
183 		case ALAW:
184 		case ULAW:
185 		case LINEAR:
186 			chdr = (Audio_hdr)outhdr;
187 			if (!initialized) {
188 				g721_init_state(&g72x_state);
189 				initialized = TRUE;
190 			}
191 			err = g721_decode(inptr, nbytes, &chdr,
192 			    (void*)outptr, &cnt, &g72x_state);
193 			length = outhdr.Samples_to_Time(cnt);
194 			break;
195 		default:
196 			err = AUDIO_ERR_HDRINVAL; break;
197 		}
198 		break;
199 	case G723:
200 		switch (outhdr.encoding) {
201 		case ALAW:
202 		case ULAW:
203 		case LINEAR:
204 			chdr = (Audio_hdr)outhdr;
205 			if (!initialized) {
206 				g723_init_state(&g72x_state);
207 				initialized = TRUE;
208 			}
209 			err = g723_decode(inptr, nbytes, &chdr,
210 			    (void*)outptr, &cnt, &g72x_state);
211 			length = outhdr.Samples_to_Time(cnt);
212 			break;
213 		default:
214 			err = AUDIO_ERR_HDRINVAL; break;
215 		}
216 		break;
217 	default:
218 		err = AUDIO_ERR_HDRINVAL; break;
219 	}
220 	if (err) {
221 		if (outbuf != inbuf)
222 			delete outbuf;
223 		return (err);
224 	}
225 cleanup:
226 	// This will delete the buffer
227 	inbuf->Reference();
228 	inbuf->Dereference();
229 
230 	// Set the valid data length
231 	outbuf->SetLength(length);
232 	inbuf = outbuf;
233 
234 	return (AUDIO_SUCCESS);
235 }
236 
237 // Flush out any leftover state, appending to supplied buffer
238 AudioError AudioTypeG72X::
Flush(AudioBuffer * & outbuf)239 Flush(
240 	AudioBuffer*&	outbuf)
241 {
242 	AudioHdr	h;
243 	Double		pos;
244 	size_t		cnt;
245 	AudioError	err;
246 	unsigned char	tmpbuf[32];
247 
248 	if (!initialized)
249 		return (AUDIO_SUCCESS);
250 	initialized = FALSE;
251 	if (outbuf == NULL)
252 		return (AUDIO_SUCCESS);
253 
254 	h = outbuf->GetHeader();
255 
256 	switch (h.encoding) {
257 	case G721:
258 	case G723:
259 		switch (h.encoding) {
260 		case G721:
261 			err = g721_encode(NULL, 0, NULL,
262 			    tmpbuf, (int *)&cnt, &g72x_state);
263 			break;
264 		case G723:
265 			err = g723_encode(NULL, 0, NULL,
266 			    tmpbuf, (int *)&cnt, &g72x_state);
267 			break;
268 		}
269 		// Copy to the supplied buffer
270 		if (cnt > 0) {
271 			pos = outbuf->GetLength();
272 			err = outbuf->AppendData(tmpbuf, cnt, pos);
273 			if (err)
274 				return (err);
275 		}
276 		break;
277 	default:
278 		break;
279 	}
280 	return (AUDIO_SUCCESS);
281 }
282