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