summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSteve Murphy <murf@digium.com>2007-08-20 22:53:48 +0000
committerSteve Murphy <murf@digium.com>2007-08-20 22:53:48 +0000
commit337c44236d51aaa30d249a99b952bb049ef74adc (patch)
treeba8c79a84cc6cbddcd2d849a6b9895d6124c4452
parentc9ab65a3bf8f6ef64434cb01d3e75adba6d1f44b (diff)
This change set fixes bug 8126 in trunk. It is implemented via compile time options, activated via the menuselect stuff, which defaults to the old way. non-zero sample data added. Translate tables expressed in microseconds instead of milliseconds, with 5-digit data now instead of 3, giving 2 more digits of precision.
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@80113 65c4cc65-6c06-0410-ace0-fbb531ad65f3
-rw-r--r--build_tools/cflags.xml13
-rw-r--r--codecs/slin_ulaw_ex.h20
-rw-r--r--codecs/ulaw_slin_ex.h20
-rw-r--r--include/asterisk/alaw.h52
-rw-r--r--include/asterisk/ulaw.h47
-rw-r--r--main/alaw.c138
-rw-r--r--main/translate.c21
-rw-r--r--main/ulaw.c165
8 files changed, 421 insertions, 55 deletions
diff --git a/build_tools/cflags.xml b/build_tools/cflags.xml
index 58a90fd5a..2cd423e01 100644
--- a/build_tools/cflags.xml
+++ b/build_tools/cflags.xml
@@ -20,6 +20,19 @@
</member>
<member name="LOW_MEMORY" displayname="Optimize for Low Memory Usage">
</member>
+ <member name="G711_NEW_ALGORITHM" displayname="Use the NEW ulaw/alaw codecs (slower, but cleaner)">
+ <defaultenabled>no</defaultenabled>
+ </member>
+ <member name="G711_REDUCED_BRANCHING" displayname="New ulaw/alaw codec, reduced branching (might help it run faster in some architectures)">
+ <defaultenabled>yes</defaultenabled>
+ <depend>G711_NEW_ALGORITHM</depend>
+ </member>
+ <member name="TEST_CODING_TABLES" displayname="New ulaw/alaw codec, turn on table tests on init">
+ <depend>G711_NEW_ALGORITHM</depend>
+ </member>
+ <member name="TEST_TANDEM_TRANSCODING" displayname="New ulaw/alaw codec, turn on transcoding tests on init">
+ <depend>G711_NEW_ALGORITHM</depend>
+ </member>
<member name="MALLOC_DEBUG" displayname="Keep Track of Memory Allocations">
</member>
<member name="MTX_PROFILE" displayname="Enable Code Profiling Using TSC Counters">
diff --git a/codecs/slin_ulaw_ex.h b/codecs/slin_ulaw_ex.h
index 9af79eba2..083acef3c 100644
--- a/codecs/slin_ulaw_ex.h
+++ b/codecs/slin_ulaw_ex.h
@@ -12,14 +12,14 @@
*/
static signed short slin_ulaw_ex[] = {
- 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
- 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
- 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
- 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
- 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
- 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
- 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
- 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
- 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
- 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000
+ 0xcac0, 0xcdeb, 0xd116, 0xd441, 0xd76c, 0xda97, 0xddc2, 0xe0ed,
+ 0x0000, 0x032b, 0x0656, 0x0981, 0x0cac, 0x0fd7, 0x1302, 0x162d,
+ 0x1958, 0x1c83, 0x1fae, 0x22d9, 0x2604, 0x292f, 0x2c5a, 0x2f85,
+ 0x32b0, 0x35db, 0x3906, 0x3c31, 0x3f5c, 0x4287, 0x45b2, 0x48dd,
+ 0xb168, 0xb493, 0xb7be, 0xbae9, 0xbe14, 0xc13f, 0xc46a, 0xc795,
+ 0xe418, 0xe743, 0xea6e, 0xed99, 0xf0c4, 0xf3ef, 0xf71a, 0xfa45,
+ 0x9810, 0x9b3b, 0x9e66, 0xa191, 0xa4bc, 0xa7e7, 0xab12, 0xae3d,
+ 0x4c08, 0x4f33, 0x525e, 0x5589, 0x58b4, 0x5bdf, 0x5f0a, 0x6235,
+ 0x6560, 0x688b, 0x6bb6, 0x6ee1, 0x720c, 0x7537, 0x7862, 0x7b8d,
+ 0x7eb8, 0x81e3, 0x850e, 0x8839, 0x8b64, 0x8e8f, 0x91ba, 0x94e5,
};
diff --git a/codecs/ulaw_slin_ex.h b/codecs/ulaw_slin_ex.h
index 9f0417a6b..a12556824 100644
--- a/codecs/ulaw_slin_ex.h
+++ b/codecs/ulaw_slin_ex.h
@@ -12,14 +12,14 @@
*/
static unsigned char ulaw_slin_ex[] = {
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+ 0x00, 0x03, 0x06, 0x09, 0x0c, 0x0f, 0x12, 0x15,
+ 0x10, 0x18, 0x1b, 0x1e, 0x21, 0x24, 0x27, 0x2a,
+ 0x20, 0x2d, 0x30, 0x33, 0x36, 0x39, 0x3c, 0x3f,
+ 0x30, 0x42, 0x45, 0x48, 0x4b, 0x4e, 0x51, 0x54,
+ 0x40, 0x57, 0x5a, 0x5d, 0x60, 0x63, 0x66, 0x69,
+ 0x50, 0x6c, 0x6f, 0x72, 0x75, 0x78, 0x7b, 0x7e,
+ 0x60, 0x81, 0x84, 0x87, 0x8a, 0x8d, 0x90, 0x93,
+ 0x70, 0x96, 0x99, 0x9c, 0x9f, 0xa2, 0xa5, 0xa8,
+ 0x80, 0xab, 0xae, 0xb1, 0xb4, 0xb7, 0xba, 0xbd,
+ 0x90, 0xc0, 0xc3, 0xc6, 0xc9, 0xcc, 0xcf, 0xd2
};
diff --git a/include/asterisk/alaw.h b/include/asterisk/alaw.h
index 44b3bad86..34968969d 100644
--- a/include/asterisk/alaw.h
+++ b/include/asterisk/alaw.h
@@ -23,21 +23,67 @@
#ifndef _ASTERISK_ALAW_H
#define _ASTERISK_ALAW_H
+
/*! Init the ulaw conversion stuff */
/*!
- * To init the ulaw to slinear conversion stuff, this needs to be run.
+ * To init the alaw to slinear conversion stuff, this needs to be run.
*/
void ast_alaw_init(void);
-/*! converts signed linear to mulaw */
+#define AST_ALAW_BIT_LOSS 4
+#define AST_ALAW_STEP (1 << AST_ALAW_BIT_LOSS)
+#define AST_ALAW_TAB_SIZE (32768 / AST_ALAW_STEP + 1)
+#define AST_ALAW_SIGN_BIT 0x80
+#define AST_ALAW_AMI_MASK 0x55
+
+
+/*! converts signed linear to alaw */
/*!
- */
+ */
+#ifndef G711_NEW_ALGORITHM
extern unsigned char __ast_lin2a[8192];
+#else
+extern unsigned char __ast_lin2a[AST_ALAW_TAB_SIZE];
+#endif
/*! help */
extern short __ast_alaw[256];
+#ifndef G711_NEW_ALGORITHM
#define AST_LIN2A(a) (__ast_lin2a[((unsigned short)(a)) >> 3])
+#else
+#define AST_LIN2A_LOOKUP(mag) \
+ __ast_lin2a[(mag) >> AST_ALAW_BIT_LOSS]
+
+/*! convert signed linear sample to sign-magnitude pair for a-Law */
+static inline void ast_alaw_get_sign_mag(short sample, unsigned *sign, unsigned *mag)
+{
+ /* It may look illogical to retrive the sign this way in both cases,
+ * but this helps gcc eliminate the branch below and produces
+ * faster code */
+ *sign = ((unsigned short)sample >> 8) & AST_ALAW_SIGN_BIT;
+#if defined(G711_REDUCED_BRANCHING)
+ {
+ unsigned dual_mag = (-sample << 16) | (unsigned short)sample;
+ *mag = (dual_mag >> (*sign >> 3)) & 0xffffU;
+ }
+#else
+ if (sample < 0)
+ *mag = -sample;
+ else
+ *mag = sample;
+#endif /* G711_REDUCED_BRANCHING */
+ *sign ^= AST_ALAW_SIGN_BIT;
+}
+
+static inline unsigned char AST_LIN2A(short sample)
+{
+ unsigned mag, sign;
+ ast_alaw_get_sign_mag(sample, &sign, &mag);
+ return (sign | AST_LIN2A_LOOKUP(mag)) ^ AST_ALAW_AMI_MASK;
+}
+#endif
+
#define AST_ALAW(a) (__ast_alaw[(int)(a)])
#endif /* _ASTERISK_ALAW_H */
diff --git a/include/asterisk/ulaw.h b/include/asterisk/ulaw.h
index d9ab0d178..1ac079d54 100644
--- a/include/asterisk/ulaw.h
+++ b/include/asterisk/ulaw.h
@@ -23,21 +23,68 @@
#ifndef _ASTERISK_ULAW_H
#define _ASTERISK_ULAW_H
+
/*! Init the ulaw conversion stuff */
/*!
* To init the ulaw to slinear conversion stuff, this needs to be run.
*/
void ast_ulaw_init(void);
+#define AST_ULAW_BIT_LOSS 3
+#define AST_ULAW_STEP (1 << AST_ULAW_BIT_LOSS)
+#define AST_ULAW_TAB_SIZE (32768 / AST_ULAW_STEP + 1)
+#define AST_ULAW_SIGN_BIT 0x80
+
/*! converts signed linear to mulaw */
/*!
*/
+#ifndef G711_NEW_ALGORITHM
extern unsigned char __ast_lin2mu[16384];
+#else
+extern unsigned char __ast_lin2mu[AST_ULAW_TAB_SIZE];
+#endif
/*! help */
extern short __ast_mulaw[256];
+#ifndef G711_NEW_ALGORITHM
+
#define AST_LIN2MU(a) (__ast_lin2mu[((unsigned short)(a)) >> 2])
+
+#else
+
+#define AST_LIN2MU_LOOKUP(mag) \
+ __ast_lin2mu[((mag) + AST_ULAW_STEP / 2) >> AST_ULAW_BIT_LOSS]
+
+
+/*! convert signed linear sample to sign-magnitude pair for u-Law */
+static inline void ast_ulaw_get_sign_mag(short sample, unsigned *sign, unsigned *mag)
+{
+ /* It may look illogical to retrive the sign this way in both cases,
+ * but this helps gcc eliminate the branch below and produces
+ * faster code */
+ *sign = ((unsigned short)sample >> 8) & AST_ULAW_SIGN_BIT;
+#if defined(G711_REDUCED_BRANCHING)
+ {
+ unsigned dual_mag = (-sample << 16) | (unsigned short)sample;
+ *mag = (dual_mag >> (*sign >> 3)) & 0xffffU;
+ }
+#else
+ if (sample < 0)
+ *mag = -sample;
+ else
+ *mag = sample;
+#endif /* G711_REDUCED_BRANCHING */
+}
+
+static inline unsigned char AST_LIN2MU(short sample)
+{
+ unsigned mag, sign;
+ ast_ulaw_get_sign_mag(sample, &sign, &mag);
+ return ~(sign | AST_LIN2MU_LOOKUP(mag));
+}
+#endif
+
#define AST_MULAW(a) (__ast_mulaw[(a)])
#endif /* _ASTERISK_ULAW_H */
diff --git a/main/alaw.c b/main/alaw.c
index d388d1e61..fbc99b0fe 100644
--- a/main/alaw.c
+++ b/main/alaw.c
@@ -18,7 +18,7 @@
/*! \file
*
- * \brief u-Law to Signed linear conversion
+ * \brief a-Law to Signed linear conversion
*
* \author Mark Spencer <markster@digium.com>
*/
@@ -28,18 +28,20 @@
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/alaw.h"
+#include "asterisk/logger.h"
+#ifndef G711_NEW_ALGORITHM
#define AMI_MASK 0x55
-static inline unsigned char linear2alaw (short int linear)
+static inline unsigned char linear2alaw(short int linear)
{
int mask;
int seg;
int pcm_val;
static int seg_end[8] =
- {
- 0xFF, 0x1FF, 0x3FF, 0x7FF, 0xFFF, 0x1FFF, 0x3FFF, 0x7FFF
- };
+ {
+ 0xFF, 0x1FF, 0x3FF, 0x7FF, 0xFFF, 0x1FFF, 0x3FFF, 0x7FFF
+ };
pcm_val = linear;
if (pcm_val >= 0) {
@@ -50,7 +52,7 @@ static inline unsigned char linear2alaw (short int linear)
mask = AMI_MASK;
pcm_val = -pcm_val;
}
-
+
/* Convert the scaled magnitude to segment number. */
for (seg = 0; seg < 8; seg++) {
if (pcm_val <= seg_end[seg])
@@ -59,13 +61,56 @@ static inline unsigned char linear2alaw (short int linear)
/* Combine the sign, segment, and quantization bits. */
return ((seg << 4) | ((pcm_val >> ((seg) ? (seg + 3) : 4)) & 0x0F)) ^ mask;
}
-/*- End of function --------------------------------------------------------*/
+#else
+static unsigned char linear2alaw(short sample, int full_coding)
+{
+ static const unsigned exp_lut[128] = {
+ 1,1,2,2,3,3,3,3,
+ 4,4,4,4,4,4,4,4,
+ 5,5,5,5,5,5,5,5,
+ 5,5,5,5,5,5,5,5,
+ 6,6,6,6,6,6,6,6,
+ 6,6,6,6,6,6,6,6,
+ 6,6,6,6,6,6,6,6,
+ 6,6,6,6,6,6,6,6,
+ 7,7,7,7,7,7,7,7,
+ 7,7,7,7,7,7,7,7,
+ 7,7,7,7,7,7,7,7,
+ 7,7,7,7,7,7,7,7,
+ 7,7,7,7,7,7,7,7,
+ 7,7,7,7,7,7,7,7,
+ 7,7,7,7,7,7,7,7,
+ 7,7,7,7,7,7,7,7 };
+ unsigned sign, exponent, mantissa, mag;
+ unsigned char alawbyte;
+
+ ast_alaw_get_sign_mag(sample, &sign, &mag);
+ if (mag > 32767)
+ mag = 32767; /* clip the magnitude for -32768 */
+
+ exponent = exp_lut[(mag >> 8) & 0x7f];
+ mantissa = (mag >> (exponent + 3)) & 0x0f;
+ if (mag < 0x100)
+ exponent = 0;
+
+ if (full_coding) {
+ /* full encoding, with sign and xform */
+ alawbyte = (unsigned char)(sign | (exponent << 4) | mantissa);
+ alawbyte ^= AST_ALAW_AMI_MASK;
+ } else {
+ /* half-cooked coding -- mantissa+exponent only (for lookup tab) */
+ alawbyte = (exponent << 4) | mantissa;
+ }
+ return alawbyte;
+}
+#endif
+#ifndef G711_NEW_ALGORITHM
static inline short int alaw2linear (unsigned char alaw)
{
int i;
int seg;
-
+
alaw ^= AMI_MASK;
i = ((alaw & 0x0F) << 4);
seg = (((int) alaw & 0x70) >> 4);
@@ -73,8 +118,31 @@ static inline short int alaw2linear (unsigned char alaw)
i = (i + 0x100) << (seg - 1);
return (short int) ((alaw & 0x80) ? i : -i);
}
+#else
+static inline short alaw2linear(unsigned char alawbyte)
+{
+ unsigned exponent, mantissa;
+ short sample;
+
+ alawbyte ^= AST_ALAW_AMI_MASK;
+ exponent = (alawbyte & 0x70) >> 4;
+ mantissa = alawbyte & 0x0f;
+ sample = (mantissa << 4) + 8 /* rounding error */;
+ if (exponent)
+ sample = (sample + 0x100) << (exponent - 1);
+ if (!(alawbyte & 0x80))
+ sample = -sample;
+ return sample;
+}
+#endif
+
+
+#ifndef G711_NEW_ALGORITHM
unsigned char __ast_lin2a[8192];
+#else
+unsigned char __ast_lin2a[AST_ALAW_TAB_SIZE];
+#endif
short __ast_alaw[256];
void ast_alaw_init(void)
@@ -82,14 +150,62 @@ void ast_alaw_init(void)
int i;
/*
* Set up mu-law conversion table
- */
+ */
+#ifndef G711_NEW_ALGORITHM
for (i = 0; i < 256; i++) {
- __ast_alaw[i] = alaw2linear(i);
+ __ast_alaw[i] = alaw2linear(i);
}
/* set up the reverse (mu-law) conversion table */
for (i = -32768; i < 32768; i++) {
__ast_lin2a[((unsigned short)i) >> 3] = linear2alaw(i);
}
-
+#else
+ for (i = 0; i < 256; i++) {
+ __ast_alaw[i] = alaw2linear(i);
+ }
+ /* set up the reverse (a-law) conversion table */
+ for (i = 0; i <= 32768; i += AST_ALAW_STEP) {
+ AST_LIN2A_LOOKUP(i) = linear2alaw(i, 0 /* half-cooked */);
+ }
+#endif
+
+#ifdef TEST_CODING_TABLES
+ for (i = -32768; i < 32768; ++i) {
+#ifndef G711_NEW_ALGORITHM
+ unsigned char e1 = linear2alaw(i);
+#else
+ unsigned char e1 = linear2alaw(i, 1);
+#endif
+ short d1 = alaw2linear(e1);
+ unsigned char e2 = AST_LIN2A(i);
+ short d2 = alaw2linear(e2);
+ short d3 = AST_ALAW(e1);
+
+ if (e1 != e2 || d1 != d3 || d2 != d3) {
+ ast_log(LOG_WARNING, "a-Law coding tables test failed on %d: e1=%u, e2=%u, d1=%d, d2=%d\n",
+ i, (unsigned)e1, (unsigned)e2, (int)d1, (int)d2);
+ }
+ }
+ ast_log(LOG_NOTICE, "a-Law coding tables test complete.\n");
+#endif /* TEST_CODING_TABLES */
+
+#ifdef TEST_TANDEM_TRANSCODING
+ /* tandem transcoding test */
+ for (i = -32768; i < 32768; ++i) {
+ unsigned char e1 = AST_LIN2A(i);
+ short d1 = AST_ALAW(e1);
+ unsigned char e2 = AST_LIN2A(d1);
+ short d2 = AST_ALAW(e2);
+ unsigned char e3 = AST_LIN2A(d2);
+ short d3 = AST_ALAW(e3);
+
+ if (e1 != e2 || e2 != e3 || d1 != d2 || d2 != d3) {
+ ast_log(LOG_WARNING, "a-Law tandem transcoding test failed on %d: e1=%u, e2=%u, d1=%d, d2=%d, d3=%d\n",
+ i, (unsigned)e1, (unsigned)e2, (int)d1, (int)d2, (int)d3);
+ }
+ }
+ ast_log(LOG_NOTICE, "a-Law tandem transcoding test complete.\n");
+#endif /* TEST_TANDEM_TRANSCODING */
+
}
diff --git a/main/translate.c b/main/translate.c
index 3f9ffd764..c26e627a2 100644
--- a/main/translate.c
+++ b/main/translate.c
@@ -46,7 +46,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/cli.h"
#include "asterisk/term.h"
-#define MAX_RECALC 200 /* max sample recalc */
+#define MAX_RECALC 1000 /* max sample recalc */
/*! \brief the list of translators */
static AST_RWLIST_HEAD_STATIC(translators, ast_translator);
@@ -371,6 +371,7 @@ static void calc_cost(struct ast_translator *t, int seconds)
int sofar=0;
struct ast_trans_pvt *pvt;
struct timeval start;
+ struct timeval end;
int cost;
if (!seconds)
@@ -379,13 +380,13 @@ static void calc_cost(struct ast_translator *t, int seconds)
/* If they don't make samples, give them a terrible score */
if (!t->sample) {
ast_log(LOG_WARNING, "Translator '%s' does not produce sample frames.\n", t->name);
- t->cost = 99999;
+ t->cost = 999999;
return;
}
pvt = newpvt(t);
if (!pvt) {
ast_log(LOG_WARNING, "Translator '%s' appears to be broken and will probably fail.\n", t->name);
- t->cost = 99999;
+ t->cost = 999999;
return;
}
start = ast_tvnow();
@@ -395,7 +396,7 @@ static void calc_cost(struct ast_translator *t, int seconds)
if (!f) {
ast_log(LOG_WARNING, "Translator '%s' failed to produce a sample frame.\n", t->name);
destroy(pvt);
- t->cost = 99999;
+ t->cost = 999999;
return;
}
framein(pvt, f);
@@ -405,7 +406,8 @@ static void calc_cost(struct ast_translator *t, int seconds)
ast_frfree(f);
}
}
- cost = ast_tvdiff_ms(ast_tvnow(), start);
+ end = ast_tvnow();
+ cost = ((end.tv_sec - start.tv_sec)*1000000) + end.tv_usec - start.tv_usec;
destroy(pvt);
t->cost = cost / seconds;
if (!t->cost)
@@ -516,7 +518,7 @@ static int show_translation(int fd, int argc, char *argv[])
AST_RWLIST_RDLOCK(&translators);
- ast_cli(fd, " Translation times between formats (in milliseconds) for one second of data\n");
+ ast_cli(fd, " Translation times between formats (in microseconds) for one second of data\n");
ast_cli(fd, " Source Format (Rows) Destination Format (Columns)\n\n");
/* Get the length of the longest (usable?) codec name, so we know how wide the left side should be */
for (x = 0; x < SHOW_TRANS; x++) {
@@ -530,12 +532,13 @@ static int show_translation(int fd, int argc, char *argv[])
ast_str_set(&out, -1, " ");
for (y = -1; y < SHOW_TRANS; y++) {
curlen = strlen(ast_getformatname(1 << (y)));
-
+ if (curlen < 5)
+ curlen = 5;
if (x >= 0 && y >= 0 && tr_matrix[x][y].step) {
- /* XXX 999 is a little hackish
+ /* XXX 99999 is a little hackish
We don't want this number being larger than the shortest (or current) codec
For now, that is "gsm" */
- ast_str_append(&out, -1, "%*d", curlen + 1, tr_matrix[x][y].cost > 999 ? 0 : tr_matrix[x][y].cost);
+ ast_str_append(&out, -1, "%*d", curlen + 1, tr_matrix[x][y].cost > 99999 ? 0 : tr_matrix[x][y].cost);
} else if (x == -1 && y >= 0) {
/* Top row - use a dynamic size */
ast_str_append(&out, -1, "%*s", curlen + 1, ast_getformatname(1 << (x + y + 1)) );
diff --git a/main/ulaw.c b/main/ulaw.c
index 2735f6cce..8e47d8a77 100644
--- a/main/ulaw.c
+++ b/main/ulaw.c
@@ -28,15 +28,25 @@
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/ulaw.h"
+#include "asterisk/logger.h"
+#if 0
+/* ZEROTRAP is the military recommendation to improve the encryption
+ * of u-Law traffic. It is irrelevant with modern encryption systems
+ * like AES, and will simply degrade the signal quality.
+ * ZEROTRAP is not implemented in AST_LIN2MU and so the coding table
+ * tests will fail if you use it */
#define ZEROTRAP /*!< turn on the trap as per the MIL-STD */
+#endif
+
#define BIAS 0x84 /*!< define the add-in bias for 16 bit samples */
#define CLIP 32635
+#ifndef G711_NEW_ALGORITHM
+
unsigned char __ast_lin2mu[16384];
short __ast_mulaw[256];
-
static unsigned char linear2ulaw(short sample)
{
static int exp_lut[256] = {
@@ -58,26 +68,102 @@ static unsigned char linear2ulaw(short sample)
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7 };
int sign, exponent, mantissa;
unsigned char ulawbyte;
-
+
/* Get the sample into sign-magnitude. */
sign = (sample >> 8) & 0x80; /* set aside the sign */
- if (sign != 0)
+ if (sign != 0)
sample = -sample; /* get magnitude */
if (sample > CLIP)
sample = CLIP; /* clip the magnitude */
-
+
/* Convert from 16 bit linear to ulaw. */
sample = sample + BIAS;
exponent = exp_lut[(sample >> 7) & 0xFF];
mantissa = (sample >> (exponent + 3)) & 0x0F;
ulawbyte = ~(sign | (exponent << 4) | mantissa);
+
#ifdef ZEROTRAP
if (ulawbyte == 0)
ulawbyte = 0x02; /* optional CCITT trap */
#endif
+
+ return ulawbyte;
+}
+
+#else
+
+unsigned char __ast_lin2mu[AST_ULAW_TAB_SIZE];
+short __ast_mulaw[256];
+
+static unsigned char linear2ulaw(short sample, int full_coding)
+{
+ static const unsigned exp_lut[256] = {
+ 0,0,1,1,2,2,2,2,3,3,3,3,3,3,3,3,
+ 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
+ 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+ 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+ 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
+ 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
+ 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
+ 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
+ 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
+ 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
+ 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
+ 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
+ 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
+ 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
+ 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
+ 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7 };
+ unsigned sign, exponent, mantissa, mag;
+ unsigned char ulawbyte;
+
+ /* Get the sample into sign-magnitude. */
+ ast_ulaw_get_sign_mag(sample, &sign, &mag);
+ if (mag > CLIP)
+ mag = CLIP; /* clip the magnitude */
+
+ sign = (sample >> 8) & 0x80; /* set aside the sign */
+ if (sign != 0)
+ sample = -sample; /* get magnitude */
+ if (sample > CLIP)
+ sample = CLIP; /* clip the magnitude */
+
+ /* Convert from 16 bit linear to ulaw. */
+ mag += BIAS;
+ exponent = exp_lut[(mag >> 7) & 0xFF];
+ mantissa = (mag >> (exponent + 3)) & 0x0F;
+
+ if (full_coding) {
+ /* full encoding, with sign and xform */
+ ulawbyte = ~(sign | (exponent << 4) | mantissa);
+#ifdef ZEROTRAP
+ if (ulawbyte == 0)
+ ulawbyte = 0x02; /* optional CCITT trap */
+#endif
+ } else {
+ /* half-cooked coding -- mantissa+exponent only (for lookup tab) */
+ ulawbyte = (exponent << 4) | mantissa;
+ }
return ulawbyte;
}
+
+static inline short ulaw2linear(unsigned char ulawbyte)
+{
+ unsigned exponent, mantissa;
+ short sample;
+ static const short etab[]={0,132,396,924,1980,4092,8316,16764};
+
+ ulawbyte = ~ulawbyte;
+ exponent = (ulawbyte & 0x70) >> 4;
+ mantissa = ulawbyte & 0x0f;
+ sample = mantissa << (exponent + 3);
+ sample += etab[exponent];
+ if (ulawbyte & 0x80)
+ sample = -sample;
+ return sample;
+}
+#endif
/*!
* \brief Set up mu-law conversion table
@@ -85,22 +171,77 @@ static unsigned char linear2ulaw(short sample)
void ast_ulaw_init(void)
{
int i;
- for (i = 0; i < 256; i++) {
- short mu, e, f, y;
- static short etab[] = {0,132,396,924,1980,4092,8316,16764};
-
- mu = 255 - i;
- e = (mu & 0x70) / 16;
+
+ /*
+ * Set up mu-law conversion table
+ */
+#ifndef G711_NEW_ALGORITHM
+ for (i = 0;i < 256;i++) {
+ short mu,e,f,y;
+ static short etab[]={0,132,396,924,1980,4092,8316,16764};
+
+ mu = 255-i;
+ e = (mu & 0x70)/16;
f = mu & 0x0f;
y = f * (1 << (e + 3));
y += etab[e];
- if (mu & 0x80)
- y = -y;
+ if (mu & 0x80) y = -y;
__ast_mulaw[i] = y;
}
/* set up the reverse (mu-law) conversion table */
for (i = -32768; i < 32768; i++) {
__ast_lin2mu[((unsigned short)i) >> 2] = linear2ulaw(i);
}
+#else
+
+ for (i = 0; i < 256; i++) {
+ __ast_mulaw[i] = ulaw2linear(i);
+ }
+ /* set up the reverse (mu-law) conversion table */
+ for (i = 0; i <= 32768; i += AST_ULAW_STEP) {
+ AST_LIN2MU_LOOKUP(i) = linear2ulaw(i, 0 /* half-cooked */);
+ }
+#endif
+
+#ifdef TEST_CODING_TABLES
+ for (i = -32768; i < 32768; ++i) {
+#ifndef G711_NEW_ALGORITHM
+ unsigned char e1 = linear2ulaw(i);
+#else
+ unsigned char e1 = linear2ulaw(i, 1);
+#endif
+ short d1 = ulaw2linear(e1);
+ unsigned char e2 = AST_LIN2MU(i);
+ short d2 = ulaw2linear(e2);
+ short d3 = AST_MULAW(e1);
+
+ if (e1 != e2 || d1 != d3 || d2 != d3) {
+ ast_log(LOG_WARNING, "u-Law coding tables test failed on %d: e1=%u, e2=%u, d1=%d, d2=%d\n",
+ i, (unsigned)e1, (unsigned)e2, (int)d1, (int)d2);
+ }
+ }
+ ast_log(LOG_NOTICE, "u-Law coding table test complete.\n");
+#endif /* TEST_CODING_TABLES */
+
+#ifdef TEST_TANDEM_TRANSCODING
+ /* tandem transcoding test */
+ for (i = -32768; i < 32768; ++i) {
+ unsigned char e1 = AST_LIN2MU(i);
+ short d1 = AST_MULAW(e1);
+ unsigned char e2 = AST_LIN2MU(d1);
+ short d2 = AST_MULAW(e2);
+ unsigned char e3 = AST_LIN2MU(d2);
+ short d3 = AST_MULAW(e3);
+
+ if (i < 0 && e1 == 0x7f && e2 == 0xff && e3 == 0xff)
+ continue; /* known and normal negative 0 case */
+
+ if (e1 != e2 || e2 != e3 || d1 != d2 || d2 != d3) {
+ ast_log(LOG_WARNING, "u-Law tandem transcoding test failed on %d: e1=%u, e2=%u, d1=%d, d2=%d, d3=%d\n",
+ i, (unsigned)e1, (unsigned)e2, (int)d1, (int)d2, (int)d3);
+ }
+ }
+ ast_log(LOG_NOTICE, "u-Law tandem transcoding test complete.\n");
+#endif /* TEST_TANDEM_TRANSCODING */
}