1 /*
2  * Copyright (C) 2014 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 //#define LOG_NDEBUG 0
18 #define LOG_TAG "audioflinger_resampler_tests"
19 
20 #include <errno.h>
21 #include <fcntl.h>
22 #include <math.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <sys/mman.h>
27 #include <sys/stat.h>
28 #include <time.h>
29 #include <unistd.h>
30 
31 #include <iostream>
32 #include <memory>
33 #include <utility>
34 #include <vector>
35 
36 #include <gtest/gtest.h>
37 #include <log/log.h>
38 #include <media/AudioBufferProvider.h>
39 
40 #include <media/AudioResampler.h>
41 #include "../AudioResamplerDyn.h"
42 #include "../AudioResamplerFirGen.h"
43 #include "test_utils.h"
44 
45 template <typename T>
printData(T * data,size_t size)46 static void printData(T *data, size_t size) {
47     const size_t stride = 8;
48     for (size_t i = 0; i < size; ) {
49         for (size_t j = 0; j < stride && i < size; ++j) {
50             std::cout << data[i++] << ' ';  // extra space before newline
51         }
52         std::cout << '\n'; // or endl
53     }
54 }
55 
resample(int channels,void * output,size_t outputFrames,const std::vector<size_t> & outputIncr,android::AudioBufferProvider * provider,android::AudioResampler * resampler)56 void resample(int channels, void *output,
57         size_t outputFrames, const std::vector<size_t> &outputIncr,
58         android::AudioBufferProvider *provider, android::AudioResampler *resampler)
59 {
60     for (size_t i = 0, j = 0; i < outputFrames; ) {
61         size_t thisFrames = outputIncr[j++];
62         if (j >= outputIncr.size()) {
63             j = 0;
64         }
65         if (thisFrames == 0 || thisFrames > outputFrames - i) {
66             thisFrames = outputFrames - i;
67         }
68         size_t framesResampled = resampler->resample(
69                 (int32_t*) output + channels*i, thisFrames, provider);
70         // we should have enough buffer space, so there is no short count.
71         ASSERT_EQ(thisFrames, framesResampled);
72         i += thisFrames;
73     }
74 }
75 
buffercmp(const void * reference,const void * test,size_t outputFrameSize,size_t outputFrames)76 void buffercmp(const void *reference, const void *test,
77         size_t outputFrameSize, size_t outputFrames)
78 {
79     for (size_t i = 0; i < outputFrames; ++i) {
80         int check = memcmp((const char*)reference + i * outputFrameSize,
81                 (const char*)test + i * outputFrameSize, outputFrameSize);
82         if (check) {
83             ALOGE("Failure at frame %zu", i);
84             ASSERT_EQ(check, 0); /* fails */
85         }
86     }
87 }
88 
testBufferIncrement(size_t channels,bool useFloat,unsigned inputFreq,unsigned outputFreq,enum android::AudioResampler::src_quality quality)89 void testBufferIncrement(size_t channels, bool useFloat,
90         unsigned inputFreq, unsigned outputFreq,
91         enum android::AudioResampler::src_quality quality)
92 {
93     const audio_format_t format = useFloat ? AUDIO_FORMAT_PCM_FLOAT : AUDIO_FORMAT_PCM_16_BIT;
94     // create the provider
95     std::vector<int> inputIncr;
96     SignalProvider provider;
97     if (useFloat) {
98         provider.setChirp<float>(channels,
99                 0., outputFreq/2., outputFreq, outputFreq/2000.);
100     } else {
101         provider.setChirp<int16_t>(channels,
102                 0., outputFreq/2., outputFreq, outputFreq/2000.);
103     }
104     provider.setIncr(inputIncr);
105 
106     // calculate the output size
107     size_t outputFrames = ((int64_t) provider.getNumFrames() * outputFreq) / inputFreq;
108     size_t outputFrameSize = (channels == 1 ? 2 : channels) * (useFloat ? sizeof(float) : sizeof(int32_t));
109     size_t outputSize = outputFrameSize * outputFrames;
110     outputSize &= ~7;
111 
112     // create the resampler
113     android::AudioResampler* resampler;
114 
115     resampler = android::AudioResampler::create(format, channels, outputFreq, quality);
116     resampler->setSampleRate(inputFreq);
117     resampler->setVolume(android::AudioResampler::UNITY_GAIN_FLOAT,
118             android::AudioResampler::UNITY_GAIN_FLOAT);
119 
120     // set up the reference run
121     std::vector<size_t> refIncr;
122     refIncr.push_back(outputFrames);
123     void* reference = calloc(outputFrames, outputFrameSize);
124     resample(channels, reference, outputFrames, refIncr, &provider, resampler);
125 
126     provider.reset();
127 
128 #if 0
129     /* this test will fail - API interface issue: reset() does not clear internal buffers */
130     resampler->reset();
131 #else
132     delete resampler;
133     resampler = android::AudioResampler::create(format, channels, outputFreq, quality);
134     resampler->setSampleRate(inputFreq);
135     resampler->setVolume(android::AudioResampler::UNITY_GAIN_FLOAT,
136             android::AudioResampler::UNITY_GAIN_FLOAT);
137 #endif
138 
139     // set up the test run
140     std::vector<size_t> outIncr;
141     outIncr.push_back(1);
142     outIncr.push_back(2);
143     outIncr.push_back(3);
144     void* test = calloc(outputFrames, outputFrameSize);
145     inputIncr.push_back(1);
146     inputIncr.push_back(3);
147     provider.setIncr(inputIncr);
148     resample(channels, test, outputFrames, outIncr, &provider, resampler);
149 
150     // check
151     buffercmp(reference, test, outputFrameSize, outputFrames);
152 
153     free(reference);
154     free(test);
155     delete resampler;
156 }
157 
158 template <typename T>
sqr(T v)159 inline double sqr(T v)
160 {
161     double dv = static_cast<double>(v);
162     return dv * dv;
163 }
164 
165 template <typename T>
signalEnergy(T * start,T * end,unsigned stride)166 double signalEnergy(T *start, T *end, unsigned stride)
167 {
168     double accum = 0;
169 
170     for (T *p = start; p < end; p += stride) {
171         accum += sqr(*p);
172     }
173     unsigned count = (end - start + stride - 1) / stride;
174     return accum / count;
175 }
176 
177 // TI = resampler input type, int16_t or float
178 // TO = resampler output type, int32_t or float
179 template <typename TI, typename TO>
testStopbandDownconversion(size_t channels,unsigned inputFreq,unsigned outputFreq,unsigned passband,unsigned stopband,enum android::AudioResampler::src_quality quality)180 void testStopbandDownconversion(size_t channels,
181         unsigned inputFreq, unsigned outputFreq,
182         unsigned passband, unsigned stopband,
183         enum android::AudioResampler::src_quality quality)
184 {
185     // create the provider
186     std::vector<int> inputIncr;
187     SignalProvider provider;
188     provider.setChirp<TI>(channels,
189             0., inputFreq/2., inputFreq, inputFreq/2000.);
190     provider.setIncr(inputIncr);
191 
192     // calculate the output size
193     size_t outputFrames = ((int64_t) provider.getNumFrames() * outputFreq) / inputFreq;
194     size_t outputFrameSize = (channels == 1 ? 2 : channels) * sizeof(TO);
195     size_t outputSize = outputFrameSize * outputFrames;
196     outputSize &= ~7;
197 
198     // create the resampler
199     android::AudioResampler* resampler;
200 
201     resampler = android::AudioResampler::create(
202             is_same<TI, int16_t>::value ? AUDIO_FORMAT_PCM_16_BIT : AUDIO_FORMAT_PCM_FLOAT,
203             channels, outputFreq, quality);
204     resampler->setSampleRate(inputFreq);
205     resampler->setVolume(android::AudioResampler::UNITY_GAIN_FLOAT,
206             android::AudioResampler::UNITY_GAIN_FLOAT);
207 
208     // set up the reference run
209     std::vector<size_t> refIncr;
210     refIncr.push_back(outputFrames);
211     void* reference = calloc(outputFrames, outputFrameSize);
212     resample(channels, reference, outputFrames, refIncr, &provider, resampler);
213 
214     TO *out = reinterpret_cast<TO *>(reference);
215 
216     // check signal energy in passband
217     const unsigned passbandFrame = passband * outputFreq / 1000.;
218     const unsigned stopbandFrame = stopband * outputFreq / 1000.;
219 
220     // check each channel separately
221     if (channels == 1) channels = 2; // workaround (mono duplicates output channel)
222 
223     for (size_t i = 0; i < channels; ++i) {
224         double passbandEnergy = signalEnergy(out, out + passbandFrame * channels, channels);
225         double stopbandEnergy = signalEnergy(out + stopbandFrame * channels,
226                 out + outputFrames * channels, channels);
227         double dbAtten = -10. * log10(stopbandEnergy / passbandEnergy);
228         ASSERT_GT(dbAtten, 60.);
229 
230 #if 0
231         // internal verification
232         printf("if:%d  of:%d  pbf:%d  sbf:%d  sbe: %f  pbe: %f  db: %.2f\n",
233                 provider.getNumFrames(), outputFrames,
234                 passbandFrame, stopbandFrame, stopbandEnergy, passbandEnergy, dbAtten);
235         for (size_t i = 0; i < 10; ++i) {
236             std::cout << out[i+passbandFrame*channels] << std::endl;
237         }
238         for (size_t i = 0; i < 10; ++i) {
239             std::cout << out[i+stopbandFrame*channels] << std::endl;
240         }
241 #endif
242     }
243 
244     free(reference);
245     delete resampler;
246 }
247 
testFilterResponse(size_t channels,unsigned inputFreq,unsigned outputFreq)248 void testFilterResponse(
249         size_t channels, unsigned inputFreq, unsigned outputFreq)
250 {
251     // create resampler
252     using ResamplerType = android::AudioResamplerDyn<float, float, float>;
253     std::unique_ptr<ResamplerType> rdyn(
254             static_cast<ResamplerType *>(
255                     android::AudioResampler::create(
256                             AUDIO_FORMAT_PCM_FLOAT,
257                             channels,
258                             outputFreq,
259                             android::AudioResampler::DYN_HIGH_QUALITY)));
260     rdyn->setSampleRate(inputFreq);
261 
262     // get design parameters
263     const int phases = rdyn->getPhases();
264     const int halfLength = rdyn->getHalfLength();
265     const float *coefs = rdyn->getFilterCoefs();
266     const double fcr = rdyn->getNormalizedCutoffFrequency();
267     const double tbw = rdyn->getNormalizedTransitionBandwidth();
268     const double attenuation = rdyn->getFilterAttenuation();
269     const double stopbandDb = rdyn->getStopbandAttenuationDb();
270     const double passbandDb = rdyn->getPassbandRippleDb();
271     const double fp = fcr - tbw / 2;
272     const double fs = fcr + tbw / 2;
273 
274     printf("inputFreq:%d outputFreq:%d design"
275             " phases:%d halfLength:%d"
276             " fcr:%lf fp:%lf fs:%lf tbw:%lf"
277             " attenuation:%lf stopRipple:%.lf passRipple:%lf"
278             "\n",
279             inputFreq, outputFreq,
280             phases, halfLength,
281             fcr, fp, fs, tbw,
282             attenuation, stopbandDb, passbandDb);
283 
284     // verify design parameters
285     constexpr int32_t passSteps = 1000;
286     double passMin, passMax, passRipple, stopMax, stopRipple;
287     android::testFir(coefs, phases, halfLength, fp / phases, fs / phases,
288             passSteps, phases * passSteps /* stopSteps */,
289             passMin, passMax, passRipple,
290             stopMax, stopRipple);
291     printf("inputFreq:%d outputFreq:%d verify"
292             " passMin:%lf passMax:%lf passRipple:%lf stopMax:%lf stopRipple:%lf"
293             "\n",
294             inputFreq, outputFreq,
295             passMin, passMax, passRipple, stopMax, stopRipple);
296 
297     ASSERT_GT(stopRipple, 60.);  // enough stopband attenuation
298     ASSERT_LT(passRipple, 0.2);  // small passband ripple
299     ASSERT_GT(passMin, 0.99);    // we do not attenuate the signal (ideally 1.)
300 }
301 
302 /* Buffer increment test
303  *
304  * We compare a reference output, where we consume and process the entire
305  * buffer at a time, and a test output, where we provide small chunks of input
306  * data and process small chunks of output (which may not be equivalent in size).
307  *
308  * Two subtests - fixed phase (3:2 down) and interpolated phase (147:320 up)
309  */
TEST(audioflinger_resampler,bufferincrement_fixedphase)310 TEST(audioflinger_resampler, bufferincrement_fixedphase) {
311     // all of these work
312     static const enum android::AudioResampler::src_quality kQualityArray[] = {
313             android::AudioResampler::LOW_QUALITY,
314             android::AudioResampler::MED_QUALITY,
315             android::AudioResampler::HIGH_QUALITY,
316             android::AudioResampler::VERY_HIGH_QUALITY,
317             android::AudioResampler::DYN_LOW_QUALITY,
318             android::AudioResampler::DYN_MED_QUALITY,
319             android::AudioResampler::DYN_HIGH_QUALITY,
320     };
321 
322     for (size_t i = 0; i < ARRAY_SIZE(kQualityArray); ++i) {
323         testBufferIncrement(2, false, 48000, 32000, kQualityArray[i]);
324     }
325 }
326 
TEST(audioflinger_resampler,bufferincrement_interpolatedphase)327 TEST(audioflinger_resampler, bufferincrement_interpolatedphase) {
328     // all of these work except low quality
329     static const enum android::AudioResampler::src_quality kQualityArray[] = {
330 //           android::AudioResampler::LOW_QUALITY,
331             android::AudioResampler::MED_QUALITY,
332             android::AudioResampler::HIGH_QUALITY,
333             android::AudioResampler::VERY_HIGH_QUALITY,
334             android::AudioResampler::DYN_LOW_QUALITY,
335             android::AudioResampler::DYN_MED_QUALITY,
336             android::AudioResampler::DYN_HIGH_QUALITY,
337     };
338 
339     for (size_t i = 0; i < ARRAY_SIZE(kQualityArray); ++i) {
340         testBufferIncrement(2, false, 22050, 48000, kQualityArray[i]);
341     }
342 }
343 
TEST(audioflinger_resampler,bufferincrement_fixedphase_multi)344 TEST(audioflinger_resampler, bufferincrement_fixedphase_multi) {
345     // only dynamic quality
346     static const enum android::AudioResampler::src_quality kQualityArray[] = {
347             android::AudioResampler::DYN_LOW_QUALITY,
348             android::AudioResampler::DYN_MED_QUALITY,
349             android::AudioResampler::DYN_HIGH_QUALITY,
350     };
351 
352     for (size_t i = 0; i < ARRAY_SIZE(kQualityArray); ++i) {
353         testBufferIncrement(4, false, 48000, 32000, kQualityArray[i]);
354     }
355 }
356 
TEST(audioflinger_resampler,bufferincrement_interpolatedphase_multi_float)357 TEST(audioflinger_resampler, bufferincrement_interpolatedphase_multi_float) {
358     // only dynamic quality
359     static const enum android::AudioResampler::src_quality kQualityArray[] = {
360             android::AudioResampler::DYN_LOW_QUALITY,
361             android::AudioResampler::DYN_MED_QUALITY,
362             android::AudioResampler::DYN_HIGH_QUALITY,
363     };
364 
365     for (size_t i = 0; i < ARRAY_SIZE(kQualityArray); ++i) {
366         testBufferIncrement(8, true, 22050, 48000, kQualityArray[i]);
367     }
368 }
369 
370 /* Simple aliasing test
371  *
372  * This checks stopband response of the chirp signal to make sure frequencies
373  * are properly suppressed.  It uses downsampling because the stopband can be
374  * clearly isolated by input frequencies exceeding the output sample rate (nyquist).
375  */
TEST(audioflinger_resampler,stopbandresponse_integer)376 TEST(audioflinger_resampler, stopbandresponse_integer) {
377     // not all of these may work (old resamplers fail on downsampling)
378     static const enum android::AudioResampler::src_quality kQualityArray[] = {
379             //android::AudioResampler::LOW_QUALITY,
380             //android::AudioResampler::MED_QUALITY,
381             //android::AudioResampler::HIGH_QUALITY,
382             //android::AudioResampler::VERY_HIGH_QUALITY,
383             android::AudioResampler::DYN_LOW_QUALITY,
384             android::AudioResampler::DYN_MED_QUALITY,
385             android::AudioResampler::DYN_HIGH_QUALITY,
386     };
387 
388     // in this test we assume a maximum transition band between 12kHz and 20kHz.
389     // there must be at least 60dB relative attenuation between stopband and passband.
390     for (size_t i = 0; i < ARRAY_SIZE(kQualityArray); ++i) {
391         testStopbandDownconversion<int16_t, int32_t>(
392                 2, 48000, 32000, 12000, 20000, kQualityArray[i]);
393     }
394 
395     // in this test we assume a maximum transition band between 7kHz and 15kHz.
396     // there must be at least 60dB relative attenuation between stopband and passband.
397     // (the weird ratio triggers interpolative resampling)
398     for (size_t i = 0; i < ARRAY_SIZE(kQualityArray); ++i) {
399         testStopbandDownconversion<int16_t, int32_t>(
400                 2, 48000, 22101, 7000, 15000, kQualityArray[i]);
401     }
402 }
403 
TEST(audioflinger_resampler,stopbandresponse_integer_mono)404 TEST(audioflinger_resampler, stopbandresponse_integer_mono) {
405     // not all of these may work (old resamplers fail on downsampling)
406     static const enum android::AudioResampler::src_quality kQualityArray[] = {
407             //android::AudioResampler::LOW_QUALITY,
408             //android::AudioResampler::MED_QUALITY,
409             //android::AudioResampler::HIGH_QUALITY,
410             //android::AudioResampler::VERY_HIGH_QUALITY,
411             android::AudioResampler::DYN_LOW_QUALITY,
412             android::AudioResampler::DYN_MED_QUALITY,
413             android::AudioResampler::DYN_HIGH_QUALITY,
414     };
415 
416     // in this test we assume a maximum transition band between 12kHz and 20kHz.
417     // there must be at least 60dB relative attenuation between stopband and passband.
418     for (size_t i = 0; i < ARRAY_SIZE(kQualityArray); ++i) {
419         testStopbandDownconversion<int16_t, int32_t>(
420                 1, 48000, 32000, 12000, 20000, kQualityArray[i]);
421     }
422 
423     // in this test we assume a maximum transition band between 7kHz and 15kHz.
424     // there must be at least 60dB relative attenuation between stopband and passband.
425     // (the weird ratio triggers interpolative resampling)
426     for (size_t i = 0; i < ARRAY_SIZE(kQualityArray); ++i) {
427         testStopbandDownconversion<int16_t, int32_t>(
428                 1, 48000, 22101, 7000, 15000, kQualityArray[i]);
429     }
430 }
431 
TEST(audioflinger_resampler,stopbandresponse_integer_multichannel)432 TEST(audioflinger_resampler, stopbandresponse_integer_multichannel) {
433     // not all of these may work (old resamplers fail on downsampling)
434     static const enum android::AudioResampler::src_quality kQualityArray[] = {
435             //android::AudioResampler::LOW_QUALITY,
436             //android::AudioResampler::MED_QUALITY,
437             //android::AudioResampler::HIGH_QUALITY,
438             //android::AudioResampler::VERY_HIGH_QUALITY,
439             android::AudioResampler::DYN_LOW_QUALITY,
440             android::AudioResampler::DYN_MED_QUALITY,
441             android::AudioResampler::DYN_HIGH_QUALITY,
442     };
443 
444     // in this test we assume a maximum transition band between 12kHz and 20kHz.
445     // there must be at least 60dB relative attenuation between stopband and passband.
446     for (size_t i = 0; i < ARRAY_SIZE(kQualityArray); ++i) {
447         testStopbandDownconversion<int16_t, int32_t>(
448                 8, 48000, 32000, 12000, 20000, kQualityArray[i]);
449     }
450 
451     // in this test we assume a maximum transition band between 7kHz and 15kHz.
452     // there must be at least 60dB relative attenuation between stopband and passband.
453     // (the weird ratio triggers interpolative resampling)
454     for (size_t i = 0; i < ARRAY_SIZE(kQualityArray); ++i) {
455         testStopbandDownconversion<int16_t, int32_t>(
456                 8, 48000, 22101, 7000, 15000, kQualityArray[i]);
457     }
458 }
459 
TEST(audioflinger_resampler,stopbandresponse_float)460 TEST(audioflinger_resampler, stopbandresponse_float) {
461     // not all of these may work (old resamplers fail on downsampling)
462     static const enum android::AudioResampler::src_quality kQualityArray[] = {
463             //android::AudioResampler::LOW_QUALITY,
464             //android::AudioResampler::MED_QUALITY,
465             //android::AudioResampler::HIGH_QUALITY,
466             //android::AudioResampler::VERY_HIGH_QUALITY,
467             android::AudioResampler::DYN_LOW_QUALITY,
468             android::AudioResampler::DYN_MED_QUALITY,
469             android::AudioResampler::DYN_HIGH_QUALITY,
470     };
471 
472     // in this test we assume a maximum transition band between 12kHz and 20kHz.
473     // there must be at least 60dB relative attenuation between stopband and passband.
474     for (size_t i = 0; i < ARRAY_SIZE(kQualityArray); ++i) {
475         testStopbandDownconversion<float, float>(
476                 2, 48000, 32000, 12000, 20000, kQualityArray[i]);
477     }
478 
479     // in this test we assume a maximum transition band between 7kHz and 15kHz.
480     // there must be at least 60dB relative attenuation between stopband and passband.
481     // (the weird ratio triggers interpolative resampling)
482     for (size_t i = 0; i < ARRAY_SIZE(kQualityArray); ++i) {
483         testStopbandDownconversion<float, float>(
484                 2, 48000, 22101, 7000, 15000, kQualityArray[i]);
485     }
486 }
487 
TEST(audioflinger_resampler,stopbandresponse_float_mono)488 TEST(audioflinger_resampler, stopbandresponse_float_mono) {
489     // not all of these may work (old resamplers fail on downsampling)
490     static const enum android::AudioResampler::src_quality kQualityArray[] = {
491             //android::AudioResampler::LOW_QUALITY,
492             //android::AudioResampler::MED_QUALITY,
493             //android::AudioResampler::HIGH_QUALITY,
494             //android::AudioResampler::VERY_HIGH_QUALITY,
495             android::AudioResampler::DYN_LOW_QUALITY,
496             android::AudioResampler::DYN_MED_QUALITY,
497             android::AudioResampler::DYN_HIGH_QUALITY,
498     };
499 
500     // in this test we assume a maximum transition band between 12kHz and 20kHz.
501     // there must be at least 60dB relative attenuation between stopband and passband.
502     for (size_t i = 0; i < ARRAY_SIZE(kQualityArray); ++i) {
503         testStopbandDownconversion<float, float>(
504                 1, 48000, 32000, 12000, 20000, kQualityArray[i]);
505     }
506 
507     // in this test we assume a maximum transition band between 7kHz and 15kHz.
508     // there must be at least 60dB relative attenuation between stopband and passband.
509     // (the weird ratio triggers interpolative resampling)
510     for (size_t i = 0; i < ARRAY_SIZE(kQualityArray); ++i) {
511         testStopbandDownconversion<float, float>(
512                 1, 48000, 22101, 7000, 15000, kQualityArray[i]);
513     }
514 }
515 
TEST(audioflinger_resampler,stopbandresponse_float_multichannel)516 TEST(audioflinger_resampler, stopbandresponse_float_multichannel) {
517     // not all of these may work (old resamplers fail on downsampling)
518     static const enum android::AudioResampler::src_quality kQualityArray[] = {
519             //android::AudioResampler::LOW_QUALITY,
520             //android::AudioResampler::MED_QUALITY,
521             //android::AudioResampler::HIGH_QUALITY,
522             //android::AudioResampler::VERY_HIGH_QUALITY,
523             android::AudioResampler::DYN_LOW_QUALITY,
524             android::AudioResampler::DYN_MED_QUALITY,
525             android::AudioResampler::DYN_HIGH_QUALITY,
526     };
527 
528     // in this test we assume a maximum transition band between 12kHz and 20kHz.
529     // there must be at least 60dB relative attenuation between stopband and passband.
530     for (size_t i = 0; i < ARRAY_SIZE(kQualityArray); ++i) {
531         testStopbandDownconversion<float, float>(
532                 8, 48000, 32000, 12000, 20000, kQualityArray[i]);
533     }
534 
535     // in this test we assume a maximum transition band between 7kHz and 15kHz.
536     // there must be at least 60dB relative attenuation between stopband and passband.
537     // (the weird ratio triggers interpolative resampling)
538     for (size_t i = 0; i < ARRAY_SIZE(kQualityArray); ++i) {
539         testStopbandDownconversion<float, float>(
540                 8, 48000, 22101, 7000, 15000, kQualityArray[i]);
541     }
542 }
543 
TEST(audioflinger_resampler,filterresponse)544 TEST(audioflinger_resampler, filterresponse) {
545     std::vector<int> inSampleRates{
546         8000,
547         11025,
548         12000,
549         16000,
550         22050,
551         24000,
552         32000,
553         44100,
554         48000,
555         88200,
556         96000,
557         176400,
558         192000,
559     };
560     std::vector<int> outSampleRates{
561         48000,
562         96000,
563     };
564 
565     for (int outSampleRate : outSampleRates) {
566         for (int inSampleRate : inSampleRates) {
567             testFilterResponse(2 /* channels */, inSampleRate, outSampleRate);
568         }
569     }
570 }
571