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/channel.h>
00019 #include <asterisk/cli.h>
00020 #include <asterisk/term.h>
00021 #include <asterisk/utils.h>
00022 #include <stdlib.h>
00023 #include <unistd.h>
00024 #include <string.h>
00025 #include <errno.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_format_list {
00038 int visible;
00039 int bits;
00040 char *name;
00041 char *desc;
00042 };
00043
00044 struct ast_smoother {
00045 int size;
00046 int format;
00047 int readdata;
00048 int optimizablestream;
00049 int flags;
00050 float samplesperbyte;
00051 struct ast_frame f;
00052 struct timeval delivery;
00053 char data[SMOOTHER_SIZE];
00054 char framedata[SMOOTHER_SIZE + AST_FRIENDLY_OFFSET];
00055 struct ast_frame *opt;
00056 int len;
00057 };
00058
00059 void ast_smoother_reset(struct ast_smoother *s, int size)
00060 {
00061 memset(s, 0, sizeof(struct ast_smoother));
00062 s->size = size;
00063 }
00064
00065 struct ast_smoother *ast_smoother_new(int size)
00066 {
00067 struct ast_smoother *s;
00068 if (size < 1)
00069 return NULL;
00070 s = malloc(sizeof(struct ast_smoother));
00071 if (s)
00072 ast_smoother_reset(s, size);
00073 return s;
00074 }
00075
00076 int ast_smoother_get_flags(struct ast_smoother *s)
00077 {
00078 return s->flags;
00079 }
00080
00081 void ast_smoother_set_flags(struct ast_smoother *s, int flags)
00082 {
00083 s->flags = flags;
00084 }
00085
00086 int ast_smoother_feed(struct ast_smoother *s, struct ast_frame *f)
00087 {
00088 if (f->frametype != AST_FRAME_VOICE) {
00089 ast_log(LOG_WARNING, "Huh? Can't smooth a non-voice frame!\n");
00090 return -1;
00091 }
00092 if (!s->format) {
00093 s->format = f->subclass;
00094 s->samplesperbyte = (float)f->samples / (float)f->datalen;
00095 } else if (s->format != f->subclass) {
00096 ast_log(LOG_WARNING, "Smoother was working on %d format frames, now trying to feed %d?\n", s->format, f->subclass);
00097 return -1;
00098 }
00099 if (s->len + f->datalen > SMOOTHER_SIZE) {
00100 ast_log(LOG_WARNING, "Out of smoother space\n");
00101 return -1;
00102 }
00103 if (((f->datalen == s->size) || ((f->datalen < 10) && (s->flags & AST_SMOOTHER_FLAG_G729)))
00104 && !s->opt && (f->offset >= AST_MIN_OFFSET)) {
00105 if (!s->len) {
00106
00107
00108
00109 s->opt = f;
00110 return 0;
00111 } else {
00112 s->optimizablestream++;
00113 if (s->optimizablestream > 10) {
00114
00115
00116
00117
00118
00119 s->len = 0;
00120 s->opt = f;
00121 return 0;
00122 }
00123 }
00124 } else
00125 s->optimizablestream = 0;
00126 if (s->flags & AST_SMOOTHER_FLAG_G729) {
00127 if (s->len % 10) {
00128 ast_log(LOG_NOTICE, "Dropping extra frame of G.729 since we already have a VAD frame at the end\n");
00129 return 0;
00130 }
00131 }
00132 memcpy(s->data + s->len, f->data, f->datalen);
00133
00134 if (!s->len || (!f->delivery.tv_sec && !f->delivery.tv_usec) ||
00135 (!s->delivery.tv_sec && !s->delivery.tv_usec))
00136 s->delivery = f->delivery;
00137 s->len += f->datalen;
00138 return 0;
00139 }
00140
00141 struct ast_frame *ast_smoother_read(struct ast_smoother *s)
00142 {
00143 struct ast_frame *opt;
00144 int len;
00145
00146 if (s->opt) {
00147 if (s->opt->offset < AST_FRIENDLY_OFFSET)
00148 ast_log(LOG_WARNING, "Returning a frame of inappropriate offset (%d).",
00149 s->opt->offset);
00150 opt = s->opt;
00151 s->opt = NULL;
00152 return opt;
00153 }
00154
00155
00156 if (s->len < s->size) {
00157
00158 if (!((s->flags & AST_SMOOTHER_FLAG_G729) && (s->size % 10)))
00159 return NULL;
00160 }
00161 len = s->size;
00162 if (len > s->len)
00163 len = s->len;
00164
00165 s->f.frametype = AST_FRAME_VOICE;
00166 s->f.subclass = s->format;
00167 s->f.data = s->framedata + AST_FRIENDLY_OFFSET;
00168 s->f.offset = AST_FRIENDLY_OFFSET;
00169 s->f.datalen = len;
00170
00171 s->f.samples = len * s->samplesperbyte;
00172 s->f.delivery = s->delivery;
00173
00174 memcpy(s->f.data, s->data, len);
00175 s->len -= len;
00176
00177 if (s->len) {
00178
00179
00180 memmove(s->data, s->data + len, s->len);
00181 if (s->delivery.tv_sec || s->delivery.tv_usec) {
00182
00183 s->delivery.tv_sec += (len * s->samplesperbyte) / 8000.0;
00184 s->delivery.tv_usec += (((int)(len * s->samplesperbyte)) % 8000) * 125;
00185 if (s->delivery.tv_usec > 1000000) {
00186 s->delivery.tv_usec -= 1000000;
00187 s->delivery.tv_sec += 1;
00188 }
00189 }
00190 }
00191
00192 return &s->f;
00193 }
00194
00195 void ast_smoother_free(struct ast_smoother *s)
00196 {
00197 free(s);
00198 }
00199
00200 static struct ast_frame *ast_frame_header_new(void)
00201 {
00202 struct ast_frame *f;
00203 f = malloc(sizeof(struct ast_frame));
00204 if (f)
00205 memset(f, 0, sizeof(struct ast_frame));
00206 #ifdef TRACE_FRAMES
00207 if (f) {
00208 headers++;
00209 f->prev = NULL;
00210 ast_mutex_lock(&framelock);
00211 f->next = headerlist;
00212 if (headerlist)
00213 headerlist->prev = f;
00214 headerlist = f;
00215 ast_mutex_unlock(&framelock);
00216 }
00217 #endif
00218 return f;
00219 }
00220
00221
00222
00223
00224
00225
00226 void ast_frfree(struct ast_frame *fr)
00227 {
00228 if (fr->mallocd & AST_MALLOCD_DATA) {
00229 if (fr->data)
00230 free(fr->data - fr->offset);
00231 }
00232 if (fr->mallocd & AST_MALLOCD_SRC) {
00233 if (fr->src)
00234 free(fr->src);
00235 }
00236 if (fr->mallocd & AST_MALLOCD_HDR) {
00237 #ifdef TRACE_FRAMES
00238 headers--;
00239 ast_mutex_lock(&framelock);
00240 if (fr->next)
00241 fr->next->prev = fr->prev;
00242 if (fr->prev)
00243 fr->prev->next = fr->next;
00244 else
00245 headerlist = fr->next;
00246 ast_mutex_unlock(&framelock);
00247 #endif
00248 free(fr);
00249 }
00250 }
00251
00252 struct ast_frame *ast_frisolate(struct ast_frame *fr)
00253 {
00254 struct ast_frame *out;
00255 if (!(fr->mallocd & AST_MALLOCD_HDR)) {
00256
00257 out = ast_frame_header_new();
00258 if (!out) {
00259 ast_log(LOG_WARNING, "Out of memory\n");
00260 return NULL;
00261 }
00262 out->frametype = fr->frametype;
00263 out->subclass = fr->subclass;
00264 out->datalen = 0;
00265 out->samples = fr->samples;
00266 out->offset = 0;
00267 out->src = NULL;
00268 out->data = NULL;
00269 } else {
00270 out = fr;
00271 }
00272 if (!(fr->mallocd & AST_MALLOCD_SRC)) {
00273 if (fr->src)
00274 out->src = strdup(fr->src);
00275 } else
00276 out->src = fr->src;
00277 if (!(fr->mallocd & AST_MALLOCD_DATA)) {
00278 out->data = malloc(fr->datalen + AST_FRIENDLY_OFFSET);
00279 if (!out->data) {
00280 free(out);
00281 ast_log(LOG_WARNING, "Out of memory\n");
00282 return NULL;
00283 }
00284 out->data += AST_FRIENDLY_OFFSET;
00285 out->offset = AST_FRIENDLY_OFFSET;
00286 out->datalen = fr->datalen;
00287 memcpy(out->data, fr->data, fr->datalen);
00288 }
00289 out->mallocd = AST_MALLOCD_HDR | AST_MALLOCD_SRC | AST_MALLOCD_DATA;
00290 return out;
00291 }
00292
00293 struct ast_frame *ast_frdup(struct ast_frame *f)
00294 {
00295 struct ast_frame *out;
00296 int len, srclen = 0;
00297 void *buf;
00298
00299 len = sizeof(struct ast_frame) + AST_FRIENDLY_OFFSET + f->datalen;
00300
00301 if (f->src)
00302 srclen = strlen(f->src);
00303 if (srclen > 0)
00304 len += srclen + 1;
00305 buf = malloc(len);
00306 if (!buf)
00307 return NULL;
00308 out = buf;
00309
00310
00311 out->frametype = f->frametype;
00312 out->subclass = f->subclass;
00313 out->datalen = f->datalen;
00314 out->samples = f->samples;
00315 out->delivery = f->delivery;
00316 out->mallocd = AST_MALLOCD_HDR;
00317 out->offset = AST_FRIENDLY_OFFSET;
00318 out->data = buf + sizeof(struct ast_frame) + AST_FRIENDLY_OFFSET;
00319 if (srclen > 0) {
00320 out->src = out->data + f->datalen;
00321
00322 strcpy(out->src, f->src);
00323 } else
00324 out->src = NULL;
00325 out->prev = NULL;
00326 out->next = NULL;
00327 memcpy(out->data, f->data, out->datalen);
00328 return out;
00329 }
00330
00331 struct ast_frame *ast_fr_fdread(int fd)
00332 {
00333 char buf[65536];
00334 int res;
00335 int ttl = sizeof(struct ast_frame);
00336 struct ast_frame *f = (struct ast_frame *)buf;
00337
00338
00339
00340 while(ttl) {
00341 res = read(fd, buf, ttl);
00342 if (res < 0) {
00343 ast_log(LOG_WARNING, "Bad read on %d: %s\n", fd, strerror(errno));
00344 return NULL;
00345 }
00346 ttl -= res;
00347 }
00348
00349
00350 f->mallocd = 0;
00351
00352 f->data = buf + sizeof(struct ast_frame);
00353 f->offset = 0;
00354
00355 f->mallocd = 0;
00356
00357 f->src = __FUNCTION__;
00358 if (f->datalen > sizeof(buf) - sizeof(struct ast_frame)) {
00359
00360 ast_log(LOG_WARNING, "Strange read (%d bytes)\n", f->datalen);
00361 return NULL;
00362 }
00363 if (f->datalen) {
00364 if ((res = read(fd, f->data, f->datalen)) != f->datalen) {
00365
00366 ast_log(LOG_WARNING, "How very strange, expected %d, got %d\n", f->datalen, res);
00367 return NULL;
00368 }
00369 }
00370 if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_HANGUP)) {
00371 return NULL;
00372 }
00373 return ast_frisolate(f);
00374 }
00375
00376
00377
00378
00379 int ast_fr_fdwrite(int fd, struct ast_frame *frame)
00380 {
00381
00382 if (write(fd, frame, sizeof(struct ast_frame)) != sizeof(struct ast_frame)) {
00383 ast_log(LOG_WARNING, "Write error: %s\n", strerror(errno));
00384 return -1;
00385 }
00386 if (write(fd, frame->data, frame->datalen) != frame->datalen) {
00387 ast_log(LOG_WARNING, "Write error: %s\n", strerror(errno));
00388 return -1;
00389 }
00390 return 0;
00391 }
00392
00393 int ast_fr_fdhangup(int fd)
00394 {
00395 struct ast_frame hangup = {
00396 AST_FRAME_CONTROL,
00397 AST_CONTROL_HANGUP
00398 };
00399 return ast_fr_fdwrite(fd, &hangup);
00400 }
00401
00402 static struct ast_format_list AST_FORMAT_LIST[] = {
00403 { 1, AST_FORMAT_G723_1 , "g723" , "G.723.1"},
00404 { 1, AST_FORMAT_GSM, "gsm" , "GSM"},
00405 { 1, AST_FORMAT_ULAW, "ulaw", "G.711 u-law" },
00406 { 1, AST_FORMAT_ALAW, "alaw", "G.711 A-law" },
00407 { 1, AST_FORMAT_G726, "g726", "G.726" },
00408 { 1, AST_FORMAT_ADPCM, "adpcm" , "ADPCM"},
00409 { 1, AST_FORMAT_SLINEAR, "slin", "16 bit Signed Linear PCM"},
00410 { 1, AST_FORMAT_LPC10, "lpc10", "LPC10" },
00411 { 1, AST_FORMAT_G729A, "g729", "G.729A" },
00412 { 1, AST_FORMAT_SPEEX, "speex", "SpeeX" },
00413 { 1, AST_FORMAT_ILBC, "ilbc", "iLBC"},
00414 { 0, 0, "nothing", "undefined" },
00415 { 0, 0, "nothing", "undefined" },
00416 { 0, 0, "nothing", "undefined" },
00417 { 0, 0, "nothing", "undefined" },
00418 { 0, AST_FORMAT_MAX_AUDIO, "maxaudio", "Maximum audio format" },
00419 { 1, AST_FORMAT_JPEG, "jpeg", "JPEG image"},
00420 { 1, AST_FORMAT_PNG, "png", "PNG image"},
00421 { 1, AST_FORMAT_H261, "h261", "H.261 Video" },
00422 { 1, AST_FORMAT_H263, "h263", "H.263 Video" },
00423 { 0, 0, "nothing", "undefined" },
00424 { 0, 0, "nothing", "undefined" },
00425 { 0, 0, "nothing", "undefined" },
00426 { 0, 0, "nothing", "undefined" },
00427 { 0, AST_FORMAT_MAX_VIDEO, "maxvideo", "Maximum video format" },
00428 };
00429
00430 struct ast_format_list *ast_get_format_list_index(int index) {
00431 return &AST_FORMAT_LIST[index];
00432 }
00433
00434 struct ast_format_list *ast_get_format_list(size_t *size) {
00435 *size = (sizeof(AST_FORMAT_LIST) / sizeof(struct ast_format_list));
00436 return AST_FORMAT_LIST;
00437 }
00438
00439 char* ast_getformatname(int format)
00440 {
00441 int x = 0;
00442 char *ret = "unknown";
00443 for (x = 0 ; x < sizeof(AST_FORMAT_LIST) / sizeof(struct ast_format_list) ; x++) {
00444 if(AST_FORMAT_LIST[x].visible && AST_FORMAT_LIST[x].bits == format) {
00445 ret = AST_FORMAT_LIST[x].name;
00446 break;
00447 }
00448 }
00449 return ret;
00450 }
00451
00452 char *ast_getformatname_multiple(char *buf, size_t size, int format) {
00453
00454 int x = 0;
00455 unsigned len;
00456 char *end = buf;
00457 char *start = buf;
00458 if (!size) return buf;
00459 snprintf(end, size, "0x%x (", format);
00460 len = strlen(end);
00461 end += len;
00462 size -= len;
00463 start = end;
00464 for (x = 0 ; x < sizeof(AST_FORMAT_LIST) / sizeof(struct ast_format_list) ; x++) {
00465 if (AST_FORMAT_LIST[x].visible && (AST_FORMAT_LIST[x].bits & format)) {
00466 snprintf(end, size,"%s|",AST_FORMAT_LIST[x].name);
00467 len = strlen(end);
00468 end += len;
00469 size -= len;
00470 }
00471 }
00472 if (start == end)
00473 snprintf(start, size, "nothing)");
00474 else if (size > 1)
00475 *(end -1) = ')';
00476 return buf;
00477 }
00478
00479 static struct ast_codec_alias_table {
00480 char *alias;
00481 char *realname;
00482
00483 } ast_codec_alias_table[] = {
00484 {"slinear","slin"},
00485 {"g723.1","g723"},
00486 };
00487
00488 static char *ast_expand_codec_alias(char *in) {
00489 int x = 0;
00490
00491 for (x = 0; x < sizeof(ast_codec_alias_table) / sizeof(struct ast_codec_alias_table) ; x++) {
00492 if(!strcmp(in,ast_codec_alias_table[x].alias))
00493 return ast_codec_alias_table[x].realname;
00494 }
00495 return in;
00496 }
00497
00498 int ast_getformatbyname(char *name)
00499 {
00500 int x = 0, all = 0, format = 0;
00501
00502 all = strcasecmp(name, "all") ? 0 : 1;
00503 for (x = 0 ; x < sizeof(AST_FORMAT_LIST) / sizeof(struct ast_format_list) ; x++) {
00504 if(AST_FORMAT_LIST[x].visible && (all ||
00505 !strcasecmp(AST_FORMAT_LIST[x].name,name) ||
00506 !strcasecmp(AST_FORMAT_LIST[x].name,ast_expand_codec_alias(name)))) {
00507 format |= AST_FORMAT_LIST[x].bits;
00508 if(!all)
00509 break;
00510 }
00511 }
00512
00513 return format;
00514 }
00515
00516 char *ast_codec2str(int codec) {
00517 int x = 0;
00518 char *ret = "unknown";
00519 for (x = 0 ; x < sizeof(AST_FORMAT_LIST) / sizeof(struct ast_format_list) ; x++) {
00520 if(AST_FORMAT_LIST[x].visible && AST_FORMAT_LIST[x].bits == codec) {
00521 ret = AST_FORMAT_LIST[x].desc;
00522 break;
00523 }
00524 }
00525 return ret;
00526 }
00527
00528 static int show_codecs(int fd, int argc, char *argv[])
00529 {
00530 int i, found=0;
00531 char hex[25];
00532
00533 if ((argc < 2) || (argc > 3))
00534 return RESULT_SHOWUSAGE;
00535
00536 if (getenv("I_AM_NOT_AN_IDIOT") == NULL)
00537 ast_cli(fd, "Disclaimer: this command is for informational purposes only.\n"
00538 "\tIt does not indicate anything about your configuration.\n");
00539
00540 ast_cli(fd, "%11s %9s %10s TYPE %5s %s\n","INT","BINARY","HEX","NAME","DESC");
00541 ast_cli(fd, "--------------------------------------------------------------------------------\n");
00542 if ((argc == 2) || (!strcasecmp(argv[1],"audio"))) {
00543 found = 1;
00544 for (i=0;i<11;i++) {
00545 snprintf(hex,25,"(0x%x)",1<<i);
00546 ast_cli(fd, "%11u (1 << %2d) %10s audio %5s (%s)\n",1 << i,i,hex,ast_getformatname(1<<i),ast_codec2str(1<<i));
00547 }
00548 }
00549
00550 if ((argc == 2) || (!strcasecmp(argv[1],"image"))) {
00551 found = 1;
00552 for (i=16;i<18;i++) {
00553 snprintf(hex,25,"(0x%x)",1<<i);
00554 ast_cli(fd, "%11u (1 << %2d) %10s image %5s (%s)\n",1 << i,i,hex,ast_getformatname(1<<i),ast_codec2str(1<<i));
00555 }
00556 }
00557
00558 if ((argc == 2) || (!strcasecmp(argv[1],"video"))) {
00559 found = 1;
00560 for (i=18;i<20;i++) {
00561 snprintf(hex,25,"(0x%x)",1<<i);
00562 ast_cli(fd, "%11u (1 << %2d) %10s video %5s (%s)\n",1 << i,i,hex,ast_getformatname(1<<i),ast_codec2str(1<<i));
00563 }
00564 }
00565
00566 if (! found)
00567 return RESULT_SHOWUSAGE;
00568 else
00569 return RESULT_SUCCESS;
00570 }
00571
00572 static char frame_show_codecs_usage[] =
00573 "Usage: show [audio|video|image] codecs\n"
00574 " Displays codec mapping\n";
00575
00576 struct ast_cli_entry cli_show_codecs =
00577 { { "show", "codecs", NULL }, show_codecs, "Shows codecs", frame_show_codecs_usage };
00578 struct ast_cli_entry cli_show_codecs_audio =
00579 { { "show", "audio", "codecs", NULL }, show_codecs, "Shows audio codecs", frame_show_codecs_usage };
00580 struct ast_cli_entry cli_show_codecs_video =
00581 { { "show", "video", "codecs", NULL }, show_codecs, "Shows video codecs", frame_show_codecs_usage };
00582 struct ast_cli_entry cli_show_codecs_image =
00583 { { "show", "image", "codecs", NULL }, show_codecs, "Shows image codecs", frame_show_codecs_usage };
00584
00585 static int show_codec_n(int fd, int argc, char *argv[])
00586 {
00587 int codec, i, found=0;
00588
00589 if (argc != 3)
00590 return RESULT_SHOWUSAGE;
00591
00592 if (sscanf(argv[2],"%d",&codec) != 1)
00593 return RESULT_SHOWUSAGE;
00594
00595 for (i=0;i<32;i++)
00596 if (codec & (1 << i)) {
00597 found = 1;
00598 ast_cli(fd, "%11u (1 << %2d) %s\n",1 << i,i,ast_codec2str(1<<i));
00599 }
00600
00601 if (! found)
00602 ast_cli(fd, "Codec %d not found\n", codec);
00603
00604 return RESULT_SUCCESS;
00605 }
00606
00607 static char frame_show_codec_n_usage[] =
00608 "Usage: show codec <number>\n"
00609 " Displays codec mapping\n";
00610
00611 struct ast_cli_entry cli_show_codec_n =
00612 { { "show", "codec", NULL }, show_codec_n, "Shows a specific codec", frame_show_codec_n_usage };
00613
00614 void ast_frame_dump(char *name, struct ast_frame *f, char *prefix)
00615 {
00616 char *n = "unknown";
00617 char ftype[40] = "Unknown Frametype";
00618 char cft[80];
00619 char subclass[40] = "Unknown Subclass";
00620 char csub[80];
00621 char moreinfo[40] = "";
00622 char cn[60];
00623 char cp[40];
00624 char cmn[40];
00625 if (name)
00626 n = name;
00627 if (!f) {
00628 ast_verbose("%s [ %s (NULL) ] [%s]\n",
00629 term_color(cp, prefix, COLOR_BRMAGENTA, COLOR_BLACK, sizeof(cp)),
00630 term_color(cft, "HANGUP", COLOR_BRRED, COLOR_BLACK, sizeof(cft)),
00631 term_color(cn, n, COLOR_YELLOW, COLOR_BLACK, sizeof(cn)));
00632 return;
00633 }
00634
00635 if (f->frametype == AST_FRAME_VOICE)
00636 return;
00637 if (f->frametype == AST_FRAME_VIDEO)
00638 return;
00639 switch(f->frametype) {
00640 case AST_FRAME_DTMF:
00641 strcpy(ftype, "DTMF");
00642 subclass[0] = f->subclass;
00643 subclass[1] = '\0';
00644 break;
00645 case AST_FRAME_CONTROL:
00646 strcpy(ftype, "Control");
00647 switch(f->subclass) {
00648 case AST_CONTROL_HANGUP:
00649 strcpy(subclass, "Hangup");
00650 break;
00651 case AST_CONTROL_RING:
00652 strcpy(subclass, "Ring");
00653 break;
00654 case AST_CONTROL_RINGING:
00655 strcpy(subclass, "Ringing");
00656 break;
00657 case AST_CONTROL_ANSWER:
00658 strcpy(subclass, "Answer");
00659 break;
00660 case AST_CONTROL_BUSY:
00661 strcpy(subclass, "Busy");
00662 break;
00663 case AST_CONTROL_TAKEOFFHOOK:
00664 strcpy(subclass, "Take Off Hook");
00665 break;
00666 case AST_CONTROL_OFFHOOK:
00667 strcpy(subclass, "Line Off Hook");
00668 break;
00669 case AST_CONTROL_CONGESTION:
00670 strcpy(subclass, "Congestion");
00671 break;
00672 case AST_CONTROL_FLASH:
00673 strcpy(subclass, "Flash");
00674 break;
00675 case AST_CONTROL_WINK:
00676 strcpy(subclass, "Wink");
00677 break;
00678 case AST_CONTROL_OPTION:
00679 strcpy(subclass, "Option");
00680 break;
00681 case AST_CONTROL_RADIO_KEY:
00682 strcpy(subclass, "Key Radio");
00683 break;
00684 case AST_CONTROL_RADIO_UNKEY:
00685 strcpy(subclass, "Unkey Radio");
00686 break;
00687 case -1:
00688 strcpy(subclass, "Stop generators");
00689 break;
00690 default:
00691 snprintf(subclass, sizeof(subclass), "Unknown control '%d'", f->subclass);
00692 }
00693 break;
00694 case AST_FRAME_NULL:
00695 strcpy(ftype, "Null Frame");
00696 strcpy(subclass, "N/A");
00697 break;
00698 case AST_FRAME_IAX:
00699
00700 strcpy(ftype, "IAX Specific");
00701 snprintf(subclass, sizeof(subclass), "IAX Frametype %d", f->subclass);
00702 break;
00703 case AST_FRAME_TEXT:
00704 strcpy(ftype, "Text");
00705 strcpy(subclass, "N/A");
00706 strncpy(moreinfo, f->data, sizeof(moreinfo) - 1);
00707 break;
00708 case AST_FRAME_IMAGE:
00709 strcpy(ftype, "Image");
00710 snprintf(subclass, sizeof(subclass), "Image format %s\n", ast_getformatname(f->subclass));
00711 break;
00712 case AST_FRAME_HTML:
00713 strcpy(ftype, "HTML");
00714 switch(f->subclass) {
00715 case AST_HTML_URL:
00716 strcpy(subclass, "URL");
00717 strncpy(moreinfo, f->data, sizeof(moreinfo) - 1);
00718 break;
00719 case AST_HTML_DATA:
00720 strcpy(subclass, "Data");
00721 break;
00722 case AST_HTML_BEGIN:
00723 strcpy(subclass, "Begin");
00724 break;
00725 case AST_HTML_END:
00726 strcpy(subclass, "End");
00727 break;
00728 case AST_HTML_LDCOMPLETE:
00729 strcpy(subclass, "Load Complete");
00730 break;
00731 case AST_HTML_NOSUPPORT:
00732 strcpy(subclass, "No Support");
00733 break;
00734 case AST_HTML_LINKURL:
00735 strcpy(subclass, "Link URL");
00736 strncpy(moreinfo, f->data, sizeof(moreinfo) - 1);
00737 break;
00738 case AST_HTML_UNLINK:
00739 strcpy(subclass, "Unlink");
00740 break;
00741 case AST_HTML_LINKREJECT:
00742 strcpy(subclass, "Link Reject");
00743 break;
00744 default:
00745 snprintf(subclass, sizeof(subclass), "Unknown HTML frame '%d'\n", f->subclass);
00746 break;
00747 }
00748 break;
00749 default:
00750 snprintf(ftype, sizeof(ftype), "Unknown Frametype '%d'", f->frametype);
00751 }
00752 if (!ast_strlen_zero(moreinfo))
00753 ast_verbose("%s [ TYPE: %s (%d) SUBCLASS: %s (%d) '%s' ] [%s]\n",
00754 term_color(cp, prefix, COLOR_BRMAGENTA, COLOR_BLACK, sizeof(cp)),
00755 term_color(cft, ftype, COLOR_BRRED, COLOR_BLACK, sizeof(cft)),
00756 f->frametype,
00757 term_color(csub, subclass, COLOR_BRCYAN, COLOR_BLACK, sizeof(csub)),
00758 f->subclass,
00759 term_color(cmn, moreinfo, COLOR_BRGREEN, COLOR_BLACK, sizeof(cmn)),
00760 term_color(cn, n, COLOR_YELLOW, COLOR_BLACK, sizeof(cn)));
00761 else
00762 ast_verbose("%s [ TYPE: %s (%d) SUBCLASS: %s (%d) ] [%s]\n",
00763 term_color(cp, prefix, COLOR_BRMAGENTA, COLOR_BLACK, sizeof(cp)),
00764 term_color(cft, ftype, COLOR_BRRED, COLOR_BLACK, sizeof(cft)),
00765 f->frametype,
00766 term_color(csub, subclass, COLOR_BRCYAN, COLOR_BLACK, sizeof(csub)),
00767 f->subclass,
00768 term_color(cn, n, COLOR_YELLOW, COLOR_BLACK, sizeof(cn)));
00769
00770 }
00771
00772
00773 #ifdef TRACE_FRAMES
00774 static int show_frame_stats(int fd, int argc, char *argv[])
00775 {
00776 struct ast_frame *f;
00777 int x=1;
00778 if (argc != 3)
00779 return RESULT_SHOWUSAGE;
00780 ast_cli(fd, " Framer Statistics \n");
00781 ast_cli(fd, "---------------------------\n");
00782 ast_cli(fd, "Total allocated headers: %d\n", headers);
00783 ast_cli(fd, "Queue Dump:\n");
00784 ast_mutex_lock(&framelock);
00785 for (f=headerlist; f; f = f->next) {
00786 ast_cli(fd, "%d. Type %d, subclass %d from %s\n", x++, f->frametype, f->subclass, f->src ? f->src : "<Unknown>");
00787 }
00788 ast_mutex_unlock(&framelock);
00789 return RESULT_SUCCESS;
00790 }
00791
00792 static char frame_stats_usage[] =
00793 "Usage: show frame stats\n"
00794 " Displays debugging statistics from framer\n";
00795
00796 struct ast_cli_entry cli_frame_stats =
00797 { { "show", "frame", "stats", NULL }, show_frame_stats, "Shows frame statistics", frame_stats_usage };
00798 #endif
00799
00800 int init_framer(void)
00801 {
00802 #ifdef TRACE_FRAMES
00803 ast_cli_register(&cli_frame_stats);
00804 #endif
00805 ast_cli_register(&cli_show_codecs);
00806 ast_cli_register(&cli_show_codecs_audio);
00807 ast_cli_register(&cli_show_codecs_video);
00808 ast_cli_register(&cli_show_codecs_image);
00809 ast_cli_register(&cli_show_codec_n);
00810 return 0;
00811 }
00812
00813 void ast_codec_pref_shift(struct ast_codec_pref *pref, char *buf, size_t size, int right)
00814 {
00815 int x = 0, differential = 65, mem = 0;
00816 char *from = NULL, *to = NULL;
00817
00818 if(right) {
00819 from = pref->order;
00820 to = buf;
00821 mem = size;
00822 } else {
00823 to = pref->order;
00824 from = buf;
00825 mem = 32;
00826 }
00827
00828 memset(to, 0, mem);
00829 for (x = 0; x < 32 ; x++) {
00830 if(!from[x])
00831 break;
00832 to[x] = right ? (from[x] + differential) : (from[x] - differential);
00833 }
00834 }
00835
00836 int ast_codec_pref_string(struct ast_codec_pref *pref, char *buf, size_t size)
00837 {
00838 int x = 0, codec = 0;
00839 size_t total_len = 0, slen = 0;
00840 char *formatname = 0;
00841
00842 memset(buf,0,size);
00843 total_len = size;
00844 buf[0] = '(';
00845 total_len--;
00846 for(x = 0; x < 32 ; x++) {
00847 if(total_len <= 0)
00848 break;
00849 if(!(codec = ast_codec_pref_index(pref,x)))
00850 break;
00851 if((formatname = ast_getformatname(codec))) {
00852 slen = strlen(formatname);
00853 if(slen > total_len)
00854 break;
00855 strncat(buf,formatname,total_len);
00856 total_len -= slen;
00857 }
00858 if(total_len && x < 31 && ast_codec_pref_index(pref , x + 1)) {
00859 strncat(buf,"|",total_len);
00860 total_len--;
00861 }
00862 }
00863 if(total_len) {
00864 strncat(buf,")",total_len);
00865 total_len--;
00866 }
00867
00868 return size - total_len;
00869 }
00870
00871 int ast_codec_pref_index(struct ast_codec_pref *pref, int index)
00872 {
00873 int slot = 0;
00874
00875
00876 if((index >= 0) && (index < sizeof(pref->order))) {
00877 slot = pref->order[index];
00878 }
00879
00880 return slot ? AST_FORMAT_LIST[slot-1].bits : 0;
00881 }
00882
00883
00884 void ast_codec_pref_remove(struct ast_codec_pref *pref, int format)
00885 {
00886 struct ast_codec_pref oldorder;
00887 int x=0, y=0;
00888 size_t size = 0;
00889 int slot = 0;
00890
00891 if(!pref->order[0])
00892 return;
00893
00894 size = sizeof(AST_FORMAT_LIST) / sizeof(struct ast_format_list);
00895
00896 memcpy(&oldorder,pref,sizeof(struct ast_codec_pref));
00897 memset(pref,0,sizeof(struct ast_codec_pref));
00898
00899 for (x = 0; x < size; x++) {
00900 slot = oldorder.order[x];
00901 if(! slot)
00902 break;
00903 if(AST_FORMAT_LIST[slot-1].bits != format)
00904 pref->order[y++] = slot;
00905 }
00906
00907 }
00908
00909
00910 int ast_codec_pref_append(struct ast_codec_pref *pref, int format)
00911 {
00912 size_t size = 0;
00913 int x = 0, newindex = -1;
00914
00915 ast_codec_pref_remove(pref, format);
00916 size = sizeof(AST_FORMAT_LIST) / sizeof(struct ast_format_list);
00917
00918 for (x = 0; x < size; x++) {
00919 if(AST_FORMAT_LIST[x].bits == format) {
00920 newindex = x + 1;
00921 break;
00922 }
00923 }
00924
00925 if(newindex) {
00926 for (x = 0; x < size; x++) {
00927 if(!pref->order[x]) {
00928 pref->order[x] = newindex;
00929 break;
00930 }
00931 }
00932 }
00933
00934 return x;
00935 }
00936
00937
00938
00939 int ast_codec_choose(struct ast_codec_pref *pref, int formats, int find_best)
00940 {
00941 size_t size = 0;
00942 int x = 0, ret = 0, slot = 0;
00943
00944 size = sizeof(AST_FORMAT_LIST) / sizeof(struct ast_format_list);
00945 for (x = 0; x < size; x++) {
00946 slot = pref->order[x];
00947
00948 if(!slot)
00949 break;
00950 if ( formats & AST_FORMAT_LIST[slot-1].bits ) {
00951 ret = AST_FORMAT_LIST[slot-1].bits;
00952 break;
00953 }
00954 }
00955 if(ret)
00956 return ret;
00957
00958 return find_best ? ast_best_codec(formats) : 0;
00959 }
00960
00961 void ast_parse_allow_disallow(struct ast_codec_pref *pref, int *mask, char *list, int allowing)
00962 {
00963 int format_i = 0;
00964 char *next_format = NULL, *last_format = NULL;
00965
00966 last_format = ast_strdupa(list);
00967 while(last_format) {
00968 if((next_format = strchr(last_format, ','))) {
00969 *next_format = '\0';
00970 next_format++;
00971 }
00972 if ((format_i = ast_getformatbyname(last_format)) > 0) {
00973 if (mask) {
00974 if (allowing)
00975 (*mask) |= format_i;
00976 else
00977 (*mask) &= ~format_i;
00978 }
00979
00980 if(pref && strcasecmp(last_format, "all")) {
00981 if(allowing)
00982 ast_codec_pref_append(pref, format_i);
00983 else
00984 ast_codec_pref_remove(pref, format_i);
00985 } else if(!allowing)
00986 memset(pref, 0, sizeof(struct ast_codec_pref));
00987 } else
00988 ast_log(LOG_WARNING, "Cannot %s unknown format '%s'\n", allowing ? "allow" : "disallow", last_format);
00989
00990 last_format = next_format;
00991 }
00992 }
00993
00994