merge rizzo's codec module rework (very similar to the format module rework)
authorKevin P. Fleming <kpfleming@digium.com>
Sat, 8 Apr 2006 21:40:57 +0000 (21:40 +0000)
committerKevin P. Fleming <kpfleming@digium.com>
Sat, 8 Apr 2006 21:40:57 +0000 (21:40 +0000)
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@18541 65c4cc65-6c06-0410-ace0-fbb531ad65f3

12 files changed:
codecs/codec_a_mu.c
codecs/codec_adpcm.c
codecs/codec_alaw.c
codecs/codec_g723_1.c
codecs/codec_g726.c
codecs/codec_gsm.c
codecs/codec_ilbc.c
codecs/codec_lpc10.c
codecs/codec_speex.c
codecs/codec_ulaw.c
include/asterisk/translate.h
translate.c

index f03612b..4d05891 100644 (file)
@@ -43,12 +43,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #include "asterisk/ulaw.h"
 #include "asterisk/utils.h"
 
-#define BUFFER_SIZE   8096     /* size for the translation buffers */
-
-AST_MUTEX_DEFINE_STATIC(localuser_lock);
-static int localusecnt = 0;
-
-static char *tdesc = "A-law and Mulaw direct Coder/Decoder";
+#define BUFFER_SAMPLES   8000  /* size for the translation buffers */
 
 static unsigned char mu2a[256];
 static unsigned char a2mu[256];
@@ -57,146 +52,37 @@ static unsigned char a2mu[256];
 
 #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 laws.
- */
-
-struct ulaw_encoder_pvt
-{
-       struct ast_frame f;
-       char offset[AST_FRIENDLY_OFFSET];       /* Space to build offset */
-       unsigned char outbuf[BUFFER_SIZE];      /* Encoded ulaw values */
-       int tail;
-};
-
-static struct ast_translator_pvt *alawtoulaw_new(void)
-{
-       struct ulaw_encoder_pvt *tmp;
-       
-       if ((tmp = ast_calloc(1, sizeof(*tmp)))) {
-               tmp->tail = 0;
-               localusecnt++;
-               ast_update_use_count();
-       }
-
-       return (struct ast_translator_pvt *)tmp;
-}
-
-static struct ast_translator_pvt *ulawtoalaw_new(void)
-{
-       struct alaw_encoder_pvt *tmp;
-       
-       if ((tmp = ast_calloc(1, sizeof(*tmp)))) {
-               localusecnt++;
-               ast_update_use_count();
-               tmp->tail = 0;
-       }
-
-       return (struct ast_translator_pvt *)tmp;
-}
-
-static int alawtoulaw_framein(struct ast_translator_pvt *pvt, struct ast_frame *f)
+/*! \brief convert frame data and store into the buffer */
+static int alawtoulaw_framein(struct ast_trans_pvt *pvt, struct ast_frame *f)
 {
-       struct ulaw_encoder_pvt *tmp = (struct ulaw_encoder_pvt *)pvt;
        int x;
-       unsigned char *b;
+       unsigned char *src = f->data;
+       unsigned char *dst = (unsigned char *)pvt->outbuf + pvt->samples;
 
-       if ((tmp->tail + f->datalen) > 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;x<f->datalen;x++)
-               tmp->outbuf[tmp->tail + x] = a2mu[b[x]];
-
-       tmp->tail += f->datalen;
+       for ( x = 0 ; x < f->samples; x++)
+               dst[x] = a2mu[src[x]];
+       pvt->samples += f->samples;
+       pvt->datalen += f->datalen;
        return 0;
 }
 
-static struct ast_frame *alawtoulaw_frameout(struct ast_translator_pvt *pvt)
-{
-       struct ulaw_encoder_pvt *tmp = (struct ulaw_encoder_pvt *)pvt;
-
-       if (!tmp->tail)
-               return NULL;
-
-       tmp->f.frametype = AST_FRAME_VOICE;
-       tmp->f.subclass = AST_FORMAT_ULAW;
-       tmp->f.datalen = tmp->tail;
-       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;
-}
-
-static int ulawtoalaw_framein(struct ast_translator_pvt *pvt, struct ast_frame *f)
+/*! \brief convert frame data and store into the buffer */
+static int ulawtoalaw_framein(struct ast_trans_pvt *pvt, struct ast_frame *f)
 {
-       struct alaw_encoder_pvt *tmp = (struct alaw_encoder_pvt *)pvt;
        int x;
-       unsigned char *s;
-       if (tmp->tail + f->datalen >= sizeof(tmp->outbuf)) {
-               ast_log(LOG_WARNING, "Out of buffer space\n");
-               return -1;
-       }
-       s = f->data;
-       for (x=0;x<f->datalen;x++) 
-               tmp->outbuf[x+tmp->tail] = mu2a[s[x]];
-       tmp->tail += f->datalen;
-       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.
- */
+       unsigned char *src = f->data;
+       unsigned char *dst = (unsigned char *)pvt->outbuf + pvt->samples;
 
-static struct ast_frame *ulawtoalaw_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.samples = tmp->tail;
-               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;
+       for ( x = 0 ; x < f->samples; x++)
+               dst[x] = mu2a[src[x]];
+       pvt->samples += f->samples;
+       pvt->datalen += f->datalen;
+       return 0;
 }
 
 /*
- * alawToLin_Sample
+ * alawToLin_Sample. Just random data, somehow...
  */
-
 static struct ast_frame *alawtoulaw_sample(void)
 {
        static struct ast_frame f;
@@ -207,7 +93,7 @@ static struct ast_frame *alawtoulaw_sample(void)
        f.mallocd = 0;
        f.offset = 0;
        f.src = __PRETTY_FUNCTION__;
-       f.data = ulaw_slin_ex;
+       f.data = ulaw_slin_ex; /* XXX what ? */
        return &f;
 }
 
@@ -225,66 +111,41 @@ static struct ast_frame *ulawtoalaw_sample(void)
        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_module_lock me = { .usecnt = -1 };
 
 static struct ast_translator alawtoulaw = {
-       "alawtoulaw",
-       AST_FORMAT_ALAW,
-       AST_FORMAT_ULAW,
-       alawtoulaw_new,
-       alawtoulaw_framein,
-       alawtoulaw_frameout,
-       alaw_destroy,
-       /* NULL */
-       alawtoulaw_sample
+       .name = "alawtoulaw",
+       .srcfmt = AST_FORMAT_ALAW,
+       .dstfmt = AST_FORMAT_ULAW,
+       .framein = alawtoulaw_framein,
+       .sample = alawtoulaw_sample,
+       .buffer_samples = BUFFER_SAMPLES,
+       .buf_size = BUFFER_SAMPLES,
+       .lockp = &me,
 };
 
-/*
- * The complete translator for LinToalaw.
- */
-
 static struct ast_translator ulawtoalaw = {
-       "ulawtoalaw",
-       AST_FORMAT_ULAW,
-       AST_FORMAT_ALAW,
-       ulawtoalaw_new,
-       ulawtoalaw_framein,
-       ulawtoalaw_frameout,
-       alaw_destroy,
-       /* NULL */
-       ulawtoalaw_sample
+       .name = "ulawtoalaw",
+       .srcfmt = AST_FORMAT_ULAW,
+       .dstfmt = AST_FORMAT_ALAW,
+       .framein = ulawtoalaw_framein,
+       .sample = ulawtoalaw_sample,
+       .buffer_samples = BUFFER_SAMPLES,
+       .buf_size = BUFFER_SAMPLES,
+       .lockp = &me,
 };
 
+/*! \brief standard module glue */
+
 int unload_module(void)
 {
        int res;
-       ast_mutex_lock(&localuser_lock);
+       ast_mutex_lock(&me.lock);
        res = ast_unregister_translator(&ulawtoalaw);
-       if (!res)
-               res = ast_unregister_translator(&alawtoulaw);
-       if (localusecnt)
+       res |= ast_unregister_translator(&alawtoulaw);
+       if (me.usecnt)
                res = -1;
-       ast_mutex_unlock(&localuser_lock);
+       ast_mutex_unlock(&me.lock);
        return res;
 }
 
@@ -304,20 +165,14 @@ int load_module(void)
        return res;
 }
 
-/*
- * Return a description of this module.
- */
-
 char *description(void)
 {
-       return tdesc;
+       return "A-law and Mulaw direct Coder/Decoder";
 }
 
 int usecount(void)
 {
-       int res;
-       OLD_STANDARD_USECOUNT(res);
-       return res;
+       return me.usecnt;
 }
 
 char *key()
index 19970a5..192ae10 100644 (file)
@@ -40,6 +40,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"
@@ -50,14 +51,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 /* define NOT_BLI to use a faster but not bit-level identical version */
 /* #define NOT_BLI */
 
-#define BUFFER_SIZE   8096     /* size for the translation buffers */
-
-AST_MUTEX_DEFINE_STATIC(localuser_lock);
-static int localusecnt = 0;
-
-static char *tdesc = "Adaptive Differential PCM Coder/Decoder";
-
-static int useplc = 0;
+#define BUFFER_SAMPLES   8096  /* size for the translation buffers */
 
 /* Sample frame data */
 
@@ -227,250 +221,81 @@ static inline int adpcm(short csig, struct adpcm_state *state)
        return encoded;
 }
 
-/*
- * Private workspace for translating signed linear signals to ADPCM.
- */
+/*----------------- Asterisk-codec glue ------------*/
 
