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 Fri Sep 24 21:03:47 2004 for Asterisk by doxygen 1.3.8