- replace the LGPL G.722 codec with Asterisk's public-domain copy

The previous src/libs/g722 was spandsp's G.722 offered only under GPL-2 or
LGPL-2.1. That blocks shipping rtphone statically linked in a closed binary
(the freeware VQ for Asterisk engine) without a relink offer. Asterisk's
codecs/g722 is the same code: Steve Underwood placed his contributions in the
public domain there, and the CMU 1993 code under it is "completely
unrestricted" for any use. src/libs/g722/README.md records the provenance and
both statements.

It also fixes the decoded level. Asterisk's copy halves the encoder input and
doubles the decoder output, so streams from Asterisk and ffmpeg decode at
their original level. The old copy decoded them 6 dB too quiet (ITU-convention
streams from pjmedia 12 dB), and its encoder clipped input above -6 dBFS.

Local changes to Asterisk's files:
- the decoder saturates its output instead of casting. Asterisk's cast wraps:
  259 samples in 11 s of speech peaking at -0.2 dBFS came out with the
  opposite sign;
- g722.h includes <stdint.h> and maps __inline__ for MSVC (the removed
  g722_inttypes.h used to).
Dropped: g722_bitstream.*, g722codec.c and three helper headers, none used.
The API is unchanged (g722_encode_init / g722_decode, same options).

Measured in vq-core (16 simultaneous replayed calls, NISQA speech):
- G.711 control calls score identically;
- normal-level G.722: SilentCall -0.09..-0.14, DeadAir-01 -0.06..-0.09, MOS
  unchanged;
- loud G.722 with a clipped source now shows AmpClipping 0.02-0.03 and MOS
  3.89/4.28 instead of 4.45: the codec overshoots on the clipped peaks at the
  correct level, which the old -6 dB hid;
- results are identical across runs (the old decoder varied by up to 0.30 MOS).

