Codename Pineapple

Home page | Mailing list | Docs

Last updated: Sat Feb 3 05:00:48 2007

Asterisk developer's documentation :: Codename Pineapple


frame.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  * See http://www.asterisk.org for more information about
00009  * the Asterisk project. Please do not directly contact
00010  * any of the maintainers of this project for assistance;
00011  * the project provides a web site, mailing lists and IRC
00012  * channels for your use.
00013  *
00014  * This program is free software, distributed under the terms of
00015  * the GNU General Public License Version 2. See the LICENSE file
00016  * at the top of the source tree.
00017  */
00018 
00019 /*! \file
00020  *
00021  * \brief Frame and codec manipulation routines
00022  *
00023  * \author Mark Spencer <markster@digium.com> 
00024  */
00025 
00026 #include "asterisk.h"
00027 
00028 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 51499 $")
00029 
00030 #include <stdlib.h>
00031 #include <unistd.h>
00032 #include <string.h>
00033 #include <errno.h>
00034 #include <stdio.h>
00035 
00036 #include "asterisk/lock.h"
00037 #include "asterisk/frame.h"
00038 #include "asterisk/logger.h"
00039 #include "asterisk/options.h"
00040 #include "asterisk/channel.h"
00041 #include "asterisk/cli.h"
00042 #include "asterisk/term.h"
00043 #include "asterisk/utils.h"
00044 #include "asterisk/threadstorage.h"
00045 #include "asterisk/linkedlists.h"
00046 
00047 #ifdef TRACE_FRAMES
00048 static int headers;
00049 static AST_LIST_HEAD_STATIC(headerlist, ast_frame);
00050 #endif
00051 
00052 #if !defined(LOW_MEMORY)
00053 static void frame_cache_cleanup(void *data);
00054 
00055 /*! \brief A per-thread cache of frame headers */
00056 AST_THREADSTORAGE_CUSTOM(frame_cache, NULL, frame_cache_cleanup);
00057 
00058 /*! 
00059  * \brief Maximum ast_frame cache size
00060  *
00061  * In most cases where the frame header cache will be useful, the size
00062  * of the cache will stay very small.  However, it is not always the case that
00063  * the same thread that allocates the frame will be the one freeing them, so
00064  * sometimes a thread will never have any frames in its cache, or the cache
00065  * will never be pulled from.  For the latter case, we limit the maximum size. 
00066  */ 
00067 #define FRAME_CACHE_MAX_SIZE  10
00068 
00069 /*! \brief This is just so ast_frames, a list head struct for holding a list of
00070  *  ast_frame structures, is defined. */
00071 AST_LIST_HEAD_NOLOCK(ast_frames, ast_frame);
00072 
00073 struct ast_frame_cache {
00074    struct ast_frames list;
00075    size_t size;
00076 };
00077 #endif
00078 
00079 #define SMOOTHER_SIZE 8000
00080 
00081 enum frame_type {
00082    TYPE_HIGH,     /* 0x0 */
00083    TYPE_LOW,      /* 0x1 */
00084    TYPE_SILENCE,  /* 0x2 */
00085    TYPE_DONTSEND  /* 0x3 */
00086 };
00087 
00088 #define TYPE_MASK 0x3
00089 
00090 struct ast_smoother {
00091    int size;
00092    int format;
00093    int readdata;
00094    int optimizablestream;
00095    int flags;
00096    float samplesperbyte;
00097    struct ast_frame f;
00098    struct timeval delivery;
00099    char data[SMOOTHER_SIZE];
00100    char framedata[SMOOTHER_SIZE + AST_FRIENDLY_OFFSET];
00101    struct ast_frame *opt;
00102    int len;
00103 };
00104 
00105 /*! \brief Definition of supported media formats (codecs) */
00106 static struct ast_format_list AST_FORMAT_LIST[] = {               /*!< Bit number: comment  - Bit numbers are hard coded in show_codec() */
00107    { 1, AST_FORMAT_G723_1 , "g723" , "G.723.1", 20, 30, 300, 30, 30 },  /*!<  1 */
00108    { 1, AST_FORMAT_GSM, "gsm" , "GSM", 33, 20, 300, 20, 20 },     /*!<  2: codec_gsm.c */
00109    { 1, AST_FORMAT_ULAW, "ulaw", "G.711 u-law", 80, 10, 150, 10, 20 },  /*!<  3: codec_ulaw.c */
00110    { 1, AST_FORMAT_ALAW, "alaw", "G.711 A-law", 80, 10, 150, 10, 20 },  /*!<  4: codec_alaw.c */
00111    { 1, AST_FORMAT_G726, "g726", "G.726 RFC3551", 40, 10, 300, 10, 20 },   /*!<  5: codec_g726.c */
00112    { 1, AST_FORMAT_ADPCM, "adpcm" , "ADPCM", 40, 10, 300, 10, 20 },  /*!<  6: codec_adpcm.c */
00113    { 1, AST_FORMAT_SLINEAR, "slin", "16 bit Signed Linear PCM", 160, 10, 70, 10, 20, AST_SMOOTHER_FLAG_BE },   /*!< 7 */
00114    { 1, AST_FORMAT_LPC10, "lpc10", "LPC10", 7, 20, 20, 20, 20 },     /*!<  8: codec_lpc10.c */ 
00115    { 1, AST_FORMAT_G729A, "g729", "G.729A", 10, 10, 230, 10, 20, AST_SMOOTHER_FLAG_G729 },   /*!<  9: Binary commercial distribution */
00116    { 1, AST_FORMAT_SPEEX, "speex", "SpeeX", 10, 10, 60, 10, 20 },    /*!< 10: codec_speex.c */
00117    { 1, AST_FORMAT_ILBC, "ilbc", "iLBC", 50, 30, 30, 30, 30 },    /*!< 11: codec_ilbc.c */ /* inc=30ms - workaround */
00118    { 1, AST_FORMAT_G726_AAL2, "g726aal2", "G.726 AAL2", 40, 10, 300, 10, 20 },   /*!<  12: codec_g726.c */
00119    { 1, AST_FORMAT_G722, "g722", "G722"},             /*!< 13 */
00120    { 0, 0, "nothing", "undefined" },
00121    { 0, 0, "nothing", "undefined" },
00122    { 0, 0, "nothing", "undefined" },
00123    { 0, 0, "nothing", "undefined" },
00124    { 0, AST_FORMAT_MAX_AUDIO, "maxaudio", "Maximum audio format" },  
00125    { 1, AST_FORMAT_JPEG, "jpeg", "JPEG image"}, /*!< 17: See format_jpeg.c */
00126    { 1, AST_FORMAT_PNG, "png", "PNG image"}, /*!< 18: Image format */
00127    { 1, AST_FORMAT_H261, "h261", "H.261 Video" },  /*!< 19: H.261 Video Passthrough */
00128    { 1, AST_FORMAT_H263, "h263", "H.263 Video" },  /*!< 20: H.263 Passthrough support, see format_h263.c */
00129    { 1, AST_FORMAT_H263_PLUS, "h263p", "H.263+ Video" }, /*!< 21: H.263plus passthrough support See format_h263.c */
00130    { 1, AST_FORMAT_H264, "h264", "H.264 Video" },  /*!< 22: Passthrough support, see format_h263.c */
00131    { 1, AST_FORMAT_MP4_VIDEO, "mpeg4", "MPEG4 Video" }, /*!< Passthrough support for MPEG4 */
00132    { 0, 0, "nothing", "undefined" },
00133    { 0, 0, "nothing", "undefined" },
00134    { 0, 0, "nothing", "undefined" },
00135    { 0, AST_FORMAT_MAX_VIDEO, "maxvideo", "Maximum video format" },
00136    { 1, AST_FORMAT_T140, "t140", "Passthrough T.140 Realtime Text" },
00137    { 0, 0, "nothing", "undefined" },
00138    { 0, 0, "nothing", "undefined" },
00139    { 0, AST_FORMAT_MAX_TEXT, "maxtext", "Maximum text format" },
00140 };
00141 
00142 struct ast_frame ast_null_frame = { AST_FRAME_NULL, };
00143 
00144 void ast_smoother_reset(struct ast_smoother *s, int size)
00145 {
00146    memset(s, 0, sizeof(*s));
00147    s->size = size;
00148 }
00149 
00150 struct ast_smoother *ast_smoother_new(int size)
00151 {
00152    struct ast_smoother *s;
00153    if (size < 1)
00154       return NULL;
00155    if ((s = ast_malloc(sizeof(*s))))
00156       ast_smoother_reset(s, size);
00157    return s;
00158 }
00159 
00160 int ast_smoother_get_flags(struct ast_smoother *s)
00161 {
00162    return s->flags;
00163 }
00164 
00165 void ast_smoother_set_flags(struct ast_smoother *s, int flags)
00166 {
00167    s->flags = flags;
00168 }
00169 
00170 int ast_smoother_test_flag(struct ast_smoother *s, int flag)
00171 {
00172    return (s->flags & flag);
00173 }
00174 
00175 int __ast_smoother_feed(struct ast_smoother *s, struct ast_frame *f, int swap)
00176 {
00177    if (f->frametype != AST_FRAME_VOICE) {
00178       ast_log(LOG_WARNING, "Huh?  Can't smooth a non-voice frame!\n");
00179       return -1;
00180    }
00181    if (!s->format) {
00182       s->format = f->subclass;
00183       s->samplesperbyte = (float)f->samples / (float)f->datalen;
00184    } else if (s->format != f->subclass) {
00185       ast_log(LOG_WARNING, "Smoother was working on %d format frames, now trying to feed %d?\n", s->format, f->subclass);
00186       return -1;
00187    }
00188    if (s->len + f->datalen > SMOOTHER_SIZE) {
00189       ast_log(LOG_WARNING, "Out of smoother space\n");
00190       return -1;
00191    }
00192    if (((f->datalen == s->size) || ((f->datalen < 10) && (s->flags & AST_SMOOTHER_FLAG_G729)))
00193              && !s->opt && (f->offset >= AST_MIN_OFFSET)) {
00194       if (!s->len) {
00195          /* Optimize by sending the frame we just got
00196             on the next read, thus eliminating the douple
00197             copy */
00198          if (swap)
00199             ast_swapcopy_samples(f->data, f->data, f->samples);
00200          s->opt = f;
00201          return 0;
00202       } else {
00203          s->optimizablestream++;
00204          if (s->optimizablestream > 10) {
00205             /* For the past 10 rounds, we have input and output
00206                frames of the correct size for this smoother, yet
00207                we were unable to optimize because there was still
00208                some cruft left over.  Lets just drop the cruft so
00209                we can move to a fully optimized path */
00210             if (swap)
00211                ast_swapcopy_samples(f->data, f->data, f->samples);
00212             s->len = 0;
00213             s->opt = f;
00214             return 0;
00215          }
00216       }
00217    } else 
00218       s->optimizablestream = 0;
00219    if (s->flags & AST_SMOOTHER_FLAG_G729) {
00220       if (s->len % 10) {
00221          ast_log(LOG_NOTICE, "Dropping extra frame of G.729 since we already have a VAD frame at the end\n");
00222          return 0;
00223       }
00224    }
00225    if (swap)
00226       ast_swapcopy_samples(s->data+s->len, f->data, f->samples);
00227    else
00228       memcpy(s->data + s->len, f->data, f->datalen);
00229    /* If either side is empty, reset the delivery time */
00230    if (!s->len || ast_tvzero(f->delivery) || ast_tvzero(s->delivery))   /* XXX really ? */
00231       s->delivery = f->delivery;
00232    s->len += f->datalen;
00233    return 0;
00234 }
00235 
00236 struct ast_frame *ast_smoother_read(struct ast_smoother *s)
00237 {
00238    struct ast_frame *opt;
00239    int len;
00240 
00241    /* IF we have an optimization frame, send it */
00242    if (s->opt) {
00243       if (s->opt->offset < AST_FRIENDLY_OFFSET)
00244          ast_log(LOG_WARNING, "Returning a frame of inappropriate offset (%d).\n",
00245                      s->opt->offset);
00246       opt = s->opt;
00247       s->opt = NULL;
00248       return opt;
00249    }
00250 
00251    /* Make sure we have enough data */
00252    if (s->len < s->size) {
00253       /* Or, if this is a G.729 frame with VAD on it, send it immediately anyway */
00254       if (!((s->flags & AST_SMOOTHER_FLAG_G729) && (s->size % 10)))
00255          return NULL;
00256    }
00257    len = s->size;
00258    if (len > s->len)
00259       len = s->len;
00260    /* Make frame */
00261    s->f.frametype = AST_FRAME_VOICE;
00262    s->f.subclass = s->format;
00263    s->f.data = s->framedata + AST_FRIENDLY_OFFSET;
00264    s->f.offset = AST_FRIENDLY_OFFSET;
00265    s->f.datalen = len;
00266    /* Samples will be improper given VAD, but with VAD the concept really doesn't even exist */
00267    s->f.samples = len * s->samplesperbyte;   /* XXX rounding */
00268    s->f.delivery = s->delivery;
00269    /* Fill Data */
00270    memcpy(s->f.data, s->data, len);
00271    s->len -= len;
00272    /* Move remaining data to the front if applicable */
00273    if (s->len) {
00274       /* In principle this should all be fine because if we are sending
00275          G.729 VAD, the next timestamp will take over anyawy */
00276       memmove(s->data, s->data + len, s->len);
00277       if (!ast_tvzero(s->delivery)) {
00278          /* If we have delivery time, increment it, otherwise, leave it at 0 */
00279          s->delivery = ast_tvadd(s->delivery, ast_samp2tv(s->f.samples, 8000));
00280       }
00281    }
00282    /* Return frame */
00283    return &s->f;
00284 }
00285 
00286 void ast_smoother_free(struct ast_smoother *s)
00287 {
00288    free(s);
00289 }
00290 
00291 static struct ast_frame *ast_frame_header_new(void)
00292 {
00293    struct ast_frame *f;
00294 
00295 #if !defined(LOW_MEMORY)
00296    struct ast_frame_cache *frames;
00297 
00298    if ((frames = ast_threadstorage_get(&frame_cache, sizeof(*frames)))) {
00299       if ((f = AST_LIST_REMOVE_HEAD(&frames->list, frame_list))) {
00300          size_t mallocd_len = f->mallocd_hdr_len;
00301          memset(f, 0, sizeof(*f));
00302          f->mallocd_hdr_len = mallocd_len;
00303          f->mallocd = AST_MALLOCD_HDR;
00304          frames->size--;
00305          return f;
00306       }
00307    }
00308    if (!(f = ast_calloc_cache(1, sizeof(*f))))
00309       return NULL;
00310 #else
00311    if (!(f = ast_calloc(1, sizeof(*f))))
00312       return NULL;
00313 #endif
00314 
00315    f->mallocd_hdr_len = sizeof(*f);
00316 #ifdef TRACE_FRAMES
00317    AST_LIST_LOCK(&headerlist);
00318    headers++;
00319    AST_LIST_INSERT_HEAD(&headerlist, f, frame_list);
00320    AST_LIST_UNLOCK(&headerlist);
00321 #endif   
00322    
00323    return f;
00324 }
00325 
00326 #if !defined(LOW_MEMORY)
00327 static void frame_cache_cleanup(void *data)
00328 {
00329    struct ast_frame_cache *frames = data;
00330    struct ast_frame *f;
00331 
00332    while ((f = AST_LIST_REMOVE_HEAD(&frames->list, frame_list)))
00333       free(f);
00334    
00335    free(frames);
00336 }
00337 #endif
00338 
00339 void ast_frame_free(struct ast_frame *fr, int cache)
00340 {
00341    if (!fr->mallocd)
00342       return;
00343 
00344 #if !defined(LOW_MEMORY)
00345    if (cache && fr->mallocd == AST_MALLOCD_HDR) {
00346       /* Cool, only the header is malloc'd, let's just cache those for now 
00347        * to keep things simple... */
00348       struct ast_frame_cache *frames;
00349 
00350       if ((frames = ast_threadstorage_get(&frame_cache, sizeof(*frames))) 
00351           && frames->size < FRAME_CACHE_MAX_SIZE) {
00352          AST_LIST_INSERT_HEAD(&frames->list, fr, frame_list);
00353          frames->size++;
00354          return;
00355       }
00356    }
00357 #endif
00358    
00359    if (fr->mallocd & AST_MALLOCD_DATA) {
00360       if (fr->data) 
00361          free(fr->data - fr->offset);
00362    }
00363    if (fr->mallocd & AST_MALLOCD_SRC) {
00364       if (fr->src)
00365          free((char *)fr->src);
00366    }
00367    if (fr->mallocd & AST_MALLOCD_HDR) {
00368 #ifdef TRACE_FRAMES
00369       AST_LIST_LOCK(&headerlist);
00370       headers--;
00371       AST_LIST_REMOVE(&headerlist, fr, frame_list);
00372       AST_LIST_UNLOCK(&headerlist);
00373 #endif         
00374       free(fr);
00375    }
00376 }
00377 
00378 /*!
00379  * \brief 'isolates' a frame by duplicating non-malloc'ed components
00380  * (header, src, data).
00381  * On return all components are malloc'ed
00382  */
00383 struct ast_frame *ast_frisolate(struct ast_frame *fr)
00384 {
00385    struct ast_frame *out;
00386    void *newdata;
00387    
00388    if (!(fr->mallocd & AST_MALLOCD_HDR)) {
00389       /* Allocate a new header if needed */
00390       if (!(out = ast_frame_header_new()))
00391          return NULL;
00392       out->frametype = fr->frametype;
00393       out->subclass = fr->subclass;
00394       out->datalen = fr->datalen;
00395       out->samples = fr->samples;
00396       out->offset = fr->offset;
00397       out->data = fr->data;
00398       /* Copy the timing data */
00399       out->has_timing_info = fr->has_timing_info;
00400       if (fr->has_timing_info) {
00401          out->ts = fr->ts;
00402          out->len = fr->len;
00403          out->seqno = fr->seqno;
00404       }
00405    } else
00406       out = fr;
00407    
00408    if (!(fr->mallocd & AST_MALLOCD_SRC)) {
00409       if (fr->src) {
00410          if (!(out->src = ast_strdup(fr->src))) {
00411             if (out != fr)
00412                free(out);
00413             return NULL;
00414          }
00415       }
00416    } else
00417       out->src = fr->src;
00418    
00419    if (!(fr->mallocd & AST_MALLOCD_DATA))  {
00420       if (!(newdata = ast_malloc(fr->datalen + AST_FRIENDLY_OFFSET))) {
00421          if (out->src != fr->src)
00422             free((void *) out->src);
00423          if (out != fr)
00424             free(out);
00425          return NULL;
00426       }
00427       newdata += AST_FRIENDLY_OFFSET;
00428       out->offset = AST_FRIENDLY_OFFSET;
00429       out->datalen = fr->datalen;
00430       memcpy(newdata, fr->data, fr->datalen);
00431       out->data = newdata;
00432    }
00433 
00434    out->mallocd = AST_MALLOCD_HDR | AST_MALLOCD_SRC | AST_MALLOCD_DATA;
00435    
00436    return out;
00437 }
00438 
00439 struct ast_frame *ast_frdup(const struct ast_frame *f)
00440 {
00441    struct ast_frame *out = NULL;
00442    int len, srclen = 0;
00443    void *buf = NULL;
00444 
00445 #if !defined(LOW_MEMORY)
00446    struct ast_frame_cache *frames;
00447 #endif
00448 
00449    /* Start with standard stuff */
00450    len = sizeof(*out) + AST_FRIENDLY_OFFSET + f->datalen;
00451    /* If we have a source, add space for it */
00452    /*
00453     * XXX Watch out here - if we receive a src which is not terminated
00454     * properly, we can be easily attacked. Should limit the size we deal with.
00455     */
00456    if (f->src)
00457       srclen = strlen(f->src);
00458    if (srclen > 0)
00459       len += srclen + 1;
00460    
00461 #if !defined(LOW_MEMORY)
00462    if ((frames = ast_threadstorage_get(&frame_cache, sizeof(*frames)))) {
00463       AST_LIST_TRAVERSE_SAFE_BEGIN(&frames->list, out, frame_list) {
00464          if (out->mallocd_hdr_len >= len) {
00465             size_t mallocd_len = out->mallocd_hdr_len;
00466             AST_LIST_REMOVE_CURRENT(&frames->list, frame_list);
00467             memset(out, 0, sizeof(*out));
00468             out->mallocd_hdr_len = mallocd_len;
00469             buf = out;
00470             frames->size--;
00471             break;
00472          }
00473       }
00474       AST_LIST_TRAVERSE_SAFE_END
00475    }
00476 #endif
00477 
00478    if (!buf) {
00479       if (!(buf = ast_calloc_cache(1, len)))
00480          return NULL;
00481       out = buf;
00482       out->mallocd_hdr_len = len;
00483    }
00484 
00485    out->frametype = f->frametype;
00486    out->subclass = f->subclass;
00487    out->datalen = f->datalen;
00488    out->samples = f->samples;
00489    out->delivery = f->delivery;
00490    /* Set us as having malloc'd header only, so it will eventually
00491       get freed. */
00492    out->mallocd = AST_MALLOCD_HDR;
00493    out->offset = AST_FRIENDLY_OFFSET;
00494    if (out->datalen) {
00495       out->data = buf + sizeof(*out) + AST_FRIENDLY_OFFSET;
00496       memcpy(out->data, f->data, out->datalen); 
00497    }
00498    if (srclen > 0) {
00499       out->src = buf + sizeof(*out) + AST_FRIENDLY_OFFSET + f->datalen;
00500       /* Must have space since we allocated for it */
00501       strcpy((char *)out->src, f->src);
00502    }
00503    out->has_timing_info = f->has_timing_info;
00504    out->ts = f->ts;
00505    out->len = f->len;
00506    out->seqno = f->seqno;
00507    return out;
00508 }
00509 
00510 void ast_swapcopy_samples(void *dst, const void *src, int samples)
00511 {
00512    int i;
00513    unsigned short *dst_s = dst;
00514    const unsigned short *src_s = src;
00515 
00516    for (i = 0; i < samples; i++)
00517       dst_s[i] = (src_s[i]<<8) | (src_s[i]>>8);
00518 }
00519 
00520 
00521 struct ast_format_list *ast_get_format_list_index(int index) 
00522 {
00523    return &AST_FORMAT_LIST[index];
00524 }
00525 
00526 struct ast_format_list *ast_get_format_list(size_t *size) 
00527 {
00528    *size = (sizeof(AST_FORMAT_LIST) / sizeof(AST_FORMAT_LIST[0]));
00529    return AST_FORMAT_LIST;
00530 }
00531 
00532 char* ast_getformatname(int format)
00533 {
00534    int x;
00535    char *ret = "unknown";
00536    for (x = 0; x < sizeof(AST_FORMAT_LIST) / sizeof(AST_FORMAT_LIST[0]); x++) {
00537       if (AST_FORMAT_LIST[x].visible && AST_FORMAT_LIST[x].bits == format) {
00538          ret = AST_FORMAT_LIST[x].name;
00539          break;
00540       }
00541    }
00542    return ret;
00543 }
00544 
00545 char *ast_getformatname_multiple(char *buf, size_t size, int format)
00546 {
00547    int x;
00548    unsigned len;
00549    char *start, *end = buf;
00550 
00551    if (!size)
00552       return buf;
00553    snprintf(end, size, "0x%x (", format);
00554    len = strlen(end);
00555    end += len;
00556    size -= len;
00557    start = end;
00558    for (x = 0; x < sizeof(AST_FORMAT_LIST) / sizeof(AST_FORMAT_LIST[0]); x++) {
00559       if (AST_FORMAT_LIST[x].visible && (AST_FORMAT_LIST[x].bits & format)) {
00560          snprintf(end, size,"%s|",AST_FORMAT_LIST[x].name);
00561          len = strlen(end);
00562          end += len;
00563          size -= len;
00564       }
00565    }
00566    if (start == end)
00567       snprintf(start, size, "nothing)");
00568    else if (size > 1)
00569       *(end -1) = ')';
00570    return buf;
00571 }
00572 
00573 static struct ast_codec_alias_table {
00574    char *alias;
00575    char *realname;
00576 } ast_codec_alias_table[] = {
00577    { "slinear", "slin"},
00578    { "g723.1", "g723"},
00579 };
00580 
00581 static const char *ast_expand_codec_alias(const char *in)
00582 {
00583    int x;
00584 
00585    for (x = 0; x < sizeof(ast_codec_alias_table) / sizeof(ast_codec_alias_table[0]); x++) {
00586       if (!strcmp(in,ast_codec_alias_table[x].alias))
00587          return ast_codec_alias_table[x].realname;
00588    }
00589    return in;
00590 }
00591 
00592 int ast_getformatbyname(const char *name)
00593 {
00594    int x, all, format = 0;
00595 
00596    all = strcasecmp(name, "all") ? 0 : 1;
00597    for (x = 0; x < sizeof(AST_FORMAT_LIST) / sizeof(AST_FORMAT_LIST[0]); x++) {
00598       if (AST_FORMAT_LIST[x].visible && (all || 
00599            !strcasecmp(AST_FORMAT_LIST[x].name,name) ||
00600            !strcasecmp(AST_FORMAT_LIST[x].name,ast_expand_codec_alias(name)))) {
00601          format |= AST_FORMAT_LIST[x].bits;
00602          if (!all)
00603             break;
00604       }
00605    }
00606 
00607    return format;
00608 }
00609 
00610 char *ast_codec2str(int codec)
00611 {
00612    int x;
00613    char *ret = "unknown";
00614    for (x = 0; x < sizeof(AST_FORMAT_LIST) / sizeof(AST_FORMAT_LIST[0]); x++) {
00615       if (AST_FORMAT_LIST[x].visible && AST_FORMAT_LIST[x].bits == codec) {
00616          ret = AST_FORMAT_LIST[x].desc;
00617          break;
00618       }
00619    }
00620    return ret;
00621 }
00622 
00623 static int show_codecs(int fd, int argc, char *argv[])
00624 {
00625    int i, found=0;
00626    char hex[25];
00627    
00628    if ((argc < 3) || (argc > 4))
00629       return RESULT_SHOWUSAGE;
00630 
00631    if (!ast_opt_dont_warn)
00632       ast_cli(fd, "Disclaimer: this command is for informational purposes only.\n"
00633             "\tIt does not indicate anything about your configuration.\n");
00634 
00635    ast_cli(fd, "%11s %9s %10s   TYPE   %8s   %s\n","INT","BINARY","HEX","NAME","DESC");
00636    ast_cli(fd, "--------------------------------------------------------------------------------\n");
00637    if ((argc == 3) || (!strcasecmp(argv[3],"audio"))) {
00638       found = 1;
00639       for (i=0;i<13;i++) {
00640          snprintf(hex,25,"(0x%x)",1<<i);
00641          ast_cli(fd, "%11u (1 << %2d) %10s  audio   %8s   (%s)\n",1 << i,i,hex,ast_getformatname(1<<i),ast_codec2str(1<<i));
00642       }
00643    }
00644 
00645    if ((argc == 3) || (!strcasecmp(argv[3],"image"))) {
00646       found = 1;
00647       for (i=16;i<18;i++) {
00648          snprintf(hex,25,"(0x%x)",1<<i);
00649          ast_cli(fd, "%11u (1 << %2d) %10s  image   %8s   (%s)\n",1 << i,i,hex,ast_getformatname(1<<i),ast_codec2str(1<<i));
00650       }
00651    }
00652 
00653    if ((argc == 3) || (!strcasecmp(argv[3],"video"))) {
00654       found = 1;
00655       for (i=18;i<22;i++) {
00656          snprintf(hex,25,"(0x%x)",1<<i);
00657          ast_cli(fd, "%11u (1 << %2d) %10s  video   %8s   (%s)\n",1 << i,i,hex,ast_getformatname(1<<i),ast_codec2str(1<<i));
00658       }
00659    }
00660 
00661    if (! found)
00662       return RESULT_SHOWUSAGE;
00663    else
00664       return RESULT_SUCCESS;
00665 }
00666 
00667 static const char frame_show_codecs_usage[] =
00668 "Usage: core show codecs [audio|video|image]\n"
00669 "       Displays codec mapping\n";
00670 
00671 static int show_codec_n(int fd, int argc, char *argv[])
00672 {
00673    int codec, i, found=0;
00674 
00675    if (argc != 4)
00676       return RESULT_SHOWUSAGE;
00677 
00678    if (sscanf(argv[3],"%d",&codec) != 1)
00679       return RESULT_SHOWUSAGE;
00680 
00681    for (i = 0; i < 32; i++)
00682       if (codec & (1 << i)) {
00683          found = 1;
00684          ast_cli(fd, "%11u (1 << %2d)  %s\n",1 << i,i,ast_codec2str(1<<i));
00685       }
00686 
00687    if (!found)
00688       ast_cli(fd, "Codec %d not found\n", codec);
00689 
00690    return RESULT_SUCCESS;
00691 }
00692 
00693 static char frame_show_codec_n_usage[] =
00694 "Usage: core show codec <number>\n"
00695 "       Displays codec mapping\n";
00696 
00697 /*! Dump a frame for debugging purposes */
00698 void ast_frame_dump(const char *name, struct ast_frame *f, char *prefix)
00699 {
00700    const char noname[] = "unknown";
00701    char ftype[40] = "Unknown Frametype";
00702    char cft[80];
00703    char subclass[40] = "Unknown Subclass";
00704    char csub[80];
00705    char moreinfo[40] = "";
00706    char cn[60];
00707    char cp[40];
00708    char cmn[40];
00709 
00710    if (!name)
00711       name = noname;
00712 
00713 
00714    if (!f) {
00715       ast_verbose("%s [ %s (NULL) ] [%s]\n", 
00716          term_color(cp, prefix, COLOR_BRMAGENTA, COLOR_BLACK, sizeof(cp)),
00717          term_color(cft, "HANGUP", COLOR_BRRED, COLOR_BLACK, sizeof(cft)), 
00718          term_color(cn, name, COLOR_YELLOW, COLOR_BLACK, sizeof(cn)));
00719       return;
00720    }
00721    /* XXX We should probably print one each of voice and video when the format changes XXX */
00722    if (f->frametype == AST_FRAME_VOICE)
00723       return;
00724    if (f->frametype == AST_FRAME_VIDEO)
00725       return;
00726    switch(f->frametype) {
00727    case AST_FRAME_DTMF_BEGIN:
00728       strcpy(ftype, "DTMF Begin");
00729       subclass[0] = f->subclass;
00730       subclass[1] = '\0';
00731       break;
00732    case AST_FRAME_DTMF_END:
00733       strcpy(ftype, "DTMF End");
00734       subclass[0] = f->subclass;
00735       subclass[1] = '\0';
00736       break;
00737    case AST_FRAME_CONTROL:
00738       strcpy(ftype, "Control");
00739       switch(f->subclass) {
00740       case AST_CONTROL_HANGUP:
00741          strcpy(subclass, "Hangup");
00742          break;
00743       case AST_CONTROL_RING:
00744          strcpy(subclass, "Ring");
00745          break;
00746       case AST_CONTROL_RINGING:
00747          strcpy(subclass, "Ringing");
00748          break;
00749       case AST_CONTROL_ANSWER:
00750          strcpy(subclass, "Answer");
00751          break;
00752       case AST_CONTROL_BUSY:
00753          strcpy(subclass, "Busy");
00754          break;
00755       case AST_CONTROL_TAKEOFFHOOK:
00756          strcpy(subclass, "Take Off Hook");
00757          break;
00758       case AST_CONTROL_OFFHOOK:
00759          strcpy(subclass, "Line Off Hook");
00760          break;
00761       case AST_CONTROL_CONGESTION:
00762          strcpy(subclass, "Congestion");
00763          break;
00764       case AST_CONTROL_FLASH:
00765          strcpy(subclass, "Flash");
00766          break;
00767       case AST_CONTROL_WINK:
00768          strcpy(subclass, "Wink");
00769          break;
00770       case AST_CONTROL_OPTION:
00771          strcpy(subclass, "Option");
00772          break;
00773       case AST_CONTROL_RADIO_KEY:
00774          strcpy(subclass, "Key Radio");
00775          break;
00776       case AST_CONTROL_RADIO_UNKEY:
00777          strcpy(subclass, "Unkey Radio");
00778          break;
00779       case -1:
00780          strcpy(subclass, "Stop generators");
00781          break;
00782       default:
00783          snprintf(subclass, sizeof(subclass), "Unknown control '%d'", f->subclass);
00784       }
00785       break;
00786    case AST_FRAME_NULL:
00787       strcpy(ftype, "Null Frame");
00788       strcpy(subclass, "N/A");
00789       break;
00790    case AST_FRAME_IAX:
00791       /* Should never happen */
00792       strcpy(ftype, "IAX Specific");
00793       snprintf(subclass, sizeof(subclass), "IAX Frametype %d", f->subclass);
00794       break;
00795    case AST_FRAME_TEXT:
00796       strcpy(ftype, "Text");
00797       strcpy(subclass, "N/A");
00798       ast_copy_string(moreinfo, f->data, sizeof(moreinfo));
00799       break;
00800    case AST_FRAME_IMAGE:
00801       strcpy(ftype, "Image");
00802       snprintf(subclass, sizeof(subclass), "Image format %s\n", ast_getformatname(f->subclass));
00803       break;
00804    case AST_FRAME_HTML:
00805       strcpy(ftype, "HTML");
00806       switch(f->subclass) {
00807       case AST_HTML_URL:
00808          strcpy(subclass, "URL");
00809          ast_copy_string(moreinfo, f->data, sizeof(moreinfo));
00810          break;
00811       case AST_HTML_DATA:
00812          strcpy(subclass, "Data");
00813          break;
00814       case AST_HTML_BEGIN:
00815          strcpy(subclass, "Begin");
00816          break;
00817       case AST_HTML_END:
00818          strcpy(subclass, "End");
00819          break;
00820       case AST_HTML_LDCOMPLETE:
00821          strcpy(subclass, "Load Complete");
00822          break;
00823       case AST_HTML_NOSUPPORT:
00824          strcpy(subclass, "No Support");
00825          break;
00826       case AST_HTML_LINKURL:
00827          strcpy(subclass, "Link URL");
00828          ast_copy_string(moreinfo, f->data, sizeof(moreinfo));
00829          break;
00830       case AST_HTML_UNLINK:
00831          strcpy(subclass, "Unlink");
00832          break;
00833       case AST_HTML_LINKREJECT:
00834          strcpy(subclass, "Link Reject");
00835          break;
00836       default:
00837          snprintf(subclass, sizeof(subclass), "Unknown HTML frame '%d'\n", f->subclass);
00838          break;
00839       }
00840       break;
00841    case AST_FRAME_MODEM:
00842       strcpy(ftype, "Modem");
00843       switch (f->subclass) {
00844       case AST_MODEM_T38:
00845          strcpy(subclass, "T.38");
00846          break;
00847       case AST_MODEM_V150:
00848          strcpy(subclass, "V.150");
00849          break;
00850       default:
00851          snprintf(subclass, sizeof(subclass), "Unknown MODEM frame '%d'\n", f->subclass);
00852          break;
00853       }
00854       break;
00855    default:
00856       snprintf(ftype, sizeof(ftype), "Unknown Frametype '%d'", f->frametype);
00857    }
00858    if (!ast_strlen_zero(moreinfo))
00859       ast_verbose("%s [ TYPE: %s (%d) SUBCLASS: %s (%d) '%s' ] [%s]\n",  
00860              term_color(cp, prefix, COLOR_BRMAGENTA, COLOR_BLACK, sizeof(cp)),
00861              term_color(cft, ftype, COLOR_BRRED, COLOR_BLACK, sizeof(cft)),
00862              f->frametype, 
00863              term_color(csub, subclass, COLOR_BRCYAN, COLOR_BLACK, sizeof(csub)),
00864              f->subclass, 
00865              term_color(cmn, moreinfo, COLOR_BRGREEN, COLOR_BLACK, sizeof(cmn)),
00866              term_color(cn, name, COLOR_YELLOW, COLOR_BLACK, sizeof(cn)));
00867    else
00868       ast_verbose("%s [ TYPE: %s (%d) SUBCLASS: %s (%d) ] [%s]\n",  
00869              term_color(cp, prefix, COLOR_BRMAGENTA, COLOR_BLACK, sizeof(cp)),
00870              term_color(cft, ftype, COLOR_BRRED, COLOR_BLACK, sizeof(cft)),
00871              f->frametype, 
00872              term_color(csub, subclass, COLOR_BRCYAN, COLOR_BLACK, sizeof(csub)),
00873              f->subclass, 
00874              term_color(cn, name, COLOR_YELLOW, COLOR_BLACK, sizeof(cn)));
00875 }
00876 
00877 
00878 #ifdef TRACE_FRAMES
00879 static int show_frame_stats(int fd, int argc, char *argv[])
00880 {
00881    struct ast_frame *f;
00882    int x=1;
00883    if (argc != 4)
00884       return RESULT_SHOWUSAGE;
00885    AST_LIST_LOCK(&headerlist);
00886    ast_cli(fd, "     Framer Statistics     \n");
00887    ast_cli(fd, "---------------------------\n");
00888    ast_cli(fd, "Total allocated headers: %d\n", headers);
00889    ast_cli(fd, "Queue Dump:\n");
00890    AST_LIST_TRAVERSE(&headerlist, f, frame_list)
00891       ast_cli(fd, "%d.  Type %d, subclass %d from %s\n", x++, f->frametype, f->subclass, f->src ? f->src : "<Unknown>");
00892    AST_LIST_UNLOCK(&headerlist);
00893    return RESULT_SUCCESS;
00894 }
00895 
00896 static const char frame_stats_usage[] =
00897 "Usage: core show frame stats\n"
00898 "       Displays debugging statistics from framer\n";
00899 #endif
00900 
00901 /* Builtin Asterisk CLI-commands for debugging */
00902 static struct ast_cli_entry my_clis[] = {
00903    { { "core", "show", "codecs", NULL },
00904    show_codecs, "Displays a list of codecs",
00905    frame_show_codecs_usage },
00906 
00907    { { "core", "show", "audio", "codecs", NULL },
00908    show_codecs, "Displays a list of audio codecs",
00909    frame_show_codecs_usage },
00910 
00911    { { "core", "show", "video", "codecs", NULL },
00912    show_codecs, "Displays a list of video codecs",
00913    frame_show_codecs_usage },
00914 
00915    { { "core", "show", "image", "codecs", NULL },
00916    show_codecs, "Displays a list of image codecs",
00917    frame_show_codecs_usage },
00918 
00919    { { "core", "show", "codec", NULL },
00920    show_codec_n, "Shows a specific codec",
00921    frame_show_codec_n_usage },
00922 
00923 #ifdef TRACE_FRAMES
00924    { { "core", "show", "frame", "stats", NULL },
00925    show_frame_stats, "Shows frame statistics",
00926    frame_stats_usage },
00927 #endif
00928 };
00929 
00930 int init_framer(void)
00931 {
00932    ast_cli_register_multiple(my_clis, sizeof(my_clis) / sizeof(struct ast_cli_entry));
00933    return 0;   
00934 }
00935 
00936 void ast_codec_pref_convert(struct ast_codec_pref *pref, char *buf, size_t size, int right) 
00937 {
00938    int x, differential = (int) 'A', mem;
00939    char *from, *to;
00940 
00941    if (right) {
00942       from = pref->order;
00943       to = buf;
00944       mem = size;
00945    } else {
00946       to = pref->order;
00947       from = buf;
00948       mem = 32;
00949    }
00950 
00951    memset(to, 0, mem);
00952    for (x = 0; x < 32 ; x++) {
00953       if (!from[x])
00954          break;
00955       to[x] = right ? (from[x] + differential) : (from[x] - differential);
00956    }
00957 }
00958 
00959 int ast_codec_pref_string(struct ast_codec_pref *pref, char *buf, size_t size) 
00960 {
00961    int x, codec; 
00962    size_t total_len, slen;
00963    char *formatname;
00964    
00965    memset(buf,0,size);
00966    total_len = size;
00967    buf[0] = '(';
00968    total_len--;
00969    for(x = 0; x < 32 ; x++) {
00970       if (total_len <= 0)
00971          break;
00972       if (!(codec = ast_codec_pref_index(pref,x)))
00973          break;
00974       if ((formatname = ast_getformatname(codec))) {
00975          slen = strlen(formatname);
00976          if (slen > total_len)
00977             break;
00978          strncat(buf,formatname,total_len);
00979          total_len -= slen;
00980       }
00981       if (total_len && x < 31 && ast_codec_pref_index(pref , x + 1)) {
00982          strncat(buf,"|",total_len);
00983          total_len--;
00984       }
00985    }
00986    if (total_len) {
00987       strncat(buf,")",total_len);
00988       total_len--;
00989    }
00990 
00991    return size - total_len;
00992 }
00993 
00994 int ast_codec_pref_index(struct ast_codec_pref *pref, int index) 
00995 {
00996    int slot = 0;
00997 
00998    
00999    if ((index >= 0) && (index < sizeof(pref->order))) {
01000       slot = pref->order[index];
01001    }
01002 
01003    return slot ? AST_FORMAT_LIST[slot-1].bits : 0;
01004 }
01005 
01006 /*! \brief Remove codec from pref list */
01007 void ast_codec_pref_remove(struct ast_codec_pref *pref, int format)
01008 {
01009    struct ast_codec_pref oldorder;
01010    int x, y = 0;
01011    int slot;
01012    int size;
01013 
01014    if (!pref->order[0])
01015       return;
01016 
01017    memcpy(&oldorder, pref, sizeof(oldorder));
01018    memset(pref, 0, sizeof(*pref));
01019 
01020    for (x = 0; x < sizeof(AST_FORMAT_LIST) / sizeof(AST_FORMAT_LIST[0]); x++) {
01021       slot = oldorder.order[x];
01022       size = oldorder.framing[x];
01023       if (! slot)
01024          break;
01025       if (AST_FORMAT_LIST[slot-1].bits != format) {
01026          pref->order[y] = slot;
01027          pref->framing[y++] = size;
01028       }
01029    }
01030    
01031 }
01032 
01033 /*! \brief Append codec to list */
01034 int ast_codec_pref_append(struct ast_codec_pref *pref, int format)
01035 {
01036    int x, newindex = -1;
01037 
01038    ast_codec_pref_remove(pref, format);
01039 
01040    for (x = 0; x < sizeof(AST_FORMAT_LIST) / sizeof(AST_FORMAT_LIST[0]); x++) {
01041       if (AST_FORMAT_LIST[x].bits == format) {
01042          newindex = x + 1;
01043          break;
01044       }
01045    }
01046 
01047    if (newindex) {
01048       for (x = 0; x < sizeof(AST_FORMAT_LIST) / sizeof(AST_FORMAT_LIST[0]); x++) {
01049          if (!pref->order[x]) {
01050             pref->order[x] = newindex;
01051             break;
01052          }
01053       }
01054    }
01055 
01056    return x;
01057 }
01058 
01059 
01060 /*! \brief Set packet size for codec */
01061 int ast_codec_pref_setsize(struct ast_codec_pref *pref, int format, int framems)
01062 {
01063    int x, index = -1;
01064 
01065    for (x = 0; x < sizeof(AST_FORMAT_LIST) / sizeof(AST_FORMAT_LIST[0]); x++) {
01066       if (AST_FORMAT_LIST[x].bits == format) {
01067          index = x;
01068          break;
01069       }
01070    }
01071 
01072    if (index < 0)
01073       return -1;
01074 
01075    /* size validation */
01076    if (!framems)
01077       framems = AST_FORMAT_LIST[index].def_ms;
01078 
01079    if (AST_FORMAT_LIST[index].inc_ms && framems % AST_FORMAT_LIST[index].inc_ms) /* avoid division by zero */
01080       framems -= framems % AST_FORMAT_LIST[index].inc_ms;
01081 
01082    if (framems < AST_FORMAT_LIST[index].min_ms)
01083       framems = AST_FORMAT_LIST[index].min_ms;
01084 
01085    if (framems > AST_FORMAT_LIST[index].max_ms)
01086       framems = AST_FORMAT_LIST[index].max_ms;
01087 
01088 
01089    for (x = 0; x < sizeof(AST_FORMAT_LIST) / sizeof(AST_FORMAT_LIST[0]); x++) {
01090       if (pref->order[x] == (index + 1)) {
01091          pref->framing[x] = framems;
01092          break;
01093       }
01094    }
01095 
01096    return x;
01097 }
01098 
01099 /*! \brief Get packet size for codec */
01100 struct ast_format_list ast_codec_pref_getsize(struct ast_codec_pref *pref, int format)
01101 {
01102    int x, index = -1, framems = 0;
01103    struct ast_format_list fmt = { 0, };
01104 
01105    for (x = 0; x < sizeof(AST_FORMAT_LIST) / sizeof(AST_FORMAT_LIST[0]); x++) {
01106       if (AST_FORMAT_LIST[x].bits == format) {
01107          fmt = AST_FORMAT_LIST[x];
01108          index = x;
01109          break;
01110       }
01111    }
01112 
01113    for (x = 0; x < sizeof(AST_FORMAT_LIST) / sizeof(AST_FORMAT_LIST[0]); x++) {
01114       if (pref->order[x] == (index + 1)) {
01115          framems = pref->framing[x];
01116          break;
01117       }
01118    }
01119 
01120    /* size validation */
01121    if (!framems)
01122       framems = AST_FORMAT_LIST[index].def_ms;
01123 
01124    if (AST_FORMAT_LIST[index].inc_ms && framems % AST_FORMAT_LIST[index].inc_ms) /* avoid division by zero */
01125       framems -= framems % AST_FORMAT_LIST[index].inc_ms;
01126 
01127    if (framems < AST_FORMAT_LIST[index].min_ms)
01128       framems = AST_FORMAT_LIST[index].min_ms;
01129 
01130    if (framems > AST_FORMAT_LIST[index].max_ms)
01131       framems = AST_FORMAT_LIST[index].max_ms;
01132 
01133    fmt.cur_ms = framems;
01134 
01135    return fmt;
01136 }
01137 
01138 /*! \brief Pick a codec */
01139 int ast_codec_choose(struct ast_codec_pref *pref, int formats, int find_best)
01140 {
01141    int x, ret = 0, slot;
01142 
01143    for (x = 0; x < sizeof(AST_FORMAT_LIST) / sizeof(AST_FORMAT_LIST[0]); x++) {
01144       slot = pref->order[x];
01145 
01146       if (!slot)
01147          break;
01148       if (formats & AST_FORMAT_LIST[slot-1].bits) {
01149          ret = AST_FORMAT_LIST[slot-1].bits;
01150          break;
01151       }
01152    }
01153    if (ret & AST_FORMAT_AUDIO_MASK)
01154       return ret;
01155 
01156    if (option_debug > 3)
01157       ast_log(LOG_DEBUG, "Could not find preferred codec - %s\n", find_best ? "Going for the best codec" : "Returning zero codec");
01158 
01159       return find_best ? ast_best_codec(formats) : 0;
01160 }
01161 
01162 int ast_parse_allow_disallow(struct ast_codec_pref *pref, int *mask, const char *list, int allowing) 
01163 {
01164    int errors = 0;
01165    char *parse = NULL, *this = NULL, *psize = NULL;
01166    int format = 0, framems = 0;
01167 
01168    parse = ast_strdupa(list);
01169    while ((this = strsep(&parse, ","))) {
01170       framems = 0;
01171       if ((psize = strrchr(this, ':'))) {
01172          *psize++ = '\0';
01173          if (option_debug)
01174             ast_log(LOG_DEBUG,"Packetization for codec: %s is %s\n", this, psize);
01175          framems = atoi(psize);
01176          if (framems < 0) {
01177             framems = 0;
01178             errors++;
01179             ast_log(LOG_WARNING, "Bad packetization value for codec %s\n", this);
01180          }
01181       }
01182       if (!(format = ast_getformatbyname(this))) {
01183          ast_log(LOG_WARNING, "Cannot %s unknown format '%s'\n", allowing ? "allow" : "disallow", this);
01184          errors++;
01185          continue;
01186       }
01187 
01188       if (mask) {
01189          if (allowing)
01190             *mask |= format;
01191          else
01192             *mask &= ~format;
01193       }
01194 
01195       /* Set up a preference list for audio. Do not include video in preferences 
01196          since we can not transcode video and have to use whatever is offered
01197        */
01198       if (pref && (format & AST_FORMAT_AUDIO_MASK)) {
01199          if (strcasecmp(this, "all")) {
01200             if (allowing) {
01201                ast_codec_pref_append(pref, format);
01202                ast_codec_pref_setsize(pref, format, framems);
01203             }
01204             else
01205                ast_codec_pref_remove(pref, format);
01206          } else if (!allowing) {
01207             memset(pref, 0, sizeof(*pref));
01208          }
01209       }
01210    }
01211    return errors;
01212 }
01213 
01214 static int g723_len(unsigned char buf)
01215 {
01216    enum frame_type type = buf & TYPE_MASK;
01217 
01218    switch(type) {
01219    case TYPE_DONTSEND:
01220       return 0;
01221       break;
01222    case TYPE_SILENCE:
01223       return 4;
01224       break;
01225    case TYPE_HIGH:
01226       return 24;
01227       break;
01228    case TYPE_LOW:
01229       return 20;
01230       break;
01231    default:
01232       ast_log(LOG_WARNING, "Badly encoded frame (%d)\n", type);
01233    }
01234    return -1;
01235 }
01236 
01237 static int g723_samples(unsigned char *buf, int maxlen)
01238 {
01239    int pos = 0;
01240    int samples = 0;
01241    int res;
01242    while(pos < maxlen) {
01243       res = g723_len(buf[pos]);
01244       if (res <= 0)
01245          break;
01246       samples += 240;
01247       pos += res;
01248    }
01249    return samples;
01250 }
01251 
01252 static unsigned char get_n_bits_at(unsigned char *data, int n, int bit)
01253 {
01254    int byte = bit / 8;       /* byte containing first bit */
01255    int rem = 8 - (bit % 8);  /* remaining bits in first byte */
01256    unsigned char ret = 0;
01257    
01258    if (n <= 0 || n > 8)
01259       return 0;
01260 
01261    if (rem < n) {
01262       ret = (data[byte] << (n - rem));
01263       ret |= (data[byte + 1] >> (8 - n + rem));
01264    } else {
01265       ret = (data[byte] >> (rem - n));
01266    }
01267 
01268    return (ret & (0xff >> (8 - n)));
01269 }
01270 
01271 static int speex_get_wb_sz_at(unsigned char *data, int len, int bit)
01272 {
01273    static int SpeexWBSubModeSz[] = {
01274       0, 36, 112, 192,
01275       352, 0, 0, 0 };
01276    int off = bit;
01277    unsigned char c;
01278 
01279    /* skip up to two wideband frames */
01280    if (((len * 8 - off) >= 5) && 
01281       get_n_bits_at(data, 1, off)) {
01282       c = get_n_bits_at(data, 3, off + 1);
01283       off += SpeexWBSubModeSz[c];
01284 
01285       if (((len * 8 - off) >= 5) && 
01286          get_n_bits_at(data, 1, off)) {
01287          c = get_n_bits_at(data, 3, off + 1);
01288          off += SpeexWBSubModeSz[c];
01289 
01290          if (((len * 8 - off) >= 5) && 
01291             get_n_bits_at(data, 1, off)) {
01292             ast_log(LOG_WARNING, "Encountered corrupt speex frame; too many wideband frames in a row.\n");
01293             return -1;
01294          }
01295       }
01296 
01297    }
01298    return off - bit;
01299 }
01300 
01301 static int speex_samples(unsigned char *data, int len)
01302 {
01303    static int SpeexSubModeSz[] = {
01304                5, 43, 119, 160,
01305       220, 300, 364, 492, 
01306       79, 0, 0, 0,
01307       0, 0, 0, 0 };
01308    static int SpeexInBandSz[] = { 
01309       1, 1, 4, 4,
01310       4, 4, 4, 4,
01311       8, 8, 16, 16,
01312       32, 32, 64, 64 };
01313    int bit = 0;
01314    int cnt = 0;
01315    int off;
01316    unsigned char c;
01317 
01318    while ((len * 8 - bit) >= 5) {
01319       /* skip wideband frames */
01320       off = speex_get_wb_sz_at(data, len, bit);
01321       if (off < 0)  {
01322          ast_log(LOG_WARNING, "Had error while reading wideband frames for speex samples\n");
01323          break;
01324       }
01325       bit += off;
01326 
01327       if ((len * 8 - bit) < 5) {
01328          ast_log(LOG_WARNING, "Not enough bits remaining after wide band for speex samples.\n");
01329          break;
01330       }
01331 
01332       /* get control bits */
01333       c = get_n_bits_at(data, 5, bit);
01334       bit += 5;
01335 
01336       if (c == 15) { 
01337          /* terminator */
01338          break; 
01339       } else if (c == 14) {
01340          /* in-band signal; next 4 bits contain signal id */
01341          c = get_n_bits_at(data, 4, bit);
01342          bit += 4;
01343          bit += SpeexInBandSz[c];
01344       } else if (c == 13) {
01345          /* user in-band; next 5 bits contain msg len */
01346          c = get_n_bits_at(data, 5, bit);
01347          bit += 5;
01348          bit += c * 8;
01349       } else if (c > 8) {
01350          /* unknown */
01351          break;
01352       } else {
01353          /* skip number bits for submode (less the 5 control bits) */
01354          bit += SpeexSubModeSz[c] - 5;
01355          cnt += 160; /* new frame */
01356       }
01357    }
01358    return cnt;
01359 }
01360 
01361 int ast_codec_get_samples(struct ast_frame *f)
01362 {
01363    int samples=0;
01364    switch(f->subclass) {
01365    case AST_FORMAT_SPEEX:
01366       samples = speex_samples(f->data, f->datalen);
01367       break;
01368    case AST_FORMAT_G723_1:
01369                 samples = g723_samples(f->data, f->datalen);
01370       break;
01371    case AST_FORMAT_ILBC:
01372       samples = 240 * (f->datalen / 50);
01373       break;
01374    case AST_FORMAT_GSM:
01375       samples = 160 * (f->datalen / 33);
01376       break;
01377    case AST_FORMAT_G729A:
01378       samples = f->datalen * 8;
01379       break;
01380    case AST_FORMAT_SLINEAR:
01381       samples = f->datalen / 2;
01382       break;
01383    case AST_FORMAT_LPC10:
01384                 /* assumes that the RTP packet contains one LPC10 frame */
01385       samples = 22 * 8;
01386       samples += (((char *)(f->data))[7] & 0x1) * 8;
01387       break;
01388    case AST_FORMAT_ULAW:
01389    case AST_FORMAT_ALAW:
01390    case AST_FORMAT_G722:
01391       samples = f->datalen;
01392       break;
01393    case AST_FORMAT_ADPCM:
01394    case AST_FORMAT_G726:
01395    case AST_FORMAT_G726_AAL2:
01396       samples = f->datalen * 2;
01397       break;
01398    default:
01399       ast_log(LOG_WARNING, "Unable to calculate samples for format %s\n", ast_getformatname(f->subclass));
01400    }
01401    return samples;
01402 }
01403 
01404 int ast_codec_get_len(int format, int samples)
01405 {
01406    int len = 0;
01407 
01408    /* XXX Still need speex, g723, and lpc10 XXX */ 
01409    switch(format) {
01410    case AST_FORMAT_G723_1:
01411       len = (samples / 240) * 20;
01412       break;
01413    case AST_FORMAT_ILBC:
01414       len = (samples / 240) * 50;
01415       break;
01416    case AST_FORMAT_GSM:
01417       len = (samples / 160) * 33;
01418       break;
01419    case AST_FORMAT_G729A:
01420       len = samples / 8;
01421       break;
01422    case AST_FORMAT_SLINEAR:
01423       len = samples * 2;
01424       break;
01425    case AST_FORMAT_ULAW:
01426    case AST_FORMAT_ALAW:
01427       len = samples;
01428       break;
01429    case AST_FORMAT_ADPCM:
01430    case AST_FORMAT_G726:
01431    case AST_FORMAT_G726_AAL2:
01432       len = samples / 2;
01433       break;
01434    default:
01435       ast_log(LOG_WARNING, "Unable to calculate sample length for format %s\n", ast_getformatname(format));
01436    }
01437 
01438    return len;
01439 }
01440 
01441 int ast_frame_adjust_volume(struct ast_frame *f, int adjustment)
01442 {
01443    int count;
01444    short *fdata = f->data;
01445    short adjust_value = abs(adjustment);
01446 
01447    if ((f->frametype != AST_FRAME_VOICE) || (f->subclass != AST_FORMAT_SLINEAR))
01448       return -1;
01449 
01450    if (!adjustment)
01451       return 0;
01452 
01453    for (count = 0; count < f->samples; count++) {
01454       if (adjustment > 0) {
01455          ast_slinear_saturated_multiply(&fdata[count], &adjust_value);
01456       } else if (adjustment < 0) {
01457          ast_slinear_saturated_divide(&fdata[count], &adjust_value);
01458       }
01459    }
01460 
01461    return 0;
01462 }
01463 
01464 int ast_frame_slinear_sum(struct ast_frame *f1, struct ast_frame *f2)
01465 {
01466    int count;
01467    short *data1, *data2;
01468 
01469    if ((f1->frametype != AST_FRAME_VOICE) || (f1->subclass != AST_FORMAT_SLINEAR))
01470       return -1;
01471 
01472    if ((f2->frametype != AST_FRAME_VOICE) || (f2->subclass != AST_FORMAT_SLINEAR))
01473       return -1;
01474 
01475    if (f1->samples != f2->samples)
01476       return -1;
01477 
01478    for (count = 0, data1 = f1->data, data2 = f2->data;
01479         count < f1->samples;
01480         count++, data1++, data2++)
01481       ast_slinear_saturated_add(data1, data2);
01482 
01483    return 0;
01484 }

Asterisk is a trademark for Digium, inc.. | Edvina.net | Asterisk.org | This documentation was generated with Doxygen