Asterisk.org: Developer Documentation (28 Oct 2009)

Wed Oct 28 15:47:53 2009

## Asterisk developer's documentation

# codec_ilbc.c

Go to the documentation of this file.

    00001 /*
    00002  * Asterisk -- An open source telephony toolkit.
    00003  *
    00004  * The iLBC code is from The IETF code base and is copyright The Internet Society (2004)
    00005  *
    00006  * Copyright (C) 1999 - 2005, Digium, Inc.
    00007  *
    00008  * Mark Spencer <markster@digium.com>
    00009  *
    00010  * See http://www.asterisk.org for more information about
    00011  * the Asterisk project. Please do not directly contact
    00012  * any of the maintainers of this project for assistance;
    00013  * the project provides a web site, mailing lists and IRC
    00014  * channels for your use.
    00015  *
    00016  * This program is free software, distributed under the terms of
    00017  * the GNU General Public License Version 2. See the LICENSE file
    00018  * at the top of the source tree.
    00019  */
    00020
    00021 /*! \file
    00022  *
    00023  * \brief Translate between signed linear and Internet Low Bitrate Codec
    00024  *
    00025  * \ingroup codecs
    00026  */
    00027
    00028 #include <fcntl.h>
    00029 #include <stdlib.h>
    00030 #include <unistd.h>
    00031 #include <netinet/in.h>
    00032 #include <string.h>
    00033 #include <stdio.h>
    00034
    00035 #include "asterisk.h"
    00036
    00037 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 7221 $")
    00038
    00039 #include "asterisk/lock.h"
    00040 #include "asterisk/translate.h"
    00041 #include "asterisk/module.h"
    00042 #include "asterisk/logger.h"
    00043 #include "asterisk/channel.h"
    00044
    00045 #include "ilbc/iLBC_encode.h"
    00046 #include "ilbc/iLBC_decode.h"
    00047
    00048 /* Sample frame data */
    00049 #include "slin_ilbc_ex.h"
    00050 #include "ilbc_slin_ex.h"
    00051
    00052 #define USE_ILBC_ENHANCER  0
    00053 #define ILBC_MS         30
    00054 /* #define ILBC_MS         20 */
    00055
    00056 AST_MUTEX_DEFINE_STATIC(localuser_lock);
    00057 static int localusecnt=0;
    00058
    00059 static char *tdesc = "iLBC/PCM16 (signed linear) Codec Translator";
    00060
    00061 struct ast_translator_pvt {
    00062    iLBC_Enc_Inst_t enc;
    00063    iLBC_Dec_Inst_t dec;
    00064    struct ast_frame f;
    00065    /* Space to build offset */
    00066    char offset[AST_FRIENDLY_OFFSET];
    00067    /* Buffer for our outgoing frame */
    00068    short outbuf[8000];
    00069    /* Enough to store a full second */
    00070    short buf[8000];
    00071    int tail;
    00072 };
    00073
    00074 #define ilbc_coder_pvt ast_translator_pvt
    00075
    00076 static struct ast_translator_pvt *lintoilbc_new(void)
    00077 {
    00078    struct ilbc_coder_pvt *tmp;
    00079    tmp = malloc(sizeof(struct ilbc_coder_pvt));
    00080    if (tmp) {
    00081       /* Shut valgrind up */
    00082       memset(&tmp->enc, 0, sizeof(tmp->enc));
    00083       initEncode(&tmp->enc, ILBC_MS);
    00084       tmp->tail = 0;
    00085       localusecnt++;
    00086    }
    00087    return tmp;
    00088 }
    00089
    00090 static struct ast_translator_pvt *ilbctolin_new(void)
    00091 {
    00092    struct ilbc_coder_pvt *tmp;
    00093    tmp = malloc(sizeof(struct ilbc_coder_pvt));
    00094    if (tmp) {
    00095       /* Shut valgrind up */
    00096       memset(&tmp->dec, 0, sizeof(tmp->dec));
    00097       initDecode(&tmp->dec, ILBC_MS, USE_ILBC_ENHANCER);
    00098       tmp->tail = 0;
    00099       localusecnt++;
    00100    }
    00101    return tmp;
    00102 }
    00103
    00104 static struct ast_frame *lintoilbc_sample(void)
    00105 {
    00106    static struct ast_frame f;
    00107    f.frametype = AST_FRAME_VOICE;
    00108    f.subclass = AST_FORMAT_SLINEAR;
    00109    f.datalen = sizeof(slin_ilbc_ex);
    00110    /* Assume 8000 Hz */
    00111    f.samples = sizeof(slin_ilbc_ex)/2;
    00112    f.mallocd = 0;
    00113    f.offset = 0;
    00114    f.src = __PRETTY_FUNCTION__;
    00115    f.data = slin_ilbc_ex;
    00116    return &f;
    00117 }
    00118
    00119 static struct ast_frame *ilbctolin_sample(void)
    00120 {
    00121    static struct ast_frame f;
    00122    f.frametype = AST_FRAME_VOICE;
    00123    f.subclass = AST_FORMAT_ILBC;
    00124    f.datalen = sizeof(ilbc_slin_ex);
    00125    /* All frames are 30 ms long */
    00126    f.samples = 240;
    00127    f.mallocd = 0;
    00128    f.offset = 0;
    00129    f.src = __PRETTY_FUNCTION__;
    00130    f.data = ilbc_slin_ex;
    00131    return &f;
    00132 }
    00133
    00134 static struct ast_frame *ilbctolin_frameout(struct ast_translator_pvt *tmp)
    00135 {
    00136    if (!tmp->tail)
    00137       return NULL;
    00138    /* Signed linear is no particular frame size, so just send whatever
    00139       we have in the buffer in one lump sum */
    00140    tmp->f.frametype = AST_FRAME_VOICE;
    00141    tmp->f.subclass = AST_FORMAT_SLINEAR;
    00142    tmp->f.datalen = tmp->tail * 2;
    00143    /* Assume 8000 Hz */
    00144    tmp->f.samples = tmp->tail;
    00145    tmp->f.mallocd = 0;
    00146    tmp->f.offset = AST_FRIENDLY_OFFSET;
    00147    tmp->f.src = __PRETTY_FUNCTION__;
    00148    tmp->f.data = tmp->buf;
    00149    /* Reset tail pointer */
    00150    tmp->tail = 0;
    00151
    00152    return &tmp->f;
    00153 }
    00154
    00155 static int ilbctolin_framein(struct ast_translator_pvt *tmp, struct ast_frame *f)
    00156 {
    00157    /* Assuming there's space left, decode into the current buffer at
    00158       the tail location.  Read in as many frames as there are */
    00159    int x,i;
    00160    float tmpf[240];
    00161
    00162    if (f->datalen == 0) { /* native PLC */
    00163       if (tmp->tail + 240 < sizeof(tmp->buf)/2) {
    00164          iLBC_decode(tmpf, NULL, &tmp->dec, 0);
    00165          for (i=0;i<240;i++)
    00166             tmp->buf[tmp->tail + i] = tmpf[i];
    00167          tmp->tail+=240;
    00168       } else {
    00169          ast_log(LOG_WARNING, "Out of buffer space\n");
    00170          return -1;
    00171       }
    00172    }
    00173
    00174    if (f->datalen % 50) {
    00175       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);
    00176       return -1;
    00177    }
    00178
    00179    for (x=0;x<f->datalen;x+=50) {
    00180       if (tmp->tail + 240 < sizeof(tmp->buf)/2) {
    00181          iLBC_decode(tmpf, f->data + x, &tmp->dec, 1);
    00182          for (i=0;i<240;i++)
    00183             tmp->buf[tmp->tail + i] = tmpf[i];
    00184          tmp->tail+=240;
    00185       } else {
    00186          ast_log(LOG_WARNING, "Out of buffer space\n");
    00187          return -1;
    00188       }
    00189    }
    00190    return 0;
    00191 }
    00192
    00193 static int lintoilbc_framein(struct ast_translator_pvt *tmp, struct ast_frame *f)
    00194 {
    00195    /* Just add the frames to our stream */
    00196    /* XXX We should look at how old the rest of our stream is, and if it
    00197       is too old, then we should overwrite it entirely, otherwise we can
    00198       get artifacts of earlier talk that do not belong */
    00199    if (tmp->tail + f->datalen/2 < sizeof(tmp->buf) / 2) {
    00200       memcpy((tmp->buf + tmp->tail), f->data, f->datalen);
    00201       tmp->tail += f->datalen/2;
    00202    } else {
    00203       ast_log(LOG_WARNING, "Out of buffer space\n");
    00204       return -1;
    00205    }
    00206    return 0;
    00207 }
    00208
    00209 static struct ast_frame *lintoilbc_frameout(struct ast_translator_pvt *tmp)
    00210 {
    00211    int x=0,i;
    00212    float tmpf[240];
    00213    /* We can't work on anything less than a frame in size */
    00214    if (tmp->tail < 240)
    00215       return NULL;
    00216    tmp->f.frametype = AST_FRAME_VOICE;
    00217    tmp->f.subclass = AST_FORMAT_ILBC;
    00218    tmp->f.mallocd = 0;
    00219    tmp->f.offset = AST_FRIENDLY_OFFSET;
    00220    tmp->f.src = __PRETTY_FUNCTION__;
    00221    tmp->f.data = tmp->outbuf;
    00222    while(tmp->tail >= 240) {
    00223       if ((x+1) * 50 >= sizeof(tmp->outbuf)) {
    00224          ast_log(LOG_WARNING, "Out of buffer space\n");
    00225          break;
    00226       }
    00227       for (i=0;i<240;i++)
    00228          tmpf[i] = tmp->buf[i];
    00229       /* Encode a frame of data */
    00230       iLBC_encode(((unsigned char *)(tmp->outbuf)) + (x * 50), tmpf, &tmp->enc);
    00231       /* Assume 8000 Hz -- 20 ms */
    00232       tmp->tail -= 240;
    00233       /* Move the data at the end of the buffer to the front */
    00234       if (tmp->tail)
    00235          memmove(tmp->buf, tmp->buf + 240, tmp->tail * 2);
    00236       x++;
    00237    }
    00238    tmp->f.datalen = x * 50;
    00239    tmp->f.samples = x * 240;
    00240 #if 0
    00241    {
    00242       static int fd = -1;
    00243       if (fd == -1) {
    00244          fd = open("ilbc.out", O_CREAT|O_TRUNC|O_WRONLY, 0666);
    00245          write(fd, tmp->f.data, tmp->f.datalen);
    00246          close(fd);
    00247       }
    00248    }
    00249 #endif
    00250    return &tmp->f;
    00251 }
    00252
    00253 static void ilbc_destroy_stuff(struct ast_translator_pvt *pvt)
    00254 {
    00255    free(pvt);
    00256    localusecnt--;
    00257 }
    00258
    00259 static struct ast_translator ilbctolin =
    00260    { "ilbctolin",
    00261       AST_FORMAT_ILBC, AST_FORMAT_SLINEAR,
    00262       ilbctolin_new,
    00263       ilbctolin_framein,
    00264       ilbctolin_frameout,
    00265       ilbc_destroy_stuff,
    00266       ilbctolin_sample
    00267       };
    00268
    00269 static struct ast_translator lintoilbc =
    00270    { "lintoilbc",
    00271       AST_FORMAT_SLINEAR, AST_FORMAT_ILBC,
    00272       lintoilbc_new,
    00273       lintoilbc_framein,
    00274       lintoilbc_frameout,
    00275       ilbc_destroy_stuff,
    00276       lintoilbc_sample
    00277       };
    00278
    00279 int unload_module(void)
    00280 {
    00281    int res;
    00282    ast_mutex_lock(&localuser_lock);
    00283    res = ast_unregister_translator(&lintoilbc);
    00284    if (!res)
    00285       res = ast_unregister_translator(&ilbctolin);
    00286    if (localusecnt)
    00287       res = -1;
    00288    ast_mutex_unlock(&localuser_lock);
    00289    return res;
    00290 }
    00291
    00292 int load_module(void)
    00293 {
    00294    int res;
    00295    res=ast_register_translator(&ilbctolin);
    00296    if (!res)
    00297       res=ast_register_translator(&lintoilbc);
    00298    else
    00299       ast_unregister_translator(&ilbctolin);
    00300    return res;
    00301 }
    00302
    00303 char *description(void)
    00304 {
    00305    return tdesc;
    00306 }
    00307
    00308 int usecount(void)
    00309 {
    00310    int res;
    00311    STANDARD_USECOUNT(res);
    00312    return res;
    00313 }
    00314
    00315 char *key()
    00316 {
    00317    return ASTERISK_GPL_KEY;
    00318 }