Skip to content

Instantly share code, notes, and snippets.

@airend
Created May 18, 2015 18:59
Show Gist options
  • Save airend/ad78f1ea0a3e6c13d230 to your computer and use it in GitHub Desktop.
Save airend/ad78f1ea0a3e6c13d230 to your computer and use it in GitHub Desktop.
AMR Narrowband for Asterisk 11.x
Index: asterisk-11.10.2/channels/chan_sip.c
===================================================================
--- asterisk-11.10.2.orig/channels/chan_sip.c 2014-06-17 18:53:02.633454582 -0400
+++ asterisk-11.10.2/channels/chan_sip.c 2014-06-23 19:56:24.565721407 -0400
@@ -11143,6 +11143,23 @@
}
switch ((int) format->id) {
+ case AST_FORMAT_AMRNB:
+ if (sscanf(fmtp_string, "mode=%30u", &value) == 1) {
+ ast_log(LOG_WARNING, "Got AMR-NB mode=%d\n", value);
+ /* TODO: actually handle this */
+ found = TRUE;
+ }
+ if (sscanf(fmtp_string, "octet-align=%30u", &value) == 1) {
+ ast_log(LOG_WARNING, "Got AMR-NB octet-align set to [%s]\n", value ? "on" : "off");
+ /* TODO: actually handle this */
+ found = TRUE;
+ }
+ if (sscanf(fmtp_string, "dtx=%30u", &value) == 1) {
+ ast_log(LOG_WARNING, "Got AMR-NB set to [%s]\n", value ? "on" : "off");
+ /* TODO: actually handle this */
+ found = TRUE;
+ }
+ break;
case AST_FORMAT_SIREN7:
if (sscanf(fmtp_string, "bitrate=%30u", &bit_rate) == 1) {
if (bit_rate != 32000) {
@@ -12860,6 +12877,10 @@
/* Add information about us using only 20/30 ms packetization */
ast_str_append(a_buf, 0, "a=fmtp:%d mode=%d\r\n", rtp_code, fmt.cur_ms);
break;
+ case AST_FORMAT_AMRNB:
+ /* Indicate that we accept octet-align mode set to 1 (AMR-NB for exoteric devices)*/
+ //ast_str_append(a_buf, 0, "a=fmtp:%d octet-align=1\r\n", rtp_code);
+ break;
case AST_FORMAT_SIREN7:
/* Indicate that we only expect 32Kbps */
ast_str_append(a_buf, 0, "a=fmtp:%d bitrate=32000\r\n", rtp_code);
Index: asterisk-11.10.2/codecs/codec_amrnb.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ asterisk-11.10.2/codecs/codec_amrnb.c 2014-06-23 21:02:34.373721407 -0400
@@ -0,0 +1,480 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * The AMR-NB code is from 3GPP TS 26.104. Copyright information for that package is available
+ * in the amrnb directory.
+ *
+ * Copyright (C) 2007, 2010 Digital Solutions
+ * Paul Bagyenda <bagyenda@dsmagic.com>
+ *
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*! \file
+ *
+ * \brief Translate between signed linear and Adaptive Multi-Rate (AMR) Narrow Band (RFC 3267 format).
+ *
+ * \ingroup codecs
+ */
+
+/*** MODULEINFO
+ <depend>amrnb</depend>
+ <support_level>core</support_level>
+ ***/
+
+#include "asterisk.h"
+
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
+
+// #include <fcntl.h>
+// #include <stdlib.h>
+// #include <unistd.h>
+// #include <netinet/in.h>
+// #include <string.h>
+// #include <stdio.h>
+#include <assert.h>
+
+// #include "asterisk/lock.h"
+// #include "asterisk/options.h"
+// #include "asterisk/logger.h"
+// #include "asterisk/channel.h"
+
+#include "asterisk/translate.h"
+#include "asterisk/config.h"
+#include "asterisk/module.h"
+#include "asterisk/utils.h"
+
+// #include "amrnb/typedef.h"
+#include "opencore-amrnb/interf_enc.h"
+#include "opencore-amrnb/interf_dec.h"
+
+/* Sample frame data */
+#include "asterisk/slin.h"
+#include "ex_amrnb.h"
+
+#define BUFFER_SAMPLES 8000 /* maximum number of samples we will process at a go. */
+#define AMRNB_SAMPLES 160
+#define AMRNB_FRAME_LEN 32
+#define AMRNB_MAX_FRAMES 1000/20 /* each frame is 20ms, hence max frames = samples/samples_per_sec*/
+
+static int dtx = 0;
+
+// enum Mode {
+// MR475 = 0,/* 4.75 kbps */
+// MR515, /* 5.15 kbps */
+// MR59, /* 5.90 kbps */
+// MR67, /* 6.70 kbps */
+// MR74, /* 7.40 kbps */
+// MR795, /* 7.95 kbps */
+// MR102, /* 10.2 kbps */
+// MR122, /* 12.2 kbps */
+// MRDTX, /* DTX */
+// N_MODES /* Not Used */
+// };
+
+static enum Mode enc_mode = MR122;
+
+/* whether we are parsing/encoding using octet-aligned mode -- XXX not very clean
+ * Note: We don't handle crc or inter-leaving for now
+ */
+static int octet_aligned = 0;
+
+/* Size of (octet-aligned) speech block for each mode */
+static short block_size[16] = {12, 13, 15, 17, 19, 20, 26, 31, 5, 0, 0, 0, 0, 0, 0, 0};
+
+/* Frame lengths in bits, taken from Table 2, of 3GPP TS 26.101, v5.0.0 */
+static int num_bits[9] = {95, 103, 118, 134, 148, 159, 204, 244, 39};
+
+/* Mapping of encoding mode/bitrates to AMR-NB codec mode */
+static const short modeConv[8] = {475, 515, 59, 67, 74, 795, 102, 122};
+// {4750, 5150, 5900, 6700, 7400, 7950, 10200, 12200};
+
+struct amrnb_translator_pvt { /* both amrnb2lin and lin2amrnb */
+ int *destate; /* decoder state */
+ int *enstate; /* encoder state. */
+ enum Mode enc_mode; /* Currrently requested mode */
+ int16_t buf[BUFFER_SAMPLES]; /* lin2amrnb, temporary storage */
+#if 0
+ unsigned char pheader[AMRNB_MAX_FRAMES + 1]; /* lin2amrnb temporary storage for Pay load header + Table of Contents */
+#endif
+ unsigned char speech_bits[AMRNB_MAX_FRAMES*AMRNB_FRAME_LEN + 1]; /* storage for packed bits. */
+};
+
+
+/* Pack bits into dst, advance ptr */
+static int pack_bits(unsigned char **dst, int d_offset, unsigned char *src, unsigned sbits)
+{
+ unsigned char *p = *dst;
+ unsigned s_offset, x,y,sbytes = (sbits+7)/8; /* Number of bytes. */
+ unsigned char *end_ptr = src + sbytes;
+ assert(d_offset >= 0 && d_offset < 8);
+#if 0
+ ast_verbose("pack_bits: off=%d,sbits=%d\n",d_offset,sbits);
+#endif
+
+ /* Fill first dst byte, then we proceed */
+ x = d_offset + 1;
+ /* *p &= (1<<x) - 1; Clear top bits. */
+ *p = (*p & (~0 << x)) | (*src >> (8 - x)); /* Clear bits, then set */
+ if (d_offset == 7)
+ src++;
+ /* Now fill whole dst bytes in each pass */
+ s_offset = (d_offset == 7) ? 7 : 7 - x;
+ y = s_offset + 1;
+ while (src < end_ptr) {
+ p++; /* Go to next; Only do so here, because we need to go to next only if octet is used up. */
+ *p = (*src & ((1<<y) - 1)) << (8 - y);
+ if (s_offset < 7) /* Need part of next byte. Redundant check? I think so */
+ *p |= (src[1] >> y) & ((1<<(8 - s_offset)) - 1);
+ src++;
+ }
+ if (*dst == p && (sbits % 8 ) == 0)
+ p++; /* Terrible kludge, but... */
+
+ *dst = p;
+ /* Compute new d_offset */
+ if (sbits > x) {
+ sbits = (sbits - x) % 8; /* We'd have filled in first byte, and X full bytes */
+ /* We now have a remainder set of bits, which are fewer than 8, time to fill them in and calculate */
+ d_offset = 7 - sbits;
+ } else {
+ d_offset -= sbits; /* We stayed in same byte, or just filled it: Subtract # of bits added */
+ if (d_offset < 0)
+ d_offset = 7;
+ }
+ return d_offset;
+}
+
+/* unpack bits from src, advance src */
+static int unpack_bits(unsigned char **src, int s_offset, unsigned char *dst, unsigned sbits)
+{
+ unsigned char *q = *src;;
+
+ assert(s_offset >= 0 && s_offset <= 7);
+ while (sbits > 0) {
+ int bits = sbits >= 8 ? 8 : sbits;
+ unsigned mask = ~((1<<(8-bits)) - 1);
+ int x = s_offset + 1;
+
+ *dst = (*q << (8 - x)); /* Set */
+ if (x - bits < 0) /* Get bit off next byte */
+ *dst |= (q[1] >> x) /* & ((1 << (8-s_offset)) - 1) */; /* right shift of unsigned left pads with zeros*/
+ *dst &= mask; /* Clear all other bits */
+
+ s_offset -= bits;
+ if (s_offset < 0) { /* This means we got a bit off next byte or all of current byte, so move. */
+ q++;
+ s_offset += 8;
+ }
+ dst++;
+ sbits -= bits;
+ }
+
+ *src = q;
+
+ return s_offset;
+}
+
+static int amrnb_new(struct ast_trans_pvt *pvt)
+{
+ struct amrnb_translator_pvt *tmp = pvt->pvt;
+ tmp->enstate = Encoder_Interface_init(dtx);
+ tmp->destate = Decoder_Interface_init();
+ tmp->enc_mode = enc_mode;
+ return 0;
+}
+
+/*! \brief decode and store in outbuf. */
+static int amrnbtolin_framein(struct ast_trans_pvt *pvt, struct ast_frame *f)
+{
+ struct amrnb_translator_pvt *tmp = pvt->pvt;
+ int x = 0, more_frames = 1, nframes = 0;
+ int16_t *dst = pvt->outbuf.i16;
+ unsigned char *src = f->data.ptr, cmr, buffer[AMRNB_FRAME_LEN+1];
+ struct {
+ unsigned char ft;
+ unsigned char q;
+ } toc[AMRNB_MAX_FRAMES];
+ unsigned char *end_ptr = src + f->datalen;
+ int pos; /* position in current byte in the bit stream. */
+ int xoctet_aligned = octet_aligned;
+ /* Massive kludge, but we need it to stay alive. Here goes: */
+ if (f->data.ptr == ex_amrnb)
+ xoctet_aligned = 1;
+ //ast_log(LOG_WARNING, "AMR-NB set octet-aligned mode!\n");
+ pos = unpack_bits(&src, 7, &cmr, xoctet_aligned ? 8 : 4);
+ cmr >>= 4; /* So we get correct one */
+
+ /* Get the table of contents first... */
+ while (src < end_ptr && more_frames) {
+ unsigned char ch;
+ /* get table of contents. */
+ pos = unpack_bits(&src, pos, &ch, xoctet_aligned ? 8 : 6);
+ more_frames = (ch>>7);
+ toc[nframes].ft = (ch >> 3) & 0x0F; /* Kill Q bit */
+ toc[nframes].q = (ch >> 2) & 0x01;
+#if 0
+ ast_verbose("amrnbtolin_framein: cmr=%02hhx, toc.ft=%02hhx,toc.q=%d more=%d, datalen=%d\n",
+ cmr, toc[nframes].ft, toc[nframes].q, more_frames, f->datalen);
+#endif
+ nframes++;
+ }
+ /* Now get the speech bits, and decode as we go. */
+ for (x = 0; x<nframes; x++) {
+ unsigned char ft = toc[x].ft, q = toc[x].q;
+ int bits = xoctet_aligned ? (num_bits[ft]+7)&~7 : num_bits[ft];
+ if (ft == 14 || ft == 15) /* No data */
+ goto loop;
+
+ if (pvt->samples + AMRNB_SAMPLES > BUFFER_SAMPLES) {
+ ast_log(LOG_WARNING, "Out of buffer space\n");
+ return -1;
+ }
+#if 0
+ memset(buffer, 0, sizeof buffer); /* clear it. */
+#endif
+ /* for octet-aligned mode, the speech frames are octet aligned as well */
+ pos = unpack_bits(&src, pos, &buffer[1], bits);
+ buffer[0] = (ft<<3) | (q<<2);
+ Decoder_Interface_Decode(tmp->destate,buffer, dst + pvt->samples,0);
+ pvt->samples += AMRNB_SAMPLES;
+ pvt->datalen += 2 * AMRNB_SAMPLES;
+
+ loop:
+ (void)0;
+#if 0
+ ast_verbose("amrnb2lin: %d/%d Decode ft=%u, num_bits=%d\n", x,nframes, ft, bits);
+#endif
+ }
+
+ /* Honour the requested codec? */
+ if (cmr < tmp->enc_mode)
+ tmp->enc_mode = cmr;
+ return 0;
+}
+
+/*! \brief store samples into working buffer for later decode */
+static int lintoamrnb_framein(struct ast_trans_pvt *pvt, struct ast_frame *f)
+{
+ struct amrnb_translator_pvt *tmp = pvt->pvt;
+
+ /* XXX We should look at how old the rest of our stream is, and if it
+ is too old, then we should overwrite it entirely, otherwise we can
+ get artifacts of earlier talk that do not belong */
+
+ /* ast_verbose("lintoamrnb_framein: %d samples\n", f->samples);*/
+
+ if (pvt->samples + f->samples > BUFFER_SAMPLES) {
+ ast_log(LOG_WARNING, "Out of buffer space\n");
+ return -1;
+ }
+ memcpy(tmp->buf + pvt->samples, f->data.ptr, f->datalen);
+ pvt->samples += f->samples;
+#if 0
+ ast_verbose("lintoamrnb_framein: %d/%d samples\n", f->samples, pvt->samples);
+#endif
+ return 0;
+}
+
+/*! \brief encode and produce a frame */
+static struct ast_frame *lintoamrnb_frameout(struct ast_trans_pvt *pvt)
+{
+ struct amrnb_translator_pvt *tmp = pvt->pvt;
+ int datalen = 0, samples = 0, npad, h_offset, d_offset;
+ int pbits = 0, sbits = 0; /* header and body bit count */
+ unsigned char buffer[AMRNB_FRAME_LEN+1], cmr = tmp->enc_mode, toc_entry, *phdr, *pdata;
+ const unsigned char xzero = 0;
+
+ /* We can't work on anything less than a frame in size */
+ if (pvt->samples < AMRNB_SAMPLES)
+ return NULL;
+
+#if 0
+ ast_verbose("lintoamrnb_frameout: %d samples\n", pvt->samples);
+#endif
+
+ /* First, put the CMR into the header. */
+ cmr <<= 4; /* Put in higher order nibble. */
+ phdr = pvt->outbuf.uc;
+ pdata = tmp->speech_bits;
+ d_offset = h_offset = 7;
+ h_offset = pack_bits(&phdr, h_offset, &cmr, octet_aligned ? 8 : 4);
+ pbits += octet_aligned ? 8 : 4;
+#if 0
+ memset(tmp->speech_bits, 0, sizeof tmp->speech_bits);
+ memset(buffer, 0, sizeof buffer);
+#endif
+ while (pvt->samples >= AMRNB_SAMPLES) {
+ unsigned int mode, bits, q;
+ /* Encode a frame of data */
+ Encoder_Interface_Encode(tmp->enstate, tmp->enc_mode,
+ tmp->buf + samples,
+ buffer, 0);
+ samples += AMRNB_SAMPLES;
+ pvt->samples -= AMRNB_SAMPLES;
+ mode = (buffer[0]>>3)&0x0F;
+ q = (buffer[0]>>2)&0x01;
+ toc_entry = (mode<<3) | (q<<2);
+
+ bits = octet_aligned ? (num_bits[mode]+7)&~7 : num_bits[mode];
+ /* Set the F bit */
+ if (pvt->samples >= AMRNB_SAMPLES) /* then we have another frame to pack, so... */
+ toc_entry |= (1<<7);
+ h_offset = pack_bits(&phdr, h_offset,
+ &toc_entry, octet_aligned ? 8 : 6); /* put in the table of contents element. */
+ pbits += octet_aligned ? 8 : 6;
+
+ /* Pack the bits of the speech. */
+ d_offset = pack_bits(&pdata, d_offset, &buffer[1], bits);
+ sbits += bits;
+#if 0
+ ast_verbose("lin2amrnb[1]: mode=%d,q=%d,enc_mode=%d,byte_count=%d,bits=%d,more=%d\n",
+ mode, q, tmp->enc_mode,byte_count,bits,
+ toc_entry & (1<<7) ? 1 : 0);
+#endif
+ }
+ /* CMR+TOC is already in outbuf. So: Add speech bits */
+ h_offset = pack_bits(&phdr, h_offset, tmp->speech_bits, sbits);
+ npad = (8 - ((sbits + pbits) & 7))&0x7; /* Number of padding bits */
+
+ if (octet_aligned && npad != 0)
+ ast_log(LOG_ERROR,"Padding bits cannot be > 0 in octet aligned mode!\n");
+ pack_bits(&phdr, h_offset, (void *)&xzero, npad); /* zero out the rest of the padding bits. */
+ datalen = (sbits + pbits + npad + 7)/8; /* Round up to nearest octet. */
+#if 0
+ ast_verbose("lin2amrnb: toc_bit_count=%d,body_bit_count=%d, npad=%d,p[0]=0X%02hhX,p[1]=0X%02hhX,data_len=%d\n",
+ pbits, sbits, npad, (unsigned)pvt->outbuf.uc[0], (unsigned)pvt->outbuf.uc[1], datalen);
+#endif
+ /* Move the data at the end of the buffer to the front */
+ if (pvt->samples)
+ memmove(tmp->buf, tmp->buf + samples, pvt->samples * 2);
+ return ast_trans_frameout(pvt, datalen, samples);
+}
+
+static void amrnb_destroy_stuff(struct ast_trans_pvt *pvt)
+{
+ struct amrnb_translator_pvt *tmp = pvt->pvt;
+ Encoder_Interface_exit(tmp->enstate);
+ Decoder_Interface_exit(tmp->destate);
+}
+
+/* Translators */
+static struct ast_translator amrnbtolin = {
+ .name = "amrnbtolin",
+ .newpvt = amrnb_new,
+ .framein = amrnbtolin_framein,
+ .destroy = amrnb_destroy_stuff,
+ .sample = amrnb_sample,
+ .buffer_samples = BUFFER_SAMPLES,
+ .buf_size = BUFFER_SAMPLES * 2,
+ .desc_size = sizeof (struct amrnb_translator_pvt ),
+ .native_plc = 1, /* FIXME: needed? */
+};
+
+static struct ast_translator lintoamrnb = {
+ .name = "lintoamrnb",
+ .newpvt = amrnb_new,
+ .framein = lintoamrnb_framein,
+ .frameout = lintoamrnb_frameout,
+ .destroy = amrnb_destroy_stuff,
+ .sample = slin8_sample,
+ .desc_size = sizeof (struct amrnb_translator_pvt ),
+ .buf_size = (BUFFER_SAMPLES * AMRNB_FRAME_LEN + AMRNB_SAMPLES - 1)/AMRNB_SAMPLES,
+// .buffer_samples = BUFFER_SAMPLES,
+};
+
+
+static int parse_config(int reload)
+{
+ struct ast_variable *var;
+ struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
+ struct ast_config *cfg = ast_config_load("codecs.conf", config_flags);
+
+ if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEUNCHANGED || cfg == CONFIG_STATUS_FILEINVALID)
+ return 0;
+
+ for (var = ast_variable_browse(cfg, "amr"); var; var = var->next) {
+ if (!strcasecmp(var->name, "octet-aligned")) {
+ octet_aligned = ast_true(var->value) ? 1 : 0;
+ ast_verb(3, "codec_amrnb: octet-align mode set to [%s]\n", octet_aligned ? "on" : "off");
+ } else if (!strcasecmp(var->name, "dtx")) {
+ dtx = ast_true(var->value) ? 1 : 0;
+ ast_verb(3, "codec_amrnb: set dtx mode to [%s]\n", dtx ? "on" : "off");
+ } else if (!strcasecmp(var->name, "mode")) {
+ int mode_tmp = strtol(var->value + 2, NULL, 10);
+ int req_mode;
+ for (req_mode = 0; req_mode < 8; req_mode++)
+ if (mode_tmp == modeConv[req_mode])
+ break;
+ if (req_mode == 8) {
+ ast_log(LOG_ERROR, "Error, unknown mode %s. Must be one of MR475, MR515, MR59, MR67, MR74, MR795, MR102, MR122\n",
+ var->value);
+ } else {
+ enc_mode = req_mode;
+ ast_verb(3, "codec_amrnb: AMR-NB mode set to MR%d\n", mode_tmp);
+ }
+ }
+ }
+ ast_config_destroy(cfg);
+ ast_verbose("codec_amrnb: enc_mode = %d, dtx = %d\n", enc_mode, dtx);
+
+ return 0;
+}
+
+/*! \brief standard module glue */
+static int reload(void)
+{
+ if (parse_config(1))
+ return AST_MODULE_LOAD_DECLINE;
+ return AST_MODULE_LOAD_SUCCESS;
+}
+
+static int unload_module(void)
+{
+ int res;
+
+ res = ast_unregister_translator(&lintoamrnb);
+ if (!res)
+ res = ast_unregister_translator(&amrnbtolin);
+
+ return res;
+}
+
+static int load_module(void)
+{
+ int res = 0;
+
+ if (parse_config(0))
+ return AST_MODULE_LOAD_DECLINE;
+
+ ast_format_set(&amrnbtolin.src_format, AST_FORMAT_AMRNB, 0);
+ ast_format_set(&amrnbtolin.dst_format, AST_FORMAT_SLINEAR, 0);
+
+ ast_format_set(&lintoamrnb.src_format, AST_FORMAT_SLINEAR, 0);
+ ast_format_set(&lintoamrnb.dst_format, AST_FORMAT_AMRNB, 0);
+
+ res = ast_register_translator(&amrnbtolin);
+ if (!res)
+ res=ast_register_translator(&lintoamrnb);
+ else
+ ast_unregister_translator(&amrnbtolin);
+
+ if (res)
+ return AST_MODULE_LOAD_FAILURE;
+ return AST_MODULE_LOAD_SUCCESS;
+}
+
+AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "AMR-NB Coder/Decoder",
+ .load = load_module,
+ .unload = unload_module,
+ .reload = reload,
+ );
Index: asterisk-11.10.2/main/format.c
===================================================================
--- asterisk-11.10.2.orig/main/format.c 2014-06-17 18:53:02.694454582 -0400
+++ asterisk-11.10.2/main/format.c 2014-06-21 16:02:40.957454583 -0400
@@ -382,6 +382,9 @@
/*! GSM compression */
case AST_FORMAT_GSM:
return (1ULL << 1);
+ /*! AMR-NB compression */
+ case AST_FORMAT_AMRNB:
+ return (1ULL << 35);
/*! Raw mu-law data (G.711) */
case AST_FORMAT_ULAW:
return (1ULL << 2);
@@ -490,6 +493,9 @@
/*! GSM compression */
case (1ULL << 1):
return ast_format_set(dst, AST_FORMAT_GSM, 0);
+ /*! AMR-NB compression */
+ case (1ULL << 35):
+ return ast_format_set(dst, AST_FORMAT_AMRNB, 0);
/*! Raw mu-law data (G.711) */
case (1ULL << 2):
return ast_format_set(dst, AST_FORMAT_ULAW, 0);
@@ -1078,6 +1084,7 @@
format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_G719, 0), "g719", 48000, "ITU G.719", 160, 20, 80, 20, 20, 0, 0);
/* ORDER MAY CHANGE AFTER THIS POINT IN THE LIST */
+ format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_AMRNB, 0), "amr", 8000, "AMR-NB", 32, 20, 300, 20, 20, 0, 0); /*!< codec_amrnb.c */
format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_SPEEX32, 0), "speex32", 32000, "SpeeX 32khz", 10, 10, 60, 10, 20, 0, 0); /*!< codec_speex.c */
format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR12, 0), "slin12", 12000, "16 bit Signed Linear PCM (12kHz)", 240, 10, 70, 10, 20, AST_SMOOTHER_FLAG_BE, 0);/*!< Signed linear (12kHz) */
format_list_add_static(ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR24, 0), "slin24", 24000, "16 bit Signed Linear PCM (24kHz)", 480, 10, 70, 10, 20, AST_SMOOTHER_FLAG_BE, 0);/*!< Signed linear (24kHz) */
Index: asterisk-11.10.2/include/asterisk/format.h
===================================================================
--- asterisk-11.10.2.orig/include/asterisk/format.h 2014-06-17 18:53:02.766454582 -0400
+++ asterisk-11.10.2/include/asterisk/format.h 2014-06-17 19:33:15.462454585 -0400
@@ -49,6 +49,8 @@
AST_FORMAT_G723_1 = 1 + AST_FORMAT_TYPE_AUDIO,
/*! GSM compression */
AST_FORMAT_GSM = 2 + AST_FORMAT_TYPE_AUDIO,
+ /*! AMR-NB compression */
+ AST_FORMAT_AMRNB = 31 + AST_FORMAT_TYPE_AUDIO,
/*! Raw mu-law data (G.711) */
AST_FORMAT_ULAW = 3 + AST_FORMAT_TYPE_AUDIO,
/*! Raw A-law data (G.711) */
Index: asterisk-11.10.2/main/channel.c
===================================================================
--- asterisk-11.10.2.orig/main/channel.c 2014-06-17 18:53:02.726454582 -0400
+++ asterisk-11.10.2/main/channel.c 2014-06-23 17:53:44.957721412 -0400
@@ -908,6 +908,7 @@
/*! Okay, we're down to vocoders now, so pick GSM because it's small and easier to
translate and sounds pretty good */
AST_FORMAT_GSM,
+ AST_FORMAT_AMRNB,
/*! iLBC is not too bad */
AST_FORMAT_ILBC,
/*! Speex is free, but computationally more expensive than GSM */
Index: asterisk-11.10.2/main/frame.c
===================================================================
--- asterisk-11.10.2.orig/main/frame.c 2014-06-17 18:53:02.710454582 -0400
+++ asterisk-11.10.2/main/frame.c 2014-06-18 15:04:15.003454584 -0400
@@ -1059,6 +1059,9 @@
case AST_FORMAT_GSM:
samples = 160 * (f->datalen / 33);
break;
+ case AST_FORMAT_AMRNB:
+ samples = 160 * (f->datalen / 32); /* Use smallest packet size. Crude, but... */
+ break;
case AST_FORMAT_G729A:
samples = f->datalen * 8;
break;
@@ -1142,6 +1145,9 @@
case AST_FORMAT_GSM:
len = (samples / 160) * 33;
break;
+ case AST_FORMAT_AMRNB:
+ len = (samples / 160) * 32;
+ break;
case AST_FORMAT_G729A:
len = samples / 8;
break;
Index: asterisk-11.10.2/main/rtp_engine.c
===================================================================
--- asterisk-11.10.2.orig/main/rtp_engine.c 2014-06-17 18:53:02.744454582 -0400
+++ asterisk-11.10.2/main/rtp_engine.c 2014-06-18 14:21:59.821454577 -0400
@@ -2274,6 +2274,7 @@
/* Define all the RTP mime types available */
set_next_mime_type(ast_format_set(&tmpfmt, AST_FORMAT_G723_1, 0), 0, "audio", "G723", 8000);
set_next_mime_type(ast_format_set(&tmpfmt, AST_FORMAT_GSM, 0), 0, "audio", "GSM", 8000);
+ set_next_mime_type(ast_format_set(&tmpfmt, AST_FORMAT_AMRNB, 0), 0, "audio", "AMR", 8000);
set_next_mime_type(ast_format_set(&tmpfmt, AST_FORMAT_ULAW, 0), 0, "audio", "PCMU", 8000);
set_next_mime_type(ast_format_set(&tmpfmt, AST_FORMAT_ULAW, 0), 0, "audio", "G711U", 8000);
set_next_mime_type(ast_format_set(&tmpfmt, AST_FORMAT_ALAW, 0), 0, "audio", "PCMA", 8000);
@@ -2335,6 +2336,7 @@
add_static_payload(26, ast_format_set(&tmpfmt, AST_FORMAT_JPEG, 0), 0);
add_static_payload(31, ast_format_set(&tmpfmt, AST_FORMAT_H261, 0), 0);
add_static_payload(34, ast_format_set(&tmpfmt, AST_FORMAT_H263, 0), 0);
+ add_static_payload(96, ast_format_set(&tmpfmt, AST_FORMAT_AMRNB, 0), 0);
add_static_payload(97, ast_format_set(&tmpfmt, AST_FORMAT_ILBC, 0), 0);
add_static_payload(98, ast_format_set(&tmpfmt, AST_FORMAT_H263_PLUS, 0), 0);
add_static_payload(99, ast_format_set(&tmpfmt, AST_FORMAT_H264, 0), 0);
Index: asterisk-11.10.2/res/res_rtp_asterisk.c
===================================================================
--- asterisk-11.10.2.orig/res/res_rtp_asterisk.c 2014-06-17 18:53:02.797454583 -0400
+++ asterisk-11.10.2/res/res_rtp_asterisk.c 2014-06-17 18:56:33.882454583 -0400
@@ -2940,6 +2940,7 @@
case AST_FORMAT_SPEEX32:
case AST_FORMAT_SILK:
case AST_FORMAT_CELT:
+ case AST_FORMAT_AMRNB:
case AST_FORMAT_G723_1:
case AST_FORMAT_SIREN7:
case AST_FORMAT_SIREN14:
Index: asterisk-11.10.2/codecs/ex_amrnb.h
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ asterisk-11.10.2/codecs/ex_amrnb.h 2014-06-19 21:32:10.340454603 -0400
@@ -0,0 +1,40 @@
+/*! \file
+ * \brief 8-bit raw data
+ *
+ * Source: gsm.example
+ *
+ * Copyright (C) 1999-2005, Digium Inc.
+ *
+ * Distributed under the terms of the GNU General Public License
+ *
+ */
+
+/* Got this by converting ex_slin16 to amrnb (in RTP Format) */
+static uint8_t ex_amrnb[] = {
+ 0x23, 0x21, 0x41, 0x4d, 0x52, 0x0a, 0x04, 0x63, 0x8e, 0xcb, 0xbf, 0xf6,
+ 0xe5, 0xfb, 0x84, 0xe0, 0xb6, 0xec, 0xac, 0x04, 0x53, 0x18, 0x26, 0x4f,
+ 0xf9, 0xff, 0xa0, 0x88, 0x63, 0x06, 0x91, 0xa4
+// 0x10, 0x0c, 0x46, 0xEF, 0x18, 0xE0, 0xF0, 0x84, 0xD3, 0x43,
+// 0xDE, 0x56, 0xCA, 0x4E, 0x8E,
+// 0xda, 0xa6, 0xac, 0x2d, 0xa3, 0x50, 0x00, 0x49, 0x24, 0x92,
+// 0x49, 0x24, 0x50, 0x40, 0x49, 0x24, 0x92, 0x37, 0x24, 0x52,
+// 0x00, 0x49, 0x24, 0x92, 0x47, 0x24, 0x50, 0x80, 0x46, 0xe3,
+// 0x6d, 0xb8, 0xdc,
+};
+
+static struct ast_frame *amrnb_sample(void)
+{
+ static struct ast_frame f = {
+ .frametype = AST_FRAME_VOICE,
+ .datalen = sizeof(ex_amrnb),
+ /* All frames are 20 ms long */
+ .samples = ARRAY_LEN(ex_amrnb), //AMRNB_SAMPLES,
+ .mallocd = 0,
+ .offset = 0,
+ .src = __PRETTY_FUNCTION__,
+ .data.ptr = ex_amrnb,
+ };
+
+ ast_format_set(&f.subclass.format, AST_FORMAT_AMRNB, 0);
+ return &f;
+}
Index: asterisk-11.10.2/configure.ac
===================================================================
--- asterisk-11.10.2.orig/configure.ac 2014-06-16 21:31:27.260454583 -0400
+++ asterisk-11.10.2/configure.ac 2014-06-17 18:56:33.882454583 -0400
@@ -461,6 +461,7 @@
AST_OPTION_ONLY([sounds-cache], [SOUNDS_CACHE_DIR], [cached sound tarfiles], [])
AST_EXT_LIB_SETUP([SPANDSP], [SPANDSP], [spandsp])
AST_EXT_LIB_SETUP([SS7], [ISDN SS7], [ss7])
+AST_EXT_LIB_SETUP([AMRNB], [OpenCORE AMR-NB], [opencore-amrnb])
AST_EXT_LIB_SETUP([SPEEX], [Speex], [speex])
AST_EXT_LIB_SETUP([SPEEX_PREPROCESS], [Speex preprocess routines], [speex])
AST_EXT_LIB_SETUP([SPEEXDSP], [SpeexDSP], [speexdsp])
@@ -2135,6 +2136,8 @@
AST_EXT_LIB_CHECK([COROSYNC], [cpg], [cpg_join], [corosync/cpg.h], [-lcfg])
AST_EXT_LIB_CHECK([COROSYNC_CFG_STATE_TRACK], [cfg], [corosync_cfg_state_track], [corosync/cfg.h], [-lcfg])
+AST_EXT_LIB_CHECK([AMRNB], [opencore-amrnb], [Decoder_Interface_Decode], [opencore-amrnb/interf_dec.h])
+
AST_EXT_LIB_CHECK([SPEEX], [speex], [speex_encode], [speex/speex.h], [-lm])
# See if the main speex library contains the preprocess functions
Index: asterisk-11.10.2/build_tools/menuselect-deps.in
===================================================================
--- asterisk-11.10.2.orig/build_tools/menuselect-deps.in 2014-06-16 21:31:27.196454583 -0400
+++ asterisk-11.10.2/build_tools/menuselect-deps.in 2014-06-17 18:56:33.883454583 -0400
@@ -52,6 +52,7 @@
RADIUS=@PBX_RADIUS@
LAUNCHD=@PBX_LAUNCHD@
SPANDSP=@PBX_SPANDSP@
+AMRNB=@PBX_AMRNB@
SPEEX=@PBX_SPEEX@
SPEEXDSP=@PBX_SPEEXDSP@
SPEEX_PREPROCESS=@PBX_SPEEX_PREPROCESS@
Index: asterisk-11.10.2/makeopts.in
===================================================================
--- asterisk-11.10.2.orig/makeopts.in 2014-06-16 21:31:27.008454581 -0400
+++ asterisk-11.10.2/makeopts.in 2014-06-17 18:56:33.905454576 -0400
@@ -256,6 +256,9 @@
SPANDSP_INCLUDE=@SPANDSP_INCLUDE@
SPANDSP_LIB=@SPANDSP_LIB@
+AMRNB_INCLUDE=@AMRNB_INCLUDE@
+AMRNB_LIB=@AMRNB_LIB@
+
SPEEX_INCLUDE=@SPEEX_INCLUDE@
SPEEX_LIB=@SPEEX_LIB@
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment