Home | History | Annotate | Download | only in aec
      1 /*
      2  *  Copyright (c) 2011 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 clock
     12  * skew by resampling the farend signal.
     13  */
     14 
     15 #include "aec_resampler.h"
     16 
     17 #include <assert.h>
     18 #include <stdlib.h>
     19 #include <string.h>
     20 #include <math.h>
     21 
     22 #include "aec_core.h"
     23 
     24 enum { kEstimateLengthFrames = 400 };
     25 
     26 typedef struct {
     27     short buffer[kResamplerBufferSize];
     28     float position;
     29 
     30     int deviceSampleRateHz;
     31     int skewData[kEstimateLengthFrames];
     32     int skewDataIndex;
     33     float skewEstimate;
     34 } resampler_t;
     35 
     36 static int EstimateSkew(const int* rawSkew,
     37                         int size,
     38                         int absLimit,
     39                         float *skewEst);
     40 
     41 int WebRtcAec_CreateResampler(void **resampInst)
     42 {
     43     resampler_t *obj = malloc(sizeof(resampler_t));
     44     *resampInst = obj;
     45     if (obj == NULL) {
     46         return -1;
     47     }
     48 
     49     return 0;
     50 }
     51 
     52 int WebRtcAec_InitResampler(void *resampInst, int deviceSampleRateHz)
     53 {
     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 {
     68     resampler_t *obj = (resampler_t*) resampInst;
     69     free(obj);
     70 
     71     return 0;
     72 }
     73 
     74 int WebRtcAec_ResampleLinear(void *resampInst,
     75                              const short *inspeech,
     76                              int size,
     77                              float skew,
     78                              short *outspeech)
     79 {
     80     resampler_t *obj = (resampler_t*) resampInst;
     81 
     82     short *y;
     83     float be, tnew, interp;
     84     int tn, outsize, mm;
     85 
     86     if (size < 0 || size > 2 * FRAME_LEN) {
     87         return -1;
     88     }
     89 
     90     // Add new frame data in lookahead
     91     memcpy(&obj->buffer[FRAME_LEN + kResamplingDelay],
     92            inspeech,
     93            size * sizeof(short));
     94 
     95     // Sample rate ratio
     96     be = 1 + skew;
     97 
     98     // Loop over input frame
     99     mm = 0;
    100     y = &obj->buffer[FRAME_LEN]; // Point at current frame
    101 
    102     tnew = be * mm + obj->position;
    103     tn = (int) tnew;
    104 
    105     while (tn < size) {
    106 
    107         // Interpolation
    108         interp = y[tn] + (tnew - tn) * (y[tn+1] - y[tn]);
    109 
    110         if (interp > 32767) {
    111             interp = 32767;
    112         }
    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     outsize = mm;
    125     obj->position += outsize * be - size;
    126 
    127     // Shift buffer
    128     memmove(obj->buffer,
    129             &obj->buffer[size],
    130             (kResamplerBufferSize - size) * sizeof(short));
    131 
    132     return outsize;
    133 }
    134 
    135 int WebRtcAec_GetSkew(void *resampInst, int rawSkew, float *skewEst)
    136 {
    137     resampler_t *obj = (resampler_t*)resampInst;
    138     int err = 0;
    139 
    140     if (obj->skewDataIndex < kEstimateLengthFrames) {
    141         obj->skewData[obj->skewDataIndex] = rawSkew;
    142         obj->skewDataIndex++;
    143     }
    144     else if (obj->skewDataIndex == kEstimateLengthFrames) {
    145         err = EstimateSkew(obj->skewData,
    146                            kEstimateLengthFrames,
    147                            obj->deviceSampleRateHz,
    148                            skewEst);
    149         obj->skewEstimate = *skewEst;
    150         obj->skewDataIndex++;
    151     }
    152     else {
    153         *skewEst = obj->skewEstimate;
    154     }
    155 
    156     return err;
    157 }
    158 
    159 int EstimateSkew(const int* rawSkew,
    160                  int size,
    161                  int deviceSampleRateHz,
    162                  float *skewEst)
    163 {
    164     const int absLimitOuter = (int)(0.04f * deviceSampleRateHz);
    165     const int absLimitInner = (int)(0.0025f * deviceSampleRateHz);
    166     int i = 0;
    167     int n = 0;
    168     float rawAvg = 0;
    169     float err = 0;
    170     float rawAbsDev = 0;
    171     int upperLimit = 0;
    172     int lowerLimit = 0;
    173     float cumSum = 0;
    174     float x = 0;
    175     float x2 = 0;
    176     float y = 0;
    177     float xy = 0;
    178     float xAvg = 0;
    179     float denom = 0;
    180     float skew = 0;
    181 
    182     *skewEst = 0; // Set in case of error below.
    183     for (i = 0; i < size; i++) {
    184       if ((rawSkew[i] < absLimitOuter && rawSkew[i] > -absLimitOuter)) {
    185         n++;
    186         rawAvg += rawSkew[i];
    187       }
    188     }
    189 
    190     if (n == 0) {
    191       return -1;
    192     }
    193     assert(n > 0);
    194     rawAvg /= n;
    195 
    196     for (i = 0; i < size; i++) {
    197       if ((rawSkew[i] < absLimitOuter && rawSkew[i] > -absLimitOuter)) {
    198         err = rawSkew[i] - rawAvg;
    199         rawAbsDev += err >= 0 ? err : -err;
    200       }
    201     }
    202     assert(n > 0);
    203     rawAbsDev /= n;
    204     upperLimit = (int)(rawAvg + 5 * rawAbsDev + 1); // +1 for ceiling.
    205     lowerLimit = (int)(rawAvg - 5 * rawAbsDev - 1); // -1 for floor.
    206 
    207     n = 0;
    208     for (i = 0; i < size; i++) {
    209         if ((rawSkew[i] < absLimitInner && rawSkew[i] > -absLimitInner) ||
    210             (rawSkew[i] < upperLimit && rawSkew[i] > lowerLimit)) {
    211             n++;
    212             cumSum += rawSkew[i];
    213             x += n;
    214             x2 += n*n;
    215             y += cumSum;
    216             xy += n * cumSum;
    217         }
    218     }
    219 
    220     if (n == 0) {
    221       return -1;
    222     }
    223     assert(n > 0);
    224     xAvg = x / n;
    225     denom = x2 - xAvg*x;
    226 
    227     if (denom != 0) {
    228         skew = (xy - xAvg*y) / denom;
    229     }
    230 
    231     *skewEst = skew;
    232     return 0;
    233 }
    234