G.722 still loses about 44% of its packets in AudioReceiver because
G722Codec::info() reports an 8 kHz sample rate for 16 kHz audio. That is fixed
separately.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Dmytro Bogovych
2026-09-21 17:54:18 +02:00
parent 405483a00d
commit c8d9bad845
11 changed files with 993 additions and 1842 deletions
+3 -6
View File
@@ -1,16 +1,13 @@
project (g722_codec) project (g722_codec)
# Rely on C++ 11
set (CMAKE_CXX_STANDARD 20)
set (CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_POSITION_INDEPENDENT_CODE ON) set(CMAKE_POSITION_INDEPENDENT_CODE ON)
# G.722 from Asterisk (codecs/g722): Steve Underwood's spandsp code, which he
# placed in the public domain, on top of the CMU 1993 codec, whose use "for
# any research or commercial purpose, is completely unrestricted". See README.md.
set (G722_SOURCES set (G722_SOURCES
g722_bitstream.c
g722_decode.c g722_decode.c
g722_encode.c g722_encode.c
) )
add_library(g722_codec ${G722_SOURCES}) add_library(g722_codec ${G722_SOURCES})
+35
View File
@@ -0,0 +1,35 @@
# G.722 codec
Source: Asterisk, `codecs/g722/` (`g722.h`, `g722_encode.c`, `g722_decode.c`),
https://github.com/asterisk/asterisk, taken 2026-09-21.
## Licence
No copyleft. The code has two layers:
- **Steve Underwood, 2005** (spandsp): "Despite my general liking of the GPL, I
place my own contributions to this code in the public domain for the benefit
of all mankind - even the slimy ones who might try to proprietize my work and
use it to my detriment." (in each file's header)
- **Carnegie Mellon University, 1993** (Chengxiang Lu and Alex Hauptmann, Speech
Group): "The Carnegie Mellon ADPCM program is Copyright (c) 1993 by Carnegie
Mellon University. Use of this program, for any research or commercial
purpose, is completely unrestricted. If you make use of or redistribute this
material, we would appreciate acknowlegement of its origin." (the terms as
reproduced in sippy's libg722, https://github.com/sippy/libg722, LICENSE)
This replaces an older copy of the same spandsp code that was offered only
under GPL-2 or LGPL-2.1.
## Behaviour
Asterisk's version maps 16-bit PCM to the codec's range: the encoder halves its
input and the decoder doubles its output. Streams from Asterisk and ffmpeg
therefore decode at their original level. The older copy did neither, so it
decoded those streams 6 dB too quiet and clipped encoder input above -6 dBFS.
Local changes:
- the decoder saturates its output (`saturate()`) instead of casting. Asterisk's
cast wraps loud samples around int16: 259 samples in 11 s of speech peaking
at -0.2 dBFS came out as large values of the opposite sign;
- `g722.h` includes `<stdint.h>` and maps `__inline__` to `__inline` for MSVC.
+22 -53
View File
@@ -1,5 +1,5 @@
/* /*
* VoIPcodecs - a series of DSP components for telephony * SpanDSP - a series of DSP components for telephony
* *
* g722.h - The ITU G.722 codec. * g722.h - The ITU G.722 codec.
* *
@@ -7,21 +7,10 @@
* *
* Copyright (C) 2005 Steve Underwood * Copyright (C) 2005 Steve Underwood
* *
* All rights reserved. * Despite my general liking of the GPL, I place my own contributions
* * to this code in the public domain for the benefit of all mankind -
* This program is free software; you can redistribute it and/or modify * even the slimy ones who might try to proprietize my work and use it
* it under the terms of the GNU General Public License version 2, or * to my detriment.
* 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
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
* *
* Based on a single channel G.722 codec which is: * Based on a single channel G.722 codec which is:
* *
@@ -29,17 +18,19 @@
* Computer Science, Speech Group * Computer Science, Speech Group
* Chengxiang Lu and Alex Hauptmann * Chengxiang Lu and Alex Hauptmann
* *
* $Id: g722.h,v 1.17 2008/02/09 15:32:26 steveu Exp $ * $Id$
*/ */
/*! \file */ /*! \file */
#if !defined(_SPANDSP_G722_H_) #if !defined(_G722_H_)
#define _SPANDSP_G722_H_ #define _G722_H_
#include "inttypes.h"
#include <stdint.h> /* rtphone: the header uses int16_t/uint8_t itself */
#if defined(_MSC_VER) && !defined(__inline__)
#define __inline__ __inline /* rtphone: MSVC has no __inline__ (the .c files use it) */
#endif
/*! \page g722_page G.722 encoding and decoding /*! \page g722_page G.722 encoding and decoding
\section g722_page_sec_1 What does it do? \section g722_page_sec_1 What does it do?
@@ -60,6 +51,13 @@ enum
G722_PACKED = 0x0002 G722_PACKED = 0x0002
}; };
#ifndef INT16_MAX
#define INT16_MAX 32767
#endif
#ifndef INT16_MIN
#define INT16_MIN (-32768)
#endif
typedef struct typedef struct
{ {
/*! TRUE if the operating in the special ITU test mode, with the band split filters /*! TRUE if the operating in the special ITU test mode, with the band split filters
@@ -136,48 +134,19 @@ typedef struct
int out_bits; int out_bits;
} g722_decode_state_t; } g722_decode_state_t;
#if defined(__cplusplus) #ifdef __cplusplus
extern "C" extern "C" {
{
#endif #endif
/*! Initialise an G.722 encode context.
\param s The G.722 encode context.
\param rate The required bit rate for the G.722 data.
The valid rates are 64000, 56000 and 48000.
\param options
\return A pointer to the G.722 encode context, or NULL for error. */
g722_encode_state_t *g722_encode_init(g722_encode_state_t *s, int rate, int options); g722_encode_state_t *g722_encode_init(g722_encode_state_t *s, int rate, int options);
int g722_encode_release(g722_encode_state_t *s); int g722_encode_release(g722_encode_state_t *s);
/*! Encode a buffer of linear PCM data to G.722
\param s The G.722 context.
\param g722_data The G.722 data produced.
\param amp The audio sample buffer.
\param len The number of samples in the buffer.
\return The number of bytes of G.722 data produced. */
int g722_encode(g722_encode_state_t *s, uint8_t g722_data[], const int16_t amp[], int len); int g722_encode(g722_encode_state_t *s, uint8_t g722_data[], const int16_t amp[], int len);
/*! Initialise an G.722 decode context.
\param s The G.722 decode context.
\param rate The bit rate of the G.722 data.
The valid rates are 64000, 56000 and 48000.
\param options
\return A pointer to the G.722 decode context, or NULL for error. */
g722_decode_state_t *g722_decode_init(g722_decode_state_t *s, int rate, int options); g722_decode_state_t *g722_decode_init(g722_decode_state_t *s, int rate, int options);
int g722_decode_release(g722_decode_state_t *s); int g722_decode_release(g722_decode_state_t *s);
/*! Decode a buffer of G.722 data to linear PCM.
\param s The G.722 context.
\param amp The audio sample buffer.
\param g722_data
\param len
\return The number of samples returned. */
int g722_decode(g722_decode_state_t *s, int16_t amp[], const uint8_t g722_data[], int len); int g722_decode(g722_decode_state_t *s, int16_t amp[], const uint8_t g722_data[], int len);
#if defined(__cplusplus) #ifdef __cplusplus
} }
#endif #endif
-137
View File
@@ -1,137 +0,0 @@
/*
* VoIPcodecs - a series of DSP components for telephony
*
* bitstream.c - Bitstream composition and decomposition routines.
*
* Written by Steve Underwood <steveu@coppice.org>
*
* Copyright (C) 2006 Steve Underwood
*
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the Lesser Lesser GNU General Public License version 2.1.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
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: bitstream.c,v 1.8 2007/08/20 15:22:21 steveu Exp $
*/
/*! \file */
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include "inttypes.h"
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include "g722_telephony.h"
#include "g722_bitstream.h"
void bitstream_put(bitstream_state_t *s, uint8_t **c, unsigned int value, int bits)
{
value &= ((1 << bits) - 1);
if (s->residue + bits <= 32)
{
s->bitstream |= (value << s->residue);
s->residue += bits;
}
while (s->residue >= 8)
{
s->residue -= 8;
*(*c)++ = (uint8_t) (s->bitstream & 0xFF);
s->bitstream >>= 8;
}
}
/*- End of function --------------------------------------------------------*/
void bitstream_put2(bitstream_state_t *s, uint8_t **c, unsigned int value, int bits)
{
value &= ((1 << bits) - 1);
if (s->residue + bits <= 32)
{
s->bitstream = (s->bitstream << bits) | value;
s->residue += bits;
}
while (s->residue >= 8)
{
s->residue -= 8;
*(*c)++ = (uint8_t) ((s->bitstream >> s->residue) & 0xFF);
}
}
/*- End of function --------------------------------------------------------*/
unsigned int bitstream_get(bitstream_state_t *s, const uint8_t **c, int bits)
{
unsigned int x;
while (s->residue < (unsigned int) bits)
{
x = (unsigned int) *(*c)++;
s->bitstream |= (x << s->residue);
s->residue += 8;
}
s->residue -= bits;
x = s->bitstream & ((1 << bits) - 1);
s->bitstream >>= bits;
return x;
}
/*- End of function --------------------------------------------------------*/
unsigned int bitstream_get2(bitstream_state_t *s, const uint8_t **c, int bits)
{
unsigned int x;
while (s->residue < (unsigned int) bits)
{
x = (unsigned int) *(*c)++;
s->bitstream = (s->bitstream << 8) | x;
s->residue += 8;
}
s->residue -= bits;
x = (s->bitstream >> s->residue) & ((1 << bits) - 1);
return x;
}
/*- End of function --------------------------------------------------------*/
void bitstream_flush(bitstream_state_t *s, uint8_t **c)
{
if (s->residue > 0)
{
*(*c)++ = (uint8_t) ((s->bitstream << (8 - s->residue)) & 0xFF);
s->residue = 0;
}
}
/*- End of function --------------------------------------------------------*/
void bitstream_flush2(bitstream_state_t *s, uint8_t **c)
{
if (s->residue > 0)
{
*(*c)++ = (uint8_t) ((s->bitstream << (8 - s->residue)) & 0xFF);
s->residue = 0;
}
}
/*- End of function --------------------------------------------------------*/
bitstream_state_t *bitstream_init(bitstream_state_t *s)
{
if (s == NULL)
return NULL;
s->bitstream = 0;
s->residue = 0;
return s;
}
/*- End of function --------------------------------------------------------*/
/*- End of file ------------------------------------------------------------*/
-89
View File
@@ -1,89 +0,0 @@
/*
* VoIPcodecs - a series of DSP components for telephony
*
* bitstream.h - Bitstream composition and decomposition routines.
*
* Written by Steve Underwood <steveu@coppice.org>
*
* Copyright (C) 2006 Steve Underwood
*
* 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: bitstream.h,v 1.8 2007/12/13 11:31:32 steveu Exp $
*/
/*! \file */
#if !defined(_SPANDSP_BITSTREAM_H_)
#define _SPANDSP_BITSTREAM_H_
/*! \page bitstream_page Bitstream composition and decomposition
\section bitstream_page_sec_1 What does it do?
\section bitstream_page_sec_2 How does it work?
*/
/*! Bitstream handler state */
typedef struct
{
/*! The bit stream. */
unsigned int bitstream;
/*! The residual bits in bitstream. */
unsigned int residue;
} bitstream_state_t;
#if defined(__cplusplus)
extern "C"
{
#endif
/*! \brief Put a chunk of bits into the output buffer.
\param s A pointer to the bitstream context.
\param c A pointer to the bitstream output buffer.
\param value The value to be pushed into the output buffer.
\param bits The number of bits of value to be pushed. 1 to 25 bit is valid. */
void bitstream_put(bitstream_state_t *s, uint8_t **c, unsigned int value, int bits);
void bitstream_put2(bitstream_state_t *s, uint8_t **c, unsigned int value, int bits);
/*! \brief Get a chunk of bits from the input buffer.
\param s A pointer to the bitstream context.
\param c A pointer to the bitstream input buffer.
\param bits The number of bits of value to be grabbed. 1 to 25 bit is valid.
\return The value retrieved from the input buffer. */
unsigned int bitstream_get(bitstream_state_t *s, const uint8_t **c, int bits);
unsigned int bitstream_get2(bitstream_state_t *s, const uint8_t **c, int bits);
/*! \brief Flush any residual bit to the output buffer.
\param s A pointer to the bitstream context.
\param c A pointer to the bitstream output buffer. */
void bitstream_flush(bitstream_state_t *s, uint8_t **c);
void bitstream_flush2(bitstream_state_t *s, uint8_t **c);
/*! \brief Initialise a bitstream context.
\param s A pointer to the bitstream context.
\return A pointer to the bitstream context. */
bitstream_state_t *bitstream_init(bitstream_state_t *s);
#if defined(__cplusplus)
}
#endif
#endif
/*- End of file ------------------------------------------------------------*/
-157
View File
@@ -1,157 +0,0 @@
/*
* VoIPcodecs - a series of DSP components for telephony
*
* dc_restore.h - General telephony routines to restore the zero D.C.
* level to audio which has a D.C. bias.
*
* Written by Steve Underwood <steveu@coppice.org>
*
* Copyright (C) 2001 Steve Underwood
*
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2, 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
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: dc_restore.h,v 1.18 2007/04/08 08:16:17 steveu Exp $
*/
/*! \file */
#if !defined(_SPANDSP_DC_RESTORE_H_)
#define _SPANDSP_DC_RESTORE_H_
/*! \page dc_restore_page Removing DC bias from a signal
\section dc_restore_page_sec_1 What does it do?
Telecoms signals often contain considerable DC, but DC upsets a lot of signal
processing functions. Placing a zero DC restorer at the front of the processing
chain can often simplify the downstream processing.
\section dc_restore_page_sec_2 How does it work?
The DC restorer uses a leaky integrator to provide a long-ish term estimate of
the DC bias in the signal. A 32 bit estimate is used for the 16 bit audio, so
the noise introduced by the estimation can be keep in the lower bits, and the 16
bit DC value, which is subtracted from the signal, is fairly clean. The
following code fragment shows the algorithm used. dc_bias is a 32 bit integer,
while the sample and the resulting clean_sample are 16 bit integers.
dc_bias += ((((int32_t) sample << 15) - dc_bias) >> 14);
clean_sample = sample - (dc_bias >> 15);
*/
/*!
Zero DC restoration descriptor. This defines the working state for a single
instance of DC content filter.
*/
typedef struct
{
int32_t state;
} dc_restore_state_t;
#if defined(__cplusplus)
extern "C"
{
#endif
static __inline__ void dc_restore_init(dc_restore_state_t *dc)
{
dc->state = 0;
}
/*- End of function --------------------------------------------------------*/
static __inline__ int16_t dc_restore(dc_restore_state_t *dc, int16_t sample)
{
dc->state += ((((int32_t) sample << 15) - dc->state) >> 14);
return (int16_t) (sample - (dc->state >> 15));
}
/*- End of function --------------------------------------------------------*/
static __inline__ int16_t dc_restore_estimate(dc_restore_state_t *dc)
{
return (int16_t) (dc->state >> 15);
}
/*- End of function --------------------------------------------------------*/
static __inline__ int16_t saturate(int32_t amp)
{
int16_t amp16;
/* Hopefully this is optimised for the common case - not clipping */
amp16 = (int16_t) amp;
if (amp == amp16)
return amp16;
if (amp > INT16_MAX)
return INT16_MAX;
return INT16_MIN;
}
/*- End of function --------------------------------------------------------*/
/*#ifdef _MSC_VER
__inline float rintf (float flt)
{
_asm
{ fld flt
frndint
}
}
__inline double rint(double dbl)
{
__asm
{
fld dbl
frndint
}
}
__inline long lrintf (float flt)
{
long retval;
_asm
{ fld flt
fistp retval
}
return retval;
}
#endif
*/
static __inline__ int16_t fsaturatef(float famp)
{
if (famp > 32767.0)
return INT16_MAX;
if (famp < -32768.0)
return INT16_MIN;
return (int16_t) rintf(famp);
}
/*- End of function --------------------------------------------------------*/
static __inline__ int16_t fsaturate(double damp)
{
if (damp > 32767.0)
return INT16_MAX;
if (damp < -32768.0)
return INT16_MIN;
return (int16_t) rint(damp);
}
/*- End of function --------------------------------------------------------*/
#if defined(__cplusplus)
}
#endif
#endif
/*- End of file ------------------------------------------------------------*/
+46 -47
View File
@@ -1,5 +1,5 @@
/* /*
* VoIPcodecs - a series of DSP components for telephony * SpanDSP - a series of DSP components for telephony
* *
* g722_decode.c - The ITU G.722 codec, decode part. * g722_decode.c - The ITU G.722 codec, decode part.
* *
@@ -7,21 +7,10 @@
* *
* Copyright (C) 2005 Steve Underwood * Copyright (C) 2005 Steve Underwood
* *
* All rights reserved. * Despite my general liking of the GPL, I place my own contributions
* * to this code in the public domain for the benefit of all mankind -
* This program is free software; you can redistribute it and/or modify * even the slimy ones who might try to proprietize my work and use it
* it under the terms of the GNU General Public License version 2, or * to my detriment.
* 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
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
* *
* Based in part on a single channel G.722 codec which is: * Based in part on a single channel G.722 codec which is:
* *
@@ -29,7 +18,11 @@
* Computer Science, Speech Group * Computer Science, Speech Group
* Chengxiang Lu and Alex Hauptmann * Chengxiang Lu and Alex Hauptmann
* *
* $Id: g722_decode.c,v 1.20 2008/02/09 15:32:56 steveu Exp $ * $Id$
*
* rtphone: taken from Asterisk (codecs/g722). The only change is that the
* decoder saturates its output instead of letting a corrupt stream wrap
* around int16 (Asterisk casts (rlow << 1) and (xout >> 11) directly).
*/ */
/*! \file */ /*! \file */
@@ -38,18 +31,37 @@
#include <config.h> #include <config.h>
#endif #endif
#include "g722_inttypes.h" #include <stdio.h>
#include <inttypes.h>
#include <memory.h> #include <memory.h>
#include <stdlib.h> #include <stdlib.h>
#if defined(HAVE_TGMATH_H) #if 0
#include <tgmath.h> #include <tgmath.h>
#endif #endif
#include <math.h>
#include "g722_telephony.h"
#include "g722_dc_restore.h"
#include "g722.h" #include "g722.h"
#if !defined(FALSE)
#define FALSE 0
#endif
#if !defined(TRUE)
#define TRUE (!FALSE)
#endif
static __inline__ int16_t saturate(int32_t amp)
{
int16_t amp16;
/* Hopefully this is optimised for the common case - not clipping */
amp16 = (int16_t) amp;
if (amp == amp16)
return amp16;
if (amp > INT16_MAX)
return INT16_MAX;
return INT16_MIN;
}
/*- End of function --------------------------------------------------------*/
static void block4(g722_decode_state_t *s, int band, int d); static void block4(g722_decode_state_t *s, int band, int d);
static void block4(g722_decode_state_t *s, int band, int d) static void block4(g722_decode_state_t *s, int band, int d)
@@ -177,14 +189,8 @@ int g722_decode_release(g722_decode_state_t *s)
int g722_decode(g722_decode_state_t *s, int16_t amp[], const uint8_t g722_data[], int len) int g722_decode(g722_decode_state_t *s, int16_t amp[], const uint8_t g722_data[], int len)
{ {
static const int wl[8] = static const int wl[8] = {-60, -30, 58, 172, 334, 538, 1198, 3042 };
{ static const int rl42[16] = {0, 7, 6, 5, 4, 3, 2, 1, 7, 6, 5, 4, 3, 2, 1, 0 };
-60, -30, 58, 172, 334, 538, 1198, 3042
};
static const int rl42[16] =
{
0, 7, 6, 5, 4, 3, 2, 1, 7, 6, 5, 4, 3, 2, 1, 0
};
static const int ilb[32] = static const int ilb[32] =
{ {
2048, 2093, 2139, 2186, 2233, 2282, 2332, 2048, 2093, 2139, 2186, 2233, 2282, 2332,
@@ -193,18 +199,9 @@ int g722_decode(g722_decode_state_t *s, int16_t amp[], const uint8_t g722_data[]
3228, 3298, 3371, 3444, 3520, 3597, 3676, 3228, 3298, 3371, 3444, 3520, 3597, 3676,
3756, 3838, 3922, 4008 3756, 3838, 3922, 4008
}; };
static const int wh[3] = static const int wh[3] = {0, -214, 798};
{ static const int rh2[4] = {2, 1, 2, 1};
0, -214, 798 static const int qm2[4] = {-7408, -1616, 7408, 1616};
};
static const int rh2[4] =
{
2, 1, 2, 1
};
static const int qm2[4] =
{
-7408, -1616, 7408, 1616
};
static const int qm4[16] = static const int qm4[16] =
{ {
0, -20456, -12896, -8968, 0, -20456, -12896, -8968,
@@ -246,6 +243,7 @@ int g722_decode(g722_decode_state_t *s, int16_t amp[], const uint8_t g722_data[]
{ {
3, -11, 12, 32, -210, 951, 3876, -805, 362, -156, 53, -11, 3, -11, 12, 32, -210, 951, 3876, -805, 362, -156, 53, -11,
}; };
int dlowt; int dlowt;
int rlow; int rlow;
int ihigh; int ihigh;
@@ -369,19 +367,20 @@ int g722_decode(g722_decode_state_t *s, int16_t amp[], const uint8_t g722_data[]
if (s->itu_test_mode) if (s->itu_test_mode)
{ {
amp[outlen++] = (int16_t) (rlow << 1); amp[outlen++] = saturate(rlow << 1);
amp[outlen++] = (int16_t) (rhigh << 1); amp[outlen++] = (int16_t) (rhigh << 1);
} }
else else
{ {
if (s->eight_k) if (s->eight_k)
{ {
amp[outlen++] = (int16_t) rlow; amp[outlen++] = saturate(rlow << 1);
} }
else else
{ {
/* Apply the receive QMF */ /* Apply the receive QMF */
memcpy(s->x, &s->x[2], 22*sizeof(s->x[0])); for (i = 0; i < 22; i++)
s->x[i] = s->x[i + 2];
s->x[22] = rlow + rhigh; s->x[22] = rlow + rhigh;
s->x[23] = rlow - rhigh; s->x[23] = rlow - rhigh;
@@ -392,8 +391,8 @@ int g722_decode(g722_decode_state_t *s, int16_t amp[], const uint8_t g722_data[]
xout2 += s->x[2*i]*qmf_coeffs[i]; xout2 += s->x[2*i]*qmf_coeffs[i];
xout1 += s->x[2*i + 1]*qmf_coeffs[11 - i]; xout1 += s->x[2*i + 1]*qmf_coeffs[11 - i];
} }
amp[outlen++] = (int16_t) (xout1 >> 12); amp[outlen++] = saturate(xout1 >> 11);
amp[outlen++] = (int16_t) (xout2 >> 12); amp[outlen++] = saturate(xout2 >> 11);
} }
} }
} }
+35 -24
View File
@@ -1,5 +1,5 @@
/* /*
* VoIPcodecs - a series of DSP components for telephony * SpanDSP - a series of DSP components for telephony
* *
* g722_encode.c - The ITU G.722 codec, encode part. * g722_encode.c - The ITU G.722 codec, encode part.
* *
@@ -9,19 +9,10 @@
* *
* All rights reserved. * All rights reserved.
* *
* This program is free software; you can redistribute it and/or modify * Despite my general liking of the GPL, I place my own contributions
* it under the terms of the GNU General Public License version 2, or * to this code in the public domain for the benefit of all mankind -
* the Lesser GNU General Public License version 2.1, as published by * even the slimy ones who might try to proprietize my work and use it
* the Free Software Foundation. * to my detriment.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
* *
* Based on a single channel 64kbps only G.722 codec which is: * Based on a single channel 64kbps only G.722 codec which is:
* *
@@ -29,7 +20,7 @@
* Computer Science, Speech Group * Computer Science, Speech Group
* Chengxiang Lu and Alex Hauptmann * Chengxiang Lu and Alex Hauptmann
* *
* $Id: g722_encode.c,v 1.18 2008/02/09 15:32:56 steveu Exp $ * $Id$
*/ */
/*! \file */ /*! \file */
@@ -38,18 +29,37 @@
#include <config.h> #include <config.h>
#endif #endif
#include "g722_inttypes.h" #include <stdio.h>
#include <inttypes.h>
#include <memory.h> #include <memory.h>
#include <stdlib.h> #include <stdlib.h>
#if defined(HAVE_TGMATH_H) #if 0
#include <tgmath.h> #include <tgmath.h>
#endif #endif
#include <math.h>
#include "g722_telephony.h"
#include "g722_dc_restore.h"
#include "g722.h" #include "g722.h"
#if !defined(FALSE)
#define FALSE 0
#endif
#if !defined(TRUE)
#define TRUE (!FALSE)
#endif
static __inline__ int16_t saturate(int32_t amp)
{
int16_t amp16;
/* Hopefully this is optimised for the common case - not clipping */
amp16 = (int16_t) amp;
if (amp == amp16)
return amp16;
if (amp > INT16_MAX)
return INT16_MAX;
return INT16_MIN;
}
/*- End of function --------------------------------------------------------*/
static void block4(g722_encode_state_t *s, int band, int d) static void block4(g722_encode_state_t *s, int band, int d)
{ {
int wd1; int wd1;
@@ -269,13 +279,14 @@ int g722_encode(g722_encode_state_t *s, uint8_t g722_data[], const int16_t amp[]
{ {
if (s->eight_k) if (s->eight_k)
{ {
xlow = amp[j++]; xlow = amp[j++] >> 1;
} }
else else
{ {
/* Apply the transmit QMF */ /* Apply the transmit QMF */
/* Shuffle the buffer down */ /* Shuffle the buffer down */
memcpy(s->x, &s->x[2], 22*sizeof(s->x[0])); for (i = 0; i < 22; i++)
s->x[i] = s->x[i + 2];
s->x[22] = amp[j++]; s->x[22] = amp[j++];
s->x[23] = amp[j++]; s->x[23] = amp[j++];
@@ -287,8 +298,8 @@ int g722_encode(g722_encode_state_t *s, uint8_t g722_data[], const int16_t amp[]
sumodd += s->x[2*i]*qmf_coeffs[i]; sumodd += s->x[2*i]*qmf_coeffs[i];
sumeven += s->x[2*i + 1]*qmf_coeffs[11 - i]; sumeven += s->x[2*i + 1]*qmf_coeffs[11 - i];
} }
xlow = (sumeven + sumodd) >> 13; xlow = (sumeven + sumodd) >> 14;
xhigh = (sumeven - sumodd) >> 13; xhigh = (sumeven - sumodd) >> 14;
} }
} }
/* Block 1L, SUBTRA */ /* Block 1L, SUBTRA */
-103
View File
@@ -1,103 +0,0 @@
/*
* SpanDSP - a series of DSP components for telephony
*
* inttypes.h - a fudge for MSVC, which lacks this header
*
* Written by Steve Underwood <steveu@coppice.org>
*
* Copyright (C) 2006 Michael Jerris
*
*
* This file is released in the public domain.
*
*/
#if !defined(_INTTYPES_H_)
#define _INTTYPES_H_
#ifdef __cplusplus
extern "C" {
#endif
#ifdef _MSC_VER
#if (_MSC_VER >= 1400) // VC8+
#ifndef _CRT_SECURE_NO_DEPRECATE
#define _CRT_SECURE_NO_DEPRECATE
#endif
#ifndef _CRT_NONSTDC_NO_DEPRECATE
#define _CRT_NONSTDC_NO_DEPRECATE
#endif
#endif // VC8+
#include <windows.h>
typedef unsigned __int8 uint8_t;
typedef unsigned __int16 uint16_t;
typedef unsigned __int32 uint32_t;
typedef unsigned __int64 uint64_t;
typedef __int8 int8_t;
typedef __int16 int16_t;
typedef __int32 int32_t;
typedef __int64 int64_t;
#define inline __inline
#define __inline__ __inline
#define INT16_MAX 0x7fff
#define INT16_MIN (-INT16_MAX - 1)
#define _MMX_H_
/* disable the following warnings
* C4100: The formal parameter is not referenced in the body of the function. The unreferenced parameter is ignored.
* C4200: Non standard extension C zero sized array
* C4706: assignment within conditional expression
* C4244: conversion from 'type1' to 'type2', possible loss of data
* C4295: array is too small to include a terminating null character
* C4125: decimal digit terminates octal escape sequence
*/
#pragma warning(disable:4100 4200 4706 4295 4125)
//#pragma comment(lib, "ws2_32.lib")
#define strncasecmp _strnicmp
#define strcasecmp _stricmp
#define snprintf _snprintf
#if !defined(INFINITY)
#define INFINITY 0x7fffffff
#endif
#else
#include <stdint.h>
#endif
#define PACKAGE "voipcodecs"
#define VERSION "0.0.1andabit"
#ifndef INT32_MAX
#define INT32_MAX (2147483647)
#endif
#ifndef INT32_MIN
#define INT32_MIN (-2147483647 - 1)
#endif
#define PRId8 "d"
#define PRId16 "d"
#ifndef PRId32
# define PRId32 "ld"
#endif
#ifndef PRId64
# define PRId64 "lld"
#endif
#define PRIu8 "u"
#define PRIu16 "u"
#ifndef PRIu32
# define PRIu32 "lu"
#endif
#ifndef PRIu64
# define PRIu64 "llu"
#endif
#ifdef __cplusplus
}
#endif
#endif // _INTTYPES_H_
-74
View File
@@ -1,74 +0,0 @@
/*
* VoIPcodecs - a series of DSP components for telephony
*
* telephony.h - some very basic telephony definitions
*
* Written by Steve Underwood <steveu@coppice.org>
*
* Copyright (C) 2003 Steve Underwood
*
* 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: telephony.h,v 1.10 2007/04/05 19:20:50 steveu Exp $
*/
#if !defined(_SPANDSP_TELEPHONY_H_)
#define _SPANDSP_TELEPHONY_H_
#define SAMPLE_RATE 8000
/* This is based on A-law, but u-law is only 0.03dB different */
#define DBM0_MAX_POWER (3.14f + 3.02f)
#define DBM0_MAX_SINE_POWER (3.14f)
/* This is based on the ITU definition of dbOv in G.100.1 */
#define DBOV_MAX_POWER (0.0f)
#define DBOV_MAX_SINE_POWER (-3.02f)
/*! \brief A handler for pure receive. The buffer cannot be altered. */
typedef int (span_rx_handler_t)(void *s, const int16_t amp[], int len);
/*! \brief A handler for receive, where the buffer can be altered. */
typedef int (span_mod_handler_t)(void *s, int16_t amp[], int len);
/*! \brief A handler for transmit, where the buffer will be filled. */
typedef int (span_tx_handler_t)(void *s, int16_t amp[], int max_len);
#define ms_to_samples(t) (((t)*SAMPLE_RATE)/1000)
#if !defined(FALSE)
#define FALSE 0
#endif
#if !defined(TRUE)
#define TRUE (!FALSE)
#endif
#include <assert.h>
#if (_MSC_VER >= 1400) // VC8+
#define vc_assert(expr) assert(expr);__analysis_assume( expr )
#else
#define vc_assert(expr) assert(expr)
#endif
#if defined(__cplusplus)
/* C++ doesn't seem to have sane rounding functions/macros yet */
#ifndef _MSC_VER
#define lrint(x) ((long int) (x))
#define lrintf(x) ((long int) (x))
#endif
#endif
#endif
/*- End of file ------------------------------------------------------------*/
-300
View File
@@ -1,300 +0,0 @@
/*
* G.722 Plugin codec for OpenH323/OPAL
*
* Copyright (C) 2008 by Hermon Labs, All Rights Reserved
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.0 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS"
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
* the License for the specific language governing rights and limitations
* under the License.
*
* The Original Code is Open Phone Abstraction Library.
*
* The Initial Developer of the Original Code is Eugene Mednikov
*
* Contributor(s): ______________________________________.
*
* $Revision: 23265 $
* $Author: rjongbloed $
* $Date: 2009-08-25 04:25:58 +0300 (вт, 25 серп 2009) $
*/
#ifndef PLUGIN_CODEC_DLL_EXPORTS
#include "plugin-config.h"
#endif
#include <codec/opalplugin.h>
#include "VoIPCodecs/inttypes.h"
#include "VoIPCodecs/g722.h"
#define INCLUDE_SDP_16000_VERSION 0
/* Due to a spec error, clock rate is 8kHz even though this is 16kHz codec,
see RFC3551/4.5.2. So some of these values have to be lied about so that
the OPAL system gets it right.
*/
#define CLOCK_RATE 8000 // Clock rate is not samples/second in this case!
#define BITS_PER_SECOND 64000 // raw bits per second
#define FRAME_TIME 1000 // Microseconds in a millisecond
#define SAMPLES_PER_FRAME 16 // Samples in a millisecond
#define BYTES_PER_FRAME 8 // Bytes in a millisecond
#define MAX_FRAMES_PER_PACKET 90 // 90 milliseconds, which means RTP packets smaller than 1500 bytes typical LAN maximum
#define PREF_FRAMES_PER_PACKET 20 // 20 milliseconds
static const char L16Desc[] = "PCM-16-16kHz"; // Cannot use "L16" as usual, force 16kHz PCM
static const char g722[] = "G.722-64k";
static const char sdpG722[] = "G722";
#if INCLUDE_SDP_16000_VERSION
static const char g722_16[] = "G.722-16kHz";
#endif
#define PAYLOAD_CODE 9
/////////////////////////////////////////////////////////////////////////////
static void * create_encoder(const struct PluginCodec_Definition * codec)
{
return g722_encode_init(NULL, BITS_PER_SECOND, 0);
}
static void destroy_encoder(const struct PluginCodec_Definition * codec, void * context)
{
g722_encode_release(context);
}
static int encode(const struct PluginCodec_Definition * codec,
void * context,
const void * from,
unsigned * fromLen,
void * to,
unsigned * toLen,
unsigned int * flag)
{
g722_encode_state_t * state = context;
if (*toLen < *fromLen / 4)
return 0; // Destination buffer not big enough
*toLen = g722_encode(state, to, from, *fromLen / 2);
return 1;
}
/////////////////////////////////////////////////////////////////////////////
static void * create_decoder(const struct PluginCodec_Definition * codec)
{
return g722_decode_init(NULL, BITS_PER_SECOND, 0);
}
static void destroy_decoder(const struct PluginCodec_Definition * codec, void * context)
{
g722_decode_release(context);
}
static int decode(const struct PluginCodec_Definition * codec,
void * _context,
const void * from,
unsigned * fromLen,
void * to,
unsigned * toLen,
unsigned int * flag)
{
g722_decode_state_t * state = _context;
if (*toLen < *fromLen * 4)
return 0; // Destination buffer not big enough
*toLen = g722_decode(state, to, from, *fromLen) * 2;
return 1;
}
/////////////////////////////////////////////////////////////////////////////
static struct PluginCodec_information licenseInfo = {
1084181196, // timestamp = Mon 10 May 2004 09:26:36 AM UTC
"Eugene Mednikov", // source code author
"1.0", // source code version
"em@hermonlabs.com", // source code email
"http://www.hermonlabs.com", // source code URL
"Copyright (C) 2008 by Hermon Labs, All Rights Reserved", // source code copyright
"MPL 1.0", // source code license
PluginCodec_License_MPL, // source code license
"ITU G.722", // codec description
"Steve Underwood", // codec author
NULL, // codec version
"steveu@coppice.org", // codec email
NULL, // codec URL
NULL, // codec copyright information
NULL, // codec license
PluginCodec_License_LGPL // codec license code
};
/////////////////////////////////////////////////////////////////////////////
static struct PluginCodec_Definition g722CodecDefn[] =
{
#if INCLUDE_SDP_16000_VERSION
// Include a version for SIP/SDP that indicates the more logical, though
// incorrect by RFC3551/4.5.2, 16000Hz version of G.722. We use dynamic
// payload types to avoid conflict with the compliant 8000Hz version.
{
// encoder
PLUGIN_CODEC_VERSION_WIDEBAND, // codec API version
&licenseInfo, // license information
PluginCodec_MediaTypeAudio | // audio codec
PluginCodec_InputTypeRaw | // raw input data
PluginCodec_OutputTypeRaw | // raw output data
PluginCodec_RTPTypeDynamic, // specified RTP type
g722_16, // text decription
L16Desc, // source format
g722_16, // destination format
0, // user data
16000, // samples per second
BITS_PER_SECOND, // raw bits per second
FRAME_TIME, // microseconds per frame
SAMPLES_PER_FRAME, // samples per frame
BYTES_PER_FRAME, // bytes per frame
PREF_FRAMES_PER_PACKET, // recommended number of frames per packet
MAX_FRAMES_PER_PACKET, // maximum number of frames per packe
PAYLOAD_CODE, // IANA RTP payload code
sdpG722, // RTP payload name
create_encoder, // create codec function
destroy_encoder, // destroy codec
encode, // encode/decode
NULL, // codec controls
0, // h323CapabilityType
NULL // h323CapabilityData
},
{
// decoder
PLUGIN_CODEC_VERSION_WIDEBAND, // codec API version
&licenseInfo, // license information
PluginCodec_MediaTypeAudio | // audio codec
PluginCodec_InputTypeRaw | // raw input data
PluginCodec_OutputTypeRaw | // raw output data
PluginCodec_RTPTypeDynamic, // specified RTP type
g722_16, // text decription
g722_16, // source format
L16Desc, // destination format
0, // user data
16000, // samples per second
BITS_PER_SECOND, // raw bits per second
FRAME_TIME, // microseconds per frame
SAMPLES_PER_FRAME, // samples per frame
BYTES_PER_FRAME, // bytes per frame
PREF_FRAMES_PER_PACKET, // recommended number of frames per packet
MAX_FRAMES_PER_PACKET, // maximum number of frames per packe
PAYLOAD_CODE, // IANA RTP payload code
sdpG722, // RTP payload name
create_decoder, // create codec function
destroy_decoder, // destroy codec
decode, // encode/decode
NULL, // codec controls
0, // h323CapabilityType
NULL // h323CapabilityData
},
#endif
// Standards compliant version
{
// encoder
PLUGIN_CODEC_VERSION_WIDEBAND, // codec API version
&licenseInfo, // license information
PluginCodec_MediaTypeAudio | // audio codec
PluginCodec_InputTypeRaw | // raw input data
PluginCodec_OutputTypeRaw | // raw output data
PluginCodec_RTPTypeExplicit, // specified RTP type
g722, // text decription
L16Desc, // source format
g722, // destination format
0, // user data
CLOCK_RATE, // samples per second
BITS_PER_SECOND, // raw bits per second
FRAME_TIME, // microseconds per frame
SAMPLES_PER_FRAME, // samples per frame
BYTES_PER_FRAME, // bytes per frame
PREF_FRAMES_PER_PACKET, // recommended number of frames per packet
MAX_FRAMES_PER_PACKET, // maximum number of frames per packe
PAYLOAD_CODE, // IANA RTP payload code
sdpG722, // RTP payload name
create_encoder, // create codec function
destroy_encoder, // destroy codec
encode, // encode/decode
NULL, // codec controls
PluginCodec_H323AudioCodec_g722_64k, // h323CapabilityType
NULL // h323CapabilityData
},
{
// decoder
PLUGIN_CODEC_VERSION_WIDEBAND, // codec API version
&licenseInfo, // license information
PluginCodec_MediaTypeAudio | // audio codec
PluginCodec_InputTypeRaw | // raw input data
PluginCodec_OutputTypeRaw | // raw output data
PluginCodec_RTPTypeExplicit, // specified RTP type
g722, // text decription
g722, // source format
L16Desc, // destination format
0, // user data
CLOCK_RATE, // samples per second
BITS_PER_SECOND, // raw bits per second
FRAME_TIME, // microseconds per frame
SAMPLES_PER_FRAME, // samples per frame
BYTES_PER_FRAME, // bytes per frame
PREF_FRAMES_PER_PACKET, // recommended number of frames per packet
MAX_FRAMES_PER_PACKET, // maximum number of frames per packe
PAYLOAD_CODE, // IANA RTP payload code
sdpG722, // RTP payload name
create_decoder, // create codec function
destroy_decoder, // destroy codec
decode, // encode/decode
NULL, // codec controls
PluginCodec_H323AudioCodec_g722_64k, // h323CapabilityType
NULL // h323CapabilityData
}
};
PLUGIN_CODEC_IMPLEMENT_ALL(G722, g722CodecDefn, PLUGIN_CODEC_VERSION_WIDEBAND)
/////////////////////////////////////////////////////////////////////////////