Home | History | Annotate | Download | only in aec
      1 /*
      2  *  Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
      3  *
      4  *  Use of this source code is governed by a BSD-style license
      5  *  that can be found in the LICENSE file in the root of the source
      6  *  tree. An additional intellectual property rights grant can be found
      7  *  in the file PATENTS.  All contributing project authors may
      8  *  be found in the AUTHORS file in the root of the source tree.
      9  */
     10 
     11 /* Resamples a signal to an arbitrary rate. Used by the AEC to compensate for
     12  * clock skew by resampling the farend signal.
     13  */
     14 
     15 #include "webrtc/modules/audio_processing/aec/aec_resampler.h"
     16 
     17 #include <assert.h>
     18 #include <math.h>
     19 #include <stdlib.h>
     20 #include <string.h>
     21 
     22 #include "webrtc/modules/audio_processing/aec/aec_core.h"
     23 
     24 enum {
     25   kEstimateLengthFrames = 400
     26 };
     27 
     28 typedef struct {
     29   short buffer[kResamplerBufferSize];
     30   float position;
     31 
     32   int deviceSampleRateHz;
     33   int skewData[kEstimateLengthFrames];
     34   int skewDataIndex;
     35   float skewEstimate;
     36 } resampler_t;
     37 
     38 static int EstimateSkew(const int* rawSkew,
     39                         int size,
     40                         int absLimit,
     41                         float* skewEst);
     42 
     43 int WebRtcAec_CreateResampler(void** resampInst) {
     44   resampler_t* obj = malloc(sizeof(resampler_t));
     45   *resampInst = obj;
     46   if (obj == NULL) {
     47     return -1;
     48   }
     49 
     50   return 0;
     51 }
     52 
     53 int WebRtcAec_InitResampler(void* resampInst, int deviceSampleRateHz) {
     54   resampler_t* obj = (resampler_t*)resampInst;
     55   memset(obj->buffer, 0, sizeof(obj->buffer));
     56   obj->position = 0.0;
     57 
     58   obj->deviceSampleRateHz = deviceSampleRateHz;
     59   memset(obj->skewData, 0, sizeof(obj->skewData));
     60   obj->skewDataIndex = 0;
     61   obj->skewEstimate = 0.0;
     62 
     63   return 0;
     64 }
     65 
     66 int WebRtcAec_FreeResampler(void* resampInst) {
     67   resampler_t* obj = (resampler_t*)resampInst;
     68   free(obj);
     69 
     70   return 0;
     71 }
     72 
     73 void WebRtcAec_ResampleLinear(void* resampInst,
     74                               const short* inspeech,
     75                               int size,
     76                               float skew,
     77                               short* outspeech,
     78                               int* size_out) {
     79   resampler_t* obj = (resampler_t*)resampInst;
     80 
     81   short* y;
     82   float be, tnew, interp;
     83   int tn, mm;
     84 
     85   assert(!(size < 0 || size > 2 * FRAME_LEN));
     86   assert(resampInst != NULL);
     87   assert(inspeech != NULL);
     88   assert(outspeech != NULL);
     89   assert(size_out != NULL);
     90 
     91   // Add new frame data in lookahead
     92   memcpy(&obj->buffer[FRAME_LEN + kResamplingDelay],
     93          inspeech,
     94          size * sizeof(short));
     95 
     96   // Sample rate ratio
     97   be = 1 + skew;
     98 
     99   // Loop over input frame
    100   mm = 0;
    101   y = &obj->buffer[FRAME_LEN];  // Point at current frame
    102 
    103   tnew = be * mm + obj->position;
    104   tn = (int)tnew;
    105 
    106   while (tn < size) {
    107 
    108     // Interpolation
    109     interp = y[tn] + (tnew - tn) * (y[tn + 1] - y[tn]);
    110 
    111     if (interp > 32767) {
    112       interp = 32767;
    113     } else if (interp < -32768) {
    114       interp = -32768;
    115     }
    116 
    117     outspeech[mm] = (short)interp;
    118     mm++;
    119 
    120     tnew = be * mm + obj->position;
    121     tn = (int)tnew;
    122   }
    123 
    124   *size_out = mm;
    125   obj->position += (*size_out) * be - size;
    126 
    127   // Shift buffer
    128   memmove(obj->buffer,
    129           &obj->buffer[size],
    130           (kResamplerBufferSize - size) * sizeof(short));
    131 }
    132 
    133 int WebRtcAec_GetSkew(void* resampInst, int rawSkew, float* skewEst) {
    134   resampler_t* obj = (resampler_t*)resampInst;
    135   int err = 0;
    136 
    137   if (obj->skewDataIndex < kEstimateLengthFrames) {
    138     obj->skewData[obj->skewDataIndex] = rawSkew;
    139     obj->skewDataIndex++;
    140   } else if (obj->skewDataIndex == kEstimateLengthFrames) {
    141     err = EstimateSkew(
    142         obj->skewData, kEstimateLengthFrames, obj->deviceSampleRateHz, skewEst);
    143     obj->skewEstimate = *skewEst;
    144     obj->skewDataIndex++;
    145   } else {
    146     *skewEst = obj->skewEstimate;
    147   }
    148 
    149   return err;
    150 }
    151 
    152 int EstimateSkew(const int* rawSkew,
    153                  int size,
    154                  int deviceSampleRateHz,
    155                  float* skewEst) {
    156   const int absLimitOuter = (int)(0.04f * deviceSampleRateHz);
    157   const int absLimitInner = (int)(0.0025f * deviceSampleRateHz);
    158   int i = 0;
    159   int n = 0;
    160   float rawAvg = 0;
    161   float err = 0;
    162   float rawAbsDev = 0;
    163   int upperLimit = 0;
    164   int lowerLimit = 0;
    165   float cumSum = 0;
    166   float x = 0;
    167   float x2 = 0;
    168   float y = 0;
    169   float xy = 0;
    170   float xAvg = 0;
    171   float denom = 0;
    172   float skew = 0;
    173 
    174   *skewEst = 0;  // Set in case of error below.
    175   for (i = 0; i < size; i++) {
    176     if ((rawSkew[i] < absLimitOuter && rawSkew[i] > -absLimitOuter)) {
    177       n++;
    178       rawAvg += rawSkew[i];
    179     }
    180   }
    181 
    182   if (n == 0) {
    183     return -1;
    184   }
    185   assert(n > 0);
    186   rawAvg /= n;
    187 
    188   for (i = 0; i < size; i++) {
    189     if ((rawSkew[i] < absLimitOuter && rawSkew[i] > -absLimitOuter)) {
    190       err = rawSkew[i] - rawAvg;
    191       rawAbsDev += err >= 0 ? err : -err;
    192     }
    193   }
    194   assert(n > 0);
    195   rawAbsDev /= n;
    196   upperLimit = (int)(rawAvg + 5 * rawAbsDev + 1);  // +1 for ceiling.
    197   lowerLimit = (int)(rawAvg - 5 * rawAbsDev - 1);  // -1 for floor.
    198 
    199   n = 0;
    200   for (i = 0; i < size; i++) {
    201     if ((rawSkew[i] < absLimitInner && rawSkew[i] > -absLimitInner) ||
    202         (rawSkew[i] < upperLimit && rawSkew[i] > lowerLimit)) {
    203       n++;
    204       cumSum += rawSkew[i];
    205       x += n;
    206       x2 += n * n;
    207       y += cumSum;
    208       xy += n * cumSum;
    209     }
    210   }
    211 
    212   if (n == 0) {
    213     return -1;
    214   }
    215   assert(n > 0);
    216   xAvg = x / n;
    217   denom = x2 - xAvg * x;
    218 
    219   if (denom != 0) {
    220     skew = (xy - xAvg * y) / denom;
    221   }
    222 
    223   *skewEst = skew;
    224   return 0;
    225 }
    226