
TBR=niklas.enbom@webrtc.org Review URL: https://webrtc-codereview.appspot.com/915006 git-svn-id: http://webrtc.googlecode.com/svn/trunk@2963 4adac7df-926f-26a2-2b94-8c16560cd09d
354 lines
10 KiB
C++
354 lines
10 KiB
C++
/*
|
|
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
|
|
*
|
|
* Use of this source code is governed by a BSD-style license
|
|
* that can be found in the LICENSE file in the root of the source
|
|
* tree. An additional intellectual property rights grant can be found
|
|
* in the file PATENTS. All contributing project authors may
|
|
* be found in the AUTHORS file in the root of the source tree.
|
|
*/
|
|
|
|
#include "acm_g722.h"
|
|
#include "acm_codec_database.h"
|
|
#include "acm_common_defs.h"
|
|
#include "acm_neteq.h"
|
|
#include "trace.h"
|
|
#include "webrtc_neteq.h"
|
|
#include "webrtc_neteq_help_macros.h"
|
|
#include "g722_interface.h"
|
|
|
|
namespace webrtc {
|
|
|
|
#ifndef WEBRTC_CODEC_G722
|
|
|
|
ACMG722::ACMG722(WebRtc_Word16 /* codecID */)
|
|
: _ptrEncStr(NULL),
|
|
_ptrDecStr(NULL),
|
|
_encoderInstPtr(NULL),
|
|
_encoderInstPtrRight(NULL),
|
|
_decoderInstPtr(NULL) {
|
|
return;
|
|
}
|
|
|
|
ACMG722::~ACMG722() {
|
|
return;
|
|
}
|
|
|
|
WebRtc_Word32 ACMG722::Add10MsDataSafe(const WebRtc_UWord32 /* timestamp */,
|
|
const WebRtc_Word16* /* data */,
|
|
const WebRtc_UWord16 /* lengthSmpl */,
|
|
const WebRtc_UWord8 /* audioChannel */) {
|
|
return -1;
|
|
}
|
|
|
|
WebRtc_Word16 ACMG722::InternalEncode(WebRtc_UWord8* /* bitStream */,
|
|
WebRtc_Word16* /* bitStreamLenByte */) {
|
|
return -1;
|
|
}
|
|
|
|
WebRtc_Word16 ACMG722::DecodeSafe(WebRtc_UWord8* /* bitStream */,
|
|
WebRtc_Word16 /* bitStreamLenByte */,
|
|
WebRtc_Word16* /* audio */,
|
|
WebRtc_Word16* /* audioSamples */,
|
|
WebRtc_Word8* /* speechType */) {
|
|
return -1;
|
|
}
|
|
|
|
WebRtc_Word16 ACMG722::InternalInitEncoder(
|
|
WebRtcACMCodecParams* /* codecParams */) {
|
|
return -1;
|
|
}
|
|
|
|
WebRtc_Word16 ACMG722::InternalInitDecoder(
|
|
WebRtcACMCodecParams* /* codecParams */) {
|
|
return -1;
|
|
}
|
|
|
|
WebRtc_Word32 ACMG722::CodecDef(WebRtcNetEQ_CodecDef& /* codecDef */,
|
|
const CodecInst& /* codecInst */) {
|
|
return -1;
|
|
}
|
|
|
|
ACMGenericCodec* ACMG722::CreateInstance(void) {
|
|
return NULL;
|
|
}
|
|
|
|
WebRtc_Word16 ACMG722::InternalCreateEncoder() {
|
|
return -1;
|
|
}
|
|
|
|
void ACMG722::DestructEncoderSafe() {
|
|
return;
|
|
}
|
|
|
|
WebRtc_Word16 ACMG722::InternalCreateDecoder() {
|
|
return -1;
|
|
}
|
|
|
|
void ACMG722::DestructDecoderSafe() {
|
|
return;
|
|
}
|
|
|
|
void ACMG722::InternalDestructEncoderInst(void* /* ptrInst */) {
|
|
return;
|
|
}
|
|
|
|
void ACMG722::SplitStereoPacket(uint8_t* /*payload*/,
|
|
int32_t* /*payload_length*/) {}
|
|
|
|
#else //===================== Actual Implementation =======================
|
|
|
|
// Encoder and decoder memory
|
|
struct ACMG722EncStr {
|
|
G722EncInst* inst; // instance for left channel in case of stereo
|
|
G722EncInst* instRight; // instance for right channel in case of stereo
|
|
};
|
|
struct ACMG722DecStr {
|
|
G722DecInst* inst; // instance for left channel in case of stereo
|
|
G722DecInst* instRight; // instance for right channel in case of stereo
|
|
};
|
|
|
|
ACMG722::ACMG722(WebRtc_Word16 codecID)
|
|
: _encoderInstPtr(NULL),
|
|
_encoderInstPtrRight(NULL),
|
|
_decoderInstPtr(NULL) {
|
|
// Encoder
|
|
_ptrEncStr = new ACMG722EncStr;
|
|
if (_ptrEncStr != NULL) {
|
|
_ptrEncStr->inst = NULL;
|
|
_ptrEncStr->instRight = NULL;
|
|
}
|
|
// Decoder
|
|
_ptrDecStr = new ACMG722DecStr;
|
|
if (_ptrDecStr != NULL) {
|
|
_ptrDecStr->inst = NULL;
|
|
_ptrDecStr->instRight = NULL; // Not used
|
|
}
|
|
_codecID = codecID;
|
|
return;
|
|
}
|
|
|
|
ACMG722::~ACMG722() {
|
|
// Encoder
|
|
if (_ptrEncStr != NULL) {
|
|
if (_ptrEncStr->inst != NULL) {
|
|
WebRtcG722_FreeEncoder(_ptrEncStr->inst);
|
|
_ptrEncStr->inst = NULL;
|
|
}
|
|
if (_ptrEncStr->instRight != NULL) {
|
|
WebRtcG722_FreeEncoder(_ptrEncStr->instRight);
|
|
_ptrEncStr->instRight = NULL;
|
|
}
|
|
delete _ptrEncStr;
|
|
_ptrEncStr = NULL;
|
|
}
|
|
// Decoder
|
|
if (_ptrDecStr != NULL) {
|
|
if (_ptrDecStr->inst != NULL) {
|
|
WebRtcG722_FreeDecoder(_ptrDecStr->inst);
|
|
_ptrDecStr->inst = NULL;
|
|
}
|
|
if (_ptrDecStr->instRight != NULL) {
|
|
WebRtcG722_FreeDecoder(_ptrDecStr->instRight);
|
|
_ptrDecStr->instRight = NULL;
|
|
}
|
|
delete _ptrDecStr;
|
|
_ptrDecStr = NULL;
|
|
}
|
|
return;
|
|
}
|
|
|
|
WebRtc_Word32 ACMG722::Add10MsDataSafe(const WebRtc_UWord32 timestamp,
|
|
const WebRtc_Word16* data,
|
|
const WebRtc_UWord16 lengthSmpl,
|
|
const WebRtc_UWord8 audioChannel) {
|
|
return ACMGenericCodec::Add10MsDataSafe((timestamp >> 1), data, lengthSmpl,
|
|
audioChannel);
|
|
}
|
|
|
|
WebRtc_Word16 ACMG722::InternalEncode(WebRtc_UWord8* bitStream,
|
|
WebRtc_Word16* bitStreamLenByte) {
|
|
// If stereo, split input signal in left and right channel before encoding
|
|
if (_noChannels == 2) {
|
|
WebRtc_Word16 leftChannel[960];
|
|
WebRtc_Word16 rightChannel[960];
|
|
WebRtc_UWord8 outLeft[480];
|
|
WebRtc_UWord8 outRight[480];
|
|
WebRtc_Word16 lenInBytes;
|
|
for (int i = 0, j = 0; i < _frameLenSmpl * 2; i += 2, j++) {
|
|
leftChannel[j] = _inAudio[_inAudioIxRead + i];
|
|
rightChannel[j] = _inAudio[_inAudioIxRead + i + 1];
|
|
}
|
|
lenInBytes = WebRtcG722_Encode(_encoderInstPtr, leftChannel, _frameLenSmpl,
|
|
(WebRtc_Word16*) outLeft);
|
|
lenInBytes += WebRtcG722_Encode(_encoderInstPtrRight, rightChannel,
|
|
_frameLenSmpl, (WebRtc_Word16*) outRight);
|
|
*bitStreamLenByte = lenInBytes;
|
|
|
|
// Interleave the 4 bits per sample from left and right channel
|
|
for (int i = 0, j = 0; i < lenInBytes; i += 2, j++) {
|
|
bitStream[i] = (outLeft[j] & 0xF0) + (outRight[j] >> 4);
|
|
bitStream[i + 1] = ((outLeft[j] & 0x0F) << 4) + (outRight[j] & 0x0F);
|
|
}
|
|
} else {
|
|
*bitStreamLenByte = WebRtcG722_Encode(_encoderInstPtr,
|
|
&_inAudio[_inAudioIxRead],
|
|
_frameLenSmpl,
|
|
(WebRtc_Word16*) bitStream);
|
|
}
|
|
|
|
// increment the read index this tell the caller how far
|
|
// we have gone forward in reading the audio buffer
|
|
_inAudioIxRead += _frameLenSmpl * _noChannels;
|
|
return *bitStreamLenByte;
|
|
}
|
|
|
|
WebRtc_Word16 ACMG722::DecodeSafe(WebRtc_UWord8* /* bitStream */,
|
|
WebRtc_Word16 /* bitStreamLenByte */,
|
|
WebRtc_Word16* /* audio */,
|
|
WebRtc_Word16* /* audioSamples */,
|
|
WebRtc_Word8* /* speechType */) {
|
|
return 0;
|
|
}
|
|
|
|
WebRtc_Word16 ACMG722::InternalInitEncoder(WebRtcACMCodecParams* codecParams) {
|
|
if (codecParams->codecInstant.channels == 2) {
|
|
// Create codec struct for right channel
|
|
if (_ptrEncStr->instRight == NULL) {
|
|
WebRtcG722_CreateEncoder(&_ptrEncStr->instRight);
|
|
if (_ptrEncStr->instRight == NULL) {
|
|
return -1;
|
|
}
|
|
}
|
|
_encoderInstPtrRight = _ptrEncStr->instRight;
|
|
if (WebRtcG722_EncoderInit(_encoderInstPtrRight) < 0) {
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
return WebRtcG722_EncoderInit(_encoderInstPtr);
|
|
}
|
|
|
|
WebRtc_Word16 ACMG722::InternalInitDecoder(
|
|
WebRtcACMCodecParams* /* codecParams */) {
|
|
return WebRtcG722_DecoderInit(_decoderInstPtr);
|
|
}
|
|
|
|
WebRtc_Word32 ACMG722::CodecDef(WebRtcNetEQ_CodecDef& codecDef,
|
|
const CodecInst& codecInst) {
|
|
if (!_decoderInitialized) {
|
|
// TODO: log error
|
|
return -1;
|
|
}
|
|
// Fill up the structure by calling
|
|
// "SET_CODEC_PAR" & "SET_G722_FUNCTION."
|
|
// Then call NetEQ to add the codec to it's
|
|
// database.
|
|
if (codecInst.channels == 1) {
|
|
SET_CODEC_PAR(codecDef, kDecoderG722, codecInst.pltype, _decoderInstPtr,
|
|
16000);
|
|
} else {
|
|
SET_CODEC_PAR(codecDef, kDecoderG722_2ch, codecInst.pltype,
|
|
_decoderInstPtr, 16000);
|
|
}
|
|
SET_G722_FUNCTIONS(codecDef);
|
|
return 0;
|
|
}
|
|
|
|
ACMGenericCodec* ACMG722::CreateInstance(void) {
|
|
return NULL;
|
|
}
|
|
|
|
WebRtc_Word16 ACMG722::InternalCreateEncoder() {
|
|
if (_ptrEncStr == NULL) {
|
|
// this structure must be created at the costructor
|
|
// if it is still NULL then there is a probelm and
|
|
// we dont continue
|
|
return -1;
|
|
}
|
|
WebRtcG722_CreateEncoder(&_ptrEncStr->inst);
|
|
if (_ptrEncStr->inst == NULL) {
|
|
return -1;
|
|
}
|
|
_encoderInstPtr = _ptrEncStr->inst;
|
|
return 0;
|
|
}
|
|
|
|
void ACMG722::DestructEncoderSafe() {
|
|
if (_ptrEncStr != NULL) {
|
|
if (_ptrEncStr->inst != NULL) {
|
|
WebRtcG722_FreeEncoder(_ptrEncStr->inst);
|
|
_ptrEncStr->inst = NULL;
|
|
}
|
|
}
|
|
_encoderExist = false;
|
|
_encoderInitialized = false;
|
|
}
|
|
|
|
WebRtc_Word16 ACMG722::InternalCreateDecoder() {
|
|
if (_ptrDecStr == NULL) {
|
|
// this structure must be created at the costructor
|
|
// if it is still NULL then there is a probelm and
|
|
// we dont continue
|
|
return -1;
|
|
}
|
|
|
|
WebRtcG722_CreateDecoder(&_ptrDecStr->inst);
|
|
if (_ptrDecStr->inst == NULL) {
|
|
return -1;
|
|
}
|
|
_decoderInstPtr = _ptrDecStr->inst;
|
|
return 0;
|
|
}
|
|
|
|
void ACMG722::DestructDecoderSafe() {
|
|
_decoderExist = false;
|
|
_decoderInitialized = false;
|
|
if (_ptrDecStr != NULL) {
|
|
if (_ptrDecStr->inst != NULL) {
|
|
WebRtcG722_FreeDecoder(_ptrDecStr->inst);
|
|
_ptrDecStr->inst = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
void ACMG722::InternalDestructEncoderInst(void* ptrInst) {
|
|
if (ptrInst != NULL) {
|
|
WebRtcG722_FreeEncoder(static_cast<G722EncInst*>(ptrInst));
|
|
}
|
|
return;
|
|
}
|
|
|
|
// Split the stereo packet and place left and right channel after each other
|
|
// in the payload vector.
|
|
void ACMG722::SplitStereoPacket(uint8_t* payload, int32_t* payload_length) {
|
|
uint8_t right_byte;
|
|
|
|
// Check for valid inputs.
|
|
assert(payload != NULL);
|
|
assert(*payload_length > 0);
|
|
|
|
// Regroup the 4 bits/sample so to |l1 l2| |r1 r2| |l3 l4| |r3 r4| ...,
|
|
// where "lx" is 4 bits representing left sample number x, and "rx" right
|
|
// sample. Two samples fits in one byte, represented with |...|.
|
|
for (int i = 0; i < *payload_length; i += 2) {
|
|
right_byte = ((payload[i] & 0x0F) << 4) + (payload[i + 1] & 0x0F);
|
|
payload[i] = (payload[i] & 0xF0) + (payload[i + 1] >> 4);
|
|
payload[i + 1] = right_byte;
|
|
}
|
|
|
|
// Move one byte representing right channel each loop, and place it at the
|
|
// end of the bytestream vector. After looping the data is reordered to:
|
|
// |l1 l2| |l3 l4| ... |l(N-1) lN| |r1 r2| |r3 r4| ... |r(N-1) r(N)|,
|
|
// where N is the total number of samples.
|
|
for (int i = 0; i < *payload_length / 2; i++) {
|
|
right_byte = payload[i + 1];
|
|
memmove(&payload[i + 1], &payload[i + 2], *payload_length - i - 2);
|
|
payload[*payload_length - 1] = right_byte;
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
} // namespace webrtc
|