• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <utility>
33 #include <vector>
34 
35 #include <gtest/gtest.h>
36 #include <log/log.h>
37 #include <media/AudioBufferProvider.h>
38 
39 #include <media/AudioResampler.h>
40 #include "test_utils.h"
41 
42 template <typename T>
printData(T * data,size_t size)43 static void printData(T *data, size_t size) {
44     const size_t stride = 8;
45     for (size_t i = 0; i < size; ) {
46         for (size_t j = 0; j < stride && i < size; ++j) {
47             std::cout << data[i++] << ' ';  // extra space before newline
48         }
49         std::cout << '\n'; // or endl
50     }
51 }
52 
resample(int channels,void * output,size_t outputFrames,const std::vector<size_t> & outputIncr,android::AudioBufferProvider * provider,android::AudioResampler * resampler)53 void resample(int channels, void *output,
54         size_t outputFrames, const std::vector<size_t> &outputIncr,
55         android::AudioBufferProvider *provider, android::AudioResampler *resampler)
56 {
57     for (size_t i = 0, j = 0; i < outputFrames; ) {
58         size_t thisFrames = outputIncr[j++];
59         if (j >= outputIncr.size()) {
60             j = 0;
61         }
62         if (thisFrames == 0 || thisFrames > outputFrames - i) {
63             thisFrames = outputFrames - i;
64         }
65         size_t framesResampled = resampler->resample(
66                 (int32_t*) output + channels*i, thisFrames, provider);
67         // we should have enough buffer space, so there is no short count.
68         ASSERT_EQ(thisFrames, framesResampled);
69         i += thisFrames;
70     }
71 }
72 
buffercmp(const void * reference,const void * test,size_t outputFrameSize,size_t outputFrames)73 void buffercmp(const void *reference, const void *test,
74         size_t outputFrameSize, size_t outputFrames)
75 {
76     for (size_t i = 0; i < outputFrames; ++i) {
77         int check = memcmp((const char*)reference + i * outputFrameSize,
78                 (const char*)test + i * outputFrameSize, outputFrameSize);
79         if (check) {
80             ALOGE("Failure at frame %zu", i);
81             ASSERT_EQ(check, 0); /* fails */
82         }
83     }
84 }
85 
testBufferIncrement(size_t channels,bool useFloat,unsigned inputFreq,unsigned outputFreq,enum android::AudioResampler::src_quality quality)86 void testBufferIncrement(size_t channels, bool useFloat,
87         unsigned inputFreq, unsigned outputFreq,
88         enum android::AudioResampler::src_quality quality)
89 {
90     const audio_format_t format = useFloat ? AUDIO_FORMAT_PCM_FLOAT : AUDIO_FORMAT_PCM_16_BIT;
91     // create the provider
92     std::vector<int> inputIncr;
93     SignalProvider provider;
94     if (useFloat) {
95         provider.setChirp<float>(channels,
96                 0., outputFreq/2., outputFreq, outputFreq/2000.);
97     } else {
98         provider.setChirp<int16_t>(channels,
99                 0., outputFreq/2., outputFreq, outputFreq/2000.);
100     }
101     provider.setIncr(inputIncr);
102 
103     // calculate the output size
104     size_t outputFrames = ((int64_t) provider.getNumFrames() * outputFreq) / inputFreq;
105     size_t outputFrameSize = (channels == 1 ? 2 : channels) * (useFloat ? sizeof(float) : sizeof(int32_t));
106     size_t outputSize = outputFrameSize * outputFrames;
107     outputSize &= ~7;
108 
109     // create the resampler
110     android::AudioResampler* resampler;
111 
112     resampler = android::AudioResampler::create(format, channels, outputFreq, quality);
113     resampler->setSampleRate(inputFreq);
114     resampler->setVolume(android::AudioResampler::UNITY_GAIN_FLOAT,
115             android::AudioResampler::UNITY_GAIN_FLOAT);
116 
117     // set up the reference run
118     std::vector<size_t> refIncr;
119     refIncr.push_back(outputFrames);
120     void* reference = calloc(outputFrames, outputFrameSize);
121     resample(channels, reference, outputFrames, refIncr, &provider, resampler);
122 
123     provider.reset();
124 
125 #if 0
126     /* this test will fail - API interface issue: reset() does not clear internal buffers */
127     resampler->reset();
128 #else
129     delete resampler;
130     resampler = android::AudioResampler::create(format, channels, outputFreq, quality);
131     resampler->setSampleRate(inputFreq);
132     resampler->setVolume(android::AudioResampler::UNITY_GAIN_FLOAT,
133             android::AudioResampler::UNITY_GAIN_FLOAT);
134 #endif
135 
136     // set up the test run
137     std::vector<size_t> outIncr;
138     outIncr.push_back(1);
139     outIncr.push_back(2);
140     outIncr.push_back(3);
141     void* test = calloc(outputFrames, outputFrameSize);
142     inputIncr.push_back(1);
143     inputIncr.push_back(3);
144     provider.setIncr(inputIncr);
145     resample(channels, test, outputFrames, outIncr, &provider, resampler);
146 
147     // check
148     buffercmp(reference, test, outputFrameSize, outputFrames);
149 
150     free(reference);
151     free(test);
152     delete resampler;
153 }
154 
155 template <typename T>
sqr(T v)156 inline double sqr(T v)
157 {
158     double dv = static_cast<double>(v);
159     return dv * dv;
160 }
161 
162 template <typename T>
signalEnergy(T * start,T * end,unsigned stride)163 double signalEnergy(T *start, T *end, unsigned stride)
164 {
165     double accum = 0;
166 
167     for (T *p = start; p < end; p += stride) {
168         accum += sqr(*p);
169     }
170     unsigned count = (end - start + stride - 1) / stride;
171     return accum / count;
172 }
173 
174 // TI = resampler input type, int16_t or float
175 // TO = resampler output type, int32_t or float
176 template <typename TI, typename TO>
testStopbandDownconversion(size_t channels,unsigned inputFreq,unsigned outputFreq,unsigned passband,unsigned stopband,enum android::AudioResampler::src_quality quality)177 void testStopbandDownconversion(size_t channels,
178         unsigned inputFreq, unsigned outputFreq,
179         unsigned passband, unsigned stopband,
180         enum android::AudioResampler::src_quality quality)
181 {
182     // create the provider
183     std::vector<int> inputIncr;
184     SignalProvider provider;
185     provider.setChirp<TI>(channels,
186             0., inputFreq/2., inputFreq, inputFreq/2000.);
187     provider.setIncr(inputIncr);
188 
189     // calculate the output size
190     size_t outputFrames = ((int64_t) provider.getNumFrames() * outputFreq) / inputFreq;
191     size_t outputFrameSize = (channels == 1 ? 2 : channels) * sizeof(TO);
192     size_t outputSize = outputFrameSize * outputFrames;
193     outputSize &= ~7;
194 
195     // create the resampler
196     android::AudioResampler* resampler;
197 
198     resampler = android::AudioResampler::create(
199             is_same<TI, int16_t>::value ? AUDIO_FORMAT_PCM_16_BIT : AUDIO_FORMAT_PCM_FLOAT,
200             channels, outputFreq, quality);
201     resampler->setSampleRate(inputFreq);
202     resampler->setVolume(android::AudioResampler::UNITY_GAIN_FLOAT,
203             android::AudioResampler::UNITY_GAIN_FLOAT);
204 
205     // set up the reference run
206     std::vector<size_t> refIncr;
207     refIncr.push_back(outputFrames);
208     void* reference = calloc(outputFrames, outputFrameSize);
209     resample(channels, reference, outputFrames, refIncr, &provider, resampler);
210 
211     TO *out = reinterpret_cast<TO *>(reference);
212 
213     // check signal energy in passband
214     const unsigned passbandFrame = passband * outputFreq / 1000.;
215     const unsigned stopbandFrame = stopband * outputFreq / 1000.;
216 
217     // check each channel separately
218     if (channels == 1) channels = 2; // workaround (mono duplicates output channel)
219 
220     for (size_t i = 0; i < channels; ++i) {
221         double passbandEnergy = signalEnergy(out, out + passbandFrame * channels, channels);
222         double stopbandEnergy = signalEnergy(out + stopbandFrame * channels,
223                 out + outputFrames * channels, channels);
224         double dbAtten = -10. * log10(stopbandEnergy / passbandEnergy);
225         ASSERT_GT(dbAtten, 60.);
226 
227 #if 0
228         // internal verification
229         printf("if:%d  of:%d  pbf:%d  sbf:%d  sbe: %f  pbe: %f  db: %.2f\n",
230                 provider.getNumFrames(), outputFrames,
231                 passbandFrame, stopbandFrame, stopbandEnergy, passbandEnergy, dbAtten);
232         for (size_t i = 0; i < 10; ++i) {
233             std::cout << out[i+passbandFrame*channels] << std::endl;
234         }
235         for (size_t i = 0; i < 10; ++i) {
236             std::cout << out[i+stopbandFrame*channels] << std::endl;
237         }
238 #endif
239     }
240 
241     free(reference);
242     delete resampler;
243 }
244 
245 /* Buffer increment test
246  *
247  * We compare a reference output, where we consume and process the entire
248  * buffer at a time, and a test output, where we provide small chunks of input
249  * data and process small chunks of output (which may not be equivalent in size).
250  *
251  * Two subtests - fixed phase (3:2 down) and interpolated phase (147:320 up)
252  */
TEST(audioflinger_resampler,bufferincrement_fixedphase)253 TEST(audioflinger_resampler, bufferincrement_fixedphase) {
254     // all of these work
255     static const enum android::AudioResampler::src_quality kQualityArray[] = {
256             android::AudioResampler::LOW_QUALITY,
257             android::AudioResampler::MED_QUALITY,
258             android::AudioResampler::HIGH_QUALITY,
259             android::AudioResampler::VERY_HIGH_QUALITY,
260             android::AudioResampler::DYN_LOW_QUALITY,
261             android::AudioResampler::DYN_MED_QUALITY,
262             android::AudioResampler::DYN_HIGH_QUALITY,
263     };
264 
265     for (size_t i = 0; i < ARRAY_SIZE(kQualityArray); ++i) {
266         testBufferIncrement(2, false, 48000, 32000, kQualityArray[i]);
267     }
268 }
269 
TEST(audioflinger_resampler,bufferincrement_interpolatedphase)270 TEST(audioflinger_resampler, bufferincrement_interpolatedphase) {
271     // all of these work except low quality
272     static const enum android::AudioResampler::src_quality kQualityArray[] = {
273 //           android::AudioResampler::LOW_QUALITY,
274             android::AudioResampler::MED_QUALITY,
275             android::AudioResampler::HIGH_QUALITY,
276             android::AudioResampler::VERY_HIGH_QUALITY,
277             android::AudioResampler::DYN_LOW_QUALITY,
278             android::AudioResampler::DYN_MED_QUALITY,
279             android::AudioResampler::DYN_HIGH_QUALITY,
280     };
281 
282     for (size_t i = 0; i < ARRAY_SIZE(kQualityArray); ++i) {
283         testBufferIncrement(2, false, 22050, 48000, kQualityArray[i]);
284     }
285 }
286 
TEST(audioflinger_resampler,bufferincrement_fixedphase_multi)287 TEST(audioflinger_resampler, bufferincrement_fixedphase_multi) {
288     // only dynamic quality
289     static const enum android::AudioResampler::src_quality kQualityArray[] = {
290             android::AudioResampler::DYN_LOW_QUALITY,
291             android::AudioResampler::DYN_MED_QUALITY,
292             android::AudioResampler::DYN_HIGH_QUALITY,
293     };
294 
295     for (size_t i = 0; i < ARRAY_SIZE(kQualityArray); ++i) {
296         testBufferIncrement(4, false, 48000, 32000, kQualityArray[i]);
297     }
298 }
299 
TEST(audioflinger_resampler,bufferincrement_interpolatedphase_multi_float)300 TEST(audioflinger_resampler, bufferincrement_interpolatedphase_multi_float) {
301     // only dynamic quality
302     static const enum android::AudioResampler::src_quality kQualityArray[] = {
303             android::AudioResampler::DYN_LOW_QUALITY,
304             android::AudioResampler::DYN_MED_QUALITY,
305             android::AudioResampler::DYN_HIGH_QUALITY,
306     };
307 
308     for (size_t i = 0; i < ARRAY_SIZE(kQualityArray); ++i) {
309         testBufferIncrement(8, true, 22050, 48000, kQualityArray[i]);
310     }
311 }
312 
313 /* Simple aliasing test
314  *
315  * This checks stopband response of the chirp signal to make sure frequencies
316  * are properly suppressed.  It uses downsampling because the stopband can be
317  * clearly isolated by input frequencies exceeding the output sample rate (nyquist).
318  */
TEST(audioflinger_resampler,stopbandresponse_integer)319 TEST(audioflinger_resampler, stopbandresponse_integer) {
320     // not all of these may work (old resamplers fail on downsampling)
321     static const enum android::AudioResampler::src_quality kQualityArray[] = {
322             //android::AudioResampler::LOW_QUALITY,
323             //android::AudioResampler::MED_QUALITY,
324             //android::AudioResampler::HIGH_QUALITY,
325             //android::AudioResampler::VERY_HIGH_QUALITY,
326             android::AudioResampler::DYN_LOW_QUALITY,
327             android::AudioResampler::DYN_MED_QUALITY,
328             android::AudioResampler::DYN_HIGH_QUALITY,
329     };
330 
331     // in this test we assume a maximum transition band between 12kHz and 20kHz.
332     // there must be at least 60dB relative attenuation between stopband and passband.
333     for (size_t i = 0; i < ARRAY_SIZE(kQualityArray); ++i) {
334         testStopbandDownconversion<int16_t, int32_t>(
335                 2, 48000, 32000, 12000, 20000, kQualityArray[i]);
336     }
337 
338     // in this test we assume a maximum transition band between 7kHz and 15kHz.
339     // there must be at least 60dB relative attenuation between stopband and passband.
340     // (the weird ratio triggers interpolative resampling)
341     for (size_t i = 0; i < ARRAY_SIZE(kQualityArray); ++i) {
342         testStopbandDownconversion<int16_t, int32_t>(
343                 2, 48000, 22101, 7000, 15000, kQualityArray[i]);
344     }
345 }
346 
TEST(audioflinger_resampler,stopbandresponse_integer_mono)347 TEST(audioflinger_resampler, stopbandresponse_integer_mono) {
348     // not all of these may work (old resamplers fail on downsampling)
349     static const enum android::AudioResampler::src_quality kQualityArray[] = {
350             //android::AudioResampler::LOW_QUALITY,
351             //android::AudioResampler::MED_QUALITY,
352             //android::AudioResampler::HIGH_QUALITY,
353             //android::AudioResampler::VERY_HIGH_QUALITY,
354             android::AudioResampler::DYN_LOW_QUALITY,
355             android::AudioResampler::DYN_MED_QUALITY,
356             android::AudioResampler::DYN_HIGH_QUALITY,
357     };
358 
359     // in this test we assume a maximum transition band between 12kHz and 20kHz.
360     // there must be at least 60dB relative attenuation between stopband and passband.
361     for (size_t i = 0; i < ARRAY_SIZE(kQualityArray); ++i) {
362         testStopbandDownconversion<int16_t, int32_t>(
363                 1, 48000, 32000, 12000, 20000, kQualityArray[i]);
364     }
365 
366     // in this test we assume a maximum transition band between 7kHz and 15kHz.
367     // there must be at least 60dB relative attenuation between stopband and passband.
368     // (the weird ratio triggers interpolative resampling)
369     for (size_t i = 0; i < ARRAY_SIZE(kQualityArray); ++i) {
370         testStopbandDownconversion<int16_t, int32_t>(
371                 1, 48000, 22101, 7000, 15000, kQualityArray[i]);
372     }
373 }
374 
TEST(audioflinger_resampler,stopbandresponse_integer_multichannel)375 TEST(audioflinger_resampler, stopbandresponse_integer_multichannel) {
376     // not all of these may work (old resamplers fail on downsampling)
377     static const enum android::AudioResampler::src_quality kQualityArray[] = {
378             //android::AudioResampler::LOW_QUALITY,
379             //android::AudioResampler::MED_QUALITY,
380             //android::AudioResampler::HIGH_QUALITY,
381             //android::AudioResampler::VERY_HIGH_QUALITY,
382             android::AudioResampler::DYN_LOW_QUALITY,
383             android::AudioResampler::DYN_MED_QUALITY,
384             android::AudioResampler::DYN_HIGH_QUALITY,
385     };
386 
387     // in this test we assume a maximum transition band between 12kHz and 20kHz.
388     // there must be at least 60dB relative attenuation between stopband and passband.
389     for (size_t i = 0; i < ARRAY_SIZE(kQualityArray); ++i) {
390         testStopbandDownconversion<int16_t, int32_t>(
391                 8, 48000, 32000, 12000, 20000, kQualityArray[i]);
392     }
393 
394     // in this test we assume a maximum transition band between 7kHz and 15kHz.
395     // there must be at least 60dB relative attenuation between stopband and passband.
396     // (the weird ratio triggers interpolative resampling)
397     for (size_t i = 0; i < ARRAY_SIZE(kQualityArray); ++i) {
398         testStopbandDownconversion<int16_t, int32_t>(
399                 8, 48000, 22101, 7000, 15000, kQualityArray[i]);
400     }
401 }
402 
TEST(audioflinger_resampler,stopbandresponse_float)403 TEST(audioflinger_resampler, stopbandresponse_float) {
404     // not all of these may work (old resamplers fail on downsampling)
405     static const enum android::AudioResampler::src_quality kQualityArray[] = {
406             //android::AudioResampler::LOW_QUALITY,
407             //android::AudioResampler::MED_QUALITY,
408             //android::AudioResampler::HIGH_QUALITY,
409             //android::AudioResampler::VERY_HIGH_QUALITY,
410             android::AudioResampler::DYN_LOW_QUALITY,
411             android::AudioResampler::DYN_MED_QUALITY,
412             android::AudioResampler::DYN_HIGH_QUALITY,
413     };
414 
415     // in this test we assume a maximum transition band between 12kHz and 20kHz.
416     // there must be at least 60dB relative attenuation between stopband and passband.
417     for (size_t i = 0; i < ARRAY_SIZE(kQualityArray); ++i) {
418         testStopbandDownconversion<float, float>(
419                 2, 48000, 32000, 12000, 20000, kQualityArray[i]);
420     }
421 
422     // in this test we assume a maximum transition band between 7kHz and 15kHz.
423     // there must be at least 60dB relative attenuation between stopband and passband.
424     // (the weird ratio triggers interpolative resampling)
425     for (size_t i = 0; i < ARRAY_SIZE(kQualityArray); ++i) {
426         testStopbandDownconversion<float, float>(
427                 2, 48000, 22101, 7000, 15000, kQualityArray[i]);
428     }
429 }
430 
TEST(audioflinger_resampler,stopbandresponse_float_mono)431 TEST(audioflinger_resampler, stopbandresponse_float_mono) {
432     // not all of these may work (old resamplers fail on downsampling)
433     static const enum android::AudioResampler::src_quality kQualityArray[] = {
434             //android::AudioResampler::LOW_QUALITY,
435             //android::AudioResampler::MED_QUALITY,
436             //android::AudioResampler::HIGH_QUALITY,
437             //android::AudioResampler::VERY_HIGH_QUALITY,
438             android::AudioResampler::DYN_LOW_QUALITY,
439             android::AudioResampler::DYN_MED_QUALITY,
440             android::AudioResampler::DYN_HIGH_QUALITY,
441     };
442 
443     // in this test we assume a maximum transition band between 12kHz and 20kHz.
444     // there must be at least 60dB relative attenuation between stopband and passband.
445     for (size_t i = 0; i < ARRAY_SIZE(kQualityArray); ++i) {
446         testStopbandDownconversion<float, float>(
447                 1, 48000, 32000, 12000, 20000, kQualityArray[i]);
448     }
449 
450     // in this test we assume a maximum transition band between 7kHz and 15kHz.
451     // there must be at least 60dB relative attenuation between stopband and passband.
452     // (the weird ratio triggers interpolative resampling)
453     for (size_t i = 0; i < ARRAY_SIZE(kQualityArray); ++i) {
454         testStopbandDownconversion<float, float>(
455                 1, 48000, 22101, 7000, 15000, kQualityArray[i]);
456     }
457 }
458 
TEST(audioflinger_resampler,stopbandresponse_float_multichannel)459 TEST(audioflinger_resampler, stopbandresponse_float_multichannel) {
460     // not all of these may work (old resamplers fail on downsampling)
461     static const enum android::AudioResampler::src_quality kQualityArray[] = {
462             //android::AudioResampler::LOW_QUALITY,
463             //android::AudioResampler::MED_QUALITY,
464             //android::AudioResampler::HIGH_QUALITY,
465             //android::AudioResampler::VERY_HIGH_QUALITY,
466             android::AudioResampler::DYN_LOW_QUALITY,
467             android::AudioResampler::DYN_MED_QUALITY,
468             android::AudioResampler::DYN_HIGH_QUALITY,
469     };
470 
471     // in this test we assume a maximum transition band between 12kHz and 20kHz.
472     // there must be at least 60dB relative attenuation between stopband and passband.
473     for (size_t i = 0; i < ARRAY_SIZE(kQualityArray); ++i) {
474         testStopbandDownconversion<float, float>(
475                 8, 48000, 32000, 12000, 20000, kQualityArray[i]);
476     }
477 
478     // in this test we assume a maximum transition band between 7kHz and 15kHz.
479     // there must be at least 60dB relative attenuation between stopband and passband.
480     // (the weird ratio triggers interpolative resampling)
481     for (size_t i = 0; i < ARRAY_SIZE(kQualityArray); ++i) {
482         testStopbandDownconversion<float, float>(
483                 8, 48000, 22101, 7000, 15000, kQualityArray[i]);
484     }
485 }
486 
487