blob: 8528fa65e385609f4dfaa39207c5edce55bd0d8c [file] [log] [blame]
niklase@google.com470e71d2011-07-07 08:21:25 +00001/*
bjornv@webrtc.org281b7982012-05-30 07:41:57 +00002 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
niklase@google.com470e71d2011-07-07 08:21:25 +00003 *
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
andrew@webrtc.org13b2d462013-10-08 23:41:42 +000011/* Resamples a signal to an arbitrary rate. Used by the AEC to compensate for
andrew@webrtc.org89b1e682013-10-18 14:23:29 +000012 * clock skew by resampling the farend signal.
niklase@google.com470e71d2011-07-07 08:21:25 +000013 */
14
pbos@webrtc.org7fad4b82013-05-28 08:11:59 +000015#include "webrtc/modules/audio_processing/aec/aec_resampler.h"
bjornv@webrtc.org4b80eb42011-11-29 08:44:01 +000016
niklase@google.com470e71d2011-07-07 08:21:25 +000017#include <assert.h>
pbos@webrtc.org7fad4b82013-05-28 08:11:59 +000018#include <math.h>
niklase@google.com470e71d2011-07-07 08:21:25 +000019#include <stdlib.h>
20#include <string.h>
niklase@google.com470e71d2011-07-07 08:21:25 +000021
pbos@webrtc.org7fad4b82013-05-28 08:11:59 +000022#include "webrtc/modules/audio_processing/aec/aec_core.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000023
peahff63ed22016-01-29 07:46:13 -080024enum { kEstimateLengthFrames = 400 };
niklase@google.com470e71d2011-07-07 08:21:25 +000025
26typedef struct {
kwiberg@webrtc.org38214d52014-07-03 09:47:33 +000027 float buffer[kResamplerBufferSize];
andrew@webrtc.org13b2d462013-10-08 23:41:42 +000028 float position;
niklase@google.com470e71d2011-07-07 08:21:25 +000029
andrew@webrtc.org13b2d462013-10-08 23:41:42 +000030 int deviceSampleRateHz;
31 int skewData[kEstimateLengthFrames];
32 int skewDataIndex;
33 float skewEstimate;
pbos@webrtc.orge468bc92014-12-18 09:11:33 +000034} AecResampler;
niklase@google.com470e71d2011-07-07 08:21:25 +000035
36static int EstimateSkew(const int* rawSkew,
37 int size,
38 int absLimit,
andrew@webrtc.org13b2d462013-10-08 23:41:42 +000039 float* skewEst);
niklase@google.com470e71d2011-07-07 08:21:25 +000040
Bjorn Volcker9345e862015-06-10 21:43:36 +020041void* WebRtcAec_CreateResampler() {
42 return malloc(sizeof(AecResampler));
niklase@google.com470e71d2011-07-07 08:21:25 +000043}
44
andrew@webrtc.org13b2d462013-10-08 23:41:42 +000045int WebRtcAec_InitResampler(void* resampInst, int deviceSampleRateHz) {
peah88950cf2016-03-04 00:12:40 -080046 AecResampler* obj = static_cast<AecResampler*>(resampInst);
andrew@webrtc.org13b2d462013-10-08 23:41:42 +000047 memset(obj->buffer, 0, sizeof(obj->buffer));
48 obj->position = 0.0;
niklase@google.com470e71d2011-07-07 08:21:25 +000049
andrew@webrtc.org13b2d462013-10-08 23:41:42 +000050 obj->deviceSampleRateHz = deviceSampleRateHz;
51 memset(obj->skewData, 0, sizeof(obj->skewData));
52 obj->skewDataIndex = 0;
53 obj->skewEstimate = 0.0;
niklase@google.com470e71d2011-07-07 08:21:25 +000054
andrew@webrtc.org13b2d462013-10-08 23:41:42 +000055 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +000056}
57
Bjorn Volckerf6a99e62015-04-10 07:56:57 +020058void WebRtcAec_FreeResampler(void* resampInst) {
peah88950cf2016-03-04 00:12:40 -080059 AecResampler* obj = static_cast<AecResampler*>(resampInst);
andrew@webrtc.org13b2d462013-10-08 23:41:42 +000060 free(obj);
niklase@google.com470e71d2011-07-07 08:21:25 +000061}
62
andrew@webrtc.org13b2d462013-10-08 23:41:42 +000063void WebRtcAec_ResampleLinear(void* resampInst,
kwiberg@webrtc.org38214d52014-07-03 09:47:33 +000064 const float* inspeech,
Peter Kastingdce40cf2015-08-24 14:52:23 -070065 size_t size,
bjornv@webrtc.org281b7982012-05-30 07:41:57 +000066 float skew,
kwiberg@webrtc.org38214d52014-07-03 09:47:33 +000067 float* outspeech,
Peter Kastingdce40cf2015-08-24 14:52:23 -070068 size_t* size_out) {
peah88950cf2016-03-04 00:12:40 -080069 AecResampler* obj = static_cast<AecResampler*>(resampInst);
niklase@google.com470e71d2011-07-07 08:21:25 +000070
kwiberg@webrtc.org38214d52014-07-03 09:47:33 +000071 float* y;
72 float be, tnew;
Peter Kastingdce40cf2015-08-24 14:52:23 -070073 size_t tn, mm;
niklase@google.com470e71d2011-07-07 08:21:25 +000074
Peter Kasting728d9032015-06-11 14:31:38 -070075 assert(size <= 2 * FRAME_LEN);
andrew@webrtc.org13b2d462013-10-08 23:41:42 +000076 assert(resampInst != NULL);
77 assert(inspeech != NULL);
78 assert(outspeech != NULL);
79 assert(size_out != NULL);
niklase@google.com470e71d2011-07-07 08:21:25 +000080
andrew@webrtc.org13b2d462013-10-08 23:41:42 +000081 // Add new frame data in lookahead
peahff63ed22016-01-29 07:46:13 -080082 memcpy(&obj->buffer[FRAME_LEN + kResamplingDelay], inspeech,
kwiberg@webrtc.org38214d52014-07-03 09:47:33 +000083 size * sizeof(inspeech[0]));
niklase@google.com470e71d2011-07-07 08:21:25 +000084
andrew@webrtc.org13b2d462013-10-08 23:41:42 +000085 // Sample rate ratio
86 be = 1 + skew;
niklase@google.com470e71d2011-07-07 08:21:25 +000087
andrew@webrtc.org13b2d462013-10-08 23:41:42 +000088 // Loop over input frame
89 mm = 0;
90 y = &obj->buffer[FRAME_LEN]; // Point at current frame
91
92 tnew = be * mm + obj->position;
Peter Kastingdce40cf2015-08-24 14:52:23 -070093 tn = (size_t)tnew;
andrew@webrtc.org13b2d462013-10-08 23:41:42 +000094
95 while (tn < size) {
andrew@webrtc.org13b2d462013-10-08 23:41:42 +000096 // Interpolation
kwiberg@webrtc.org38214d52014-07-03 09:47:33 +000097 outspeech[mm] = y[tn] + (tnew - tn) * (y[tn + 1] - y[tn]);
andrew@webrtc.org13b2d462013-10-08 23:41:42 +000098 mm++;
niklase@google.com470e71d2011-07-07 08:21:25 +000099
100 tnew = be * mm + obj->position;
peah88950cf2016-03-04 00:12:40 -0800101 tn = static_cast<int>(tnew);
andrew@webrtc.org13b2d462013-10-08 23:41:42 +0000102 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000103
andrew@webrtc.org13b2d462013-10-08 23:41:42 +0000104 *size_out = mm;
105 obj->position += (*size_out) * be - size;
niklase@google.com470e71d2011-07-07 08:21:25 +0000106
andrew@webrtc.org13b2d462013-10-08 23:41:42 +0000107 // Shift buffer
peahff63ed22016-01-29 07:46:13 -0800108 memmove(obj->buffer, &obj->buffer[size],
kwiberg@webrtc.org38214d52014-07-03 09:47:33 +0000109 (kResamplerBufferSize - size) * sizeof(obj->buffer[0]));
niklase@google.com470e71d2011-07-07 08:21:25 +0000110}
111
andrew@webrtc.org13b2d462013-10-08 23:41:42 +0000112int WebRtcAec_GetSkew(void* resampInst, int rawSkew, float* skewEst) {
peah88950cf2016-03-04 00:12:40 -0800113 AecResampler* obj = static_cast<AecResampler*>(resampInst);
andrew@webrtc.org13b2d462013-10-08 23:41:42 +0000114 int err = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000115
andrew@webrtc.org13b2d462013-10-08 23:41:42 +0000116 if (obj->skewDataIndex < kEstimateLengthFrames) {
117 obj->skewData[obj->skewDataIndex] = rawSkew;
118 obj->skewDataIndex++;
119 } else if (obj->skewDataIndex == kEstimateLengthFrames) {
peahff63ed22016-01-29 07:46:13 -0800120 err = EstimateSkew(obj->skewData, kEstimateLengthFrames,
121 obj->deviceSampleRateHz, skewEst);
andrew@webrtc.org13b2d462013-10-08 23:41:42 +0000122 obj->skewEstimate = *skewEst;
123 obj->skewDataIndex++;
124 } else {
125 *skewEst = obj->skewEstimate;
126 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000127
andrew@webrtc.org13b2d462013-10-08 23:41:42 +0000128 return err;
niklase@google.com470e71d2011-07-07 08:21:25 +0000129}
130
131int EstimateSkew(const int* rawSkew,
ajm@google.com75e12392011-07-13 16:35:10 +0000132 int size,
133 int deviceSampleRateHz,
andrew@webrtc.org13b2d462013-10-08 23:41:42 +0000134 float* skewEst) {
peah88950cf2016-03-04 00:12:40 -0800135 const int absLimitOuter = static_cast<int>(0.04f * deviceSampleRateHz);
136 const int absLimitInner = static_cast<int>(0.0025f * deviceSampleRateHz);
andrew@webrtc.org13b2d462013-10-08 23:41:42 +0000137 int i = 0;
138 int n = 0;
139 float rawAvg = 0;
140 float err = 0;
141 float rawAbsDev = 0;
142 int upperLimit = 0;
143 int lowerLimit = 0;
144 float cumSum = 0;
145 float x = 0;
146 float x2 = 0;
147 float y = 0;
148 float xy = 0;
149 float xAvg = 0;
150 float denom = 0;
151 float skew = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000152
andrew@webrtc.org13b2d462013-10-08 23:41:42 +0000153 *skewEst = 0; // Set in case of error below.
154 for (i = 0; i < size; i++) {
155 if ((rawSkew[i] < absLimitOuter && rawSkew[i] > -absLimitOuter)) {
156 n++;
157 rawAvg += rawSkew[i];
niklase@google.com470e71d2011-07-07 08:21:25 +0000158 }
andrew@webrtc.org13b2d462013-10-08 23:41:42 +0000159 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000160
andrew@webrtc.org13b2d462013-10-08 23:41:42 +0000161 if (n == 0) {
162 return -1;
163 }
164 assert(n > 0);
165 rawAvg /= n;
166
167 for (i = 0; i < size; i++) {
168 if ((rawSkew[i] < absLimitOuter && rawSkew[i] > -absLimitOuter)) {
169 err = rawSkew[i] - rawAvg;
170 rawAbsDev += err >= 0 ? err : -err;
niklase@google.com470e71d2011-07-07 08:21:25 +0000171 }
andrew@webrtc.org13b2d462013-10-08 23:41:42 +0000172 }
173 assert(n > 0);
174 rawAbsDev /= n;
peah88950cf2016-03-04 00:12:40 -0800175 upperLimit = static_cast<int>(rawAvg + 5 * rawAbsDev + 1); // +1 for ceiling.
176 lowerLimit = static_cast<int>(rawAvg - 5 * rawAbsDev - 1); // -1 for floor.
niklase@google.com470e71d2011-07-07 08:21:25 +0000177
andrew@webrtc.org13b2d462013-10-08 23:41:42 +0000178 n = 0;
179 for (i = 0; i < size; i++) {
180 if ((rawSkew[i] < absLimitInner && rawSkew[i] > -absLimitInner) ||
181 (rawSkew[i] < upperLimit && rawSkew[i] > lowerLimit)) {
182 n++;
183 cumSum += rawSkew[i];
184 x += n;
185 x2 += n * n;
186 y += cumSum;
187 xy += n * cumSum;
niklase@google.com470e71d2011-07-07 08:21:25 +0000188 }
andrew@webrtc.org13b2d462013-10-08 23:41:42 +0000189 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000190
andrew@webrtc.org13b2d462013-10-08 23:41:42 +0000191 if (n == 0) {
192 return -1;
193 }
194 assert(n > 0);
195 xAvg = x / n;
196 denom = x2 - xAvg * x;
niklase@google.com470e71d2011-07-07 08:21:25 +0000197
andrew@webrtc.org13b2d462013-10-08 23:41:42 +0000198 if (denom != 0) {
199 skew = (xy - xAvg * y) / denom;
200 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000201
andrew@webrtc.org13b2d462013-10-08 23:41:42 +0000202 *skewEst = skew;
203 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000204}