Created
May 18, 2015 18:59
-
-
Save airend/ad78f1ea0a3e6c13d230 to your computer and use it in GitHub Desktop.
AMR Narrowband for Asterisk 11.x
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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