/* * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "acm_codec_database.h" #include "acm_common_defs.h" #include "acm_isac.h" #include "acm_neteq.h" #include "trace.h" #include "webrtc_neteq.h" #include "webrtc_neteq_help_macros.h" #ifdef WEBRTC_CODEC_ISAC #include "acm_isac_macros.h" #include "isac.h" #endif #ifdef WEBRTC_CODEC_ISACFX #include "acm_isac_macros.h" #include "isacfix.h" #endif namespace webrtc { // we need this otherwise we cannot use forward declaration // in the header file #if (defined(WEBRTC_CODEC_ISAC) || defined(WEBRTC_CODEC_ISACFX)) struct ACMISACInst { ACM_ISAC_STRUCT *inst; }; #endif #define ISAC_MIN_RATE 10000 #define ISAC_MAX_RATE 56000 // How the scaling is computed. iSAC computes a gain based on the // bottleneck. It follows the following expression for that // // G(BN_kbps) = pow(10, (a + b * BN_kbps + c * BN_kbps * BN_kbps) / 20.0) // / 3.4641; // // Where for 30 ms framelength we have, // // a = -23; b = 0.48; c = 0; // // As the default encoder is operating at 32kbps we have the scale as // // S(BN_kbps) = G(BN_kbps) / G(32); #define ISAC_NUM_SUPPORTED_RATES 9 const WebRtc_UWord16 isacSuportedRates[ISAC_NUM_SUPPORTED_RATES] = { 32000, 30000, 26000, 23000, 21000, 19000, 17000, 15000, 12000}; const float isacScale[ISAC_NUM_SUPPORTED_RATES] = { 1.0f, 0.8954f, 0.7178f, 0.6081f, 0.5445f, 0.4875f, 0.4365f, 0.3908f, 0.3311f}; // Tables for bandwidth estimates #define NR_ISAC_BANDWIDTHS 24 const WebRtc_Word32 isacRatesWB[NR_ISAC_BANDWIDTHS] = { 10000, 11100, 12300, 13700, 15200, 16900, 18800, 20900, 23300, 25900, 28700, 31900, 10100, 11200, 12400, 13800, 15300, 17000, 18900, 21000, 23400, 26000, 28800, 32000}; const WebRtc_Word32 isacRatesSWB[NR_ISAC_BANDWIDTHS] = { 10000, 11000, 12400, 13800, 15300, 17000, 18900, 21000, 23200, 25400, 27600, 29800, 32000, 34100, 36300, 38500, 40700, 42900, 45100, 47300, 49500, 51700, 53900, 56000, }; #if (!defined(WEBRTC_CODEC_ISAC) && !defined(WEBRTC_CODEC_ISACFX)) ACMISAC::ACMISAC( WebRtc_Word16 /* codecID */) { return; } ACMISAC::~ACMISAC() { return; } ACMGenericCodec* ACMISAC::CreateInstance(void) { return NULL; } WebRtc_Word16 ACMISAC::InternalEncode( WebRtc_UWord8* /* bitstream */, WebRtc_Word16* /* bitStreamLenByte */) { return -1; } WebRtc_Word16 ACMISAC::DecodeSafe( WebRtc_UWord8* /* bitStream */, WebRtc_Word16 /* bitStreamLenByte */, WebRtc_Word16* /* audio */, WebRtc_Word16* /* audioSamples */, WebRtc_Word8* /* speechType */) { return 0; } WebRtc_Word16 ACMISAC::InternalInitEncoder( WebRtcACMCodecParams* /* codecParams */) { return -1; } WebRtc_Word16 ACMISAC::InternalInitDecoder( WebRtcACMCodecParams* /* codecParams */) { return -1; } WebRtc_Word16 ACMISAC::InternalCreateDecoder() { return -1; } void ACMISAC::DestructDecoderSafe() { return; } WebRtc_Word16 ACMISAC::InternalCreateEncoder() { return -1; } void ACMISAC::DestructEncoderSafe() { return; } WebRtc_Word32 ACMISAC::CodecDef( WebRtcNetEQ_CodecDef& /* codecDef */, const CodecInst& /* codecInst */) { return -1; } void ACMISAC::InternalDestructEncoderInst( void* /* ptrInst */) { return; } WebRtc_Word16 ACMISAC::DeliverCachedIsacData( WebRtc_UWord8* /* bitStream */, WebRtc_Word16* /* bitStreamLenByte */, WebRtc_UWord32* /* timestamp */, WebRtcACMEncodingType* /* encodingType */, const WebRtc_UWord16 /* isacRate */, const WebRtc_UWord8 /* isacBWestimate */) { return -1; } WebRtc_Word16 ACMISAC::Transcode( WebRtc_UWord8* /* bitStream */, WebRtc_Word16* /* bitStreamLenByte */, WebRtc_Word16 /* qBWE */, WebRtc_Word32 /* scale */, bool /* isRED */) { return -1; } WebRtc_Word16 ACMISAC::SetBitRateSafe( WebRtc_Word32 /* bitRate */) { return -1; } WebRtc_Word32 ACMISAC::GetEstimatedBandwidthSafe() { return -1; } WebRtc_Word32 ACMISAC::SetEstimatedBandwidthSafe( WebRtc_Word32 /* estimatedBandwidth */) { return -1; } WebRtc_Word32 ACMISAC::GetRedPayloadSafe( WebRtc_UWord8* /* redPayload */, WebRtc_Word16* /* payloadBytes */) { return -1; } WebRtc_Word16 ACMISAC::UnregisterFromNetEqSafe( ACMNetEQ* /* netEq */, WebRtc_Word16 /* payloadType */) { return -1; } bool ACMISAC::IsValidDefaultEncoder() { return false; } WebRtc_Word16 ACMISAC::UpdateDecoderSampFreq( WebRtc_Word16 /* codecId */) { return -1; } WebRtc_Word16 ACMISAC::UpdateEncoderSampFreq( WebRtc_UWord16 /* encoderSampFreqHz */) { return -1; } WebRtc_Word16 ACMISAC::EncoderSampFreq( WebRtc_UWord16& /* sampFreqHz */) { return -1; } WebRtc_Word32 ACMISAC::ConfigISACBandwidthEstimator( const WebRtc_UWord8 /* initFrameSizeMsec */, const WebRtc_UWord16 /* initRateBitPerSec */, const bool /* enforceFrameSize */) { return -1; } WebRtc_Word32 ACMISAC::SetISACMaxPayloadSize( const WebRtc_UWord16 /* maxPayloadLenBytes */) { return -1; } WebRtc_Word32 ACMISAC::SetISACMaxRate( const WebRtc_UWord32 /* maxRateBitPerSec */) { return -1; } void ACMISAC::UpdateFrameLen() { return; } void ACMISAC::CurrentRate( WebRtc_Word32& /*rateBitPerSec */) { return; } bool ACMISAC::DecoderParamsSafe( WebRtcACMCodecParams* /* decParams */, const WebRtc_UWord8 /* payloadType */) { return false; } void ACMISAC::SaveDecoderParamSafe( const WebRtcACMCodecParams* /* codecParams */) { return; } WebRtc_Word16 ACMISAC::REDPayloadISAC( const WebRtc_Word32 /* isacRate */, const WebRtc_Word16 /* isacBwEstimate */, WebRtc_UWord8* /* payload */, WebRtc_Word16* /* payloadLenBytes */) { return -1; } #else //===================== Actual Implementation ======================= #ifdef WEBRTC_CODEC_ISACFX enum IsacSamplingRate { kIsacWideband = 16, kIsacSuperWideband = 32 }; static float ACMISACFixTranscodingScale( WebRtc_UWord16 rate) { // find the scale for transcoding, the scale is rounded // downward float scale = -1; for(WebRtc_Word16 n=0; n < ISAC_NUM_SUPPORTED_RATES; n++) { if(rate >= isacSuportedRates[n]) { scale = isacScale[n]; break; } } return scale; } static void ACMISACFixGetSendBitrate( ACM_ISAC_STRUCT* inst, WebRtc_Word32* bottleNeck) { *bottleNeck = WebRtcIsacfix_GetUplinkBw(inst); } static WebRtc_Word16 ACMISACFixGetNewBitstream( ACM_ISAC_STRUCT* inst, WebRtc_Word16 BWEIndex, WebRtc_Word16 jitterIndex, WebRtc_Word32 rate, WebRtc_Word16* bitStream, bool isRED) { if (isRED) { // RED not supported with iSACFIX return -1; } float scale = ACMISACFixTranscodingScale((WebRtc_UWord16)rate); return WebRtcIsacfix_GetNewBitStream(inst, BWEIndex, scale, bitStream); } static WebRtc_Word16 ACMISACFixGetSendBWE( ACM_ISAC_STRUCT* inst, WebRtc_Word16* rateIndex, WebRtc_Word16* /* dummy */) { WebRtc_Word16 localRateIndex; WebRtc_Word16 status = WebRtcIsacfix_GetDownLinkBwIndex(inst, &localRateIndex); if(status < 0) { return -1; } else { *rateIndex = localRateIndex; return 0; } } static WebRtc_Word16 ACMISACFixControlBWE( ACM_ISAC_STRUCT* inst, WebRtc_Word32 rateBPS, WebRtc_Word16 frameSizeMs, WebRtc_Word16 enforceFrameSize) { return WebRtcIsacfix_ControlBwe(inst, (WebRtc_Word16)rateBPS, frameSizeMs, enforceFrameSize); } static WebRtc_Word16 ACMISACFixControl( ACM_ISAC_STRUCT* inst, WebRtc_Word32 rateBPS, WebRtc_Word16 frameSizeMs) { return WebRtcIsacfix_Control(inst, (WebRtc_Word16)rateBPS, frameSizeMs); } static IsacSamplingRate ACMISACFixGetEncSampRate( ACM_ISAC_STRUCT* /* inst */) { return kIsacWideband; } static IsacSamplingRate ACMISACFixGetDecSampRate( ACM_ISAC_STRUCT* /* inst */) { return kIsacWideband; } #endif ACMISAC::ACMISAC( WebRtc_Word16 codecID): _codecInstPtr(NULL) { _codecInstPtr = new ACMISACInst; if (_codecInstPtr == NULL) { return; } _codecInstPtr->inst = NULL; _codecID = codecID; _enforceFrameSize = false; // by default a 16 kHz iSAC is created. _samplesIn10MsAudio = 160; // Initialize values that can be used uninitialized otherwise _decoderParams.codecInstant.pltype = -1; _decoderParams32kHz.codecInstant.pltype = -1; } ACMISAC::~ACMISAC() { if (_codecInstPtr != NULL) { if(_codecInstPtr->inst != NULL) { ACM_ISAC_FREE(_codecInstPtr->inst); _codecInstPtr->inst = NULL; } delete _codecInstPtr; _codecInstPtr = NULL; } return; } ACMGenericCodec* ACMISAC::CreateInstance(void) { return NULL; } WebRtc_Word16 ACMISAC::InternalEncode( WebRtc_UWord8* bitstream, WebRtc_Word16* bitStreamLenByte) { // ISAC takes 10ms audio everytime we call encoder, therefor, // it should be treated like codecs with 'basic coding block' // non-zero, and the following 'while-loop' should not be necessary. // However, due to a mistake in the codec the frame-size might change // at the first 10ms pushed in to iSAC if the bit-rate is low, this is // sort of a bug in iSAC. to address this we treat iSAC as the // following. if (_codecInstPtr == NULL) { return -1; } *bitStreamLenByte = 0; while((*bitStreamLenByte == 0) && (_inAudioIxRead < _frameLenSmpl)) { if(_inAudioIxRead > _inAudioIxWrite) { // something is wrong. WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _uniqueID, "The actual fram-size of iSAC appears to be larger that expected. All audio \ pushed in but no bit-stream is generated."); return -1; } *bitStreamLenByte = ACM_ISAC_ENCODE(_codecInstPtr->inst, &_inAudio[_inAudioIxRead], (WebRtc_Word16*)bitstream); // increment the read index this tell the caller that how far // we have gone forward in reading the audio buffer _inAudioIxRead += _samplesIn10MsAudio; } if(*bitStreamLenByte == 0) { WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceAudioCoding, _uniqueID, "ISAC Has encoded the whole frame but no bit-stream is generated."); } // a packet is generated iSAC, is set in adaptive mode may change // the frame length and we like to update the bottleneck value as // well, although updating bottleneck is not crucial if((*bitStreamLenByte > 0) && (_isacCodingMode == ADAPTIVE)) { //_frameLenSmpl = ACM_ISAC_GETNEWFRAMELEN(_codecInstPtr->inst); ACM_ISAC_GETSENDBITRATE(_codecInstPtr->inst, &_isacCurrentBN); } UpdateFrameLen(); return *bitStreamLenByte; } WebRtc_Word16 ACMISAC::DecodeSafe( WebRtc_UWord8* /* bitStream */, WebRtc_Word16 /* bitStreamLenByte */, WebRtc_Word16* /* audio */, WebRtc_Word16* /* audioSamples */, WebRtc_Word8* /* speechType */) { return 0; } WebRtc_Word16 ACMISAC::InternalInitEncoder( WebRtcACMCodecParams* codecParams) { // if rate is set to -1 then iSAC has to be in adaptive mode if(codecParams->codecInstant.rate == -1) { _isacCodingMode = ADAPTIVE; } // sanity check that rate is in acceptable range else if((codecParams->codecInstant.rate >= ISAC_MIN_RATE) && (codecParams->codecInstant.rate <= ISAC_MAX_RATE)) { _isacCodingMode = CHANNEL_INDEPENDENT; _isacCurrentBN = codecParams->codecInstant.rate; } else { return -1; } // we need to set the encoder sampling frequency. if(UpdateEncoderSampFreq((WebRtc_UWord16)codecParams->codecInstant.plfreq) < 0) { return -1; } if(ACM_ISAC_ENCODERINIT(_codecInstPtr->inst, _isacCodingMode) < 0) { return -1; } // apply the frame-size and rate if operating in // channel-independent mode if(_isacCodingMode == CHANNEL_INDEPENDENT) { if(ACM_ISAC_CONTROL(_codecInstPtr->inst, codecParams->codecInstant.rate, codecParams->codecInstant.pacsize / (codecParams->codecInstant.plfreq / 1000)) < 0) { return -1; } } else { // We need this for adaptive case and has to be called // after initialization ACM_ISAC_GETSENDBITRATE( _codecInstPtr->inst, &_isacCurrentBN); } _frameLenSmpl = ACM_ISAC_GETNEWFRAMELEN(_codecInstPtr->inst); return 0; } WebRtc_Word16 ACMISAC::InternalInitDecoder( WebRtcACMCodecParams* codecParams) { if (_codecInstPtr == NULL) { return -1; } // set decoder sampling frequency. if(codecParams->codecInstant.plfreq == 32000) { UpdateDecoderSampFreq(ACMCodecDB::isacswb); } else { UpdateDecoderSampFreq(ACMCodecDB::isac); } // in a one-way communication we may never register send-codec. // However we like that the BWE to work properly so it has to // be initialized. The BWE is initialized when iSAC encoder is initialized. // Therefore, we need this. if(!_encoderInitialized) { // Since we don't require a valid rate or a valid packet size when initializing // the decoder, we set valid values before initializing encoder codecParams->codecInstant.rate = ISACWB_DEFAULT_RATE; codecParams->codecInstant.pacsize = ISACSWB_PAC_SIZE; if(InternalInitEncoder(codecParams) < 0) { return -1; } _encoderInitialized = true; } return ACM_ISAC_DECODERINIT(_codecInstPtr->inst); } WebRtc_Word16 ACMISAC::InternalCreateDecoder() { if (_codecInstPtr == NULL) { return -1; } WebRtc_Word16 status = ACM_ISAC_CREATE (&(_codecInstPtr->inst)); // specific to codecs with one instance for encoding and decoding _encoderInitialized = false; if(status < 0) { _encoderExist = false; } else { _encoderExist = true; } return status; } void ACMISAC::DestructDecoderSafe() { // codec with shared instance cannot delete. _decoderInitialized = false; return; } WebRtc_Word16 ACMISAC::InternalCreateEncoder() { if (_codecInstPtr == NULL) { return -1; } WebRtc_Word16 status = ACM_ISAC_CREATE(&(_codecInstPtr->inst)); // specific to codecs with one instance for encoding and decoding _decoderInitialized = false; if(status < 0) { _decoderExist = false; } else { _decoderExist = true; } return status; } void ACMISAC::DestructEncoderSafe() { // codec with shared instance cannot delete. _encoderInitialized = false; return; } WebRtc_Word32 ACMISAC::CodecDef( WebRtcNetEQ_CodecDef& codecDef, const CodecInst& codecInst) { // Sanity checks if (_codecInstPtr == NULL) { return -1; } if (!_decoderInitialized || !_decoderExist) { // Todo: // log error return -1; } // Fill up the structure by calling // "SET_CODEC_PAR" & "SET_ISAC_FUNCTION." // Then call NetEQ to add the codec to it's // database. if(codecInst.plfreq == 16000) { SET_CODEC_PAR((codecDef), kDecoderISAC, codecInst.pltype, _codecInstPtr->inst, 16000); #ifdef WEBRTC_CODEC_ISAC SET_ISAC_FUNCTIONS((codecDef)); #else SET_ISACfix_FUNCTIONS((codecDef)); #endif } else { #ifdef WEBRTC_CODEC_ISAC SET_CODEC_PAR((codecDef), kDecoderISACswb, codecInst.pltype, _codecInstPtr->inst, 32000); SET_ISACSWB_FUNCTIONS((codecDef)); #else return -1; #endif } return 0; } void ACMISAC::InternalDestructEncoderInst( void* ptrInst) { if(ptrInst != NULL) { ACM_ISAC_FREE((ACM_ISAC_STRUCT *)ptrInst); } return; } WebRtc_Word16 ACMISAC::Transcode( WebRtc_UWord8* bitStream, WebRtc_Word16* bitStreamLenByte, WebRtc_Word16 qBWE, WebRtc_Word32 rate, bool isRED) { WebRtc_Word16 jitterInfo = 0; // transcode from a higher rate to lower rate // sanity check if (_codecInstPtr == NULL) { return -1; } *bitStreamLenByte = ACM_ISAC_GETNEWBITSTREAM(_codecInstPtr->inst, qBWE, jitterInfo, rate, (WebRtc_Word16*)bitStream, (isRED)? 1:0); if(*bitStreamLenByte < 0) { // error happened *bitStreamLenByte = 0; return -1; } else { return *bitStreamLenByte; } } WebRtc_Word16 ACMISAC::SetBitRateSafe( WebRtc_Word32 bitRate) { if (_codecInstPtr == NULL) { return -1; } WebRtc_UWord16 encoderSampFreq; EncoderSampFreq(encoderSampFreq); bool reinit = false; // change the BN of iSAC if(bitRate == -1) { // ADAPTIVE MODE // Check if it was already in adaptive mode if(_isacCodingMode != ADAPTIVE) { // was not in adaptive, then set the mode to adaptive // and flag for re-initialization _isacCodingMode = ADAPTIVE; reinit = true; } } // Sanity check if the rate valid else if((bitRate >= ISAC_MIN_RATE) && (bitRate <= ISAC_MAX_RATE)) { //check if it was in channel-independent mode before if(_isacCodingMode != CHANNEL_INDEPENDENT) { // was not in channel independent, set the mode to // channel-independent and flag for re-initialization _isacCodingMode = CHANNEL_INDEPENDENT; reinit = true; } // store the bottleneck _isacCurrentBN = (WebRtc_UWord16)bitRate; } else { // invlaid rate return -1; } WebRtc_Word16 status = 0; if(reinit) { // initialize and check if it is successful if(ACM_ISAC_ENCODERINIT(_codecInstPtr->inst, _isacCodingMode) < 0) { // failed initialization return -1; } } if(_isacCodingMode == CHANNEL_INDEPENDENT) { status = ACM_ISAC_CONTROL(_codecInstPtr->inst, _isacCurrentBN, (encoderSampFreq == 32000)? 30:(_frameLenSmpl / 16)); if(status < 0) { status = -1; } } // Update encoder parameters _encoderParams.codecInstant.rate = bitRate; UpdateFrameLen(); return status; } WebRtc_Word32 ACMISAC::GetEstimatedBandwidthSafe() { WebRtc_Word16 bandwidthIndex; WebRtc_Word16 delayIndex; IsacSamplingRate sampRate; // Get bandwidth information ACM_ISAC_GETSENDBWE(_codecInstPtr->inst, &bandwidthIndex, &delayIndex); // Validy check of index if ((bandwidthIndex < 0) || (bandwidthIndex > NR_ISAC_BANDWIDTHS)) { return -1; } // Check sample frequency sampRate = ACM_ISAC_GETDECSAMPRATE(_codecInstPtr->inst); if(sampRate == kIsacWideband) { return isacRatesWB[bandwidthIndex]; } else { return isacRatesSWB[bandwidthIndex]; } } WebRtc_Word32 ACMISAC::SetEstimatedBandwidthSafe( WebRtc_Word32 estimatedBandwidth) { IsacSamplingRate sampRate; WebRtc_Word16 bandwidthIndex; // Check sample frequency and choose appropriate table sampRate = ACM_ISAC_GETENCSAMPRATE(_codecInstPtr->inst); if(sampRate == kIsacWideband) { // Search through the WB rate table to find the index bandwidthIndex = NR_ISAC_BANDWIDTHS/2 - 1; for (int i=0; i<(NR_ISAC_BANDWIDTHS/2); i++) { if (estimatedBandwidth == isacRatesWB[i]) { bandwidthIndex = i; break; } else if (estimatedBandwidth == isacRatesWB[i+NR_ISAC_BANDWIDTHS/2]) { bandwidthIndex = i + NR_ISAC_BANDWIDTHS/2; break; } else if (estimatedBandwidth < isacRatesWB[i]) { bandwidthIndex = i; break; } } } else { // Search through the SWB rate table to find the index bandwidthIndex = NR_ISAC_BANDWIDTHS - 1; for (int i=0; iinst, bandwidthIndex); return 0; } WebRtc_Word32 ACMISAC::GetRedPayloadSafe( #if (!defined(WEBRTC_CODEC_ISAC)) WebRtc_UWord8* /* redPayload */, WebRtc_Word16* /* payloadBytes */) { return -1; #else WebRtc_UWord8* redPayload, WebRtc_Word16* payloadBytes) { WebRtc_Word16 bytes = WebRtcIsac_GetRedPayload(_codecInstPtr->inst, (WebRtc_Word16*)redPayload); if (bytes < 0) { return -1; } *payloadBytes = bytes; return 0; #endif } WebRtc_Word16 ACMISAC::UnregisterFromNetEqSafe( ACMNetEQ* netEq, WebRtc_Word16 payloadType) { if(payloadType == _decoderParams.codecInstant.pltype) { return netEq->RemoveCodec(kDecoderISAC); } else if(payloadType == _decoderParams32kHz.codecInstant.pltype) { return netEq->RemoveCodec(kDecoderISACswb); } else { WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _uniqueID, "Cannot unregister codec %s given payload-type %d does not match \ the stored payload type %d or %d", _decoderParams.codecInstant.plname, payloadType, _decoderParams.codecInstant.pltype, _decoderParams32kHz.codecInstant.pltype); return -1; } } WebRtc_Word16 ACMISAC::UpdateDecoderSampFreq( #ifdef WEBRTC_CODEC_ISAC WebRtc_Word16 codecId) { if(ACMCodecDB::isac == codecId) { return WebRtcIsac_SetDecSampRate(_codecInstPtr->inst, kIsacWideband); } else if(ACMCodecDB::isacswb == codecId) { return WebRtcIsac_SetDecSampRate(_codecInstPtr->inst, kIsacSuperWideband); } else { return -1; } #else WebRtc_Word16 /* codecId */) { return 0; #endif } WebRtc_Word16 ACMISAC::UpdateEncoderSampFreq( #ifdef WEBRTC_CODEC_ISAC WebRtc_UWord16 encoderSampFreqHz) { WebRtc_UWord16 currentSampRateHz; EncoderSampFreq(currentSampRateHz); if(currentSampRateHz != encoderSampFreqHz) { if((encoderSampFreqHz != 16000) && (encoderSampFreqHz != 32000)) { return -1; } else { _inAudioIxRead = 0; _inAudioIxWrite = 0; _inTimestampIxWrite = 0; if(encoderSampFreqHz == 16000) { if(WebRtcIsac_SetEncSampRate(_codecInstPtr->inst, kIsacWideband) < 0) { return -1; } _samplesIn10MsAudio = 160; } else { if(WebRtcIsac_SetEncSampRate(_codecInstPtr->inst, kIsacSuperWideband) < 0) { return -1; } _samplesIn10MsAudio = 320; } _frameLenSmpl = ACM_ISAC_GETNEWFRAMELEN(_codecInstPtr->inst); _encoderParams.codecInstant.pacsize = _frameLenSmpl; _encoderParams.codecInstant.plfreq = encoderSampFreqHz; return 0; } } #else WebRtc_UWord16 /* codecId */) { #endif return 0; } WebRtc_Word16 ACMISAC::EncoderSampFreq( WebRtc_UWord16& sampFreqHz) { IsacSamplingRate sampRate; sampRate = ACM_ISAC_GETENCSAMPRATE(_codecInstPtr->inst); if(sampRate == kIsacSuperWideband) { sampFreqHz = 32000; } else { sampFreqHz = 16000; } return 0; } WebRtc_Word32 ACMISAC::ConfigISACBandwidthEstimator( const WebRtc_UWord8 initFrameSizeMsec, const WebRtc_UWord16 initRateBitPerSec, const bool enforceFrameSize) { WebRtc_Word16 status; { WebRtc_UWord16 sampFreqHz; EncoderSampFreq(sampFreqHz); // @TODO: at 32kHz we hardcode calling with 30ms and enforce // the frame-size otherwise we might get error. Revise if // control-bwe is changed. if(sampFreqHz == 32000) { status = ACM_ISAC_CONTROL_BWE(_codecInstPtr->inst, initRateBitPerSec, 30, 1); } else { status = ACM_ISAC_CONTROL_BWE(_codecInstPtr->inst, initRateBitPerSec, initFrameSizeMsec, enforceFrameSize? 1:0); } } if(status < 0) { WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _uniqueID, "Coutn't config iSAC BWE."); return -1; } UpdateFrameLen(); ACM_ISAC_GETSENDBITRATE(_codecInstPtr->inst, &_isacCurrentBN); return 0; } WebRtc_Word32 ACMISAC::SetISACMaxPayloadSize( const WebRtc_UWord16 maxPayloadLenBytes) { return ACM_ISAC_SETMAXPAYLOADSIZE(_codecInstPtr->inst, maxPayloadLenBytes); } WebRtc_Word32 ACMISAC::SetISACMaxRate( const WebRtc_UWord32 maxRateBitPerSec) { return ACM_ISAC_SETMAXRATE(_codecInstPtr->inst, maxRateBitPerSec); } void ACMISAC::UpdateFrameLen() { _frameLenSmpl = ACM_ISAC_GETNEWFRAMELEN(_codecInstPtr->inst); _encoderParams.codecInstant.pacsize = _frameLenSmpl; } void ACMISAC::CurrentRate(WebRtc_Word32& rateBitPerSec) { if(_isacCodingMode == ADAPTIVE) { ACM_ISAC_GETSENDBITRATE(_codecInstPtr->inst, &rateBitPerSec); } } bool ACMISAC::DecoderParamsSafe( WebRtcACMCodecParams* decParams, const WebRtc_UWord8 payloadType) { if(_decoderInitialized) { if(payloadType == _decoderParams.codecInstant.pltype) { memcpy(decParams, &_decoderParams, sizeof(WebRtcACMCodecParams)); return true; } if(payloadType == _decoderParams32kHz.codecInstant.pltype) { memcpy(decParams, &_decoderParams32kHz, sizeof(WebRtcACMCodecParams)); return true; } } return false; } void ACMISAC::SaveDecoderParamSafe( const WebRtcACMCodecParams* codecParams) { // set decoder sampling frequency. if(codecParams->codecInstant.plfreq == 32000) { memcpy(&_decoderParams32kHz, codecParams, sizeof(WebRtcACMCodecParams)); } else { memcpy(&_decoderParams, codecParams, sizeof(WebRtcACMCodecParams)); } } WebRtc_Word16 ACMISAC::REDPayloadISAC( const WebRtc_Word32 isacRate, const WebRtc_Word16 isacBwEstimate, WebRtc_UWord8* payload, WebRtc_Word16* payloadLenBytes) { WebRtc_Word16 status; ReadLockScoped rl(_codecWrapperLock); status = Transcode(payload, payloadLenBytes, isacBwEstimate, isacRate, true); return status; } #endif } // namespace webrtc