blob: 210c2bebe0e2113ad0e808d24f23b9bc808608ad [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
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020015#include "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 <stdlib.h>
18#include <string.h>
niklase@google.com470e71d2011-07-07 08:21:25 +000019
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020020#include "modules/audio_processing/aec/aec_core.h"
21#include "rtc_base/checks.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000022
peah50e21bd2016-03-05 08:39:21 -080023namespace webrtc {
24
peahff63ed22016-01-29 07:46:13 -080025enum { kEstimateLengthFrames = 400 };
niklase@google.com470e71d2011-07-07 08:21:25 +000026
27typedef struct {
kwiberg@webrtc.org38214d52014-07-03 09:47:33 +000028 float buffer[kResamplerBufferSize];
andrew@webrtc.org13b2d462013-10-08 23:41:42 +000029 float position;
niklase@google.com470e71d2011-07-07 08:21:25 +000030
andrew@webrtc.org13b2d462013-10-08 23:41:42 +000031 int deviceSampleRateHz;
32 int skewData[kEstimateLengthFrames];
33 int skewDataIndex;
34 float skewEstimate;
pbos@webrtc.orge468bc92014-12-18 09:11:33 +000035} AecResampler;
niklase@google.com470e71d2011-07-07 08:21:25 +000036
37static int EstimateSkew(const int* rawSkew,
38 int size,
Alex Loiko890988c2017-08-31 10:25:48 +020039 int deviceSampleRateHz,
andrew@webrtc.org13b2d462013-10-08 23:41:42 +000040 float* skewEst);
niklase@google.com470e71d2011-07-07 08:21:25 +000041
Bjorn Volcker9345e862015-06-10 21:43:36 +020042void* WebRtcAec_CreateResampler() {
43 return malloc(sizeof(AecResampler));
niklase@google.com470e71d2011-07-07 08:21:25 +000044}
45
andrew@webrtc.org13b2d462013-10-08 23:41:42 +000046int WebRtcAec_InitResampler(void* resampInst, int deviceSampleRateHz) {
peah88950cf2016-03-04 00:12:40 -080047 AecResampler* obj = static_cast<AecResampler*>(resampInst);
andrew@webrtc.org13b2d462013-10-08 23:41:42 +000048 memset(obj->buffer, 0, sizeof(obj->buffer));
49 obj->position = 0.0;
niklase@google.com470e71d2011-07-07 08:21:25 +000050
andrew@webrtc.org13b2d462013-10-08 23:41:42 +000051 obj->deviceSampleRateHz = deviceSampleRateHz;
52 memset(obj->skewData, 0, sizeof(obj->skewData));
53 obj->skewDataIndex = 0;
54 obj->skewEstimate = 0.0;
niklase@google.com470e71d2011-07-07 08:21:25 +000055
andrew@webrtc.org13b2d462013-10-08 23:41:42 +000056 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +000057}
58
Bjorn Volckerf6a99e62015-04-10 07:56:57 +020059void WebRtcAec_FreeResampler(void* resampInst) {
peah88950cf2016-03-04 00:12:40 -080060 AecResampler* obj = static_cast<AecResampler*>(resampInst);
andrew@webrtc.org13b2d462013-10-08 23:41:42 +000061 free(obj);
niklase@google.com470e71d2011-07-07 08:21:25 +000062}
63
andrew@webrtc.org13b2d462013-10-08 23:41:42 +000064void WebRtcAec_ResampleLinear(void* resampInst,
kwiberg@webrtc.org38214d52014-07-03 09:47:33 +000065 const float* inspeech,
Peter Kastingdce40cf2015-08-24 14:52:23 -070066 size_t size,
bjornv@webrtc.org281b7982012-05-30 07:41:57 +000067 float skew,
kwiberg@webrtc.org38214d52014-07-03 09:47:33 +000068 float* outspeech,
Peter Kastingdce40cf2015-08-24 14:52:23 -070069 size_t* size_out) {
peah88950cf2016-03-04 00:12:40 -080070 AecResampler* obj = static_cast<AecResampler*>(resampInst);
niklase@google.com470e71d2011-07-07 08:21:25 +000071
kwiberg@webrtc.org38214d52014-07-03 09:47:33 +000072 float* y;
73 float be, tnew;
Peter Kastingdce40cf2015-08-24 14:52:23 -070074 size_t tn, mm;
niklase@google.com470e71d2011-07-07 08:21:25 +000075
kwibergaf476c72016-11-28 15:21:39 -080076 RTC_DCHECK_LE(size, 2 * FRAME_LEN);
kwiberg9e2be5f2016-09-14 05:23:22 -070077 RTC_DCHECK(resampInst);
78 RTC_DCHECK(inspeech);
79 RTC_DCHECK(outspeech);
80 RTC_DCHECK(size_out);
niklase@google.com470e71d2011-07-07 08:21:25 +000081
andrew@webrtc.org13b2d462013-10-08 23:41:42 +000082 // Add new frame data in lookahead
peahff63ed22016-01-29 07:46:13 -080083 memcpy(&obj->buffer[FRAME_LEN + kResamplingDelay], inspeech,
kwiberg@webrtc.org38214d52014-07-03 09:47:33 +000084 size * sizeof(inspeech[0]));
niklase@google.com470e71d2011-07-07 08:21:25 +000085
andrew@webrtc.org13b2d462013-10-08 23:41:42 +000086 // Sample rate ratio
87 be = 1 + skew;
niklase@google.com470e71d2011-07-07 08:21:25 +000088
andrew@webrtc.org13b2d462013-10-08 23:41:42 +000089 // Loop over input frame
90 mm = 0;
91 y = &obj->buffer[FRAME_LEN]; // Point at current frame
92
93 tnew = be * mm + obj->position;
Peter Kastingdce40cf2015-08-24 14:52:23 -070094 tn = (size_t)tnew;
andrew@webrtc.org13b2d462013-10-08 23:41:42 +000095
96 while (tn < size) {
andrew@webrtc.org13b2d462013-10-08 23:41:42 +000097 // Interpolation
kwiberg@webrtc.org38214d52014-07-03 09:47:33 +000098 outspeech[mm] = y[tn] + (tnew - tn) * (y[tn + 1] - y[tn]);
andrew@webrtc.org13b2d462013-10-08 23:41:42 +000099 mm++;
niklase@google.com470e71d2011-07-07 08:21:25 +0000100
101 tnew = be * mm + obj->position;
peah88950cf2016-03-04 00:12:40 -0800102 tn = static_cast<int>(tnew);
andrew@webrtc.org13b2d462013-10-08 23:41:42 +0000103 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000104
andrew@webrtc.org13b2d462013-10-08 23:41:42 +0000105 *size_out = mm;
106 obj->position += (*size_out) * be - size;
niklase@google.com470e71d2011-07-07 08:21:25 +0000107
andrew@webrtc.org13b2d462013-10-08 23:41:42 +0000108 // Shift buffer
peahff63ed22016-01-29 07:46:13 -0800109 memmove(obj->buffer, &obj->buffer[size],
kwiberg@webrtc.org38214d52014-07-03 09:47:33 +0000110 (kResamplerBufferSize - size) * sizeof(obj->buffer[0]));
niklase@google.com470e71d2011-07-07 08:21:25 +0000111}
112
andrew@webrtc.org13b2d462013-10-08 23:41:42 +0000113int WebRtcAec_GetSkew(void* resampInst, int rawSkew, float* skewEst) {
peah88950cf2016-03-04 00:12:40 -0800114 AecResampler* obj = static_cast<AecResampler*>(resampInst);
andrew@webrtc.org13b2d462013-10-08 23:41:42 +0000115 int err = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000116
andrew@webrtc.org13b2d462013-10-08 23:41:42 +0000117 if (obj->skewDataIndex < kEstimateLengthFrames) {
118 obj->skewData[obj->skewDataIndex] = rawSkew;
119 obj->skewDataIndex++;
120 } else if (obj->skewDataIndex == kEstimateLengthFrames) {
peahff63ed22016-01-29 07:46:13 -0800121 err = EstimateSkew(obj->skewData, kEstimateLengthFrames,
122 obj->deviceSampleRateHz, skewEst);
andrew@webrtc.org13b2d462013-10-08 23:41:42 +0000123 obj->skewEstimate = *skewEst;
124 obj->skewDataIndex++;
125 } else {
126 *skewEst = obj->skewEstimate;
127 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000128
andrew@webrtc.org13b2d462013-10-08 23:41:42 +0000129 return err;
niklase@google.com470e71d2011-07-07 08:21:25 +0000130}
131
132int EstimateSkew(const int* rawSkew,
ajm@google.com75e12392011-07-13 16:35:10 +0000133 int size,
134 int deviceSampleRateHz,
andrew@webrtc.org13b2d462013-10-08 23:41:42 +0000135 float* skewEst) {
peah88950cf2016-03-04 00:12:40 -0800136 const int absLimitOuter = static_cast<int>(0.04f * deviceSampleRateHz);
137 const int absLimitInner = static_cast<int>(0.0025f * deviceSampleRateHz);
andrew@webrtc.org13b2d462013-10-08 23:41:42 +0000138 int i = 0;
139 int n = 0;
140 float rawAvg = 0;
141 float err = 0;
142 float rawAbsDev = 0;
143 int upperLimit = 0;
144 int lowerLimit = 0;
145 float cumSum = 0;
146 float x = 0;
147 float x2 = 0;
148 float y = 0;
149 float xy = 0;
150 float xAvg = 0;
151 float denom = 0;
152 float skew = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000153
andrew@webrtc.org13b2d462013-10-08 23:41:42 +0000154 *skewEst = 0; // Set in case of error below.
155 for (i = 0; i < size; i++) {
156 if ((rawSkew[i] < absLimitOuter && rawSkew[i] > -absLimitOuter)) {
157 n++;
158 rawAvg += rawSkew[i];
niklase@google.com470e71d2011-07-07 08:21:25 +0000159 }
andrew@webrtc.org13b2d462013-10-08 23:41:42 +0000160 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000161
andrew@webrtc.org13b2d462013-10-08 23:41:42 +0000162 if (n == 0) {
163 return -1;
164 }
kwiberg9e2be5f2016-09-14 05:23:22 -0700165 RTC_DCHECK_GT(n, 0);
andrew@webrtc.org13b2d462013-10-08 23:41:42 +0000166 rawAvg /= n;
167
168 for (i = 0; i < size; i++) {
169 if ((rawSkew[i] < absLimitOuter && rawSkew[i] > -absLimitOuter)) {
170 err = rawSkew[i] - rawAvg;
171 rawAbsDev += err >= 0 ? err : -err;
niklase@google.com470e71d2011-07-07 08:21:25 +0000172 }
andrew@webrtc.org13b2d462013-10-08 23:41:42 +0000173 }
kwiberg9e2be5f2016-09-14 05:23:22 -0700174 RTC_DCHECK_GT(n, 0);
andrew@webrtc.org13b2d462013-10-08 23:41:42 +0000175 rawAbsDev /= n;
peah88950cf2016-03-04 00:12:40 -0800176 upperLimit = static_cast<int>(rawAvg + 5 * rawAbsDev + 1); // +1 for ceiling.
177 lowerLimit = static_cast<int>(rawAvg - 5 * rawAbsDev - 1); // -1 for floor.
niklase@google.com470e71d2011-07-07 08:21:25 +0000178
andrew@webrtc.org13b2d462013-10-08 23:41:42 +0000179 n = 0;
180 for (i = 0; i < size; i++) {
181 if ((rawSkew[i] < absLimitInner && rawSkew[i] > -absLimitInner) ||
182 (rawSkew[i] < upperLimit && rawSkew[i] > lowerLimit)) {
183 n++;
184 cumSum += rawSkew[i];
185 x += n;
186 x2 += n * n;
187 y += cumSum;
188 xy += n * cumSum;
niklase@google.com470e71d2011-07-07 08:21:25 +0000189 }
andrew@webrtc.org13b2d462013-10-08 23:41:42 +0000190 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000191
andrew@webrtc.org13b2d462013-10-08 23:41:42 +0000192 if (n == 0) {
193 return -1;
194 }
kwiberg9e2be5f2016-09-14 05:23:22 -0700195 RTC_DCHECK_GT(n, 0);
andrew@webrtc.org13b2d462013-10-08 23:41:42 +0000196 xAvg = x / n;
197 denom = x2 - xAvg * x;
niklase@google.com470e71d2011-07-07 08:21:25 +0000198
andrew@webrtc.org13b2d462013-10-08 23:41:42 +0000199 if (denom != 0) {
200 skew = (xy - xAvg * y) / denom;
201 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000202
andrew@webrtc.org13b2d462013-10-08 23:41:42 +0000203 *skewEst = skew;
204 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000205}
peah50e21bd2016-03-05 08:39:21 -0800206} // namespace webrtc