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 */
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 RFC3551" },/*!< 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 { 1, AST_FORMAT_G726_AAL2
, "g726aal2", "G.726 AAL2" }, /*!< 12: codec_g726.c */
96 { 0, 0, "nothing", "undefined" },
97 { 0, 0, "nothing", "undefined" },
98 { 0, 0, "nothing", "undefined" },
99 { 0, 0, "nothing", "undefined" },
100 { 0, AST_FORMAT_MAX_AUDIO
, "maxaudio", "Maximum audio format" },
101 { 1, AST_FORMAT_JPEG
, "jpeg", "JPEG image"}, /*!< 17: See format_jpeg.c */
102 { 1, AST_FORMAT_PNG
, "png", "PNG image"}, /*!< 18: Image format */
103 { 1, AST_FORMAT_H261
, "h261", "H.261 Video" }, /*!< 19: Video Passthrough */
104 { 1, AST_FORMAT_H263
, "h263", "H.263 Video" }, /*!< 20: Passthrough support, see format_h263.c */
105 { 1, AST_FORMAT_H263_PLUS
, "h263p", "H.263+ Video" }, /*!< 21: See format_h263.c */
106 { 1, AST_FORMAT_H264
, "h264", "H.264 Video" }, /*!< 22: Passthrough support, see format_h263.c */
107 { 0, 0, "nothing", "undefined" },
108 { 0, 0, "nothing", "undefined" },
109 { 0, 0, "nothing", "undefined" },
110 { 0, AST_FORMAT_MAX_VIDEO
, "maxvideo", "Maximum video format" },
113 struct ast_frame ast_null_frame
= { AST_FRAME_NULL
, };
115 void ast_smoother_reset(struct ast_smoother
*s
, int size
)
117 memset(s
, 0, sizeof(*s
));
121 struct ast_smoother
*ast_smoother_new(int size
)
123 struct ast_smoother
*s
;
126 if ((s
= ast_malloc(sizeof(*s
))))
127 ast_smoother_reset(s
, size
);
131 int ast_smoother_get_flags(struct ast_smoother
*s
)
136 void ast_smoother_set_flags(struct ast_smoother
*s
, int flags
)
141 int __ast_smoother_feed(struct ast_smoother
*s
, struct ast_frame
*f
, int swap
)
143 if (f
->frametype
!= AST_FRAME_VOICE
) {
144 ast_log(LOG_WARNING
, "Huh? Can't smooth a non-voice frame!\n");
148 s
->format
= f
->subclass
;
149 s
->samplesperbyte
= (float)f
->samples
/ (float)f
->datalen
;
150 } else if (s
->format
!= f
->subclass
) {
151 ast_log(LOG_WARNING
, "Smoother was working on %d format frames, now trying to feed %d?\n", s
->format
, f
->subclass
);
154 if (s
->len
+ f
->datalen
> SMOOTHER_SIZE
) {
155 ast_log(LOG_WARNING
, "Out of smoother space\n");
158 if (((f
->datalen
== s
->size
) || ((f
->datalen
< 10) && (s
->flags
& AST_SMOOTHER_FLAG_G729
)))
159 && !s
->opt
&& (f
->offset
>= AST_MIN_OFFSET
)) {
161 /* Optimize by sending the frame we just got
162 on the next read, thus eliminating the douple
167 s
->optimizablestream
++;
168 if (s
->optimizablestream
> 10) {
169 /* For the past 10 rounds, we have input and output
170 frames of the correct size for this smoother, yet
171 we were unable to optimize because there was still
172 some cruft left over. Lets just drop the cruft so
173 we can move to a fully optimized path */
180 s
->optimizablestream
= 0;
181 if (s
->flags
& AST_SMOOTHER_FLAG_G729
) {
183 ast_log(LOG_NOTICE
, "Dropping extra frame of G.729 since we already have a VAD frame at the end\n");
188 ast_swapcopy_samples(s
->data
+s
->len
, f
->data
, f
->samples
);
190 memcpy(s
->data
+ s
->len
, f
->data
, f
->datalen
);
191 /* If either side is empty, reset the delivery time */
192 if (!s
->len
|| ast_tvzero(f
->delivery
) || ast_tvzero(s
->delivery
)) /* XXX really ? */
193 s
->delivery
= f
->delivery
;
194 s
->len
+= f
->datalen
;
198 struct ast_frame
*ast_smoother_read(struct ast_smoother
*s
)
200 struct ast_frame
*opt
;
203 /* IF we have an optimization frame, send it */
205 if (s
->opt
->offset
< AST_FRIENDLY_OFFSET
)
206 ast_log(LOG_WARNING
, "Returning a frame of inappropriate offset (%d).",
213 /* Make sure we have enough data */
214 if (s
->len
< s
->size
) {
215 /* Or, if this is a G.729 frame with VAD on it, send it immediately anyway */
216 if (!((s
->flags
& AST_SMOOTHER_FLAG_G729
) && (s
->size
% 10)))
223 s
->f
.frametype
= AST_FRAME_VOICE
;
224 s
->f
.subclass
= s
->format
;
225 s
->f
.data
= s
->framedata
+ AST_FRIENDLY_OFFSET
;
226 s
->f
.offset
= AST_FRIENDLY_OFFSET
;
228 /* Samples will be improper given VAD, but with VAD the concept really doesn't even exist */
229 s
->f
.samples
= len
* s
->samplesperbyte
; /* XXX rounding */
230 s
->f
.delivery
= s
->delivery
;
232 memcpy(s
->f
.data
, s
->data
, len
);
234 /* Move remaining data to the front if applicable */
236 /* In principle this should all be fine because if we are sending
237 G.729 VAD, the next timestamp will take over anyawy */
238 memmove(s
->data
, s
->data
+ len
, s
->len
);
239 if (!ast_tvzero(s
->delivery
)) {
240 /* If we have delivery time, increment it, otherwise, leave it at 0 */
241 s
->delivery
= ast_tvadd(s
->delivery
, ast_samp2tv(s
->f
.samples
, 8000));
248 void ast_smoother_free(struct ast_smoother
*s
)
253 static struct ast_frame
*ast_frame_header_new(void)
255 struct ast_frame
*f
= ast_calloc(1, sizeof(*f
));
260 ast_mutex_lock(&framelock
);
261 f
->next
= headerlist
;
263 headerlist
->prev
= f
;
265 ast_mutex_unlock(&framelock
);
272 * \todo Important: I should be made more efficient. Frame headers should
273 * most definitely be cached
275 void ast_frfree(struct ast_frame
*fr
)
277 if (fr
->mallocd
& AST_MALLOCD_DATA
) {
279 free(fr
->data
- fr
->offset
);
281 if (fr
->mallocd
& AST_MALLOCD_SRC
) {
283 free((char *)fr
->src
);
285 if (fr
->mallocd
& AST_MALLOCD_HDR
) {
288 ast_mutex_lock(&framelock
);
290 fr
->next
->prev
= fr
->prev
;
292 fr
->prev
->next
= fr
->next
;
294 headerlist
= fr
->next
;
295 ast_mutex_unlock(&framelock
);
302 * \brief 'isolates' a frame by duplicating non-malloc'ed components
303 * (header, src, data).
304 * On return all components are malloc'ed
306 struct ast_frame
*ast_frisolate(struct ast_frame
*fr
)
308 struct ast_frame
*out
;
311 if (!(fr
->mallocd
& AST_MALLOCD_HDR
)) {
312 /* Allocate a new header if needed */
313 if (!(out
= ast_frame_header_new()))
315 out
->frametype
= fr
->frametype
;
316 out
->subclass
= fr
->subclass
;
317 out
->datalen
= fr
->datalen
;
318 out
->samples
= fr
->samples
;
319 out
->offset
= fr
->offset
;
320 out
->data
= fr
->data
;
321 /* Copy the timing data */
322 out
->has_timing_info
= fr
->has_timing_info
;
323 if (fr
->has_timing_info
) {
326 out
->seqno
= fr
->seqno
;
331 if (!(fr
->mallocd
& AST_MALLOCD_SRC
)) {
333 if (!(out
->src
= ast_strdup(fr
->src
))) {
342 if (!(fr
->mallocd
& AST_MALLOCD_DATA
)) {
343 if (!(newdata
= ast_malloc(fr
->datalen
+ AST_FRIENDLY_OFFSET
))) {
344 if (out
->src
!= fr
->src
)
345 free((void *) out
->src
);
350 newdata
+= AST_FRIENDLY_OFFSET
;
351 out
->offset
= AST_FRIENDLY_OFFSET
;
352 out
->datalen
= fr
->datalen
;
353 memcpy(newdata
, fr
->data
, fr
->datalen
);
357 out
->mallocd
= AST_MALLOCD_HDR
| AST_MALLOCD_SRC
| AST_MALLOCD_DATA
;
362 struct ast_frame
*ast_frdup(struct ast_frame
*f
)
364 struct ast_frame
*out
;
367 /* Start with standard stuff */
368 len
= sizeof(*out
) + AST_FRIENDLY_OFFSET
+ f
->datalen
;
369 /* If we have a source, add space for it */
371 * XXX Watch out here - if we receive a src which is not terminated
372 * properly, we can be easily attacked. Should limit the size we deal with.
375 srclen
= strlen(f
->src
);
378 if (!(buf
= ast_malloc(len
)))
381 /* Set us as having malloc'd header only, so it will eventually
383 out
->frametype
= f
->frametype
;
384 out
->subclass
= f
->subclass
;
385 out
->datalen
= f
->datalen
;
386 out
->samples
= f
->samples
;
387 out
->delivery
= f
->delivery
;
388 out
->mallocd
= AST_MALLOCD_HDR
;
389 out
->offset
= AST_FRIENDLY_OFFSET
;
390 out
->data
= buf
+ sizeof(*out
) + AST_FRIENDLY_OFFSET
;
392 out
->src
= out
->data
+ f
->datalen
;
393 /* Must have space since we allocated for it */
394 strcpy((char *)out
->src
, f
->src
);
399 memcpy(out
->data
, f
->data
, out
->datalen
);
400 out
->has_timing_info
= f
->has_timing_info
;
401 if (f
->has_timing_info
) {
404 out
->seqno
= f
->seqno
;
412 * This function is badly broken - it does not handle correctly
413 * partial reads on either header or body.
414 * However is it never used anywhere so we leave it commented out
416 struct ast_frame
*ast_fr_fdread(int fd
)
420 struct ast_frame
*f
= (struct ast_frame
*)buf
;
421 int ttl
= sizeof(*f
);
422 /* Read a frame directly from there. They're always in the
426 res
= read(fd
, buf
, ttl
);
428 ast_log(LOG_WARNING
, "Bad read on %d: %s\n", fd
, strerror(errno
));
434 /* read the frame header */
436 /* Re-write data position */
437 f
->data
= buf
+ sizeof(*f
);
439 /* Forget about being mallocd */
441 /* Re-write the source */
442 f
->src
= (char *)__FUNCTION__
;
443 if (f
->datalen
> sizeof(buf
) - sizeof(*f
)) {
444 /* Really bad read */
445 ast_log(LOG_WARNING
, "Strange read (%d bytes)\n", f
->datalen
);
449 if ((res
= read(fd
, f
->data
, f
->datalen
)) != f
->datalen
) {
451 ast_log(LOG_WARNING
, "How very strange, expected %d, got %d\n", f
->datalen
, res
);
455 if ((f
->frametype
== AST_FRAME_CONTROL
) && (f
->subclass
== AST_CONTROL_HANGUP
)) {
458 return ast_frisolate(f
);
461 /* Some convenient routines for sending frames to/from stream or datagram
462 sockets, pipes, etc (maybe even files) */
465 * XXX this function is also partly broken because it does not handle
466 * partial writes. We comment it out too, and also the unique
467 * client it has, ast_fr_fdhangup()
469 int ast_fr_fdwrite(int fd
, struct ast_frame
*frame
)
471 /* Write the frame exactly */
472 if (write(fd
, frame
, sizeof(*frame
)) != sizeof(*frame
)) {
473 ast_log(LOG_WARNING
, "Write error: %s\n", strerror(errno
));
476 if (write(fd
, frame
->data
, frame
->datalen
) != frame
->datalen
) {
477 ast_log(LOG_WARNING
, "Write error: %s\n", strerror(errno
));
483 int ast_fr_fdhangup(int fd
)
485 struct ast_frame hangup
= {
489 return ast_fr_fdwrite(fd
, &hangup
);
492 #endif /* unused functions */
494 void ast_swapcopy_samples(void *dst
, const void *src
, int samples
)
497 unsigned short *dst_s
= dst
;
498 const unsigned short *src_s
= src
;
500 for (i
= 0; i
< samples
; i
++)
501 dst_s
[i
] = (src_s
[i
]<<8) | (src_s
[i
]>>8);
505 struct ast_format_list
*ast_get_format_list_index(int index
)
507 return &AST_FORMAT_LIST
[index
];
510 struct ast_format_list
*ast_get_format_list(size_t *size
)
512 *size
= (sizeof(AST_FORMAT_LIST
) / sizeof(AST_FORMAT_LIST
[0]));
513 return AST_FORMAT_LIST
;
516 char* ast_getformatname(int format
)
519 char *ret
= "unknown";
520 for (x
= 0; x
< sizeof(AST_FORMAT_LIST
) / sizeof(AST_FORMAT_LIST
[0]); x
++) {
521 if(AST_FORMAT_LIST
[x
].visible
&& AST_FORMAT_LIST
[x
].bits
== format
) {
522 ret
= AST_FORMAT_LIST
[x
].name
;
529 char *ast_getformatname_multiple(char *buf
, size_t size
, int format
)
533 char *start
, *end
= buf
;
537 snprintf(end
, size
, "0x%x (", format
);
542 for (x
= 0; x
< sizeof(AST_FORMAT_LIST
) / sizeof(AST_FORMAT_LIST
[0]); x
++) {
543 if (AST_FORMAT_LIST
[x
].visible
&& (AST_FORMAT_LIST
[x
].bits
& format
)) {
544 snprintf(end
, size
,"%s|",AST_FORMAT_LIST
[x
].name
);
551 snprintf(start
, size
, "nothing)");
557 static struct ast_codec_alias_table
{
560 } ast_codec_alias_table
[] = {
561 { "slinear", "slin"},
565 static const char *ast_expand_codec_alias(const char *in
)
569 for (x
= 0; x
< sizeof(ast_codec_alias_table
) / sizeof(ast_codec_alias_table
[0]); x
++) {
570 if(!strcmp(in
,ast_codec_alias_table
[x
].alias
))
571 return ast_codec_alias_table
[x
].realname
;
576 int ast_getformatbyname(const char *name
)
578 int x
, all
, format
= 0;
580 all
= strcasecmp(name
, "all") ? 0 : 1;
581 for (x
= 0; x
< sizeof(AST_FORMAT_LIST
) / sizeof(AST_FORMAT_LIST
[0]); x
++) {
582 if(AST_FORMAT_LIST
[x
].visible
&& (all
||
583 !strcasecmp(AST_FORMAT_LIST
[x
].name
,name
) ||
584 !strcasecmp(AST_FORMAT_LIST
[x
].name
,ast_expand_codec_alias(name
)))) {
585 format
|= AST_FORMAT_LIST
[x
].bits
;
594 char *ast_codec2str(int codec
)
597 char *ret
= "unknown";
598 for (x
= 0; x
< sizeof(AST_FORMAT_LIST
) / sizeof(AST_FORMAT_LIST
[0]); x
++) {
599 if(AST_FORMAT_LIST
[x
].visible
&& AST_FORMAT_LIST
[x
].bits
== codec
) {
600 ret
= AST_FORMAT_LIST
[x
].desc
;
607 static int show_codecs(int fd
, int argc
, char *argv
[])
612 if ((argc
< 2) || (argc
> 3))
613 return RESULT_SHOWUSAGE
;
615 if (!ast_opt_dont_warn
)
616 ast_cli(fd
, "Disclaimer: this command is for informational purposes only.\n"
617 "\tIt does not indicate anything about your configuration.\n");
619 ast_cli(fd
, "%11s %9s %10s TYPE %5s %s\n","INT","BINARY","HEX","NAME","DESC");
620 ast_cli(fd
, "--------------------------------------------------------------------------------\n");
621 if ((argc
== 2) || (!strcasecmp(argv
[1],"audio"))) {
624 snprintf(hex
,25,"(0x%x)",1<<i
);
625 ast_cli(fd
, "%11u (1 << %2d) %10s audio %5s (%s)\n",1 << i
,i
,hex
,ast_getformatname(1<<i
),ast_codec2str(1<<i
));
629 if ((argc
== 2) || (!strcasecmp(argv
[1],"image"))) {
631 for (i
=16;i
<18;i
++) {
632 snprintf(hex
,25,"(0x%x)",1<<i
);
633 ast_cli(fd
, "%11u (1 << %2d) %10s image %5s (%s)\n",1 << i
,i
,hex
,ast_getformatname(1<<i
),ast_codec2str(1<<i
));
637 if ((argc
== 2) || (!strcasecmp(argv
[1],"video"))) {
639 for (i
=18;i
<22;i
++) {
640 snprintf(hex
,25,"(0x%x)",1<<i
);
641 ast_cli(fd
, "%11u (1 << %2d) %10s video %5s (%s)\n",1 << i
,i
,hex
,ast_getformatname(1<<i
),ast_codec2str(1<<i
));
646 return RESULT_SHOWUSAGE
;
648 return RESULT_SUCCESS
;
651 static char frame_show_codecs_usage
[] =
652 "Usage: show [audio|video|image] codecs\n"
653 " Displays codec mapping\n";
655 static int show_codec_n(int fd
, int argc
, char *argv
[])
657 int codec
, i
, found
=0;
660 return RESULT_SHOWUSAGE
;
662 if (sscanf(argv
[2],"%d",&codec
) != 1)
663 return RESULT_SHOWUSAGE
;
665 for (i
= 0; i
< 32; i
++)
666 if (codec
& (1 << i
)) {
668 ast_cli(fd
, "%11u (1 << %2d) %s\n",1 << i
,i
,ast_codec2str(1<<i
));
672 ast_cli(fd
, "Codec %d not found\n", codec
);
674 return RESULT_SUCCESS
;
677 static char frame_show_codec_n_usage
[] =
678 "Usage: show codec <number>\n"
679 " Displays codec mapping\n";
681 /*! Dump a frame for debugging purposes */
682 void ast_frame_dump(const char *name
, struct ast_frame
*f
, char *prefix
)
684 const char noname
[] = "unknown";
685 char ftype
[40] = "Unknown Frametype";
687 char subclass
[40] = "Unknown Subclass";
689 char moreinfo
[40] = "";
699 ast_verbose("%s [ %s (NULL) ] [%s]\n",
700 term_color(cp
, prefix
, COLOR_BRMAGENTA
, COLOR_BLACK
, sizeof(cp
)),
701 term_color(cft
, "HANGUP", COLOR_BRRED
, COLOR_BLACK
, sizeof(cft
)),
702 term_color(cn
, name
, COLOR_YELLOW
, COLOR_BLACK
, sizeof(cn
)));
705 /* XXX We should probably print one each of voice and video when the format changes XXX */
706 if (f
->frametype
== AST_FRAME_VOICE
)
708 if (f
->frametype
== AST_FRAME_VIDEO
)
710 switch(f
->frametype
) {
712 strcpy(ftype
, "DTMF");
713 subclass
[0] = f
->subclass
;
716 case AST_FRAME_CONTROL
:
717 strcpy(ftype
, "Control");
718 switch(f
->subclass
) {
719 case AST_CONTROL_HANGUP
:
720 strcpy(subclass
, "Hangup");
722 case AST_CONTROL_RING
:
723 strcpy(subclass
, "Ring");
725 case AST_CONTROL_RINGING
:
726 strcpy(subclass
, "Ringing");
728 case AST_CONTROL_ANSWER
:
729 strcpy(subclass
, "Answer");
731 case AST_CONTROL_BUSY
:
732 strcpy(subclass
, "Busy");
734 case AST_CONTROL_TAKEOFFHOOK
:
735 strcpy(subclass
, "Take Off Hook");
737 case AST_CONTROL_OFFHOOK
:
738 strcpy(subclass
, "Line Off Hook");
740 case AST_CONTROL_CONGESTION
:
741 strcpy(subclass
, "Congestion");
743 case AST_CONTROL_FLASH
:
744 strcpy(subclass
, "Flash");
746 case AST_CONTROL_WINK
:
747 strcpy(subclass
, "Wink");
749 case AST_CONTROL_OPTION
:
750 strcpy(subclass
, "Option");
752 case AST_CONTROL_RADIO_KEY
:
753 strcpy(subclass
, "Key Radio");
755 case AST_CONTROL_RADIO_UNKEY
:
756 strcpy(subclass
, "Unkey Radio");
759 strcpy(subclass
, "Stop generators");
762 snprintf(subclass
, sizeof(subclass
), "Unknown control '%d'", f
->subclass
);
766 strcpy(ftype
, "Null Frame");
767 strcpy(subclass
, "N/A");
770 /* Should never happen */
771 strcpy(ftype
, "IAX Specific");
772 snprintf(subclass
, sizeof(subclass
), "IAX Frametype %d", f
->subclass
);
775 strcpy(ftype
, "Text");
776 strcpy(subclass
, "N/A");
777 ast_copy_string(moreinfo
, f
->data
, sizeof(moreinfo
));
779 case AST_FRAME_IMAGE
:
780 strcpy(ftype
, "Image");
781 snprintf(subclass
, sizeof(subclass
), "Image format %s\n", ast_getformatname(f
->subclass
));
784 strcpy(ftype
, "HTML");
785 switch(f
->subclass
) {
787 strcpy(subclass
, "URL");
788 ast_copy_string(moreinfo
, f
->data
, sizeof(moreinfo
));
791 strcpy(subclass
, "Data");
794 strcpy(subclass
, "Begin");
797 strcpy(subclass
, "End");
799 case AST_HTML_LDCOMPLETE
:
800 strcpy(subclass
, "Load Complete");
802 case AST_HTML_NOSUPPORT
:
803 strcpy(subclass
, "No Support");
805 case AST_HTML_LINKURL
:
806 strcpy(subclass
, "Link URL");
807 ast_copy_string(moreinfo
, f
->data
, sizeof(moreinfo
));
809 case AST_HTML_UNLINK
:
810 strcpy(subclass
, "Unlink");
812 case AST_HTML_LINKREJECT
:
813 strcpy(subclass
, "Link Reject");
816 snprintf(subclass
, sizeof(subclass
), "Unknown HTML frame '%d'\n", f
->subclass
);
820 case AST_FRAME_MODEM
:
821 strcpy(ftype
, "Modem");
822 switch (f
->subclass
) {
824 strcpy(subclass
, "T.38");
827 strcpy(subclass
, "V.150");
830 snprintf(subclass
, sizeof(subclass
), "Unknown MODEM frame '%d'\n", f
->subclass
);
835 snprintf(ftype
, sizeof(ftype
), "Unknown Frametype '%d'", f
->frametype
);
837 if (!ast_strlen_zero(moreinfo
))
838 ast_verbose("%s [ TYPE: %s (%d) SUBCLASS: %s (%d) '%s' ] [%s]\n",
839 term_color(cp
, prefix
, COLOR_BRMAGENTA
, COLOR_BLACK
, sizeof(cp
)),
840 term_color(cft
, ftype
, COLOR_BRRED
, COLOR_BLACK
, sizeof(cft
)),
842 term_color(csub
, subclass
, COLOR_BRCYAN
, COLOR_BLACK
, sizeof(csub
)),
844 term_color(cmn
, moreinfo
, COLOR_BRGREEN
, COLOR_BLACK
, sizeof(cmn
)),
845 term_color(cn
, name
, COLOR_YELLOW
, COLOR_BLACK
, sizeof(cn
)));
847 ast_verbose("%s [ TYPE: %s (%d) SUBCLASS: %s (%d) ] [%s]\n",
848 term_color(cp
, prefix
, COLOR_BRMAGENTA
, COLOR_BLACK
, sizeof(cp
)),
849 term_color(cft
, ftype
, COLOR_BRRED
, COLOR_BLACK
, sizeof(cft
)),
851 term_color(csub
, subclass
, COLOR_BRCYAN
, COLOR_BLACK
, sizeof(csub
)),
853 term_color(cn
, name
, COLOR_YELLOW
, COLOR_BLACK
, sizeof(cn
)));
858 static int show_frame_stats(int fd
, int argc
, char *argv
[])
863 return RESULT_SHOWUSAGE
;
864 ast_cli(fd
, " Framer Statistics \n");
865 ast_cli(fd
, "---------------------------\n");
866 ast_cli(fd
, "Total allocated headers: %d\n", headers
);
867 ast_cli(fd
, "Queue Dump:\n");
868 ast_mutex_lock(&framelock
);
869 for (f
=headerlist
; f
; f
= f
->next
) {
870 ast_cli(fd
, "%d. Type %d, subclass %d from %s\n", x
++, f
->frametype
, f
->subclass
, f
->src
? f
->src
: "<Unknown>");
872 ast_mutex_unlock(&framelock
);
873 return RESULT_SUCCESS
;
876 static char frame_stats_usage
[] =
877 "Usage: show frame stats\n"
878 " Displays debugging statistics from framer\n";
881 /* Builtin Asterisk CLI-commands for debugging */
882 static struct ast_cli_entry my_clis
[] = {
883 { { "show", "codecs", NULL
}, show_codecs
, "Shows codecs", frame_show_codecs_usage
},
884 { { "show", "audio", "codecs", NULL
}, show_codecs
, "Shows audio codecs", frame_show_codecs_usage
},
885 { { "show", "video", "codecs", NULL
}, show_codecs
, "Shows video codecs", frame_show_codecs_usage
},
886 { { "show", "image", "codecs", NULL
}, show_codecs
, "Shows image codecs", frame_show_codecs_usage
},
887 { { "show", "codec", NULL
}, show_codec_n
, "Shows a specific codec", frame_show_codec_n_usage
},
889 { { "show", "frame", "stats", NULL
}, show_frame_stats
, "Shows frame statistics", frame_stats_usage
},
893 int init_framer(void)
895 ast_cli_register_multiple(my_clis
, sizeof(my_clis
)/sizeof(my_clis
[0]) );
899 void ast_codec_pref_convert(struct ast_codec_pref
*pref
, char *buf
, size_t size
, int right
)
901 int x
, differential
= (int) 'A', mem
;
915 for (x
= 0; x
< 32 ; x
++) {
918 to
[x
] = right
? (from
[x
] + differential
) : (from
[x
] - differential
);
922 int ast_codec_pref_string(struct ast_codec_pref
*pref
, char *buf
, size_t size
)
925 size_t total_len
, slen
;
932 for(x
= 0; x
< 32 ; x
++) {
935 if(!(codec
= ast_codec_pref_index(pref
,x
)))
937 if((formatname
= ast_getformatname(codec
))) {
938 slen
= strlen(formatname
);
941 strncat(buf
,formatname
,total_len
);
944 if(total_len
&& x
< 31 && ast_codec_pref_index(pref
, x
+ 1)) {
945 strncat(buf
,"|",total_len
);
950 strncat(buf
,")",total_len
);
954 return size
- total_len
;
957 int ast_codec_pref_index(struct ast_codec_pref
*pref
, int index
)
962 if((index
>= 0) && (index
< sizeof(pref
->order
))) {
963 slot
= pref
->order
[index
];
966 return slot
? AST_FORMAT_LIST
[slot
-1].bits
: 0;
969 /*! \brief Remove codec from pref list */
970 void ast_codec_pref_remove(struct ast_codec_pref
*pref
, int format
)
972 struct ast_codec_pref oldorder
;
979 memcpy(&oldorder
, pref
, sizeof(oldorder
));
980 memset(pref
, 0, sizeof(*pref
));
982 for (x
= 0; x
< sizeof(AST_FORMAT_LIST
) / sizeof(AST_FORMAT_LIST
[0]); x
++) {
983 slot
= oldorder
.order
[x
];
986 if(AST_FORMAT_LIST
[slot
-1].bits
!= format
)
987 pref
->order
[y
++] = slot
;
992 /*! \brief Append codec to list */
993 int ast_codec_pref_append(struct ast_codec_pref
*pref
, int format
)
995 int x
, newindex
= -1;
997 ast_codec_pref_remove(pref
, format
);
999 for (x
= 0; x
< sizeof(AST_FORMAT_LIST
) / sizeof(AST_FORMAT_LIST
[0]); x
++) {
1000 if(AST_FORMAT_LIST
[x
].bits
== format
) {
1007 for (x
= 0; x
< sizeof(AST_FORMAT_LIST
) / sizeof(AST_FORMAT_LIST
[0]); x
++) {
1008 if(!pref
->order
[x
]) {
1009 pref
->order
[x
] = newindex
;
1019 /*! \brief Pick a codec */
1020 int ast_codec_choose(struct ast_codec_pref
*pref
, int formats
, int find_best
)
1022 int x
, ret
= 0, slot
;
1024 for (x
= 0; x
< sizeof(AST_FORMAT_LIST
) / sizeof(AST_FORMAT_LIST
[0]); x
++) {
1025 slot
= pref
->order
[x
];
1029 if (formats
& AST_FORMAT_LIST
[slot
-1].bits
) {
1030 ret
= AST_FORMAT_LIST
[slot
-1].bits
;
1034 if(ret
& AST_FORMAT_AUDIO_MASK
)
1037 if (option_debug
> 3)
1038 ast_log(LOG_DEBUG
, "Could not find preferred codec - %s\n", find_best
? "Going for the best codec" : "Returning zero codec");
1040 return find_best
? ast_best_codec(formats
) : 0;
1043 void ast_parse_allow_disallow(struct ast_codec_pref
*pref
, int *mask
, const char *list
, int allowing
)
1049 parse
= ast_strdupa(list
);
1050 while ((this = strsep(&parse
, ","))) {
1051 if (!(format
= ast_getformatbyname(this))) {
1052 ast_log(LOG_WARNING
, "Cannot %s unknown format '%s'\n", allowing
? "allow" : "disallow", this);
1063 /* Set up a preference list for audio. Do not include video in preferences
1064 since we can not transcode video and have to use whatever is offered
1066 if (pref
&& (format
& AST_FORMAT_AUDIO_MASK
)) {
1067 if (strcasecmp(this, "all")) {
1069 ast_codec_pref_append(pref
, format
);
1071 ast_codec_pref_remove(pref
, format
);
1072 } else if (!allowing
) {
1073 memset(pref
, 0, sizeof(*pref
));
1079 static int g723_len(unsigned char buf
)
1081 enum frame_type type
= buf
& TYPE_MASK
;
1097 ast_log(LOG_WARNING
, "Badly encoded frame (%d)\n", type
);
1102 static int g723_samples(unsigned char *buf
, int maxlen
)
1107 while(pos
< maxlen
) {
1108 res
= g723_len(buf
[pos
]);
1117 static unsigned char get_n_bits_at(unsigned char *data
, int n
, int bit
)
1119 int byte
= bit
/ 8; /* byte containing first bit */
1120 int rem
= 8 - (bit
% 8); /* remaining bits in first byte */
1121 unsigned char ret
= 0;
1123 if (n
<= 0 || n
> 8)
1127 ret
= (data
[byte
] << (n
- rem
));
1128 ret
|= (data
[byte
+ 1] >> (8 - n
+ rem
));
1130 ret
= (data
[byte
] >> (rem
- n
));
1133 return (ret
& (0xff >> (8 - n
)));
1136 static int speex_get_wb_sz_at(unsigned char *data
, int len
, int bit
)
1138 static int SpeexWBSubModeSz
[] = {
1144 /* skip up to two wideband frames */
1145 if (((len
* 8 - off
) >= 5) &&
1146 get_n_bits_at(data
, 1, off
)) {
1147 c
= get_n_bits_at(data
, 3, off
+ 1);
1148 off
+= SpeexWBSubModeSz
[c
];
1150 if (((len
* 8 - off
) >= 5) &&
1151 get_n_bits_at(data
, 1, off
)) {
1152 c
= get_n_bits_at(data
, 3, off
+ 1);
1153 off
+= SpeexWBSubModeSz
[c
];
1155 if (((len
* 8 - off
) >= 5) &&
1156 get_n_bits_at(data
, 1, off
)) {
1157 ast_log(LOG_WARNING
, "Encountered corrupt speex frame; too many wideband frames in a row.\n");
1166 static int speex_samples(unsigned char *data
, int len
)
1168 static int SpeexSubModeSz
[] = {
1173 static int SpeexInBandSz
[] = {
1183 while ((len
* 8 - bit
) >= 5) {
1184 /* skip wideband frames */
1185 off
= speex_get_wb_sz_at(data
, len
, bit
);
1187 ast_log(LOG_WARNING
, "Had error while reading wideband frames for speex samples\n");
1192 if ((len
* 8 - bit
) < 5) {
1193 ast_log(LOG_WARNING
, "Not enough bits remaining after wide band for speex samples.\n");
1197 /* get control bits */
1198 c
= get_n_bits_at(data
, 5, bit
);
1204 } else if (c
== 14) {
1205 /* in-band signal; next 4 bits contain signal id */
1206 c
= get_n_bits_at(data
, 4, bit
);
1208 bit
+= SpeexInBandSz
[c
];
1209 } else if (c
== 13) {
1210 /* user in-band; next 5 bits contain msg len */
1211 c
= get_n_bits_at(data
, 5, bit
);
1218 /* skip number bits for submode (less the 5 control bits) */
1219 bit
+= SpeexSubModeSz
[c
] - 5;
1220 cnt
+= 160; /* new frame */
1226 int ast_codec_get_samples(struct ast_frame
*f
)
1229 switch(f
->subclass
) {
1230 case AST_FORMAT_SPEEX
:
1231 samples
= speex_samples(f
->data
, f
->datalen
);
1233 case AST_FORMAT_G723_1
:
1234 samples
= g723_samples(f
->data
, f
->datalen
);
1236 case AST_FORMAT_ILBC
:
1237 samples
= 240 * (f
->datalen
/ 50);
1239 case AST_FORMAT_GSM
:
1240 samples
= 160 * (f
->datalen
/ 33);
1242 case AST_FORMAT_G729A
:
1243 samples
= f
->datalen
* 8;
1245 case AST_FORMAT_SLINEAR
:
1246 samples
= f
->datalen
/ 2;
1248 case AST_FORMAT_LPC10
:
1249 /* assumes that the RTP packet contains one LPC10 frame */
1251 samples
+= (((char *)(f
->data
))[7] & 0x1) * 8;
1253 case AST_FORMAT_ULAW
:
1254 case AST_FORMAT_ALAW
:
1255 samples
= f
->datalen
;
1257 case AST_FORMAT_ADPCM
:
1258 case AST_FORMAT_G726
:
1259 case AST_FORMAT_G726_AAL2
:
1260 samples
= f
->datalen
* 2;
1263 ast_log(LOG_WARNING
, "Unable to calculate samples for format %s\n", ast_getformatname(f
->subclass
));
1268 int ast_codec_get_len(int format
, int samples
)
1272 /* XXX Still need speex, g723, and lpc10 XXX */
1274 case AST_FORMAT_ILBC
:
1275 len
= (samples
/ 240) * 50;
1277 case AST_FORMAT_GSM
:
1278 len
= (samples
/ 160) * 33;
1280 case AST_FORMAT_G729A
:
1283 case AST_FORMAT_SLINEAR
:
1286 case AST_FORMAT_ULAW
:
1287 case AST_FORMAT_ALAW
:
1290 case AST_FORMAT_ADPCM
:
1291 case AST_FORMAT_G726
:
1292 case AST_FORMAT_G726_AAL2
:
1296 ast_log(LOG_WARNING
, "Unable to calculate sample length for format %s\n", ast_getformatname(format
));
1302 int ast_frame_adjust_volume(struct ast_frame
*f
, int adjustment
)
1305 short *fdata
= f
->data
;
1306 short adjust_value
= abs(adjustment
);
1308 if ((f
->frametype
!= AST_FRAME_VOICE
) || (f
->subclass
!= AST_FORMAT_SLINEAR
))
1314 for (count
= 0; count
< f
->samples
; count
++) {
1315 if (adjustment
> 0) {
1316 ast_slinear_saturated_multiply(&fdata
[count
], &adjust_value
);
1317 } else if (adjustment
< 0) {
1318 ast_slinear_saturated_divide(&fdata
[count
], &adjust_value
);
1325 int ast_frame_slinear_sum(struct ast_frame
*f1
, struct ast_frame
*f2
)
1328 short *data1
, *data2
;
1330 if ((f1
->frametype
!= AST_FRAME_VOICE
) || (f1
->subclass
!= AST_FORMAT_SLINEAR
))
1333 if ((f2
->frametype
!= AST_FRAME_VOICE
) || (f2
->subclass
!= AST_FORMAT_SLINEAR
))
1336 if (f1
->samples
!= f2
->samples
)
1339 for (count
= 0, data1
= f1
->data
, data2
= f2
->data
;
1340 count
< f1
->samples
;
1341 count
++, data1
++, data2
++)
1342 ast_slinear_saturated_add(data1
, data2
);
1347 struct ast_frame
*ast_frame_enqueue(struct ast_frame
*head
, struct ast_frame
*f
, int maxlen
, int dupe
)
1349 struct ast_frame
*cur
, *oldhead
;
1363 if (len
>= maxlen
) {
1366 ast_frfree(oldhead
);