Index: frame.c =================================================================== RCS file: /usr/cvsroot/asterisk/frame.c,v retrieving revision 1.37 diff -u -r1.37 frame.c --- frame.c 6 Nov 2004 21:33:01 -0000 1.37 +++ frame.c 1 Dec 2004 18:35:21 -0000 @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -391,141 +392,137 @@ 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"; + 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, unsigned n, int format) { - unsigned u=1; +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; - } - u *= 2; - } - if (start==b) - snprintf(start,n,"EMPTY)"); - else if (n>1) - b[-1]=')'; + 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; + } + } + 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 +530,30 @@ 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<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[y++] = 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) { + slot = pref->order[index]; + } + + return slot ? AST_FORMAT_LIST[slot-1].bits : 0; +} + +int ast_codec_pref_inuse(struct ast_codec_pref *pref) { + return (pref->order[0]) ? 1 : 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; +} + +int ast_parse_allow(struct ast_codec_pref *pref, char *list, int allowing) { + int mask = 0, 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) { + mask |= format_i; + /* can't consider 'all' a prefered codec*/ + if(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; + } + return mask; +} + + Index: include/asterisk/frame.h =================================================================== RCS file: /usr/cvsroot/asterisk/include/asterisk/frame.h,v retrieving revision 1.35 diff -u -r1.35 frame.h --- include/asterisk/frame.h 26 Aug 2004 04:56:26 -0000 1.35 +++ include/asterisk/frame.h 1 Dec 2004 18:35:21 -0000 @@ -58,6 +58,18 @@ #error Need to know endianess #endif /* __BYTE_ORDER */ +struct ast_format_list { + int visible; /* Can we see this entry */ + int bits; /* bitmask value */ + char *name; /* short name */ + char *desc; /* Description */ +}; + +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 +349,10 @@ * \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 +375,8 @@ 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); @@ -373,6 +386,16 @@ extern struct ast_frame *ast_smoother_read(struct ast_smoother *s); extern void ast_frame_dump(char *name, struct ast_frame *f, char *prefix); + +extern void ast_codec_pref_init(struct ast_codec_pref *pref); +extern int ast_codec_pref_inuse(struct ast_codec_pref *pref); +extern int ast_codec_pref_index(struct ast_codec_pref *pref, int index); +extern void ast_codec_pref_remove(struct ast_codec_pref *pref, int format); +extern int ast_codec_pref_append(struct ast_codec_pref *pref, int format); +extern int ast_codec_choose(struct ast_codec_pref *pref, int formats, int find_best); +extern int ast_parse_allow(struct ast_codec_pref *pref, char *list, int allowing); +extern int ast_codec_pref_string(struct ast_codec_pref *pref, char *buf, size_t size); +extern void ast_codec_pref_shift(struct ast_codec_pref *pref, char *buf, size_t size, int right); #if defined(__cplusplus) || defined(c_plusplus) } Index: channels/chan_iax2.c =================================================================== RCS file: /usr/cvsroot/asterisk/channels/chan_iax2.c,v retrieving revision 1.221 diff -u -r1.221 chan_iax2.c --- channels/chan_iax2.c 29 Nov 2004 03:24:35 -0000 1.221 +++ channels/chan_iax2.c 1 Dec 2004 18:35:28 -0000 @@ -99,6 +99,8 @@ /* Sample over last 100 units to determine historic jitter */ #define GAMMA (0.01) +static struct ast_codec_pref prefs; + static char *desc = "Inter Asterisk eXchange (Ver 2)"; static char *tdesc = "Inter Asterisk eXchange Driver (Ver 2)"; static char *type = "IAX2"; @@ -203,6 +205,7 @@ int trunk; char cid_num[AST_MAX_EXTENSION]; char cid_name[AST_MAX_EXTENSION]; + struct ast_codec_pref prefs; struct ast_ha *ha; struct iax2_context *contexts; struct iax2_user *next; @@ -221,6 +224,7 @@ char regexten[AST_MAX_EXTENSION]; /* Extension to register (if regcontext is used) */ char peercontext[AST_MAX_EXTENSION]; /* Context to pass to peer */ char mailbox[AST_MAX_EXTENSION]; /* Mailbox */ + struct ast_codec_pref prefs; struct sockaddr_in addr; int formats; struct in_addr mask; @@ -366,6 +370,7 @@ int maxtime; /* Peer Address */ struct sockaddr_in addr; + struct ast_codec_pref prefs; /* Our call number */ unsigned short callno; /* Peer callno */ @@ -624,6 +629,20 @@ return csub; } +static struct iax2_peer *find_peer(const char *name) { + struct iax2_peer *peer; + struct iax2_peer *prev; + ast_mutex_lock(&peerl.lock); + for(peer = peerl.peers; peer; peer = peer->next) { + if (!strcasecmp(peer->name, name)) { + break; + } + prev = peer; + } + ast_mutex_unlock(&peerl.lock); + return peer; +} + static int iax2_getpeername(struct sockaddr_in sin, char *host, int len, int lockpeer) { struct iax2_peer *peer; @@ -651,6 +670,7 @@ tmp = malloc(sizeof(struct chan_iax2_pvt)); if (tmp) { memset(tmp, 0, sizeof(struct chan_iax2_pvt)); + tmp->prefs = prefs; tmp->callno = 0; tmp->peercallno = 0; tmp->transfercallno = 0; @@ -1575,6 +1595,75 @@ "to establish the maximum excess jitter buffer that is permitted before the jitter\n" "buffer size is reduced."; + +/*--- iax2_show_peer: Show one peer in detail ---*/ +static int iax2_show_peer(int fd, int argc, char *argv[]) +{ + char status[30] = ""; + char cbuf[256]; + char iabuf[INET_ADDRSTRLEN]; + struct iax2_peer *peer; + char codec_buf[512]; + struct ast_codec_pref *pref; + int x = 0, codec = 0; + + if (argc != 4) + return RESULT_SHOWUSAGE; + ast_mutex_lock(&peerl.lock); + peer = find_peer(argv[3]); + if (peer) { + ast_cli(fd,"\n\n"); + ast_cli(fd, " * Name : %s\n", peer->name); + ast_cli(fd, " Secret : %s\n", ast_strlen_zero(peer->secret)?"":""); + ast_cli(fd, " Context : %s\n", peer->context); + ast_cli(fd, " Mailbox : %s\n", peer->mailbox); + ast_cli(fd, " Dynamic : %s\n", (peer->dynamic?"Yes":"No")); + ast_cli(fd, " Callerid : %s\n", ast_callerid_merge(cbuf, sizeof(cbuf), peer->cid_name, peer->cid_num, "")); + ast_cli(fd, " Expire : %d\n", peer->expire); + ast_cli(fd, " ACL : %s\n", (peer->ha?"Yes":"No")); + ast_cli(fd, " Addr->IP : %s Port %d\n", peer->addr.sin_addr.s_addr ? ast_inet_ntoa(iabuf, sizeof(iabuf), peer->addr.sin_addr) : "(Unspecified)", ntohs(peer->addr.sin_port)); + ast_cli(fd, " Defaddr->IP : %s Port %d\n", ast_inet_ntoa(iabuf, sizeof(iabuf), peer->defaddr.sin_addr), ntohs(peer->defaddr.sin_port)); + ast_cli(fd, " Username : %s\n", peer->username); + ast_cli(fd, " Codecs : "); + ast_getformatname_multiple(codec_buf, sizeof(codec_buf) -1, peer->capability); + ast_cli(fd, "%s\n", codec_buf); + ast_cli(fd, " Codec Order : ("); + pref = ast_codec_pref_inuse(&peer->prefs) ? &peer->prefs : &prefs; + for(x = 0; x < 32 ; x++) { + codec = ast_codec_pref_index(pref,x); + if(!codec) + break; + ast_cli(fd, "%s", ast_getformatname(codec)); + if(x < 31 && ast_codec_pref_index(pref,x+1)) + ast_cli(fd, "|"); + } + + if (!ast_codec_pref_inuse(&peer->prefs) && !ast_codec_pref_inuse(&prefs)) + ast_cli(fd, "none"); + ast_cli(fd, ")\n"); + + ast_cli(fd, " Status : "); + if (peer->lastms < 0) + strncpy(status, "UNREACHABLE", sizeof(status) - 1); + else if (peer->lastms > peer->maxms) + snprintf(status, sizeof(status), "LAGGED (%d ms)", peer->lastms); + else if (peer->lastms) + snprintf(status, sizeof(status), "OK (%d ms)", peer->lastms); + else + strncpy(status, "UNKNOWN", sizeof(status) - 1); + ast_cli(fd, "%s\n",status); + ast_cli(fd,"\n"); + } else { + ast_cli(fd,"Peer %s not found.\n", argv[3]); + ast_cli(fd,"\n"); + } + + ast_mutex_unlock(&peerl.lock); + + return RESULT_SUCCESS; +} + + static int iax2_show_stats(int fd, int argc, char *argv[]) { struct iax_frame *cur; @@ -1658,6 +1747,10 @@ "Usage: iax show cache\n" " Display currently cached IAX Dialplan results.\n"; +static char show_peer_usage[] = +"Usage: iax show peer \n" +" Display details on specific IAX peer\n"; + static struct ast_cli_entry cli_set_jitter = { { "iax2", "set", "jitter", NULL }, iax2_set_jitter, "Sets IAX jitter buffer", jitter_usage }; @@ -1667,6 +1760,8 @@ static struct ast_cli_entry cli_show_cache = { { "iax2", "show", "cache", NULL }, iax2_show_cache, "Display IAX cached dialplan", show_cache_usage }; +static struct ast_cli_entry cli_show_peer = + { { "iax2", "show", "peer", NULL }, iax2_show_peer, "Show details on specific IAX peer", show_peer_usage }; static unsigned int calc_rxstamp(struct chan_iax2_pvt *p, unsigned int offset); @@ -2099,11 +2194,13 @@ } -static int create_addr(struct sockaddr_in *sin, int *capability, int *sendani, int *maxtime, char *peer, char *context, int *trunk, int *notransfer, int *usejitterbuf, char *username, int usernlen, char *secret, int seclen, int *ofound, char *peercontext, char *timezone, int tzlen) +static int create_addr(struct sockaddr_in *sin, int *capability, int *sendani, int *maxtime, char *peer, char *context, int *trunk, int *notransfer, int *usejitterbuf, char *username, int usernlen, char *secret, int seclen, int *ofound, char *peercontext, char *timezone, int tzlen, char *pref_str, size_t pref_size) { struct ast_hostent ahp; struct hostent *hp; struct iax2_peer *p; int found=0; + struct ast_codec_pref *pref; + if (sendani) *sendani = 0; if (maxtime) @@ -2126,6 +2223,11 @@ found++; if ((p->addr.sin_addr.s_addr || p->defaddr.sin_addr.s_addr) && (!p->maxms || ((p->lastms > 0) && (p->lastms <= p->maxms)))) { + + if(pref_str) { + pref = (ast_codec_pref_inuse(&p->prefs)) ? &p->prefs : &prefs; + ast_codec_pref_shift(pref, pref_str, pref_size, 1); + } if (sendani) *sendani = p->sendani; /* Whether we transmit ANI */ if (maxtime) @@ -2250,6 +2352,10 @@ char *stringp=NULL; char storedusern[80], storedsecret[80]; char tz[80] = ""; + char out_prefs[32]; + + memset(out_prefs,0,32); + if ((c->_state != AST_STATE_DOWN) && (c->_state != AST_STATE_RESERVED)) { ast_log(LOG_WARNING, "Line is already in use (%s)?\n", c->name); return -1; @@ -2291,7 +2397,7 @@ strsep(&stringp, ":"); portno = strsep(&stringp, ":"); } - if (create_addr(&sin, NULL, NULL, NULL, hname, context, NULL, NULL, NULL, storedusern, sizeof(storedusern) - 1, storedsecret, sizeof(storedsecret) - 1, NULL, peercontext, tz, sizeof(tz))) { + if (create_addr(&sin, NULL, NULL, NULL, hname, context, NULL, NULL, NULL, storedusern, sizeof(storedusern) - 1, storedsecret, sizeof(storedsecret) - 1, NULL, peercontext, tz, sizeof(tz), out_prefs, sizeof(out_prefs))) { ast_log(LOG_WARNING, "No address associated with '%s'\n", hname); return -1; } @@ -2311,6 +2417,8 @@ /* Request auto answer */ iax_ie_append(&ied, IAX_IE_AUTOANSWER); } + iax_ie_append_str(&ied, IAX_IE_CODEC_PREFS, out_prefs); + if (l) { iax_ie_append_str(&ied, IAX_IE_CALLING_NUMBER, l); iax_ie_append_byte(&ied, IAX_IE_CALLINGPRES, c->cid.cid_pres); @@ -3590,7 +3698,7 @@ int gotcapability=0; char iabuf[INET_ADDRSTRLEN]; struct ast_variable *v = NULL, *tmpvar = NULL; - + if (!iaxs[callno]) return res; if (ies->called_number) @@ -3627,6 +3735,10 @@ } if (ies->version) version = ies->version; + + if(ies->codec_prefs) + ast_codec_pref_shift(&iaxs[callno]->prefs, ies->codec_prefs, 32, 0); + if (!gotcapability) iaxs[callno]->peercapability = iaxs[callno]->peerformat; if (version > IAX_PROTO_VERSION) { @@ -3699,6 +3811,8 @@ iaxs[callno]->vars = tmpvar; } } + if(ast_codec_pref_inuse(&user->prefs)) + iaxs[callno]->prefs = user->prefs; /* Store the requested username if not specified */ if (ast_strlen_zero(iaxs[callno]->username)) @@ -5041,6 +5155,9 @@ unsigned int ts; char empty[32]=""; /* Safety measure */ struct iax_frame *duped_fr; + char my_pref_buf[128]; + char his_pref_buf[128]; + struct ast_codec_pref pref; dblbuf[0] = 0; /* Keep GCC from whining */ fr.callno = 0; @@ -5465,9 +5582,22 @@ ast_log(LOG_NOTICE, "Rejected connect attempt from %s, request '%s@%s' does not exist\n", ast_inet_ntoa(iabuf, sizeof(iabuf), sin.sin_addr), iaxs[fr.callno]->exten, iaxs[fr.callno]->context); } else { /* Select an appropriate format */ - format = iaxs[fr.callno]->peerformat & iaxs[fr.callno]->capability; + if(ies.codec_prefs) + ast_codec_pref_shift(&pref, ies.codec_prefs, 32, 0); + else + pref = ast_codec_pref_inuse(&iaxs[fr.callno]->prefs) ? iaxs[fr.callno]->prefs : prefs; + + + //format = iaxs[fr.callno]->peerformat & iaxs[fr.callno]->capability; + format = ast_codec_choose(&pref, iaxs[fr.callno]->capability, 0); + ast_codec_pref_string(&pref, his_pref_buf, sizeof(his_pref_buf) - 1); + ast_codec_pref_string(ast_codec_pref_inuse(&iaxs[fr.callno]->prefs) ? &iaxs[fr.callno]->prefs : &prefs, + my_pref_buf, sizeof(my_pref_buf) - 1); + + if (!format) { format = iaxs[fr.callno]->peercapability & iaxs[fr.callno]->capability; + if (!format) { memset(&ied0, 0, sizeof(ied0)); iax_ie_append_str(&ied0, IAX_IE_CAUSE, "Unable to negotiate codec"); @@ -5476,7 +5606,12 @@ ast_log(LOG_NOTICE, "Rejected connect attempt from %s, requested/capability 0x%x/0x%x incompatible with our capability 0x%x.\n", ast_inet_ntoa(iabuf, sizeof(iabuf), sin.sin_addr), iaxs[fr.callno]->peerformat, iaxs[fr.callno]->peercapability, iaxs[fr.callno]->capability); } else { /* Pick one... */ - format = ast_best_codec(iaxs[fr.callno]->peercapability & iaxs[fr.callno]->capability); + if(ies.codec_prefs) + format = ast_codec_choose(ast_codec_pref_inuse(&iaxs[fr.callno]->prefs) ? &iaxs[fr.callno]->prefs : &prefs, + iaxs[fr.callno]->peercapability & iaxs[fr.callno]->capability, 1); + else + format = ast_best_codec(iaxs[fr.callno]->peercapability & iaxs[fr.callno]->capability); + if (!format) { memset(&ied0, 0, sizeof(ied0)); iax_ie_append_str(&ied0, IAX_IE_CAUSE, "Unable to negotiate codec"); @@ -5497,8 +5632,8 @@ if (strcmp(iaxs[fr.callno]->exten, "TBD")) { iaxs[fr.callno]->state |= IAX_STATE_STARTED; if (option_verbose > 2) - ast_verbose(VERBOSE_PREFIX_3 "Accepting unauthenticated call from %s, requested format = %d, actual format = %d\n", - ast_inet_ntoa(iabuf, sizeof(iabuf), sin.sin_addr), iaxs[fr.callno]->peerformat,format); + ast_verbose(VERBOSE_PREFIX_3 "Accepting unauthenticated call from %s, requested format = %s, requested prefs = %s, actual format = %s, my prefs = %s\n", + ast_inet_ntoa(iabuf, sizeof(iabuf), sin.sin_addr), ast_getformatname(iaxs[fr.callno]->peerformat), his_pref_buf, ast_getformatname(format), my_pref_buf); if(!(c = ast_iax2_new(fr.callno, AST_STATE_RING, format))) iax2_destroy_nolock(fr.callno); } else { @@ -5761,10 +5896,23 @@ send_command_final(iaxs[fr.callno], AST_FRAME_IAX, IAX_COMMAND_REJECT, 0, ied0.buf, ied0.pos, -1); } else { /* Select an appropriate format */ - format = iaxs[fr.callno]->peerformat & iaxs[fr.callno]->capability; + if(ies.codec_prefs) + ast_codec_pref_shift(&pref, ies.codec_prefs, 32, 0); + else + pref = ast_codec_pref_inuse(&iaxs[fr.callno]->prefs) ? iaxs[fr.callno]->prefs : prefs; + + //format = iaxs[fr.callno]->peerformat & iaxs[fr.callno]->capability; + format = ast_codec_choose(&pref, iaxs[fr.callno]->capability, 0); + ast_codec_pref_string(&pref, his_pref_buf, sizeof(his_pref_buf) - 1); + ast_codec_pref_string(ast_codec_pref_inuse(&iaxs[fr.callno]->prefs) ? &iaxs[fr.callno]->prefs : &prefs, + my_pref_buf, sizeof(my_pref_buf) - 1); + + + if (!format) { ast_log(LOG_DEBUG, "We don't do requested format %s, falling back to peer capability %d\n", ast_getformatname(iaxs[fr.callno]->peerformat), iaxs[fr.callno]->peercapability); format = iaxs[fr.callno]->peercapability & iaxs[fr.callno]->capability; + if (!format) { if (authdebug) ast_log(LOG_NOTICE, "Rejected connect attempt from %s, requested/capability 0x%x/0x%x incompatible with our capability 0x%x.\n", ast_inet_ntoa(iabuf, sizeof(iabuf), sin.sin_addr), iaxs[fr.callno]->peerformat, iaxs[fr.callno]->peercapability, iaxs[fr.callno]->capability); @@ -5773,7 +5921,12 @@ send_command_final(iaxs[fr.callno], AST_FRAME_IAX, IAX_COMMAND_REJECT, 0, ied0.buf, ied0.pos, -1); } else { /* Pick one... */ - format = ast_best_codec(iaxs[fr.callno]->peercapability & iaxs[fr.callno]->capability); + if(ies.codec_prefs) + format = ast_codec_choose(ast_codec_pref_inuse(&iaxs[fr.callno]->prefs) ? &iaxs[fr.callno]->prefs : &prefs, + iaxs[fr.callno]->peercapability & iaxs[fr.callno]->capability, 1); + else + format = ast_best_codec(iaxs[fr.callno]->peercapability & iaxs[fr.callno]->capability); + if (!format) { ast_log(LOG_ERROR, "No best format in 0x%x???\n", iaxs[fr.callno]->peercapability & iaxs[fr.callno]->capability); if (authdebug) @@ -5792,8 +5945,9 @@ if (strcmp(iaxs[fr.callno]->exten, "TBD")) { iaxs[fr.callno]->state |= IAX_STATE_STARTED; if (option_verbose > 2) - ast_verbose(VERBOSE_PREFIX_3 "Accepting AUTHENTICATED call from %s, requested format = %d, actual format = %d\n", - ast_inet_ntoa(iabuf, sizeof(iabuf), sin.sin_addr), iaxs[fr.callno]->peerformat,format); + ast_verbose(VERBOSE_PREFIX_3 "Accepting AUTHENTICATED call from %s, requested format = %s, requested prefs = %s, actual format = %s, my prefs = %s\n", + ast_inet_ntoa(iabuf, sizeof(iabuf), sin.sin_addr), ast_getformatname(iaxs[fr.callno]->peerformat), + his_pref_buf, ast_getformatname(format), my_pref_buf); iaxs[fr.callno]->state |= IAX_STATE_STARTED; if(!(c = ast_iax2_new(fr.callno, AST_STATE_RING, format))) iax2_destroy_nolock(fr.callno); @@ -6128,7 +6282,7 @@ if (end) memcpy(&sin, end, sizeof(sin)); else { - if (create_addr(&sin, NULL, NULL, NULL, dest, NULL, NULL, NULL, NULL, NULL, 0, NULL, 0, NULL, NULL, NULL, 0)) + if (create_addr(&sin, NULL, NULL, NULL, dest, NULL, NULL, NULL, NULL, NULL, 0, NULL, 0, NULL, NULL, NULL, 0, NULL, 0)) return -1; } /* Build the rest of the message */ @@ -6283,7 +6437,7 @@ } /* Populate our address from the given */ - if (create_addr(&sin, &capability, &sendani, &maxtime, hostname, NULL, &trunk, ¬ransfer, &usejitterbuf, NULL, 0, NULL, 0, &found, NULL, NULL, 0)) { + if (create_addr(&sin, &capability, &sendani, &maxtime, hostname, NULL, &trunk, ¬ransfer, &usejitterbuf, NULL, 0, NULL, 0, &found, NULL, NULL, 0, NULL, 0)) { *cause = AST_CAUSE_UNREGISTERED; return NULL; } @@ -6414,6 +6568,7 @@ return methods; } + static struct iax2_peer *build_peer(const char *name, struct ast_variable *v, int temponly) { struct iax2_peer *peer; @@ -6459,7 +6614,9 @@ peer->messagedetail = globalmessagedetail; peer->usejitterbuf = globalusejitterbuf; peer->secret[0] = '\0'; - if (!found) { + if (found) + memset(&peer->prefs, 0, sizeof(struct ast_codec_pref)); + else { strncpy(peer->name, name, sizeof(peer->name)-1); peer->addr.sin_port = htons(IAX_DEFAULT_PORTNO); peer->expirey = expirey; @@ -6544,17 +6701,15 @@ } else if (!strcasecmp(v->name, "username")) { strncpy(peer->username, v->value, sizeof(peer->username)-1); } else if (!strcasecmp(v->name, "allow")) { - format = ast_getformatbyname(v->value); - if (format < 1) - ast_log(LOG_WARNING, "Cannot allow unknown format '%s'\n", v->value); - else + ast_mutex_lock(&peerl.lock); + if((format = ast_parse_allow(&peer->prefs, v->value, 1))) peer->capability |= format; + ast_mutex_unlock(&peerl.lock); } else if (!strcasecmp(v->name, "disallow")) { - format = ast_getformatbyname(v->value); - if (format < 1) - ast_log(LOG_WARNING, "Cannot disallow unknown format '%s'\n", v->value); - else + ast_mutex_lock(&peerl.lock); + if((format = ast_parse_allow(&peer->prefs, v->value, 0))) peer->capability &= ~format; + ast_mutex_unlock(&peerl.lock); } else if (!strcasecmp(v->name, "callerid")) { ast_callerid_split(v->value, peer->cid_name, sizeof(peer->cid_name), peer->cid_num, sizeof(peer->cid_num)); @@ -6667,17 +6822,15 @@ } } } else if (!strcasecmp(v->name, "allow")) { - format = ast_getformatbyname(v->value); - if (format < 1) - ast_log(LOG_WARNING, "Cannot allow unknown format '%s'\n", v->value); - else + ast_mutex_lock(&userl.lock); + if((format = ast_parse_allow(&user->prefs, v->value, 1))) user->capability |= format; + ast_mutex_unlock(&userl.lock); } else if (!strcasecmp(v->name, "disallow")) { - format = ast_getformatbyname(v->value); - if (format < 1) - ast_log(LOG_WARNING, "Cannot disallow unknown format '%s'\n", v->value); - else + ast_mutex_lock(&userl.lock); + if((format = ast_parse_allow(&user->prefs, v->value, 0))) user->capability &= ~format; + ast_mutex_unlock(&userl.lock); } else if (!strcasecmp(v->name, "trunk")) { user->trunk = ast_true(v->value); if (user->trunk && (timingfd < 0)) { @@ -6951,16 +7104,10 @@ } else ast_log(LOG_WARNING, "bandwidth must be either low, medium, or high\n"); } else if (!strcasecmp(v->name, "allow")) { - format = ast_getformatbyname(v->value); - if (format < 1) - ast_log(LOG_WARNING, "Cannot allow unknown format '%s'\n", v->value); - else + if((format = ast_parse_allow(&prefs, v->value, 1))) capability |= format; } else if (!strcasecmp(v->name, "disallow")) { - format = ast_getformatbyname(v->value); - if (format < 1) - ast_log(LOG_WARNING, "Cannot disallow unknown format '%s'\n", v->value); - else + if((format = ast_parse_allow(&prefs, v->value, 0))) capability &= ~format; } else if (!strcasecmp(v->name, "register")) { iax2_register(v->value, v->lineno); @@ -7043,6 +7190,7 @@ struct iax2_registry *reg; struct sockaddr_in dead_sin; struct iax2_peer *peer; + memset(&prefs, 0 , sizeof(struct ast_codec_pref)); strncpy(accountcode, "", sizeof(accountcode)-1); strncpy(language, "", sizeof(language)-1); amaflags = 0; @@ -7119,7 +7267,7 @@ host = st; } /* Populate our address from the given */ - if (create_addr(&sin, NULL, NULL, NULL, host, NULL, NULL, NULL, NULL, NULL, 0, NULL, 0, NULL, NULL, NULL, 0)) { + if (create_addr(&sin, NULL, NULL, NULL, host, NULL, NULL, NULL, NULL, NULL, 0, NULL, 0, NULL, NULL, NULL, 0, NULL, 0)) { return -1; } ast_log(LOG_DEBUG, "host: %s, user: %s, password: %s, context: %s\n", host, username, password, context); @@ -7460,6 +7608,7 @@ ast_cli_unregister(&cli_set_jitter); ast_cli_unregister(&cli_show_stats); ast_cli_unregister(&cli_show_cache); + ast_cli_unregister(&cli_show_peer); ast_unregister_switch(&iax2_switch); ast_channel_unregister(type); delete_users(); @@ -7487,6 +7636,7 @@ struct sockaddr_in sin; + memset(&prefs, 0 , sizeof(struct ast_codec_pref)); iax_set_output(iax_debug_output); iax_set_error(iax_error_output); @@ -7538,6 +7688,7 @@ ast_cli_register(&cli_set_jitter); ast_cli_register(&cli_show_stats); ast_cli_register(&cli_show_cache); + ast_cli_register(&cli_show_peer); ast_manager_register( "IAXpeers", 0, manager_iax2_show_peers, "List IAX Peers" ); Index: channels/chan_sip.c =================================================================== RCS file: /usr/cvsroot/asterisk/channels/chan_sip.c,v retrieving revision 1.577 diff -u -r1.577 chan_sip.c --- channels/chan_sip.c 28 Nov 2004 21:49:07 -0000 1.577 +++ channels/chan_sip.c 1 Dec 2004 18:35:34 -0000 @@ -163,6 +163,7 @@ static int usecnt =0; AST_MUTEX_DEFINE_STATIC(usecnt_lock); + /* Protect the interface list (of sip_pvt's) */ AST_MUTEX_DEFINE_STATIC(iflock); @@ -220,10 +221,8 @@ #define DEC_OUT_USE 2 #define INC_OUT_USE 3 -static struct sip_codec_pref { - int codec; - struct sip_codec_pref *next; -} *prefs; +static struct ast_codec_pref prefs; + /* sip_request: The data grabbed from the UDP socket */ struct sip_request { @@ -254,6 +253,7 @@ ast_mutex_t lock; /* Channel private lock */ char callid[80]; /* Global CallID */ char randdata[80]; /* Random data */ + struct ast_codec_pref prefs; /* codec prefs */ unsigned int ocseq; /* Current outgoing seqno */ unsigned int icseq; /* Current incoming seqno */ unsigned int callgroup; /* Call group */ @@ -265,7 +265,6 @@ int novideo; /* Didn't get video in invite, don't offer */ int jointcapability; /* Supported capability at both ends (codecs ) */ int peercapability; /* Supported peer capability */ - int prefcodec; /* Preferred codec (outbound only) */ int noncodeccapability; int callingpres; /* Calling presentation */ int outgoing; /* Outgoing or incoming call? */ @@ -391,6 +390,7 @@ char language[MAX_LANGUAGE]; /* Default language for this user */ char musicclass[MAX_LANGUAGE]; /* Music on Hold class */ char useragent[256]; /* User agent in SIP request */ + struct ast_codec_pref prefs; /* codec prefs */ unsigned int callgroup; /* Call group */ unsigned int pickupgroup; /* Pickup Group */ int nat; /* NAT setting */ @@ -435,6 +435,7 @@ char language[MAX_LANGUAGE]; /* Default language for prompts */ char musicclass[MAX_LANGUAGE]; /* Music on Hold class */ char useragent[256]; /* User agent in SIP request (saved from registration) */ + struct ast_codec_pref prefs; /* codec prefs */ int lastmsgssent; time_t lastmsgcheck; /* Last time we checked for MWI */ int dynamic; /* Dynamic? Yes or no. Dynamic hosts register with us */ @@ -1364,71 +1365,8 @@ return 0; } -/*--- sip_prefs_free: Free codec list in preference structure ---*/ -static void sip_prefs_free(void) -{ - struct sip_codec_pref *cur, *next; - cur = prefs; - while(cur) { - next = cur->next; - free(cur); - cur = next; - } - prefs = NULL; -} - -/*--- sip_pref_remove: Remove codec from pref list ---*/ -static void sip_pref_remove(int format) -{ - struct sip_codec_pref *cur, *prev=NULL; - cur = prefs; - while(cur) { - if (cur->codec == format) { - if (prev) - prev->next = cur->next; - else - prefs = cur->next; - free(cur); - return; - } - prev = cur; - cur = cur->next; - } -} -/*--- sip_pref_append: Append codec to list ---*/ -static int sip_pref_append(int format) -{ - struct sip_codec_pref *cur, *tmp; - sip_pref_remove(format); - tmp = (struct sip_codec_pref *)malloc(sizeof(struct sip_codec_pref)); - if (!tmp) - return -1; - memset(tmp, 0, sizeof(struct sip_codec_pref)); - tmp->codec = format; - if (prefs) { - cur = prefs; - while(cur->next) - cur = cur->next; - cur->next = tmp; - } else - prefs = tmp; - return 0; -} -/*--- sip_codec_choose: Pick a codec ---*/ -static int sip_codec_choose(int formats) -{ - struct sip_codec_pref *cur; - formats &= ((AST_FORMAT_MAX_AUDIO << 1) - 1); - cur = prefs; - while(cur) { - if (formats & cur->codec) - return cur->codec; - cur = cur->next; - } - return ast_best_codec(formats); -} /*--- sip_call: Initiate SIP call from PBX ---*/ /* used from the dial() application */ @@ -1985,12 +1923,14 @@ if (tmp) { /* Select our native format based on codec preference until we receive something from another device to the contrary. */ + ast_mutex_lock(&i->lock); if (i->jointcapability) - tmp->nativeformats = sip_codec_choose(i->jointcapability); + tmp->nativeformats = ast_codec_choose(ast_codec_pref_inuse(&i->prefs) ? &i->prefs : &prefs, i->jointcapability, 1); else if (i->capability) - tmp->nativeformats = sip_codec_choose(i->capability); + tmp->nativeformats = ast_codec_choose(ast_codec_pref_inuse(&i->prefs) ? &i->prefs : &prefs, i->capability, 1); else - tmp->nativeformats = sip_codec_choose(global_capability); + tmp->nativeformats = ast_codec_choose(ast_codec_pref_inuse(&i->prefs) ? &i->prefs : &prefs, global_capability, 1); + ast_mutex_unlock(&i->lock); fmt = ast_best_codec(tmp->nativeformats); if (title) snprintf(tmp->name, sizeof(tmp->name), "SIP/%s-%04x", title, rand() & 0xffff); @@ -2083,6 +2023,7 @@ } for (v = i->vars ; v ; v = v->next) pbx_builtin_setvar_helper(tmp,v->name,v->value); + } else ast_log(LOG_WARNING, "Unable to allocate channel structure\n"); return tmp; @@ -2291,9 +2232,11 @@ /* Keep track of stuff */ memset(p, 0, sizeof(struct sip_pvt)); ast_mutex_init(&p->lock); + p->initid = -1; p->autokillid = -1; p->stateid = -1; + p->prefs = prefs; #ifdef OSP_SUPPORT p->osphandle = -1; #endif @@ -2770,7 +2713,8 @@ p->noncodeccapability = noncodeccapability & peernoncodeccapability; if (debug) { - const unsigned slen=80; + /* shame on whoever coded this.... */ + const unsigned slen=512; char s1[slen], s2[slen], s3[slen], s4[slen]; ast_verbose("Capabilities: us - %s, peer - audio=%s/video=%s, combined - %s\n", @@ -2790,12 +2734,14 @@ } if (p->owner) { if (!(p->owner->nativeformats & p->jointcapability)) { - const unsigned slen=80; + const unsigned slen=512; char s1[slen], s2[slen]; ast_log(LOG_DEBUG, "Oooh, we need to change our formats since our peer supports only %s and not %s\n", ast_getformatname_multiple(s1, slen, p->jointcapability), ast_getformatname_multiple(s2, slen, p->owner->nativeformats)); - p->owner->nativeformats = sip_codec_choose(p->jointcapability); + ast_mutex_lock(&p->lock); + p->owner->nativeformats = ast_codec_choose(ast_codec_pref_inuse(&p->prefs) ? &p->prefs : &prefs, p->jointcapability, 1); + ast_mutex_unlock(&p->lock); ast_set_read_format(p->owner, p->owner->readformat); ast_set_write_format(p->owner, p->owner->writeformat); } @@ -3336,13 +3282,14 @@ /*--- add_sdp: Add Session Description Protocol message ---*/ static int add_sdp(struct sip_request *resp, struct sip_pvt *p) { - int len; - int codec; + int len = 0; + int codec = 0; + int pref_codec = 0; int alreadysent = 0; char costr[80]; struct sockaddr_in sin; struct sockaddr_in vsin; - struct sip_codec_pref *cur; + struct ast_codec_pref *cur = NULL; char v[256] = ""; char s[256] = ""; char o[256] = ""; @@ -3353,11 +3300,13 @@ char a[1024] = ""; char a2[1024] = ""; char iabuf[INET_ADDRSTRLEN]; - int x; - int capability; + int x = 0; + int capability = 0 ; struct sockaddr_in dest; struct sockaddr_in vdest = { 0, }; - int debug=sip_debug_test_pvt(p); + int debug=0; + + debug = sip_debug_test_pvt(p); /* XXX We break with the "recommendation" and send our IP, in order that our peer doesn't have to ast_gethostbyname() us XXX */ @@ -3409,52 +3358,36 @@ snprintf(t, sizeof(t), "t=0 0\r\n"); snprintf(m, sizeof(m), "m=audio %d RTP/AVP", ntohs(dest.sin_port)); snprintf(m2, sizeof(m2), "m=video %d RTP/AVP", ntohs(vdest.sin_port)); - if (capability & p->prefcodec) { - if (debug) - ast_verbose("Answering/Requesting with root capability %d\n", p->prefcodec); - codec = ast_rtp_lookup_code(p->rtp, 1, p->prefcodec); - if (codec > -1) { - snprintf(costr, sizeof(costr), " %d", codec); - if (p->prefcodec <= AST_FORMAT_MAX_AUDIO) { - strncat(m, costr, sizeof(m) - strlen(m) - 1); - snprintf(costr, sizeof(costr), "a=rtpmap:%d %s/8000\r\n", codec, ast_rtp_lookup_mime_subtype(1, p->prefcodec)); - strncpy(a, costr, sizeof(a) - 1); - } else { - strncat(m2, costr, sizeof(m2) - strlen(m2) - 1); - snprintf(costr, sizeof(costr), "a=rtpmap:%d %s/90000\r\n", codec, ast_rtp_lookup_mime_subtype(1, p->prefcodec)); - strncpy(a2, costr, sizeof(a2) - 1); - } - } - alreadysent |= p->prefcodec; - } /* Start by sending our preferred codecs */ - cur = prefs; - while(cur) { - if ((capability & cur->codec) && !(alreadysent & cur->codec)) { - if (debug) - ast_verbose("Answering with preferred capability 0x%x(%s)\n", cur->codec, ast_getformatname(cur->codec)); - codec = ast_rtp_lookup_code(p->rtp, 1, cur->codec); - if (codec > -1) { - snprintf(costr, sizeof(costr), " %d", codec); - if (cur->codec <= AST_FORMAT_MAX_AUDIO) { - strncat(m, costr, sizeof(m) - strlen(m) - 1); - snprintf(costr, sizeof(costr), "a=rtpmap:%d %s/8000\r\n", codec, ast_rtp_lookup_mime_subtype(1, cur->codec)); - strncat(a, costr, sizeof(a) - strlen(a) - 1); - } else { - strncat(m2, costr, sizeof(m2) - strlen(m2) - 1); - snprintf(costr, sizeof(costr), "a=rtpmap:%d %s/90000\r\n", codec, ast_rtp_lookup_mime_subtype(1, cur->codec)); - strncat(a2, costr, sizeof(a2) - strlen(a) - 1); + if((cur = ast_codec_pref_inuse(&p->prefs) ? &p->prefs : &prefs)) { + for (x = 0 ; x < 32 ; x++) { + if(!(pref_codec = ast_codec_pref_index(cur,x))) + break; + if ((capability & pref_codec) && !(alreadysent & pref_codec)) { + if (debug) + ast_verbose("Answering with preferred capability 0x%x (%s)\n", pref_codec, ast_getformatname(pref_codec)); + codec = ast_rtp_lookup_code(p->rtp, 1, pref_codec); + if (codec > -1) { + snprintf(costr, sizeof(costr), " %d", codec); + if (pref_codec <= AST_FORMAT_MAX_AUDIO) { + strncat(m, costr, sizeof(m) - strlen(m) - 1); + snprintf(costr, sizeof(costr), "a=rtpmap:%d %s/8000\r\n", codec, ast_rtp_lookup_mime_subtype(1, pref_codec)); + strncat(a, costr, sizeof(a) - strlen(a) - 1); + } else { + strncat(m2, costr, sizeof(m2) - strlen(m2) - 1); + snprintf(costr, sizeof(costr), "a=rtpmap:%d %s/90000\r\n", codec, ast_rtp_lookup_mime_subtype(1, pref_codec)); + strncat(a2, costr, sizeof(a2) - strlen(a) - 1); + } } } + alreadysent |= pref_codec; } - alreadysent |= cur->codec; - cur = cur->next; } /* Now send any other common codecs, and non-codec formats: */ for (x = 1; x <= ((videosupport && p->vrtp) ? AST_FORMAT_MAX_VIDEO : AST_FORMAT_MAX_AUDIO); x <<= 1) { if ((capability & x) && !(alreadysent & x)) { if (debug) - ast_verbose("Answering with capability 0x%x(%s)\n", x, ast_getformatname(x)); + ast_verbose("Answering with capability 0x%x (%s)\n", x, ast_getformatname(x)); codec = ast_rtp_lookup_code(p->rtp, 1, x); if (codec > -1) { snprintf(costr, sizeof(costr), " %d", codec); @@ -3473,7 +3406,7 @@ for (x = 1; x <= AST_RTP_MAX; x <<= 1) { if (p->noncodeccapability & x) { if (debug) - ast_verbose("Answering with non-codec capability 0x%x(%s)\n", x, ast_getformatname(x)); + ast_verbose("Answering with non-codec capability 0x%x (%s)\n", x, ast_rtp_lookup_mime_subtype(0, x)); codec = ast_rtp_lookup_code(p->rtp, 0, x); if (codec > -1) { snprintf(costr, sizeof(costr), " %d", codec); @@ -5349,6 +5282,9 @@ p->vars = tmpvar; } } + if(ast_codec_pref_inuse(&user->prefs)) + p->prefs = user->prefs; + p->nat = user->nat; #ifdef OSP_SUPPORT p->ospauth = user->ospauth; @@ -5700,7 +5636,7 @@ snprintf(srch, sizeof(srch), FORMAT, name, peer->addr.sin_addr.s_addr ? ast_inet_ntoa(iabuf, sizeof(iabuf), peer->addr.sin_addr) : "(Unspecified)", peer->dynamic ? " D " : " ", /* Dynamic or not? */ - (peer->nat & SIP_NAT_ROUTE) ? " N " : " ", /* NAT=yes? */ + (peer->nat & SIP_NAT_ROUTE) ? " Y " : " ", /* NAT=yes? */ peer->ha ? " A " : " ", /* permit/deny */ nm, ntohs(peer->addr.sin_port), status); @@ -5760,6 +5696,9 @@ char cbuf[256]; char iabuf[INET_ADDRSTRLEN]; struct sip_peer *peer; + char codec_buf[512]; + struct ast_codec_pref *pref; + int x = 0, codec = 0; if (argc != 4) return RESULT_SHOWUSAGE; @@ -5805,38 +5744,23 @@ ast_cli(fd, " Defaddr->IP : %s Port %d\n", ast_inet_ntoa(iabuf, sizeof(iabuf), peer->defaddr.sin_addr), ntohs(peer->defaddr.sin_port)); ast_cli(fd, " Username : %s\n", peer->username); ast_cli(fd, " Codecs : "); - /* This should really be a function in frame.c */ - if (peer->capability & AST_FORMAT_G723_1) - ast_cli(fd, "G723 "); - if (peer->capability & AST_FORMAT_GSM) - ast_cli(fd, "GSM "); - if (peer->capability & AST_FORMAT_ULAW) - ast_cli(fd, "ULAW "); - if (peer->capability & AST_FORMAT_ALAW) - ast_cli(fd, "ALAW "); - if (peer->capability & AST_FORMAT_G726) - ast_cli(fd, "G.726 "); - if (peer->capability & AST_FORMAT_SLINEAR) - ast_cli(fd, "SLINR "); - if (peer->capability & AST_FORMAT_LPC10) - ast_cli(fd, "LPC10 "); - if (peer->capability & AST_FORMAT_ADPCM) - ast_cli(fd, "ADPCM "); - if (peer->capability & AST_FORMAT_G729A) - ast_cli(fd, "G.729A "); - if (peer->capability & AST_FORMAT_SPEEX) - ast_cli(fd, "SPEEX "); - if (peer->capability & AST_FORMAT_ILBC) - ast_cli(fd, "ILBC "); - if (peer->capability & AST_FORMAT_JPEG) - ast_cli(fd, "JPEG "); - if (peer->capability & AST_FORMAT_PNG) - ast_cli(fd, "PNG "); - if (peer->capability & AST_FORMAT_H261) - ast_cli(fd, "H.261 "); - if (peer->capability & AST_FORMAT_H263) - ast_cli(fd, "H.263 "); - ast_cli(fd, "\n"); + ast_getformatname_multiple(codec_buf, sizeof(codec_buf) -1, peer->capability); + ast_cli(fd, "%s\n", codec_buf); + ast_cli(fd, " Codec Order : ("); + pref = ast_codec_pref_inuse(&peer->prefs) ? &peer->prefs : &prefs; + for(x = 0; x < 32 ; x++) { + codec = ast_codec_pref_index(pref,x); + if(!codec) + break; + ast_cli(fd, "%s", ast_getformatname(codec)); + if(x < 31 && ast_codec_pref_index(pref,x+1)) + ast_cli(fd, "|"); + } + + if (!ast_codec_pref_inuse(&peer->prefs) && !ast_codec_pref_inuse(&prefs)) + ast_cli(fd, "none"); + ast_cli(fd, ")\n"); + ast_cli(fd, " Status : "); if (peer->lastms < 0) strncpy(status, "UNREACHABLE", sizeof(status) - 1); @@ -8154,7 +8078,6 @@ #if 0 printf("Setting up to call extension '%s' at '%s'\n", ext ? ext : "", host); #endif - p->prefcodec = format; ast_mutex_lock(&p->lock); tmpc = sip_new(p, AST_STATE_DOWN, host); ast_mutex_unlock(&p->lock); @@ -8271,17 +8194,15 @@ user->amaflags = format; } } else if (!strcasecmp(v->name, "allow")) { - format = ast_getformatbyname(v->value); - if (format < 1) - ast_log(LOG_WARNING, "Cannot allow unknown format '%s'\n", v->value); - else + ast_mutex_lock(&userl.lock); + if((format = ast_parse_allow(&user->prefs, v->value, 1))) user->capability |= format; + ast_mutex_unlock(&userl.lock); } else if (!strcasecmp(v->name, "disallow")) { - format = ast_getformatbyname(v->value); - if (format < 1) - ast_log(LOG_WARNING, "Cannot disallow unknown format '%s'\n", v->value); - else + ast_mutex_lock(&userl.lock); + if((format = ast_parse_allow(&user->prefs, v->value, 0))) user->capability &= ~format; + ast_mutex_unlock(&userl.lock); } else if (!strcasecmp(v->name, "insecure")) { user->insecure = ast_true(v->value); } else if (!strcasecmp(v->name, "callingpres")) { @@ -8324,6 +8245,7 @@ peer = malloc(sizeof(struct sip_peer)); if (!peer) return NULL; + memset(peer, 0, sizeof(struct sip_peer)); peer->expire = -1; peer->pokeexpire = -1; @@ -8397,7 +8319,9 @@ } if (peer) { peer->lastmsgssent = -1; - if (!found) { + if (found) + memset(&peer->prefs, 0, sizeof(struct ast_codec_pref)); + else { strncpy(peer->name, name, sizeof(peer->name)-1); strncpy(peer->context, default_context, sizeof(peer->context)-1); strncpy(peer->language, default_language, sizeof(peer->language)-1); @@ -8521,17 +8445,15 @@ } else if (!strcasecmp(v->name, "pickupgroup")) { peer->pickupgroup = ast_get_group(v->value); } else if (!strcasecmp(v->name, "allow")) { - format = ast_getformatbyname(v->value); - if (format < 1) - ast_log(LOG_WARNING, "Cannot allow unknown format '%s'\n", v->value); - else + ast_mutex_lock(&peerl.lock); + if((format = ast_parse_allow(&peer->prefs, v->value, 1))) peer->capability |= format; + ast_mutex_unlock(&peerl.lock); } else if (!strcasecmp(v->name, "disallow")) { - format = ast_getformatbyname(v->value); - if (format < 1) - ast_log(LOG_WARNING, "Cannot disallow unknown format '%s'\n", v->value); - else + ast_mutex_lock(&peerl.lock); + if((format = ast_parse_allow(&peer->prefs, v->value, 0))) peer->capability &= ~format; + ast_mutex_unlock(&peerl.lock); } else if (!strcasecmp(v->name, "insecure")) { if (!strcasecmp(v->value, "very")) { peer->insecure = 2; @@ -8626,8 +8548,6 @@ } - sip_prefs_free(); - /* Reset IP addresses */ memset(&bindaddr, 0, sizeof(bindaddr)); memset(&localaddr, 0, sizeof(localaddr)); @@ -8794,21 +8714,11 @@ else memcpy(&externip.sin_addr, hp->h_addr, sizeof(externip.sin_addr)); } else if (!strcasecmp(v->name, "allow")) { - format = ast_getformatbyname(v->value); - if (format < 1) - ast_log(LOG_WARNING, "Cannot allow unknown format '%s'\n", v->value); - else { + if((format = ast_parse_allow(&prefs, v->value, 1))) global_capability |= format; - sip_pref_append(format); - } } else if (!strcasecmp(v->name, "disallow")) { - format = ast_getformatbyname(v->value); - if (format < 1) - ast_log(LOG_WARNING, "Cannot disallow unknown format '%s'\n", v->value); - else { + if((format = ast_parse_allow(&prefs, v->value, 0))) global_capability &= ~format; - sip_pref_remove(format); - } } else if (!strcasecmp(v->name, "register")) { sip_register(v->value, v->lineno); } else if (!strcasecmp(v->name, "recordhistory")) { @@ -9127,7 +9037,7 @@ struct sip_peer *peer; delete_users(); reload_config(); - + memset(&prefs, 0 , sizeof(struct ast_codec_pref)); prune_peers(); /* And start the monitor for the first time */ ast_mutex_lock(®l.lock); @@ -9171,9 +9081,11 @@ struct sip_peer *peer; struct sip_registry *reg; - ast_mutex_init(&userl.lock); - ast_mutex_init(&peerl.lock); - ast_mutex_init(®l.lock); + + memset(&prefs, 0 , sizeof(struct ast_codec_pref)); + ast_mutex_init(&userl.lock); + ast_mutex_init(&peerl.lock); + ast_mutex_init(®l.lock); sched = sched_context_create(); if (!sched) { ast_log(LOG_WARNING, "Unable to create schedule context\n"); @@ -9182,7 +9094,8 @@ if (!io) { ast_log(LOG_WARNING, "Unable to create I/O context\n"); } - + + res = reload_config(); if (!res) { /* Make sure we can register our sip channel type */ Index: channels/iax2-parser.c =================================================================== RCS file: /usr/cvsroot/asterisk/channels/iax2-parser.c,v retrieving revision 1.30 diff -u -r1.30 iax2-parser.c --- channels/iax2-parser.c 19 Nov 2004 21:52:25 -0000 1.30 +++ channels/iax2-parser.c 1 Dec 2004 18:35:35 -0000 @@ -64,6 +64,25 @@ output[maxlen] = '\0'; } +static void dump_prefs(char *output, int maxlen, void *value, int len) +{ + struct ast_codec_pref pref; + int total_len = 0; + + maxlen--; + total_len = maxlen; + + if (maxlen > len) + maxlen = len; + + strncpy(output,value, maxlen); + output[maxlen] = '\0'; + + ast_codec_pref_shift(&pref, output, total_len, 0); + memset(output,0,total_len); + ast_codec_pref_string(&pref, output, total_len); +} + static void dump_int(char *output, int maxlen, void *value, int len) { if (len == (int)sizeof(unsigned int)) @@ -189,6 +208,7 @@ { IAX_IE_CALLINGTON, "CALLING TYPEOFNUM", dump_byte }, { IAX_IE_CALLINGTNS, "CALLING TRANSITNET", dump_short }, { IAX_IE_SAMPLINGRATE, "SAMPLINGRATE", dump_samprate }, + { IAX_IE_CODEC_PREFS, "CODEC_PREFS", dump_prefs }, }; static struct iax2_ie prov_ies[] = { @@ -558,6 +578,9 @@ errorf(tmp); } else ies->format = ntohl(*((unsigned int *)(data + 2))); + break; + case IAX_IE_CODEC_PREFS: + ies->codec_prefs = data + 2; break; case IAX_IE_LANGUAGE: ies->language = data + 2; Index: channels/iax2-parser.h =================================================================== RCS file: /usr/cvsroot/asterisk/channels/iax2-parser.h,v retrieving revision 1.11 diff -u -r1.11 iax2-parser.h --- channels/iax2-parser.h 19 Nov 2004 21:52:25 -0000 1.11 +++ channels/iax2-parser.h 1 Dec 2004 18:35:35 -0000 @@ -27,6 +27,7 @@ char *password; unsigned int capability; unsigned int format; + char *codec_prefs; char *language; int version; unsigned short adsicpe; Index: channels/iax2.h =================================================================== RCS file: /usr/cvsroot/asterisk/channels/iax2.h,v retrieving revision 1.17 diff -u -r1.17 iax2.h --- channels/iax2.h 19 Nov 2004 21:52:25 -0000 1.17 +++ channels/iax2.h 1 Dec 2004 18:35:35 -0000 @@ -116,6 +116,7 @@ #define IAX_IE_CALLINGTON 39 /* Calling type of number (u8) */ #define IAX_IE_CALLINGTNS 40 /* Calling transit network select (u16) */ #define IAX_IE_SAMPLINGRATE 41 /* Supported sampling rates (u16) */ +#define IAX_IE_CODEC_PREFS 42 /* codec preference */ #define IAX_AUTH_PLAINTEXT (1 << 0) #define IAX_AUTH_MD5 (1 << 1)