Merge "CameraService: trigger appropriate callbacks for burst capture."
diff --git a/services/audioflinger/AudioResampler.cpp b/services/audioflinger/AudioResampler.cpp
index ca98f16..562c4ea 100644
--- a/services/audioflinger/AudioResampler.cpp
+++ b/services/audioflinger/AudioResampler.cpp
@@ -234,7 +234,16 @@
     case DYN_MED_QUALITY:
     case DYN_HIGH_QUALITY:
         ALOGV("Create dynamic Resampler = %d", quality);
-        resampler = new AudioResamplerDyn(bitDepth, inChannelCount, sampleRate, quality);
+        if (bitDepth == 32) { /* bitDepth == 32 signals float precision */
+            resampler = new AudioResamplerDyn<float, float, float>(bitDepth, inChannelCount,
+                    sampleRate, quality);
+        } else if (quality == DYN_HIGH_QUALITY) {
+            resampler = new AudioResamplerDyn<int32_t, int16_t, int32_t>(bitDepth, inChannelCount,
+                    sampleRate, quality);
+        } else {
+            resampler = new AudioResamplerDyn<int16_t, int16_t, int32_t>(bitDepth, inChannelCount,
+                    sampleRate, quality);
+        }
         break;
     }
 
diff --git a/services/audioflinger/AudioResamplerDyn.cpp b/services/audioflinger/AudioResamplerDyn.cpp
index 7e4ca0c..3abe8fd 100644
--- a/services/audioflinger/AudioResamplerDyn.cpp
+++ b/services/audioflinger/AudioResamplerDyn.cpp
@@ -25,6 +25,7 @@
 
 #include <cutils/compiler.h>
 #include <cutils/properties.h>
+#include <utils/Debug.h>
 #include <utils/Log.h>
 
 #include "AudioResamplerFirOps.h" // USE_NEON and USE_INLINE_ASSEMBLY defined here
