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,android::AudioResampler::src_quality quality=android::AudioResampler::DYN_HIGH_QUALITY)248 void testFilterResponse(
249         size_t channels, unsigned inputFreq, unsigned outputFreq,
250         android::AudioResampler::src_quality quality = android::AudioResampler::DYN_HIGH_QUALITY)
251 {
252     // create resampler
253     using ResamplerType = android::AudioResamplerDyn<float, float, float>;
254     std::unique_ptr<ResamplerType> rdyn(
255             static_cast<ResamplerType *>(
256                     android::AudioResampler::create(
257                             AUDIO_FORMAT_PCM_FLOAT,
258                             channels,
259                             outputFreq,
260                             quality)));
261     rdyn->setSampleRate(inputFreq);
262 
263     // get design parameters
264     const int phases = rdyn->getPhases();
265     const int halfLength = rdyn->getHalfLength();
266     const float *coefs = rdyn->getFilterCoefs();
267     const double fcr = rdyn->getNormalizedCutoffFrequency();
268     const double tbw = rdyn->getNormalizedTransitionBandwidth();
269     const double attenuation = rdyn->getFilterAttenuation();
270     const double stopbandDb = rdyn->getStopbandAttenuationDb();
271     const double passbandDb = rdyn->getPassbandRippleDb();
272     const double fp = fcr - tbw * 0.5;
273     const double fs = fcr + tbw * 0.5;
274     const double idealfs = inputFreq <= outputFreq
275         ? 0.5                            // upsample
276         : 0.5 * outputFreq  / inputFreq; // downsample
277 
278     printf("inputFreq:%d outputFreq:%d design quality %d"
279             " phases:%d halfLength:%d"
280             " fcr:%lf fp:%lf fs:%lf tbw:%lf fcrp:%lf"
281             " attenuation:%lf stopRipple:%.lf passRipple:%lf"
282             "\n",
283             inputFreq, outputFreq, quality,
284             phases, halfLength,
285             fcr, fp, fs, tbw, fcr * 100. / idealfs,
286             attenuation, stopbandDb, passbandDb);
287 
288     // verify design parameters
289     constexpr int32_t passSteps = 1000;
290     double passMin, passMax, passRipple, stopMax, stopRipple;
291     android::testFir(coefs, phases, halfLength, fp / phases, fs / phases,
292             passSteps, phases * passSteps /* stopSteps */,
293             passMin, passMax, passRipple,
294             stopMax, stopRipple);
295     printf("inputFreq:%d outputFreq:%d verify"
296             " passMin:%lf passMax:%lf passRipple:%lf stopMax:%lf stopRipple:%lf"
297             "\n",
298             inputFreq, outputFreq,
299             passMin, passMax, passRipple, stopMax, stopRipple);
300 
301     ASSERT_GT(stopRipple, 60.);  // enough stopband attenuation
302     ASSERT_LT(passRipple, 0.2);  // small passband ripple
303     ASSERT_GT(passMin, 0.99);    // we do not attenuate the signal (ideally 1.)
304 }
305 
306 /* Buffer increment test
307  *
308  * We compare a reference output, where we consume and process the entire
309  * buffer at a time, and a test output, where we provide small chunks of input
310  * data and process small chunks of output (which may not be equivalent in size).
311  *
312  * Two subtests - fixed phase (3:2 down) and interpolated phase (147:320 up)
313  */
TEST(audioflinger_resampler,bufferincrement_fixedphase)314 TEST(audioflinger_resampler, bufferincrement_fixedphase) {
315     // all of these work
316     static const enum android::AudioResampler::src_quality kQualityArray[] = {
317             android::AudioResampler::LOW_QUALITY,
318             android::AudioResampler::MED_QUALITY,
319             android::AudioResampler::HIGH_QUALITY,
320             android::AudioResampler::VERY_HIGH_QUALITY,
321             android::AudioResampler::DYN_LOW_QUALITY,
322             android::AudioResampler::DYN_MED_QUALITY,
323             android::AudioResampler::DYN_HIGH_QUALITY,
324     };
325 
326     for (size_t i = 0; i < ARRAY_SIZE(kQualityArray); ++i) {
327         testBufferIncrement(2, false, 48000, 32000, kQualityArray[i]);
328     }
329 }
330 
TEST(audioflinger_resampler,bufferincrement_interpolatedphase)331 TEST(audioflinger_resampler, bufferincrement_interpolatedphase) {
332     // all of these work except low quality
333     static const enum android::AudioResampler::src_quality kQualityArray[] = {
334 //           android::AudioResampler::LOW_QUALITY,
335             android::AudioResampler::MED_QUALITY,
336             android::AudioResampler::HIGH_QUALITY,
337             android::AudioResampler::VERY_HIGH_QUALITY,
338             android::AudioResampler::DYN_LOW_QUALITY,
339             android::AudioResampler::DYN_MED_QUALITY,
340             android::AudioResampler::DYN_HIGH_QUALITY,
341     };
342 
343     for (size_t i = 0; i < ARRAY_SIZE(kQualityArray); ++i) {
344         testBufferIncrement(2, false, 22050, 48000, kQualityArray[i]);
345     }
346 }
347 
TEST(audioflinger_resampler,bufferincrement_fixedphase_multi)348 TEST(audioflinger_resampler, bufferincrement_fixedphase_multi) {
349     // only dynamic quality
350     static const enum android::AudioResampler::src_quality kQualityArray[] = {
351             android::AudioResampler::DYN_LOW_QUALITY,
352             android::AudioResampler::DYN_MED_QUALITY,
353             android::AudioResampler::DYN_HIGH_QUALITY,
354     };
355 
356     for (size_t i = 0; i < ARRAY_SIZE(kQualityArray); ++i) {
357         testBufferIncrement(4, false, 48000, 32000, kQualityArray[i]);
358     }
359 }
360 
TEST(audioflinger_resampler,bufferincrement_interpolatedphase_multi_float)361 TEST(audioflinger_resampler, bufferincrement_interpolatedphase_multi_float) {
362     // only dynamic quality
363     static const enum android::AudioResampler::src_quality kQualityArray[] = {
364             android::AudioResampler::DYN_LOW_QUALITY,
365             android::AudioResampler::DYN_MED_QUALITY,
366             android::AudioResampler::DYN_HIGH_QUALITY,
367     };
368 
369     for (size_t i = 0; i < ARRAY_SIZE(kQualityArray); ++i) {
370         testBufferIncrement(8, true, 22050, 48000, kQualityArray[i]);
371     }
372 }
373 
374 /* Simple aliasing test
375  *
376  * This checks stopband response of the chirp signal to make sure frequencies
377  * are properly suppressed.  It uses downsampling because the stopband can be
378  * clearly isolated by input frequencies exceeding the output sample rate (nyquist).
379  */
TEST(audioflinger_resampler,stopbandresponse_integer)380 TEST(audioflinger_resampler, stopbandresponse_integer) {
381     // not all of these may work (old resamplers fail on downsampling)
382     static const enum android::AudioResampler::src_quality kQualityArray[] = {
383             //android::AudioResampler::LOW_QUALITY,
384             //android::AudioResampler::MED_QUALITY,
385             //android::AudioResampler::HIGH_QUALITY,
386             //android::AudioResampler::VERY_HIGH_QUALITY,
387             android::AudioResampler::DYN_LOW_QUALITY,
388             android::AudioResampler::DYN_MED_QUALITY,
389             android::AudioResampler::DYN_HIGH_QUALITY,
390     };
391 
392     // in this test we assume a maximum transition band between 12kHz and 20kHz.
393     // there must be at least 60dB relative attenuation between stopband and passband.
394     for (size_t i = 0; i < ARRAY_SIZE(kQualityArray); ++i) {
395         testStopbandDownconversion<int16_t, int32_t>(
396                 2, 48000, 32000, 12000, 20000, kQualityArray[i]);
397     }
398 
399     // in this test we assume a maximum transition band between 7kHz and 15kHz.
400     // there must be at least 60dB relative attenuation between stopband and passband.
401     // (the weird ratio triggers interpolative resampling)
402     for (size_t i = 0; i < ARRAY_SIZE(kQualityArray); ++i) {
403         testStopbandDownconversion<int16_t, int32_t>(
404                 2, 48000, 22101, 7000, 15000, kQualityArray[i]);
405     }
406 }
407 
TEST(audioflinger_resampler,stopbandresponse_integer_mono)408 TEST(audioflinger_resampler, stopbandresponse_integer_mono) {
409     // not all of these may work (old resamplers fail on downsampling)
410     static const enum android::AudioResampler::src_quality kQualityArray[] = {
411             //android::AudioResampler::LOW_QUALITY,
412             //android::AudioResampler::MED_QUALITY,
413             //android::AudioResampler::HIGH_QUALITY,
414             //android::AudioResampler::VERY_HIGH_QUALITY,
415             android::AudioResampler::DYN_LOW_QUALITY,
416             android::AudioResampler::DYN_MED_QUALITY,
417             android::AudioResampler::DYN_HIGH_QUALITY,
418     };
419 
420     // in this test we assume a maximum transition band between 12kHz and 20kHz.
421     // there must be at least 60dB relative attenuation between stopband and passband.
422     for (size_t i = 0; i < ARRAY_SIZE(kQualityArray); ++i) {
423         testStopbandDownconversion<int16_t, int32_t>(
424                 1, 48000, 32000, 12000, 20000, kQualityArray[i]);
425     }
426 
427     // in this test we assume a maximum transition band between 7kHz and 15kHz.
428     // there must be at least 60dB relative attenuation between stopband and passband.
429     // (the weird ratio triggers interpolative resampling)
430     for (size_t i = 0; i < ARRAY_SIZE(kQualityArray); ++i) {
431         testStopbandDownconversion<int16_t, int32_t>(
432                 1, 48000, 22101, 7000, 15000, kQualityArray[i]);
433     }
434 }
435 
TEST(audioflinger_resampler,stopbandresponse_integer_multichannel)436 TEST(audioflinger_resampler, stopbandresponse_integer_multichannel) {
437     // not all of these may work (old resamplers fail on downsampling)
438     static const enum android::AudioResampler::src_quality kQualityArray[] = {
439             //android::AudioResampler::LOW_QUALITY,
440             //android::AudioResampler::MED_QUALITY,
441             //android::AudioResampler::HIGH_QUALITY,
442             //android::AudioResampler::VERY_HIGH_QUALITY,
443             android::AudioResampler::DYN_LOW_QUALITY,
444             android::AudioResampler::DYN_MED_QUALITY,
445             android::AudioResampler::DYN_HIGH_QUALITY,
446     };
447 
448     // in this test we assume a maximum transition band between 12kHz and 20kHz.
449     // there must be at least 60dB relative attenuation between stopband and passband.
450     for (size_t i = 0; i < ARRAY_SIZE(kQualityArray); ++i) {
451         testStopbandDownconversion<int16_t, int32_t>(
452                 8, 48000, 32000, 12000, 20000, kQualityArray[i]);
453     }
454 
455     // in this test we assume a maximum transition band between 7kHz and 15kHz.
456     // there must be at least 60dB relative attenuation between stopband and passband.
457     // (the weird ratio triggers interpolative resampling)
458     for (size_t i = 0; i < ARRAY_SIZE(kQualityArray); ++i) {
459         testStopbandDownconversion<int16_t, int32_t>(
460                 8, 48000, 22101, 7000, 15000, kQualityArray[i]);
461     }
462 }
463 
TEST(audioflinger_resampler,stopbandresponse_float)464 TEST(audioflinger_resampler, stopbandresponse_float) {
465     // not all of these may work (old resamplers fail on downsampling)
466     static const enum android::AudioResampler::src_quality kQualityArray[] = {
467             //android::AudioResampler::LOW_QUALITY,
468             //android::AudioResampler::MED_QUALITY,
469             //android::AudioResampler::HIGH_QUALITY,
470             //android::AudioResampler::VERY_HIGH_QUALITY,
471             android::AudioResampler::DYN_LOW_QUALITY,
472             android::AudioResampler::DYN_MED_QUALITY,
473             android::AudioResampler::DYN_HIGH_QUALITY,
474     };
475 
476     // in this test we assume a maximum transition band between 12kHz and 20kHz.
477     // there must be at least 60dB relative attenuation between stopband and passband.
478     for (size_t i = 0; i < ARRAY_SIZE(kQualityArray); ++i) {
479         testStopbandDownconversion<float, float>(
480                 2, 48000, 32000, 12000, 20000, kQualityArray[i]);
481     }
482 
483     // in this test we assume a maximum transition band between 7kHz and 15kHz.
484     // there must be at least 60dB relative attenuation between stopband and passband.
485     // (the weird ratio triggers interpolative resampling)
486     for (size_t i = 0; i < ARRAY_SIZE(kQualityArray); ++i) {
487         testStopbandDownconversion<float, float>(
488                 2, 48000, 22101, 7000, 15000, kQualityArray[i]);
489     }
490 }
491 
TEST(audioflinger_resampler,stopbandresponse_float_mono)492 TEST(audioflinger_resampler, stopbandresponse_float_mono) {
493     // not all of these may work (old resamplers fail on downsampling)
494     static const enum android::AudioResampler::src_quality kQualityArray[] = {
495             //android::AudioResampler::LOW_QUALITY,
496             //android::AudioResampler::MED_QUALITY,
497             //android::AudioResampler::HIGH_QUALITY,
498             //android::AudioResampler::VERY_HIGH_QUALITY,
499             android::AudioResampler::DYN_LOW_QUALITY,
500             android::AudioResampler::DYN_MED_QUALITY,
501             android::AudioResampler::DYN_HIGH_QUALITY,
502     };
503 
504     // in this test we assume a maximum transition band between 12kHz and 20kHz.
505     // there must be at least 60dB relative attenuation between stopband and passband.
506     for (size_t i = 0; i < ARRAY_SIZE(kQualityArray); ++i) {
507         testStopbandDownconversion<float, float>(
508                 1, 48000, 32000, 12000, 20000, kQualityArray[i]);
509     }
510 
511     // in this test we assume a maximum transition band between 7kHz and 15kHz.
512     // there must be at least 60dB relative attenuation between stopband and passband.
513     // (the weird ratio triggers interpolative resampling)
514     for (size_t i = 0; i < ARRAY_SIZE(kQualityArray); ++i) {
515         testStopbandDownconversion<float, float>(
516                 1, 48000, 22101, 7000, 15000, kQualityArray[i]);
517     }
518 }
519 
TEST(audioflinger_resampler,stopbandresponse_float_multichannel)520 TEST(audioflinger_resampler, stopbandresponse_float_multichannel) {
521     // not all of these may work (old resamplers fail on downsampling)
522     static const enum android::AudioResampler::src_quality kQualityArray[] = {
523             //android::AudioResampler::LOW_QUALITY,
524             //android::AudioResampler::MED_QUALITY,
525             //android::AudioResampler::HIGH_QUALITY,
526             //android::AudioResampler::VERY_HIGH_QUALITY,
527             android::AudioResampler::DYN_LOW_QUALITY,
528             android::AudioResampler::DYN_MED_QUALITY,
529             android::AudioResampler::DYN_HIGH_QUALITY,
530     };
531 
532     // in this test we assume a maximum transition band between 12kHz and 20kHz.
533     // there must be at least 60dB relative attenuation between stopband and passband.
534     for (size_t i = 0; i < ARRAY_SIZE(kQualityArray); ++i) {
535         testStopbandDownconversion<float, float>(
536                 8, 48000, 32000, 12000, 20000, kQualityArray[i]);
537     }
538 
539     // in this test we assume a maximum transition band between 7kHz and 15kHz.
540     // there must be at least 60dB relative attenuation between stopband and passband.
541     // (the weird ratio triggers interpolative resampling)
542     for (size_t i = 0; i < ARRAY_SIZE(kQualityArray); ++i) {
543         testStopbandDownconversion<float, float>(
544                 8, 48000, 22101, 7000, 15000, kQualityArray[i]);
545     }
546 }
547 
548 // Selected downsampling responses for various frequencies relating to hearing aid.
TEST(audioflinger_resampler,downsamplingresponse)549 TEST(audioflinger_resampler, downsamplingresponse) {
550     static constexpr android::AudioResampler::src_quality qualities[] = {
551         android::AudioResampler::DYN_LOW_QUALITY,
552         android::AudioResampler::DYN_MED_QUALITY,
553         android::AudioResampler::DYN_HIGH_QUALITY,
554     };
555     static constexpr int inSampleRates[] = {
556         32000,
557         44100,
558         48000,
559     };
560     static constexpr int outSampleRates[] = {
561         16000,
562         24000,
563     };
564 
565     for (auto quality : qualities) {
566         for (int outSampleRate : outSampleRates) {
567             for (int inSampleRate : inSampleRates) {
568                 testFilterResponse(2 /* channels */, inSampleRate, outSampleRate, quality);
569             }
570         }
571     }
572 }
573 
574 // General responses for typical output device scenarios - 44.1, 48, 96 kHz
575 // (48, 96 are part of the same resampler generation family).
TEST(audioflinger_resampler,generalresponse)576 TEST(audioflinger_resampler, generalresponse) {
577     static constexpr int inSampleRates[] = {
578         8000,
579         11025,
580         12000,
581         16000,
582         22050,
583         24000,
584         32000,
585         44100,
586         48000,
587         88200,
588         96000,
589         176400,
590         192000,
591     };
592     static constexpr int outSampleRates[] = {
593         44100,
594         48000,
595         96000,
596     };
597 
598     for (int outSampleRate : outSampleRates) {
599         for (int inSampleRate : inSampleRates) {
600             testFilterResponse(2 /* channels */, inSampleRate, outSampleRate);
601         }
602     }
603 }
604