Compare commits
3
Commits
405483a00d
..
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f0a880c64d | ||
|
|
03c58c4572 | ||
|
|
c8d9bad845 |
@@ -434,6 +434,13 @@ Codec::Info OpusCodec::info()
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int OpusCodec::packetTime(std::span<const uint8_t> payload)
|
||||||
|
{
|
||||||
|
int samples = payload.empty() ? 0
|
||||||
|
: opus_packet_get_nb_samples(payload.data(), (opus_int32)payload.size(), mSamplerate);
|
||||||
|
return samples > 0 ? samples * 1000 / mSamplerate : frameTime();
|
||||||
|
}
|
||||||
|
|
||||||
Codec::EncodeResult OpusCodec::encode(std::span<const uint8_t> input, std::span<uint8_t> output)
|
Codec::EncodeResult OpusCodec::encode(std::span<const uint8_t> input, std::span<uint8_t> output)
|
||||||
{
|
{
|
||||||
// opus_encode() takes the frame size in samples per channel and the output
|
// opus_encode() takes the frame size in samples per channel and the output
|
||||||
@@ -1132,13 +1139,15 @@ G722Codec::~G722Codec()
|
|||||||
|
|
||||||
Codec::Info G722Codec::info()
|
Codec::Info G722Codec::info()
|
||||||
{
|
{
|
||||||
// ToDo: double check the G722 calls - remember RFC has bug about samplerate
|
// G.722 decodes to 16 kHz (640 bytes of PCM per 20 ms frame), but RFC 3551 keeps its RTP
|
||||||
|
// clock at 8 kHz for historical reasons: the timestamp unit is 1/8000, not 1/samplerate.
|
||||||
return {.mName = G722_MIME_NAME,
|
return {.mName = G722_MIME_NAME,
|
||||||
.mSamplerate = 8000,
|
.mSamplerate = 16000,
|
||||||
.mChannels = 1,
|
.mChannels = 1,
|
||||||
.mPcmLength = 640,
|
.mPcmLength = 640,
|
||||||
.mFrameTime = 20,
|
.mFrameTime = 20,
|
||||||
.mRtpLength = 160};
|
.mRtpLength = 160,
|
||||||
|
.mTimestampUnit = 1.0f / 8000};
|
||||||
}
|
}
|
||||||
|
|
||||||
Codec::EncodeResult G722Codec::encode(std::span<const uint8_t> input, std::span<uint8_t> output)
|
Codec::EncodeResult G722Codec::encode(std::span<const uint8_t> input, std::span<uint8_t> output)
|
||||||
@@ -1186,7 +1195,8 @@ const char* G722Codec::G722Factory::name()
|
|||||||
|
|
||||||
int G722Codec::G722Factory::samplerate()
|
int G722Codec::G722Factory::samplerate()
|
||||||
{
|
{
|
||||||
// Although G722 uses 16000 as rate for timestamping RTP frames - in fact it is 8KHz codec. So return 8KHz here.
|
// The rate SDP advertises (rtpmap G722/8000) is the RTP clock, 8 kHz by RFC 3551, although the
|
||||||
|
// audio is 16 kHz; see G722Codec::info().
|
||||||
return 8000;
|
return 8000;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -69,6 +69,8 @@ protected:
|
|||||||
int mDecoderChannels = 0;
|
int mDecoderChannels = 0;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
int packetTime(std::span<const uint8_t> payload) override;
|
||||||
|
|
||||||
struct Params
|
struct Params
|
||||||
{
|
{
|
||||||
bool mUseDtx = false, mUseInbandFec = false, mStereo = false;
|
bool mUseDtx = false, mUseInbandFec = false, mStereo = false;
|
||||||
|
|||||||
@@ -520,13 +520,11 @@ Codec* AudioReceiver::add(const std::shared_ptr<jrtplib::RTPPacket>& p)
|
|||||||
|
|
||||||
if (!codec)
|
if (!codec)
|
||||||
time_length = 10;
|
time_length = 10;
|
||||||
else if (!codec->rtpLength())
|
|
||||||
time_length = codec->frameTime();
|
|
||||||
else
|
else
|
||||||
time_length = lround(double(payloadLength) / codec->rtpLength() * codec->frameTime());
|
time_length = codec->packetTime(std::span{p->GetPayloadData(), (size_t)payloadLength});
|
||||||
|
|
||||||
if (codec)
|
if (codec)
|
||||||
samplerate = codec->samplerate();
|
samplerate = codec->rtpClockRate(); // RTP timestamp units, not PCM rate (G.722)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Process jitter anyway - can we decode payload or not
|
// Process jitter anyway - can we decode payload or not
|
||||||
@@ -724,7 +722,7 @@ AudioReceiver::DecodeResult AudioReceiver::decodePacketTo(Audio::DataWindow& out
|
|||||||
if (mLastPacketTimestamp && mLastPacketTimeLength && mCodec)
|
if (mLastPacketTimestamp && mLastPacketTimeLength && mCodec)
|
||||||
{
|
{
|
||||||
int units = rtp.GetTimestamp() - *mLastPacketTimestamp;
|
int units = rtp.GetTimestamp() - *mLastPacketTimestamp;
|
||||||
int milliseconds = units / (mCodec->samplerate() / 1000);
|
int milliseconds = units / (mCodec->rtpClockRate() / 1000);
|
||||||
if (milliseconds > mLastPacketTimeLength)
|
if (milliseconds > mLastPacketTimeLength)
|
||||||
{
|
{
|
||||||
auto silenceLength = std::chrono::milliseconds(milliseconds - mLastPacketTimeLength);
|
auto silenceLength = std::chrono::milliseconds(milliseconds - mLastPacketTimeLength);
|
||||||
@@ -794,8 +792,11 @@ AudioReceiver::DecodeResult AudioReceiver::decodePacketTo(Audio::DataWindow& out
|
|||||||
mFrameCount = mCodec->rtpLength() ? rtp.GetPayloadLength() / mCodec->rtpLength() : 1;
|
mFrameCount = mCodec->rtpLength() ? rtp.GetPayloadLength() / mCodec->rtpLength() : 1;
|
||||||
int frameLength = mCodec->rtpLength() ? mCodec->rtpLength() : (int)rtp.GetPayloadLength();
|
int frameLength = mCodec->rtpLength() ? mCodec->rtpLength() : (int)rtp.GetPayloadLength();
|
||||||
|
|
||||||
// Save last packet time length
|
// Save last packet time length. Taken from the payload, not mFrameCount *
|
||||||
mLastPacketTimeLength = mFrameCount * mCodec->frameTime();
|
// frameTime(): an Opus packet of 40 or 60 ms is one "frame" here, and counting
|
||||||
|
// it as frameTime() (20 ms) made the gap check above emit silence before every
|
||||||
|
// packet and pushed the jitter buffer into discarding about half of them.
|
||||||
|
mLastPacketTimeLength = mCodec->packetTime(std::span{rtp.GetPayloadData(), payload_length});
|
||||||
|
|
||||||
// Decode
|
// Decode
|
||||||
for (int i = 0; i < mFrameCount && !mCodecSettings.mSkipDecode; i++)
|
for (int i = 0; i < mFrameCount && !mCodecSettings.mSkipDecode; i++)
|
||||||
@@ -1157,11 +1158,16 @@ AudioReceiver::MediaInfo AudioReceiver::infoFor(jrtplib::RTPPacket& p)
|
|||||||
|
|
||||||
if (codec->rtpLength() != 0)
|
if (codec->rtpLength() != 0)
|
||||||
{
|
{
|
||||||
int frameCount = static_cast<int>(p.GetPayloadLength() / codec->rtpLength());
|
// A G.729 (PT 18) SID frame is shorter than a voice frame but stands for one; other
|
||||||
if (p.GetPayloadType() == 9 /*G729A silence*/ && p.GetPayloadLength() % codec->rtpLength())
|
// codecs scale with the payload (G.722 at 10 ms ptime carries half a 160-byte frame).
|
||||||
frameCount++;
|
if (p.GetPayloadType() == 18 && p.GetPayloadLength() % codec->rtpLength())
|
||||||
|
{
|
||||||
packetTime = std::chrono::milliseconds(frameCount * codec->frameTime());
|
int frameCount = static_cast<int>(p.GetPayloadLength() / codec->rtpLength()) + 1;
|
||||||
|
packetTime = std::chrono::milliseconds(frameCount * codec->frameTime());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
packetTime = std::chrono::milliseconds(
|
||||||
|
lround(double(p.GetPayloadLength()) / codec->rtpLength() * codec->frameTime()));
|
||||||
}
|
}
|
||||||
else if (typeid(*codec) == typeid(OpusCodec))
|
else if (typeid(*codec) == typeid(OpusCodec))
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -114,7 +114,7 @@ void AudioStream::setTransmittingCodec(Codec::Factory& factory, int payloadType)
|
|||||||
mTransmittingCodec = factory.create();
|
mTransmittingCodec = factory.create();
|
||||||
mTransmittingPayloadType = payloadType;
|
mTransmittingPayloadType = payloadType;
|
||||||
if (mRtpSession.IsActive())
|
if (mRtpSession.IsActive())
|
||||||
mRtpSession.SetTimestampUnit(1.0 / mTransmittingCodec->samplerate());
|
mRtpSession.SetTimestampUnit(mTransmittingCodec->timestampUnit());
|
||||||
}
|
}
|
||||||
|
|
||||||
PCodec AudioStream::transmittingCodec()
|
PCodec AudioStream::transmittingCodec()
|
||||||
@@ -241,7 +241,7 @@ void AudioStream::addData(const void* buffer, int bytes)
|
|||||||
ICELogMedia(<< "Sending RTP packet pt = " << mTransmittingPayloadType
|
ICELogMedia(<< "Sending RTP packet pt = " << mTransmittingPayloadType
|
||||||
<< ", plength = " << (int)mEncodedAudio.size() << " to ");
|
<< ", plength = " << (int)mEncodedAudio.size() << " to ");
|
||||||
mRtpSession.SendPacketEx(mEncodedAudio.data(), mEncodedAudio.size(), mTransmittingPayloadType, false,
|
mRtpSession.SendPacketEx(mEncodedAudio.data(), mEncodedAudio.size(), mTransmittingPayloadType, false,
|
||||||
packetTime * codec->samplerate() / 1000, 0, nullptr, 0);
|
packetTime * codec->rtpClockRate() / 1000, 0, nullptr, 0);
|
||||||
mEncodedAudio.clear();
|
mEncodedAudio.clear();
|
||||||
encodedTime = 0;
|
encodedTime = 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
#ifndef __MT_CODEC_H
|
#ifndef __MT_CODEC_H
|
||||||
#define __MT_CODEC_H
|
#define __MT_CODEC_H
|
||||||
|
|
||||||
|
#include <cmath>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <span>
|
#include <span>
|
||||||
|
|
||||||
@@ -66,9 +67,24 @@ public:
|
|||||||
int frameTime() { return info().mFrameTime; }
|
int frameTime() { return info().mFrameTime; }
|
||||||
std::string name() { return info().mName; }
|
std::string name() { return info().mName; }
|
||||||
float timestampUnit() { return info().mTimestampUnit == 0.0f ? 1.0f / info().mSamplerate : info().mTimestampUnit; }
|
float timestampUnit() { return info().mTimestampUnit == 0.0f ? 1.0f / info().mSamplerate : info().mTimestampUnit; }
|
||||||
|
// RTP clock rate in Hz, the unit of RTP timestamps. Equals samplerate() except for codecs
|
||||||
|
// whose RTP clock differs from the decoded audio: G.722 decodes to 16 kHz but its RTP clock
|
||||||
|
// is 8 kHz (RFC 3551). Use it for timestamp arithmetic and jitter, samplerate() for PCM.
|
||||||
|
int rtpClockRate() { return static_cast<int>(1.0f / timestampUnit() + 0.5f); }
|
||||||
|
|
||||||
Audio::Format getAudioFormat() { return Audio::Format(this->info().mSamplerate, this->info().mChannels); }
|
Audio::Format getAudioFormat() { return Audio::Format(this->info().mSamplerate, this->info().mChannels); }
|
||||||
|
|
||||||
|
// Audio duration of one RTP payload, in milliseconds. The default suits fixed-size
|
||||||
|
// frames (rtpLength() bytes per frameTime()); a codec whose packets carry a variable
|
||||||
|
// amount of audio (Opus: 2.5-120 ms, whatever the sender's ptime) reads it from the
|
||||||
|
// payload instead, as frameTime() is only the local ptime.
|
||||||
|
virtual int packetTime(std::span<const uint8_t> payload)
|
||||||
|
{
|
||||||
|
if (!rtpLength())
|
||||||
|
return frameTime();
|
||||||
|
return static_cast<int>(std::lround(double(payload.size()) / rtpLength() * frameTime()));
|
||||||
|
}
|
||||||
|
|
||||||
// Returns size of encoded data (RTP) in bytes
|
// Returns size of encoded data (RTP) in bytes
|
||||||
struct EncodeResult
|
struct EncodeResult
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -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})
|
||||||
|
|
||||||
|
|||||||
@@ -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.
|
||||||
+153
-184
@@ -1,184 +1,153 @@
|
|||||||
/*
|
/*
|
||||||
* 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.
|
||||||
*
|
*
|
||||||
* Written by Steve Underwood <steveu@coppice.org>
|
* Written by Steve Underwood <steveu@coppice.org>
|
||||||
*
|
*
|
||||||
* 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.
|
* Based on a single channel G.722 codec which is:
|
||||||
*
|
*
|
||||||
* This program is distributed in the hope that it will be useful,
|
***** Copyright (c) CMU 1993 *****
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* Computer Science, Speech Group
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* Chengxiang Lu and Alex Hauptmann
|
||||||
* GNU General Public License for more details.
|
*
|
||||||
*
|
* $Id$
|
||||||
* 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.
|
|
||||||
*
|
/*! \file */
|
||||||
* Based on a single channel G.722 codec which is:
|
|
||||||
*
|
#if !defined(_G722_H_)
|
||||||
***** Copyright (c) CMU 1993 *****
|
#define _G722_H_
|
||||||
* Computer Science, Speech Group
|
|
||||||
* Chengxiang Lu and Alex Hauptmann
|
#include <stdint.h> /* rtphone: the header uses int16_t/uint8_t itself */
|
||||||
*
|
#if defined(_MSC_VER) && !defined(__inline__)
|
||||||
* $Id: g722.h,v 1.17 2008/02/09 15:32:26 steveu Exp $
|
#define __inline__ __inline /* rtphone: MSVC has no __inline__ (the .c files use it) */
|
||||||
*/
|
#endif
|
||||||
|
|
||||||
|
/*! \page g722_page G.722 encoding and decoding
|
||||||
/*! \file */
|
\section g722_page_sec_1 What does it do?
|
||||||
|
The G.722 module is a bit exact implementation of the ITU G.722 specification for all three
|
||||||
#if !defined(_SPANDSP_G722_H_)
|
specified bit rates - 64000bps, 56000bps and 48000bps. It passes the ITU tests.
|
||||||
#define _SPANDSP_G722_H_
|
|
||||||
|
To allow fast and flexible interworking with narrow band telephony, the encoder and decoder
|
||||||
#include "inttypes.h"
|
support an option for the linear audio to be an 8k samples/second stream. In this mode the
|
||||||
|
codec is considerably faster, and still fully compatible with wideband terminals using G.722.
|
||||||
|
|
||||||
/*! \page g722_page G.722 encoding and decoding
|
\section g722_page_sec_2 How does it work?
|
||||||
\section g722_page_sec_1 What does it do?
|
???.
|
||||||
The G.722 module is a bit exact implementation of the ITU G.722 specification for all three
|
*/
|
||||||
specified bit rates - 64000bps, 56000bps and 48000bps. It passes the ITU tests.
|
|
||||||
|
enum
|
||||||
To allow fast and flexible interworking with narrow band telephony, the encoder and decoder
|
{
|
||||||
support an option for the linear audio to be an 8k samples/second stream. In this mode the
|
G722_SAMPLE_RATE_8000 = 0x0001,
|
||||||
codec is considerably faster, and still fully compatible with wideband terminals using G.722.
|
G722_PACKED = 0x0002
|
||||||
|
};
|
||||||
\section g722_page_sec_2 How does it work?
|
|
||||||
???.
|
#ifndef INT16_MAX
|
||||||
*/
|
#define INT16_MAX 32767
|
||||||
|
#endif
|
||||||
enum
|
#ifndef INT16_MIN
|
||||||
{
|
#define INT16_MIN (-32768)
|
||||||
G722_SAMPLE_RATE_8000 = 0x0001,
|
#endif
|
||||||
G722_PACKED = 0x0002
|
|
||||||
};
|
typedef struct
|
||||||
|
{
|
||||||
typedef struct
|
/*! TRUE if the operating in the special ITU test mode, with the band split filters
|
||||||
{
|
disabled. */
|
||||||
/*! TRUE if the operating in the special ITU test mode, with the band split filters
|
int itu_test_mode;
|
||||||
disabled. */
|
/*! TRUE if the G.722 data is packed */
|
||||||
int itu_test_mode;
|
int packed;
|
||||||
/*! TRUE if the G.722 data is packed */
|
/*! TRUE if encode from 8k samples/second */
|
||||||
int packed;
|
int eight_k;
|
||||||
/*! TRUE if encode from 8k samples/second */
|
/*! 6 for 48000kbps, 7 for 56000kbps, or 8 for 64000kbps. */
|
||||||
int eight_k;
|
int bits_per_sample;
|
||||||
/*! 6 for 48000kbps, 7 for 56000kbps, or 8 for 64000kbps. */
|
|
||||||
int bits_per_sample;
|
/*! Signal history for the QMF */
|
||||||
|
int x[24];
|
||||||
/*! Signal history for the QMF */
|
|
||||||
int x[24];
|
struct
|
||||||
|
{
|
||||||
struct
|
int s;
|
||||||
{
|
int sp;
|
||||||
int s;
|
int sz;
|
||||||
int sp;
|
int r[3];
|
||||||
int sz;
|
int a[3];
|
||||||
int r[3];
|
int ap[3];
|
||||||
int a[3];
|
int p[3];
|
||||||
int ap[3];
|
int d[7];
|
||||||
int p[3];
|
int b[7];
|
||||||
int d[7];
|
int bp[7];
|
||||||
int b[7];
|
int sg[7];
|
||||||
int bp[7];
|
int nb;
|
||||||
int sg[7];
|
int det;
|
||||||
int nb;
|
} band[2];
|
||||||
int det;
|
|
||||||
} band[2];
|
unsigned int in_buffer;
|
||||||
|
int in_bits;
|
||||||
unsigned int in_buffer;
|
unsigned int out_buffer;
|
||||||
int in_bits;
|
int out_bits;
|
||||||
unsigned int out_buffer;
|
} g722_encode_state_t;
|
||||||
int out_bits;
|
|
||||||
} g722_encode_state_t;
|
typedef struct
|
||||||
|
{
|
||||||
typedef struct
|
/*! TRUE if the operating in the special ITU test mode, with the band split filters
|
||||||
{
|
disabled. */
|
||||||
/*! TRUE if the operating in the special ITU test mode, with the band split filters
|
int itu_test_mode;
|
||||||
disabled. */
|
/*! TRUE if the G.722 data is packed */
|
||||||
int itu_test_mode;
|
int packed;
|
||||||
/*! TRUE if the G.722 data is packed */
|
/*! TRUE if decode to 8k samples/second */
|
||||||
int packed;
|
int eight_k;
|
||||||
/*! TRUE if decode to 8k samples/second */
|
/*! 6 for 48000kbps, 7 for 56000kbps, or 8 for 64000kbps. */
|
||||||
int eight_k;
|
int bits_per_sample;
|
||||||
/*! 6 for 48000kbps, 7 for 56000kbps, or 8 for 64000kbps. */
|
|
||||||
int bits_per_sample;
|
/*! Signal history for the QMF */
|
||||||
|
int x[24];
|
||||||
/*! Signal history for the QMF */
|
|
||||||
int x[24];
|
struct
|
||||||
|
{
|
||||||
struct
|
int s;
|
||||||
{
|
int sp;
|
||||||
int s;
|
int sz;
|
||||||
int sp;
|
int r[3];
|
||||||
int sz;
|
int a[3];
|
||||||
int r[3];
|
int ap[3];
|
||||||
int a[3];
|
int p[3];
|
||||||
int ap[3];
|
int d[7];
|
||||||
int p[3];
|
int b[7];
|
||||||
int d[7];
|
int bp[7];
|
||||||
int b[7];
|
int sg[7];
|
||||||
int bp[7];
|
int nb;
|
||||||
int sg[7];
|
int det;
|
||||||
int nb;
|
} band[2];
|
||||||
int det;
|
|
||||||
} band[2];
|
unsigned int in_buffer;
|
||||||
|
int in_bits;
|
||||||
unsigned int in_buffer;
|
unsigned int out_buffer;
|
||||||
int in_bits;
|
int out_bits;
|
||||||
unsigned int out_buffer;
|
} g722_decode_state_t;
|
||||||
int out_bits;
|
|
||||||
} g722_decode_state_t;
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
#if defined(__cplusplus)
|
#endif
|
||||||
extern "C"
|
|
||||||
{
|
g722_encode_state_t *g722_encode_init(g722_encode_state_t *s, int rate, int options);
|
||||||
#endif
|
int g722_encode_release(g722_encode_state_t *s);
|
||||||
|
int g722_encode(g722_encode_state_t *s, uint8_t g722_data[], const int16_t amp[], int len);
|
||||||
/*! Initialise an G.722 encode context.
|
|
||||||
\param s The G.722 encode context.
|
g722_decode_state_t *g722_decode_init(g722_decode_state_t *s, int rate, int options);
|
||||||
\param rate The required bit rate for the G.722 data.
|
int g722_decode_release(g722_decode_state_t *s);
|
||||||
The valid rates are 64000, 56000 and 48000.
|
int g722_decode(g722_decode_state_t *s, int16_t amp[], const uint8_t g722_data[], int len);
|
||||||
\param options
|
|
||||||
\return A pointer to the G.722 encode context, or NULL for error. */
|
#ifdef __cplusplus
|
||||||
g722_encode_state_t *g722_encode_init(g722_encode_state_t *s, int rate, int options);
|
}
|
||||||
|
#endif
|
||||||
int g722_encode_release(g722_encode_state_t *s);
|
|
||||||
|
#endif
|
||||||
/*! 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);
|
|
||||||
|
|
||||||
/*! 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);
|
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
#if defined(__cplusplus)
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|||||||
@@ -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 ------------------------------------------------------------*/
|
|
||||||
@@ -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 ------------------------------------------------------------*/
|
|
||||||
@@ -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 ------------------------------------------------------------*/
|
|
||||||
+402
-403
@@ -1,403 +1,402 @@
|
|||||||
/*
|
/*
|
||||||
* 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.
|
||||||
*
|
*
|
||||||
* Written by Steve Underwood <steveu@coppice.org>
|
* Written by Steve Underwood <steveu@coppice.org>
|
||||||
*
|
*
|
||||||
* 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.
|
* Based in part on a single channel G.722 codec which is:
|
||||||
*
|
*
|
||||||
* This program is distributed in the hope that it will be useful,
|
* Copyright (c) CMU 1993
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* Computer Science, Speech Group
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* Chengxiang Lu and Alex Hauptmann
|
||||||
* GNU General Public License for more details.
|
*
|
||||||
*
|
* $Id$
|
||||||
* You should have received a copy of the GNU General Public License
|
*
|
||||||
* along with this program; if not, write to the Free Software
|
* rtphone: taken from Asterisk (codecs/g722). The only change is that the
|
||||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
* decoder saturates its output instead of letting a corrupt stream wrap
|
||||||
*
|
* around int16 (Asterisk casts (rlow << 1) and (xout >> 11) directly).
|
||||||
* Based in part on a single channel G.722 codec which is:
|
*/
|
||||||
*
|
|
||||||
* Copyright (c) CMU 1993
|
/*! \file */
|
||||||
* Computer Science, Speech Group
|
|
||||||
* Chengxiang Lu and Alex Hauptmann
|
#ifdef HAVE_CONFIG_H
|
||||||
*
|
#include <config.h>
|
||||||
* $Id: g722_decode.c,v 1.20 2008/02/09 15:32:56 steveu Exp $
|
#endif
|
||||||
*/
|
|
||||||
|
#include <stdio.h>
|
||||||
/*! \file */
|
#include <inttypes.h>
|
||||||
|
#include <memory.h>
|
||||||
#ifdef HAVE_CONFIG_H
|
#include <stdlib.h>
|
||||||
#include <config.h>
|
#if 0
|
||||||
#endif
|
#include <tgmath.h>
|
||||||
|
#endif
|
||||||
#include "g722_inttypes.h"
|
|
||||||
#include <memory.h>
|
#include "g722.h"
|
||||||
#include <stdlib.h>
|
|
||||||
#if defined(HAVE_TGMATH_H)
|
#if !defined(FALSE)
|
||||||
#include <tgmath.h>
|
#define FALSE 0
|
||||||
#endif
|
#endif
|
||||||
#include <math.h>
|
#if !defined(TRUE)
|
||||||
|
#define TRUE (!FALSE)
|
||||||
#include "g722_telephony.h"
|
#endif
|
||||||
#include "g722_dc_restore.h"
|
|
||||||
#include "g722.h"
|
static __inline__ int16_t saturate(int32_t amp)
|
||||||
|
{
|
||||||
static void block4(g722_decode_state_t *s, int band, int d);
|
int16_t amp16;
|
||||||
|
|
||||||
static void block4(g722_decode_state_t *s, int band, int d)
|
/* Hopefully this is optimised for the common case - not clipping */
|
||||||
{
|
amp16 = (int16_t) amp;
|
||||||
int wd1;
|
if (amp == amp16)
|
||||||
int wd2;
|
return amp16;
|
||||||
int wd3;
|
if (amp > INT16_MAX)
|
||||||
int i;
|
return INT16_MAX;
|
||||||
|
return INT16_MIN;
|
||||||
/* Block 4, RECONS */
|
}
|
||||||
s->band[band].d[0] = d;
|
/*- End of function --------------------------------------------------------*/
|
||||||
s->band[band].r[0] = saturate(s->band[band].s + d);
|
|
||||||
|
static void block4(g722_decode_state_t *s, int band, int d);
|
||||||
/* Block 4, PARREC */
|
|
||||||
s->band[band].p[0] = saturate(s->band[band].sz + d);
|
static void block4(g722_decode_state_t *s, int band, int d)
|
||||||
|
{
|
||||||
/* Block 4, UPPOL2 */
|
int wd1;
|
||||||
for (i = 0; i < 3; i++)
|
int wd2;
|
||||||
s->band[band].sg[i] = s->band[band].p[i] >> 15;
|
int wd3;
|
||||||
wd1 = saturate(s->band[band].a[1] << 2);
|
int i;
|
||||||
|
|
||||||
wd2 = (s->band[band].sg[0] == s->band[band].sg[1]) ? -wd1 : wd1;
|
/* Block 4, RECONS */
|
||||||
if (wd2 > 32767)
|
s->band[band].d[0] = d;
|
||||||
wd2 = 32767;
|
s->band[band].r[0] = saturate(s->band[band].s + d);
|
||||||
wd3 = (s->band[band].sg[0] == s->band[band].sg[2]) ? 128 : -128;
|
|
||||||
wd3 += (wd2 >> 7);
|
/* Block 4, PARREC */
|
||||||
wd3 += (s->band[band].a[2]*32512) >> 15;
|
s->band[band].p[0] = saturate(s->band[band].sz + d);
|
||||||
if (wd3 > 12288)
|
|
||||||
wd3 = 12288;
|
/* Block 4, UPPOL2 */
|
||||||
else if (wd3 < -12288)
|
for (i = 0; i < 3; i++)
|
||||||
wd3 = -12288;
|
s->band[band].sg[i] = s->band[band].p[i] >> 15;
|
||||||
s->band[band].ap[2] = wd3;
|
wd1 = saturate(s->band[band].a[1] << 2);
|
||||||
|
|
||||||
/* Block 4, UPPOL1 */
|
wd2 = (s->band[band].sg[0] == s->band[band].sg[1]) ? -wd1 : wd1;
|
||||||
s->band[band].sg[0] = s->band[band].p[0] >> 15;
|
if (wd2 > 32767)
|
||||||
s->band[band].sg[1] = s->band[band].p[1] >> 15;
|
wd2 = 32767;
|
||||||
wd1 = (s->band[band].sg[0] == s->band[band].sg[1]) ? 192 : -192;
|
wd3 = (s->band[band].sg[0] == s->band[band].sg[2]) ? 128 : -128;
|
||||||
wd2 = (s->band[band].a[1]*32640) >> 15;
|
wd3 += (wd2 >> 7);
|
||||||
|
wd3 += (s->band[band].a[2]*32512) >> 15;
|
||||||
s->band[band].ap[1] = saturate(wd1 + wd2);
|
if (wd3 > 12288)
|
||||||
wd3 = saturate(15360 - s->band[band].ap[2]);
|
wd3 = 12288;
|
||||||
if (s->band[band].ap[1] > wd3)
|
else if (wd3 < -12288)
|
||||||
s->band[band].ap[1] = wd3;
|
wd3 = -12288;
|
||||||
else if (s->band[band].ap[1] < -wd3)
|
s->band[band].ap[2] = wd3;
|
||||||
s->band[band].ap[1] = -wd3;
|
|
||||||
|
/* Block 4, UPPOL1 */
|
||||||
/* Block 4, UPZERO */
|
s->band[band].sg[0] = s->band[band].p[0] >> 15;
|
||||||
wd1 = (d == 0) ? 0 : 128;
|
s->band[band].sg[1] = s->band[band].p[1] >> 15;
|
||||||
s->band[band].sg[0] = d >> 15;
|
wd1 = (s->band[band].sg[0] == s->band[band].sg[1]) ? 192 : -192;
|
||||||
for (i = 1; i < 7; i++)
|
wd2 = (s->band[band].a[1]*32640) >> 15;
|
||||||
{
|
|
||||||
s->band[band].sg[i] = s->band[band].d[i] >> 15;
|
s->band[band].ap[1] = saturate(wd1 + wd2);
|
||||||
wd2 = (s->band[band].sg[i] == s->band[band].sg[0]) ? wd1 : -wd1;
|
wd3 = saturate(15360 - s->band[band].ap[2]);
|
||||||
wd3 = (s->band[band].b[i]*32640) >> 15;
|
if (s->band[band].ap[1] > wd3)
|
||||||
s->band[band].bp[i] = saturate(wd2 + wd3);
|
s->band[band].ap[1] = wd3;
|
||||||
}
|
else if (s->band[band].ap[1] < -wd3)
|
||||||
|
s->band[band].ap[1] = -wd3;
|
||||||
/* Block 4, DELAYA */
|
|
||||||
for (i = 6; i > 0; i--)
|
/* Block 4, UPZERO */
|
||||||
{
|
wd1 = (d == 0) ? 0 : 128;
|
||||||
s->band[band].d[i] = s->band[band].d[i - 1];
|
s->band[band].sg[0] = d >> 15;
|
||||||
s->band[band].b[i] = s->band[band].bp[i];
|
for (i = 1; i < 7; i++)
|
||||||
}
|
{
|
||||||
|
s->band[band].sg[i] = s->band[band].d[i] >> 15;
|
||||||
for (i = 2; i > 0; i--)
|
wd2 = (s->band[band].sg[i] == s->band[band].sg[0]) ? wd1 : -wd1;
|
||||||
{
|
wd3 = (s->band[band].b[i]*32640) >> 15;
|
||||||
s->band[band].r[i] = s->band[band].r[i - 1];
|
s->band[band].bp[i] = saturate(wd2 + wd3);
|
||||||
s->band[band].p[i] = s->band[band].p[i - 1];
|
}
|
||||||
s->band[band].a[i] = s->band[band].ap[i];
|
|
||||||
}
|
/* Block 4, DELAYA */
|
||||||
|
for (i = 6; i > 0; i--)
|
||||||
/* Block 4, FILTEP */
|
{
|
||||||
wd1 = saturate(s->band[band].r[1] + s->band[band].r[1]);
|
s->band[band].d[i] = s->band[band].d[i - 1];
|
||||||
wd1 = (s->band[band].a[1]*wd1) >> 15;
|
s->band[band].b[i] = s->band[band].bp[i];
|
||||||
wd2 = saturate(s->band[band].r[2] + s->band[band].r[2]);
|
}
|
||||||
wd2 = (s->band[band].a[2]*wd2) >> 15;
|
|
||||||
s->band[band].sp = saturate(wd1 + wd2);
|
for (i = 2; i > 0; i--)
|
||||||
|
{
|
||||||
/* Block 4, FILTEZ */
|
s->band[band].r[i] = s->band[band].r[i - 1];
|
||||||
s->band[band].sz = 0;
|
s->band[band].p[i] = s->band[band].p[i - 1];
|
||||||
for (i = 6; i > 0; i--)
|
s->band[band].a[i] = s->band[band].ap[i];
|
||||||
{
|
}
|
||||||
wd1 = saturate(s->band[band].d[i] + s->band[band].d[i]);
|
|
||||||
s->band[band].sz += (s->band[band].b[i]*wd1) >> 15;
|
/* Block 4, FILTEP */
|
||||||
}
|
wd1 = saturate(s->band[band].r[1] + s->band[band].r[1]);
|
||||||
s->band[band].sz = saturate(s->band[band].sz);
|
wd1 = (s->band[band].a[1]*wd1) >> 15;
|
||||||
|
wd2 = saturate(s->band[band].r[2] + s->band[band].r[2]);
|
||||||
/* Block 4, PREDIC */
|
wd2 = (s->band[band].a[2]*wd2) >> 15;
|
||||||
s->band[band].s = saturate(s->band[band].sp + s->band[band].sz);
|
s->band[band].sp = saturate(wd1 + wd2);
|
||||||
}
|
|
||||||
/*- End of function --------------------------------------------------------*/
|
/* Block 4, FILTEZ */
|
||||||
|
s->band[band].sz = 0;
|
||||||
g722_decode_state_t *g722_decode_init(g722_decode_state_t *s, int rate, int options)
|
for (i = 6; i > 0; i--)
|
||||||
{
|
{
|
||||||
if (s == NULL)
|
wd1 = saturate(s->band[band].d[i] + s->band[band].d[i]);
|
||||||
{
|
s->band[band].sz += (s->band[band].b[i]*wd1) >> 15;
|
||||||
if ((s = (g722_decode_state_t *) malloc(sizeof(*s))) == NULL)
|
}
|
||||||
return NULL;
|
s->band[band].sz = saturate(s->band[band].sz);
|
||||||
}
|
|
||||||
memset(s, 0, sizeof(*s));
|
/* Block 4, PREDIC */
|
||||||
if (rate == 48000)
|
s->band[band].s = saturate(s->band[band].sp + s->band[band].sz);
|
||||||
s->bits_per_sample = 6;
|
}
|
||||||
else if (rate == 56000)
|
/*- End of function --------------------------------------------------------*/
|
||||||
s->bits_per_sample = 7;
|
|
||||||
else
|
g722_decode_state_t *g722_decode_init(g722_decode_state_t *s, int rate, int options)
|
||||||
s->bits_per_sample = 8;
|
{
|
||||||
if ((options & G722_SAMPLE_RATE_8000))
|
if (s == NULL)
|
||||||
s->eight_k = TRUE;
|
{
|
||||||
if ((options & G722_PACKED) && s->bits_per_sample != 8)
|
if ((s = (g722_decode_state_t *) malloc(sizeof(*s))) == NULL)
|
||||||
s->packed = TRUE;
|
return NULL;
|
||||||
else
|
}
|
||||||
s->packed = FALSE;
|
memset(s, 0, sizeof(*s));
|
||||||
s->band[0].det = 32;
|
if (rate == 48000)
|
||||||
s->band[1].det = 8;
|
s->bits_per_sample = 6;
|
||||||
return s;
|
else if (rate == 56000)
|
||||||
}
|
s->bits_per_sample = 7;
|
||||||
/*- End of function --------------------------------------------------------*/
|
else
|
||||||
|
s->bits_per_sample = 8;
|
||||||
int g722_decode_release(g722_decode_state_t *s)
|
if ((options & G722_SAMPLE_RATE_8000))
|
||||||
{
|
s->eight_k = TRUE;
|
||||||
free(s);
|
if ((options & G722_PACKED) && s->bits_per_sample != 8)
|
||||||
return 0;
|
s->packed = TRUE;
|
||||||
}
|
else
|
||||||
/*- End of function --------------------------------------------------------*/
|
s->packed = FALSE;
|
||||||
|
s->band[0].det = 32;
|
||||||
int g722_decode(g722_decode_state_t *s, int16_t amp[], const uint8_t g722_data[], int len)
|
s->band[1].det = 8;
|
||||||
{
|
return s;
|
||||||
static const int wl[8] =
|
}
|
||||||
{
|
/*- End of function --------------------------------------------------------*/
|
||||||
-60, -30, 58, 172, 334, 538, 1198, 3042
|
|
||||||
};
|
int g722_decode_release(g722_decode_state_t *s)
|
||||||
static const int rl42[16] =
|
{
|
||||||
{
|
free(s);
|
||||||
0, 7, 6, 5, 4, 3, 2, 1, 7, 6, 5, 4, 3, 2, 1, 0
|
return 0;
|
||||||
};
|
}
|
||||||
static const int ilb[32] =
|
/*- End of function --------------------------------------------------------*/
|
||||||
{
|
|
||||||
2048, 2093, 2139, 2186, 2233, 2282, 2332,
|
int g722_decode(g722_decode_state_t *s, int16_t amp[], const uint8_t g722_data[], int len)
|
||||||
2383, 2435, 2489, 2543, 2599, 2656, 2714,
|
{
|
||||||
2774, 2834, 2896, 2960, 3025, 3091, 3158,
|
static const int wl[8] = {-60, -30, 58, 172, 334, 538, 1198, 3042 };
|
||||||
3228, 3298, 3371, 3444, 3520, 3597, 3676,
|
static const int rl42[16] = {0, 7, 6, 5, 4, 3, 2, 1, 7, 6, 5, 4, 3, 2, 1, 0 };
|
||||||
3756, 3838, 3922, 4008
|
static const int ilb[32] =
|
||||||
};
|
{
|
||||||
static const int wh[3] =
|
2048, 2093, 2139, 2186, 2233, 2282, 2332,
|
||||||
{
|
2383, 2435, 2489, 2543, 2599, 2656, 2714,
|
||||||
0, -214, 798
|
2774, 2834, 2896, 2960, 3025, 3091, 3158,
|
||||||
};
|
3228, 3298, 3371, 3444, 3520, 3597, 3676,
|
||||||
static const int rh2[4] =
|
3756, 3838, 3922, 4008
|
||||||
{
|
};
|
||||||
2, 1, 2, 1
|
static const int wh[3] = {0, -214, 798};
|
||||||
};
|
static const int rh2[4] = {2, 1, 2, 1};
|
||||||
static const int qm2[4] =
|
static const int qm2[4] = {-7408, -1616, 7408, 1616};
|
||||||
{
|
static const int qm4[16] =
|
||||||
-7408, -1616, 7408, 1616
|
{
|
||||||
};
|
0, -20456, -12896, -8968,
|
||||||
static const int qm4[16] =
|
-6288, -4240, -2584, -1200,
|
||||||
{
|
20456, 12896, 8968, 6288,
|
||||||
0, -20456, -12896, -8968,
|
4240, 2584, 1200, 0
|
||||||
-6288, -4240, -2584, -1200,
|
};
|
||||||
20456, 12896, 8968, 6288,
|
static const int qm5[32] =
|
||||||
4240, 2584, 1200, 0
|
{
|
||||||
};
|
-280, -280, -23352, -17560,
|
||||||
static const int qm5[32] =
|
-14120, -11664, -9752, -8184,
|
||||||
{
|
-6864, -5712, -4696, -3784,
|
||||||
-280, -280, -23352, -17560,
|
-2960, -2208, -1520, -880,
|
||||||
-14120, -11664, -9752, -8184,
|
23352, 17560, 14120, 11664,
|
||||||
-6864, -5712, -4696, -3784,
|
9752, 8184, 6864, 5712,
|
||||||
-2960, -2208, -1520, -880,
|
4696, 3784, 2960, 2208,
|
||||||
23352, 17560, 14120, 11664,
|
1520, 880, 280, -280
|
||||||
9752, 8184, 6864, 5712,
|
};
|
||||||
4696, 3784, 2960, 2208,
|
static const int qm6[64] =
|
||||||
1520, 880, 280, -280
|
{
|
||||||
};
|
-136, -136, -136, -136,
|
||||||
static const int qm6[64] =
|
-24808, -21904, -19008, -16704,
|
||||||
{
|
-14984, -13512, -12280, -11192,
|
||||||
-136, -136, -136, -136,
|
-10232, -9360, -8576, -7856,
|
||||||
-24808, -21904, -19008, -16704,
|
-7192, -6576, -6000, -5456,
|
||||||
-14984, -13512, -12280, -11192,
|
-4944, -4464, -4008, -3576,
|
||||||
-10232, -9360, -8576, -7856,
|
-3168, -2776, -2400, -2032,
|
||||||
-7192, -6576, -6000, -5456,
|
-1688, -1360, -1040, -728,
|
||||||
-4944, -4464, -4008, -3576,
|
24808, 21904, 19008, 16704,
|
||||||
-3168, -2776, -2400, -2032,
|
14984, 13512, 12280, 11192,
|
||||||
-1688, -1360, -1040, -728,
|
10232, 9360, 8576, 7856,
|
||||||
24808, 21904, 19008, 16704,
|
7192, 6576, 6000, 5456,
|
||||||
14984, 13512, 12280, 11192,
|
4944, 4464, 4008, 3576,
|
||||||
10232, 9360, 8576, 7856,
|
3168, 2776, 2400, 2032,
|
||||||
7192, 6576, 6000, 5456,
|
1688, 1360, 1040, 728,
|
||||||
4944, 4464, 4008, 3576,
|
432, 136, -432, -136
|
||||||
3168, 2776, 2400, 2032,
|
};
|
||||||
1688, 1360, 1040, 728,
|
static const int qmf_coeffs[12] =
|
||||||
432, 136, -432, -136
|
{
|
||||||
};
|
3, -11, 12, 32, -210, 951, 3876, -805, 362, -156, 53, -11,
|
||||||
static const int qmf_coeffs[12] =
|
};
|
||||||
{
|
|
||||||
3, -11, 12, 32, -210, 951, 3876, -805, 362, -156, 53, -11,
|
int dlowt;
|
||||||
};
|
int rlow;
|
||||||
int dlowt;
|
int ihigh;
|
||||||
int rlow;
|
int dhigh;
|
||||||
int ihigh;
|
int rhigh;
|
||||||
int dhigh;
|
int xout1;
|
||||||
int rhigh;
|
int xout2;
|
||||||
int xout1;
|
int wd1;
|
||||||
int xout2;
|
int wd2;
|
||||||
int wd1;
|
int wd3;
|
||||||
int wd2;
|
int code;
|
||||||
int wd3;
|
int outlen;
|
||||||
int code;
|
int i;
|
||||||
int outlen;
|
int j;
|
||||||
int i;
|
|
||||||
int j;
|
outlen = 0;
|
||||||
|
rhigh = 0;
|
||||||
outlen = 0;
|
for (j = 0; j < len; )
|
||||||
rhigh = 0;
|
{
|
||||||
for (j = 0; j < len; )
|
if (s->packed)
|
||||||
{
|
{
|
||||||
if (s->packed)
|
/* Unpack the code bits */
|
||||||
{
|
if (s->in_bits < s->bits_per_sample)
|
||||||
/* Unpack the code bits */
|
{
|
||||||
if (s->in_bits < s->bits_per_sample)
|
s->in_buffer |= (g722_data[j++] << s->in_bits);
|
||||||
{
|
s->in_bits += 8;
|
||||||
s->in_buffer |= (g722_data[j++] << s->in_bits);
|
}
|
||||||
s->in_bits += 8;
|
code = s->in_buffer & ((1 << s->bits_per_sample) - 1);
|
||||||
}
|
s->in_buffer >>= s->bits_per_sample;
|
||||||
code = s->in_buffer & ((1 << s->bits_per_sample) - 1);
|
s->in_bits -= s->bits_per_sample;
|
||||||
s->in_buffer >>= s->bits_per_sample;
|
}
|
||||||
s->in_bits -= s->bits_per_sample;
|
else
|
||||||
}
|
{
|
||||||
else
|
code = g722_data[j++];
|
||||||
{
|
}
|
||||||
code = g722_data[j++];
|
|
||||||
}
|
switch (s->bits_per_sample)
|
||||||
|
{
|
||||||
switch (s->bits_per_sample)
|
default:
|
||||||
{
|
case 8:
|
||||||
default:
|
wd1 = code & 0x3F;
|
||||||
case 8:
|
ihigh = (code >> 6) & 0x03;
|
||||||
wd1 = code & 0x3F;
|
wd2 = qm6[wd1];
|
||||||
ihigh = (code >> 6) & 0x03;
|
wd1 >>= 2;
|
||||||
wd2 = qm6[wd1];
|
break;
|
||||||
wd1 >>= 2;
|
case 7:
|
||||||
break;
|
wd1 = code & 0x1F;
|
||||||
case 7:
|
ihigh = (code >> 5) & 0x03;
|
||||||
wd1 = code & 0x1F;
|
wd2 = qm5[wd1];
|
||||||
ihigh = (code >> 5) & 0x03;
|
wd1 >>= 1;
|
||||||
wd2 = qm5[wd1];
|
break;
|
||||||
wd1 >>= 1;
|
case 6:
|
||||||
break;
|
wd1 = code & 0x0F;
|
||||||
case 6:
|
ihigh = (code >> 4) & 0x03;
|
||||||
wd1 = code & 0x0F;
|
wd2 = qm4[wd1];
|
||||||
ihigh = (code >> 4) & 0x03;
|
break;
|
||||||
wd2 = qm4[wd1];
|
}
|
||||||
break;
|
/* Block 5L, LOW BAND INVQBL */
|
||||||
}
|
wd2 = (s->band[0].det*wd2) >> 15;
|
||||||
/* Block 5L, LOW BAND INVQBL */
|
/* Block 5L, RECONS */
|
||||||
wd2 = (s->band[0].det*wd2) >> 15;
|
rlow = s->band[0].s + wd2;
|
||||||
/* Block 5L, RECONS */
|
/* Block 6L, LIMIT */
|
||||||
rlow = s->band[0].s + wd2;
|
if (rlow > 16383)
|
||||||
/* Block 6L, LIMIT */
|
rlow = 16383;
|
||||||
if (rlow > 16383)
|
else if (rlow < -16384)
|
||||||
rlow = 16383;
|
rlow = -16384;
|
||||||
else if (rlow < -16384)
|
|
||||||
rlow = -16384;
|
/* Block 2L, INVQAL */
|
||||||
|
wd2 = qm4[wd1];
|
||||||
/* Block 2L, INVQAL */
|
dlowt = (s->band[0].det*wd2) >> 15;
|
||||||
wd2 = qm4[wd1];
|
|
||||||
dlowt = (s->band[0].det*wd2) >> 15;
|
/* Block 3L, LOGSCL */
|
||||||
|
wd2 = rl42[wd1];
|
||||||
/* Block 3L, LOGSCL */
|
wd1 = (s->band[0].nb*127) >> 7;
|
||||||
wd2 = rl42[wd1];
|
wd1 += wl[wd2];
|
||||||
wd1 = (s->band[0].nb*127) >> 7;
|
if (wd1 < 0)
|
||||||
wd1 += wl[wd2];
|
wd1 = 0;
|
||||||
if (wd1 < 0)
|
else if (wd1 > 18432)
|
||||||
wd1 = 0;
|
wd1 = 18432;
|
||||||
else if (wd1 > 18432)
|
s->band[0].nb = wd1;
|
||||||
wd1 = 18432;
|
|
||||||
s->band[0].nb = wd1;
|
/* Block 3L, SCALEL */
|
||||||
|
wd1 = (s->band[0].nb >> 6) & 31;
|
||||||
/* Block 3L, SCALEL */
|
wd2 = 8 - (s->band[0].nb >> 11);
|
||||||
wd1 = (s->band[0].nb >> 6) & 31;
|
wd3 = (wd2 < 0) ? (ilb[wd1] << -wd2) : (ilb[wd1] >> wd2);
|
||||||
wd2 = 8 - (s->band[0].nb >> 11);
|
s->band[0].det = wd3 << 2;
|
||||||
wd3 = (wd2 < 0) ? (ilb[wd1] << -wd2) : (ilb[wd1] >> wd2);
|
|
||||||
s->band[0].det = wd3 << 2;
|
block4(s, 0, dlowt);
|
||||||
|
|
||||||
block4(s, 0, dlowt);
|
if (!s->eight_k)
|
||||||
|
{
|
||||||
if (!s->eight_k)
|
/* Block 2H, INVQAH */
|
||||||
{
|
wd2 = qm2[ihigh];
|
||||||
/* Block 2H, INVQAH */
|
dhigh = (s->band[1].det*wd2) >> 15;
|
||||||
wd2 = qm2[ihigh];
|
/* Block 5H, RECONS */
|
||||||
dhigh = (s->band[1].det*wd2) >> 15;
|
rhigh = dhigh + s->band[1].s;
|
||||||
/* Block 5H, RECONS */
|
/* Block 6H, LIMIT */
|
||||||
rhigh = dhigh + s->band[1].s;
|
if (rhigh > 16383)
|
||||||
/* Block 6H, LIMIT */
|
rhigh = 16383;
|
||||||
if (rhigh > 16383)
|
else if (rhigh < -16384)
|
||||||
rhigh = 16383;
|
rhigh = -16384;
|
||||||
else if (rhigh < -16384)
|
|
||||||
rhigh = -16384;
|
/* Block 2H, INVQAH */
|
||||||
|
wd2 = rh2[ihigh];
|
||||||
/* Block 2H, INVQAH */
|
wd1 = (s->band[1].nb*127) >> 7;
|
||||||
wd2 = rh2[ihigh];
|
wd1 += wh[wd2];
|
||||||
wd1 = (s->band[1].nb*127) >> 7;
|
if (wd1 < 0)
|
||||||
wd1 += wh[wd2];
|
wd1 = 0;
|
||||||
if (wd1 < 0)
|
else if (wd1 > 22528)
|
||||||
wd1 = 0;
|
wd1 = 22528;
|
||||||
else if (wd1 > 22528)
|
s->band[1].nb = wd1;
|
||||||
wd1 = 22528;
|
|
||||||
s->band[1].nb = wd1;
|
/* Block 3H, SCALEH */
|
||||||
|
wd1 = (s->band[1].nb >> 6) & 31;
|
||||||
/* Block 3H, SCALEH */
|
wd2 = 10 - (s->band[1].nb >> 11);
|
||||||
wd1 = (s->band[1].nb >> 6) & 31;
|
wd3 = (wd2 < 0) ? (ilb[wd1] << -wd2) : (ilb[wd1] >> wd2);
|
||||||
wd2 = 10 - (s->band[1].nb >> 11);
|
s->band[1].det = wd3 << 2;
|
||||||
wd3 = (wd2 < 0) ? (ilb[wd1] << -wd2) : (ilb[wd1] >> wd2);
|
|
||||||
s->band[1].det = wd3 << 2;
|
block4(s, 1, dhigh);
|
||||||
|
}
|
||||||
block4(s, 1, dhigh);
|
|
||||||
}
|
if (s->itu_test_mode)
|
||||||
|
{
|
||||||
if (s->itu_test_mode)
|
amp[outlen++] = saturate(rlow << 1);
|
||||||
{
|
amp[outlen++] = (int16_t) (rhigh << 1);
|
||||||
amp[outlen++] = (int16_t) (rlow << 1);
|
}
|
||||||
amp[outlen++] = (int16_t) (rhigh << 1);
|
else
|
||||||
}
|
{
|
||||||
else
|
if (s->eight_k)
|
||||||
{
|
{
|
||||||
if (s->eight_k)
|
amp[outlen++] = saturate(rlow << 1);
|
||||||
{
|
}
|
||||||
amp[outlen++] = (int16_t) rlow;
|
else
|
||||||
}
|
{
|
||||||
else
|
/* Apply the receive QMF */
|
||||||
{
|
for (i = 0; i < 22; i++)
|
||||||
/* Apply the receive QMF */
|
s->x[i] = s->x[i + 2];
|
||||||
memcpy(s->x, &s->x[2], 22*sizeof(s->x[0]));
|
s->x[22] = rlow + rhigh;
|
||||||
s->x[22] = rlow + rhigh;
|
s->x[23] = rlow - rhigh;
|
||||||
s->x[23] = rlow - rhigh;
|
|
||||||
|
xout1 = 0;
|
||||||
xout1 = 0;
|
xout2 = 0;
|
||||||
xout2 = 0;
|
for (i = 0; i < 12; i++)
|
||||||
for (i = 0; i < 12; i++)
|
{
|
||||||
{
|
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++] = saturate(xout1 >> 11);
|
||||||
amp[outlen++] = (int16_t) (xout1 >> 12);
|
amp[outlen++] = saturate(xout2 >> 11);
|
||||||
amp[outlen++] = (int16_t) (xout2 >> 12);
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
return outlen;
|
||||||
return outlen;
|
}
|
||||||
}
|
/*- End of function --------------------------------------------------------*/
|
||||||
/*- End of function --------------------------------------------------------*/
|
/*- End of file ------------------------------------------------------------*/
|
||||||
/*- End of file ------------------------------------------------------------*/
|
|
||||||
|
|||||||
+400
-389
@@ -1,389 +1,400 @@
|
|||||||
/*
|
/*
|
||||||
* 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.
|
||||||
*
|
*
|
||||||
* Written by Steve Underwood <steveu@coppice.org>
|
* Written by Steve Underwood <steveu@coppice.org>
|
||||||
*
|
*
|
||||||
* Copyright (C) 2005 Steve Underwood
|
* Copyright (C) 2005 Steve Underwood
|
||||||
*
|
*
|
||||||
* 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,
|
* Based on a single channel 64kbps only G.722 codec which is:
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
*
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
***** Copyright (c) CMU 1993 *****
|
||||||
* GNU General Public License for more details.
|
* Computer Science, Speech Group
|
||||||
*
|
* Chengxiang Lu and Alex Hauptmann
|
||||||
* You should have received a copy of the GNU General Public License
|
*
|
||||||
* along with this program; if not, write to the Free Software
|
* $Id$
|
||||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
*/
|
||||||
*
|
|
||||||
* Based on a single channel 64kbps only G.722 codec which is:
|
/*! \file */
|
||||||
*
|
|
||||||
***** Copyright (c) CMU 1993 *****
|
#ifdef HAVE_CONFIG_H
|
||||||
* Computer Science, Speech Group
|
#include <config.h>
|
||||||
* Chengxiang Lu and Alex Hauptmann
|
#endif
|
||||||
*
|
|
||||||
* $Id: g722_encode.c,v 1.18 2008/02/09 15:32:56 steveu Exp $
|
#include <stdio.h>
|
||||||
*/
|
#include <inttypes.h>
|
||||||
|
#include <memory.h>
|
||||||
/*! \file */
|
#include <stdlib.h>
|
||||||
|
#if 0
|
||||||
#ifdef HAVE_CONFIG_H
|
#include <tgmath.h>
|
||||||
#include <config.h>
|
#endif
|
||||||
#endif
|
|
||||||
|
#include "g722.h"
|
||||||
#include "g722_inttypes.h"
|
|
||||||
#include <memory.h>
|
#if !defined(FALSE)
|
||||||
#include <stdlib.h>
|
#define FALSE 0
|
||||||
#if defined(HAVE_TGMATH_H)
|
#endif
|
||||||
#include <tgmath.h>
|
#if !defined(TRUE)
|
||||||
#endif
|
#define TRUE (!FALSE)
|
||||||
#include <math.h>
|
#endif
|
||||||
|
|
||||||
#include "g722_telephony.h"
|
static __inline__ int16_t saturate(int32_t amp)
|
||||||
#include "g722_dc_restore.h"
|
{
|
||||||
#include "g722.h"
|
int16_t amp16;
|
||||||
|
|
||||||
static void block4(g722_encode_state_t *s, int band, int d)
|
/* Hopefully this is optimised for the common case - not clipping */
|
||||||
{
|
amp16 = (int16_t) amp;
|
||||||
int wd1;
|
if (amp == amp16)
|
||||||
int wd2;
|
return amp16;
|
||||||
int wd3;
|
if (amp > INT16_MAX)
|
||||||
int i;
|
return INT16_MAX;
|
||||||
|
return INT16_MIN;
|
||||||
/* Block 4, RECONS */
|
}
|
||||||
s->band[band].d[0] = d;
|
/*- End of function --------------------------------------------------------*/
|
||||||
s->band[band].r[0] = saturate(s->band[band].s + d);
|
|
||||||
|
static void block4(g722_encode_state_t *s, int band, int d)
|
||||||
/* Block 4, PARREC */
|
{
|
||||||
s->band[band].p[0] = saturate(s->band[band].sz + d);
|
int wd1;
|
||||||
|
int wd2;
|
||||||
/* Block 4, UPPOL2 */
|
int wd3;
|
||||||
for (i = 0; i < 3; i++)
|
int i;
|
||||||
s->band[band].sg[i] = s->band[band].p[i] >> 15;
|
|
||||||
wd1 = saturate(s->band[band].a[1] << 2);
|
/* Block 4, RECONS */
|
||||||
|
s->band[band].d[0] = d;
|
||||||
wd2 = (s->band[band].sg[0] == s->band[band].sg[1]) ? -wd1 : wd1;
|
s->band[band].r[0] = saturate(s->band[band].s + d);
|
||||||
if (wd2 > 32767)
|
|
||||||
wd2 = 32767;
|
/* Block 4, PARREC */
|
||||||
wd3 = (wd2 >> 7) + ((s->band[band].sg[0] == s->band[band].sg[2]) ? 128 : -128);
|
s->band[band].p[0] = saturate(s->band[band].sz + d);
|
||||||
wd3 += (s->band[band].a[2]*32512) >> 15;
|
|
||||||
if (wd3 > 12288)
|
/* Block 4, UPPOL2 */
|
||||||
wd3 = 12288;
|
for (i = 0; i < 3; i++)
|
||||||
else if (wd3 < -12288)
|
s->band[band].sg[i] = s->band[band].p[i] >> 15;
|
||||||
wd3 = -12288;
|
wd1 = saturate(s->band[band].a[1] << 2);
|
||||||
s->band[band].ap[2] = wd3;
|
|
||||||
|
wd2 = (s->band[band].sg[0] == s->band[band].sg[1]) ? -wd1 : wd1;
|
||||||
/* Block 4, UPPOL1 */
|
if (wd2 > 32767)
|
||||||
s->band[band].sg[0] = s->band[band].p[0] >> 15;
|
wd2 = 32767;
|
||||||
s->band[band].sg[1] = s->band[band].p[1] >> 15;
|
wd3 = (wd2 >> 7) + ((s->band[band].sg[0] == s->band[band].sg[2]) ? 128 : -128);
|
||||||
wd1 = (s->band[band].sg[0] == s->band[band].sg[1]) ? 192 : -192;
|
wd3 += (s->band[band].a[2]*32512) >> 15;
|
||||||
wd2 = (s->band[band].a[1]*32640) >> 15;
|
if (wd3 > 12288)
|
||||||
|
wd3 = 12288;
|
||||||
s->band[band].ap[1] = saturate(wd1 + wd2);
|
else if (wd3 < -12288)
|
||||||
wd3 = saturate(15360 - s->band[band].ap[2]);
|
wd3 = -12288;
|
||||||
if (s->band[band].ap[1] > wd3)
|
s->band[band].ap[2] = wd3;
|
||||||
s->band[band].ap[1] = wd3;
|
|
||||||
else if (s->band[band].ap[1] < -wd3)
|
/* Block 4, UPPOL1 */
|
||||||
s->band[band].ap[1] = -wd3;
|
s->band[band].sg[0] = s->band[band].p[0] >> 15;
|
||||||
|
s->band[band].sg[1] = s->band[band].p[1] >> 15;
|
||||||
/* Block 4, UPZERO */
|
wd1 = (s->band[band].sg[0] == s->band[band].sg[1]) ? 192 : -192;
|
||||||
wd1 = (d == 0) ? 0 : 128;
|
wd2 = (s->band[band].a[1]*32640) >> 15;
|
||||||
s->band[band].sg[0] = d >> 15;
|
|
||||||
for (i = 1; i < 7; i++)
|
s->band[band].ap[1] = saturate(wd1 + wd2);
|
||||||
{
|
wd3 = saturate(15360 - s->band[band].ap[2]);
|
||||||
s->band[band].sg[i] = s->band[band].d[i] >> 15;
|
if (s->band[band].ap[1] > wd3)
|
||||||
wd2 = (s->band[band].sg[i] == s->band[band].sg[0]) ? wd1 : -wd1;
|
s->band[band].ap[1] = wd3;
|
||||||
wd3 = (s->band[band].b[i]*32640) >> 15;
|
else if (s->band[band].ap[1] < -wd3)
|
||||||
s->band[band].bp[i] = saturate(wd2 + wd3);
|
s->band[band].ap[1] = -wd3;
|
||||||
}
|
|
||||||
|
/* Block 4, UPZERO */
|
||||||
/* Block 4, DELAYA */
|
wd1 = (d == 0) ? 0 : 128;
|
||||||
for (i = 6; i > 0; i--)
|
s->band[band].sg[0] = d >> 15;
|
||||||
{
|
for (i = 1; i < 7; i++)
|
||||||
s->band[band].d[i] = s->band[band].d[i - 1];
|
{
|
||||||
s->band[band].b[i] = s->band[band].bp[i];
|
s->band[band].sg[i] = s->band[band].d[i] >> 15;
|
||||||
}
|
wd2 = (s->band[band].sg[i] == s->band[band].sg[0]) ? wd1 : -wd1;
|
||||||
|
wd3 = (s->band[band].b[i]*32640) >> 15;
|
||||||
for (i = 2; i > 0; i--)
|
s->band[band].bp[i] = saturate(wd2 + wd3);
|
||||||
{
|
}
|
||||||
s->band[band].r[i] = s->band[band].r[i - 1];
|
|
||||||
s->band[band].p[i] = s->band[band].p[i - 1];
|
/* Block 4, DELAYA */
|
||||||
s->band[band].a[i] = s->band[band].ap[i];
|
for (i = 6; i > 0; i--)
|
||||||
}
|
{
|
||||||
|
s->band[band].d[i] = s->band[band].d[i - 1];
|
||||||
/* Block 4, FILTEP */
|
s->band[band].b[i] = s->band[band].bp[i];
|
||||||
wd1 = saturate(s->band[band].r[1] + s->band[band].r[1]);
|
}
|
||||||
wd1 = (s->band[band].a[1]*wd1) >> 15;
|
|
||||||
wd2 = saturate(s->band[band].r[2] + s->band[band].r[2]);
|
for (i = 2; i > 0; i--)
|
||||||
wd2 = (s->band[band].a[2]*wd2) >> 15;
|
{
|
||||||
s->band[band].sp = saturate(wd1 + wd2);
|
s->band[band].r[i] = s->band[band].r[i - 1];
|
||||||
|
s->band[band].p[i] = s->band[band].p[i - 1];
|
||||||
/* Block 4, FILTEZ */
|
s->band[band].a[i] = s->band[band].ap[i];
|
||||||
s->band[band].sz = 0;
|
}
|
||||||
for (i = 6; i > 0; i--)
|
|
||||||
{
|
/* Block 4, FILTEP */
|
||||||
wd1 = saturate(s->band[band].d[i] + s->band[band].d[i]);
|
wd1 = saturate(s->band[band].r[1] + s->band[band].r[1]);
|
||||||
s->band[band].sz += (s->band[band].b[i]*wd1) >> 15;
|
wd1 = (s->band[band].a[1]*wd1) >> 15;
|
||||||
}
|
wd2 = saturate(s->band[band].r[2] + s->band[band].r[2]);
|
||||||
s->band[band].sz = saturate(s->band[band].sz);
|
wd2 = (s->band[band].a[2]*wd2) >> 15;
|
||||||
|
s->band[band].sp = saturate(wd1 + wd2);
|
||||||
/* Block 4, PREDIC */
|
|
||||||
s->band[band].s = saturate(s->band[band].sp + s->band[band].sz);
|
/* Block 4, FILTEZ */
|
||||||
}
|
s->band[band].sz = 0;
|
||||||
/*- End of function --------------------------------------------------------*/
|
for (i = 6; i > 0; i--)
|
||||||
|
{
|
||||||
g722_encode_state_t *g722_encode_init(g722_encode_state_t *s, int rate, int options)
|
wd1 = saturate(s->band[band].d[i] + s->band[band].d[i]);
|
||||||
{
|
s->band[band].sz += (s->band[band].b[i]*wd1) >> 15;
|
||||||
if (s == NULL)
|
}
|
||||||
{
|
s->band[band].sz = saturate(s->band[band].sz);
|
||||||
if ((s = (g722_encode_state_t *) malloc(sizeof(*s))) == NULL)
|
|
||||||
return NULL;
|
/* Block 4, PREDIC */
|
||||||
}
|
s->band[band].s = saturate(s->band[band].sp + s->band[band].sz);
|
||||||
memset(s, 0, sizeof(*s));
|
}
|
||||||
if (rate == 48000)
|
/*- End of function --------------------------------------------------------*/
|
||||||
s->bits_per_sample = 6;
|
|
||||||
else if (rate == 56000)
|
g722_encode_state_t *g722_encode_init(g722_encode_state_t *s, int rate, int options)
|
||||||
s->bits_per_sample = 7;
|
{
|
||||||
else
|
if (s == NULL)
|
||||||
s->bits_per_sample = 8;
|
{
|
||||||
if ((options & G722_SAMPLE_RATE_8000))
|
if ((s = (g722_encode_state_t *) malloc(sizeof(*s))) == NULL)
|
||||||
s->eight_k = TRUE;
|
return NULL;
|
||||||
if ((options & G722_PACKED) && s->bits_per_sample != 8)
|
}
|
||||||
s->packed = TRUE;
|
memset(s, 0, sizeof(*s));
|
||||||
else
|
if (rate == 48000)
|
||||||
s->packed = FALSE;
|
s->bits_per_sample = 6;
|
||||||
s->band[0].det = 32;
|
else if (rate == 56000)
|
||||||
s->band[1].det = 8;
|
s->bits_per_sample = 7;
|
||||||
return s;
|
else
|
||||||
}
|
s->bits_per_sample = 8;
|
||||||
/*- End of function --------------------------------------------------------*/
|
if ((options & G722_SAMPLE_RATE_8000))
|
||||||
|
s->eight_k = TRUE;
|
||||||
int g722_encode_release(g722_encode_state_t *s)
|
if ((options & G722_PACKED) && s->bits_per_sample != 8)
|
||||||
{
|
s->packed = TRUE;
|
||||||
free(s);
|
else
|
||||||
return 0;
|
s->packed = FALSE;
|
||||||
}
|
s->band[0].det = 32;
|
||||||
/*- End of function --------------------------------------------------------*/
|
s->band[1].det = 8;
|
||||||
|
return s;
|
||||||
int g722_encode(g722_encode_state_t *s, uint8_t g722_data[], const int16_t amp[], int len)
|
}
|
||||||
{
|
/*- End of function --------------------------------------------------------*/
|
||||||
static const int q6[32] =
|
|
||||||
{
|
int g722_encode_release(g722_encode_state_t *s)
|
||||||
0, 35, 72, 110, 150, 190, 233, 276,
|
{
|
||||||
323, 370, 422, 473, 530, 587, 650, 714,
|
free(s);
|
||||||
786, 858, 940, 1023, 1121, 1219, 1339, 1458,
|
return 0;
|
||||||
1612, 1765, 1980, 2195, 2557, 2919, 0, 0
|
}
|
||||||
};
|
/*- End of function --------------------------------------------------------*/
|
||||||
static const int iln[32] =
|
|
||||||
{
|
int g722_encode(g722_encode_state_t *s, uint8_t g722_data[], const int16_t amp[], int len)
|
||||||
0, 63, 62, 31, 30, 29, 28, 27,
|
{
|
||||||
26, 25, 24, 23, 22, 21, 20, 19,
|
static const int q6[32] =
|
||||||
18, 17, 16, 15, 14, 13, 12, 11,
|
{
|
||||||
10, 9, 8, 7, 6, 5, 4, 0
|
0, 35, 72, 110, 150, 190, 233, 276,
|
||||||
};
|
323, 370, 422, 473, 530, 587, 650, 714,
|
||||||
static const int ilp[32] =
|
786, 858, 940, 1023, 1121, 1219, 1339, 1458,
|
||||||
{
|
1612, 1765, 1980, 2195, 2557, 2919, 0, 0
|
||||||
0, 61, 60, 59, 58, 57, 56, 55,
|
};
|
||||||
54, 53, 52, 51, 50, 49, 48, 47,
|
static const int iln[32] =
|
||||||
46, 45, 44, 43, 42, 41, 40, 39,
|
{
|
||||||
38, 37, 36, 35, 34, 33, 32, 0
|
0, 63, 62, 31, 30, 29, 28, 27,
|
||||||
};
|
26, 25, 24, 23, 22, 21, 20, 19,
|
||||||
static const int wl[8] =
|
18, 17, 16, 15, 14, 13, 12, 11,
|
||||||
{
|
10, 9, 8, 7, 6, 5, 4, 0
|
||||||
-60, -30, 58, 172, 334, 538, 1198, 3042
|
};
|
||||||
};
|
static const int ilp[32] =
|
||||||
static const int rl42[16] =
|
{
|
||||||
{
|
0, 61, 60, 59, 58, 57, 56, 55,
|
||||||
0, 7, 6, 5, 4, 3, 2, 1, 7, 6, 5, 4, 3, 2, 1, 0
|
54, 53, 52, 51, 50, 49, 48, 47,
|
||||||
};
|
46, 45, 44, 43, 42, 41, 40, 39,
|
||||||
static const int ilb[32] =
|
38, 37, 36, 35, 34, 33, 32, 0
|
||||||
{
|
};
|
||||||
2048, 2093, 2139, 2186, 2233, 2282, 2332,
|
static const int wl[8] =
|
||||||
2383, 2435, 2489, 2543, 2599, 2656, 2714,
|
{
|
||||||
2774, 2834, 2896, 2960, 3025, 3091, 3158,
|
-60, -30, 58, 172, 334, 538, 1198, 3042
|
||||||
3228, 3298, 3371, 3444, 3520, 3597, 3676,
|
};
|
||||||
3756, 3838, 3922, 4008
|
static const int rl42[16] =
|
||||||
};
|
{
|
||||||
static const int qm4[16] =
|
0, 7, 6, 5, 4, 3, 2, 1, 7, 6, 5, 4, 3, 2, 1, 0
|
||||||
{
|
};
|
||||||
0, -20456, -12896, -8968,
|
static const int ilb[32] =
|
||||||
-6288, -4240, -2584, -1200,
|
{
|
||||||
20456, 12896, 8968, 6288,
|
2048, 2093, 2139, 2186, 2233, 2282, 2332,
|
||||||
4240, 2584, 1200, 0
|
2383, 2435, 2489, 2543, 2599, 2656, 2714,
|
||||||
};
|
2774, 2834, 2896, 2960, 3025, 3091, 3158,
|
||||||
static const int qm2[4] =
|
3228, 3298, 3371, 3444, 3520, 3597, 3676,
|
||||||
{
|
3756, 3838, 3922, 4008
|
||||||
-7408, -1616, 7408, 1616
|
};
|
||||||
};
|
static const int qm4[16] =
|
||||||
static const int qmf_coeffs[12] =
|
{
|
||||||
{
|
0, -20456, -12896, -8968,
|
||||||
3, -11, 12, 32, -210, 951, 3876, -805, 362, -156, 53, -11,
|
-6288, -4240, -2584, -1200,
|
||||||
};
|
20456, 12896, 8968, 6288,
|
||||||
static const int ihn[3] = {0, 1, 0};
|
4240, 2584, 1200, 0
|
||||||
static const int ihp[3] = {0, 3, 2};
|
};
|
||||||
static const int wh[3] = {0, -214, 798};
|
static const int qm2[4] =
|
||||||
static const int rh2[4] = {2, 1, 2, 1};
|
{
|
||||||
|
-7408, -1616, 7408, 1616
|
||||||
int dlow;
|
};
|
||||||
int dhigh;
|
static const int qmf_coeffs[12] =
|
||||||
int el;
|
{
|
||||||
int wd;
|
3, -11, 12, 32, -210, 951, 3876, -805, 362, -156, 53, -11,
|
||||||
int wd1;
|
};
|
||||||
int ril;
|
static const int ihn[3] = {0, 1, 0};
|
||||||
int wd2;
|
static const int ihp[3] = {0, 3, 2};
|
||||||
int il4;
|
static const int wh[3] = {0, -214, 798};
|
||||||
int ih2;
|
static const int rh2[4] = {2, 1, 2, 1};
|
||||||
int wd3;
|
|
||||||
int eh;
|
int dlow;
|
||||||
int mih;
|
int dhigh;
|
||||||
int i;
|
int el;
|
||||||
int j;
|
int wd;
|
||||||
/* Low and high band PCM from the QMF */
|
int wd1;
|
||||||
int xlow;
|
int ril;
|
||||||
int xhigh;
|
int wd2;
|
||||||
int g722_bytes;
|
int il4;
|
||||||
/* Even and odd tap accumulators */
|
int ih2;
|
||||||
int sumeven;
|
int wd3;
|
||||||
int sumodd;
|
int eh;
|
||||||
int ihigh;
|
int mih;
|
||||||
int ilow;
|
int i;
|
||||||
int code;
|
int j;
|
||||||
|
/* Low and high band PCM from the QMF */
|
||||||
g722_bytes = 0;
|
int xlow;
|
||||||
xhigh = 0;
|
int xhigh;
|
||||||
for (j = 0; j < len; )
|
int g722_bytes;
|
||||||
{
|
/* Even and odd tap accumulators */
|
||||||
if (s->itu_test_mode)
|
int sumeven;
|
||||||
{
|
int sumodd;
|
||||||
xlow =
|
int ihigh;
|
||||||
xhigh = amp[j++] >> 1;
|
int ilow;
|
||||||
}
|
int code;
|
||||||
else
|
|
||||||
{
|
g722_bytes = 0;
|
||||||
if (s->eight_k)
|
xhigh = 0;
|
||||||
{
|
for (j = 0; j < len; )
|
||||||
xlow = amp[j++];
|
{
|
||||||
}
|
if (s->itu_test_mode)
|
||||||
else
|
{
|
||||||
{
|
xlow =
|
||||||
/* Apply the transmit QMF */
|
xhigh = amp[j++] >> 1;
|
||||||
/* Shuffle the buffer down */
|
}
|
||||||
memcpy(s->x, &s->x[2], 22*sizeof(s->x[0]));
|
else
|
||||||
s->x[22] = amp[j++];
|
{
|
||||||
s->x[23] = amp[j++];
|
if (s->eight_k)
|
||||||
|
{
|
||||||
/* Discard every other QMF output */
|
xlow = amp[j++] >> 1;
|
||||||
sumeven = 0;
|
}
|
||||||
sumodd = 0;
|
else
|
||||||
for (i = 0; i < 12; i++)
|
{
|
||||||
{
|
/* Apply the transmit QMF */
|
||||||
sumodd += s->x[2*i]*qmf_coeffs[i];
|
/* Shuffle the buffer down */
|
||||||
sumeven += s->x[2*i + 1]*qmf_coeffs[11 - i];
|
for (i = 0; i < 22; i++)
|
||||||
}
|
s->x[i] = s->x[i + 2];
|
||||||
xlow = (sumeven + sumodd) >> 13;
|
s->x[22] = amp[j++];
|
||||||
xhigh = (sumeven - sumodd) >> 13;
|
s->x[23] = amp[j++];
|
||||||
}
|
|
||||||
}
|
/* Discard every other QMF output */
|
||||||
/* Block 1L, SUBTRA */
|
sumeven = 0;
|
||||||
el = saturate(xlow - s->band[0].s);
|
sumodd = 0;
|
||||||
|
for (i = 0; i < 12; i++)
|
||||||
/* Block 1L, QUANTL */
|
{
|
||||||
wd = (el >= 0) ? el : -(el + 1);
|
sumodd += s->x[2*i]*qmf_coeffs[i];
|
||||||
|
sumeven += s->x[2*i + 1]*qmf_coeffs[11 - i];
|
||||||
for (i = 1; i < 30; i++)
|
}
|
||||||
{
|
xlow = (sumeven + sumodd) >> 14;
|
||||||
wd1 = (q6[i]*s->band[0].det) >> 12;
|
xhigh = (sumeven - sumodd) >> 14;
|
||||||
if (wd < wd1)
|
}
|
||||||
break;
|
}
|
||||||
}
|
/* Block 1L, SUBTRA */
|
||||||
ilow = (el < 0) ? iln[i] : ilp[i];
|
el = saturate(xlow - s->band[0].s);
|
||||||
|
|
||||||
/* Block 2L, INVQAL */
|
/* Block 1L, QUANTL */
|
||||||
ril = ilow >> 2;
|
wd = (el >= 0) ? el : -(el + 1);
|
||||||
wd2 = qm4[ril];
|
|
||||||
dlow = (s->band[0].det*wd2) >> 15;
|
for (i = 1; i < 30; i++)
|
||||||
|
{
|
||||||
/* Block 3L, LOGSCL */
|
wd1 = (q6[i]*s->band[0].det) >> 12;
|
||||||
il4 = rl42[ril];
|
if (wd < wd1)
|
||||||
wd = (s->band[0].nb*127) >> 7;
|
break;
|
||||||
s->band[0].nb = wd + wl[il4];
|
}
|
||||||
if (s->band[0].nb < 0)
|
ilow = (el < 0) ? iln[i] : ilp[i];
|
||||||
s->band[0].nb = 0;
|
|
||||||
else if (s->band[0].nb > 18432)
|
/* Block 2L, INVQAL */
|
||||||
s->band[0].nb = 18432;
|
ril = ilow >> 2;
|
||||||
|
wd2 = qm4[ril];
|
||||||
/* Block 3L, SCALEL */
|
dlow = (s->band[0].det*wd2) >> 15;
|
||||||
wd1 = (s->band[0].nb >> 6) & 31;
|
|
||||||
wd2 = 8 - (s->band[0].nb >> 11);
|
/* Block 3L, LOGSCL */
|
||||||
wd3 = (wd2 < 0) ? (ilb[wd1] << -wd2) : (ilb[wd1] >> wd2);
|
il4 = rl42[ril];
|
||||||
s->band[0].det = wd3 << 2;
|
wd = (s->band[0].nb*127) >> 7;
|
||||||
|
s->band[0].nb = wd + wl[il4];
|
||||||
block4(s, 0, dlow);
|
if (s->band[0].nb < 0)
|
||||||
|
s->band[0].nb = 0;
|
||||||
if (s->eight_k)
|
else if (s->band[0].nb > 18432)
|
||||||
{
|
s->band[0].nb = 18432;
|
||||||
/* Just leave the high bits as zero */
|
|
||||||
code = (0xC0 | ilow) >> (8 - s->bits_per_sample);
|
/* Block 3L, SCALEL */
|
||||||
}
|
wd1 = (s->band[0].nb >> 6) & 31;
|
||||||
else
|
wd2 = 8 - (s->band[0].nb >> 11);
|
||||||
{
|
wd3 = (wd2 < 0) ? (ilb[wd1] << -wd2) : (ilb[wd1] >> wd2);
|
||||||
/* Block 1H, SUBTRA */
|
s->band[0].det = wd3 << 2;
|
||||||
eh = saturate(xhigh - s->band[1].s);
|
|
||||||
|
block4(s, 0, dlow);
|
||||||
/* Block 1H, QUANTH */
|
|
||||||
wd = (eh >= 0) ? eh : -(eh + 1);
|
if (s->eight_k)
|
||||||
wd1 = (564*s->band[1].det) >> 12;
|
{
|
||||||
mih = (wd >= wd1) ? 2 : 1;
|
/* Just leave the high bits as zero */
|
||||||
ihigh = (eh < 0) ? ihn[mih] : ihp[mih];
|
code = (0xC0 | ilow) >> (8 - s->bits_per_sample);
|
||||||
|
}
|
||||||
/* Block 2H, INVQAH */
|
else
|
||||||
wd2 = qm2[ihigh];
|
{
|
||||||
dhigh = (s->band[1].det*wd2) >> 15;
|
/* Block 1H, SUBTRA */
|
||||||
|
eh = saturate(xhigh - s->band[1].s);
|
||||||
/* Block 3H, LOGSCH */
|
|
||||||
ih2 = rh2[ihigh];
|
/* Block 1H, QUANTH */
|
||||||
wd = (s->band[1].nb*127) >> 7;
|
wd = (eh >= 0) ? eh : -(eh + 1);
|
||||||
s->band[1].nb = wd + wh[ih2];
|
wd1 = (564*s->band[1].det) >> 12;
|
||||||
if (s->band[1].nb < 0)
|
mih = (wd >= wd1) ? 2 : 1;
|
||||||
s->band[1].nb = 0;
|
ihigh = (eh < 0) ? ihn[mih] : ihp[mih];
|
||||||
else if (s->band[1].nb > 22528)
|
|
||||||
s->band[1].nb = 22528;
|
/* Block 2H, INVQAH */
|
||||||
|
wd2 = qm2[ihigh];
|
||||||
/* Block 3H, SCALEH */
|
dhigh = (s->band[1].det*wd2) >> 15;
|
||||||
wd1 = (s->band[1].nb >> 6) & 31;
|
|
||||||
wd2 = 10 - (s->band[1].nb >> 11);
|
/* Block 3H, LOGSCH */
|
||||||
wd3 = (wd2 < 0) ? (ilb[wd1] << -wd2) : (ilb[wd1] >> wd2);
|
ih2 = rh2[ihigh];
|
||||||
s->band[1].det = wd3 << 2;
|
wd = (s->band[1].nb*127) >> 7;
|
||||||
|
s->band[1].nb = wd + wh[ih2];
|
||||||
block4(s, 1, dhigh);
|
if (s->band[1].nb < 0)
|
||||||
code = ((ihigh << 6) | ilow) >> (8 - s->bits_per_sample);
|
s->band[1].nb = 0;
|
||||||
}
|
else if (s->band[1].nb > 22528)
|
||||||
|
s->band[1].nb = 22528;
|
||||||
if (s->packed)
|
|
||||||
{
|
/* Block 3H, SCALEH */
|
||||||
/* Pack the code bits */
|
wd1 = (s->band[1].nb >> 6) & 31;
|
||||||
s->out_buffer |= (code << s->out_bits);
|
wd2 = 10 - (s->band[1].nb >> 11);
|
||||||
s->out_bits += s->bits_per_sample;
|
wd3 = (wd2 < 0) ? (ilb[wd1] << -wd2) : (ilb[wd1] >> wd2);
|
||||||
if (s->out_bits >= 8)
|
s->band[1].det = wd3 << 2;
|
||||||
{
|
|
||||||
g722_data[g722_bytes++] = (uint8_t) (s->out_buffer & 0xFF);
|
block4(s, 1, dhigh);
|
||||||
s->out_bits -= 8;
|
code = ((ihigh << 6) | ilow) >> (8 - s->bits_per_sample);
|
||||||
s->out_buffer >>= 8;
|
}
|
||||||
}
|
|
||||||
}
|
if (s->packed)
|
||||||
else
|
{
|
||||||
{
|
/* Pack the code bits */
|
||||||
g722_data[g722_bytes++] = (uint8_t) code;
|
s->out_buffer |= (code << s->out_bits);
|
||||||
}
|
s->out_bits += s->bits_per_sample;
|
||||||
}
|
if (s->out_bits >= 8)
|
||||||
return g722_bytes;
|
{
|
||||||
}
|
g722_data[g722_bytes++] = (uint8_t) (s->out_buffer & 0xFF);
|
||||||
/*- End of function --------------------------------------------------------*/
|
s->out_bits -= 8;
|
||||||
/*- End of file ------------------------------------------------------------*/
|
s->out_buffer >>= 8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
g722_data[g722_bytes++] = (uint8_t) code;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return g722_bytes;
|
||||||
|
}
|
||||||
|
/*- End of function --------------------------------------------------------*/
|
||||||
|
/*- End of 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_
|
|
||||||
|
|
||||||
@@ -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 ------------------------------------------------------------*/
|
|
||||||
@@ -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)
|
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////
|
|
||||||
Reference in New Issue
Block a user