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)
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) {
234 free((char *)fr->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((char *)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 = (char *)__FUNCTION__;
358 if (f->datalen > sizeof(buf) - sizeof(struct ast_frame)) {
359 /* Really bad read */
360 ast_log(LOG_WARNING, "Strange read (%d bytes)\n", f->datalen);
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 { 1, AST_FORMAT_H263_PLUS, "h263p", "H.263+ Video" },
424 { 0, 0, "nothing", "undefined" },
425 { 0, 0, "nothing", "undefined" },
426 { 0, 0, "nothing", "undefined" },
427 { 0, 0, "nothing", "undefined" },
428 { 0, AST_FORMAT_MAX_VIDEO, "maxvideo", "Maximum video format" },
431 struct ast_format_list *ast_get_format_list_index(int index)
433 return &AST_FORMAT_LIST[index];
436 struct ast_format_list *ast_get_format_list(size_t *size)
438 *size = (sizeof(AST_FORMAT_LIST) / sizeof(struct ast_format_list));
439 return AST_FORMAT_LIST;
442 char* ast_getformatname(int format)
445 char *ret = "unknown";
446 for (x = 0 ; x < sizeof(AST_FORMAT_LIST) / sizeof(struct ast_format_list) ; x++) {
447 if(AST_FORMAT_LIST[x].visible && AST_FORMAT_LIST[x].bits == format) {
448 ret = AST_FORMAT_LIST[x].name;
455 char *ast_getformatname_multiple(char *buf, size_t size, int format) {
461 if (!size) return buf;
462 snprintf(end, size, "0x%x (", format);
467 for (x = 0 ; x < sizeof(AST_FORMAT_LIST) / sizeof(struct ast_format_list) ; x++) {
468 if (AST_FORMAT_LIST[x].visible && (AST_FORMAT_LIST[x].bits & format)) {
469 snprintf(end, size,"%s|",AST_FORMAT_LIST[x].name);
476 snprintf(start, size, "nothing)");
482 static struct ast_codec_alias_table {
486 } ast_codec_alias_table[] = {
491 static char *ast_expand_codec_alias(char *in) {
494 for (x = 0; x < sizeof(ast_codec_alias_table) / sizeof(struct ast_codec_alias_table) ; x++) {
495 if(!strcmp(in,ast_codec_alias_table[x].alias))
496 return ast_codec_alias_table[x].realname;
501 int ast_getformatbyname(char *name)
503 int x = 0, all = 0, format = 0;
505 all = strcasecmp(name, "all") ? 0 : 1;
506 for (x = 0 ; x < sizeof(AST_FORMAT_LIST) / sizeof(struct ast_format_list) ; x++) {
507 if(AST_FORMAT_LIST[x].visible && (all ||
508 !strcasecmp(AST_FORMAT_LIST[x].name,name) ||
509 !strcasecmp(AST_FORMAT_LIST[x].name,ast_expand_codec_alias(name)))) {
510 format |= AST_FORMAT_LIST[x].bits;
519 char *ast_codec2str(int codec) {
521 char *ret = "unknown";
522 for (x = 0 ; x < sizeof(AST_FORMAT_LIST) / sizeof(struct ast_format_list) ; x++) {
523 if(AST_FORMAT_LIST[x].visible && AST_FORMAT_LIST[x].bits == codec) {
524 ret = AST_FORMAT_LIST[x].desc;
531 static int show_codecs(int fd, int argc, char *argv[])
536 if ((argc < 2) || (argc > 3))
537 return RESULT_SHOWUSAGE;
539 if (getenv("I_AM_NOT_AN_IDIOT") == NULL)
540 ast_cli(fd, "Disclaimer: this command is for informational purposes only.\n"
541 "\tIt does not indicate anything about your configuration.\n");
543 ast_cli(fd, "%11s %9s %10s TYPE %5s %s\n","INT","BINARY","HEX","NAME","DESC");
544 ast_cli(fd, "--------------------------------------------------------------------------------\n");
545 if ((argc == 2) || (!strcasecmp(argv[1],"audio"))) {
548 snprintf(hex,25,"(0x%x)",1<<i);
549 ast_cli(fd, "%11u (1 << %2d) %10s audio %5s (%s)\n",1 << i,i,hex,ast_getformatname(1<<i),ast_codec2str(1<<i));
553 if ((argc == 2) || (!strcasecmp(argv[1],"image"))) {
555 for (i=16;i<18;i++) {
556 snprintf(hex,25,"(0x%x)",1<<i);
557 ast_cli(fd, "%11u (1 << %2d) %10s image %5s (%s)\n",1 << i,i,hex,ast_getformatname(1<<i),ast_codec2str(1<<i));
561 if ((argc == 2) || (!strcasecmp(argv[1],"video"))) {
563 for (i=18;i<21;i++) {
564 snprintf(hex,25,"(0x%x)",1<<i);
565 ast_cli(fd, "%11u (1 << %2d) %10s video %5s (%s)\n",1 << i,i,hex,ast_getformatname(1<<i),ast_codec2str(1<<i));
570 return RESULT_SHOWUSAGE;
572 return RESULT_SUCCESS;
575 static char frame_show_codecs_usage[] =
576 "Usage: show [audio|video|image] codecs\n"
577 " Displays codec mapping\n";
579 struct ast_cli_entry cli_show_codecs =
580 { { "show", "codecs", NULL }, show_codecs, "Shows codecs", frame_show_codecs_usage };
581 struct ast_cli_entry cli_show_codecs_audio =
582 { { "show", "audio", "codecs", NULL }, show_codecs, "Shows audio codecs", frame_show_codecs_usage };
583 struct ast_cli_entry cli_show_codecs_video =
584 { { "show", "video", "codecs", NULL }, show_codecs, "Shows video codecs", frame_show_codecs_usage };
585 struct ast_cli_entry cli_show_codecs_image =
586 { { "show", "image", "codecs", NULL }, show_codecs, "Shows image codecs", frame_show_codecs_usage };
588 static int show_codec_n(int fd, int argc, char *argv[])
590 int codec, i, found=0;
593 return RESULT_SHOWUSAGE;
595 if (sscanf(argv[2],"%d",&codec) != 1)
596 return RESULT_SHOWUSAGE;
599 if (codec & (1 << i)) {
601 ast_cli(fd, "%11u (1 << %2d) %s\n",1 << i,i,ast_codec2str(1<<i));
605 ast_cli(fd, "Codec %d not found\n", codec);
607 return RESULT_SUCCESS;
610 static char frame_show_codec_n_usage[] =
611 "Usage: show codec <number>\n"
612 " Displays codec mapping\n";
614 struct ast_cli_entry cli_show_codec_n =
615 { { "show", "codec", NULL }, show_codec_n, "Shows a specific codec", frame_show_codec_n_usage };
617 void ast_frame_dump(char *name, struct ast_frame *f, char *prefix)
620 char ftype[40] = "Unknown Frametype";
622 char subclass[40] = "Unknown Subclass";
624 char moreinfo[40] = "";
631 ast_verbose("%s [ %s (NULL) ] [%s]\n",
632 term_color(cp, prefix, COLOR_BRMAGENTA, COLOR_BLACK, sizeof(cp)),
633 term_color(cft, "HANGUP", COLOR_BRRED, COLOR_BLACK, sizeof(cft)),
634 term_color(cn, n, COLOR_YELLOW, COLOR_BLACK, sizeof(cn)));
637 /* XXX We should probably print one each of voice and video when the format changes XXX */
638 if (f->frametype == AST_FRAME_VOICE)
640 if (f->frametype == AST_FRAME_VIDEO)
642 switch(f->frametype) {
644 strcpy(ftype, "DTMF");
645 subclass[0] = f->subclass;
648 case AST_FRAME_CONTROL:
649 strcpy(ftype, "Control");
650 switch(f->subclass) {
651 case AST_CONTROL_HANGUP:
652 strcpy(subclass, "Hangup");
654 case AST_CONTROL_RING:
655 strcpy(subclass, "Ring");
657 case AST_CONTROL_RINGING:
658 strcpy(subclass, "Ringing");
660 case AST_CONTROL_ANSWER:
661 strcpy(subclass, "Answer");
663 case AST_CONTROL_BUSY:
664 strcpy(subclass, "Busy");
666 case AST_CONTROL_TAKEOFFHOOK:
667 strcpy(subclass, "Take Off Hook");
669 case AST_CONTROL_OFFHOOK:
670 strcpy(subclass, "Line Off Hook");
672 case AST_CONTROL_CONGESTION:
673 strcpy(subclass, "Congestion");
675 case AST_CONTROL_FLASH:
676 strcpy(subclass, "Flash");
678 case AST_CONTROL_WINK:
679 strcpy(subclass, "Wink");
681 case AST_CONTROL_OPTION:
682 strcpy(subclass, "Option");
684 case AST_CONTROL_RADIO_KEY:
685 strcpy(subclass, "Key Radio");
687 case AST_CONTROL_RADIO_UNKEY:
688 strcpy(subclass, "Unkey Radio");
691 strcpy(subclass, "Stop generators");
694 snprintf(subclass, sizeof(subclass), "Unknown control '%d'", f->subclass);
698 strcpy(ftype, "Null Frame");
699 strcpy(subclass, "N/A");
702 /* Should never happen */
703 strcpy(ftype, "IAX Specific");
704 snprintf(subclass, sizeof(subclass), "IAX Frametype %d", f->subclass);
707 strcpy(ftype, "Text");
708 strcpy(subclass, "N/A");
709 strncpy(moreinfo, f->data, sizeof(moreinfo) - 1);
711 case AST_FRAME_IMAGE:
712 strcpy(ftype, "Image");
713 snprintf(subclass, sizeof(subclass), "Image format %s\n", ast_getformatname(f->subclass));
716 strcpy(ftype, "HTML");
717 switch(f->subclass) {
719 strcpy(subclass, "URL");
720 strncpy(moreinfo, f->data, sizeof(moreinfo) - 1);
723 strcpy(subclass, "Data");
726 strcpy(subclass, "Begin");
729 strcpy(subclass, "End");
731 case AST_HTML_LDCOMPLETE:
732 strcpy(subclass, "Load Complete");
734 case AST_HTML_NOSUPPORT:
735 strcpy(subclass, "No Support");
737 case AST_HTML_LINKURL:
738 strcpy(subclass, "Link URL");
739 strncpy(moreinfo, f->data, sizeof(moreinfo) - 1);
741 case AST_HTML_UNLINK:
742 strcpy(subclass, "Unlink");
744 case AST_HTML_LINKREJECT:
745 strcpy(subclass, "Link Reject");
748 snprintf(subclass, sizeof(subclass), "Unknown HTML frame '%d'\n", f->subclass);
753 snprintf(ftype, sizeof(ftype), "Unknown Frametype '%d'", f->frametype);
755 if (!ast_strlen_zero(moreinfo))
756 ast_verbose("%s [ TYPE: %s (%d) SUBCLASS: %s (%d) '%s' ] [%s]\n",
757 term_color(cp, prefix, COLOR_BRMAGENTA, COLOR_BLACK, sizeof(cp)),
758 term_color(cft, ftype, COLOR_BRRED, COLOR_BLACK, sizeof(cft)),
760 term_color(csub, subclass, COLOR_BRCYAN, COLOR_BLACK, sizeof(csub)),
762 term_color(cmn, moreinfo, COLOR_BRGREEN, COLOR_BLACK, sizeof(cmn)),
763 term_color(cn, n, COLOR_YELLOW, COLOR_BLACK, sizeof(cn)));
765 ast_verbose("%s [ TYPE: %s (%d) SUBCLASS: %s (%d) ] [%s]\n",
766 term_color(cp, prefix, COLOR_BRMAGENTA, COLOR_BLACK, sizeof(cp)),
767 term_color(cft, ftype, COLOR_BRRED, COLOR_BLACK, sizeof(cft)),
769 term_color(csub, subclass, COLOR_BRCYAN, COLOR_BLACK, sizeof(csub)),
771 term_color(cn, n, COLOR_YELLOW, COLOR_BLACK, sizeof(cn)));
777 static int show_frame_stats(int fd, int argc, char *argv[])
782 return RESULT_SHOWUSAGE;
783 ast_cli(fd, " Framer Statistics \n");
784 ast_cli(fd, "---------------------------\n");
785 ast_cli(fd, "Total allocated headers: %d\n", headers);
786 ast_cli(fd, "Queue Dump:\n");
787 ast_mutex_lock(&framelock);
788 for (f=headerlist; f; f = f->next) {
789 ast_cli(fd, "%d. Type %d, subclass %d from %s\n", x++, f->frametype, f->subclass, f->src ? f->src : "<Unknown>");
791 ast_mutex_unlock(&framelock);
792 return RESULT_SUCCESS;
795 static char frame_stats_usage[] =
796 "Usage: show frame stats\n"
797 " Displays debugging statistics from framer\n";
799 struct ast_cli_entry cli_frame_stats =
800 { { "show", "frame", "stats", NULL }, show_frame_stats, "Shows frame statistics", frame_stats_usage };
803 int init_framer(void)
806 ast_cli_register(&cli_frame_stats);
808 ast_cli_register(&cli_show_codecs);
809 ast_cli_register(&cli_show_codecs_audio);
810 ast_cli_register(&cli_show_codecs_video);
811 ast_cli_register(&cli_show_codecs_image);
812 ast_cli_register(&cli_show_codec_n);
816 void ast_codec_pref_convert(struct ast_codec_pref *pref, char *buf, size_t size, int right)
818 int x = 0, differential = (int) 'A', mem = 0;
819 char *from = NULL, *to = NULL;
832 for (x = 0; x < 32 ; x++) {
835 to[x] = right ? (from[x] + differential) : (from[x] - differential);
839 int ast_codec_pref_string(struct ast_codec_pref *pref, char *buf, size_t size)
841 int x = 0, codec = 0;
842 size_t total_len = 0, slen = 0;
843 char *formatname = 0;
849 for(x = 0; x < 32 ; x++) {
852 if(!(codec = ast_codec_pref_index(pref,x)))
854 if((formatname = ast_getformatname(codec))) {
855 slen = strlen(formatname);
858 strncat(buf,formatname,total_len);
861 if(total_len && x < 31 && ast_codec_pref_index(pref , x + 1)) {
862 strncat(buf,"|",total_len);
867 strncat(buf,")",total_len);
871 return size - total_len;
874 int ast_codec_pref_index(struct ast_codec_pref *pref, int index)
879 if((index >= 0) && (index < sizeof(pref->order))) {
880 slot = pref->order[index];
883 return slot ? AST_FORMAT_LIST[slot-1].bits : 0;
886 /*--- ast_codec_pref_remove: Remove codec from pref list ---*/
887 void ast_codec_pref_remove(struct ast_codec_pref *pref, int format)
889 struct ast_codec_pref oldorder;
897 size = sizeof(AST_FORMAT_LIST) / sizeof(struct ast_format_list);
899 memcpy(&oldorder,pref,sizeof(struct ast_codec_pref));
900 memset(pref,0,sizeof(struct ast_codec_pref));
902 for (x = 0; x < size; x++) {
903 slot = oldorder.order[x];
906 if(AST_FORMAT_LIST[slot-1].bits != format)
907 pref->order[y++] = slot;
912 /*--- ast_codec_pref_append: Append codec to list ---*/
913 int ast_codec_pref_append(struct ast_codec_pref *pref, int format)
916 int x = 0, newindex = -1;
918 ast_codec_pref_remove(pref, format);
919 size = sizeof(AST_FORMAT_LIST) / sizeof(struct ast_format_list);
921 for (x = 0; x < size; x++) {
922 if(AST_FORMAT_LIST[x].bits == format) {
929 for (x = 0; x < size; x++) {
930 if(!pref->order[x]) {
931 pref->order[x] = newindex;
941 /*--- sip_codec_choose: Pick a codec ---*/
942 int ast_codec_choose(struct ast_codec_pref *pref, int formats, int find_best)
945 int x = 0, ret = 0, slot = 0;
947 size = sizeof(AST_FORMAT_LIST) / sizeof(struct ast_format_list);
948 for (x = 0; x < size; x++) {
949 slot = pref->order[x];
953 if ( formats & AST_FORMAT_LIST[slot-1].bits ) {
954 ret = AST_FORMAT_LIST[slot-1].bits;
961 return find_best ? ast_best_codec(formats) : 0;
964 void ast_parse_allow_disallow(struct ast_codec_pref *pref, int *mask, char *list, int allowing)
967 char *next_format = NULL, *last_format = NULL;
969 last_format = ast_strdupa(list);
971 if((next_format = strchr(last_format, ','))) {
975 if ((format_i = ast_getformatbyname(last_format)) > 0) {
980 (*mask) &= ~format_i;
982 /* can't consider 'all' a prefered codec*/
983 if(pref && strcasecmp(last_format, "all")) {
985 ast_codec_pref_append(pref, format_i);
987 ast_codec_pref_remove(pref, format_i);
988 } else if(!allowing) /* disallow all must clear your prefs or it makes no sense */
989 memset(pref, 0, sizeof(struct ast_codec_pref));
991 ast_log(LOG_WARNING, "Cannot %s unknown format '%s'\n", allowing ? "allow" : "disallow", last_format);
993 last_format = next_format;