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