00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
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 <stdlib.h>
00021 #include <unistd.h>
00022 #include <string.h>
00023 #include <errno.h>
00024 #include <pthread.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 static ast_mutex_t framelock = AST_MUTEX_INITIALIZER;
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 float samplesperbyte;
00042 struct ast_frame f;
00043 char data[SMOOTHER_SIZE];
00044 char framedata[SMOOTHER_SIZE + AST_FRIENDLY_OFFSET];
00045 struct ast_frame *opt;
00046 int len;
00047 };
00048
00049 void ast_smoother_reset(struct ast_smoother *s, int size)
00050 {
00051 memset(s, 0, sizeof(struct ast_smoother));
00052 s->size = size;
00053 }
00054
00055 struct ast_smoother *ast_smoother_new(int size)
00056 {
00057 struct ast_smoother *s;
00058 if (size < 1)
00059 return NULL;
00060 s = malloc(sizeof(struct ast_smoother));
00061 if (s)
00062 ast_smoother_reset(s, size);
00063 return s;
00064 }
00065
00066 int ast_smoother_feed(struct ast_smoother *s, struct ast_frame *f)
00067 {
00068 if (f->frametype != AST_FRAME_VOICE) {
00069 ast_log(LOG_WARNING, "Huh? Can't smooth a non-voice frame!\n");
00070 return -1;
00071 }
00072 if (!s->format) {
00073 s->format = f->subclass;
00074 s->samplesperbyte = (float)f->samples / (float)f->datalen;
00075 } else if (s->format != f->subclass) {
00076 ast_log(LOG_WARNING, "Smoother was working on %d format frames, now trying to feed %d?\n", s->format, f->subclass);
00077 return -1;
00078 }
00079 if (s->len + f->datalen > SMOOTHER_SIZE) {
00080 ast_log(LOG_WARNING, "Out of smoother space\n");
00081 return -1;
00082 }
00083 if ((f->datalen == s->size) && !s->opt) {
00084 if (!s->len) {
00085
00086
00087
00088 s->opt = f;
00089 return 0;
00090 } else {
00091 s->optimizablestream++;
00092 if (s->optimizablestream > 10) {
00093
00094
00095
00096
00097
00098 s->len = 0;
00099 s->opt = f;
00100 return 0;
00101 }
00102 }
00103 } else
00104 s->optimizablestream = 0;
00105 memcpy(s->data + s->len, f->data, f->datalen);
00106 s->len += f->datalen;
00107 return 0;
00108 }
00109
00110 struct ast_frame *ast_smoother_read(struct ast_smoother *s)
00111 {
00112 struct ast_frame *opt;
00113
00114
00115 if (s->opt) {
00116 opt = s->opt;
00117 s->opt = NULL;
00118 return opt;
00119 }
00120
00121
00122 if (s->len < s->size) {
00123 return NULL;
00124 }
00125
00126 s->f.frametype = AST_FRAME_VOICE;
00127 s->f.subclass = s->format;
00128 s->f.data = s->framedata + AST_FRIENDLY_OFFSET;
00129 s->f.offset = AST_FRIENDLY_OFFSET;
00130 s->f.datalen = s->size;
00131 s->f.samples = s->size * s->samplesperbyte;
00132
00133 memcpy(s->f.data, s->data, s->size);
00134 s->len -= s->size;
00135
00136 if (s->len)
00137 memmove(s->data, s->data + s->size, s->len);
00138
00139 return &s->f;
00140 }
00141
00142 void ast_smoother_free(struct ast_smoother *s)
00143 {
00144 free(s);
00145 }
00146
00147 static struct ast_frame *ast_frame_header_new(void)
00148 {
00149 struct ast_frame *f;
00150 f = malloc(sizeof(struct ast_frame));
00151 if (f)
00152 memset(f, 0, sizeof(struct ast_frame));
00153 #ifdef TRACE_FRAMES
00154 if (f) {
00155 headers++;
00156 f->prev = NULL;
00157 ast_mutex_lock(&framelock);
00158 f->next = headerlist;
00159 if (headerlist)
00160 headerlist->prev = f;
00161 headerlist = f;
00162 ast_mutex_unlock(&framelock);
00163 }
00164 #endif
00165 return f;
00166 }
00167
00168
00169
00170
00171
00172
00173 void ast_frfree(struct ast_frame *fr)
00174 {
00175 if (fr->mallocd & AST_MALLOCD_DATA) {
00176 if (fr->data)
00177 free(fr->data - fr->offset);
00178 }
00179 if (fr->mallocd & AST_MALLOCD_SRC) {
00180 if (fr->src)
00181 free(fr->src);
00182 }
00183 if (fr->mallocd & AST_MALLOCD_HDR) {
00184 #ifdef TRACE_FRAMES
00185 headers--;
00186 ast_mutex_lock(&framelock);
00187 if (fr->next)
00188 fr->next->prev = fr->prev;
00189 if (fr->prev)
00190 fr->prev->next = fr->next;
00191 else
00192 headerlist = fr->next;
00193 ast_mutex_unlock(&framelock);
00194 #endif
00195 free(fr);
00196 }
00197 }
00198
00199 struct ast_frame *ast_frisolate(struct ast_frame *fr)
00200 {
00201 struct ast_frame *out;
00202 if (!(fr->mallocd & AST_MALLOCD_HDR)) {
00203
00204 out = ast_frame_header_new();
00205 if (!out) {
00206 ast_log(LOG_WARNING, "Out of memory\n");
00207 return NULL;
00208 }
00209 out->frametype = fr->frametype;
00210 out->subclass = fr->subclass;
00211 out->datalen = 0;
00212 out->samples = fr->samples;
00213 out->offset = 0;
00214 out->src = NULL;
00215 out->data = NULL;
00216 } else {
00217 out = fr;
00218 }
00219 if (!(fr->mallocd & AST_MALLOCD_SRC)) {
00220 if (fr->src)
00221 out->src = strdup(fr->src);
00222 } else
00223 out->src = fr->src;
00224 if (!(fr->mallocd & AST_MALLOCD_DATA)) {
00225 out->data = malloc(fr->datalen + AST_FRIENDLY_OFFSET);
00226 if (!out->data) {
00227 free(out);
00228 ast_log(LOG_WARNING, "Out of memory\n");
00229 return NULL;
00230 }
00231 out->data += AST_FRIENDLY_OFFSET;
00232 out->offset = AST_FRIENDLY_OFFSET;
00233 out->datalen = fr->datalen;
00234 memcpy(out->data, fr->data, fr->datalen);
00235 }
00236 out->mallocd = AST_MALLOCD_HDR | AST_MALLOCD_SRC | AST_MALLOCD_DATA;
00237 return out;
00238 }
00239
00240 struct ast_frame *ast_frdup(struct ast_frame *f)
00241 {
00242 struct ast_frame *out;
00243 int len;
00244 void *buf;
00245
00246 len = sizeof(struct ast_frame) + AST_FRIENDLY_OFFSET + f->datalen;
00247
00248 if (f->src && strlen(f->src))
00249 len += strlen(f->src) + 1;
00250 buf = malloc(len);
00251 if (!buf)
00252 return NULL;
00253 out = buf;
00254
00255
00256 out->frametype = f->frametype;
00257 out->subclass = f->subclass;
00258 out->datalen = f->datalen;
00259 out->samples = f->samples;
00260 out->mallocd = AST_MALLOCD_HDR;
00261 out->offset = AST_FRIENDLY_OFFSET;
00262 out->data = buf + sizeof(struct ast_frame) + AST_FRIENDLY_OFFSET;
00263 if (f->src && strlen(f->src)) {
00264 out->src = out->data + f->datalen;
00265
00266 strcpy(out->src, f->src);
00267 } else
00268 out->src = NULL;
00269 out->prev = NULL;
00270 out->next = NULL;
00271 memcpy(out->data, f->data, out->datalen);
00272 return out;
00273 }
00274
00275 struct ast_frame *ast_fr_fdread(int fd)
00276 {
00277 char buf[65536];
00278 int res;
00279 int ttl = sizeof(struct ast_frame);
00280 struct ast_frame *f = (struct ast_frame *)buf;
00281
00282
00283
00284 while(ttl) {
00285 res = read(fd, buf, ttl);
00286 if (res < 0) {
00287 ast_log(LOG_WARNING, "Bad read on %d: %s\n", fd, strerror(errno));
00288 return NULL;
00289 }
00290 ttl -= res;
00291 }
00292
00293
00294 f->mallocd = 0;
00295
00296 f->data = buf + sizeof(struct ast_frame);
00297 f->offset = 0;
00298
00299 f->mallocd = 0;
00300
00301 f->src = __FUNCTION__;
00302 if (f->datalen > sizeof(buf) - sizeof(struct ast_frame)) {
00303
00304 ast_log(LOG_WARNING, "Strange read (%d bytes)\n", f->datalen);
00305 return NULL;
00306 }
00307 if (f->datalen) {
00308 if ((res = read(fd, f->data, f->datalen)) != f->datalen) {
00309
00310 ast_log(LOG_WARNING, "How very strange, expected %d, got %d\n", f->datalen, res);
00311 return NULL;
00312 }
00313 }
00314 if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_HANGUP)) {
00315 return NULL;
00316 }
00317 return ast_frisolate(f);
00318 }
00319
00320
00321
00322
00323 int ast_fr_fdwrite(int fd, struct ast_frame *frame)
00324 {
00325
00326 if (write(fd, frame, sizeof(struct ast_frame)) != sizeof(struct ast_frame)) {
00327 ast_log(LOG_WARNING, "Write error: %s\n", strerror(errno));
00328 return -1;
00329 }
00330 if (write(fd, frame->data, frame->datalen) != frame->datalen) {
00331 ast_log(LOG_WARNING, "Write error: %s\n", strerror(errno));
00332 return -1;
00333 }
00334 return 0;
00335 }
00336
00337 int ast_fr_fdhangup(int fd)
00338 {
00339 struct ast_frame hangup = {
00340 AST_FRAME_CONTROL,
00341 AST_CONTROL_HANGUP
00342 };
00343 return ast_fr_fdwrite(fd, &hangup);
00344 }
00345
00346 char* ast_getformatname(int format)
00347 {
00348 if (format == AST_FORMAT_G723_1)
00349 return "G723";
00350 else if (format == AST_FORMAT_GSM)
00351 return "GSM";
00352 else if (format == AST_FORMAT_ULAW)
00353 return "ULAW";
00354 else if (format == AST_FORMAT_ALAW)
00355 return "ALAW";
00356 else if (format == AST_FORMAT_G726)
00357 return "G726";
00358 else if (format == AST_FORMAT_SLINEAR)
00359 return "SLINR";
00360 else if (format == AST_FORMAT_LPC10)
00361 return "LPC10";
00362 else if (format == AST_FORMAT_ADPCM)
00363 return "ADPCM";
00364 else if (format == AST_FORMAT_G729A)
00365 return "G729A";
00366 else if (format == AST_FORMAT_SPEEX)
00367 return "SPEEX";
00368 else if (format == AST_FORMAT_ILBC)
00369 return "ILBC";
00370 else if (format == AST_FORMAT_JPEG)
00371 return "JPEG";
00372 else if (format == AST_FORMAT_PNG)
00373 return "PNG";
00374 else if (format == AST_FORMAT_H261)
00375 return "H261";
00376 else if (format == AST_FORMAT_H263)
00377 return "H263";
00378 return "UNKN";
00379 }
00380
00381 int ast_getformatbyname(char *name)
00382 {
00383 if (!strcasecmp(name, "g723.1"))
00384 return AST_FORMAT_G723_1;
00385 else if (!strcasecmp(name, "gsm"))
00386 return AST_FORMAT_GSM;
00387 else if (!strcasecmp(name, "ulaw"))
00388 return AST_FORMAT_ULAW;
00389 else if (!strcasecmp(name, "alaw"))
00390 return AST_FORMAT_ALAW;
00391 else if (!strcasecmp(name, "g726"))
00392 return AST_FORMAT_G726;
00393 else if (!strcasecmp(name, "slinear"))
00394 return AST_FORMAT_SLINEAR;
00395 else if (!strcasecmp(name, "lpc10"))
00396 return AST_FORMAT_LPC10;
00397 else if (!strcasecmp(name, "adpcm"))
00398 return AST_FORMAT_ADPCM;
00399 else if (!strcasecmp(name, "g729"))
00400 return AST_FORMAT_G729A;
00401 else if (!strcasecmp(name, "speex"))
00402 return AST_FORMAT_SPEEX;
00403 else if (!strcasecmp(name, "ilbc"))
00404 return AST_FORMAT_ILBC;
00405 else if (!strcasecmp(name, "h261"))
00406 return AST_FORMAT_H261;
00407 else if (!strcasecmp(name, "h263"))
00408 return AST_FORMAT_H263;
00409 else if (!strcasecmp(name, "all"))
00410 return 0x7FFFFFFF;
00411 return 0;
00412 }
00413
00414 char *ast_codec2str(int codec) {
00415 static char codecs[25][30] = {
00416
00417 "G.723.1",
00418 "GSM",
00419 "G.711 u-law",
00420 "G.711 A-law",
00421 "MPEG-2 layer 3",
00422 "ADPCM",
00423 "16 bit Signed Linear PCM",
00424 "LPC10",
00425 "G.729A audio",
00426 "SpeeX",
00427 "iLBC",
00428 "undefined",
00429 "undefined",
00430 "undefined",
00431 "undefined",
00432 "Maximum audio format",
00433
00434 "JPEG image",
00435 "PNG image",
00436 "H.261 Video",
00437 "H.263 Video",
00438 "undefined",
00439 "undefined",
00440 "undefined",
00441 "undefined",
00442 "Maximum video format",
00443 };
00444 if ((codec >= 0) && (codec <= 24))
00445 return codecs[codec];
00446 else
00447 return "unknown";
00448 }
00449
00450 static int show_codecs(int fd, int argc, char *argv[])
00451 {
00452 int i, found=0;
00453
00454 if ((argc < 2) || (argc > 3))
00455 return RESULT_SHOWUSAGE;
00456
00457 if (getenv("I_AM_NOT_AN_IDIOT") == NULL)
00458 ast_cli(fd, "Disclaimer: this command is for informational purposes only.\n"
00459 "\tIt does not indicate anything about your configuration.\n");
00460
00461 if ((argc == 2) || (!strcasecmp(argv[1],"audio"))) {
00462 found = 1;
00463 for (i=0;i<11;i++)
00464 ast_cli(fd, "%11u (1 << %2d) %s\n",1 << i,i,ast_codec2str(i));
00465 }
00466
00467 if ((argc == 2) || (!strcasecmp(argv[1],"image"))) {
00468 found = 1;
00469 for (i=16;i<18;i++)
00470 ast_cli(fd, "%11u (1 << %2d) %s\n",1 << i,i,ast_codec2str(i));
00471 }
00472
00473 if ((argc == 2) || (!strcasecmp(argv[1],"video"))) {
00474 found = 1;
00475 for (i=18;i<20;i++)
00476 ast_cli(fd, "%11u (1 << %2d) %s\n",1 << i,i,ast_codec2str(i));
00477 }
00478
00479 if (! found)
00480 return RESULT_SHOWUSAGE;
00481 else
00482 return RESULT_SUCCESS;
00483 }
00484
00485 static char frame_show_codecs_usage[] =
00486 "Usage: show [audio|video|image] codecs\n"
00487 " Displays codec mapping\n";
00488
00489 struct ast_cli_entry cli_show_codecs =
00490 { { "show", "codecs", NULL }, show_codecs, "Shows codecs", frame_show_codecs_usage };
00491 struct ast_cli_entry cli_show_codecs_audio =
00492 { { "show", "audio", "codecs", NULL }, show_codecs, "Shows audio codecs", frame_show_codecs_usage };
00493 struct ast_cli_entry cli_show_codecs_video =
00494 { { "show", "video", "codecs", NULL }, show_codecs, "Shows video codecs", frame_show_codecs_usage };
00495 struct ast_cli_entry cli_show_codecs_image =
00496 { { "show", "image", "codecs", NULL }, show_codecs, "Shows image codecs", frame_show_codecs_usage };
00497
00498 static int show_codec_n(int fd, int argc, char *argv[])
00499 {
00500 int codec, i, found=0;
00501
00502 if (argc != 3)
00503 return RESULT_SHOWUSAGE;
00504
00505 if (sscanf(argv[2],"%d",&codec) != 1)
00506 return RESULT_SHOWUSAGE;
00507
00508 for (i=0;i<32;i++)
00509 if (codec & (1 << i)) {
00510 found = 1;
00511 ast_cli(fd, "%11u (1 << %2d) %s\n",1 << i,i,ast_codec2str(i));
00512 }
00513
00514 if (! found)
00515 ast_cli(fd, "Codec %d not found\n", codec);
00516
00517 return RESULT_SUCCESS;
00518 }
00519
00520 static char frame_show_codec_n_usage[] =
00521 "Usage: show codec <number>\n"
00522 " Displays codec mapping\n";
00523
00524 struct ast_cli_entry cli_show_codec_n =
00525 { { "show", "codec", NULL }, show_codec_n, "Shows a specific codec", frame_show_codec_n_usage };
00526
00527 void ast_frame_dump(char *name, struct ast_frame *f, char *prefix)
00528 {
00529 char *n = "unknown";
00530 char ftype[40] = "Unknown Frametype";
00531 char cft[80];
00532 char subclass[40] = "Unknown Subclass";
00533 char csub[80];
00534 char moreinfo[40] = "";
00535 char cn[40];
00536 char cp[40];
00537 char cmn[40];
00538 if (name)
00539 n = name;
00540 if (!f) {
00541 ast_verbose("%s [ %s (NULL) ] [%s]\n",
00542 term_color(cp, prefix, COLOR_BRMAGENTA, COLOR_BLACK, sizeof(cp)),
00543 term_color(cft, "HANGUP", COLOR_BRRED, COLOR_BLACK, sizeof(cft)),
00544 term_color(cn, n, COLOR_YELLOW, COLOR_BLACK, sizeof(cn)));
00545 return;
00546 }
00547
00548 if (f->frametype == AST_FRAME_VOICE)
00549 return;
00550 if (f->frametype == AST_FRAME_VIDEO)
00551 return;
00552 switch(f->frametype) {
00553 case AST_FRAME_DTMF:
00554 strcpy(ftype, "DTMF");
00555 subclass[0] = f->subclass;
00556 subclass[1] = '\0';
00557 break;
00558 case AST_FRAME_CONTROL:
00559 strcpy(ftype, "Control");
00560 switch(f->subclass) {
00561 case AST_CONTROL_HANGUP:
00562 strcpy(subclass, "Hangup");
00563 break;
00564 case AST_CONTROL_RING:
00565 strcpy(subclass, "Ring");
00566 break;
00567 case AST_CONTROL_RINGING:
00568 strcpy(subclass, "Ringing");
00569 break;
00570 case AST_CONTROL_ANSWER:
00571 strcpy(subclass, "Answer");
00572 break;
00573 case AST_CONTROL_BUSY:
00574 strcpy(subclass, "Busy");
00575 break;
00576 case AST_CONTROL_TAKEOFFHOOK:
00577 strcpy(subclass, "Take Off Hook");
00578 break;
00579 case AST_CONTROL_OFFHOOK:
00580 strcpy(subclass, "Line Off Hook");
00581 break;
00582 case AST_CONTROL_CONGESTION:
00583 strcpy(subclass, "Congestion");
00584 break;
00585 case AST_CONTROL_FLASH:
00586 strcpy(subclass, "Flash");
00587 break;
00588 case AST_CONTROL_WINK:
00589 strcpy(subclass, "Wink");
00590 break;
00591 case AST_CONTROL_OPTION:
00592 strcpy(subclass, "Option");
00593 break;
00594 case AST_CONTROL_RADIO_KEY:
00595 strcpy(subclass, "Key Radio");
00596 break;
00597 case AST_CONTROL_RADIO_UNKEY:
00598 strcpy(subclass, "Unkey Radio");
00599 break;
00600 default:
00601 snprintf(subclass, sizeof(subclass), "Unknown control '%d'", f->subclass);
00602 }
00603 case AST_FRAME_NULL:
00604 strcpy(ftype, "Null Frame");
00605 strcpy(subclass, "N/A");
00606 break;
00607 case AST_FRAME_IAX:
00608
00609 strcpy(ftype, "IAX Specific");
00610 snprintf(subclass, sizeof(subclass), "IAX Frametype %d", f->subclass);
00611 break;
00612 case AST_FRAME_TEXT:
00613 strcpy(ftype, "Text");
00614 strcpy(subclass, "N/A");
00615 strncpy(moreinfo, f->data, sizeof(moreinfo) - 1);
00616 break;
00617 case AST_FRAME_IMAGE:
00618 strcpy(ftype, "Image");
00619 snprintf(subclass, sizeof(subclass), "Image format %s\n", ast_getformatname(f->subclass));
00620 break;
00621 case AST_FRAME_HTML:
00622 strcpy(ftype, "HTML");
00623 switch(f->subclass) {
00624 case AST_HTML_URL:
00625 strcpy(subclass, "URL");
00626 strncpy(moreinfo, f->data, sizeof(moreinfo) - 1);
00627 break;
00628 case AST_HTML_DATA:
00629 strcpy(subclass, "Data");
00630 break;
00631 case AST_HTML_BEGIN:
00632 strcpy(subclass, "Begin");
00633 break;
00634 case AST_HTML_END:
00635 strcpy(subclass, "End");
00636 break;
00637 case AST_HTML_LDCOMPLETE:
00638 strcpy(subclass, "Load Complete");
00639 break;
00640 case AST_HTML_NOSUPPORT:
00641 strcpy(subclass, "No Support");
00642 break;
00643 case AST_HTML_LINKURL:
00644 strcpy(subclass, "Link URL");
00645 strncpy(moreinfo, f->data, sizeof(moreinfo) - 1);
00646 break;
00647 case AST_HTML_UNLINK:
00648 strcpy(subclass, "Unlink");
00649 break;
00650 case AST_HTML_LINKREJECT:
00651 strcpy(subclass, "Link Reject");
00652 break;
00653 default:
00654 snprintf(subclass, sizeof(subclass), "Unknown HTML frame '%d'\n", f->subclass);
00655 break;
00656 }
00657 break;
00658 default:
00659 snprintf(ftype, sizeof(ftype), "Unknown Frametype '%d'", f->frametype);
00660 }
00661 if (strlen(moreinfo))
00662 ast_verbose("%s [ TYPE: %s (%d) SUBCLASS: %s (%d) '%s' ] [%s]\n",
00663 term_color(cp, prefix, COLOR_BRMAGENTA, COLOR_BLACK, sizeof(cp)),
00664 term_color(cft, ftype, COLOR_BRRED, COLOR_BLACK, sizeof(cft)),
00665 f->frametype,
00666 term_color(csub, subclass, COLOR_BRCYAN, COLOR_BLACK, sizeof(csub)),
00667 f->subclass,
00668 term_color(cmn, moreinfo, COLOR_BRGREEN, COLOR_BLACK, sizeof(cmn)),
00669 term_color(cn, n, COLOR_YELLOW, COLOR_BLACK, sizeof(cn)));
00670 else
00671 ast_verbose("%s [ TYPE: %s (%d) SUBCLASS: %s (%d) ] [%s]\n",
00672 term_color(cp, prefix, COLOR_BRMAGENTA, COLOR_BLACK, sizeof(cp)),
00673 term_color(cft, ftype, COLOR_BRRED, COLOR_BLACK, sizeof(cft)),
00674 f->frametype,
00675 term_color(csub, subclass, COLOR_BRCYAN, COLOR_BLACK, sizeof(csub)),
00676 f->subclass,
00677 term_color(cn, n, COLOR_YELLOW, COLOR_BLACK, sizeof(cn)));
00678
00679 }
00680
00681
00682 #ifdef TRACE_FRAMES
00683 static int show_frame_stats(int fd, int argc, char *argv[])
00684 {
00685 struct ast_frame *f;
00686 int x=1;
00687 if (argc != 3)
00688 return RESULT_SHOWUSAGE;
00689 ast_cli(fd, " Framer Statistics \n");
00690 ast_cli(fd, "---------------------------\n");
00691 ast_cli(fd, "Total allocated headers: %d\n", headers);
00692 ast_cli(fd, "Queue Dump:\n");
00693 ast_mutex_lock(&framelock);
00694 for (f=headerlist; f; f = f->next) {
00695 ast_cli(fd, "%d. Type %d, subclass %d from %s\n", x++, f->frametype, f->subclass, f->src ? f->src : "<Unknown>");
00696 }
00697 ast_mutex_unlock(&framelock);
00698 return RESULT_SUCCESS;
00699 }
00700
00701 static char frame_stats_usage[] =
00702 "Usage: show frame stats\n"
00703 " Displays debugging statistics from framer\n";
00704
00705 struct ast_cli_entry cli_frame_stats =
00706 { { "show", "frame", "stats", NULL }, show_frame_stats, "Shows frame statistics", frame_stats_usage };
00707 #endif
00708
00709 int init_framer(void)
00710 {
00711 #ifdef TRACE_FRAMES
00712 ast_cli_register(&cli_frame_stats);
00713 #endif
00714 ast_cli_register(&cli_show_codecs);
00715 ast_cli_register(&cli_show_codecs_audio);
00716 ast_cli_register(&cli_show_codecs_video);
00717 ast_cli_register(&cli_show_codecs_image);
00718 ast_cli_register(&cli_show_codec_n);
00719 return 0;
00720 }