2 * Asterisk -- A telephony toolkit for Linux.
4 * Frame manipulation routines
6 * Copyright (C) 1999 - 2005, Digium, Inc.
8 * Mark Spencer <markster@digium.com>
10 * This program is free software, distributed under the terms of
11 * the GNU General Public License
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>
30 static int headers = 0;
31 static struct ast_frame *headerlist = NULL;
32 AST_MUTEX_DEFINE_STATIC(framelock);
35 #define SMOOTHER_SIZE 8000
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 */
48 int optimizablestream;
52 struct timeval delivery;
53 char data[SMOOTHER_SIZE];
54 char framedata[SMOOTHER_SIZE + AST_FRIENDLY_OFFSET];
55 struct ast_frame *opt;
59 void ast_smoother_reset(struct ast_smoother *s, int size)
61 memset(s, 0, sizeof(struct ast_smoother));
65 struct ast_smoother *ast_smoother_new(int size)
67 struct ast_smoother *s;
70 s = malloc(sizeof(struct ast_smoother));
72 ast_smoother_reset(s, size);
76 int ast_smoother_get_flags(struct ast_smoother *s)
81 void ast_smoother_set_flags(struct ast_smoother *s, int flags)
86 int __ast_smoother_feed(struct ast_smoother *s, struct ast_frame *f, int swap)
88 if (f->frametype != AST_FRAME_VOICE) {
89 ast_log(LOG_WARNING, "Huh? Can't smooth a non-voice frame!\n");
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);
99 if (s->len + f->datalen > SMOOTHER_SIZE) {
100 ast_log(LOG_WARNING, "Out of smoother space\n");
103 if (((f->datalen == s->size) || ((f->datalen < 10) && (s->flags & AST_SMOOTHER_FLAG_G729)))
104 && !s->opt && (f->offset >= AST_MIN_OFFSET)) {
106 /* Optimize by sending the frame we just got
107 on the next read, thus eliminating the douple
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 */
125 s->optimizablestream = 0;
126 if (s->flags & AST_SMOOTHER_FLAG_G729) {
128 ast_log(LOG_NOTICE, "Dropping extra frame of G.729 since we already have a VAD frame at the end\n");
133 ast_swapcopy_samples(s->data+s->len, f->data, f->samples);
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;
144 struct ast_frame *ast_smoother_read(struct ast_smoother *s)
146 struct ast_frame *opt;
148 /* IF we have an optimization frame, send it */
150 if (s->opt->offset < AST_FRIENDLY_OFFSET)
151 ast_log(LOG_WARNING, "Returning a frame of inappropriate offset (%d).",
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)))
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;
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;
177 memcpy(s->f.data, s->data, len);
179 /* Move remaining data to the front if applicable */
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;
198 void ast_smoother_free(struct ast_smoother *s)
203 static struct ast_frame *ast_frame_header_new(void)
206 f = malloc(sizeof(struct ast_frame));
208 memset(f, 0, sizeof(struct ast_frame));
213 ast_mutex_lock(&framelock);
214 f->next = headerlist;
216 headerlist->prev = f;
218 ast_mutex_unlock(&framelock);
225 * Important: I should be made more efficient. Frame headers should
226 * most definitely be cached
229 void ast_frfree(struct ast_frame *fr)
231 if (fr->mallocd & AST_MALLOCD_DATA) {
233 free(fr->data - fr->offset);
235 if (fr->mallocd & AST_MALLOCD_SRC) {
237 free((char *)fr->src);
239 if (fr->mallocd & AST_MALLOCD_HDR) {
242 ast_mutex_lock(&framelock);
244 fr->next->prev = fr->prev;
246 fr->prev->next = fr->next;
248 headerlist = fr->next;
249 ast_mutex_unlock(&framelock);
255 struct ast_frame *ast_frisolate(struct ast_frame *fr)
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();
262 ast_log(LOG_WARNING, "Out of memory\n");
265 out->frametype = fr->frametype;
266 out->subclass = fr->subclass;
268 out->samples = fr->samples;
275 if (!(fr->mallocd & AST_MALLOCD_SRC)) {
277 out->src = strdup(fr->src);
280 if (!(fr->mallocd & AST_MALLOCD_DATA)) {
281 out->data = malloc(fr->datalen + AST_FRIENDLY_OFFSET);
284 ast_log(LOG_WARNING, "Out of memory\n");
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);
292 out->mallocd = AST_MALLOCD_HDR | AST_MALLOCD_SRC | AST_MALLOCD_DATA;
296 struct ast_frame *ast_frdup(struct ast_frame *f)
298 struct ast_frame *out;
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 */
305 srclen = strlen(f->src);
312 /* Set us as having malloc'd header only, so it will eventually
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;
323 out->src = out->data + f->datalen;
324 /* Must have space since we allocated for it */
325 strcpy((char *)out->src, f->src);
330 memcpy(out->data, f->data, out->datalen);
334 struct ast_frame *ast_fr_fdread(int fd)
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
344 res = read(fd, buf, ttl);
346 ast_log(LOG_WARNING, "Bad read on %d: %s\n", fd, strerror(errno));
352 /* read the frame header */
354 /* Re-write data position */
355 f->data = buf + sizeof(struct ast_frame);
357 /* Forget about being mallocd */
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);
367 if ((res = read(fd, f->data, f->datalen)) != f->datalen) {
369 ast_log(LOG_WARNING, "How very strange, expected %d, got %d\n", f->datalen, res);
373 if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_HANGUP)) {
376 return ast_frisolate(f);
379 /* Some convenient routines for sending frames to/from stream or datagram
380 sockets, pipes, etc (maybe even files) */
382 int ast_fr_fdwrite(int fd, struct ast_frame *frame)
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));
389 if (write(fd, frame->data, frame->datalen) != frame->datalen) {
390 ast_log(LOG_WARNING, "Write error: %s\n", strerror(errno));
396 int ast_fr_fdhangup(int fd)
398 struct ast_frame hangup = {
402 return ast_fr_fdwrite(fd, &hangup);
405 void ast_swapcopy_samples(void *dst, const void *src, int samples)
408 unsigned short *dst_s = dst;
409 const unsigned short *src_s = src;
411 for (i=0; i<samples; i++)
412 dst_s[i] = (src_s[i]<<8) | (src_s[i]>>8);
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" },
444 struct ast_format_list *ast_get_format_list_index(int index)
446 return &AST_FORMAT_LIST[index];
449 struct ast_format_list *ast_get_format_list(size_t *size)
451 *size = (sizeof(AST_FORMAT_LIST) / sizeof(struct ast_format_list));
452 return AST_FORMAT_LIST;
455 char* ast_getformatname(int format)
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;
468 char *ast_getformatname_multiple(char *buf, size_t size, int format) {
474 if (!size) return buf;
475 snprintf(end, size, "0x%x (", format);
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);
489 snprintf(start, size, "nothing)");
495 static struct ast_codec_alias_table {
499 } ast_codec_alias_table[] = {
504 static char *ast_expand_codec_alias(char *in) {
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;
514 int ast_getformatbyname(char *name)
516 int x = 0, all = 0, format = 0;
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;
532 char *ast_codec2str(int codec) {
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;
544 static int show_codecs(int fd, int argc, char *argv[])
549 if ((argc < 2) || (argc > 3))
550 return RESULT_SHOWUSAGE;
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");
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"))) {
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));
566 if ((argc == 2) || (!strcasecmp(argv[1],"image"))) {
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));
574 if ((argc == 2) || (!strcasecmp(argv[1],"video"))) {
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));
583 return RESULT_SHOWUSAGE;
585 return RESULT_SUCCESS;
588 static char frame_show_codecs_usage[] =
589 "Usage: show [audio|video|image] codecs\n"
590 " Displays codec mapping\n";
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 };
601 static int show_codec_n(int fd, int argc, char *argv[])
603 int codec, i, found=0;
606 return RESULT_SHOWUSAGE;
608 if (sscanf(argv[2],"%d",&codec) != 1)
609 return RESULT_SHOWUSAGE;
612 if (codec & (1 << i)) {
614 ast_cli(fd, "%11u (1 << %2d) %s\n",1 << i,i,ast_codec2str(1<<i));
618 ast_cli(fd, "Codec %d not found\n", codec);
620 return RESULT_SUCCESS;
623 static char frame_show_codec_n_usage[] =
624 "Usage: show codec <number>\n"
625 " Displays codec mapping\n";
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 };
630 void ast_frame_dump(char *name, struct ast_frame *f, char *prefix)
633 char ftype[40] = "Unknown Frametype";
635 char subclass[40] = "Unknown Subclass";
637 char moreinfo[40] = "";
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)));
650 /* XXX We should probably print one each of voice and video when the format changes XXX */
651 if (f->frametype == AST_FRAME_VOICE)
653 if (f->frametype == AST_FRAME_VIDEO)
655 switch(f->frametype) {
657 strcpy(ftype, "DTMF");
658 subclass[0] = f->subclass;
661 case AST_FRAME_CONTROL:
662 strcpy(ftype, "Control");
663 switch(f->subclass) {
664 case AST_CONTROL_HANGUP:
665 strcpy(subclass, "Hangup");
667 case AST_CONTROL_RING:
668 strcpy(subclass, "Ring");
670 case AST_CONTROL_RINGING:
671 strcpy(subclass, "Ringing");
673 case AST_CONTROL_ANSWER:
674 strcpy(subclass, "Answer");
676 case AST_CONTROL_BUSY:
677 strcpy(subclass, "Busy");
679 case AST_CONTROL_TAKEOFFHOOK:
680 strcpy(subclass, "Take Off Hook");
682 case AST_CONTROL_OFFHOOK:
683 strcpy(subclass, "Line Off Hook");
685 case AST_CONTROL_CONGESTION:
686 strcpy(subclass, "Congestion");
688 case AST_CONTROL_FLASH:
689 strcpy(subclass, "Flash");
691 case AST_CONTROL_WINK:
692 strcpy(subclass, "Wink");
694 case AST_CONTROL_OPTION:
695 strcpy(subclass, "Option");
697 case AST_CONTROL_RADIO_KEY:
698 strcpy(subclass, "Key Radio");
700 case AST_CONTROL_RADIO_UNKEY:
701 strcpy(subclass, "Unkey Radio");
704 strcpy(subclass, "Stop generators");
707 snprintf(subclass, sizeof(subclass), "Unknown control '%d'", f->subclass);
711 strcpy(ftype, "Null Frame");
712 strcpy(subclass, "N/A");
715 /* Should never happen */
716 strcpy(ftype, "IAX Specific");
717 snprintf(subclass, sizeof(subclass), "IAX Frametype %d", f->subclass);
720 strcpy(ftype, "Text");
721 strcpy(subclass, "N/A");
722 strncpy(moreinfo, f->data, sizeof(moreinfo) - 1);
724 case AST_FRAME_IMAGE:
725 strcpy(ftype, "Image");
726 snprintf(subclass, sizeof(subclass), "Image format %s\n", ast_getformatname(f->subclass));
729 strcpy(ftype, "HTML");
730 switch(f->subclass) {
732 strcpy(subclass, "URL");
733 strncpy(moreinfo, f->data, sizeof(moreinfo) - 1);
736 strcpy(subclass, "Data");
739 strcpy(subclass, "Begin");
742 strcpy(subclass, "End");
744 case AST_HTML_LDCOMPLETE:
745 strcpy(subclass, "Load Complete");
747 case AST_HTML_NOSUPPORT:
748 strcpy(subclass, "No Support");
750 case AST_HTML_LINKURL:
751 strcpy(subclass, "Link URL");
752 strncpy(moreinfo, f->data, sizeof(moreinfo) - 1);
754 case AST_HTML_UNLINK:
755 strcpy(subclass, "Unlink");
757 case AST_HTML_LINKREJECT:
758 strcpy(subclass, "Link Reject");
761 snprintf(subclass, sizeof(subclass), "Unknown HTML frame '%d'\n", f->subclass);
766 snprintf(ftype, sizeof(ftype), "Unknown Frametype '%d'", f->frametype);
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)),
773 term_color(csub, subclass, COLOR_BRCYAN, COLOR_BLACK, sizeof(csub)),
775 term_color(cmn, moreinfo, COLOR_BRGREEN, COLOR_BLACK, sizeof(cmn)),
776 term_color(cn, n, COLOR_YELLOW, COLOR_BLACK, sizeof(cn)));
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)),
782 term_color(csub, subclass, COLOR_BRCYAN, COLOR_BLACK, sizeof(csub)),
784 term_color(cn, n, COLOR_YELLOW, COLOR_BLACK, sizeof(cn)));
790 static int show_frame_stats(int fd, int argc, char *argv[])
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>");
804 ast_mutex_unlock(&framelock);
805 return RESULT_SUCCESS;
808 static char frame_stats_usage[] =
809 "Usage: show frame stats\n"
810 " Displays debugging statistics from framer\n";
812 struct ast_cli_entry cli_frame_stats =
813 { { "show", "frame", "stats", NULL }, show_frame_stats, "Shows frame statistics", frame_stats_usage };
816 int init_framer(void)
819 ast_cli_register(&cli_frame_stats);
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);
829 void ast_codec_pref_convert(struct ast_codec_pref *pref, char *buf, size_t size, int right)
831 int x = 0, differential = (int) 'A', mem = 0;
832 char *from = NULL, *to = NULL;
845 for (x = 0; x < 32 ; x++) {
848 to[x] = right ? (from[x] + differential) : (from[x] - differential);
852 int ast_codec_pref_string(struct ast_codec_pref *pref, char *buf, size_t size)
854 int x = 0, codec = 0;
855 size_t total_len = 0, slen = 0;
856 char *formatname = 0;
862 for(x = 0; x < 32 ; x++) {
865 if(!(codec = ast_codec_pref_index(pref,x)))
867 if((formatname = ast_getformatname(codec))) {
868 slen = strlen(formatname);
871 strncat(buf,formatname,total_len);
874 if(total_len && x < 31 && ast_codec_pref_index(pref , x + 1)) {
875 strncat(buf,"|",total_len);
880 strncat(buf,")",total_len);
884 return size - total_len;
887 int ast_codec_pref_index(struct ast_codec_pref *pref, int index)
892 if((index >= 0) && (index < sizeof(pref->order))) {
893 slot = pref->order[index];
896 return slot ? AST_FORMAT_LIST[slot-1].bits : 0;
899 /*--- ast_codec_pref_remove: Remove codec from pref list ---*/
900 void ast_codec_pref_remove(struct ast_codec_pref *pref, int format)
902 struct ast_codec_pref oldorder;
910 size = sizeof(AST_FORMAT_LIST) / sizeof(struct ast_format_list);
912 memcpy(&oldorder,pref,sizeof(struct ast_codec_pref));
913 memset(pref,0,sizeof(struct ast_codec_pref));
915 for (x = 0; x < size; x++) {
916 slot = oldorder.order[x];
919 if(AST_FORMAT_LIST[slot-1].bits != format)
920 pref->order[y++] = slot;
925 /*--- ast_codec_pref_append: Append codec to list ---*/
926 int ast_codec_pref_append(struct ast_codec_pref *pref, int format)
929 int x = 0, newindex = -1;
931 ast_codec_pref_remove(pref, format);
932 size = sizeof(AST_FORMAT_LIST) / sizeof(struct ast_format_list);
934 for (x = 0; x < size; x++) {
935 if(AST_FORMAT_LIST[x].bits == format) {
942 for (x = 0; x < size; x++) {
943 if(!pref->order[x]) {
944 pref->order[x] = newindex;
954 /*--- sip_codec_choose: Pick a codec ---*/
955 int ast_codec_choose(struct ast_codec_pref *pref, int formats, int find_best)
958 int x = 0, ret = 0, slot = 0;
960 size = sizeof(AST_FORMAT_LIST) / sizeof(struct ast_format_list);
961 for (x = 0; x < size; x++) {
962 slot = pref->order[x];
966 if ( formats & AST_FORMAT_LIST[slot-1].bits ) {
967 ret = AST_FORMAT_LIST[slot-1].bits;
974 return find_best ? ast_best_codec(formats) : 0;
977 void ast_parse_allow_disallow(struct ast_codec_pref *pref, int *mask, char *list, int allowing)
980 char *next_format = NULL, *last_format = NULL;
982 last_format = ast_strdupa(list);
984 if((next_format = strchr(last_format, ','))) {
988 if ((format_i = ast_getformatbyname(last_format)) > 0) {
993 (*mask) &= ~format_i;
995 /* can't consider 'all' a prefered codec*/
996 if(pref && strcasecmp(last_format, "all")) {
998 ast_codec_pref_append(pref, format_i);
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));
1004 ast_log(LOG_WARNING, "Cannot %s unknown format '%s'\n", allowing ? "allow" : "disallow", last_format);
1006 last_format = next_format;