don't mark these allocations as 'cache' allocations when caching has been disabled
[asterisk-bristuff.git] / main / frame.c
blob83599fff87f60cce5512be2c7b35d6e32408b09d
1 /*
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.
19 /*! \file
21 * \brief Frame and codec manipulation routines
23 * \author Mark Spencer <markster@digium.com>
26 #include "asterisk.h"
28 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
30 #include <stdlib.h>
31 #include <unistd.h>
32 #include <string.h>
33 #include <errno.h>
34 #include <stdio.h>
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"
47 #ifdef TRACE_FRAMES
48 static int headers;
49 static AST_LIST_HEAD_STATIC(headerlist, ast_frame);
50 #endif
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);
58 /*!
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.
66 */
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;
75 size_t size;
77 #endif
79 #define SMOOTHER_SIZE 8000
81 enum frame_type {
82 TYPE_HIGH, /* 0x0 */
83 TYPE_LOW, /* 0x1 */
84 TYPE_SILENCE, /* 0x2 */
85 TYPE_DONTSEND /* 0x3 */
88 #define TYPE_MASK 0x3
90 struct ast_smoother {
91 int size;
92 int format;
93 int readdata;
94 int optimizablestream;
95 int flags;
96 float samplesperbyte;
97 struct ast_frame f;
98 struct timeval delivery;
99 char data[SMOOTHER_SIZE];
100 char framedata[SMOOTHER_SIZE + AST_FRIENDLY_OFFSET];
101 struct ast_frame *opt;
102 int len;
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));
142 s->size = size;
145 struct ast_smoother *ast_smoother_new(int size)
147 struct ast_smoother *s;
148 if (size < 1)
149 return NULL;
150 if ((s = ast_malloc(sizeof(*s))))
151 ast_smoother_reset(s, size);
152 return s;
155 int ast_smoother_get_flags(struct ast_smoother *s)
157 return s->flags;
160 void ast_smoother_set_flags(struct ast_smoother *s, int flags)
162 s->flags = 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");
174 return -1;
176 if (!s->format) {
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);
181 return -1;
183 if (s->len + f->datalen > SMOOTHER_SIZE) {
184 ast_log(LOG_WARNING, "Out of smoother space\n");
185 return -1;
187 if (((f->datalen == s->size) || ((f->datalen < 10) && (s->flags & AST_SMOOTHER_FLAG_G729)))
188 && !s->opt && (f->offset >= AST_MIN_OFFSET)) {
189 if (!s->len) {
190 /* Optimize by sending the frame we just got
191 on the next read, thus eliminating the douple
192 copy */
193 if (swap)
194 ast_swapcopy_samples(f->data, f->data, f->samples);
195 s->opt = f;
196 return 0;
197 } else {
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 */
205 if (swap)
206 ast_swapcopy_samples(f->data, f->data, f->samples);
207 s->len = 0;
208 s->opt = f;
209 return 0;
212 } else
213 s->optimizablestream = 0;
214 if (s->flags & AST_SMOOTHER_FLAG_G729) {
215 if (s->len % 10) {
216 ast_log(LOG_NOTICE, "Dropping extra frame of G.729 since we already have a VAD frame at the end\n");
217 return 0;
220 if (swap)
221 ast_swapcopy_samples(s->data+s->len, f->data, f->samples);
222 else
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;
228 return 0;
231 struct ast_frame *ast_smoother_read(struct ast_smoother *s)
233 struct ast_frame *opt;
234 int len;
236 /* IF we have an optimization frame, send it */
237 if (s->opt) {
238 if (s->opt->offset < AST_FRIENDLY_OFFSET)
239 ast_log(LOG_WARNING, "Returning a frame of inappropriate offset (%d).\n",
240 s->opt->offset);
241 opt = s->opt;
242 s->opt = NULL;
243 return opt;
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)))
250 return NULL;
252 len = s->size;
253 if (len > s->len)
254 len = s->len;
255 /* Make frame */
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;
260 s->f.datalen = len;
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;
264 /* Fill Data */
265 memcpy(s->f.data, s->data, len);
266 s->len -= len;
267 /* Move remaining data to the front if applicable */
268 if (s->len) {
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));
277 /* Return frame */
278 return &s->f;
281 void ast_smoother_free(struct ast_smoother *s)
283 free(s);
286 static struct ast_frame *ast_frame_header_new(void)
288 struct ast_frame *f;
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;
299 frames->size--;
300 return f;
303 if (!(f = ast_calloc_cache(1, sizeof(*f))))
304 return NULL;
305 #else
306 if (!(f = ast_calloc(1, sizeof(*f))))
307 return NULL;
308 #endif
310 f->mallocd_hdr_len = sizeof(*f);
311 #ifdef TRACE_FRAMES
312 AST_LIST_LOCK(&headerlist);
313 headers++;
314 AST_LIST_INSERT_HEAD(&headerlist, f, frame_list);
315 AST_LIST_UNLOCK(&headerlist);
316 #endif
318 return f;
321 #if !defined(LOW_MEMORY)
322 static void frame_cache_cleanup(void *data)
324 struct ast_frame_cache *frames = data;
325 struct ast_frame *f;
327 while ((f = AST_LIST_REMOVE_HEAD(&frames->list, frame_list)))
328 free(f);
330 free(frames);
332 #endif
334 void ast_frame_free(struct ast_frame *fr, int cache)
336 if (!fr->mallocd)
337 return;
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);
348 frames->size++;
349 return;
352 #endif
354 if (fr->mallocd & AST_MALLOCD_DATA) {
355 if (fr->data)
356 free(fr->data - fr->offset);
358 if (fr->mallocd & AST_MALLOCD_SRC) {
359 if (fr->src)
360 free((char *)fr->src);
362 if (fr->mallocd & AST_MALLOCD_HDR) {
363 #ifdef TRACE_FRAMES
364 AST_LIST_LOCK(&headerlist);
365 headers--;
366 AST_LIST_REMOVE(&headerlist, fr, frame_list);
367 AST_LIST_UNLOCK(&headerlist);
368 #endif
369 free(fr);
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;
381 void *newdata;
383 if (!(fr->mallocd & AST_MALLOCD_HDR)) {
384 /* Allocate a new header if needed */
385 if (!(out = ast_frame_header_new()))
386 return NULL;
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) {
396 out->ts = fr->ts;
397 out->len = fr->len;
398 out->seqno = fr->seqno;
400 } else
401 out = fr;
403 if (!(fr->mallocd & AST_MALLOCD_SRC)) {
404 if (fr->src) {
405 if (!(out->src = ast_strdup(fr->src))) {
406 if (out != fr)
407 free(out);
408 return NULL;
411 } else
412 out->src = 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);
418 if (out != fr)
419 free(out);
420 return NULL;
422 newdata += AST_FRIENDLY_OFFSET;
423 out->offset = AST_FRIENDLY_OFFSET;
424 out->datalen = fr->datalen;
425 memcpy(newdata, fr->data, fr->datalen);
426 out->data = newdata;
429 out->mallocd = AST_MALLOCD_HDR | AST_MALLOCD_SRC | AST_MALLOCD_DATA;
431 return out;
434 struct ast_frame *ast_frdup(const struct ast_frame *f)
436 struct ast_frame *out = NULL;
437 int len, srclen = 0;
438 void *buf = NULL;
440 #if !defined(LOW_MEMORY)
441 struct ast_frame_cache *frames;
442 #endif
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.
451 if (f->src)
452 srclen = strlen(f->src);
453 if (srclen > 0)
454 len += srclen + 1;
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;
464 buf = out;
465 frames->size--;
466 break;
469 AST_LIST_TRAVERSE_SAFE_END
471 #endif
473 if (!buf) {
474 if (!(buf = ast_calloc_cache(1, len)))
475 return NULL;
476 out = buf;
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
486 get freed. */
487 out->mallocd = AST_MALLOCD_HDR;
488 out->offset = AST_FRIENDLY_OFFSET;
489 if (out->datalen) {
490 out->data = buf + sizeof(*out) + AST_FRIENDLY_OFFSET;
491 memcpy(out->data, f->data, out->datalen);
493 if (srclen > 0) {
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) {
500 out->ts = f->ts;
501 out->len = f->len;
502 out->seqno = f->seqno;
504 return out;
507 void ast_swapcopy_samples(void *dst, const void *src, int samples)
509 int i;
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)
531 int x;
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;
536 break;
539 return ret;
542 char *ast_getformatname_multiple(char *buf, size_t size, int format)
544 int x;
545 unsigned len;
546 char *start, *end = buf;
548 if (!size)
549 return buf;
550 snprintf(end, size, "0x%x (", format);
551 len = strlen(end);
552 end += len;
553 size -= len;
554 start = end;
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);
558 len = strlen(end);
559 end += len;
560 size -= len;
563 if (start == end)
564 snprintf(start, size, "nothing)");
565 else if (size > 1)
566 *(end -1) = ')';
567 return buf;
570 static struct ast_codec_alias_table {
571 char *alias;
572 char *realname;
573 } ast_codec_alias_table[] = {
574 { "slinear", "slin"},
575 { "g723.1", "g723"},
578 static const char *ast_expand_codec_alias(const char *in)
580 int x;
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;
586 return in;
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;
599 if(!all)
600 break;
604 return format;
607 char *ast_codec2str(int codec)
609 int x;
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;
614 break;
617 return ret;
620 static int show_codecs_deprecated(int fd, int argc, char *argv[])
622 int i, found=0;
623 char hex[25];
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"))) {
635 found = 1;
636 for (i=0;i<13;i++) {
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"))) {
643 found = 1;
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"))) {
651 found = 1;
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));
658 if (! found)
659 return RESULT_SHOWUSAGE;
660 else
661 return RESULT_SUCCESS;
664 static int show_codecs(int fd, int argc, char *argv[])
666 int i, found=0;
667 char hex[25];
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"))) {
679 found = 1;
680 for (i=0;i<13;i++) {
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"))) {
687 found = 1;
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"))) {
695 found = 1;
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));
702 if (! found)
703 return RESULT_SHOWUSAGE;
704 else
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;
716 if (argc != 3)
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)) {
724 found = 1;
725 ast_cli(fd, "%11u (1 << %2d) %s\n",1 << i,i,ast_codec2str(1<<i));
728 if (!found)
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;
738 if (argc != 4)
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)) {
746 found = 1;
747 ast_cli(fd, "%11u (1 << %2d) %s\n",1 << i,i,ast_codec2str(1<<i));
750 if (!found)
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";
765 char cft[80];
766 char subclass[40] = "Unknown Subclass";
767 char csub[80];
768 char moreinfo[40] = "";
769 char cn[60];
770 char cp[40];
771 char cmn[40];
773 if (!name)
774 name = noname;
777 if (!f) {
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)));
782 return;
784 /* XXX We should probably print one each of voice and video when the format changes XXX */
785 if (f->frametype == AST_FRAME_VOICE)
786 return;
787 if (f->frametype == AST_FRAME_VIDEO)
788 return;
789 switch(f->frametype) {
790 case AST_FRAME_DTMF_BEGIN:
791 strcpy(ftype, "DTMF Begin");
792 subclass[0] = f->subclass;
793 subclass[1] = '\0';
794 break;
795 case AST_FRAME_DTMF_END:
796 strcpy(ftype, "DTMF End");
797 subclass[0] = f->subclass;
798 subclass[1] = '\0';
799 break;
800 case AST_FRAME_CONTROL:
801 strcpy(ftype, "Control");
802 switch(f->subclass) {
803 case AST_CONTROL_HANGUP:
804 strcpy(subclass, "Hangup");
805 break;
806 case AST_CONTROL_RING:
807 strcpy(subclass, "Ring");
808 break;
809 case AST_CONTROL_RINGING:
810 strcpy(subclass, "Ringing");
811 break;
812 case AST_CONTROL_ANSWER:
813 strcpy(subclass, "Answer");
814 break;
815 case AST_CONTROL_BUSY:
816 strcpy(subclass, "Busy");
817 break;
818 case AST_CONTROL_TAKEOFFHOOK:
819 strcpy(subclass, "Take Off Hook");
820 break;
821 case AST_CONTROL_OFFHOOK:
822 strcpy(subclass, "Line Off Hook");
823 break;
824 case AST_CONTROL_CONGESTION:
825 strcpy(subclass, "Congestion");
826 break;
827 case AST_CONTROL_FLASH:
828 strcpy(subclass, "Flash");
829 break;
830 case AST_CONTROL_WINK:
831 strcpy(subclass, "Wink");
832 break;
833 case AST_CONTROL_OPTION:
834 strcpy(subclass, "Option");
835 break;
836 case AST_CONTROL_RADIO_KEY:
837 strcpy(subclass, "Key Radio");
838 break;
839 case AST_CONTROL_RADIO_UNKEY:
840 strcpy(subclass, "Unkey Radio");
841 break;
842 case -1:
843 strcpy(subclass, "Stop generators");
844 break;
845 default:
846 snprintf(subclass, sizeof(subclass), "Unknown control '%d'", f->subclass);
848 break;
849 case AST_FRAME_NULL:
850 strcpy(ftype, "Null Frame");
851 strcpy(subclass, "N/A");
852 break;
853 case AST_FRAME_IAX:
854 /* Should never happen */
855 strcpy(ftype, "IAX Specific");
856 snprintf(subclass, sizeof(subclass), "IAX Frametype %d", f->subclass);
857 break;
858 case AST_FRAME_TEXT:
859 strcpy(ftype, "Text");
860 strcpy(subclass, "N/A");
861 ast_copy_string(moreinfo, f->data, sizeof(moreinfo));
862 break;
863 case AST_FRAME_IMAGE:
864 strcpy(ftype, "Image");
865 snprintf(subclass, sizeof(subclass), "Image format %s\n", ast_getformatname(f->subclass));
866 break;
867 case AST_FRAME_HTML:
868 strcpy(ftype, "HTML");
869 switch(f->subclass) {
870 case AST_HTML_URL:
871 strcpy(subclass, "URL");
872 ast_copy_string(moreinfo, f->data, sizeof(moreinfo));
873 break;
874 case AST_HTML_DATA:
875 strcpy(subclass, "Data");
876 break;
877 case AST_HTML_BEGIN:
878 strcpy(subclass, "Begin");
879 break;
880 case AST_HTML_END:
881 strcpy(subclass, "End");
882 break;
883 case AST_HTML_LDCOMPLETE:
884 strcpy(subclass, "Load Complete");
885 break;
886 case AST_HTML_NOSUPPORT:
887 strcpy(subclass, "No Support");
888 break;
889 case AST_HTML_LINKURL:
890 strcpy(subclass, "Link URL");
891 ast_copy_string(moreinfo, f->data, sizeof(moreinfo));
892 break;
893 case AST_HTML_UNLINK:
894 strcpy(subclass, "Unlink");
895 break;
896 case AST_HTML_LINKREJECT:
897 strcpy(subclass, "Link Reject");
898 break;
899 default:
900 snprintf(subclass, sizeof(subclass), "Unknown HTML frame '%d'\n", f->subclass);
901 break;
903 break;
904 case AST_FRAME_MODEM:
905 strcpy(ftype, "Modem");
906 switch (f->subclass) {
907 case AST_MODEM_T38:
908 strcpy(subclass, "T.38");
909 break;
910 case AST_MODEM_V150:
911 strcpy(subclass, "V.150");
912 break;
913 default:
914 snprintf(subclass, sizeof(subclass), "Unknown MODEM frame '%d'\n", f->subclass);
915 break;
917 break;
918 default:
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)),
925 f->frametype,
926 term_color(csub, subclass, COLOR_BRCYAN, COLOR_BLACK, sizeof(csub)),
927 f->subclass,
928 term_color(cmn, moreinfo, COLOR_BRGREEN, COLOR_BLACK, sizeof(cmn)),
929 term_color(cn, name, COLOR_YELLOW, COLOR_BLACK, sizeof(cn)));
930 else
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)),
934 f->frametype,
935 term_color(csub, subclass, COLOR_BRCYAN, COLOR_BLACK, sizeof(csub)),
936 f->subclass,
937 term_color(cn, name, COLOR_YELLOW, COLOR_BLACK, sizeof(cn)));
941 #ifdef TRACE_FRAMES
942 static int show_frame_stats_deprecated(int fd, int argc, char *argv[])
944 struct ast_frame *f;
945 int x=1;
946 if (argc != 3)
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[])
961 struct ast_frame *f;
962 int x=1;
963 if (argc != 4)
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";
979 #endif
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,
985 NULL };
987 static struct ast_cli_entry cli_show_audio_codecs = {
988 { "show", "audio", "codecs", NULL },
989 show_codecs_deprecated, NULL,
990 NULL };
992 static struct ast_cli_entry cli_show_video_codecs = {
993 { "show", "video", "codecs", NULL },
994 show_codecs_deprecated, NULL,
995 NULL };
997 static struct ast_cli_entry cli_show_image_codecs = {
998 { "show", "image", "codecs", NULL },
999 show_codecs_deprecated, NULL,
1000 NULL };
1002 static struct ast_cli_entry cli_show_codec = {
1003 { "show", "codec", NULL },
1004 show_codec_n_deprecated, NULL,
1005 NULL };
1007 #ifdef TRACE_FRAMES
1008 static struct ast_cli_entry cli_show_frame_stats = {
1009 { "show", "frame", "stats", NULL },
1010 show_frame_stats, NULL,
1011 NULL };
1012 #endif
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 },
1035 #ifdef TRACE_FRAMES
1036 { { "core", "show", "frame", "stats", NULL },
1037 show_frame_stats, "Shows frame statistics",
1038 frame_stats_usage, NULL, &cli_show_frame_stats },
1039 #endif
1042 int init_framer(void)
1044 ast_cli_register_multiple(my_clis, sizeof(my_clis) / sizeof(struct ast_cli_entry));
1045 return 0;
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;
1051 char *from, *to;
1053 if(right) {
1054 from = pref->order;
1055 to = buf;
1056 mem = size;
1057 } else {
1058 to = pref->order;
1059 from = buf;
1060 mem = 32;
1063 memset(to, 0, mem);
1064 for (x = 0; x < 32 ; x++) {
1065 if(!from[x])
1066 break;
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)
1073 int x, codec;
1074 size_t total_len, slen;
1075 char *formatname;
1077 memset(buf,0,size);
1078 total_len = size;
1079 buf[0] = '(';
1080 total_len--;
1081 for(x = 0; x < 32 ; x++) {
1082 if(total_len <= 0)
1083 break;
1084 if(!(codec = ast_codec_pref_index(pref,x)))
1085 break;
1086 if((formatname = ast_getformatname(codec))) {
1087 slen = strlen(formatname);
1088 if(slen > total_len)
1089 break;
1090 strncat(buf,formatname,total_len);
1091 total_len -= slen;
1093 if(total_len && x < 31 && ast_codec_pref_index(pref , x + 1)) {
1094 strncat(buf,"|",total_len);
1095 total_len--;
1098 if(total_len) {
1099 strncat(buf,")",total_len);
1100 total_len--;
1103 return size - total_len;
1106 int ast_codec_pref_index(struct ast_codec_pref *pref, int index)
1108 int slot = 0;
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;
1122 int x, y = 0;
1123 int slot;
1124 int size;
1126 if(!pref->order[0])
1127 return;
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];
1135 if(! slot)
1136 break;
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) {
1154 newindex = x + 1;
1155 break;
1159 if(newindex) {
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;
1163 break;
1168 return x;
1172 /*! \brief Set packet size for codec */
1173 int ast_codec_pref_setsize(struct ast_codec_pref *pref, int format, int framems)
1175 int x, index = -1;
1177 for (x = 0; x < sizeof(AST_FORMAT_LIST) / sizeof(AST_FORMAT_LIST[0]); x++) {
1178 if(AST_FORMAT_LIST[x].bits == format) {
1179 index = x;
1180 break;
1184 if(index < 0)
1185 return -1;
1187 /* size validation */
1188 if(!framems)
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;
1204 break;
1208 return x;
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];
1220 index = x;
1221 break;
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];
1228 break;
1232 /* size validation */
1233 if(!framems)
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;
1247 return fmt;
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];
1258 if (!slot)
1259 break;
1260 if (formats & AST_FORMAT_LIST[slot-1].bits) {
1261 ret = AST_FORMAT_LIST[slot-1].bits;
1262 break;
1265 if(ret & AST_FORMAT_AUDIO_MASK)
1266 return ret;
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, ","))) {
1281 framems = 0;
1282 if ((psize = strrchr(this, ':'))) {
1283 *psize++ = '\0';
1284 if (option_debug)
1285 ast_log(LOG_DEBUG,"Packetization for codec: %s is %s\n", this, psize);
1286 framems = atoi(psize);
1287 if (framems < 0)
1288 framems = 0;
1290 if (!(format = ast_getformatbyname(this))) {
1291 ast_log(LOG_WARNING, "Cannot %s unknown format '%s'\n", allowing ? "allow" : "disallow", this);
1292 continue;
1295 if (mask) {
1296 if (allowing)
1297 *mask |= format;
1298 else
1299 *mask &= ~format;
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")) {
1307 if (allowing) {
1308 ast_codec_pref_append(pref, format);
1309 ast_codec_pref_setsize(pref, format, framems);
1311 else
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;
1324 switch(type) {
1325 case TYPE_DONTSEND:
1326 return 0;
1327 break;
1328 case TYPE_SILENCE:
1329 return 4;
1330 break;
1331 case TYPE_HIGH:
1332 return 24;
1333 break;
1334 case TYPE_LOW:
1335 return 20;
1336 break;
1337 default:
1338 ast_log(LOG_WARNING, "Badly encoded frame (%d)\n", type);
1340 return -1;
1343 static int g723_samples(unsigned char *buf, int maxlen)
1345 int pos = 0;
1346 int samples = 0;
1347 int res;
1348 while(pos < maxlen) {
1349 res = g723_len(buf[pos]);
1350 if (res <= 0)
1351 break;
1352 samples += 240;
1353 pos += res;
1355 return samples;
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)
1365 return 0;
1367 if (rem < n) {
1368 ret = (data[byte] << (n - rem));
1369 ret |= (data[byte + 1] >> (8 - n + rem));
1370 } else {
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[] = {
1380 0, 36, 112, 192,
1381 352, 0, 0, 0 };
1382 int off = bit;
1383 unsigned char c;
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");
1399 return -1;
1404 return off - bit;
1407 static int speex_samples(unsigned char *data, int len)
1409 static int SpeexSubModeSz[] = {
1410 5, 43, 119, 160,
1411 220, 300, 364, 492,
1412 79, 0, 0, 0,
1413 0, 0, 0, 0 };
1414 static int SpeexInBandSz[] = {
1415 1, 1, 4, 4,
1416 4, 4, 4, 4,
1417 8, 8, 16, 16,
1418 32, 32, 64, 64 };
1419 int bit = 0;
1420 int cnt = 0;
1421 int off;
1422 unsigned char c;
1424 while ((len * 8 - bit) >= 5) {
1425 /* skip wideband frames */
1426 off = speex_get_wb_sz_at(data, len, bit);
1427 if (off < 0) {
1428 ast_log(LOG_WARNING, "Had error while reading wideband frames for speex samples\n");
1429 break;
1431 bit += off;
1433 if ((len * 8 - bit) < 5) {
1434 ast_log(LOG_WARNING, "Not enough bits remaining after wide band for speex samples.\n");
1435 break;
1438 /* get control bits */
1439 c = get_n_bits_at(data, 5, bit);
1440 bit += 5;
1442 if (c == 15) {
1443 /* terminator */
1444 break;
1445 } else if (c == 14) {
1446 /* in-band signal; next 4 bits contain signal id */
1447 c = get_n_bits_at(data, 4, bit);
1448 bit += 4;
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);
1453 bit += 5;
1454 bit += c * 8;
1455 } else if (c > 8) {
1456 /* unknown */
1457 break;
1458 } else {
1459 /* skip number bits for submode (less the 5 control bits) */
1460 bit += SpeexSubModeSz[c] - 5;
1461 cnt += 160; /* new frame */
1464 return cnt;
1467 int ast_codec_get_samples(struct ast_frame *f)
1469 int samples=0;
1470 switch(f->subclass) {
1471 case AST_FORMAT_SPEEX:
1472 samples = speex_samples(f->data, f->datalen);
1473 break;
1474 case AST_FORMAT_G723_1:
1475 samples = g723_samples(f->data, f->datalen);
1476 break;
1477 case AST_FORMAT_ILBC:
1478 samples = 240 * (f->datalen / 50);
1479 break;
1480 case AST_FORMAT_GSM:
1481 samples = 160 * (f->datalen / 33);
1482 break;
1483 case AST_FORMAT_G729A:
1484 samples = f->datalen * 8;
1485 break;
1486 case AST_FORMAT_SLINEAR:
1487 samples = f->datalen / 2;
1488 break;
1489 case AST_FORMAT_LPC10:
1490 /* assumes that the RTP packet contains one LPC10 frame */
1491 samples = 22 * 8;
1492 samples += (((char *)(f->data))[7] & 0x1) * 8;
1493 break;
1494 case AST_FORMAT_ULAW:
1495 case AST_FORMAT_ALAW:
1496 case AST_FORMAT_G722:
1497 samples = f->datalen;
1498 break;
1499 case AST_FORMAT_ADPCM:
1500 case AST_FORMAT_G726:
1501 case AST_FORMAT_G726_AAL2:
1502 samples = f->datalen * 2;
1503 break;
1504 default:
1505 ast_log(LOG_WARNING, "Unable to calculate samples for format %s\n", ast_getformatname(f->subclass));
1507 return samples;
1510 int ast_codec_get_len(int format, int samples)
1512 int len = 0;
1514 /* XXX Still need speex, g723, and lpc10 XXX */
1515 switch(format) {
1516 case AST_FORMAT_ILBC:
1517 len = (samples / 240) * 50;
1518 break;
1519 case AST_FORMAT_GSM:
1520 len = (samples / 160) * 33;
1521 break;
1522 case AST_FORMAT_G729A:
1523 len = samples / 8;
1524 break;
1525 case AST_FORMAT_SLINEAR:
1526 len = samples * 2;
1527 break;
1528 case AST_FORMAT_ULAW:
1529 case AST_FORMAT_ALAW:
1530 len = samples;
1531 break;
1532 case AST_FORMAT_ADPCM:
1533 case AST_FORMAT_G726:
1534 case AST_FORMAT_G726_AAL2:
1535 len = samples / 2;
1536 break;
1537 default:
1538 ast_log(LOG_WARNING, "Unable to calculate sample length for format %s\n", ast_getformatname(format));
1541 return len;
1544 int ast_frame_adjust_volume(struct ast_frame *f, int adjustment)
1546 int count;
1547 short *fdata = f->data;
1548 short adjust_value = abs(adjustment);
1550 if ((f->frametype != AST_FRAME_VOICE) || (f->subclass != AST_FORMAT_SLINEAR))
1551 return -1;
1553 if (!adjustment)
1554 return 0;
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);
1564 return 0;
1567 int ast_frame_slinear_sum(struct ast_frame *f1, struct ast_frame *f2)
1569 int count;
1570 short *data1, *data2;
1572 if ((f1->frametype != AST_FRAME_VOICE) || (f1->subclass != AST_FORMAT_SLINEAR))
1573 return -1;
1575 if ((f2->frametype != AST_FRAME_VOICE) || (f2->subclass != AST_FORMAT_SLINEAR))
1576 return -1;
1578 if (f1->samples != f2->samples)
1579 return -1;
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);
1586 return 0;