/* * 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. */ /* * Signal the MCU that data is available and ask for a RecOut decision. */ #include "mcu.h" #include #include "signal_processing_library.h" #include "automode.h" #include "dtmf_buffer.h" #include "mcu_dsp_common.h" #include "neteq_error_codes.h" #ifdef NETEQ_DELAY_LOGGING #include "delay_logging.h" #include extern FILE *delay_fid2; /* file pointer to delay log file */ #endif /* * Signals the MCU that DSP status data is available. */ int WebRtcNetEQ_SignalMcu(MCUInst_t *inst) { int i_bufferpos, i_res; WebRtc_UWord16 uw16_instr; DSP2MCU_info_t dspInfo; WebRtc_Word16 *blockPtr, blockLen; WebRtc_UWord32 uw32_availableTS; RTPPacket_t temp_pkt; WebRtc_Word32 w32_bufsize, w32_tmp; WebRtc_Word16 payloadType = -1; WebRtc_Word16 wantedNoOfTimeStamps; WebRtc_Word32 totalTS; WebRtc_Word16 oldPT, latePacketExist = 0; WebRtc_UWord32 oldTS, prevTS, uw32_tmp; WebRtc_UWord16 prevSeqNo; WebRtc_Word16 nextSeqNoAvail; WebRtc_Word16 fs_mult, w16_tmp; WebRtc_Word16 lastModeBGNonly = 0; #ifdef NETEQ_DELAY_LOGGING int temp_var; #endif int playDtmf = 0; fs_mult = WebRtcSpl_DivW32W16ResW16(inst->fs, 8000); /* Increment counter since last statistics report */ inst->lastReportTS += inst->timestampsPerCall; /* Read info from DSP so we now current status */ WEBRTC_SPL_MEMCPY_W8(&dspInfo,inst->pw16_readAddress,sizeof(DSP2MCU_info_t)); /* Set blockPtr to first payload block */ blockPtr = &inst->pw16_writeAddress[3]; /* Clear instruction word and number of lost samples (2*WebRtc_Word16) */ inst->pw16_writeAddress[0] = 0; inst->pw16_writeAddress[1] = 0; inst->pw16_writeAddress[2] = 0; if ((dspInfo.lastMode & MODE_AWAITING_CODEC_PTR) != 0) { /* * Make sure state is adjusted so that a codec update is * performed when first packet arrives. */ if (inst->new_codec != 1) { inst->current_Codec = -1; } dspInfo.lastMode = (dspInfo.lastMode ^ MODE_AWAITING_CODEC_PTR); } #ifdef NETEQ_STEREO if ((dspInfo.lastMode & MODE_MASTER_DTMF_SIGNAL) != 0) { playDtmf = 1; /* force DTMF decision */ dspInfo.lastMode = (dspInfo.lastMode ^ MODE_MASTER_DTMF_SIGNAL); } if ((dspInfo.lastMode & MODE_USING_STEREO) != 0) { if (inst->usingStereo == 0) { /* stereo mode changed; reset automode instance to re-synchronize statistics */ WebRtcNetEQ_ResetAutomode(&(inst->BufferStat_inst.Automode_inst), inst->PacketBuffer_inst.maxInsertPositions); } inst->usingStereo = 1; dspInfo.lastMode = (dspInfo.lastMode ^ MODE_USING_STEREO); } else { inst->usingStereo = 0; } #endif /* detect if BGN_ONLY flag is set in lastMode */ if ((dspInfo.lastMode & MODE_BGN_ONLY) != 0) { lastModeBGNonly = 1; /* remember flag */ dspInfo.lastMode ^= MODE_BGN_ONLY; /* clear the flag */ } if ((dspInfo.lastMode == MODE_RFC3389CNG) || (dspInfo.lastMode == MODE_CODEC_INTERNAL_CNG) || (dspInfo.lastMode == MODE_EXPAND)) { /* * If last mode was CNG (or Expand, since this could be covering up for a lost CNG * packet), increase the CNGplayedTS counter. */ inst->BufferStat_inst.uw32_CNGplayedTS += inst->timestampsPerCall; if (dspInfo.lastMode == MODE_RFC3389CNG) { /* remember that RFC3389CNG is on (needed if CNG is interrupted by DTMF) */ inst->BufferStat_inst.w16_cngOn = CNG_RFC3389_ON; } else if (dspInfo.lastMode == MODE_CODEC_INTERNAL_CNG) { /* remember that internal CNG is on (needed if CNG is interrupted by DTMF) */ inst->BufferStat_inst.w16_cngOn = CNG_INTERNAL_ON; } } /* Update packet size from previously decoded packet */ if (dspInfo.frameLen > 0) { inst->PacketBuffer_inst.packSizeSamples = dspInfo.frameLen; } /* Look for late packet (unless codec has changed) */ if (inst->new_codec != 1) { if (WebRtcNetEQ_DbIsMDCodec((enum WebRtcNetEQDecoder) inst->current_Codec)) { WebRtcNetEQ_PacketBufferFindLowestTimestamp(&inst->PacketBuffer_inst, inst->timeStamp, &uw32_availableTS, &i_bufferpos, 1, &payloadType); if ((inst->new_codec != 1) && (inst->timeStamp == uw32_availableTS) && (inst->timeStamp < dspInfo.playedOutTS) && (i_bufferpos != -1) && (WebRtcNetEQ_DbGetPayload(&(inst->codec_DB_inst), (enum WebRtcNetEQDecoder) inst->current_Codec) == payloadType)) { temp_pkt.payload = blockPtr + 1; i_res = WebRtcNetEQ_PacketBufferExtract(&inst->PacketBuffer_inst, &temp_pkt, i_bufferpos); if (i_res < 0) { /* error returned */ return i_res; } *blockPtr = temp_pkt.payloadLen; /* set the flag if this is a redundant payload */ if (temp_pkt.rcuPlCntr > 0) { *blockPtr = (*blockPtr) | (DSP_CODEC_RED_FLAG); } blockPtr += ((temp_pkt.payloadLen + 1) >> 1) + 1; /* * Close the data with a zero size block, in case we will not write any * more data. */ *blockPtr = 0; inst->pw16_writeAddress[0] = (inst->pw16_writeAddress[0] & 0xf0ff) | DSP_CODEC_ADD_LATE_PKT; latePacketExist = 1; } } } i_res = WebRtcNetEQ_PacketBufferFindLowestTimestamp(&inst->PacketBuffer_inst, dspInfo.playedOutTS, &uw32_availableTS, &i_bufferpos, (inst->new_codec == 0), &payloadType); if (i_res < 0) { /* error returned */ return i_res; } if (inst->BufferStat_inst.w16_cngOn == CNG_RFC3389_ON) { /* * Because of timestamp peculiarities, we have to "manually" disallow using a CNG * packet with the same timestamp as the one that was last played. This can happen * when using redundancy and will cause the timing to shift. */ while (i_bufferpos != -1 && WebRtcNetEQ_DbIsCNGPayload(&inst->codec_DB_inst, payloadType) && dspInfo.playedOutTS >= uw32_availableTS) { /* Don't use this packet, discard it */ inst->PacketBuffer_inst.payloadType[i_bufferpos] = -1; inst->PacketBuffer_inst.payloadLengthBytes[i_bufferpos] = 0; inst->PacketBuffer_inst.numPacketsInBuffer--; /* Check buffer again */ WebRtcNetEQ_PacketBufferFindLowestTimestamp(&inst->PacketBuffer_inst, dspInfo.playedOutTS, &uw32_availableTS, &i_bufferpos, (inst->new_codec == 0), &payloadType); } } /* Check packet buffer */ w32_bufsize = WebRtcNetEQ_PacketBufferGetSize(&inst->PacketBuffer_inst); if (dspInfo.lastMode == MODE_SUCCESS_ACCELERATE || dspInfo.lastMode == MODE_LOWEN_ACCELERATE || dspInfo.lastMode == MODE_SUCCESS_PREEMPTIVE || dspInfo.lastMode == MODE_LOWEN_PREEMPTIVE) { /* Subtract (dspInfo.samplesLeft + inst->timestampsPerCall) from sampleMemory */ inst->BufferStat_inst.Automode_inst.sampleMemory -= dspInfo.samplesLeft + inst->timestampsPerCall; /* Update post-call statistics */ inst->statInst.jbChangeCount++; } /* calculate total current buffer size (in ms*8), including sync buffer */ w32_bufsize = WebRtcSpl_DivW32W16((w32_bufsize + dspInfo.samplesLeft), fs_mult); if (((WebRtc_UWord32) w32_bufsize >> 3) < inst->statInst.jbMinSize) { /* new all-time low */ inst->statInst.jbMinSize = ((WebRtc_UWord32) w32_bufsize >> 3); /* shift to ms */ } if (((WebRtc_UWord32) w32_bufsize >> 3) > inst->statInst.jbMaxSize) { /* new all-time high */ inst->statInst.jbMaxSize = ((WebRtc_UWord32) w32_bufsize >> 3); /* shift to ms */ } /* Update avg bufsize: * jbAvgSize = (jbAvgCount * jbAvgSize + w32_bufsize/8)/(jbAvgCount+1) * with proper rounding */ { WebRtc_Word32 avgTmp; /* Simplify the above formula to: * jbAvgSizeQ16 = * jbAvgSizeQ16 + ( (w32_bufsize/8 << 16) - jbAvgSizeQ16 + d ) / (jbAvgCount+1) * where d = jbAvgCount/2 for proper rounding. */ avgTmp = (((WebRtc_UWord32) w32_bufsize >> 3) << 16) - inst->statInst.jbAvgSizeQ16; avgTmp = WEBRTC_SPL_DIV( avgTmp + (inst->statInst.jbAvgCount>>1), inst->statInst.jbAvgCount + 1 ); inst->statInst.jbAvgSizeQ16 += avgTmp; if (inst->statInst.jbAvgCount < (0xFFFF - 1)) { inst->statInst.jbAvgCount++; } } #ifdef NETEQ_ATEVENT_DECODE /* DTMF data will affect the decision */ if (WebRtcNetEQ_DtmfDecode(&inst->DTMF_inst, blockPtr + 1, blockPtr + 2, dspInfo.playedOutTS + inst->BufferStat_inst.uw32_CNGplayedTS) > 0) { playDtmf = 1; /* Flag DTMF payload */ inst->pw16_writeAddress[0] = inst->pw16_writeAddress[0] | DSP_DTMF_PAYLOAD; /* Block Length in bytes */ blockPtr[0] = 4; /* Advance to next payload position */ blockPtr += 3; } #endif /* Update statistics and make decision */ uw16_instr = WebRtcNetEQ_BufstatsDecision(&inst->BufferStat_inst, inst->PacketBuffer_inst.packSizeSamples, w32_bufsize, dspInfo.playedOutTS, uw32_availableTS, i_bufferpos == -1, WebRtcNetEQ_DbIsCNGPayload(&inst->codec_DB_inst, payloadType), dspInfo.lastMode, inst->NetEqPlayoutMode, inst->timestampsPerCall, inst->NoOfExpandCalls, fs_mult, lastModeBGNonly, playDtmf); /* Check if time to reset loss counter */ if (inst->lastReportTS > WEBRTC_SPL_UMUL(inst->fs, MAX_LOSS_REPORT_PERIOD)) { /* reset loss counter */ WebRtcNetEQ_ResetMcuInCallStats(inst); } /* Check sync buffer size */ if ((dspInfo.samplesLeft >= inst->timestampsPerCall) && (uw16_instr != BUFSTATS_DO_ACCELERATE) && (uw16_instr != BUFSTATS_DO_MERGE) && (uw16_instr != BUFSTATS_DO_PREEMPTIVE_EXPAND)) { *blockPtr = 0; inst->pw16_writeAddress[0] = (inst->pw16_writeAddress[0] & 0x0fff) | DSP_INSTR_NORMAL; return 0; } if (uw16_instr == BUFSTATS_DO_EXPAND) { inst->NoOfExpandCalls++; } else { /* update post-call statistics */ WebRtc_UWord32 expandTime = WEBRTC_SPL_UDIV(WEBRTC_SPL_UMUL_32_16( WEBRTC_SPL_UMUL_32_16((WebRtc_UWord32) inst->NoOfExpandCalls, (WebRtc_UWord16) 1000), inst->timestampsPerCall), inst->fs); /* expand time in ms */ if (expandTime > 2000) { inst->statInst.countExpandMoreThan2000ms++; } else if (expandTime > 500) { inst->statInst.countExpandMoreThan500ms++; } else if (expandTime > 250) { inst->statInst.countExpandMoreThan250ms++; } else if (expandTime > 120) { inst->statInst.countExpandMoreThan120ms++; } if (expandTime > inst->statInst.longestExpandDurationMs) { inst->statInst.longestExpandDurationMs = expandTime; } /* reset counter */ inst->NoOfExpandCalls = 0; } /* New codec or big change in packet number? */ if (((inst->new_codec) || (uw16_instr == BUFSTAT_REINIT)) && (uw16_instr != BUFSTATS_DO_EXPAND)) { CodecFuncInst_t cinst; /* Clear other instructions */ blockPtr = &inst->pw16_writeAddress[3]; /* Clear instruction word */ inst->pw16_writeAddress[0] = 0; inst->timeStamp = uw32_availableTS; dspInfo.playedOutTS = uw32_availableTS; if (inst->current_Codec != -1) { i_res = WebRtcNetEQ_DbGetPtrs(&inst->codec_DB_inst, (enum WebRtcNetEQDecoder) inst->current_Codec, &cinst); if (i_res < 0) { /* error returned */ return i_res; } } else { /* The main codec has not been initialized yet (first packets are DTMF or CNG). */ if (WebRtcNetEQ_DbIsCNGPayload(&inst->codec_DB_inst, payloadType)) { /* The currently extracted packet is CNG; get CNG fs */ WebRtc_UWord16 tempFs; tempFs = WebRtcNetEQ_DbGetSampleRate(&inst->codec_DB_inst, payloadType); if (tempFs > 0) { inst->fs = tempFs; } } WebRtcSpl_MemSetW16((WebRtc_Word16*) &cinst, 0, sizeof(CodecFuncInst_t) / sizeof(WebRtc_Word16)); cinst.codec_fs = inst->fs; } cinst.timeStamp = inst->timeStamp; blockLen = (sizeof(CodecFuncInst_t)) >> (sizeof(WebRtc_Word16) - 1); /* in Word16 */ *blockPtr = blockLen * 2; blockPtr++; WEBRTC_SPL_MEMCPY_W8(blockPtr,&cinst,sizeof(CodecFuncInst_t)); blockPtr += blockLen; inst->new_codec = 0; /* Reinitialize the MCU fs */ i_res = WebRtcNetEQ_McuSetFs(inst, cinst.codec_fs); if (i_res < 0) { /* error returned */ return i_res; } /* Set the packet size by guessing */ inst->PacketBuffer_inst.packSizeSamples = inst->timestampsPerCall * 3; WebRtcNetEQ_ResetAutomode(&(inst->BufferStat_inst.Automode_inst), inst->PacketBuffer_inst.maxInsertPositions); #ifdef NETEQ_CNG_CODEC /* Also insert CNG state as this might be needed by DSP */ i_res = WebRtcNetEQ_DbGetPtrs(&inst->codec_DB_inst, kDecoderCNG, &cinst); if ((i_res < 0) && (i_res != CODEC_DB_NOT_EXIST1)) { /* other error returned */ /* (CODEC_DB_NOT_EXIST1 simply indicates that CNG is not used */ return i_res; } else { /* CNG exists */ blockLen = (sizeof(cinst.codec_state)) >> (sizeof(WebRtc_Word16) - 1); *blockPtr = blockLen * 2; blockPtr++; WEBRTC_SPL_MEMCPY_W8(blockPtr,&cinst.codec_state,sizeof(cinst.codec_state)); blockPtr += blockLen; } #endif inst->pw16_writeAddress[0] = (inst->pw16_writeAddress[0] & 0xf0ff) | DSP_CODEC_NEW_CODEC; if (uw16_instr == BUFSTATS_DO_RFC3389CNG_NOPACKET) { /* * Change decision to CNG packet, since we do have a CNG packet, but it was * considered too early to use. Now, use it anyway. */ uw16_instr = BUFSTATS_DO_RFC3389CNG_PACKET; } else if (uw16_instr != BUFSTATS_DO_RFC3389CNG_PACKET) { uw16_instr = BUFSTATS_DO_NORMAL; } /* reset loss counter */ WebRtcNetEQ_ResetMcuInCallStats(inst); } /* Should we just reset the decoder? */ if (uw16_instr == BUFSTAT_REINIT_DECODER) { /* Change decision to normal and flag decoder reset */ uw16_instr = BUFSTATS_DO_NORMAL; inst->pw16_writeAddress[0] = (inst->pw16_writeAddress[0] & 0xf0ff) | DSP_CODEC_RESET; } /* Expand requires no new packet */ if (uw16_instr == BUFSTATS_DO_EXPAND) { inst->timeStamp = dspInfo.playedOutTS; /* Have we got one descriptor left? */ if (WebRtcNetEQ_DbIsMDCodec((enum WebRtcNetEQDecoder) inst->current_Codec) && (dspInfo.MD || latePacketExist)) { if (dspInfo.lastMode != MODE_ONE_DESCRIPTOR) { /* this is the first "consecutive" one-descriptor decoding; reset counter */ inst->one_desc = 0; } if (inst->one_desc < MAX_ONE_DESC) { /* use that one descriptor */ inst->one_desc++; /* increase counter */ inst->pw16_writeAddress[0] = (inst->pw16_writeAddress[0] & 0x0fff) | DSP_INSTR_NORMAL_ONE_DESC; /* decrease counter since we did no Expand */ inst->NoOfExpandCalls = WEBRTC_SPL_MAX(inst->NoOfExpandCalls - 1, 0); return 0; } else { /* too many consecutive one-descriptor decodings; do expand instead */ inst->one_desc = 0; /* reset counter */ } } inst->pw16_writeAddress[0] = (inst->pw16_writeAddress[0] & 0x0fff) | DSP_INSTR_EXPAND; return 0; } /* Merge is not needed if we still have a descriptor */ if ((uw16_instr == BUFSTATS_DO_MERGE) && (dspInfo.MD != 0)) { inst->pw16_writeAddress[0] = (inst->pw16_writeAddress[0] & 0x0fff) | DSP_INSTR_NORMAL_ONE_DESC; *blockPtr = 0; return 0; } /* Do CNG without trying to extract any packets from buffer */ if (uw16_instr == BUFSTATS_DO_RFC3389CNG_NOPACKET) { inst->pw16_writeAddress[0] = (inst->pw16_writeAddress[0] & 0x0fff) | DSP_INSTR_DO_RFC3389CNG; *blockPtr = 0; return 0; } /* Do built-in CNG without extracting any new packets from buffer */ if (uw16_instr == BUFSTATS_DO_INTERNAL_CNG_NOPACKET) { inst->pw16_writeAddress[0] = (inst->pw16_writeAddress[0] & 0x0fff) | DSP_INSTR_DO_CODEC_INTERNAL_CNG; *blockPtr = 0; return 0; } /* Do DTMF without extracting any new packets from buffer */ if (uw16_instr == BUFSTATS_DO_DTMF_ONLY) { WebRtc_UWord32 timeStampJump = 0; /* Update timestamp */ if ((inst->BufferStat_inst.uw32_CNGplayedTS > 0) && (dspInfo.lastMode != MODE_DTMF)) { /* Jump in timestamps if needed */ timeStampJump = inst->BufferStat_inst.uw32_CNGplayedTS; inst->pw16_writeAddress[1] = (WebRtc_UWord16) (timeStampJump >> 16); inst->pw16_writeAddress[2] = (WebRtc_UWord16) (timeStampJump & 0xFFFF); } inst->timeStamp = dspInfo.playedOutTS + timeStampJump; /* update post-call statistics (since we will reset the CNG counter) */ inst->statInst.generatedSilentMs += WEBRTC_SPL_UDIV( WEBRTC_SPL_UMUL_32_16(inst->BufferStat_inst.uw32_CNGplayedTS, (WebRtc_UWord16) 1000), inst->fs); inst->BufferStat_inst.uw32_CNGplayedTS = 0; inst->NoOfExpandCalls = 0; inst->pw16_writeAddress[0] = (inst->pw16_writeAddress[0] & 0x0fff) | DSP_INSTR_DTMF_GENERATE; *blockPtr = 0; return 0; } if (uw16_instr == BUFSTATS_DO_ACCELERATE) { /* In order to do a Accelerate we need at least 30 ms of data */ if (dspInfo.samplesLeft >= (3 * 80 * fs_mult)) { /* Already have enough data, so we do not need to extract any more */ inst->pw16_writeAddress[0] = (inst->pw16_writeAddress[0] & 0x0fff) | DSP_INSTR_ACCELERATE; *blockPtr = 0; inst->BufferStat_inst.Automode_inst.sampleMemory = (WebRtc_Word32) dspInfo.samplesLeft; inst->BufferStat_inst.Automode_inst.prevTimeScale = 1; return 0; } else if ((dspInfo.samplesLeft >= (1 * 80 * fs_mult)) && (inst->PacketBuffer_inst.packSizeSamples >= (240 * fs_mult))) { /* Avoid decoding more data as it might overflow playout buffer */ inst->pw16_writeAddress[0] = (inst->pw16_writeAddress[0] & 0x0fff) | DSP_INSTR_NORMAL; *blockPtr = 0; return 0; } else if ((dspInfo.samplesLeft < (1 * 80 * fs_mult)) && (inst->PacketBuffer_inst.packSizeSamples >= (240 * fs_mult))) { /* For >= 30ms allow Accelerate with a decoding to avoid overflow in playout buffer */ wantedNoOfTimeStamps = inst->timestampsPerCall; } else if (dspInfo.samplesLeft >= (2 * 80 * fs_mult)) { /* We need to decode another 10 ms in order to do an Accelerate */ wantedNoOfTimeStamps = inst->timestampsPerCall; } else { /* * Build up decoded data by decoding at least 20 ms of data. * Do not perform Accelerate yet, but wait until we only need to do one decoding. */ wantedNoOfTimeStamps = 2 * inst->timestampsPerCall; uw16_instr = BUFSTATS_DO_NORMAL; } } else if (uw16_instr == BUFSTATS_DO_PREEMPTIVE_EXPAND) { /* In order to do a Preemptive Expand we need at least 30 ms of data */ if (dspInfo.samplesLeft >= (3 * 80 * fs_mult)) { /* Already have enough data, so we do not need to extract any more */ inst->pw16_writeAddress[0] = (inst->pw16_writeAddress[0] & 0x0fff) | DSP_INSTR_PREEMPTIVE_EXPAND; *blockPtr = 0; inst->BufferStat_inst.Automode_inst.sampleMemory = (WebRtc_Word32) dspInfo.samplesLeft; inst->BufferStat_inst.Automode_inst.prevTimeScale = 1; return 0; } else if ((dspInfo.samplesLeft >= (1 * 80 * fs_mult)) && (inst->PacketBuffer_inst.packSizeSamples >= (240 * fs_mult))) { /* * Avoid decoding more data as it might overflow playout buffer; * still try Preemptive Expand though. */ inst->pw16_writeAddress[0] = (inst->pw16_writeAddress[0] & 0x0fff) | DSP_INSTR_PREEMPTIVE_EXPAND; *blockPtr = 0; inst->BufferStat_inst.Automode_inst.sampleMemory = (WebRtc_Word32) dspInfo.samplesLeft; inst->BufferStat_inst.Automode_inst.prevTimeScale = 1; return 0; } else if ((dspInfo.samplesLeft < (1 * 80 * fs_mult)) && (inst->PacketBuffer_inst.packSizeSamples >= (240 * fs_mult))) { /* * For >= 30ms allow Preemptive Expand with a decoding to avoid overflow in * playout buffer */ wantedNoOfTimeStamps = inst->timestampsPerCall; } else if (dspInfo.samplesLeft >= (2 * 80 * fs_mult)) { /* We need to decode another 10 ms in order to do an Preemptive Expand */ wantedNoOfTimeStamps = inst->timestampsPerCall; } else { /* * Build up decoded data by decoding at least 20 ms of data, * Still try to perform Preemptive Expand. */ wantedNoOfTimeStamps = 2 * inst->timestampsPerCall; } } else { wantedNoOfTimeStamps = inst->timestampsPerCall; } /* Otherwise get data from buffer, try to get at least 10ms */ totalTS = 0; oldTS = uw32_availableTS; if ((i_bufferpos > -1) && (uw16_instr != BUFSTATS_DO_ALTERNATIVE_PLC) && (uw16_instr != BUFSTATS_DO_ALTERNATIVE_PLC_INC_TS) && (uw16_instr != BUFSTATS_DO_AUDIO_REPETITION) && (uw16_instr != BUFSTATS_DO_AUDIO_REPETITION_INC_TS)) { uw32_tmp = (uw32_availableTS - dspInfo.playedOutTS); inst->pw16_writeAddress[1] = (WebRtc_UWord16) (uw32_tmp >> 16); inst->pw16_writeAddress[2] = (WebRtc_UWord16) (uw32_tmp & 0xFFFF); if (inst->BufferStat_inst.w16_cngOn == CNG_OFF) { /* * Adjustment of TS only corresponds to an actual packet loss * if comfort noise is not played. If comfort noise was just played, * this adjustment of TS is only done to get back in sync with the * stream TS; no loss to report. */ inst->lostTS += uw32_tmp; } if (uw16_instr != BUFSTATS_DO_RFC3389CNG_PACKET) { /* We are about to decode and use a non-CNG packet => CNG period is ended */ inst->BufferStat_inst.w16_cngOn = CNG_OFF; } /* update post-call statistics */ inst->statInst.generatedSilentMs += WEBRTC_SPL_UDIV( WEBRTC_SPL_UMUL_32_16(inst->BufferStat_inst.uw32_CNGplayedTS, (WebRtc_UWord16) 1000), inst->fs); /* * Reset CNG timestamp as a new packet will be delivered. * (Also if CNG packet, since playedOutTS is updated.) */ inst->BufferStat_inst.uw32_CNGplayedTS = 0; prevSeqNo = inst->PacketBuffer_inst.seqNumber[i_bufferpos]; prevTS = inst->PacketBuffer_inst.timeStamp[i_bufferpos]; oldPT = inst->PacketBuffer_inst.payloadType[i_bufferpos]; /* clear flag bits */ inst->pw16_writeAddress[0] = inst->pw16_writeAddress[0] & 0xFF3F; do { inst->timeStamp = uw32_availableTS; /* Write directly to shared memory */ temp_pkt.payload = blockPtr + 1; i_res = WebRtcNetEQ_PacketBufferExtract(&inst->PacketBuffer_inst, &temp_pkt, i_bufferpos); if (i_res < 0) { /* error returned */ return i_res; } #ifdef NETEQ_DELAY_LOGGING temp_var = NETEQ_DELAY_LOGGING_SIGNAL_DECODE; fwrite(&temp_var,sizeof(int),1,delay_fid2); fwrite(&temp_pkt.timeStamp,sizeof(WebRtc_UWord32),1,delay_fid2); fwrite(&dspInfo.samplesLeft, sizeof(WebRtc_UWord16), 1, delay_fid2); #endif *blockPtr = temp_pkt.payloadLen; /* set the flag if this is a redundant payload */ if (temp_pkt.rcuPlCntr > 0) { *blockPtr = (*blockPtr) | (DSP_CODEC_RED_FLAG); } blockPtr += ((temp_pkt.payloadLen + 1) >> 1) + 1; if (i_bufferpos > -1) { /* * Store number of TS extracted (last extracted is assumed to be of * packSizeSamples). */ totalTS = uw32_availableTS - oldTS + inst->PacketBuffer_inst.packSizeSamples; } /* Check what next packet is available */ WebRtcNetEQ_PacketBufferFindLowestTimestamp(&inst->PacketBuffer_inst, inst->timeStamp, &uw32_availableTS, &i_bufferpos, 0, &payloadType); nextSeqNoAvail = 0; if ((i_bufferpos > -1) && (oldPT == inst->PacketBuffer_inst.payloadType[i_bufferpos])) { w16_tmp = inst->PacketBuffer_inst.seqNumber[i_bufferpos] - prevSeqNo; w32_tmp = inst->PacketBuffer_inst.timeStamp[i_bufferpos] - prevTS; if ((w16_tmp == 1) || /* Next packet */ ((w16_tmp == 0) && (w32_tmp == inst->PacketBuffer_inst.packSizeSamples))) { /* or packet split into frames */ nextSeqNoAvail = 1; } prevSeqNo = inst->PacketBuffer_inst.seqNumber[i_bufferpos]; } } while ((totalTS < wantedNoOfTimeStamps) && (nextSeqNoAvail == 1)); } if ((uw16_instr == BUFSTATS_DO_ACCELERATE) || (uw16_instr == BUFSTATS_DO_PREEMPTIVE_EXPAND)) { /* Check that we have enough data (30ms) to do the Accelearate */ if ((totalTS + dspInfo.samplesLeft) < WEBRTC_SPL_MUL(3,inst->timestampsPerCall) && (uw16_instr == BUFSTATS_DO_ACCELERATE)) { /* Not enough, do normal operation instead */ uw16_instr = BUFSTATS_DO_NORMAL; } else { inst->BufferStat_inst.Automode_inst.sampleMemory = (WebRtc_Word32) dspInfo.samplesLeft + totalTS; inst->BufferStat_inst.Automode_inst.prevTimeScale = 1; } } /* Close the data with a zero size block */ *blockPtr = 0; /* Write data to DSP */ switch (uw16_instr) { case BUFSTATS_DO_NORMAL: /* Normal with decoding included */ inst->pw16_writeAddress[0] = (inst->pw16_writeAddress[0] & 0x0fff) | DSP_INSTR_NORMAL; break; case BUFSTATS_DO_ACCELERATE: inst->pw16_writeAddress[0] = (inst->pw16_writeAddress[0] & 0x0fff) | DSP_INSTR_ACCELERATE; break; case BUFSTATS_DO_MERGE: inst->pw16_writeAddress[0] = (inst->pw16_writeAddress[0] & 0x0fff) | DSP_INSTR_MERGE; break; case BUFSTATS_DO_RFC3389CNG_PACKET: inst->pw16_writeAddress[0] = (inst->pw16_writeAddress[0] & 0x0fff) | DSP_INSTR_DO_RFC3389CNG; break; case BUFSTATS_DO_ALTERNATIVE_PLC: inst->pw16_writeAddress[1] = 0; inst->pw16_writeAddress[0] = (inst->pw16_writeAddress[0] & 0x0fff) | DSP_INSTR_DO_ALTERNATIVE_PLC; break; case BUFSTATS_DO_ALTERNATIVE_PLC_INC_TS: inst->pw16_writeAddress[1] = 0; inst->pw16_writeAddress[0] = (inst->pw16_writeAddress[0] & 0x0fff) | DSP_INSTR_DO_ALTERNATIVE_PLC_INC_TS; break; case BUFSTATS_DO_AUDIO_REPETITION: inst->pw16_writeAddress[1] = 0; inst->pw16_writeAddress[0] = (inst->pw16_writeAddress[0] & 0x0fff) | DSP_INSTR_DO_AUDIO_REPETITION; break; case BUFSTATS_DO_AUDIO_REPETITION_INC_TS: inst->pw16_writeAddress[1] = 0; inst->pw16_writeAddress[0] = (inst->pw16_writeAddress[0] & 0x0fff) | DSP_INSTR_DO_AUDIO_REPETITION_INC_TS; break; case BUFSTATS_DO_PREEMPTIVE_EXPAND: inst->pw16_writeAddress[0] = (inst->pw16_writeAddress[0] & 0x0fff) | DSP_INSTR_PREEMPTIVE_EXPAND; break; default: return UNKNOWN_BUFSTAT_DECISION; } inst->timeStamp = dspInfo.playedOutTS; return 0; }