Beispiel #1
0
void WebRtcAec_ProcessFrame(aec_t *aec,
                            const short *nearend,
                            const short *nearendH,
                            int knownDelay)
{
    // For each frame the process is as follows:
    // 1) If the system_delay indicates on being too small for processing a
    //    frame we stuff the buffer with enough data for 10 ms.
    // 2) Adjust the buffer to the system delay, by moving the read pointer.
    // 3) If we can't move read pointer due to buffer size limitations we
    //    flush/stuff the buffer.
    // 4) Process as many partitions as possible.
    // 5) Update the |system_delay| with respect to a full frame of FRAME_LEN
    //    samples. Even though we will have data left to process (we work with
    //    partitions) we consider updating a whole frame, since that's the
    //    amount of data we input and output in audio_processing.

    // TODO(bjornv): Investigate how we should round the delay difference; right
    // now we know that incoming |knownDelay| is underestimated when it's less
    // than |aec->knownDelay|. We therefore, round (-32) in that direction. In
    // the other direction, we don't have this situation, but might flush one
    // partition too little. This can cause non-causality, which should be
    // investigated. Maybe, allow for a non-symmetric rounding, like -16.
    int move_elements = (aec->knownDelay - knownDelay - 32) / PART_LEN;
    int moved_elements = 0;

    // TODO(bjornv): Change the near-end buffer handling to be the same as for
    // far-end, that is, with a near_pre_buf.
    // Buffer the near-end frame.
    WebRtc_WriteBuffer(aec->nearFrBuf, nearend, FRAME_LEN);
    // For H band
    if (aec->sampFreq == 32000) {
        WebRtc_WriteBuffer(aec->nearFrBufH, nearendH, FRAME_LEN);
    }

    // 1) At most we process |aec->mult|+1 partitions in 10 ms. Make sure we
    // have enough far-end data for that by stuffing the buffer if the
    // |system_delay| indicates others.
    if (aec->system_delay < FRAME_LEN) {
      // We don't have enough data so we rewind 10 ms.
      WebRtcAec_MoveFarReadPtr(aec, -(aec->mult + 1));
    }

    // 2) Compensate for a possible change in the system delay.
    WebRtc_MoveReadPtr(aec->far_buf_windowed, move_elements);
    moved_elements = WebRtc_MoveReadPtr(aec->far_buf, move_elements);
    aec->knownDelay -= moved_elements * PART_LEN;
#ifdef WEBRTC_AEC_DEBUG_DUMP
    WebRtc_MoveReadPtr(aec->far_time_buf, move_elements);
#endif

    // 4) Process as many blocks as possible.
    while (WebRtc_available_read(aec->nearFrBuf) >= PART_LEN) {
        ProcessBlock(aec);
    }

    // 5) Update system delay with respect to the entire frame.
    aec->system_delay -= FRAME_LEN;
}
Beispiel #2
0
int WebRtcAec_MoveFarReadPtr(aec_t *aec, int elements) {
  int elements_moved = WebRtc_MoveReadPtr(aec->far_buf_windowed, elements);
  WebRtc_MoveReadPtr(aec->far_buf, elements);
#ifdef WEBRTC_AEC_DEBUG_DUMP
  WebRtc_MoveReadPtr(aec->far_time_buf, elements);
#endif
  aec->system_delay -= elements_moved * PART_LEN;
  return elements_moved;
}
// only buffer L band for farend
int32_t WebRtcAec_BufferFarend(void* aecInst,
                               const float* farend,
                               size_t nrOfSamples) {
  Aec* aecpc = aecInst;
  size_t newNrOfSamples = nrOfSamples;
  float new_farend[MAX_RESAMP_LEN];
  const float* farend_ptr = farend;

  // Get any error caused by buffering the farend signal.
  int32_t error_code = WebRtcAec_GetBufferFarendError(aecInst, farend,
                                                      nrOfSamples);

  if (error_code != 0)
    return error_code;


  if (aecpc->skewMode == kAecTrue && aecpc->resample == kAecTrue) {
    // Resample and get a new number of samples
    WebRtcAec_ResampleLinear(aecpc->resampler,
                             farend,
                             nrOfSamples,
                             aecpc->skew,
                             new_farend,
                             &newNrOfSamples);
    farend_ptr = new_farend;
  }

  aecpc->farend_started = 1;
  WebRtcAec_SetSystemDelay(
      aecpc->aec, WebRtcAec_system_delay(aecpc->aec) + (int)newNrOfSamples);

  // Write the time-domain data to |far_pre_buf|.
  WebRtc_WriteBuffer(aecpc->far_pre_buf, farend_ptr, newNrOfSamples);

  // Transform to frequency domain if we have enough data.
  while (WebRtc_available_read(aecpc->far_pre_buf) >= PART_LEN2) {
    // We have enough data to pass to the FFT, hence read PART_LEN2 samples.
    {
      float* ptmp = NULL;
      float tmp[PART_LEN2];
      WebRtc_ReadBuffer(aecpc->far_pre_buf, (void**)&ptmp, tmp, PART_LEN2);
      WebRtcAec_BufferFarendPartition(aecpc->aec, ptmp);
#ifdef WEBRTC_AEC_DEBUG_DUMP
      WebRtc_WriteBuffer(
          WebRtcAec_far_time_buf(aecpc->aec), &ptmp[PART_LEN], 1);
#endif
    }

    // Rewind |far_pre_buf| PART_LEN samples for overlap before continuing.
    WebRtc_MoveReadPtr(aecpc->far_pre_buf, -PART_LEN);
  }

  return 0;
}
Beispiel #4
0
size_t WebRtc_ReadBuffer(RingBuffer* self,
                         void** data_ptr,
                         void* data,
                         size_t element_count) {

  if (self == NULL) {
    return 0;
  }
  if (data == NULL) {
    return 0;
  }

  {
    void* buf_ptr_1 = NULL;
    void* buf_ptr_2 = NULL;
    size_t buf_ptr_bytes_1 = 0;
    size_t buf_ptr_bytes_2 = 0;
    const size_t read_count = GetBufferReadRegions(self,
                                                   element_count,
                                                   &buf_ptr_1,
                                                   &buf_ptr_bytes_1,
                                                   &buf_ptr_2,
                                                   &buf_ptr_bytes_2);

    if (buf_ptr_bytes_2 > 0) {
      // We have a wrap around when reading the buffer. Copy the buffer data to
      // |data| and point to it.
      memcpy(data, buf_ptr_1, buf_ptr_bytes_1);
      memcpy(((char*) data) + buf_ptr_bytes_1, buf_ptr_2, buf_ptr_bytes_2);
      buf_ptr_1 = data;
    } else if (!data_ptr) {
      // No wrap, but a memcpy was requested.
      memcpy(data, buf_ptr_1, buf_ptr_bytes_1);
    }
    if (data_ptr) {
      // |buf_ptr_1| == |data| in the case of a wrap.
      *data_ptr = buf_ptr_1;
    }

    // Update read position
    WebRtc_MoveReadPtr(self, (int) read_count);

    return read_count;
  }
}
// only buffer L band for farend
int32_t WebRtcAec_BufferFarend(void *aecInst, const int16_t *farend,
                               int16_t nrOfSamples)
{
    aecpc_t *aecpc = aecInst;
    int32_t retVal = 0;
    int newNrOfSamples = (int) nrOfSamples;
    short newFarend[MAX_RESAMP_LEN];
    const int16_t* farend_ptr = farend;
    float tmp_farend[MAX_RESAMP_LEN];
    const float* farend_float = tmp_farend;
    float skew;
    int i = 0;

    if (aecpc == NULL) {
        return -1;
    }

    if (farend == NULL) {
        aecpc->lastError = AEC_NULL_POINTER_ERROR;
        return -1;
    }

    if (aecpc->initFlag != initCheck) {
        aecpc->lastError = AEC_UNINITIALIZED_ERROR;
        return -1;
    }

    // number of samples == 160 for SWB input
    if (nrOfSamples != 80 && nrOfSamples != 160) {
        aecpc->lastError = AEC_BAD_PARAMETER_ERROR;
        return -1;
    }

    skew = aecpc->skew;

    if (aecpc->skewMode == kAecTrue && aecpc->resample == kAecTrue) {
        // Resample and get a new number of samples
        WebRtcAec_ResampleLinear(aecpc->resampler, farend, nrOfSamples, skew,
                                 newFarend, &newNrOfSamples);
        farend_ptr = (const int16_t*) newFarend;
    }

    WebRtcAec_SetSystemDelay(aecpc->aec, WebRtcAec_system_delay(aecpc->aec) +
                             newNrOfSamples);

#ifdef WEBRTC_AEC_DEBUG_DUMP
    WebRtc_WriteBuffer(aecpc->far_pre_buf_s16, farend_ptr,
                       (size_t) newNrOfSamples);
#endif
    // Cast to float and write the time-domain data to |far_pre_buf|.
    for (i = 0; i < newNrOfSamples; i++) {
      tmp_farend[i] = (float) farend_ptr[i];
    }
    WebRtc_WriteBuffer(aecpc->far_pre_buf, farend_float,
                       (size_t) newNrOfSamples);

    // Transform to frequency domain if we have enough data.
    while (WebRtc_available_read(aecpc->far_pre_buf) >= PART_LEN2) {
      // We have enough data to pass to the FFT, hence read PART_LEN2 samples.
      WebRtc_ReadBuffer(aecpc->far_pre_buf, (void**) &farend_float, tmp_farend,
                        PART_LEN2);

      WebRtcAec_BufferFarendPartition(aecpc->aec, farend_float);

      // Rewind |far_pre_buf| PART_LEN samples for overlap before continuing.
      WebRtc_MoveReadPtr(aecpc->far_pre_buf, -PART_LEN);
#ifdef WEBRTC_AEC_DEBUG_DUMP
      WebRtc_ReadBuffer(aecpc->far_pre_buf_s16, (void**) &farend_ptr, newFarend,
                        PART_LEN2);
      WebRtc_WriteBuffer(WebRtcAec_far_time_buf(aecpc->aec),
                         &farend_ptr[PART_LEN], 1);
      WebRtc_MoveReadPtr(aecpc->far_pre_buf_s16, -PART_LEN);
#endif
    }

    return retVal;
}
int32_t WebRtcAec_Init(void *aecInst, int32_t sampFreq, int32_t scSampFreq)
{
    aecpc_t *aecpc = aecInst;
    AecConfig aecConfig;

    if (aecpc == NULL) {
        return -1;
    }

    if (sampFreq != 8000 && sampFreq != 16000  && sampFreq != 32000) {
        aecpc->lastError = AEC_BAD_PARAMETER_ERROR;
        return -1;
    }
    aecpc->sampFreq = sampFreq;

    if (scSampFreq < 1 || scSampFreq > 96000) {
        aecpc->lastError = AEC_BAD_PARAMETER_ERROR;
        return -1;
    }
    aecpc->scSampFreq = scSampFreq;

    // Initialize echo canceller core
    if (WebRtcAec_InitAec(aecpc->aec, aecpc->sampFreq) == -1) {
        aecpc->lastError = AEC_UNSPECIFIED_ERROR;
        return -1;
    }

    if (WebRtcAec_InitResampler(aecpc->resampler, aecpc->scSampFreq) == -1) {
        aecpc->lastError = AEC_UNSPECIFIED_ERROR;
        return -1;
    }

    if (WebRtc_InitBuffer(aecpc->far_pre_buf) == -1) {
        aecpc->lastError = AEC_UNSPECIFIED_ERROR;
        return -1;
    }
    WebRtc_MoveReadPtr(aecpc->far_pre_buf, -PART_LEN);  // Start overlap.

    aecpc->initFlag = initCheck;  // indicates that initialization has been done

    if (aecpc->sampFreq == 32000) {
        aecpc->splitSampFreq = 16000;
    }
    else {
        aecpc->splitSampFreq = sampFreq;
    }

    aecpc->skewFrCtr = 0;
    aecpc->activity = 0;

    aecpc->delayCtr = 0;

    aecpc->sum = 0;
    aecpc->counter = 0;
    aecpc->checkBuffSize = 1;
    aecpc->firstVal = 0;

    aecpc->ECstartup = 1;
    aecpc->bufSizeStart = 0;
    aecpc->checkBufSizeCtr = 0;
    aecpc->filtDelay = 0;
    aecpc->timeForDelayChange = 0;
    aecpc->knownDelay = 0;
    aecpc->lastDelayDiff = 0;

    aecpc->skew = 0;
    aecpc->resample = kAecFalse;
    aecpc->highSkewCtr = 0;
    aecpc->sampFactor = (aecpc->scSampFreq * 1.0f) / aecpc->splitSampFreq;

    // Sampling frequency multiplier (SWB is processed as 160 frame size).
    aecpc->rate_factor = aecpc->splitSampFreq / 8000;

    // Default settings.
    aecConfig.nlpMode = kAecNlpModerate;
    aecConfig.skewMode = kAecFalse;
    aecConfig.metricsMode = kAecFalse;
    aecConfig.delay_logging = kAecFalse;

    if (WebRtcAec_set_config(aecpc, aecConfig) == -1) {
        aecpc->lastError = AEC_UNSPECIFIED_ERROR;
        return -1;
    }

#ifdef WEBRTC_AEC_DEBUG_DUMP
    if (WebRtc_InitBuffer(aecpc->far_pre_buf_s16) == -1) {
        aecpc->lastError = AEC_UNSPECIFIED_ERROR;
        return -1;
    }
    WebRtc_MoveReadPtr(aecpc->far_pre_buf_s16, -PART_LEN);  // Start overlap.
#endif

    return 0;
}
WebRtc_Word32 WebRtcAec_Process(void *aecInst, const WebRtc_Word16 *nearend,
    const WebRtc_Word16 *nearendH, WebRtc_Word16 *out, WebRtc_Word16 *outH,
    WebRtc_Word16 nrOfSamples, WebRtc_Word16 msInSndCardBuf, WebRtc_Word32 skew)
{
    aecpc_t *aecpc = aecInst;
    WebRtc_Word32 retVal = 0;
    short i;
    short nBlocks10ms;
    short nFrames;
    // Limit resampling to doubling/halving of signal
    const float minSkewEst = -0.5f;
    const float maxSkewEst = 1.0f;

    if (aecpc == NULL) {
        return -1;
    }

    if (nearend == NULL) {
        aecpc->lastError = AEC_NULL_POINTER_ERROR;
        return -1;
    }

    if (out == NULL) {
        aecpc->lastError = AEC_NULL_POINTER_ERROR;
        return -1;
    }

    if (aecpc->initFlag != initCheck) {
        aecpc->lastError = AEC_UNINITIALIZED_ERROR;
        return -1;
    }

    // number of samples == 160 for SWB input
    if (nrOfSamples != 80 && nrOfSamples != 160) {
        aecpc->lastError = AEC_BAD_PARAMETER_ERROR;
        return -1;
    }

    // Check for valid pointers based on sampling rate
    if (aecpc->sampFreq == 32000 && nearendH == NULL) {
       aecpc->lastError = AEC_NULL_POINTER_ERROR;
       return -1;
    }

    if (msInSndCardBuf < 0) {
        msInSndCardBuf = 0;
        aecpc->lastError = AEC_BAD_PARAMETER_WARNING;
        retVal = -1;
    }
    else if (msInSndCardBuf > 500) {
        msInSndCardBuf = 500;
        aecpc->lastError = AEC_BAD_PARAMETER_WARNING;
        retVal = -1;
    }
    // TODO(andrew): we need to investigate if this +10 is really wanted.
    msInSndCardBuf += 10;
    aecpc->msInSndCardBuf = msInSndCardBuf;

    if (aecpc->skewMode == kAecTrue) {
        if (aecpc->skewFrCtr < 25) {
            aecpc->skewFrCtr++;
        }
        else {
            retVal = WebRtcAec_GetSkew(aecpc->resampler, skew, &aecpc->skew);
            if (retVal == -1) {
                aecpc->skew = 0;
                aecpc->lastError = AEC_BAD_PARAMETER_WARNING;
            }

            aecpc->skew /= aecpc->sampFactor*nrOfSamples;

            if (aecpc->skew < 1.0e-3 && aecpc->skew > -1.0e-3) {
                aecpc->resample = kAecFalse;
            }
            else {
                aecpc->resample = kAecTrue;
            }

            if (aecpc->skew < minSkewEst) {
                aecpc->skew = minSkewEst;
            }
            else if (aecpc->skew > maxSkewEst) {
                aecpc->skew = maxSkewEst;
            }

#ifdef WEBRTC_AEC_DEBUG_DUMP
            fwrite(&aecpc->skew, sizeof(aecpc->skew), 1, aecpc->skewFile);
#endif
        }
    }

    nFrames = nrOfSamples / FRAME_LEN;
    nBlocks10ms = nFrames / aecpc->aec->mult;

    if (aecpc->ECstartup) {
        if (nearend != out) {
            // Only needed if they don't already point to the same place.
            memcpy(out, nearend, sizeof(short) * nrOfSamples);
        }

        // The AEC is in the start up mode
        // AEC is disabled until the system delay is OK

        // Mechanism to ensure that the system delay is reasonably stable.
        if (aecpc->checkBuffSize) {
            aecpc->checkBufSizeCtr++;
            // Before we fill up the far-end buffer we require the system delay
            // to be stable (+/-8 ms) compared to the first value. This
            // comparison is made during the following 6 consecutive 10 ms
            // blocks. If it seems to be stable then we start to fill up the
            // far-end buffer.
            if (aecpc->counter == 0) {
                aecpc->firstVal = aecpc->msInSndCardBuf;
                aecpc->sum = 0;
            }

            if (abs(aecpc->firstVal - aecpc->msInSndCardBuf) <
                WEBRTC_SPL_MAX(0.2 * aecpc->msInSndCardBuf, sampMsNb)) {
                aecpc->sum += aecpc->msInSndCardBuf;
                aecpc->counter++;
            }
            else {
                aecpc->counter = 0;
            }

            if (aecpc->counter * nBlocks10ms >= 6) {
                // The far-end buffer size is determined in partitions of
                // PART_LEN samples. Use 75% of the average value of the system
                // delay as buffer size to start with.
                aecpc->bufSizeStart = WEBRTC_SPL_MIN((3 * aecpc->sum *
                  aecpc->aec->mult * 8) / (4 * aecpc->counter * PART_LEN),
                  kMaxBufSizeStart);
                // Buffer size has now been determined.
                aecpc->checkBuffSize = 0;
            }

            if (aecpc->checkBufSizeCtr * nBlocks10ms > 50) {
                // For really bad systems, don't disable the echo canceller for
                // more than 0.5 sec.
                aecpc->bufSizeStart = WEBRTC_SPL_MIN((aecpc->msInSndCardBuf *
                    aecpc->aec->mult * 3) / 40, kMaxBufSizeStart);
                aecpc->checkBuffSize = 0;
            }
        }

        // If |checkBuffSize| changed in the if-statement above.
        if (!aecpc->checkBuffSize) {
            // The system delay is now reasonably stable (or has been unstable
            // for too long). When the far-end buffer is filled with
            // approximately the same amount of data as reported by the system
            // we end the startup phase.
            int overhead_elements = aecpc->aec->system_delay / PART_LEN -
                aecpc->bufSizeStart;
            if (overhead_elements == 0) {
                // Enable the AEC
                aecpc->ECstartup = 0;
            } else if (overhead_elements > 0) {
                // TODO(bjornv): Do we need a check on how much we actually
                // moved the read pointer? It should always be possible to move
                // the pointer |overhead_elements| since we have only added data
                // to the buffer and no delay compensation nor AEC processing
                // has been done.
                WebRtcAec_MoveFarReadPtr(aecpc->aec, overhead_elements);

                // Enable the AEC
                aecpc->ECstartup = 0;
            }
        }
    } else {
        // AEC is enabled.

        int out_elements = 0;

        EstBufDelay(aecpc);

        // Note that 1 frame is supported for NB and 2 frames for WB.
        for (i = 0; i < nFrames; i++) {
            int16_t* out_ptr = NULL;
            int16_t out_tmp[FRAME_LEN];

            // Call the AEC.
            WebRtcAec_ProcessFrame(aecpc->aec,
                                   &nearend[FRAME_LEN * i],
                                   &nearendH[FRAME_LEN * i],
                                   aecpc->knownDelay);
            // TODO(bjornv): Re-structure such that we don't have to pass
            // |aecpc->knownDelay| as input. Change name to something like
            // |system_buffer_diff|.

            // Stuff the out buffer if we have less than a frame to output.
            // This should only happen for the first frame.
            out_elements = (int) WebRtc_available_read(aecpc->aec->outFrBuf);
            if (out_elements < FRAME_LEN) {
                WebRtc_MoveReadPtr(aecpc->aec->outFrBuf,
                                   out_elements - FRAME_LEN);
                if (aecpc->sampFreq == 32000) {
                    WebRtc_MoveReadPtr(aecpc->aec->outFrBufH,
                                       out_elements - FRAME_LEN);
                }
            }

            // Obtain an output frame.
            WebRtc_ReadBuffer(aecpc->aec->outFrBuf, (void**) &out_ptr,
                              out_tmp, FRAME_LEN);
            memcpy(&out[FRAME_LEN * i], out_ptr, sizeof(int16_t) * FRAME_LEN);
            // For H band
            if (aecpc->sampFreq == 32000) {
                WebRtc_ReadBuffer(aecpc->aec->outFrBufH, (void**) &out_ptr,
                                  out_tmp, FRAME_LEN);
                memcpy(&outH[FRAME_LEN * i], out_ptr,
                       sizeof(int16_t) * FRAME_LEN);
            }
        }
    }

#ifdef WEBRTC_AEC_DEBUG_DUMP
    {
        int16_t far_buf_size_ms = (int16_t) (aecpc->aec->system_delay /
            (sampMsNb * aecpc->aec->mult));
        fwrite(&far_buf_size_ms, 2, 1, aecpc->bufFile);
        fwrite(&(aecpc->knownDelay), sizeof(aecpc->knownDelay), 1, aecpc->delayFile);
    }
#endif

    return retVal;
}
// only buffer L band for farend
int32_t WebRtcAec_BufferFarend(void* aecInst,
                               const float* farend,
                               int16_t nrOfSamples) {
  Aec* aecpc = aecInst;
  int newNrOfSamples = (int)nrOfSamples;
  float new_farend[MAX_RESAMP_LEN];
  const float* farend_ptr = farend;

  if (farend == NULL) {
    aecpc->lastError = AEC_NULL_POINTER_ERROR;
    return -1;
  }

  if (aecpc->initFlag != initCheck) {
    aecpc->lastError = AEC_UNINITIALIZED_ERROR;
    return -1;
  }

  // number of samples == 160 for SWB input
  if (nrOfSamples != 80 && nrOfSamples != 160) {
    aecpc->lastError = AEC_BAD_PARAMETER_ERROR;
    return -1;
  }

  if (aecpc->skewMode == kAecTrue && aecpc->resample == kAecTrue) {
    // Resample and get a new number of samples
    WebRtcAec_ResampleLinear(aecpc->resampler,
                             farend,
                             nrOfSamples,
                             aecpc->skew,
                             new_farend,
                             &newNrOfSamples);
    farend_ptr = new_farend;
  }

  aecpc->farend_started = 1;
  WebRtcAec_SetSystemDelay(aecpc->aec,
                           WebRtcAec_system_delay(aecpc->aec) + newNrOfSamples);

  // Write the time-domain data to |far_pre_buf|.
  WebRtc_WriteBuffer(aecpc->far_pre_buf, farend_ptr, (size_t)newNrOfSamples);

  // Transform to frequency domain if we have enough data.
  while (WebRtc_available_read(aecpc->far_pre_buf) >= PART_LEN2) {
    // We have enough data to pass to the FFT, hence read PART_LEN2 samples.
    {
      float* ptmp = NULL;
      float tmp[PART_LEN2];
      WebRtc_ReadBuffer(aecpc->far_pre_buf, (void**)&ptmp, tmp, PART_LEN2);
      WebRtcAec_BufferFarendPartition(aecpc->aec, ptmp);
#ifdef WEBRTC_AEC_DEBUG_DUMP
      WebRtc_WriteBuffer(
          WebRtcAec_far_time_buf(aecpc->aec), &ptmp[PART_LEN], 1);
#endif
    }

    // Rewind |far_pre_buf| PART_LEN samples for overlap before continuing.
    WebRtc_MoveReadPtr(aecpc->far_pre_buf, -PART_LEN);
  }

  return 0;
}
int32_t WebRtcAec_Init(void* aecInst, int32_t sampFreq, int32_t scSampFreq) {
  Aec* aecpc = aecInst;
  AecConfig aecConfig;

  if (sampFreq != 8000 &&
      sampFreq != 16000 &&
      sampFreq != 32000 &&
      sampFreq != 48000) {
    return AEC_BAD_PARAMETER_ERROR;
  }
  aecpc->sampFreq = sampFreq;

  if (scSampFreq < 1 || scSampFreq > 96000) {
    return AEC_BAD_PARAMETER_ERROR;
  }
  aecpc->scSampFreq = scSampFreq;

  // Initialize echo canceller core
  if (WebRtcAec_InitAec(aecpc->aec, aecpc->sampFreq) == -1) {
    return AEC_UNSPECIFIED_ERROR;
  }

  if (WebRtcAec_InitResampler(aecpc->resampler, aecpc->scSampFreq) == -1) {
    return AEC_UNSPECIFIED_ERROR;
  }

  WebRtc_InitBuffer(aecpc->far_pre_buf);
  WebRtc_MoveReadPtr(aecpc->far_pre_buf, -PART_LEN);  // Start overlap.

  aecpc->initFlag = initCheck;  // indicates that initialization has been done

  if (aecpc->sampFreq == 32000 || aecpc->sampFreq == 48000) {
    aecpc->splitSampFreq = 16000;
  } else {
    aecpc->splitSampFreq = sampFreq;
  }

  aecpc->delayCtr = 0;
  aecpc->sampFactor = (aecpc->scSampFreq * 1.0f) / aecpc->splitSampFreq;
  // Sampling frequency multiplier (SWB is processed as 160 frame size).
  aecpc->rate_factor = aecpc->splitSampFreq / 8000;

  aecpc->sum = 0;
  aecpc->counter = 0;
  aecpc->checkBuffSize = 1;
  aecpc->firstVal = 0;

  // We skip the startup_phase completely (setting to 0) if DA-AEC is enabled,
  // but not extended_filter mode.
  aecpc->startup_phase = WebRtcAec_extended_filter_enabled(aecpc->aec) ||
      !WebRtcAec_delay_agnostic_enabled(aecpc->aec);
  aecpc->bufSizeStart = 0;
  aecpc->checkBufSizeCtr = 0;
  aecpc->msInSndCardBuf = 0;
  aecpc->filtDelay = -1;  // -1 indicates an initialized state.
  aecpc->timeForDelayChange = 0;
  aecpc->knownDelay = 0;
  aecpc->lastDelayDiff = 0;

  aecpc->skewFrCtr = 0;
  aecpc->resample = kAecFalse;
  aecpc->highSkewCtr = 0;
  aecpc->skew = 0;

  aecpc->farend_started = 0;

  // Default settings.
  aecConfig.nlpMode = kAecNlpModerate;
  aecConfig.skewMode = kAecFalse;
  aecConfig.metricsMode = kAecFalse;
  aecConfig.delay_logging = kAecFalse;

  if (WebRtcAec_set_config(aecpc, aecConfig) == -1) {
    return AEC_UNSPECIFIED_ERROR;
  }

  return 0;
  }