673e7b46d9e6e9a30fc7e68ef9a5536baea8cb0e
[asterisk/asterisk.git] / frame.c
1 /*
2  * Asterisk -- A telephony toolkit for Linux.
3  *
4  * Frame manipulation routines
5  * 
6  * Copyright (C) 1999 - 2005, Digium, Inc.
7  *
8  * Mark Spencer <markster@digium.com>
9  *
10  * This program is free software, distributed under the terms of
11  * the GNU General Public License
12  */
13
14 #include <asterisk/lock.h>
15 #include <asterisk/frame.h>
16 #include <asterisk/logger.h>
17 #include <asterisk/options.h>
18 #include <asterisk/channel.h>
19 #include <asterisk/cli.h>
20 #include <asterisk/term.h>
21 #include <asterisk/utils.h>
22 #include <stdlib.h>
23 #include <unistd.h>
24 #include <string.h>
25 #include <errno.h>
26 #include <stdio.h>
27 #include "asterisk.h"
28
29 #ifdef TRACE_FRAMES
30 static int headers = 0;
31 static struct ast_frame *headerlist = NULL;
32 AST_MUTEX_DEFINE_STATIC(framelock);
33 #endif
34
35 #define SMOOTHER_SIZE 8000
36
37 struct ast_format_list {
38         int visible; /* Can we see this entry */
39         int bits; /* bitmask value */
40         char *name; /* short name */
41         char *desc; /* Description */
42 };
43
44 struct ast_smoother {
45         int size;
46         int format;
47         int readdata;
48         int optimizablestream;
49         int flags;
50         float samplesperbyte;
51         struct ast_frame f;
52         struct timeval delivery;
53         char data[SMOOTHER_SIZE];
54         char framedata[SMOOTHER_SIZE + AST_FRIENDLY_OFFSET];
55         struct ast_frame *opt;
56         int len;
57 };
58
59 void ast_smoother_reset(struct ast_smoother *s, int size)
60 {
61         memset(s, 0, sizeof(struct ast_smoother));
62         s->size = size;
63 }
64
65 struct ast_smoother *ast_smoother_new(int size)
66 {
67         struct ast_smoother *s;
68         if (size < 1)
69                 return NULL;
70         s = malloc(sizeof(struct ast_smoother));
71         if (s)
72                 ast_smoother_reset(s, size);
73         return s;
74 }
75
76 int ast_smoother_get_flags(struct ast_smoother *s)
77 {
78         return s->flags;
79 }
80
81 void ast_smoother_set_flags(struct ast_smoother *s, int flags)
82 {
83         s->flags = flags;
84 }
85
86 int ast_smoother_feed(struct ast_smoother *s, struct ast_frame *f)
87 {
88         if (f->frametype != AST_FRAME_VOICE) {
89                 ast_log(LOG_WARNING, "Huh?  Can't smooth a non-voice frame!\n");
90                 return -1;
91         }
92         if (!s->format) {
93                 s->format = f->subclass;
94                 s->samplesperbyte = (float)f->samples / (float)f->datalen;
95         } else if (s->format != f->subclass) {
96                 ast_log(LOG_WARNING, "Smoother was working on %d format frames, now trying to feed %d?\n", s->format, f->subclass);
97                 return -1;
98         }
99         if (s->len + f->datalen > SMOOTHER_SIZE) {
100                 ast_log(LOG_WARNING, "Out of smoother space\n");
101                 return -1;
102         }
103         if (((f->datalen == s->size) || ((f->datalen < 10) && (s->flags & AST_SMOOTHER_FLAG_G729)))
104                                  && !s->opt && (f->offset >= AST_MIN_OFFSET)) {
105                 if (!s->len) {
106                         /* Optimize by sending the frame we just got
107                            on the next read, thus eliminating the douple
108                            copy */
109                         s->opt = f;
110                         return 0;
111                 } else {
112                         s->optimizablestream++;
113                         if (s->optimizablestream > 10) {
114                                 /* For the past 10 rounds, we have input and output
115                                    frames of the correct size for this smoother, yet
116                                    we were unable to optimize because there was still
117                                    some cruft left over.  Lets just drop the cruft so
118                                    we can move to a fully optimized path */
119                                 s->len = 0;
120                                 s->opt = f;
121                                 return 0;
122                         }
123                 }
124         } else 
125                 s->optimizablestream = 0;
126         if (s->flags & AST_SMOOTHER_FLAG_G729) {
127                 if (s->len % 10) {
128                         ast_log(LOG_NOTICE, "Dropping extra frame of G.729 since we already have a VAD frame at the end\n");
129                         return 0;
130                 }
131         }
132         memcpy(s->data + s->len, f->data, f->datalen);
133         /* If either side is empty, reset the delivery time */
134         if (!s->len || (!f->delivery.tv_sec && !f->delivery.tv_usec) ||
135                         (!s->delivery.tv_sec && !s->delivery.tv_usec))
136                 s->delivery = f->delivery;
137         s->len += f->datalen;
138         return 0;
139 }
140
141 struct ast_frame *ast_smoother_read(struct ast_smoother *s)
142 {
143         struct ast_frame *opt;
144         int len;
145         /* IF we have an optimization frame, send it */
146         if (s->opt) {
147                 if (s->opt->offset < AST_FRIENDLY_OFFSET)
148                         ast_log(LOG_WARNING, "Returning a frame of inappropriate offset (%d).",
149                                                         s->opt->offset);
150                 opt = s->opt;
151                 s->opt = NULL;
152                 return opt;
153         }
154
155         /* Make sure we have enough data */
156         if (s->len < s->size) {
157                 /* Or, if this is a G.729 frame with VAD on it, send it immediately anyway */
158                 if (!((s->flags & AST_SMOOTHER_FLAG_G729) && (s->size % 10)))
159                         return NULL;
160         }
161         len = s->size;
162         if (len > s->len)
163                 len = s->len;
164         /* Make frame */
165         s->f.frametype = AST_FRAME_VOICE;
166         s->f.subclass = s->format;
167         s->f.data = s->framedata + AST_FRIENDLY_OFFSET;
168         s->f.offset = AST_FRIENDLY_OFFSET;
169         s->f.datalen = len;
170         /* Samples will be improper given VAD, but with VAD the concept really doesn't even exist */
171         s->f.samples = len * s->samplesperbyte;
172         s->f.delivery = s->delivery;
173         /* Fill Data */
174         memcpy(s->f.data, s->data, len);
175         s->len -= len;
176         /* Move remaining data to the front if applicable */
177         if (s->len) {
178                 /* In principle this should all be fine because if we are sending
179                    G.729 VAD, the next timestamp will take over anyawy */
180                 memmove(s->data, s->data + len, s->len);
181                 if (s->delivery.tv_sec || s->delivery.tv_usec) {
182                         /* If we have delivery time, increment it, otherwise, leave it at 0 */
183                         s->delivery.tv_sec += (len * s->samplesperbyte) / 8000.0;
184                         s->delivery.tv_usec += (((int)(len * s->samplesperbyte)) % 8000) * 125;
185                         if (s->delivery.tv_usec > 1000000) {
186                                 s->delivery.tv_usec -= 1000000;
187                                 s->delivery.tv_sec += 1;
188                         }
189                 }
190         }
191         /* Return frame */
192         return &s->f;
193 }
194
195 void ast_smoother_free(struct ast_smoother *s)
196 {
197         free(s);
198 }
199
200 static struct ast_frame *ast_frame_header_new(void)
201 {
202         struct ast_frame *f;
203         f = malloc(sizeof(struct ast_frame));
204         if (f)
205                 memset(f, 0, sizeof(struct ast_frame));
206 #ifdef TRACE_FRAMES
207         if (f) {
208                 headers++;
209                 f->prev = NULL;
210                 ast_mutex_lock(&framelock);
211                 f->next = headerlist;
212                 if (headerlist)
213                         headerlist->prev = f;
214                 headerlist = f;
215                 ast_mutex_unlock(&framelock);
216         }
217 #endif  
218         return f;
219 }
220
221 /*
222  * Important: I should be made more efficient.  Frame headers should
223  * most definitely be cached
224  */
225
226 void ast_frfree(struct ast_frame *fr)
227 {
228         if (fr->mallocd & AST_MALLOCD_DATA) {
229                 if (fr->data) 
230                         free(fr->data - fr->offset);
231         }
232         if (fr->mallocd & AST_MALLOCD_SRC) {
233                 if (fr->src)
234                         free((char *)fr->src);
235         }
236         if (fr->mallocd & AST_MALLOCD_HDR) {
237 #ifdef TRACE_FRAMES
238                 headers--;
239                 ast_mutex_lock(&framelock);
240                 if (fr->next)
241                         fr->next->prev = fr->prev;
242                 if (fr->prev)
243                         fr->prev->next = fr->next;
244                 else
245                         headerlist = fr->next;
246                 ast_mutex_unlock(&framelock);
247 #endif                  
248                 free(fr);
249         }
250 }
251
252 struct ast_frame *ast_frisolate(struct ast_frame *fr)
253 {
254         struct ast_frame *out;
255         if (!(fr->mallocd & AST_MALLOCD_HDR)) {
256                 /* Allocate a new header if needed */
257                 out = ast_frame_header_new();
258                 if (!out) {
259                         ast_log(LOG_WARNING, "Out of memory\n");
260                         return NULL;
261                 }
262                 out->frametype = fr->frametype;
263                 out->subclass = fr->subclass;
264                 out->datalen = 0;
265                 out->samples = fr->samples;
266                 out->offset = 0;
267                 out->src = NULL;
268                 out->data = NULL;
269         } else {
270                 out = fr;
271         }
272         if (!(fr->mallocd & AST_MALLOCD_SRC)) {
273                 if (fr->src)
274                         out->src = strdup(fr->src);
275         } else
276                 out->src = fr->src;
277         if (!(fr->mallocd & AST_MALLOCD_DATA))  {
278                 out->data = malloc(fr->datalen + AST_FRIENDLY_OFFSET);
279                 if (!out->data) {
280                         free(out);
281                         ast_log(LOG_WARNING, "Out of memory\n");
282                         return NULL;
283                 }
284                 out->data += AST_FRIENDLY_OFFSET;
285                 out->offset = AST_FRIENDLY_OFFSET;
286                 out->datalen = fr->datalen;
287                 memcpy(out->data, fr->data, fr->datalen);
288         }
289         out->mallocd = AST_MALLOCD_HDR | AST_MALLOCD_SRC | AST_MALLOCD_DATA;
290         return out;
291 }
292
293 struct ast_frame *ast_frdup(struct ast_frame *f)
294 {
295         struct ast_frame *out;
296         int len, srclen = 0;
297         void *buf;
298         /* Start with standard stuff */
299         len = sizeof(struct ast_frame) + AST_FRIENDLY_OFFSET + f->datalen;
300         /* If we have a source, add space for it */
301         if (f->src)
302                 srclen = strlen(f->src);
303         if (srclen > 0)
304                 len += srclen + 1;
305         buf = malloc(len);
306         if (!buf)
307                 return NULL;
308         out = buf;
309         /* Set us as having malloc'd header only, so it will eventually
310            get freed. */
311         out->frametype = f->frametype;
312         out->subclass = f->subclass;
313         out->datalen = f->datalen;
314         out->samples = f->samples;
315         out->delivery = f->delivery;
316         out->mallocd = AST_MALLOCD_HDR;
317         out->offset = AST_FRIENDLY_OFFSET;
318         out->data = buf + sizeof(struct ast_frame) + AST_FRIENDLY_OFFSET;
319         if (srclen > 0) {
320                 out->src = out->data + f->datalen;
321                 /* Must have space since we allocated for it */
322                 strcpy((char *)out->src, f->src);
323         } else
324                 out->src = NULL;
325         out->prev = NULL;
326         out->next = NULL;
327         memcpy(out->data, f->data, out->datalen);       
328         return out;
329 }
330
331 struct ast_frame *ast_fr_fdread(int fd)
332 {
333         char buf[65536];
334         int res;
335         int ttl = sizeof(struct ast_frame);
336         struct ast_frame *f = (struct ast_frame *)buf;
337         /* Read a frame directly from there.  They're always in the
338            right format. */
339         
340         while(ttl) {
341                 res = read(fd, buf, ttl);
342                 if (res < 0) {
343                         ast_log(LOG_WARNING, "Bad read on %d: %s\n", fd, strerror(errno));
344                         return NULL;
345                 }
346                 ttl -= res;
347         }
348         
349         /* read the frame header */
350         f->mallocd = 0;
351         /* Re-write data position */
352         f->data = buf + sizeof(struct ast_frame);
353         f->offset = 0;
354         /* Forget about being mallocd */
355         f->mallocd = 0;
356         /* Re-write the source */
357         f->src = (char *)__FUNCTION__;
358         if (f->datalen > sizeof(buf) - sizeof(struct ast_frame)) {
359                 /* Really bad read */
360                 ast_log(LOG_WARNING, "Strange read (%d bytes)\n", f->datalen);
361                 return NULL;
362         }
363         if (f->datalen) {
364                 if ((res = read(fd, f->data, f->datalen)) != f->datalen) {
365                         /* Bad read */
366                         ast_log(LOG_WARNING, "How very strange, expected %d, got %d\n", f->datalen, res);
367                         return NULL;
368                 }
369         }
370         if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_HANGUP)) {
371                 return NULL;
372         }
373         return ast_frisolate(f);
374 }
375
376 /* Some convenient routines for sending frames to/from stream or datagram
377    sockets, pipes, etc (maybe even files) */
378
379 int ast_fr_fdwrite(int fd, struct ast_frame *frame)
380 {
381         /* Write the frame exactly */
382         if (write(fd, frame, sizeof(struct ast_frame)) != sizeof(struct ast_frame)) {
383                 ast_log(LOG_WARNING, "Write error: %s\n", strerror(errno));
384                 return -1;
385         }
386         if (write(fd, frame->data, frame->datalen) != frame->datalen) {
387                 ast_log(LOG_WARNING, "Write error: %s\n", strerror(errno));
388                 return -1;
389         }
390         return 0;
391 }
392
393 int ast_fr_fdhangup(int fd)
394 {
395         struct ast_frame hangup = {
396                 AST_FRAME_CONTROL,
397                 AST_CONTROL_HANGUP
398         };
399         return ast_fr_fdwrite(fd, &hangup);
400 }
401
402 static struct ast_format_list AST_FORMAT_LIST[] = {
403         { 1, AST_FORMAT_G723_1 , "g723" , "G.723.1"},
404         { 1, AST_FORMAT_GSM, "gsm" , "GSM"},
405         { 1, AST_FORMAT_ULAW, "ulaw", "G.711 u-law" },
406         { 1, AST_FORMAT_ALAW, "alaw", "G.711 A-law" },
407         { 1, AST_FORMAT_G726, "g726", "G.726" },
408         { 1, AST_FORMAT_ADPCM, "adpcm" , "ADPCM"},
409         { 1, AST_FORMAT_SLINEAR, "slin",  "16 bit Signed Linear PCM"},
410         { 1, AST_FORMAT_LPC10, "lpc10", "LPC10" },
411         { 1, AST_FORMAT_G729A, "g729", "G.729A" },
412         { 1, AST_FORMAT_SPEEX, "speex", "SpeeX" },
413         { 1, AST_FORMAT_ILBC, "ilbc", "iLBC"},
414         { 0, 0, "nothing", "undefined" },
415         { 0, 0, "nothing", "undefined" },
416         { 0, 0, "nothing", "undefined" },
417         { 0, 0, "nothing", "undefined" },
418         { 0, AST_FORMAT_MAX_AUDIO, "maxaudio", "Maximum audio format" },
419         { 1, AST_FORMAT_JPEG, "jpeg", "JPEG image"},
420         { 1, AST_FORMAT_PNG, "png", "PNG image"},
421         { 1, AST_FORMAT_H261, "h261", "H.261 Video" },
422         { 1, AST_FORMAT_H263, "h263", "H.263 Video" },
423         { 1, AST_FORMAT_H263_PLUS, "h263p", "H.263+ Video" },
424         { 0, 0, "nothing", "undefined" },
425         { 0, 0, "nothing", "undefined" },
426         { 0, 0, "nothing", "undefined" },
427         { 0, 0, "nothing", "undefined" },
428         { 0, AST_FORMAT_MAX_VIDEO, "maxvideo", "Maximum video format" },
429 };
430
431 struct ast_format_list *ast_get_format_list_index(int index) 
432 {
433         return &AST_FORMAT_LIST[index];
434 }
435
436 struct ast_format_list *ast_get_format_list(size_t *size) 
437 {
438         *size = (sizeof(AST_FORMAT_LIST) / sizeof(struct ast_format_list));
439         return AST_FORMAT_LIST;
440 }
441
442 char* ast_getformatname(int format)
443 {
444         int x = 0;
445         char *ret = "unknown";
446         for (x = 0 ; x < sizeof(AST_FORMAT_LIST) / sizeof(struct ast_format_list) ; x++) {
447                 if(AST_FORMAT_LIST[x].visible && AST_FORMAT_LIST[x].bits == format) {
448                         ret = AST_FORMAT_LIST[x].name;
449                         break;
450                 }
451         }
452         return ret;
453 }
454
455 char *ast_getformatname_multiple(char *buf, size_t size, int format) {
456
457         int x = 0;
458         unsigned len;
459         char *end = buf;
460         char *start = buf;
461         if (!size) return buf;
462         snprintf(end, size, "0x%x (", format);
463         len = strlen(end);
464         end += len;
465         size -= len;
466         start = end;
467         for (x = 0 ; x < sizeof(AST_FORMAT_LIST) / sizeof(struct ast_format_list) ; x++) {
468                 if (AST_FORMAT_LIST[x].visible && (AST_FORMAT_LIST[x].bits & format)) {
469                         snprintf(end, size,"%s|",AST_FORMAT_LIST[x].name);
470                         len = strlen(end);
471                         end += len;
472                         size -= len;
473                 }
474         }
475         if (start == end)
476                 snprintf(start, size, "nothing)");
477         else if (size > 1)
478                 *(end -1) = ')';
479         return buf;
480 }
481
482 static struct ast_codec_alias_table {
483         char *alias;
484         char *realname;
485
486 } ast_codec_alias_table[] = {
487         {"slinear","slin"},
488         {"g723.1","g723"},
489 };
490
491 static char *ast_expand_codec_alias(char *in) {
492         int x = 0;
493
494         for (x = 0; x < sizeof(ast_codec_alias_table) / sizeof(struct ast_codec_alias_table) ; x++) {
495                 if(!strcmp(in,ast_codec_alias_table[x].alias))
496                         return ast_codec_alias_table[x].realname;
497         }
498         return in;
499 }
500
501 int ast_getformatbyname(char *name)
502 {
503         int x = 0, all = 0, format = 0;
504
505         all = strcasecmp(name, "all") ? 0 : 1;
506         for (x = 0 ; x < sizeof(AST_FORMAT_LIST) / sizeof(struct ast_format_list) ; x++) {
507                 if(AST_FORMAT_LIST[x].visible && (all || 
508                                                                                   !strcasecmp(AST_FORMAT_LIST[x].name,name) ||
509                                                                                   !strcasecmp(AST_FORMAT_LIST[x].name,ast_expand_codec_alias(name)))) {
510                         format |= AST_FORMAT_LIST[x].bits;
511                         if(!all)
512                                 break;
513                 }
514         }
515
516         return format;
517 }
518
519 char *ast_codec2str(int codec) {
520         int x = 0;
521         char *ret = "unknown";
522         for (x = 0 ; x < sizeof(AST_FORMAT_LIST) / sizeof(struct ast_format_list) ; x++) {
523                 if(AST_FORMAT_LIST[x].visible && AST_FORMAT_LIST[x].bits == codec) {
524                         ret = AST_FORMAT_LIST[x].desc;
525                         break;
526                 }
527         }
528         return ret;
529 }
530
531 static int show_codecs(int fd, int argc, char *argv[])
532 {
533         int i, found=0;
534         char hex[25];
535         
536         if ((argc < 2) || (argc > 3))
537                 return RESULT_SHOWUSAGE;
538
539         if (getenv("I_AM_NOT_AN_IDIOT") == NULL)
540                 ast_cli(fd, "Disclaimer: this command is for informational purposes only.\n"
541                                 "\tIt does not indicate anything about your configuration.\n");
542
543         ast_cli(fd, "%11s %9s %10s   TYPE   %5s   %s\n","INT","BINARY","HEX","NAME","DESC");
544         ast_cli(fd, "--------------------------------------------------------------------------------\n");
545         if ((argc == 2) || (!strcasecmp(argv[1],"audio"))) {
546                 found = 1;
547                 for (i=0;i<11;i++) {
548                         snprintf(hex,25,"(0x%x)",1<<i);
549                         ast_cli(fd, "%11u (1 << %2d) %10s  audio   %5s   (%s)\n",1 << i,i,hex,ast_getformatname(1<<i),ast_codec2str(1<<i));
550                 }
551         }
552
553         if ((argc == 2) || (!strcasecmp(argv[1],"image"))) {
554                 found = 1;
555                 for (i=16;i<18;i++) {
556                         snprintf(hex,25,"(0x%x)",1<<i);
557                         ast_cli(fd, "%11u (1 << %2d) %10s  image   %5s   (%s)\n",1 << i,i,hex,ast_getformatname(1<<i),ast_codec2str(1<<i));
558                 }
559         }
560
561         if ((argc == 2) || (!strcasecmp(argv[1],"video"))) {
562                 found = 1;
563                 for (i=18;i<21;i++) {
564                         snprintf(hex,25,"(0x%x)",1<<i);
565                         ast_cli(fd, "%11u (1 << %2d) %10s  video   %5s   (%s)\n",1 << i,i,hex,ast_getformatname(1<<i),ast_codec2str(1<<i));
566                 }
567         }
568
569         if (! found)
570                 return RESULT_SHOWUSAGE;
571         else
572                 return RESULT_SUCCESS;
573 }
574
575 static char frame_show_codecs_usage[] =
576 "Usage: show [audio|video|image] codecs\n"
577 "       Displays codec mapping\n";
578
579 struct ast_cli_entry cli_show_codecs =
580 { { "show", "codecs", NULL }, show_codecs, "Shows codecs", frame_show_codecs_usage };
581 struct ast_cli_entry cli_show_codecs_audio =
582 { { "show", "audio", "codecs", NULL }, show_codecs, "Shows audio codecs", frame_show_codecs_usage };
583 struct ast_cli_entry cli_show_codecs_video =
584 { { "show", "video", "codecs", NULL }, show_codecs, "Shows video codecs", frame_show_codecs_usage };
585 struct ast_cli_entry cli_show_codecs_image =
586 { { "show", "image", "codecs", NULL }, show_codecs, "Shows image codecs", frame_show_codecs_usage };
587
588 static int show_codec_n(int fd, int argc, char *argv[])
589 {
590         int codec, i, found=0;
591
592         if (argc != 3)
593                 return RESULT_SHOWUSAGE;
594
595         if (sscanf(argv[2],"%d",&codec) != 1)
596                 return RESULT_SHOWUSAGE;
597
598         for (i=0;i<32;i++)
599                 if (codec & (1 << i)) {
600                         found = 1;
601                         ast_cli(fd, "%11u (1 << %2d)  %s\n",1 << i,i,ast_codec2str(1<<i));
602                 }
603
604         if (! found)
605                 ast_cli(fd, "Codec %d not found\n", codec);
606
607         return RESULT_SUCCESS;
608 }
609
610 static char frame_show_codec_n_usage[] =
611 "Usage: show codec <number>\n"
612 "       Displays codec mapping\n";
613
614 struct ast_cli_entry cli_show_codec_n =
615 { { "show", "codec", NULL }, show_codec_n, "Shows a specific codec", frame_show_codec_n_usage };
616
617 void ast_frame_dump(char *name, struct ast_frame *f, char *prefix)
618 {
619         char *n = "unknown";
620         char ftype[40] = "Unknown Frametype";
621         char cft[80];
622         char subclass[40] = "Unknown Subclass";
623         char csub[80];
624         char moreinfo[40] = "";
625         char cn[60];
626         char cp[40];
627         char cmn[40];
628         if (name)
629                 n = name;
630         if (!f) {
631                 ast_verbose("%s [ %s (NULL) ] [%s]\n", 
632                         term_color(cp, prefix, COLOR_BRMAGENTA, COLOR_BLACK, sizeof(cp)),
633                         term_color(cft, "HANGUP", COLOR_BRRED, COLOR_BLACK, sizeof(cft)), 
634                         term_color(cn, n, COLOR_YELLOW, COLOR_BLACK, sizeof(cn)));
635                 return;
636         }
637         /* XXX We should probably print one each of voice and video when the format changes XXX */
638         if (f->frametype == AST_FRAME_VOICE)
639                 return;
640         if (f->frametype == AST_FRAME_VIDEO)
641                 return;
642         switch(f->frametype) {
643         case AST_FRAME_DTMF:
644                 strcpy(ftype, "DTMF");
645                 subclass[0] = f->subclass;
646                 subclass[1] = '\0';
647                 break;
648         case AST_FRAME_CONTROL:
649                 strcpy(ftype, "Control");
650                 switch(f->subclass) {
651                 case AST_CONTROL_HANGUP:
652                         strcpy(subclass, "Hangup");
653                         break;
654                 case AST_CONTROL_RING:
655                         strcpy(subclass, "Ring");
656                         break;
657                 case AST_CONTROL_RINGING:
658                         strcpy(subclass, "Ringing");
659                         break;
660                 case AST_CONTROL_ANSWER:
661                         strcpy(subclass, "Answer");
662                         break;
663                 case AST_CONTROL_BUSY:
664                         strcpy(subclass, "Busy");
665                         break;
666                 case AST_CONTROL_TAKEOFFHOOK:
667                         strcpy(subclass, "Take Off Hook");
668                         break;
669                 case AST_CONTROL_OFFHOOK:
670                         strcpy(subclass, "Line Off Hook");
671                         break;
672                 case AST_CONTROL_CONGESTION:
673                         strcpy(subclass, "Congestion");
674                         break;
675                 case AST_CONTROL_FLASH:
676                         strcpy(subclass, "Flash");
677                         break;
678                 case AST_CONTROL_WINK:
679                         strcpy(subclass, "Wink");
680                         break;
681                 case AST_CONTROL_OPTION:
682                         strcpy(subclass, "Option");
683                         break;
684                 case AST_CONTROL_RADIO_KEY:
685                         strcpy(subclass, "Key Radio");
686                         break;
687                 case AST_CONTROL_RADIO_UNKEY:
688                         strcpy(subclass, "Unkey Radio");
689                         break;
690                 case -1:
691                         strcpy(subclass, "Stop generators");
692                         break;
693                 default:
694                         snprintf(subclass, sizeof(subclass), "Unknown control '%d'", f->subclass);
695                 }
696                 break;
697         case AST_FRAME_NULL:
698                 strcpy(ftype, "Null Frame");
699                 strcpy(subclass, "N/A");
700                 break;
701         case AST_FRAME_IAX:
702                 /* Should never happen */
703                 strcpy(ftype, "IAX Specific");
704                 snprintf(subclass, sizeof(subclass), "IAX Frametype %d", f->subclass);
705                 break;
706         case AST_FRAME_TEXT:
707                 strcpy(ftype, "Text");
708                 strcpy(subclass, "N/A");
709                 strncpy(moreinfo, f->data, sizeof(moreinfo) - 1);
710                 break;
711         case AST_FRAME_IMAGE:
712                 strcpy(ftype, "Image");
713                 snprintf(subclass, sizeof(subclass), "Image format %s\n", ast_getformatname(f->subclass));
714                 break;
715         case AST_FRAME_HTML:
716                 strcpy(ftype, "HTML");
717                 switch(f->subclass) {
718                 case AST_HTML_URL:
719                         strcpy(subclass, "URL");
720                         strncpy(moreinfo, f->data, sizeof(moreinfo) - 1);
721                         break;
722                 case AST_HTML_DATA:
723                         strcpy(subclass, "Data");
724                         break;
725                 case AST_HTML_BEGIN:
726                         strcpy(subclass, "Begin");
727                         break;
728                 case AST_HTML_END:
729                         strcpy(subclass, "End");
730                         break;
731                 case AST_HTML_LDCOMPLETE:
732                         strcpy(subclass, "Load Complete");
733                         break;
734                 case AST_HTML_NOSUPPORT:
735                         strcpy(subclass, "No Support");
736                         break;
737                 case AST_HTML_LINKURL:
738                         strcpy(subclass, "Link URL");
739                         strncpy(moreinfo, f->data, sizeof(moreinfo) - 1);
740                         break;
741                 case AST_HTML_UNLINK:
742                         strcpy(subclass, "Unlink");
743                         break;
744                 case AST_HTML_LINKREJECT:
745                         strcpy(subclass, "Link Reject");
746                         break;
747                 default:
748                         snprintf(subclass, sizeof(subclass), "Unknown HTML frame '%d'\n", f->subclass);
749                         break;
750                 }
751                 break;
752         default:
753                 snprintf(ftype, sizeof(ftype), "Unknown Frametype '%d'", f->frametype);
754         }
755         if (!ast_strlen_zero(moreinfo))
756                 ast_verbose("%s [ TYPE: %s (%d) SUBCLASS: %s (%d) '%s' ] [%s]\n",  
757                         term_color(cp, prefix, COLOR_BRMAGENTA, COLOR_BLACK, sizeof(cp)),
758                         term_color(cft, ftype, COLOR_BRRED, COLOR_BLACK, sizeof(cft)),
759                         f->frametype, 
760                         term_color(csub, subclass, COLOR_BRCYAN, COLOR_BLACK, sizeof(csub)),
761                         f->subclass, 
762                         term_color(cmn, moreinfo, COLOR_BRGREEN, COLOR_BLACK, sizeof(cmn)),
763                         term_color(cn, n, COLOR_YELLOW, COLOR_BLACK, sizeof(cn)));
764         else
765                 ast_verbose("%s [ TYPE: %s (%d) SUBCLASS: %s (%d) ] [%s]\n",  
766                         term_color(cp, prefix, COLOR_BRMAGENTA, COLOR_BLACK, sizeof(cp)),
767                         term_color(cft, ftype, COLOR_BRRED, COLOR_BLACK, sizeof(cft)),
768                         f->frametype, 
769                         term_color(csub, subclass, COLOR_BRCYAN, COLOR_BLACK, sizeof(csub)),
770                         f->subclass, 
771                         term_color(cn, n, COLOR_YELLOW, COLOR_BLACK, sizeof(cn)));
772
773 }
774
775
776 #ifdef TRACE_FRAMES
777 static int show_frame_stats(int fd, int argc, char *argv[])
778 {
779         struct ast_frame *f;
780         int x=1;
781         if (argc != 3)
782                 return RESULT_SHOWUSAGE;
783         ast_cli(fd, "     Framer Statistics     \n");
784         ast_cli(fd, "---------------------------\n");
785         ast_cli(fd, "Total allocated headers: %d\n", headers);
786         ast_cli(fd, "Queue Dump:\n");
787         ast_mutex_lock(&framelock);
788         for (f=headerlist; f; f = f->next) {
789                 ast_cli(fd, "%d.  Type %d, subclass %d from %s\n", x++, f->frametype, f->subclass, f->src ? f->src : "<Unknown>");
790         }
791         ast_mutex_unlock(&framelock);
792         return RESULT_SUCCESS;
793 }
794
795 static char frame_stats_usage[] =
796 "Usage: show frame stats\n"
797 "       Displays debugging statistics from framer\n";
798
799 struct ast_cli_entry cli_frame_stats =
800 { { "show", "frame", "stats", NULL }, show_frame_stats, "Shows frame statistics", frame_stats_usage };
801 #endif
802
803 int init_framer(void)
804 {
805 #ifdef TRACE_FRAMES
806         ast_cli_register(&cli_frame_stats);
807 #endif
808         ast_cli_register(&cli_show_codecs);
809         ast_cli_register(&cli_show_codecs_audio);
810         ast_cli_register(&cli_show_codecs_video);
811         ast_cli_register(&cli_show_codecs_image);
812         ast_cli_register(&cli_show_codec_n);
813         return 0;       
814 }
815
816 void ast_codec_pref_convert(struct ast_codec_pref *pref, char *buf, size_t size, int right) 
817 {
818         int x = 0, differential = (int) 'A', mem = 0;
819         char *from = NULL, *to = NULL;
820
821         if(right) {
822                 from = pref->order;
823                 to = buf;
824                 mem = size;
825         } else {
826                 to = pref->order;
827                 from = buf;
828                 mem = 32;
829         }
830
831         memset(to, 0, mem);
832         for (x = 0; x < 32 ; x++) {
833                 if(!from[x])
834                         break;
835                 to[x] = right ? (from[x] + differential) : (from[x] - differential);
836         }
837 }
838
839 int ast_codec_pref_string(struct ast_codec_pref *pref, char *buf, size_t size) 
840 {
841         int x = 0, codec = 0; 
842         size_t total_len = 0, slen = 0;
843         char *formatname = 0;
844         
845         memset(buf,0,size);
846         total_len = size;
847         buf[0] = '(';
848         total_len--;
849         for(x = 0; x < 32 ; x++) {
850                 if(total_len <= 0)
851                         break;
852                 if(!(codec = ast_codec_pref_index(pref,x)))
853                         break;
854                 if((formatname = ast_getformatname(codec))) {
855                         slen = strlen(formatname);
856                         if(slen > total_len)
857                                 break;
858                         strncat(buf,formatname,total_len);
859                         total_len -= slen;
860                 }
861                 if(total_len && x < 31 && ast_codec_pref_index(pref , x + 1)) {
862                         strncat(buf,"|",total_len);
863                         total_len--;
864                 }
865         }
866         if(total_len) {
867                 strncat(buf,")",total_len);
868                 total_len--;
869         }
870
871         return size - total_len;
872 }
873
874 int ast_codec_pref_index(struct ast_codec_pref *pref, int index) 
875 {
876         int slot = 0;
877
878         
879         if((index >= 0) && (index < sizeof(pref->order))) {
880                 slot = pref->order[index];
881         }
882
883         return slot ? AST_FORMAT_LIST[slot-1].bits : 0;
884 }
885
886 /*--- ast_codec_pref_remove: Remove codec from pref list ---*/
887 void ast_codec_pref_remove(struct ast_codec_pref *pref, int format)
888 {
889         struct ast_codec_pref oldorder;
890         int x=0, y=0;
891         size_t size = 0;
892         int slot = 0;
893
894         if(!pref->order[0])
895                 return;
896
897         size = sizeof(AST_FORMAT_LIST) / sizeof(struct ast_format_list);
898
899         memcpy(&oldorder,pref,sizeof(struct ast_codec_pref));
900         memset(pref,0,sizeof(struct ast_codec_pref));
901
902         for (x = 0; x < size; x++) {
903                 slot = oldorder.order[x];
904                 if(! slot)
905                         break;
906                 if(AST_FORMAT_LIST[slot-1].bits != format)
907                         pref->order[y++] = slot;
908         }
909         
910 }
911
912 /*--- ast_codec_pref_append: Append codec to list ---*/
913 int ast_codec_pref_append(struct ast_codec_pref *pref, int format)
914 {
915         size_t size = 0;
916         int x = 0, newindex = -1;
917
918         ast_codec_pref_remove(pref, format);
919         size = sizeof(AST_FORMAT_LIST) / sizeof(struct ast_format_list);
920
921         for (x = 0; x < size; x++) {
922                 if(AST_FORMAT_LIST[x].bits == format) {
923                         newindex = x + 1;
924                         break;
925                 }
926         }
927
928         if(newindex) {
929                 for (x = 0; x < size; x++) {
930                         if(!pref->order[x]) {
931                                 pref->order[x] = newindex;
932                                 break;
933                         }
934                 }
935         }
936
937         return x;
938 }
939
940
941 /*--- sip_codec_choose: Pick a codec ---*/
942 int ast_codec_choose(struct ast_codec_pref *pref, int formats, int find_best)
943 {
944         size_t size = 0;
945         int x = 0, ret = 0, slot = 0;
946
947         size = sizeof(AST_FORMAT_LIST) / sizeof(struct ast_format_list);
948         for (x = 0; x < size; x++) {
949                 slot = pref->order[x];
950
951                 if(!slot)
952                         break;
953                 if ( formats & AST_FORMAT_LIST[slot-1].bits ) {
954                         ret = AST_FORMAT_LIST[slot-1].bits;
955                         break;
956                 }
957         }
958         if(ret)
959                 return ret;
960
961         return find_best ? ast_best_codec(formats) : 0;
962 }
963
964 void ast_parse_allow_disallow(struct ast_codec_pref *pref, int *mask, char *list, int allowing) 
965 {
966         int format_i = 0;
967         char *next_format = NULL, *last_format = NULL;
968
969         last_format = ast_strdupa(list);
970         while(last_format) {
971                 if((next_format = strchr(last_format, ','))) {
972                         *next_format = '\0';
973                         next_format++;
974                 }
975                 if ((format_i = ast_getformatbyname(last_format)) > 0) {
976                         if (mask) {
977                                 if (allowing)
978                                         (*mask) |= format_i;
979                                 else
980                                         (*mask) &= ~format_i;
981                         }
982                         /* can't consider 'all' a prefered codec*/
983                         if(pref && strcasecmp(last_format, "all")) {
984                                 if(allowing)
985                                         ast_codec_pref_append(pref, format_i);
986                                 else
987                                         ast_codec_pref_remove(pref, format_i);
988                         } else if(!allowing) /* disallow all must clear your prefs or it makes no sense */
989                                 memset(pref, 0, sizeof(struct ast_codec_pref));
990                 } else
991                         ast_log(LOG_WARNING, "Cannot %s unknown format '%s'\n", allowing ? "allow" : "disallow", last_format);
992
993                 last_format = next_format;
994         }
995 }
996
997