Deleting all NetEq3 files
NetEq3 is deprecated and replaced by NetEq4 (webrtc/modules/audio_coding/neteq4/). BUG=2996 R=turaj@webrtc.org Review URL: https://webrtc-codereview.appspot.com/14469007 git-svn-id: http://webrtc.googlecode.com/svn/trunk@6118 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
parent
4d363ae305
commit
c3e8abda7c
@ -1,73 +0,0 @@
|
||||
# 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.
|
||||
|
||||
LOCAL_PATH := $(call my-dir)
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
include $(LOCAL_PATH)/../../../../android-webrtc.mk
|
||||
|
||||
LOCAL_ARM_MODE := arm
|
||||
LOCAL_MODULE_CLASS := STATIC_LIBRARIES
|
||||
LOCAL_MODULE := libwebrtc_neteq
|
||||
LOCAL_MODULE_TAGS := optional
|
||||
LOCAL_SRC_FILES := \
|
||||
accelerate.c \
|
||||
automode.c \
|
||||
bgn_update.c \
|
||||
bufstats_decision.c \
|
||||
cng_internal.c \
|
||||
codec_db.c \
|
||||
correlator.c \
|
||||
dsp.c \
|
||||
dsp_helpfunctions.c \
|
||||
dtmf_buffer.c \
|
||||
dtmf_tonegen.c \
|
||||
expand.c \
|
||||
mcu_address_init.c \
|
||||
mcu_dsp_common.c \
|
||||
mcu_reset.c \
|
||||
merge.c \
|
||||
min_distortion.c \
|
||||
mix_voice_unvoice.c \
|
||||
mute_signal.c \
|
||||
normal.c \
|
||||
packet_buffer.c \
|
||||
peak_detection.c \
|
||||
preemptive_expand.c \
|
||||
random_vector.c \
|
||||
recin.c \
|
||||
recout.c \
|
||||
rtcp.c \
|
||||
rtp.c \
|
||||
set_fs.c \
|
||||
signal_mcu.c \
|
||||
split_and_insert.c \
|
||||
unmute_signal.c \
|
||||
webrtc_neteq.c
|
||||
|
||||
# Flags passed to both C and C++ files.
|
||||
LOCAL_CFLAGS := \
|
||||
$(MY_WEBRTC_COMMON_DEFS) \
|
||||
'-DNETEQ_VOICEENGINE_CODECS'
|
||||
|
||||
LOCAL_C_INCLUDES := \
|
||||
$(LOCAL_PATH)/interface \
|
||||
$(LOCAL_PATH)/../codecs/cng/include \
|
||||
$(LOCAL_PATH)/../../.. \
|
||||
$(LOCAL_PATH)/../../../common_audio/signal_processing/include
|
||||
|
||||
LOCAL_SHARED_LIBRARIES := \
|
||||
libcutils \
|
||||
libdl \
|
||||
libstlport
|
||||
|
||||
ifndef NDK_ROOT
|
||||
include external/stlport/libstlport.mk
|
||||
endif
|
||||
include $(BUILD_STATIC_LIBRARY)
|
@ -1,8 +0,0 @@
|
||||
henrik.lundin@webrtc.org
|
||||
tina.legrand@webrtc.org
|
||||
turaj@webrtc.org
|
||||
|
||||
# These are for the common case of adding or renaming files. If you're doing
|
||||
# structural changes, please get a review from a reviewer in this file.
|
||||
per-file *.gyp=*
|
||||
per-file *.gypi=*
|
@ -1,493 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file contains the Accelerate algorithm that is used to reduce
|
||||
* the delay by removing a part of the audio stream.
|
||||
*/
|
||||
|
||||
#include "dsp.h"
|
||||
|
||||
#include "signal_processing_library.h"
|
||||
|
||||
#include "dsp_helpfunctions.h"
|
||||
#include "neteq_error_codes.h"
|
||||
|
||||
#define ACCELERATE_CORR_LEN 50
|
||||
#define ACCELERATE_MIN_LAG 10
|
||||
#define ACCELERATE_MAX_LAG 60
|
||||
#define ACCELERATE_DOWNSAMPLED_LEN (ACCELERATE_CORR_LEN + ACCELERATE_MAX_LAG)
|
||||
|
||||
/* Scratch usage:
|
||||
|
||||
Type Name size startpos endpos
|
||||
int16_t pw16_downSampSpeech 110 0 109
|
||||
int32_t pw32_corr 2*50 110 209
|
||||
int16_t pw16_corr 50 0 49
|
||||
|
||||
Total: 110+2*50
|
||||
*/
|
||||
|
||||
#define SCRATCH_PW16_DS_SPEECH 0
|
||||
#define SCRATCH_PW32_CORR ACCELERATE_DOWNSAMPLED_LEN
|
||||
#define SCRATCH_PW16_CORR 0
|
||||
|
||||
/****************************************************************************
|
||||
* WebRtcNetEQ_Accelerate(...)
|
||||
*
|
||||
* This function tries to shorten the audio data by removing one or several
|
||||
* pitch periods. The operation is only carried out if the correlation is
|
||||
* strong or if the signal energy is very low.
|
||||
*
|
||||
* Input:
|
||||
* - inst : NetEQ DSP instance
|
||||
* - scratchPtr : Pointer to scratch vector.
|
||||
* - decoded : Pointer to newly decoded speech.
|
||||
* - len : Length of decoded speech.
|
||||
* - BGNonly : If non-zero, Accelerate will only remove the last
|
||||
* DEFAULT_TIME_ADJUST seconds of the input.
|
||||
* No signal matching is done.
|
||||
*
|
||||
* Output:
|
||||
* - inst : Updated instance
|
||||
* - outData : Pointer to a memory space where the output data
|
||||
* should be stored
|
||||
* - pw16_len : Number of samples written to outData.
|
||||
*
|
||||
* Return value : 0 - Ok
|
||||
* <0 - Error
|
||||
*/
|
||||
|
||||
int WebRtcNetEQ_Accelerate(DSPInst_t *inst,
|
||||
#ifdef SCRATCH
|
||||
int16_t *pw16_scratchPtr,
|
||||
#endif
|
||||
const int16_t *pw16_decoded, int len,
|
||||
int16_t *pw16_outData, int16_t *pw16_len,
|
||||
int16_t BGNonly)
|
||||
{
|
||||
|
||||
#ifdef SCRATCH
|
||||
/* Use scratch memory for internal temporary vectors */
|
||||
int16_t *pw16_downSampSpeech = pw16_scratchPtr + SCRATCH_PW16_DS_SPEECH;
|
||||
int32_t *pw32_corr = (int32_t*) (pw16_scratchPtr + SCRATCH_PW32_CORR);
|
||||
int16_t *pw16_corr = pw16_scratchPtr + SCRATCH_PW16_CORR;
|
||||
#else
|
||||
/* Allocate memory for temporary vectors */
|
||||
int16_t pw16_downSampSpeech[ACCELERATE_DOWNSAMPLED_LEN];
|
||||
int32_t pw32_corr[ACCELERATE_CORR_LEN];
|
||||
int16_t pw16_corr[ACCELERATE_CORR_LEN];
|
||||
#endif
|
||||
int16_t w16_decodedMax = 0;
|
||||
int16_t w16_tmp;
|
||||
int16_t w16_tmp2;
|
||||
int32_t w32_tmp;
|
||||
int32_t w32_tmp2;
|
||||
|
||||
const int16_t w16_startLag = ACCELERATE_MIN_LAG;
|
||||
const int16_t w16_endLag = ACCELERATE_MAX_LAG;
|
||||
const int16_t w16_corrLen = ACCELERATE_CORR_LEN;
|
||||
const int16_t *pw16_vec1, *pw16_vec2;
|
||||
int16_t *pw16_vectmp;
|
||||
int16_t w16_inc, w16_startfact;
|
||||
int16_t w16_bestIndex, w16_bestVal;
|
||||
int16_t w16_VAD = 1;
|
||||
int16_t fsMult;
|
||||
int16_t fsMult120;
|
||||
int32_t w32_en1, w32_en2, w32_cc;
|
||||
int16_t w16_en1, w16_en2;
|
||||
int16_t w16_en1Scale, w16_en2Scale;
|
||||
int16_t w16_sqrtEn1En2;
|
||||
int16_t w16_bestCorr = 0;
|
||||
int ok;
|
||||
|
||||
#ifdef NETEQ_STEREO
|
||||
MasterSlaveInfo *msInfo = inst->msInfo;
|
||||
#endif
|
||||
|
||||
fsMult = WebRtcNetEQ_CalcFsMult(inst->fs); /* Calculate fs/8000 */
|
||||
|
||||
/* Pre-calculate common multiplication with fsMult */
|
||||
fsMult120 = (int16_t) WEBRTC_SPL_MUL_16_16(fsMult, 120); /* 15 ms */
|
||||
|
||||
inst->ExpandInst.w16_consecExp = 0; /* Last was not expand any more */
|
||||
|
||||
/* Sanity check for len variable; must be (almost) 30 ms
|
||||
(120*fsMult + max(bestIndex)) */
|
||||
if (len < (int16_t) WEBRTC_SPL_MUL_16_16((120 + 119), fsMult))
|
||||
{
|
||||
/* Length of decoded data too short */
|
||||
inst->w16_mode = MODE_UNSUCCESS_ACCELERATE;
|
||||
*pw16_len = len;
|
||||
|
||||
/* simply move all data from decoded to outData */
|
||||
WEBRTC_SPL_MEMMOVE_W16(pw16_outData, pw16_decoded, (int16_t) len);
|
||||
|
||||
return NETEQ_OTHER_ERROR;
|
||||
}
|
||||
|
||||
/***********************************/
|
||||
/* Special operations for BGN only */
|
||||
/***********************************/
|
||||
|
||||
/* Check if "background noise only" flag is set */
|
||||
if (BGNonly)
|
||||
{
|
||||
/* special operation for BGN only; simply remove a chunk of data */
|
||||
w16_bestIndex = DEFAULT_TIME_ADJUST * WEBRTC_SPL_LSHIFT_W16(fsMult, 3); /* X*fs/1000 */
|
||||
|
||||
/* Sanity check for bestIndex */
|
||||
if (w16_bestIndex > len)
|
||||
{ /* not good, do nothing instead */
|
||||
inst->w16_mode = MODE_UNSUCCESS_ACCELERATE;
|
||||
*pw16_len = len;
|
||||
|
||||
/* simply move all data from decoded to outData */
|
||||
WEBRTC_SPL_MEMMOVE_W16(pw16_outData, pw16_decoded, (int16_t) len);
|
||||
|
||||
return NETEQ_OTHER_ERROR;
|
||||
}
|
||||
|
||||
/* set length parameter */
|
||||
*pw16_len = len - w16_bestIndex; /* we remove bestIndex samples */
|
||||
|
||||
/* copy to output */
|
||||
WEBRTC_SPL_MEMMOVE_W16(pw16_outData, pw16_decoded, *pw16_len);
|
||||
|
||||
/* set mode */
|
||||
inst->w16_mode = MODE_LOWEN_ACCELERATE;
|
||||
|
||||
/* update statistics */
|
||||
inst->statInst.accelerateLength += w16_bestIndex;
|
||||
/* Short-term activity statistics. */
|
||||
inst->activity_stats.accelerate_bgn_samples += w16_bestIndex;
|
||||
|
||||
return 0;
|
||||
} /* end of special code for BGN mode */
|
||||
|
||||
#ifdef NETEQ_STEREO
|
||||
|
||||
/* Sanity for msInfo */
|
||||
if (msInfo == NULL)
|
||||
{
|
||||
/* this should not happen here */
|
||||
return MASTER_SLAVE_ERROR;
|
||||
}
|
||||
|
||||
if (msInfo->msMode != NETEQ_SLAVE)
|
||||
{
|
||||
/* Find correlation lag only for non-slave instances */
|
||||
|
||||
#endif
|
||||
|
||||
/****************************************************************/
|
||||
/* Find the strongest correlation lag by downsampling to 4 kHz, */
|
||||
/* calculating correlation for downsampled signal and finding */
|
||||
/* the strongest correlation peak. */
|
||||
/****************************************************************/
|
||||
|
||||
/* find maximum absolute value */
|
||||
w16_decodedMax = WebRtcSpl_MaxAbsValueW16(pw16_decoded, (int16_t) len);
|
||||
|
||||
/* downsample the decoded speech to 4 kHz */
|
||||
ok = WebRtcNetEQ_DownSampleTo4kHz(pw16_decoded, len, inst->fs, pw16_downSampSpeech,
|
||||
ACCELERATE_DOWNSAMPLED_LEN, 1 /* compensate delay*/);
|
||||
if (ok != 0)
|
||||
{
|
||||
/* error */
|
||||
inst->w16_mode = MODE_UNSUCCESS_ACCELERATE;
|
||||
*pw16_len = len;
|
||||
/* simply move all data from decoded to outData */
|
||||
WEBRTC_SPL_MEMMOVE_W16(pw16_outData, pw16_decoded, (int16_t) len);
|
||||
return NETEQ_OTHER_ERROR;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set scaling factor for cross correlation to protect against overflow
|
||||
* (log2(50) => 6)
|
||||
*/
|
||||
w16_tmp = 6 - WebRtcSpl_NormW32(WEBRTC_SPL_MUL_16_16(w16_decodedMax, w16_decodedMax));
|
||||
w16_tmp = WEBRTC_SPL_MAX(0, w16_tmp);
|
||||
|
||||
/* Perform correlation from lag 10 to lag 60 in 4 kHz domain */
|
||||
WebRtcNetEQ_CrossCorr(
|
||||
pw32_corr, &pw16_downSampSpeech[w16_endLag],
|
||||
&pw16_downSampSpeech[w16_endLag - w16_startLag], w16_corrLen,
|
||||
(int16_t) (w16_endLag - w16_startLag), w16_tmp, -1);
|
||||
|
||||
/* Normalize correlation to 14 bits and put in a int16_t vector */
|
||||
w32_tmp = WebRtcSpl_MaxAbsValueW32(pw32_corr, w16_corrLen);
|
||||
w16_tmp = 17 - WebRtcSpl_NormW32(w32_tmp);
|
||||
w16_tmp = WEBRTC_SPL_MAX(0, w16_tmp);
|
||||
|
||||
WebRtcSpl_VectorBitShiftW32ToW16(pw16_corr, w16_corrLen, pw32_corr, w16_tmp);
|
||||
|
||||
#ifdef NETEQ_STEREO
|
||||
} /* end if (msInfo->msMode != NETEQ_SLAVE) */
|
||||
|
||||
if ((msInfo->msMode == NETEQ_MASTER) || (msInfo->msMode == NETEQ_MONO))
|
||||
{
|
||||
/* Find the strongest correlation peak by using the parabolic fit method */
|
||||
WebRtcNetEQ_PeakDetection(pw16_corr, (int16_t) w16_corrLen, 1, fsMult,
|
||||
&w16_bestIndex, &w16_bestVal);
|
||||
/* 0 <= bestIndex <= (2*corrLen - 1)*fsMult = 99*fsMult */
|
||||
|
||||
/* Compensate bestIndex for displaced starting position */
|
||||
w16_bestIndex = w16_bestIndex + w16_startLag * WEBRTC_SPL_LSHIFT_W16(fsMult, 1);
|
||||
/* 20*fsMult <= bestIndex <= 119*fsMult */
|
||||
|
||||
msInfo->bestIndex = w16_bestIndex;
|
||||
}
|
||||
else if (msInfo->msMode == NETEQ_SLAVE)
|
||||
{
|
||||
if (msInfo->extraInfo == ACC_FAIL)
|
||||
{
|
||||
/* Master has signaled an unsuccessful accelerate */
|
||||
w16_bestIndex = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Get best index from master */
|
||||
w16_bestIndex = msInfo->bestIndex;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Invalid mode */
|
||||
return MASTER_SLAVE_ERROR;
|
||||
}
|
||||
|
||||
#else /* NETEQ_STEREO */
|
||||
|
||||
/* Find the strongest correlation peak by using the parabolic fit method */
|
||||
WebRtcNetEQ_PeakDetection(pw16_corr, (int16_t) w16_corrLen, 1, fsMult,
|
||||
&w16_bestIndex, &w16_bestVal);
|
||||
/* 0 <= bestIndex <= (2*corrLen - 1)*fsMult = 99*fsMult */
|
||||
|
||||
/* Compensate bestIndex for displaced starting position */
|
||||
w16_bestIndex = w16_bestIndex + w16_startLag * WEBRTC_SPL_LSHIFT_W16(fsMult, 1);
|
||||
/* 20*fsMult <= bestIndex <= 119*fsMult */
|
||||
|
||||
#endif /* NETEQ_STEREO */
|
||||
|
||||
#ifdef NETEQ_STEREO
|
||||
|
||||
if (msInfo->msMode != NETEQ_SLAVE)
|
||||
{
|
||||
/* Calculate correlation only for non-slave instances */
|
||||
|
||||
#endif /* NETEQ_STEREO */
|
||||
|
||||
/*****************************************************/
|
||||
/* Calculate correlation bestCorr for the found lag. */
|
||||
/* Also do a simple VAD decision. */
|
||||
/*****************************************************/
|
||||
|
||||
/*
|
||||
* Calculate scaling to ensure that bestIndex samples can be square-summed
|
||||
* without overflowing
|
||||
*/
|
||||
w16_tmp = (31
|
||||
- WebRtcSpl_NormW32(WEBRTC_SPL_MUL_16_16(w16_decodedMax, w16_decodedMax)));
|
||||
w16_tmp += (31 - WebRtcSpl_NormW32(w16_bestIndex));
|
||||
w16_tmp -= 31;
|
||||
w16_tmp = WEBRTC_SPL_MAX(0, w16_tmp);
|
||||
|
||||
/* vec1 starts at 15 ms minus one pitch period */
|
||||
pw16_vec1 = &pw16_decoded[fsMult120 - w16_bestIndex];
|
||||
/* vec2 start at 15 ms */
|
||||
pw16_vec2 = &pw16_decoded[fsMult120];
|
||||
|
||||
/* Calculate energies for vec1 and vec2 */
|
||||
w32_en1 = WebRtcNetEQ_DotW16W16((int16_t*) pw16_vec1,
|
||||
(int16_t*) pw16_vec1, w16_bestIndex, w16_tmp);
|
||||
w32_en2 = WebRtcNetEQ_DotW16W16((int16_t*) pw16_vec2,
|
||||
(int16_t*) pw16_vec2, w16_bestIndex, w16_tmp);
|
||||
|
||||
/* Calculate cross-correlation at the found lag */
|
||||
w32_cc = WebRtcNetEQ_DotW16W16((int16_t*) pw16_vec1, (int16_t*) pw16_vec2,
|
||||
w16_bestIndex, w16_tmp);
|
||||
|
||||
/* Check VAD constraint
|
||||
((en1+en2)/(2*bestIndex)) <= 8*inst->BGNInst.energy */
|
||||
w32_tmp = WEBRTC_SPL_RSHIFT_W32(w32_en1 + w32_en2, 4); /* (en1+en2)/(2*8) */
|
||||
if (inst->BGNInst.w16_initialized == 1)
|
||||
{
|
||||
w32_tmp2 = inst->BGNInst.w32_energy;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* if BGN parameters have not been estimated, use a fixed threshold */
|
||||
w32_tmp2 = 75000;
|
||||
}
|
||||
w16_tmp2 = 16 - WebRtcSpl_NormW32(w32_tmp2);
|
||||
w16_tmp2 = WEBRTC_SPL_MAX(0, w16_tmp2);
|
||||
w32_tmp = WEBRTC_SPL_RSHIFT_W32(w32_tmp, w16_tmp2);
|
||||
w16_tmp2 = (int16_t) WEBRTC_SPL_RSHIFT_W32(w32_tmp2, w16_tmp2);
|
||||
w32_tmp2 = WEBRTC_SPL_MUL_16_16(w16_bestIndex, w16_tmp2);
|
||||
|
||||
/* Scale w32_tmp properly before comparing with w32_tmp2 */
|
||||
/* (w16_tmp is scaling before energy calculation, thus 2*w16_tmp) */
|
||||
if (WebRtcSpl_NormW32(w32_tmp) < WEBRTC_SPL_LSHIFT_W32(w16_tmp,1))
|
||||
{
|
||||
/* Cannot scale only w32_tmp, must scale w32_temp2 too */
|
||||
int16_t tempshift = WebRtcSpl_NormW32(w32_tmp);
|
||||
w32_tmp = WEBRTC_SPL_LSHIFT_W32(w32_tmp, tempshift);
|
||||
w32_tmp2 = WEBRTC_SPL_RSHIFT_W32(w32_tmp2,
|
||||
WEBRTC_SPL_LSHIFT_W32(w16_tmp,1) - tempshift);
|
||||
}
|
||||
else
|
||||
{
|
||||
w32_tmp = WEBRTC_SPL_LSHIFT_W32(w32_tmp,
|
||||
WEBRTC_SPL_LSHIFT_W32(w16_tmp,1));
|
||||
}
|
||||
|
||||
if (w32_tmp <= w32_tmp2) /*((en1+en2)/(2*bestIndex)) <= 8*inst->BGNInst.energy */
|
||||
{
|
||||
/* The signal seems to be passive speech */
|
||||
w16_VAD = 0;
|
||||
w16_bestCorr = 0; /* Correlation does not matter */
|
||||
}
|
||||
else
|
||||
{
|
||||
/* The signal is active speech */
|
||||
w16_VAD = 1;
|
||||
|
||||
/* Calculate correlation (cc/sqrt(en1*en2)) */
|
||||
|
||||
/* Start with calculating scale values */
|
||||
w16_en1Scale = 16 - WebRtcSpl_NormW32(w32_en1);
|
||||
w16_en1Scale = WEBRTC_SPL_MAX(0, w16_en1Scale);
|
||||
w16_en2Scale = 16 - WebRtcSpl_NormW32(w32_en2);
|
||||
w16_en2Scale = WEBRTC_SPL_MAX(0, w16_en2Scale);
|
||||
|
||||
/* Make sure total scaling is even (to simplify scale factor after sqrt) */
|
||||
if ((w16_en1Scale + w16_en2Scale) & 1)
|
||||
{
|
||||
w16_en1Scale += 1;
|
||||
}
|
||||
|
||||
/* Convert energies to int16_t */
|
||||
w16_en1 = (int16_t) WEBRTC_SPL_RSHIFT_W32(w32_en1, w16_en1Scale);
|
||||
w16_en2 = (int16_t) WEBRTC_SPL_RSHIFT_W32(w32_en2, w16_en2Scale);
|
||||
|
||||
/* Calculate energy product */
|
||||
w32_tmp = WEBRTC_SPL_MUL_16_16(w16_en1, w16_en2);
|
||||
|
||||
/* Calculate square-root of energy product */
|
||||
w16_sqrtEn1En2 = (int16_t) WebRtcSpl_SqrtFloor(w32_tmp);
|
||||
|
||||
/* Calculate cc/sqrt(en1*en2) in Q14 */
|
||||
w16_tmp = 14 - WEBRTC_SPL_RSHIFT_W16(w16_en1Scale+w16_en2Scale, 1);
|
||||
w32_cc = WEBRTC_SPL_SHIFT_W32(w32_cc, w16_tmp);
|
||||
w32_cc = WEBRTC_SPL_MAX(0, w32_cc); /* Don't divide with negative number */
|
||||
w16_bestCorr = (int16_t) WebRtcSpl_DivW32W16(w32_cc, w16_sqrtEn1En2);
|
||||
w16_bestCorr = WEBRTC_SPL_MIN(16384, w16_bestCorr); /* set maximum to 1.0 */
|
||||
}
|
||||
|
||||
#ifdef NETEQ_STEREO
|
||||
|
||||
} /* end if (msInfo->msMode != NETEQ_SLAVE) */
|
||||
|
||||
#endif /* NETEQ_STEREO */
|
||||
|
||||
/************************************************/
|
||||
/* Check accelerate criteria and remove samples */
|
||||
/************************************************/
|
||||
|
||||
/* Check for strong correlation (>0.9) or passive speech */
|
||||
#ifdef NETEQ_STEREO
|
||||
if ((((w16_bestCorr > 14746) || (w16_VAD == 0)) && (msInfo->msMode != NETEQ_SLAVE))
|
||||
|| ((msInfo->msMode == NETEQ_SLAVE) && (msInfo->extraInfo != ACC_FAIL)))
|
||||
#else
|
||||
if ((w16_bestCorr > 14746) || (w16_VAD == 0))
|
||||
#endif
|
||||
{
|
||||
/* Do accelerate operation by overlap add */
|
||||
|
||||
/*
|
||||
* Calculate cross-fading slope so that the fading factor goes from
|
||||
* 1 (16384 in Q14) to 0 in one pitch period (bestIndex).
|
||||
*/
|
||||
w16_inc = (int16_t) WebRtcSpl_DivW32W16((int32_t) 16384,
|
||||
(int16_t) (w16_bestIndex + 1)); /* in Q14 */
|
||||
|
||||
/* Initiate fading factor */
|
||||
w16_startfact = 16384 - w16_inc;
|
||||
|
||||
/* vec1 starts at 15 ms minus one pitch period */
|
||||
pw16_vec1 = &pw16_decoded[fsMult120 - w16_bestIndex];
|
||||
/* vec2 start at 15 ms */
|
||||
pw16_vec2 = &pw16_decoded[fsMult120];
|
||||
|
||||
/* Copy unmodified part [0 to 15 ms minus 1 pitch period] */
|
||||
w16_tmp = (fsMult120 - w16_bestIndex);
|
||||
WEBRTC_SPL_MEMMOVE_W16(pw16_outData, pw16_decoded, w16_tmp);
|
||||
|
||||
/* Generate interpolated part of length bestIndex (1 pitch period) */
|
||||
pw16_vectmp = pw16_outData + w16_tmp; /* start of interpolation output */
|
||||
/* Reuse mixing function from Expand */
|
||||
WebRtcNetEQ_MixVoiceUnvoice(pw16_vectmp, (int16_t*) pw16_vec1,
|
||||
(int16_t*) pw16_vec2, &w16_startfact, w16_inc, w16_bestIndex);
|
||||
|
||||
/* Move the last part (also unmodified) */
|
||||
/* Take from decoded at 15 ms + 1 pitch period */
|
||||
pw16_vec2 = &pw16_decoded[fsMult120 + w16_bestIndex];
|
||||
WEBRTC_SPL_MEMMOVE_W16(&pw16_outData[fsMult120], pw16_vec2,
|
||||
(int16_t) (len - fsMult120 - w16_bestIndex));
|
||||
|
||||
/* Set the mode flag */
|
||||
if (w16_VAD)
|
||||
{
|
||||
inst->w16_mode = MODE_SUCCESS_ACCELERATE;
|
||||
}
|
||||
else
|
||||
{
|
||||
inst->w16_mode = MODE_LOWEN_ACCELERATE;
|
||||
}
|
||||
|
||||
/* Calculate resulting length = original length - pitch period */
|
||||
*pw16_len = len - w16_bestIndex;
|
||||
|
||||
/* Update in-call statistics */
|
||||
inst->statInst.accelerateLength += w16_bestIndex;
|
||||
/* Short-term activity statistics. */
|
||||
inst->activity_stats.accelarate_normal_samples += w16_bestIndex;
|
||||
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Accelerate not allowed */
|
||||
|
||||
#ifdef NETEQ_STEREO
|
||||
/* Signal to slave(s) that this was unsuccessful */
|
||||
if (msInfo->msMode == NETEQ_MASTER)
|
||||
{
|
||||
msInfo->extraInfo = ACC_FAIL;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Set mode flag to unsuccessful accelerate */
|
||||
inst->w16_mode = MODE_UNSUCCESS_ACCELERATE;
|
||||
|
||||
/* Length is unmodified */
|
||||
*pw16_len = len;
|
||||
|
||||
/* Simply move all data from decoded to outData */
|
||||
WEBRTC_SPL_MEMMOVE_W16(pw16_outData, pw16_decoded, (int16_t) len);
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
#undef SCRATCH_PW16_DS_SPEECH
|
||||
#undef SCRATCH_PW32_CORR
|
||||
#undef SCRATCH_PW16_CORR
|
@ -1,783 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file contains the implementation of automatic buffer level optimization.
|
||||
*/
|
||||
|
||||
#include "automode.h"
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include "signal_processing_library.h"
|
||||
|
||||
#include "neteq_defines.h"
|
||||
|
||||
#ifdef NETEQ_DELAY_LOGGING
|
||||
/* special code for offline delay logging */
|
||||
#include <stdio.h>
|
||||
#include "delay_logging.h"
|
||||
|
||||
extern FILE *delay_fid2; /* file pointer to delay log file */
|
||||
#endif /* NETEQ_DELAY_LOGGING */
|
||||
|
||||
// These two functions are copied from module_common_types.h, but adapted for C.
|
||||
int WebRtcNetEQ_IsNewerSequenceNumber(uint16_t sequence_number,
|
||||
uint16_t prev_sequence_number) {
|
||||
return sequence_number != prev_sequence_number &&
|
||||
((uint16_t) (sequence_number - prev_sequence_number)) < 0x8000;
|
||||
}
|
||||
|
||||
int WebRtcNetEQ_IsNewerTimestamp(uint32_t timestamp, uint32_t prev_timestamp) {
|
||||
return timestamp != prev_timestamp &&
|
||||
((uint32_t) (timestamp - prev_timestamp)) < 0x80000000;
|
||||
}
|
||||
|
||||
int WebRtcNetEQ_UpdateIatStatistics(AutomodeInst_t *inst, int maxBufLen,
|
||||
uint16_t seqNumber, uint32_t timeStamp,
|
||||
int32_t fsHz, int mdCodec, int streamingMode)
|
||||
{
|
||||
uint32_t timeIat; /* inter-arrival time */
|
||||
int i;
|
||||
int32_t tempsum = 0; /* temp summation */
|
||||
int32_t tempvar; /* temporary variable */
|
||||
int retval = 0; /* return value */
|
||||
int16_t packetLenSamp; /* packet speech length in samples */
|
||||
|
||||
/****************/
|
||||
/* Sanity check */
|
||||
/****************/
|
||||
|
||||
if (maxBufLen <= 1 || fsHz <= 0)
|
||||
{
|
||||
/* maxBufLen must be at least 2 and fsHz must both be strictly positive */
|
||||
return -1;
|
||||
}
|
||||
|
||||
/****************************/
|
||||
/* Update packet statistics */
|
||||
/****************************/
|
||||
|
||||
/* Try calculating packet length from current and previous timestamps */
|
||||
if (!WebRtcNetEQ_IsNewerTimestamp(timeStamp, inst->lastTimeStamp) ||
|
||||
!WebRtcNetEQ_IsNewerSequenceNumber(seqNumber, inst->lastSeqNo))
|
||||
{
|
||||
/* Wrong timestamp or sequence order; revert to backup plan */
|
||||
packetLenSamp = inst->packetSpeechLenSamp; /* use stored value */
|
||||
}
|
||||
else
|
||||
{
|
||||
/* calculate timestamps per packet */
|
||||
packetLenSamp = (int16_t) WebRtcSpl_DivU32U16(timeStamp - inst->lastTimeStamp,
|
||||
seqNumber - inst->lastSeqNo);
|
||||
}
|
||||
|
||||
/* Check that the packet size is positive; if not, the statistics cannot be updated. */
|
||||
if (inst->firstPacketReceived && packetLenSamp > 0)
|
||||
{ /* packet size ok */
|
||||
|
||||
/* calculate inter-arrival time in integer packets (rounding down) */
|
||||
timeIat = WebRtcSpl_DivW32W16(inst->packetIatCountSamp, packetLenSamp);
|
||||
|
||||
/* Special operations for streaming mode */
|
||||
if (streamingMode != 0)
|
||||
{
|
||||
/*
|
||||
* Calculate IAT in Q8, including fractions of a packet (i.e., more accurate
|
||||
* than timeIat).
|
||||
*/
|
||||
int16_t timeIatQ8 = (int16_t) WebRtcSpl_DivW32W16(
|
||||
WEBRTC_SPL_LSHIFT_W32(inst->packetIatCountSamp, 8), packetLenSamp);
|
||||
|
||||
/*
|
||||
* Calculate cumulative sum iat with sequence number compensation (ideal arrival
|
||||
* times makes this sum zero).
|
||||
*/
|
||||
inst->cSumIatQ8 += (timeIatQ8
|
||||
- WEBRTC_SPL_LSHIFT_W32(seqNumber - inst->lastSeqNo, 8));
|
||||
|
||||
/* subtract drift term */
|
||||
inst->cSumIatQ8 -= CSUM_IAT_DRIFT;
|
||||
|
||||
/* ensure not negative */
|
||||
inst->cSumIatQ8 = WEBRTC_SPL_MAX(inst->cSumIatQ8, 0);
|
||||
|
||||
/* remember max */
|
||||
if (inst->cSumIatQ8 > inst->maxCSumIatQ8)
|
||||
{
|
||||
inst->maxCSumIatQ8 = inst->cSumIatQ8;
|
||||
inst->maxCSumUpdateTimer = 0;
|
||||
}
|
||||
|
||||
/* too long since the last maximum was observed; decrease max value */
|
||||
if (inst->maxCSumUpdateTimer > (uint32_t) WEBRTC_SPL_MUL_32_16(fsHz,
|
||||
MAX_STREAMING_PEAK_PERIOD))
|
||||
{
|
||||
inst->maxCSumIatQ8 -= 4; /* remove 1000*4/256 = 15.6 ms/s */
|
||||
}
|
||||
} /* end of streaming mode */
|
||||
|
||||
/* check for discontinuous packet sequence and re-ordering */
|
||||
if (WebRtcNetEQ_IsNewerSequenceNumber(seqNumber, inst->lastSeqNo + 1))
|
||||
{
|
||||
/* Compensate for gap in the sequence numbers.
|
||||
* Reduce IAT with expected extra time due to lost packets, but ensure that
|
||||
* the IAT is not negative.
|
||||
*/
|
||||
timeIat -= WEBRTC_SPL_MIN(timeIat,
|
||||
(uint16_t) (seqNumber - (uint16_t) (inst->lastSeqNo + 1)));
|
||||
}
|
||||
else if (!WebRtcNetEQ_IsNewerSequenceNumber(seqNumber, inst->lastSeqNo))
|
||||
{
|
||||
/* compensate for re-ordering */
|
||||
timeIat += (uint16_t) (inst->lastSeqNo + 1 - seqNumber);
|
||||
}
|
||||
|
||||
/* saturate IAT at maximum value */
|
||||
timeIat = WEBRTC_SPL_MIN( timeIat, MAX_IAT );
|
||||
|
||||
/* update iatProb = forgetting_factor * iatProb for all elements */
|
||||
for (i = 0; i <= MAX_IAT; i++)
|
||||
{
|
||||
int32_t tempHi, tempLo; /* Temporary variables */
|
||||
|
||||
/*
|
||||
* Multiply iatProbFact (Q15) with iatProb (Q30) and right-shift 15 steps
|
||||
* to come back to Q30. The operation is done in two steps:
|
||||
*/
|
||||
|
||||
/*
|
||||
* 1) Multiply the high 16 bits (15 bits + sign) of iatProb. Shift iatProb
|
||||
* 16 steps right to get the high 16 bits in a int16_t prior to
|
||||
* multiplication, and left-shift with 1 afterwards to come back to
|
||||
* Q30 = (Q15 * (Q30>>16)) << 1.
|
||||
*/
|
||||
tempHi = WEBRTC_SPL_MUL_16_16(inst->iatProbFact,
|
||||
(int16_t) WEBRTC_SPL_RSHIFT_W32(inst->iatProb[i], 16));
|
||||
tempHi = WEBRTC_SPL_LSHIFT_W32(tempHi, 1); /* left-shift 1 step */
|
||||
|
||||
/*
|
||||
* 2) Isolate and multiply the low 16 bits of iatProb. Right-shift 15 steps
|
||||
* afterwards to come back to Q30 = (Q15 * Q30) >> 15.
|
||||
*/
|
||||
tempLo = inst->iatProb[i] & 0x0000FFFF; /* sift out the 16 low bits */
|
||||
tempLo = WEBRTC_SPL_MUL_16_U16(inst->iatProbFact,
|
||||
(uint16_t) tempLo);
|
||||
tempLo = WEBRTC_SPL_RSHIFT_W32(tempLo, 15);
|
||||
|
||||
/* Finally, add the high and low parts */
|
||||
inst->iatProb[i] = tempHi + tempLo;
|
||||
|
||||
/* Sum all vector elements while we are at it... */
|
||||
tempsum += inst->iatProb[i];
|
||||
}
|
||||
|
||||
/*
|
||||
* Increase the probability for the currently observed inter-arrival time
|
||||
* with 1 - iatProbFact. The factor is in Q15, iatProb in Q30;
|
||||
* hence, left-shift 15 steps to obtain result in Q30.
|
||||
*/
|
||||
inst->iatProb[timeIat] += (32768 - inst->iatProbFact) << 15;
|
||||
|
||||
tempsum += (32768 - inst->iatProbFact) << 15; /* add to vector sum */
|
||||
|
||||
/*
|
||||
* Update iatProbFact (changes only during the first seconds after reset)
|
||||
* The factor converges to IAT_PROB_FACT.
|
||||
*/
|
||||
inst->iatProbFact += (IAT_PROB_FACT - inst->iatProbFact + 3) >> 2;
|
||||
|
||||
/* iatProb should sum up to 1 (in Q30). */
|
||||
tempsum -= 1 << 30; /* should be zero */
|
||||
|
||||
/* Check if it does, correct if it doesn't. */
|
||||
if (tempsum > 0)
|
||||
{
|
||||
/* tempsum too large => decrease a few values in the beginning */
|
||||
i = 0;
|
||||
while (i <= MAX_IAT && tempsum > 0)
|
||||
{
|
||||
/* Remove iatProb[i] / 16 from iatProb, but not more than tempsum */
|
||||
tempvar = WEBRTC_SPL_MIN(tempsum, inst->iatProb[i] >> 4);
|
||||
inst->iatProb[i++] -= tempvar;
|
||||
tempsum -= tempvar;
|
||||
}
|
||||
}
|
||||
else if (tempsum < 0)
|
||||
{
|
||||
/* tempsum too small => increase a few values in the beginning */
|
||||
i = 0;
|
||||
while (i <= MAX_IAT && tempsum < 0)
|
||||
{
|
||||
/* Add iatProb[i] / 16 to iatProb, but not more than tempsum */
|
||||
tempvar = WEBRTC_SPL_MIN(-tempsum, inst->iatProb[i] >> 4);
|
||||
inst->iatProb[i++] += tempvar;
|
||||
tempsum += tempvar;
|
||||
}
|
||||
}
|
||||
|
||||
/* Calculate optimal buffer level based on updated statistics */
|
||||
tempvar = (int32_t) WebRtcNetEQ_CalcOptimalBufLvl(inst, fsHz, mdCodec, timeIat,
|
||||
streamingMode);
|
||||
if (tempvar > 0)
|
||||
{
|
||||
int high_lim_delay;
|
||||
/* Convert the minimum delay from milliseconds to packets in Q8.
|
||||
* |fsHz| is sampling rate in Hertz, and |packetLenSamp|
|
||||
* is the number of samples per packet (according to the last
|
||||
* decoding).
|
||||
*/
|
||||
int32_t minimum_delay_q8 = ((inst->minimum_delay_ms *
|
||||
(fsHz / 1000)) << 8) / packetLenSamp;
|
||||
|
||||
int32_t maximum_delay_q8 = ((inst->maximum_delay_ms *
|
||||
(fsHz / 1000)) << 8) / packetLenSamp;
|
||||
|
||||
inst->optBufLevel = tempvar;
|
||||
|
||||
if (streamingMode != 0)
|
||||
{
|
||||
inst->optBufLevel = WEBRTC_SPL_MAX(inst->optBufLevel,
|
||||
inst->maxCSumIatQ8);
|
||||
}
|
||||
|
||||
/* The required delay. */
|
||||
inst->required_delay_q8 = inst->optBufLevel;
|
||||
|
||||
// Maintain the target delay.
|
||||
inst->optBufLevel = WEBRTC_SPL_MAX(inst->optBufLevel,
|
||||
minimum_delay_q8);
|
||||
|
||||
if (maximum_delay_q8 > 0) {
|
||||
// Make sure that max is at least one packet length.
|
||||
maximum_delay_q8 = WEBRTC_SPL_MAX(maximum_delay_q8, (1 << 8));
|
||||
inst->optBufLevel = WEBRTC_SPL_MIN(inst->optBufLevel,
|
||||
maximum_delay_q8);
|
||||
}
|
||||
/*********/
|
||||
/* Limit */
|
||||
/*********/
|
||||
|
||||
/* Subtract extra delay from maxBufLen */
|
||||
if (inst->extraDelayMs > 0 && inst->packetSpeechLenSamp > 0)
|
||||
{
|
||||
maxBufLen -= inst->extraDelayMs / inst->packetSpeechLenSamp * fsHz / 1000;
|
||||
maxBufLen = WEBRTC_SPL_MAX(maxBufLen, 1); // sanity: at least one packet
|
||||
}
|
||||
|
||||
maxBufLen = WEBRTC_SPL_LSHIFT_W32(maxBufLen, 8); /* shift to Q8 */
|
||||
|
||||
/* Enforce upper limit; 75% of maxBufLen */
|
||||
/* 1/2 + 1/4 = 75% */
|
||||
high_lim_delay = (maxBufLen >> 1) + (maxBufLen >> 2);
|
||||
inst->optBufLevel = WEBRTC_SPL_MIN(inst->optBufLevel,
|
||||
high_lim_delay);
|
||||
inst->required_delay_q8 = WEBRTC_SPL_MIN(inst->required_delay_q8,
|
||||
high_lim_delay);
|
||||
}
|
||||
else
|
||||
{
|
||||
retval = (int) tempvar;
|
||||
}
|
||||
|
||||
} /* end if */
|
||||
|
||||
/*******************************/
|
||||
/* Update post-call statistics */
|
||||
/*******************************/
|
||||
|
||||
/* Calculate inter-arrival time in ms = packetIatCountSamp / (fsHz / 1000) */
|
||||
timeIat = WEBRTC_SPL_UDIV(
|
||||
WEBRTC_SPL_UMUL_32_16(inst->packetIatCountSamp, (int16_t) 1000),
|
||||
(uint32_t) fsHz);
|
||||
|
||||
/* Increase counter corresponding to current inter-arrival time */
|
||||
if (timeIat > 2000)
|
||||
{
|
||||
inst->countIAT2000ms++;
|
||||
}
|
||||
else if (timeIat > 1000)
|
||||
{
|
||||
inst->countIAT1000ms++;
|
||||
}
|
||||
else if (timeIat > 500)
|
||||
{
|
||||
inst->countIAT500ms++;
|
||||
}
|
||||
|
||||
if (timeIat > inst->longestIATms)
|
||||
{
|
||||
/* update maximum value */
|
||||
inst->longestIATms = timeIat;
|
||||
}
|
||||
|
||||
/***********************************/
|
||||
/* Prepare for next packet arrival */
|
||||
/***********************************/
|
||||
|
||||
inst->packetIatCountSamp = 0; /* reset inter-arrival time counter */
|
||||
|
||||
inst->lastSeqNo = seqNumber; /* remember current sequence number */
|
||||
|
||||
inst->lastTimeStamp = timeStamp; /* remember current timestamp */
|
||||
|
||||
inst->firstPacketReceived = 1;
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
int16_t WebRtcNetEQ_CalcOptimalBufLvl(AutomodeInst_t *inst, int32_t fsHz,
|
||||
int mdCodec, uint32_t timeIatPkts,
|
||||
int streamingMode)
|
||||
{
|
||||
|
||||
int32_t sum1 = 1 << 30; /* assign to 1 in Q30 */
|
||||
int16_t B;
|
||||
uint16_t Bopt;
|
||||
int i;
|
||||
int32_t betaInv; /* optimization parameter */
|
||||
|
||||
#ifdef NETEQ_DELAY_LOGGING
|
||||
/* special code for offline delay logging */
|
||||
int temp_var;
|
||||
#endif
|
||||
|
||||
/****************/
|
||||
/* Sanity check */
|
||||
/****************/
|
||||
|
||||
if (fsHz <= 0)
|
||||
{
|
||||
/* fsHz must be strictly positive */
|
||||
return -1;
|
||||
}
|
||||
|
||||
/***********************************************/
|
||||
/* Get betaInv parameter based on playout mode */
|
||||
/***********************************************/
|
||||
|
||||
if (streamingMode)
|
||||
{
|
||||
/* streaming (listen-only) mode */
|
||||
betaInv = AUTOMODE_STREAMING_BETA_INV_Q30;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* normal mode */
|
||||
betaInv = AUTOMODE_BETA_INV_Q30;
|
||||
}
|
||||
|
||||
/*******************************************************************/
|
||||
/* Calculate optimal buffer level without considering jitter peaks */
|
||||
/*******************************************************************/
|
||||
|
||||
/*
|
||||
* Find the B for which the probability of observing an inter-arrival time larger
|
||||
* than or equal to B is less than or equal to betaInv.
|
||||
*/
|
||||
B = 0; /* start from the beginning of iatProb */
|
||||
sum1 -= inst->iatProb[B]; /* ensure that optimal level is not less than 1 */
|
||||
|
||||
do
|
||||
{
|
||||
/*
|
||||
* Subtract the probabilities one by one until the sum is no longer greater
|
||||
* than betaInv.
|
||||
*/
|
||||
sum1 -= inst->iatProb[++B];
|
||||
}
|
||||
while ((sum1 > betaInv) && (B < MAX_IAT));
|
||||
|
||||
Bopt = B; /* This is our primary value for the optimal buffer level Bopt */
|
||||
|
||||
if (mdCodec)
|
||||
{
|
||||
/*
|
||||
* Use alternative cost function when multiple description codec is in use.
|
||||
* Do not have to re-calculate all points, just back off a few steps from
|
||||
* previous value of B.
|
||||
*/
|
||||
int32_t sum2 = sum1; /* copy sum1 */
|
||||
|
||||
while ((sum2 <= betaInv + inst->iatProb[Bopt]) && (Bopt > 0))
|
||||
{
|
||||
/* Go backwards in the sum until the modified cost function solution is found */
|
||||
sum2 += inst->iatProb[Bopt--];
|
||||
}
|
||||
|
||||
Bopt++; /* This is the optimal level when using an MD codec */
|
||||
|
||||
/* Now, Bopt and B can have different values. */
|
||||
}
|
||||
|
||||
#ifdef NETEQ_DELAY_LOGGING
|
||||
/* special code for offline delay logging */
|
||||
temp_var = NETEQ_DELAY_LOGGING_SIGNAL_OPTBUF;
|
||||
if (fwrite( &temp_var, sizeof(int), 1, delay_fid2 ) != 1) {
|
||||
return -1;
|
||||
}
|
||||
temp_var = (int) (Bopt * inst->packetSpeechLenSamp);
|
||||
#endif
|
||||
|
||||
/******************************************************************/
|
||||
/* Make levelFiltFact adaptive: Larger B <=> larger levelFiltFact */
|
||||
/******************************************************************/
|
||||
|
||||
switch (B)
|
||||
{
|
||||
case 0:
|
||||
case 1:
|
||||
{
|
||||
inst->levelFiltFact = 251;
|
||||
break;
|
||||
}
|
||||
case 2:
|
||||
case 3:
|
||||
{
|
||||
inst->levelFiltFact = 252;
|
||||
break;
|
||||
}
|
||||
case 4:
|
||||
case 5:
|
||||
case 6:
|
||||
case 7:
|
||||
{
|
||||
inst->levelFiltFact = 253;
|
||||
break;
|
||||
}
|
||||
default: /* B > 7 */
|
||||
{
|
||||
inst->levelFiltFact = 254;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/************************/
|
||||
/* Peak mode operations */
|
||||
/************************/
|
||||
|
||||
/* Compare current IAT with peak threshold
|
||||
*
|
||||
* If IAT > optimal level + threshold (+1 for MD codecs)
|
||||
* or if IAT > 2 * optimal level (note: optimal level is in Q8):
|
||||
*/
|
||||
if (timeIatPkts > (uint32_t) (Bopt + inst->peakThresholdPkt + (mdCodec != 0))
|
||||
|| timeIatPkts > (uint32_t) WEBRTC_SPL_LSHIFT_U16(Bopt, 1))
|
||||
{
|
||||
/* A peak is observed */
|
||||
|
||||
if (inst->peakIndex == -1)
|
||||
{
|
||||
/* this is the first peak; prepare for next peak */
|
||||
inst->peakIndex = 0;
|
||||
/* set the mode-disable counter */
|
||||
inst->peakModeDisabled = WEBRTC_SPL_LSHIFT_W16(1, NUM_PEAKS_REQUIRED-2);
|
||||
}
|
||||
else if (inst->peakIatCountSamp
|
||||
<=
|
||||
(uint32_t) WEBRTC_SPL_MUL_32_16(fsHz, MAX_PEAK_PERIOD))
|
||||
{
|
||||
/* This is not the first peak and the period time is valid */
|
||||
|
||||
/* store time elapsed since last peak */
|
||||
inst->peakPeriodSamp[inst->peakIndex] = inst->peakIatCountSamp;
|
||||
|
||||
/* saturate height to 16 bits */
|
||||
inst->peakHeightPkt[inst->peakIndex]
|
||||
=
|
||||
(int16_t) WEBRTC_SPL_MIN(timeIatPkts, WEBRTC_SPL_WORD16_MAX);
|
||||
|
||||
/* increment peakIndex and wrap/modulo */
|
||||
inst->peakIndex = (inst->peakIndex + 1) & PEAK_INDEX_MASK;
|
||||
|
||||
/* process peak vectors */
|
||||
inst->curPeakHeight = 0;
|
||||
inst->curPeakPeriod = 0;
|
||||
|
||||
for (i = 0; i < NUM_PEAKS; i++)
|
||||
{
|
||||
/* Find maximum of peak heights and peak periods */
|
||||
inst->curPeakHeight
|
||||
= WEBRTC_SPL_MAX(inst->curPeakHeight, inst->peakHeightPkt[i]);
|
||||
inst->curPeakPeriod
|
||||
= WEBRTC_SPL_MAX(inst->curPeakPeriod, inst->peakPeriodSamp[i]);
|
||||
|
||||
}
|
||||
|
||||
inst->peakModeDisabled >>= 1; /* decrease mode-disable "counter" */
|
||||
|
||||
}
|
||||
else if (inst->peakIatCountSamp > (uint32_t) WEBRTC_SPL_MUL_32_16(fsHz,
|
||||
WEBRTC_SPL_LSHIFT_W16(MAX_PEAK_PERIOD, 1)))
|
||||
{
|
||||
/*
|
||||
* More than 2 * MAX_PEAK_PERIOD has elapsed since last peak;
|
||||
* too long time => reset peak statistics
|
||||
*/
|
||||
inst->curPeakHeight = 0;
|
||||
inst->curPeakPeriod = 0;
|
||||
for (i = 0; i < NUM_PEAKS; i++)
|
||||
{
|
||||
inst->peakHeightPkt[i] = 0;
|
||||
inst->peakPeriodSamp[i] = 0;
|
||||
}
|
||||
|
||||
inst->peakIndex = -1; /* Next peak is first peak */
|
||||
inst->peakIatCountSamp = 0;
|
||||
}
|
||||
|
||||
inst->peakIatCountSamp = 0; /* Reset peak interval timer */
|
||||
} /* end if peak is observed */
|
||||
|
||||
/* Evaluate peak mode conditions */
|
||||
|
||||
/*
|
||||
* If not disabled (enough peaks have been observed) and
|
||||
* time since last peak is less than two peak periods.
|
||||
*/
|
||||
inst->peakFound = 0;
|
||||
if ((!inst->peakModeDisabled) && (inst->peakIatCountSamp
|
||||
<= WEBRTC_SPL_LSHIFT_W32(inst->curPeakPeriod , 1)))
|
||||
{
|
||||
/* Engage peak mode */
|
||||
inst->peakFound = 1;
|
||||
/* Set optimal buffer level to curPeakHeight (if it's not already larger) */
|
||||
Bopt = WEBRTC_SPL_MAX(Bopt, inst->curPeakHeight);
|
||||
|
||||
#ifdef NETEQ_DELAY_LOGGING
|
||||
/* special code for offline delay logging */
|
||||
temp_var = (int) -(Bopt * inst->packetSpeechLenSamp);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Scale Bopt to Q8 */
|
||||
Bopt = WEBRTC_SPL_LSHIFT_U16(Bopt,8);
|
||||
|
||||
#ifdef NETEQ_DELAY_LOGGING
|
||||
/* special code for offline delay logging */
|
||||
if (fwrite( &temp_var, sizeof(int), 1, delay_fid2 ) != 1) {
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Sanity check: Bopt must be strictly positive */
|
||||
if (Bopt <= 0)
|
||||
{
|
||||
Bopt = WEBRTC_SPL_LSHIFT_W16(1, 8); /* 1 in Q8 */
|
||||
}
|
||||
|
||||
return Bopt; /* return value in Q8 */
|
||||
}
|
||||
|
||||
|
||||
int WebRtcNetEQ_BufferLevelFilter(int32_t curSizeMs8, AutomodeInst_t *inst,
|
||||
int sampPerCall, int16_t fsMult)
|
||||
{
|
||||
|
||||
int16_t curSizeFrames;
|
||||
|
||||
/****************/
|
||||
/* Sanity check */
|
||||
/****************/
|
||||
|
||||
if (sampPerCall <= 0 || fsMult <= 0)
|
||||
{
|
||||
/* sampPerCall and fsMult must both be strictly positive */
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Check if packet size has been detected */
|
||||
if (inst->packetSpeechLenSamp > 0)
|
||||
{
|
||||
/*
|
||||
* Current buffer level in packet lengths
|
||||
* = (curSizeMs8 * fsMult) / packetSpeechLenSamp
|
||||
*/
|
||||
curSizeFrames = (int16_t) WebRtcSpl_DivW32W16(
|
||||
WEBRTC_SPL_MUL_32_16(curSizeMs8, fsMult), inst->packetSpeechLenSamp);
|
||||
}
|
||||
else
|
||||
{
|
||||
curSizeFrames = 0;
|
||||
}
|
||||
|
||||
/* Filter buffer level */
|
||||
if (inst->levelFiltFact > 0) /* check that filter factor is set */
|
||||
{
|
||||
/* Filter:
|
||||
* buffLevelFilt = levelFiltFact * buffLevelFilt
|
||||
* + (1-levelFiltFact) * curSizeFrames
|
||||
*
|
||||
* levelFiltFact is in Q8
|
||||
*/
|
||||
inst->buffLevelFilt = ((inst->levelFiltFact * inst->buffLevelFilt) >> 8) +
|
||||
(256 - inst->levelFiltFact) * curSizeFrames;
|
||||
}
|
||||
|
||||
/* Account for time-scale operations (accelerate and pre-emptive expand) */
|
||||
if (inst->prevTimeScale)
|
||||
{
|
||||
/*
|
||||
* Time-scaling has been performed since last filter update.
|
||||
* Subtract the sampleMemory from buffLevelFilt after converting sampleMemory
|
||||
* from samples to packets in Q8. Make sure that the filtered value is
|
||||
* non-negative.
|
||||
*/
|
||||
inst->buffLevelFilt = WEBRTC_SPL_MAX( inst->buffLevelFilt -
|
||||
WebRtcSpl_DivW32W16(
|
||||
WEBRTC_SPL_LSHIFT_W32(inst->sampleMemory, 8), /* sampleMemory in Q8 */
|
||||
inst->packetSpeechLenSamp ), /* divide by packetSpeechLenSamp */
|
||||
0);
|
||||
|
||||
/*
|
||||
* Reset flag and set timescaleHoldOff timer to prevent further time-scaling
|
||||
* for some time.
|
||||
*/
|
||||
inst->prevTimeScale = 0;
|
||||
inst->timescaleHoldOff = AUTOMODE_TIMESCALE_LIMIT;
|
||||
}
|
||||
|
||||
/* Update time counters and HoldOff timer */
|
||||
inst->packetIatCountSamp += sampPerCall; /* packet inter-arrival time */
|
||||
inst->peakIatCountSamp += sampPerCall; /* peak inter-arrival time */
|
||||
inst->timescaleHoldOff >>= 1; /* time-scaling limiter */
|
||||
inst->maxCSumUpdateTimer += sampPerCall; /* cumulative-sum timer */
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
|
||||
int WebRtcNetEQ_SetPacketSpeechLen(AutomodeInst_t *inst, int16_t newLenSamp,
|
||||
int32_t fsHz)
|
||||
{
|
||||
|
||||
/* Sanity check for newLenSamp and fsHz */
|
||||
if (newLenSamp <= 0 || fsHz <= 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
inst->packetSpeechLenSamp = newLenSamp; /* Store packet size in instance */
|
||||
|
||||
/* Make NetEQ wait for first regular packet before starting the timer */
|
||||
inst->lastPackCNGorDTMF = 1;
|
||||
|
||||
inst->packetIatCountSamp = 0; /* Reset packet time counter */
|
||||
|
||||
/*
|
||||
* Calculate peak threshold from packet size. The threshold is defined as
|
||||
* the (fractional) number of packets that corresponds to PEAK_HEIGHT
|
||||
* (in Q8 seconds). That is, threshold = PEAK_HEIGHT/256 * fsHz / packLen.
|
||||
*/
|
||||
inst->peakThresholdPkt = (uint16_t) WebRtcSpl_DivW32W16ResW16(
|
||||
WEBRTC_SPL_MUL_16_16_RSFT(PEAK_HEIGHT,
|
||||
(int16_t) WEBRTC_SPL_RSHIFT_W32(fsHz, 6), 2), inst->packetSpeechLenSamp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int WebRtcNetEQ_ResetAutomode(AutomodeInst_t *inst, int maxBufLenPackets)
|
||||
{
|
||||
|
||||
int i;
|
||||
uint16_t tempprob = 0x4002; /* 16384 + 2 = 100000000000010 binary; */
|
||||
|
||||
/* Sanity check for maxBufLenPackets */
|
||||
if (maxBufLenPackets <= 1)
|
||||
{
|
||||
/* Invalid value; set to 10 instead (arbitary small number) */
|
||||
maxBufLenPackets = 10;
|
||||
}
|
||||
|
||||
/* Reset filtered buffer level */
|
||||
inst->buffLevelFilt = 0;
|
||||
|
||||
/* Reset packet size to unknown */
|
||||
inst->packetSpeechLenSamp = 0;
|
||||
|
||||
/*
|
||||
* Flag that last packet was special payload, so that automode will treat the next speech
|
||||
* payload as the first payload received.
|
||||
*/
|
||||
inst->lastPackCNGorDTMF = 1;
|
||||
|
||||
/* Reset peak detection parameters */
|
||||
inst->peakModeDisabled = 1; /* disable peak mode */
|
||||
inst->peakIatCountSamp = 0;
|
||||
inst->peakIndex = -1; /* indicates that no peak is registered */
|
||||
inst->curPeakHeight = 0;
|
||||
inst->curPeakPeriod = 0;
|
||||
for (i = 0; i < NUM_PEAKS; i++)
|
||||
{
|
||||
inst->peakHeightPkt[i] = 0;
|
||||
inst->peakPeriodSamp[i] = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the iatProb PDF vector to an exponentially decaying distribution
|
||||
* iatProb[i] = 0.5^(i+1), i = 0, 1, 2, ...
|
||||
* iatProb is in Q30.
|
||||
*/
|
||||
for (i = 0; i <= MAX_IAT; i++)
|
||||
{
|
||||
/* iatProb[i] = 0.5^(i+1) = iatProb[i-1] / 2 */
|
||||
tempprob = WEBRTC_SPL_RSHIFT_U16(tempprob, 1);
|
||||
/* store in PDF vector */
|
||||
inst->iatProb[i] = WEBRTC_SPL_LSHIFT_W32((int32_t) tempprob, 16);
|
||||
}
|
||||
|
||||
/*
|
||||
* Calculate the optimal buffer level corresponding to the initial PDF.
|
||||
* No need to call WebRtcNetEQ_CalcOptimalBufLvl() since we have just hard-coded
|
||||
* all the variables that the buffer level depends on => we know the result
|
||||
*/
|
||||
inst->optBufLevel = WEBRTC_SPL_MIN(4,
|
||||
(maxBufLenPackets >> 1) + (maxBufLenPackets >> 1)); /* 75% of maxBufLenPackets */
|
||||
inst->required_delay_q8 = inst->optBufLevel;
|
||||
inst->levelFiltFact = 253;
|
||||
|
||||
/*
|
||||
* Reset the iat update forgetting factor to 0 to make the impact of the first
|
||||
* incoming packets greater.
|
||||
*/
|
||||
inst->iatProbFact = 0;
|
||||
|
||||
/* Reset packet inter-arrival time counter */
|
||||
inst->packetIatCountSamp = 0;
|
||||
|
||||
/* Clear time-scaling related variables */
|
||||
inst->prevTimeScale = 0;
|
||||
inst->timescaleHoldOff = AUTOMODE_TIMESCALE_LIMIT; /* don't allow time-scaling immediately */
|
||||
|
||||
inst->cSumIatQ8 = 0;
|
||||
inst->maxCSumIatQ8 = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t WebRtcNetEQ_AverageIAT(const AutomodeInst_t *inst) {
|
||||
int i;
|
||||
int32_t sum_q24 = 0;
|
||||
assert(inst);
|
||||
for (i = 0; i <= MAX_IAT; ++i) {
|
||||
/* Shift 6 to fit worst case: 2^30 * 64. */
|
||||
sum_q24 += (inst->iatProb[i] >> 6) * i;
|
||||
}
|
||||
/* Subtract the nominal inter-arrival time 1 = 2^24 in Q24. */
|
||||
sum_q24 -= (1 << 24);
|
||||
/*
|
||||
* Multiply with 1000000 / 2^24 = 15625 / 2^18 to get in parts-per-million.
|
||||
* Shift 7 to Q17 first, then multiply with 15625 and shift another 11.
|
||||
*/
|
||||
return ((sum_q24 >> 7) * 15625) >> 11;
|
||||
}
|
@ -1,274 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file contains the functionality for automatic buffer level optimization.
|
||||
*/
|
||||
|
||||
#ifndef AUTOMODE_H
|
||||
#define AUTOMODE_H
|
||||
|
||||
#include "typedefs.h"
|
||||
|
||||
/*************/
|
||||
/* Constants */
|
||||
/*************/
|
||||
|
||||
/* The beta parameter defines the trade-off between delay and underrun probability. */
|
||||
/* It is defined through its inverse in Q30 */
|
||||
#define AUTOMODE_BETA_INV_Q30 53687091 /* 1/20 in Q30 */
|
||||
#define AUTOMODE_STREAMING_BETA_INV_Q30 536871 /* 1/2000 in Q30 */
|
||||
|
||||
/* Forgetting factor for the inter-arrival time statistics */
|
||||
#define IAT_PROB_FACT 32745 /* 0.9993 in Q15 */
|
||||
|
||||
/* Maximum inter-arrival time to register (in "packet-times") */
|
||||
#define MAX_IAT 64
|
||||
#define PEAK_HEIGHT 20 /* 0.08s in Q8 */
|
||||
|
||||
/* The value (1<<5) sets maximum accelerate "speed" to about 100 ms/s */
|
||||
#define AUTOMODE_TIMESCALE_LIMIT (1<<5)
|
||||
|
||||
/* Peak mode related parameters */
|
||||
/* Number of peaks in peak vector; must be a power of 2 */
|
||||
#define NUM_PEAKS 8
|
||||
|
||||
/* Must be NUM_PEAKS-1 */
|
||||
#define PEAK_INDEX_MASK 0x0007
|
||||
|
||||
/* Longest accepted peak distance */
|
||||
#define MAX_PEAK_PERIOD 10
|
||||
#define MAX_STREAMING_PEAK_PERIOD 600 /* 10 minutes */
|
||||
|
||||
/* Number of peaks required before peak mode can be engaged */
|
||||
#define NUM_PEAKS_REQUIRED 3
|
||||
|
||||
/* Drift term for cumulative sum */
|
||||
#define CSUM_IAT_DRIFT 2
|
||||
|
||||
/*******************/
|
||||
/* Automode struct */
|
||||
/*******************/
|
||||
|
||||
/* The automode struct is a sub-struct of the
|
||||
bufstats-struct (BufstatsInst_t). */
|
||||
|
||||
typedef struct
|
||||
{
|
||||
|
||||
/* Filtered current buffer level */
|
||||
uint16_t levelFiltFact; /* filter forgetting factor in Q8 */
|
||||
int buffLevelFilt; /* filtered buffer level in Q8 */
|
||||
|
||||
/* Inter-arrival time (iat) statistics */
|
||||
int32_t iatProb[MAX_IAT + 1]; /* iat probabilities in Q30 */
|
||||
int16_t iatProbFact; /* iat forgetting factor in Q15 */
|
||||
uint32_t packetIatCountSamp; /* time (in timestamps) elapsed since last
|
||||
packet arrival, based on RecOut calls */
|
||||
int optBufLevel; /* current optimal buffer level in Q8 */
|
||||
|
||||
/* Packet related information */
|
||||
int16_t packetSpeechLenSamp; /* speech samples per incoming packet */
|
||||
int16_t lastPackCNGorDTMF; /* indicates that the last received packet
|
||||
contained special information */
|
||||
uint16_t lastSeqNo; /* sequence number for last packet received */
|
||||
uint32_t lastTimeStamp; /* timestamp for the last packet received */
|
||||
int firstPacketReceived; /* set to zero implicitly when the instance is
|
||||
filled with zeros */
|
||||
int32_t sampleMemory; /* memory position for keeping track of how many
|
||||
samples we cut during expand */
|
||||
int16_t prevTimeScale; /* indicates that the last mode was an accelerate
|
||||
or pre-emptive expand operation */
|
||||
uint32_t timescaleHoldOff; /* counter that is shifted one step right each
|
||||
RecOut call; time-scaling allowed when it has
|
||||
reached 0 */
|
||||
int16_t extraDelayMs; /* extra delay for sync with video */
|
||||
|
||||
int minimum_delay_ms; /* Desired delay, NetEq maintains this amount of
|
||||
delay unless jitter statistics suggests a higher value. */
|
||||
int maximum_delay_ms; /* Max desired delay, NetEq will not go above this
|
||||
amount of delay even if jitter statistics suggests a higher value. */
|
||||
|
||||
int required_delay_q8; /* Smallest delay required. This is computed
|
||||
according to inter-arrival time and playout mode. It has the same unit
|
||||
as |optBufLevel|. */
|
||||
|
||||
/* Peak-detection */
|
||||
/* vector with the latest peak periods (peak spacing in samples) */
|
||||
uint32_t peakPeriodSamp[NUM_PEAKS];
|
||||
/* vector with the latest peak heights (in packets) */
|
||||
int16_t peakHeightPkt[NUM_PEAKS];
|
||||
int16_t peakIndex; /* index for the vectors peakPeriodSamp and peakHeightPkt;
|
||||
-1 if still waiting for first peak */
|
||||
uint16_t peakThresholdPkt; /* definition of peak (in packets);
|
||||
calculated from PEAK_HEIGHT */
|
||||
uint32_t peakIatCountSamp; /* samples elapsed since last peak was observed */
|
||||
uint32_t curPeakPeriod; /* current maximum of peakPeriodSamp vector */
|
||||
int16_t curPeakHeight; /* derived from peakHeightPkt vector;
|
||||
used as optimal buffer level in peak mode */
|
||||
int16_t peakModeDisabled; /* ==0 if peak mode can be engaged; >0 if not */
|
||||
uint16_t peakFound; /* 1 if peaks are detected and extra delay is applied;
|
||||
* 0 otherwise. */
|
||||
|
||||
/* Post-call statistics */
|
||||
uint32_t countIAT500ms; /* number of times we got small network outage */
|
||||
uint32_t countIAT1000ms; /* number of times we got medium network outage */
|
||||
uint32_t countIAT2000ms; /* number of times we got large network outage */
|
||||
uint32_t longestIATms; /* mSec duration of longest network outage */
|
||||
|
||||
int16_t cSumIatQ8; /* cumulative sum of inter-arrival times */
|
||||
int16_t maxCSumIatQ8; /* max cumulative sum IAT */
|
||||
uint32_t maxCSumUpdateTimer;/* time elapsed since maximum was observed */
|
||||
} AutomodeInst_t;
|
||||
|
||||
/*************/
|
||||
/* Functions */
|
||||
/*************/
|
||||
|
||||
/****************************************************************************
|
||||
* WebRtcNetEQ_UpdateIatStatistics(...)
|
||||
*
|
||||
* Update the packet inter-arrival time statistics when a new packet arrives.
|
||||
* This function should be called for every arriving packet, with some
|
||||
* exceptions when using DTX/VAD and DTMF. A new optimal buffer level is
|
||||
* calculated after the update.
|
||||
*
|
||||
* Input:
|
||||
* - inst : Automode instance
|
||||
* - maxBufLen : Maximum number of packets the buffer can hold
|
||||
* - seqNumber : RTP sequence number of incoming packet
|
||||
* - timeStamp : RTP timestamp of incoming packet
|
||||
* - fsHz : Sample rate in Hz
|
||||
* - mdCodec : Non-zero if the current codec is a multiple-
|
||||
* description codec
|
||||
* - streamingMode : A non-zero value will increase jitter robustness (and delay)
|
||||
*
|
||||
* Output:
|
||||
* - inst : Updated automode instance
|
||||
*
|
||||
* Return value : 0 - Ok
|
||||
* <0 - Error
|
||||
*/
|
||||
|
||||
int WebRtcNetEQ_UpdateIatStatistics(AutomodeInst_t *inst, int maxBufLen,
|
||||
uint16_t seqNumber, uint32_t timeStamp,
|
||||
int32_t fsHz, int mdCodec, int streamingMode);
|
||||
|
||||
/****************************************************************************
|
||||
* WebRtcNetEQ_CalcOptimalBufLvl(...)
|
||||
*
|
||||
* Calculate the optimal buffer level based on packet inter-arrival time
|
||||
* statistics.
|
||||
*
|
||||
* Input:
|
||||
* - inst : Automode instance
|
||||
* - fsHz : Sample rate in Hz
|
||||
* - mdCodec : Non-zero if the current codec is a multiple-
|
||||
* description codec
|
||||
* - timeIatPkts : Currently observed inter-arrival time in packets
|
||||
* - streamingMode : A non-zero value will increase jitter robustness (and delay)
|
||||
*
|
||||
* Output:
|
||||
* - inst : Updated automode instance
|
||||
*
|
||||
* Return value : >0 - Optimal buffer level
|
||||
* <0 - Error
|
||||
*/
|
||||
|
||||
int16_t WebRtcNetEQ_CalcOptimalBufLvl(AutomodeInst_t *inst, int32_t fsHz,
|
||||
int mdCodec, uint32_t timeIatPkts,
|
||||
int streamingMode);
|
||||
|
||||
/****************************************************************************
|
||||
* WebRtcNetEQ_BufferLevelFilter(...)
|
||||
*
|
||||
* Update filtered buffer level. The function must be called once for each
|
||||
* RecOut call, since the timing of automode hinges on counters that are
|
||||
* updated by this function.
|
||||
*
|
||||
* Input:
|
||||
* - curSizeMs8 : Total length of unused speech data in packet buffer
|
||||
* and sync buffer, in ms * 8
|
||||
* - inst : Automode instance
|
||||
* - sampPerCall : Number of samples per RecOut call
|
||||
* - fsMult : Sample rate in Hz divided by 8000
|
||||
*
|
||||
* Output:
|
||||
* - inst : Updated automode instance
|
||||
*
|
||||
* Return value : 0 - Ok
|
||||
* : <0 - Error
|
||||
*/
|
||||
|
||||
int WebRtcNetEQ_BufferLevelFilter(int32_t curSizeMs8, AutomodeInst_t *inst,
|
||||
int sampPerCall, int16_t fsMult);
|
||||
|
||||
/****************************************************************************
|
||||
* WebRtcNetEQ_SetPacketSpeechLen(...)
|
||||
*
|
||||
* Provide the number of speech samples extracted from a packet to the
|
||||
* automode instance. Several of the calculations within automode depend
|
||||
* on knowing the packet size.
|
||||
*
|
||||
*
|
||||
* Input:
|
||||
* - inst : Automode instance
|
||||
* - newLenSamp : Number of samples per RecOut call
|
||||
* - fsHz : Sample rate in Hz
|
||||
*
|
||||
* Output:
|
||||
* - inst : Updated automode instance
|
||||
*
|
||||
* Return value : 0 - Ok
|
||||
* <0 - Error
|
||||
*/
|
||||
|
||||
int WebRtcNetEQ_SetPacketSpeechLen(AutomodeInst_t *inst, int16_t newLenSamp,
|
||||
int32_t fsHz);
|
||||
|
||||
/****************************************************************************
|
||||
* WebRtcNetEQ_ResetAutomode(...)
|
||||
*
|
||||
* Reset the automode instance.
|
||||
*
|
||||
*
|
||||
* Input:
|
||||
* - inst : Automode instance
|
||||
* - maxBufLenPackets : Maximum number of packets that the packet
|
||||
* buffer can hold (>1)
|
||||
*
|
||||
* Output:
|
||||
* - inst : Updated automode instance
|
||||
*
|
||||
* Return value : 0 - Ok
|
||||
*/
|
||||
|
||||
int WebRtcNetEQ_ResetAutomode(AutomodeInst_t *inst, int maxBufLenPackets);
|
||||
|
||||
/****************************************************************************
|
||||
* WebRtcNetEQ_AverageIAT(...)
|
||||
*
|
||||
* Calculate the average inter-arrival time based on current statistics.
|
||||
* The average is expressed in parts per million relative the nominal. That is,
|
||||
* if the average inter-arrival time is equal to the nominal frame time,
|
||||
* the return value is zero. A positive value corresponds to packet spacing
|
||||
* being too large, while a negative value means that the packets arrive with
|
||||
* less spacing than expected.
|
||||
*
|
||||
*
|
||||
* Input:
|
||||
* - inst : Automode instance.
|
||||
*
|
||||
* Return value : Average relative inter-arrival time in samples.
|
||||
*/
|
||||
|
||||
int32_t WebRtcNetEQ_AverageIAT(const AutomodeInst_t *inst);
|
||||
|
||||
#endif /* AUTOMODE_H */
|
@ -1,247 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file contains the function for updating the background noise estimate.
|
||||
*/
|
||||
|
||||
#include "dsp.h"
|
||||
|
||||
#include "signal_processing_library.h"
|
||||
|
||||
#include "dsp_helpfunctions.h"
|
||||
|
||||
/* Scratch usage:
|
||||
Designed for BGN_LPC_ORDER <= 10
|
||||
|
||||
Type Name size startpos endpos
|
||||
int32_t pw32_autoCorr 22 0 21 (Length (BGN_LPC_ORDER + 1)*2)
|
||||
int16_t pw16_tempVec 10 22 31 (Length BGN_LPC_ORDER)
|
||||
int16_t pw16_rc 10 32 41 (Length BGN_LPC_ORDER)
|
||||
int16_t pw16_outVec 74 0 73 (Length BGN_LPC_ORDER + 64)
|
||||
|
||||
Total: 74
|
||||
*/
|
||||
|
||||
#if (BGN_LPC_ORDER > 10) && (defined SCRATCH)
|
||||
#error BGN_LPC_ORDER is too large for current scratch memory allocation
|
||||
#endif
|
||||
|
||||
#define SCRATCH_PW32_AUTO_CORR 0
|
||||
#define SCRATCH_PW16_TEMP_VEC 22
|
||||
#define SCRATCH_PW16_RC 32
|
||||
#define SCRATCH_PW16_OUT_VEC 0
|
||||
|
||||
#define NETEQFIX_BGNFRAQINCQ16 229 /* 0.0035 in Q16 */
|
||||
|
||||
/****************************************************************************
|
||||
* WebRtcNetEQ_BGNUpdate(...)
|
||||
*
|
||||
* This function updates the background noise parameter estimates.
|
||||
*
|
||||
* Input:
|
||||
* - inst : NetEQ instance, where the speech history is stored.
|
||||
* - scratchPtr : Pointer to scratch vector.
|
||||
*
|
||||
* Output:
|
||||
* - inst : Updated information about the BGN characteristics.
|
||||
*
|
||||
* Return value : No return value
|
||||
*/
|
||||
|
||||
void WebRtcNetEQ_BGNUpdate(
|
||||
#ifdef SCRATCH
|
||||
DSPInst_t *inst, int16_t *pw16_scratchPtr
|
||||
#else
|
||||
DSPInst_t *inst
|
||||
#endif
|
||||
)
|
||||
{
|
||||
const int16_t w16_vecLen = 256;
|
||||
BGNInst_t *BGN_Inst = &(inst->BGNInst);
|
||||
#ifdef SCRATCH
|
||||
int32_t *pw32_autoCorr = (int32_t*) (pw16_scratchPtr + SCRATCH_PW32_AUTO_CORR);
|
||||
int16_t *pw16_tempVec = pw16_scratchPtr + SCRATCH_PW16_TEMP_VEC;
|
||||
int16_t *pw16_rc = pw16_scratchPtr + SCRATCH_PW16_RC;
|
||||
int16_t *pw16_outVec = pw16_scratchPtr + SCRATCH_PW16_OUT_VEC;
|
||||
#else
|
||||
int32_t pw32_autoCorr[BGN_LPC_ORDER + 1];
|
||||
int16_t pw16_tempVec[BGN_LPC_ORDER];
|
||||
int16_t pw16_outVec[BGN_LPC_ORDER + 64];
|
||||
int16_t pw16_rc[BGN_LPC_ORDER];
|
||||
#endif
|
||||
int16_t pw16_A[BGN_LPC_ORDER + 1];
|
||||
int32_t w32_tmp;
|
||||
int16_t *pw16_vec;
|
||||
int16_t w16_maxSample;
|
||||
int16_t w16_tmp, w16_tmp2;
|
||||
int16_t w16_enSampleShift;
|
||||
int32_t w32_en, w32_enBGN;
|
||||
int32_t w32_enUpdateThreashold;
|
||||
int16_t stability;
|
||||
|
||||
pw16_vec = inst->pw16_speechHistory + inst->w16_speechHistoryLen - w16_vecLen;
|
||||
|
||||
#ifdef NETEQ_VAD
|
||||
if( !inst->VADInst.VADEnabled /* we are not using post-decode VAD */
|
||||
|| inst->VADInst.VADDecision == 0 )
|
||||
{ /* ... or, post-decode VAD says passive speaker */
|
||||
#endif /* NETEQ_VAD */
|
||||
|
||||
/*Insert zeros to guarantee that boundary values do not distort autocorrelation */
|
||||
WEBRTC_SPL_MEMCPY_W16(pw16_tempVec, pw16_vec - BGN_LPC_ORDER, BGN_LPC_ORDER);
|
||||
WebRtcSpl_MemSetW16(pw16_vec - BGN_LPC_ORDER, 0, BGN_LPC_ORDER);
|
||||
|
||||
w16_maxSample = WebRtcSpl_MaxAbsValueW16(pw16_vec, w16_vecLen);
|
||||
w16_tmp = 8 /* log2(w16_veclen) = 8 */
|
||||
- WebRtcSpl_NormW32(WEBRTC_SPL_MUL_16_16(w16_maxSample, w16_maxSample));
|
||||
w16_tmp = WEBRTC_SPL_MAX(0, w16_tmp);
|
||||
|
||||
WebRtcNetEQ_CrossCorr(pw32_autoCorr, pw16_vec, pw16_vec, w16_vecLen, BGN_LPC_ORDER + 1,
|
||||
w16_tmp, -1);
|
||||
|
||||
/* Copy back data */
|
||||
WEBRTC_SPL_MEMCPY_W16(pw16_vec - BGN_LPC_ORDER, pw16_tempVec, BGN_LPC_ORDER);
|
||||
|
||||
w16_enSampleShift = 8 - w16_tmp; /* Number of shifts to get energy/sample */
|
||||
/* pw32_autoCorr[0]>>w16_enSampleShift */
|
||||
w32_en = WEBRTC_SPL_RSHIFT_W32(pw32_autoCorr[0], w16_enSampleShift);
|
||||
if ((w32_en < BGN_Inst->w32_energyUpdate
|
||||
#ifdef NETEQ_VAD
|
||||
/* post-decode VAD disabled and w32_en sufficiently low */
|
||||
&& !inst->VADInst.VADEnabled)
|
||||
/* ... or, post-decode VAD says passive speaker */
|
||||
|| (inst->VADInst.VADEnabled && inst->VADInst.VADDecision == 0)
|
||||
#else
|
||||
) /* just close the extra parenthesis */
|
||||
#endif /* NETEQ_VAD */
|
||||
)
|
||||
{
|
||||
/* Generate LPC coefficients */
|
||||
if (pw32_autoCorr[0] > 0)
|
||||
{
|
||||
/* regardless of whether the filter is actually updated or not,
|
||||
update energy threshold levels, since we have in fact observed
|
||||
a low energy signal */
|
||||
if (w32_en < BGN_Inst->w32_energyUpdate)
|
||||
{
|
||||
/* Never get under 1.0 in average sample energy */
|
||||
BGN_Inst->w32_energyUpdate = WEBRTC_SPL_MAX(w32_en, 1);
|
||||
BGN_Inst->w32_energyUpdateLow = 0;
|
||||
}
|
||||
|
||||
stability = WebRtcSpl_LevinsonDurbin(pw32_autoCorr, pw16_A, pw16_rc, BGN_LPC_ORDER);
|
||||
/* Only update BGN if filter is stable */
|
||||
if (stability != 1)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Do not update */
|
||||
return;
|
||||
}
|
||||
/* Generate the CNG gain factor by looking at the energy of the residual */
|
||||
WebRtcSpl_FilterMAFastQ12(pw16_vec + w16_vecLen - 64, pw16_outVec, pw16_A,
|
||||
BGN_LPC_ORDER + 1, 64);
|
||||
w32_enBGN = WebRtcNetEQ_DotW16W16(pw16_outVec, pw16_outVec, 64, 0);
|
||||
/* Dot product should never overflow since it is BGN and residual! */
|
||||
|
||||
/*
|
||||
* Check spectral flatness
|
||||
* Comparing the residual variance with the input signal variance tells
|
||||
* if the spectrum is flat or not.
|
||||
* (20*w32_enBGN) >= (w32_en<<6)
|
||||
* Also ensure that the energy is non-zero.
|
||||
*/
|
||||
if ((WEBRTC_SPL_MUL_32_16(w32_enBGN, 20) >= WEBRTC_SPL_LSHIFT_W32(w32_en, 6))
|
||||
&& (w32_en > 0))
|
||||
{
|
||||
/* spectrum is flat enough; save filter parameters */
|
||||
|
||||
WEBRTC_SPL_MEMCPY_W16(BGN_Inst->pw16_filter, pw16_A, BGN_LPC_ORDER+1);
|
||||
WEBRTC_SPL_MEMCPY_W16(BGN_Inst->pw16_filterState,
|
||||
pw16_vec + w16_vecLen - BGN_LPC_ORDER, BGN_LPC_ORDER);
|
||||
|
||||
/* Save energy level */
|
||||
BGN_Inst->w32_energy = WEBRTC_SPL_MAX(w32_en, 1);
|
||||
|
||||
/* Update energy threshold levels */
|
||||
/* Never get under 1.0 in average sample energy */
|
||||
BGN_Inst->w32_energyUpdate = WEBRTC_SPL_MAX(w32_en, 1);
|
||||
BGN_Inst->w32_energyUpdateLow = 0;
|
||||
|
||||
/* Normalize w32_enBGN to 29 or 30 bits before sqrt */
|
||||
w16_tmp2 = WebRtcSpl_NormW32(w32_enBGN) - 1;
|
||||
if (w16_tmp2 & 0x1)
|
||||
{
|
||||
w16_tmp2 -= 1; /* Even number of shifts required */
|
||||
}
|
||||
w32_enBGN = WEBRTC_SPL_SHIFT_W32(w32_enBGN, w16_tmp2);
|
||||
|
||||
/* Calculate scale and shift factor */
|
||||
BGN_Inst->w16_scale = (int16_t) WebRtcSpl_SqrtFloor(w32_enBGN);
|
||||
BGN_Inst->w16_scaleShift = 13 + ((6 + w16_tmp2) >> 1); /* RANDN table is in Q13, */
|
||||
/* 6=log2(64) */
|
||||
|
||||
BGN_Inst->w16_initialized = 1;
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
* Will only happen if post-decode VAD is disabled and w32_en is not low enough.
|
||||
* Increase the threshold for update so that it increases by a factor 4 in four
|
||||
* seconds.
|
||||
* energy = energy * 1.0035
|
||||
*/
|
||||
w32_tmp = WEBRTC_SPL_MUL_16_16_RSFT(NETEQFIX_BGNFRAQINCQ16,
|
||||
BGN_Inst->w32_energyUpdateLow, 16);
|
||||
w32_tmp += WEBRTC_SPL_MUL_16_16(NETEQFIX_BGNFRAQINCQ16,
|
||||
(int16_t)(BGN_Inst->w32_energyUpdate & 0xFF));
|
||||
w32_tmp += (WEBRTC_SPL_MUL_16_16(NETEQFIX_BGNFRAQINCQ16,
|
||||
(int16_t)((BGN_Inst->w32_energyUpdate>>8) & 0xFF)) << 8);
|
||||
BGN_Inst->w32_energyUpdateLow += w32_tmp;
|
||||
|
||||
BGN_Inst->w32_energyUpdate += WEBRTC_SPL_MUL_16_16(NETEQFIX_BGNFRAQINCQ16,
|
||||
(int16_t)(BGN_Inst->w32_energyUpdate>>16));
|
||||
BGN_Inst->w32_energyUpdate += BGN_Inst->w32_energyUpdateLow >> 16;
|
||||
BGN_Inst->w32_energyUpdateLow = (BGN_Inst->w32_energyUpdateLow & 0x0FFFF);
|
||||
|
||||
/* Update maximum energy */
|
||||
/* Decrease by a factor 1/1024 each time */
|
||||
BGN_Inst->w32_energyMax = BGN_Inst->w32_energyMax - (BGN_Inst->w32_energyMax >> 10);
|
||||
if (w32_en > BGN_Inst->w32_energyMax)
|
||||
{
|
||||
BGN_Inst->w32_energyMax = w32_en;
|
||||
}
|
||||
|
||||
/* Set update level to at the minimum 60.21dB lower then the maximum energy */
|
||||
w32_enUpdateThreashold = (BGN_Inst->w32_energyMax + 524288) >> 20;
|
||||
if (w32_enUpdateThreashold > BGN_Inst->w32_energyUpdate)
|
||||
{
|
||||
BGN_Inst->w32_energyUpdate = w32_enUpdateThreashold;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef NETEQ_VAD
|
||||
} /* closing initial if-statement */
|
||||
#endif /* NETEQ_VAD */
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
#undef SCRATCH_PW32_AUTO_CORR
|
||||
#undef SCRATCH_PW16_TEMP_VEC
|
||||
#undef SCRATCH_PW16_RC
|
||||
#undef SCRATCH_PW16_OUT_VEC
|
||||
|
@ -1,95 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Calculates and stores the packet buffer statistics.
|
||||
*/
|
||||
|
||||
#ifndef BUFFER_STATS_H
|
||||
#define BUFFER_STATS_H
|
||||
|
||||
#include "automode.h"
|
||||
#include "webrtc_neteq.h" /* to define enum WebRtcNetEQPlayoutMode */
|
||||
|
||||
/* NetEQ related decisions */
|
||||
#define BUFSTATS_DO_NORMAL 0
|
||||
#define BUFSTATS_DO_ACCELERATE 1
|
||||
#define BUFSTATS_DO_MERGE 2
|
||||
#define BUFSTATS_DO_EXPAND 3
|
||||
#define BUFSTAT_REINIT 4
|
||||
#define BUFSTATS_DO_RFC3389CNG_PACKET 5
|
||||
#define BUFSTATS_DO_RFC3389CNG_NOPACKET 6
|
||||
#define BUFSTATS_DO_INTERNAL_CNG_NOPACKET 7
|
||||
#define BUFSTATS_DO_PREEMPTIVE_EXPAND 8
|
||||
#define BUFSTAT_REINIT_DECODER 9
|
||||
#define BUFSTATS_DO_DTMF_ONLY 10
|
||||
/* Decisions related to when NetEQ is switched off (or in FAX mode) */
|
||||
#define BUFSTATS_DO_ALTERNATIVE_PLC 11
|
||||
#define BUFSTATS_DO_ALTERNATIVE_PLC_INC_TS 12
|
||||
#define BUFSTATS_DO_AUDIO_REPETITION 13
|
||||
#define BUFSTATS_DO_AUDIO_REPETITION_INC_TS 14
|
||||
|
||||
/* Reinit decoder states after this number of expands (upon arrival of new packet) */
|
||||
#define REINIT_AFTER_EXPANDS 100
|
||||
|
||||
/* Wait no longer than this number of RecOut calls before using an "early" packet */
|
||||
#define MAX_WAIT_FOR_PACKET 10
|
||||
|
||||
/* CNG modes */
|
||||
#define CNG_OFF 0
|
||||
#define CNG_RFC3389_ON 1
|
||||
#define CNG_INTERNAL_ON 2
|
||||
|
||||
typedef struct
|
||||
{
|
||||
|
||||
/* store statistical data here */
|
||||
int16_t w16_cngOn; /* remember if CNG is interrupted by other event (e.g. DTMF) */
|
||||
int16_t w16_noExpand;
|
||||
int32_t uw32_CNGplayedTS;
|
||||
|
||||
/* VQmon data */
|
||||
uint16_t avgDelayMsQ8;
|
||||
int16_t maxDelayMs;
|
||||
|
||||
AutomodeInst_t Automode_inst;
|
||||
|
||||
} BufstatsInst_t;
|
||||
|
||||
/****************************************************************************
|
||||
* WebRtcNetEQ_BufstatsDecision()
|
||||
*
|
||||
* Gives a decision about what action that is currently desired
|
||||
*
|
||||
*
|
||||
* Input:
|
||||
* inst: The bufstat instance
|
||||
* cur_size: Current buffer size in ms in Q3 domain
|
||||
* targetTS: The desired timestamp to start playout from
|
||||
* availableTS: The closest future value available in buffer
|
||||
* noPacket 1 if no packet is available, makes availableTS undefined
|
||||
* prevPlayMode mode of last NetEq playout
|
||||
* timestampsPerCall number of timestamp for 10ms
|
||||
*
|
||||
* Output:
|
||||
* Returns: A decision, as defined above (see top of file)
|
||||
*
|
||||
*/
|
||||
|
||||
uint16_t WebRtcNetEQ_BufstatsDecision(BufstatsInst_t *inst, int16_t frameSize,
|
||||
int32_t cur_size, uint32_t targetTS,
|
||||
uint32_t availableTS, int noPacket,
|
||||
int cngPacket, int prevPlayMode,
|
||||
enum WebRtcNetEQPlayoutMode playoutMode,
|
||||
int timestampsPerCall, int NoOfExpandCalls,
|
||||
int16_t fs_mult,
|
||||
int16_t lastModeBGNonly, int playDtmf);
|
||||
|
||||
#endif
|
@ -1,427 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file contains the function where the main decision logic for buffer level
|
||||
* adaptation happens.
|
||||
*/
|
||||
|
||||
#include "buffer_stats.h"
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include "signal_processing_library.h"
|
||||
|
||||
#include "automode.h"
|
||||
#include "neteq_defines.h"
|
||||
#include "neteq_error_codes.h"
|
||||
#include "webrtc_neteq.h"
|
||||
|
||||
#define NETEQ_BUFSTAT_20MS_Q7 2560 /* = 20 ms in Q7 */
|
||||
|
||||
uint16_t WebRtcNetEQ_BufstatsDecision(BufstatsInst_t *inst, int16_t frameSize,
|
||||
int32_t cur_size, uint32_t targetTS,
|
||||
uint32_t availableTS, int noPacket,
|
||||
int cngPacket, int prevPlayMode,
|
||||
enum WebRtcNetEQPlayoutMode playoutMode,
|
||||
int timestampsPerCall, int NoOfExpandCalls,
|
||||
int16_t fs_mult,
|
||||
int16_t lastModeBGNonly, int playDtmf)
|
||||
{
|
||||
|
||||
int currentDelayMs;
|
||||
int32_t currSizeSamples = cur_size;
|
||||
int extraDelayPacketsQ8 = 0;
|
||||
|
||||
/* Avoid overflow if the buffer size should be really large (cur_size is limited 256ms) */
|
||||
int32_t curr_sizeQ7 = WEBRTC_SPL_LSHIFT_W32(cur_size, 4);
|
||||
int level_limit_hi, level_limit_lo;
|
||||
|
||||
inst->Automode_inst.prevTimeScale &= (prevPlayMode == MODE_SUCCESS_ACCELERATE
|
||||
|| prevPlayMode == MODE_LOWEN_ACCELERATE || prevPlayMode == MODE_SUCCESS_PREEMPTIVE
|
||||
|| prevPlayMode == MODE_LOWEN_PREEMPTIVE);
|
||||
|
||||
if ((prevPlayMode != MODE_RFC3389CNG) && (prevPlayMode != MODE_CODEC_INTERNAL_CNG))
|
||||
{
|
||||
/*
|
||||
* Do not update buffer history if currently playing CNG
|
||||
* since it will bias the filtered buffer level.
|
||||
*/
|
||||
WebRtcNetEQ_BufferLevelFilter(cur_size, &(inst->Automode_inst), timestampsPerCall,
|
||||
fs_mult);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* only update time counters */
|
||||
inst->Automode_inst.packetIatCountSamp += timestampsPerCall; /* packet inter-arrival time */
|
||||
inst->Automode_inst.peakIatCountSamp += timestampsPerCall; /* peak inter-arrival time */
|
||||
inst->Automode_inst.timescaleHoldOff >>= 1; /* time-scaling limiter */
|
||||
}
|
||||
cur_size = WEBRTC_SPL_MIN(curr_sizeQ7, WEBRTC_SPL_WORD16_MAX);
|
||||
|
||||
/* Calculate VQmon related variables */
|
||||
/* avgDelay = avgDelay*(511/512) + currentDelay*(1/512) (sample ms delay in Q8) */
|
||||
inst->avgDelayMsQ8 = (int16_t) (WEBRTC_SPL_MUL_16_16_RSFT(inst->avgDelayMsQ8,511,9)
|
||||
+ (cur_size >> 9));
|
||||
|
||||
/* Update maximum delay if needed */
|
||||
currentDelayMs = (curr_sizeQ7 >> 7);
|
||||
if (currentDelayMs > inst->maxDelayMs)
|
||||
{
|
||||
inst->maxDelayMs = currentDelayMs;
|
||||
}
|
||||
|
||||
/* NetEQ is on with normal or steaming mode */
|
||||
if (playoutMode == kPlayoutOn || playoutMode == kPlayoutStreaming)
|
||||
{
|
||||
/* Guard for errors, so that it should not get stuck in error mode */
|
||||
if (prevPlayMode == MODE_ERROR)
|
||||
{
|
||||
if (noPacket)
|
||||
{
|
||||
return BUFSTATS_DO_EXPAND;
|
||||
}
|
||||
else
|
||||
{
|
||||
return BUFSTAT_REINIT;
|
||||
}
|
||||
}
|
||||
|
||||
if (prevPlayMode != MODE_EXPAND && prevPlayMode != MODE_FADE_TO_BGN)
|
||||
{
|
||||
inst->w16_noExpand = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
inst->w16_noExpand = 0;
|
||||
}
|
||||
|
||||
if (cngPacket)
|
||||
{
|
||||
/* signed difference between wanted and available TS */
|
||||
int32_t diffTS = (inst->uw32_CNGplayedTS + targetTS) - availableTS;
|
||||
int32_t optimal_level_samp = (inst->Automode_inst.optBufLevel *
|
||||
inst->Automode_inst.packetSpeechLenSamp) >> 8;
|
||||
int32_t excess_waiting_time_samp = -diffTS - optimal_level_samp;
|
||||
|
||||
if (excess_waiting_time_samp > optimal_level_samp / 2)
|
||||
{
|
||||
/* The waiting time for this packet will be longer than 1.5
|
||||
* times the wanted buffer delay. Advance the clock to cut
|
||||
* waiting time down to the optimal.
|
||||
*/
|
||||
inst->uw32_CNGplayedTS += excess_waiting_time_samp;
|
||||
diffTS += excess_waiting_time_samp;
|
||||
}
|
||||
|
||||
if ((diffTS) < 0 && (prevPlayMode == MODE_RFC3389CNG))
|
||||
{
|
||||
/* Not time to play this packet yet. Wait another round before using this
|
||||
* packet. Keep on playing CNG from previous CNG parameters. */
|
||||
return BUFSTATS_DO_RFC3389CNG_NOPACKET;
|
||||
}
|
||||
|
||||
/* otherwise, go for the CNG packet now */
|
||||
return BUFSTATS_DO_RFC3389CNG_PACKET;
|
||||
}
|
||||
|
||||
/*Check for expand/cng */
|
||||
if (noPacket)
|
||||
{
|
||||
if (inst->w16_cngOn == CNG_RFC3389_ON)
|
||||
{
|
||||
/* keep on playing CNG */
|
||||
return BUFSTATS_DO_RFC3389CNG_NOPACKET;
|
||||
}
|
||||
else if (inst->w16_cngOn == CNG_INTERNAL_ON)
|
||||
{
|
||||
/* keep on playing internal CNG */
|
||||
return BUFSTATS_DO_INTERNAL_CNG_NOPACKET;
|
||||
}
|
||||
else if (playDtmf == 1)
|
||||
{
|
||||
/* we have not audio data, but can play DTMF */
|
||||
return BUFSTATS_DO_DTMF_ONLY;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* nothing to play => do Expand */
|
||||
return BUFSTATS_DO_EXPAND;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If the expand period was very long, reset NetEQ since it is likely that the
|
||||
* sender was restarted.
|
||||
*/
|
||||
if (NoOfExpandCalls > REINIT_AFTER_EXPANDS) return BUFSTAT_REINIT_DECODER;
|
||||
|
||||
/* Calculate extra delay in Q8 packets */
|
||||
if (inst->Automode_inst.extraDelayMs > 0 && inst->Automode_inst.packetSpeechLenSamp
|
||||
> 0)
|
||||
{
|
||||
|
||||
/* (extra delay in samples in Q8) */
|
||||
extraDelayPacketsQ8 =
|
||||
((inst->Automode_inst.extraDelayMs * 8 * fs_mult) << 8) /
|
||||
inst->Automode_inst.packetSpeechLenSamp;
|
||||
}
|
||||
|
||||
/* Check if needed packet is available */
|
||||
if (targetTS == availableTS)
|
||||
{
|
||||
|
||||
/* If last mode was not expand, and there is no DTMF to play */
|
||||
if (inst->w16_noExpand == 1 && playDtmf == 0)
|
||||
{
|
||||
/* If so check for accelerate */
|
||||
|
||||
level_limit_lo = ((inst->Automode_inst.optBufLevel) >> 1) /* 50 % */
|
||||
+ ((inst->Automode_inst.optBufLevel) >> 2); /* ... + 25% = 75% */
|
||||
|
||||
/* set upper limit to optBufLevel, but make sure that window is at least 20ms */
|
||||
level_limit_hi = WEBRTC_SPL_MAX(inst->Automode_inst.optBufLevel,
|
||||
level_limit_lo +
|
||||
WebRtcSpl_DivW32W16ResW16((WEBRTC_SPL_MUL(20*8, fs_mult) << 8),
|
||||
inst->Automode_inst.packetSpeechLenSamp));
|
||||
|
||||
/* if extra delay is non-zero, add it */
|
||||
if (extraDelayPacketsQ8 > 0)
|
||||
{
|
||||
level_limit_hi += extraDelayPacketsQ8;
|
||||
level_limit_lo += extraDelayPacketsQ8;
|
||||
}
|
||||
|
||||
if (((inst->Automode_inst.buffLevelFilt >= level_limit_hi) &&
|
||||
(inst->Automode_inst.timescaleHoldOff == 0)) ||
|
||||
(inst->Automode_inst.buffLevelFilt >= level_limit_hi << 2))
|
||||
{
|
||||
/*
|
||||
* Buffer level higher than limit and time-scaling allowed,
|
||||
* OR buffer level _really_ high.
|
||||
*/
|
||||
return BUFSTATS_DO_ACCELERATE;
|
||||
}
|
||||
else if ((inst->Automode_inst.buffLevelFilt < level_limit_lo)
|
||||
&& (inst->Automode_inst.timescaleHoldOff == 0))
|
||||
{
|
||||
return BUFSTATS_DO_PREEMPTIVE_EXPAND;
|
||||
}
|
||||
}
|
||||
return BUFSTATS_DO_NORMAL;
|
||||
}
|
||||
|
||||
/* Check for Merge */
|
||||
else if (availableTS > targetTS)
|
||||
{
|
||||
|
||||
/* Check that we do not play a packet "too early" */
|
||||
if ((prevPlayMode == MODE_EXPAND)
|
||||
&& (availableTS - targetTS
|
||||
< (uint32_t) WEBRTC_SPL_MUL_16_16((int16_t)timestampsPerCall,
|
||||
(int16_t)REINIT_AFTER_EXPANDS))
|
||||
&& (NoOfExpandCalls < MAX_WAIT_FOR_PACKET)
|
||||
&& (availableTS
|
||||
> targetTS
|
||||
+ WEBRTC_SPL_MUL_16_16((int16_t)timestampsPerCall,
|
||||
(int16_t)NoOfExpandCalls))
|
||||
&& (inst->Automode_inst.buffLevelFilt <= inst->Automode_inst.optBufLevel
|
||||
+ extraDelayPacketsQ8))
|
||||
{
|
||||
if (playDtmf == 1)
|
||||
{
|
||||
/* we still have DTMF to play, so do not perform expand */
|
||||
return BUFSTATS_DO_DTMF_ONLY;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* nothing to play */
|
||||
return BUFSTATS_DO_EXPAND;
|
||||
}
|
||||
}
|
||||
|
||||
/* If previous was CNG period or BGNonly then no merge is needed */
|
||||
if ((prevPlayMode == MODE_RFC3389CNG) || (prevPlayMode == MODE_CODEC_INTERNAL_CNG)
|
||||
|| lastModeBGNonly)
|
||||
{
|
||||
/*
|
||||
* Keep the same delay as before the CNG (or maximum 70 ms in buffer as safety
|
||||
* precaution), but make sure that the number of samples in buffer is no
|
||||
* higher than 4 times the optimal level.
|
||||
*/
|
||||
int32_t diffTS = (inst->uw32_CNGplayedTS + targetTS) - availableTS;
|
||||
int val = ((inst->Automode_inst.optBufLevel +
|
||||
extraDelayPacketsQ8) *
|
||||
inst->Automode_inst.packetSpeechLenSamp) >> 6;
|
||||
if (diffTS >= 0 || val < currSizeSamples)
|
||||
{
|
||||
/* it is time to play this new packet */
|
||||
return BUFSTATS_DO_NORMAL;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* it is too early to play this new packet => keep on playing CNG */
|
||||
if (prevPlayMode == MODE_RFC3389CNG)
|
||||
{
|
||||
return BUFSTATS_DO_RFC3389CNG_NOPACKET;
|
||||
}
|
||||
else if (prevPlayMode == MODE_CODEC_INTERNAL_CNG)
|
||||
{
|
||||
return BUFSTATS_DO_INTERNAL_CNG_NOPACKET;
|
||||
}
|
||||
else if (playDtmf == 1)
|
||||
{
|
||||
/* we have not audio data, but can play DTMF */
|
||||
return BUFSTATS_DO_DTMF_ONLY;
|
||||
}
|
||||
else /* lastModeBGNonly */
|
||||
{
|
||||
/* signal expand, but this will result in BGN again */
|
||||
return BUFSTATS_DO_EXPAND;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Do not merge unless we have done a Expand before (for complexity reasons) */
|
||||
if ((inst->w16_noExpand == 0) || ((frameSize < timestampsPerCall) && (cur_size
|
||||
> NETEQ_BUFSTAT_20MS_Q7)))
|
||||
{
|
||||
return BUFSTATS_DO_MERGE;
|
||||
}
|
||||
else if (playDtmf == 1)
|
||||
{
|
||||
/* play DTMF instead of expand */
|
||||
return BUFSTATS_DO_DTMF_ONLY;
|
||||
}
|
||||
else
|
||||
{
|
||||
return BUFSTATS_DO_EXPAND;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{ /* kPlayoutOff or kPlayoutFax */
|
||||
if (cngPacket)
|
||||
{
|
||||
if (((int32_t) ((inst->uw32_CNGplayedTS + targetTS) - availableTS)) >= 0)
|
||||
{
|
||||
/* time to play this packet now */
|
||||
return BUFSTATS_DO_RFC3389CNG_PACKET;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* wait before playing this packet */
|
||||
return BUFSTATS_DO_RFC3389CNG_NOPACKET;
|
||||
}
|
||||
}
|
||||
if (noPacket)
|
||||
{
|
||||
/*
|
||||
* No packet =>
|
||||
* 1. If in CNG mode play as usual
|
||||
* 2. Otherwise use other method to generate data and hold TS value
|
||||
*/
|
||||
if (inst->w16_cngOn == CNG_RFC3389_ON)
|
||||
{
|
||||
/* keep on playing CNG */
|
||||
return BUFSTATS_DO_RFC3389CNG_NOPACKET;
|
||||
}
|
||||
else if (inst->w16_cngOn == CNG_INTERNAL_ON)
|
||||
{
|
||||
/* keep on playing internal CNG */
|
||||
return BUFSTATS_DO_INTERNAL_CNG_NOPACKET;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* nothing to play => invent some data to play out */
|
||||
if (playoutMode == kPlayoutOff)
|
||||
{
|
||||
return BUFSTATS_DO_ALTERNATIVE_PLC;
|
||||
}
|
||||
else if (playoutMode == kPlayoutFax)
|
||||
{
|
||||
return BUFSTATS_DO_AUDIO_REPETITION;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* UNDEFINED, should not get here... */
|
||||
assert(0);
|
||||
return BUFSTAT_REINIT;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (targetTS == availableTS)
|
||||
{
|
||||
return BUFSTATS_DO_NORMAL;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (((int32_t) ((inst->uw32_CNGplayedTS + targetTS) - availableTS)) >= 0)
|
||||
{
|
||||
return BUFSTATS_DO_NORMAL;
|
||||
}
|
||||
else if (playoutMode == kPlayoutOff)
|
||||
{
|
||||
/*
|
||||
* If currently playing CNG, continue with that. Don't increase TS
|
||||
* since uw32_CNGplayedTS will be increased.
|
||||
*/
|
||||
if (inst->w16_cngOn == CNG_RFC3389_ON)
|
||||
{
|
||||
return BUFSTATS_DO_RFC3389CNG_NOPACKET;
|
||||
}
|
||||
else if (inst->w16_cngOn == CNG_INTERNAL_ON)
|
||||
{
|
||||
return BUFSTATS_DO_INTERNAL_CNG_NOPACKET;
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
* Otherwise, do PLC and increase TS while waiting for the time to
|
||||
* play this packet.
|
||||
*/
|
||||
return BUFSTATS_DO_ALTERNATIVE_PLC_INC_TS;
|
||||
}
|
||||
}
|
||||
else if (playoutMode == kPlayoutFax)
|
||||
{
|
||||
/*
|
||||
* If currently playing CNG, continue with that don't increase TS since
|
||||
* uw32_CNGplayedTS will be increased.
|
||||
*/
|
||||
if (inst->w16_cngOn == CNG_RFC3389_ON)
|
||||
{
|
||||
return BUFSTATS_DO_RFC3389CNG_NOPACKET;
|
||||
}
|
||||
else if (inst->w16_cngOn == CNG_INTERNAL_ON)
|
||||
{
|
||||
return BUFSTATS_DO_INTERNAL_CNG_NOPACKET;
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
* Otherwise, do audio repetition and increase TS while waiting for the
|
||||
* time to play this packet.
|
||||
*/
|
||||
return BUFSTATS_DO_AUDIO_REPETITION_INC_TS;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* UNDEFINED, should not get here... */
|
||||
assert(0);
|
||||
return BUFSTAT_REINIT;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* We should not get here (but sometimes we do anyway...) */
|
||||
return BUFSTAT_REINIT;
|
||||
}
|
||||
|
@ -1,155 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file contains the function for obtaining comfort noise from noise parameters
|
||||
* according to IETF RFC 3389.
|
||||
*/
|
||||
|
||||
#include "dsp.h"
|
||||
|
||||
#include "signal_processing_library.h"
|
||||
#include "webrtc_cng.h"
|
||||
|
||||
#include "dsp_helpfunctions.h"
|
||||
#include "neteq_error_codes.h"
|
||||
|
||||
/****************************************************************************
|
||||
* WebRtcNetEQ_Cng(...)
|
||||
*
|
||||
* This function produces CNG according to RFC 3389.
|
||||
*
|
||||
* Input:
|
||||
* - inst : NetEQ DSP instance
|
||||
* - len : Number of samples to produce (max 640 or
|
||||
* 640 - fsHz*5/8000 for first-time CNG, governed by
|
||||
* the definition of WEBRTC_CNG_MAX_OUTSIZE_ORDER in
|
||||
* webrtc_cng.h)
|
||||
*
|
||||
* Output:
|
||||
* - pw16_outData : Output CNG
|
||||
*
|
||||
* Return value : 0 - Ok
|
||||
* <0 - Error
|
||||
*/
|
||||
|
||||
#ifdef NETEQ_CNG_CODEC
|
||||
/* Must compile NetEQ with CNG support to enable this function */
|
||||
|
||||
int WebRtcNetEQ_Cng(DSPInst_t *inst, int16_t *pw16_outData, int len)
|
||||
{
|
||||
int16_t w16_winMute = 0; /* mixing factor for overlap data */
|
||||
int16_t w16_winUnMute = 0; /* mixing factor for comfort noise */
|
||||
int16_t w16_winMuteInc = 0; /* mixing factor increment (negative) */
|
||||
int16_t w16_winUnMuteInc = 0; /* mixing factor increment */
|
||||
int i;
|
||||
|
||||
/*
|
||||
* Check if last RecOut call was other than RFC3389,
|
||||
* that is, this call is the first of a CNG period.
|
||||
*/
|
||||
if (inst->w16_mode != MODE_RFC3389CNG)
|
||||
{
|
||||
/* Reset generation and overlap slightly with old data */
|
||||
|
||||
/* Generate len samples + overlap */
|
||||
if (WebRtcCng_Generate(inst->CNG_Codec_inst, pw16_outData,
|
||||
(int16_t) (len + inst->ExpandInst.w16_overlap), 1) < 0)
|
||||
{
|
||||
/* error returned */
|
||||
return -WebRtcCng_GetErrorCodeDec(inst->CNG_Codec_inst);
|
||||
}
|
||||
|
||||
/* Set windowing parameters depending on sample rate */
|
||||
if (inst->fs == 8000)
|
||||
{
|
||||
/* Windowing in Q15 */
|
||||
w16_winMute = NETEQ_OVERLAP_WINMUTE_8KHZ_START;
|
||||
w16_winMuteInc = NETEQ_OVERLAP_WINMUTE_8KHZ_INC;
|
||||
w16_winUnMute = NETEQ_OVERLAP_WINUNMUTE_8KHZ_START;
|
||||
w16_winUnMuteInc = NETEQ_OVERLAP_WINUNMUTE_8KHZ_INC;
|
||||
#ifdef NETEQ_WIDEBAND
|
||||
}
|
||||
else if (inst->fs == 16000)
|
||||
{
|
||||
/* Windowing in Q15 */
|
||||
w16_winMute = NETEQ_OVERLAP_WINMUTE_16KHZ_START;
|
||||
w16_winMuteInc = NETEQ_OVERLAP_WINMUTE_16KHZ_INC;
|
||||
w16_winUnMute = NETEQ_OVERLAP_WINUNMUTE_16KHZ_START;
|
||||
w16_winUnMuteInc = NETEQ_OVERLAP_WINUNMUTE_16KHZ_INC;
|
||||
#endif
|
||||
#ifdef NETEQ_32KHZ_WIDEBAND
|
||||
}
|
||||
else if (inst->fs == 32000)
|
||||
{
|
||||
/* Windowing in Q15 */
|
||||
w16_winMute = NETEQ_OVERLAP_WINMUTE_32KHZ_START;
|
||||
w16_winMuteInc = NETEQ_OVERLAP_WINMUTE_32KHZ_INC;
|
||||
w16_winUnMute = NETEQ_OVERLAP_WINUNMUTE_32KHZ_START;
|
||||
w16_winUnMuteInc = NETEQ_OVERLAP_WINUNMUTE_32KHZ_INC;
|
||||
#endif
|
||||
#ifdef NETEQ_48KHZ_WIDEBAND
|
||||
}
|
||||
else if (inst->fs == 48000)
|
||||
{
|
||||
/* Windowing in Q15 */
|
||||
w16_winMute = NETEQ_OVERLAP_WINMUTE_48KHZ_START;
|
||||
w16_winMuteInc = NETEQ_OVERLAP_WINMUTE_48KHZ_INC;
|
||||
w16_winUnMute = NETEQ_OVERLAP_WINUNMUTE_48KHZ_START;
|
||||
w16_winUnMuteInc = NETEQ_OVERLAP_WINUNMUTE_48KHZ_INC;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Unsupported sample rate (should not be possible) */
|
||||
return NETEQ_OTHER_ERROR;
|
||||
}
|
||||
|
||||
/* Do overlap add between new vector and overlap */
|
||||
for (i = 0; i < inst->ExpandInst.w16_overlap; i++)
|
||||
{
|
||||
/* overlapVec[i] = WinMute * overlapVec[i] + WinUnMute * outData[i] */
|
||||
inst->ExpandInst.pw16_overlapVec[i] = (int16_t) WEBRTC_SPL_RSHIFT_W32(
|
||||
WEBRTC_SPL_MUL_16_16(
|
||||
inst->ExpandInst.pw16_overlapVec[i], w16_winMute) +
|
||||
WEBRTC_SPL_MUL_16_16(pw16_outData[i], w16_winUnMute)
|
||||
+ 16384, 15); /* shift with proper rounding */
|
||||
|
||||
w16_winMute += w16_winMuteInc; /* decrease mute factor (inc<0) */
|
||||
w16_winUnMute += w16_winUnMuteInc; /* increase unmute factor (inc>0) */
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Shift the contents of the outData buffer by overlap samples, since we
|
||||
* already used these first samples in the overlapVec above
|
||||
*/
|
||||
|
||||
WEBRTC_SPL_MEMMOVE_W16(pw16_outData, pw16_outData+inst->ExpandInst.w16_overlap, len);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
/* This is a subsequent CNG call; no special overlap needed */
|
||||
|
||||
/* Generate len samples */
|
||||
if (WebRtcCng_Generate(inst->CNG_Codec_inst, pw16_outData, (int16_t) len, 0) < 0)
|
||||
{
|
||||
/* error returned */
|
||||
return -WebRtcCng_GetErrorCodeDec(inst->CNG_Codec_inst);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
#endif /* NETEQ_CNG_CODEC */
|
||||
|
@ -1,782 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Implementation of the codec database.
|
||||
*/
|
||||
|
||||
#include "codec_db.h"
|
||||
|
||||
#include <string.h> /* to define NULL */
|
||||
|
||||
#include "signal_processing_library.h"
|
||||
|
||||
#include "neteq_error_codes.h"
|
||||
|
||||
/*
|
||||
* Resets the codec database.
|
||||
*/
|
||||
|
||||
int WebRtcNetEQ_DbReset(CodecDbInst_t *inst)
|
||||
{
|
||||
int i;
|
||||
|
||||
WebRtcSpl_MemSetW16((int16_t*) inst, 0,
|
||||
sizeof(CodecDbInst_t) / sizeof(int16_t));
|
||||
|
||||
for (i = 0; i < NUM_TOTAL_CODECS; i++)
|
||||
{
|
||||
inst->position[i] = -1;
|
||||
}
|
||||
|
||||
for (i = 0; i < NUM_CODECS; i++)
|
||||
{
|
||||
inst->payloadType[i] = -1;
|
||||
}
|
||||
|
||||
for (i = 0; i < NUM_CNG_CODECS; i++)
|
||||
{
|
||||
inst->CNGpayloadType[i] = -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Adds a new codec to the database.
|
||||
*/
|
||||
|
||||
int WebRtcNetEQ_DbAdd(CodecDbInst_t *inst, enum WebRtcNetEQDecoder codec,
|
||||
int16_t payloadType, FuncDecode funcDecode,
|
||||
FuncDecode funcDecodeRCU, FuncDecodePLC funcDecodePLC,
|
||||
FuncDecodeInit funcDecodeInit, FuncAddLatePkt funcAddLatePkt,
|
||||
FuncGetMDinfo funcGetMDinfo, FuncGetPitchInfo funcGetPitch,
|
||||
FuncUpdBWEst funcUpdBWEst, FuncDurationEst funcDurationEst,
|
||||
FuncGetErrorCode funcGetErrorCode, void* codec_state,
|
||||
uint16_t codec_fs)
|
||||
{
|
||||
|
||||
int temp;
|
||||
int insertCNGcodec = 0, overwriteCNGcodec = 0, CNGpos = -1;
|
||||
|
||||
#ifndef NETEQ_RED_CODEC
|
||||
if (codec == kDecoderRED)
|
||||
{
|
||||
return CODEC_DB_UNSUPPORTED_CODEC;
|
||||
}
|
||||
#endif
|
||||
if (((int) codec <= (int) kDecoderReservedStart) || ((int) codec
|
||||
>= (int) kDecoderReservedEnd))
|
||||
{
|
||||
return CODEC_DB_UNSUPPORTED_CODEC;
|
||||
}
|
||||
|
||||
if ((codec_fs != 8000)
|
||||
#ifdef NETEQ_WIDEBAND
|
||||
&&(codec_fs!=16000)
|
||||
#endif
|
||||
#ifdef NETEQ_32KHZ_WIDEBAND
|
||||
&&(codec_fs!=32000)
|
||||
#endif
|
||||
#if defined(NETEQ_48KHZ_WIDEBAND) || defined(NETEQ_OPUS_CODEC)
|
||||
&&(codec_fs!=48000)
|
||||
#endif
|
||||
)
|
||||
{
|
||||
return CODEC_DB_UNSUPPORTED_FS;
|
||||
}
|
||||
|
||||
/* Ensure that the codec type is supported */
|
||||
switch (codec)
|
||||
{
|
||||
#ifdef NETEQ_PCM16B_CODEC
|
||||
case kDecoderPCM16B :
|
||||
case kDecoderPCM16B_2ch :
|
||||
#endif
|
||||
#ifdef NETEQ_G711_CODEC
|
||||
case kDecoderPCMu :
|
||||
case kDecoderPCMa :
|
||||
case kDecoderPCMu_2ch :
|
||||
case kDecoderPCMa_2ch :
|
||||
#endif
|
||||
#ifdef NETEQ_ILBC_CODEC
|
||||
case kDecoderILBC :
|
||||
#endif
|
||||
#ifdef NETEQ_ISAC_CODEC
|
||||
case kDecoderISAC :
|
||||
#endif
|
||||
#ifdef NETEQ_ISAC_SWB_CODEC
|
||||
case kDecoderISACswb :
|
||||
#endif
|
||||
#ifdef NETEQ_ISAC_FB_CODEC
|
||||
case kDecoderISACfb :
|
||||
#endif
|
||||
#ifdef NETEQ_OPUS_CODEC
|
||||
case kDecoderOpus :
|
||||
#endif
|
||||
#ifdef NETEQ_G722_CODEC
|
||||
case kDecoderG722 :
|
||||
case kDecoderG722_2ch :
|
||||
#endif
|
||||
#ifdef NETEQ_WIDEBAND
|
||||
case kDecoderPCM16Bwb :
|
||||
case kDecoderPCM16Bwb_2ch :
|
||||
#endif
|
||||
#ifdef NETEQ_32KHZ_WIDEBAND
|
||||
case kDecoderPCM16Bswb32kHz :
|
||||
case kDecoderPCM16Bswb32kHz_2ch :
|
||||
#endif
|
||||
#ifdef NETEQ_CNG_CODEC
|
||||
case kDecoderCNG :
|
||||
#endif
|
||||
#ifdef NETEQ_ATEVENT_DECODE
|
||||
case kDecoderAVT :
|
||||
#endif
|
||||
#ifdef NETEQ_RED_CODEC
|
||||
case kDecoderRED :
|
||||
#endif
|
||||
#ifdef NETEQ_48KHZ_WIDEBAND
|
||||
case kDecoderPCM16Bswb48kHz :
|
||||
#endif
|
||||
#ifdef NETEQ_ARBITRARY_CODEC
|
||||
case kDecoderArbitrary:
|
||||
#endif
|
||||
#ifdef NETEQ_G729_CODEC
|
||||
case kDecoderG729:
|
||||
#endif
|
||||
#ifdef NETEQ_G729_1_CODEC
|
||||
case kDecoderG729_1 :
|
||||
#endif
|
||||
#ifdef NETEQ_G726_CODEC
|
||||
case kDecoderG726_16 :
|
||||
case kDecoderG726_24 :
|
||||
case kDecoderG726_32 :
|
||||
case kDecoderG726_40 :
|
||||
#endif
|
||||
#ifdef NETEQ_G722_1_CODEC
|
||||
case kDecoderG722_1_16 :
|
||||
case kDecoderG722_1_24 :
|
||||
case kDecoderG722_1_32 :
|
||||
#endif
|
||||
#ifdef NETEQ_G722_1C_CODEC
|
||||
case kDecoderG722_1C_24 :
|
||||
case kDecoderG722_1C_32 :
|
||||
case kDecoderG722_1C_48 :
|
||||
#endif
|
||||
#ifdef NETEQ_SPEEX_CODEC
|
||||
case kDecoderSPEEX_8 :
|
||||
case kDecoderSPEEX_16 :
|
||||
#endif
|
||||
#ifdef NETEQ_CELT_CODEC
|
||||
case kDecoderCELT_32 :
|
||||
case kDecoderCELT_32_2ch :
|
||||
#endif
|
||||
#ifdef NETEQ_GSMFR_CODEC
|
||||
case kDecoderGSMFR :
|
||||
#endif
|
||||
#ifdef NETEQ_AMR_CODEC
|
||||
case kDecoderAMR :
|
||||
#endif
|
||||
#ifdef NETEQ_AMRWB_CODEC
|
||||
case kDecoderAMRWB :
|
||||
#endif
|
||||
{
|
||||
/* If we end up here, the inserted codec is supported => Do nothing */
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
/* If we get to this point, the inserted codec is not supported */
|
||||
return CODEC_DB_UNSUPPORTED_CODEC;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check to see if payload type is taken */
|
||||
if (WebRtcNetEQ_DbGetCodec(inst, payloadType) > 0)
|
||||
{
|
||||
return CODEC_DB_PAYLOAD_TAKEN;
|
||||
}
|
||||
|
||||
/* Special case for CNG codecs */
|
||||
if (codec == kDecoderCNG)
|
||||
{
|
||||
/* check if this is first CNG codec to be registered */
|
||||
if (WebRtcNetEQ_DbGetPayload(inst, codec) == CODEC_DB_NOT_EXIST2)
|
||||
{
|
||||
/* no other CNG codec found */
|
||||
insertCNGcodec = 1;
|
||||
}
|
||||
|
||||
/* find the appropriate insert position in CNG payload vector */
|
||||
switch (codec_fs)
|
||||
{
|
||||
case 8000:
|
||||
CNGpos = 0;
|
||||
/*
|
||||
* The 8 kHz CNG payload type is the one associated with the regular codec DB
|
||||
* should override any other setting.
|
||||
* Overwrite if this isn't the first CNG
|
||||
*/
|
||||
overwriteCNGcodec = !insertCNGcodec;
|
||||
break;
|
||||
#ifdef NETEQ_WIDEBAND
|
||||
case 16000:
|
||||
CNGpos = 1;
|
||||
break;
|
||||
#endif
|
||||
#ifdef NETEQ_32KHZ_WIDEBAND
|
||||
case 32000:
|
||||
CNGpos = 2;
|
||||
break;
|
||||
#endif
|
||||
#ifdef NETEQ_48KHZ_WIDEBAND
|
||||
case 48000:
|
||||
CNGpos = 3;
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
/* If we get to this point, the inserted codec is not supported */
|
||||
return CODEC_DB_UNSUPPORTED_CODEC;
|
||||
}
|
||||
|
||||
/* insert CNG payload type */
|
||||
inst->CNGpayloadType[CNGpos] = payloadType;
|
||||
|
||||
}
|
||||
|
||||
if ((codec != kDecoderCNG) || (insertCNGcodec == 1) || (overwriteCNGcodec == 1))
|
||||
{
|
||||
/* Check if we have reached the maximum numbers of simultaneous codecs */
|
||||
if (inst->nrOfCodecs == NUM_CODECS) return CODEC_DB_FULL;
|
||||
|
||||
/* Check that codec has not already been initialized to DB =>
|
||||
remove it and reinitialize according to new spec */
|
||||
if ((inst->position[codec] != -1) && (overwriteCNGcodec != 1))
|
||||
{ /* if registering multiple CNG codecs, don't remove, just overwrite */
|
||||
WebRtcNetEQ_DbRemove(inst, codec);
|
||||
}
|
||||
|
||||
if (overwriteCNGcodec == 1)
|
||||
{
|
||||
temp = inst->position[codec];
|
||||
}
|
||||
else
|
||||
{
|
||||
temp = inst->nrOfCodecs; /* Store this codecs position */
|
||||
inst->position[codec] = temp;
|
||||
inst->nrOfCodecs++;
|
||||
}
|
||||
|
||||
inst->payloadType[temp] = payloadType;
|
||||
|
||||
/* Copy to database */
|
||||
inst->codec_state[temp] = codec_state;
|
||||
inst->funcDecode[temp] = funcDecode;
|
||||
inst->funcDecodeRCU[temp] = funcDecodeRCU;
|
||||
inst->funcAddLatePkt[temp] = funcAddLatePkt;
|
||||
inst->funcDecodeInit[temp] = funcDecodeInit;
|
||||
inst->funcDecodePLC[temp] = funcDecodePLC;
|
||||
inst->funcGetMDinfo[temp] = funcGetMDinfo;
|
||||
inst->funcGetPitch[temp] = funcGetPitch;
|
||||
inst->funcUpdBWEst[temp] = funcUpdBWEst;
|
||||
inst->funcDurationEst[temp] = funcDurationEst;
|
||||
inst->funcGetErrorCode[temp] = funcGetErrorCode;
|
||||
inst->codec_fs[temp] = codec_fs;
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Removes a codec from the database.
|
||||
*/
|
||||
|
||||
int WebRtcNetEQ_DbRemove(CodecDbInst_t *inst, enum WebRtcNetEQDecoder codec)
|
||||
{
|
||||
int i;
|
||||
int pos = -1;
|
||||
|
||||
#ifndef NETEQ_RED_CODEC
|
||||
if (codec == kDecoderRED)
|
||||
{
|
||||
return CODEC_DB_UNSUPPORTED_CODEC;
|
||||
}
|
||||
#endif
|
||||
if (((int) codec <= (int) kDecoderReservedStart) || ((int) codec
|
||||
>= (int) kDecoderReservedEnd))
|
||||
{
|
||||
return CODEC_DB_UNSUPPORTED_CODEC;
|
||||
}
|
||||
|
||||
pos = inst->position[codec];
|
||||
if (pos == -1)
|
||||
{
|
||||
return CODEC_DB_NOT_EXIST4;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Remove this codec */
|
||||
inst->position[codec] = -1;
|
||||
for (i = pos; i < (inst->nrOfCodecs - 1); i++)
|
||||
{
|
||||
inst->payloadType[i] = inst->payloadType[i + 1];
|
||||
inst->codec_state[i] = inst->codec_state[i + 1];
|
||||
inst->funcDecode[i] = inst->funcDecode[i + 1];
|
||||
inst->funcDecodeRCU[i] = inst->funcDecodeRCU[i + 1];
|
||||
inst->funcAddLatePkt[i] = inst->funcAddLatePkt[i + 1];
|
||||
inst->funcDecodeInit[i] = inst->funcDecodeInit[i + 1];
|
||||
inst->funcDecodePLC[i] = inst->funcDecodePLC[i + 1];
|
||||
inst->funcGetMDinfo[i] = inst->funcGetMDinfo[i + 1];
|
||||
inst->funcGetPitch[i] = inst->funcGetPitch[i + 1];
|
||||
inst->funcDurationEst[i] = inst->funcDurationEst[i + 1];
|
||||
inst->funcUpdBWEst[i] = inst->funcUpdBWEst[i + 1];
|
||||
inst->funcGetErrorCode[i] = inst->funcGetErrorCode[i + 1];
|
||||
inst->codec_fs[i] = inst->codec_fs[i + 1];
|
||||
}
|
||||
inst->payloadType[i] = -1;
|
||||
inst->codec_state[i] = NULL;
|
||||
inst->funcDecode[i] = NULL;
|
||||
inst->funcDecodeRCU[i] = NULL;
|
||||
inst->funcAddLatePkt[i] = NULL;
|
||||
inst->funcDecodeInit[i] = NULL;
|
||||
inst->funcDecodePLC[i] = NULL;
|
||||
inst->funcGetMDinfo[i] = NULL;
|
||||
inst->funcGetPitch[i] = NULL;
|
||||
inst->funcDurationEst[i] = NULL;
|
||||
inst->funcUpdBWEst[i] = NULL;
|
||||
inst->funcGetErrorCode[i] = NULL;
|
||||
inst->codec_fs[i] = 0;
|
||||
/* Move down all the codecs above this one */
|
||||
for (i = 0; i < NUM_TOTAL_CODECS; i++)
|
||||
{
|
||||
if (inst->position[i] >= pos)
|
||||
{
|
||||
inst->position[i] = inst->position[i] - 1;
|
||||
}
|
||||
}
|
||||
inst->nrOfCodecs--;
|
||||
|
||||
if (codec == kDecoderCNG)
|
||||
{
|
||||
/* also remove all registered CNG payload types */
|
||||
for (i = 0; i < NUM_CNG_CODECS; i++)
|
||||
{
|
||||
inst->CNGpayloadType[i] = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the decoder function pointers for a codec.
|
||||
*/
|
||||
|
||||
int WebRtcNetEQ_DbGetPtrs(CodecDbInst_t *inst, enum WebRtcNetEQDecoder codec,
|
||||
CodecFuncInst_t *ptr_inst)
|
||||
{
|
||||
|
||||
int pos = inst->position[codec];
|
||||
if ((codec <= kDecoderReservedStart) || (codec >= kDecoderReservedEnd) || (codec
|
||||
> NUM_TOTAL_CODECS))
|
||||
{
|
||||
/* ERROR */
|
||||
pos = -1;
|
||||
}
|
||||
if (pos >= 0)
|
||||
{
|
||||
ptr_inst->codec_state = inst->codec_state[pos];
|
||||
ptr_inst->funcAddLatePkt = inst->funcAddLatePkt[pos];
|
||||
ptr_inst->funcDecode = inst->funcDecode[pos];
|
||||
ptr_inst->funcDecodeRCU = inst->funcDecodeRCU[pos];
|
||||
ptr_inst->funcDecodeInit = inst->funcDecodeInit[pos];
|
||||
ptr_inst->funcDecodePLC = inst->funcDecodePLC[pos];
|
||||
ptr_inst->funcGetMDinfo = inst->funcGetMDinfo[pos];
|
||||
ptr_inst->funcUpdBWEst = inst->funcUpdBWEst[pos];
|
||||
ptr_inst->funcGetErrorCode = inst->funcGetErrorCode[pos];
|
||||
ptr_inst->codec_fs = inst->codec_fs[pos];
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
WebRtcSpl_MemSetW16((int16_t*) ptr_inst, 0,
|
||||
sizeof(CodecFuncInst_t) / sizeof(int16_t));
|
||||
return CODEC_DB_NOT_EXIST1;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns payload number given a codec identifier.
|
||||
*/
|
||||
|
||||
int WebRtcNetEQ_DbGetPayload(CodecDbInst_t *inst, enum WebRtcNetEQDecoder codecID)
|
||||
{
|
||||
if (inst->position[codecID] == -1)
|
||||
return CODEC_DB_NOT_EXIST2;
|
||||
else
|
||||
return (inst->payloadType[inst->position[codecID]]);
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns codec identifier given a payload number.
|
||||
* Returns -1 if the payload type does not exist.
|
||||
*/
|
||||
|
||||
int WebRtcNetEQ_DbGetCodec(const CodecDbInst_t *inst, int payloadType)
|
||||
{
|
||||
int i, pos;
|
||||
|
||||
for (i = 0; i < NUM_TOTAL_CODECS; i++)
|
||||
{
|
||||
pos = inst->position[i];
|
||||
if (pos != -1)
|
||||
{
|
||||
if (inst->payloadType[pos] == payloadType) return i;
|
||||
}
|
||||
}
|
||||
|
||||
/* did not find payload type */
|
||||
/* check if it's a CNG codec */
|
||||
if (WebRtcNetEQ_DbIsCNGPayload(inst, payloadType))
|
||||
{
|
||||
return kDecoderCNG;
|
||||
}
|
||||
|
||||
/* found no match */
|
||||
return CODEC_DB_NOT_EXIST3;
|
||||
}
|
||||
|
||||
/*
|
||||
* Extracts the Payload Split information of the codec with the specified payloadType.
|
||||
*/
|
||||
|
||||
int WebRtcNetEQ_DbGetSplitInfo(SplitInfo_t *inst, enum WebRtcNetEQDecoder codecID,
|
||||
int codedsize)
|
||||
{
|
||||
|
||||
switch (codecID)
|
||||
{
|
||||
#ifdef NETEQ_ISAC_CODEC
|
||||
case kDecoderISAC:
|
||||
#endif
|
||||
#ifdef NETEQ_ISAC_SWB_CODEC
|
||||
case kDecoderISACswb:
|
||||
#endif
|
||||
#ifdef NETEQ_ISAC_FB_CODEC
|
||||
case kDecoderISACfb:
|
||||
#endif
|
||||
#ifdef NETEQ_OPUS_CODEC
|
||||
case kDecoderOpus:
|
||||
#endif
|
||||
#ifdef NETEQ_ARBITRARY_CODEC
|
||||
case kDecoderArbitrary:
|
||||
#endif
|
||||
#ifdef NETEQ_AMR_CODEC
|
||||
case kDecoderAMR:
|
||||
#endif
|
||||
#ifdef NETEQ_AMRWB_CODEC
|
||||
case kDecoderAMRWB:
|
||||
#endif
|
||||
#ifdef NETEQ_G726_CODEC
|
||||
/* Treat G726 as non-splittable to simplify the implementation */
|
||||
case kDecoderG726_16:
|
||||
case kDecoderG726_24:
|
||||
case kDecoderG726_32:
|
||||
case kDecoderG726_40:
|
||||
#endif
|
||||
#ifdef NETEQ_SPEEX_CODEC
|
||||
case kDecoderSPEEX_8:
|
||||
case kDecoderSPEEX_16:
|
||||
#endif
|
||||
#ifdef NETEQ_CELT_CODEC
|
||||
case kDecoderCELT_32 :
|
||||
case kDecoderCELT_32_2ch :
|
||||
#endif
|
||||
#ifdef NETEQ_G729_1_CODEC
|
||||
case kDecoderG729_1:
|
||||
#endif
|
||||
{
|
||||
/* These codecs' payloads are not splittable */
|
||||
inst->deltaBytes = NO_SPLIT;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Sample based coders are a special case.
|
||||
* In this case, deltaTime signals the number of bytes per timestamp unit times 2
|
||||
* in log2 domain.
|
||||
*/
|
||||
#if (defined NETEQ_G711_CODEC)
|
||||
case kDecoderPCMu:
|
||||
case kDecoderPCMa:
|
||||
case kDecoderPCMu_2ch:
|
||||
case kDecoderPCMa_2ch:
|
||||
{
|
||||
inst->deltaBytes = -12;
|
||||
inst->deltaTime = 1;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
#if (defined NETEQ_G722_CODEC)
|
||||
case kDecoderG722:
|
||||
case kDecoderG722_2ch:
|
||||
{
|
||||
inst->deltaBytes = -14;
|
||||
inst->deltaTime = 0;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
#if (defined NETEQ_PCM16B_CODEC)
|
||||
case kDecoderPCM16B:
|
||||
case kDecoderPCM16B_2ch:
|
||||
{
|
||||
inst->deltaBytes = -12;
|
||||
inst->deltaTime = 2;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
#if ((defined NETEQ_PCM16B_CODEC)&&(defined NETEQ_WIDEBAND))
|
||||
case kDecoderPCM16Bwb:
|
||||
case kDecoderPCM16Bwb_2ch:
|
||||
{
|
||||
inst->deltaBytes = -14;
|
||||
inst->deltaTime = 2;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
#if ((defined NETEQ_PCM16B_CODEC)&&(defined NETEQ_32KHZ_WIDEBAND))
|
||||
case kDecoderPCM16Bswb32kHz:
|
||||
case kDecoderPCM16Bswb32kHz_2ch:
|
||||
{
|
||||
inst->deltaBytes = -18;
|
||||
inst->deltaTime = 2;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
#if ((defined NETEQ_PCM16B_CODEC)&&(defined NETEQ_48KHZ_WIDEBAND))
|
||||
case kDecoderPCM16Bswb48kHz:
|
||||
{
|
||||
inst->deltaBytes = -22;
|
||||
inst->deltaTime = 2;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Splittable payloads */
|
||||
#ifdef NETEQ_G722_1_CODEC
|
||||
case kDecoderG722_1_16:
|
||||
{
|
||||
inst->deltaBytes = 40;
|
||||
inst->deltaTime = 320;
|
||||
return 0;
|
||||
}
|
||||
case kDecoderG722_1_24:
|
||||
{
|
||||
inst->deltaBytes = 60;
|
||||
inst->deltaTime = 320;
|
||||
return 0;
|
||||
}
|
||||
case kDecoderG722_1_32:
|
||||
{
|
||||
inst->deltaBytes = 80;
|
||||
inst->deltaTime = 320;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
#ifdef NETEQ_G722_1C_CODEC
|
||||
case kDecoderG722_1C_24:
|
||||
{
|
||||
inst->deltaBytes = 60;
|
||||
inst->deltaTime = 640;
|
||||
return 0;
|
||||
}
|
||||
case kDecoderG722_1C_32:
|
||||
{
|
||||
inst->deltaBytes = 80;
|
||||
inst->deltaTime = 640;
|
||||
return 0;
|
||||
}
|
||||
case kDecoderG722_1C_48:
|
||||
{
|
||||
inst->deltaBytes = 120;
|
||||
inst->deltaTime = 640;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
#ifdef NETEQ_G729_CODEC
|
||||
case kDecoderG729:
|
||||
{
|
||||
inst->deltaBytes = 10;
|
||||
inst->deltaTime = 80;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
#ifdef NETEQ_ILBC_CODEC
|
||||
case kDecoderILBC:
|
||||
{
|
||||
/* Check for splitting of iLBC packets.
|
||||
* If payload size is a multiple of 50 bytes it should be split into 30ms frames.
|
||||
* If payload size is a multiple of 38 bytes it should be split into 20ms frames.
|
||||
* Least common multiplier between 38 and 50 is 950, so the payload size must be less than
|
||||
* 950 bytes in order to resolve the frames unambiguously.
|
||||
* Currently max 12 frames in one bundle.
|
||||
*/
|
||||
switch (codedsize)
|
||||
{
|
||||
case 50:
|
||||
case 100:
|
||||
case 150:
|
||||
case 200:
|
||||
case 250:
|
||||
case 300:
|
||||
case 350:
|
||||
case 400:
|
||||
case 450:
|
||||
case 500:
|
||||
case 550:
|
||||
case 600:
|
||||
{
|
||||
inst->deltaBytes = 50;
|
||||
inst->deltaTime = 240;
|
||||
break;
|
||||
}
|
||||
case 38:
|
||||
case 76:
|
||||
case 114:
|
||||
case 152:
|
||||
case 190:
|
||||
case 228:
|
||||
case 266:
|
||||
case 304:
|
||||
case 342:
|
||||
case 380:
|
||||
case 418:
|
||||
case 456:
|
||||
{
|
||||
inst->deltaBytes = 38;
|
||||
inst->deltaTime = 160;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
return AMBIGUOUS_ILBC_FRAME_SIZE; /* Something not supported... */
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
#ifdef NETEQ_GSMFR_CODEC
|
||||
case kDecoderGSMFR:
|
||||
{
|
||||
inst->deltaBytes = 33;
|
||||
inst->deltaTime = 160;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
default:
|
||||
{ /*Unknown codec */
|
||||
inst->deltaBytes = NO_SPLIT;
|
||||
return CODEC_DB_UNKNOWN_CODEC;
|
||||
}
|
||||
} /* end of switch */
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns 1 if codec is multiple description, 0 otherwise.
|
||||
* NOTE: This function is a stub, since there currently are no MD codecs.
|
||||
*/
|
||||
int WebRtcNetEQ_DbIsMDCodec(enum WebRtcNetEQDecoder codecID)
|
||||
{
|
||||
if (0) /* Add test for MD codecs here */
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns 1 if payload type is registered as a CNG codec, 0 otherwise
|
||||
*/
|
||||
int WebRtcNetEQ_DbIsCNGPayload(const CodecDbInst_t *inst, int payloadType)
|
||||
{
|
||||
#ifdef NETEQ_CNG_CODEC
|
||||
int i;
|
||||
|
||||
for(i=0; i<NUM_CNG_CODECS; i++)
|
||||
{
|
||||
if( (inst->CNGpayloadType[i] != -1) && (inst->CNGpayloadType[i] == payloadType) )
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the sample rate for the codec with the given payload type, 0 if error
|
||||
*/
|
||||
uint16_t WebRtcNetEQ_DbGetSampleRate(CodecDbInst_t *inst, int payloadType)
|
||||
{
|
||||
int i;
|
||||
CodecFuncInst_t codecInst;
|
||||
|
||||
/* Sanity */
|
||||
if (inst == NULL)
|
||||
{
|
||||
/* return 0 Hz */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Check among CNG payloads */
|
||||
for (i = 0; i < NUM_CNG_CODECS; i++)
|
||||
{
|
||||
if ((inst->CNGpayloadType[i] != -1) && (inst->CNGpayloadType[i] == payloadType))
|
||||
{
|
||||
switch (i)
|
||||
{
|
||||
#ifdef NETEQ_WIDEBAND
|
||||
case 1:
|
||||
return 16000;
|
||||
#endif
|
||||
#ifdef NETEQ_32KHZ_WIDEBAND
|
||||
case 2:
|
||||
return 32000;
|
||||
#endif
|
||||
#ifdef NETEQ_48KHZ_WIDEBAND
|
||||
case 3:
|
||||
return 48000;
|
||||
#endif
|
||||
default:
|
||||
return 8000;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Not a CNG payload, check the other payloads */
|
||||
i = WebRtcNetEQ_DbGetCodec(inst, payloadType);
|
||||
if (i >= 0)
|
||||
{
|
||||
if (WebRtcNetEQ_DbGetPtrs(inst, (enum WebRtcNetEQDecoder) i, &codecInst) != 0)
|
||||
{
|
||||
/* Unexpected error, return 0 Hz */
|
||||
return 0;
|
||||
}
|
||||
return codecInst.codec_fs;
|
||||
}
|
||||
|
||||
/* If we end up here, we got an error, return 0 Hz */
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
@ -1,128 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Interface for the codec database.
|
||||
*/
|
||||
|
||||
#ifndef CODEC_DB_H
|
||||
#define CODEC_DB_H
|
||||
|
||||
#include "typedefs.h"
|
||||
|
||||
#include "webrtc_neteq.h"
|
||||
#include "codec_db_defines.h"
|
||||
#include "neteq_defines.h"
|
||||
|
||||
#if defined(NETEQ_48KHZ_WIDEBAND)
|
||||
#define NUM_CNG_CODECS 4
|
||||
#elif defined(NETEQ_32KHZ_WIDEBAND)
|
||||
#define NUM_CNG_CODECS 3
|
||||
#elif defined(NETEQ_WIDEBAND)
|
||||
#define NUM_CNG_CODECS 2
|
||||
#else
|
||||
#define NUM_CNG_CODECS 1
|
||||
#endif
|
||||
|
||||
typedef struct
|
||||
{
|
||||
|
||||
int16_t position[NUM_TOTAL_CODECS];
|
||||
int16_t nrOfCodecs;
|
||||
|
||||
int16_t payloadType[NUM_CODECS];
|
||||
FuncDecode funcDecode[NUM_CODECS];
|
||||
FuncDecode funcDecodeRCU[NUM_CODECS];
|
||||
FuncDecodePLC funcDecodePLC[NUM_CODECS];
|
||||
FuncDecodeInit funcDecodeInit[NUM_CODECS];
|
||||
FuncAddLatePkt funcAddLatePkt[NUM_CODECS];
|
||||
FuncGetMDinfo funcGetMDinfo[NUM_CODECS];
|
||||
FuncGetPitchInfo funcGetPitch[NUM_CODECS];
|
||||
FuncUpdBWEst funcUpdBWEst[NUM_CODECS];
|
||||
FuncDurationEst funcDurationEst[NUM_CODECS];
|
||||
FuncGetErrorCode funcGetErrorCode[NUM_CODECS];
|
||||
void * codec_state[NUM_CODECS];
|
||||
uint16_t codec_fs[NUM_CODECS];
|
||||
int16_t CNGpayloadType[NUM_CNG_CODECS];
|
||||
|
||||
} CodecDbInst_t;
|
||||
|
||||
#define NO_SPLIT -1 /* codec payload cannot be split */
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int16_t deltaBytes;
|
||||
int16_t deltaTime;
|
||||
} SplitInfo_t;
|
||||
|
||||
/*
|
||||
* Resets the codec database.
|
||||
*/
|
||||
int WebRtcNetEQ_DbReset(CodecDbInst_t *inst);
|
||||
|
||||
/*
|
||||
* Adds a new codec to the database.
|
||||
*/
|
||||
int WebRtcNetEQ_DbAdd(CodecDbInst_t *inst, enum WebRtcNetEQDecoder codec,
|
||||
int16_t payloadType, FuncDecode funcDecode,
|
||||
FuncDecode funcDecodeRCU, FuncDecodePLC funcDecodePLC,
|
||||
FuncDecodeInit funcDecodeInit, FuncAddLatePkt funcAddLatePkt,
|
||||
FuncGetMDinfo funcGetMDinfo, FuncGetPitchInfo funcGetPitch,
|
||||
FuncUpdBWEst funcUpdBWEst, FuncDurationEst funcDurationEst,
|
||||
FuncGetErrorCode funcGetErrorCode, void* codec_state,
|
||||
uint16_t codec_fs);
|
||||
|
||||
/*
|
||||
* Removes a codec from the database.
|
||||
*/
|
||||
int WebRtcNetEQ_DbRemove(CodecDbInst_t *inst, enum WebRtcNetEQDecoder codec);
|
||||
|
||||
/*
|
||||
* Get the decoder function pointers for a codec.
|
||||
*/
|
||||
int WebRtcNetEQ_DbGetPtrs(CodecDbInst_t *inst, enum WebRtcNetEQDecoder,
|
||||
CodecFuncInst_t *ptr_inst);
|
||||
|
||||
/*
|
||||
* Returns payload number given a codec identifier.
|
||||
*/
|
||||
|
||||
int WebRtcNetEQ_DbGetPayload(CodecDbInst_t *inst, enum WebRtcNetEQDecoder codecID);
|
||||
|
||||
/*
|
||||
* Returns codec identifier given a payload number.
|
||||
*/
|
||||
|
||||
int WebRtcNetEQ_DbGetCodec(const CodecDbInst_t *inst, int payloadType);
|
||||
|
||||
/*
|
||||
* Extracts the Payload Split information of the codec with the specified payloadType.
|
||||
*/
|
||||
|
||||
int WebRtcNetEQ_DbGetSplitInfo(SplitInfo_t *inst, enum WebRtcNetEQDecoder codecID,
|
||||
int codedsize);
|
||||
|
||||
/*
|
||||
* Returns 1 if codec is multiple description type, 0 otherwise.
|
||||
*/
|
||||
int WebRtcNetEQ_DbIsMDCodec(enum WebRtcNetEQDecoder codecID);
|
||||
|
||||
/*
|
||||
* Returns 1 if payload type is registered as a CNG codec, 0 otherwise.
|
||||
*/
|
||||
int WebRtcNetEQ_DbIsCNGPayload(const CodecDbInst_t *inst, int payloadType);
|
||||
|
||||
/*
|
||||
* Return the sample rate for the codec with the given payload type, 0 if error.
|
||||
*/
|
||||
uint16_t WebRtcNetEQ_DbGetSampleRate(CodecDbInst_t *inst, int payloadType);
|
||||
|
||||
#endif
|
||||
|
@ -1,97 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Some definitions related to the codec database.
|
||||
*/
|
||||
|
||||
#ifndef CODEC_DB_DEFINES_H
|
||||
#define CODEC_DB_DEFINES_H
|
||||
|
||||
#include "typedefs.h"
|
||||
|
||||
#define NUM_CODECS 47 /* probably too large with the limited set of supported codecs*/
|
||||
#define NUM_TOTAL_CODECS kDecoderReservedEnd
|
||||
|
||||
/*
|
||||
* Pointer to decoder function.
|
||||
*/
|
||||
typedef int16_t (*FuncDecode)(void* state, int16_t* encoded, int16_t len,
|
||||
int16_t* decoded, int16_t* speechType);
|
||||
|
||||
/*
|
||||
* Pointer to PLC function.
|
||||
*/
|
||||
typedef int16_t (*FuncDecodePLC)(void* state, int16_t* decodec,
|
||||
int16_t frames);
|
||||
|
||||
/*
|
||||
* Pointer to decoder init function.
|
||||
*/
|
||||
typedef int16_t (*FuncDecodeInit)(void* state);
|
||||
|
||||
/*
|
||||
* Pointer to add late packet function.
|
||||
*/
|
||||
typedef int16_t
|
||||
(*FuncAddLatePkt)(void* state, int16_t* encoded, int16_t len);
|
||||
|
||||
/*
|
||||
* Pointer to get MD infofunction.
|
||||
*/
|
||||
typedef int16_t (*FuncGetMDinfo)(void* state);
|
||||
|
||||
/*
|
||||
* Pointer to pitch info function.
|
||||
* Return 0 for unvoiced, -1 if pitch not availiable.
|
||||
*/
|
||||
typedef int16_t (*FuncGetPitchInfo)(void* state, int16_t* encoded,
|
||||
int16_t* length);
|
||||
|
||||
/*
|
||||
* Pointer to the update bandwidth estimate function
|
||||
*/
|
||||
typedef int16_t (*FuncUpdBWEst)(void* state, const uint16_t *encoded,
|
||||
int32_t packet_size,
|
||||
uint16_t rtp_seq_number, uint32_t send_ts,
|
||||
uint32_t arr_ts);
|
||||
|
||||
/*
|
||||
* Pointer to the frame size estimate function.
|
||||
* Returns the estimated number of samples in the packet.
|
||||
*/
|
||||
typedef int (*FuncDurationEst)(void* state, const uint8_t* payload,
|
||||
int payload_length_bytes);
|
||||
|
||||
/*
|
||||
* Pointer to error code function
|
||||
*/
|
||||
typedef int16_t (*FuncGetErrorCode)(void* state);
|
||||
|
||||
typedef struct CodecFuncInst_t_
|
||||
{
|
||||
|
||||
FuncDecode funcDecode;
|
||||
FuncDecode funcDecodeRCU;
|
||||
FuncDecodePLC funcDecodePLC;
|
||||
FuncDecodeInit funcDecodeInit;
|
||||
FuncAddLatePkt funcAddLatePkt;
|
||||
FuncGetMDinfo funcGetMDinfo;
|
||||
FuncUpdBWEst funcUpdBWEst; /* Currently in use for the ISAC family (without LC) only*/
|
||||
FuncDurationEst funcDurationEst;
|
||||
FuncGetErrorCode funcGetErrorCode;
|
||||
void * codec_state;
|
||||
uint16_t codec_fs;
|
||||
uint32_t timeStamp;
|
||||
|
||||
} CodecFuncInst_t;
|
||||
|
||||
#endif
|
||||
|
@ -1,132 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "dsp.h"
|
||||
|
||||
#include "signal_processing_library.h"
|
||||
|
||||
#include "dsp_helpfunctions.h"
|
||||
|
||||
/* Scratch usage:
|
||||
|
||||
Type Name size startpos endpos
|
||||
int16_t pw16_corrVec 62 0 61
|
||||
int16_t pw16_data_ds 124 0 123
|
||||
int32_t pw32_corr 2*54 124 231
|
||||
|
||||
Total: 232
|
||||
*/
|
||||
|
||||
#define SCRATCH_pw16_corrVec 0
|
||||
#define SCRATCH_pw16_data_ds 0
|
||||
#define SCRATCH_pw32_corr 124
|
||||
|
||||
#define NETEQ_CORRELATOR_DSVECLEN 124 /* 124 = 60 + 10 + 54 */
|
||||
|
||||
int16_t WebRtcNetEQ_Correlator(DSPInst_t *inst,
|
||||
#ifdef SCRATCH
|
||||
int16_t *pw16_scratchPtr,
|
||||
#endif
|
||||
int16_t *pw16_data,
|
||||
int16_t w16_dataLen,
|
||||
int16_t *pw16_corrOut,
|
||||
int16_t *pw16_corrScale)
|
||||
{
|
||||
int16_t w16_corrLen = 60;
|
||||
#ifdef SCRATCH
|
||||
int16_t *pw16_data_ds = pw16_scratchPtr + SCRATCH_pw16_corrVec;
|
||||
int32_t *pw32_corr = (int32_t*) (pw16_scratchPtr + SCRATCH_pw32_corr);
|
||||
/* int16_t *pw16_corrVec = pw16_scratchPtr + SCRATCH_pw16_corrVec;*/
|
||||
#else
|
||||
int16_t pw16_data_ds[NETEQ_CORRELATOR_DSVECLEN];
|
||||
int32_t pw32_corr[54];
|
||||
/* int16_t pw16_corrVec[4+54+4];*/
|
||||
#endif
|
||||
/* int16_t *pw16_corr=&pw16_corrVec[4];*/
|
||||
int16_t w16_maxVal;
|
||||
int32_t w32_maxVal;
|
||||
int16_t w16_normVal;
|
||||
int16_t w16_normVal2;
|
||||
/* int16_t w16_corrUpsLen;*/
|
||||
int16_t *pw16_B = NULL;
|
||||
int16_t w16_Blen = 0;
|
||||
int16_t w16_factor = 0;
|
||||
|
||||
/* Set constants depending on frequency used */
|
||||
if (inst->fs == 8000)
|
||||
{
|
||||
w16_Blen = 3;
|
||||
w16_factor = 2;
|
||||
pw16_B = (int16_t*) WebRtcNetEQ_kDownsample8kHzTbl;
|
||||
#ifdef NETEQ_WIDEBAND
|
||||
}
|
||||
else if (inst->fs==16000)
|
||||
{
|
||||
w16_Blen = 5;
|
||||
w16_factor = 4;
|
||||
pw16_B = (int16_t*)WebRtcNetEQ_kDownsample16kHzTbl;
|
||||
#endif
|
||||
#ifdef NETEQ_32KHZ_WIDEBAND
|
||||
}
|
||||
else if (inst->fs==32000)
|
||||
{
|
||||
w16_Blen = 7;
|
||||
w16_factor = 8;
|
||||
pw16_B = (int16_t*)WebRtcNetEQ_kDownsample32kHzTbl;
|
||||
#endif
|
||||
#ifdef NETEQ_48KHZ_WIDEBAND
|
||||
}
|
||||
else /* if inst->fs==48000 */
|
||||
{
|
||||
w16_Blen = 7;
|
||||
w16_factor = 12;
|
||||
pw16_B = (int16_t*)WebRtcNetEQ_kDownsample48kHzTbl;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Downsample data in order to work on a 4 kHz sampled signal */
|
||||
WebRtcSpl_DownsampleFast(
|
||||
pw16_data + w16_dataLen - (NETEQ_CORRELATOR_DSVECLEN * w16_factor),
|
||||
(int16_t) (NETEQ_CORRELATOR_DSVECLEN * w16_factor), pw16_data_ds,
|
||||
NETEQ_CORRELATOR_DSVECLEN, pw16_B, w16_Blen, w16_factor, (int16_t) 0);
|
||||
|
||||
/* Normalize downsampled vector to using entire 16 bit */
|
||||
w16_maxVal = WebRtcSpl_MaxAbsValueW16(pw16_data_ds, 124);
|
||||
w16_normVal = 16 - WebRtcSpl_NormW32((int32_t) w16_maxVal);
|
||||
WebRtcSpl_VectorBitShiftW16(pw16_data_ds, NETEQ_CORRELATOR_DSVECLEN, pw16_data_ds,
|
||||
w16_normVal);
|
||||
|
||||
/* Correlate from lag 10 to lag 60 (20..120 in NB and 40..240 in WB) */
|
||||
|
||||
WebRtcNetEQ_CrossCorr(
|
||||
pw32_corr, &pw16_data_ds[NETEQ_CORRELATOR_DSVECLEN - w16_corrLen],
|
||||
&pw16_data_ds[NETEQ_CORRELATOR_DSVECLEN - w16_corrLen - 10], 60, 54,
|
||||
6 /*maxValue... shifts*/, -1);
|
||||
|
||||
/*
|
||||
* Move data from w32 to w16 vector.
|
||||
* Normalize downsampled vector to using all 14 bits
|
||||
*/
|
||||
w32_maxVal = WebRtcSpl_MaxAbsValueW32(pw32_corr, 54);
|
||||
w16_normVal2 = 18 - WebRtcSpl_NormW32(w32_maxVal);
|
||||
w16_normVal2 = WEBRTC_SPL_MAX(w16_normVal2, 0);
|
||||
|
||||
WebRtcSpl_VectorBitShiftW32ToW16(pw16_corrOut, 54, pw32_corr, w16_normVal2);
|
||||
|
||||
/* Total scale factor (right shifts) of correlation value */
|
||||
*pw16_corrScale = 2 * w16_normVal + 6 + w16_normVal2;
|
||||
|
||||
return (50 + 1);
|
||||
}
|
||||
|
||||
#undef SCRATCH_pw16_corrVec
|
||||
#undef SCRATCH_pw16_data_ds
|
||||
#undef SCRATCH_pw32_corr
|
||||
|
@ -1,34 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Contains definitions for the delay logging functionality. Only used for debugging and
|
||||
* tracing purposes.
|
||||
*/
|
||||
|
||||
#ifndef DELAY_LOGGING_H
|
||||
#define DELAY_LOGGING_H
|
||||
|
||||
#define NETEQ_DELAY_LOGGING_VERSION_STRING "2.0"
|
||||
|
||||
#define NETEQ_DELAY_LOGGING_SIGNAL_RECIN 1
|
||||
#define NETEQ_DELAY_LOGGING_SIGNAL_FLUSH 2
|
||||
#define NETEQ_DELAY_LOGGING_SIGNAL_CLOCK 3
|
||||
#define NETEQ_DELAY_LOGGING_SIGNAL_EOF 4
|
||||
#define NETEQ_DELAY_LOGGING_SIGNAL_DECODE 5
|
||||
#define NETEQ_DELAY_LOGGING_SIGNAL_CHANGE_FS 6
|
||||
#define NETEQ_DELAY_LOGGING_SIGNAL_MERGE_INFO 7
|
||||
#define NETEQ_DELAY_LOGGING_SIGNAL_EXPAND_INFO 8
|
||||
#define NETEQ_DELAY_LOGGING_SIGNAL_ACCELERATE_INFO 9
|
||||
#define NETEQ_DELAY_LOGGING_SIGNAL_PREEMPTIVE_INFO 10
|
||||
#define NETEQ_DELAY_LOGGING_SIGNAL_OPTBUF 11
|
||||
#define NETEQ_DELAY_LOGGING_SIGNAL_DECODE_ONE_DESC 12
|
||||
|
||||
#endif
|
@ -1,532 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file contains some DSP initialization functions and
|
||||
* constant table definitions.
|
||||
*/
|
||||
|
||||
#include "dsp.h"
|
||||
|
||||
#include "signal_processing_library.h"
|
||||
|
||||
#include "neteq_error_codes.h"
|
||||
|
||||
/* Filter coefficients used when downsampling from the indicated
|
||||
sample rates (8, 16, 32, 48 kHz) to 4 kHz.
|
||||
Coefficients are in Q12. */
|
||||
|
||||
/* {0.3, 0.4, 0.3} */
|
||||
const int16_t WebRtcNetEQ_kDownsample8kHzTbl[] = { 1229, 1638, 1229 };
|
||||
|
||||
#ifdef NETEQ_WIDEBAND
|
||||
/* {0.15, 0.2, 0.3, 0.2, 0.15} */
|
||||
const int16_t WebRtcNetEQ_kDownsample16kHzTbl[] =
|
||||
{ 614, 819, 1229, 819, 614};
|
||||
#endif
|
||||
|
||||
#ifdef NETEQ_32KHZ_WIDEBAND
|
||||
/* {0.1425, 0.1251, 0.1525, 0.1628, 0.1525, 0.1251, 0.1425} */
|
||||
const int16_t WebRtcNetEQ_kDownsample32kHzTbl[] =
|
||||
{ 584, 512, 625, 667, 625, 512, 584};
|
||||
#endif
|
||||
|
||||
#ifdef NETEQ_48KHZ_WIDEBAND
|
||||
/* {0.2487, 0.0952, 0.1042, 0.1074, 0.1042, 0.0952, 0.2487} */
|
||||
const int16_t WebRtcNetEQ_kDownsample48kHzTbl[] =
|
||||
{ 1019, 390, 427, 440, 427, 390, 1019};
|
||||
#endif
|
||||
|
||||
/* Constants used in expand function WebRtcNetEQ_Expand */
|
||||
|
||||
/* Q12: -1.264421 + 4.8659148*x - 4.0092827*x^2 + 1.4100529*x^3 */
|
||||
const int16_t WebRtcNetEQ_kMixFractionFuncTbl[4] = { -5179, 19931, -16422, 5776 };
|
||||
|
||||
/* Tabulated divisions to save complexity */
|
||||
/* 1049/{0, .., 6} */
|
||||
const int16_t WebRtcNetEQ_k1049div[7] = { 0, 1049, 524, 349, 262, 209, 174 };
|
||||
|
||||
/* 2097/{0, .., 6} */
|
||||
const int16_t WebRtcNetEQ_k2097div[7] = { 0, 2097, 1048, 699, 524, 419, 349 };
|
||||
|
||||
/* 5243/{0, .., 6} */
|
||||
const int16_t WebRtcNetEQ_k5243div[7] = { 0, 5243, 2621, 1747, 1310, 1048, 873 };
|
||||
|
||||
#ifdef WEBRTC_NETEQ_40BITACC_TEST
|
||||
/*
|
||||
* Run NetEQ with simulated 40-bit accumulator to run bit-exact to a DSP
|
||||
* implementation where the main (spl and NetEQ) functions have been
|
||||
* 40-bit optimized. For testing purposes.
|
||||
*/
|
||||
|
||||
/****************************************************************************
|
||||
* WebRtcNetEQ_40BitAccCrossCorr(...)
|
||||
*
|
||||
* Calculates the Cross correlation between two sequences seq1 and seq2. Seq1
|
||||
* is fixed and seq2 slides as the pointer is increased with step
|
||||
*
|
||||
* Input:
|
||||
* - seq1 : First sequence (fixed throughout the correlation)
|
||||
* - seq2 : Second sequence (slided step_seq2 for each
|
||||
* new correlation)
|
||||
* - dimSeq : Number of samples to use in the cross correlation.
|
||||
* Should be no larger than 1024 to avoid overflow.
|
||||
* - dimCrossCorr : Number of CrossCorrelations to calculate (start
|
||||
* position for seq2 is updated for each new one)
|
||||
* - rShift : Number of right shifts to use
|
||||
* - step_seq2 : How many (positive or negative) steps the seq2
|
||||
* pointer should be updated for each new cross
|
||||
* correlation value
|
||||
*
|
||||
* Output:
|
||||
* - crossCorr : The cross correlation in Q-rShift
|
||||
*/
|
||||
|
||||
void WebRtcNetEQ_40BitAccCrossCorr(int32_t *crossCorr,
|
||||
int16_t *seq1,
|
||||
int16_t *seq2,
|
||||
int16_t dimSeq,
|
||||
int16_t dimCrossCorr,
|
||||
int16_t rShift,
|
||||
int16_t step_seq2)
|
||||
{
|
||||
int i, j;
|
||||
int16_t *seq1Ptr, *seq2Ptr;
|
||||
int64_t acc;
|
||||
|
||||
for (i = 0; i < dimCrossCorr; i++)
|
||||
{
|
||||
/* Set the pointer to the static vector, set the pointer to
|
||||
the sliding vector and initialize crossCorr */
|
||||
seq1Ptr = seq1;
|
||||
seq2Ptr = seq2 + (step_seq2 * i);
|
||||
acc = 0;
|
||||
|
||||
/* Perform the cross correlation */
|
||||
for (j = 0; j < dimSeq; j++)
|
||||
{
|
||||
acc += WEBRTC_SPL_MUL_16_16((*seq1Ptr), (*seq2Ptr));
|
||||
seq1Ptr++;
|
||||
seq2Ptr++;
|
||||
}
|
||||
|
||||
(*crossCorr) = (int32_t) (acc >> rShift);
|
||||
crossCorr++;
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* WebRtcNetEQ_40BitAccDotW16W16(...)
|
||||
*
|
||||
* Calculates the dot product between two vectors (int16_t)
|
||||
*
|
||||
* Input:
|
||||
* - vector1 : Vector 1
|
||||
* - vector2 : Vector 2
|
||||
* - len : Number of samples in vector
|
||||
* Should be no larger than 1024 to avoid overflow.
|
||||
* - scaling : The number of left shifts required to avoid overflow
|
||||
* in the dot product
|
||||
* Return value : The dot product
|
||||
*/
|
||||
|
||||
int32_t WebRtcNetEQ_40BitAccDotW16W16(int16_t *vector1,
|
||||
int16_t *vector2,
|
||||
int len,
|
||||
int scaling)
|
||||
{
|
||||
int32_t sum;
|
||||
int i;
|
||||
int64_t acc;
|
||||
|
||||
acc = 0;
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
acc += WEBRTC_SPL_MUL_16_16(*vector1++, *vector2++);
|
||||
}
|
||||
|
||||
sum = (int32_t) (acc >> scaling);
|
||||
|
||||
return(sum);
|
||||
}
|
||||
|
||||
#endif /* WEBRTC_NETEQ_40BITACC_TEST */
|
||||
|
||||
/****************************************************************************
|
||||
* WebRtcNetEQ_DSPInit(...)
|
||||
*
|
||||
* Initializes DSP side of NetEQ.
|
||||
*
|
||||
* Input:
|
||||
* - inst : NetEq DSP instance
|
||||
* - fs : Initial sample rate (may change when decoding data)
|
||||
*
|
||||
* Output:
|
||||
* - inst : Updated instance
|
||||
*
|
||||
* Return value : 0 - ok
|
||||
* : non-zero - error
|
||||
*/
|
||||
|
||||
int WebRtcNetEQ_DSPInit(DSPInst_t *inst, uint16_t fs)
|
||||
{
|
||||
|
||||
int res = 0;
|
||||
int16_t fs_mult;
|
||||
|
||||
/* Pointers and values to save before clearing the instance */
|
||||
#ifdef NETEQ_CNG_CODEC
|
||||
void *savedPtr1 = inst->CNG_Codec_inst;
|
||||
#endif
|
||||
void *savedPtr2 = inst->pw16_readAddress;
|
||||
void *savedPtr3 = inst->pw16_writeAddress;
|
||||
void *savedPtr4 = inst->main_inst;
|
||||
#ifdef NETEQ_VAD
|
||||
void *savedVADptr = inst->VADInst.VADState;
|
||||
VADInitFunction savedVADinit = inst->VADInst.initFunction;
|
||||
VADSetmodeFunction savedVADsetmode = inst->VADInst.setmodeFunction;
|
||||
VADFunction savedVADfunc = inst->VADInst.VADFunction;
|
||||
int16_t savedVADEnabled = inst->VADInst.VADEnabled;
|
||||
int savedVADMode = inst->VADInst.VADMode;
|
||||
#endif /* NETEQ_VAD */
|
||||
DSPStats_t saveStats;
|
||||
int16_t saveMsPerCall = inst->millisecondsPerCall;
|
||||
enum BGNMode saveBgnMode = inst->BGNInst.bgnMode;
|
||||
#ifdef NETEQ_STEREO
|
||||
MasterSlaveInfo* saveMSinfo = inst->msInfo;
|
||||
#endif
|
||||
|
||||
/* copy contents of statInst to avoid clearing */WEBRTC_SPL_MEMCPY_W16(&saveStats, &(inst->statInst),
|
||||
sizeof(DSPStats_t)/sizeof(int16_t));
|
||||
|
||||
/* check that the sample rate is valid */
|
||||
if ((fs != 8000)
|
||||
#ifdef NETEQ_WIDEBAND
|
||||
&&(fs!=16000)
|
||||
#endif
|
||||
#ifdef NETEQ_32KHZ_WIDEBAND
|
||||
&&(fs!=32000)
|
||||
#endif
|
||||
#ifdef NETEQ_48KHZ_WIDEBAND
|
||||
&&(fs!=48000)
|
||||
#endif
|
||||
)
|
||||
{
|
||||
/* invalid rate */
|
||||
return (CODEC_DB_UNSUPPORTED_FS);
|
||||
}
|
||||
|
||||
/* calcualte fs/8000 */
|
||||
fs_mult = WebRtcSpl_DivW32W16ResW16(fs, 8000);
|
||||
|
||||
/* Set everything to zero since most variables should be zero at start */
|
||||
WebRtcSpl_MemSetW16((int16_t *) inst, 0, sizeof(DSPInst_t) / sizeof(int16_t));
|
||||
|
||||
/* Restore saved pointers */
|
||||
#ifdef NETEQ_CNG_CODEC
|
||||
inst->CNG_Codec_inst = (CNG_dec_inst *)savedPtr1;
|
||||
#endif
|
||||
inst->pw16_readAddress = (int16_t *) savedPtr2;
|
||||
inst->pw16_writeAddress = (int16_t *) savedPtr3;
|
||||
inst->main_inst = savedPtr4;
|
||||
#ifdef NETEQ_VAD
|
||||
inst->VADInst.VADState = savedVADptr;
|
||||
inst->VADInst.initFunction = savedVADinit;
|
||||
inst->VADInst.setmodeFunction = savedVADsetmode;
|
||||
inst->VADInst.VADFunction = savedVADfunc;
|
||||
inst->VADInst.VADEnabled = savedVADEnabled;
|
||||
inst->VADInst.VADMode = savedVADMode;
|
||||
#endif /* NETEQ_VAD */
|
||||
|
||||
/* Initialize main part */
|
||||
inst->fs = fs;
|
||||
inst->millisecondsPerCall = saveMsPerCall;
|
||||
inst->timestampsPerCall = inst->millisecondsPerCall * 8 * fs_mult;
|
||||
inst->ExpandInst.w16_overlap = 5 * fs_mult;
|
||||
inst->endPosition = 565 * fs_mult;
|
||||
inst->curPosition = inst->endPosition - inst->ExpandInst.w16_overlap;
|
||||
inst->w16_seedInc = 1;
|
||||
inst->uw16_seed = 777;
|
||||
inst->w16_muteFactor = 16384; /* 1.0 in Q14 */
|
||||
inst->w16_frameLen = 3 * inst->timestampsPerCall; /* Dummy initialize to 30ms */
|
||||
|
||||
inst->w16_speechHistoryLen = 256 * fs_mult;
|
||||
inst->pw16_speechHistory = &inst->speechBuffer[inst->endPosition
|
||||
- inst->w16_speechHistoryLen];
|
||||
inst->ExpandInst.pw16_overlapVec = &(inst->pw16_speechHistory[inst->w16_speechHistoryLen
|
||||
- inst->ExpandInst.w16_overlap]);
|
||||
|
||||
/* Reusage of memory in speechBuffer inside Expand */
|
||||
inst->ExpandInst.pw16_expVecs[0] = &inst->speechBuffer[0];
|
||||
inst->ExpandInst.pw16_expVecs[1] = &inst->speechBuffer[126 * fs_mult];
|
||||
inst->ExpandInst.pw16_arState = &inst->speechBuffer[2 * 126 * fs_mult];
|
||||
inst->ExpandInst.pw16_arFilter = &inst->speechBuffer[2 * 126 * fs_mult
|
||||
+ UNVOICED_LPC_ORDER];
|
||||
/* Ends at 2*126*fs_mult+UNVOICED_LPC_ORDER+(UNVOICED_LPC_ORDER+1) */
|
||||
|
||||
inst->ExpandInst.w16_expandMuteFactor = 16384; /* 1.0 in Q14 */
|
||||
|
||||
/* Initialize BGN part */
|
||||
inst->BGNInst.pw16_filter[0] = 4096;
|
||||
inst->BGNInst.w16_scale = 20000;
|
||||
inst->BGNInst.w16_scaleShift = 24;
|
||||
inst->BGNInst.w32_energyUpdate = 500000;
|
||||
inst->BGNInst.w32_energyUpdateLow = 0;
|
||||
inst->BGNInst.w32_energy = 2500;
|
||||
inst->BGNInst.w16_initialized = 0;
|
||||
inst->BGNInst.bgnMode = saveBgnMode;
|
||||
|
||||
/* Recreate statistics counters */WEBRTC_SPL_MEMCPY_W16(&(inst->statInst), &saveStats,
|
||||
sizeof(DSPStats_t)/sizeof(int16_t));
|
||||
|
||||
#ifdef NETEQ_STEREO
|
||||
/* Write back the pointer. */
|
||||
inst->msInfo = saveMSinfo;
|
||||
#endif
|
||||
|
||||
#ifdef NETEQ_CNG_CODEC
|
||||
if (inst->CNG_Codec_inst!=NULL)
|
||||
{
|
||||
/* initialize comfort noise generator */
|
||||
res |= WebRtcCng_InitDec(inst->CNG_Codec_inst);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef NETEQ_VAD
|
||||
/* initialize PostDecode VAD instance
|
||||
(don't bother checking for NULL instance, this is done inside init function) */
|
||||
res |= WebRtcNetEQ_InitVAD(&inst->VADInst, fs);
|
||||
#endif /* NETEQ_VAD */
|
||||
|
||||
return (res);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* WebRtcNetEQ_AddressInit(...)
|
||||
*
|
||||
* Initializes the shared-memory communication on the DSP side.
|
||||
*
|
||||
* Input:
|
||||
* - inst : NetEQ DSP instance
|
||||
* - data2McuAddress : Pointer to memory where DSP writes / MCU reads
|
||||
* - data2DspAddress : Pointer to memory where MCU writes / DSP reads
|
||||
* - mainInst : NetEQ main instance
|
||||
*
|
||||
* Output:
|
||||
* - inst : Updated instance
|
||||
*
|
||||
* Return value : 0 - ok
|
||||
*/
|
||||
|
||||
int WebRtcNetEQ_AddressInit(DSPInst_t *inst, const void *data2McuAddress,
|
||||
const void *data2DspAddress, const void *mainInst)
|
||||
{
|
||||
|
||||
/* set shared-memory addresses in the DSP instance */
|
||||
inst->pw16_readAddress = (int16_t *) data2DspAddress;
|
||||
inst->pw16_writeAddress = (int16_t *) data2McuAddress;
|
||||
|
||||
/* set pointer to main NetEQ instance */
|
||||
inst->main_inst = (void *) mainInst;
|
||||
|
||||
/* set output frame size to 10 ms = 80 samples in narrowband */
|
||||
inst->millisecondsPerCall = 10;
|
||||
inst->timestampsPerCall = 80;
|
||||
|
||||
return (0);
|
||||
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* NETEQDSP_clearInCallStats(...)
|
||||
*
|
||||
* Reset in-call statistics variables on DSP side.
|
||||
*
|
||||
* Input:
|
||||
* - inst : NetEQ DSP instance
|
||||
*
|
||||
* Output:
|
||||
* - inst : Updated instance
|
||||
*
|
||||
* Return value : 0 - ok
|
||||
*/
|
||||
|
||||
int WebRtcNetEQ_ClearInCallStats(DSPInst_t *inst)
|
||||
{
|
||||
/* Reset statistics counters */
|
||||
inst->statInst.accelerateLength = 0;
|
||||
inst->statInst.expandLength = 0;
|
||||
inst->statInst.preemptiveLength = 0;
|
||||
inst->statInst.addedSamples = 0;
|
||||
return (0);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* WebRtcNetEQ_ClearPostCallStats(...)
|
||||
*
|
||||
* Reset post-call statistics variables on DSP side.
|
||||
*
|
||||
* Input:
|
||||
* - inst : NetEQ DSP instance
|
||||
*
|
||||
* Output:
|
||||
* - inst : Updated instance
|
||||
*
|
||||
* Return value : 0 - ok
|
||||
*/
|
||||
|
||||
int WebRtcNetEQ_ClearPostCallStats(DSPInst_t *inst)
|
||||
{
|
||||
|
||||
/* Reset statistics counters */
|
||||
inst->statInst.expandedVoiceSamples = 0;
|
||||
inst->statInst.expandedNoiseSamples = 0;
|
||||
return (0);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* WebRtcNetEQ_ClearActivityStats(...)
|
||||
*
|
||||
* Reset processing activity statistics.
|
||||
*
|
||||
* Input:
|
||||
* - inst : NetEQ DSP instance
|
||||
*
|
||||
* Output:
|
||||
* - inst : Updated instance
|
||||
*
|
||||
*/
|
||||
|
||||
void WebRtcNetEQ_ClearActivityStats(DSPInst_t *inst) {
|
||||
memset(&inst->activity_stats, 0, sizeof(ActivityStats));
|
||||
}
|
||||
|
||||
#ifdef NETEQ_VAD
|
||||
|
||||
/****************************************************************************
|
||||
* WebRtcNetEQ_InitVAD(...)
|
||||
*
|
||||
* Initializes post-decode VAD instance.
|
||||
*
|
||||
* Input:
|
||||
* - VADinst : PostDecodeVAD instance
|
||||
* - fs : Initial sample rate
|
||||
*
|
||||
* Output:
|
||||
* - VADinst : Updated instance
|
||||
*
|
||||
* Return value : 0 - Ok
|
||||
* -1 - Error
|
||||
*/
|
||||
|
||||
int WebRtcNetEQ_InitVAD(PostDecodeVAD_t *VADInst, uint16_t fs)
|
||||
{
|
||||
|
||||
int res = 0;
|
||||
|
||||
/* initially, disable the post-decode VAD */
|
||||
VADInst->VADEnabled = 0;
|
||||
|
||||
if (VADInst->VADState != NULL /* if VAD state is provided */
|
||||
&& VADInst->initFunction != NULL /* and all function ... */
|
||||
&& VADInst->setmodeFunction != NULL /* ... pointers ... */
|
||||
&& VADInst->VADFunction != NULL) /* ... are defined */
|
||||
{
|
||||
res = VADInst->initFunction( VADInst->VADState ); /* call VAD init function */
|
||||
res |= WebRtcNetEQ_SetVADModeInternal( VADInst, VADInst->VADMode );
|
||||
|
||||
if (res!=0)
|
||||
{
|
||||
/* something is wrong; play it safe and set the VADstate to NULL */
|
||||
VADInst->VADState = NULL;
|
||||
}
|
||||
else if (fs<=16000)
|
||||
{
|
||||
/* enable VAD if NB or WB (VAD cannot handle SWB) */
|
||||
VADInst->VADEnabled = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* reset SID/CNG interval counter */
|
||||
VADInst->SIDintervalCounter = 0;
|
||||
|
||||
/* initialize with active-speaker decision */
|
||||
VADInst->VADDecision = 1;
|
||||
|
||||
return(res);
|
||||
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* WebRtcNetEQ_SetVADModeInternal(...)
|
||||
*
|
||||
* Set the VAD mode in the VAD struct, and communicate it to the VAD instance
|
||||
* if it exists.
|
||||
*
|
||||
* Input:
|
||||
* - VADinst : PostDecodeVAD instance
|
||||
* - mode : Mode number passed on to the VAD function
|
||||
*
|
||||
* Output:
|
||||
* - VADinst : Updated instance
|
||||
*
|
||||
* Return value : 0 - Ok
|
||||
* -1 - Error
|
||||
*/
|
||||
|
||||
int WebRtcNetEQ_SetVADModeInternal(PostDecodeVAD_t *VADInst, int mode)
|
||||
{
|
||||
|
||||
int res = 0;
|
||||
|
||||
VADInst->VADMode = mode;
|
||||
|
||||
if (VADInst->VADState != NULL)
|
||||
{
|
||||
/* call setmode function */
|
||||
res = VADInst->setmodeFunction(VADInst->VADState, mode);
|
||||
}
|
||||
|
||||
return(res);
|
||||
|
||||
}
|
||||
|
||||
#endif /* NETEQ_VAD */
|
||||
|
||||
/****************************************************************************
|
||||
* WebRtcNetEQ_FlushSpeechBuffer(...)
|
||||
*
|
||||
* Flush the speech buffer.
|
||||
*
|
||||
* Input:
|
||||
* - inst : NetEq DSP instance
|
||||
*
|
||||
* Output:
|
||||
* - inst : Updated instance
|
||||
*
|
||||
* Return value : 0 - ok
|
||||
* : non-zero - error
|
||||
*/
|
||||
|
||||
int WebRtcNetEQ_FlushSpeechBuffer(DSPInst_t *inst)
|
||||
{
|
||||
int16_t fs_mult;
|
||||
|
||||
/* calcualte fs/8000 */
|
||||
fs_mult = WebRtcSpl_DivW32W16ResW16(inst->fs, 8000);
|
||||
|
||||
/* clear buffer */
|
||||
WebRtcSpl_MemSetW16(inst->speechBuffer, 0, SPEECH_BUF_SIZE);
|
||||
inst->endPosition = 565 * fs_mult;
|
||||
inst->curPosition = inst->endPosition - inst->ExpandInst.w16_overlap;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -1,807 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file contains some DSP initialization functions,
|
||||
* constant table definitions and other parameters.
|
||||
* Also contains definitions of all DSP-side data structures.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef DSP_H
|
||||
#define DSP_H
|
||||
|
||||
#include "typedefs.h"
|
||||
|
||||
#include "webrtc_cng.h"
|
||||
|
||||
#include "codec_db_defines.h"
|
||||
#include "neteq_defines.h"
|
||||
#include "neteq_statistics.h"
|
||||
|
||||
#ifdef NETEQ_ATEVENT_DECODE
|
||||
#include "dtmf_tonegen.h"
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/*****************************/
|
||||
/* Pre-processor definitions */
|
||||
/*****************************/
|
||||
|
||||
/* FSMULT is the sample rate divided by 8000 */
|
||||
#if defined(NETEQ_48KHZ_WIDEBAND)
|
||||
#define FSMULT 6
|
||||
#elif defined(NETEQ_32KHZ_WIDEBAND)
|
||||
#define FSMULT 4
|
||||
#elif defined(NETEQ_WIDEBAND)
|
||||
#define FSMULT 2
|
||||
#else
|
||||
#define FSMULT 1
|
||||
#endif
|
||||
|
||||
/* Size of the speech buffer (or synchronization buffer). */
|
||||
/* 60 ms decoding + 10 ms syncbuff + 0.625ms lookahead */
|
||||
#define SPEECH_BUF_SIZE (565 * FSMULT)
|
||||
|
||||
/* Misc definitions */
|
||||
#define BGN_LPC_ORDER (4 + FSMULT) /* 5, 6, 8, or 10 */
|
||||
#define UNVOICED_LPC_ORDER 6
|
||||
#define RANDVEC_NO_OF_SAMPLES 256
|
||||
|
||||
/* Number of milliseconds to remove/add during accelerate/pre-emptive expand
|
||||
under BGNonly operation */
|
||||
#define DEFAULT_TIME_ADJUST 8
|
||||
|
||||
/* Number of RecOut calls without CNG/SID before re-enabling post-decode VAD */
|
||||
#define POST_DECODE_VAD_AUTO_ENABLE 3000
|
||||
|
||||
/* 8kHz windowing in Q15 (over 5 samples) */
|
||||
#define NETEQ_OVERLAP_WINMUTE_8KHZ_START 27307
|
||||
#define NETEQ_OVERLAP_WINMUTE_8KHZ_INC -5461
|
||||
#define NETEQ_OVERLAP_WINUNMUTE_8KHZ_START 5461
|
||||
#define NETEQ_OVERLAP_WINUNMUTE_8KHZ_INC 5461
|
||||
/* 16kHz windowing in Q15 (over 10 samples) */
|
||||
#define NETEQ_OVERLAP_WINMUTE_16KHZ_START 29789
|
||||
#define NETEQ_OVERLAP_WINMUTE_16KHZ_INC -2979
|
||||
#define NETEQ_OVERLAP_WINUNMUTE_16KHZ_START 2979
|
||||
#define NETEQ_OVERLAP_WINUNMUTE_16KHZ_INC 2979
|
||||
/* 32kHz windowing in Q15 (over 20 samples) */
|
||||
#define NETEQ_OVERLAP_WINMUTE_32KHZ_START 31208
|
||||
#define NETEQ_OVERLAP_WINMUTE_32KHZ_INC -1560
|
||||
#define NETEQ_OVERLAP_WINUNMUTE_32KHZ_START 1560
|
||||
#define NETEQ_OVERLAP_WINUNMUTE_32KHZ_INC 1560
|
||||
/* 48kHz windowing in Q15 (over 30 samples) */
|
||||
#define NETEQ_OVERLAP_WINMUTE_48KHZ_START 31711
|
||||
#define NETEQ_OVERLAP_WINMUTE_48KHZ_INC -1057
|
||||
#define NETEQ_OVERLAP_WINUNMUTE_48KHZ_START 1057
|
||||
#define NETEQ_OVERLAP_WINUNMUTE_48KHZ_INC 1057
|
||||
|
||||
/* Fade BGN towards zero after this many Expand calls */
|
||||
#define FADE_BGN_TIME 200
|
||||
|
||||
|
||||
/*******************/
|
||||
/* Constant tables */
|
||||
/*******************/
|
||||
|
||||
extern const int16_t WebRtcNetEQ_kDownsample8kHzTbl[];
|
||||
extern const int16_t WebRtcNetEQ_kDownsample16kHzTbl[];
|
||||
extern const int16_t WebRtcNetEQ_kDownsample32kHzTbl[];
|
||||
extern const int16_t WebRtcNetEQ_kDownsample48kHzTbl[];
|
||||
extern const int16_t WebRtcNetEQ_kRandnTbl[];
|
||||
extern const int16_t WebRtcNetEQ_kMixFractionFuncTbl[];
|
||||
extern const int16_t WebRtcNetEQ_k1049div[];
|
||||
extern const int16_t WebRtcNetEQ_k2097div[];
|
||||
extern const int16_t WebRtcNetEQ_k5243div[];
|
||||
|
||||
|
||||
|
||||
/************/
|
||||
/* Typedefs */
|
||||
/************/
|
||||
|
||||
enum BGNMode
|
||||
{
|
||||
BGN_ON, /* default "normal" behavior with eternal noise */
|
||||
BGN_FADE, /* noise fades to zero after some time */
|
||||
BGN_OFF /* background noise is always zero */
|
||||
};
|
||||
|
||||
#ifdef NETEQ_STEREO
|
||||
enum MasterSlaveMode
|
||||
{
|
||||
NETEQ_MONO, /* stand-alone instance */
|
||||
NETEQ_MASTER, /* master instance in a spatial/stereo configuration */
|
||||
NETEQ_SLAVE /* slave instance in a spatial/stereo configuration */
|
||||
};
|
||||
|
||||
enum MasterSlaveExtraInfo
|
||||
{
|
||||
NO_INFO, /* no info to convey */
|
||||
ACC_FAIL, /* signal that accelerate failed */
|
||||
PE_EXP_FAIL, /* signal that pre-emptive expand failed */
|
||||
DTMF_OVERDUB, /* signal that DTMF overdub is generated */
|
||||
DTMF_ONLY /* signal that DTMF only is played */
|
||||
};
|
||||
#endif
|
||||
|
||||
/****************************/
|
||||
/* DSP-side data structures */
|
||||
/****************************/
|
||||
|
||||
/* Background noise (BGN) instance for storing BGN parameters
|
||||
(sub-instance of NETEQDSP_inst) */
|
||||
typedef struct BGNInst_t_
|
||||
{
|
||||
|
||||
int32_t w32_energy;
|
||||
int32_t w32_energyMax;
|
||||
int32_t w32_energyUpdate;
|
||||
int32_t w32_energyUpdateLow;
|
||||
int16_t pw16_filterState[BGN_LPC_ORDER];
|
||||
int16_t pw16_filter[BGN_LPC_ORDER + 1];
|
||||
int16_t w16_mutefactor;
|
||||
int16_t w16_scale;
|
||||
int16_t w16_scaleShift;
|
||||
int16_t w16_initialized;
|
||||
enum BGNMode bgnMode;
|
||||
|
||||
} BGNInst_t;
|
||||
|
||||
/* Expansion instance (sub-instance of NETEQDSP_inst) */
|
||||
typedef struct ExpandInst_t_
|
||||
{
|
||||
|
||||
int16_t w16_overlap; /* Constant, 5 for NB and 10 for WB */
|
||||
int16_t w16_consecExp; /* Number of consecutive expand calls */
|
||||
int16_t *pw16_arFilter; /* length [UNVOICED_LPC_ORDER+1] */
|
||||
int16_t *pw16_arState; /* length [UNVOICED_LPC_ORDER] */
|
||||
int16_t w16_arGain;
|
||||
int16_t w16_arGainScale;
|
||||
int16_t w16_vFraction; /* Q14 */
|
||||
int16_t w16_currentVFraction; /* Q14 */
|
||||
int16_t *pw16_expVecs[2];
|
||||
int16_t w16_lags[3];
|
||||
int16_t w16_maxLag;
|
||||
int16_t *pw16_overlapVec; /* last samples of speech history */
|
||||
int16_t w16_lagsDirection;
|
||||
int16_t w16_lagsPosition;
|
||||
int16_t w16_expandMuteFactor; /* Q14 */
|
||||
int16_t w16_stopMuting;
|
||||
int16_t w16_onset;
|
||||
int16_t w16_muteSlope; /* Q20 */
|
||||
|
||||
} ExpandInst_t;
|
||||
|
||||
#ifdef NETEQ_VAD
|
||||
|
||||
/*
|
||||
* VAD function pointer types, replicating the typedefs in webrtc_neteq_internal.h.
|
||||
* These function pointers match the definitions of WebRtc VAD functions WebRtcVad_Init,
|
||||
* WebRtcVad_set_mode and WebRtcVad_Process, respectively, all found in webrtc_vad.h.
|
||||
*/
|
||||
typedef int (*VADInitFunction)(void *VAD_inst);
|
||||
typedef int (*VADSetmodeFunction)(void *VAD_inst, int mode);
|
||||
typedef int (*VADFunction)(void *VAD_inst, int fs, int16_t *frame,
|
||||
int frameLen);
|
||||
|
||||
/* Post-decode VAD instance (sub-instance of NETEQDSP_inst) */
|
||||
typedef struct PostDecodeVAD_t_
|
||||
{
|
||||
|
||||
void *VADState; /* pointer to a VAD instance */
|
||||
|
||||
int16_t VADEnabled; /* 1 if enabled, 0 if disabled */
|
||||
int VADMode; /* mode parameter to pass to the VAD function */
|
||||
int VADDecision; /* 1 for active, 0 for passive */
|
||||
int16_t SIDintervalCounter; /* reset when decoding CNG/SID frame,
|
||||
increment for each recout call */
|
||||
|
||||
/* Function pointers */
|
||||
VADInitFunction initFunction; /* VAD init function */
|
||||
VADSetmodeFunction setmodeFunction; /* VAD setmode function */
|
||||
VADFunction VADFunction; /* VAD function */
|
||||
|
||||
} PostDecodeVAD_t;
|
||||
|
||||
#endif /* NETEQ_VAD */
|
||||
|
||||
#ifdef NETEQ_STEREO
|
||||
#define MAX_MS_DECODES 10
|
||||
|
||||
typedef struct
|
||||
{
|
||||
/* Stand-alone, master, or slave */
|
||||
enum MasterSlaveMode msMode;
|
||||
|
||||
enum MasterSlaveExtraInfo extraInfo;
|
||||
|
||||
uint16_t instruction;
|
||||
int16_t distLag;
|
||||
int16_t corrLag;
|
||||
int16_t bestIndex;
|
||||
|
||||
uint32_t endTimestamp;
|
||||
uint16_t samplesLeftWithOverlap;
|
||||
|
||||
} MasterSlaveInfo;
|
||||
#endif
|
||||
|
||||
|
||||
/* "Main" NetEQ DSP instance */
|
||||
typedef struct DSPInst_t_
|
||||
{
|
||||
|
||||
/* MCU/DSP Communication layer */
|
||||
int16_t *pw16_readAddress;
|
||||
int16_t *pw16_writeAddress;
|
||||
void *main_inst;
|
||||
|
||||
/* Output frame size in ms and samples */
|
||||
int16_t millisecondsPerCall;
|
||||
int16_t timestampsPerCall;
|
||||
|
||||
/*
|
||||
* Example of speech buffer
|
||||
*
|
||||
* -----------------------------------------------------------
|
||||
* | History T-60 to T | Future |
|
||||
* -----------------------------------------------------------
|
||||
* ^ ^
|
||||
* | |
|
||||
* curPosition endPosition
|
||||
*
|
||||
* History is gradually shifted out to the left when inserting
|
||||
* new data at the end.
|
||||
*/
|
||||
|
||||
int16_t speechBuffer[SPEECH_BUF_SIZE]; /* History/future speech buffer */
|
||||
int curPosition; /* Next sample to play */
|
||||
int endPosition; /* Position that ends future data */
|
||||
uint32_t endTimestamp; /* Timestamp value at end of future data */
|
||||
uint32_t videoSyncTimestamp; /* (Estimated) timestamp of the last
|
||||
played sample (usually same as
|
||||
endTimestamp-(endPosition-curPosition)
|
||||
except during Expand and CNG) */
|
||||
uint16_t fs; /* sample rate in Hz */
|
||||
int16_t w16_frameLen; /* decoder frame length in samples */
|
||||
int16_t w16_mode; /* operation used during last RecOut call */
|
||||
int16_t w16_muteFactor; /* speech mute factor in Q14 */
|
||||
int16_t *pw16_speechHistory; /* beginning of speech history during Expand */
|
||||
int16_t w16_speechHistoryLen; /* 256 for NB and 512 for WB */
|
||||
|
||||
/* random noise seed parameters */
|
||||
int16_t w16_seedInc;
|
||||
uint32_t uw16_seed;
|
||||
|
||||
/* VQmon related variable */
|
||||
int16_t w16_concealedTS;
|
||||
|
||||
/*****************/
|
||||
/* Sub-instances */
|
||||
/*****************/
|
||||
|
||||
/* Decoder data */
|
||||
CodecFuncInst_t codec_ptr_inst;
|
||||
|
||||
#ifdef NETEQ_CNG_CODEC
|
||||
/* CNG "decoder" instance */
|
||||
CNG_dec_inst *CNG_Codec_inst;
|
||||
#endif /* NETEQ_CNG_CODEC */
|
||||
|
||||
#ifdef NETEQ_ATEVENT_DECODE
|
||||
/* DTMF generator instance */
|
||||
dtmf_tone_inst_t DTMFInst;
|
||||
#endif /* NETEQ_CNG_CODEC */
|
||||
|
||||
#ifdef NETEQ_VAD
|
||||
/* Post-decode VAD instance */
|
||||
PostDecodeVAD_t VADInst;
|
||||
#endif /* NETEQ_VAD */
|
||||
|
||||
/* Expand instance (defined above) */
|
||||
ExpandInst_t ExpandInst;
|
||||
|
||||
/* Background noise instance (defined above) */
|
||||
BGNInst_t BGNInst;
|
||||
|
||||
/* Internal statistics instance */
|
||||
DSPStats_t statInst;
|
||||
|
||||
/* Internal instance for short-term processing activity. */
|
||||
ActivityStats activity_stats;
|
||||
|
||||
#ifdef NETEQ_STEREO
|
||||
/* Pointer to Master/Slave info */
|
||||
MasterSlaveInfo *msInfo;
|
||||
#endif
|
||||
|
||||
} DSPInst_t;
|
||||
|
||||
|
||||
/*************************/
|
||||
/* Function declarations */
|
||||
/*************************/
|
||||
|
||||
/****************************************************************************
|
||||
* WebRtcNetEQ_DSPInit(...)
|
||||
*
|
||||
* Initializes DSP side of NetEQ.
|
||||
*
|
||||
* Input:
|
||||
* - inst : NetEq DSP instance
|
||||
* - fs : Initial sample rate (may change when decoding data)
|
||||
*
|
||||
* Output:
|
||||
* - inst : Updated instance
|
||||
*
|
||||
* Return value : 0 - ok
|
||||
* : non-zero - error
|
||||
*/
|
||||
|
||||
int WebRtcNetEQ_DSPInit(DSPInst_t *inst, uint16_t fs);
|
||||
|
||||
/****************************************************************************
|
||||
* WebRtcNetEQ_AddressInit(...)
|
||||
*
|
||||
* Initializes the shared-memory communication on the DSP side.
|
||||
*
|
||||
* Input:
|
||||
* - inst : NetEQ DSP instance
|
||||
* - data2McuAddress : Pointer to memory where DSP writes / MCU reads
|
||||
* - data2DspAddress : Pointer to memory where MCU writes / DSP reads
|
||||
* - mainInst : NetEQ main instance
|
||||
*
|
||||
* Output:
|
||||
* - inst : Updated instance
|
||||
*
|
||||
* Return value : 0 - ok
|
||||
*/
|
||||
|
||||
int WebRtcNetEQ_AddressInit(DSPInst_t *inst, const void *data2McuAddress,
|
||||
const void *data2DspAddress, const void *mainInst);
|
||||
|
||||
/****************************************************************************
|
||||
* WebRtcNetEQ_ClearInCallStats(...)
|
||||
*
|
||||
* Reset in-call statistics variables on DSP side.
|
||||
*
|
||||
* Input:
|
||||
* - inst : NetEQ DSP instance
|
||||
*
|
||||
* Output:
|
||||
* - inst : Updated instance
|
||||
*
|
||||
* Return value : 0 - ok
|
||||
*/
|
||||
|
||||
int WebRtcNetEQ_ClearInCallStats(DSPInst_t *inst);
|
||||
|
||||
/****************************************************************************
|
||||
* WebRtcNetEQ_ClearPostCallStats(...)
|
||||
*
|
||||
* Reset post-call statistics variables on DSP side.
|
||||
*
|
||||
* Input:
|
||||
* - inst : NetEQ DSP instance
|
||||
*
|
||||
* Output:
|
||||
* - inst : Updated instance
|
||||
*
|
||||
* Return value : 0 - ok
|
||||
*/
|
||||
|
||||
int WebRtcNetEQ_ClearPostCallStats(DSPInst_t *inst);
|
||||
|
||||
/****************************************************************************
|
||||
* WebRtcNetEQ_ClearActivityStats(...)
|
||||
*
|
||||
* Reset processing activity statistics.
|
||||
*
|
||||
* Input:
|
||||
* - inst : NetEQ DSP instance
|
||||
*
|
||||
* Output:
|
||||
* - inst : Updated instance
|
||||
*
|
||||
*/
|
||||
|
||||
void WebRtcNetEQ_ClearActivityStats(DSPInst_t *inst);
|
||||
|
||||
/****************************************************************************
|
||||
* WebRtcNetEQ_RecOutInternal(...)
|
||||
*
|
||||
* This function asks NetEQ for more speech/audio data.
|
||||
*
|
||||
* Input:
|
||||
* - inst : NetEQ instance, i.e. the user that requests more
|
||||
* speech/audio data.
|
||||
* - outdata : Pointer to a memory space where the output data
|
||||
* should be stored.
|
||||
* - BGNonly : If non-zero, RecOut will only produce background
|
||||
* noise. It will still draw packets from the packet
|
||||
* buffer, but they will never be decoded.
|
||||
* - av_sync : 1 if NetEQ is in AV-sync, 0 otherwise.
|
||||
*
|
||||
* Output:
|
||||
* - inst : Updated user information
|
||||
* - len : Number of samples that were outputted from NetEq
|
||||
*
|
||||
* Return value : 0 - Ok
|
||||
* -1 - Error
|
||||
*/
|
||||
|
||||
int WebRtcNetEQ_RecOutInternal(DSPInst_t *inst, int16_t *pw16_outData,
|
||||
int16_t *pw16_len, int16_t BGNonly, int av_sync);
|
||||
|
||||
/****************************************************************************
|
||||
* WebRtcNetEQ_Normal(...)
|
||||
*
|
||||
* This function has the possibility to modify data that is played out in Normal
|
||||
* mode, for example adjust the gain of the signal. The length of the signal
|
||||
* can not be changed.
|
||||
*
|
||||
* Input:
|
||||
* - inst : NetEQ DSP instance
|
||||
* - scratchPtr : Pointer to scratch vector
|
||||
* - decoded : Pointer to vector of new data from decoder
|
||||
* - len : Number of input samples
|
||||
*
|
||||
* Output:
|
||||
* - inst : Updated user information
|
||||
* - pw16_len : Pointer to varibale where the number of samples
|
||||
* produced will be written
|
||||
*
|
||||
* Return value : >=0 - Number of samples written to outData
|
||||
* -1 - Error
|
||||
*/
|
||||
|
||||
int WebRtcNetEQ_Normal(DSPInst_t *inst,
|
||||
#ifdef SCRATCH
|
||||
int16_t *pw16_scratchPtr,
|
||||
#endif
|
||||
int16_t *pw16_decoded, int16_t len,
|
||||
int16_t *pw16_outData, int16_t *pw16_len);
|
||||
|
||||
/****************************************************************************
|
||||
* WebRtcNetEQ_Expand(...)
|
||||
*
|
||||
* This function produces one "chunk" of expansion data (PLC audio). The
|
||||
* lenght of the produced audio depends on the speech history.
|
||||
*
|
||||
* Input:
|
||||
* - inst : NetEQ DSP instance
|
||||
* - scratchPtr : Pointer to scratch vector
|
||||
* - BGNonly : If non-zero, Expand will only produce background
|
||||
* noise.
|
||||
* - pw16_len : Desired number of samples (only for BGN mode).
|
||||
*
|
||||
* Output:
|
||||
* - inst : Updated user information
|
||||
* - outdata : Pointer to a memory space where the output data
|
||||
* should be stored
|
||||
* - pw16_len : Number of samples that were outputted from NetEq
|
||||
*
|
||||
* Return value : 0 - Ok
|
||||
* <0 - Error
|
||||
*/
|
||||
|
||||
int WebRtcNetEQ_Expand(DSPInst_t *inst,
|
||||
#ifdef SCRATCH
|
||||
int16_t *pw16_scratchPtr,
|
||||
#endif
|
||||
int16_t *pw16_outData, int16_t *pw16_len,
|
||||
int16_t BGNonly);
|
||||
|
||||
/****************************************************************************
|
||||
* WebRtcNetEQ_GenerateBGN(...)
|
||||
*
|
||||
* This function generates and writes len samples of background noise to the
|
||||
* output vector. The Expand function will be called repeteadly until the
|
||||
* correct number of samples is produced.
|
||||
*
|
||||
* Input:
|
||||
* - inst : NetEQ DSP instance
|
||||
* - scratchPtr : Pointer to scratch vector
|
||||
* - len : Desired length of produced BGN.
|
||||
*
|
||||
*
|
||||
* Output:
|
||||
* - pw16_outData : Pointer to a memory space where the output data
|
||||
* should be stored
|
||||
*
|
||||
* Return value : >=0 - Number of noise samples produced and written
|
||||
* to output
|
||||
* -1 - Error
|
||||
*/
|
||||
|
||||
int WebRtcNetEQ_GenerateBGN(DSPInst_t *inst,
|
||||
#ifdef SCRATCH
|
||||
int16_t *pw16_scratchPtr,
|
||||
#endif
|
||||
int16_t *pw16_outData, int16_t len);
|
||||
|
||||
/****************************************************************************
|
||||
* WebRtcNetEQ_PreEmptiveExpand(...)
|
||||
*
|
||||
* This function tries to extend the audio data by repeating one or several
|
||||
* pitch periods. The operation is only carried out if the correlation is
|
||||
* strong or if the signal energy is very low. The algorithm is the
|
||||
* reciprocal of the Accelerate algorithm.
|
||||
*
|
||||
* Input:
|
||||
* - inst : NetEQ DSP instance
|
||||
* - scratchPtr : Pointer to scratch vector.
|
||||
* - decoded : Pointer to newly decoded speech.
|
||||
* - len : Length of decoded speech.
|
||||
* - oldDataLen : Length of the part of decoded that has already been played out.
|
||||
* - BGNonly : If non-zero, Pre-emptive Expand will only copy
|
||||
* the first DEFAULT_TIME_ADJUST seconds of the
|
||||
* input and append to the end. No signal matching is
|
||||
* done.
|
||||
*
|
||||
* Output:
|
||||
* - inst : Updated instance
|
||||
* - outData : Pointer to a memory space where the output data
|
||||
* should be stored. The vector must be at least
|
||||
* min(len + 120*fs/8000, NETEQ_MAX_OUTPUT_SIZE)
|
||||
* elements long.
|
||||
* - pw16_len : Number of samples written to outData.
|
||||
*
|
||||
* Return value : 0 - Ok
|
||||
* <0 - Error
|
||||
*/
|
||||
|
||||
int WebRtcNetEQ_PreEmptiveExpand(DSPInst_t *inst,
|
||||
#ifdef SCRATCH
|
||||
int16_t *pw16_scratchPtr,
|
||||
#endif
|
||||
const int16_t *pw16_decoded, int len, int oldDataLen,
|
||||
int16_t *pw16_outData, int16_t *pw16_len,
|
||||
int16_t BGNonly);
|
||||
|
||||
/****************************************************************************
|
||||
* WebRtcNetEQ_Accelerate(...)
|
||||
*
|
||||
* This function tries to shorten the audio data by removing one or several
|
||||
* pitch periods. The operation is only carried out if the correlation is
|
||||
* strong or if the signal energy is very low.
|
||||
*
|
||||
* Input:
|
||||
* - inst : NetEQ DSP instance
|
||||
* - scratchPtr : Pointer to scratch vector.
|
||||
* - decoded : Pointer to newly decoded speech.
|
||||
* - len : Length of decoded speech.
|
||||
* - BGNonly : If non-zero, Accelerate will only remove the last
|
||||
* DEFAULT_TIME_ADJUST seconds of the intput.
|
||||
* No signal matching is done.
|
||||
*
|
||||
*
|
||||
* Output:
|
||||
* - inst : Updated instance
|
||||
* - outData : Pointer to a memory space where the output data
|
||||
* should be stored
|
||||
* - pw16_len : Number of samples written to outData.
|
||||
*
|
||||
* Return value : 0 - Ok
|
||||
* <0 - Error
|
||||
*/
|
||||
|
||||
int WebRtcNetEQ_Accelerate(DSPInst_t *inst,
|
||||
#ifdef SCRATCH
|
||||
int16_t *pw16_scratchPtr,
|
||||
#endif
|
||||
const int16_t *pw16_decoded, int len,
|
||||
int16_t *pw16_outData, int16_t *pw16_len,
|
||||
int16_t BGNonly);
|
||||
|
||||
/****************************************************************************
|
||||
* WebRtcNetEQ_Merge(...)
|
||||
*
|
||||
* This function is used to merge new data from the decoder to the exisiting
|
||||
* stream in the synchronization buffer. The merge operation is typically
|
||||
* done after a packet loss, where the end of the expanded data does not
|
||||
* fit naturally with the new decoded data.
|
||||
*
|
||||
* Input:
|
||||
* - inst : NetEQ DSP instance
|
||||
* - scratchPtr : Pointer to scratch vector.
|
||||
* - decoded : Pointer to new decoded speech.
|
||||
* - len : Number of samples in pw16_decoded.
|
||||
*
|
||||
*
|
||||
* Output:
|
||||
* - inst : Updated user information
|
||||
* - outData : Pointer to a memory space where the output data
|
||||
* should be stored
|
||||
* - pw16_len : Number of samples written to pw16_outData
|
||||
*
|
||||
* Return value : 0 - Ok
|
||||
* <0 - Error
|
||||
*/
|
||||
|
||||
int WebRtcNetEQ_Merge(DSPInst_t *inst,
|
||||
#ifdef SCRATCH
|
||||
int16_t *pw16_scratchPtr,
|
||||
#endif
|
||||
int16_t *pw16_decoded, int len, int16_t *pw16_outData,
|
||||
int16_t *pw16_len);
|
||||
|
||||
/****************************************************************************
|
||||
* WebRtcNetEQ_Cng(...)
|
||||
*
|
||||
* This function produces CNG according to RFC 3389
|
||||
*
|
||||
* Input:
|
||||
* - inst : NetEQ DSP instance
|
||||
* - len : Number of samples to produce
|
||||
*
|
||||
* Output:
|
||||
* - pw16_outData : Output CNG
|
||||
*
|
||||
* Return value : 0 - Ok
|
||||
* <0 - Error
|
||||
*/
|
||||
|
||||
#ifdef NETEQ_CNG_CODEC
|
||||
/* Must compile NetEQ with CNG support to enable this function */
|
||||
|
||||
int WebRtcNetEQ_Cng(DSPInst_t *inst, int16_t *pw16_outData, int len);
|
||||
|
||||
#endif /* NETEQ_CNG_CODEC */
|
||||
|
||||
/****************************************************************************
|
||||
* WebRtcNetEQ_BGNUpdate(...)
|
||||
*
|
||||
* This function updates the background noise parameter estimates.
|
||||
*
|
||||
* Input:
|
||||
* - inst : NetEQ instance, where the speech history is stored.
|
||||
* - scratchPtr : Pointer to scratch vector.
|
||||
*
|
||||
* Output:
|
||||
* - inst : Updated information about the BGN characteristics.
|
||||
*
|
||||
* Return value : No return value
|
||||
*/
|
||||
|
||||
void WebRtcNetEQ_BGNUpdate(
|
||||
#ifdef SCRATCH
|
||||
DSPInst_t *inst, int16_t *pw16_scratchPtr
|
||||
#else
|
||||
DSPInst_t *inst
|
||||
#endif
|
||||
);
|
||||
|
||||
#ifdef NETEQ_VAD
|
||||
/* Functions used by post-decode VAD */
|
||||
|
||||
/****************************************************************************
|
||||
* WebRtcNetEQ_InitVAD(...)
|
||||
*
|
||||
* Initializes post-decode VAD instance.
|
||||
*
|
||||
* Input:
|
||||
* - VADinst : PostDecodeVAD instance
|
||||
* - fs : Initial sample rate
|
||||
*
|
||||
* Output:
|
||||
* - VADinst : Updated instance
|
||||
*
|
||||
* Return value : 0 - Ok
|
||||
* -1 - Error
|
||||
*/
|
||||
|
||||
int WebRtcNetEQ_InitVAD(PostDecodeVAD_t *VADInst, uint16_t fs);
|
||||
|
||||
/****************************************************************************
|
||||
* WebRtcNetEQ_SetVADModeInternal(...)
|
||||
*
|
||||
* Set the VAD mode in the VAD struct, and communicate it to the VAD instance
|
||||
* if it exists.
|
||||
*
|
||||
* Input:
|
||||
* - VADinst : PostDecodeVAD instance
|
||||
* - mode : Mode number passed on to the VAD function
|
||||
*
|
||||
* Output:
|
||||
* - VADinst : Updated instance
|
||||
*
|
||||
* Return value : 0 - Ok
|
||||
* -1 - Error
|
||||
*/
|
||||
|
||||
int WebRtcNetEQ_SetVADModeInternal(PostDecodeVAD_t *VADInst, int mode);
|
||||
|
||||
#endif /* NETEQ_VAD */
|
||||
|
||||
/****************************************************************************
|
||||
* WebRtcNetEQ_FlushSpeechBuffer(...)
|
||||
*
|
||||
* Flush the speech buffer.
|
||||
*
|
||||
* Input:
|
||||
* - inst : NetEq DSP instance
|
||||
*
|
||||
* Output:
|
||||
* - inst : Updated instance
|
||||
*
|
||||
* Return value : 0 - ok
|
||||
* : non-zero - error
|
||||
*/
|
||||
|
||||
int WebRtcNetEQ_FlushSpeechBuffer(DSPInst_t *inst);
|
||||
|
||||
#ifndef WEBRTC_NETEQ_40BITACC_TEST
|
||||
|
||||
#include "signal_processing_library.h"
|
||||
/* Map to regular SPL functions */
|
||||
#define WebRtcNetEQ_CrossCorr WebRtcSpl_CrossCorrelation
|
||||
#define WebRtcNetEQ_DotW16W16 WebRtcSpl_DotProductWithScale
|
||||
|
||||
#else /* WEBRTC_NETEQ_40BITACC_TEST defined */
|
||||
/* Run NetEQ with simulated 40-bit accumulator to run bit-exact to a DSP
|
||||
implementation where the main (splib and NetEQ) functions have been
|
||||
40-bit optimized. */
|
||||
|
||||
/* Map to special 40-bit optimized functions, defined below */
|
||||
#define WebRtcNetEQ_CrossCorr WebRtcNetEQ_40BitAccCrossCorr
|
||||
#define WebRtcNetEQ_DotW16W16 WebRtcNetEQ_40BitAccDotW16W16
|
||||
|
||||
/****************************************************************************
|
||||
* WebRtcNetEQ_40BitAccCrossCorr(...)
|
||||
*
|
||||
* Calculates the Cross correlation between two sequences seq1 and seq2. Seq1
|
||||
* is fixed and seq2 slides as the pointer is increased with step
|
||||
*
|
||||
* Input:
|
||||
* - seq1 : First sequence (fixed throughout the correlation)
|
||||
* - seq2 : Second sequence (slided step_seq2 for each
|
||||
* new correlation)
|
||||
* - dimSeq : Number of samples to use in the cross correlation.
|
||||
* Should be no larger than 1024 to avoid overflow.
|
||||
* - dimCrossCorr : Number of CrossCorrelations to calculate (start
|
||||
* position for seq2 is updated for each new one)
|
||||
* - rShift : Number of right shifts to use
|
||||
* - step_seq2 : How many (positive or negative) steps the seq2
|
||||
* pointer should be updated for each new cross
|
||||
* correlation value
|
||||
*
|
||||
* Output:
|
||||
* - crossCorr : The cross correlation in Q-rShift
|
||||
*/
|
||||
|
||||
void WebRtcNetEQ_40BitAccCrossCorr(int32_t *crossCorr, int16_t *seq1,
|
||||
int16_t *seq2, int16_t dimSeq,
|
||||
int16_t dimCrossCorr, int16_t rShift,
|
||||
int16_t step_seq2);
|
||||
|
||||
/****************************************************************************
|
||||
* WebRtcNetEQ_40BitAccDotW16W16(...)
|
||||
*
|
||||
* Calculates the dot product between two vectors (int16_t)
|
||||
*
|
||||
* Input:
|
||||
* - vector1 : Vector 1
|
||||
* - vector2 : Vector 2
|
||||
* - len : Number of samples in vector
|
||||
* Should be no larger than 1024 to avoid overflow.
|
||||
* - scaling : The number of right shifts (after multiplication)
|
||||
* required to avoid overflow in the dot product.
|
||||
* Return value : The dot product
|
||||
*/
|
||||
|
||||
int32_t WebRtcNetEQ_40BitAccDotW16W16(int16_t *vector1, int16_t *vector2,
|
||||
int len, int scaling);
|
||||
|
||||
#endif /* WEBRTC_NETEQ_40BITACC_TEST */
|
||||
|
||||
#endif /* DSP_H */
|
@ -1,120 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file contains some help functions that did not fit elsewhere.
|
||||
*/
|
||||
|
||||
#include "dsp_helpfunctions.h"
|
||||
|
||||
|
||||
int16_t WebRtcNetEQ_CalcFsMult(uint16_t fsHz)
|
||||
{
|
||||
switch (fsHz)
|
||||
{
|
||||
case 8000:
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
case 16000:
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
case 32000:
|
||||
{
|
||||
return 4;
|
||||
}
|
||||
case 48000:
|
||||
{
|
||||
return 6;
|
||||
}
|
||||
default:
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int WebRtcNetEQ_DownSampleTo4kHz(const int16_t *in, int inLen, uint16_t inFsHz,
|
||||
int16_t *out, int outLen, int compensateDelay)
|
||||
{
|
||||
int16_t *B; /* filter coefficients */
|
||||
int16_t Blen; /* number of coefficients */
|
||||
int16_t filterDelay; /* phase delay in samples */
|
||||
int16_t factor; /* conversion rate (inFsHz/8000) */
|
||||
int ok;
|
||||
|
||||
/* Set constants depending on frequency used */
|
||||
/* NOTE: The phase delay values are wrong compared to the true phase delay
|
||||
of the filters. However, the error is preserved (through the +1 term)
|
||||
for consistency. */
|
||||
switch (inFsHz)
|
||||
{
|
||||
case 8000:
|
||||
{
|
||||
Blen = 3;
|
||||
factor = 2;
|
||||
B = (int16_t*) WebRtcNetEQ_kDownsample8kHzTbl;
|
||||
filterDelay = 1 + 1;
|
||||
break;
|
||||
}
|
||||
#ifdef NETEQ_WIDEBAND
|
||||
case 16000:
|
||||
{
|
||||
Blen = 5;
|
||||
factor = 4;
|
||||
B = (int16_t*) WebRtcNetEQ_kDownsample16kHzTbl;
|
||||
filterDelay = 2 + 1;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
#ifdef NETEQ_32KHZ_WIDEBAND
|
||||
case 32000:
|
||||
{
|
||||
Blen = 7;
|
||||
factor = 8;
|
||||
B = (int16_t*) WebRtcNetEQ_kDownsample32kHzTbl;
|
||||
filterDelay = 3 + 1;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
#ifdef NETEQ_48KHZ_WIDEBAND
|
||||
case 48000:
|
||||
{
|
||||
Blen = 7;
|
||||
factor = 12;
|
||||
B = (int16_t*) WebRtcNetEQ_kDownsample48kHzTbl;
|
||||
filterDelay = 3 + 1;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
default:
|
||||
{
|
||||
/* unsupported or wrong sample rate */
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (!compensateDelay)
|
||||
{
|
||||
/* disregard delay compensation */
|
||||
filterDelay = 0;
|
||||
}
|
||||
|
||||
ok = WebRtcSpl_DownsampleFast((int16_t*) &in[Blen - 1],
|
||||
(int16_t) (inLen - (Blen - 1)), /* number of input samples */
|
||||
out, (int16_t) outLen, /* number of output samples to produce */
|
||||
B, Blen, factor, filterDelay); /* filter parameters */
|
||||
|
||||
return ok; /* return value is -1 if input signal is too short */
|
||||
|
||||
}
|
||||
|
@ -1,220 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Various help functions used by the DSP functions.
|
||||
*/
|
||||
|
||||
#ifndef DSP_HELPFUNCTIONS_H
|
||||
#define DSP_HELPFUNCTIONS_H
|
||||
|
||||
#include "typedefs.h"
|
||||
|
||||
#include "dsp.h"
|
||||
|
||||
/****************************************************************************
|
||||
* WebRtcNetEQ_Correlator(...)
|
||||
*
|
||||
* Calculate signal correlation.
|
||||
*
|
||||
* Input:
|
||||
* - inst : DSP instance
|
||||
* - data : Speech history to do expand from (older history in data[-4..-1])
|
||||
* - dataLen : Length of data
|
||||
*
|
||||
* Output:
|
||||
* - corrOut : CC of downsampled signal
|
||||
* - corrScale : Scale factor for correlation (-Qdomain)
|
||||
*
|
||||
* Return value : Length of correlated data
|
||||
*/
|
||||
|
||||
int16_t WebRtcNetEQ_Correlator(DSPInst_t *inst,
|
||||
#ifdef SCRATCH
|
||||
int16_t *pw16_scratchPtr,
|
||||
#endif
|
||||
int16_t *pw16_data, int16_t w16_dataLen,
|
||||
int16_t *pw16_corrOut,
|
||||
int16_t *pw16_corrScale);
|
||||
|
||||
/****************************************************************************
|
||||
* WebRtcNetEQ_PeakDetection(...)
|
||||
*
|
||||
* Peak detection with parabolic fit.
|
||||
*
|
||||
* Input:
|
||||
* - data : Data sequence for peak detection
|
||||
* - dataLen : Length of data
|
||||
* - nmbPeaks : Number of peaks to detect
|
||||
* - fs_mult : Sample rate multiplier
|
||||
*
|
||||
* Output:
|
||||
* - corrIndex : Index of the peak
|
||||
* - winner : Value of the peak
|
||||
*
|
||||
* Return value : 0 for ok
|
||||
*/
|
||||
|
||||
int16_t WebRtcNetEQ_PeakDetection(int16_t *pw16_data, int16_t w16_dataLen,
|
||||
int16_t w16_nmbPeaks, int16_t fs_mult,
|
||||
int16_t *pw16_corrIndex,
|
||||
int16_t *pw16_winners);
|
||||
|
||||
/****************************************************************************
|
||||
* WebRtcNetEQ_PrblFit(...)
|
||||
*
|
||||
* Three-point parbola fit.
|
||||
*
|
||||
* Input:
|
||||
* - 3pts : Three input samples
|
||||
* - fs_mult : Sample rate multiplier
|
||||
*
|
||||
* Output:
|
||||
* - Ind : Index of the peak
|
||||
* - outVal : Value of the peak
|
||||
*
|
||||
* Return value : 0 for ok
|
||||
*/
|
||||
|
||||
int16_t WebRtcNetEQ_PrblFit(int16_t *pw16_3pts, int16_t *pw16_Ind,
|
||||
int16_t *pw16_outVal, int16_t fs_mult);
|
||||
|
||||
/****************************************************************************
|
||||
* WebRtcNetEQ_MinDistortion(...)
|
||||
*
|
||||
* Find the lag that results in minimum distortion.
|
||||
*
|
||||
* Input:
|
||||
* - data : Start of speech to perform distortion on, second vector is assumed
|
||||
* to be data[-Lag]
|
||||
* - minLag : Start lag
|
||||
* - maxLag : End lag
|
||||
* - len : Length to correlate
|
||||
*
|
||||
* Output:
|
||||
* - dist : Distorion value
|
||||
*
|
||||
* Return value : Lag for minimum distortion
|
||||
*/
|
||||
|
||||
int16_t WebRtcNetEQ_MinDistortion(const int16_t *pw16_data,
|
||||
int16_t w16_minLag, int16_t w16_maxLag,
|
||||
int16_t len, int32_t *pw16_dist);
|
||||
|
||||
/****************************************************************************
|
||||
* WebRtcNetEQ_RandomVec(...)
|
||||
*
|
||||
* Generate random vector.
|
||||
*
|
||||
* Input:
|
||||
* - seed : Current seed (input/output)
|
||||
* - len : Number of samples to generate
|
||||
* - incVal : Jump step
|
||||
*
|
||||
* Output:
|
||||
* - randVec : Generated random vector
|
||||
*/
|
||||
|
||||
void WebRtcNetEQ_RandomVec(uint32_t *w32_seed, int16_t *pw16_randVec,
|
||||
int16_t w16_len, int16_t w16_incval);
|
||||
|
||||
/****************************************************************************
|
||||
* WebRtcNetEQ_MixVoiceUnvoice(...)
|
||||
*
|
||||
* Mix voiced and unvoiced signal.
|
||||
*
|
||||
* Input:
|
||||
* - voicedVec : Voiced input signal
|
||||
* - unvoicedVec : Unvoiced input signal
|
||||
* - current_vfraction : Current mixing factor
|
||||
* - vfraction_change : Mixing factor change per sample
|
||||
* - N : Number of samples
|
||||
*
|
||||
* Output:
|
||||
* - outData : Mixed signal
|
||||
*/
|
||||
|
||||
void WebRtcNetEQ_MixVoiceUnvoice(int16_t *pw16_outData, int16_t *pw16_voicedVec,
|
||||
int16_t *pw16_unvoicedVec,
|
||||
int16_t *w16_current_vfraction,
|
||||
int16_t w16_vfraction_change, int16_t N);
|
||||
|
||||
/****************************************************************************
|
||||
* WebRtcNetEQ_UnmuteSignal(...)
|
||||
*
|
||||
* Gradually reduce attenuation.
|
||||
*
|
||||
* Input:
|
||||
* - inVec : Input signal
|
||||
* - startMuteFact : Starting attenuation
|
||||
* - unmuteFact : Factor to "unmute" with (Q20)
|
||||
* - N : Number of samples
|
||||
*
|
||||
* Output:
|
||||
* - outVec : Output signal
|
||||
*/
|
||||
|
||||
void WebRtcNetEQ_UnmuteSignal(int16_t *pw16_inVec, int16_t *startMuteFact,
|
||||
int16_t *pw16_outVec, int16_t unmuteFact,
|
||||
int16_t N);
|
||||
|
||||
/****************************************************************************
|
||||
* WebRtcNetEQ_MuteSignal(...)
|
||||
*
|
||||
* Gradually increase attenuation.
|
||||
*
|
||||
* Input:
|
||||
* - inout : Input/output signal
|
||||
* - muteSlope : Slope of muting
|
||||
* - N : Number of samples
|
||||
*/
|
||||
|
||||
void WebRtcNetEQ_MuteSignal(int16_t *pw16_inout, int16_t muteSlope,
|
||||
int16_t N);
|
||||
|
||||
/****************************************************************************
|
||||
* WebRtcNetEQ_CalcFsMult(...)
|
||||
*
|
||||
* Calculate the sample rate divided by 8000.
|
||||
*
|
||||
* Input:
|
||||
* - fsHz : Sample rate in Hz in {8000, 16000, 32000, 48000}.
|
||||
*
|
||||
* Return value : fsHz/8000 for the valid values, 1 for other inputs
|
||||
*/
|
||||
|
||||
int16_t WebRtcNetEQ_CalcFsMult(uint16_t fsHz);
|
||||
|
||||
/****************************************************************************
|
||||
* WebRtcNetEQ_DownSampleTo4kHz(...)
|
||||
*
|
||||
* Lowpass filter and downsample a signal to 4 kHz sample rate.
|
||||
*
|
||||
* Input:
|
||||
* - in : Input signal samples.
|
||||
* - inLen : Number of input samples.
|
||||
* - inFsHz : Input sample rate in Hz.
|
||||
* - outLen : Desired number of samples in decimated signal.
|
||||
* - compensateDelay : If non-zero, compensate for the phase delay of
|
||||
* of the anti-alias filter.
|
||||
*
|
||||
* Output:
|
||||
* - out : Output signal samples.
|
||||
*
|
||||
* Return value : 0 - Ok
|
||||
* -1 - Error
|
||||
*
|
||||
*/
|
||||
|
||||
int WebRtcNetEQ_DownSampleTo4kHz(const int16_t *in, int inLen, uint16_t inFsHz,
|
||||
int16_t *out, int outLen, int compensateDelay);
|
||||
|
||||
#endif
|
||||
|
@ -1,232 +0,0 @@
|
||||
/*
|
||||
* 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 packet buffer for DTMF messages.
|
||||
*/
|
||||
|
||||
#include "dtmf_buffer.h"
|
||||
|
||||
#include "typedefs.h" /* to define endianness */
|
||||
#include "signal_processing_library.h"
|
||||
|
||||
#include "neteq_error_codes.h"
|
||||
|
||||
|
||||
#ifdef NETEQ_ATEVENT_DECODE
|
||||
|
||||
int16_t WebRtcNetEQ_DtmfRemoveEvent(dtmf_inst_t *DTMFdec_inst)
|
||||
{
|
||||
|
||||
int i;
|
||||
for (i = 0; i < 3; i++)
|
||||
{
|
||||
DTMFdec_inst->EventQueue[i] = DTMFdec_inst->EventQueue[i + 1];
|
||||
DTMFdec_inst->EventQueueVolume[i] = DTMFdec_inst->EventQueueVolume[i + 1];
|
||||
DTMFdec_inst->EventQueueEnded[i] = DTMFdec_inst->EventQueueEnded[i + 1];
|
||||
DTMFdec_inst->EventQueueStartTime[i] = DTMFdec_inst->EventQueueStartTime[i + 1];
|
||||
DTMFdec_inst->EventQueueEndTime[i] = DTMFdec_inst->EventQueueEndTime[i + 1];
|
||||
}
|
||||
DTMFdec_inst->EventBufferSize--;
|
||||
DTMFdec_inst->EventQueue[3] = -1;
|
||||
DTMFdec_inst->EventQueueVolume[3] = 0;
|
||||
DTMFdec_inst->EventQueueEnded[3] = 0;
|
||||
DTMFdec_inst->EventQueueStartTime[3] = 0;
|
||||
DTMFdec_inst->EventQueueEndTime[3] = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int16_t WebRtcNetEQ_DtmfDecoderInit(dtmf_inst_t *DTMFdec_inst, uint16_t fs,
|
||||
int16_t MaxPLCtime)
|
||||
{
|
||||
int i;
|
||||
if (((fs != 8000) && (fs != 16000) && (fs != 32000) && (fs != 48000)) || (MaxPLCtime < 0))
|
||||
{
|
||||
return DTMF_DEC_PARAMETER_ERROR;
|
||||
}
|
||||
if (fs == 8000)
|
||||
DTMFdec_inst->framelen = 80;
|
||||
else if (fs == 16000)
|
||||
DTMFdec_inst->framelen = 160;
|
||||
else if (fs == 32000)
|
||||
DTMFdec_inst->framelen = 320;
|
||||
else
|
||||
/* fs == 48000 */
|
||||
DTMFdec_inst->framelen = 480;
|
||||
|
||||
DTMFdec_inst->MaxPLCtime = MaxPLCtime;
|
||||
DTMFdec_inst->CurrentPLCtime = 0;
|
||||
DTMFdec_inst->EventBufferSize = 0;
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
DTMFdec_inst->EventQueue[i] = -1;
|
||||
DTMFdec_inst->EventQueueVolume[i] = 0;
|
||||
DTMFdec_inst->EventQueueEnded[i] = 0;
|
||||
DTMFdec_inst->EventQueueStartTime[i] = 0;
|
||||
DTMFdec_inst->EventQueueEndTime[i] = 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int16_t WebRtcNetEQ_DtmfInsertEvent(dtmf_inst_t *DTMFdec_inst,
|
||||
const int16_t *encoded, int16_t len,
|
||||
uint32_t timeStamp)
|
||||
{
|
||||
|
||||
int i;
|
||||
int16_t value;
|
||||
const int16_t *EventStart;
|
||||
int16_t endEvent;
|
||||
int16_t Volume;
|
||||
int16_t Duration;
|
||||
int16_t position = -1;
|
||||
|
||||
/* Extract event */
|
||||
if (len == 4)
|
||||
{
|
||||
EventStart = encoded;
|
||||
#ifdef WEBRTC_ARCH_BIG_ENDIAN
|
||||
value=((*EventStart)>>8);
|
||||
endEvent=((*EventStart)&0x80)>>7;
|
||||
Volume=((*EventStart)&0x3F);
|
||||
Duration=EventStart[1];
|
||||
#else
|
||||
value = ((*EventStart) & 0xFF);
|
||||
endEvent = ((*EventStart) & 0x8000) >> 15;
|
||||
Volume = ((*EventStart) & 0x3F00) >> 8;
|
||||
Duration = (((((uint16_t) EventStart[1]) >> 8) & 0xFF)
|
||||
| (((uint16_t) (EventStart[1] & 0xFF)) << 8));
|
||||
#endif
|
||||
/* Only events between 0-15 are supported (DTMF tones) */
|
||||
if ((value < 0) || (value > 15))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Discard all DTMF tones with really low volume (<-36dbm0) */
|
||||
if (Volume > 36)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*Are there any unended events of the same type? */
|
||||
for (i = 0; i < DTMFdec_inst->EventBufferSize; i++)
|
||||
{
|
||||
/* Going through the whole queue even when we have found a match will
|
||||
ensure that we add to the latest applicable event */
|
||||
if ((DTMFdec_inst->EventQueue[i] == value) && (!DTMFdec_inst->EventQueueEnded[i]
|
||||
|| endEvent)) position = i;
|
||||
}
|
||||
if (position > -1)
|
||||
{
|
||||
DTMFdec_inst->EventQueueVolume[position] = Volume;
|
||||
if ((timeStamp + Duration) > DTMFdec_inst->EventQueueEndTime[position]) DTMFdec_inst->EventQueueEndTime[position]
|
||||
= DTMFdec_inst->EventQueueStartTime[position] + Duration;
|
||||
if (endEvent) DTMFdec_inst->EventQueueEnded[position] = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (DTMFdec_inst->EventBufferSize == MAX_DTMF_QUEUE_SIZE)
|
||||
{ /* Buffer full */
|
||||
/* Remove one event */
|
||||
DTMFdec_inst->EventBufferSize--;
|
||||
}
|
||||
/* Store data in the instance on a new position*/
|
||||
DTMFdec_inst->EventQueue[DTMFdec_inst->EventBufferSize] = value;
|
||||
DTMFdec_inst->EventQueueVolume[DTMFdec_inst->EventBufferSize] = Volume;
|
||||
DTMFdec_inst->EventQueueEnded[DTMFdec_inst->EventBufferSize] = endEvent;
|
||||
DTMFdec_inst->EventQueueStartTime[DTMFdec_inst->EventBufferSize] = timeStamp;
|
||||
DTMFdec_inst->EventQueueEndTime[DTMFdec_inst->EventBufferSize] = timeStamp
|
||||
+ Duration;
|
||||
DTMFdec_inst->EventBufferSize++;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
return DTMF_INSERT_ERROR;
|
||||
}
|
||||
|
||||
int16_t WebRtcNetEQ_DtmfDecode(dtmf_inst_t *DTMFdec_inst, int16_t *event,
|
||||
int16_t *volume, uint32_t currTimeStamp)
|
||||
{
|
||||
|
||||
if (DTMFdec_inst->EventBufferSize < 1) return 0; /* No events to play */
|
||||
|
||||
/* We have events, is it time to play them? */
|
||||
if (currTimeStamp < DTMFdec_inst->EventQueueStartTime[0])
|
||||
{
|
||||
/*No, just return zero */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Continue on the event that is currently ongoing */
|
||||
*event = DTMFdec_inst->EventQueue[0];
|
||||
*volume = DTMFdec_inst->EventQueueVolume[0];
|
||||
|
||||
if (DTMFdec_inst->EventQueueEndTime[0] >= (currTimeStamp + DTMFdec_inst->framelen))
|
||||
{
|
||||
|
||||
/* Still at least framLen to play */
|
||||
|
||||
DTMFdec_inst->CurrentPLCtime = 0;
|
||||
if ((DTMFdec_inst->EventQueueEndTime[0] == (currTimeStamp + DTMFdec_inst->framelen))
|
||||
&& (DTMFdec_inst->EventQueueEnded[0]))
|
||||
{ /* We are done */
|
||||
/*Remove the event from Queue*/
|
||||
WebRtcNetEQ_DtmfRemoveEvent(DTMFdec_inst);
|
||||
}
|
||||
return DTMFdec_inst->framelen;
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((DTMFdec_inst->EventQueueEnded[0]) || (DTMFdec_inst->EventQueue[1] > -1))
|
||||
{
|
||||
/*
|
||||
* Less than frameLen to play and end of event or already received next event.
|
||||
* Give our a whole frame size of audio to simplify things.
|
||||
*/
|
||||
|
||||
/*Remove the event from Queue*/
|
||||
WebRtcNetEQ_DtmfRemoveEvent(DTMFdec_inst);
|
||||
DTMFdec_inst->CurrentPLCtime = 0;
|
||||
|
||||
return DTMFdec_inst->framelen;
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Less than frameLen to play and not end of event. */
|
||||
DTMFdec_inst->CurrentPLCtime = (int16_t) (currTimeStamp
|
||||
- DTMFdec_inst->EventQueueEndTime[0]);
|
||||
|
||||
if ((DTMFdec_inst->CurrentPLCtime > DTMFdec_inst->MaxPLCtime)
|
||||
|| (DTMFdec_inst->CurrentPLCtime < -DTMFdec_inst->MaxPLCtime))
|
||||
{
|
||||
/*Remove the event from queue*/
|
||||
WebRtcNetEQ_DtmfRemoveEvent(DTMFdec_inst);
|
||||
DTMFdec_inst->CurrentPLCtime = 0;
|
||||
}
|
||||
|
||||
/* If we have a new event that it's time to play */
|
||||
if ((DTMFdec_inst->EventQueue[1] > -1) && (DTMFdec_inst->EventQueueStartTime[1]
|
||||
>= (currTimeStamp + DTMFdec_inst->framelen)))
|
||||
{
|
||||
/*Remove the event from queue*/
|
||||
WebRtcNetEQ_DtmfRemoveEvent(DTMFdec_inst);
|
||||
DTMFdec_inst->CurrentPLCtime = 0;
|
||||
}
|
||||
|
||||
return DTMFdec_inst->framelen;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
@ -1,101 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Packet buffer for DTMF messages.
|
||||
*/
|
||||
|
||||
#ifndef DTMF_BUFFER_H
|
||||
#define DTMF_BUFFER_H
|
||||
|
||||
#include "typedefs.h"
|
||||
|
||||
#include "neteq_defines.h"
|
||||
|
||||
/* Include this code only if ATEVENT (DTMF) is defined in */
|
||||
#ifdef NETEQ_ATEVENT_DECODE
|
||||
|
||||
#define MAX_DTMF_QUEUE_SIZE 4
|
||||
|
||||
typedef struct dtmf_inst_t_
|
||||
{
|
||||
int16_t MaxPLCtime;
|
||||
int16_t CurrentPLCtime;
|
||||
int16_t EventQueue[MAX_DTMF_QUEUE_SIZE];
|
||||
int16_t EventQueueVolume[MAX_DTMF_QUEUE_SIZE];
|
||||
int16_t EventQueueEnded[MAX_DTMF_QUEUE_SIZE];
|
||||
uint32_t EventQueueStartTime[MAX_DTMF_QUEUE_SIZE];
|
||||
uint32_t EventQueueEndTime[MAX_DTMF_QUEUE_SIZE];
|
||||
int16_t EventBufferSize;
|
||||
int16_t framelen;
|
||||
} dtmf_inst_t;
|
||||
|
||||
/****************************************************************************
|
||||
* WebRtcNetEQ_DtmfDecoderInit(...)
|
||||
*
|
||||
* This function initializes a DTMF instance.
|
||||
*
|
||||
* Input:
|
||||
* - DTMF_decinst_t : DTMF instance
|
||||
* - fs : The sample rate used for the DTMF
|
||||
* - MaxPLCtime : Maximum length for a PLC before zeros should be inserted
|
||||
*
|
||||
* Return value : 0 - Ok
|
||||
* -1 - Error
|
||||
*/
|
||||
|
||||
int16_t WebRtcNetEQ_DtmfDecoderInit(dtmf_inst_t *DTMFdec_inst, uint16_t fs,
|
||||
int16_t MaxPLCtime);
|
||||
|
||||
/****************************************************************************
|
||||
* WebRtcNetEQ_DtmfInsertEvent(...)
|
||||
*
|
||||
* This function decodes a packet with DTMF frames.
|
||||
*
|
||||
* Input:
|
||||
* - DTMFdec_inst : DTMF instance
|
||||
* - encoded : Encoded DTMF frame(s)
|
||||
* - len : Bytes in encoded vector
|
||||
*
|
||||
*
|
||||
* Return value : 0 - Ok
|
||||
* -1 - Error
|
||||
*/
|
||||
|
||||
int16_t WebRtcNetEQ_DtmfInsertEvent(dtmf_inst_t *DTMFdec_inst,
|
||||
const int16_t *encoded, int16_t len,
|
||||
uint32_t timeStamp);
|
||||
|
||||
/****************************************************************************
|
||||
* WebRtcNetEQ_DtmfDecode(...)
|
||||
*
|
||||
* This function decodes a packet with DTMF frame(s). Output will be the
|
||||
* event that should be played for next 10 ms.
|
||||
*
|
||||
* Input:
|
||||
* - DTMFdec_inst : DTMF instance
|
||||
* - currTimeStamp : The current playout timestamp
|
||||
*
|
||||
* Output:
|
||||
* - event : Event number to be played
|
||||
* - volume : Event volume to be played
|
||||
*
|
||||
* Return value : >0 - There is a event to be played
|
||||
* 0 - No event to be played
|
||||
* -1 - Error
|
||||
*/
|
||||
|
||||
int16_t WebRtcNetEQ_DtmfDecode(dtmf_inst_t *DTMFdec_inst, int16_t *event,
|
||||
int16_t *volume, uint32_t currTimeStamp);
|
||||
|
||||
#endif /* NETEQ_ATEVENT_DECODE */
|
||||
|
||||
#endif /* DTMF_BUFFER_H */
|
||||
|
@ -1,367 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file contains the DTMF tone generator and its parameters.
|
||||
*
|
||||
* A sinusoid is generated using the recursive oscillator model
|
||||
*
|
||||
* y[n] = sin(w*n + phi) = 2*cos(w) * y[n-1] - y[n-2]
|
||||
* = a * y[n-1] - y[n-2]
|
||||
*
|
||||
* initialized with
|
||||
* y[-2] = 0
|
||||
* y[-1] = sin(w)
|
||||
*
|
||||
* A DTMF signal is a combination of two sinusoids, depending
|
||||
* on which event is sent (i.e, which key is pressed). The following
|
||||
* table maps each key (event codes in parentheses) into two tones:
|
||||
*
|
||||
* 1209 Hz 1336 Hz 1477 Hz 1633 Hz
|
||||
* 697 Hz 1 (ev. 1) 2 (ev. 2) 3 (ev. 3) A (ev. 12)
|
||||
* 770 Hz 4 (ev. 4) 5 (ev. 5) 6 (ev. 6) B (ev. 13)
|
||||
* 852 Hz 7 (ev. 7) 8 (ev. 8) 9 (ev. 9) C (ev. 14)
|
||||
* 941 Hz * (ev. 10) 0 (ev. 0) # (ev. 11) D (ev. 15)
|
||||
*
|
||||
* The two tones are added to form the DTMF signal.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "dtmf_tonegen.h"
|
||||
|
||||
#include "signal_processing_library.h"
|
||||
|
||||
#include "neteq_error_codes.h"
|
||||
|
||||
#ifdef NETEQ_ATEVENT_DECODE
|
||||
/* Must compile NetEQ with DTMF support to enable the functionality */
|
||||
|
||||
/*******************/
|
||||
/* Constant tables */
|
||||
/*******************/
|
||||
|
||||
/*
|
||||
* All tables corresponding to the oscillator model are organized so that
|
||||
* the coefficients for a specific frequency is found in the same position
|
||||
* in every table. The positions for the tones follow this layout:
|
||||
*
|
||||
* dummyVector[8] =
|
||||
* {
|
||||
* 697 Hz, 770 Hz, 852 Hz, 941 Hz,
|
||||
* 1209 Hz, 1336 Hz, 1477 Hz, 1633 Hz
|
||||
* };
|
||||
*/
|
||||
|
||||
/*
|
||||
* Tables for the constant a = 2*cos(w) = 2*cos(2*pi*f/fs)
|
||||
* in the oscillator model, for 8, 16, 32 and 48 kHz sample rate.
|
||||
* Table values in Q14.
|
||||
*/
|
||||
|
||||
const int16_t WebRtcNetEQ_dtfm_aTbl8Khz[8] =
|
||||
{
|
||||
27980, 26956, 25701, 24219,
|
||||
19073, 16325, 13085, 9315
|
||||
};
|
||||
|
||||
#ifdef NETEQ_WIDEBAND
|
||||
const int16_t WebRtcNetEQ_dtfm_aTbl16Khz[8]=
|
||||
{
|
||||
31548, 31281, 30951, 30556,
|
||||
29144, 28361, 27409, 26258
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifdef NETEQ_32KHZ_WIDEBAND
|
||||
const int16_t WebRtcNetEQ_dtfm_aTbl32Khz[8]=
|
||||
{
|
||||
32462, 32394, 32311, 32210,
|
||||
31849, 31647, 31400, 31098
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifdef NETEQ_48KHZ_WIDEBAND
|
||||
const int16_t WebRtcNetEQ_dtfm_aTbl48Khz[8]=
|
||||
{
|
||||
32632, 32602, 32564, 32520,
|
||||
32359, 32268, 32157, 32022
|
||||
};
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Initialization values y[-1] = sin(w) = sin(2*pi*f/fs), for 8, 16, 32 and 48 kHz sample rate.
|
||||
* Table values in Q14.
|
||||
*/
|
||||
|
||||
const int16_t WebRtcNetEQ_dtfm_yInitTab8Khz[8] =
|
||||
{
|
||||
8528, 9315, 10163, 11036,
|
||||
13323, 14206,15021, 15708
|
||||
};
|
||||
|
||||
#ifdef NETEQ_WIDEBAND
|
||||
const int16_t WebRtcNetEQ_dtfm_yInitTab16Khz[8]=
|
||||
{
|
||||
4429, 4879, 5380, 5918,
|
||||
7490, 8207, 8979, 9801
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifdef NETEQ_32KHZ_WIDEBAND
|
||||
const int16_t WebRtcNetEQ_dtfm_yInitTab32Khz[8]=
|
||||
{
|
||||
2235, 2468, 2728, 3010,
|
||||
3853, 4249, 4685, 5164
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifdef NETEQ_48KHZ_WIDEBAND
|
||||
const int16_t WebRtcNetEQ_dtfm_yInitTab48Khz[8]=
|
||||
{
|
||||
1493, 1649, 1823, 2013,
|
||||
2582, 2851, 3148, 3476
|
||||
};
|
||||
#endif
|
||||
|
||||
/* Volume in dBm0 from 0 to -63, where 0 is the first table entry.
|
||||
Everything below -36 is discarded, wherefore the table stops at -36.
|
||||
Table entries are in Q14.
|
||||
*/
|
||||
|
||||
const int16_t WebRtcNetEQ_dtfm_dBm0[37] = { 16141, 14386, 12821, 11427, 10184, 9077, 8090,
|
||||
7210, 6426, 5727, 5104, 4549, 4054, 3614,
|
||||
3221, 2870, 2558, 2280, 2032, 1811, 1614,
|
||||
1439, 1282, 1143, 1018, 908, 809, 721, 643,
|
||||
573, 510, 455, 405, 361, 322, 287, 256 };
|
||||
|
||||
/****************************************************************************
|
||||
* WebRtcNetEQ_DTMFGenerate(...)
|
||||
*
|
||||
* Generate 10 ms DTMF signal according to input parameters.
|
||||
*
|
||||
* Input:
|
||||
* - DTMFdecInst : DTMF instance
|
||||
* - value : DTMF event number (0-15)
|
||||
* - volume : Volume of generated signal (0-36)
|
||||
* Volume is given in negative dBm0, i.e., volume == 0
|
||||
* means 0 dBm0 while volume == 36 mean -36 dBm0.
|
||||
* - sampFreq : Sample rate in Hz
|
||||
*
|
||||
* Output:
|
||||
* - signal : Pointer to vector where DTMF signal is stored;
|
||||
* Vector must be at least sampFreq/100 samples long.
|
||||
* - DTMFdecInst : Updated DTMF instance
|
||||
*
|
||||
* Return value : >0 - Number of samples written to signal
|
||||
* : <0 - error
|
||||
*/
|
||||
|
||||
int16_t WebRtcNetEQ_DTMFGenerate(dtmf_tone_inst_t *DTMFdecInst, int16_t value,
|
||||
int16_t volume, int16_t *signal,
|
||||
uint16_t sampFreq, int16_t extFrameLen)
|
||||
{
|
||||
const int16_t *aTbl; /* pointer to a-coefficient table */
|
||||
const int16_t *yInitTable; /* pointer to initialization value table */
|
||||
int16_t a1 = 0; /* a-coefficient for first tone (low tone) */
|
||||
int16_t a2 = 0; /* a-coefficient for second tone (high tone) */
|
||||
int i;
|
||||
int frameLen; /* number of samples to generate */
|
||||
int lowIndex = 0; /* Default to avoid compiler warnings. */
|
||||
int highIndex = 4; /* Default to avoid compiler warnings. */
|
||||
int32_t tempVal;
|
||||
int16_t tempValLow;
|
||||
int16_t tempValHigh;
|
||||
|
||||
/* Sanity check for volume */
|
||||
if ((volume < 0) || (volume > 36))
|
||||
{
|
||||
return DTMF_DEC_PARAMETER_ERROR;
|
||||
}
|
||||
|
||||
/* Sanity check for extFrameLen */
|
||||
if (extFrameLen < -1)
|
||||
{
|
||||
return DTMF_DEC_PARAMETER_ERROR;
|
||||
}
|
||||
|
||||
/* Select oscillator coefficient tables based on sample rate */
|
||||
if (sampFreq == 8000)
|
||||
{
|
||||
aTbl = WebRtcNetEQ_dtfm_aTbl8Khz;
|
||||
yInitTable = WebRtcNetEQ_dtfm_yInitTab8Khz;
|
||||
frameLen = 80;
|
||||
#ifdef NETEQ_WIDEBAND
|
||||
}
|
||||
else if (sampFreq == 16000)
|
||||
{
|
||||
aTbl = WebRtcNetEQ_dtfm_aTbl16Khz;
|
||||
yInitTable = WebRtcNetEQ_dtfm_yInitTab16Khz;
|
||||
frameLen = 160;
|
||||
#endif
|
||||
#ifdef NETEQ_32KHZ_WIDEBAND
|
||||
}
|
||||
else if (sampFreq == 32000)
|
||||
{
|
||||
aTbl = WebRtcNetEQ_dtfm_aTbl32Khz;
|
||||
yInitTable = WebRtcNetEQ_dtfm_yInitTab32Khz;
|
||||
frameLen = 320;
|
||||
#endif
|
||||
#ifdef NETEQ_48KHZ_WIDEBAND
|
||||
}
|
||||
else if (sampFreq == 48000)
|
||||
{
|
||||
aTbl = WebRtcNetEQ_dtfm_aTbl48Khz;
|
||||
yInitTable = WebRtcNetEQ_dtfm_yInitTab48Khz;
|
||||
frameLen = 480;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
/* unsupported sample rate */
|
||||
return DTMF_GEN_UNKNOWN_SAMP_FREQ;
|
||||
}
|
||||
|
||||
if (extFrameLen >= 0)
|
||||
{
|
||||
frameLen = extFrameLen;
|
||||
}
|
||||
|
||||
/* select low frequency based on event value */
|
||||
switch (value)
|
||||
{
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
case 12: /* first row on keypad */
|
||||
{
|
||||
lowIndex = 0; /* low frequency: 697 Hz */
|
||||
break;
|
||||
}
|
||||
case 4:
|
||||
case 5:
|
||||
case 6:
|
||||
case 13: /* second row on keypad */
|
||||
{
|
||||
lowIndex = 1; /* low frequency: 770 Hz */
|
||||
break;
|
||||
}
|
||||
case 7:
|
||||
case 8:
|
||||
case 9:
|
||||
case 14: /* third row on keypad */
|
||||
{
|
||||
lowIndex = 2; /* low frequency: 852 Hz */
|
||||
break;
|
||||
}
|
||||
case 0:
|
||||
case 10:
|
||||
case 11:
|
||||
case 15: /* fourth row on keypad */
|
||||
{
|
||||
lowIndex = 3; /* low frequency: 941 Hz */
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
return DTMF_DEC_PARAMETER_ERROR;
|
||||
}
|
||||
} /* end switch */
|
||||
|
||||
/* select high frequency based on event value */
|
||||
switch (value)
|
||||
{
|
||||
case 1:
|
||||
case 4:
|
||||
case 7:
|
||||
case 10: /* first column on keypad */
|
||||
{
|
||||
highIndex = 4; /* high frequency: 1209 Hz */
|
||||
break;
|
||||
}
|
||||
case 2:
|
||||
case 5:
|
||||
case 8:
|
||||
case 0: /* second column on keypad */
|
||||
{
|
||||
highIndex = 5;/* high frequency: 1336 Hz */
|
||||
break;
|
||||
}
|
||||
case 3:
|
||||
case 6:
|
||||
case 9:
|
||||
case 11: /* third column on keypad */
|
||||
{
|
||||
highIndex = 6;/* high frequency: 1477 Hz */
|
||||
break;
|
||||
}
|
||||
case 12:
|
||||
case 13:
|
||||
case 14:
|
||||
case 15: /* fourth column on keypad (special) */
|
||||
{
|
||||
highIndex = 7;/* high frequency: 1633 Hz */
|
||||
break;
|
||||
}
|
||||
} /* end switch */
|
||||
|
||||
/* select coefficients based on results from switches above */
|
||||
a1 = aTbl[lowIndex]; /* coefficient for first (low) tone */
|
||||
a2 = aTbl[highIndex]; /* coefficient for second (high) tone */
|
||||
|
||||
if (DTMFdecInst->reinit)
|
||||
{
|
||||
/* set initial values for the recursive model */
|
||||
DTMFdecInst->oldOutputLow[0] = yInitTable[lowIndex];
|
||||
DTMFdecInst->oldOutputLow[1] = 0;
|
||||
DTMFdecInst->oldOutputHigh[0] = yInitTable[highIndex];
|
||||
DTMFdecInst->oldOutputHigh[1] = 0;
|
||||
|
||||
/* reset reinit flag */
|
||||
DTMFdecInst->reinit = 0;
|
||||
}
|
||||
|
||||
/* generate signal sample by sample */
|
||||
for (i = 0; i < frameLen; i++)
|
||||
{
|
||||
|
||||
/* Use rescursion formula y[n] = a*y[n-1] - y[n-2] */
|
||||
tempValLow
|
||||
= (int16_t) (((WEBRTC_SPL_MUL_16_16(a1, DTMFdecInst->oldOutputLow[1])
|
||||
+ 8192) >> 14) - DTMFdecInst->oldOutputLow[0]);
|
||||
tempValHigh
|
||||
= (int16_t) (((WEBRTC_SPL_MUL_16_16(a2, DTMFdecInst->oldOutputHigh[1])
|
||||
+ 8192) >> 14) - DTMFdecInst->oldOutputHigh[0]);
|
||||
|
||||
/* Update recursion memory */
|
||||
DTMFdecInst->oldOutputLow[0] = DTMFdecInst->oldOutputLow[1];
|
||||
DTMFdecInst->oldOutputLow[1] = tempValLow;
|
||||
DTMFdecInst->oldOutputHigh[0] = DTMFdecInst->oldOutputHigh[1];
|
||||
DTMFdecInst->oldOutputHigh[1] = tempValHigh;
|
||||
|
||||
/* scale high tone with 32768 (15 left shifts)
|
||||
and low tone with 23171 (3dB lower than high tone) */
|
||||
tempVal = WEBRTC_SPL_MUL_16_16(DTMF_AMP_LOW, tempValLow)
|
||||
+ WEBRTC_SPL_LSHIFT_W32((int32_t)tempValHigh, 15);
|
||||
|
||||
/* Norm the signal to Q14 (with proper rounding) */
|
||||
tempVal = (tempVal + 16384) >> 15;
|
||||
|
||||
/* Scale the signal to correct dbM0 value */
|
||||
signal[i] = (int16_t) WEBRTC_SPL_RSHIFT_W32(
|
||||
(WEBRTC_SPL_MUL_16_16(tempVal, WebRtcNetEQ_dtfm_dBm0[volume])
|
||||
+ 8192), 14); /* volume value is in Q14; use proper rounding */
|
||||
}
|
||||
|
||||
return frameLen;
|
||||
|
||||
}
|
||||
|
||||
#endif /* NETEQ_ATEVENT_DECODE */
|
||||
|
@ -1,73 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file contains the DTMF tone generator function.
|
||||
*/
|
||||
|
||||
#ifndef DTMF_TONEGEN_H
|
||||
#define DTMF_TONEGEN_H
|
||||
|
||||
#include "typedefs.h"
|
||||
|
||||
#include "neteq_defines.h"
|
||||
|
||||
#ifdef NETEQ_ATEVENT_DECODE
|
||||
/* Must compile NetEQ with DTMF support to enable the functionality */
|
||||
|
||||
#define DTMF_AMP_LOW 23171 /* 3 dB lower than the high frequency */
|
||||
|
||||
/* The DTMF generator struct (part of DSP main struct DSPInst_t) */
|
||||
typedef struct dtmf_tone_inst_t_
|
||||
{
|
||||
|
||||
int16_t reinit; /* non-zero if the oscillator model should
|
||||
be reinitialized for next event */
|
||||
int16_t oldOutputLow[2]; /* oscillator recursion history (low tone) */
|
||||
int16_t oldOutputHigh[2]; /* oscillator recursion history (high tone) */
|
||||
|
||||
int lastDtmfSample; /* index to the first non-DTMF sample in the
|
||||
speech history, if non-negative */
|
||||
}dtmf_tone_inst_t;
|
||||
|
||||
/****************************************************************************
|
||||
* WebRtcNetEQ_DTMFGenerate(...)
|
||||
*
|
||||
* Generate 10 ms DTMF signal according to input parameters.
|
||||
*
|
||||
* Input:
|
||||
* - DTMFdecInst : DTMF instance
|
||||
* - value : DTMF event number (0-15)
|
||||
* - volume : Volume of generated signal (0-36)
|
||||
* Volume is given in negative dBm0, i.e., volume == 0
|
||||
* means 0 dBm0 while volume == 36 mean -36 dBm0.
|
||||
* - sampFreq : Sample rate in Hz
|
||||
*
|
||||
* Output:
|
||||
* - signal : Pointer to vector where DTMF signal is stored;
|
||||
* Vector must be at least sampFreq/100 samples long.
|
||||
* - DTMFdecInst : Updated DTMF instance
|
||||
*
|
||||
* Return value : >0 - Number of samples written to signal
|
||||
* : <0 - Error
|
||||
*/
|
||||
|
||||
int16_t WebRtcNetEQ_DTMFGenerate(dtmf_tone_inst_t *DTMFdecInst,
|
||||
int16_t value,
|
||||
int16_t volume,
|
||||
int16_t *signal,
|
||||
uint16_t sampFreq,
|
||||
int16_t frameLen
|
||||
);
|
||||
|
||||
#endif /* NETEQ_ATEVENT_DECODE */
|
||||
|
||||
#endif /* DTMF_TONEGEN_H */
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,230 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This is the main API for NetEQ. Helper macros are located in webrtc_neteq_help_macros.h,
|
||||
* while some internal API functions are found in webrtc_neteq_internal.h.
|
||||
*/
|
||||
|
||||
#include "typedefs.h"
|
||||
|
||||
#ifndef WEBRTC_NETEQ_H
|
||||
#define WEBRTC_NETEQ_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
/**********************************************************
|
||||
* Definitions
|
||||
*/
|
||||
|
||||
enum WebRtcNetEQDecoder
|
||||
{
|
||||
kDecoderReservedStart,
|
||||
kDecoderPCMu,
|
||||
kDecoderPCMa,
|
||||
kDecoderPCMu_2ch,
|
||||
kDecoderPCMa_2ch,
|
||||
kDecoderILBC,
|
||||
kDecoderISAC,
|
||||
kDecoderISACswb,
|
||||
kDecoderISACfb,
|
||||
kDecoderPCM16B,
|
||||
kDecoderPCM16Bwb,
|
||||
kDecoderPCM16Bswb32kHz,
|
||||
kDecoderPCM16Bswb48kHz,
|
||||
kDecoderPCM16B_2ch,
|
||||
kDecoderPCM16Bwb_2ch,
|
||||
kDecoderPCM16Bswb32kHz_2ch,
|
||||
kDecoderG722,
|
||||
kDecoderG722_2ch,
|
||||
kDecoderRED,
|
||||
kDecoderAVT,
|
||||
kDecoderCNG,
|
||||
kDecoderArbitrary,
|
||||
kDecoderG729,
|
||||
kDecoderG729_1,
|
||||
kDecoderG726_16,
|
||||
kDecoderG726_24,
|
||||
kDecoderG726_32,
|
||||
kDecoderG726_40,
|
||||
kDecoderG722_1_16,
|
||||
kDecoderG722_1_24,
|
||||
kDecoderG722_1_32,
|
||||
kDecoderG722_1C_24,
|
||||
kDecoderG722_1C_32,
|
||||
kDecoderG722_1C_48,
|
||||
kDecoderOpus,
|
||||
kDecoderSPEEX_8,
|
||||
kDecoderSPEEX_16,
|
||||
kDecoderCELT_32,
|
||||
kDecoderCELT_32_2ch,
|
||||
kDecoderGSMFR,
|
||||
kDecoderAMR,
|
||||
kDecoderAMRWB,
|
||||
kDecoderReservedEnd
|
||||
};
|
||||
|
||||
enum WebRtcNetEQNetworkType
|
||||
{
|
||||
kUDPNormal,
|
||||
kUDPVideoSync,
|
||||
kTCPNormal,
|
||||
kTCPLargeJitter,
|
||||
kTCPXLargeJitter
|
||||
};
|
||||
|
||||
enum WebRtcNetEQOutputType
|
||||
{
|
||||
kOutputNormal,
|
||||
kOutputPLC,
|
||||
kOutputCNG,
|
||||
kOutputPLCtoCNG,
|
||||
kOutputVADPassive
|
||||
};
|
||||
|
||||
enum WebRtcNetEQPlayoutMode
|
||||
{
|
||||
kPlayoutOn, kPlayoutOff, kPlayoutFax, kPlayoutStreaming
|
||||
};
|
||||
|
||||
/* Available modes for background noise (inserted after long expands) */
|
||||
enum WebRtcNetEQBGNMode
|
||||
{
|
||||
kBGNOn, /* default "normal" behavior with eternal noise */
|
||||
kBGNFade, /* noise fades to zero after some time */
|
||||
kBGNOff
|
||||
/* background noise is always zero */
|
||||
};
|
||||
|
||||
/*************************************************
|
||||
* Definitions of decoder calls and the default
|
||||
* API function calls for each codec
|
||||
*/
|
||||
|
||||
typedef int16_t (*WebRtcNetEQ_FuncDecode)(void* state, int16_t* encoded,
|
||||
int16_t len, int16_t* decoded,
|
||||
int16_t* speechType);
|
||||
typedef int16_t (*WebRtcNetEQ_FuncDecodePLC)(void* state, int16_t* decoded,
|
||||
int16_t frames);
|
||||
typedef int16_t (*WebRtcNetEQ_FuncDecodeInit)(void* state);
|
||||
typedef int16_t (*WebRtcNetEQ_FuncAddLatePkt)(void* state, int16_t* encoded,
|
||||
int16_t len);
|
||||
typedef int16_t (*WebRtcNetEQ_FuncGetMDinfo)(void* state);
|
||||
typedef int16_t (*WebRtcNetEQ_FuncGetPitchInfo)(void* state, int16_t* encoded,
|
||||
int16_t* length);
|
||||
typedef int16_t (*WebRtcNetEQ_FuncUpdBWEst)(void* state, const uint16_t *encoded,
|
||||
int32_t packet_size,
|
||||
uint16_t rtp_seq_number,
|
||||
uint32_t send_ts,
|
||||
uint32_t arr_ts);
|
||||
typedef int (*WebRtcNetEQ_FuncDurationEst)(void* state, const uint8_t* payload,
|
||||
int payload_length_bytes);
|
||||
typedef int16_t (*WebRtcNetEQ_FuncGetErrorCode)(void* state);
|
||||
|
||||
/**********************************************************
|
||||
* Structures
|
||||
*/
|
||||
|
||||
typedef struct
|
||||
{
|
||||
enum WebRtcNetEQDecoder codec;
|
||||
int16_t payloadType;
|
||||
WebRtcNetEQ_FuncDecode funcDecode;
|
||||
WebRtcNetEQ_FuncDecode funcDecodeRCU;
|
||||
WebRtcNetEQ_FuncDecodePLC funcDecodePLC;
|
||||
WebRtcNetEQ_FuncDecodeInit funcDecodeInit;
|
||||
WebRtcNetEQ_FuncAddLatePkt funcAddLatePkt;
|
||||
WebRtcNetEQ_FuncGetMDinfo funcGetMDinfo;
|
||||
WebRtcNetEQ_FuncGetPitchInfo funcGetPitch;
|
||||
WebRtcNetEQ_FuncUpdBWEst funcUpdBWEst;
|
||||
WebRtcNetEQ_FuncDurationEst funcDurationEst;
|
||||
WebRtcNetEQ_FuncGetErrorCode funcGetErrorCode;
|
||||
void* codec_state;
|
||||
uint16_t codec_fs;
|
||||
} WebRtcNetEQ_CodecDef;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint16_t fraction_lost;
|
||||
uint32_t cum_lost;
|
||||
uint32_t ext_max;
|
||||
uint32_t jitter;
|
||||
} WebRtcNetEQ_RTCPStat;
|
||||
|
||||
/**********************************************************
|
||||
* NETEQ Functions
|
||||
*/
|
||||
|
||||
/* Info functions */
|
||||
|
||||
#define WEBRTC_NETEQ_MAX_ERROR_NAME 40
|
||||
int WebRtcNetEQ_GetErrorCode(void *inst);
|
||||
int WebRtcNetEQ_GetErrorName(int errorCode, char *errorName, int maxStrLen);
|
||||
|
||||
/* Instance memory assign functions */
|
||||
|
||||
int WebRtcNetEQ_AssignSize(int *sizeinbytes);
|
||||
int WebRtcNetEQ_Assign(void **inst, void *NETEQ_inst_Addr);
|
||||
int WebRtcNetEQ_GetRecommendedBufferSize(void *inst, const enum WebRtcNetEQDecoder *codec,
|
||||
int noOfCodecs, enum WebRtcNetEQNetworkType nwType,
|
||||
int *MaxNoOfPackets, int *sizeinbytes,
|
||||
int* per_packet_overhead_bytes);
|
||||
int WebRtcNetEQ_AssignBuffer(void *inst, int MaxNoOfPackets, void *NETEQ_Buffer_Addr,
|
||||
int sizeinbytes);
|
||||
|
||||
/* Init functions */
|
||||
|
||||
int WebRtcNetEQ_Init(void *inst, uint16_t fs);
|
||||
int WebRtcNetEQ_SetAVTPlayout(void *inst, int PlayoutAVTon);
|
||||
int WebRtcNetEQ_SetExtraDelay(void *inst, int DelayInMs);
|
||||
int WebRtcNetEQ_SetPlayoutMode(void *inst, enum WebRtcNetEQPlayoutMode playoutMode);
|
||||
int WebRtcNetEQ_SetBGNMode(void *inst, enum WebRtcNetEQBGNMode bgnMode);
|
||||
int WebRtcNetEQ_GetBGNMode(const void *inst, enum WebRtcNetEQBGNMode *bgnMode);
|
||||
|
||||
/* Codec Database functions */
|
||||
|
||||
int WebRtcNetEQ_CodecDbReset(void *inst);
|
||||
int WebRtcNetEQ_CodecDbAdd(void *inst, WebRtcNetEQ_CodecDef *codecInst);
|
||||
int WebRtcNetEQ_CodecDbRemove(void *inst, enum WebRtcNetEQDecoder codec);
|
||||
int WebRtcNetEQ_CodecDbGetSizeInfo(void *inst, int16_t *UsedEntries,
|
||||
int16_t *MaxEntries);
|
||||
int WebRtcNetEQ_CodecDbGetCodecInfo(void *inst, int16_t Entry,
|
||||
enum WebRtcNetEQDecoder *codec);
|
||||
|
||||
/* Real-time functions */
|
||||
|
||||
int WebRtcNetEQ_RecIn(void *inst, int16_t *p_w16datagramstart, int16_t w16_RTPlen,
|
||||
uint32_t uw32_timeRec);
|
||||
int WebRtcNetEQ_RecOut(void *inst, int16_t *pw16_outData, int16_t *pw16_len);
|
||||
int WebRtcNetEQ_GetRTCPStats(void *inst, WebRtcNetEQ_RTCPStat *RTCP_inst);
|
||||
int WebRtcNetEQ_GetRTCPStatsNoReset(void *inst, WebRtcNetEQ_RTCPStat *RTCP_inst);
|
||||
int WebRtcNetEQ_GetSpeechTimeStamp(void *inst, uint32_t *timestamp);
|
||||
int WebRtcNetEQ_DecodedRtpInfo(const void* inst,
|
||||
int* sequence_number,
|
||||
uint32_t* timestamp);
|
||||
int WebRtcNetEQ_GetSpeechOutputType(void *inst, enum WebRtcNetEQOutputType *outputType);
|
||||
|
||||
/* VQmon related functions */
|
||||
int WebRtcNetEQ_VQmonRecOutStatistics(void *inst, uint16_t *validVoiceDurationMs,
|
||||
uint16_t *concealedVoiceDurationMs,
|
||||
uint8_t *concealedVoiceFlags);
|
||||
int WebRtcNetEQ_VQmonGetConfiguration(void *inst, uint16_t *absMaxDelayMs,
|
||||
uint8_t *adaptationRate);
|
||||
int WebRtcNetEQ_VQmonGetRxStatistics(void *inst, uint16_t *avgDelayMs,
|
||||
uint16_t *maxDelayMs);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
@ -1,454 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file contains some helper macros that can be used when loading the
|
||||
* NetEQ codec database.
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_NETEQ_HELP_MACROS_H
|
||||
#define WEBRTC_NETEQ_HELP_MACROS_H
|
||||
|
||||
#ifndef NULL
|
||||
#define NULL 0
|
||||
#endif
|
||||
|
||||
/**********************************************************
|
||||
* Help macros for NetEQ initialization
|
||||
*/
|
||||
|
||||
#define SET_CODEC_PAR(inst,decoder,pt,state,fs) \
|
||||
inst.codec=decoder; \
|
||||
inst.payloadType=pt; \
|
||||
inst.codec_state=state; \
|
||||
inst.codec_fs=fs;
|
||||
|
||||
#define SET_PCMU_FUNCTIONS(inst) \
|
||||
inst.funcDecode=(WebRtcNetEQ_FuncDecode)WebRtcG711_DecodeU; \
|
||||
inst.funcDecodeRCU=NULL; \
|
||||
inst.funcDecodePLC=NULL; \
|
||||
inst.funcDecodeInit=NULL; \
|
||||
inst.funcAddLatePkt=NULL; \
|
||||
inst.funcGetMDinfo=NULL; \
|
||||
inst.funcGetPitch=NULL; \
|
||||
inst.funcUpdBWEst=NULL; \
|
||||
inst.funcDurationEst=WebRtcG711_DurationEst; \
|
||||
inst.funcGetErrorCode=NULL;
|
||||
|
||||
#define SET_PCMA_FUNCTIONS(inst) \
|
||||
inst.funcDecode=(WebRtcNetEQ_FuncDecode)WebRtcG711_DecodeA; \
|
||||
inst.funcDecodeRCU=NULL; \
|
||||
inst.funcDecodePLC=NULL; \
|
||||
inst.funcDecodeInit=NULL; \
|
||||
inst.funcAddLatePkt=NULL; \
|
||||
inst.funcGetMDinfo=NULL; \
|
||||
inst.funcGetPitch=NULL; \
|
||||
inst.funcUpdBWEst=NULL; \
|
||||
inst.funcDurationEst=WebRtcG711_DurationEst; \
|
||||
inst.funcGetErrorCode=NULL;
|
||||
|
||||
#define SET_ILBC_FUNCTIONS(inst) \
|
||||
inst.funcDecode=(WebRtcNetEQ_FuncDecode)WebRtcIlbcfix_Decode; \
|
||||
inst.funcDecodeRCU=NULL; \
|
||||
inst.funcDecodePLC=(WebRtcNetEQ_FuncDecodePLC)WebRtcIlbcfix_NetEqPlc; \
|
||||
inst.funcDecodeInit=(WebRtcNetEQ_FuncDecodeInit)WebRtcIlbcfix_Decoderinit30Ms; \
|
||||
inst.funcAddLatePkt=NULL; \
|
||||
inst.funcGetMDinfo=NULL; \
|
||||
inst.funcGetPitch=NULL; \
|
||||
inst.funcUpdBWEst=NULL; \
|
||||
inst.funcDurationEst=NULL; \
|
||||
inst.funcGetErrorCode=NULL;
|
||||
|
||||
#define SET_ISAC_FUNCTIONS(inst) \
|
||||
inst.funcDecode=(WebRtcNetEQ_FuncDecode)WebRtcIsac_Decode; \
|
||||
inst.funcDecodeRCU=(WebRtcNetEQ_FuncDecode)WebRtcIsac_DecodeRcu; \
|
||||
inst.funcDecodePLC=NULL; \
|
||||
inst.funcDecodeInit=(WebRtcNetEQ_FuncDecodeInit)WebRtcIsac_DecoderInit; \
|
||||
inst.funcAddLatePkt=NULL; \
|
||||
inst.funcGetMDinfo=NULL; \
|
||||
inst.funcGetPitch=NULL; \
|
||||
inst.funcUpdBWEst=(WebRtcNetEQ_FuncUpdBWEst)WebRtcIsac_UpdateBwEstimate; \
|
||||
inst.funcDurationEst=NULL; \
|
||||
inst.funcGetErrorCode=(WebRtcNetEQ_FuncGetErrorCode)WebRtcIsac_GetErrorCode;
|
||||
|
||||
#define SET_ISACfix_FUNCTIONS(inst) \
|
||||
inst.funcDecode=(WebRtcNetEQ_FuncDecode)WebRtcIsacfix_Decode; \
|
||||
inst.funcDecodeRCU=NULL; \
|
||||
inst.funcDecodePLC=NULL; \
|
||||
inst.funcDecodeInit=(WebRtcNetEQ_FuncDecodeInit)WebRtcIsacfix_DecoderInit; \
|
||||
inst.funcAddLatePkt=NULL; \
|
||||
inst.funcGetMDinfo=NULL; \
|
||||
inst.funcGetPitch=NULL; \
|
||||
inst.funcUpdBWEst=(WebRtcNetEQ_FuncUpdBWEst)WebRtcIsacfix_UpdateBwEstimate; \
|
||||
inst.funcDurationEst=NULL; \
|
||||
inst.funcGetErrorCode=(WebRtcNetEQ_FuncGetErrorCode)WebRtcIsacfix_GetErrorCode;
|
||||
|
||||
#define SET_ISACSWB_FUNCTIONS(inst) \
|
||||
inst.funcDecode=(WebRtcNetEQ_FuncDecode)WebRtcIsac_Decode; \
|
||||
inst.funcDecodeRCU=(WebRtcNetEQ_FuncDecode)WebRtcIsac_DecodeRcu; \
|
||||
inst.funcDecodePLC=NULL; \
|
||||
inst.funcDecodeInit=(WebRtcNetEQ_FuncDecodeInit)WebRtcIsac_DecoderInit; \
|
||||
inst.funcAddLatePkt=NULL; \
|
||||
inst.funcGetMDinfo=NULL; \
|
||||
inst.funcGetPitch=NULL; \
|
||||
inst.funcUpdBWEst=(WebRtcNetEQ_FuncUpdBWEst)WebRtcIsac_UpdateBwEstimate; \
|
||||
inst.funcDurationEst=NULL; \
|
||||
inst.funcGetErrorCode=(WebRtcNetEQ_FuncGetErrorCode)WebRtcIsac_GetErrorCode;
|
||||
|
||||
#define SET_ISACFB_FUNCTIONS(inst) \
|
||||
inst.funcDecode=(WebRtcNetEQ_FuncDecode)WebRtcIsac_Decode; \
|
||||
inst.funcDecodeRCU=(WebRtcNetEQ_FuncDecode)WebRtcIsac_DecodeRcu; \
|
||||
inst.funcDecodePLC=NULL; \
|
||||
inst.funcDecodeInit=(WebRtcNetEQ_FuncDecodeInit)WebRtcIsac_DecoderInit; \
|
||||
inst.funcAddLatePkt=NULL; \
|
||||
inst.funcGetMDinfo=NULL; \
|
||||
inst.funcGetPitch=NULL; \
|
||||
inst.funcUpdBWEst=(WebRtcNetEQ_FuncUpdBWEst)WebRtcIsac_UpdateBwEstimate; \
|
||||
inst.funcDurationEst=NULL; \
|
||||
inst.funcGetErrorCode=(WebRtcNetEQ_FuncGetErrorCode)WebRtcIsac_GetErrorCode;
|
||||
|
||||
#define SET_G729_FUNCTIONS(inst) \
|
||||
inst.funcDecode=(WebRtcNetEQ_FuncDecode)WebRtcG729_Decode; \
|
||||
inst.funcDecodeRCU=NULL; \
|
||||
inst.funcDecodePLC=(WebRtcNetEQ_FuncDecodePLC)WebRtcG729_DecodePlc; \
|
||||
inst.funcDecodeInit=(WebRtcNetEQ_FuncDecodeInit)WebRtcG729_DecoderInit; \
|
||||
inst.funcAddLatePkt=NULL; \
|
||||
inst.funcGetMDinfo=NULL; \
|
||||
inst.funcGetPitch=NULL; \
|
||||
inst.funcUpdBWEst=NULL; \
|
||||
inst.funcDurationEst=NULL; \
|
||||
inst.funcGetErrorCode=NULL;
|
||||
|
||||
#define SET_G729_1_FUNCTIONS(inst) \
|
||||
inst.funcDecode=(WebRtcNetEQ_FuncDecode)WebRtcG7291_Decode; \
|
||||
inst.funcDecodeRCU=NULL; \
|
||||
inst.funcDecodePLC=NULL; \
|
||||
inst.funcDecodeInit=(WebRtcNetEQ_FuncDecodeInit)WebRtcG7291_DecoderInit; \
|
||||
inst.funcAddLatePkt=NULL; \
|
||||
inst.funcGetMDinfo=NULL; \
|
||||
inst.funcGetPitch=NULL; \
|
||||
inst.funcUpdBWEst=(WebRtcNetEQ_FuncUpdBWEst)WebRtcG7291_DecodeBwe; \
|
||||
inst.funcDurationEst=NULL; \
|
||||
inst.funcGetErrorCode=NULL;
|
||||
|
||||
#define SET_PCM16B_FUNCTIONS(inst) \
|
||||
inst.funcDecode=(WebRtcNetEQ_FuncDecode)WebRtcPcm16b_DecodeW16; \
|
||||
inst.funcDecodeRCU=NULL; \
|
||||
inst.funcDecodePLC=NULL; \
|
||||
inst.funcDecodeInit=NULL; \
|
||||
inst.funcAddLatePkt=NULL; \
|
||||
inst.funcGetMDinfo=NULL; \
|
||||
inst.funcGetPitch=NULL; \
|
||||
inst.funcUpdBWEst=NULL; \
|
||||
inst.funcDurationEst=NULL; \
|
||||
inst.funcGetErrorCode=NULL;
|
||||
|
||||
#define SET_PCM16B_WB_FUNCTIONS(inst) \
|
||||
inst.funcDecode=(WebRtcNetEQ_FuncDecode)WebRtcPcm16b_DecodeW16; \
|
||||
inst.funcDecodeRCU=NULL; \
|
||||
inst.funcDecodePLC=NULL; \
|
||||
inst.funcDecodeInit=NULL; \
|
||||
inst.funcAddLatePkt=NULL; \
|
||||
inst.funcGetMDinfo=NULL; \
|
||||
inst.funcGetPitch=NULL; \
|
||||
inst.funcUpdBWEst=NULL; \
|
||||
inst.funcDurationEst=NULL; \
|
||||
inst.funcGetErrorCode=NULL;
|
||||
|
||||
#define SET_PCM16B_SWB32_FUNCTIONS(inst) \
|
||||
inst.funcDecode=(WebRtcNetEQ_FuncDecode)WebRtcPcm16b_DecodeW16; \
|
||||
inst.funcDecodeRCU=NULL; \
|
||||
inst.funcDecodePLC=NULL; \
|
||||
inst.funcDecodeInit=NULL; \
|
||||
inst.funcAddLatePkt=NULL; \
|
||||
inst.funcGetMDinfo=NULL; \
|
||||
inst.funcGetPitch=NULL; \
|
||||
inst.funcUpdBWEst=NULL; \
|
||||
inst.funcDurationEst=NULL; \
|
||||
inst.funcGetErrorCode=NULL;
|
||||
|
||||
#define SET_PCM16B_SWB48_FUNCTIONS(inst) \
|
||||
inst.funcDecode=(WebRtcNetEQ_FuncDecode)WebRtcPcm16b_DecodeW16; \
|
||||
inst.funcDecodeRCU=NULL; \
|
||||
inst.funcDecodePLC=NULL; \
|
||||
inst.funcDecodeInit=NULL; \
|
||||
inst.funcAddLatePkt=NULL; \
|
||||
inst.funcGetMDinfo=NULL; \
|
||||
inst.funcGetPitch=NULL; \
|
||||
inst.funcUpdBWEst=NULL; \
|
||||
inst.funcDurationEst=NULL; \
|
||||
inst.funcGetErrorCode=NULL;
|
||||
|
||||
#define SET_G722_FUNCTIONS(inst) \
|
||||
inst.funcDecode=(WebRtcNetEQ_FuncDecode)WebRtcG722_Decode; \
|
||||
inst.funcDecodeRCU=NULL; \
|
||||
inst.funcDecodePLC=NULL; \
|
||||
inst.funcDecodeInit=(WebRtcNetEQ_FuncDecodeInit)WebRtcG722_DecoderInit;\
|
||||
inst.funcAddLatePkt=NULL; \
|
||||
inst.funcGetMDinfo=NULL; \
|
||||
inst.funcGetPitch=NULL; \
|
||||
inst.funcUpdBWEst=NULL; \
|
||||
inst.funcDurationEst=NULL; \
|
||||
inst.funcGetErrorCode=NULL;
|
||||
|
||||
#define SET_G722_1_16_FUNCTIONS(inst) \
|
||||
inst.funcDecode=(WebRtcNetEQ_FuncDecode)WebRtcG7221_Decode16; \
|
||||
inst.funcDecodeRCU=NULL; \
|
||||
inst.funcDecodePLC=(WebRtcNetEQ_FuncDecodePLC)WebRtcG7221_DecodePlc16; \
|
||||
inst.funcDecodeInit=(WebRtcNetEQ_FuncDecodeInit)WebRtcG7221_DecoderInit16; \
|
||||
inst.funcAddLatePkt=NULL; \
|
||||
inst.funcGetMDinfo=NULL; \
|
||||
inst.funcGetPitch=NULL; \
|
||||
inst.funcUpdBWEst=NULL; \
|
||||
inst.funcDurationEst=NULL; \
|
||||
inst.funcGetErrorCode=NULL;
|
||||
|
||||
#define SET_G722_1_24_FUNCTIONS(inst) \
|
||||
inst.funcDecode=(WebRtcNetEQ_FuncDecode)WebRtcG7221_Decode24; \
|
||||
inst.funcDecodeRCU=NULL; \
|
||||
inst.funcDecodePLC=(WebRtcNetEQ_FuncDecodePLC)WebRtcG7221_DecodePlc24; \
|
||||
inst.funcDecodeInit=(WebRtcNetEQ_FuncDecodeInit)WebRtcG7221_DecoderInit24; \
|
||||
inst.funcAddLatePkt=NULL; \
|
||||
inst.funcGetMDinfo=NULL; \
|
||||
inst.funcGetPitch=NULL; \
|
||||
inst.funcUpdBWEst=NULL; \
|
||||
inst.funcDurationEst=NULL; \
|
||||
inst.funcGetErrorCode=NULL;
|
||||
|
||||
#define SET_G722_1_32_FUNCTIONS(inst) \
|
||||
inst.funcDecode=(WebRtcNetEQ_FuncDecode)WebRtcG7221_Decode32; \
|
||||
inst.funcDecodeRCU=NULL; \
|
||||
inst.funcDecodePLC=(WebRtcNetEQ_FuncDecodePLC)WebRtcG7221_DecodePlc32; \
|
||||
inst.funcDecodeInit=(WebRtcNetEQ_FuncDecodeInit)WebRtcG7221_DecoderInit32; \
|
||||
inst.funcAddLatePkt=NULL; \
|
||||
inst.funcGetMDinfo=NULL; \
|
||||
inst.funcGetPitch=NULL; \
|
||||
inst.funcUpdBWEst=NULL; \
|
||||
inst.funcDurationEst=NULL; \
|
||||
inst.funcGetErrorCode=NULL;
|
||||
|
||||
#define SET_G722_1C_24_FUNCTIONS(inst) \
|
||||
inst.funcDecode=(WebRtcNetEQ_FuncDecode)WebRtcG7221C_Decode24; \
|
||||
inst.funcDecodeRCU=NULL; \
|
||||
inst.funcDecodePLC=(WebRtcNetEQ_FuncDecodePLC)WebRtcG7221C_DecodePlc24; \
|
||||
inst.funcDecodeInit=(WebRtcNetEQ_FuncDecodeInit)WebRtcG7221C_DecoderInit24; \
|
||||
inst.funcAddLatePkt=NULL; \
|
||||
inst.funcGetMDinfo=NULL; \
|
||||
inst.funcGetPitch=NULL; \
|
||||
inst.funcUpdBWEst=NULL; \
|
||||
inst.funcDurationEst=NULL; \
|
||||
inst.funcGetErrorCode=NULL;
|
||||
|
||||
#define SET_G722_1C_32_FUNCTIONS(inst) \
|
||||
inst.funcDecode=(WebRtcNetEQ_FuncDecode)WebRtcG7221C_Decode32; \
|
||||
inst.funcDecodeRCU=NULL; \
|
||||
inst.funcDecodePLC=(WebRtcNetEQ_FuncDecodePLC)WebRtcG7221C_DecodePlc32; \
|
||||
inst.funcDecodeInit=(WebRtcNetEQ_FuncDecodeInit)WebRtcG7221C_DecoderInit32; \
|
||||
inst.funcAddLatePkt=NULL; \
|
||||
inst.funcGetMDinfo=NULL; \
|
||||
inst.funcGetPitch=NULL; \
|
||||
inst.funcUpdBWEst=NULL; \
|
||||
inst.funcDurationEst=NULL; \
|
||||
inst.funcGetErrorCode=NULL;
|
||||
|
||||
#define SET_G722_1C_48_FUNCTIONS(inst) \
|
||||
inst.funcDecode=(WebRtcNetEQ_FuncDecode)WebRtcG7221C_Decode48; \
|
||||
inst.funcDecodeRCU=NULL; \
|
||||
inst.funcDecodePLC=(WebRtcNetEQ_FuncDecodePLC)WebRtcG7221C_DecodePlc48; \
|
||||
inst.funcDecodeInit=(WebRtcNetEQ_FuncDecodeInit)WebRtcG7221C_DecoderInit48; \
|
||||
inst.funcAddLatePkt=NULL; \
|
||||
inst.funcGetMDinfo=NULL; \
|
||||
inst.funcGetPitch=NULL; \
|
||||
inst.funcUpdBWEst=NULL; \
|
||||
inst.funcDurationEst=NULL; \
|
||||
inst.funcGetErrorCode=NULL;
|
||||
|
||||
#define SET_AMR_FUNCTIONS(inst) \
|
||||
inst.funcDecode=(WebRtcNetEQ_FuncDecode)WebRtcAmr_Decode; \
|
||||
inst.funcDecodeRCU=NULL; \
|
||||
inst.funcDecodePLC=(WebRtcNetEQ_FuncDecodePLC)WebRtcAmr_DecodePlc; \
|
||||
inst.funcDecodeInit=(WebRtcNetEQ_FuncDecodeInit)WebRtcAmr_DecoderInit; \
|
||||
inst.funcAddLatePkt=NULL; \
|
||||
inst.funcGetMDinfo=NULL; \
|
||||
inst.funcGetPitch=NULL; \
|
||||
inst.funcUpdBWEst=NULL; \
|
||||
inst.funcDurationEst=NULL; \
|
||||
inst.funcGetErrorCode=NULL;
|
||||
|
||||
#define SET_AMRWB_FUNCTIONS(inst) \
|
||||
inst.funcDecode=(WebRtcNetEQ_FuncDecode)WebRtcAmrWb_Decode; \
|
||||
inst.funcDecodeRCU=NULL; \
|
||||
inst.funcDecodePLC=(WebRtcNetEQ_FuncDecodePLC)WebRtcAmrWb_DecodePlc; \
|
||||
inst.funcDecodeInit=(WebRtcNetEQ_FuncDecodeInit)WebRtcAmrWb_DecoderInit; \
|
||||
inst.funcAddLatePkt=NULL; \
|
||||
inst.funcGetMDinfo=NULL; \
|
||||
inst.funcGetPitch=NULL; \
|
||||
inst.funcUpdBWEst=NULL; \
|
||||
inst.funcDurationEst=NULL; \
|
||||
inst.funcGetErrorCode=NULL;
|
||||
|
||||
#define SET_GSMFR_FUNCTIONS(inst) \
|
||||
inst.funcDecode=(WebRtcNetEQ_FuncDecode)WebRtcGSMFR_Decode; \
|
||||
inst.funcDecodeRCU=NULL; \
|
||||
inst.funcDecodePLC=(WebRtcNetEQ_FuncDecodePLC)WebRtcGSMFR_DecodePlc; \
|
||||
inst.funcDecodeInit=(WebRtcNetEQ_FuncDecodeInit)WebRtcGSMFR_DecoderInit; \
|
||||
inst.funcAddLatePkt=NULL; \
|
||||
inst.funcGetMDinfo=NULL; \
|
||||
inst.funcGetPitch=NULL; \
|
||||
inst.funcUpdBWEst=NULL; \
|
||||
inst.funcDurationEst=NULL; \
|
||||
inst.funcGetErrorCode=NULL;
|
||||
|
||||
#define SET_G726_16_FUNCTIONS(inst) \
|
||||
inst.funcDecode=(WebRtcNetEQ_FuncDecode)WebRtcG726_decode16; \
|
||||
inst.funcDecodeRCU=NULL; \
|
||||
inst.funcDecodePLC=NULL; \
|
||||
inst.funcDecodeInit=(WebRtcNetEQ_FuncDecodeInit)WebRtcG726_decoderinit16; \
|
||||
inst.funcAddLatePkt=NULL; \
|
||||
inst.funcGetMDinfo=NULL; \
|
||||
inst.funcGetPitch=NULL; \
|
||||
inst.funcUpdBWEst=NULL; \
|
||||
inst.funcDurationEst=NULL; \
|
||||
inst.funcGetErrorCode=NULL;
|
||||
|
||||
#define SET_G726_24_FUNCTIONS(inst) \
|
||||
inst.funcDecode=(WebRtcNetEQ_FuncDecode)WebRtcG726_decode24; \
|
||||
inst.funcDecodeRCU=NULL; \
|
||||
inst.funcDecodePLC=NULL; \
|
||||
inst.funcDecodeInit=(WebRtcNetEQ_FuncDecodeInit)WebRtcG726_decoderinit24; \
|
||||
inst.funcAddLatePkt=NULL; \
|
||||
inst.funcGetMDinfo=NULL; \
|
||||
inst.funcGetPitch=NULL; \
|
||||
inst.funcUpdBWEst=NULL; \
|
||||
inst.funcDurationEst=NULL; \
|
||||
inst.funcGetErrorCode=NULL;
|
||||
|
||||
#define SET_G726_32_FUNCTIONS(inst) \
|
||||
inst.funcDecode=(WebRtcNetEQ_FuncDecode)WebRtcG726_decode32; \
|
||||
inst.funcDecodeRCU=NULL; \
|
||||
inst.funcDecodePLC=NULL; \
|
||||
inst.funcDecodeInit=(WebRtcNetEQ_FuncDecodeInit)WebRtcG726_decoderinit32; \
|
||||
inst.funcAddLatePkt=NULL; \
|
||||
inst.funcGetMDinfo=NULL; \
|
||||
inst.funcGetPitch=NULL; \
|
||||
inst.funcUpdBWEst=NULL; \
|
||||
inst.funcDurationEst=NULL; \
|
||||
inst.funcGetErrorCode=NULL;
|
||||
|
||||
#define SET_G726_40_FUNCTIONS(inst) \
|
||||
inst.funcDecode=(WebRtcNetEQ_FuncDecode)WebRtcG726_decode40; \
|
||||
inst.funcDecodeRCU=NULL; \
|
||||
inst.funcDecodePLC=NULL; \
|
||||
inst.funcDecodeInit=(WebRtcNetEQ_FuncDecodeInit)WebRtcG726_decoderinit40; \
|
||||
inst.funcAddLatePkt=NULL; \
|
||||
inst.funcGetMDinfo=NULL; \
|
||||
inst.funcGetPitch=NULL; \
|
||||
inst.funcUpdBWEst=NULL; \
|
||||
inst.funcDurationEst=NULL; \
|
||||
inst.funcGetErrorCode=NULL;
|
||||
|
||||
#define SET_OPUS_FUNCTIONS(inst) \
|
||||
inst.funcDecode=(WebRtcNetEQ_FuncDecode)WebRtcOpus_Decode; \
|
||||
inst.funcDecodeRCU=NULL; \
|
||||
inst.funcDecodePLC=(WebRtcNetEQ_FuncDecodePLC)WebRtcOpus_DecodePlcMaster; \
|
||||
inst.funcDecodeInit=(WebRtcNetEQ_FuncDecodeInit)WebRtcOpus_DecoderInit; \
|
||||
inst.funcAddLatePkt=NULL; \
|
||||
inst.funcGetMDinfo=NULL; \
|
||||
inst.funcGetPitch=NULL; \
|
||||
inst.funcUpdBWEst=NULL; \
|
||||
inst.funcDurationEst=(WebRtcNetEQ_FuncDurationEst)WebRtcOpus_DurationEst; \
|
||||
inst.funcGetErrorCode=NULL;
|
||||
|
||||
#define SET_OPUSSLAVE_FUNCTIONS(inst) \
|
||||
inst.funcDecode=(WebRtcNetEQ_FuncDecode)WebRtcOpus_DecodeSlave; \
|
||||
inst.funcDecodeRCU=NULL; \
|
||||
inst.funcDecodePLC=(WebRtcNetEQ_FuncDecodePLC)WebRtcOpus_DecodePlcSlave; \
|
||||
inst.funcDecodeInit=(WebRtcNetEQ_FuncDecodeInit)WebRtcOpus_DecoderInitSlave; \
|
||||
inst.funcAddLatePkt=NULL; \
|
||||
inst.funcGetMDinfo=NULL; \
|
||||
inst.funcGetPitch=NULL; \
|
||||
inst.funcUpdBWEst=NULL; \
|
||||
inst.funcDurationEst=(WebRtcNetEQ_FuncDurationEst)WebRtcOpus_DurationEst; \
|
||||
inst.funcGetErrorCode=NULL;
|
||||
|
||||
#define SET_SPEEX_FUNCTIONS(inst) \
|
||||
inst.funcDecode=(WebRtcNetEQ_FuncDecode)WebRtcSpeex_Decode; \
|
||||
inst.funcDecodeRCU=NULL; \
|
||||
inst.funcDecodePLC=(WebRtcNetEQ_FuncDecodePLC)WebRtcSpeex_DecodePlc; \
|
||||
inst.funcDecodeInit=(WebRtcNetEQ_FuncDecodeInit)WebRtcSpeex_DecoderInit; \
|
||||
inst.funcAddLatePkt=NULL; \
|
||||
inst.funcGetMDinfo=NULL; \
|
||||
inst.funcGetPitch=NULL; \
|
||||
inst.funcUpdBWEst=NULL; \
|
||||
inst.funcDurationEst=NULL; \
|
||||
inst.funcGetErrorCode=NULL;
|
||||
|
||||
#define SET_CELT_FUNCTIONS(inst) \
|
||||
inst.funcDecode=(WebRtcNetEQ_FuncDecode)WebRtcCelt_Decode; \
|
||||
inst.funcDecodeRCU=NULL; \
|
||||
inst.funcDecodePLC=NULL; \
|
||||
inst.funcDecodeInit=(WebRtcNetEQ_FuncDecodeInit)WebRtcCelt_DecoderInit; \
|
||||
inst.funcAddLatePkt=NULL; \
|
||||
inst.funcGetMDinfo=NULL; \
|
||||
inst.funcGetPitch=NULL; \
|
||||
inst.funcUpdBWEst=NULL; \
|
||||
inst.funcDurationEst=NULL; \
|
||||
inst.funcGetErrorCode=NULL;
|
||||
|
||||
#define SET_CELTSLAVE_FUNCTIONS(inst) \
|
||||
inst.funcDecode=(WebRtcNetEQ_FuncDecode)WebRtcCelt_DecodeSlave; \
|
||||
inst.funcDecodeRCU=NULL; \
|
||||
inst.funcDecodePLC=NULL; \
|
||||
inst.funcDecodeInit=(WebRtcNetEQ_FuncDecodeInit)WebRtcCelt_DecoderInitSlave; \
|
||||
inst.funcAddLatePkt=NULL; \
|
||||
inst.funcGetMDinfo=NULL; \
|
||||
inst.funcGetPitch=NULL; \
|
||||
inst.funcUpdBWEst=NULL; \
|
||||
inst.funcDurationEst=NULL; \
|
||||
inst.funcGetErrorCode=NULL;
|
||||
|
||||
#define SET_RED_FUNCTIONS(inst) \
|
||||
inst.funcDecode=NULL; \
|
||||
inst.funcDecodeRCU=NULL; \
|
||||
inst.funcDecodePLC=NULL; \
|
||||
inst.funcDecodeInit=NULL; \
|
||||
inst.funcAddLatePkt=NULL; \
|
||||
inst.funcGetMDinfo=NULL; \
|
||||
inst.funcGetPitch=NULL; \
|
||||
inst.funcUpdBWEst=NULL; \
|
||||
inst.funcDurationEst=NULL; \
|
||||
inst.funcGetErrorCode=NULL;
|
||||
|
||||
#define SET_AVT_FUNCTIONS(inst) \
|
||||
inst.funcDecode=NULL; \
|
||||
inst.funcDecodeRCU=NULL; \
|
||||
inst.funcDecodePLC=NULL; \
|
||||
inst.funcDecodeInit=NULL; \
|
||||
inst.funcAddLatePkt=NULL; \
|
||||
inst.funcGetMDinfo=NULL; \
|
||||
inst.funcGetPitch=NULL; \
|
||||
inst.funcUpdBWEst=NULL; \
|
||||
inst.funcDurationEst=NULL; \
|
||||
inst.funcGetErrorCode=NULL;
|
||||
|
||||
#define SET_CNG_FUNCTIONS(inst) \
|
||||
inst.funcDecode=NULL; \
|
||||
inst.funcDecodeRCU=NULL; \
|
||||
inst.funcDecodePLC=NULL; \
|
||||
inst.funcDecodeInit=NULL; \
|
||||
inst.funcAddLatePkt=NULL; \
|
||||
inst.funcGetMDinfo=NULL; \
|
||||
inst.funcGetPitch=NULL; \
|
||||
inst.funcUpdBWEst=NULL; \
|
||||
inst.funcDurationEst=NULL; \
|
||||
inst.funcGetErrorCode=NULL;
|
||||
|
||||
#endif /* WEBRTC_NETEQ_HELP_MACROS_H */
|
||||
|
@ -1,336 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file contains the internal API functions.
|
||||
*/
|
||||
|
||||
#include "typedefs.h"
|
||||
|
||||
#ifndef WEBRTC_NETEQ_INTERNAL_H
|
||||
#define WEBRTC_NETEQ_INTERNAL_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint8_t payloadType;
|
||||
uint16_t sequenceNumber;
|
||||
uint32_t timeStamp;
|
||||
uint32_t SSRC;
|
||||
uint8_t markerBit;
|
||||
} WebRtcNetEQ_RTPInfo;
|
||||
|
||||
/****************************************************************************
|
||||
* 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 uint8_t *payloadPtr, int16_t payloadLenBytes,
|
||||
uint32_t timeRec);
|
||||
|
||||
/****************************************************************************
|
||||
* WebRtcNetEQ_GetMasterSlaveInfoSize(...)
|
||||
*
|
||||
* Get size in bytes for master/slave struct msInfo used in
|
||||
* WebRtcNetEQ_RecOutMasterSlave.
|
||||
*
|
||||
* Return value : Struct size in bytes
|
||||
*
|
||||
*/
|
||||
|
||||
int WebRtcNetEQ_GetMasterSlaveInfoSize();
|
||||
|
||||
/****************************************************************************
|
||||
* WebRtcNetEQ_RecOutMasterSlave(...)
|
||||
*
|
||||
* RecOut function for running several NetEQ instances in master/slave mode.
|
||||
* One master can be used to control several slaves.
|
||||
* The MasterSlaveInfo struct must be allocated outside NetEQ.
|
||||
* Use function WebRtcNetEQ_GetMasterSlaveInfoSize to get the size needed.
|
||||
*
|
||||
* 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, int16_t *pw16_outData,
|
||||
int16_t *pw16_len, void *msInfo,
|
||||
int16_t isMaster);
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint16_t currentBufferSize; /* Current jitter buffer size in ms. */
|
||||
uint16_t preferredBufferSize; /* Preferred buffer size in ms. */
|
||||
uint16_t jitterPeaksFound; /* 1 if adding extra delay due to peaky
|
||||
* jitter; 0 otherwise. */
|
||||
uint16_t currentPacketLossRate; /* Loss rate (network + late) (Q14). */
|
||||
uint16_t currentDiscardRate; /* Late loss rate (Q14). */
|
||||
uint16_t currentExpandRate; /* Fraction (of original stream) of
|
||||
* synthesized speech inserted through
|
||||
* expansion (in Q14). */
|
||||
uint16_t currentPreemptiveRate; /* Fraction of data inserted through
|
||||
* pre-emptive expansion (in Q14). */
|
||||
uint16_t currentAccelerateRate; /* Fraction of data removed through
|
||||
* acceleration (in Q14). */
|
||||
int32_t clockDriftPPM; /* Average clock-drift in parts-per-
|
||||
* million (positive or negative). */
|
||||
int addedSamples; /* Number of zero samples added in off
|
||||
* mode */
|
||||
} WebRtcNetEQ_NetworkStatistics;
|
||||
|
||||
/*
|
||||
* Get the "in-call" statistics from NetEQ.
|
||||
* The statistics are reset after the query.
|
||||
*/
|
||||
int WebRtcNetEQ_GetNetworkStatistics(void *inst, WebRtcNetEQ_NetworkStatistics *stats);
|
||||
|
||||
|
||||
typedef struct {
|
||||
/* Samples removed from background noise only segments. */
|
||||
int accelerate_bgn_samples;
|
||||
|
||||
/* Samples removed from normal audio segments. */
|
||||
int accelerate_normal_samples;
|
||||
|
||||
/* Number of samples synthesized during background noise only segments. */
|
||||
int expand_bgn_sampels;
|
||||
|
||||
/* Number of samples synthesized during normal audio segments. */
|
||||
int expand_normal_samples;
|
||||
|
||||
/* Number of samples synthesized during background noise only segments,
|
||||
* in preemptive mode. */
|
||||
int preemptive_expand_bgn_samples;
|
||||
|
||||
/* Number of samples synthesized during normal audio segments, in preemptive
|
||||
* mode. */
|
||||
int preemptive_expand_normal_samples;
|
||||
|
||||
/* Number of samples synthesized during background noise only segments,
|
||||
* while merging. */
|
||||
int merge_expand_bgn_samples;
|
||||
|
||||
/* Number of samples synthesized during normal audio segments, while
|
||||
* merging. */
|
||||
int merge_expand_normal_samples;
|
||||
} WebRtcNetEQ_ProcessingActivity;
|
||||
|
||||
/*
|
||||
* Get the processing activities from NetEQ.
|
||||
* The statistics are reset after the query.
|
||||
* This API is meant to obtain processing activities in high granularity,
|
||||
* e.g. per RecOut() call.
|
||||
*/
|
||||
void WebRtcNetEQ_GetProcessingActivity(void* inst,
|
||||
WebRtcNetEQ_ProcessingActivity* stat);
|
||||
|
||||
/*
|
||||
* Get the raw waiting times for decoded frames. The function writes the last
|
||||
* recorded waiting times (from frame arrival to frame decoding) to the memory
|
||||
* pointed to by waitingTimeMs. The number of elements written is in the return
|
||||
* value. No more than maxLength elements are written. Statistics are reset on
|
||||
* each query.
|
||||
*/
|
||||
int WebRtcNetEQ_GetRawFrameWaitingTimes(void *inst,
|
||||
int max_length,
|
||||
int* waiting_times_ms);
|
||||
|
||||
/***********************************************/
|
||||
/* Functions for post-decode VAD functionality */
|
||||
/***********************************************/
|
||||
|
||||
/* NetEQ must be compiled with the flag NETEQ_VAD enabled for these functions to work. */
|
||||
|
||||
/*
|
||||
* VAD function pointer types
|
||||
*
|
||||
* These function pointers match the definitions of webrtc VAD functions WebRtcVad_Init,
|
||||
* WebRtcVad_set_mode and WebRtcVad_Process, respectively, all found in webrtc_vad.h.
|
||||
*/
|
||||
typedef int (*WebRtcNetEQ_VADInitFunction)(void *VAD_inst);
|
||||
typedef int (*WebRtcNetEQ_VADSetmodeFunction)(void *VAD_inst, int mode);
|
||||
typedef int (*WebRtcNetEQ_VADFunction)(void *VAD_inst, int fs,
|
||||
int16_t *frame, int frameLen);
|
||||
|
||||
/****************************************************************************
|
||||
* 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);
|
||||
|
||||
/****************************************************************************
|
||||
* 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 *NetEQ_inst, int mode);
|
||||
|
||||
/****************************************************************************
|
||||
* WebRtcNetEQ_RecOutNoDecode(...)
|
||||
*
|
||||
* Special RecOut that does not do any decoding.
|
||||
*
|
||||
* Input:
|
||||
* - inst : NetEQ instance
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* Return value : 0 - Ok
|
||||
* -1 - Error
|
||||
*/
|
||||
|
||||
int WebRtcNetEQ_RecOutNoDecode(void *inst, int16_t *pw16_outData,
|
||||
int16_t *pw16_len);
|
||||
|
||||
/****************************************************************************
|
||||
* WebRtcNetEQ_FlushBuffers(...)
|
||||
*
|
||||
* Flush packet and speech buffers. Does not reset codec database or
|
||||
* jitter statistics.
|
||||
*
|
||||
* Input:
|
||||
* - inst : NetEQ instance
|
||||
*
|
||||
* Output:
|
||||
* - inst : Updated NetEQ instance
|
||||
*
|
||||
* Return value : 0 - Ok
|
||||
* -1 - Error
|
||||
*/
|
||||
|
||||
int WebRtcNetEQ_FlushBuffers(void *inst);
|
||||
|
||||
/*****************************************************************************
|
||||
* void WebRtcNetEq_EnableAVSync(...)
|
||||
*
|
||||
* Enable AV-sync. If Enabled, NetEq will screen for sync payloads. For
|
||||
* each sync payload a silence frame is generated.
|
||||
*
|
||||
* Input:
|
||||
* - inst : NetEQ instance
|
||||
* - enable : non-zero to enable, otherwise disabled.
|
||||
*
|
||||
* Output:
|
||||
* - inst : Updated NetEQ instance
|
||||
*
|
||||
*/
|
||||
|
||||
void WebRtcNetEQ_EnableAVSync(void* inst, int enable);
|
||||
|
||||
/****************************************************************************
|
||||
* WebRtcNetEQ_RecInSyncRTP(...)
|
||||
*
|
||||
* Insert a sync packet with the given RTP specification.
|
||||
*
|
||||
* Input:
|
||||
* - inst : NetEQ instance
|
||||
* - rtpInfo : Pointer to RTP info
|
||||
* - receive_timestamp : Receive time (in timestamps of the used codec)
|
||||
*
|
||||
* Output:
|
||||
* - inst : Updated NetEQ instance
|
||||
*
|
||||
* Return value : if succeeded it returns the number of bytes pushed
|
||||
* in, otherwise returns -1.
|
||||
*/
|
||||
|
||||
int WebRtcNetEQ_RecInSyncRTP(void* inst,
|
||||
WebRtcNetEQ_RTPInfo* rtp_info,
|
||||
uint32_t receive_timestamp);
|
||||
|
||||
/*
|
||||
* Set a minimum latency for the jitter buffer. The overall delay is the max of
|
||||
* |minimum_delay_ms| and the latency that is internally computed based on the
|
||||
* inter-arrival times.
|
||||
*/
|
||||
int WebRtcNetEQ_SetMinimumDelay(void *inst, int minimum_delay_ms);
|
||||
|
||||
/*
|
||||
* Set a maximum latency for the jitter buffer. The overall delay is the min of
|
||||
* |maximum_delay_ms| and the latency that is internally computed based on the
|
||||
* inter-arrival times.
|
||||
*/
|
||||
int WebRtcNetEQ_SetMaximumDelay(void *inst, int maximum_delay_ms);
|
||||
|
||||
/*
|
||||
* Get the least required delay in milliseconds given inter-arrival times
|
||||
* and playout mode.
|
||||
*/
|
||||
int WebRtcNetEQ_GetRequiredDelayMs(const void* inst);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
@ -1,300 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* MCU struct and functions related to the MCU side operations.
|
||||
*/
|
||||
|
||||
#ifndef MCU_H
|
||||
#define MCU_H
|
||||
|
||||
#include "typedefs.h"
|
||||
|
||||
#include "codec_db.h"
|
||||
#include "rtcp.h"
|
||||
#include "packet_buffer.h"
|
||||
#include "buffer_stats.h"
|
||||
#include "neteq_statistics.h"
|
||||
|
||||
#ifdef NETEQ_ATEVENT_DECODE
|
||||
#include "dtmf_buffer.h"
|
||||
#endif
|
||||
|
||||
#define MAX_ONE_DESC 5 /* cannot do more than this many consecutive one-descriptor decodings */
|
||||
#define MAX_LOSS_REPORT_PERIOD 60 /* number of seconds between auto-reset */
|
||||
|
||||
enum TsScaling
|
||||
{
|
||||
kTSnoScaling = 0,
|
||||
kTSscalingTwo,
|
||||
kTSscalingTwoThirds,
|
||||
kTSscalingFourThirds
|
||||
};
|
||||
|
||||
enum { kLenWaitingTimes = 100 };
|
||||
|
||||
typedef struct
|
||||
{
|
||||
|
||||
int16_t current_Codec;
|
||||
int16_t current_Payload;
|
||||
uint32_t timeStamp; /* Next timestamp that should be played */
|
||||
int16_t millisecondsPerCall;
|
||||
uint16_t timestampsPerCall; /* Output chunk size */
|
||||
uint16_t fs;
|
||||
uint32_t ssrc; /* Current ssrc */
|
||||
int16_t new_codec;
|
||||
int16_t first_packet;
|
||||
|
||||
/* MCU/DSP Communication layer */
|
||||
int16_t *pw16_readAddress;
|
||||
int16_t *pw16_writeAddress;
|
||||
void *main_inst;
|
||||
|
||||
CodecDbInst_t codec_DB_inst; /* Information about all the codecs, i.e. which
|
||||
functions to use and which codpoints that
|
||||
have been assigned */
|
||||
SplitInfo_t PayloadSplit_inst; /* Information about how the current codec
|
||||
payload should be splitted */
|
||||
WebRtcNetEQ_RTCP_t RTCP_inst; /* RTCP statistics */
|
||||
PacketBuf_t PacketBuffer_inst; /* The packet buffer */
|
||||
BufstatsInst_t BufferStat_inst; /* Statistics that are used to make decision
|
||||
for what the DSP should perform */
|
||||
#ifdef NETEQ_ATEVENT_DECODE
|
||||
dtmf_inst_t DTMF_inst;
|
||||
#endif
|
||||
int NoOfExpandCalls;
|
||||
int16_t AVT_PlayoutOn;
|
||||
enum WebRtcNetEQPlayoutMode NetEqPlayoutMode;
|
||||
|
||||
int16_t one_desc; /* Number of times running on one desc */
|
||||
|
||||
uint32_t lostTS; /* Number of timestamps lost */
|
||||
uint32_t lastReportTS; /* Timestamp elapsed since last report was given */
|
||||
|
||||
int waiting_times[kLenWaitingTimes]; /* Waiting time statistics storage. */
|
||||
int len_waiting_times;
|
||||
int next_waiting_time_index;
|
||||
|
||||
uint32_t externalTS;
|
||||
uint32_t internalTS;
|
||||
int16_t TSscalingInitialized;
|
||||
enum TsScaling scalingFactor;
|
||||
|
||||
/* AV-sync enabled. In AV-sync NetEq screens packets for specific sync
|
||||
* packets. Sync packets are not decoded by a decoder but generate all-zero
|
||||
* signal with the same number of samples as previously decoded payload.
|
||||
* Also in AV-sync mode the sample-size of a sync payload is reported as
|
||||
* previous frame-size. */
|
||||
int av_sync;
|
||||
|
||||
#ifdef NETEQ_STEREO
|
||||
int usingStereo;
|
||||
#endif
|
||||
|
||||
/* The sequence number of the latest decoded RTP payload. */
|
||||
int decoded_packet_sequence_number;
|
||||
uint32_t decoded_packet_timestamp;
|
||||
} MCUInst_t;
|
||||
|
||||
/****************************************************************************
|
||||
* WebRtcNetEQ_McuReset(...)
|
||||
*
|
||||
* Reset the MCU instance.
|
||||
*
|
||||
* Input:
|
||||
* - inst : MCU instance
|
||||
*
|
||||
* Return value : 0 - Ok
|
||||
* <0 - Error
|
||||
*/
|
||||
int WebRtcNetEQ_McuReset(MCUInst_t *inst);
|
||||
|
||||
/****************************************************************************
|
||||
* WebRtcNetEQ_ResetMcuInCallStats(...)
|
||||
*
|
||||
* Reset MCU-side statistics variables for the in-call statistics.
|
||||
*
|
||||
* Input:
|
||||
* - inst : MCU instance
|
||||
*
|
||||
* Return value : 0 - Ok
|
||||
* <0 - Error
|
||||
*/
|
||||
int WebRtcNetEQ_ResetMcuInCallStats(MCUInst_t *inst);
|
||||
|
||||
/****************************************************************************
|
||||
* WebRtcNetEQ_ResetWaitingTimeStats(...)
|
||||
*
|
||||
* Reset waiting-time statistics.
|
||||
*
|
||||
* Input:
|
||||
* - inst : MCU instance.
|
||||
*
|
||||
* Return value : n/a
|
||||
*/
|
||||
void WebRtcNetEQ_ResetWaitingTimeStats(MCUInst_t *inst);
|
||||
|
||||
/****************************************************************************
|
||||
* WebRtcNetEQ_LogWaitingTime(...)
|
||||
*
|
||||
* Log waiting-time to the statistics.
|
||||
*
|
||||
* Input:
|
||||
* - inst : MCU instance.
|
||||
* - waiting_time : Waiting time in "RecOut calls" (i.e., 1 call = 10 ms).
|
||||
*
|
||||
* Return value : n/a
|
||||
*/
|
||||
void WebRtcNetEQ_StoreWaitingTime(MCUInst_t *inst, int waiting_time);
|
||||
|
||||
/****************************************************************************
|
||||
* WebRtcNetEQ_ResetMcuJitterStat(...)
|
||||
*
|
||||
* Reset MCU-side statistics variables for the post-call statistics.
|
||||
*
|
||||
* Input:
|
||||
* - inst : MCU instance
|
||||
*
|
||||
* Return value : 0 - Ok
|
||||
* <0 - Error
|
||||
*/
|
||||
int WebRtcNetEQ_ResetMcuJitterStat(MCUInst_t *inst);
|
||||
|
||||
/****************************************************************************
|
||||
* WebRtcNetEQ_McuAddressInit(...)
|
||||
*
|
||||
* Initializes MCU with read address and write address.
|
||||
*
|
||||
* Input:
|
||||
* - inst : MCU instance
|
||||
* - Data2McuAddress : Pointer to MCU address
|
||||
* - Data2DspAddress : Pointer to DSP address
|
||||
* - main_inst : Pointer to NetEQ main instance
|
||||
*
|
||||
* Return value : 0 - Ok
|
||||
* <0 - Error
|
||||
*/
|
||||
int WebRtcNetEQ_McuAddressInit(MCUInst_t *inst, void * Data2McuAddress,
|
||||
void * Data2DspAddress, void *main_inst);
|
||||
|
||||
/****************************************************************************
|
||||
* WebRtcNetEQ_McuSetFs(...)
|
||||
*
|
||||
* Initializes MCU with read address and write address.
|
||||
*
|
||||
* Input:
|
||||
* - inst : MCU instance
|
||||
* - fs_hz : Sample rate in Hz -- 8000, 16000, 32000, (48000)
|
||||
*
|
||||
* Return value : 0 - Ok
|
||||
* <0 - Error
|
||||
*/
|
||||
int WebRtcNetEQ_McuSetFs(MCUInst_t *inst, uint16_t fs_hz);
|
||||
|
||||
/****************************************************************************
|
||||
* WebRtcNetEQ_SignalMcu(...)
|
||||
*
|
||||
* Signal the MCU that data is available and ask for a RecOut decision.
|
||||
*
|
||||
* Input:
|
||||
* - inst : MCU instance
|
||||
* - av_sync : 1 if NetEQ is in AV-sync mode, otherwise 0.
|
||||
*
|
||||
* Return value : 0 - Ok
|
||||
* <0 - Error
|
||||
*/
|
||||
int WebRtcNetEQ_SignalMcu(MCUInst_t *inst);
|
||||
|
||||
/****************************************************************************
|
||||
* WebRtcNetEQ_RecInInternal(...)
|
||||
*
|
||||
* This function inserts a packet into the jitter buffer.
|
||||
*
|
||||
* Input:
|
||||
* - MCU_inst : MCU instance
|
||||
* - RTPpacket : The RTP packet, parsed into NetEQ's internal RTP struct
|
||||
* - uw32_timeRec : Time stamp for the arrival of the packet (not RTP timestamp)
|
||||
*
|
||||
* Return value : 0 - Ok
|
||||
* -1 - Error
|
||||
*/
|
||||
|
||||
int WebRtcNetEQ_RecInInternal(MCUInst_t *MCU_inst, RTPPacket_t *RTPpacket,
|
||||
uint32_t uw32_timeRec);
|
||||
|
||||
/****************************************************************************
|
||||
* WebRtcNetEQ_RecInInternal(...)
|
||||
*
|
||||
* Split the packet according to split_inst and inserts the parts into
|
||||
* Buffer_inst.
|
||||
*
|
||||
* Input:
|
||||
* - MCU_inst : MCU instance
|
||||
* - RTPpacket : The RTP packet, parsed into NetEQ's internal RTP struct
|
||||
* - uw32_timeRec : Time stamp for the arrival of the packet (not RTP timestamp)
|
||||
* - av_sync : indicates if AV-sync is enabled, 1 enabled,
|
||||
* 0 disabled.
|
||||
*
|
||||
* Return value : 0 - Ok
|
||||
* -1 - Error
|
||||
*/
|
||||
int WebRtcNetEQ_SplitAndInsertPayload(RTPPacket_t* packet,
|
||||
PacketBuf_t* Buffer_inst,
|
||||
SplitInfo_t* split_inst,
|
||||
int16_t* flushed,
|
||||
int av_sync);
|
||||
|
||||
/****************************************************************************
|
||||
* WebRtcNetEQ_GetTimestampScaling(...)
|
||||
*
|
||||
* Update information about timestamp scaling for a payload type
|
||||
* in MCU_inst->scalingFactor.
|
||||
*
|
||||
* Input:
|
||||
* - MCU_inst : MCU instance
|
||||
* - rtpPayloadType : RTP payload number
|
||||
*
|
||||
* Return value : 0 - Ok
|
||||
* -1 - Error
|
||||
*/
|
||||
|
||||
int WebRtcNetEQ_GetTimestampScaling(MCUInst_t *MCU_inst, int rtpPayloadType);
|
||||
|
||||
/****************************************************************************
|
||||
* WebRtcNetEQ_ScaleTimestampExternalToInternal(...)
|
||||
*
|
||||
* Convert from external to internal timestamp using current scaling info.
|
||||
*
|
||||
* Input:
|
||||
* - MCU_inst : MCU instance
|
||||
* - externalTS : External timestamp
|
||||
*
|
||||
* Return value : Internal timestamp
|
||||
*/
|
||||
|
||||
uint32_t WebRtcNetEQ_ScaleTimestampExternalToInternal(const MCUInst_t *MCU_inst,
|
||||
uint32_t externalTS);
|
||||
|
||||
/****************************************************************************
|
||||
* WebRtcNetEQ_ScaleTimestampInternalToExternal(...)
|
||||
*
|
||||
* Convert from external to internal timestamp using current scaling info.
|
||||
*
|
||||
* Input:
|
||||
* - MCU_inst : MCU instance
|
||||
* - externalTS : Internal timestamp
|
||||
*
|
||||
* Return value : External timestamp
|
||||
*/
|
||||
|
||||
uint32_t WebRtcNetEQ_ScaleTimestampInternalToExternal(const MCUInst_t *MCU_inst,
|
||||
uint32_t internalTS);
|
||||
#endif
|
@ -1,33 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "mcu.h"
|
||||
|
||||
#include <string.h> /* to define NULL */
|
||||
|
||||
/*
|
||||
* Initializes MCU with read address and write address
|
||||
*/
|
||||
int WebRtcNetEQ_McuAddressInit(MCUInst_t *inst, void * Data2McuAddress,
|
||||
void * Data2DspAddress, void *main_inst)
|
||||
{
|
||||
|
||||
inst->pw16_readAddress = (int16_t*) Data2McuAddress;
|
||||
inst->pw16_writeAddress = (int16_t*) Data2DspAddress;
|
||||
inst->main_inst = main_inst;
|
||||
|
||||
inst->millisecondsPerCall = 10;
|
||||
|
||||
/* Do expansions in the beginning */
|
||||
if (inst->pw16_writeAddress != NULL) inst->pw16_writeAddress[0] = DSP_INSTR_EXPAND;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
@ -1,45 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Communication between MCU and DSP sides.
|
||||
*/
|
||||
|
||||
#include "mcu_dsp_common.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
/* Initialize instances with read and write address */
|
||||
int WebRtcNetEQ_DSPinit(MainInst_t *inst)
|
||||
{
|
||||
int res = 0;
|
||||
|
||||
res |= WebRtcNetEQ_AddressInit(&inst->DSPinst, NULL, NULL, inst);
|
||||
res |= WebRtcNetEQ_McuAddressInit(&inst->MCUinst, NULL, NULL, inst);
|
||||
|
||||
return res;
|
||||
|
||||
}
|
||||
|
||||
/* The DSP side will call this function to interrupt the MCU side */
|
||||
int WebRtcNetEQ_DSP2MCUinterrupt(MainInst_t *inst, int16_t *pw16_shared_mem)
|
||||
{
|
||||
inst->MCUinst.pw16_readAddress = pw16_shared_mem;
|
||||
inst->MCUinst.pw16_writeAddress = pw16_shared_mem;
|
||||
return WebRtcNetEQ_SignalMcu(&inst->MCUinst);
|
||||
}
|
||||
|
||||
int WebRtcNetEQ_IsSyncPayload(const void* payload, int payload_len_bytes) {
|
||||
if (payload_len_bytes != SYNC_PAYLOAD_LEN_BYTES ||
|
||||
memcmp(payload, kSyncPayload, SYNC_PAYLOAD_LEN_BYTES) != 0) {
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
@ -1,69 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* The main NetEQ instance, which is where the DSP and MCU sides join.
|
||||
*/
|
||||
|
||||
#ifndef MCU_DSP_COMMON_H
|
||||
#define MCU_DSP_COMMON_H
|
||||
|
||||
#include "typedefs.h"
|
||||
|
||||
#include "dsp.h"
|
||||
#include "mcu.h"
|
||||
|
||||
/* Define size of shared memory area. */
|
||||
#if defined(NETEQ_48KHZ_WIDEBAND)
|
||||
#define SHARED_MEM_SIZE (6*640)
|
||||
#elif defined(NETEQ_32KHZ_WIDEBAND)
|
||||
#define SHARED_MEM_SIZE (4*640)
|
||||
#elif defined(NETEQ_WIDEBAND)
|
||||
#define SHARED_MEM_SIZE (2*640)
|
||||
#else
|
||||
#define SHARED_MEM_SIZE 640
|
||||
#endif
|
||||
|
||||
#define SYNC_PAYLOAD_LEN_BYTES 7
|
||||
static const uint8_t kSyncPayload[SYNC_PAYLOAD_LEN_BYTES] = {
|
||||
'a', 'v', 's', 'y', 'n', 'c', '\0' };
|
||||
|
||||
/* Struct to hold the NetEQ instance */
|
||||
typedef struct
|
||||
{
|
||||
DSPInst_t DSPinst; /* DSP part of the NetEQ instance */
|
||||
MCUInst_t MCUinst; /* MCU part of the NetEQ instance */
|
||||
int16_t ErrorCode; /* Store last error code */
|
||||
#ifdef NETEQ_STEREO
|
||||
int16_t masterSlave; /* 0 = not set, 1 = master, 2 = slave */
|
||||
#endif /* NETEQ_STEREO */
|
||||
} MainInst_t;
|
||||
|
||||
/* Struct used for communication between DSP and MCU sides of NetEQ */
|
||||
typedef struct
|
||||
{
|
||||
uint32_t playedOutTS; /* Timestamp position at end of DSP data */
|
||||
uint16_t samplesLeft; /* Number of samples stored */
|
||||
int16_t MD; /* Multiple description codec information */
|
||||
int16_t lastMode; /* Latest mode of NetEQ playout */
|
||||
int16_t frameLen; /* Frame length of previously decoded packet */
|
||||
} DSP2MCU_info_t;
|
||||
|
||||
/* Initialize instances with read and write address */
|
||||
int WebRtcNetEQ_DSPinit(MainInst_t *inst);
|
||||
|
||||
/* The DSP side will call this function to interrupt the MCU side */
|
||||
int WebRtcNetEQ_DSP2MCUinterrupt(MainInst_t *inst, int16_t *pw16_shared_mem);
|
||||
|
||||
/* Returns 1 if the given payload matches |kSyncPayload| payload, otherwise
|
||||
* 0 is returned. */
|
||||
int WebRtcNetEQ_IsSyncPayload(const void* payload, int payload_len_bytes);
|
||||
|
||||
#endif
|
@ -1,131 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Reset MCU side data.
|
||||
*/
|
||||
|
||||
#include "mcu.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "automode.h"
|
||||
|
||||
int WebRtcNetEQ_McuReset(MCUInst_t *inst)
|
||||
{
|
||||
|
||||
#ifdef NETEQ_ATEVENT_DECODE
|
||||
int ok;
|
||||
#endif
|
||||
|
||||
/* MCU/DSP Communication layer */
|
||||
inst->pw16_readAddress = NULL;
|
||||
inst->pw16_writeAddress = NULL;
|
||||
inst->main_inst = NULL;
|
||||
inst->one_desc = 0;
|
||||
inst->BufferStat_inst.Automode_inst.extraDelayMs = 0;
|
||||
inst->BufferStat_inst.Automode_inst.minimum_delay_ms = 0;
|
||||
inst->BufferStat_inst.Automode_inst.maximum_delay_ms = 10000;
|
||||
inst->NetEqPlayoutMode = kPlayoutOn;
|
||||
inst->av_sync = 0;
|
||||
|
||||
WebRtcNetEQ_DbReset(&inst->codec_DB_inst);
|
||||
memset(&inst->PayloadSplit_inst, 0, sizeof(SplitInfo_t));
|
||||
|
||||
/* Clear the Packet buffer and the pointer to memory storage */
|
||||
WebRtcNetEQ_PacketBufferFlush(&inst->PacketBuffer_inst);
|
||||
inst->PacketBuffer_inst.memorySizeW16 = 0;
|
||||
inst->PacketBuffer_inst.maxInsertPositions = 0;
|
||||
|
||||
/* Clear the decision and delay history */
|
||||
memset(&inst->BufferStat_inst, 0, sizeof(BufstatsInst_t));
|
||||
#ifdef NETEQ_ATEVENT_DECODE
|
||||
ok = WebRtcNetEQ_DtmfDecoderInit(&inst->DTMF_inst, 8000, 560);
|
||||
if (ok != 0)
|
||||
{
|
||||
return ok;
|
||||
}
|
||||
#endif
|
||||
inst->NoOfExpandCalls = 0;
|
||||
inst->current_Codec = -1;
|
||||
inst->current_Payload = -1;
|
||||
|
||||
inst->millisecondsPerCall = 10;
|
||||
inst->timestampsPerCall = inst->millisecondsPerCall * 8;
|
||||
inst->fs = 8000;
|
||||
inst->first_packet = 1;
|
||||
|
||||
WebRtcNetEQ_ResetMcuInCallStats(inst);
|
||||
|
||||
WebRtcNetEQ_ResetWaitingTimeStats(inst);
|
||||
|
||||
WebRtcNetEQ_ResetMcuJitterStat(inst);
|
||||
|
||||
WebRtcNetEQ_ResetAutomode(&(inst->BufferStat_inst.Automode_inst),
|
||||
inst->PacketBuffer_inst.maxInsertPositions);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Reset MCU-side statistics variables for the in-call statistics.
|
||||
*/
|
||||
|
||||
int WebRtcNetEQ_ResetMcuInCallStats(MCUInst_t *inst)
|
||||
{
|
||||
inst->lostTS = 0;
|
||||
inst->lastReportTS = 0;
|
||||
inst->PacketBuffer_inst.discardedPackets = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Reset waiting-time statistics.
|
||||
*/
|
||||
|
||||
void WebRtcNetEQ_ResetWaitingTimeStats(MCUInst_t *inst) {
|
||||
memset(inst->waiting_times, 0,
|
||||
kLenWaitingTimes * sizeof(inst->waiting_times[0]));
|
||||
inst->len_waiting_times = 0;
|
||||
inst->next_waiting_time_index = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Store waiting-time in the statistics.
|
||||
*/
|
||||
|
||||
void WebRtcNetEQ_StoreWaitingTime(MCUInst_t *inst, int waiting_time) {
|
||||
assert(inst->next_waiting_time_index < kLenWaitingTimes);
|
||||
inst->waiting_times[inst->next_waiting_time_index] = waiting_time;
|
||||
inst->next_waiting_time_index++;
|
||||
if (inst->next_waiting_time_index >= kLenWaitingTimes) {
|
||||
inst->next_waiting_time_index = 0;
|
||||
}
|
||||
if (inst->len_waiting_times < kLenWaitingTimes) {
|
||||
inst->len_waiting_times++;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Reset all MCU-side statistics variables for the post-call statistics.
|
||||
*/
|
||||
|
||||
int WebRtcNetEQ_ResetMcuJitterStat(MCUInst_t *inst)
|
||||
{
|
||||
inst->BufferStat_inst.Automode_inst.countIAT500ms = 0;
|
||||
inst->BufferStat_inst.Automode_inst.countIAT1000ms = 0;
|
||||
inst->BufferStat_inst.Automode_inst.countIAT2000ms = 0;
|
||||
inst->BufferStat_inst.Automode_inst.longestIATms = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -1,570 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This is the function to merge a new packet with expanded data after a packet loss.
|
||||
*/
|
||||
|
||||
#include "dsp.h"
|
||||
|
||||
#include "signal_processing_library.h"
|
||||
|
||||
#include "dsp_helpfunctions.h"
|
||||
#include "neteq_error_codes.h"
|
||||
|
||||
/****************************************************************************
|
||||
* WebRtcNetEQ_Merge(...)
|
||||
*
|
||||
* This function...
|
||||
*
|
||||
* Input:
|
||||
* - inst : NetEQ DSP instance
|
||||
* - scratchPtr : Pointer to scratch vector.
|
||||
* - decoded : Pointer to new decoded speech.
|
||||
* - len : Number of samples in pw16_decoded.
|
||||
*
|
||||
*
|
||||
* Output:
|
||||
* - inst : Updated user information
|
||||
* - outData : Pointer to a memory space where the output data
|
||||
* should be stored
|
||||
* - pw16_len : Number of samples written to pw16_outData
|
||||
*
|
||||
* Return value : 0 - Ok
|
||||
* <0 - Error
|
||||
*/
|
||||
|
||||
/* Scratch usage:
|
||||
|
||||
Type Name size startpos endpos
|
||||
int16_t pw16_expanded 210*fs/8000 0 209*fs/8000
|
||||
int16_t pw16_expandedLB 100 210*fs/8000 99+210*fs/8000
|
||||
int16_t pw16_decodedLB 40 100+210*fs/8000 139+210*fs/8000
|
||||
int32_t pw32_corr 2*60 140+210*fs/8000 260+210*fs/8000
|
||||
int16_t pw16_corrVec 68 210*fs/8000 67+210*fs/8000
|
||||
|
||||
[gap in scratch vector]
|
||||
|
||||
func WebRtcNetEQ_Expand 40+370*fs/8000 126*fs/8000 39+496*fs/8000
|
||||
|
||||
Total: 40+496*fs/8000
|
||||
*/
|
||||
|
||||
#define SCRATCH_pw16_expanded 0
|
||||
#if (defined(NETEQ_48KHZ_WIDEBAND))
|
||||
#define SCRATCH_pw16_expandedLB 1260
|
||||
#define SCRATCH_pw16_decodedLB 1360
|
||||
#define SCRATCH_pw32_corr 1400
|
||||
#define SCRATCH_pw16_corrVec 1260
|
||||
#define SCRATCH_NETEQ_EXPAND 756
|
||||
#elif (defined(NETEQ_32KHZ_WIDEBAND))
|
||||
#define SCRATCH_pw16_expandedLB 840
|
||||
#define SCRATCH_pw16_decodedLB 940
|
||||
#define SCRATCH_pw32_corr 980
|
||||
#define SCRATCH_pw16_corrVec 840
|
||||
#define SCRATCH_NETEQ_EXPAND 504
|
||||
#elif (defined(NETEQ_WIDEBAND))
|
||||
#define SCRATCH_pw16_expandedLB 420
|
||||
#define SCRATCH_pw16_decodedLB 520
|
||||
#define SCRATCH_pw32_corr 560
|
||||
#define SCRATCH_pw16_corrVec 420
|
||||
#define SCRATCH_NETEQ_EXPAND 252
|
||||
#else /* NB */
|
||||
#define SCRATCH_pw16_expandedLB 210
|
||||
#define SCRATCH_pw16_decodedLB 310
|
||||
#define SCRATCH_pw32_corr 350
|
||||
#define SCRATCH_pw16_corrVec 210
|
||||
#define SCRATCH_NETEQ_EXPAND 126
|
||||
#endif
|
||||
|
||||
int WebRtcNetEQ_Merge(DSPInst_t *inst,
|
||||
#ifdef SCRATCH
|
||||
int16_t *pw16_scratchPtr,
|
||||
#endif
|
||||
int16_t *pw16_decoded, int len, int16_t *pw16_outData,
|
||||
int16_t *pw16_len)
|
||||
{
|
||||
|
||||
int16_t fs_mult;
|
||||
int16_t fs_shift;
|
||||
int32_t w32_En_new_frame, w32_En_old_frame;
|
||||
int16_t w16_expmax, w16_newmax;
|
||||
int16_t w16_tmp, w16_tmp2;
|
||||
int32_t w32_tmp;
|
||||
#ifdef SCRATCH
|
||||
int16_t *pw16_expanded = pw16_scratchPtr + SCRATCH_pw16_expanded;
|
||||
int16_t *pw16_expandedLB = pw16_scratchPtr + SCRATCH_pw16_expandedLB;
|
||||
int16_t *pw16_decodedLB = pw16_scratchPtr + SCRATCH_pw16_decodedLB;
|
||||
int32_t *pw32_corr = (int32_t*) (pw16_scratchPtr + SCRATCH_pw32_corr);
|
||||
int16_t *pw16_corrVec = pw16_scratchPtr + SCRATCH_pw16_corrVec;
|
||||
#else
|
||||
int16_t pw16_expanded[(125+80+5)*FSMULT];
|
||||
int16_t pw16_expandedLB[100];
|
||||
int16_t pw16_decodedLB[40];
|
||||
int32_t pw32_corr[60];
|
||||
int16_t pw16_corrVec[4+60+4];
|
||||
#endif
|
||||
int16_t *pw16_corr = &pw16_corrVec[4];
|
||||
int16_t w16_stopPos = 0, w16_bestIndex, w16_interpLen;
|
||||
int16_t w16_bestVal; /* bestVal is dummy */
|
||||
int16_t w16_startfact, w16_inc;
|
||||
int16_t w16_expandedLen;
|
||||
int16_t w16_startPos;
|
||||
int16_t w16_expLen, w16_newLen = 0;
|
||||
int16_t *pw16_decodedOut;
|
||||
int16_t w16_muted;
|
||||
|
||||
int w16_decodedLen = len;
|
||||
|
||||
#ifdef NETEQ_STEREO
|
||||
MasterSlaveInfo *msInfo = inst->msInfo;
|
||||
#endif
|
||||
|
||||
fs_mult = WebRtcSpl_DivW32W16ResW16(inst->fs, 8000);
|
||||
fs_shift = 30 - WebRtcSpl_NormW32(fs_mult); /* Note that this is not "exact" for 48kHz */
|
||||
|
||||
/*************************************
|
||||
* Generate data to merge with
|
||||
*************************************/
|
||||
/*
|
||||
* Check how much data that is left since earlier
|
||||
* (at least there should be the overlap)...
|
||||
*/
|
||||
w16_startPos = inst->endPosition - inst->curPosition;
|
||||
/* Get one extra expansion to merge and overlap with */
|
||||
inst->ExpandInst.w16_stopMuting = 1;
|
||||
inst->ExpandInst.w16_lagsDirection = 1; /* make sure we get the "optimal" lag */
|
||||
inst->ExpandInst.w16_lagsPosition = -1; /* out of the 3 possible ones */
|
||||
w16_expandedLen = 0; /* Does not fill any function currently */
|
||||
|
||||
if (w16_startPos >= 210 * FSMULT)
|
||||
{
|
||||
/*
|
||||
* The number of samples available in the sync buffer is more than what fits in
|
||||
* pw16_expanded.Keep the first 210*FSMULT samples, but shift them towards the end of
|
||||
* the buffer. This is ok, since all of the buffer will be expand data anyway, so as
|
||||
* long as the beginning is left untouched, we're fine.
|
||||
*/
|
||||
|
||||
w16_tmp = w16_startPos - 210 * FSMULT; /* length difference */
|
||||
|
||||
WEBRTC_SPL_MEMMOVE_W16(&inst->speechBuffer[inst->curPosition+w16_tmp] ,
|
||||
&inst->speechBuffer[inst->curPosition], 210*FSMULT);
|
||||
|
||||
inst->curPosition += w16_tmp; /* move start position of sync buffer accordingly */
|
||||
w16_startPos = 210 * FSMULT; /* this is the truncated length */
|
||||
}
|
||||
|
||||
WebRtcNetEQ_Expand(inst,
|
||||
#ifdef SCRATCH
|
||||
pw16_scratchPtr + SCRATCH_NETEQ_EXPAND,
|
||||
#endif
|
||||
pw16_expanded, /* let Expand write to beginning of pw16_expanded to avoid overflow */
|
||||
&w16_newLen, 0);
|
||||
|
||||
/*
|
||||
* Now shift the data in pw16_expanded to where it belongs.
|
||||
* Truncate all that ends up outside the vector.
|
||||
*/
|
||||
|
||||
WEBRTC_SPL_MEMMOVE_W16(&pw16_expanded[w16_startPos], pw16_expanded,
|
||||
WEBRTC_SPL_MIN(w16_newLen,
|
||||
WEBRTC_SPL_MAX(210*FSMULT - w16_startPos, 0) ) );
|
||||
|
||||
inst->ExpandInst.w16_stopMuting = 0;
|
||||
|
||||
/* Copy what is left since earlier into the expanded vector */
|
||||
|
||||
WEBRTC_SPL_MEMCPY_W16(pw16_expanded, &inst->speechBuffer[inst->curPosition], w16_startPos);
|
||||
|
||||
/*
|
||||
* Do "ugly" copy and paste from the expanded in order to generate more data
|
||||
* to correlate (but not interpolate) with.
|
||||
*/
|
||||
w16_expandedLen = (120 + 80 + 2) * fs_mult;
|
||||
w16_expLen = w16_startPos + w16_newLen;
|
||||
|
||||
if (w16_expLen < w16_expandedLen)
|
||||
{
|
||||
while ((w16_expLen + w16_newLen) < w16_expandedLen)
|
||||
{
|
||||
WEBRTC_SPL_MEMCPY_W16(&pw16_expanded[w16_expLen], &pw16_expanded[w16_startPos],
|
||||
w16_newLen);
|
||||
w16_expLen += w16_newLen;
|
||||
}
|
||||
|
||||
/* Copy last part (fraction of a whole expansion) */
|
||||
|
||||
WEBRTC_SPL_MEMCPY_W16(&pw16_expanded[w16_expLen], &pw16_expanded[w16_startPos],
|
||||
(w16_expandedLen-w16_expLen));
|
||||
}
|
||||
w16_expLen = w16_expandedLen;
|
||||
|
||||
/* Adjust muting factor (main muting factor times expand muting factor) */
|
||||
inst->w16_muteFactor
|
||||
= (int16_t) WEBRTC_SPL_MUL_16_16_RSFT(inst->w16_muteFactor,
|
||||
inst->ExpandInst.w16_expandMuteFactor, 14);
|
||||
|
||||
/* Adjust muting factor if new vector is more or less of the BGN energy */
|
||||
len = WEBRTC_SPL_MIN(64*fs_mult, w16_decodedLen);
|
||||
w16_expmax = WebRtcSpl_MaxAbsValueW16(pw16_expanded, (int16_t) len);
|
||||
w16_newmax = WebRtcSpl_MaxAbsValueW16(pw16_decoded, (int16_t) len);
|
||||
|
||||
/* Calculate energy of old data */
|
||||
w16_tmp = 6 + fs_shift - WebRtcSpl_NormW32(WEBRTC_SPL_MUL_16_16(w16_expmax, w16_expmax));
|
||||
w16_tmp = WEBRTC_SPL_MAX(w16_tmp,0);
|
||||
w32_En_old_frame = WebRtcNetEQ_DotW16W16(pw16_expanded, pw16_expanded, len, w16_tmp);
|
||||
|
||||
/* Calculate energy of new data */
|
||||
w16_tmp2 = 6 + fs_shift - WebRtcSpl_NormW32(WEBRTC_SPL_MUL_16_16(w16_newmax, w16_newmax));
|
||||
w16_tmp2 = WEBRTC_SPL_MAX(w16_tmp2,0);
|
||||
w32_En_new_frame = WebRtcNetEQ_DotW16W16(pw16_decoded, pw16_decoded, len, w16_tmp2);
|
||||
|
||||
/* Align to same Q-domain */
|
||||
if (w16_tmp2 > w16_tmp)
|
||||
{
|
||||
w32_En_old_frame = WEBRTC_SPL_RSHIFT_W32(w32_En_old_frame, (w16_tmp2-w16_tmp));
|
||||
}
|
||||
else
|
||||
{
|
||||
w32_En_new_frame = WEBRTC_SPL_RSHIFT_W32(w32_En_new_frame, (w16_tmp-w16_tmp2));
|
||||
}
|
||||
|
||||
/* Calculate muting factor to use for new frame */
|
||||
if (w32_En_new_frame > w32_En_old_frame)
|
||||
{
|
||||
/* Normalize w32_En_new_frame to 14 bits */
|
||||
w16_tmp = WebRtcSpl_NormW32(w32_En_new_frame) - 17;
|
||||
w32_En_new_frame = WEBRTC_SPL_SHIFT_W32(w32_En_new_frame, w16_tmp);
|
||||
|
||||
/*
|
||||
* Put w32_En_old_frame in a domain 14 higher, so that
|
||||
* w32_En_old_frame/w32_En_new_frame is in Q14
|
||||
*/
|
||||
w16_tmp = w16_tmp + 14;
|
||||
w32_En_old_frame = WEBRTC_SPL_SHIFT_W32(w32_En_old_frame, w16_tmp);
|
||||
w16_tmp
|
||||
= WebRtcSpl_DivW32W16ResW16(w32_En_old_frame, (int16_t) w32_En_new_frame);
|
||||
/* Calculate sqrt(w32_En_old_frame/w32_En_new_frame) in Q14 */
|
||||
w16_muted = (int16_t) WebRtcSpl_SqrtFloor(
|
||||
WEBRTC_SPL_LSHIFT_W32((int32_t)w16_tmp,14));
|
||||
}
|
||||
else
|
||||
{
|
||||
w16_muted = 16384; /* Set = 1.0 when old frame has higher energy than new */
|
||||
}
|
||||
|
||||
/* Set the raise the continued muting factor w16_muted if w16_muteFactor is lower */
|
||||
if (w16_muted > inst->w16_muteFactor)
|
||||
{
|
||||
inst->w16_muteFactor = WEBRTC_SPL_MIN(w16_muted, 16384);
|
||||
}
|
||||
|
||||
#ifdef NETEQ_STEREO
|
||||
|
||||
/* Sanity for msInfo */
|
||||
if (msInfo == NULL)
|
||||
{
|
||||
/* this should not happen here */
|
||||
return MASTER_SLAVE_ERROR;
|
||||
}
|
||||
|
||||
/* do not downsample and calculate correlations for slave instance(s) */
|
||||
if ((msInfo->msMode == NETEQ_MASTER) || (msInfo->msMode == NETEQ_MONO))
|
||||
{
|
||||
#endif
|
||||
|
||||
/*********************************************
|
||||
* Downsample to 4kHz and find best overlap
|
||||
*********************************************/
|
||||
|
||||
/* Downsample to 4 kHz */
|
||||
if (inst->fs == 8000)
|
||||
{
|
||||
WebRtcSpl_DownsampleFast(&pw16_expanded[2], (int16_t) (w16_expandedLen - 2),
|
||||
pw16_expandedLB, (int16_t) (100),
|
||||
(int16_t*) WebRtcNetEQ_kDownsample8kHzTbl, (int16_t) 3,
|
||||
(int16_t) 2, (int16_t) 0);
|
||||
if (w16_decodedLen <= 80)
|
||||
{
|
||||
/* Not quite long enough, so we have to cheat a bit... */
|
||||
int16_t temp_len = w16_decodedLen - 2;
|
||||
w16_tmp = temp_len / 2;
|
||||
WebRtcSpl_DownsampleFast(&pw16_decoded[2], temp_len,
|
||||
pw16_decodedLB, w16_tmp,
|
||||
(int16_t*) WebRtcNetEQ_kDownsample8kHzTbl,
|
||||
(int16_t) 3, (int16_t) 2, (int16_t) 0);
|
||||
WebRtcSpl_MemSetW16(&pw16_decodedLB[w16_tmp], 0, (40 - w16_tmp));
|
||||
}
|
||||
else
|
||||
{
|
||||
WebRtcSpl_DownsampleFast(&pw16_decoded[2],
|
||||
(int16_t) (w16_decodedLen - 2), pw16_decodedLB,
|
||||
(int16_t) (40), (int16_t*) WebRtcNetEQ_kDownsample8kHzTbl,
|
||||
(int16_t) 3, (int16_t) 2, (int16_t) 0);
|
||||
}
|
||||
#ifdef NETEQ_WIDEBAND
|
||||
}
|
||||
else if (inst->fs==16000)
|
||||
{
|
||||
WebRtcSpl_DownsampleFast(
|
||||
&pw16_expanded[4], (int16_t)(w16_expandedLen-4),
|
||||
pw16_expandedLB, (int16_t)(100),
|
||||
(int16_t*)WebRtcNetEQ_kDownsample16kHzTbl, (int16_t)5,
|
||||
(int16_t)4, (int16_t)0);
|
||||
if (w16_decodedLen<=160)
|
||||
{
|
||||
/* Not quite long enough, so we have to cheat a bit... */
|
||||
int16_t temp_len = w16_decodedLen - 4;
|
||||
w16_tmp = temp_len / 4;
|
||||
WebRtcSpl_DownsampleFast(
|
||||
&pw16_decoded[4], temp_len,
|
||||
pw16_decodedLB, w16_tmp,
|
||||
(int16_t*)WebRtcNetEQ_kDownsample16kHzTbl, (int16_t)5,
|
||||
(int16_t)4, (int16_t)0);
|
||||
WebRtcSpl_MemSetW16(&pw16_decodedLB[w16_tmp], 0, (40-w16_tmp));
|
||||
}
|
||||
else
|
||||
{
|
||||
WebRtcSpl_DownsampleFast(
|
||||
&pw16_decoded[4], (int16_t)(w16_decodedLen-4),
|
||||
pw16_decodedLB, (int16_t)(40),
|
||||
(int16_t*)WebRtcNetEQ_kDownsample16kHzTbl, (int16_t)5,
|
||||
(int16_t)4, (int16_t)0);
|
||||
}
|
||||
#endif
|
||||
#ifdef NETEQ_32KHZ_WIDEBAND
|
||||
}
|
||||
else if (inst->fs==32000)
|
||||
{
|
||||
/*
|
||||
* TODO(hlundin) Why is the offset into pw16_expanded 6?
|
||||
*/
|
||||
WebRtcSpl_DownsampleFast(
|
||||
&pw16_expanded[6], (int16_t)(w16_expandedLen-6),
|
||||
pw16_expandedLB, (int16_t)(100),
|
||||
(int16_t*)WebRtcNetEQ_kDownsample32kHzTbl, (int16_t)7,
|
||||
(int16_t)8, (int16_t)0);
|
||||
if (w16_decodedLen<=320)
|
||||
{
|
||||
/* Not quite long enough, so we have to cheat a bit... */
|
||||
int16_t temp_len = w16_decodedLen - 6;
|
||||
w16_tmp = temp_len / 8;
|
||||
WebRtcSpl_DownsampleFast(
|
||||
&pw16_decoded[6], temp_len,
|
||||
pw16_decodedLB, w16_tmp,
|
||||
(int16_t*)WebRtcNetEQ_kDownsample32kHzTbl, (int16_t)7,
|
||||
(int16_t)8, (int16_t)0);
|
||||
WebRtcSpl_MemSetW16(&pw16_decodedLB[w16_tmp], 0, (40-w16_tmp));
|
||||
}
|
||||
else
|
||||
{
|
||||
WebRtcSpl_DownsampleFast(
|
||||
&pw16_decoded[6], (int16_t)(w16_decodedLen-6),
|
||||
pw16_decodedLB, (int16_t)(40),
|
||||
(int16_t*)WebRtcNetEQ_kDownsample32kHzTbl, (int16_t)7,
|
||||
(int16_t)8, (int16_t)0);
|
||||
}
|
||||
#endif
|
||||
#ifdef NETEQ_48KHZ_WIDEBAND
|
||||
}
|
||||
else /* if (inst->fs==48000) */
|
||||
{
|
||||
/*
|
||||
* TODO(hlundin) Why is the offset into pw16_expanded 6?
|
||||
*/
|
||||
WebRtcSpl_DownsampleFast(
|
||||
&pw16_expanded[6], (int16_t)(w16_expandedLen-6),
|
||||
pw16_expandedLB, (int16_t)(100),
|
||||
(int16_t*)WebRtcNetEQ_kDownsample48kHzTbl, (int16_t)7,
|
||||
(int16_t)12, (int16_t)0);
|
||||
if (w16_decodedLen<=320)
|
||||
{
|
||||
/* Not quite long enough, so we have to cheat a bit... */
|
||||
/*
|
||||
* TODO(hlundin): Is this correct? Downsampling is a factor 12
|
||||
* but w16_tmp = temp_len / 8.
|
||||
* (Was w16_tmp = ((w16_decodedLen-6)>>3) before re-write.)
|
||||
*/
|
||||
int16_t temp_len = w16_decodedLen - 6;
|
||||
w16_tmp = temp_len / 8;
|
||||
WebRtcSpl_DownsampleFast(
|
||||
&pw16_decoded[6], temp_len,
|
||||
pw16_decodedLB, w16_tmp,
|
||||
(int16_t*)WebRtcNetEQ_kDownsample48kHzTbl, (int16_t)7,
|
||||
(int16_t)12, (int16_t)0);
|
||||
WebRtcSpl_MemSetW16(&pw16_decodedLB[w16_tmp], 0, (40-w16_tmp));
|
||||
}
|
||||
else
|
||||
{
|
||||
WebRtcSpl_DownsampleFast(
|
||||
&pw16_decoded[6], (int16_t)(w16_decodedLen-6),
|
||||
pw16_decodedLB, (int16_t)(40),
|
||||
(int16_t*)WebRtcNetEQ_kDownsample48kHzTbl, (int16_t)7,
|
||||
(int16_t)12, (int16_t)0);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Calculate correlation without any normalization (40 samples) */
|
||||
w16_tmp = WebRtcSpl_DivW32W16ResW16((int32_t) inst->ExpandInst.w16_maxLag,
|
||||
(int16_t) (fs_mult * 2)) + 1;
|
||||
w16_stopPos = WEBRTC_SPL_MIN(60, w16_tmp);
|
||||
w32_tmp = WEBRTC_SPL_MUL_16_16(w16_expmax, w16_newmax);
|
||||
if (w32_tmp > 26843546)
|
||||
{
|
||||
w16_tmp = 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
w16_tmp = 0;
|
||||
}
|
||||
|
||||
WebRtcNetEQ_CrossCorr(pw32_corr, pw16_decodedLB, pw16_expandedLB, 40,
|
||||
(int16_t) w16_stopPos, w16_tmp, 1);
|
||||
|
||||
/* Normalize correlation to 14 bits and put in a int16_t vector */
|
||||
WebRtcSpl_MemSetW16(pw16_corrVec, 0, (4 + 60 + 4));
|
||||
w32_tmp = WebRtcSpl_MaxAbsValueW32(pw32_corr, w16_stopPos);
|
||||
w16_tmp = 17 - WebRtcSpl_NormW32(w32_tmp);
|
||||
w16_tmp = WEBRTC_SPL_MAX(0, w16_tmp);
|
||||
|
||||
WebRtcSpl_VectorBitShiftW32ToW16(pw16_corr, w16_stopPos, pw32_corr, w16_tmp);
|
||||
|
||||
/* Calculate allowed starting point for peak finding.
|
||||
The peak location bestIndex must fulfill two criteria:
|
||||
(1) w16_bestIndex+w16_decodedLen < inst->timestampsPerCall+inst->ExpandInst.w16_overlap
|
||||
(2) w16_bestIndex+w16_decodedLen < w16_startPos */
|
||||
w16_tmp = WEBRTC_SPL_MAX(0, WEBRTC_SPL_MAX(w16_startPos,
|
||||
inst->timestampsPerCall+inst->ExpandInst.w16_overlap) - w16_decodedLen);
|
||||
/* Downscale starting index to 4kHz domain */
|
||||
w16_tmp2 = WebRtcSpl_DivW32W16ResW16((int32_t) w16_tmp,
|
||||
(int16_t) (fs_mult << 1));
|
||||
|
||||
#ifdef NETEQ_STEREO
|
||||
} /* end if (msInfo->msMode != NETEQ_SLAVE) */
|
||||
|
||||
if ((msInfo->msMode == NETEQ_MASTER) || (msInfo->msMode == NETEQ_MONO))
|
||||
{
|
||||
/* This is master or mono instance; find peak */
|
||||
WebRtcNetEQ_PeakDetection(&pw16_corr[w16_tmp2], w16_stopPos, 1, fs_mult, &w16_bestIndex,
|
||||
&w16_bestVal);
|
||||
w16_bestIndex += w16_tmp; /* compensate for modified starting index */
|
||||
msInfo->bestIndex = w16_bestIndex;
|
||||
}
|
||||
else if (msInfo->msMode == NETEQ_SLAVE)
|
||||
{
|
||||
/* Get peak location from master instance */
|
||||
w16_bestIndex = msInfo->bestIndex;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Invalid mode */
|
||||
return MASTER_SLAVE_ERROR;
|
||||
}
|
||||
|
||||
#else /* NETEQ_STEREO */
|
||||
|
||||
/* Find peak */
|
||||
WebRtcNetEQ_PeakDetection(&pw16_corr[w16_tmp2], w16_stopPos, 1, fs_mult, &w16_bestIndex,
|
||||
&w16_bestVal);
|
||||
w16_bestIndex += w16_tmp; /* compensate for modified starting index */
|
||||
|
||||
#endif /* NETEQ_STEREO */
|
||||
|
||||
/*
|
||||
* Ensure that underrun does not occur for 10ms case => we have to get at least
|
||||
* 10ms + overlap . (This should never happen thanks to the above modification of
|
||||
* peak-finding starting point.)
|
||||
* */
|
||||
while ((w16_bestIndex + w16_decodedLen) < (inst->timestampsPerCall
|
||||
+ inst->ExpandInst.w16_overlap) || w16_bestIndex + w16_decodedLen < w16_startPos)
|
||||
{
|
||||
w16_bestIndex += w16_newLen; /* Jump one lag ahead */
|
||||
}
|
||||
pw16_decodedOut = pw16_outData + w16_bestIndex;
|
||||
|
||||
/* Mute the new decoded data if needed (and unmute it linearly) */
|
||||
w16_interpLen = WEBRTC_SPL_MIN(60*fs_mult,
|
||||
w16_expandedLen-w16_bestIndex); /* this is the overlapping part of pw16_expanded */
|
||||
w16_interpLen = WEBRTC_SPL_MIN(w16_interpLen, w16_decodedLen);
|
||||
w16_inc = WebRtcSpl_DivW32W16ResW16(4194,
|
||||
fs_mult); /* in Q20, 0.004 for NB and 0.002 for WB */
|
||||
if (inst->w16_muteFactor < 16384)
|
||||
{
|
||||
WebRtcNetEQ_UnmuteSignal(pw16_decoded, &inst->w16_muteFactor, pw16_decoded, w16_inc,
|
||||
(int16_t) w16_interpLen);
|
||||
WebRtcNetEQ_UnmuteSignal(&pw16_decoded[w16_interpLen], &inst->w16_muteFactor,
|
||||
&pw16_decodedOut[w16_interpLen], w16_inc,
|
||||
(int16_t) (w16_decodedLen - w16_interpLen));
|
||||
}
|
||||
else
|
||||
{
|
||||
/* No muting needed */
|
||||
|
||||
WEBRTC_SPL_MEMMOVE_W16(&pw16_decodedOut[w16_interpLen], &pw16_decoded[w16_interpLen],
|
||||
(w16_decodedLen-w16_interpLen));
|
||||
}
|
||||
|
||||
/* Do overlap and interpolate linearly */
|
||||
w16_inc = WebRtcSpl_DivW32W16ResW16(16384, (int16_t) (w16_interpLen + 1)); /* Q14 */
|
||||
w16_startfact = (16384 - w16_inc);
|
||||
WEBRTC_SPL_MEMMOVE_W16(pw16_outData, pw16_expanded, w16_bestIndex);
|
||||
WebRtcNetEQ_MixVoiceUnvoice(pw16_decodedOut, &pw16_expanded[w16_bestIndex], pw16_decoded,
|
||||
&w16_startfact, w16_inc, w16_interpLen);
|
||||
|
||||
inst->w16_mode = MODE_MERGE;
|
||||
inst->ExpandInst.w16_consecExp = 0; /* Last was not expand any more */
|
||||
|
||||
/* New added length (w16_startPos samples were borrowed) */
|
||||
*pw16_len = w16_bestIndex + w16_decodedLen - w16_startPos;
|
||||
|
||||
/* Update VQmon parameter */
|
||||
inst->w16_concealedTS += (*pw16_len - w16_decodedLen);
|
||||
inst->w16_concealedTS = WEBRTC_SPL_MAX(0, inst->w16_concealedTS);
|
||||
|
||||
/* Update in-call and post-call statistics */
|
||||
if (inst->ExpandInst.w16_expandMuteFactor == 0)
|
||||
{
|
||||
/* expansion generates noise only */
|
||||
inst->statInst.expandedNoiseSamples += (*pw16_len - w16_decodedLen);
|
||||
/* Short-term activity statistics. */
|
||||
inst->activity_stats.merge_expand_bgn_samples +=
|
||||
(*pw16_len - w16_decodedLen);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* expansion generates more than only noise */
|
||||
inst->statInst.expandedVoiceSamples += (*pw16_len - w16_decodedLen);
|
||||
/* Short-term activity statistics. */
|
||||
inst->activity_stats.merge_expand_normal_samples +=
|
||||
(*pw16_len - w16_decodedLen);
|
||||
}
|
||||
inst->statInst.expandLength += (*pw16_len - w16_decodedLen);
|
||||
|
||||
|
||||
/* Copy back the first part of the data to the speechHistory */
|
||||
|
||||
WEBRTC_SPL_MEMCPY_W16(&inst->speechBuffer[inst->curPosition], pw16_outData, w16_startPos);
|
||||
|
||||
|
||||
/* Move data to within outData */
|
||||
|
||||
WEBRTC_SPL_MEMMOVE_W16(pw16_outData, &pw16_outData[w16_startPos], (*pw16_len));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#undef SCRATCH_pw16_expanded
|
||||
#undef SCRATCH_pw16_expandedLB
|
||||
#undef SCRATCH_pw16_decodedLB
|
||||
#undef SCRATCH_pw32_corr
|
||||
#undef SCRATCH_pw16_corrVec
|
||||
#undef SCRATCH_NETEQ_EXPAND
|
@ -1,55 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Calculate best overlap fit according to distortion measure.
|
||||
*/
|
||||
|
||||
#include "dsp_helpfunctions.h"
|
||||
|
||||
#include "signal_processing_library.h"
|
||||
|
||||
int16_t WebRtcNetEQ_MinDistortion(const int16_t *pw16_data,
|
||||
int16_t w16_minLag, int16_t w16_maxLag,
|
||||
int16_t len, int32_t *pw16_dist)
|
||||
{
|
||||
int i, j;
|
||||
const int16_t *pw16_data1;
|
||||
const int16_t *pw16_data2;
|
||||
int32_t w32_diff;
|
||||
int32_t w32_sumdiff;
|
||||
int16_t bestIndex = -1;
|
||||
int32_t minDist = WEBRTC_SPL_WORD32_MAX;
|
||||
|
||||
for (i = w16_minLag; i <= w16_maxLag; i++)
|
||||
{
|
||||
w32_sumdiff = 0;
|
||||
pw16_data1 = pw16_data;
|
||||
pw16_data2 = pw16_data - i;
|
||||
|
||||
for (j = 0; j < len; j++)
|
||||
{
|
||||
w32_diff = pw16_data1[j] - pw16_data2[j];
|
||||
w32_sumdiff += WEBRTC_SPL_ABS_W32(w32_diff);
|
||||
}
|
||||
|
||||
/* Compare with previous minimum */
|
||||
if (w32_sumdiff < minDist)
|
||||
{
|
||||
minDist = w32_sumdiff;
|
||||
bestIndex = i;
|
||||
}
|
||||
}
|
||||
|
||||
*pw16_dist = minDist;
|
||||
|
||||
return bestIndex;
|
||||
}
|
||||
|
@ -1,41 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This function mixes a voiced signal with an unvoiced signal and
|
||||
* updates the weight on a sample by sample basis.
|
||||
*/
|
||||
|
||||
#include "dsp_helpfunctions.h"
|
||||
|
||||
#include "signal_processing_library.h"
|
||||
|
||||
void WebRtcNetEQ_MixVoiceUnvoice(int16_t *pw16_outData, int16_t *pw16_voicedVec,
|
||||
int16_t *pw16_unvoicedVec,
|
||||
int16_t *w16_current_vfraction,
|
||||
int16_t w16_vfraction_change, int16_t N)
|
||||
{
|
||||
int i;
|
||||
int16_t w16_tmp2;
|
||||
int16_t vfraction = *w16_current_vfraction;
|
||||
|
||||
w16_tmp2 = 16384 - vfraction;
|
||||
for (i = 0; i < N; i++)
|
||||
{
|
||||
pw16_outData[i] = (int16_t) WEBRTC_SPL_RSHIFT_W32(
|
||||
WEBRTC_SPL_MUL_16_16(vfraction, pw16_voicedVec[i]) +
|
||||
WEBRTC_SPL_MUL_16_16(w16_tmp2, pw16_unvoicedVec[i]) + 8192,
|
||||
14);
|
||||
vfraction -= w16_vfraction_change;
|
||||
w16_tmp2 += w16_vfraction_change;
|
||||
}
|
||||
*w16_current_vfraction = vfraction;
|
||||
}
|
||||
|
@ -1,33 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This function mutes a signal linearly on a sample by sample basis.
|
||||
*/
|
||||
|
||||
#include "dsp_helpfunctions.h"
|
||||
|
||||
#include "signal_processing_library.h"
|
||||
|
||||
void WebRtcNetEQ_MuteSignal(int16_t *pw16_inout, int16_t muteSlope,
|
||||
int16_t N)
|
||||
{
|
||||
int i;
|
||||
int32_t w32_tmp = 1048608; /* (16384<<6 + 32) */
|
||||
|
||||
for (i = 0; i < N; i++)
|
||||
{
|
||||
pw16_inout[i]
|
||||
= (int16_t) ((WEBRTC_SPL_MUL_16_16((int16_t)(w32_tmp>>6), pw16_inout[i])
|
||||
+ 8192) >> 14);
|
||||
w32_tmp -= muteSlope;
|
||||
}
|
||||
}
|
||||
|
@ -1,272 +0,0 @@
|
||||
# Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
|
||||
#
|
||||
# Use of this source code is governed by a BSD-style license
|
||||
# that can be found in the LICENSE file in the root of the source
|
||||
# tree. An additional intellectual property rights grant can be found
|
||||
# in the file PATENTS. All contributing project authors may
|
||||
# be found in the AUTHORS file in the root of the source tree.
|
||||
|
||||
{
|
||||
'targets': [
|
||||
{
|
||||
'target_name': 'NetEq',
|
||||
'type': 'static_library',
|
||||
'dependencies': [
|
||||
'CNG',
|
||||
'<(webrtc_root)/common_audio/common_audio.gyp:common_audio',
|
||||
],
|
||||
'defines': [
|
||||
'NETEQ_VOICEENGINE_CODECS', # TODO: Should create a Chrome define which
|
||||
'SCRATCH', # specifies a subset of codecs to support.
|
||||
],
|
||||
'include_dirs': [
|
||||
'interface',
|
||||
'<(webrtc_root)',
|
||||
],
|
||||
'direct_dependent_settings': {
|
||||
'include_dirs': [
|
||||
'interface',
|
||||
'<(webrtc_root)',
|
||||
],
|
||||
},
|
||||
'sources': [
|
||||
'interface/webrtc_neteq.h',
|
||||
'interface/webrtc_neteq_help_macros.h',
|
||||
'interface/webrtc_neteq_internal.h',
|
||||
'accelerate.c',
|
||||
'automode.c',
|
||||
'automode.h',
|
||||
'bgn_update.c',
|
||||
'buffer_stats.h',
|
||||
'bufstats_decision.c',
|
||||
'cng_internal.c',
|
||||
'codec_db.c',
|
||||
'codec_db.h',
|
||||
'codec_db_defines.h',
|
||||
'correlator.c',
|
||||
'delay_logging.h',
|
||||
'dsp.c',
|
||||
'dsp.h',
|
||||
'dsp_helpfunctions.c',
|
||||
'dsp_helpfunctions.h',
|
||||
'dtmf_buffer.c',
|
||||
'dtmf_buffer.h',
|
||||
'dtmf_tonegen.c',
|
||||
'dtmf_tonegen.h',
|
||||
'expand.c',
|
||||
'mcu.h',
|
||||
'mcu_address_init.c',
|
||||
'mcu_dsp_common.c',
|
||||
'mcu_dsp_common.h',
|
||||
'mcu_reset.c',
|
||||
'merge.c',
|
||||
'min_distortion.c',
|
||||
'mix_voice_unvoice.c',
|
||||
'mute_signal.c',
|
||||
'neteq_defines.h',
|
||||
'neteq_error_codes.h',
|
||||
'neteq_statistics.h',
|
||||
'normal.c',
|
||||
'packet_buffer.c',
|
||||
'packet_buffer.h',
|
||||
'peak_detection.c',
|
||||
'preemptive_expand.c',
|
||||
'random_vector.c',
|
||||
'recin.c',
|
||||
'recout.c',
|
||||
'rtcp.c',
|
||||
'rtcp.h',
|
||||
'rtp.c',
|
||||
'rtp.h',
|
||||
'set_fs.c',
|
||||
'signal_mcu.c',
|
||||
'split_and_insert.c',
|
||||
'unmute_signal.c',
|
||||
'webrtc_neteq.c',
|
||||
],
|
||||
},
|
||||
], # targets
|
||||
'conditions': [
|
||||
['include_tests==1', {
|
||||
'targets': [
|
||||
{
|
||||
'target_name': 'neteq_unittests',
|
||||
'type': '<(gtest_target_type)',
|
||||
'dependencies': [
|
||||
'NetEq',
|
||||
'NetEqTestTools',
|
||||
'neteq_unittest_tools',
|
||||
'<(DEPTH)/testing/gtest.gyp:gtest',
|
||||
'<(webrtc_root)/test/test.gyp:test_support_main',
|
||||
],
|
||||
'sources': [
|
||||
'webrtc_neteq_unittest.cc',
|
||||
],
|
||||
# Disable warnings to enable Win64 build, issue 1323.
|
||||
'msvs_disabled_warnings': [
|
||||
4267, # size_t to int truncation.
|
||||
],
|
||||
'conditions': [
|
||||
# TODO(henrike): remove build_with_chromium==1 when the bots are
|
||||
# using Chromium's buildbots.
|
||||
['build_with_chromium==1 and OS=="android" and gtest_target_type=="shared_library"', {
|
||||
'dependencies': [
|
||||
'<(DEPTH)/testing/android/native_test.gyp:native_test_native_code',
|
||||
],
|
||||
}],
|
||||
],
|
||||
}, # neteq_unittests
|
||||
{
|
||||
'target_name': 'NetEqRTPplay',
|
||||
'type': 'executable',
|
||||
'dependencies': [
|
||||
'NetEq', # NetEQ library defined above
|
||||
'NetEqTestTools', # Test helpers
|
||||
'G711',
|
||||
'G722',
|
||||
'PCM16B',
|
||||
'iLBC',
|
||||
'iSAC',
|
||||
'CNG',
|
||||
],
|
||||
'defines': [
|
||||
# TODO: Make codec selection conditional on definitions in target NetEq
|
||||
'CODEC_ILBC',
|
||||
'CODEC_PCM16B',
|
||||
'CODEC_G711',
|
||||
'CODEC_G722',
|
||||
'CODEC_ISAC',
|
||||
'CODEC_PCM16B_WB',
|
||||
'CODEC_ISAC_SWB',
|
||||
'CODEC_ISAC_FB',
|
||||
'CODEC_PCM16B_32KHZ',
|
||||
'CODEC_CNGCODEC8',
|
||||
'CODEC_CNGCODEC16',
|
||||
'CODEC_CNGCODEC32',
|
||||
'CODEC_ATEVENT_DECODE',
|
||||
'CODEC_RED',
|
||||
],
|
||||
'include_dirs': [
|
||||
'.',
|
||||
'test',
|
||||
],
|
||||
'sources': [
|
||||
'test/NetEqRTPplay.cc',
|
||||
],
|
||||
# Disable warnings to enable Win64 build, issue 1323.
|
||||
'msvs_disabled_warnings': [
|
||||
4267, # size_t to int truncation.
|
||||
],
|
||||
},
|
||||
|
||||
{
|
||||
'target_name': 'neteq3_speed_test',
|
||||
'type': 'executable',
|
||||
'dependencies': [
|
||||
'NetEq',
|
||||
'PCM16B',
|
||||
'neteq_unittest_tools',
|
||||
'<(DEPTH)/third_party/gflags/gflags.gyp:gflags',
|
||||
'<(webrtc_root)/test/test.gyp:test_support_main',
|
||||
],
|
||||
'sources': [
|
||||
'test/neteq_speed_test.cc',
|
||||
],
|
||||
},
|
||||
|
||||
{
|
||||
'target_name': 'NetEqTestTools',
|
||||
# Collection of useful functions used in other tests
|
||||
'type': 'static_library',
|
||||
'variables': {
|
||||
# Expects RTP packets without payloads when enabled.
|
||||
'neteq_dummy_rtp%': 0,
|
||||
},
|
||||
'dependencies': [
|
||||
'G711',
|
||||
'G722',
|
||||
'PCM16B',
|
||||
'iLBC',
|
||||
'iSAC',
|
||||
'CNG',
|
||||
'<(DEPTH)/testing/gtest.gyp:gtest',
|
||||
],
|
||||
'direct_dependent_settings': {
|
||||
'include_dirs': [
|
||||
'interface',
|
||||
'test',
|
||||
],
|
||||
},
|
||||
'defines': [
|
||||
# TODO: Make codec selection conditional on definitions in target NetEq
|
||||
'CODEC_ILBC',
|
||||
'CODEC_PCM16B',
|
||||
'CODEC_G711',
|
||||
'CODEC_G722',
|
||||
'CODEC_ISAC',
|
||||
'CODEC_PCM16B_WB',
|
||||
'CODEC_ISAC_SWB',
|
||||
'CODEC_ISAC_FB',
|
||||
'CODEC_PCM16B_32KHZ',
|
||||
'CODEC_CNGCODEC8',
|
||||
'CODEC_CNGCODEC16',
|
||||
'CODEC_CNGCODEC32',
|
||||
'CODEC_ATEVENT_DECODE',
|
||||
'CODEC_RED',
|
||||
],
|
||||
'include_dirs': [
|
||||
'interface',
|
||||
'test',
|
||||
],
|
||||
'sources': [
|
||||
'test/NETEQTEST_CodecClass.cc',
|
||||
'test/NETEQTEST_CodecClass.h',
|
||||
'test/NETEQTEST_DummyRTPpacket.cc',
|
||||
'test/NETEQTEST_DummyRTPpacket.h',
|
||||
'test/NETEQTEST_NetEQClass.cc',
|
||||
'test/NETEQTEST_NetEQClass.h',
|
||||
'test/NETEQTEST_RTPpacket.cc',
|
||||
'test/NETEQTEST_RTPpacket.h',
|
||||
],
|
||||
# Disable warnings to enable Win64 build, issue 1323.
|
||||
'msvs_disabled_warnings': [
|
||||
4267, # size_t to int truncation.
|
||||
],
|
||||
},
|
||||
], # targets
|
||||
'conditions': [
|
||||
# TODO(henrike): remove build_with_chromium==1 when the bots are using
|
||||
# Chromium's buildbots.
|
||||
['build_with_chromium==1 and OS=="android" and gtest_target_type=="shared_library"', {
|
||||
'targets': [
|
||||
{
|
||||
'target_name': 'neteq_unittests_apk_target',
|
||||
'type': 'none',
|
||||
'dependencies': [
|
||||
'<(apk_tests_path):neteq_unittests_apk',
|
||||
],
|
||||
},
|
||||
],
|
||||
}],
|
||||
['test_isolation_mode != "noop"', {
|
||||
'targets': [
|
||||
{
|
||||
'target_name': 'neteq_unittests_run',
|
||||
'type': 'none',
|
||||
'dependencies': [
|
||||
'neteq_unittests',
|
||||
],
|
||||
'includes': [
|
||||
'../../../build/isolate.gypi',
|
||||
'neteq_unittests.isolate',
|
||||
],
|
||||
'sources': [
|
||||
'neteq_unittests.isolate',
|
||||
],
|
||||
},
|
||||
],
|
||||
}],
|
||||
],
|
||||
}], # include_tests
|
||||
], # conditions
|
||||
}
|
@ -1,374 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
/*****************************************************************************************
|
||||
*
|
||||
* Compilation flags in NetEQ:
|
||||
*
|
||||
*****************************************************************************************
|
||||
*
|
||||
***** Platform flags ******
|
||||
*
|
||||
* SCRATCH Run NetEQ with "Scratch memory" to save some stack memory.
|
||||
* Definition can be used on all platforms
|
||||
*
|
||||
***** Summary flags ******
|
||||
*
|
||||
* NETEQ_ALL_SPECIAL_CODECS Add support for special codecs (CN/RED/DTMF)
|
||||
*
|
||||
* NETEQ_ALL_NB_CODECS Add support for all NB codecs (except CN/RED/DTMF)
|
||||
*
|
||||
* NETEQ_ALL_WB_CODECS Add support for all WB codecs (except CN/RED/DTMF)
|
||||
*
|
||||
* NETEQ_VOICEENGINE_CODECS Support for all NB, WB and SWB32 codecs and CN, RED and DTMF
|
||||
*
|
||||
* NETEQ_ALL_CODECS Support for all NB, WB, SWB 32kHz and SWB 48kHz as well as
|
||||
* CN, RED and DTMF
|
||||
*
|
||||
***** Sampling frequency ******
|
||||
* (Note: usually not needed when Summary flags are used)
|
||||
*
|
||||
* NETEQ_WIDEBAND Wideband enabled
|
||||
*
|
||||
* NETEQ_32KHZ_WIDEBAND Super wideband @ 32kHz enabled
|
||||
*
|
||||
* NETEQ_48KHZ_WIDEBAND Super wideband @ 48kHz enabled
|
||||
*
|
||||
***** Special Codec ******
|
||||
* (Note: not needed if NETEQ_ALL_CODECS is used)
|
||||
*
|
||||
* NETEQ_RED_CODEC With this flag you enable NetEQ to understand redundancy in
|
||||
* the RTP. NetEQ will use the redundancy if it's the same
|
||||
* codec
|
||||
*
|
||||
* NETEQ_CNG_CODEC Enable DTX with the CN payload
|
||||
*
|
||||
* NETEQ_ATEVENT_DECODE Enable AVT event and play out the corresponding DTMF tone
|
||||
*
|
||||
***** Speech Codecs *****
|
||||
* (Note: Not needed if Summary flags are used)
|
||||
*
|
||||
* NETEQ_G711_CODEC Enable G.711 u- and A-law
|
||||
*
|
||||
* NETEQ_PCM16B_CODEC Enable uncompressed 16-bit
|
||||
*
|
||||
* NETEQ_ILBC_CODEC Enable iLBC
|
||||
*
|
||||
* NETEQ_ISAC_CODEC Enable iSAC
|
||||
*
|
||||
* NETEQ_ISAC_SWB_CODEC Enable iSAC-SWB
|
||||
*
|
||||
* Note that the decoder of iSAC full-band operates at 32 kHz, that is the
|
||||
* decoded signal is at 32 kHz.
|
||||
* NETEQ_ISAC_FB_CODEC Enable iSAC-FB
|
||||
*
|
||||
* NETEQ_G722_CODEC Enable G.722
|
||||
*
|
||||
* NETEQ_G729_CODEC Enable G.729
|
||||
*
|
||||
* NETEQ_G729_1_CODEC Enable G.729.1
|
||||
*
|
||||
* NETEQ_G726_CODEC Enable G.726
|
||||
*
|
||||
* NETEQ_G722_1_CODEC Enable G722.1
|
||||
*
|
||||
* NETEQ_G722_1C_CODEC Enable G722.1 Annex C
|
||||
*
|
||||
* NETEQ_OPUS_CODEC Enable Opus
|
||||
*
|
||||
* NETEQ_SPEEX_CODEC Enable Speex (at 8 and 16 kHz sample rate)
|
||||
*
|
||||
* NETEQ_CELT_CODEC Enable Celt (at 32 kHz sample rate)
|
||||
*
|
||||
* NETEQ_GSMFR_CODEC Enable GSM-FR
|
||||
*
|
||||
* NETEQ_AMR_CODEC Enable AMR (narrowband)
|
||||
*
|
||||
* NETEQ_AMRWB_CODEC Enable AMR-WB
|
||||
*
|
||||
* NETEQ_CNG_CODEC Enable DTX with the CNG payload
|
||||
*
|
||||
* NETEQ_ATEVENT_DECODE Enable AVT event and play out the corresponding DTMF tone
|
||||
*
|
||||
***** Test flags ******
|
||||
*
|
||||
* WEBRTC_NETEQ_40BITACC_TEST Run NetEQ with simulated 40-bit accumulator to run
|
||||
* bit-exact to a DSP implementation where the main (splib
|
||||
* and NetEQ) functions have been 40-bit optimized
|
||||
*
|
||||
*****************************************************************************************
|
||||
*/
|
||||
|
||||
#if !defined NETEQ_DEFINES_H
|
||||
#define NETEQ_DEFINES_H
|
||||
|
||||
/* Data block structure for MCU to DSP communication:
|
||||
*
|
||||
*
|
||||
* First 3 16-bit words are pre-header that contains instructions and timestamp update
|
||||
* Fourth 16-bit word is length of data block 1
|
||||
* Rest is payload data
|
||||
*
|
||||
* 0 48 64 80
|
||||
* -------------...----------------------------------------------------------------------
|
||||
* | PreHeader ... | Length 1 | Payload data 1 ...... | Lenght 2| Data block 2.... | ...
|
||||
* -------------...----------------------------------------------------------------------
|
||||
*
|
||||
*
|
||||
* Preheader:
|
||||
* 4 MSB can be either of:
|
||||
*/
|
||||
|
||||
#define DSP_INSTR_NORMAL 0x1000
|
||||
/* Payload data will contain the encoded frames */
|
||||
|
||||
#define DSP_INSTR_MERGE 0x2000
|
||||
/* Payload data block 1 will contain the encoded frame */
|
||||
/* Info block will contain the number of missing samples */
|
||||
|
||||
#define DSP_INSTR_EXPAND 0x3000
|
||||
/* Payload data will be empty */
|
||||
|
||||
#define DSP_INSTR_ACCELERATE 0x4000
|
||||
/* Payload data will contain the encoded frame */
|
||||
|
||||
#define DSP_INSTR_DO_RFC3389CNG 0x5000
|
||||
/* Payload data will contain the SID frame if there is one*/
|
||||
|
||||
#define DSP_INSTR_DTMF_GENERATE 0x6000
|
||||
/* Payload data will be one int16_t with the current DTMF value and one
|
||||
* int16_t with the current volume value
|
||||
*/
|
||||
#define DSP_INSTR_NORMAL_ONE_DESC 0x7000
|
||||
/* No encoded frames */
|
||||
|
||||
#define DSP_INSTR_DO_CODEC_INTERNAL_CNG 0x8000
|
||||
/* Codec has a built-in VAD/DTX scheme (use the above for "no transmission") */
|
||||
|
||||
#define DSP_INSTR_PREEMPTIVE_EXPAND 0x9000
|
||||
/* Payload data will contain the encoded frames, if any */
|
||||
|
||||
#define DSP_INSTR_DO_ALTERNATIVE_PLC 0xB000
|
||||
/* NetEQ switched off and packet missing... */
|
||||
|
||||
#define DSP_INSTR_DO_ALTERNATIVE_PLC_INC_TS 0xC000
|
||||
/* NetEQ switched off and packet missing... */
|
||||
|
||||
#define DSP_INSTR_DO_AUDIO_REPETITION 0xD000
|
||||
/* NetEQ switched off and packet missing... */
|
||||
|
||||
#define DSP_INSTR_DO_AUDIO_REPETITION_INC_TS 0xE000
|
||||
/* NetEQ switched off and packet missing... */
|
||||
|
||||
#define DSP_INSTR_FADE_TO_BGN 0xF000
|
||||
/* Exception handling: fade out to BGN (expand) */
|
||||
|
||||
/*
|
||||
* Next 4 bits signal additional data that needs to be transmitted
|
||||
*/
|
||||
|
||||
#define DSP_CODEC_NO_CHANGE 0x0100
|
||||
#define DSP_CODEC_NEW_CODEC 0x0200
|
||||
#define DSP_CODEC_ADD_LATE_PKT 0x0300
|
||||
#define DSP_CODEC_RESET 0x0400
|
||||
#define DSP_DTMF_PAYLOAD 0x0010
|
||||
|
||||
/*
|
||||
* The most significant bit of the payload-length
|
||||
* is used to flag whether the associated payload
|
||||
* is redundant payload. This currently useful only for
|
||||
* iSAC, where redundant payloads have to be treated
|
||||
* differently. Every time the length is read it must be
|
||||
* masked by DSP_CODEC_MASK_RED_FLAG to ignore the flag.
|
||||
* Use DSP_CODEC_RED_FLAG to set or retrieve the flag.
|
||||
*/
|
||||
#define DSP_CODEC_MASK_RED_FLAG 0x7FFF
|
||||
#define DSP_CODEC_RED_FLAG 0x8000
|
||||
|
||||
/*
|
||||
* The first block of payload data consist of decode function pointers,
|
||||
* and then the speech blocks.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* The playout modes that NetEq produced (i.e. gives more info about if the
|
||||
* Accelerate was successful or not)
|
||||
*/
|
||||
|
||||
#define MODE_NORMAL 0x0000
|
||||
#define MODE_EXPAND 0x0001
|
||||
#define MODE_MERGE 0x0002
|
||||
#define MODE_SUCCESS_ACCELERATE 0x0003
|
||||
#define MODE_UNSUCCESS_ACCELERATE 0x0004
|
||||
#define MODE_RFC3389CNG 0x0005
|
||||
#define MODE_LOWEN_ACCELERATE 0x0006
|
||||
#define MODE_DTMF 0x0007
|
||||
#define MODE_ONE_DESCRIPTOR 0x0008
|
||||
#define MODE_CODEC_INTERNAL_CNG 0x0009
|
||||
#define MODE_SUCCESS_PREEMPTIVE 0x000A
|
||||
#define MODE_UNSUCCESS_PREEMPTIVE 0x000B
|
||||
#define MODE_LOWEN_PREEMPTIVE 0x000C
|
||||
#define MODE_FADE_TO_BGN 0x000D
|
||||
|
||||
#define MODE_ERROR 0x0010
|
||||
|
||||
#define MODE_AWAITING_CODEC_PTR 0x0100
|
||||
|
||||
#define MODE_BGN_ONLY 0x0200
|
||||
|
||||
#define MODE_MASTER_DTMF_SIGNAL 0x0400
|
||||
|
||||
#define MODE_USING_STEREO 0x0800
|
||||
|
||||
|
||||
|
||||
/***********************/
|
||||
/* Group codec defines */
|
||||
/***********************/
|
||||
|
||||
#if (defined(NETEQ_ALL_SPECIAL_CODECS))
|
||||
#define NETEQ_CNG_CODEC
|
||||
#define NETEQ_ATEVENT_DECODE
|
||||
#define NETEQ_RED_CODEC
|
||||
#define NETEQ_VAD
|
||||
#define NETEQ_ARBITRARY_CODEC
|
||||
#endif
|
||||
|
||||
#if (defined(NETEQ_ALL_NB_CODECS)) /* Except RED, DTMF and CNG */
|
||||
#define NETEQ_PCM16B_CODEC
|
||||
#define NETEQ_G711_CODEC
|
||||
#define NETEQ_ILBC_CODEC
|
||||
#define NETEQ_G729_CODEC
|
||||
#define NETEQ_G726_CODEC
|
||||
#define NETEQ_GSMFR_CODEC
|
||||
#define NETEQ_OPUS_CODEC
|
||||
#define NETEQ_AMR_CODEC
|
||||
#endif
|
||||
|
||||
#if (defined(NETEQ_ALL_WB_CODECS)) /* Except RED, DTMF and CNG */
|
||||
#define NETEQ_ISAC_CODEC
|
||||
#define NETEQ_G722_CODEC
|
||||
#define NETEQ_G722_1_CODEC
|
||||
#define NETEQ_G729_1_CODEC
|
||||
#define NETEQ_OPUS_CODEC
|
||||
#define NETEQ_SPEEX_CODEC
|
||||
#define NETEQ_AMRWB_CODEC
|
||||
#define NETEQ_WIDEBAND
|
||||
#endif
|
||||
|
||||
#if (defined(NETEQ_ALL_WB32_CODECS)) /* AAC, RED, DTMF and CNG */
|
||||
#define NETEQ_ISAC_SWB_CODEC
|
||||
#define NETEQ_32KHZ_WIDEBAND
|
||||
#define NETEQ_G722_1C_CODEC
|
||||
#define NETEQ_CELT_CODEC
|
||||
#define NETEQ_OPUS_CODEC
|
||||
#endif
|
||||
|
||||
#if (defined(NETEQ_VOICEENGINE_CODECS))
|
||||
/* Special codecs */
|
||||
#define NETEQ_CNG_CODEC
|
||||
#define NETEQ_ATEVENT_DECODE
|
||||
#define NETEQ_RED_CODEC
|
||||
#define NETEQ_VAD
|
||||
#define NETEQ_ARBITRARY_CODEC
|
||||
|
||||
/* Narrowband codecs */
|
||||
#define NETEQ_PCM16B_CODEC
|
||||
#define NETEQ_G711_CODEC
|
||||
#define NETEQ_ILBC_CODEC
|
||||
#define NETEQ_AMR_CODEC
|
||||
#define NETEQ_G729_CODEC
|
||||
#define NETEQ_GSMFR_CODEC
|
||||
|
||||
/* Wideband codecs */
|
||||
#define NETEQ_WIDEBAND
|
||||
#define NETEQ_ISAC_CODEC
|
||||
#define NETEQ_G722_CODEC
|
||||
#define NETEQ_G722_1_CODEC
|
||||
#define NETEQ_G729_1_CODEC
|
||||
#define NETEQ_AMRWB_CODEC
|
||||
#define NETEQ_SPEEX_CODEC
|
||||
|
||||
/* Super wideband 32kHz codecs */
|
||||
#define NETEQ_ISAC_SWB_CODEC
|
||||
#define NETEQ_32KHZ_WIDEBAND
|
||||
#define NETEQ_G722_1C_CODEC
|
||||
#define NETEQ_CELT_CODEC
|
||||
|
||||
/* Fullband 48 kHz codecs */
|
||||
#define NETEQ_OPUS_CODEC
|
||||
#define NETEQ_ISAC_FB_CODEC
|
||||
#endif
|
||||
|
||||
#if (defined(NETEQ_ALL_CODECS))
|
||||
/* Special codecs */
|
||||
#define NETEQ_CNG_CODEC
|
||||
#define NETEQ_ATEVENT_DECODE
|
||||
#define NETEQ_RED_CODEC
|
||||
#define NETEQ_VAD
|
||||
#define NETEQ_ARBITRARY_CODEC
|
||||
|
||||
/* Narrowband codecs */
|
||||
#define NETEQ_PCM16B_CODEC
|
||||
#define NETEQ_G711_CODEC
|
||||
#define NETEQ_ILBC_CODEC
|
||||
#define NETEQ_G729_CODEC
|
||||
#define NETEQ_G726_CODEC
|
||||
#define NETEQ_GSMFR_CODEC
|
||||
#define NETEQ_AMR_CODEC
|
||||
|
||||
/* Wideband codecs */
|
||||
#define NETEQ_WIDEBAND
|
||||
#define NETEQ_ISAC_CODEC
|
||||
#define NETEQ_G722_CODEC
|
||||
#define NETEQ_G722_1_CODEC
|
||||
#define NETEQ_G729_1_CODEC
|
||||
#define NETEQ_SPEEX_CODEC
|
||||
#define NETEQ_AMRWB_CODEC
|
||||
|
||||
/* Super wideband 32kHz codecs */
|
||||
#define NETEQ_ISAC_SWB_CODEC
|
||||
#define NETEQ_32KHZ_WIDEBAND
|
||||
#define NETEQ_G722_1C_CODEC
|
||||
#define NETEQ_CELT_CODEC
|
||||
|
||||
/* Super wideband 48kHz codecs */
|
||||
#define NETEQ_48KHZ_WIDEBAND
|
||||
#define NETEQ_OPUS_CODEC
|
||||
#define NETEQ_ISAC_FB_CODEC
|
||||
#endif
|
||||
|
||||
/* Max output size from decoding one frame */
|
||||
#if defined(NETEQ_48KHZ_WIDEBAND)
|
||||
#define NETEQ_MAX_FRAME_SIZE 5760 /* 120 ms super wideband */
|
||||
#define NETEQ_MAX_OUTPUT_SIZE 6480 /* 120+15 ms super wideband (120 ms
|
||||
* decoded + 15 ms for merge overlap) */
|
||||
#elif defined(NETEQ_32KHZ_WIDEBAND)
|
||||
#define NETEQ_MAX_FRAME_SIZE 3840 /* 120 ms super wideband */
|
||||
#define NETEQ_MAX_OUTPUT_SIZE 4320 /* 120+15 ms super wideband (120 ms
|
||||
* decoded + 15 ms for merge overlap) */
|
||||
#elif defined(NETEQ_WIDEBAND)
|
||||
#define NETEQ_MAX_FRAME_SIZE 1920 /* 120 ms wideband */
|
||||
#define NETEQ_MAX_OUTPUT_SIZE 2160 /* 120+15 ms wideband (120 ms decoded +
|
||||
* 15 ms for merge overlap) */
|
||||
#else
|
||||
#define NETEQ_MAX_FRAME_SIZE 960 /* 120 ms narrowband */
|
||||
#define NETEQ_MAX_OUTPUT_SIZE 1080 /* 120+15 ms narrowband (120 ms decoded
|
||||
* + 15 ms for merge overlap) */
|
||||
#endif
|
||||
|
||||
|
||||
/* Enable stereo */
|
||||
#define NETEQ_STEREO
|
||||
|
||||
#endif /* #if !defined NETEQ_DEFINES_H */
|
||||
|
@ -1,81 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Definition of error codes.
|
||||
*
|
||||
* NOTE: When modifying the error codes,
|
||||
* also modify the function WebRtcNetEQ_GetErrorCode!
|
||||
*/
|
||||
|
||||
#if !defined NETEQ_ERROR_CODES_H
|
||||
#define NETEQ_ERROR_CODES_H
|
||||
|
||||
/* Misc Error */
|
||||
#define NETEQ_OTHER_ERROR -1000
|
||||
|
||||
/* Misc Recout Errors */
|
||||
#define FAULTY_INSTRUCTION -1001
|
||||
#define FAULTY_NETWORK_TYPE -1002
|
||||
#define FAULTY_DELAYVALUE -1003
|
||||
#define FAULTY_PLAYOUTMODE -1004
|
||||
#define CORRUPT_INSTANCE -1005
|
||||
#define ILLEGAL_MASTER_SLAVE_SWITCH -1006
|
||||
#define MASTER_SLAVE_ERROR -1007
|
||||
|
||||
/* Misc Recout problems */
|
||||
#define UNKNOWN_BUFSTAT_DECISION -2001
|
||||
#define RECOUT_ERROR_DECODING -2002
|
||||
#define RECOUT_ERROR_SAMPLEUNDERRUN -2003
|
||||
#define RECOUT_ERROR_DECODED_TOO_MUCH -2004
|
||||
|
||||
/* Misc RecIn problems */
|
||||
#define RECIN_CNG_ERROR -3001
|
||||
#define RECIN_UNKNOWNPAYLOAD -3002
|
||||
#define RECIN_BUFFERINSERT_ERROR -3003
|
||||
#define RECIN_SYNC_RTP_CHANGED_CODEC -3004
|
||||
#define RECIN_SYNC_RTP_NOT_ACCEPTABLE -3005
|
||||
|
||||
/* PBUFFER/BUFSTAT ERRORS */
|
||||
#define PBUFFER_INIT_ERROR -4001
|
||||
#define PBUFFER_INSERT_ERROR1 -4002
|
||||
#define PBUFFER_INSERT_ERROR2 -4003
|
||||
#define PBUFFER_INSERT_ERROR3 -4004
|
||||
#define PBUFFER_INSERT_ERROR4 -4005
|
||||
#define PBUFFER_INSERT_ERROR5 -4006
|
||||
#define UNKNOWN_G723_HEADER -4007
|
||||
#define PBUFFER_NONEXISTING_PACKET -4008
|
||||
#define PBUFFER_NOT_INITIALIZED -4009
|
||||
#define AMBIGUOUS_ILBC_FRAME_SIZE -4010
|
||||
|
||||
/* CODEC DATABASE ERRORS */
|
||||
#define CODEC_DB_FULL -5001
|
||||
#define CODEC_DB_NOT_EXIST1 -5002
|
||||
#define CODEC_DB_NOT_EXIST2 -5003
|
||||
#define CODEC_DB_NOT_EXIST3 -5004
|
||||
#define CODEC_DB_NOT_EXIST4 -5005
|
||||
#define CODEC_DB_UNKNOWN_CODEC -5006
|
||||
#define CODEC_DB_PAYLOAD_TAKEN -5007
|
||||
#define CODEC_DB_UNSUPPORTED_CODEC -5008
|
||||
#define CODEC_DB_UNSUPPORTED_FS -5009
|
||||
|
||||
/* DTMF ERRORS */
|
||||
#define DTMF_DEC_PARAMETER_ERROR -6001
|
||||
#define DTMF_INSERT_ERROR -6002
|
||||
#define DTMF_GEN_UNKNOWN_SAMP_FREQ -6003
|
||||
#define DTMF_NOT_SUPPORTED -6004
|
||||
|
||||
/* RTP/PACKET ERRORS */
|
||||
#define RED_SPLIT_ERROR1 -7001
|
||||
#define RED_SPLIT_ERROR2 -7002
|
||||
#define RTP_TOO_SHORT_PACKET -7003
|
||||
#define RTP_CORRUPT_PACKET -7004
|
||||
|
||||
#endif
|
@ -1,56 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Definitions of statistics data structures for MCU and DSP sides.
|
||||
*/
|
||||
|
||||
#include "typedefs.h"
|
||||
|
||||
#ifndef NETEQ_STATISTICS_H
|
||||
#define NETEQ_STATISTICS_H
|
||||
|
||||
/*
|
||||
* Statistics struct on DSP side
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
|
||||
/* variables for in-call statistics; queried through WebRtcNetEQ_GetNetworkStatistics */
|
||||
uint32_t expandLength; /* number of samples produced through expand */
|
||||
uint32_t preemptiveLength; /* number of samples produced through pre-emptive
|
||||
expand */
|
||||
uint32_t accelerateLength; /* number of samples removed through accelerate */
|
||||
int addedSamples; /* number of samples inserted in off mode */
|
||||
|
||||
/* variables for post-call statistics; queried through WebRtcNetEQ_GetJitterStatistics */
|
||||
uint32_t expandedVoiceSamples; /* number of voice samples produced through expand */
|
||||
uint32_t expandedNoiseSamples; /* number of noise (background) samples produced
|
||||
through expand */
|
||||
|
||||
} DSPStats_t;
|
||||
|
||||
typedef struct {
|
||||
int preemptive_expand_bgn_samples;
|
||||
int preemptive_expand_normal_samples;
|
||||
|
||||
int expand_bgn_samples;
|
||||
int expand_normal_samples;
|
||||
|
||||
int merge_expand_bgn_samples;
|
||||
int merge_expand_normal_samples;
|
||||
|
||||
int accelerate_bgn_samples;
|
||||
int accelarate_normal_samples;
|
||||
} ActivityStats;
|
||||
|
||||
|
||||
#endif
|
||||
|
@ -1,44 +0,0 @@
|
||||
# Copyright (c) 2013 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.
|
||||
{
|
||||
'conditions': [
|
||||
['OS=="android"', {
|
||||
# When doing Android builds, the WebRTC code is put in third_party/webrtc
|
||||
# of a Chromium checkout, this is one level above the standalone build.
|
||||
'variables': {
|
||||
'isolate_dependency_untracked': [
|
||||
'../../../../../data/',
|
||||
'../../../../../resources/',
|
||||
],
|
||||
},
|
||||
}],
|
||||
['OS=="linux" or OS=="mac" or OS=="win"', {
|
||||
'variables': {
|
||||
'command': [
|
||||
'../../../../testing/test_env.py',
|
||||
'<(PRODUCT_DIR)/neteq_unittests<(EXECUTABLE_SUFFIX)',
|
||||
],
|
||||
'isolate_dependency_touched': [
|
||||
'../../../../DEPS',
|
||||
],
|
||||
'isolate_dependency_tracked': [
|
||||
'../../../../resources/audio_coding/neteq_network_stats.dat',
|
||||
'../../../../resources/audio_coding/neteq_rtcp_stats.dat',
|
||||
'../../../../resources/audio_coding/neteq_universal.rtp',
|
||||
'../../../../resources/audio_coding/neteq_universal_ref.pcm',
|
||||
'../../../../resources/audio_coding/testfile32kHz.pcm',
|
||||
'../../../../testing/test_env.py',
|
||||
'<(PRODUCT_DIR)/neteq_unittests<(EXECUTABLE_SUFFIX)',
|
||||
],
|
||||
'isolate_dependency_untracked': [
|
||||
'../../../../tools/swarming_client/',
|
||||
],
|
||||
},
|
||||
}],
|
||||
],
|
||||
}
|
@ -1,279 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file contains the function for handling "normal" speech operation.
|
||||
*/
|
||||
#include "dsp.h"
|
||||
|
||||
#include "signal_processing_library.h"
|
||||
|
||||
#include "dsp_helpfunctions.h"
|
||||
|
||||
/* Scratch usage:
|
||||
|
||||
Type Name size startpos endpos
|
||||
int16_t pw16_expanded 125*fs/8000 0 125*fs/8000-1
|
||||
|
||||
func WebRtcNetEQ_Expand 40+370*fs/8000 125*fs/8000 39+495*fs/8000
|
||||
|
||||
Total: 40+495*fs/8000
|
||||
*/
|
||||
|
||||
#define SCRATCH_PW16_EXPANDED 0
|
||||
#if (defined(NETEQ_48KHZ_WIDEBAND))
|
||||
#define SCRATCH_NETEQ_EXPAND 756
|
||||
#elif (defined(NETEQ_32KHZ_WIDEBAND))
|
||||
#define SCRATCH_NETEQ_EXPAND 504
|
||||
#elif (defined(NETEQ_WIDEBAND))
|
||||
#define SCRATCH_NETEQ_EXPAND 252
|
||||
#else /* NB */
|
||||
#define SCRATCH_NETEQ_EXPAND 126
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* WebRtcNetEQ_Normal(...)
|
||||
*
|
||||
* This function has the possibility to modify data that is played out in Normal
|
||||
* mode, for example adjust the gain of the signal. The length of the signal
|
||||
* can not be changed.
|
||||
*
|
||||
* Input:
|
||||
* - inst : NetEq instance, i.e. the user that requests more
|
||||
* speech/audio data
|
||||
* - scratchPtr : Pointer to scratch vector
|
||||
* - decoded : Pointer to vector of new data from decoder
|
||||
* (Vector contents may be altered by the function)
|
||||
* - len : Number of input samples
|
||||
*
|
||||
* Output:
|
||||
* - inst : Updated user information
|
||||
* - outData : Pointer to a memory space where the output data
|
||||
* should be stored
|
||||
* - pw16_len : Pointer to variable where the number of samples
|
||||
* produced will be written
|
||||
*
|
||||
* Return value : >=0 - Number of samples written to outData
|
||||
* -1 - Error
|
||||
*/
|
||||
|
||||
int WebRtcNetEQ_Normal(DSPInst_t *inst,
|
||||
#ifdef SCRATCH
|
||||
int16_t *pw16_scratchPtr,
|
||||
#endif
|
||||
int16_t *pw16_decoded, int16_t len,
|
||||
int16_t *pw16_outData, int16_t *pw16_len)
|
||||
{
|
||||
|
||||
int i;
|
||||
int16_t fs_mult;
|
||||
int16_t fs_shift;
|
||||
int32_t w32_En_speech;
|
||||
int16_t enLen;
|
||||
int16_t w16_muted;
|
||||
int16_t w16_inc, w16_frac;
|
||||
int16_t w16_tmp;
|
||||
int32_t w32_tmp;
|
||||
|
||||
/* Sanity check */
|
||||
if (len < 0)
|
||||
{
|
||||
/* Cannot have negative length of input vector */
|
||||
return (-1);
|
||||
}
|
||||
|
||||
if (len == 0)
|
||||
{
|
||||
/* Still got some data to play => continue with the same mode */
|
||||
*pw16_len = len;
|
||||
return (len);
|
||||
}
|
||||
|
||||
fs_mult = WebRtcSpl_DivW32W16ResW16(inst->fs, 8000);
|
||||
fs_shift = 30 - WebRtcSpl_NormW32(fs_mult); /* Note that this is not "exact" for 48kHz */
|
||||
|
||||
/*
|
||||
* Check if last RecOut call resulted in an Expand or a FadeToBGN. If so, we have to take
|
||||
* care of some cross-fading and unmuting.
|
||||
*/
|
||||
if (inst->w16_mode == MODE_EXPAND || inst->w16_mode == MODE_FADE_TO_BGN)
|
||||
{
|
||||
|
||||
/* Define memory where temporary result from Expand algorithm can be stored. */
|
||||
#ifdef SCRATCH
|
||||
int16_t *pw16_expanded = pw16_scratchPtr + SCRATCH_PW16_EXPANDED;
|
||||
#else
|
||||
int16_t pw16_expanded[FSMULT * 125];
|
||||
#endif
|
||||
int16_t expandedLen = 0;
|
||||
int16_t w16_decodedMax;
|
||||
|
||||
/* Find largest value in new data */
|
||||
w16_decodedMax = WebRtcSpl_MaxAbsValueW16(pw16_decoded, (int16_t) len);
|
||||
|
||||
/* Generate interpolation data using Expand */
|
||||
/* First, set Expand parameters to appropriate values. */
|
||||
inst->ExpandInst.w16_lagsPosition = 0;
|
||||
inst->ExpandInst.w16_lagsDirection = 0;
|
||||
inst->ExpandInst.w16_stopMuting = 1; /* Do not mute signal any more */
|
||||
|
||||
/* Call Expand */
|
||||
WebRtcNetEQ_Expand(inst,
|
||||
#ifdef SCRATCH
|
||||
pw16_scratchPtr + SCRATCH_NETEQ_EXPAND,
|
||||
#endif
|
||||
pw16_expanded, &expandedLen, (int16_t) (inst->w16_mode == MODE_FADE_TO_BGN));
|
||||
|
||||
inst->ExpandInst.w16_stopMuting = 0; /* Restore value */
|
||||
inst->ExpandInst.w16_consecExp = 0; /* Last was not Expand any more */
|
||||
|
||||
/* Adjust muting factor (main muting factor times expand muting factor) */
|
||||
if (inst->w16_mode == MODE_FADE_TO_BGN)
|
||||
{
|
||||
/* If last mode was FadeToBGN, the mute factor should be zero. */
|
||||
inst->w16_muteFactor = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* w16_muteFactor * w16_expandMuteFactor */
|
||||
inst->w16_muteFactor
|
||||
= (int16_t) WEBRTC_SPL_MUL_16_16_RSFT(inst->w16_muteFactor,
|
||||
inst->ExpandInst.w16_expandMuteFactor, 14);
|
||||
}
|
||||
|
||||
/* Adjust muting factor if needed (to BGN level) */
|
||||
enLen = WEBRTC_SPL_MIN(fs_mult<<6, len); /* min( fs_mult * 64, len ) */
|
||||
w16_tmp = 6 + fs_shift - WebRtcSpl_NormW32(
|
||||
WEBRTC_SPL_MUL_16_16(w16_decodedMax, w16_decodedMax));
|
||||
w16_tmp = WEBRTC_SPL_MAX(w16_tmp, 0);
|
||||
w32_En_speech = WebRtcNetEQ_DotW16W16(pw16_decoded, pw16_decoded, enLen, w16_tmp);
|
||||
w32_En_speech = WebRtcSpl_DivW32W16(w32_En_speech, (int16_t) (enLen >> w16_tmp));
|
||||
|
||||
if ((w32_En_speech != 0) && (w32_En_speech > inst->BGNInst.w32_energy))
|
||||
{
|
||||
/* Normalize new frame energy to 15 bits */
|
||||
w16_tmp = WebRtcSpl_NormW32(w32_En_speech) - 16;
|
||||
/* we want inst->BGNInst.energy/En_speech in Q14 */
|
||||
w32_tmp = WEBRTC_SPL_SHIFT_W32(inst->BGNInst.w32_energy, (w16_tmp+14));
|
||||
w16_tmp = (int16_t) WEBRTC_SPL_SHIFT_W32(w32_En_speech, w16_tmp);
|
||||
w16_tmp = (int16_t) WebRtcSpl_DivW32W16(w32_tmp, w16_tmp);
|
||||
w16_muted = (int16_t) WebRtcSpl_SqrtFloor(
|
||||
WEBRTC_SPL_LSHIFT_W32((int32_t) w16_tmp,
|
||||
14)); /* w16_muted in Q14 (sqrt(Q28)) */
|
||||
}
|
||||
else
|
||||
{
|
||||
w16_muted = 16384; /* 1.0 in Q14 */
|
||||
}
|
||||
if (w16_muted > inst->w16_muteFactor)
|
||||
{
|
||||
inst->w16_muteFactor = WEBRTC_SPL_MIN(w16_muted, 16384);
|
||||
}
|
||||
|
||||
/* If muted increase by 0.64 for every 20 ms (NB/WB 0.0040/0.0020 in Q14) */
|
||||
w16_inc = WebRtcSpl_DivW32W16ResW16(64, fs_mult);
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
/* scale with mute factor */
|
||||
w32_tmp = WEBRTC_SPL_MUL_16_16(pw16_decoded[i], inst->w16_muteFactor);
|
||||
/* shift 14 with proper rounding */
|
||||
pw16_decoded[i] = (int16_t) WEBRTC_SPL_RSHIFT_W32((w32_tmp + 8192), 14);
|
||||
/* increase mute_factor towards 16384 */
|
||||
inst->w16_muteFactor = WEBRTC_SPL_MIN(16384, (inst->w16_muteFactor+w16_inc));
|
||||
}
|
||||
|
||||
/*
|
||||
* Interpolate the expanded data into the new vector
|
||||
* (NB/WB/SWB32/SWB40 8/16/32/32 samples)
|
||||
*/
|
||||
fs_shift = WEBRTC_SPL_MIN(3, fs_shift); /* Set to 3 for >32kHz */
|
||||
w16_inc = 4 >> fs_shift;
|
||||
w16_frac = w16_inc;
|
||||
for (i = 0; i < 8 * fs_mult; i++)
|
||||
{
|
||||
pw16_decoded[i] = (int16_t) WEBRTC_SPL_RSHIFT_W32(
|
||||
(WEBRTC_SPL_MUL_16_16(w16_frac, pw16_decoded[i]) +
|
||||
WEBRTC_SPL_MUL_16_16((32 - w16_frac), pw16_expanded[i]) + 8),
|
||||
5);
|
||||
w16_frac += w16_inc;
|
||||
}
|
||||
|
||||
#ifdef NETEQ_CNG_CODEC
|
||||
}
|
||||
else if (inst->w16_mode==MODE_RFC3389CNG)
|
||||
{ /* previous was RFC 3389 CNG...*/
|
||||
int16_t pw16_CngInterp[32];
|
||||
/* Reset mute factor and start up fresh */
|
||||
inst->w16_muteFactor = 16384;
|
||||
if (inst->CNG_Codec_inst != NULL)
|
||||
{
|
||||
/* Generate long enough for 32kHz */
|
||||
if(WebRtcCng_Generate(inst->CNG_Codec_inst,pw16_CngInterp, 32, 0)<0)
|
||||
{
|
||||
/* error returned; set return vector to all zeros */
|
||||
WebRtcSpl_MemSetW16(pw16_CngInterp, 0, 32);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
* If no CNG instance is defined, just copy from the decoded data.
|
||||
* (This will result in interpolating the decoded with itself.)
|
||||
*/
|
||||
WEBRTC_SPL_MEMCPY_W16(pw16_CngInterp, pw16_decoded, fs_mult * 8);
|
||||
}
|
||||
/*
|
||||
* Interpolate the CNG into the new vector
|
||||
* (NB/WB/SWB32kHz/SWB48kHz 8/16/32/32 samples)
|
||||
*/
|
||||
fs_shift = WEBRTC_SPL_MIN(3, fs_shift); /* Set to 3 for >32kHz */
|
||||
w16_inc = 4>>fs_shift;
|
||||
w16_frac = w16_inc;
|
||||
for (i = 0; i < 8 * fs_mult; i++)
|
||||
{
|
||||
pw16_decoded[i] = (int16_t) WEBRTC_SPL_RSHIFT_W32(
|
||||
(WEBRTC_SPL_MUL_16_16(w16_frac, pw16_decoded[i]) +
|
||||
WEBRTC_SPL_MUL_16_16((32-w16_frac), pw16_CngInterp[i]) + 8),
|
||||
5);
|
||||
w16_frac += w16_inc;
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
else if (inst->w16_muteFactor < 16384)
|
||||
{
|
||||
/*
|
||||
* Previous was neither of Expand, FadeToBGN or RFC3389_CNG, but we are still
|
||||
* ramping up from previous muting.
|
||||
* If muted increase by 0.64 for every 20 ms (NB/WB 0.0040/0.0020 in Q14)
|
||||
*/
|
||||
w16_inc = WebRtcSpl_DivW32W16ResW16(64, fs_mult);
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
/* scale with mute factor */
|
||||
w32_tmp = WEBRTC_SPL_MUL_16_16(pw16_decoded[i], inst->w16_muteFactor);
|
||||
/* shift 14 with proper rounding */
|
||||
pw16_decoded[i] = (int16_t) WEBRTC_SPL_RSHIFT_W32((w32_tmp + 8192), 14);
|
||||
/* increase mute_factor towards 16384 */
|
||||
inst->w16_muteFactor = WEBRTC_SPL_MIN(16384, (inst->w16_muteFactor+w16_inc));
|
||||
}
|
||||
}
|
||||
|
||||
/* Copy data to other buffer */WEBRTC_SPL_MEMMOVE_W16(pw16_outData, pw16_decoded, len);
|
||||
|
||||
inst->w16_mode = MODE_NORMAL;
|
||||
*pw16_len = len;
|
||||
return (len);
|
||||
|
||||
}
|
||||
|
||||
#undef SCRATCH_PW16_EXPANDED
|
||||
#undef SCRATCH_NETEQ_EXPAND
|
||||
|
@ -1,851 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Implementation of the actual packet buffer data structure.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include "packet_buffer.h"
|
||||
|
||||
#include <string.h> /* to define NULL */
|
||||
|
||||
#include "signal_processing_library.h"
|
||||
|
||||
#include "mcu_dsp_common.h"
|
||||
|
||||
#include "neteq_error_codes.h"
|
||||
|
||||
#ifdef NETEQ_DELAY_LOGGING
|
||||
/* special code for offline delay logging */
|
||||
#include "delay_logging.h"
|
||||
#include <stdio.h>
|
||||
|
||||
extern FILE *delay_fid2; /* file pointer to delay log file */
|
||||
extern uint32_t tot_received_packets;
|
||||
#endif /* NETEQ_DELAY_LOGGING */
|
||||
|
||||
|
||||
int WebRtcNetEQ_PacketBufferInit(PacketBuf_t *bufferInst, int maxNoOfPackets,
|
||||
int16_t *pw16_memory, int memorySize)
|
||||
{
|
||||
int i;
|
||||
int pos = 0;
|
||||
|
||||
/* Sanity check */
|
||||
if ((memorySize < PBUFFER_MIN_MEMORY_SIZE) || (pw16_memory == NULL)
|
||||
|| (maxNoOfPackets < 2) || (maxNoOfPackets > 600))
|
||||
{
|
||||
/* Invalid parameters */
|
||||
return (PBUFFER_INIT_ERROR);
|
||||
}
|
||||
|
||||
/* Clear the buffer instance */
|
||||
WebRtcSpl_MemSetW16((int16_t*) bufferInst, 0,
|
||||
sizeof(PacketBuf_t) / sizeof(int16_t));
|
||||
|
||||
/* Clear the buffer memory */
|
||||
WebRtcSpl_MemSetW16((int16_t*) pw16_memory, 0, memorySize);
|
||||
|
||||
/* Set maximum number of packets */
|
||||
bufferInst->maxInsertPositions = maxNoOfPackets;
|
||||
|
||||
/* Initialize array pointers */
|
||||
/* After each pointer has been set, the index pos is advanced to point immediately
|
||||
* after the the recently allocated vector. Note that one step for the pos index
|
||||
* corresponds to a int16_t.
|
||||
*/
|
||||
|
||||
bufferInst->timeStamp = (uint32_t*) &pw16_memory[pos];
|
||||
pos += maxNoOfPackets << 1; /* advance maxNoOfPackets * uint32_t */
|
||||
|
||||
bufferInst->payloadLocation = (int16_t**) &pw16_memory[pos];
|
||||
pos += maxNoOfPackets * (sizeof(int16_t*) / sizeof(int16_t)); /* advance */
|
||||
|
||||
bufferInst->seqNumber = (uint16_t*) &pw16_memory[pos];
|
||||
pos += maxNoOfPackets; /* advance maxNoOfPackets * uint16_t */
|
||||
|
||||
bufferInst->payloadType = &pw16_memory[pos];
|
||||
pos += maxNoOfPackets; /* advance maxNoOfPackets * int16_t */
|
||||
|
||||
bufferInst->payloadLengthBytes = &pw16_memory[pos];
|
||||
pos += maxNoOfPackets; /* advance maxNoOfPackets * int16_t */
|
||||
|
||||
bufferInst->rcuPlCntr = &pw16_memory[pos];
|
||||
pos += maxNoOfPackets; /* advance maxNoOfPackets * int16_t */
|
||||
|
||||
bufferInst->waitingTime = (int*) (&pw16_memory[pos]);
|
||||
/* Advance maxNoOfPackets * sizeof(waitingTime element). */
|
||||
pos += maxNoOfPackets *
|
||||
sizeof(*bufferInst->waitingTime) / sizeof(*pw16_memory);
|
||||
|
||||
/* The payload memory starts after the slot arrays */
|
||||
bufferInst->startPayloadMemory = &pw16_memory[pos];
|
||||
bufferInst->currentMemoryPos = bufferInst->startPayloadMemory;
|
||||
bufferInst->memorySizeW16 = (memorySize - pos); /* Remaining memory */
|
||||
|
||||
/* Initialize each payload slot as empty with infinite delay */
|
||||
for (i = 0; i < bufferInst->maxInsertPositions; i++)
|
||||
{
|
||||
bufferInst->payloadType[i] = -1;
|
||||
}
|
||||
|
||||
/* Reset buffer parameters */
|
||||
bufferInst->numPacketsInBuffer = 0;
|
||||
bufferInst->packSizeSamples = 0;
|
||||
bufferInst->insertPosition = 0;
|
||||
|
||||
/* Reset buffer statistics */
|
||||
bufferInst->discardedPackets = 0;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
||||
int WebRtcNetEQ_PacketBufferFlush(PacketBuf_t *bufferInst)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* Sanity check */
|
||||
if (bufferInst->startPayloadMemory == NULL)
|
||||
{
|
||||
/* Packet buffer has not been initialized */
|
||||
/* Don't do the flushing operation, since we do not
|
||||
know the state of the struct variables */
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* Set all payload lengths to zero */
|
||||
WebRtcSpl_MemSetW16(bufferInst->payloadLengthBytes, 0, bufferInst->maxInsertPositions);
|
||||
|
||||
/* Reset buffer variables */
|
||||
bufferInst->numPacketsInBuffer = 0;
|
||||
bufferInst->currentMemoryPos = bufferInst->startPayloadMemory;
|
||||
bufferInst->insertPosition = 0;
|
||||
|
||||
/* Clear all slots, starting with the last one */
|
||||
for (i = (bufferInst->maxInsertPositions - 1); i >= 0; i--)
|
||||
{
|
||||
bufferInst->payloadType[i] = -1;
|
||||
bufferInst->timeStamp[i] = 0;
|
||||
bufferInst->seqNumber[i] = 0;
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
||||
int WebRtcNetEQ_PacketBufferInsert(PacketBuf_t *bufferInst, const RTPPacket_t *RTPpacket,
|
||||
int16_t *flushed, int av_sync)
|
||||
{
|
||||
int nextPos;
|
||||
int i;
|
||||
|
||||
#ifdef NETEQ_DELAY_LOGGING
|
||||
/* special code for offline delay logging */
|
||||
int temp_var;
|
||||
#endif /* NETEQ_DELAY_LOGGING */
|
||||
|
||||
/* Initialize to "no flush" */
|
||||
*flushed = 0;
|
||||
|
||||
/* Sanity check */
|
||||
if (bufferInst->startPayloadMemory == NULL)
|
||||
{
|
||||
/* packet buffer has not been initialized */
|
||||
return (-1);
|
||||
}
|
||||
|
||||
/* Sanity check for payload length
|
||||
(payloadLen in bytes and memory size in int16_t) */
|
||||
if ((RTPpacket->payloadLen > (bufferInst->memorySizeW16 << 1)) || (RTPpacket->payloadLen
|
||||
<= 0))
|
||||
{
|
||||
/* faulty or too long payload length */
|
||||
return (-1);
|
||||
}
|
||||
|
||||
/* If we are in AV-sync mode, there is a risk that we have inserted a sync
|
||||
* packet but now received the real version of it. Or because of some timing
|
||||
* we might be overwriting a true payload with sync (I'm not sure why this
|
||||
* should happen in regular case, but in some FEC enabled case happens).
|
||||
* Go through packets and delete the sync version of the packet in hand. Or
|
||||
* if this is sync packet and the regular version of it exists in the buffer
|
||||
* refrain from inserting.
|
||||
*
|
||||
* TODO(turajs): Could we get this for free if we had set the RCU-counter of
|
||||
* the sync packet to a number larger than 2?
|
||||
*/
|
||||
if (av_sync) {
|
||||
for (i = 0; i < bufferInst->maxInsertPositions; ++i) {
|
||||
/* Check if sequence numbers match and the payload actually exists. */
|
||||
if (bufferInst->seqNumber[i] == RTPpacket->seqNumber &&
|
||||
bufferInst->payloadLengthBytes[i] > 0) {
|
||||
if (WebRtcNetEQ_IsSyncPayload(RTPpacket->payload,
|
||||
RTPpacket->payloadLen)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (WebRtcNetEQ_IsSyncPayload(bufferInst->payloadLocation[i],
|
||||
bufferInst->payloadLengthBytes[i])) {
|
||||
/* Clear the position in the buffer. */
|
||||
bufferInst->payloadType[i] = -1;
|
||||
bufferInst->payloadLengthBytes[i] = 0;
|
||||
|
||||
/* Reduce packet counter by one. */
|
||||
bufferInst->numPacketsInBuffer--;
|
||||
/* TODO(turajs) if this is the latest packet better we rewind
|
||||
* insertPosition and related variables. */
|
||||
break; /* There should be only one match. */
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Find a position in the buffer for this packet */
|
||||
if (bufferInst->numPacketsInBuffer != 0)
|
||||
{
|
||||
/* Get the next slot */
|
||||
bufferInst->insertPosition++;
|
||||
if (bufferInst->insertPosition >= bufferInst->maxInsertPositions)
|
||||
{
|
||||
/* "Wrap around" and start from the beginning */
|
||||
bufferInst->insertPosition = 0;
|
||||
}
|
||||
|
||||
/* Check if there is enough space for the new packet */
|
||||
if (bufferInst->currentMemoryPos + ((RTPpacket->payloadLen + 1) >> 1)
|
||||
>= &bufferInst->startPayloadMemory[bufferInst->memorySizeW16])
|
||||
{
|
||||
int16_t *tempMemAddress;
|
||||
|
||||
/*
|
||||
* Payload does not fit at the end of the memory, put it in the beginning
|
||||
* instead
|
||||
*/
|
||||
bufferInst->currentMemoryPos = bufferInst->startPayloadMemory;
|
||||
|
||||
/*
|
||||
* Now, we must search for the next non-empty payload,
|
||||
* finding the one with the lowest start address for the payload
|
||||
*/
|
||||
tempMemAddress = &bufferInst->startPayloadMemory[bufferInst->memorySizeW16];
|
||||
nextPos = -1;
|
||||
|
||||
/* Loop through all slots again */
|
||||
for (i = 0; i < bufferInst->maxInsertPositions; i++)
|
||||
{
|
||||
/* Look for the non-empty slot with the lowest
|
||||
payload location address */
|
||||
if (bufferInst->payloadLengthBytes[i] != 0 && bufferInst->payloadLocation[i]
|
||||
< tempMemAddress)
|
||||
{
|
||||
tempMemAddress = bufferInst->payloadLocation[i];
|
||||
nextPos = i;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check that we did find a previous payload */
|
||||
if (nextPos == -1)
|
||||
{
|
||||
/* The buffer is corrupt => flush and return error */
|
||||
WebRtcNetEQ_PacketBufferFlush(bufferInst);
|
||||
*flushed = 1;
|
||||
return (-1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Payload fits at the end of memory. */
|
||||
|
||||
/* Find the next non-empty slot. */
|
||||
nextPos = bufferInst->insertPosition + 1;
|
||||
|
||||
/* Increase nextPos until a non-empty slot is found or end of array is encountered*/
|
||||
while ((bufferInst->payloadLengthBytes[nextPos] == 0) && (nextPos
|
||||
< bufferInst->maxInsertPositions))
|
||||
{
|
||||
nextPos++;
|
||||
}
|
||||
|
||||
if (nextPos == bufferInst->maxInsertPositions)
|
||||
{
|
||||
/*
|
||||
* Reached the end of the array, so there must be a packet in the first
|
||||
* position instead
|
||||
*/
|
||||
nextPos = 0;
|
||||
|
||||
/* Increase nextPos until a non-empty slot is found */
|
||||
while (bufferInst->payloadLengthBytes[nextPos] == 0)
|
||||
{
|
||||
nextPos++;
|
||||
}
|
||||
}
|
||||
} /* end if-else */
|
||||
|
||||
/*
|
||||
* Check if the new payload will extend into a payload later in memory.
|
||||
* If so, the buffer is full.
|
||||
*/
|
||||
if ((bufferInst->currentMemoryPos <= bufferInst->payloadLocation[nextPos])
|
||||
&& ((&bufferInst->currentMemoryPos[(RTPpacket->payloadLen + 1) >> 1])
|
||||
> bufferInst->payloadLocation[nextPos]))
|
||||
{
|
||||
/* Buffer is full, so the buffer must be flushed */
|
||||
WebRtcNetEQ_PacketBufferFlush(bufferInst);
|
||||
*flushed = 1;
|
||||
}
|
||||
|
||||
if (bufferInst->payloadLengthBytes[bufferInst->insertPosition] != 0)
|
||||
{
|
||||
/* All positions are already taken and entire buffer should be flushed */
|
||||
WebRtcNetEQ_PacketBufferFlush(bufferInst);
|
||||
*flushed = 1;
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Buffer is empty, just insert the packet at the beginning */
|
||||
bufferInst->currentMemoryPos = bufferInst->startPayloadMemory;
|
||||
bufferInst->insertPosition = 0;
|
||||
}
|
||||
|
||||
/* Insert packet in the found position */
|
||||
if (RTPpacket->starts_byte1 == 0)
|
||||
{
|
||||
/* Payload is 16-bit aligned => just copy it */
|
||||
|
||||
WEBRTC_SPL_MEMCPY_W8(bufferInst->currentMemoryPos,
|
||||
RTPpacket->payload, RTPpacket->payloadLen);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Payload is not 16-bit aligned => align it during copy operation */
|
||||
for (i = 0; i < RTPpacket->payloadLen; i++)
|
||||
{
|
||||
/* copy the (i+1)-th byte to the i-th byte */
|
||||
|
||||
WEBRTC_SPL_SET_BYTE(bufferInst->currentMemoryPos,
|
||||
(WEBRTC_SPL_GET_BYTE(RTPpacket->payload, (i + 1))), i);
|
||||
}
|
||||
}
|
||||
|
||||
/* Copy the packet information */
|
||||
bufferInst->payloadLocation[bufferInst->insertPosition] = bufferInst->currentMemoryPos;
|
||||
bufferInst->payloadLengthBytes[bufferInst->insertPosition] = RTPpacket->payloadLen;
|
||||
bufferInst->payloadType[bufferInst->insertPosition] = RTPpacket->payloadType;
|
||||
bufferInst->seqNumber[bufferInst->insertPosition] = RTPpacket->seqNumber;
|
||||
bufferInst->timeStamp[bufferInst->insertPosition] = RTPpacket->timeStamp;
|
||||
bufferInst->rcuPlCntr[bufferInst->insertPosition] = RTPpacket->rcuPlCntr;
|
||||
bufferInst->waitingTime[bufferInst->insertPosition] = 0;
|
||||
/* Update buffer parameters */
|
||||
bufferInst->numPacketsInBuffer++;
|
||||
bufferInst->currentMemoryPos += (RTPpacket->payloadLen + 1) >> 1;
|
||||
|
||||
#ifdef NETEQ_DELAY_LOGGING
|
||||
/* special code for offline delay logging */
|
||||
if (*flushed)
|
||||
{
|
||||
temp_var = NETEQ_DELAY_LOGGING_SIGNAL_FLUSH;
|
||||
if (fwrite(&temp_var, sizeof(int), 1, delay_fid2) != 1) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
temp_var = NETEQ_DELAY_LOGGING_SIGNAL_RECIN;
|
||||
if ((fwrite(&temp_var, sizeof(int),
|
||||
1, delay_fid2) != 1) ||
|
||||
(fwrite(&RTPpacket->timeStamp, sizeof(uint32_t),
|
||||
1, delay_fid2) != 1) ||
|
||||
(fwrite(&RTPpacket->seqNumber, sizeof(uint16_t),
|
||||
1, delay_fid2) != 1) ||
|
||||
(fwrite(&RTPpacket->payloadType, sizeof(int),
|
||||
1, delay_fid2) != 1) ||
|
||||
(fwrite(&RTPpacket->payloadLen, sizeof(int16_t),
|
||||
1, delay_fid2) != 1)) {
|
||||
return -1;
|
||||
}
|
||||
tot_received_packets++;
|
||||
#endif /* NETEQ_DELAY_LOGGING */
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
||||
int WebRtcNetEQ_PacketBufferExtract(PacketBuf_t *bufferInst, RTPPacket_t *RTPpacket,
|
||||
int bufferPosition, int *waitingTime)
|
||||
{
|
||||
|
||||
/* Sanity check */
|
||||
if (bufferInst->startPayloadMemory == NULL)
|
||||
{
|
||||
/* packet buffer has not been initialized */
|
||||
return (PBUFFER_NOT_INITIALIZED);
|
||||
}
|
||||
|
||||
if (bufferPosition < 0 || bufferPosition >= bufferInst->maxInsertPositions)
|
||||
{
|
||||
/* buffer position is outside valid range */
|
||||
return (NETEQ_OTHER_ERROR);
|
||||
}
|
||||
|
||||
/* Check that there is a valid payload in the specified position */
|
||||
if (bufferInst->payloadLengthBytes[bufferPosition] <= 0)
|
||||
{
|
||||
/* The position does not contain a valid payload */
|
||||
RTPpacket->payloadLen = 0; /* Set zero length */
|
||||
return (PBUFFER_NONEXISTING_PACKET); /* Return error */
|
||||
}
|
||||
|
||||
/* Payload exists => extract payload data */
|
||||
|
||||
/* Copy the actual data payload to RTP packet struct */
|
||||
|
||||
WEBRTC_SPL_MEMCPY_W16((int16_t*) RTPpacket->payload,
|
||||
bufferInst->payloadLocation[bufferPosition],
|
||||
(bufferInst->payloadLengthBytes[bufferPosition] + 1) >> 1); /*length in int16_t*/
|
||||
|
||||
/* Copy payload parameters */
|
||||
RTPpacket->payloadLen = bufferInst->payloadLengthBytes[bufferPosition];
|
||||
RTPpacket->payloadType = bufferInst->payloadType[bufferPosition];
|
||||
RTPpacket->seqNumber = bufferInst->seqNumber[bufferPosition];
|
||||
RTPpacket->timeStamp = bufferInst->timeStamp[bufferPosition];
|
||||
RTPpacket->rcuPlCntr = bufferInst->rcuPlCntr[bufferPosition];
|
||||
*waitingTime = bufferInst->waitingTime[bufferPosition];
|
||||
RTPpacket->starts_byte1 = 0; /* payload is 16-bit aligned */
|
||||
|
||||
/* Clear the position in the packet buffer */
|
||||
bufferInst->payloadType[bufferPosition] = -1;
|
||||
bufferInst->payloadLengthBytes[bufferPosition] = 0;
|
||||
bufferInst->seqNumber[bufferPosition] = 0;
|
||||
bufferInst->timeStamp[bufferPosition] = 0;
|
||||
bufferInst->waitingTime[bufferPosition] = 0;
|
||||
bufferInst->payloadLocation[bufferPosition] = bufferInst->startPayloadMemory;
|
||||
|
||||
/* Reduce packet counter with one */
|
||||
bufferInst->numPacketsInBuffer--;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int WebRtcNetEQ_PacketBufferFindLowestTimestamp(PacketBuf_t* buffer_inst,
|
||||
uint32_t current_time_stamp,
|
||||
uint32_t* time_stamp,
|
||||
int* buffer_position,
|
||||
int erase_old_packets,
|
||||
int16_t* payload_type) {
|
||||
int32_t time_stamp_diff = WEBRTC_SPL_WORD32_MAX; /* Smallest diff found. */
|
||||
int32_t new_diff;
|
||||
int i;
|
||||
int16_t rcu_payload_cntr;
|
||||
if (buffer_inst->startPayloadMemory == NULL) {
|
||||
/* Packet buffer has not been initialized. */
|
||||
return PBUFFER_NOT_INITIALIZED;
|
||||
}
|
||||
|
||||
/* Initialize all return values. */
|
||||
*time_stamp = 0;
|
||||
*payload_type = -1; /* Indicates that no packet was found. */
|
||||
*buffer_position = -1; /* Indicates that no packet was found. */
|
||||
rcu_payload_cntr = WEBRTC_SPL_WORD16_MAX; /* Indicates no packet found. */
|
||||
|
||||
/* Check if buffer is empty. */
|
||||
if (buffer_inst->numPacketsInBuffer <= 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Loop through all slots in buffer. */
|
||||
if (erase_old_packets) { /* If old payloads should be discarded. */
|
||||
for (i = 0; i < buffer_inst->maxInsertPositions; ++i) {
|
||||
/* Calculate difference between this slot and current_time_stamp. */
|
||||
new_diff = (int32_t)(buffer_inst->timeStamp[i] - current_time_stamp);
|
||||
|
||||
/* Check if payload should be discarded. */
|
||||
if ((new_diff < 0) /* Payload is too old */
|
||||
&& (new_diff > -30000) /* Account for TS wrap-around. */
|
||||
&& (buffer_inst->payloadLengthBytes[i] > 0)) { /* Payload exists. */
|
||||
/* Throw away old packet. */
|
||||
|
||||
/* Clear the position in the buffer. */
|
||||
buffer_inst->payloadType[i] = -1;
|
||||
buffer_inst->payloadLengthBytes[i] = 0;
|
||||
|
||||
/* Reduce packet counter by one. */
|
||||
buffer_inst->numPacketsInBuffer--;
|
||||
/* Increase discard counter for in-call statistics. */
|
||||
buffer_inst->discardedPackets++;
|
||||
} else if (((new_diff < time_stamp_diff)
|
||||
|| ((new_diff == time_stamp_diff)
|
||||
&& (buffer_inst->rcuPlCntr[i] < rcu_payload_cntr)))
|
||||
&& (buffer_inst->payloadLengthBytes[i] > 0)) {
|
||||
/* New diff is smaller than previous diffs or we have a candidate with a
|
||||
* time stamp as previous candidate but better RCU-counter;
|
||||
* and the payload exists.
|
||||
*/
|
||||
/* Save this position as the best candidate. */
|
||||
*buffer_position = i;
|
||||
time_stamp_diff = new_diff;
|
||||
*payload_type = buffer_inst->payloadType[i];
|
||||
rcu_payload_cntr = buffer_inst->rcuPlCntr[i];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (i = 0; i < buffer_inst->maxInsertPositions; ++i) {
|
||||
/* Calculate difference between this slot and current_time_stamp. */
|
||||
new_diff = (int32_t)(buffer_inst->timeStamp[i] - current_time_stamp);
|
||||
|
||||
/* Check if this is the oldest packet. */
|
||||
if (((new_diff < time_stamp_diff)
|
||||
|| ((new_diff == time_stamp_diff)
|
||||
&& (buffer_inst->rcuPlCntr[i] < rcu_payload_cntr)))
|
||||
&& (buffer_inst->payloadLengthBytes[i] > 0)) {
|
||||
/* New diff is smaller than previous diffs or we have a candidate with a
|
||||
* time_stamp as previous candidate but better RCU-counter;
|
||||
* and the payload exists.
|
||||
*/
|
||||
/* Save this position as the best candidate. */
|
||||
*buffer_position = i;
|
||||
time_stamp_diff = new_diff;
|
||||
*payload_type = buffer_inst->payloadType[i];
|
||||
rcu_payload_cntr = buffer_inst->rcuPlCntr[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Check that we did find a real position. */
|
||||
if (*buffer_position >= 0) {
|
||||
/* Get the time_stamp for the best position. */
|
||||
*time_stamp = buffer_inst->timeStamp[*buffer_position];
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int WebRtcNetEQ_PacketBufferGetPacketSize(const PacketBuf_t* buffer_inst,
|
||||
int buffer_pos,
|
||||
const CodecDbInst_t* codec_database,
|
||||
int codec_pos, int last_duration,
|
||||
int av_sync) {
|
||||
if (codec_database->funcDurationEst[codec_pos] == NULL) {
|
||||
return last_duration;
|
||||
}
|
||||
|
||||
if (av_sync != 0 &&
|
||||
WebRtcNetEQ_IsSyncPayload(buffer_inst->payloadLocation[buffer_pos],
|
||||
buffer_inst->payloadLengthBytes[buffer_pos])) {
|
||||
// In AV-sync and sync payload, report |last_duration| as current duration.
|
||||
return last_duration;
|
||||
}
|
||||
|
||||
return (*codec_database->funcDurationEst[codec_pos])(
|
||||
codec_database->codec_state[codec_pos],
|
||||
(const uint8_t *)buffer_inst->payloadLocation[buffer_pos],
|
||||
buffer_inst->payloadLengthBytes[buffer_pos]);
|
||||
}
|
||||
|
||||
int32_t WebRtcNetEQ_PacketBufferGetSize(const PacketBuf_t* buffer_inst,
|
||||
const CodecDbInst_t* codec_database,
|
||||
int av_sync) {
|
||||
int i, count;
|
||||
int last_duration;
|
||||
int last_codec_pos;
|
||||
int last_payload_type;
|
||||
int32_t size_samples;
|
||||
|
||||
count = 0;
|
||||
last_duration = buffer_inst->packSizeSamples;
|
||||
last_codec_pos = -1;
|
||||
last_payload_type = -1;
|
||||
size_samples = 0;
|
||||
|
||||
/* Loop through all slots in the buffer */
|
||||
for (i = 0; i < buffer_inst->maxInsertPositions; i++) {
|
||||
/* Only count the packets with non-zero size */
|
||||
if (buffer_inst->payloadLengthBytes[i] != 0) {
|
||||
int payload_type;
|
||||
int codec_pos;
|
||||
/* Figure out the codec database entry for this payload_type. */
|
||||
payload_type = buffer_inst->payloadType[i];
|
||||
/* Remember the last one, to avoid the database search. */
|
||||
if(payload_type == last_payload_type) {
|
||||
codec_pos = last_codec_pos;
|
||||
}
|
||||
else {
|
||||
codec_pos = WebRtcNetEQ_DbGetCodec(codec_database,
|
||||
payload_type);
|
||||
if (codec_pos >= 0) {
|
||||
codec_pos = codec_database->position[codec_pos];
|
||||
}
|
||||
}
|
||||
last_codec_pos = codec_pos;
|
||||
last_payload_type = payload_type;
|
||||
if (codec_pos >= 0) {
|
||||
/*
|
||||
* Right now WebRtcNetEQ_PacketBufferGetPacketSize either always
|
||||
* returns last_duration or always computes the real duration without
|
||||
* looking at last_duration. If an implementation really wanted to use
|
||||
* last_duration to compute a changing duration, we would have to
|
||||
* iterate through the packets in chronological order by timestamp.
|
||||
*/
|
||||
/* Check for error before setting. */
|
||||
int temp_last_duration = WebRtcNetEQ_PacketBufferGetPacketSize(
|
||||
buffer_inst, i, codec_database, codec_pos,
|
||||
last_duration, av_sync);
|
||||
if (temp_last_duration >= 0)
|
||||
last_duration = temp_last_duration;
|
||||
}
|
||||
/* Add in the size of this packet. */
|
||||
size_samples += last_duration;
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
/* Sanity check; size cannot be negative */
|
||||
if (size_samples < 0) {
|
||||
size_samples = 0;
|
||||
}
|
||||
return size_samples;
|
||||
}
|
||||
|
||||
void WebRtcNetEQ_IncrementWaitingTimes(PacketBuf_t *buffer_inst) {
|
||||
int i;
|
||||
/* Loop through all slots in the buffer. */
|
||||
for (i = 0; i < buffer_inst->maxInsertPositions; ++i) {
|
||||
/* Only increment waiting time for the packets with non-zero size. */
|
||||
if (buffer_inst->payloadLengthBytes[i] != 0) {
|
||||
buffer_inst->waitingTime[i]++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int WebRtcNetEQ_GetDefaultCodecSettings(const enum WebRtcNetEQDecoder *codecID,
|
||||
int noOfCodecs, int *maxBytes,
|
||||
int *maxSlots,
|
||||
int* per_slot_overhead_bytes)
|
||||
{
|
||||
int i;
|
||||
int ok = 0;
|
||||
int16_t w16_tmp;
|
||||
int16_t codecBytes;
|
||||
int16_t codecBuffers;
|
||||
|
||||
/* Initialize return variables to zero */
|
||||
*maxBytes = 0;
|
||||
*maxSlots = 0;
|
||||
|
||||
/* Loop through all codecs supplied to function */
|
||||
for (i = 0; i < noOfCodecs; i++)
|
||||
{
|
||||
/* Find current codec and set parameters accordingly */
|
||||
|
||||
if ((codecID[i] == kDecoderPCMu) || (codecID[i] == kDecoderPCMu_2ch))
|
||||
{
|
||||
codecBytes = 1680; /* Up to 210ms @ 64kbps */
|
||||
codecBuffers = 30; /* Down to 5ms frames */
|
||||
}
|
||||
else if ((codecID[i] == kDecoderPCMa) ||
|
||||
(codecID[i] == kDecoderPCMa_2ch))
|
||||
{
|
||||
codecBytes = 1680; /* Up to 210ms @ 64kbps */
|
||||
codecBuffers = 30; /* Down to 5ms frames */
|
||||
}
|
||||
else if (codecID[i] == kDecoderILBC)
|
||||
{
|
||||
codecBytes = 380; /* 200ms @ 15.2kbps (20ms frames) */
|
||||
codecBuffers = 10;
|
||||
}
|
||||
else if (codecID[i] == kDecoderISAC)
|
||||
{
|
||||
codecBytes = 960; /* 240ms @ 32kbps (60ms frames) */
|
||||
codecBuffers = 8;
|
||||
}
|
||||
else if ((codecID[i] == kDecoderISACswb) ||
|
||||
(codecID[i] == kDecoderISACfb))
|
||||
{
|
||||
codecBytes = 1560; /* 240ms @ 52kbps (30ms frames) */
|
||||
codecBuffers = 8;
|
||||
}
|
||||
else if (codecID[i] == kDecoderOpus)
|
||||
{
|
||||
codecBytes = 15300; /* 240ms @ 510kbps (60ms frames) */
|
||||
codecBuffers = 30; /* Replicating the value for PCMu/a */
|
||||
}
|
||||
else if ((codecID[i] == kDecoderPCM16B) ||
|
||||
(codecID[i] == kDecoderPCM16B_2ch))
|
||||
{
|
||||
codecBytes = 3360; /* 210ms */
|
||||
codecBuffers = 15;
|
||||
}
|
||||
else if ((codecID[i] == kDecoderPCM16Bwb) ||
|
||||
(codecID[i] == kDecoderPCM16Bwb_2ch))
|
||||
{
|
||||
codecBytes = 6720; /* 210ms */
|
||||
codecBuffers = 15;
|
||||
}
|
||||
else if ((codecID[i] == kDecoderPCM16Bswb32kHz) ||
|
||||
(codecID[i] == kDecoderPCM16Bswb32kHz_2ch))
|
||||
{
|
||||
codecBytes = 13440; /* 210ms */
|
||||
codecBuffers = 15;
|
||||
}
|
||||
else if (codecID[i] == kDecoderPCM16Bswb48kHz)
|
||||
{
|
||||
codecBytes = 20160; /* 210ms */
|
||||
codecBuffers = 15;
|
||||
}
|
||||
else if ((codecID[i] == kDecoderG722) ||
|
||||
(codecID[i] == kDecoderG722_2ch))
|
||||
{
|
||||
codecBytes = 1680; /* 210ms @ 64kbps */
|
||||
codecBuffers = 15;
|
||||
}
|
||||
else if (codecID[i] == kDecoderRED)
|
||||
{
|
||||
codecBytes = 0; /* Should not be max... */
|
||||
codecBuffers = 0;
|
||||
}
|
||||
else if (codecID[i] == kDecoderAVT)
|
||||
{
|
||||
codecBytes = 0; /* Should not be max... */
|
||||
codecBuffers = 0;
|
||||
}
|
||||
else if (codecID[i] == kDecoderCNG)
|
||||
{
|
||||
codecBytes = 0; /* Should not be max... */
|
||||
codecBuffers = 0;
|
||||
}
|
||||
else if (codecID[i] == kDecoderG729)
|
||||
{
|
||||
codecBytes = 210; /* 210ms @ 8kbps */
|
||||
codecBuffers = 20; /* max 200ms supported for 10ms frames */
|
||||
}
|
||||
else if (codecID[i] == kDecoderG729_1)
|
||||
{
|
||||
codecBytes = 840; /* 210ms @ 32kbps */
|
||||
codecBuffers = 10; /* max 200ms supported for 20ms frames */
|
||||
}
|
||||
else if (codecID[i] == kDecoderG726_16)
|
||||
{
|
||||
codecBytes = 400; /* 200ms @ 16kbps */
|
||||
codecBuffers = 10;
|
||||
}
|
||||
else if (codecID[i] == kDecoderG726_24)
|
||||
{
|
||||
codecBytes = 600; /* 200ms @ 24kbps */
|
||||
codecBuffers = 10;
|
||||
}
|
||||
else if (codecID[i] == kDecoderG726_32)
|
||||
{
|
||||
codecBytes = 800; /* 200ms @ 32kbps */
|
||||
codecBuffers = 10;
|
||||
}
|
||||
else if (codecID[i] == kDecoderG726_40)
|
||||
{
|
||||
codecBytes = 1000; /* 200ms @ 40kbps */
|
||||
codecBuffers = 10;
|
||||
}
|
||||
else if (codecID[i] == kDecoderG722_1_16)
|
||||
{
|
||||
codecBytes = 420; /* 210ms @ 16kbps */
|
||||
codecBuffers = 10;
|
||||
}
|
||||
else if (codecID[i] == kDecoderG722_1_24)
|
||||
{
|
||||
codecBytes = 630; /* 210ms @ 24kbps */
|
||||
codecBuffers = 10;
|
||||
}
|
||||
else if (codecID[i] == kDecoderG722_1_32)
|
||||
{
|
||||
codecBytes = 840; /* 210ms @ 32kbps */
|
||||
codecBuffers = 10;
|
||||
}
|
||||
else if (codecID[i] == kDecoderG722_1C_24)
|
||||
{
|
||||
codecBytes = 630; /* 210ms @ 24kbps */
|
||||
codecBuffers = 10;
|
||||
}
|
||||
else if (codecID[i] == kDecoderG722_1C_32)
|
||||
{
|
||||
codecBytes = 840; /* 210ms @ 32kbps */
|
||||
codecBuffers = 10;
|
||||
}
|
||||
else if (codecID[i] == kDecoderG722_1C_48)
|
||||
{
|
||||
codecBytes = 1260; /* 210ms @ 48kbps */
|
||||
codecBuffers = 10;
|
||||
}
|
||||
else if (codecID[i] == kDecoderSPEEX_8)
|
||||
{
|
||||
codecBytes = 1250; /* 210ms @ 50kbps */
|
||||
codecBuffers = 10;
|
||||
}
|
||||
else if (codecID[i] == kDecoderSPEEX_16)
|
||||
{
|
||||
codecBytes = 1250; /* 210ms @ 50kbps */
|
||||
codecBuffers = 10;
|
||||
}
|
||||
else if ((codecID[i] == kDecoderCELT_32) ||
|
||||
(codecID[i] == kDecoderCELT_32_2ch))
|
||||
{
|
||||
codecBytes = 1250; /* 210ms @ 50kbps */
|
||||
codecBuffers = 10;
|
||||
}
|
||||
else if (codecID[i] == kDecoderGSMFR)
|
||||
{
|
||||
codecBytes = 340; /* 200ms */
|
||||
codecBuffers = 10;
|
||||
}
|
||||
else if (codecID[i] == kDecoderAMR)
|
||||
{
|
||||
codecBytes = 384; /* 240ms @ 12.2kbps+headers (60ms frames) */
|
||||
codecBuffers = 10;
|
||||
}
|
||||
else if (codecID[i] == kDecoderAMRWB)
|
||||
{
|
||||
codecBytes = 744;
|
||||
codecBuffers = 10;
|
||||
}
|
||||
else if (codecID[i] == kDecoderArbitrary)
|
||||
{
|
||||
codecBytes = 6720; /* Assume worst case uncompressed WB 210ms */
|
||||
codecBuffers = 15;
|
||||
}
|
||||
else
|
||||
{
|
||||
/*Unknow codec */
|
||||
codecBytes = 0;
|
||||
codecBuffers = 0;
|
||||
ok = CODEC_DB_UNKNOWN_CODEC;
|
||||
}
|
||||
|
||||
/* Update max variables */
|
||||
*maxBytes = WEBRTC_SPL_MAX((*maxBytes), codecBytes);
|
||||
*maxSlots = WEBRTC_SPL_MAX((*maxSlots), codecBuffers);
|
||||
|
||||
} /* end of for loop */
|
||||
|
||||
/*
|
||||
* Add size needed by the additional pointers for each slot inside struct,
|
||||
* as indicated on each line below.
|
||||
*/
|
||||
w16_tmp = (sizeof(uint32_t) /* timeStamp */
|
||||
+ sizeof(int16_t*) /* payloadLocation */
|
||||
+ sizeof(uint16_t) /* seqNumber */
|
||||
+ sizeof(int16_t) /* payloadType */
|
||||
+ sizeof(int16_t) /* payloadLengthBytes */
|
||||
+ sizeof(int16_t) /* rcuPlCntr */
|
||||
+ sizeof(int)); /* waitingTime */
|
||||
/* Add the extra size per slot to the memory count */
|
||||
*maxBytes += w16_tmp * (*maxSlots);
|
||||
|
||||
*per_slot_overhead_bytes = w16_tmp;
|
||||
return ok;
|
||||
}
|
@ -1,254 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Interface for the actual packet buffer data structure.
|
||||
*/
|
||||
|
||||
#ifndef PACKET_BUFFER_H
|
||||
#define PACKET_BUFFER_H
|
||||
|
||||
#include "typedefs.h"
|
||||
|
||||
#include "webrtc_neteq.h"
|
||||
#include "rtp.h"
|
||||
|
||||
/* Define minimum allowed buffer memory, in 16-bit words */
|
||||
#define PBUFFER_MIN_MEMORY_SIZE 150
|
||||
|
||||
/****************************/
|
||||
/* The packet buffer struct */
|
||||
/****************************/
|
||||
|
||||
typedef struct
|
||||
{
|
||||
|
||||
/* Variables common to the entire buffer */
|
||||
uint16_t packSizeSamples; /* packet size in samples of last decoded packet */
|
||||
int16_t *startPayloadMemory; /* pointer to the payload memory */
|
||||
int memorySizeW16; /* the size (in int16_t) of the payload memory */
|
||||
int16_t *currentMemoryPos; /* The memory position to insert next payload */
|
||||
int numPacketsInBuffer; /* The number of packets in the buffer */
|
||||
int insertPosition; /* The position to insert next packet */
|
||||
int maxInsertPositions; /* Maximum number of packets allowed */
|
||||
|
||||
/* Arrays with one entry per packet slot */
|
||||
/* NOTE: If these are changed, the changes must be accounted for at the end of
|
||||
the function WebRtcNetEQ_GetDefaultCodecSettings(). */
|
||||
uint32_t *timeStamp; /* Timestamp in slot n */
|
||||
int16_t **payloadLocation; /* Memory location of payload in slot n */
|
||||
uint16_t *seqNumber; /* Sequence number in slot n */
|
||||
int16_t *payloadType; /* Payload type of packet in slot n */
|
||||
int16_t *payloadLengthBytes; /* Payload length of packet in slot n */
|
||||
int16_t *rcuPlCntr; /* zero for non-RCU payload, 1 for main payload
|
||||
2 for redundant payload */
|
||||
int *waitingTime;
|
||||
|
||||
/* Statistics counter */
|
||||
uint16_t discardedPackets; /* Number of discarded packets */
|
||||
|
||||
} PacketBuf_t;
|
||||
|
||||
/*************************/
|
||||
/* Function declarations */
|
||||
/*************************/
|
||||
|
||||
/****************************************************************************
|
||||
* WebRtcNetEQ_PacketBufferInit(...)
|
||||
*
|
||||
* This function initializes the packet buffer.
|
||||
*
|
||||
* Input:
|
||||
* - bufferInst : Buffer instance to be initialized
|
||||
* - noOfPackets : Maximum number of packets that buffer should hold
|
||||
* - memory : Pointer to the storage memory for the payloads
|
||||
* - memorySize : The size of the payload memory (in int16_t)
|
||||
*
|
||||
* Output:
|
||||
* - bufferInst : Updated buffer instance
|
||||
*
|
||||
* Return value : 0 - Ok
|
||||
* <0 - Error
|
||||
*/
|
||||
|
||||
int WebRtcNetEQ_PacketBufferInit(PacketBuf_t *bufferInst, int maxNoOfPackets,
|
||||
int16_t *pw16_memory, int memorySize);
|
||||
|
||||
/****************************************************************************
|
||||
* WebRtcNetEQ_PacketBufferFlush(...)
|
||||
*
|
||||
* This function flushes all the packets in the buffer.
|
||||
*
|
||||
* Input:
|
||||
* - bufferInst : Buffer instance to be flushed
|
||||
*
|
||||
* Output:
|
||||
* - bufferInst : Flushed buffer instance
|
||||
*
|
||||
* Return value : 0 - Ok
|
||||
*/
|
||||
|
||||
int WebRtcNetEQ_PacketBufferFlush(PacketBuf_t *bufferInst);
|
||||
|
||||
/****************************************************************************
|
||||
* WebRtcNetEQ_PacketBufferInsert(...)
|
||||
*
|
||||
* This function inserts an RTP packet into the packet buffer.
|
||||
*
|
||||
* Input:
|
||||
* - bufferInst : Buffer instance
|
||||
* - RTPpacket : An RTP packet struct (with payload, sequence
|
||||
* number, etc.)
|
||||
* - av_sync : 1 indicates AV-sync enabled, 0 disabled.
|
||||
*
|
||||
* Output:
|
||||
* - bufferInst : Updated buffer instance
|
||||
* - flushed : 1 if buffer was flushed, 0 otherwise
|
||||
*
|
||||
* Return value : 0 - Ok
|
||||
* -1 - Error
|
||||
*/
|
||||
|
||||
int WebRtcNetEQ_PacketBufferInsert(PacketBuf_t *bufferInst, const RTPPacket_t *RTPpacket,
|
||||
int16_t *flushed, int av_sync);
|
||||
|
||||
/****************************************************************************
|
||||
* WebRtcNetEQ_PacketBufferExtract(...)
|
||||
*
|
||||
* This function extracts a payload from the buffer.
|
||||
*
|
||||
* Input:
|
||||
* - bufferInst : Buffer instance
|
||||
* - bufferPosition: Position of the packet that should be extracted
|
||||
*
|
||||
* Output:
|
||||
* - RTPpacket : An RTP packet struct (with payload, sequence
|
||||
* number, etc)
|
||||
* - bufferInst : Updated buffer instance
|
||||
*
|
||||
* Return value : 0 - Ok
|
||||
* <0 - Error
|
||||
*/
|
||||
|
||||
int WebRtcNetEQ_PacketBufferExtract(PacketBuf_t *bufferInst, RTPPacket_t *RTPpacket,
|
||||
int bufferPosition, int *waitingTime);
|
||||
|
||||
/****************************************************************************
|
||||
* WebRtcNetEQ_PacketBufferFindLowestTimestamp(...)
|
||||
*
|
||||
* This function finds the next packet with the lowest timestamp.
|
||||
*
|
||||
* Input:
|
||||
* - buffer_inst : Buffer instance.
|
||||
* - current_time_stamp : The timestamp to compare packet timestamps with.
|
||||
* - erase_old_packets : If non-zero, erase packets older than currentTS.
|
||||
*
|
||||
* Output:
|
||||
* - time_stamp : Lowest timestamp that was found.
|
||||
* - buffer_position : Position of this packet (-1 if there are no
|
||||
* packets in the buffer).
|
||||
* - payload_type : Payload type of the found payload.
|
||||
*
|
||||
* Return value : 0 - Ok;
|
||||
* < 0 - Error.
|
||||
*/
|
||||
|
||||
int WebRtcNetEQ_PacketBufferFindLowestTimestamp(PacketBuf_t* buffer_inst,
|
||||
uint32_t current_time_stamp,
|
||||
uint32_t* time_stamp,
|
||||
int* buffer_position,
|
||||
int erase_old_packets,
|
||||
int16_t* payload_type);
|
||||
|
||||
/****************************************************************************
|
||||
* WebRtcNetEQ_PacketBufferGetPacketSize(...)
|
||||
*
|
||||
* Calculate and return an estimate of the data length (in samples) of the
|
||||
* given packet. If no estimate is available (because we do not know how to
|
||||
* compute packet durations for the associated payload type), last_duration
|
||||
* will be returned instead.
|
||||
*
|
||||
* Input:
|
||||
* - buffer_inst : Buffer instance
|
||||
* - buffer_pos : The index of the buffer of which to estimate the
|
||||
* duration
|
||||
* - codec_database : Codec database instance
|
||||
* - codec_pos : The codec database entry associated with the payload
|
||||
* type of the specified buffer.
|
||||
* - last_duration : The duration of the previous frame.
|
||||
* - av_sync : 1 indicates AV-sync enabled, 0 disabled.
|
||||
*
|
||||
* Return value : The buffer size in samples
|
||||
*/
|
||||
|
||||
int WebRtcNetEQ_PacketBufferGetPacketSize(const PacketBuf_t* buffer_inst,
|
||||
int buffer_pos,
|
||||
const CodecDbInst_t* codec_database,
|
||||
int codec_pos, int last_duration,
|
||||
int av_sync);
|
||||
|
||||
/****************************************************************************
|
||||
* WebRtcNetEQ_PacketBufferGetSize(...)
|
||||
*
|
||||
* Calculate and return an estimate of the total data length (in samples)
|
||||
* currently in the buffer. The estimate is calculated as the number of
|
||||
* packets currently in the buffer (which does not have any remaining waiting
|
||||
* time), multiplied with the number of samples obtained from the last
|
||||
* decoded packet.
|
||||
*
|
||||
* Input:
|
||||
* - buffer_inst : Buffer instance
|
||||
* - codec_database : Codec database instance
|
||||
* - av_sync : 1 indicates AV-sync enabled, 0 disabled.
|
||||
*
|
||||
* Return value : The buffer size in samples
|
||||
*/
|
||||
|
||||
int32_t WebRtcNetEQ_PacketBufferGetSize(const PacketBuf_t* buffer_inst,
|
||||
const CodecDbInst_t* codec_database,
|
||||
int av_sync);
|
||||
|
||||
/****************************************************************************
|
||||
* WebRtcNetEQ_IncrementWaitingTimes(...)
|
||||
*
|
||||
* Increment the waiting time for all packets in the buffer by one.
|
||||
*
|
||||
* Input:
|
||||
* - bufferInst : Buffer instance
|
||||
*
|
||||
* Return value : n/a
|
||||
*/
|
||||
|
||||
void WebRtcNetEQ_IncrementWaitingTimes(PacketBuf_t *buffer_inst);
|
||||
|
||||
/****************************************************************************
|
||||
* WebRtcNetEQ_GetDefaultCodecSettings(...)
|
||||
*
|
||||
* Calculates a recommended buffer size for a specific set of codecs.
|
||||
*
|
||||
* Input:
|
||||
* - codecID : An array of codec types that will be used
|
||||
* - noOfCodecs : Number of codecs in array codecID
|
||||
*
|
||||
* Output:
|
||||
* - maxBytes : Recommended buffer memory size in bytes
|
||||
* - maxSlots : Recommended number of slots in buffer
|
||||
* - per_slot_overhead_bytes : overhead in bytes for each slot in buffer.
|
||||
*
|
||||
* Return value : 0 - Ok
|
||||
* <0 - Error
|
||||
*/
|
||||
|
||||
int WebRtcNetEQ_GetDefaultCodecSettings(const enum WebRtcNetEQDecoder *codecID,
|
||||
int noOfCodecs, int *maxBytes,
|
||||
int *maxSlots,
|
||||
int* per_slot_overhead_bytes);
|
||||
|
||||
#endif /* PACKET_BUFFER_H */
|
@ -1,232 +0,0 @@
|
||||
/*
|
||||
* 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 the peak detection used for finding correlation peaks.
|
||||
*/
|
||||
|
||||
#include "dsp_helpfunctions.h"
|
||||
|
||||
#include "signal_processing_library.h"
|
||||
|
||||
/* Table of constants used in parabolic fit function WebRtcNetEQ_PrblFit */
|
||||
const int16_t WebRtcNetEQ_kPrblCf[17][3] = { { 120, 32, 64 }, { 140, 44, 75 },
|
||||
{ 150, 50, 80 }, { 160, 57, 85 },
|
||||
{ 180, 72, 96 }, { 200, 89, 107 },
|
||||
{ 210, 98, 112 }, { 220, 108, 117 },
|
||||
{ 240, 128, 128 }, { 260, 150, 139 },
|
||||
{ 270, 162, 144 }, { 280, 174, 149 },
|
||||
{ 300, 200, 160 }, { 320, 228, 171 },
|
||||
{ 330, 242, 176 }, { 340, 257, 181 },
|
||||
{ 360, 288, 192 } };
|
||||
|
||||
int16_t WebRtcNetEQ_PeakDetection(int16_t *pw16_data, int16_t w16_dataLen,
|
||||
int16_t w16_nmbPeaks, int16_t fs_mult,
|
||||
int16_t *pw16_winIndex,
|
||||
int16_t *pw16_winValue)
|
||||
{
|
||||
/* Local variables */
|
||||
int i;
|
||||
int16_t w16_tmp;
|
||||
int16_t w16_tmp2;
|
||||
int16_t indMin = 0;
|
||||
int16_t indMax = 0;
|
||||
|
||||
/* Peak detection */
|
||||
|
||||
for (i = 0; i <= (w16_nmbPeaks - 1); i++)
|
||||
{
|
||||
if (w16_nmbPeaks == 1)
|
||||
{
|
||||
/*
|
||||
* Single peak
|
||||
* The parabola fit assumes that an extra point is available; worst case it gets
|
||||
* a zero on the high end of the signal.
|
||||
*/
|
||||
w16_dataLen++;
|
||||
}
|
||||
|
||||
pw16_winIndex[i] = WebRtcSpl_MaxIndexW16(pw16_data, (int16_t) (w16_dataLen - 1));
|
||||
|
||||
if (i != w16_nmbPeaks - 1)
|
||||
{
|
||||
w16_tmp = pw16_winIndex[i] - 2; /* *fs_mult; */
|
||||
indMin = WEBRTC_SPL_MAX(0, w16_tmp);
|
||||
w16_tmp = pw16_winIndex[i] + 2; /* *fs_mult; */
|
||||
w16_tmp2 = w16_dataLen - 1;
|
||||
indMax = WEBRTC_SPL_MIN(w16_tmp2, w16_tmp);
|
||||
}
|
||||
|
||||
if ((pw16_winIndex[i] != 0) && (pw16_winIndex[i] != (w16_dataLen - 2)))
|
||||
{
|
||||
/* Parabola fit*/
|
||||
WebRtcNetEQ_PrblFit(&(pw16_data[pw16_winIndex[i] - 1]), &(pw16_winIndex[i]),
|
||||
&(pw16_winValue[i]), fs_mult);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (pw16_winIndex[i] == (w16_dataLen - 2))
|
||||
{
|
||||
if (pw16_data[pw16_winIndex[i]] > pw16_data[pw16_winIndex[i] + 1])
|
||||
{
|
||||
WebRtcNetEQ_PrblFit(&(pw16_data[pw16_winIndex[i] - 1]),
|
||||
&(pw16_winIndex[i]), &(pw16_winValue[i]), fs_mult);
|
||||
}
|
||||
else if (pw16_data[pw16_winIndex[i]] <= pw16_data[pw16_winIndex[i] + 1])
|
||||
{
|
||||
pw16_winValue[i] = (pw16_data[pw16_winIndex[i]]
|
||||
+ pw16_data[pw16_winIndex[i] + 1]) >> 1; /* lin approx */
|
||||
pw16_winIndex[i] = (pw16_winIndex[i] * 2 + 1) * fs_mult;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
pw16_winValue[i] = pw16_data[pw16_winIndex[i]];
|
||||
pw16_winIndex[i] = pw16_winIndex[i] * 2 * fs_mult;
|
||||
}
|
||||
}
|
||||
|
||||
if (i != w16_nmbPeaks - 1)
|
||||
{
|
||||
WebRtcSpl_MemSetW16(&(pw16_data[indMin]), 0, (indMax - indMin + 1));
|
||||
/* for (j=indMin; j<=indMax; j++) pw16_data[j] = 0; */
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int16_t WebRtcNetEQ_PrblFit(int16_t *pw16_3pts, int16_t *pw16_Ind,
|
||||
int16_t *pw16_outVal, int16_t fs_mult)
|
||||
{
|
||||
/* Variables */
|
||||
int32_t Num, Den;
|
||||
int32_t temp;
|
||||
int16_t flag, stp, strt, lmt;
|
||||
uint16_t PFind[13];
|
||||
|
||||
if (fs_mult == 1)
|
||||
{
|
||||
PFind[0] = 0;
|
||||
PFind[1] = 8;
|
||||
PFind[2] = 16;
|
||||
}
|
||||
else if (fs_mult == 2)
|
||||
{
|
||||
PFind[0] = 0;
|
||||
PFind[1] = 4;
|
||||
PFind[2] = 8;
|
||||
PFind[3] = 12;
|
||||
PFind[4] = 16;
|
||||
}
|
||||
else if (fs_mult == 4)
|
||||
{
|
||||
PFind[0] = 0;
|
||||
PFind[1] = 2;
|
||||
PFind[2] = 4;
|
||||
PFind[3] = 6;
|
||||
PFind[4] = 8;
|
||||
PFind[5] = 10;
|
||||
PFind[6] = 12;
|
||||
PFind[7] = 14;
|
||||
PFind[8] = 16;
|
||||
}
|
||||
else
|
||||
{
|
||||
PFind[0] = 0;
|
||||
PFind[1] = 1;
|
||||
PFind[2] = 3;
|
||||
PFind[3] = 4;
|
||||
PFind[4] = 5;
|
||||
PFind[5] = 7;
|
||||
PFind[6] = 8;
|
||||
PFind[7] = 9;
|
||||
PFind[8] = 11;
|
||||
PFind[9] = 12;
|
||||
PFind[10] = 13;
|
||||
PFind[11] = 15;
|
||||
PFind[12] = 16;
|
||||
}
|
||||
|
||||
/* Num = -3*pw16_3pts[0] + 4*pw16_3pts[1] - pw16_3pts[2]; */
|
||||
/* Den = pw16_3pts[0] - 2*pw16_3pts[1] + pw16_3pts[2]; */
|
||||
Num = WEBRTC_SPL_MUL_16_16(pw16_3pts[0],-3) + WEBRTC_SPL_MUL_16_16(pw16_3pts[1],4)
|
||||
- pw16_3pts[2];
|
||||
|
||||
Den = pw16_3pts[0] + WEBRTC_SPL_MUL_16_16(pw16_3pts[1],-2) + pw16_3pts[2];
|
||||
|
||||
temp = (int32_t) WEBRTC_SPL_MUL(Num, (int32_t)120); /* need 32_16 really */
|
||||
flag = 1;
|
||||
stp = WebRtcNetEQ_kPrblCf[PFind[fs_mult]][0] - WebRtcNetEQ_kPrblCf[PFind[fs_mult - 1]][0];
|
||||
strt = (WebRtcNetEQ_kPrblCf[PFind[fs_mult]][0]
|
||||
+ WebRtcNetEQ_kPrblCf[PFind[fs_mult - 1]][0]) >> 1;
|
||||
|
||||
if (temp < (int32_t) WEBRTC_SPL_MUL(-Den,(int32_t)strt))
|
||||
{
|
||||
lmt = strt - stp;
|
||||
while (flag)
|
||||
{
|
||||
if ((flag == fs_mult) || (temp
|
||||
> (int32_t) WEBRTC_SPL_MUL(-Den,(int32_t)lmt)))
|
||||
{
|
||||
*pw16_outVal
|
||||
= (int16_t)
|
||||
(((int32_t) ((int32_t) WEBRTC_SPL_MUL(Den,(int32_t)WebRtcNetEQ_kPrblCf[PFind[fs_mult-flag]][1])
|
||||
+ (int32_t) WEBRTC_SPL_MUL(Num,(int32_t)WebRtcNetEQ_kPrblCf[PFind[fs_mult-flag]][2])
|
||||
+ WEBRTC_SPL_MUL_16_16(pw16_3pts[0],256))) >> 8);
|
||||
*pw16_Ind = (*pw16_Ind) * (fs_mult << 1) - flag;
|
||||
flag = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
flag++;
|
||||
lmt -= stp;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (temp > (int32_t) WEBRTC_SPL_MUL(-Den,(int32_t)(strt+stp)))
|
||||
{
|
||||
lmt = strt + (stp << 1);
|
||||
while (flag)
|
||||
{
|
||||
if ((flag == fs_mult) || (temp
|
||||
< (int32_t) WEBRTC_SPL_MUL(-Den,(int32_t)lmt)))
|
||||
{
|
||||
int32_t temp_term_1, temp_term_2, temp_term_3;
|
||||
|
||||
temp_term_1 = WEBRTC_SPL_MUL(Den,
|
||||
(int32_t) WebRtcNetEQ_kPrblCf[PFind[fs_mult+flag]][1]);
|
||||
temp_term_2 = WEBRTC_SPL_MUL(Num,
|
||||
(int32_t) WebRtcNetEQ_kPrblCf[PFind[fs_mult+flag]][2]);
|
||||
temp_term_3 = WEBRTC_SPL_MUL_16_16(pw16_3pts[0],256);
|
||||
|
||||
*pw16_outVal
|
||||
= (int16_t) ((temp_term_1 + temp_term_2 + temp_term_3) >> 8);
|
||||
|
||||
*pw16_Ind = (*pw16_Ind) * (fs_mult << 1) + flag;
|
||||
flag = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
flag++;
|
||||
lmt += stp;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
*pw16_outVal = pw16_3pts[1];
|
||||
*pw16_Ind = (*pw16_Ind) * 2 * fs_mult;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -1,527 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file contains the Pre-emptive Expand algorithm that is used to increase
|
||||
* the delay by repeating a part of the audio stream.
|
||||
*/
|
||||
|
||||
#include "dsp.h"
|
||||
|
||||
#include "signal_processing_library.h"
|
||||
|
||||
#include "dsp_helpfunctions.h"
|
||||
#include "neteq_error_codes.h"
|
||||
|
||||
#define PREEMPTIVE_CORR_LEN 50
|
||||
#define PREEMPTIVE_MIN_LAG 10
|
||||
#define PREEMPTIVE_MAX_LAG 60
|
||||
#define PREEMPTIVE_DOWNSAMPLED_LEN (PREEMPTIVE_CORR_LEN + PREEMPTIVE_MAX_LAG)
|
||||
|
||||
/* Scratch usage:
|
||||
|
||||
Type Name size startpos endpos
|
||||
int16_t pw16_downSampSpeech 110 0 109
|
||||
int32_t pw32_corr 2*50 110 209
|
||||
int16_t pw16_corr 50 0 49
|
||||
|
||||
Total: 110+2*50
|
||||
*/
|
||||
|
||||
#define SCRATCH_PW16_DS_SPEECH 0
|
||||
#define SCRATCH_PW32_CORR PREEMPTIVE_DOWNSAMPLED_LEN
|
||||
#define SCRATCH_PW16_CORR 0
|
||||
|
||||
/****************************************************************************
|
||||
* WebRtcNetEQ_PreEmptiveExpand(...)
|
||||
*
|
||||
* This function tries to extend the audio data by repeating one or several
|
||||
* pitch periods. The operation is only carried out if the correlation is
|
||||
* strong or if the signal energy is very low. The algorithm is the
|
||||
* reciprocal of the Accelerate algorithm.
|
||||
*
|
||||
* Input:
|
||||
* - inst : NetEQ DSP instance
|
||||
* - scratchPtr : Pointer to scratch vector.
|
||||
* - decoded : Pointer to newly decoded speech.
|
||||
* - len : Length of decoded speech.
|
||||
* - oldDataLen : Length of the part of decoded that has already been played out.
|
||||
* - BGNonly : If non-zero, Pre-emptive Expand will only copy
|
||||
* the first DEFAULT_TIME_ADJUST seconds of the
|
||||
* input and append to the end. No signal matching is
|
||||
* done.
|
||||
*
|
||||
* Output:
|
||||
* - inst : Updated instance
|
||||
* - outData : Pointer to a memory space where the output data
|
||||
* should be stored. The vector must be at least
|
||||
* min(len + 120*fs/8000, NETEQ_MAX_OUTPUT_SIZE)
|
||||
* elements long.
|
||||
* - pw16_len : Number of samples written to outData.
|
||||
*
|
||||
* Return value : 0 - Ok
|
||||
* <0 - Error
|
||||
*/
|
||||
|
||||
int WebRtcNetEQ_PreEmptiveExpand(DSPInst_t *inst,
|
||||
#ifdef SCRATCH
|
||||
int16_t *pw16_scratchPtr,
|
||||
#endif
|
||||
const int16_t *pw16_decoded, int len, int oldDataLen,
|
||||
int16_t *pw16_outData, int16_t *pw16_len,
|
||||
int16_t BGNonly)
|
||||
{
|
||||
|
||||
#ifdef SCRATCH
|
||||
/* Use scratch memory for internal temporary vectors */
|
||||
int16_t *pw16_downSampSpeech = pw16_scratchPtr + SCRATCH_PW16_DS_SPEECH;
|
||||
int32_t *pw32_corr = (int32_t*) (pw16_scratchPtr + SCRATCH_PW32_CORR);
|
||||
int16_t *pw16_corr = pw16_scratchPtr + SCRATCH_PW16_CORR;
|
||||
#else
|
||||
/* Allocate memory for temporary vectors */
|
||||
int16_t pw16_downSampSpeech[PREEMPTIVE_DOWNSAMPLED_LEN];
|
||||
int32_t pw32_corr[PREEMPTIVE_CORR_LEN];
|
||||
int16_t pw16_corr[PREEMPTIVE_CORR_LEN];
|
||||
#endif
|
||||
int16_t w16_decodedMax = 0;
|
||||
int16_t w16_tmp = 0;
|
||||
int16_t w16_tmp2;
|
||||
int32_t w32_tmp;
|
||||
int32_t w32_tmp2;
|
||||
|
||||
const int16_t w16_startLag = PREEMPTIVE_MIN_LAG;
|
||||
const int16_t w16_endLag = PREEMPTIVE_MAX_LAG;
|
||||
const int16_t w16_corrLen = PREEMPTIVE_CORR_LEN;
|
||||
const int16_t *pw16_vec1, *pw16_vec2;
|
||||
int16_t *pw16_vectmp;
|
||||
int16_t w16_inc, w16_startfact;
|
||||
int16_t w16_bestIndex, w16_bestVal;
|
||||
int16_t w16_VAD = 1;
|
||||
int16_t fsMult;
|
||||
int16_t fsMult120;
|
||||
int32_t w32_en1, w32_en2, w32_cc;
|
||||
int16_t w16_en1, w16_en2;
|
||||
int16_t w16_en1Scale, w16_en2Scale;
|
||||
int16_t w16_sqrtEn1En2;
|
||||
int16_t w16_bestCorr = 0;
|
||||
int ok;
|
||||
|
||||
#ifdef NETEQ_STEREO
|
||||
MasterSlaveInfo *msInfo = inst->msInfo;
|
||||
#endif
|
||||
|
||||
fsMult = WebRtcNetEQ_CalcFsMult(inst->fs); /* Calculate fs/8000 */
|
||||
|
||||
/* Pre-calculate common multiplication with fsMult */
|
||||
fsMult120 = (int16_t) WEBRTC_SPL_MUL_16_16(fsMult, 120); /* 15 ms */
|
||||
|
||||
inst->ExpandInst.w16_consecExp = 0; /* Last was not expand any more */
|
||||
|
||||
/*
|
||||
* Sanity check for len variable; must be (almost) 30 ms (120*fsMult + max(bestIndex)).
|
||||
* Also, the new part must be at least .625 ms (w16_overlap).
|
||||
*/
|
||||
if (len < (int16_t) WEBRTC_SPL_MUL_16_16((120 + 119), fsMult) || oldDataLen >= len
|
||||
- inst->ExpandInst.w16_overlap)
|
||||
{
|
||||
/* Length of decoded data too short */
|
||||
inst->w16_mode = MODE_UNSUCCESS_PREEMPTIVE;
|
||||
*pw16_len = len;
|
||||
|
||||
|
||||
/* simply move all data from decoded to outData */
|
||||
|
||||
WEBRTC_SPL_MEMMOVE_W16(pw16_outData, pw16_decoded, (int16_t) len);
|
||||
|
||||
return NETEQ_OTHER_ERROR;
|
||||
}
|
||||
|
||||
/***********************************/
|
||||
/* Special operations for BGN only */
|
||||
/***********************************/
|
||||
|
||||
/* Check if "background noise only" flag is set */
|
||||
if (BGNonly)
|
||||
{
|
||||
/* special operation for BGN only; simply insert a chunk of data */
|
||||
w16_bestIndex = DEFAULT_TIME_ADJUST * (fsMult << 3); /* X*fs/1000 */
|
||||
|
||||
/* Sanity check for bestIndex */
|
||||
if (w16_bestIndex > len)
|
||||
{ /* not good, do nothing instead */
|
||||
inst->w16_mode = MODE_UNSUCCESS_PREEMPTIVE;
|
||||
*pw16_len = len;
|
||||
|
||||
|
||||
/* simply move all data from decoded to outData */
|
||||
|
||||
WEBRTC_SPL_MEMMOVE_W16(pw16_outData, pw16_decoded, (int16_t) len);
|
||||
|
||||
return NETEQ_OTHER_ERROR;
|
||||
}
|
||||
|
||||
/* set length parameter */
|
||||
*pw16_len = len + w16_bestIndex;
|
||||
|
||||
|
||||
/* copy to output */
|
||||
|
||||
WEBRTC_SPL_MEMMOVE_W16(pw16_outData, pw16_decoded, len);
|
||||
WEBRTC_SPL_MEMCPY_W16(&pw16_outData[len], pw16_decoded, w16_bestIndex);
|
||||
|
||||
/* set mode */
|
||||
inst->w16_mode = MODE_LOWEN_PREEMPTIVE;
|
||||
|
||||
/* update statistics */
|
||||
inst->statInst.preemptiveLength += w16_bestIndex;
|
||||
/* Short-term activity statistics. */
|
||||
inst->activity_stats.preemptive_expand_bgn_samples += w16_bestIndex;
|
||||
|
||||
return 0;
|
||||
} /* end of special code for BGN mode */
|
||||
|
||||
#ifdef NETEQ_STEREO
|
||||
|
||||
/* Sanity for msInfo */
|
||||
if (msInfo == NULL)
|
||||
{
|
||||
/* this should not happen here */
|
||||
return MASTER_SLAVE_ERROR;
|
||||
}
|
||||
|
||||
if ((msInfo->msMode == NETEQ_MASTER) || (msInfo->msMode == NETEQ_MONO))
|
||||
{
|
||||
/* Find correlation lag only for non-slave instances */
|
||||
|
||||
#endif
|
||||
|
||||
/****************************************************************/
|
||||
/* Find the strongest correlation lag by downsampling to 4 kHz, */
|
||||
/* calculating correlation for downsampled signal and finding */
|
||||
/* the strongest correlation peak. */
|
||||
/****************************************************************/
|
||||
|
||||
/* find maximum absolute value */
|
||||
w16_decodedMax = WebRtcSpl_MaxAbsValueW16(pw16_decoded, (int16_t) len);
|
||||
|
||||
/* downsample the decoded speech to 4 kHz */
|
||||
ok = WebRtcNetEQ_DownSampleTo4kHz(pw16_decoded, len, inst->fs, pw16_downSampSpeech,
|
||||
PREEMPTIVE_DOWNSAMPLED_LEN, 1 /* compensate delay*/);
|
||||
if (ok != 0)
|
||||
{
|
||||
/* error */
|
||||
inst->w16_mode = MODE_UNSUCCESS_PREEMPTIVE;
|
||||
*pw16_len = len;
|
||||
|
||||
|
||||
/* simply move all data from decoded to outData */
|
||||
|
||||
WEBRTC_SPL_MEMMOVE_W16(pw16_outData, pw16_decoded, (int16_t) len);
|
||||
|
||||
return NETEQ_OTHER_ERROR;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set scaling factor for cross correlation to protect against
|
||||
* overflow (log2(50) => 6)
|
||||
*/
|
||||
w16_tmp = 6 - WebRtcSpl_NormW32(WEBRTC_SPL_MUL_16_16(w16_decodedMax, w16_decodedMax));
|
||||
w16_tmp = WEBRTC_SPL_MAX(0, w16_tmp);
|
||||
|
||||
/* Perform correlation from lag 10 to lag 60 in 4 kHz domain */WebRtcNetEQ_CrossCorr(
|
||||
pw32_corr, &pw16_downSampSpeech[w16_endLag],
|
||||
&pw16_downSampSpeech[w16_endLag - w16_startLag], w16_corrLen,
|
||||
(int16_t) (w16_endLag - w16_startLag), w16_tmp, -1);
|
||||
|
||||
/* Normalize correlation to 14 bits and put in a int16_t vector */
|
||||
w32_tmp = WebRtcSpl_MaxAbsValueW32(pw32_corr, w16_corrLen);
|
||||
w16_tmp = 17 - WebRtcSpl_NormW32(w32_tmp);
|
||||
w16_tmp = WEBRTC_SPL_MAX(0, w16_tmp);
|
||||
|
||||
WebRtcSpl_VectorBitShiftW32ToW16(pw16_corr, w16_corrLen, pw32_corr, w16_tmp);
|
||||
|
||||
/* Find limits for peak finding, in order to avoid overful NetEQ algorithm buffer. */
|
||||
/* Calculate difference between MAX_OUTPUT_SIZE and len in 4 kHz domain. */
|
||||
w16_tmp = WebRtcSpl_DivW32W16ResW16((int32_t) (NETEQ_MAX_OUTPUT_SIZE - len),
|
||||
(int16_t) (fsMult << 1)) - w16_startLag;
|
||||
w16_tmp = WEBRTC_SPL_MIN(w16_corrLen, w16_tmp); /* no more than corrLen = 50 */
|
||||
|
||||
#ifdef NETEQ_STEREO
|
||||
} /* end if (msInfo->msMode != NETEQ_SLAVE) */
|
||||
|
||||
if ((msInfo->msMode == NETEQ_MASTER) || (msInfo->msMode == NETEQ_MONO))
|
||||
{
|
||||
/* Find the strongest correlation peak by using the parabolic fit method */
|
||||
WebRtcNetEQ_PeakDetection(pw16_corr, w16_tmp, 1, fsMult, &w16_bestIndex, &w16_bestVal);
|
||||
/* 0 <= bestIndex <= (2*w16_tmp - 1)*fsMult <= (2*corrLen - 1)*fsMult = 99*fsMult */
|
||||
|
||||
/* Compensate bestIndex for displaced starting position */
|
||||
w16_bestIndex = w16_bestIndex + w16_startLag * WEBRTC_SPL_LSHIFT_W16(fsMult, 1);
|
||||
/* 20*fsMult <= bestIndex <= 119*fsMult */
|
||||
|
||||
msInfo->bestIndex = w16_bestIndex;
|
||||
}
|
||||
else if (msInfo->msMode == NETEQ_SLAVE)
|
||||
{
|
||||
if (msInfo->extraInfo == PE_EXP_FAIL)
|
||||
{
|
||||
/* Master has signaled an unsuccessful preemptive expand */
|
||||
w16_bestIndex = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Get best index from master */
|
||||
w16_bestIndex = msInfo->bestIndex;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Invalid mode */
|
||||
return (MASTER_SLAVE_ERROR);
|
||||
}
|
||||
|
||||
#else /* NETEQ_STEREO */
|
||||
|
||||
/* Find the strongest correlation peak by using the parabolic fit method */
|
||||
WebRtcNetEQ_PeakDetection(pw16_corr, w16_tmp, 1, fsMult, &w16_bestIndex, &w16_bestVal);
|
||||
/* 0 <= bestIndex <= (2*w16_tmp - 1)*fsMult <= (2*corrLen - 1)*fsMult = 99*fsMult */
|
||||
|
||||
/* Compensate bestIndex for displaced starting position */
|
||||
w16_bestIndex = w16_bestIndex + w16_startLag * WEBRTC_SPL_LSHIFT_W16(fsMult, 1);
|
||||
/* 20*fsMult <= bestIndex <= 119*fsMult */
|
||||
|
||||
#endif /* NETEQ_STEREO */
|
||||
|
||||
#ifdef NETEQ_STEREO
|
||||
|
||||
if ((msInfo->msMode == NETEQ_MASTER) || (msInfo->msMode == NETEQ_MONO))
|
||||
{
|
||||
/* Calculate correlation only for non-slave instances */
|
||||
|
||||
#endif /* NETEQ_STEREO */
|
||||
|
||||
/*****************************************************/
|
||||
/* Calculate correlation bestCorr for the found lag. */
|
||||
/* Also do a simple VAD decision. */
|
||||
/*****************************************************/
|
||||
|
||||
/*
|
||||
* Calculate scaling to ensure that bestIndex samples can be square-summed
|
||||
* without overflowing
|
||||
*/
|
||||
w16_tmp = (31
|
||||
- WebRtcSpl_NormW32(WEBRTC_SPL_MUL_16_16(w16_decodedMax, w16_decodedMax)));
|
||||
w16_tmp += (31 - WebRtcSpl_NormW32(w16_bestIndex));
|
||||
w16_tmp -= 31;
|
||||
w16_tmp = WEBRTC_SPL_MAX(0, w16_tmp);
|
||||
|
||||
/* vec1 starts at 15 ms minus one pitch period */
|
||||
pw16_vec1 = &pw16_decoded[fsMult120 - w16_bestIndex];
|
||||
/* vec2 start at 15 ms */
|
||||
pw16_vec2 = &pw16_decoded[fsMult120];
|
||||
|
||||
/* Calculate energies for vec1 and vec2 */
|
||||
w32_en1 = WebRtcNetEQ_DotW16W16((int16_t*) pw16_vec1,
|
||||
(int16_t*) pw16_vec1, w16_bestIndex, w16_tmp);
|
||||
w32_en2 = WebRtcNetEQ_DotW16W16((int16_t*) pw16_vec2,
|
||||
(int16_t*) pw16_vec2, w16_bestIndex, w16_tmp);
|
||||
|
||||
/* Calculate cross-correlation at the found lag */
|
||||
w32_cc = WebRtcNetEQ_DotW16W16((int16_t*) pw16_vec1, (int16_t*) pw16_vec2,
|
||||
w16_bestIndex, w16_tmp);
|
||||
|
||||
/* Check VAD constraint
|
||||
((en1+en2)/(2*bestIndex)) <= 8*inst->BGNInst.energy */
|
||||
w32_tmp = WEBRTC_SPL_RSHIFT_W32(w32_en1 + w32_en2, 4); /* (en1+en2)/(2*8) */
|
||||
if (inst->BGNInst.w16_initialized == 1)
|
||||
{
|
||||
w32_tmp2 = inst->BGNInst.w32_energy;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* if BGN parameters have not been estimated, use a fixed threshold */
|
||||
w32_tmp2 = 75000;
|
||||
}
|
||||
w16_tmp2 = 16 - WebRtcSpl_NormW32(w32_tmp2);
|
||||
w16_tmp2 = WEBRTC_SPL_MAX(0, w16_tmp2);
|
||||
w32_tmp = WEBRTC_SPL_RSHIFT_W32(w32_tmp, w16_tmp2);
|
||||
w16_tmp2 = (int16_t) WEBRTC_SPL_RSHIFT_W32(w32_tmp2, w16_tmp2);
|
||||
w32_tmp2 = WEBRTC_SPL_MUL_16_16(w16_bestIndex, w16_tmp2);
|
||||
|
||||
/* Scale w32_tmp properly before comparing with w32_tmp2 */
|
||||
/* (w16_tmp is scaling before energy calculation, thus 2*w16_tmp) */
|
||||
if (WebRtcSpl_NormW32(w32_tmp) < WEBRTC_SPL_LSHIFT_W32(w16_tmp,1))
|
||||
{
|
||||
/* Cannot scale only w32_tmp, must scale w32_temp2 too */
|
||||
int16_t tempshift = WebRtcSpl_NormW32(w32_tmp);
|
||||
w32_tmp = WEBRTC_SPL_LSHIFT_W32(w32_tmp, tempshift);
|
||||
w32_tmp2 = WEBRTC_SPL_RSHIFT_W32(w32_tmp2,
|
||||
WEBRTC_SPL_LSHIFT_W32(w16_tmp,1) - tempshift);
|
||||
}
|
||||
else
|
||||
{
|
||||
w32_tmp = WEBRTC_SPL_LSHIFT_W32(w32_tmp,
|
||||
WEBRTC_SPL_LSHIFT_W32(w16_tmp,1));
|
||||
}
|
||||
|
||||
if (w32_tmp <= w32_tmp2) /*((en1+en2)/(2*bestIndex)) <= 8*inst->BGNInst.energy */
|
||||
{
|
||||
/* The signal seems to be passive speech */
|
||||
w16_VAD = 0;
|
||||
w16_bestCorr = 0; /* Correlation does not matter */
|
||||
|
||||
/* For low energy expansion, the new data can be less than 15 ms,
|
||||
but we must ensure that bestIndex is not larger than the new data. */
|
||||
w16_bestIndex = WEBRTC_SPL_MIN( w16_bestIndex, len - oldDataLen );
|
||||
}
|
||||
else
|
||||
{
|
||||
/* The signal is active speech */
|
||||
w16_VAD = 1;
|
||||
|
||||
/* Calculate correlation (cc/sqrt(en1*en2)) */
|
||||
|
||||
/* Start with calculating scale values */
|
||||
w16_en1Scale = 16 - WebRtcSpl_NormW32(w32_en1);
|
||||
w16_en1Scale = WEBRTC_SPL_MAX(0, w16_en1Scale);
|
||||
w16_en2Scale = 16 - WebRtcSpl_NormW32(w32_en2);
|
||||
w16_en2Scale = WEBRTC_SPL_MAX(0, w16_en2Scale);
|
||||
|
||||
/* Make sure total scaling is even (to simplify scale factor after sqrt) */
|
||||
if ((w16_en1Scale + w16_en2Scale) & 1)
|
||||
{
|
||||
w16_en1Scale += 1;
|
||||
}
|
||||
|
||||
/* Convert energies to int16_t */
|
||||
w16_en1 = (int16_t) WEBRTC_SPL_RSHIFT_W32(w32_en1, w16_en1Scale);
|
||||
w16_en2 = (int16_t) WEBRTC_SPL_RSHIFT_W32(w32_en2, w16_en2Scale);
|
||||
|
||||
/* Calculate energy product */
|
||||
w32_tmp = WEBRTC_SPL_MUL_16_16(w16_en1, w16_en2);
|
||||
|
||||
/* Calculate square-root of energy product */
|
||||
w16_sqrtEn1En2 = (int16_t) WebRtcSpl_SqrtFloor(w32_tmp);
|
||||
|
||||
/* Calculate cc/sqrt(en1*en2) in Q14 */
|
||||
w16_tmp = 14 - ((w16_en1Scale + w16_en2Scale) >> 1);
|
||||
w32_cc = WEBRTC_SPL_SHIFT_W32(w32_cc, w16_tmp);
|
||||
w32_cc = WEBRTC_SPL_MAX(0, w32_cc); /* Don't divide with negative number */
|
||||
w16_bestCorr = (int16_t) WebRtcSpl_DivW32W16(w32_cc, w16_sqrtEn1En2);
|
||||
w16_bestCorr = WEBRTC_SPL_MIN(16384, w16_bestCorr); /* set maximum to 1.0 */
|
||||
}
|
||||
|
||||
#ifdef NETEQ_STEREO
|
||||
|
||||
} /* end if (msInfo->msMode != NETEQ_SLAVE) */
|
||||
|
||||
#endif /* NETEQ_STEREO */
|
||||
|
||||
/*******************************************************/
|
||||
/* Check preemptive expand criteria and insert samples */
|
||||
/*******************************************************/
|
||||
|
||||
/* Check for strong correlation (>0.9) and at least 15 ms new data,
|
||||
or passive speech */
|
||||
#ifdef NETEQ_STEREO
|
||||
if (((((w16_bestCorr > 14746) && (oldDataLen <= fsMult120)) || (w16_VAD == 0))
|
||||
&& (msInfo->msMode != NETEQ_SLAVE)) || ((msInfo->msMode == NETEQ_SLAVE)
|
||||
&& (msInfo->extraInfo != PE_EXP_FAIL)))
|
||||
#else
|
||||
if (((w16_bestCorr > 14746) && (oldDataLen <= fsMult120))
|
||||
|| (w16_VAD == 0))
|
||||
#endif
|
||||
{
|
||||
/* Do expand operation by overlap add */
|
||||
|
||||
/* Set length of the first part, not to be modified */
|
||||
int16_t w16_startIndex = WEBRTC_SPL_MAX(oldDataLen, fsMult120);
|
||||
|
||||
/*
|
||||
* Calculate cross-fading slope so that the fading factor goes from
|
||||
* 1 (16384 in Q14) to 0 in one pitch period (bestIndex).
|
||||
*/
|
||||
w16_inc = (int16_t) WebRtcSpl_DivW32W16((int32_t) 16384,
|
||||
(int16_t) (w16_bestIndex + 1)); /* in Q14 */
|
||||
|
||||
/* Initiate fading factor */
|
||||
w16_startfact = 16384 - w16_inc;
|
||||
|
||||
/* vec1 starts at 15 ms minus one pitch period */
|
||||
pw16_vec1 = &pw16_decoded[w16_startIndex - w16_bestIndex];
|
||||
/* vec2 start at 15 ms */
|
||||
pw16_vec2 = &pw16_decoded[w16_startIndex];
|
||||
|
||||
|
||||
/* Copy unmodified part [0 to 15 ms] */
|
||||
|
||||
WEBRTC_SPL_MEMMOVE_W16(pw16_outData, pw16_decoded, w16_startIndex);
|
||||
|
||||
/* Generate interpolated part of length bestIndex (1 pitch period) */
|
||||
pw16_vectmp = pw16_outData + w16_startIndex;
|
||||
/* Reuse mixing function from Expand */
|
||||
WebRtcNetEQ_MixVoiceUnvoice(pw16_vectmp, (int16_t*) pw16_vec2,
|
||||
(int16_t*) pw16_vec1, &w16_startfact, w16_inc, w16_bestIndex);
|
||||
|
||||
/* Move the last part (also unmodified) */
|
||||
/* Take from decoded at 15 ms */
|
||||
pw16_vec2 = &pw16_decoded[w16_startIndex];
|
||||
WEBRTC_SPL_MEMMOVE_W16(&pw16_outData[w16_startIndex + w16_bestIndex], pw16_vec2,
|
||||
(int16_t) (len - w16_startIndex));
|
||||
|
||||
/* Set the mode flag */
|
||||
if (w16_VAD)
|
||||
{
|
||||
inst->w16_mode = MODE_SUCCESS_PREEMPTIVE;
|
||||
}
|
||||
else
|
||||
{
|
||||
inst->w16_mode = MODE_LOWEN_PREEMPTIVE;
|
||||
}
|
||||
|
||||
/* Calculate resulting length = original length + pitch period */
|
||||
*pw16_len = len + w16_bestIndex;
|
||||
|
||||
/* Update in-call statistics */
|
||||
inst->statInst.preemptiveLength += w16_bestIndex;
|
||||
/* Short-term activity statistics. */
|
||||
inst->activity_stats.preemptive_expand_normal_samples += w16_bestIndex;
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Preemptive Expand not allowed */
|
||||
|
||||
#ifdef NETEQ_STEREO
|
||||
/* Signal to slave(s) that this was unsuccessful */
|
||||
if (msInfo->msMode == NETEQ_MASTER)
|
||||
{
|
||||
msInfo->extraInfo = PE_EXP_FAIL;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Set mode flag to unsuccessful preemptive expand */
|
||||
inst->w16_mode = MODE_UNSUCCESS_PREEMPTIVE;
|
||||
|
||||
/* Length is unmodified */
|
||||
*pw16_len = len;
|
||||
|
||||
|
||||
/* Simply move all data from decoded to outData */
|
||||
|
||||
WEBRTC_SPL_MEMMOVE_W16(pw16_outData, pw16_decoded, (int16_t) len);
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
#undef SCRATCH_PW16_DS_SPEECH
|
||||
#undef SCRATCH_PW32_CORR
|
||||
#undef SCRATCH_PW16_CORR
|
@ -1,54 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This function generates a pseudo-random vector.
|
||||
*/
|
||||
|
||||
#include "dsp_helpfunctions.h"
|
||||
|
||||
/*
|
||||
* Values are normalized so that
|
||||
* sqrt(dot(pw16_NETEQFIX_RANDN_TBL,pw16_NETEQFIX_RANDN_TBL)/256)=2^13
|
||||
*/
|
||||
const int16_t WebRtcNetEQ_kRandnTbl[RANDVEC_NO_OF_SAMPLES] =
|
||||
{
|
||||
2680, 5532, 441, 5520, 16170, -5146, -1024, -8733, 3115, 9598, -10380, -4959, -1280, -21716, 7133, -1522,
|
||||
13458, -3902, 2789, -675, 3441, 5016, -13599, -4003, -2739, 3922, -7209, 13352, -11617, -7241, 12905, -2314,
|
||||
5426, 10121, -9702, 11207, -13542, 1373, 816, -5934, -12504, 4798, 1811, 4112, -613, 201, -10367, -2960,
|
||||
-2419, 3442, 4299, -6116, -6092, 1552, -1650, -480, -1237, 18720, -11858, -8303, -8212, 865, -2890, -16968,
|
||||
12052, -5845, -5912, 9777, -5665, -6294, 5426, -4737, -6335, 1652, 761, 3832, 641, -8552, -9084, -5753,
|
||||
8146, 12156, -4915, 15086, -1231, -1869, 11749, -9319, -6403, 11407, 6232, -1683, 24340, -11166, 4017, -10448,
|
||||
3153, -2936, 6212, 2891, -866, -404, -4807, -2324, -1917, -2388, -6470, -3895, -10300, 5323, -5403, 2205,
|
||||
4640, 7022, -21186, -6244, -882, -10031, -3395, -12885, 7155, -5339, 5079, -2645, -9515, 6622, 14651, 15852,
|
||||
359, 122, 8246, -3502, -6696, -3679, -13535, -1409, -704, -7403, -4007, 1798, 279, -420, -12796, -14219,
|
||||
1141, 3359, 11434, 7049, -6684, -7473, 14283, -4115, -9123, -8969, 4152, 4117, 13792, 5742, 16168, 8661,
|
||||
-1609, -6095, 1881, 14380, -5588, 6758, -6425, -22969, -7269, 7031, 1119, -1611, -5850, -11281, 3559, -8952,
|
||||
-10146, -4667, -16251, -1538, 2062, -1012, -13073, 227, -3142, -5265, 20, 5770, -7559, 4740, -4819, 992,
|
||||
-8208, -7130, -4652, 6725, 7369, -1036, 13144, -1588, -5304, -2344, -449, -5705, -8894, 5205, -17904, -11188,
|
||||
-1022, 4852, 10101, -5255, -4200, -752, 7941, -1543, 5959, 14719, 13346, 17045, -15605, -1678, -1600, -9230,
|
||||
68, 23348, 1172, 7750, 11212, -18227, 9956, 4161, 883, 3947, 4341, 1014, -4889, -2603, 1246, -5630,
|
||||
-3596, -870, -1298, 2784, -3317, -6612, -20541, 4166, 4181, -8625, 3562, 12890, 4761, 3205, -12259, -8579
|
||||
};
|
||||
|
||||
|
||||
void WebRtcNetEQ_RandomVec(uint32_t *w32_seed, int16_t *pw16_randVec,
|
||||
int16_t w16_len, int16_t w16_incval)
|
||||
{
|
||||
int i;
|
||||
int16_t w16_pos;
|
||||
for (i = 0; i < w16_len; i++)
|
||||
{
|
||||
*w32_seed = (*w32_seed) + w16_incval;
|
||||
w16_pos = (int16_t) ((*w32_seed) & (RANDVEC_NO_OF_SAMPLES - 1));
|
||||
pw16_randVec[i] = WebRtcNetEQ_kRandnTbl[w16_pos];
|
||||
}
|
||||
}
|
||||
|
@ -1,531 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Implementation of the RecIn function, which is the main function for inserting RTP
|
||||
* packets into NetEQ.
|
||||
*/
|
||||
|
||||
#include "mcu.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "automode.h"
|
||||
#include "dtmf_buffer.h"
|
||||
#include "mcu_dsp_common.h"
|
||||
#include "neteq_defines.h"
|
||||
#include "neteq_error_codes.h"
|
||||
#include "signal_processing_library.h"
|
||||
|
||||
int WebRtcNetEQ_RecInInternal(MCUInst_t *MCU_inst, RTPPacket_t *RTPpacketInput,
|
||||
uint32_t uw32_timeRec)
|
||||
{
|
||||
RTPPacket_t RTPpacket[2];
|
||||
int i_k;
|
||||
int i_ok = 0, i_No_Of_Payloads = 1;
|
||||
int16_t flushed = 0;
|
||||
int16_t codecPos;
|
||||
int curr_Codec;
|
||||
int16_t isREDPayload = 0;
|
||||
int32_t temp_bufsize;
|
||||
int is_sync_rtp = MCU_inst->av_sync && WebRtcNetEQ_IsSyncPayload(
|
||||
RTPpacketInput->payload, RTPpacketInput->payloadLen);
|
||||
#ifdef NETEQ_RED_CODEC
|
||||
RTPPacket_t* RTPpacketPtr[2]; /* Support for redundancy up to 2 payloads */
|
||||
RTPpacketPtr[0] = &RTPpacket[0];
|
||||
RTPpacketPtr[1] = &RTPpacket[1];
|
||||
#endif
|
||||
|
||||
temp_bufsize = WebRtcNetEQ_PacketBufferGetSize(&MCU_inst->PacketBuffer_inst,
|
||||
&MCU_inst->codec_DB_inst,
|
||||
MCU_inst->av_sync);
|
||||
/*
|
||||
* Copy from input RTP packet to local copy
|
||||
* (mainly to enable multiple payloads using RED)
|
||||
*/
|
||||
|
||||
WEBRTC_SPL_MEMCPY_W8(&RTPpacket[0], RTPpacketInput, sizeof(RTPPacket_t));
|
||||
|
||||
/* Reinitialize NetEq if it's needed (changed SSRC or first call) */
|
||||
|
||||
if ((RTPpacket[0].ssrc != MCU_inst->ssrc) || (MCU_inst->first_packet == 1))
|
||||
{
|
||||
WebRtcNetEQ_RTCPInit(&MCU_inst->RTCP_inst, RTPpacket[0].seqNumber);
|
||||
MCU_inst->first_packet = 0;
|
||||
|
||||
/* Flush the buffer */
|
||||
WebRtcNetEQ_PacketBufferFlush(&MCU_inst->PacketBuffer_inst);
|
||||
|
||||
/* Store new SSRC */
|
||||
MCU_inst->ssrc = RTPpacket[0].ssrc;
|
||||
|
||||
/* Update codecs */
|
||||
MCU_inst->timeStamp = RTPpacket[0].timeStamp;
|
||||
MCU_inst->current_Payload = RTPpacket[0].payloadType;
|
||||
|
||||
/*Set MCU to update codec on next SignalMCU call */
|
||||
MCU_inst->new_codec = 1;
|
||||
|
||||
/* Reset timestamp scaling */
|
||||
MCU_inst->TSscalingInitialized = 0;
|
||||
|
||||
}
|
||||
|
||||
if (!is_sync_rtp) { /* Update only if it not sync packet. */
|
||||
/* Call RTCP statistics if it is not sync packet. */
|
||||
i_ok |= WebRtcNetEQ_RTCPUpdate(&(MCU_inst->RTCP_inst),
|
||||
RTPpacket[0].seqNumber,
|
||||
RTPpacket[0].timeStamp, uw32_timeRec);
|
||||
}
|
||||
|
||||
/* If Redundancy is supported and this is the redundancy payload, separate the payloads */
|
||||
#ifdef NETEQ_RED_CODEC
|
||||
if (RTPpacket[0].payloadType == WebRtcNetEQ_DbGetPayload(&MCU_inst->codec_DB_inst,
|
||||
kDecoderRED))
|
||||
{
|
||||
if (is_sync_rtp)
|
||||
{
|
||||
/* Sync packet should not have RED payload type. */
|
||||
return RECIN_SYNC_RTP_NOT_ACCEPTABLE;
|
||||
}
|
||||
|
||||
/* Split the payload into a main and a redundancy payloads */
|
||||
i_ok = WebRtcNetEQ_RedundancySplit(RTPpacketPtr, 2, &i_No_Of_Payloads);
|
||||
if (i_ok < 0)
|
||||
{
|
||||
/* error returned */
|
||||
return i_ok;
|
||||
}
|
||||
|
||||
/*
|
||||
* Only accept a few redundancies of the same type as the main data,
|
||||
* AVT events and CNG.
|
||||
*/
|
||||
if ((i_No_Of_Payloads > 1) && (RTPpacket[0].payloadType != RTPpacket[1].payloadType)
|
||||
&& (RTPpacket[0].payloadType != WebRtcNetEQ_DbGetPayload(&MCU_inst->codec_DB_inst,
|
||||
kDecoderAVT)) && (RTPpacket[1].payloadType != WebRtcNetEQ_DbGetPayload(
|
||||
&MCU_inst->codec_DB_inst, kDecoderAVT)) && (!WebRtcNetEQ_DbIsCNGPayload(
|
||||
&MCU_inst->codec_DB_inst, RTPpacket[0].payloadType))
|
||||
&& (!WebRtcNetEQ_DbIsCNGPayload(&MCU_inst->codec_DB_inst, RTPpacket[1].payloadType)))
|
||||
{
|
||||
i_No_Of_Payloads = 1;
|
||||
}
|
||||
isREDPayload = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* loop over the number of payloads */
|
||||
for (i_k = 0; i_k < i_No_Of_Payloads; i_k++)
|
||||
{
|
||||
|
||||
if (isREDPayload == 1)
|
||||
{
|
||||
RTPpacket[i_k].rcuPlCntr = i_k;
|
||||
}
|
||||
else
|
||||
{
|
||||
RTPpacket[i_k].rcuPlCntr = 0;
|
||||
}
|
||||
|
||||
/* Force update of SplitInfo if it's iLBC because of potential change between 20/30ms */
|
||||
if (RTPpacket[i_k].payloadType == WebRtcNetEQ_DbGetPayload(&MCU_inst->codec_DB_inst,
|
||||
kDecoderILBC) && !is_sync_rtp) /* Don't update if sync RTP. */
|
||||
{
|
||||
i_ok = WebRtcNetEQ_DbGetSplitInfo(
|
||||
&MCU_inst->PayloadSplit_inst,
|
||||
(enum WebRtcNetEQDecoder) WebRtcNetEQ_DbGetCodec(&MCU_inst->codec_DB_inst,
|
||||
RTPpacket[i_k].payloadType), RTPpacket[i_k].payloadLen);
|
||||
if (i_ok < 0)
|
||||
{
|
||||
/* error returned */
|
||||
return i_ok;
|
||||
}
|
||||
}
|
||||
|
||||
/* Get information about timestamp scaling for this payload type */
|
||||
i_ok = WebRtcNetEQ_GetTimestampScaling(MCU_inst, RTPpacket[i_k].payloadType);
|
||||
if (i_ok < 0)
|
||||
{
|
||||
/* error returned */
|
||||
return i_ok;
|
||||
}
|
||||
|
||||
if (MCU_inst->TSscalingInitialized == 0 && MCU_inst->scalingFactor != kTSnoScaling)
|
||||
{
|
||||
/* Must initialize scaling with current timestamps */
|
||||
MCU_inst->externalTS = RTPpacket[i_k].timeStamp;
|
||||
MCU_inst->internalTS = RTPpacket[i_k].timeStamp;
|
||||
MCU_inst->TSscalingInitialized = 1;
|
||||
}
|
||||
|
||||
/* Adjust timestamp if timestamp scaling is needed (e.g. SILK or G.722) */
|
||||
if (MCU_inst->TSscalingInitialized == 1)
|
||||
{
|
||||
uint32_t newTS = WebRtcNetEQ_ScaleTimestampExternalToInternal(MCU_inst,
|
||||
RTPpacket[i_k].timeStamp);
|
||||
|
||||
/* save the incoming timestamp for next time */
|
||||
MCU_inst->externalTS = RTPpacket[i_k].timeStamp;
|
||||
|
||||
/* add the scaled difference to last scaled timestamp and save ... */
|
||||
MCU_inst->internalTS = newTS;
|
||||
|
||||
RTPpacket[i_k].timeStamp = newTS;
|
||||
}
|
||||
|
||||
/* Is this a DTMF packet?*/
|
||||
if (RTPpacket[i_k].payloadType == WebRtcNetEQ_DbGetPayload(&MCU_inst->codec_DB_inst,
|
||||
kDecoderAVT))
|
||||
{
|
||||
if (is_sync_rtp)
|
||||
{
|
||||
/* Sync RTP should not have AVT payload type. */
|
||||
return RECIN_SYNC_RTP_NOT_ACCEPTABLE;
|
||||
}
|
||||
|
||||
#ifdef NETEQ_ATEVENT_DECODE
|
||||
if (MCU_inst->AVT_PlayoutOn)
|
||||
{
|
||||
i_ok = WebRtcNetEQ_DtmfInsertEvent(&MCU_inst->DTMF_inst,
|
||||
RTPpacket[i_k].payload, RTPpacket[i_k].payloadLen,
|
||||
RTPpacket[i_k].timeStamp);
|
||||
if (i_ok != 0)
|
||||
{
|
||||
return i_ok;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#ifdef NETEQ_STEREO
|
||||
if (MCU_inst->usingStereo == 0)
|
||||
{
|
||||
/* do not set this for DTMF packets when using stereo mode */
|
||||
MCU_inst->BufferStat_inst.Automode_inst.lastPackCNGorDTMF = 1;
|
||||
}
|
||||
#else
|
||||
MCU_inst->BufferStat_inst.Automode_inst.lastPackCNGorDTMF = 1;
|
||||
#endif
|
||||
}
|
||||
else if (WebRtcNetEQ_DbIsCNGPayload(&MCU_inst->codec_DB_inst,
|
||||
RTPpacket[i_k].payloadType))
|
||||
{
|
||||
/* Is this a CNG packet? how should we handle this?*/
|
||||
#ifdef NETEQ_CNG_CODEC
|
||||
/* Get CNG sample rate */
|
||||
uint16_t fsCng = WebRtcNetEQ_DbGetSampleRate(&MCU_inst->codec_DB_inst,
|
||||
RTPpacket[i_k].payloadType);
|
||||
if (is_sync_rtp)
|
||||
{
|
||||
/* Sync RTP should not have CNG payload type. */
|
||||
return RECIN_SYNC_RTP_NOT_ACCEPTABLE;
|
||||
}
|
||||
|
||||
/* Force sampling frequency to 32000 Hz CNG 48000 Hz. */
|
||||
/* TODO(tlegrand): remove limitation once ACM has full 48 kHz
|
||||
* support. */
|
||||
if (fsCng > 32000) {
|
||||
fsCng = 32000;
|
||||
}
|
||||
if ((fsCng != MCU_inst->fs) && (fsCng > 8000))
|
||||
{
|
||||
/*
|
||||
* We have received CNG with a different sample rate from what we are using
|
||||
* now (must be > 8000, since we may use only one CNG type (default) for all
|
||||
* frequencies). Flush buffer and signal new codec.
|
||||
*/
|
||||
WebRtcNetEQ_PacketBufferFlush(&MCU_inst->PacketBuffer_inst);
|
||||
MCU_inst->new_codec = 1;
|
||||
MCU_inst->current_Codec = -1;
|
||||
}
|
||||
i_ok = WebRtcNetEQ_PacketBufferInsert(&MCU_inst->PacketBuffer_inst,
|
||||
&RTPpacket[i_k], &flushed, MCU_inst->av_sync);
|
||||
if (i_ok < 0)
|
||||
{
|
||||
return RECIN_CNG_ERROR;
|
||||
}
|
||||
MCU_inst->BufferStat_inst.Automode_inst.lastPackCNGorDTMF = 1;
|
||||
#else /* NETEQ_CNG_CODEC not defined */
|
||||
return RECIN_UNKNOWNPAYLOAD;
|
||||
#endif /* NETEQ_CNG_CODEC */
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Reinitialize the splitting if the payload and/or the payload length has changed */
|
||||
curr_Codec = WebRtcNetEQ_DbGetCodec(&MCU_inst->codec_DB_inst,
|
||||
RTPpacket[i_k].payloadType);
|
||||
if (curr_Codec != MCU_inst->current_Codec)
|
||||
{
|
||||
if (curr_Codec < 0)
|
||||
{
|
||||
return RECIN_UNKNOWNPAYLOAD;
|
||||
}
|
||||
if (is_sync_rtp)
|
||||
{
|
||||
/* Sync RTP should not cause codec change. */
|
||||
return RECIN_SYNC_RTP_CHANGED_CODEC;
|
||||
}
|
||||
MCU_inst->current_Codec = curr_Codec;
|
||||
MCU_inst->current_Payload = RTPpacket[i_k].payloadType;
|
||||
i_ok = WebRtcNetEQ_DbGetSplitInfo(&MCU_inst->PayloadSplit_inst,
|
||||
(enum WebRtcNetEQDecoder) MCU_inst->current_Codec,
|
||||
RTPpacket[i_k].payloadLen);
|
||||
if (i_ok < 0)
|
||||
{ /* error returned */
|
||||
return i_ok;
|
||||
}
|
||||
WebRtcNetEQ_PacketBufferFlush(&MCU_inst->PacketBuffer_inst);
|
||||
MCU_inst->new_codec = 1;
|
||||
}
|
||||
|
||||
/* Parse the payload and insert it into the buffer */
|
||||
i_ok = WebRtcNetEQ_SplitAndInsertPayload(&RTPpacket[i_k],
|
||||
&MCU_inst->PacketBuffer_inst, &MCU_inst->PayloadSplit_inst,
|
||||
&flushed, MCU_inst->av_sync);
|
||||
if (i_ok < 0)
|
||||
{
|
||||
return i_ok;
|
||||
}
|
||||
if (MCU_inst->BufferStat_inst.Automode_inst.lastPackCNGorDTMF != 0)
|
||||
{
|
||||
/* first normal packet after CNG or DTMF */
|
||||
MCU_inst->BufferStat_inst.Automode_inst.lastPackCNGorDTMF = -1;
|
||||
}
|
||||
}
|
||||
/* Reset DSP timestamp etc. if packet buffer flushed */
|
||||
if (flushed)
|
||||
{
|
||||
MCU_inst->new_codec = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If not sync RTP, update Bandwidth Estimate.
|
||||
* Only send the main payload to BWE.
|
||||
*/
|
||||
if (!is_sync_rtp &&
|
||||
(curr_Codec = WebRtcNetEQ_DbGetCodec(&MCU_inst->codec_DB_inst,
|
||||
RTPpacket[0].payloadType)) >= 0)
|
||||
{
|
||||
codecPos = MCU_inst->codec_DB_inst.position[curr_Codec];
|
||||
if (MCU_inst->codec_DB_inst.funcUpdBWEst[codecPos] != NULL) /* codec has BWE function */
|
||||
{
|
||||
if (RTPpacket[0].starts_byte1) /* check for shifted byte alignment */
|
||||
{
|
||||
/* re-align to 16-bit alignment */
|
||||
for (i_k = 0; i_k < RTPpacket[0].payloadLen; i_k++)
|
||||
{
|
||||
WEBRTC_SPL_SET_BYTE(RTPpacket[0].payload,
|
||||
WEBRTC_SPL_GET_BYTE(RTPpacket[0].payload, i_k+1),
|
||||
i_k);
|
||||
}
|
||||
RTPpacket[0].starts_byte1 = 0;
|
||||
}
|
||||
|
||||
MCU_inst->codec_DB_inst.funcUpdBWEst[codecPos](
|
||||
MCU_inst->codec_DB_inst.codec_state[codecPos],
|
||||
(const uint16_t *) RTPpacket[0].payload,
|
||||
(int32_t) RTPpacket[0].payloadLen, RTPpacket[0].seqNumber,
|
||||
(uint32_t) RTPpacket[0].timeStamp, (uint32_t) uw32_timeRec);
|
||||
}
|
||||
}
|
||||
|
||||
if (MCU_inst->BufferStat_inst.Automode_inst.lastPackCNGorDTMF == 0)
|
||||
{
|
||||
/* Calculate the total speech length carried in each packet */
|
||||
temp_bufsize = WebRtcNetEQ_PacketBufferGetSize(
|
||||
&MCU_inst->PacketBuffer_inst, &MCU_inst->codec_DB_inst,
|
||||
MCU_inst->av_sync) - temp_bufsize;
|
||||
|
||||
if ((temp_bufsize > 0) && (MCU_inst->BufferStat_inst.Automode_inst.lastPackCNGorDTMF
|
||||
== 0) && (temp_bufsize
|
||||
!= MCU_inst->BufferStat_inst.Automode_inst.packetSpeechLenSamp))
|
||||
{
|
||||
/* Change the auto-mode parameters if packet length has changed */
|
||||
WebRtcNetEQ_SetPacketSpeechLen(&(MCU_inst->BufferStat_inst.Automode_inst),
|
||||
(int16_t) temp_bufsize, MCU_inst->fs);
|
||||
}
|
||||
|
||||
/* update statistics */
|
||||
if ((int32_t) (RTPpacket[0].timeStamp - MCU_inst->timeStamp) >= 0
|
||||
&& !MCU_inst->new_codec)
|
||||
{
|
||||
/*
|
||||
* Only update statistics if incoming packet is not older than last played out
|
||||
* packet, and if new codec flag is not set.
|
||||
*/
|
||||
WebRtcNetEQ_UpdateIatStatistics(&MCU_inst->BufferStat_inst.Automode_inst,
|
||||
MCU_inst->PacketBuffer_inst.maxInsertPositions, RTPpacket[0].seqNumber,
|
||||
RTPpacket[0].timeStamp, MCU_inst->fs,
|
||||
WebRtcNetEQ_DbIsMDCodec((enum WebRtcNetEQDecoder) MCU_inst->current_Codec),
|
||||
(MCU_inst->NetEqPlayoutMode == kPlayoutStreaming));
|
||||
}
|
||||
}
|
||||
else if (MCU_inst->BufferStat_inst.Automode_inst.lastPackCNGorDTMF == -1)
|
||||
{
|
||||
/*
|
||||
* This is first "normal" packet after CNG or DTMF.
|
||||
* Reset packet time counter and measure time until next packet,
|
||||
* but don't update statistics.
|
||||
*/
|
||||
MCU_inst->BufferStat_inst.Automode_inst.lastPackCNGorDTMF = 0;
|
||||
MCU_inst->BufferStat_inst.Automode_inst.packetIatCountSamp = 0;
|
||||
}
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
int WebRtcNetEQ_GetTimestampScaling(MCUInst_t *MCU_inst, int rtpPayloadType)
|
||||
{
|
||||
enum WebRtcNetEQDecoder codec;
|
||||
int codecNumber;
|
||||
|
||||
codecNumber = WebRtcNetEQ_DbGetCodec(&MCU_inst->codec_DB_inst, rtpPayloadType);
|
||||
if (codecNumber < 0)
|
||||
{
|
||||
/* error */
|
||||
return codecNumber;
|
||||
}
|
||||
|
||||
/* cast to enumerator */
|
||||
codec = (enum WebRtcNetEQDecoder) codecNumber;
|
||||
|
||||
/*
|
||||
* The factor obtained below is the number with which the RTP timestamp must be
|
||||
* multiplied to get the true sample count.
|
||||
*/
|
||||
switch (codec)
|
||||
{
|
||||
case kDecoderG722:
|
||||
case kDecoderG722_2ch:
|
||||
{
|
||||
/* Use timestamp scaling with factor 2 (two output samples per RTP timestamp) */
|
||||
MCU_inst->scalingFactor = kTSscalingTwo;
|
||||
break;
|
||||
}
|
||||
case kDecoderISACfb:
|
||||
case kDecoderOpus:
|
||||
{
|
||||
/* We resample Opus internally to 32 kHz, and isac-fb decodes at
|
||||
* 32 kHz, but timestamps are counted at 48 kHz. So there are two
|
||||
* output samples per three RTP timestamp ticks. */
|
||||
MCU_inst->scalingFactor = kTSscalingTwoThirds;
|
||||
break;
|
||||
}
|
||||
|
||||
case kDecoderAVT:
|
||||
case kDecoderCNG:
|
||||
{
|
||||
/* TODO(tlegrand): remove scaling once ACM has full 48 kHz
|
||||
* support. */
|
||||
uint16_t sample_freq =
|
||||
WebRtcNetEQ_DbGetSampleRate(&MCU_inst->codec_DB_inst,
|
||||
rtpPayloadType);
|
||||
if (sample_freq == 48000) {
|
||||
MCU_inst->scalingFactor = kTSscalingTwoThirds;
|
||||
}
|
||||
|
||||
/* For sample_freq <= 32 kHz, do not change the timestamp scaling
|
||||
* settings. */
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
/* do not use timestamp scaling */
|
||||
MCU_inst->scalingFactor = kTSnoScaling;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t WebRtcNetEQ_ScaleTimestampExternalToInternal(const MCUInst_t *MCU_inst,
|
||||
uint32_t externalTS)
|
||||
{
|
||||
int32_t timestampDiff;
|
||||
uint32_t internalTS;
|
||||
|
||||
/* difference between this and last incoming timestamp */
|
||||
timestampDiff = externalTS - MCU_inst->externalTS;
|
||||
|
||||
switch (MCU_inst->scalingFactor)
|
||||
{
|
||||
case kTSscalingTwo:
|
||||
{
|
||||
/* multiply with 2 */
|
||||
timestampDiff = WEBRTC_SPL_LSHIFT_W32(timestampDiff, 1);
|
||||
break;
|
||||
}
|
||||
case kTSscalingTwoThirds:
|
||||
{
|
||||
/* multiply with 2/3 */
|
||||
timestampDiff = WEBRTC_SPL_LSHIFT_W32(timestampDiff, 1);
|
||||
timestampDiff = WebRtcSpl_DivW32W16(timestampDiff, 3);
|
||||
break;
|
||||
}
|
||||
case kTSscalingFourThirds:
|
||||
{
|
||||
/* multiply with 4/3 */
|
||||
timestampDiff = WEBRTC_SPL_LSHIFT_W32(timestampDiff, 2);
|
||||
timestampDiff = WebRtcSpl_DivW32W16(timestampDiff, 3);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
/* no scaling */
|
||||
}
|
||||
}
|
||||
|
||||
/* add the scaled difference to last scaled timestamp and save ... */
|
||||
internalTS = MCU_inst->internalTS + timestampDiff;
|
||||
|
||||
return internalTS;
|
||||
}
|
||||
|
||||
uint32_t WebRtcNetEQ_ScaleTimestampInternalToExternal(const MCUInst_t *MCU_inst,
|
||||
uint32_t internalTS)
|
||||
{
|
||||
int32_t timestampDiff;
|
||||
uint32_t externalTS;
|
||||
|
||||
/* difference between this and last incoming timestamp */
|
||||
timestampDiff = (int32_t) internalTS - MCU_inst->internalTS;
|
||||
|
||||
switch (MCU_inst->scalingFactor)
|
||||
{
|
||||
case kTSscalingTwo:
|
||||
{
|
||||
/* divide by 2 */
|
||||
timestampDiff = WEBRTC_SPL_RSHIFT_W32(timestampDiff, 1);
|
||||
break;
|
||||
}
|
||||
case kTSscalingTwoThirds:
|
||||
{
|
||||
/* multiply with 3/2 */
|
||||
timestampDiff = WEBRTC_SPL_MUL_32_16(timestampDiff, 3);
|
||||
timestampDiff = WEBRTC_SPL_RSHIFT_W32(timestampDiff, 1);
|
||||
break;
|
||||
}
|
||||
case kTSscalingFourThirds:
|
||||
{
|
||||
/* multiply with 3/4 */
|
||||
timestampDiff = WEBRTC_SPL_MUL_32_16(timestampDiff, 3);
|
||||
timestampDiff = WEBRTC_SPL_RSHIFT_W32(timestampDiff, 2);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
/* no scaling */
|
||||
}
|
||||
}
|
||||
|
||||
/* add the scaled difference to last scaled timestamp and save ... */
|
||||
externalTS = MCU_inst->externalTS + timestampDiff;
|
||||
|
||||
return externalTS;
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -1,134 +0,0 @@
|
||||
/*
|
||||
* 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 RTCP statistics reporting.
|
||||
*/
|
||||
|
||||
#include "rtcp.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "signal_processing_library.h"
|
||||
|
||||
int WebRtcNetEQ_RTCPInit(WebRtcNetEQ_RTCP_t *RTCP_inst, uint16_t uw16_seqNo)
|
||||
{
|
||||
/*
|
||||
* Initialize everything to zero and then set the start values for the RTP packet stream.
|
||||
*/
|
||||
WebRtcSpl_MemSetW16((int16_t*) RTCP_inst, 0,
|
||||
sizeof(WebRtcNetEQ_RTCP_t) / sizeof(int16_t));
|
||||
RTCP_inst->base_seq = uw16_seqNo;
|
||||
RTCP_inst->max_seq = uw16_seqNo;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int WebRtcNetEQ_RTCPUpdate(WebRtcNetEQ_RTCP_t *RTCP_inst, uint16_t uw16_seqNo,
|
||||
uint32_t uw32_timeStamp, uint32_t uw32_recTime)
|
||||
{
|
||||
int16_t w16_SeqDiff;
|
||||
int32_t w32_TimeDiff;
|
||||
int32_t w32_JitterDiff;
|
||||
|
||||
/*
|
||||
* Update number of received packets, and largest packet number received.
|
||||
*/
|
||||
RTCP_inst->received++;
|
||||
w16_SeqDiff = uw16_seqNo - RTCP_inst->max_seq;
|
||||
if (w16_SeqDiff >= 0)
|
||||
{
|
||||
if (uw16_seqNo < RTCP_inst->max_seq)
|
||||
{
|
||||
/* Wrap around detected */
|
||||
RTCP_inst->cycles++;
|
||||
}
|
||||
RTCP_inst->max_seq = uw16_seqNo;
|
||||
}
|
||||
|
||||
/* Calculate Jitter, and update previous timestamps */
|
||||
/* Note that the value in RTCP_inst->jitter is in Q4. */
|
||||
if (RTCP_inst->received > 1)
|
||||
{
|
||||
w32_TimeDiff = (uw32_recTime - (uw32_timeStamp - RTCP_inst->transit));
|
||||
w32_TimeDiff = WEBRTC_SPL_ABS_W32(w32_TimeDiff);
|
||||
w32_JitterDiff = WEBRTC_SPL_LSHIFT_W16(w32_TimeDiff, 4) - RTCP_inst->jitter;
|
||||
RTCP_inst->jitter = RTCP_inst->jitter + WEBRTC_SPL_RSHIFT_W32((w32_JitterDiff + 8), 4);
|
||||
}
|
||||
RTCP_inst->transit = (uw32_timeStamp - uw32_recTime);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int WebRtcNetEQ_RTCPGetStats(WebRtcNetEQ_RTCP_t *RTCP_inst,
|
||||
uint16_t *puw16_fraction_lost,
|
||||
uint32_t *puw32_cum_lost, uint32_t *puw32_ext_max,
|
||||
uint32_t *puw32_jitter, int16_t doNotReset)
|
||||
{
|
||||
uint32_t uw32_exp_nr, uw32_exp_interval, uw32_rec_interval;
|
||||
int32_t w32_lost;
|
||||
|
||||
/* Extended highest sequence number received */
|
||||
*puw32_ext_max
|
||||
= (uint32_t) WEBRTC_SPL_LSHIFT_W32((uint32_t)RTCP_inst->cycles, 16)
|
||||
+ RTCP_inst->max_seq;
|
||||
|
||||
/*
|
||||
* Calculate expected number of packets and compare it to the number of packets that
|
||||
* were actually received => the cumulative number of packets lost can be extracted.
|
||||
*/
|
||||
uw32_exp_nr = *puw32_ext_max - RTCP_inst->base_seq + 1;
|
||||
if (RTCP_inst->received == 0)
|
||||
{
|
||||
/* no packets received, assume none lost */
|
||||
*puw32_cum_lost = 0;
|
||||
}
|
||||
else if (uw32_exp_nr > RTCP_inst->received)
|
||||
{
|
||||
*puw32_cum_lost = uw32_exp_nr - RTCP_inst->received;
|
||||
if (*puw32_cum_lost > (uint32_t) 0xFFFFFF)
|
||||
{
|
||||
*puw32_cum_lost = 0xFFFFFF;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
*puw32_cum_lost = 0;
|
||||
}
|
||||
|
||||
/* Fraction lost (Since last report) */
|
||||
uw32_exp_interval = uw32_exp_nr - RTCP_inst->exp_prior;
|
||||
if (!doNotReset)
|
||||
{
|
||||
RTCP_inst->exp_prior = uw32_exp_nr;
|
||||
}
|
||||
uw32_rec_interval = RTCP_inst->received - RTCP_inst->rec_prior;
|
||||
if (!doNotReset)
|
||||
{
|
||||
RTCP_inst->rec_prior = RTCP_inst->received;
|
||||
}
|
||||
w32_lost = (int32_t) (uw32_exp_interval - uw32_rec_interval);
|
||||
if (uw32_exp_interval == 0 || w32_lost <= 0 || RTCP_inst->received == 0)
|
||||
{
|
||||
*puw16_fraction_lost = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
*puw16_fraction_lost = (uint16_t) (WEBRTC_SPL_LSHIFT_W32(w32_lost, 8)
|
||||
/ uw32_exp_interval);
|
||||
}
|
||||
if (*puw16_fraction_lost > 0xFF)
|
||||
{
|
||||
*puw16_fraction_lost = 0xFF;
|
||||
}
|
||||
|
||||
/* Inter-arrival jitter */
|
||||
*puw32_jitter = (RTCP_inst->jitter) >> 4; /* scaling from Q4 */
|
||||
return 0;
|
||||
}
|
||||
|
@ -1,102 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* RTCP statistics reporting.
|
||||
*/
|
||||
|
||||
#ifndef RTCP_H
|
||||
#define RTCP_H
|
||||
|
||||
#include "typedefs.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint16_t cycles; /* The number of wrap-arounds for the sequence number */
|
||||
uint16_t max_seq; /* The maximum sequence number received
|
||||
(starts from 0 again after wrap around) */
|
||||
uint16_t base_seq; /* The sequence number of the first packet that arrived */
|
||||
uint32_t received; /* The number of packets that has been received */
|
||||
uint32_t rec_prior; /* Number of packets received when last report was generated */
|
||||
uint32_t exp_prior; /* Number of packets that should have been received if no
|
||||
packets were lost. Stored value from last report. */
|
||||
uint32_t jitter; /* Jitter statistics at this instance (calculated according to RFC) */
|
||||
int32_t transit; /* Clock difference for previous packet (RTPtimestamp - LOCALtime_rec) */
|
||||
} WebRtcNetEQ_RTCP_t;
|
||||
|
||||
/****************************************************************************
|
||||
* WebRtcNetEQ_RTCPInit(...)
|
||||
*
|
||||
* This function calculates the parameters that are needed for the RTCP
|
||||
* report.
|
||||
*
|
||||
* Input:
|
||||
* - RTCP_inst : RTCP instance, that contains information about the
|
||||
* packets that have been received etc.
|
||||
* - seqNo : Packet number of the first received frame.
|
||||
*
|
||||
* Return value : 0 - Ok
|
||||
* -1 - Error
|
||||
*/
|
||||
|
||||
int WebRtcNetEQ_RTCPInit(WebRtcNetEQ_RTCP_t *RTCP_inst, uint16_t uw16_seqNo);
|
||||
|
||||
/****************************************************************************
|
||||
* WebRtcNetEQ_RTCPUpdate(...)
|
||||
*
|
||||
* This function calculates the parameters that are needed for the RTCP
|
||||
* report.
|
||||
*
|
||||
* Input:
|
||||
* - RTCP_inst : RTCP instance, that contains information about the
|
||||
* packets that have been received etc.
|
||||
* - seqNo : Packet number of the first received frame.
|
||||
* - timeStamp : Time stamp from the RTP header.
|
||||
* - recTime : Time (in RTP timestamps) when this packet was received.
|
||||
*
|
||||
* Return value : 0 - Ok
|
||||
* -1 - Error
|
||||
*/
|
||||
|
||||
int WebRtcNetEQ_RTCPUpdate(WebRtcNetEQ_RTCP_t *RTCP_inst, uint16_t uw16_seqNo,
|
||||
uint32_t uw32_timeStamp, uint32_t uw32_recTime);
|
||||
|
||||
/****************************************************************************
|
||||
* WebRtcNetEQ_RTCPGetStats(...)
|
||||
*
|
||||
* This function calculates the parameters that are needed for the RTCP
|
||||
* report.
|
||||
*
|
||||
* Input:
|
||||
* - RTCP_inst : RTCP instance, that contains information about the
|
||||
* packets that have been received etc.
|
||||
* - doNotReset : If non-zero, the fraction lost statistics will not
|
||||
* be reset.
|
||||
*
|
||||
* Output:
|
||||
* - RTCP_inst : Updated RTCP information (some statistics are
|
||||
* reset when generating this report)
|
||||
* - fraction_lost : Number of lost RTP packets divided by the number of
|
||||
* expected packets, since the last RTCP Report.
|
||||
* - cum_lost : Cumulative number of lost packets during this
|
||||
* session.
|
||||
* - ext_max : Extended highest sequence number received.
|
||||
* - jitter : Inter-arrival jitter.
|
||||
*
|
||||
* Return value : 0 - Ok
|
||||
* -1 - Error
|
||||
*/
|
||||
|
||||
int WebRtcNetEQ_RTCPGetStats(WebRtcNetEQ_RTCP_t *RTCP_inst,
|
||||
uint16_t *puw16_fraction_lost,
|
||||
uint32_t *puw32_cum_lost, uint32_t *puw32_ext_max,
|
||||
uint32_t *puw32_jitter, int16_t doNotReset);
|
||||
|
||||
#endif
|
@ -1,240 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* RTP related functions.
|
||||
*/
|
||||
|
||||
#include "rtp.h"
|
||||
|
||||
#include "typedefs.h" /* to define endianness */
|
||||
|
||||
#include "neteq_error_codes.h"
|
||||
|
||||
int WebRtcNetEQ_RTPPayloadInfo(int16_t* pw16_Datagram, int i_DatagramLen,
|
||||
RTPPacket_t* RTPheader)
|
||||
{
|
||||
int i_P, i_X, i_CC, i_startPosition;
|
||||
int i_IPver;
|
||||
int i_extlength = -1; /* Default value is there is no extension */
|
||||
int i_padlength = 0; /* Default value if there is no padding */
|
||||
|
||||
if (i_DatagramLen < 12)
|
||||
{
|
||||
return RTP_TOO_SHORT_PACKET;
|
||||
}
|
||||
|
||||
#ifdef WEBRTC_ARCH_BIG_ENDIAN
|
||||
i_IPver = (((uint16_t) (pw16_Datagram[0] & 0xC000)) >> 14); /* Extract the version */
|
||||
i_P = (((uint16_t) (pw16_Datagram[0] & 0x2000)) >> 13); /* Extract the P bit */
|
||||
i_X = (((uint16_t) (pw16_Datagram[0] & 0x1000)) >> 12); /* Extract the X bit */
|
||||
i_CC = ((uint16_t) (pw16_Datagram[0] >> 8) & 0xF); /* Get the CC number */
|
||||
RTPheader->payloadType = pw16_Datagram[0] & 0x7F; /* Get the coder type */
|
||||
RTPheader->seqNumber = pw16_Datagram[1]; /* Get the sequence number */
|
||||
RTPheader->timeStamp = ((((uint32_t) ((uint16_t) pw16_Datagram[2])) << 16)
|
||||
| (uint16_t) (pw16_Datagram[3])); /* Get timestamp */
|
||||
RTPheader->ssrc = (((uint32_t) pw16_Datagram[4]) << 16)
|
||||
+ (((uint32_t) pw16_Datagram[5])); /* Get the SSRC */
|
||||
|
||||
if (i_X == 1)
|
||||
{
|
||||
/* Extension header exists. Find out how many int32_t it consists of. */
|
||||
i_extlength = pw16_Datagram[7 + 2 * i_CC];
|
||||
}
|
||||
if (i_P == 1)
|
||||
{
|
||||
/* Padding exists. Find out how many bytes the padding consists of. */
|
||||
if (i_DatagramLen & 0x1)
|
||||
{
|
||||
/* odd number of bytes => last byte in higher byte */
|
||||
i_padlength = (((uint16_t) pw16_Datagram[i_DatagramLen >> 1]) >> 8);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* even number of bytes => last byte in lower byte */
|
||||
i_padlength = ((pw16_Datagram[(i_DatagramLen >> 1) - 1]) & 0xFF);
|
||||
}
|
||||
}
|
||||
#else /* WEBRTC_ARCH_LITTLE_ENDIAN */
|
||||
i_IPver = (((uint16_t) (pw16_Datagram[0] & 0xC0)) >> 6); /* Extract the IP version */
|
||||
i_P = (((uint16_t) (pw16_Datagram[0] & 0x20)) >> 5); /* Extract the P bit */
|
||||
i_X = (((uint16_t) (pw16_Datagram[0] & 0x10)) >> 4); /* Extract the X bit */
|
||||
i_CC = (uint16_t) (pw16_Datagram[0] & 0xF); /* Get the CC number */
|
||||
RTPheader->payloadType = (pw16_Datagram[0] >> 8) & 0x7F; /* Get the coder type */
|
||||
RTPheader->seqNumber = (((((uint16_t) pw16_Datagram[1]) >> 8) & 0xFF)
|
||||
| (((uint16_t) (pw16_Datagram[1] & 0xFF)) << 8)); /* Get the packet number */
|
||||
RTPheader->timeStamp = ((((uint16_t) pw16_Datagram[2]) & 0xFF) << 24)
|
||||
| ((((uint16_t) pw16_Datagram[2]) & 0xFF00) << 8)
|
||||
| ((((uint16_t) pw16_Datagram[3]) >> 8) & 0xFF)
|
||||
| ((((uint16_t) pw16_Datagram[3]) & 0xFF) << 8); /* Get timestamp */
|
||||
RTPheader->ssrc = ((((uint16_t) pw16_Datagram[4]) & 0xFF) << 24)
|
||||
| ((((uint16_t) pw16_Datagram[4]) & 0xFF00) << 8)
|
||||
| ((((uint16_t) pw16_Datagram[5]) >> 8) & 0xFF)
|
||||
| ((((uint16_t) pw16_Datagram[5]) & 0xFF) << 8); /* Get the SSRC */
|
||||
|
||||
if (i_X == 1)
|
||||
{
|
||||
/* Extension header exists. Find out how many int32_t it consists of. */
|
||||
i_extlength = (((((uint16_t) pw16_Datagram[7 + 2 * i_CC]) >> 8) & 0xFF)
|
||||
| (((uint16_t) (pw16_Datagram[7 + 2 * i_CC] & 0xFF)) << 8));
|
||||
}
|
||||
if (i_P == 1)
|
||||
{
|
||||
/* Padding exists. Find out how many bytes the padding consists of. */
|
||||
if (i_DatagramLen & 0x1)
|
||||
{
|
||||
/* odd number of bytes => last byte in higher byte */
|
||||
i_padlength = (pw16_Datagram[i_DatagramLen >> 1] & 0xFF);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* even number of bytes => last byte in lower byte */
|
||||
i_padlength = (((uint16_t) pw16_Datagram[(i_DatagramLen >> 1) - 1]) >> 8);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
i_startPosition = 12 + 4 * (i_extlength + 1) + 4 * i_CC;
|
||||
RTPheader->payload = &pw16_Datagram[i_startPosition >> 1];
|
||||
RTPheader->payloadLen = i_DatagramLen - i_startPosition - i_padlength;
|
||||
RTPheader->starts_byte1 = 0;
|
||||
|
||||
if ((i_IPver != 2) || (RTPheader->payloadLen <= 0) || (RTPheader->payloadLen >= 16000)
|
||||
|| (i_startPosition < 12) || (i_startPosition > i_DatagramLen))
|
||||
{
|
||||
return RTP_CORRUPT_PACKET;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef NETEQ_RED_CODEC
|
||||
|
||||
int WebRtcNetEQ_RedundancySplit(RTPPacket_t* RTPheader[], int i_MaximumPayloads,
|
||||
int *i_No_Of_Payloads)
|
||||
{
|
||||
const int16_t *pw16_data = RTPheader[0]->payload; /* Pointer to the data */
|
||||
uint16_t uw16_offsetTimeStamp = 65535, uw16_secondPayload = 65535;
|
||||
int i_blockLength, i_k;
|
||||
int i_discardedBlockLength = 0;
|
||||
int singlePayload = 0;
|
||||
|
||||
#ifdef WEBRTC_ARCH_BIG_ENDIAN
|
||||
if ((pw16_data[0] & 0x8000) == 0)
|
||||
{
|
||||
/* Only one payload in this packet*/
|
||||
singlePayload = 1;
|
||||
/* set the blocklength to -4 to deduce the non-existent 4-byte RED header */
|
||||
i_blockLength = -4;
|
||||
RTPheader[0]->payloadType = ((((uint16_t)pw16_data[0]) & 0x7F00) >> 8);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Discard all but the two last payloads. */
|
||||
while (((pw16_data[2] & 0x8000) != 0) &&
|
||||
(pw16_data<((RTPheader[0]->payload)+((RTPheader[0]->payloadLen+1)>>1))))
|
||||
{
|
||||
i_discardedBlockLength += (4+(((uint16_t)pw16_data[1]) & 0x3FF));
|
||||
pw16_data+=2;
|
||||
}
|
||||
if (pw16_data>=(RTPheader[0]->payload+((RTPheader[0]->payloadLen+1)>>1)))
|
||||
{
|
||||
return RED_SPLIT_ERROR2; /* Error, we are outside the packet */
|
||||
}
|
||||
singlePayload = 0; /* the packet contains more than one payload */
|
||||
uw16_secondPayload = ((((uint16_t)pw16_data[0]) & 0x7F00) >> 8);
|
||||
RTPheader[0]->payloadType = ((((uint16_t)pw16_data[2]) & 0x7F00) >> 8);
|
||||
uw16_offsetTimeStamp = ((((uint16_t)pw16_data[0]) & 0xFF) << 6) +
|
||||
((((uint16_t)pw16_data[1]) & 0xFC00) >> 10);
|
||||
i_blockLength = (((uint16_t)pw16_data[1]) & 0x3FF);
|
||||
}
|
||||
#else /* WEBRTC_ARCH_LITTLE_ENDIAN */
|
||||
if ((pw16_data[0] & 0x80) == 0)
|
||||
{
|
||||
/* Only one payload in this packet */
|
||||
singlePayload = 1;
|
||||
/* set the blocklength to -4 to deduce the non-existent 4-byte RED header */
|
||||
i_blockLength = -4;
|
||||
RTPheader[0]->payloadType = (((uint16_t) pw16_data[0]) & 0x7F);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Discard all but the two last payloads. */
|
||||
while (((pw16_data[2] & 0x80) != 0) && (pw16_data < ((RTPheader[0]->payload)
|
||||
+ ((RTPheader[0]->payloadLen + 1) >> 1))))
|
||||
{
|
||||
i_discardedBlockLength += (4 + ((((uint16_t) pw16_data[1]) & 0x3) << 8)
|
||||
+ ((((uint16_t) pw16_data[1]) & 0xFF00) >> 8));
|
||||
pw16_data += 2;
|
||||
}
|
||||
if (pw16_data >= (RTPheader[0]->payload + ((RTPheader[0]->payloadLen + 1) >> 1)))
|
||||
{
|
||||
return RED_SPLIT_ERROR2; /* Error, we are outside the packet */;
|
||||
}
|
||||
singlePayload = 0; /* the packet contains more than one payload */
|
||||
uw16_secondPayload = (((uint16_t) pw16_data[0]) & 0x7F);
|
||||
RTPheader[0]->payloadType = (((uint16_t) pw16_data[2]) & 0x7F);
|
||||
uw16_offsetTimeStamp = ((((uint16_t) pw16_data[0]) & 0xFF00) >> 2)
|
||||
+ ((((uint16_t) pw16_data[1]) & 0xFC) >> 2);
|
||||
i_blockLength = ((((uint16_t) pw16_data[1]) & 0x3) << 8)
|
||||
+ ((((uint16_t) pw16_data[1]) & 0xFF00) >> 8);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (i_MaximumPayloads < 2 || singlePayload == 1)
|
||||
{
|
||||
/* Reject the redundancy; or no redundant payload present. */
|
||||
for (i_k = 1; i_k < i_MaximumPayloads; i_k++)
|
||||
{
|
||||
RTPheader[i_k]->payloadType = -1;
|
||||
RTPheader[i_k]->payloadLen = 0;
|
||||
}
|
||||
|
||||
/* update the pointer for the main data */
|
||||
pw16_data = &pw16_data[(5 + i_blockLength) >> 1];
|
||||
RTPheader[0]->starts_byte1 = (5 + i_blockLength) & 0x1;
|
||||
RTPheader[0]->payloadLen = RTPheader[0]->payloadLen - (i_blockLength + 5)
|
||||
- i_discardedBlockLength;
|
||||
RTPheader[0]->payload = pw16_data;
|
||||
|
||||
*i_No_Of_Payloads = 1;
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Redundancy accepted, put the redundancy in second RTPheader. */
|
||||
RTPheader[1]->payloadType = uw16_secondPayload;
|
||||
RTPheader[1]->payload = &pw16_data[5 >> 1];
|
||||
RTPheader[1]->starts_byte1 = 5 & 0x1;
|
||||
RTPheader[1]->seqNumber = RTPheader[0]->seqNumber;
|
||||
RTPheader[1]->timeStamp = RTPheader[0]->timeStamp - uw16_offsetTimeStamp;
|
||||
RTPheader[1]->ssrc = RTPheader[0]->ssrc;
|
||||
RTPheader[1]->payloadLen = i_blockLength;
|
||||
|
||||
/* Modify first RTP packet, so that it contains the main data. */
|
||||
RTPheader[0]->payload = &pw16_data[(5 + i_blockLength) >> 1];
|
||||
RTPheader[0]->starts_byte1 = (5 + i_blockLength) & 0x1;
|
||||
RTPheader[0]->payloadLen = RTPheader[0]->payloadLen - (i_blockLength + 5)
|
||||
- i_discardedBlockLength;
|
||||
|
||||
/* Clear the following payloads. */
|
||||
for (i_k = 2; i_k < i_MaximumPayloads; i_k++)
|
||||
{
|
||||
RTPheader[i_k]->payloadType = -1;
|
||||
RTPheader[i_k]->payloadLen = 0;
|
||||
}
|
||||
|
||||
*i_No_Of_Payloads = 2;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -1,78 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* RTP data struct and related functions.
|
||||
*/
|
||||
|
||||
#ifndef RTP_H
|
||||
#define RTP_H
|
||||
|
||||
#include "typedefs.h"
|
||||
|
||||
#include "codec_db.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint16_t seqNumber;
|
||||
uint32_t timeStamp;
|
||||
uint32_t ssrc;
|
||||
int payloadType;
|
||||
const int16_t *payload;
|
||||
int16_t payloadLen;
|
||||
int16_t starts_byte1;
|
||||
int16_t rcuPlCntr;
|
||||
} RTPPacket_t;
|
||||
|
||||
/****************************************************************************
|
||||
* WebRtcNetEQ_RTPPayloadInfo(...)
|
||||
*
|
||||
* Converts a datagram into an RTP header struct.
|
||||
*
|
||||
* Input:
|
||||
* - Datagram : UDP datagram from the network
|
||||
* - DatagramLen : Length in bytes of the datagram
|
||||
*
|
||||
* Output:
|
||||
* - RTPheader : Structure with the datagram info
|
||||
*
|
||||
* Return value : 0 - Ok
|
||||
* -1 - Error
|
||||
*/
|
||||
|
||||
int WebRtcNetEQ_RTPPayloadInfo(int16_t* pw16_Datagram, int i_DatagramLen,
|
||||
RTPPacket_t* RTPheader);
|
||||
|
||||
/****************************************************************************
|
||||
* WebRtcNetEQ_RedundancySplit(...)
|
||||
*
|
||||
* Splits a Redundancy RTP struct into two RTP structs. User has to check
|
||||
* that it's really the redundancy payload. No such check is done inside this
|
||||
* function.
|
||||
*
|
||||
* Input:
|
||||
* - RTPheader : First header holds the whole RTP packet (with the redundancy payload)
|
||||
* - MaximumPayloads:
|
||||
* The maximum number of RTP payloads that should be
|
||||
* extracted (1+maximum_no_of_Redundancies).
|
||||
*
|
||||
* Output:
|
||||
* - RTPheader : First header holds the main RTP data, while 2..N
|
||||
* holds the redundancy data.
|
||||
* - No_Of
|
||||
*
|
||||
* Return value : 0 - Ok
|
||||
* -1 - Error
|
||||
*/
|
||||
|
||||
int WebRtcNetEQ_RedundancySplit(RTPPacket_t* RTPheader[], int i_MaximumPayloads,
|
||||
int *i_No_Of_Payloads);
|
||||
|
||||
#endif
|
@ -1,78 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Function were the sample rate is set.
|
||||
*/
|
||||
|
||||
#include "mcu.h"
|
||||
|
||||
#include "dtmf_buffer.h"
|
||||
#include "neteq_error_codes.h"
|
||||
|
||||
int WebRtcNetEQ_McuSetFs(MCUInst_t *inst, uint16_t fs)
|
||||
{
|
||||
int16_t ok = 0;
|
||||
|
||||
switch (fs)
|
||||
{
|
||||
case 8000:
|
||||
{
|
||||
#ifdef NETEQ_ATEVENT_DECODE
|
||||
ok = WebRtcNetEQ_DtmfDecoderInit(&inst->DTMF_inst, 8000, 560);
|
||||
#endif
|
||||
inst->timestampsPerCall = inst->millisecondsPerCall * 8;
|
||||
break;
|
||||
}
|
||||
|
||||
#ifdef NETEQ_WIDEBAND
|
||||
case 16000:
|
||||
{
|
||||
#ifdef NETEQ_ATEVENT_DECODE
|
||||
ok = WebRtcNetEQ_DtmfDecoderInit(&inst->DTMF_inst, 16000, 1120);
|
||||
#endif
|
||||
inst->timestampsPerCall = inst->millisecondsPerCall * 16;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef NETEQ_32KHZ_WIDEBAND
|
||||
case 32000:
|
||||
{
|
||||
#ifdef NETEQ_ATEVENT_DECODE
|
||||
ok = WebRtcNetEQ_DtmfDecoderInit(&inst->DTMF_inst, 32000, 2240);
|
||||
#endif
|
||||
inst->timestampsPerCall = inst->millisecondsPerCall * 32;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef NETEQ_48KHZ_WIDEBAND
|
||||
case 48000:
|
||||
{
|
||||
#ifdef NETEQ_ATEVENT_DECODE
|
||||
ok = WebRtcNetEQ_DtmfDecoderInit(&inst->DTMF_inst, 48000, 3360);
|
||||
#endif
|
||||
inst->timestampsPerCall = inst->millisecondsPerCall * 48;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
default:
|
||||
{
|
||||
/* Not supported yet */
|
||||
return CODEC_DB_UNSUPPORTED_FS;
|
||||
}
|
||||
} /* end switch */
|
||||
|
||||
inst->fs = fs;
|
||||
|
||||
return ok;
|
||||
}
|
@ -1,820 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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
|
||||
|
||||
|
||||
/*
|
||||
* Update the frame size, if we can.
|
||||
*/
|
||||
static int WebRtcNetEQ_UpdatePackSizeSamples(MCUInst_t* inst, int buffer_pos,
|
||||
int payload_type,
|
||||
int pack_size_samples) {
|
||||
if (buffer_pos >= 0) {
|
||||
int codec_pos;
|
||||
codec_pos = WebRtcNetEQ_DbGetCodec(&inst->codec_DB_inst, payload_type);
|
||||
if (codec_pos >= 0) {
|
||||
codec_pos = inst->codec_DB_inst.position[codec_pos];
|
||||
if (codec_pos >= 0) {
|
||||
int temp_packet_size_samples = WebRtcNetEQ_PacketBufferGetPacketSize(
|
||||
&inst->PacketBuffer_inst, buffer_pos, &inst->codec_DB_inst,
|
||||
codec_pos, pack_size_samples, inst->av_sync);
|
||||
if (temp_packet_size_samples > 0)
|
||||
return temp_packet_size_samples;
|
||||
return pack_size_samples;
|
||||
}
|
||||
}
|
||||
}
|
||||
return pack_size_samples;
|
||||
}
|
||||
|
||||
/*
|
||||
* Signals the MCU that DSP status data is available.
|
||||
*/
|
||||
int WebRtcNetEQ_SignalMcu(MCUInst_t *inst)
|
||||
{
|
||||
|
||||
int i_bufferpos, i_res;
|
||||
uint16_t uw16_instr;
|
||||
DSP2MCU_info_t dspInfo;
|
||||
int16_t *blockPtr, blockLen;
|
||||
uint32_t uw32_availableTS;
|
||||
RTPPacket_t temp_pkt;
|
||||
int32_t w32_bufsize, w32_tmp;
|
||||
int16_t payloadType = -1;
|
||||
int16_t wantedNoOfTimeStamps;
|
||||
int32_t totalTS;
|
||||
int16_t oldPT, latePacketExist = 0;
|
||||
uint32_t oldTS, prevTS, uw32_tmp;
|
||||
uint16_t prevSeqNo;
|
||||
int16_t nextSeqNoAvail;
|
||||
int16_t fs_mult, w16_tmp;
|
||||
int16_t 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;
|
||||
|
||||
/* Increment waiting time for all packets. */
|
||||
WebRtcNetEQ_IncrementWaitingTimes(&inst->PacketBuffer_inst);
|
||||
|
||||
/* 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*int16_t) */
|
||||
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))
|
||||
{
|
||||
int waitingTime;
|
||||
temp_pkt.payload = blockPtr + 1;
|
||||
i_res = WebRtcNetEQ_PacketBufferExtract(&inst->PacketBuffer_inst, &temp_pkt,
|
||||
i_bufferpos, &waitingTime);
|
||||
if (i_res < 0)
|
||||
{ /* error returned */
|
||||
return i_res;
|
||||
}
|
||||
WebRtcNetEQ_StoreWaitingTime(inst, waitingTime);
|
||||
*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,
|
||||
&inst->codec_DB_inst, inst->av_sync);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/* calculate total current buffer size (in ms*8), including sync buffer */
|
||||
w32_bufsize = WebRtcSpl_DivW32W16((w32_bufsize + dspInfo.samplesLeft), fs_mult);
|
||||
|
||||
#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 the frame size, if we can. */
|
||||
inst->PacketBuffer_inst.packSizeSamples =
|
||||
WebRtcNetEQ_UpdatePackSizeSamples(inst, i_bufferpos, payloadType,
|
||||
inst->PacketBuffer_inst.packSizeSamples);
|
||||
/* 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
|
||||
{
|
||||
/* reset counter */
|
||||
inst->NoOfExpandCalls = 0;
|
||||
}
|
||||
|
||||
/* New codec or big change in packet number? */
|
||||
if ((inst->new_codec) || (uw16_instr == BUFSTAT_REINIT))
|
||||
{
|
||||
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 */
|
||||
uint16_t tempFs;
|
||||
|
||||
tempFs = WebRtcNetEQ_DbGetSampleRate(&inst->codec_DB_inst, payloadType);
|
||||
/* TODO(tlegrand): Remove this limitation once ACM has full
|
||||
* 48 kHz support. */
|
||||
if (tempFs > 32000)
|
||||
{
|
||||
inst->fs = 32000;
|
||||
}
|
||||
else if (tempFs > 0)
|
||||
{
|
||||
inst->fs = tempFs;
|
||||
}
|
||||
}
|
||||
WebRtcSpl_MemSetW16((int16_t*) &cinst, 0,
|
||||
sizeof(CodecFuncInst_t) / sizeof(int16_t));
|
||||
cinst.codec_fs = inst->fs;
|
||||
}
|
||||
cinst.timeStamp = inst->timeStamp;
|
||||
blockLen = (sizeof(CodecFuncInst_t)) >> (sizeof(int16_t) - 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 =
|
||||
WebRtcNetEQ_UpdatePackSizeSamples(inst, i_bufferpos, payloadType,
|
||||
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(int16_t) - 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)
|
||||
{
|
||||
uint32_t 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] = (uint16_t) (timeStampJump >> 16);
|
||||
inst->pw16_writeAddress[2] = (uint16_t) (timeStampJump & 0xFFFF);
|
||||
}
|
||||
|
||||
inst->timeStamp = dspInfo.playedOutTS + timeStampJump;
|
||||
|
||||
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
|
||||
= (int32_t) 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
|
||||
= (int32_t) 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
|
||||
= (int32_t) 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] = (uint16_t) (uw32_tmp >> 16);
|
||||
inst->pw16_writeAddress[2] = (uint16_t) (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;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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];
|
||||
|
||||
/* These values are used by NACK module to estimate time-to-play of
|
||||
* a missing packet. Occasionally, NetEq might decide to decode more
|
||||
* than one packet. Therefore, these values store sequence number and
|
||||
* timestamp of the first packet pulled from the packet buffer. In
|
||||
* such cases, these values do not exactly represent the sequence number
|
||||
* or timestamp associated with a 10ms audio pulled from NetEq. NACK
|
||||
* module is designed to compensate for this.
|
||||
*/
|
||||
inst->decoded_packet_sequence_number = prevSeqNo;
|
||||
inst->decoded_packet_timestamp = prevTS;
|
||||
|
||||
/* clear flag bits */
|
||||
inst->pw16_writeAddress[0] = inst->pw16_writeAddress[0] & 0xFF3F;
|
||||
do
|
||||
{
|
||||
int waitingTime;
|
||||
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, &waitingTime);
|
||||
|
||||
if (i_res < 0)
|
||||
{
|
||||
/* error returned */
|
||||
return i_res;
|
||||
}
|
||||
WebRtcNetEQ_StoreWaitingTime(inst, waitingTime);
|
||||
|
||||
#ifdef NETEQ_DELAY_LOGGING
|
||||
temp_var = NETEQ_DELAY_LOGGING_SIGNAL_DECODE;
|
||||
if ((fwrite(&temp_var, sizeof(int),
|
||||
1, delay_fid2) != 1) ||
|
||||
(fwrite(&temp_pkt.timeStamp, sizeof(uint32_t),
|
||||
1, delay_fid2) != 1) ||
|
||||
(fwrite(&dspInfo.samplesLeft, sizeof(uint16_t),
|
||||
1, delay_fid2) != 1)) {
|
||||
return -1;
|
||||
}
|
||||
#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];
|
||||
}
|
||||
/* Update the frame size, if we can. */
|
||||
inst->PacketBuffer_inst.packSizeSamples =
|
||||
WebRtcNetEQ_UpdatePackSizeSamples(inst, i_bufferpos,
|
||||
payloadType, inst->PacketBuffer_inst.packSizeSamples);
|
||||
}
|
||||
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
|
||||
= (int32_t) 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;
|
||||
|
||||
}
|
@ -1,152 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Split an RTP payload (if possible and suitable) and insert into packet buffer.
|
||||
*/
|
||||
|
||||
#include "mcu.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "mcu_dsp_common.h"
|
||||
#include "neteq_error_codes.h"
|
||||
#include "signal_processing_library.h"
|
||||
|
||||
int WebRtcNetEQ_SplitAndInsertPayload(RTPPacket_t* packet,
|
||||
PacketBuf_t* Buffer_inst,
|
||||
SplitInfo_t* split_inst,
|
||||
int16_t* flushed,
|
||||
int av_sync)
|
||||
{
|
||||
|
||||
int i_ok;
|
||||
int len;
|
||||
int i;
|
||||
RTPPacket_t temp_packet;
|
||||
int16_t localFlushed = 0;
|
||||
const int16_t *pw16_startPayload;
|
||||
const int is_sync_rtp = av_sync &&
|
||||
WebRtcNetEQ_IsSyncPayload(packet->payload, packet->payloadLen);
|
||||
*flushed = 0;
|
||||
|
||||
len = packet->payloadLen;
|
||||
|
||||
/* Copy to temp packet that can be modified. */
|
||||
|
||||
WEBRTC_SPL_MEMCPY_W8(&temp_packet,packet,sizeof(RTPPacket_t));
|
||||
|
||||
if (split_inst->deltaBytes == NO_SPLIT ||
|
||||
is_sync_rtp) /* Don't split sync RTPs just insert. */
|
||||
{
|
||||
/* Not splittable codec */
|
||||
i_ok = WebRtcNetEQ_PacketBufferInsert(Buffer_inst, packet,
|
||||
&localFlushed, av_sync);
|
||||
*flushed |= localFlushed;
|
||||
if (i_ok < 0)
|
||||
{
|
||||
return PBUFFER_INSERT_ERROR5;
|
||||
}
|
||||
}
|
||||
else if (split_inst->deltaBytes < -10)
|
||||
{
|
||||
/* G711, PCM16B or G722, use "soft splitting" */
|
||||
int split_size = packet->payloadLen;
|
||||
int mult = WEBRTC_SPL_ABS_W32(split_inst->deltaBytes) - 10;
|
||||
|
||||
/* Find "chunk size" >= 20 ms and < 40 ms
|
||||
* split_inst->deltaTime in this case contains the number of bytes per
|
||||
* timestamp unit times 2
|
||||
*/
|
||||
while (split_size >= ((80 << split_inst->deltaTime) * mult))
|
||||
{
|
||||
split_size >>= 1;
|
||||
}
|
||||
|
||||
/* Make the size an even value. */
|
||||
if (split_size > 1)
|
||||
{
|
||||
split_size >>= 1;
|
||||
split_size *= 2;
|
||||
}
|
||||
|
||||
temp_packet.payloadLen = split_size;
|
||||
pw16_startPayload = temp_packet.payload;
|
||||
i = 0;
|
||||
while (len >= (2 * split_size))
|
||||
{
|
||||
/* insert every chunk */
|
||||
i_ok = WebRtcNetEQ_PacketBufferInsert(Buffer_inst, &temp_packet,
|
||||
&localFlushed, av_sync);
|
||||
*flushed |= localFlushed;
|
||||
temp_packet.timeStamp += ((2 * split_size) >> split_inst->deltaTime);
|
||||
i++;
|
||||
temp_packet.payload = &(pw16_startPayload[(i * split_size) >> 1]);
|
||||
temp_packet.starts_byte1 = temp_packet.starts_byte1 ^ (split_size & 0x1);
|
||||
|
||||
len -= split_size;
|
||||
if (i_ok < 0)
|
||||
{
|
||||
return PBUFFER_INSERT_ERROR1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Insert the rest */
|
||||
temp_packet.payloadLen = len;
|
||||
i_ok = WebRtcNetEQ_PacketBufferInsert(Buffer_inst, &temp_packet,
|
||||
&localFlushed, av_sync);
|
||||
*flushed |= localFlushed;
|
||||
if (i_ok < 0)
|
||||
{
|
||||
return PBUFFER_INSERT_ERROR2;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Frame based codec, use hard splitting. */
|
||||
i = 0;
|
||||
pw16_startPayload = temp_packet.payload;
|
||||
while (len >= split_inst->deltaBytes)
|
||||
{
|
||||
|
||||
temp_packet.payloadLen = split_inst->deltaBytes;
|
||||
i_ok = WebRtcNetEQ_PacketBufferInsert(Buffer_inst, &temp_packet,
|
||||
&localFlushed, av_sync);
|
||||
*flushed |= localFlushed;
|
||||
i++;
|
||||
temp_packet.payload = &(pw16_startPayload[(i * split_inst->deltaBytes) >> 1]);
|
||||
temp_packet.timeStamp += split_inst->deltaTime;
|
||||
temp_packet.starts_byte1 = temp_packet.starts_byte1 ^ (split_inst->deltaBytes
|
||||
& 0x1);
|
||||
|
||||
if (i_ok < 0)
|
||||
{
|
||||
return PBUFFER_INSERT_ERROR3;
|
||||
}
|
||||
len -= split_inst->deltaBytes;
|
||||
|
||||
}
|
||||
if (len > 0)
|
||||
{
|
||||
/* Must be a either an error or a SID frame at the end of the packet. */
|
||||
temp_packet.payloadLen = len;
|
||||
i_ok = WebRtcNetEQ_PacketBufferInsert(Buffer_inst, &temp_packet,
|
||||
&localFlushed, av_sync);
|
||||
*flushed |= localFlushed;
|
||||
if (i_ok < 0)
|
||||
{
|
||||
return PBUFFER_INSERT_ERROR4;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -1,704 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include "NETEQTEST_CodecClass.h"
|
||||
|
||||
#include <stdlib.h> // exit
|
||||
|
||||
#include "webrtc_neteq_help_macros.h"
|
||||
|
||||
NETEQTEST_Decoder::NETEQTEST_Decoder(enum WebRtcNetEQDecoder type, uint16_t fs, const char * name, uint8_t pt)
|
||||
:
|
||||
_decoder(NULL),
|
||||
_decoderType(type),
|
||||
_pt(pt),
|
||||
_fs(fs),
|
||||
_name(name)
|
||||
{
|
||||
}
|
||||
|
||||
int NETEQTEST_Decoder::loadToNetEQ(NETEQTEST_NetEQClass & neteq, WebRtcNetEQ_CodecDef & codecInst)
|
||||
{
|
||||
SET_CODEC_PAR(codecInst, _decoderType, _pt, _decoder, _fs);
|
||||
int err = neteq.loadCodec(codecInst);
|
||||
|
||||
if (err)
|
||||
{
|
||||
printf("Error loading codec %s into NetEQ database\n", _name.c_str());
|
||||
}
|
||||
|
||||
return(err);
|
||||
}
|
||||
|
||||
|
||||
// iSAC
|
||||
#ifdef CODEC_ISAC
|
||||
#include "isac.h"
|
||||
|
||||
decoder_iSAC::decoder_iSAC(uint8_t pt)
|
||||
:
|
||||
NETEQTEST_Decoder(kDecoderISAC, 16000, "iSAC", pt)
|
||||
{
|
||||
int16_t err = WebRtcIsac_Create((ISACStruct **) &_decoder);
|
||||
if (err)
|
||||
{
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
WebRtcIsac_EncoderInit((ISACStruct *) _decoder, 0);
|
||||
WebRtcIsac_SetDecSampRate((ISACStruct *) _decoder, 16000);
|
||||
}
|
||||
|
||||
|
||||
decoder_iSAC::~decoder_iSAC()
|
||||
{
|
||||
if (_decoder)
|
||||
{
|
||||
WebRtcIsac_Free((ISACStruct *) _decoder);
|
||||
_decoder = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int decoder_iSAC::loadToNetEQ(NETEQTEST_NetEQClass & neteq)
|
||||
{
|
||||
WebRtcNetEQ_CodecDef codecInst;
|
||||
|
||||
SET_ISAC_FUNCTIONS(codecInst);
|
||||
|
||||
return(NETEQTEST_Decoder::loadToNetEQ(neteq, codecInst));
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CODEC_ISAC_SWB
|
||||
decoder_iSACSWB::decoder_iSACSWB(uint8_t pt)
|
||||
:
|
||||
NETEQTEST_Decoder(kDecoderISACswb, 32000, "iSAC swb", pt)
|
||||
{
|
||||
int16_t err = WebRtcIsac_Create((ISACStruct **) &_decoder);
|
||||
if (err)
|
||||
{
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
WebRtcIsac_EncoderInit((ISACStruct *) _decoder, 0);
|
||||
WebRtcIsac_SetDecSampRate((ISACStruct *) _decoder, 32000);
|
||||
}
|
||||
|
||||
decoder_iSACSWB::~decoder_iSACSWB()
|
||||
{
|
||||
if (_decoder)
|
||||
{
|
||||
WebRtcIsac_Free((ISACStruct *) _decoder);
|
||||
_decoder = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
int decoder_iSACSWB::loadToNetEQ(NETEQTEST_NetEQClass & neteq)
|
||||
{
|
||||
WebRtcNetEQ_CodecDef codecInst;
|
||||
|
||||
SET_ISACSWB_FUNCTIONS(codecInst);
|
||||
|
||||
return(NETEQTEST_Decoder::loadToNetEQ(neteq, codecInst));
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CODEC_ISAC_FB
|
||||
decoder_iSACFB::decoder_iSACFB(uint8_t pt)
|
||||
: NETEQTEST_Decoder(kDecoderISACfb, 32000, "iSAC fb", pt) {
|
||||
int16_t err = WebRtcIsac_Create((ISACStruct **) &_decoder);
|
||||
if (err) {
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
WebRtcIsac_EncoderInit((ISACStruct *) _decoder, 0);
|
||||
WebRtcIsac_SetDecSampRate((ISACStruct *) _decoder, 32000);
|
||||
}
|
||||
|
||||
decoder_iSACFB::~decoder_iSACFB() {
|
||||
if (_decoder) {
|
||||
WebRtcIsac_Free((ISACStruct *) _decoder);
|
||||
_decoder = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
int decoder_iSACFB::loadToNetEQ(NETEQTEST_NetEQClass & neteq){
|
||||
WebRtcNetEQ_CodecDef codecInst;
|
||||
SET_ISACFB_FUNCTIONS(codecInst);
|
||||
return(NETEQTEST_Decoder::loadToNetEQ(neteq, codecInst));
|
||||
}
|
||||
#endif
|
||||
|
||||
// PCM u/A
|
||||
#ifdef CODEC_G711
|
||||
#include "g711_interface.h"
|
||||
|
||||
decoder_PCMU::decoder_PCMU(uint8_t pt)
|
||||
:
|
||||
NETEQTEST_Decoder(kDecoderPCMu, 8000, "G.711-u", pt)
|
||||
{
|
||||
// no state to crate or init
|
||||
}
|
||||
|
||||
int decoder_PCMU::loadToNetEQ(NETEQTEST_NetEQClass & neteq)
|
||||
{
|
||||
WebRtcNetEQ_CodecDef codecInst;
|
||||
|
||||
SET_PCMU_FUNCTIONS(codecInst);
|
||||
|
||||
return(NETEQTEST_Decoder::loadToNetEQ(neteq, codecInst));
|
||||
|
||||
}
|
||||
|
||||
decoder_PCMA::decoder_PCMA(uint8_t pt)
|
||||
:
|
||||
NETEQTEST_Decoder(kDecoderPCMa, 8000, "G.711-A", pt)
|
||||
{
|
||||
// no state to crate or init
|
||||
}
|
||||
|
||||
int decoder_PCMA::loadToNetEQ(NETEQTEST_NetEQClass & neteq)
|
||||
{
|
||||
WebRtcNetEQ_CodecDef codecInst;
|
||||
|
||||
SET_PCMA_FUNCTIONS(codecInst);
|
||||
|
||||
return(NETEQTEST_Decoder::loadToNetEQ(neteq, codecInst));
|
||||
}
|
||||
#endif
|
||||
|
||||
// Linear PCM16b
|
||||
#if (defined(CODEC_PCM16B) || defined(CODEC_PCM16B_WB) || \
|
||||
defined(CODEC_PCM16B_32KHZ) || defined(CODEC_PCM16B_48KHZ))
|
||||
#include "pcm16b.h"
|
||||
#endif
|
||||
|
||||
#ifdef CODEC_PCM16B
|
||||
int decoder_PCM16B_NB::loadToNetEQ(NETEQTEST_NetEQClass &neteq)
|
||||
{
|
||||
WebRtcNetEQ_CodecDef codecInst;
|
||||
|
||||
SET_PCM16B_FUNCTIONS(codecInst);
|
||||
|
||||
return(NETEQTEST_Decoder::loadToNetEQ(neteq, codecInst));
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CODEC_PCM16B_WB
|
||||
int decoder_PCM16B_WB::loadToNetEQ(NETEQTEST_NetEQClass &neteq)
|
||||
{
|
||||
WebRtcNetEQ_CodecDef codecInst;
|
||||
|
||||
SET_PCM16B_WB_FUNCTIONS(codecInst);
|
||||
|
||||
return(NETEQTEST_Decoder::loadToNetEQ(neteq, codecInst));
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CODEC_PCM16B_32KHZ
|
||||
int decoder_PCM16B_SWB32::loadToNetEQ(NETEQTEST_NetEQClass &neteq)
|
||||
{
|
||||
WebRtcNetEQ_CodecDef codecInst;
|
||||
|
||||
SET_PCM16B_SWB32_FUNCTIONS(codecInst);
|
||||
|
||||
return(NETEQTEST_Decoder::loadToNetEQ(neteq, codecInst));
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CODEC_PCM16B_48KHZ
|
||||
int decoder_PCM16B_SWB48::loadToNetEQ(NETEQTEST_NetEQClass &neteq)
|
||||
{
|
||||
WebRtcNetEQ_CodecDef codecInst;
|
||||
|
||||
SET_PCM16B_SWB48_FUNCTIONS(codecInst);
|
||||
|
||||
return(NETEQTEST_Decoder::loadToNetEQ(neteq, codecInst));
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CODEC_ILBC
|
||||
#include "ilbc.h"
|
||||
decoder_ILBC::decoder_ILBC(uint8_t pt)
|
||||
:
|
||||
NETEQTEST_Decoder(kDecoderILBC, 8000, "iLBC", pt)
|
||||
{
|
||||
int16_t err = WebRtcIlbcfix_DecoderCreate((iLBC_decinst_t **) &_decoder);
|
||||
if (err)
|
||||
{
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
decoder_ILBC::~decoder_ILBC()
|
||||
{
|
||||
WebRtcIlbcfix_DecoderFree((iLBC_decinst_t *) _decoder);
|
||||
}
|
||||
|
||||
int decoder_ILBC::loadToNetEQ(NETEQTEST_NetEQClass & neteq)
|
||||
{
|
||||
WebRtcNetEQ_CodecDef codecInst;
|
||||
|
||||
SET_ILBC_FUNCTIONS(codecInst);
|
||||
|
||||
return(NETEQTEST_Decoder::loadToNetEQ(neteq, codecInst));
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CODEC_G729
|
||||
#include "G729Interface.h"
|
||||
decoder_G729::decoder_G729(uint8_t pt)
|
||||
:
|
||||
NETEQTEST_Decoder(kDecoderG729, 8000, "G.729", pt)
|
||||
{
|
||||
int16_t err = WebRtcG729_CreateDec((G729_decinst_t **) &_decoder);
|
||||
if (err)
|
||||
{
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
decoder_G729::~decoder_G729()
|
||||
{
|
||||
WebRtcG729_FreeDec((G729_decinst_t *) _decoder);
|
||||
}
|
||||
|
||||
int decoder_G729::loadToNetEQ(NETEQTEST_NetEQClass & neteq)
|
||||
{
|
||||
WebRtcNetEQ_CodecDef codecInst;
|
||||
|
||||
SET_G729_FUNCTIONS(codecInst);
|
||||
|
||||
return(NETEQTEST_Decoder::loadToNetEQ(neteq, codecInst));
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CODEC_G729_1
|
||||
#include "G729_1Interface.h"
|
||||
decoder_G729_1::decoder_G729_1(uint8_t pt)
|
||||
:
|
||||
NETEQTEST_Decoder(kDecoderG729_1, 16000, "G.729.1", pt)
|
||||
{
|
||||
int16_t err = WebRtcG7291_Create((G729_1_inst_t **) &_decoder);
|
||||
if (err)
|
||||
{
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
decoder_G729_1::~decoder_G729_1()
|
||||
{
|
||||
WebRtcG7291_Free((G729_1_inst_t *) _decoder);
|
||||
}
|
||||
|
||||
int decoder_G729_1::loadToNetEQ(NETEQTEST_NetEQClass & neteq)
|
||||
{
|
||||
WebRtcNetEQ_CodecDef codecInst;
|
||||
|
||||
SET_G729_1_FUNCTIONS(codecInst);
|
||||
|
||||
return(NETEQTEST_Decoder::loadToNetEQ(neteq, codecInst));
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CODEC_G722
|
||||
#include "g722_interface.h"
|
||||
decoder_G722::decoder_G722(uint8_t pt)
|
||||
:
|
||||
NETEQTEST_Decoder(kDecoderG722, 16000, "G.722", pt)
|
||||
{
|
||||
int16_t err = WebRtcG722_CreateDecoder((G722DecInst **) &_decoder);
|
||||
if (err)
|
||||
{
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
decoder_G722::~decoder_G722()
|
||||
{
|
||||
WebRtcG722_FreeDecoder((G722DecInst *) _decoder);
|
||||
}
|
||||
|
||||
int decoder_G722::loadToNetEQ(NETEQTEST_NetEQClass & neteq)
|
||||
{
|
||||
WebRtcNetEQ_CodecDef codecInst;
|
||||
|
||||
SET_G722_FUNCTIONS(codecInst);
|
||||
|
||||
return(NETEQTEST_Decoder::loadToNetEQ(neteq, codecInst));
|
||||
}
|
||||
#endif
|
||||
|
||||
#if (defined(CODEC_G722_1_16) || defined(CODEC_G722_1_24) || \
|
||||
defined(CODEC_G722_1_32) || defined(CODEC_G722_1C_24) || \
|
||||
defined(CODEC_G722_1C_32) || defined(CODEC_G722_1C_48))
|
||||
#include "G722_1Interface.h"
|
||||
#endif
|
||||
|
||||
#ifdef CODEC_G722_1_16
|
||||
decoder_G722_1_16::decoder_G722_1_16(uint8_t pt)
|
||||
:
|
||||
NETEQTEST_Decoder(kDecoderG722_1_16, 16000, "G.722.1 (16 kbps)", pt)
|
||||
{
|
||||
if (WebRtcG7221_CreateDec16((G722_1_16_decinst_t **) &_decoder))
|
||||
{
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
decoder_G722_1_16::~decoder_G722_1_16()
|
||||
{
|
||||
WebRtcG7221_FreeDec16((G722_1_16_decinst_t *) _decoder);
|
||||
}
|
||||
|
||||
int decoder_G722_1_16::loadToNetEQ(NETEQTEST_NetEQClass & neteq)
|
||||
{
|
||||
WebRtcNetEQ_CodecDef codecInst;
|
||||
|
||||
SET_G722_1_16_FUNCTIONS(codecInst);
|
||||
|
||||
return(NETEQTEST_Decoder::loadToNetEQ(neteq, codecInst));
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CODEC_G722_1_24
|
||||
decoder_G722_1_24::decoder_G722_1_24(uint8_t pt)
|
||||
:
|
||||
NETEQTEST_Decoder(kDecoderG722_1_24, 16000, "G.722.1 (24 kbps)", pt)
|
||||
{
|
||||
if (WebRtcG7221_CreateDec24((G722_1_24_decinst_t **) &_decoder))
|
||||
{
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
decoder_G722_1_24::~decoder_G722_1_24()
|
||||
{
|
||||
WebRtcG7221_FreeDec24((G722_1_24_decinst_t *) _decoder);
|
||||
}
|
||||
|
||||
int decoder_G722_1_24::loadToNetEQ(NETEQTEST_NetEQClass & neteq)
|
||||
{
|
||||
WebRtcNetEQ_CodecDef codecInst;
|
||||
|
||||
SET_G722_1_24_FUNCTIONS(codecInst);
|
||||
|
||||
return(NETEQTEST_Decoder::loadToNetEQ(neteq, codecInst));
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CODEC_G722_1_32
|
||||
decoder_G722_1_32::decoder_G722_1_32(uint8_t pt)
|
||||
:
|
||||
NETEQTEST_Decoder(kDecoderG722_1_32, 16000, "G.722.1 (32 kbps)", pt)
|
||||
{
|
||||
if (WebRtcG7221_CreateDec32((G722_1_32_decinst_t **) &_decoder))
|
||||
{
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
decoder_G722_1_32::~decoder_G722_1_32()
|
||||
{
|
||||
WebRtcG7221_FreeDec32((G722_1_32_decinst_t *) _decoder);
|
||||
}
|
||||
|
||||
int decoder_G722_1_32::loadToNetEQ(NETEQTEST_NetEQClass & neteq)
|
||||
{
|
||||
WebRtcNetEQ_CodecDef codecInst;
|
||||
|
||||
SET_G722_1_32_FUNCTIONS(codecInst);
|
||||
|
||||
return(NETEQTEST_Decoder::loadToNetEQ(neteq, codecInst));
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CODEC_G722_1C_24
|
||||
decoder_G722_1C_24::decoder_G722_1C_24(uint8_t pt)
|
||||
:
|
||||
NETEQTEST_Decoder(kDecoderG722_1C_24, 32000, "G.722.1C (24 kbps)", pt)
|
||||
{
|
||||
if (WebRtcG7221C_CreateDec24((G722_1C_24_decinst_t **) &_decoder))
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
decoder_G722_1C_24::~decoder_G722_1C_24()
|
||||
{
|
||||
WebRtcG7221C_FreeDec24((G722_1C_24_decinst_t *) _decoder);
|
||||
}
|
||||
|
||||
int decoder_G722_1C_24::loadToNetEQ(NETEQTEST_NetEQClass & neteq)
|
||||
{
|
||||
WebRtcNetEQ_CodecDef codecInst;
|
||||
|
||||
SET_G722_1C_24_FUNCTIONS(codecInst);
|
||||
|
||||
return(NETEQTEST_Decoder::loadToNetEQ(neteq, codecInst));
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CODEC_G722_1C_32
|
||||
decoder_G722_1C_32::decoder_G722_1C_32(uint8_t pt)
|
||||
:
|
||||
NETEQTEST_Decoder(kDecoderG722_1C_32, 32000, "G.722.1C (32 kbps)", pt)
|
||||
{
|
||||
if (WebRtcG7221C_CreateDec32((G722_1C_32_decinst_t **) &_decoder))
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
decoder_G722_1C_32::~decoder_G722_1C_32()
|
||||
{
|
||||
WebRtcG7221C_FreeDec32((G722_1C_32_decinst_t *) _decoder);
|
||||
}
|
||||
|
||||
int decoder_G722_1C_32::loadToNetEQ(NETEQTEST_NetEQClass & neteq)
|
||||
{
|
||||
WebRtcNetEQ_CodecDef codecInst;
|
||||
|
||||
SET_G722_1C_32_FUNCTIONS(codecInst);
|
||||
|
||||
return(NETEQTEST_Decoder::loadToNetEQ(neteq, codecInst));
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CODEC_G722_1C_48
|
||||
decoder_G722_1C_48::decoder_G722_1C_48(uint8_t pt)
|
||||
:
|
||||
NETEQTEST_Decoder(kDecoderG722_1C_48, 32000, "G.722.1C (48 kbps)", pt)
|
||||
{
|
||||
if (WebRtcG7221C_CreateDec48((G722_1C_48_decinst_t **) &_decoder))
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
decoder_G722_1C_48::~decoder_G722_1C_48()
|
||||
{
|
||||
WebRtcG7221C_FreeDec48((G722_1C_48_decinst_t *) _decoder);
|
||||
}
|
||||
|
||||
int decoder_G722_1C_48::loadToNetEQ(NETEQTEST_NetEQClass & neteq)
|
||||
{
|
||||
WebRtcNetEQ_CodecDef codecInst;
|
||||
|
||||
SET_G722_1C_48_FUNCTIONS(codecInst);
|
||||
|
||||
return(NETEQTEST_Decoder::loadToNetEQ(neteq, codecInst));
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CODEC_AMR
|
||||
#include "AMRInterface.h"
|
||||
#include "AMRCreation.h"
|
||||
decoder_AMR::decoder_AMR(uint8_t pt)
|
||||
:
|
||||
NETEQTEST_Decoder(kDecoderAMR, 8000, "AMR", pt)
|
||||
{
|
||||
if (WebRtcAmr_CreateDec((AMR_decinst_t **) &_decoder))
|
||||
exit(EXIT_FAILURE);
|
||||
|
||||
WebRtcAmr_DecodeBitmode((AMR_decinst_t *) _decoder, AMRBandwidthEfficient);
|
||||
}
|
||||
|
||||
decoder_AMR::~decoder_AMR()
|
||||
{
|
||||
WebRtcAmr_FreeDec((AMR_decinst_t *) _decoder);
|
||||
}
|
||||
|
||||
int decoder_AMR::loadToNetEQ(NETEQTEST_NetEQClass & neteq)
|
||||
{
|
||||
WebRtcNetEQ_CodecDef codecInst;
|
||||
|
||||
SET_AMR_FUNCTIONS(codecInst);
|
||||
|
||||
return(NETEQTEST_Decoder::loadToNetEQ(neteq, codecInst));
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CODEC_AMRWB
|
||||
#include "AMRWBInterface.h"
|
||||
#include "AMRWBCreation.h"
|
||||
decoder_AMRWB::decoder_AMRWB(uint8_t pt)
|
||||
:
|
||||
NETEQTEST_Decoder(kDecoderAMRWB, 16000, "AMR wb", pt)
|
||||
{
|
||||
if (WebRtcAmrWb_CreateDec((AMRWB_decinst_t **) &_decoder))
|
||||
exit(EXIT_FAILURE);
|
||||
|
||||
WebRtcAmrWb_DecodeBitmode((AMRWB_decinst_t *) _decoder, AMRBandwidthEfficient);
|
||||
}
|
||||
|
||||
decoder_AMRWB::~decoder_AMRWB()
|
||||
{
|
||||
WebRtcAmrWb_FreeDec((AMRWB_decinst_t *) _decoder);
|
||||
}
|
||||
|
||||
int decoder_AMRWB::loadToNetEQ(NETEQTEST_NetEQClass & neteq)
|
||||
{
|
||||
WebRtcNetEQ_CodecDef codecInst;
|
||||
|
||||
SET_AMRWB_FUNCTIONS(codecInst);
|
||||
|
||||
return(NETEQTEST_Decoder::loadToNetEQ(neteq, codecInst));
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CODEC_GSMFR
|
||||
#include "GSMFRInterface.h"
|
||||
#include "GSMFRCreation.h"
|
||||
decoder_GSMFR::decoder_GSMFR(uint8_t pt)
|
||||
:
|
||||
NETEQTEST_Decoder(kDecoderGSMFR, 8000, "GSM-FR", pt)
|
||||
{
|
||||
if (WebRtcGSMFR_CreateDec((GSMFR_decinst_t **) &_decoder))
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
decoder_GSMFR::~decoder_GSMFR()
|
||||
{
|
||||
WebRtcGSMFR_FreeDec((GSMFR_decinst_t *) _decoder);
|
||||
}
|
||||
|
||||
int decoder_GSMFR::loadToNetEQ(NETEQTEST_NetEQClass & neteq)
|
||||
{
|
||||
WebRtcNetEQ_CodecDef codecInst;
|
||||
|
||||
SET_GSMFR_FUNCTIONS(codecInst);
|
||||
|
||||
return(NETEQTEST_Decoder::loadToNetEQ(neteq, codecInst));
|
||||
}
|
||||
#endif
|
||||
|
||||
#if (defined(CODEC_SPEEX_8) || defined (CODEC_SPEEX_16))
|
||||
#include "SpeexInterface.h"
|
||||
decoder_SPEEX::decoder_SPEEX(uint8_t pt, uint16_t fs)
|
||||
:
|
||||
NETEQTEST_Decoder(fs == 8000 ? kDecoderSPEEX_8 : kDecoderSPEEX_16,
|
||||
fs, "SPEEX", pt)
|
||||
{
|
||||
if (fs != 8000 && fs != 16000)
|
||||
throw std::exception("Wrong sample rate for SPEEX");
|
||||
|
||||
if (WebRtcSpeex_CreateDec((SPEEX_decinst_t **) &_decoder, fs, 1))
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
decoder_SPEEX::~decoder_SPEEX()
|
||||
{
|
||||
WebRtcSpeex_FreeDec((SPEEX_decinst_t *) _decoder);
|
||||
}
|
||||
|
||||
int decoder_SPEEX::loadToNetEQ(NETEQTEST_NetEQClass & neteq)
|
||||
{
|
||||
WebRtcNetEQ_CodecDef codecInst;
|
||||
|
||||
SET_SPEEX_FUNCTIONS(codecInst);
|
||||
|
||||
return(NETEQTEST_Decoder::loadToNetEQ(neteq, codecInst));
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CODEC_CELT_32
|
||||
#include "celt_interface.h"
|
||||
decoder_CELT::decoder_CELT(uint8_t pt, uint16_t fs)
|
||||
:
|
||||
NETEQTEST_Decoder(kDecoderCELT_32, fs, "CELT", pt)
|
||||
{
|
||||
if (WebRtcCelt_CreateDec((CELT_decinst_t **) &_decoder, 2))
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
decoder_CELT::~decoder_CELT()
|
||||
{
|
||||
WebRtcCelt_FreeDec((CELT_decinst_t *) _decoder);
|
||||
}
|
||||
|
||||
int decoder_CELT::loadToNetEQ(NETEQTEST_NetEQClass & neteq)
|
||||
{
|
||||
WebRtcNetEQ_CodecDef codecInst;
|
||||
|
||||
SET_CELT_FUNCTIONS(codecInst);
|
||||
|
||||
return(NETEQTEST_Decoder::loadToNetEQ(neteq, codecInst));
|
||||
}
|
||||
|
||||
decoder_CELTslave::decoder_CELTslave(uint8_t pt, uint16_t fs)
|
||||
:
|
||||
NETEQTEST_Decoder(kDecoderCELT_32, fs, "CELT", pt)
|
||||
{
|
||||
if (WebRtcCelt_CreateDec((CELT_decinst_t **) &_decoder, 2))
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
decoder_CELTslave::~decoder_CELTslave()
|
||||
{
|
||||
WebRtcCelt_FreeDec((CELT_decinst_t *) _decoder);
|
||||
}
|
||||
|
||||
int decoder_CELTslave::loadToNetEQ(NETEQTEST_NetEQClass & neteq)
|
||||
{
|
||||
WebRtcNetEQ_CodecDef codecInst;
|
||||
|
||||
SET_CELTSLAVE_FUNCTIONS(codecInst);
|
||||
return(NETEQTEST_Decoder::loadToNetEQ(neteq, codecInst));
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CODEC_RED
|
||||
int decoder_RED::loadToNetEQ(NETEQTEST_NetEQClass & neteq)
|
||||
{
|
||||
WebRtcNetEQ_CodecDef codecInst;
|
||||
|
||||
SET_RED_FUNCTIONS(codecInst);
|
||||
|
||||
return(NETEQTEST_Decoder::loadToNetEQ(neteq, codecInst));
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CODEC_ATEVENT_DECODE
|
||||
int decoder_AVT::loadToNetEQ(NETEQTEST_NetEQClass & neteq)
|
||||
{
|
||||
WebRtcNetEQ_CodecDef codecInst;
|
||||
|
||||
SET_AVT_FUNCTIONS(codecInst);
|
||||
|
||||
return(NETEQTEST_Decoder::loadToNetEQ(neteq, codecInst));
|
||||
}
|
||||
#endif
|
||||
|
||||
#if (defined(CODEC_CNGCODEC8) || defined(CODEC_CNGCODEC16) || \
|
||||
defined(CODEC_CNGCODEC32) || defined(CODEC_CNGCODEC48))
|
||||
#include "webrtc_cng.h"
|
||||
decoder_CNG::decoder_CNG(uint8_t pt, uint16_t fs)
|
||||
:
|
||||
NETEQTEST_Decoder(kDecoderCNG, fs, "CNG", pt)
|
||||
{
|
||||
if (fs != 8000 && fs != 16000 && fs != 32000 && fs != 48000)
|
||||
exit(EXIT_FAILURE);
|
||||
|
||||
if (WebRtcCng_CreateDec((CNG_dec_inst **) &_decoder))
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
decoder_CNG::~decoder_CNG()
|
||||
{
|
||||
WebRtcCng_FreeDec((CNG_dec_inst *) _decoder);
|
||||
}
|
||||
|
||||
int decoder_CNG::loadToNetEQ(NETEQTEST_NetEQClass & neteq)
|
||||
{
|
||||
WebRtcNetEQ_CodecDef codecInst;
|
||||
|
||||
SET_CNG_FUNCTIONS(codecInst);
|
||||
|
||||
return(NETEQTEST_Decoder::loadToNetEQ(neteq, codecInst));
|
||||
}
|
||||
#endif
|
@ -1,316 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#ifndef NETEQTEST_CODECCLASS_H
|
||||
#define NETEQTEST_CODECCLASS_H
|
||||
|
||||
#include <string>
|
||||
#include <string.h>
|
||||
|
||||
#include "typedefs.h"
|
||||
#include "webrtc_neteq.h"
|
||||
#include "NETEQTEST_NetEQClass.h"
|
||||
|
||||
class NETEQTEST_Decoder
|
||||
{
|
||||
public:
|
||||
NETEQTEST_Decoder(enum WebRtcNetEQDecoder type, uint16_t fs, const char * name, uint8_t pt = 0);
|
||||
virtual ~NETEQTEST_Decoder() {};
|
||||
|
||||
virtual int loadToNetEQ(NETEQTEST_NetEQClass & neteq) = 0;
|
||||
|
||||
int getName(char * name, int maxLen) const { strncpy( name, _name.c_str(), maxLen ); return 0;};
|
||||
|
||||
void setPT(uint8_t pt) { _pt = pt; };
|
||||
uint16_t getFs() const { return (_fs); };
|
||||
enum WebRtcNetEQDecoder getType() const { return (_decoderType); };
|
||||
uint8_t getPT() const { return (_pt); };
|
||||
|
||||
protected:
|
||||
int loadToNetEQ(NETEQTEST_NetEQClass & neteq, WebRtcNetEQ_CodecDef & codecInst);
|
||||
|
||||
void * _decoder;
|
||||
enum WebRtcNetEQDecoder _decoderType;
|
||||
uint8_t _pt;
|
||||
uint16_t _fs;
|
||||
std::string _name;
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
|
||||
class decoder_iSAC : public NETEQTEST_Decoder
|
||||
{
|
||||
public:
|
||||
decoder_iSAC(uint8_t pt = 0);
|
||||
virtual ~decoder_iSAC();
|
||||
virtual int loadToNetEQ(NETEQTEST_NetEQClass & neteq) OVERRIDE;
|
||||
};
|
||||
|
||||
|
||||
class decoder_iSACSWB : public NETEQTEST_Decoder
|
||||
{
|
||||
public:
|
||||
decoder_iSACSWB(uint8_t pt = 0);
|
||||
virtual ~decoder_iSACSWB();
|
||||
virtual int loadToNetEQ(NETEQTEST_NetEQClass & neteq) OVERRIDE;
|
||||
};
|
||||
|
||||
|
||||
class decoder_iSACFB : public NETEQTEST_Decoder {
|
||||
public:
|
||||
decoder_iSACFB(uint8_t pt = 0);
|
||||
virtual ~decoder_iSACFB();
|
||||
virtual int loadToNetEQ(NETEQTEST_NetEQClass & neteq) OVERRIDE;
|
||||
};
|
||||
|
||||
|
||||
class decoder_PCMU : public NETEQTEST_Decoder
|
||||
{
|
||||
public:
|
||||
decoder_PCMU(uint8_t pt = 0);
|
||||
virtual ~decoder_PCMU() {};
|
||||
virtual int loadToNetEQ(NETEQTEST_NetEQClass & neteq) OVERRIDE;
|
||||
};
|
||||
|
||||
|
||||
class decoder_PCMA : public NETEQTEST_Decoder
|
||||
{
|
||||
public:
|
||||
decoder_PCMA(uint8_t pt = 0);
|
||||
virtual ~decoder_PCMA() {};
|
||||
virtual int loadToNetEQ(NETEQTEST_NetEQClass & neteq) OVERRIDE;
|
||||
};
|
||||
|
||||
class decoder_PCM16B_NB : public NETEQTEST_Decoder
|
||||
{
|
||||
public:
|
||||
decoder_PCM16B_NB(uint8_t pt = 0) : NETEQTEST_Decoder(kDecoderPCM16B, 8000, "PCM16 nb", pt) {};
|
||||
virtual ~decoder_PCM16B_NB() {};
|
||||
virtual int loadToNetEQ(NETEQTEST_NetEQClass & neteq) OVERRIDE;
|
||||
};
|
||||
class decoder_PCM16B_WB : public NETEQTEST_Decoder
|
||||
{
|
||||
public:
|
||||
decoder_PCM16B_WB(uint8_t pt = 0) : NETEQTEST_Decoder(kDecoderPCM16Bwb, 16000, "PCM16 wb", pt) {};
|
||||
virtual ~decoder_PCM16B_WB() {};
|
||||
virtual int loadToNetEQ(NETEQTEST_NetEQClass & neteq) OVERRIDE;
|
||||
};
|
||||
class decoder_PCM16B_SWB32 : public NETEQTEST_Decoder
|
||||
{
|
||||
public:
|
||||
decoder_PCM16B_SWB32(uint8_t pt = 0) : NETEQTEST_Decoder(kDecoderPCM16Bswb32kHz, 32000, "PCM16 swb32", pt) {};
|
||||
virtual ~decoder_PCM16B_SWB32() {};
|
||||
virtual int loadToNetEQ(NETEQTEST_NetEQClass & neteq) OVERRIDE;
|
||||
};
|
||||
|
||||
class decoder_PCM16B_SWB48 : public NETEQTEST_Decoder
|
||||
{
|
||||
public:
|
||||
decoder_PCM16B_SWB48(uint8_t pt = 0) : NETEQTEST_Decoder(kDecoderPCM16Bswb48kHz, 48000, "PCM16 swb48", pt) {};
|
||||
virtual ~decoder_PCM16B_SWB48() {};
|
||||
virtual int loadToNetEQ(NETEQTEST_NetEQClass & neteq) OVERRIDE;
|
||||
};
|
||||
|
||||
class decoder_ILBC : public NETEQTEST_Decoder
|
||||
{
|
||||
public:
|
||||
decoder_ILBC(uint8_t pt = 0);
|
||||
virtual ~decoder_ILBC();
|
||||
virtual int loadToNetEQ(NETEQTEST_NetEQClass & neteq) OVERRIDE;
|
||||
};
|
||||
|
||||
|
||||
class decoder_G729 : public NETEQTEST_Decoder
|
||||
{
|
||||
public:
|
||||
decoder_G729(uint8_t pt = 0);
|
||||
virtual ~decoder_G729();
|
||||
virtual int loadToNetEQ(NETEQTEST_NetEQClass & neteq) OVERRIDE;
|
||||
};
|
||||
|
||||
class decoder_G729_1 : public NETEQTEST_Decoder
|
||||
{
|
||||
public:
|
||||
decoder_G729_1(uint8_t pt = 0);
|
||||
virtual ~decoder_G729_1();
|
||||
virtual int loadToNetEQ(NETEQTEST_NetEQClass & neteq) OVERRIDE;
|
||||
};
|
||||
|
||||
|
||||
class decoder_G722 : public NETEQTEST_Decoder
|
||||
{
|
||||
public:
|
||||
decoder_G722(uint8_t pt = 0);
|
||||
virtual ~decoder_G722();
|
||||
virtual int loadToNetEQ(NETEQTEST_NetEQClass & neteq) OVERRIDE;
|
||||
};
|
||||
|
||||
|
||||
class decoder_G722_1_16 : public NETEQTEST_Decoder
|
||||
{
|
||||
public:
|
||||
decoder_G722_1_16(uint8_t pt = 0);
|
||||
virtual ~decoder_G722_1_16();
|
||||
virtual int loadToNetEQ(NETEQTEST_NetEQClass & neteq) OVERRIDE;
|
||||
};
|
||||
|
||||
class decoder_G722_1_24 : public NETEQTEST_Decoder
|
||||
{
|
||||
public:
|
||||
decoder_G722_1_24(uint8_t pt = 0);
|
||||
virtual ~decoder_G722_1_24();
|
||||
virtual int loadToNetEQ(NETEQTEST_NetEQClass & neteq) OVERRIDE;
|
||||
};
|
||||
|
||||
class decoder_G722_1_32 : public NETEQTEST_Decoder
|
||||
{
|
||||
public:
|
||||
decoder_G722_1_32(uint8_t pt = 0);
|
||||
virtual ~decoder_G722_1_32();
|
||||
virtual int loadToNetEQ(NETEQTEST_NetEQClass & neteq) OVERRIDE;
|
||||
};
|
||||
|
||||
|
||||
class decoder_G722_1C_24 : public NETEQTEST_Decoder
|
||||
{
|
||||
public:
|
||||
decoder_G722_1C_24(uint8_t pt = 0);
|
||||
virtual ~decoder_G722_1C_24();
|
||||
virtual int loadToNetEQ(NETEQTEST_NetEQClass & neteq) OVERRIDE;
|
||||
};
|
||||
|
||||
class decoder_G722_1C_32 : public NETEQTEST_Decoder
|
||||
{
|
||||
public:
|
||||
decoder_G722_1C_32(uint8_t pt = 0);
|
||||
virtual ~decoder_G722_1C_32();
|
||||
virtual int loadToNetEQ(NETEQTEST_NetEQClass & neteq) OVERRIDE;
|
||||
};
|
||||
|
||||
class decoder_G722_1C_48 : public NETEQTEST_Decoder
|
||||
{
|
||||
public:
|
||||
decoder_G722_1C_48(uint8_t pt = 0);
|
||||
virtual ~decoder_G722_1C_48();
|
||||
virtual int loadToNetEQ(NETEQTEST_NetEQClass & neteq) OVERRIDE;
|
||||
};
|
||||
|
||||
|
||||
class decoder_AMR : public NETEQTEST_Decoder
|
||||
{
|
||||
public:
|
||||
decoder_AMR(uint8_t pt = 0);
|
||||
virtual ~decoder_AMR();
|
||||
virtual int loadToNetEQ(NETEQTEST_NetEQClass & neteq) OVERRIDE;
|
||||
};
|
||||
|
||||
class decoder_AMRWB : public NETEQTEST_Decoder
|
||||
{
|
||||
public:
|
||||
decoder_AMRWB(uint8_t pt = 0);
|
||||
virtual ~decoder_AMRWB();
|
||||
virtual int loadToNetEQ(NETEQTEST_NetEQClass & neteq) OVERRIDE;
|
||||
};
|
||||
|
||||
class decoder_GSMFR : public NETEQTEST_Decoder
|
||||
{
|
||||
public:
|
||||
decoder_GSMFR(uint8_t pt = 0);
|
||||
virtual ~decoder_GSMFR();
|
||||
virtual int loadToNetEQ(NETEQTEST_NetEQClass & neteq) OVERRIDE;
|
||||
};
|
||||
|
||||
class decoder_G726 : public NETEQTEST_Decoder
|
||||
{
|
||||
public:
|
||||
//virtual decoder_G726(uint8_t pt = 0) = 0;
|
||||
decoder_G726(enum WebRtcNetEQDecoder type, const char * name, uint8_t pt = 0);
|
||||
virtual ~decoder_G726();
|
||||
virtual int loadToNetEQ(NETEQTEST_NetEQClass & neteq) = 0;
|
||||
};
|
||||
|
||||
class decoder_G726_16 : public decoder_G726
|
||||
{
|
||||
public:
|
||||
decoder_G726_16(uint8_t pt = 0) : decoder_G726(kDecoderG726_16, "G.726 (16 kbps)", pt) {};
|
||||
virtual int loadToNetEQ(NETEQTEST_NetEQClass & neteq) OVERRIDE;
|
||||
};
|
||||
|
||||
class decoder_G726_24 : public decoder_G726
|
||||
{
|
||||
public:
|
||||
decoder_G726_24(uint8_t pt = 0) : decoder_G726(kDecoderG726_24, "G.726 (24 kbps)", pt) {};
|
||||
virtual int loadToNetEQ(NETEQTEST_NetEQClass & neteq) OVERRIDE;
|
||||
};
|
||||
|
||||
class decoder_G726_32 : public decoder_G726
|
||||
{
|
||||
public:
|
||||
decoder_G726_32(uint8_t pt = 0) : decoder_G726(kDecoderG726_32, "G.726 (32 kbps)", pt) {};
|
||||
virtual int loadToNetEQ(NETEQTEST_NetEQClass & neteq) OVERRIDE;
|
||||
};
|
||||
|
||||
class decoder_G726_40 : public decoder_G726
|
||||
{
|
||||
public:
|
||||
decoder_G726_40(uint8_t pt = 0) : decoder_G726(kDecoderG726_40, "G.726 (40 kbps)", pt) {};
|
||||
virtual int loadToNetEQ(NETEQTEST_NetEQClass & neteq) OVERRIDE;
|
||||
};
|
||||
|
||||
class decoder_SPEEX : public NETEQTEST_Decoder
|
||||
{
|
||||
public:
|
||||
decoder_SPEEX(uint8_t pt = 0, uint16_t fs = 8000);
|
||||
virtual ~decoder_SPEEX();
|
||||
virtual int loadToNetEQ(NETEQTEST_NetEQClass & neteq) OVERRIDE;
|
||||
};
|
||||
|
||||
class decoder_CELT : public NETEQTEST_Decoder
|
||||
{
|
||||
public:
|
||||
decoder_CELT(uint8_t pt = 0, uint16_t fs = 32000);
|
||||
virtual ~decoder_CELT();
|
||||
virtual int loadToNetEQ(NETEQTEST_NetEQClass & neteq) OVERRIDE;
|
||||
};
|
||||
class decoder_CELTslave : public NETEQTEST_Decoder
|
||||
{
|
||||
public:
|
||||
decoder_CELTslave(uint8_t pt = 0, uint16_t fs = 32000);
|
||||
virtual ~decoder_CELTslave();
|
||||
virtual int loadToNetEQ(NETEQTEST_NetEQClass & neteq) OVERRIDE;
|
||||
};
|
||||
|
||||
class decoder_RED : public NETEQTEST_Decoder
|
||||
{
|
||||
public:
|
||||
decoder_RED(uint8_t pt = 0) : NETEQTEST_Decoder(kDecoderRED, 8000, "RED", pt) {};
|
||||
virtual ~decoder_RED() {};
|
||||
virtual int loadToNetEQ(NETEQTEST_NetEQClass & neteq) OVERRIDE;
|
||||
};
|
||||
|
||||
class decoder_AVT : public NETEQTEST_Decoder
|
||||
{
|
||||
public:
|
||||
decoder_AVT(uint8_t pt = 0) : NETEQTEST_Decoder(kDecoderAVT, 8000, "AVT", pt) {};
|
||||
virtual ~decoder_AVT() {};
|
||||
virtual int loadToNetEQ(NETEQTEST_NetEQClass & neteq) OVERRIDE;
|
||||
};
|
||||
|
||||
|
||||
class decoder_CNG : public NETEQTEST_Decoder
|
||||
{
|
||||
public:
|
||||
decoder_CNG(uint8_t pt = 0, uint16_t fs = 8000);
|
||||
virtual ~decoder_CNG();
|
||||
virtual int loadToNetEQ(NETEQTEST_NetEQClass & neteq) OVERRIDE;
|
||||
};
|
||||
|
||||
#endif //NETEQTEST_CODECCLASS_H
|
@ -1,210 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include "NETEQTEST_DummyRTPpacket.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <algorithm> // max
|
||||
|
||||
#ifdef WIN32
|
||||
#include <winsock2.h>
|
||||
#else
|
||||
#include <netinet/in.h> // for htons, htonl, etc
|
||||
#endif
|
||||
|
||||
int NETEQTEST_DummyRTPpacket::readFromFile(FILE *fp)
|
||||
{
|
||||
if (!fp)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
uint16_t length, plen;
|
||||
uint32_t offset;
|
||||
int packetLen;
|
||||
|
||||
bool readNextPacket = true;
|
||||
while (readNextPacket) {
|
||||
readNextPacket = false;
|
||||
if (fread(&length, 2, 1, fp) == 0)
|
||||
{
|
||||
reset();
|
||||
return -2;
|
||||
}
|
||||
length = ntohs(length);
|
||||
|
||||
if (fread(&plen, 2, 1, fp) == 0)
|
||||
{
|
||||
reset();
|
||||
return -1;
|
||||
}
|
||||
packetLen = ntohs(plen);
|
||||
|
||||
if (fread(&offset, 4, 1, fp) == 0)
|
||||
{
|
||||
reset();
|
||||
return -1;
|
||||
}
|
||||
// Store in local variable until we have passed the reset below.
|
||||
uint32_t receiveTime = ntohl(offset);
|
||||
|
||||
// Use length here because a plen of 0 specifies rtcp.
|
||||
length = (uint16_t) (length - _kRDHeaderLen);
|
||||
|
||||
// check buffer size
|
||||
if (_datagram && _memSize < length + 1)
|
||||
{
|
||||
reset();
|
||||
}
|
||||
|
||||
if (!_datagram)
|
||||
{
|
||||
// Add one extra byte, to be able to fake a dummy payload of one byte.
|
||||
_datagram = new uint8_t[length + 1];
|
||||
_memSize = length + 1;
|
||||
}
|
||||
memset(_datagram, 0, length + 1);
|
||||
|
||||
if (length == 0)
|
||||
{
|
||||
_datagramLen = 0;
|
||||
return packetLen;
|
||||
}
|
||||
|
||||
// Read basic header
|
||||
if (fread(_datagram, 1, _kBasicHeaderLen, fp)
|
||||
!= (size_t)_kBasicHeaderLen)
|
||||
{
|
||||
reset();
|
||||
return -1;
|
||||
}
|
||||
_receiveTime = receiveTime;
|
||||
_datagramLen = _kBasicHeaderLen;
|
||||
int header_length = _kBasicHeaderLen;
|
||||
|
||||
// Parse the basic header
|
||||
WebRtcNetEQ_RTPInfo tempRTPinfo;
|
||||
int P, X, CC;
|
||||
parseBasicHeader(&tempRTPinfo, &P, &X, &CC);
|
||||
|
||||
// Check if we have to extend the header
|
||||
if (X != 0 || CC != 0)
|
||||
{
|
||||
int newLen = _kBasicHeaderLen + CC * 4 + X * 4;
|
||||
assert(_memSize >= newLen + 1);
|
||||
|
||||
// Read extension from file
|
||||
size_t readLen = newLen - _kBasicHeaderLen;
|
||||
if (fread(_datagram + _kBasicHeaderLen, 1, readLen,
|
||||
fp) != readLen)
|
||||
{
|
||||
reset();
|
||||
return -1;
|
||||
}
|
||||
_datagramLen = newLen;
|
||||
header_length = newLen;
|
||||
|
||||
if (X != 0)
|
||||
{
|
||||
int totHdrLen = calcHeaderLength(X, CC);
|
||||
assert(_memSize >= totHdrLen);
|
||||
|
||||
// Read extension from file
|
||||
size_t readLen = totHdrLen - newLen;
|
||||
if (fread(_datagram + newLen, 1, readLen, fp)
|
||||
!= readLen)
|
||||
{
|
||||
reset();
|
||||
return -1;
|
||||
}
|
||||
_datagramLen = totHdrLen;
|
||||
header_length = totHdrLen;
|
||||
}
|
||||
}
|
||||
// Make sure that we have at least one byte of dummy payload.
|
||||
_datagramLen = std::max(static_cast<int>(length), header_length + 1);
|
||||
assert(_datagramLen <= _memSize);
|
||||
|
||||
if (!_blockList.empty() && _blockList.count(payloadType()) > 0)
|
||||
{
|
||||
// discard this payload
|
||||
readNextPacket = true;
|
||||
}
|
||||
|
||||
if (_filterSSRC && _selectSSRC != SSRC())
|
||||
{
|
||||
// Discard this payload.
|
||||
readNextPacket = true;
|
||||
}
|
||||
}
|
||||
|
||||
return packetLen;
|
||||
|
||||
}
|
||||
|
||||
int NETEQTEST_DummyRTPpacket::writeToFile(FILE *fp)
|
||||
{
|
||||
if (!fp)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
uint16_t length, plen;
|
||||
uint32_t offset;
|
||||
|
||||
// length including RTPplay header
|
||||
length = htons(_datagramLen + _kRDHeaderLen);
|
||||
if (fwrite(&length, 2, 1, fp) != 1)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
// payload length
|
||||
plen = htons(_datagramLen);
|
||||
if (fwrite(&plen, 2, 1, fp) != 1)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
// offset (=receive time)
|
||||
offset = htonl(_receiveTime);
|
||||
if (fwrite(&offset, 4, 1, fp) != 1)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Figure out the length of the RTP header.
|
||||
int headerLen;
|
||||
if (_datagramLen == 0)
|
||||
{
|
||||
// No payload at all; we are done writing to file.
|
||||
headerLen = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
parseHeader();
|
||||
headerLen = _payloadPtr - _datagram;
|
||||
assert(headerLen >= 0);
|
||||
}
|
||||
|
||||
// write RTP header
|
||||
if (fwrite((unsigned short *) _datagram, 1, headerLen, fp) !=
|
||||
static_cast<size_t>(headerLen))
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
return (headerLen + _kRDHeaderLen); // total number of bytes written
|
||||
|
||||
}
|
||||
|
@ -1,22 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#ifndef NETEQTEST_DUMMYRTPPACKET_H
|
||||
#define NETEQTEST_DUMMYRTPPACKET_H
|
||||
|
||||
#include "NETEQTEST_RTPpacket.h"
|
||||
|
||||
class NETEQTEST_DummyRTPpacket : public NETEQTEST_RTPpacket {
|
||||
public:
|
||||
virtual int readFromFile(FILE* fp) OVERRIDE;
|
||||
virtual int writeToFile(FILE* fp) OVERRIDE;
|
||||
};
|
||||
|
||||
#endif // NETEQTEST_DUMMYRTPPACKET_H
|
@ -1,395 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include <memory.h>
|
||||
|
||||
#include "NETEQTEST_NetEQClass.h"
|
||||
|
||||
|
||||
NETEQTEST_NetEQClass::NETEQTEST_NetEQClass()
|
||||
:
|
||||
_inst(NULL),
|
||||
_instMem(NULL),
|
||||
_bufferMem(NULL),
|
||||
_preparseRTP(false),
|
||||
_fsmult(1),
|
||||
_isMaster(true),
|
||||
_noDecode(false)
|
||||
{
|
||||
#ifdef WINDOWS_TIMING
|
||||
_totTimeRecIn.QuadPart = 0;
|
||||
_totTimeRecOut.QuadPart = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
NETEQTEST_NetEQClass::NETEQTEST_NetEQClass(enum WebRtcNetEQDecoder *usedCodec, int noOfCodecs,
|
||||
uint16_t fs, WebRtcNetEQNetworkType nwType)
|
||||
:
|
||||
_inst(NULL),
|
||||
_instMem(NULL),
|
||||
_bufferMem(NULL),
|
||||
_preparseRTP(false),
|
||||
_fsmult(1),
|
||||
_isMaster(true),
|
||||
_noDecode(false)
|
||||
{
|
||||
#ifdef WINDOWS_TIMING
|
||||
_totTimeRecIn.QuadPart = 0;
|
||||
_totTimeRecOut.QuadPart = 0;
|
||||
#endif
|
||||
|
||||
if (assign() == 0)
|
||||
{
|
||||
if (init(fs) == 0)
|
||||
{
|
||||
assignBuffer(usedCodec, noOfCodecs, nwType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
NETEQTEST_NetEQClass::~NETEQTEST_NetEQClass()
|
||||
{
|
||||
if (_instMem)
|
||||
{
|
||||
delete [] _instMem;
|
||||
_instMem = NULL;
|
||||
}
|
||||
|
||||
if (_bufferMem)
|
||||
{
|
||||
delete [] _bufferMem;
|
||||
_bufferMem = NULL;
|
||||
}
|
||||
|
||||
_inst = NULL;
|
||||
}
|
||||
|
||||
int NETEQTEST_NetEQClass::assign()
|
||||
{
|
||||
int memSize;
|
||||
|
||||
WebRtcNetEQ_AssignSize(&memSize);
|
||||
|
||||
if (_instMem)
|
||||
{
|
||||
delete [] _instMem;
|
||||
_instMem = NULL;
|
||||
}
|
||||
|
||||
_instMem = new int8_t[memSize];
|
||||
|
||||
int ret = WebRtcNetEQ_Assign(&_inst, _instMem);
|
||||
|
||||
if (ret)
|
||||
{
|
||||
printError();
|
||||
}
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
|
||||
int NETEQTEST_NetEQClass::init(uint16_t fs)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!_inst)
|
||||
{
|
||||
// not assigned
|
||||
ret = assign();
|
||||
|
||||
if (ret != 0)
|
||||
{
|
||||
printError();
|
||||
return (ret);
|
||||
}
|
||||
}
|
||||
|
||||
ret = WebRtcNetEQ_Init(_inst, fs);
|
||||
|
||||
if (ret != 0)
|
||||
{
|
||||
printError();
|
||||
}
|
||||
|
||||
return (ret);
|
||||
|
||||
}
|
||||
|
||||
|
||||
int NETEQTEST_NetEQClass::assignBuffer(enum WebRtcNetEQDecoder *usedCodec, int noOfCodecs, WebRtcNetEQNetworkType nwType)
|
||||
{
|
||||
int numPackets, memSize, ret, overhead_bytes;
|
||||
|
||||
if (!_inst)
|
||||
{
|
||||
// not assigned
|
||||
ret = assign();
|
||||
|
||||
if (ret != 0)
|
||||
{
|
||||
printError();
|
||||
return (ret);
|
||||
}
|
||||
|
||||
ret = init();
|
||||
|
||||
if (ret != 0)
|
||||
{
|
||||
printError();
|
||||
return (ret);
|
||||
}
|
||||
}
|
||||
|
||||
ret = WebRtcNetEQ_GetRecommendedBufferSize(_inst, usedCodec, noOfCodecs,
|
||||
nwType, &numPackets, &memSize,
|
||||
&overhead_bytes);
|
||||
|
||||
if (ret != 0)
|
||||
{
|
||||
printError();
|
||||
return (ret);
|
||||
}
|
||||
|
||||
if (_bufferMem)
|
||||
{
|
||||
delete [] _bufferMem;
|
||||
_bufferMem = NULL;
|
||||
}
|
||||
|
||||
_bufferMem = new int8_t[memSize];
|
||||
|
||||
memset(_bufferMem, -1, memSize);
|
||||
|
||||
ret = WebRtcNetEQ_AssignBuffer(_inst, numPackets, _bufferMem, memSize);
|
||||
|
||||
if (ret != 0)
|
||||
{
|
||||
printError();
|
||||
}
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
int NETEQTEST_NetEQClass::loadCodec(WebRtcNetEQ_CodecDef &codecInst)
|
||||
{
|
||||
int err = WebRtcNetEQ_CodecDbAdd(_inst, &codecInst);
|
||||
|
||||
if (err)
|
||||
{
|
||||
printError();
|
||||
}
|
||||
|
||||
return (err);
|
||||
}
|
||||
|
||||
void NETEQTEST_NetEQClass::printError()
|
||||
{
|
||||
if (_inst)
|
||||
{
|
||||
int errorCode = WebRtcNetEQ_GetErrorCode(_inst);
|
||||
|
||||
if (errorCode)
|
||||
{
|
||||
char errorName[WEBRTC_NETEQ_MAX_ERROR_NAME];
|
||||
|
||||
WebRtcNetEQ_GetErrorName(errorCode, errorName, WEBRTC_NETEQ_MAX_ERROR_NAME);
|
||||
|
||||
printf("Error %i: %s\n", errorCode, errorName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void NETEQTEST_NetEQClass::printError(NETEQTEST_RTPpacket &rtp)
|
||||
{
|
||||
// print regular error info
|
||||
printError();
|
||||
|
||||
// print extra info from packet
|
||||
printf("\tRTP: TS=%u, SN=%u, PT=%u, M=%i, len=%i\n",
|
||||
rtp.timeStamp(), rtp.sequenceNumber(), rtp.payloadType(),
|
||||
rtp.markerBit(), rtp.payloadLen());
|
||||
|
||||
}
|
||||
|
||||
int NETEQTEST_NetEQClass::recIn(NETEQTEST_RTPpacket &rtp)
|
||||
{
|
||||
|
||||
int err;
|
||||
#ifdef WINDOWS_TIMING
|
||||
LARGE_INTEGER countA, countB;
|
||||
#endif
|
||||
|
||||
if (_preparseRTP)
|
||||
{
|
||||
WebRtcNetEQ_RTPInfo rtpInfo;
|
||||
// parse RTP header
|
||||
rtp.parseHeader(rtpInfo);
|
||||
|
||||
#ifdef WINDOWS_TIMING
|
||||
QueryPerformanceCounter(&countA); // get start count for processor
|
||||
#endif
|
||||
|
||||
err = WebRtcNetEQ_RecInRTPStruct(_inst, &rtpInfo, rtp.payload(), rtp.payloadLen(), rtp.time() * _fsmult * 8);
|
||||
|
||||
#ifdef WINDOWS_TIMING
|
||||
QueryPerformanceCounter(&countB); // get stop count for processor
|
||||
_totTimeRecIn.QuadPart += (countB.QuadPart - countA.QuadPart);
|
||||
#endif
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
#ifdef WINDOWS_TIMING
|
||||
QueryPerformanceCounter(&countA); // get start count for processor
|
||||
#endif
|
||||
|
||||
err = WebRtcNetEQ_RecIn(_inst, (int16_t *) rtp.datagram(), rtp.dataLen(), rtp.time() * _fsmult * 8);
|
||||
|
||||
#ifdef WINDOWS_TIMING
|
||||
QueryPerformanceCounter(&countB); // get stop count for processor
|
||||
_totTimeRecIn.QuadPart += (countB.QuadPart - countA.QuadPart);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
if (err)
|
||||
{
|
||||
printError(rtp);
|
||||
}
|
||||
|
||||
return (err);
|
||||
|
||||
}
|
||||
|
||||
|
||||
int16_t NETEQTEST_NetEQClass::recOut(int16_t *outData, void *msInfo, enum WebRtcNetEQOutputType *outputType)
|
||||
{
|
||||
int err;
|
||||
int16_t outLen = 0;
|
||||
#ifdef WINDOWS_TIMING
|
||||
LARGE_INTEGER countA, countB;
|
||||
#endif
|
||||
|
||||
#ifdef WINDOWS_TIMING
|
||||
QueryPerformanceCounter(&countA); // get start count for processor
|
||||
#endif
|
||||
|
||||
if (!msInfo)
|
||||
{
|
||||
// no msInfo given, do mono mode
|
||||
if (_noDecode)
|
||||
{
|
||||
err = WebRtcNetEQ_RecOutNoDecode(_inst, outData, &outLen);
|
||||
}
|
||||
else
|
||||
{
|
||||
err = WebRtcNetEQ_RecOut(_inst, outData, &outLen);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// master/slave mode
|
||||
err = WebRtcNetEQ_RecOutMasterSlave(_inst, outData, &outLen, msInfo, static_cast<int16_t>(_isMaster));
|
||||
}
|
||||
|
||||
#ifdef WINDOWS_TIMING
|
||||
QueryPerformanceCounter(&countB); // get stop count for processor
|
||||
_totTimeRecOut.QuadPart += (countB.QuadPart - countA.QuadPart);
|
||||
#endif
|
||||
|
||||
if (err)
|
||||
{
|
||||
printError();
|
||||
}
|
||||
else
|
||||
{
|
||||
int newfsmult = static_cast<int>(outLen / 80);
|
||||
|
||||
if (newfsmult != _fsmult)
|
||||
{
|
||||
#ifdef NETEQTEST_PRINT_WARNINGS
|
||||
printf("Warning: output sample rate changed\n");
|
||||
#endif // NETEQTEST_PRINT_WARNINGS
|
||||
_fsmult = newfsmult;
|
||||
}
|
||||
}
|
||||
|
||||
if (outputType != NULL)
|
||||
{
|
||||
err = WebRtcNetEQ_GetSpeechOutputType(_inst, outputType);
|
||||
|
||||
if (err)
|
||||
{
|
||||
printError();
|
||||
}
|
||||
}
|
||||
|
||||
return (outLen);
|
||||
}
|
||||
|
||||
|
||||
uint32_t NETEQTEST_NetEQClass::getSpeechTimeStamp()
|
||||
{
|
||||
|
||||
uint32_t ts = 0;
|
||||
int err;
|
||||
|
||||
err = WebRtcNetEQ_GetSpeechTimeStamp(_inst, &ts);
|
||||
|
||||
if (err)
|
||||
{
|
||||
printError();
|
||||
ts = 0;
|
||||
}
|
||||
|
||||
return (ts);
|
||||
|
||||
}
|
||||
|
||||
WebRtcNetEQOutputType NETEQTEST_NetEQClass::getOutputType() {
|
||||
WebRtcNetEQOutputType type;
|
||||
|
||||
int err = WebRtcNetEQ_GetSpeechOutputType(_inst, &type);
|
||||
if (err)
|
||||
{
|
||||
printError();
|
||||
type = kOutputNormal;
|
||||
}
|
||||
return (type);
|
||||
}
|
||||
|
||||
//NETEQTEST_NetEQVector::NETEQTEST_NetEQVector(int numChannels)
|
||||
//:
|
||||
//channels(numChannels, new NETEQTEST_NetEQClass())
|
||||
//{
|
||||
// //for (int i = 0; i < numChannels; i++)
|
||||
// //{
|
||||
// // channels.push_back(new NETEQTEST_NetEQClass());
|
||||
// //}
|
||||
//}
|
||||
//
|
||||
//NETEQTEST_NetEQVector::NETEQTEST_NetEQVector(int numChannels, enum WebRtcNetEQDecoder *usedCodec, int noOfCodecs,
|
||||
// uint16_t fs, WebRtcNetEQNetworkType nwType)
|
||||
// :
|
||||
//channels(numChannels, new NETEQTEST_NetEQClass(usedCodec, noOfCodecs, fs, nwType))
|
||||
//{
|
||||
// //for (int i = 0; i < numChannels; i++)
|
||||
// //{
|
||||
// // channels.push_back(new NETEQTEST_NetEQClass(usedCodec, noOfCodecs, fs, nwType));
|
||||
// //}
|
||||
//}
|
||||
//
|
||||
//NETEQTEST_NetEQVector::~NETEQTEST_NetEQVector()
|
||||
//{
|
||||
//}
|
||||
|
@ -1,81 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#ifndef NETEQTEST_NETEQCLASS_H
|
||||
#define NETEQTEST_NETEQCLASS_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <vector>
|
||||
|
||||
#include "webrtc_neteq.h"
|
||||
#include "webrtc_neteq_internal.h"
|
||||
|
||||
#include "NETEQTEST_RTPpacket.h"
|
||||
|
||||
#ifdef WIN32
|
||||
#define WINDOWS_TIMING // complexity measurement only implemented for windows
|
||||
//TODO(hlundin):Add complexity testing for Linux.
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
class NETEQTEST_NetEQClass
|
||||
{
|
||||
public:
|
||||
NETEQTEST_NetEQClass();
|
||||
NETEQTEST_NetEQClass(enum WebRtcNetEQDecoder *usedCodec, int noOfCodecs,
|
||||
uint16_t fs = 8000, WebRtcNetEQNetworkType nwType = kTCPLargeJitter);
|
||||
~NETEQTEST_NetEQClass();
|
||||
|
||||
int assign();
|
||||
int init(uint16_t fs = 8000);
|
||||
int assignBuffer(enum WebRtcNetEQDecoder *usedCodec, int noOfCodecs, WebRtcNetEQNetworkType nwType = kTCPLargeJitter);
|
||||
int loadCodec(WebRtcNetEQ_CodecDef & codecInst);
|
||||
int recIn(NETEQTEST_RTPpacket & rtp);
|
||||
int16_t recOut(int16_t *outData, void *msInfo = NULL, enum WebRtcNetEQOutputType *outputType = NULL);
|
||||
uint32_t getSpeechTimeStamp();
|
||||
WebRtcNetEQOutputType getOutputType();
|
||||
|
||||
void * instance() { return (_inst); };
|
||||
void usePreparseRTP( bool useIt = true ) { _preparseRTP = useIt; };
|
||||
bool usingPreparseRTP() { return (_preparseRTP); };
|
||||
void setMaster( bool isMaster = true ) { _isMaster = isMaster; };
|
||||
void setSlave() { _isMaster = false; };
|
||||
void setNoDecode(bool noDecode = true) { _noDecode = noDecode; };
|
||||
bool isMaster() { return (_isMaster); };
|
||||
bool isSlave() { return (!_isMaster); };
|
||||
bool isNoDecode() { return _noDecode; };
|
||||
|
||||
#ifdef WINDOWS_TIMING
|
||||
double getRecInTime() { return (static_cast<double>( _totTimeRecIn.QuadPart )); };
|
||||
double getRecOutTime() { return (static_cast<double>( _totTimeRecOut.QuadPart )); };
|
||||
#else
|
||||
double getRecInTime() { return (0.0); };
|
||||
double getRecOutTime() { return (0.0); };
|
||||
|
||||
#endif
|
||||
|
||||
void printError();
|
||||
void printError(NETEQTEST_RTPpacket & rtp);
|
||||
|
||||
private:
|
||||
void * _inst;
|
||||
int8_t * _instMem;
|
||||
int8_t * _bufferMem;
|
||||
bool _preparseRTP;
|
||||
int _fsmult;
|
||||
bool _isMaster;
|
||||
bool _noDecode;
|
||||
#ifdef WINDOWS_TIMING
|
||||
LARGE_INTEGER _totTimeRecIn;
|
||||
LARGE_INTEGER _totTimeRecOut;
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif //NETEQTEST_NETEQCLASS_H
|
@ -1,882 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include "NETEQTEST_RTPpacket.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h> // rand
|
||||
#include <string.h>
|
||||
|
||||
#ifdef WIN32
|
||||
#include <winsock2.h>
|
||||
#else
|
||||
#include <netinet/in.h> // for htons, htonl, etc
|
||||
#endif
|
||||
|
||||
const int NETEQTEST_RTPpacket::_kRDHeaderLen = 8;
|
||||
const int NETEQTEST_RTPpacket::_kBasicHeaderLen = 12;
|
||||
|
||||
NETEQTEST_RTPpacket::NETEQTEST_RTPpacket()
|
||||
:
|
||||
_datagram(NULL),
|
||||
_payloadPtr(NULL),
|
||||
_memSize(0),
|
||||
_datagramLen(-1),
|
||||
_payloadLen(0),
|
||||
_rtpParsed(false),
|
||||
_receiveTime(0),
|
||||
_lost(false),
|
||||
_selectSSRC(0),
|
||||
_filterSSRC(false)
|
||||
{
|
||||
memset(&_rtpInfo, 0, sizeof(_rtpInfo));
|
||||
_blockList.clear();
|
||||
}
|
||||
|
||||
NETEQTEST_RTPpacket::~NETEQTEST_RTPpacket()
|
||||
{
|
||||
if(_datagram)
|
||||
{
|
||||
delete [] _datagram;
|
||||
}
|
||||
}
|
||||
|
||||
void NETEQTEST_RTPpacket::reset()
|
||||
{
|
||||
if(_datagram) {
|
||||
delete [] _datagram;
|
||||
}
|
||||
_datagram = NULL;
|
||||
_memSize = 0;
|
||||
_datagramLen = -1;
|
||||
_payloadLen = 0;
|
||||
_payloadPtr = NULL;
|
||||
_receiveTime = 0;
|
||||
memset(&_rtpInfo, 0, sizeof(_rtpInfo));
|
||||
_rtpParsed = false;
|
||||
|
||||
}
|
||||
|
||||
int NETEQTEST_RTPpacket::skipFileHeader(FILE *fp)
|
||||
{
|
||||
if (!fp) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
const int kFirstLineLength = 40;
|
||||
char firstline[kFirstLineLength];
|
||||
if (fgets(firstline, kFirstLineLength, fp) == NULL) {
|
||||
return -1;
|
||||
}
|
||||
if (strncmp(firstline, "#!rtpplay", 9) == 0) {
|
||||
if (strncmp(firstline, "#!rtpplay1.0", 12) != 0) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else if (strncmp(firstline, "#!RTPencode", 11) == 0) {
|
||||
if (strncmp(firstline, "#!RTPencode1.0", 14) != 0) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
const int kRtpDumpHeaderSize = 4 + 4 + 4 + 2 + 2;
|
||||
if (fseek(fp, kRtpDumpHeaderSize, SEEK_CUR) != 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int NETEQTEST_RTPpacket::readFromFile(FILE *fp)
|
||||
{
|
||||
if(!fp)
|
||||
{
|
||||
return(-1);
|
||||
}
|
||||
|
||||
uint16_t length, plen;
|
||||
uint32_t offset;
|
||||
int packetLen;
|
||||
|
||||
bool readNextPacket = true;
|
||||
while (readNextPacket) {
|
||||
readNextPacket = false;
|
||||
if (fread(&length,2,1,fp)==0)
|
||||
{
|
||||
reset();
|
||||
return(-2);
|
||||
}
|
||||
length = ntohs(length);
|
||||
|
||||
if (fread(&plen,2,1,fp)==0)
|
||||
{
|
||||
reset();
|
||||
return(-1);
|
||||
}
|
||||
packetLen = ntohs(plen);
|
||||
|
||||
if (fread(&offset,4,1,fp)==0)
|
||||
{
|
||||
reset();
|
||||
return(-1);
|
||||
}
|
||||
// store in local variable until we have passed the reset below
|
||||
uint32_t receiveTime = ntohl(offset);
|
||||
|
||||
// Use length here because a plen of 0 specifies rtcp
|
||||
length = (uint16_t) (length - _kRDHeaderLen);
|
||||
|
||||
// check buffer size
|
||||
if (_datagram && _memSize < length)
|
||||
{
|
||||
reset();
|
||||
}
|
||||
|
||||
if (!_datagram)
|
||||
{
|
||||
_datagram = new uint8_t[length];
|
||||
_memSize = length;
|
||||
}
|
||||
|
||||
if (fread((unsigned short *) _datagram,1,length,fp) != length)
|
||||
{
|
||||
reset();
|
||||
return(-1);
|
||||
}
|
||||
|
||||
_datagramLen = length;
|
||||
_receiveTime = receiveTime;
|
||||
|
||||
if (!_blockList.empty() && _blockList.count(payloadType()) > 0)
|
||||
{
|
||||
readNextPacket = true;
|
||||
}
|
||||
|
||||
if (_filterSSRC && _selectSSRC != SSRC())
|
||||
{
|
||||
readNextPacket = true;
|
||||
}
|
||||
}
|
||||
|
||||
return(packetLen);
|
||||
|
||||
}
|
||||
|
||||
|
||||
int NETEQTEST_RTPpacket::readFixedFromFile(FILE *fp, size_t length)
|
||||
{
|
||||
if (!fp)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
// check buffer size
|
||||
if (_datagram && _memSize < static_cast<int>(length))
|
||||
{
|
||||
reset();
|
||||
}
|
||||
|
||||
if (!_datagram)
|
||||
{
|
||||
_datagram = new uint8_t[length];
|
||||
_memSize = length;
|
||||
}
|
||||
|
||||
if (fread(_datagram, 1, length, fp) != length)
|
||||
{
|
||||
reset();
|
||||
return -1;
|
||||
}
|
||||
|
||||
_datagramLen = length;
|
||||
_receiveTime = 0;
|
||||
|
||||
if (!_blockList.empty() && _blockList.count(payloadType()) > 0)
|
||||
{
|
||||
// discard this payload
|
||||
return readFromFile(fp);
|
||||
}
|
||||
|
||||
return length;
|
||||
|
||||
}
|
||||
|
||||
|
||||
int NETEQTEST_RTPpacket::writeToFile(FILE *fp)
|
||||
{
|
||||
if (!fp)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
uint16_t length, plen;
|
||||
uint32_t offset;
|
||||
|
||||
// length including RTPplay header
|
||||
length = htons(_datagramLen + _kRDHeaderLen);
|
||||
if (fwrite(&length, 2, 1, fp) != 1)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
// payload length
|
||||
plen = htons(_datagramLen);
|
||||
if (fwrite(&plen, 2, 1, fp) != 1)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
// offset (=receive time)
|
||||
offset = htonl(_receiveTime);
|
||||
if (fwrite(&offset, 4, 1, fp) != 1)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
// write packet data
|
||||
if (fwrite(_datagram, 1, _datagramLen, fp) !=
|
||||
static_cast<size_t>(_datagramLen))
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
return _datagramLen + _kRDHeaderLen; // total number of bytes written
|
||||
|
||||
}
|
||||
|
||||
|
||||
void NETEQTEST_RTPpacket::blockPT(uint8_t pt)
|
||||
{
|
||||
_blockList[pt] = true;
|
||||
}
|
||||
|
||||
void NETEQTEST_RTPpacket::selectSSRC(uint32_t ssrc)
|
||||
{
|
||||
_selectSSRC = ssrc;
|
||||
_filterSSRC = true;
|
||||
}
|
||||
|
||||
void NETEQTEST_RTPpacket::parseHeader()
|
||||
{
|
||||
if (_rtpParsed)
|
||||
{
|
||||
// nothing to do
|
||||
return;
|
||||
}
|
||||
|
||||
if (_datagramLen < _kBasicHeaderLen)
|
||||
{
|
||||
// corrupt packet?
|
||||
return;
|
||||
}
|
||||
|
||||
_payloadLen = parseRTPheader(&_payloadPtr);
|
||||
|
||||
_rtpParsed = true;
|
||||
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
void NETEQTEST_RTPpacket::parseHeader(WebRtcNetEQ_RTPInfo & rtpInfo)
|
||||
{
|
||||
if (!_rtpParsed)
|
||||
{
|
||||
// parse the header
|
||||
parseHeader();
|
||||
}
|
||||
|
||||
memcpy(&rtpInfo, &_rtpInfo, sizeof(WebRtcNetEQ_RTPInfo));
|
||||
}
|
||||
|
||||
WebRtcNetEQ_RTPInfo const * NETEQTEST_RTPpacket::RTPinfo() const
|
||||
{
|
||||
if (_rtpParsed)
|
||||
{
|
||||
return &_rtpInfo;
|
||||
}
|
||||
else
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t * NETEQTEST_RTPpacket::datagram() const
|
||||
{
|
||||
if (_datagramLen > 0)
|
||||
{
|
||||
return _datagram;
|
||||
}
|
||||
else
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t * NETEQTEST_RTPpacket::payload() const
|
||||
{
|
||||
if (_payloadLen > 0)
|
||||
{
|
||||
return _payloadPtr;
|
||||
}
|
||||
else
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
int16_t NETEQTEST_RTPpacket::payloadLen()
|
||||
{
|
||||
parseHeader();
|
||||
return _payloadLen;
|
||||
}
|
||||
|
||||
int16_t NETEQTEST_RTPpacket::dataLen() const
|
||||
{
|
||||
return _datagramLen;
|
||||
}
|
||||
|
||||
bool NETEQTEST_RTPpacket::isParsed() const
|
||||
{
|
||||
return _rtpParsed;
|
||||
}
|
||||
|
||||
bool NETEQTEST_RTPpacket::isLost() const
|
||||
{
|
||||
return _lost;
|
||||
}
|
||||
|
||||
uint8_t NETEQTEST_RTPpacket::payloadType() const
|
||||
{
|
||||
WebRtcNetEQ_RTPInfo tempRTPinfo;
|
||||
|
||||
if(_datagram && _datagramLen >= _kBasicHeaderLen)
|
||||
{
|
||||
parseRTPheader(&tempRTPinfo);
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return tempRTPinfo.payloadType;
|
||||
}
|
||||
|
||||
uint16_t NETEQTEST_RTPpacket::sequenceNumber() const
|
||||
{
|
||||
WebRtcNetEQ_RTPInfo tempRTPinfo;
|
||||
|
||||
if(_datagram && _datagramLen >= _kBasicHeaderLen)
|
||||
{
|
||||
parseRTPheader(&tempRTPinfo);
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return tempRTPinfo.sequenceNumber;
|
||||
}
|
||||
|
||||
uint32_t NETEQTEST_RTPpacket::timeStamp() const
|
||||
{
|
||||
WebRtcNetEQ_RTPInfo tempRTPinfo;
|
||||
|
||||
if(_datagram && _datagramLen >= _kBasicHeaderLen)
|
||||
{
|
||||
parseRTPheader(&tempRTPinfo);
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return tempRTPinfo.timeStamp;
|
||||
}
|
||||
|
||||
uint32_t NETEQTEST_RTPpacket::SSRC() const
|
||||
{
|
||||
WebRtcNetEQ_RTPInfo tempRTPinfo;
|
||||
|
||||
if(_datagram && _datagramLen >= _kBasicHeaderLen)
|
||||
{
|
||||
parseRTPheader(&tempRTPinfo);
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return tempRTPinfo.SSRC;
|
||||
}
|
||||
|
||||
uint8_t NETEQTEST_RTPpacket::markerBit() const
|
||||
{
|
||||
WebRtcNetEQ_RTPInfo tempRTPinfo;
|
||||
|
||||
if(_datagram && _datagramLen >= _kBasicHeaderLen)
|
||||
{
|
||||
parseRTPheader(&tempRTPinfo);
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return tempRTPinfo.markerBit;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int NETEQTEST_RTPpacket::setPayloadType(uint8_t pt)
|
||||
{
|
||||
|
||||
if (_datagramLen < 12)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!_rtpParsed)
|
||||
{
|
||||
_rtpInfo.payloadType = pt;
|
||||
}
|
||||
|
||||
_datagram[1]=(unsigned char)(pt & 0xFF);
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
int NETEQTEST_RTPpacket::setSequenceNumber(uint16_t sn)
|
||||
{
|
||||
|
||||
if (_datagramLen < 12)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!_rtpParsed)
|
||||
{
|
||||
_rtpInfo.sequenceNumber = sn;
|
||||
}
|
||||
|
||||
_datagram[2]=(unsigned char)((sn>>8)&0xFF);
|
||||
_datagram[3]=(unsigned char)((sn)&0xFF);
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
int NETEQTEST_RTPpacket::setTimeStamp(uint32_t ts)
|
||||
{
|
||||
|
||||
if (_datagramLen < 12)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!_rtpParsed)
|
||||
{
|
||||
_rtpInfo.timeStamp = ts;
|
||||
}
|
||||
|
||||
_datagram[4]=(unsigned char)((ts>>24)&0xFF);
|
||||
_datagram[5]=(unsigned char)((ts>>16)&0xFF);
|
||||
_datagram[6]=(unsigned char)((ts>>8)&0xFF);
|
||||
_datagram[7]=(unsigned char)(ts & 0xFF);
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
int NETEQTEST_RTPpacket::setSSRC(uint32_t ssrc)
|
||||
{
|
||||
|
||||
if (_datagramLen < 12)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!_rtpParsed)
|
||||
{
|
||||
_rtpInfo.SSRC = ssrc;
|
||||
}
|
||||
|
||||
_datagram[8]=(unsigned char)((ssrc>>24)&0xFF);
|
||||
_datagram[9]=(unsigned char)((ssrc>>16)&0xFF);
|
||||
_datagram[10]=(unsigned char)((ssrc>>8)&0xFF);
|
||||
_datagram[11]=(unsigned char)(ssrc & 0xFF);
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
int NETEQTEST_RTPpacket::setMarkerBit(uint8_t mb)
|
||||
{
|
||||
|
||||
if (_datagramLen < 12)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (_rtpParsed)
|
||||
{
|
||||
_rtpInfo.markerBit = mb;
|
||||
}
|
||||
|
||||
if (mb)
|
||||
{
|
||||
_datagram[0] |= 0x01;
|
||||
}
|
||||
else
|
||||
{
|
||||
_datagram[0] &= 0xFE;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
int NETEQTEST_RTPpacket::setRTPheader(const WebRtcNetEQ_RTPInfo *RTPinfo)
|
||||
{
|
||||
if (_datagramLen < 12)
|
||||
{
|
||||
// this packet is not ok
|
||||
return -1;
|
||||
}
|
||||
|
||||
makeRTPheader(_datagram,
|
||||
RTPinfo->payloadType,
|
||||
RTPinfo->sequenceNumber,
|
||||
RTPinfo->timeStamp,
|
||||
RTPinfo->SSRC,
|
||||
RTPinfo->markerBit);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int NETEQTEST_RTPpacket::splitStereo(NETEQTEST_RTPpacket* slaveRtp,
|
||||
enum stereoModes mode)
|
||||
{
|
||||
// if mono, do nothing
|
||||
if (mode == stereoModeMono)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
// check that the RTP header info is parsed
|
||||
parseHeader();
|
||||
|
||||
// start by copying the main rtp packet
|
||||
*slaveRtp = *this;
|
||||
|
||||
if(_payloadLen == 0)
|
||||
{
|
||||
// do no more
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(_payloadLen%2 != 0)
|
||||
{
|
||||
// length must be a factor of 2
|
||||
return -1;
|
||||
}
|
||||
|
||||
switch(mode)
|
||||
{
|
||||
case stereoModeSample1:
|
||||
{
|
||||
// sample based codec with 1-byte samples
|
||||
splitStereoSample(slaveRtp, 1 /* 1 byte/sample */);
|
||||
break;
|
||||
}
|
||||
case stereoModeSample2:
|
||||
{
|
||||
// sample based codec with 2-byte samples
|
||||
splitStereoSample(slaveRtp, 2 /* 2 bytes/sample */);
|
||||
break;
|
||||
}
|
||||
case stereoModeFrame:
|
||||
{
|
||||
// frame based codec
|
||||
splitStereoFrame(slaveRtp);
|
||||
break;
|
||||
}
|
||||
case stereoModeDuplicate:
|
||||
{
|
||||
// frame based codec, send the whole packet to both master and slave
|
||||
splitStereoDouble(slaveRtp);
|
||||
break;
|
||||
}
|
||||
case stereoModeMono:
|
||||
{
|
||||
assert(false);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void NETEQTEST_RTPpacket::makeRTPheader(unsigned char* rtp_data, uint8_t payloadType, uint16_t seqNo, uint32_t timestamp, uint32_t ssrc, uint8_t markerBit) const
|
||||
{
|
||||
rtp_data[0]=(unsigned char)0x80;
|
||||
if (markerBit)
|
||||
{
|
||||
rtp_data[0] |= 0x01;
|
||||
}
|
||||
else
|
||||
{
|
||||
rtp_data[0] &= 0xFE;
|
||||
}
|
||||
rtp_data[1]=(unsigned char)(payloadType & 0xFF);
|
||||
rtp_data[2]=(unsigned char)((seqNo>>8)&0xFF);
|
||||
rtp_data[3]=(unsigned char)((seqNo)&0xFF);
|
||||
rtp_data[4]=(unsigned char)((timestamp>>24)&0xFF);
|
||||
rtp_data[5]=(unsigned char)((timestamp>>16)&0xFF);
|
||||
|
||||
rtp_data[6]=(unsigned char)((timestamp>>8)&0xFF);
|
||||
rtp_data[7]=(unsigned char)(timestamp & 0xFF);
|
||||
|
||||
rtp_data[8]=(unsigned char)((ssrc>>24)&0xFF);
|
||||
rtp_data[9]=(unsigned char)((ssrc>>16)&0xFF);
|
||||
|
||||
rtp_data[10]=(unsigned char)((ssrc>>8)&0xFF);
|
||||
rtp_data[11]=(unsigned char)(ssrc & 0xFF);
|
||||
}
|
||||
|
||||
uint16_t
|
||||
NETEQTEST_RTPpacket::parseRTPheader(WebRtcNetEQ_RTPInfo *RTPinfo,
|
||||
uint8_t **payloadPtr) const
|
||||
{
|
||||
int16_t *rtp_data = (int16_t *) _datagram;
|
||||
int i_P, i_X, i_CC;
|
||||
|
||||
assert(_datagramLen >= 12);
|
||||
parseBasicHeader(RTPinfo, &i_P, &i_X, &i_CC);
|
||||
|
||||
int i_startPosition = calcHeaderLength(i_X, i_CC);
|
||||
|
||||
int i_padlength = calcPadLength(i_P);
|
||||
|
||||
if (payloadPtr)
|
||||
{
|
||||
*payloadPtr = (uint8_t*) &rtp_data[i_startPosition >> 1];
|
||||
}
|
||||
|
||||
return (uint16_t) (_datagramLen - i_startPosition - i_padlength);
|
||||
}
|
||||
|
||||
|
||||
void NETEQTEST_RTPpacket::parseBasicHeader(WebRtcNetEQ_RTPInfo *RTPinfo,
|
||||
int *i_P, int *i_X, int *i_CC) const
|
||||
{
|
||||
int16_t *rtp_data = (int16_t *) _datagram;
|
||||
if (_datagramLen < 12)
|
||||
{
|
||||
assert(false);
|
||||
return;
|
||||
}
|
||||
|
||||
*i_P=(((uint16_t)(rtp_data[0] & 0x20))>>5); /* Extract the P bit */
|
||||
*i_X=(((uint16_t)(rtp_data[0] & 0x10))>>4); /* Extract the X bit */
|
||||
*i_CC=(uint16_t)(rtp_data[0] & 0xF); /* Get the CC number */
|
||||
/* Get the marker bit */
|
||||
RTPinfo->markerBit = (uint8_t) ((rtp_data[0] >> 15) & 0x01);
|
||||
/* Get the coder type */
|
||||
RTPinfo->payloadType = (uint8_t) ((rtp_data[0] >> 8) & 0x7F);
|
||||
/* Get the packet number */
|
||||
RTPinfo->sequenceNumber = ((( ((uint16_t)rtp_data[1]) >> 8) & 0xFF) |
|
||||
( ((uint16_t)(rtp_data[1] & 0xFF)) << 8));
|
||||
/* Get timestamp */
|
||||
RTPinfo->timeStamp = ((((uint16_t)rtp_data[2]) & 0xFF) << 24) |
|
||||
((((uint16_t)rtp_data[2]) & 0xFF00) << 8) |
|
||||
((((uint16_t)rtp_data[3]) >> 8) & 0xFF) |
|
||||
((((uint16_t)rtp_data[3]) & 0xFF) << 8);
|
||||
/* Get the SSRC */
|
||||
RTPinfo->SSRC=((((uint16_t)rtp_data[4]) & 0xFF) << 24) |
|
||||
((((uint16_t)rtp_data[4]) & 0xFF00) << 8) |
|
||||
((((uint16_t)rtp_data[5]) >> 8) & 0xFF) |
|
||||
((((uint16_t)rtp_data[5]) & 0xFF) << 8);
|
||||
}
|
||||
|
||||
int NETEQTEST_RTPpacket::calcHeaderLength(int i_X, int i_CC) const
|
||||
{
|
||||
int i_extlength = 0;
|
||||
int16_t *rtp_data = (int16_t *) _datagram;
|
||||
|
||||
if (i_X == 1)
|
||||
{
|
||||
// Extension header exists.
|
||||
// Find out how many int32_t it consists of.
|
||||
assert(_datagramLen > 2 * (7 + 2 * i_CC));
|
||||
if (_datagramLen > 2 * (7 + 2 * i_CC))
|
||||
{
|
||||
i_extlength = (((((uint16_t) rtp_data[7 + 2 * i_CC]) >> 8)
|
||||
& 0xFF) | (((uint16_t) (rtp_data[7 + 2 * i_CC] & 0xFF))
|
||||
<< 8)) + 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 12 + 4 * i_extlength + 4 * i_CC;
|
||||
}
|
||||
|
||||
int NETEQTEST_RTPpacket::calcPadLength(int i_P) const
|
||||
{
|
||||
int16_t *rtp_data = (int16_t *) _datagram;
|
||||
if (i_P == 1)
|
||||
{
|
||||
/* Padding exists. Find out how many bytes the padding consists of. */
|
||||
if (_datagramLen & 0x1)
|
||||
{
|
||||
/* odd number of bytes => last byte in higher byte */
|
||||
return rtp_data[_datagramLen >> 1] & 0xFF;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* even number of bytes => last byte in lower byte */
|
||||
return ((uint16_t) rtp_data[(_datagramLen >> 1) - 1]) >> 8;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void NETEQTEST_RTPpacket::splitStereoSample(NETEQTEST_RTPpacket* slaveRtp,
|
||||
int stride)
|
||||
{
|
||||
if(!_payloadPtr || !slaveRtp || !slaveRtp->_payloadPtr
|
||||
|| _payloadLen <= 0 || slaveRtp->_memSize < _memSize)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t *readDataPtr = _payloadPtr;
|
||||
uint8_t *writeDataPtr = _payloadPtr;
|
||||
uint8_t *slaveData = slaveRtp->_payloadPtr;
|
||||
|
||||
while (readDataPtr - _payloadPtr < _payloadLen)
|
||||
{
|
||||
// master data
|
||||
for (int ix = 0; ix < stride; ix++) {
|
||||
*writeDataPtr = *readDataPtr;
|
||||
writeDataPtr++;
|
||||
readDataPtr++;
|
||||
}
|
||||
|
||||
// slave data
|
||||
for (int ix = 0; ix < stride; ix++) {
|
||||
*slaveData = *readDataPtr;
|
||||
slaveData++;
|
||||
readDataPtr++;
|
||||
}
|
||||
}
|
||||
|
||||
_payloadLen /= 2;
|
||||
slaveRtp->_payloadLen = _payloadLen;
|
||||
}
|
||||
|
||||
|
||||
void NETEQTEST_RTPpacket::splitStereoFrame(NETEQTEST_RTPpacket* slaveRtp)
|
||||
{
|
||||
if(!_payloadPtr || !slaveRtp || !slaveRtp->_payloadPtr
|
||||
|| _payloadLen <= 0 || slaveRtp->_memSize < _memSize)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
memmove(slaveRtp->_payloadPtr, _payloadPtr + _payloadLen/2, _payloadLen/2);
|
||||
|
||||
_payloadLen /= 2;
|
||||
slaveRtp->_payloadLen = _payloadLen;
|
||||
}
|
||||
void NETEQTEST_RTPpacket::splitStereoDouble(NETEQTEST_RTPpacket* slaveRtp)
|
||||
{
|
||||
if(!_payloadPtr || !slaveRtp || !slaveRtp->_payloadPtr
|
||||
|| _payloadLen <= 0 || slaveRtp->_memSize < _memSize)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
memcpy(slaveRtp->_payloadPtr, _payloadPtr, _payloadLen);
|
||||
slaveRtp->_payloadLen = _payloadLen;
|
||||
}
|
||||
|
||||
// Get the RTP header for the RED payload indicated by argument index.
|
||||
// The first RED payload is index = 0.
|
||||
int NETEQTEST_RTPpacket::extractRED(int index, WebRtcNetEQ_RTPInfo& red)
|
||||
{
|
||||
//
|
||||
// 0 1 2 3
|
||||
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// |1| block PT | timestamp offset | block length |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// |1| ... |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// |0| block PT |
|
||||
// +-+-+-+-+-+-+-+-+
|
||||
//
|
||||
|
||||
parseHeader();
|
||||
|
||||
uint8_t* ptr = payload();
|
||||
uint8_t* payloadEndPtr = ptr + payloadLen();
|
||||
int num_encodings = 0;
|
||||
int total_len = 0;
|
||||
|
||||
while ((ptr < payloadEndPtr) && (*ptr & 0x80))
|
||||
{
|
||||
int len = ((ptr[2] & 0x03) << 8) + ptr[3];
|
||||
if (num_encodings == index)
|
||||
{
|
||||
// Header found.
|
||||
red.payloadType = ptr[0] & 0x7F;
|
||||
uint32_t offset = (ptr[1] << 6) + ((ptr[2] & 0xFC) >> 2);
|
||||
red.sequenceNumber = sequenceNumber();
|
||||
red.timeStamp = timeStamp() - offset;
|
||||
red.markerBit = markerBit();
|
||||
red.SSRC = SSRC();
|
||||
return len;
|
||||
}
|
||||
++num_encodings;
|
||||
total_len += len;
|
||||
ptr += 4;
|
||||
}
|
||||
if ((ptr < payloadEndPtr) && (num_encodings == index))
|
||||
{
|
||||
// Last header.
|
||||
red.payloadType = ptr[0] & 0x7F;
|
||||
red.sequenceNumber = sequenceNumber();
|
||||
red.timeStamp = timeStamp();
|
||||
red.markerBit = markerBit();
|
||||
red.SSRC = SSRC();
|
||||
++ptr;
|
||||
return payloadLen() - (ptr - payload()) - total_len;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Randomize the payload, not the RTP header.
|
||||
void NETEQTEST_RTPpacket::scramblePayload(void)
|
||||
{
|
||||
parseHeader();
|
||||
|
||||
for (int i = 0; i < _payloadLen; ++i)
|
||||
{
|
||||
_payloadPtr[i] = static_cast<uint8_t>(rand());
|
||||
}
|
||||
}
|
@ -1,108 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#ifndef NETEQTEST_RTPPACKET_H
|
||||
#define NETEQTEST_RTPPACKET_H
|
||||
|
||||
#include <map>
|
||||
#include <stdio.h>
|
||||
#include "typedefs.h"
|
||||
#include "webrtc_neteq_internal.h"
|
||||
|
||||
enum stereoModes {
|
||||
stereoModeMono,
|
||||
stereoModeSample1,
|
||||
stereoModeSample2,
|
||||
stereoModeFrame,
|
||||
stereoModeDuplicate
|
||||
};
|
||||
|
||||
class NETEQTEST_RTPpacket
|
||||
{
|
||||
public:
|
||||
NETEQTEST_RTPpacket();
|
||||
bool operator !() const { return (dataLen() < 0); };
|
||||
virtual ~NETEQTEST_RTPpacket();
|
||||
void reset();
|
||||
static int skipFileHeader(FILE *fp);
|
||||
virtual int readFromFile(FILE *fp);
|
||||
int readFixedFromFile(FILE *fp, size_t len);
|
||||
virtual int writeToFile(FILE *fp);
|
||||
void blockPT(uint8_t pt);
|
||||
void selectSSRC(uint32_t ssrc);
|
||||
//int16_t payloadType();
|
||||
void parseHeader();
|
||||
void parseHeader(WebRtcNetEQ_RTPInfo & rtpInfo);
|
||||
WebRtcNetEQ_RTPInfo const * RTPinfo() const;
|
||||
uint8_t * datagram() const;
|
||||
uint8_t * payload() const;
|
||||
int16_t payloadLen();
|
||||
int16_t dataLen() const;
|
||||
bool isParsed() const;
|
||||
bool isLost() const;
|
||||
uint32_t time() const { return _receiveTime; };
|
||||
|
||||
uint8_t payloadType() const;
|
||||
uint16_t sequenceNumber() const;
|
||||
uint32_t timeStamp() const;
|
||||
uint32_t SSRC() const;
|
||||
uint8_t markerBit() const;
|
||||
|
||||
int setPayloadType(uint8_t pt);
|
||||
int setSequenceNumber(uint16_t sn);
|
||||
int setTimeStamp(uint32_t ts);
|
||||
int setSSRC(uint32_t ssrc);
|
||||
int setMarkerBit(uint8_t mb);
|
||||
void setTime(uint32_t receiveTime) { _receiveTime = receiveTime; };
|
||||
|
||||
int setRTPheader(const WebRtcNetEQ_RTPInfo *RTPinfo);
|
||||
|
||||
int splitStereo(NETEQTEST_RTPpacket* slaveRtp, enum stereoModes mode);
|
||||
|
||||
int extractRED(int index, WebRtcNetEQ_RTPInfo& red);
|
||||
|
||||
void scramblePayload(void);
|
||||
|
||||
uint8_t * _datagram;
|
||||
uint8_t * _payloadPtr;
|
||||
int _memSize;
|
||||
int16_t _datagramLen;
|
||||
int16_t _payloadLen;
|
||||
WebRtcNetEQ_RTPInfo _rtpInfo;
|
||||
bool _rtpParsed;
|
||||
uint32_t _receiveTime;
|
||||
bool _lost;
|
||||
std::map<uint8_t, bool> _blockList;
|
||||
uint32_t _selectSSRC;
|
||||
bool _filterSSRC;
|
||||
|
||||
protected:
|
||||
static const int _kRDHeaderLen;
|
||||
static const int _kBasicHeaderLen;
|
||||
|
||||
void parseBasicHeader(WebRtcNetEQ_RTPInfo *RTPinfo, int *i_P, int *i_X,
|
||||
int *i_CC) const;
|
||||
int calcHeaderLength(int i_X, int i_CC) const;
|
||||
|
||||
private:
|
||||
void makeRTPheader(unsigned char* rtp_data, uint8_t payloadType,
|
||||
uint16_t seqNo, uint32_t timestamp,
|
||||
uint32_t ssrc, uint8_t markerBit) const;
|
||||
uint16_t parseRTPheader(WebRtcNetEQ_RTPInfo *RTPinfo,
|
||||
uint8_t **payloadPtr = NULL) const;
|
||||
uint16_t parseRTPheader(uint8_t **payloadPtr = NULL)
|
||||
{ return parseRTPheader(&_rtpInfo, payloadPtr);};
|
||||
int calcPadLength(int i_P) const;
|
||||
void splitStereoSample(NETEQTEST_RTPpacket* slaveRtp, int stride);
|
||||
void splitStereoFrame(NETEQTEST_RTPpacket* slaveRtp);
|
||||
void splitStereoDouble(NETEQTEST_RTPpacket* slaveRtp);
|
||||
};
|
||||
|
||||
#endif //NETEQTEST_RTPPACKET_H
|
File diff suppressed because it is too large
Load Diff
@ -1,78 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
/* PayloadTypes.h */
|
||||
/* Used by NetEqRTPplay application */
|
||||
|
||||
/* RTP defined codepoints */
|
||||
#define NETEQ_CODEC_PCMU_PT 0
|
||||
#define NETEQ_CODEC_GSMFR_PT 3
|
||||
#define NETEQ_CODEC_G723_PT 4
|
||||
#define NETEQ_CODEC_DVI4_PT 125 // 8 kHz version
|
||||
//#define NETEQ_CODEC_DVI4_16_PT 6 // 16 kHz version
|
||||
#define NETEQ_CODEC_PCMA_PT 8
|
||||
#define NETEQ_CODEC_G722_PT 9
|
||||
#define NETEQ_CODEC_CN_PT 13
|
||||
//#define NETEQ_CODEC_G728_PT 15
|
||||
//#define NETEQ_CODEC_DVI4_11_PT 16 // 11.025 kHz version
|
||||
//#define NETEQ_CODEC_DVI4_22_PT 17 // 22.050 kHz version
|
||||
#define NETEQ_CODEC_G729_PT 18
|
||||
|
||||
/* Dynamic RTP codepoints as defined in VoiceEngine (file VEAPI.cpp) */
|
||||
#define NETEQ_CODEC_IPCMWB_PT 97
|
||||
#define NETEQ_CODEC_SPEEX8_PT 98
|
||||
#define NETEQ_CODEC_SPEEX16_PT 99
|
||||
#define NETEQ_CODEC_EG711U_PT 100
|
||||
#define NETEQ_CODEC_EG711A_PT 101
|
||||
#define NETEQ_CODEC_ILBC_PT 102
|
||||
#define NETEQ_CODEC_ISAC_PT 103
|
||||
#define NETEQ_CODEC_ISACLC_PT 119
|
||||
#define NETEQ_CODEC_ISACSWB_PT 104
|
||||
#define NETEQ_CODEC_ISACFB_PT 124
|
||||
#define NETEQ_CODEC_AVT_PT 106
|
||||
#define NETEQ_CODEC_G722_1_16_PT 108
|
||||
#define NETEQ_CODEC_G722_1_24_PT 109
|
||||
#define NETEQ_CODEC_G722_1_32_PT 110
|
||||
#define NETEQ_CODEC_SC3_PT 111
|
||||
#define NETEQ_CODEC_AMR_PT 112
|
||||
#define NETEQ_CODEC_GSMEFR_PT 113
|
||||
//#define NETEQ_CODEC_ILBCRCU_PT 114
|
||||
#define NETEQ_CODEC_G726_16_PT 115
|
||||
#define NETEQ_CODEC_G726_24_PT 116
|
||||
#define NETEQ_CODEC_G726_32_PT 121
|
||||
#define NETEQ_CODEC_RED_PT 117
|
||||
#define NETEQ_CODEC_G726_40_PT 118
|
||||
//#define NETEQ_CODEC_ENERGY_PT 120
|
||||
#define NETEQ_CODEC_CN_WB_PT 105
|
||||
#define NETEQ_CODEC_CN_SWB_PT 126
|
||||
#define NETEQ_CODEC_G729_1_PT 107
|
||||
#define NETEQ_CODEC_G729D_PT 123
|
||||
//#define NETEQ_CODEC_MELPE_PT 124
|
||||
#define NETEQ_CODEC_CELT32_PT 114
|
||||
|
||||
/* Extra dynamic codepoints */
|
||||
#define NETEQ_CODEC_AMRWB_PT 120
|
||||
#define NETEQ_CODEC_PCM16B_PT 93
|
||||
#define NETEQ_CODEC_PCM16B_WB_PT 94
|
||||
#define NETEQ_CODEC_PCM16B_SWB32KHZ_PT 95
|
||||
#define NETEQ_CODEC_PCM16B_SWB48KHZ_PT 96
|
||||
#define NETEQ_CODEC_MPEG4AAC_PT 122
|
||||
|
||||
|
||||
/* Not default in VoiceEngine */
|
||||
#define NETEQ_CODEC_G722_1C_24_PT 84
|
||||
#define NETEQ_CODEC_G722_1C_32_PT 85
|
||||
#define NETEQ_CODEC_G722_1C_48_PT 86
|
||||
|
||||
#define NETEQ_CODEC_SILK_8_PT 80
|
||||
#define NETEQ_CODEC_SILK_12_PT 81
|
||||
#define NETEQ_CODEC_SILK_16_PT 82
|
||||
#define NETEQ_CODEC_SILK_24_PT 83
|
||||
|
@ -1,75 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
#include "modules/audio_coding/neteq/test/NETEQTEST_RTPpacket.h"
|
||||
|
||||
#define FIRSTLINELEN 40
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
if (argc < 3) {
|
||||
printf("Usage: RTPcat in1.rtp int2.rtp [...] out.rtp\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
FILE* in_file = fopen(argv[1], "rb");
|
||||
if (!in_file) {
|
||||
printf("Cannot open input file %s\n", argv[1]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
FILE* out_file = fopen(argv[argc - 1], "wb"); // Last parameter is out file.
|
||||
if (!out_file) {
|
||||
printf("Cannot open output file %s\n", argv[argc - 1]);
|
||||
return -1;
|
||||
}
|
||||
printf("Output RTP file: %s\n\n", argv[argc - 1]);
|
||||
|
||||
// Read file header and write directly to output file.
|
||||
char firstline[FIRSTLINELEN];
|
||||
const unsigned int kRtpDumpHeaderSize = 4 + 4 + 4 + 2 + 2;
|
||||
EXPECT_TRUE(fgets(firstline, FIRSTLINELEN, in_file) != NULL);
|
||||
EXPECT_GT(fputs(firstline, out_file), 0);
|
||||
EXPECT_EQ(kRtpDumpHeaderSize, fread(firstline, 1, kRtpDumpHeaderSize,
|
||||
in_file));
|
||||
EXPECT_EQ(kRtpDumpHeaderSize, fwrite(firstline, 1, kRtpDumpHeaderSize,
|
||||
out_file));
|
||||
|
||||
// Close input file and re-open it later (easier to write the loop below).
|
||||
fclose(in_file);
|
||||
|
||||
for (int i = 1; i < argc - 1; i++) {
|
||||
in_file = fopen(argv[i], "rb");
|
||||
if (!in_file) {
|
||||
printf("Cannot open input file %s\n", argv[i]);
|
||||
return -1;
|
||||
}
|
||||
printf("Input RTP file: %s\n", argv[i]);
|
||||
|
||||
NETEQTEST_RTPpacket::skipFileHeader(in_file);
|
||||
NETEQTEST_RTPpacket packet;
|
||||
int pack_len = packet.readFromFile(in_file);
|
||||
if (pack_len < 0) {
|
||||
exit(1);
|
||||
}
|
||||
while (pack_len >= 0) {
|
||||
packet.writeToFile(out_file);
|
||||
pack_len = packet.readFromFile(in_file);
|
||||
}
|
||||
fclose(in_file);
|
||||
}
|
||||
fclose(out_file);
|
||||
return 0;
|
||||
}
|
@ -1,133 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
|
||||
#include "modules/audio_coding/neteq/test/NETEQTEST_RTPpacket.h"
|
||||
#include "modules/audio_coding/neteq/test/NETEQTEST_DummyRTPpacket.h"
|
||||
|
||||
#define FIRSTLINELEN 40
|
||||
//#define WEBRTC_DUMMY_RTP
|
||||
|
||||
static bool pktCmp(NETEQTEST_RTPpacket *a, NETEQTEST_RTPpacket *b) {
|
||||
return (a->time() < b->time());
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
FILE* in_file = fopen(argv[1], "rb");
|
||||
if (!in_file) {
|
||||
printf("Cannot open input file %s\n", argv[1]);
|
||||
return -1;
|
||||
}
|
||||
printf("Input RTP file: %s\n", argv[1]);
|
||||
|
||||
FILE* stat_file = fopen(argv[2], "rt");
|
||||
if (!stat_file) {
|
||||
printf("Cannot open timing file %s\n", argv[2]);
|
||||
return -1;
|
||||
}
|
||||
printf("Timing file: %s\n", argv[2]);
|
||||
|
||||
FILE* out_file = fopen(argv[3], "wb");
|
||||
if (!out_file) {
|
||||
printf("Cannot open output file %s\n", argv[3]);
|
||||
return -1;
|
||||
}
|
||||
printf("Output RTP file: %s\n\n", argv[3]);
|
||||
|
||||
// Read all statistics and insert into map.
|
||||
// Read first line.
|
||||
char temp_str[100];
|
||||
if (fgets(temp_str, 100, stat_file) == NULL) {
|
||||
printf("Failed to read timing file %s\n", argv[2]);
|
||||
return -1;
|
||||
}
|
||||
// Define map.
|
||||
std::map<std::pair<uint16_t, uint32_t>, uint32_t> packet_stats;
|
||||
uint16_t seq_no;
|
||||
uint32_t ts;
|
||||
uint32_t send_time;
|
||||
|
||||
while (fscanf(stat_file,
|
||||
"%hu %u %u %*i %*i %*i %*x\n", &seq_no, &ts, &send_time) == 3) {
|
||||
std::pair<uint16_t, uint32_t>
|
||||
temp_pair = std::pair<uint16_t, uint32_t>(seq_no, ts);
|
||||
|
||||
packet_stats[temp_pair] = send_time;
|
||||
}
|
||||
|
||||
fclose(stat_file);
|
||||
|
||||
// Read file header and write directly to output file.
|
||||
char first_line[FIRSTLINELEN];
|
||||
if (fgets(first_line, FIRSTLINELEN, in_file) == NULL) {
|
||||
printf("Failed to read first line of input file %s\n", argv[1]);
|
||||
return -1;
|
||||
}
|
||||
fputs(first_line, out_file);
|
||||
// start_sec + start_usec + source + port + padding
|
||||
const unsigned int kRtpDumpHeaderSize = 4 + 4 + 4 + 2 + 2;
|
||||
if (fread(first_line, 1, kRtpDumpHeaderSize, in_file)
|
||||
!= kRtpDumpHeaderSize) {
|
||||
printf("Failed to read RTP dump header from input file %s\n", argv[1]);
|
||||
return -1;
|
||||
}
|
||||
if (fwrite(first_line, 1, kRtpDumpHeaderSize, out_file)
|
||||
!= kRtpDumpHeaderSize) {
|
||||
printf("Failed to write RTP dump header to output file %s\n", argv[3]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
std::vector<NETEQTEST_RTPpacket *> packet_vec;
|
||||
|
||||
while (1) {
|
||||
// Insert in vector.
|
||||
#ifdef WEBRTC_DUMMY_RTP
|
||||
NETEQTEST_RTPpacket *new_packet = new NETEQTEST_DummyRTPpacket();
|
||||
#else
|
||||
NETEQTEST_RTPpacket *new_packet = new NETEQTEST_RTPpacket();
|
||||
#endif
|
||||
if (new_packet->readFromFile(in_file) < 0) {
|
||||
// End of file.
|
||||
break;
|
||||
}
|
||||
|
||||
// Look for new send time in statistics vector.
|
||||
std::pair<uint16_t, uint32_t> temp_pair =
|
||||
std::pair<uint16_t, uint32_t>(new_packet->sequenceNumber(),
|
||||
new_packet->timeStamp());
|
||||
|
||||
uint32_t new_send_time = packet_stats[temp_pair];
|
||||
new_packet->setTime(new_send_time); // Set new send time.
|
||||
packet_vec.push_back(new_packet); // Insert in vector.
|
||||
}
|
||||
|
||||
// Sort the vector according to send times.
|
||||
std::sort(packet_vec.begin(), packet_vec.end(), pktCmp);
|
||||
|
||||
std::vector<NETEQTEST_RTPpacket *>::iterator it;
|
||||
for (it = packet_vec.begin(); it != packet_vec.end(); it++) {
|
||||
// Write to out file.
|
||||
if ((*it)->writeToFile(out_file) < 0) {
|
||||
printf("Error writing to file\n");
|
||||
return -1;
|
||||
}
|
||||
// Delete packet.
|
||||
delete *it;
|
||||
}
|
||||
|
||||
fclose(in_file);
|
||||
fclose(out_file);
|
||||
|
||||
return 0;
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -1,200 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
//TODO(hlundin): Reformat file to meet style guide.
|
||||
|
||||
/* header includes */
|
||||
#include "typedefs.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#ifdef WIN32
|
||||
#include <winsock2.h>
|
||||
#include <io.h>
|
||||
#endif
|
||||
#ifdef WEBRTC_LINUX
|
||||
#include <netinet/in.h>
|
||||
#endif
|
||||
#include <float.h>
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
/*********************/
|
||||
/* Misc. definitions */
|
||||
/*********************/
|
||||
|
||||
#define FIRSTLINELEN 40
|
||||
#define CHECK_ZERO(a) {int errCode = a; if((errCode)!=0){fprintf(stderr,"\n %s \n line: %d \n error at %s\n Error Code = %d\n",__FILE__,__LINE__,#a, WebRtcNetEQ_GetErrorCode(inst)); exit(0);}}
|
||||
#define CHECK_NOT_NULL(a) if((a)==NULL){fprintf(stderr,"\n %s \n line: %d \nerror at %s\n",__FILE__,__LINE__,#a );return(-1);}
|
||||
|
||||
struct arr_time {
|
||||
float time;
|
||||
uint32_t ix;
|
||||
};
|
||||
|
||||
int filelen(FILE *fid)
|
||||
{
|
||||
fpos_t cur_pos;
|
||||
int len;
|
||||
|
||||
if (!fid || fgetpos(fid, &cur_pos)) {
|
||||
return(-1);
|
||||
}
|
||||
|
||||
fseek(fid, 0, SEEK_END);
|
||||
len = ftell(fid);
|
||||
|
||||
fsetpos(fid, &cur_pos);
|
||||
|
||||
return (len);
|
||||
}
|
||||
|
||||
int compare_arr_time(const void *x, const void *y);
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
unsigned int dat_len, rtp_len, Npack, k;
|
||||
arr_time *time_vec;
|
||||
char firstline[FIRSTLINELEN];
|
||||
unsigned char *rtp_vec = NULL, **packet_ptr, *temp_packet;
|
||||
const unsigned int kRtpDumpHeaderSize = 4 + 4 + 4 + 2 + 2;
|
||||
uint16_t len;
|
||||
uint32_t *offset;
|
||||
|
||||
/* check number of parameters */
|
||||
if (argc != 4) {
|
||||
/* print help text and exit */
|
||||
printf("Apply jitter on RTP stream.\n");
|
||||
printf("The program reads an RTP stream and packet timing from two files.\n");
|
||||
printf("The RTP stream is modified to have the same jitter as described in the timing files.\n");
|
||||
printf("The format of the RTP stream file should be the same as for rtpplay,\n");
|
||||
printf("and can be obtained e.g., from Ethereal by using\n");
|
||||
printf("Statistics -> RTP -> Show All Streams -> [select a stream] -> Save As\n\n");
|
||||
printf("Usage:\n\n");
|
||||
printf("%s RTP_infile dat_file RTP_outfile\n", argv[0]);
|
||||
printf("where:\n");
|
||||
|
||||
printf("RTP_infile : RTP stream input file\n\n");
|
||||
|
||||
printf("dat_file : file with packet arrival times in ms\n\n");
|
||||
|
||||
printf("RTP_outfile : RTP stream output file\n\n");
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
FILE* in_file=fopen(argv[1],"rb");
|
||||
CHECK_NOT_NULL(in_file);
|
||||
printf("Input file: %s\n",argv[1]);
|
||||
FILE* dat_file=fopen(argv[2],"rb");
|
||||
CHECK_NOT_NULL(dat_file);
|
||||
printf("Dat-file: %s\n",argv[2]);
|
||||
FILE* out_file=fopen(argv[3],"wb");
|
||||
CHECK_NOT_NULL(out_file);
|
||||
printf("Output file: %s\n\n",argv[3]);
|
||||
|
||||
time_vec = (arr_time *) malloc(sizeof(arr_time)*(filelen(dat_file)/sizeof(float)) + 1000); // add 1000 bytes to avoid (rare) strange error
|
||||
if (time_vec==NULL) {
|
||||
fprintf(stderr, "Error: could not allocate memory for reading dat file\n");
|
||||
goto closing;
|
||||
}
|
||||
|
||||
dat_len=0;
|
||||
while(fread(&(time_vec[dat_len].time),sizeof(float),1,dat_file)>0) {
|
||||
time_vec[dat_len].ix=dat_len;
|
||||
dat_len++;
|
||||
}
|
||||
|
||||
qsort(time_vec,dat_len,sizeof(arr_time),compare_arr_time);
|
||||
|
||||
|
||||
rtp_vec = (unsigned char *) malloc(sizeof(unsigned char)*filelen(in_file));
|
||||
if (rtp_vec==NULL) {
|
||||
fprintf(stderr,"Error: could not allocate memory for reading rtp file\n");
|
||||
goto closing;
|
||||
}
|
||||
|
||||
// read file header and write directly to output file
|
||||
EXPECT_TRUE(fgets(firstline, FIRSTLINELEN, in_file) != NULL);
|
||||
EXPECT_GT(fputs(firstline, out_file), 0);
|
||||
EXPECT_EQ(kRtpDumpHeaderSize, fread(firstline, 1, kRtpDumpHeaderSize,
|
||||
in_file));
|
||||
EXPECT_EQ(kRtpDumpHeaderSize, fwrite(firstline, 1, kRtpDumpHeaderSize,
|
||||
out_file));
|
||||
|
||||
// read all RTP packets into vector
|
||||
rtp_len=0;
|
||||
Npack=0;
|
||||
len=(uint16_t) fread(&rtp_vec[rtp_len], sizeof(unsigned char), 2, in_file); // read length of first packet
|
||||
while(len==2) {
|
||||
len = ntohs(*((uint16_t *)(rtp_vec + rtp_len)));
|
||||
rtp_len += 2;
|
||||
if(fread(&rtp_vec[rtp_len], sizeof(unsigned char), len-2, in_file)!=(unsigned) (len-2)) {
|
||||
fprintf(stderr,"Error: currupt packet length\n");
|
||||
goto closing;
|
||||
}
|
||||
rtp_len += len-2;
|
||||
Npack++;
|
||||
len=(uint16_t) fread(&rtp_vec[rtp_len], sizeof(unsigned char), 2, in_file); // read length of next packet
|
||||
}
|
||||
|
||||
packet_ptr = (unsigned char **) malloc(Npack*sizeof(unsigned char*));
|
||||
|
||||
packet_ptr[0]=rtp_vec;
|
||||
k=1;
|
||||
while(k<Npack) {
|
||||
len = ntohs(*((uint16_t *) packet_ptr[k-1]));
|
||||
packet_ptr[k]=packet_ptr[k-1]+len;
|
||||
k++;
|
||||
}
|
||||
|
||||
for(k=0; k<dat_len && k<Npack; k++) {
|
||||
if(time_vec[k].time < FLT_MAX && time_vec[k].ix < Npack){
|
||||
temp_packet = packet_ptr[time_vec[k].ix];
|
||||
offset = (uint32_t *) (temp_packet+4);
|
||||
if ( time_vec[k].time >= 0 ) {
|
||||
*offset = htonl((uint32_t) time_vec[k].time);
|
||||
}
|
||||
else {
|
||||
*offset = htonl((uint32_t) 0);
|
||||
fprintf(stderr, "Warning: negative receive time in dat file transformed to 0.\n");
|
||||
}
|
||||
|
||||
// write packet to file
|
||||
if (fwrite(temp_packet, sizeof(unsigned char),
|
||||
ntohs(*((uint16_t*) temp_packet)),
|
||||
out_file) !=
|
||||
ntohs(*((uint16_t*) temp_packet))) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
closing:
|
||||
free(time_vec);
|
||||
free(rtp_vec);
|
||||
fclose(in_file);
|
||||
fclose(dat_file);
|
||||
fclose(out_file);
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
int compare_arr_time(const void *xp, const void *yp) {
|
||||
|
||||
if(((arr_time *)xp)->time == ((arr_time *)yp)->time)
|
||||
return(0);
|
||||
else if(((arr_time *)xp)->time > ((arr_time *)yp)->time)
|
||||
return(1);
|
||||
|
||||
return(-1);
|
||||
}
|
@ -1,89 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <algorithm>
|
||||
#include <stdio.h>
|
||||
#include <vector>
|
||||
|
||||
#include "NETEQTEST_RTPpacket.h"
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
/*********************/
|
||||
/* Misc. definitions */
|
||||
/*********************/
|
||||
|
||||
#define FIRSTLINELEN 40
|
||||
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
if (argc < 4 || argc > 6) {
|
||||
printf(
|
||||
"Usage: RTPtimeshift in.rtp out.rtp newStartTS "
|
||||
"[newStartSN [newStartArrTime]]\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
FILE *inFile = fopen(argv[1], "rb");
|
||||
if (!inFile) {
|
||||
printf("Cannot open input file %s\n", argv[1]);
|
||||
return (-1);
|
||||
}
|
||||
printf("Input RTP file: %s\n", argv[1]);
|
||||
|
||||
FILE *outFile = fopen(argv[2], "wb");
|
||||
if (!outFile) {
|
||||
printf("Cannot open output file %s\n", argv[2]);
|
||||
return (-1);
|
||||
}
|
||||
printf("Output RTP file: %s\n\n", argv[2]);
|
||||
|
||||
// read file header and write directly to output file
|
||||
const unsigned int kRtpDumpHeaderSize = 4 + 4 + 4 + 2 + 2;
|
||||
char firstline[FIRSTLINELEN];
|
||||
EXPECT_TRUE(fgets(firstline, FIRSTLINELEN, inFile) != NULL);
|
||||
EXPECT_GT(fputs(firstline, outFile), 0);
|
||||
EXPECT_EQ(kRtpDumpHeaderSize,
|
||||
fread(firstline, 1, kRtpDumpHeaderSize, inFile));
|
||||
EXPECT_EQ(kRtpDumpHeaderSize,
|
||||
fwrite(firstline, 1, kRtpDumpHeaderSize, outFile));
|
||||
NETEQTEST_RTPpacket packet;
|
||||
int packLen = packet.readFromFile(inFile);
|
||||
if (packLen < 0) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// get new start TS and start SeqNo from arguments
|
||||
uint32_t TSdiff = atoi(argv[3]) - packet.timeStamp();
|
||||
uint16_t SNdiff = 0;
|
||||
uint32_t ATdiff = 0;
|
||||
if (argc > 4) {
|
||||
SNdiff = atoi(argv[4]) - packet.sequenceNumber();
|
||||
if (argc > 5) {
|
||||
ATdiff = atoi(argv[5]) - packet.time();
|
||||
}
|
||||
}
|
||||
|
||||
while (packLen >= 0) {
|
||||
|
||||
packet.setTimeStamp(packet.timeStamp() + TSdiff);
|
||||
packet.setSequenceNumber(packet.sequenceNumber() + SNdiff);
|
||||
packet.setTime(packet.time() + ATdiff);
|
||||
|
||||
packet.writeToFile(outFile);
|
||||
|
||||
packLen = packet.readFromFile(inFile);
|
||||
|
||||
}
|
||||
|
||||
fclose(inFile);
|
||||
fclose(outFile);
|
||||
|
||||
return 0;
|
||||
}
|
@ -1,191 +0,0 @@
|
||||
function outStruct = parse_delay_file(file)
|
||||
|
||||
fid = fopen(file, 'rb');
|
||||
if fid == -1
|
||||
error('Cannot open file %s', file);
|
||||
end
|
||||
|
||||
textline = fgetl(fid);
|
||||
if ~strncmp(textline, '#!NetEQ_Delay_Logging', 21)
|
||||
error('Wrong file format');
|
||||
end
|
||||
|
||||
ver = sscanf(textline, '#!NetEQ_Delay_Logging%d.%d');
|
||||
if ~all(ver == [2; 0])
|
||||
error('Wrong version of delay logging function')
|
||||
end
|
||||
|
||||
|
||||
start_pos = ftell(fid);
|
||||
fseek(fid, -12, 'eof');
|
||||
textline = fgetl(fid);
|
||||
if ~strncmp(textline, 'End of file', 21)
|
||||
error('File ending is not correct. Seems like the simulation ended abnormally.');
|
||||
end
|
||||
|
||||
fseek(fid,-12-4, 'eof');
|
||||
Npackets = fread(fid, 1, 'int32');
|
||||
fseek(fid, start_pos, 'bof');
|
||||
|
||||
rtpts = zeros(Npackets, 1);
|
||||
seqno = zeros(Npackets, 1);
|
||||
pt = zeros(Npackets, 1);
|
||||
plen = zeros(Npackets, 1);
|
||||
recin_t = nan*ones(Npackets, 1);
|
||||
decode_t = nan*ones(Npackets, 1);
|
||||
playout_delay = zeros(Npackets, 1);
|
||||
optbuf = zeros(Npackets, 1);
|
||||
|
||||
fs_ix = 1;
|
||||
clock = 0;
|
||||
ts_ix = 1;
|
||||
ended = 0;
|
||||
late_packets = 0;
|
||||
fs_now = 8000;
|
||||
last_decode_k = 0;
|
||||
tot_expand = 0;
|
||||
tot_accelerate = 0;
|
||||
tot_preemptive = 0;
|
||||
|
||||
while not(ended)
|
||||
signal = fread(fid, 1, '*int32');
|
||||
|
||||
switch signal
|
||||
case 3 % NETEQ_DELAY_LOGGING_SIGNAL_CLOCK
|
||||
clock = fread(fid, 1, '*float32');
|
||||
|
||||
% keep on reading batches of M until the signal is no longer "3"
|
||||
% read int32 + float32 in one go
|
||||
% this is to save execution time
|
||||
temp = [3; 0];
|
||||
M = 120;
|
||||
while all(temp(1,:) == 3)
|
||||
fp = ftell(fid);
|
||||
temp = fread(fid, [2 M], '*int32');
|
||||
end
|
||||
|
||||
% back up to last clock event
|
||||
fseek(fid, fp - ftell(fid) + ...
|
||||
(find(temp(1,:) ~= 3, 1 ) - 2) * 2 * 4 + 4, 'cof');
|
||||
% read the last clock value
|
||||
clock = fread(fid, 1, '*float32');
|
||||
|
||||
case 1 % NETEQ_DELAY_LOGGING_SIGNAL_RECIN
|
||||
temp_ts = fread(fid, 1, 'uint32');
|
||||
|
||||
if late_packets > 0
|
||||
temp_ix = ts_ix - 1;
|
||||
while (temp_ix >= 1) && (rtpts(temp_ix) ~= temp_ts)
|
||||
% TODO(hlundin): use matlab vector search instead?
|
||||
temp_ix = temp_ix - 1;
|
||||
end
|
||||
|
||||
if temp_ix >= 1
|
||||
% the ts was found in the vector
|
||||
late_packets = late_packets - 1;
|
||||
else
|
||||
temp_ix = ts_ix;
|
||||
ts_ix = ts_ix + 1;
|
||||
end
|
||||
else
|
||||
temp_ix = ts_ix;
|
||||
ts_ix = ts_ix + 1;
|
||||
end
|
||||
|
||||
rtpts(temp_ix) = temp_ts;
|
||||
seqno(temp_ix) = fread(fid, 1, 'uint16');
|
||||
pt(temp_ix) = fread(fid, 1, 'int32');
|
||||
plen(temp_ix) = fread(fid, 1, 'int16');
|
||||
recin_t(temp_ix) = clock;
|
||||
|
||||
case 2 % NETEQ_DELAY_LOGGING_SIGNAL_FLUSH
|
||||
% do nothing
|
||||
|
||||
case 4 % NETEQ_DELAY_LOGGING_SIGNAL_EOF
|
||||
ended = 1;
|
||||
|
||||
case 5 % NETEQ_DELAY_LOGGING_SIGNAL_DECODE
|
||||
last_decode_ts = fread(fid, 1, 'uint32');
|
||||
temp_delay = fread(fid, 1, 'uint16');
|
||||
|
||||
k = find(rtpts(1:(ts_ix - 1))==last_decode_ts,1,'last');
|
||||
if ~isempty(k)
|
||||
decode_t(k) = clock;
|
||||
playout_delay(k) = temp_delay + ...
|
||||
5 * fs_now / 8000; % add overlap length
|
||||
last_decode_k = k;
|
||||
end
|
||||
|
||||
case 6 % NETEQ_DELAY_LOGGING_SIGNAL_CHANGE_FS
|
||||
fsvec(fs_ix) = fread(fid, 1, 'uint16');
|
||||
fschange_ts(fs_ix) = last_decode_ts;
|
||||
fs_now = fsvec(fs_ix);
|
||||
fs_ix = fs_ix + 1;
|
||||
|
||||
case 7 % NETEQ_DELAY_LOGGING_SIGNAL_MERGE_INFO
|
||||
playout_delay(last_decode_k) = playout_delay(last_decode_k) ...
|
||||
+ fread(fid, 1, 'int32');
|
||||
|
||||
case 8 % NETEQ_DELAY_LOGGING_SIGNAL_EXPAND_INFO
|
||||
temp = fread(fid, 1, 'int32');
|
||||
if last_decode_k ~= 0
|
||||
tot_expand = tot_expand + temp / (fs_now / 1000);
|
||||
end
|
||||
|
||||
case 9 % NETEQ_DELAY_LOGGING_SIGNAL_ACCELERATE_INFO
|
||||
temp = fread(fid, 1, 'int32');
|
||||
if last_decode_k ~= 0
|
||||
tot_accelerate = tot_accelerate + temp / (fs_now / 1000);
|
||||
end
|
||||
|
||||
case 10 % NETEQ_DELAY_LOGGING_SIGNAL_PREEMPTIVE_INFO
|
||||
temp = fread(fid, 1, 'int32');
|
||||
if last_decode_k ~= 0
|
||||
tot_preemptive = tot_preemptive + temp / (fs_now / 1000);
|
||||
end
|
||||
|
||||
case 11 % NETEQ_DELAY_LOGGING_SIGNAL_OPTBUF
|
||||
optbuf(last_decode_k) = fread(fid, 1, 'int32');
|
||||
|
||||
case 12 % NETEQ_DELAY_LOGGING_SIGNAL_DECODE_ONE_DESC
|
||||
last_decode_ts = fread(fid, 1, 'uint32');
|
||||
k = ts_ix - 1;
|
||||
|
||||
while (k >= 1) && (rtpts(k) ~= last_decode_ts)
|
||||
% TODO(hlundin): use matlab vector search instead?
|
||||
k = k - 1;
|
||||
end
|
||||
|
||||
if k < 1
|
||||
% packet not received yet
|
||||
k = ts_ix;
|
||||
rtpts(ts_ix) = last_decode_ts;
|
||||
late_packets = late_packets + 1;
|
||||
end
|
||||
|
||||
decode_t(k) = clock;
|
||||
playout_delay(k) = fread(fid, 1, 'uint16') + ...
|
||||
5 * fs_now / 8000; % add overlap length
|
||||
last_decode_k = k;
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
fclose(fid);
|
||||
|
||||
outStruct = struct(...
|
||||
'ts', rtpts, ...
|
||||
'sn', seqno, ...
|
||||
'pt', pt,...
|
||||
'plen', plen,...
|
||||
'arrival', recin_t,...
|
||||
'decode', decode_t,...
|
||||
'fs', fsvec(:),...
|
||||
'fschange_ts', fschange_ts(:),...
|
||||
'playout_delay', playout_delay,...
|
||||
'tot_expand', tot_expand,...
|
||||
'tot_accelerate', tot_accelerate,...
|
||||
'tot_preemptive', tot_preemptive,...
|
||||
'optbuf', optbuf);
|
@ -1,207 +0,0 @@
|
||||
function [delay_struct, delayvalues] = plot_neteq_delay(delayfile, varargin)
|
||||
|
||||
% InfoStruct = plot_neteq_delay(delayfile)
|
||||
% InfoStruct = plot_neteq_delay(delayfile, 'skipdelay', skip_seconds)
|
||||
%
|
||||
% Henrik Lundin, 2006-11-17
|
||||
% Henrik Lundin, 2011-05-17
|
||||
%
|
||||
|
||||
try
|
||||
s = parse_delay_file(delayfile);
|
||||
catch
|
||||
error(lasterr);
|
||||
end
|
||||
|
||||
delayskip=0;
|
||||
noplot=0;
|
||||
arg_ptr=1;
|
||||
delaypoints=[];
|
||||
|
||||
s.sn=unwrap_seqno(s.sn);
|
||||
|
||||
while arg_ptr+1 <= nargin
|
||||
switch lower(varargin{arg_ptr})
|
||||
case {'skipdelay', 'delayskip'}
|
||||
% skip a number of seconds in the beginning when calculating delays
|
||||
delayskip = varargin{arg_ptr+1};
|
||||
arg_ptr = arg_ptr + 2;
|
||||
case 'noplot'
|
||||
noplot=1;
|
||||
arg_ptr = arg_ptr + 1;
|
||||
case {'get_delay', 'getdelay'}
|
||||
% return a vector of delay values for the points in the given vector
|
||||
delaypoints = varargin{arg_ptr+1};
|
||||
arg_ptr = arg_ptr + 2;
|
||||
otherwise
|
||||
warning('Unknown switch %s\n', varargin{arg_ptr});
|
||||
arg_ptr = arg_ptr + 1;
|
||||
end
|
||||
end
|
||||
|
||||
% find lost frames that were covered by one-descriptor decoding
|
||||
one_desc_ix=find(isnan(s.arrival));
|
||||
for k=1:length(one_desc_ix)
|
||||
ix=find(s.ts==max(s.ts(s.ts(one_desc_ix(k))>s.ts)));
|
||||
s.sn(one_desc_ix(k))=s.sn(ix)+1;
|
||||
s.pt(one_desc_ix(k))=s.pt(ix);
|
||||
s.arrival(one_desc_ix(k))=s.arrival(ix)+s.decode(one_desc_ix(k))-s.decode(ix);
|
||||
end
|
||||
|
||||
% remove duplicate received frames that were never decoded (RED codec)
|
||||
if length(unique(s.ts(isfinite(s.ts)))) < length(s.ts(isfinite(s.ts)))
|
||||
ix=find(isfinite(s.decode));
|
||||
s.sn=s.sn(ix);
|
||||
s.ts=s.ts(ix);
|
||||
s.arrival=s.arrival(ix);
|
||||
s.playout_delay=s.playout_delay(ix);
|
||||
s.pt=s.pt(ix);
|
||||
s.optbuf=s.optbuf(ix);
|
||||
s.decode=s.decode(ix);
|
||||
end
|
||||
|
||||
% find non-unique sequence numbers
|
||||
[~,un_ix]=unique(s.sn);
|
||||
nonun_ix=setdiff(1:length(s.sn),un_ix);
|
||||
if ~isempty(nonun_ix)
|
||||
warning('RTP sequence numbers are in error');
|
||||
end
|
||||
|
||||
% sort vectors
|
||||
[s.sn,sort_ix]=sort(s.sn);
|
||||
s.ts=s.ts(sort_ix);
|
||||
s.arrival=s.arrival(sort_ix);
|
||||
s.decode=s.decode(sort_ix);
|
||||
s.playout_delay=s.playout_delay(sort_ix);
|
||||
s.pt=s.pt(sort_ix);
|
||||
|
||||
ts_unw = unwrap_ts(s.ts);
|
||||
unwrapped = any(ts_unw ~= s.ts);
|
||||
send_t = ts_unw - ts_unw(1);
|
||||
|
||||
if length(s.fs)<1
|
||||
warning('No info about sample rate found in file. Using default 8000.');
|
||||
s.fs(1)=8000;
|
||||
s.fschange_ts(1)=min(s.ts);
|
||||
elseif s.fschange_ts(1) ~= s.ts(1)
|
||||
if ~unwrapped
|
||||
s.fschange_ts(1) = s.ts(1);
|
||||
else
|
||||
error('TS wrapped, and sample rate change info is not found at the start of file => problem...')
|
||||
end
|
||||
end
|
||||
|
||||
end_ix=length(send_t);
|
||||
for k=length(s.fs):-1:1
|
||||
if (k < length(s.fs) && s.fschange_ts(k) > s.fschange_ts(k+1))
|
||||
% The sample rate changes are out of order, probably due to
|
||||
% packet re-ordering.
|
||||
warning('fschange_ts is out of order')
|
||||
continue % Skip to the next one.
|
||||
end
|
||||
start_ix=find(s.ts==s.fschange_ts(k));
|
||||
send_t(start_ix:end_ix)=send_t(start_ix:end_ix)/s.fs(k)*1000;
|
||||
s.playout_delay(start_ix:end_ix)=s.playout_delay(start_ix:end_ix)/s.fs(k)*1000;
|
||||
s.optbuf(start_ix:end_ix)=s.optbuf(start_ix:end_ix)/s.fs(k)*1000;
|
||||
end_ix=start_ix-1;
|
||||
end
|
||||
|
||||
tot_time=max(send_t)-min(send_t);
|
||||
|
||||
seq_ix=s.sn-min(s.sn)+1;
|
||||
send_t=send_t+max(min(s.arrival-send_t),0);
|
||||
|
||||
plot_send_t=nan*ones(max(seq_ix),1);
|
||||
plot_send_t(seq_ix)=send_t;
|
||||
plot_nw_delay=nan*ones(max(seq_ix),1);
|
||||
plot_nw_delay(seq_ix)=s.arrival-send_t;
|
||||
|
||||
cng_ix=find(s.pt~=13); % find those packets that are not CNG/SID
|
||||
|
||||
if noplot==0
|
||||
h=plot(plot_send_t/1000,plot_nw_delay);
|
||||
set(h,'color',0.75*[1 1 1]);
|
||||
hold on
|
||||
if any(s.optbuf~=0)
|
||||
peak_ix=find(s.optbuf(cng_ix)<0); % peak mode is labeled with negative values
|
||||
no_peak_ix=find(s.optbuf(cng_ix)>0); %setdiff(1:length(cng_ix),peak_ix);
|
||||
h1=plot(send_t(cng_ix(peak_ix))/1000,...
|
||||
s.arrival(cng_ix(peak_ix))+abs(s.optbuf(cng_ix(peak_ix)))-send_t(cng_ix(peak_ix)),...
|
||||
'r.');
|
||||
h2=plot(send_t(cng_ix(no_peak_ix))/1000,...
|
||||
s.arrival(cng_ix(no_peak_ix))+abs(s.optbuf(cng_ix(no_peak_ix)))-send_t(cng_ix(no_peak_ix)),...
|
||||
'g.');
|
||||
set([h1, h2],'markersize',1)
|
||||
end
|
||||
%h=plot(send_t(seq_ix)/1000,s.decode+s.playout_delay-send_t(seq_ix));
|
||||
h=plot(send_t(cng_ix)/1000,s.decode(cng_ix)+s.playout_delay(cng_ix)-send_t(cng_ix));
|
||||
set(h,'linew',1.5);
|
||||
hold off
|
||||
ax1=axis;
|
||||
axis tight
|
||||
ax2=axis;
|
||||
axis([ax2(1:3) ax1(4)])
|
||||
end
|
||||
|
||||
|
||||
% calculate delays and other parameters
|
||||
|
||||
delayskip_ix = find(send_t-send_t(1)>=delayskip*1000, 1 );
|
||||
|
||||
use_ix = intersect(cng_ix,... % use those that are not CNG/SID frames...
|
||||
intersect(find(isfinite(s.decode)),... % ... that did arrive ...
|
||||
(delayskip_ix:length(s.decode))')); % ... and are sent after delayskip seconds
|
||||
|
||||
mean_delay = mean(s.decode(use_ix)+s.playout_delay(use_ix)-send_t(use_ix));
|
||||
neteq_delay = mean(s.decode(use_ix)+s.playout_delay(use_ix)-s.arrival(use_ix));
|
||||
max_neteq_delay = max(s.decode(use_ix)+s.playout_delay(use_ix)-s.arrival(use_ix));
|
||||
|
||||
Npack=max(s.sn(delayskip_ix:end))-min(s.sn(delayskip_ix:end))+1;
|
||||
nw_lossrate=(Npack-length(s.sn(delayskip_ix:end)))/Npack;
|
||||
neteq_lossrate=(length(s.sn(delayskip_ix:end))-length(use_ix))/Npack;
|
||||
|
||||
delay_struct=struct('mean_delay',mean_delay,'neteq_delay',neteq_delay,...
|
||||
'max_neteq_delay', max_neteq_delay,...
|
||||
'nw_lossrate',nw_lossrate,'neteq_lossrate',neteq_lossrate,...
|
||||
'tot_expand',round(s.tot_expand),'tot_accelerate',round(s.tot_accelerate),...
|
||||
'tot_preemptive',round(s.tot_preemptive),'tot_time',tot_time,...
|
||||
'filename',delayfile,'units','ms','fs',unique(s.fs));
|
||||
|
||||
if not(isempty(delaypoints))
|
||||
delayvalues=interp1(send_t(cng_ix),...
|
||||
s.decode(cng_ix)+s.playout_delay(cng_ix)-send_t(cng_ix),...
|
||||
delaypoints,'nearest',NaN);
|
||||
else
|
||||
delayvalues=[];
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
% SUBFUNCTIONS %
|
||||
|
||||
function y=unwrap_seqno(x)
|
||||
|
||||
jumps=find(abs((diff(x)-1))>65000);
|
||||
|
||||
while ~isempty(jumps)
|
||||
n=jumps(1);
|
||||
if x(n+1)-x(n) < 0
|
||||
% negative jump
|
||||
x(n+1:end)=x(n+1:end)+65536;
|
||||
else
|
||||
% positive jump
|
||||
x(n+1:end)=x(n+1:end)-65536;
|
||||
end
|
||||
|
||||
jumps=find(abs((diff(x)-1))>65000);
|
||||
end
|
||||
|
||||
y=x;
|
||||
|
||||
end
|
||||
|
||||
function y = unwrap_ts(x)
|
||||
max_u32 = 4294967295; % 0xFFFFFFFF
|
||||
% Use the unwrap function made for unrwapping phase angle in radians.
|
||||
y = round(max_u32 / (2*pi) * unwrap(x * 2*pi / max_u32));
|
||||
end
|
@ -1,233 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2013 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.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include "gflags/gflags.h"
|
||||
#include "webrtc/modules/audio_coding/codecs/pcm16b/include/pcm16b.h"
|
||||
#include "webrtc/modules/audio_coding/neteq/interface/webrtc_neteq.h"
|
||||
#include "webrtc/modules/audio_coding/neteq/interface/webrtc_neteq_help_macros.h"
|
||||
#include "webrtc/modules/audio_coding/neteq/interface/webrtc_neteq_internal.h"
|
||||
#include "webrtc/modules/audio_coding/neteq4/tools/audio_loop.h"
|
||||
#include "webrtc/modules/audio_coding/neteq4/tools/rtp_generator.h"
|
||||
#include "webrtc/test/testsupport/fileutils.h"
|
||||
#include "webrtc/typedefs.h"
|
||||
|
||||
using webrtc::test::AudioLoop;
|
||||
using webrtc::test::RtpGenerator;
|
||||
using webrtc::WebRtcRTPHeader;
|
||||
|
||||
// Flag validators.
|
||||
static bool ValidateRuntime(const char* flagname, int value) {
|
||||
if (value > 0) // Value is ok.
|
||||
return true;
|
||||
printf("Invalid value for --%s: %d\n", flagname, static_cast<int>(value));
|
||||
return false;
|
||||
}
|
||||
static bool ValidateLossrate(const char* flagname, int value) {
|
||||
if (value >= 0) // Value is ok.
|
||||
return true;
|
||||
printf("Invalid value for --%s: %d\n", flagname, static_cast<int>(value));
|
||||
return false;
|
||||
}
|
||||
static bool ValidateDriftfactor(const char* flagname, double value) {
|
||||
if (value >= 0.0 && value < 1.0) // Value is ok.
|
||||
return true;
|
||||
printf("Invalid value for --%s: %f\n", flagname, value);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Define command line flags.
|
||||
DEFINE_int32(runtime_ms, 10000, "Simulated runtime in ms.");
|
||||
static const bool runtime_ms_dummy =
|
||||
google::RegisterFlagValidator(&FLAGS_runtime_ms, &ValidateRuntime);
|
||||
DEFINE_int32(lossrate, 10,
|
||||
"Packet lossrate; drop every N packets.");
|
||||
static const bool lossrate_dummy =
|
||||
google::RegisterFlagValidator(&FLAGS_lossrate, &ValidateLossrate);
|
||||
DEFINE_double(drift, 0.1,
|
||||
"Clockdrift factor.");
|
||||
static const bool drift_dummy =
|
||||
google::RegisterFlagValidator(&FLAGS_drift, &ValidateDriftfactor);
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
static const int kMaxChannels = 1;
|
||||
static const int kMaxSamplesPerMs = 48000 / 1000;
|
||||
static const int kOutputBlockSizeMs = 10;
|
||||
const std::string kInputFileName =
|
||||
webrtc::test::ResourcePath("audio_coding/testfile32kHz", "pcm");
|
||||
const int kSampRateHz = 32000;
|
||||
const WebRtcNetEQDecoder kDecoderType = kDecoderPCM16Bswb32kHz;
|
||||
const int kPayloadType = 95;
|
||||
|
||||
std::string program_name = argv[0];
|
||||
std::string usage = "Tool for measuring the speed of NetEq.\n"
|
||||
"Usage: " + program_name + " [options]\n\n"
|
||||
" --runtime_ms=N runtime in ms; default is 10000 ms\n"
|
||||
" --lossrate=N drop every N packets; default is 10\n"
|
||||
" --drift=F clockdrift factor between 0.0 and 1.0; "
|
||||
"default is 0.1\n";
|
||||
google::SetUsageMessage(usage);
|
||||
google::ParseCommandLineFlags(&argc, &argv, true);
|
||||
|
||||
if (argc != 1) {
|
||||
// Print usage information.
|
||||
std::cout << google::ProgramUsage();
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Initialize NetEq instance.
|
||||
int error;
|
||||
int inst_size_bytes;
|
||||
error = WebRtcNetEQ_AssignSize(&inst_size_bytes);
|
||||
if (error) {
|
||||
std::cerr << "Error returned from WebRtcNetEQ_AssignSize." << std::endl;
|
||||
exit(1);
|
||||
}
|
||||
char* inst_mem = new char[inst_size_bytes];
|
||||
void* neteq_inst;
|
||||
error = WebRtcNetEQ_Assign(&neteq_inst, inst_mem);
|
||||
if (error) {
|
||||
std::cerr << "Error returned from WebRtcNetEQ_Assign." << std::endl;
|
||||
exit(1);
|
||||
}
|
||||
// Select decoders.
|
||||
WebRtcNetEQDecoder decoder_list[] = {kDecoderType};
|
||||
int max_number_of_packets;
|
||||
int buffer_size_bytes;
|
||||
int overhead_bytes_dummy;
|
||||
error = WebRtcNetEQ_GetRecommendedBufferSize(
|
||||
neteq_inst, decoder_list, sizeof(decoder_list) / sizeof(decoder_list[1]),
|
||||
kTCPLargeJitter, &max_number_of_packets, &buffer_size_bytes,
|
||||
&overhead_bytes_dummy);
|
||||
if (error) {
|
||||
std::cerr << "Error returned from WebRtcNetEQ_GetRecommendedBufferSize."
|
||||
<< std::endl;
|
||||
exit(1);
|
||||
}
|
||||
char* buffer_mem = new char[buffer_size_bytes];
|
||||
error = WebRtcNetEQ_AssignBuffer(neteq_inst, max_number_of_packets,
|
||||
buffer_mem, buffer_size_bytes);
|
||||
if (error) {
|
||||
std::cerr << "Error returned from WebRtcNetEQ_AssignBuffer." << std::endl;
|
||||
exit(1);
|
||||
}
|
||||
error = WebRtcNetEQ_Init(neteq_inst, kSampRateHz);
|
||||
if (error) {
|
||||
std::cerr << "Error returned from WebRtcNetEQ_Init." << std::endl;
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// Register decoder.
|
||||
WebRtcNetEQ_CodecDef codec_definition;
|
||||
SET_CODEC_PAR(codec_definition, kDecoderType, kPayloadType, NULL,
|
||||
kSampRateHz);
|
||||
SET_PCM16B_SWB32_FUNCTIONS(codec_definition);
|
||||
error = WebRtcNetEQ_CodecDbAdd(neteq_inst, &codec_definition);
|
||||
if (error) {
|
||||
std::cerr << "Cannot register decoder." << std::endl;
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// Set up AudioLoop object.
|
||||
AudioLoop audio_loop;
|
||||
const size_t kMaxLoopLengthSamples = kSampRateHz * 10; // 10 second loop.
|
||||
const size_t kInputBlockSizeSamples = 60 * kSampRateHz / 1000; // 60 ms.
|
||||
if (!audio_loop.Init(kInputFileName, kMaxLoopLengthSamples,
|
||||
kInputBlockSizeSamples)) {
|
||||
std::cerr << "Cannot initialize AudioLoop object." << std::endl;
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int32_t time_now_ms = 0;
|
||||
|
||||
// Get first input packet.
|
||||
WebRtcRTPHeader rtp_header;
|
||||
RtpGenerator rtp_gen(kSampRateHz / 1000);
|
||||
// Start with positive drift first half of simulation.
|
||||
double drift_factor = 0.1;
|
||||
rtp_gen.set_drift_factor(drift_factor);
|
||||
bool drift_flipped = false;
|
||||
int32_t packet_input_time_ms =
|
||||
rtp_gen.GetRtpHeader(kPayloadType, kInputBlockSizeSamples, &rtp_header);
|
||||
const int16_t* input_samples = audio_loop.GetNextBlock();
|
||||
if (!input_samples) exit(1);
|
||||
uint8_t input_payload[kInputBlockSizeSamples * sizeof(int16_t)];
|
||||
int payload_len = WebRtcPcm16b_Encode(const_cast<int16_t*>(input_samples),
|
||||
kInputBlockSizeSamples,
|
||||
input_payload);
|
||||
assert(payload_len == kInputBlockSizeSamples * sizeof(int16_t));
|
||||
|
||||
// Main loop.
|
||||
while (time_now_ms < FLAGS_runtime_ms) {
|
||||
while (packet_input_time_ms <= time_now_ms) {
|
||||
// Drop every N packets, where N = FLAGS_lossrate.
|
||||
bool lost = false;
|
||||
if (FLAGS_lossrate > 0) {
|
||||
lost = ((rtp_header.header.sequenceNumber - 1) % FLAGS_lossrate) == 0;
|
||||
}
|
||||
if (!lost) {
|
||||
WebRtcNetEQ_RTPInfo rtp_info;
|
||||
rtp_info.payloadType = rtp_header.header.payloadType;
|
||||
rtp_info.sequenceNumber = rtp_header.header.sequenceNumber;
|
||||
rtp_info.timeStamp = rtp_header.header.timestamp;
|
||||
rtp_info.SSRC = rtp_header.header.ssrc;
|
||||
rtp_info.markerBit = rtp_header.header.markerBit;
|
||||
// Insert packet.
|
||||
error = WebRtcNetEQ_RecInRTPStruct(
|
||||
neteq_inst, &rtp_info, input_payload, payload_len,
|
||||
packet_input_time_ms * kSampRateHz / 1000);
|
||||
if (error != 0) {
|
||||
std::cerr << "WebRtcNetEQ_RecInRTPStruct returned error code " <<
|
||||
WebRtcNetEQ_GetErrorCode(neteq_inst) << std::endl;
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
// Get next packet.
|
||||
packet_input_time_ms = rtp_gen.GetRtpHeader(kPayloadType,
|
||||
kInputBlockSizeSamples,
|
||||
&rtp_header);
|
||||
input_samples = audio_loop.GetNextBlock();
|
||||
if (!input_samples) exit(1);
|
||||
payload_len = WebRtcPcm16b_Encode(const_cast<int16_t*>(input_samples),
|
||||
kInputBlockSizeSamples,
|
||||
input_payload);
|
||||
assert(payload_len == kInputBlockSizeSamples * sizeof(int16_t));
|
||||
}
|
||||
|
||||
// Get output audio, but don't do anything with it.
|
||||
static const int kOutDataLen = kOutputBlockSizeMs * kMaxSamplesPerMs *
|
||||
kMaxChannels;
|
||||
int16_t out_data[kOutDataLen];
|
||||
int16_t samples_per_channel;
|
||||
error = WebRtcNetEQ_RecOut(neteq_inst, out_data, &samples_per_channel);
|
||||
if (error != 0) {
|
||||
std::cerr << "WebRtcNetEQ_RecOut returned error code " <<
|
||||
WebRtcNetEQ_GetErrorCode(neteq_inst) << std::endl;
|
||||
exit(1);
|
||||
}
|
||||
assert(samples_per_channel == kSampRateHz * 10 / 1000);
|
||||
|
||||
time_now_ms += kOutputBlockSizeMs;
|
||||
if (time_now_ms >= FLAGS_runtime_ms / 2 && !drift_flipped) {
|
||||
// Apply negative drift second half of simulation.
|
||||
rtp_gen.set_drift_factor(-drift_factor);
|
||||
drift_flipped = true;
|
||||
}
|
||||
}
|
||||
|
||||
std::cout << "Simulation done" << std::endl;
|
||||
delete [] buffer_mem;
|
||||
delete [] inst_mem;
|
||||
return 0;
|
||||
}
|
@ -1,15 +0,0 @@
|
||||
pcmu 0
|
||||
pcma 8
|
||||
cn 13
|
||||
ilbc 102
|
||||
isac 103
|
||||
isacswb 104
|
||||
isacfb 124
|
||||
avt 106
|
||||
red 117
|
||||
cn_wb 98
|
||||
cn_swb32 99
|
||||
pcm16b 93
|
||||
pcm16b_wb 94
|
||||
pcm16b_swb32khz 95
|
||||
g722 9
|
@ -1,124 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Parses an rtpdump file and outputs a text table parsable by parseLog.m.
|
||||
* The output file will have .txt appended to the specified base name.
|
||||
* $ rtp_to_text [-d] <input_rtp_file> <output_base_name>
|
||||
*
|
||||
* -d RTP headers only
|
||||
*
|
||||
*/
|
||||
|
||||
#include "data_log.h"
|
||||
#include "NETEQTEST_DummyRTPpacket.h"
|
||||
#include "NETEQTEST_RTPpacket.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
/*********************/
|
||||
/* Misc. definitions */
|
||||
/*********************/
|
||||
|
||||
#define FIRSTLINELEN 40
|
||||
|
||||
using ::webrtc::DataLog;
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
int arg_count = 1;
|
||||
NETEQTEST_RTPpacket* packet;
|
||||
|
||||
if (argc < 3)
|
||||
{
|
||||
printf("Usage: %s [-d] <input_rtp_file> <output_base_name>\n", argv[0]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Parse dummy option
|
||||
if (argc >= 3 && strcmp(argv[arg_count], "-d") == 0)
|
||||
{
|
||||
packet = new NETEQTEST_DummyRTPpacket;
|
||||
++arg_count;
|
||||
}
|
||||
else
|
||||
{
|
||||
packet = new NETEQTEST_RTPpacket;
|
||||
}
|
||||
|
||||
std::string input_filename = argv[arg_count++];
|
||||
std::string table_name = argv[arg_count];
|
||||
|
||||
std::cout << "Input file: " << input_filename << std::endl;
|
||||
std::cout << "Output file: " << table_name << ".txt" << std::endl;
|
||||
|
||||
FILE *inFile=fopen(input_filename.c_str(),"rb");
|
||||
if (!inFile)
|
||||
{
|
||||
std::cout << "Cannot open input file " << input_filename << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Set up the DataLog and define the table
|
||||
DataLog::CreateLog();
|
||||
if (DataLog::AddTable(table_name) < 0)
|
||||
{
|
||||
std::cout << "Error adding table " << table_name << ".txt" << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
DataLog::AddColumn(table_name, "seq", 1);
|
||||
DataLog::AddColumn(table_name, "ssrc", 1);
|
||||
DataLog::AddColumn(table_name, "payload type", 1);
|
||||
DataLog::AddColumn(table_name, "length", 1);
|
||||
DataLog::AddColumn(table_name, "timestamp", 1);
|
||||
DataLog::AddColumn(table_name, "marker bit", 1);
|
||||
DataLog::AddColumn(table_name, "arrival", 1);
|
||||
|
||||
// read file header
|
||||
char firstline[FIRSTLINELEN];
|
||||
if (fgets(firstline, FIRSTLINELEN, inFile) == NULL)
|
||||
{
|
||||
std::cout << "Error reading file " << input_filename << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// start_sec + start_usec + source + port + padding
|
||||
if (fread(firstline, 4+4+4+2+2, 1, inFile) != 1)
|
||||
{
|
||||
std::cout << "Error reading file " << input_filename << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
while (packet->readFromFile(inFile) >= 0)
|
||||
{
|
||||
// write packet headers to
|
||||
DataLog::InsertCell(table_name, "seq", packet->sequenceNumber());
|
||||
DataLog::InsertCell(table_name, "ssrc", packet->SSRC());
|
||||
DataLog::InsertCell(table_name, "payload type", packet->payloadType());
|
||||
DataLog::InsertCell(table_name, "length", packet->dataLen());
|
||||
DataLog::InsertCell(table_name, "timestamp", packet->timeStamp());
|
||||
DataLog::InsertCell(table_name, "marker bit", packet->markerBit());
|
||||
DataLog::InsertCell(table_name, "arrival", packet->time());
|
||||
DataLog::NextRow(table_name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
DataLog::ReturnLog();
|
||||
|
||||
fclose(inFile);
|
||||
|
||||
return 0;
|
||||
}
|
@ -1,41 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This function "unmutes" a vector on a sample by sample basis.
|
||||
*/
|
||||
|
||||
#include "dsp_helpfunctions.h"
|
||||
|
||||
#include "signal_processing_library.h"
|
||||
|
||||
|
||||
void WebRtcNetEQ_UnmuteSignal(int16_t *pw16_inVec, int16_t *startMuteFact,
|
||||
int16_t *pw16_outVec, int16_t unmuteFact,
|
||||
int16_t N)
|
||||
{
|
||||
int i;
|
||||
uint16_t w16_tmp;
|
||||
int32_t w32_tmp;
|
||||
|
||||
w16_tmp = (uint16_t) *startMuteFact;
|
||||
w32_tmp = WEBRTC_SPL_LSHIFT_W32((int32_t)w16_tmp,6) + 32;
|
||||
for (i = 0; i < N; i++)
|
||||
{
|
||||
pw16_outVec[i]
|
||||
= (int16_t) ((WEBRTC_SPL_MUL_16_16(w16_tmp, pw16_inVec[i]) + 8192) >> 14);
|
||||
w32_tmp += unmuteFact;
|
||||
w32_tmp = WEBRTC_SPL_MAX(0, w32_tmp);
|
||||
w16_tmp = (uint16_t) WEBRTC_SPL_RSHIFT_W32(w32_tmp, 6); /* 20 - 14 = 6 */
|
||||
w16_tmp = WEBRTC_SPL_MIN(16384, w16_tmp);
|
||||
}
|
||||
*startMuteFact = (int16_t) w16_tmp;
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,779 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file includes unit tests for NetEQ.
|
||||
*/
|
||||
|
||||
#include "webrtc/modules/audio_coding/neteq/interface/webrtc_neteq.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h> // memset
|
||||
|
||||
#include <algorithm>
|
||||
#include <set>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
#include "webrtc/modules/audio_coding/neteq/interface/webrtc_neteq_help_macros.h"
|
||||
#include "webrtc/modules/audio_coding/neteq/interface/webrtc_neteq_internal.h"
|
||||
#include "webrtc/modules/audio_coding/neteq/test/NETEQTEST_CodecClass.h"
|
||||
#include "webrtc/modules/audio_coding/neteq/test/NETEQTEST_NetEQClass.h"
|
||||
#include "webrtc/modules/audio_coding/neteq/test/NETEQTEST_RTPpacket.h"
|
||||
#include "webrtc/modules/audio_coding/neteq4/tools/input_audio_file.h"
|
||||
#include "webrtc/test/testsupport/fileutils.h"
|
||||
#include "webrtc/typedefs.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
class RefFiles {
|
||||
public:
|
||||
RefFiles(const std::string& input_file, const std::string& output_file);
|
||||
~RefFiles();
|
||||
template<class T> void ProcessReference(const T& test_results);
|
||||
template<typename T, size_t n> void ProcessReference(
|
||||
const T (&test_results)[n],
|
||||
size_t length);
|
||||
template<typename T, size_t n> void WriteToFile(
|
||||
const T (&test_results)[n],
|
||||
size_t length);
|
||||
template<typename T, size_t n> void ReadFromFileAndCompare(
|
||||
const T (&test_results)[n],
|
||||
size_t length);
|
||||
void WriteToFile(const WebRtcNetEQ_NetworkStatistics& stats);
|
||||
void ReadFromFileAndCompare(const WebRtcNetEQ_NetworkStatistics& stats);
|
||||
void WriteToFile(const WebRtcNetEQ_RTCPStat& stats);
|
||||
void ReadFromFileAndCompare(const WebRtcNetEQ_RTCPStat& stats);
|
||||
|
||||
FILE* input_fp_;
|
||||
FILE* output_fp_;
|
||||
};
|
||||
|
||||
RefFiles::RefFiles(const std::string &input_file,
|
||||
const std::string &output_file)
|
||||
: input_fp_(NULL),
|
||||
output_fp_(NULL) {
|
||||
if (!input_file.empty()) {
|
||||
input_fp_ = fopen(input_file.c_str(), "rb");
|
||||
EXPECT_TRUE(input_fp_ != NULL);
|
||||
}
|
||||
if (!output_file.empty()) {
|
||||
output_fp_ = fopen(output_file.c_str(), "wb");
|
||||
EXPECT_TRUE(output_fp_ != NULL);
|
||||
}
|
||||
}
|
||||
|
||||
RefFiles::~RefFiles() {
|
||||
if (input_fp_) {
|
||||
EXPECT_EQ(EOF, fgetc(input_fp_)); // Make sure that we reached the end.
|
||||
fclose(input_fp_);
|
||||
}
|
||||
if (output_fp_) fclose(output_fp_);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void RefFiles::ProcessReference(const T& test_results) {
|
||||
WriteToFile(test_results);
|
||||
ReadFromFileAndCompare(test_results);
|
||||
}
|
||||
|
||||
template<typename T, size_t n>
|
||||
void RefFiles::ProcessReference(const T (&test_results)[n], size_t length) {
|
||||
WriteToFile(test_results, length);
|
||||
ReadFromFileAndCompare(test_results, length);
|
||||
}
|
||||
|
||||
template<typename T, size_t n>
|
||||
void RefFiles::WriteToFile(const T (&test_results)[n], size_t length) {
|
||||
if (output_fp_) {
|
||||
ASSERT_EQ(length, fwrite(&test_results, sizeof(T), length, output_fp_));
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T, size_t n>
|
||||
void RefFiles::ReadFromFileAndCompare(const T (&test_results)[n],
|
||||
size_t length) {
|
||||
if (input_fp_) {
|
||||
// Read from ref file.
|
||||
T* ref = new T[length];
|
||||
ASSERT_EQ(length, fread(ref, sizeof(T), length, input_fp_));
|
||||
// Compare
|
||||
ASSERT_EQ(0, memcmp(&test_results, ref, sizeof(T) * length));
|
||||
delete [] ref;
|
||||
}
|
||||
}
|
||||
|
||||
void RefFiles::WriteToFile(const WebRtcNetEQ_NetworkStatistics& stats) {
|
||||
if (output_fp_) {
|
||||
ASSERT_EQ(1u, fwrite(&stats, sizeof(WebRtcNetEQ_NetworkStatistics), 1,
|
||||
output_fp_));
|
||||
}
|
||||
}
|
||||
|
||||
void RefFiles::ReadFromFileAndCompare(
|
||||
const WebRtcNetEQ_NetworkStatistics& stats) {
|
||||
if (input_fp_) {
|
||||
// Read from ref file.
|
||||
size_t stat_size = sizeof(WebRtcNetEQ_NetworkStatistics);
|
||||
WebRtcNetEQ_NetworkStatistics ref_stats;
|
||||
ASSERT_EQ(1u, fread(&ref_stats, stat_size, 1, input_fp_));
|
||||
// Compare
|
||||
EXPECT_EQ(0, memcmp(&stats, &ref_stats, stat_size));
|
||||
}
|
||||
}
|
||||
|
||||
void RefFiles::WriteToFile(const WebRtcNetEQ_RTCPStat& stats) {
|
||||
if (output_fp_) {
|
||||
ASSERT_EQ(1u, fwrite(&(stats.fraction_lost), sizeof(stats.fraction_lost), 1,
|
||||
output_fp_));
|
||||
ASSERT_EQ(1u, fwrite(&(stats.cum_lost), sizeof(stats.cum_lost), 1,
|
||||
output_fp_));
|
||||
ASSERT_EQ(1u, fwrite(&(stats.ext_max), sizeof(stats.ext_max), 1,
|
||||
output_fp_));
|
||||
ASSERT_EQ(1u, fwrite(&(stats.jitter), sizeof(stats.jitter), 1,
|
||||
output_fp_));
|
||||
}
|
||||
}
|
||||
|
||||
void RefFiles::ReadFromFileAndCompare(
|
||||
const WebRtcNetEQ_RTCPStat& stats) {
|
||||
if (input_fp_) {
|
||||
// Read from ref file.
|
||||
WebRtcNetEQ_RTCPStat ref_stats;
|
||||
ASSERT_EQ(1u, fread(&(ref_stats.fraction_lost),
|
||||
sizeof(ref_stats.fraction_lost), 1, input_fp_));
|
||||
ASSERT_EQ(1u, fread(&(ref_stats.cum_lost), sizeof(ref_stats.cum_lost), 1,
|
||||
input_fp_));
|
||||
ASSERT_EQ(1u, fread(&(ref_stats.ext_max), sizeof(ref_stats.ext_max), 1,
|
||||
input_fp_));
|
||||
ASSERT_EQ(1u, fread(&(ref_stats.jitter), sizeof(ref_stats.jitter), 1,
|
||||
input_fp_));
|
||||
// Compare
|
||||
EXPECT_EQ(ref_stats.fraction_lost, stats.fraction_lost);
|
||||
EXPECT_EQ(ref_stats.cum_lost, stats.cum_lost);
|
||||
EXPECT_EQ(ref_stats.ext_max, stats.ext_max);
|
||||
EXPECT_EQ(ref_stats.jitter, stats.jitter);
|
||||
}
|
||||
}
|
||||
|
||||
class NetEqDecodingTest : public ::testing::Test {
|
||||
protected:
|
||||
// NetEQ must be polled for data once every 10 ms. Thus, neither of the
|
||||
// constants below can be changed.
|
||||
static const int kTimeStepMs = 10;
|
||||
static const int kBlockSize8kHz = kTimeStepMs * 8;
|
||||
static const int kBlockSize16kHz = kTimeStepMs * 16;
|
||||
static const int kBlockSize32kHz = kTimeStepMs * 32;
|
||||
static const int kMaxBlockSize = kBlockSize32kHz;
|
||||
|
||||
NetEqDecodingTest();
|
||||
virtual void SetUp();
|
||||
virtual void TearDown();
|
||||
void SelectDecoders(WebRtcNetEQDecoder* used_codec);
|
||||
void LoadDecoders();
|
||||
void OpenInputFile(const std::string &rtp_file);
|
||||
void Process(NETEQTEST_RTPpacket* rtp_ptr, int16_t* out_len);
|
||||
void DecodeAndCompare(const std::string &rtp_file,
|
||||
const std::string &ref_file);
|
||||
void DecodeAndCheckStats(const std::string &rtp_file,
|
||||
const std::string &stat_ref_file,
|
||||
const std::string &rtcp_ref_file);
|
||||
static void PopulateRtpInfo(int frame_index,
|
||||
int timestamp,
|
||||
WebRtcNetEQ_RTPInfo* rtp_info);
|
||||
static void PopulateCng(int frame_index,
|
||||
int timestamp,
|
||||
WebRtcNetEQ_RTPInfo* rtp_info,
|
||||
uint8_t* payload,
|
||||
int* payload_len);
|
||||
void WrapTest(uint16_t start_seq_no, uint32_t start_timestamp,
|
||||
const std::set<uint16_t>& drop_seq_numbers);
|
||||
|
||||
NETEQTEST_NetEQClass* neteq_inst_;
|
||||
std::vector<NETEQTEST_Decoder*> dec_;
|
||||
FILE* rtp_fp_;
|
||||
unsigned int sim_clock_;
|
||||
int16_t out_data_[kMaxBlockSize];
|
||||
};
|
||||
|
||||
NetEqDecodingTest::NetEqDecodingTest()
|
||||
: neteq_inst_(NULL),
|
||||
rtp_fp_(NULL),
|
||||
sim_clock_(0) {
|
||||
memset(out_data_, 0, sizeof(out_data_));
|
||||
}
|
||||
|
||||
void NetEqDecodingTest::SetUp() {
|
||||
WebRtcNetEQDecoder usedCodec[kDecoderReservedEnd - 1];
|
||||
|
||||
SelectDecoders(usedCodec);
|
||||
neteq_inst_ = new NETEQTEST_NetEQClass(usedCodec, dec_.size(), 8000,
|
||||
kTCPLargeJitter);
|
||||
ASSERT_TRUE(neteq_inst_);
|
||||
LoadDecoders();
|
||||
}
|
||||
|
||||
void NetEqDecodingTest::TearDown() {
|
||||
if (neteq_inst_)
|
||||
delete neteq_inst_;
|
||||
for (size_t i = 0; i < dec_.size(); ++i) {
|
||||
if (dec_[i])
|
||||
delete dec_[i];
|
||||
}
|
||||
if (rtp_fp_)
|
||||
fclose(rtp_fp_);
|
||||
}
|
||||
|
||||
void NetEqDecodingTest::SelectDecoders(WebRtcNetEQDecoder* used_codec) {
|
||||
*used_codec++ = kDecoderPCMu;
|
||||
dec_.push_back(new decoder_PCMU(0));
|
||||
*used_codec++ = kDecoderPCMa;
|
||||
dec_.push_back(new decoder_PCMA(8));
|
||||
*used_codec++ = kDecoderILBC;
|
||||
dec_.push_back(new decoder_ILBC(102));
|
||||
*used_codec++ = kDecoderISAC;
|
||||
dec_.push_back(new decoder_iSAC(103));
|
||||
*used_codec++ = kDecoderISACswb;
|
||||
dec_.push_back(new decoder_iSACSWB(104));
|
||||
*used_codec++ = kDecoderISACfb;
|
||||
dec_.push_back(new decoder_iSACFB(105));
|
||||
*used_codec++ = kDecoderPCM16B;
|
||||
dec_.push_back(new decoder_PCM16B_NB(93));
|
||||
*used_codec++ = kDecoderPCM16Bwb;
|
||||
dec_.push_back(new decoder_PCM16B_WB(94));
|
||||
*used_codec++ = kDecoderPCM16Bswb32kHz;
|
||||
dec_.push_back(new decoder_PCM16B_SWB32(95));
|
||||
*used_codec++ = kDecoderCNG;
|
||||
dec_.push_back(new decoder_CNG(13, 8000));
|
||||
*used_codec++ = kDecoderCNG;
|
||||
dec_.push_back(new decoder_CNG(98, 16000));
|
||||
}
|
||||
|
||||
void NetEqDecodingTest::LoadDecoders() {
|
||||
for (size_t i = 0; i < dec_.size(); ++i) {
|
||||
ASSERT_EQ(0, dec_[i]->loadToNetEQ(*neteq_inst_));
|
||||
}
|
||||
}
|
||||
|
||||
void NetEqDecodingTest::OpenInputFile(const std::string &rtp_file) {
|
||||
rtp_fp_ = fopen(rtp_file.c_str(), "rb");
|
||||
ASSERT_TRUE(rtp_fp_ != NULL);
|
||||
ASSERT_EQ(0, NETEQTEST_RTPpacket::skipFileHeader(rtp_fp_));
|
||||
}
|
||||
|
||||
void NetEqDecodingTest::Process(NETEQTEST_RTPpacket* rtp, int16_t* out_len) {
|
||||
// Check if time to receive.
|
||||
while ((sim_clock_ >= rtp->time()) &&
|
||||
(rtp->dataLen() >= 0)) {
|
||||
if (rtp->dataLen() > 0) {
|
||||
ASSERT_EQ(0, neteq_inst_->recIn(*rtp));
|
||||
}
|
||||
// Get next packet.
|
||||
ASSERT_NE(-1, rtp->readFromFile(rtp_fp_));
|
||||
}
|
||||
|
||||
// RecOut
|
||||
*out_len = neteq_inst_->recOut(out_data_);
|
||||
ASSERT_TRUE((*out_len == kBlockSize8kHz) ||
|
||||
(*out_len == kBlockSize16kHz) ||
|
||||
(*out_len == kBlockSize32kHz));
|
||||
|
||||
// Increase time.
|
||||
sim_clock_ += kTimeStepMs;
|
||||
}
|
||||
|
||||
void NetEqDecodingTest::DecodeAndCompare(const std::string &rtp_file,
|
||||
const std::string &ref_file) {
|
||||
OpenInputFile(rtp_file);
|
||||
|
||||
std::string ref_out_file = "";
|
||||
if (ref_file.empty()) {
|
||||
ref_out_file = webrtc::test::OutputPath() + "neteq_out.pcm";
|
||||
}
|
||||
RefFiles ref_files(ref_file, ref_out_file);
|
||||
|
||||
NETEQTEST_RTPpacket rtp;
|
||||
ASSERT_GT(rtp.readFromFile(rtp_fp_), 0);
|
||||
int i = 0;
|
||||
while (rtp.dataLen() >= 0) {
|
||||
std::ostringstream ss;
|
||||
ss << "Lap number " << i++ << " in DecodeAndCompare while loop";
|
||||
SCOPED_TRACE(ss.str()); // Print out the parameter values on failure.
|
||||
int16_t out_len;
|
||||
ASSERT_NO_FATAL_FAILURE(Process(&rtp, &out_len));
|
||||
ASSERT_NO_FATAL_FAILURE(ref_files.ProcessReference(out_data_, out_len));
|
||||
}
|
||||
}
|
||||
|
||||
void NetEqDecodingTest::DecodeAndCheckStats(const std::string &rtp_file,
|
||||
const std::string &stat_ref_file,
|
||||
const std::string &rtcp_ref_file) {
|
||||
OpenInputFile(rtp_file);
|
||||
std::string stat_out_file = "";
|
||||
if (stat_ref_file.empty()) {
|
||||
stat_out_file = webrtc::test::OutputPath() +
|
||||
"neteq_network_stats.dat";
|
||||
}
|
||||
RefFiles network_stat_files(stat_ref_file, stat_out_file);
|
||||
|
||||
std::string rtcp_out_file = "";
|
||||
if (rtcp_ref_file.empty()) {
|
||||
rtcp_out_file = webrtc::test::OutputPath() +
|
||||
"neteq_rtcp_stats.dat";
|
||||
}
|
||||
RefFiles rtcp_stat_files(rtcp_ref_file, rtcp_out_file);
|
||||
|
||||
NETEQTEST_RTPpacket rtp;
|
||||
ASSERT_GT(rtp.readFromFile(rtp_fp_), 0);
|
||||
while (rtp.dataLen() >= 0) {
|
||||
int16_t out_len;
|
||||
Process(&rtp, &out_len);
|
||||
|
||||
// Query the network statistics API once per second
|
||||
if (sim_clock_ % 1000 == 0) {
|
||||
// Process NetworkStatistics.
|
||||
WebRtcNetEQ_NetworkStatistics network_stats;
|
||||
ASSERT_EQ(0, WebRtcNetEQ_GetNetworkStatistics(neteq_inst_->instance(),
|
||||
&network_stats));
|
||||
network_stat_files.ProcessReference(network_stats);
|
||||
|
||||
// Process RTCPstat.
|
||||
WebRtcNetEQ_RTCPStat rtcp_stats;
|
||||
ASSERT_EQ(0, WebRtcNetEQ_GetRTCPStats(neteq_inst_->instance(),
|
||||
&rtcp_stats));
|
||||
rtcp_stat_files.ProcessReference(rtcp_stats);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void NetEqDecodingTest::PopulateRtpInfo(int frame_index,
|
||||
int timestamp,
|
||||
WebRtcNetEQ_RTPInfo* rtp_info) {
|
||||
rtp_info->sequenceNumber = frame_index;
|
||||
rtp_info->timeStamp = timestamp;
|
||||
rtp_info->SSRC = 0x1234; // Just an arbitrary SSRC.
|
||||
rtp_info->payloadType = 94; // PCM16b WB codec.
|
||||
rtp_info->markerBit = 0;
|
||||
}
|
||||
|
||||
void NetEqDecodingTest::PopulateCng(int frame_index,
|
||||
int timestamp,
|
||||
WebRtcNetEQ_RTPInfo* rtp_info,
|
||||
uint8_t* payload,
|
||||
int* payload_len) {
|
||||
rtp_info->sequenceNumber = frame_index;
|
||||
rtp_info->timeStamp = timestamp;
|
||||
rtp_info->SSRC = 0x1234; // Just an arbitrary SSRC.
|
||||
rtp_info->payloadType = 98; // WB CNG.
|
||||
rtp_info->markerBit = 0;
|
||||
payload[0] = 64; // Noise level -64 dBov, quite arbitrarily chosen.
|
||||
*payload_len = 1; // Only noise level, no spectral parameters.
|
||||
}
|
||||
|
||||
#if (defined(_WIN32) && defined(WEBRTC_ARCH_64_BITS)) || defined(WEBRTC_ANDROID)
|
||||
// Disabled for Windows 64-bit until webrtc:1460 is fixed.
|
||||
#define MAYBE_TestBitExactness DISABLED_TestBitExactness
|
||||
#else
|
||||
#define MAYBE_TestBitExactness TestBitExactness
|
||||
#endif
|
||||
|
||||
TEST_F(NetEqDecodingTest, MAYBE_TestBitExactness) {
|
||||
const std::string kInputRtpFile = webrtc::test::ProjectRootPath() +
|
||||
"resources/audio_coding/neteq_universal.rtp";
|
||||
#if defined(_MSC_VER) && (_MSC_VER >= 1700)
|
||||
// For Visual Studio 2012 and later, we will have to use the generic reference
|
||||
// file, rather than the windows-specific one.
|
||||
const std::string kInputRefFile = webrtc::test::ProjectRootPath() +
|
||||
"resources/audio_coding/neteq_universal_ref.pcm";
|
||||
#else
|
||||
const std::string kInputRefFile =
|
||||
webrtc::test::ResourcePath("audio_coding/neteq_universal_ref", "pcm");
|
||||
#endif
|
||||
DecodeAndCompare(kInputRtpFile, kInputRefFile);
|
||||
}
|
||||
|
||||
TEST_F(NetEqDecodingTest, TestNetworkStatistics) {
|
||||
const std::string kInputRtpFile = webrtc::test::ProjectRootPath() +
|
||||
"resources/audio_coding/neteq_universal.rtp";
|
||||
#if defined(_MSC_VER) && (_MSC_VER >= 1700)
|
||||
// For Visual Studio 2012 and later, we will have to use the generic reference
|
||||
// file, rather than the windows-specific one.
|
||||
const std::string kNetworkStatRefFile = webrtc::test::ProjectRootPath() +
|
||||
"resources/audio_coding/neteq_network_stats.dat";
|
||||
#else
|
||||
const std::string kNetworkStatRefFile =
|
||||
webrtc::test::ResourcePath("audio_coding/neteq_network_stats", "dat");
|
||||
#endif
|
||||
const std::string kRtcpStatRefFile =
|
||||
webrtc::test::ResourcePath("audio_coding/neteq_rtcp_stats", "dat");
|
||||
DecodeAndCheckStats(kInputRtpFile, kNetworkStatRefFile, kRtcpStatRefFile);
|
||||
}
|
||||
|
||||
TEST_F(NetEqDecodingTest, TestFrameWaitingTimeStatistics) {
|
||||
// Use fax mode to avoid time-scaling. This is to simplify the testing of
|
||||
// packet waiting times in the packet buffer.
|
||||
ASSERT_EQ(0,
|
||||
WebRtcNetEQ_SetPlayoutMode(neteq_inst_->instance(), kPlayoutFax));
|
||||
// Insert 30 dummy packets at once. Each packet contains 10 ms 16 kHz audio.
|
||||
int num_frames = 30;
|
||||
const int kSamples = 10 * 16;
|
||||
const int kPayloadBytes = kSamples * 2;
|
||||
for (int i = 0; i < num_frames; ++i) {
|
||||
uint16_t payload[kSamples] = {0};
|
||||
WebRtcNetEQ_RTPInfo rtp_info;
|
||||
rtp_info.sequenceNumber = i;
|
||||
rtp_info.timeStamp = i * kSamples;
|
||||
rtp_info.SSRC = 0x1234; // Just an arbitrary SSRC.
|
||||
rtp_info.payloadType = 94; // PCM16b WB codec.
|
||||
rtp_info.markerBit = 0;
|
||||
ASSERT_EQ(0, WebRtcNetEQ_RecInRTPStruct(neteq_inst_->instance(), &rtp_info,
|
||||
reinterpret_cast<uint8_t*>(payload),
|
||||
kPayloadBytes, 0));
|
||||
}
|
||||
// Pull out all data.
|
||||
for (int i = 0; i < num_frames; ++i) {
|
||||
ASSERT_TRUE(kBlockSize16kHz == neteq_inst_->recOut(out_data_));
|
||||
}
|
||||
const int kVecLen = 110; // More than kLenWaitingTimes in mcu.h.
|
||||
int waiting_times[kVecLen];
|
||||
int len = WebRtcNetEQ_GetRawFrameWaitingTimes(neteq_inst_->instance(),
|
||||
kVecLen, waiting_times);
|
||||
EXPECT_EQ(num_frames, len);
|
||||
// Since all frames are dumped into NetEQ at once, but pulled out with 10 ms
|
||||
// spacing (per definition), we expect the delay to increase with 10 ms for
|
||||
// each packet.
|
||||
for (int i = 0; i < len; ++i) {
|
||||
EXPECT_EQ((i + 1) * 10, waiting_times[i]);
|
||||
}
|
||||
|
||||
// Check statistics again and make sure it's been reset.
|
||||
EXPECT_EQ(0, WebRtcNetEQ_GetRawFrameWaitingTimes(neteq_inst_->instance(),
|
||||
kVecLen, waiting_times));
|
||||
|
||||
// Process > 100 frames, and make sure that that we get statistics
|
||||
// only for 100 frames. Note the new SSRC, causing NetEQ to reset.
|
||||
num_frames = 110;
|
||||
for (int i = 0; i < num_frames; ++i) {
|
||||
uint16_t payload[kSamples] = {0};
|
||||
WebRtcNetEQ_RTPInfo rtp_info;
|
||||
rtp_info.sequenceNumber = i;
|
||||
rtp_info.timeStamp = i * kSamples;
|
||||
rtp_info.SSRC = 0x1235; // Just an arbitrary SSRC.
|
||||
rtp_info.payloadType = 94; // PCM16b WB codec.
|
||||
rtp_info.markerBit = 0;
|
||||
ASSERT_EQ(0, WebRtcNetEQ_RecInRTPStruct(neteq_inst_->instance(), &rtp_info,
|
||||
reinterpret_cast<uint8_t*>(payload),
|
||||
kPayloadBytes, 0));
|
||||
ASSERT_TRUE(kBlockSize16kHz == neteq_inst_->recOut(out_data_));
|
||||
}
|
||||
|
||||
len = WebRtcNetEQ_GetRawFrameWaitingTimes(neteq_inst_->instance(),
|
||||
kVecLen, waiting_times);
|
||||
EXPECT_EQ(100, len);
|
||||
}
|
||||
|
||||
TEST_F(NetEqDecodingTest, TestAverageInterArrivalTimeNegative) {
|
||||
const int kNumFrames = 3000; // Needed for convergence.
|
||||
int frame_index = 0;
|
||||
const int kSamples = 10 * 16;
|
||||
const int kPayloadBytes = kSamples * 2;
|
||||
while (frame_index < kNumFrames) {
|
||||
// Insert one packet each time, except every 10th time where we insert two
|
||||
// packets at once. This will create a negative clock-drift of approx. 10%.
|
||||
int num_packets = (frame_index % 10 == 0 ? 2 : 1);
|
||||
for (int n = 0; n < num_packets; ++n) {
|
||||
uint8_t payload[kPayloadBytes] = {0};
|
||||
WebRtcNetEQ_RTPInfo rtp_info;
|
||||
PopulateRtpInfo(frame_index, frame_index * kSamples, &rtp_info);
|
||||
ASSERT_EQ(0,
|
||||
WebRtcNetEQ_RecInRTPStruct(neteq_inst_->instance(),
|
||||
&rtp_info,
|
||||
payload,
|
||||
kPayloadBytes, 0));
|
||||
++frame_index;
|
||||
}
|
||||
|
||||
// Pull out data once.
|
||||
ASSERT_TRUE(kBlockSize16kHz == neteq_inst_->recOut(out_data_));
|
||||
}
|
||||
|
||||
WebRtcNetEQ_NetworkStatistics network_stats;
|
||||
ASSERT_EQ(0, WebRtcNetEQ_GetNetworkStatistics(neteq_inst_->instance(),
|
||||
&network_stats));
|
||||
EXPECT_EQ(-103196, network_stats.clockDriftPPM);
|
||||
}
|
||||
|
||||
TEST_F(NetEqDecodingTest, TestAverageInterArrivalTimePositive) {
|
||||
const int kNumFrames = 5000; // Needed for convergence.
|
||||
int frame_index = 0;
|
||||
const int kSamples = 10 * 16;
|
||||
const int kPayloadBytes = kSamples * 2;
|
||||
for (int i = 0; i < kNumFrames; ++i) {
|
||||
// Insert one packet each time, except every 10th time where we don't insert
|
||||
// any packet. This will create a positive clock-drift of approx. 11%.
|
||||
int num_packets = (i % 10 == 9 ? 0 : 1);
|
||||
for (int n = 0; n < num_packets; ++n) {
|
||||
uint8_t payload[kPayloadBytes] = {0};
|
||||
WebRtcNetEQ_RTPInfo rtp_info;
|
||||
PopulateRtpInfo(frame_index, frame_index * kSamples, &rtp_info);
|
||||
ASSERT_EQ(0,
|
||||
WebRtcNetEQ_RecInRTPStruct(neteq_inst_->instance(),
|
||||
&rtp_info,
|
||||
payload,
|
||||
kPayloadBytes, 0));
|
||||
++frame_index;
|
||||
}
|
||||
|
||||
// Pull out data once.
|
||||
ASSERT_TRUE(kBlockSize16kHz == neteq_inst_->recOut(out_data_));
|
||||
}
|
||||
|
||||
WebRtcNetEQ_NetworkStatistics network_stats;
|
||||
ASSERT_EQ(0, WebRtcNetEQ_GetNetworkStatistics(neteq_inst_->instance(),
|
||||
&network_stats));
|
||||
EXPECT_EQ(110946, network_stats.clockDriftPPM);
|
||||
}
|
||||
|
||||
TEST_F(NetEqDecodingTest, LongCngWithClockDrift) {
|
||||
uint16_t seq_no = 0;
|
||||
uint32_t timestamp = 0;
|
||||
const int kFrameSizeMs = 30;
|
||||
const int kSamples = kFrameSizeMs * 16;
|
||||
const int kPayloadBytes = kSamples * 2;
|
||||
// Apply a clock drift of -25 ms / s (sender faster than receiver).
|
||||
const double kDriftFactor = 1000.0 / (1000.0 + 25.0);
|
||||
double next_input_time_ms = 0.0;
|
||||
double t_ms;
|
||||
|
||||
// Insert speech for 5 seconds.
|
||||
const int kSpeechDurationMs = 5000;
|
||||
for (t_ms = 0; t_ms < kSpeechDurationMs; t_ms += 10) {
|
||||
// Each turn in this for loop is 10 ms.
|
||||
while (next_input_time_ms <= t_ms) {
|
||||
// Insert one 30 ms speech frame.
|
||||
uint8_t payload[kPayloadBytes] = {0};
|
||||
WebRtcNetEQ_RTPInfo rtp_info;
|
||||
PopulateRtpInfo(seq_no, timestamp, &rtp_info);
|
||||
ASSERT_EQ(0,
|
||||
WebRtcNetEQ_RecInRTPStruct(neteq_inst_->instance(),
|
||||
&rtp_info,
|
||||
payload,
|
||||
kPayloadBytes, 0));
|
||||
++seq_no;
|
||||
timestamp += kSamples;
|
||||
next_input_time_ms += static_cast<double>(kFrameSizeMs) * kDriftFactor;
|
||||
}
|
||||
// Pull out data once.
|
||||
ASSERT_TRUE(kBlockSize16kHz == neteq_inst_->recOut(out_data_));
|
||||
}
|
||||
|
||||
EXPECT_EQ(kOutputNormal, neteq_inst_->getOutputType());
|
||||
int32_t delay_before = timestamp - neteq_inst_->getSpeechTimeStamp();
|
||||
|
||||
// Insert CNG for 1 minute (= 60000 ms).
|
||||
const int kCngPeriodMs = 100;
|
||||
const int kCngPeriodSamples = kCngPeriodMs * 16; // Period in 16 kHz samples.
|
||||
const int kCngDurationMs = 60000;
|
||||
for (; t_ms < kSpeechDurationMs + kCngDurationMs; t_ms += 10) {
|
||||
// Each turn in this for loop is 10 ms.
|
||||
while (next_input_time_ms <= t_ms) {
|
||||
// Insert one CNG frame each 100 ms.
|
||||
uint8_t payload[kPayloadBytes];
|
||||
int payload_len;
|
||||
WebRtcNetEQ_RTPInfo rtp_info;
|
||||
PopulateCng(seq_no, timestamp, &rtp_info, payload, &payload_len);
|
||||
ASSERT_EQ(0,
|
||||
WebRtcNetEQ_RecInRTPStruct(neteq_inst_->instance(),
|
||||
&rtp_info,
|
||||
payload,
|
||||
payload_len, 0));
|
||||
++seq_no;
|
||||
timestamp += kCngPeriodSamples;
|
||||
next_input_time_ms += static_cast<double>(kCngPeriodMs) * kDriftFactor;
|
||||
}
|
||||
// Pull out data once.
|
||||
ASSERT_TRUE(kBlockSize16kHz == neteq_inst_->recOut(out_data_));
|
||||
}
|
||||
|
||||
EXPECT_EQ(kOutputCNG, neteq_inst_->getOutputType());
|
||||
|
||||
// Insert speech again until output type is speech.
|
||||
while (neteq_inst_->getOutputType() != kOutputNormal) {
|
||||
// Each turn in this for loop is 10 ms.
|
||||
while (next_input_time_ms <= t_ms) {
|
||||
// Insert one 30 ms speech frame.
|
||||
uint8_t payload[kPayloadBytes] = {0};
|
||||
WebRtcNetEQ_RTPInfo rtp_info;
|
||||
PopulateRtpInfo(seq_no, timestamp, &rtp_info);
|
||||
ASSERT_EQ(0,
|
||||
WebRtcNetEQ_RecInRTPStruct(neteq_inst_->instance(),
|
||||
&rtp_info,
|
||||
payload,
|
||||
kPayloadBytes, 0));
|
||||
++seq_no;
|
||||
timestamp += kSamples;
|
||||
next_input_time_ms += static_cast<double>(kFrameSizeMs) * kDriftFactor;
|
||||
}
|
||||
// Pull out data once.
|
||||
ASSERT_TRUE(kBlockSize16kHz == neteq_inst_->recOut(out_data_));
|
||||
// Increase clock.
|
||||
t_ms += 10;
|
||||
}
|
||||
|
||||
int32_t delay_after = timestamp - neteq_inst_->getSpeechTimeStamp();
|
||||
// Compare delay before and after, and make sure it differs less than 20 ms.
|
||||
EXPECT_LE(delay_after, delay_before + 20 * 16);
|
||||
EXPECT_GE(delay_after, delay_before - 20 * 16);
|
||||
}
|
||||
|
||||
TEST_F(NetEqDecodingTest, NoInputDataStereo) {
|
||||
void *ms_info;
|
||||
ms_info = malloc(WebRtcNetEQ_GetMasterSlaveInfoSize());
|
||||
neteq_inst_->setMaster();
|
||||
|
||||
// Slave instance without decoders (because it is easier).
|
||||
WebRtcNetEQDecoder usedCodec[kDecoderReservedEnd - 1];
|
||||
usedCodec[0] = kDecoderPCMu;
|
||||
NETEQTEST_NetEQClass* slave_inst =
|
||||
new NETEQTEST_NetEQClass(usedCodec, 1, 8000, kTCPLargeJitter);
|
||||
ASSERT_TRUE(slave_inst);
|
||||
NETEQTEST_Decoder* dec = new decoder_PCMU(0);
|
||||
ASSERT_TRUE(dec != NULL);
|
||||
dec->loadToNetEQ(*slave_inst);
|
||||
slave_inst->setSlave();
|
||||
|
||||
// Pull out data.
|
||||
const int kNumFrames = 100;
|
||||
for (int i = 0; i < kNumFrames; ++i) {
|
||||
ASSERT_TRUE(kBlockSize8kHz == neteq_inst_->recOut(out_data_, ms_info));
|
||||
ASSERT_TRUE(kBlockSize8kHz == slave_inst->recOut(out_data_, ms_info));
|
||||
}
|
||||
|
||||
delete dec;
|
||||
delete slave_inst;
|
||||
free(ms_info);
|
||||
}
|
||||
|
||||
TEST_F(NetEqDecodingTest, TestExtraDelay) {
|
||||
static const int kNumFrames = 120000; // Needed for convergence.
|
||||
int frame_index = 0;
|
||||
static const int kFrameSizeSamples = 30 * 16;
|
||||
static const int kPayloadBytes = kFrameSizeSamples * 2;
|
||||
test::InputAudioFile input_file(
|
||||
webrtc::test::ResourcePath("audio_coding/testfile32kHz", "pcm"));
|
||||
int16_t input[kFrameSizeSamples];
|
||||
// Buffers of NetEq cannot accommodate larger delays for PCM16.
|
||||
static const int kExtraDelayMs = 3200;
|
||||
ASSERT_EQ(0, WebRtcNetEQ_SetExtraDelay(neteq_inst_->instance(),
|
||||
kExtraDelayMs));
|
||||
for (int i = 0; i < kNumFrames; ++i) {
|
||||
ASSERT_TRUE(input_file.Read(kFrameSizeSamples, input));
|
||||
WebRtcNetEQ_RTPInfo rtp_info;
|
||||
PopulateRtpInfo(frame_index, frame_index * kFrameSizeSamples, &rtp_info);
|
||||
uint8_t* payload = reinterpret_cast<uint8_t*>(input);
|
||||
ASSERT_EQ(0,
|
||||
WebRtcNetEQ_RecInRTPStruct(neteq_inst_->instance(),
|
||||
&rtp_info,
|
||||
payload,
|
||||
kPayloadBytes, 0));
|
||||
++frame_index;
|
||||
// Pull out data.
|
||||
for (int j = 0; j < 3; ++j) {
|
||||
ASSERT_TRUE(kBlockSize16kHz == neteq_inst_->recOut(out_data_));
|
||||
}
|
||||
if (i % 100 == 0) {
|
||||
WebRtcNetEQ_NetworkStatistics network_stats;
|
||||
ASSERT_EQ(0, WebRtcNetEQ_GetNetworkStatistics(neteq_inst_->instance(),
|
||||
&network_stats));
|
||||
const int expected_lower_limit =
|
||||
std::min(i * 0.083 - 210, 0.9 * network_stats.preferredBufferSize);
|
||||
EXPECT_GE(network_stats.currentBufferSize, expected_lower_limit);
|
||||
const int expected_upper_limit =
|
||||
std::min(i * 0.083 + 255, 1.2 * network_stats.preferredBufferSize);
|
||||
EXPECT_LE(network_stats.currentBufferSize, expected_upper_limit);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void NetEqDecodingTest::WrapTest(uint16_t start_seq_no,
|
||||
uint32_t start_timestamp,
|
||||
const std::set<uint16_t>& drop_seq_numbers) {
|
||||
uint16_t seq_no = start_seq_no;
|
||||
uint32_t timestamp = start_timestamp;
|
||||
const int kFrameSizeMs = 30;
|
||||
const int kSamples = kFrameSizeMs * 16;
|
||||
const int kPayloadBytes = kSamples * 2;
|
||||
double next_input_time_ms = 0.0;
|
||||
|
||||
// Insert speech for 1 second.
|
||||
const int kSpeechDurationMs = 1000;
|
||||
for (double t_ms = 0; t_ms < kSpeechDurationMs; t_ms += 10) {
|
||||
// Each turn in this for loop is 10 ms.
|
||||
while (next_input_time_ms <= t_ms) {
|
||||
// Insert one 30 ms speech frame.
|
||||
uint8_t payload[kPayloadBytes] = {0};
|
||||
WebRtcNetEQ_RTPInfo rtp_info;
|
||||
PopulateRtpInfo(seq_no, timestamp, &rtp_info);
|
||||
if (drop_seq_numbers.find(seq_no) == drop_seq_numbers.end()) {
|
||||
// This sequence number was not in the set to drop. Insert it.
|
||||
ASSERT_EQ(0,
|
||||
WebRtcNetEQ_RecInRTPStruct(neteq_inst_->instance(),
|
||||
&rtp_info,
|
||||
payload,
|
||||
kPayloadBytes, 0));
|
||||
}
|
||||
++seq_no;
|
||||
timestamp += kSamples;
|
||||
next_input_time_ms += static_cast<double>(kFrameSizeMs);
|
||||
WebRtcNetEQ_NetworkStatistics network_stats;
|
||||
ASSERT_EQ(0, WebRtcNetEQ_GetNetworkStatistics(neteq_inst_->instance(),
|
||||
&network_stats));
|
||||
// Expect preferred and actual buffer size to be no more than 2 frames.
|
||||
EXPECT_LE(network_stats.preferredBufferSize, kFrameSizeMs * 2);
|
||||
EXPECT_LE(network_stats.currentBufferSize, kFrameSizeMs * 2);
|
||||
}
|
||||
// Pull out data once.
|
||||
ASSERT_TRUE(kBlockSize16kHz == neteq_inst_->recOut(out_data_));
|
||||
// Expect delay (in samples) to be less than 2 packets.
|
||||
EXPECT_LE(timestamp - neteq_inst_->getSpeechTimeStamp(),
|
||||
static_cast<uint32_t>(kSamples * 2));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(NetEqDecodingTest, SequenceNumberWrap) {
|
||||
// Start with a sequence number that will soon wrap.
|
||||
std::set<uint16_t> drop_seq_numbers; // Don't drop any packets.
|
||||
WrapTest(0xFFFF - 5, 0, drop_seq_numbers);
|
||||
}
|
||||
|
||||
TEST_F(NetEqDecodingTest, SequenceNumberWrapAndDrop) {
|
||||
// Start with a sequence number that will soon wrap.
|
||||
std::set<uint16_t> drop_seq_numbers;
|
||||
drop_seq_numbers.insert(0xFFFF);
|
||||
drop_seq_numbers.insert(0x0);
|
||||
WrapTest(0xFFFF - 5, 0, drop_seq_numbers);
|
||||
}
|
||||
|
||||
TEST_F(NetEqDecodingTest, TimestampWrap) {
|
||||
// Start with a timestamp that will soon wrap.
|
||||
std::set<uint16_t> drop_seq_numbers;
|
||||
WrapTest(0, 0xFFFFFFFF - 1000, drop_seq_numbers);
|
||||
}
|
||||
|
||||
TEST_F(NetEqDecodingTest, TimestampAndSequenceNumberWrap) {
|
||||
// Start with a timestamp and a sequence number that will wrap at the same
|
||||
// time.
|
||||
std::set<uint16_t> drop_seq_numbers;
|
||||
WrapTest(0xFFFF - 2, 0xFFFFFFFF - 1000, drop_seq_numbers);
|
||||
}
|
||||
|
||||
} // namespace
|
Loading…
x
Reference in New Issue
Block a user