git-svn-id: http://webrtc.googlecode.com/svn/trunk@4 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
838
modules/audio_coding/NetEQ/main/source/signal_mcu.c
Normal file
838
modules/audio_coding/NetEQ/main/source/signal_mcu.c
Normal file
@@ -0,0 +1,838 @@
|
||||
/*
|
||||
* 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 <string.h>
|
||||
|
||||
#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 <stdio.h>
|
||||
|
||||
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;
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user