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"
44 #include "asterisk/threadstorage.h"
45 #include "asterisk/linkedlists.h"
48 static int headers
= 0;
49 static AST_LIST_HEAD_STATIC(headerlist
, ast_frame
);
52 static void frame_cache_cleanup(void *data
);
54 /*! \brief A per-thread cache of frame headers */
55 AST_THREADSTORAGE_CUSTOM(frame_cache
, frame_cache_init
, frame_cache_cleanup
);
58 * \brief Maximum ast_frame cache size
60 * In most cases where the frame header cache will be useful, the size
61 * of the cache will stay very small. However, it is not always the case that
62 * the same thread that allocates the frame will be the one freeing them, so
63 * sometimes a thread will never have any frames in its cache, or the cache
64 * will never be pulled from. For the latter case, we limit the maximum size.
66 #define FRAME_CACHE_MAX_SIZE 10
68 /*! \brief This is just so ast_frames, a list head struct for holding a list of
69 * ast_frame structures, is defined. */
70 AST_LIST_HEAD_NOLOCK(ast_frames
, ast_frame
);
72 struct ast_frame_cache
{
73 struct ast_frames list
;
77 #define SMOOTHER_SIZE 8000
82 TYPE_SILENCE
, /* 0x2 */
83 TYPE_DONTSEND
/* 0x3 */
92 int optimizablestream
;
96 struct timeval delivery
;
97 char data
[SMOOTHER_SIZE
];
98 char framedata
[SMOOTHER_SIZE
+ AST_FRIENDLY_OFFSET
];
99 struct ast_frame
*opt
;
103 /*! \brief Definition of supported media formats (codecs) */
104 static struct ast_format_list AST_FORMAT_LIST
[] = { /*!< Bit number: comment - Bit numbers are hard coded in show_codec() */
105 { 1, AST_FORMAT_G723_1
, "g723" , "G.723.1", 24, 30, 300, 30, 30 }, /*!< 1 */
106 { 1, AST_FORMAT_GSM
, "gsm" , "GSM", 33, 20, 300, 20, 20 }, /*!< 2: codec_gsm.c */
107 { 1, AST_FORMAT_ULAW
, "ulaw", "G.711 u-law", 80, 10, 150, 10, 20 }, /*!< 3: codec_ulaw.c */
108 { 1, AST_FORMAT_ALAW
, "alaw", "G.711 A-law", 80, 10, 150, 10, 20 }, /*!< 4: codec_alaw.c */
109 { 1, AST_FORMAT_G726
, "g726", "G.726 RFC3551", 40, 10, 300, 10, 20 }, /*!< 5: codec_g726.c */
110 { 1, AST_FORMAT_ADPCM
, "adpcm" , "ADPCM", 40, 10, 300, 10, 20 }, /*!< 6: codec_adpcm.c */
111 { 1, AST_FORMAT_SLINEAR
, "slin", "16 bit Signed Linear PCM", 160, 10, 70, 10, 20, AST_SMOOTHER_FLAG_BE
}, /*!< 7 */
112 { 1, AST_FORMAT_LPC10
, "lpc10", "LPC10", 7, 20, 20, 20, 20 }, /*!< 8: codec_lpc10.c */
113 { 1, AST_FORMAT_G729A
, "g729", "G.729A", 10, 10, 230, 10, 20, AST_SMOOTHER_FLAG_G729
}, /*!< 9: Binary commercial distribution */
114 { 1, AST_FORMAT_SPEEX
, "speex", "SpeeX", 10, 10, 60, 10, 20 }, /*!< 10: codec_speex.c */
115 { 1, AST_FORMAT_ILBC
, "ilbc", "iLBC", 50, 30, 30, 30, 30 }, /*!< 11: codec_ilbc.c */ /* inc=30ms - workaround */
116 { 1, AST_FORMAT_G726_AAL2
, "g726aal2", "G.726 AAL2", 40, 10, 300, 10, 20 }, /*!< 12: codec_g726.c */
117 { 1, AST_FORMAT_G722
, "g722", "G722"}, /*!< 13 */
118 { 0, 0, "nothing", "undefined" },
119 { 0, 0, "nothing", "undefined" },
120 { 0, 0, "nothing", "undefined" },
121 { 0, 0, "nothing", "undefined" },
122 { 0, AST_FORMAT_MAX_AUDIO
, "maxaudio", "Maximum audio format" },
123 { 1, AST_FORMAT_JPEG
, "jpeg", "JPEG image"}, /*!< 17: See format_jpeg.c */
124 { 1, AST_FORMAT_PNG
, "png", "PNG image"}, /*!< 18: Image format */
125 { 1, AST_FORMAT_H261
, "h261", "H.261 Video" }, /*!< 19: Video Passthrough */
126 { 1, AST_FORMAT_H263
, "h263", "H.263 Video" }, /*!< 20: Passthrough support, see format_h263.c */
127 { 1, AST_FORMAT_H263_PLUS
, "h263p", "H.263+ Video" }, /*!< 21: See format_h263.c */
128 { 1, AST_FORMAT_H264
, "h264", "H.264 Video" }, /*!< 22: Passthrough support, see format_h263.c */
129 { 0, 0, "nothing", "undefined" },
130 { 0, 0, "nothing", "undefined" },
131 { 0, 0, "nothing", "undefined" },
132 { 0, AST_FORMAT_MAX_VIDEO
, "maxvideo", "Maximum video format" },
135 struct ast_frame ast_null_frame
= { AST_FRAME_NULL
, };
137 void ast_smoother_reset(struct ast_smoother
*s
, int size
)
139 memset(s
, 0, sizeof(*s
));
143 struct ast_smoother
*ast_smoother_new(int size
)
145 struct ast_smoother
*s
;
148 if ((s
= ast_malloc(sizeof(*s
))))
149 ast_smoother_reset(s
, size
);
153 int ast_smoother_get_flags(struct ast_smoother
*s
)
158 void ast_smoother_set_flags(struct ast_smoother
*s
, int flags
)
163 int ast_smoother_test_flag(struct ast_smoother
*s
, int flag
)
165 return (s
->flags
& flag
);
168 int __ast_smoother_feed(struct ast_smoother
*s
, struct ast_frame
*f
, int swap
)
170 if (f
->frametype
!= AST_FRAME_VOICE
) {
171 ast_log(LOG_WARNING
, "Huh? Can't smooth a non-voice frame!\n");
175 s
->format
= f
->subclass
;
176 s
->samplesperbyte
= (float)f
->samples
/ (float)f
->datalen
;
177 } else if (s
->format
!= f
->subclass
) {
178 ast_log(LOG_WARNING
, "Smoother was working on %d format frames, now trying to feed %d?\n", s
->format
, f
->subclass
);
181 if (s
->len
+ f
->datalen
> SMOOTHER_SIZE
) {
182 ast_log(LOG_WARNING
, "Out of smoother space\n");
185 if (((f
->datalen
== s
->size
) || ((f
->datalen
< 10) && (s
->flags
& AST_SMOOTHER_FLAG_G729
)))
186 && !s
->opt
&& (f
->offset
>= AST_MIN_OFFSET
)) {
188 /* Optimize by sending the frame we just got
189 on the next read, thus eliminating the douple
192 ast_swapcopy_samples(f
->data
, f
->data
, f
->samples
);
196 s
->optimizablestream
++;
197 if (s
->optimizablestream
> 10) {
198 /* For the past 10 rounds, we have input and output
199 frames of the correct size for this smoother, yet
200 we were unable to optimize because there was still
201 some cruft left over. Lets just drop the cruft so
202 we can move to a fully optimized path */
204 ast_swapcopy_samples(f
->data
, f
->data
, f
->samples
);
211 s
->optimizablestream
= 0;
212 if (s
->flags
& AST_SMOOTHER_FLAG_G729
) {
214 ast_log(LOG_NOTICE
, "Dropping extra frame of G.729 since we already have a VAD frame at the end\n");
219 ast_swapcopy_samples(s
->data
+s
->len
, f
->data
, f
->samples
);
221 memcpy(s
->data
+ s
->len
, f
->data
, f
->datalen
);
222 /* If either side is empty, reset the delivery time */
223 if (!s
->len
|| ast_tvzero(f
->delivery
) || ast_tvzero(s
->delivery
)) /* XXX really ? */
224 s
->delivery
= f
->delivery
;
225 s
->len
+= f
->datalen
;
229 struct ast_frame
*ast_smoother_read(struct ast_smoother
*s
)
231 struct ast_frame
*opt
;
234 /* IF we have an optimization frame, send it */
236 if (s
->opt
->offset
< AST_FRIENDLY_OFFSET
)
237 ast_log(LOG_WARNING
, "Returning a frame of inappropriate offset (%d).\n",
244 /* Make sure we have enough data */
245 if (s
->len
< s
->size
) {
246 /* Or, if this is a G.729 frame with VAD on it, send it immediately anyway */
247 if (!((s
->flags
& AST_SMOOTHER_FLAG_G729
) && (s
->size
% 10)))
254 s
->f
.frametype
= AST_FRAME_VOICE
;
255 s
->f
.subclass
= s
->format
;
256 s
->f
.data
= s
->framedata
+ AST_FRIENDLY_OFFSET
;
257 s
->f
.offset
= AST_FRIENDLY_OFFSET
;
259 /* Samples will be improper given VAD, but with VAD the concept really doesn't even exist */
260 s
->f
.samples
= len
* s
->samplesperbyte
; /* XXX rounding */
261 s
->f
.delivery
= s
->delivery
;
263 memcpy(s
->f
.data
, s
->data
, len
);
265 /* Move remaining data to the front if applicable */
267 /* In principle this should all be fine because if we are sending
268 G.729 VAD, the next timestamp will take over anyawy */
269 memmove(s
->data
, s
->data
+ len
, s
->len
);
270 if (!ast_tvzero(s
->delivery
)) {
271 /* If we have delivery time, increment it, otherwise, leave it at 0 */
272 s
->delivery
= ast_tvadd(s
->delivery
, ast_samp2tv(s
->f
.samples
, 8000));
279 void ast_smoother_free(struct ast_smoother
*s
)
284 static struct ast_frame
*ast_frame_header_new(void)
287 struct ast_frame_cache
*frames
;
289 if ((frames
= ast_threadstorage_get(&frame_cache
, sizeof(*frames
)))) {
290 if ((f
= AST_LIST_REMOVE_HEAD(&frames
->list
, frame_list
))) {
291 size_t mallocd_len
= f
->mallocd_hdr_len
;
292 memset(f
, 0, sizeof(*f
));
293 f
->mallocd_hdr_len
= mallocd_len
;
294 f
->mallocd
= AST_MALLOCD_HDR
;
300 if (!(f
= ast_calloc(1, sizeof(*f
))))
303 f
->mallocd_hdr_len
= sizeof(*f
);
305 AST_LIST_LOCK(&headerlist
);
307 AST_LIST_INSERT_HEAD(&headerlist
, f
, frame_list
);
308 AST_LIST_UNLOCK(&headerlist
);
314 static void frame_cache_cleanup(void *data
)
316 struct ast_frame_cache
*frames
= data
;
319 while ((f
= AST_LIST_REMOVE_HEAD(&frames
->list
, frame_list
)))
325 void ast_frame_free(struct ast_frame
*fr
, int cache
)
330 if (cache
&& fr
->mallocd
== AST_MALLOCD_HDR
) {
331 /* Cool, only the header is malloc'd, let's just cache those for now
332 * to keep things simple... */
333 struct ast_frame_cache
*frames
;
335 if ((frames
= ast_threadstorage_get(&frame_cache
, sizeof(*frames
)))
336 && frames
->size
< FRAME_CACHE_MAX_SIZE
) {
337 AST_LIST_INSERT_HEAD(&frames
->list
, fr
, frame_list
);
343 if (fr
->mallocd
& AST_MALLOCD_DATA
) {
345 free(fr
->data
- fr
->offset
);
347 if (fr
->mallocd
& AST_MALLOCD_SRC
) {
349 free((char *)fr
->src
);
351 if (fr
->mallocd
& AST_MALLOCD_HDR
) {
353 AST_LIST_LOCK(&headerlist
);
355 AST_LIST_REMOVE(&headerlist
, fr
, frame_list
);
356 AST_LIST_UNLOCK(&headerlist
);
363 * \brief 'isolates' a frame by duplicating non-malloc'ed components
364 * (header, src, data).
365 * On return all components are malloc'ed
367 struct ast_frame
*ast_frisolate(struct ast_frame
*fr
)
369 struct ast_frame
*out
;
372 if (!(fr
->mallocd
& AST_MALLOCD_HDR
)) {
373 /* Allocate a new header if needed */
374 if (!(out
= ast_frame_header_new()))
376 out
->frametype
= fr
->frametype
;
377 out
->subclass
= fr
->subclass
;
378 out
->datalen
= fr
->datalen
;
379 out
->samples
= fr
->samples
;
380 out
->offset
= fr
->offset
;
381 out
->data
= fr
->data
;
382 /* Copy the timing data */
383 out
->has_timing_info
= fr
->has_timing_info
;
384 if (fr
->has_timing_info
) {
387 out
->seqno
= fr
->seqno
;
392 if (!(fr
->mallocd
& AST_MALLOCD_SRC
)) {
394 if (!(out
->src
= ast_strdup(fr
->src
))) {
403 if (!(fr
->mallocd
& AST_MALLOCD_DATA
)) {
404 if (!(newdata
= ast_malloc(fr
->datalen
+ AST_FRIENDLY_OFFSET
))) {
405 if (out
->src
!= fr
->src
)
406 free((void *) out
->src
);
411 newdata
+= AST_FRIENDLY_OFFSET
;
412 out
->offset
= AST_FRIENDLY_OFFSET
;
413 out
->datalen
= fr
->datalen
;
414 memcpy(newdata
, fr
->data
, fr
->datalen
);
418 out
->mallocd
= AST_MALLOCD_HDR
| AST_MALLOCD_SRC
| AST_MALLOCD_DATA
;
423 struct ast_frame
*ast_frdup(const struct ast_frame
*f
)
425 struct ast_frame_cache
*frames
;
426 struct ast_frame
*out
= NULL
;
430 /* Start with standard stuff */
431 len
= sizeof(*out
) + AST_FRIENDLY_OFFSET
+ f
->datalen
;
432 /* If we have a source, add space for it */
434 * XXX Watch out here - if we receive a src which is not terminated
435 * properly, we can be easily attacked. Should limit the size we deal with.
438 srclen
= strlen(f
->src
);
442 if ((frames
= ast_threadstorage_get(&frame_cache
, sizeof(*frames
)))) {
443 AST_LIST_TRAVERSE_SAFE_BEGIN(&frames
->list
, out
, frame_list
) {
444 if (out
->mallocd_hdr_len
>= len
) {
445 size_t mallocd_len
= out
->mallocd_hdr_len
;
446 AST_LIST_REMOVE_CURRENT(&frames
->list
, frame_list
);
447 memset(out
, 0, sizeof(*out
));
448 out
->mallocd_hdr_len
= mallocd_len
;
454 AST_LIST_TRAVERSE_SAFE_END
457 if (!(buf
= ast_calloc(1, len
)))
460 out
->mallocd_hdr_len
= len
;
463 out
->frametype
= f
->frametype
;
464 out
->subclass
= f
->subclass
;
465 out
->datalen
= f
->datalen
;
466 out
->samples
= f
->samples
;
467 out
->delivery
= f
->delivery
;
468 /* Set us as having malloc'd header only, so it will eventually
470 out
->mallocd
= AST_MALLOCD_HDR
;
471 out
->offset
= AST_FRIENDLY_OFFSET
;
473 out
->data
= buf
+ sizeof(*out
) + AST_FRIENDLY_OFFSET
;
474 memcpy(out
->data
, f
->data
, out
->datalen
);
477 out
->src
= buf
+ sizeof(*out
) + AST_FRIENDLY_OFFSET
+ f
->datalen
;
478 /* Must have space since we allocated for it */
479 strcpy((char *)out
->src
, f
->src
);
481 out
->has_timing_info
= f
->has_timing_info
;
482 if (f
->has_timing_info
) {
485 out
->seqno
= f
->seqno
;
490 void ast_swapcopy_samples(void *dst
, const void *src
, int samples
)
493 unsigned short *dst_s
= dst
;
494 const unsigned short *src_s
= src
;
496 for (i
= 0; i
< samples
; i
++)
497 dst_s
[i
] = (src_s
[i
]<<8) | (src_s
[i
]>>8);
501 struct ast_format_list
*ast_get_format_list_index(int index
)
503 return &AST_FORMAT_LIST
[index
];
506 struct ast_format_list
*ast_get_format_list(size_t *size
)
508 *size
= (sizeof(AST_FORMAT_LIST
) / sizeof(AST_FORMAT_LIST
[0]));
509 return AST_FORMAT_LIST
;
512 char* ast_getformatname(int format
)
515 char *ret
= "unknown";
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 ret
= AST_FORMAT_LIST
[x
].name
;
525 char *ast_getformatname_multiple(char *buf
, size_t size
, int format
)
529 char *start
, *end
= buf
;
533 snprintf(end
, size
, "0x%x (", format
);
538 for (x
= 0; x
< sizeof(AST_FORMAT_LIST
) / sizeof(AST_FORMAT_LIST
[0]); x
++) {
539 if (AST_FORMAT_LIST
[x
].visible
&& (AST_FORMAT_LIST
[x
].bits
& format
)) {
540 snprintf(end
, size
,"%s|",AST_FORMAT_LIST
[x
].name
);
547 snprintf(start
, size
, "nothing)");
553 static struct ast_codec_alias_table
{
556 } ast_codec_alias_table
[] = {
557 { "slinear", "slin"},
561 static const char *ast_expand_codec_alias(const char *in
)
565 for (x
= 0; x
< sizeof(ast_codec_alias_table
) / sizeof(ast_codec_alias_table
[0]); x
++) {
566 if(!strcmp(in
,ast_codec_alias_table
[x
].alias
))
567 return ast_codec_alias_table
[x
].realname
;
572 int ast_getformatbyname(const char *name
)
574 int x
, all
, format
= 0;
576 all
= strcasecmp(name
, "all") ? 0 : 1;
577 for (x
= 0; x
< sizeof(AST_FORMAT_LIST
) / sizeof(AST_FORMAT_LIST
[0]); x
++) {
578 if(AST_FORMAT_LIST
[x
].visible
&& (all
||
579 !strcasecmp(AST_FORMAT_LIST
[x
].name
,name
) ||
580 !strcasecmp(AST_FORMAT_LIST
[x
].name
,ast_expand_codec_alias(name
)))) {
581 format
|= AST_FORMAT_LIST
[x
].bits
;
590 char *ast_codec2str(int codec
)
593 char *ret
= "unknown";
594 for (x
= 0; x
< sizeof(AST_FORMAT_LIST
) / sizeof(AST_FORMAT_LIST
[0]); x
++) {
595 if(AST_FORMAT_LIST
[x
].visible
&& AST_FORMAT_LIST
[x
].bits
== codec
) {
596 ret
= AST_FORMAT_LIST
[x
].desc
;
603 static int show_codecs_deprecated(int fd
, int argc
, char *argv
[])
608 if ((argc
< 2) || (argc
> 3))
609 return RESULT_SHOWUSAGE
;
611 if (!ast_opt_dont_warn
)
612 ast_cli(fd
, "Disclaimer: this command is for informational purposes only.\n"
613 "\tIt does not indicate anything about your configuration.\n");
615 ast_cli(fd
, "%11s %9s %10s TYPE %8s %s\n","INT","BINARY","HEX","NAME","DESC");
616 ast_cli(fd
, "--------------------------------------------------------------------------------\n");
617 if ((argc
== 2) || (!strcasecmp(argv
[1],"audio"))) {
620 snprintf(hex
,25,"(0x%x)",1<<i
);
621 ast_cli(fd
, "%11u (1 << %2d) %10s audio %8s (%s)\n",1 << i
,i
,hex
,ast_getformatname(1<<i
),ast_codec2str(1<<i
));
625 if ((argc
== 2) || (!strcasecmp(argv
[1],"image"))) {
627 for (i
=16;i
<18;i
++) {
628 snprintf(hex
,25,"(0x%x)",1<<i
);
629 ast_cli(fd
, "%11u (1 << %2d) %10s image %8s (%s)\n",1 << i
,i
,hex
,ast_getformatname(1<<i
),ast_codec2str(1<<i
));
633 if ((argc
== 2) || (!strcasecmp(argv
[1],"video"))) {
635 for (i
=18;i
<22;i
++) {
636 snprintf(hex
,25,"(0x%x)",1<<i
);
637 ast_cli(fd
, "%11u (1 << %2d) %10s video %8s (%s)\n",1 << i
,i
,hex
,ast_getformatname(1<<i
),ast_codec2str(1<<i
));
642 return RESULT_SHOWUSAGE
;
644 return RESULT_SUCCESS
;
647 static int show_codecs(int fd
, int argc
, char *argv
[])
652 if ((argc
< 3) || (argc
> 4))
653 return RESULT_SHOWUSAGE
;
655 if (!ast_opt_dont_warn
)
656 ast_cli(fd
, "Disclaimer: this command is for informational purposes only.\n"
657 "\tIt does not indicate anything about your configuration.\n");
659 ast_cli(fd
, "%11s %9s %10s TYPE %8s %s\n","INT","BINARY","HEX","NAME","DESC");
660 ast_cli(fd
, "--------------------------------------------------------------------------------\n");
661 if ((argc
== 3) || (!strcasecmp(argv
[3],"audio"))) {
664 snprintf(hex
,25,"(0x%x)",1<<i
);
665 ast_cli(fd
, "%11u (1 << %2d) %10s audio %8s (%s)\n",1 << i
,i
,hex
,ast_getformatname(1<<i
),ast_codec2str(1<<i
));
669 if ((argc
== 3) || (!strcasecmp(argv
[3],"image"))) {
671 for (i
=16;i
<18;i
++) {
672 snprintf(hex
,25,"(0x%x)",1<<i
);
673 ast_cli(fd
, "%11u (1 << %2d) %10s image %8s (%s)\n",1 << i
,i
,hex
,ast_getformatname(1<<i
),ast_codec2str(1<<i
));
677 if ((argc
== 3) || (!strcasecmp(argv
[3],"video"))) {
679 for (i
=18;i
<22;i
++) {
680 snprintf(hex
,25,"(0x%x)",1<<i
);
681 ast_cli(fd
, "%11u (1 << %2d) %10s video %8s (%s)\n",1 << i
,i
,hex
,ast_getformatname(1<<i
),ast_codec2str(1<<i
));
686 return RESULT_SHOWUSAGE
;
688 return RESULT_SUCCESS
;
691 static char frame_show_codecs_usage
[] =
692 "Usage: core show codecs [audio|video|image]\n"
693 " Displays codec mapping\n";
695 static int show_codec_n_deprecated(int fd
, int argc
, char *argv
[])
697 int codec
, i
, found
=0;
700 return RESULT_SHOWUSAGE
;
702 if (sscanf(argv
[2],"%d",&codec
) != 1)
703 return RESULT_SHOWUSAGE
;
705 for (i
= 0; i
< 32; i
++)
706 if (codec
& (1 << i
)) {
708 ast_cli(fd
, "%11u (1 << %2d) %s\n",1 << i
,i
,ast_codec2str(1<<i
));
712 ast_cli(fd
, "Codec %d not found\n", codec
);
714 return RESULT_SUCCESS
;
717 static int show_codec_n(int fd
, int argc
, char *argv
[])
719 int codec
, i
, found
=0;
722 return RESULT_SHOWUSAGE
;
724 if (sscanf(argv
[3],"%d",&codec
) != 1)
725 return RESULT_SHOWUSAGE
;
727 for (i
= 0; i
< 32; i
++)
728 if (codec
& (1 << i
)) {
730 ast_cli(fd
, "%11u (1 << %2d) %s\n",1 << i
,i
,ast_codec2str(1<<i
));
734 ast_cli(fd
, "Codec %d not found\n", codec
);
736 return RESULT_SUCCESS
;
739 static char frame_show_codec_n_usage
[] =
740 "Usage: core show codec <number>\n"
741 " Displays codec mapping\n";
743 /*! Dump a frame for debugging purposes */
744 void ast_frame_dump(const char *name
, struct ast_frame
*f
, char *prefix
)
746 const char noname
[] = "unknown";
747 char ftype
[40] = "Unknown Frametype";
749 char subclass
[40] = "Unknown Subclass";
751 char moreinfo
[40] = "";
761 ast_verbose("%s [ %s (NULL) ] [%s]\n",
762 term_color(cp
, prefix
, COLOR_BRMAGENTA
, COLOR_BLACK
, sizeof(cp
)),
763 term_color(cft
, "HANGUP", COLOR_BRRED
, COLOR_BLACK
, sizeof(cft
)),
764 term_color(cn
, name
, COLOR_YELLOW
, COLOR_BLACK
, sizeof(cn
)));
767 /* XXX We should probably print one each of voice and video when the format changes XXX */
768 if (f
->frametype
== AST_FRAME_VOICE
)
770 if (f
->frametype
== AST_FRAME_VIDEO
)
772 switch(f
->frametype
) {
773 case AST_FRAME_DTMF_BEGIN
:
774 strcpy(ftype
, "DTMF Begin");
775 subclass
[0] = f
->subclass
;
778 case AST_FRAME_DTMF_END
:
779 strcpy(ftype
, "DTMF End");
780 subclass
[0] = f
->subclass
;
783 case AST_FRAME_CONTROL
:
784 strcpy(ftype
, "Control");
785 switch(f
->subclass
) {
786 case AST_CONTROL_HANGUP
:
787 strcpy(subclass
, "Hangup");
789 case AST_CONTROL_RING
:
790 strcpy(subclass
, "Ring");
792 case AST_CONTROL_RINGING
:
793 strcpy(subclass
, "Ringing");
795 case AST_CONTROL_ANSWER
:
796 strcpy(subclass
, "Answer");
798 case AST_CONTROL_BUSY
:
799 strcpy(subclass
, "Busy");
801 case AST_CONTROL_TAKEOFFHOOK
:
802 strcpy(subclass
, "Take Off Hook");
804 case AST_CONTROL_OFFHOOK
:
805 strcpy(subclass
, "Line Off Hook");
807 case AST_CONTROL_CONGESTION
:
808 strcpy(subclass
, "Congestion");
810 case AST_CONTROL_FLASH
:
811 strcpy(subclass
, "Flash");
813 case AST_CONTROL_WINK
:
814 strcpy(subclass
, "Wink");
816 case AST_CONTROL_OPTION
:
817 strcpy(subclass
, "Option");
819 case AST_CONTROL_RADIO_KEY
:
820 strcpy(subclass
, "Key Radio");
822 case AST_CONTROL_RADIO_UNKEY
:
823 strcpy(subclass
, "Unkey Radio");
826 strcpy(subclass
, "Stop generators");
829 snprintf(subclass
, sizeof(subclass
), "Unknown control '%d'", f
->subclass
);
833 strcpy(ftype
, "Null Frame");
834 strcpy(subclass
, "N/A");
837 /* Should never happen */
838 strcpy(ftype
, "IAX Specific");
839 snprintf(subclass
, sizeof(subclass
), "IAX Frametype %d", f
->subclass
);
842 strcpy(ftype
, "Text");
843 strcpy(subclass
, "N/A");
844 ast_copy_string(moreinfo
, f
->data
, sizeof(moreinfo
));
846 case AST_FRAME_IMAGE
:
847 strcpy(ftype
, "Image");
848 snprintf(subclass
, sizeof(subclass
), "Image format %s\n", ast_getformatname(f
->subclass
));
851 strcpy(ftype
, "HTML");
852 switch(f
->subclass
) {
854 strcpy(subclass
, "URL");
855 ast_copy_string(moreinfo
, f
->data
, sizeof(moreinfo
));
858 strcpy(subclass
, "Data");
861 strcpy(subclass
, "Begin");
864 strcpy(subclass
, "End");
866 case AST_HTML_LDCOMPLETE
:
867 strcpy(subclass
, "Load Complete");
869 case AST_HTML_NOSUPPORT
:
870 strcpy(subclass
, "No Support");
872 case AST_HTML_LINKURL
:
873 strcpy(subclass
, "Link URL");
874 ast_copy_string(moreinfo
, f
->data
, sizeof(moreinfo
));
876 case AST_HTML_UNLINK
:
877 strcpy(subclass
, "Unlink");
879 case AST_HTML_LINKREJECT
:
880 strcpy(subclass
, "Link Reject");
883 snprintf(subclass
, sizeof(subclass
), "Unknown HTML frame '%d'\n", f
->subclass
);
887 case AST_FRAME_MODEM
:
888 strcpy(ftype
, "Modem");
889 switch (f
->subclass
) {
891 strcpy(subclass
, "T.38");
894 strcpy(subclass
, "V.150");
897 snprintf(subclass
, sizeof(subclass
), "Unknown MODEM frame '%d'\n", f
->subclass
);
902 snprintf(ftype
, sizeof(ftype
), "Unknown Frametype '%d'", f
->frametype
);
904 if (!ast_strlen_zero(moreinfo
))
905 ast_verbose("%s [ TYPE: %s (%d) SUBCLASS: %s (%d) '%s' ] [%s]\n",
906 term_color(cp
, prefix
, COLOR_BRMAGENTA
, COLOR_BLACK
, sizeof(cp
)),
907 term_color(cft
, ftype
, COLOR_BRRED
, COLOR_BLACK
, sizeof(cft
)),
909 term_color(csub
, subclass
, COLOR_BRCYAN
, COLOR_BLACK
, sizeof(csub
)),
911 term_color(cmn
, moreinfo
, COLOR_BRGREEN
, COLOR_BLACK
, sizeof(cmn
)),
912 term_color(cn
, name
, COLOR_YELLOW
, COLOR_BLACK
, sizeof(cn
)));
914 ast_verbose("%s [ TYPE: %s (%d) SUBCLASS: %s (%d) ] [%s]\n",
915 term_color(cp
, prefix
, COLOR_BRMAGENTA
, COLOR_BLACK
, sizeof(cp
)),
916 term_color(cft
, ftype
, COLOR_BRRED
, COLOR_BLACK
, sizeof(cft
)),
918 term_color(csub
, subclass
, COLOR_BRCYAN
, COLOR_BLACK
, sizeof(csub
)),
920 term_color(cn
, name
, COLOR_YELLOW
, COLOR_BLACK
, sizeof(cn
)));
925 static int show_frame_stats_deprecated(int fd
, int argc
, char *argv
[])
930 return RESULT_SHOWUSAGE
;
931 AST_LIST_LOCK(&headerlist
);
932 ast_cli(fd
, " Framer Statistics \n");
933 ast_cli(fd
, "---------------------------\n");
934 ast_cli(fd
, "Total allocated headers: %d\n", headers
);
935 ast_cli(fd
, "Queue Dump:\n");
936 AST_LIST_TRAVERSE(&headerlist
, f
, frame_list
)
937 ast_cli(fd
, "%d. Type %d, subclass %d from %s\n", x
++, f
->frametype
, f
->subclass
, f
->src
? f
->src
: "<Unknown>");
938 AST_LIST_UNLOCK(&headerlist
);
939 return RESULT_SUCCESS
;
942 static int show_frame_stats(int fd
, int argc
, char *argv
[])
947 return RESULT_SHOWUSAGE
;
948 AST_LIST_LOCK(&headerlist
);
949 ast_cli(fd
, " Framer Statistics \n");
950 ast_cli(fd
, "---------------------------\n");
951 ast_cli(fd
, "Total allocated headers: %d\n", headers
);
952 ast_cli(fd
, "Queue Dump:\n");
953 AST_LIST_TRAVERSE(&headerlist
, f
, frame_list
)
954 ast_cli(fd
, "%d. Type %d, subclass %d from %s\n", x
++, f
->frametype
, f
->subclass
, f
->src
? f
->src
: "<Unknown>");
955 AST_LIST_UNLOCK(&headerlist
);
956 return RESULT_SUCCESS
;
959 static char frame_stats_usage
[] =
960 "Usage: core show frame stats\n"
961 " Displays debugging statistics from framer\n";
964 /* Builtin Asterisk CLI-commands for debugging */
965 static struct ast_cli_entry cli_show_codecs
= {
966 { "show", "codecs", NULL
},
967 show_codecs_deprecated
, NULL
,
970 static struct ast_cli_entry cli_show_audio_codecs
= {
971 { "show", "audio", "codecs", NULL
},
972 show_codecs_deprecated
, NULL
,
975 static struct ast_cli_entry cli_show_video_codecs
= {
976 { "show", "video", "codecs", NULL
},
977 show_codecs_deprecated
, NULL
,
980 static struct ast_cli_entry cli_show_image_codecs
= {
981 { "show", "image", "codecs", NULL
},
982 show_codecs_deprecated
, NULL
,
985 static struct ast_cli_entry cli_show_codec
= {
986 { "show", "codec", NULL
},
987 show_codec_n_deprecated
, NULL
,
991 static struct ast_cli_entry cli_show_frame_stats
= {
992 { "show", "frame", "stats", NULL
},
993 show_frame_stats
, NULL
,
997 static struct ast_cli_entry my_clis
[] = {
998 { { "core", "show", "codecs", NULL
},
999 show_codecs
, "Displays a list of codecs",
1000 frame_show_codecs_usage
, NULL
, &cli_show_codecs
},
1002 { { "core", "show", "audio", "codecs", NULL
},
1003 show_codecs
, "Displays a list of audio codecs",
1004 frame_show_codecs_usage
, NULL
, &cli_show_audio_codecs
},
1006 { { "core", "show", "video", "codecs", NULL
},
1007 show_codecs
, "Displays a list of video codecs",
1008 frame_show_codecs_usage
, NULL
, &cli_show_video_codecs
},
1010 { { "core", "show", "image", "codecs", NULL
},
1011 show_codecs
, "Displays a list of image codecs",
1012 frame_show_codecs_usage
, NULL
, &cli_show_image_codecs
},
1014 { { "core", "show", "codec", NULL
},
1015 show_codec_n
, "Shows a specific codec",
1016 frame_show_codec_n_usage
, NULL
, &cli_show_codec
},
1019 { { "core", "show", "frame", "stats", NULL
},
1020 show_frame_stats
, "Shows frame statistics",
1021 frame_stats_usage
, NULL
, &cli_show_frame_stats
},
1025 int init_framer(void)
1027 ast_cli_register_multiple(my_clis
, sizeof(my_clis
) / sizeof(struct ast_cli_entry
));
1031 void ast_codec_pref_convert(struct ast_codec_pref
*pref
, char *buf
, size_t size
, int right
)
1033 int x
, differential
= (int) 'A', mem
;
1047 for (x
= 0; x
< 32 ; x
++) {
1050 to
[x
] = right
? (from
[x
] + differential
) : (from
[x
] - differential
);
1054 int ast_codec_pref_string(struct ast_codec_pref
*pref
, char *buf
, size_t size
)
1057 size_t total_len
, slen
;
1064 for(x
= 0; x
< 32 ; x
++) {
1067 if(!(codec
= ast_codec_pref_index(pref
,x
)))
1069 if((formatname
= ast_getformatname(codec
))) {
1070 slen
= strlen(formatname
);
1071 if(slen
> total_len
)
1073 strncat(buf
,formatname
,total_len
);
1076 if(total_len
&& x
< 31 && ast_codec_pref_index(pref
, x
+ 1)) {
1077 strncat(buf
,"|",total_len
);
1082 strncat(buf
,")",total_len
);
1086 return size
- total_len
;
1089 int ast_codec_pref_index(struct ast_codec_pref
*pref
, int index
)
1094 if((index
>= 0) && (index
< sizeof(pref
->order
))) {
1095 slot
= pref
->order
[index
];
1098 return slot
? AST_FORMAT_LIST
[slot
-1].bits
: 0;
1101 /*! \brief Remove codec from pref list */
1102 void ast_codec_pref_remove(struct ast_codec_pref
*pref
, int format
)
1104 struct ast_codec_pref oldorder
;
1112 memcpy(&oldorder
, pref
, sizeof(oldorder
));
1113 memset(pref
, 0, sizeof(*pref
));
1115 for (x
= 0; x
< sizeof(AST_FORMAT_LIST
) / sizeof(AST_FORMAT_LIST
[0]); x
++) {
1116 slot
= oldorder
.order
[x
];
1117 size
= oldorder
.framing
[x
];
1120 if(AST_FORMAT_LIST
[slot
-1].bits
!= format
) {
1121 pref
->order
[y
] = slot
;
1122 pref
->framing
[y
++] = size
;
1128 /*! \brief Append codec to list */
1129 int ast_codec_pref_append(struct ast_codec_pref
*pref
, int format
)
1131 int x
, newindex
= -1;
1133 ast_codec_pref_remove(pref
, format
);
1135 for (x
= 0; x
< sizeof(AST_FORMAT_LIST
) / sizeof(AST_FORMAT_LIST
[0]); x
++) {
1136 if(AST_FORMAT_LIST
[x
].bits
== format
) {
1143 for (x
= 0; x
< sizeof(AST_FORMAT_LIST
) / sizeof(AST_FORMAT_LIST
[0]); x
++) {
1144 if(!pref
->order
[x
]) {
1145 pref
->order
[x
] = newindex
;
1155 /*! \brief Set packet size for codec */
1156 int ast_codec_pref_setsize(struct ast_codec_pref
*pref
, int format
, int framems
)
1160 for (x
= 0; x
< sizeof(AST_FORMAT_LIST
) / sizeof(AST_FORMAT_LIST
[0]); x
++) {
1161 if(AST_FORMAT_LIST
[x
].bits
== format
) {
1170 /* size validation */
1172 framems
= AST_FORMAT_LIST
[index
].def_ms
;
1174 if(AST_FORMAT_LIST
[index
].inc_ms
&& framems
% AST_FORMAT_LIST
[index
].inc_ms
) /* avoid division by zero */
1175 framems
-= framems
% AST_FORMAT_LIST
[index
].inc_ms
;
1177 if(framems
< AST_FORMAT_LIST
[index
].min_ms
)
1178 framems
= AST_FORMAT_LIST
[index
].min_ms
;
1180 if(framems
> AST_FORMAT_LIST
[index
].max_ms
)
1181 framems
= AST_FORMAT_LIST
[index
].max_ms
;
1184 for (x
= 0; x
< sizeof(AST_FORMAT_LIST
) / sizeof(AST_FORMAT_LIST
[0]); x
++) {
1185 if(pref
->order
[x
] == (index
+ 1)) {
1186 pref
->framing
[x
] = framems
;
1194 /*! \brief Get packet size for codec */
1195 struct ast_format_list
ast_codec_pref_getsize(struct ast_codec_pref
*pref
, int format
)
1197 int x
, index
= -1, framems
= 0;
1198 struct ast_format_list fmt
;
1200 for (x
= 0; x
< sizeof(AST_FORMAT_LIST
) / sizeof(AST_FORMAT_LIST
[0]); x
++) {
1201 if(AST_FORMAT_LIST
[x
].bits
== format
) {
1202 fmt
= AST_FORMAT_LIST
[x
];
1208 for (x
= 0; x
< sizeof(AST_FORMAT_LIST
) / sizeof(AST_FORMAT_LIST
[0]); x
++) {
1209 if(pref
->order
[x
] == (index
+ 1)) {
1210 framems
= pref
->framing
[x
];
1215 /* size validation */
1217 framems
= AST_FORMAT_LIST
[index
].def_ms
;
1219 if(AST_FORMAT_LIST
[index
].inc_ms
&& framems
% AST_FORMAT_LIST
[index
].inc_ms
) /* avoid division by zero */
1220 framems
-= framems
% AST_FORMAT_LIST
[index
].inc_ms
;
1222 if(framems
< AST_FORMAT_LIST
[index
].min_ms
)
1223 framems
= AST_FORMAT_LIST
[index
].min_ms
;
1225 if(framems
> AST_FORMAT_LIST
[index
].max_ms
)
1226 framems
= AST_FORMAT_LIST
[index
].max_ms
;
1228 fmt
.cur_ms
= framems
;
1233 /*! \brief Pick a codec */
1234 int ast_codec_choose(struct ast_codec_pref
*pref
, int formats
, int find_best
)
1236 int x
, ret
= 0, slot
;
1238 for (x
= 0; x
< sizeof(AST_FORMAT_LIST
) / sizeof(AST_FORMAT_LIST
[0]); x
++) {
1239 slot
= pref
->order
[x
];
1243 if (formats
& AST_FORMAT_LIST
[slot
-1].bits
) {
1244 ret
= AST_FORMAT_LIST
[slot
-1].bits
;
1248 if(ret
& AST_FORMAT_AUDIO_MASK
)
1251 if (option_debug
> 3)
1252 ast_log(LOG_DEBUG
, "Could not find preferred codec - %s\n", find_best
? "Going for the best codec" : "Returning zero codec");
1254 return find_best
? ast_best_codec(formats
) : 0;
1257 void ast_parse_allow_disallow(struct ast_codec_pref
*pref
, int *mask
, const char *list
, int allowing
)
1259 char *parse
= NULL
, *this = NULL
, *psize
= NULL
;
1260 int format
= 0, framems
= 0;
1262 parse
= ast_strdupa(list
);
1263 while ((this = strsep(&parse
, ","))) {
1265 if ((psize
= strrchr(this, ':'))) {
1268 ast_log(LOG_DEBUG
,"Packetization for codec: %s is %s\n", this, psize
);
1269 framems
= atoi(psize
);
1273 if (!(format
= ast_getformatbyname(this))) {
1274 ast_log(LOG_WARNING
, "Cannot %s unknown format '%s'\n", allowing
? "allow" : "disallow", this);
1285 /* Set up a preference list for audio. Do not include video in preferences
1286 since we can not transcode video and have to use whatever is offered
1288 if (pref
&& (format
& AST_FORMAT_AUDIO_MASK
)) {
1289 if (strcasecmp(this, "all")) {
1291 ast_codec_pref_append(pref
, format
);
1292 ast_codec_pref_setsize(pref
, format
, framems
);
1295 ast_codec_pref_remove(pref
, format
);
1296 } else if (!allowing
) {
1297 memset(pref
, 0, sizeof(*pref
));
1303 static int g723_len(unsigned char buf
)
1305 enum frame_type type
= buf
& TYPE_MASK
;
1321 ast_log(LOG_WARNING
, "Badly encoded frame (%d)\n", type
);
1326 static int g723_samples(unsigned char *buf
, int maxlen
)
1331 while(pos
< maxlen
) {
1332 res
= g723_len(buf
[pos
]);
1341 static unsigned char get_n_bits_at(unsigned char *data
, int n
, int bit
)
1343 int byte
= bit
/ 8; /* byte containing first bit */
1344 int rem
= 8 - (bit
% 8); /* remaining bits in first byte */
1345 unsigned char ret
= 0;
1347 if (n
<= 0 || n
> 8)
1351 ret
= (data
[byte
] << (n
- rem
));
1352 ret
|= (data
[byte
+ 1] >> (8 - n
+ rem
));
1354 ret
= (data
[byte
] >> (rem
- n
));
1357 return (ret
& (0xff >> (8 - n
)));
1360 static int speex_get_wb_sz_at(unsigned char *data
, int len
, int bit
)
1362 static int SpeexWBSubModeSz
[] = {
1368 /* skip up to two wideband frames */
1369 if (((len
* 8 - off
) >= 5) &&
1370 get_n_bits_at(data
, 1, off
)) {
1371 c
= get_n_bits_at(data
, 3, off
+ 1);
1372 off
+= SpeexWBSubModeSz
[c
];
1374 if (((len
* 8 - off
) >= 5) &&
1375 get_n_bits_at(data
, 1, off
)) {
1376 c
= get_n_bits_at(data
, 3, off
+ 1);
1377 off
+= SpeexWBSubModeSz
[c
];
1379 if (((len
* 8 - off
) >= 5) &&
1380 get_n_bits_at(data
, 1, off
)) {
1381 ast_log(LOG_WARNING
, "Encountered corrupt speex frame; too many wideband frames in a row.\n");
1390 static int speex_samples(unsigned char *data
, int len
)
1392 static int SpeexSubModeSz
[] = {
1397 static int SpeexInBandSz
[] = {
1407 while ((len
* 8 - bit
) >= 5) {
1408 /* skip wideband frames */
1409 off
= speex_get_wb_sz_at(data
, len
, bit
);
1411 ast_log(LOG_WARNING
, "Had error while reading wideband frames for speex samples\n");
1416 if ((len
* 8 - bit
) < 5) {
1417 ast_log(LOG_WARNING
, "Not enough bits remaining after wide band for speex samples.\n");
1421 /* get control bits */
1422 c
= get_n_bits_at(data
, 5, bit
);
1428 } else if (c
== 14) {
1429 /* in-band signal; next 4 bits contain signal id */
1430 c
= get_n_bits_at(data
, 4, bit
);
1432 bit
+= SpeexInBandSz
[c
];
1433 } else if (c
== 13) {
1434 /* user in-band; next 5 bits contain msg len */
1435 c
= get_n_bits_at(data
, 5, bit
);
1442 /* skip number bits for submode (less the 5 control bits) */
1443 bit
+= SpeexSubModeSz
[c
] - 5;
1444 cnt
+= 160; /* new frame */
1450 int ast_codec_get_samples(struct ast_frame
*f
)
1453 switch(f
->subclass
) {
1454 case AST_FORMAT_SPEEX
:
1455 samples
= speex_samples(f
->data
, f
->datalen
);
1457 case AST_FORMAT_G723_1
:
1458 samples
= g723_samples(f
->data
, f
->datalen
);
1460 case AST_FORMAT_ILBC
:
1461 samples
= 240 * (f
->datalen
/ 50);
1463 case AST_FORMAT_GSM
:
1464 samples
= 160 * (f
->datalen
/ 33);
1466 case AST_FORMAT_G729A
:
1467 samples
= f
->datalen
* 8;
1469 case AST_FORMAT_SLINEAR
:
1470 samples
= f
->datalen
/ 2;
1472 case AST_FORMAT_LPC10
:
1473 /* assumes that the RTP packet contains one LPC10 frame */
1475 samples
+= (((char *)(f
->data
))[7] & 0x1) * 8;
1477 case AST_FORMAT_ULAW
:
1478 case AST_FORMAT_ALAW
:
1479 case AST_FORMAT_G722
:
1480 samples
= f
->datalen
;
1482 case AST_FORMAT_ADPCM
:
1483 case AST_FORMAT_G726
:
1484 case AST_FORMAT_G726_AAL2
:
1485 samples
= f
->datalen
* 2;
1488 ast_log(LOG_WARNING
, "Unable to calculate samples for format %s\n", ast_getformatname(f
->subclass
));
1493 int ast_codec_get_len(int format
, int samples
)
1497 /* XXX Still need speex, g723, and lpc10 XXX */
1499 case AST_FORMAT_ILBC
:
1500 len
= (samples
/ 240) * 50;
1502 case AST_FORMAT_GSM
:
1503 len
= (samples
/ 160) * 33;
1505 case AST_FORMAT_G729A
:
1508 case AST_FORMAT_SLINEAR
:
1511 case AST_FORMAT_ULAW
:
1512 case AST_FORMAT_ALAW
:
1515 case AST_FORMAT_ADPCM
:
1516 case AST_FORMAT_G726
:
1517 case AST_FORMAT_G726_AAL2
:
1521 ast_log(LOG_WARNING
, "Unable to calculate sample length for format %s\n", ast_getformatname(format
));
1527 int ast_frame_adjust_volume(struct ast_frame
*f
, int adjustment
)
1530 short *fdata
= f
->data
;
1531 short adjust_value
= abs(adjustment
);
1533 if ((f
->frametype
!= AST_FRAME_VOICE
) || (f
->subclass
!= AST_FORMAT_SLINEAR
))
1539 for (count
= 0; count
< f
->samples
; count
++) {
1540 if (adjustment
> 0) {
1541 ast_slinear_saturated_multiply(&fdata
[count
], &adjust_value
);
1542 } else if (adjustment
< 0) {
1543 ast_slinear_saturated_divide(&fdata
[count
], &adjust_value
);
1550 int ast_frame_slinear_sum(struct ast_frame
*f1
, struct ast_frame
*f2
)
1553 short *data1
, *data2
;
1555 if ((f1
->frametype
!= AST_FRAME_VOICE
) || (f1
->subclass
!= AST_FORMAT_SLINEAR
))
1558 if ((f2
->frametype
!= AST_FRAME_VOICE
) || (f2
->subclass
!= AST_FORMAT_SLINEAR
))
1561 if (f1
->samples
!= f2
->samples
)
1564 for (count
= 0, data1
= f1
->data
, data2
= f2
->data
;
1565 count
< f1
->samples
;
1566 count
++, data1
++, data2
++)
1567 ast_slinear_saturated_add(data1
, data2
);