Merge updates to frame.h and frame.c (codec stuff from bug #2945, part 1)
authorMark Spencer <markster@digium.com>
Thu, 2 Dec 2004 21:57:45 +0000 (21:57 +0000)
committerMark Spencer <markster@digium.com>
Thu, 2 Dec 2004 21:57:45 +0000 (21:57 +0000)
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@4370 65c4cc65-6c06-0410-ace0-fbb531ad65f3

frame.c
include/asterisk/frame.h

diff --git a/frame.c b/frame.c
index 3538d35..c3f0d94 100755 (executable)
--- a/frame.c
+++ b/frame.c
@@ -15,6 +15,7 @@
 #include <asterisk/frame.h>
 #include <asterisk/logger.h>
 #include <asterisk/options.h>
+#include <asterisk/channel.h>
 #include <asterisk/cli.h>
 #include <asterisk/term.h>
 #include <asterisk/utils.h>
@@ -33,6 +34,13 @@ AST_MUTEX_DEFINE_STATIC(framelock);
 
 #define SMOOTHER_SIZE 8000
 
+struct ast_format_list {
+       int visible; /* Can we see this entry */
+       int bits; /* bitmask value */
+       char *name; /* short name */
+       char *desc; /* Description */
+};
+
 struct ast_smoother {
        int size;
        int format;
@@ -391,141 +399,137 @@ int ast_fr_fdhangup(int fd)
        return ast_fr_fdwrite(fd, &hangup);
 }
 
+static struct ast_format_list AST_FORMAT_LIST[] = {
+       { 1, AST_FORMAT_G723_1 , "g723" , "G.723.1"},
+       { 1, AST_FORMAT_GSM, "gsm" , "GSM"},
+       { 1, AST_FORMAT_ULAW, "ulaw", "G.711 u-law" },
+       { 1, AST_FORMAT_ALAW, "alaw", "G.711 A-law" },
+       { 1, AST_FORMAT_G726, "g726", "G.726" },
+       { 1, AST_FORMAT_ADPCM, "adpcm" , "ADPCM"},
+       { 1, AST_FORMAT_SLINEAR, "slin",  "16 bit Signed Linear PCM"},
+       { 1, AST_FORMAT_LPC10, "lpc10", "LPC10" },
+       { 1, AST_FORMAT_G729A, "g729", "G.729A" },
+       { 1, AST_FORMAT_SPEEX, "speex", "SpeeX" },
+       { 1, AST_FORMAT_ILBC, "ilbc", "iLBC"},
+       { 0, 0, "nothing", "undefined" },
+       { 0, 0, "nothing", "undefined" },
+       { 0, 0, "nothing", "undefined" },
+       { 0, 0, "nothing", "undefined" },
+       { 0, AST_FORMAT_MAX_AUDIO, "maxaudio", "Maximum audio format" },
+       { 1, AST_FORMAT_JPEG, "jpeg", "JPEG image"},
+       { 1, AST_FORMAT_PNG, "png", "PNG image"},
+       { 1, AST_FORMAT_H261, "h261", "H.261 Video" },
+       { 1, AST_FORMAT_H263, "h263", "H.263 Video" },
+       { 0, 0, "nothing", "undefined" },
+       { 0, 0, "nothing", "undefined" },
+       { 0, 0, "nothing", "undefined" },
+       { 0, 0, "nothing", "undefined" },
+       { 0, AST_FORMAT_MAX_VIDEO, "maxvideo", "Maximum video format" },
+};
+
+struct ast_format_list *ast_get_format_list_index(int index) {
+       return &AST_FORMAT_LIST[index];
+}
+
+struct ast_format_list *ast_get_format_list(size_t *size) {
+       *size = (sizeof(AST_FORMAT_LIST) / sizeof(struct ast_format_list));
+       return AST_FORMAT_LIST;
+}
+
 char* ast_getformatname(int format)
 {
-       if (format == AST_FORMAT_G723_1) 
-               return "G723";
-       else if (format == AST_FORMAT_GSM)
-               return "GSM";
-       else if (format == AST_FORMAT_ULAW)
-               return "ULAW";
-       else if (format == AST_FORMAT_ALAW)
-               return "ALAW";
-       else if (format == AST_FORMAT_G726)
-               return "G726";
-       else if (format == AST_FORMAT_SLINEAR)
-               return "SLINR";
-       else if (format == AST_FORMAT_LPC10)
-               return "LPC10";
-       else if (format == AST_FORMAT_ADPCM)
-               return "ADPCM";
-       else if (format == AST_FORMAT_G729A)
-               return "G729A";
-       else if (format == AST_FORMAT_SPEEX)
-               return "SPEEX";
-       else if (format == AST_FORMAT_ILBC)
-               return "ILBC";
-       else if (format == AST_FORMAT_JPEG)
-               return "JPEG";
-       else if (format == AST_FORMAT_PNG)
-               return "PNG";
-       else if (format == AST_FORMAT_H261)
-               return "H261";
-       else if (format == AST_FORMAT_H263)
-               return "H263";
-       return "UNKN";
-}
-
-char* ast_getformatname_multiple(char *buf, unsigned n, int format) {
-       unsigned u=1;
+       int x = 0;
+       char *ret = "unknown";
+       for (x = 0 ; x < sizeof(AST_FORMAT_LIST) / sizeof(struct ast_format_list) ; x++) {
+               if(AST_FORMAT_LIST[x].visible && AST_FORMAT_LIST[x].bits == format) {
+                       ret = AST_FORMAT_LIST[x].name;
+                       break;
+               }
+       }
+       return ret;
+}
+
+char *ast_getformatname_multiple(char *buf, size_t size, int format) {
+
+       int x = 0;
        unsigned len;
-       char *b = buf;
+       char *end = buf;
        char *start = buf;
-       if (!n) return buf;
-       snprintf(b,n,"0x%x(",format);
-       len = strlen(b);
-       b += len;
-       n -= len;
-       start = b;
-       while (u) {
-               if (u&format) {
-                       snprintf(b,n,"%s|",ast_getformatname(u));
-                       len = strlen(b);
-                       b += len;
-                       n -= len;
+       if (!size) return buf;
+       snprintf(end, size, "0x%x (", format);
+       len = strlen(end);
+       end += len;
+       size -= len;
+       start = end;
+       for (x = 0 ; x < sizeof(AST_FORMAT_LIST) / sizeof(struct ast_format_list) ; x++) {
+               if (AST_FORMAT_LIST[x].visible && (AST_FORMAT_LIST[x].bits & format)) {
+                       snprintf(end, size,"%s|",AST_FORMAT_LIST[x].name);
+                       len = strlen(end);
+                       end += len;
+                       size -= len;
                }
-               u *= 2;
        }
-       if (start==b)
-               snprintf(start,n,"EMPTY)");
-       else if (n>1)
-               b[-1]=')';
+       if (start == end)
+               snprintf(start, size, "nothing)");
+       else if (size > 1)
+               *(end -1) = ')';
        return buf;
 }
 
+static struct ast_codec_alias_table {
+       char *alias;
+       char *realname;
+
+} ast_codec_alias_table[] = {
+       {"slinear","slin"},
+       {"g723.1","g723"},
+};
+
+static char *ast_expand_codec_alias(char *in) {
+       int x = 0;
+
+       for (x = 0; x < sizeof(ast_codec_alias_table) / sizeof(struct ast_codec_alias_table) ; x++) {
+               if(!strcmp(in,ast_codec_alias_table[x].alias))
+                       return ast_codec_alias_table[x].realname;
+       }
+       return in;
+}
+
 int ast_getformatbyname(char *name)
 {
-       if (!strcasecmp(name, "g723.1")) 
-               return AST_FORMAT_G723_1;
-       else if (!strcasecmp(name, "gsm"))
-               return AST_FORMAT_GSM;
-       else if (!strcasecmp(name, "ulaw"))
-               return AST_FORMAT_ULAW;
-       else if (!strcasecmp(name, "alaw"))
-               return AST_FORMAT_ALAW;
-       else if (!strcasecmp(name, "g726"))
-               return AST_FORMAT_G726;
-       else if (!strcasecmp(name, "slinear"))
-               return AST_FORMAT_SLINEAR;
-       else if (!strcasecmp(name, "lpc10"))
-               return AST_FORMAT_LPC10;
-       else if (!strcasecmp(name, "adpcm"))
-               return AST_FORMAT_ADPCM;
-       else if (!strcasecmp(name, "g729"))
-               return AST_FORMAT_G729A;
-       else if (!strcasecmp(name, "speex"))
-               return AST_FORMAT_SPEEX;
-       else if (!strcasecmp(name, "ilbc"))
-               return AST_FORMAT_ILBC;
-       else if (!strcasecmp(name, "h261"))
-               return AST_FORMAT_H261;
-       else if (!strcasecmp(name, "h263"))
-               return AST_FORMAT_H263;
-       else if (!strcasecmp(name, "all"))
-               return 0x7FFFFFFF;
-       return 0;
+       int x = 0, all = 0, format = 0;
+
+       all = strcmp(name, "all") ? 0 : 1;
+       for (x = 0 ; x < sizeof(AST_FORMAT_LIST) / sizeof(struct ast_format_list) ; x++) {
+               if(AST_FORMAT_LIST[x].visible && (all || 
+                                                                                 !strcmp(AST_FORMAT_LIST[x].name,name) ||
+                                                                                 !strcmp(AST_FORMAT_LIST[x].name,ast_expand_codec_alias(name)))) {
+                       format |= AST_FORMAT_LIST[x].bits;
+                       if(!all)
+                               break;
+               }
+       }
+
+       return format;
 }
 
 char *ast_codec2str(int codec) {
-       static char codecs[25][30] = {
-               /* Audio formats */
-               "G.723.1",                    /*  0 */
-               "GSM",                        /*  1 */
-               "G.711 u-law",                /*  2 */
-               "G.711 A-law",                /*  3 */
-               "G.726",                      /*  4 */
-               "ADPCM",                      /*  5 */
-               "16 bit Signed Linear PCM",   /*  6 */
-               "LPC10",                      /*  7 */
-               "G.729A audio",               /*  8 */
-               "SpeeX",                      /*  9 */
-               "iLBC",                       /* 10 */
-               "undefined",                  /* 11 */
-               "undefined",                  /* 12 */
-               "undefined",                  /* 13 */
-               "undefined",                  /* 14 */
-               "Maximum audio format",       /* 15 */
-               /* Image formats */
-               "JPEG image",                 /* 16 */
-               "PNG image",                  /* 17 */
-               "H.261 Video",                /* 18 */
-               "H.263 Video",                /* 19 */
-               "undefined",                  /* 20 */
-               "undefined",                  /* 21 */
-               "undefined",                  /* 22 */
-               "undefined",                  /* 23 */
-               "Maximum video format",       /* 24 */
-               };
-       if ((codec >= 0) && (codec <= 24))
-               return codecs[codec];
-       else
-               return "unknown";
+       int x = 0;
+       char *ret = "unknown";
+       for (x = 0 ; x < sizeof(AST_FORMAT_LIST) / sizeof(struct ast_format_list) ; x++) {
+               if(AST_FORMAT_LIST[x].visible && AST_FORMAT_LIST[x].bits == codec) {
+                       ret = AST_FORMAT_LIST[x].desc;
+                       break;
+               }
+       }
+       return ret;
 }
 
 static int show_codecs(int fd, int argc, char *argv[])
 {
        int i, found=0;
-
+       char hex[25];
+       
        if ((argc < 2) || (argc > 3))
                return RESULT_SHOWUSAGE;
 
@@ -533,22 +537,30 @@ static int show_codecs(int fd, int argc, char *argv[])
                ast_cli(fd, "Disclaimer: this command is for informational purposes only.\n"
                                "\tIt does not indicate anything about your configuration.\n");
 
+       ast_cli(fd, "%11s %9s %10s   TYPE   %5s   %s\n","INT","BINARY","HEX","NAME","DESC");
+       ast_cli(fd, "--------------------------------------------------------------------------------\n");
        if ((argc == 2) || (!strcasecmp(argv[1],"audio"))) {
                found = 1;
-               for (i=0;i<11;i++)
-                       ast_cli(fd, "%11u (1 << %2d)  %s\n",1 << i,i,ast_codec2str(i));
+               for (i=0;i<11;i++) {
+                       snprintf(hex,25,"(0x%x)",1<<i);
+                       ast_cli(fd, "%11u (1 << %2d) %10s  audio   %5s   (%s)\n",1 << i,i,hex,ast_getformatname(1<<i),ast_codec2str(1<<i));
+               }
        }
 
        if ((argc == 2) || (!strcasecmp(argv[1],"image"))) {
                found = 1;
-               for (i=16;i<18;i++)
-                       ast_cli(fd, "%11u (1 << %2d)  %s\n",1 << i,i,ast_codec2str(i));
+               for (i=16;i<18;i++) {
+                       snprintf(hex,25,"(0x%x)",1<<i);
+                       ast_cli(fd, "%11u (1 << %2d) %10s  image   %5s   (%s)\n",1 << i,i,hex,ast_getformatname(1<<i),ast_codec2str(1<<i));
+               }
        }
 
        if ((argc == 2) || (!strcasecmp(argv[1],"video"))) {
                found = 1;
-               for (i=18;i<20;i++)
-                       ast_cli(fd, "%11u (1 << %2d)  %s\n",1 << i,i,ast_codec2str(i));
+               for (i=18;i<20;i++) {
+                       snprintf(hex,25,"(0x%x)",1<<i);
+                       ast_cli(fd, "%11u (1 << %2d) %10s  video   %5s   (%s)\n",1 << i,i,hex,ast_getformatname(1<<i),ast_codec2str(1<<i));
+               }
        }
 
        if (! found)
@@ -797,3 +809,185 @@ int init_framer(void)
        ast_cli_register(&cli_show_codec_n);
        return 0;       
 }
+
+void ast_codec_pref_shift(struct ast_codec_pref *pref, char *buf, size_t size, int right) 
+{
+       int x = 0, differential = 65, mem = 0;
+       char *from = NULL, *to = NULL;
+
+       if(right) {
+               from = pref->order;
+               to = buf;
+               mem = size;
+       } else {
+               to = pref->order;
+               from = buf;
+               mem = 32;
+       }
+
+       memset(to, 0, mem);
+       for (x = 0; x < 32 ; x++) {
+               if(!from[x])
+                       break;
+               to[x] = right ? (from[x] + differential) : (from[x] - differential);
+       }
+}
+
+int ast_codec_pref_string(struct ast_codec_pref *pref, char *buf, size_t size) 
+{
+       int x = 0, codec = 0; 
+       size_t total_len = 0, slen = 0;
+       char *formatname = 0;
+       
+       memset(buf,0,size);
+       total_len = size;
+       buf[0] = '(';
+       total_len--;
+       for(x = 0; x < 32 ; x++) {
+               if(total_len <= 0)
+                       break;
+               if(!(codec = ast_codec_pref_index(pref,x)))
+                       break;
+               if((formatname = ast_getformatname(codec))) {
+                       slen = strlen(formatname);
+                       if(slen > total_len)
+                               break;
+                       strncat(buf,formatname,total_len);
+                       total_len -= slen;
+               }
+               if(total_len && x < 31 && ast_codec_pref_index(pref , x + 1)) {
+                       strncat(buf,"|",total_len);
+                       total_len--;
+               }
+       }
+       if(total_len) {
+               strncat(buf,")",total_len);
+               total_len--;
+       }
+
+       return size - total_len;
+}
+
+int ast_codec_pref_index(struct ast_codec_pref *pref, int index) 
+{
+       int slot = 0;
+
+       
+       if((index >= 0) && (index < sizeof(pref->order))) {
+               slot = pref->order[index];
+       }
+
+       return slot ? AST_FORMAT_LIST[slot-1].bits : 0;
+}
+
+/*--- ast_codec_pref_remove: Remove codec from pref list ---*/
+void ast_codec_pref_remove(struct ast_codec_pref *pref, int format)
+{
+       struct ast_codec_pref oldorder;
+       int x=0, y=0;
+       size_t size = 0;
+       int slot = 0;
+
+       if(!pref->order[0])
+               return;
+
+       size = sizeof(AST_FORMAT_LIST) / sizeof(struct ast_format_list);
+
+       memcpy(&oldorder,pref,sizeof(struct ast_codec_pref));
+       memset(pref,0,sizeof(struct ast_codec_pref));
+
+       for (x = 0; x < size; x++) {
+               slot = oldorder.order[x];
+               if(! slot)
+                       break;
+               if(AST_FORMAT_LIST[slot-1].bits != format)
+                       pref->order[y++] = slot;
+       }
+       
+}
+
+/*--- ast_codec_pref_append: Append codec to list ---*/
+int ast_codec_pref_append(struct ast_codec_pref *pref, int format)
+{
+       size_t size = 0;
+       int x = 0, newindex = -1;
+
+       ast_codec_pref_remove(pref, format);
+       size = sizeof(AST_FORMAT_LIST) / sizeof(struct ast_format_list);
+
+       for (x = 0; x < size; x++) {
+               if(AST_FORMAT_LIST[x].bits == format) {
+                       newindex = x + 1;
+                       break;
+               }
+       }
+
+       if(newindex) {
+               for (x = 0; x < size; x++) {
+                       if(!pref->order[x]) {
+                               pref->order[x] = newindex;
+                               break;
+                       }
+               }
+       }
+
+       return x;
+}
+
+
+/*--- sip_codec_choose: Pick a codec ---*/
+int ast_codec_choose(struct ast_codec_pref *pref, int formats, int find_best)
+{
+       size_t size = 0;
+       int x = 0, ret = 0, slot = 0;
+
+       size = sizeof(AST_FORMAT_LIST) / sizeof(struct ast_format_list);
+       for (x = 0; x < size; x++) {
+               slot = pref->order[x];
+
+               if(!slot)
+                       break;
+               if ( formats & AST_FORMAT_LIST[slot-1].bits ) {
+                       ret = AST_FORMAT_LIST[slot-1].bits;
+                       break;
+               }
+       }
+       if(ret)
+               return ret;
+
+       return find_best ? ast_best_codec(formats) : 0;
+}
+
+void ast_parse_allow_deny(struct ast_codec_pref *pref, int *mask, char *list, int allowing) 
+{
+       int format_i = 0;
+       char *next_format = NULL, *last_format = NULL;
+
+       last_format = ast_strdupa(list);
+       while(last_format) {
+               if((next_format = strchr(last_format, ','))) {
+                       *next_format = '\0';
+                       next_format++;
+               }
+               if ((format_i = ast_getformatbyname(last_format)) > 0) {
+                       if (mask) {
+                               if (allowing)
+                                       (*mask) |= format_i;
+                               else
+                                       (*mask) &= format_i;
+                       }
+                       /* can't consider 'all' a prefered codec*/
+                       if(pref && strcasecmp(last_format, "all")) {
+                               if(allowing)
+                                       ast_codec_pref_append(pref, format_i);
+                               else
+                                       ast_codec_pref_remove(pref, format_i);
+                       }
+               } else
+                       ast_log(LOG_WARNING, "Cannot %s unknown format '%s'\n", allowing ? "allow" : "disallow", last_format);
+
+               last_format = next_format;
+       }
+}
+
+
index c80ca72..a612ea9 100755 (executable)
@@ -58,6 +58,11 @@ extern "C" {
 #error Need to know endianess
 #endif /* __BYTE_ORDER */
 
+struct ast_codec_pref {
+       char order[32];
+};
+
+
 //! Data structure associated with a single frame of data
 /* A frame of data read used to communicate between 
    between channels and applications */
@@ -337,11 +342,10 @@ extern char* ast_getformatname(int format);
  * \param n size of buf (bytes)
  * \param format the format (combined IDs of codecs)
  * Prints a list of readable codec names corresponding to "format".
- * ex: for format=AST_FORMAT_GSM|AST_FORMAT_SPEEX|AST_FORMAT_ILBC it will return "0x602(GSM|SPEEX|ILBC)"
+ * ex: for format=AST_FORMAT_GSM|AST_FORMAT_SPEEX|AST_FORMAT_ILBC it will return "0x602 (GSM|SPEEX|ILBC)"
  * \return The return value is buf.
  */
-extern char* ast_getformatname_multiple(char *buf, unsigned n, int format);
-
+extern char* ast_getformatname_multiple(char *buf, size_t size, int format);
 
 /*!
  * \param name string of format
@@ -364,6 +368,8 @@ extern int ast_best_codec(int fmts);
 
 struct ast_smoother;
 
+extern struct ast_format_list *ast_get_format_list_index(int index);
+extern struct ast_format_list *ast_get_format_list(size_t *size);
 extern struct ast_smoother *ast_smoother_new(int bytes);
 extern void ast_smoother_set_flags(struct ast_smoother *smoother, int flags);
 extern int ast_smoother_get_flags(struct ast_smoother *smoother);
@@ -374,6 +380,32 @@ extern struct ast_frame *ast_smoother_read(struct ast_smoother *s);
 
 extern void ast_frame_dump(char *name, struct ast_frame *f, char *prefix);
 
+/* Initialize a codec preference to "no preference" */
+extern void ast_codec_pref_init(struct ast_codec_pref *pref);
+
+/* Codec located at  a particular place in the preference index */
+extern int ast_codec_pref_index(struct ast_codec_pref *pref, int index);
+
+/* Remove a codec from a preference list */
+extern void ast_codec_pref_remove(struct ast_codec_pref *pref, int format);
+
+/* Append a codec to a preference list, removing it first if it was already there */
+extern int ast_codec_pref_append(struct ast_codec_pref *pref, int format);
+
+/* Select the best format according to preference list from supplied options. 
+   If "find_best" is non-zero then if nothing is found, the "Best" format of 
+   the format list is selected, otherwise 0 is returned. */
+extern int ast_codec_choose(struct ast_codec_pref *pref, int formats, int find_best);
+
+/* Parse an "allow" or "deny" line and update the mask and pref if provided */
+extern void ast_parse_allow_deny(struct ast_codec_pref *pref, int *mask, char *list, int allowing);
+
+/* Dump codec preference list into a string */
+extern int ast_codec_pref_string(struct ast_codec_pref *pref, char *buf, size_t size);
+
+/* Shift a codec preference list up or down 65 bytes so that it becomes an ASCII string */
+extern void ast_codec_pref_shift(struct ast_codec_pref *pref, char *buf, size_t size, int right);
+
 #if defined(__cplusplus) || defined(c_plusplus)
 }
 #endif