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 39AudioTypeG72X:: 40AudioTypeG72X() 41{ 42 initialized = FALSE; 43} 44 45// Destructor 46AudioTypeG72X:: 47~AudioTypeG72X() 48{ 49} 50 51// Test conversion possibilities. 52// Return TRUE if conversion to/from the specified type is possible. 53Boolean AudioTypeG72X:: 54CanConvert( 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 95AudioError AudioTypeG72X:: 96Convert( 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 } 227cleanup: 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 240AudioError AudioTypeG72X:: 241Flush( 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