Mon Sep 18 09:13:14 2006

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 }

Generated on Mon Sep 18 09:13:14 2006 for Asterisk - the Open Source PBX by  doxygen 1.4.7