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 manipulation routines
23 * \author Mark Spencer <markster@digium.com>
34 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
[] = {
84 { 1, AST_FORMAT_G723_1
, "g723" , "G.723.1"}, /*!< codec_g723_1.c */
85 { 1, AST_FORMAT_GSM
, "gsm" , "GSM"}, /*!< codec_gsm.c */
86 { 1, AST_FORMAT_ULAW
, "ulaw", "G.711 u-law" }, /*!< codec_ulaw.c */
87 { 1, AST_FORMAT_ALAW
, "alaw", "G.711 A-law" }, /*!< codec_alaw.c */
88 { 1, AST_FORMAT_G726
, "g726", "G.726" }, /*!< codec_g726.c */
89 { 1, AST_FORMAT_ADPCM
, "adpcm" , "ADPCM"}, /*!< codec_adpcm.c */
90 { 1, AST_FORMAT_SLINEAR
, "slin", "16 bit Signed Linear PCM"}, /*!< */
91 { 1, AST_FORMAT_LPC10
, "lpc10", "LPC10" }, /*!< codec_lpc10.c */
92 { 1, AST_FORMAT_G729A
, "g729", "G.729A" }, /*!< Binary commercial distribution */
93 { 1, AST_FORMAT_SPEEX
, "speex", "SpeeX" }, /*!< codec_speex.c */
94 { 1, AST_FORMAT_ILBC
, "ilbc", "iLBC"}, /*!< 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"}, /*!< See format_jpeg.c */
101 { 1, AST_FORMAT_PNG
, "png", "PNG image"}, /*!< Image format */
102 { 1, AST_FORMAT_H261
, "h261", "H.261 Video" }, /*!< Passthrough */
103 { 1, AST_FORMAT_H263
, "h263", "H.263 Video" }, /*!< Passthrough support, see format_h263.c */
104 { 1, AST_FORMAT_H263_PLUS
, "h263p", "H.263+ Video" }, /*!< See format_h263.c */
105 { 1, AST_FORMAT_H264
, "h264", "H.264 Video" }, /*!< 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
;
201 /* IF we have an optimization frame, send it */
203 if (s
->opt
->offset
< AST_FRIENDLY_OFFSET
)
204 ast_log(LOG_WARNING
, "Returning a frame of inappropriate offset (%d).",
211 /* Make sure we have enough data */
212 if (s
->len
< s
->size
) {
213 /* Or, if this is a G.729 frame with VAD on it, send it immediately anyway */
214 if (!((s
->flags
& AST_SMOOTHER_FLAG_G729
) && (s
->size
% 10)))
221 s
->f
.frametype
= AST_FRAME_VOICE
;
222 s
->f
.subclass
= s
->format
;
223 s
->f
.data
= s
->framedata
+ AST_FRIENDLY_OFFSET
;
224 s
->f
.offset
= AST_FRIENDLY_OFFSET
;
226 /* Samples will be improper given VAD, but with VAD the concept really doesn't even exist */
227 s
->f
.samples
= len
* s
->samplesperbyte
; /* XXX rounding */
228 s
->f
.delivery
= s
->delivery
;
230 memcpy(s
->f
.data
, s
->data
, len
);
232 /* Move remaining data to the front if applicable */
234 /* In principle this should all be fine because if we are sending
235 G.729 VAD, the next timestamp will take over anyawy */
236 memmove(s
->data
, s
->data
+ len
, s
->len
);
237 if (!ast_tvzero(s
->delivery
)) {
238 /* If we have delivery time, increment it, otherwise, leave it at 0 */
239 s
->delivery
= ast_tvadd(s
->delivery
, ast_samp2tv(s
->f
.samples
, 8000));
246 void ast_smoother_free(struct ast_smoother
*s
)
251 static struct ast_frame
*ast_frame_header_new(void)
253 struct ast_frame
*f
= ast_calloc(1, sizeof(*f
));
258 ast_mutex_lock(&framelock
);
259 f
->next
= headerlist
;
261 headerlist
->prev
= f
;
263 ast_mutex_unlock(&framelock
);
270 * \todo Important: I should be made more efficient. Frame headers should
271 * most definitely be cached
273 void ast_frfree(struct ast_frame
*fr
)
275 if (fr
->mallocd
& AST_MALLOCD_DATA
) {
277 free(fr
->data
- fr
->offset
);
279 if (fr
->mallocd
& AST_MALLOCD_SRC
) {
281 free((char *)fr
->src
);
283 if (fr
->mallocd
& AST_MALLOCD_HDR
) {
286 ast_mutex_lock(&framelock
);
288 fr
->next
->prev
= fr
->prev
;
290 fr
->prev
->next
= fr
->next
;
292 headerlist
= fr
->next
;
293 ast_mutex_unlock(&framelock
);
300 * \brief 'isolates' a frame by duplicating non-malloc'ed components
301 * (header, src, data).
302 * On return all components are malloc'ed
304 struct ast_frame
*ast_frisolate(struct ast_frame
*fr
)
306 struct ast_frame
*out
;
309 if (!(fr
->mallocd
& AST_MALLOCD_HDR
)) {
310 /* Allocate a new header if needed */
311 if (!(out
= ast_frame_header_new()))
313 out
->frametype
= fr
->frametype
;
314 out
->subclass
= fr
->subclass
;
315 out
->datalen
= fr
->datalen
;
316 out
->samples
= fr
->samples
;
317 out
->offset
= fr
->offset
;
318 out
->data
= fr
->data
;
322 if (!(fr
->mallocd
& AST_MALLOCD_SRC
)) {
324 out
->src
= strdup(fr
->src
);
328 if (!(fr
->mallocd
& AST_MALLOCD_DATA
)) {
329 if (!(newdata
= ast_malloc(fr
->datalen
+ AST_FRIENDLY_OFFSET
))) {
333 newdata
+= AST_FRIENDLY_OFFSET
;
334 out
->offset
= AST_FRIENDLY_OFFSET
;
335 out
->datalen
= fr
->datalen
;
336 memcpy(newdata
, fr
->data
, fr
->datalen
);
340 out
->mallocd
= AST_MALLOCD_HDR
| AST_MALLOCD_SRC
| AST_MALLOCD_DATA
;
345 struct ast_frame
*ast_frdup(struct ast_frame
*f
)
347 struct ast_frame
*out
;
350 /* Start with standard stuff */
351 len
= sizeof(*out
) + AST_FRIENDLY_OFFSET
+ f
->datalen
;
352 /* If we have a source, add space for it */
354 * XXX Watch out here - if we receive a src which is not terminated
355 * properly, we can be easily attacked. Should limit the size we deal with.
358 srclen
= strlen(f
->src
);
361 if (!(buf
= ast_malloc(len
)))
364 /* Set us as having malloc'd header only, so it will eventually
366 out
->frametype
= f
->frametype
;
367 out
->subclass
= f
->subclass
;
368 out
->datalen
= f
->datalen
;
369 out
->samples
= f
->samples
;
370 out
->delivery
= f
->delivery
;
371 out
->mallocd
= AST_MALLOCD_HDR
;
372 out
->offset
= AST_FRIENDLY_OFFSET
;
373 out
->data
= buf
+ sizeof(*out
) + AST_FRIENDLY_OFFSET
;
375 out
->src
= out
->data
+ f
->datalen
;
376 /* Must have space since we allocated for it */
377 strcpy((char *)out
->src
, f
->src
);
382 memcpy(out
->data
, f
->data
, out
->datalen
);
389 * This function is badly broken - it does not handle correctly
390 * partial reads on either header or body.
391 * However is it never used anywhere so we leave it commented out
393 struct ast_frame
*ast_fr_fdread(int fd
)
397 struct ast_frame
*f
= (struct ast_frame
*)buf
;
398 int ttl
= sizeof(*f
);
399 /* Read a frame directly from there. They're always in the
403 res
= read(fd
, buf
, ttl
);
405 ast_log(LOG_WARNING
, "Bad read on %d: %s\n", fd
, strerror(errno
));
411 /* read the frame header */
413 /* Re-write data position */
414 f
->data
= buf
+ sizeof(*f
);
416 /* Forget about being mallocd */
418 /* Re-write the source */
419 f
->src
= (char *)__FUNCTION__
;
420 if (f
->datalen
> sizeof(buf
) - sizeof(*f
)) {
421 /* Really bad read */
422 ast_log(LOG_WARNING
, "Strange read (%d bytes)\n", f
->datalen
);
426 if ((res
= read(fd
, f
->data
, f
->datalen
)) != f
->datalen
) {
428 ast_log(LOG_WARNING
, "How very strange, expected %d, got %d\n", f
->datalen
, res
);
432 if ((f
->frametype
== AST_FRAME_CONTROL
) && (f
->subclass
== AST_CONTROL_HANGUP
)) {
435 return ast_frisolate(f
);
438 /* Some convenient routines for sending frames to/from stream or datagram
439 sockets, pipes, etc (maybe even files) */
442 * XXX this function is also partly broken because it does not handle
443 * partial writes. We comment it out too, and also the unique
444 * client it has, ast_fr_fdhangup()
446 int ast_fr_fdwrite(int fd
, struct ast_frame
*frame
)
448 /* Write the frame exactly */
449 if (write(fd
, frame
, sizeof(*frame
)) != sizeof(*frame
)) {
450 ast_log(LOG_WARNING
, "Write error: %s\n", strerror(errno
));
453 if (write(fd
, frame
->data
, frame
->datalen
) != frame
->datalen
) {
454 ast_log(LOG_WARNING
, "Write error: %s\n", strerror(errno
));
460 int ast_fr_fdhangup(int fd
)
462 struct ast_frame hangup
= {
466 return ast_fr_fdwrite(fd
, &hangup
);
469 #endif /* unused functions */
470 void ast_swapcopy_samples(void *dst
, const void *src
, int samples
)
473 unsigned short *dst_s
= dst
;
474 const unsigned short *src_s
= src
;
476 for (i
=0; i
<samples
; i
++)
477 dst_s
[i
] = (src_s
[i
]<<8) | (src_s
[i
]>>8);
481 struct ast_format_list
*ast_get_format_list_index(int index
)
483 return &AST_FORMAT_LIST
[index
];
486 struct ast_format_list
*ast_get_format_list(size_t *size
)
488 *size
= (sizeof(AST_FORMAT_LIST
) / sizeof(AST_FORMAT_LIST
[0]));
489 return AST_FORMAT_LIST
;
492 char* ast_getformatname(int format
)
495 char *ret
= "unknown";
496 for (x
= 0; x
< sizeof(AST_FORMAT_LIST
) / sizeof(AST_FORMAT_LIST
[0]); x
++) {
497 if(AST_FORMAT_LIST
[x
].visible
&& AST_FORMAT_LIST
[x
].bits
== format
) {
498 ret
= AST_FORMAT_LIST
[x
].name
;
505 char *ast_getformatname_multiple(char *buf
, size_t size
, int format
) {
509 char *start
, *end
= buf
;
510 if (!size
) return buf
;
511 snprintf(end
, size
, "0x%x (", format
);
516 for (x
= 0; x
< sizeof(AST_FORMAT_LIST
) / sizeof(AST_FORMAT_LIST
[0]); x
++) {
517 if (AST_FORMAT_LIST
[x
].visible
&& (AST_FORMAT_LIST
[x
].bits
& format
)) {
518 snprintf(end
, size
,"%s|",AST_FORMAT_LIST
[x
].name
);
525 snprintf(start
, size
, "nothing)");
531 static struct ast_codec_alias_table
{
535 } ast_codec_alias_table
[] = {
540 static const char *ast_expand_codec_alias(const char *in
) {
543 for (x
= 0; x
< sizeof(ast_codec_alias_table
) / sizeof(ast_codec_alias_table
[0]); x
++) {
544 if(!strcmp(in
,ast_codec_alias_table
[x
].alias
))
545 return ast_codec_alias_table
[x
].realname
;
550 int ast_getformatbyname(const char *name
)
552 int x
, all
, format
= 0;
554 all
= strcasecmp(name
, "all") ? 0 : 1;
555 for (x
= 0; x
< sizeof(AST_FORMAT_LIST
) / sizeof(AST_FORMAT_LIST
[0]); x
++) {
556 if(AST_FORMAT_LIST
[x
].visible
&& (all
||
557 !strcasecmp(AST_FORMAT_LIST
[x
].name
,name
) ||
558 !strcasecmp(AST_FORMAT_LIST
[x
].name
,ast_expand_codec_alias(name
)))) {
559 format
|= AST_FORMAT_LIST
[x
].bits
;
568 char *ast_codec2str(int codec
) {
570 char *ret
= "unknown";
571 for (x
= 0; x
< sizeof(AST_FORMAT_LIST
) / sizeof(AST_FORMAT_LIST
[0]); x
++) {
572 if(AST_FORMAT_LIST
[x
].visible
&& AST_FORMAT_LIST
[x
].bits
== codec
) {
573 ret
= AST_FORMAT_LIST
[x
].desc
;
580 static int show_codecs(int fd
, int argc
, char *argv
[])
585 if ((argc
< 2) || (argc
> 3))
586 return RESULT_SHOWUSAGE
;
588 if (!ast_opt_dont_warn
)
589 ast_cli(fd
, "Disclaimer: this command is for informational purposes only.\n"
590 "\tIt does not indicate anything about your configuration.\n");
592 ast_cli(fd
, "%11s %9s %10s TYPE %5s %s\n","INT","BINARY","HEX","NAME","DESC");
593 ast_cli(fd
, "--------------------------------------------------------------------------------\n");
594 if ((argc
== 2) || (!strcasecmp(argv
[1],"audio"))) {
597 snprintf(hex
,25,"(0x%x)",1<<i
);
598 ast_cli(fd
, "%11u (1 << %2d) %10s audio %5s (%s)\n",1 << i
,i
,hex
,ast_getformatname(1<<i
),ast_codec2str(1<<i
));
602 if ((argc
== 2) || (!strcasecmp(argv
[1],"image"))) {
604 for (i
=16;i
<18;i
++) {
605 snprintf(hex
,25,"(0x%x)",1<<i
);
606 ast_cli(fd
, "%11u (1 << %2d) %10s image %5s (%s)\n",1 << i
,i
,hex
,ast_getformatname(1<<i
),ast_codec2str(1<<i
));
610 if ((argc
== 2) || (!strcasecmp(argv
[1],"video"))) {
612 for (i
=18;i
<21;i
++) {
613 snprintf(hex
,25,"(0x%x)",1<<i
);
614 ast_cli(fd
, "%11u (1 << %2d) %10s video %5s (%s)\n",1 << i
,i
,hex
,ast_getformatname(1<<i
),ast_codec2str(1<<i
));
619 return RESULT_SHOWUSAGE
;
621 return RESULT_SUCCESS
;
624 static char frame_show_codecs_usage
[] =
625 "Usage: show [audio|video|image] codecs\n"
626 " Displays codec mapping\n";
628 static int show_codec_n(int fd
, int argc
, char *argv
[])
630 int codec
, i
, found
=0;
633 return RESULT_SHOWUSAGE
;
635 if (sscanf(argv
[2],"%d",&codec
) != 1)
636 return RESULT_SHOWUSAGE
;
639 if (codec
& (1 << i
)) {
641 ast_cli(fd
, "%11u (1 << %2d) %s\n",1 << i
,i
,ast_codec2str(1<<i
));
645 ast_cli(fd
, "Codec %d not found\n", codec
);
647 return RESULT_SUCCESS
;
650 static char frame_show_codec_n_usage
[] =
651 "Usage: show codec <number>\n"
652 " Displays codec mapping\n";
654 /*! Dump a frame for debugging purposes */
655 void ast_frame_dump(const char *name
, struct ast_frame
*f
, char *prefix
)
657 const char noname
[] = "unknown";
658 char ftype
[40] = "Unknown Frametype";
660 char subclass
[40] = "Unknown Subclass";
662 char moreinfo
[40] = "";
672 ast_verbose("%s [ %s (NULL) ] [%s]\n",
673 term_color(cp
, prefix
, COLOR_BRMAGENTA
, COLOR_BLACK
, sizeof(cp
)),
674 term_color(cft
, "HANGUP", COLOR_BRRED
, COLOR_BLACK
, sizeof(cft
)),
675 term_color(cn
, name
, COLOR_YELLOW
, COLOR_BLACK
, sizeof(cn
)));
678 /* XXX We should probably print one each of voice and video when the format changes XXX */
679 if (f
->frametype
== AST_FRAME_VOICE
)
681 if (f
->frametype
== AST_FRAME_VIDEO
)
683 switch(f
->frametype
) {
685 strcpy(ftype
, "DTMF");
686 subclass
[0] = f
->subclass
;
689 case AST_FRAME_CONTROL
:
690 strcpy(ftype
, "Control");
691 switch(f
->subclass
) {
692 case AST_CONTROL_HANGUP
:
693 strcpy(subclass
, "Hangup");
695 case AST_CONTROL_RING
:
696 strcpy(subclass
, "Ring");
698 case AST_CONTROL_RINGING
:
699 strcpy(subclass
, "Ringing");
701 case AST_CONTROL_ANSWER
:
702 strcpy(subclass
, "Answer");
704 case AST_CONTROL_BUSY
:
705 strcpy(subclass
, "Busy");
707 case AST_CONTROL_TAKEOFFHOOK
:
708 strcpy(subclass
, "Take Off Hook");
710 case AST_CONTROL_OFFHOOK
:
711 strcpy(subclass
, "Line Off Hook");
713 case AST_CONTROL_CONGESTION
:
714 strcpy(subclass
, "Congestion");
716 case AST_CONTROL_FLASH
:
717 strcpy(subclass
, "Flash");
719 case AST_CONTROL_WINK
:
720 strcpy(subclass
, "Wink");
722 case AST_CONTROL_OPTION
:
723 strcpy(subclass
, "Option");
725 case AST_CONTROL_RADIO_KEY
:
726 strcpy(subclass
, "Key Radio");
728 case AST_CONTROL_RADIO_UNKEY
:
729 strcpy(subclass
, "Unkey Radio");
732 strcpy(subclass
, "Stop generators");
735 snprintf(subclass
, sizeof(subclass
), "Unknown control '%d'", f
->subclass
);
739 strcpy(ftype
, "Null Frame");
740 strcpy(subclass
, "N/A");
743 /* Should never happen */
744 strcpy(ftype
, "IAX Specific");
745 snprintf(subclass
, sizeof(subclass
), "IAX Frametype %d", f
->subclass
);
748 strcpy(ftype
, "Text");
749 strcpy(subclass
, "N/A");
750 ast_copy_string(moreinfo
, f
->data
, sizeof(moreinfo
));
752 case AST_FRAME_IMAGE
:
753 strcpy(ftype
, "Image");
754 snprintf(subclass
, sizeof(subclass
), "Image format %s\n", ast_getformatname(f
->subclass
));
757 strcpy(ftype
, "HTML");
758 switch(f
->subclass
) {
760 strcpy(subclass
, "URL");
761 ast_copy_string(moreinfo
, f
->data
, sizeof(moreinfo
));
764 strcpy(subclass
, "Data");
767 strcpy(subclass
, "Begin");
770 strcpy(subclass
, "End");
772 case AST_HTML_LDCOMPLETE
:
773 strcpy(subclass
, "Load Complete");
775 case AST_HTML_NOSUPPORT
:
776 strcpy(subclass
, "No Support");
778 case AST_HTML_LINKURL
:
779 strcpy(subclass
, "Link URL");
780 ast_copy_string(moreinfo
, f
->data
, sizeof(moreinfo
));
782 case AST_HTML_UNLINK
:
783 strcpy(subclass
, "Unlink");
785 case AST_HTML_LINKREJECT
:
786 strcpy(subclass
, "Link Reject");
789 snprintf(subclass
, sizeof(subclass
), "Unknown HTML frame '%d'\n", f
->subclass
);
794 snprintf(ftype
, sizeof(ftype
), "Unknown Frametype '%d'", f
->frametype
);
796 if (!ast_strlen_zero(moreinfo
))
797 ast_verbose("%s [ TYPE: %s (%d) SUBCLASS: %s (%d) '%s' ] [%s]\n",
798 term_color(cp
, prefix
, COLOR_BRMAGENTA
, COLOR_BLACK
, sizeof(cp
)),
799 term_color(cft
, ftype
, COLOR_BRRED
, COLOR_BLACK
, sizeof(cft
)),
801 term_color(csub
, subclass
, COLOR_BRCYAN
, COLOR_BLACK
, sizeof(csub
)),
803 term_color(cmn
, moreinfo
, COLOR_BRGREEN
, COLOR_BLACK
, sizeof(cmn
)),
804 term_color(cn
, name
, COLOR_YELLOW
, COLOR_BLACK
, sizeof(cn
)));
806 ast_verbose("%s [ TYPE: %s (%d) SUBCLASS: %s (%d) ] [%s]\n",
807 term_color(cp
, prefix
, COLOR_BRMAGENTA
, COLOR_BLACK
, sizeof(cp
)),
808 term_color(cft
, ftype
, COLOR_BRRED
, COLOR_BLACK
, sizeof(cft
)),
810 term_color(csub
, subclass
, COLOR_BRCYAN
, COLOR_BLACK
, sizeof(csub
)),
812 term_color(cn
, name
, COLOR_YELLOW
, COLOR_BLACK
, sizeof(cn
)));
817 static int show_frame_stats(int fd
, int argc
, char *argv
[])
822 return RESULT_SHOWUSAGE
;
823 ast_cli(fd
, " Framer Statistics \n");
824 ast_cli(fd
, "---------------------------\n");
825 ast_cli(fd
, "Total allocated headers: %d\n", headers
);
826 ast_cli(fd
, "Queue Dump:\n");
827 ast_mutex_lock(&framelock
);
828 for (f
=headerlist
; f
; f
= f
->next
) {
829 ast_cli(fd
, "%d. Type %d, subclass %d from %s\n", x
++, f
->frametype
, f
->subclass
, f
->src
? f
->src
: "<Unknown>");
831 ast_mutex_unlock(&framelock
);
832 return RESULT_SUCCESS
;
835 static char frame_stats_usage
[] =
836 "Usage: show frame stats\n"
837 " Displays debugging statistics from framer\n";
840 /* Builtin Asterisk CLI-commands for debugging */
841 static struct ast_cli_entry my_clis
[] = {
842 { { "show", "codecs", NULL
}, show_codecs
, "Shows codecs", frame_show_codecs_usage
},
843 { { "show", "audio", "codecs", NULL
}, show_codecs
, "Shows audio codecs", frame_show_codecs_usage
},
844 { { "show", "video", "codecs", NULL
}, show_codecs
, "Shows video codecs", frame_show_codecs_usage
},
845 { { "show", "image", "codecs", NULL
}, show_codecs
, "Shows image codecs", frame_show_codecs_usage
},
846 { { "show", "codec", NULL
}, show_codec_n
, "Shows a specific codec", frame_show_codec_n_usage
},
848 { { "show", "frame", "stats", NULL
}, show_frame_stats
, "Shows frame statistics", frame_stats_usage
},
852 int init_framer(void)
854 ast_cli_register_multiple(my_clis
, sizeof(my_clis
)/sizeof(my_clis
[0]) );
858 void ast_codec_pref_convert(struct ast_codec_pref
*pref
, char *buf
, size_t size
, int right
)
860 int x
, differential
= (int) 'A', mem
;
874 for (x
= 0; x
< 32 ; x
++) {
877 to
[x
] = right
? (from
[x
] + differential
) : (from
[x
] - differential
);
881 int ast_codec_pref_string(struct ast_codec_pref
*pref
, char *buf
, size_t size
)
884 size_t total_len
, slen
;
891 for(x
= 0; x
< 32 ; x
++) {
894 if(!(codec
= ast_codec_pref_index(pref
,x
)))
896 if((formatname
= ast_getformatname(codec
))) {
897 slen
= strlen(formatname
);
900 strncat(buf
,formatname
,total_len
);
903 if(total_len
&& x
< 31 && ast_codec_pref_index(pref
, x
+ 1)) {
904 strncat(buf
,"|",total_len
);
909 strncat(buf
,")",total_len
);
913 return size
- total_len
;
916 int ast_codec_pref_index(struct ast_codec_pref
*pref
, int index
)
921 if((index
>= 0) && (index
< sizeof(pref
->order
))) {
922 slot
= pref
->order
[index
];
925 return slot
? AST_FORMAT_LIST
[slot
-1].bits
: 0;
928 /*! \brief ast_codec_pref_remove: Remove codec from pref list ---*/
929 void ast_codec_pref_remove(struct ast_codec_pref
*pref
, int format
)
931 struct ast_codec_pref oldorder
;
938 memcpy(&oldorder
, pref
, sizeof(oldorder
));
939 memset(pref
, 0, sizeof(*pref
));
941 for (x
= 0; x
< sizeof(AST_FORMAT_LIST
) / sizeof(AST_FORMAT_LIST
[0]); x
++) {
942 slot
= oldorder
.order
[x
];
945 if(AST_FORMAT_LIST
[slot
-1].bits
!= format
)
946 pref
->order
[y
++] = slot
;
951 /*! \brief ast_codec_pref_append: Append codec to list ---*/
952 int ast_codec_pref_append(struct ast_codec_pref
*pref
, int format
)
954 int x
, newindex
= -1;
956 ast_codec_pref_remove(pref
, format
);
958 for (x
= 0; x
< sizeof(AST_FORMAT_LIST
) / sizeof(AST_FORMAT_LIST
[0]); x
++) {
959 if(AST_FORMAT_LIST
[x
].bits
== format
) {
966 for (x
= 0; x
< sizeof(AST_FORMAT_LIST
) / sizeof(AST_FORMAT_LIST
[0]); x
++) {
967 if(!pref
->order
[x
]) {
968 pref
->order
[x
] = newindex
;
978 /*! \brief ast_codec_choose: Pick a codec ---*/
979 int ast_codec_choose(struct ast_codec_pref
*pref
, int formats
, int find_best
)
981 int x
, ret
= 0, slot
;
983 for (x
= 0; x
< sizeof(AST_FORMAT_LIST
) / sizeof(AST_FORMAT_LIST
[0]); x
++) {
984 slot
= pref
->order
[x
];
988 if ( formats
& AST_FORMAT_LIST
[slot
-1].bits
) {
989 ret
= AST_FORMAT_LIST
[slot
-1].bits
;
996 return find_best
? ast_best_codec(formats
) : 0;
999 void ast_parse_allow_disallow(struct ast_codec_pref
*pref
, int *mask
, const char *list
, int allowing
)
1005 parse
= ast_strdupa(list
);
1006 while ((this = strsep(&parse
, ","))) {
1007 if (!(format
= ast_getformatbyname(this))) {
1008 ast_log(LOG_WARNING
, "Cannot %s unknown format '%s'\n", allowing
? "allow" : "disallow", this);
1020 if (strcasecmp(this, "all")) {
1022 ast_codec_pref_append(pref
, format
);
1024 ast_codec_pref_remove(pref
, format
);
1025 } else if (!allowing
) {
1026 memset(pref
, 0, sizeof(*pref
));
1032 static int g723_len(unsigned char buf
)
1034 enum frame_type type
= buf
& TYPE_MASK
;
1050 ast_log(LOG_WARNING
, "Badly encoded frame (%d)\n", type
);
1055 static int g723_samples(unsigned char *buf
, int maxlen
)
1060 while(pos
< maxlen
) {
1061 res
= g723_len(buf
[pos
]);
1070 static unsigned char get_n_bits_at(unsigned char *data
, int n
, int bit
)
1072 int byte
= bit
/ 8; /* byte containing first bit */
1073 int rem
= 8 - (bit
% 8); /* remaining bits in first byte */
1074 unsigned char ret
= 0;
1076 if (n
<= 0 || n
> 8)
1080 ret
= (data
[byte
] << (n
- rem
));
1081 ret
|= (data
[byte
+ 1] >> (8 - n
+ rem
));
1083 ret
= (data
[byte
] >> (rem
- n
));
1086 return (ret
& (0xff >> (8 - n
)));
1089 static int speex_get_wb_sz_at(unsigned char *data
, int len
, int bit
)
1091 static int SpeexWBSubModeSz
[] = {
1097 /* skip up to two wideband frames */
1098 if (((len
* 8 - off
) >= 5) &&
1099 get_n_bits_at(data
, 1, off
)) {
1100 c
= get_n_bits_at(data
, 3, off
+ 1);
1101 off
+= SpeexWBSubModeSz
[c
];
1103 if (((len
* 8 - off
) >= 5) &&
1104 get_n_bits_at(data
, 1, off
)) {
1105 c
= get_n_bits_at(data
, 3, off
+ 1);
1106 off
+= SpeexWBSubModeSz
[c
];
1108 if (((len
* 8 - off
) >= 5) &&
1109 get_n_bits_at(data
, 1, off
)) {
1110 ast_log(LOG_WARNING
, "Encountered corrupt speex frame; too many wideband frames in a row.\n");
1119 static int speex_samples(unsigned char *data
, int len
)
1121 static int SpeexSubModeSz
[] = {
1126 static int SpeexInBandSz
[] = {
1136 while ((len
* 8 - bit
) >= 5) {
1137 /* skip wideband frames */
1138 off
= speex_get_wb_sz_at(data
, len
, bit
);
1140 ast_log(LOG_WARNING
, "Had error while reading wideband frames for speex samples\n");
1145 if ((len
* 8 - bit
) < 5) {
1146 ast_log(LOG_WARNING
, "Not enough bits remaining after wide band for speex samples.\n");
1150 /* get control bits */
1151 c
= get_n_bits_at(data
, 5, bit
);
1157 } else if (c
== 14) {
1158 /* in-band signal; next 4 bits contain signal id */
1159 c
= get_n_bits_at(data
, 4, bit
);
1161 bit
+= SpeexInBandSz
[c
];
1162 } else if (c
== 13) {
1163 /* user in-band; next 5 bits contain msg len */
1164 c
= get_n_bits_at(data
, 5, bit
);
1171 /* skip number bits for submode (less the 5 control bits) */
1172 bit
+= SpeexSubModeSz
[c
] - 5;
1173 cnt
+= 160; /* new frame */
1179 int ast_codec_get_samples(struct ast_frame
*f
)
1182 switch(f
->subclass
) {
1183 case AST_FORMAT_SPEEX
:
1184 samples
= speex_samples(f
->data
, f
->datalen
);
1186 case AST_FORMAT_G723_1
:
1187 samples
= g723_samples(f
->data
, f
->datalen
);
1189 case AST_FORMAT_ILBC
:
1190 samples
= 240 * (f
->datalen
/ 50);
1192 case AST_FORMAT_GSM
:
1193 samples
= 160 * (f
->datalen
/ 33);
1195 case AST_FORMAT_G729A
:
1196 samples
= f
->datalen
* 8;
1198 case AST_FORMAT_SLINEAR
:
1199 samples
= f
->datalen
/ 2;
1201 case AST_FORMAT_LPC10
:
1202 /* assumes that the RTP packet contains one LPC10 frame */
1204 samples
+= (((char *)(f
->data
))[7] & 0x1) * 8;
1206 case AST_FORMAT_ULAW
:
1207 case AST_FORMAT_ALAW
:
1208 samples
= f
->datalen
;
1210 case AST_FORMAT_ADPCM
:
1211 case AST_FORMAT_G726
:
1212 samples
= f
->datalen
* 2;
1215 ast_log(LOG_WARNING
, "Unable to calculate samples for format %s\n", ast_getformatname(f
->subclass
));
1220 int ast_codec_get_len(int format
, int samples
)
1224 /* XXX Still need speex, g723, and lpc10 XXX */
1226 case AST_FORMAT_ILBC
:
1227 len
= (samples
/ 240) * 50;
1229 case AST_FORMAT_GSM
:
1230 len
= (samples
/ 160) * 33;
1232 case AST_FORMAT_G729A
:
1235 case AST_FORMAT_SLINEAR
:
1238 case AST_FORMAT_ULAW
:
1239 case AST_FORMAT_ALAW
:
1242 case AST_FORMAT_ADPCM
:
1243 case AST_FORMAT_G726
:
1247 ast_log(LOG_WARNING
, "Unable to calculate sample length for format %s\n", ast_getformatname(format
));
1253 int ast_frame_adjust_volume(struct ast_frame
*f
, int adjustment
)
1256 short *fdata
= f
->data
;
1257 short adjust_value
= abs(adjustment
);
1259 if ((f
->frametype
!= AST_FRAME_VOICE
) || (f
->subclass
!= AST_FORMAT_SLINEAR
))
1265 for (count
= 0; count
< f
->samples
; count
++) {
1266 if (adjustment
> 0) {
1267 ast_slinear_saturated_multiply(&fdata
[count
], &adjust_value
);
1268 } else if (adjustment
< 0) {
1269 ast_slinear_saturated_divide(&fdata
[count
], &adjust_value
);
1276 int ast_frame_slinear_sum(struct ast_frame
*f1
, struct ast_frame
*f2
)
1279 short *data1
, *data2
;
1281 if ((f1
->frametype
!= AST_FRAME_VOICE
) || (f1
->subclass
!= AST_FORMAT_SLINEAR
))
1284 if ((f2
->frametype
!= AST_FRAME_VOICE
) || (f2
->subclass
!= AST_FORMAT_SLINEAR
))
1287 if (f1
->samples
!= f2
->samples
)
1290 for (count
= 0, data1
= f1
->data
, data2
= f2
->data
;
1291 count
< f1
->samples
;
1292 count
++, data1
++, data2
++)
1293 ast_slinear_saturated_add(data1
, data2
);
1298 struct ast_frame
*ast_frame_enqueue(struct ast_frame
*head
, struct ast_frame
*f
, int maxlen
, int dupe
)
1300 struct ast_frame
*cur
, *oldhead
;
1314 if (len
>= maxlen
) {
1317 ast_frfree(oldhead
);