00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #include <stdlib.h>
00026 #include <unistd.h>
00027 #include <string.h>
00028 #include <errno.h>
00029 #include <stdio.h>
00030
00031 #include "asterisk.h"
00032
00033 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 7221 $")
00034
00035 #include "asterisk/lock.h"
00036 #include "asterisk/frame.h"
00037 #include "asterisk/logger.h"
00038 #include "asterisk/options.h"
00039 #include "asterisk/channel.h"
00040 #include "asterisk/cli.h"
00041 #include "asterisk/term.h"
00042 #include "asterisk/utils.h"
00043
00044 #ifdef TRACE_FRAMES
00045 static int headers = 0;
00046 static struct ast_frame *headerlist = NULL;
00047 AST_MUTEX_DEFINE_STATIC(framelock);
00048 #endif
00049
00050 #define SMOOTHER_SIZE 8000
00051
00052 #define TYPE_HIGH 0x0
00053 #define TYPE_LOW 0x1
00054 #define TYPE_SILENCE 0x2
00055 #define TYPE_DONTSEND 0x3
00056 #define TYPE_MASK 0x3
00057
00058 struct ast_format_list {
00059 int visible;
00060 int bits;
00061 char *name;
00062 char *desc;
00063 };
00064
00065 struct ast_smoother {
00066 int size;
00067 int format;
00068 int readdata;
00069 int optimizablestream;
00070 int flags;
00071 float samplesperbyte;
00072 struct ast_frame f;
00073 struct timeval delivery;
00074 char data[SMOOTHER_SIZE];
00075 char framedata[SMOOTHER_SIZE + AST_FRIENDLY_OFFSET];
00076 struct ast_frame *opt;
00077 int len;
00078 };
00079
00080
00081 static struct ast_format_list AST_FORMAT_LIST[] = {
00082 { 1, AST_FORMAT_G723_1 , "g723" , "G.723.1"},
00083 { 1, AST_FORMAT_GSM, "gsm" , "GSM"},
00084 { 1, AST_FORMAT_ULAW, "ulaw", "G.711 u-law" },
00085 { 1, AST_FORMAT_ALAW, "alaw", "G.711 A-law" },
00086 { 1, AST_FORMAT_G726, "g726", "G.726" },
00087 { 1, AST_FORMAT_ADPCM, "adpcm" , "ADPCM"},
00088 { 1, AST_FORMAT_SLINEAR, "slin", "16 bit Signed Linear PCM"},
00089 { 1, AST_FORMAT_LPC10, "lpc10", "LPC10" },
00090 { 1, AST_FORMAT_G729A, "g729", "G.729A" },
00091 { 1, AST_FORMAT_SPEEX, "speex", "SpeeX" },
00092 { 1, AST_FORMAT_ILBC, "ilbc", "iLBC"},
00093 { 0, 0, "nothing", "undefined" },
00094 { 0, 0, "nothing", "undefined" },
00095 { 0, 0, "nothing", "undefined" },
00096 { 0, 0, "nothing", "undefined" },
00097 { 0, AST_FORMAT_MAX_AUDIO, "maxaudio", "Maximum audio format" },
00098 { 1, AST_FORMAT_JPEG, "jpeg", "JPEG image"},
00099 { 1, AST_FORMAT_PNG, "png", "PNG image"},
00100 { 1, AST_FORMAT_H261, "h261", "H.261 Video" },
00101 { 1, AST_FORMAT_H263, "h263", "H.263 Video" },
00102 { 1, AST_FORMAT_H263_PLUS, "h263p", "H.263+ Video" },
00103 { 0, 0, "nothing", "undefined" },
00104 { 0, 0, "nothing", "undefined" },
00105 { 0, 0, "nothing", "undefined" },
00106 { 0, 0, "nothing", "undefined" },
00107 { 0, AST_FORMAT_MAX_VIDEO, "maxvideo", "Maximum video format" },
00108 };
00109
00110 void ast_smoother_reset(struct ast_smoother *s, int size)
00111 {
00112 memset(s, 0, sizeof(struct ast_smoother));
00113 s->size = size;
00114 }
00115
00116 struct ast_smoother *ast_smoother_new(int size)
00117 {
00118 struct ast_smoother *s;
00119 if (size < 1)
00120 return NULL;
00121 s = malloc(sizeof(struct ast_smoother));
00122 if (s)
00123 ast_smoother_reset(s, size);
00124 return s;
00125 }
00126
00127 int ast_smoother_get_flags(struct ast_smoother *s)
00128 {
00129 return s->flags;
00130 }
00131
00132 void ast_smoother_set_flags(struct ast_smoother *s, int flags)
00133 {
00134 s->flags = flags;
00135 }
00136
00137 int __ast_smoother_feed(struct ast_smoother *s, struct ast_frame *f, int swap)
00138 {
00139 if (f->frametype != AST_FRAME_VOICE) {
00140 ast_log(LOG_WARNING, "Huh? Can't smooth a non-voice frame!\n");
00141 return -1;
00142 }
00143 if (!s->format) {
00144 s->format = f->subclass;
00145 s->samplesperbyte = (float)f->samples / (float)f->datalen;
00146 } else if (s->format != f->subclass) {
00147 ast_log(LOG_WARNING, "Smoother was working on %d format frames, now trying to feed %d?\n", s->format, f->subclass);
00148 return -1;
00149 }
00150 if (s->len + f->datalen > SMOOTHER_SIZE) {
00151 ast_log(LOG_WARNING, "Out of smoother space\n");
00152 return -1;
00153 }
00154 if (((f->datalen == s->size) || ((f->datalen < 10) && (s->flags & AST_SMOOTHER_FLAG_G729)))
00155 && !s->opt && (f->offset >= AST_MIN_OFFSET)) {
00156 if (!s->len) {
00157
00158
00159
00160 s->opt = f;
00161 return 0;
00162 } else {
00163 s->optimizablestream++;
00164 if (s->optimizablestream > 10) {
00165
00166
00167
00168
00169
00170 s->len = 0;
00171 s->opt = f;
00172 return 0;
00173 }
00174 }
00175 } else
00176 s->optimizablestream = 0;
00177 if (s->flags & AST_SMOOTHER_FLAG_G729) {
00178 if (s->len % 10) {
00179 ast_log(LOG_NOTICE, "Dropping extra frame of G.729 since we already have a VAD frame at the end\n");
00180 return 0;
00181 }
00182 }
00183 if (swap)
00184 ast_swapcopy_samples(s->data+s->len, f->data, f->samples);
00185 else
00186 memcpy(s->data + s->len, f->data, f->datalen);
00187
00188 if (!s->len || ast_tvzero(f->delivery) || ast_tvzero(s->delivery))
00189 s->delivery = f->delivery;
00190 s->len += f->datalen;
00191 return 0;
00192 }
00193
00194 struct ast_frame *ast_smoother_read(struct ast_smoother *s)
00195 {
00196 struct ast_frame *opt;
00197 int len;
00198
00199 if (s->opt) {
00200 if (s->opt->offset < AST_FRIENDLY_OFFSET)
00201 ast_log(LOG_WARNING, "Returning a frame of inappropriate offset (%d).",
00202 s->opt->offset);
00203 opt = s->opt;
00204 s->opt = NULL;
00205 return opt;
00206 }
00207
00208
00209 if (s->len < s->size) {
00210
00211 if (!((s->flags & AST_SMOOTHER_FLAG_G729) && (s->size % 10)))
00212 return NULL;
00213 }
00214 len = s->size;
00215 if (len > s->len)
00216 len = s->len;
00217
00218 s->f.frametype = AST_FRAME_VOICE;
00219 s->f.subclass = s->format;
00220 s->f.data = s->framedata + AST_FRIENDLY_OFFSET;
00221 s->f.offset = AST_FRIENDLY_OFFSET;
00222 s->f.datalen = len;
00223
00224 s->f.samples = len * s->samplesperbyte;
00225 s->f.delivery = s->delivery;
00226
00227 memcpy(s->f.data, s->data, len);
00228 s->len -= len;
00229
00230 if (s->len) {
00231
00232
00233 memmove(s->data, s->data + len, s->len);
00234 if (!ast_tvzero(s->delivery)) {
00235
00236 s->delivery = ast_tvadd(s->delivery, ast_samp2tv(s->f.samples, 8000));
00237 }
00238 }
00239
00240 return &s->f;
00241 }
00242
00243 void ast_smoother_free(struct ast_smoother *s)
00244 {
00245 free(s);
00246 }
00247
00248 static struct ast_frame *ast_frame_header_new(void)
00249 {
00250 struct ast_frame *f;
00251 f = malloc(sizeof(struct ast_frame));
00252 if (f)
00253 memset(f, 0, sizeof(struct ast_frame));
00254 #ifdef TRACE_FRAMES
00255 if (f) {
00256 headers++;
00257 f->prev = NULL;
00258 ast_mutex_lock(&framelock);
00259 f->next = headerlist;
00260 if (headerlist)
00261 headerlist->prev = f;
00262 headerlist = f;
00263 ast_mutex_unlock(&framelock);
00264 }
00265 #endif
00266 return f;
00267 }
00268
00269
00270
00271
00272
00273 void ast_frfree(struct ast_frame *fr)
00274 {
00275 if (fr->mallocd & AST_MALLOCD_DATA) {
00276 if (fr->data)
00277 free(fr->data - fr->offset);
00278 }
00279 if (fr->mallocd & AST_MALLOCD_SRC) {
00280 if (fr->src)
00281 free((char *)fr->src);
00282 }
00283 if (fr->mallocd & AST_MALLOCD_HDR) {
00284 #ifdef TRACE_FRAMES
00285 headers--;
00286 ast_mutex_lock(&framelock);
00287 if (fr->next)
00288 fr->next->prev = fr->prev;
00289 if (fr->prev)
00290 fr->prev->next = fr->next;
00291 else
00292 headerlist = fr->next;
00293 ast_mutex_unlock(&framelock);
00294 #endif
00295 free(fr);
00296 }
00297 }
00298
00299
00300
00301
00302
00303
00304 struct ast_frame *ast_frisolate(struct ast_frame *fr)
00305 {
00306 struct ast_frame *out;
00307 if (!(fr->mallocd & AST_MALLOCD_HDR)) {
00308
00309 out = ast_frame_header_new();
00310 if (!out) {
00311 ast_log(LOG_WARNING, "Out of memory\n");
00312 return NULL;
00313 }
00314 out->frametype = fr->frametype;
00315 out->subclass = fr->subclass;
00316 out->datalen = fr->datalen;
00317 out->samples = fr->samples;
00318 out->offset = fr->offset;
00319 out->src = NULL;
00320 out->data = fr->data;
00321 } else {
00322 out = fr;
00323 }
00324 if (!(fr->mallocd & AST_MALLOCD_SRC)) {
00325 if (fr->src)
00326 out->src = strdup(fr->src);
00327 } else
00328 out->src = fr->src;
00329 if (!(fr->mallocd & AST_MALLOCD_DATA)) {
00330 out->data = malloc(fr->datalen + AST_FRIENDLY_OFFSET);
00331 if (!out->data) {
00332 free(out);
00333 ast_log(LOG_WARNING, "Out of memory\n");
00334 return NULL;
00335 }
00336 out->data += AST_FRIENDLY_OFFSET;
00337 out->offset = AST_FRIENDLY_OFFSET;
00338 out->datalen = fr->datalen;
00339 memcpy(out->data, fr->data, fr->datalen);
00340 }
00341 out->mallocd = AST_MALLOCD_HDR | AST_MALLOCD_SRC | AST_MALLOCD_DATA;
00342 return out;
00343 }
00344
00345 struct ast_frame *ast_frdup(struct ast_frame *f)
00346 {
00347 struct ast_frame *out;
00348 int len, srclen = 0;
00349 void *buf;
00350
00351 len = sizeof(struct ast_frame) + AST_FRIENDLY_OFFSET + f->datalen;
00352
00353
00354
00355
00356
00357 if (f->src)
00358 srclen = strlen(f->src);
00359 if (srclen > 0)
00360 len += srclen + 1;
00361 buf = malloc(len);
00362 if (!buf)
00363 return NULL;
00364 out = buf;
00365
00366
00367 out->frametype = f->frametype;
00368 out->subclass = f->subclass;
00369 out->datalen = f->datalen;
00370 out->samples = f->samples;
00371 out->delivery = f->delivery;
00372 out->mallocd = AST_MALLOCD_HDR;
00373 out->offset = AST_FRIENDLY_OFFSET;
00374 out->data = buf + sizeof(struct ast_frame) + AST_FRIENDLY_OFFSET;
00375 if (srclen > 0) {
00376 out->src = out->data + f->datalen;
00377
00378 strcpy((char *)out->src, f->src);
00379 } else
00380 out->src = NULL;
00381 out->prev = NULL;
00382 out->next = NULL;
00383 memcpy(out->data, f->data, out->datalen);
00384 return out;
00385 }
00386
00387 #if 0
00388
00389
00390
00391
00392
00393
00394 struct ast_frame *ast_fr_fdread(int fd)
00395 {
00396 char buf[65536];
00397 int res;
00398 int ttl = sizeof(struct ast_frame);
00399 struct ast_frame *f = (struct ast_frame *)buf;
00400
00401
00402
00403 while(ttl) {
00404 res = read(fd, buf, ttl);
00405 if (res < 0) {
00406 ast_log(LOG_WARNING, "Bad read on %d: %s\n", fd, strerror(errno));
00407 return NULL;
00408 }
00409 ttl -= res;
00410 }
00411
00412
00413 f->mallocd = 0;
00414
00415 f->data = buf + sizeof(struct ast_frame);
00416 f->offset = 0;
00417
00418 f->mallocd = 0;
00419
00420 f->src = (char *)__FUNCTION__;
00421 if (f->datalen > sizeof(buf) - sizeof(struct ast_frame)) {
00422
00423 ast_log(LOG_WARNING, "Strange read (%d bytes)\n", f->datalen);
00424 return NULL;
00425 }
00426 if (f->datalen) {
00427 if ((res = read(fd, f->data, f->datalen)) != f->datalen) {
00428
00429 ast_log(LOG_WARNING, "How very strange, expected %d, got %d\n", f->datalen, res);
00430 return NULL;
00431 }
00432 }
00433 if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_HANGUP)) {
00434 return NULL;
00435 }
00436 return ast_frisolate(f);
00437 }
00438
00439
00440
00441
00442
00443
00444
00445
00446
00447 int ast_fr_fdwrite(int fd, struct ast_frame *frame)
00448 {
00449
00450 if (write(fd, frame, sizeof(struct ast_frame)) != sizeof(struct ast_frame)) {
00451 ast_log(LOG_WARNING, "Write error: %s\n", strerror(errno));
00452 return -1;
00453 }
00454 if (write(fd, frame->data, frame->datalen) != frame->datalen) {
00455 ast_log(LOG_WARNING, "Write error: %s\n", strerror(errno));
00456 return -1;
00457 }
00458 return 0;
00459 }
00460
00461 int ast_fr_fdhangup(int fd)
00462 {
00463 struct ast_frame hangup = {
00464 AST_FRAME_CONTROL,
00465 AST_CONTROL_HANGUP
00466 };
00467 return ast_fr_fdwrite(fd, &hangup);
00468 }
00469
00470 #endif
00471 void ast_swapcopy_samples(void *dst, const void *src, int samples)
00472 {
00473 int i;
00474 unsigned short *dst_s = dst;
00475 const unsigned short *src_s = src;
00476
00477 for (i=0; i<samples; i++)
00478 dst_s[i] = (src_s[i]<<8) | (src_s[i]>>8);
00479 }
00480
00481
00482 struct ast_format_list *ast_get_format_list_index(int index)
00483 {
00484 return &AST_FORMAT_LIST[index];
00485 }
00486
00487 struct ast_format_list *ast_get_format_list(size_t *size)
00488 {
00489 *size = (sizeof(AST_FORMAT_LIST) / sizeof(struct ast_format_list));
00490 return AST_FORMAT_LIST;
00491 }
00492
00493 char* ast_getformatname(int format)
00494 {
00495 int x = 0;
00496 char *ret = "unknown";
00497 for (x = 0 ; x < sizeof(AST_FORMAT_LIST) / sizeof(struct ast_format_list) ; x++) {
00498 if(AST_FORMAT_LIST[x].visible && AST_FORMAT_LIST[x].bits == format) {
00499 ret = AST_FORMAT_LIST[x].name;
00500 break;
00501 }
00502 }
00503 return ret;
00504 }
00505
00506 char *ast_getformatname_multiple(char *buf, size_t size, int format) {
00507
00508 int x = 0;
00509 unsigned len;
00510 char *end = buf;
00511 char *start = buf;
00512 if (!size) return buf;
00513 snprintf(end, size, "0x%x (", format);
00514 len = strlen(end);
00515 end += len;
00516 size -= len;
00517 start = end;
00518 for (x = 0 ; x < sizeof(AST_FORMAT_LIST) / sizeof(struct ast_format_list) ; x++) {
00519 if (AST_FORMAT_LIST[x].visible && (AST_FORMAT_LIST[x].bits & format)) {
00520 snprintf(end, size,"%s|",AST_FORMAT_LIST[x].name);
00521 len = strlen(end);
00522 end += len;
00523 size -= len;
00524 }
00525 }
00526 if (start == end)
00527 snprintf(start, size, "nothing)");
00528 else if (size > 1)
00529 *(end -1) = ')';
00530 return buf;
00531 }
00532
00533 static struct ast_codec_alias_table {
00534 char *alias;
00535 char *realname;
00536
00537 } ast_codec_alias_table[] = {
00538 {"slinear","slin"},
00539 {"g723.1","g723"},
00540 };
00541
00542 static char *ast_expand_codec_alias(char *in) {
00543 int x = 0;
00544
00545 for (x = 0; x < sizeof(ast_codec_alias_table) / sizeof(struct ast_codec_alias_table) ; x++) {
00546 if(!strcmp(in,ast_codec_alias_table[x].alias))
00547 return ast_codec_alias_table[x].realname;
00548 }
00549 return in;
00550 }
00551
00552 int ast_getformatbyname(char *name)
00553 {
00554 int x = 0, all = 0, format = 0;
00555
00556 all = strcasecmp(name, "all") ? 0 : 1;
00557 for (x = 0 ; x < sizeof(AST_FORMAT_LIST) / sizeof(struct ast_format_list) ; x++) {
00558 if(AST_FORMAT_LIST[x].visible && (all ||
00559 !strcasecmp(AST_FORMAT_LIST[x].name,name) ||
00560 !strcasecmp(AST_FORMAT_LIST[x].name,ast_expand_codec_alias(name)))) {
00561 format |= AST_FORMAT_LIST[x].bits;
00562 if(!all)
00563 break;
00564 }
00565 }
00566
00567 return format;
00568 }
00569
00570 char *ast_codec2str(int codec) {
00571 int x = 0;
00572 char *ret = "unknown";
00573 for (x = 0 ; x < sizeof(AST_FORMAT_LIST) / sizeof(struct ast_format_list) ; x++) {
00574 if(AST_FORMAT_LIST[x].visible && AST_FORMAT_LIST[x].bits == codec) {
00575 ret = AST_FORMAT_LIST[x].desc;
00576 break;
00577 }
00578 }
00579 return ret;
00580 }
00581
00582 static int show_codecs(int fd, int argc, char *argv[])
00583 {
00584 int i, found=0;
00585 char hex[25];
00586
00587 if ((argc < 2) || (argc > 3))
00588 return RESULT_SHOWUSAGE;
00589
00590 if (!option_dontwarn)
00591 ast_cli(fd, "Disclaimer: this command is for informational purposes only.\n"
00592 "\tIt does not indicate anything about your configuration.\n");
00593
00594 ast_cli(fd, "%11s %9s %10s TYPE %5s %s\n","INT","BINARY","HEX","NAME","DESC");
00595 ast_cli(fd, "--------------------------------------------------------------------------------\n");
00596 if ((argc == 2) || (!strcasecmp(argv[1],"audio"))) {
00597 found = 1;
00598 for (i=0;i<11;i++) {
00599 snprintf(hex,25,"(0x%x)",1<<i);
00600 ast_cli(fd, "%11u (1 << %2d) %10s audio %5s (%s)\n",1 << i,i,hex,ast_getformatname(1<<i),ast_codec2str(1<<i));
00601 }
00602 }
00603
00604 if ((argc == 2) || (!strcasecmp(argv[1],"image"))) {
00605 found = 1;
00606 for (i=16;i<18;i++) {
00607 snprintf(hex,25,"(0x%x)",1<<i);
00608 ast_cli(fd, "%11u (1 << %2d) %10s image %5s (%s)\n",1 << i,i,hex,ast_getformatname(1<<i),ast_codec2str(1<<i));
00609 }
00610 }
00611
00612 if ((argc == 2) || (!strcasecmp(argv[1],"video"))) {
00613 found = 1;
00614 for (i=18;i<21;i++) {
00615 snprintf(hex,25,"(0x%x)",1<<i);
00616 ast_cli(fd, "%11u (1 << %2d) %10s video %5s (%s)\n",1 << i,i,hex,ast_getformatname(1<<i),ast_codec2str(1<<i));
00617 }
00618 }
00619
00620 if (! found)
00621 return RESULT_SHOWUSAGE;
00622 else
00623 return RESULT_SUCCESS;
00624 }
00625
00626 static char frame_show_codecs_usage[] =
00627 "Usage: show [audio|video|image] codecs\n"
00628 " Displays codec mapping\n";
00629
00630 static int show_codec_n(int fd, int argc, char *argv[])
00631 {
00632 int codec, i, found=0;
00633
00634 if (argc != 3)
00635 return RESULT_SHOWUSAGE;
00636
00637 if (sscanf(argv[2],"%d",&codec) != 1)
00638 return RESULT_SHOWUSAGE;
00639
00640 for (i=0;i<32;i++)
00641 if (codec & (1 << i)) {
00642 found = 1;
00643 ast_cli(fd, "%11u (1 << %2d) %s\n",1 << i,i,ast_codec2str(1<<i));
00644 }
00645
00646 if (! found)
00647 ast_cli(fd, "Codec %d not found\n", codec);
00648
00649 return RESULT_SUCCESS;
00650 }
00651
00652 static char frame_show_codec_n_usage[] =
00653 "Usage: show codec <number>\n"
00654 " Displays codec mapping\n";
00655
00656
00657 void ast_frame_dump(char *name, struct ast_frame *f, char *prefix)
00658 {
00659 char *n = "unknown";
00660 char ftype[40] = "Unknown Frametype";
00661 char cft[80];
00662 char subclass[40] = "Unknown Subclass";
00663 char csub[80];
00664 char moreinfo[40] = "";
00665 char cn[60];
00666 char cp[40];
00667 char cmn[40];
00668 if (name)
00669 n = name;
00670 if (!f) {
00671 ast_verbose("%s [ %s (NULL) ] [%s]\n",
00672 term_color(cp, prefix, COLOR_BRMAGENTA, COLOR_BLACK, sizeof(cp)),
00673 term_color(cft, "HANGUP", COLOR_BRRED, COLOR_BLACK, sizeof(cft)),
00674 term_color(cn, n, COLOR_YELLOW, COLOR_BLACK, sizeof(cn)));
00675 return;
00676 }
00677
00678 if (f->frametype == AST_FRAME_VOICE)
00679 return;
00680 if (f->frametype == AST_FRAME_VIDEO)
00681 return;
00682 switch(f->frametype) {
00683 case AST_FRAME_DTMF:
00684 strcpy(ftype, "DTMF");
00685 subclass[0] = f->subclass;
00686 subclass[1] = '\0';
00687 break;
00688 case AST_FRAME_CONTROL:
00689 strcpy(ftype, "Control");
00690 switch(f->subclass) {
00691 case AST_CONTROL_HANGUP:
00692 strcpy(subclass, "Hangup");
00693 break;
00694 case AST_CONTROL_RING:
00695 strcpy(subclass, "Ring");
00696 break;
00697 case AST_CONTROL_RINGING:
00698 strcpy(subclass, "Ringing");
00699 break;
00700 case AST_CONTROL_ANSWER:
00701 strcpy(subclass, "Answer");
00702 break;
00703 case AST_CONTROL_BUSY:
00704 strcpy(subclass, "Busy");
00705 break;
00706 case AST_CONTROL_TAKEOFFHOOK:
00707 strcpy(subclass, "Take Off Hook");
00708 break;
00709 case AST_CONTROL_OFFHOOK:
00710 strcpy(subclass, "Line Off Hook");
00711 break;
00712 case AST_CONTROL_CONGESTION:
00713 strcpy(subclass, "Congestion");
00714 break;
00715 case AST_CONTROL_FLASH:
00716 strcpy(subclass, "Flash");
00717 break;
00718 case AST_CONTROL_WINK:
00719 strcpy(subclass, "Wink");
00720 break;
00721 case AST_CONTROL_OPTION:
00722 strcpy(subclass, "Option");
00723 break;
00724 case AST_CONTROL_RADIO_KEY:
00725 strcpy(subclass, "Key Radio");
00726 break;
00727 case AST_CONTROL_RADIO_UNKEY:
00728 strcpy(subclass, "Unkey Radio");
00729 break;
00730 case -1:
00731 strcpy(subclass, "Stop generators");
00732 break;
00733 default:
00734 snprintf(subclass, sizeof(subclass), "Unknown control '%d'", f->subclass);
00735 }
00736 break;
00737 case AST_FRAME_NULL:
00738 strcpy(ftype, "Null Frame");
00739 strcpy(subclass, "N/A");
00740 break;
00741 case AST_FRAME_IAX:
00742
00743 strcpy(ftype, "IAX Specific");
00744 snprintf(subclass, sizeof(subclass), "IAX Frametype %d", f->subclass);
00745 break;
00746 case AST_FRAME_TEXT:
00747 strcpy(ftype, "Text");
00748 strcpy(subclass, "N/A");
00749 ast_copy_string(moreinfo, f->data, sizeof(moreinfo));
00750 break;
00751 case AST_FRAME_IMAGE:
00752 strcpy(ftype, "Image");
00753 snprintf(subclass, sizeof(subclass), "Image format %s\n", ast_getformatname(f->subclass));
00754 break;
00755 case AST_FRAME_HTML:
00756 strcpy(ftype, "HTML");
00757 switch(f->subclass) {
00758 case AST_HTML_URL:
00759 strcpy(subclass, "URL");
00760 ast_copy_string(moreinfo, f->data, sizeof(moreinfo));
00761 break;
00762 case AST_HTML_DATA:
00763 strcpy(subclass, "Data");
00764 break;
00765 case AST_HTML_BEGIN:
00766 strcpy(subclass, "Begin");
00767 break;
00768 case AST_HTML_END:
00769 strcpy(subclass, "End");
00770 break;
00771 case AST_HTML_LDCOMPLETE:
00772 strcpy(subclass, "Load Complete");
00773 break;
00774 case AST_HTML_NOSUPPORT:
00775 strcpy(subclass, "No Support");
00776 break;
00777 case AST_HTML_LINKURL:
00778 strcpy(subclass, "Link URL");
00779 ast_copy_string(moreinfo, f->data, sizeof(moreinfo));
00780 break;
00781 case AST_HTML_UNLINK:
00782 strcpy(subclass, "Unlink");
00783 break;
00784 case AST_HTML_LINKREJECT:
00785 strcpy(subclass, "Link Reject");
00786 break;
00787 default:
00788 snprintf(subclass, sizeof(subclass), "Unknown HTML frame '%d'\n", f->subclass);
00789 break;
00790 }
00791 break;
00792 default:
00793 snprintf(ftype, sizeof(ftype), "Unknown Frametype '%d'", f->frametype);
00794 }
00795 if (!ast_strlen_zero(moreinfo))
00796 ast_verbose("%s [ TYPE: %s (%d) SUBCLASS: %s (%d) '%s' ] [%s]\n",
00797 term_color(cp, prefix, COLOR_BRMAGENTA, COLOR_BLACK, sizeof(cp)),
00798 term_color(cft, ftype, COLOR_BRRED, COLOR_BLACK, sizeof(cft)),
00799 f->frametype,
00800 term_color(csub, subclass, COLOR_BRCYAN, COLOR_BLACK, sizeof(csub)),
00801 f->subclass,
00802 term_color(cmn, moreinfo, COLOR_BRGREEN, COLOR_BLACK, sizeof(cmn)),
00803 term_color(cn, n, COLOR_YELLOW, COLOR_BLACK, sizeof(cn)));
00804 else
00805 ast_verbose("%s [ TYPE: %s (%d) SUBCLASS: %s (%d) ] [%s]\n",
00806 term_color(cp, prefix, COLOR_BRMAGENTA, COLOR_BLACK, sizeof(cp)),
00807 term_color(cft, ftype, COLOR_BRRED, COLOR_BLACK, sizeof(cft)),
00808 f->frametype,
00809 term_color(csub, subclass, COLOR_BRCYAN, COLOR_BLACK, sizeof(csub)),
00810 f->subclass,
00811 term_color(cn, n, COLOR_YELLOW, COLOR_BLACK, sizeof(cn)));
00812
00813 }
00814
00815
00816 #ifdef TRACE_FRAMES
00817 static int show_frame_stats(int fd, int argc, char *argv[])
00818 {
00819 struct ast_frame *f;
00820 int x=1;
00821 if (argc != 3)
00822 return RESULT_SHOWUSAGE;
00823 ast_cli(fd, " Framer Statistics \n");
00824 ast_cli(fd, "---------------------------\n");
00825 ast_cli(fd, "Total allocated headers: %d\n", headers);
00826 ast_cli(fd, "Queue Dump:\n");
00827 ast_mutex_lock(&framelock);
00828 for (f=headerlist; f; f = f->next) {
00829 ast_cli(fd, "%d. Type %d, subclass %d from %s\n", x++, f->frametype, f->subclass, f->src ? f->src : "<Unknown>");
00830 }
00831 ast_mutex_unlock(&framelock);
00832 return RESULT_SUCCESS;
00833 }
00834
00835 static char frame_stats_usage[] =
00836 "Usage: show frame stats\n"
00837 " Displays debugging statistics from framer\n";
00838 #endif
00839
00840
00841 static struct ast_cli_entry my_clis[] = {
00842 { { "show", "codecs", NULL }, show_codecs, "Shows codecs", frame_show_codecs_usage },
00843 { { "show", "audio", "codecs", NULL }, show_codecs, "Shows audio codecs", frame_show_codecs_usage },
00844 { { "show", "video", "codecs", NULL }, show_codecs, "Shows video codecs", frame_show_codecs_usage },
00845 { { "show", "image", "codecs", NULL }, show_codecs, "Shows image codecs", frame_show_codecs_usage },
00846 { { "show", "codec", NULL }, show_codec_n, "Shows a specific codec", frame_show_codec_n_usage },
00847 #ifdef TRACE_FRAMES
00848 { { "show", "frame", "stats", NULL }, show_frame_stats, "Shows frame statistics", frame_stats_usage },
00849 #endif
00850 };
00851
00852 int init_framer(void)
00853 {
00854 ast_cli_register_multiple(my_clis, sizeof(my_clis)/sizeof(my_clis[0]) );
00855 return 0;
00856 }
00857
00858 void ast_codec_pref_convert(struct ast_codec_pref *pref, char *buf, size_t size, int right)
00859 {
00860 int x = 0, differential = (int) 'A', mem = 0;
00861 char *from = NULL, *to = NULL;
00862
00863 if(right) {
00864 from = pref->order;
00865 to = buf;
00866 mem = size;
00867 } else {
00868 to = pref->order;
00869 from = buf;
00870 mem = 32;
00871 }
00872
00873 memset(to, 0, mem);
00874 for (x = 0; x < 32 ; x++) {
00875 if(!from[x])
00876 break;
00877 to[x] = right ? (from[x] + differential) : (from[x] - differential);
00878 }
00879 }
00880
00881 int ast_codec_pref_string(struct ast_codec_pref *pref, char *buf, size_t size)
00882 {
00883 int x = 0, codec = 0;
00884 size_t total_len = 0, slen = 0;
00885 char *formatname = 0;
00886
00887 memset(buf,0,size);
00888 total_len = size;
00889 buf[0] = '(';
00890 total_len--;
00891 for(x = 0; x < 32 ; x++) {
00892 if(total_len <= 0)
00893 break;
00894 if(!(codec = ast_codec_pref_index(pref,x)))
00895 break;
00896 if((formatname = ast_getformatname(codec))) {
00897 slen = strlen(formatname);
00898 if(slen > total_len)
00899 break;
00900 strncat(buf,formatname,total_len);
00901 total_len -= slen;
00902 }
00903 if(total_len && x < 31 && ast_codec_pref_index(pref , x + 1)) {
00904 strncat(buf,"|",total_len);
00905 total_len--;
00906 }
00907 }
00908 if(total_len) {
00909 strncat(buf,")",total_len);
00910 total_len--;
00911 }
00912
00913 return size - total_len;
00914 }
00915
00916 int ast_codec_pref_index(struct ast_codec_pref *pref, int index)
00917 {
00918 int slot = 0;
00919
00920
00921 if((index >= 0) && (index < sizeof(pref->order))) {
00922 slot = pref->order[index];
00923 }
00924
00925 return slot ? AST_FORMAT_LIST[slot-1].bits : 0;
00926 }
00927
00928
00929 void ast_codec_pref_remove(struct ast_codec_pref *pref, int format)
00930 {
00931 struct ast_codec_pref oldorder;
00932 int x=0, y=0;
00933 size_t size = 0;
00934 int slot = 0;
00935
00936 if(!pref->order[0])
00937 return;
00938
00939 size = sizeof(AST_FORMAT_LIST) / sizeof(struct ast_format_list);
00940
00941 memcpy(&oldorder,pref,sizeof(struct ast_codec_pref));
00942 memset(pref,0,sizeof(struct ast_codec_pref));
00943
00944 for (x = 0; x < size; x++) {
00945 slot = oldorder.order[x];
00946 if(! slot)
00947 break;
00948 if(AST_FORMAT_LIST[slot-1].bits != format)
00949 pref->order[y++] = slot;
00950 }
00951
00952 }
00953
00954
00955 int ast_codec_pref_append(struct ast_codec_pref *pref, int format)
00956 {
00957 size_t size = 0;
00958 int x = 0, newindex = -1;
00959
00960 ast_codec_pref_remove(pref, format);
00961 size = sizeof(AST_FORMAT_LIST) / sizeof(struct ast_format_list);
00962
00963 for (x = 0; x < size; x++) {
00964 if(AST_FORMAT_LIST[x].bits == format) {
00965 newindex = x + 1;
00966 break;
00967 }
00968 }
00969
00970 if(newindex) {
00971 for (x = 0; x < size; x++) {
00972 if(!pref->order[x]) {
00973 pref->order[x] = newindex;
00974 break;
00975 }
00976 }
00977 }
00978
00979 return x;
00980 }
00981
00982
00983
00984 int ast_codec_choose(struct ast_codec_pref *pref, int formats, int find_best)
00985 {
00986 size_t size = 0;
00987 int x = 0, ret = 0, slot = 0;
00988
00989 size = sizeof(AST_FORMAT_LIST) / sizeof(struct ast_format_list);
00990 for (x = 0; x < size; x++) {
00991 slot = pref->order[x];
00992
00993 if(!slot)
00994 break;
00995 if ( formats & AST_FORMAT_LIST[slot-1].bits ) {
00996 ret = AST_FORMAT_LIST[slot-1].bits;
00997 break;
00998 }
00999 }
01000 if(ret)
01001 return ret;
01002
01003 return find_best ? ast_best_codec(formats) : 0;
01004 }
01005
01006 void ast_parse_allow_disallow(struct ast_codec_pref *pref, int *mask, const char *list, int allowing)
01007 {
01008 char *parse;
01009 char *this;
01010 int format;
01011
01012 parse = ast_strdupa(list);
01013 while ((this = strsep(&parse, ","))) {
01014 if (!(format = ast_getformatbyname(this))) {
01015 ast_log(LOG_WARNING, "Cannot %s unknown format '%s'\n", allowing ? "allow" : "disallow", this);
01016 continue;
01017 }
01018
01019 if (mask) {
01020 if (allowing)
01021 *mask |= format;
01022 else
01023 *mask &= ~format;
01024 }
01025
01026 if (pref) {
01027 if (strcasecmp(this, "all")) {
01028 if (allowing)
01029 ast_codec_pref_append(pref, format);
01030 else
01031 ast_codec_pref_remove(pref, format);
01032 } else if (!allowing) {
01033 memset(pref, 0, sizeof(*pref));
01034 }
01035 }
01036 }
01037 }
01038
01039 static int g723_len(unsigned char buf)
01040 {
01041 switch(buf & TYPE_MASK) {
01042 case TYPE_DONTSEND:
01043 return 0;
01044 break;
01045 case TYPE_SILENCE:
01046 return 4;
01047 break;
01048 case TYPE_HIGH:
01049 return 24;
01050 break;
01051 case TYPE_LOW:
01052 return 20;
01053 break;
01054 default:
01055 ast_log(LOG_WARNING, "Badly encoded frame (%d)\n", buf & TYPE_MASK);
01056 }
01057 return -1;
01058 }
01059
01060 static int g723_samples(unsigned char *buf, int maxlen)
01061 {
01062 int pos = 0;
01063 int samples = 0;
01064 int res;
01065 while(pos < maxlen) {
01066 res = g723_len(buf[pos]);
01067 if (res <= 0)
01068 break;
01069 samples += 240;
01070 pos += res;
01071 }
01072 return samples;
01073 }
01074
01075 static unsigned char get_n_bits_at(unsigned char *data, int n, int bit)
01076 {
01077 int byte = bit / 8;
01078 int rem = 8 - (bit % 8);
01079 unsigned char ret = 0;
01080
01081 if (n <= 0 || n > 8)
01082 return 0;
01083
01084 if (rem < n) {
01085 ret = (data[byte] << (n - rem));
01086 ret |= (data[byte + 1] >> (8 - n + rem));
01087 } else {
01088 ret = (data[byte] >> (rem - n));
01089 }
01090
01091 return (ret & (0xff >> (8 - n)));
01092 }
01093
01094 static int speex_get_wb_sz_at(unsigned char *data, int len, int bit)
01095 {
01096 static int SpeexWBSubModeSz[] = {
01097 0, 36, 112, 192,
01098 352, 0, 0, 0 };
01099 int off = bit;
01100 unsigned char c;
01101
01102
01103 if (((len * 8 - off) >= 5) &&
01104 get_n_bits_at(data, 1, off)) {
01105 c = get_n_bits_at(data, 3, off + 1);
01106 off += SpeexWBSubModeSz[c];
01107
01108 if (((len * 8 - off) >= 5) &&
01109 get_n_bits_at(data, 1, off)) {
01110 c = get_n_bits_at(data, 3, off + 1);
01111 off += SpeexWBSubModeSz[c];
01112
01113 if (((len * 8 - off) >= 5) &&
01114 get_n_bits_at(data, 1, off)) {
01115 ast_log(LOG_WARNING, "Encountered corrupt speex frame; too many wideband frames in a row.\n");
01116 return -1;
01117 }
01118 }
01119
01120 }
01121 return off - bit;
01122 }
01123
01124 static int speex_samples(unsigned char *data, int len)
01125 {
01126 static int SpeexSubModeSz[] = {
01127 5, 43, 119, 160,
01128 220, 300, 364, 492,
01129 79, 0, 0, 0,
01130 0, 0, 0, 0 };
01131 static int SpeexInBandSz[] = {
01132 1, 1, 4, 4,
01133 4, 4, 4, 4,
01134 8, 8, 16, 16,
01135 32, 32, 64, 64 };
01136 int bit = 0;
01137 int cnt = 0;
01138 int off = 0;
01139 unsigned char c;
01140
01141 while ((len * 8 - bit) >= 5) {
01142
01143 off = speex_get_wb_sz_at(data, len, bit);
01144 if (off < 0) {
01145 ast_log(LOG_WARNING, "Had error while reading wideband frames for speex samples\n");
01146 break;
01147 }
01148 bit += off;
01149
01150 if ((len * 8 - bit) < 5) {
01151 ast_log(LOG_WARNING, "Not enough bits remaining after wide band for speex samples.\n");
01152 break;
01153 }
01154
01155
01156 c = get_n_bits_at(data, 5, bit);
01157 bit += 5;
01158
01159 if (c == 15) {
01160
01161 break;
01162 } else if (c == 14) {
01163
01164 c = get_n_bits_at(data, 4, bit);
01165 bit += 4;
01166 bit += SpeexInBandSz[c];
01167 } else if (c == 13) {
01168
01169 c = get_n_bits_at(data, 5, bit);
01170 bit += 5;
01171 bit += c * 8;
01172 } else if (c > 8) {
01173
01174 break;
01175 } else {
01176
01177 bit += SpeexSubModeSz[c] - 5;
01178 cnt += 160;
01179 }
01180 }
01181 return cnt;
01182 }
01183
01184 int ast_codec_get_samples(struct ast_frame *f)
01185 {
01186 int samples=0;
01187 switch(f->subclass) {
01188 case AST_FORMAT_SPEEX:
01189 samples = speex_samples(f->data, f->datalen);
01190 break;
01191 case AST_FORMAT_G723_1:
01192 samples = g723_samples(f->data, f->datalen);
01193 break;
01194 case AST_FORMAT_ILBC:
01195 samples = 240 * (f->datalen / 50);
01196 break;
01197 case AST_FORMAT_GSM:
01198 samples = 160 * (f->datalen / 33);
01199 break;
01200 case AST_FORMAT_G729A:
01201 samples = f->datalen * 8;
01202 break;
01203 case AST_FORMAT_SLINEAR:
01204 samples = f->datalen / 2;
01205 break;
01206 case AST_FORMAT_LPC10:
01207
01208 samples = 22 * 8;
01209 samples += (((char *)(f->data))[7] & 0x1) * 8;
01210 break;
01211 case AST_FORMAT_ULAW:
01212 case AST_FORMAT_ALAW:
01213 samples = f->datalen;
01214 break;
01215 case AST_FORMAT_ADPCM:
01216 case AST_FORMAT_G726:
01217 samples = f->datalen * 2;
01218 break;
01219 default:
01220 ast_log(LOG_WARNING, "Unable to calculate samples for format %s\n", ast_getformatname(f->subclass));
01221 }
01222 return samples;
01223 }
01224
01225 int ast_codec_get_len(int format, int samples)
01226 {
01227 int len = 0;
01228
01229
01230 switch(format) {
01231 case AST_FORMAT_ILBC:
01232 len = (samples / 240) * 50;
01233 break;
01234 case AST_FORMAT_GSM:
01235 len = (samples / 160) * 33;
01236 break;
01237 case AST_FORMAT_G729A:
01238 len = samples / 8;
01239 break;
01240 case AST_FORMAT_SLINEAR:
01241 len = samples * 2;
01242 break;
01243 case AST_FORMAT_ULAW:
01244 case AST_FORMAT_ALAW:
01245 len = samples;
01246 break;
01247 case AST_FORMAT_ADPCM:
01248 case AST_FORMAT_G726:
01249 len = samples / 2;
01250 break;
01251 default:
01252 ast_log(LOG_WARNING, "Unable to calculate sample length for format %s\n", ast_getformatname(format));
01253 }
01254
01255 return len;
01256 }
01257
01258 int ast_frame_adjust_volume(struct ast_frame *f, int adjustment)
01259 {
01260 int count;
01261 short *fdata = f->data;
01262 short adjust_value = abs(adjustment);
01263
01264 if ((f->frametype != AST_FRAME_VOICE) || (f->subclass != AST_FORMAT_SLINEAR))
01265 return -1;
01266
01267 if (!adjustment)
01268 return 0;
01269
01270 for (count = 0; count < f->samples; count++) {
01271 if (adjustment > 0) {
01272 ast_slinear_saturated_multiply(&fdata[count], &adjust_value);
01273 } else if (adjustment < 0) {
01274 ast_slinear_saturated_divide(&fdata[count], &adjust_value);
01275 }
01276 }
01277
01278 return 0;
01279 }
01280
01281 int ast_frame_slinear_sum(struct ast_frame *f1, struct ast_frame *f2)
01282 {
01283 int count;
01284 short *data1, *data2;
01285
01286 if ((f1->frametype != AST_FRAME_VOICE) || (f1->subclass != AST_FORMAT_SLINEAR))
01287 return -1;
01288
01289 if ((f2->frametype != AST_FRAME_VOICE) || (f2->subclass != AST_FORMAT_SLINEAR))
01290 return -1;
01291
01292 if (f1->samples != f2->samples)
01293 return -1;
01294
01295 for (count = 0, data1 = f1->data, data2 = f2->data;
01296 count < f1->samples;
01297 count++, data1++, data2++)
01298 ast_slinear_saturated_add(data1, data2);
01299
01300 return 0;
01301 }