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

Generated on Tue Aug 17 16:13:53 2004 for Asterisk by doxygen 1.3.8