Wed Oct 28 11:51:02 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 /*** MODULEINFO
00030    <depend>gsm</depend>
00031  ***/
00032 
00033 #include "asterisk.h"
00034 
00035 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 125386 $")
00036 
00037 #include "asterisk/translate.h"
00038 #include "asterisk/config.h"
00039 #include "asterisk/module.h"
00040 #include "asterisk/utils.h"
00041 
00042 #ifdef HAVE_GSM_HEADER
00043 #include "gsm.h"
00044 #elif defined(HAVE_GSM_GSM_HEADER)
00045 #include <gsm/gsm.h>
00046 #endif
00047 
00048 #include "../formats/msgsm.h"
00049 
00050 /* Sample frame data */
00051 #include "slin_gsm_ex.h"
00052 #include "gsm_slin_ex.h"
00053 
00054 #define BUFFER_SAMPLES  8000
00055 #define GSM_SAMPLES  160
00056 #define  GSM_FRAME_LEN  33
00057 #define  MSGSM_FRAME_LEN   65
00058 
00059 struct gsm_translator_pvt {   /* both gsm2lin and lin2gsm */
00060    gsm gsm;
00061    int16_t buf[BUFFER_SAMPLES];  /* lin2gsm, temporary storage */
00062 };
00063 
00064 static int gsm_new(struct ast_trans_pvt *pvt)
00065 {
00066    struct gsm_translator_pvt *tmp = pvt->pvt;
00067    
00068    return (tmp->gsm = gsm_create()) ? 0 : -1;
00069 }
00070 
00071 static struct ast_frame *lintogsm_sample(void)
00072 {
00073    static struct ast_frame f;
00074    f.frametype = AST_FRAME_VOICE;
00075    f.subclass = AST_FORMAT_SLINEAR;
00076    f.datalen = sizeof(slin_gsm_ex);
00077    /* Assume 8000 Hz */
00078    f.samples = sizeof(slin_gsm_ex)/2;
00079    f.mallocd = 0;
00080    f.offset = 0;
00081    f.src = __PRETTY_FUNCTION__;
00082    f.data.ptr = slin_gsm_ex;
00083    return &f;
00084 }
00085 
00086 static struct ast_frame *gsmtolin_sample(void)
00087 {
00088    static struct ast_frame f;
00089    f.frametype = AST_FRAME_VOICE;
00090    f.subclass = AST_FORMAT_GSM;
00091    f.datalen = sizeof(gsm_slin_ex);
00092    /* All frames are 20 ms long */
00093    f.samples = GSM_SAMPLES;
00094    f.mallocd = 0;
00095    f.offset = 0;
00096    f.src = __PRETTY_FUNCTION__;
00097    f.data.ptr = gsm_slin_ex;
00098    return &f;
00099 }
00100 
00101 /*! \brief decode and store in outbuf. */
00102 static int gsmtolin_framein(struct ast_trans_pvt *pvt, struct ast_frame *f)
00103 {
00104    struct gsm_translator_pvt *tmp = pvt->pvt;
00105    int x;
00106    int16_t *dst = pvt->outbuf.i16;
00107    /* guess format from frame len. 65 for MSGSM, 33 for regular GSM */
00108    int flen = (f->datalen % MSGSM_FRAME_LEN == 0) ?
00109       MSGSM_FRAME_LEN : GSM_FRAME_LEN;
00110 
00111    for (x=0; x < f->datalen; x += flen) {
00112       unsigned char data[2 * GSM_FRAME_LEN];
00113       unsigned char *src;
00114       int len;
00115       if (flen == MSGSM_FRAME_LEN) {
00116          len = 2*GSM_SAMPLES;
00117          src = data;
00118          /* Translate MSGSM format to Real GSM format before feeding in */
00119          /* XXX what's the point here! we should just work
00120           * on the full format.
00121           */
00122          conv65(f->data.ptr + x, data);
00123       } else {
00124          len = GSM_SAMPLES;
00125          src = f->data.ptr + x;
00126       }
00127       /* XXX maybe we don't need to check */
00128       if (pvt->samples + len > BUFFER_SAMPLES) {   
00129          ast_log(LOG_WARNING, "Out of buffer space\n");
00130          return -1;
00131       }
00132       if (gsm_decode(tmp->gsm, src, dst + pvt->samples)) {
00133          ast_log(LOG_WARNING, "Invalid GSM data (1)\n");
00134          return -1;
00135       }
00136       pvt->samples += GSM_SAMPLES;
00137       pvt->datalen += 2 * GSM_SAMPLES;
00138       if (flen == MSGSM_FRAME_LEN) {
00139          if (gsm_decode(tmp->gsm, data + GSM_FRAME_LEN, dst + pvt->samples)) {
00140             ast_log(LOG_WARNING, "Invalid GSM data (2)\n");
00141             return -1;
00142          }
00143          pvt->samples += GSM_SAMPLES;
00144          pvt->datalen += 2 * GSM_SAMPLES;
00145       }
00146    }
00147    return 0;
00148 }
00149 
00150 /*! \brief store samples into working buffer for later decode */
00151 static int lintogsm_framein(struct ast_trans_pvt *pvt, struct ast_frame *f)
00152 {
00153    struct gsm_translator_pvt *tmp = pvt->pvt;
00154 
00155    /* XXX We should look at how old the rest of our stream is, and if it
00156       is too old, then we should overwrite it entirely, otherwise we can
00157       get artifacts of earlier talk that do not belong */
00158    if (pvt->samples + f->samples > BUFFER_SAMPLES) {
00159       ast_log(LOG_WARNING, "Out of buffer space\n");
00160       return -1;
00161    }
00162    memcpy(tmp->buf + pvt->samples, f->data.ptr, f->datalen);
00163    pvt->samples += f->samples;
00164    return 0;
00165 }
00166 
00167 /*! \brief encode and produce a frame */
00168 static struct ast_frame *lintogsm_frameout(struct ast_trans_pvt *pvt)
00169 {
00170    struct gsm_translator_pvt *tmp = pvt->pvt;
00171    int datalen = 0;
00172    int samples = 0;
00173 
00174    /* We can't work on anything less than a frame in size */
00175    if (pvt->samples < GSM_SAMPLES)
00176       return NULL;
00177    while (pvt->samples >= GSM_SAMPLES) {
00178       /* Encode a frame of data */
00179       gsm_encode(tmp->gsm, tmp->buf + samples, (gsm_byte *) pvt->outbuf.c + datalen);
00180       datalen += GSM_FRAME_LEN;
00181       samples += GSM_SAMPLES;
00182       pvt->samples -= GSM_SAMPLES;
00183    }
00184 
00185    /* Move the data at the end of the buffer to the front */
00186    if (pvt->samples)
00187       memmove(tmp->buf, tmp->buf + samples, pvt->samples * 2);
00188 
00189    return ast_trans_frameout(pvt, datalen, samples);
00190 }
00191 
00192 static void gsm_destroy_stuff(struct ast_trans_pvt *pvt)
00193 {
00194    struct gsm_translator_pvt *tmp = pvt->pvt;
00195    if (tmp->gsm)
00196       gsm_destroy(tmp->gsm);
00197 }
00198 
00199 static struct ast_translator gsmtolin = {
00200    .name = "gsmtolin", 
00201    .srcfmt = AST_FORMAT_GSM,
00202    .dstfmt = AST_FORMAT_SLINEAR,
00203    .newpvt = gsm_new,
00204    .framein = gsmtolin_framein,
00205    .destroy = gsm_destroy_stuff,
00206    .sample = gsmtolin_sample,
00207    .buffer_samples = BUFFER_SAMPLES,
00208    .buf_size = BUFFER_SAMPLES * 2,
00209    .desc_size = sizeof (struct gsm_translator_pvt ),
00210    .plc_samples = GSM_SAMPLES,
00211 };
00212 
00213 static struct ast_translator lintogsm = {
00214    .name = "lintogsm", 
00215    .srcfmt = AST_FORMAT_SLINEAR,
00216    .dstfmt = AST_FORMAT_GSM,
00217    .newpvt = gsm_new,
00218    .framein = lintogsm_framein,
00219    .frameout = lintogsm_frameout,
00220    .destroy = gsm_destroy_stuff,
00221    .sample = lintogsm_sample,
00222    .desc_size = sizeof (struct gsm_translator_pvt ),
00223    .buf_size = (BUFFER_SAMPLES * GSM_FRAME_LEN + GSM_SAMPLES - 1)/GSM_SAMPLES,
00224 };
00225 
00226 
00227 static int parse_config(int reload)
00228 {
00229    struct ast_variable *var;
00230    struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
00231    struct ast_config *cfg = ast_config_load("codecs.conf", config_flags);
00232    if (cfg == NULL)
00233       return 0;
00234    if (cfg == CONFIG_STATUS_FILEUNCHANGED) 
00235       return 0;
00236    for (var = ast_variable_browse(cfg, "plc"); var; var = var->next) {
00237           if (!strcasecmp(var->name, "genericplc")) {
00238              gsmtolin.useplc = ast_true(var->value) ? 1 : 0;
00239             ast_verb(3, "codec_gsm: %susing generic PLC\n", gsmtolin.useplc ? "" : "not ");
00240           }
00241    }
00242    ast_config_destroy(cfg);
00243    return 0;
00244 }
00245 
00246 /*! \brief standard module glue */
00247 static int reload(void)
00248 {
00249    if (parse_config(1)) {
00250       return AST_MODULE_LOAD_DECLINE;
00251    }
00252    return AST_MODULE_LOAD_SUCCESS;
00253 }
00254 
00255 static int unload_module(void)
00256 {
00257    int res;
00258 
00259    res = ast_unregister_translator(&lintogsm);
00260    if (!res)
00261       res = ast_unregister_translator(&gsmtolin);
00262 
00263    return res;
00264 }
00265 
00266 static int load_module(void)
00267 {
00268    int res;
00269 
00270    if (parse_config(0))
00271       return AST_MODULE_LOAD_DECLINE;
00272    res = ast_register_translator(&gsmtolin);
00273    if (!res) 
00274       res=ast_register_translator(&lintogsm);
00275    else
00276       ast_unregister_translator(&gsmtolin);
00277    if (res) 
00278       return AST_MODULE_LOAD_FAILURE;
00279    return AST_MODULE_LOAD_SUCCESS;
00280 }
00281 
00282 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "GSM Coder/Decoder",
00283       .load = load_module,
00284       .unload = unload_module,
00285       .reload = reload,
00286           );

Generated on Wed Oct 28 11:51:02 2009 for Asterisk - the Open Source PBX by  doxygen 1.5.6