summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--services/audioflinger/AudioResampler.cpp11
-rw-r--r--services/audioflinger/AudioResamplerDyn.cpp106
-rw-r--r--services/audioflinger/AudioResamplerDyn.h4
-rw-r--r--services/audioflinger/tests/resampler_tests.cpp65
4 files changed, 130 insertions, 56 deletions
diff --git a/services/audioflinger/AudioResampler.cpp b/services/audioflinger/AudioResampler.cpp
index 562c4ea..b8a0357 100644
--- a/services/audioflinger/AudioResampler.cpp
+++ b/services/audioflinger/AudioResampler.cpp
@@ -259,13 +259,14 @@ AudioResampler::AudioResampler(int bitDepth, int inChannelCount,
mPhaseFraction(0), mLocalTimeFreq(0),
mPTS(AudioBufferProvider::kInvalidPTS), mQuality(quality) {
// sanity check on format
- if ((bitDepth != 16) ||(inChannelCount < 1) || (inChannelCount > 2)) {
- ALOGE("Unsupported sample format, %d bits, %d channels", bitDepth,
- inChannelCount);
- // ALOG_ASSERT(0);
+ if ((bitDepth != 16 && (quality < DYN_LOW_QUALITY || bitDepth != 32))
+ || inChannelCount < 1
+ || inChannelCount > (quality < DYN_LOW_QUALITY ? 2 : 8)) {
+ LOG_ALWAYS_FATAL("Unsupported sample format %d quality %d bits, %d channels",
+ quality, bitDepth, inChannelCount);
}
if (sampleRate <= 0) {
- ALOGE("Unsupported sample rate %d Hz", sampleRate);
+ LOG_ALWAYS_FATAL("Unsupported sample rate %d Hz", sampleRate);
}
// initialize common members
diff --git a/services/audioflinger/AudioResamplerDyn.cpp b/services/audioflinger/AudioResamplerDyn.cpp
index 318eb57..7ca10c1 100644
--- a/services/audioflinger/AudioResamplerDyn.cpp
+++ b/services/audioflinger/AudioResamplerDyn.cpp
@@ -38,11 +38,6 @@
namespace android {
-// generate a unique resample type compile-time constant (constexpr)
-#define RESAMPLETYPE(CHANNELS, LOCKED, STRIDE) \
- ((((CHANNELS)-1)&1) | !!(LOCKED)<<1 \
- | ((STRIDE)==8 ? 1 : (STRIDE)==16 ? 2 : 0)<<2)
-
/*
* InBuffer is a type agnostic input buffer.
*
@@ -403,12 +398,76 @@ void AudioResamplerDyn<TC, TI, TO>::setSampleRate(int32_t inSampleRate)
// determine which resampler to use
// check if locked phase (works only if mPhaseIncrement has no "fractional phase bits")
int locked = (mPhaseIncrement << (sizeof(mPhaseIncrement)*8 - c.mShift)) == 0;
- int stride = (c.mHalfNumCoefs&7)==0 ? 16 : (c.mHalfNumCoefs&3)==0 ? 8 : 2;
if (locked) {
mPhaseFraction = mPhaseFraction >> c.mShift << c.mShift; // remove fractional phase
}
- setResampler(RESAMPLETYPE(mChannelCount, locked, stride));
+ // stride is the minimum number of filter coefficients processed per loop iteration.
+ // We currently only allow a stride of 16 to match with SIMD processing.
+ // This means that the filter length must be a multiple of 16,
+ // or half the filter length (mHalfNumCoefs) must be a multiple of 8.
+ //
+ // Note: A stride of 2 is achieved with non-SIMD processing.
+ int stride = ((c.mHalfNumCoefs & 7) == 0) ? 16 : 2;
+ LOG_ALWAYS_FATAL_IF(stride < 16, "Resampler stride must be 16 or more");
+ LOG_ALWAYS_FATAL_IF(mChannelCount > 8 || mChannelCount < 1,
+ "Resampler channels(%d) must be between 1 to 8", mChannelCount);
+ // stride 16 (falls back to stride 2 for machines that do not support NEON)
+ if (locked) {
+ switch (mChannelCount) {
+ case 1:
+ mResampleFunc = &AudioResamplerDyn<TC, TI, TO>::resample<1, true, 16>;
+ break;
+ case 2:
+ mResampleFunc = &AudioResamplerDyn<TC, TI, TO>::resample<2, true, 16>;
+ break;
+ case 3:
+ mResampleFunc = &AudioResamplerDyn<TC, TI, TO>::resample<3, true, 16>;
+ break;
+ case 4:
+ mResampleFunc = &AudioResamplerDyn<TC, TI, TO>::resample<4, true, 16>;
+ break;
+ case 5:
+ mResampleFunc = &AudioResamplerDyn<TC, TI, TO>::resample<5, true, 16>;
+ break;
+ case 6:
+ mResampleFunc = &AudioResamplerDyn<TC, TI, TO>::resample<6, true, 16>;
+ break;
+ case 7:
+ mResampleFunc = &AudioResamplerDyn<TC, TI, TO>::resample<7, true, 16>;
+ break;
+ case 8:
+ mResampleFunc = &AudioResamplerDyn<TC, TI, TO>::resample<8, true, 16>;
+ break;
+ }
+ } else {
+ switch (mChannelCount) {
+ case 1:
+ mResampleFunc = &AudioResamplerDyn<TC, TI, TO>::resample<1, false, 16>;
+ break;
+ case 2:
+ mResampleFunc = &AudioResamplerDyn<TC, TI, TO>::resample<2, false, 16>;
+ break;
+ case 3:
+ mResampleFunc = &AudioResamplerDyn<TC, TI, TO>::resample<3, false, 16>;
+ break;
+ case 4:
+ mResampleFunc = &AudioResamplerDyn<TC, TI, TO>::resample<4, false, 16>;
+ break;
+ case 5:
+ mResampleFunc = &AudioResamplerDyn<TC, TI, TO>::resample<5, false, 16>;
+ break;
+ case 6:
+ mResampleFunc = &AudioResamplerDyn<TC, TI, TO>::resample<6, false, 16>;
+ break;
+ case 7:
+ mResampleFunc = &AudioResamplerDyn<TC, TI, TO>::resample<7, false, 16>;
+ break;
+ case 8:
+ mResampleFunc = &AudioResamplerDyn<TC, TI, TO>::resample<8, false, 16>;
+ break;
+ }
+ }
#ifdef DEBUG_RESAMPLER
printf("channels:%d %s stride:%d %s coef:%d shift:%d\n",
mChannelCount, locked ? "locked" : "interpolated",
@@ -424,34 +483,12 @@ void AudioResamplerDyn<TC, TI, TO>::resample(int32_t* out, size_t outFrameCount,
}
template<typename TC, typename TI, typename TO>
-void AudioResamplerDyn<TC, TI, TO>::setResampler(unsigned resampleType)
-{
- // stride 16 (falls back to stride 2 for machines that do not support NEON)
- switch (resampleType) {
- case RESAMPLETYPE(1, true, 16):
- mResampleFunc = &AudioResamplerDyn<TC, TI, TO>::resample<1, true, 16>;
- return;
- case RESAMPLETYPE(2, true, 16):
- mResampleFunc = &AudioResamplerDyn<TC, TI, TO>::resample<2, true, 16>;
- return;
- case RESAMPLETYPE(1, false, 16):
- mResampleFunc = &AudioResamplerDyn<TC, TI, TO>::resample<1, false, 16>;
- return;
- case RESAMPLETYPE(2, false, 16):
- mResampleFunc = &AudioResamplerDyn<TC, TI, TO>::resample<2, false, 16>;
- return;
- default:
- LOG_ALWAYS_FATAL("Invalid resampler type: %u", resampleType);
- mResampleFunc = NULL;
- return;
- }
-}
-
-template<typename TC, typename TI, typename TO>
template<int CHANNELS, bool LOCKED, int STRIDE>
void AudioResamplerDyn<TC, TI, TO>::resample(TO* out, size_t outFrameCount,
AudioBufferProvider* provider)
{
+ // TODO Mono -> Mono is not supported. OUTPUT_CHANNELS reflects minimum of stereo out.
+ const int OUTPUT_CHANNELS = (CHANNELS < 2) ? 2 : CHANNELS;
const Constants& c(mConstants);
const TC* const coefs = mConstants.mFirCoefs;
TI* impulse = mInBuffer.getImpulse();
@@ -459,7 +496,7 @@ void AudioResamplerDyn<TC, TI, TO>::resample(TO* out, size_t outFrameCount,
uint32_t phaseFraction = mPhaseFraction;
const uint32_t phaseIncrement = mPhaseIncrement;
size_t outputIndex = 0;
- size_t outputSampleCount = outFrameCount * 2; // stereo output
+ size_t outputSampleCount = outFrameCount * OUTPUT_CHANNELS;
const uint32_t phaseWrapLimit = c.mL << c.mShift;
size_t inFrameCount = (phaseIncrement * (uint64_t)outFrameCount + phaseFraction)
/ phaseWrapLimit;
@@ -490,7 +527,7 @@ void AudioResamplerDyn<TC, TI, TO>::resample(TO* out, size_t outFrameCount,
while (mBuffer.frameCount == 0 && inFrameCount > 0) {
mBuffer.frameCount = inFrameCount;
provider->getNextBuffer(&mBuffer,
- calculateOutputPTS(outputIndex / 2));
+ calculateOutputPTS(outputIndex / OUTPUT_CHANNELS));
if (mBuffer.raw == NULL) {
goto resample_exit;
}
@@ -538,7 +575,8 @@ void AudioResamplerDyn<TC, TI, TO>::resample(TO* out, size_t outFrameCount,
phaseFraction, phaseWrapLimit,
coefShift, halfNumCoefs, coefs,
impulse, volumeSimd);
- outputIndex += 2;
+
+ outputIndex += OUTPUT_CHANNELS;
phaseFraction += phaseIncrement;
while (phaseFraction >= phaseWrapLimit) {
diff --git a/services/audioflinger/AudioResamplerDyn.h b/services/audioflinger/AudioResamplerDyn.h
index 8c56319..3dced8a 100644
--- a/services/audioflinger/AudioResamplerDyn.h
+++ b/services/audioflinger/AudioResamplerDyn.h
@@ -110,12 +110,10 @@ private:
void createKaiserFir(Constants &c, double stopBandAtten,
int inSampleRate, int outSampleRate, double tbwCheat);
- void setResampler(unsigned resampleType);
-
template<int CHANNELS, bool LOCKED, int STRIDE>
void resample(TO* out, size_t outFrameCount, AudioBufferProvider* provider);
- // declare a pointer to member function for resample
+ // define a pointer to member function type for resample
typedef void (AudioResamplerDyn<TC, TI, TO>::*resample_ABP_t)(TO* out,
size_t outFrameCount, AudioBufferProvider* provider);
diff --git a/services/audioflinger/tests/resampler_tests.cpp b/services/audioflinger/tests/resampler_tests.cpp
index 4a67d0b..d76c376 100644
--- a/services/audioflinger/tests/resampler_tests.cpp
+++ b/services/audioflinger/tests/resampler_tests.cpp
@@ -35,7 +35,8 @@
#include "AudioResampler.h"
#include "test_utils.h"
-void resample(void *output, size_t outputFrames, const std::vector<size_t> &outputIncr,
+void resample(int channels, void *output,
+ size_t outputFrames, const std::vector<size_t> &outputIncr,
android::AudioBufferProvider *provider, android::AudioResampler *resampler)
{
for (size_t i = 0, j = 0; i < outputFrames; ) {
@@ -46,7 +47,7 @@ void resample(void *output, size_t outputFrames, const std::vector<size_t> &outp
if (thisFrames == 0 || thisFrames > outputFrames - i) {
thisFrames = outputFrames - i;
}
- resampler->resample((int32_t*) output + 2*i, thisFrames, provider);
+ resampler->resample((int32_t*) output + channels*i, thisFrames, provider);
i += thisFrames;
}
}
@@ -64,19 +65,26 @@ void buffercmp(const void *reference, const void *test,
}
}
-void testBufferIncrement(size_t channels, unsigned inputFreq, unsigned outputFreq,
+void testBufferIncrement(size_t channels, bool useFloat,
+ unsigned inputFreq, unsigned outputFreq,
enum android::AudioResampler::src_quality quality)
{
+ const int bits = useFloat ? 32 : 16;
// create the provider
std::vector<int> inputIncr;
SignalProvider provider;
- provider.setChirp<int16_t>(channels,
- 0., outputFreq/2., outputFreq, outputFreq/2000.);
+ if (useFloat) {
+ provider.setChirp<float>(channels,
+ 0., outputFreq/2., outputFreq, outputFreq/2000.);
+ } else {
+ provider.setChirp<int16_t>(channels,
+ 0., outputFreq/2., outputFreq, outputFreq/2000.);
+ }
provider.setIncr(inputIncr);
// calculate the output size
size_t outputFrames = ((int64_t) provider.getNumFrames() * outputFreq) / inputFreq;
- size_t outputFrameSize = 2 * sizeof(int32_t);
+ size_t outputFrameSize = channels * (useFloat ? sizeof(float) : sizeof(int32_t));
size_t outputSize = outputFrameSize * outputFrames;
outputSize &= ~7;
@@ -84,7 +92,7 @@ void testBufferIncrement(size_t channels, unsigned inputFreq, unsigned outputFre
const int volumePrecision = 12; /* typical unity gain */
android::AudioResampler* resampler;
- resampler = android::AudioResampler::create(16, channels, outputFreq, quality);
+ resampler = android::AudioResampler::create(bits, channels, outputFreq, quality);
resampler->setSampleRate(inputFreq);
resampler->setVolume(1 << volumePrecision, 1 << volumePrecision);
@@ -92,7 +100,7 @@ void testBufferIncrement(size_t channels, unsigned inputFreq, unsigned outputFre
std::vector<size_t> refIncr;
refIncr.push_back(outputFrames);
void* reference = malloc(outputSize);
- resample(reference, outputFrames, refIncr, &provider, resampler);
+ resample(channels, reference, outputFrames, refIncr, &provider, resampler);
provider.reset();
@@ -101,7 +109,7 @@ void testBufferIncrement(size_t channels, unsigned inputFreq, unsigned outputFre
resampler->reset();
#else
delete resampler;
- resampler = android::AudioResampler::create(16, channels, outputFreq, quality);
+ resampler = android::AudioResampler::create(bits, channels, outputFreq, quality);
resampler->setSampleRate(inputFreq);
resampler->setVolume(1 << volumePrecision, 1 << volumePrecision);
#endif
@@ -112,7 +120,10 @@ void testBufferIncrement(size_t channels, unsigned inputFreq, unsigned outputFre
outIncr.push_back(2);
outIncr.push_back(3);
void* test = malloc(outputSize);
- resample(test, outputFrames, outIncr, &provider, resampler);
+ inputIncr.push_back(1);
+ inputIncr.push_back(3);
+ provider.setIncr(inputIncr);
+ resample(channels, test, outputFrames, outIncr, &provider, resampler);
// check
buffercmp(reference, test, outputFrameSize, outputFrames);
@@ -155,7 +166,7 @@ void testStopbandDownconversion(size_t channels,
// calculate the output size
size_t outputFrames = ((int64_t) provider.getNumFrames() * outputFreq) / inputFreq;
- size_t outputFrameSize = 2 * sizeof(int32_t);
+ size_t outputFrameSize = channels * sizeof(int32_t);
size_t outputSize = outputFrameSize * outputFrames;
outputSize &= ~7;
@@ -171,7 +182,7 @@ void testStopbandDownconversion(size_t channels,
std::vector<size_t> refIncr;
refIncr.push_back(outputFrames);
void* reference = malloc(outputSize);
- resample(reference, outputFrames, refIncr, &provider, resampler);
+ resample(channels, reference, outputFrames, refIncr, &provider, resampler);
int32_t *out = reinterpret_cast<int32_t *>(reference);
@@ -226,7 +237,7 @@ TEST(audioflinger_resampler, bufferincrement_fixedphase) {
};
for (size_t i = 0; i < ARRAY_SIZE(kQualityArray); ++i) {
- testBufferIncrement(2, 48000, 32000, kQualityArray[i]);
+ testBufferIncrement(2, false, 48000, 32000, kQualityArray[i]);
}
}
@@ -243,7 +254,33 @@ TEST(audioflinger_resampler, bufferincrement_interpolatedphase) {
};
for (size_t i = 0; i < ARRAY_SIZE(kQualityArray); ++i) {
- testBufferIncrement(2, 22050, 48000, kQualityArray[i]);
+ testBufferIncrement(2, false, 22050, 48000, kQualityArray[i]);
+ }
+}
+
+TEST(audioflinger_resampler, bufferincrement_fixedphase_multi) {
+ // only dynamic quality
+ static const enum android::AudioResampler::src_quality kQualityArray[] = {
+ android::AudioResampler::DYN_LOW_QUALITY,
+ android::AudioResampler::DYN_MED_QUALITY,
+ android::AudioResampler::DYN_HIGH_QUALITY,
+ };
+
+ for (size_t i = 0; i < ARRAY_SIZE(kQualityArray); ++i) {
+ testBufferIncrement(4, false, 48000, 32000, kQualityArray[i]);
+ }
+}
+
+TEST(audioflinger_resampler, bufferincrement_interpolatedphase_multi_float) {
+ // only dynamic quality
+ static const enum android::AudioResampler::src_quality kQualityArray[] = {
+ android::AudioResampler::DYN_LOW_QUALITY,
+ android::AudioResampler::DYN_MED_QUALITY,
+ android::AudioResampler::DYN_HIGH_QUALITY,
+ };
+
+ for (size_t i = 0; i < ARRAY_SIZE(kQualityArray); ++i) {
+ testBufferIncrement(8, true, 22050, 48000, kQualityArray[i]);
}
}