| /* | |
| * 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 "modules/audio_coding/codecs/isac/main/include/isac.h" | |
| #include <math.h> | |
| #include <stdio.h> | |
| #include <stdlib.h> | |
| #include <string.h> | |
| #include "rtc_base/checks.h" | |
| #include "common_audio/signal_processing/include/signal_processing_library.h" | |
| #include "modules/audio_coding/codecs/isac/main/source/bandwidth_estimator.h" | |
| #include "modules/audio_coding/codecs/isac/main/source/codec.h" | |
| #include "modules/audio_coding/codecs/isac/main/source/crc.h" | |
| #include "modules/audio_coding/codecs/isac/main/source/entropy_coding.h" | |
| #include "modules/audio_coding/codecs/isac/main/source/lpc_shape_swb16_tables.h" | |
| #include "modules/audio_coding/codecs/isac/main/source/os_specific_inline.h" | |
| #include "modules/audio_coding/codecs/isac/main/source/structs.h" | |
| #include "modules/audio_coding/codecs/isac/main/source/isac_vad.h" | |
| #include "rtc_base/system/arch.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 translates 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) { | |
| int16_t lim30MsPayloadBytes = WEBRTC_SPL_MIN( | |
| (instISAC->maxPayloadSizeBytes), | |
| (instISAC->maxRateBytesPer30Ms)); | |
| int16_t 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 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)) { | |
| int32_t bottleneck = | |
| WebRtcIsac_GetUplinkBandwidth(&instISAC->bwestimator_obj); | |
| /* 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 choice we have here. */ | |
| instISAC->instLB.ISACencLB_obj.bottleneck = | |
| (bottleneck > 32000) ? 32000 : bottleneck; | |
| instISAC->bandwidthKHz = isac8kHz; | |
| } else { | |
| /* Do the rate-allocation 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 | |
| * care of buffer_index and the last LPC vector. */ | |
| } | |
| } | |
| } | |
| } | |
| /**************************************************************************** | |
| * GetSendBandwidthInfo(...) | |
| * | |
| * This is called to get the bandwidth info. This info is the bandwidth and | |
| * the jitter of 'there-to-here' channel, estimated 'here.' These info | |
| * is signaled in an in-band fashion to the other side. | |
| * | |
| * The call to the bandwidth estimator triggers 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 | |
| * generate 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, | |
| int16_t* bandwidthIndex, | |
| int16_t* 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 | |
| */ | |
| int16_t WebRtcIsac_AssignSize(int* sizeInBytes) { | |
| *sizeInBytes = sizeof(ISACMainStruct) * 2 / sizeof(int16_t); | |
| return 0; | |
| } | |
| /**************************************************************************** | |
| * WebRtcIsac_Assign(...) | |
| * | |
| * This function assigns the memory already created to the ISAC instance. | |
| * | |
| * Input: | |
| * - ISAC_main_inst : address of the pointer to the coder instance. | |
| * - instISAC_Addr : the already allocated memory, where we put the | |
| * iSAC structure. | |
| * | |
| * Return value : 0 - Ok | |
| * -1 - Error | |
| */ | |
| int16_t 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; | |
| instISAC->in_sample_rate_hz = 16000; | |
| WebRtcIsac_InitTransform(&instISAC->transform_tables); | |
| 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 | |
| */ | |
| int16_t WebRtcIsac_Create(ISACStruct** ISAC_main_inst) { | |
| ISACMainStruct* instISAC; | |
| if (ISAC_main_inst != NULL) { | |
| instISAC = (ISACMainStruct*)malloc(sizeof(ISACMainStruct)); | |
| *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; | |
| instISAC->in_sample_rate_hz = 16000; | |
| WebRtcIsac_InitTransform(&instISAC->transform_tables); | |
| return 0; | |
| } else { | |
| return -1; | |
| } | |
| } 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 | |
| */ | |
| int16_t WebRtcIsac_Free(ISACStruct* ISAC_main_inst) { | |
| ISACMainStruct* instISAC = (ISACMainStruct*)ISAC_main_inst; | |
| 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 int16_t EncoderInitLb(ISACLBStruct* instLB, | |
| int16_t codingMode, | |
| enum IsacSamplingRate sampRate) { | |
| int16_t 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 | |
| * instantaneous 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 int16_t EncoderInitUb(ISACUBStruct* instUB, | |
| int16_t bandwidth) { | |
| int16_t 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; | |
| } | |
| int16_t WebRtcIsac_EncoderInit(ISACStruct* ISAC_main_inst, | |
| int16_t codingMode) { | |
| ISACMainStruct* instISAC = (ISACMainStruct*)ISAC_main_inst; | |
| int16_t status; | |
| 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(int32_t)); | |
| memset(instISAC->analysisFBState2, 0, | |
| FB_STATE_SIZE_WORD32 * sizeof(int32_t)); | |
| status = EncoderInitUb(&(instISAC->instUB), | |
| instISAC->bandwidthKHz); | |
| if (status < 0) { | |
| instISAC->errorCode = -status; | |
| return -1; | |
| } | |
| } | |
| /* Initialization 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 | |
| */ | |
| int WebRtcIsac_Encode(ISACStruct* ISAC_main_inst, | |
| const int16_t* speechIn, | |
| uint8_t* encoded) { | |
| float inFrame[FRAMESAMPLES_10ms]; | |
| int16_t speechInLB[FRAMESAMPLES_10ms]; | |
| int16_t speechInUB[FRAMESAMPLES_10ms]; | |
| int streamLenLB = 0; | |
| int streamLenUB = 0; | |
| int streamLen = 0; | |
| size_t k = 0; | |
| uint8_t garbageLen = 0; | |
| int32_t bottleneck = 0; | |
| int16_t bottleneckIdx = 0; | |
| int16_t jitterInfo = 0; | |
| ISACMainStruct* instISAC = (ISACMainStruct*)ISAC_main_inst; | |
| ISACLBStruct* instLB = &(instISAC->instLB); | |
| ISACUBStruct* 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, SWBFRAMESAMPLES_10ms, 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(&instISAC->transform_tables, | |
| 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 = | |
| (int16_t)(streamLenLB + 1 + LEN_CHECK_SUM_WORD8); | |
| /* Encode upper-band. */ | |
| switch (instISAC->bandwidthKHz) { | |
| case isac12kHz: { | |
| streamLenUB = WebRtcIsac_EncodeUb12(&instISAC->transform_tables, | |
| inFrame, &instUB->ISACencUB_obj, | |
| jitterInfo); | |
| break; | |
| } | |
| case isac16kHz: { | |
| streamLenUB = WebRtcIsac_EncodeUb16(&instISAC->transform_tables, | |
| 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 byte 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(encoded, instLB->ISACencLB_obj.bitstr_obj.stream, streamLenLB); | |
| streamLen = streamLenLB; | |
| if (streamLenUB > 0) { | |
| encoded[streamLenLB] = (uint8_t)(streamLenUB + 1 + LEN_CHECK_SUM_WORD8); | |
| memcpy(&encoded[streamLenLB + 1], | |
| instUB->ISACencUB_obj.bitstr_obj.stream, | |
| streamLenUB); | |
| streamLen += encoded[streamLenLB]; | |
| } else { | |
| encoded[streamLenLB] = 0; | |
| } | |
| } else { | |
| if (streamLenLB == 0) { | |
| return 0; | |
| } | |
| memcpy(encoded, instLB->ISACencLB_obj.bitstr_obj.stream, streamLenLB); | |
| streamLenUB = 0; | |
| streamLen = streamLenLB; | |
| } | |
| /* Add Garbage if required. */ | |
| bottleneck = WebRtcIsac_GetUplinkBandwidth(&instISAC->bwestimator_obj); | |
| if (instISAC->codingMode == 0) { | |
| int minBytes; | |
| int limit; | |
| uint8_t* 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 = &encoded[streamLenLB]; | |
| limit = streamLen + 255; | |
| } else { | |
| ptrGarbage = &encoded[streamLenLB + 1 + streamLenUB]; | |
| limit = streamLen + (255 - encoded[streamLenLB]); | |
| } | |
| minBytes = (minBytes > limit) ? limit : minBytes; | |
| garbageLen = (minBytes > streamLen) ? (uint8_t)(minBytes - streamLen) : 0; | |
| /* Save data for creation of multiple bit-streams. */ | |
| /* If bit-stream too short then add garbage at the end. */ | |
| if (garbageLen > 0) { | |
| /* Overwrite the garbage area to avoid leaking possibly sensitive data | |
| over the network. This also makes the output deterministic. */ | |
| memset(ptrGarbage, 0, garbageLen); | |
| /* 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)) { | |
| encoded[streamLenLB] = garbageLen; | |
| } else { | |
| encoded[streamLenLB] += garbageLen; | |
| /* Write the length of the garbage at the end of the upper-band | |
| * bit-stream, if exists. This helps for sanity check. */ | |
| encoded[streamLenLB + 1 + streamLenUB] = 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)) { | |
| uint32_t crc; | |
| WebRtcIsac_GetCrc((int16_t*)(&(encoded[streamLenLB + 1])), | |
| streamLenUB + garbageLen, &crc); | |
| #ifndef WEBRTC_ARCH_BIG_ENDIAN | |
| for (k = 0; k < LEN_CHECK_SUM_WORD8; k++) { | |
| encoded[streamLen - LEN_CHECK_SUM_WORD8 + k] = | |
| (uint8_t)(crc >> (24 - k * 8)); | |
| } | |
| #else | |
| memcpy(&encoded[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 2! 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. | |
| */ | |
| int16_t WebRtcIsac_GetNewBitStream(ISACStruct* ISAC_main_inst, | |
| int16_t bweIndex, | |
| int16_t jitterInfo, | |
| int32_t rate, | |
| uint8_t* encoded, | |
| int16_t isRCU) { | |
| Bitstr iSACBitStreamInst; /* Local struct for bitstream handling */ | |
| int16_t streamLenLB; | |
| int16_t streamLenUB; | |
| int16_t totalStreamLen; | |
| double gain2; | |
| double gain1; | |
| float scale; | |
| enum ISACBandwidth bandwidthKHz; | |
| double rateLB; | |
| double rateUB; | |
| int32_t currentBN; | |
| uint32_t crc; | |
| #ifndef WEBRTC_ARCH_BIG_ENDIAN | |
| int16_t k; | |
| #endif | |
| ISACMainStruct* 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; | |
| } | |
| /* A gain [dB] for the given rate. */ | |
| gain1 = WebRtcIsac_GetSnr( | |
| rateLB, instISAC->instLB.ISACencLB_obj.current_framesamples); | |
| /* The gain [dB] 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 int16_t. */ | |
| 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; | |
| streamLenUB = WebRtcIsac_EncodeStoredDataUb( | |
| &(instISAC->instUB.ISACencUB_obj.SaveEnc_obj), | |
| &iSACBitStreamInst, jitterInfo, scale, | |
| instISAC->bandwidthKHz); | |
| if (streamLenUB < 0) { | |
| return -1; | |
| } | |
| if (streamLenUB + 1 + LEN_CHECK_SUM_WORD8 > 255) { | |
| return streamLenLB; | |
| } | |
| totalStreamLen = streamLenLB + streamLenUB + 1 + LEN_CHECK_SUM_WORD8; | |
| encoded[streamLenLB] = streamLenUB + 1 + LEN_CHECK_SUM_WORD8; | |
| memcpy(&encoded[streamLenLB + 1], iSACBitStreamInst.stream, | |
| streamLenUB); | |
| WebRtcIsac_GetCrc((int16_t*)(&(encoded[streamLenLB + 1])), | |
| streamLenUB, &crc); | |
| #ifndef WEBRTC_ARCH_BIG_ENDIAN | |
| for (k = 0; k < LEN_CHECK_SUM_WORD8; k++) { | |
| encoded[totalStreamLen - LEN_CHECK_SUM_WORD8 + k] = | |
| (uint8_t)((crc >> (24 - k * 8)) & 0xFF); | |
| } | |
| #else | |
| memcpy(&encoded[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. | |
| */ | |
| static void DecoderInitLb(ISACLBStruct* instISAC) { | |
| int i; | |
| /* Initialize 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); | |
| } | |
| static void 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); | |
| } | |
| void WebRtcIsac_DecoderInit(ISACStruct* ISAC_main_inst) { | |
| ISACMainStruct* instISAC = (ISACMainStruct*)ISAC_main_inst; | |
| DecoderInitLb(&instISAC->instLB); | |
| if (instISAC->decoderSamplingRateKHz == kIsacSuperWideband) { | |
| memset(instISAC->synthesisFBState1, 0, | |
| FB_STATE_SIZE_WORD32 * sizeof(int32_t)); | |
| memset(instISAC->synthesisFBState2, 0, | |
| FB_STATE_SIZE_WORD32 * sizeof(int32_t)); | |
| DecoderInitUb(&(instISAC->instUB)); | |
| } | |
| 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; | |
| } | |
| /**************************************************************************** | |
| * WebRtcIsac_UpdateBwEstimate(...) | |
| * | |
| * This function updates the estimate of the bandwidth. | |
| * | |
| * NOTE: | |
| * The estimates of bandwidth is not valid if the sample rate of the far-end | |
| * encoder is set to 48 kHz and send timestamps are increamented according to | |
| * 48 kHz sampling rate. | |
| * | |
| * 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 | |
| */ | |
| int16_t WebRtcIsac_UpdateBwEstimate(ISACStruct* ISAC_main_inst, | |
| const uint8_t* encoded, | |
| size_t packet_size, | |
| uint16_t rtp_seq_number, | |
| uint32_t send_ts, | |
| uint32_t arr_ts) { | |
| ISACMainStruct* instISAC = (ISACMainStruct*)ISAC_main_inst; | |
| Bitstr streamdata; | |
| #ifndef WEBRTC_ARCH_BIG_ENDIAN | |
| int k; | |
| #endif | |
| int16_t err; | |
| /* Check if decoder initiated. */ | |
| if ((instISAC->initFlag & BIT_MASK_DEC_INIT) != BIT_MASK_DEC_INIT) { | |
| instISAC->errorCode = ISAC_DECODER_NOT_INITIATED; | |
| return -1; | |
| } | |
| /* Check that the size of the packet is valid, and if not return without | |
| * updating the bandwidth estimate. A valid size is at least 10 bytes. */ | |
| if (packet_size < 10) { | |
| /* Return error code if the packet length is null. */ | |
| instISAC->errorCode = ISAC_EMPTY_PACKET; | |
| return -1; | |
| } | |
| WebRtcIsac_ResetBitstream(&(streamdata)); | |
| #ifndef WEBRTC_ARCH_BIG_ENDIAN | |
| for (k = 0; k < 10; k++) { | |
| uint16_t ek = ((const uint16_t*)encoded)[k >> 1]; | |
| streamdata.stream[k] = (uint8_t)((ek >> ((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 int Decode(ISACStruct* ISAC_main_inst, | |
| const uint8_t* encoded, | |
| size_t lenEncodedBytes, | |
| int16_t* decoded, | |
| int16_t* speechType, | |
| int16_t isRCUPayload) { | |
| /* Number of samples (480 or 960), output from decoder | |
| that were actually used in the encoder/decoder | |
| (determined on the fly). */ | |
| int16_t numSamplesLB; | |
| int16_t numSamplesUB; | |
| int16_t speechIdx; | |
| float outFrame[MAX_FRAMESAMPLES]; | |
| int16_t outFrameLB[MAX_FRAMESAMPLES]; | |
| int16_t outFrameUB[MAX_FRAMESAMPLES]; | |
| int numDecodedBytesLBint; | |
| size_t numDecodedBytesLB; | |
| int numDecodedBytesUB; | |
| size_t lenEncodedLBBytes; | |
| int16_t validChecksum = 1; | |
| int16_t k; | |
| uint16_t numLayer; | |
| size_t totSizeBytes; | |
| int16_t err; | |
| ISACMainStruct* instISAC = (ISACMainStruct*)ISAC_main_inst; | |
| ISACUBDecStruct* decInstUB = &(instISAC->instUB.ISACdecUB_obj); | |
| ISACLBDecStruct* 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 encoded 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, encoded, | |
| lenEncodedLBBytes); | |
| /* We need to initialize numSamplesLB to something; otherwise, in the test | |
| for whether we should return -1 below, the compiler might generate code | |
| that fools Memcheck (Valgrind) into thinking that the control flow depends | |
| on the uninitialized value in numSamplesLB (since WebRtcIsac_DecodeLb will | |
| not fill it in if it fails and returns -1). */ | |
| numSamplesLB = 0; | |
| /* 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. */ | |
| numDecodedBytesLBint = WebRtcIsac_DecodeLb(&instISAC->transform_tables, | |
| outFrame, decInstLB, | |
| &numSamplesLB, isRCUPayload); | |
| numDecodedBytesLB = (size_t)numDecodedBytesLBint; | |
| if ((numDecodedBytesLBint < 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 without this the number | |
| * of iterations is limited. */ | |
| numLayer = 1; | |
| totSizeBytes = numDecodedBytesLB; | |
| while (totSizeBytes != lenEncodedBytes) { | |
| if ((totSizeBytes > lenEncodedBytes) || | |
| (encoded[totSizeBytes] == 0) || | |
| (numLayer > MAX_NUM_LAYERS)) { | |
| instISAC->errorCode = ISAC_LENGTH_MISMATCH; | |
| return -1; | |
| } | |
| totSizeBytes += encoded[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] = (int16_t)WebRtcIsac_lrint(outFrame[k]); | |
| } | |
| } | |
| numSamplesUB = 0; | |
| } else { | |
| uint32_t 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] = (int16_t)WebRtcIsac_lrint(outFrame[k]); | |
| } | |
| } | |
| /* Check for possible error, and if upper-band stream exists. */ | |
| if (numDecodedBytesLB == lenEncodedBytes) { | |
| /* Decoding was successful. No super-wideband bit-stream exists. */ | |
| numSamplesUB = numSamplesLB; | |
| memset(outFrameUB, 0, sizeof(int16_t) * numSamplesUB); | |
| /* Prepare for the potential increase of signal bandwidth. */ | |
| instISAC->resetFlag_8kHz = 2; | |
| } else { | |
| /* This includes the checksum and the bytes that stores the length. */ | |
| int16_t lenNextStream = encoded[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((int16_t*)(&encoded[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) == | |
| encoded[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(int16_t) * numSamplesUB); | |
| } else { | |
| /* A valid super-wideband biststream exists. */ | |
| enum ISACBandwidth bandwidthKHz; | |
| int32_t maxDelayBit; | |
| /* 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, | |
| &encoded[numDecodedBytesLB + 1], lenNextStream); | |
| /* Reset bit-stream object, this is the first decoding. */ | |
| WebRtcIsac_ResetBitstream(&(decInstUB->bitstr_obj)); | |
| /* Decode jitter information. */ | |
| err = WebRtcIsac_DecodeJitterInfo(&decInstUB->bitstr_obj, &maxDelayBit); | |
| 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 embedded 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( | |
| &instISAC->transform_tables, 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( | |
| &instISAC->transform_tables, outFrame, decInstUB, isRCUPayload); | |
| break; | |
| } | |
| default: | |
| return -1; | |
| } | |
| if (numDecodedBytesUB < 0) { | |
| instISAC->errorCode = numDecodedBytesUB; | |
| return -1; | |
| } | |
| if (numDecodedBytesLB + numDecodedBytesUB > lenEncodedBytes) { | |
| // We have supposedly decoded more bytes than we were given. Likely | |
| // caused by bad input data. | |
| instISAC->errorCode = ISAC_LENGTH_MISMATCH; | |
| return -1; | |
| } | |
| /* It might be less due to garbage. */ | |
| if ((numDecodedBytesUB != lenNextStream) && | |
| (numDecodedBytesLB + 1 + numDecodedBytesUB >= lenEncodedBytes || | |
| numDecodedBytesUB != | |
| (lenNextStream - | |
| encoded[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] = (int16_t)WebRtcIsac_lrint( | |
| outFrame[k]); | |
| } | |
| } | |
| } | |
| } | |
| speechIdx = 0; | |
| while (speechIdx < numSamplesLB) { | |
| WebRtcSpl_SynthesisQMF(&outFrameLB[speechIdx], &outFrameUB[speechIdx], | |
| FRAMESAMPLES_10ms, &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 | |
| */ | |
| int WebRtcIsac_Decode(ISACStruct* ISAC_main_inst, | |
| const uint8_t* encoded, | |
| size_t lenEncodedBytes, | |
| int16_t* decoded, | |
| int16_t* speechType) { | |
| int16_t 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 in 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 | |
| */ | |
| int WebRtcIsac_DecodeRcu(ISACStruct* ISAC_main_inst, | |
| const uint8_t* encoded, | |
| size_t lenEncodedBytes, | |
| int16_t* decoded, | |
| int16_t* speechType) { | |
| int16_t 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 : Number of samples in decoded PLC vector | |
| */ | |
| size_t WebRtcIsac_DecodePlc(ISACStruct* ISAC_main_inst, | |
| int16_t* decoded, | |
| size_t noOfLostFrames) { | |
| size_t numSamples = 0; | |
| ISACMainStruct* instISAC = (ISACMainStruct*)ISAC_main_inst; | |
| /* Limit number of frames to two = 60 millisecond. | |
| * 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(int16_t)); | |
| return numSamples; | |
| } | |
| /**************************************************************************** | |
| * ControlLb(...) - Internal function for controlling Lower Band | |
| * ControlUb(...) - Internal function for controlling 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 int16_t ControlLb(ISACLBStruct* instISAC, double rate, | |
| int16_t 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 int16_t ControlUb(ISACUBStruct* instISAC, double rate) { | |
| if ((rate >= 10000) && (rate <= 32000)) { | |
| instISAC->ISACencUB_obj.bottleneck = rate; | |
| } else { | |
| return -ISAC_DISALLOWED_BOTTLENECK; | |
| } | |
| return 0; | |
| } | |
| int16_t WebRtcIsac_Control(ISACStruct* ISAC_main_inst, | |
| int32_t bottleneckBPS, | |
| int frameSize) { | |
| ISACMainStruct* instISAC = (ISACMainStruct*)ISAC_main_inst; | |
| int16_t status; | |
| double rateLB; | |
| double rateUB; | |
| enum ISACBandwidth bandwidthKHz; | |
| 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, (int16_t)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 if the bandwidth is changing. */ | |
| if (instISAC->bandwidthKHz != bandwidthKHz) { | |
| instISAC->bandwidthKHz = bandwidthKHz; | |
| UpdatePayloadSizeLimit(instISAC); | |
| } | |
| instISAC->bottleneck = bottleneckBPS; | |
| return 0; | |
| } | |
| void WebRtcIsac_SetInitialBweBottleneck(ISACStruct* ISAC_main_inst, | |
| int bottleneck_bits_per_second) { | |
| ISACMainStruct* instISAC = (ISACMainStruct*)ISAC_main_inst; | |
| RTC_DCHECK_GE(bottleneck_bits_per_second, 10000); | |
| RTC_DCHECK_LE(bottleneck_bits_per_second, 32000); | |
| instISAC->bwestimator_obj.send_bw_avg = (float)bottleneck_bits_per_second; | |
| } | |
| /**************************************************************************** | |
| * 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 | |
| */ | |
| int16_t WebRtcIsac_ControlBwe(ISACStruct* ISAC_main_inst, | |
| int32_t bottleneckBPS, | |
| int frameSizeMs, | |
| int16_t enforceFrameSize) { | |
| ISACMainStruct* instISAC = (ISACMainStruct*)ISAC_main_inst; | |
| enum ISACBandwidth bandwidth; | |
| /* 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 structure variable if enforceFrameSize is set. ISAC will then | |
| * keep the chosen frame size. */ | |
| if (enforceFrameSize != 0) { | |
| instISAC->instLB.ISACencLB_obj.enforceFrameSize = 1; | |
| } else { | |
| instISAC->instLB.ISACencLB_obj.enforceFrameSize = 0; | |
| } | |
| /* Set the initial rate. If the input value is zero then the default intial | |
| * rate is used. Otehrwise, values between 10 to 32 kbps are accepted. */ | |
| 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 the initial frame-size. If 'enforceFrameSize' is set, the frame-size | |
| * will not change */ | |
| if (frameSizeMs != 0) { | |
| if ((frameSizeMs == 30) || (frameSizeMs == 60)) { | |
| instISAC->instLB.ISACencLB_obj.new_framelength = | |
| (int16_t)((FS / 1000) * frameSizeMs); | |
| } else { | |
| instISAC->errorCode = ISAC_DISALLOWED_FRAME_LENGTH; | |
| return -1; | |
| } | |
| } | |
| return 0; | |
| } | |
| /**************************************************************************** | |
| * WebRtcIsac_GetDownLinkBwIndex(...) | |
| * | |
| * This function returns index representing the Bandwidth estimate from | |
| * the other side to this side. | |
| * | |
| * Input: | |
| * - ISAC_main_inst : iSAC structure | |
| * | |
| * Output: | |
| * - bweIndex : Bandwidth estimate to transmit to other side. | |
| * | |
| */ | |
| int16_t WebRtcIsac_GetDownLinkBwIndex(ISACStruct* ISAC_main_inst, | |
| int16_t* bweIndex, | |
| int16_t* jitterInfo) { | |
| ISACMainStruct* instISAC = (ISACMainStruct*)ISAC_main_inst; | |
| /* Check if encoder initialized. */ | |
| 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 structure | |
| * - rateIndex : Bandwidth estimate from other side. | |
| * | |
| * Return value : 0 - ok | |
| * -1 - index out of range | |
| */ | |
| int16_t WebRtcIsac_UpdateUplinkBw(ISACStruct* ISAC_main_inst, | |
| int16_t bweIndex) { | |
| ISACMainStruct* instISAC = (ISACMainStruct*)ISAC_main_inst; | |
| int16_t returnVal; | |
| /* 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 | |
| * bit-stream. | |
| * | |
| * Input: | |
| * - encoded : Encoded bit-stream | |
| * | |
| * Output: | |
| * - frameLength : Length of frame in packet (in samples) | |
| * - bweIndex : Bandwidth estimate in bit-stream | |
| * | |
| */ | |
| int16_t WebRtcIsac_ReadBwIndex(const uint8_t* encoded, | |
| int16_t* bweIndex) { | |
| Bitstr streamdata; | |
| #ifndef WEBRTC_ARCH_BIG_ENDIAN | |
| int k; | |
| #endif | |
| int16_t err; | |
| WebRtcIsac_ResetBitstream(&(streamdata)); | |
| #ifndef WEBRTC_ARCH_BIG_ENDIAN | |
| for (k = 0; k < 10; k++) { | |
| int16_t ek2 = ((const int16_t*)encoded)[k >> 1]; | |
| streamdata.stream[k] = (uint8_t)((ek2 >> ((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 number of samples the decoder will generate if | |
| * the given payload is decoded. | |
| * | |
| * Input: | |
| * - encoded : Encoded bitstream | |
| * | |
| * Output: | |
| * - frameLength : Length of frame in packet (in samples) | |
| * | |
| */ | |
| int16_t WebRtcIsac_ReadFrameLen(ISACStruct* ISAC_main_inst, | |
| const uint8_t* encoded, | |
| int16_t* frameLength) { | |
| Bitstr streamdata; | |
| #ifndef WEBRTC_ARCH_BIG_ENDIAN | |
| int k; | |
| #endif | |
| int16_t err; | |
| ISACMainStruct* instISAC; | |
| WebRtcIsac_ResetBitstream(&(streamdata)); | |
| #ifndef WEBRTC_ARCH_BIG_ENDIAN | |
| for (k = 0; k < 10; k++) { | |
| int16_t ek2 = ((const int16_t*)encoded)[k >> 1]; | |
| streamdata.stream[k] = (uint8_t)((ek2 >> ((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(...) | |
| * | |
| * This function returns the frame length (in samples) of the next packet. | |
| * In the case of channel-adaptive mode, iSAC decides on its frame length based | |
| * on the estimated bottleneck, this AOI 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 | |
| * | |
| */ | |
| int16_t WebRtcIsac_GetNewFrameLen(ISACStruct* ISAC_main_inst) { | |
| ISACMainStruct* instISAC = (ISACMainStruct*)ISAC_main_inst; | |
| /* Return new frame length. */ | |
| if (instISAC->in_sample_rate_hz == 16000) | |
| return (instISAC->instLB.ISACencLB_obj.new_framelength); | |
| else /* 32000 Hz */ | |
| return ((instISAC->instLB.ISACencLB_obj.new_framelength) * 2); | |
| } | |
| /**************************************************************************** | |
| * WebRtcIsac_GetErrorCode(...) | |
| * | |
| * This function can be used to check the error code of an iSAC instance. | |
| * When a function returns -1 an error code will be set for that instance. | |
| * The function below extracts the code of the last error that occurred in | |
| * the specified instance. | |
| * | |
| * Input: | |
| * - ISAC_main_inst : ISAC instance | |
| * | |
| * Return value : Error code | |
| */ | |
| int16_t WebRtcIsac_GetErrorCode(ISACStruct* ISAC_main_inst) { | |
| return ((ISACMainStruct*)ISAC_main_inst)->errorCode; | |
| } | |
| /**************************************************************************** | |
| * WebRtcIsac_GetUplinkBw(...) | |
| * | |
| * This function outputs the target bottleneck of the codec. In | |
| * channel-adaptive mode, the target bottleneck is specified through an in-band | |
| * signalling retrieved 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 are used.). | |
| * Note that the output is the iSAC internal operating bottleneck which 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. | |
| */ | |
| int16_t WebRtcIsac_GetUplinkBw(ISACStruct* ISAC_main_inst, | |
| int32_t* bottleneck) { | |
| ISACMainStruct* instISAC = (ISACMainStruct*)ISAC_main_inst; | |
| if (instISAC->codingMode == 0) { | |
| /* We are in adaptive mode then get the bottleneck from BWE. */ | |
| *bottleneck = (int32_t)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 | |
| */ | |
| int16_t WebRtcIsac_SetMaxPayloadSize(ISACStruct* ISAC_main_inst, | |
| int16_t maxPayloadBytes) { | |
| ISACMainStruct* instISAC = (ISACMainStruct*)ISAC_main_inst; | |
| int16_t status = 0; | |
| /* 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 | |
| */ | |
| int16_t WebRtcIsac_SetMaxRate(ISACStruct* ISAC_main_inst, | |
| int32_t maxRate) { | |
| ISACMainStruct* instISAC = (ISACMainStruct*)ISAC_main_inst; | |
| int16_t maxRateInBytesPer30Ms; | |
| int16_t status = 0; | |
| /* 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 = (int16_t)(maxRate * 3 / 800); | |
| if (instISAC->encoderSamplingRateKHz == kIsacWideband) { | |
| if (maxRate < 32000) { | |
| /* 'maxRate' is out of valid range. | |
| * Set to the acceptable value and return -1. */ | |
| maxRateInBytesPer30Ms = 120; | |
| status = -1; | |
| } | |
| if (maxRate > 53400) { | |
| /* 'maxRate' 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(...) | |
| * | |
| * This function populates "encoded" with the redundant payload of the recently | |
| * encodedframe. 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 | |
| */ | |
| int16_t WebRtcIsac_GetRedPayload(ISACStruct* ISAC_main_inst, | |
| uint8_t* encoded) { | |
| Bitstr iSACBitStreamInst; | |
| int16_t streamLenLB; | |
| int16_t streamLenUB; | |
| int16_t streamLen; | |
| int16_t totalLenUB; | |
| ISACMainStruct* instISAC = (ISACMainStruct*)ISAC_main_inst; | |
| #ifndef WEBRTC_ARCH_BIG_ENDIAN | |
| int k; | |
| #endif | |
| if ((instISAC->initFlag & BIT_MASK_ENC_INIT) != | |
| BIT_MASK_ENC_INIT) { | |
| instISAC->errorCode = ISAC_ENCODER_NOT_INITIATED; | |
| } | |
| WebRtcIsac_ResetBitstream(&(iSACBitStreamInst)); | |
| 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 int16_t. */ | |
| memcpy(encoded, 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 includes the bit-stream 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)) { | |
| uint32_t crc; | |
| streamLen += totalLenUB; | |
| encoded[streamLenLB] = (uint8_t)totalLenUB; | |
| memcpy(&encoded[streamLenLB + 1], iSACBitStreamInst.stream, | |
| streamLenUB); | |
| WebRtcIsac_GetCrc((int16_t*)(&(encoded[streamLenLB + 1])), | |
| streamLenUB, &crc); | |
| #ifndef WEBRTC_ARCH_BIG_ENDIAN | |
| for (k = 0; k < LEN_CHECK_SUM_WORD8; k++) { | |
| encoded[streamLen - LEN_CHECK_SUM_WORD8 + k] = | |
| (uint8_t)((crc >> (24 - k * 8)) & 0xFF); | |
| } | |
| #else | |
| memcpy(&encoded[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() | |
| * This function sets 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 be reset to their default values. | |
| * | |
| * Input: | |
| * - ISAC_main_inst : iSAC instance | |
| * - sample_rate_hz : sampling rate in Hertz, valid values are 16000 | |
| * and 32000. | |
| * | |
| * Return value : 0 if successful | |
| * -1 if failed. | |
| */ | |
| int16_t WebRtcIsac_SetEncSampRate(ISACStruct* ISAC_main_inst, | |
| uint16_t sample_rate_hz) { | |
| ISACMainStruct* instISAC = (ISACMainStruct*)ISAC_main_inst; | |
| enum IsacSamplingRate encoder_operational_rate; | |
| if ((sample_rate_hz != 16000) && (sample_rate_hz != 32000)) { | |
| /* Sampling Frequency is not supported. */ | |
| instISAC->errorCode = ISAC_UNSUPPORTED_SAMPLING_FREQUENCY; | |
| return -1; | |
| } | |
| if (sample_rate_hz == 16000) { | |
| encoder_operational_rate = kIsacWideband; | |
| } else { | |
| encoder_operational_rate = kIsacSuperWideband; | |
| } | |
| if ((instISAC->initFlag & BIT_MASK_ENC_INIT) != | |
| BIT_MASK_ENC_INIT) { | |
| if (encoder_operational_rate == kIsacWideband) { | |
| instISAC->bandwidthKHz = isac8kHz; | |
| } else { | |
| instISAC->bandwidthKHz = isac16kHz; | |
| } | |
| } else { | |
| ISACUBStruct* instUB = &(instISAC->instUB); | |
| ISACLBStruct* instLB = &(instISAC->instLB); | |
| int32_t bottleneck = instISAC->bottleneck; | |
| int16_t codingMode = instISAC->codingMode; | |
| int16_t frameSizeMs = instLB->ISACencLB_obj.new_framelength / | |
| (FS / 1000); | |
| if ((encoder_operational_rate == 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 ((encoder_operational_rate == kIsacSuperWideband) && | |
| (instISAC->encoderSamplingRateKHz == kIsacWideband)) { | |
| double bottleneckLB = 0; | |
| double bottleneckUB = 0; | |
| 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, encoder_operational_rate); | |
| EncoderInitUb(instUB, instISAC->bandwidthKHz); | |
| memset(instISAC->analysisFBState1, 0, | |
| FB_STATE_SIZE_WORD32 * sizeof(int32_t)); | |
| memset(instISAC->analysisFBState2, 0, | |
| FB_STATE_SIZE_WORD32 * sizeof(int32_t)); | |
| 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 = encoder_operational_rate; | |
| instISAC->in_sample_rate_hz = sample_rate_hz; | |
| return 0; | |
| } | |
| /****************************************************************************** | |
| * WebRtcIsac_SetDecSampRate() | |
| * This function sets 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 | |
| * - sample_rate_hz : sampling rate in Hertz, valid values are 16000 | |
| * and 32000. | |
| * | |
| * Return value : 0 if successful | |
| * -1 if failed. | |
| */ | |
| int16_t WebRtcIsac_SetDecSampRate(ISACStruct* ISAC_main_inst, | |
| uint16_t sample_rate_hz) { | |
| ISACMainStruct* instISAC = (ISACMainStruct*)ISAC_main_inst; | |
| enum IsacSamplingRate decoder_operational_rate; | |
| if (sample_rate_hz == 16000) { | |
| decoder_operational_rate = kIsacWideband; | |
| } else if (sample_rate_hz == 32000) { | |
| decoder_operational_rate = kIsacSuperWideband; | |
| } else { | |
| /* Sampling Frequency is not supported. */ | |
| instISAC->errorCode = ISAC_UNSUPPORTED_SAMPLING_FREQUENCY; | |
| return -1; | |
| } | |
| if ((instISAC->decoderSamplingRateKHz == kIsacWideband) && | |
| (decoder_operational_rate == 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(int32_t)); | |
| memset(instISAC->synthesisFBState2, 0, | |
| FB_STATE_SIZE_WORD32 * sizeof(int32_t)); | |
| DecoderInitUb(&instISAC->instUB); | |
| } | |
| instISAC->decoderSamplingRateKHz = decoder_operational_rate; | |
| return 0; | |
| } | |
| /****************************************************************************** | |
| * WebRtcIsac_EncSampRate() | |
| * | |
| * Input: | |
| * - ISAC_main_inst : iSAC instance | |
| * | |
| * Return value : sampling rate in Hertz. The input to encoder | |
| * is expected to be sampled in this rate. | |
| * | |
| */ | |
| uint16_t WebRtcIsac_EncSampRate(ISACStruct* ISAC_main_inst) { | |
| ISACMainStruct* instISAC = (ISACMainStruct*)ISAC_main_inst; | |
| return instISAC->in_sample_rate_hz; | |
| } | |
| /****************************************************************************** | |
| * WebRtcIsac_DecSampRate() | |
| * Return the sampling rate of the decoded audio. | |
| * | |
| * Input: | |
| * - ISAC_main_inst : iSAC instance | |
| * | |
| * Return value : sampling rate in Hertz. Decoder output is | |
| * sampled at this rate. | |
| * | |
| */ | |
| uint16_t WebRtcIsac_DecSampRate(ISACStruct* ISAC_main_inst) { | |
| ISACMainStruct* instISAC = (ISACMainStruct*)ISAC_main_inst; | |
| return instISAC->decoderSamplingRateKHz == kIsacWideband ? 16000 : 32000; | |
| } | |
| void WebRtcIsac_GetBandwidthInfo(ISACStruct* inst, | |
| IsacBandwidthInfo* bwinfo) { | |
| ISACMainStruct* instISAC = (ISACMainStruct*)inst; | |
| RTC_DCHECK_NE(0, instISAC->initFlag & BIT_MASK_DEC_INIT); | |
| WebRtcIsacBw_GetBandwidthInfo(&instISAC->bwestimator_obj, | |
| instISAC->decoderSamplingRateKHz, bwinfo); | |
| } | |
| void WebRtcIsac_SetBandwidthInfo(ISACStruct* inst, | |
| const IsacBandwidthInfo* bwinfo) { | |
| ISACMainStruct* instISAC = (ISACMainStruct*)inst; | |
| RTC_DCHECK_NE(0, instISAC->initFlag & BIT_MASK_ENC_INIT); | |
| WebRtcIsacBw_SetBandwidthInfo(&instISAC->bwestimator_obj, bwinfo); | |
| } | |
| void WebRtcIsac_SetEncSampRateInDecoder(ISACStruct* inst, | |
| int sample_rate_hz) { | |
| ISACMainStruct* instISAC = (ISACMainStruct*)inst; | |
| RTC_DCHECK_NE(0, instISAC->initFlag & BIT_MASK_DEC_INIT); | |
| RTC_DCHECK(!(instISAC->initFlag & BIT_MASK_ENC_INIT)); | |
| RTC_DCHECK(sample_rate_hz == 16000 || sample_rate_hz == 32000); | |
| instISAC->encoderSamplingRateKHz = sample_rate_hz / 1000; | |
| } |