summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGlenn Kasten <gkasten@google.com>2012-10-01 14:04:31 -0700
committerGlenn Kasten <gkasten@google.com>2012-10-04 09:44:04 -0700
commita6d41334d25ffde12484eb28301352560a063ef6 (patch)
tree4d8df3822f93824ada324d5038ab0b4cd27ce77b
parent95f24dacbde69295fd21bbf683281b277e097bb1 (diff)
downloadframeworks_av-a6d41334d25ffde12484eb28301352560a063ef6.zip
frameworks_av-a6d41334d25ffde12484eb28301352560a063ef6.tar.gz
frameworks_av-a6d41334d25ffde12484eb28301352560a063ef6.tar.bz2
Integrate improved coefficient sinc resampler: VHQ
Summary: Very high quality is enabled only for 44.1 -> 48 or 48 -> 44.1, and uses low quality for all other use cases. Track estimated CPU load and throttles the quality based on load; as currently configured it should allow up to 2 instances of very high quality. Medium quality and high quality are currently disabled unless explicitly requested. Details: Only load .so the first time it is needed. Cleanup code style: formatting, indentation, whitespace. Restore medium quality resampler, but it is not used (see next line). Fix memory leak for sinc resampler. Check sample rate in resampler constructor. Add logs for debugging. Rename DEFAULT to DEFAULT_QUALITY for consistency with other quality levels. Renumber VERY_HIGH_QUALITY from 255 to 4. Use enum src_quality consistently. Improve parsing of property af.resampler.quality. Fix reentrancy bug - allow an instance of high quality and an instance of very high quality to both be active concurrently. Bug: 7229644 Change-Id: I0ce6b913b05038889f50462a38830b61a602a9f7
-rwxr-xr-xlibvideoeditor/lvpp/VideoEditorSRC.cpp3
-rwxr-xr-xlibvideoeditor/vss/src/VideoEditorResampler.cpp2
-rw-r--r--services/audioflinger/Android.mk4
-rw-r--r--services/audioflinger/AudioMixer.cpp14
-rw-r--r--services/audioflinger/AudioResampler.cpp134
-rw-r--r--services/audioflinger/AudioResampler.h24
-rw-r--r--services/audioflinger/AudioResamplerCubic.h2
-rw-r--r--services/audioflinger/AudioResamplerSinc.cpp177
-rw-r--r--services/audioflinger/AudioResamplerSinc.h39
9 files changed, 272 insertions, 127 deletions
diff --git a/libvideoeditor/lvpp/VideoEditorSRC.cpp b/libvideoeditor/lvpp/VideoEditorSRC.cpp
index 4753dd4..36d0812 100755
--- a/libvideoeditor/lvpp/VideoEditorSRC.cpp
+++ b/libvideoeditor/lvpp/VideoEditorSRC.cpp
@@ -321,8 +321,7 @@ void VideoEditorSRC::checkAndSetResampler() {
mResampler = AudioResampler::create(
16 /* bit depth */,
mChannelCnt,
- mOutputSampleRate,
- AudioResampler::DEFAULT);
+ mOutputSampleRate);
CHECK(mResampler);
mResampler->setSampleRate(mSampleRate);
mResampler->setVolume(kUnityGain, kUnityGain);
diff --git a/libvideoeditor/vss/src/VideoEditorResampler.cpp b/libvideoeditor/vss/src/VideoEditorResampler.cpp
index 38dffb7..1129c3c 100755
--- a/libvideoeditor/vss/src/VideoEditorResampler.cpp
+++ b/libvideoeditor/vss/src/VideoEditorResampler.cpp
@@ -80,7 +80,7 @@ M4OSA_Context LVAudioResamplerCreate(M4OSA_Int32 bitDepth, M4OSA_Int32 inChanne
VideoEditorResampler *context = new VideoEditorResampler();
context->mResampler = AudioResampler::create(
- bitDepth, inChannelCount, sampleRate, AudioResampler::DEFAULT);
+ bitDepth, inChannelCount, sampleRate);
if (context->mResampler == NULL) {
return NULL;
}
diff --git a/services/audioflinger/Android.mk b/services/audioflinger/Android.mk
index 7a1c020..85c2dac 100644
--- a/services/audioflinger/Android.mk
+++ b/services/audioflinger/Android.mk
@@ -20,7 +20,9 @@ LOCAL_SRC_FILES:= \
AudioPolicyService.cpp \
ServiceUtilities.cpp \
AudioResamplerSinc.cpp.arm
-# AudioResamplerCubic.cpp.arm
+
+# uncomment to enable AudioResampler::MED_QUALITY
+# LOCAL_SRC_FILES += AudioResamplerCubic.cpp.arm
LOCAL_SRC_FILES += StateQueue.cpp
diff --git a/services/audioflinger/AudioMixer.cpp b/services/audioflinger/AudioMixer.cpp
index ab75dd0..af169d5 100644
--- a/services/audioflinger/AudioMixer.cpp
+++ b/services/audioflinger/AudioMixer.cpp
@@ -539,11 +539,23 @@ bool AudioMixer::track_t::setResampler(uint32_t value, uint32_t devSampleRate)
if (sampleRate != value) {
sampleRate = value;
if (resampler == NULL) {
+ ALOGV("creating resampler from track %d Hz to device %d Hz", value, devSampleRate);
+ AudioResampler::src_quality quality;
+ // force lowest quality level resampler if use case isn't music or video
+ // FIXME this is flawed for dynamic sample rates, as we choose the resampler
+ // quality level based on the initial ratio, but that could change later.
+ // Should have a way to distinguish tracks with static ratios vs. dynamic ratios.
+ if (!((value == 44100 && devSampleRate == 48000) ||
+ (value == 48000 && devSampleRate == 44100))) {
+ quality = AudioResampler::LOW_QUALITY;
+ } else {
+ quality = AudioResampler::DEFAULT_QUALITY;
+ }
resampler = AudioResampler::create(
format,
// the resampler sees the number of channels after the downmixer, if any
downmixerBufferProvider != NULL ? MAX_NUM_CHANNELS : channelCount,
- devSampleRate);
+ devSampleRate, quality);
resampler->setLocalTimeFreq(localTimeFreq);
}
return true;
diff --git a/services/audioflinger/AudioResampler.cpp b/services/audioflinger/AudioResampler.cpp
index 5c1c905..96293e3 100644
--- a/services/audioflinger/AudioResampler.cpp
+++ b/services/audioflinger/AudioResampler.cpp
@@ -24,9 +24,7 @@
#include <cutils/properties.h>
#include "AudioResampler.h"
#include "AudioResamplerSinc.h"
-#if 0
#include "AudioResamplerCubic.h"
-#endif
#ifdef __arm__
#include <machine/cpu-features.h>
@@ -42,7 +40,7 @@ namespace android {
class AudioResamplerOrder1 : public AudioResampler {
public:
AudioResamplerOrder1(int bitDepth, int inChannelCount, int32_t sampleRate) :
- AudioResampler(bitDepth, inChannelCount, sampleRate), mX0L(0), mX0R(0) {
+ AudioResampler(bitDepth, inChannelCount, sampleRate, LOW_QUALITY), mX0L(0), mX0R(0) {
}
virtual void resample(int32_t* out, size_t outFrameCount,
AudioBufferProvider* provider);
@@ -79,29 +77,120 @@ private:
int mX0R;
};
+bool AudioResampler::qualityIsSupported(src_quality quality)
+{
+ switch (quality) {
+ case DEFAULT_QUALITY:
+ case LOW_QUALITY:
+#if 0 // these have not been qualified recently so are not supported unless explicitly requested
+ case MED_QUALITY:
+ case HIGH_QUALITY:
+#endif
+ case VERY_HIGH_QUALITY:
+ return true;
+ default:
+ return false;
+ }
+}
+
// ----------------------------------------------------------------------------
-AudioResampler* AudioResampler::create(int bitDepth, int inChannelCount,
- int32_t sampleRate, int quality) {
- // can only create low quality resample now
- AudioResampler* resampler;
+static pthread_once_t once_control = PTHREAD_ONCE_INIT;
+static AudioResampler::src_quality defaultQuality = AudioResampler::DEFAULT_QUALITY;
+void AudioResampler::init_routine()
+{
char value[PROPERTY_VALUE_MAX];
- if (property_get("af.resampler.quality", value, 0)) {
- quality = atoi(value);
- ALOGD("forcing AudioResampler quality to %d", quality);
+ if (property_get("af.resampler.quality", value, NULL) > 0) {
+ char *endptr;
+ unsigned long l = strtoul(value, &endptr, 0);
+ if (*endptr == '\0') {
+ defaultQuality = (src_quality) l;
+ ALOGD("forcing AudioResampler quality to %d", defaultQuality);
+ if (defaultQuality < DEFAULT_QUALITY || defaultQuality > VERY_HIGH_QUALITY) {
+ defaultQuality = DEFAULT_QUALITY;
+ }
+ }
}
+}
- if (quality == DEFAULT)
- quality = LOW_QUALITY;
+uint32_t AudioResampler::qualityMHz(src_quality quality)
+{
+ switch (quality) {
+ default:
+ case DEFAULT_QUALITY:
+ case LOW_QUALITY:
+ return 3;
+ case MED_QUALITY:
+ return 6;
+ case HIGH_QUALITY:
+ return 20;
+ case VERY_HIGH_QUALITY:
+ return 34;
+ }
+}
+
+static const uint32_t maxMHz = 75; // an arbitrary number that permits 2 VHQ, should be tunable
+static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
+static uint32_t currentMHz = 0;
+
+AudioResampler* AudioResampler::create(int bitDepth, int inChannelCount,
+ int32_t sampleRate, src_quality quality) {
+
+ bool atFinalQuality;
+ if (quality == DEFAULT_QUALITY) {
+ // read the resampler default quality property the first time it is needed
+ int ok = pthread_once(&once_control, init_routine);
+ if (ok != 0) {
+ ALOGE("%s pthread_once failed: %d", __func__, ok);
+ }
+ quality = defaultQuality;
+ atFinalQuality = false;
+ } else {
+ atFinalQuality = true;
+ }
+
+ // naive implementation of CPU load throttling doesn't account for whether resampler is active
+ pthread_mutex_lock(&mutex);
+ for (;;) {
+ uint32_t deltaMHz = qualityMHz(quality);
+ uint32_t newMHz = currentMHz + deltaMHz;
+ if ((qualityIsSupported(quality) && newMHz <= maxMHz) || atFinalQuality) {
+ ALOGV("resampler load %u -> %u MHz due to delta +%u MHz from quality %d",
+ currentMHz, newMHz, deltaMHz, quality);
+ currentMHz = newMHz;
+ break;
+ }
+ // not enough CPU available for proposed quality level, so try next lowest level
+ switch (quality) {
+ default:
+ case DEFAULT_QUALITY:
+ case LOW_QUALITY:
+ atFinalQuality = true;
+ break;
+ case MED_QUALITY:
+ quality = LOW_QUALITY;
+ break;
+ case HIGH_QUALITY:
+ quality = MED_QUALITY;
+ break;
+ case VERY_HIGH_QUALITY:
+ quality = HIGH_QUALITY;
+ break;
+ }
+ }
+ pthread_mutex_unlock(&mutex);
+
+ AudioResampler* resampler;
switch (quality) {
default:
+ case DEFAULT_QUALITY:
case LOW_QUALITY:
ALOGV("Create linear Resampler");
resampler = new AudioResamplerOrder1(bitDepth, inChannelCount, sampleRate);
break;
-#if 0
+#if 0 // disabled because it has not been qualified recently, if requested will use default:
case MED_QUALITY:
ALOGV("Create cubic Resampler");
resampler = new AudioResamplerCubic(bitDepth, inChannelCount, sampleRate);
@@ -110,8 +199,9 @@ AudioResampler* AudioResampler::create(int bitDepth, int inChannelCount,
case HIGH_QUALITY:
ALOGV("Create HIGH_QUALITY sinc Resampler");
resampler = new AudioResamplerSinc(bitDepth, inChannelCount, sampleRate);
+ break;
case VERY_HIGH_QUALITY:
- ALOGV("Create VERY_HIGH_QUALITY sinc Resampler = %d",quality);
+ ALOGV("Create VERY_HIGH_QUALITY sinc Resampler = %d", quality);
resampler = new AudioResamplerSinc(bitDepth, inChannelCount, sampleRate, quality);
break;
}
@@ -122,17 +212,20 @@ AudioResampler* AudioResampler::create(int bitDepth, int inChannelCount,
}
AudioResampler::AudioResampler(int bitDepth, int inChannelCount,
- int32_t sampleRate) :
+ int32_t sampleRate, src_quality quality) :
mBitDepth(bitDepth), mChannelCount(inChannelCount),
mSampleRate(sampleRate), mInSampleRate(sampleRate), mInputIndex(0),
mPhaseFraction(0), mLocalTimeFreq(0),
- mPTS(AudioBufferProvider::kInvalidPTS) {
+ 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 (sampleRate <= 0) {
+ ALOGE("Unsupported sample rate %d Hz", sampleRate);
+ }
// initialize common members
mVolume[0] = mVolume[1] = 0;
@@ -141,6 +234,15 @@ AudioResampler::AudioResampler(int bitDepth, int inChannelCount,
}
AudioResampler::~AudioResampler() {
+ pthread_mutex_lock(&mutex);
+ src_quality quality = getQuality();
+ uint32_t deltaMHz = qualityMHz(quality);
+ int32_t newMHz = currentMHz - deltaMHz;
+ ALOGV("resampler load %u -> %d MHz due to delta -%u MHz from quality %d",
+ currentMHz, newMHz, deltaMHz, quality);
+ LOG_ALWAYS_FATAL_IF(newMHz < 0, "negative resampler load %d MHz", newMHz);
+ currentMHz = newMHz;
+ pthread_mutex_unlock(&mutex);
}
void AudioResampler::setSampleRate(int32_t inSampleRate) {
diff --git a/services/audioflinger/AudioResampler.h b/services/audioflinger/AudioResampler.h
index 71cdfda..2b8694f 100644
--- a/services/audioflinger/AudioResampler.h
+++ b/services/audioflinger/AudioResampler.h
@@ -35,15 +35,15 @@ public:
// certain fixed rate conversions. Sample rate cannot be
// changed dynamically.
enum src_quality {
- DEFAULT=0,
+ DEFAULT_QUALITY=0,
LOW_QUALITY=1,
MED_QUALITY=2,
HIGH_QUALITY=3,
- VERY_HIGH_QUALITY=255
+ VERY_HIGH_QUALITY=4,
};
static AudioResampler* create(int bitDepth, int inChannelCount,
- int32_t sampleRate, int quality=DEFAULT);
+ int32_t sampleRate, src_quality quality=DEFAULT_QUALITY);
virtual ~AudioResampler();
@@ -61,6 +61,9 @@ public:
virtual void reset();
virtual size_t getUnreleasedFrames() const { return mInputIndex; }
+ // called from destructor, so must not be virtual
+ src_quality getQuality() const { return mQuality; }
+
protected:
// number of bits for phase fraction - 30 bits allows nearly 2x downsampling
static const int kNumPhaseBits = 30;
@@ -71,7 +74,7 @@ protected:
// multiplier to calculate fixed point phase increment
static const double kPhaseMultiplier = 1L << kNumPhaseBits;
- AudioResampler(int bitDepth, int inChannelCount, int32_t sampleRate);
+ AudioResampler(int bitDepth, int inChannelCount, int32_t sampleRate, src_quality quality);
// prevent copying
AudioResampler(const AudioResampler&);
@@ -94,6 +97,19 @@ protected:
uint32_t mPhaseFraction;
uint64_t mLocalTimeFreq;
int64_t mPTS;
+
+private:
+ const src_quality mQuality;
+
+ // Return 'true' if the quality level is supported without explicit request
+ static bool qualityIsSupported(src_quality quality);
+
+ // For pthread_once()
+ static void init_routine();
+
+ // Return the estimated CPU load for specific resampler in MHz.
+ // The absolute number is irrelevant, it's the relative values that matter.
+ static uint32_t qualityMHz(src_quality quality);
};
// ----------------------------------------------------------------------------
diff --git a/services/audioflinger/AudioResamplerCubic.h b/services/audioflinger/AudioResamplerCubic.h
index 892785a..203b933 100644
--- a/services/audioflinger/AudioResamplerCubic.h
+++ b/services/audioflinger/AudioResamplerCubic.h
@@ -29,7 +29,7 @@ namespace android {
class AudioResamplerCubic : public AudioResampler {
public:
AudioResamplerCubic(int bitDepth, int inChannelCount, int32_t sampleRate) :
- AudioResampler(bitDepth, inChannelCount, sampleRate) {
+ AudioResampler(bitDepth, inChannelCount, sampleRate, MED_QUALITY) {
}
virtual void resample(int32_t* out, size_t outFrameCount,
AudioBufferProvider* provider);
diff --git a/services/audioflinger/AudioResamplerSinc.cpp b/services/audioflinger/AudioResamplerSinc.cpp
index 0ae4b64..90651f1 100644
--- a/services/audioflinger/AudioResamplerSinc.cpp
+++ b/services/audioflinger/AudioResamplerSinc.cpp
@@ -64,13 +64,65 @@ const int32_t AudioResamplerSinc::mFirCoefsDown[] = {
0x00000000 // this one is needed for lerping the last coefficient
};
-//Define the static variables
-int AudioResamplerSinc::coefsBits;
-int AudioResamplerSinc::cShift;
-uint32_t AudioResamplerSinc::cMask;
-int AudioResamplerSinc::pShift;
-uint32_t AudioResamplerSinc::pMask;
-unsigned int AudioResamplerSinc::halfNumCoefs;
+// we use 15 bits to interpolate between these samples
+// this cannot change because the mul below rely on it.
+static const int pLerpBits = 15;
+
+static pthread_once_t once_control = PTHREAD_ONCE_INIT;
+static readCoefficientsFn readResampleCoefficients = NULL;
+
+/*static*/ AudioResamplerSinc::Constants AudioResamplerSinc::highQualityConstants;
+/*static*/ AudioResamplerSinc::Constants AudioResamplerSinc::veryHighQualityConstants;
+
+void AudioResamplerSinc::init_routine()
+{
+ // for high quality resampler, the parameters for coefficients are compile-time constants
+ Constants *c = &highQualityConstants;
+ c->coefsBits = RESAMPLE_FIR_LERP_INT_BITS;
+ c->cShift = kNumPhaseBits - c->coefsBits;
+ c->cMask = ((1<< c->coefsBits)-1) << c->cShift;
+ c->pShift = kNumPhaseBits - c->coefsBits - pLerpBits;
+ c->pMask = ((1<< pLerpBits)-1) << c->pShift;
+ c->halfNumCoefs = RESAMPLE_FIR_NUM_COEF;
+
+ // for very high quality resampler, the parameters are load-time constants
+ veryHighQualityConstants = highQualityConstants;
+
+ // Open the dll to get the coefficients for VERY_HIGH_QUALITY
+ void *resampleCoeffLib = dlopen("libaudio-resampler.so", RTLD_NOW);
+ ALOGV("Open libaudio-resampler library = %p", resampleCoeffLib);
+ if (resampleCoeffLib == NULL) {
+ ALOGE("Could not open audio-resampler library: %s", dlerror());
+ return;
+ }
+
+ readResampleCoefficients = (readCoefficientsFn) dlsym(resampleCoeffLib,
+ "readResamplerCoefficients");
+ readResampleFirNumCoeffFn readResampleFirNumCoeff = (readResampleFirNumCoeffFn)
+ dlsym(resampleCoeffLib, "readResampleFirNumCoeff");
+ readResampleFirLerpIntBitsFn readResampleFirLerpIntBits = (readResampleFirLerpIntBitsFn)
+ dlsym(resampleCoeffLib, "readResampleFirLerpIntBits");
+ if (!readResampleCoefficients || !readResampleFirNumCoeff || !readResampleFirLerpIntBits) {
+ readResampleCoefficients = NULL;
+ dlclose(resampleCoeffLib);
+ resampleCoeffLib = NULL;
+ ALOGE("Could not find symbol: %s", dlerror());
+ return;
+ }
+
+ c = &veryHighQualityConstants;
+ // we have 16 coefs samples per zero-crossing
+ c->coefsBits = readResampleFirLerpIntBits();
+ ALOGV("coefsBits = %d", c->coefsBits);
+ c->cShift = kNumPhaseBits - c->coefsBits;
+ c->cMask = ((1<<c->coefsBits)-1) << c->cShift;
+ c->pShift = kNumPhaseBits - c->coefsBits - pLerpBits;
+ c->pMask = ((1<<pLerpBits)-1) << c->pShift;
+ // number of zero-crossing on each side
+ c->halfNumCoefs = readResampleFirNumCoeff();
+ ALOGV("halfNumCoefs = %d", c->halfNumCoefs);
+ // note that we "leak" resampleCoeffLib until the process exits
+}
// ----------------------------------------------------------------------------
@@ -148,8 +200,8 @@ int32_t mulAddRL(int left, uint32_t inRL, int32_t v, int32_t a)
// ----------------------------------------------------------------------------
AudioResamplerSinc::AudioResamplerSinc(int bitDepth,
- int inChannelCount, int32_t sampleRate, int32_t quality)
- : AudioResampler(bitDepth, inChannelCount, sampleRate),
+ int inChannelCount, int32_t sampleRate, src_quality quality)
+ : AudioResampler(bitDepth, inChannelCount, sampleRate, quality),
mState(0)
{
/*
@@ -168,74 +220,28 @@ AudioResamplerSinc::AudioResamplerSinc(int bitDepth,
*
*/
- mResampleCoeffLib = NULL;
- //Intialize the parameters for resampler coefficients
- //for high quality
- coefsBits = RESAMPLE_FIR_LERP_INT_BITS;
- cShift = kNumPhaseBits - coefsBits;
- cMask = ((1<< coefsBits)-1) << cShift;
-
- pShift = kNumPhaseBits - coefsBits - pLerpBits;
- pMask = ((1<< pLerpBits)-1) << pShift;
-
- halfNumCoefs = RESAMPLE_FIR_NUM_COEF;
-
- //Check if qcom highest quality can be used
- char value[PROPERTY_VALUE_MAX];
- //Open the dll to get the coefficients for VERY_HIGH_QUALITY
- if (quality == VERY_HIGH_QUALITY ) {
- mResampleCoeffLib = dlopen("libaudio-resampler.so", RTLD_NOW);
- ALOGV("Open libaudio-resampler library = %p",mResampleCoeffLib);
- if (mResampleCoeffLib == NULL) {
- ALOGE("Could not open audio-resampler library: %s", dlerror());
- return;
- }
- mReadResampleCoefficients = (readCoefficientsFn)dlsym(mResampleCoeffLib, "readResamplerCoefficients");
- mReadResampleFirNumCoeff = (readResampleFirNumCoeffFn)dlsym(mResampleCoeffLib, "readResampleFirNumCoeff");
- mReadResampleFirLerpIntBits = (readResampleFirLerpIntBitsFn)dlsym(mResampleCoeffLib,"readResampleFirLerpIntBits");
- if (!mReadResampleCoefficients || !mReadResampleFirNumCoeff || !mReadResampleFirLerpIntBits) {
- mReadResampleCoefficients = NULL;
- mReadResampleFirNumCoeff = NULL;
- mReadResampleFirLerpIntBits = NULL;
- dlclose(mResampleCoeffLib);
- mResampleCoeffLib = NULL;
- ALOGE("Could not find convert symbol: %s", dlerror());
- return;
- }
- // we have 16 coefs samples per zero-crossing
- coefsBits = mReadResampleFirLerpIntBits();
- ALOGV("coefsBits = %d",coefsBits);
- cShift = kNumPhaseBits - coefsBits;
- cMask = ((1<<coefsBits)-1) << cShift;
- pShift = kNumPhaseBits - coefsBits - pLerpBits;
- pMask = ((1<<pLerpBits)-1) << pShift;
- // number of zero-crossing on each side
- halfNumCoefs = mReadResampleFirNumCoeff();
- ALOGV("halfNumCoefs = %d",halfNumCoefs);
+ // Load the constants for coefficients
+ int ok = pthread_once(&once_control, init_routine);
+ if (ok != 0) {
+ ALOGE("%s pthread_once failed: %d", __func__, ok);
}
+ mConstants = (quality == VERY_HIGH_QUALITY) ? &veryHighQualityConstants : &highQualityConstants;
}
AudioResamplerSinc::~AudioResamplerSinc()
{
- if(mResampleCoeffLib) {
- ALOGV("close the libaudio-resampler library");
- dlclose(mResampleCoeffLib);
- mResampleCoeffLib = NULL;
- mReadResampleCoefficients = NULL;
- mReadResampleFirNumCoeff = NULL;
- mReadResampleFirLerpIntBits = NULL;
- }
- delete [] mState;
+ delete[] mState;
}
void AudioResamplerSinc::init() {
+ const Constants *c = mConstants;
- const size_t numCoefs = 2*halfNumCoefs;
+ const size_t numCoefs = 2*c->halfNumCoefs;
const size_t stateSize = numCoefs * mChannelCount * 2;
mState = new int16_t[stateSize];
memset(mState, 0, sizeof(int16_t)*stateSize);
- mImpulse = mState + (halfNumCoefs-1)*mChannelCount;
+ mImpulse = mState + (c->halfNumCoefs-1)*mChannelCount;
mRingFull = mImpulse + (numCoefs+1)*mChannelCount;
}
@@ -243,11 +249,14 @@ void AudioResamplerSinc::resample(int32_t* out, size_t outFrameCount,
AudioBufferProvider* provider)
{
- if(mResampleCoeffLib){
+ // FIXME store current state (up or down sample) and only load the coefs when the state
+ // changes. Or load two pointers one for up and one for down in the init function.
+ // Not critical now since the read functions are fast, but would be important if read was slow.
+ if (readResampleCoefficients) {
ALOGV("get coefficient from libmm-audio resampler library");
- mFirCoefs = (mInSampleRate <= mSampleRate) ? mReadResampleCoefficients(true) : mReadResampleCoefficients(false);
- }
- else {
+ mFirCoefs = (mInSampleRate <= mSampleRate) ? readResampleCoefficients(true) :
+ readResampleCoefficients(false);
+ } else {
ALOGV("Use default coefficients");
mFirCoefs = (mInSampleRate <= mSampleRate) ? mFirCoefsUp : mFirCoefsDown;
}
@@ -269,6 +278,7 @@ template<int CHANNELS>
void AudioResamplerSinc::resample(int32_t* out, size_t outFrameCount,
AudioBufferProvider* provider)
{
+ const Constants *c = mConstants;
int16_t* impulse = mImpulse;
uint32_t vRL = mVolumeRL;
size_t inputIndex = mInputIndex;
@@ -307,7 +317,7 @@ void AudioResamplerSinc::resample(int32_t* out, size_t outFrameCount,
const size_t frameCount = mBuffer.frameCount;
// Always read-in the first samples from the input buffer
- int16_t* head = impulse + halfNumCoefs*CHANNELS;
+ int16_t* head = impulse + c->halfNumCoefs*CHANNELS;
head[0] = in[inputIndex*CHANNELS + 0];
if (CHANNELS == 2)
head[1] = in[inputIndex*CHANNELS + 1];
@@ -365,15 +375,16 @@ void AudioResamplerSinc::read(
int16_t*& impulse, uint32_t& phaseFraction,
const int16_t* in, size_t inputIndex)
{
+ const Constants *c = mConstants;
const uint32_t phaseIndex = phaseFraction >> kNumPhaseBits;
impulse += CHANNELS;
phaseFraction -= 1LU<<kNumPhaseBits;
if (impulse >= mRingFull) {
- const size_t stateSize = (halfNumCoefs*2)*CHANNELS;
+ const size_t stateSize = (c->halfNumCoefs*2)*CHANNELS;
memcpy(mState, mState+stateSize, sizeof(int16_t)*stateSize);
impulse -= stateSize;
}
- int16_t* head = impulse + halfNumCoefs*CHANNELS;
+ int16_t* head = impulse + c->halfNumCoefs*CHANNELS;
head[0] = in[inputIndex*CHANNELS + 0];
if (CHANNELS == 2)
head[1] = in[inputIndex*CHANNELS + 1];
@@ -383,15 +394,17 @@ template<int CHANNELS>
void AudioResamplerSinc::filterCoefficient(
int32_t& l, int32_t& r, uint32_t phase, const int16_t *samples)
{
+ const Constants *c = mConstants;
+
// compute the index of the coefficient on the positive side and
// negative side
- uint32_t indexP = (phase & cMask) >> cShift;
- uint16_t lerpP = (phase & pMask) >> pShift;
- uint32_t indexN = (-phase & cMask) >> cShift;
- uint16_t lerpN = (-phase & pMask) >> pShift;
+ uint32_t indexP = (phase & c->cMask) >> c->cShift;
+ uint16_t lerpP = (phase & c->pMask) >> c->pShift;
+ uint32_t indexN = (-phase & c->cMask) >> c->cShift;
+ uint16_t lerpN = (-phase & c->pMask) >> c->pShift;
if ((indexP == 0) && (lerpP == 0)) {
- indexN = cMask >> cShift;
- lerpN = pMask >> pShift;
+ indexN = c->cMask >> c->cShift;
+ lerpN = c->pMask >> c->pShift;
}
l = 0;
@@ -399,19 +412,19 @@ void AudioResamplerSinc::filterCoefficient(
const int32_t* coefs = mFirCoefs;
const int16_t *sP = samples;
const int16_t *sN = samples+CHANNELS;
- for (unsigned int i=0 ; i<halfNumCoefs/4 ; i++) {
+ for (unsigned int i=0 ; i < c->halfNumCoefs/4 ; i++) {
interpolate<CHANNELS>(l, r, coefs+indexP, lerpP, sP);
interpolate<CHANNELS>(l, r, coefs+indexN, lerpN, sN);
- sP -= CHANNELS; sN += CHANNELS; coefs += 1<<coefsBits;
+ sP -= CHANNELS; sN += CHANNELS; coefs += 1 << c->coefsBits;
interpolate<CHANNELS>(l, r, coefs+indexP, lerpP, sP);
interpolate<CHANNELS>(l, r, coefs+indexN, lerpN, sN);
- sP -= CHANNELS; sN += CHANNELS; coefs += 1<<coefsBits;
+ sP -= CHANNELS; sN += CHANNELS; coefs += 1 << c->coefsBits;
interpolate<CHANNELS>(l, r, coefs+indexP, lerpP, sP);
interpolate<CHANNELS>(l, r, coefs+indexN, lerpN, sN);
- sP -= CHANNELS; sN += CHANNELS; coefs += 1<<coefsBits;
+ sP -= CHANNELS; sN += CHANNELS; coefs += 1 << c->coefsBits;
interpolate<CHANNELS>(l, r, coefs+indexP, lerpP, sP);
interpolate<CHANNELS>(l, r, coefs+indexN, lerpN, sN);
- sP -= CHANNELS; sN += CHANNELS; coefs += 1<<coefsBits;
+ sP -= CHANNELS; sN += CHANNELS; coefs += 1 << c->coefsBits;
}
}
diff --git a/services/audioflinger/AudioResamplerSinc.h b/services/audioflinger/AudioResamplerSinc.h
index c53c66d..25fc025 100644
--- a/services/audioflinger/AudioResamplerSinc.h
+++ b/services/audioflinger/AudioResamplerSinc.h
@@ -27,14 +27,15 @@ namespace android {
typedef const int32_t * (*readCoefficientsFn)(bool upDownSample);
-typedef int32_t (*readResampleFirNumCoeffFn)();
-typedef int32_t (*readResampleFirLerpIntBitsFn)();
+typedef int32_t (*readResampleFirNumCoeffFn)();
+typedef int32_t (*readResampleFirLerpIntBitsFn)();
// ----------------------------------------------------------------------------
class AudioResamplerSinc : public AudioResampler {
public:
- AudioResamplerSinc(int bitDepth, int inChannelCount, int32_t sampleRate, int32_t quality = HIGH_QUALITY);
+ AudioResamplerSinc(int bitDepth, int inChannelCount, int32_t sampleRate,
+ src_quality quality = HIGH_QUALITY);
virtual ~AudioResamplerSinc();
@@ -60,10 +61,6 @@ private:
inline void read(int16_t*& impulse, uint32_t& phaseFraction,
const int16_t* in, size_t inputIndex);
- readCoefficientsFn mReadResampleCoefficients ;
- readResampleFirNumCoeffFn mReadResampleFirNumCoeff;
- readResampleFirLerpIntBitsFn mReadResampleFirLerpIntBits;
-
int16_t *mState;
int16_t *mImpulse;
int16_t *mRingFull;
@@ -72,24 +69,28 @@ private:
static const int32_t mFirCoefsDown[];
static const int32_t mFirCoefsUp[];
- void * mResampleCoeffLib;
// ----------------------------------------------------------------------------
static const int32_t RESAMPLE_FIR_NUM_COEF = 8;
static const int32_t RESAMPLE_FIR_LERP_INT_BITS = 4;
- // we have 16 coefs samples per zero-crossing
- static int coefsBits;
- static int cShift;
- static uint32_t cMask;
+ struct Constants {
+ // we have 16 coefs samples per zero-crossing
+ int coefsBits;
+ int cShift;
+ uint32_t cMask;
+
+ int pShift;
+ uint32_t pMask;
+
+ // number of zero-crossing on each side
+ unsigned int halfNumCoefs;
+ };
- // and we use 15 bits to interpolate between these samples
- // this cannot change because the mul below rely on it.
- static const int pLerpBits = 15;
- static int pShift;
- static uint32_t pMask;
+ static Constants highQualityConstants;
+ static Constants veryHighQualityConstants;
+ const Constants *mConstants; // points to appropriate set of coefficient parameters
- // number of zero-crossing on each side
- static unsigned int halfNumCoefs;
+ static void init_routine();
};
// ----------------------------------------------------------------------------