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

Generated on Fri Jun 19 12:09:44 2009 for Asterisk - the Open Source PBX by  doxygen 1.4.7