/* * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ /* * Implementation of RecOut function, which is the main function for the audio output * process. This function must be called (through the NetEQ API) once every 10 ms. */ #include "dsp.h" #include #include /* to define NULL */ #include "signal_processing_library.h" #include "dsp_helpfunctions.h" #include "neteq_error_codes.h" #include "neteq_defines.h" #include "mcu_dsp_common.h" /* Audio types */ #define TYPE_SPEECH 1 #define TYPE_CNG 2 #ifdef NETEQ_DELAY_LOGGING #include "delay_logging.h" #include #pragma message("*******************************************************************") #pragma message("You have specified to use NETEQ_DELAY_LOGGING in the NetEQ library.") #pragma message("Make sure that your test application supports this.") #pragma message("*******************************************************************") #endif /* Scratch usage: Type Name size startpos endpos WebRtc_Word16 pw16_NetEqAlgorithm_buffer 600*fs/8000 0 600*fs/8000-1 struct dspInfo 6 600*fs/8000 605*fs/8000 func WebRtcNetEQ_Normal 40+495*fs/8000 0 39+495*fs/8000 func WebRtcNetEQ_Merge 40+496*fs/8000 0 39+496*fs/8000 func WebRtcNetEQ_Expand 40+370*fs/8000 126*fs/800 39+496*fs/8000 func WebRtcNetEQ_Accelerate 210 240*fs/8000 209+240*fs/8000 func WebRtcNetEQ_BGNUpdate 69 480*fs/8000 68+480*fs/8000 Total: 605*fs/8000 */ #define SCRATCH_ALGORITHM_BUFFER 0 #define SCRATCH_NETEQ_NORMAL 0 #define SCRATCH_NETEQ_MERGE 0 #if (defined(NETEQ_48KHZ_WIDEBAND)) #define SCRATCH_DSP_INFO 3600 #define SCRATCH_NETEQ_ACCELERATE 1440 #define SCRATCH_NETEQ_BGN_UPDATE 2880 #define SCRATCH_NETEQ_EXPAND 756 #elif (defined(NETEQ_32KHZ_WIDEBAND)) #define SCRATCH_DSP_INFO 2400 #define SCRATCH_NETEQ_ACCELERATE 960 #define SCRATCH_NETEQ_BGN_UPDATE 1920 #define SCRATCH_NETEQ_EXPAND 504 #elif (defined(NETEQ_WIDEBAND)) #define SCRATCH_DSP_INFO 1200 #define SCRATCH_NETEQ_ACCELERATE 480 #define SCRATCH_NETEQ_BGN_UPDATE 960 #define SCRATCH_NETEQ_EXPAND 252 #else /* NB */ #define SCRATCH_DSP_INFO 600 #define SCRATCH_NETEQ_ACCELERATE 240 #define SCRATCH_NETEQ_BGN_UPDATE 480 #define SCRATCH_NETEQ_EXPAND 126 #endif #if (defined(NETEQ_48KHZ_WIDEBAND)) #define SIZE_SCRATCH_BUFFER 3636 #elif (defined(NETEQ_32KHZ_WIDEBAND)) #define SIZE_SCRATCH_BUFFER 2424 #elif (defined(NETEQ_WIDEBAND)) #define SIZE_SCRATCH_BUFFER 1212 #else /* NB */ #define SIZE_SCRATCH_BUFFER 606 #endif #ifdef NETEQ_DELAY_LOGGING extern FILE *delay_fid2; /* file pointer to delay log file */ extern WebRtc_UWord32 tot_received_packets; #endif int WebRtcNetEQ_RecOutInternal(DSPInst_t *inst, WebRtc_Word16 *pw16_outData, WebRtc_Word16 *pw16_len, WebRtc_Word16 BGNonly) { WebRtc_Word16 blockLen, payloadLen, len = 0, pos; WebRtc_Word16 w16_tmp1, w16_tmp2, w16_tmp3, DataEnough; WebRtc_Word16 *blockPtr; WebRtc_Word16 MD = 0; WebRtc_Word16 speechType = TYPE_SPEECH; WebRtc_UWord16 instr; WebRtc_UWord16 uw16_tmp; #ifdef SCRATCH char pw8_ScratchBuffer[((SIZE_SCRATCH_BUFFER + 1) * 2)]; WebRtc_Word16 *pw16_scratchPtr = (WebRtc_Word16*) pw8_ScratchBuffer; WebRtc_Word16 pw16_decoded_buffer[NETEQ_MAX_FRAME_SIZE]; WebRtc_Word16 *pw16_NetEqAlgorithm_buffer = pw16_scratchPtr + SCRATCH_ALGORITHM_BUFFER; DSP2MCU_info_t *dspInfo = (DSP2MCU_info_t*) (pw16_scratchPtr + SCRATCH_DSP_INFO); #else WebRtc_Word16 pw16_decoded_buffer[NETEQ_MAX_FRAME_SIZE]; WebRtc_Word16 pw16_NetEqAlgorithm_buffer[NETEQ_MAX_OUTPUT_SIZE]; DSP2MCU_info_t dspInfoStruct; DSP2MCU_info_t *dspInfo = &dspInfoStruct; #endif WebRtc_Word16 fs_mult; int borrowedSamples; int oldBorrowedSamples; int return_value = 0; WebRtc_Word16 lastModeBGNonly = (inst->w16_mode & MODE_BGN_ONLY) != 0; /* check BGN flag */ void *mainInstBackup = inst->main_inst; #ifdef NETEQ_DELAY_LOGGING int i, j, temp_var; #endif WebRtc_Word16 dtmfValue = -1; WebRtc_Word16 dtmfVolume = -1; int playDtmf = 0; int dtmfSwitch = 0; #ifdef NETEQ_STEREO MasterSlaveInfo *msInfo = inst->msInfo; #endif WebRtc_Word16 *sharedMem = pw16_NetEqAlgorithm_buffer; /* Reuse memory SHARED_MEM_SIZE size */ inst->pw16_readAddress = sharedMem; inst->pw16_writeAddress = sharedMem; /* Get information about if there is one descriptor left */ if (inst->codec_ptr_inst.funcGetMDinfo != NULL) { MD = inst->codec_ptr_inst.funcGetMDinfo(inst->codec_ptr_inst.codec_state); if (MD > 0) MD = 1; else MD = 0; } #ifdef NETEQ_STEREO if ((msInfo->msMode == NETEQ_SLAVE) && (inst->codec_ptr_inst.funcDecode != NULL)) { /* * Valid function pointers indicate that we have decoded something, * and that the timestamp information is correct. */ /* Get the information from master to correct synchronization */ WebRtc_UWord32 currentMasterTimestamp; WebRtc_UWord32 currentSlaveTimestamp; currentMasterTimestamp = msInfo->endTimestamp - msInfo->samplesLeftWithOverlap; currentSlaveTimestamp = inst->endTimestamp - (inst->endPosition - inst->curPosition); if (currentSlaveTimestamp < currentMasterTimestamp) { /* brute-force discard a number of samples to catch up */ inst->curPosition += currentMasterTimestamp - currentSlaveTimestamp; /* make sure we have at least "overlap" samples left */ inst->curPosition = WEBRTC_SPL_MIN(inst->curPosition, inst->endPosition - inst->ExpandInst.w16_overlap); } else if (currentSlaveTimestamp > currentMasterTimestamp) { /* back off current position to slow down */ inst->curPosition -= currentSlaveTimestamp - currentMasterTimestamp; /* make sure we do not end up outside the speech history */ inst->curPosition = WEBRTC_SPL_MAX(inst->curPosition, 0); } } #endif /* Write status data to shared memory */ dspInfo->playedOutTS = inst->endTimestamp; dspInfo->samplesLeft = inst->endPosition - inst->curPosition - inst->ExpandInst.w16_overlap; dspInfo->MD = MD; dspInfo->lastMode = inst->w16_mode; dspInfo->frameLen = inst->w16_frameLen; /* Force update of codec if codec function is NULL */ if (inst->codec_ptr_inst.funcDecode == NULL) { dspInfo->lastMode |= MODE_AWAITING_CODEC_PTR; } #ifdef NETEQ_STEREO if (msInfo->msMode == NETEQ_SLAVE && (msInfo->extraInfo == DTMF_OVERDUB || msInfo->extraInfo == DTMF_ONLY)) { /* Signal that the master instance generated DTMF tones */ dspInfo->lastMode |= MODE_MASTER_DTMF_SIGNAL; } if (msInfo->msMode != NETEQ_MONO) { /* We are using stereo mode; signal this to MCU side */ dspInfo->lastMode |= MODE_USING_STEREO; } #endif WEBRTC_SPL_MEMCPY_W8(inst->pw16_writeAddress,dspInfo,sizeof(DSP2MCU_info_t)); /* Signal MCU with "interrupt" call to main inst*/ #ifdef NETEQ_STEREO assert(msInfo != NULL); if (msInfo->msMode == NETEQ_MASTER) { /* clear info to slave */ WebRtcSpl_MemSetW16((WebRtc_Word16 *) msInfo, 0, sizeof(MasterSlaveInfo) / sizeof(WebRtc_Word16)); /* re-set mode */ msInfo->msMode = NETEQ_MASTER; /* Store some information to slave */ msInfo->endTimestamp = inst->endTimestamp; msInfo->samplesLeftWithOverlap = inst->endPosition - inst->curPosition; } #endif /* * This call will trigger the MCU side to make a decision based on buffer contents and * decision history. Instructions, encoded data and function pointers will be written * to the shared memory. */ return_value = WebRtcNetEQ_DSP2MCUinterrupt((MainInst_t *) inst->main_inst, sharedMem); /* Read MCU data and instructions */ instr = (WebRtc_UWord16) (inst->pw16_readAddress[0] & 0xf000); #ifdef NETEQ_STEREO if (msInfo->msMode == NETEQ_MASTER) { msInfo->instruction = instr; } else if (msInfo->msMode == NETEQ_SLAVE) { /* Nothing to do */ } #endif /* check for error returned from MCU side, if so, return error */ if (return_value < 0) { inst->w16_mode = MODE_ERROR; dspInfo->lastMode = MODE_ERROR; return return_value; } blockPtr = &((inst->pw16_readAddress)[3]); /* Check for DTMF payload flag */ if ((inst->pw16_readAddress[0] & DSP_DTMF_PAYLOAD) != 0) { playDtmf = 1; dtmfValue = blockPtr[1]; dtmfVolume = blockPtr[2]; blockPtr += 3; #ifdef NETEQ_STEREO if (msInfo->msMode == NETEQ_MASTER) { /* signal to slave that master is using DTMF */ msInfo->extraInfo = DTMF_OVERDUB; } #endif } blockLen = (((*blockPtr) & DSP_CODEC_MASK_RED_FLAG) + 1) >> 1; /* In # of WebRtc_Word16 */ payloadLen = ((*blockPtr) & DSP_CODEC_MASK_RED_FLAG); blockPtr++; /* Do we have to change our decoder? */ if ((inst->pw16_readAddress[0] & 0x0f00) == DSP_CODEC_NEW_CODEC) { WEBRTC_SPL_MEMCPY_W16(&inst->codec_ptr_inst,blockPtr,(payloadLen+1)>>1); if (inst->codec_ptr_inst.codec_fs != 0) { return_value = WebRtcNetEQ_DSPInit(inst, inst->codec_ptr_inst.codec_fs); if (return_value != 0) { /* error returned */ instr = DSP_INSTR_FADE_TO_BGN; /* emergency instruction */ } #ifdef NETEQ_DELAY_LOGGING temp_var = NETEQ_DELAY_LOGGING_SIGNAL_CHANGE_FS; fwrite(&temp_var, sizeof(int), 1, delay_fid2); fwrite(&inst->fs, sizeof(WebRtc_UWord16), 1, delay_fid2); #endif } /* Copy it again since the init destroys this part */ WEBRTC_SPL_MEMCPY_W16(&inst->codec_ptr_inst,blockPtr,(payloadLen+1)>>1); inst->endTimestamp = inst->codec_ptr_inst.timeStamp; inst->videoSyncTimestamp = inst->codec_ptr_inst.timeStamp; blockPtr += blockLen; blockLen = (((*blockPtr) & DSP_CODEC_MASK_RED_FLAG) + 1) >> 1; payloadLen = ((*blockPtr) & DSP_CODEC_MASK_RED_FLAG); blockPtr++; if (inst->codec_ptr_inst.funcDecodeInit != NULL) { inst->codec_ptr_inst.funcDecodeInit(inst->codec_ptr_inst.codec_state); } #ifdef NETEQ_CNG_CODEC /* Also update the CNG state as this might be uninitialized */ WEBRTC_SPL_MEMCPY_W16(&inst->CNG_Codec_inst,blockPtr,(payloadLen+1)>>1); blockPtr += blockLen; blockLen = (((*blockPtr) & DSP_CODEC_MASK_RED_FLAG) + 1) >> 1; payloadLen = ((*blockPtr) & DSP_CODEC_MASK_RED_FLAG); blockPtr++; if (inst->CNG_Codec_inst != NULL) { WebRtcCng_InitDec(inst->CNG_Codec_inst); } #endif } else if ((inst->pw16_readAddress[0] & 0x0f00) == DSP_CODEC_RESET) { /* Reset the current codec (but not DSP struct) */ if (inst->codec_ptr_inst.funcDecodeInit != NULL) { inst->codec_ptr_inst.funcDecodeInit(inst->codec_ptr_inst.codec_state); } /* And reset CNG */ if (inst->CNG_Codec_inst != NULL) { WebRtcCng_InitDec(inst->CNG_Codec_inst); } } fs_mult = WebRtcNetEQ_CalcFsMult(inst->fs); /* Add late packet? */ if ((inst->pw16_readAddress[0] & 0x0f00) == DSP_CODEC_ADD_LATE_PKT) { if (inst->codec_ptr_inst.funcAddLatePkt != NULL) { /* Only do this if the codec has support for Add Late Pkt */ inst->codec_ptr_inst.funcAddLatePkt(inst->codec_ptr_inst.codec_state, blockPtr, payloadLen); } blockPtr += blockLen; blockLen = (((*blockPtr) & DSP_CODEC_MASK_RED_FLAG) + 1) >> 1; /* In # of Word16 */ payloadLen = ((*blockPtr) & DSP_CODEC_MASK_RED_FLAG); blockPtr++; } /* Do we have to decode data? */ if ((instr == DSP_INSTR_NORMAL) || (instr == DSP_INSTR_ACCELERATE) || (instr == DSP_INSTR_MERGE) || (instr == DSP_INSTR_PREEMPTIVE_EXPAND)) { /* Do we need to update codec-internal PLC state? */ if ((instr == DSP_INSTR_MERGE) && (inst->codec_ptr_inst.funcDecodePLC != NULL)) { len = 0; len = inst->codec_ptr_inst.funcDecodePLC(inst->codec_ptr_inst.codec_state, &pw16_decoded_buffer[len], 1); } len = 0; /* Do decoding */ while ((blockLen > 0) && (len < (240 * fs_mult))) /* Guard somewhat against overflow */ { if (inst->codec_ptr_inst.funcDecode != NULL) { WebRtc_Word16 dec_Len; if (!BGNonly) { /* Do decoding as normal * * blockPtr is pointing to payload, at this point, * the most significant bit of *(blockPtr - 1) is a flag if set to 1 * indicates that the following payload is the redundant payload. */ if (((*(blockPtr - 1) & DSP_CODEC_RED_FLAG) != 0) && (inst->codec_ptr_inst.funcDecodeRCU != NULL)) { dec_Len = inst->codec_ptr_inst.funcDecodeRCU( inst->codec_ptr_inst.codec_state, blockPtr, payloadLen, &pw16_decoded_buffer[len], &speechType); } else { dec_Len = inst->codec_ptr_inst.funcDecode( inst->codec_ptr_inst.codec_state, blockPtr, payloadLen, &pw16_decoded_buffer[len], &speechType); } } else { /* * Background noise mode: don't decode, just produce the same length BGN. * Don't call Expand for BGN here, since Expand uses the memory where the * bitstreams are stored (sharemem). */ dec_Len = inst->w16_frameLen; } if (dec_Len > 0) { len += dec_Len; /* Update frameLen */ inst->w16_frameLen = dec_Len; } else if (dec_Len < 0) { /* Error */ len = -1; break; } /* * Sanity check (although we might still write outside memory when this * happens...) */ if (len > NETEQ_MAX_FRAME_SIZE) { WebRtcSpl_MemSetW16(pw16_outData, 0, inst->timestampsPerCall); *pw16_len = inst->timestampsPerCall; inst->w16_mode = MODE_ERROR; dspInfo->lastMode = MODE_ERROR; return RECOUT_ERROR_DECODED_TOO_MUCH; } /* Verify that instance was not corrupted by decoder */ if (mainInstBackup != inst->main_inst) { /* Instance is corrupt */ return CORRUPT_INSTANCE; } } blockPtr += blockLen; blockLen = (((*blockPtr) & DSP_CODEC_MASK_RED_FLAG) + 1) >> 1; /* In # of Word16 */ payloadLen = ((*blockPtr) & DSP_CODEC_MASK_RED_FLAG); blockPtr++; } if (len < 0) { len = 0; inst->endTimestamp += inst->w16_frameLen; /* advance one frame */ if (inst->codec_ptr_inst.funcGetErrorCode != NULL) { return_value = -inst->codec_ptr_inst.funcGetErrorCode( inst->codec_ptr_inst.codec_state); } else { return_value = RECOUT_ERROR_DECODING; } instr = DSP_INSTR_FADE_TO_BGN; } if (speechType != TYPE_CNG) { /* * Don't increment timestamp if codec returned CNG speech type * since in this case, the MCU side will increment the CNGplayedTS counter. */ inst->endTimestamp += len; } } else if (instr == DSP_INSTR_NORMAL_ONE_DESC) { if (inst->codec_ptr_inst.funcDecode != NULL) { len = inst->codec_ptr_inst.funcDecode(inst->codec_ptr_inst.codec_state, NULL, 0, pw16_decoded_buffer, &speechType); #ifdef NETEQ_DELAY_LOGGING temp_var = NETEQ_DELAY_LOGGING_SIGNAL_DECODE_ONE_DESC; fwrite(&temp_var, sizeof(int), 1, delay_fid2); fwrite(&inst->endTimestamp, sizeof(WebRtc_UWord32), 1, delay_fid2); fwrite(&dspInfo->samplesLeft, sizeof(WebRtc_UWord16), 1, delay_fid2); tot_received_packets++; #endif } if (speechType != TYPE_CNG) { /* * Don't increment timestamp if codec returned CNG speech type * since in this case, the MCU side will increment the CNGplayedTS counter. */ inst->endTimestamp += len; } /* Verify that instance was not corrupted by decoder */ if (mainInstBackup != inst->main_inst) { /* Instance is corrupt */ return CORRUPT_INSTANCE; } if (len <= 0) { len = 0; if (inst->codec_ptr_inst.funcGetErrorCode != NULL) { return_value = -inst->codec_ptr_inst.funcGetErrorCode( inst->codec_ptr_inst.codec_state); } else { return_value = RECOUT_ERROR_DECODING; } if ((inst->codec_ptr_inst.funcDecodeInit != NULL) && (inst->codec_ptr_inst.codec_state != NULL)) { /* Reinitialize codec state as something is obviously wrong */ inst->codec_ptr_inst.funcDecodeInit(inst->codec_ptr_inst.codec_state); } inst->endTimestamp += inst->w16_frameLen; /* advance one frame */ instr = DSP_INSTR_FADE_TO_BGN; } } if (len == 0 && lastModeBGNonly) /* no new data */ { BGNonly = 1; /* force BGN this time too */ } #ifdef NETEQ_VAD if ((speechType == TYPE_CNG) /* decoder responded with codec-internal CNG */ || ((instr == DSP_INSTR_DO_RFC3389CNG) && (blockLen > 0)) /* ... or, SID frame */ || (inst->fs > 16000)) /* ... or, if not NB or WB */ { /* disable post-decode VAD upon first sign of send-side DTX/VAD active, or if SWB */ inst->VADInst.VADEnabled = 0; inst->VADInst.VADDecision = 1; /* set to always active, just to be on the safe side */ inst->VADInst.SIDintervalCounter = 0; /* reset SID interval counter */ } else if (!inst->VADInst.VADEnabled) /* VAD disabled and no SID/CNG data observed this time */ { inst->VADInst.SIDintervalCounter++; /* increase counter */ } /* check for re-enabling the VAD */ if (inst->VADInst.SIDintervalCounter >= POST_DECODE_VAD_AUTO_ENABLE) { /* * It's been a while since the last CNG/SID frame was observed => re-enable VAD. * (Do not care to look for a VAD instance, since this is done inside the init * function) */ WebRtcNetEQ_InitVAD(&inst->VADInst, inst->fs); } if (len > 0 /* if we decoded any data */ && inst->VADInst.VADEnabled /* and VAD enabled */ && inst->fs <= 16000) /* can only do VAD for NB and WB */ { int VADframeSize; /* VAD frame size in ms */ int VADSamplePtr = 0; inst->VADInst.VADDecision = 0; if (inst->VADInst.VADFunction != NULL) /* make sure that VAD function is provided */ { /* divide the data into groups, as large as possible */ for (VADframeSize = 30; VADframeSize >= 10; VADframeSize -= 10) { /* loop through 30, 20, 10 */ while (inst->VADInst.VADDecision == 0 && len - VADSamplePtr >= VADframeSize * fs_mult * 8) { /* * Only continue until first active speech found, and as long as there is * one VADframeSize left. */ /* call VAD with new decoded data */ inst->VADInst.VADDecision |= inst->VADInst.VADFunction( inst->VADInst.VADState, (WebRtc_Word16) inst->fs, (WebRtc_Word16 *) &pw16_decoded_buffer[VADSamplePtr], (WebRtc_Word16) (VADframeSize * fs_mult * 8)); VADSamplePtr += VADframeSize * fs_mult * 8; /* increment sample counter */ } } } else { /* VAD function is NULL */ inst->VADInst.VADDecision = 1; /* set decision to active */ inst->VADInst.VADEnabled = 0; /* disable VAD since we have no VAD function */ } } #endif /* NETEQ_VAD */ /* Adjust timestamp if needed */ uw16_tmp = (WebRtc_UWord16) inst->pw16_readAddress[1]; inst->endTimestamp += (((WebRtc_UWord32) uw16_tmp) << 16); uw16_tmp = (WebRtc_UWord16) inst->pw16_readAddress[2]; inst->endTimestamp += uw16_tmp; if (BGNonly && len > 0) { /* * If BGN mode, we did not produce any data at decoding. * Do it now instead. */ WebRtcNetEQ_GenerateBGN(inst, #ifdef SCRATCH pw16_scratchPtr + SCRATCH_NETEQ_EXPAND, #endif pw16_decoded_buffer, len); } /* Switch on the instruction received from the MCU side. */ switch (instr) { case DSP_INSTR_NORMAL: /* Allow for signal processing to apply gain-back etc */ WebRtcNetEQ_Normal(inst, #ifdef SCRATCH pw16_scratchPtr + SCRATCH_NETEQ_NORMAL, #endif pw16_decoded_buffer, len, pw16_NetEqAlgorithm_buffer, &len); /* If last packet was decoded as a inband CNG set mode to CNG instead */ if ((speechType == TYPE_CNG) || ((inst->w16_mode == MODE_CODEC_INTERNAL_CNG) && (len == 0))) { inst->w16_mode = MODE_CODEC_INTERNAL_CNG; } #ifdef NETEQ_ATEVENT_DECODE if (playDtmf == 0) { inst->DTMFInst.reinit = 1; } #endif break; case DSP_INSTR_NORMAL_ONE_DESC: /* Allow for signal processing to apply gain-back etc */ WebRtcNetEQ_Normal(inst, #ifdef SCRATCH pw16_scratchPtr + SCRATCH_NETEQ_NORMAL, #endif pw16_decoded_buffer, len, pw16_NetEqAlgorithm_buffer, &len); #ifdef NETEQ_ATEVENT_DECODE if (playDtmf == 0) { inst->DTMFInst.reinit = 1; } #endif inst->w16_mode = MODE_ONE_DESCRIPTOR; break; case DSP_INSTR_MERGE: #ifdef NETEQ_DELAY_LOGGING temp_var = NETEQ_DELAY_LOGGING_SIGNAL_MERGE_INFO; fwrite(&temp_var, sizeof(int), 1, delay_fid2); temp_var = -len; #endif /* Call Merge with history*/ return_value = WebRtcNetEQ_Merge(inst, #ifdef SCRATCH pw16_scratchPtr + SCRATCH_NETEQ_MERGE, #endif pw16_decoded_buffer, len, pw16_NetEqAlgorithm_buffer, &len); if (return_value < 0) { /* error */ return return_value; } #ifdef NETEQ_DELAY_LOGGING temp_var += len; fwrite(&temp_var, sizeof(int), 1, delay_fid2); #endif /* If last packet was decoded as a inband CNG set mode to CNG instead */ if (speechType == TYPE_CNG) inst->w16_mode = MODE_CODEC_INTERNAL_CNG; #ifdef NETEQ_ATEVENT_DECODE if (playDtmf == 0) { inst->DTMFInst.reinit = 1; } #endif break; case DSP_INSTR_EXPAND: len = 0; pos = 0; while ((inst->endPosition - inst->curPosition - inst->ExpandInst.w16_overlap + pos) < (inst->timestampsPerCall)) { return_value = WebRtcNetEQ_Expand(inst, #ifdef SCRATCH pw16_scratchPtr + SCRATCH_NETEQ_EXPAND, #endif pw16_NetEqAlgorithm_buffer, &len, BGNonly); if (return_value < 0) { /* error */ return return_value; } /* * Update buffer, but only end part (otherwise expand state is destroyed * since it reuses speechBuffer[] memory */ WEBRTC_SPL_MEMMOVE_W16(inst->pw16_speechHistory, inst->pw16_speechHistory + len, (inst->w16_speechHistoryLen-len)); WEBRTC_SPL_MEMCPY_W16(&inst->pw16_speechHistory[inst->w16_speechHistoryLen-len], pw16_NetEqAlgorithm_buffer, len); inst->curPosition -= len; /* Update variables for VQmon */ inst->w16_concealedTS += len; #ifdef NETEQ_DELAY_LOGGING temp_var = NETEQ_DELAY_LOGGING_SIGNAL_EXPAND_INFO; fwrite(&temp_var, sizeof(int), 1, delay_fid2); temp_var = len; fwrite(&temp_var, sizeof(int), 1, delay_fid2); #endif len = 0; /* already written the data, so do not write it again further down. */ } #ifdef NETEQ_ATEVENT_DECODE if (playDtmf == 0) { inst->DTMFInst.reinit = 1; } #endif break; case DSP_INSTR_ACCELERATE: if (len < 3 * 80 * fs_mult) { /* We need to move data from the speechBuffer[] in order to get 30 ms */ borrowedSamples = 3 * 80 * fs_mult - len; WEBRTC_SPL_MEMMOVE_W16(&pw16_decoded_buffer[borrowedSamples], pw16_decoded_buffer, len); WEBRTC_SPL_MEMCPY_W16(pw16_decoded_buffer, &(inst->speechBuffer[inst->endPosition-borrowedSamples]), borrowedSamples); return_value = WebRtcNetEQ_Accelerate(inst, #ifdef SCRATCH pw16_scratchPtr + SCRATCH_NETEQ_ACCELERATE, #endif pw16_decoded_buffer, 3 * inst->timestampsPerCall, pw16_NetEqAlgorithm_buffer, &len, BGNonly); if (return_value < 0) { /* error */ return return_value; } /* Copy back samples to the buffer */ if (len < borrowedSamples) { /* * This destroys the beginning of the buffer, but will not cause any * problems */ WEBRTC_SPL_MEMCPY_W16(&inst->speechBuffer[inst->endPosition-borrowedSamples], pw16_NetEqAlgorithm_buffer, len); WEBRTC_SPL_MEMMOVE_W16(&inst->speechBuffer[borrowedSamples-len], inst->speechBuffer, (inst->endPosition-(borrowedSamples-len))); inst->curPosition += (borrowedSamples - len); #ifdef NETEQ_DELAY_LOGGING temp_var = NETEQ_DELAY_LOGGING_SIGNAL_ACCELERATE_INFO; fwrite(&temp_var, sizeof(int), 1, delay_fid2); temp_var = 3 * inst->timestampsPerCall - len; fwrite(&temp_var, sizeof(int), 1, delay_fid2); #endif len = 0; } else { WEBRTC_SPL_MEMCPY_W16(&inst->speechBuffer[inst->endPosition-borrowedSamples], pw16_NetEqAlgorithm_buffer, borrowedSamples); WEBRTC_SPL_MEMMOVE_W16(pw16_NetEqAlgorithm_buffer, &pw16_NetEqAlgorithm_buffer[borrowedSamples], (len-borrowedSamples)); #ifdef NETEQ_DELAY_LOGGING temp_var = NETEQ_DELAY_LOGGING_SIGNAL_ACCELERATE_INFO; fwrite(&temp_var, sizeof(int), 1, delay_fid2); temp_var = 3 * inst->timestampsPerCall - len; fwrite(&temp_var, sizeof(int), 1, delay_fid2); #endif len = len - borrowedSamples; } } else { #ifdef NETEQ_DELAY_LOGGING temp_var = NETEQ_DELAY_LOGGING_SIGNAL_ACCELERATE_INFO; fwrite(&temp_var, sizeof(int), 1, delay_fid2); temp_var = len; #endif return_value = WebRtcNetEQ_Accelerate(inst, #ifdef SCRATCH pw16_scratchPtr + SCRATCH_NETEQ_ACCELERATE, #endif pw16_decoded_buffer, len, pw16_NetEqAlgorithm_buffer, &len, BGNonly); if (return_value < 0) { /* error */ return return_value; } #ifdef NETEQ_DELAY_LOGGING temp_var -= len; fwrite(&temp_var, sizeof(int), 1, delay_fid2); #endif } /* If last packet was decoded as a inband CNG set mode to CNG instead */ if (speechType == TYPE_CNG) inst->w16_mode = MODE_CODEC_INTERNAL_CNG; #ifdef NETEQ_ATEVENT_DECODE if (playDtmf == 0) { inst->DTMFInst.reinit = 1; } #endif break; case DSP_INSTR_DO_RFC3389CNG: #ifdef NETEQ_CNG_CODEC if (blockLen > 0) { if (WebRtcCng_UpdateSid(inst->CNG_Codec_inst, (WebRtc_UWord8*) blockPtr, payloadLen) < 0) { /* error returned from CNG function */ return_value = -WebRtcCng_GetErrorCodeDec(inst->CNG_Codec_inst); len = inst->timestampsPerCall; WebRtcSpl_MemSetW16(pw16_NetEqAlgorithm_buffer, 0, len); break; } } if (BGNonly) { /* Get data from BGN function instead of CNG */ len = WebRtcNetEQ_GenerateBGN(inst, #ifdef SCRATCH pw16_scratchPtr + SCRATCH_NETEQ_EXPAND, #endif pw16_NetEqAlgorithm_buffer, inst->timestampsPerCall); if (len != inst->timestampsPerCall) { /* this is not good, treat this as an error */ return_value = -1; } } else { return_value = WebRtcNetEQ_Cng(inst, pw16_NetEqAlgorithm_buffer, inst->timestampsPerCall); } len = inst->timestampsPerCall; inst->ExpandInst.w16_consecExp = 0; inst->w16_mode = MODE_RFC3389CNG; #ifdef NETEQ_ATEVENT_DECODE if (playDtmf == 0) { inst->DTMFInst.reinit = 1; } #endif if (return_value < 0) { /* error returned */ WebRtcSpl_MemSetW16(pw16_NetEqAlgorithm_buffer, 0, len); } break; #else return FAULTY_INSTRUCTION; #endif case DSP_INSTR_DO_CODEC_INTERNAL_CNG: /* * This represents the case when there is no transmission and the decoder should * do internal CNG. */ len = 0; if (inst->codec_ptr_inst.funcDecode != NULL && !BGNonly) { len = inst->codec_ptr_inst.funcDecode(inst->codec_ptr_inst.codec_state, blockPtr, 0, pw16_decoded_buffer, &speechType); } else { /* get BGN data */ len = WebRtcNetEQ_GenerateBGN(inst, #ifdef SCRATCH pw16_scratchPtr + SCRATCH_NETEQ_EXPAND, #endif pw16_decoded_buffer, inst->timestampsPerCall); } WebRtcNetEQ_Normal(inst, #ifdef SCRATCH pw16_scratchPtr + SCRATCH_NETEQ_NORMAL, #endif pw16_decoded_buffer, len, pw16_NetEqAlgorithm_buffer, &len); inst->w16_mode = MODE_CODEC_INTERNAL_CNG; inst->ExpandInst.w16_consecExp = 0; break; case DSP_INSTR_DTMF_GENERATE: #ifdef NETEQ_ATEVENT_DECODE dtmfSwitch = 0; if ((inst->w16_mode != MODE_DTMF) && (inst->DTMFInst.reinit == 0)) { /* Special case; see below. * We must catch this before calling DTMFGenerate, * since reinit is set to 0 in that call. */ dtmfSwitch = 1; } len = WebRtcNetEQ_DTMFGenerate(&inst->DTMFInst, dtmfValue, dtmfVolume, pw16_NetEqAlgorithm_buffer, inst->fs, -1); if (len < 0) { /* error occurred */ return_value = len; len = inst->timestampsPerCall; WebRtcSpl_MemSetW16(pw16_NetEqAlgorithm_buffer, 0, len); } if (dtmfSwitch == 1) { /* * This is the special case where the previous operation was DTMF overdub. * but the current instruction is "regular" DTMF. We must make sure that the * DTMF does not have any discontinuities. The first DTMF sample that we * generate now must be played out immediately, wherefore it must be copied to * the speech buffer. */ /* * Generate extra DTMF data to fill the space between * curPosition and endPosition */ WebRtc_Word16 tempLen; tempLen = WebRtcNetEQ_DTMFGenerate(&inst->DTMFInst, dtmfValue, dtmfVolume, &pw16_NetEqAlgorithm_buffer[len], inst->fs, inst->endPosition - inst->curPosition); if (tempLen < 0) { /* error occurred */ return_value = tempLen; len = inst->endPosition - inst->curPosition; WebRtcSpl_MemSetW16(pw16_NetEqAlgorithm_buffer, 0, inst->endPosition - inst->curPosition); } /* Add to total length */ len += tempLen; /* Overwrite the "future" part of the speech buffer with the new DTMF data */ WEBRTC_SPL_MEMCPY_W16(&inst->speechBuffer[inst->curPosition], pw16_NetEqAlgorithm_buffer, inst->endPosition - inst->curPosition); /* Shuffle the remaining data to the beginning of algorithm buffer */ len -= (inst->endPosition - inst->curPosition); WEBRTC_SPL_MEMMOVE_W16(pw16_NetEqAlgorithm_buffer, &pw16_NetEqAlgorithm_buffer[inst->endPosition - inst->curPosition], len); } inst->endTimestamp += inst->timestampsPerCall; inst->DTMFInst.reinit = 0; inst->ExpandInst.w16_consecExp = 0; inst->w16_mode = MODE_DTMF; BGNonly = 0; /* override BGN only and let DTMF through */ playDtmf = 0; /* set to zero because the DTMF is already in the Algorithm buffer */ /* * If playDtmf is 1, an extra DTMF vector will be generated and overdubbed * on the output. */ #ifdef NETEQ_STEREO if (msInfo->msMode == NETEQ_MASTER) { /* signal to slave that master is using DTMF only */ msInfo->extraInfo = DTMF_ONLY; } #endif break; #else inst->w16_mode = MODE_ERROR; dspInfo->lastMode = MODE_ERROR; return FAULTY_INSTRUCTION; #endif case DSP_INSTR_DO_ALTERNATIVE_PLC: if (inst->codec_ptr_inst.funcDecodePLC != 0) { len = inst->codec_ptr_inst.funcDecodePLC(inst->codec_ptr_inst.codec_state, pw16_NetEqAlgorithm_buffer, 1); } else { len = inst->timestampsPerCall; /* ZeroStuffing... */ WebRtcSpl_MemSetW16(pw16_NetEqAlgorithm_buffer, 0, len); } inst->ExpandInst.w16_consecExp = 0; break; case DSP_INSTR_DO_ALTERNATIVE_PLC_INC_TS: if (inst->codec_ptr_inst.funcDecodePLC != 0) { len = inst->codec_ptr_inst.funcDecodePLC(inst->codec_ptr_inst.codec_state, pw16_NetEqAlgorithm_buffer, 1); } else { len = inst->timestampsPerCall; /* ZeroStuffing... */ WebRtcSpl_MemSetW16(pw16_NetEqAlgorithm_buffer, 0, len); } inst->ExpandInst.w16_consecExp = 0; inst->endTimestamp += len; break; case DSP_INSTR_DO_AUDIO_REPETITION: len = inst->timestampsPerCall; /* copy->paste... */ WEBRTC_SPL_MEMCPY_W16(pw16_NetEqAlgorithm_buffer, &inst->speechBuffer[inst->endPosition-len], len); inst->ExpandInst.w16_consecExp = 0; break; case DSP_INSTR_DO_AUDIO_REPETITION_INC_TS: len = inst->timestampsPerCall; /* copy->paste... */ WEBRTC_SPL_MEMCPY_W16(pw16_NetEqAlgorithm_buffer, &inst->speechBuffer[inst->endPosition-len], len); inst->ExpandInst.w16_consecExp = 0; inst->endTimestamp += len; break; case DSP_INSTR_PREEMPTIVE_EXPAND: if (len < 3 * inst->timestampsPerCall) { /* borrow samples from sync buffer if necessary */ borrowedSamples = 3 * inst->timestampsPerCall - len; /* borrow this many samples */ /* calculate how many of these are already played out */ oldBorrowedSamples = WEBRTC_SPL_MAX(0, borrowedSamples - (inst->endPosition - inst->curPosition)); WEBRTC_SPL_MEMMOVE_W16(&pw16_decoded_buffer[borrowedSamples], pw16_decoded_buffer, len); WEBRTC_SPL_MEMCPY_W16(pw16_decoded_buffer, &(inst->speechBuffer[inst->endPosition-borrowedSamples]), borrowedSamples); } else { borrowedSamples = 0; oldBorrowedSamples = 0; } #ifdef NETEQ_DELAY_LOGGING w16_tmp1 = len; #endif /* do the expand */ return_value = WebRtcNetEQ_PreEmptiveExpand(inst, #ifdef SCRATCH /* use same scratch memory as Accelerate */ pw16_scratchPtr + SCRATCH_NETEQ_ACCELERATE, #endif pw16_decoded_buffer, len + borrowedSamples, oldBorrowedSamples, pw16_NetEqAlgorithm_buffer, &len, BGNonly); if (return_value < 0) { /* error */ return return_value; } if (borrowedSamples > 0) { /* return borrowed samples */ /* Copy back to last part of speechBuffer from beginning of output buffer */ WEBRTC_SPL_MEMCPY_W16( &(inst->speechBuffer[inst->endPosition-borrowedSamples]), pw16_NetEqAlgorithm_buffer, borrowedSamples); len -= borrowedSamples; /* remove the borrowed samples from new total length */ /* Move to beginning of output buffer from end of output buffer */ WEBRTC_SPL_MEMMOVE_W16( pw16_NetEqAlgorithm_buffer, &pw16_NetEqAlgorithm_buffer[borrowedSamples], len); } #ifdef NETEQ_DELAY_LOGGING temp_var = NETEQ_DELAY_LOGGING_SIGNAL_PREEMPTIVE_INFO; fwrite(&temp_var, sizeof(int), 1, delay_fid2); temp_var = len - w16_tmp1; /* number of samples added */ fwrite(&temp_var, sizeof(int), 1, delay_fid2); #endif /* If last packet was decoded as inband CNG, set mode to CNG instead */ if (speechType == TYPE_CNG) inst->w16_mode = MODE_CODEC_INTERNAL_CNG; #ifdef NETEQ_ATEVENT_DECODE if (playDtmf == 0) { inst->DTMFInst.reinit = 1; } #endif break; case DSP_INSTR_FADE_TO_BGN: { int tempReturnValue; /* do not overwrite return_value, since it likely contains an error code */ /* calculate interpolation length */ w16_tmp3 = WEBRTC_SPL_MIN(inst->endPosition - inst->curPosition, inst->timestampsPerCall); /* check that it will fit in pw16_NetEqAlgorithm_buffer */ if (w16_tmp3 + inst->w16_frameLen > NETEQ_MAX_OUTPUT_SIZE) { w16_tmp3 = NETEQ_MAX_OUTPUT_SIZE - inst->w16_frameLen; } /* call Expand */ len = inst->timestampsPerCall + inst->ExpandInst.w16_overlap; pos = 0; tempReturnValue = WebRtcNetEQ_Expand(inst, #ifdef SCRATCH pw16_scratchPtr + SCRATCH_NETEQ_EXPAND, #endif pw16_NetEqAlgorithm_buffer, &len, 1); if (tempReturnValue < 0) { /* error */ /* this error value will override return_value */ return tempReturnValue; } pos += len; /* got len samples from expand */ /* copy to fill the demand */ while (pos + len <= inst->w16_frameLen + w16_tmp3) { WEBRTC_SPL_MEMCPY_W16(&pw16_NetEqAlgorithm_buffer[pos], pw16_NetEqAlgorithm_buffer, len); pos += len; } /* fill with fraction of the expand vector if needed */ if (pos < inst->w16_frameLen + w16_tmp3) { WEBRTC_SPL_MEMCPY_W16(&pw16_NetEqAlgorithm_buffer[pos], pw16_NetEqAlgorithm_buffer, inst->w16_frameLen + w16_tmp3 - pos); } len = inst->w16_frameLen + w16_tmp3; /* truncate any surplus samples since we don't want these */ /* * Mix with contents in sync buffer. Find largest power of two that is less than * interpolate length divide 16384 with this number; result is in w16_tmp2. */ w16_tmp1 = 2; w16_tmp2 = 16384; while (w16_tmp1 <= w16_tmp3) { w16_tmp2 >>= 1; /* divide with 2 */ w16_tmp1 <<= 1; /* increase with a factor of 2 */ } w16_tmp1 = 0; pos = 0; while (w16_tmp1 < 16384) { inst->speechBuffer[inst->curPosition + pos] = (WebRtc_Word16) WEBRTC_SPL_RSHIFT_W32( WEBRTC_SPL_MUL_16_16( inst->speechBuffer[inst->endPosition - w16_tmp3 + pos], 16384-w16_tmp1 ) + WEBRTC_SPL_MUL_16_16( pw16_NetEqAlgorithm_buffer[pos], w16_tmp1 ), 14 ); w16_tmp1 += w16_tmp2; pos++; } /* overwrite remainder of speech buffer */ WEBRTC_SPL_MEMCPY_W16( &inst->speechBuffer[inst->endPosition - w16_tmp3 + pos], &pw16_NetEqAlgorithm_buffer[pos], w16_tmp3 - pos); len -= w16_tmp3; /* shift algorithm buffer */ WEBRTC_SPL_MEMMOVE_W16( pw16_NetEqAlgorithm_buffer, &pw16_NetEqAlgorithm_buffer[w16_tmp3], len ); /* Update variables for VQmon */ inst->w16_concealedTS += len; inst->w16_mode = MODE_FADE_TO_BGN; #ifdef NETEQ_DELAY_LOGGING temp_var = NETEQ_DELAY_LOGGING_SIGNAL_EXPAND_INFO; fwrite(&temp_var, sizeof(int), 1, delay_fid2); temp_var = len; fwrite(&temp_var, sizeof(int), 1, delay_fid2); #endif break; } default: inst->w16_mode = MODE_ERROR; dspInfo->lastMode = MODE_ERROR; return FAULTY_INSTRUCTION; } /* end of grand switch */ /* Copy data directly to output buffer */ w16_tmp2 = 0; if ((inst->endPosition + len - inst->curPosition - inst->ExpandInst.w16_overlap) >= inst->timestampsPerCall) { w16_tmp2 = inst->endPosition - inst->curPosition; w16_tmp2 = WEBRTC_SPL_MAX(w16_tmp2, 0); /* Additional error protection, just in case */ w16_tmp1 = WEBRTC_SPL_MIN(w16_tmp2, inst->timestampsPerCall); w16_tmp2 = inst->timestampsPerCall - w16_tmp1; WEBRTC_SPL_MEMCPY_W16(pw16_outData, &inst->speechBuffer[inst->curPosition], w16_tmp1); WEBRTC_SPL_MEMCPY_W16(&pw16_outData[w16_tmp1], pw16_NetEqAlgorithm_buffer, w16_tmp2); DataEnough = 1; } else { DataEnough = 0; } if (playDtmf != 0) { WebRtc_Word16 outDataIndex = 0; WebRtc_Word16 overdubLen = -1; /* default len */ WebRtc_Word16 dtmfLen; /* * Overdub the output with DTMF. Note that this is not executed if the * DSP_INSTR_DTMF_GENERATE operation is performed above. */ #ifdef NETEQ_ATEVENT_DECODE if (inst->DTMFInst.lastDtmfSample - inst->curPosition > 0) { /* special operation for transition from "DTMF only" to "DTMF overdub" */ outDataIndex = WEBRTC_SPL_MIN(inst->DTMFInst.lastDtmfSample - inst->curPosition, inst->timestampsPerCall); overdubLen = inst->timestampsPerCall - outDataIndex; } dtmfLen = WebRtcNetEQ_DTMFGenerate(&inst->DTMFInst, dtmfValue, dtmfVolume, &pw16_outData[outDataIndex], inst->fs, overdubLen); if (dtmfLen < 0) { /* error occurred */ return_value = dtmfLen; } inst->DTMFInst.reinit = 0; #else inst->w16_mode = MODE_ERROR; dspInfo->lastMode = MODE_ERROR; return FAULTY_INSTRUCTION; #endif } /* * Shuffle speech buffer to allow more data. Move data from pw16_NetEqAlgorithm_buffer * to speechBuffer. */ if (instr != DSP_INSTR_EXPAND) { w16_tmp1 = WEBRTC_SPL_MIN(inst->endPosition, len); WEBRTC_SPL_MEMMOVE_W16(inst->speechBuffer, inst->speechBuffer + w16_tmp1, (inst->endPosition-w16_tmp1)); WEBRTC_SPL_MEMCPY_W16(&inst->speechBuffer[inst->endPosition-w16_tmp1], &pw16_NetEqAlgorithm_buffer[len-w16_tmp1], w16_tmp1); #ifdef NETEQ_ATEVENT_DECODE /* Update index to end of DTMF data in speech buffer */ if (instr == DSP_INSTR_DTMF_GENERATE) { /* We have written DTMF data to the end of speech buffer */ inst->DTMFInst.lastDtmfSample = inst->endPosition; } else if (inst->DTMFInst.lastDtmfSample > 0) { /* The end of DTMF data in speech buffer has been shuffled */ inst->DTMFInst.lastDtmfSample -= w16_tmp1; } #endif /* * Update the BGN history if last operation was not expand (nor Merge, Accelerate * or Pre-emptive expand, to save complexity). */ if ((inst->w16_mode != MODE_EXPAND) && (inst->w16_mode != MODE_MERGE) && (inst->w16_mode != MODE_SUCCESS_ACCELERATE) && (inst->w16_mode != MODE_LOWEN_ACCELERATE) && (inst->w16_mode != MODE_SUCCESS_PREEMPTIVE) && (inst->w16_mode != MODE_LOWEN_PREEMPTIVE) && (inst->w16_mode != MODE_FADE_TO_BGN) && (inst->w16_mode != MODE_DTMF) && (!BGNonly)) { WebRtcNetEQ_BGNUpdate(inst #ifdef SCRATCH , pw16_scratchPtr + SCRATCH_NETEQ_BGN_UPDATE #endif ); } } else /* instr == DSP_INSTR_EXPAND */ { /* Nothing should be done since data is already copied to output. */ } inst->curPosition -= len; /* * Extra protection in case something should go totally wrong in terms of sizes... * If everything is ok this should NEVER happen. */ if (inst->curPosition < -inst->timestampsPerCall) { inst->curPosition = -inst->timestampsPerCall; } if ((instr != DSP_INSTR_EXPAND) && (instr != DSP_INSTR_MERGE) && (instr != DSP_INSTR_FADE_TO_BGN)) { /* Reset concealed TS parameter if it does not seem to have been flushed */ if (inst->w16_concealedTS > inst->timestampsPerCall) { inst->w16_concealedTS = 0; } } /* * Double-check that we actually have 10 ms to play. If we haven't, there has been a * serious error.The decoder might have returned way too few samples */ if (!DataEnough) { /* This should not happen. Set outdata to zeros, and return error. */ WebRtcSpl_MemSetW16(pw16_outData, 0, inst->timestampsPerCall); *pw16_len = inst->timestampsPerCall; inst->w16_mode = MODE_ERROR; dspInfo->lastMode = MODE_ERROR; return RECOUT_ERROR_SAMPLEUNDERRUN; } /* * Update Videosync timestamp (this special timestamp is needed since the endTimestamp * stops during CNG and Expand periods. */ if ((inst->w16_mode != MODE_EXPAND) && (inst->w16_mode != MODE_RFC3389CNG)) { WebRtc_UWord32 uw32_tmpTS; uw32_tmpTS = inst->endTimestamp - (inst->endPosition - inst->curPosition); if ((WebRtc_Word32) (uw32_tmpTS - inst->videoSyncTimestamp) > 0) { inst->videoSyncTimestamp = uw32_tmpTS; } } else { inst->videoSyncTimestamp += inst->timestampsPerCall; } /* After this, regardless of what has happened, deliver 10 ms of future data */ inst->curPosition += inst->timestampsPerCall; *pw16_len = inst->timestampsPerCall; /* Remember if BGNonly was used */ if (BGNonly) { inst->w16_mode |= MODE_BGN_ONLY; } return return_value; } #undef SCRATCH_ALGORITHM_BUFFER #undef SCRATCH_NETEQ_NORMAL #undef SCRATCH_NETEQ_MERGE #undef SCRATCH_NETEQ_BGN_UPDATE #undef SCRATCH_NETEQ_EXPAND #undef SCRATCH_DSP_INFO #undef SCRATCH_NETEQ_ACCELERATE #undef SIZE_SCRATCH_BUFFER