From 1bba6ec6fc2a031acc861d920a58efdca1922b0a Mon Sep 17 00:00:00 2001 From: "Kevin P. Fleming" Date: Sat, 8 Apr 2006 21:40:57 +0000 Subject: merge rizzo's codec module rework (very similar to the format module rework) git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@18541 65c4cc65-6c06-0410-ace0-fbb531ad65f3 --- codecs/codec_g726.c | 486 ++++++++++++++-------------------------------------- 1 file changed, 133 insertions(+), 353 deletions(-) (limited to 'codecs/codec_g726.c') diff --git a/codecs/codec_g726.c b/codecs/codec_g726.c index 6a33d8519..a71651cd5 100644 --- a/codecs/codec_g726.c +++ b/codecs/codec_g726.c @@ -19,7 +19,6 @@ * at the top of the source tree. */ - /*! \file * * \brief codec_g726.c - translate between signed linear and ITU G.726-32kbps @@ -40,6 +39,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/lock.h" #include "asterisk/logger.h" +#include "asterisk/linkedlists.h" #include "asterisk/module.h" #include "asterisk/config.h" #include "asterisk/options.h" @@ -63,16 +63,9 @@ typedef long long sint64; # endif #endif -#define BUFFER_SIZE 8096 /* size for the translation buffers */ +#define BUFFER_SAMPLES 8096 /* size for the translation buffers */ #define BUF_SHIFT 5 -AST_MUTEX_DEFINE_STATIC(localuser_lock); -static int localusecnt = 0; - -static char *tdesc = "ITU G.726-32kbps G726 Transcoder"; - -static int useplc = 0; - /* Sample frame data */ #include "slin_g726_ex.h" @@ -152,8 +145,7 @@ static void g726_init_state(struct g726_state *state_ptr) state_ptr->dms = 0; state_ptr->dml = 0; state_ptr->ap = 0; - for (cnta = 0; cnta < 2; cnta++) - { + for (cnta = 0; cnta < 2; cnta++) { state_ptr->a[cnta] = 0; state_ptr->pk[cnta] = 0; #ifdef NOT_BLI @@ -162,8 +154,7 @@ static void g726_init_state(struct g726_state *state_ptr) state_ptr->sr[cnta] = 32; #endif } - for (cnta = 0; cnta < 6; cnta++) - { + for (cnta = 0; cnta < 6; cnta++) { state_ptr->b[cnta] = 0; #ifdef NOT_BLI state_ptr->dq[cnta] = 1; @@ -694,396 +685,185 @@ static int g726_encode(int sl, struct g726_state *state_ptr) } /* - * Private workspace for translating signed linear signals to G726. + * ------------ Asterisk-codec hooks. ------------------- */ -struct g726_encoder_pvt -{ - struct ast_frame f; - char offset[AST_FRIENDLY_OFFSET]; /* Space to build offset */ - unsigned char outbuf[BUFFER_SIZE]; /* Encoded G726, two nibbles to a word */ - unsigned char next_flag; - struct g726_state g726; - int tail; -}; - /* - * Private workspace for translating G726 signals to signed linear. + * Private workspace for translating signed linear signals to G726. + * Don't bother to define two distinct structs. */ -struct g726_decoder_pvt -{ - struct ast_frame f; - char offset[AST_FRIENDLY_OFFSET]; /* Space to build offset */ - short outbuf[BUFFER_SIZE]; /* Decoded signed linear values */ - struct g726_state g726; - int tail; - plc_state_t plc; +struct g726_coder_pvt { + /* buffer any odd byte in input - 0x80 + (value & 0xf) if present */ + unsigned char next_flag; + struct g726_state g726; }; -/* - * G726ToLin_New - * Create a new instance of g726_decoder_pvt. - * - * Results: - * Returns a pointer to the new instance. - * - * Side effects: - * None. - */ - -static struct ast_translator_pvt * -g726tolin_new (void) +/*! \brief init a new instance of g726_coder_pvt. */ +static void *lintog726_new(struct ast_trans_pvt *pvt) { - struct g726_decoder_pvt *tmp; - if ((tmp = ast_calloc(1, sizeof(*tmp)))) - { - tmp->tail = 0; - plc_init(&tmp->plc); - localusecnt++; - g726_init_state(&tmp->g726); - ast_update_use_count (); - } - return (struct ast_translator_pvt *) tmp; -} - -/* - * LinToG726_New - * Create a new instance of g726_encoder_pvt. - * - * Results: - * Returns a pointer to the new instance. - * - * Side effects: - * None. - */ + struct g726_coder_pvt *tmp = pvt->pvt; -static struct ast_translator_pvt * -lintog726_new (void) -{ - struct g726_encoder_pvt *tmp; - if ((tmp = ast_calloc(1, sizeof(*tmp)))) - { - localusecnt++; - tmp->tail = 0; - g726_init_state(&tmp->g726); - ast_update_use_count (); - } - return (struct ast_translator_pvt *) tmp; + g726_init_state(&tmp->g726); + return tmp; } -/* - * G726ToLin_FrameIn - * Fill an input buffer with packed 4-bit G726 values if there is room - * left. - * - * Results: - * Foo - * - * Side effects: - * tmp->tail is the number of packed values in the buffer. - */ - -static int -g726tolin_framein (struct ast_translator_pvt *pvt, struct ast_frame *f) +/*! \brief decode packed 4-bit G726 values and store in buffer. */ +static int g726tolin_framein (struct ast_trans_pvt *pvt, struct ast_frame *f) { - struct g726_decoder_pvt *tmp = (struct g726_decoder_pvt *) pvt; - unsigned char *b; - int x; - - if(f->datalen == 0) { /* perform PLC with nominal framesize of 20ms/160 samples */ - if((tmp->tail + 160) > BUFFER_SIZE) { - ast_log(LOG_WARNING, "Out of buffer space\n"); - return -1; - } - if(useplc) { - plc_fillin(&tmp->plc, tmp->outbuf+tmp->tail, 160); - tmp->tail += 160; - } - return 0; - } - - b = f->data; - for (x=0;xdatalen;x++) { - if (tmp->tail >= BUFFER_SIZE) { - ast_log(LOG_WARNING, "Out of buffer space!\n"); - return -1; - } - tmp->outbuf[tmp->tail++] = g726_decode((b[x] >> 4) & 0xf, &tmp->g726); - if (tmp->tail >= BUFFER_SIZE) { - ast_log(LOG_WARNING, "Out of buffer space!\n"); - return -1; - } - tmp->outbuf[tmp->tail++] = g726_decode(b[x] & 0x0f, &tmp->g726); - } - - if(useplc) plc_rx(&tmp->plc, tmp->outbuf+tmp->tail-f->datalen*2, f->datalen*2); + struct g726_coder_pvt *tmp = pvt->pvt; + unsigned char *src = f->data; + int16_t *dst = (int16_t *)pvt->outbuf + pvt->samples; + int i; - return 0; + for ( i = 0 ; i < f->datalen ; i++ ) { + *dst++ = g726_decode((src[i] >> 4) & 0xf, &tmp->g726); + *dst++ = g726_decode(src[i] & 0x0f, &tmp->g726); + } + pvt->samples += f->samples; + pvt->datalen += 2 * f->samples; /* 2 bytes/sample */ + return 0; } -/* - * G726ToLin_FrameOut - * Convert 4-bit G726 encoded signals to 16-bit signed linear. - * - * Results: - * Converted signals are placed in tmp->f.data, tmp->f.datalen - * and tmp->f.samples are calculated. - * - * Side effects: - * None. - */ - -static struct ast_frame * -g726tolin_frameout (struct ast_translator_pvt *pvt) +/*! \brief compress and store data (4-bit G726 samples) in outbuf */ +static int lintog726_framein(struct ast_trans_pvt *pvt, struct ast_frame *f) { - struct g726_decoder_pvt *tmp = (struct g726_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.samples = tmp->tail; - 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; -} - -/* - * LinToG726_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 -lintog726_framein (struct ast_translator_pvt *pvt, struct ast_frame *f) -{ - struct g726_encoder_pvt *tmp = (struct g726_encoder_pvt *) pvt; - short *s = f->data; - int samples = f->datalen / 2; - int x; - for (x=0;xnext_flag & 0x80) { - if (tmp->tail >= BUFFER_SIZE) { - ast_log(LOG_WARNING, "Out of buffer space\n"); - return -1; + struct g726_coder_pvt *tmp = pvt->pvt; + int16_t *src = f->data; + int i; + for ( i = 0; i < f->samples; i++ ) { + unsigned char d = g726_encode(src[i], &tmp->g726); /* this sample */ + if (tmp->next_flag & 0x80) { /* merge with leftover sample */ + pvt->outbuf[pvt->datalen++] = ((tmp->next_flag & 0xf)<< 4) | d; + pvt->samples += 2; /* 2 samples per byte */ + tmp->next_flag = 0; + } else { + tmp->next_flag = 0x80 | d; } - tmp->outbuf[tmp->tail++] = ((tmp->next_flag & 0xf)<< 4) | g726_encode(s[x], &tmp->g726); - tmp->next_flag = 0; - } else { - tmp->next_flag = 0x80 | g726_encode(s[x], &tmp->g726); } - } - return 0; + return 0; } -/* - * LinToG726_FrameOut - * Convert a buffer of raw 16-bit signed linear PCM to a buffer - * of 4-bit G726 packed two to a byte (Big Endian). - * - * Results: - * Foo - * - * Side effects: - * Leftover inbuf data gets packed, tail gets updated. - */ - -static struct ast_frame * -lintog726_frameout (struct ast_translator_pvt *pvt) +/*! \brief G726ToLin_Sample */ +static struct ast_frame *g726tolin_sample(void) { - struct g726_encoder_pvt *tmp = (struct g726_encoder_pvt *) pvt; - - if (!tmp->tail) - return NULL; - tmp->f.frametype = AST_FRAME_VOICE; - tmp->f.subclass = AST_FORMAT_G726; - tmp->f.samples = tmp->tail * 2; - 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; + static struct ast_frame f; + f.frametype = AST_FRAME_VOICE; + f.subclass = AST_FORMAT_G726; + f.datalen = sizeof (g726_slin_ex); + f.samples = sizeof(g726_slin_ex) * 2; /* 2 samples per byte */ + f.mallocd = 0; + f.offset = 0; + f.src = __PRETTY_FUNCTION__; + f.data = g726_slin_ex; + return &f; } - -/* - * G726ToLin_Sample - */ - -static struct ast_frame * -g726tolin_sample (void) +/*! \brief LinToG726_Sample */ +static struct ast_frame *lintog726_sample (void) { - static struct ast_frame f; - f.frametype = AST_FRAME_VOICE; - f.subclass = AST_FORMAT_G726; - f.datalen = sizeof (g726_slin_ex); - f.samples = sizeof(g726_slin_ex) * 2; - f.mallocd = 0; - f.offset = 0; - f.src = __PRETTY_FUNCTION__; - f.data = g726_slin_ex; - return &f; + static struct ast_frame f; + f.frametype = AST_FRAME_VOICE; + f.subclass = AST_FORMAT_SLINEAR; + f.datalen = sizeof (slin_g726_ex); + /* Assume 8000 Hz */ + f.samples = sizeof (slin_g726_ex) / 2; /* 1 sample per 2 bytes */ + f.mallocd = 0; + f.offset = 0; + f.src = __PRETTY_FUNCTION__; + f.data = slin_g726_ex; + return &f; } -/* - * LinToG726_Sample - */ - -static struct ast_frame * -lintog726_sample (void) -{ - static struct ast_frame f; - f.frametype = AST_FRAME_VOICE; - f.subclass = AST_FORMAT_SLINEAR; - f.datalen = sizeof (slin_g726_ex); - /* Assume 8000 Hz */ - f.samples = sizeof (slin_g726_ex) / 2; - f.mallocd = 0; - f.offset = 0; - f.src = __PRETTY_FUNCTION__; - f.data = slin_g726_ex; - return &f; -} - -/* - * G726_Destroy - * Destroys a private workspace. - * - * Results: - * It's gone! - * - * Side effects: - * None. - */ - -static void -g726_destroy (struct ast_translator_pvt *pvt) -{ - free (pvt); - localusecnt--; - ast_update_use_count (); -} - -/* - * The complete translator for G726ToLin. - */ +static struct ast_module_lock me = { .usecnt = -1 }; static struct ast_translator g726tolin = { - "g726tolin", - AST_FORMAT_G726, - AST_FORMAT_SLINEAR, - g726tolin_new, - g726tolin_framein, - g726tolin_frameout, - g726_destroy, - /* NULL */ - g726tolin_sample + .name = "g726tolin", + .srcfmt = AST_FORMAT_G726, + .dstfmt = AST_FORMAT_SLINEAR, + .newpvt = lintog726_new, /* same for both directions */ + .framein = g726tolin_framein, + .sample = g726tolin_sample, + .desc_size = sizeof(struct g726_coder_pvt), + .buffer_samples = BUFFER_SAMPLES, + .buf_size = BUFFER_SAMPLES * 2, + .plc_samples = 160, + .lockp = &me, }; -/* - * The complete translator for LinToG726. - */ - static struct ast_translator lintog726 = { - "lintog726", - AST_FORMAT_SLINEAR, - AST_FORMAT_G726, - lintog726_new, - lintog726_framein, - lintog726_frameout, - g726_destroy, - /* NULL */ - lintog726_sample + .name = "lintog726", + .srcfmt = AST_FORMAT_SLINEAR, + .dstfmt = AST_FORMAT_G726, + .newpvt = lintog726_new, /* same for both directions */ + .framein = lintog726_framein, + .sample = lintog726_sample, + .desc_size = sizeof(struct g726_coder_pvt), + .buffer_samples = BUFFER_SAMPLES, + .buf_size = BUFFER_SAMPLES/2, + .lockp = &me, }; -static void -parse_config(void) +static void parse_config(void) { - struct ast_config *cfg; - struct ast_variable *var; - if ((cfg = ast_config_load("codecs.conf"))) { - if ((var = ast_variable_browse(cfg, "plc"))) { - while (var) { - if (!strcasecmp(var->name, "genericplc")) { - useplc = ast_true(var->value) ? 1 : 0; - if (option_verbose > 2) - ast_verbose(VERBOSE_PREFIX_3 "codec_g726: %susing generic PLC\n", useplc ? "" : "not "); - } - var = var->next; - } - } - ast_config_destroy(cfg); - } + struct ast_variable *var; + struct ast_config *cfg = ast_config_load("codecs.conf"); + if (!cfg) + return; + for (var = ast_variable_browse(cfg, "plc"); var; var = var->next) { + if (!strcasecmp(var->name, "genericplc")) { + g726tolin.useplc = ast_true(var->value) ? 1 : 0; + if (option_verbose > 2) + ast_verbose(VERBOSE_PREFIX_3 "codec_g726: %susing generic PLC\n", + g726tolin.useplc ? "" : "not "); + } + } + ast_config_destroy(cfg); } -int -reload(void) +/*! \brief standard module glue */ + +int reload(void) { - parse_config(); - return 0; + parse_config(); + return 0; } -int -unload_module (void) +int unload_module (void) { - int res; - ast_mutex_lock (&localuser_lock); - res = ast_unregister_translator (&lintog726); - if (!res) - res = ast_unregister_translator (&g726tolin); - if (localusecnt) - res = -1; - ast_mutex_unlock (&localuser_lock); - return res; + int res; + ast_mutex_lock (&me.lock); + res = ast_unregister_translator (&lintog726); + res |= ast_unregister_translator (&g726tolin); + if (me.usecnt) + res = -1; + ast_mutex_unlock (&me.lock); + return res; } -int -load_module (void) +int load_module (void) { - int res; - parse_config(); - res = ast_register_translator (&g726tolin); - if (!res) - res = ast_register_translator (&lintog726); - else - ast_unregister_translator (&g726tolin); - return res; + int res; + parse_config(); + res = ast_register_translator (&g726tolin); + if (!res) + res = ast_register_translator (&lintog726); + else + ast_unregister_translator (&g726tolin); + return res; } -/* - * Return a description of this module. - */ - -char * -description (void) +char *description (void) { - return tdesc; + return "ITU G.726-32kbps G726 Transcoder"; } -int -usecount (void) +int usecount (void) { - int res; - OLD_STANDARD_USECOUNT (res); - return res; + return me.usecnt; } -char * -key () +char *key() { - return ASTERISK_GPL_KEY; + return ASTERISK_GPL_KEY; } -- cgit v1.2.3