1762 lines
55 KiB
C
1762 lines
55 KiB
C
|
/*
|
||
|
* 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 main NetEQ API.
|
||
|
*/
|
||
|
|
||
|
#include "webrtc_neteq.h"
|
||
|
#include "webrtc_neteq_internal.h"
|
||
|
|
||
|
#include <string.h>
|
||
|
|
||
|
#include "typedefs.h"
|
||
|
#include "signal_processing_library.h"
|
||
|
|
||
|
#include "neteq_error_codes.h"
|
||
|
#include "mcu_dsp_common.h"
|
||
|
#include "rtcp.h"
|
||
|
|
||
|
#define RETURN_ON_ERROR( macroExpr, macroInstPtr ) { \
|
||
|
if ((macroExpr) != 0) { \
|
||
|
if ((macroExpr) == -1) { \
|
||
|
(macroInstPtr)->ErrorCode = - (NETEQ_OTHER_ERROR); \
|
||
|
} else { \
|
||
|
(macroInstPtr)->ErrorCode = -((WebRtc_Word16) (macroExpr)); \
|
||
|
} \
|
||
|
return(-1); \
|
||
|
} }
|
||
|
|
||
|
int WebRtcNetEQ_strncpy(WebRtc_Word8 *strDest, int numberOfElements,
|
||
|
const WebRtc_Word8 *strSource, int count)
|
||
|
{
|
||
|
/* check vector lengths */
|
||
|
if (count > numberOfElements)
|
||
|
{
|
||
|
strDest[0] = '\0';
|
||
|
return (-1);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
strncpy(strDest, strSource, count);
|
||
|
return (0);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**********************************************************
|
||
|
* NETEQ Functions
|
||
|
*/
|
||
|
|
||
|
/*****************************************
|
||
|
* Info functions
|
||
|
*/
|
||
|
|
||
|
int WebRtcNetEQ_GetVersion(WebRtc_Word8 *version)
|
||
|
{
|
||
|
char versionString[] = "3.3.0\0 ";
|
||
|
char endChar[] = " ";
|
||
|
int i = 0;
|
||
|
while ((versionString[i] != endChar[0]) && (i <= 20))
|
||
|
{
|
||
|
version[i] = versionString[i]; /* To avoid using strcpy */
|
||
|
i++;
|
||
|
}
|
||
|
return (0);
|
||
|
}
|
||
|
|
||
|
int WebRtcNetEQ_GetErrorCode(void *inst)
|
||
|
{
|
||
|
MainInst_t *NetEqMainInst = (MainInst_t*) inst;
|
||
|
if (NetEqMainInst == NULL) return (-1);
|
||
|
return (NetEqMainInst->ErrorCode);
|
||
|
}
|
||
|
|
||
|
int WebRtcNetEQ_GetErrorName(int errorCode, WebRtc_Word8 *errorName, int maxStrLen)
|
||
|
{
|
||
|
if ((errorName == NULL) || (maxStrLen <= 0))
|
||
|
{
|
||
|
return (-1);
|
||
|
}
|
||
|
|
||
|
if (errorCode < 0)
|
||
|
{
|
||
|
errorCode = -errorCode; // absolute value
|
||
|
}
|
||
|
|
||
|
switch (errorCode)
|
||
|
{
|
||
|
case 1: // could be -1
|
||
|
{
|
||
|
WebRtcNetEQ_strncpy(errorName, maxStrLen, "OTHER_ERROR", maxStrLen);
|
||
|
break;
|
||
|
}
|
||
|
case 1001:
|
||
|
{
|
||
|
WebRtcNetEQ_strncpy(errorName, maxStrLen, "FAULTY_INSTRUCTION", maxStrLen);
|
||
|
break;
|
||
|
}
|
||
|
case 1002:
|
||
|
{
|
||
|
WebRtcNetEQ_strncpy(errorName, maxStrLen, "FAULTY_NETWORK_TYPE", maxStrLen);
|
||
|
break;
|
||
|
}
|
||
|
case 1003:
|
||
|
{
|
||
|
WebRtcNetEQ_strncpy(errorName, maxStrLen, "FAULTY_DELAYVALUE", maxStrLen);
|
||
|
break;
|
||
|
}
|
||
|
case 1004:
|
||
|
{
|
||
|
WebRtcNetEQ_strncpy(errorName, maxStrLen, "FAULTY_PLAYOUTMODE", maxStrLen);
|
||
|
break;
|
||
|
}
|
||
|
case 1005:
|
||
|
{
|
||
|
WebRtcNetEQ_strncpy(errorName, maxStrLen, "CORRUPT_INSTANCE", maxStrLen);
|
||
|
break;
|
||
|
}
|
||
|
case 1006:
|
||
|
{
|
||
|
WebRtcNetEQ_strncpy(errorName, maxStrLen, "ILLEGAL_MASTER_SLAVE_SWITCH", maxStrLen);
|
||
|
break;
|
||
|
}
|
||
|
case 1007:
|
||
|
{
|
||
|
WebRtcNetEQ_strncpy(errorName, maxStrLen, "MASTER_SLAVE_ERROR", maxStrLen);
|
||
|
break;
|
||
|
}
|
||
|
case 2001:
|
||
|
{
|
||
|
WebRtcNetEQ_strncpy(errorName, maxStrLen, "UNKNOWN_BUFSTAT_DECISION", maxStrLen);
|
||
|
break;
|
||
|
}
|
||
|
case 2002:
|
||
|
{
|
||
|
WebRtcNetEQ_strncpy(errorName, maxStrLen, "RECOUT_ERROR_DECODING", maxStrLen);
|
||
|
break;
|
||
|
}
|
||
|
case 2003:
|
||
|
{
|
||
|
WebRtcNetEQ_strncpy(errorName, maxStrLen, "RECOUT_ERROR_SAMPLEUNDERRUN", maxStrLen);
|
||
|
break;
|
||
|
}
|
||
|
case 2004:
|
||
|
{
|
||
|
WebRtcNetEQ_strncpy(errorName, maxStrLen, "RECOUT_ERROR_DECODED_TOO_MUCH",
|
||
|
maxStrLen);
|
||
|
break;
|
||
|
}
|
||
|
case 3001:
|
||
|
{
|
||
|
WebRtcNetEQ_strncpy(errorName, maxStrLen, "RECIN_CNG_ERROR", maxStrLen);
|
||
|
break;
|
||
|
}
|
||
|
case 3002:
|
||
|
{
|
||
|
WebRtcNetEQ_strncpy(errorName, maxStrLen, "RECIN_UNKNOWNPAYLOAD", maxStrLen);
|
||
|
break;
|
||
|
}
|
||
|
case 3003:
|
||
|
{
|
||
|
WebRtcNetEQ_strncpy(errorName, maxStrLen, "RECIN_BUFFERINSERT_ERROR", maxStrLen);
|
||
|
break;
|
||
|
}
|
||
|
case 4001:
|
||
|
{
|
||
|
WebRtcNetEQ_strncpy(errorName, maxStrLen, "PBUFFER_INIT_ERROR", maxStrLen);
|
||
|
break;
|
||
|
}
|
||
|
case 4002:
|
||
|
case 4003:
|
||
|
case 4004:
|
||
|
case 4005:
|
||
|
case 4006:
|
||
|
{
|
||
|
WebRtcNetEQ_strncpy(errorName, maxStrLen, "PBUFFER_INSERT_ERROR1", maxStrLen);
|
||
|
break;
|
||
|
}
|
||
|
case 4007:
|
||
|
{
|
||
|
WebRtcNetEQ_strncpy(errorName, maxStrLen, "UNKNOWN_G723_HEADER", maxStrLen);
|
||
|
break;
|
||
|
}
|
||
|
case 4008:
|
||
|
{
|
||
|
WebRtcNetEQ_strncpy(errorName, maxStrLen, "PBUFFER_NONEXISTING_PACKET", maxStrLen);
|
||
|
break;
|
||
|
}
|
||
|
case 4009:
|
||
|
{
|
||
|
WebRtcNetEQ_strncpy(errorName, maxStrLen, "PBUFFER_NOT_INITIALIZED", maxStrLen);
|
||
|
break;
|
||
|
}
|
||
|
case 4010:
|
||
|
{
|
||
|
WebRtcNetEQ_strncpy(errorName, maxStrLen, "AMBIGUOUS_ILBC_FRAME_SIZE", maxStrLen);
|
||
|
break;
|
||
|
}
|
||
|
case 5001:
|
||
|
{
|
||
|
WebRtcNetEQ_strncpy(errorName, maxStrLen, "CODEC_DB_FULL", maxStrLen);
|
||
|
break;
|
||
|
}
|
||
|
case 5002:
|
||
|
case 5003:
|
||
|
case 5004:
|
||
|
case 5005:
|
||
|
{
|
||
|
WebRtcNetEQ_strncpy(errorName, maxStrLen, "CODEC_DB_NOT_EXIST", maxStrLen);
|
||
|
break;
|
||
|
}
|
||
|
case 5006:
|
||
|
{
|
||
|
WebRtcNetEQ_strncpy(errorName, maxStrLen, "CODEC_DB_UNKNOWN_CODEC", maxStrLen);
|
||
|
break;
|
||
|
}
|
||
|
case 5007:
|
||
|
{
|
||
|
WebRtcNetEQ_strncpy(errorName, maxStrLen, "CODEC_DB_PAYLOAD_TAKEN", maxStrLen);
|
||
|
break;
|
||
|
}
|
||
|
case 5008:
|
||
|
{
|
||
|
WebRtcNetEQ_strncpy(errorName, maxStrLen, "CODEC_DB_UNSUPPORTED_CODEC", maxStrLen);
|
||
|
break;
|
||
|
}
|
||
|
case 5009:
|
||
|
{
|
||
|
WebRtcNetEQ_strncpy(errorName, maxStrLen, "CODEC_DB_UNSUPPORTED_FS", maxStrLen);
|
||
|
break;
|
||
|
}
|
||
|
case 6001:
|
||
|
{
|
||
|
WebRtcNetEQ_strncpy(errorName, maxStrLen, "DTMF_DEC_PARAMETER_ERROR", maxStrLen);
|
||
|
break;
|
||
|
}
|
||
|
case 6002:
|
||
|
{
|
||
|
WebRtcNetEQ_strncpy(errorName, maxStrLen, "DTMF_INSERT_ERROR", maxStrLen);
|
||
|
break;
|
||
|
}
|
||
|
case 6003:
|
||
|
{
|
||
|
WebRtcNetEQ_strncpy(errorName, maxStrLen, "DTMF_GEN_UNKNOWN_SAMP_FREQ", maxStrLen);
|
||
|
break;
|
||
|
}
|
||
|
case 6004:
|
||
|
{
|
||
|
WebRtcNetEQ_strncpy(errorName, maxStrLen, "DTMF_NOT_SUPPORTED", maxStrLen);
|
||
|
break;
|
||
|
}
|
||
|
case 7001:
|
||
|
case 7002:
|
||
|
{
|
||
|
WebRtcNetEQ_strncpy(errorName, maxStrLen, "RED_SPLIT_ERROR", maxStrLen);
|
||
|
break;
|
||
|
}
|
||
|
case 7003:
|
||
|
{
|
||
|
WebRtcNetEQ_strncpy(errorName, maxStrLen, "RTP_TOO_SHORT_PACKET", maxStrLen);
|
||
|
break;
|
||
|
}
|
||
|
case 7004:
|
||
|
{
|
||
|
WebRtcNetEQ_strncpy(errorName, maxStrLen, "RTP_CORRUPT_PACKET", maxStrLen);
|
||
|
break;
|
||
|
}
|
||
|
default:
|
||
|
{
|
||
|
/* check for decoder error ranges */
|
||
|
if (errorCode >= 6010 && errorCode <= 6810)
|
||
|
{
|
||
|
/* iSAC error code */
|
||
|
WebRtcNetEQ_strncpy(errorName, maxStrLen, "iSAC ERROR", maxStrLen);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
WebRtcNetEQ_strncpy(errorName, maxStrLen, "UNKNOWN_ERROR", maxStrLen);
|
||
|
return (-1);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return (0);
|
||
|
}
|
||
|
|
||
|
/* Assign functions (create not allowed in order to avoid malloc in lib) */
|
||
|
int WebRtcNetEQ_AssignSize(int *sizeinbytes)
|
||
|
{
|
||
|
*sizeinbytes = (sizeof(MainInst_t) * 2) / sizeof(WebRtc_Word16);
|
||
|
return (0);
|
||
|
}
|
||
|
|
||
|
int WebRtcNetEQ_Assign(void **inst, void *NETEQ_inst_Addr)
|
||
|
{
|
||
|
int ok = 0;
|
||
|
MainInst_t *NetEqMainInst = (MainInst_t*) NETEQ_inst_Addr;
|
||
|
*inst = NETEQ_inst_Addr;
|
||
|
if (*inst == NULL) return (-1);
|
||
|
/* Clear memory */
|
||
|
WebRtcSpl_MemSetW16((WebRtc_Word16*) NetEqMainInst, 0,
|
||
|
(sizeof(MainInst_t) / sizeof(WebRtc_Word16)));
|
||
|
ok = WebRtcNetEQ_McuReset(&NetEqMainInst->MCUinst);
|
||
|
if (ok != 0)
|
||
|
{
|
||
|
NetEqMainInst->ErrorCode = -ok;
|
||
|
return (-1);
|
||
|
}
|
||
|
return (0);
|
||
|
}
|
||
|
|
||
|
int WebRtcNetEQ_GetRecommendedBufferSize(void *inst, enum WebRtcNetEQDecoder *codec,
|
||
|
int noOfCodecs, enum WebRtcNetEQNetworkType nwType,
|
||
|
int *MaxNoOfPackets, int *sizeinbytes)
|
||
|
{
|
||
|
int ok = 0;
|
||
|
int multiplier;
|
||
|
MainInst_t *NetEqMainInst = (MainInst_t*) inst;
|
||
|
if (NetEqMainInst == NULL) return (-1);
|
||
|
*MaxNoOfPackets = 0;
|
||
|
*sizeinbytes = 0;
|
||
|
ok = WebRtcNetEQ_GetDefaultCodecSettings(codec, noOfCodecs, sizeinbytes, MaxNoOfPackets);
|
||
|
if (ok != 0)
|
||
|
{
|
||
|
NetEqMainInst->ErrorCode = -ok;
|
||
|
return (-1);
|
||
|
}
|
||
|
if (nwType == kUDPNormal)
|
||
|
{
|
||
|
multiplier = 1;
|
||
|
}
|
||
|
else if (nwType == kUDPVideoSync)
|
||
|
{
|
||
|
multiplier = 4;
|
||
|
}
|
||
|
else if (nwType == kTCPNormal)
|
||
|
{
|
||
|
multiplier = 4;
|
||
|
}
|
||
|
else if (nwType == kTCPLargeJitter)
|
||
|
{
|
||
|
multiplier = 8;
|
||
|
}
|
||
|
else if (nwType == kTCPXLargeJitter)
|
||
|
{
|
||
|
multiplier = 20;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
NetEqMainInst->ErrorCode = -FAULTY_NETWORK_TYPE;
|
||
|
return (-1);
|
||
|
}
|
||
|
*MaxNoOfPackets = (*MaxNoOfPackets) * multiplier;
|
||
|
*sizeinbytes = (*sizeinbytes) * multiplier;
|
||
|
if (ok != 0)
|
||
|
{
|
||
|
NetEqMainInst->ErrorCode = -ok;
|
||
|
return (-1);
|
||
|
}
|
||
|
return (ok);
|
||
|
}
|
||
|
|
||
|
int WebRtcNetEQ_AssignBuffer(void *inst, int MaxNoOfPackets, void *NETEQ_Buffer_Addr,
|
||
|
int sizeinbytes)
|
||
|
{
|
||
|
int ok;
|
||
|
MainInst_t *NetEqMainInst = (MainInst_t*) inst;
|
||
|
if (NetEqMainInst == NULL) return (-1);
|
||
|
ok = WebRtcNetEQ_PacketBufferInit(&NetEqMainInst->MCUinst.PacketBuffer_inst,
|
||
|
MaxNoOfPackets, (WebRtc_Word16*) NETEQ_Buffer_Addr, (sizeinbytes >> 1));
|
||
|
if (ok != 0)
|
||
|
{
|
||
|
NetEqMainInst->ErrorCode = -ok;
|
||
|
return (-1);
|
||
|
}
|
||
|
return (ok);
|
||
|
}
|
||
|
|
||
|
/************************************************
|
||
|
* Init functions
|
||
|
*/
|
||
|
|
||
|
/****************************************************************************
|
||
|
* WebRtcNetEQ_Init(...)
|
||
|
*
|
||
|
* Initialize NetEQ.
|
||
|
*
|
||
|
* Input:
|
||
|
* - inst : NetEQ instance
|
||
|
* - fs : Initial sample rate in Hz (may change with payload)
|
||
|
*
|
||
|
* Output:
|
||
|
* - inst : Initialized NetEQ instance
|
||
|
*
|
||
|
* Return value : 0 - Ok
|
||
|
* -1 - Error
|
||
|
*/
|
||
|
|
||
|
int WebRtcNetEQ_Init(void *inst, WebRtc_UWord16 fs)
|
||
|
{
|
||
|
int ok = 0;
|
||
|
|
||
|
/* Typecast inst to internal instance format */
|
||
|
MainInst_t *NetEqMainInst = (MainInst_t*) inst;
|
||
|
|
||
|
if (NetEqMainInst == NULL)
|
||
|
{
|
||
|
return (-1);
|
||
|
}
|
||
|
|
||
|
#ifdef NETEQ_VAD
|
||
|
/* Start out with no PostDecode VAD instance */
|
||
|
NetEqMainInst->DSPinst.VADInst.VADState = NULL;
|
||
|
/* Also set all VAD function pointers to NULL */
|
||
|
NetEqMainInst->DSPinst.VADInst.initFunction = NULL;
|
||
|
NetEqMainInst->DSPinst.VADInst.setmodeFunction = NULL;
|
||
|
NetEqMainInst->DSPinst.VADInst.VADFunction = NULL;
|
||
|
#endif /* NETEQ_VAD */
|
||
|
|
||
|
ok = WebRtcNetEQ_DSPinit(NetEqMainInst); /* Init addresses between MCU and DSP */
|
||
|
RETURN_ON_ERROR(ok, NetEqMainInst);
|
||
|
|
||
|
ok = WebRtcNetEQ_DSPInit(&NetEqMainInst->DSPinst, fs); /* Init dsp side */
|
||
|
RETURN_ON_ERROR(ok, NetEqMainInst);
|
||
|
/* set BGN mode to default, since it is not cleared by DSP init function */
|
||
|
NetEqMainInst->DSPinst.BGNInst.bgnMode = BGN_ON;
|
||
|
|
||
|
/* init statistics functions and counters */
|
||
|
ok = WebRtcNetEQ_ClearInCallStats(&NetEqMainInst->DSPinst);
|
||
|
RETURN_ON_ERROR(ok, NetEqMainInst);
|
||
|
ok = WebRtcNetEQ_ClearPostCallStats(&NetEqMainInst->DSPinst);
|
||
|
RETURN_ON_ERROR(ok, NetEqMainInst);
|
||
|
ok = WebRtcNetEQ_ResetMcuJitterStat(&NetEqMainInst->MCUinst);
|
||
|
RETURN_ON_ERROR(ok, NetEqMainInst);
|
||
|
|
||
|
/* flush packet buffer */
|
||
|
ok = WebRtcNetEQ_PacketBufferFlush(&NetEqMainInst->MCUinst.PacketBuffer_inst);
|
||
|
RETURN_ON_ERROR(ok, NetEqMainInst);
|
||
|
|
||
|
/* set some variables to initial values */
|
||
|
NetEqMainInst->MCUinst.current_Codec = -1;
|
||
|
NetEqMainInst->MCUinst.current_Payload = -1;
|
||
|
NetEqMainInst->MCUinst.first_packet = 1;
|
||
|
NetEqMainInst->MCUinst.one_desc = 0;
|
||
|
NetEqMainInst->MCUinst.BufferStat_inst.Automode_inst.extraDelayMs = 0;
|
||
|
NetEqMainInst->MCUinst.NoOfExpandCalls = 0;
|
||
|
NetEqMainInst->MCUinst.fs = fs;
|
||
|
|
||
|
#ifdef NETEQ_ATEVENT_DECODE
|
||
|
/* init DTMF decoder */
|
||
|
ok = WebRtcNetEQ_DtmfDecoderInit(&(NetEqMainInst->MCUinst.DTMF_inst),fs,560);
|
||
|
RETURN_ON_ERROR(ok, NetEqMainInst);
|
||
|
#endif
|
||
|
|
||
|
/* init RTCP statistics */
|
||
|
WebRtcNetEQ_RTCPInit(&(NetEqMainInst->MCUinst.RTCP_inst), 0);
|
||
|
|
||
|
/* set BufferStat struct to zero */
|
||
|
WebRtcSpl_MemSetW16((WebRtc_Word16*) &(NetEqMainInst->MCUinst.BufferStat_inst), 0,
|
||
|
sizeof(BufstatsInst_t) / sizeof(WebRtc_Word16));
|
||
|
|
||
|
/* reset automode */
|
||
|
WebRtcNetEQ_ResetAutomode(&(NetEqMainInst->MCUinst.BufferStat_inst.Automode_inst),
|
||
|
NetEqMainInst->MCUinst.PacketBuffer_inst.maxInsertPositions);
|
||
|
|
||
|
NetEqMainInst->ErrorCode = 0;
|
||
|
|
||
|
#ifdef NETEQ_STEREO
|
||
|
/* set master/slave info to undecided */
|
||
|
NetEqMainInst->masterSlave = 0;
|
||
|
#endif
|
||
|
|
||
|
return (ok);
|
||
|
}
|
||
|
|
||
|
int WebRtcNetEQ_FlushBuffers(void *inst)
|
||
|
{
|
||
|
int ok = 0;
|
||
|
|
||
|
/* Typecast inst to internal instance format */
|
||
|
MainInst_t *NetEqMainInst = (MainInst_t*) inst;
|
||
|
|
||
|
if (NetEqMainInst == NULL)
|
||
|
{
|
||
|
return (-1);
|
||
|
}
|
||
|
|
||
|
/* Flush packet buffer */
|
||
|
ok = WebRtcNetEQ_PacketBufferFlush(&NetEqMainInst->MCUinst.PacketBuffer_inst);
|
||
|
RETURN_ON_ERROR(ok, NetEqMainInst);
|
||
|
|
||
|
/* Set MCU to wait for new codec */
|
||
|
NetEqMainInst->MCUinst.first_packet = 1;
|
||
|
|
||
|
/* Flush speech buffer */
|
||
|
ok = WebRtcNetEQ_FlushSpeechBuffer(&NetEqMainInst->DSPinst);
|
||
|
RETURN_ON_ERROR(ok, NetEqMainInst);
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
int WebRtcNetEQ_SetAVTPlayout(void *inst, int PlayoutAVTon)
|
||
|
{
|
||
|
MainInst_t *NetEqMainInst = (MainInst_t*) inst;
|
||
|
if (NetEqMainInst == NULL) return (-1);
|
||
|
#ifdef NETEQ_ATEVENT_DECODE
|
||
|
NetEqMainInst->MCUinst.AVT_PlayoutOn = PlayoutAVTon;
|
||
|
return(0);
|
||
|
#else
|
||
|
if (PlayoutAVTon != 0)
|
||
|
{
|
||
|
NetEqMainInst->ErrorCode = -DTMF_NOT_SUPPORTED;
|
||
|
return (-1);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
return (0);
|
||
|
}
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
int WebRtcNetEQ_SetExtraDelay(void *inst, int DelayInMs)
|
||
|
{
|
||
|
MainInst_t *NetEqMainInst = (MainInst_t*) inst;
|
||
|
if (NetEqMainInst == NULL) return (-1);
|
||
|
if ((DelayInMs < 0) || (DelayInMs > 1000))
|
||
|
{
|
||
|
NetEqMainInst->ErrorCode = -FAULTY_DELAYVALUE;
|
||
|
return (-1);
|
||
|
}
|
||
|
NetEqMainInst->MCUinst.BufferStat_inst.Automode_inst.extraDelayMs = DelayInMs;
|
||
|
return (0);
|
||
|
}
|
||
|
|
||
|
int WebRtcNetEQ_SetPlayoutMode(void *inst, enum WebRtcNetEQPlayoutMode playoutMode)
|
||
|
{
|
||
|
MainInst_t *NetEqMainInst = (MainInst_t*) inst;
|
||
|
if (NetEqMainInst == NULL) return (-1);
|
||
|
if ((playoutMode != kPlayoutOn) && (playoutMode != kPlayoutOff) && (playoutMode
|
||
|
!= kPlayoutFax) && (playoutMode != kPlayoutStreaming))
|
||
|
{
|
||
|
NetEqMainInst->ErrorCode = -FAULTY_PLAYOUTMODE;
|
||
|
return (-1);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
NetEqMainInst->MCUinst.NetEqPlayoutMode = playoutMode;
|
||
|
return (0);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
int WebRtcNetEQ_SetBGNMode(void *inst, enum WebRtcNetEQBGNMode bgnMode)
|
||
|
{
|
||
|
|
||
|
MainInst_t *NetEqMainInst = (MainInst_t*) inst;
|
||
|
|
||
|
/* Instance sanity */
|
||
|
if (NetEqMainInst == NULL) return (-1);
|
||
|
|
||
|
/* Check for corrupt/cleared instance */
|
||
|
if (NetEqMainInst->MCUinst.main_inst != NetEqMainInst)
|
||
|
{
|
||
|
/* Instance is corrupt */
|
||
|
NetEqMainInst->ErrorCode = CORRUPT_INSTANCE;
|
||
|
return (-1);
|
||
|
}
|
||
|
|
||
|
NetEqMainInst->DSPinst.BGNInst.bgnMode = (enum BGNMode) bgnMode;
|
||
|
|
||
|
return (0);
|
||
|
}
|
||
|
|
||
|
int WebRtcNetEQ_GetBGNMode(const void *inst, enum WebRtcNetEQBGNMode *bgnMode)
|
||
|
{
|
||
|
|
||
|
const MainInst_t *NetEqMainInst = (const MainInst_t*) inst;
|
||
|
|
||
|
/* Instance sanity */
|
||
|
if (NetEqMainInst == NULL) return (-1);
|
||
|
|
||
|
*bgnMode = (enum WebRtcNetEQBGNMode) NetEqMainInst->DSPinst.BGNInst.bgnMode;
|
||
|
|
||
|
return (0);
|
||
|
}
|
||
|
|
||
|
/************************************************
|
||
|
* CodecDB functions
|
||
|
*/
|
||
|
|
||
|
int WebRtcNetEQ_CodecDbReset(void *inst)
|
||
|
{
|
||
|
int ok = 0;
|
||
|
MainInst_t *NetEqMainInst = (MainInst_t*) inst;
|
||
|
if (NetEqMainInst == NULL) return (-1);
|
||
|
ok = WebRtcNetEQ_DbReset(&NetEqMainInst->MCUinst.codec_DB_inst);
|
||
|
if (ok != 0)
|
||
|
{
|
||
|
NetEqMainInst->ErrorCode = -ok;
|
||
|
return (-1);
|
||
|
}
|
||
|
|
||
|
/* set function pointers to NULL to prevent RecOut from using the codec */
|
||
|
NetEqMainInst->DSPinst.codec_ptr_inst.funcDecode = NULL;
|
||
|
NetEqMainInst->DSPinst.codec_ptr_inst.funcDecodeRCU = NULL;
|
||
|
NetEqMainInst->DSPinst.codec_ptr_inst.funcAddLatePkt = NULL;
|
||
|
NetEqMainInst->DSPinst.codec_ptr_inst.funcDecode = NULL;
|
||
|
NetEqMainInst->DSPinst.codec_ptr_inst.funcDecodeInit = NULL;
|
||
|
NetEqMainInst->DSPinst.codec_ptr_inst.funcDecodePLC = NULL;
|
||
|
NetEqMainInst->DSPinst.codec_ptr_inst.funcGetMDinfo = NULL;
|
||
|
NetEqMainInst->DSPinst.codec_ptr_inst.funcUpdBWEst = NULL;
|
||
|
NetEqMainInst->DSPinst.codec_ptr_inst.funcGetErrorCode = NULL;
|
||
|
|
||
|
return (0);
|
||
|
}
|
||
|
|
||
|
int WebRtcNetEQ_CodecDbGetSizeInfo(void *inst, WebRtc_Word16 *UsedEntries,
|
||
|
WebRtc_Word16 *MaxEntries)
|
||
|
{
|
||
|
MainInst_t *NetEqMainInst = (MainInst_t*) inst;
|
||
|
if (NetEqMainInst == NULL) return (-1);
|
||
|
*MaxEntries = NUM_CODECS;
|
||
|
*UsedEntries = NetEqMainInst->MCUinst.codec_DB_inst.nrOfCodecs;
|
||
|
return (0);
|
||
|
}
|
||
|
|
||
|
int WebRtcNetEQ_CodecDbGetCodecInfo(void *inst, WebRtc_Word16 Entry,
|
||
|
enum WebRtcNetEQDecoder *codec)
|
||
|
{
|
||
|
int i;
|
||
|
MainInst_t *NetEqMainInst = (MainInst_t*) inst;
|
||
|
if (NetEqMainInst == NULL) return (-1);
|
||
|
*codec = (enum WebRtcNetEQDecoder) 0;
|
||
|
if ((Entry >= 0) && (Entry < NetEqMainInst->MCUinst.codec_DB_inst.nrOfCodecs))
|
||
|
{
|
||
|
for (i = 0; i < NUM_TOTAL_CODECS; i++)
|
||
|
{
|
||
|
if (NetEqMainInst->MCUinst.codec_DB_inst.position[i] == Entry)
|
||
|
{
|
||
|
*codec = (enum WebRtcNetEQDecoder) i;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
NetEqMainInst->ErrorCode = -(CODEC_DB_NOT_EXIST1);
|
||
|
return (-1);
|
||
|
}
|
||
|
return (0);
|
||
|
}
|
||
|
|
||
|
int WebRtcNetEQ_CodecDbAdd(void *inst, WebRtcNetEQ_CodecDef *codecInst)
|
||
|
{
|
||
|
int ok = 0;
|
||
|
MainInst_t *NetEqMainInst = (MainInst_t*) inst;
|
||
|
if (NetEqMainInst == NULL) return (-1);
|
||
|
ok = WebRtcNetEQ_DbAdd(&NetEqMainInst->MCUinst.codec_DB_inst, codecInst->codec,
|
||
|
codecInst->payloadType, codecInst->funcDecode, codecInst->funcDecodeRCU,
|
||
|
codecInst->funcDecodePLC, codecInst->funcDecodeInit, codecInst->funcAddLatePkt,
|
||
|
codecInst->funcGetMDinfo, codecInst->funcGetPitch, codecInst->funcUpdBWEst,
|
||
|
codecInst->funcGetErrorCode, codecInst->codec_state, codecInst->codec_fs);
|
||
|
if (ok != 0)
|
||
|
{
|
||
|
NetEqMainInst->ErrorCode = -ok;
|
||
|
return (-1);
|
||
|
}
|
||
|
return (ok);
|
||
|
}
|
||
|
|
||
|
int WebRtcNetEQ_CodecDbRemove(void *inst, enum WebRtcNetEQDecoder codec)
|
||
|
{
|
||
|
int ok = 0;
|
||
|
MainInst_t *NetEqMainInst = (MainInst_t*) inst;
|
||
|
if (NetEqMainInst == NULL) return (-1);
|
||
|
|
||
|
/* check if currently used codec is being removed */
|
||
|
if (NetEqMainInst->MCUinst.current_Codec == (WebRtc_Word16) codec)
|
||
|
{
|
||
|
/* set function pointers to NULL to prevent RecOut from using the codec */
|
||
|
NetEqMainInst->DSPinst.codec_ptr_inst.funcDecode = NULL;
|
||
|
NetEqMainInst->DSPinst.codec_ptr_inst.funcDecodeRCU = NULL;
|
||
|
NetEqMainInst->DSPinst.codec_ptr_inst.funcAddLatePkt = NULL;
|
||
|
NetEqMainInst->DSPinst.codec_ptr_inst.funcDecode = NULL;
|
||
|
NetEqMainInst->DSPinst.codec_ptr_inst.funcDecodeInit = NULL;
|
||
|
NetEqMainInst->DSPinst.codec_ptr_inst.funcDecodePLC = NULL;
|
||
|
NetEqMainInst->DSPinst.codec_ptr_inst.funcGetMDinfo = NULL;
|
||
|
NetEqMainInst->DSPinst.codec_ptr_inst.funcUpdBWEst = NULL;
|
||
|
NetEqMainInst->DSPinst.codec_ptr_inst.funcGetErrorCode = NULL;
|
||
|
}
|
||
|
|
||
|
ok = WebRtcNetEQ_DbRemove(&NetEqMainInst->MCUinst.codec_DB_inst, codec);
|
||
|
if (ok != 0)
|
||
|
{
|
||
|
NetEqMainInst->ErrorCode = -ok;
|
||
|
return (-1);
|
||
|
}
|
||
|
return (ok);
|
||
|
}
|
||
|
|
||
|
/*********************************
|
||
|
* Real-time functions
|
||
|
*/
|
||
|
|
||
|
int WebRtcNetEQ_RecIn(void *inst, WebRtc_Word16 *p_w16datagramstart, WebRtc_Word16 w16_RTPlen,
|
||
|
WebRtc_UWord32 uw32_timeRec)
|
||
|
{
|
||
|
int ok = 0;
|
||
|
RTPPacket_t RTPpacket;
|
||
|
MainInst_t *NetEqMainInst = (MainInst_t*) inst;
|
||
|
if (NetEqMainInst == NULL) return (-1);
|
||
|
|
||
|
/* Check for corrupt/cleared instance */
|
||
|
if (NetEqMainInst->MCUinst.main_inst != NetEqMainInst)
|
||
|
{
|
||
|
/* Instance is corrupt */
|
||
|
NetEqMainInst->ErrorCode = CORRUPT_INSTANCE;
|
||
|
return (-1);
|
||
|
}
|
||
|
|
||
|
/* Parse RTP header */
|
||
|
ok = WebRtcNetEQ_RTPPayloadInfo(p_w16datagramstart, w16_RTPlen, &RTPpacket);
|
||
|
if (ok != 0)
|
||
|
{
|
||
|
NetEqMainInst->ErrorCode = -ok;
|
||
|
return (-1);
|
||
|
}
|
||
|
|
||
|
ok = WebRtcNetEQ_RecInInternal(&NetEqMainInst->MCUinst, &RTPpacket, uw32_timeRec);
|
||
|
if (ok != 0)
|
||
|
{
|
||
|
NetEqMainInst->ErrorCode = -ok;
|
||
|
return (-1);
|
||
|
}
|
||
|
return (ok);
|
||
|
}
|
||
|
|
||
|
/****************************************************************************
|
||
|
* WebRtcNetEQ_RecInRTPStruct(...)
|
||
|
*
|
||
|
* Alternative RecIn function, used when the RTP data has already been
|
||
|
* parsed into an RTP info struct (WebRtcNetEQ_RTPInfo).
|
||
|
*
|
||
|
* Input:
|
||
|
* - inst : NetEQ instance
|
||
|
* - rtpInfo : Pointer to RTP info
|
||
|
* - payloadPtr : Pointer to the RTP payload (first byte after header)
|
||
|
* - payloadLenBytes : Length (in bytes) of the payload in payloadPtr
|
||
|
* - timeRec : Receive time (in timestamps of the used codec)
|
||
|
*
|
||
|
* Return value : 0 - Ok
|
||
|
* -1 - Error
|
||
|
*/
|
||
|
int WebRtcNetEQ_RecInRTPStruct(void *inst, WebRtcNetEQ_RTPInfo *rtpInfo,
|
||
|
const WebRtc_UWord8 *payloadPtr, WebRtc_Word16 payloadLenBytes,
|
||
|
WebRtc_UWord32 uw32_timeRec)
|
||
|
{
|
||
|
int ok = 0;
|
||
|
RTPPacket_t RTPpacket;
|
||
|
MainInst_t *NetEqMainInst = (MainInst_t*) inst;
|
||
|
if (NetEqMainInst == NULL)
|
||
|
{
|
||
|
return (-1);
|
||
|
}
|
||
|
|
||
|
/* Check for corrupt/cleared instance */
|
||
|
if (NetEqMainInst->MCUinst.main_inst != NetEqMainInst)
|
||
|
{
|
||
|
/* Instance is corrupt */
|
||
|
NetEqMainInst->ErrorCode = CORRUPT_INSTANCE;
|
||
|
return (-1);
|
||
|
}
|
||
|
|
||
|
/* Load NetEQ's RTP struct from Module RTP struct */
|
||
|
RTPpacket.payloadType = rtpInfo->payloadType;
|
||
|
RTPpacket.seqNumber = rtpInfo->sequenceNumber;
|
||
|
RTPpacket.timeStamp = rtpInfo->timeStamp;
|
||
|
RTPpacket.ssrc = rtpInfo->SSRC;
|
||
|
RTPpacket.payload = (const WebRtc_Word16*) payloadPtr;
|
||
|
RTPpacket.payloadLen = payloadLenBytes;
|
||
|
RTPpacket.starts_byte1 = 0;
|
||
|
|
||
|
ok = WebRtcNetEQ_RecInInternal(&NetEqMainInst->MCUinst, &RTPpacket, uw32_timeRec);
|
||
|
if (ok != 0)
|
||
|
{
|
||
|
NetEqMainInst->ErrorCode = -ok;
|
||
|
return (-1);
|
||
|
}
|
||
|
return (ok);
|
||
|
}
|
||
|
|
||
|
int WebRtcNetEQ_RecOut(void *inst, WebRtc_Word16 *pw16_outData, WebRtc_Word16 *pw16_len)
|
||
|
{
|
||
|
int ok = 0;
|
||
|
MainInst_t *NetEqMainInst = (MainInst_t*) inst;
|
||
|
#ifdef NETEQ_STEREO
|
||
|
MasterSlaveInfo msInfo;
|
||
|
msInfo.msMode = NETEQ_MONO;
|
||
|
#endif
|
||
|
|
||
|
if (NetEqMainInst == NULL) return (-1);
|
||
|
|
||
|
/* Check for corrupt/cleared instance */
|
||
|
if (NetEqMainInst->DSPinst.main_inst != NetEqMainInst)
|
||
|
{
|
||
|
/* Instance is corrupt */
|
||
|
NetEqMainInst->ErrorCode = CORRUPT_INSTANCE;
|
||
|
return (-1);
|
||
|
}
|
||
|
|
||
|
#ifdef NETEQ_STEREO
|
||
|
NetEqMainInst->DSPinst.msInfo = &msInfo;
|
||
|
#endif
|
||
|
|
||
|
ok = WebRtcNetEQ_RecOutInternal(&NetEqMainInst->DSPinst, pw16_outData,
|
||
|
pw16_len, 0 /* not BGN only */);
|
||
|
if (ok != 0)
|
||
|
{
|
||
|
NetEqMainInst->ErrorCode = -ok;
|
||
|
return (-1);
|
||
|
}
|
||
|
return (ok);
|
||
|
}
|
||
|
|
||
|
/****************************************************************************
|
||
|
* WebRtcNetEQ_RecOutMasterSlave(...)
|
||
|
*
|
||
|
* RecOut function for running several NetEQ instances in master/slave mode.
|
||
|
* One master can be used to control several slaves.
|
||
|
*
|
||
|
* Input:
|
||
|
* - inst : NetEQ instance
|
||
|
* - isMaster : Non-zero indicates that this is the master channel
|
||
|
* - msInfo : (slave only) Information from master
|
||
|
*
|
||
|
* Output:
|
||
|
* - inst : Updated NetEQ instance
|
||
|
* - pw16_outData : Pointer to vector where output should be written
|
||
|
* - pw16_len : Pointer to variable where output length is returned
|
||
|
* - msInfo : (master only) Information to slave(s)
|
||
|
*
|
||
|
* Return value : 0 - Ok
|
||
|
* -1 - Error
|
||
|
*/
|
||
|
|
||
|
int WebRtcNetEQ_RecOutMasterSlave(void *inst, WebRtc_Word16 *pw16_outData,
|
||
|
WebRtc_Word16 *pw16_len, void *msInfo,
|
||
|
WebRtc_Word16 isMaster)
|
||
|
{
|
||
|
#ifndef NETEQ_STEREO
|
||
|
/* Stereo not supported */
|
||
|
return(-1);
|
||
|
#else
|
||
|
int ok = 0;
|
||
|
MainInst_t *NetEqMainInst = (MainInst_t*) inst;
|
||
|
|
||
|
if (NetEqMainInst == NULL) return (-1);
|
||
|
|
||
|
/* Check for corrupt/cleared instance */
|
||
|
if (NetEqMainInst->DSPinst.main_inst != NetEqMainInst)
|
||
|
{
|
||
|
/* Instance is corrupt */
|
||
|
NetEqMainInst->ErrorCode = CORRUPT_INSTANCE;
|
||
|
return (-1);
|
||
|
}
|
||
|
|
||
|
if (msInfo == NULL)
|
||
|
{
|
||
|
/* msInfo not provided */
|
||
|
NetEqMainInst->ErrorCode = NETEQ_OTHER_ERROR;
|
||
|
return (-1);
|
||
|
}
|
||
|
|
||
|
/* translate from external to internal Master/Slave information */
|
||
|
NetEqMainInst->DSPinst.msInfo = (MasterSlaveInfo *) msInfo;
|
||
|
|
||
|
/* check that we have not done a master/slave switch without first re-initializing */
|
||
|
if ((NetEqMainInst->masterSlave == 1 && !isMaster) || /* switch from master to slave */
|
||
|
(NetEqMainInst->masterSlave == 2 && isMaster)) /* switch from slave to master */
|
||
|
{
|
||
|
NetEqMainInst->ErrorCode = ILLEGAL_MASTER_SLAVE_SWITCH;
|
||
|
return (-1);
|
||
|
}
|
||
|
|
||
|
if (!isMaster)
|
||
|
{
|
||
|
/* this is the slave */
|
||
|
NetEqMainInst->masterSlave = 2;
|
||
|
NetEqMainInst->DSPinst.msInfo->msMode = NETEQ_SLAVE;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
NetEqMainInst->DSPinst.msInfo->msMode = NETEQ_MASTER;
|
||
|
}
|
||
|
|
||
|
ok = WebRtcNetEQ_RecOutInternal(&NetEqMainInst->DSPinst, pw16_outData,
|
||
|
pw16_len, 0 /* not BGN only */);
|
||
|
if (ok != 0)
|
||
|
{
|
||
|
NetEqMainInst->ErrorCode = -ok;
|
||
|
return (-1);
|
||
|
}
|
||
|
|
||
|
if (isMaster)
|
||
|
{
|
||
|
/* this is the master */
|
||
|
NetEqMainInst->masterSlave = 1;
|
||
|
}
|
||
|
|
||
|
return (ok);
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
int WebRtcNetEQ_GetMasterSlaveInfoSize()
|
||
|
{
|
||
|
#ifdef NETEQ_STEREO
|
||
|
return (sizeof(MasterSlaveInfo));
|
||
|
#else
|
||
|
return(-1);
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
/* Special RecOut that does not do any decoding. */
|
||
|
int WebRtcNetEQ_RecOutNoDecode(void *inst, WebRtc_Word16 *pw16_outData,
|
||
|
WebRtc_Word16 *pw16_len)
|
||
|
{
|
||
|
int ok = 0;
|
||
|
MainInst_t *NetEqMainInst = (MainInst_t*) inst;
|
||
|
#ifdef NETEQ_STEREO
|
||
|
MasterSlaveInfo msInfo;
|
||
|
#endif
|
||
|
|
||
|
if (NetEqMainInst == NULL) return (-1);
|
||
|
|
||
|
/* Check for corrupt/cleared instance */
|
||
|
if (NetEqMainInst->DSPinst.main_inst != NetEqMainInst)
|
||
|
{
|
||
|
/* Instance is corrupt */
|
||
|
NetEqMainInst->ErrorCode = CORRUPT_INSTANCE;
|
||
|
return (-1);
|
||
|
}
|
||
|
|
||
|
#ifdef NETEQ_STEREO
|
||
|
/* keep same mode as before */
|
||
|
switch (NetEqMainInst->masterSlave)
|
||
|
{
|
||
|
case 1:
|
||
|
{
|
||
|
msInfo.msMode = NETEQ_MASTER;
|
||
|
break;
|
||
|
}
|
||
|
case 2:
|
||
|
{
|
||
|
msInfo.msMode = NETEQ_SLAVE;
|
||
|
break;
|
||
|
}
|
||
|
default:
|
||
|
{
|
||
|
msInfo.msMode = NETEQ_MONO;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
NetEqMainInst->DSPinst.msInfo = &msInfo;
|
||
|
#endif
|
||
|
|
||
|
ok = WebRtcNetEQ_RecOutInternal(&NetEqMainInst->DSPinst, pw16_outData,
|
||
|
pw16_len, 1 /* BGN only */);
|
||
|
if (ok != 0)
|
||
|
{
|
||
|
NetEqMainInst->ErrorCode = -ok;
|
||
|
return (-1);
|
||
|
}
|
||
|
return (ok);
|
||
|
}
|
||
|
|
||
|
int WebRtcNetEQ_GetRTCPStats(void *inst, WebRtcNetEQ_RTCPStat *RTCP_inst)
|
||
|
{
|
||
|
int ok = 0;
|
||
|
MainInst_t *NetEqMainInst = (MainInst_t*) inst;
|
||
|
if (NetEqMainInst == NULL) return (-1);
|
||
|
ok = WebRtcNetEQ_RTCPGetStats(&NetEqMainInst->MCUinst.RTCP_inst,
|
||
|
&RTCP_inst->fraction_lost, &RTCP_inst->cum_lost, &RTCP_inst->ext_max,
|
||
|
&RTCP_inst->jitter, 0);
|
||
|
if (ok != 0)
|
||
|
{
|
||
|
NetEqMainInst->ErrorCode = -ok;
|
||
|
return (-1);
|
||
|
}
|
||
|
return (ok);
|
||
|
}
|
||
|
|
||
|
int WebRtcNetEQ_GetRTCPStatsNoReset(void *inst, WebRtcNetEQ_RTCPStat *RTCP_inst)
|
||
|
{
|
||
|
int ok = 0;
|
||
|
MainInst_t *NetEqMainInst = (MainInst_t*) inst;
|
||
|
if (NetEqMainInst == NULL) return (-1);
|
||
|
ok = WebRtcNetEQ_RTCPGetStats(&NetEqMainInst->MCUinst.RTCP_inst,
|
||
|
&RTCP_inst->fraction_lost, &RTCP_inst->cum_lost, &RTCP_inst->ext_max,
|
||
|
&RTCP_inst->jitter, 1);
|
||
|
if (ok != 0)
|
||
|
{
|
||
|
NetEqMainInst->ErrorCode = -ok;
|
||
|
return (-1);
|
||
|
}
|
||
|
return (ok);
|
||
|
}
|
||
|
|
||
|
int WebRtcNetEQ_GetSpeechTimeStamp(void *inst, WebRtc_UWord32 *timestamp)
|
||
|
{
|
||
|
MainInst_t *NetEqMainInst = (MainInst_t*) inst;
|
||
|
if (NetEqMainInst == NULL) return (-1);
|
||
|
|
||
|
if (NetEqMainInst->MCUinst.TSscalingInitialized)
|
||
|
{
|
||
|
*timestamp = WebRtcNetEQ_ScaleTimestampInternalToExternal(&NetEqMainInst->MCUinst,
|
||
|
NetEqMainInst->DSPinst.videoSyncTimestamp);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
*timestamp = NetEqMainInst->DSPinst.videoSyncTimestamp;
|
||
|
}
|
||
|
|
||
|
return (0);
|
||
|
}
|
||
|
|
||
|
/****************************************************************************
|
||
|
* WebRtcNetEQ_GetSpeechOutputType(...)
|
||
|
*
|
||
|
* Get the output type for the audio provided by the latest call to
|
||
|
* WebRtcNetEQ_RecOut().
|
||
|
*
|
||
|
* kOutputNormal = normal audio (possibly processed)
|
||
|
* kOutputPLC = loss concealment through stretching audio
|
||
|
* kOutputCNG = comfort noise (codec-internal or RFC3389)
|
||
|
* kOutputPLCtoCNG = background noise only due to long expand or error
|
||
|
* kOutputVADPassive = PostDecode VAD signalling passive speaker
|
||
|
*
|
||
|
* Input:
|
||
|
* - inst : NetEQ instance
|
||
|
*
|
||
|
* Output:
|
||
|
* - outputType : Output type from enum list WebRtcNetEQOutputType
|
||
|
*
|
||
|
* Return value : 0 - Ok
|
||
|
* -1 - Error
|
||
|
*/
|
||
|
|
||
|
int WebRtcNetEQ_GetSpeechOutputType(void *inst, enum WebRtcNetEQOutputType *outputType)
|
||
|
{
|
||
|
/* Typecast to internal instance type */
|
||
|
MainInst_t *NetEqMainInst = (MainInst_t*) inst;
|
||
|
|
||
|
if (NetEqMainInst == NULL)
|
||
|
{
|
||
|
return (-1);
|
||
|
}
|
||
|
|
||
|
if ((NetEqMainInst->DSPinst.w16_mode & MODE_BGN_ONLY) != 0)
|
||
|
{
|
||
|
/* If last mode was background noise only */
|
||
|
*outputType = kOutputPLCtoCNG;
|
||
|
|
||
|
}
|
||
|
else if ((NetEqMainInst->DSPinst.w16_mode == MODE_CODEC_INTERNAL_CNG)
|
||
|
|| (NetEqMainInst->DSPinst.w16_mode == MODE_RFC3389CNG))
|
||
|
{
|
||
|
/* If CN or internal CNG */
|
||
|
*outputType = kOutputCNG;
|
||
|
|
||
|
#ifdef NETEQ_VAD
|
||
|
}
|
||
|
else if ( NetEqMainInst->DSPinst.VADInst.VADDecision == 0 )
|
||
|
{
|
||
|
/* post-decode VAD says passive speaker */
|
||
|
*outputType = kOutputVADPassive;
|
||
|
#endif /* NETEQ_VAD */
|
||
|
|
||
|
}
|
||
|
else if ((NetEqMainInst->DSPinst.w16_mode == MODE_EXPAND)
|
||
|
&& (NetEqMainInst->DSPinst.ExpandInst.w16_expandMuteFactor == 0))
|
||
|
{
|
||
|
/* Expand mode has faded down to background noise only (very long expand) */
|
||
|
*outputType = kOutputPLCtoCNG;
|
||
|
|
||
|
}
|
||
|
else if (NetEqMainInst->DSPinst.w16_mode == MODE_EXPAND)
|
||
|
{
|
||
|
/* PLC mode */
|
||
|
*outputType = kOutputPLC;
|
||
|
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
/* Normal speech output type (can still be manipulated, e.g., accelerated) */
|
||
|
*outputType = kOutputNormal;
|
||
|
}
|
||
|
|
||
|
return (0);
|
||
|
}
|
||
|
|
||
|
/**********************************
|
||
|
* Functions related to VQmon
|
||
|
*/
|
||
|
|
||
|
#define WEBRTC_NETEQ_CONCEALMENTFLAG_LOST 0x01
|
||
|
#define WEBRTC_NETEQ_CONCEALMENTFLAG_DISCARDED 0x02
|
||
|
#define WEBRTC_NETEQ_CONCEALMENTFLAG_SUPRESS 0x04
|
||
|
#define WEBRTC_NETEQ_CONCEALMENTFLAG_CNGACTIVE 0x80
|
||
|
|
||
|
int WebRtcNetEQ_VQmonRecOutStatistics(void *inst, WebRtc_UWord16 *validVoiceDurationMs,
|
||
|
WebRtc_UWord16 *concealedVoiceDurationMs,
|
||
|
WebRtc_UWord8 *concealedVoiceFlags)
|
||
|
{
|
||
|
MainInst_t *NetEqMainInst = (MainInst_t*) inst;
|
||
|
WebRtc_Word16 fs_mult;
|
||
|
WebRtc_Word16 ms_lost;
|
||
|
if (NetEqMainInst == NULL) return (-1);
|
||
|
fs_mult = WebRtcSpl_DivW32W16ResW16(NetEqMainInst->MCUinst.fs, 8000);
|
||
|
|
||
|
ms_lost = WebRtcSpl_DivW32W16ResW16(
|
||
|
(WebRtc_Word32) NetEqMainInst->DSPinst.w16_concealedTS, (WebRtc_Word16) (8 * fs_mult));
|
||
|
if (ms_lost > NetEqMainInst->DSPinst.millisecondsPerCall) ms_lost
|
||
|
= NetEqMainInst->DSPinst.millisecondsPerCall;
|
||
|
|
||
|
*validVoiceDurationMs = NetEqMainInst->DSPinst.millisecondsPerCall - ms_lost;
|
||
|
*concealedVoiceDurationMs = ms_lost;
|
||
|
if (ms_lost > 0)
|
||
|
{
|
||
|
*concealedVoiceFlags = WEBRTC_NETEQ_CONCEALMENTFLAG_LOST;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
*concealedVoiceFlags = 0;
|
||
|
}
|
||
|
NetEqMainInst->DSPinst.w16_concealedTS -= ms_lost * (8 * fs_mult);
|
||
|
|
||
|
return (0);
|
||
|
}
|
||
|
|
||
|
int WebRtcNetEQ_VQmonGetConfiguration(void *inst, WebRtc_UWord16 *absMaxDelayMs,
|
||
|
WebRtc_UWord8 *adaptationRate)
|
||
|
{
|
||
|
/* Dummy check the inst, just to avoid compiler warnings. */
|
||
|
if (inst == NULL)
|
||
|
{
|
||
|
/* Do nothing. */
|
||
|
}
|
||
|
|
||
|
/* Hardcoded variables that are used for VQmon as jitter buffer parameters */
|
||
|
*absMaxDelayMs = 240;
|
||
|
*adaptationRate = 1;
|
||
|
return (0);
|
||
|
}
|
||
|
|
||
|
int WebRtcNetEQ_VQmonGetRxStatistics(void *inst, WebRtc_UWord16 *avgDelayMs,
|
||
|
WebRtc_UWord16 *maxDelayMs)
|
||
|
{
|
||
|
MainInst_t *NetEqMainInst = (MainInst_t*) inst;
|
||
|
if (NetEqMainInst == NULL) return (-1);
|
||
|
*avgDelayMs = (WebRtc_UWord16) (NetEqMainInst->MCUinst.BufferStat_inst.avgDelayMsQ8 >> 8);
|
||
|
*maxDelayMs = (WebRtc_UWord16) NetEqMainInst->MCUinst.BufferStat_inst.maxDelayMs;
|
||
|
return (0);
|
||
|
}
|
||
|
|
||
|
/*************************************
|
||
|
* Statistics functions
|
||
|
*/
|
||
|
|
||
|
/* Get the "in-call" statistics from NetEQ.
|
||
|
* The statistics are reset after the query. */
|
||
|
int WebRtcNetEQ_GetNetworkStatistics(void *inst, WebRtcNetEQ_NetworkStatistics *stats)
|
||
|
|
||
|
{
|
||
|
|
||
|
WebRtc_UWord16 tempU16;
|
||
|
WebRtc_UWord32 tempU32, tempU32_2;
|
||
|
int numShift;
|
||
|
MainInst_t *NetEqMainInst = (MainInst_t*) inst;
|
||
|
|
||
|
/* Instance sanity */
|
||
|
if (NetEqMainInst == NULL) return (-1);
|
||
|
|
||
|
/*******************/
|
||
|
/* Get buffer size */
|
||
|
/*******************/
|
||
|
|
||
|
if (WebRtcNetEQ_GetCurrentDelay((void *) inst, &(stats->currentBufferSize)) != 0)
|
||
|
{
|
||
|
return (-1);
|
||
|
}
|
||
|
|
||
|
/***************************/
|
||
|
/* Get optimal buffer size */
|
||
|
/***************************/
|
||
|
|
||
|
if (NetEqMainInst->MCUinst.fs != 0 && NetEqMainInst->MCUinst.fs <= WEBRTC_SPL_WORD16_MAX)
|
||
|
{
|
||
|
/* preferredBufferSize = Bopt * packSizeSamples / (fs/1000) */
|
||
|
stats->preferredBufferSize
|
||
|
= (WebRtc_UWord16) WEBRTC_SPL_MUL_16_16(
|
||
|
(WebRtc_Word16) ((NetEqMainInst->MCUinst.BufferStat_inst.Automode_inst.optBufLevel) >> 8), /* optimal buffer level in packets shifted to Q0 */
|
||
|
WebRtcSpl_DivW32W16ResW16(
|
||
|
(WebRtc_Word32) NetEqMainInst->MCUinst.BufferStat_inst.Automode_inst.packetSpeechLenSamp, /* samples per packet */
|
||
|
WebRtcSpl_DivW32W16ResW16( (WebRtc_Word32) NetEqMainInst->MCUinst.fs, (WebRtc_Word16) 1000 ) /* samples per ms */
|
||
|
) );
|
||
|
|
||
|
/* add extra delay */
|
||
|
if (NetEqMainInst->MCUinst.BufferStat_inst.Automode_inst.extraDelayMs > 0)
|
||
|
{
|
||
|
stats->preferredBufferSize
|
||
|
+= NetEqMainInst->MCUinst.BufferStat_inst.Automode_inst.extraDelayMs;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
/* sample rate not initialized */
|
||
|
stats->preferredBufferSize = 0;
|
||
|
}
|
||
|
|
||
|
/***********************/
|
||
|
/* Calculate loss rate */
|
||
|
/***********************/
|
||
|
|
||
|
/* timestamps elapsed since last report */
|
||
|
tempU32 = NetEqMainInst->MCUinst.lastReportTS;
|
||
|
|
||
|
if (NetEqMainInst->MCUinst.lostTS == 0)
|
||
|
{
|
||
|
/* no losses */
|
||
|
stats->currentPacketLossRate = 0;
|
||
|
}
|
||
|
else if (NetEqMainInst->MCUinst.lostTS < tempU32)
|
||
|
{
|
||
|
/* calculate shifts; we want the result in Q14 */
|
||
|
numShift = WebRtcSpl_NormU32(NetEqMainInst->MCUinst.lostTS); /* numerator shift for normalize */
|
||
|
|
||
|
if (numShift < 14)
|
||
|
{
|
||
|
/* cannot shift numerator 14 steps; shift denominator too */
|
||
|
tempU32 = WEBRTC_SPL_RSHIFT_U32(tempU32, 14-numShift); /* right-shift */
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
/* shift no more than 14 steps */
|
||
|
numShift = 14;
|
||
|
}
|
||
|
|
||
|
if (tempU32 == 0)
|
||
|
{
|
||
|
/* check for zero denominator; result should be zero in this case */
|
||
|
stats->currentPacketLossRate = 0;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
/* check that denominator fits in signed 16-bit */
|
||
|
while (tempU32 > WEBRTC_SPL_WORD16_MAX)
|
||
|
{
|
||
|
tempU32 >>= 1; /* right-shift 1 step */
|
||
|
numShift--; /* compensate in numerator */
|
||
|
}
|
||
|
tempU16 = (WebRtc_UWord16) tempU32;
|
||
|
|
||
|
/* do the shift of numerator */
|
||
|
tempU32
|
||
|
= WEBRTC_SPL_SHIFT_W32( (WebRtc_UWord32) NetEqMainInst->MCUinst.lostTS, numShift);
|
||
|
|
||
|
stats->currentPacketLossRate = (WebRtc_UWord16) WebRtcSpl_DivU32U16(tempU32,
|
||
|
tempU16);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
/* lost count is larger than elapsed time count; probably timestamp wrap-around or something else wrong */
|
||
|
/* set loss rate = 1 */
|
||
|
stats->currentPacketLossRate = 1 << 14; /* 1 in Q14 */
|
||
|
}
|
||
|
|
||
|
/**************************/
|
||
|
/* Calculate discard rate */
|
||
|
/**************************/
|
||
|
|
||
|
/* timestamps elapsed since last report */
|
||
|
tempU32 = NetEqMainInst->MCUinst.lastReportTS;
|
||
|
|
||
|
/* number of discarded samples */
|
||
|
tempU32_2
|
||
|
= WEBRTC_SPL_MUL_16_U16( (WebRtc_Word16) NetEqMainInst->MCUinst.PacketBuffer_inst.packSizeSamples,
|
||
|
NetEqMainInst->MCUinst.PacketBuffer_inst.discardedPackets);
|
||
|
|
||
|
if (tempU32_2 == 0)
|
||
|
{
|
||
|
/* no discarded samples */
|
||
|
stats->currentDiscardRate = 0;
|
||
|
}
|
||
|
else if (tempU32_2 < tempU32)
|
||
|
{
|
||
|
/* calculate shifts; we want the result in Q14 */
|
||
|
numShift = WebRtcSpl_NormU32(tempU32_2); /* numerator shift for normalize */
|
||
|
|
||
|
if (numShift < 14)
|
||
|
{
|
||
|
/* cannot shift numerator 14 steps; shift denominator too */
|
||
|
tempU32 = WEBRTC_SPL_RSHIFT_U32(tempU32, 14-numShift); /* right-shift */
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
/* shift no more than 14 steps */
|
||
|
numShift = 14;
|
||
|
}
|
||
|
|
||
|
if (tempU32 == 0)
|
||
|
{
|
||
|
/* check for zero denominator; result should be zero in this case */
|
||
|
stats->currentDiscardRate = 0;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
/* check that denominator fits in signed 16-bit */
|
||
|
while (tempU32 > WEBRTC_SPL_WORD16_MAX)
|
||
|
{
|
||
|
tempU32 >>= 1; /* right-shift 1 step */
|
||
|
numShift--; /* compensate in numerator */
|
||
|
}
|
||
|
tempU16 = (WebRtc_UWord16) tempU32;
|
||
|
|
||
|
/* do the shift of numerator */
|
||
|
tempU32 = WEBRTC_SPL_SHIFT_W32( tempU32_2, numShift);
|
||
|
|
||
|
stats->currentDiscardRate = (WebRtc_UWord16) WebRtcSpl_DivU32U16(tempU32, tempU16);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
/* lost count is larger than elapsed time count; probably timestamp wrap-around or something else wrong */
|
||
|
/* set loss rate = 1 */
|
||
|
stats->currentDiscardRate = 1 << 14; /* 1 in Q14 */
|
||
|
}
|
||
|
|
||
|
/*************************************************************/
|
||
|
/* Calculate Accelerate, Expand and Pre-emptive Expand rates */
|
||
|
/*************************************************************/
|
||
|
|
||
|
/* timestamps elapsed since last report */
|
||
|
tempU32 = NetEqMainInst->MCUinst.lastReportTS;
|
||
|
|
||
|
if (NetEqMainInst->DSPinst.statInst.accelerateLength == 0)
|
||
|
{
|
||
|
/* no accelerate */
|
||
|
stats->currentAccelerateRate = 0;
|
||
|
}
|
||
|
else if (NetEqMainInst->DSPinst.statInst.accelerateLength < tempU32)
|
||
|
{
|
||
|
/* calculate shifts; we want the result in Q14 */
|
||
|
numShift = WebRtcSpl_NormU32(NetEqMainInst->DSPinst.statInst.accelerateLength); /* numerator shift for normalize */
|
||
|
|
||
|
if (numShift < 14)
|
||
|
{
|
||
|
/* cannot shift numerator 14 steps; shift denominator too */
|
||
|
tempU32 = WEBRTC_SPL_RSHIFT_U32(tempU32, 14-numShift); /* right-shift */
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
/* shift no more than 14 steps */
|
||
|
numShift = 14;
|
||
|
}
|
||
|
|
||
|
if (tempU32 == 0)
|
||
|
{
|
||
|
/* check for zero denominator; result should be zero in this case */
|
||
|
stats->currentAccelerateRate = 0;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
/* check that denominator fits in signed 16-bit */
|
||
|
while (tempU32 > WEBRTC_SPL_WORD16_MAX)
|
||
|
{
|
||
|
tempU32 >>= 1; /* right-shift 1 step */
|
||
|
numShift--; /* compensate in numerator */
|
||
|
}
|
||
|
tempU16 = (WebRtc_UWord16) tempU32;
|
||
|
|
||
|
/* do the shift of numerator */
|
||
|
tempU32
|
||
|
= WEBRTC_SPL_SHIFT_W32( NetEqMainInst->DSPinst.statInst.accelerateLength, numShift);
|
||
|
|
||
|
stats->currentAccelerateRate = (WebRtc_UWord16) WebRtcSpl_DivU32U16(tempU32,
|
||
|
tempU16);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
/* lost count is larger than elapsed time count; probably timestamp wrap-around or something else wrong */
|
||
|
/* set loss rate = 1 */
|
||
|
stats->currentAccelerateRate = 1 << 14; /* 1 in Q14 */
|
||
|
}
|
||
|
|
||
|
/* also transfer measure to post-call statistics */
|
||
|
NetEqMainInst->MCUinst.statInst.accelerateMs
|
||
|
+= WebRtcSpl_DivU32U16(
|
||
|
WEBRTC_SPL_UMUL_32_16( NetEqMainInst->DSPinst.statInst.accelerateLength, (WebRtc_UWord16) 1000),
|
||
|
NetEqMainInst->MCUinst.fs);
|
||
|
|
||
|
/* timestamps elapsed since last report */
|
||
|
tempU32 = NetEqMainInst->MCUinst.lastReportTS;
|
||
|
|
||
|
if (NetEqMainInst->DSPinst.statInst.expandLength == 0)
|
||
|
{
|
||
|
/* no expand */
|
||
|
stats->currentExpandRate = 0;
|
||
|
}
|
||
|
else if (NetEqMainInst->DSPinst.statInst.expandLength < tempU32)
|
||
|
{
|
||
|
/* calculate shifts; we want the result in Q14 */
|
||
|
numShift = WebRtcSpl_NormU32(NetEqMainInst->DSPinst.statInst.expandLength); /* numerator shift for normalize */
|
||
|
|
||
|
if (numShift < 14)
|
||
|
{
|
||
|
/* cannot shift numerator 14 steps; shift denominator too */
|
||
|
tempU32 = WEBRTC_SPL_RSHIFT_U32(tempU32, 14-numShift); /* right-shift */
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
/* shift no more than 14 steps */
|
||
|
numShift = 14;
|
||
|
}
|
||
|
|
||
|
if (tempU32 == 0)
|
||
|
{
|
||
|
/* check for zero denominator; result should be zero in this case */
|
||
|
stats->currentExpandRate = 0;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
/* check that denominator fits in signed 16-bit */
|
||
|
while (tempU32 > WEBRTC_SPL_WORD16_MAX)
|
||
|
{
|
||
|
tempU32 >>= 1; /* right-shift 1 step */
|
||
|
numShift--; /* compensate in numerator */
|
||
|
}
|
||
|
tempU16 = (WebRtc_UWord16) tempU32;
|
||
|
|
||
|
/* do the shift of numerator */
|
||
|
tempU32
|
||
|
= WEBRTC_SPL_SHIFT_W32( NetEqMainInst->DSPinst.statInst.expandLength, numShift);
|
||
|
|
||
|
stats->currentExpandRate = (WebRtc_UWord16) WebRtcSpl_DivU32U16(tempU32, tempU16);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
/* lost count is larger than elapsed time count; probably timestamp wrap-around or something else wrong */
|
||
|
/* set loss rate = 1 */
|
||
|
stats->currentExpandRate = 1 << 14; /* 1 in Q14 */
|
||
|
}
|
||
|
|
||
|
/* timestamps elapsed since last report */
|
||
|
tempU32 = NetEqMainInst->MCUinst.lastReportTS;
|
||
|
|
||
|
if (NetEqMainInst->DSPinst.statInst.preemptiveLength == 0)
|
||
|
{
|
||
|
/* no pre-emptive expand */
|
||
|
stats->currentPreemptiveRate = 0;
|
||
|
}
|
||
|
else if (NetEqMainInst->DSPinst.statInst.preemptiveLength < tempU32)
|
||
|
{
|
||
|
/* calculate shifts; we want the result in Q14 */
|
||
|
numShift = WebRtcSpl_NormU32(NetEqMainInst->DSPinst.statInst.preemptiveLength); /* numerator shift for normalize */
|
||
|
|
||
|
if (numShift < 14)
|
||
|
{
|
||
|
/* cannot shift numerator 14 steps; shift denominator too */
|
||
|
tempU32 = WEBRTC_SPL_RSHIFT_U32(tempU32, 14-numShift); /* right-shift */
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
/* shift no more than 14 steps */
|
||
|
numShift = 14;
|
||
|
}
|
||
|
|
||
|
if (tempU32 == 0)
|
||
|
{
|
||
|
/* check for zero denominator; result should be zero in this case */
|
||
|
stats->currentPreemptiveRate = 0;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
/* check that denominator fits in signed 16-bit */
|
||
|
while (tempU32 > WEBRTC_SPL_WORD16_MAX)
|
||
|
{
|
||
|
tempU32 >>= 1; /* right-shift 1 step */
|
||
|
numShift--; /* compensate in numerator */
|
||
|
}
|
||
|
tempU16 = (WebRtc_UWord16) tempU32;
|
||
|
|
||
|
/* do the shift of numerator */
|
||
|
tempU32
|
||
|
= WEBRTC_SPL_SHIFT_W32( NetEqMainInst->DSPinst.statInst.preemptiveLength, numShift);
|
||
|
|
||
|
stats->currentPreemptiveRate = (WebRtc_UWord16) WebRtcSpl_DivU32U16(tempU32,
|
||
|
tempU16);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
/* lost count is larger than elapsed time count; probably timestamp wrap-around or something else wrong */
|
||
|
/* set loss rate = 1 */
|
||
|
stats->currentPreemptiveRate = 1 << 14; /* 1 in Q14 */
|
||
|
}
|
||
|
|
||
|
/* reset counters */
|
||
|
WebRtcNetEQ_ResetMcuInCallStats(&(NetEqMainInst->MCUinst));
|
||
|
WebRtcNetEQ_ClearInCallStats(&(NetEqMainInst->DSPinst));
|
||
|
|
||
|
return (0);
|
||
|
}
|
||
|
|
||
|
/* Get the optimal buffer size calculated for the current network conditions. */
|
||
|
int WebRtcNetEQ_GetPreferredBufferSize(void *inst, WebRtc_UWord16 *preferredBufferSize)
|
||
|
{
|
||
|
|
||
|
MainInst_t *NetEqMainInst = (MainInst_t*) inst;
|
||
|
|
||
|
/***************************/
|
||
|
/* Get optimal buffer size */
|
||
|
/***************************/
|
||
|
|
||
|
if (NetEqMainInst->MCUinst.fs != 0 && NetEqMainInst->MCUinst.fs <= WEBRTC_SPL_WORD16_MAX)
|
||
|
{
|
||
|
/* preferredBufferSize = Bopt * packSizeSamples / (fs/1000) */
|
||
|
*preferredBufferSize
|
||
|
= (WebRtc_UWord16) WEBRTC_SPL_MUL_16_16(
|
||
|
(WebRtc_Word16) ((NetEqMainInst->MCUinst.BufferStat_inst.Automode_inst.optBufLevel) >> 8), /* optimal buffer level in packets shifted to Q0 */
|
||
|
WebRtcSpl_DivW32W16ResW16(
|
||
|
(WebRtc_Word32) NetEqMainInst->MCUinst.BufferStat_inst.Automode_inst.packetSpeechLenSamp, /* samples per packet */
|
||
|
WebRtcSpl_DivW32W16ResW16( (WebRtc_Word32) NetEqMainInst->MCUinst.fs, (WebRtc_Word16) 1000 ) /* samples per ms */
|
||
|
) );
|
||
|
|
||
|
/* add extra delay */
|
||
|
if (NetEqMainInst->MCUinst.BufferStat_inst.Automode_inst.extraDelayMs > 0)
|
||
|
{
|
||
|
*preferredBufferSize
|
||
|
+= NetEqMainInst->MCUinst.BufferStat_inst.Automode_inst.extraDelayMs;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
/* sample rate not initialized */
|
||
|
*preferredBufferSize = 0;
|
||
|
}
|
||
|
|
||
|
return (0);
|
||
|
|
||
|
}
|
||
|
|
||
|
/* Get the current buffer size in ms. Return value is 0 if ok, -1 if error. */
|
||
|
int WebRtcNetEQ_GetCurrentDelay(const void *inst, WebRtc_UWord16 *currentDelayMs)
|
||
|
{
|
||
|
WebRtc_Word32 temp32;
|
||
|
const MainInst_t *NetEqMainInst = (const MainInst_t*) inst;
|
||
|
|
||
|
/* Instance sanity */
|
||
|
if (NetEqMainInst == NULL) return (-1);
|
||
|
|
||
|
/*******************/
|
||
|
/* Get buffer size */
|
||
|
/*******************/
|
||
|
|
||
|
if (NetEqMainInst->MCUinst.fs != 0 && NetEqMainInst->MCUinst.fs <= WEBRTC_SPL_WORD16_MAX)
|
||
|
{
|
||
|
/* query packet buffer for number of samples */
|
||
|
temp32 = WebRtcNetEQ_PacketBufferGetSize(&NetEqMainInst->MCUinst.PacketBuffer_inst);
|
||
|
|
||
|
/* divide by sample rate */
|
||
|
*currentDelayMs = WebRtcSpl_DivW32W16ResW16(temp32 * 1000, /* multiply by 1000 to get ms */
|
||
|
(WebRtc_Word16) NetEqMainInst->MCUinst.fs); /* divide by fs in samples per second */
|
||
|
|
||
|
/* add number of samples yet to play in sync buffer */
|
||
|
temp32 = (WebRtc_Word32) (NetEqMainInst->DSPinst.endPosition
|
||
|
- NetEqMainInst->DSPinst.curPosition);
|
||
|
*currentDelayMs += WebRtcSpl_DivW32W16ResW16(temp32 * 1000, /* multiply by 1000 to get ms */
|
||
|
(WebRtc_Word16) NetEqMainInst->MCUinst.fs); /* divide by fs in samples per second */
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
/* sample rate not initialized */
|
||
|
*currentDelayMs = 0;
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
/* Get the "post-call" jitter statistics from NetEQ.
|
||
|
* The statistics are not reset by the query. Use the function WebRtcNetEQ_ResetJitterStatistics
|
||
|
* to reset the statistics. */
|
||
|
int WebRtcNetEQ_GetJitterStatistics(void *inst, WebRtcNetEQ_JitterStatistics *jitterStats)
|
||
|
{
|
||
|
|
||
|
MainInst_t *NetEqMainInst = (MainInst_t*) inst;
|
||
|
|
||
|
/* collect statistics not yet transfered to post-call statistics */
|
||
|
NetEqMainInst->MCUinst.statInst.accelerateMs
|
||
|
+= WebRtcSpl_DivU32U16(
|
||
|
WEBRTC_SPL_UMUL_32_16( NetEqMainInst->DSPinst.statInst.accelerateLength, (WebRtc_UWord16) 1000),
|
||
|
NetEqMainInst->MCUinst.fs);
|
||
|
|
||
|
jitterStats->jbMinSize = NetEqMainInst->MCUinst.statInst.jbMinSize; /* smallest Jitter Buffer size during call - mSec */
|
||
|
jitterStats->jbMaxSize = NetEqMainInst->MCUinst.statInst.jbMaxSize; /* largest Jitter Buffer size during call - mSec */
|
||
|
jitterStats->jbAvgSize = NetEqMainInst->MCUinst.statInst.jbAvgSizeQ16 >> 16; /* the average JB size, measured over time - mSec */
|
||
|
jitterStats->jbChangeCount = NetEqMainInst->MCUinst.statInst.jbChangeCount; /* number of times the Jitter Buffer changed */
|
||
|
jitterStats->lateLossMs = (NetEqMainInst->MCUinst.PacketBuffer_inst.totalDiscardedPackets
|
||
|
* NetEqMainInst->MCUinst.PacketBuffer_inst.packSizeSamples * 1000)
|
||
|
/ NetEqMainInst->MCUinst.fs; /* number of frames received late */
|
||
|
jitterStats->accelerateMs = NetEqMainInst->MCUinst.statInst.accelerateMs; /* milliseconds removed to reduce jitter buffer size */
|
||
|
jitterStats->flushedMs = (NetEqMainInst->MCUinst.PacketBuffer_inst.totalFlushedPackets
|
||
|
* NetEqMainInst->MCUinst.PacketBuffer_inst.packSizeSamples * 1000)
|
||
|
/ NetEqMainInst->MCUinst.fs;
|
||
|
jitterStats->generatedSilentMs = NetEqMainInst->MCUinst.statInst.generatedSilentMs; /* number of generated silence frames */
|
||
|
jitterStats->countExpandMoreThan120ms
|
||
|
= NetEqMainInst->MCUinst.statInst.countExpandMoreThan120ms; /* count of tiny BFI events output audio */
|
||
|
jitterStats->countExpandMoreThan250ms
|
||
|
= NetEqMainInst->MCUinst.statInst.countExpandMoreThan250ms; /* count of small BFI events output audio */
|
||
|
jitterStats->countExpandMoreThan500ms
|
||
|
= NetEqMainInst->MCUinst.statInst.countExpandMoreThan500ms; /* count of medium BFI events output audio */
|
||
|
jitterStats->countExpandMoreThan2000ms
|
||
|
= NetEqMainInst->MCUinst.statInst.countExpandMoreThan2000ms; /* count of large BFI events output audio */
|
||
|
jitterStats->longestExpandDurationMs
|
||
|
= NetEqMainInst->MCUinst.statInst.longestExpandDurationMs; /* mSec duration of longest audio drop-out */
|
||
|
jitterStats->countIAT500ms
|
||
|
= NetEqMainInst->MCUinst.BufferStat_inst.Automode_inst.countIAT500ms; /* count of times we got small network outage */
|
||
|
jitterStats->countIAT1000ms
|
||
|
= NetEqMainInst->MCUinst.BufferStat_inst.Automode_inst.countIAT1000ms; /* count of times we got medium network outage */
|
||
|
jitterStats->countIAT2000ms
|
||
|
= NetEqMainInst->MCUinst.BufferStat_inst.Automode_inst.countIAT2000ms; /* count of times we got large network outage */
|
||
|
jitterStats->longestIATms
|
||
|
= NetEqMainInst->MCUinst.BufferStat_inst.Automode_inst.longestIATms; /* mSec duration of longest network outage */
|
||
|
jitterStats->minPacketDelayMs = NetEqMainInst->MCUinst.statInst.minPacketDelayMs; /* min time incoming frame "waited" to be played */
|
||
|
jitterStats->maxPacketDelayMs = NetEqMainInst->MCUinst.statInst.maxPacketDelayMs; /* max time incoming frame "waited" to be played */
|
||
|
jitterStats->avgPacketDelayMs = NetEqMainInst->MCUinst.statInst.avgPacketDelayMs; /* avg time incoming frame "waited" to be played */
|
||
|
|
||
|
jitterStats->interpolatedVoiceMs
|
||
|
= WebRtcSpl_DivU32U16(
|
||
|
WEBRTC_SPL_UMUL_32_16( NetEqMainInst->DSPinst.statInst.expandedVoiceSamples, (WebRtc_UWord16) 1000),
|
||
|
NetEqMainInst->MCUinst.fs); /* interpolated voice in ms */
|
||
|
jitterStats->interpolatedSilentMs
|
||
|
= WebRtcSpl_DivU32U16(
|
||
|
WEBRTC_SPL_UMUL_32_16( NetEqMainInst->DSPinst.statInst.expandedNoiseSamples, (WebRtc_UWord16) 1000),
|
||
|
NetEqMainInst->MCUinst.fs); /* interpolated silence in ms */
|
||
|
|
||
|
return (0);
|
||
|
}
|
||
|
|
||
|
/* Reset "post-call" jitter statistics. */
|
||
|
int WebRtcNetEQ_ResetJitterStatistics(void *inst)
|
||
|
{
|
||
|
|
||
|
MainInst_t *NetEqMainInst = (MainInst_t*) inst;
|
||
|
|
||
|
WebRtcNetEQ_ResetMcuJitterStat(&(NetEqMainInst->MCUinst));
|
||
|
|
||
|
WebRtcNetEQ_ClearPostCallStats(&(NetEqMainInst->DSPinst));
|
||
|
|
||
|
return (0);
|
||
|
}
|
||
|
|
||
|
/****************************************************************************
|
||
|
* WebRtcNetEQ_SetVADInstance(...)
|
||
|
*
|
||
|
* Provide a pointer to an allocated VAD instance. If function is never
|
||
|
* called or it is called with NULL pointer as VAD_inst, the post-decode
|
||
|
* VAD functionality is disabled. Also provide pointers to init, setmode
|
||
|
* and VAD functions. These are typically pointers to WebRtcVad_Init,
|
||
|
* WebRtcVad_set_mode and WebRtcVad_Process, respectively, all found in the
|
||
|
* interface file webrtc_vad.h.
|
||
|
*
|
||
|
* Input:
|
||
|
* - NetEQ_inst : NetEQ instance
|
||
|
* - VADinst : VAD instance
|
||
|
* - initFunction : Pointer to VAD init function
|
||
|
* - setmodeFunction : Pointer to VAD setmode function
|
||
|
* - VADfunction : Pointer to VAD function
|
||
|
*
|
||
|
* Output:
|
||
|
* - NetEQ_inst : Updated NetEQ instance
|
||
|
*
|
||
|
* Return value : 0 - Ok
|
||
|
* -1 - Error
|
||
|
*/
|
||
|
|
||
|
int WebRtcNetEQ_SetVADInstance(void *NetEQ_inst, void *VAD_inst,
|
||
|
WebRtcNetEQ_VADInitFunction initFunction,
|
||
|
WebRtcNetEQ_VADSetmodeFunction setmodeFunction,
|
||
|
WebRtcNetEQ_VADFunction VADFunction)
|
||
|
{
|
||
|
|
||
|
/* Typecast to internal instance type */
|
||
|
MainInst_t *NetEqMainInst = (MainInst_t*) NetEQ_inst;
|
||
|
if (NetEqMainInst == NULL)
|
||
|
{
|
||
|
return (-1);
|
||
|
}
|
||
|
|
||
|
#ifdef NETEQ_VAD
|
||
|
|
||
|
/* Store pointer in PostDecode VAD struct */
|
||
|
NetEqMainInst->DSPinst.VADInst.VADState = VAD_inst;
|
||
|
|
||
|
/* Store function pointers */
|
||
|
NetEqMainInst->DSPinst.VADInst.initFunction = initFunction;
|
||
|
NetEqMainInst->DSPinst.VADInst.setmodeFunction = setmodeFunction;
|
||
|
NetEqMainInst->DSPinst.VADInst.VADFunction = VADFunction;
|
||
|
|
||
|
/* Call init function and return the result (ok or fail) */
|
||
|
return(WebRtcNetEQ_InitVAD(&NetEqMainInst->DSPinst.VADInst, NetEqMainInst->DSPinst.fs));
|
||
|
|
||
|
#else /* NETEQ_VAD not defined */
|
||
|
return (-1);
|
||
|
#endif /* NETEQ_VAD */
|
||
|
|
||
|
}
|
||
|
|
||
|
/****************************************************************************
|
||
|
* WebRtcNetEQ_SetVADMode(...)
|
||
|
*
|
||
|
* Pass an aggressiveness mode parameter to the post-decode VAD instance.
|
||
|
* If this function is never called, mode 0 (quality mode) is used as default.
|
||
|
*
|
||
|
* Input:
|
||
|
* - inst : NetEQ instance
|
||
|
* - mode : mode parameter (same range as WebRtc VAD mode)
|
||
|
*
|
||
|
* Output:
|
||
|
* - inst : Updated NetEQ instance
|
||
|
*
|
||
|
* Return value : 0 - Ok
|
||
|
* -1 - Error
|
||
|
*/
|
||
|
|
||
|
int WebRtcNetEQ_SetVADMode(void *inst, WebRtc_Word16 mode)
|
||
|
{
|
||
|
|
||
|
/* Typecast to internal instance type */
|
||
|
MainInst_t *NetEqMainInst = (MainInst_t*) inst;
|
||
|
if (NetEqMainInst == NULL)
|
||
|
{
|
||
|
return (-1);
|
||
|
}
|
||
|
|
||
|
#ifdef NETEQ_VAD
|
||
|
|
||
|
/* Set mode and return result */
|
||
|
return(WebRtcNetEQ_SetVADModeInternal(&NetEqMainInst->DSPinst.VADInst, mode));
|
||
|
|
||
|
#else /* NETEQ_VAD not defined */
|
||
|
return (-1);
|
||
|
#endif /* NETEQ_VAD */
|
||
|
|
||
|
}
|