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

Generated on Sat Jun 12 16:40:58 2004 for Asterisk by doxygen 1.3.7