/* * iaxclient: a cross-platform IAX softphone library * * Copyrights: * Copyright (C) 2004 Cyril VELTER * * Contributors: * Cyril VELTER * * This program is free software, distributed under the terms of * the GNU Lesser (Library) General Public License. */ #include "codec_alaw.h" #include "iaxclient_lib.h" #if defined(_MSC_VER) #define INLINE __inline #else #define INLINE inline #endif struct state { plc_state_t plc; }; static INLINE short int alawdecode (unsigned char alaw) { int value; int segment; /* Mask value */ alaw ^= 0x55; /* Extract and scale value */ value = (alaw & 0x0f) << 4; /* Extract segment number */ segment = (alaw & 0x70) >> 4; /* Compute value */ switch (segment) { case 0: break; case 1: value += 0x100; break; default: value += 0x100; value <<= segment - 1; } /* Extract sign */ return (alaw & 0x80) ? value : -value; } static INLINE unsigned char alawencode (short int linear) { int mask = 0x55; int segment; unsigned char alaw; static int segments[8] = {0xFF, 0x1FF, 0x3FF, 0x7FF, 0xFFF, 0x1FFF, 0x3FFF, 0x7FFF}; if (linear >= 0) { /* Sign (7th) bit = 1 */ mask |= 0x80; } else { /* Sign (7th) bit = 0 */ linear = -linear; } /* Find the segment */ for (segment = 0;segment < 8;segment++) if (linear <= segments[segment]) break; /* Combine the sign, segment, and quantization bits. */ if (segment < 8) { if (segment < 2) alaw = (linear >> 4) & 0x0F; else alaw = (linear >> (segment + 3)) & 0x0F; return ((alaw | (segment << 4)) ^ mask); } else /* out of range, return maximum value. */ return (0x7F ^ mask); } static int decode ( struct iaxc_audio_codec *c, int *inlen, unsigned char *in, int *outlen, short *out ) { struct state *state = (struct state *)(c->decstate); short *orig_out = out; short sample; if(*inlen == 0) { int interp_len = 160; if(*outlen < interp_len) interp_len = *outlen; plc_fillin(&state->plc,out,interp_len); *outlen -= interp_len; return 0; } while ((*inlen > 0) && (*outlen > 0)) { sample = alawdecode((unsigned char)*(in++)); *(out++) = sample; (*inlen)--; (*outlen)--; } plc_rx(&state->plc, orig_out, (int)(out - orig_out)); return 0; } static int encode ( struct iaxc_audio_codec *c, int *inlen, short *in, int *outlen, unsigned char *out ) { while ((*inlen > 0) && (*outlen > 0)) { *(out++) = alawencode(*(in++)); (*inlen)--; (*outlen)--; } return 0; } static void destroy ( struct iaxc_audio_codec *c) { free(c); } struct iaxc_audio_codec *codec_audio_alaw_new() { struct iaxc_audio_codec *c = (struct iaxc_audio_codec *)calloc(1, sizeof(struct iaxc_audio_codec)); if(!c) return c; strcpy(c->name,"alaw"); c->format = IAXC_FORMAT_ALAW; c->encode = encode; c->decode = decode; c->destroy = destroy; /* really, we can use less, but don't want to */ c->minimum_frame_size = 160; /* decoder state, used for interpolation */ c->decstate = calloc(sizeof(struct state),1); plc_init(&((struct state *)c->decstate)->plc); return c; }