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