Thu Oct 8 00:59:04 2009

Asterisk developer's documentation


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

Generated on Thu Oct 8 00:59:04 2009 for Asterisk - the Open Source PBX by  doxygen 1.4.7