diff options
author | russell <russell@f38db490-d61c-443f-a65b-d21fe96a405b> | 2004-12-05 05:17:51 +0000 |
---|---|---|
committer | russell <russell@f38db490-d61c-443f-a65b-d21fe96a405b> | 2004-12-05 05:17:51 +0000 |
commit | bcda3e822bef0b3c5daecd2a1471a4e7853dc49f (patch) | |
tree | 2a2cae28335a163c6a9cfa54cac37a7fa6592d1a | |
parent | 3d10e7bbb1153baa49672f656d81c15ba06b0759 (diff) |
merge codec preference changes for SIP
git-svn-id: http://svn.digium.com/svn/asterisk/branches/v1-0@4388 f38db490-d61c-443f-a65b-d21fe96a405b
-rwxr-xr-x | CHANGES | 4 | ||||
-rwxr-xr-x | channels/chan_sip.c | 243 | ||||
-rwxr-xr-x | frame.c | 443 | ||||
-rwxr-xr-x | include/asterisk/frame.h | 38 |
4 files changed, 434 insertions, 294 deletions
@@ -1,10 +1,12 @@ +Asterisk 1.0.3 -- chan_zap - -- seg fault fix + -- fix seg fault when doing *0 to flash a trunk -- rtp -- seg fault fix -- chan_sip -- fix to prevent seg fault when attempting a transfer -- fix bug with supervised transfers + -- fix codec preferences -- chan_h323 -- fix compilation problem -- chan_iax2 diff --git a/channels/chan_sip.c b/channels/chan_sip.c index 454975a8f..2fa0d7942 100755 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -170,6 +170,7 @@ static int global_ospauth = 0; static int usecnt =0; AST_MUTEX_DEFINE_STATIC(usecnt_lock); + /* Protect the interface list (of sip_pvt's) */ AST_MUTEX_DEFINE_STATIC(iflock); @@ -224,10 +225,8 @@ static struct io_context *io; #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 { @@ -258,6 +257,7 @@ static struct sip_pvt { 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 */ @@ -393,6 +393,7 @@ struct sip_user { char useragent[256]; /* User agent in SIP request */ unsigned int callgroup; unsigned int pickupgroup; + struct ast_codec_pref prefs; /* codec prefs */ int nat; int hascallerid; int amaflags; @@ -434,6 +435,7 @@ struct sip_peer { char language[MAX_LANGUAGE]; char musicclass[MAX_LANGUAGE]; /* Music on Hold class */ char useragent[256]; /* User agent in SIP request */ + struct ast_codec_pref prefs; /* codec prefs */ int lastmsgssent; time_t lastmsgcheck; int dynamic; @@ -1417,71 +1419,8 @@ static int auto_congest(void *nothing) 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 */ @@ -2026,12 +1965,14 @@ static struct ast_channel *sip_new(struct sip_pvt *i, int state, char *title) 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(&i->prefs, i->jointcapability, 1); else if (i->capability) - tmp->nativeformats = sip_codec_choose(i->capability); + tmp->nativeformats = ast_codec_choose(&i->prefs, i->capability, 1); else - tmp->nativeformats = sip_codec_choose(global_capability); + tmp->nativeformats = ast_codec_choose(&i->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); @@ -2328,9 +2269,11 @@ static struct sip_pvt *sip_alloc(char *callid, struct sockaddr_in *sin, int useg /* 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 @@ -2802,7 +2745,8 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req) 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", @@ -2822,12 +2766,12 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req) } 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); + p->owner->nativeformats = ast_codec_choose(&p->prefs, p->jointcapability, 1); ast_set_read_format(p->owner, p->owner->readformat); ast_set_write_format(p->owner, p->owner->writeformat); } @@ -3356,13 +3300,13 @@ static int add_digit(struct sip_request *req, char digit) /*--- 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; char v[256] = ""; char s[256] = ""; char o[256] = ""; @@ -3373,11 +3317,13 @@ static int add_sdp(struct sip_request *resp, struct sip_pvt *p) 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 */ @@ -3429,6 +3375,7 @@ static int add_sdp(struct sip_request *resp, struct sip_pvt *p) 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)); + /* Prefer the codec we were requested to use, first, no matter what */ if (capability & p->prefcodec) { if (debug) ast_verbose("Answering/Requesting with root capability %d\n", p->prefcodec); @@ -3448,33 +3395,34 @@ static int add_sdp(struct sip_request *resp, struct sip_pvt *p) alreadysent |= p->prefcodec; } /* Start by sending our preferred codecs */ - cur = prefs; - while(cur) { - if ((capability & cur->codec) && !(alreadysent & cur->codec)) { + for (x = 0 ; x < 32 ; x++) { + if(!(pref_codec = ast_codec_pref_index(&p->prefs,x))) + break; + if ((capability & pref_codec) && !(alreadysent & pref_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); + 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 (cur->codec <= AST_FORMAT_MAX_AUDIO) { + 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, cur->codec)); + 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, cur->codec)); + 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 |= cur->codec; - cur = cur->next; + alreadysent |= pref_codec; } + /* 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); @@ -3493,7 +3441,7 @@ static int add_sdp(struct sip_request *resp, struct sip_pvt *p) 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); @@ -5382,6 +5330,7 @@ static int check_user_full(struct sip_pvt *p, struct sip_request *req, char *cmd user = find_user(of); /* Find user based on user name in the from header */ if (user && ast_apply_ha(user->ha, sin)) { + p->prefs = user->prefs; p->nat = user->nat; #ifdef OSP_SUPPORT p->ospauth = user->ospauth; @@ -5750,6 +5699,9 @@ static int sip_show_peer(int fd, int argc, char *argv[]) char status[30] = ""; 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; @@ -5794,38 +5746,23 @@ static int sip_show_peer(int fd, int argc, char *argv[]) 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 = &peer->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 (!x) + ast_cli(fd, "none"); + ast_cli(fd, ")\n"); + ast_cli(fd, " Status : "); if (peer->lastms < 0) strncpy(status, "UNREACHABLE", sizeof(status) - 1); @@ -8134,6 +8071,7 @@ static struct sip_user *build_user(char *name, struct ast_variable *v) user->trustrpid = global_trustrpid; user->dtmfmode = global_dtmfmode; user->progressinband = global_progressinband; + user->prefs = prefs; #ifdef OSP_SUPPORT user->ospauth = global_ospauth; #endif @@ -8207,17 +8145,9 @@ static struct sip_user *build_user(char *name, struct ast_variable *v) 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 - user->capability |= format; + ast_parse_allow_disallow(&user->prefs, &user->capability, v->value, 1); } 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 - user->capability &= ~format; + ast_parse_allow_disallow(&user->prefs, &user->capability, v->value, 0); } else if (!strcasecmp(v->name, "insecure")) { user->insecure = ast_true(v->value); } else if (!strcasecmp(v->name, "restrictcid")) { @@ -8254,6 +8184,7 @@ static struct sip_peer *temp_peer(char *name) peer = malloc(sizeof(struct sip_peer)); if (!peer) return NULL; + memset(peer, 0, sizeof(struct sip_peer)); peer->expire = -1; peer->pokeexpire = -1; @@ -8276,6 +8207,7 @@ static struct sip_peer *temp_peer(char *name) peer->dynamic = 1; peer->trustrpid = global_trustrpid; peer->progressinband = global_progressinband; + peer->prefs = prefs; #ifdef OSP_SUPPORT peer->ospauth = global_ospauth; #endif @@ -8290,7 +8222,6 @@ static struct sip_peer *build_peer(char *name, struct ast_variable *v) struct sip_peer *prev; struct ast_ha *oldha = NULL; int maskfound=0; - int format; int found=0; prev = NULL; ast_mutex_lock(&peerl.lock); @@ -8332,6 +8263,7 @@ static struct sip_peer *build_peer(char *name, struct ast_variable *v) peer->defaddr.sin_family = AF_INET; peer->expiry = expiry; } + peer->prefs = prefs; oldha = peer->ha; peer->ha = NULL; peer->addr.sin_family = AF_INET; @@ -8444,17 +8376,9 @@ static struct sip_peer *build_peer(char *name, struct ast_variable *v) } 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 - peer->capability |= format; + ast_parse_allow_disallow(&peer->prefs, &peer->capability, v->value, 1); } 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 - peer->capability &= ~format; + ast_parse_allow_disallow(&peer->prefs, &peer->capability, v->value, 0); } else if (!strcasecmp(v->name, "insecure")) { if (!strcasecmp(v->value, "very")) { peer->insecure = 2; @@ -8518,7 +8442,7 @@ static int reload_config(void) struct sip_user *user; struct ast_hostent ahp; char *cat; - char *utype; + char *utype; struct hostent *hp; int format; int oldport = ntohs(bindaddr.sin_port); @@ -8541,11 +8465,10 @@ static int reload_config(void) global_nat = SIP_NAT_RFC3581; - sip_prefs_free(); - memset(&bindaddr, 0, sizeof(bindaddr)); memset(&localaddr, 0, sizeof(localaddr)); memset(&externip, 0, sizeof(externip)); + memset(&prefs, 0 , sizeof(struct ast_codec_pref)); /* Initialize some reasonable defaults */ strncpy(default_context, "default", sizeof(default_context) - 1); @@ -8676,21 +8599,9 @@ static int reload_config(void) 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 { - global_capability |= format; - sip_pref_append(format); - } + ast_parse_allow_disallow(&prefs, &global_capability, v->value, 1); } 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 { - global_capability &= ~format; - sip_pref_remove(format); - } + ast_parse_allow_disallow(&prefs, &global_capability, v->value, 0); } else if (!strcasecmp(v->name, "register")) { sip_register(v->value, v->lineno); } else if (!strcasecmp(v->name, "recordhistory")) { @@ -9040,7 +8951,6 @@ static int sip_do_reload(void) struct sip_peer *peer; delete_users(); reload_config(); - prune_peers(); /* And start the monitor for the first time */ ast_mutex_lock(®l.lock); @@ -9084,9 +8994,9 @@ int load_module() struct sip_peer *peer; struct sip_registry *reg; - ast_mutex_init(&userl.lock); - ast_mutex_init(&peerl.lock); - ast_mutex_init(®l.lock); + 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"); @@ -9095,7 +9005,8 @@ int load_module() 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 */ @@ -3,9 +3,9 @@ * * Frame manipulation routines * - * Copyright (C) 1999, Mark Spencer + * Copyright (C) 1999-2004, Mark Spencer * - * Mark Spencer <markster@linux-support.net> + * Mark Spencer <markster@digium.com> * * This program is free software, distributed under the terms of * the GNU General Public License @@ -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,186 @@ 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_disallow(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 if(!allowing) /* disallow all must clear your prefs or it makes no sense */ + memset(pref, 0, sizeof(struct ast_codec_pref)); + } else + ast_log(LOG_WARNING, "Cannot %s unknown format '%s'\n", allowing ? "allow" : "disallow", last_format); + + last_format = next_format; + } +} + + diff --git a/include/asterisk/frame.h b/include/asterisk/frame.h index c80ca72f5..c97973226 100755 --- a/include/asterisk/frame.h +++ b/include/asterisk/frame.h @@ -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_disallow(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 |