diff --git a/libs/voipcodecs/src/ima_adpcm.c b/libs/voipcodecs/src/ima_adpcm.c index 7c8c11dd06..f7d348d492 100644 --- a/libs/voipcodecs/src/ima_adpcm.c +++ b/libs/voipcodecs/src/ima_adpcm.c @@ -1,8 +1,8 @@ /* - * VoIPcodecs - a series of DSP components for telephony + * SpanDSP - a series of DSP components for telephony * * ima_adpcm.c - Conversion routines between linear 16 bit PCM data and - * IMA/DVI/Intel ADPCM format. + * IMA/DVI/Intel ADPCM format. * * Written by Steve Underwood * @@ -11,8 +11,9 @@ * All rights reserved. * * This program is free software; you can redistribute it and/or modify - * it under the terms of the Lesser GNU General Public License version 2.1, as - * published by the Free Software Foundation. + * it under the terms of the GNU General Public License version 2, or + * the Lesser GNU General Public License version 2.1, as published by + * the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -23,7 +24,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * $Id: ima_adpcm.c,v 1.18 2006/11/30 15:41:47 steveu Exp $ + * $Id: ima_adpcm.c,v 1.21 2008/02/09 15:33:40 steveu Exp $ */ /*! \file */ @@ -42,9 +43,9 @@ #include #endif -#include "voipcodecs/telephony.h" -#include "voipcodecs/dc_restore.h" -#include "voipcodecs/ima_adpcm.h" +#include "spandsp/telephony.h" +#include "spandsp/dc_restore.h" +#include "spandsp/ima_adpcm.h" /* * Intel/DVI ADPCM coder/decoder. @@ -76,8 +77,46 @@ * Any left over bits in the last octet of an encoded burst are set to one. */ +/* + DVI4 uses an adaptive delta pulse code modulation (ADPCM) encoding + scheme that was specified by the Interactive Multimedia Association + (IMA) as the "IMA ADPCM wave type". However, the encoding defined + here as DVI4 differs in three respects from the IMA specification: + + o The RTP DVI4 header contains the predicted value rather than the + first sample value contained the IMA ADPCM block header. + + o IMA ADPCM blocks contain an odd number of samples, since the first + sample of a block is contained just in the header (uncompressed), + followed by an even number of compressed samples. DVI4 has an + even number of compressed samples only, using the `predict' word + from the header to decode the first sample. + + o For DVI4, the 4-bit samples are packed with the first sample in + the four most significant bits and the second sample in the four + least significant bits. In the IMA ADPCM codec, the samples are + packed in the opposite order. + + Each packet contains a single DVI block. This profile only defines + the 4-bit-per-sample version, while IMA also specified a 3-bit-per- + sample encoding. + + The "header" word for each channel has the following structure: + + int16 predict; // predicted value of first sample + // from the previous block (L16 format) + u_int8 index; // current index into stepsize table + u_int8 reserved; // set to zero by sender, ignored by receiver + + Each octet following the header contains two 4-bit samples, thus the + number of samples per packet MUST be even because there is no means + to indicate a partially filled last octet. +*/ + +#define STEP_MAX 88 + /* Intel ADPCM step variation table */ -static const int step_size[89] = +static const int step_size[STEP_MAX + 1] = { 7, 8, 9, 10, 11, 12, 13, 14, 16, 17, 19, 21, 23, 25, 28, 31, 34, 37, 41, 45, @@ -151,7 +190,6 @@ static int16_t decode(ima_adpcm_state_t *s, uint8_t adpcm) int16_t linear; /* e = (adpcm+0.5)*step/4 */ - ss = step_size[s->step_index]; e = ss >> 3; if (adpcm & 0x01) @@ -171,8 +209,8 @@ static int16_t decode(ima_adpcm_state_t *s, uint8_t adpcm) s->step_index += step_adjustment[adpcm & 0x07]; if (s->step_index < 0) s->step_index = 0; - else if (s->step_index > 88) - s->step_index = 88; + else if (s->step_index > STEP_MAX) + s->step_index = STEP_MAX; /*endif*/ return linear; } @@ -227,14 +265,14 @@ static uint8_t encode(ima_adpcm_state_t *s, int16_t linear) s->step_index += step_adjustment[adpcm & 0x07]; if (s->step_index < 0) s->step_index = 0; - else if (s->step_index > 88) - s->step_index = 88; + else if (s->step_index > STEP_MAX) + s->step_index = STEP_MAX; /*endif*/ return (uint8_t) adpcm; } /*- End of function --------------------------------------------------------*/ -ima_adpcm_state_t *ima_adpcm_init(ima_adpcm_state_t *s, int variant) +ima_adpcm_state_t *ima_adpcm_init(ima_adpcm_state_t *s, int variant, int chunk_size) { if (s == NULL) { @@ -244,6 +282,7 @@ ima_adpcm_state_t *ima_adpcm_init(ima_adpcm_state_t *s, int variant) /*endif*/ memset(s, 0, sizeof(*s)); s->variant = variant; + s->chunk_size = chunk_size; return s; } /*- End of function --------------------------------------------------------*/ @@ -266,11 +305,50 @@ int ima_adpcm_decode(ima_adpcm_state_t *s, uint16_t code; samples = 0; - if (s->variant == IMA_ADPCM_VDVI) + switch (s->variant) { + case IMA_ADPCM_IMA4: + i = 0; + if (s->chunk_size == 0) + { + amp[samples++] = (ima_data[1] << 8) | ima_data[0]; + s->step_index = ima_data[2]; + s->last = amp[0]; + i = 4; + } + for ( ; i < ima_bytes; i++) + { + amp[samples++] = decode(s, ima_data[i] & 0xF); + amp[samples++] = decode(s, (ima_data[i] >> 4) & 0xF); + } + /*endfor*/ + break; + case IMA_ADPCM_DVI4: + i = 0; + if (s->chunk_size == 0) + { + s->last = (int16_t) ((ima_data[0] << 8) | ima_data[1]); + s->step_index = ima_data[2]; + i = 4; + } + for ( ; i < ima_bytes; i++) + { + amp[samples++] = decode(s, (ima_data[i] >> 4) & 0xF); + amp[samples++] = decode(s, ima_data[i] & 0xF); + } + /*endfor*/ + break; + case IMA_ADPCM_VDVI: + i = 0; + if (s->chunk_size == 0) + { + s->last = (int16_t) ((ima_data[0] << 8) | ima_data[1]); + s->step_index = ima_data[2]; + i = 4; + } code = 0; s->bits = 0; - for (i = 0; ; ) + for (;;) { if (s->bits <= 8) { @@ -321,18 +399,10 @@ int ima_adpcm_decode(ima_adpcm_state_t *s, code <<= vdvi_decode[j].bits; s->bits -= vdvi_decode[j].bits; } - /*endfor*/ - } - else - { - for (i = 0; i < ima_bytes; i++) - { - amp[samples++] = decode(s, ima_data[i] & 0xF); - amp[samples++] = decode(s, (ima_data[i] >> 4) & 0xF); - } /*endwhile*/ + break; } - /*endif*/ + /*endswitch*/ return samples; } /*- End of function --------------------------------------------------------*/ @@ -347,8 +417,54 @@ int ima_adpcm_encode(ima_adpcm_state_t *s, uint8_t code; bytes = 0; - if (s->variant == IMA_ADPCM_VDVI) + switch (s->variant) { + case IMA_ADPCM_IMA4: + i = 0; + if (s->chunk_size == 0) + { + ima_data[bytes++] = amp[1]; + ima_data[bytes++] = amp[1] >> 8; + ima_data[bytes++] = s->step_index; + ima_data[bytes++] = 0; + s->last = amp[1]; + s->bits = 0; + i = 1; + } + for ( ; i < len; i++) + { + s->ima_byte = (uint8_t) ((s->ima_byte >> 4) | (encode(s, amp[i]) << 4)); + if ((s->bits++ & 1)) + ima_data[bytes++] = (uint8_t) s->ima_byte; + /*endif*/ + } + /*endfor*/ + break; + case IMA_ADPCM_DVI4: + if (s->chunk_size == 0) + { + ima_data[bytes++] = s->last >> 8; + ima_data[bytes++] = s->last; + ima_data[bytes++] = s->step_index; + ima_data[bytes++] = 0; + } + for (i = 0; i < len; i++) + { + s->ima_byte = (uint8_t) ((s->ima_byte << 4) | encode(s, amp[i])); + if ((s->bits++ & 1)) + ima_data[bytes++] = (uint8_t) s->ima_byte; + /*endif*/ + } + /*endfor*/ + break; + case IMA_ADPCM_VDVI: + if (s->chunk_size == 0) + { + ima_data[bytes++] = s->last >> 8; + ima_data[bytes++] = s->last; + ima_data[bytes++] = s->step_index; + ima_data[bytes++] = 0; + } s->bits = 0; for (i = 0; i < len; i++) { @@ -364,23 +480,11 @@ int ima_adpcm_encode(ima_adpcm_state_t *s, } /*endfor*/ if (s->bits) - { ima_data[bytes++] = (uint8_t) (((s->ima_byte << 8) | 0xFF) >> s->bits); - } /*endif*/ + break; } - else - { - for (i = 0; i < len; i++) - { - s->ima_byte = (uint8_t) ((s->ima_byte >> 4) | (encode(s, amp[i]) << 4)); - if ((s->bits++ & 1)) - ima_data[bytes++] = (uint8_t) s->ima_byte; - /*endif*/ - } - /*endfor*/ - } - /*endif*/ + /*endswitch*/ return bytes; } /*- End of function --------------------------------------------------------*/ diff --git a/libs/voipcodecs/src/voipcodecs/ima_adpcm.h b/libs/voipcodecs/src/voipcodecs/ima_adpcm.h index 8a54cb48f6..573f5066ca 100644 --- a/libs/voipcodecs/src/voipcodecs/ima_adpcm.h +++ b/libs/voipcodecs/src/voipcodecs/ima_adpcm.h @@ -14,8 +14,9 @@ * All rights reserved. * * This program is free software; you can redistribute it and/or modify - * it under the terms of the Lesser GNU General Public License version 2.1, as - * published by the Free Software Foundation. + * it under the terms of the GNU General Public License version 2, or + * the Lesser GNU General Public License version 2.1, as published by + * the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -26,7 +27,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * $Id: ima_adpcm.h,v 1.16 2007/12/13 11:31:32 steveu Exp $ + * $Id: ima_adpcm.h,v 1.18 2008/02/09 15:33:40 steveu Exp $ */ /*! \file */ @@ -46,8 +47,12 @@ IMA ADPCM offers a good balance of simplicity and quality at a rate of enum { - IMA_ADPCM_DVI4 = 0, - IMA_ADPCM_VDVI = 1 + /*! IMA4 is the original IMA ADPCM variant */ + IMA_ADPCM_IMA4 = 0, + /*! DVI4 is the IMA ADPCM variant defined in RFC3551 */ + IMA_ADPCM_DVI4 = 1, + /*! VDVI is the variable bit rate IMA ADPCM variant defined in RFC3551 */ + IMA_ADPCM_VDVI = 2 }; /*! @@ -58,6 +63,8 @@ enum typedef struct { int variant; + /*! \brief The size of a chunk, in samples. */ + int chunk_size; /*! \brief The last state of the ADPCM algorithm. */ int last; /*! \brief Current index into the step size table. */ @@ -75,8 +82,11 @@ extern "C" /*! Initialise an IMA ADPCM encode or decode context. \param s The IMA ADPCM context \param variant ??? + \param chunk_size The size of a chunk, in samples. A chunk size of + zero sample samples means treat each encode or decode operation + as a chunk. \return A pointer to the IMA ADPCM context, or NULL for error. */ -ima_adpcm_state_t *ima_adpcm_init(ima_adpcm_state_t *s, int variant); +ima_adpcm_state_t *ima_adpcm_init(ima_adpcm_state_t *s, int variant, int chunk_size); /*! Free an IMA ADPCM encode or decode context. \param s The IMA ADPCM context. diff --git a/src/mod/codecs/mod_voipcodecs/mod_voipcodecs.c b/src/mod/codecs/mod_voipcodecs/mod_voipcodecs.c index c818098f25..46f4ab8ed9 100644 --- a/src/mod/codecs/mod_voipcodecs/mod_voipcodecs.c +++ b/src/mod/codecs/mod_voipcodecs/mod_voipcodecs.c @@ -496,10 +496,10 @@ static switch_status_t switch_adpcm_init(switch_codec_t *codec, switch_codec_fla return SWITCH_STATUS_FALSE; } else { if (encoding) { - ima_adpcm_init(&context->encoder_object, IMA_ADPCM_DVI4); + ima_adpcm_init(&context->encoder_object, IMA_ADPCM_DVI4, 0); } if (decoding) { - ima_adpcm_init(&context->decoder_object, IMA_ADPCM_DVI4); + ima_adpcm_init(&context->decoder_object, IMA_ADPCM_DVI4, 0); } codec->private_info = context; @@ -538,7 +538,7 @@ static switch_status_t switch_adpcm_decode(switch_codec_t *codec, return SWITCH_STATUS_FALSE; } - *decoded_data_len = (2 * ima_adpcm_decode(&context->decoder_object, (int16_t *) decoded_data, (uint8_t *) encoded_data, encoded_data_len)); + *decoded_data_len = ima_adpcm_decode(&context->decoder_object, (int16_t *) decoded_data, (uint8_t *) encoded_data, encoded_data_len); return SWITCH_STATUS_SUCCESS; } @@ -567,14 +567,14 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_voipcodecs_load) for (count = 12; count > 0; count--) { switch_core_codec_add_implementation(pool, codec_interface, SWITCH_CODEC_TYPE_AUDIO, 5, "DVI4", NULL, 8000, 8000, 32000, - mpf * count, spf * count, bpf * count, ebpf * count, 1, 1, 12, + mpf * count, spf * count, bpf * count, (ebpf * count) + 4, 1, 1, 12, switch_adpcm_init, switch_adpcm_encode, switch_adpcm_decode, switch_adpcm_destroy); } - mpf = 10000, spf = 160, bpf = 360, ebpf = 160; + mpf = 10000, spf = 160, bpf = 320, ebpf = 160; for (count = 12; count > 0; count--) { switch_core_codec_add_implementation(pool, codec_interface, SWITCH_CODEC_TYPE_AUDIO, 6, "DVI4", NULL, 16000, 16000, 64000, - mpf * count, spf * count, bpf * count, ebpf * count, 1, 1, 12, + mpf * count, spf * count, bpf * count, (ebpf * count) + 4, 1, 1, 12, switch_adpcm_init, switch_adpcm_encode, switch_adpcm_decode, switch_adpcm_destroy); }