Main Page   Alphabetical List   Data Structures   File List   Data Fields   Globals  

frame.c

Go to the documentation of this file.
00001 /*
00002  * Asterisk -- A telephony toolkit for Linux.
00003  *
00004  * Frame manipulation routines
00005  * 
00006  * Copyright (C) 1999, Mark Spencer
00007  *
00008  * Mark Spencer <markster@linux-support.net>
00009  *
00010  * This program is free software, distributed under the terms of
00011  * the GNU General Public License
00012  */
00013 
00014 #include <asterisk/lock.h>
00015 #include <asterisk/frame.h>
00016 #include <asterisk/logger.h>
00017 #include <asterisk/options.h>
00018 #include <asterisk/cli.h>
00019 #include <asterisk/term.h>
00020 #include <asterisk/utils.h>
00021 #include <stdlib.h>
00022 #include <unistd.h>
00023 #include <string.h>
00024 #include <errno.h>
00025 #include <stdio.h>
00026 #include "asterisk.h"
00027 
00028 #ifdef TRACE_FRAMES
00029 static int headers = 0;
00030 static struct ast_frame *headerlist = NULL;
00031 AST_MUTEX_DEFINE_STATIC(framelock);
00032 #endif
00033 
00034 #define SMOOTHER_SIZE 8000
00035 
00036 struct ast_smoother {
00037    int size;
00038    int format;
00039    int readdata;
00040    int optimizablestream;
00041    int flags;
00042    float samplesperbyte;
00043    struct ast_frame f;
00044    struct timeval delivery;
00045    char data[SMOOTHER_SIZE];
00046    char framedata[SMOOTHER_SIZE + AST_FRIENDLY_OFFSET];
00047    struct ast_frame *opt;
00048    int len;
00049 };
00050 
00051 void ast_smoother_reset(struct ast_smoother *s, int size)
00052 {
00053    memset(s, 0, sizeof(struct ast_smoother));
00054    s->size = size;
00055 }
00056 
00057 struct ast_smoother *ast_smoother_new(int size)
00058 {
00059    struct ast_smoother *s;
00060    if (size < 1)
00061       return NULL;
00062    s = malloc(sizeof(struct ast_smoother));
00063    if (s)
00064       ast_smoother_reset(s, size);
00065    return s;
00066 }
00067 
00068 int ast_smoother_get_flags(struct ast_smoother *s)
00069 {
00070    return s->flags;
00071 }
00072 
00073 void ast_smoother_set_flags(struct ast_smoother *s, int flags)
00074 {
00075    s->flags = flags;
00076 }
00077 
00078 int ast_smoother_feed(struct ast_smoother *s, struct ast_frame *f)
00079 {
00080    if (f->frametype != AST_FRAME_VOICE) {
00081       ast_log(LOG_WARNING, "Huh?  Can't smooth a non-voice frame!\n");
00082       return -1;
00083    }
00084    if (!s->format) {
00085       s->format = f->subclass;
00086       s->samplesperbyte = (float)f->samples / (float)f->datalen;
00087    } else if (s->format != f->subclass) {
00088       ast_log(LOG_WARNING, "Smoother was working on %d format frames, now trying to feed %d?\n", s->format, f->subclass);
00089       return -1;
00090    }
00091    if (s->len + f->datalen > SMOOTHER_SIZE) {
00092       ast_log(LOG_WARNING, "Out of smoother space\n");
00093       return -1;
00094    }
00095    if (((f->datalen == s->size) || ((f->datalen < 10) && (s->flags & AST_SMOOTHER_FLAG_G729)))
00096              && !s->opt && (f->offset >= AST_MIN_OFFSET)) {
00097       if (!s->len) {
00098          /* Optimize by sending the frame we just got
00099             on the next read, thus eliminating the douple
00100             copy */
00101          s->opt = f;
00102          return 0;
00103       } else {
00104          s->optimizablestream++;
00105          if (s->optimizablestream > 10) {
00106             /* For the past 10 rounds, we have input and output
00107                frames of the correct size for this smoother, yet
00108                we were unable to optimize because there was still
00109                some cruft left over.  Lets just drop the cruft so
00110                we can move to a fully optimized path */
00111             s->len = 0;
00112             s->opt = f;
00113             return 0;
00114          }
00115       }
00116    } else 
00117       s->optimizablestream = 0;
00118    if (s->flags & AST_SMOOTHER_FLAG_G729) {
00119       if (s->len % 10) {
00120          ast_log(LOG_NOTICE, "Dropping extra frame of G.729 since we already have a VAD frame at the end\n");
00121          return 0;
00122       }
00123    }
00124    memcpy(s->data + s->len, f->data, f->datalen);
00125    /* If either side is empty, reset the delivery time */
00126    if (!s->len || (!f->delivery.tv_sec && !f->delivery.tv_usec) ||
00127          (!s->delivery.tv_sec && !s->delivery.tv_usec))
00128       s->delivery = f->delivery;
00129    s->len += f->datalen;
00130    return 0;
00131 }
00132 
00133 struct ast_frame *ast_smoother_read(struct ast_smoother *s)
00134 {
00135    struct ast_frame *opt;
00136    int len;
00137    /* IF we have an optimization frame, send it */
00138    if (s->opt) {
00139       if (s->opt->offset < AST_FRIENDLY_OFFSET)
00140          ast_log(LOG_WARNING, "Returning a frame of inappropriate offset (%d).",
00141                      s->opt->offset);
00142       opt = s->opt;
00143       s->opt = NULL;
00144       return opt;
00145    }
00146 
00147    /* Make sure we have enough data */
00148    if (s->len < s->size) {
00149       /* Or, if this is a G.729 frame with VAD on it, send it immediately anyway */
00150       if (!((s->flags & AST_SMOOTHER_FLAG_G729) && (s->size % 10)))
00151          return NULL;
00152    }
00153    len = s->size;
00154    if (len > s->len)
00155       len = s->len;
00156    /* Make frame */
00157    s->f.frametype = AST_FRAME_VOICE;
00158    s->f.subclass = s->format;
00159    s->f.data = s->framedata + AST_FRIENDLY_OFFSET;
00160    s->f.offset = AST_FRIENDLY_OFFSET;
00161    s->f.datalen = len;
00162    /* Samples will be improper given VAD, but with VAD the concept really doesn't even exist */
00163    s->f.samples = len * s->samplesperbyte;
00164    s->f.delivery = s->delivery;
00165    /* Fill Data */
00166    memcpy(s->f.data, s->data, len);
00167    s->len -= len;
00168    /* Move remaining data to the front if applicable */
00169    if (s->len) {
00170       /* In principle this should all be fine because if we are sending
00171          G.729 VAD, the next timestamp will take over anyawy */
00172       memmove(s->data, s->data + len, s->len);
00173       if (s->delivery.tv_sec || s->delivery.tv_usec) {
00174          /* If we have delivery time, increment it, otherwise, leave it at 0 */
00175          s->delivery.tv_sec += (len * s->samplesperbyte) / 8000.0;
00176          s->delivery.tv_usec += (((int)(len * s->samplesperbyte)) % 8000) * 125;
00177          if (s->delivery.tv_usec > 1000000) {
00178             s->delivery.tv_usec -= 1000000;
00179             s->delivery.tv_sec += 1;
00180          }
00181       }
00182    }
00183    /* Return frame */
00184    return &s->f;
00185 }
00186 
00187 void ast_smoother_free(struct ast_smoother *s)
00188 {
00189    free(s);
00190 }
00191 
00192 static struct ast_frame *ast_frame_header_new(void)
00193 {
00194    struct ast_frame *f;
00195    f = malloc(sizeof(struct ast_frame));
00196    if (f)
00197       memset(f, 0, sizeof(struct ast_frame));
00198 #ifdef TRACE_FRAMES
00199    if (f) {
00200       headers++;
00201       f->prev = NULL;
00202       ast_mutex_lock(&framelock);
00203       f->next = headerlist;
00204       if (headerlist)
00205          headerlist->prev = f;
00206       headerlist = f;
00207       ast_mutex_unlock(&framelock);
00208    }
00209 #endif   
00210    return f;
00211 }
00212 
00213 /*
00214  * Important: I should be made more efficient.  Frame headers should
00215  * most definitely be cached
00216  */
00217 
00218 void ast_frfree(struct ast_frame *fr)
00219 {
00220    if (fr->mallocd & AST_MALLOCD_DATA) {
00221       if (fr->data) 
00222          free(fr->data - fr->offset);
00223    }
00224    if (fr->mallocd & AST_MALLOCD_SRC) {
00225       if (fr->src)
00226          free(fr->src);
00227    }
00228    if (fr->mallocd & AST_MALLOCD_HDR) {
00229 #ifdef TRACE_FRAMES
00230       headers--;
00231       ast_mutex_lock(&framelock);
00232       if (fr->next)
00233          fr->next->prev = fr->prev;
00234       if (fr->prev)
00235          fr->prev->next = fr->next;
00236       else
00237          headerlist = fr->next;
00238       ast_mutex_unlock(&framelock);
00239 #endif         
00240       free(fr);
00241    }
00242 }
00243 
00244 struct ast_frame *ast_frisolate(struct ast_frame *fr)
00245 {
00246    struct ast_frame *out;
00247    if (!(fr->mallocd & AST_MALLOCD_HDR)) {
00248       /* Allocate a new header if needed */
00249       out = ast_frame_header_new();
00250       if (!out) {
00251          ast_log(LOG_WARNING, "Out of memory\n");
00252          return NULL;
00253       }
00254       out->frametype = fr->frametype;
00255       out->subclass = fr->subclass;
00256       out->datalen = 0;
00257       out->samples = fr->samples;
00258       out->offset = 0;
00259       out->src = NULL;
00260       out->data = NULL;
00261    } else {
00262       out = fr;
00263    }
00264    if (!(fr->mallocd & AST_MALLOCD_SRC)) {
00265       if (fr->src)
00266          out->src = strdup(fr->src);
00267    } else
00268       out->src = fr->src;
00269    if (!(fr->mallocd & AST_MALLOCD_DATA))  {
00270       out->data = malloc(fr->datalen + AST_FRIENDLY_OFFSET);
00271       if (!out->data) {
00272          free(out);
00273          ast_log(LOG_WARNING, "Out of memory\n");
00274          return NULL;
00275       }
00276       out->data += AST_FRIENDLY_OFFSET;
00277       out->offset = AST_FRIENDLY_OFFSET;
00278       out->datalen = fr->datalen;
00279       memcpy(out->data, fr->data, fr->datalen);
00280    }
00281    out->mallocd = AST_MALLOCD_HDR | AST_MALLOCD_SRC | AST_MALLOCD_DATA;
00282    return out;
00283 }
00284 
00285 struct ast_frame *ast_frdup(struct ast_frame *f)
00286 {
00287    struct ast_frame *out;
00288    int len, srclen = 0;
00289    void *buf;
00290    /* Start with standard stuff */
00291    len = sizeof(struct ast_frame) + AST_FRIENDLY_OFFSET + f->datalen;
00292    /* If we have a source, add space for it */
00293    if (f->src)
00294       srclen = strlen(f->src);
00295    if (srclen > 0)
00296       len += srclen + 1;
00297    buf = malloc(len);
00298    if (!buf)
00299       return NULL;
00300    out = buf;
00301    /* Set us as having malloc'd header only, so it will eventually
00302       get freed. */
00303    out->frametype = f->frametype;
00304    out->subclass = f->subclass;
00305    out->datalen = f->datalen;
00306    out->samples = f->samples;
00307    out->delivery = f->delivery;
00308    out->mallocd = AST_MALLOCD_HDR;
00309    out->offset = AST_FRIENDLY_OFFSET;
00310    out->data = buf + sizeof(struct ast_frame) + AST_FRIENDLY_OFFSET;
00311    if (srclen > 0) {
00312       out->src = out->data + f->datalen;
00313       /* Must have space since we allocated for it */
00314       strcpy(out->src, f->src);
00315    } else
00316       out->src = NULL;
00317    out->prev = NULL;
00318    out->next = NULL;
00319    memcpy(out->data, f->data, out->datalen); 
00320    return out;
00321 }
00322 
00323 struct ast_frame *ast_fr_fdread(int fd)
00324 {
00325    char buf[65536];
00326    int res;
00327    int ttl = sizeof(struct ast_frame);
00328    struct ast_frame *f = (struct ast_frame *)buf;
00329    /* Read a frame directly from there.  They're always in the
00330       right format. */
00331    
00332    while(ttl) {
00333       res = read(fd, buf, ttl);
00334       if (res < 0) {
00335          ast_log(LOG_WARNING, "Bad read on %d: %s\n", fd, strerror(errno));
00336          return NULL;
00337       }
00338       ttl -= res;
00339    }
00340    
00341    /* read the frame header */
00342    f->mallocd = 0;
00343    /* Re-write data position */
00344    f->data = buf + sizeof(struct ast_frame);
00345    f->offset = 0;
00346    /* Forget about being mallocd */
00347    f->mallocd = 0;
00348    /* Re-write the source */
00349    f->src = __FUNCTION__;
00350    if (f->datalen > sizeof(buf) - sizeof(struct ast_frame)) {
00351       /* Really bad read */
00352       ast_log(LOG_WARNING, "Strange read (%d bytes)\n", f->datalen);
00353       return NULL;
00354    }
00355    if (f->datalen) {
00356       if ((res = read(fd, f->data, f->datalen)) != f->datalen) {
00357          /* Bad read */
00358          ast_log(LOG_WARNING, "How very strange, expected %d, got %d\n", f->datalen, res);
00359          return NULL;
00360       }
00361    }
00362    if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_HANGUP)) {
00363       return NULL;
00364    }
00365    return ast_frisolate(f);
00366 }
00367 
00368 /* Some convenient routines for sending frames to/from stream or datagram
00369    sockets, pipes, etc (maybe even files) */
00370 
00371 int ast_fr_fdwrite(int fd, struct ast_frame *frame)
00372 {
00373    /* Write the frame exactly */
00374    if (write(fd, frame, sizeof(struct ast_frame)) != sizeof(struct ast_frame)) {
00375       ast_log(LOG_WARNING, "Write error: %s\n", strerror(errno));
00376       return -1;
00377    }
00378    if (write(fd, frame->data, frame->datalen) != frame->datalen) {
00379       ast_log(LOG_WARNING, "Write error: %s\n", strerror(errno));
00380       return -1;
00381    }
00382    return 0;
00383 }
00384 
00385 int ast_fr_fdhangup(int fd)
00386 {
00387    struct ast_frame hangup = {
00388       AST_FRAME_CONTROL,
00389       AST_CONTROL_HANGUP
00390    };
00391    return ast_fr_fdwrite(fd, &hangup);
00392 }
00393 
00394 char* ast_getformatname(int format)
00395 {
00396    if (format == AST_FORMAT_G723_1) 
00397       return "G723";
00398    else if (format == AST_FORMAT_GSM)
00399       return "GSM";
00400    else if (format == AST_FORMAT_ULAW)
00401       return "ULAW";
00402    else if (format == AST_FORMAT_ALAW)
00403       return "ALAW";
00404    else if (format == AST_FORMAT_G726)
00405       return "G726";
00406    else if (format == AST_FORMAT_SLINEAR)
00407       return "SLINR";
00408    else if (format == AST_FORMAT_LPC10)
00409       return "LPC10";
00410    else if (format == AST_FORMAT_ADPCM)
00411       return "ADPCM";
00412    else if (format == AST_FORMAT_G729A)
00413       return "G729A";
00414    else if (format == AST_FORMAT_SPEEX)
00415       return "SPEEX";
00416    else if (format == AST_FORMAT_ILBC)
00417       return "ILBC";
00418    else if (format == AST_FORMAT_JPEG)
00419       return "JPEG";
00420    else if (format == AST_FORMAT_PNG)
00421       return "PNG";
00422    else if (format == AST_FORMAT_H261)
00423       return "H261";
00424    else if (format == AST_FORMAT_H263)
00425       return "H263";
00426    return "UNKN";
00427 }
00428 
00429 char* ast_getformatname_multiple(char *buf, unsigned n, int format) {
00430    unsigned u=1;
00431    unsigned len;
00432    char *b = buf;
00433    char *start = buf;
00434    if (!n) return buf;
00435    snprintf(b,n,"0x%x(",format);
00436    len = strlen(b);
00437    b += len;
00438    n -= len;
00439    start = b;
00440    while (u) {
00441       if (u&format) {
00442          snprintf(b,n,"%s|",ast_getformatname(u));
00443          len = strlen(b);
00444          b += len;
00445          n -= len;
00446       }
00447       u *= 2;
00448    }
00449    if (start==b)
00450       snprintf(start,n,"EMPTY)");
00451    else if (n>1)
00452       b[-1]=')';
00453    return buf;
00454 }
00455 
00456 int ast_getformatbyname(char *name)
00457 {
00458    if (!strcasecmp(name, "g723.1")) 
00459       return AST_FORMAT_G723_1;
00460    else if (!strcasecmp(name, "gsm"))
00461       return AST_FORMAT_GSM;
00462    else if (!strcasecmp(name, "ulaw"))
00463       return AST_FORMAT_ULAW;
00464    else if (!strcasecmp(name, "alaw"))
00465       return AST_FORMAT_ALAW;
00466    else if (!strcasecmp(name, "g726"))
00467       return AST_FORMAT_G726;
00468    else if (!strcasecmp(name, "slinear"))
00469       return AST_FORMAT_SLINEAR;
00470    else if (!strcasecmp(name, "lpc10"))
00471       return AST_FORMAT_LPC10;
00472    else if (!strcasecmp(name, "adpcm"))
00473       return AST_FORMAT_ADPCM;
00474    else if (!strcasecmp(name, "g729"))
00475       return AST_FORMAT_G729A;
00476    else if (!strcasecmp(name, "speex"))
00477       return AST_FORMAT_SPEEX;
00478    else if (!strcasecmp(name, "ilbc"))
00479       return AST_FORMAT_ILBC;
00480    else if (!strcasecmp(name, "h261"))
00481       return AST_FORMAT_H261;
00482    else if (!strcasecmp(name, "h263"))
00483       return AST_FORMAT_H263;
00484    else if (!strcasecmp(name, "all"))
00485       return 0x7FFFFFFF;
00486    return 0;
00487 }
00488 
00489 char *ast_codec2str(int codec) {
00490    static char codecs[25][30] = {
00491       /* Audio formats */
00492       "G.723.1",                    /*  0 */
00493       "GSM",                        /*  1 */
00494       "G.711 u-law",                /*  2 */
00495       "G.711 A-law",                /*  3 */
00496       "G.726",                      /*  4 */
00497       "ADPCM",                      /*  5 */
00498       "16 bit Signed Linear PCM",   /*  6 */
00499       "LPC10",                      /*  7 */
00500       "G.729A audio",               /*  8 */
00501       "SpeeX",                      /*  9 */
00502       "iLBC",                       /* 10 */
00503       "undefined",                  /* 11 */
00504       "undefined",                  /* 12 */
00505       "undefined",                  /* 13 */
00506       "undefined",                  /* 14 */
00507       "Maximum audio format",       /* 15 */
00508       /* Image formats */
00509       "JPEG image",                 /* 16 */
00510       "PNG image",                  /* 17 */
00511       "H.261 Video",                /* 18 */
00512       "H.263 Video",                /* 19 */
00513       "undefined",                  /* 20 */
00514       "undefined",                  /* 21 */
00515       "undefined",                  /* 22 */
00516       "undefined",                  /* 23 */
00517       "Maximum video format",       /* 24 */
00518       };
00519    if ((codec >= 0) && (codec <= 24))
00520       return codecs[codec];
00521    else
00522       return "unknown";
00523 }
00524 
00525 static int show_codecs(int fd, int argc, char *argv[])
00526 {
00527    int i, found=0;
00528 
00529    if ((argc < 2) || (argc > 3))
00530       return RESULT_SHOWUSAGE;
00531 
00532    if (getenv("I_AM_NOT_AN_IDIOT") == NULL)
00533       ast_cli(fd, "Disclaimer: this command is for informational purposes only.\n"
00534             "\tIt does not indicate anything about your configuration.\n");
00535 
00536    if ((argc == 2) || (!strcasecmp(argv[1],"audio"))) {
00537       found = 1;
00538       for (i=0;i<11;i++)
00539          ast_cli(fd, "%11u (1 << %2d)  %s\n",1 << i,i,ast_codec2str(i));
00540    }
00541 
00542    if ((argc == 2) || (!strcasecmp(argv[1],"image"))) {
00543       found = 1;
00544       for (i=16;i<18;i++)
00545          ast_cli(fd, "%11u (1 << %2d)  %s\n",1 << i,i,ast_codec2str(i));
00546    }
00547 
00548    if ((argc == 2) || (!strcasecmp(argv[1],"video"))) {
00549       found = 1;
00550       for (i=18;i<20;i++)
00551          ast_cli(fd, "%11u (1 << %2d)  %s\n",1 << i,i,ast_codec2str(i));
00552    }
00553 
00554    if (! found)
00555       return RESULT_SHOWUSAGE;
00556    else
00557       return RESULT_SUCCESS;
00558 }
00559 
00560 static char frame_show_codecs_usage[] =
00561 "Usage: show [audio|video|image] codecs\n"
00562 "       Displays codec mapping\n";
00563 
00564 struct ast_cli_entry cli_show_codecs =
00565 { { "show", "codecs", NULL }, show_codecs, "Shows codecs", frame_show_codecs_usage };
00566 struct ast_cli_entry cli_show_codecs_audio =
00567 { { "show", "audio", "codecs", NULL }, show_codecs, "Shows audio codecs", frame_show_codecs_usage };
00568 struct ast_cli_entry cli_show_codecs_video =
00569 { { "show", "video", "codecs", NULL }, show_codecs, "Shows video codecs", frame_show_codecs_usage };
00570 struct ast_cli_entry cli_show_codecs_image =
00571 { { "show", "image", "codecs", NULL }, show_codecs, "Shows image codecs", frame_show_codecs_usage };
00572 
00573 static int show_codec_n(int fd, int argc, char *argv[])
00574 {
00575    int codec, i, found=0;
00576 
00577    if (argc != 3)
00578       return RESULT_SHOWUSAGE;
00579 
00580    if (sscanf(argv[2],"%d",&codec) != 1)
00581       return RESULT_SHOWUSAGE;
00582 
00583    for (i=0;i<32;i++)
00584       if (codec & (1 << i)) {
00585          found = 1;
00586          ast_cli(fd, "%11u (1 << %2d)  %s\n",1 << i,i,ast_codec2str(i));
00587       }
00588 
00589    if (! found)
00590       ast_cli(fd, "Codec %d not found\n", codec);
00591 
00592    return RESULT_SUCCESS;
00593 }
00594 
00595 static char frame_show_codec_n_usage[] =
00596 "Usage: show codec <number>\n"
00597 "       Displays codec mapping\n";
00598 
00599 struct ast_cli_entry cli_show_codec_n =
00600 { { "show", "codec", NULL }, show_codec_n, "Shows a specific codec", frame_show_codec_n_usage };
00601 
00602 void ast_frame_dump(char *name, struct ast_frame *f, char *prefix)
00603 {
00604    char *n = "unknown";
00605    char ftype[40] = "Unknown Frametype";
00606    char cft[80];
00607    char subclass[40] = "Unknown Subclass";
00608    char csub[80];
00609    char moreinfo[40] = "";
00610    char cn[40];
00611    char cp[40];
00612    char cmn[40];
00613    if (name)
00614       n = name;
00615    if (!f) {
00616       ast_verbose("%s [ %s (NULL) ] [%s]\n", 
00617          term_color(cp, prefix, COLOR_BRMAGENTA, COLOR_BLACK, sizeof(cp)),
00618          term_color(cft, "HANGUP", COLOR_BRRED, COLOR_BLACK, sizeof(cft)), 
00619          term_color(cn, n, COLOR_YELLOW, COLOR_BLACK, sizeof(cn)));
00620       return;
00621    }
00622    /* XXX We should probably print one each of voice and video when the format changes XXX */
00623    if (f->frametype == AST_FRAME_VOICE)
00624       return;
00625    if (f->frametype == AST_FRAME_VIDEO)
00626       return;
00627    switch(f->frametype) {
00628    case AST_FRAME_DTMF:
00629       strcpy(ftype, "DTMF");
00630       subclass[0] = f->subclass;
00631       subclass[1] = '\0';
00632       break;
00633    case AST_FRAME_CONTROL:
00634       strcpy(ftype, "Control");
00635       switch(f->subclass) {
00636       case AST_CONTROL_HANGUP:
00637          strcpy(subclass, "Hangup");
00638          break;
00639       case AST_CONTROL_RING:
00640          strcpy(subclass, "Ring");
00641          break;
00642       case AST_CONTROL_RINGING:
00643          strcpy(subclass, "Ringing");
00644          break;
00645       case AST_CONTROL_ANSWER:
00646          strcpy(subclass, "Answer");
00647          break;
00648       case AST_CONTROL_BUSY:
00649          strcpy(subclass, "Busy");
00650          break;
00651       case AST_CONTROL_TAKEOFFHOOK:
00652          strcpy(subclass, "Take Off Hook");
00653          break;
00654       case AST_CONTROL_OFFHOOK:
00655          strcpy(subclass, "Line Off Hook");
00656          break;
00657       case AST_CONTROL_CONGESTION:
00658          strcpy(subclass, "Congestion");
00659          break;
00660       case AST_CONTROL_FLASH:
00661          strcpy(subclass, "Flash");
00662          break;
00663       case AST_CONTROL_WINK:
00664          strcpy(subclass, "Wink");
00665          break;
00666       case AST_CONTROL_OPTION:
00667          strcpy(subclass, "Option");
00668          break;
00669       case AST_CONTROL_RADIO_KEY:
00670          strcpy(subclass, "Key Radio");
00671          break;
00672       case AST_CONTROL_RADIO_UNKEY:
00673          strcpy(subclass, "Unkey Radio");
00674          break;
00675       default:
00676          snprintf(subclass, sizeof(subclass), "Unknown control '%d'", f->subclass);
00677       }
00678    case AST_FRAME_NULL:
00679       strcpy(ftype, "Null Frame");
00680       strcpy(subclass, "N/A");
00681       break;
00682    case AST_FRAME_IAX:
00683       /* Should never happen */
00684       strcpy(ftype, "IAX Specific");
00685       snprintf(subclass, sizeof(subclass), "IAX Frametype %d", f->subclass);
00686       break;
00687    case AST_FRAME_TEXT:
00688       strcpy(ftype, "Text");
00689       strcpy(subclass, "N/A");
00690       strncpy(moreinfo, f->data, sizeof(moreinfo) - 1);
00691       break;
00692    case AST_FRAME_IMAGE:
00693       strcpy(ftype, "Image");
00694       snprintf(subclass, sizeof(subclass), "Image format %s\n", ast_getformatname(f->subclass));
00695       break;
00696    case AST_FRAME_HTML:
00697       strcpy(ftype, "HTML");
00698       switch(f->subclass) {
00699       case AST_HTML_URL:
00700          strcpy(subclass, "URL");
00701          strncpy(moreinfo, f->data, sizeof(moreinfo) - 1);
00702          break;
00703       case AST_HTML_DATA:
00704          strcpy(subclass, "Data");
00705          break;
00706       case AST_HTML_BEGIN:
00707          strcpy(subclass, "Begin");
00708          break;
00709       case AST_HTML_END:
00710          strcpy(subclass, "End");
00711          break;
00712       case AST_HTML_LDCOMPLETE:
00713          strcpy(subclass, "Load Complete");
00714          break;
00715       case AST_HTML_NOSUPPORT:
00716          strcpy(subclass, "No Support");
00717          break;
00718       case AST_HTML_LINKURL:
00719          strcpy(subclass, "Link URL");
00720          strncpy(moreinfo, f->data, sizeof(moreinfo) - 1);
00721          break;
00722       case AST_HTML_UNLINK:
00723          strcpy(subclass, "Unlink");
00724          break;
00725       case AST_HTML_LINKREJECT:
00726          strcpy(subclass, "Link Reject");
00727          break;
00728       default:
00729          snprintf(subclass, sizeof(subclass), "Unknown HTML frame '%d'\n", f->subclass);
00730          break;
00731       }
00732       break;
00733    default:
00734       snprintf(ftype, sizeof(ftype), "Unknown Frametype '%d'", f->frametype);
00735    }
00736    if (!ast_strlen_zero(moreinfo))
00737       ast_verbose("%s [ TYPE: %s (%d) SUBCLASS: %s (%d) '%s' ] [%s]\n",  
00738          term_color(cp, prefix, COLOR_BRMAGENTA, COLOR_BLACK, sizeof(cp)),
00739          term_color(cft, ftype, COLOR_BRRED, COLOR_BLACK, sizeof(cft)),
00740          f->frametype, 
00741          term_color(csub, subclass, COLOR_BRCYAN, COLOR_BLACK, sizeof(csub)),
00742          f->subclass, 
00743          term_color(cmn, moreinfo, COLOR_BRGREEN, COLOR_BLACK, sizeof(cmn)),
00744          term_color(cn, n, COLOR_YELLOW, COLOR_BLACK, sizeof(cn)));
00745    else
00746       ast_verbose("%s [ TYPE: %s (%d) SUBCLASS: %s (%d) ] [%s]\n",  
00747          term_color(cp, prefix, COLOR_BRMAGENTA, COLOR_BLACK, sizeof(cp)),
00748          term_color(cft, ftype, COLOR_BRRED, COLOR_BLACK, sizeof(cft)),
00749          f->frametype, 
00750          term_color(csub, subclass, COLOR_BRCYAN, COLOR_BLACK, sizeof(csub)),
00751          f->subclass, 
00752          term_color(cn, n, COLOR_YELLOW, COLOR_BLACK, sizeof(cn)));
00753 
00754 }
00755 
00756 
00757 #ifdef TRACE_FRAMES
00758 static int show_frame_stats(int fd, int argc, char *argv[])
00759 {
00760    struct ast_frame *f;
00761    int x=1;
00762    if (argc != 3)
00763       return RESULT_SHOWUSAGE;
00764    ast_cli(fd, "     Framer Statistics     \n");
00765    ast_cli(fd, "---------------------------\n");
00766    ast_cli(fd, "Total allocated headers: %d\n", headers);
00767    ast_cli(fd, "Queue Dump:\n");
00768    ast_mutex_lock(&framelock);
00769    for (f=headerlist; f; f = f->next) {
00770       ast_cli(fd, "%d.  Type %d, subclass %d from %s\n", x++, f->frametype, f->subclass, f->src ? f->src : "<Unknown>");
00771    }
00772    ast_mutex_unlock(&framelock);
00773    return RESULT_SUCCESS;
00774 }
00775 
00776 static char frame_stats_usage[] =
00777 "Usage: show frame stats\n"
00778 "       Displays debugging statistics from framer\n";
00779 
00780 struct ast_cli_entry cli_frame_stats =
00781 { { "show", "frame", "stats", NULL }, show_frame_stats, "Shows frame statistics", frame_stats_usage };
00782 #endif
00783 
00784 int init_framer(void)
00785 {
00786 #ifdef TRACE_FRAMES
00787    ast_cli_register(&cli_frame_stats);
00788 #endif
00789    ast_cli_register(&cli_show_codecs);
00790    ast_cli_register(&cli_show_codecs_audio);
00791    ast_cli_register(&cli_show_codecs_video);
00792    ast_cli_register(&cli_show_codecs_image);
00793    ast_cli_register(&cli_show_codec_n);
00794    return 0;   
00795 }

Generated on Thu Oct 28 11:32:53 2004 for Asterisk by doxygen1.2.15