Fix chan_phone error code (bug #3692)
[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(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(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         { 0, 0, "nothing", "undefined" },
424         { 0, 0, "nothing", "undefined" },
425         { 0, 0, "nothing", "undefined" },
426         { 0, 0, "nothing", "undefined" },
427         { 0, AST_FORMAT_MAX_VIDEO, "maxvideo", "Maximum video format" },
428 };
429
430 struct ast_format_list *ast_get_format_list_index(int index) 
431 {
432         return &AST_FORMAT_LIST[index];
433 }
434
435 struct ast_format_list *ast_get_format_list(size_t *size) 
436 {
437         *size = (sizeof(AST_FORMAT_LIST) / sizeof(struct ast_format_list));
438         return AST_FORMAT_LIST;
439 }
440
441 char* ast_getformatname(int format)
442 {
443         int x = 0;
444         char *ret = "unknown";
445         for (x = 0 ; x < sizeof(AST_FORMAT_LIST) / sizeof(struct ast_format_list) ; x++) {
446                 if(AST_FORMAT_LIST[x].visible && AST_FORMAT_LIST[x].bits == format) {
447                         ret = AST_FORMAT_LIST[x].name;
448                         break;
449                 }
450         }
451         return ret;
452 }
453
454 char *ast_getformatname_multiple(char *buf, size_t size, int format) {
455
456         int x = 0;
457         unsigned len;
458         char *end = buf;
459         char *start = buf;
460         if (!size) return buf;
461         snprintf(end, size, "0x%x (", format);
462         len = strlen(end);
463         end += len;
464         size -= len;
465         start = end;
466         for (x = 0 ; x < sizeof(AST_FORMAT_LIST) / sizeof(struct ast_format_list) ; x++) {
467                 if (AST_FORMAT_LIST[x].visible && (AST_FORMAT_LIST[x].bits & format)) {
468                         snprintf(end, size,"%s|",AST_FORMAT_LIST[x].name);
469                         len = strlen(end);
470                         end += len;
471                         size -= len;
472                 }
473         }
474         if (start == end)
475                 snprintf(start, size, "nothing)");
476         else if (size > 1)
477                 *(end -1) = ')';
478         return buf;
479 }
480
481 static struct ast_codec_alias_table {
482         char *alias;
483         char *realname;
484
485 } ast_codec_alias_table[] = {
486         {"slinear","slin"},
487         {"g723.1","g723"},
488 };
489
490 static char *ast_expand_codec_alias(char *in) {
491         int x = 0;
492
493         for (x = 0; x < sizeof(ast_codec_alias_table) / sizeof(struct ast_codec_alias_table) ; x++) {
494                 if(!strcmp(in,ast_codec_alias_table[x].alias))
495                         return ast_codec_alias_table[x].realname;
496         }
497         return in;
498 }
499
500 int ast_getformatbyname(char *name)
501 {
502         int x = 0, all = 0, format = 0;
503
504         all = strcasecmp(name, "all") ? 0 : 1;
505         for (x = 0 ; x < sizeof(AST_FORMAT_LIST) / sizeof(struct ast_format_list) ; x++) {
506                 if(AST_FORMAT_LIST[x].visible && (all || 
507                                                                                   !strcasecmp(AST_FORMAT_LIST[x].name,name) ||
508                                                                                   !strcasecmp(AST_FORMAT_LIST[x].name,ast_expand_codec_alias(name)))) {
509                         format |= AST_FORMAT_LIST[x].bits;
510                         if(!all)
511                                 break;
512                 }
513         }
514
515         return format;
516 }
517
518 char *ast_codec2str(int codec) {
519         int x = 0;
520         char *ret = "unknown";
521         for (x = 0 ; x < sizeof(AST_FORMAT_LIST) / sizeof(struct ast_format_list) ; x++) {
522                 if(AST_FORMAT_LIST[x].visible && AST_FORMAT_LIST[x].bits == codec) {
523                         ret = AST_FORMAT_LIST[x].desc;
524                         break;
525                 }
526         }
527         return ret;
528 }
529
530 static int show_codecs(int fd, int argc, char *argv[])
531 {
532         int i, found=0;
533         char hex[25];
534         
535         if ((argc < 2) || (argc > 3))
536                 return RESULT_SHOWUSAGE;
537
538         if (getenv("I_AM_NOT_AN_IDIOT") == NULL)
539                 ast_cli(fd, "Disclaimer: this command is for informational purposes only.\n"
540                                 "\tIt does not indicate anything about your configuration.\n");
541
542         ast_cli(fd, "%11s %9s %10s   TYPE   %5s   %s\n","INT","BINARY","HEX","NAME","DESC");
543         ast_cli(fd, "--------------------------------------------------------------------------------\n");
544         if ((argc == 2) || (!strcasecmp(argv[1],"audio"))) {
545                 found = 1;
546                 for (i=0;i<11;i++) {
547                         snprintf(hex,25,"(0x%x)",1<<i);
548                         ast_cli(fd, "%11u (1 << %2d) %10s  audio   %5s   (%s)\n",1 << i,i,hex,ast_getformatname(1<<i),ast_codec2str(1<<i));
549                 }
550         }
551
552         if ((argc == 2) || (!strcasecmp(argv[1],"image"))) {
553                 found = 1;
554                 for (i=16;i<18;i++) {
555                         snprintf(hex,25,"(0x%x)",1<<i);
556                         ast_cli(fd, "%11u (1 << %2d) %10s  image   %5s   (%s)\n",1 << i,i,hex,ast_getformatname(1<<i),ast_codec2str(1<<i));
557                 }
558         }
559
560         if ((argc == 2) || (!strcasecmp(argv[1],"video"))) {
561                 found = 1;
562                 for (i=18;i<20;i++) {
563                         snprintf(hex,25,"(0x%x)",1<<i);
564                         ast_cli(fd, "%11u (1 << %2d) %10s  video   %5s   (%s)\n",1 << i,i,hex,ast_getformatname(1<<i),ast_codec2str(1<<i));
565                 }
566         }
567
568         if (! found)
569                 return RESULT_SHOWUSAGE;
570         else
571                 return RESULT_SUCCESS;
572 }
573
574 static char frame_show_codecs_usage[] =
575 "Usage: show [audio|video|image] codecs\n"
576 "       Displays codec mapping\n";
577
578 struct ast_cli_entry cli_show_codecs =
579 { { "show", "codecs", NULL }, show_codecs, "Shows codecs", frame_show_codecs_usage };
580 struct ast_cli_entry cli_show_codecs_audio =
581 { { "show", "audio", "codecs", NULL }, show_codecs, "Shows audio codecs", frame_show_codecs_usage };
582 struct ast_cli_entry cli_show_codecs_video =
583 { { "show", "video", "codecs", NULL }, show_codecs, "Shows video codecs", frame_show_codecs_usage };
584 struct ast_cli_entry cli_show_codecs_image =
585 { { "show", "image", "codecs", NULL }, show_codecs, "Shows image codecs", frame_show_codecs_usage };
586
587 static int show_codec_n(int fd, int argc, char *argv[])
588 {
589         int codec, i, found=0;
590
591         if (argc != 3)
592                 return RESULT_SHOWUSAGE;
593
594         if (sscanf(argv[2],"%d",&codec) != 1)
595                 return RESULT_SHOWUSAGE;
596
597         for (i=0;i<32;i++)
598                 if (codec & (1 << i)) {
599                         found = 1;
600                         ast_cli(fd, "%11u (1 << %2d)  %s\n",1 << i,i,ast_codec2str(1<<i));
601                 }
602
603         if (! found)
604                 ast_cli(fd, "Codec %d not found\n", codec);
605
606         return RESULT_SUCCESS;
607 }
608
609 static char frame_show_codec_n_usage[] =
610 "Usage: show codec <number>\n"
611 "       Displays codec mapping\n";
612
613 struct ast_cli_entry cli_show_codec_n =
614 { { "show", "codec", NULL }, show_codec_n, "Shows a specific codec", frame_show_codec_n_usage };
615
616 void ast_frame_dump(char *name, struct ast_frame *f, char *prefix)
617 {
618         char *n = "unknown";
619         char ftype[40] = "Unknown Frametype";
620         char cft[80];
621         char subclass[40] = "Unknown Subclass";
622         char csub[80];
623         char moreinfo[40] = "";
624         char cn[60];
625         char cp[40];
626         char cmn[40];
627         if (name)
628                 n = name;
629         if (!f) {
630                 ast_verbose("%s [ %s (NULL) ] [%s]\n", 
631                         term_color(cp, prefix, COLOR_BRMAGENTA, COLOR_BLACK, sizeof(cp)),
632                         term_color(cft, "HANGUP", COLOR_BRRED, COLOR_BLACK, sizeof(cft)), 
633                         term_color(cn, n, COLOR_YELLOW, COLOR_BLACK, sizeof(cn)));
634                 return;
635         }
636         /* XXX We should probably print one each of voice and video when the format changes XXX */
637         if (f->frametype == AST_FRAME_VOICE)
638                 return;
639         if (f->frametype == AST_FRAME_VIDEO)
640                 return;
641         switch(f->frametype) {
642         case AST_FRAME_DTMF:
643                 strcpy(ftype, "DTMF");
644                 subclass[0] = f->subclass;
645                 subclass[1] = '\0';
646                 break;
647         case AST_FRAME_CONTROL:
648                 strcpy(ftype, "Control");
649                 switch(f->subclass) {
650                 case AST_CONTROL_HANGUP:
651                         strcpy(subclass, "Hangup");
652                         break;
653                 case AST_CONTROL_RING:
654                         strcpy(subclass, "Ring");
655                         break;
656                 case AST_CONTROL_RINGING:
657                         strcpy(subclass, "Ringing");
658                         break;
659                 case AST_CONTROL_ANSWER:
660                         strcpy(subclass, "Answer");
661                         break;
662                 case AST_CONTROL_BUSY:
663                         strcpy(subclass, "Busy");
664                         break;
665                 case AST_CONTROL_TAKEOFFHOOK:
666                         strcpy(subclass, "Take Off Hook");
667                         break;
668                 case AST_CONTROL_OFFHOOK:
669                         strcpy(subclass, "Line Off Hook");
670                         break;
671                 case AST_CONTROL_CONGESTION:
672                         strcpy(subclass, "Congestion");
673                         break;
674                 case AST_CONTROL_FLASH:
675                         strcpy(subclass, "Flash");
676                         break;
677                 case AST_CONTROL_WINK:
678                         strcpy(subclass, "Wink");
679                         break;
680                 case AST_CONTROL_OPTION:
681                         strcpy(subclass, "Option");
682                         break;
683                 case AST_CONTROL_RADIO_KEY:
684                         strcpy(subclass, "Key Radio");
685                         break;
686                 case AST_CONTROL_RADIO_UNKEY:
687                         strcpy(subclass, "Unkey Radio");
688                         break;
689                 case -1:
690                         strcpy(subclass, "Stop generators");
691                         break;
692                 default:
693                         snprintf(subclass, sizeof(subclass), "Unknown control '%d'", f->subclass);
694                 }
695                 break;
696         case AST_FRAME_NULL:
697                 strcpy(ftype, "Null Frame");
698                 strcpy(subclass, "N/A");
699                 break;
700         case AST_FRAME_IAX:
701                 /* Should never happen */
702                 strcpy(ftype, "IAX Specific");
703                 snprintf(subclass, sizeof(subclass), "IAX Frametype %d", f->subclass);
704                 break;
705         case AST_FRAME_TEXT:
706                 strcpy(ftype, "Text");
707                 strcpy(subclass, "N/A");
708                 strncpy(moreinfo, f->data, sizeof(moreinfo) - 1);
709                 break;
710         case AST_FRAME_IMAGE:
711                 strcpy(ftype, "Image");
712                 snprintf(subclass, sizeof(subclass), "Image format %s\n", ast_getformatname(f->subclass));
713                 break;
714         case AST_FRAME_HTML:
715                 strcpy(ftype, "HTML");
716                 switch(f->subclass) {
717                 case AST_HTML_URL:
718                         strcpy(subclass, "URL");
719                         strncpy(moreinfo, f->data, sizeof(moreinfo) - 1);
720                         break;
721                 case AST_HTML_DATA:
722                         strcpy(subclass, "Data");
723                         break;
724                 case AST_HTML_BEGIN:
725                         strcpy(subclass, "Begin");
726                         break;
727                 case AST_HTML_END:
728                         strcpy(subclass, "End");
729                         break;
730                 case AST_HTML_LDCOMPLETE:
731                         strcpy(subclass, "Load Complete");
732                         break;
733                 case AST_HTML_NOSUPPORT:
734                         strcpy(subclass, "No Support");
735                         break;
736                 case AST_HTML_LINKURL:
737                         strcpy(subclass, "Link URL");
738                         strncpy(moreinfo, f->data, sizeof(moreinfo) - 1);
739                         break;
740                 case AST_HTML_UNLINK:
741                         strcpy(subclass, "Unlink");
742                         break;
743                 case AST_HTML_LINKREJECT:
744                         strcpy(subclass, "Link Reject");
745                         break;
746                 default:
747                         snprintf(subclass, sizeof(subclass), "Unknown HTML frame '%d'\n", f->subclass);
748                         break;
749                 }
750                 break;
751         default:
752                 snprintf(ftype, sizeof(ftype), "Unknown Frametype '%d'", f->frametype);
753         }
754         if (!ast_strlen_zero(moreinfo))
755                 ast_verbose("%s [ TYPE: %s (%d) SUBCLASS: %s (%d) '%s' ] [%s]\n",  
756                         term_color(cp, prefix, COLOR_BRMAGENTA, COLOR_BLACK, sizeof(cp)),
757                         term_color(cft, ftype, COLOR_BRRED, COLOR_BLACK, sizeof(cft)),
758                         f->frametype, 
759                         term_color(csub, subclass, COLOR_BRCYAN, COLOR_BLACK, sizeof(csub)),
760                         f->subclass, 
761                         term_color(cmn, moreinfo, COLOR_BRGREEN, COLOR_BLACK, sizeof(cmn)),
762                         term_color(cn, n, COLOR_YELLOW, COLOR_BLACK, sizeof(cn)));
763         else
764                 ast_verbose("%s [ TYPE: %s (%d) SUBCLASS: %s (%d) ] [%s]\n",  
765                         term_color(cp, prefix, COLOR_BRMAGENTA, COLOR_BLACK, sizeof(cp)),
766                         term_color(cft, ftype, COLOR_BRRED, COLOR_BLACK, sizeof(cft)),
767                         f->frametype, 
768                         term_color(csub, subclass, COLOR_BRCYAN, COLOR_BLACK, sizeof(csub)),
769                         f->subclass, 
770                         term_color(cn, n, COLOR_YELLOW, COLOR_BLACK, sizeof(cn)));
771
772 }
773
774
775 #ifdef TRACE_FRAMES
776 static int show_frame_stats(int fd, int argc, char *argv[])
777 {
778         struct ast_frame *f;
779         int x=1;
780         if (argc != 3)
781                 return RESULT_SHOWUSAGE;
782         ast_cli(fd, "     Framer Statistics     \n");
783         ast_cli(fd, "---------------------------\n");
784         ast_cli(fd, "Total allocated headers: %d\n", headers);
785         ast_cli(fd, "Queue Dump:\n");
786         ast_mutex_lock(&framelock);
787         for (f=headerlist; f; f = f->next) {
788                 ast_cli(fd, "%d.  Type %d, subclass %d from %s\n", x++, f->frametype, f->subclass, f->src ? f->src : "<Unknown>");
789         }
790         ast_mutex_unlock(&framelock);
791         return RESULT_SUCCESS;
792 }
793
794 static char frame_stats_usage[] =
795 "Usage: show frame stats\n"
796 "       Displays debugging statistics from framer\n";
797
798 struct ast_cli_entry cli_frame_stats =
799 { { "show", "frame", "stats", NULL }, show_frame_stats, "Shows frame statistics", frame_stats_usage };
800 #endif
801
802 int init_framer(void)
803 {
804 #ifdef TRACE_FRAMES
805         ast_cli_register(&cli_frame_stats);
806 #endif
807         ast_cli_register(&cli_show_codecs);
808         ast_cli_register(&cli_show_codecs_audio);
809         ast_cli_register(&cli_show_codecs_video);
810         ast_cli_register(&cli_show_codecs_image);
811         ast_cli_register(&cli_show_codec_n);
812         return 0;       
813 }
814
815 void ast_codec_pref_convert(struct ast_codec_pref *pref, char *buf, size_t size, int right) 
816 {
817         int x = 0, differential = (int) 'A', mem = 0;
818         char *from = NULL, *to = NULL;
819
820         if(right) {
821                 from = pref->order;
822                 to = buf;
823                 mem = size;
824         } else {
825                 to = pref->order;
826                 from = buf;
827                 mem = 32;
828         }
829
830         memset(to, 0, mem);
831         for (x = 0; x < 32 ; x++) {
832                 if(!from[x])
833                         break;
834                 to[x] = right ? (from[x] + differential) : (from[x] - differential);
835         }
836 }
837
838 int ast_codec_pref_string(struct ast_codec_pref *pref, char *buf, size_t size) 
839 {
840         int x = 0, codec = 0; 
841         size_t total_len = 0, slen = 0;
842         char *formatname = 0;
843         
844         memset(buf,0,size);
845         total_len = size;
846         buf[0] = '(';
847         total_len--;
848         for(x = 0; x < 32 ; x++) {
849                 if(total_len <= 0)
850                         break;
851                 if(!(codec = ast_codec_pref_index(pref,x)))
852                         break;
853                 if((formatname = ast_getformatname(codec))) {
854                         slen = strlen(formatname);
855                         if(slen > total_len)
856                                 break;
857                         strncat(buf,formatname,total_len);
858                         total_len -= slen;
859                 }
860                 if(total_len && x < 31 && ast_codec_pref_index(pref , x + 1)) {
861                         strncat(buf,"|",total_len);
862                         total_len--;
863                 }
864         }
865         if(total_len) {
866                 strncat(buf,")",total_len);
867                 total_len--;
868         }
869
870         return size - total_len;
871 }
872
873 int ast_codec_pref_index(struct ast_codec_pref *pref, int index) 
874 {
875         int slot = 0;
876
877         
878         if((index >= 0) && (index < sizeof(pref->order))) {
879                 slot = pref->order[index];
880         }
881
882         return slot ? AST_FORMAT_LIST[slot-1].bits : 0;
883 }
884
885 /*--- ast_codec_pref_remove: Remove codec from pref list ---*/
886 void ast_codec_pref_remove(struct ast_codec_pref *pref, int format)
887 {
888         struct ast_codec_pref oldorder;
889         int x=0, y=0;
890         size_t size = 0;
891         int slot = 0;
892
893         if(!pref->order[0])
894                 return;
895
896         size = sizeof(AST_FORMAT_LIST) / sizeof(struct ast_format_list);
897
898         memcpy(&oldorder,pref,sizeof(struct ast_codec_pref));
899         memset(pref,0,sizeof(struct ast_codec_pref));
900
901         for (x = 0; x < size; x++) {
902                 slot = oldorder.order[x];
903                 if(! slot)
904                         break;
905                 if(AST_FORMAT_LIST[slot-1].bits != format)
906                         pref->order[y++] = slot;
907         }
908         
909 }
910
911 /*--- ast_codec_pref_append: Append codec to list ---*/
912 int ast_codec_pref_append(struct ast_codec_pref *pref, int format)
913 {
914         size_t size = 0;
915         int x = 0, newindex = -1;
916
917         ast_codec_pref_remove(pref, format);
918         size = sizeof(AST_FORMAT_LIST) / sizeof(struct ast_format_list);
919
920         for (x = 0; x < size; x++) {
921                 if(AST_FORMAT_LIST[x].bits == format) {
922                         newindex = x + 1;
923                         break;
924                 }
925         }
926
927         if(newindex) {
928                 for (x = 0; x < size; x++) {
929                         if(!pref->order[x]) {
930                                 pref->order[x] = newindex;
931                                 break;
932                         }
933                 }
934         }
935
936         return x;
937 }
938
939
940 /*--- sip_codec_choose: Pick a codec ---*/
941 int ast_codec_choose(struct ast_codec_pref *pref, int formats, int find_best)
942 {
943         size_t size = 0;
944         int x = 0, ret = 0, slot = 0;
945
946         size = sizeof(AST_FORMAT_LIST) / sizeof(struct ast_format_list);
947         for (x = 0; x < size; x++) {
948                 slot = pref->order[x];
949
950                 if(!slot)
951                         break;
952                 if ( formats & AST_FORMAT_LIST[slot-1].bits ) {
953                         ret = AST_FORMAT_LIST[slot-1].bits;
954                         break;
955                 }
956         }
957         if(ret)
958                 return ret;
959
960         return find_best ? ast_best_codec(formats) : 0;
961 }
962
963 void ast_parse_allow_disallow(struct ast_codec_pref *pref, int *mask, char *list, int allowing) 
964 {
965         int format_i = 0;
966         char *next_format = NULL, *last_format = NULL;
967
968         last_format = ast_strdupa(list);
969         while(last_format) {
970                 if((next_format = strchr(last_format, ','))) {
971                         *next_format = '\0';
972                         next_format++;
973                 }
974                 if ((format_i = ast_getformatbyname(last_format)) > 0) {
975                         if (mask) {
976                                 if (allowing)
977                                         (*mask) |= format_i;
978                                 else
979                                         (*mask) &= ~format_i;
980                         }
981                         /* can't consider 'all' a prefered codec*/
982                         if(pref && strcasecmp(last_format, "all")) {
983                                 if(allowing)
984                                         ast_codec_pref_append(pref, format_i);
985                                 else
986                                         ast_codec_pref_remove(pref, format_i);
987                         } else if(!allowing) /* disallow all must clear your prefs or it makes no sense */
988                                 memset(pref, 0, sizeof(struct ast_codec_pref));
989                 } else
990                         ast_log(LOG_WARNING, "Cannot %s unknown format '%s'\n", allowing ? "allow" : "disallow", last_format);
991
992                 last_format = next_format;
993         }
994 }
995
996