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:: 40 AudioTypeG72X() 41 { 42 initialized = FALSE; 43 } 44 45 // Destructor 46 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:: 54 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:: 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:: 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