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 }

Generated on Wed Oct 28 15:47:53 2009 for Asterisk - the Open Source PBX by  doxygen 1.5.6