-struct adpcm_encoder_pvt
-{
-       struct ast_frame f;
-       char offset[AST_FRIENDLY_OFFSET];       /* Space to build offset */
-       short inbuf[BUFFER_SIZE];               /* Unencoded signed linear values */
-       unsigned char outbuf[BUFFER_SIZE];      /* Encoded ADPCM, two nibbles to a word */
+/*! \brief Workspace for translating signed linear signals to ADPCM. */
+struct adpcm_encoder_pvt {
        struct adpcm_state state;
-       int tail;
+       int16_t inbuf[BUFFER_SAMPLES];  /* Unencoded signed linear values */
 };
 
-/*
- * Private workspace for translating ADPCM signals to signed linear.
- */
-
-struct adpcm_decoder_pvt
-{
-       struct ast_frame f;
-       char offset[AST_FRIENDLY_OFFSET];       /* Space to build offset */
-       short outbuf[BUFFER_SIZE];              /* Decoded signed linear values */
+/*! \brief Workspace for translating ADPCM signals to signed linear. */
+struct adpcm_decoder_pvt {
        struct adpcm_state state;
-       int tail;
-       plc_state_t plc;
 };
 
-/*
- * AdpcmToLin_New
- *  Create a new instance of adpcm_decoder_pvt.
- *
- * Results:
- *  Returns a pointer to the new instance.
- *
- * Side effects:
- *  None.
- */
-
-static struct ast_translator_pvt *adpcmtolin_new(void)
+/*! \brief decode 4-bit adpcm frame data and store in output buffer */
+static int adpcmtolin_framein(struct ast_trans_pvt *pvt, struct ast_frame *f)
 {
-       struct adpcm_decoder_pvt *tmp;
-       
-       if ((tmp = ast_calloc(1, sizeof(*tmp)))) {
-               tmp->tail = 0;
-               plc_init(&tmp->plc);
-               localusecnt++;
-               ast_update_use_count();
-       }
-
-       return (struct ast_translator_pvt *)tmp;
-}
-
-/*
- * LinToAdpcm_New
- *  Create a new instance of adpcm_encoder_pvt.
- *
- * Results:
- *  Returns a pointer to the new instance.
- *
- * Side effects:
- *  None.
- */
-
-static struct ast_translator_pvt *lintoadpcm_new(void)
-{
-       struct adpcm_encoder_pvt *tmp;
-       
-       if ((tmp = ast_calloc(1, sizeof(*tmp)))) {
-               localusecnt++;
-               ast_update_use_count();
-               tmp->tail = 0;
-       }
-
-       return (struct ast_translator_pvt *)tmp;
-}
-
-/*
- * AdpcmToLin_FrameIn
- *  Take an input buffer with packed 4-bit ADPCM values and put decoded PCM in outbuf, 
- *  if there is room left.
- *
- * Results:
- *  Foo
- *
- * Side effects:
- *  tmp->tail is the number of packed values in the buffer.
- */
-
-static int adpcmtolin_framein(struct ast_translator_pvt *pvt, struct ast_frame *f)
-{
-       struct adpcm_decoder_pvt *tmp = (struct adpcm_decoder_pvt *)pvt;
+       struct adpcm_decoder_pvt *tmp = pvt->pvt;
        int x;
-       unsigned char *b;
+       unsigned char *src = f->data;
+       int16_t *dst = (int16_t *)pvt->outbuf + pvt->samples;
 
-       if(f->datalen == 0) { /* perform PLC with nominal framesize of 20ms/160 samples */
-               if((tmp->tail + 160) > sizeof(tmp->outbuf) / 2) {
-                       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;
+       for (x=0; x < f->datalen; x++) {
+               *dst++ = decode((src[x] >> 4) & 0xf, &tmp->state);
+               *dst++ = decode(src[x] & 0x0f, &tmp->state);
        }
-
-       if (f->datalen * 4 + tmp->tail * 2 > sizeof(tmp->outbuf)) {
-               ast_log(LOG_WARNING, "Out of buffer space\n");
-               return -1;
-       }
-
-       b = f->data;
-
-       for (x=0;x<f->datalen;x++) {
-               tmp->outbuf[tmp->tail++] = decode((b[x] >> 4) & 0xf, &tmp->state);
-               tmp->outbuf[tmp->tail++] = decode(b[x] & 0x0f, &tmp->state);
-       }
-
-       if(useplc)
-               plc_rx(&tmp->plc, tmp->outbuf+tmp->tail-f->datalen*2, f->datalen*2);
-
+       pvt->samples += f->samples;
+       pvt->datalen += 2*f->samples;
        return 0;
 }
 
-/*
- * AdpcmToLin_FrameOut
- *  Convert 4-bit ADPCM 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 *adpcmtolin_frameout(struct ast_translator_pvt *pvt)
+/*! \brief fill input buffer with 16-bit signed linear PCM values. */
+static int lintoadpcm_framein(struct ast_trans_pvt *pvt, struct ast_frame *f)
 {
-       struct adpcm_decoder_pvt *tmp = (struct adpcm_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;
-}
+       struct adpcm_encoder_pvt *tmp = pvt->pvt;
 
-/*
- * LinToAdpcm_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 lintoadpcm_framein(struct ast_translator_pvt *pvt, struct ast_frame *f)
-{
-       struct adpcm_encoder_pvt *tmp = (struct adpcm_encoder_pvt *)pvt;
-
-       if ((tmp->tail + f->datalen / 2) < (sizeof(tmp->inbuf) / 2)) {
-               memcpy(&tmp->inbuf[tmp->tail], f->data, f->datalen);
-               tmp->tail += f->datalen / 2;
-       } else {
-               ast_log(LOG_WARNING, "Out of buffer space\n");
-               return -1;
-       }
+       memcpy(&tmp->inbuf[pvt->samples], f->data, f->datalen);
+       pvt->samples += f->samples;
        return 0;
 }
 
-/*
- * LinToAdpcm_FrameOut
- *  Convert a buffer of raw 16-bit signed linear PCM to a buffer
- *  of 4-bit ADPCM packed two to a byte (Big Endian).
- *
- * Results:
- *  Foo
- *
- * Side effects:
- *  Leftover inbuf data gets packed, tail gets updated.
- */
-
-static struct ast_frame *lintoadpcm_frameout(struct ast_translator_pvt *pvt)
+/*! \brief convert inbuf and store into frame */
+static struct ast_frame *lintoadpcm_frameout(struct ast_trans_pvt *pvt)
 {
-       struct adpcm_encoder_pvt *tmp = (struct adpcm_encoder_pvt *)pvt;
-       int i_max, i;
+       struct adpcm_encoder_pvt *tmp = pvt->pvt;
+       struct ast_frame *f;
+       int i;
+       int samples = pvt->samples;     /* save original number */
   
-       if (tmp->tail < 2)
+       if (samples < 2)
                return NULL;
 
-       i_max = tmp->tail & ~1; /* atomic size is 2 samples */
-
-       /* What is this, state debugging? should be #ifdef'd then
-       tmp->outbuf[0] = tmp->ssindex & 0xff;
-       tmp->outbuf[1] = (tmp->signal >> 8) & 0xff;
-       tmp->outbuf[2] = (tmp->signal & 0xff);
-       tmp->outbuf[3] = tmp->zero_count;
-       tmp->outbuf[4] = tmp->next_flag;
-       */
-       for (i = 0; i < i_max; i+=2) {
-               tmp->outbuf[i/2] =
+       pvt->samples &= ~1; /* atomic size is 2 samples */
+
+       for (i = 0; i < pvt->samples; i += 2) {
+               pvt->outbuf[i/2] =
                        (adpcm(tmp->inbuf[i  ], &tmp->state) << 4) |
                        (adpcm(tmp->inbuf[i+1], &tmp->state)     );
        };
 
-       tmp->f.frametype = AST_FRAME_VOICE;
-       tmp->f.subclass = AST_FORMAT_ADPCM;
-       tmp->f.samples = i_max;
-       tmp->f.mallocd = 0;
-       tmp->f.offset = AST_FRIENDLY_OFFSET;
-       tmp->f.src = __PRETTY_FUNCTION__;
-       tmp->f.data = tmp->outbuf;
-       tmp->f.datalen = i_max / 2;
+       f = ast_trans_frameout(pvt, pvt->samples/2, 0);
 
        /*
-        * If there is a signal left over (there should be no more than
-        * one) move it to the beginning of the input buffer.
+        * If there is a left over sample, move it to the beginning
+        * of the input buffer.
         */
 
-       if (tmp->tail == i_max)
-               tmp->tail = 0;
-       else {
-               tmp->inbuf[0] = tmp->inbuf[tmp->tail];
-               tmp->tail = 1;
+       if (samples & 1) {      /* move the leftover sample at beginning */
+               tmp->inbuf[0] = tmp->inbuf[samples - 1];
+               pvt->samples = 1;
        }
-       return &tmp->f;
+       return f;
 }
 
 
-/*
- * AdpcmToLin_Sample
- */
-
+/*! \brief AdpcmToLin_Sample */
 static struct ast_frame *adpcmtolin_sample(void)
 {
        static struct ast_frame f;
@@ -485,10 +310,7 @@ static struct ast_frame *adpcmtolin_sample(void)
        return &f;
 }
 
-/*
- * LinToAdpcm_Sample
- */
-
+/*! \brief LinToAdpcm_Sample */
 static struct ast_frame *lintoadpcm_sample(void)
 {
        static struct ast_frame f;
@@ -504,75 +326,51 @@ static struct ast_frame *lintoadpcm_sample(void)
        return &f;
 }
 
-/*
- * Adpcm_Destroy
- *  Destroys a private workspace.
- *
- * Results:
- *  It's gone!
- *
- * Side effects:
- *  None.
- */
-
-static void adpcm_destroy(struct ast_translator_pvt *pvt)
-{
-       free(pvt);
-       localusecnt--;
-       ast_update_use_count();
-}
-
-/*
- * The complete translator for ADPCMToLin.
- */
+struct ast_module_lock me = { .usecnt = -1 };
 
 static struct ast_translator adpcmtolin = {
-       "adpcmtolin",
-       AST_FORMAT_ADPCM,
-       AST_FORMAT_SLINEAR,
-       adpcmtolin_new,
-       adpcmtolin_framein,
-       adpcmtolin_frameout,
-       adpcm_destroy,
-       /* NULL */
-       adpcmtolin_sample
+       .name = "adpcmtolin",
+       .srcfmt = AST_FORMAT_ADPCM,
+       .dstfmt = AST_FORMAT_SLINEAR,
+       .framein = adpcmtolin_framein,
+       .sample = adpcmtolin_sample,
+       .desc_size = sizeof(struct adpcm_decoder_pvt),
+       .buffer_samples = BUFFER_SAMPLES,
+       .buf_size = BUFFER_SAMPLES * 2,
+       .plc_samples = 160,
+       .lockp = &me,
 };
 
-/*
- * The complete translator for LinToADPCM.
- */
-
 static struct ast_translator lintoadpcm = {
-       "lintoadpcm",
-       AST_FORMAT_SLINEAR,
-       AST_FORMAT_ADPCM,
-       lintoadpcm_new,
-       lintoadpcm_framein,
-       lintoadpcm_frameout,
-       adpcm_destroy,
-       /* NULL */
-       lintoadpcm_sample
+       .name = "lintoadpcm",
+       .srcfmt = AST_FORMAT_SLINEAR,
+       .dstfmt = AST_FORMAT_ADPCM,
+       .framein = lintoadpcm_framein,
+       .frameout = lintoadpcm_frameout,
+       .sample = lintoadpcm_sample,
+       .desc_size = sizeof (struct adpcm_encoder_pvt),
+       .buffer_samples = BUFFER_SAMPLES,
+       .buf_size = BUFFER_SAMPLES/ 2,  /* 2 samples per byte */
+       .lockp = &me,
 };
 
 static void parse_config(void)
 {
-       struct ast_config *cfg;
+       struct ast_config *cfg = ast_config_load("codecs.conf");
        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_adpcm: %susing generic PLC\n", useplc ? "" : "not ");
-                               }
-                               var = var->next;
-                       }
+       if (cfg == NULL)
+               return;
+       for (var = ast_variable_browse(cfg, "plc"); var ; var = var->next) {
+               if (!strcasecmp(var->name, "genericplc")) {
+                       adpcmtolin.useplc = ast_true(var->value) ? 1 : 0;
+                       if (option_verbose > 2)
+                               ast_verbose(VERBOSE_PREFIX_3 "codec_adpcm: %susing generic PLC\n", adpcmtolin.useplc ? "" : "not ");
                }
-               ast_config_destroy(cfg);
        }
+       ast_config_destroy(cfg);
 }
 
+/*! \brief standard module glue */
 int reload(void)
 {
        parse_config();
@@ -582,13 +380,12 @@ int reload(void)
 int unload_module(void)
 {
        int res;
-       ast_mutex_lock(&localuser_lock);
+       ast_mutex_lock(&me.lock);
        res = ast_unregister_translator(&lintoadpcm);
-       if (!res)
-               res = ast_unregister_translator(&adpcmtolin);
-       if (localusecnt)
+       res |= ast_unregister_translator(&adpcmtolin);
+       if (me.usecnt)
                res = -1;
-       ast_mutex_unlock(&localuser_lock);
+       ast_mutex_unlock(&me.lock);
        return res;
 }
 
@@ -604,20 +401,14 @@ int load_module(void)
        return res;
 }
 
-/*
- * Return a description of this module.
- */
-
 char *description(void)
 {
-       return tdesc;
+       return "Adaptive Differential PCM Coder/Decoder";
 }
 
 int usecount(void)
 {
-       int res;
-       OLD_STANDARD_USECOUNT(res);
-       return res;
+       return me.usecnt;
 }
 
 char *key()
index 480b92c..cc3f643 100644 (file)
@@ -44,232 +44,42 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #include "asterisk/alaw.h"
 #include "asterisk/utils.h"
 
-#define BUFFER_SIZE   8096     /* size for the translation buffers */
-
-AST_MUTEX_DEFINE_STATIC(localuser_lock);
-static int localusecnt = 0;
-
-static char *tdesc = "A-law Coder/Decoder";
-
-static int useplc = 0;
+#define BUFFER_SAMPLES   8096  /* size for the translation buffers */
 
 /* Sample frame data (Mu data is okay) */
 
 #include "slin_ulaw_ex.h"
 #include "ulaw_slin_ex.h"
 
-/*!
- * \brief 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;
-};
-
-/*!
- * \brief 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;
-       plc_state_t plc;
-};
-
-/*!
- * \brief 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(void)
-{
-       struct alaw_decoder_pvt *tmp;
-       
-       if ((tmp = ast_calloc(1, sizeof(*tmp)))) {
-               tmp->tail = 0;
-               plc_init(&tmp->plc);
-               localusecnt++;
-               ast_update_use_count();
-       }
-
-       return (struct ast_translator_pvt *)tmp;
-}
-
-/*!
- * \brief 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(void)
-{
-       struct alaw_encoder_pvt *tmp;
-
-       if ((tmp = ast_calloc(1, sizeof(*tmp)))) {
-               localusecnt++;
-               ast_update_use_count();
-               tmp->tail = 0;
-       }
-
-       return (struct ast_translator_pvt *)tmp;
-}
-
-/*!
- * \brief 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)
+/*! \brief decode frame into lin and fill output buffer. */
+static int alawtolin_framein(struct ast_trans_pvt *pvt, struct ast_frame *f)
 {
-       struct alaw_decoder_pvt *tmp = (struct alaw_decoder_pvt *)pvt;
-       int x;
-       unsigned char *b;
-
-       if(f->datalen == 0) { /* perform PLC with nominal framesize of 20ms/160 samples */
-               if((tmp->tail + 160) * 2 > sizeof(tmp->outbuf)) {
-                       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;
-       }
+       int i;
+       unsigned char *src = f->data;
+       int16_t *dst = (int16_t *)pvt->outbuf;
 
-       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;x<f->datalen;x++)
-               tmp->outbuf[tmp->tail + x] = AST_ALAW(b[x]);
-
-       if(useplc)
-               plc_rx(&tmp->plc, tmp->outbuf+tmp->tail, f->datalen);
-
-       tmp->tail += f->datalen;
+       for ( i = 0; i < f->samples; i++)
+               dst[pvt->samples + i] = AST_ALAW(src[i]);
+       pvt->samples += f->samples;
+       pvt->datalen += 2*f->samples;   /* 2 bytes/sample */
        return 0;
 }
 
-/*!
- * \brief 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.samples 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.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;
-}
-
-/*!
- * \brief 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)
+/*! \brief convert and store input samples in output buffer */
+static int lintoalaw_framein(struct ast_trans_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;x<f->datalen/2;x++) 
-               tmp->outbuf[x+tmp->tail] = AST_LIN2A(s[x]);
-       tmp->tail += f->datalen/2;
-       return 0;
-}
+       char *dst = pvt->outbuf + pvt->samples;
+       int16_t *src = f->data;
 
-/*!
- * \brief 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.samples = tmp->tail;
-               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;
+       for ( x = 0; x < f->samples; x++) 
+               *dst++ = AST_LIN2A(src[x]);
+       pvt->samples += f->samples;
+       pvt->datalen += f->samples;     /* 1 byte/sample */
+       return 0;
 }
 
-/*!
- * \brief alawToLin_Sample
- */
-
+/*! \brief alawToLin_Sample */
 static struct ast_frame *alawtolin_sample(void)
 {
        static struct ast_frame f;
@@ -284,17 +94,13 @@ static struct ast_frame *alawtolin_sample(void)
        return &f;
 }
 
-/*!
- * \brief LinToalaw_Sample
- */
-
+/*! \brief LinToalaw_Sample */
 static struct ast_frame *lintoalaw_sample(void)
 {
        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.samples = sizeof(slin_ulaw_ex) / 2;
        f.mallocd = 0;
        f.offset = 0;
@@ -303,76 +109,49 @@ static struct ast_frame *lintoalaw_sample(void)
        return &f;
 }
 
-/*!
- * \brief 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();
-}
-
-/*!
- * \brief The complete translator for alawToLin.
- */
+static struct ast_module_lock me = { .usecnt = -1 };
 
 static struct ast_translator alawtolin = {
-       "alawtolin",
-       AST_FORMAT_ALAW,
-       AST_FORMAT_SLINEAR,
-       alawtolin_new,
-       alawtolin_framein,
-       alawtolin_frameout,
-       alaw_destroy,
-       /* NULL */
-       alawtolin_sample
+       .name = "alawtolin",
+       .srcfmt = AST_FORMAT_ALAW,
+       .dstfmt = AST_FORMAT_SLINEAR,
+       .framein = alawtolin_framein,
+       .sample = alawtolin_sample,
+       .buffer_samples = BUFFER_SAMPLES,
+       .buf_size = BUFFER_SAMPLES * 2,
+       .plc_samples = 160,
+       .lockp = &me,
 };
 
-/*!
- * \brief 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
+       .srcfmt = AST_FORMAT_SLINEAR,
+       .dstfmt = AST_FORMAT_ALAW,
+       .framein = lintoalaw_framein,
+       .sample = lintoalaw_sample,
+       .buffer_samples = BUFFER_SAMPLES,
+       .buf_size = BUFFER_SAMPLES,
+       .lockp = &me,
 };
 
 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_alaw: %susing generic PLC\n", useplc ? "" : "not ");
-                               }
-                               var = var->next;
-                       }
+       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")) {
+                       alawtolin.useplc = ast_true(var->value) ? 1 : 0;
+                       if (option_verbose > 2)
+                               ast_verbose(VERBOSE_PREFIX_3 "codec_alaw: %susing generic PLC\n", alawtolin.useplc ? "" : "not ");
                }
-               ast_config_destroy(cfg);
        }
+       ast_config_destroy(cfg);
 }
 
+/*! \brief standard module stuff */
+
 int reload(void)
 {
        parse_config();
@@ -382,13 +161,12 @@ int reload(void)
 int unload_module(void)
 {
        int res;
-       ast_mutex_lock(&localuser_lock);
+       ast_mutex_lock(&me.lock);
        res = ast_unregister_translator(&lintoalaw);
-       if (!res)
-               res = ast_unregister_translator(&alawtolin);
-       if (localusecnt)
+       res |= ast_unregister_translator(&alawtolin);
+       if (me.usecnt)
                res = -1;
-       ast_mutex_unlock(&localuser_lock);
+       ast_mutex_unlock(&me.lock);
        return res;
 }
 
@@ -404,20 +182,14 @@ int load_module(void)
        return res;
 }
 
-/*
- * Return a description of this module.
- */
-
 char *description(void)
 {
-       return tdesc;
+       return "A-law Coder/Decoder";
 }
 
 int usecount(void)
 {
-       int res;
-       OLD_STANDARD_USECOUNT(res);
-       return res;
+       return me.usecnt;
 }
 
 char *key()
index c226bb0..4eeb60e 100644 (file)
@@ -74,14 +74,11 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #include "slin_g723_ex.h"
 #include "g723_slin_ex.h"
 
-AST_MUTEX_DEFINE_STATIC(localuser_lock);
-static int localusecnt=0;
-
-#ifdef ANNEX_B
-static char *tdesc = "Annex B (floating point) G.723.1/PCM16 Codec Translator";
-#else
-static char *tdesc = "Annex A (fixed point) G.723.1/PCM16 Codec Translator";
-#endif
+/* g723_1 has 240 samples per buffer.
+ * We want a buffer which is a multiple...
+ */
+#define        G723_SAMPLES    240
+#define        BUFFER_SAMPLES  8160    /* 240 * 34 */
 
 /* Globals */
 Flag UsePf = True;
@@ -92,37 +89,20 @@ enum Crate WrkRate = Rate63;
 
 struct g723_encoder_pvt {
        struct cod_state cod;
-       struct ast_frame f;
-       /* Space to build offset */
-       char offset[AST_FRIENDLY_OFFSET];
-       /* Buffer for our outgoing frame */
-       char outbuf[8000];
-       /* Enough to store a full second */
-       short buf[8000];
-       int tail;
+       int16_t buf[BUFFER_SAMPLES];    /* input buffer */
 };
 
 struct g723_decoder_pvt {
        struct dec_state dec;
-       struct ast_frame f;
-       /* Space to build offset */
-       char offset[AST_FRIENDLY_OFFSET];
-       /* Enough to store a full second */
-       short buf[8000];
-       int tail;
 };
 
-static struct ast_translator_pvt *g723tolin_new(void)
+static struct ast_trans_pvt *g723tolin_new(struct ast *pvt)
 {
-       struct g723_decoder_pvt *tmp;   
-       if ((tmp = ast_malloc(sizeof(*tmp)))) {
-               Init_Decod(&tmp->dec);
-           Init_Dec_Cng(&tmp->dec);
-               tmp->tail = 0;
-               localusecnt++;
-               ast_update_use_count();
-       }
-       return (struct ast_translator_pvt *)tmp;
+       struct g723_decoder_pvt *tmp = pvt;
+
+       Init_Decod(&tmp->dec);
+       Init_Dec_Cng(&tmp->dec);
+       return tmp;
 }
 
 static struct ast_frame *lintog723_sample(void)
@@ -131,7 +111,6 @@ static struct ast_frame *lintog723_sample(void)
        f.frametype = AST_FRAME_VOICE;
        f.subclass = AST_FORMAT_SLINEAR;
        f.datalen = sizeof(slin_g723_ex);
-       /* Assume 8000 Hz */
        f.samples = sizeof(slin_g723_ex)/2;
        f.mallocd = 0;
        f.offset = 0;
@@ -155,53 +134,16 @@ static struct ast_frame *g723tolin_sample(void)
        return &f;
 }
 
-static struct ast_translator_pvt *lintog723_new(void)
+static void *lintog723_new(void *pvt)
 {
-       struct g723_encoder_pvt *tmp;   
-       if ((tmp = ast_malloc(sizeof(*tmp)))) {
-               Init_Coder(&tmp->cod);
-           /* Init Comfort Noise Functions */
-                if( UseVx ) {
-                       Init_Vad(&tmp->cod);
-               Init_Cod_Cng(&tmp->cod);
-        }
-               localusecnt++;
-               ast_update_use_count();
-               tmp->tail = 0;
+       struct g723_encoder_pvt *tmp = pvt;
+       Init_Coder(&tmp->cod);
+       /* Init Comfort Noise Functions */
+       if( UseVx ) {
+               Init_Vad(&tmp->cod);
+               Init_Cod_Cng(&tmp->cod);
        }
-       return (struct ast_translator_pvt *)tmp;
-}
-
-static struct ast_frame *g723tolin_frameout(struct ast_translator_pvt *pvt)
-{
-       struct g723_decoder_pvt *tmp = (struct g723_decoder_pvt *)pvt;
-       if (!tmp->tail)
-               return NULL;
-       /* Signed linear is no particular frame size, so just send whatever
-          we have in the buffer in one lump sum */
-       tmp->f.frametype = AST_FRAME_VOICE;
-       tmp->f.subclass = AST_FORMAT_SLINEAR;
-       tmp->f.datalen = tmp->tail * 2;
-       /* Assume 8000 Hz */
-       tmp->f.samples = tmp->tail;
-       tmp->f.mallocd = 0;
-       tmp->f.offset = AST_FRIENDLY_OFFSET;
-       tmp->f.src = __PRETTY_FUNCTION__;
-       tmp->f.data = tmp->buf;
-       /* Reset tail pointer */
-       tmp->tail = 0;
-
-#if 0
-       /* Save the frames */
-       { 
-               static int fd2 = -1;
-               if (fd2 == -1) {
-                       fd2 = open("g723.example", O_WRONLY | O_CREAT | O_TRUNC, 0644);
-               }
-               write(fd2, tmp->f.data, tmp->f.datalen);
-       }               
-#endif
-       return &tmp->f; 
+       return tmp;
 }
 
 static int g723_len(unsigned char buf)
@@ -225,19 +167,22 @@ static int g723_len(unsigned char buf)
        return -1;
 }
 
-static int g723tolin_framein(struct ast_translator_pvt *pvt, struct ast_frame *f)
+static int g723tolin_framein(struct ast_trans_pvt *pvt, struct ast_frame *f)
 {
-       struct g723_decoder_pvt *tmp = (struct g723_decoder_pvt *)pvt;
+       struct g723_decoder_pvt *tmp = pvt->pvt;
        int len = 0;
        int res;
+       int16_t *dst = pvt->outbuf;
 #ifdef  ANNEX_B
        FLOAT tmpdata[Frame];
        int x;
 #endif
+       unsigned char *src = f->data;
+
        while(len < f->datalen) {
                /* Assuming there's space left, decode into the current buffer at
                   the tail location */
-               res = g723_len(((unsigned char *)f->data + len)[0]);
+               res = g723_len(src[len]);
                if (res < 0) {
                        ast_log(LOG_WARNING, "Invalid data\n");
                        return -1;
@@ -246,145 +191,127 @@ static int g723tolin_framein(struct ast_translator_pvt *pvt, struct ast_frame *f
                        ast_log(LOG_WARNING, "Measured length exceeds frame length\n");
                        return -1;
                }
-               if (tmp->tail + Frame < sizeof(tmp->buf)/2) {   
-#ifdef ANNEX_B
-                       Decod(&tmp->dec, tmpdata, f->data + len, 0);
-                       for (x=0;x<Frame;x++)
-                               (tmp->buf + tmp->tail)[x] = (short)(tmpdata[x]); 
-#else
-                       Decod(&tmp->dec, tmp->buf + tmp->tail, f->data + len, 0);
-#endif
-                       tmp->tail+=Frame;
-               } else {
+               if (pvt->samples + Frame > BUFFER_SAMPLES) {    
                        ast_log(LOG_WARNING, "Out of buffer space\n");
                        return -1;
                }
+#ifdef ANNEX_B
+               Decod(&tmp->dec, tmpdata, f->data + len, 0);
+               for (x=0;x<Frame;x++)
+                       dst[pvt->samples + x] = (int16_t)(tmpdata[x]); 
+#else
+               Decod(&tmp->dec, dst + pvt->samples, f->data + len, 0);
+#endif
+               pvt->samples += Frame;
+               pvt->datalen += 2*Frame; /* 2 bytes/sample */
                len += res;
        }
        return 0;
 }
 
-static int lintog723_framein(struct ast_translator_pvt *pvt, struct ast_frame *f)
+static int lintog723_framein(struct ast_trans_pvt *pvt, struct ast_frame *f)
 {
        /* Just add the frames to our stream */
        /* XXX We should look at how old the rest of our stream is, and if it
           is too old, then we should overwrite it entirely, otherwise we can
           get artifacts of earlier talk that do not belong */
-       struct g723_encoder_pvt *tmp = (struct g723_encoder_pvt *)pvt;
-       if (tmp->tail + f->datalen/2 < sizeof(tmp->buf) / 2) {
-               memcpy(&tmp->buf[tmp->tail], f->data, f->datalen);
-               tmp->tail += f->datalen/2;
-       } else {
+       struct g723_encoder_pvt *tmp = pvt->pvt;
+
+       if (tmp->samples + f->samples > BUFFER_SAMPLES) {
                ast_log(LOG_WARNING, "Out of buffer space\n");
                return -1;
        }
+       memcpy(&tmp->buf[pvt->samples], f->data, f->datalen);
+       pvt->samples += f->samples;
        return 0;
 }
 
-static struct ast_frame *lintog723_frameout(struct ast_translator_pvt *pvt)
+static struct ast_frame *lintog723_frameout(void *pvt)
 {
        struct g723_encoder_pvt *tmp = (struct g723_encoder_pvt *)pvt;
+       int samples = 0;        /* how many samples in buffer */
 #ifdef ANNEX_B
        int x;
        FLOAT tmpdata[Frame];
 #endif
-       int cnt=0;
+       int cnt = 0;    /* how many bytes so far */
+
        /* We can't work on anything less than a frame in size */
-       if (tmp->tail < Frame)
+       if (pvt->samples < Frame)
                return NULL;
-       tmp->f.frametype = AST_FRAME_VOICE;
-       tmp->f.subclass = AST_FORMAT_G723_1;
-       tmp->f.offset = AST_FRIENDLY_OFFSET;
-       tmp->f.src = __PRETTY_FUNCTION__;
-       tmp->f.samples = 0;
-       tmp->f.mallocd = 0;
-       while(tmp->tail >= Frame) {
+       while (pvt->samples >= Frame) {
                /* Encode a frame of data */
-               if (cnt + 24 >= sizeof(tmp->outbuf)) {
+               /* at most 24 bytes/frame... */
+               if (cnt + 24 > pvt->buf_size) {
                        ast_log(LOG_WARNING, "Out of buffer space\n");
                        return NULL;
                }
 #ifdef ANNEX_B
-               for (x=0;x<Frame;x++)
+               for ( x = 0; x < Frame ; x++)
                        tmpdata[x] = tmp->buf[x];
-               Coder(&tmp->cod, tmpdata, tmp->outbuf + cnt);
+               Coder(&tmp->cod, tmpdata, pvt->outbuf + cnt);
 #else
-               Coder(&tmp->cod, tmp->buf, tmp->outbuf + cnt);
+               Coder(&tmp->cod, tmp->buf, pvt->outbuf + cnt);
 #endif
                /* Assume 8000 Hz */
-               tmp->f.samples += 240;
+               samples += G723_SAMPLES;
                cnt += g723_len(tmp->outbuf[cnt]);
-               tmp->tail -= Frame;
+               pvt->samples -= Frame;
                /* Move the data at the end of the buffer to the front */
-               if (tmp->tail)
-                       memmove(tmp->buf, tmp->buf + Frame, tmp->tail * 2);
+               /* XXX inefficient... */
+               if (pvt->samples)
+                       memmove(tmp->buf, tmp->buf + Frame, pvt->samples * 2);
        }
-       tmp->f.datalen = cnt;
-       tmp->f.data = tmp->outbuf;
-#if 0
-       /* Save to a g723 sample output file... */
-       { 
-               static int fd = -1;
-               int delay = htonl(30);
-               short size;
-               if (fd < 0)
-                       fd = open("trans.g723", O_WRONLY | O_CREAT | O_TRUNC, 0644);
-               if (fd < 0)
-                       ast_log(LOG_WARNING, "Unable to create demo\n");
-               write(fd, &delay, 4);
-               size = htons(tmp->f.datalen);
-               write(fd, &size, 2);
-               write(fd, tmp->f.data, tmp->f.datalen);
-       }
-#endif
-       return &tmp->f; 
+       return ast_trans_frameout(pvt, cnt, samples);
 }
 
-static void g723_destroy(struct ast_translator_pvt *pvt)
-{
-       free(pvt);
-       localusecnt--;
-       ast_update_use_count();
-}
+static struct ast_module_lock me = { .usecnt = -1 };
 
-static struct ast_translator g723tolin =
+static struct ast_translator g723tolin = {
+       .name =
 #ifdef ANNEX_B
-       { "g723tolinb", 
+       "g723btolin", 
 #else
-       { "g723tolin", 
+       "g723tolin", 
 #endif
-          AST_FORMAT_G723_1, AST_FORMAT_SLINEAR,
-          g723tolin_new,
-          g723tolin_framein,
-          g723tolin_frameout,
-          g723_destroy,
-          g723tolin_sample
-          };
-
-static struct ast_translator lintog723 =
+       .srcfmt = AST_FORMAT_G723_1,
+       .dstfmt =  AST_FORMAT_SLINEAR,
+       .newpvt = g723tolin_new,
+       .framein = g723tolin_framein,
+       .sample = g723tolin_sample,
+       .desc_size = sizeof(struct ...),
+       .lockp = &me,
+};
+
+static struct ast_translator lintog723 = {
+       .name =
 #ifdef ANNEX_B
-       { "lintog723b", 
+       "lintog723b", 
 #else
-       { "lintog723", 
+       "lintog723", 
 #endif
-          AST_FORMAT_SLINEAR, AST_FORMAT_G723_1,
-          lintog723_new,
-          lintog723_framein,
-          lintog723_frameout,
-          g723_destroy,
-          lintog723_sample
-          };
+       .srcfmt = AST_FORMAT_SLINEAR,
+       .dstfmt =  AST_FORMAT_G723_1,
+       .new = lintog723_new,
+       .framein = lintog723_framein,
+       .frameout = lintog723_frameout,
+       .destroy = g723_destroy,
+       .sample = lintog723_sample,
+       .lockp = &me,
+       .desc_size = sizeof(struct ...),
+};
+
+/*! \brief standard module glue */
 
 int unload_module(void)
 {
        int res;
-       ast_mutex_lock(&localuser_lock);
+       ast_mutex_lock(&me.lock);
        res = ast_unregister_translator(&lintog723);
-       if (!res)
-               res = ast_unregister_translator(&g723tolin);
-       if (localusecnt)
+       res |= ast_unregister_translator(&g723tolin);
+       if (me.usecnt)
                res = -1;
-       ast_mutex_unlock(&localuser_lock);
+       ast_mutex_unlock(&me.lock);
        return res;
 }
 
@@ -401,14 +328,17 @@ int load_module(void)
 
 char *description(void)
 {
-       return tdesc;
+#ifdef ANNEX_B
+       return "Annex B (floating point) G.723.1/PCM16 Codec Translator";
+#else
+       return "Annex A (fixed point) G.723.1/PCM16 Codec Translator";
+#endif
+
 }
 
 int usecount(void)
 {
-       int res;
-       OLD_STANDARD_USECOUNT(res);
-       return res;
+       return me.usecnt;
 }
 
 char *key(void)
index 6a33d85..a71651c 100644 (file)
@@ -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;x<f->datalen;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;x<samples;x++) {
-       if (tmp->next_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;
 }
index 59ce77f..d6a82f0 100644 (file)
@@ -58,40 +58,22 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #include "slin_gsm_ex.h"
 #include "gsm_slin_ex.h"
 
-AST_MUTEX_DEFINE_STATIC(localuser_lock);
-static int localusecnt=0;
+#define BUFFER_SAMPLES 8000
+#define GSM_SAMPLES    160
+#define        GSM_FRAME_LEN   33
+#define        MSGSM_FRAME_LEN 65
 
-static char *tdesc = "GSM/PCM16 (signed linear) Codec Translator";
-
-static int useplc = 0;
-
-struct ast_translator_pvt {
+struct gsm_translator_pvt {    /* both gsm2lin and lin2gsm */
        gsm gsm;
-       struct ast_frame f;
-       /* Space to build offset */
-       char offset[AST_FRIENDLY_OFFSET];
-       /* Buffer for our outgoing frame */
-       short outbuf[8000];
-       /* Enough to store a full second */
-       short buf[8000];
-       int tail;
-       plc_state_t plc;
+       int16_t buf[BUFFER_SAMPLES];    /* lin2gsm, temporary storage */
 };
 
-#define gsm_coder_pvt ast_translator_pvt
-
-static struct ast_translator_pvt *gsm_new(void)
+static void *gsm_new(struct ast_trans_pvt *pvt)
 {
-       struct gsm_coder_pvt *tmp;      
-       if ((tmp = ast_malloc(sizeof(*tmp)))) {
-               if (!(tmp->gsm = gsm_create())) {
-                       free(tmp);
-                       tmp = NULL;
-               }
-               tmp->tail = 0;
-               plc_init(&tmp->plc);
-               localusecnt++;
-       }
+       struct gsm_translator_pvt *tmp = pvt->pvt;
+       
+       if (!(tmp->gsm = gsm_create()))
+               return NULL;
        return tmp;
 }
 
@@ -117,7 +99,7 @@ static struct ast_frame *gsmtolin_sample(void)
        f.subclass = AST_FORMAT_GSM;
        f.datalen = sizeof(gsm_slin_ex);
        /* All frames are 20 ms long */
-       f.samples = 160;
+       f.samples = GSM_SAMPLES;
        f.mallocd = 0;
        f.offset = 0;
        f.src = __PRETTY_FUNCTION__;
@@ -125,189 +107,151 @@ static struct ast_frame *gsmtolin_sample(void)
        return &f;
 }
 
-static struct ast_frame *gsmtolin_frameout(struct ast_translator_pvt *tmp)
+/*! \brief decode and store in outbuf. */
+static int gsmtolin_framein(struct ast_trans_pvt *pvt, struct ast_frame *f)
 {
-       if (!tmp->tail)
-               return NULL;
-       /* Signed linear is no particular frame size, so just send whatever
-          we have in the buffer in one lump sum */
-       tmp->f.frametype = AST_FRAME_VOICE;
-       tmp->f.subclass = AST_FORMAT_SLINEAR;
-       tmp->f.datalen = tmp->tail * 2;
-       /* Assume 8000 Hz */
-       tmp->f.samples = tmp->tail;
-       tmp->f.mallocd = 0;
-       tmp->f.offset = AST_FRIENDLY_OFFSET;
-       tmp->f.src = __PRETTY_FUNCTION__;
-       tmp->f.data = tmp->buf;
-       /* Reset tail pointer */
-       tmp->tail = 0;
-
-       return &tmp->f; 
-}
-
-static int gsmtolin_framein(struct ast_translator_pvt *tmp, struct ast_frame *f)
-{
-       /* Assuming there's space left, decode into the current buffer at
-          the tail location.  Read in as many frames as there are */
+       struct gsm_translator_pvt *tmp = pvt->pvt;
        int x;
-       unsigned char data[66];
-       int msgsm=0;
-       
-       if(f->datalen == 0) { /* perform PLC with nominal framesize of 20ms/160 samples */
-             if((tmp->tail + 160) > sizeof(tmp->buf) / 2) {
-                 ast_log(LOG_WARNING, "Out of buffer space\n");
-                 return -1;
-             }
-             if(useplc) {
-                 plc_fillin(&tmp->plc, tmp->buf+tmp->tail, 160);
-                 tmp->tail += 160;
-             }
-             return 0;
-       }
-
-       if ((f->datalen % 33) && (f->datalen % 65)) {
-               ast_log(LOG_WARNING, "Huh?  A GSM frame that isn't a multiple of 33 or 65 bytes long from %s (%d)?\n", f->src, f->datalen);
-               return -1;
-       }
-       
-       if (f->datalen % 65 == 0) 
-               msgsm = 1;
-               
-       for (x=0;x<f->datalen;x+=(msgsm ? 65 : 33)) {
-               if (msgsm) {
+       int16_t *dst = (int16_t *)pvt->outbuf;
+       /* guess format from frame len. 65 for MSGSM, 33 for regular GSM */
+       int flen = (f->datalen % MSGSM_FRAME_LEN == 0) ?
+               MSGSM_FRAME_LEN : GSM_FRAME_LEN;
+
+       for (x=0; x < f->datalen; x += flen) {
+               unsigned char data[2 * GSM_FRAME_LEN];
+               char *src;
+               int len;
+               if (flen == MSGSM_FRAME_LEN) {
+                       len = 2*GSM_SAMPLES;
+                       src = data;
                        /* Translate MSGSM format to Real GSM format before feeding in */
+                       /* XXX what's the point here! we should just work
+                        * on the full format.
+                        */
                        conv65(f->data + x, data);
-                       if (tmp->tail + 320 < sizeof(tmp->buf)/2) {     
-                               if (gsm_decode(tmp->gsm, data, tmp->buf + tmp->tail)) {
-                                       ast_log(LOG_WARNING, "Invalid GSM data (1)\n");
-                                       return -1;
-                               }
-                               tmp->tail+=160;
-                               if (gsm_decode(tmp->gsm, data + 33, tmp->buf + tmp->tail)) {
-                                       ast_log(LOG_WARNING, "Invalid GSM data (2)\n");
-                                       return -1;
-                               }
-                               tmp->tail+=160;
-                       } else {
-                               ast_log(LOG_WARNING, "Out of (MS) buffer space\n");
-                               return -1;
-                       }
                } else {
-                       if (tmp->tail + 160 < sizeof(tmp->buf)/2) {     
-                               if (gsm_decode(tmp->gsm, f->data + x, tmp->buf + tmp->tail)) {
-                                       ast_log(LOG_WARNING, "Invalid GSM data\n");
-                                       return -1;
-                               }
-                               tmp->tail+=160;
-                       } else {
-                               ast_log(LOG_WARNING, "Out of buffer space\n");
+                       len = GSM_SAMPLES;
+                       src = f->data + x;
+               }
+               /* XXX maybe we don't need to check */
+               if (pvt->samples + len > BUFFER_SAMPLES) {      
+                       ast_log(LOG_WARNING, "Out of buffer space\n");
+                       return -1;
+               }
+               if (gsm_decode(tmp->gsm, src, dst + pvt->samples)) {
+                       ast_log(LOG_WARNING, "Invalid GSM data (1)\n");
+                       return -1;
+               }
+               pvt->samples += GSM_SAMPLES;
+               pvt->datalen += 2 * GSM_SAMPLES;
+               if (flen == MSGSM_FRAME_LEN) {
+                       if (gsm_decode(tmp->gsm, data + GSM_FRAME_LEN, dst + pvt->samples)) {
+                               ast_log(LOG_WARNING, "Invalid GSM data (2)\n");
                                return -1;
                        }
+                       pvt->samples += GSM_SAMPLES;
+                       pvt->datalen += 2 * GSM_SAMPLES;
                }
        }
-
-       /* just add the last 20ms frame; there must have been at least one */
-       if(useplc) plc_rx(&tmp->plc, tmp->buf+tmp->tail-160, 160);
-
        return 0;
 }
 
-static int lintogsm_framein(struct ast_translator_pvt *tmp, struct ast_frame *f)
+/*! \brief store samples into working buffer for later decode */
+static int lintogsm_framein(struct ast_trans_pvt *pvt, struct ast_frame *f)
 {
-       /* Just add the frames to our stream */
+       struct gsm_translator_pvt *tmp = pvt->pvt;
+
        /* XXX We should look at how old the rest of our stream is, and if it
           is too old, then we should overwrite it entirely, otherwise we can
           get artifacts of earlier talk that do not belong */
-       if (tmp->tail + f->datalen/2 < sizeof(tmp->buf) / 2) {
-               memcpy((tmp->buf + tmp->tail), f->data, f->datalen);
-               tmp->tail += f->datalen/2;
-       } else {
+       if (pvt->samples + f->samples > BUFFER_SAMPLES) {
                ast_log(LOG_WARNING, "Out of buffer space\n");
                return -1;
        }
+       memcpy(tmp->buf + pvt->samples, f->data, f->datalen);
+       pvt->samples += f->samples;
        return 0;
 }
 
-static struct ast_frame *lintogsm_frameout(struct ast_translator_pvt *tmp)
+/*! \brief encode and produce a frame */
+static struct ast_frame *lintogsm_frameout(struct ast_trans_pvt *pvt)
 {
-       int x=0;
+       struct gsm_translator_pvt *tmp = pvt->pvt;
+       int datalen = 0;
+       int samples = 0;
+
        /* We can't work on anything less than a frame in size */
-       if (tmp->tail < 160)
+       if (pvt->samples < GSM_SAMPLES)
                return NULL;
-       tmp->f.frametype = AST_FRAME_VOICE;
-       tmp->f.subclass = AST_FORMAT_GSM;
-       tmp->f.mallocd = 0;
-       tmp->f.offset = AST_FRIENDLY_OFFSET;
-       tmp->f.src = __PRETTY_FUNCTION__;
-       tmp->f.data = tmp->outbuf;
-       while(tmp->tail >= 160) {
-               if ((x+1) * 33 >= sizeof(tmp->outbuf)) {
-                       ast_log(LOG_WARNING, "Out of buffer space\n");
-                       break;
-               }
+       while (pvt->samples >= GSM_SAMPLES) {
                /* Encode a frame of data */
-               gsm_encode(tmp->gsm, tmp->buf, ((gsm_byte *) tmp->outbuf) + (x * 33));
-               /* Assume 8000 Hz -- 20 ms */
-               tmp->tail -= 160;
+               gsm_encode(tmp->gsm, tmp->buf, (gsm_byte *)pvt->outbuf + datalen);
+               datalen += GSM_FRAME_LEN;
+               samples += GSM_SAMPLES;
+               pvt->samples -= GSM_SAMPLES;
                /* Move the data at the end of the buffer to the front */
-               if (tmp->tail)
-                       memmove(tmp->buf, tmp->buf + 160, tmp->tail * 2);
-               x++;
+               if (pvt->samples)
+                       memmove(tmp->buf, tmp->buf + GSM_SAMPLES, pvt->samples * 2);
        }
-       tmp->f.datalen = x * 33;
-       tmp->f.samples = x * 160;
-       return &tmp->f; 
+       return ast_trans_frameout(pvt, datalen, samples);
 }
 
-static void gsm_destroy_stuff(struct ast_translator_pvt *pvt)
+static void gsm_destroy_stuff(struct ast_trans_pvt *pvt)
 {
-       if (pvt->gsm)
-               gsm_destroy(pvt->gsm);
-       free(pvt);
-       localusecnt--;
+       struct gsm_translator_pvt *tmp = pvt->pvt;
+       if (tmp->gsm)
+               gsm_destroy(tmp->gsm);
 }
 
-static struct ast_translator gsmtolin =
-       { "gsmtolin", 
-          AST_FORMAT_GSM, AST_FORMAT_SLINEAR,
-          gsm_new,
-          gsmtolin_framein,
-          gsmtolin_frameout,
-          gsm_destroy_stuff,
-          gsmtolin_sample
-          };
+static struct ast_module_lock me = { .usecnt = -1 };
+
+static struct ast_translator gsmtolin = {
+       .name = "gsmtolin", 
+       .srcfmt = AST_FORMAT_GSM,
+       .dstfmt = AST_FORMAT_SLINEAR,
+       .newpvt = gsm_new,
+       .framein = gsmtolin_framein,
+       .destroy = gsm_destroy_stuff,
+       .sample = gsmtolin_sample,
+       .lockp = &me,
+       .buffer_samples = BUFFER_SAMPLES,
+       .buf_size = BUFFER_SAMPLES * 2,
+       .desc_size = sizeof (struct gsm_translator_pvt ),
+       .plc_samples = GSM_SAMPLES,
+};
 
-static struct ast_translator lintogsm =
-       { "lintogsm", 
-          AST_FORMAT_SLINEAR, AST_FORMAT_GSM,
-          gsm_new,
-          lintogsm_framein,
-          lintogsm_frameout,
-          gsm_destroy_stuff,
-          lintogsm_sample
-          };
+static struct ast_translator lintogsm = {
+       .name = "lintogsm", 
+       .srcfmt = AST_FORMAT_SLINEAR,
+       .dstfmt = AST_FORMAT_GSM,
+       .newpvt = gsm_new,
+       .framein = lintogsm_framein,
+       .frameout = lintogsm_frameout,
+       .destroy = gsm_destroy_stuff,
+       .sample = lintogsm_sample,
+       .lockp = &me,
+       .desc_size = sizeof (struct gsm_translator_pvt ),
+       .buf_size = (BUFFER_SAMPLES * GSM_FRAME_LEN + GSM_SAMPLES - 1)/GSM_SAMPLES,
+};
 
 
 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_gsm: %susing generic PLC\n", useplc ? "" : "not ");
-                              }
-                              var = var->next;
-                       }
-               }
-               ast_config_destroy(cfg);
+       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")) {
+                      gsmtolin.useplc = ast_true(var->value) ? 1 : 0;
+                      if (option_verbose > 2)
+                              ast_verbose(VERBOSE_PREFIX_3 "codec_gsm: %susing generic PLC\n", gsmtolin.useplc ? "" : "not ");
+              }
        }
+       ast_config_destroy(cfg);
 }
 
+/*! \brief standard module glue */
 int reload(void)
 {
        parse_config();
@@ -317,13 +261,13 @@ int reload(void)
 int unload_module(void)
 {
        int res;
-       ast_mutex_lock(&localuser_lock);
+       ast_mutex_lock(&me.lock);
        res = ast_unregister_translator(&lintogsm);
        if (!res)
                res = ast_unregister_translator(&gsmtolin);
-       if (localusecnt)
+       if (me.usecnt)
                res = -1;
-       ast_mutex_unlock(&localuser_lock);
+       ast_mutex_unlock(&me.lock);
        return res;
 }
 
@@ -341,14 +285,12 @@ int load_module(void)
 
 char *description(void)
 {
-       return tdesc;
+       return "GSM/PCM16 (signed linear) Codec Translator";
 }
 
 int usecount(void)
 {
-       int res;
-       OLD_STANDARD_USECOUNT(res);
-       return res;
+       return me.usecnt;
 }
 
 char *key()
index fb042cf..35404f6 100644 (file)
@@ -54,49 +54,32 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #define ILBC_MS                        30
 /* #define ILBC_MS                     20 */
 
-AST_MUTEX_DEFINE_STATIC(localuser_lock);
-static int localusecnt=0;
+#define        ILBC_FRAME_LEN  50      /* apparently... */
+#define        ILBC_SAMPLES    240     /* 30ms at 8000 hz */
+#define        BUFFER_SAMPLES  8000
 
 static char *tdesc = "iLBC/PCM16 (signed linear) Codec Translator";
 
-struct ast_translator_pvt {
+struct ilbc_coder_pvt {
        iLBC_Enc_Inst_t enc;
        iLBC_Dec_Inst_t dec;
-       struct ast_frame f;
-       /* Space to build offset */
-       char offset[AST_FRIENDLY_OFFSET];
-       /* Buffer for our outgoing frame */
-       short outbuf[8000];
        /* Enough to store a full second */
-       short buf[8000];
-       int tail;
+       int16_t buf[BUFFER_SAMPLES];
 };
 
-#define ilbc_coder_pvt ast_translator_pvt
-
-static struct ast_translator_pvt *lintoilbc_new(void)
+static void *lintoilbc_new(struct ast_trans_pvt *pvt)
 {
-       struct ilbc_coder_pvt *tmp;
-       if ((tmp = ast_malloc(sizeof(*tmp)))) {
-               /* Shut valgrind up */
-               memset(&tmp->enc, 0, sizeof(tmp->enc));
-               initEncode(&tmp->enc, ILBC_MS);
-               tmp->tail = 0;
-               localusecnt++;
-       }
+       struct ilbc_coder_pvt *tmp = pvt->pvt;
+
+       initEncode(&tmp->enc, ILBC_MS);
        return tmp;
 }
 
-static struct ast_translator_pvt *ilbctolin_new(void)
+static void *ilbctolin_new(struct ast_trans_pvt *pvt)
 {
-       struct ilbc_coder_pvt *tmp;     
-       if ((tmp = ast_malloc(sizeof(*tmp)))) {
-               /* Shut valgrind up */
-               memset(&tmp->dec, 0, sizeof(tmp->dec));
-               initDecode(&tmp->dec, ILBC_MS, USE_ILBC_ENHANCER);
-               tmp->tail = 0;
-               localusecnt++;
-       }
+       struct ilbc_coder_pvt *tmp = pvt->pvt;
+
+       initDecode(&tmp->dec, ILBC_MS, USE_ILBC_ENHANCER);
        return tmp;
 }
 
@@ -106,7 +89,6 @@ static struct ast_frame *lintoilbc_sample(void)
        f.frametype = AST_FRAME_VOICE;
        f.subclass = AST_FORMAT_SLINEAR;
        f.datalen = sizeof(slin_ilbc_ex);
-       /* Assume 8000 Hz */
        f.samples = sizeof(slin_ilbc_ex)/2;
        f.mallocd = 0;
        f.offset = 0;
@@ -122,7 +104,7 @@ static struct ast_frame *ilbctolin_sample(void)
        f.subclass = AST_FORMAT_ILBC;
        f.datalen = sizeof(ilbc_slin_ex);
        /* All frames are 30 ms long */
-       f.samples = 240;
+       f.samples = ILBC_SAMPLES;
        f.mallocd = 0;
        f.offset = 0;
        f.src = __PRETTY_FUNCTION__;
@@ -130,161 +112,120 @@ static struct ast_frame *ilbctolin_sample(void)
        return &f;
 }
 
-static struct ast_frame *ilbctolin_frameout(struct ast_translator_pvt *tmp)
-{
-       if (!tmp->tail)
-               return NULL;
-       /* Signed linear is no particular frame size, so just send whatever
-          we have in the buffer in one lump sum */
-       tmp->f.frametype = AST_FRAME_VOICE;
-       tmp->f.subclass = AST_FORMAT_SLINEAR;
-       tmp->f.datalen = tmp->tail * 2;
-       /* Assume 8000 Hz */
-       tmp->f.samples = tmp->tail;
-       tmp->f.mallocd = 0;
-       tmp->f.offset = AST_FRIENDLY_OFFSET;
-       tmp->f.src = __PRETTY_FUNCTION__;
-       tmp->f.data = tmp->buf;
-       /* Reset tail pointer */
-       tmp->tail = 0;
-
-       return &tmp->f; 
-}
-
-static int ilbctolin_framein(struct ast_translator_pvt *tmp, struct ast_frame *f)
+/*! \brief decode a frame and store in outbuf */
+static int ilbctolin_framein(struct ast_trans_pvt *pvt, struct ast_frame *f)
 {
+       struct ilbc_coder_pvt *tmp = pvt->pvt;
+       int plc_mode = 1; /* 1 = normal data, 0 = plc */
        /* Assuming there's space left, decode into the current buffer at
           the tail location.  Read in as many frames as there are */
        int x,i;
-       float tmpf[240];
-
-       if (f->datalen == 0) { /* native PLC */
-               if (tmp->tail + 240 < sizeof(tmp->buf)/2) {     
-                       iLBC_decode(tmpf, NULL, &tmp->dec, 0);
-                       for (i=0;i<240;i++)
-                               tmp->buf[tmp->tail + i] = tmpf[i];
-                       tmp->tail+=240;
-               } else {
-                       ast_log(LOG_WARNING, "Out of buffer space\n");
-                       return -1;
-               }               
+       int16_t *dst = (int16_t *)pvt->outbuf;
+       float tmpf[ILBC_SAMPLES];
+
+       if (f->datalen == 0) { /* native PLC, set fake f->datalen and clear plc_mode */
+               f->datalen = ILBC_FRAME_LEN;
+               f->samples = ILBC_SAMPLES;
+               plc_mode = 0;   /* do native plc */
+               pvt->samples += ILBC_SAMPLES;
        }
 
-       if (f->datalen % 50) {
+       if (f->datalen % ILBC_FRAME_LEN) {
                ast_log(LOG_WARNING, "Huh?  An ilbc frame that isn't a multiple of 50 bytes long from %s (%d)?\n", f->src, f->datalen);
                return -1;
        }
        
-       for (x=0;x<f->datalen;x+=50) {
-               if (tmp->tail + 240 < sizeof(tmp->buf)/2) {     
-                       iLBC_decode(tmpf, f->data + x, &tmp->dec, 1);
-                       for (i=0;i<240;i++)
-                               tmp->buf[tmp->tail + i] = tmpf[i];
-                       tmp->tail+=240;
-               } else {
+       for (x=0; x < f->datalen ; x += ILBC_FRAME_LEN) {
+               if (pvt->samples + ILBC_SAMPLES > BUFFER_SAMPLES) {     
                        ast_log(LOG_WARNING, "Out of buffer space\n");
                        return -1;
                }               
+               iLBC_decode(tmpf, plc_mode ? f->data + x : NULL, &tmp->dec, plc_mode);
+               for ( i=0; i < ILBC_SAMPLES; i++)
+                       dst[pvt->samples + i] = tmpf[i];
+               pvt->samples += ILBC_SAMPLES;
+               pvt->datalen += 2*ILBC_SAMPLES;
        }
        return 0;
 }
 
-static int lintoilbc_framein(struct ast_translator_pvt *tmp, struct ast_frame *f)
+/*! \brief store a frame into a temporary buffer, for later decoding */
+static int lintoilbc_framein(struct ast_trans_pvt *pvt, struct ast_frame *f)
 {
+       struct ilbc_coder_pvt *tmp = pvt->pvt;
+
        /* Just add the frames to our stream */
        /* XXX We should look at how old the rest of our stream is, and if it
           is too old, then we should overwrite it entirely, otherwise we can
           get artifacts of earlier talk that do not belong */
-       if (tmp->tail + f->datalen/2 < sizeof(tmp->buf) / 2) {
-               memcpy((tmp->buf + tmp->tail), f->data, f->datalen);
-               tmp->tail += f->datalen/2;
-       } else {
-               ast_log(LOG_WARNING, "Out of buffer space\n");
-               return -1;
-       }
+       memcpy(tmp->buf + pvt->samples, f->data, f->datalen);
+       pvt->samples += f->samples;
        return 0;
 }
 
-static struct ast_frame *lintoilbc_frameout(struct ast_translator_pvt *tmp)
+/*! \brief encode the temporary buffer and generate a frame */
+static struct ast_frame *lintoilbc_frameout(struct ast_trans_pvt *pvt)
 {
-       int x=0,i;
-       float tmpf[240];
+       struct ilbc_coder_pvt *tmp = pvt->pvt;
+       int datalen = 0;
+       int samples = 0;
+
        /* We can't work on anything less than a frame in size */
-       if (tmp->tail < 240)
+       if (pvt->samples < ILBC_SAMPLES)
                return NULL;
-       tmp->f.frametype = AST_FRAME_VOICE;
-       tmp->f.subclass = AST_FORMAT_ILBC;
-       tmp->f.mallocd = 0;
-       tmp->f.offset = AST_FRIENDLY_OFFSET;
-       tmp->f.src = __PRETTY_FUNCTION__;
-       tmp->f.data = tmp->outbuf;
-       while(tmp->tail >= 240) {
-               if ((x+1) * 50 >= sizeof(tmp->outbuf)) {
-                       ast_log(LOG_WARNING, "Out of buffer space\n");
-                       break;
-               }
-               for (i=0;i<240;i++)
-                       tmpf[i] = tmp->buf[i];
+       while (pvt->samples >= ILBC_SAMPLES) {
+               float tmpf[ILBC_SAMPLES];
+               int i;
                /* Encode a frame of data */
-               iLBC_encode(((unsigned char *)(tmp->outbuf)) + (x * 50), tmpf, &tmp->enc);
-               /* Assume 8000 Hz -- 20 ms */
-               tmp->tail -= 240;
+               for ( i = 0 ; i < ILBC_SAMPLES ; i++ )
+                       tmpf[i] = tmp->buf[i];
+               iLBC_encode(pvt->outbuf + datalen, tmpf, &tmp->enc);
+               datalen += ILBC_FRAME_LEN;
+               samples += ILBC_SAMPLES;
+               pvt->samples -= ILBC_SAMPLES;
                /* Move the data at the end of the buffer to the front */
-               if (tmp->tail)
-                       memmove(tmp->buf, tmp->buf + 240, tmp->tail * 2);
-               x++;
-       }
-       tmp->f.datalen = x * 50;
-       tmp->f.samples = x * 240;
-#if 0
-       {
-               static int fd = -1;
-               if (fd == -1) {
-                       fd = open("ilbc.out", O_CREAT|O_TRUNC|O_WRONLY, 0666);
-                       write(fd, tmp->f.data, tmp->f.datalen);
-                       close(fd);
-               }
+               if (pvt->samples)
+                       memmove(tmp->buf, tmp->buf + ILBC_SAMPLES, pvt->samples * 2);
        }
-#endif 
-       return &tmp->f; 
+       return ast_trans_frameout(pvt, datalen, samples);
 }
 
-static void ilbc_destroy_stuff(struct ast_translator_pvt *pvt)
-{
-       free(pvt);
-       localusecnt--;
-}
+static struct ast_module_lock me = { .usecnt = -1 };
 
-static struct ast_translator ilbctolin =
-       { "ilbctolin", 
-          AST_FORMAT_ILBC, AST_FORMAT_SLINEAR,
-          ilbctolin_new,
-          ilbctolin_framein,
-          ilbctolin_frameout,
-          ilbc_destroy_stuff,
-          ilbctolin_sample
-          };
-
-static struct ast_translator lintoilbc =
-       { "lintoilbc", 
-          AST_FORMAT_SLINEAR, AST_FORMAT_ILBC,
-          lintoilbc_new,
-          lintoilbc_framein,
-          lintoilbc_frameout,
-          ilbc_destroy_stuff,
-          lintoilbc_sample
-          };
+static struct ast_translator ilbctolin = {
+       .name = "ilbctolin", 
+       .srcfmt = AST_FORMAT_ILBC,
+       .dstfmt = AST_FORMAT_SLINEAR,
+       .newpvt = ilbctolin_new,
+       .framein = ilbctolin_framein,
+       .sample = ilbctolin_sample,
+       .desc_size = sizeof(struct ilbc_coder_pvt),
+       .buf_size = BUFFER_SAMPLES * 2,
+       .lockp = &me,
+};
+
+static struct ast_translator lintoilbc = {
+       .name = "lintoilbc", 
+       .srcfmt = AST_FORMAT_SLINEAR,
+       .dstfmt = AST_FORMAT_ILBC,
+       .newpvt = lintoilbc_new,
+       .framein = lintoilbc_framein,
+       .frameout = lintoilbc_frameout,
+       .sample = lintoilbc_sample,
+       .desc_size = sizeof(struct ilbc_coder_pvt),
+       .buf_size = (BUFFER_SAMPLES * ILBC_FRAME_LEN + ILBC_SAMPLES - 1) / ILBC_SAMPLES,
+       .lockp = &me,
+};
 
 int unload_module(void)
 {
        int res;
-       ast_mutex_lock(&localuser_lock);
+       ast_mutex_lock(&me.lock);
        res = ast_unregister_translator(&lintoilbc);
-       if (!res)
-               res = ast_unregister_translator(&ilbctolin);
-       if (localusecnt)
+       res |= ast_unregister_translator(&ilbctolin);
+       if (me.usecnt)
                res = -1;
-       ast_mutex_unlock(&localuser_lock);
+       ast_mutex_unlock(&me.lock);
        return res;
 }
 
@@ -306,9 +247,7 @@ char *description(void)
 
 int usecount(void)
 {
-       int res;
-       OLD_STANDARD_USECOUNT(res);
-       return res;
+       return me.usecnt;
 }
 
 char *key()
index f9157cd..c280069 100644 (file)
@@ -60,62 +60,36 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #define LPC10_BYTES_IN_COMPRESSED_FRAME (LPC10_BITS_IN_COMPRESSED_FRAME + 7)/8
 
-AST_MUTEX_DEFINE_STATIC(localuser_lock);
-static int localusecnt=0;
+#define        BUFFER_SAMPLES  8000
 
-static char *tdesc = "LPC10 2.4kbps (signed linear) Voice Coder";
-
-static int useplc = 0;
-
-struct ast_translator_pvt {
+struct lpc10_coder_pvt {
        union {
                struct lpc10_encoder_state *enc;
                struct lpc10_decoder_state *dec;
        } lpc10;
-       struct ast_frame f;
-       /* Space to build offset */
-       char offset[AST_FRIENDLY_OFFSET];
-       /* Buffer for our outgoing frame */
-       short outbuf[8000];
        /* Enough to store a full second */
-       short buf[8000];
-       int tail;
+       short buf[BUFFER_SAMPLES];
        int longer;
-       plc_state_t plc; /* god only knows why I bothered to implement PLC for LPC10 :) */
 };
 
-#define lpc10_coder_pvt ast_translator_pvt
-
-static struct ast_translator_pvt *lpc10_enc_new(void)
+static void *lpc10_enc_new(struct ast_trans_pvt *pvt)
 {
-       struct lpc10_coder_pvt *tmp;    
-       if ((tmp = ast_malloc(sizeof(*tmp)))) {
-               if (!(tmp->lpc10.enc = create_lpc10_encoder_state())) {
-                       free(tmp);
-                       tmp = NULL;
-               }
-               tmp->tail = 0;
-               tmp->longer = 0;
-               localusecnt++;
-       }
+       struct lpc10_coder_pvt *tmp = pvt->pvt;
+
+       if (!(tmp->lpc10.enc = create_lpc10_encoder_state()))
+               return NULL;
        return tmp;
 }
 
-static struct ast_translator_pvt *lpc10_dec_new(void)
+static void *lpc10_dec_new(struct ast_trans_pvt *pvt)
 {
-       struct lpc10_coder_pvt *tmp;    
-       if ((tmp = ast_malloc(sizeof(*tmp)))) {
-               if (!(tmp->lpc10.dec = create_lpc10_decoder_state())) {
-                       free(tmp);
-                       tmp = NULL;
-               }
-               tmp->tail = 0;
-               tmp->longer = 0;
-               plc_init(&tmp->plc);
-               localusecnt++;
-       }
+       struct lpc10_coder_pvt *tmp = pvt->pvt;
+
+       if (!(tmp->lpc10.dec = create_lpc10_decoder_state()))
+               return NULL;
        return tmp;
 }
+
 static struct ast_frame *lintolpc10_sample(void)
 {
        static struct ast_frame f;
@@ -147,39 +121,6 @@ static struct ast_frame *lpc10tolin_sample(void)
        return &f;
 }
 
-static struct ast_frame *lpc10tolin_frameout(struct ast_translator_pvt *tmp)
-{
-       if (!tmp->tail)
-               return NULL;
-       /* Signed linear is no particular frame size, so just send whatever
-          we have in the buffer in one lump sum */
-       tmp->f.frametype = AST_FRAME_VOICE;
-       tmp->f.subclass = AST_FORMAT_SLINEAR;
-       tmp->f.datalen = tmp->tail * 2;
-       /* Assume 8000 Hz */
-       tmp->f.samples = tmp->tail;
-       tmp->f.mallocd = 0;
-       tmp->f.offset = AST_FRIENDLY_OFFSET;
-       tmp->f.src = __PRETTY_FUNCTION__;
-       tmp->f.data = tmp->buf;
-       /* Reset tail pointer */
-       tmp->tail = 0;
-
-#if 0
-       /* Save a sample frame */
-       { static int samplefr = 0;
-       if (samplefr == 80) {
-               int fd;
-               fd = open("lpc10.example", O_WRONLY | O_CREAT, 0644);
-               write(fd, tmp->f.data, tmp->f.datalen);
-               close(fd);
-       }               
-       samplefr++;
-       }
-#endif
-       return &tmp->f; 
-}
-
 static void extract_bits(INT32 *bits, unsigned char *c)
 {
        int x;
@@ -193,6 +134,7 @@ static void extract_bits(INT32 *bits, unsigned char *c)
        }
 }
 
+/* XXX note lpc10_encode() produces one bit per word in bits[] */
 static void build_bits(unsigned char *c, INT32 *bits)
 {
        unsigned char mask=0x80;
@@ -210,48 +152,32 @@ static void build_bits(unsigned char *c, INT32 *bits)
        }
 }
 
-static int lpc10tolin_framein(struct ast_translator_pvt *tmp, struct ast_frame *f)
+static int lpc10tolin_framein(struct ast_trans_pvt *pvt, struct ast_frame *f)
 {
-       /* Assuming there's space left, decode into the current buffer at
-          the tail location */
-       int x;
-       int len=0;
-       float tmpbuf[LPC10_SAMPLES_PER_FRAME];
-       short *sd;
-       INT32 bits[LPC10_BITS_IN_COMPRESSED_FRAME];
-
-       if(f->datalen == 0) { /* perform PLC with nominal framesize of LPC10_SAMPLES_PER_FRAME */
-             if((tmp->tail + LPC10_SAMPLES_PER_FRAME) > sizeof(tmp->buf)/2) {
-                 ast_log(LOG_WARNING, "Out of buffer space\n");
-                 return -1;
-             }
-             if(useplc) {
-                 plc_fillin(&tmp->plc, tmp->buf+tmp->tail, LPC10_SAMPLES_PER_FRAME);
-                 tmp->tail += LPC10_SAMPLES_PER_FRAME;
-             }
-             return 0;
-       }
-
-       while(len + LPC10_BYTES_IN_COMPRESSED_FRAME <= f->datalen) {
-               if (tmp->tail + LPC10_SAMPLES_PER_FRAME < sizeof(tmp->buf)/2) {
-                       sd = tmp->buf + tmp->tail;
-                       extract_bits(bits, f->data + len);
-                       if (lpc10_decode(bits, tmpbuf, tmp->lpc10.dec)) {
-                               ast_log(LOG_WARNING, "Invalid lpc10 data\n");
-                               return -1;
-                       }
-                       for (x=0;x<LPC10_SAMPLES_PER_FRAME;x++) {
-                               /* Convert to a real between -1.0 and 1.0 */
-                               sd[x] = 32768.0 * tmpbuf[x];
-                       }
-
-                       if(useplc) plc_rx(&tmp->plc, tmp->buf + tmp->tail, LPC10_SAMPLES_PER_FRAME);
-                       
-                       tmp->tail+=LPC10_SAMPLES_PER_FRAME;
-               } else {
+       struct lpc10_coder_pvt *tmp = pvt->pvt;
+       int16_t *dst = (int16_t *)pvt->outbuf;
+       int len = 0;
+
+       while (len + LPC10_BYTES_IN_COMPRESSED_FRAME <= f->datalen) {
+               int x;
+               float tmpbuf[LPC10_SAMPLES_PER_FRAME];
+               INT32 bits[LPC10_BITS_IN_COMPRESSED_FRAME]; /* XXX see note */
+               if (pvt->samples + LPC10_SAMPLES_PER_FRAME > BUFFER_SAMPLES) {
                        ast_log(LOG_WARNING, "Out of buffer space\n");
                        return -1;
                }
+               extract_bits(bits, f->data + len);
+               if (lpc10_decode(bits, tmpbuf, tmp->lpc10.dec)) {
+                       ast_log(LOG_WARNING, "Invalid lpc10 data\n");
+                       return -1;
+               }
+               for (x=0;x<LPC10_SAMPLES_PER_FRAME;x++) {
+                       /* Convert to a short between -1.0 and 1.0 */
+                       dst[pvt->samples + x] = (int16_t)(32768.0 * tmpbuf[x]);
+               }
+
+               pvt->samples += LPC10_SAMPLES_PER_FRAME;
+               pvt->datalen += 2*LPC10_SAMPLES_PER_FRAME;
                len += LPC10_BYTES_IN_COMPRESSED_FRAME;
        }
        if (len != f->datalen) 
@@ -259,125 +185,108 @@ static int lpc10tolin_framein(struct ast_translator_pvt *tmp, struct ast_frame *
        return 0;
 }
 
-static int lintolpc10_framein(struct ast_translator_pvt *tmp, struct ast_frame *f)
+static int lintolpc10_framein(struct ast_trans_pvt *pvt, struct ast_frame *f)
 {
+       struct lpc10_coder_pvt *tmp = pvt->pvt;
+
        /* Just add the frames to our stream */
-       /* XXX We should look at how old the rest of our stream is, and if it
-          is too old, then we should overwrite it entirely, otherwise we can
-          get artifacts of earlier talk that do not belong */
-       if (tmp->tail + f->datalen < sizeof(tmp->buf) / 2) {
-               memcpy((tmp->buf + tmp->tail), f->data, f->datalen);
-               tmp->tail += f->datalen/2;
-       } else {
+       if (pvt->samples + f->samples > BUFFER_SAMPLES) {
                ast_log(LOG_WARNING, "Out of buffer space\n");
                return -1;
        }
+       memcpy(tmp->buf + pvt->samples, f->data, f->datalen);
+       pvt->samples += f->samples;
        return 0;
 }
 
-static struct ast_frame *lintolpc10_frameout(struct ast_translator_pvt *tmp)
+static struct ast_frame *lintolpc10_frameout(struct ast_trans_pvt *pvt)
 {
+       struct lpc10_coder_pvt *tmp = pvt->pvt;
        int x;
-       int consumed = 0;
+       int datalen = 0;        /* output frame */
+       int samples = 0;        /* output samples */
        float tmpbuf[LPC10_SAMPLES_PER_FRAME];
-       INT32 bits[LPC10_BITS_IN_COMPRESSED_FRAME];
+       INT32 bits[LPC10_BITS_IN_COMPRESSED_FRAME];     /* XXX what ??? */
        /* We can't work on anything less than a frame in size */
-       if (tmp->tail < LPC10_SAMPLES_PER_FRAME)
+       if (pvt->samples < LPC10_SAMPLES_PER_FRAME)
                return NULL;
-       /* Start with an empty frame */
-       tmp->f.samples = 0;
-       tmp->f.datalen = 0;
-       tmp->f.frametype = AST_FRAME_VOICE;
-       tmp->f.subclass = AST_FORMAT_LPC10;
-       while(tmp->tail >=  LPC10_SAMPLES_PER_FRAME) {
-               if (tmp->f.datalen + LPC10_BYTES_IN_COMPRESSED_FRAME > sizeof(tmp->outbuf)) {
-                       ast_log(LOG_WARNING, "Out of buffer space\n");
-                       return NULL;
-               }
+       while (pvt->samples >=  LPC10_SAMPLES_PER_FRAME) {
                /* Encode a frame of data */
-               for (x=0;x<LPC10_SAMPLES_PER_FRAME;x++) {
-                       tmpbuf[x] = (float)tmp->buf[x+consumed] / 32768.0;
-               }
+               for (x=0;x<LPC10_SAMPLES_PER_FRAME;x++)
+                       tmpbuf[x] = (float)tmp->buf[x + samples] / 32768.0;
                lpc10_encode(tmpbuf, bits, tmp->lpc10.enc);
-               build_bits(((unsigned char *)tmp->outbuf) + tmp->f.datalen, bits);
-               tmp->f.datalen += LPC10_BYTES_IN_COMPRESSED_FRAME;
-               tmp->f.samples += LPC10_SAMPLES_PER_FRAME;
+               build_bits(pvt->outbuf + datalen, bits);
+               datalen += LPC10_BYTES_IN_COMPRESSED_FRAME;
+               samples += LPC10_SAMPLES_PER_FRAME;
+               pvt->samples -= LPC10_SAMPLES_PER_FRAME;
                /* Use one of the two left over bits to record if this is a 22 or 23 ms frame...
                   important for IAX use */
                tmp->longer = 1 - tmp->longer;
 #if 0  /* what the heck was this for? */
                ((char *)(tmp->f.data))[consumed - 1] |= tmp->longer;
 #endif         
-               tmp->tail -= LPC10_SAMPLES_PER_FRAME;
-               consumed += LPC10_SAMPLES_PER_FRAME;
        }
-       tmp->f.mallocd = 0;
-       tmp->f.offset = AST_FRIENDLY_OFFSET;
-       tmp->f.src = __PRETTY_FUNCTION__;
-       tmp->f.data = tmp->outbuf;
        /* Move the data at the end of the buffer to the front */
-       if (tmp->tail)
-               memmove(tmp->buf, tmp->buf + consumed, tmp->tail * 2);
-#if 0
-       /* Save a sample frame */
-       { static int samplefr = 0;
-       if (samplefr == 0) {
-               int fd;
-               fd = open("lpc10.example", O_WRONLY | O_CREAT, 0644);
-               write(fd, tmp->f.data, tmp->f.datalen);
-               close(fd);
-       }               
-       samplefr++;
-       }
-#endif
-       return &tmp->f; 
+       if (pvt->samples)
+               memmove(tmp->buf, tmp->buf + samples, pvt->samples * 2);
+       return ast_trans_frameout(pvt, datalen, samples);
 }
 
-static void lpc10_destroy(struct ast_translator_pvt *pvt)
+
+static void lpc10_destroy(struct ast_trans_pvt *arg)
 {
+       struct lpc10_coder_pvt *pvt = arg->pvt;
        /* Enc and DEC are both just allocated, so they can be freed */
        free(pvt->lpc10.enc);
-       free(pvt);
-       localusecnt--;
 }
 
-static struct ast_translator lpc10tolin =
-       { "lpc10tolin", 
-          AST_FORMAT_LPC10, AST_FORMAT_SLINEAR,
-          lpc10_dec_new,
-          lpc10tolin_framein,
-          lpc10tolin_frameout,
-          lpc10_destroy,
-          lpc10tolin_sample
-          };
-
-static struct ast_translator lintolpc10 =
-       { "lintolpc10", 
-          AST_FORMAT_SLINEAR, AST_FORMAT_LPC10,
-          lpc10_enc_new,
-          lintolpc10_framein,
-          lintolpc10_frameout,
-          lpc10_destroy,
-          lintolpc10_sample
-          };
+static struct ast_module_lock me = { .usecnt = -1 };
+
+static struct ast_translator lpc10tolin = {
+       .name = "lpc10tolin", 
+       .srcfmt = AST_FORMAT_LPC10,
+       .dstfmt = AST_FORMAT_SLINEAR,
+       .newpvt = lpc10_dec_new,
+       .framein = lpc10tolin_framein,
+       .destroy = lpc10_destroy,
+       .sample = lpc10tolin_sample,
+       .lockp = &me,
+       .desc_size = sizeof(struct lpc10_coder_pvt),
+       .buffer_samples = BUFFER_SAMPLES,
+       .plc_samples = LPC10_SAMPLES_PER_FRAME,
+       .buf_size = BUFFER_SAMPLES * 2,
+};
+
+static struct ast_translator lintolpc10 = {
+       .name = "lintolpc10", 
+       .srcfmt = AST_FORMAT_SLINEAR,
+       .dstfmt = AST_FORMAT_LPC10,
+       .newpvt = lpc10_enc_new,
+       .framein = lintolpc10_framein,
+       .frameout = lintolpc10_frameout,
+       .destroy = lpc10_destroy,
+       .sample = lintolpc10_sample,
+       .lockp = &me,
+       .desc_size = sizeof(struct lpc10_coder_pvt),
+       .buffer_samples = BUFFER_SAMPLES,
+       .buf_size = LPC10_BYTES_IN_COMPRESSED_FRAME * (1 + BUFFER_SAMPLES / LPC10_SAMPLES_PER_FRAME),
+};
 
 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_lpc10: %susing generic PLC\n", useplc ? "" : "not ");
-                               }
-                               var = var->next;
-                        }
-                }
-               ast_config_destroy(cfg);
+        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")) {
+                       lpc10tolin.useplc = ast_true(var->value) ? 1 : 0;
+                       if (option_verbose > 2)
+                              ast_verbose(VERBOSE_PREFIX_3 "codec_lpc10: %susing generic PLC\n",
+                                       lpc10tolin.useplc ? "" : "not ");
+               }
         }
+       ast_config_destroy(cfg);
 }
 
 int reload(void)
@@ -390,13 +299,13 @@ int reload(void)
 int unload_module(void)
 {
        int res;
-       ast_mutex_lock(&localuser_lock);
+       ast_mutex_lock(&me.lock);
        res = ast_unregister_translator(&lintolpc10);
        if (!res)
                res = ast_unregister_translator(&lpc10tolin);
-       if (localusecnt)
+       if (me.usecnt)
                res = -1;
-       ast_mutex_unlock(&localuser_lock);
+       ast_mutex_unlock(&me.lock);
        return res;
 }
 
@@ -414,14 +323,12 @@ int load_module(void)
 
 char *description(void)
 {
-       return tdesc;
+       return "LPC10 2.4kbps (signed linear) Voice Coder";
 }
 
 int usecount(void)
 {
-       int res;
-       OLD_STANDARD_USECOUNT(res);
-       return res;
+       return me.usecnt;
 }
 
 char *key()
index fc9b22b..daaf5ed 100644 (file)
@@ -41,6 +41,7 @@
 #include <speex/speex_preprocess.h>
 #endif
 
+/* codec variables */
 static int quality = 3;
 static int complexity = 2;
 static int enhancement = 0;
@@ -48,12 +49,12 @@ static int vad = 0;
 static int vbr = 0;
 static float vbr_quality = 4;
 static int abr = 0;
-static int dtx = 0;
+static int dtx = 0;    /* set to 1 to enable silence detection */
 
 static int preproc = 0;
 static int pp_vad = 0;
 static int pp_agc = 0;
-static float pp_agc_level = 8000;
+static float pp_agc_level = 8000; /* XXX what is this 8000 ? */
 static int pp_denoise = 0;
 static int pp_dereverb = 0;
 static float pp_dereverb_decay = 0.4;
@@ -81,97 +82,75 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #include "slin_speex_ex.h"
 #include "speex_slin_ex.h"
 
-AST_MUTEX_DEFINE_STATIC(localuser_lock);
-static int localusecnt=0;
+#define        BUFFER_SAMPLES  8000
+#define        SPEEX_SAMPLES   160
 
-static char *tdesc = "Speex/PCM16 (signed linear) Codec Translator";
-
-struct ast_translator_pvt {
+struct speex_coder_pvt {
        void *speex;
-       struct ast_frame f;
        SpeexBits bits;
        int framesize;
-       /* Space to build offset */
-       char offset[AST_FRIENDLY_OFFSET];
+       int silent_state;
 #ifdef _SPEEX_TYPES_H
        SpeexPreprocessState *pp;
-       /* Buffer for our outgoing frame */
-       spx_int16_t outbuf[8000];
-       /* Enough to store a full second */
-       spx_int16_t buf[8000];
+       spx_int16_t buf[BUFFER_SAMPLES];
 #else
-       short outbuf[8000];
-       short buf[8000];
+       int16_t buf[BUFFER_SAMPLES];    /* input, waiting to be compressed */
 #endif
-
-       int tail;
-       int silent_state;
 };
 
-#define speex_coder_pvt ast_translator_pvt
 
-static struct ast_translator_pvt *lintospeex_new(void)
+static void *lintospeex_new(struct ast_trans_pvt *pvt)
 {
-       struct speex_coder_pvt *tmp;    
-       if ((tmp = ast_malloc(sizeof(*tmp)))) {
-               if (!(tmp->speex = speex_encoder_init(&speex_nb_mode))) {
-                       free(tmp);
-                       tmp = NULL;
-               } else {
-                       speex_bits_init(&tmp->bits);
-                       speex_bits_reset(&tmp->bits);
-                       speex_encoder_ctl(tmp->speex, SPEEX_GET_FRAME_SIZE, &tmp->framesize);
-                       speex_encoder_ctl(tmp->speex, SPEEX_SET_COMPLEXITY, &complexity);
+       struct speex_coder_pvt *tmp = pvt->pvt;
+
+       if (!(tmp->speex = speex_encoder_init(&speex_nb_mode)))
+               return NULL;
+
+       speex_bits_init(&tmp->bits);
+       speex_bits_reset(&tmp->bits);
+       speex_encoder_ctl(tmp->speex, SPEEX_GET_FRAME_SIZE, &tmp->framesize);
+       ast_log(LOG_WARNING, "speex framesize is %d\n", tmp->framesize);
+       speex_encoder_ctl(tmp->speex, SPEEX_SET_COMPLEXITY, &complexity);
 #ifdef _SPEEX_TYPES_H
-                       if (preproc) {
-                               tmp->pp = speex_preprocess_state_init(tmp->framesize, 8000);
-                               speex_preprocess_ctl(tmp->pp, SPEEX_PREPROCESS_SET_VAD, &pp_vad);
-                               speex_preprocess_ctl(tmp->pp, SPEEX_PREPROCESS_SET_AGC, &pp_agc);
-                               speex_preprocess_ctl(tmp->pp, SPEEX_PREPROCESS_SET_AGC_LEVEL, &pp_agc_level);
-                               speex_preprocess_ctl(tmp->pp, SPEEX_PREPROCESS_SET_DENOISE, &pp_denoise);
-                               speex_preprocess_ctl(tmp->pp, SPEEX_PREPROCESS_SET_DEREVERB, &pp_dereverb);
-                               speex_preprocess_ctl(tmp->pp, SPEEX_PREPROCESS_SET_DEREVERB_DECAY, &pp_dereverb_decay);
-                               speex_preprocess_ctl(tmp->pp, SPEEX_PREPROCESS_SET_DEREVERB_LEVEL, &pp_dereverb_level);
-                       }
+       if (preproc) {
+               tmp->pp = speex_preprocess_state_init(tmp->framesize, 8000); /* XXX what is this 8000 ? */
+               speex_preprocess_ctl(tmp->pp, SPEEX_PREPROCESS_SET_VAD, &pp_vad);
+               speex_preprocess_ctl(tmp->pp, SPEEX_PREPROCESS_SET_AGC, &pp_agc);
+               speex_preprocess_ctl(tmp->pp, SPEEX_PREPROCESS_SET_AGC_LEVEL, &pp_agc_level);
+               speex_preprocess_ctl(tmp->pp, SPEEX_PREPROCESS_SET_DENOISE, &pp_denoise);
+               speex_preprocess_ctl(tmp->pp, SPEEX_PREPROCESS_SET_DEREVERB, &pp_dereverb);
+               speex_preprocess_ctl(tmp->pp, SPEEX_PREPROCESS_SET_DEREVERB_DECAY, &pp_dereverb_decay);
+               speex_preprocess_ctl(tmp->pp, SPEEX_PREPROCESS_SET_DEREVERB_LEVEL, &pp_dereverb_level);
+       }
 #endif
-                       if (!abr && !vbr) {
-                               speex_encoder_ctl(tmp->speex, SPEEX_SET_QUALITY, &quality);
-                               if (vad)
-                                       speex_encoder_ctl(tmp->speex, SPEEX_SET_VAD, &vad);
-                       }
-                       if (vbr) {
-                               speex_encoder_ctl(tmp->speex, SPEEX_SET_VBR, &vbr);
-                               speex_encoder_ctl(tmp->speex, SPEEX_SET_VBR_QUALITY, &vbr_quality);
-                       }
-                       if (abr) {
-                               speex_encoder_ctl(tmp->speex, SPEEX_SET_ABR, &abr);
-                       }
-                       if (dtx)
-                               speex_encoder_ctl(tmp->speex, SPEEX_SET_DTX, &dtx); 
-                       tmp->tail = 0;
-                       tmp->silent_state = 0;
-               }
-               localusecnt++;
+       if (!abr && !vbr) {
+               speex_encoder_ctl(tmp->speex, SPEEX_SET_QUALITY, &quality);
+               if (vad)
+                       speex_encoder_ctl(tmp->speex, SPEEX_SET_VAD, &vad);
        }
+       if (vbr) {
+               speex_encoder_ctl(tmp->speex, SPEEX_SET_VBR, &vbr);
+               speex_encoder_ctl(tmp->speex, SPEEX_SET_VBR_QUALITY, &vbr_quality);
+       }
+       if (abr)
+               speex_encoder_ctl(tmp->speex, SPEEX_SET_ABR, &abr);
+       if (dtx)
+               speex_encoder_ctl(tmp->speex, SPEEX_SET_DTX, &dtx); 
+       tmp->silent_state = 0;
+
        return tmp;
 }
 
-static struct ast_translator_pvt *speextolin_new(void)
+static void *speextolin_new(struct ast_trans_pvt *pvt)
 {
-       struct speex_coder_pvt *tmp;    
-       if ((tmp = ast_malloc(sizeof(*tmp)))) {
-               if (!(tmp->speex = speex_decoder_init(&speex_nb_mode))) {
-                       free(tmp);
-                       tmp = NULL;
-               } else {
-                       speex_bits_init(&tmp->bits);
-                       speex_decoder_ctl(tmp->speex, SPEEX_GET_FRAME_SIZE, &tmp->framesize);
-                       if (enhancement)
-                               speex_decoder_ctl(tmp->speex, SPEEX_SET_ENH, &enhancement);
-                       tmp->tail = 0;
-               }
-               localusecnt++;
-       }
+       struct speex_coder_pvt *tmp = pvt->pvt;
+       
+       if (!(tmp->speex = speex_decoder_init(&speex_nb_mode)))
+               return NULL;
+       speex_bits_init(&tmp->bits);
+       speex_decoder_ctl(tmp->speex, SPEEX_GET_FRAME_SIZE, &tmp->framesize);
+       if (enhancement)
+               speex_decoder_ctl(tmp->speex, SPEEX_SET_ENH, &enhancement);
        return tmp;
 }
 
@@ -197,7 +176,7 @@ static struct ast_frame *speextolin_sample(void)
        f.subclass = AST_FORMAT_SPEEX;
        f.datalen = sizeof(speex_slin_ex);
        /* All frames are 20 ms long */
-       f.samples = 160;
+       f.samples = SPEEX_SAMPLES;
        f.mallocd = 0;
        f.offset = 0;
        f.src = __PRETTY_FUNCTION__;
@@ -205,122 +184,91 @@ static struct ast_frame *speextolin_sample(void)
        return &f;
 }
 
-static struct ast_frame *speextolin_frameout(struct ast_translator_pvt *tmp)
+/*! \brief convert and store into outbuf */
+static int speextolin_framein(struct ast_trans_pvt *pvt, struct ast_frame *f)
 {
-       if (!tmp->tail)
-               return NULL;
-       /* Signed linear is no particular frame size, so just send whatever
-          we have in the buffer in one lump sum */
-       tmp->f.frametype = AST_FRAME_VOICE;
-       tmp->f.subclass = AST_FORMAT_SLINEAR;
-       tmp->f.datalen = tmp->tail * 2;
-       /* Assume 8000 Hz */
-       tmp->f.samples = tmp->tail;
-       tmp->f.mallocd = 0;
-       tmp->f.offset = AST_FRIENDLY_OFFSET;
-       tmp->f.src = __PRETTY_FUNCTION__;
-       tmp->f.data = tmp->buf;
-       /* Reset tail pointer */
-       tmp->tail = 0;
-       return &tmp->f; 
-}
+       struct speex_coder_pvt *tmp = pvt->pvt;
 
-static int speextolin_framein(struct ast_translator_pvt *tmp, struct ast_frame *f)
-{
        /* Assuming there's space left, decode into the current buffer at
           the tail location.  Read in as many frames as there are */
        int x;
        int res;
+       int16_t *dst = (int16_t *)pvt->outbuf;
+       /* XXX fout is a temporary buffer, may have different types */
 #ifdef _SPEEX_TYPES_H
-       spx_int16_t out[1024];
+       spx_int16_t fout[1024];
 #else
        float fout[1024];
 #endif
 
        if (f->datalen == 0) {  /* Native PLC interpolation */
-               if (tmp->tail + tmp->framesize > sizeof(tmp->buf) / 2) {
+               if (pvt->samples + tmp->framesize > BUFFER_SAMPLES) {
                        ast_log(LOG_WARNING, "Out of buffer space\n");
                        return -1;
                }
 #ifdef _SPEEX_TYPES_H
-               speex_decode_int(tmp->speex, NULL, tmp->buf + tmp->tail);
+               speex_decode_int(tmp->speex, NULL, dst + pvt->samples);
 #else
                speex_decode(tmp->speex, NULL, fout);
                for (x=0;x<tmp->framesize;x++) {
-                       tmp->buf[tmp->tail + x] = fout[x];
+                       dst[pvt->samples + x] = (int16_t)fout[x];
                }
 #endif
-               tmp->tail += tmp->framesize;
+               pvt->samples += tmp->framesize;
                return 0;
        }
 
        /* Read in bits */
        speex_bits_read_from(&tmp->bits, f->data, f->datalen);
-       for(;;) {
+       for (;;) {
 #ifdef _SPEEX_TYPES_H
-               res = speex_decode_int(tmp->speex, &tmp->bits, out);
+               res = speex_decode_int(tmp->speex, &tmp->bits, fout);
 #else
                res = speex_decode(tmp->speex, &tmp->bits, fout);
 #endif
                if (res < 0)
                        break;
-               if (tmp->tail + tmp->framesize < sizeof(tmp->buf) / 2) {
-                       for (x=0;x<tmp->framesize;x++) {
-#ifdef _SPEEX_TYPES_H
-                               tmp->buf[tmp->tail + x] = out[x];
-#else
-                               tmp->buf[tmp->tail + x] = fout[x];
-#endif
-                       }
-                       tmp->tail += tmp->framesize;
-               } else {
+               if (pvt->samples + tmp->framesize > BUFFER_SAMPLES) {
                        ast_log(LOG_WARNING, "Out of buffer space\n");
                        return -1;
                }
-               
+               for (x = 0 ; x < tmp->framesize; x++)
+                       dst[pvt->samples + x] = (int16_t)fout[x];
+               pvt->samples += tmp->framesize;
+               pvt->datalen += 2 * tmp->framesize; /* 2 bytes/sample */
        }
        return 0;
 }
 
-static int lintospeex_framein(struct ast_translator_pvt *tmp, struct ast_frame *f)
+/*! \brief store input frame in work buffer */
+static int lintospeex_framein(struct ast_trans_pvt *pvt, struct ast_frame *f)
 {
-       /* Just add the frames to our stream */
+       struct speex_coder_pvt *tmp = pvt->pvt;
+
        /* XXX We should look at how old the rest of our stream is, and if it
           is too old, then we should overwrite it entirely, otherwise we can
           get artifacts of earlier talk that do not belong */
-       if (tmp->tail + f->datalen/2 < sizeof(tmp->buf) / 2) {
-               memcpy((tmp->buf + tmp->tail), f->data, f->datalen);
-               tmp->tail += f->datalen/2;
-       } else {
-               ast_log(LOG_WARNING, "Out of buffer space\n");
-               return -1;
-       }
+       memcpy(tmp->buf + pvt->samples, f->data, f->datalen);
+       pvt->samples += f->samples;
        return 0;
 }
 
-static struct ast_frame *lintospeex_frameout(struct ast_translator_pvt *tmp)
+/*! \brief convert work buffer and produce output frame */
+static struct ast_frame *lintospeex_frameout(struct ast_trans_pvt *pvt)
 {
-#ifndef _SPEEX_TYPES_H
-       float fbuf[1024];
-       int x;
-#endif
-       int len;
-       int y=0;
+       struct speex_coder_pvt *tmp = pvt->pvt;
        int is_speech=1;
+       int datalen = 0;        /* output bytes */
+       int samples = 0;        /* output samples */
+
        /* We can't work on anything less than a frame in size */
-       if (tmp->tail < tmp->framesize)
+       if (pvt->samples < tmp->framesize)
                return NULL;
-       tmp->f.frametype = AST_FRAME_VOICE;
-       tmp->f.subclass = AST_FORMAT_SPEEX;
-       tmp->f.mallocd = 0;
-       tmp->f.offset = AST_FRIENDLY_OFFSET;
-       tmp->f.src = __PRETTY_FUNCTION__;
-       tmp->f.data = tmp->outbuf;
        speex_bits_reset(&tmp->bits);
-       while(tmp->tail >= tmp->framesize) {
+       while (pvt->samples >= tmp->framesize) {
 #ifdef _SPEEX_TYPES_H
                /* Preprocess audio */
-               if(preproc)
+               if (preproc)
                        is_speech = speex_preprocess(tmp->pp, tmp->buf, NULL);
                /* Encode a frame of data */
                if (is_speech) {
@@ -331,254 +279,230 @@ static struct ast_frame *lintospeex_frameout(struct ast_translator_pvt *tmp)
                        speex_bits_pack(&tmp->bits, 0, 5);
                }
 #else
-               /* Convert to floating point */
-               for (x=0;x<tmp->framesize;x++)
-                       fbuf[x] = tmp->buf[x];
-               /* Encode a frame of data */
-               is_speech = speex_encode(tmp->speex, fbuf, &tmp->bits) || !dtx;
+               {
+                       float fbuf[1024];
+                       int x;
+                       /* Convert to floating point */
+                       for (x = 0; x < tmp->framesize; x++)
+                               fbuf[x] = tmp->buf[x];
+                       /* Encode a frame of data */
+                       is_speech = speex_encode(tmp->speex, fbuf, &tmp->bits) || !dtx;
+               }
 #endif
-               /* Assume 8000 Hz -- 20 ms */
-               tmp->tail -= tmp->framesize;
+               samples += tmp->framesize;
+               pvt->samples -= tmp->framesize;
                /* Move the data at the end of the buffer to the front */
-               if (tmp->tail)
-                       memmove(tmp->buf, tmp->buf + tmp->framesize, tmp->tail * 2);
-               y++;
+               if (pvt->samples)
+                       memmove(tmp->buf, tmp->buf + tmp->framesize, pvt->samples * 2);
        }
 
        /* Use AST_FRAME_CNG to signify the start of any silence period */
-       if (!is_speech) {
+       if (is_speech) {
+               tmp->silent_state = 0;
+       } else {
                if (tmp->silent_state) {
                        return NULL;
                } else {
                        tmp->silent_state = 1;
                        speex_bits_reset(&tmp->bits);
-                       tmp->f.frametype = AST_FRAME_CNG;
+                       memset(&pvt->f, 0, sizeof(pvt->f));
+                       pvt->f.frametype = AST_FRAME_CNG;
+                       pvt->f.samples = samples;
+                       /* XXX what now ? format etc... */
                }
-       } else {
-               tmp->silent_state = 0;
        }
 
        /* Terminate bit stream */
        speex_bits_pack(&tmp->bits, 15, 5);
-       len = speex_bits_write(&tmp->bits, (char *)tmp->outbuf, sizeof(tmp->outbuf));
-       tmp->f.datalen = len;
-       tmp->f.samples = y * 160;
-#if 0
-       {
-               static int fd = -1;
-               if (fd < 0) {
-                       fd = open("speex.raw", O_WRONLY|O_TRUNC|O_CREAT);
-                       if (fd > -1) {
-                               write(fd, tmp->f.data, tmp->f.datalen);
-                               close(fd);
-                       }
-               }
-       }
-#endif
-       return &tmp->f; 
+       datalen = speex_bits_write(&tmp->bits, pvt->outbuf, pvt->t->buf_size);
+       return ast_trans_frameout(pvt, datalen, samples);
 }
 
-static void speextolin_destroy(struct ast_translator_pvt *pvt)
+static void speextolin_destroy(struct ast_trans_pvt *arg)
 {
+       struct speex_coder_pvt *pvt = arg->pvt;
+
        speex_decoder_destroy(pvt->speex);
        speex_bits_destroy(&pvt->bits);
-       free(pvt);
-       localusecnt--;
 }
 
-static void lintospeex_destroy(struct ast_translator_pvt *pvt)
+static void lintospeex_destroy(struct ast_trans_pvt *arg)
 {
+       struct speex_coder_pvt *pvt = arg->pvt;
 #ifdef _SPEEX_TYPES_H
        if (preproc)
                speex_preprocess_state_destroy(pvt->pp);
 #endif
        speex_encoder_destroy(pvt->speex);
        speex_bits_destroy(&pvt->bits);
-       free(pvt);
-       localusecnt--;
 }
 
-static struct ast_translator speextolin =
-       { "speextolin", 
-          AST_FORMAT_SPEEX, AST_FORMAT_SLINEAR,
-          speextolin_new,
-          speextolin_framein,
-          speextolin_frameout,
-          speextolin_destroy,
-          speextolin_sample
-          };
-
-static struct ast_translator lintospeex =
-       { "lintospeex", 
-          AST_FORMAT_SLINEAR, AST_FORMAT_SPEEX,
-          lintospeex_new,
-          lintospeex_framein,
-          lintospeex_frameout,
-          lintospeex_destroy,
-          lintospeex_sample
-       };
+static struct ast_module_lock me = { .usecnt = -1 };
+
+static struct ast_translator speextolin = {
+       .name = "speextolin", 
+       .srcfmt = AST_FORMAT_SPEEX,
+       .dstfmt =  AST_FORMAT_SLINEAR,
+       .newpvt = speextolin_new,
+       .framein = speextolin_framein,
+       .destroy = speextolin_destroy,
+       .sample = speextolin_sample,
+       .desc_size = sizeof(struct speex_coder_pvt),
+       .buffer_samples = BUFFER_SAMPLES,
+       .buf_size = BUFFER_SAMPLES * 2,
+       .lockp = &me,
+};
+
+static struct ast_translator lintospeex = {
+       .name = "lintospeex", 
+       .srcfmt = AST_FORMAT_SLINEAR,
+       .dstfmt = AST_FORMAT_SPEEX,
+       .newpvt = lintospeex_new,
+       .framein = lintospeex_framein,
+       .frameout = lintospeex_frameout,
+       .destroy = lintospeex_destroy,
+       .sample = lintospeex_sample,
+       .desc_size = sizeof(struct speex_coder_pvt),
+       .buffer_samples = BUFFER_SAMPLES,
+       .buf_size = BUFFER_SAMPLES * 2, /* XXX maybe a lot less ? */
+       .lockp = &me,
+};
 
 
 static void parse_config(void) 
 {
-       struct ast_config *cfg;
+       struct ast_config *cfg = ast_config_load("codecs.conf");
        struct ast_variable *var;
        int res;
        float res_f;
 
-       if ((cfg = ast_config_load("codecs.conf"))) {
-               if ((var = ast_variable_browse(cfg, "speex"))) {
-                       while (var) {
-                               if (!strcasecmp(var->name, "quality")) {
-                                       res = abs(atoi(var->value));
-                                       if (res > -1 && res < 11) {
-                                               if (option_verbose > 2)
-                                                       ast_verbose(VERBOSE_PREFIX_3 "CODEC SPEEX: Setting Quality to %d\n",res);
-                                               ast_mutex_lock(&localuser_lock);
-                                               quality = res;
-                                               ast_mutex_unlock(&localuser_lock);
-                                       } else 
-                                               ast_log(LOG_ERROR,"Error Quality must be 0-10\n");
-                               } else if (!strcasecmp(var->name, "complexity")) {
-                                       res = abs(atoi(var->value));
-                                       if (res > -1 && res < 11) {
-                                               if (option_verbose > 2)
-                                                       ast_verbose(VERBOSE_PREFIX_3 "CODEC SPEEX: Setting Complexity to %d\n",res);
-                                               ast_mutex_lock(&localuser_lock);
-                                               complexity = res;
-                                               ast_mutex_unlock(&localuser_lock);
-                                       } else 
-                                               ast_log(LOG_ERROR,"Error! Complexity must be 0-10\n");
-                               } else if (!strcasecmp(var->name, "vbr_quality")) {
-                                       if (sscanf(var->value, "%f", &res_f) == 1 && res_f >= 0 && res_f <= 10) {
-                                               if (option_verbose > 2)
-                                                       ast_verbose(VERBOSE_PREFIX_3 "CODEC SPEEX: Setting VBR Quality to %f\n",res_f);
-                                               ast_mutex_lock(&localuser_lock);
-                                               vbr_quality = res_f;
-                                               ast_mutex_unlock(&localuser_lock);
-                                       } else
-                                               ast_log(LOG_ERROR,"Error! VBR Quality must be 0-10\n");
-                               } else if (!strcasecmp(var->name, "abr_quality")) {
-                                       ast_log(LOG_ERROR,"Error! ABR Quality setting obsolete, set ABR to desired bitrate\n");
-                               } else if (!strcasecmp(var->name, "enhancement")) {
-                                       ast_mutex_lock(&localuser_lock);
-                                       enhancement = ast_true(var->value) ? 1 : 0;
-                                       if (option_verbose > 2)
-                                               ast_verbose(VERBOSE_PREFIX_3 "CODEC SPEEX: Perceptual Enhancement Mode. [%s]\n",enhancement ? "on" : "off");
-                                       ast_mutex_unlock(&localuser_lock);
-                               } else if (!strcasecmp(var->name, "vbr")) {
-                                       ast_mutex_lock(&localuser_lock);
-                                       vbr = ast_true(var->value) ? 1 : 0;
-                                       if (option_verbose > 2)
-                                               ast_verbose(VERBOSE_PREFIX_3 "CODEC SPEEX: VBR Mode. [%s]\n",vbr ? "on" : "off");
-                                       ast_mutex_unlock(&localuser_lock);
-                               } else if (!strcasecmp(var->name, "abr")) {
-                                       res = abs(atoi(var->value));
-                                       if (res >= 0) {
-                                               if (option_verbose > 2) {
-                                                       if (res > 0)
-                                                               ast_verbose(VERBOSE_PREFIX_3 "CODEC SPEEX: Setting ABR target bitrate to %d\n",res);
-                                                       else
-                                                               ast_verbose(VERBOSE_PREFIX_3 "CODEC SPEEX: Disabling ABR\n");
-                                               }
-                                               ast_mutex_lock(&localuser_lock);
-                                               abr = res;
-                                               ast_mutex_unlock(&localuser_lock);
-                                       } else 
-                                               ast_log(LOG_ERROR,"Error! ABR target bitrate must be >= 0\n");
-                               } else if (!strcasecmp(var->name, "vad")) {
-                                       ast_mutex_lock(&localuser_lock);
-                                       vad = ast_true(var->value) ? 1 : 0;
-                                       if (option_verbose > 2)
-                                               ast_verbose(VERBOSE_PREFIX_3 "CODEC SPEEX: VAD Mode. [%s]\n",vad ? "on" : "off");
-                                       ast_mutex_unlock(&localuser_lock);
-                               } else if (!strcasecmp(var->name, "dtx")) {
-                                       ast_mutex_lock(&localuser_lock);
-                                       dtx = ast_true(var->value) ? 1 : 0;
-                                       if (option_verbose > 2)
-                                               ast_verbose(VERBOSE_PREFIX_3 "CODEC SPEEX: DTX Mode. [%s]\n",dtx ? "on" : "off");
-                                       ast_mutex_unlock(&localuser_lock);
-                               } else if (!strcasecmp(var->name, "preprocess")) {
-                                       ast_mutex_lock(&localuser_lock);
-                                       preproc = ast_true(var->value) ? 1 : 0;
-                                       if (option_verbose > 2)
-                                               ast_verbose(VERBOSE_PREFIX_3 "CODEC SPEEX: Preprocessing. [%s]\n",preproc ? "on" : "off");
-                                       ast_mutex_unlock(&localuser_lock);
-                               } else if (!strcasecmp(var->name, "pp_vad")) {
-                                       ast_mutex_lock(&localuser_lock);
-                                       pp_vad = ast_true(var->value) ? 1 : 0;
-                                       if (option_verbose > 2)
-                                               ast_verbose(VERBOSE_PREFIX_3 "CODEC SPEEX: Preprocessor VAD. [%s]\n",pp_vad ? "on" : "off");
-                                       ast_mutex_unlock(&localuser_lock);
-                               } else if (!strcasecmp(var->name, "pp_agc")) {
-                                       ast_mutex_lock(&localuser_lock);
-                                       pp_agc = ast_true(var->value) ? 1 : 0;
-                                       if (option_verbose > 2)
-                                               ast_verbose(VERBOSE_PREFIX_3 "CODEC SPEEX: Preprocessor AGC. [%s]\n",pp_agc ? "on" : "off");
-                                       ast_mutex_unlock(&localuser_lock);
-                               } else if (!strcasecmp(var->name, "pp_agc_level")) {
-                                       if (sscanf(var->value, "%f", &res_f) == 1 && res_f >= 0) {
-                                               if (option_verbose > 2)
-                                                       ast_verbose(VERBOSE_PREFIX_3 "CODEC SPEEX: Setting preprocessor AGC Level to %f\n",res_f);
-                                               ast_mutex_lock(&localuser_lock);
-                                               pp_agc_level = res_f;
-                                               ast_mutex_unlock(&localuser_lock);
-                                       } else
-                                               ast_log(LOG_ERROR,"Error! Preprocessor AGC Level must be >= 0\n");
-                               } else if (!strcasecmp(var->name, "pp_denoise")) {
-                                       ast_mutex_lock(&localuser_lock);
-                                       pp_denoise = ast_true(var->value) ? 1 : 0;
-                                       if (option_verbose > 2)
-                                               ast_verbose(VERBOSE_PREFIX_3 "CODEC SPEEX: Preprocessor Denoise. [%s]\n",pp_denoise ? "on" : "off");
-                                       ast_mutex_unlock(&localuser_lock);
-                               } else if (!strcasecmp(var->name, "pp_dereverb")) {
-                                       ast_mutex_lock(&localuser_lock);
-                                       pp_dereverb = ast_true(var->value) ? 1 : 0;
-                                       if (option_verbose > 2)
-                                               ast_verbose(VERBOSE_PREFIX_3 "CODEC SPEEX: Preprocessor Dereverb. [%s]\n",pp_dereverb ? "on" : "off");
-                                       ast_mutex_unlock(&localuser_lock);
-                               } else if (!strcasecmp(var->name, "pp_dereverb_decay")) {
-                                       if (sscanf(var->value, "%f", &res_f) == 1 && res_f >= 0) {
-                                               if (option_verbose > 2)
-                                                       ast_verbose(VERBOSE_PREFIX_3 "CODEC SPEEX: Setting preprocessor Dereverb Decay to %f\n",res_f);
-                                               ast_mutex_lock(&localuser_lock);
-                                               pp_dereverb_decay = res_f;
-                                               ast_mutex_unlock(&localuser_lock);
-                                       } else
-                                               ast_log(LOG_ERROR,"Error! Preprocessor Dereverb Decay must be >= 0\n");
-                               } else if (!strcasecmp(var->name, "pp_dereverb_level")) {
-                                       if (sscanf(var->value, "%f", &res_f) == 1 && res_f >= 0) {
-                                               if (option_verbose > 2)
-                                                       ast_verbose(VERBOSE_PREFIX_3 "CODEC SPEEX: Setting preprocessor Dereverb Level to %f\n",res_f);
-                                               ast_mutex_lock(&localuser_lock);
-                                               pp_dereverb_level = res_f;
-                                               ast_mutex_unlock(&localuser_lock);
-                                       } else
-                                               ast_log(LOG_ERROR,"Error! Preprocessor Dereverb Level must be >= 0\n");
+       if (cfg == NULL)
+               return;
+
+       for (var = ast_variable_browse(cfg, "speex"); var; var = var->next) {
+               if (!strcasecmp(var->name, "quality")) {
+                       res = abs(atoi(var->value));
+                       if (res > -1 && res < 11) {
+                               if (option_verbose > 2)
+                                       ast_verbose(VERBOSE_PREFIX_3 "CODEC SPEEX: Setting Quality to %d\n",res);
+                               quality = res;
+                       } else 
+                               ast_log(LOG_ERROR,"Error Quality must be 0-10\n");
+               } else if (!strcasecmp(var->name, "complexity")) {
+                       res = abs(atoi(var->value));
+                       if (res > -1 && res < 11) {
+                               if (option_verbose > 2)
+                                       ast_verbose(VERBOSE_PREFIX_3 "CODEC SPEEX: Setting Complexity to %d\n",res);
+                               complexity = res;
+                       } else 
+                               ast_log(LOG_ERROR,"Error! Complexity must be 0-10\n");
+               } else if (!strcasecmp(var->name, "vbr_quality")) {
+                       if (sscanf(var->value, "%f", &res_f) == 1 && res_f >= 0 && res_f <= 10) {
+                               if (option_verbose > 2)
+                                       ast_verbose(VERBOSE_PREFIX_3 "CODEC SPEEX: Setting VBR Quality to %f\n",res_f);
+                               vbr_quality = res_f;
+                       } else
+                               ast_log(LOG_ERROR,"Error! VBR Quality must be 0-10\n");
+               } else if (!strcasecmp(var->name, "abr_quality")) {
+                       ast_log(LOG_ERROR,"Error! ABR Quality setting obsolete, set ABR to desired bitrate\n");
+               } else if (!strcasecmp(var->name, "enhancement")) {
+                       enhancement = ast_true(var->value) ? 1 : 0;
+                       if (option_verbose > 2)
+                               ast_verbose(VERBOSE_PREFIX_3 "CODEC SPEEX: Perceptual Enhancement Mode. [%s]\n",enhancement ? "on" : "off");
+               } else if (!strcasecmp(var->name, "vbr")) {
+                       vbr = ast_true(var->value) ? 1 : 0;
+                       if (option_verbose > 2)
+                               ast_verbose(VERBOSE_PREFIX_3 "CODEC SPEEX: VBR Mode. [%s]\n",vbr ? "on" : "off");
+               } else if (!strcasecmp(var->name, "abr")) {
+                       res = abs(atoi(var->value));
+                       if (res >= 0) {
+                               if (option_verbose > 2) {
+                                       if (res > 0)
+                                               ast_verbose(VERBOSE_PREFIX_3 "CODEC SPEEX: Setting ABR target bitrate to %d\n",res);
+                                       else
+                                               ast_verbose(VERBOSE_PREFIX_3 "CODEC SPEEX: Disabling ABR\n");
                                }
-                               var = var->next;
-                       }
+                               abr = res;
+                       } else 
+                               ast_log(LOG_ERROR,"Error! ABR target bitrate must be >= 0\n");
+               } else if (!strcasecmp(var->name, "vad")) {
+                       vad = ast_true(var->value) ? 1 : 0;
+                       if (option_verbose > 2)
+                               ast_verbose(VERBOSE_PREFIX_3 "CODEC SPEEX: VAD Mode. [%s]\n",vad ? "on" : "off");
+               } else if (!strcasecmp(var->name, "dtx")) {
+                       dtx = ast_true(var->value) ? 1 : 0;
+                       if (option_verbose > 2)
+                               ast_verbose(VERBOSE_PREFIX_3 "CODEC SPEEX: DTX Mode. [%s]\n",dtx ? "on" : "off");
+               } else if (!strcasecmp(var->name, "preprocess")) {
+                       preproc = ast_true(var->value) ? 1 : 0;
+                       if (option_verbose > 2)
+                               ast_verbose(VERBOSE_PREFIX_3 "CODEC SPEEX: Preprocessing. [%s]\n",preproc ? "on" : "off");
+               } else if (!strcasecmp(var->name, "pp_vad")) {
+                       pp_vad = ast_true(var->value) ? 1 : 0;
+                       if (option_verbose > 2)
+                               ast_verbose(VERBOSE_PREFIX_3 "CODEC SPEEX: Preprocessor VAD. [%s]\n",pp_vad ? "on" : "off");
+               } else if (!strcasecmp(var->name, "pp_agc")) {
+                       pp_agc = ast_true(var->value) ? 1 : 0;
+                       if (option_verbose > 2)
+                               ast_verbose(VERBOSE_PREFIX_3 "CODEC SPEEX: Preprocessor AGC. [%s]\n",pp_agc ? "on" : "off");
+               } else if (!strcasecmp(var->name, "pp_agc_level")) {
+                       if (sscanf(var->value, "%f", &res_f) == 1 && res_f >= 0) {
+                               if (option_verbose > 2)
+                                       ast_verbose(VERBOSE_PREFIX_3 "CODEC SPEEX: Setting preprocessor AGC Level to %f\n",res_f);
+                               pp_agc_level = res_f;
+                       } else
+                               ast_log(LOG_ERROR,"Error! Preprocessor AGC Level must be >= 0\n");
+               } else if (!strcasecmp(var->name, "pp_denoise")) {
+                       pp_denoise = ast_true(var->value) ? 1 : 0;
+                       if (option_verbose > 2)
+                               ast_verbose(VERBOSE_PREFIX_3 "CODEC SPEEX: Preprocessor Denoise. [%s]\n",pp_denoise ? "on" : "off");
+               } else if (!strcasecmp(var->name, "pp_dereverb")) {
+                       pp_dereverb = ast_true(var->value) ? 1 : 0;
+                       if (option_verbose > 2)
+                               ast_verbose(VERBOSE_PREFIX_3 "CODEC SPEEX: Preprocessor Dereverb. [%s]\n",pp_dereverb ? "on" : "off");
+               } else if (!strcasecmp(var->name, "pp_dereverb_decay")) {
+                       if (sscanf(var->value, "%f", &res_f) == 1 && res_f >= 0) {
+                               if (option_verbose > 2)
+                                       ast_verbose(VERBOSE_PREFIX_3 "CODEC SPEEX: Setting preprocessor Dereverb Decay to %f\n",res_f);
+                               pp_dereverb_decay = res_f;
+                       } else
+                               ast_log(LOG_ERROR,"Error! Preprocessor Dereverb Decay must be >= 0\n");
+               } else if (!strcasecmp(var->name, "pp_dereverb_level")) {
+                       if (sscanf(var->value, "%f", &res_f) == 1 && res_f >= 0) {
+                               if (option_verbose > 2)
+                                       ast_verbose(VERBOSE_PREFIX_3 "CODEC SPEEX: Setting preprocessor Dereverb Level to %f\n",res_f);
+                               pp_dereverb_level = res_f;
+                       } else
+                               ast_log(LOG_ERROR,"Error! Preprocessor Dereverb Level must be >= 0\n");
                }
-               ast_config_destroy(cfg);
        }
+       ast_config_destroy(cfg);
 }
 
 int reload(void) 
 {
+       /*
+        * XXX reloading while there are active sessions is
+        * somewhat silly because the old state presumably
+        * wouldn't work anymore...
+        * maybe we shuld do a standard hangup localusers ?
+        */
+       ast_mutex_lock(&me.lock);
        parse_config();
+       ast_mutex_lock(&me.lock);
        return 0;
 }
 
 int unload_module(void)
 {
        int res;
-       ast_mutex_lock(&localuser_lock);
+       ast_mutex_lock(&me.lock);
        res = ast_unregister_translator(&lintospeex);
        if (!res)
                res = ast_unregister_translator(&speextolin);
-       if (localusecnt)
+       if (me.usecnt)
                res = -1;
-       ast_mutex_unlock(&localuser_lock);
+       ast_mutex_unlock(&me.lock);
        return res;
 }
 
@@ -596,14 +520,12 @@ int load_module(void)
 
 char *description(void)
 {
-       return tdesc;
+       return "Speex/PCM16 (signed linear) Codec Translator";
 }
 
 int usecount(void)
 {
-       int res;
-       OLD_STANDARD_USECOUNT(res);
-       return res;
+       return me.usecnt;
 }
 
 char *key()
index 4f38a02..ff42128 100644 (file)
@@ -44,235 +44,43 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #include "asterisk/ulaw.h"
 #include "asterisk/utils.h"
 
-#define BUFFER_SIZE   8096     /* size for the translation buffers */
-
-AST_MUTEX_DEFINE_STATIC(localuser_lock);
-static int localusecnt = 0;
-
-static char *tdesc = "Mu-law Coder/Decoder";
-
-static int useplc = 0;
+#define BUFFER_SAMPLES   8096  /* size for the translation buffers */
 
 /* Sample frame data */
 
 #include "slin_ulaw_ex.h"
 #include "ulaw_slin_ex.h"
 
-/*!
- * \brief Private workspace for translating signed linear signals to ulaw.
- */
-
-struct ulaw_encoder_pvt
-{
-       struct ast_frame f;
-       char offset[AST_FRIENDLY_OFFSET];   /*!< Space to build offset */
-       unsigned char outbuf[BUFFER_SIZE];  /*!< Encoded ulaw, two nibbles to a word */
-       int tail;
-};
-
-/*!
- * \brief Private workspace for translating ulaw signals to signed linear.
- */
-
-struct ulaw_decoder_pvt
+/*! \brief convert and store samples in outbuf */
+static int ulawtolin_framein(struct ast_trans_pvt *pvt, struct ast_frame *f)
 {
-       struct ast_frame f;
-       char offset[AST_FRIENDLY_OFFSET];       /* Space to build offset */
-       short outbuf[BUFFER_SIZE];              /* Decoded signed linear values */
-       int tail;
-       plc_state_t plc;
-};
-
-/*!
- * \brief ulawToLin_New
- *  Create a new instance of ulaw_decoder_pvt.
- *
- * Results:
- *  Returns a pointer to the new instance.
- *
- * Side effects:
- *  None.
- */
-
-static struct ast_translator_pvt *ulawtolin_new(void)
-{
-       struct ulaw_decoder_pvt *tmp;
-
-       if ((tmp = ast_calloc(1, sizeof(*tmp)))) {
-               tmp->tail = 0;
-               plc_init(&tmp->plc);
-               localusecnt++;
-               ast_update_use_count();
-       }
-
-       return (struct ast_translator_pvt *)tmp;
-}
-
-/*!
- * \brief LinToulaw_New
- *  Create a new instance of ulaw_encoder_pvt.
- *
- * Results:
- *  Returns a pointer to the new instance.
- *
- * Side effects:
- *  None.
- */
-
-static struct ast_translator_pvt *lintoulaw_new(void)
-{
-       struct ulaw_encoder_pvt *tmp;
-       
-       if ((tmp = ast_calloc(1, sizeof(*tmp)))) {
-               localusecnt++;
-               ast_update_use_count();
-               tmp->tail = 0;
-       }
-
-       return (struct ast_translator_pvt *)tmp;
-}
-
-/*!
- * \brief ulawToLin_FrameIn
- *  Fill an input buffer with packed 4-bit ulaw values if there is room
- *  left.
- *
- * Results:
- *  Foo
- *
- * Side effects:
- *  tmp->tail is the number of packed values in the buffer.
- */
-
-static int ulawtolin_framein(struct ast_translator_pvt *pvt, struct ast_frame *f)
-{
-       struct ulaw_decoder_pvt *tmp = (struct ulaw_decoder_pvt *)pvt;
-       int x;
-       unsigned char *b;
-
-       if(f->datalen == 0) { /* perform PLC with nominal framesize of 20ms/160 samples */
-               if((tmp->tail + 160) * 2 > sizeof(tmp->outbuf)) {
-                       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;
-       }
-
-       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;x<f->datalen;x++)
-               tmp->outbuf[tmp->tail + x] = AST_MULAW(b[x]);
+       int i;
+       unsigned char *src = f->data;
+       int16_t *dst = (int16_t *)pvt->outbuf;
 
-       if(useplc)
-               plc_rx(&tmp->plc, tmp->outbuf+tmp->tail, f->datalen);
+       /* convert and copy in outbuf */
+       for (i=0;  i<f->samples; i++)
+               dst[pvt->samples + i] = AST_MULAW(src[i]);
 
-       tmp->tail += f->datalen;
+       pvt->samples += f->samples;
+       pvt->datalen += 2 * f->samples;
        return 0;
 }
 
-/*!
- * \brief ulawToLin_FrameOut
- *  Convert 4-bit ulaw 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 *ulawtolin_frameout(struct ast_translator_pvt *pvt)
+/*! \brief convert and store samples in outbuf */
+static int lintoulaw_framein(struct ast_trans_pvt *pvt, struct ast_frame *f)
 {
-       struct ulaw_decoder_pvt *tmp = (struct ulaw_decoder_pvt *)pvt;
-
-       if (!tmp->tail)
-               return NULL;
+       int i;
+       int16_t *src = f->data;
 
-       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;
-}
-
-/*!
- * \brief LinToulaw_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 lintoulaw_framein(struct ast_translator_pvt *pvt, struct ast_frame *f)
-{
-       struct ulaw_encoder_pvt *tmp = (struct ulaw_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;x<f->datalen/2;x++) 
-               tmp->outbuf[x+tmp->tail] = AST_LIN2MU(s[x]);
-       tmp->tail += f->datalen/2;
+       for (i=0 ; i < f->samples; i++) 
+               pvt->outbuf[pvt->samples + i] = AST_LIN2MU(src[i]);
+       pvt->samples += f->samples;
+       pvt->datalen += f->samples;     /* 1 byte/sample */
        return 0;
 }
 
-/*!
- * \brief LinToulaw_FrameOut
- *  Convert a buffer of raw 16-bit signed linear PCM to a buffer
- *  of 4-bit ulaw packed two to a byte (Big Endian).
- *
- * Results:
- *  Foo
- *
- * Side effects:
- *  Leftover inbuf data gets packed, tail gets updated.
- */
-
-static struct ast_frame *lintoulaw_frameout(struct ast_translator_pvt *pvt)
-{
-       struct ulaw_encoder_pvt *tmp = (struct ulaw_encoder_pvt *)pvt;
-  
-       if (tmp->tail) {
-               tmp->f.frametype = AST_FRAME_VOICE;
-               tmp->f.subclass = AST_FORMAT_ULAW;
-               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->f.datalen = tmp->tail;
-               tmp->tail = 0;
-               return &tmp->f;
-       } else
-               return NULL;
-}
-
-
-/*!
- * \brief ulawToLin_Sample
- */
-
+/*!  * \brief ulawToLin_Sample */
 static struct ast_frame *ulawtolin_sample(void)
 {
        static struct ast_frame f;
@@ -307,37 +115,21 @@ static struct ast_frame *lintoulaw_sample(void)
 }
 
 /*!
- * \brief ulaw_Destroy
- *  Destroys a private workspace.
- *
- * Results:
- *  It's gone!
- *
- * Side effects:
- *  None.
- */
-
-static void ulaw_destroy(struct ast_translator_pvt *pvt)
-{
-       free(pvt);
-       localusecnt--;
-       ast_update_use_count();
-}
-
-/*!
  * \brief The complete translator for ulawToLin.
  */
 
+static struct ast_module_lock me = { .usecnt = -1 };
+
 static struct ast_translator ulawtolin = {
-       "ulawtolin",
-       AST_FORMAT_ULAW,
-       AST_FORMAT_SLINEAR,
-       ulawtolin_new,
-       ulawtolin_framein,
-       ulawtolin_frameout,
-       ulaw_destroy,
-       /* NULL */
-       ulawtolin_sample
+       .name = "ulawtolin",
+       .srcfmt = AST_FORMAT_ULAW,
+       .dstfmt = AST_FORMAT_SLINEAR,
+       .framein = ulawtolin_framein,
+       .sample = ulawtolin_sample,
+       .lockp = &me,
+       .buffer_samples = BUFFER_SAMPLES,
+       .buf_size = BUFFER_SAMPLES * 2,
+       .plc_samples = 160,
 };
 
 /*!
@@ -345,34 +137,30 @@ static struct ast_translator ulawtolin = {
  */
 
 static struct ast_translator lintoulaw = {
-       "lintoulaw",
-       AST_FORMAT_SLINEAR,
-       AST_FORMAT_ULAW,
-       lintoulaw_new,
-       lintoulaw_framein,
-       lintoulaw_frameout,
-       ulaw_destroy,
-       /* NULL */
-       lintoulaw_sample
+       .name = "lintoulaw",
+       .srcfmt = AST_FORMAT_SLINEAR,
+       .dstfmt = AST_FORMAT_ULAW,
+       .framein = lintoulaw_framein,
+       .sample = lintoulaw_sample,
+       .lockp = &me,
+       .buf_size = BUFFER_SAMPLES,
+       .buffer_samples = BUFFER_SAMPLES,
 };
 
 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_ulaw: %susing generic PLC\n", useplc ? "" : "not ");
-                               }
-                               var = var->next;
-                       }
+       struct ast_config *cfg = ast_config_load("codecs.conf");
+       if (cfg == NULL)
+               return;
+       for (var = ast_variable_browse(cfg, "plc"); var; var = var->next) {
+               if (!strcasecmp(var->name, "genericplc")) {
+                       ulawtolin.useplc = ast_true(var->value) ? 1 : 0;
+                       if (option_verbose > 2)
+                               ast_verbose(VERBOSE_PREFIX_3 "codec_ulaw: %susing generic PLC\n", ulawtolin.useplc ? "" : "not ");
                }
-               ast_config_destroy(cfg);
        }
+       ast_config_destroy(cfg);
 }
 
 int reload(void)
@@ -384,13 +172,13 @@ int reload(void)
 int unload_module(void)
 {
        int res;
-       ast_mutex_lock(&localuser_lock);
+       ast_mutex_lock(&me.lock);
        res = ast_unregister_translator(&lintoulaw);
        if (!res)
                res = ast_unregister_translator(&ulawtolin);
-       if (localusecnt)
+       if (me.usecnt)
                res = -1;
-       ast_mutex_unlock(&localuser_lock);
+       ast_mutex_unlock(&me.lock);
        return res;
 }
 
@@ -412,14 +200,12 @@ int load_module(void)
 
 char *description(void)
 {
-       return tdesc;
+       return "Mu-law Coder/Decoder";
 }
 
 int usecount(void)
 {
-       int res;
-       OLD_STANDARD_USECOUNT(res);
-       return res;
+       return me.usecnt;
 }
 
 char *key()
index 118ba6d..8f1a867 100644 (file)
@@ -17,7 +17,7 @@
  */
 
 /*! \file
- * \brief Translate via the use of pseudo channels
+ * \brief Support for translation of data formats.
  */
 
 #ifndef _ASTERISK_TRANSLATE_H
 extern "C" {
 #endif
 
+#if 1  /* need lots of stuff... */
 #include "asterisk/frame.h"
 #include "asterisk/plc.h"
 #include "asterisk/linkedlists.h"
+#include "asterisk/module.h"
+#endif
 
-/* Declared by individual translators */
-struct ast_translator_pvt;
+struct ast_trans_pvt;  /* declared below */
 
-/*! data structure associated with a translator */
+/*!
+ * Descriptor of a translator. Name, callbacks, and various options
+ * related to run-time operation (size of buffers, auxiliary
+ * descriptors, etc).
+ * A coded registers itself by filling the relevant fields
+ * of a structure and passing it as an argument to
+ * ast_register_translator(). The structure should not be
+ * modified after a successful register(), and its address
+ * must be used as an argument to ast_unregister_translator().
+ *
+ * As a minimum, a translator should supply name, srcfmt and dstfmt,
+ * the required buf_size (in bytes) and buffer_samples (in samples),
+ * and a few callbacks (framein, frameout, sample).
+ * The outbuf is automatically prepended by AST_FRIENDLY_OFFSET
+ * spare bytes so generic routines can place data in there.
+ *
+ * Note, the translator is not supposed to do any memory allocation
+ * or deallocation, nor any locking, because all of this is done in
+ * the generic code.
+ *
+ * Translators using generic plc (packet loss concealment) should
+ * supply a non-zero plc_samples indicating the size (in samples)
+ * of artificially generated frames and incoming data.
+ * Generic plc is only available for dstfmt = SLINEAR
+ */
 struct ast_translator {
-       /*! Name of translator */
-       char name[80];
-       /*! Source format */
-       int srcfmt;
-       /*! Destination format */
-       int dstfmt;
-       /*! Private data associated with the translator */
-       struct ast_translator_pvt *(*newpvt)(void);
-       /*! Input frame callback */
-       int (*framein)(struct ast_translator_pvt *pvt, struct ast_frame *in);
-       /*! Output frame callback */
-       struct ast_frame * (*frameout)(struct ast_translator_pvt *pvt);
-       /*! Destroy translator callback */
-       void (*destroy)(struct ast_translator_pvt *pvt);
-       /* For performance measurements */
-       /*! Generate an example frame */
-       struct ast_frame * (*sample)(void);
-       /*! Cost in milliseconds for encoding/decoding 1 second of sound */
-       int cost;
-       /*! For linking, not to be modified by the translator */
-       AST_LIST_ENTRY(ast_translator) list;
+       const char name[80];            /*! Name of translator */
+       int srcfmt;                     /*! Source format (note: bit position) */
+       int dstfmt;                     /*! Destination format (note: bit position) */
+
+       /*! initialize private data associated with the translator */
+       void *(*newpvt)(struct ast_trans_pvt *);
+
+       /*! Input frame callback. Store (and possibly convert) input frame. */
+       int (*framein)(struct ast_trans_pvt *pvt, struct ast_frame *in);
+
+       /*! Output frame callback. Generate a frame with outbuf content. */
+       struct ast_frame * (*frameout)(struct ast_trans_pvt *pvt);
+
+       /*! cleanup private data, if needed (often unnecessary). */
+       void (*destroy)(struct ast_trans_pvt *pvt);
+
+       struct ast_frame * (*sample)(void);     /*! Generate an example frame */
+
+       /*! size of outbuf, in samples. Leave it 0 if you want the framein
+        * callback deal with the frame. Set it appropriately if you
+        * want the code to checks if the incoming frame fits the
+        * outbuf (this is e.g. required for plc).
+        */
+       int buffer_samples;     /* size of outbuf, in samples */
+
+       /*! size of outbuf, in bytes. Mandatory. The wrapper code will also
+        * allocate an AST_FRIENDLY_OFFSET space before.
+        */
+       int buf_size;
+
+       int desc_size;          /*! size of private descriptor in pvt->pvt, if any */
+       int plc_samples;        /* set to the plc block size if used, 0 otherwise */
+       int useplc;             /* current status of plc, changed at runtime */
+
+       struct ast_module_lock *lockp;
+
+       int cost;               /*! Cost in milliseconds for encoding/decoding 1 second of sound */
+       AST_LIST_ENTRY(ast_translator) list;    /*! link field */
 };
 
+/*
+ * Default structure for translators, with the basic fields and buffers,
+ * all allocated as part of the same chunk of memory. The buffer is
+ * preceded by AST_FRIENDLY_OFFSET bytes in front of the user portion.
+ * 'buf' points right after this space.
+ *
+ * *_framein() routines operate in two ways:
+ * 1. some convert on the fly and place the data directly in outbuf;
+ *    in this case 'samples' and 'datalen' contain the number of samples
+ *    and number of bytes available in the buffer.
+ *    In this case we can use a generic *_frameout() routine that simply
+ *    takes whatever is there and places it into the output frame.
+ * 2. others simply store the (unconverted) samples into a working
+ *    buffer, and leave the conversion task to *_frameout().
+ *    In this case, the intermediate buffer must be in the private
+ *    descriptor, 'datalen' is left to 0, while 'samples' is still
+ *    updated with the number of samples received.
+ */
+struct ast_trans_pvt {
+       struct ast_translator *t;
+       struct ast_frame f;     /* used in frameout */
+       int samples;            /* samples available in outbuf */
+       int datalen;            /* actual space used in outbuf */
+       void *pvt;              /* more private data, if any */
+       char *outbuf;           /* the useful portion of the buffer */
+       plc_state_t *plc;       /* optional plc pointer */
+       struct ast_trans_pvt *next;     /* next in translator chain */
+       struct timeval nextin;
+       struct timeval nextout;
+};
+
+/* generic frameout function */
+struct ast_frame *ast_trans_frameout(struct ast_trans_pvt *pvt,
+        int datalen, int samples);
+
 struct ast_trans_pvt;
 
 /*!
@@ -69,7 +147,7 @@ struct ast_trans_pvt;
  * This registers a codec translator with asterisk
  * Returns 0 on success, -1 on failure
  */
-extern int ast_register_translator(struct ast_translator *t);
+int ast_register_translator(struct ast_translator *t);
 
 /*!
  * \brief Unregister a translator
@@ -77,7 +155,7 @@ extern int ast_register_translator(struct ast_translator *t);
  * Unregisters the given tranlator
  * Returns 0 on success, -1 on failure
  */
-extern int ast_unregister_translator(struct ast_translator *t);
+int ast_unregister_translator(struct ast_translator *t);
 
 /*!
  * \brief Chooses the best translation path
@@ -86,7 +164,7 @@ extern int ast_unregister_translator(struct ast_translator *t);
  * I choose? Returns 0 on success, -1 if no path could be found.  Modifies
  * dests and srcs in place 
  */
-extern int ast_translator_best_choice(int *dsts, int *srcs);
+int ast_translator_best_choice(int *dsts, int *srcs);
 
 /*! 
  * \brief Builds a translator path
@@ -95,14 +173,14 @@ extern int ast_translator_best_choice(int *dsts, int *srcs);
  * Build a path (possibly NULL) from source to dest 
  * Returns ast_trans_pvt on success, NULL on failure
  * */
-extern struct ast_trans_pvt *ast_translator_build_path(int dest, int source);
+struct ast_trans_pvt *ast_translator_build_path(int dest, int source);
 
 /*!
  * \brief Frees a translator path
  * \param tr translator path to get rid of
  * Frees the given translator path structure
  */
-extern void ast_translator_free_path(struct ast_trans_pvt *tr);
+void ast_translator_free_path(struct ast_trans_pvt *tr);
 
 /*!
  * \brief translates one or more frames
@@ -113,7 +191,7 @@ extern void ast_translator_free_path(struct ast_trans_pvt *tr);
  * determines whether the original frame should be freed
  * Returns an ast_frame of the new translation format on success, NULL on failure
  */
-extern struct ast_frame *ast_translate(struct ast_trans_pvt *tr, struct ast_frame *f, int consume);
+struct ast_frame *ast_translate(struct ast_trans_pvt *tr, struct ast_frame *f, int consume);
 
 #if defined(__cplusplus) || defined(c_plusplus)
 }
index 69a2a2b..b3af17d 100644 (file)
@@ -47,118 +47,243 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #define MAX_RECALC 200 /* max sample recalc */
 
-/*! \note
-   This could all be done more efficiently *IF* we chained packets together
-   by default, but it would also complicate virtually every application. */
-   
+/*! \brief the list of translators */
 static AST_LIST_HEAD_STATIC(translators, ast_translator);
 
-struct ast_translator_dir {
+struct translator_path {
        struct ast_translator *step;    /*!< Next step translator */
        unsigned int cost;              /*!< Complete cost to destination */
        unsigned int multistep;         /*!< Multiple conversions required for this translation */
 };
 
-struct ast_frame_delivery {
-       struct ast_frame *f;
-       struct ast_channel *chan;
-       int fd;
-       struct translator_pvt *owner;
-       struct ast_frame_delivery *prev;
-       struct ast_frame_delivery *next;
-};
-
-static struct ast_translator_dir tr_matrix[MAX_FORMAT][MAX_FORMAT];
-
-struct ast_trans_pvt {
-       struct ast_translator *step;
-       struct ast_translator_pvt *state;
-       struct ast_trans_pvt *next;
-       struct timeval nextin;
-       struct timeval nextout;
-};
+/*! \brief a matrix that, for any pair of supported formats,
+ * indicates the total cost of translation and the first step.
+ * The full path can be reconstricted iterating on the matrix
+ * until step->dstfmt == desired_format.
+ */
+static struct translator_path tr_matrix[MAX_FORMAT][MAX_FORMAT];
 
+/*
+ * TODO: sample frames for each supported input format.
+ * We build this on the fly, by taking an SLIN frame and using
+ * the existing converter to play with it.
+ */
 
+/* returns the index of the lowest bit set */
 static int powerof(int d)
 {
        int x;
-       for (x = 0; x < 32; x++)
+       for (x = 0; x < MAX_FORMAT; x++)
                if ((1 << x) & d)
                        return x;
        ast_log(LOG_WARNING, "Powerof %d: No power??\n", d);
        return -1;
 }
 
+/*
+ * wrappers around the translator routines.
+ */
+
+/*!
+ * \brief Allocate the descriptor, required outbuf space,
+ * and possibly also plc and desc.
+ */
+static void *newpvt(struct ast_translator *t)
+{
+       struct ast_trans_pvt *pvt;
+       int len;
+       int useplc = t->plc_samples > 0 && t->useplc;   /* cache, because it can change on the fly */
+       char *ofs;
+       /*
+        * compute the required size adding private descriptor,
+        * plc, buffer, AST_FRIENDLY_OFFSET.
+        */
+       len = sizeof(*pvt) + t->desc_size;
+       if (useplc)
+               len += sizeof(plc_state_t);
+       if (t->buf_size)
+               len += AST_FRIENDLY_OFFSET + t->buf_size;
+       pvt = ast_calloc(1, len);
+       if (!pvt)
+               return NULL;
+       pvt->t = t;
+       ofs = (char *)(pvt + 1);        /* pointer to data space */
+       if (t->desc_size) {             /* first comes the descriptor */
+               pvt->pvt = ofs;
+               ofs += t->desc_size;
+       }
+       if (useplc) {                   /* then plc state */
+               pvt->plc = (plc_state_t *)ofs;
+               ofs += sizeof(plc_state_t);
+       }
+       if (t->buf_size)                /* finally buffer and header */
+               pvt->outbuf = ofs + AST_FRIENDLY_OFFSET;
+       /* call local init routine, if present */
+       if (t->newpvt && t->newpvt(pvt) == NULL) {
+               free(pvt);
+               return NULL;
+       }
+       ast_mutex_lock(&t->lockp->lock);
+       t->lockp->usecnt++;
+       ast_mutex_unlock(&t->lockp->lock);
+       ast_update_use_count();
+       return pvt;
+}
+
+static void destroy(struct ast_trans_pvt *pvt)
+{
+       struct ast_translator *t = pvt->t;
+
+       if (t->destroy)
+               t->destroy(pvt);
+       free(pvt);
+       ast_mutex_lock(&t->lockp->lock);
+       t->lockp->usecnt--;
+       ast_mutex_unlock(&t->lockp->lock);
+       ast_update_use_count();
+}
+
+/*
+ * framein wrapper, deals with plc and bound checks.
+ */
+static int framein(struct ast_trans_pvt *pvt, struct ast_frame *f)
+{
+       int16_t *dst = (int16_t *)pvt->outbuf;
+       int ret;
+       int samples = pvt->samples;     /* initial value */
+
+       if (f->samples == 0) {
+               ast_log(LOG_WARNING, "no samples for %s\n", pvt->t->name);
+       }
+       if (pvt->t->buffer_samples) {   /* do not pass empty frames to callback */
+               if (f->datalen == 0) { /* perform PLC with nominal framesize of 20ms/160 samples */
+                       if (pvt->plc) {
+                               int l = pvt->t->plc_samples;
+                               if (pvt->samples + l > pvt->t->buffer_samples) {
+                                       ast_log(LOG_WARNING, "Out of buffer space\n");
+                                       return -1;
+                               }
+                               l = plc_fillin(pvt->plc, dst + pvt->samples, l);
+                               pvt->samples += l;
+                       }
+                       return 0;
+               }
+               if (pvt->samples + f->samples > pvt->t->buffer_samples) {
+                       ast_log(LOG_WARNING, "Out of buffer space\n");
+                       return -1;
+               }
+       }
+       /* we require a framein routine, wouldn't know how to do
+        * it otherwise.
+        */
+       ret = pvt->t->framein(pvt, f);
+       /* possibly store data for plc */
+       if (!ret && pvt->plc) {
+               int l = pvt->t->plc_samples;
+               if (pvt->samples < l)
+                       l = pvt->samples;
+               plc_rx(pvt->plc, dst + pvt->samples - l, l);
+       }
+       /* diagnostic ... */
+       if (pvt->samples == samples)
+               ast_log(LOG_WARNING, "%s did not update samples %d\n",
+                       pvt->t->name, pvt->samples);
+        return ret;
+}
+
+/*
+ * generic frameout routine.
+ * If samples and datalen are 0, take whatever is in pvt
+ * and reset them, otherwise take the values in the caller and
+ * leave alone the pvt values.
+ */
+struct ast_frame *ast_trans_frameout(struct ast_trans_pvt *pvt,
+       int datalen, int samples)
+{
+       struct ast_frame *f = &pvt->f;
+
+        if (samples)
+               f->samples = samples;
+       else {
+               if (pvt->samples == 0)
+                       return NULL;
+               f->samples = pvt->samples;
+               pvt->samples = 0;
+       }
+       if (datalen)
+               f->datalen = datalen;
+       else {
+               f->datalen = pvt->datalen;
+               pvt->datalen = 0;
+       }
+
+       f->frametype = AST_FRAME_VOICE;
+       f->subclass = 1 << (pvt->t->dstfmt);
+       f->mallocd = 0;
+       f->offset = AST_FRIENDLY_OFFSET;
+       f->src = pvt->t->name;
+       f->data = pvt->outbuf;
+       return f;
+}
+
+static struct ast_frame *default_frameout(struct ast_trans_pvt *pvt)
+{
+       return ast_trans_frameout(pvt, 0, 0);
+}
+
+/* end of callback wrappers and helpers */
+
 void ast_translator_free_path(struct ast_trans_pvt *p)
 {
-       struct ast_trans_pvt *pl, *pn;
-       pn = p;
-       while(pn) {
-               pl = pn;
-               pn = pn->next;
-               if (pl->state && pl->step->destroy)
-                       pl->step->destroy(pl->state);
-               free(pl);
+       struct ast_trans_pvt *pn = p;
+       while ( (p = pn) ) {
+               pn = p->next;
+               destroy(p);
        }
 }
 
-/*! Build a set of translators based upon the given source and destination formats */
+/*! Build a chain of translators based upon the given source and dest formats */
 struct ast_trans_pvt *ast_translator_build_path(int dest, int source)
 {
-       struct ast_trans_pvt *tmpr = NULL, *tmp = NULL;
+       struct ast_trans_pvt *head = NULL, *tail = NULL;
        
        source = powerof(source);
        dest = powerof(dest);
        
        while (source != dest) {
-               if (!tr_matrix[source][dest].step) {
-                       /* We shouldn't have allocated any memory */
+               struct ast_trans_pvt *cur;
+               struct ast_translator *t = tr_matrix[source][dest].step;
+               if (!t) {
                        ast_log(LOG_WARNING, "No translator path from %s to %s\n", 
                                ast_getformatname(source), ast_getformatname(dest));
                        return NULL;
                }
-
-               if (tmp) {
-                       tmp->next = ast_malloc(sizeof(*tmp));
-                       tmp = tmp->next;
-               } else
-                       tmp = ast_malloc(sizeof(*tmp));
-                       
-               if (!tmp) {
-                       if (tmpr)
-                               ast_translator_free_path(tmpr); 
-                       return NULL;
-               }
-
-               /* Set the root, if it doesn't exist yet... */
-               if (!tmpr)
-                       tmpr = tmp;
-
-               tmp->next = NULL;
-               tmp->nextin = tmp->nextout = ast_tv(0, 0);
-               tmp->step = tr_matrix[source][dest].step;
-               tmp->state = tmp->step->newpvt();
-               
-               if (!tmp->state) {
+               if (!(cur = newpvt(t))) {
                        ast_log(LOG_WARNING, "Failed to build translator step from %d to %d\n", source, dest);
-                       ast_translator_free_path(tmpr); 
+                       if (head)
+                               ast_translator_free_path(head); 
                        return NULL;
                }
-               
+               if (!head)
+                       head = cur;
+               else
+                       tail->next = cur;
+               tail = cur;
+               cur->nextin = cur->nextout = ast_tv(0, 0);
                /* Keep going if this isn't the final destination */
-               source = tmp->step->dstfmt;
+               source = cur->t->dstfmt;
        }
-       return tmpr;
+       return head;
 }
 
+/*! \brief do the actual translation */
 struct ast_frame *ast_translate(struct ast_trans_pvt *path, struct ast_frame *f, int consume)
 {
-       struct ast_trans_pvt *p;
-       struct ast_frame *out;
+       struct ast_trans_pvt *p = path;
+       struct ast_frame *out = f;
        struct timeval delivery;
-       p = path;
-       /* Feed the first frame into the first translator */
-       p->step->framein(p->state, f);
+
+       /* XXX hmmm... check this below */
        if (!ast_tvzero(f->delivery)) {
                if (!ast_tvzero(path->nextin)) {
                        /* Make sure this is in line with what we were expecting */
@@ -181,54 +306,45 @@ struct ast_frame *ast_translate(struct ast_trans_pvt *path, struct ast_frame *f,
                path->nextin = ast_tvadd(path->nextin, ast_samp2tv(f->samples, 8000));
        }
        delivery = f->delivery;
+       for ( ; out && p ; p = p->next) {
+               framein(p, out);
+               out = p->t->frameout(p);
+       }
        if (consume)
                ast_frfree(f);
-       while(p) {
-               out = p->step->frameout(p->state);
-               /* If we get nothing out, return NULL */
-               if (!out)
-                       return NULL;
-               /* If there is a next state, feed it in there.  If not,
-                  return this frame  */
-               if (p->next) 
-                       p->next->step->framein(p->next->state, out);
-               else {
-                       if (!ast_tvzero(delivery)) {
-                               /* Regenerate prediction after a discontinuity */
-                               if (ast_tvzero(path->nextout))
-                                       path->nextout = ast_tvnow();
-
-                               /* Use next predicted outgoing timestamp */
-                               out->delivery = path->nextout;
-                               
-                               /* Predict next outgoing timestamp from samples in this
-                                  frame. */
-                               path->nextout = ast_tvadd(path->nextout, ast_samp2tv( out->samples, 8000));
-                       } else {
-                               out->delivery = ast_tv(0, 0);
-                       }
-                       /* Invalidate prediction if we're entering a silence period */
-                       if (out->frametype == AST_FRAME_CNG)
-                               path->nextout = ast_tv(0, 0);
-                       return out;
-               }
-               p = p->next;
+       if (out == NULL)
+               return NULL;
+       /* we have a frame, play with times */
+       if (!ast_tvzero(delivery)) {
+               /* Regenerate prediction after a discontinuity */
+               if (ast_tvzero(path->nextout))
+                       path->nextout = ast_tvnow();
+
+               /* Use next predicted outgoing timestamp */
+               out->delivery = path->nextout;
+               
+               /* Predict next outgoing timestamp from samples in this
+                  frame. */
+               path->nextout = ast_tvadd(path->nextout, ast_samp2tv( out->samples, 8000));
+       } else {
+               out->delivery = ast_tv(0, 0);
        }
-       ast_log(LOG_WARNING, "I should never get here...\n");
-       return NULL;
+       /* Invalidate prediction if we're entering a silence period */
+       if (out->frametype == AST_FRAME_CNG)
+               path->nextout = ast_tv(0, 0);
+       return out;
 }
 
-
-static void calc_cost(struct ast_translator *t, int samples)
+/*! \brief compute the cost of a single translation step */
+static void calc_cost(struct ast_translator *t, int seconds)
 {
        int sofar=0;
-       struct ast_translator_pvt *pvt;
-       struct ast_frame *f, *out;
+       struct ast_trans_pvt *pvt;
        struct timeval start;
        int cost;
 
-       if(!samples)
-               samples = 1;
+       if (!seconds)
+               seconds = 1;
        
        /* If they don't make samples, give them a terrible score */
        if (!t->sample) {
@@ -236,108 +352,114 @@ static void calc_cost(struct ast_translator *t, int samples)
                t->cost = 99999;
                return;
        }
-       pvt = t->newpvt();
+       pvt = newpvt(t);
        if (!pvt) {
                ast_log(LOG_WARNING, "Translator '%s' appears to be broken and will probably fail.\n", t->name);
                t->cost = 99999;
                return;
        }
        start = ast_tvnow();
-       /* Call the encoder until we've processed one second of time */
-       while(sofar < samples * 8000) {
-               f = t->sample();
+       /* Call the encoder until we've processed the required number of samples */
+       while (sofar < seconds * 8000) {
+               struct ast_frame *f = t->sample();
                if (!f) {
                        ast_log(LOG_WARNING, "Translator '%s' failed to produce a sample frame.\n", t->name);
-                       t->destroy(pvt);
+                       destroy(pvt);
                        t->cost = 99999;
                        return;
                }
-               t->framein(pvt, f);
+               framein(pvt, f);
                ast_frfree(f);
-               while((out = t->frameout(pvt))) {
-                       sofar += out->samples;
-                       ast_frfree(out);
+               while( (f = t->frameout(pvt))) {
+                       sofar += f->samples;
+                       ast_frfree(f);
                }
        }
        cost = ast_tvdiff_ms(ast_tvnow(), start);
-       t->destroy(pvt);
-       t->cost = cost / samples;
+       destroy(pvt);
+       t->cost = cost / seconds;
        if (!t->cost)
                t->cost = 1;
 }
 
-/*! 
-  \brief Use the list of translators to build a translation matrix
-
-  \note This function expects the list of translators to be locked
+/*!
+ * \brief rebuild a translation matrix.
+ * \note This function expects the list of translators to be locked
 */
 static void rebuild_matrix(int samples)
 {
        struct ast_translator *t;
-       int changed;
-       int x, y, z;
+       int x;  /* source format index */
+       int y;  /* intermediate format index */
+       int z;  /* destination format index */
 
        if (option_debug)
                ast_log(LOG_DEBUG, "Resetting translation matrix\n");
 
        bzero(tr_matrix, sizeof(tr_matrix));
-
+       /* first, compute all direct costs */
        AST_LIST_TRAVERSE(&translators, t, list) {
+               x = t->srcfmt;
+               z = t->dstfmt;
+
                if (samples)
                        calc_cost(t, samples);
          
-               if (!tr_matrix[t->srcfmt][t->dstfmt].step ||
-                   tr_matrix[t->srcfmt][t->dstfmt].cost > t->cost) {
-                       tr_matrix[t->srcfmt][t->dstfmt].step = t;
-                       tr_matrix[t->srcfmt][t->dstfmt].cost = t->cost;
+               if (!tr_matrix[x][z].step || t->cost < tr_matrix[x][z].cost) {
+                       tr_matrix[x][z].step = t;
+                       tr_matrix[x][z].cost = t->cost;
                }
        }
-
-       do {
-               changed = 0;
-
-               /* Don't you just love O(N^3) operations? */
-               for (x = 0; x< MAX_FORMAT; x++) {                       /* For each source format */
-                       for (y = 0; y < MAX_FORMAT; y++) {              /* And each destination format */
-                               if (x == y)                             /* Except ourselves, of course */
+       /*
+        * For each triple x, y, z of distinct formats, check if there is
+        * a path from x to z through y which is cheaper than what is
+        * currently known, and in case, update the matrix.
+        * Repeat until the matrix is stable.
+        */
+       for (;;) {
+               int changed = 0;
+               for (x=0; x < MAX_FORMAT; x++) {                        /* source format */
+                       for (y=0; y < MAX_FORMAT; y++) {        /* intermediate format */
+                               if (x == y)                     /* skip ourselves */
                                        continue;
 
-                               for (z=0; z < MAX_FORMAT; z++) {        /* And each format it might convert to */
-                                       if ((x == z) || (y == z))       /* Don't ever convert back to us */
-                                               continue;
+                               for (z=0; z<MAX_FORMAT; z++) {  /* dst format */
+                                       int newcost;
 
-                                       if (tr_matrix[x][y].step &&     /* We can convert from x to y */
-                                           tr_matrix[y][z].step &&     /* And from y to z and... */
-                                           (!tr_matrix[x][z].step ||   /* Either there isn't an x->z conversion */
-                                            (tr_matrix[x][y].cost + 
-                                             tr_matrix[y][z].cost <    /* Or we're cheaper than the existing */
-                                             tr_matrix[x][z].cost)     /* solution */
-                                                   )) {
-                                               /* We can get from x to z via y with a cost that
-                                                  is the sum of the transition from x to y and
-                                                  from y to z */
-                                               
-                                               tr_matrix[x][z].step = tr_matrix[x][y].step;
-                                               tr_matrix[x][z].cost = tr_matrix[x][y].cost + 
-                                                       tr_matrix[y][z].cost;
-                                               tr_matrix[x][z].multistep = 1;
-                                               if (option_debug)
-                                                       ast_log(LOG_DEBUG, "Discovered %d cost path from %s to %s, via %d\n", tr_matrix[x][z].cost, ast_getformatname(x), ast_getformatname(z), y);
-                                               changed++;
-                                       }
+                                       if (z == x || z == y)   /* skip null conversions */
+                                               continue;
+                                       if (!tr_matrix[x][y].step)      /* no path from x to y */
+                                               continue;
+                                       if (!tr_matrix[y][z].step)      /* no path from y to z */
+                                               continue;
+                                       newcost = tr_matrix[x][y].cost + tr_matrix[y][z].cost;
+                                       if (tr_matrix[x][z].step && newcost >= tr_matrix[x][z].cost)
+                                               continue;       /* x->y->z is more expensive than
+                                                                * the existing path */
+                                       /* ok, we can get from x to z via y with a cost that
+                                          is the sum of the transition from x to y and
+                                          from y to z */
+                                                
+                                       tr_matrix[x][z].step = tr_matrix[x][y].step;
+                                       tr_matrix[x][z].cost = newcost;
+                                       tr_matrix[x][z].multistep = 1;
+                                       if (option_debug)
+                                               ast_log(LOG_DEBUG, "Discovered %d cost path from %s to %s, via %d\n", tr_matrix[x][z].cost, ast_getformatname(x), ast_getformatname(z), y);
+                                       changed++;
                                }
                        }
                }
-       } while (changed);
+               if (!changed)
+                       break;
+       }
 }
 
-
 /*! \brief CLI "show translation" command handler */
 static int show_translation(int fd, int argc, char *argv[])
 {
 #define SHOW_TRANS 11
        int x, y, z;
-       char line[80];
+
        if (argc > 4) 
                return RESULT_SHOWUSAGE;
 
@@ -362,30 +484,30 @@ static int show_translation(int fd, int argc, char *argv[])
        ast_cli(fd, "         Translation times between formats (in milliseconds)\n");
        ast_cli(fd, "          Source Format (Rows) Destination Format(Columns)\n\n");
        for (x = -1; x < SHOW_TRANS; x++) {
-               /* next 2 lines run faster than using strcpy() */
-               line[0] = ' ';
-               line[1] = '\0';
+               char line[80];
+               char *buf = line;
+               int left = sizeof(line) - 1;    /* one initial space */
+               /* next 2 lines run faster than using ast_build_string() */
+               *buf++ = ' ';
+               *buf = '\0';
                for (y=-1;y<SHOW_TRANS;y++) {
-                       if (x >= 0 && y >= 0 && tr_matrix[x][y].step)
-                               snprintf(line + strlen(line), sizeof(line) - strlen(line), " %5d", tr_matrix[x][y].cost >= 99999 ? tr_matrix[x][y].cost-99999 : tr_matrix[x][y].cost);
-                       else
-                               if (((x == -1 && y >= 0) || (y == -1 && x >= 0))) {
-                                       snprintf(line + strlen(line), sizeof(line) - strlen(line), 
-                                               " %5s", ast_getformatname(1<<(x+y+1)) );
-                               } else if (x != -1 && y != -1) {
-                                       snprintf(line + strlen(line), sizeof(line) - strlen(line), "     -");
-                               } else {
-                                       snprintf(line + strlen(line), sizeof(line) - strlen(line), "      ");
-                               }
+                       if (x >= 0 && y >= 0 && tr_matrix[x][y].step)   /* XXX what is 99999 ? */
+                               ast_build_string(&buf, &left, " %5d", tr_matrix[x][y].cost >= 99999 ? 0 : tr_matrix[x][y].cost);
+                       else if (((x == -1 && y >= 0) || (y == -1 && x >= 0))) {
+                               ast_build_string(&buf, &left, " %5s", ast_getformatname(1<<(x+y+1)) );
+                       } else if (x != -1 && y != -1) {
+                               ast_build_string(&buf, &left, "     -");
+                       } else {
+                               ast_build_string(&buf, &left, "      ");
+                       }
                }
-               snprintf(line + strlen(line), sizeof(line) - strlen(line), "\n");
+               ast_build_string(&buf, &left, "\n");
                ast_cli(fd, line);                      
        }
        AST_LIST_UNLOCK(&translators);
        return RESULT_SUCCESS;
 }
 
-static int added_cli = 0;
 
 static char show_trans_usage[] =
 "Usage: show translation [recalc] [<recalc seconds>]\n"
@@ -399,9 +521,29 @@ static struct ast_cli_entry show_trans =
 
 int ast_register_translator(struct ast_translator *t)
 {
-       char tmp[80];
+       static int added_cli = 0;
+
+       if (t->lockp == NULL) {
+               ast_log(LOG_WARNING, "Missing lock pointer, you need to supply one\n");
+               return -1;
+       }
+       if (t->buf_size == 0) {
+               ast_log(LOG_WARNING, "empty buf size, you need to supply one\n");
+               return -1;
+       }
+       if (t->plc_samples) {
+               if (t->buffer_samples < t->plc_samples) {
+                       ast_log(LOG_WARNING, "plc_samples %d buffer_samples %d\n",
+                               t->plc_samples, t->buffer_samples);
+                       return -1;
+               }
+               if (t->dstfmt != AST_FORMAT_SLINEAR)
+                       ast_log(LOG_WARNING, "plc_samples %d format %x\n",
+                               t->plc_samples, t->dstfmt);
+       }
        t->srcfmt = powerof(t->srcfmt);
        t->dstfmt = powerof(t->dstfmt);
+       /* XXX maybe check that it is not existing yet ? */
        if (t->srcfmt >= MAX_FORMAT) {
                ast_log(LOG_WARNING, "Source format %s is larger than MAX_FORMAT\n", ast_getformatname(t->srcfmt));
                return -1;
@@ -410,9 +552,29 @@ int ast_register_translator(struct ast_translator *t)
                ast_log(LOG_WARNING, "Destination format %s is larger than MAX_FORMAT\n", ast_getformatname(t->dstfmt));
                return -1;
        }
+       if (t->buf_size) {
+               /*
+               * Align buf_size properly, rounding up to the machine-specific
+               * alignment for pointers.
+               */
+               struct _test_align { void *a, *b; } p;
+               int align = (char *)&p.b - (char *)&p.a;
+               t->buf_size = ((t->buf_size + align - 1)/align)*align;
+       }
+       if (t->lockp->usecnt < 0) {     /* XXX need to initialize the lock */
+               ast_mutex_init(&t->lockp->lock);
+               t->lockp->usecnt = 0;
+       }
+       if (t->frameout == NULL)
+               t->frameout = default_frameout;
+  
        calc_cost(t,1);
-       if (option_verbose > 1)
-               ast_verbose(VERBOSE_PREFIX_2 "Registered translator '%s' from format %s to %s, cost %d\n", term_color(tmp, t->name, COLOR_MAGENTA, COLOR_BLACK, sizeof(tmp)), ast_getformatname(1 << t->srcfmt), ast_getformatname(1 << t->dstfmt), t->cost);
+       if (option_verbose > 1) {
+               char tmp[80];
+               ast_verbose(VERBOSE_PREFIX_2 "Registered translator '%s' from format %s to %s, cost %d\n",
+                       term_color(tmp, t->name, COLOR_MAGENTA, COLOR_BLACK, sizeof(tmp)),
+                       ast_getformatname(1 << t->srcfmt), ast_getformatname(1 << t->dstfmt), t->cost);
+       }
        AST_LIST_LOCK(&translators);
        if (!added_cli) {
                ast_cli_register(&show_trans);
@@ -450,58 +612,44 @@ int ast_translator_best_choice(int *dst, int *srcs)
        int x,y;
        int best = -1;
        int bestdst = 0;
-       int cur = 1;
+       int cur, cursrc;
        int besttime = INT_MAX;
        int beststeps = INT_MAX;
-       int common;
-
-       if ((common = (*dst) & (*srcs))) {
-               /* We have a format in common */
-               for (y = 0; y < MAX_FORMAT; y++) {
-                       if (cur & common) {
-                               /* This is a common format to both.  Pick it if we don't have one already */
-                               bestdst = cur;
-                               best = cur;
-                       }
-                       cur = cur << 1;
+       int common = (*dst) & (*srcs);  /* are there common formats ? */
+
+       if (common) { /* yes, pick one and return */
+               for (cur = 1, y=0; y < MAX_FORMAT; cur <<=1, y++) {
+                       if (cur & common)       /* guaranteed to find one */
+                               break;
                }
-       } else {
-               /* We will need to translate */
+               /* We are done, this is a common format to both. */
+               *srcs = *dst  = cur;
+               return 0;
+       } else {        /* No, we will need to translate */
                AST_LIST_LOCK(&translators);
-               for (y = 0; y < MAX_FORMAT; y++) {
-                       if (!(cur & *dst)) {
-                               cur = cur << 1;
+               for (cur = 1, y=0; y < MAX_FORMAT; cur <<=1, y++) {
+                       if (! (cur & *dst))
                                continue;
-                       }
-
-                       for (x = 0; x < MAX_FORMAT; x++) {
-                               if ((*srcs & (1 << x)) &&                       /* x is a valid source format */
-                                   tr_matrix[x][y].step) {                     /* There's a step */
-                                       if (tr_matrix[x][y].cost > besttime)
-                                               continue;                       /* It's more expensive, skip it */
-                                       
-                                       if (tr_matrix[x][y].cost == besttime &&
-                                           tr_matrix[x][y].multistep >= beststeps)
-                                               continue;                       /* It requires the same (or more) steps,
-                                                                                  skip it */
-
-                                       /* It's better than what we have so far */
-                                       best = 1 << x;
+                       for (cursrc = 1, x=0; x < MAX_FORMAT; cursrc <<= 1, x++) {
+                               if (!(*srcs & cursrc) || !tr_matrix[x][y].step ||
+                                   tr_matrix[x][y].cost >  besttime)
+                                       continue;       /* not existing or no better */
+                               if (tr_matrix[x][y].cost < besttime ||
+                                   tr_matrix[x][y].multistep < beststeps) {
+                                       /* better than what we have so far */
+                                       best = cursrc;
                                        bestdst = cur;
                                        besttime = tr_matrix[x][y].cost;
                                        beststeps = tr_matrix[x][y].multistep;
                                }
                        }
-                       cur = cur << 1;
                }
                AST_LIST_UNLOCK(&translators);
+               if (best > -1) {
+                       *srcs = best;
+                       *dst = bestdst;
+                       best = 0;
+               }
+               return best;
        }
-
-       if (best > -1) {
-               *srcs = best;
-               *dst = bestdst;
-               best = 0;
-       }
-
-       return best;
 }