// Avoid linking issues on embedded systems #if !defined(TARGET_ANDROID) && !defined(TARGET_OPENWRT) && !defined(TARGET_RPI) #include "MT_AmrCodec.h" #include "../helper/HL_ByteBuffer.h" #include "../helper/HL_Log.h" #include "../helper/HL_IuUP.h" #define LOG_SUBSYSTEM "AmrCodec" 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 }; /** * 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}; /** * Constant of AMR-NB frame lengths in bits. */ const uint16_t amrnb_framelenbits[9] = {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}; /** * 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}; /** * Constant of AMR-WB frame lengths in bits. */ const uint16_t amrwb_framelenbits[10] = {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}; // Helper routines /*static int8_t bitrateToMode(uint16_t bitrate) { int8_t mode = -1; switch (bitrate) { // AMR NB case 4750: mode = 0; break; case 5150: mode = 1; break; case 5900: mode = 2; break; case 6700: mode = 3; break; case 7400: mode = 4; break; case 7950: mode = 5; break; case 10200: mode = 6; break; case 12200: mode = 7; break; // AMRWB case 6600: mode = 0; break; case 8850: mode = 1; break; case 12650: mode = 2; break; case 14250: mode = 3; break; case 15850: mode = 4; break; case 18250: mode = 5; break; case 19850: mode = 6; break; case 23050: mode = 7; break; case 23850: mode = 8; break; } return mode; }*/ struct AmrPayloadInfo { 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; }; struct AmrPayload { uint8_t mCodeModeRequest; std::vector mFrames; bool mDiscardPacket; }; // ARM RTP payload has next structure // Header // Table of Contents // Frames static AmrPayload parseAmrPayload(AmrPayloadInfo& input) { AmrPayload result; // Do not skip packet by default; I suppose packet is good enough by default. result.mDiscardPacket = false; // Wrap incoming data with ByteArray to make bit dequeuing easy ByteBuffer dataIn(input.mPayload, static_cast(input.mPayloadLength)); BitReader br(input.mPayload, static_cast(input.mPayloadLength)); // In bandwidth-efficient mode, the payload header simply consists of a // 4-bit codec mode request: // CMR (4 bits): Indicates a codec mode request sent to the speech // encoder at the site of the receiver of this payload. The value of // the CMR field is set to the frame type index of the corresponding // speech mode being requested. The frame type index may be 0-7 for // AMR, as defined in Table 1a in [2], or 0-8 for AMR-WB, as defined // in Table 1a in [4]. CMR value 15 indicates that no mode request // is present, and other values are for future use. result.mCodeModeRequest = static_cast(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); // Silence codec mode constant (it differs for wideband and narrowband codecs) uint8_t SID_FT = input.mWideband ? 9 : 8; // Table of contents uint8_t F, FT, Q; do { // Read TOC. It is still relates to RTP part of AMR frames packing; not the AMR frame itself. // F (1 bit): If set to 1, indicates that this frame is followed by // another speech frame in this payload; if set to 0, indicates that // this frame is the last frame in this payload. F = br.readBit(); // FT (4 bits): Frame type index, indicating either the AMR or AMR-WB // speech coding mode or comfort noise (SID) mode of the // corresponding frame carried in this payload. FT = static_cast(br.readBits(4)); // Q (1 bit): Frame quality indicator. If set to 0, indicates the // corresponding frame is severely damaged, and the receiver should // set the RX_TYPE (see [6]) to either SPEECH_BAD or SID_BAD // depending on the frame type (FT). Q = br.readBit(); // If receiving a ToC entry with a FT value in the range 9-14 for AMR or // 10-13 for AMR-WB, the whole packet SHOULD be discarded. This is to // avoid the loss of data synchronization in the depacketization // process, which can result in a huge degradation in speech quality. if ((input.mWideband && (FT >= 10 && FT <= 13)) || (!input.mWideband && (FT >= 9 && FT <= 14))) { ICELogMedia(<< "Discard corrupted packet"); // Discard bad packet result.mDiscardPacket = true; return result; } // Handle padding for octet alignment if (input.mOctetAligned) br.readBits(2); AmrFrame frame; frame.mFrameType = FT; frame.mSTI = 0; frame.mMode = FT < SID_FT ? FT : 0xFF; frame.mGoodQuality = Q == 1; frame.mTimestamp = input.mCurrentTimestamp; result.mFrames.push_back(frame); input.mCurrentTimestamp += input.mWideband ? 320 : 160; } while (F != 0); for (size_t frameIndex=0; frameIndex < result.mFrames.size(); frameIndex++) { AmrFrame& frame = result.mFrames[frameIndex]; size_t bitsLength = input.mWideband ? amrwb_framelenbits[frame.mFrameType] : amrnb_framelenbits[frame.mFrameType]; size_t byteLength = input.mWideband ? amrwb_framelen[frame.mFrameType] : amrnb_framelen[frame.mFrameType]; ICELogMedia(<< "New AMR speech frame: frame type = " << FT << ", mode = " << frame.mMode << ", timestamp = " << static_cast(frame.mTimestamp) << ", bits length = " << static_cast(bitsLength) << ", byte length =" << static_cast(byteLength) << ", remaining packet length = " << static_cast(dataIn.size())); if (bitsLength > 0) { if (input.mOctetAligned) { if (dataIn.size() < byteLength) frame.mGoodQuality = false; else { // It is octet aligned scheme, so we are on byte boundary now size_t 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) { // Data are already moved into }*/ AmrNbCodec::CodecFactory::CodecFactory(const AmrCodecConfig& config) :mConfig(config) { } const char* AmrNbCodec::CodecFactory::name() { return MT_AMRNB_CODECNAME; } int AmrNbCodec::CodecFactory::samplerate() { return 8000; } int AmrNbCodec::CodecFactory::payloadType() { return mConfig.mPayloadType; } #ifdef USE_RESIP_INTEGRATION void AmrNbCodec::CodecFactory::updateSdp(resip::SdpContents::Session::Medium::CodecContainer& codecs, SdpDirection direction) { } int AmrNbCodec::CodecFactory::processSdp(const resip::SdpContents::Session::Medium::CodecContainer& codecs, SdpDirection direction) { return 0; } void AmrNbCodec::CodecFactory::create(CodecMap& codecs) { codecs[payloadType()] = std::shared_ptr(new AmrNbCodec(mConfig)); } #endif PCodec AmrNbCodec::CodecFactory::create() { return PCodec(new AmrNbCodec(mConfig)); } AmrNbCodec::AmrNbCodec(const AmrCodecConfig& config) :mEncoderCtx(nullptr), mDecoderCtx(nullptr), mConfig(config), mCurrentDecoderTimestamp(0), mSwitchCounter(0), mPreviousPacketLength(0) { mEncoderCtx = Encoder_Interface_init(1); mDecoderCtx = Decoder_Interface_init(); } AmrNbCodec::~AmrNbCodec() { if (mEncoderCtx) { Encoder_Interface_exit(mEncoderCtx); mEncoderCtx = nullptr; } if (mDecoderCtx) { Decoder_Interface_exit(mDecoderCtx); mDecoderCtx = nullptr; } } const char* AmrNbCodec::name() { return MT_AMRNB_CODECNAME; } int AmrNbCodec::pcmLength() { return 20 * 16; } int AmrNbCodec::rtpLength() { return 0; } int AmrNbCodec::frameTime() { return 20; } int AmrNbCodec::samplerate() { return 8000; } int AmrNbCodec::encode(const void* input, int inputBytes, void* output, int outputCapacity) { if (inputBytes % pcmLength()) return 0; // Declare the data input pointer const short *dataIn = (const short *)input; // Declare the data output pointer unsigned char *dataOut = (unsigned char *)output; // 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; } 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) { 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(); } return pcmLength(); } int AmrNbCodec::plc(int lostFrames, void* output, int outputCapacity) { if (outputCapacity < lostFrames * pcmLength()) return 0; 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; } return lostFrames * pcmLength(); } int AmrNbCodec::getSwitchCounter() const { return mSwitchCounter; } // -------- AMR WB codec AmrWbCodec::CodecFactory::CodecFactory(const AmrCodecConfig& config) :mConfig(config) {} const char* AmrWbCodec::CodecFactory::name() { return MT_AMRWB_CODECNAME; } int AmrWbCodec::CodecFactory::samplerate() { return 16000; } int AmrWbCodec::CodecFactory::payloadType() { return mConfig.mPayloadType; } #ifdef USE_RESIP_INTEGRATION void AmrWbCodec::CodecFactory::updateSdp(resip::SdpContents::Session::Medium::CodecContainer& codecs, SdpDirection direction) { } int AmrWbCodec::CodecFactory::processSdp(const resip::SdpContents::Session::Medium::CodecContainer& codecs, SdpDirection direction) { return 0; } void AmrWbCodec::CodecFactory::create(CodecMap& codecs) { codecs[payloadType()] = std::shared_ptr(new AmrWbCodec(mConfig)); } #endif PCodec AmrWbCodec::CodecFactory::create() { return PCodec(new AmrWbCodec(mConfig)); } AmrWbStatistics MT::GAmrWbStatistics; AmrWbCodec::AmrWbCodec(const AmrCodecConfig& config) :mEncoderCtx(nullptr), mDecoderCtx(nullptr), mConfig(config), mSwitchCounter(0), mPreviousPacketLength(0) { //mEncoderCtx = E_IF_init(); mDecoderCtx = D_IF_init(); mCurrentDecoderTimestamp = 0; } AmrWbCodec::~AmrWbCodec() { if (mEncoderCtx) { //E_IF_exit(mEncoderCtx); mEncoderCtx = nullptr; } if (mDecoderCtx) { D_IF_exit(mDecoderCtx); mDecoderCtx = nullptr; } } const char* AmrWbCodec::name() { return MT_AMRWB_CODECNAME; } int AmrWbCodec::pcmLength() { return 20 * 16 * 2; } int AmrWbCodec::rtpLength() { return 0; // VBR } int AmrWbCodec::frameTime() { return 20; } int AmrWbCodec::samplerate() { return 16000; } int AmrWbCodec::encode(const void* input, int inputBytes, void* output, int outputCapacity) { if (inputBytes % pcmLength()) return 0; // Declare the data input pointer // const short *dataIn = (const short *)input; // Declare the data output pointer // unsigned char *dataOut = (unsigned char *)output; // 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; } 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) { 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(...) { GAmrWbStatistics.mNonParsed++; ICELogDebug(<< "Failed to decode AMR payload"); return 0; } // Save current timestamp mCurrentDecoderTimestamp = info.mCurrentTimestamp; // Check if packet is corrupted if (ap.mDiscardPacket) { GAmrWbStatistics.mDiscarded++; 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) { memset(dataOut, 0, static_cast(pcmLength())); 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; } int AmrWbCodec::plc(int lostFrames, void* output, int outputCapacity) { /* if (outputCapacity < lostFrames * pcmLength()) return 0; 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; } */ return lostFrames * pcmLength(); } int AmrWbCodec::getSwitchCounter() const { return mSwitchCounter; } // ------------- GSM EFR ----------------- GsmEfrCodec::GsmEfrFactory::GsmEfrFactory(bool iuup, int ptype) :mIuUP(iuup), mPayloadType(ptype) { } const char* GsmEfrCodec::GsmEfrFactory::name() { return MT_GSMEFR_CODECNAME; } int GsmEfrCodec::GsmEfrFactory::samplerate() { return 8000; } int GsmEfrCodec::GsmEfrFactory::payloadType() { return mPayloadType; } #ifdef USE_RESIP_INTEGRATION void GsmEfrCodec::GsmEfrFactory::updateSdp(resip::SdpContents::Session::Medium::CodecContainer& codecs, SdpDirection direction) { } int GsmEfrCodec::GsmEfrFactory::processSdp(const resip::SdpContents::Session::Medium::CodecContainer& codecs, SdpDirection direction) { return 0; } void GsmEfrCodec::GsmEfrFactory::create(CodecMap& codecs) { codecs[payloadType()] = std::shared_ptr(new GsmEfrCodec(mIuUP)); } #endif PCodec GsmEfrCodec::GsmEfrFactory::create() { return PCodec(new GsmEfrCodec(mIuUP)); } GsmEfrCodec::GsmEfrCodec(bool iuup) :mEncoderCtx(nullptr), mDecoderCtx(nullptr), mIuUP(iuup) { mEncoderCtx = Encoder_Interface_init(1); mDecoderCtx = Decoder_Interface_init(); } GsmEfrCodec::~GsmEfrCodec() { if (mEncoderCtx) { Encoder_Interface_exit(mEncoderCtx); mEncoderCtx = nullptr; } if (mDecoderCtx) { Decoder_Interface_exit(mDecoderCtx); mDecoderCtx = nullptr; } } const char* GsmEfrCodec::name() { return MT_GSMEFR_CODECNAME; } int GsmEfrCodec::pcmLength() { return 20 * 16; } int GsmEfrCodec::rtpLength() { return 0; } int GsmEfrCodec::frameTime() { return 20; } int GsmEfrCodec::samplerate() { return 8000; } int GsmEfrCodec::encode(const void* input, int inputBytes, void* output, int outputCapacity) { if (inputBytes % pcmLength()) return 0; // Declare the data input pointer const short *dataIn = (const short *)input; // Declare the data output pointer unsigned char *dataOut = (unsigned char *)output; // 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; } return frames * rtpLength(); } #define L_FRAME 160 #define AMR_BITRATE_DTX 15 #define GSM_EFR_SAMPLES 160 #define GSM_EFR_FRAME_LEN 31 static void msb_put_bit(uint8_t *buf, int bn, int bit) { 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); } static int msb_get_bit(const uint8_t *buf, int bn) { int pos_byte = bn >> 3; int pos_bit = 7 - (bn & 7); 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, 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, 136, 189, 239, 87, 137, 190, 240, 88, 138, 191, 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, 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, 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, 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, 229, 228, 227, 232, 231, 230, 235, 234, 233, 238, 237, 236, 96, 199, }; int GsmEfrCodec::decode(const void* input, int inputBytes, void* output, int outputCapacity) { /* if (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) { 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 } 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; unsigned char in[GSM_EFR_FRAME_LEN + 1]; // Reorder bits in[0] = 0x3c; /* AMR mode 7 = GSM-EFR, Quality bit is set */ in[GSM_EFR_FRAME_LEN] = 0x0; 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; } } } return pcmLength(); } int GsmEfrCodec::plc(int lostFrames, void* output, int outputCapacity) { if (outputCapacity < lostFrames * pcmLength()) return 0; 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; } return lostFrames * pcmLength(); } #endif