Asterisk.org: Developer Documentation (28 Oct 2009)

Wed Oct 28 15:47:53 2009

## Asterisk developer's documentation

# codec_gsm.c

Go to the documentation of this file.

    00001 /*
    00002  * Asterisk -- An open source telephony toolkit.
    00003  *
    00004  * The GSM code is from TOAST.  Copyright information for that package is available
    00005  * in the GSM directory.
    00006  *
    00007  * Copyright (C) 1999 - 2005, Digium, Inc.
    00008  *
    00009  * Mark Spencer <markster@digium.com>
    00010  *
    00011  * See http://www.asterisk.org for more information about
    00012  * the Asterisk project. Please do not directly contact
    00013  * any of the maintainers of this project for assistance;
    00014  * the project provides a web site, mailing lists and IRC
    00015  * channels for your use.
    00016  *
    00017  * This program is free software, distributed under the terms of
    00018  * the GNU General Public License Version 2. See the LICENSE file
    00019  * at the top of the source tree.
    00020  */
    00021
    00022 /*! \file
    00023  *
    00024  * \brief Translate between signed linear and Global System for Mobile Communications (GSM)
    00025  *
    00026  * \ingroup codecs
    00027  */
    00028
    00029 #include <fcntl.h>
    00030 #include <stdlib.h>
    00031 #include <unistd.h>
    00032 #include <netinet/in.h>
    00033 #include <string.h>
    00034 #include <stdio.h>
    00035
    00036 #include "asterisk.h"
    00037
    00038 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 7221 $")
    00039
    00040 #include "asterisk/lock.h"
    00041 #include "asterisk/translate.h"
    00042 #include "asterisk/config.h"
    00043 #include "asterisk/options.h"
    00044 #include "asterisk/module.h"
    00045 #include "asterisk/logger.h"
    00046 #include "asterisk/channel.h"
    00047
    00048 #include "gsm/inc/gsm.h"
    00049 #include "../formats/msgsm.h"
    00050
    00051 /* Sample frame data */
    00052 #include "slin_gsm_ex.h"
    00053 #include "gsm_slin_ex.h"
    00054
    00055 AST_MUTEX_DEFINE_STATIC(localuser_lock);
    00056 static int localusecnt=0;
    00057
    00058 static char *tdesc = "GSM/PCM16 (signed linear) Codec Translator";
    00059
    00060 static int useplc = 0;
    00061
    00062 struct ast_translator_pvt {
    00063    gsm gsm;
    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    plc_state_t plc;
    00073 };
    00074
    00075 #define gsm_coder_pvt ast_translator_pvt
    00076
    00077 static struct ast_translator_pvt *gsm_new(void)
    00078 {
    00079    struct gsm_coder_pvt *tmp;
    00080    tmp = malloc(sizeof(struct gsm_coder_pvt));
    00081    if (tmp) {
    00082       if (!(tmp->gsm = gsm_create())) {
    00083          free(tmp);
    00084          tmp = NULL;
    00085       }
    00086       tmp->tail = 0;
    00087       plc_init(&tmp->plc);
    00088       localusecnt++;
    00089    }
    00090    return tmp;
    00091 }
    00092
    00093 static struct ast_frame *lintogsm_sample(void)
    00094 {
    00095    static struct ast_frame f;
    00096    f.frametype = AST_FRAME_VOICE;
    00097    f.subclass = AST_FORMAT_SLINEAR;
    00098    f.datalen = sizeof(slin_gsm_ex);
    00099    /* Assume 8000 Hz */
    00100    f.samples = sizeof(slin_gsm_ex)/2;
    00101    f.mallocd = 0;
    00102    f.offset = 0;
    00103    f.src = __PRETTY_FUNCTION__;
    00104    f.data = slin_gsm_ex;
    00105    return &f;
    00106 }
    00107
    00108 static struct ast_frame *gsmtolin_sample(void)
    00109 {
    00110    static struct ast_frame f;
    00111    f.frametype = AST_FRAME_VOICE;
    00112    f.subclass = AST_FORMAT_GSM;
    00113    f.datalen = sizeof(gsm_slin_ex);
    00114    /* All frames are 20 ms long */
    00115    f.samples = 160;
    00116    f.mallocd = 0;
    00117    f.offset = 0;
    00118    f.src = __PRETTY_FUNCTION__;
    00119    f.data = gsm_slin_ex;
    00120    return &f;
    00121 }
    00122
    00123 static struct ast_frame *gsmtolin_frameout(struct ast_translator_pvt *tmp)
    00124 {
    00125    if (!tmp->tail)
    00126       return NULL;
    00127    /* Signed linear is no particular frame size, so just send whatever
    00128       we have in the buffer in one lump sum */
    00129    tmp->f.frametype = AST_FRAME_VOICE;
    00130    tmp->f.subclass = AST_FORMAT_SLINEAR;
    00131    tmp->f.datalen = tmp->tail * 2;
    00132    /* Assume 8000 Hz */
    00133    tmp->f.samples = tmp->tail;
    00134    tmp->f.mallocd = 0;
    00135    tmp->f.offset = AST_FRIENDLY_OFFSET;
    00136    tmp->f.src = __PRETTY_FUNCTION__;
    00137    tmp->f.data = tmp->buf;
    00138    /* Reset tail pointer */
    00139    tmp->tail = 0;
    00140
    00141    return &tmp->f;
    00142 }
    00143
    00144 static int gsmtolin_framein(struct ast_translator_pvt *tmp, struct ast_frame *f)
    00145 {
    00146    /* Assuming there's space left, decode into the current buffer at
    00147       the tail location.  Read in as many frames as there are */
    00148    int x;
    00149    unsigned char data[66];
    00150    int msgsm=0;
    00151
    00152    if(f->datalen == 0) { /* perform PLC with nominal framesize of 20ms/160 samples */
    00153          if((tmp->tail + 160) > sizeof(tmp->buf) / 2) {
    00154         ast_log(LOG_WARNING, "Out of buffer space\n");
    00155         return -1;
    00156          }
    00157          if(useplc) {
    00158         plc_fillin(&tmp->plc, tmp->buf+tmp->tail, 160);
    00159         tmp->tail += 160;
    00160          }
    00161          return 0;
    00162    }
    00163
    00164    if ((f->datalen % 33) && (f->datalen % 65)) {
    00165       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);
    00166       return -1;
    00167    }
    00168
    00169    if (f->datalen % 65 == 0)
    00170       msgsm = 1;
    00171
    00172    for (x=0;x<f->datalen;x+=(msgsm ? 65 : 33)) {
    00173       if (msgsm) {
    00174          /* Translate MSGSM format to Real GSM format before feeding in */
    00175          conv65(f->data + x, data);
    00176          if (tmp->tail + 320 < sizeof(tmp->buf)/2) {
    00177             if (gsm_decode(tmp->gsm, data, tmp->buf + tmp->tail)) {
    00178                ast_log(LOG_WARNING, "Invalid GSM data (1)\n");
    00179                return -1;
    00180             }
    00181             tmp->tail+=160;
    00182             if (gsm_decode(tmp->gsm, data + 33, tmp->buf + tmp->tail)) {
    00183                ast_log(LOG_WARNING, "Invalid GSM data (2)\n");
    00184                return -1;
    00185             }
    00186             tmp->tail+=160;
    00187          } else {
    00188             ast_log(LOG_WARNING, "Out of (MS) buffer space\n");
    00189             return -1;
    00190          }
    00191       } else {
    00192          if (tmp->tail + 160 < sizeof(tmp->buf)/2) {
    00193             if (gsm_decode(tmp->gsm, f->data + x, tmp->buf + tmp->tail)) {
    00194                ast_log(LOG_WARNING, "Invalid GSM data\n");
    00195                return -1;
    00196             }
    00197             tmp->tail+=160;
    00198          } else {
    00199             ast_log(LOG_WARNING, "Out of buffer space\n");
    00200             return -1;
    00201          }
    00202       }
    00203    }
    00204
    00205    /* just add the last 20ms frame; there must have been at least one */
    00206    if(useplc) plc_rx(&tmp->plc, tmp->buf+tmp->tail-160, 160);
    00207
    00208    return 0;
    00209 }
    00210
    00211 static int lintogsm_framein(struct ast_translator_pvt *tmp, struct ast_frame *f)
    00212 {
    00213    /* Just add the frames to our stream */
    00214    /* XXX We should look at how old the rest of our stream is, and if it
    00215       is too old, then we should overwrite it entirely, otherwise we can
    00216       get artifacts of earlier talk that do not belong */
    00217    if (tmp->tail + f->datalen/2 < sizeof(tmp->buf) / 2) {
    00218       memcpy((tmp->buf + tmp->tail), f->data, f->datalen);
    00219       tmp->tail += f->datalen/2;
    00220    } else {
    00221       ast_log(LOG_WARNING, "Out of buffer space\n");
    00222       return -1;
    00223    }
    00224    return 0;
    00225 }
    00226
    00227 static struct ast_frame *lintogsm_frameout(struct ast_translator_pvt *tmp)
    00228 {
    00229    int x=0;
    00230    /* We can't work on anything less than a frame in size */
    00231    if (tmp->tail < 160)
    00232       return NULL;
    00233    tmp->f.frametype = AST_FRAME_VOICE;
    00234    tmp->f.subclass = AST_FORMAT_GSM;
    00235    tmp->f.mallocd = 0;
    00236    tmp->f.offset = AST_FRIENDLY_OFFSET;
    00237    tmp->f.src = __PRETTY_FUNCTION__;
    00238    tmp->f.data = tmp->outbuf;
    00239    while(tmp->tail >= 160) {
    00240       if ((x+1) * 33 >= sizeof(tmp->outbuf)) {
    00241          ast_log(LOG_WARNING, "Out of buffer space\n");
    00242          break;
    00243       }
    00244       /* Encode a frame of data */
    00245       gsm_encode(tmp->gsm, tmp->buf, ((gsm_byte *) tmp->outbuf) + (x * 33));
    00246       /* Assume 8000 Hz -- 20 ms */
    00247       tmp->tail -= 160;
    00248       /* Move the data at the end of the buffer to the front */
    00249       if (tmp->tail)
    00250          memmove(tmp->buf, tmp->buf + 160, tmp->tail * 2);
    00251       x++;
    00252    }
    00253    tmp->f.datalen = x * 33;
    00254    tmp->f.samples = x * 160;
    00255    return &tmp->f;
    00256 }
    00257
    00258 static void gsm_destroy_stuff(struct ast_translator_pvt *pvt)
    00259 {
    00260    if (pvt->gsm)
    00261       gsm_destroy(pvt->gsm);
    00262    free(pvt);
    00263    localusecnt--;
    00264 }
    00265
    00266 static struct ast_translator gsmtolin =
    00267    { "gsmtolin",
    00268       AST_FORMAT_GSM, AST_FORMAT_SLINEAR,
    00269       gsm_new,
    00270       gsmtolin_framein,
    00271       gsmtolin_frameout,
    00272       gsm_destroy_stuff,
    00273       gsmtolin_sample
    00274       };
    00275
    00276 static struct ast_translator lintogsm =
    00277    { "lintogsm",
    00278       AST_FORMAT_SLINEAR, AST_FORMAT_GSM,
    00279       gsm_new,
    00280       lintogsm_framein,
    00281       lintogsm_frameout,
    00282       gsm_destroy_stuff,
    00283       lintogsm_sample
    00284       };
    00285
    00286
    00287 static void parse_config(void)
    00288 {
    00289    struct ast_config *cfg;
    00290    struct ast_variable *var;
    00291    if ((cfg = ast_config_load("codecs.conf"))) {
    00292       if ((var = ast_variable_browse(cfg, "plc"))) {
    00293          while (var) {
    00294                 if (!strcasecmp(var->name, "genericplc")) {
    00295                    useplc = ast_true(var->value) ? 1 : 0;
    00296                    if (option_verbose > 2)
    00297                       ast_verbose(VERBOSE_PREFIX_3 "codec_gsm: %susing generic PLC\n", useplc ? "" : "not ");
    00298                 }
    00299                 var = var->next;
    00300          }
    00301       }
    00302       ast_config_destroy(cfg);
    00303    }
    00304 }
    00305
    00306 int reload(void)
    00307 {
    00308    parse_config();
    00309    return 0;
    00310 }
    00311
    00312 int unload_module(void)
    00313 {
    00314    int res;
    00315    ast_mutex_lock(&localuser_lock);
    00316    res = ast_unregister_translator(&lintogsm);
    00317    if (!res)
    00318       res = ast_unregister_translator(&gsmtolin);
    00319    if (localusecnt)
    00320       res = -1;
    00321    ast_mutex_unlock(&localuser_lock);
    00322    return res;
    00323 }
    00324
    00325 int load_module(void)
    00326 {
    00327    int res;
    00328    parse_config();
    00329    res=ast_register_translator(&gsmtolin);
    00330    if (!res)
    00331       res=ast_register_translator(&lintogsm);
    00332    else
    00333       ast_unregister_translator(&gsmtolin);
    00334    return res;
    00335 }
    00336
    00337 char *description(void)
    00338 {
    00339    return tdesc;
    00340 }
    00341
    00342 int usecount(void)
    00343 {
    00344    int res;
    00345    STANDARD_USECOUNT(res);
    00346    return res;
    00347 }
    00348
    00349 char *key()
    00350 {
    00351    return ASTERISK_GPL_KEY;
    00352 }