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