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
;
501 out
->seqno
= f
->seqno
;
505 void ast_swapcopy_samples(void *dst
, const void *src
, int samples
)
508 unsigned short *dst_s
= dst
;
509 const unsigned short *src_s
= src
;
511 for (i
= 0; i
< samples
; i
++)
512 dst_s
[i
] = (src_s
[i
]<<8) | (src_s
[i
]>>8);
516 struct ast_format_list
*ast_get_format_list_index(int index
)
518 return &AST_FORMAT_LIST
[index
];
521 struct ast_format_list
*ast_get_format_list(size_t *size
)
523 *size
= (sizeof(AST_FORMAT_LIST
) / sizeof(AST_FORMAT_LIST
[0]));
524 return AST_FORMAT_LIST
;
527 char* ast_getformatname(int format
)
530 char *ret
= "unknown";
531 for (x
= 0; x
< sizeof(AST_FORMAT_LIST
) / sizeof(AST_FORMAT_LIST
[0]); x
++) {
532 if(AST_FORMAT_LIST
[x
].visible
&& AST_FORMAT_LIST
[x
].bits
== format
) {
533 ret
= AST_FORMAT_LIST
[x
].name
;
540 char *ast_getformatname_multiple(char *buf
, size_t size
, int format
)
544 char *start
, *end
= buf
;
548 snprintf(end
, size
, "0x%x (", format
);
553 for (x
= 0; x
< sizeof(AST_FORMAT_LIST
) / sizeof(AST_FORMAT_LIST
[0]); x
++) {
554 if (AST_FORMAT_LIST
[x
].visible
&& (AST_FORMAT_LIST
[x
].bits
& format
)) {
555 snprintf(end
, size
,"%s|",AST_FORMAT_LIST
[x
].name
);
562 snprintf(start
, size
, "nothing)");
568 static struct ast_codec_alias_table
{
571 } ast_codec_alias_table
[] = {
572 { "slinear", "slin"},
576 static const char *ast_expand_codec_alias(const char *in
)
580 for (x
= 0; x
< sizeof(ast_codec_alias_table
) / sizeof(ast_codec_alias_table
[0]); x
++) {
581 if(!strcmp(in
,ast_codec_alias_table
[x
].alias
))
582 return ast_codec_alias_table
[x
].realname
;
587 int ast_getformatbyname(const char *name
)
589 int x
, all
, format
= 0;
591 all
= strcasecmp(name
, "all") ? 0 : 1;
592 for (x
= 0; x
< sizeof(AST_FORMAT_LIST
) / sizeof(AST_FORMAT_LIST
[0]); x
++) {
593 if(AST_FORMAT_LIST
[x
].visible
&& (all
||
594 !strcasecmp(AST_FORMAT_LIST
[x
].name
,name
) ||
595 !strcasecmp(AST_FORMAT_LIST
[x
].name
,ast_expand_codec_alias(name
)))) {
596 format
|= AST_FORMAT_LIST
[x
].bits
;
605 char *ast_codec2str(int codec
)
608 char *ret
= "unknown";
609 for (x
= 0; x
< sizeof(AST_FORMAT_LIST
) / sizeof(AST_FORMAT_LIST
[0]); x
++) {
610 if(AST_FORMAT_LIST
[x
].visible
&& AST_FORMAT_LIST
[x
].bits
== codec
) {
611 ret
= AST_FORMAT_LIST
[x
].desc
;
618 static int show_codecs_deprecated(int fd
, int argc
, char *argv
[])
623 if ((argc
< 2) || (argc
> 3))
624 return RESULT_SHOWUSAGE
;
626 if (!ast_opt_dont_warn
)
627 ast_cli(fd
, "Disclaimer: this command is for informational purposes only.\n"
628 "\tIt does not indicate anything about your configuration.\n");
630 ast_cli(fd
, "%11s %9s %10s TYPE %8s %s\n","INT","BINARY","HEX","NAME","DESC");
631 ast_cli(fd
, "--------------------------------------------------------------------------------\n");
632 if ((argc
== 2) || (!strcasecmp(argv
[1],"audio"))) {
635 snprintf(hex
,25,"(0x%x)",1<<i
);
636 ast_cli(fd
, "%11u (1 << %2d) %10s audio %8s (%s)\n",1 << i
,i
,hex
,ast_getformatname(1<<i
),ast_codec2str(1<<i
));
640 if ((argc
== 2) || (!strcasecmp(argv
[1],"image"))) {
642 for (i
=16;i
<18;i
++) {
643 snprintf(hex
,25,"(0x%x)",1<<i
);
644 ast_cli(fd
, "%11u (1 << %2d) %10s image %8s (%s)\n",1 << i
,i
,hex
,ast_getformatname(1<<i
),ast_codec2str(1<<i
));
648 if ((argc
== 2) || (!strcasecmp(argv
[1],"video"))) {
650 for (i
=18;i
<22;i
++) {
651 snprintf(hex
,25,"(0x%x)",1<<i
);
652 ast_cli(fd
, "%11u (1 << %2d) %10s video %8s (%s)\n",1 << i
,i
,hex
,ast_getformatname(1<<i
),ast_codec2str(1<<i
));
657 return RESULT_SHOWUSAGE
;
659 return RESULT_SUCCESS
;
662 static int show_codecs(int fd
, int argc
, char *argv
[])
667 if ((argc
< 3) || (argc
> 4))
668 return RESULT_SHOWUSAGE
;
670 if (!ast_opt_dont_warn
)
671 ast_cli(fd
, "Disclaimer: this command is for informational purposes only.\n"
672 "\tIt does not indicate anything about your configuration.\n");
674 ast_cli(fd
, "%11s %9s %10s TYPE %8s %s\n","INT","BINARY","HEX","NAME","DESC");
675 ast_cli(fd
, "--------------------------------------------------------------------------------\n");
676 if ((argc
== 3) || (!strcasecmp(argv
[3],"audio"))) {
679 snprintf(hex
,25,"(0x%x)",1<<i
);
680 ast_cli(fd
, "%11u (1 << %2d) %10s audio %8s (%s)\n",1 << i
,i
,hex
,ast_getformatname(1<<i
),ast_codec2str(1<<i
));
684 if ((argc
== 3) || (!strcasecmp(argv
[3],"image"))) {
686 for (i
=16;i
<18;i
++) {
687 snprintf(hex
,25,"(0x%x)",1<<i
);
688 ast_cli(fd
, "%11u (1 << %2d) %10s image %8s (%s)\n",1 << i
,i
,hex
,ast_getformatname(1<<i
),ast_codec2str(1<<i
));
692 if ((argc
== 3) || (!strcasecmp(argv
[3],"video"))) {
694 for (i
=18;i
<22;i
++) {
695 snprintf(hex
,25,"(0x%x)",1<<i
);
696 ast_cli(fd
, "%11u (1 << %2d) %10s video %8s (%s)\n",1 << i
,i
,hex
,ast_getformatname(1<<i
),ast_codec2str(1<<i
));
701 return RESULT_SHOWUSAGE
;
703 return RESULT_SUCCESS
;
706 static char frame_show_codecs_usage
[] =
707 "Usage: core show codecs [audio|video|image]\n"
708 " Displays codec mapping\n";
710 static int show_codec_n_deprecated(int fd
, int argc
, char *argv
[])
712 int codec
, i
, found
=0;
715 return RESULT_SHOWUSAGE
;
717 if (sscanf(argv
[2],"%d",&codec
) != 1)
718 return RESULT_SHOWUSAGE
;
720 for (i
= 0; i
< 32; i
++)
721 if (codec
& (1 << i
)) {
723 ast_cli(fd
, "%11u (1 << %2d) %s\n",1 << i
,i
,ast_codec2str(1<<i
));
727 ast_cli(fd
, "Codec %d not found\n", codec
);
729 return RESULT_SUCCESS
;
732 static int show_codec_n(int fd
, int argc
, char *argv
[])
734 int codec
, i
, found
=0;
737 return RESULT_SHOWUSAGE
;
739 if (sscanf(argv
[3],"%d",&codec
) != 1)
740 return RESULT_SHOWUSAGE
;
742 for (i
= 0; i
< 32; i
++)
743 if (codec
& (1 << i
)) {
745 ast_cli(fd
, "%11u (1 << %2d) %s\n",1 << i
,i
,ast_codec2str(1<<i
));
749 ast_cli(fd
, "Codec %d not found\n", codec
);
751 return RESULT_SUCCESS
;
754 static char frame_show_codec_n_usage
[] =
755 "Usage: core show codec <number>\n"
756 " Displays codec mapping\n";
758 /*! Dump a frame for debugging purposes */
759 void ast_frame_dump(const char *name
, struct ast_frame
*f
, char *prefix
)
761 const char noname
[] = "unknown";
762 char ftype
[40] = "Unknown Frametype";
764 char subclass
[40] = "Unknown Subclass";
766 char moreinfo
[40] = "";
776 ast_verbose("%s [ %s (NULL) ] [%s]\n",
777 term_color(cp
, prefix
, COLOR_BRMAGENTA
, COLOR_BLACK
, sizeof(cp
)),
778 term_color(cft
, "HANGUP", COLOR_BRRED
, COLOR_BLACK
, sizeof(cft
)),
779 term_color(cn
, name
, COLOR_YELLOW
, COLOR_BLACK
, sizeof(cn
)));
782 /* XXX We should probably print one each of voice and video when the format changes XXX */
783 if (f
->frametype
== AST_FRAME_VOICE
)
785 if (f
->frametype
== AST_FRAME_VIDEO
)
787 switch(f
->frametype
) {
788 case AST_FRAME_DTMF_BEGIN
:
789 strcpy(ftype
, "DTMF Begin");
790 subclass
[0] = f
->subclass
;
793 case AST_FRAME_DTMF_END
:
794 strcpy(ftype
, "DTMF End");
795 subclass
[0] = f
->subclass
;
798 case AST_FRAME_CONTROL
:
799 strcpy(ftype
, "Control");
800 switch(f
->subclass
) {
801 case AST_CONTROL_HANGUP
:
802 strcpy(subclass
, "Hangup");
804 case AST_CONTROL_RING
:
805 strcpy(subclass
, "Ring");
807 case AST_CONTROL_RINGING
:
808 strcpy(subclass
, "Ringing");
810 case AST_CONTROL_ANSWER
:
811 strcpy(subclass
, "Answer");
813 case AST_CONTROL_BUSY
:
814 strcpy(subclass
, "Busy");
816 case AST_CONTROL_TAKEOFFHOOK
:
817 strcpy(subclass
, "Take Off Hook");
819 case AST_CONTROL_OFFHOOK
:
820 strcpy(subclass
, "Line Off Hook");
822 case AST_CONTROL_CONGESTION
:
823 strcpy(subclass
, "Congestion");
825 case AST_CONTROL_FLASH
:
826 strcpy(subclass
, "Flash");
828 case AST_CONTROL_WINK
:
829 strcpy(subclass
, "Wink");
831 case AST_CONTROL_OPTION
:
832 strcpy(subclass
, "Option");
834 case AST_CONTROL_RADIO_KEY
:
835 strcpy(subclass
, "Key Radio");
837 case AST_CONTROL_RADIO_UNKEY
:
838 strcpy(subclass
, "Unkey Radio");
841 strcpy(subclass
, "Stop generators");
844 snprintf(subclass
, sizeof(subclass
), "Unknown control '%d'", f
->subclass
);
848 strcpy(ftype
, "Null Frame");
849 strcpy(subclass
, "N/A");
852 /* Should never happen */
853 strcpy(ftype
, "IAX Specific");
854 snprintf(subclass
, sizeof(subclass
), "IAX Frametype %d", f
->subclass
);
857 strcpy(ftype
, "Text");
858 strcpy(subclass
, "N/A");
859 ast_copy_string(moreinfo
, f
->data
, sizeof(moreinfo
));
861 case AST_FRAME_IMAGE
:
862 strcpy(ftype
, "Image");
863 snprintf(subclass
, sizeof(subclass
), "Image format %s\n", ast_getformatname(f
->subclass
));
866 strcpy(ftype
, "HTML");
867 switch(f
->subclass
) {
869 strcpy(subclass
, "URL");
870 ast_copy_string(moreinfo
, f
->data
, sizeof(moreinfo
));
873 strcpy(subclass
, "Data");
876 strcpy(subclass
, "Begin");
879 strcpy(subclass
, "End");
881 case AST_HTML_LDCOMPLETE
:
882 strcpy(subclass
, "Load Complete");
884 case AST_HTML_NOSUPPORT
:
885 strcpy(subclass
, "No Support");
887 case AST_HTML_LINKURL
:
888 strcpy(subclass
, "Link URL");
889 ast_copy_string(moreinfo
, f
->data
, sizeof(moreinfo
));
891 case AST_HTML_UNLINK
:
892 strcpy(subclass
, "Unlink");
894 case AST_HTML_LINKREJECT
:
895 strcpy(subclass
, "Link Reject");
898 snprintf(subclass
, sizeof(subclass
), "Unknown HTML frame '%d'\n", f
->subclass
);
902 case AST_FRAME_MODEM
:
903 strcpy(ftype
, "Modem");
904 switch (f
->subclass
) {
906 strcpy(subclass
, "T.38");
909 strcpy(subclass
, "V.150");
912 snprintf(subclass
, sizeof(subclass
), "Unknown MODEM frame '%d'\n", f
->subclass
);
917 snprintf(ftype
, sizeof(ftype
), "Unknown Frametype '%d'", f
->frametype
);
919 if (!ast_strlen_zero(moreinfo
))
920 ast_verbose("%s [ TYPE: %s (%d) SUBCLASS: %s (%d) '%s' ] [%s]\n",
921 term_color(cp
, prefix
, COLOR_BRMAGENTA
, COLOR_BLACK
, sizeof(cp
)),
922 term_color(cft
, ftype
, COLOR_BRRED
, COLOR_BLACK
, sizeof(cft
)),
924 term_color(csub
, subclass
, COLOR_BRCYAN
, COLOR_BLACK
, sizeof(csub
)),
926 term_color(cmn
, moreinfo
, COLOR_BRGREEN
, COLOR_BLACK
, sizeof(cmn
)),
927 term_color(cn
, name
, COLOR_YELLOW
, COLOR_BLACK
, sizeof(cn
)));
929 ast_verbose("%s [ TYPE: %s (%d) SUBCLASS: %s (%d) ] [%s]\n",
930 term_color(cp
, prefix
, COLOR_BRMAGENTA
, COLOR_BLACK
, sizeof(cp
)),
931 term_color(cft
, ftype
, COLOR_BRRED
, COLOR_BLACK
, sizeof(cft
)),
933 term_color(csub
, subclass
, COLOR_BRCYAN
, COLOR_BLACK
, sizeof(csub
)),
935 term_color(cn
, name
, COLOR_YELLOW
, COLOR_BLACK
, sizeof(cn
)));
940 static int show_frame_stats_deprecated(int fd
, int argc
, char *argv
[])
945 return RESULT_SHOWUSAGE
;
946 AST_LIST_LOCK(&headerlist
);
947 ast_cli(fd
, " Framer Statistics \n");
948 ast_cli(fd
, "---------------------------\n");
949 ast_cli(fd
, "Total allocated headers: %d\n", headers
);
950 ast_cli(fd
, "Queue Dump:\n");
951 AST_LIST_TRAVERSE(&headerlist
, f
, frame_list
)
952 ast_cli(fd
, "%d. Type %d, subclass %d from %s\n", x
++, f
->frametype
, f
->subclass
, f
->src
? f
->src
: "<Unknown>");
953 AST_LIST_UNLOCK(&headerlist
);
954 return RESULT_SUCCESS
;
957 static int show_frame_stats(int fd
, int argc
, char *argv
[])
962 return RESULT_SHOWUSAGE
;
963 AST_LIST_LOCK(&headerlist
);
964 ast_cli(fd
, " Framer Statistics \n");
965 ast_cli(fd
, "---------------------------\n");
966 ast_cli(fd
, "Total allocated headers: %d\n", headers
);
967 ast_cli(fd
, "Queue Dump:\n");
968 AST_LIST_TRAVERSE(&headerlist
, f
, frame_list
)
969 ast_cli(fd
, "%d. Type %d, subclass %d from %s\n", x
++, f
->frametype
, f
->subclass
, f
->src
? f
->src
: "<Unknown>");
970 AST_LIST_UNLOCK(&headerlist
);
971 return RESULT_SUCCESS
;
974 static char frame_stats_usage
[] =
975 "Usage: core show frame stats\n"
976 " Displays debugging statistics from framer\n";
979 /* Builtin Asterisk CLI-commands for debugging */
980 static struct ast_cli_entry cli_show_codecs
= {
981 { "show", "codecs", NULL
},
982 show_codecs_deprecated
, NULL
,
985 static struct ast_cli_entry cli_show_audio_codecs
= {
986 { "show", "audio", "codecs", NULL
},
987 show_codecs_deprecated
, NULL
,
990 static struct ast_cli_entry cli_show_video_codecs
= {
991 { "show", "video", "codecs", NULL
},
992 show_codecs_deprecated
, NULL
,
995 static struct ast_cli_entry cli_show_image_codecs
= {
996 { "show", "image", "codecs", NULL
},
997 show_codecs_deprecated
, NULL
,
1000 static struct ast_cli_entry cli_show_codec
= {
1001 { "show", "codec", NULL
},
1002 show_codec_n_deprecated
, NULL
,
1006 static struct ast_cli_entry cli_show_frame_stats
= {
1007 { "show", "frame", "stats", NULL
},
1008 show_frame_stats
, NULL
,
1012 static struct ast_cli_entry my_clis
[] = {
1013 { { "core", "show", "codecs", NULL
},
1014 show_codecs
, "Displays a list of codecs",
1015 frame_show_codecs_usage
, NULL
, &cli_show_codecs
},
1017 { { "core", "show", "audio", "codecs", NULL
},
1018 show_codecs
, "Displays a list of audio codecs",
1019 frame_show_codecs_usage
, NULL
, &cli_show_audio_codecs
},
1021 { { "core", "show", "video", "codecs", NULL
},
1022 show_codecs
, "Displays a list of video codecs",
1023 frame_show_codecs_usage
, NULL
, &cli_show_video_codecs
},
1025 { { "core", "show", "image", "codecs", NULL
},
1026 show_codecs
, "Displays a list of image codecs",
1027 frame_show_codecs_usage
, NULL
, &cli_show_image_codecs
},
1029 { { "core", "show", "codec", NULL
},
1030 show_codec_n
, "Shows a specific codec",
1031 frame_show_codec_n_usage
, NULL
, &cli_show_codec
},
1034 { { "core", "show", "frame", "stats", NULL
},
1035 show_frame_stats
, "Shows frame statistics",
1036 frame_stats_usage
, NULL
, &cli_show_frame_stats
},
1040 int init_framer(void)
1042 ast_cli_register_multiple(my_clis
, sizeof(my_clis
) / sizeof(struct ast_cli_entry
));
1046 void ast_codec_pref_convert(struct ast_codec_pref
*pref
, char *buf
, size_t size
, int right
)
1048 int x
, differential
= (int) 'A', mem
;
1062 for (x
= 0; x
< 32 ; x
++) {
1065 to
[x
] = right
? (from
[x
] + differential
) : (from
[x
] - differential
);
1069 int ast_codec_pref_string(struct ast_codec_pref
*pref
, char *buf
, size_t size
)
1072 size_t total_len
, slen
;
1079 for(x
= 0; x
< 32 ; x
++) {
1082 if(!(codec
= ast_codec_pref_index(pref
,x
)))
1084 if((formatname
= ast_getformatname(codec
))) {
1085 slen
= strlen(formatname
);
1086 if(slen
> total_len
)
1088 strncat(buf
,formatname
,total_len
);
1091 if(total_len
&& x
< 31 && ast_codec_pref_index(pref
, x
+ 1)) {
1092 strncat(buf
,"|",total_len
);
1097 strncat(buf
,")",total_len
);
1101 return size
- total_len
;
1104 int ast_codec_pref_index(struct ast_codec_pref
*pref
, int index
)
1109 if((index
>= 0) && (index
< sizeof(pref
->order
))) {
1110 slot
= pref
->order
[index
];
1113 return slot
? AST_FORMAT_LIST
[slot
-1].bits
: 0;
1116 /*! \brief Remove codec from pref list */
1117 void ast_codec_pref_remove(struct ast_codec_pref
*pref
, int format
)
1119 struct ast_codec_pref oldorder
;
1127 memcpy(&oldorder
, pref
, sizeof(oldorder
));
1128 memset(pref
, 0, sizeof(*pref
));
1130 for (x
= 0; x
< sizeof(AST_FORMAT_LIST
) / sizeof(AST_FORMAT_LIST
[0]); x
++) {
1131 slot
= oldorder
.order
[x
];
1132 size
= oldorder
.framing
[x
];
1135 if(AST_FORMAT_LIST
[slot
-1].bits
!= format
) {
1136 pref
->order
[y
] = slot
;
1137 pref
->framing
[y
++] = size
;
1143 /*! \brief Append codec to list */
1144 int ast_codec_pref_append(struct ast_codec_pref
*pref
, int format
)
1146 int x
, newindex
= -1;
1148 ast_codec_pref_remove(pref
, format
);
1150 for (x
= 0; x
< sizeof(AST_FORMAT_LIST
) / sizeof(AST_FORMAT_LIST
[0]); x
++) {
1151 if(AST_FORMAT_LIST
[x
].bits
== format
) {
1158 for (x
= 0; x
< sizeof(AST_FORMAT_LIST
) / sizeof(AST_FORMAT_LIST
[0]); x
++) {
1159 if(!pref
->order
[x
]) {
1160 pref
->order
[x
] = newindex
;
1170 /*! \brief Set packet size for codec */
1171 int ast_codec_pref_setsize(struct ast_codec_pref
*pref
, int format
, int framems
)
1175 for (x
= 0; x
< sizeof(AST_FORMAT_LIST
) / sizeof(AST_FORMAT_LIST
[0]); x
++) {
1176 if(AST_FORMAT_LIST
[x
].bits
== format
) {
1185 /* size validation */
1187 framems
= AST_FORMAT_LIST
[index
].def_ms
;
1189 if(AST_FORMAT_LIST
[index
].inc_ms
&& framems
% AST_FORMAT_LIST
[index
].inc_ms
) /* avoid division by zero */
1190 framems
-= framems
% AST_FORMAT_LIST
[index
].inc_ms
;
1192 if(framems
< AST_FORMAT_LIST
[index
].min_ms
)
1193 framems
= AST_FORMAT_LIST
[index
].min_ms
;
1195 if(framems
> AST_FORMAT_LIST
[index
].max_ms
)
1196 framems
= AST_FORMAT_LIST
[index
].max_ms
;
1199 for (x
= 0; x
< sizeof(AST_FORMAT_LIST
) / sizeof(AST_FORMAT_LIST
[0]); x
++) {
1200 if(pref
->order
[x
] == (index
+ 1)) {
1201 pref
->framing
[x
] = framems
;
1209 /*! \brief Get packet size for codec */
1210 struct ast_format_list
ast_codec_pref_getsize(struct ast_codec_pref
*pref
, int format
)
1212 int x
, index
= -1, framems
= 0;
1213 struct ast_format_list fmt
= {0};
1215 for (x
= 0; x
< sizeof(AST_FORMAT_LIST
) / sizeof(AST_FORMAT_LIST
[0]); x
++) {
1216 if(AST_FORMAT_LIST
[x
].bits
== format
) {
1217 fmt
= AST_FORMAT_LIST
[x
];
1223 for (x
= 0; x
< sizeof(AST_FORMAT_LIST
) / sizeof(AST_FORMAT_LIST
[0]); x
++) {
1224 if(pref
->order
[x
] == (index
+ 1)) {
1225 framems
= pref
->framing
[x
];
1230 /* size validation */
1232 framems
= AST_FORMAT_LIST
[index
].def_ms
;
1234 if(AST_FORMAT_LIST
[index
].inc_ms
&& framems
% AST_FORMAT_LIST
[index
].inc_ms
) /* avoid division by zero */
1235 framems
-= framems
% AST_FORMAT_LIST
[index
].inc_ms
;
1237 if(framems
< AST_FORMAT_LIST
[index
].min_ms
)
1238 framems
= AST_FORMAT_LIST
[index
].min_ms
;
1240 if(framems
> AST_FORMAT_LIST
[index
].max_ms
)
1241 framems
= AST_FORMAT_LIST
[index
].max_ms
;
1243 fmt
.cur_ms
= framems
;
1248 /*! \brief Pick a codec */
1249 int ast_codec_choose(struct ast_codec_pref
*pref
, int formats
, int find_best
)
1251 int x
, ret
= 0, slot
;
1253 for (x
= 0; x
< sizeof(AST_FORMAT_LIST
) / sizeof(AST_FORMAT_LIST
[0]); x
++) {
1254 slot
= pref
->order
[x
];
1258 if (formats
& AST_FORMAT_LIST
[slot
-1].bits
) {
1259 ret
= AST_FORMAT_LIST
[slot
-1].bits
;
1263 if(ret
& AST_FORMAT_AUDIO_MASK
)
1266 if (option_debug
> 3)
1267 ast_log(LOG_DEBUG
, "Could not find preferred codec - %s\n", find_best
? "Going for the best codec" : "Returning zero codec");
1269 return find_best
? ast_best_codec(formats
) : 0;
1272 void ast_parse_allow_disallow(struct ast_codec_pref
*pref
, int *mask
, const char *list
, int allowing
)
1274 char *parse
= NULL
, *this = NULL
, *psize
= NULL
;
1275 int format
= 0, framems
= 0;
1277 parse
= ast_strdupa(list
);
1278 while ((this = strsep(&parse
, ","))) {
1280 if ((psize
= strrchr(this, ':'))) {
1283 ast_log(LOG_DEBUG
,"Packetization for codec: %s is %s\n", this, psize
);
1284 framems
= atoi(psize
);
1288 if (!(format
= ast_getformatbyname(this))) {
1289 ast_log(LOG_WARNING
, "Cannot %s unknown format '%s'\n", allowing
? "allow" : "disallow", this);
1300 /* Set up a preference list for audio. Do not include video in preferences
1301 since we can not transcode video and have to use whatever is offered
1303 if (pref
&& (format
& AST_FORMAT_AUDIO_MASK
)) {
1304 if (strcasecmp(this, "all")) {
1306 ast_codec_pref_append(pref
, format
);
1307 ast_codec_pref_setsize(pref
, format
, framems
);
1310 ast_codec_pref_remove(pref
, format
);
1311 } else if (!allowing
) {
1312 memset(pref
, 0, sizeof(*pref
));
1318 static int g723_len(unsigned char buf
)
1320 enum frame_type type
= buf
& TYPE_MASK
;
1336 ast_log(LOG_WARNING
, "Badly encoded frame (%d)\n", type
);
1341 static int g723_samples(unsigned char *buf
, int maxlen
)
1346 while(pos
< maxlen
) {
1347 res
= g723_len(buf
[pos
]);
1356 static unsigned char get_n_bits_at(unsigned char *data
, int n
, int bit
)
1358 int byte
= bit
/ 8; /* byte containing first bit */
1359 int rem
= 8 - (bit
% 8); /* remaining bits in first byte */
1360 unsigned char ret
= 0;
1362 if (n
<= 0 || n
> 8)
1366 ret
= (data
[byte
] << (n
- rem
));
1367 ret
|= (data
[byte
+ 1] >> (8 - n
+ rem
));
1369 ret
= (data
[byte
] >> (rem
- n
));
1372 return (ret
& (0xff >> (8 - n
)));
1375 static int speex_get_wb_sz_at(unsigned char *data
, int len
, int bit
)
1377 static int SpeexWBSubModeSz
[] = {
1383 /* skip up to two wideband frames */
1384 if (((len
* 8 - off
) >= 5) &&
1385 get_n_bits_at(data
, 1, off
)) {
1386 c
= get_n_bits_at(data
, 3, off
+ 1);
1387 off
+= SpeexWBSubModeSz
[c
];
1389 if (((len
* 8 - off
) >= 5) &&
1390 get_n_bits_at(data
, 1, off
)) {
1391 c
= get_n_bits_at(data
, 3, off
+ 1);
1392 off
+= SpeexWBSubModeSz
[c
];
1394 if (((len
* 8 - off
) >= 5) &&
1395 get_n_bits_at(data
, 1, off
)) {
1396 ast_log(LOG_WARNING
, "Encountered corrupt speex frame; too many wideband frames in a row.\n");
1405 static int speex_samples(unsigned char *data
, int len
)
1407 static int SpeexSubModeSz
[] = {
1412 static int SpeexInBandSz
[] = {
1422 while ((len
* 8 - bit
) >= 5) {
1423 /* skip wideband frames */
1424 off
= speex_get_wb_sz_at(data
, len
, bit
);
1426 ast_log(LOG_WARNING
, "Had error while reading wideband frames for speex samples\n");
1431 if ((len
* 8 - bit
) < 5) {
1432 ast_log(LOG_WARNING
, "Not enough bits remaining after wide band for speex samples.\n");
1436 /* get control bits */
1437 c
= get_n_bits_at(data
, 5, bit
);
1443 } else if (c
== 14) {
1444 /* in-band signal; next 4 bits contain signal id */
1445 c
= get_n_bits_at(data
, 4, bit
);
1447 bit
+= SpeexInBandSz
[c
];
1448 } else if (c
== 13) {
1449 /* user in-band; next 5 bits contain msg len */
1450 c
= get_n_bits_at(data
, 5, bit
);
1457 /* skip number bits for submode (less the 5 control bits) */
1458 bit
+= SpeexSubModeSz
[c
] - 5;
1459 cnt
+= 160; /* new frame */
1465 int ast_codec_get_samples(struct ast_frame
*f
)
1468 switch(f
->subclass
) {
1469 case AST_FORMAT_SPEEX
:
1470 samples
= speex_samples(f
->data
, f
->datalen
);
1472 case AST_FORMAT_G723_1
:
1473 samples
= g723_samples(f
->data
, f
->datalen
);
1475 case AST_FORMAT_ILBC
:
1476 samples
= 240 * (f
->datalen
/ 50);
1478 case AST_FORMAT_GSM
:
1479 samples
= 160 * (f
->datalen
/ 33);
1481 case AST_FORMAT_G729A
:
1482 samples
= f
->datalen
* 8;
1484 case AST_FORMAT_SLINEAR
:
1485 samples
= f
->datalen
/ 2;
1487 case AST_FORMAT_LPC10
:
1488 /* assumes that the RTP packet contains one LPC10 frame */
1490 samples
+= (((char *)(f
->data
))[7] & 0x1) * 8;
1492 case AST_FORMAT_ULAW
:
1493 case AST_FORMAT_ALAW
:
1494 samples
= f
->datalen
;
1496 case AST_FORMAT_G722
:
1497 case AST_FORMAT_ADPCM
:
1498 case AST_FORMAT_G726
:
1499 case AST_FORMAT_G726_AAL2
:
1500 samples
= f
->datalen
* 2;
1503 ast_log(LOG_WARNING
, "Unable to calculate samples for format %s\n", ast_getformatname(f
->subclass
));
1508 int ast_codec_get_len(int format
, int samples
)
1512 /* XXX Still need speex, g723, and lpc10 XXX */
1514 case AST_FORMAT_ILBC
:
1515 len
= (samples
/ 240) * 50;
1517 case AST_FORMAT_GSM
:
1518 len
= (samples
/ 160) * 33;
1520 case AST_FORMAT_G729A
:
1523 case AST_FORMAT_SLINEAR
:
1526 case AST_FORMAT_ULAW
:
1527 case AST_FORMAT_ALAW
:
1530 case AST_FORMAT_G722
:
1531 case AST_FORMAT_ADPCM
:
1532 case AST_FORMAT_G726
:
1533 case AST_FORMAT_G726_AAL2
:
1537 ast_log(LOG_WARNING
, "Unable to calculate sample length for format %s\n", ast_getformatname(format
));
1543 int ast_frame_adjust_volume(struct ast_frame
*f
, int adjustment
)
1546 short *fdata
= f
->data
;
1547 short adjust_value
= abs(adjustment
);
1549 if ((f
->frametype
!= AST_FRAME_VOICE
) || (f
->subclass
!= AST_FORMAT_SLINEAR
))
1555 for (count
= 0; count
< f
->samples
; count
++) {
1556 if (adjustment
> 0) {
1557 ast_slinear_saturated_multiply(&fdata
[count
], &adjust_value
);
1558 } else if (adjustment
< 0) {
1559 ast_slinear_saturated_divide(&fdata
[count
], &adjust_value
);
1566 int ast_frame_slinear_sum(struct ast_frame
*f1
, struct ast_frame
*f2
)
1569 short *data1
, *data2
;
1571 if ((f1
->frametype
!= AST_FRAME_VOICE
) || (f1
->subclass
!= AST_FORMAT_SLINEAR
))
1574 if ((f2
->frametype
!= AST_FRAME_VOICE
) || (f2
->subclass
!= AST_FORMAT_SLINEAR
))
1577 if (f1
->samples
!= f2
->samples
)
1580 for (count
= 0, data1
= f1
->data
, data2
= f2
->data
;
1581 count
< f1
->samples
;
1582 count
++, data1
++, data2
++)
1583 ast_slinear_saturated_add(data1
, data2
);