2 * Asterisk -- A telephony toolkit for Linux.
4 * Frame manipulation routines
6 * Copyright (C) 1999-2004, 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)
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");
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;
141 struct ast_frame *ast_smoother_read(struct ast_smoother *s)
143 struct ast_frame *opt;
145 /* IF we have an optimization frame, send it */
147 if (s->opt->offset < AST_FRIENDLY_OFFSET)
148 ast_log(LOG_WARNING, "Returning a frame of inappropriate offset (%d).",
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)))
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;
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;
174 memcpy(s->f.data, s->data, len);
176 /* Move remaining data to the front if applicable */
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;
195 void ast_smoother_free(struct ast_smoother *s)
200 static struct ast_frame *ast_frame_header_new(void)
203 f = malloc(sizeof(struct ast_frame));
205 memset(f, 0, sizeof(struct ast_frame));
210 ast_mutex_lock(&framelock);
211 f->next = headerlist;
213 headerlist->prev = f;
215 ast_mutex_unlock(&framelock);
222 * Important: I should be made more efficient. Frame headers should
223 * most definitely be cached
226 void ast_frfree(struct ast_frame *fr)
228 if (fr->mallocd & AST_MALLOCD_DATA) {
230 free(fr->data - fr->offset);
232 if (fr->mallocd & AST_MALLOCD_SRC) {
236 if (fr->mallocd & AST_MALLOCD_HDR) {
239 ast_mutex_lock(&framelock);
241 fr->next->prev = fr->prev;
243 fr->prev->next = fr->next;
245 headerlist = fr->next;
246 ast_mutex_unlock(&framelock);
252 struct ast_frame *ast_frisolate(struct ast_frame *fr)
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();
259 ast_log(LOG_WARNING, "Out of memory\n");
262 out->frametype = fr->frametype;
263 out->subclass = fr->subclass;
265 out->samples = fr->samples;
272 if (!(fr->mallocd & AST_MALLOCD_SRC)) {
274 out->src = strdup(fr->src);
277 if (!(fr->mallocd & AST_MALLOCD_DATA)) {
278 out->data = malloc(fr->datalen + AST_FRIENDLY_OFFSET);
281 ast_log(LOG_WARNING, "Out of memory\n");
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);
289 out->mallocd = AST_MALLOCD_HDR | AST_MALLOCD_SRC | AST_MALLOCD_DATA;
293 struct ast_frame *ast_frdup(struct ast_frame *f)
295 struct ast_frame *out;
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 */
302 srclen = strlen(f->src);
309 /* Set us as having malloc'd header only, so it will eventually
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;
320 out->src = out->data + f->datalen;
321 /* Must have space since we allocated for it */
322 strcpy(out->src, f->src);
327 memcpy(out->data, f->data, out->datalen);
331 struct ast_frame *ast_fr_fdread(int fd)
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
341 res = read(fd, buf, ttl);
343 ast_log(LOG_WARNING, "Bad read on %d: %s\n", fd, strerror(errno));
349 /* read the frame header */
351 /* Re-write data position */
352 f->data = buf + sizeof(struct ast_frame);
354 /* Forget about being mallocd */
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);
364 if ((res = read(fd, f->data, f->datalen)) != f->datalen) {
366 ast_log(LOG_WARNING, "How very strange, expected %d, got %d\n", f->datalen, res);
370 if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_HANGUP)) {
373 return ast_frisolate(f);
376 /* Some convenient routines for sending frames to/from stream or datagram
377 sockets, pipes, etc (maybe even files) */
379 int ast_fr_fdwrite(int fd, struct ast_frame *frame)
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));
386 if (write(fd, frame->data, frame->datalen) != frame->datalen) {
387 ast_log(LOG_WARNING, "Write error: %s\n", strerror(errno));
393 int ast_fr_fdhangup(int fd)
395 struct ast_frame hangup = {
399 return ast_fr_fdwrite(fd, &hangup);
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" },
430 struct ast_format_list *ast_get_format_list_index(int index) {
431 return &AST_FORMAT_LIST[index];
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;
439 char* ast_getformatname(int format)
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;
452 char *ast_getformatname_multiple(char *buf, size_t size, int format) {
458 if (!size) return buf;
459 snprintf(end, size, "0x%x (", format);
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);
473 snprintf(start, size, "nothing)");
479 static struct ast_codec_alias_table {
483 } ast_codec_alias_table[] = {
488 static char *ast_expand_codec_alias(char *in) {
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;
498 int ast_getformatbyname(char *name)
500 int x = 0, all = 0, format = 0;
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;
516 char *ast_codec2str(int codec) {
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;
528 static int show_codecs(int fd, int argc, char *argv[])
533 if ((argc < 2) || (argc > 3))
534 return RESULT_SHOWUSAGE;
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");
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"))) {
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));
550 if ((argc == 2) || (!strcasecmp(argv[1],"image"))) {
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));
558 if ((argc == 2) || (!strcasecmp(argv[1],"video"))) {
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));
567 return RESULT_SHOWUSAGE;
569 return RESULT_SUCCESS;
572 static char frame_show_codecs_usage[] =
573 "Usage: show [audio|video|image] codecs\n"
574 " Displays codec mapping\n";
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 };
585 static int show_codec_n(int fd, int argc, char *argv[])
587 int codec, i, found=0;
590 return RESULT_SHOWUSAGE;
592 if (sscanf(argv[2],"%d",&codec) != 1)
593 return RESULT_SHOWUSAGE;
596 if (codec & (1 << i)) {
598 ast_cli(fd, "%11u (1 << %2d) %s\n",1 << i,i,ast_codec2str(i));
602 ast_cli(fd, "Codec %d not found\n", codec);
604 return RESULT_SUCCESS;
607 static char frame_show_codec_n_usage[] =
608 "Usage: show codec <number>\n"
609 " Displays codec mapping\n";
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 };
614 void ast_frame_dump(char *name, struct ast_frame *f, char *prefix)
617 char ftype[40] = "Unknown Frametype";
619 char subclass[40] = "Unknown Subclass";
621 char moreinfo[40] = "";
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)));
634 /* XXX We should probably print one each of voice and video when the format changes XXX */
635 if (f->frametype == AST_FRAME_VOICE)
637 if (f->frametype == AST_FRAME_VIDEO)
639 switch(f->frametype) {
641 strcpy(ftype, "DTMF");
642 subclass[0] = f->subclass;
645 case AST_FRAME_CONTROL:
646 strcpy(ftype, "Control");
647 switch(f->subclass) {
648 case AST_CONTROL_HANGUP:
649 strcpy(subclass, "Hangup");
651 case AST_CONTROL_RING:
652 strcpy(subclass, "Ring");
654 case AST_CONTROL_RINGING:
655 strcpy(subclass, "Ringing");
657 case AST_CONTROL_ANSWER:
658 strcpy(subclass, "Answer");
660 case AST_CONTROL_BUSY:
661 strcpy(subclass, "Busy");
663 case AST_CONTROL_TAKEOFFHOOK:
664 strcpy(subclass, "Take Off Hook");
666 case AST_CONTROL_OFFHOOK:
667 strcpy(subclass, "Line Off Hook");
669 case AST_CONTROL_CONGESTION:
670 strcpy(subclass, "Congestion");
672 case AST_CONTROL_FLASH:
673 strcpy(subclass, "Flash");
675 case AST_CONTROL_WINK:
676 strcpy(subclass, "Wink");
678 case AST_CONTROL_OPTION:
679 strcpy(subclass, "Option");
681 case AST_CONTROL_RADIO_KEY:
682 strcpy(subclass, "Key Radio");
684 case AST_CONTROL_RADIO_UNKEY:
685 strcpy(subclass, "Unkey Radio");
688 strcpy(subclass, "Stop generators");
691 snprintf(subclass, sizeof(subclass), "Unknown control '%d'", f->subclass);
695 strcpy(ftype, "Null Frame");
696 strcpy(subclass, "N/A");
699 /* Should never happen */
700 strcpy(ftype, "IAX Specific");
701 snprintf(subclass, sizeof(subclass), "IAX Frametype %d", f->subclass);
704 strcpy(ftype, "Text");
705 strcpy(subclass, "N/A");
706 strncpy(moreinfo, f->data, sizeof(moreinfo) - 1);
708 case AST_FRAME_IMAGE:
709 strcpy(ftype, "Image");
710 snprintf(subclass, sizeof(subclass), "Image format %s\n", ast_getformatname(f->subclass));
713 strcpy(ftype, "HTML");
714 switch(f->subclass) {
716 strcpy(subclass, "URL");
717 strncpy(moreinfo, f->data, sizeof(moreinfo) - 1);
720 strcpy(subclass, "Data");
723 strcpy(subclass, "Begin");
726 strcpy(subclass, "End");
728 case AST_HTML_LDCOMPLETE:
729 strcpy(subclass, "Load Complete");
731 case AST_HTML_NOSUPPORT:
732 strcpy(subclass, "No Support");
734 case AST_HTML_LINKURL:
735 strcpy(subclass, "Link URL");
736 strncpy(moreinfo, f->data, sizeof(moreinfo) - 1);
738 case AST_HTML_UNLINK:
739 strcpy(subclass, "Unlink");
741 case AST_HTML_LINKREJECT:
742 strcpy(subclass, "Link Reject");
745 snprintf(subclass, sizeof(subclass), "Unknown HTML frame '%d'\n", f->subclass);
750 snprintf(ftype, sizeof(ftype), "Unknown Frametype '%d'", f->frametype);
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)),
757 term_color(csub, subclass, COLOR_BRCYAN, COLOR_BLACK, sizeof(csub)),
759 term_color(cmn, moreinfo, COLOR_BRGREEN, COLOR_BLACK, sizeof(cmn)),
760 term_color(cn, n, COLOR_YELLOW, COLOR_BLACK, sizeof(cn)));
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)),
766 term_color(csub, subclass, COLOR_BRCYAN, COLOR_BLACK, sizeof(csub)),
768 term_color(cn, n, COLOR_YELLOW, COLOR_BLACK, sizeof(cn)));
774 static int show_frame_stats(int fd, int argc, char *argv[])
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>");
788 ast_mutex_unlock(&framelock);
789 return RESULT_SUCCESS;
792 static char frame_stats_usage[] =
793 "Usage: show frame stats\n"
794 " Displays debugging statistics from framer\n";
796 struct ast_cli_entry cli_frame_stats =
797 { { "show", "frame", "stats", NULL }, show_frame_stats, "Shows frame statistics", frame_stats_usage };
800 int init_framer(void)
803 ast_cli_register(&cli_frame_stats);
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);
813 void ast_codec_pref_shift(struct ast_codec_pref *pref, char *buf, size_t size, int right)
815 int x = 0, differential = 65, mem = 0;
816 char *from = NULL, *to = NULL;
829 for (x = 0; x < 32 ; x++) {
832 to[x] = right ? (from[x] + differential) : (from[x] - differential);
836 int ast_codec_pref_string(struct ast_codec_pref *pref, char *buf, size_t size)
838 int x = 0, codec = 0;
839 size_t total_len = 0, slen = 0;
840 char *formatname = 0;
846 for(x = 0; x < 32 ; x++) {
849 if(!(codec = ast_codec_pref_index(pref,x)))
851 if((formatname = ast_getformatname(codec))) {
852 slen = strlen(formatname);
855 strncat(buf,formatname,total_len);
858 if(total_len && x < 31 && ast_codec_pref_index(pref , x + 1)) {
859 strncat(buf,"|",total_len);
864 strncat(buf,")",total_len);
868 return size - total_len;
871 int ast_codec_pref_index(struct ast_codec_pref *pref, int index)
876 if((index >= 0) && (index < sizeof(pref->order))) {
877 slot = pref->order[index];
880 return slot ? AST_FORMAT_LIST[slot-1].bits : 0;
883 /*--- ast_codec_pref_remove: Remove codec from pref list ---*/
884 void ast_codec_pref_remove(struct ast_codec_pref *pref, int format)
886 struct ast_codec_pref oldorder;
894 size = sizeof(AST_FORMAT_LIST) / sizeof(struct ast_format_list);
896 memcpy(&oldorder,pref,sizeof(struct ast_codec_pref));
897 memset(pref,0,sizeof(struct ast_codec_pref));
899 for (x = 0; x < size; x++) {
900 slot = oldorder.order[x];
903 if(AST_FORMAT_LIST[slot-1].bits != format)
904 pref->order[y++] = slot;
909 /*--- ast_codec_pref_append: Append codec to list ---*/
910 int ast_codec_pref_append(struct ast_codec_pref *pref, int format)
913 int x = 0, newindex = -1;
915 ast_codec_pref_remove(pref, format);
916 size = sizeof(AST_FORMAT_LIST) / sizeof(struct ast_format_list);
918 for (x = 0; x < size; x++) {
919 if(AST_FORMAT_LIST[x].bits == format) {
926 for (x = 0; x < size; x++) {
927 if(!pref->order[x]) {
928 pref->order[x] = newindex;
938 /*--- sip_codec_choose: Pick a codec ---*/
939 int ast_codec_choose(struct ast_codec_pref *pref, int formats, int find_best)
942 int x = 0, ret = 0, slot = 0;
944 size = sizeof(AST_FORMAT_LIST) / sizeof(struct ast_format_list);
945 for (x = 0; x < size; x++) {
946 slot = pref->order[x];
950 if ( formats & AST_FORMAT_LIST[slot-1].bits ) {
951 ret = AST_FORMAT_LIST[slot-1].bits;
958 return find_best ? ast_best_codec(formats) : 0;
961 void ast_parse_allow_disallow(struct ast_codec_pref *pref, int *mask, char *list, int allowing)
964 char *next_format = NULL, *last_format = NULL;
966 last_format = ast_strdupa(list);
968 if((next_format = strchr(last_format, ','))) {
972 if ((format_i = ast_getformatbyname(last_format)) > 0) {
977 (*mask) &= ~format_i;
979 /* can't consider 'all' a prefered codec*/
980 if(pref && strcasecmp(last_format, "all")) {
982 ast_codec_pref_append(pref, format_i);
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));
988 ast_log(LOG_WARNING, "Cannot %s unknown format '%s'\n", allowing ? "allow" : "disallow", last_format);
990 last_format = next_format;