resolved conflicts for merge of f12b1c81 to master

Change-Id: I914a11706bd01a198e2137e0c12af0fc92ffa02b
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 @@
         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 @@
 
     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 @@
     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 1f13625..e652d14 100644
--- a/services/audioflinger/AudioMixer.cpp
+++ b/services/audioflinger/AudioMixer.cpp
@@ -538,11 +538,23 @@
         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(sLocalTimeFreq);
             }
             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 @@
 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 @@
     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;
+            }
+        }
+    }
+}
+
+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;
     }
 
-    if (quality == DEFAULT)
-        quality = LOW_QUALITY;
+    // 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 @@
     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(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() {
+    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 @@
     // 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 @@
     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 @@
     // 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 @@
     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 @@
 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 @@
         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 @@
 // ----------------------------------------------------------------------------
 
 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 @@
      *
      */
 
-    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 @@
             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 @@
 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 @@
         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 @@
         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 @@
 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 @@
     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 @@
 
 
 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 @@
     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 @@
     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;
 
-    // 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;
+        int pShift;
+        uint32_t pMask;
 
-    // number of zero-crossing on each side
-    static  unsigned int halfNumCoefs;
+        // number of zero-crossing on each side
+        unsigned int halfNumCoefs;
+    };
+
+    static Constants highQualityConstants;
+    static Constants veryHighQualityConstants;
+    const Constants *mConstants;    // points to appropriate set of coefficient parameters
+
+    static void init_routine();
 };
 
 // ----------------------------------------------------------------------------