blob: 62a830ba65f49c6b81fb7668dbd3e2a45543d378 [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
andrew@webrtc.org13b2d462013-10-08 23:41:42 +000024enum {
25 kEstimateLengthFrames = 400
26};
niklase@google.com470e71d2011-07-07 08:21:25 +000027
28typedef struct {
kwiberg@webrtc.org38214d52014-07-03 09:47:33 +000029 float buffer[kResamplerBufferSize];
andrew@webrtc.org13b2d462013-10-08 23:41:42 +000030 float position;
niklase@google.com470e71d2011-07-07 08:21:25 +000031
andrew@webrtc.org13b2d462013-10-08 23:41:42 +000032 int deviceSampleRateHz;
33 int skewData[kEstimateLengthFrames];
34 int skewDataIndex;
35 float skewEstimate;
pbos@webrtc.orge468bc92014-12-18 09:11:33 +000036} AecResampler;
niklase@google.com470e71d2011-07-07 08:21:25 +000037
38static int EstimateSkew(const int* rawSkew,
39 int size,
40 int absLimit,
andrew@webrtc.org13b2d462013-10-08 23:41:42 +000041 float* skewEst);
niklase@google.com470e71d2011-07-07 08:21:25 +000042
Bjorn Volcker9345e862015-06-10 21:43:36 +020043void* WebRtcAec_CreateResampler() {
44 return malloc(sizeof(AecResampler));
niklase@google.com470e71d2011-07-07 08:21:25 +000045}
46
andrew@webrtc.org13b2d462013-10-08 23:41:42 +000047int WebRtcAec_InitResampler(void* resampInst, int deviceSampleRateHz) {
pbos@webrtc.orge468bc92014-12-18 09:11:33 +000048 AecResampler* obj = (AecResampler*)resampInst;
andrew@webrtc.org13b2d462013-10-08 23:41:42 +000049 memset(obj->buffer, 0, sizeof(obj->buffer));
50 obj->position = 0.0;
niklase@google.com470e71d2011-07-07 08:21:25 +000051
andrew@webrtc.org13b2d462013-10-08 23:41:42 +000052 obj->deviceSampleRateHz = deviceSampleRateHz;
53 memset(obj->skewData, 0, sizeof(obj->skewData));
54 obj->skewDataIndex = 0;
55 obj->skewEstimate = 0.0;
niklase@google.com470e71d2011-07-07 08:21:25 +000056
andrew@webrtc.org13b2d462013-10-08 23:41:42 +000057 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +000058}
59
Bjorn Volckerf6a99e62015-04-10 07:56:57 +020060void WebRtcAec_FreeResampler(void* resampInst) {
pbos@webrtc.orge468bc92014-12-18 09:11:33 +000061 AecResampler* obj = (AecResampler*)resampInst;
andrew@webrtc.org13b2d462013-10-08 23:41:42 +000062 free(obj);
niklase@google.com470e71d2011-07-07 08:21:25 +000063}
64
andrew@webrtc.org13b2d462013-10-08 23:41:42 +000065void WebRtcAec_ResampleLinear(void* resampInst,
kwiberg@webrtc.org38214d52014-07-03 09:47:33 +000066 const float* inspeech,
bjornv@webrtc.org281b7982012-05-30 07:41:57 +000067 int size,
68 float skew,
kwiberg@webrtc.org38214d52014-07-03 09:47:33 +000069 float* outspeech,
andrew@webrtc.org13b2d462013-10-08 23:41:42 +000070 int* size_out) {
pbos@webrtc.orge468bc92014-12-18 09:11:33 +000071 AecResampler* obj = (AecResampler*)resampInst;
niklase@google.com470e71d2011-07-07 08:21:25 +000072
kwiberg@webrtc.org38214d52014-07-03 09:47:33 +000073 float* y;
74 float be, tnew;
andrew@webrtc.org13b2d462013-10-08 23:41:42 +000075 int tn, mm;
niklase@google.com470e71d2011-07-07 08:21:25 +000076
Peter Kasting728d9032015-06-11 14:31:38 -070077 assert(size >= 0);
78 assert(size <= 2 * FRAME_LEN);
andrew@webrtc.org13b2d462013-10-08 23:41:42 +000079 assert(resampInst != NULL);
80 assert(inspeech != NULL);
81 assert(outspeech != NULL);
82 assert(size_out != NULL);
niklase@google.com470e71d2011-07-07 08:21:25 +000083
andrew@webrtc.org13b2d462013-10-08 23:41:42 +000084 // Add new frame data in lookahead
85 memcpy(&obj->buffer[FRAME_LEN + kResamplingDelay],
86 inspeech,
kwiberg@webrtc.org38214d52014-07-03 09:47:33 +000087 size * sizeof(inspeech[0]));
niklase@google.com470e71d2011-07-07 08:21:25 +000088
andrew@webrtc.org13b2d462013-10-08 23:41:42 +000089 // Sample rate ratio
90 be = 1 + skew;
niklase@google.com470e71d2011-07-07 08:21:25 +000091
andrew@webrtc.org13b2d462013-10-08 23:41:42 +000092 // Loop over input frame
93 mm = 0;
94 y = &obj->buffer[FRAME_LEN]; // Point at current frame
95
96 tnew = be * mm + obj->position;
97 tn = (int)tnew;
98
99 while (tn < size) {
100
101 // Interpolation
kwiberg@webrtc.org38214d52014-07-03 09:47:33 +0000102 outspeech[mm] = y[tn] + (tnew - tn) * (y[tn + 1] - y[tn]);
andrew@webrtc.org13b2d462013-10-08 23:41:42 +0000103 mm++;
niklase@google.com470e71d2011-07-07 08:21:25 +0000104
105 tnew = be * mm + obj->position;
andrew@webrtc.org13b2d462013-10-08 23:41:42 +0000106 tn = (int)tnew;
107 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000108
andrew@webrtc.org13b2d462013-10-08 23:41:42 +0000109 *size_out = mm;
110 obj->position += (*size_out) * be - size;
niklase@google.com470e71d2011-07-07 08:21:25 +0000111
andrew@webrtc.org13b2d462013-10-08 23:41:42 +0000112 // Shift buffer
113 memmove(obj->buffer,
114 &obj->buffer[size],
kwiberg@webrtc.org38214d52014-07-03 09:47:33 +0000115 (kResamplerBufferSize - size) * sizeof(obj->buffer[0]));
niklase@google.com470e71d2011-07-07 08:21:25 +0000116}
117
andrew@webrtc.org13b2d462013-10-08 23:41:42 +0000118int WebRtcAec_GetSkew(void* resampInst, int rawSkew, float* skewEst) {
pbos@webrtc.orge468bc92014-12-18 09:11:33 +0000119 AecResampler* obj = (AecResampler*)resampInst;
andrew@webrtc.org13b2d462013-10-08 23:41:42 +0000120 int err = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000121
andrew@webrtc.org13b2d462013-10-08 23:41:42 +0000122 if (obj->skewDataIndex < kEstimateLengthFrames) {
123 obj->skewData[obj->skewDataIndex] = rawSkew;
124 obj->skewDataIndex++;
125 } else if (obj->skewDataIndex == kEstimateLengthFrames) {
126 err = EstimateSkew(
127 obj->skewData, kEstimateLengthFrames, obj->deviceSampleRateHz, skewEst);
128 obj->skewEstimate = *skewEst;
129 obj->skewDataIndex++;
130 } else {
131 *skewEst = obj->skewEstimate;
132 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000133
andrew@webrtc.org13b2d462013-10-08 23:41:42 +0000134 return err;
niklase@google.com470e71d2011-07-07 08:21:25 +0000135}
136
137int EstimateSkew(const int* rawSkew,
ajm@google.com75e12392011-07-13 16:35:10 +0000138 int size,
139 int deviceSampleRateHz,
andrew@webrtc.org13b2d462013-10-08 23:41:42 +0000140 float* skewEst) {
141 const int absLimitOuter = (int)(0.04f * deviceSampleRateHz);
142 const int absLimitInner = (int)(0.0025f * deviceSampleRateHz);
143 int i = 0;
144 int n = 0;
145 float rawAvg = 0;
146 float err = 0;
147 float rawAbsDev = 0;
148 int upperLimit = 0;
149 int lowerLimit = 0;
150 float cumSum = 0;
151 float x = 0;
152 float x2 = 0;
153 float y = 0;
154 float xy = 0;
155 float xAvg = 0;
156 float denom = 0;
157 float skew = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000158
andrew@webrtc.org13b2d462013-10-08 23:41:42 +0000159 *skewEst = 0; // Set in case of error below.
160 for (i = 0; i < size; i++) {
161 if ((rawSkew[i] < absLimitOuter && rawSkew[i] > -absLimitOuter)) {
162 n++;
163 rawAvg += rawSkew[i];
niklase@google.com470e71d2011-07-07 08:21:25 +0000164 }
andrew@webrtc.org13b2d462013-10-08 23:41:42 +0000165 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000166
andrew@webrtc.org13b2d462013-10-08 23:41:42 +0000167 if (n == 0) {
168 return -1;
169 }
170 assert(n > 0);
171 rawAvg /= n;
172
173 for (i = 0; i < size; i++) {
174 if ((rawSkew[i] < absLimitOuter && rawSkew[i] > -absLimitOuter)) {
175 err = rawSkew[i] - rawAvg;
176 rawAbsDev += err >= 0 ? err : -err;
niklase@google.com470e71d2011-07-07 08:21:25 +0000177 }
andrew@webrtc.org13b2d462013-10-08 23:41:42 +0000178 }
179 assert(n > 0);
180 rawAbsDev /= n;
181 upperLimit = (int)(rawAvg + 5 * rawAbsDev + 1); // +1 for ceiling.
182 lowerLimit = (int)(rawAvg - 5 * rawAbsDev - 1); // -1 for floor.
niklase@google.com470e71d2011-07-07 08:21:25 +0000183
andrew@webrtc.org13b2d462013-10-08 23:41:42 +0000184 n = 0;
185 for (i = 0; i < size; i++) {
186 if ((rawSkew[i] < absLimitInner && rawSkew[i] > -absLimitInner) ||
187 (rawSkew[i] < upperLimit && rawSkew[i] > lowerLimit)) {
188 n++;
189 cumSum += rawSkew[i];
190 x += n;
191 x2 += n * n;
192 y += cumSum;
193 xy += n * cumSum;
niklase@google.com470e71d2011-07-07 08:21:25 +0000194 }
andrew@webrtc.org13b2d462013-10-08 23:41:42 +0000195 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000196
andrew@webrtc.org13b2d462013-10-08 23:41:42 +0000197 if (n == 0) {
198 return -1;
199 }
200 assert(n > 0);
201 xAvg = x / n;
202 denom = x2 - xAvg * x;
niklase@google.com470e71d2011-07-07 08:21:25 +0000203
andrew@webrtc.org13b2d462013-10-08 23:41:42 +0000204 if (denom != 0) {
205 skew = (xy - xAvg * y) / denom;
206 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000207
andrew@webrtc.org13b2d462013-10-08 23:41:42 +0000208 *skewEst = skew;
209 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000210}