document usage of 'transfer' configuration option for ISDN PRI switch-side transfers
[asterisk-bristuff.git] / main / frame.c
blob1dafce9f8497466d2b536966a27f8338672ab50d
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"
46 #include "asterisk/translate.h"
48 #ifdef TRACE_FRAMES
49 static int headers;
50 static AST_LIST_HEAD_STATIC(headerlist, ast_frame);
51 #endif
53 #if !defined(LOW_MEMORY)
54 static void frame_cache_cleanup(void *data);
56 /*! \brief A per-thread cache of frame headers */
57 AST_THREADSTORAGE_CUSTOM(frame_cache, frame_cache_init, frame_cache_cleanup);
59 /*!
60 * \brief Maximum ast_frame cache size
62 * In most cases where the frame header cache will be useful, the size
63 * of the cache will stay very small. However, it is not always the case that
64 * the same thread that allocates the frame will be the one freeing them, so
65 * sometimes a thread will never have any frames in its cache, or the cache
66 * will never be pulled from. For the latter case, we limit the maximum size.
67 */
68 #define FRAME_CACHE_MAX_SIZE 10
70 /*! \brief This is just so ast_frames, a list head struct for holding a list of
71 * ast_frame structures, is defined. */
72 AST_LIST_HEAD_NOLOCK(ast_frames, ast_frame);
74 struct ast_frame_cache {
75 struct ast_frames list;
76 size_t size;
78 #endif
80 #define SMOOTHER_SIZE 8000
82 enum frame_type {
83 TYPE_HIGH, /* 0x0 */
84 TYPE_LOW, /* 0x1 */
85 TYPE_SILENCE, /* 0x2 */
86 TYPE_DONTSEND /* 0x3 */
89 #define TYPE_MASK 0x3
91 struct ast_smoother {
92 int size;
93 int format;
94 int readdata;
95 int optimizablestream;
96 int flags;
97 float samplesperbyte;
98 struct ast_frame f;
99 struct timeval delivery;
100 char data[SMOOTHER_SIZE];
101 char framedata[SMOOTHER_SIZE + AST_FRIENDLY_OFFSET];
102 struct ast_frame *opt;
103 int len;
106 /*! \brief Definition of supported media formats (codecs) */
107 static struct ast_format_list AST_FORMAT_LIST[] = { /*!< Bit number: comment - Bit numbers are hard coded in show_codec() */
108 { 1, AST_FORMAT_G723_1 , "g723" , "G.723.1", 24, 30, 300, 30, 30 }, /*!< 1 */
109 { 1, AST_FORMAT_GSM, "gsm" , "GSM", 33, 20, 300, 20, 20 }, /*!< 2: codec_gsm.c */
110 { 1, AST_FORMAT_ULAW, "ulaw", "G.711 u-law", 80, 10, 150, 10, 20 }, /*!< 3: codec_ulaw.c */
111 { 1, AST_FORMAT_ALAW, "alaw", "G.711 A-law", 80, 10, 150, 10, 20 }, /*!< 4: codec_alaw.c */
112 { 1, AST_FORMAT_G726, "g726", "G.726 RFC3551", 40, 10, 300, 10, 20 }, /*!< 5: codec_g726.c */
113 { 1, AST_FORMAT_ADPCM, "adpcm" , "ADPCM", 40, 10, 300, 10, 20 }, /*!< 6: codec_adpcm.c */
114 { 1, AST_FORMAT_SLINEAR, "slin", "16 bit Signed Linear PCM", 160, 10, 70, 10, 20, AST_SMOOTHER_FLAG_BE }, /*!< 7 */
115 { 1, AST_FORMAT_LPC10, "lpc10", "LPC10", 7, 20, 20, 20, 20 }, /*!< 8: codec_lpc10.c */
116 { 1, AST_FORMAT_G729A, "g729", "G.729A", 10, 10, 230, 10, 20, AST_SMOOTHER_FLAG_G729 }, /*!< 9: Binary commercial distribution */
117 { 1, AST_FORMAT_SPEEX, "speex", "SpeeX", 10, 10, 60, 10, 20 }, /*!< 10: codec_speex.c */
118 { 1, AST_FORMAT_ILBC, "ilbc", "iLBC", 50, 30, 30, 30, 30 }, /*!< 11: codec_ilbc.c */ /* inc=30ms - workaround */
119 { 1, AST_FORMAT_G726_AAL2, "g726aal2", "G.726 AAL2", 40, 10, 300, 10, 20 }, /*!< 12: codec_g726.c */
120 { 1, AST_FORMAT_G722, "g722", "G722"}, /*!< 13 */
121 { 0, 0, "nothing", "undefined" },
122 { 0, 0, "nothing", "undefined" },
123 { 0, 0, "nothing", "undefined" },
124 { 0, 0, "nothing", "undefined" },
125 { 0, AST_FORMAT_MAX_AUDIO, "maxaudio", "Maximum audio format" },
126 { 1, AST_FORMAT_JPEG, "jpeg", "JPEG image"}, /*!< 17: See format_jpeg.c */
127 { 1, AST_FORMAT_PNG, "png", "PNG image"}, /*!< 18: Image format */
128 { 1, AST_FORMAT_H261, "h261", "H.261 Video" }, /*!< 19: Video Passthrough */
129 { 1, AST_FORMAT_H263, "h263", "H.263 Video" }, /*!< 20: Passthrough support, see format_h263.c */
130 { 1, AST_FORMAT_H263_PLUS, "h263p", "H.263+ Video" }, /*!< 21: See format_h263.c */
131 { 1, AST_FORMAT_H264, "h264", "H.264 Video" }, /*!< 22: Passthrough support, see format_h263.c */
132 { 0, 0, "nothing", "undefined" },
133 { 0, 0, "nothing", "undefined" },
134 { 0, 0, "nothing", "undefined" },
135 { 0, AST_FORMAT_MAX_VIDEO, "maxvideo", "Maximum video format" },
138 struct ast_frame ast_null_frame = { AST_FRAME_NULL, };
140 void ast_smoother_reset(struct ast_smoother *s, int size)
142 memset(s, 0, sizeof(*s));
143 s->size = size;
146 struct ast_smoother *ast_smoother_new(int size)
148 struct ast_smoother *s;
149 if (size < 1)
150 return NULL;
151 if ((s = ast_malloc(sizeof(*s))))
152 ast_smoother_reset(s, size);
153 return s;
156 int ast_smoother_get_flags(struct ast_smoother *s)
158 return s->flags;
161 void ast_smoother_set_flags(struct ast_smoother *s, int flags)
163 s->flags = flags;
166 int ast_smoother_test_flag(struct ast_smoother *s, int flag)
168 return (s->flags & flag);
171 int __ast_smoother_feed(struct ast_smoother *s, struct ast_frame *f, int swap)
173 if (f->frametype != AST_FRAME_VOICE) {
174 ast_log(LOG_WARNING, "Huh? Can't smooth a non-voice frame!\n");
175 return -1;
177 if (!s->format) {
178 s->format = f->subclass;
179 s->samplesperbyte = (float)f->samples / (float)f->datalen;
180 } else if (s->format != f->subclass) {
181 ast_log(LOG_WARNING, "Smoother was working on %d format frames, now trying to feed %d?\n", s->format, f->subclass);
182 return -1;
184 if (s->len + f->datalen > SMOOTHER_SIZE) {
185 ast_log(LOG_WARNING, "Out of smoother space\n");
186 return -1;
188 if (((f->datalen == s->size) || ((f->datalen < 10) && (s->flags & AST_SMOOTHER_FLAG_G729)))
189 && !s->opt && (f->offset >= AST_MIN_OFFSET)) {
190 if (!s->len) {
191 /* Optimize by sending the frame we just got
192 on the next read, thus eliminating the douple
193 copy */
194 if (swap)
195 ast_swapcopy_samples(f->data, f->data, f->samples);
196 s->opt = f;
197 return 0;
198 } else {
199 s->optimizablestream++;
200 if (s->optimizablestream > 10) {
201 /* For the past 10 rounds, we have input and output
202 frames of the correct size for this smoother, yet
203 we were unable to optimize because there was still
204 some cruft left over. Lets just drop the cruft so
205 we can move to a fully optimized path */
206 if (swap)
207 ast_swapcopy_samples(f->data, f->data, f->samples);
208 s->len = 0;
209 s->opt = f;
210 return 0;
213 } else
214 s->optimizablestream = 0;
215 if (s->flags & AST_SMOOTHER_FLAG_G729) {
216 if (s->len % 10) {
217 ast_log(LOG_NOTICE, "Dropping extra frame of G.729 since we already have a VAD frame at the end\n");
218 return 0;
221 if (swap)
222 ast_swapcopy_samples(s->data+s->len, f->data, f->samples);
223 else
224 memcpy(s->data + s->len, f->data, f->datalen);
225 /* If either side is empty, reset the delivery time */
226 if (!s->len || ast_tvzero(f->delivery) || ast_tvzero(s->delivery)) /* XXX really ? */
227 s->delivery = f->delivery;
228 s->len += f->datalen;
229 return 0;
232 struct ast_frame *ast_smoother_read(struct ast_smoother *s)
234 struct ast_frame *opt;
235 int len;
237 /* IF we have an optimization frame, send it */
238 if (s->opt) {
239 if (s->opt->offset < AST_FRIENDLY_OFFSET)
240 ast_log(LOG_WARNING, "Returning a frame of inappropriate offset (%d).\n",
241 s->opt->offset);
242 opt = s->opt;
243 s->opt = NULL;
244 return opt;
247 /* Make sure we have enough data */
248 if (s->len < s->size) {
249 /* Or, if this is a G.729 frame with VAD on it, send it immediately anyway */
250 if (!((s->flags & AST_SMOOTHER_FLAG_G729) && (s->size % 10)))
251 return NULL;
253 len = s->size;
254 if (len > s->len)
255 len = s->len;
256 /* Make frame */
257 s->f.frametype = AST_FRAME_VOICE;
258 s->f.subclass = s->format;
259 s->f.data = s->framedata + AST_FRIENDLY_OFFSET;
260 s->f.offset = AST_FRIENDLY_OFFSET;
261 s->f.datalen = len;
262 /* Samples will be improper given VAD, but with VAD the concept really doesn't even exist */
263 s->f.samples = len * s->samplesperbyte; /* XXX rounding */
264 s->f.delivery = s->delivery;
265 /* Fill Data */
266 memcpy(s->f.data, s->data, len);
267 s->len -= len;
268 /* Move remaining data to the front if applicable */
269 if (s->len) {
270 /* In principle this should all be fine because if we are sending
271 G.729 VAD, the next timestamp will take over anyawy */
272 memmove(s->data, s->data + len, s->len);
273 if (!ast_tvzero(s->delivery)) {
274 /* If we have delivery time, increment it, otherwise, leave it at 0 */
275 s->delivery = ast_tvadd(s->delivery, ast_samp2tv(s->f.samples, 8000));
278 /* Return frame */
279 return &s->f;
282 void ast_smoother_free(struct ast_smoother *s)
284 free(s);
287 static struct ast_frame *ast_frame_header_new(void)
289 struct ast_frame *f;
291 #if !defined(LOW_MEMORY)
292 struct ast_frame_cache *frames;
294 if ((frames = ast_threadstorage_get(&frame_cache, sizeof(*frames)))) {
295 if ((f = AST_LIST_REMOVE_HEAD(&frames->list, frame_list))) {
296 size_t mallocd_len = f->mallocd_hdr_len;
297 memset(f, 0, sizeof(*f));
298 f->mallocd_hdr_len = mallocd_len;
299 f->mallocd = AST_MALLOCD_HDR;
300 frames->size--;
301 return f;
304 if (!(f = ast_calloc_cache(1, sizeof(*f))))
305 return NULL;
306 #else
307 if (!(f = ast_calloc(1, sizeof(*f))))
308 return NULL;
309 #endif
311 f->mallocd_hdr_len = sizeof(*f);
312 #ifdef TRACE_FRAMES
313 AST_LIST_LOCK(&headerlist);
314 headers++;
315 AST_LIST_INSERT_HEAD(&headerlist, f, frame_list);
316 AST_LIST_UNLOCK(&headerlist);
317 #endif
319 return f;
322 #if !defined(LOW_MEMORY)
323 static void frame_cache_cleanup(void *data)
325 struct ast_frame_cache *frames = data;
326 struct ast_frame *f;
328 while ((f = AST_LIST_REMOVE_HEAD(&frames->list, frame_list)))
329 free(f);
331 free(frames);
333 #endif
335 void ast_frame_free(struct ast_frame *fr, int cache)
337 if (ast_test_flag(fr, AST_FRFLAG_FROM_TRANSLATOR))
338 ast_translate_frame_freed(fr);
340 if (!fr->mallocd)
341 return;
343 #if !defined(LOW_MEMORY)
344 if (cache && fr->mallocd == AST_MALLOCD_HDR) {
345 /* Cool, only the header is malloc'd, let's just cache those for now
346 * to keep things simple... */
347 struct ast_frame_cache *frames;
349 if ((frames = ast_threadstorage_get(&frame_cache, sizeof(*frames)))
350 && frames->size < FRAME_CACHE_MAX_SIZE) {
351 AST_LIST_INSERT_HEAD(&frames->list, fr, frame_list);
352 frames->size++;
353 return;
356 #endif
358 if (fr->mallocd & AST_MALLOCD_DATA) {
359 if (fr->data)
360 free(fr->data - fr->offset);
362 if (fr->mallocd & AST_MALLOCD_SRC) {
363 if (fr->src)
364 free((char *)fr->src);
366 if (fr->mallocd & AST_MALLOCD_HDR) {
367 #ifdef TRACE_FRAMES
368 AST_LIST_LOCK(&headerlist);
369 headers--;
370 AST_LIST_REMOVE(&headerlist, fr, frame_list);
371 AST_LIST_UNLOCK(&headerlist);
372 #endif
373 free(fr);
378 * \brief 'isolates' a frame by duplicating non-malloc'ed components
379 * (header, src, data).
380 * On return all components are malloc'ed
382 struct ast_frame *ast_frisolate(struct ast_frame *fr)
384 struct ast_frame *out;
385 void *newdata;
387 ast_clear_flag(fr, AST_FRFLAG_FROM_TRANSLATOR);
389 if (!(fr->mallocd & AST_MALLOCD_HDR)) {
390 /* Allocate a new header if needed */
391 if (!(out = ast_frame_header_new()))
392 return NULL;
393 out->frametype = fr->frametype;
394 out->subclass = fr->subclass;
395 out->datalen = fr->datalen;
396 out->samples = fr->samples;
397 out->offset = fr->offset;
398 out->data = fr->data;
399 /* Copy the timing data */
400 ast_copy_flags(out, fr, AST_FRFLAG_HAS_TIMING_INFO);
401 if (ast_test_flag(fr, AST_FRFLAG_HAS_TIMING_INFO)) {
402 out->ts = fr->ts;
403 out->len = fr->len;
404 out->seqno = fr->seqno;
406 } else
407 out = fr;
409 if (!(fr->mallocd & AST_MALLOCD_SRC)) {
410 if (fr->src) {
411 if (!(out->src = ast_strdup(fr->src))) {
412 if (out != fr)
413 free(out);
414 return NULL;
417 } else
418 out->src = fr->src;
420 if (!(fr->mallocd & AST_MALLOCD_DATA)) {
421 if (!(newdata = ast_malloc(fr->datalen + AST_FRIENDLY_OFFSET))) {
422 if (out->src != fr->src)
423 free((void *) out->src);
424 if (out != fr)
425 free(out);
426 return NULL;
428 newdata += AST_FRIENDLY_OFFSET;
429 out->offset = AST_FRIENDLY_OFFSET;
430 out->datalen = fr->datalen;
431 memcpy(newdata, fr->data, fr->datalen);
432 out->data = newdata;
435 out->mallocd = AST_MALLOCD_HDR | AST_MALLOCD_SRC | AST_MALLOCD_DATA;
437 return out;
440 struct ast_frame *ast_frdup(const struct ast_frame *f)
442 struct ast_frame *out = NULL;
443 int len, srclen = 0;
444 void *buf = NULL;
446 #if !defined(LOW_MEMORY)
447 struct ast_frame_cache *frames;
448 #endif
450 /* Start with standard stuff */
451 len = sizeof(*out) + AST_FRIENDLY_OFFSET + f->datalen;
452 /* If we have a source, add space for it */
454 * XXX Watch out here - if we receive a src which is not terminated
455 * properly, we can be easily attacked. Should limit the size we deal with.
457 if (f->src)
458 srclen = strlen(f->src);
459 if (srclen > 0)
460 len += srclen + 1;
462 #if !defined(LOW_MEMORY)
463 if ((frames = ast_threadstorage_get(&frame_cache, sizeof(*frames)))) {
464 AST_LIST_TRAVERSE_SAFE_BEGIN(&frames->list, out, frame_list) {
465 if (out->mallocd_hdr_len >= len) {
466 size_t mallocd_len = out->mallocd_hdr_len;
467 AST_LIST_REMOVE_CURRENT(&frames->list, frame_list);
468 memset(out, 0, sizeof(*out));
469 out->mallocd_hdr_len = mallocd_len;
470 buf = out;
471 frames->size--;
472 break;
475 AST_LIST_TRAVERSE_SAFE_END
477 #endif
479 if (!buf) {
480 if (!(buf = ast_calloc_cache(1, len)))
481 return NULL;
482 out = buf;
483 out->mallocd_hdr_len = len;
486 out->frametype = f->frametype;
487 out->subclass = f->subclass;
488 out->datalen = f->datalen;
489 out->samples = f->samples;
490 out->delivery = f->delivery;
491 /* Set us as having malloc'd header only, so it will eventually
492 get freed. */
493 out->mallocd = AST_MALLOCD_HDR;
494 out->offset = AST_FRIENDLY_OFFSET;
495 if (out->datalen) {
496 out->data = buf + sizeof(*out) + AST_FRIENDLY_OFFSET;
497 memcpy(out->data, f->data, out->datalen);
499 if (srclen > 0) {
500 out->src = buf + sizeof(*out) + AST_FRIENDLY_OFFSET + f->datalen;
501 /* Must have space since we allocated for it */
502 strcpy((char *)out->src, f->src);
504 ast_copy_flags(out, f, AST_FRFLAG_HAS_TIMING_INFO);
505 out->ts = f->ts;
506 out->len = f->len;
507 out->seqno = f->seqno;
508 return out;
511 void ast_swapcopy_samples(void *dst, const void *src, int samples)
513 int i;
514 unsigned short *dst_s = dst;
515 const unsigned short *src_s = src;
517 for (i = 0; i < samples; i++)
518 dst_s[i] = (src_s[i]<<8) | (src_s[i]>>8);
522 struct ast_format_list *ast_get_format_list_index(int index)
524 return &AST_FORMAT_LIST[index];
527 struct ast_format_list *ast_get_format_list(size_t *size)
529 *size = (sizeof(AST_FORMAT_LIST) / sizeof(AST_FORMAT_LIST[0]));
530 return AST_FORMAT_LIST;
533 char* ast_getformatname(int format)
535 int x;
536 char *ret = "unknown";
537 for (x = 0; x < sizeof(AST_FORMAT_LIST) / sizeof(AST_FORMAT_LIST[0]); x++) {
538 if(AST_FORMAT_LIST[x].visible && AST_FORMAT_LIST[x].bits == format) {
539 ret = AST_FORMAT_LIST[x].name;
540 break;
543 return ret;
546 char *ast_getformatname_multiple(char *buf, size_t size, int format)
548 int x;
549 unsigned len;
550 char *start, *end = buf;
552 if (!size)
553 return buf;
554 snprintf(end, size, "0x%x (", format);
555 len = strlen(end);
556 end += len;
557 size -= len;
558 start = end;
559 for (x = 0; x < sizeof(AST_FORMAT_LIST) / sizeof(AST_FORMAT_LIST[0]); x++) {
560 if (AST_FORMAT_LIST[x].visible && (AST_FORMAT_LIST[x].bits & format)) {
561 snprintf(end, size,"%s|",AST_FORMAT_LIST[x].name);
562 len = strlen(end);
563 end += len;
564 size -= len;
567 if (start == end)
568 snprintf(start, size, "nothing)");
569 else if (size > 1)
570 *(end -1) = ')';
571 return buf;
574 static struct ast_codec_alias_table {
575 char *alias;
576 char *realname;
577 } ast_codec_alias_table[] = {
578 { "slinear", "slin"},
579 { "g723.1", "g723"},
582 static const char *ast_expand_codec_alias(const char *in)
584 int x;
586 for (x = 0; x < sizeof(ast_codec_alias_table) / sizeof(ast_codec_alias_table[0]); x++) {
587 if(!strcmp(in,ast_codec_alias_table[x].alias))
588 return ast_codec_alias_table[x].realname;
590 return in;
593 int ast_getformatbyname(const char *name)
595 int x, all, format = 0;
597 all = strcasecmp(name, "all") ? 0 : 1;
598 for (x = 0; x < sizeof(AST_FORMAT_LIST) / sizeof(AST_FORMAT_LIST[0]); x++) {
599 if(AST_FORMAT_LIST[x].visible && (all ||
600 !strcasecmp(AST_FORMAT_LIST[x].name,name) ||
601 !strcasecmp(AST_FORMAT_LIST[x].name,ast_expand_codec_alias(name)))) {
602 format |= AST_FORMAT_LIST[x].bits;
603 if(!all)
604 break;
608 return format;
611 char *ast_codec2str(int codec)
613 int x;
614 char *ret = "unknown";
615 for (x = 0; x < sizeof(AST_FORMAT_LIST) / sizeof(AST_FORMAT_LIST[0]); x++) {
616 if(AST_FORMAT_LIST[x].visible && AST_FORMAT_LIST[x].bits == codec) {
617 ret = AST_FORMAT_LIST[x].desc;
618 break;
621 return ret;
624 static int show_codecs_deprecated(int fd, int argc, char *argv[])
626 int i, found=0;
627 char hex[25];
629 if ((argc < 2) || (argc > 3))
630 return RESULT_SHOWUSAGE;
632 if (!ast_opt_dont_warn)
633 ast_cli(fd, "Disclaimer: this command is for informational purposes only.\n"
634 "\tIt does not indicate anything about your configuration.\n");
636 ast_cli(fd, "%11s %9s %10s TYPE %8s %s\n","INT","BINARY","HEX","NAME","DESC");
637 ast_cli(fd, "--------------------------------------------------------------------------------\n");
638 if ((argc == 2) || (!strcasecmp(argv[1],"audio"))) {
639 found = 1;
640 for (i=0;i<13;i++) {
641 snprintf(hex,25,"(0x%x)",1<<i);
642 ast_cli(fd, "%11u (1 << %2d) %10s audio %8s (%s)\n",1 << i,i,hex,ast_getformatname(1<<i),ast_codec2str(1<<i));
646 if ((argc == 2) || (!strcasecmp(argv[1],"image"))) {
647 found = 1;
648 for (i=16;i<18;i++) {
649 snprintf(hex,25,"(0x%x)",1<<i);
650 ast_cli(fd, "%11u (1 << %2d) %10s image %8s (%s)\n",1 << i,i,hex,ast_getformatname(1<<i),ast_codec2str(1<<i));
654 if ((argc == 2) || (!strcasecmp(argv[1],"video"))) {
655 found = 1;
656 for (i=18;i<22;i++) {
657 snprintf(hex,25,"(0x%x)",1<<i);
658 ast_cli(fd, "%11u (1 << %2d) %10s video %8s (%s)\n",1 << i,i,hex,ast_getformatname(1<<i),ast_codec2str(1<<i));
662 if (! found)
663 return RESULT_SHOWUSAGE;
664 else
665 return RESULT_SUCCESS;
668 static int show_codecs(int fd, int argc, char *argv[])
670 int i, found=0;
671 char hex[25];
673 if ((argc < 3) || (argc > 4))
674 return RESULT_SHOWUSAGE;
676 if (!ast_opt_dont_warn)
677 ast_cli(fd, "Disclaimer: this command is for informational purposes only.\n"
678 "\tIt does not indicate anything about your configuration.\n");
680 ast_cli(fd, "%11s %9s %10s TYPE %8s %s\n","INT","BINARY","HEX","NAME","DESC");
681 ast_cli(fd, "--------------------------------------------------------------------------------\n");
682 if ((argc == 3) || (!strcasecmp(argv[3],"audio"))) {
683 found = 1;
684 for (i=0;i<13;i++) {
685 snprintf(hex,25,"(0x%x)",1<<i);
686 ast_cli(fd, "%11u (1 << %2d) %10s audio %8s (%s)\n",1 << i,i,hex,ast_getformatname(1<<i),ast_codec2str(1<<i));
690 if ((argc == 3) || (!strcasecmp(argv[3],"image"))) {
691 found = 1;
692 for (i=16;i<18;i++) {
693 snprintf(hex,25,"(0x%x)",1<<i);
694 ast_cli(fd, "%11u (1 << %2d) %10s image %8s (%s)\n",1 << i,i,hex,ast_getformatname(1<<i),ast_codec2str(1<<i));
698 if ((argc == 3) || (!strcasecmp(argv[3],"video"))) {
699 found = 1;
700 for (i=18;i<22;i++) {
701 snprintf(hex,25,"(0x%x)",1<<i);
702 ast_cli(fd, "%11u (1 << %2d) %10s video %8s (%s)\n",1 << i,i,hex,ast_getformatname(1<<i),ast_codec2str(1<<i));
706 if (! found)
707 return RESULT_SHOWUSAGE;
708 else
709 return RESULT_SUCCESS;
712 static char frame_show_codecs_usage[] =
713 "Usage: core show codecs [audio|video|image]\n"
714 " Displays codec mapping\n";
716 static int show_codec_n_deprecated(int fd, int argc, char *argv[])
718 int codec, i, found=0;
720 if (argc != 3)
721 return RESULT_SHOWUSAGE;
723 if (sscanf(argv[2],"%d",&codec) != 1)
724 return RESULT_SHOWUSAGE;
726 for (i = 0; i < 32; i++)
727 if (codec & (1 << i)) {
728 found = 1;
729 ast_cli(fd, "%11u (1 << %2d) %s\n",1 << i,i,ast_codec2str(1<<i));
732 if (!found)
733 ast_cli(fd, "Codec %d not found\n", codec);
735 return RESULT_SUCCESS;
738 static int show_codec_n(int fd, int argc, char *argv[])
740 int codec, i, found=0;
742 if (argc != 4)
743 return RESULT_SHOWUSAGE;
745 if (sscanf(argv[3],"%d",&codec) != 1)
746 return RESULT_SHOWUSAGE;
748 for (i = 0; i < 32; i++)
749 if (codec & (1 << i)) {
750 found = 1;
751 ast_cli(fd, "%11u (1 << %2d) %s\n",1 << i,i,ast_codec2str(1<<i));
754 if (!found)
755 ast_cli(fd, "Codec %d not found\n", codec);
757 return RESULT_SUCCESS;
760 static char frame_show_codec_n_usage[] =
761 "Usage: core show codec <number>\n"
762 " Displays codec mapping\n";
764 /*! Dump a frame for debugging purposes */
765 void ast_frame_dump(const char *name, struct ast_frame *f, char *prefix)
767 const char noname[] = "unknown";
768 char ftype[40] = "Unknown Frametype";
769 char cft[80];
770 char subclass[40] = "Unknown Subclass";
771 char csub[80];
772 char moreinfo[40] = "";
773 char cn[60];
774 char cp[40];
775 char cmn[40];
777 if (!name)
778 name = noname;
781 if (!f) {
782 ast_verbose("%s [ %s (NULL) ] [%s]\n",
783 term_color(cp, prefix, COLOR_BRMAGENTA, COLOR_BLACK, sizeof(cp)),
784 term_color(cft, "HANGUP", COLOR_BRRED, COLOR_BLACK, sizeof(cft)),
785 term_color(cn, name, COLOR_YELLOW, COLOR_BLACK, sizeof(cn)));
786 return;
788 /* XXX We should probably print one each of voice and video when the format changes XXX */
789 if (f->frametype == AST_FRAME_VOICE)
790 return;
791 if (f->frametype == AST_FRAME_VIDEO)
792 return;
793 switch(f->frametype) {
794 case AST_FRAME_DTMF_BEGIN:
795 strcpy(ftype, "DTMF Begin");
796 subclass[0] = f->subclass;
797 subclass[1] = '\0';
798 break;
799 case AST_FRAME_DTMF_END:
800 strcpy(ftype, "DTMF End");
801 subclass[0] = f->subclass;
802 subclass[1] = '\0';
803 break;
804 case AST_FRAME_CONTROL:
805 strcpy(ftype, "Control");
806 switch(f->subclass) {
807 case AST_CONTROL_HANGUP:
808 strcpy(subclass, "Hangup");
809 break;
810 case AST_CONTROL_RING:
811 strcpy(subclass, "Ring");
812 break;
813 case AST_CONTROL_RINGING:
814 strcpy(subclass, "Ringing");
815 break;
816 case AST_CONTROL_ANSWER:
817 strcpy(subclass, "Answer");
818 break;
819 case AST_CONTROL_BUSY:
820 strcpy(subclass, "Busy");
821 break;
822 case AST_CONTROL_TAKEOFFHOOK:
823 strcpy(subclass, "Take Off Hook");
824 break;
825 case AST_CONTROL_OFFHOOK:
826 strcpy(subclass, "Line Off Hook");
827 break;
828 case AST_CONTROL_CONGESTION:
829 strcpy(subclass, "Congestion");
830 break;
831 case AST_CONTROL_FLASH:
832 strcpy(subclass, "Flash");
833 break;
834 case AST_CONTROL_WINK:
835 strcpy(subclass, "Wink");
836 break;
837 case AST_CONTROL_OPTION:
838 strcpy(subclass, "Option");
839 break;
840 case AST_CONTROL_RADIO_KEY:
841 strcpy(subclass, "Key Radio");
842 break;
843 case AST_CONTROL_RADIO_UNKEY:
844 strcpy(subclass, "Unkey Radio");
845 break;
846 case -1:
847 strcpy(subclass, "Stop generators");
848 break;
849 default:
850 snprintf(subclass, sizeof(subclass), "Unknown control '%d'", f->subclass);
852 break;
853 case AST_FRAME_NULL:
854 strcpy(ftype, "Null Frame");
855 strcpy(subclass, "N/A");
856 break;
857 case AST_FRAME_IAX:
858 /* Should never happen */
859 strcpy(ftype, "IAX Specific");
860 snprintf(subclass, sizeof(subclass), "IAX Frametype %d", f->subclass);
861 break;
862 case AST_FRAME_TEXT:
863 strcpy(ftype, "Text");
864 strcpy(subclass, "N/A");
865 ast_copy_string(moreinfo, f->data, sizeof(moreinfo));
866 break;
867 case AST_FRAME_IMAGE:
868 strcpy(ftype, "Image");
869 snprintf(subclass, sizeof(subclass), "Image format %s\n", ast_getformatname(f->subclass));
870 break;
871 case AST_FRAME_HTML:
872 strcpy(ftype, "HTML");
873 switch(f->subclass) {
874 case AST_HTML_URL:
875 strcpy(subclass, "URL");
876 ast_copy_string(moreinfo, f->data, sizeof(moreinfo));
877 break;
878 case AST_HTML_DATA:
879 strcpy(subclass, "Data");
880 break;
881 case AST_HTML_BEGIN:
882 strcpy(subclass, "Begin");
883 break;
884 case AST_HTML_END:
885 strcpy(subclass, "End");
886 break;
887 case AST_HTML_LDCOMPLETE:
888 strcpy(subclass, "Load Complete");
889 break;
890 case AST_HTML_NOSUPPORT:
891 strcpy(subclass, "No Support");
892 break;
893 case AST_HTML_LINKURL:
894 strcpy(subclass, "Link URL");
895 ast_copy_string(moreinfo, f->data, sizeof(moreinfo));
896 break;
897 case AST_HTML_UNLINK:
898 strcpy(subclass, "Unlink");
899 break;
900 case AST_HTML_LINKREJECT:
901 strcpy(subclass, "Link Reject");
902 break;
903 default:
904 snprintf(subclass, sizeof(subclass), "Unknown HTML frame '%d'\n", f->subclass);
905 break;
907 break;
908 case AST_FRAME_MODEM:
909 strcpy(ftype, "Modem");
910 switch (f->subclass) {
911 case AST_MODEM_T38:
912 strcpy(subclass, "T.38");
913 break;
914 case AST_MODEM_V150:
915 strcpy(subclass, "V.150");
916 break;
917 default:
918 snprintf(subclass, sizeof(subclass), "Unknown MODEM frame '%d'\n", f->subclass);
919 break;
921 break;
922 default:
923 snprintf(ftype, sizeof(ftype), "Unknown Frametype '%d'", f->frametype);
925 if (!ast_strlen_zero(moreinfo))
926 ast_verbose("%s [ TYPE: %s (%d) SUBCLASS: %s (%d) '%s' ] [%s]\n",
927 term_color(cp, prefix, COLOR_BRMAGENTA, COLOR_BLACK, sizeof(cp)),
928 term_color(cft, ftype, COLOR_BRRED, COLOR_BLACK, sizeof(cft)),
929 f->frametype,
930 term_color(csub, subclass, COLOR_BRCYAN, COLOR_BLACK, sizeof(csub)),
931 f->subclass,
932 term_color(cmn, moreinfo, COLOR_BRGREEN, COLOR_BLACK, sizeof(cmn)),
933 term_color(cn, name, COLOR_YELLOW, COLOR_BLACK, sizeof(cn)));
934 else
935 ast_verbose("%s [ TYPE: %s (%d) SUBCLASS: %s (%d) ] [%s]\n",
936 term_color(cp, prefix, COLOR_BRMAGENTA, COLOR_BLACK, sizeof(cp)),
937 term_color(cft, ftype, COLOR_BRRED, COLOR_BLACK, sizeof(cft)),
938 f->frametype,
939 term_color(csub, subclass, COLOR_BRCYAN, COLOR_BLACK, sizeof(csub)),
940 f->subclass,
941 term_color(cn, name, COLOR_YELLOW, COLOR_BLACK, sizeof(cn)));
945 #ifdef TRACE_FRAMES
946 static int show_frame_stats_deprecated(int fd, int argc, char *argv[])
948 struct ast_frame *f;
949 int x=1;
950 if (argc != 3)
951 return RESULT_SHOWUSAGE;
952 AST_LIST_LOCK(&headerlist);
953 ast_cli(fd, " Framer Statistics \n");
954 ast_cli(fd, "---------------------------\n");
955 ast_cli(fd, "Total allocated headers: %d\n", headers);
956 ast_cli(fd, "Queue Dump:\n");
957 AST_LIST_TRAVERSE(&headerlist, f, frame_list)
958 ast_cli(fd, "%d. Type %d, subclass %d from %s\n", x++, f->frametype, f->subclass, f->src ? f->src : "<Unknown>");
959 AST_LIST_UNLOCK(&headerlist);
960 return RESULT_SUCCESS;
963 static int show_frame_stats(int fd, int argc, char *argv[])
965 struct ast_frame *f;
966 int x=1;
967 if (argc != 4)
968 return RESULT_SHOWUSAGE;
969 AST_LIST_LOCK(&headerlist);
970 ast_cli(fd, " Framer Statistics \n");
971 ast_cli(fd, "---------------------------\n");
972 ast_cli(fd, "Total allocated headers: %d\n", headers);
973 ast_cli(fd, "Queue Dump:\n");
974 AST_LIST_TRAVERSE(&headerlist, f, frame_list)
975 ast_cli(fd, "%d. Type %d, subclass %d from %s\n", x++, f->frametype, f->subclass, f->src ? f->src : "<Unknown>");
976 AST_LIST_UNLOCK(&headerlist);
977 return RESULT_SUCCESS;
980 static char frame_stats_usage[] =
981 "Usage: core show frame stats\n"
982 " Displays debugging statistics from framer\n";
983 #endif
985 /* Builtin Asterisk CLI-commands for debugging */
986 static struct ast_cli_entry cli_show_codecs = {
987 { "show", "codecs", NULL },
988 show_codecs_deprecated, NULL,
989 NULL };
991 static struct ast_cli_entry cli_show_audio_codecs = {
992 { "show", "audio", "codecs", NULL },
993 show_codecs_deprecated, NULL,
994 NULL };
996 static struct ast_cli_entry cli_show_video_codecs = {
997 { "show", "video", "codecs", NULL },
998 show_codecs_deprecated, NULL,
999 NULL };
1001 static struct ast_cli_entry cli_show_image_codecs = {
1002 { "show", "image", "codecs", NULL },
1003 show_codecs_deprecated, NULL,
1004 NULL };
1006 static struct ast_cli_entry cli_show_codec = {
1007 { "show", "codec", NULL },
1008 show_codec_n_deprecated, NULL,
1009 NULL };
1011 #ifdef TRACE_FRAMES
1012 static struct ast_cli_entry cli_show_frame_stats = {
1013 { "show", "frame", "stats", NULL },
1014 show_frame_stats, NULL,
1015 NULL };
1016 #endif
1018 static struct ast_cli_entry my_clis[] = {
1019 { { "core", "show", "codecs", NULL },
1020 show_codecs, "Displays a list of codecs",
1021 frame_show_codecs_usage, NULL, &cli_show_codecs },
1023 { { "core", "show", "audio", "codecs", NULL },
1024 show_codecs, "Displays a list of audio codecs",
1025 frame_show_codecs_usage, NULL, &cli_show_audio_codecs },
1027 { { "core", "show", "video", "codecs", NULL },
1028 show_codecs, "Displays a list of video codecs",
1029 frame_show_codecs_usage, NULL, &cli_show_video_codecs },
1031 { { "core", "show", "image", "codecs", NULL },
1032 show_codecs, "Displays a list of image codecs",
1033 frame_show_codecs_usage, NULL, &cli_show_image_codecs },
1035 { { "core", "show", "codec", NULL },
1036 show_codec_n, "Shows a specific codec",
1037 frame_show_codec_n_usage, NULL, &cli_show_codec },
1039 #ifdef TRACE_FRAMES
1040 { { "core", "show", "frame", "stats", NULL },
1041 show_frame_stats, "Shows frame statistics",
1042 frame_stats_usage, NULL, &cli_show_frame_stats },
1043 #endif
1046 int init_framer(void)
1048 ast_cli_register_multiple(my_clis, sizeof(my_clis) / sizeof(struct ast_cli_entry));
1049 return 0;
1052 void ast_codec_pref_convert(struct ast_codec_pref *pref, char *buf, size_t size, int right)
1054 int x, differential = (int) 'A', mem;
1055 char *from, *to;
1057 if(right) {
1058 from = pref->order;
1059 to = buf;
1060 mem = size;
1061 } else {
1062 to = pref->order;
1063 from = buf;
1064 mem = 32;
1067 memset(to, 0, mem);
1068 for (x = 0; x < 32 ; x++) {
1069 if(!from[x])
1070 break;
1071 to[x] = right ? (from[x] + differential) : (from[x] - differential);
1075 int ast_codec_pref_string(struct ast_codec_pref *pref, char *buf, size_t size)
1077 int x, codec;
1078 size_t total_len, slen;
1079 char *formatname;
1081 memset(buf,0,size);
1082 total_len = size;
1083 buf[0] = '(';
1084 total_len--;
1085 for(x = 0; x < 32 ; x++) {
1086 if(total_len <= 0)
1087 break;
1088 if(!(codec = ast_codec_pref_index(pref,x)))
1089 break;
1090 if((formatname = ast_getformatname(codec))) {
1091 slen = strlen(formatname);
1092 if(slen > total_len)
1093 break;
1094 strncat(buf,formatname,total_len);
1095 total_len -= slen;
1097 if(total_len && x < 31 && ast_codec_pref_index(pref , x + 1)) {
1098 strncat(buf,"|",total_len);
1099 total_len--;
1102 if(total_len) {
1103 strncat(buf,")",total_len);
1104 total_len--;
1107 return size - total_len;
1110 int ast_codec_pref_index(struct ast_codec_pref *pref, int index)
1112 int slot = 0;
1115 if((index >= 0) && (index < sizeof(pref->order))) {
1116 slot = pref->order[index];
1119 return slot ? AST_FORMAT_LIST[slot-1].bits : 0;
1122 /*! \brief Remove codec from pref list */
1123 void ast_codec_pref_remove(struct ast_codec_pref *pref, int format)
1125 struct ast_codec_pref oldorder;
1126 int x, y = 0;
1127 int slot;
1128 int size;
1130 if(!pref->order[0])
1131 return;
1133 memcpy(&oldorder, pref, sizeof(oldorder));
1134 memset(pref, 0, sizeof(*pref));
1136 for (x = 0; x < sizeof(AST_FORMAT_LIST) / sizeof(AST_FORMAT_LIST[0]); x++) {
1137 slot = oldorder.order[x];
1138 size = oldorder.framing[x];
1139 if(! slot)
1140 break;
1141 if(AST_FORMAT_LIST[slot-1].bits != format) {
1142 pref->order[y] = slot;
1143 pref->framing[y++] = size;
1149 /*! \brief Append codec to list */
1150 int ast_codec_pref_append(struct ast_codec_pref *pref, int format)
1152 int x, newindex = 0;
1154 ast_codec_pref_remove(pref, format);
1156 for (x = 0; x < sizeof(AST_FORMAT_LIST) / sizeof(AST_FORMAT_LIST[0]); x++) {
1157 if(AST_FORMAT_LIST[x].bits == format) {
1158 newindex = x + 1;
1159 break;
1163 if(newindex) {
1164 for (x = 0; x < sizeof(AST_FORMAT_LIST) / sizeof(AST_FORMAT_LIST[0]); x++) {
1165 if(!pref->order[x]) {
1166 pref->order[x] = newindex;
1167 break;
1172 return x;
1175 /*! \brief Prepend codec to list */
1176 void ast_codec_pref_prepend(struct ast_codec_pref *pref, int format, int only_if_existing)
1178 int x, newindex = 0;
1180 /* First step is to get the codecs "index number" */
1181 for (x = 0; x < ARRAY_LEN(AST_FORMAT_LIST); x++) {
1182 if (AST_FORMAT_LIST[x].bits == format) {
1183 newindex = x + 1;
1184 break;
1187 /* Done if its unknown */
1188 if (!newindex)
1189 return;
1191 /* Now find any existing occurrence, or the end */
1192 for (x = 0; x < 32; x++) {
1193 if (!pref->order[x] || pref->order[x] == newindex)
1194 break;
1197 if (only_if_existing && !pref->order[x])
1198 return;
1200 /* Move down to make space to insert - either all the way to the end,
1201 or as far as the existing location (which will be overwritten) */
1202 for (; x > 0; x--) {
1203 pref->order[x] = pref->order[x - 1];
1204 pref->framing[x] = pref->framing[x - 1];
1207 /* And insert the new entry */
1208 pref->order[0] = newindex;
1209 pref->framing[0] = 0; /* ? */
1212 /*! \brief Set packet size for codec */
1213 int ast_codec_pref_setsize(struct ast_codec_pref *pref, int format, int framems)
1215 int x, index = -1;
1217 for (x = 0; x < sizeof(AST_FORMAT_LIST) / sizeof(AST_FORMAT_LIST[0]); x++) {
1218 if(AST_FORMAT_LIST[x].bits == format) {
1219 index = x;
1220 break;
1224 if(index < 0)
1225 return -1;
1227 /* size validation */
1228 if(!framems)
1229 framems = AST_FORMAT_LIST[index].def_ms;
1231 if(AST_FORMAT_LIST[index].inc_ms && framems % AST_FORMAT_LIST[index].inc_ms) /* avoid division by zero */
1232 framems -= framems % AST_FORMAT_LIST[index].inc_ms;
1234 if(framems < AST_FORMAT_LIST[index].min_ms)
1235 framems = AST_FORMAT_LIST[index].min_ms;
1237 if(framems > AST_FORMAT_LIST[index].max_ms)
1238 framems = AST_FORMAT_LIST[index].max_ms;
1241 for (x = 0; x < sizeof(AST_FORMAT_LIST) / sizeof(AST_FORMAT_LIST[0]); x++) {
1242 if(pref->order[x] == (index + 1)) {
1243 pref->framing[x] = framems;
1244 break;
1248 return x;
1251 /*! \brief Get packet size for codec */
1252 struct ast_format_list ast_codec_pref_getsize(struct ast_codec_pref *pref, int format)
1254 int x, index = -1, framems = 0;
1255 struct ast_format_list fmt = {0};
1257 for (x = 0; x < sizeof(AST_FORMAT_LIST) / sizeof(AST_FORMAT_LIST[0]); x++) {
1258 if(AST_FORMAT_LIST[x].bits == format) {
1259 fmt = AST_FORMAT_LIST[x];
1260 index = x;
1261 break;
1265 for (x = 0; x < sizeof(AST_FORMAT_LIST) / sizeof(AST_FORMAT_LIST[0]); x++) {
1266 if(pref->order[x] == (index + 1)) {
1267 framems = pref->framing[x];
1268 break;
1272 /* size validation */
1273 if(!framems)
1274 framems = AST_FORMAT_LIST[index].def_ms;
1276 if(AST_FORMAT_LIST[index].inc_ms && framems % AST_FORMAT_LIST[index].inc_ms) /* avoid division by zero */
1277 framems -= framems % AST_FORMAT_LIST[index].inc_ms;
1279 if(framems < AST_FORMAT_LIST[index].min_ms)
1280 framems = AST_FORMAT_LIST[index].min_ms;
1282 if(framems > AST_FORMAT_LIST[index].max_ms)
1283 framems = AST_FORMAT_LIST[index].max_ms;
1285 fmt.cur_ms = framems;
1287 return fmt;
1290 /*! \brief Pick a codec */
1291 int ast_codec_choose(struct ast_codec_pref *pref, int formats, int find_best)
1293 int x, ret = 0, slot;
1295 for (x = 0; x < sizeof(AST_FORMAT_LIST) / sizeof(AST_FORMAT_LIST[0]); x++) {
1296 slot = pref->order[x];
1298 if (!slot)
1299 break;
1300 if (formats & AST_FORMAT_LIST[slot-1].bits) {
1301 ret = AST_FORMAT_LIST[slot-1].bits;
1302 break;
1305 if(ret & AST_FORMAT_AUDIO_MASK)
1306 return ret;
1308 if (option_debug > 3)
1309 ast_log(LOG_DEBUG, "Could not find preferred codec - %s\n", find_best ? "Going for the best codec" : "Returning zero codec");
1311 return find_best ? ast_best_codec(formats) : 0;
1314 void ast_parse_allow_disallow(struct ast_codec_pref *pref, int *mask, const char *list, int allowing)
1316 char *parse = NULL, *this = NULL, *psize = NULL;
1317 int format = 0, framems = 0;
1319 parse = ast_strdupa(list);
1320 while ((this = strsep(&parse, ","))) {
1321 framems = 0;
1322 if ((psize = strrchr(this, ':'))) {
1323 *psize++ = '\0';
1324 if (option_debug)
1325 ast_log(LOG_DEBUG,"Packetization for codec: %s is %s\n", this, psize);
1326 framems = atoi(psize);
1327 if (framems < 0)
1328 framems = 0;
1330 if (!(format = ast_getformatbyname(this))) {
1331 ast_log(LOG_WARNING, "Cannot %s unknown format '%s'\n", allowing ? "allow" : "disallow", this);
1332 continue;
1335 if (mask) {
1336 if (allowing)
1337 *mask |= format;
1338 else
1339 *mask &= ~format;
1342 /* Set up a preference list for audio. Do not include video in preferences
1343 since we can not transcode video and have to use whatever is offered
1345 if (pref && (format & AST_FORMAT_AUDIO_MASK)) {
1346 if (strcasecmp(this, "all")) {
1347 if (allowing) {
1348 ast_codec_pref_append(pref, format);
1349 ast_codec_pref_setsize(pref, format, framems);
1351 else
1352 ast_codec_pref_remove(pref, format);
1353 } else if (!allowing) {
1354 memset(pref, 0, sizeof(*pref));
1360 static int g723_len(unsigned char buf)
1362 enum frame_type type = buf & TYPE_MASK;
1364 switch(type) {
1365 case TYPE_DONTSEND:
1366 return 0;
1367 break;
1368 case TYPE_SILENCE:
1369 return 4;
1370 break;
1371 case TYPE_HIGH:
1372 return 24;
1373 break;
1374 case TYPE_LOW:
1375 return 20;
1376 break;
1377 default:
1378 ast_log(LOG_WARNING, "Badly encoded frame (%d)\n", type);
1380 return -1;
1383 static int g723_samples(unsigned char *buf, int maxlen)
1385 int pos = 0;
1386 int samples = 0;
1387 int res;
1388 while(pos < maxlen) {
1389 res = g723_len(buf[pos]);
1390 if (res <= 0)
1391 break;
1392 samples += 240;
1393 pos += res;
1395 return samples;
1398 static unsigned char get_n_bits_at(unsigned char *data, int n, int bit)
1400 int byte = bit / 8; /* byte containing first bit */
1401 int rem = 8 - (bit % 8); /* remaining bits in first byte */
1402 unsigned char ret = 0;
1404 if (n <= 0 || n > 8)
1405 return 0;
1407 if (rem < n) {
1408 ret = (data[byte] << (n - rem));
1409 ret |= (data[byte + 1] >> (8 - n + rem));
1410 } else {
1411 ret = (data[byte] >> (rem - n));
1414 return (ret & (0xff >> (8 - n)));
1417 static int speex_get_wb_sz_at(unsigned char *data, int len, int bit)
1419 static int SpeexWBSubModeSz[] = {
1420 0, 36, 112, 192,
1421 352, 0, 0, 0 };
1422 int off = bit;
1423 unsigned char c;
1425 /* skip up to two wideband frames */
1426 if (((len * 8 - off) >= 5) &&
1427 get_n_bits_at(data, 1, off)) {
1428 c = get_n_bits_at(data, 3, off + 1);
1429 off += SpeexWBSubModeSz[c];
1431 if (((len * 8 - off) >= 5) &&
1432 get_n_bits_at(data, 1, off)) {
1433 c = get_n_bits_at(data, 3, off + 1);
1434 off += SpeexWBSubModeSz[c];
1436 if (((len * 8 - off) >= 5) &&
1437 get_n_bits_at(data, 1, off)) {
1438 ast_log(LOG_WARNING, "Encountered corrupt speex frame; too many wideband frames in a row.\n");
1439 return -1;
1444 return off - bit;
1447 static int speex_samples(unsigned char *data, int len)
1449 static int SpeexSubModeSz[] = {
1450 5, 43, 119, 160,
1451 220, 300, 364, 492,
1452 79, 0, 0, 0,
1453 0, 0, 0, 0 };
1454 static int SpeexInBandSz[] = {
1455 1, 1, 4, 4,
1456 4, 4, 4, 4,
1457 8, 8, 16, 16,
1458 32, 32, 64, 64 };
1459 int bit = 0;
1460 int cnt = 0;
1461 int off;
1462 unsigned char c;
1464 while ((len * 8 - bit) >= 5) {
1465 /* skip wideband frames */
1466 off = speex_get_wb_sz_at(data, len, bit);
1467 if (off < 0) {
1468 ast_log(LOG_WARNING, "Had error while reading wideband frames for speex samples\n");
1469 break;
1471 bit += off;
1473 if ((len * 8 - bit) < 5) {
1474 ast_log(LOG_WARNING, "Not enough bits remaining after wide band for speex samples.\n");
1475 break;
1478 /* get control bits */
1479 c = get_n_bits_at(data, 5, bit);
1480 bit += 5;
1482 if (c == 15) {
1483 /* terminator */
1484 break;
1485 } else if (c == 14) {
1486 /* in-band signal; next 4 bits contain signal id */
1487 c = get_n_bits_at(data, 4, bit);
1488 bit += 4;
1489 bit += SpeexInBandSz[c];
1490 } else if (c == 13) {
1491 /* user in-band; next 5 bits contain msg len */
1492 c = get_n_bits_at(data, 5, bit);
1493 bit += 5;
1494 bit += c * 8;
1495 } else if (c > 8) {
1496 /* unknown */
1497 break;
1498 } else {
1499 /* skip number bits for submode (less the 5 control bits) */
1500 bit += SpeexSubModeSz[c] - 5;
1501 cnt += 160; /* new frame */
1504 return cnt;
1507 int ast_codec_get_samples(struct ast_frame *f)
1509 int samples=0;
1510 switch(f->subclass) {
1511 case AST_FORMAT_SPEEX:
1512 samples = speex_samples(f->data, f->datalen);
1513 break;
1514 case AST_FORMAT_G723_1:
1515 samples = g723_samples(f->data, f->datalen);
1516 break;
1517 case AST_FORMAT_ILBC:
1518 samples = 240 * (f->datalen / 50);
1519 break;
1520 case AST_FORMAT_GSM:
1521 samples = 160 * (f->datalen / 33);
1522 break;
1523 case AST_FORMAT_G729A:
1524 samples = f->datalen * 8;
1525 break;
1526 case AST_FORMAT_SLINEAR:
1527 samples = f->datalen / 2;
1528 break;
1529 case AST_FORMAT_LPC10:
1530 /* assumes that the RTP packet contains one LPC10 frame */
1531 samples = 22 * 8;
1532 samples += (((char *)(f->data))[7] & 0x1) * 8;
1533 break;
1534 case AST_FORMAT_ULAW:
1535 case AST_FORMAT_ALAW:
1536 samples = f->datalen;
1537 break;
1538 case AST_FORMAT_G722:
1539 case AST_FORMAT_ADPCM:
1540 case AST_FORMAT_G726:
1541 case AST_FORMAT_G726_AAL2:
1542 samples = f->datalen * 2;
1543 break;
1544 default:
1545 ast_log(LOG_WARNING, "Unable to calculate samples for format %s\n", ast_getformatname(f->subclass));
1547 return samples;
1550 int ast_codec_get_len(int format, int samples)
1552 int len = 0;
1554 /* XXX Still need speex, g723, and lpc10 XXX */
1555 switch(format) {
1556 case AST_FORMAT_ILBC:
1557 len = (samples / 240) * 50;
1558 break;
1559 case AST_FORMAT_GSM:
1560 len = (samples / 160) * 33;
1561 break;
1562 case AST_FORMAT_G729A:
1563 len = samples / 8;
1564 break;
1565 case AST_FORMAT_SLINEAR:
1566 len = samples * 2;
1567 break;
1568 case AST_FORMAT_ULAW:
1569 case AST_FORMAT_ALAW:
1570 len = samples;
1571 break;
1572 case AST_FORMAT_G722:
1573 case AST_FORMAT_ADPCM:
1574 case AST_FORMAT_G726:
1575 case AST_FORMAT_G726_AAL2:
1576 len = samples / 2;
1577 break;
1578 default:
1579 ast_log(LOG_WARNING, "Unable to calculate sample length for format %s\n", ast_getformatname(format));
1582 return len;
1585 int ast_frame_adjust_volume(struct ast_frame *f, int adjustment)
1587 int count;
1588 short *fdata = f->data;
1589 short adjust_value = abs(adjustment);
1591 if ((f->frametype != AST_FRAME_VOICE) || (f->subclass != AST_FORMAT_SLINEAR))
1592 return -1;
1594 if (!adjustment)
1595 return 0;
1597 for (count = 0; count < f->samples; count++) {
1598 if (adjustment > 0) {
1599 ast_slinear_saturated_multiply(&fdata[count], &adjust_value);
1600 } else if (adjustment < 0) {
1601 ast_slinear_saturated_divide(&fdata[count], &adjust_value);
1605 return 0;
1608 int ast_frame_slinear_sum(struct ast_frame *f1, struct ast_frame *f2)
1610 int count;
1611 short *data1, *data2;
1613 if ((f1->frametype != AST_FRAME_VOICE) || (f1->subclass != AST_FORMAT_SLINEAR))
1614 return -1;
1616 if ((f2->frametype != AST_FRAME_VOICE) || (f2->subclass != AST_FORMAT_SLINEAR))
1617 return -1;
1619 if (f1->samples != f2->samples)
1620 return -1;
1622 for (count = 0, data1 = f1->data, data2 = f2->data;
1623 count < f1->samples;
1624 count++, data1++, data2++)
1625 ast_slinear_saturated_add(data1, data2);
1627 return 0;