| /* |
| * 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" |
| |
| #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; |
| } |