/* * 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. */ /* * isac.c * * This C file contains the functions for the ISAC API * */ #include "isac.h" #include "bandwidth_estimator.h" #include "crc.h" #include "entropy_coding.h" #include "codec.h" #include "structs.h" #include "signal_processing_library.h" #include "lpc_shape_swb16_tables.h" #include "os_specific_inline.h" #include #include #include #include #define BIT_MASK_DEC_INIT 0x0001 #define BIT_MASK_ENC_INIT 0x0002 #define LEN_CHECK_SUM_WORD8 4 #define MAX_NUM_LAYERS 10 /**************************************************************************** * UpdatePayloadSizeLimit() * * Call this function to update the limit on the payload size. The limit on * payload size might change i) if a user ''directly changes the limit by * calling xxx_setMaxPayloadSize() or xxx_setMaxRate(), or ii) indirectly * when bandwidth is changing. The latter might be the result of bandwidth * adaptation, or direct change of the bottleneck in instantaneous mode. * * This function takes the current overall limit on payload, and translate it * to the limits on lower and upper-band. If the codec is in wideband mode * then the overall limit and the limit on the lower-band is the same. * Otherwise, a fraction of the limit should be allocated to lower-band * leaving some room for the upper-band bit-stream. That is why an update * of limit is required every time that the bandwidth is changing. * */ static void UpdatePayloadSizeLimit( ISACMainStruct *instISAC) { WebRtc_Word16 lim30MsPayloadBytes; WebRtc_Word16 lim60MsPayloadBytes; lim30MsPayloadBytes = WEBRTC_SPL_MIN( (instISAC->maxPayloadSizeBytes), (instISAC->maxRateBytesPer30Ms)); lim60MsPayloadBytes = WEBRTC_SPL_MIN( (instISAC->maxPayloadSizeBytes), (instISAC->maxRateBytesPer30Ms << 1)); // The only time that iSAC will have 60 ms // frame-size is when operating in wideband so // there is no upper-band bit-stream if(instISAC->bandwidthKHz == isac8kHz) { // at 8 kHz there is no upper-band bit-stream // therefore the lower-band limit is as the overall // limit. instISAC->instLB.ISACencLB_obj.payloadLimitBytes60 = lim60MsPayloadBytes; instISAC->instLB.ISACencLB_obj.payloadLimitBytes30 = lim30MsPayloadBytes; } else { // when in super-wideband, we only have 30 ms frames // Do a rate allocation for the given limit. if(lim30MsPayloadBytes > 250) { // 4/5 to lower-band the rest for upper-band instISAC->instLB.ISACencLB_obj.payloadLimitBytes30 = (lim30MsPayloadBytes << 2) / 5; } else if(lim30MsPayloadBytes > 200) { // for the interval of 200 to 250 the share of // upper-band linearly grows from 20 to 50; instISAC->instLB.ISACencLB_obj.payloadLimitBytes30 = (lim30MsPayloadBytes << 1) / 5 + 100; } else { // allocate only 20 for upper-band instISAC->instLB.ISACencLB_obj.payloadLimitBytes30 = lim30MsPayloadBytes - 20; } instISAC->instUB.ISACencUB_obj.maxPayloadSizeBytes = lim30MsPayloadBytes; } } /**************************************************************************** * UpdateBottleneck() * * This function updates the bottleneck only if the codec is operating in * channel-adaptive mode. Furthermore, as the update of bottleneck might * result in an update of bandwidth, therefore, the bottlenech should be * updated just right before the first 10ms of a frame is pushed into encoder. * */ static void UpdateBottleneck( ISACMainStruct *instISAC) { // read the bottleneck from bandwidth estimator for the // first 10 ms audio. This way, if there is a change // in bandwidth upper and lower-band will be in sync. if((instISAC->codingMode == 0) && (instISAC->instLB.ISACencLB_obj.buffer_index == 0) && (instISAC->instLB.ISACencLB_obj.frame_nb == 0)) { WebRtc_Word32 bottleneck; WebRtcIsac_GetUplinkBandwidth(&(instISAC->bwestimator_obj), &bottleneck); // Adding hysteresis when increasing signal bandwidth if((instISAC->bandwidthKHz == isac8kHz) && (bottleneck > 37000) && (bottleneck < 41000)) { bottleneck = 37000; } // switching from 12 kHz to 16 kHz is not allowed at this revision // If we let this happen, we have to take care of buffer_index and // the last LPC vector. if((instISAC->bandwidthKHz != isac16kHz) && (bottleneck > 46000)) { bottleneck = 46000; } // we might need a rate allocation. if(instISAC->encoderSamplingRateKHz == kIsacWideband) { // wideband is the only choise we have here. instISAC->instLB.ISACencLB_obj.bottleneck = (bottleneck > 32000)? 32000:bottleneck; instISAC->bandwidthKHz = isac8kHz; } else { // do the rate-allosation and get the new bandwidth. enum ISACBandwidth bandwidth; WebRtcIsac_RateAllocation(bottleneck, &(instISAC->instLB.ISACencLB_obj.bottleneck), &(instISAC->instUB.ISACencUB_obj.bottleneck), &bandwidth); if(bandwidth != isac8kHz) { instISAC->instLB.ISACencLB_obj.new_framelength = 480; } if(bandwidth != instISAC->bandwidthKHz) { // bandwidth is changing. instISAC->bandwidthKHz = bandwidth; UpdatePayloadSizeLimit(instISAC); if(bandwidth == isac12kHz) { instISAC->instLB.ISACencLB_obj.buffer_index = 0; } // currently we don't let the bandwidth to switch to 16 kHz // if in adaptive mode. If we let this happen, we have to take // car of buffer_index and the last LPC vector. } } } } /**************************************************************************** * GetSendBandwidthInfo() * * This is called to get the bandwidth info. This info is the bandwidth and * and the jitter of 'there-to-here' channel, estimated 'here.' These info * is signaled in an in-band fashion to the otherside. * * The call to the bandwidth estimator trigers a recursive averaging which * has to be synchronized between encoder & decoder, therefore. The call to * BWE should be once per packet. As the BWE info is inserted into bit-stream * we need a valid info right before the encodeLB function is going to * generating a bit-stream. That is when lower-band buffer has already 20ms * of audio, and the 3rd block of 10ms is going to be injected into encoder. * * Inputs: * - instISAC : iSAC instance. * * Outputs: * - bandwidthIndex : an index which has to be encoded in * lower-band bit-stream, indicating the * bandwidth of there-to-here channel. * - jitterInfo : this indicates if the jitter is high * or low and it is encoded in upper-band * bit-stream. * */ static void GetSendBandwidthInfo( ISACMainStruct* instISAC, WebRtc_Word16* bandwidthIndex, WebRtc_Word16* jitterInfo) { if((instISAC->instLB.ISACencLB_obj.buffer_index == (FRAMESAMPLES_10ms << 1)) && (instISAC->instLB.ISACencLB_obj.frame_nb == 0)) { /* bandwidth estimation and coding */ WebRtcIsac_GetDownlinkBwJitIndexImpl(&(instISAC->bwestimator_obj), bandwidthIndex, jitterInfo, instISAC->decoderSamplingRateKHz); } } /**************************************************************************** * WebRtcIsac_AssignSize(...) * * This function returns the size of the ISAC instance, so that the instance * can be created out side iSAC. * * Output: * - sizeinbytes : number of bytes needed to allocate for the * instance. * * Return value : 0 - Ok * -1 - Error */ WebRtc_Word16 WebRtcIsac_AssignSize( int *sizeInBytes) { *sizeInBytes = sizeof(ISACMainStruct) * 2 / sizeof(WebRtc_Word16); return 0; } /**************************************************************************** * WebRtcIsac_Assign(...) * * This function assignes the memory already created to the ISAC instance. * * Input: * - ISAC_main_inst : address of the pointer to the coder instance. * - instISAC_Addr : the already allocaded memeory, where we put the * iSAC struct * * Return value : 0 - Ok * -1 - Error */ WebRtc_Word16 WebRtcIsac_Assign( ISACStruct** ISAC_main_inst, void* instISAC_Addr) { if(instISAC_Addr != NULL) { ISACMainStruct* instISAC = (ISACMainStruct*)instISAC_Addr; instISAC->errorCode = 0; instISAC->initFlag = 0; // Assign the address *ISAC_main_inst = (ISACStruct*)instISAC_Addr; // Default is wideband. instISAC->encoderSamplingRateKHz = kIsacWideband; instISAC->decoderSamplingRateKHz = kIsacWideband; instISAC->bandwidthKHz = isac8kHz; return 0; } else { return -1; } } /**************************************************************************** * WebRtcIsac_Create(...) * * This function creates an ISAC instance, which will contain the state * information for one coding/decoding channel. * * Input: * - ISAC_main_inst : address of the pointer to the coder instance. * * Return value : 0 - Ok * -1 - Error */ WebRtc_Word16 WebRtcIsac_Create( ISACStruct** ISAC_main_inst) { ISACMainStruct* instISAC; instISAC = (ISACMainStruct*)WEBRTC_SPL_VNEW(ISACMainStruct, 1); *ISAC_main_inst = (ISACStruct*)instISAC; if(*ISAC_main_inst != NULL) { instISAC->errorCode = 0; instISAC->initFlag = 0; // Default is wideband instISAC->bandwidthKHz = isac8kHz; instISAC->encoderSamplingRateKHz = kIsacWideband; instISAC->decoderSamplingRateKHz = kIsacWideband; return 0; } else { return -1; } } /**************************************************************************** * WebRtcIsac_Free(...) * * This function frees the ISAC instance created at the beginning. * * Input: * - ISAC_main_inst : a ISAC instance. * * Return value : 0 - Ok * -1 - Error */ WebRtc_Word16 WebRtcIsac_Free( ISACStruct* ISAC_main_inst) { ISACMainStruct* instISAC; instISAC = (ISACMainStruct*)ISAC_main_inst; WEBRTC_SPL_FREE(instISAC); return 0; } /**************************************************************************** * EncoderInitLb(...) - internal function for initialization of * Lower Band * EncoderInitUb(...) - internal function for initialization of * Upper Band * WebRtcIsac_EncoderInit(...) - API function * * This function initializes a ISAC instance prior to the encoder calls. * * Input: * - ISAC_main_inst : ISAC instance. * - CodingMode : 0 -> Bit rate and frame length are automatically * adjusted to available bandwidth on * transmission channel, applicable just to * wideband mode. * 1 -> User sets a frame length and a target bit * rate which is taken as the maximum * short-term average bit rate. * * Return value : 0 - Ok * -1 - Error */ static WebRtc_Word16 EncoderInitLb( ISACLBStruct* instLB, WebRtc_Word16 codingMode, enum IsacSamplingRate sampRate) { WebRtc_Word16 statusInit = 0; int k; /* Init stream vector to zero */ for(k=0; k < STREAM_SIZE_MAX_60; k++) { instLB->ISACencLB_obj.bitstr_obj.stream[k] = 0; } if((codingMode == 1) || (sampRate == kIsacSuperWideband)) { // 30 ms frame-size if either in super-wideband or // instanteneous mode (I-mode) instLB->ISACencLB_obj.new_framelength = 480; } else { instLB->ISACencLB_obj.new_framelength = INITIAL_FRAMESAMPLES; } WebRtcIsac_InitMasking(&instLB->ISACencLB_obj.maskfiltstr_obj); WebRtcIsac_InitPreFilterbank(&instLB->ISACencLB_obj.prefiltbankstr_obj); WebRtcIsac_InitPitchFilter(&instLB->ISACencLB_obj.pitchfiltstr_obj); WebRtcIsac_InitPitchAnalysis( &instLB->ISACencLB_obj.pitchanalysisstr_obj); instLB->ISACencLB_obj.buffer_index = 0; instLB->ISACencLB_obj.frame_nb = 0; /* default for I-mode */ instLB->ISACencLB_obj.bottleneck = 32000; instLB->ISACencLB_obj.current_framesamples = 0; instLB->ISACencLB_obj.s2nr = 0; instLB->ISACencLB_obj.payloadLimitBytes30 = STREAM_SIZE_MAX_30; instLB->ISACencLB_obj.payloadLimitBytes60 = STREAM_SIZE_MAX_60; instLB->ISACencLB_obj.maxPayloadBytes = STREAM_SIZE_MAX_60; instLB->ISACencLB_obj.maxRateInBytes = STREAM_SIZE_MAX_30; instLB->ISACencLB_obj.enforceFrameSize = 0; /* invalid value prevents getRedPayload to run before encoder is called */ instLB->ISACencLB_obj.lastBWIdx = -1; return statusInit; } static WebRtc_Word16 EncoderInitUb( ISACUBStruct* instUB, WebRtc_Word16 bandwidth) { WebRtc_Word16 statusInit = 0; int k; /* Init stream vector to zero */ for(k = 0; k < STREAM_SIZE_MAX_60; k++) { instUB->ISACencUB_obj.bitstr_obj.stream[k] = 0; } WebRtcIsac_InitMasking(&instUB->ISACencUB_obj.maskfiltstr_obj); WebRtcIsac_InitPreFilterbank(&instUB->ISACencUB_obj.prefiltbankstr_obj); if(bandwidth == isac16kHz) { instUB->ISACencUB_obj.buffer_index = LB_TOTAL_DELAY_SAMPLES; } else { instUB->ISACencUB_obj.buffer_index = 0; } /* default for I-mode */ instUB->ISACencUB_obj.bottleneck = 32000; // These store the limits for the wideband + super-wideband bit-stream. instUB->ISACencUB_obj.maxPayloadSizeBytes = STREAM_SIZE_MAX_30 << 1; // This has to be updated after each lower-band encoding to guarantee // a correct payload-limitation. instUB->ISACencUB_obj.numBytesUsed = 0; memset(instUB->ISACencUB_obj.data_buffer_float, 0, (MAX_FRAMESAMPLES + LB_TOTAL_DELAY_SAMPLES) * sizeof(float)); memcpy(&(instUB->ISACencUB_obj.lastLPCVec), WebRtcIsac_kMeanLarUb16, sizeof(double) * UB_LPC_ORDER); return statusInit; } WebRtc_Word16 WebRtcIsac_EncoderInit( ISACStruct* ISAC_main_inst, WebRtc_Word16 codingMode) { ISACMainStruct *instISAC; WebRtc_Word16 status; instISAC = (ISACMainStruct*)ISAC_main_inst; if((codingMode != 0) && (codingMode != 1)) { instISAC->errorCode = ISAC_DISALLOWED_CODING_MODE; return -1; } // default bottleneck instISAC->bottleneck = MAX_ISAC_BW; if(instISAC->encoderSamplingRateKHz == kIsacWideband) { instISAC->bandwidthKHz = isac8kHz; instISAC->maxPayloadSizeBytes = STREAM_SIZE_MAX_60; instISAC->maxRateBytesPer30Ms = STREAM_SIZE_MAX_30; } else { instISAC->bandwidthKHz = isac16kHz; instISAC->maxPayloadSizeBytes = STREAM_SIZE_MAX; instISAC->maxRateBytesPer30Ms = STREAM_SIZE_MAX; } // Channel-adaptive = 0; Instantaneous (Channel-independent) = 1; instISAC->codingMode = codingMode; WebRtcIsac_InitBandwidthEstimator(&instISAC->bwestimator_obj, instISAC->encoderSamplingRateKHz, instISAC->decoderSamplingRateKHz); WebRtcIsac_InitRateModel(&instISAC->rate_data_obj); /* default for I-mode */ instISAC->MaxDelay = 10.0; status = EncoderInitLb(&instISAC->instLB, codingMode, instISAC->encoderSamplingRateKHz); if(status < 0) { instISAC->errorCode = -status; return -1; } if(instISAC->encoderSamplingRateKHz == kIsacSuperWideband) { // Initialize encoder filter-bank. memset(instISAC->analysisFBState1, 0, FB_STATE_SIZE_WORD32 * sizeof(WebRtc_Word32)); memset(instISAC->analysisFBState2, 0, FB_STATE_SIZE_WORD32 * sizeof(WebRtc_Word32)); status = EncoderInitUb(&(instISAC->instUB), instISAC->bandwidthKHz); if(status < 0) { instISAC->errorCode = -status; return -1; } } // Initializtion is successful, set the flag instISAC->initFlag |= BIT_MASK_ENC_INIT; return 0; } /**************************************************************************** * WebRtcIsac_Encode(...) * * This function encodes 10ms frame(s) and inserts it into a package. * Input speech length has to be 160 samples (10ms). The encoder buffers those * 10ms frames until it reaches the chosen Framesize (480 or 960 samples * corresponding to 30 or 60 ms frames), and then proceeds to the encoding. * * Input: * - ISAC_main_inst : ISAC instance. * - speechIn : input speech vector. * * Output: * - encoded : the encoded data vector * * Return value: * : >0 - Length (in bytes) of coded data * : 0 - The buffer didn't reach the chosen * frameSize so it keeps buffering speech * samples. * : -1 - Error */ WebRtc_Word16 WebRtcIsac_Encode( ISACStruct* ISAC_main_inst, const WebRtc_Word16* speechIn, WebRtc_Word16* encoded) { ISACMainStruct* instISAC; ISACLBStruct* instLB; ISACUBStruct* instUB; float inFrame[FRAMESAMPLES_10ms]; WebRtc_Word16 speechInLB[FRAMESAMPLES_10ms]; WebRtc_Word16 speechInUB[FRAMESAMPLES_10ms]; WebRtc_Word16 streamLenLB; WebRtc_Word16 streamLenUB; WebRtc_Word16 streamLen; WebRtc_Word16 k; WebRtc_UWord8* ptrEncodedUW8 = (WebRtc_UWord8*)encoded; int garbageLen; WebRtc_Word32 bottleneck; WebRtc_Word16 bottleneckIdx = 0; WebRtc_Word16 jitterInfo = 0; instISAC = (ISACMainStruct*)ISAC_main_inst; instLB = &(instISAC->instLB); instUB = &(instISAC->instUB); /* check if encoder initiated */ if((instISAC->initFlag & BIT_MASK_ENC_INIT) != BIT_MASK_ENC_INIT) { instISAC->errorCode = ISAC_ENCODER_NOT_INITIATED; return -1; } if(instISAC->encoderSamplingRateKHz == kIsacSuperWideband) { WebRtcSpl_AnalysisQMF(speechIn, speechInLB, speechInUB, instISAC->analysisFBState1, instISAC->analysisFBState2); /* convert from fixed to floating point */ for(k = 0; k < FRAMESAMPLES_10ms; k++) { inFrame[k] = (float)speechInLB[k]; } } else { for(k = 0; k < FRAMESAMPLES_10ms; k++) { inFrame[k] = (float) speechIn[k]; } } /* add some noise to avoid denormal numbers */ inFrame[0] += (float)1.23455334e-3; inFrame[1] -= (float)2.04324239e-3; inFrame[2] += (float)1.90854954e-3; inFrame[9] += (float)1.84854878e-3; // This function will update the bottleneck if required UpdateBottleneck(instISAC); // Get the bandwith information which has to be sent to the other side GetSendBandwidthInfo(instISAC, &bottleneckIdx, &jitterInfo); // // ENCODE LOWER-BAND // streamLenLB = WebRtcIsac_EncodeLb(inFrame, &instLB->ISACencLB_obj, instISAC->codingMode, bottleneckIdx); if(streamLenLB < 0) { return -1; } if(instISAC->encoderSamplingRateKHz == kIsacSuperWideband) { instUB = &(instISAC->instUB); // convert to float for(k = 0; k < FRAMESAMPLES_10ms; k++) { inFrame[k] = (float) speechInUB[k]; } /* add some noise to avoid denormal numbers */ inFrame[0] += (float)1.23455334e-3; inFrame[1] -= (float)2.04324239e-3; inFrame[2] += (float)1.90854954e-3; inFrame[9] += (float)1.84854878e-3; // Tell to upper-band the number of bytes used so far. // This is for payload limitation. instUB->ISACencUB_obj.numBytesUsed = streamLenLB + 1 + LEN_CHECK_SUM_WORD8; // // ENCODE UPPER-BAND // switch(instISAC->bandwidthKHz) { case isac12kHz: { streamLenUB = WebRtcIsac_EncodeUb12(inFrame, &instUB->ISACencUB_obj, jitterInfo); break; } case isac16kHz: { streamLenUB = WebRtcIsac_EncodeUb16(inFrame, &instUB->ISACencUB_obj, jitterInfo); break; } case isac8kHz: { streamLenUB = 0; break; } default: return -1; } if((streamLenUB < 0) && (streamLenUB != -ISAC_PAYLOAD_LARGER_THAN_LIMIT)) { // an error has happened but this is not the error due to a // bit-stream larger than the limit return -1; } if(streamLenLB == 0) { return 0; } // One bite is allocated for the length. According to older decoders // so the length bit-stream plus one byte for size and // LEN_CHECK_SUM_WORD8 for the checksum should be less than or equal // to 255. if((streamLenUB > (255 - (LEN_CHECK_SUM_WORD8 + 1))) || (streamLenUB == -ISAC_PAYLOAD_LARGER_THAN_LIMIT)) { // we have got a too long bit-stream we skip the upper-band // bit-stream for this frame. streamLenUB = 0; } memcpy(ptrEncodedUW8, instLB->ISACencLB_obj.bitstr_obj.stream, streamLenLB); streamLen = streamLenLB; if(streamLenUB > 0) { ptrEncodedUW8[streamLenLB] = (WebRtc_UWord8)(streamLenUB + 1 + LEN_CHECK_SUM_WORD8); memcpy(&ptrEncodedUW8[streamLenLB + 1], instUB->ISACencUB_obj.bitstr_obj.stream, streamLenUB); streamLen += ptrEncodedUW8[streamLenLB]; } else { ptrEncodedUW8[streamLenLB] = 0; } } else { if(streamLenLB == 0) { return 0; } memcpy(ptrEncodedUW8, instLB->ISACencLB_obj.bitstr_obj.stream, streamLenLB); streamLenUB = 0; streamLen = streamLenLB; } // Add Garbage if required. WebRtcIsac_GetUplinkBandwidth(&instISAC->bwestimator_obj, &bottleneck); if(instISAC->codingMode == 0) { int minBytes; int limit; WebRtc_UWord8* ptrGarbage; instISAC->MaxDelay = (double)WebRtcIsac_GetUplinkMaxDelay( &instISAC->bwestimator_obj); /* update rate model and get minimum number of bytes in this packet */ minBytes = WebRtcIsac_GetMinBytes(&(instISAC->rate_data_obj), streamLen, instISAC->instLB.ISACencLB_obj.current_framesamples, bottleneck, instISAC->MaxDelay, instISAC->bandwidthKHz); /* Make sure MinBytes does not exceed packet size limit */ if(instISAC->bandwidthKHz == isac8kHz) { if(instLB->ISACencLB_obj.current_framesamples == FRAMESAMPLES) { limit = instLB->ISACencLB_obj.payloadLimitBytes30; } else { limit = instLB->ISACencLB_obj.payloadLimitBytes60; } } else { limit = instUB->ISACencUB_obj.maxPayloadSizeBytes; } minBytes = (minBytes > limit)? limit:minBytes; /* Make sure we don't allow more than 255 bytes of garbage data. We store the length of the garbage data in 8 bits in the bitstream, 255 is the max garbage length we can signal using 8 bits. */ if((instISAC->bandwidthKHz == isac8kHz) || (streamLenUB == 0)) { ptrGarbage = &ptrEncodedUW8[streamLenLB]; limit = streamLen + 255; } else { ptrGarbage = &ptrEncodedUW8[streamLenLB + 1 + streamLenUB]; limit = streamLen + (255 - ptrEncodedUW8[streamLenLB]); } minBytes = (minBytes > limit)? limit:minBytes; garbageLen = (minBytes > streamLen)? (minBytes - streamLen):0; /* Save data for creation of multiple bitstreams */ //ISACencLB_obj->SaveEnc_obj.minBytes = MinBytes; /* if bitstream is too short, add garbage at the end */ if(garbageLen > 0) { for(k = 0; k < garbageLen; k++) { ptrGarbage[k] = (WebRtc_UWord8)(rand() & 0xFF); } // for a correct length of the upper-band bit-stream together // with the garbage. Garbage is embeded in upper-band bit-stream. // That is the only way to preserve backward compatibility. if((instISAC->bandwidthKHz == isac8kHz) || (streamLenUB == 0)) { ptrEncodedUW8[streamLenLB] = (WebRtc_UWord8)garbageLen; } else { ptrEncodedUW8[streamLenLB] += (WebRtc_UWord8)garbageLen; // write the length of the garbage at the end of the upper-band // bit-stream, if exists. This helps for sanity check. ptrEncodedUW8[streamLenLB + 1 + streamLenUB] = (WebRtc_UWord8)garbageLen; } streamLen += garbageLen; } } else { /* update rate model */ WebRtcIsac_UpdateRateModel(&instISAC->rate_data_obj, streamLen, instISAC->instLB.ISACencLB_obj.current_framesamples, bottleneck); garbageLen = 0; } // Generate CRC if required. if((instISAC->bandwidthKHz != isac8kHz) && (streamLenUB > 0)) { WebRtc_UWord32 crc; WebRtcIsac_GetCrc((WebRtc_Word16*)(&(ptrEncodedUW8[streamLenLB + 1])), streamLenUB + garbageLen, &crc); #ifndef WEBRTC_BIG_ENDIAN for(k = 0; k < LEN_CHECK_SUM_WORD8; k++) { ptrEncodedUW8[streamLen - LEN_CHECK_SUM_WORD8 + k] = (WebRtc_UWord8)((crc >> (24 - k * 8)) & 0xFF); } #else memcpy(&ptrEncodedUW8[streamLenLB + streamLenUB + 1], &crc, LEN_CHECK_SUM_WORD8); #endif } return streamLen; } /****************************************************************************** * WebRtcIsac_GetNewBitStream(...) * * This function returns encoded data, with the recieved bwe-index in the * stream. If the rate is set to a value less than bottleneck of codec * the new bistream will be re-encoded with the given target rate. * It should always return a complete packet, i.e. only called once * even for 60 msec frames. * * NOTE 1! This function does not write in the ISACStruct, it is not allowed. * NOTE 3! Rates larger than the bottleneck of the codec will be limited * to the current bottleneck. * * Input: * - ISAC_main_inst : ISAC instance. * - bweIndex : Index of bandwidth estimate to put in new * bitstream * - rate : target rate of the transcoder is bits/sec. * Valid values are the accepted rate in iSAC, * i.e. 10000 to 56000. * * Output: * - encoded : The encoded data vector * * Return value : >0 - Length (in bytes) of coded data * -1 - Error or called in SWB mode * NOTE! No error code is written to * the struct since it is only allowed to read * the struct. */ WebRtc_Word16 WebRtcIsac_GetNewBitStream( ISACStruct* ISAC_main_inst, WebRtc_Word16 bweIndex, WebRtc_Word16 jitterInfo, WebRtc_Word32 rate, WebRtc_Word16* encoded, WebRtc_Word16 isRCU) { Bitstr iSACBitStreamInst; /* Local struct for bitstream handling */ WebRtc_Word16 streamLenLB; WebRtc_Word16 streamLenUB; WebRtc_Word16 totalStreamLen; double gain2; double gain1; float scale; enum ISACBandwidth bandwidthKHz; double rateLB; double rateUB; WebRtc_Word32 currentBN; ISACMainStruct* instISAC; WebRtc_UWord8* encodedPtrUW8 = (WebRtc_UWord8*)encoded; WebRtc_UWord32 crc; #ifndef WEBRTC_BIG_ENDIAN WebRtc_Word16 k; #endif instISAC = (ISACMainStruct*)ISAC_main_inst; if((instISAC->initFlag & BIT_MASK_ENC_INIT) != BIT_MASK_ENC_INIT) { return -1; } // Get the bottleneck of this iSAC and limit the // given rate to the current bottleneck. WebRtcIsac_GetUplinkBw(ISAC_main_inst, ¤tBN); if(rate > currentBN) { rate = currentBN; } if(WebRtcIsac_RateAllocation(rate, &rateLB, &rateUB, &bandwidthKHz) < 0) { return -1; } // Cannot transcode from 16 kHz to 12 kHz if((bandwidthKHz == isac12kHz) && (instISAC->bandwidthKHz == isac16kHz)) { return -1; } // These gains are in dB // gain for the given rate. gain1 = WebRtcIsac_GetSnr(rateLB, instISAC->instLB.ISACencLB_obj.current_framesamples); // gain of this iSAC gain2 = WebRtcIsac_GetSnr( instISAC->instLB.ISACencLB_obj.bottleneck, instISAC->instLB.ISACencLB_obj.current_framesamples); // scale is the ratio of two gains in normal domain. scale = (float)pow(10, (gain1 - gain2) / 20.0); // change the scale if this is a RCU bit-stream. scale = (isRCU)? (scale * RCU_TRANSCODING_SCALE):scale; streamLenLB = WebRtcIsac_EncodeStoredDataLb( &instISAC->instLB.ISACencLB_obj.SaveEnc_obj, &iSACBitStreamInst, bweIndex, scale); if(streamLenLB < 0) { return -1; } /* convert from bytes to WebRtc_Word16 */ memcpy(encoded, iSACBitStreamInst.stream, streamLenLB); if(bandwidthKHz == isac8kHz) { return streamLenLB; } totalStreamLen = streamLenLB; // super-wideband is always at 30ms. // These gains are in dB // gain for the given rate. gain1 = WebRtcIsac_GetSnr(rateUB, FRAMESAMPLES); // gain of this iSAC gain2 = WebRtcIsac_GetSnr( instISAC->instUB.ISACencUB_obj.bottleneck, FRAMESAMPLES); // scale is the ratio of two gains in normal domain. scale = (float)pow(10, (gain1 - gain2) / 20.0); // change the scale if this is a RCU bit-stream. scale = (isRCU)? (scale * RCU_TRANSCODING_SCALE_UB):scale; switch(instISAC->bandwidthKHz) { case isac12kHz: { streamLenUB = WebRtcIsac_EncodeStoredDataUb12( &(instISAC->instUB.ISACencUB_obj.SaveEnc_obj), &iSACBitStreamInst, jitterInfo, scale); break; } case isac16kHz: { streamLenUB = WebRtcIsac_EncodeStoredDataUb16( &(instISAC->instUB.ISACencUB_obj.SaveEnc_obj), &iSACBitStreamInst, jitterInfo, scale); break; } default: return -1; } if(streamLenUB < 0) { return -1; } if(streamLenUB + 1 + LEN_CHECK_SUM_WORD8 > 255) { return streamLenLB; } totalStreamLen = streamLenLB + streamLenUB + 1 + LEN_CHECK_SUM_WORD8; encodedPtrUW8[streamLenLB] = streamLenUB + 1 + LEN_CHECK_SUM_WORD8; memcpy(&encodedPtrUW8[streamLenLB+1], iSACBitStreamInst.stream, streamLenUB); WebRtcIsac_GetCrc((WebRtc_Word16*)(&(encodedPtrUW8[streamLenLB + 1])), streamLenUB, &crc); #ifndef WEBRTC_BIG_ENDIAN for(k = 0; k < LEN_CHECK_SUM_WORD8; k++) { encodedPtrUW8[totalStreamLen - LEN_CHECK_SUM_WORD8 + k] = (WebRtc_UWord8)((crc >> (24 - k * 8)) & 0xFF); } #else memcpy(&encodedPtrUW8[streamLenLB + streamLenUB + 1], &crc, LEN_CHECK_SUM_WORD8); #endif return totalStreamLen; } /**************************************************************************** * DecoderInitLb(...) - internal function for initialization of * Lower Band * DecoderInitUb(...) - internal function for initialization of * Upper Band * WebRtcIsac_DecoderInit(...) - API function * * This function initializes a ISAC instance prior to the decoder calls. * * Input: * - ISAC_main_inst : ISAC instance. * * Return value * : 0 - Ok * -1 - Error */ static WebRtc_Word16 DecoderInitLb( ISACLBStruct* instISAC) { int i; /* Init stream vector to zero */ for (i=0; iISACdecLB_obj.bitstr_obj.stream[i] = 0; } WebRtcIsac_InitMasking(&instISAC->ISACdecLB_obj.maskfiltstr_obj); WebRtcIsac_InitPostFilterbank( &instISAC->ISACdecLB_obj.postfiltbankstr_obj); WebRtcIsac_InitPitchFilter(&instISAC->ISACdecLB_obj.pitchfiltstr_obj); return (0); } static WebRtc_Word16 DecoderInitUb( ISACUBStruct* instISAC) { int i; /* Init stream vector to zero */ for (i = 0; i < STREAM_SIZE_MAX_60; i++) { instISAC->ISACdecUB_obj.bitstr_obj.stream[i] = 0; } WebRtcIsac_InitMasking(&instISAC->ISACdecUB_obj.maskfiltstr_obj); WebRtcIsac_InitPostFilterbank( &instISAC->ISACdecUB_obj.postfiltbankstr_obj); return (0); } WebRtc_Word16 WebRtcIsac_DecoderInit( ISACStruct *ISAC_main_inst) { ISACMainStruct* instISAC; instISAC = (ISACMainStruct*)ISAC_main_inst; if(DecoderInitLb(&instISAC->instLB) < 0) { return -1; } if(instISAC->decoderSamplingRateKHz == kIsacSuperWideband) { memset(instISAC->synthesisFBState1, 0, FB_STATE_SIZE_WORD32 * sizeof(WebRtc_Word32)); memset(instISAC->synthesisFBState2, 0, FB_STATE_SIZE_WORD32 * sizeof(WebRtc_Word32)); if(DecoderInitUb(&(instISAC->instUB)) < 0) { return -1; } } if((instISAC->initFlag & BIT_MASK_ENC_INIT) != BIT_MASK_ENC_INIT) { WebRtcIsac_InitBandwidthEstimator(&instISAC->bwestimator_obj, instISAC->encoderSamplingRateKHz, instISAC->decoderSamplingRateKHz); } instISAC->initFlag |= BIT_MASK_DEC_INIT; instISAC->resetFlag_8kHz = 0; return 0; } /**************************************************************************** * WebRtcIsac_UpdateBwEstimate(...) * * This function updates the estimate of the bandwidth. * * Input: * - ISAC_main_inst : ISAC instance. * - encoded : encoded ISAC frame(s). * - packet_size : size of the packet. * - rtp_seq_number : the RTP number of the packet. * - arr_ts : the arrival time of the packet (from NetEq) * in samples. * * Return value : 0 - Ok * -1 - Error */ WebRtc_Word16 WebRtcIsac_UpdateBwEstimate( ISACStruct* ISAC_main_inst, const WebRtc_UWord16* encoded, WebRtc_Word32 packet_size, WebRtc_UWord16 rtp_seq_number, WebRtc_UWord32 send_ts, WebRtc_UWord32 arr_ts) { ISACMainStruct *instISAC; Bitstr streamdata; #ifndef WEBRTC_BIG_ENDIAN int k; #endif WebRtc_Word16 err; /* typecast pointer to real structure */ instISAC = (ISACMainStruct *)ISAC_main_inst; /* check if decoder initiated */ if((instISAC->initFlag & BIT_MASK_DEC_INIT) != BIT_MASK_DEC_INIT) { instISAC->errorCode = ISAC_DECODER_NOT_INITIATED; return -1; } if(packet_size <= 0) { /* return error code if the packet length is null */ instISAC->errorCode = ISAC_EMPTY_PACKET; return -1; } streamdata.W_upper = 0xFFFFFFFF; streamdata.streamval = 0; streamdata.stream_index = 0; #ifndef WEBRTC_BIG_ENDIAN for(k = 0; k < 10; k++) { streamdata.stream[k] = (WebRtc_UWord8) ((encoded[k>>1] >> ((k&1) << 3)) & 0xFF); } #else memcpy(streamdata.stream, encoded, 10); #endif err = WebRtcIsac_EstimateBandwidth(&instISAC->bwestimator_obj, &streamdata, packet_size, rtp_seq_number, send_ts, arr_ts, instISAC->encoderSamplingRateKHz, instISAC->decoderSamplingRateKHz); if(err < 0) { /* return error code if something went wrong */ instISAC->errorCode = -err; return -1; } return 0; } static WebRtc_Word16 Decode( ISACStruct* ISAC_main_inst, const WebRtc_UWord16* encoded, WebRtc_Word16 lenEncodedBytes, WebRtc_Word16* decoded, WebRtc_Word16* speechType, WebRtc_Word16 isRCUPayload) { /* number of samples (480 or 960), output from decoder that were actually used in the encoder/decoder (determined on the fly) */ ISACMainStruct* instISAC; ISACUBDecStruct* decInstUB; ISACLBDecStruct* decInstLB; WebRtc_Word16 numSamplesLB; WebRtc_Word16 numSamplesUB; WebRtc_Word16 speechIdx; float outFrame[MAX_FRAMESAMPLES]; WebRtc_Word16 outFrameLB[MAX_FRAMESAMPLES]; WebRtc_Word16 outFrameUB[MAX_FRAMESAMPLES]; WebRtc_Word16 numDecodedBytesLB; WebRtc_Word16 numDecodedBytesUB; WebRtc_Word16 lenEncodedLBBytes; WebRtc_Word16 validChecksum = 1; WebRtc_Word16 k; WebRtc_UWord8* ptrEncodedUW8 = (WebRtc_UWord8*)encoded; WebRtc_UWord16 numLayer; WebRtc_Word16 totSizeBytes; WebRtc_Word16 err; instISAC = (ISACMainStruct*)ISAC_main_inst; decInstUB = &(instISAC->instUB.ISACdecUB_obj); decInstLB = &(instISAC->instLB.ISACdecLB_obj); /* check if decoder initiated */ if((instISAC->initFlag & BIT_MASK_DEC_INIT) != BIT_MASK_DEC_INIT) { instISAC->errorCode = ISAC_DECODER_NOT_INITIATED; return -1; } if(lenEncodedBytes <= 0) { /* return error code if the packet length is null */ instISAC->errorCode = ISAC_EMPTY_PACKET; return -1; } // the size of the rncoded lower-band is bounded by // STREAM_SIZE_MAX, // If a payload with the size larger than STREAM_SIZE_MAX // is received, it is not considered erroneous. lenEncodedLBBytes = (lenEncodedBytes > STREAM_SIZE_MAX) ? STREAM_SIZE_MAX:lenEncodedBytes; // Copy to lower-band bit-stream structure memcpy(instISAC->instLB.ISACdecLB_obj.bitstr_obj.stream, ptrEncodedUW8, lenEncodedLBBytes); // Regardless of that the current codec is setup to work in // wideband or super-wideband, the decoding of the lower-band // has to be performed. numDecodedBytesLB = WebRtcIsac_DecodeLb(outFrame, decInstLB, &numSamplesLB, isRCUPayload); // Check for error if((numDecodedBytesLB < 0) || (numDecodedBytesLB > lenEncodedLBBytes) || (numSamplesLB > MAX_FRAMESAMPLES)) { instISAC->errorCode = ISAC_LENGTH_MISMATCH; return -1; } // Error Check, we accept multi-layer bit-stream // This will limit number of iterations of the // while loop. Even withouut this the number of iterations // is limited. numLayer = 1; totSizeBytes = numDecodedBytesLB; while(totSizeBytes != lenEncodedBytes) { if((totSizeBytes > lenEncodedBytes) || (ptrEncodedUW8[totSizeBytes] == 0) || (numLayer > MAX_NUM_LAYERS)) { instISAC->errorCode = ISAC_LENGTH_MISMATCH; return -1; } totSizeBytes += ptrEncodedUW8[totSizeBytes]; numLayer++; } if(instISAC->decoderSamplingRateKHz == kIsacWideband) { for(k = 0; k < numSamplesLB; k++) { if(outFrame[k] > 32767) { decoded[k] = 32767; } else if(outFrame[k] < -32768) { decoded[k] = -32768; } else { decoded[k] = (WebRtc_Word16)WebRtcIsac_lrint(outFrame[k]); } } numSamplesUB = 0; } else { WebRtc_UWord32 crc; // We don't accept larger than 30ms (480 samples at lower-band) // frame-size. for(k = 0; k < numSamplesLB; k++) { if(outFrame[k] > 32767) { outFrameLB[k] = 32767; } else if(outFrame[k] < -32768) { outFrameLB[k] = -32768; } else { outFrameLB[k] = (WebRtc_Word16)WebRtcIsac_lrint(outFrame[k]); } } //numSamplesUB = numSamplesLB; // Check for possible error, and if upper-band stream exist. if(numDecodedBytesLB == lenEncodedBytes) { // Decoding was successful. No super-wideband bitstream // exists. numSamplesUB = numSamplesLB; memset(outFrameUB, 0, sizeof(WebRtc_Word16) * numSamplesUB); // Prepare for the potential increase of signal bandwidth instISAC->resetFlag_8kHz = 2; } else { // this includes the check sum and the bytes that stores the // length WebRtc_Word16 lenNextStream = ptrEncodedUW8[numDecodedBytesLB]; // Is this garbage or valid super-wideband bit-stream? // Check if checksum is valid if(lenNextStream <= (LEN_CHECK_SUM_WORD8 + 1)) { // such a small second layer cannot be super-wideband layer. // It must be a short garbage. validChecksum = 0; } else { // Run CRC to see if the checksum match. WebRtcIsac_GetCrc((WebRtc_Word16*)( &ptrEncodedUW8[numDecodedBytesLB + 1]), lenNextStream - LEN_CHECK_SUM_WORD8 - 1, &crc); validChecksum = 1; for(k = 0; k < LEN_CHECK_SUM_WORD8; k++) { validChecksum &= (((crc >> (24 - k * 8)) & 0xFF) == ptrEncodedUW8[numDecodedBytesLB + lenNextStream - LEN_CHECK_SUM_WORD8 + k]); } } if(!validChecksum) { // this is a garbage, we have received a wideband // bit-stream with garbage numSamplesUB = numSamplesLB; memset(outFrameUB, 0, sizeof(WebRtc_Word16) * numSamplesUB); } else { // A valid super-wideband biststream exists. enum ISACBandwidth bandwidthKHz; WebRtc_Word32 maxDelayBit; //instISAC->bwestimator_obj.incomingStreamSampFreq = // kIsacSuperWideband; // If we have super-wideband bit-stream, we cannot // have 60 ms frame-size. if(numSamplesLB > FRAMESAMPLES) { instISAC->errorCode = ISAC_LENGTH_MISMATCH; return -1; } // the rest of the bit-stream contains the upper-band // bit-stream curently this is the only thing there, // however, we might add more layers. // Have to exclude one byte where the length is stored // and last 'LEN_CHECK_SUM_WORD8' bytes where the // checksum is stored. lenNextStream -= (LEN_CHECK_SUM_WORD8 + 1); memcpy(decInstUB->bitstr_obj.stream, &ptrEncodedUW8[numDecodedBytesLB + 1], lenNextStream); // THIS IS THE FIRST DECODING decInstUB->bitstr_obj.W_upper = 0xFFFFFFFF; decInstUB->bitstr_obj.streamval = 0; decInstUB->bitstr_obj.stream_index = 0; // Decode jitter infotmation err = WebRtcIsac_DecodeJitterInfo(&decInstUB->bitstr_obj, &maxDelayBit); // error check if(err < 0) { instISAC->errorCode = -err; return -1; } // Update jitter info which is in the upper-band bit-stream // only if the encoder is in super-wideband. Otherwise, // the jitter info is already embeded in bandwidth index // and has been updated. if(instISAC->encoderSamplingRateKHz == kIsacSuperWideband) { err = WebRtcIsac_UpdateUplinkJitter( &(instISAC->bwestimator_obj), maxDelayBit); if(err < 0) { instISAC->errorCode = -err; return -1; } } // decode bandwidth information err = WebRtcIsac_DecodeBandwidth(&decInstUB->bitstr_obj, &bandwidthKHz); if(err < 0) { instISAC->errorCode = -err; return -1; } switch(bandwidthKHz) { case isac12kHz: { numDecodedBytesUB = WebRtcIsac_DecodeUb12(outFrame, decInstUB, isRCUPayload); // Hang-over for transient alleviation - // wait two frames to add the upper band going up from 8 kHz if (instISAC->resetFlag_8kHz > 0) { if (instISAC->resetFlag_8kHz == 2) { // Silence first and a half frame memset(outFrame, 0, MAX_FRAMESAMPLES * sizeof(float)); } else { const float rampStep = 2.0f / MAX_FRAMESAMPLES; float rampVal = 0; memset(outFrame, 0, (MAX_FRAMESAMPLES>>1) * sizeof(float)); // Ramp up second half of second frame for(k = MAX_FRAMESAMPLES/2; k < MAX_FRAMESAMPLES; k++) { outFrame[k] *= rampVal; rampVal += rampStep; } } instISAC->resetFlag_8kHz -= 1; } break; } case isac16kHz: { numDecodedBytesUB = WebRtcIsac_DecodeUb16(outFrame, decInstUB, isRCUPayload); break; } default: return -1; } // it might be less due to garbage. if((numDecodedBytesUB != lenNextStream) && (numDecodedBytesUB != (lenNextStream - ptrEncodedUW8[ numDecodedBytesLB + 1 + numDecodedBytesUB]))) { instISAC->errorCode = ISAC_LENGTH_MISMATCH; return -1; } // If there is no error Upper-band always decodes // 30 ms (480 samples) numSamplesUB = FRAMESAMPLES; // Convert to W16 for(k = 0; k < numSamplesUB; k++) { if(outFrame[k] > 32767) { outFrameUB[k] = 32767; } else if(outFrame[k] < -32768) { outFrameUB[k] = -32768; } else { outFrameUB[k] = (WebRtc_Word16)WebRtcIsac_lrint( outFrame[k]); } } } } speechIdx = 0; while(speechIdx < numSamplesLB) { WebRtcSpl_SynthesisQMF(&outFrameLB[speechIdx], &outFrameUB[speechIdx], &decoded[(speechIdx<<1)], instISAC->synthesisFBState1, instISAC->synthesisFBState2); speechIdx += FRAMESAMPLES_10ms; } } *speechType = 0; return (numSamplesLB + numSamplesUB); } /**************************************************************************** * WebRtcIsac_Decode(...) * * This function decodes a ISAC frame. Output speech length * will be a multiple of 480 samples: 480 or 960 samples, * depending on the frameSize (30 or 60 ms). * * Input: * - ISAC_main_inst : ISAC instance. * - encoded : encoded ISAC frame(s) * - len : bytes in encoded vector * * Output: * - decoded : The decoded vector * * Return value : >0 - number of samples in decoded vector * -1 - Error */ WebRtc_Word16 WebRtcIsac_Decode( ISACStruct* ISAC_main_inst, const WebRtc_UWord16* encoded, WebRtc_Word16 lenEncodedBytes, WebRtc_Word16* decoded, WebRtc_Word16* speechType) { WebRtc_Word16 isRCUPayload = 0; return Decode(ISAC_main_inst, encoded, lenEncodedBytes, decoded, speechType, isRCUPayload); } /**************************************************************************** * WebRtcIsac_DecodeRcu(...) * * This function decodes a redundant (RCU) iSAC frame. Function is called in * NetEq with a stored RCU payload i case of packet loss. Output speech length * will be a multiple of 480 samples: 480 or 960 samples, * depending on the framesize (30 or 60 ms). * * Input: * - ISAC_main_inst : ISAC instance. * - encoded : encoded ISAC RCU frame(s) * - len : bytes in encoded vector * * Output: * - decoded : The decoded vector * * Return value : >0 - number of samples in decoded vector * -1 - Error */ WebRtc_Word16 WebRtcIsac_DecodeRcu( ISACStruct* ISAC_main_inst, const WebRtc_UWord16* encoded, WebRtc_Word16 lenEncodedBytes, WebRtc_Word16* decoded, WebRtc_Word16* speechType) { WebRtc_Word16 isRCUPayload = 1; return Decode(ISAC_main_inst, encoded, lenEncodedBytes, decoded, speechType, isRCUPayload); } /**************************************************************************** * WebRtcIsac_DecodePlc(...) * * This function conducts PLC for ISAC frame(s). Output speech length * will be a multiple of 480 samples: 480 or 960 samples, * depending on the frameSize (30 or 60 ms). * * Input: * - ISAC_main_inst : ISAC instance. * - noOfLostFrames : Number of PLC frames to produce * * Output: * - decoded : The decoded vector * * Return value : >0 - number of samples in decoded PLC vector * -1 - Error */ WebRtc_Word16 WebRtcIsac_DecodePlc( ISACStruct* ISAC_main_inst, WebRtc_Word16* decoded, WebRtc_Word16 noOfLostFrames) { WebRtc_Word16 numSamples; ISACMainStruct* instISAC; /* typecast pointer to real structure */ instISAC = (ISACMainStruct*)ISAC_main_inst; /* Limit number of frames to two = 60 msec. Otherwise we exceed data vectors */ if(noOfLostFrames > 2) { noOfLostFrames = 2; } /* Get the number of samples per frame */ switch(instISAC->decoderSamplingRateKHz) { case kIsacWideband: { numSamples = 480 * noOfLostFrames; break; } case kIsacSuperWideband: { numSamples = 960 * noOfLostFrames; break; } default: return -1; } /* Set output samples to zero */ memset(decoded, 0, numSamples * sizeof(WebRtc_Word16)); return numSamples; } /**************************************************************************** * ControlLb(...) - Internal function for controling Lower Band * ControlUb(...) - Internal function for controling Upper Band * WebRtcIsac_Control(...) - API function * * This function sets the limit on the short-term average bit rate and the * frame length. Should be used only in Instantaneous mode. * * Input: * - ISAC_main_inst : ISAC instance. * - rate : limit on the short-term average bit rate, * in bits/second (between 10000 and 32000) * - frameSize : number of milliseconds per frame (30 or 60) * * Return value : 0 - ok * -1 - Error */ static WebRtc_Word16 ControlLb( ISACLBStruct* instISAC, double rate, WebRtc_Word16 frameSize) { if((rate >= 10000) && (rate <= 32000)) { instISAC->ISACencLB_obj.bottleneck = rate; } else { return -ISAC_DISALLOWED_BOTTLENECK; } if((frameSize == 30) || (frameSize == 60)) { instISAC->ISACencLB_obj.new_framelength = (FS/1000) * frameSize; } else { return -ISAC_DISALLOWED_FRAME_LENGTH; } return 0; } static WebRtc_Word16 ControlUb( ISACUBStruct* instISAC, double rate) { if((rate >= 10000) && (rate <= 32000)) { instISAC->ISACencUB_obj.bottleneck = rate; } else { return -ISAC_DISALLOWED_BOTTLENECK; } return 0; } WebRtc_Word16 WebRtcIsac_Control( ISACStruct* ISAC_main_inst, WebRtc_Word32 bottleneckBPS, WebRtc_Word16 frameSize) { ISACMainStruct *instISAC; WebRtc_Word16 status; double rateLB; double rateUB; enum ISACBandwidth bandwidthKHz; /* Typecast pointer to real structure */ instISAC = (ISACMainStruct*)ISAC_main_inst; if(instISAC->codingMode == 0) { /* in adaptive mode */ instISAC->errorCode = ISAC_MODE_MISMATCH; return -1; } /* check if encoder initiated */ if((instISAC->initFlag & BIT_MASK_ENC_INIT) != BIT_MASK_ENC_INIT) { instISAC->errorCode = ISAC_ENCODER_NOT_INITIATED; return -1; } if(instISAC->encoderSamplingRateKHz == kIsacWideband) { // if the sampling rate is 16kHz then bandwith should be 8kHz, // regardless of bottleneck. bandwidthKHz = isac8kHz; rateLB = (bottleneckBPS > 32000)? 32000:bottleneckBPS; rateUB = 0; } else { if(WebRtcIsac_RateAllocation(bottleneckBPS, &rateLB, &rateUB, &bandwidthKHz) < 0) { return -1; } } if((instISAC->encoderSamplingRateKHz == kIsacSuperWideband) && (frameSize != 30) && (bandwidthKHz != isac8kHz)) { // Cannot have 60 ms in super-wideband instISAC->errorCode = ISAC_DISALLOWED_FRAME_LENGTH; return -1; } status = ControlLb(&instISAC->instLB, rateLB, frameSize); if(status < 0) { instISAC->errorCode = -status; return -1; } if(bandwidthKHz != isac8kHz) { status = ControlUb(&(instISAC->instUB), rateUB); if(status < 0) { instISAC->errorCode = -status; return -1; } } // // Check if bandwidth is changing from wideband to super-wideband // then we have to synch data buffer of lower & upper-band. also // clean up the upper-band data buffer. // if((instISAC->bandwidthKHz == isac8kHz) && (bandwidthKHz != isac8kHz)) { memset(instISAC->instUB.ISACencUB_obj.data_buffer_float, 0, sizeof(float) * (MAX_FRAMESAMPLES + LB_TOTAL_DELAY_SAMPLES)); if(bandwidthKHz == isac12kHz) { instISAC->instUB.ISACencUB_obj.buffer_index = instISAC->instLB.ISACencLB_obj.buffer_index; } else { instISAC->instUB.ISACencUB_obj.buffer_index = LB_TOTAL_DELAY_SAMPLES + instISAC->instLB.ISACencLB_obj.buffer_index; memcpy(&(instISAC->instUB.ISACencUB_obj.lastLPCVec), WebRtcIsac_kMeanLarUb16, sizeof(double) * UB_LPC_ORDER); } } // update the payload limit it the bandwidth is changing. if(instISAC->bandwidthKHz != bandwidthKHz) { instISAC->bandwidthKHz = bandwidthKHz; UpdatePayloadSizeLimit(instISAC); } instISAC->bottleneck = bottleneckBPS; return 0; } /**************************************************************************** * WebRtcIsac_ControlBwe(...) * * This function sets the initial values of bottleneck and frame-size if * iSAC is used in channel-adaptive mode. Through this API, users can * enforce a frame-size for all values of bottleneck. Then iSAC will not * automatically change the frame-size. * * * Input: * - ISAC_main_inst : ISAC instance. * - rateBPS : initial value of bottleneck in bits/second * 10000 <= rateBPS <= 32000 is accepted * For default bottleneck set rateBPS = 0 * - frameSizeMs : number of milliseconds per frame (30 or 60) * - enforceFrameSize : 1 to enforce the given frame-size through out * the adaptation process, 0 to let iSAC change * the frame-size if required. * * Return value : 0 - ok * -1 - Error */ WebRtc_Word16 WebRtcIsac_ControlBwe( ISACStruct* ISAC_main_inst, WebRtc_Word32 bottleneckBPS, WebRtc_Word16 frameSizeMs, WebRtc_Word16 enforceFrameSize) { ISACMainStruct *instISAC; enum ISACBandwidth bandwidth; /* Typecast pointer to real structure */ instISAC = (ISACMainStruct *)ISAC_main_inst; /* check if encoder initiated */ if((instISAC->initFlag & BIT_MASK_ENC_INIT) != BIT_MASK_ENC_INIT) { instISAC->errorCode = ISAC_ENCODER_NOT_INITIATED; return -1; } /* Check that we are in channel-adaptive mode, otherwise, return (-1) */ if(instISAC->codingMode != 0) { instISAC->errorCode = ISAC_MODE_MISMATCH; return -1; } if((frameSizeMs != 30) && (instISAC->encoderSamplingRateKHz == kIsacSuperWideband)) { return -1; } /* Set struct variable if enforceFrameSize is set. ISAC will then */ /* keep the chosen frame size. */ if((enforceFrameSize != 0) /*|| (instISAC->samplingRateKHz == kIsacSuperWideband)*/) { instISAC->instLB.ISACencLB_obj.enforceFrameSize = 1; } else { instISAC->instLB.ISACencLB_obj.enforceFrameSize = 0; } /* Set initial rate, if value between 10000 and 32000, */ /* if rateBPS is 0, keep the default initial bottleneck value (15000) */ if(bottleneckBPS != 0) { double rateLB; double rateUB; if(WebRtcIsac_RateAllocation(bottleneckBPS, &rateLB, &rateUB, &bandwidth) < 0) { return -1; } instISAC->bwestimator_obj.send_bw_avg = (float)bottleneckBPS; instISAC->bandwidthKHz = bandwidth; } /* Set initial frameSize. If enforceFrameSize is set the frame size will not change */ if(frameSizeMs != 0) { if((frameSizeMs == 30) || (frameSizeMs == 60)) { instISAC->instLB.ISACencLB_obj.new_framelength = (FS/1000) * frameSizeMs; //instISAC->bwestimator_obj.rec_header_rate = ((float)HEADER_SIZE * // 8.0f * 1000.0f / (float)frameSizeMs); } else { instISAC->errorCode = ISAC_DISALLOWED_FRAME_LENGTH; return -1; } } return 0; } /**************************************************************************** * WebRtcIsac_GetDownLinkBwIndex(...) * * This function returns index representing the Bandwidth estimate from * other side to this side. * * Input: * - ISAC_main_inst : iSAC struct * * Output: * - bweIndex : Bandwidth estimate to transmit to other side. * */ WebRtc_Word16 WebRtcIsac_GetDownLinkBwIndex( ISACStruct* ISAC_main_inst, WebRtc_Word16* bweIndex, WebRtc_Word16* jitterInfo) { ISACMainStruct *instISAC; /* typecast pointer to real structure */ instISAC = (ISACMainStruct*)ISAC_main_inst; /* check if encoder initiated */ if((instISAC->initFlag & BIT_MASK_DEC_INIT) != BIT_MASK_DEC_INIT) { instISAC->errorCode = ISAC_ENCODER_NOT_INITIATED; return -1; } /* Call function to get Bandwidth Estimate */ WebRtcIsac_GetDownlinkBwJitIndexImpl(&(instISAC->bwestimator_obj), bweIndex, jitterInfo, instISAC->decoderSamplingRateKHz); return 0; } /**************************************************************************** * WebRtcIsac_UpdateUplinkBw(...) * * This function takes an index representing the Bandwidth estimate from * this side to other side and updates BWE. * * Input: * - ISAC_main_inst : iSAC struct * - rateIndex : Bandwidth estimate from other side. * * Return value : 0 - ok * -1 - index out of range */ WebRtc_Word16 WebRtcIsac_UpdateUplinkBw( ISACStruct* ISAC_main_inst, WebRtc_Word16 bweIndex) { ISACMainStruct *instISAC; WebRtc_Word16 returnVal; /* typecast pointer to real structure */ instISAC = (ISACMainStruct *)ISAC_main_inst; /* check if encoder initiated */ if((instISAC->initFlag & BIT_MASK_ENC_INIT) != BIT_MASK_ENC_INIT) { instISAC->errorCode = ISAC_ENCODER_NOT_INITIATED; return -1; } /* Call function to get Bandwidth Estimate */ returnVal = WebRtcIsac_UpdateUplinkBwImpl( &(instISAC->bwestimator_obj), bweIndex, instISAC->encoderSamplingRateKHz); if(returnVal < 0) { instISAC->errorCode = -returnVal; return -1; } else { return 0; } } /**************************************************************************** * WebRtcIsac_ReadBwIndex(...) * * This function returns the index of the Bandwidth estimate from the * bitstream. * * Input: * - encoded : Encoded bitstream * * Output: * - frameLength : Length of frame in packet (in samples) * - bweIndex : Bandwidth estimate in bitstream * */ WebRtc_Word16 WebRtcIsac_ReadBwIndex( const WebRtc_Word16* encoded, WebRtc_Word16* bweIndex) { Bitstr streamdata; #ifndef WEBRTC_BIG_ENDIAN int k; #endif WebRtc_Word16 err; streamdata.W_upper = 0xFFFFFFFF; streamdata.streamval = 0; streamdata.stream_index = 0; #ifndef WEBRTC_BIG_ENDIAN for(k = 0; k < 10; k++) { streamdata.stream[k] = (WebRtc_UWord8) ((encoded[k>>1] >> ((k&1) << 3)) & 0xFF); } #else memcpy(streamdata.stream, encoded, 10); #endif /* decode frame length */ err = WebRtcIsac_DecodeFrameLen(&streamdata, bweIndex); if(err < 0) { return err; } /* decode BW estimation */ err = WebRtcIsac_DecodeSendBW(&streamdata, bweIndex); if(err < 0) { return err; } return 0; } /**************************************************************************** * WebRtcIsac_ReadFrameLen(...) * * This function returns the length of the frame represented in the packet. * * Input: * - encoded : Encoded bitstream * * Output: * - frameLength : Length of frame in packet (in samples) * */ WebRtc_Word16 WebRtcIsac_ReadFrameLen( ISACStruct* ISAC_main_inst, const WebRtc_Word16* encoded, WebRtc_Word16* frameLength) { Bitstr streamdata; #ifndef WEBRTC_BIG_ENDIAN int k; #endif WebRtc_Word16 err; ISACMainStruct* instISAC; streamdata.W_upper = 0xFFFFFFFF; streamdata.streamval = 0; streamdata.stream_index = 0; #ifndef WEBRTC_BIG_ENDIAN for (k=0; k<10; k++) { streamdata.stream[k] = (WebRtc_UWord8) ((encoded[k>>1] >> ((k&1) << 3)) & 0xFF); } #else memcpy(streamdata.stream, encoded, 10); #endif /* decode frame length */ err = WebRtcIsac_DecodeFrameLen(&streamdata, frameLength); if(err < 0) { return -1; } instISAC = (ISACMainStruct*)ISAC_main_inst; if(instISAC->decoderSamplingRateKHz == kIsacSuperWideband) { // the decoded frame length indicates the number of samples in // lower-band in this case, multiply by 2 to get the total number // of samples. *frameLength <<= 1; } return 0; } /******************************************************************************* * WebRtcIsac_GetNewFrameLen(...) * * returns the frame lenght (in samples) of the next packet. In the case of * channel-adaptive mode, iSAC decides on its frame lenght based on the * estimated bottleneck this allows a user to prepare for the next packet * (at the encoder). * * The primary usage is in CE to make the iSAC works in channel-adaptive mode * * Input: * - ISAC_main_inst : iSAC struct * * Return Value : frame lenght in samples * */ WebRtc_Word16 WebRtcIsac_GetNewFrameLen( ISACStruct *ISAC_main_inst) { ISACMainStruct *instISAC; /* typecast pointer to real structure */ instISAC = (ISACMainStruct *)ISAC_main_inst; /* Return new frame length */ if(instISAC->encoderSamplingRateKHz == kIsacWideband) { return (instISAC->instLB.ISACencLB_obj.new_framelength); } else { return ((instISAC->instLB.ISACencLB_obj.new_framelength) << 1); } } /**************************************************************************** * WebRtcIsac_GetErrorCode(...) * * This function can be used to check the error code of an iSAC instance. * When a function returns -1 a error code will be set for that instance. * The function below extract the code of the last error that occured in * the specified instance. * * Input: * - ISAC_main_inst : ISAC instance * * Return value : Error code */ WebRtc_Word16 WebRtcIsac_GetErrorCode( ISACStruct *ISAC_main_inst) { ISACMainStruct *instISAC; /* typecast pointer to real structure */ instISAC = (ISACMainStruct *)ISAC_main_inst; return (instISAC->errorCode); } /**************************************************************************** * WebRtcIsac_GetUplinkBw(...) * * This function outputs the target bottleneck of the codec. In * channel-adaptive mode, the target bottleneck is specified through in-band * signalling retreived by bandwidth estimator. * In channel-independent, also called instantaneous mode, the target * bottleneck is provided to the encoder by calling xxx_control(...) (if * xxx_control is never called the default values is). * Note that the output is the iSAC internal operating bottleneck whch might * differ slightly from the one provided through xxx_control(). * * Input: * - ISAC_main_inst : iSAC instance * * Output: * - *bottleneck : bottleneck in bits/sec * * Return value : -1 if error happens * 0 bit-rates computed correctly. */ WebRtc_Word16 WebRtcIsac_GetUplinkBw( ISACStruct* ISAC_main_inst, WebRtc_Word32* bottleneck) { ISACMainStruct* instISAC = (ISACMainStruct *)ISAC_main_inst; if(instISAC->codingMode == 0) { // we are in adaptive mode then get the bottleneck from BWE *bottleneck = (WebRtc_Word32)instISAC->bwestimator_obj.send_bw_avg; } else { *bottleneck = instISAC->bottleneck; } if((*bottleneck > 32000) && (*bottleneck < 38000)) { *bottleneck = 32000; } else if((*bottleneck > 45000) && (*bottleneck < 50000)) { *bottleneck = 45000; } else if(*bottleneck > 56000) { *bottleneck = 56000; } return 0; } /****************************************************************************** * WebRtcIsac_SetMaxPayloadSize(...) * * This function sets a limit for the maximum payload size of iSAC. The same * value is used both for 30 and 60 ms packets. If the encoder sampling rate * is 16 kHz the maximum payload size is between 120 and 400 bytes. If the * encoder sampling rate is 32 kHz the maximum payload size is between 120 * and 600 bytes. * * --------------- * IMPORTANT NOTES * --------------- * The size of a packet is limited to the minimum of 'max-payload-size' and * 'max-rate.' For instance, let's assume the max-payload-size is set to * 170 bytes, and max-rate is set to 40 kbps. Note that a limit of 40 kbps * translates to 150 bytes for 30ms frame-size & 300 bytes for 60ms * frame-size. Then a packet with a frame-size of 30 ms is limited to 150, * i.e. min(170, 150), and a packet with 60 ms frame-size is limited to * 170 bytes, i.e. min(170, 300). * * Input: * - ISAC_main_inst : iSAC instance * - maxPayloadBytes : maximum size of the payload in bytes * valid values are between 100 and 400 bytes * if encoder sampling rate is 16 kHz. For * 32 kHz encoder sampling rate valid values * are between 100 and 600 bytes. * * Return value : 0 if successful * -1 if error happens */ WebRtc_Word16 WebRtcIsac_SetMaxPayloadSize( ISACStruct* ISAC_main_inst, WebRtc_Word16 maxPayloadBytes) { ISACMainStruct *instISAC; WebRtc_Word16 status = 0; /* typecast pointer to real structure */ instISAC = (ISACMainStruct *)ISAC_main_inst; /* check if encoder initiated */ if((instISAC->initFlag & BIT_MASK_ENC_INIT) != BIT_MASK_ENC_INIT) { instISAC->errorCode = ISAC_ENCODER_NOT_INITIATED; return -1; } if(instISAC->encoderSamplingRateKHz == kIsacSuperWideband) { // sanity check if(maxPayloadBytes < 120) { // maxRate is out of valid range // set to the acceptable value and return -1. maxPayloadBytes = 120; status = -1; } /* sanity check */ if(maxPayloadBytes > STREAM_SIZE_MAX) { // maxRate is out of valid range // set to the acceptable value and return -1. maxPayloadBytes = STREAM_SIZE_MAX; status = -1; } } else { if(maxPayloadBytes < 120) { // max payload-size is out of valid range // set to the acceptable value and return -1. maxPayloadBytes = 120; status = -1; } if(maxPayloadBytes > STREAM_SIZE_MAX_60) { // max payload-size is out of valid range // set to the acceptable value and return -1. maxPayloadBytes = STREAM_SIZE_MAX_60; status = -1; } } instISAC->maxPayloadSizeBytes = maxPayloadBytes; UpdatePayloadSizeLimit(instISAC); return status; } /****************************************************************************** * WebRtcIsac_SetMaxRate(...) * * This function sets the maximum rate which the codec may not exceed for * any signal packet. The maximum rate is defined and payload-size per * frame-size in bits per second. * * The codec has a maximum rate of 53400 bits per second (200 bytes per 30 * ms) if the encoder sampling rate is 16kHz, and 160 kbps (600 bytes/30 ms) * if the encoder sampling rate is 32 kHz. * * It is possible to set a maximum rate between 32000 and 53400 bits/sec * in wideband mode, and 32000 to 160000 bits/sec in super-wideband mode. * * --------------- * IMPORTANT NOTES * --------------- * The size of a packet is limited to the minimum of 'max-payload-size' and * 'max-rate.' For instance, let's assume the max-payload-size is set to * 170 bytes, and max-rate is set to 40 kbps. Note that a limit of 40 kbps * translates to 150 bytes for 30ms frame-size & 300 bytes for 60ms * frame-size. Then a packet with a frame-size of 30 ms is limited to 150, * i.e. min(170, 150), and a packet with 60 ms frame-size is limited to * 170 bytes, min(170, 300). * * Input: * - ISAC_main_inst : iSAC instance * - maxRate : maximum rate in bits per second, * valid values are 32000 to 53400 bits/sec in * wideband mode, and 32000 to 160000 bits/sec in * super-wideband mode. * * Return value : 0 if successful * -1 if error happens */ WebRtc_Word16 WebRtcIsac_SetMaxRate( ISACStruct* ISAC_main_inst, WebRtc_Word32 maxRate) { ISACMainStruct *instISAC; WebRtc_Word16 maxRateInBytesPer30Ms; WebRtc_Word16 status = 0; /* typecast pointer to real structure */ instISAC = (ISACMainStruct *)ISAC_main_inst; /* check if encoder initiated */ if((instISAC->initFlag & BIT_MASK_ENC_INIT) != BIT_MASK_ENC_INIT) { instISAC->errorCode = ISAC_ENCODER_NOT_INITIATED; return -1; } /* Calculate maximum number of bytes per 30 msec packets for the given maximum rate. Multiply with 30/1000 to get number of bits per 30 ms, divide by 8 to get number of bytes per 30 ms: maxRateInBytes = floor((maxRate * 30/1000) / 8); */ maxRateInBytesPer30Ms = (WebRtc_Word16)(maxRate*3/800); if(instISAC->encoderSamplingRateKHz == kIsacWideband) { if(maxRate < 32000) { // max rate is out of valid range // set to the acceptable value and return -1. maxRateInBytesPer30Ms = 120; status = -1; } if(maxRate > 53400) { // max rate is out of valid range // set to the acceptable value and return -1. maxRateInBytesPer30Ms = 200; status = -1; } } else { if(maxRateInBytesPer30Ms < 120) { // maxRate is out of valid range // set to the acceptable value and return -1. maxRateInBytesPer30Ms = 120; status = -1; } if(maxRateInBytesPer30Ms > STREAM_SIZE_MAX) { // maxRate is out of valid range // set to the acceptable value and return -1. maxRateInBytesPer30Ms = STREAM_SIZE_MAX; status = -1; } } instISAC->maxRateBytesPer30Ms = maxRateInBytesPer30Ms; UpdatePayloadSizeLimit(instISAC); return status; } /**************************************************************************** * WebRtcIsac_GetRedPayload(...) * * Populates "encoded" with the redundant payload of the recently encoded * frame. This function has to be called once that WebRtcIsac_Encode(...) * returns a positive value. Regardless of the frame-size this function will * be called only once after encoding is completed. The bit-stream is * targeted for 16000 bit/sec. * * Input: * - ISAC_main_inst : iSAC struct * * Output: * - encoded : the encoded data vector * * * Return value : >0 - Length (in bytes) of coded data * : -1 - Error * * */ WebRtc_Word16 WebRtcIsac_GetRedPayload( ISACStruct* ISAC_main_inst, WebRtc_Word16* encoded) { ISACMainStruct* instISAC; Bitstr iSACBitStreamInst; WebRtc_Word16 streamLenLB; WebRtc_Word16 streamLenUB; WebRtc_Word16 streamLen; WebRtc_Word16 totalLenUB; WebRtc_UWord8* ptrEncodedUW8 = (WebRtc_UWord8*)encoded; #ifndef WEBRTC_BIG_ENDIAN int k; #endif /* typecast pointer to real structure */ instISAC = (ISACMainStruct*)ISAC_main_inst; if((instISAC->initFlag & BIT_MASK_ENC_INIT) != BIT_MASK_ENC_INIT) { instISAC->errorCode = ISAC_ENCODER_NOT_INITIATED; } iSACBitStreamInst.W_upper = 0xFFFFFFFF; iSACBitStreamInst.streamval = 0; iSACBitStreamInst.stream_index = 0; streamLenLB = WebRtcIsac_EncodeStoredDataLb( &instISAC->instLB.ISACencLB_obj.SaveEnc_obj, &iSACBitStreamInst, instISAC->instLB.ISACencLB_obj.lastBWIdx, RCU_TRANSCODING_SCALE); if(streamLenLB < 0) { return -1; } /* convert from bytes to WebRtc_Word16 */ memcpy(ptrEncodedUW8, iSACBitStreamInst.stream, streamLenLB); streamLen = streamLenLB; if(instISAC->bandwidthKHz == isac8kHz) { return streamLenLB; } streamLenUB = WebRtcIsac_GetRedPayloadUb( &instISAC->instUB.ISACencUB_obj.SaveEnc_obj, &iSACBitStreamInst, instISAC->bandwidthKHz); if(streamLenUB < 0) { // an error has happened but this is not the error due to a // bit-stream larger than the limit return -1; } // We have one byte to write the total length of the upper band // the length include the bitstream length, check-sum and the // single byte where the length is written to. This is according to // iSAC wideband and how the "garbage" is dealt. totalLenUB = streamLenUB + 1 + LEN_CHECK_SUM_WORD8; if(totalLenUB > 255) { streamLenUB = 0; } // Generate CRC if required. if((instISAC->bandwidthKHz != isac8kHz) && (streamLenUB > 0)) { WebRtc_UWord32 crc; streamLen += totalLenUB; ptrEncodedUW8[streamLenLB] = (WebRtc_UWord8)totalLenUB; memcpy(&ptrEncodedUW8[streamLenLB+1], iSACBitStreamInst.stream, streamLenUB); WebRtcIsac_GetCrc((WebRtc_Word16*)(&(ptrEncodedUW8[streamLenLB + 1])), streamLenUB, &crc); #ifndef WEBRTC_BIG_ENDIAN for(k = 0; k < LEN_CHECK_SUM_WORD8; k++) { ptrEncodedUW8[streamLen - LEN_CHECK_SUM_WORD8 + k] = (WebRtc_UWord8)((crc >> (24 - k * 8)) & 0xFF); } #else memcpy(&ptrEncodedUW8[streamLenLB + streamLenUB + 1], &crc, LEN_CHECK_SUM_WORD8); #endif } return streamLen; } /**************************************************************************** * WebRtcIsac_version(...) * * This function returns the version number. * * Output: * - version : Pointer to character string * */ void WebRtcIsac_version(char *version) { strcpy(version, "4.3.0"); } /****************************************************************************** * WebRtcIsac_SetEncSampRate() * Set the sampling rate of the encoder. Initialization of the encoder WILL * NOT overwrite the sampling rate of the encoder. The default value is 16 kHz * which is set when the instance is created. The encoding-mode and the * bottleneck remain unchanged by this call, however, the maximum rate and * maximum payload-size will reset to their default value. * * Input: * - ISAC_main_inst : iSAC instance * - sampRate : enumerator specifying the sampling rate. * * Return value : 0 if successful * -1 if failed. */ WebRtc_Word16 WebRtcIsac_SetEncSampRate( ISACStruct* ISAC_main_inst, enum IsacSamplingRate sampRate) { ISACMainStruct* instISAC; instISAC = (ISACMainStruct*)ISAC_main_inst; if((sampRate != kIsacWideband) && (sampRate != kIsacSuperWideband)) { // Sampling Frequency is not supported instISAC->errorCode = ISAC_UNSUPPORTED_SAMPLING_FREQUENCY; return -1; } else if((instISAC->initFlag & BIT_MASK_ENC_INIT) != BIT_MASK_ENC_INIT) { if(sampRate == kIsacWideband) { instISAC->bandwidthKHz = isac8kHz; } else { instISAC->bandwidthKHz = isac16kHz; } instISAC->encoderSamplingRateKHz = sampRate; return 0; } else { ISACUBStruct* instUB = &(instISAC->instUB); ISACLBStruct* instLB = &(instISAC->instLB); double bottleneckLB; double bottleneckUB; WebRtc_Word32 bottleneck = instISAC->bottleneck; WebRtc_Word16 codingMode = instISAC->codingMode; WebRtc_Word16 frameSizeMs = instLB->ISACencLB_obj.new_framelength / (FS / 1000); if((sampRate == kIsacWideband) && (instISAC->encoderSamplingRateKHz == kIsacSuperWideband)) { // changing from super-wideband to wideband. // we don't need to re-initialize the encoder of the // lower-band. instISAC->bandwidthKHz = isac8kHz; if(codingMode == 1) { ControlLb(instLB, (bottleneck > 32000)? 32000:bottleneck, FRAMESIZE); } instISAC->maxPayloadSizeBytes = STREAM_SIZE_MAX_60; instISAC->maxRateBytesPer30Ms = STREAM_SIZE_MAX_30; } else if((sampRate == kIsacSuperWideband) && (instISAC->encoderSamplingRateKHz == kIsacWideband)) { if(codingMode == 1) { WebRtcIsac_RateAllocation(bottleneck, &bottleneckLB, &bottleneckUB, &(instISAC->bandwidthKHz)); } instISAC->bandwidthKHz = isac16kHz; instISAC->maxPayloadSizeBytes = STREAM_SIZE_MAX; instISAC->maxRateBytesPer30Ms = STREAM_SIZE_MAX; EncoderInitLb(instLB, codingMode, sampRate); EncoderInitUb(instUB, instISAC->bandwidthKHz); memset(instISAC->analysisFBState1, 0, FB_STATE_SIZE_WORD32 * sizeof(WebRtc_Word32)); memset(instISAC->analysisFBState2, 0, FB_STATE_SIZE_WORD32 * sizeof(WebRtc_Word32)); if(codingMode == 1) { instISAC->bottleneck = bottleneck; ControlLb(instLB, bottleneckLB, (instISAC->bandwidthKHz == isac8kHz)? frameSizeMs:FRAMESIZE); if(instISAC->bandwidthKHz > isac8kHz) { ControlUb(instUB, bottleneckUB); } } else { instLB->ISACencLB_obj.enforceFrameSize = 0; instLB->ISACencLB_obj.new_framelength = FRAMESAMPLES; } } instISAC->encoderSamplingRateKHz = sampRate; return 0; } } /****************************************************************************** * WebRtcIsac_SetDecSampRate() * Set the sampling rate of the decoder. Initialization of the decoder WILL * NOT overwrite the sampling rate of the encoder. The default value is 16 kHz * which is set when the instance is created. * * Input: * - ISAC_main_inst : iSAC instance * - sampRate : enumerator specifying the sampling rate. * * Return value : 0 if successful * -1 if failed. */ WebRtc_Word16 WebRtcIsac_SetDecSampRate( ISACStruct* ISAC_main_inst, enum IsacSamplingRate sampRate) { ISACMainStruct* instISAC; instISAC = (ISACMainStruct*)ISAC_main_inst; if((sampRate != kIsacWideband) && (sampRate != kIsacSuperWideband)) { // Sampling Frequency is not supported instISAC->errorCode = ISAC_UNSUPPORTED_SAMPLING_FREQUENCY; return -1; } else { if((instISAC->decoderSamplingRateKHz == kIsacWideband) && (sampRate == kIsacSuperWideband)) { // switching from wideband to super-wideband at the decoder // we need to reset the filter-bank and initialize // upper-band decoder. memset(instISAC->synthesisFBState1, 0, FB_STATE_SIZE_WORD32 * sizeof(WebRtc_Word32)); memset(instISAC->synthesisFBState2, 0, FB_STATE_SIZE_WORD32 * sizeof(WebRtc_Word32)); if(DecoderInitUb(&(instISAC->instUB)) < 0) { return -1; } } instISAC->decoderSamplingRateKHz = sampRate; return 0; } } /****************************************************************************** * WebRtcIsac_EncSampRate() * * Input: * - ISAC_main_inst : iSAC instance * * Return value : enumerator representing sampling frequency * associated with the encoder, the input audio * is expected to be sampled at this rate. * */ enum IsacSamplingRate WebRtcIsac_EncSampRate( ISACStruct* ISAC_main_inst) { ISACMainStruct* instISAC; instISAC = (ISACMainStruct*)ISAC_main_inst; return instISAC->encoderSamplingRateKHz; } /****************************************************************************** * WebRtcIsac_DecSampRate() * Return the sampling rate of the decoded audio. * * Input: * - ISAC_main_inst : iSAC instance * * Return value : enumerator representing sampling frequency * associated with the decoder, i.e. the * sampling rate of the decoded audio. * */ enum IsacSamplingRate WebRtcIsac_DecSampRate( ISACStruct* ISAC_main_inst) { ISACMainStruct* instISAC; instISAC = (ISACMainStruct*)ISAC_main_inst; return instISAC->decoderSamplingRateKHz; }