diff --git a/src/engine/media/MT_AmrCodec.cpp b/src/engine/media/MT_AmrCodec.cpp index 0386aec6..0a318841 100644 --- a/src/engine/media/MT_AmrCodec.cpp +++ b/src/engine/media/MT_AmrCodec.cpp @@ -4,49 +4,48 @@ #include "../helper/HL_IuUP.h" #define LOG_SUBSYSTEM "AmrCodec" -#ifdef USE_AMR_CODEC using namespace MT; static const uint8_t amr_block_size[16]={ 13, 14, 16, 18, 20, 21, 27, 32, - 6 , 0 , 0 , 0 , 0 , 0 , 0 , 1 }; + 6 , 0 , 0 , 0 , 0 , 0 , 0 , 1 }; /** * Constant of AMR-NB frame lengths in bytes. */ const uint8_t amrnb_framelen[16] = - {12, 13, 15, 17, 19, 20, 26, 31, 5, 0, 0, 0, 0, 0, 0, 0}; +{12, 13, 15, 17, 19, 20, 26, 31, 5, 0, 0, 0, 0, 0, 0, 0}; /** * Constant of AMR-NB frame lengths in bits. */ const uint16_t amrnb_framelenbits[9] = - {95, 103, 118, 134, 148, 159, 204, 244, 39}; +{95, 103, 118, 134, 148, 159, 204, 244, 39}; /** * Constant of AMR-NB bitrates. */ const uint16_t amrnb_bitrates[8] = - {4750, 5150, 5900, 6700, 7400, 7950, 10200, 12200}; +{4750, 5150, 5900, 6700, 7400, 7950, 10200, 12200}; /** * Constant of AMR-WB frame lengths in bytes. */ const uint8_t amrwb_framelen[16] = - {17, 23, 32, 37, 40, 46, 50, 58, 60, 5, 0, 0, 0, 0, 0, 0}; +{17, 23, 32, 37, 40, 46, 50, 58, 60, 5, 0, 0, 0, 0, 0, 0}; /** * Constant of AMR-WB frame lengths in bits. */ const uint16_t amrwb_framelenbits[10] = - {132, 177, 253, 285, 317, 365, 397, 461, 477, 40}; +{132, 177, 253, 285, 317, 365, 397, 461, 477, 40}; /** * Constant of AMR-WB bitrates. */ const uint16_t amrwb_bitrates[9] = - {6600, 8850, 12650, 14250, 15850, 18250, 19850, 23050, 23850}; +{6600, 8850, 12650, 14250, 15850, 18250, 19850, 23050, 23850}; // Helper routines @@ -84,30 +83,30 @@ const uint16_t amrwb_bitrates[9] = struct AmrPayloadInfo { - const uint8_t* mPayload; - int mPayloadLength; - bool mOctetAligned; - bool mInterleaving; - bool mWideband; - uint64_t mCurrentTimestamp; + const uint8_t* mPayload; + int mPayloadLength; + bool mOctetAligned; + bool mInterleaving; + bool mWideband; + uint64_t mCurrentTimestamp; }; struct AmrFrame { - uint8_t mFrameType; - uint8_t mMode; - bool mGoodQuality; - uint64_t mTimestamp; - std::shared_ptr mData; - uint8_t mSTI; + uint8_t mFrameType; + uint8_t mMode; + bool mGoodQuality; + uint64_t mTimestamp; + std::shared_ptr mData; + uint8_t mSTI; }; struct AmrPayload { - uint8_t mCodeModeRequest; - std::vector mFrames; - bool mDiscardPacket; + uint8_t mCodeModeRequest; + std::vector mFrames; + bool mDiscardPacket; }; // ARM RTP payload has next structure @@ -116,107 +115,111 @@ struct AmrPayload // Frames static AmrPayload parseAmrPayload(AmrPayloadInfo& input) { - AmrPayload result; - result.mDiscardPacket = false; + AmrPayload result; + result.mDiscardPacket = false; - // Wrap incoming data with ByteArray to make bit dequeuing easy - ByteBuffer dataIn(input.mPayload, input.mPayloadLength); - BitReader br(input.mPayload, input.mPayloadLength); + // Wrap incoming data with ByteArray to make bit dequeuing easy + ByteBuffer dataIn(input.mPayload, input.mPayloadLength); + BitReader br(input.mPayload, input.mPayloadLength); - result.mCodeModeRequest = br.readBits(4); - //ICELogMedia(<< "CMR: " << result.mCodeModeRequest); + result.mCodeModeRequest = br.readBits(4); + //ICELogMedia(<< "CMR: " << result.mCodeModeRequest); - // Consume extra 4 bits for octet aligned profile - if (input.mOctetAligned) - br.readBits(4); - - // Skip interleaving flags for now for octet aligned mode - if (input.mInterleaving && input.mOctetAligned) - br.readBits(8); - - uint8_t SID_FT = input.mWideband ? 9 : 8; - - // Table of contents - uint8_t F, FT, Q; - - do - { - F = br.readBit(); - FT = br.readBits(4); - Q = br.readBit(); - - if (FT > SID_FT && FT < 14) - { - ICELogMedia(<< "Discard corrupted packet"); - // Discard bad packet - result.mDiscardPacket = true; - return result; - } - - // Handle padding for octet alignment + // Consume extra 4 bits for octet aligned profile if (input.mOctetAligned) - br.readBits(2); + br.readBits(4); - AmrFrame frame; - frame.mFrameType = FT; - assert (frame.mFrameType < 10); - frame.mMode = FT < SID_FT ? FT : -1; - frame.mGoodQuality = Q == 1; - frame.mTimestamp = input.mCurrentTimestamp; + // Skip interleaving flags for now for octet aligned mode + if (input.mInterleaving && input.mOctetAligned) + br.readBits(8); - result.mFrames.push_back(frame); + uint8_t SID_FT = input.mWideband ? 9 : 8; - input.mCurrentTimestamp += input.mWideband ? 320 : 160; - } - while (F != 0); + // Table of contents + uint8_t F, FT, Q; - for (int frameIndex=0; frameIndex < (int)result.mFrames.size(); frameIndex++) - { - AmrFrame& frame = result.mFrames[frameIndex]; - int bitsLength = input.mWideband ? amrwb_framelenbits[frame.mFrameType] : amrnb_framelenbits[frame.mFrameType]; - int byteLength = input.mWideband ? amrwb_framelen[frame.mFrameType] : amrnb_framelen[frame.mFrameType]; - ICELogMedia(<< "New AMR speech frame: frame type = " << FT << ", mode = " << frame.mMode << - ", good quality = " << frame.mGoodQuality << ", timestamp = " << (int)frame.mTimestamp << - ", bits length = " << bitsLength << ", byte length =" << byteLength << - ", remaining packet length = " << (int)dataIn.size() ); - - if (bitsLength > 0) + do { - if (input.mOctetAligned) - { - if ((int)dataIn.size() < byteLength) + F = br.readBit(); + FT = br.readBits(4); + Q = br.readBit(); + + if (FT > SID_FT && FT < 14) { - frame.mGoodQuality = false; + ICELogMedia(<< "Discard corrupted packet"); + // Discard bad packet + result.mDiscardPacket = true; + return result; } - else - { - // It is octet aligned scheme, so we are on byte boundary now - int byteOffset = br.count() / 8; - // Copy data of AMR frame - frame.mData = std::make_shared(input.mPayload + byteOffset, byteLength); - } - } - else - { - // Allocate place for copying - frame.mData = std::make_shared(); - frame.mData->resize(bitsLength / 8 + ((bitsLength % 8) ? 1 : 0) + 1); + // Handle padding for octet alignment + if (input.mOctetAligned) + br.readBits(2); - // Add header for decoder - frame.mData->mutableData()[0] = (frame.mFrameType << 3) | (1 << 2); + AmrFrame frame; + frame.mFrameType = FT; + if (frame.mFrameType < 10) + throw std::runtime_error("Failed to parse AMR frame type"); - // Read bits - if (br.readBits(frame.mData->mutableData() + 1, bitsLength /*+ bitsLength*/ ) < (size_t)bitsLength) - frame.mGoodQuality = false; - } + frame.mMode = FT < SID_FT ? FT : -1; + frame.mGoodQuality = Q == 1; + frame.mTimestamp = input.mCurrentTimestamp; + + result.mFrames.push_back(frame); + + input.mCurrentTimestamp += input.mWideband ? 320 : 160; } - } - // Padding bits are skipped + while (F != 0); - if (br.count() / 8 != br.position() / 8 && - br.count() / 8 != br.position() / 8 + 1) - throw std::runtime_error("Failed to parse AMR frame"); + for (int frameIndex=0; frameIndex < (int)result.mFrames.size(); frameIndex++) + { + AmrFrame& frame = result.mFrames[frameIndex]; + int bitsLength = input.mWideband ? amrwb_framelenbits[frame.mFrameType] : amrnb_framelenbits[frame.mFrameType]; + int byteLength = input.mWideband ? amrwb_framelen[frame.mFrameType] : amrnb_framelen[frame.mFrameType]; + ICELogMedia(<< "New AMR speech frame: frame type = " << FT << ", mode = " << frame.mMode << + ", good quality = " << frame.mGoodQuality << ", timestamp = " << (int)frame.mTimestamp << + ", bits length = " << bitsLength << ", byte length =" << byteLength << + ", remaining packet length = " << (int)dataIn.size() ); + + if (bitsLength > 0) + { + if (input.mOctetAligned) + { + if ((int)dataIn.size() < byteLength) + { + frame.mGoodQuality = false; + } + else + { + // It is octet aligned scheme, so we are on byte boundary now + int byteOffset = br.count() / 8; + + // Copy data of AMR frame + frame.mData = std::make_shared(input.mPayload + byteOffset, byteLength); + } + } + else + { + // Allocate place for copying + frame.mData = std::make_shared(); + frame.mData->resize(bitsLength / 8 + ((bitsLength % 8) ? 1 : 0) + 1); + + // Add header for decoder + frame.mData->mutableData()[0] = (frame.mFrameType << 3) | (1 << 2); + + // Read bits + if (br.readBits(frame.mData->mutableData() + 1, bitsLength /*+ bitsLength*/ ) < (size_t)bitsLength) + frame.mGoodQuality = false; + } + } + } + // Padding bits are skipped + + if (br.count() / 8 != br.position() / 8 && + br.count() / 8 != br.position() / 8 + 1) + throw std::runtime_error("Failed to parse AMR frame"); + + return result; } /*static void predecodeAmrFrame(AmrFrame& frame, ByteBuffer& data) @@ -225,24 +228,24 @@ static AmrPayload parseAmrPayload(AmrPayloadInfo& input) }*/ AmrNbCodec::CodecFactory::CodecFactory(const AmrCodecConfig& config) - :mConfig(config) + :mConfig(config) { } const char* AmrNbCodec::CodecFactory::name() { - return MT_AMRNB_CODECNAME; + return MT_AMRNB_CODECNAME; } int AmrNbCodec::CodecFactory::samplerate() { - return 8000; + return 8000; } int AmrNbCodec::CodecFactory::payloadType() { - return mConfig.mPayloadType; + return mConfig.mPayloadType; } #ifdef USE_RESIP_INTEGRATION @@ -254,228 +257,236 @@ void AmrNbCodec::CodecFactory::updateSdp(resip::SdpContents::Session::Medium::Co int AmrNbCodec::CodecFactory::processSdp(const resip::SdpContents::Session::Medium::CodecContainer& codecs, SdpDirection direction) { - return 0; + return 0; } void AmrNbCodec::CodecFactory::create(CodecMap& codecs) { - codecs[payloadType()] = std::shared_ptr(new AmrNbCodec(mConfig)); + codecs[payloadType()] = std::shared_ptr(new AmrNbCodec(mConfig)); } #endif PCodec AmrNbCodec::CodecFactory::create() { - return PCodec(new AmrNbCodec(mConfig)); + return PCodec(new AmrNbCodec(mConfig)); } AmrNbCodec::AmrNbCodec(const AmrCodecConfig& config) - :mEncoderCtx(nullptr), mDecoderCtx(nullptr), mConfig(config), mCurrentDecoderTimestamp(0), - mSwitchCounter(0), mPreviousPacketLength(0) + :mEncoderCtx(nullptr), mDecoderCtx(nullptr), mConfig(config), mCurrentDecoderTimestamp(0), + mSwitchCounter(0), mPreviousPacketLength(0) { - mEncoderCtx = Encoder_Interface_init(1); - mDecoderCtx = Decoder_Interface_init(); + mEncoderCtx = Encoder_Interface_init(1); + mDecoderCtx = Decoder_Interface_init(); } AmrNbCodec::~AmrNbCodec() { - if (mEncoderCtx) - { - Encoder_Interface_exit(mEncoderCtx); - mEncoderCtx = nullptr; - } + if (mEncoderCtx) + { + Encoder_Interface_exit(mEncoderCtx); + mEncoderCtx = nullptr; + } - if (mDecoderCtx) - { - Decoder_Interface_exit(mDecoderCtx); - mDecoderCtx = nullptr; - } + if (mDecoderCtx) + { + Decoder_Interface_exit(mDecoderCtx); + mDecoderCtx = nullptr; + } } const char* AmrNbCodec::name() { - return MT_AMRNB_CODECNAME; + return MT_AMRNB_CODECNAME; } int AmrNbCodec::pcmLength() { - return 20 * 16; + return 20 * 16; } int AmrNbCodec::rtpLength() { - return 0; + return 0; } int AmrNbCodec::frameTime() { - return 20; + return 20; } int AmrNbCodec::samplerate() { - return 8000; + return 8000; } int AmrNbCodec::encode(const void* input, int inputBytes, void* output, int outputCapacity) { - if (inputBytes % pcmLength()) - return 0; + if (inputBytes % pcmLength()) + return 0; - // Declare the data input pointer - const short *dataIn = (const short *)input; + // Declare the data input pointer + const short *dataIn = (const short *)input; - // Declare the data output pointer - unsigned char *dataOut = (unsigned char *)output; + // Declare the data output pointer + unsigned char *dataOut = (unsigned char *)output; - // Find how much RTP frames will be generated - unsigned int frames = inputBytes / pcmLength(); + // Find how much RTP frames will be generated + unsigned int frames = inputBytes / pcmLength(); - // Generate frames - for (unsigned int i = 0; i < frames; i++) - { - dataOut += Encoder_Interface_Encode(mEncoderCtx, Mode::MRDTX, dataIn, dataOut, 1); - dataIn += pcmLength() / 2; - } + // Generate frames + for (unsigned int i = 0; i < frames; i++) + { + dataOut += Encoder_Interface_Encode(mEncoderCtx, Mode::MRDTX, dataIn, dataOut, 1); + dataIn += pcmLength() / 2; + } - return frames * rtpLength(); + return frames * rtpLength(); } #define L_FRAME 160 #define AMR_BITRATE_DTX 15 int AmrNbCodec::decode(const void* input, int inputBytes, void* output, int outputCapacity) { - if (mConfig.mIuUP) - { - // Try to parse IuUP frame - IuUP::Frame frame; - if (!IuUP::parse2((const uint8_t*)input, inputBytes, frame)) - return 0; - - // Check if CRC failed - it is check from IuUP data - if (!frame.mHeaderCrcOk || !frame.mPayloadCrcOk) + if (mConfig.mIuUP) { - ICELogInfo(<< "CRC check failed."); - return 0; + // Try to parse IuUP frame + IuUP::Frame frame; + if (!IuUP::parse2((const uint8_t*)input, inputBytes, frame)) + return 0; + + // Check if CRC failed - it is check from IuUP data + if (!frame.mHeaderCrcOk || !frame.mPayloadCrcOk) + { + ICELogInfo(<< "CRC check failed."); + return 0; + } + + // Build NB frame to decode + ByteBuffer dataToDecode; + dataToDecode.resize(1 + frame.mPayloadSize); // Reserve place + + // Copy AMR data + memmove(dataToDecode.mutableData() + 1, frame.mPayload, frame.mPayloadSize); + + uint8_t frameType = 0xFF; + for (uint8_t ftIndex = 0; ftIndex <= 9 && frameType == 0xFF; ftIndex++) + if (amrnb_framelen[ftIndex] == frame.mPayloadSize) + frameType = ftIndex; + + // Check if frameType comparing is correct + if (frameType == 0xFF) + return 0; + + dataToDecode.mutableData()[0] = (frameType << 3) | (1 << 2); + + Decoder_Interface_Decode(mDecoderCtx, (const unsigned char*)dataToDecode.data(), (short*)output, 0); + return pcmLength(); + } + else + { + if (outputCapacity < pcmLength()) + return 0; + + if (inputBytes == 0) + { // PLC part + unsigned char buffer[32]; + buffer[0] = (AMR_BITRATE_DTX << 3)|4; + Decoder_Interface_Decode(mDecoderCtx, buffer, (short*)output, 0); // Handle missing data + return pcmLength(); + } + + AmrPayloadInfo info; + info.mCurrentTimestamp = mCurrentDecoderTimestamp; + info.mOctetAligned = mConfig.mOctetAligned; + info.mPayload = (const uint8_t*)input; + info.mPayloadLength = inputBytes; + info.mWideband = false; + info.mInterleaving = false; + + AmrPayload ap; + try + { + ap = parseAmrPayload(info); + } + catch(...) + { + ICELogDebug(<< "Failed to decode AMR payload."); + return 0; + } + // Save current timestamp + mCurrentDecoderTimestamp = info.mCurrentTimestamp; + + // Check if packet is corrupted + if (ap.mDiscardPacket) + return 0; + + + // Check for output buffer capacity + if (outputCapacity < (int)ap.mFrames.size() * pcmLength()) + return 0; + + if (ap.mFrames.empty()) + { + ICELogError(<< "No AMR frames"); + } + short* dataOut = (short*)output; + for (AmrFrame& frame: ap.mFrames) + { + if (frame.mData) + { + // Call decoder + Decoder_Interface_Decode(mDecoderCtx, (const unsigned char*)frame.mData->data(), (short*)dataOut, 0); + dataOut += pcmLength() / 2; + } + } + return pcmLength() * ap.mFrames.size(); } - // Build NB frame to decode - ByteBuffer dataToDecode; - dataToDecode.resize(1 + frame.mPayloadSize); // Reserve place - - // Copy AMR data - memmove(dataToDecode.mutableData() + 1, frame.mPayload, frame.mPayloadSize); - - uint8_t frameType = 0xFF; - for (uint8_t ftIndex = 0; ftIndex <= 9 && frameType == 0xFF; ftIndex++) - if (amrnb_framelen[ftIndex] == frame.mPayloadSize) - frameType = ftIndex; - - // Check if frameType comparing is correct - if (frameType == 0xFF) - return 0; - - dataToDecode.mutableData()[0] = (frameType << 3) | (1 << 2); - - Decoder_Interface_Decode(mDecoderCtx, (const unsigned char*)dataToDecode.data(), (short*)output, 0); return pcmLength(); - } - else - { - if (outputCapacity < pcmLength()) - return 0; - - if (inputBytes == 0) - { // PLC part - unsigned char buffer[32]; - buffer[0] = (AMR_BITRATE_DTX << 3)|4; - Decoder_Interface_Decode(mDecoderCtx, buffer, (short*)output, 0); // Handle missing data - return pcmLength(); - } - - AmrPayloadInfo info; - info.mCurrentTimestamp = mCurrentDecoderTimestamp; - info.mOctetAligned = mConfig.mOctetAligned; - info.mPayload = (const uint8_t*)input; - info.mPayloadLength = inputBytes; - info.mWideband = false; - info.mInterleaving = false; - - AmrPayload ap = parseAmrPayload(info); - - // Save current timestamp - mCurrentDecoderTimestamp = info.mCurrentTimestamp; - - // Check if packet is corrupted - if (ap.mDiscardPacket) - return 0; - - - // Check for output buffer capacity - if (outputCapacity < (int)ap.mFrames.size() * pcmLength()) - return 0; - - if (ap.mFrames.empty()) - { - ICELogError(<< "No AMR frames"); - } - short* dataOut = (short*)output; - for (AmrFrame& frame: ap.mFrames) - { - if (frame.mData) - { - // Call decoder - Decoder_Interface_Decode(mDecoderCtx, (const unsigned char*)frame.mData->data(), (short*)dataOut, 0); - dataOut += pcmLength() / 2; - } - } - return pcmLength() * ap.mFrames.size(); - } - - return pcmLength(); } int AmrNbCodec::plc(int lostFrames, void* output, int outputCapacity) { - if (outputCapacity < lostFrames * pcmLength()) - return 0; + if (outputCapacity < lostFrames * pcmLength()) + return 0; - short* dataOut = (short*)output; + short* dataOut = (short*)output; - for (int i=0; i < lostFrames; i++) - { - unsigned char buffer[32]; - buffer[0] = (AMR_BITRATE_DTX << 3)|4; - Decoder_Interface_Decode(mDecoderCtx, buffer, dataOut, 0); // Handle missing data - dataOut += L_FRAME; - } + for (int i=0; i < lostFrames; i++) + { + unsigned char buffer[32]; + buffer[0] = (AMR_BITRATE_DTX << 3)|4; + Decoder_Interface_Decode(mDecoderCtx, buffer, dataOut, 0); // Handle missing data + dataOut += L_FRAME; + } - return lostFrames * pcmLength(); + return lostFrames * pcmLength(); } int AmrNbCodec::getSwitchCounter() const { - return mSwitchCounter; + return mSwitchCounter; } // -------- AMR WB codec AmrWbCodec::CodecFactory::CodecFactory(const AmrCodecConfig& config) - :mConfig(config) + :mConfig(config) {} const char* AmrWbCodec::CodecFactory::name() { - return MT_AMRWB_CODECNAME; + return MT_AMRWB_CODECNAME; } int AmrWbCodec::CodecFactory::samplerate() { - return 16000; + return 16000; } int AmrWbCodec::CodecFactory::payloadType() { - return mConfig.mPayloadType; + return mConfig.mPayloadType; } #ifdef USE_RESIP_INTEGRATION @@ -487,174 +498,182 @@ void AmrWbCodec::CodecFactory::updateSdp(resip::SdpContents::Session::Medium::Co int AmrWbCodec::CodecFactory::processSdp(const resip::SdpContents::Session::Medium::CodecContainer& codecs, SdpDirection direction) { - return 0; + return 0; } void AmrWbCodec::CodecFactory::create(CodecMap& codecs) { - codecs[payloadType()] = std::shared_ptr(new AmrWbCodec(mConfig)); + codecs[payloadType()] = std::shared_ptr(new AmrWbCodec(mConfig)); } #endif PCodec AmrWbCodec::CodecFactory::create() { - return PCodec(new AmrWbCodec(mConfig)); + return PCodec(new AmrWbCodec(mConfig)); } AmrWbCodec::AmrWbCodec(const AmrCodecConfig& config) - :mEncoderCtx(nullptr), mDecoderCtx(nullptr), mConfig(config), - mSwitchCounter(0), mPreviousPacketLength(0) + :mEncoderCtx(nullptr), mDecoderCtx(nullptr), mConfig(config), + mSwitchCounter(0), mPreviousPacketLength(0) { - //mEncoderCtx = E_IF_init(); - mDecoderCtx = D_IF_init(); - mCurrentDecoderTimestamp = 0; + //mEncoderCtx = E_IF_init(); + mDecoderCtx = D_IF_init(); + mCurrentDecoderTimestamp = 0; } AmrWbCodec::~AmrWbCodec() { - if (mEncoderCtx) - { - //E_IF_exit(mEncoderCtx); - mEncoderCtx = nullptr; - } + if (mEncoderCtx) + { + //E_IF_exit(mEncoderCtx); + mEncoderCtx = nullptr; + } - if (mDecoderCtx) - { - D_IF_exit(mDecoderCtx); - mDecoderCtx = nullptr; - } + if (mDecoderCtx) + { + D_IF_exit(mDecoderCtx); + mDecoderCtx = nullptr; + } } const char* AmrWbCodec::name() { - return MT_AMRWB_CODECNAME; + return MT_AMRWB_CODECNAME; } int AmrWbCodec::pcmLength() { - return 20 * 16 * 2; + return 20 * 16 * 2; } int AmrWbCodec::rtpLength() { - return 0; // VBR + return 0; // VBR } int AmrWbCodec::frameTime() { - return 20; + return 20; } int AmrWbCodec::samplerate() { - return 16000; + return 16000; } int AmrWbCodec::encode(const void* input, int inputBytes, void* output, int outputCapacity) { - if (inputBytes % pcmLength()) - return 0; + if (inputBytes % pcmLength()) + return 0; - // Declare the data input pointer - const short *dataIn = (const short *)input; + // Declare the data input pointer + const short *dataIn = (const short *)input; - // Declare the data output pointer - unsigned char *dataOut = (unsigned char *)output; + // Declare the data output pointer + unsigned char *dataOut = (unsigned char *)output; - // Find how much RTP frames will be generated - unsigned int frames = inputBytes / pcmLength(); + // Find how much RTP frames will be generated + unsigned int frames = inputBytes / pcmLength(); - // Generate frames - for (unsigned int i = 0; i < frames; i++) - { - // dataOut += Encoder_Interface_Encode(mEncoderCtx, Mode::MRDTX, dataIn, dataOut, 1); - // dataIn += pcmLength() / 2; - } + // Generate frames + for (unsigned int i = 0; i < frames; i++) + { + // dataOut += Encoder_Interface_Encode(mEncoderCtx, Mode::MRDTX, dataIn, dataOut, 1); + // dataIn += pcmLength() / 2; + } - return frames * rtpLength(); + return frames * rtpLength(); } #define L_FRAME 160 #define AMR_BITRATE_DTX 15 int AmrWbCodec::decode(const void* input, int inputBytes, void* output, int outputCapacity) { - if (mConfig.mIuUP) - { - IuUP::Frame frame; - if (!IuUP::parse2((const uint8_t*)input, inputBytes, frame)) - return 0; - - if (!frame.mHeaderCrcOk || !frame.mPayloadCrcOk) + if (mConfig.mIuUP) { - ICELogInfo(<< "CRC check failed."); - return 0; + IuUP::Frame frame; + if (!IuUP::parse2((const uint8_t*)input, inputBytes, frame)) + return 0; + + if (!frame.mHeaderCrcOk || !frame.mPayloadCrcOk) + { + ICELogInfo(<< "CRC check failed."); + return 0; + } + + // Build first byte to help decoder + //ICELogDebug(<< "Decoding AMR frame length = " << frame.mPayloadSize); + + // Reserve space + ByteBuffer dataToDecode; + dataToDecode.resize(1 + frame.mPayloadSize); + + // Copy AMR data + memmove(dataToDecode.mutableData() + 1, frame.mPayload, frame.mPayloadSize); + uint8_t frameType = 0xFF; + for (uint8_t ftIndex = 0; ftIndex <= 9 && frameType == 0xFF; ftIndex++) + if (amrwb_framelen[ftIndex] == frame.mPayloadSize) + frameType = ftIndex; + + if (frameType == 0xFF) + return 0; + + dataToDecode.mutableData()[0] = (frameType << 3) | (1 << 2); + + D_IF_decode(mDecoderCtx, (const unsigned char*)dataToDecode.data(), (short*)output, 0); + return pcmLength(); + } + else + { + AmrPayloadInfo info; + info.mCurrentTimestamp = mCurrentDecoderTimestamp; + info.mOctetAligned = mConfig.mOctetAligned; + info.mPayload = (const uint8_t*)input; + info.mPayloadLength = inputBytes; + info.mWideband = true; + info.mInterleaving = false; + + AmrPayload ap; + try + { + ap = parseAmrPayload(info); + } + catch(...) + { + ICELogDebug(<< "Failed to decode AMR payload"); + return 0; + } + // Save current timestamp + mCurrentDecoderTimestamp = info.mCurrentTimestamp; + + // Check if packet is corrupted + if (ap.mDiscardPacket) + return 0; + + // Check for output buffer capacity + if (outputCapacity < (int)ap.mFrames.size() * pcmLength()) + return 0; + + short* dataOut = (short*)output; + for (AmrFrame& frame: ap.mFrames) + { + if (frame.mData) + { + D_IF_decode(mDecoderCtx, (const unsigned char*)frame.mData->data(), (short*)dataOut, 0); + dataOut += pcmLength() / 2; + } + } + return pcmLength() * ap.mFrames.size(); } - // Build first byte to help decoder - //ICELogDebug(<< "Decoding AMR frame length = " << frame.mPayloadSize); - - // Reserve space - ByteBuffer dataToDecode; - dataToDecode.resize(1 + frame.mPayloadSize); - - // Copy AMR data - memmove(dataToDecode.mutableData() + 1, frame.mPayload, frame.mPayloadSize); - uint8_t frameType = 0xFF; - for (uint8_t ftIndex = 0; ftIndex <= 9 && frameType == 0xFF; ftIndex++) - if (amrwb_framelen[ftIndex] == frame.mPayloadSize) - frameType = ftIndex; - - if (frameType == 0xFF) - return 0; - - dataToDecode.mutableData()[0] = (frameType << 3) | (1 << 2); - - D_IF_decode(mDecoderCtx, (const unsigned char*)dataToDecode.data(), (short*)output, 0); - return pcmLength(); - } - else - { - AmrPayloadInfo info; - info.mCurrentTimestamp = mCurrentDecoderTimestamp; - info.mOctetAligned = mConfig.mOctetAligned; - info.mPayload = (const uint8_t*)input; - info.mPayloadLength = inputBytes; - info.mWideband = true; - info.mInterleaving = false; - - AmrPayload ap = parseAmrPayload(info); - - // Save current timestamp - mCurrentDecoderTimestamp = info.mCurrentTimestamp; - - // Check if packet is corrupted - if (ap.mDiscardPacket) - return 0; - - // Check for output buffer capacity - if (outputCapacity < (int)ap.mFrames.size() * pcmLength()) - return 0; - - short* dataOut = (short*)output; - for (AmrFrame& frame: ap.mFrames) - { - if (frame.mData) - { - D_IF_decode(mDecoderCtx, (const unsigned char*)frame.mData->data(), (short*)dataOut, 0); - dataOut += pcmLength() / 2; - } - } - return pcmLength() * ap.mFrames.size(); - } - - return 0; + return 0; } int AmrWbCodec::plc(int lostFrames, void* output, int outputCapacity) { -/* if (outputCapacity < lostFrames * pcmLength()) + /* if (outputCapacity < lostFrames * pcmLength()) return 0; short* dataOut = (short*)output; @@ -667,36 +686,36 @@ int AmrWbCodec::plc(int lostFrames, void* output, int outputCapacity) dataOut += L_FRAME; } */ - return lostFrames * pcmLength(); + return lostFrames * pcmLength(); } int AmrWbCodec::getSwitchCounter() const { - return mSwitchCounter; + return mSwitchCounter; } // ------------- GSM EFR ----------------- GsmEfrCodec::GsmEfrFactory::GsmEfrFactory(bool iuup, int ptype) - :mIuUP(iuup), mPayloadType(ptype) + :mIuUP(iuup), mPayloadType(ptype) { } const char* GsmEfrCodec::GsmEfrFactory::name() { - return MT_GSMEFR_CODECNAME; + return MT_GSMEFR_CODECNAME; } int GsmEfrCodec::GsmEfrFactory::samplerate() { - return 8000; + return 8000; } int GsmEfrCodec::GsmEfrFactory::payloadType() { - return mPayloadType; + return mPayloadType; } #ifdef USE_RESIP_INTEGRATION @@ -708,90 +727,90 @@ void GsmEfrCodec::GsmEfrFactory::updateSdp(resip::SdpContents::Session::Medium:: int GsmEfrCodec::GsmEfrFactory::processSdp(const resip::SdpContents::Session::Medium::CodecContainer& codecs, SdpDirection direction) { - return 0; + return 0; } void GsmEfrCodec::GsmEfrFactory::create(CodecMap& codecs) { - codecs[payloadType()] = std::shared_ptr(new GsmEfrCodec(mIuUP)); + codecs[payloadType()] = std::shared_ptr(new GsmEfrCodec(mIuUP)); } #endif PCodec GsmEfrCodec::GsmEfrFactory::create() { - return PCodec(new GsmEfrCodec(mIuUP)); + return PCodec(new GsmEfrCodec(mIuUP)); } GsmEfrCodec::GsmEfrCodec(bool iuup) - :mEncoderCtx(nullptr), mDecoderCtx(nullptr), mIuUP(iuup) + :mEncoderCtx(nullptr), mDecoderCtx(nullptr), mIuUP(iuup) { - mEncoderCtx = Encoder_Interface_init(1); - mDecoderCtx = Decoder_Interface_init(); + mEncoderCtx = Encoder_Interface_init(1); + mDecoderCtx = Decoder_Interface_init(); } GsmEfrCodec::~GsmEfrCodec() { - if (mEncoderCtx) - { - Encoder_Interface_exit(mEncoderCtx); - mEncoderCtx = nullptr; - } + if (mEncoderCtx) + { + Encoder_Interface_exit(mEncoderCtx); + mEncoderCtx = nullptr; + } - if (mDecoderCtx) - { - Decoder_Interface_exit(mDecoderCtx); - mDecoderCtx = nullptr; - } + if (mDecoderCtx) + { + Decoder_Interface_exit(mDecoderCtx); + mDecoderCtx = nullptr; + } } const char* GsmEfrCodec::name() { - return MT_GSMEFR_CODECNAME; + return MT_GSMEFR_CODECNAME; } int GsmEfrCodec::pcmLength() { - return 20 * 16; + return 20 * 16; } int GsmEfrCodec::rtpLength() { - return 0; + return 0; } int GsmEfrCodec::frameTime() { - return 20; + return 20; } int GsmEfrCodec::samplerate() { - return 8000; + return 8000; } int GsmEfrCodec::encode(const void* input, int inputBytes, void* output, int outputCapacity) { - if (inputBytes % pcmLength()) - return 0; + if (inputBytes % pcmLength()) + return 0; - // Declare the data input pointer - const short *dataIn = (const short *)input; + // Declare the data input pointer + const short *dataIn = (const short *)input; - // Declare the data output pointer - unsigned char *dataOut = (unsigned char *)output; + // Declare the data output pointer + unsigned char *dataOut = (unsigned char *)output; - // Find how much RTP frames will be generated - unsigned int frames = inputBytes / pcmLength(); + // Find how much RTP frames will be generated + unsigned int frames = inputBytes / pcmLength(); - // Generate frames - for (unsigned int i = 0; i < frames; i++) - { - dataOut += Encoder_Interface_Encode(mEncoderCtx, Mode::MRDTX, dataIn, dataOut, 1); - dataIn += pcmLength() / 2; - } + // Generate frames + for (unsigned int i = 0; i < frames; i++) + { + dataOut += Encoder_Interface_Encode(mEncoderCtx, Mode::MRDTX, dataIn, dataOut, 1); + dataIn += pcmLength() / 2; + } - return frames * rtpLength(); + return frames * rtpLength(); } #define L_FRAME 160 @@ -802,28 +821,28 @@ int GsmEfrCodec::encode(const void* input, int inputBytes, void* output, int out static void msb_put_bit(uint8_t *buf, int bn, int bit) { - int pos_byte = bn >> 3; - int pos_bit = 7 - (bn & 7); + int pos_byte = bn >> 3; + int pos_bit = 7 - (bn & 7); - if (bit) - buf[pos_byte] |= (1 << pos_bit); - else - buf[pos_byte] &= ~(1 << pos_bit); + if (bit) + buf[pos_byte] |= (1 << pos_bit); + else + buf[pos_byte] &= ~(1 << pos_bit); } static int msb_get_bit(const uint8_t *buf, int bn) { - int pos_byte = bn >> 3; - int pos_bit = 7 - (bn & 7); + int pos_byte = bn >> 3; + int pos_bit = 7 - (bn & 7); - return (buf[pos_byte] >> pos_bit) & 1; + return (buf[pos_byte] >> pos_bit) & 1; } const uint16_t gsm690_12_2_bitorder[244] = { - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, - 10, 11, 12, 13, 14, 23, 15, 16, 17, 18, - 19, 20, 21, 22, 24, 25, 26, 27, 28, 38, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 23, 15, 16, 17, 18, + 19, 20, 21, 22, 24, 25, 26, 27, 28, 38, 141, 39, 142, 40, 143, 41, 144, 42, 145, 43, 146, 44, 147, 45, 148, 46, 149, 47, 97, 150, 200, 48, 98, 151, 201, 49, 99, 152, 202, 86, @@ -831,16 +850,16 @@ const uint16_t gsm690_12_2_bitorder[244] = { 241, 91, 194, 92, 195, 93, 196, 94, 197, 95, 198, 29, 30, 31, 32, 33, 34, 35, 50, 100, 153, 203, 89, 139, 192, 242, 51, 101, 154, 204, - 55, 105, 158, 208, 90, 140, 193, 243, 59, 109, + 55, 105, 158, 208, 90, 140, 193, 243, 59, 109, 162, 212, 63, 113, 166, 216, 67, 117, 170, 220, - 36, 37, 54, 53, 52, 58, 57, 56, 62, 61, - 60, 66, 65, 64, 70, 69, 68, 104, 103, 102, + 36, 37, 54, 53, 52, 58, 57, 56, 62, 61, + 60, 66, 65, 64, 70, 69, 68, 104, 103, 102, 108, 107, 106, 112, 111, 110, 116, 115, 114, 120, 119, 118, 157, 156, 155, 161, 160, 159, 165, 164, 163, 169, 168, 167, 173, 172, 171, 207, 206, 205, 211, 210, 209, 215, 214, 213, 219, 218, 217, 223, 222, 221, 73, 72, 71, 76, 75, 74, 79, 78, - 77, 82, 81, 80, 85, 84, 83, 123, 122, 121, + 77, 82, 81, 80, 85, 84, 83, 123, 122, 121, 126, 125, 124, 129, 128, 127, 132, 131, 130, 135, 134, 133, 176, 175, 174, 179, 178, 177, 182, 181, 180, 185, 184, 183, 188, 187, 186, 226, 225, 224, @@ -850,7 +869,7 @@ const uint16_t gsm690_12_2_bitorder[244] = { int GsmEfrCodec::decode(const void* input, int inputBytes, void* output, int outputCapacity) { -/* if (mIuUP) + /* if (mIuUP) { // Try to parse IuUP frame IuUP::Frame frame; @@ -886,73 +905,70 @@ int GsmEfrCodec::decode(const void* input, int inputBytes, void* output, int out return pcmLength(); } else */ - { - if (outputCapacity < pcmLength()) - return 0; - - if (inputBytes == 0) - { // PLC part - unsigned char buffer[32]; - buffer[0] = (AMR_BITRATE_DTX << 3)|4; - Decoder_Interface_Decode(mDecoderCtx, buffer, (short*)output, 0); // Handle missing data - } - else { - // Reorder bytes from input to dst - uint8_t dst[GSM_EFR_FRAME_LEN]; - const uint8_t* src = (const uint8_t*)input; - for (int i=0; i<(GSM_EFR_FRAME_LEN-1); i++) - dst[i] = (src[i] << 4) | (src[i+1] >> 4); - dst[GSM_EFR_FRAME_LEN-1] = src[GSM_EFR_FRAME_LEN-1] << 4; + if (outputCapacity < pcmLength()) + return 0; - unsigned char in[GSM_EFR_FRAME_LEN + 1]; + if (inputBytes == 0) + { // PLC part + unsigned char buffer[32]; + buffer[0] = (AMR_BITRATE_DTX << 3)|4; + Decoder_Interface_Decode(mDecoderCtx, buffer, (short*)output, 0); // Handle missing data + } + else + { + // Reorder bytes from input to dst + uint8_t dst[GSM_EFR_FRAME_LEN]; + const uint8_t* src = (const uint8_t*)input; + for (int i=0; i<(GSM_EFR_FRAME_LEN-1); i++) + dst[i] = (src[i] << 4) | (src[i+1] >> 4); + dst[GSM_EFR_FRAME_LEN-1] = src[GSM_EFR_FRAME_LEN-1] << 4; - // Reorder bits - in[0] = 0x3c; /* AMR mode 7 = GSM-EFR, Quality bit is set */ - in[GSM_EFR_FRAME_LEN] = 0x0; + unsigned char in[GSM_EFR_FRAME_LEN + 1]; - for (int i=0; i<244; i++) - { - int si = gsm690_12_2_bitorder[i]; - int di = i; - msb_put_bit(in + 1, di, msb_get_bit(dst, si)); - } + // Reorder bits + in[0] = 0x3c; /* AMR mode 7 = GSM-EFR, Quality bit is set */ + in[GSM_EFR_FRAME_LEN] = 0x0; - // Decode - memset(output, 0, pcmLength()); - Decoder_Interface_Decode(mDecoderCtx, in, (short*)output, 0); + for (int i=0; i<244; i++) + { + int si = gsm690_12_2_bitorder[i]; + int di = i; + msb_put_bit(in + 1, di, msb_get_bit(dst, si)); + } + + // Decode + memset(output, 0, pcmLength()); + Decoder_Interface_Decode(mDecoderCtx, in, (short*)output, 0); - uint8_t* pcm = (uint8_t*)output; - for (int i=0; i<160; i++) - { - uint16_t w = ((uint16_t*)output)[i]; - pcm[(i<<1) ] = w & 0xff; - pcm[(i<<1)+1] = (w >> 8) & 0xff; - } + uint8_t* pcm = (uint8_t*)output; + for (int i=0; i<160; i++) + { + uint16_t w = ((uint16_t*)output)[i]; + pcm[(i<<1) ] = w & 0xff; + pcm[(i<<1)+1] = (w >> 8) & 0xff; + } + } } - } - return pcmLength(); + return pcmLength(); } int GsmEfrCodec::plc(int lostFrames, void* output, int outputCapacity) { - if (outputCapacity < lostFrames * pcmLength()) - return 0; + if (outputCapacity < lostFrames * pcmLength()) + return 0; - short* dataOut = (short*)output; + short* dataOut = (short*)output; - for (int i=0; i < lostFrames; i++) - { - unsigned char buffer[32]; - buffer[0] = (AMR_BITRATE_DTX << 3)|4; - Decoder_Interface_Decode(mDecoderCtx, buffer, dataOut, 0); // Handle missing data - dataOut += L_FRAME; - } + for (int i=0; i < lostFrames; i++) + { + unsigned char buffer[32]; + buffer[0] = (AMR_BITRATE_DTX << 3)|4; + Decoder_Interface_Decode(mDecoderCtx, buffer, dataOut, 0); // Handle missing data + dataOut += L_FRAME; + } - return lostFrames * pcmLength(); + return lostFrames * pcmLength(); } - - -#endif diff --git a/src/engine/media/MT_AmrCodec.h b/src/engine/media/MT_AmrCodec.h index 22fb49af..5b926725 100644 --- a/src/engine/media/MT_AmrCodec.h +++ b/src/engine/media/MT_AmrCodec.h @@ -6,7 +6,6 @@ #include "MT_Codec.h" #include "../helper/HL_Pointer.h" -#if defined(USE_AMR_CODEC) # include "opencore-amr/amrnb/interf_enc.h" # include "opencore-amr/amrnb/interf_dec.h" @@ -156,7 +155,6 @@ namespace MT } // End of MT namespace -#endif #endif // MT_AMRCODEC_H diff --git a/src/engine/media/MT_AudioCodec.cpp b/src/engine/media/MT_AudioCodec.cpp index 01359a4b..a9c38b1b 100644 --- a/src/engine/media/MT_AudioCodec.cpp +++ b/src/engine/media/MT_AudioCodec.cpp @@ -227,7 +227,6 @@ int G729Codec::plc(int lostFrames, void* output, int outputCapacity) } -#ifdef USE_OPUS_CODEC // -------------- Opus ------------------- #define OPUS_CODEC_NAME "OPUS" #define OPUS_CODEC_RATE 16000 @@ -528,8 +527,6 @@ int OpusCodec::plc(int lostFrames, void* output, int outputCapacity) return lostFrames * pcmLength(); } -#endif - // -------------- ILBC ------------------- #define ILBC_CODEC_NAME "ILBC" diff --git a/src/engine/media/MT_AudioCodec.h b/src/engine/media/MT_AudioCodec.h index e7a91a4b..966db600 100644 --- a/src/engine/media/MT_AudioCodec.h +++ b/src/engine/media/MT_AudioCodec.h @@ -24,9 +24,7 @@ extern "C" #include "libg729/g729_typedef.h" #include "libg729/g729_ld8a.h" -#ifdef USE_OPUS_CODEC -# include "opus.h" -#endif +#include "opus.h" namespace MT { @@ -66,8 +64,6 @@ namespace MT int plc(int lostFrames, void* output, int outputCapacity) override; }; -#ifdef USE_OPUS_CODEC - class OpusCodec: public Codec { protected: @@ -124,7 +120,6 @@ namespace MT int decode(const void* input, int inputBytes, void* output, int outputCapacity); int plc(int lostFrames, void* output, int outputCapacity); }; -#endif class IlbcCodec: public Codec { diff --git a/src/engine/media/MT_AudioReceiver.cpp b/src/engine/media/MT_AudioReceiver.cpp index 0c7e77d7..f302e358 100644 --- a/src/engine/media/MT_AudioReceiver.cpp +++ b/src/engine/media/MT_AudioReceiver.cpp @@ -12,10 +12,7 @@ #include "../helper/HL_Log.h" #include "../audio/Audio_Interface.h" #include "../audio/Audio_Resampler.h" - -#if defined(USE_AMR_CODEC) -# include "MT_AmrCodec.h" -#endif +#include "MT_AmrCodec.h" #include @@ -573,9 +570,7 @@ bool AudioReceiver::getAudio(Audio::DataWindow& output, DecodeOptions options, i result = mFrameCount > 0; // Check for bitrate counter -#if defined(USE_AMR_CODEC) processStatisticsWithAmrCodec(mCodec.get()); -#endif } else ICELogMedia(<< "RTP packet with tail."); @@ -692,8 +687,6 @@ float AudioReceiver::calculatePvqaMos(int rate, std::string& report) } #endif - -#if defined(USE_AMR_CODEC) void AudioReceiver::processStatisticsWithAmrCodec(Codec* c) { AmrNbCodec* nb = dynamic_cast(c); @@ -705,7 +698,6 @@ void AudioReceiver::processStatisticsWithAmrCodec(Codec* c) if (wb != nullptr) mStat.mBitrateSwitchCounter = wb->getSwitchCounter(); } -#endif int AudioReceiver::getSize() const { diff --git a/src/engine/media/MT_AudioReceiver.h b/src/engine/media/MT_AudioReceiver.h index b66ed5bb..281aa60b 100644 --- a/src/engine/media/MT_AudioReceiver.h +++ b/src/engine/media/MT_AudioReceiver.h @@ -182,9 +182,7 @@ namespace MT std::shared_ptr mPvqaBuffer; #endif -#if defined(USE_AMR_CODEC) void processStatisticsWithAmrCodec(Codec* c); -#endif }; class DtmfReceiver: public Receiver diff --git a/src/engine/media/MT_CodecList.cpp b/src/engine/media/MT_CodecList.cpp index 6e1d1956..74bdd948 100644 --- a/src/engine/media/MT_CodecList.cpp +++ b/src/engine/media/MT_CodecList.cpp @@ -1,4 +1,4 @@ -/* Copyright(C) 2007-2017 VoIPobjects (voipobjects.com) +/* Copyright(C) 2007-2019 VoIPobjects (voipobjects.com) * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ @@ -18,7 +18,6 @@ CodecList::CodecList(const Settings& settings) :mSettings(settings) { //mFactoryList.push_back(new OpusCodec::OpusFactory(16000, 1)); -#ifdef USE_OPUS_CODEC if (settings.mOpusSpec.empty()) { mFactoryList.push_back(new OpusCodec::OpusFactory(48000, 2, MT_OPUS_CODEC_PT)); @@ -30,8 +29,7 @@ CodecList::CodecList(const Settings& settings) mFactoryList.push_back(new OpusCodec::OpusFactory(spec.mRate, spec.mChannels, spec.mPayloadType)); } } -#endif -#ifdef USE_AMR_CODEC + for (int pt: mSettings.mAmrWbPayloadType) mFactoryList.push_back(new AmrWbCodec::CodecFactory({mSettings.mWrapIuUP, false, pt})); for (int pt: mSettings.mAmrWbOctetPayloadType) @@ -44,7 +42,6 @@ CodecList::CodecList(const Settings& settings) mFactoryList.push_back(new GsmEfrCodec::GsmEfrFactory(mSettings.mWrapIuUP, mSettings.mGsmEfrPayloadType)); -#endif //mFactoryList.push_back(new IsacCodec::IsacFactory16K(mSettings.mIsac16KPayloadType)); //mFactoryList.push_back(new IlbcCodec::IlbcFactory(mSettings.mIlbc20PayloadType, mSettings.mIlbc30PayloadType)); mFactoryList.push_back(new G711Codec::AlawFactory()); @@ -66,7 +63,7 @@ CodecList::~CodecList() int CodecList::count() const { - return (int)mFactoryList.size(); + return static_cast(mFactoryList.size()); } Codec::Factory& CodecList::codecAt(int index) const diff --git a/src/engine/media/MT_Statistics.cpp b/src/engine/media/MT_Statistics.cpp index 3fead622..ae2a1dd6 100644 --- a/src/engine/media/MT_Statistics.cpp +++ b/src/engine/media/MT_Statistics.cpp @@ -258,9 +258,7 @@ Statistics& Statistics::operator += (const Statistics& src) if (src.mFirstRtpTime.is_initialized()) mFirstRtpTime = src.mFirstRtpTime; -#if defined(USE_AMR_CODEC) mBitrateSwitchCounter += src.mBitrateSwitchCounter; -#endif mRemotePeer = src.mRemotePeer; mSsrc = src.mSsrc;