Asterisk.org: Developer Documentation (28 Oct 2009)

Wed Oct 28 15:47:53 2009

## Asterisk developer's documentation

# codec_lpc10.c

Go to the documentation of this file.

    00001 /*
    00002  * Asterisk -- An open source telephony toolkit.
    00003  *
    00004  * Copyright (C) 1999 - 2005, Digium, Inc.
    00005  *
    00006  * Mark Spencer <markster@digium.com>
    00007  *
    00008  * The lpc10 code is from a library used by nautilus, modified to be a bit
    00009  * nicer to the compiler.
    00010  * See http://www.arl.wustl.edu/~jaf/
    00011  *
    00012  * See http://www.asterisk.org for more information about
    00013  * the Asterisk project. Please do not directly contact
    00014  * any of the maintainers of this project for assistance;
    00015  * the project provides a web site, mailing lists and IRC
    00016  * channels for your use.
    00017  *
    00018  * This program is free software, distributed under the terms of
    00019  * the GNU General Public License Version 2. See the LICENSE file
    00020  * at the top of the source tree.
    00021  */
    00022
    00023 /*! \file
    00024  *
    00025  * \brief Translate between signed linear and LPC10 (Linear Predictor Code)
    00026  *
    00027  * \ingroup codecs
    00028  */
    00029
    00030 #include <fcntl.h>
    00031 #include <stdlib.h>
    00032 #include <unistd.h>
    00033 #include <netinet/in.h>
    00034 #include <string.h>
    00035 #include <stdio.h>
    00036
    00037 #include "asterisk.h"
    00038
    00039 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 7221 $")
    00040
    00041 #include "asterisk/lock.h"
    00042 #include "asterisk/translate.h"
    00043 #include "asterisk/config.h"
    00044 #include "asterisk/options.h"
    00045 #include "asterisk/module.h"
    00046 #include "asterisk/logger.h"
    00047 #include "asterisk/channel.h"
    00048
    00049 #include "lpc10/lpc10.h"
    00050
    00051 /* Sample frame data */
    00052 #include "slin_lpc10_ex.h"
    00053 #include "lpc10_slin_ex.h"
    00054
    00055 /* We use a very strange format here...  I have no idea why...  The frames are 180
    00056    samples long, which isn't even an even number of milliseconds...  Not only that
    00057    but we hvae to waste two bits of each frame to keep them ending on a byte boundary
    00058    because the frames are 54 bits long */
    00059
    00060 #define LPC10_BYTES_IN_COMPRESSED_FRAME (LPC10_BITS_IN_COMPRESSED_FRAME + 7)/8
    00061
    00062 AST_MUTEX_DEFINE_STATIC(localuser_lock);
    00063 static int localusecnt=0;
    00064
    00065 static char *tdesc = "LPC10 2.4kbps (signed linear) Voice Coder";
    00066
    00067 static int useplc = 0;
    00068
    00069 struct ast_translator_pvt {
    00070    union {
    00071       struct lpc10_encoder_state *enc;
    00072       struct lpc10_decoder_state *dec;
    00073    } lpc10;
    00074    struct ast_frame f;
    00075    /* Space to build offset */
    00076    char offset[AST_FRIENDLY_OFFSET];
    00077    /* Buffer for our outgoing frame */
    00078    short outbuf[8000];
    00079    /* Enough to store a full second */
    00080    short buf[8000];
    00081    int tail;
    00082    int longer;
    00083    plc_state_t plc; /* god only knows why I bothered to implement PLC for LPC10 :) */
    00084 };
    00085
    00086 #define lpc10_coder_pvt ast_translator_pvt
    00087
    00088 static struct ast_translator_pvt *lpc10_enc_new(void)
    00089 {
    00090    struct lpc10_coder_pvt *tmp;
    00091    tmp = malloc(sizeof(struct lpc10_coder_pvt));
    00092    if (tmp) {
    00093       if (!(tmp->lpc10.enc = create_lpc10_encoder_state())) {
    00094          free(tmp);
    00095          tmp = NULL;
    00096       }
    00097       tmp->tail = 0;
    00098       tmp->longer = 0;
    00099       localusecnt++;
    00100    }
    00101    return tmp;
    00102 }
    00103
    00104 static struct ast_translator_pvt *lpc10_dec_new(void)
    00105 {
    00106    struct lpc10_coder_pvt *tmp;
    00107    tmp = malloc(sizeof(struct lpc10_coder_pvt));
    00108    if (tmp) {
    00109       if (!(tmp->lpc10.dec = create_lpc10_decoder_state())) {
    00110          free(tmp);
    00111          tmp = NULL;
    00112       }
    00113       tmp->tail = 0;
    00114       tmp->longer = 0;
    00115       plc_init(&tmp->plc);
    00116       localusecnt++;
    00117    }
    00118    return tmp;
    00119 }
    00120 static struct ast_frame *lintolpc10_sample(void)
    00121 {
    00122    static struct ast_frame f;
    00123    f.frametype = AST_FRAME_VOICE;
    00124    f.subclass = AST_FORMAT_SLINEAR;
    00125    f.datalen = sizeof(slin_lpc10_ex);
    00126    /* Assume 8000 Hz */
    00127    f.samples = LPC10_SAMPLES_PER_FRAME;
    00128    f.mallocd = 0;
    00129    f.offset = 0;
    00130    f.src = __PRETTY_FUNCTION__;
    00131    f.data = slin_lpc10_ex;
    00132    return &f;
    00133 }
    00134
    00135 static struct ast_frame *lpc10tolin_sample(void)
    00136 {
    00137    static struct ast_frame f;
    00138    f.frametype = AST_FRAME_VOICE;
    00139    f.subclass = AST_FORMAT_LPC10;
    00140    f.datalen = sizeof(lpc10_slin_ex);
    00141    /* All frames are 22 ms long (maybe a little more -- why did he choose
    00142       LPC10_SAMPLES_PER_FRAME sample frames anyway?? */
    00143    f.samples = LPC10_SAMPLES_PER_FRAME;
    00144    f.mallocd = 0;
    00145    f.offset = 0;
    00146    f.src = __PRETTY_FUNCTION__;
    00147    f.data = lpc10_slin_ex;
    00148    return &f;
    00149 }
    00150
    00151 static struct ast_frame *lpc10tolin_frameout(struct ast_translator_pvt *tmp)
    00152 {
    00153    if (!tmp->tail)
    00154       return NULL;
    00155    /* Signed linear is no particular frame size, so just send whatever
    00156       we have in the buffer in one lump sum */
    00157    tmp->f.frametype = AST_FRAME_VOICE;
    00158    tmp->f.subclass = AST_FORMAT_SLINEAR;
    00159    tmp->f.datalen = tmp->tail * 2;
    00160    /* Assume 8000 Hz */
    00161    tmp->f.samples = tmp->tail;
    00162    tmp->f.mallocd = 0;
    00163    tmp->f.offset = AST_FRIENDLY_OFFSET;
    00164    tmp->f.src = __PRETTY_FUNCTION__;
    00165    tmp->f.data = tmp->buf;
    00166    /* Reset tail pointer */
    00167    tmp->tail = 0;
    00168
    00169 #if 0
    00170    /* Save a sample frame */
    00171    { static int samplefr = 0;
    00172    if (samplefr == 80) {
    00173       int fd;
    00174       fd = open("lpc10.example", O_WRONLY | O_CREAT, 0644);
    00175       write(fd, tmp->f.data, tmp->f.datalen);
    00176       close(fd);
    00177    }
    00178    samplefr++;
    00179    }
    00180 #endif
    00181    return &tmp->f;
    00182 }
    00183
    00184 static void extract_bits(INT32 *bits, unsigned char *c)
    00185 {
    00186    int x;
    00187    for (x=0;x<LPC10_BITS_IN_COMPRESSED_FRAME;x++) {
    00188       if (*c & (0x80 >> (x & 7)))
    00189          bits[x] = 1;
    00190       else
    00191          bits[x] = 0;
    00192       if ((x & 7) == 7)
    00193          c++;
    00194    }
    00195 }
    00196
    00197 static void build_bits(unsigned char *c, INT32 *bits)
    00198 {
    00199    unsigned char mask=0x80;
    00200    int x;
    00201    *c = 0;
    00202    for (x=0;x<LPC10_BITS_IN_COMPRESSED_FRAME;x++) {
    00203       if (bits[x])
    00204          *c |= mask;
    00205       mask = mask >> 1;
    00206       if ((x % 8)==7) {
    00207          c++;
    00208          *c = 0;
    00209          mask = 0x80;
    00210       }
    00211    }
    00212 }
    00213
    00214 static int lpc10tolin_framein(struct ast_translator_pvt *tmp, struct ast_frame *f)
    00215 {
    00216    /* Assuming there's space left, decode into the current buffer at
    00217       the tail location */
    00218    int x;
    00219    int len=0;
    00220    float tmpbuf[LPC10_SAMPLES_PER_FRAME];
    00221    short *sd;
    00222    INT32 bits[LPC10_BITS_IN_COMPRESSED_FRAME];
    00223
    00224    if(f->datalen == 0) { /* perform PLC with nominal framesize of LPC10_SAMPLES_PER_FRAME */
    00225          if((tmp->tail + LPC10_SAMPLES_PER_FRAME) > sizeof(tmp->buf)/2) {
    00226         ast_log(LOG_WARNING, "Out of buffer space\n");
    00227         return -1;
    00228          }
    00229          if(useplc) {
    00230         plc_fillin(&tmp->plc, tmp->buf+tmp->tail, LPC10_SAMPLES_PER_FRAME);
    00231         tmp->tail += LPC10_SAMPLES_PER_FRAME;
    00232          }
    00233          return 0;
    00234    }
    00235
    00236    while(len + LPC10_BYTES_IN_COMPRESSED_FRAME <= f->datalen) {
    00237       if (tmp->tail + LPC10_SAMPLES_PER_FRAME < sizeof(tmp->buf)/2) {
    00238          sd = tmp->buf + tmp->tail;
    00239          extract_bits(bits, f->data + len);
    00240          if (lpc10_decode(bits, tmpbuf, tmp->lpc10.dec)) {
    00241             ast_log(LOG_WARNING, "Invalid lpc10 data\n");
    00242             return -1;
    00243          }
    00244          for (x=0;x<LPC10_SAMPLES_PER_FRAME;x++) {
    00245             /* Convert to a real between -1.0 and 1.0 */
    00246             sd[x] = 32768.0 * tmpbuf[x];
    00247          }
    00248
    00249          if(useplc) plc_rx(&tmp->plc, tmp->buf + tmp->tail, LPC10_SAMPLES_PER_FRAME);
    00250
    00251          tmp->tail+=LPC10_SAMPLES_PER_FRAME;
    00252       } else {
    00253          ast_log(LOG_WARNING, "Out of buffer space\n");
    00254          return -1;
    00255       }
    00256       len += LPC10_BYTES_IN_COMPRESSED_FRAME;
    00257    }
    00258    if (len != f->datalen)
    00259       printf("Decoded %d, expected %d\n", len, f->datalen);
    00260    return 0;
    00261 }
    00262
    00263 static int lintolpc10_framein(struct ast_translator_pvt *tmp, struct ast_frame *f)
    00264 {
    00265    /* Just add the frames to our stream */
    00266    /* XXX We should look at how old the rest of our stream is, and if it
    00267       is too old, then we should overwrite it entirely, otherwise we can
    00268       get artifacts of earlier talk that do not belong */
    00269    if (tmp->tail + f->datalen < sizeof(tmp->buf) / 2) {
    00270       memcpy((tmp->buf + tmp->tail), f->data, f->datalen);
    00271       tmp->tail += f->datalen/2;
    00272    } else {
    00273       ast_log(LOG_WARNING, "Out of buffer space\n");
    00274       return -1;
    00275    }
    00276    return 0;
    00277 }
    00278
    00279 static struct ast_frame *lintolpc10_frameout(struct ast_translator_pvt *tmp)
    00280 {
    00281    int x;
    00282    int consumed = 0;
    00283    float tmpbuf[LPC10_SAMPLES_PER_FRAME];
    00284    INT32 bits[LPC10_BITS_IN_COMPRESSED_FRAME];
    00285    /* We can't work on anything less than a frame in size */
    00286    if (tmp->tail < LPC10_SAMPLES_PER_FRAME)
    00287       return NULL;
    00288    /* Start with an empty frame */
    00289    tmp->f.samples = 0;
    00290    tmp->f.datalen = 0;
    00291    tmp->f.frametype = AST_FRAME_VOICE;
    00292    tmp->f.subclass = AST_FORMAT_LPC10;
    00293    while(tmp->tail >=  LPC10_SAMPLES_PER_FRAME) {
    00294       if (tmp->f.datalen + LPC10_BYTES_IN_COMPRESSED_FRAME > sizeof(tmp->outbuf)) {
    00295          ast_log(LOG_WARNING, "Out of buffer space\n");
    00296          return NULL;
    00297       }
    00298       /* Encode a frame of data */
    00299       for (x=0;x<LPC10_SAMPLES_PER_FRAME;x++) {
    00300          tmpbuf[x] = (float)tmp->buf[x+consumed] / 32768.0;
    00301       }
    00302       lpc10_encode(tmpbuf, bits, tmp->lpc10.enc);
    00303       build_bits(((unsigned char *)tmp->outbuf) + tmp->f.datalen, bits);
    00304       tmp->f.datalen += LPC10_BYTES_IN_COMPRESSED_FRAME;
    00305       tmp->f.samples += LPC10_SAMPLES_PER_FRAME;
    00306       /* Use one of the two left over bits to record if this is a 22 or 23 ms frame...
    00307          important for IAX use */
    00308       tmp->longer = 1 - tmp->longer;
    00309 #if 0 /* what the heck was this for? */
    00310       ((char *)(tmp->f.data))[consumed - 1] |= tmp->longer;
    00311 #endif
    00312       tmp->tail -= LPC10_SAMPLES_PER_FRAME;
    00313       consumed += LPC10_SAMPLES_PER_FRAME;
    00314    }
    00315    tmp->f.mallocd = 0;
    00316    tmp->f.offset = AST_FRIENDLY_OFFSET;
    00317    tmp->f.src = __PRETTY_FUNCTION__;
    00318    tmp->f.data = tmp->outbuf;
    00319    /* Move the data at the end of the buffer to the front */
    00320    if (tmp->tail)
    00321       memmove(tmp->buf, tmp->buf + consumed, tmp->tail * 2);
    00322 #if 0
    00323    /* Save a sample frame */
    00324    { static int samplefr = 0;
    00325    if (samplefr == 0) {
    00326       int fd;
    00327       fd = open("lpc10.example", O_WRONLY | O_CREAT, 0644);
    00328       write(fd, tmp->f.data, tmp->f.datalen);
    00329       close(fd);
    00330    }
    00331    samplefr++;
    00332    }
    00333 #endif
    00334    return &tmp->f;
    00335 }
    00336
    00337 static void lpc10_destroy(struct ast_translator_pvt *pvt)
    00338 {
    00339    /* Enc and DEC are both just allocated, so they can be freed */
    00340    free(pvt->lpc10.enc);
    00341    free(pvt);
    00342    localusecnt--;
    00343 }
    00344
    00345 static struct ast_translator lpc10tolin =
    00346    { "lpc10tolin",
    00347       AST_FORMAT_LPC10, AST_FORMAT_SLINEAR,
    00348       lpc10_dec_new,
    00349       lpc10tolin_framein,
    00350       lpc10tolin_frameout,
    00351       lpc10_destroy,
    00352       lpc10tolin_sample
    00353       };
    00354
    00355 static struct ast_translator lintolpc10 =
    00356    { "lintolpc10",
    00357       AST_FORMAT_SLINEAR, AST_FORMAT_LPC10,
    00358       lpc10_enc_new,
    00359       lintolpc10_framein,
    00360       lintolpc10_frameout,
    00361       lpc10_destroy,
    00362       lintolpc10_sample
    00363       };
    00364
    00365 static void parse_config(void)
    00366 {
    00367         struct ast_config *cfg;
    00368         struct ast_variable *var;
    00369         if ((cfg = ast_config_load("codecs.conf"))) {
    00370                 if ((var = ast_variable_browse(cfg, "plc"))) {
    00371                         while (var) {
    00372                                if (!strcasecmp(var->name, "genericplc")) {
    00373                                        useplc = ast_true(var->value) ? 1 : 0;
    00374                                        if (option_verbose > 2)
    00375                                                ast_verbose(VERBOSE_PREFIX_3 "codec_lpc10: %susing generic PLC\n", useplc ? "" : "not ");
    00376                                }
    00377                                var = var->next;
    00378                         }
    00379                 }
    00380       ast_config_destroy(cfg);
    00381         }
    00382 }
    00383
    00384 int reload(void)
    00385 {
    00386         parse_config();
    00387         return 0;
    00388 }
    00389
    00390
    00391 int unload_module(void)
    00392 {
    00393    int res;
    00394    ast_mutex_lock(&localuser_lock);
    00395    res = ast_unregister_translator(&lintolpc10);
    00396    if (!res)
    00397       res = ast_unregister_translator(&lpc10tolin);
    00398    if (localusecnt)
    00399       res = -1;
    00400    ast_mutex_unlock(&localuser_lock);
    00401    return res;
    00402 }
    00403
    00404 int load_module(void)
    00405 {
    00406    int res;
    00407    parse_config();
    00408    res=ast_register_translator(&lpc10tolin);
    00409    if (!res)
    00410       res=ast_register_translator(&lintolpc10);
    00411    else
    00412       ast_unregister_translator(&lpc10tolin);
    00413    return res;
    00414 }
    00415
    00416 char *description(void)
    00417 {
    00418    return tdesc;
    00419 }
    00420
    00421 int usecount(void)
    00422 {
    00423    int res;
    00424    STANDARD_USECOUNT(res);
    00425    return res;
    00426 }
    00427
    00428 char *key()
    00429 {
    00430    return ASTERISK_GPL_KEY;
    00431 }