2 * Asterisk -- An open source telephony toolkit.
4 * Copyright (C) 1999 - 2005, Digium, Inc.
6 * Mark Spencer <markster@digium.com>
8 * See http://www.asterisk.org for more information about
9 * the Asterisk project. Please do not directly contact
10 * any of the maintainers of this project for assistance;
11 * the project provides a web site, mailing lists and IRC
12 * channels for your use.
14 * This program is free software, distributed under the terms of
15 * the GNU General Public License Version 2. See the LICENSE file
16 * at the top of the source tree.
21 * \brief Frame and codec manipulation routines
23 * \author Mark Spencer <markster@digium.com>
28 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
36 #include "asterisk/lock.h"
37 #include "asterisk/frame.h"
38 #include "asterisk/logger.h"
39 #include "asterisk/options.h"
40 #include "asterisk/channel.h"
41 #include "asterisk/cli.h"
42 #include "asterisk/term.h"
43 #include "asterisk/utils.h"
46 static int headers = 0;
47 static struct ast_frame *headerlist = NULL;
48 AST_MUTEX_DEFINE_STATIC(framelock);
51 #define SMOOTHER_SIZE 8000
56 TYPE_SILENCE, /* 0x2 */
57 TYPE_DONTSEND /* 0x3 */
66 int optimizablestream;
70 struct timeval delivery;
71 char data[SMOOTHER_SIZE];
72 char framedata[SMOOTHER_SIZE + AST_FRIENDLY_OFFSET];
73 struct ast_frame *opt;
77 /*! \brief Definition of supported media formats (codecs) */
78 static struct ast_format_list {
79 int visible; /*!< Can we see this entry */
80 int bits; /*!< bitmask value */
81 char *name; /*!< short name */
82 char *desc; /*!< Description */
83 } AST_FORMAT_LIST[] = { /*!< Bit number: comment - Bit numbers are hard coded in show_codec() */
84 { 1, AST_FORMAT_G723_1 , "g723" , "G.723.1"}, /*!< 1: codec_g723_1.c */
85 { 1, AST_FORMAT_GSM, "gsm" , "GSM"}, /*!< 2: codec_gsm.c */
86 { 1, AST_FORMAT_ULAW, "ulaw", "G.711 u-law" }, /*!< 3: codec_ulaw.c */
87 { 1, AST_FORMAT_ALAW, "alaw", "G.711 A-law" }, /*!< 4: codec_alaw.c */
88 { 1, AST_FORMAT_G726, "g726", "G.726" }, /*!< 5: codec_g726.c */
89 { 1, AST_FORMAT_ADPCM, "adpcm" , "ADPCM"}, /*!< 6: codec_adpcm.c */
90 { 1, AST_FORMAT_SLINEAR, "slin", "16 bit Signed Linear PCM"}, /*!< 7 */
91 { 1, AST_FORMAT_LPC10, "lpc10", "LPC10" }, /*!< 8: codec_lpc10.c */
92 { 1, AST_FORMAT_G729A, "g729", "G.729A" }, /*!< 9: Binary commercial distribution */
93 { 1, AST_FORMAT_SPEEX, "speex", "SpeeX" }, /*!< 10: codec_speex.c */
94 { 1, AST_FORMAT_ILBC, "ilbc", "iLBC"}, /*!< 11: codec_ilbc.c */
95 { 0, 0, "nothing", "undefined" },
96 { 0, 0, "nothing", "undefined" },
97 { 0, 0, "nothing", "undefined" },
98 { 0, 0, "nothing", "undefined" },
99 { 0, AST_FORMAT_MAX_AUDIO, "maxaudio", "Maximum audio format" },
100 { 1, AST_FORMAT_JPEG, "jpeg", "JPEG image"}, /*!< 17: See format_jpeg.c */
101 { 1, AST_FORMAT_PNG, "png", "PNG image"}, /*!< 18: Image format */
102 { 1, AST_FORMAT_H261, "h261", "H.261 Video" }, /*!< 19: Video Passthrough */
103 { 1, AST_FORMAT_H263, "h263", "H.263 Video" }, /*!< 20: Passthrough support, see format_h263.c */
104 { 1, AST_FORMAT_H263_PLUS, "h263p", "H.263+ Video" }, /*!< 21: See format_h263.c */
105 { 1, AST_FORMAT_H264, "h264", "H.264 Video" }, /*!< 22: Passthrough support, see format_h263.c */
106 { 0, 0, "nothing", "undefined" },
107 { 0, 0, "nothing", "undefined" },
108 { 0, 0, "nothing", "undefined" },
109 { 0, AST_FORMAT_MAX_VIDEO, "maxvideo", "Maximum video format" },
112 struct ast_frame ast_null_frame = { AST_FRAME_NULL, };
114 void ast_smoother_reset(struct ast_smoother *s, int size)
116 memset(s, 0, sizeof(*s));
120 struct ast_smoother *ast_smoother_new(int size)
122 struct ast_smoother *s;
125 if ((s = ast_malloc(sizeof(*s))))
126 ast_smoother_reset(s, size);
130 int ast_smoother_get_flags(struct ast_smoother *s)
135 void ast_smoother_set_flags(struct ast_smoother *s, int flags)
140 int __ast_smoother_feed(struct ast_smoother *s, struct ast_frame *f, int swap)
142 if (f->frametype != AST_FRAME_VOICE) {
143 ast_log(LOG_WARNING, "Huh? Can't smooth a non-voice frame!\n");
147 s->format = f->subclass;
148 s->samplesperbyte = (float)f->samples / (float)f->datalen;
149 } else if (s->format != f->subclass) {
150 ast_log(LOG_WARNING, "Smoother was working on %d format frames, now trying to feed %d?\n", s->format, f->subclass);
153 if (s->len + f->datalen > SMOOTHER_SIZE) {
154 ast_log(LOG_WARNING, "Out of smoother space\n");
157 if (((f->datalen == s->size) || ((f->datalen < 10) && (s->flags & AST_SMOOTHER_FLAG_G729)))
158 && !s->opt && (f->offset >= AST_MIN_OFFSET)) {
160 /* Optimize by sending the frame we just got
161 on the next read, thus eliminating the douple
166 s->optimizablestream++;
167 if (s->optimizablestream > 10) {
168 /* For the past 10 rounds, we have input and output
169 frames of the correct size for this smoother, yet
170 we were unable to optimize because there was still
171 some cruft left over. Lets just drop the cruft so
172 we can move to a fully optimized path */
179 s->optimizablestream = 0;
180 if (s->flags & AST_SMOOTHER_FLAG_G729) {
182 ast_log(LOG_NOTICE, "Dropping extra frame of G.729 since we already have a VAD frame at the end\n");
187 ast_swapcopy_samples(s->data+s->len, f->data, f->samples);
189 memcpy(s->data + s->len, f->data, f->datalen);
190 /* If either side is empty, reset the delivery time */
191 if (!s->len || ast_tvzero(f->delivery) || ast_tvzero(s->delivery)) /* XXX really ? */
192 s->delivery = f->delivery;
193 s->len += f->datalen;
197 struct ast_frame *ast_smoother_read(struct ast_smoother *s)
199 struct ast_frame *opt;
202 /* IF we have an optimization frame, send it */
204 if (s->opt->offset < AST_FRIENDLY_OFFSET)
205 ast_log(LOG_WARNING, "Returning a frame of inappropriate offset (%d).",
212 /* Make sure we have enough data */
213 if (s->len < s->size) {
214 /* Or, if this is a G.729 frame with VAD on it, send it immediately anyway */
215 if (!((s->flags & AST_SMOOTHER_FLAG_G729) && (s->size % 10)))
222 s->f.frametype = AST_FRAME_VOICE;
223 s->f.subclass = s->format;
224 s->f.data = s->framedata + AST_FRIENDLY_OFFSET;
225 s->f.offset = AST_FRIENDLY_OFFSET;
227 /* Samples will be improper given VAD, but with VAD the concept really doesn't even exist */
228 s->f.samples = len * s->samplesperbyte; /* XXX rounding */
229 s->f.delivery = s->delivery;
231 memcpy(s->f.data, s->data, len);
233 /* Move remaining data to the front if applicable */
235 /* In principle this should all be fine because if we are sending
236 G.729 VAD, the next timestamp will take over anyawy */
237 memmove(s->data, s->data + len, s->len);
238 if (!ast_tvzero(s->delivery)) {
239 /* If we have delivery time, increment it, otherwise, leave it at 0 */
240 s->delivery = ast_tvadd(s->delivery, ast_samp2tv(s->f.samples, 8000));
247 void ast_smoother_free(struct ast_smoother *s)
252 static struct ast_frame *ast_frame_header_new(void)
254 struct ast_frame *f = ast_calloc(1, sizeof(*f));
259 ast_mutex_lock(&framelock);
260 f->next = headerlist;
262 headerlist->prev = f;
264 ast_mutex_unlock(&framelock);
271 * \todo Important: I should be made more efficient. Frame headers should
272 * most definitely be cached
274 void ast_frfree(struct ast_frame *fr)
276 if (fr->mallocd & AST_MALLOCD_DATA) {
278 free(fr->data - fr->offset);
280 if (fr->mallocd & AST_MALLOCD_SRC) {
282 free((char *)fr->src);
284 if (fr->mallocd & AST_MALLOCD_HDR) {
287 ast_mutex_lock(&framelock);
289 fr->next->prev = fr->prev;
291 fr->prev->next = fr->next;
293 headerlist = fr->next;
294 ast_mutex_unlock(&framelock);
301 * \brief 'isolates' a frame by duplicating non-malloc'ed components
302 * (header, src, data).
303 * On return all components are malloc'ed
305 struct ast_frame *ast_frisolate(struct ast_frame *fr)
307 struct ast_frame *out;
310 if (!(fr->mallocd & AST_MALLOCD_HDR)) {
311 /* Allocate a new header if needed */
312 if (!(out = ast_frame_header_new()))
314 out->frametype = fr->frametype;
315 out->subclass = fr->subclass;
316 out->datalen = fr->datalen;
317 out->samples = fr->samples;
318 out->offset = fr->offset;
319 out->data = fr->data;
320 /* Copy the timing data */
321 out->has_timing_info = fr->has_timing_info;
322 if (fr->has_timing_info) {
325 out->seqno = fr->seqno;
330 if (!(fr->mallocd & AST_MALLOCD_SRC)) {
332 if (!(out->src = ast_strdup(fr->src))) {
341 if (!(fr->mallocd & AST_MALLOCD_DATA)) {
342 if (!(newdata = ast_malloc(fr->datalen + AST_FRIENDLY_OFFSET))) {
343 if (out->src != fr->src)
344 free((void *) out->src);
349 newdata += AST_FRIENDLY_OFFSET;
350 out->offset = AST_FRIENDLY_OFFSET;
351 out->datalen = fr->datalen;
352 memcpy(newdata, fr->data, fr->datalen);
356 out->mallocd = AST_MALLOCD_HDR | AST_MALLOCD_SRC | AST_MALLOCD_DATA;
361 struct ast_frame *ast_frdup(struct ast_frame *f)
363 struct ast_frame *out;
366 /* Start with standard stuff */
367 len = sizeof(*out) + AST_FRIENDLY_OFFSET + f->datalen;
368 /* If we have a source, add space for it */
370 * XXX Watch out here - if we receive a src which is not terminated
371 * properly, we can be easily attacked. Should limit the size we deal with.
374 srclen = strlen(f->src);
377 if (!(buf = ast_malloc(len)))
380 /* Set us as having malloc'd header only, so it will eventually
382 out->frametype = f->frametype;
383 out->subclass = f->subclass;
384 out->datalen = f->datalen;
385 out->samples = f->samples;
386 out->delivery = f->delivery;
387 out->mallocd = AST_MALLOCD_HDR;
388 out->offset = AST_FRIENDLY_OFFSET;
389 out->data = buf + sizeof(*out) + AST_FRIENDLY_OFFSET;
391 out->src = out->data + f->datalen;
392 /* Must have space since we allocated for it */
393 strcpy((char *)out->src, f->src);
398 memcpy(out->data, f->data, out->datalen);
399 out->has_timing_info = f->has_timing_info;
400 if (f->has_timing_info) {
403 out->seqno = f->seqno;
411 * This function is badly broken - it does not handle correctly
412 * partial reads on either header or body.
413 * However is it never used anywhere so we leave it commented out
415 struct ast_frame *ast_fr_fdread(int fd)
419 struct ast_frame *f = (struct ast_frame *)buf;
420 int ttl = sizeof(*f);
421 /* Read a frame directly from there. They're always in the
425 res = read(fd, buf, ttl);
427 ast_log(LOG_WARNING, "Bad read on %d: %s\n", fd, strerror(errno));
433 /* read the frame header */
435 /* Re-write data position */
436 f->data = buf + sizeof(*f);
438 /* Forget about being mallocd */
440 /* Re-write the source */
441 f->src = (char *)__FUNCTION__;
442 if (f->datalen > sizeof(buf) - sizeof(*f)) {
443 /* Really bad read */
444 ast_log(LOG_WARNING, "Strange read (%d bytes)\n", f->datalen);
448 if ((res = read(fd, f->data, f->datalen)) != f->datalen) {
450 ast_log(LOG_WARNING, "How very strange, expected %d, got %d\n", f->datalen, res);
454 if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_HANGUP)) {
457 return ast_frisolate(f);
460 /* Some convenient routines for sending frames to/from stream or datagram
461 sockets, pipes, etc (maybe even files) */
464 * XXX this function is also partly broken because it does not handle
465 * partial writes. We comment it out too, and also the unique
466 * client it has, ast_fr_fdhangup()
468 int ast_fr_fdwrite(int fd, struct ast_frame *frame)
470 /* Write the frame exactly */
471 if (write(fd, frame, sizeof(*frame)) != sizeof(*frame)) {
472 ast_log(LOG_WARNING, "Write error: %s\n", strerror(errno));
475 if (write(fd, frame->data, frame->datalen) != frame->datalen) {
476 ast_log(LOG_WARNING, "Write error: %s\n", strerror(errno));
482 int ast_fr_fdhangup(int fd)
484 struct ast_frame hangup = {
488 return ast_fr_fdwrite(fd, &hangup);
491 #endif /* unused functions */
493 void ast_swapcopy_samples(void *dst, const void *src, int samples)
496 unsigned short *dst_s = dst;
497 const unsigned short *src_s = src;
499 for (i = 0; i < samples; i++)
500 dst_s[i] = (src_s[i]<<8) | (src_s[i]>>8);
504 struct ast_format_list *ast_get_format_list_index(int index)
506 return &AST_FORMAT_LIST[index];
509 struct ast_format_list *ast_get_format_list(size_t *size)
511 *size = (sizeof(AST_FORMAT_LIST) / sizeof(AST_FORMAT_LIST[0]));
512 return AST_FORMAT_LIST;
515 char* ast_getformatname(int format)
518 char *ret = "unknown";
519 for (x = 0; x < sizeof(AST_FORMAT_LIST) / sizeof(AST_FORMAT_LIST[0]); x++) {
520 if(AST_FORMAT_LIST[x].visible && AST_FORMAT_LIST[x].bits == format) {
521 ret = AST_FORMAT_LIST[x].name;
528 char *ast_getformatname_multiple(char *buf, size_t size, int format)
532 char *start, *end = buf;
536 snprintf(end, size, "0x%x (", format);
541 for (x = 0; x < sizeof(AST_FORMAT_LIST) / sizeof(AST_FORMAT_LIST[0]); x++) {
542 if (AST_FORMAT_LIST[x].visible && (AST_FORMAT_LIST[x].bits & format)) {
543 snprintf(end, size,"%s|",AST_FORMAT_LIST[x].name);
550 snprintf(start, size, "nothing)");
556 static struct ast_codec_alias_table {
559 } ast_codec_alias_table[] = {
560 { "slinear", "slin"},
564 static const char *ast_expand_codec_alias(const char *in)
568 for (x = 0; x < sizeof(ast_codec_alias_table) / sizeof(ast_codec_alias_table[0]); x++) {
569 if(!strcmp(in,ast_codec_alias_table[x].alias))
570 return ast_codec_alias_table[x].realname;
575 int ast_getformatbyname(const char *name)
577 int x, all, format = 0;
579 all = strcasecmp(name, "all") ? 0 : 1;
580 for (x = 0; x < sizeof(AST_FORMAT_LIST) / sizeof(AST_FORMAT_LIST[0]); x++) {
581 if(AST_FORMAT_LIST[x].visible && (all ||
582 !strcasecmp(AST_FORMAT_LIST[x].name,name) ||
583 !strcasecmp(AST_FORMAT_LIST[x].name,ast_expand_codec_alias(name)))) {
584 format |= AST_FORMAT_LIST[x].bits;
593 char *ast_codec2str(int codec)
596 char *ret = "unknown";
597 for (x = 0; x < sizeof(AST_FORMAT_LIST) / sizeof(AST_FORMAT_LIST[0]); x++) {
598 if(AST_FORMAT_LIST[x].visible && AST_FORMAT_LIST[x].bits == codec) {
599 ret = AST_FORMAT_LIST[x].desc;
606 static int show_codecs(int fd, int argc, char *argv[])
611 if ((argc < 2) || (argc > 3))
612 return RESULT_SHOWUSAGE;
614 if (!ast_opt_dont_warn)
615 ast_cli(fd, "Disclaimer: this command is for informational purposes only.\n"
616 "\tIt does not indicate anything about your configuration.\n");
618 ast_cli(fd, "%11s %9s %10s TYPE %5s %s\n","INT","BINARY","HEX","NAME","DESC");
619 ast_cli(fd, "--------------------------------------------------------------------------------\n");
620 if ((argc == 2) || (!strcasecmp(argv[1],"audio"))) {
623 snprintf(hex,25,"(0x%x)",1<<i);
624 ast_cli(fd, "%11u (1 << %2d) %10s audio %5s (%s)\n",1 << i,i,hex,ast_getformatname(1<<i),ast_codec2str(1<<i));
628 if ((argc == 2) || (!strcasecmp(argv[1],"image"))) {
630 for (i=16;i<18;i++) {
631 snprintf(hex,25,"(0x%x)",1<<i);
632 ast_cli(fd, "%11u (1 << %2d) %10s image %5s (%s)\n",1 << i,i,hex,ast_getformatname(1<<i),ast_codec2str(1<<i));
636 if ((argc == 2) || (!strcasecmp(argv[1],"video"))) {
638 for (i=18;i<22;i++) {
639 snprintf(hex,25,"(0x%x)",1<<i);
640 ast_cli(fd, "%11u (1 << %2d) %10s video %5s (%s)\n",1 << i,i,hex,ast_getformatname(1<<i),ast_codec2str(1<<i));
645 return RESULT_SHOWUSAGE;
647 return RESULT_SUCCESS;
650 static char frame_show_codecs_usage[] =
651 "Usage: show [audio|video|image] codecs\n"
652 " Displays codec mapping\n";
654 static int show_codec_n(int fd, int argc, char *argv[])
656 int codec, i, found=0;
659 return RESULT_SHOWUSAGE;
661 if (sscanf(argv[2],"%d",&codec) != 1)
662 return RESULT_SHOWUSAGE;
664 for (i = 0; i < 32; i++)
665 if (codec & (1 << i)) {
667 ast_cli(fd, "%11u (1 << %2d) %s\n",1 << i,i,ast_codec2str(1<<i));
671 ast_cli(fd, "Codec %d not found\n", codec);
673 return RESULT_SUCCESS;
676 static char frame_show_codec_n_usage[] =
677 "Usage: show codec <number>\n"
678 " Displays codec mapping\n";
680 /*! Dump a frame for debugging purposes */
681 void ast_frame_dump(const char *name, struct ast_frame *f, char *prefix)
683 const char noname[] = "unknown";
684 char ftype[40] = "Unknown Frametype";
686 char subclass[40] = "Unknown Subclass";
688 char moreinfo[40] = "";
698 ast_verbose("%s [ %s (NULL) ] [%s]\n",
699 term_color(cp, prefix, COLOR_BRMAGENTA, COLOR_BLACK, sizeof(cp)),
700 term_color(cft, "HANGUP", COLOR_BRRED, COLOR_BLACK, sizeof(cft)),
701 term_color(cn, name, COLOR_YELLOW, COLOR_BLACK, sizeof(cn)));
704 /* XXX We should probably print one each of voice and video when the format changes XXX */
705 if (f->frametype == AST_FRAME_VOICE)
707 if (f->frametype == AST_FRAME_VIDEO)
709 switch(f->frametype) {
711 strcpy(ftype, "DTMF");
712 subclass[0] = f->subclass;
715 case AST_FRAME_CONTROL:
716 strcpy(ftype, "Control");
717 switch(f->subclass) {
718 case AST_CONTROL_HANGUP:
719 strcpy(subclass, "Hangup");
721 case AST_CONTROL_RING:
722 strcpy(subclass, "Ring");
724 case AST_CONTROL_RINGING:
725 strcpy(subclass, "Ringing");
727 case AST_CONTROL_ANSWER:
728 strcpy(subclass, "Answer");
730 case AST_CONTROL_BUSY:
731 strcpy(subclass, "Busy");
733 case AST_CONTROL_TAKEOFFHOOK:
734 strcpy(subclass, "Take Off Hook");
736 case AST_CONTROL_OFFHOOK:
737 strcpy(subclass, "Line Off Hook");
739 case AST_CONTROL_CONGESTION:
740 strcpy(subclass, "Congestion");
742 case AST_CONTROL_FLASH:
743 strcpy(subclass, "Flash");
745 case AST_CONTROL_WINK:
746 strcpy(subclass, "Wink");
748 case AST_CONTROL_OPTION:
749 strcpy(subclass, "Option");
751 case AST_CONTROL_RADIO_KEY:
752 strcpy(subclass, "Key Radio");
754 case AST_CONTROL_RADIO_UNKEY:
755 strcpy(subclass, "Unkey Radio");
758 strcpy(subclass, "Stop generators");
761 snprintf(subclass, sizeof(subclass), "Unknown control '%d'", f->subclass);
765 strcpy(ftype, "Null Frame");
766 strcpy(subclass, "N/A");
769 /* Should never happen */
770 strcpy(ftype, "IAX Specific");
771 snprintf(subclass, sizeof(subclass), "IAX Frametype %d", f->subclass);
774 strcpy(ftype, "Text");
775 strcpy(subclass, "N/A");
776 ast_copy_string(moreinfo, f->data, sizeof(moreinfo));
778 case AST_FRAME_IMAGE:
779 strcpy(ftype, "Image");
780 snprintf(subclass, sizeof(subclass), "Image format %s\n", ast_getformatname(f->subclass));
783 strcpy(ftype, "HTML");
784 switch(f->subclass) {
786 strcpy(subclass, "URL");
787 ast_copy_string(moreinfo, f->data, sizeof(moreinfo));
790 strcpy(subclass, "Data");
793 strcpy(subclass, "Begin");
796 strcpy(subclass, "End");
798 case AST_HTML_LDCOMPLETE:
799 strcpy(subclass, "Load Complete");
801 case AST_HTML_NOSUPPORT:
802 strcpy(subclass, "No Support");
804 case AST_HTML_LINKURL:
805 strcpy(subclass, "Link URL");
806 ast_copy_string(moreinfo, f->data, sizeof(moreinfo));
808 case AST_HTML_UNLINK:
809 strcpy(subclass, "Unlink");
811 case AST_HTML_LINKREJECT:
812 strcpy(subclass, "Link Reject");
815 snprintf(subclass, sizeof(subclass), "Unknown HTML frame '%d'\n", f->subclass);
819 case AST_FRAME_MODEM:
820 strcpy(ftype, "Modem");
821 switch (f->subclass) {
823 strcpy(subclass, "T.38");
826 strcpy(subclass, "V.150");
829 snprintf(subclass, sizeof(subclass), "Unknown MODEM frame '%d'\n", f->subclass);
834 snprintf(ftype, sizeof(ftype), "Unknown Frametype '%d'", f->frametype);
836 if (!ast_strlen_zero(moreinfo))
837 ast_verbose("%s [ TYPE: %s (%d) SUBCLASS: %s (%d) '%s' ] [%s]\n",
838 term_color(cp, prefix, COLOR_BRMAGENTA, COLOR_BLACK, sizeof(cp)),
839 term_color(cft, ftype, COLOR_BRRED, COLOR_BLACK, sizeof(cft)),
841 term_color(csub, subclass, COLOR_BRCYAN, COLOR_BLACK, sizeof(csub)),
843 term_color(cmn, moreinfo, COLOR_BRGREEN, COLOR_BLACK, sizeof(cmn)),
844 term_color(cn, name, COLOR_YELLOW, COLOR_BLACK, sizeof(cn)));
846 ast_verbose("%s [ TYPE: %s (%d) SUBCLASS: %s (%d) ] [%s]\n",
847 term_color(cp, prefix, COLOR_BRMAGENTA, COLOR_BLACK, sizeof(cp)),
848 term_color(cft, ftype, COLOR_BRRED, COLOR_BLACK, sizeof(cft)),
850 term_color(csub, subclass, COLOR_BRCYAN, COLOR_BLACK, sizeof(csub)),
852 term_color(cn, name, COLOR_YELLOW, COLOR_BLACK, sizeof(cn)));
857 static int show_frame_stats(int fd, int argc, char *argv[])
862 return RESULT_SHOWUSAGE;
863 ast_cli(fd, " Framer Statistics \n");
864 ast_cli(fd, "---------------------------\n");
865 ast_cli(fd, "Total allocated headers: %d\n", headers);
866 ast_cli(fd, "Queue Dump:\n");
867 ast_mutex_lock(&framelock);
868 for (f=headerlist; f; f = f->next) {
869 ast_cli(fd, "%d. Type %d, subclass %d from %s\n", x++, f->frametype, f->subclass, f->src ? f->src : "<Unknown>");
871 ast_mutex_unlock(&framelock);
872 return RESULT_SUCCESS;
875 static char frame_stats_usage[] =
876 "Usage: show frame stats\n"
877 " Displays debugging statistics from framer\n";
880 /* Builtin Asterisk CLI-commands for debugging */
881 static struct ast_cli_entry my_clis[] = {
882 { { "show", "codecs", NULL }, show_codecs, "Shows codecs", frame_show_codecs_usage },
883 { { "show", "audio", "codecs", NULL }, show_codecs, "Shows audio codecs", frame_show_codecs_usage },
884 { { "show", "video", "codecs", NULL }, show_codecs, "Shows video codecs", frame_show_codecs_usage },
885 { { "show", "image", "codecs", NULL }, show_codecs, "Shows image codecs", frame_show_codecs_usage },
886 { { "show", "codec", NULL }, show_codec_n, "Shows a specific codec", frame_show_codec_n_usage },
888 { { "show", "frame", "stats", NULL }, show_frame_stats, "Shows frame statistics", frame_stats_usage },
892 int init_framer(void)
894 ast_cli_register_multiple(my_clis, sizeof(my_clis)/sizeof(my_clis[0]) );
898 void ast_codec_pref_convert(struct ast_codec_pref *pref, char *buf, size_t size, int right)
900 int x, differential = (int) 'A', mem;
914 for (x = 0; x < 32 ; x++) {
917 to[x] = right ? (from[x] + differential) : (from[x] - differential);
921 int ast_codec_pref_string(struct ast_codec_pref *pref, char *buf, size_t size)
924 size_t total_len, slen;
931 for(x = 0; x < 32 ; x++) {
934 if(!(codec = ast_codec_pref_index(pref,x)))
936 if((formatname = ast_getformatname(codec))) {
937 slen = strlen(formatname);
940 strncat(buf,formatname,total_len);
943 if(total_len && x < 31 && ast_codec_pref_index(pref , x + 1)) {
944 strncat(buf,"|",total_len);
949 strncat(buf,")",total_len);
953 return size - total_len;
956 int ast_codec_pref_index(struct ast_codec_pref *pref, int index)
961 if((index >= 0) && (index < sizeof(pref->order))) {
962 slot = pref->order[index];
965 return slot ? AST_FORMAT_LIST[slot-1].bits : 0;
968 /*! \brief Remove codec from pref list */
969 void ast_codec_pref_remove(struct ast_codec_pref *pref, int format)
971 struct ast_codec_pref oldorder;
978 memcpy(&oldorder, pref, sizeof(oldorder));
979 memset(pref, 0, sizeof(*pref));
981 for (x = 0; x < sizeof(AST_FORMAT_LIST) / sizeof(AST_FORMAT_LIST[0]); x++) {
982 slot = oldorder.order[x];
985 if(AST_FORMAT_LIST[slot-1].bits != format)
986 pref->order[y++] = slot;
991 /*! \brief Append codec to list */
992 int ast_codec_pref_append(struct ast_codec_pref *pref, int format)
994 int x, newindex = -1;
996 ast_codec_pref_remove(pref, format);
998 for (x = 0; x < sizeof(AST_FORMAT_LIST) / sizeof(AST_FORMAT_LIST[0]); x++) {
999 if(AST_FORMAT_LIST[x].bits == format) {
1006 for (x = 0; x < sizeof(AST_FORMAT_LIST) / sizeof(AST_FORMAT_LIST[0]); x++) {
1007 if(!pref->order[x]) {
1008 pref->order[x] = newindex;
1018 /*! \brief Pick a codec */
1019 int ast_codec_choose(struct ast_codec_pref *pref, int formats, int find_best)
1021 int x, ret = 0, slot;
1023 for (x = 0; x < sizeof(AST_FORMAT_LIST) / sizeof(AST_FORMAT_LIST[0]); x++) {
1024 slot = pref->order[x];
1028 if (formats & AST_FORMAT_LIST[slot-1].bits) {
1029 ret = AST_FORMAT_LIST[slot-1].bits;
1033 if(ret & AST_FORMAT_AUDIO_MASK)
1036 if (option_debug > 3)
1037 ast_log(LOG_DEBUG, "Could not find preferred codec - %s\n", find_best ? "Going for the best codec" : "Returning zero codec");
1039 return find_best ? ast_best_codec(formats) : 0;
1042 void ast_parse_allow_disallow(struct ast_codec_pref *pref, int *mask, const char *list, int allowing)
1048 parse = ast_strdupa(list);
1049 while ((this = strsep(&parse, ","))) {
1050 if (!(format = ast_getformatbyname(this))) {
1051 ast_log(LOG_WARNING, "Cannot %s unknown format '%s'\n", allowing ? "allow" : "disallow", this);
1062 /* Set up a preference list for audio. Do not include video in preferences
1063 since we can not transcode video and have to use whatever is offered
1065 if (pref && (format & AST_FORMAT_AUDIO_MASK)) {
1066 if (strcasecmp(this, "all")) {
1068 ast_codec_pref_append(pref, format);
1070 ast_codec_pref_remove(pref, format);
1071 } else if (!allowing) {
1072 memset(pref, 0, sizeof(*pref));
1078 static int g723_len(unsigned char buf)
1080 enum frame_type type = buf & TYPE_MASK;
1096 ast_log(LOG_WARNING, "Badly encoded frame (%d)\n", type);
1101 static int g723_samples(unsigned char *buf, int maxlen)
1106 while(pos < maxlen) {
1107 res = g723_len(buf[pos]);
1116 static unsigned char get_n_bits_at(unsigned char *data, int n, int bit)
1118 int byte = bit / 8; /* byte containing first bit */
1119 int rem = 8 - (bit % 8); /* remaining bits in first byte */
1120 unsigned char ret = 0;
1122 if (n <= 0 || n > 8)
1126 ret = (data[byte] << (n - rem));
1127 ret |= (data[byte + 1] >> (8 - n + rem));
1129 ret = (data[byte] >> (rem - n));
1132 return (ret & (0xff >> (8 - n)));
1135 static int speex_get_wb_sz_at(unsigned char *data, int len, int bit)
1137 static int SpeexWBSubModeSz[] = {
1143 /* skip up to two wideband frames */
1144 if (((len * 8 - off) >= 5) &&
1145 get_n_bits_at(data, 1, off)) {
1146 c = get_n_bits_at(data, 3, off + 1);
1147 off += SpeexWBSubModeSz[c];
1149 if (((len * 8 - off) >= 5) &&
1150 get_n_bits_at(data, 1, off)) {
1151 c = get_n_bits_at(data, 3, off + 1);
1152 off += SpeexWBSubModeSz[c];
1154 if (((len * 8 - off) >= 5) &&
1155 get_n_bits_at(data, 1, off)) {
1156 ast_log(LOG_WARNING, "Encountered corrupt speex frame; too many wideband frames in a row.\n");
1165 static int speex_samples(unsigned char *data, int len)
1167 static int SpeexSubModeSz[] = {
1172 static int SpeexInBandSz[] = {
1182 while ((len * 8 - bit) >= 5) {
1183 /* skip wideband frames */
1184 off = speex_get_wb_sz_at(data, len, bit);
1186 ast_log(LOG_WARNING, "Had error while reading wideband frames for speex samples\n");
1191 if ((len * 8 - bit) < 5) {
1192 ast_log(LOG_WARNING, "Not enough bits remaining after wide band for speex samples.\n");
1196 /* get control bits */
1197 c = get_n_bits_at(data, 5, bit);
1203 } else if (c == 14) {
1204 /* in-band signal; next 4 bits contain signal id */
1205 c = get_n_bits_at(data, 4, bit);
1207 bit += SpeexInBandSz[c];
1208 } else if (c == 13) {
1209 /* user in-band; next 5 bits contain msg len */
1210 c = get_n_bits_at(data, 5, bit);
1217 /* skip number bits for submode (less the 5 control bits) */
1218 bit += SpeexSubModeSz[c] - 5;
1219 cnt += 160; /* new frame */
1225 int ast_codec_get_samples(struct ast_frame *f)
1228 switch(f->subclass) {
1229 case AST_FORMAT_SPEEX:
1230 samples = speex_samples(f->data, f->datalen);
1232 case AST_FORMAT_G723_1:
1233 samples = g723_samples(f->data, f->datalen);
1235 case AST_FORMAT_ILBC:
1236 samples = 240 * (f->datalen / 50);
1238 case AST_FORMAT_GSM:
1239 samples = 160 * (f->datalen / 33);
1241 case AST_FORMAT_G729A:
1242 samples = f->datalen * 8;
1244 case AST_FORMAT_SLINEAR:
1245 samples = f->datalen / 2;
1247 case AST_FORMAT_LPC10:
1248 /* assumes that the RTP packet contains one LPC10 frame */
1250 samples += (((char *)(f->data))[7] & 0x1) * 8;
1252 case AST_FORMAT_ULAW:
1253 case AST_FORMAT_ALAW:
1254 samples = f->datalen;
1256 case AST_FORMAT_ADPCM:
1257 case AST_FORMAT_G726:
1258 samples = f->datalen * 2;
1261 ast_log(LOG_WARNING, "Unable to calculate samples for format %s\n", ast_getformatname(f->subclass));
1266 int ast_codec_get_len(int format, int samples)
1270 /* XXX Still need speex, g723, and lpc10 XXX */
1272 case AST_FORMAT_ILBC:
1273 len = (samples / 240) * 50;
1275 case AST_FORMAT_GSM:
1276 len = (samples / 160) * 33;
1278 case AST_FORMAT_G729A:
1281 case AST_FORMAT_SLINEAR:
1284 case AST_FORMAT_ULAW:
1285 case AST_FORMAT_ALAW:
1288 case AST_FORMAT_ADPCM:
1289 case AST_FORMAT_G726:
1293 ast_log(LOG_WARNING, "Unable to calculate sample length for format %s\n", ast_getformatname(format));
1299 int ast_frame_adjust_volume(struct ast_frame *f, int adjustment)
1302 short *fdata = f->data;
1303 short adjust_value = abs(adjustment);
1305 if ((f->frametype != AST_FRAME_VOICE) || (f->subclass != AST_FORMAT_SLINEAR))
1311 for (count = 0; count < f->samples; count++) {
1312 if (adjustment > 0) {
1313 ast_slinear_saturated_multiply(&fdata[count], &adjust_value);
1314 } else if (adjustment < 0) {
1315 ast_slinear_saturated_divide(&fdata[count], &adjust_value);
1322 int ast_frame_slinear_sum(struct ast_frame *f1, struct ast_frame *f2)
1325 short *data1, *data2;
1327 if ((f1->frametype != AST_FRAME_VOICE) || (f1->subclass != AST_FORMAT_SLINEAR))
1330 if ((f2->frametype != AST_FRAME_VOICE) || (f2->subclass != AST_FORMAT_SLINEAR))
1333 if (f1->samples != f2->samples)
1336 for (count = 0, data1 = f1->data, data2 = f2->data;
1337 count < f1->samples;
1338 count++, data1++, data2++)
1339 ast_slinear_saturated_add(data1, data2);
1344 struct ast_frame *ast_frame_enqueue(struct ast_frame *head, struct ast_frame *f, int maxlen, int dupe)
1346 struct ast_frame *cur, *oldhead;
1360 if (len >= maxlen) {
1363 ast_frfree(oldhead);