/* * 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. */ // Performs echo control (suppression) with fft routines in fixed-point. #ifndef WEBRTC_MODULES_AUDIO_PROCESSING_AECM_AECM_CORE_H_ #define WEBRTC_MODULES_AUDIO_PROCESSING_AECM_AECM_CORE_H_ #include "webrtc/common_audio/ring_buffer.h" #include "webrtc/common_audio/signal_processing/include/signal_processing_library.h" #include "webrtc/modules/audio_processing/aecm/aecm_defines.h" #include "webrtc/typedefs.h" #ifdef _MSC_VER // visual c++ #define ALIGN8_BEG __declspec(align(8)) #define ALIGN8_END #else // gcc or icc #define ALIGN8_BEG #define ALIGN8_END __attribute__((aligned(8))) #endif typedef struct { int16_t real; int16_t imag; } ComplexInt16; typedef struct { int farBufWritePos; int farBufReadPos; int knownDelay; int lastKnownDelay; int firstVAD; // Parameter to control poorly initialized channels RingBuffer* farFrameBuf; RingBuffer* nearNoisyFrameBuf; RingBuffer* nearCleanFrameBuf; RingBuffer* outFrameBuf; int16_t farBuf[FAR_BUF_LEN]; int16_t mult; uint32_t seed; // Delay estimation variables void* delay_estimator_farend; void* delay_estimator; uint16_t currentDelay; // Far end history variables // TODO(bjornv): Replace |far_history| with ring_buffer. uint16_t far_history[PART_LEN1 * MAX_DELAY]; int far_history_pos; int far_q_domains[MAX_DELAY]; int16_t nlpFlag; int16_t fixedDelay; uint32_t totCount; int16_t dfaCleanQDomain; int16_t dfaCleanQDomainOld; int16_t dfaNoisyQDomain; int16_t dfaNoisyQDomainOld; int16_t nearLogEnergy[MAX_BUF_LEN]; int16_t farLogEnergy; int16_t echoAdaptLogEnergy[MAX_BUF_LEN]; int16_t echoStoredLogEnergy[MAX_BUF_LEN]; // The extra 16 or 32 bytes in the following buffers are for alignment based // Neon code. // It's designed this way since the current GCC compiler can't align a // buffer in 16 or 32 byte boundaries properly. int16_t channelStored_buf[PART_LEN1 + 8]; int16_t channelAdapt16_buf[PART_LEN1 + 8]; int32_t channelAdapt32_buf[PART_LEN1 + 8]; int16_t xBuf_buf[PART_LEN2 + 16]; // farend int16_t dBufClean_buf[PART_LEN2 + 16]; // nearend int16_t dBufNoisy_buf[PART_LEN2 + 16]; // nearend int16_t outBuf_buf[PART_LEN + 8]; // Pointers to the above buffers int16_t *channelStored; int16_t *channelAdapt16; int32_t *channelAdapt32; int16_t *xBuf; int16_t *dBufClean; int16_t *dBufNoisy; int16_t *outBuf; int32_t echoFilt[PART_LEN1]; int16_t nearFilt[PART_LEN1]; int32_t noiseEst[PART_LEN1]; int noiseEstTooLowCtr[PART_LEN1]; int noiseEstTooHighCtr[PART_LEN1]; int16_t noiseEstCtr; int16_t cngMode; int32_t mseAdaptOld; int32_t mseStoredOld; int32_t mseThreshold; int16_t farEnergyMin; int16_t farEnergyMax; int16_t farEnergyMaxMin; int16_t farEnergyVAD; int16_t farEnergyMSE; int currentVADValue; int16_t vadUpdateCount; int16_t startupState; int16_t mseChannelCount; int16_t supGain; int16_t supGainOld; int16_t supGainErrParamA; int16_t supGainErrParamD; int16_t supGainErrParamDiffAB; int16_t supGainErrParamDiffBD; struct RealFFT* real_fft; #ifdef AEC_DEBUG FILE *farFile; FILE *nearFile; FILE *outFile; #endif } AecmCore; //////////////////////////////////////////////////////////////////////////////// // WebRtcAecm_CreateCore() // // Allocates the memory needed by the AECM. The memory needs to be // initialized separately using the WebRtcAecm_InitCore() function. // Returns a pointer to the instance and a nullptr at failure. AecmCore* WebRtcAecm_CreateCore(); //////////////////////////////////////////////////////////////////////////////// // WebRtcAecm_InitCore(...) // // This function initializes the AECM instant created with // WebRtcAecm_CreateCore() // Input: // - aecm : Pointer to the AECM instance // - samplingFreq : Sampling Frequency // // Output: // - aecm : Initialized instance // // Return value : 0 - Ok // -1 - Error // int WebRtcAecm_InitCore(AecmCore* const aecm, int samplingFreq); //////////////////////////////////////////////////////////////////////////////// // WebRtcAecm_FreeCore(...) // // This function releases the memory allocated by WebRtcAecm_CreateCore() // Input: // - aecm : Pointer to the AECM instance // void WebRtcAecm_FreeCore(AecmCore* aecm); int WebRtcAecm_Control(AecmCore* aecm, int delay, int nlpFlag); //////////////////////////////////////////////////////////////////////////////// // WebRtcAecm_InitEchoPathCore(...) // // This function resets the echo channel adaptation with the specified channel. // Input: // - aecm : Pointer to the AECM instance // - echo_path : Pointer to the data that should initialize the echo // path // // Output: // - aecm : Initialized instance // void WebRtcAecm_InitEchoPathCore(AecmCore* aecm, const int16_t* echo_path); //////////////////////////////////////////////////////////////////////////////// // WebRtcAecm_ProcessFrame(...) // // This function processes frames and sends blocks to // WebRtcAecm_ProcessBlock(...) // // Inputs: // - aecm : Pointer to the AECM instance // - farend : In buffer containing one frame of echo signal // - nearendNoisy : In buffer containing one frame of nearend+echo signal // without NS // - nearendClean : In buffer containing one frame of nearend+echo signal // with NS // // Output: // - out : Out buffer, one frame of nearend signal : // // int WebRtcAecm_ProcessFrame(AecmCore* aecm, const int16_t* farend, const int16_t* nearendNoisy, const int16_t* nearendClean, int16_t* out); //////////////////////////////////////////////////////////////////////////////// // WebRtcAecm_ProcessBlock(...) // // This function is called for every block within one frame // This function is called by WebRtcAecm_ProcessFrame(...) // // Inputs: // - aecm : Pointer to the AECM instance // - farend : In buffer containing one block of echo signal // - nearendNoisy : In buffer containing one frame of nearend+echo signal // without NS // - nearendClean : In buffer containing one frame of nearend+echo signal // with NS // // Output: // - out : Out buffer, one block of nearend signal : // // int WebRtcAecm_ProcessBlock(AecmCore* aecm, const int16_t* farend, const int16_t* nearendNoisy, const int16_t* noisyClean, int16_t* out); //////////////////////////////////////////////////////////////////////////////// // WebRtcAecm_BufferFarFrame() // // Inserts a frame of data into farend buffer. // // Inputs: // - aecm : Pointer to the AECM instance // - farend : In buffer containing one frame of farend signal // - farLen : Length of frame // void WebRtcAecm_BufferFarFrame(AecmCore* const aecm, const int16_t* const farend, const int farLen); //////////////////////////////////////////////////////////////////////////////// // WebRtcAecm_FetchFarFrame() // // Read the farend buffer to account for known delay // // Inputs: // - aecm : Pointer to the AECM instance // - farend : In buffer containing one frame of farend signal // - farLen : Length of frame // - knownDelay : known delay // void WebRtcAecm_FetchFarFrame(AecmCore* const aecm, int16_t* const farend, const int farLen, const int knownDelay); // All the functions below are intended to be private //////////////////////////////////////////////////////////////////////////////// // WebRtcAecm_UpdateFarHistory() // // Moves the pointer to the next entry and inserts |far_spectrum| and // corresponding Q-domain in its buffer. // // Inputs: // - self : Pointer to the delay estimation instance // - far_spectrum : Pointer to the far end spectrum // - far_q : Q-domain of far end spectrum // void WebRtcAecm_UpdateFarHistory(AecmCore* self, uint16_t* far_spectrum, int far_q); //////////////////////////////////////////////////////////////////////////////// // WebRtcAecm_AlignedFarend() // // Returns a pointer to the far end spectrum aligned to current near end // spectrum. The function WebRtc_DelayEstimatorProcessFix(...) should have been // called before AlignedFarend(...). Otherwise, you get the pointer to the // previous frame. The memory is only valid until the next call of // WebRtc_DelayEstimatorProcessFix(...). // // Inputs: // - self : Pointer to the AECM instance. // - delay : Current delay estimate. // // Output: // - far_q : The Q-domain of the aligned far end spectrum // // Return value: // - far_spectrum : Pointer to the aligned far end spectrum // NULL - Error // const uint16_t* WebRtcAecm_AlignedFarend(AecmCore* self, int* far_q, int delay); /////////////////////////////////////////////////////////////////////////////// // WebRtcAecm_CalcSuppressionGain() // // This function calculates the suppression gain that is used in the // Wiener filter. // // Inputs: // - aecm : Pointer to the AECM instance. // // Return value: // - supGain : Suppression gain with which to scale the noise // level (Q14). // int16_t WebRtcAecm_CalcSuppressionGain(AecmCore* const aecm); /////////////////////////////////////////////////////////////////////////////// // WebRtcAecm_CalcEnergies() // // This function calculates the log of energies for nearend, farend and // estimated echoes. There is also an update of energy decision levels, // i.e. internal VAD. // // Inputs: // - aecm : Pointer to the AECM instance. // - far_spectrum : Pointer to farend spectrum. // - far_q : Q-domain of farend spectrum. // - nearEner : Near end energy for current block in // Q(aecm->dfaQDomain). // // Output: // - echoEst : Estimated echo in Q(xfa_q+RESOLUTION_CHANNEL16). // void WebRtcAecm_CalcEnergies(AecmCore* aecm, const uint16_t* far_spectrum, const int16_t far_q, const uint32_t nearEner, int32_t* echoEst); /////////////////////////////////////////////////////////////////////////////// // WebRtcAecm_CalcStepSize() // // This function calculates the step size used in channel estimation // // Inputs: // - aecm : Pointer to the AECM instance. // // Return value: // - mu : Stepsize in log2(), i.e. number of shifts. // int16_t WebRtcAecm_CalcStepSize(AecmCore* const aecm); /////////////////////////////////////////////////////////////////////////////// // WebRtcAecm_UpdateChannel(...) // // This function performs channel estimation. // NLMS and decision on channel storage. // // Inputs: // - aecm : Pointer to the AECM instance. // - far_spectrum : Absolute value of the farend signal in Q(far_q) // - far_q : Q-domain of the farend signal // - dfa : Absolute value of the nearend signal // (Q[aecm->dfaQDomain]) // - mu : NLMS step size. // Input/Output: // - echoEst : Estimated echo in Q(far_q+RESOLUTION_CHANNEL16). // void WebRtcAecm_UpdateChannel(AecmCore* aecm, const uint16_t* far_spectrum, const int16_t far_q, const uint16_t* const dfa, const int16_t mu, int32_t* echoEst); extern const int16_t WebRtcAecm_kCosTable[]; extern const int16_t WebRtcAecm_kSinTable[]; /////////////////////////////////////////////////////////////////////////////// // Some function pointers, for internal functions shared by ARM NEON and // generic C code. // typedef void (*CalcLinearEnergies)(AecmCore* aecm, const uint16_t* far_spectrum, int32_t* echoEst, uint32_t* far_energy, uint32_t* echo_energy_adapt, uint32_t* echo_energy_stored); extern CalcLinearEnergies WebRtcAecm_CalcLinearEnergies; typedef void (*StoreAdaptiveChannel)(AecmCore* aecm, const uint16_t* far_spectrum, int32_t* echo_est); extern StoreAdaptiveChannel WebRtcAecm_StoreAdaptiveChannel; typedef void (*ResetAdaptiveChannel)(AecmCore* aecm); extern ResetAdaptiveChannel WebRtcAecm_ResetAdaptiveChannel; // For the above function pointers, functions for generic platforms are declared // and defined as static in file aecm_core.c, while those for ARM Neon platforms // are declared below and defined in file aecm_core_neon.c. #if defined(WEBRTC_DETECT_NEON) || defined(WEBRTC_HAS_NEON) void WebRtcAecm_CalcLinearEnergiesNeon(AecmCore* aecm, const uint16_t* far_spectrum, int32_t* echo_est, uint32_t* far_energy, uint32_t* echo_energy_adapt, uint32_t* echo_energy_stored); void WebRtcAecm_StoreAdaptiveChannelNeon(AecmCore* aecm, const uint16_t* far_spectrum, int32_t* echo_est); void WebRtcAecm_ResetAdaptiveChannelNeon(AecmCore* aecm); #endif #if defined(MIPS32_LE) void WebRtcAecm_CalcLinearEnergies_mips(AecmCore* aecm, const uint16_t* far_spectrum, int32_t* echo_est, uint32_t* far_energy, uint32_t* echo_energy_adapt, uint32_t* echo_energy_stored); #if defined(MIPS_DSP_R1_LE) void WebRtcAecm_StoreAdaptiveChannel_mips(AecmCore* aecm, const uint16_t* far_spectrum, int32_t* echo_est); void WebRtcAecm_ResetAdaptiveChannel_mips(AecmCore* aecm); #endif #endif #endif