various doxygen fixes
[asterisk-bristuff.git] / frame.c
blob9006d5f7ccadda1d128d5da822a496ce21cd1991
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 manipulation routines
23 * \author Mark Spencer <markster@digium.com>
26 #include <stdlib.h>
27 #include <unistd.h>
28 #include <string.h>
29 #include <errno.h>
30 #include <stdio.h>
32 #include "asterisk.h"
34 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"
45 #ifdef TRACE_FRAMES
46 static int headers = 0;
47 static struct ast_frame *headerlist = NULL;
48 AST_MUTEX_DEFINE_STATIC(framelock);
49 #endif
51 #define SMOOTHER_SIZE 8000
53 enum frame_type {
54 TYPE_HIGH, /* 0x0 */
55 TYPE_LOW, /* 0x1 */
56 TYPE_SILENCE, /* 0x2 */
57 TYPE_DONTSEND /* 0x3 */
60 #define TYPE_MASK 0x3
62 struct ast_smoother {
63 int size;
64 int format;
65 int readdata;
66 int optimizablestream;
67 int flags;
68 float samplesperbyte;
69 struct ast_frame f;
70 struct timeval delivery;
71 char data[SMOOTHER_SIZE];
72 char framedata[SMOOTHER_SIZE + AST_FRIENDLY_OFFSET];
73 struct ast_frame *opt;
74 int len;
77 /*! \brief Definition of supported media formats (codecs) */
78 static struct ast_format_list {
79 int visible; /*!< Can we see this entry */
80 int bits; /*!< bitmask value */
81 char *name; /*!< short name */
82 char *desc; /*!< Description */
83 } AST_FORMAT_LIST[] = {
84 { 1, AST_FORMAT_G723_1 , "g723" , "G.723.1"}, /*!< codec_g723_1.c */
85 { 1, AST_FORMAT_GSM, "gsm" , "GSM"}, /*!< codec_gsm.c */
86 { 1, AST_FORMAT_ULAW, "ulaw", "G.711 u-law" }, /*!< codec_ulaw.c */
87 { 1, AST_FORMAT_ALAW, "alaw", "G.711 A-law" }, /*!< codec_alaw.c */
88 { 1, AST_FORMAT_G726, "g726", "G.726" }, /*!< codec_g726.c */
89 { 1, AST_FORMAT_ADPCM, "adpcm" , "ADPCM"}, /*!< codec_adpcm.c */
90 { 1, AST_FORMAT_SLINEAR, "slin", "16 bit Signed Linear PCM"}, /*!< */
91 { 1, AST_FORMAT_LPC10, "lpc10", "LPC10" }, /*!< codec_lpc10.c */
92 { 1, AST_FORMAT_G729A, "g729", "G.729A" }, /*!< Binary commercial distribution */
93 { 1, AST_FORMAT_SPEEX, "speex", "SpeeX" }, /*!< codec_speex.c */
94 { 1, AST_FORMAT_ILBC, "ilbc", "iLBC"}, /*!< codec_ilbc.c */
95 { 0, 0, "nothing", "undefined" },
96 { 0, 0, "nothing", "undefined" },
97 { 0, 0, "nothing", "undefined" },
98 { 0, 0, "nothing", "undefined" },
99 { 0, AST_FORMAT_MAX_AUDIO, "maxaudio", "Maximum audio format" },
100 { 1, AST_FORMAT_JPEG, "jpeg", "JPEG image"}, /*!< See format_jpeg.c */
101 { 1, AST_FORMAT_PNG, "png", "PNG image"}, /*!< Image format */
102 { 1, AST_FORMAT_H261, "h261", "H.261 Video" }, /*!< Passthrough */
103 { 1, AST_FORMAT_H263, "h263", "H.263 Video" }, /*!< Passthrough support, see format_h263.c */
104 { 1, AST_FORMAT_H263_PLUS, "h263p", "H.263+ Video" }, /*!< See format_h263.c */
105 { 1, AST_FORMAT_H264, "h264", "H.264 Video" }, /*!< Passthrough support, see format_h263.c */
106 { 0, 0, "nothing", "undefined" },
107 { 0, 0, "nothing", "undefined" },
108 { 0, 0, "nothing", "undefined" },
109 { 0, AST_FORMAT_MAX_VIDEO, "maxvideo", "Maximum video format" },
112 struct ast_frame ast_null_frame = { AST_FRAME_NULL, };
114 void ast_smoother_reset(struct ast_smoother *s, int size)
116 memset(s, 0, sizeof(*s));
117 s->size = size;
120 struct ast_smoother *ast_smoother_new(int size)
122 struct ast_smoother *s;
123 if (size < 1)
124 return NULL;
125 if ((s = ast_malloc(sizeof(*s))))
126 ast_smoother_reset(s, size);
127 return s;
130 int ast_smoother_get_flags(struct ast_smoother *s)
132 return s->flags;
135 void ast_smoother_set_flags(struct ast_smoother *s, int flags)
137 s->flags = flags;
140 int __ast_smoother_feed(struct ast_smoother *s, struct ast_frame *f, int swap)
142 if (f->frametype != AST_FRAME_VOICE) {
143 ast_log(LOG_WARNING, "Huh? Can't smooth a non-voice frame!\n");
144 return -1;
146 if (!s->format) {
147 s->format = f->subclass;
148 s->samplesperbyte = (float)f->samples / (float)f->datalen;
149 } else if (s->format != f->subclass) {
150 ast_log(LOG_WARNING, "Smoother was working on %d format frames, now trying to feed %d?\n", s->format, f->subclass);
151 return -1;
153 if (s->len + f->datalen > SMOOTHER_SIZE) {
154 ast_log(LOG_WARNING, "Out of smoother space\n");
155 return -1;
157 if (((f->datalen == s->size) || ((f->datalen < 10) && (s->flags & AST_SMOOTHER_FLAG_G729)))
158 && !s->opt && (f->offset >= AST_MIN_OFFSET)) {
159 if (!s->len) {
160 /* Optimize by sending the frame we just got
161 on the next read, thus eliminating the douple
162 copy */
163 s->opt = f;
164 return 0;
165 } else {
166 s->optimizablestream++;
167 if (s->optimizablestream > 10) {
168 /* For the past 10 rounds, we have input and output
169 frames of the correct size for this smoother, yet
170 we were unable to optimize because there was still
171 some cruft left over. Lets just drop the cruft so
172 we can move to a fully optimized path */
173 s->len = 0;
174 s->opt = f;
175 return 0;
178 } else
179 s->optimizablestream = 0;
180 if (s->flags & AST_SMOOTHER_FLAG_G729) {
181 if (s->len % 10) {
182 ast_log(LOG_NOTICE, "Dropping extra frame of G.729 since we already have a VAD frame at the end\n");
183 return 0;
186 if (swap)
187 ast_swapcopy_samples(s->data+s->len, f->data, f->samples);
188 else
189 memcpy(s->data + s->len, f->data, f->datalen);
190 /* If either side is empty, reset the delivery time */
191 if (!s->len || ast_tvzero(f->delivery) || ast_tvzero(s->delivery)) /* XXX really ? */
192 s->delivery = f->delivery;
193 s->len += f->datalen;
194 return 0;
197 struct ast_frame *ast_smoother_read(struct ast_smoother *s)
199 struct ast_frame *opt;
200 int len;
201 /* IF we have an optimization frame, send it */
202 if (s->opt) {
203 if (s->opt->offset < AST_FRIENDLY_OFFSET)
204 ast_log(LOG_WARNING, "Returning a frame of inappropriate offset (%d).",
205 s->opt->offset);
206 opt = s->opt;
207 s->opt = NULL;
208 return opt;
211 /* Make sure we have enough data */
212 if (s->len < s->size) {
213 /* Or, if this is a G.729 frame with VAD on it, send it immediately anyway */
214 if (!((s->flags & AST_SMOOTHER_FLAG_G729) && (s->size % 10)))
215 return NULL;
217 len = s->size;
218 if (len > s->len)
219 len = s->len;
220 /* Make frame */
221 s->f.frametype = AST_FRAME_VOICE;
222 s->f.subclass = s->format;
223 s->f.data = s->framedata + AST_FRIENDLY_OFFSET;
224 s->f.offset = AST_FRIENDLY_OFFSET;
225 s->f.datalen = len;
226 /* Samples will be improper given VAD, but with VAD the concept really doesn't even exist */
227 s->f.samples = len * s->samplesperbyte; /* XXX rounding */
228 s->f.delivery = s->delivery;
229 /* Fill Data */
230 memcpy(s->f.data, s->data, len);
231 s->len -= len;
232 /* Move remaining data to the front if applicable */
233 if (s->len) {
234 /* In principle this should all be fine because if we are sending
235 G.729 VAD, the next timestamp will take over anyawy */
236 memmove(s->data, s->data + len, s->len);
237 if (!ast_tvzero(s->delivery)) {
238 /* If we have delivery time, increment it, otherwise, leave it at 0 */
239 s->delivery = ast_tvadd(s->delivery, ast_samp2tv(s->f.samples, 8000));
242 /* Return frame */
243 return &s->f;
246 void ast_smoother_free(struct ast_smoother *s)
248 free(s);
251 static struct ast_frame *ast_frame_header_new(void)
253 struct ast_frame *f = ast_calloc(1, sizeof(*f));
254 #ifdef TRACE_FRAMES
255 if (f) {
256 headers++;
257 f->prev = NULL;
258 ast_mutex_lock(&framelock);
259 f->next = headerlist;
260 if (headerlist)
261 headerlist->prev = f;
262 headerlist = f;
263 ast_mutex_unlock(&framelock);
265 #endif
266 return f;
270 * \todo Important: I should be made more efficient. Frame headers should
271 * most definitely be cached
273 void ast_frfree(struct ast_frame *fr)
275 if (fr->mallocd & AST_MALLOCD_DATA) {
276 if (fr->data)
277 free(fr->data - fr->offset);
279 if (fr->mallocd & AST_MALLOCD_SRC) {
280 if (fr->src)
281 free((char *)fr->src);
283 if (fr->mallocd & AST_MALLOCD_HDR) {
284 #ifdef TRACE_FRAMES
285 headers--;
286 ast_mutex_lock(&framelock);
287 if (fr->next)
288 fr->next->prev = fr->prev;
289 if (fr->prev)
290 fr->prev->next = fr->next;
291 else
292 headerlist = fr->next;
293 ast_mutex_unlock(&framelock);
294 #endif
295 free(fr);
300 * \brief 'isolates' a frame by duplicating non-malloc'ed components
301 * (header, src, data).
302 * On return all components are malloc'ed
304 struct ast_frame *ast_frisolate(struct ast_frame *fr)
306 struct ast_frame *out;
307 void *newdata;
309 if (!(fr->mallocd & AST_MALLOCD_HDR)) {
310 /* Allocate a new header if needed */
311 if (!(out = ast_frame_header_new()))
312 return NULL;
313 out->frametype = fr->frametype;
314 out->subclass = fr->subclass;
315 out->datalen = fr->datalen;
316 out->samples = fr->samples;
317 out->offset = fr->offset;
318 out->data = fr->data;
319 } else
320 out = fr;
322 if (!(fr->mallocd & AST_MALLOCD_SRC)) {
323 if (fr->src)
324 out->src = strdup(fr->src);
325 } else
326 out->src = fr->src;
328 if (!(fr->mallocd & AST_MALLOCD_DATA)) {
329 if (!(newdata = ast_malloc(fr->datalen + AST_FRIENDLY_OFFSET))) {
330 free(out);
331 return NULL;
333 newdata += AST_FRIENDLY_OFFSET;
334 out->offset = AST_FRIENDLY_OFFSET;
335 out->datalen = fr->datalen;
336 memcpy(newdata, fr->data, fr->datalen);
337 out->data = newdata;
340 out->mallocd = AST_MALLOCD_HDR | AST_MALLOCD_SRC | AST_MALLOCD_DATA;
342 return out;
345 struct ast_frame *ast_frdup(struct ast_frame *f)
347 struct ast_frame *out;
348 int len, srclen = 0;
349 void *buf;
350 /* Start with standard stuff */
351 len = sizeof(*out) + AST_FRIENDLY_OFFSET + f->datalen;
352 /* If we have a source, add space for it */
354 * XXX Watch out here - if we receive a src which is not terminated
355 * properly, we can be easily attacked. Should limit the size we deal with.
357 if (f->src)
358 srclen = strlen(f->src);
359 if (srclen > 0)
360 len += srclen + 1;
361 if (!(buf = ast_malloc(len)))
362 return NULL;
363 out = buf;
364 /* Set us as having malloc'd header only, so it will eventually
365 get freed. */
366 out->frametype = f->frametype;
367 out->subclass = f->subclass;
368 out->datalen = f->datalen;
369 out->samples = f->samples;
370 out->delivery = f->delivery;
371 out->mallocd = AST_MALLOCD_HDR;
372 out->offset = AST_FRIENDLY_OFFSET;
373 out->data = buf + sizeof(*out) + AST_FRIENDLY_OFFSET;
374 if (srclen > 0) {
375 out->src = out->data + f->datalen;
376 /* Must have space since we allocated for it */
377 strcpy((char *)out->src, f->src);
378 } else
379 out->src = NULL;
380 out->prev = NULL;
381 out->next = NULL;
382 memcpy(out->data, f->data, out->datalen);
383 return out;
386 #if 0
388 * XXX
389 * This function is badly broken - it does not handle correctly
390 * partial reads on either header or body.
391 * However is it never used anywhere so we leave it commented out
393 struct ast_frame *ast_fr_fdread(int fd)
395 char buf[65536];
396 int res;
397 struct ast_frame *f = (struct ast_frame *)buf;
398 int ttl = sizeof(*f);
399 /* Read a frame directly from there. They're always in the
400 right format. */
402 while(ttl) {
403 res = read(fd, buf, ttl);
404 if (res < 0) {
405 ast_log(LOG_WARNING, "Bad read on %d: %s\n", fd, strerror(errno));
406 return NULL;
408 ttl -= res;
411 /* read the frame header */
413 /* Re-write data position */
414 f->data = buf + sizeof(*f);
415 f->offset = 0;
416 /* Forget about being mallocd */
417 f->mallocd = 0;
418 /* Re-write the source */
419 f->src = (char *)__FUNCTION__;
420 if (f->datalen > sizeof(buf) - sizeof(*f)) {
421 /* Really bad read */
422 ast_log(LOG_WARNING, "Strange read (%d bytes)\n", f->datalen);
423 return NULL;
425 if (f->datalen) {
426 if ((res = read(fd, f->data, f->datalen)) != f->datalen) {
427 /* Bad read */
428 ast_log(LOG_WARNING, "How very strange, expected %d, got %d\n", f->datalen, res);
429 return NULL;
432 if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_HANGUP)) {
433 return NULL;
435 return ast_frisolate(f);
438 /* Some convenient routines for sending frames to/from stream or datagram
439 sockets, pipes, etc (maybe even files) */
442 * XXX this function is also partly broken because it does not handle
443 * partial writes. We comment it out too, and also the unique
444 * client it has, ast_fr_fdhangup()
446 int ast_fr_fdwrite(int fd, struct ast_frame *frame)
448 /* Write the frame exactly */
449 if (write(fd, frame, sizeof(*frame)) != sizeof(*frame)) {
450 ast_log(LOG_WARNING, "Write error: %s\n", strerror(errno));
451 return -1;
453 if (write(fd, frame->data, frame->datalen) != frame->datalen) {
454 ast_log(LOG_WARNING, "Write error: %s\n", strerror(errno));
455 return -1;
457 return 0;
460 int ast_fr_fdhangup(int fd)
462 struct ast_frame hangup = {
463 AST_FRAME_CONTROL,
464 AST_CONTROL_HANGUP
466 return ast_fr_fdwrite(fd, &hangup);
469 #endif /* unused functions */
470 void ast_swapcopy_samples(void *dst, const void *src, int samples)
472 int i;
473 unsigned short *dst_s = dst;
474 const unsigned short *src_s = src;
476 for (i=0; i<samples; i++)
477 dst_s[i] = (src_s[i]<<8) | (src_s[i]>>8);
481 struct ast_format_list *ast_get_format_list_index(int index)
483 return &AST_FORMAT_LIST[index];
486 struct ast_format_list *ast_get_format_list(size_t *size)
488 *size = (sizeof(AST_FORMAT_LIST) / sizeof(AST_FORMAT_LIST[0]));
489 return AST_FORMAT_LIST;
492 char* ast_getformatname(int format)
494 int x;
495 char *ret = "unknown";
496 for (x = 0; x < sizeof(AST_FORMAT_LIST) / sizeof(AST_FORMAT_LIST[0]); x++) {
497 if(AST_FORMAT_LIST[x].visible && AST_FORMAT_LIST[x].bits == format) {
498 ret = AST_FORMAT_LIST[x].name;
499 break;
502 return ret;
505 char *ast_getformatname_multiple(char *buf, size_t size, int format) {
507 int x;
508 unsigned len;
509 char *start, *end = buf;
510 if (!size) return buf;
511 snprintf(end, size, "0x%x (", format);
512 len = strlen(end);
513 end += len;
514 size -= len;
515 start = end;
516 for (x = 0; x < sizeof(AST_FORMAT_LIST) / sizeof(AST_FORMAT_LIST[0]); x++) {
517 if (AST_FORMAT_LIST[x].visible && (AST_FORMAT_LIST[x].bits & format)) {
518 snprintf(end, size,"%s|",AST_FORMAT_LIST[x].name);
519 len = strlen(end);
520 end += len;
521 size -= len;
524 if (start == end)
525 snprintf(start, size, "nothing)");
526 else if (size > 1)
527 *(end -1) = ')';
528 return buf;
531 static struct ast_codec_alias_table {
532 char *alias;
533 char *realname;
535 } ast_codec_alias_table[] = {
536 {"slinear","slin"},
537 {"g723.1","g723"},
540 static const char *ast_expand_codec_alias(const char *in) {
541 int x;
543 for (x = 0; x < sizeof(ast_codec_alias_table) / sizeof(ast_codec_alias_table[0]); x++) {
544 if(!strcmp(in,ast_codec_alias_table[x].alias))
545 return ast_codec_alias_table[x].realname;
547 return in;
550 int ast_getformatbyname(const char *name)
552 int x, all, format = 0;
554 all = strcasecmp(name, "all") ? 0 : 1;
555 for (x = 0; x < sizeof(AST_FORMAT_LIST) / sizeof(AST_FORMAT_LIST[0]); x++) {
556 if(AST_FORMAT_LIST[x].visible && (all ||
557 !strcasecmp(AST_FORMAT_LIST[x].name,name) ||
558 !strcasecmp(AST_FORMAT_LIST[x].name,ast_expand_codec_alias(name)))) {
559 format |= AST_FORMAT_LIST[x].bits;
560 if(!all)
561 break;
565 return format;
568 char *ast_codec2str(int codec) {
569 int x;
570 char *ret = "unknown";
571 for (x = 0; x < sizeof(AST_FORMAT_LIST) / sizeof(AST_FORMAT_LIST[0]); x++) {
572 if(AST_FORMAT_LIST[x].visible && AST_FORMAT_LIST[x].bits == codec) {
573 ret = AST_FORMAT_LIST[x].desc;
574 break;
577 return ret;
580 static int show_codecs(int fd, int argc, char *argv[])
582 int i, found=0;
583 char hex[25];
585 if ((argc < 2) || (argc > 3))
586 return RESULT_SHOWUSAGE;
588 if (!ast_opt_dont_warn)
589 ast_cli(fd, "Disclaimer: this command is for informational purposes only.\n"
590 "\tIt does not indicate anything about your configuration.\n");
592 ast_cli(fd, "%11s %9s %10s TYPE %5s %s\n","INT","BINARY","HEX","NAME","DESC");
593 ast_cli(fd, "--------------------------------------------------------------------------------\n");
594 if ((argc == 2) || (!strcasecmp(argv[1],"audio"))) {
595 found = 1;
596 for (i=0;i<11;i++) {
597 snprintf(hex,25,"(0x%x)",1<<i);
598 ast_cli(fd, "%11u (1 << %2d) %10s audio %5s (%s)\n",1 << i,i,hex,ast_getformatname(1<<i),ast_codec2str(1<<i));
602 if ((argc == 2) || (!strcasecmp(argv[1],"image"))) {
603 found = 1;
604 for (i=16;i<18;i++) {
605 snprintf(hex,25,"(0x%x)",1<<i);
606 ast_cli(fd, "%11u (1 << %2d) %10s image %5s (%s)\n",1 << i,i,hex,ast_getformatname(1<<i),ast_codec2str(1<<i));
610 if ((argc == 2) || (!strcasecmp(argv[1],"video"))) {
611 found = 1;
612 for (i=18;i<21;i++) {
613 snprintf(hex,25,"(0x%x)",1<<i);
614 ast_cli(fd, "%11u (1 << %2d) %10s video %5s (%s)\n",1 << i,i,hex,ast_getformatname(1<<i),ast_codec2str(1<<i));
618 if (! found)
619 return RESULT_SHOWUSAGE;
620 else
621 return RESULT_SUCCESS;
624 static char frame_show_codecs_usage[] =
625 "Usage: show [audio|video|image] codecs\n"
626 " Displays codec mapping\n";
628 static int show_codec_n(int fd, int argc, char *argv[])
630 int codec, i, found=0;
632 if (argc != 3)
633 return RESULT_SHOWUSAGE;
635 if (sscanf(argv[2],"%d",&codec) != 1)
636 return RESULT_SHOWUSAGE;
638 for (i=0;i<32;i++)
639 if (codec & (1 << i)) {
640 found = 1;
641 ast_cli(fd, "%11u (1 << %2d) %s\n",1 << i,i,ast_codec2str(1<<i));
644 if (! found)
645 ast_cli(fd, "Codec %d not found\n", codec);
647 return RESULT_SUCCESS;
650 static char frame_show_codec_n_usage[] =
651 "Usage: show codec <number>\n"
652 " Displays codec mapping\n";
654 /*! Dump a frame for debugging purposes */
655 void ast_frame_dump(const char *name, struct ast_frame *f, char *prefix)
657 const char noname[] = "unknown";
658 char ftype[40] = "Unknown Frametype";
659 char cft[80];
660 char subclass[40] = "Unknown Subclass";
661 char csub[80];
662 char moreinfo[40] = "";
663 char cn[60];
664 char cp[40];
665 char cmn[40];
667 if (!name)
668 name = noname;
671 if (!f) {
672 ast_verbose("%s [ %s (NULL) ] [%s]\n",
673 term_color(cp, prefix, COLOR_BRMAGENTA, COLOR_BLACK, sizeof(cp)),
674 term_color(cft, "HANGUP", COLOR_BRRED, COLOR_BLACK, sizeof(cft)),
675 term_color(cn, name, COLOR_YELLOW, COLOR_BLACK, sizeof(cn)));
676 return;
678 /* XXX We should probably print one each of voice and video when the format changes XXX */
679 if (f->frametype == AST_FRAME_VOICE)
680 return;
681 if (f->frametype == AST_FRAME_VIDEO)
682 return;
683 switch(f->frametype) {
684 case AST_FRAME_DTMF:
685 strcpy(ftype, "DTMF");
686 subclass[0] = f->subclass;
687 subclass[1] = '\0';
688 break;
689 case AST_FRAME_CONTROL:
690 strcpy(ftype, "Control");
691 switch(f->subclass) {
692 case AST_CONTROL_HANGUP:
693 strcpy(subclass, "Hangup");
694 break;
695 case AST_CONTROL_RING:
696 strcpy(subclass, "Ring");
697 break;
698 case AST_CONTROL_RINGING:
699 strcpy(subclass, "Ringing");
700 break;
701 case AST_CONTROL_ANSWER:
702 strcpy(subclass, "Answer");
703 break;
704 case AST_CONTROL_BUSY:
705 strcpy(subclass, "Busy");
706 break;
707 case AST_CONTROL_TAKEOFFHOOK:
708 strcpy(subclass, "Take Off Hook");
709 break;
710 case AST_CONTROL_OFFHOOK:
711 strcpy(subclass, "Line Off Hook");
712 break;
713 case AST_CONTROL_CONGESTION:
714 strcpy(subclass, "Congestion");
715 break;
716 case AST_CONTROL_FLASH:
717 strcpy(subclass, "Flash");
718 break;
719 case AST_CONTROL_WINK:
720 strcpy(subclass, "Wink");
721 break;
722 case AST_CONTROL_OPTION:
723 strcpy(subclass, "Option");
724 break;
725 case AST_CONTROL_RADIO_KEY:
726 strcpy(subclass, "Key Radio");
727 break;
728 case AST_CONTROL_RADIO_UNKEY:
729 strcpy(subclass, "Unkey Radio");
730 break;
731 case -1:
732 strcpy(subclass, "Stop generators");
733 break;
734 default:
735 snprintf(subclass, sizeof(subclass), "Unknown control '%d'", f->subclass);
737 break;
738 case AST_FRAME_NULL:
739 strcpy(ftype, "Null Frame");
740 strcpy(subclass, "N/A");
741 break;
742 case AST_FRAME_IAX:
743 /* Should never happen */
744 strcpy(ftype, "IAX Specific");
745 snprintf(subclass, sizeof(subclass), "IAX Frametype %d", f->subclass);
746 break;
747 case AST_FRAME_TEXT:
748 strcpy(ftype, "Text");
749 strcpy(subclass, "N/A");
750 ast_copy_string(moreinfo, f->data, sizeof(moreinfo));
751 break;
752 case AST_FRAME_IMAGE:
753 strcpy(ftype, "Image");
754 snprintf(subclass, sizeof(subclass), "Image format %s\n", ast_getformatname(f->subclass));
755 break;
756 case AST_FRAME_HTML:
757 strcpy(ftype, "HTML");
758 switch(f->subclass) {
759 case AST_HTML_URL:
760 strcpy(subclass, "URL");
761 ast_copy_string(moreinfo, f->data, sizeof(moreinfo));
762 break;
763 case AST_HTML_DATA:
764 strcpy(subclass, "Data");
765 break;
766 case AST_HTML_BEGIN:
767 strcpy(subclass, "Begin");
768 break;
769 case AST_HTML_END:
770 strcpy(subclass, "End");
771 break;
772 case AST_HTML_LDCOMPLETE:
773 strcpy(subclass, "Load Complete");
774 break;
775 case AST_HTML_NOSUPPORT:
776 strcpy(subclass, "No Support");
777 break;
778 case AST_HTML_LINKURL:
779 strcpy(subclass, "Link URL");
780 ast_copy_string(moreinfo, f->data, sizeof(moreinfo));
781 break;
782 case AST_HTML_UNLINK:
783 strcpy(subclass, "Unlink");
784 break;
785 case AST_HTML_LINKREJECT:
786 strcpy(subclass, "Link Reject");
787 break;
788 default:
789 snprintf(subclass, sizeof(subclass), "Unknown HTML frame '%d'\n", f->subclass);
790 break;
792 break;
793 default:
794 snprintf(ftype, sizeof(ftype), "Unknown Frametype '%d'", f->frametype);
796 if (!ast_strlen_zero(moreinfo))
797 ast_verbose("%s [ TYPE: %s (%d) SUBCLASS: %s (%d) '%s' ] [%s]\n",
798 term_color(cp, prefix, COLOR_BRMAGENTA, COLOR_BLACK, sizeof(cp)),
799 term_color(cft, ftype, COLOR_BRRED, COLOR_BLACK, sizeof(cft)),
800 f->frametype,
801 term_color(csub, subclass, COLOR_BRCYAN, COLOR_BLACK, sizeof(csub)),
802 f->subclass,
803 term_color(cmn, moreinfo, COLOR_BRGREEN, COLOR_BLACK, sizeof(cmn)),
804 term_color(cn, name, COLOR_YELLOW, COLOR_BLACK, sizeof(cn)));
805 else
806 ast_verbose("%s [ TYPE: %s (%d) SUBCLASS: %s (%d) ] [%s]\n",
807 term_color(cp, prefix, COLOR_BRMAGENTA, COLOR_BLACK, sizeof(cp)),
808 term_color(cft, ftype, COLOR_BRRED, COLOR_BLACK, sizeof(cft)),
809 f->frametype,
810 term_color(csub, subclass, COLOR_BRCYAN, COLOR_BLACK, sizeof(csub)),
811 f->subclass,
812 term_color(cn, name, COLOR_YELLOW, COLOR_BLACK, sizeof(cn)));
816 #ifdef TRACE_FRAMES
817 static int show_frame_stats(int fd, int argc, char *argv[])
819 struct ast_frame *f;
820 int x=1;
821 if (argc != 3)
822 return RESULT_SHOWUSAGE;
823 ast_cli(fd, " Framer Statistics \n");
824 ast_cli(fd, "---------------------------\n");
825 ast_cli(fd, "Total allocated headers: %d\n", headers);
826 ast_cli(fd, "Queue Dump:\n");
827 ast_mutex_lock(&framelock);
828 for (f=headerlist; f; f = f->next) {
829 ast_cli(fd, "%d. Type %d, subclass %d from %s\n", x++, f->frametype, f->subclass, f->src ? f->src : "<Unknown>");
831 ast_mutex_unlock(&framelock);
832 return RESULT_SUCCESS;
835 static char frame_stats_usage[] =
836 "Usage: show frame stats\n"
837 " Displays debugging statistics from framer\n";
838 #endif
840 /* Builtin Asterisk CLI-commands for debugging */
841 static struct ast_cli_entry my_clis[] = {
842 { { "show", "codecs", NULL }, show_codecs, "Shows codecs", frame_show_codecs_usage },
843 { { "show", "audio", "codecs", NULL }, show_codecs, "Shows audio codecs", frame_show_codecs_usage },
844 { { "show", "video", "codecs", NULL }, show_codecs, "Shows video codecs", frame_show_codecs_usage },
845 { { "show", "image", "codecs", NULL }, show_codecs, "Shows image codecs", frame_show_codecs_usage },
846 { { "show", "codec", NULL }, show_codec_n, "Shows a specific codec", frame_show_codec_n_usage },
847 #ifdef TRACE_FRAMES
848 { { "show", "frame", "stats", NULL }, show_frame_stats, "Shows frame statistics", frame_stats_usage },
849 #endif
852 int init_framer(void)
854 ast_cli_register_multiple(my_clis, sizeof(my_clis)/sizeof(my_clis[0]) );
855 return 0;
858 void ast_codec_pref_convert(struct ast_codec_pref *pref, char *buf, size_t size, int right)
860 int x, differential = (int) 'A', mem;
861 char *from, *to;
863 if(right) {
864 from = pref->order;
865 to = buf;
866 mem = size;
867 } else {
868 to = pref->order;
869 from = buf;
870 mem = 32;
873 memset(to, 0, mem);
874 for (x = 0; x < 32 ; x++) {
875 if(!from[x])
876 break;
877 to[x] = right ? (from[x] + differential) : (from[x] - differential);
881 int ast_codec_pref_string(struct ast_codec_pref *pref, char *buf, size_t size)
883 int x, codec;
884 size_t total_len, slen;
885 char *formatname;
887 memset(buf,0,size);
888 total_len = size;
889 buf[0] = '(';
890 total_len--;
891 for(x = 0; x < 32 ; x++) {
892 if(total_len <= 0)
893 break;
894 if(!(codec = ast_codec_pref_index(pref,x)))
895 break;
896 if((formatname = ast_getformatname(codec))) {
897 slen = strlen(formatname);
898 if(slen > total_len)
899 break;
900 strncat(buf,formatname,total_len);
901 total_len -= slen;
903 if(total_len && x < 31 && ast_codec_pref_index(pref , x + 1)) {
904 strncat(buf,"|",total_len);
905 total_len--;
908 if(total_len) {
909 strncat(buf,")",total_len);
910 total_len--;
913 return size - total_len;
916 int ast_codec_pref_index(struct ast_codec_pref *pref, int index)
918 int slot = 0;
921 if((index >= 0) && (index < sizeof(pref->order))) {
922 slot = pref->order[index];
925 return slot ? AST_FORMAT_LIST[slot-1].bits : 0;
928 /*! \brief ast_codec_pref_remove: Remove codec from pref list ---*/
929 void ast_codec_pref_remove(struct ast_codec_pref *pref, int format)
931 struct ast_codec_pref oldorder;
932 int x, y = 0;
933 int slot;
935 if(!pref->order[0])
936 return;
938 memcpy(&oldorder, pref, sizeof(oldorder));
939 memset(pref, 0, sizeof(*pref));
941 for (x = 0; x < sizeof(AST_FORMAT_LIST) / sizeof(AST_FORMAT_LIST[0]); x++) {
942 slot = oldorder.order[x];
943 if(! slot)
944 break;
945 if(AST_FORMAT_LIST[slot-1].bits != format)
946 pref->order[y++] = slot;
951 /*! \brief ast_codec_pref_append: Append codec to list ---*/
952 int ast_codec_pref_append(struct ast_codec_pref *pref, int format)
954 int x, newindex = -1;
956 ast_codec_pref_remove(pref, format);
958 for (x = 0; x < sizeof(AST_FORMAT_LIST) / sizeof(AST_FORMAT_LIST[0]); x++) {
959 if(AST_FORMAT_LIST[x].bits == format) {
960 newindex = x + 1;
961 break;
965 if(newindex) {
966 for (x = 0; x < sizeof(AST_FORMAT_LIST) / sizeof(AST_FORMAT_LIST[0]); x++) {
967 if(!pref->order[x]) {
968 pref->order[x] = newindex;
969 break;
974 return x;
978 /*! \brief ast_codec_choose: Pick a codec ---*/
979 int ast_codec_choose(struct ast_codec_pref *pref, int formats, int find_best)
981 int x, ret = 0, slot;
983 for (x = 0; x < sizeof(AST_FORMAT_LIST) / sizeof(AST_FORMAT_LIST[0]); x++) {
984 slot = pref->order[x];
986 if(!slot)
987 break;
988 if ( formats & AST_FORMAT_LIST[slot-1].bits ) {
989 ret = AST_FORMAT_LIST[slot-1].bits;
990 break;
993 if(ret)
994 return ret;
996 return find_best ? ast_best_codec(formats) : 0;
999 void ast_parse_allow_disallow(struct ast_codec_pref *pref, int *mask, const char *list, int allowing)
1001 char *parse;
1002 char *this;
1003 int format;
1005 parse = ast_strdupa(list);
1006 while ((this = strsep(&parse, ","))) {
1007 if (!(format = ast_getformatbyname(this))) {
1008 ast_log(LOG_WARNING, "Cannot %s unknown format '%s'\n", allowing ? "allow" : "disallow", this);
1009 continue;
1012 if (mask) {
1013 if (allowing)
1014 *mask |= format;
1015 else
1016 *mask &= ~format;
1019 if (pref) {
1020 if (strcasecmp(this, "all")) {
1021 if (allowing)
1022 ast_codec_pref_append(pref, format);
1023 else
1024 ast_codec_pref_remove(pref, format);
1025 } else if (!allowing) {
1026 memset(pref, 0, sizeof(*pref));
1032 static int g723_len(unsigned char buf)
1034 enum frame_type type = buf & TYPE_MASK;
1036 switch(type) {
1037 case TYPE_DONTSEND:
1038 return 0;
1039 break;
1040 case TYPE_SILENCE:
1041 return 4;
1042 break;
1043 case TYPE_HIGH:
1044 return 24;
1045 break;
1046 case TYPE_LOW:
1047 return 20;
1048 break;
1049 default:
1050 ast_log(LOG_WARNING, "Badly encoded frame (%d)\n", type);
1052 return -1;
1055 static int g723_samples(unsigned char *buf, int maxlen)
1057 int pos = 0;
1058 int samples = 0;
1059 int res;
1060 while(pos < maxlen) {
1061 res = g723_len(buf[pos]);
1062 if (res <= 0)
1063 break;
1064 samples += 240;
1065 pos += res;
1067 return samples;
1070 static unsigned char get_n_bits_at(unsigned char *data, int n, int bit)
1072 int byte = bit / 8; /* byte containing first bit */
1073 int rem = 8 - (bit % 8); /* remaining bits in first byte */
1074 unsigned char ret = 0;
1076 if (n <= 0 || n > 8)
1077 return 0;
1079 if (rem < n) {
1080 ret = (data[byte] << (n - rem));
1081 ret |= (data[byte + 1] >> (8 - n + rem));
1082 } else {
1083 ret = (data[byte] >> (rem - n));
1086 return (ret & (0xff >> (8 - n)));
1089 static int speex_get_wb_sz_at(unsigned char *data, int len, int bit)
1091 static int SpeexWBSubModeSz[] = {
1092 0, 36, 112, 192,
1093 352, 0, 0, 0 };
1094 int off = bit;
1095 unsigned char c;
1097 /* skip up to two wideband frames */
1098 if (((len * 8 - off) >= 5) &&
1099 get_n_bits_at(data, 1, off)) {
1100 c = get_n_bits_at(data, 3, off + 1);
1101 off += SpeexWBSubModeSz[c];
1103 if (((len * 8 - off) >= 5) &&
1104 get_n_bits_at(data, 1, off)) {
1105 c = get_n_bits_at(data, 3, off + 1);
1106 off += SpeexWBSubModeSz[c];
1108 if (((len * 8 - off) >= 5) &&
1109 get_n_bits_at(data, 1, off)) {
1110 ast_log(LOG_WARNING, "Encountered corrupt speex frame; too many wideband frames in a row.\n");
1111 return -1;
1116 return off - bit;
1119 static int speex_samples(unsigned char *data, int len)
1121 static int SpeexSubModeSz[] = {
1122 5, 43, 119, 160,
1123 220, 300, 364, 492,
1124 79, 0, 0, 0,
1125 0, 0, 0, 0 };
1126 static int SpeexInBandSz[] = {
1127 1, 1, 4, 4,
1128 4, 4, 4, 4,
1129 8, 8, 16, 16,
1130 32, 32, 64, 64 };
1131 int bit = 0;
1132 int cnt = 0;
1133 int off;
1134 unsigned char c;
1136 while ((len * 8 - bit) >= 5) {
1137 /* skip wideband frames */
1138 off = speex_get_wb_sz_at(data, len, bit);
1139 if (off < 0) {
1140 ast_log(LOG_WARNING, "Had error while reading wideband frames for speex samples\n");
1141 break;
1143 bit += off;
1145 if ((len * 8 - bit) < 5) {
1146 ast_log(LOG_WARNING, "Not enough bits remaining after wide band for speex samples.\n");
1147 break;
1150 /* get control bits */
1151 c = get_n_bits_at(data, 5, bit);
1152 bit += 5;
1154 if (c == 15) {
1155 /* terminator */
1156 break;
1157 } else if (c == 14) {
1158 /* in-band signal; next 4 bits contain signal id */
1159 c = get_n_bits_at(data, 4, bit);
1160 bit += 4;
1161 bit += SpeexInBandSz[c];
1162 } else if (c == 13) {
1163 /* user in-band; next 5 bits contain msg len */
1164 c = get_n_bits_at(data, 5, bit);
1165 bit += 5;
1166 bit += c * 8;
1167 } else if (c > 8) {
1168 /* unknown */
1169 break;
1170 } else {
1171 /* skip number bits for submode (less the 5 control bits) */
1172 bit += SpeexSubModeSz[c] - 5;
1173 cnt += 160; /* new frame */
1176 return cnt;
1179 int ast_codec_get_samples(struct ast_frame *f)
1181 int samples=0;
1182 switch(f->subclass) {
1183 case AST_FORMAT_SPEEX:
1184 samples = speex_samples(f->data, f->datalen);
1185 break;
1186 case AST_FORMAT_G723_1:
1187 samples = g723_samples(f->data, f->datalen);
1188 break;
1189 case AST_FORMAT_ILBC:
1190 samples = 240 * (f->datalen / 50);
1191 break;
1192 case AST_FORMAT_GSM:
1193 samples = 160 * (f->datalen / 33);
1194 break;
1195 case AST_FORMAT_G729A:
1196 samples = f->datalen * 8;
1197 break;
1198 case AST_FORMAT_SLINEAR:
1199 samples = f->datalen / 2;
1200 break;
1201 case AST_FORMAT_LPC10:
1202 /* assumes that the RTP packet contains one LPC10 frame */
1203 samples = 22 * 8;
1204 samples += (((char *)(f->data))[7] & 0x1) * 8;
1205 break;
1206 case AST_FORMAT_ULAW:
1207 case AST_FORMAT_ALAW:
1208 samples = f->datalen;
1209 break;
1210 case AST_FORMAT_ADPCM:
1211 case AST_FORMAT_G726:
1212 samples = f->datalen * 2;
1213 break;
1214 default:
1215 ast_log(LOG_WARNING, "Unable to calculate samples for format %s\n", ast_getformatname(f->subclass));
1217 return samples;
1220 int ast_codec_get_len(int format, int samples)
1222 int len = 0;
1224 /* XXX Still need speex, g723, and lpc10 XXX */
1225 switch(format) {
1226 case AST_FORMAT_ILBC:
1227 len = (samples / 240) * 50;
1228 break;
1229 case AST_FORMAT_GSM:
1230 len = (samples / 160) * 33;
1231 break;
1232 case AST_FORMAT_G729A:
1233 len = samples / 8;
1234 break;
1235 case AST_FORMAT_SLINEAR:
1236 len = samples * 2;
1237 break;
1238 case AST_FORMAT_ULAW:
1239 case AST_FORMAT_ALAW:
1240 len = samples;
1241 break;
1242 case AST_FORMAT_ADPCM:
1243 case AST_FORMAT_G726:
1244 len = samples / 2;
1245 break;
1246 default:
1247 ast_log(LOG_WARNING, "Unable to calculate sample length for format %s\n", ast_getformatname(format));
1250 return len;
1253 int ast_frame_adjust_volume(struct ast_frame *f, int adjustment)
1255 int count;
1256 short *fdata = f->data;
1257 short adjust_value = abs(adjustment);
1259 if ((f->frametype != AST_FRAME_VOICE) || (f->subclass != AST_FORMAT_SLINEAR))
1260 return -1;
1262 if (!adjustment)
1263 return 0;
1265 for (count = 0; count < f->samples; count++) {
1266 if (adjustment > 0) {
1267 ast_slinear_saturated_multiply(&fdata[count], &adjust_value);
1268 } else if (adjustment < 0) {
1269 ast_slinear_saturated_divide(&fdata[count], &adjust_value);
1273 return 0;
1276 int ast_frame_slinear_sum(struct ast_frame *f1, struct ast_frame *f2)
1278 int count;
1279 short *data1, *data2;
1281 if ((f1->frametype != AST_FRAME_VOICE) || (f1->subclass != AST_FORMAT_SLINEAR))
1282 return -1;
1284 if ((f2->frametype != AST_FRAME_VOICE) || (f2->subclass != AST_FORMAT_SLINEAR))
1285 return -1;
1287 if (f1->samples != f2->samples)
1288 return -1;
1290 for (count = 0, data1 = f1->data, data2 = f2->data;
1291 count < f1->samples;
1292 count++, data1++, data2++)
1293 ast_slinear_saturated_add(data1, data2);
1295 return 0;
1298 struct ast_frame *ast_frame_enqueue(struct ast_frame *head, struct ast_frame *f, int maxlen, int dupe)
1300 struct ast_frame *cur, *oldhead;
1301 int len=0;
1302 if (f && dupe)
1303 f = ast_frdup(f);
1304 if (!f)
1305 return head;
1307 f->next = NULL;
1308 if (!head)
1309 return f;
1310 cur = head;
1311 while(cur->next) {
1312 cur = cur->next;
1313 len++;
1314 if (len >= maxlen) {
1315 oldhead = head;
1316 head = head->next;
1317 ast_frfree(oldhead);
1320 return head;