audioflinger: use resample coefficients from audio-resampler library.

-Add a separate quality VERY_HIGH_QUALITY in resampler
-Use resample coefficients audio-resampler library for
 quality VERY_HIGH_QUALITY.
-This improves the quality of resampled output.

Bug: 7024293
Change-Id: Ia44142413bed5f5963d7eab7846eec877a2415e4
Signed-off-by: Iliyan Malchev <malchev@google.com>
diff --git a/services/audioflinger/AudioResamplerSinc.cpp b/services/audioflinger/AudioResamplerSinc.cpp
index 76662d8..0ae4b64 100644
--- a/services/audioflinger/AudioResamplerSinc.cpp
+++ b/services/audioflinger/AudioResamplerSinc.cpp
@@ -14,8 +14,15 @@
  * limitations under the License.
  */
 
+#define LOG_TAG "AudioResamplerSinc"
+//#define LOG_NDEBUG 0
+
 #include <string.h>
 #include "AudioResamplerSinc.h"
+#include <dlfcn.h>
+#include <cutils/properties.h>
+#include <stdlib.h>
+#include <utils/Log.h>
 
 namespace android {
 // ----------------------------------------------------------------------------
@@ -57,6 +64,14 @@
         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;
+
 // ----------------------------------------------------------------------------
 
 static inline
@@ -133,7 +148,7 @@
 // ----------------------------------------------------------------------------
 
 AudioResamplerSinc::AudioResamplerSinc(int bitDepth,
-        int inChannelCount, int32_t sampleRate)
+        int inChannelCount, int32_t sampleRate, int32_t quality)
     : AudioResampler(bitDepth, inChannelCount, sampleRate),
     mState(0)
 {
@@ -153,26 +168,89 @@
      *
      */
 
-    const size_t numCoefs = 2*halfNumCoefs;
-    const size_t stateSize = numCoefs * inChannelCount * 2;
-    mState = new int16_t[stateSize];
-    memset(mState, 0, sizeof(int16_t)*stateSize);
-    mImpulse = mState + (halfNumCoefs-1)*inChannelCount;
-    mRingFull = mImpulse + (numCoefs+1)*inChannelCount;
+    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);
+    }
 }
 
+
 AudioResamplerSinc::~AudioResamplerSinc()
 {
+    if(mResampleCoeffLib) {
+        ALOGV("close the libaudio-resampler library");
+        dlclose(mResampleCoeffLib);
+        mResampleCoeffLib = NULL;
+        mReadResampleCoefficients = NULL;
+        mReadResampleFirNumCoeff = NULL;
+        mReadResampleFirLerpIntBits = NULL;
+    }
     delete [] mState;
 }
 
 void AudioResamplerSinc::init() {
+
+    const size_t numCoefs = 2*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;
+    mRingFull = mImpulse + (numCoefs+1)*mChannelCount;
 }
 
 void AudioResamplerSinc::resample(int32_t* out, size_t outFrameCount,
             AudioBufferProvider* provider)
 {
-    mFirCoefs = (mInSampleRate <= mSampleRate) ? mFirCoefsUp : mFirCoefsDown;
+
+    if(mResampleCoeffLib){
+        ALOGV("get coefficient from libmm-audio resampler library");
+        mFirCoefs =  (mInSampleRate <= mSampleRate) ? mReadResampleCoefficients(true) : mReadResampleCoefficients(false);
+    }
+    else {
+        ALOGV("Use default coefficients");
+        mFirCoefs = (mInSampleRate <= mSampleRate) ? mFirCoefsUp : mFirCoefsDown;
+    }
 
     // select the appropriate resampler
     switch (mChannelCount) {
@@ -183,6 +261,7 @@
         resample<2>(out, outFrameCount, provider);
         break;
     }
+
 }
 
 
@@ -352,6 +431,5 @@
         r = l = mulAdd(samples[0], sinc, l);
     }
 }
-
 // ----------------------------------------------------------------------------
 }; // namespace android