| /* |
| * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. |
| * |
| * Use of this source code is governed by a BSD-style license |
| * that can be found in the LICENSE file in the root of the source |
| * tree. An additional intellectual property rights grant can be found |
| * in the file PATENTS. All contributing project authors may |
| * be found in the AUTHORS file in the root of the source tree. |
| */ |
| |
| /* |
| * 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 <stdio.h> |
| #include <string.h> |
| #include <stdlib.h> |
| #include <math.h> |
| |
| #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 = 0; |
| WebRtc_Word16 streamLenUB = 0; |
| WebRtc_Word16 streamLen = 0; |
| WebRtc_Word16 k = 0; |
| WebRtc_UWord8* ptrEncodedUW8 = (WebRtc_UWord8*)encoded; |
| int garbageLen = 0; |
| WebRtc_Word32 bottleneck = 0; |
| 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; |
| } |
| } |
| |
| 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; i<STREAM_SIZE_MAX_60; i++) |
| { |
| instISAC->ISACdecLB_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 = 0; |
| 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; |
| } |
| } |
| |
| /* 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; |
| } |