@@ -38,9 +39,9 @@
 namespace android {
 
 // generate a unique resample type compile-time constant (constexpr)
-#define RESAMPLETYPE(CHANNELS, LOCKED, STRIDE, COEFTYPE) \
-    ((((CHANNELS)-1)&1) | !!(LOCKED)<<1 | (COEFTYPE)<<2 \
-    | ((STRIDE)==8 ? 1 : (STRIDE)==16 ? 2 : 0)<<3)
+#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.
@@ -58,42 +59,46 @@
  * r = extra space for implementing the ring buffer
  */
 
-template<typename TI>
-AudioResamplerDyn::InBuffer<TI>::InBuffer()
-    : mState(NULL), mImpulse(NULL), mRingFull(NULL), mStateSize(0) {
+template<typename TC, typename TI, typename TO>
+AudioResamplerDyn<TC, TI, TO>::InBuffer::InBuffer()
+    : mState(NULL), mImpulse(NULL), mRingFull(NULL), mStateCount(0)
+{
 }
 
-template<typename TI>
-AudioResamplerDyn::InBuffer<TI>::~InBuffer() {
+template<typename TC, typename TI, typename TO>
+AudioResamplerDyn<TC, TI, TO>::InBuffer::~InBuffer()
+{
     init();
 }
 
-template<typename TI>
-void AudioResamplerDyn::InBuffer<TI>::init() {
+template<typename TC, typename TI, typename TO>
+void AudioResamplerDyn<TC, TI, TO>::InBuffer::init()
+{
     free(mState);
     mState = NULL;
     mImpulse = NULL;
     mRingFull = NULL;
-    mStateSize = 0;
+    mStateCount = 0;
 }
 
 // resizes the state buffer to accommodate the appropriate filter length
-template<typename TI>
-void AudioResamplerDyn::InBuffer<TI>::resize(int CHANNELS, int halfNumCoefs) {
+template<typename TC, typename TI, typename TO>
+void AudioResamplerDyn<TC, TI, TO>::InBuffer::resize(int CHANNELS, int halfNumCoefs)
+{
     // calculate desired state size
-    int stateSize = halfNumCoefs * CHANNELS * 2
-            * kStateSizeMultipleOfFilterLength;
+    int stateCount = halfNumCoefs * CHANNELS * 2 * kStateSizeMultipleOfFilterLength;
 
     // check if buffer needs resizing
     if (mState
-            && stateSize == mStateSize
-            && mRingFull-mState == mStateSize-halfNumCoefs*CHANNELS) {
+            && stateCount == mStateCount
+            && mRingFull-mState == mStateCount-halfNumCoefs*CHANNELS) {
         return;
     }
 
     // create new buffer
-    TI* state = (int16_t*)memalign(32, stateSize*sizeof(*state));
-    memset(state, 0, stateSize*sizeof(*state));
+    TI* state;
+    (void)posix_memalign(reinterpret_cast<void**>(&state), 32, stateCount*sizeof(*state));
+    memset(state, 0, stateCount*sizeof(*state));
 
     // attempt to preserve state
     if (mState) {
@@ -105,8 +110,8 @@
             dst += mState-srcLo;
             srcLo = mState;
         }
-        if (srcHi > mState + mStateSize) {
-            srcHi = mState + mStateSize;
+        if (srcHi > mState + mStateCount) {
+            srcHi = mState + mStateCount;
         }
         memcpy(dst, srcLo, (srcHi - srcLo) * sizeof(*srcLo));
         free(mState);
@@ -114,27 +119,29 @@
 
     // set class member vars
     mState = state;
-    mStateSize = stateSize;
-    mImpulse = mState + halfNumCoefs*CHANNELS; // actually one sample greater than needed
-    mRingFull = mState + mStateSize - halfNumCoefs*CHANNELS;
+    mStateCount = stateCount;
+    mImpulse = state + halfNumCoefs*CHANNELS; // actually one sample greater than needed
+    mRingFull = state + mStateCount - halfNumCoefs*CHANNELS;
 }
 
 // copy in the input data into the head (impulse+halfNumCoefs) of the buffer.
-template<typename TI>
+template<typename TC, typename TI, typename TO>
 template<int CHANNELS>
-void AudioResamplerDyn::InBuffer<TI>::readAgain(TI*& impulse, const int halfNumCoefs,
-        const TI* const in, const size_t inputIndex) {
-    int16_t* head = impulse + halfNumCoefs*CHANNELS;
+void AudioResamplerDyn<TC, TI, TO>::InBuffer::readAgain(TI*& impulse, const int halfNumCoefs,
+        const TI* const in, const size_t inputIndex)
+{
+    TI* head = impulse + halfNumCoefs*CHANNELS;
     for (size_t i=0 ; i<CHANNELS ; i++) {
         head[i] = in[inputIndex*CHANNELS + i];
     }
 }
 
 // advance the impulse pointer, and load in data into the head (impulse+halfNumCoefs)
-template<typename TI>
+template<typename TC, typename TI, typename TO>
 template<int CHANNELS>
-void AudioResamplerDyn::InBuffer<TI>::readAdvance(TI*& impulse, const int halfNumCoefs,
-        const TI* const in, const size_t inputIndex) {
+void AudioResamplerDyn<TC, TI, TO>::InBuffer::readAdvance(TI*& impulse, const int halfNumCoefs,
+        const TI* const in, const size_t inputIndex)
+{
     impulse += CHANNELS;
 
     if (CC_UNLIKELY(impulse >= mRingFull)) {
@@ -145,7 +152,8 @@
     readAgain<CHANNELS>(impulse, halfNumCoefs, in, inputIndex);
 }
 
-void AudioResamplerDyn::Constants::set(
+template<typename TC, typename TI, typename TO>
+void AudioResamplerDyn<TC, TI, TO>::Constants::set(
         int L, int halfNumCoefs, int inSampleRate, int outSampleRate)
 {
     int bits = 0;
@@ -158,10 +166,11 @@
     mHalfNumCoefs = halfNumCoefs;
 }
 
-AudioResamplerDyn::AudioResamplerDyn(int bitDepth,
+template<typename TC, typename TI, typename TO>
+AudioResamplerDyn<TC, TI, TO>::AudioResamplerDyn(int bitDepth,
         int inChannelCount, int32_t sampleRate, src_quality quality)
     : AudioResampler(bitDepth, inChannelCount, sampleRate, quality),
-    mResampleType(0), mFilterSampleRate(0), mFilterQuality(DEFAULT_QUALITY),
+      mResampleFunc(0), mFilterSampleRate(0), mFilterQuality(DEFAULT_QUALITY),
     mCoefBuffer(NULL)
 {
     mVolumeSimd[0] = mVolumeSimd[1] = 0;
@@ -172,33 +181,48 @@
     mConstants.set(128, 8, mSampleRate, mSampleRate); // TODO: set better
 }
 
-AudioResamplerDyn::~AudioResamplerDyn() {
+template<typename TC, typename TI, typename TO>
+AudioResamplerDyn<TC, TI, TO>::~AudioResamplerDyn()
+{
     free(mCoefBuffer);
 }
 
-void AudioResamplerDyn::init() {
+template<typename TC, typename TI, typename TO>
+void AudioResamplerDyn<TC, TI, TO>::init()
+{
     mFilterSampleRate = 0; // always trigger new filter generation
     mInBuffer.init();
 }
 
-void AudioResamplerDyn::setVolume(int16_t left, int16_t right) {
+template<typename TC, typename TI, typename TO>
+void AudioResamplerDyn<TC, TI, TO>::setVolume(int16_t left, int16_t right)
+{
     AudioResampler::setVolume(left, right);
-    mVolumeSimd[0] = static_cast<int32_t>(left)<<16;
-    mVolumeSimd[1] = static_cast<int32_t>(right)<<16;
+    // volume is applied on the output type.
+    if (is_same<TO, float>::value || is_same<TO, double>::value) {
+        const TO scale = 1. / (1UL << 12);
+        mVolumeSimd[0] = static_cast<TO>(left) * scale;
+        mVolumeSimd[1] = static_cast<TO>(right) * scale;
+    } else {
+        mVolumeSimd[0] = static_cast<int32_t>(left) << 16;
+        mVolumeSimd[1] = static_cast<int32_t>(right) << 16;
+    }
 }
 
-template <typename T> T max(T a, T b) {return a > b ? a : b;}
+template<typename T> T max(T a, T b) {return a > b ? a : b;}
 
-template <typename T> T absdiff(T a, T b) {return a > b ? a - b : b - a;}
+template<typename T> T absdiff(T a, T b) {return a > b ? a - b : b - a;}
 
-template<typename T>
-void AudioResamplerDyn::createKaiserFir(Constants &c, double stopBandAtten,
-        int inSampleRate, int outSampleRate, double tbwCheat) {
-    T* buf = reinterpret_cast<T*>(memalign(32, (c.mL+1)*c.mHalfNumCoefs*sizeof(T)));
+template<typename TC, typename TI, typename TO>
+void AudioResamplerDyn<TC, TI, TO>::createKaiserFir(Constants &c,
+        double stopBandAtten, int inSampleRate, int outSampleRate, double tbwCheat)
+{
+    TC* buf;
     static const double atten = 0.9998;   // to avoid ripple overflow
     double fcr;
     double tbw = firKaiserTbw(c.mHalfNumCoefs, stopBandAtten);
 
+    (void)posix_memalign(reinterpret_cast<void**>(&buf), 32, (c.mL+1)*c.mHalfNumCoefs*sizeof(TC));
     if (inSampleRate < outSampleRate) { // upsample
         fcr = max(0.5*tbwCheat - tbw/2, tbw/2);
     } else { // downsample
@@ -206,7 +230,7 @@
     }
     // create and set filter
     firKaiserGen(buf, c.mL, c.mHalfNumCoefs, stopBandAtten, fcr, atten);
-    c.setBuf(buf);
+    c.mFirCoefs = buf;
     if (mCoefBuffer) {
         free(mCoefBuffer);
     }
@@ -228,7 +252,8 @@
 }
 
 // recursive gcd. Using objdump, it appears the tail recursion is converted to a while loop.
-static int gcd(int n, int m) {
+static int gcd(int n, int m)
+{
     if (m == 0) {
         return n;
     }
@@ -236,7 +261,8 @@
 }
 
 static bool isClose(int32_t newSampleRate, int32_t prevSampleRate,
-        int32_t filterSampleRate, int32_t outSampleRate) {
+        int32_t filterSampleRate, int32_t outSampleRate)
+{
 
     // different upsampling ratios do not need a filter change.
     if (filterSampleRate != 0
@@ -253,7 +279,9 @@
     return pdiff < prevSampleRate>>4 && adiff < filterSampleRate>>3;
 }
 
-void AudioResamplerDyn::setSampleRate(int32_t inSampleRate) {
+template<typename TC, typename TI, typename TO>
+void AudioResamplerDyn<TC, TI, TO>::setSampleRate(int32_t inSampleRate)
+{
     if (mInSampleRate == inSampleRate) {
         return;
     }
@@ -357,13 +385,8 @@
 
         // create the filter
         mConstants.set(phases, halfLength, inSampleRate, mSampleRate);
-        if (useS32) {
-            createKaiserFir<int32_t>(mConstants, stopBandAtten,
-                    inSampleRate, mSampleRate, tbwCheat);
-        } else {
-            createKaiserFir<int16_t>(mConstants, stopBandAtten,
-                    inSampleRate, mSampleRate, tbwCheat);
-        }
+        createKaiserFir(mConstants, stopBandAtten,
+                inSampleRate, mSampleRate, tbwCheat);
     } // End Kaiser filter
 
     // update phase and state based on the new filter.
@@ -385,7 +408,7 @@
         mPhaseFraction = mPhaseFraction >> c.mShift << c.mShift; // remove fractional phase
     }
 
-    mResampleType = RESAMPLETYPE(mChannelCount, locked, stride, !!useS32);
+    setResampler(RESAMPLETYPE(mChannelCount, locked, stride));
 #ifdef DEBUG_RESAMPLER
     printf("channels:%d  %s  stride:%d  %s  coef:%d  shift:%d\n",
             mChannelCount, locked ? "locked" : "interpolated",
@@ -393,78 +416,45 @@
 #endif
 }
 
-void AudioResamplerDyn::resample(int32_t* out, size_t outFrameCount,
+template<typename TC, typename TI, typename TO>
+void AudioResamplerDyn<TC, TI, TO>::resample(int32_t* out, size_t outFrameCount,
             AudioBufferProvider* provider)
 {
-    // TODO:
-    // 24 cases - this perhaps can be reduced later, as testing might take too long
-    switch (mResampleType) {
+    (this->*mResampleFunc)(reinterpret_cast<TO*>(out), outFrameCount, provider);
+}
 
+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)
-    case RESAMPLETYPE(1, true, 16, 0):
-        return resample<1, true, 16>(out, outFrameCount, mConstants.mFirCoefsS16, provider);
-    case RESAMPLETYPE(2, true, 16, 0):
-        return resample<2, true, 16>(out, outFrameCount, mConstants.mFirCoefsS16, provider);
-    case RESAMPLETYPE(1, false, 16, 0):
-        return resample<1, false, 16>(out, outFrameCount, mConstants.mFirCoefsS16, provider);
-    case RESAMPLETYPE(2, false, 16, 0):
-        return resample<2, false, 16>(out, outFrameCount, mConstants.mFirCoefsS16, provider);
-    case RESAMPLETYPE(1, true, 16, 1):
-        return resample<1, true, 16>(out, outFrameCount, mConstants.mFirCoefsS32, provider);
-    case RESAMPLETYPE(2, true, 16, 1):
-        return resample<2, true, 16>(out, outFrameCount, mConstants.mFirCoefsS32, provider);
-    case RESAMPLETYPE(1, false, 16, 1):
-        return resample<1, false, 16>(out, outFrameCount, mConstants.mFirCoefsS32, provider);
-    case RESAMPLETYPE(2, false, 16, 1):
-        return resample<2, false, 16>(out, outFrameCount, mConstants.mFirCoefsS32, provider);
-#if 0
-    // TODO: Remove these?
-    // stride 8
-    case RESAMPLETYPE(1, true, 8, 0):
-        return resample<1, true, 8>(out, outFrameCount, mConstants.mFirCoefsS16, provider);
-    case RESAMPLETYPE(2, true, 8, 0):
-        return resample<2, true, 8>(out, outFrameCount, mConstants.mFirCoefsS16, provider);
-    case RESAMPLETYPE(1, false, 8, 0):
-        return resample<1, false, 8>(out, outFrameCount, mConstants.mFirCoefsS16, provider);
-    case RESAMPLETYPE(2, false, 8, 0):
-        return resample<2, false, 8>(out, outFrameCount, mConstants.mFirCoefsS16, provider);
-    case RESAMPLETYPE(1, true, 8, 1):
-        return resample<1, true, 8>(out, outFrameCount, mConstants.mFirCoefsS32, provider);
-    case RESAMPLETYPE(2, true, 8, 1):
-        return resample<2, true, 8>(out, outFrameCount, mConstants.mFirCoefsS32, provider);
-    case RESAMPLETYPE(1, false, 8, 1):
-        return resample<1, false, 8>(out, outFrameCount, mConstants.mFirCoefsS32, provider);
-    case RESAMPLETYPE(2, false, 8, 1):
-        return resample<2, false, 8>(out, outFrameCount, mConstants.mFirCoefsS32, provider);
-    // stride 2 (can handle any filter length)
-    case RESAMPLETYPE(1, true, 2, 0):
-        return resample<1, true, 2>(out, outFrameCount, mConstants.mFirCoefsS16, provider);
-    case RESAMPLETYPE(2, true, 2, 0):
-        return resample<2, true, 2>(out, outFrameCount, mConstants.mFirCoefsS16, provider);
-    case RESAMPLETYPE(1, false, 2, 0):
-        return resample<1, false, 2>(out, outFrameCount, mConstants.mFirCoefsS16, provider);
-    case RESAMPLETYPE(2, false, 2, 0):
-        return resample<2, false, 2>(out, outFrameCount, mConstants.mFirCoefsS16, provider);
-    case RESAMPLETYPE(1, true, 2, 1):
-        return resample<1, true, 2>(out, outFrameCount, mConstants.mFirCoefsS32, provider);
-    case RESAMPLETYPE(2, true, 2, 1):
-        return resample<2, true, 2>(out, outFrameCount, mConstants.mFirCoefsS32, provider);
-    case RESAMPLETYPE(1, false, 2, 1):
-        return resample<1, false, 2>(out, outFrameCount, mConstants.mFirCoefsS32, provider);
-    case RESAMPLETYPE(2, false, 2, 1):
-        return resample<2, false, 2>(out, outFrameCount, mConstants.mFirCoefsS32, provider);
-#endif
+    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:
-        ; // error
+        LOG_ALWAYS_FATAL("Invalid resampler type: %u", resampleType);
+        mResampleFunc = NULL;
+        return;
     }
 }
 
-template<int CHANNELS, bool LOCKED, int STRIDE, typename TC>
-void AudioResamplerDyn::resample(int32_t* out, size_t outFrameCount,
-        const TC* const coefs,  AudioBufferProvider* provider)
+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)
 {
     const Constants& c(mConstants);
-    int16_t* impulse = mInBuffer.getImpulse();
+    const TC* const coefs = mConstants.mFirCoefs;
+    TI* impulse = mInBuffer.getImpulse();
     size_t inputIndex = mInputIndex;
     uint32_t phaseFraction = mPhaseFraction;
     const uint32_t phaseIncrement = mPhaseIncrement;
@@ -490,8 +480,9 @@
                 goto resample_exit;
             }
             if (phaseFraction >= phaseWrapLimit) { // read in data
-                mInBuffer.readAdvance<CHANNELS>(
-                        impulse, c.mHalfNumCoefs, mBuffer.i16, inputIndex);
+                mInBuffer.template readAdvance<CHANNELS>(
+                        impulse, c.mHalfNumCoefs,
+                        reinterpret_cast<TI*>(mBuffer.raw), inputIndex);
                 phaseFraction -= phaseWrapLimit;
                 while (phaseFraction >= phaseWrapLimit) {
                     inputIndex++;
@@ -500,20 +491,21 @@
                         provider->releaseBuffer(&mBuffer);
                         break;
                     }
-                    mInBuffer.readAdvance<CHANNELS>(
-                            impulse, c.mHalfNumCoefs, mBuffer.i16, inputIndex);
+                    mInBuffer.template readAdvance<CHANNELS>(
+                            impulse, c.mHalfNumCoefs,
+                            reinterpret_cast<TI*>(mBuffer.raw), inputIndex);
                     phaseFraction -= phaseWrapLimit;
                 }
             }
         }
-        const int16_t* const in = mBuffer.i16;
+        const TI* const in = reinterpret_cast<const TI*>(mBuffer.raw);
         const size_t frameCount = mBuffer.frameCount;
         const int coefShift = c.mShift;
         const int halfNumCoefs = c.mHalfNumCoefs;
-        const int32_t* const volumeSimd = mVolumeSimd;
+        const TO* const volumeSimd = mVolumeSimd;
 
         // reread the last input in.
-        mInBuffer.readAgain<CHANNELS>(impulse, halfNumCoefs, in, inputIndex);
+        mInBuffer.template readAgain<CHANNELS>(impulse, halfNumCoefs, in, inputIndex);
 
         // main processing loop
         while (CC_LIKELY(outputIndex < outputSampleCount)) {
@@ -536,7 +528,7 @@
                 if (inputIndex >= frameCount) {
                     goto done;  // need a new buffer
                 }
-                mInBuffer.readAdvance<CHANNELS>(impulse, halfNumCoefs, in, inputIndex);
+                mInBuffer.template readAdvance<CHANNELS>(impulse, halfNumCoefs, in, inputIndex);
                 phaseFraction -= phaseWrapLimit;
             }
         }
@@ -555,5 +547,10 @@
     mPhaseFraction = phaseFraction;
 }
 
+/* instantiate templates used by AudioResampler::create */
+template class AudioResamplerDyn<float, float, float>;
+template class AudioResamplerDyn<int16_t, int16_t, int32_t>;
+template class AudioResamplerDyn<int32_t, int16_t, int32_t>;
+
 // ----------------------------------------------------------------------------
 }; // namespace android
diff --git a/services/audioflinger/AudioResamplerDyn.h b/services/audioflinger/AudioResamplerDyn.h
index df1fdbe..8c56319 100644
--- a/services/audioflinger/AudioResamplerDyn.h
+++ b/services/audioflinger/AudioResamplerDyn.h
@@ -25,10 +25,24 @@
 
 namespace android {
 
+/* AudioResamplerDyn
+ *
+ * This class template is used for floating point and integer resamplers.
+ *
+ * Type variables:
+ * TC = filter coefficient type (one of int16_t, int32_t, or float)
+ * TI = input data type (one of int16_t or float)
+ * TO = output data type (one of int32_t or float)
+ *
+ * For integer input data types TI, the coefficient type TC is either int16_t or int32_t.
+ * For float input data types TI, the coefficient type TC is float.
+ */
+
+template<typename TC, typename TI, typename TO>
 class AudioResamplerDyn: public AudioResampler {
 public:
-    AudioResamplerDyn(int bitDepth, int inChannelCount, int32_t sampleRate,
-            src_quality quality);
+    AudioResamplerDyn(int bitDepth, int inChannelCount,
+            int32_t sampleRate, src_quality quality);
 
     virtual ~AudioResamplerDyn();
 
@@ -46,46 +60,38 @@
     class Constants { // stores the filter constants.
     public:
         Constants() :
-            mL(0), mShift(0), mHalfNumCoefs(0), mFirCoefsS16(NULL)
+            mL(0), mShift(0), mHalfNumCoefs(0), mFirCoefs(NULL)
         {}
         void set(int L, int halfNumCoefs,
                 int inSampleRate, int outSampleRate);
-        inline void setBuf(int16_t* buf) {
-            mFirCoefsS16 = buf;
-        }
-        inline void setBuf(int32_t* buf) {
-            mFirCoefsS32 = buf;
-        }
 
-        int mL;       // interpolation phases in the filter.
-        int mShift;   // right shift to get polyphase index
+                 int mL;            // interpolation phases in the filter.
+                 int mShift;        // right shift to get polyphase index
         unsigned int mHalfNumCoefs; // filter half #coefs
-        union {       // polyphase filter bank
-            const int16_t* mFirCoefsS16;
-            const int32_t* mFirCoefsS32;
-        };
+           const TC* mFirCoefs;     // polyphase filter bank
     };
 
-    // Input buffer management for a given input type TI, now (int16_t)
-    // Is agnostic of the actual type, can work with int32_t and float.
-    template<typename TI>
-    class InBuffer {
+    class InBuffer { // buffer management for input type TI
     public:
         InBuffer();
         ~InBuffer();
         void init();
+
         void resize(int CHANNELS, int halfNumCoefs);
 
         // used for direct management of the mImpulse pointer
         inline TI* getImpulse() {
             return mImpulse;
         }
+
         inline void setImpulse(TI *impulse) {
             mImpulse = impulse;
         }
+
         template<int CHANNELS>
         inline void readAgain(TI*& impulse, const int halfNumCoefs,
                 const TI* const in, const size_t inputIndex);
+
         template<int CHANNELS>
         inline void readAdvance(TI*& impulse, const int halfNumCoefs,
                 const TI* const in, const size_t inputIndex);
@@ -94,31 +100,35 @@
         // tuning parameter guidelines: 2 <= multiple <= 8
         static const int kStateSizeMultipleOfFilterLength = 4;
 
-        TI* mState;    // base pointer for the input buffer storage
-        TI* mImpulse;  // current location of the impulse response (centered)
-        TI* mRingFull; // mState <= mImpulse < mRingFull
         // in general, mRingFull = mState + mStateSize - halfNumCoefs*CHANNELS.
-        size_t mStateSize; // in units of TI.
+           TI* mState;      // base pointer for the input buffer storage
+           TI* mImpulse;    // current location of the impulse response (centered)
+           TI* mRingFull;   // mState <= mImpulse < mRingFull
+        size_t mStateCount; // size of state in units of TI.
     };
 
-    template<int CHANNELS, bool LOCKED, int STRIDE, typename TC>
-    void resample(int32_t* out, size_t outFrameCount,
-            const TC* const coefs, AudioBufferProvider* provider);
-
-    template<typename T>
     void createKaiserFir(Constants &c, double stopBandAtten,
             int inSampleRate, int outSampleRate, double tbwCheat);
 
-    InBuffer<int16_t> mInBuffer;
-    Constants mConstants;  // current set of coefficient parameters
-    int32_t __attribute__ ((aligned (8))) mVolumeSimd[2];
-    int32_t mResampleType; // contains the resample type.
-    int32_t mFilterSampleRate; // designed filter sample rate.
-    src_quality mFilterQuality; // designed filter quality.
-    void* mCoefBuffer; // if a filter is created, this is not null
+    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
+    typedef void (AudioResamplerDyn<TC, TI, TO>::*resample_ABP_t)(TO* out,
+            size_t outFrameCount, AudioBufferProvider* provider);
+
+    // data - the contiguous storage and layout of these is important.
+           InBuffer mInBuffer;
+          Constants mConstants;        // current set of coefficient parameters
+    TO __attribute__ ((aligned (8))) mVolumeSimd[2]; // must be aligned or NEON may crash
+     resample_ABP_t mResampleFunc;     // called function for resampling
+            int32_t mFilterSampleRate; // designed filter sample rate.
+        src_quality mFilterQuality;    // designed filter quality.
+              void* mCoefBuffer;       // if a filter is created, this is not null
 };
 
-// ----------------------------------------------------------------------------
 }; // namespace android
 
 #endif /*ANDROID_AUDIO_RESAMPLER_DYN_H*/
diff --git a/services/audioflinger/AudioResamplerFirGen.h b/services/audioflinger/AudioResamplerFirGen.h
index fac3001..8833758 100644
--- a/services/audioflinger/AudioResamplerFirGen.h
+++ b/services/audioflinger/AudioResamplerFirGen.h
@@ -669,11 +669,12 @@
                 sg.advance();
             }
 
-            // (caution!) float version does not need rounding
             if (is_same<T, int16_t>::value) { // int16_t needs noise shaping
                 *coef++ = static_cast<T>(toint(y, 1ULL<<(sizeof(T)*8-1), err));
-            } else {
+            } else if (is_same<T, int32_t>::value) {
                 *coef++ = static_cast<T>(toint(y, 1ULL<<(sizeof(T)*8-1)));
+            } else { // assumed float or double
+                *coef++ = static_cast<T>(y);
             }
         }
     }
diff --git a/services/audioflinger/AudioResamplerFirProcess.h b/services/audioflinger/AudioResamplerFirProcess.h
index 38e387c..76d2d66 100644
--- a/services/audioflinger/AudioResamplerFirProcess.h
+++ b/services/audioflinger/AudioResamplerFirProcess.h
@@ -21,47 +21,55 @@
 
 // depends on AudioResamplerFirOps.h
 
-template<int CHANNELS, typename TC>
+/* variant for input type TI = int16_t input samples */
+template<typename TC>
 static inline
-void mac(
-        int32_t& l, int32_t& r,
-        const TC coef,
-        const int16_t* samples)
+void mac(int32_t& l, int32_t& r, TC coef, const int16_t* samples)
 {
-    if (CHANNELS == 2) {
-        uint32_t rl = *reinterpret_cast<const uint32_t*>(samples);
-        l = mulAddRL(1, rl, coef, l);
-        r = mulAddRL(0, rl, coef, r);
-    } else {
-        r = l = mulAdd(samples[0], coef, l);
-    }
+    uint32_t rl = *reinterpret_cast<const uint32_t*>(samples);
+    l = mulAddRL(1, rl, coef, l);
+    r = mulAddRL(0, rl, coef, r);
 }
 
-template<int CHANNELS, typename TC>
+template<typename TC>
 static inline
-void interpolate(
-        int32_t& l, int32_t& r,
-        const TC coef_0, const TC coef_1,
-        const int16_t lerp, const int16_t* samples)
+void mac(int32_t& l, TC coef, const int16_t* samples)
 {
-    TC sinc;
+    l = mulAdd(samples[0], coef, l);
+}
 
-    if (is_same<TC, int16_t>::value) {
-        sinc = (lerp * ((coef_1-coef_0)<<1)>>16) + coef_0;
-    } else {
-        sinc = mulAdd(lerp, (coef_1-coef_0)<<1, coef_0);
-    }
-    if (CHANNELS == 2) {
-        uint32_t rl = *reinterpret_cast<const uint32_t*>(samples);
-        l = mulAddRL(1, rl, sinc, l);
-        r = mulAddRL(0, rl, sinc, r);
-    } else {
-        r = l = mulAdd(samples[0], sinc, l);
-    }
+/* variant for input type TI = float input samples */
+template<typename TC>
+static inline
+void mac(float& l, float& r, TC coef,  const float* samples)
+{
+    l += *samples++ * coef;
+    r += *samples++ * coef;
+}
+
+template<typename TC>
+static inline
+void mac(float& l, TC coef,  const float* samples)
+{
+    l += *samples++ * coef;
+}
+
+/* variant for output type TO = int32_t output samples */
+static inline
+int32_t volumeAdjust(int32_t value, int32_t volume)
+{
+    return 2 * mulRL(0, value, volume);  // Note: only use top 16b
+}
+
+/* variant for output type TO = float output samples */
+static inline
+float volumeAdjust(float value, float volume)
+{
+    return value * volume;
 }
 
 /*
- * Calculates a single output sample (two stereo frames).
+ * Calculates a single output frame (two samples).
  *
  * This function computes both the positive half FIR dot product and
  * the negative half FIR dot product, accumulates, and then applies the volume.
@@ -72,30 +80,43 @@
  * filter bank.
  */
 
-template <int CHANNELS, int STRIDE, typename TC>
+template <int CHANNELS, int STRIDE, typename TC, typename TI, typename TO>
 static inline
-void ProcessL(int32_t* const out,
+void ProcessL(TO* const out,
         int count,
         const TC* coefsP,
         const TC* coefsN,
-        const int16_t* sP,
-        const int16_t* sN,
-        const int32_t* const volumeLR)
+        const TI* sP,
+        const TI* sN,
+        const TO* const volumeLR)
 {
-    int32_t l = 0;
-    int32_t r = 0;
-    do {
-        mac<CHANNELS>(l, r, *coefsP++, sP);
-        sP -= CHANNELS;
-        mac<CHANNELS>(l, r, *coefsN++, sN);
-        sN += CHANNELS;
-    } while (--count > 0);
-    out[0] += 2 * mulRL(0, l, volumeLR[0]); // Note: only use top 16b
-    out[1] += 2 * mulRL(0, r, volumeLR[1]); // Note: only use top 16b
+    COMPILE_TIME_ASSERT_FUNCTION_SCOPE(CHANNELS >= 1 && CHANNELS <= 2)
+    if (CHANNELS == 2) {
+        TO l = 0;
+        TO r = 0;
+        do {
+            mac(l, r, *coefsP++, sP);
+            sP -= CHANNELS;
+            mac(l, r, *coefsN++, sN);
+            sN += CHANNELS;
+        } while (--count > 0);
+        out[0] += volumeAdjust(l, volumeLR[0]);
+        out[1] += volumeAdjust(r, volumeLR[1]);
+    } else { /* CHANNELS == 1 */
+        TO l = 0;
+        do {
+            mac(l, *coefsP++, sP);
+            sP -= CHANNELS;
+            mac(l, *coefsN++, sN);
+            sN += CHANNELS;
+        } while (--count > 0);
+        out[0] += volumeAdjust(l, volumeLR[0]);
+        out[1] += volumeAdjust(l, volumeLR[1]);
+    }
 }
 
 /*
- * Calculates a single output sample (two stereo frames) interpolating phase.
+ * Calculates a single output frame (two samples) interpolating phase.
  *
  * This function computes both the positive half FIR dot product and
  * the negative half FIR dot product, accumulates, and then applies the volume.
@@ -106,47 +127,91 @@
  * filter bank.
  */
 
-template <int CHANNELS, int STRIDE, typename TC>
+template<typename TC, typename T>
+void adjustLerp(T& lerpP __unused)
+{
+}
+
+template<int32_t, typename T>
+void adjustLerp(T& lerpP)
+{
+    lerpP >>= 16;   // lerpP is 32bit for NEON int32_t, but always 16 bit for non-NEON path
+}
+
+template<typename TC, typename TINTERP>
 static inline
-void Process(int32_t* const out,
+TC interpolate(TC coef_0, TC coef_1, TINTERP lerp)
+{
+    return lerp * (coef_1 - coef_0) + coef_0;
+}
+
+template<int16_t, uint32_t>
+static inline
+int16_t interpolate(int16_t coef_0, int16_t coef_1, uint32_t lerp)
+{
+    return (static_cast<int16_t>(lerp) * ((coef_1-coef_0)<<1)>>16) + coef_0;
+}
+
+template<int32_t, uint32_t>
+static inline
+int32_t interpolate(int32_t coef_0, int32_t coef_1, uint32_t lerp)
+{
+    return mulAdd(static_cast<int16_t>(lerp), (coef_1-coef_0)<<1, coef_0);
+}
+
+template <int CHANNELS, int STRIDE, typename TC, typename TI, typename TO, typename TINTERP>
+static inline
+void Process(TO* const out,
         int count,
         const TC* coefsP,
         const TC* coefsN,
-        const TC* coefsP1,
-        const TC* coefsN1,
-        const int16_t* sP,
-        const int16_t* sN,
-        uint32_t lerpP,
-        const int32_t* const volumeLR)
+        const TC* coefsP1 __unused,
+        const TC* coefsN1 __unused,
+        const TI* sP,
+        const TI* sN,
+        TINTERP lerpP,
+        const TO* const volumeLR)
 {
-    (void) coefsP1; // suppress unused parameter warning
-    (void) coefsN1;
-    if (sizeof(*coefsP)==4) {
-        lerpP >>= 16;   // ensure lerpP is 16b
+    COMPILE_TIME_ASSERT_FUNCTION_SCOPE(CHANNELS >= 1 && CHANNELS <= 2)
+    adjustLerp<TC, TINTERP>(lerpP); // coefficient type adjustment for interpolation
+
+    if (CHANNELS == 2) {
+        TO l = 0;
+        TO r = 0;
+        for (size_t i = 0; i < count; ++i) {
+            mac(l, r, interpolate(coefsP[0], coefsP[count], lerpP), sP);
+            coefsP++;
+            sP -= CHANNELS;
+            mac(l, r, interpolate(coefsN[count], coefsN[0], lerpP), sN);
+            coefsN++;
+            sN += CHANNELS;
+        }
+        out[0] += volumeAdjust(l, volumeLR[0]);
+        out[1] += volumeAdjust(r, volumeLR[1]);
+    } else { /* CHANNELS == 1 */
+        TO l = 0;
+        for (size_t i = 0; i < count; ++i) {
+            mac(l, interpolate(coefsP[0], coefsP[count], lerpP), sP);
+            coefsP++;
+            sP -= CHANNELS;
+            mac(l, interpolate(coefsN[count], coefsN[0], lerpP), sN);
+            coefsN++;
+            sN += CHANNELS;
+        }
+        out[0] += volumeAdjust(l, volumeLR[0]);
+        out[1] += volumeAdjust(l, volumeLR[1]);
     }
-    int32_t l = 0;
-    int32_t r = 0;
-    for (size_t i = 0; i < count; ++i) {
-        interpolate<CHANNELS>(l, r, coefsP[0], coefsP[count], lerpP, sP);
-        coefsP++;
-        sP -= CHANNELS;
-        interpolate<CHANNELS>(l, r, coefsN[count], coefsN[0], lerpP, sN);
-        coefsN++;
-        sN += CHANNELS;
-    }
-    out[0] += 2 * mulRL(0, l, volumeLR[0]); // Note: only use top 16b
-    out[1] += 2 * mulRL(0, r, volumeLR[1]); // Note: only use top 16b
 }
 
 /*
- * Calculates a single output sample (two stereo frames) from input sample pointer.
+ * Calculates a single output frame (two samples) from input sample pointer.
  *
  * This sets up the params for the accelerated Process() and ProcessL()
  * functions to do the appropriate dot products.
  *
- * @param out should point to the output buffer with at least enough space for 2 output frames.
+ * @param out should point to the output buffer with space for at least one output frame.
  *
- * @param phase is the fractional distance between input samples for interpolation:
+ * @param phase is the fractional distance between input frames for interpolation:
  * phase >= 0  && phase < phaseWrapLimit.  It can be thought of as a rational fraction
  * of phase/phaseWrapLimit.
  *
@@ -195,14 +260,17 @@
  * lerpP = phase << sizeof(phase)*8 - coefShift
  *              >> (sizeof(phase)-sizeof(*coefs))*8 + 1;
  *
+ * For floating point, lerpP is the fractional phase scaled to [0.0, 1.0):
+ *
+ * lerpP = (phase << 32 - coefShift) / (1 << 32); // floating point equivalent
  */
 
-template<int CHANNELS, bool LOCKED, int STRIDE, typename TC>
+template<int CHANNELS, bool LOCKED, int STRIDE, typename TC, typename TI, typename TO>
 static inline
-void fir(int32_t* const out,
+void fir(TO* const out,
         const uint32_t phase, const uint32_t phaseWrapLimit,
         const int coefShift, const int halfNumCoefs, const TC* const coefs,
-        const int16_t* const samples, const int32_t* const volumeLR)
+        const TI* const samples, const TO* const volumeLR)
 {
     // NOTE: be very careful when modifying the code here. register
     // pressure is very high and a small change might cause the compiler
@@ -216,8 +284,8 @@
         uint32_t indexN = (phaseWrapLimit - phase) >> coefShift;
         const TC* coefsP = coefs + indexP*halfNumCoefs;
         const TC* coefsN = coefs + indexN*halfNumCoefs;
-        const int16_t* sP = samples;
-        const int16_t* sN = samples + CHANNELS;
+        const TI* sP = samples;
+        const TI* sN = samples + CHANNELS;
 
         // dot product filter.
         ProcessL<CHANNELS, STRIDE>(out,
@@ -231,8 +299,8 @@
         const TC* coefsN = coefs + indexN*halfNumCoefs;
         const TC* coefsP1 = coefsP + halfNumCoefs;
         const TC* coefsN1 = coefsN + halfNumCoefs;
-        const int16_t* sP = samples;
-        const int16_t* sN = samples + CHANNELS;
+        const TI* sP = samples;
+        const TI* sN = samples + CHANNELS;
 
         // Interpolation fraction lerpP derived by shifting all the way up and down
         // to clear the appropriate bits and align to the appropriate level
@@ -242,12 +310,21 @@
         //
         // interpolated[P] = index[P]*lerpP + index[P+1]*(1-lerpP)
         // interpolated[N] = index[N+1]*lerpP + index[N]*(1-lerpP)
-        uint32_t lerpP = phase << (sizeof(phase)*8 - coefShift)
-                >> ((sizeof(phase)-sizeof(*coefs))*8 + 1);
 
         // on-the-fly interpolated dot product filter
-        Process<CHANNELS, STRIDE>(out,
-                halfNumCoefs, coefsP, coefsN, coefsP1, coefsN1, sP, sN, lerpP, volumeLR);
+        if (is_same<TC, float>::value || is_same<TC, double>::value) {
+            static const TC scale = 1. / (65536. * 65536.); // scale phase bits to [0.0, 1.0)
+            TC lerpP = TC(phase << (sizeof(phase)*8 - coefShift)) * scale;
+
+            Process<CHANNELS, STRIDE>(out,
+                    halfNumCoefs, coefsP, coefsN, coefsP1, coefsN1, sP, sN, lerpP, volumeLR);
+        } else {
+            uint32_t lerpP = phase << (sizeof(phase)*8 - coefShift)
+                    >> ((sizeof(phase)-sizeof(*coefs))*8 + 1);
+
+            Process<CHANNELS, STRIDE>(out,
+                    halfNumCoefs, coefsP, coefsN, coefsP1, coefsN1, sP, sN, lerpP, volumeLR);
+        }
     }
 }
 
diff --git a/services/audioflinger/test-resample.cpp b/services/audioflinger/test-resample.cpp
index 7b7cdac..d1de95d 100644
--- a/services/audioflinger/test-resample.cpp
+++ b/services/audioflinger/test-resample.cpp
@@ -24,20 +24,25 @@
 #include <sys/mman.h>
 #include <sys/stat.h>
 #include <errno.h>
+#include <inttypes.h>
 #include <time.h>
 #include <math.h>
+#include <audio_utils/primitives.h>
 #include <audio_utils/sndfile.h>
 #include <utils/Vector.h>
 
 using namespace android;
 
-bool gVerbose = false;
+static bool gVerbose = false;
 
 static int usage(const char* name) {
-    fprintf(stderr,"Usage: %s [-p] [-h] [-v] [-s] [-q {dq|lq|mq|hq|vhq|dlq|dmq|dhq}]"
-                   " [-i input-sample-rate] [-o output-sample-rate] [-O csv] [-P csv] [<input-file>]"
+    fprintf(stderr,"Usage: %s [-p] [-f] [-F] [-h] [-v] [-s] [-q {dq|lq|mq|hq|vhq|dlq|dmq|dhq}]"
+                   " [-i input-sample-rate] [-o output-sample-rate]"
+                   " [-O csv] [-P csv] [<input-file>]"
                    " <output-file>\n", name);
     fprintf(stderr,"    -p    enable profiling\n");
+    fprintf(stderr,"    -f    enable filter profiling\n");
+    fprintf(stderr,"    -F    enable floating point -q {dlq|dmq|dhq} only");
     fprintf(stderr,"    -h    create wav file\n");
     fprintf(stderr,"    -v    verbose : log buffer provider calls\n");
     fprintf(stderr,"    -s    stereo (ignored if input file is specified)\n");
@@ -102,6 +107,7 @@
     bool profileResample = false;
     bool profileFilter = false;
     bool writeHeader = false;
+    bool useFloat = false;
     int channels = 1;
     int input_freq = 0;
     int output_freq = 0;
@@ -110,7 +116,7 @@
     Vector<int> Pvalues;
 
     int ch;
-    while ((ch = getopt(argc, argv, "pfhvsq:i:o:O:P:")) != -1) {
+    while ((ch = getopt(argc, argv, "pfFhvsq:i:o:O:P:")) != -1) {
         switch (ch) {
         case 'p':
             profileResample = true;
@@ -118,6 +124,9 @@
         case 'f':
             profileFilter = true;
             break;
+        case 'F':
+            useFloat = true;
+            break;
         case 'h':
             writeHeader = true;
             break;
@@ -173,6 +182,12 @@
             return -1;
         }
     }
+
+    if (useFloat && quality < AudioResampler::DYN_LOW_QUALITY) {
+        fprintf(stderr, "float processing is only possible for dynamic resamplers\n");
+        return -1;
+    }
+
     argc -= optind;
     argv += optind;
 
@@ -224,22 +239,37 @@
             }
         }
     }
+    size_t frame_size = channels * sizeof(int16_t);
+    size_t input_frames = input_size / frame_size;
+
+    // For float processing, convert input int16_t to float array
+    if (useFloat) {
+        void *new_vaddr;
+
+        frame_size = channels * sizeof(float);
+        input_size = input_frames * frame_size;
+        new_vaddr = malloc(input_size);
+        memcpy_to_float_from_i16(reinterpret_cast<float*>(new_vaddr),
+                reinterpret_cast<int16_t*>(input_vaddr), input_frames * channels);
+        free(input_vaddr);
+        input_vaddr = new_vaddr;
+    }
 
     // ----------------------------------------------------------
 
     class Provider: public AudioBufferProvider {
-        int16_t* const  mAddr;      // base address
+        const void*     mAddr;      // base address
         const size_t    mNumFrames; // total frames
-        const int       mChannels;
+        const size_t    mFrameSize; // size of each frame in bytes
         size_t          mNextFrame; // index of next frame to provide
         size_t          mUnrel;     // number of frames not yet released
         const Vector<int> mPvalues; // number of frames provided per call
         size_t          mNextPidx;  // index of next entry in mPvalues to use
     public:
-        Provider(const void* addr, size_t size, int channels, const Vector<int>& Pvalues)
-          : mAddr((int16_t*) addr),
-            mNumFrames(size / (channels*sizeof(int16_t))),
-            mChannels(channels),
+        Provider(const void* addr, size_t frames, size_t frameSize, const Vector<int>& Pvalues)
+          : mAddr(addr),
+            mNumFrames(frames),
+            mFrameSize(frameSize),
             mNextFrame(0), mUnrel(0), mPvalues(Pvalues), mNextPidx(0) {
         }
         virtual status_t getNextBuffer(Buffer* buffer,
@@ -251,7 +281,7 @@
             }
             if (!mPvalues.isEmpty()) {
                 size_t provided = mPvalues[mNextPidx++];
-                printf("mPvalue[%d]=%u not %u\n", mNextPidx-1, provided, buffer->frameCount);
+                printf("mPvalue[%zu]=%zu not %zu\n", mNextPidx-1, provided, buffer->frameCount);
                 if (provided < buffer->frameCount) {
                     buffer->frameCount = provided;
                 }
@@ -260,45 +290,46 @@
                 }
             }
             if (gVerbose) {
-                printf("getNextBuffer() requested %u frames out of %u frames available,"
-                        " and returned %u frames\n",
-                        requestedFrames, mNumFrames - mNextFrame, buffer->frameCount);
+                printf("getNextBuffer() requested %zu frames out of %zu frames available,"
+                        " and returned %zu frames\n",
+                        requestedFrames, (size_t) (mNumFrames - mNextFrame), buffer->frameCount);
             }
             mUnrel = buffer->frameCount;
             if (buffer->frameCount > 0) {
-                buffer->i16 = &mAddr[mChannels * mNextFrame];
+                buffer->raw = (char *)mAddr + mFrameSize * mNextFrame;
                 return NO_ERROR;
             } else {
-                buffer->i16 = NULL;
+                buffer->raw = NULL;
                 return NOT_ENOUGH_DATA;
             }
         }
         virtual void releaseBuffer(Buffer* buffer) {
             if (buffer->frameCount > mUnrel) {
-                fprintf(stderr, "ERROR releaseBuffer() released %u frames but only %u available "
+                fprintf(stderr, "ERROR releaseBuffer() released %zu frames but only %zu available "
                         "to release\n", buffer->frameCount, mUnrel);
                 mNextFrame += mUnrel;
                 mUnrel = 0;
             } else {
                 if (gVerbose) {
-                    printf("releaseBuffer() released %u frames out of %u frames available "
+                    printf("releaseBuffer() released %zu frames out of %zu frames available "
                             "to release\n", buffer->frameCount, mUnrel);
                 }
                 mNextFrame += buffer->frameCount;
                 mUnrel -= buffer->frameCount;
             }
             buffer->frameCount = 0;
-            buffer->i16 = NULL;
+            buffer->raw = NULL;
         }
         void reset() {
             mNextFrame = 0;
         }
-    } provider(input_vaddr, input_size, channels, Pvalues);
+    } provider(input_vaddr, input_frames, frame_size, Pvalues);
 
-    size_t input_frames = input_size / (channels * sizeof(int16_t));
     if (gVerbose) {
-        printf("%u input frames\n", input_frames);
+        printf("%zu input frames\n", input_frames);
     }
+
+    int bit_depth = useFloat ? 32 : 16;
     size_t output_size = 2 * 4 * ((int64_t) input_frames * output_freq) / input_freq;
     output_size &= ~7; // always stereo, 32-bits
 
@@ -309,7 +340,7 @@
         //
         // On fast devices, filters should be generated between 0.1ms - 1ms.
         // (single threaded).
-        AudioResampler* resampler = AudioResampler::create(16, channels,
+        AudioResampler* resampler = AudioResampler::create(bit_depth, channels,
                 8000, quality);
         int looplimit = 100;
         timespec start, end;
@@ -347,7 +378,7 @@
     }
 
     void* output_vaddr = malloc(output_size);
-    AudioResampler* resampler = AudioResampler::create(16, channels,
+    AudioResampler* resampler = AudioResampler::create(bit_depth, channels,
             output_freq, quality);
     size_t out_frames = output_size/8;
 
@@ -386,7 +417,7 @@
         const int trials = 4;
         const int looplimit = 4;
         timespec start, end;
-        int64_t time;
+        int64_t time = 0;
 
         for (int n = 0; n < trials; ++n) {
             clock_gettime(CLOCK_MONOTONIC, &start);
@@ -403,14 +434,14 @@
             }
         }
         // Mfrms/s is "Millions of output frames per second".
-        printf("quality: %d  channels: %d  msec: %lld  Mfrms/s: %.2lf\n",
+        printf("quality: %d  channels: %d  msec: %" PRId64 "  Mfrms/s: %.2lf\n",
                 quality, channels, time/1000000, out_frames * looplimit / (time / 1e9) / 1e6);
         resampler->reset();
     }
 
     memset(output_vaddr, 0, output_size);
     if (gVerbose) {
-        printf("resample() %u output frames\n", out_frames);
+        printf("resample() %zu output frames\n", out_frames);
     }
     if (Ovalues.isEmpty()) {
         Ovalues.push(out_frames);
@@ -436,6 +467,13 @@
     delete resampler;
     resampler = NULL;
 
+    // For float processing, convert output format from float to Q4.27,
+    // which is then converted to int16_t for final storage.
+    if (useFloat) {
+        memcpy_to_q4_27_from_float(reinterpret_cast<int32_t*>(output_vaddr),
+                reinterpret_cast<float*>(output_vaddr), out_frames * 2); // stereo samples
+    }
+
     // mono takes left channel only
     // stereo right channel is half amplitude of stereo left channel (due to input creation)
     int32_t* out = (int32_t*) output_vaddr;