diff --git a/alaw.c b/alaw.c new file mode 100755 index 0000000000..d0495e5f6c --- /dev/null +++ b/alaw.c @@ -0,0 +1,85 @@ +/* + * Asterisk -- A telephony toolkit for Linux. + * + * u-Law to Signed linear conversion + * + * Copyright (C) 1999, Mark Spencer + * + * Mark Spencer + * + * This program is free software, distributed under the terms of + * the GNU General Public License + */ + +#include + +#define AMI_MASK 0x55 + +static inline unsigned char linear2alaw (short int linear) +{ + int mask; + int seg; + int pcm_val; + static int seg_end[8] = + { + 0xFF, 0x1FF, 0x3FF, 0x7FF, 0xFFF, 0x1FFF, 0x3FFF, 0x7FFF + }; + + pcm_val = linear; + if (pcm_val >= 0) + { + /* Sign (7th) bit = 1 */ + mask = AMI_MASK | 0x80; + } + else + { + /* Sign bit = 0 */ + mask = AMI_MASK; + pcm_val = -pcm_val; + } + + /* Convert the scaled magnitude to segment number. */ + for (seg = 0; seg < 8; seg++) + { + if (pcm_val <= seg_end[seg]) + break; + } + /* Combine the sign, segment, and quantization bits. */ + return ((seg << 4) | ((pcm_val >> ((seg) ? (seg + 3) : 4)) & 0x0F)) ^ mask; +} +/*- End of function --------------------------------------------------------*/ + +static inline short int alaw2linear (unsigned char alaw) +{ + int i; + int seg; + + alaw ^= AMI_MASK; + i = ((alaw & 0x0F) << 4); + seg = (((int) alaw & 0x70) >> 4); + if (seg) + i = (i + 0x100) << (seg - 1); + return (short int) ((alaw & 0x80) ? i : -i); +} + +unsigned char __ast_lin2a[8192]; +short __ast_alaw[256]; + +void ast_alaw_init(void) +{ + int i; + /* + * Set up mu-law conversion table + */ + for(i = 0;i < 256;i++) + { + __ast_alaw[i] = alaw2linear(i); + } + /* set up the reverse (mu-law) conversion table */ + for(i = -32768; i < 32768; i++) + { + __ast_lin2a[((unsigned short)i) >> 3] = linear2alaw(i); + } + +} + diff --git a/codecs/Makefile b/codecs/Makefile index da84127e5e..027225eb86 100755 --- a/codecs/Makefile +++ b/codecs/Makefile @@ -28,7 +28,8 @@ LIBGSM=gsm/lib/libgsm.a LIBMP3=mp3/libmp3.a LIBLPC10=lpc10/liblpc10.a -CODECS+=$(MODG723) codec_gsm.so codec_mp3_d.so codec_lpc10.so codec_adpcm.so codec_ulaw.so +CODECS+=$(MODG723) codec_gsm.so codec_mp3_d.so codec_lpc10.so \ + codec_adpcm.so codec_ulaw.so codec_alaw.so codec_a_mu.so all: $(CODECS) diff --git a/codecs/codec_alaw.c b/codecs/codec_alaw.c new file mode 100755 index 0000000000..9089fccbef --- /dev/null +++ b/codecs/codec_alaw.c @@ -0,0 +1,378 @@ +/* codec_alaw.c - translate between signed linear and alaw + * + * Asterisk -- A telephony toolkit for Linux. + * + * Copyright (c) 2001 Linux Support Services, Inc. All rights reserved. + * + * Mark Spencer +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define BUFFER_SIZE 8096 /* size for the translation buffers */ + +static pthread_mutex_t localuser_lock = PTHREAD_MUTEX_INITIALIZER; +static int localusecnt = 0; + +static char *tdesc = "A-law Coder/Decoder"; + +/* Sample frame data (Mu data is okay) */ + +#include "slin_ulaw_ex.h" +#include "ulaw_slin_ex.h" + +/* + * Private workspace for translating signed linear signals to alaw. + */ + +struct alaw_encoder_pvt +{ + struct ast_frame f; + char offset[AST_FRIENDLY_OFFSET]; /* Space to build offset */ + unsigned char outbuf[BUFFER_SIZE]; /* Encoded alaw, two nibbles to a word */ + int tail; +}; + +/* + * Private workspace for translating alaw signals to signed linear. + */ + +struct alaw_decoder_pvt +{ + struct ast_frame f; + char offset[AST_FRIENDLY_OFFSET]; /* Space to build offset */ + short outbuf[BUFFER_SIZE]; /* Decoded signed linear values */ + int tail; +}; + +/* + * alawToLin_New + * Create a new instance of alaw_decoder_pvt. + * + * Results: + * Returns a pointer to the new instance. + * + * Side effects: + * None. + */ + +static struct ast_translator_pvt * +alawtolin_new () +{ + struct alaw_decoder_pvt *tmp; + tmp = malloc (sizeof (struct alaw_decoder_pvt)); + if (tmp) + { + memset(tmp, 0, sizeof(*tmp)); + tmp->tail = 0; + localusecnt++; + ast_update_use_count (); + } + return (struct ast_translator_pvt *) tmp; +} + +/* + * LinToalaw_New + * Create a new instance of alaw_encoder_pvt. + * + * Results: + * Returns a pointer to the new instance. + * + * Side effects: + * None. + */ + +static struct ast_translator_pvt * +lintoalaw_new () +{ + struct alaw_encoder_pvt *tmp; + tmp = malloc (sizeof (struct alaw_encoder_pvt)); + if (tmp) + { + memset(tmp, 0, sizeof(*tmp)); + localusecnt++; + ast_update_use_count (); + tmp->tail = 0; + } + return (struct ast_translator_pvt *) tmp; +} + +/* + * alawToLin_FrameIn + * Fill an input buffer with packed 4-bit alaw values if there is room + * left. + * + * Results: + * Foo + * + * Side effects: + * tmp->tail is the number of packed values in the buffer. + */ + +static int +alawtolin_framein (struct ast_translator_pvt *pvt, struct ast_frame *f) +{ + struct alaw_decoder_pvt *tmp = (struct alaw_decoder_pvt *) pvt; + int x; + unsigned char *b; + + if ((tmp->tail + f->datalen) * 2 > sizeof(tmp->outbuf)) { + ast_log(LOG_WARNING, "Out of buffer space\n"); + return -1; + } + + /* Reset ssindex and signal to frame's specified values */ + b = f->data; + for (x=0;xdatalen;x++) + tmp->outbuf[tmp->tail + x] = AST_ALAW(b[x]); + + tmp->tail += f->datalen; + return 0; +} + +/* + * alawToLin_FrameOut + * Convert 4-bit alaw encoded signals to 16-bit signed linear. + * + * Results: + * Converted signals are placed in tmp->f.data, tmp->f.datalen + * and tmp->f.timelen are calculated. + * + * Side effects: + * None. + */ + +static struct ast_frame * +alawtolin_frameout (struct ast_translator_pvt *pvt) +{ + struct alaw_decoder_pvt *tmp = (struct alaw_decoder_pvt *) pvt; + + if (!tmp->tail) + return NULL; + + tmp->f.frametype = AST_FRAME_VOICE; + tmp->f.subclass = AST_FORMAT_SLINEAR; + tmp->f.datalen = tmp->tail *2; + tmp->f.timelen = tmp->tail / 8; + tmp->f.mallocd = 0; + tmp->f.offset = AST_FRIENDLY_OFFSET; + tmp->f.src = __PRETTY_FUNCTION__; + tmp->f.data = tmp->outbuf; + tmp->tail = 0; + return &tmp->f; +} + +/* + * LinToalaw_FrameIn + * Fill an input buffer with 16-bit signed linear PCM values. + * + * Results: + * None. + * + * Side effects: + * tmp->tail is number of signal values in the input buffer. + */ + +static int +lintoalaw_framein (struct ast_translator_pvt *pvt, struct ast_frame *f) +{ + struct alaw_encoder_pvt *tmp = (struct alaw_encoder_pvt *) pvt; + int x; + short *s; + if (tmp->tail + f->datalen/2 >= sizeof(tmp->outbuf)) + { + ast_log (LOG_WARNING, "Out of buffer space\n"); + return -1; + } + s = f->data; + for (x=0;xdatalen/2;x++) + tmp->outbuf[x+tmp->tail] = AST_LIN2A(s[x]); + tmp->tail += f->datalen/2; + return 0; +} + +/* + * LinToalaw_FrameOut + * Convert a buffer of raw 16-bit signed linear PCM to a buffer + * of 4-bit alaw packed two to a byte (Big Endian). + * + * Results: + * Foo + * + * Side effects: + * Leftover inbuf data gets packed, tail gets updated. + */ + +static struct ast_frame * +lintoalaw_frameout (struct ast_translator_pvt *pvt) +{ + struct alaw_encoder_pvt *tmp = (struct alaw_encoder_pvt *) pvt; + + if (tmp->tail) { + tmp->f.frametype = AST_FRAME_VOICE; + tmp->f.subclass = AST_FORMAT_ALAW; + tmp->f.timelen = tmp->tail / 8; + tmp->f.mallocd = 0; + tmp->f.offset = AST_FRIENDLY_OFFSET; + tmp->f.src = __PRETTY_FUNCTION__; + tmp->f.data = tmp->outbuf; + tmp->f.datalen = tmp->tail; + tmp->tail = 0; + return &tmp->f; + } else return NULL; +} + + +/* + * alawToLin_Sample + */ + +static struct ast_frame * +alawtolin_sample () +{ + static struct ast_frame f; + f.frametype = AST_FRAME_VOICE; + f.subclass = AST_FORMAT_ALAW; + f.datalen = sizeof (ulaw_slin_ex); + f.timelen = sizeof(ulaw_slin_ex) / 8; + f.mallocd = 0; + f.offset = 0; + f.src = __PRETTY_FUNCTION__; + f.data = ulaw_slin_ex; + return &f; +} + +/* + * LinToalaw_Sample + */ + +static struct ast_frame * +lintoalaw_sample () +{ + static struct ast_frame f; + f.frametype = AST_FRAME_VOICE; + f.subclass = AST_FORMAT_SLINEAR; + f.datalen = sizeof (slin_ulaw_ex); + /* Assume 8000 Hz */ + f.timelen = sizeof (slin_ulaw_ex) / 16; + f.mallocd = 0; + f.offset = 0; + f.src = __PRETTY_FUNCTION__; + f.data = slin_ulaw_ex; + return &f; +} + +/* + * alaw_Destroy + * Destroys a private workspace. + * + * Results: + * It's gone! + * + * Side effects: + * None. + */ + +static void +alaw_destroy (struct ast_translator_pvt *pvt) +{ + free (pvt); + localusecnt--; + ast_update_use_count (); +} + +/* + * The complete translator for alawToLin. + */ + +static struct ast_translator alawtolin = { + "alawtolin", + AST_FORMAT_ALAW, + AST_FORMAT_SLINEAR, + alawtolin_new, + alawtolin_framein, + alawtolin_frameout, + alaw_destroy, + /* NULL */ + alawtolin_sample +}; + +/* + * The complete translator for LinToalaw. + */ + +static struct ast_translator lintoalaw = { + "lintoalaw", + AST_FORMAT_SLINEAR, + AST_FORMAT_ALAW, + lintoalaw_new, + lintoalaw_framein, + lintoalaw_frameout, + alaw_destroy, + /* NULL */ + lintoalaw_sample +}; + +int +unload_module (void) +{ + int res; + ast_pthread_mutex_lock (&localuser_lock); + res = ast_unregister_translator (&lintoalaw); + if (!res) + res = ast_unregister_translator (&alawtolin); + if (localusecnt) + res = -1; + ast_pthread_mutex_unlock (&localuser_lock); + return res; +} + +int +load_module (void) +{ + int res; + res = ast_register_translator (&alawtolin); + if (!res) + res = ast_register_translator (&lintoalaw); + else + ast_unregister_translator (&alawtolin); + return res; +} + +/* + * Return a description of this module. + */ + +char * +description (void) +{ + return tdesc; +} + +int +usecount (void) +{ + int res; + STANDARD_USECOUNT (res); + return res; +} + +char * +key () +{ + return ASTERISK_GPL_KEY; +} diff --git a/include/asterisk/alaw.h b/include/asterisk/alaw.h new file mode 100755 index 0000000000..6861955bb5 --- /dev/null +++ b/include/asterisk/alaw.h @@ -0,0 +1,34 @@ +/* + * Asterisk -- A telephony toolkit for Linux. + * + * A-Law to Signed linear conversion + * + * Copyright (C) 1999, Mark Spencer + * + * Mark Spencer + * + * This program is free software, distributed under the terms of + * the GNU General Public License + */ + +#ifndef _ASTERISK_ALAW_H +#define _ASTERISK_ALAW_H + +//! Init the ulaw conversion stuff +/*! + * To init the ulaw to slinear conversion stuff, this needs to be run. + */ +extern void ast_alaw_init(void); + +//! converts signed linear to mulaw +/*! + */ +extern unsigned char __ast_lin2a[8192]; + +//! help +extern short __ast_alaw[256]; + +#define AST_LIN2A(a) (__ast_lin2a[((unsigned short)(a)) >> 3]) +#define AST_ALAW(a) (__ast_alaw[(a)]) + +#endif