aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorrussell <russell@f38db490-d61c-443f-a65b-d21fe96a405b>2004-12-05 05:17:51 +0000
committerrussell <russell@f38db490-d61c-443f-a65b-d21fe96a405b>2004-12-05 05:17:51 +0000
commitbcda3e822bef0b3c5daecd2a1471a4e7853dc49f (patch)
tree2a2cae28335a163c6a9cfa54cac37a7fa6592d1a
parent3d10e7bbb1153baa49672f656d81c15ba06b0759 (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-xCHANGES4
-rwxr-xr-xchannels/chan_sip.c243
-rwxr-xr-xframe.c443
-rwxr-xr-xinclude/asterisk/frame.h38
4 files changed, 434 insertions, 294 deletions
diff --git a/CHANGES b/CHANGES
index 1c9bfdf38..e851eec76 100755
--- a/CHANGES
+++ b/CHANGES
@@ -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(&regl.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(&regl.lock);
+ ast_mutex_init(&userl.lock);
+ ast_mutex_init(&peerl.lock);
+ ast_mutex_init(&regl.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 */
diff --git a/frame.c b/frame.c
index 3538d35b1..6556c59cb 100755
--- a/frame.c
+++ b/frame.c
@@ -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