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"
49 static AST_LIST_HEAD_STATIC(headerlist
, ast_frame
);
52 #if !defined(LOW_MEMORY)
53 static void frame_cache_cleanup(void *data
);
55 /*! \brief A per-thread cache of frame headers */
56 AST_THREADSTORAGE_CUSTOM(frame_cache
, frame_cache_init
, frame_cache_cleanup
);
59 * \brief Maximum ast_frame cache size
61 * In most cases where the frame header cache will be useful, the size
62 * of the cache will stay very small. However, it is not always the case that
63 * the same thread that allocates the frame will be the one freeing them, so
64 * sometimes a thread will never have any frames in its cache, or the cache
65 * will never be pulled from. For the latter case, we limit the maximum size.
67 #define FRAME_CACHE_MAX_SIZE 10
69 /*! \brief This is just so ast_frames, a list head struct for holding a list of
70 * ast_frame structures, is defined. */
71 AST_LIST_HEAD_NOLOCK(ast_frames
, ast_frame
);
73 struct ast_frame_cache
{
74 struct ast_frames list
;
79 #define SMOOTHER_SIZE 8000
84 TYPE_SILENCE
, /* 0x2 */
85 TYPE_DONTSEND
/* 0x3 */
94 int optimizablestream
;
98 struct timeval delivery
;
99 char data
[SMOOTHER_SIZE
];
100 char framedata
[SMOOTHER_SIZE
+ AST_FRIENDLY_OFFSET
];
101 struct ast_frame
*opt
;
105 /*! \brief Definition of supported media formats (codecs) */
106 static struct ast_format_list AST_FORMAT_LIST
[] = { /*!< Bit number: comment - Bit numbers are hard coded in show_codec() */
107 { 1, AST_FORMAT_G723_1
, "g723" , "G.723.1", 24, 30, 300, 30, 30 }, /*!< 1 */
108 { 1, AST_FORMAT_GSM
, "gsm" , "GSM", 33, 20, 300, 20, 20 }, /*!< 2: codec_gsm.c */
109 { 1, AST_FORMAT_ULAW
, "ulaw", "G.711 u-law", 80, 10, 150, 10, 20 }, /*!< 3: codec_ulaw.c */
110 { 1, AST_FORMAT_ALAW
, "alaw", "G.711 A-law", 80, 10, 150, 10, 20 }, /*!< 4: codec_alaw.c */
111 { 1, AST_FORMAT_G726
, "g726", "G.726 RFC3551", 40, 10, 300, 10, 20 }, /*!< 5: codec_g726.c */
112 { 1, AST_FORMAT_ADPCM
, "adpcm" , "ADPCM", 40, 10, 300, 10, 20 }, /*!< 6: codec_adpcm.c */
113 { 1, AST_FORMAT_SLINEAR
, "slin", "16 bit Signed Linear PCM", 160, 10, 70, 10, 20, AST_SMOOTHER_FLAG_BE
}, /*!< 7 */
114 { 1, AST_FORMAT_LPC10
, "lpc10", "LPC10", 7, 20, 20, 20, 20 }, /*!< 8: codec_lpc10.c */
115 { 1, AST_FORMAT_G729A
, "g729", "G.729A", 10, 10, 230, 10, 20, AST_SMOOTHER_FLAG_G729
}, /*!< 9: Binary commercial distribution */
116 { 1, AST_FORMAT_SPEEX
, "speex", "SpeeX", 10, 10, 60, 10, 20 }, /*!< 10: codec_speex.c */
117 { 1, AST_FORMAT_ILBC
, "ilbc", "iLBC", 50, 30, 30, 30, 30 }, /*!< 11: codec_ilbc.c */ /* inc=30ms - workaround */
118 { 1, AST_FORMAT_G726_AAL2
, "g726aal2", "G.726 AAL2", 40, 10, 300, 10, 20 }, /*!< 12: codec_g726.c */
119 { 1, AST_FORMAT_G722
, "g722", "G722"}, /*!< 13 */
120 { 0, 0, "nothing", "undefined" },
121 { 0, 0, "nothing", "undefined" },
122 { 0, 0, "nothing", "undefined" },
123 { 0, 0, "nothing", "undefined" },
124 { 0, AST_FORMAT_MAX_AUDIO
, "maxaudio", "Maximum audio format" },
125 { 1, AST_FORMAT_JPEG
, "jpeg", "JPEG image"}, /*!< 17: See format_jpeg.c */
126 { 1, AST_FORMAT_PNG
, "png", "PNG image"}, /*!< 18: Image format */
127 { 1, AST_FORMAT_H261
, "h261", "H.261 Video" }, /*!< 19: Video Passthrough */
128 { 1, AST_FORMAT_H263
, "h263", "H.263 Video" }, /*!< 20: Passthrough support, see format_h263.c */
129 { 1, AST_FORMAT_H263_PLUS
, "h263p", "H.263+ Video" }, /*!< 21: See format_h263.c */
130 { 1, AST_FORMAT_H264
, "h264", "H.264 Video" }, /*!< 22: Passthrough support, see format_h263.c */
131 { 0, 0, "nothing", "undefined" },
132 { 0, 0, "nothing", "undefined" },
133 { 0, 0, "nothing", "undefined" },
134 { 0, AST_FORMAT_MAX_VIDEO
, "maxvideo", "Maximum video format" },
137 struct ast_frame ast_null_frame
= { AST_FRAME_NULL
, };
139 void ast_smoother_reset(struct ast_smoother
*s
, int size
)
141 memset(s
, 0, sizeof(*s
));
145 struct ast_smoother
*ast_smoother_new(int size
)
147 struct ast_smoother
*s
;
150 if ((s
= ast_malloc(sizeof(*s
))))
151 ast_smoother_reset(s
, size
);
155 int ast_smoother_get_flags(struct ast_smoother
*s
)
160 void ast_smoother_set_flags(struct ast_smoother
*s
, int flags
)
165 int ast_smoother_test_flag(struct ast_smoother
*s
, int flag
)
167 return (s
->flags
& flag
);
170 int __ast_smoother_feed(struct ast_smoother
*s
, struct ast_frame
*f
, int swap
)
172 if (f
->frametype
!= AST_FRAME_VOICE
) {
173 ast_log(LOG_WARNING
, "Huh? Can't smooth a non-voice frame!\n");
177 s
->format
= f
->subclass
;
178 s
->samplesperbyte
= (float)f
->samples
/ (float)f
->datalen
;
179 } else if (s
->format
!= f
->subclass
) {
180 ast_log(LOG_WARNING
, "Smoother was working on %d format frames, now trying to feed %d?\n", s
->format
, f
->subclass
);
183 if (s
->len
+ f
->datalen
> SMOOTHER_SIZE
) {
184 ast_log(LOG_WARNING
, "Out of smoother space\n");
187 if (((f
->datalen
== s
->size
) || ((f
->datalen
< 10) && (s
->flags
& AST_SMOOTHER_FLAG_G729
)))
188 && !s
->opt
&& (f
->offset
>= AST_MIN_OFFSET
)) {
190 /* Optimize by sending the frame we just got
191 on the next read, thus eliminating the douple
194 ast_swapcopy_samples(f
->data
, f
->data
, f
->samples
);
198 s
->optimizablestream
++;
199 if (s
->optimizablestream
> 10) {
200 /* For the past 10 rounds, we have input and output
201 frames of the correct size for this smoother, yet
202 we were unable to optimize because there was still
203 some cruft left over. Lets just drop the cruft so
204 we can move to a fully optimized path */
206 ast_swapcopy_samples(f
->data
, f
->data
, f
->samples
);
213 s
->optimizablestream
= 0;
214 if (s
->flags
& AST_SMOOTHER_FLAG_G729
) {
216 ast_log(LOG_NOTICE
, "Dropping extra frame of G.729 since we already have a VAD frame at the end\n");
221 ast_swapcopy_samples(s
->data
+s
->len
, f
->data
, f
->samples
);
223 memcpy(s
->data
+ s
->len
, f
->data
, f
->datalen
);
224 /* If either side is empty, reset the delivery time */
225 if (!s
->len
|| ast_tvzero(f
->delivery
) || ast_tvzero(s
->delivery
)) /* XXX really ? */
226 s
->delivery
= f
->delivery
;
227 s
->len
+= f
->datalen
;
231 struct ast_frame
*ast_smoother_read(struct ast_smoother
*s
)
233 struct ast_frame
*opt
;
236 /* IF we have an optimization frame, send it */
238 if (s
->opt
->offset
< AST_FRIENDLY_OFFSET
)
239 ast_log(LOG_WARNING
, "Returning a frame of inappropriate offset (%d).\n",
246 /* Make sure we have enough data */
247 if (s
->len
< s
->size
) {
248 /* Or, if this is a G.729 frame with VAD on it, send it immediately anyway */
249 if (!((s
->flags
& AST_SMOOTHER_FLAG_G729
) && (s
->size
% 10)))
256 s
->f
.frametype
= AST_FRAME_VOICE
;
257 s
->f
.subclass
= s
->format
;
258 s
->f
.data
= s
->framedata
+ AST_FRIENDLY_OFFSET
;
259 s
->f
.offset
= AST_FRIENDLY_OFFSET
;
261 /* Samples will be improper given VAD, but with VAD the concept really doesn't even exist */
262 s
->f
.samples
= len
* s
->samplesperbyte
; /* XXX rounding */
263 s
->f
.delivery
= s
->delivery
;
265 memcpy(s
->f
.data
, s
->data
, len
);
267 /* Move remaining data to the front if applicable */
269 /* In principle this should all be fine because if we are sending
270 G.729 VAD, the next timestamp will take over anyawy */
271 memmove(s
->data
, s
->data
+ len
, s
->len
);
272 if (!ast_tvzero(s
->delivery
)) {
273 /* If we have delivery time, increment it, otherwise, leave it at 0 */
274 s
->delivery
= ast_tvadd(s
->delivery
, ast_samp2tv(s
->f
.samples
, 8000));
281 void ast_smoother_free(struct ast_smoother
*s
)
286 static struct ast_frame
*ast_frame_header_new(void)
290 #if !defined(LOW_MEMORY)
291 struct ast_frame_cache
*frames
;
293 if ((frames
= ast_threadstorage_get(&frame_cache
, sizeof(*frames
)))) {
294 if ((f
= AST_LIST_REMOVE_HEAD(&frames
->list
, frame_list
))) {
295 size_t mallocd_len
= f
->mallocd_hdr_len
;
296 memset(f
, 0, sizeof(*f
));
297 f
->mallocd_hdr_len
= mallocd_len
;
298 f
->mallocd
= AST_MALLOCD_HDR
;
303 if (!(f
= ast_calloc_cache(1, sizeof(*f
))))
306 if (!(f
= ast_calloc(1, sizeof(*f
))))
310 f
->mallocd_hdr_len
= sizeof(*f
);
312 AST_LIST_LOCK(&headerlist
);
314 AST_LIST_INSERT_HEAD(&headerlist
, f
, frame_list
);
315 AST_LIST_UNLOCK(&headerlist
);
321 #if !defined(LOW_MEMORY)
322 static void frame_cache_cleanup(void *data
)
324 struct ast_frame_cache
*frames
= data
;
327 while ((f
= AST_LIST_REMOVE_HEAD(&frames
->list
, frame_list
)))
334 void ast_frame_free(struct ast_frame
*fr
, int cache
)
339 #if !defined(LOW_MEMORY)
340 if (cache
&& fr
->mallocd
== AST_MALLOCD_HDR
) {
341 /* Cool, only the header is malloc'd, let's just cache those for now
342 * to keep things simple... */
343 struct ast_frame_cache
*frames
;
345 if ((frames
= ast_threadstorage_get(&frame_cache
, sizeof(*frames
)))
346 && frames
->size
< FRAME_CACHE_MAX_SIZE
) {
347 AST_LIST_INSERT_HEAD(&frames
->list
, fr
, frame_list
);
354 if (fr
->mallocd
& AST_MALLOCD_DATA
) {
356 free(fr
->data
- fr
->offset
);
358 if (fr
->mallocd
& AST_MALLOCD_SRC
) {
360 free((char *)fr
->src
);
362 if (fr
->mallocd
& AST_MALLOCD_HDR
) {
364 AST_LIST_LOCK(&headerlist
);
366 AST_LIST_REMOVE(&headerlist
, fr
, frame_list
);
367 AST_LIST_UNLOCK(&headerlist
);
374 * \brief 'isolates' a frame by duplicating non-malloc'ed components
375 * (header, src, data).
376 * On return all components are malloc'ed
378 struct ast_frame
*ast_frisolate(struct ast_frame
*fr
)
380 struct ast_frame
*out
;
383 if (!(fr
->mallocd
& AST_MALLOCD_HDR
)) {
384 /* Allocate a new header if needed */
385 if (!(out
= ast_frame_header_new()))
387 out
->frametype
= fr
->frametype
;
388 out
->subclass
= fr
->subclass
;
389 out
->datalen
= fr
->datalen
;
390 out
->samples
= fr
->samples
;
391 out
->offset
= fr
->offset
;
392 out
->data
= fr
->data
;
393 /* Copy the timing data */
394 out
->has_timing_info
= fr
->has_timing_info
;
395 if (fr
->has_timing_info
) {
398 out
->seqno
= fr
->seqno
;
403 if (!(fr
->mallocd
& AST_MALLOCD_SRC
)) {
405 if (!(out
->src
= ast_strdup(fr
->src
))) {
414 if (!(fr
->mallocd
& AST_MALLOCD_DATA
)) {
415 if (!(newdata
= ast_malloc(fr
->datalen
+ AST_FRIENDLY_OFFSET
))) {
416 if (out
->src
!= fr
->src
)
417 free((void *) out
->src
);
422 newdata
+= AST_FRIENDLY_OFFSET
;
423 out
->offset
= AST_FRIENDLY_OFFSET
;
424 out
->datalen
= fr
->datalen
;
425 memcpy(newdata
, fr
->data
, fr
->datalen
);
429 out
->mallocd
= AST_MALLOCD_HDR
| AST_MALLOCD_SRC
| AST_MALLOCD_DATA
;
434 struct ast_frame
*ast_frdup(const struct ast_frame
*f
)
436 struct ast_frame
*out
= NULL
;
440 #if !defined(LOW_MEMORY)
441 struct ast_frame_cache
*frames
;
444 /* Start with standard stuff */
445 len
= sizeof(*out
) + AST_FRIENDLY_OFFSET
+ f
->datalen
;
446 /* If we have a source, add space for it */
448 * XXX Watch out here - if we receive a src which is not terminated
449 * properly, we can be easily attacked. Should limit the size we deal with.
452 srclen
= strlen(f
->src
);
456 #if !defined(LOW_MEMORY)
457 if ((frames
= ast_threadstorage_get(&frame_cache
, sizeof(*frames
)))) {
458 AST_LIST_TRAVERSE_SAFE_BEGIN(&frames
->list
, out
, frame_list
) {
459 if (out
->mallocd_hdr_len
>= len
) {
460 size_t mallocd_len
= out
->mallocd_hdr_len
;
461 AST_LIST_REMOVE_CURRENT(&frames
->list
, frame_list
);
462 memset(out
, 0, sizeof(*out
));
463 out
->mallocd_hdr_len
= mallocd_len
;
469 AST_LIST_TRAVERSE_SAFE_END
474 if (!(buf
= ast_calloc_cache(1, len
)))
477 out
->mallocd_hdr_len
= len
;
480 out
->frametype
= f
->frametype
;
481 out
->subclass
= f
->subclass
;
482 out
->datalen
= f
->datalen
;
483 out
->samples
= f
->samples
;
484 out
->delivery
= f
->delivery
;
485 /* Set us as having malloc'd header only, so it will eventually
487 out
->mallocd
= AST_MALLOCD_HDR
;
488 out
->offset
= AST_FRIENDLY_OFFSET
;
490 out
->data
= buf
+ sizeof(*out
) + AST_FRIENDLY_OFFSET
;
491 memcpy(out
->data
, f
->data
, out
->datalen
);
494 out
->src
= buf
+ sizeof(*out
) + AST_FRIENDLY_OFFSET
+ f
->datalen
;
495 /* Must have space since we allocated for it */
496 strcpy((char *)out
->src
, f
->src
);
498 out
->has_timing_info
= f
->has_timing_info
;
499 if (f
->has_timing_info
) {
502 out
->seqno
= f
->seqno
;
507 void ast_swapcopy_samples(void *dst
, const void *src
, int samples
)
510 unsigned short *dst_s
= dst
;
511 const unsigned short *src_s
= src
;
513 for (i
= 0; i
< samples
; i
++)
514 dst_s
[i
] = (src_s
[i
]<<8) | (src_s
[i
]>>8);
518 struct ast_format_list
*ast_get_format_list_index(int index
)
520 return &AST_FORMAT_LIST
[index
];
523 struct ast_format_list
*ast_get_format_list(size_t *size
)
525 *size
= (sizeof(AST_FORMAT_LIST
) / sizeof(AST_FORMAT_LIST
[0]));
526 return AST_FORMAT_LIST
;
529 char* ast_getformatname(int format
)
532 char *ret
= "unknown";
533 for (x
= 0; x
< sizeof(AST_FORMAT_LIST
) / sizeof(AST_FORMAT_LIST
[0]); x
++) {
534 if(AST_FORMAT_LIST
[x
].visible
&& AST_FORMAT_LIST
[x
].bits
== format
) {
535 ret
= AST_FORMAT_LIST
[x
].name
;
542 char *ast_getformatname_multiple(char *buf
, size_t size
, int format
)
546 char *start
, *end
= buf
;
550 snprintf(end
, size
, "0x%x (", format
);
555 for (x
= 0; x
< sizeof(AST_FORMAT_LIST
) / sizeof(AST_FORMAT_LIST
[0]); x
++) {
556 if (AST_FORMAT_LIST
[x
].visible
&& (AST_FORMAT_LIST
[x
].bits
& format
)) {
557 snprintf(end
, size
,"%s|",AST_FORMAT_LIST
[x
].name
);
564 snprintf(start
, size
, "nothing)");
570 static struct ast_codec_alias_table
{
573 } ast_codec_alias_table
[] = {
574 { "slinear", "slin"},
578 static const char *ast_expand_codec_alias(const char *in
)
582 for (x
= 0; x
< sizeof(ast_codec_alias_table
) / sizeof(ast_codec_alias_table
[0]); x
++) {
583 if(!strcmp(in
,ast_codec_alias_table
[x
].alias
))
584 return ast_codec_alias_table
[x
].realname
;
589 int ast_getformatbyname(const char *name
)
591 int x
, all
, format
= 0;
593 all
= strcasecmp(name
, "all") ? 0 : 1;
594 for (x
= 0; x
< sizeof(AST_FORMAT_LIST
) / sizeof(AST_FORMAT_LIST
[0]); x
++) {
595 if(AST_FORMAT_LIST
[x
].visible
&& (all
||
596 !strcasecmp(AST_FORMAT_LIST
[x
].name
,name
) ||
597 !strcasecmp(AST_FORMAT_LIST
[x
].name
,ast_expand_codec_alias(name
)))) {
598 format
|= AST_FORMAT_LIST
[x
].bits
;
607 char *ast_codec2str(int codec
)
610 char *ret
= "unknown";
611 for (x
= 0; x
< sizeof(AST_FORMAT_LIST
) / sizeof(AST_FORMAT_LIST
[0]); x
++) {
612 if(AST_FORMAT_LIST
[x
].visible
&& AST_FORMAT_LIST
[x
].bits
== codec
) {
613 ret
= AST_FORMAT_LIST
[x
].desc
;
620 static int show_codecs_deprecated(int fd
, int argc
, char *argv
[])
625 if ((argc
< 2) || (argc
> 3))
626 return RESULT_SHOWUSAGE
;
628 if (!ast_opt_dont_warn
)
629 ast_cli(fd
, "Disclaimer: this command is for informational purposes only.\n"
630 "\tIt does not indicate anything about your configuration.\n");
632 ast_cli(fd
, "%11s %9s %10s TYPE %8s %s\n","INT","BINARY","HEX","NAME","DESC");
633 ast_cli(fd
, "--------------------------------------------------------------------------------\n");
634 if ((argc
== 2) || (!strcasecmp(argv
[1],"audio"))) {
637 snprintf(hex
,25,"(0x%x)",1<<i
);
638 ast_cli(fd
, "%11u (1 << %2d) %10s audio %8s (%s)\n",1 << i
,i
,hex
,ast_getformatname(1<<i
),ast_codec2str(1<<i
));
642 if ((argc
== 2) || (!strcasecmp(argv
[1],"image"))) {
644 for (i
=16;i
<18;i
++) {
645 snprintf(hex
,25,"(0x%x)",1<<i
);
646 ast_cli(fd
, "%11u (1 << %2d) %10s image %8s (%s)\n",1 << i
,i
,hex
,ast_getformatname(1<<i
),ast_codec2str(1<<i
));
650 if ((argc
== 2) || (!strcasecmp(argv
[1],"video"))) {
652 for (i
=18;i
<22;i
++) {
653 snprintf(hex
,25,"(0x%x)",1<<i
);
654 ast_cli(fd
, "%11u (1 << %2d) %10s video %8s (%s)\n",1 << i
,i
,hex
,ast_getformatname(1<<i
),ast_codec2str(1<<i
));
659 return RESULT_SHOWUSAGE
;
661 return RESULT_SUCCESS
;
664 static int show_codecs(int fd
, int argc
, char *argv
[])
669 if ((argc
< 3) || (argc
> 4))
670 return RESULT_SHOWUSAGE
;
672 if (!ast_opt_dont_warn
)
673 ast_cli(fd
, "Disclaimer: this command is for informational purposes only.\n"
674 "\tIt does not indicate anything about your configuration.\n");
676 ast_cli(fd
, "%11s %9s %10s TYPE %8s %s\n","INT","BINARY","HEX","NAME","DESC");
677 ast_cli(fd
, "--------------------------------------------------------------------------------\n");
678 if ((argc
== 3) || (!strcasecmp(argv
[3],"audio"))) {
681 snprintf(hex
,25,"(0x%x)",1<<i
);
682 ast_cli(fd
, "%11u (1 << %2d) %10s audio %8s (%s)\n",1 << i
,i
,hex
,ast_getformatname(1<<i
),ast_codec2str(1<<i
));
686 if ((argc
== 3) || (!strcasecmp(argv
[3],"image"))) {
688 for (i
=16;i
<18;i
++) {
689 snprintf(hex
,25,"(0x%x)",1<<i
);
690 ast_cli(fd
, "%11u (1 << %2d) %10s image %8s (%s)\n",1 << i
,i
,hex
,ast_getformatname(1<<i
),ast_codec2str(1<<i
));
694 if ((argc
== 3) || (!strcasecmp(argv
[3],"video"))) {
696 for (i
=18;i
<22;i
++) {
697 snprintf(hex
,25,"(0x%x)",1<<i
);
698 ast_cli(fd
, "%11u (1 << %2d) %10s video %8s (%s)\n",1 << i
,i
,hex
,ast_getformatname(1<<i
),ast_codec2str(1<<i
));
703 return RESULT_SHOWUSAGE
;
705 return RESULT_SUCCESS
;
708 static char frame_show_codecs_usage
[] =
709 "Usage: core show codecs [audio|video|image]\n"
710 " Displays codec mapping\n";
712 static int show_codec_n_deprecated(int fd
, int argc
, char *argv
[])
714 int codec
, i
, found
=0;
717 return RESULT_SHOWUSAGE
;
719 if (sscanf(argv
[2],"%d",&codec
) != 1)
720 return RESULT_SHOWUSAGE
;
722 for (i
= 0; i
< 32; i
++)
723 if (codec
& (1 << i
)) {
725 ast_cli(fd
, "%11u (1 << %2d) %s\n",1 << i
,i
,ast_codec2str(1<<i
));
729 ast_cli(fd
, "Codec %d not found\n", codec
);
731 return RESULT_SUCCESS
;
734 static int show_codec_n(int fd
, int argc
, char *argv
[])
736 int codec
, i
, found
=0;
739 return RESULT_SHOWUSAGE
;
741 if (sscanf(argv
[3],"%d",&codec
) != 1)
742 return RESULT_SHOWUSAGE
;
744 for (i
= 0; i
< 32; i
++)
745 if (codec
& (1 << i
)) {
747 ast_cli(fd
, "%11u (1 << %2d) %s\n",1 << i
,i
,ast_codec2str(1<<i
));
751 ast_cli(fd
, "Codec %d not found\n", codec
);
753 return RESULT_SUCCESS
;
756 static char frame_show_codec_n_usage
[] =
757 "Usage: core show codec <number>\n"
758 " Displays codec mapping\n";
760 /*! Dump a frame for debugging purposes */
761 void ast_frame_dump(const char *name
, struct ast_frame
*f
, char *prefix
)
763 const char noname
[] = "unknown";
764 char ftype
[40] = "Unknown Frametype";
766 char subclass
[40] = "Unknown Subclass";
768 char moreinfo
[40] = "";
778 ast_verbose("%s [ %s (NULL) ] [%s]\n",
779 term_color(cp
, prefix
, COLOR_BRMAGENTA
, COLOR_BLACK
, sizeof(cp
)),
780 term_color(cft
, "HANGUP", COLOR_BRRED
, COLOR_BLACK
, sizeof(cft
)),
781 term_color(cn
, name
, COLOR_YELLOW
, COLOR_BLACK
, sizeof(cn
)));
784 /* XXX We should probably print one each of voice and video when the format changes XXX */
785 if (f
->frametype
== AST_FRAME_VOICE
)
787 if (f
->frametype
== AST_FRAME_VIDEO
)
789 switch(f
->frametype
) {
790 case AST_FRAME_DTMF_BEGIN
:
791 strcpy(ftype
, "DTMF Begin");
792 subclass
[0] = f
->subclass
;
795 case AST_FRAME_DTMF_END
:
796 strcpy(ftype
, "DTMF End");
797 subclass
[0] = f
->subclass
;
800 case AST_FRAME_CONTROL
:
801 strcpy(ftype
, "Control");
802 switch(f
->subclass
) {
803 case AST_CONTROL_HANGUP
:
804 strcpy(subclass
, "Hangup");
806 case AST_CONTROL_RING
:
807 strcpy(subclass
, "Ring");
809 case AST_CONTROL_RINGING
:
810 strcpy(subclass
, "Ringing");
812 case AST_CONTROL_ANSWER
:
813 strcpy(subclass
, "Answer");
815 case AST_CONTROL_BUSY
:
816 strcpy(subclass
, "Busy");
818 case AST_CONTROL_TAKEOFFHOOK
:
819 strcpy(subclass
, "Take Off Hook");
821 case AST_CONTROL_OFFHOOK
:
822 strcpy(subclass
, "Line Off Hook");
824 case AST_CONTROL_CONGESTION
:
825 strcpy(subclass
, "Congestion");
827 case AST_CONTROL_FLASH
:
828 strcpy(subclass
, "Flash");
830 case AST_CONTROL_WINK
:
831 strcpy(subclass
, "Wink");
833 case AST_CONTROL_OPTION
:
834 strcpy(subclass
, "Option");
836 case AST_CONTROL_RADIO_KEY
:
837 strcpy(subclass
, "Key Radio");
839 case AST_CONTROL_RADIO_UNKEY
:
840 strcpy(subclass
, "Unkey Radio");
843 strcpy(subclass
, "Stop generators");
846 snprintf(subclass
, sizeof(subclass
), "Unknown control '%d'", f
->subclass
);
850 strcpy(ftype
, "Null Frame");
851 strcpy(subclass
, "N/A");
854 /* Should never happen */
855 strcpy(ftype
, "IAX Specific");
856 snprintf(subclass
, sizeof(subclass
), "IAX Frametype %d", f
->subclass
);
859 strcpy(ftype
, "Text");
860 strcpy(subclass
, "N/A");
861 ast_copy_string(moreinfo
, f
->data
, sizeof(moreinfo
));
863 case AST_FRAME_IMAGE
:
864 strcpy(ftype
, "Image");
865 snprintf(subclass
, sizeof(subclass
), "Image format %s\n", ast_getformatname(f
->subclass
));
868 strcpy(ftype
, "HTML");
869 switch(f
->subclass
) {
871 strcpy(subclass
, "URL");
872 ast_copy_string(moreinfo
, f
->data
, sizeof(moreinfo
));
875 strcpy(subclass
, "Data");
878 strcpy(subclass
, "Begin");
881 strcpy(subclass
, "End");
883 case AST_HTML_LDCOMPLETE
:
884 strcpy(subclass
, "Load Complete");
886 case AST_HTML_NOSUPPORT
:
887 strcpy(subclass
, "No Support");
889 case AST_HTML_LINKURL
:
890 strcpy(subclass
, "Link URL");
891 ast_copy_string(moreinfo
, f
->data
, sizeof(moreinfo
));
893 case AST_HTML_UNLINK
:
894 strcpy(subclass
, "Unlink");
896 case AST_HTML_LINKREJECT
:
897 strcpy(subclass
, "Link Reject");
900 snprintf(subclass
, sizeof(subclass
), "Unknown HTML frame '%d'\n", f
->subclass
);
904 case AST_FRAME_MODEM
:
905 strcpy(ftype
, "Modem");
906 switch (f
->subclass
) {
908 strcpy(subclass
, "T.38");
911 strcpy(subclass
, "V.150");
914 snprintf(subclass
, sizeof(subclass
), "Unknown MODEM frame '%d'\n", f
->subclass
);
919 snprintf(ftype
, sizeof(ftype
), "Unknown Frametype '%d'", f
->frametype
);
921 if (!ast_strlen_zero(moreinfo
))
922 ast_verbose("%s [ TYPE: %s (%d) SUBCLASS: %s (%d) '%s' ] [%s]\n",
923 term_color(cp
, prefix
, COLOR_BRMAGENTA
, COLOR_BLACK
, sizeof(cp
)),
924 term_color(cft
, ftype
, COLOR_BRRED
, COLOR_BLACK
, sizeof(cft
)),
926 term_color(csub
, subclass
, COLOR_BRCYAN
, COLOR_BLACK
, sizeof(csub
)),
928 term_color(cmn
, moreinfo
, COLOR_BRGREEN
, COLOR_BLACK
, sizeof(cmn
)),
929 term_color(cn
, name
, COLOR_YELLOW
, COLOR_BLACK
, sizeof(cn
)));
931 ast_verbose("%s [ TYPE: %s (%d) SUBCLASS: %s (%d) ] [%s]\n",
932 term_color(cp
, prefix
, COLOR_BRMAGENTA
, COLOR_BLACK
, sizeof(cp
)),
933 term_color(cft
, ftype
, COLOR_BRRED
, COLOR_BLACK
, sizeof(cft
)),
935 term_color(csub
, subclass
, COLOR_BRCYAN
, COLOR_BLACK
, sizeof(csub
)),
937 term_color(cn
, name
, COLOR_YELLOW
, COLOR_BLACK
, sizeof(cn
)));
942 static int show_frame_stats_deprecated(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 int show_frame_stats(int fd
, int argc
, char *argv
[])
964 return RESULT_SHOWUSAGE
;
965 AST_LIST_LOCK(&headerlist
);
966 ast_cli(fd
, " Framer Statistics \n");
967 ast_cli(fd
, "---------------------------\n");
968 ast_cli(fd
, "Total allocated headers: %d\n", headers
);
969 ast_cli(fd
, "Queue Dump:\n");
970 AST_LIST_TRAVERSE(&headerlist
, f
, frame_list
)
971 ast_cli(fd
, "%d. Type %d, subclass %d from %s\n", x
++, f
->frametype
, f
->subclass
, f
->src
? f
->src
: "<Unknown>");
972 AST_LIST_UNLOCK(&headerlist
);
973 return RESULT_SUCCESS
;
976 static char frame_stats_usage
[] =
977 "Usage: core show frame stats\n"
978 " Displays debugging statistics from framer\n";
981 /* Builtin Asterisk CLI-commands for debugging */
982 static struct ast_cli_entry cli_show_codecs
= {
983 { "show", "codecs", NULL
},
984 show_codecs_deprecated
, NULL
,
987 static struct ast_cli_entry cli_show_audio_codecs
= {
988 { "show", "audio", "codecs", NULL
},
989 show_codecs_deprecated
, NULL
,
992 static struct ast_cli_entry cli_show_video_codecs
= {
993 { "show", "video", "codecs", NULL
},
994 show_codecs_deprecated
, NULL
,
997 static struct ast_cli_entry cli_show_image_codecs
= {
998 { "show", "image", "codecs", NULL
},
999 show_codecs_deprecated
, NULL
,
1002 static struct ast_cli_entry cli_show_codec
= {
1003 { "show", "codec", NULL
},
1004 show_codec_n_deprecated
, NULL
,
1008 static struct ast_cli_entry cli_show_frame_stats
= {
1009 { "show", "frame", "stats", NULL
},
1010 show_frame_stats
, NULL
,
1014 static struct ast_cli_entry my_clis
[] = {
1015 { { "core", "show", "codecs", NULL
},
1016 show_codecs
, "Displays a list of codecs",
1017 frame_show_codecs_usage
, NULL
, &cli_show_codecs
},
1019 { { "core", "show", "audio", "codecs", NULL
},
1020 show_codecs
, "Displays a list of audio codecs",
1021 frame_show_codecs_usage
, NULL
, &cli_show_audio_codecs
},
1023 { { "core", "show", "video", "codecs", NULL
},
1024 show_codecs
, "Displays a list of video codecs",
1025 frame_show_codecs_usage
, NULL
, &cli_show_video_codecs
},
1027 { { "core", "show", "image", "codecs", NULL
},
1028 show_codecs
, "Displays a list of image codecs",
1029 frame_show_codecs_usage
, NULL
, &cli_show_image_codecs
},
1031 { { "core", "show", "codec", NULL
},
1032 show_codec_n
, "Shows a specific codec",
1033 frame_show_codec_n_usage
, NULL
, &cli_show_codec
},
1036 { { "core", "show", "frame", "stats", NULL
},
1037 show_frame_stats
, "Shows frame statistics",
1038 frame_stats_usage
, NULL
, &cli_show_frame_stats
},
1042 int init_framer(void)
1044 ast_cli_register_multiple(my_clis
, sizeof(my_clis
) / sizeof(struct ast_cli_entry
));
1048 void ast_codec_pref_convert(struct ast_codec_pref
*pref
, char *buf
, size_t size
, int right
)
1050 int x
, differential
= (int) 'A', mem
;
1064 for (x
= 0; x
< 32 ; x
++) {
1067 to
[x
] = right
? (from
[x
] + differential
) : (from
[x
] - differential
);
1071 int ast_codec_pref_string(struct ast_codec_pref
*pref
, char *buf
, size_t size
)
1074 size_t total_len
, slen
;
1081 for(x
= 0; x
< 32 ; x
++) {
1084 if(!(codec
= ast_codec_pref_index(pref
,x
)))
1086 if((formatname
= ast_getformatname(codec
))) {
1087 slen
= strlen(formatname
);
1088 if(slen
> total_len
)
1090 strncat(buf
,formatname
,total_len
);
1093 if(total_len
&& x
< 31 && ast_codec_pref_index(pref
, x
+ 1)) {
1094 strncat(buf
,"|",total_len
);
1099 strncat(buf
,")",total_len
);
1103 return size
- total_len
;
1106 int ast_codec_pref_index(struct ast_codec_pref
*pref
, int index
)
1111 if((index
>= 0) && (index
< sizeof(pref
->order
))) {
1112 slot
= pref
->order
[index
];
1115 return slot
? AST_FORMAT_LIST
[slot
-1].bits
: 0;
1118 /*! \brief Remove codec from pref list */
1119 void ast_codec_pref_remove(struct ast_codec_pref
*pref
, int format
)
1121 struct ast_codec_pref oldorder
;
1129 memcpy(&oldorder
, pref
, sizeof(oldorder
));
1130 memset(pref
, 0, sizeof(*pref
));
1132 for (x
= 0; x
< sizeof(AST_FORMAT_LIST
) / sizeof(AST_FORMAT_LIST
[0]); x
++) {
1133 slot
= oldorder
.order
[x
];
1134 size
= oldorder
.framing
[x
];
1137 if(AST_FORMAT_LIST
[slot
-1].bits
!= format
) {
1138 pref
->order
[y
] = slot
;
1139 pref
->framing
[y
++] = size
;
1145 /*! \brief Append codec to list */
1146 int ast_codec_pref_append(struct ast_codec_pref
*pref
, int format
)
1148 int x
, newindex
= -1;
1150 ast_codec_pref_remove(pref
, format
);
1152 for (x
= 0; x
< sizeof(AST_FORMAT_LIST
) / sizeof(AST_FORMAT_LIST
[0]); x
++) {
1153 if(AST_FORMAT_LIST
[x
].bits
== format
) {
1160 for (x
= 0; x
< sizeof(AST_FORMAT_LIST
) / sizeof(AST_FORMAT_LIST
[0]); x
++) {
1161 if(!pref
->order
[x
]) {
1162 pref
->order
[x
] = newindex
;
1172 /*! \brief Set packet size for codec */
1173 int ast_codec_pref_setsize(struct ast_codec_pref
*pref
, int format
, int framems
)
1177 for (x
= 0; x
< sizeof(AST_FORMAT_LIST
) / sizeof(AST_FORMAT_LIST
[0]); x
++) {
1178 if(AST_FORMAT_LIST
[x
].bits
== format
) {
1187 /* size validation */
1189 framems
= AST_FORMAT_LIST
[index
].def_ms
;
1191 if(AST_FORMAT_LIST
[index
].inc_ms
&& framems
% AST_FORMAT_LIST
[index
].inc_ms
) /* avoid division by zero */
1192 framems
-= framems
% AST_FORMAT_LIST
[index
].inc_ms
;
1194 if(framems
< AST_FORMAT_LIST
[index
].min_ms
)
1195 framems
= AST_FORMAT_LIST
[index
].min_ms
;
1197 if(framems
> AST_FORMAT_LIST
[index
].max_ms
)
1198 framems
= AST_FORMAT_LIST
[index
].max_ms
;
1201 for (x
= 0; x
< sizeof(AST_FORMAT_LIST
) / sizeof(AST_FORMAT_LIST
[0]); x
++) {
1202 if(pref
->order
[x
] == (index
+ 1)) {
1203 pref
->framing
[x
] = framems
;
1211 /*! \brief Get packet size for codec */
1212 struct ast_format_list
ast_codec_pref_getsize(struct ast_codec_pref
*pref
, int format
)
1214 int x
, index
= -1, framems
= 0;
1215 struct ast_format_list fmt
= {0};
1217 for (x
= 0; x
< sizeof(AST_FORMAT_LIST
) / sizeof(AST_FORMAT_LIST
[0]); x
++) {
1218 if(AST_FORMAT_LIST
[x
].bits
== format
) {
1219 fmt
= AST_FORMAT_LIST
[x
];
1225 for (x
= 0; x
< sizeof(AST_FORMAT_LIST
) / sizeof(AST_FORMAT_LIST
[0]); x
++) {
1226 if(pref
->order
[x
] == (index
+ 1)) {
1227 framems
= pref
->framing
[x
];
1232 /* size validation */
1234 framems
= AST_FORMAT_LIST
[index
].def_ms
;
1236 if(AST_FORMAT_LIST
[index
].inc_ms
&& framems
% AST_FORMAT_LIST
[index
].inc_ms
) /* avoid division by zero */
1237 framems
-= framems
% AST_FORMAT_LIST
[index
].inc_ms
;
1239 if(framems
< AST_FORMAT_LIST
[index
].min_ms
)
1240 framems
= AST_FORMAT_LIST
[index
].min_ms
;
1242 if(framems
> AST_FORMAT_LIST
[index
].max_ms
)
1243 framems
= AST_FORMAT_LIST
[index
].max_ms
;
1245 fmt
.cur_ms
= framems
;
1250 /*! \brief Pick a codec */
1251 int ast_codec_choose(struct ast_codec_pref
*pref
, int formats
, int find_best
)
1253 int x
, ret
= 0, slot
;
1255 for (x
= 0; x
< sizeof(AST_FORMAT_LIST
) / sizeof(AST_FORMAT_LIST
[0]); x
++) {
1256 slot
= pref
->order
[x
];
1260 if (formats
& AST_FORMAT_LIST
[slot
-1].bits
) {
1261 ret
= AST_FORMAT_LIST
[slot
-1].bits
;
1265 if(ret
& AST_FORMAT_AUDIO_MASK
)
1268 if (option_debug
> 3)
1269 ast_log(LOG_DEBUG
, "Could not find preferred codec - %s\n", find_best
? "Going for the best codec" : "Returning zero codec");
1271 return find_best
? ast_best_codec(formats
) : 0;
1274 void ast_parse_allow_disallow(struct ast_codec_pref
*pref
, int *mask
, const char *list
, int allowing
)
1276 char *parse
= NULL
, *this = NULL
, *psize
= NULL
;
1277 int format
= 0, framems
= 0;
1279 parse
= ast_strdupa(list
);
1280 while ((this = strsep(&parse
, ","))) {
1282 if ((psize
= strrchr(this, ':'))) {
1285 ast_log(LOG_DEBUG
,"Packetization for codec: %s is %s\n", this, psize
);
1286 framems
= atoi(psize
);
1290 if (!(format
= ast_getformatbyname(this))) {
1291 ast_log(LOG_WARNING
, "Cannot %s unknown format '%s'\n", allowing
? "allow" : "disallow", this);
1302 /* Set up a preference list for audio. Do not include video in preferences
1303 since we can not transcode video and have to use whatever is offered
1305 if (pref
&& (format
& AST_FORMAT_AUDIO_MASK
)) {
1306 if (strcasecmp(this, "all")) {
1308 ast_codec_pref_append(pref
, format
);
1309 ast_codec_pref_setsize(pref
, format
, framems
);
1312 ast_codec_pref_remove(pref
, format
);
1313 } else if (!allowing
) {
1314 memset(pref
, 0, sizeof(*pref
));
1320 static int g723_len(unsigned char buf
)
1322 enum frame_type type
= buf
& TYPE_MASK
;
1338 ast_log(LOG_WARNING
, "Badly encoded frame (%d)\n", type
);
1343 static int g723_samples(unsigned char *buf
, int maxlen
)
1348 while(pos
< maxlen
) {
1349 res
= g723_len(buf
[pos
]);
1358 static unsigned char get_n_bits_at(unsigned char *data
, int n
, int bit
)
1360 int byte
= bit
/ 8; /* byte containing first bit */
1361 int rem
= 8 - (bit
% 8); /* remaining bits in first byte */
1362 unsigned char ret
= 0;
1364 if (n
<= 0 || n
> 8)
1368 ret
= (data
[byte
] << (n
- rem
));
1369 ret
|= (data
[byte
+ 1] >> (8 - n
+ rem
));
1371 ret
= (data
[byte
] >> (rem
- n
));
1374 return (ret
& (0xff >> (8 - n
)));
1377 static int speex_get_wb_sz_at(unsigned char *data
, int len
, int bit
)
1379 static int SpeexWBSubModeSz
[] = {
1385 /* skip up to two wideband frames */
1386 if (((len
* 8 - off
) >= 5) &&
1387 get_n_bits_at(data
, 1, off
)) {
1388 c
= get_n_bits_at(data
, 3, off
+ 1);
1389 off
+= SpeexWBSubModeSz
[c
];
1391 if (((len
* 8 - off
) >= 5) &&
1392 get_n_bits_at(data
, 1, off
)) {
1393 c
= get_n_bits_at(data
, 3, off
+ 1);
1394 off
+= SpeexWBSubModeSz
[c
];
1396 if (((len
* 8 - off
) >= 5) &&
1397 get_n_bits_at(data
, 1, off
)) {
1398 ast_log(LOG_WARNING
, "Encountered corrupt speex frame; too many wideband frames in a row.\n");
1407 static int speex_samples(unsigned char *data
, int len
)
1409 static int SpeexSubModeSz
[] = {
1414 static int SpeexInBandSz
[] = {
1424 while ((len
* 8 - bit
) >= 5) {
1425 /* skip wideband frames */
1426 off
= speex_get_wb_sz_at(data
, len
, bit
);
1428 ast_log(LOG_WARNING
, "Had error while reading wideband frames for speex samples\n");
1433 if ((len
* 8 - bit
) < 5) {
1434 ast_log(LOG_WARNING
, "Not enough bits remaining after wide band for speex samples.\n");
1438 /* get control bits */
1439 c
= get_n_bits_at(data
, 5, bit
);
1445 } else if (c
== 14) {
1446 /* in-band signal; next 4 bits contain signal id */
1447 c
= get_n_bits_at(data
, 4, bit
);
1449 bit
+= SpeexInBandSz
[c
];
1450 } else if (c
== 13) {
1451 /* user in-band; next 5 bits contain msg len */
1452 c
= get_n_bits_at(data
, 5, bit
);
1459 /* skip number bits for submode (less the 5 control bits) */
1460 bit
+= SpeexSubModeSz
[c
] - 5;
1461 cnt
+= 160; /* new frame */
1467 int ast_codec_get_samples(struct ast_frame
*f
)
1470 switch(f
->subclass
) {
1471 case AST_FORMAT_SPEEX
:
1472 samples
= speex_samples(f
->data
, f
->datalen
);
1474 case AST_FORMAT_G723_1
:
1475 samples
= g723_samples(f
->data
, f
->datalen
);
1477 case AST_FORMAT_ILBC
:
1478 samples
= 240 * (f
->datalen
/ 50);
1480 case AST_FORMAT_GSM
:
1481 samples
= 160 * (f
->datalen
/ 33);
1483 case AST_FORMAT_G729A
:
1484 samples
= f
->datalen
* 8;
1486 case AST_FORMAT_SLINEAR
:
1487 samples
= f
->datalen
/ 2;
1489 case AST_FORMAT_LPC10
:
1490 /* assumes that the RTP packet contains one LPC10 frame */
1492 samples
+= (((char *)(f
->data
))[7] & 0x1) * 8;
1494 case AST_FORMAT_ULAW
:
1495 case AST_FORMAT_ALAW
:
1496 case AST_FORMAT_G722
:
1497 samples
= f
->datalen
;
1499 case AST_FORMAT_ADPCM
:
1500 case AST_FORMAT_G726
:
1501 case AST_FORMAT_G726_AAL2
:
1502 samples
= f
->datalen
* 2;
1505 ast_log(LOG_WARNING
, "Unable to calculate samples for format %s\n", ast_getformatname(f
->subclass
));
1510 int ast_codec_get_len(int format
, int samples
)
1514 /* XXX Still need speex, g723, and lpc10 XXX */
1516 case AST_FORMAT_ILBC
:
1517 len
= (samples
/ 240) * 50;
1519 case AST_FORMAT_GSM
:
1520 len
= (samples
/ 160) * 33;
1522 case AST_FORMAT_G729A
:
1525 case AST_FORMAT_SLINEAR
:
1528 case AST_FORMAT_ULAW
:
1529 case AST_FORMAT_ALAW
:
1532 case AST_FORMAT_ADPCM
:
1533 case AST_FORMAT_G726
:
1534 case AST_FORMAT_G726_AAL2
:
1538 ast_log(LOG_WARNING
, "Unable to calculate sample length for format %s\n", ast_getformatname(format
));
1544 int ast_frame_adjust_volume(struct ast_frame
*f
, int adjustment
)
1547 short *fdata
= f
->data
;
1548 short adjust_value
= abs(adjustment
);
1550 if ((f
->frametype
!= AST_FRAME_VOICE
) || (f
->subclass
!= AST_FORMAT_SLINEAR
))
1556 for (count
= 0; count
< f
->samples
; count
++) {
1557 if (adjustment
> 0) {
1558 ast_slinear_saturated_multiply(&fdata
[count
], &adjust_value
);
1559 } else if (adjustment
< 0) {
1560 ast_slinear_saturated_divide(&fdata
[count
], &adjust_value
);
1567 int ast_frame_slinear_sum(struct ast_frame
*f1
, struct ast_frame
*f2
)
1570 short *data1
, *data2
;
1572 if ((f1
->frametype
!= AST_FRAME_VOICE
) || (f1
->subclass
!= AST_FORMAT_SLINEAR
))
1575 if ((f2
->frametype
!= AST_FRAME_VOICE
) || (f2
->subclass
!= AST_FORMAT_SLINEAR
))
1578 if (f1
->samples
!= f2
->samples
)
1581 for (count
= 0, data1
= f1
->data
, data2
= f2
->data
;
1582 count
< f1
->samples
;
1583 count
++, data1
++, data2
++)
1584 ast_slinear_saturated_add(data1
, data2
);