Move src/ -> webrtc/
TBR=niklas.enbom@webrtc.org
Review URL: https://webrtc-codereview.appspot.com/915006
git-svn-id: http://webrtc.googlecode.com/svn/trunk/webrtc@2963 4adac7df-926f-26a2-2b94-8c16560cd09d
diff --git a/modules/audio_coding/main/source/acm_generic_codec.cc b/modules/audio_coding/main/source/acm_generic_codec.cc
new file mode 100644
index 0000000..f98f260
--- /dev/null
+++ b/modules/audio_coding/main/source/acm_generic_codec.cc
@@ -0,0 +1,1546 @@
+/*
+ * 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 <assert.h>
+#include <string.h>
+
+#include "acm_codec_database.h"
+#include "acm_common_defs.h"
+#include "acm_generic_codec.h"
+#include "acm_neteq.h"
+#include "trace.h"
+#include "webrtc_vad.h"
+#include "webrtc_cng.h"
+
+namespace webrtc
+{
+
+// Enum for CNG
+enum
+{
+ kMaxPLCParamsCNG = WEBRTC_CNG_MAX_LPC_ORDER,
+ kNewCNGNumPLCParams = 8
+};
+
+#define ACM_SID_INTERVAL_MSEC 100
+
+// We set some of the variables to invalid values as a check point
+// if a proper initialization has happened. Another approach is
+// to initialize to a default codec that we are sure is always included.
+ACMGenericCodec::ACMGenericCodec()
+ : _inAudioIxWrite(0),
+ _inAudioIxRead(0),
+ _inTimestampIxWrite(0),
+ _inAudio(NULL),
+ _inTimestamp(NULL),
+ _frameLenSmpl(-1), // invalid value
+ _noChannels(1),
+ _codecID(-1), // invalid value
+ _noMissedSamples(0),
+ _encoderExist(false),
+ _decoderExist(false),
+ _encoderInitialized(false),
+ _decoderInitialized(false),
+ _registeredInNetEq(false),
+ _hasInternalDTX(false),
+ _ptrVADInst(NULL),
+ _vadEnabled(false),
+ _vadMode(VADNormal),
+ _dtxEnabled(false),
+ _ptrDTXInst(NULL),
+ _numLPCParams(kNewCNGNumPLCParams),
+ _sentCNPrevious(false),
+ _isMaster(true),
+ _prev_frame_cng(0),
+ _netEqDecodeLock(NULL),
+ _codecWrapperLock(*RWLockWrapper::CreateRWLock()),
+ _lastEncodedTimestamp(0),
+ _lastTimestamp(0xD87F3F9F),
+ _isAudioBuffFresh(true),
+ _uniqueID(0) {
+ // Initialize VAD vector.
+ for (int i = 0; i < MAX_FRAME_SIZE_10MSEC; i++) {
+ _vadLabel[i] = 0;
+ }
+
+ // Nullify memory for encoder and decoder, and set payload type to an
+ // invalid value.
+ memset(&_encoderParams, 0, sizeof(WebRtcACMCodecParams));
+ _encoderParams.codecInstant.pltype = -1;
+ memset(&_decoderParams, 0, sizeof(WebRtcACMCodecParams));
+ _decoderParams.codecInstant.pltype = -1;
+}
+
+ACMGenericCodec::~ACMGenericCodec()
+{
+ // Check all the members which are pointers and
+ // if they are not NULL delete/free them.
+
+ if(_ptrVADInst != NULL)
+ {
+ WebRtcVad_Free(_ptrVADInst);
+ _ptrVADInst = NULL;
+ }
+
+ if (_inAudio != NULL)
+ {
+ delete [] _inAudio;
+ _inAudio = NULL;
+ }
+
+ if (_inTimestamp != NULL)
+ {
+ delete [] _inTimestamp;
+ _inTimestamp = NULL;
+ }
+ if(_ptrDTXInst != NULL)
+ {
+ WebRtcCng_FreeEnc(_ptrDTXInst);
+ _ptrDTXInst = NULL;
+ }
+ delete &_codecWrapperLock;
+}
+
+WebRtc_Word32
+ACMGenericCodec::Add10MsData(
+ const WebRtc_UWord32 timestamp,
+ const WebRtc_Word16* data,
+ const WebRtc_UWord16 lengthSmpl,
+ const WebRtc_UWord8 audioChannel)
+{
+ WriteLockScoped wl(_codecWrapperLock);
+ return Add10MsDataSafe(timestamp, data, lengthSmpl, audioChannel);
+}
+
+WebRtc_Word32
+ACMGenericCodec::Add10MsDataSafe(
+ const WebRtc_UWord32 timestamp,
+ const WebRtc_Word16* data,
+ const WebRtc_UWord16 lengthSmpl,
+ const WebRtc_UWord8 audioChannel)
+{
+ // The codec expects to get data in correct sampling rate.
+ // get the sampling frequency of the codec
+ WebRtc_UWord16 plFreqHz;
+
+ if(EncoderSampFreq(plFreqHz) < 0)
+ {
+ // _codecID is not correct, perhaps the codec is not initialized yet.
+ return -1;
+ }
+
+ // Sanity check, if the length of the input corresponds to 10 ms.
+ if((plFreqHz / 100) != lengthSmpl)
+ {
+ // This is not 10 ms of audio, given the sampling frequency of the
+ // codec
+ return -1;
+ }
+ if(_lastTimestamp == timestamp)
+ {
+ // Same timestamp as the last time, overwrite.
+ if((_inAudioIxWrite >= lengthSmpl * audioChannel) &&
+ (_inTimestampIxWrite > 0))
+ {
+ _inAudioIxWrite -= lengthSmpl * audioChannel;
+ _inTimestampIxWrite--;
+ WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceAudioCoding, _uniqueID,
+ "Adding 10ms with previous timestamp, \
+overwriting the previous 10ms");
+ }
+ else
+ {
+ WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceAudioCoding, _uniqueID,
+ "Adding 10ms with previous timestamp, this will sound bad");
+ }
+ }
+
+ _lastTimestamp = timestamp;
+
+ if ((_inAudioIxWrite + lengthSmpl*audioChannel) > AUDIO_BUFFER_SIZE_W16)
+ {
+ // Get the number of samples to be overwritten
+ WebRtc_Word16 missedSamples = _inAudioIxWrite + lengthSmpl*audioChannel -
+ AUDIO_BUFFER_SIZE_W16;
+
+ // Move the data (overwite the old data)
+ memmove(_inAudio, _inAudio + missedSamples,
+ (AUDIO_BUFFER_SIZE_W16 - lengthSmpl*audioChannel)*sizeof(WebRtc_Word16));
+ // Copy the new data
+ memcpy(_inAudio + (AUDIO_BUFFER_SIZE_W16 - lengthSmpl*audioChannel), data,
+ lengthSmpl*audioChannel * sizeof(WebRtc_Word16));
+
+ // Get the number of 10 ms blocks which are overwritten
+ WebRtc_Word16 missed10MsecBlocks =
+ (WebRtc_Word16)((missedSamples/audioChannel * 100) / plFreqHz);
+
+ // Move the timestamps
+ memmove(_inTimestamp, _inTimestamp + missed10MsecBlocks,
+ (_inTimestampIxWrite - missed10MsecBlocks) * sizeof(WebRtc_UWord32));
+ _inTimestampIxWrite -= missed10MsecBlocks;
+ _inTimestamp[_inTimestampIxWrite] = timestamp;
+ _inTimestampIxWrite++;
+
+ // Buffer is full
+ _inAudioIxWrite = AUDIO_BUFFER_SIZE_W16;
+ IncreaseNoMissedSamples(missedSamples);
+ _isAudioBuffFresh = false;
+ return -missedSamples;
+ }
+ memcpy(_inAudio + _inAudioIxWrite, data, lengthSmpl*audioChannel * sizeof(WebRtc_Word16));
+ _inAudioIxWrite += lengthSmpl*audioChannel;
+
+ assert(_inTimestampIxWrite < TIMESTAMP_BUFFER_SIZE_W32);
+ assert(_inTimestampIxWrite >= 0);
+
+ _inTimestamp[_inTimestampIxWrite] = timestamp;
+ _inTimestampIxWrite++;
+ _isAudioBuffFresh = false;
+ return 0;
+}
+
+WebRtc_Word16
+ACMGenericCodec::Encode(
+ WebRtc_UWord8* bitStream,
+ WebRtc_Word16* bitStreamLenByte,
+ WebRtc_UWord32* timeStamp,
+ WebRtcACMEncodingType* encodingType)
+{
+ WriteLockScoped lockCodec(_codecWrapperLock);
+ ReadLockScoped lockNetEq(*_netEqDecodeLock);
+ return EncodeSafe(bitStream, bitStreamLenByte,
+ timeStamp, encodingType);
+}
+
+
+WebRtc_Word16
+ACMGenericCodec::EncodeSafe(
+ WebRtc_UWord8* bitStream,
+ WebRtc_Word16* bitStreamLenByte,
+ WebRtc_UWord32* timeStamp,
+ WebRtcACMEncodingType* encodingType)
+{
+ // Do we have enough data to encode?
+ // we wait until we have a full frame to encode.
+ if(_inAudioIxWrite < _frameLenSmpl*_noChannels)
+ {
+ // There is not enough audio
+ *timeStamp = 0;
+ *bitStreamLenByte = 0;
+ // Doesn't really matter what this parameter set to
+ *encodingType = kNoEncoding;
+ return 0;
+ }
+
+ // Not all codecs accept the whole frame to be pushed into
+ // encoder at once.
+ const WebRtc_Word16 myBasicCodingBlockSmpl =
+ ACMCodecDB::BasicCodingBlock(_codecID);
+ if((myBasicCodingBlockSmpl < 0) ||
+ (!_encoderInitialized) ||
+ (!_encoderExist))
+ {
+ // This should not happen
+ *timeStamp = 0;
+ *bitStreamLenByte = 0;
+ *encodingType = kNoEncoding;
+ WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _uniqueID,
+ "EncodeSafe: error, basic coding sample block is negative");
+ return -1;
+ }
+
+ // This makes the internal encoder read from the begining of the buffer
+ _inAudioIxRead = 0;
+ *timeStamp = _inTimestamp[0];
+
+ // Process the audio through VAD the function doesn't set _vadLabels.
+ // If VAD is disabled all labels are set to ONE (active)
+ WebRtc_Word16 status = 0;
+ WebRtc_Word16 dtxProcessedSamples = 0;
+
+ status = ProcessFrameVADDTX(bitStream, bitStreamLenByte,
+ &dtxProcessedSamples);
+
+ if(status < 0)
+ {
+ *timeStamp = 0;
+ *bitStreamLenByte = 0;
+ *encodingType = kNoEncoding;
+ }
+ else
+ {
+ if(dtxProcessedSamples > 0)
+ {
+ // Dtx have processed some samples may or may not a bit-stream
+ // is generated we should not do any encoding (normally there
+ // will be not enough data)
+
+ // Setting the following makes that the move of audio data
+ // and timestamps happen correctly
+ _inAudioIxRead = dtxProcessedSamples;
+ // This will let the owner of ACMGenericCodec to know that the
+ // generated bit-stream is DTX to use correct payload type
+ WebRtc_UWord16 sampFreqHz;
+ EncoderSampFreq(sampFreqHz);
+ if (sampFreqHz == 8000) {
+ *encodingType = kPassiveDTXNB;
+ } else if (sampFreqHz == 16000) {
+ *encodingType = kPassiveDTXWB;
+ } else if (sampFreqHz == 32000) {
+ *encodingType = kPassiveDTXSWB;
+ } else if (sampFreqHz == 48000) {
+ *encodingType = kPassiveDTXFB;
+ } else {
+ status = -1;
+ WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _uniqueID,
+ "EncodeSafe: Wrong sampling frequency for DTX.");
+ }
+
+ // Transport empty frame if we have an empty bitstream
+ if ((*bitStreamLenByte == 0)
+ && (_sentCNPrevious || ((_inAudioIxWrite - _inAudioIxRead) <= 0))
+ )
+ {
+ // Makes sure we transmit an empty frame
+ *bitStreamLenByte = 1;
+ *encodingType = kNoEncoding;
+ }
+ _sentCNPrevious = true;
+ }
+ else
+ {
+ _sentCNPrevious = false;
+ // This will let the caller of the method to know if the frame is
+ // Active or non-Active The caller of the method knows that the
+ // stream is encoded by codec and can use the info for callbacks,
+ // if any registered.
+ if(myBasicCodingBlockSmpl == 0)
+ {
+ // This codec can handle all allowed frame sizes as basic
+ // coding block
+ status = InternalEncode(bitStream, bitStreamLenByte);
+
+ if(status < 0)
+ {
+ // TODO:
+ // Maybe reseting the encoder to be fresh for the next
+ // frame
+ WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _uniqueID,
+ "EncodeSafe: error in internalEncode");
+ *bitStreamLenByte = 0;
+ *encodingType = kNoEncoding;
+ }
+ }
+ else
+ {
+ // A basic-coding-block for this codec is defined so we loop
+ // over the audio with the steps of the basic-coding-block.
+ // It is not necessary that in each itteration
+ WebRtc_Word16 tmpBitStreamLenByte;
+
+ // Reset the variables which will be increamented in the loop
+ *bitStreamLenByte = 0;
+ bool done = false;
+ while(!done)
+ {
+ status = InternalEncode(&bitStream[*bitStreamLenByte],
+ &tmpBitStreamLenByte);
+ *bitStreamLenByte += tmpBitStreamLenByte;
+
+ // Guard Against errors and too large payloads
+ if((status < 0) ||
+ (*bitStreamLenByte > MAX_PAYLOAD_SIZE_BYTE))
+ {
+ // Error has happened if we are in the middle of a full
+ // frame we have to exit. Before exiting, whatever bits
+ // are in the buffer are probably corruptred. Anyways
+ // we ignore them.
+ *bitStreamLenByte = 0;
+ *encodingType = kNoEncoding;
+ // We might have come here because of the second
+ // condition.
+ status = -1;
+ WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding,
+ _uniqueID, "EncodeSafe: error in InternalEncode");
+ // break from the loop
+ break;
+ }
+
+ // TODO(andrew): This should be multiplied by the number of
+ // channels, right?
+ // http://code.google.com/p/webrtc/issues/detail?id=714
+ done = _inAudioIxRead >= _frameLenSmpl;
+ }
+ }
+ if(status >= 0)
+ {
+ *encodingType = (_vadLabel[0] == 1)?
+ kActiveNormalEncoded:kPassiveNormalEncoded;
+ // Transport empty frame if we have an empty bitsteram
+ if ((*bitStreamLenByte == 0) && ((_inAudioIxWrite - _inAudioIxRead) <= 0))
+ {
+ // Makes sure we transmit an empty frame
+ *bitStreamLenByte = 1;
+ *encodingType = kNoEncoding;
+ }
+ }
+ }
+ }
+
+ // Move the timestampe buffer according to the number of 10 ms blocks
+ // which are read.
+ WebRtc_UWord16 sampFreqHz;
+ EncoderSampFreq(sampFreqHz);
+
+ WebRtc_Word16 num10MsecBlocks =
+ (WebRtc_Word16)((_inAudioIxRead/_noChannels * 100) / sampFreqHz);
+ if(_inTimestampIxWrite > num10MsecBlocks)
+ {
+ memmove(_inTimestamp, _inTimestamp + num10MsecBlocks,
+ (_inTimestampIxWrite - num10MsecBlocks) * sizeof(WebRtc_Word32));
+ }
+ _inTimestampIxWrite -= num10MsecBlocks;
+
+ // We have to move the audio that is not encoded to the beginning
+ // of the buffer and accordingly adjust the read and write indices.
+ if(_inAudioIxRead < _inAudioIxWrite)
+ {
+ memmove(_inAudio, &_inAudio[_inAudioIxRead],
+ (_inAudioIxWrite - _inAudioIxRead)*sizeof(WebRtc_Word16));
+ }
+
+ _inAudioIxWrite -= _inAudioIxRead;
+
+ _inAudioIxRead = 0;
+ _lastEncodedTimestamp = *timeStamp;
+ return (status < 0) ? (-1):(*bitStreamLenByte);
+}
+
+WebRtc_Word16
+ACMGenericCodec::Decode(
+ WebRtc_UWord8* bitStream,
+ WebRtc_Word16 bitStreamLenByte,
+ WebRtc_Word16* audio,
+ WebRtc_Word16* audioSamples,
+ WebRtc_Word8* speechType)
+{
+ WriteLockScoped wl(_codecWrapperLock);
+ return DecodeSafe(bitStream, bitStreamLenByte, audio,
+ audioSamples, speechType);
+}
+
+bool
+ACMGenericCodec::EncoderInitialized()
+{
+ ReadLockScoped rl(_codecWrapperLock);
+ return _encoderInitialized;
+}
+
+bool
+ACMGenericCodec::DecoderInitialized()
+{
+ ReadLockScoped rl(_codecWrapperLock);
+ return _decoderInitialized;
+}
+
+
+WebRtc_Word32
+ACMGenericCodec::RegisterInNetEq(
+ ACMNetEQ* netEq,
+ const CodecInst& codecInst)
+{
+ WebRtcNetEQ_CodecDef codecDef;
+ WriteLockScoped wl(_codecWrapperLock);
+
+ if(CodecDef(codecDef, codecInst) < 0)
+ {
+ // Failed to register
+ WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _uniqueID,
+ "RegisterInNetEq: error, failed to register");
+ _registeredInNetEq = false;
+ return -1;
+ }
+ else
+ {
+ if(netEq->AddCodec(&codecDef, _isMaster) < 0)
+ {
+ WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _uniqueID,
+ "RegisterInNetEq: error, failed to add codec");
+ _registeredInNetEq = false;
+ return -1;
+ }
+ // Registered
+ _registeredInNetEq = true;
+ return 0;
+ }
+}
+
+WebRtc_Word16
+ACMGenericCodec::EncoderParams(
+ WebRtcACMCodecParams* encParams)
+{
+ ReadLockScoped rl(_codecWrapperLock);
+ return EncoderParamsSafe(encParams);
+}
+
+WebRtc_Word16
+ACMGenericCodec::EncoderParamsSafe(
+ WebRtcACMCodecParams* encParams)
+{
+ // Codec parameters are valid only if the encoder is initialized
+ if(_encoderInitialized)
+ {
+ WebRtc_Word32 currentRate;
+ memcpy(encParams, &_encoderParams, sizeof(WebRtcACMCodecParams));
+ currentRate = encParams->codecInstant.rate;
+ CurrentRate(currentRate);
+ encParams->codecInstant.rate = currentRate;
+ return 0;
+ }
+ else
+ {
+ encParams->codecInstant.plname[0] = '\0';
+ encParams->codecInstant.pltype = -1;
+ encParams->codecInstant.pacsize = 0;
+ encParams->codecInstant.rate = 0;
+ WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _uniqueID,
+ "EncoderParamsSafe: error, encoder not initialized");
+ return -1;
+ }
+}
+
+bool
+ACMGenericCodec::DecoderParams(
+ WebRtcACMCodecParams* decParams,
+ const WebRtc_UWord8 payloadType)
+{
+ ReadLockScoped rl(_codecWrapperLock);
+ return DecoderParamsSafe(decParams, payloadType);
+}
+
+bool
+ACMGenericCodec::DecoderParamsSafe(
+ WebRtcACMCodecParams* decParams,
+ const WebRtc_UWord8 payloadType)
+{
+ // Decoder parameters are valid only if decoder is initialized
+ if(_decoderInitialized)
+ {
+ if(payloadType == _decoderParams.codecInstant.pltype)
+ {
+ memcpy(decParams, &_decoderParams, sizeof(WebRtcACMCodecParams));
+ return true;
+ }
+ }
+
+ decParams->codecInstant.plname[0] = '\0';
+ decParams->codecInstant.pltype = -1;
+ decParams->codecInstant.pacsize = 0;
+ decParams->codecInstant.rate = 0;
+ return false;
+}
+
+WebRtc_Word16
+ACMGenericCodec::ResetEncoder()
+{
+ WriteLockScoped lockCodec(_codecWrapperLock);
+ ReadLockScoped lockNetEq(*_netEqDecodeLock);
+ return ResetEncoderSafe();
+}
+
+WebRtc_Word16
+ACMGenericCodec::ResetEncoderSafe()
+{
+ if(!_encoderExist || !_encoderInitialized)
+ {
+ // We don't reset if doesn't exists or not initialized yet
+ return 0;
+ }
+
+ _inAudioIxWrite = 0;
+ _inAudioIxRead = 0;
+ _inTimestampIxWrite = 0;
+ _noMissedSamples = 0;
+ _isAudioBuffFresh = true;
+ memset(_inAudio, 0, AUDIO_BUFFER_SIZE_W16 * sizeof(WebRtc_Word16));
+ memset(_inTimestamp, 0, TIMESTAMP_BUFFER_SIZE_W32 * sizeof(WebRtc_Word32));
+
+ // Store DTX/VAD params
+ bool enableVAD = _vadEnabled;
+ bool enableDTX = _dtxEnabled;
+ ACMVADMode mode = _vadMode;
+
+ // Reset the encoder
+ if(InternalResetEncoder() < 0)
+ {
+ WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _uniqueID,
+ "ResetEncoderSafe: error in reset encoder");
+ return -1;
+ }
+
+ // Disable DTX & VAD this deletes the states
+ // we like to have fresh start
+ DisableDTX();
+ DisableVAD();
+
+ // Set DTX/VAD
+ return SetVADSafe(enableDTX, enableVAD, mode);
+}
+
+WebRtc_Word16
+ACMGenericCodec::InternalResetEncoder()
+{
+ // For most of the codecs it is sufficient to
+ // call their internal initialization.
+ // There are some exceptions.
+ // ----
+ // For iSAC we don't want to lose BWE history,
+ // so for iSAC we have to over-write this function.
+ // ----
+ return InternalInitEncoder(&_encoderParams);
+}
+
+WebRtc_Word16
+ACMGenericCodec::InitEncoder(
+ WebRtcACMCodecParams* codecParams,
+ bool forceInitialization)
+{
+ WriteLockScoped lockCodec(_codecWrapperLock);
+ ReadLockScoped lockNetEq(*_netEqDecodeLock);
+ return InitEncoderSafe(codecParams, forceInitialization);
+}
+
+WebRtc_Word16
+ACMGenericCodec::InitEncoderSafe(
+ WebRtcACMCodecParams* codecParams,
+ bool forceInitialization)
+{
+ // Check if we got a valid set of parameters
+ int mirrorID;
+ int codecNumber =
+ ACMCodecDB::CodecNumber(&(codecParams->codecInstant), &mirrorID);
+
+ if(codecNumber < 0)
+ {
+ WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _uniqueID,
+ "InitEncoderSafe: error, codec number negative");
+ return -1;
+ }
+ // Check if the parameters are for this codec
+ if((_codecID >= 0) && (_codecID != codecNumber) && (_codecID != mirrorID))
+ {
+ // The current codec is not the same as the one given by codecParams
+ WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _uniqueID,
+ "InitEncoderSafe: current codec is not the same as the one given by codecParams");
+ return -1;
+ }
+
+ if(!CanChangeEncodingParam(codecParams->codecInstant))
+ {
+ WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _uniqueID,
+ "InitEncoderSafe: cannot change encoding parameters");
+ return -1;
+ }
+
+ if(_encoderInitialized && !forceInitialization)
+ {
+ // The encoder is already initialized
+ return 0;
+ }
+ WebRtc_Word16 status;
+ if(!_encoderExist)
+ {
+ _encoderInitialized = false;
+ status = CreateEncoder();
+ if(status < 0)
+ {
+ WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _uniqueID,
+ "InitEncoderSafe: cannot create encoder");
+ return -1;
+ }
+ else
+ {
+ _encoderExist = true;
+ }
+ }
+ _frameLenSmpl = (codecParams->codecInstant).pacsize;
+ _noChannels = codecParams->codecInstant.channels;
+ status = InternalInitEncoder(codecParams);
+ if(status < 0)
+ {
+ WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _uniqueID,
+ "InitEncoderSafe: error in init encoder");
+ _encoderInitialized = false;
+ return -1;
+ }
+ else
+ {
+ memcpy(&_encoderParams, codecParams, sizeof(WebRtcACMCodecParams));
+ _encoderInitialized = true;
+ if(_inAudio == NULL)
+ {
+ _inAudio = new WebRtc_Word16[AUDIO_BUFFER_SIZE_W16];
+ if(_inAudio == NULL)
+ {
+ return -1;
+ }
+ memset(_inAudio, 0, AUDIO_BUFFER_SIZE_W16 * sizeof(WebRtc_Word16));
+ }
+ if(_inTimestamp == NULL)
+ {
+ _inTimestamp = new WebRtc_UWord32[TIMESTAMP_BUFFER_SIZE_W32];
+ if(_inTimestamp == NULL)
+ {
+ return -1;
+ }
+ memset(_inTimestamp, 0, sizeof(WebRtc_UWord32) *
+ TIMESTAMP_BUFFER_SIZE_W32);
+ }
+ _isAudioBuffFresh = true;
+ }
+ status = SetVADSafe(codecParams->enableDTX, codecParams->enableVAD,
+ codecParams->vadMode);
+
+ return status;
+}
+
+bool
+ACMGenericCodec::CanChangeEncodingParam(
+ CodecInst& /*codecInst*/)
+{
+ return true;
+}
+
+WebRtc_Word16
+ACMGenericCodec::InitDecoder(
+ WebRtcACMCodecParams* codecParams,
+ bool forceInitialization)
+{
+ WriteLockScoped lockCodc(_codecWrapperLock);
+ WriteLockScoped lockNetEq(*_netEqDecodeLock);
+ return InitDecoderSafe(codecParams, forceInitialization);
+}
+
+WebRtc_Word16
+ACMGenericCodec::InitDecoderSafe(
+ WebRtcACMCodecParams* codecParams,
+ bool forceInitialization)
+{
+ int mirrorID;
+ // Check if we got a valid set of parameters
+ int codecNumber =
+ ACMCodecDB::ReceiverCodecNumber(&codecParams->codecInstant, &mirrorID);
+
+ if(codecNumber < 0)
+ {
+ WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _uniqueID,
+ "InitDecoderSafe: error, invalid codec number");
+ return -1;
+ }
+ // Check if the parameters are for this codec
+ if((_codecID >= 0) && (_codecID != codecNumber) && (_codecID != mirrorID))
+ {
+ WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _uniqueID,
+ "InitDecoderSafe: current codec is not the same as the one given "
+ "by codecParams");
+ // The current codec is not the same as the one given by codecParams
+ return -1;
+ }
+
+
+ if(_decoderInitialized && !forceInitialization)
+ {
+ // The encoder is already initialized
+ return 0;
+ }
+
+ WebRtc_Word16 status;
+ if(!_decoderExist)
+ {
+ _decoderInitialized = false;
+ status = CreateDecoder();
+ if(status < 0)
+ {
+ WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _uniqueID,
+ "InitDecoderSafe: cannot create decoder");
+ return -1;
+ }
+ else
+ {
+ _decoderExist = true;
+ }
+ }
+
+ status = InternalInitDecoder(codecParams);
+ if(status < 0)
+ {
+ WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _uniqueID,
+ "InitDecoderSafe: cannot init decoder");
+ _decoderInitialized = false;
+ return -1;
+ }
+ else
+ {
+ // Store the parameters
+ SaveDecoderParamSafe(codecParams);
+ _decoderInitialized = true;
+ }
+ return 0;
+}
+
+WebRtc_Word16
+ACMGenericCodec::ResetDecoder(WebRtc_Word16 payloadType)
+{
+ WriteLockScoped lockCodec(_codecWrapperLock);
+ WriteLockScoped lockNetEq(*_netEqDecodeLock);
+ return ResetDecoderSafe(payloadType);
+}
+
+WebRtc_Word16
+ACMGenericCodec::ResetDecoderSafe(WebRtc_Word16 payloadType)
+{
+ WebRtcACMCodecParams decoderParams;
+ if(!_decoderExist || !_decoderInitialized)
+ {
+ return 0;
+ }
+ // Initialization of the decoder should work for all
+ // the codec. If there is a codec that has to keep
+ // some states then we need to define a virtual and
+ // overwrite in that codec
+ DecoderParamsSafe(&decoderParams, (WebRtc_UWord8) payloadType);
+ return InternalInitDecoder(&decoderParams);
+}
+
+void
+ACMGenericCodec::ResetNoMissedSamples()
+{
+ WriteLockScoped cs(_codecWrapperLock);
+ _noMissedSamples = 0;
+}
+
+void
+ACMGenericCodec::IncreaseNoMissedSamples(
+ const WebRtc_Word16 noSamples)
+{
+ _noMissedSamples += noSamples;
+}
+
+// Get the number of missed samples, this can be public
+WebRtc_UWord32
+ACMGenericCodec::NoMissedSamples() const
+{
+ ReadLockScoped cs(_codecWrapperLock);
+ return _noMissedSamples;
+}
+void
+ACMGenericCodec::DestructEncoder()
+{
+ WriteLockScoped wl(_codecWrapperLock);
+
+ // Disable VAD and delete the instance
+ if(_ptrVADInst != NULL)
+ {
+ WebRtcVad_Free(_ptrVADInst);
+ _ptrVADInst = NULL;
+ }
+ _vadEnabled = false;
+ _vadMode = VADNormal;
+
+ //Disable DTX and delete the instance
+ _dtxEnabled = false;
+ if(_ptrDTXInst != NULL)
+ {
+ WebRtcCng_FreeEnc(_ptrDTXInst);
+ _ptrDTXInst = NULL;
+ }
+ _numLPCParams = kNewCNGNumPLCParams;
+
+ DestructEncoderSafe();
+}
+
+void
+ACMGenericCodec::DestructDecoder()
+{
+ WriteLockScoped wl(_codecWrapperLock);
+ _decoderParams.codecInstant.pltype = -1;
+ DestructDecoderSafe();
+}
+
+WebRtc_Word16
+ACMGenericCodec::SetBitRate(
+ const WebRtc_Word32 bitRateBPS)
+{
+ WriteLockScoped wl(_codecWrapperLock);
+ return SetBitRateSafe(bitRateBPS);
+}
+
+WebRtc_Word16
+ACMGenericCodec::SetBitRateSafe(
+ const WebRtc_Word32 bitRateBPS)
+{
+ // If the codec can change the bit-rate this function
+ // should be overwritten, otherewise the only acceptable
+ // value is the one that is in database.
+ CodecInst codecParams;
+ if(ACMCodecDB::Codec(_codecID, &codecParams) < 0)
+ {
+ WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _uniqueID,
+ "SetBitRateSafe: error in ACMCodecDB::Codec");
+ return -1;
+ }
+ if(codecParams.rate != bitRateBPS)
+ {
+ WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _uniqueID,
+ "SetBitRateSafe: rate value is not acceptable");
+ return -1;
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+WebRtc_Word32
+ACMGenericCodec::GetEstimatedBandwidth()
+{
+ WriteLockScoped wl(_codecWrapperLock);
+ return GetEstimatedBandwidthSafe();
+}
+
+WebRtc_Word32
+ACMGenericCodec::GetEstimatedBandwidthSafe()
+{
+ // All codecs but iSAC will return -1
+ return -1;
+}
+
+WebRtc_Word32
+ACMGenericCodec::SetEstimatedBandwidth(
+ WebRtc_Word32 estimatedBandwidth)
+{
+ WriteLockScoped wl(_codecWrapperLock);
+ return SetEstimatedBandwidthSafe(estimatedBandwidth);
+}
+
+WebRtc_Word32
+ACMGenericCodec::SetEstimatedBandwidthSafe(
+ WebRtc_Word32 /*estimatedBandwidth*/)
+{
+ // All codecs but iSAC will return -1
+ return -1;
+}
+
+WebRtc_Word32
+ACMGenericCodec::GetRedPayload(
+ WebRtc_UWord8* redPayload,
+ WebRtc_Word16* payloadBytes)
+{
+ WriteLockScoped wl(_codecWrapperLock);
+ return GetRedPayloadSafe(redPayload, payloadBytes);
+}
+
+WebRtc_Word32
+ACMGenericCodec::GetRedPayloadSafe(
+ WebRtc_UWord8* /* redPayload */,
+ WebRtc_Word16* /* payloadBytes */)
+{
+ return -1; // Do nothing by default
+}
+
+WebRtc_Word16
+ACMGenericCodec::CreateEncoder()
+{
+ WebRtc_Word16 status = 0;
+ if(!_encoderExist)
+ {
+ status = InternalCreateEncoder();
+ // We just created the codec and obviously it is not initialized
+ _encoderInitialized = false;
+ }
+
+ if(status < 0)
+ {
+ WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _uniqueID,
+ "CreateEncoder: error in internal create encoder");
+ _encoderExist = false;
+ }
+ else
+ {
+ _encoderExist = true;
+ }
+ return status;
+}
+
+WebRtc_Word16
+ACMGenericCodec::CreateDecoder()
+{
+ WebRtc_Word16 status = 0;
+ if(!_decoderExist)
+ {
+ status = InternalCreateDecoder();
+ // Decoder just created and obviously it is not initialized
+ _decoderInitialized = false;
+ }
+
+ if(status < 0)
+ {
+ WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _uniqueID,
+ "CreateDecoder: error in internal create decoder");
+ _decoderExist = false;
+ }
+ else
+ {
+ _decoderExist = true;
+ }
+ return status;
+}
+
+
+void ACMGenericCodec::DestructEncoderInst(void* ptrInst)
+{
+ if(ptrInst != NULL)
+ {
+ WriteLockScoped lockCodec(_codecWrapperLock);
+ ReadLockScoped lockNetEq(*_netEqDecodeLock);
+ InternalDestructEncoderInst(ptrInst);
+ }
+}
+
+
+WebRtc_Word16
+ACMGenericCodec::AudioBuffer(
+ WebRtcACMAudioBuff& audioBuff)
+{
+ ReadLockScoped cs(_codecWrapperLock);
+ memcpy(audioBuff.inAudio, _inAudio,
+ AUDIO_BUFFER_SIZE_W16 * sizeof(WebRtc_Word16));
+ audioBuff.inAudioIxRead = _inAudioIxRead;
+ audioBuff.inAudioIxWrite = _inAudioIxWrite;
+ memcpy(audioBuff.inTimestamp, _inTimestamp,
+ TIMESTAMP_BUFFER_SIZE_W32*sizeof(WebRtc_UWord32));
+ audioBuff.inTimestampIxWrite = _inTimestampIxWrite;
+ audioBuff.lastTimestamp = _lastTimestamp;
+ return 0;
+}
+
+
+WebRtc_Word16
+ACMGenericCodec::SetAudioBuffer(
+ WebRtcACMAudioBuff& audioBuff)
+{
+ WriteLockScoped cs(_codecWrapperLock);
+ memcpy(_inAudio, audioBuff.inAudio,
+ AUDIO_BUFFER_SIZE_W16 * sizeof(WebRtc_Word16));
+ _inAudioIxRead = audioBuff.inAudioIxRead;
+ _inAudioIxWrite = audioBuff.inAudioIxWrite;
+ memcpy(_inTimestamp, audioBuff.inTimestamp,
+ TIMESTAMP_BUFFER_SIZE_W32*sizeof(WebRtc_UWord32));
+ _inTimestampIxWrite = audioBuff.inTimestampIxWrite;
+ _lastTimestamp = audioBuff.lastTimestamp;
+ _isAudioBuffFresh = false;
+ return 0;
+}
+
+
+WebRtc_UWord32
+ACMGenericCodec::LastEncodedTimestamp() const
+{
+ ReadLockScoped cs(_codecWrapperLock);
+ return _lastEncodedTimestamp;
+}
+
+
+WebRtc_UWord32
+ACMGenericCodec::EarliestTimestamp() const
+{
+ ReadLockScoped cs(_codecWrapperLock);
+ return _inTimestamp[0];
+}
+
+
+WebRtc_Word16
+ACMGenericCodec::SetVAD(
+ const bool enableDTX,
+ const bool enableVAD,
+ const ACMVADMode mode)
+{
+ WriteLockScoped cs(_codecWrapperLock);
+ return SetVADSafe(enableDTX, enableVAD, mode);
+}
+
+
+WebRtc_Word16
+ACMGenericCodec::SetVADSafe(
+ const bool enableDTX,
+ const bool enableVAD,
+ const ACMVADMode mode)
+{
+ if(enableDTX)
+ {
+ // Make G729 AnnexB a special case
+ if (!STR_CASE_CMP(_encoderParams.codecInstant.plname, "G729") && !_hasInternalDTX)
+ {
+ if (ACMGenericCodec::EnableDTX() < 0)
+ {
+ WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _uniqueID,
+ "SetVADSafe: error in enable DTX");
+ return -1;
+ }
+ }
+ else
+ {
+ if(EnableDTX() < 0)
+ {
+ WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _uniqueID,
+ "SetVADSafe: error in enable DTX");
+ return -1;
+ }
+ }
+
+ if(_hasInternalDTX)
+ {
+ // Codec has internal DTX, practically we don't need WebRtc VAD,
+ // however, we let the user to turn it on if they need call-backs
+ // on silence. Store VAD mode for future even if VAD is off.
+ _vadMode = mode;
+ return (enableVAD)? EnableVAD(mode):DisableVAD();
+ }
+ else
+ {
+ // Codec does not have internal DTX so enabling DTX requires an
+ // active VAD. 'enableDTX == true' overwrites VAD status.
+ if(EnableVAD(mode) < 0)
+ {
+ // If we cannot create VAD we have to disable DTX
+ if(!_vadEnabled)
+ {
+ DisableDTX();
+ }
+ WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _uniqueID,
+ "SetVADSafe: error in enable VAD");
+ return -1;
+ }
+
+ // Return '1', to let the caller know VAD was turned on, even if the
+ // function was called with VAD='false'
+ if (enableVAD == false) {
+ return 1;
+ } else {
+ return 0;
+ }
+ }
+ }
+ else
+ {
+ // Make G729 AnnexB a special case
+ if (!STR_CASE_CMP(_encoderParams.codecInstant.plname, "G729") && !_hasInternalDTX)
+ {
+ ACMGenericCodec::DisableDTX();
+ }
+ else
+ {
+ DisableDTX();
+ }
+ return (enableVAD)? EnableVAD(mode):DisableVAD();
+ }
+}
+
+WebRtc_Word16
+ACMGenericCodec::EnableDTX()
+{
+ if(_hasInternalDTX)
+ {
+ // We should not be here if we have internal DTX
+ // this function should be overwritten by the derived
+ // class in this case
+ return -1;
+ }
+ if(!_dtxEnabled)
+ {
+ if(WebRtcCng_CreateEnc(&_ptrDTXInst) < 0)
+ {
+ _ptrDTXInst = NULL;
+ return -1;
+ }
+ WebRtc_UWord16 freqHz;
+ EncoderSampFreq(freqHz);
+ if(WebRtcCng_InitEnc(_ptrDTXInst, freqHz,
+ ACM_SID_INTERVAL_MSEC, _numLPCParams) < 0)
+ {
+ // Couldn't initialize, has to return -1, and free the memory
+ WebRtcCng_FreeEnc(_ptrDTXInst);
+ _ptrDTXInst = NULL;
+ return -1;
+ }
+ _dtxEnabled = true;
+ }
+ return 0;
+}
+
+WebRtc_Word16
+ACMGenericCodec::DisableDTX()
+{
+ if(_hasInternalDTX)
+ {
+ // We should not be here if we have internal DTX
+ // this function should be overwritten by the derived
+ // class in this case
+ return -1;
+ }
+ if(_ptrDTXInst != NULL)
+ {
+ WebRtcCng_FreeEnc(_ptrDTXInst);
+ _ptrDTXInst = NULL;
+ }
+ _dtxEnabled = false;
+ return 0;
+}
+
+WebRtc_Word16
+ACMGenericCodec::EnableVAD(
+ ACMVADMode mode)
+{
+ if((mode < VADNormal) || (mode > VADVeryAggr))
+ {
+ WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _uniqueID,
+ "EnableVAD: error in VAD mode range");
+ return -1;
+ }
+
+ if(!_vadEnabled)
+ {
+ if(WebRtcVad_Create(&_ptrVADInst) < 0)
+ {
+ _ptrVADInst = NULL;
+ WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _uniqueID,
+ "EnableVAD: error in create VAD");
+ return -1;
+ }
+ if(WebRtcVad_Init(_ptrVADInst) < 0)
+ {
+ WebRtcVad_Free(_ptrVADInst);
+ _ptrVADInst = NULL;
+ WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _uniqueID,
+ "EnableVAD: error in init VAD");
+ return -1;
+ }
+ }
+
+ // Set the vad mode to the given value
+ if(WebRtcVad_set_mode(_ptrVADInst, mode) < 0)
+ {
+ // We failed to set the mode and we have to return -1. If
+ // we already have a working VAD (_vadEnabled == true) then
+ // we leave it to work. otherwise, the following will be
+ // executed.
+ if(!_vadEnabled)
+ {
+ // We just created the instance but cannot set the mode
+ // we have to free the memomry.
+ WebRtcVad_Free(_ptrVADInst);
+ _ptrVADInst = NULL;
+ }
+ WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceAudioCoding, _uniqueID,
+ "EnableVAD: failed to set the VAD mode");
+ return -1;
+ }
+ _vadMode = mode;
+ _vadEnabled = true;
+ return 0;
+}
+
+WebRtc_Word16
+ACMGenericCodec::DisableVAD()
+{
+ if(_ptrVADInst != NULL)
+ {
+ WebRtcVad_Free(_ptrVADInst);
+ _ptrVADInst = NULL;
+ }
+ _vadEnabled = false;
+ return 0;
+}
+
+WebRtc_Word32
+ACMGenericCodec::ReplaceInternalDTX(
+ const bool replaceInternalDTX)
+{
+ WriteLockScoped cs(_codecWrapperLock);
+ return ReplaceInternalDTXSafe(replaceInternalDTX);
+}
+
+WebRtc_Word32
+ACMGenericCodec::ReplaceInternalDTXSafe(
+ const bool /* replaceInternalDTX */)
+{
+ return -1;
+}
+
+WebRtc_Word32
+ACMGenericCodec::IsInternalDTXReplaced(
+ bool* internalDTXReplaced)
+{
+ WriteLockScoped cs(_codecWrapperLock);
+ return IsInternalDTXReplacedSafe(internalDTXReplaced);
+}
+
+WebRtc_Word32
+ACMGenericCodec::IsInternalDTXReplacedSafe(
+ bool* internalDTXReplaced)
+{
+ *internalDTXReplaced = false;
+ return 0;
+}
+
+WebRtc_Word16
+ACMGenericCodec::ProcessFrameVADDTX(
+ WebRtc_UWord8* bitStream,
+ WebRtc_Word16* bitStreamLenByte,
+ WebRtc_Word16* samplesProcessed)
+{
+ if(!_vadEnabled)
+ {
+ // VAD not enabled, set all vadLable[] to 1 (speech detected)
+ for(WebRtc_Word16 n = 0; n < MAX_FRAME_SIZE_10MSEC; n++)
+ {
+ _vadLabel[n] = 1;
+ }
+ *samplesProcessed = 0;
+ return 0;
+ }
+
+ WebRtc_UWord16 freqHz;
+ EncoderSampFreq(freqHz);
+
+ // Calculate number of samples in 10 ms blocks, and number ms in one frame
+ WebRtc_Word16 samplesIn10Msec = (WebRtc_Word16)(freqHz / 100);
+ WebRtc_Word32 frameLenMsec = (((WebRtc_Word32)_frameLenSmpl * 1000) / freqHz);
+ WebRtc_Word16 status;
+
+ // Vector for storing maximum 30 ms of mono audio at 48 kHz.
+ WebRtc_Word16 audio[1440];
+
+ // Calculate number of VAD-blocks to process, and number of samples in each block.
+ int noSamplesToProcess[2];
+ if (frameLenMsec == 40)
+ {
+ // 20 ms in each VAD block
+ noSamplesToProcess[0] = noSamplesToProcess[1] = 2*samplesIn10Msec;
+ }
+ else
+ {
+ // For 10-30 ms framesizes, second VAD block will be size zero ms,
+ // for 50 and 60 ms first VAD block will be 30 ms.
+ noSamplesToProcess[0] = (frameLenMsec > 30)? 3*samplesIn10Msec : _frameLenSmpl;
+ noSamplesToProcess[1] = _frameLenSmpl-noSamplesToProcess[0];
+ }
+
+ int offSet = 0;
+ int loops = (noSamplesToProcess[1]>0) ? 2 : 1;
+ for (int i=0; i<loops; i++) {
+ // If stereo, calculate mean of the two channels
+ if(_noChannels == 2) {
+ for (int j=0; j<noSamplesToProcess[i]; j++) {
+ audio[j] = (_inAudio[(offSet+j)*2]+_inAudio[(offSet+j)*2+1])/2;
+ }
+ offSet = noSamplesToProcess[0];
+ } else {
+ // Mono, copy data from _inAudio to continue work on
+ memcpy(audio, _inAudio, sizeof(WebRtc_Word16)*noSamplesToProcess[i]);
+ }
+
+ // Call VAD
+ status = (WebRtc_Word16)WebRtcVad_Process(_ptrVADInst, (int)freqHz,
+ audio, noSamplesToProcess[i]);
+
+ _vadLabel[i] = status;
+
+ if(status < 0)
+ {
+ // This will force that the data be removed from the buffer
+ *samplesProcessed += noSamplesToProcess[i];
+ return -1;
+ }
+
+ // If VAD decision non-active, update DTX. NOTE! We only do this if the first part of
+ // a frame gets the VAD decision "inactive". Otherwise DTX might say it is time to
+ // transmit SID frame, but we will encode the whole frame, because the first part is
+ // active.
+ *samplesProcessed = 0;
+ if((status == 0) && (i==0) && _dtxEnabled && !_hasInternalDTX)
+ {
+ WebRtc_Word16 bitStreamLen;
+ WebRtc_Word16 num10MsecFrames = noSamplesToProcess[i] / samplesIn10Msec;
+ *bitStreamLenByte = 0;
+ for(WebRtc_Word16 n = 0; n < num10MsecFrames; n++)
+ {
+ // This block is (passive) && (vad enabled). If first CNG after
+ // speech, force SID by setting last parameter to "1".
+ status = WebRtcCng_Encode(_ptrDTXInst,
+ &audio[n*samplesIn10Msec],
+ samplesIn10Msec, bitStream,
+ &bitStreamLen, !_prev_frame_cng);
+ if (status < 0) {
+ return -1;
+ }
+
+ // Update previous frame was CNG.
+ _prev_frame_cng = 1;
+
+ *samplesProcessed += samplesIn10Msec*_noChannels;
+
+ // bitStreamLen will only be > 0 once per 100 ms
+ *bitStreamLenByte += bitStreamLen;
+ }
+
+ // Check if all samples got processed by the DTX
+ if(*samplesProcessed != noSamplesToProcess[i]*_noChannels) {
+ // Set to zero since something went wrong. Shouldn't happen.
+ *samplesProcessed = 0;
+ }
+ } else {
+ // Update previous frame was not CNG.
+ _prev_frame_cng = 0;
+ }
+
+ if(*samplesProcessed > 0)
+ {
+ // The block contains inactive speech, and is processed by DTX.
+ // Discontinue running VAD.
+ break;
+ }
+ }
+
+ return status;
+}
+
+WebRtc_Word16
+ACMGenericCodec::SamplesLeftToEncode()
+{
+ ReadLockScoped rl(_codecWrapperLock);
+ return (_frameLenSmpl <= _inAudioIxWrite)?
+ 0:(_frameLenSmpl - _inAudioIxWrite);
+}
+
+void
+ACMGenericCodec::SetUniqueID(
+ const WebRtc_UWord32 id)
+{
+ _uniqueID = id;
+}
+
+bool
+ACMGenericCodec::IsAudioBufferFresh() const
+{
+ ReadLockScoped rl(_codecWrapperLock);
+ return _isAudioBuffFresh;
+}
+
+// This function is replaced by codec specific functions for some codecs
+WebRtc_Word16
+ACMGenericCodec::EncoderSampFreq(WebRtc_UWord16& sampFreqHz)
+{
+ WebRtc_Word32 f;
+ f = ACMCodecDB::CodecFreq(_codecID);
+ if(f < 0)
+ {
+ WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _uniqueID,
+ "EncoderSampFreq: codec frequency is negative");
+ return -1;
+ }
+ else
+ {
+ sampFreqHz = (WebRtc_UWord16)f;
+ return 0;
+ }
+}
+
+
+WebRtc_Word32
+ACMGenericCodec::ConfigISACBandwidthEstimator(
+ const WebRtc_UWord8 /* initFrameSizeMsec */,
+ const WebRtc_UWord16 /* initRateBitPerSec */,
+ const bool /* enforceFrameSize */)
+{
+ WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceAudioCoding, _uniqueID,
+ "The send-codec is not iSAC, failed to config iSAC bandwidth estimator.");
+ return -1;
+}
+
+WebRtc_Word32
+ACMGenericCodec::SetISACMaxRate(
+ const WebRtc_UWord32 /* maxRateBitPerSec */)
+{
+ WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceAudioCoding, _uniqueID,
+ "The send-codec is not iSAC, failed to set iSAC max rate.");
+ return -1;
+}
+
+WebRtc_Word32
+ACMGenericCodec::SetISACMaxPayloadSize(
+ const WebRtc_UWord16 /* maxPayloadLenBytes */)
+{
+ WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceAudioCoding, _uniqueID,
+ "The send-codec is not iSAC, failed to set iSAC max payload-size.");
+ return -1;
+}
+
+
+void
+ACMGenericCodec::SaveDecoderParam(
+ const WebRtcACMCodecParams* codecParams)
+{
+ WriteLockScoped wl(_codecWrapperLock);
+ SaveDecoderParamSafe(codecParams);
+}
+
+
+void
+ACMGenericCodec::SaveDecoderParamSafe(
+ const WebRtcACMCodecParams* codecParams)
+{
+ memcpy(&_decoderParams, codecParams, sizeof(WebRtcACMCodecParams));
+}
+
+WebRtc_Word16
+ACMGenericCodec::UpdateEncoderSampFreq(
+ WebRtc_UWord16 /* encoderSampFreqHz */)
+{
+ WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _uniqueID,
+ "It is asked for a change in smapling frequency while the \
+current send-codec supports only one sampling rate.");
+ return -1;
+}
+
+
+void
+ACMGenericCodec::SetIsMaster(
+ bool isMaster)
+{
+ WriteLockScoped wl(_codecWrapperLock);
+ _isMaster = isMaster;
+}
+
+
+
+WebRtc_Word16
+ACMGenericCodec::REDPayloadISAC(
+ const WebRtc_Word32 /* isacRate */,
+ const WebRtc_Word16 /* isacBwEstimate */,
+ WebRtc_UWord8* /* payload */,
+ WebRtc_Word16* /* payloadLenBytes */)
+{
+ WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _uniqueID,
+ "Error: REDPayloadISAC is an iSAC specific function");
+ return -1;
+}
+
+} // namespace webrtc