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