Code drop from //branches/cupcake/...@124589
diff --git a/libs/audioflinger/A2dpAudioInterface.cpp b/libs/audioflinger/A2dpAudioInterface.cpp
new file mode 100644
index 0000000..d54795c
--- /dev/null
+++ b/libs/audioflinger/A2dpAudioInterface.cpp
@@ -0,0 +1,186 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <math.h>
+
+#define LOG_NDEBUG 0
+#define LOG_TAG "A2dpAudioInterface"
+#include <utils/Log.h>
+#include <utils/String8.h>
+
+#include "A2dpAudioInterface.h"
+#include "audio/liba2dp.h"
+
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+
+A2dpAudioInterface::A2dpAudioInterface() :
+    mOutput(0)
+{
+}
+
+A2dpAudioInterface::~A2dpAudioInterface()
+{
+    delete mOutput;
+}
+
+status_t A2dpAudioInterface::initCheck()
+{
+    return 0;
+}
+
+AudioStreamOut* A2dpAudioInterface::openOutputStream(
+        int format, int channelCount, uint32_t sampleRate, status_t *status)
+{
+    LOGD("A2dpAudioInterface::openOutputStream %d, %d, %d\n", format, channelCount, sampleRate);
+    Mutex::Autolock lock(mLock);
+    status_t err = 0;
+
+    // only one output stream allowed
+    if (mOutput) {
+        if (status)
+            *status = -1;
+        return NULL;
+    }
+
+    // create new output stream
+    A2dpAudioStreamOut* out = new A2dpAudioStreamOut();
+    if ((err = out->set(format, channelCount, sampleRate)) == NO_ERROR) {
+        mOutput = out;
+    } else {
+        delete out;
+    }
+    
+    if (status)
+        *status = err;
+    return mOutput;
+}
+
+AudioStreamIn* A2dpAudioInterface::openInputStream(
+        int format, int channelCount, uint32_t sampleRate, status_t *status)
+{
+    if (status)
+        *status = -1;
+    return NULL;
+}
+
+status_t A2dpAudioInterface::standby()
+{
+    return 0;
+}
+
+status_t A2dpAudioInterface::setMicMute(bool state)
+{
+    return 0;
+}
+
+status_t A2dpAudioInterface::getMicMute(bool* state)
+{
+    return 0;
+}
+
+status_t A2dpAudioInterface::setParameter(const char *key, const char *value)
+{
+    LOGD("setParameter %s,%s\n", key, value);
+    return 0;
+}
+
+status_t A2dpAudioInterface::setVoiceVolume(float v)
+{
+    return 0;
+}
+
+status_t A2dpAudioInterface::setMasterVolume(float v)
+{
+    return 0;
+}
+
+status_t A2dpAudioInterface::doRouting()
+{
+    return 0;
+}
+
+status_t A2dpAudioInterface::dump(int fd, const Vector<String16>& args)
+{
+    return 0;
+}
+
+// ----------------------------------------------------------------------------
+
+A2dpAudioInterface::A2dpAudioStreamOut::A2dpAudioStreamOut() :
+    mFd(-1), mStartCount(0), mRetryCount(0), mData(NULL),
+    mInitialized(false), mBufferRemaining(0)
+{
+}
+
+status_t A2dpAudioInterface::A2dpAudioStreamOut::set(
+        int format, int channels, uint32_t rate)
+{
+    LOGD("A2dpAudioStreamOut::set %d, %d, %d\n", format, channels, rate);
+
+    // fix up defaults
+    if (format == 0) format = AudioSystem::PCM_16_BIT;
+    if (channels == 0) channels = channelCount();
+    if (rate == 0) rate = sampleRate();
+
+    // check values
+    if ((format != AudioSystem::PCM_16_BIT) ||
+            (channels != channelCount()) ||
+            (rate != sampleRate()))
+        return BAD_VALUE;
+
+    return NO_ERROR;
+}
+
+A2dpAudioInterface::A2dpAudioStreamOut::~A2dpAudioStreamOut()
+{
+    if (mData)
+        a2dp_cleanup(mData);
+}
+
+ssize_t A2dpAudioInterface::A2dpAudioStreamOut::write(const void* buffer, size_t bytes)
+{    
+    if (!mInitialized) {
+        int ret = a2dp_init("00:00:00:00:00:00", 44100, 2, &mData);
+        if (ret)
+            return ret;
+        mInitialized = true;
+    }
+    
+    size_t remaining = bytes;
+    while (remaining > 0) {
+        int written = a2dp_write(mData, buffer, remaining);        
+        remaining -= written;
+        buffer = ((char *)buffer) + written;
+    }
+    
+    return bytes;
+}
+
+status_t A2dpAudioInterface::A2dpAudioStreamOut::standby()
+{
+    return 0;
+}
+
+status_t A2dpAudioInterface::A2dpAudioStreamOut::dump(int fd, const Vector<String16>& args)
+{
+    return NO_ERROR;
+}
+
+
+}; // namespace android
diff --git a/libs/audioflinger/A2dpAudioInterface.h b/libs/audioflinger/A2dpAudioInterface.h
new file mode 100644
index 0000000..03bf933
--- /dev/null
+++ b/libs/audioflinger/A2dpAudioInterface.h
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef A2DP_AUDIO_HARDWARE_H
+#define A2DP_AUDIO_HARDWARE_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/threads.h>
+
+#include <hardware/AudioHardwareBase.h>
+
+
+namespace android {
+
+class A2dpAudioInterface : public AudioHardwareBase
+{
+    class A2dpAudioStreamOut;
+
+public:
+                        A2dpAudioInterface();
+    virtual             ~A2dpAudioInterface();
+    virtual status_t    initCheck();
+    virtual status_t    standby();
+
+    virtual status_t    setVoiceVolume(float volume);
+    virtual status_t    setMasterVolume(float volume);
+
+    // mic mute
+    virtual status_t    setMicMute(bool state);
+    virtual status_t    getMicMute(bool* state);
+
+    // Temporary interface, do not use
+    // TODO: Replace with a more generic key:value get/set mechanism
+    virtual status_t    setParameter(const char *key, const char *value);
+
+    // create I/O streams
+    virtual AudioStreamOut* openOutputStream(
+                                int format=0,
+                                int channelCount=0,
+                                uint32_t sampleRate=0,
+                                status_t *status=0);
+
+    virtual AudioStreamIn* openInputStream(
+                                int format,
+                                int channelCount,
+                                uint32_t sampleRate,
+                                status_t *status);
+
+protected:
+    virtual status_t    doRouting();
+    virtual status_t    dump(int fd, const Vector<String16>& args);
+
+private:
+    class A2dpAudioStreamOut : public AudioStreamOut {
+    public:
+                            A2dpAudioStreamOut();
+        virtual             ~A2dpAudioStreamOut();
+                status_t    set(int format,
+                                int channelCount,
+                                uint32_t sampleRate);
+        virtual uint32_t    sampleRate() const { return 44100; }
+        // must be 32-bit aligned - driver only seems to like 4800
+        virtual size_t      bufferSize() const { return 5120; }
+        virtual int         channelCount() const { return 2; }
+        virtual int         format() const { return AudioSystem::PCM_16_BIT; }
+        virtual uint32_t    latency() const { return 0; }
+        virtual status_t    setVolume(float volume) { return INVALID_OPERATION; }
+        virtual ssize_t     write(const void* buffer, size_t bytes);
+                status_t    standby();
+        virtual status_t    dump(int fd, const Vector<String16>& args);
+
+    private:
+                int         mFd;
+                int         mStartCount;
+                int         mRetryCount;
+                void*       mData;
+                bool        mInitialized;
+
+#define kBufferSize 50000
+                char                    mBuffer[kBufferSize];
+                int                     mBufferRemaining;
+    };
+
+    Mutex                   mLock;
+    A2dpAudioStreamOut*     mOutput;
+};
+
+// ----------------------------------------------------------------------------
+
+}; // namespace android
+
+#endif // A2DP_AUDIO_HARDWARE_H
diff --git a/libs/audioflinger/Android.mk b/libs/audioflinger/Android.mk
index a9cb303..d16e3e1 100644
--- a/libs/audioflinger/Android.mk
+++ b/libs/audioflinger/Android.mk
@@ -45,9 +45,12 @@
 
 LOCAL_MODULE:= libaudioflinger
 
-ifeq ($(TARGET_ARCH),arm)  # not simulator
-  LOCAL_CFLAGS += -DWITH_BLUETOOTH
+ifeq ($(BOARD_HAVE_BLUETOOTH),true)
+  LOCAL_SRC_FILES += A2dpAudioInterface.cpp
+  LOCAL_SHARED_LIBRARIES += liba2dp
+  LOCAL_CFLAGS += -DWITH_BLUETOOTH -DWITH_A2DP
   LOCAL_C_INCLUDES += $(call include-path-for, bluez-libs)
+  LOCAL_C_INCLUDES += $(call include-path-for, bluez-utils)
 endif
 
 include $(BUILD_SHARED_LIBRARY)
diff --git a/libs/audioflinger/AudioDumpInterface.cpp b/libs/audioflinger/AudioDumpInterface.cpp
index 5ff2f18..8eee9cc 100644
--- a/libs/audioflinger/AudioDumpInterface.cpp
+++ b/libs/audioflinger/AudioDumpInterface.cpp
@@ -2,16 +2,16 @@
 **
 ** Copyright 2008, The Android Open Source Project
 **
-** Licensed under the Apache License, Version 2.0 (the "License"); 
-** you may not use this file except in compliance with the License. 
-** You may obtain a copy of the License at 
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
 **
-**     http://www.apache.org/licenses/LICENSE-2.0 
+**     http://www.apache.org/licenses/LICENSE-2.0
 **
-** Unless required by applicable law or agreed to in writing, software 
-** distributed under the License is distributed on an "AS IS" BASIS, 
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
-** See the License for the specific language governing permissions and 
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
 ** limitations under the License.
 */
 
@@ -28,6 +28,8 @@
 
 namespace android {
 
+bool gFirst = true;       // true if first write after a standby
+
 // ----------------------------------------------------------------------------
 
 AudioDumpInterface::AudioDumpInterface(AudioHardwareInterface* hw)
@@ -40,17 +42,25 @@
 }
 
 
+AudioDumpInterface::~AudioDumpInterface()
+{
+    if(mFinalInterface) delete mFinalInterface;
+    if(mStreamOut) delete mStreamOut;
+}
+
+
 status_t AudioDumpInterface::standby()
 {
     if(mStreamOut)  mStreamOut->Close();
+    gFirst = true;
     return mFinalInterface->standby();
 }
 
 
 AudioStreamOut* AudioDumpInterface::openOutputStream(
-        int format, int channelCount, uint32_t sampleRate)
+        int format, int channelCount, uint32_t sampleRate, status_t *status)
 {
-    AudioStreamOut* outFinal = mFinalInterface->openOutputStream(format, channelCount, sampleRate);
+    AudioStreamOut* outFinal = mFinalInterface->openOutputStream(format, channelCount, sampleRate, status);
 
     if(outFinal) {
         mStreamOut =  new AudioStreamOutDump(outFinal);
@@ -69,13 +79,26 @@
     mOutFile = 0;
 }
 
+
+AudioStreamOutDump::~AudioStreamOutDump()
+{
+    Close();
+    delete mFinalStream;
+}
+
 ssize_t AudioStreamOutDump::write(const void* buffer, size_t bytes)
 {
     ssize_t ret;
-    
+
     ret = mFinalStream->write(buffer, bytes);
-    if(!mOutFile) {
-        mOutFile = fopen(FLINGER_DUMP_NAME, "ab");
+    if(!mOutFile && gFirst) {
+        gFirst = false;
+        // check if dump file exist
+        mOutFile = fopen(FLINGER_DUMP_NAME, "r");
+        if(mOutFile) {
+            fclose(mOutFile);
+            mOutFile = fopen(FLINGER_DUMP_NAME, "ab");
+        }
     }
     if (mOutFile) {
         fwrite(buffer, bytes, 1, mOutFile);
diff --git a/libs/audioflinger/AudioDumpInterface.h b/libs/audioflinger/AudioDumpInterface.h
index 732b97d..a65e56a 100644
--- a/libs/audioflinger/AudioDumpInterface.h
+++ b/libs/audioflinger/AudioDumpInterface.h
@@ -2,16 +2,16 @@
 **
 ** Copyright 2008, The Android Open Source Project
 **
-** Licensed under the Apache License, Version 2.0 (the "License"); 
-** you may not use this file except in compliance with the License. 
-** You may obtain a copy of the License at 
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
 **
-**     http://www.apache.org/licenses/LICENSE-2.0 
+**     http://www.apache.org/licenses/LICENSE-2.0
 **
-** Unless required by applicable law or agreed to in writing, software 
-** distributed under the License is distributed on an "AS IS" BASIS, 
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
-** See the License for the specific language governing permissions and 
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
 ** limitations under the License.
 */
 
@@ -21,33 +21,35 @@
 #include <stdint.h>
 #include <sys/types.h>
 
-#include <hardware/AudioHardwareInterface.h>
+#include <hardware/AudioHardwareBase.h>
 
 namespace android {
 
-#define FLINGER_DUMP_NAME "/tmp/FlingerOut.pcm" // name of file used for dump
+#define FLINGER_DUMP_NAME "/data/FlingerOut.pcm" // name of file used for dump
 
 class AudioStreamOutDump : public AudioStreamOut {
 public:
                         AudioStreamOutDump( AudioStreamOut* FinalStream);
+                        ~AudioStreamOutDump();
                         virtual ssize_t     write(const void* buffer, size_t bytes);
-                        
+
     virtual uint32_t    sampleRate() const { return mFinalStream->sampleRate(); }
     virtual size_t      bufferSize() const { return mFinalStream->bufferSize(); }
     virtual int         channelCount() const { return mFinalStream->channelCount(); }
     virtual int         format() const { return mFinalStream->format(); }
+    virtual uint32_t    latency() const { return mFinalStream->latency(); }
     virtual status_t    setVolume(float volume)
                             { return mFinalStream->setVolume(volume); }
     virtual status_t    dump(int fd, const Vector<String16>& args) { return mFinalStream->dump(fd, args); }
     void                Close(void);
 
 private:
-    AudioStreamOut  *mFinalStream;
-    FILE            *mOutFile;     // output file
+    AudioStreamOut      *mFinalStream;
+    FILE                *mOutFile;     // output file
 };
 
 
-class AudioDumpInterface : public  AudioHardwareInterface
+class AudioDumpInterface : public AudioHardwareBase
 {
 
 public:
@@ -56,10 +58,10 @@
     virtual AudioStreamOut* openOutputStream(
                                 int format=0,
                                 int channelCount=0,
-                                uint32_t sampleRate=0);
+                                uint32_t sampleRate=0,
+                                status_t *status=0);
+    virtual             ~AudioDumpInterface();
 
-    virtual             ~AudioDumpInterface()
-                            {delete mFinalInterface;}
     virtual status_t    initCheck()
                             {return mFinalInterface->initCheck();}
     virtual status_t    setVoiceVolume(float volume)
@@ -67,13 +69,6 @@
     virtual status_t    setMasterVolume(float volume)
                             {return mFinalInterface->setMasterVolume(volume);}
 
-    virtual status_t    setRouting(int mode, uint32_t routes)
-                            {return mFinalInterface->setRouting(mode, routes);}
-    virtual status_t    getRouting(int mode, uint32_t* routes)
-                            {return mFinalInterface->getRouting(mode, routes);}
-    virtual status_t    getMode(int* mode)
-                            {return mFinalInterface->getMode(mode);}
-    
     // mic mute
     virtual status_t    setMicMute(bool state)
                             {return mFinalInterface->setMicMute(state);}
@@ -83,17 +78,17 @@
     virtual status_t    setParameter(const char* key, const char* value)
                             {return mFinalInterface->setParameter(key, value);}
 
-    virtual AudioStreamIn* openInputStream( int format, int channelCount, uint32_t sampleRate)
-                            {return mFinalInterface->openInputStream( format, channelCount, sampleRate);}
+    virtual AudioStreamIn* openInputStream( int format, int channelCount, uint32_t sampleRate, status_t *status)
+                            {return mFinalInterface->openInputStream( format, channelCount, sampleRate, status);}
 
     virtual status_t    dump(int fd, const Vector<String16>& args) { return mFinalInterface->dumpState(fd, args); }
 
 protected:
-    virtual status_t    doRouting() {return 0;}
-    
+    virtual status_t    doRouting() {return mFinalInterface->setRouting(mMode, mRoutes[mMode]);}
+
     AudioHardwareInterface  *mFinalInterface;
     AudioStreamOutDump      *mStreamOut;
-    
+
 };
 
 }; // namespace android
diff --git a/libs/audioflinger/AudioFlinger.cpp b/libs/audioflinger/AudioFlinger.cpp
index fb21629..53b18ad 100644
--- a/libs/audioflinger/AudioFlinger.cpp
+++ b/libs/audioflinger/AudioFlinger.cpp
@@ -31,6 +31,8 @@
 #include <utils/String16.h>
 #include <utils/threads.h>
 
+#include <cutils/properties.h>
+
 #include <media/AudioTrack.h>
 #include <media/AudioRecord.h>
 
@@ -41,9 +43,13 @@
 #include "AudioMixer.h"
 #include "AudioFlinger.h"
 
+#ifdef WITH_A2DP
+#include "A2dpAudioInterface.h"
+#endif
+
 namespace android {
 
-static const nsecs_t kStandbyTimeInNsecs = seconds(3);
+//static const nsecs_t kStandbyTimeInNsecs = seconds(3);
 static const unsigned long kBufferRecoveryInUsecs = 2000;
 static const unsigned long kMaxBufferRecoveryInUsecs = 20000;
 static const float MAX_GAIN = 4096.0f;
@@ -93,8 +99,9 @@
 
 AudioFlinger::AudioFlinger()
     : BnAudioFlinger(), Thread(false),
-        mMasterVolume(0), mMasterMute(true),
-        mAudioMixer(0), mAudioHardware(0), mOutput(0), mAudioRecordThread(0),
+        mMasterVolume(0), mMasterMute(true), mHardwareAudioMixer(0), mA2dpAudioMixer(0),
+        mAudioMixer(0), mAudioHardware(0), mA2dpAudioInterface(0),
+        mHardwareOutput(0), mA2dpOutput(0), mOutput(0), mAudioRecordThread(0),
         mSampleRate(0), mFrameCount(0), mChannelCount(0), mFormat(0),
         mMixBuffer(0), mLastWriteTime(0), mNumWrites(0), mNumDelayedWrites(0),
         mStandby(false), mInWrite(false)
@@ -105,17 +112,14 @@
     if (mAudioHardware->initCheck() == NO_ERROR) {
         // open 16-bit output stream for s/w mixer
         mHardwareStatus = AUDIO_HW_OUTPUT_OPEN;
-        mOutput = mAudioHardware->openOutputStream(AudioSystem::PCM_16_BIT);
+        status_t status;
+        mHardwareOutput = mAudioHardware->openOutputStream(AudioSystem::PCM_16_BIT, 0, 0, &status);
         mHardwareStatus = AUDIO_HW_IDLE;
-        if (mOutput) {
-            mSampleRate = mOutput->sampleRate();
-            mChannelCount = mOutput->channelCount();
-            mFormat = mOutput->format();
-            mMixBufferSize = mOutput->bufferSize();
-            mFrameCount = mMixBufferSize / mChannelCount / sizeof(int16_t);
-            mMixBuffer = new int16_t[mFrameCount * mChannelCount];
-            memset(mMixBuffer, 0, mMixBufferSize);
-            mAudioMixer = new AudioMixer(mFrameCount, mSampleRate);
+        if (mHardwareOutput) {
+            mSampleRate = mHardwareOutput->sampleRate();
+            mHardwareAudioMixer = new AudioMixer(getOutputFrameCount(mHardwareOutput), mSampleRate);
+            setOutput(mHardwareOutput);
+
             // FIXME - this should come from settings
             setMasterVolume(1.0f);
             setRouting(AudioSystem::MODE_NORMAL, AudioSystem::ROUTE_SPEAKER, AudioSystem::ROUTE_ALL);
@@ -124,20 +128,87 @@
             setMode(AudioSystem::MODE_NORMAL);
             mMasterMute = false;
         } else {
-            LOGE("Failed to initialize output stream");
+            LOGE("Failed to initialize output stream, status: %d", status);
         }
-    } else {
+        
+#ifdef WITH_A2DP
+        // Create A2DP interface
+        mA2dpAudioInterface = new A2dpAudioInterface();
+        mA2dpOutput = mA2dpAudioInterface->openOutputStream(AudioSystem::PCM_16_BIT, 0, 0, &status);       
+        mA2dpAudioMixer = new AudioMixer(getOutputFrameCount(mA2dpOutput), mA2dpOutput->sampleRate());
+
+        // create a buffer big enough for both hardware and A2DP audio output.
+        size_t hwFrameCount = getOutputFrameCount(mHardwareOutput);
+        size_t a2dpFrameCount = getOutputFrameCount(mA2dpOutput);
+        size_t frameCount = (hwFrameCount > a2dpFrameCount ? hwFrameCount : a2dpFrameCount);
+#else
+        size_t frameCount = getOutputFrameCount(mHardwareOutput);
+#endif
+        // FIXME - Current mixer implementation only supports stereo output: Always
+        // Allocate a stereo buffer even if HW output is mono.
+        mMixBuffer = new int16_t[frameCount * 2];
+        memset(mMixBuffer, 0, frameCount * 2 * sizeof(int16_t));
+        
+        // Start record thread
+        mAudioRecordThread = new AudioRecordThread(mAudioHardware);
+        if (mAudioRecordThread != 0) {
+            mAudioRecordThread->run("AudioRecordThread", PRIORITY_URGENT_AUDIO);            
+        }
+     } else {
         LOGE("Couldn't even initialize the stubbed audio hardware!");
     }
+
+    char value[PROPERTY_VALUE_MAX];
+    // FIXME: What property should this be???
+    property_get("ro.audio.silent", value, "0");
+    if (atoi(value)) {
+        LOGD("Silence is golden");
+        mMasterMute = true;
+    }
 }
 
 AudioFlinger::~AudioFlinger()
 {
+    if (mAudioRecordThread != 0) {
+        mAudioRecordThread->exit();
+        mAudioRecordThread.clear();        
+    }
     delete mOutput;
+    delete mA2dpOutput;
     delete mAudioHardware;
+    delete mA2dpAudioInterface;
     delete [] mMixBuffer;
-    delete mAudioMixer;
-    mAudioRecordThread.clear();
+    delete mHardwareAudioMixer;
+    delete mA2dpAudioMixer;
+}
+ 
+void AudioFlinger::setOutput(AudioStreamOut* output)
+{
+    // lock on mOutputLock to prevent threadLoop() from starving us
+    Mutex::Autolock _l2(mOutputLock);
+    
+    // to synchronize with threadLoop()
+    Mutex::Autolock _l(mLock);
+
+    if (mOutput != output) {
+        mSampleRate = output->sampleRate();
+        mChannelCount = output->channelCount();
+    
+        // FIXME - Current mixer implementation only supports stereo output
+        if (mChannelCount == 1) {
+            LOGE("Invalid audio hardware channel count");
+        }
+        mFormat = output->format();
+        mFrameCount = getOutputFrameCount(output);
+                
+        mAudioMixer = (output == mA2dpOutput ? mA2dpAudioMixer : mHardwareAudioMixer);
+        mOutput = output;
+    }
+}
+
+size_t AudioFlinger::getOutputFrameCount(AudioStreamOut* output) 
+{
+    return output->bufferSize() / output->channelCount() / sizeof(int16_t);
 }
 
 status_t AudioFlinger::dumpClients(int fd, const Vector<String16>& args)
@@ -201,8 +272,8 @@
     const size_t SIZE = 256;
     char buffer[SIZE];
     String8 result;
-    
-    snprintf(buffer, SIZE, "AudioMixer tracks: %08x\n", audioMixer().trackNames());
+
+    snprintf(buffer, SIZE, "AudioMixer tracks: %08x\n", audioMixer()->trackNames());
     result.append(buffer);
     snprintf(buffer, SIZE, "last write occurred (msecs): %llu\n", ns2ms(systemTime() - mLastWriteTime));
     result.append(buffer);
@@ -254,17 +325,26 @@
 // Thread virtuals
 bool AudioFlinger::threadLoop()
 {
-    nsecs_t maxPeriod = seconds(mFrameCount) / mSampleRate * 2;
     unsigned long sleepTime = kBufferRecoveryInUsecs;
-    const size_t mixBufferSize = mFrameCount*mChannelCount*sizeof(int16_t);
     int16_t* curBuf = mMixBuffer;
     Vector< sp<Track> > tracksToRemove;
-    size_t enabledTracks;
+    size_t enabledTracks = 0;
     nsecs_t standbyTime = systemTime();
+    AudioMixer* mixer = 0;
+    size_t frameCount = 0;
+    int channelCount = 0;
+    uint32_t sampleRate = 0;
+    AudioStreamOut* output = 0;
 
     do {
         enabledTracks = 0;
-        { // scope for the lock
+        { // scope for the mLock
+        
+            // locking briefly on the secondary mOutputLock is necessary to avoid
+            // having this thread starve the thread that called setOutput()
+            mOutputLock.lock();
+            mOutputLock.unlock();
+
             Mutex::Autolock _l(mLock);
             const SortedVector< wp<Track> >& activeTracks = mActiveTracks;
 
@@ -286,6 +366,15 @@
                 continue;
             }
 
+            // get active mixer and output parameter while the lock is held and keep them
+            // consistent till the next loop.
+            
+            mixer = audioMixer();
+            frameCount = mFrameCount;
+            channelCount = mChannelCount;
+            sampleRate = mSampleRate;
+            output = mOutput;
+            
             // find out which tracks need to be processed
             size_t count = activeTracks.size();
             for (size_t i=0 ; i<count ; i++) {
@@ -294,13 +383,11 @@
 
                 Track* const track = t.get();
                 audio_track_cblk_t* cblk = track->cblk();
-                uint32_t u = cblk->user;
-                uint32_t s = cblk->server;
 
                 // The first time a track is added we wait
                 // for all its buffers to be filled before processing it
-                audioMixer().setActiveTrack(track->name());
-                if ((u > s) && (track->isReady(u, s) || track->isStopped()) &&
+                mixer->setActiveTrack(track->name());
+                if (cblk->framesReady() && (track->isReady() || track->isStopped()) &&
                         !track->isPaused())
                 {
                     //LOGD("u=%08x, s=%08x [OK]", u, s);
@@ -325,9 +412,8 @@
                     }
 
                     // XXX: these things DON'T need to be done each time
-                    AudioMixer& mixer(audioMixer());
-                    mixer.setBufferProvider(track);
-                    mixer.enable(AudioMixer::MIXING);
+                    mixer->setBufferProvider(track);
+                    mixer->enable(AudioMixer::MIXING);
 
                     int param;
                     if ( track->mFillingUpStatus == Track::FS_FILLED) {
@@ -342,15 +428,15 @@
                     } else {
                         param = AudioMixer::RAMP_VOLUME;
                     }
-                    mixer.setParameter(param, AudioMixer::VOLUME0, left);
-                    mixer.setParameter(param, AudioMixer::VOLUME1, right);
-                    mixer.setParameter(
+                    mixer->setParameter(param, AudioMixer::VOLUME0, left);
+                    mixer->setParameter(param, AudioMixer::VOLUME1, right);
+                    mixer->setParameter(
                         AudioMixer::TRACK,
                         AudioMixer::FORMAT, track->format());
-                    mixer.setParameter(
+                    mixer->setParameter(
                         AudioMixer::TRACK,
                         AudioMixer::CHANNEL_COUNT, track->channelCount());
-                    mixer.setParameter(
+                    mixer->setParameter(
                         AudioMixer::RESAMPLE,
                         AudioMixer::SAMPLE_RATE,
                         int(cblk->sampleRate));
@@ -361,8 +447,7 @@
                 } else {
                     //LOGD("u=%08x, s=%08x [NOT READY]", u, s);
                     if (track->isStopped()) {
-                        track->mFillingUpStatus = Track::FS_FILLING;
-                        track->mFlags = 0;    
+                        track->reset();
                     }
                     if (track->isTerminated() || track->isStopped() || track->isPaused()) {
                         // We have consumed all the buffers of this track.
@@ -378,7 +463,7 @@
                         }
                     }
                     // LOGV("disable(%d)", track->name());
-                    audioMixer().disable(AudioMixer::MIXING);
+                    mixer->disable(AudioMixer::MIXING);
                 }
             }
 
@@ -390,26 +475,27 @@
                     mActiveTracks.remove(track);
                     if (track->isTerminated()) {
                         mTracks.remove(track);
-                        audioMixer().deleteTrackName(track->mName);
+                        mixer->deleteTrackName(track->mName);
                     }
                 }
-            }
-        }
-
+            }  
+       }
         if (LIKELY(enabledTracks)) {
             // mix buffers...
-            audioMixer().process(curBuf);
+            mixer->process(curBuf);
 
             // output audio to hardware
             mLastWriteTime = systemTime();
             mInWrite = true;
-            mOutput->write(curBuf, mixBufferSize);
+            size_t mixBufferSize = frameCount*channelCount*sizeof(int16_t);
+            output->write(curBuf, mixBufferSize);
             mNumWrites++;
             mInWrite = false;
             mStandby = false;
             nsecs_t temp = systemTime();
             standbyTime = temp + kStandbyTimeInNsecs;
             nsecs_t delta = temp - mLastWriteTime;
+            nsecs_t maxPeriod = seconds(frameCount) / sampleRate * 2;
             if (delta > maxPeriod) {
                 LOGW("write blocked for %llu msecs", ns2ms(delta));
                 mNumDelayedWrites++;
@@ -458,43 +544,60 @@
         uint32_t sampleRate,
         int format,
         int channelCount,
-        int bufferCount,
-        uint32_t flags)
+        int frameCount,
+        uint32_t flags,
+        const sp<IMemory>& sharedBuffer,
+        status_t *status)
 {
-    if (streamType >= AudioTrack::NUM_STREAM_TYPES) {
-        LOGE("invalid stream type");
-        return NULL;
-    }
-
-    if (sampleRate > MAX_SAMPLE_RATE) {
-        LOGE("Sample rate out of range: %d", sampleRate);
-        return NULL;
-    }
-
     sp<Track> track;
     sp<TrackHandle> trackHandle;
-    Mutex::Autolock _l(mLock);
-
-    if (mSampleRate == 0) {
-        LOGE("Audio driver not initialized.");
-        return trackHandle;
-    }
-
     sp<Client> client;
-    wp<Client> wclient = mClients.valueFor(pid);
+    wp<Client> wclient;
+    status_t lStatus;
 
-    if (wclient != NULL) {
-        client = wclient.promote();
-    } else {
-        client = new Client(this, pid);
-        mClients.add(pid, client);
+    if (streamType >= AudioTrack::NUM_STREAM_TYPES) {
+        LOGE("invalid stream type");
+        lStatus = BAD_VALUE;
+        goto Exit;
     }
 
-    // FIXME: Buffer size should be based on sample rate for consistent latency
-    track = new Track(this, client, streamType, sampleRate, format,
-            channelCount, bufferCount, channelCount == 1 ? mMixBufferSize>>1 : mMixBufferSize);
-    mTracks.add(track);
-    trackHandle = new TrackHandle(track);
+    // Resampler implementation limits input sampling rate to 2 x output sampling rate.
+    if (sampleRate > MAX_SAMPLE_RATE || sampleRate > mSampleRate*2) {
+        LOGE("Sample rate out of range: %d", sampleRate);
+        lStatus = BAD_VALUE;
+        goto Exit;
+    }
+
+    {
+        Mutex::Autolock _l(mLock);
+
+        if (mSampleRate == 0) {
+            LOGE("Audio driver not initialized.");
+            lStatus = NO_INIT;
+            goto Exit;
+        }
+
+        wclient = mClients.valueFor(pid);
+
+        if (wclient != NULL) {
+            client = wclient.promote();
+        } else {
+            client = new Client(this, pid);
+            mClients.add(pid, client);
+        }
+
+        track = new Track(this, client, streamType, sampleRate, format,
+                channelCount, frameCount, sharedBuffer);
+        mTracks.add(track);
+        trackHandle = new TrackHandle(track);
+
+        lStatus = NO_ERROR;
+    }
+
+Exit:
+    if(status) {
+        *status = lStatus;
+    }
     return trackHandle;
 }
 
@@ -518,6 +621,16 @@
     return mFrameCount;
 }
 
+uint32_t AudioFlinger::latency() const
+{
+    if (mOutput) {
+        return mOutput->latency();
+    }
+    else {
+        return 0;
+    }
+}
+
 status_t AudioFlinger::setMasterVolume(float value)
 {
     // check calling permissions
@@ -549,6 +662,21 @@
         return BAD_VALUE;
     }
 
+#ifdef WITH_A2DP
+    LOGD("setRouting %d %d %d\n", mode, routes, mask);
+    if (mode == AudioSystem::MODE_NORMAL && 
+            (mask & AudioSystem::ROUTE_BLUETOOTH_A2DP)) {
+        if (routes & AudioSystem::ROUTE_BLUETOOTH_A2DP) {
+            LOGD("set output to A2DP\n");
+            setOutput(mA2dpOutput);
+        } else {
+            LOGD("set output to hardware audio\n");
+            setOutput(mHardwareOutput);
+        }
+        LOGD("setOutput done\n");
+    }
+#endif
+
     AutoMutex lock(mHardwareLock);
     mHardwareStatus = AUDIO_HW_GET_ROUTING;
     uint32_t r;
@@ -656,7 +784,7 @@
     if (uint32_t(stream) >= AudioTrack::NUM_STREAM_TYPES) {
         return BAD_VALUE;
     }
-    
+
     mStreamTypes[stream].volume = value;
     status_t ret = NO_ERROR;
     if (stream == AudioTrack::VOICE_CALL) {
@@ -750,6 +878,7 @@
         // buffers before playing. This is to ensure the client will
         // effectively get the latency it requested.
         track->mFillingUpStatus = Track::FS_FILLING;
+        track->mResetDone = false;
         mActiveTracks.add(track);
         return NO_ERROR;
     }
@@ -771,7 +900,7 @@
     if (t!=NULL) {
         t->reset();
     }
-    audioMixer().deleteTrackName(name);
+    audioMixer()->deleteTrackName(name);
     mActiveTracks.remove(track);
     mWaitWorkCV.broadcast();
 }
@@ -789,7 +918,7 @@
     if (mActiveTracks.indexOf(track) < 0) {
         LOGV("remove track (%d) and delete from mixer", track->name());
         mTracks.remove(track);
-        audioMixer().deleteTrackName(keep->name());
+        audioMixer()->deleteTrackName(keep->name());
     }
 }
 
@@ -823,38 +952,53 @@
             uint32_t sampleRate,
             int format,
             int channelCount,
-            int bufferCount,
-            int bufferSize)
+            int frameCount,
+            const sp<IMemory>& sharedBuffer)
     :   RefBase(),
         mAudioFlinger(audioFlinger),
         mClient(client),
         mStreamType(streamType),
-        mFormat(format),
-        mChannelCount(channelCount),
-        mBufferCount(bufferCount),
-        mFlags(0),
-        mBufferSize(bufferSize),
+        mFrameCount(0),
         mState(IDLE),
-        mClientTid(-1)
+        mClientTid(-1),
+        mFormat(format),
+        mFlags(0)
 {
-    mName = audioFlinger->audioMixer().getTrackName();
+    mName = audioFlinger->audioMixer()->getTrackName();
     if (mName < 0) {
         LOGE("no more track names availlable");
         return;
     }
 
+    LOGV_IF(sharedBuffer != 0, "sharedBuffer: %p, size: %d", sharedBuffer->pointer(), sharedBuffer->size());
+
+
     // LOGD("Creating track with %d buffers @ %d bytes", bufferCount, bufferSize);
-    size_t size = sizeof(audio_track_cblk_t) + bufferCount * bufferSize;
+   size_t size = sizeof(audio_track_cblk_t);
+   size_t bufferSize = frameCount*channelCount*sizeof(int16_t);
+   if (sharedBuffer == 0) {
+       size += bufferSize;
+   }
+
     mCblkMemory = client->heap()->allocate(size);
     if (mCblkMemory != 0) {
         mCblk = static_cast<audio_track_cblk_t *>(mCblkMemory->pointer());
         if (mCblk) { // construct the shared structure in-place.
             new(mCblk) audio_track_cblk_t();
             // clear all buffers
-            mCblk->size = bufferSize;
+            mCblk->frameCount = frameCount;
             mCblk->sampleRate = sampleRate;
-            mBuffers = (char*)mCblk + sizeof(audio_track_cblk_t);
-            memset(mBuffers, 0, bufferCount * bufferSize);
+            mCblk->channels = channelCount;
+            if (sharedBuffer == 0) {
+                mBuffer = (char*)mCblk + sizeof(audio_track_cblk_t);
+                memset(mBuffer, 0, frameCount*channelCount*sizeof(int16_t));
+                // Force underrun condition to avoid false underrun callback until first data is
+                // written to buffer
+                mCblk->flowControlFlag = 1;
+            } else {
+                mBuffer = sharedBuffer->pointer();
+            }
+            mBufferEnd = (uint8_t *)mBuffer + bufferSize;
         }
     } else {
         LOGE("not enough memory for AudioTrack size=%u", size);
@@ -873,15 +1017,16 @@
 void AudioFlinger::TrackBase::releaseBuffer(AudioBufferProvider::Buffer* buffer)
 {
     buffer->raw = 0;
-    buffer->frameCount = 0;
+    mFrameCount = buffer->frameCount;
     step();
+    buffer->frameCount = 0;
 }
 
 bool AudioFlinger::TrackBase::step() {
     bool result;
     audio_track_cblk_t* cblk = this->cblk();
-    
-    result = cblk->stepServer(bufferCount()); 
+
+    result = cblk->stepServer(mFrameCount);
     if (!result) {
         LOGV("stepServer failed acquiring cblk mutex");
         mFlags |= STEPSERVER_FAILED;
@@ -894,7 +1039,10 @@
 
     cblk->user = 0;
     cblk->server = 0;
-    mFlags = 0;    
+    cblk->userBase = 0;
+    cblk->serverBase = 0;
+    mFlags = 0;
+    LOGV("TrackBase::reset");
 }
 
 sp<IMemory> AudioFlinger::TrackBase::getCblk() const
@@ -906,6 +1054,27 @@
     return mCblk->sampleRate;
 }
 
+int AudioFlinger::TrackBase::channelCount() const {
+    return mCblk->channels;
+}
+
+void* AudioFlinger::TrackBase::getBuffer(uint32_t offset, uint32_t frames) const {
+    audio_track_cblk_t* cblk = this->cblk();
+    int16_t *bufferStart = (int16_t *)mBuffer + (offset-cblk->serverBase)*cblk->channels;
+    int16_t *bufferEnd = bufferStart + frames * cblk->channels;
+
+    // Check validity of returned pointer in case the track control block would have been corrupted.
+    if (bufferStart < mBuffer || bufferStart > bufferEnd || bufferEnd > mBufferEnd) {
+        LOGW("TrackBase::getBuffer buffer out of range:\n    start: %p, end %p , mBuffer %p mBufferEnd %p\n    \
+                server %d, serverBase %d, user %d, userBase %d",
+                bufferStart, bufferEnd, mBuffer, mBufferEnd,
+                cblk->server, cblk->serverBase, cblk->user, cblk->userBase);
+        return 0;
+    }
+
+    return bufferStart;
+}
+
 // ----------------------------------------------------------------------------
 
 AudioFlinger::Track::Track(
@@ -915,13 +1084,14 @@
             uint32_t sampleRate,
             int format,
             int channelCount,
-            int bufferCount,
-            int bufferSize)
-    :   TrackBase(audioFlinger, client, streamType, sampleRate, format, channelCount, bufferCount, bufferSize)
+            int frameCount,
+            const sp<IMemory>& sharedBuffer)
+    :   TrackBase(audioFlinger, client, streamType, sampleRate, format, channelCount, frameCount, sharedBuffer)
 {
     mVolume[0] = 1.0f;
     mVolume[1] = 1.0f;
     mMute = false;
+    mSharedBuffer = sharedBuffer;
 }
 
 AudioFlinger::Track::~Track()
@@ -943,8 +1113,8 @@
             mClient->pid(),
             mStreamType,
             mFormat,
-            mChannelCount,
-            mBufferCount,
+            mCblk->channels,
+            mFrameCount,
             mState,
             mMute,
             mFillingUpStatus,
@@ -958,36 +1128,50 @@
 status_t AudioFlinger::Track::getNextBuffer(AudioBufferProvider::Buffer* buffer)
 {
      audio_track_cblk_t* cblk = this->cblk();
-     uint32_t u = cblk->user;
-     uint32_t s = cblk->server;
-     
-     // Check if last stepServer failed, try to step now 
+     uint32_t framesReady;
+     uint32_t framesReq = buffer->frameCount;
+
+     // Check if last stepServer failed, try to step now
      if (mFlags & TrackBase::STEPSERVER_FAILED) {
          if (!step())  goto getNextBuffer_exit;
          LOGV("stepServer recovered");
          mFlags &= ~TrackBase::STEPSERVER_FAILED;
      }
 
-     if (LIKELY(u > s)) {
-         int index = s & audio_track_cblk_t::BUFFER_MASK;
-         buffer->raw = getBuffer(index);
-         buffer->frameCount = mAudioFlinger->frameCount();
-         return NO_ERROR;
+     framesReady = cblk->framesReady();
+
+     if (LIKELY(framesReady)) {
+        uint32_t s = cblk->server;
+        uint32_t bufferEnd = cblk->serverBase + cblk->frameCount;
+
+        bufferEnd = (cblk->loopEnd < bufferEnd) ? cblk->loopEnd : bufferEnd;
+        if (framesReq > framesReady) {
+            framesReq = framesReady;
+        }
+        if (s + framesReq > bufferEnd) {
+            framesReq = bufferEnd - s;
+        }
+
+         buffer->raw = getBuffer(s, framesReq);
+         if (buffer->raw == 0) goto getNextBuffer_exit;
+
+         buffer->frameCount = framesReq;
+        return NO_ERROR;
      }
+
 getNextBuffer_exit:
      buffer->raw = 0;
      buffer->frameCount = 0;
      return NOT_ENOUGH_DATA;
 }
 
-bool AudioFlinger::Track::isReady(uint32_t u, int32_t s) const {
+bool AudioFlinger::Track::isReady() const {
     if (mFillingUpStatus != FS_FILLING) return true;
-    const uint32_t u_seq = u & audio_track_cblk_t::SEQUENCE_MASK;
-    const uint32_t u_buf = u & audio_track_cblk_t::BUFFER_MASK;
-    const uint32_t s_seq = s & audio_track_cblk_t::SEQUENCE_MASK;
-    const uint32_t s_buf = s & audio_track_cblk_t::BUFFER_MASK;
-    if (u_seq > s_seq && u_buf == s_buf) {
+
+    if (mCblk->framesReady() >= mCblk->frameCount ||
+        mCblk->forceReady) {
         mFillingUpStatus = FS_FILLED;
+        mCblk->forceReady = 0;
         return true;
     }
     return false;
@@ -1006,7 +1190,7 @@
     Mutex::Autolock _l(mAudioFlinger->mLock);
     if (mState > STOPPED) {
         mState = STOPPED;
-        // If the track is not active (PAUSED and buffers full), flush buffers  
+        // If the track is not active (PAUSED and buffers full), flush buffers
         if (mAudioFlinger->mActiveTracks.indexOf(this) < 0) {
             reset();
         }
@@ -1038,15 +1222,24 @@
     // NOTE: reset() will reset cblk->user and cblk->server with
     // the risk that at the same time, the AudioMixer is trying to read
     // data. In this case, getNextBuffer() would return a NULL pointer
-    // as audio buffer => the AudioMixer code MUST always test that pointer 
-    // returned by getNextBuffer() is not NULL! 
+    // as audio buffer => the AudioMixer code MUST always test that pointer
+    // returned by getNextBuffer() is not NULL!
     reset();
 }
 
 void AudioFlinger::Track::reset()
 {
-    TrackBase::reset();
-    mFillingUpStatus = FS_FILLING;
+    // Do not reset twice to avoid discarding data written just after a flush and before
+    // the audioflinger thread detects the track is stopped.
+    if (!mResetDone) {
+        TrackBase::reset();
+        // Force underrun condition to avoid false underrun callback until first data is
+        // written to buffer
+        mCblk->flowControlFlag = 1;
+        mCblk->forceReady = 0;
+        mFillingUpStatus = FS_FILLING;        
+        mResetDone = true;
+    }
 }
 
 void AudioFlinger::Track::mute(bool muted)
@@ -1112,26 +1305,15 @@
 
 // ----------------------------------------------------------------------------
 
-sp<AudioFlinger::AudioRecordThread> AudioFlinger::audioRecordThread()
-{
-    Mutex::Autolock _l(mLock);
-    return mAudioRecordThread;
-}
-
-void AudioFlinger::endRecord()
-{
-    Mutex::Autolock _l(mLock);
-    mAudioRecordThread.clear();
-}
-
 sp<IAudioRecord> AudioFlinger::openRecord(
         pid_t pid,
         int streamType,
         uint32_t sampleRate,
         int format,
         int channelCount,
-        int bufferCount,
-        uint32_t flags)
+        int frameCount,
+        uint32_t flags,
+        status_t *status)
 {
     sp<AudioRecordThread> thread;
     sp<RecordTrack> recordTrack;
@@ -1139,46 +1321,46 @@
     sp<Client> client;
     wp<Client> wclient;
     AudioStreamIn* input = 0;
+    int inFrameCount;
+    size_t inputBufferSize;
+    status_t lStatus;
 
     // check calling permissions
     if (!recordingAllowed()) {
+        lStatus = PERMISSION_DENIED;
         goto Exit;
     }
 
     if (uint32_t(streamType) >= AudioRecord::NUM_STREAM_TYPES) {
         LOGE("invalid stream type");
+        lStatus = BAD_VALUE;
         goto Exit;
     }
 
     if (sampleRate > MAX_SAMPLE_RATE) {
         LOGE("Sample rate out of range");
+        lStatus = BAD_VALUE;
         goto Exit;
     }
 
     if (mSampleRate == 0) {
         LOGE("Audio driver not initialized");
+        lStatus = NO_INIT;
         goto Exit;
     }
 
-    // Create audio thread - take mutex to prevent race condition
-    {
-        Mutex::Autolock _l(mLock);
-        if (mAudioRecordThread != 0) {
-            LOGE("Record channel already open");
-            goto Exit;
-        }
-        thread = new AudioRecordThread(this);
-        mAudioRecordThread = thread;
+    if (mAudioRecordThread == 0) {
+        LOGE("Audio record thread not started");
+        lStatus = NO_INIT;
+        goto Exit;
     }
-    // It's safe to release the mutex here since the client doesn't get a
-    // handle until we return from this call
 
-    // open driver, initialize h/w
-    input = mAudioHardware->openInputStream(
-            AudioSystem::PCM_16_BIT, channelCount, sampleRate);
-    if (!input) {
-        LOGE("Error opening input stream");
-        mAudioRecordThread.clear();
+
+    // Check that audio input stream accepts requested audio parameters 
+    inputBufferSize = mAudioHardware->getInputBufferSize(sampleRate, format, channelCount);
+    if (inputBufferSize == 0) {
+        lStatus = BAD_VALUE;
+        LOGE("Bad audio input parameters: sampling rate %u, format %d, channels %d",  sampleRate, format, channelCount);
         goto Exit;
     }
 
@@ -1194,37 +1376,38 @@
         }
     }
 
+    // frameCount must be a multiple of input buffer size
+    inFrameCount = inputBufferSize/channelCount/sizeof(short);
+    frameCount = ((frameCount - 1)/inFrameCount + 1) * inFrameCount;
+
     // create new record track and pass to record thread
     recordTrack = new RecordTrack(this, client, streamType, sampleRate,
-            format, channelCount, bufferCount, input->bufferSize());
-
-    // spin up record thread
-    thread->open(recordTrack, input);
-    thread->run("AudioRecordThread", PRIORITY_URGENT_AUDIO);
+            format, channelCount, frameCount);
 
     // return to handle to client
     recordHandle = new RecordHandle(recordTrack);
+    lStatus = NO_ERROR;
 
 Exit:
+    if (status) {
+        *status = lStatus;
+    }
     return recordHandle;
 }
 
-status_t AudioFlinger::startRecord() {
-    sp<AudioRecordThread> t = audioRecordThread();
-    if (t == 0) return NO_INIT;
-    return t->start();
+status_t AudioFlinger::startRecord(RecordTrack* recordTrack) {
+    if (mAudioRecordThread != 0) {
+        return mAudioRecordThread->start(recordTrack);        
+    }
+    return NO_INIT;
 }
 
-void AudioFlinger::stopRecord() {
-    sp<AudioRecordThread> t = audioRecordThread();
-    if (t != 0) t->stop();
+void AudioFlinger::stopRecord(RecordTrack* recordTrack) {
+    if (mAudioRecordThread != 0) {
+        mAudioRecordThread->stop(recordTrack);
+    }
 }
 
-void AudioFlinger::exitRecord()
-{
-    sp<AudioRecordThread> t = audioRecordThread();
-    if (t != 0) t->exit();
-}
 
 // ----------------------------------------------------------------------------
 
@@ -1235,55 +1418,69 @@
             uint32_t sampleRate,
             int format,
             int channelCount,
-            int bufferCount,
-            int bufferSize)
+            int frameCount)
     :   TrackBase(audioFlinger, client, streamType, sampleRate, format,
-            channelCount, bufferCount, bufferSize),
+            channelCount, frameCount, 0),
             mOverflow(false)
 {
 }
 
 AudioFlinger::RecordTrack::~RecordTrack()
 {
-    mAudioFlinger->audioMixer().deleteTrackName(mName);
-    mAudioFlinger->exitRecord();
+    mAudioFlinger->audioMixer()->deleteTrackName(mName);
 }
 
 status_t AudioFlinger::RecordTrack::getNextBuffer(AudioBufferProvider::Buffer* buffer)
 {
-     audio_track_cblk_t* cblk = this->cblk();
-     const uint32_t u_seq = cblk->user & audio_track_cblk_t::SEQUENCE_MASK;
-     const uint32_t u_buf = cblk->user & audio_track_cblk_t::BUFFER_MASK;
-     const uint32_t s_seq = cblk->server & audio_track_cblk_t::SEQUENCE_MASK;
-     const uint32_t s_buf = cblk->server & audio_track_cblk_t::BUFFER_MASK;
-     
-     // Check if last stepServer failed, try to step now 
-     if (mFlags & TrackBase::STEPSERVER_FAILED) {
-         if (!step())  goto getNextBuffer_exit;
-         LOGV("stepServer recovered");
-         mFlags &= ~TrackBase::STEPSERVER_FAILED;
-     }
+    audio_track_cblk_t* cblk = this->cblk();
+    uint32_t framesAvail;
+    uint32_t framesReq = buffer->frameCount;
 
-     if (LIKELY(s_seq == u_seq || s_buf != u_buf)) {
-         buffer->raw = getBuffer(s_buf);
-         buffer->frameCount = mAudioFlinger->frameCount();
-         return NO_ERROR;
-     }
+     // Check if last stepServer failed, try to step now
+    if (mFlags & TrackBase::STEPSERVER_FAILED) {
+        if (!step()) goto getNextBuffer_exit;
+        LOGV("stepServer recovered");
+        mFlags &= ~TrackBase::STEPSERVER_FAILED;
+    }
 
-getNextBuffer_exit:     
-     buffer->raw = 0;
-     buffer->frameCount = 0;
-     return NOT_ENOUGH_DATA;
+    framesAvail = cblk->framesAvailable_l();
+
+    if (LIKELY(framesAvail)) {
+        uint32_t s = cblk->server;
+        uint32_t bufferEnd = cblk->serverBase + cblk->frameCount;
+
+        if (framesReq > framesAvail) {
+            framesReq = framesAvail;
+        }
+        if (s + framesReq > bufferEnd) {
+            framesReq = bufferEnd - s;
+        }
+
+        buffer->raw = getBuffer(s, framesReq);
+        if (buffer->raw == 0) goto getNextBuffer_exit;
+
+        buffer->frameCount = framesReq;
+        return NO_ERROR;
+    }
+
+getNextBuffer_exit:
+    buffer->raw = 0;
+    buffer->frameCount = 0;
+    return NOT_ENOUGH_DATA;
 }
 
 status_t AudioFlinger::RecordTrack::start()
 {
-    return mAudioFlinger->startRecord();
+    return mAudioFlinger->startRecord(this);
 }
 
 void AudioFlinger::RecordTrack::stop()
 {
-    mAudioFlinger->stopRecord();
+    mAudioFlinger->stopRecord(this);
+    TrackBase::reset();
+    // Force overerrun condition to avoid false overrun callback until first data is
+    // read from buffer
+    mCblk->flowControlFlag = 1;
 }
 
 // ----------------------------------------------------------------------------
@@ -1294,7 +1491,9 @@
 {
 }
 
-AudioFlinger::RecordHandle::~RecordHandle() {}
+AudioFlinger::RecordHandle::~RecordHandle() {
+    stop();
+}
 
 status_t AudioFlinger::RecordHandle::start() {
     LOGV("RecordHandle::start()");
@@ -1318,10 +1517,8 @@
 
 // ----------------------------------------------------------------------------
 
-AudioFlinger::AudioRecordThread::AudioRecordThread(const sp<AudioFlinger>& audioFlinger) :
-    mAudioFlinger(audioFlinger),
-    mRecordTrack(0),
-    mInput(0),
+AudioFlinger::AudioRecordThread::AudioRecordThread(AudioHardwareInterface* audioHardware) :
+    mAudioHardware(audioHardware),
     mActive(false)
 {
 }
@@ -1333,108 +1530,123 @@
 bool AudioFlinger::AudioRecordThread::threadLoop()
 {
     LOGV("AudioRecordThread: start record loop");
+    AudioBufferProvider::Buffer buffer;
+    int inBufferSize = 0;
+    int inFrameCount = 0;
+    AudioStreamIn* input = 0;
 
+    mActive = 0;
+    
     // start recording
     while (!exitPending()) {
         if (!mActive) {
             mLock.lock();
             if (!mActive && !exitPending()) {
                 LOGV("AudioRecordThread: loop stopping");
+                if (input) {
+                    delete input;
+                    input = 0;
+                }
+                mRecordTrack.clear();
+
                 mWaitWorkCV.wait(mLock);
+               
                 LOGV("AudioRecordThread: loop starting");
+                if (mRecordTrack != 0) {
+                    input = mAudioHardware->openInputStream(mRecordTrack->format(), 
+                                            mRecordTrack->channelCount(), 
+                                            mRecordTrack->sampleRate(), 
+                                            &mStartStatus);
+                    if (input != 0) {
+                        inBufferSize = input->bufferSize();
+                        inFrameCount = inBufferSize/input->frameSize();                        
+                    }
+                } else {
+                    mStartStatus = NO_INIT;
+                }
+                if (mStartStatus !=NO_ERROR) {
+                    LOGW("record start failed, status %d", mStartStatus);
+                    mActive = false;
+                    mRecordTrack.clear();                    
+                }
+                mWaitWorkCV.signal();
             }
             mLock.unlock();
-        } else {
-            // promote strong ref so track isn't deleted while we access it
-            sp<RecordTrack> t = mRecordTrack.promote();
+        } else if (mRecordTrack != 0){
 
-            // if we lose the weak reference, client is gone.
-            if (t == 0) {
-                LOGV("AudioRecordThread: client deleted track");
-                break;
-            }
-
-            if (LIKELY(t->getNextBuffer(&mBuffer) == NO_ERROR)) {
-                if (mInput->read(mBuffer.raw, t->mBufferSize) < 0) {
+            buffer.frameCount = inFrameCount;
+            if (LIKELY(mRecordTrack->getNextBuffer(&buffer) == NO_ERROR)) {
+                LOGV("AudioRecordThread read: %d frames", buffer.frameCount);
+                if (input->read(buffer.raw, inBufferSize) < 0) {
                     LOGE("Error reading audio input");
                     sleep(1);
                 }
-                t->releaseBuffer(&mBuffer);
+                mRecordTrack->releaseBuffer(&buffer);
+                mRecordTrack->overflow();
             }
 
             // client isn't retrieving buffers fast enough
             else {
-                if (!t->setOverflow())
+                if (!mRecordTrack->setOverflow())
                     LOGW("AudioRecordThread: buffer overflow");
+                // Release the processor for a while before asking for a new buffer.
+                // This will give the application more chance to read from the buffer and
+                // clear the overflow.
+                usleep(5000);
             }
         }
-    };
+    }
 
-    // close hardware
-    close();
 
-    // delete this object - no more data references after this call
-    mAudioFlinger->endRecord();
+    if (input) {
+        delete input;
+    }
+    mRecordTrack.clear();
+    
     return false;
 }
 
-status_t AudioFlinger::AudioRecordThread::open(const sp<RecordTrack>& recordTrack, AudioStreamIn *input) {
-    LOGV("AudioRecordThread::open");
-    // check for record channel already open
-    AutoMutex lock(&mLock);
-    if (mRecordTrack != NULL) {
-        LOGE("Record channel already open");
-        return ALREADY_EXISTS;
-    }
-    mRecordTrack = recordTrack;
-    mInput = input;
-    return NO_ERROR;
-}
-
-status_t AudioFlinger::AudioRecordThread::start()
+status_t AudioFlinger::AudioRecordThread::start(RecordTrack* recordTrack)
 {
     LOGV("AudioRecordThread::start");
     AutoMutex lock(&mLock);
-    if (mActive) return -EBUSY;
+    mActive = true;
+    // If starting the active track, just reset mActive in case a stop
+    // was pending and exit
+    if (recordTrack == mRecordTrack.get()) return NO_ERROR;
 
-    sp<RecordTrack> t = mRecordTrack.promote();
-    if (t == 0) return UNKNOWN_ERROR;
+    if (mRecordTrack != 0) return -EBUSY;
+
+    mRecordTrack = recordTrack;
 
     // signal thread to start
     LOGV("Signal record thread");
-    mActive = true;
     mWaitWorkCV.signal();
-    return NO_ERROR;
+    mWaitWorkCV.wait(mLock);
+    LOGV("Record started, status %d", mStartStatus);
+    return mStartStatus;
 }
 
-void AudioFlinger::AudioRecordThread::stop() {
+void AudioFlinger::AudioRecordThread::stop(RecordTrack* recordTrack) {
     LOGV("AudioRecordThread::stop");
     AutoMutex lock(&mLock);
-    if (mActive) {
+    if (mActive && (recordTrack == mRecordTrack.get())) {
         mActive = false;
-        mWaitWorkCV.signal();
     }
 }
 
 void AudioFlinger::AudioRecordThread::exit()
 {
     LOGV("AudioRecordThread::exit");
-    AutoMutex lock(&mLock);
-    requestExit();
-    mWaitWorkCV.signal();
+    {
+        AutoMutex lock(&mLock);
+        requestExit();
+        mWaitWorkCV.signal();
+    }
+    requestExitAndWait();
 }
 
 
-status_t AudioFlinger::AudioRecordThread::close()
-{
-    LOGV("AudioRecordThread::close");
-    AutoMutex lock(&mLock);
-    if (!mInput) return NO_INIT;
-    delete mInput;
-    mInput = 0;
-    return NO_ERROR;
-}
-
 status_t AudioFlinger::onTransact(
         uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
 {
diff --git a/libs/audioflinger/AudioFlinger.h b/libs/audioflinger/AudioFlinger.h
index 8c02617..d9f7b49 100644
--- a/libs/audioflinger/AudioFlinger.h
+++ b/libs/audioflinger/AudioFlinger.h
@@ -43,13 +43,17 @@
 class AudioMixer;
 class AudioBuffer;
 
+
 // ----------------------------------------------------------------------------
 
 #define LIKELY( exp )       (__builtin_expect( (exp) != 0, true  ))
 #define UNLIKELY( exp )     (__builtin_expect( (exp) != 0, false ))
 
+
 // ----------------------------------------------------------------------------
 
+static const nsecs_t kStandbyTimeInNsecs = seconds(3);
+
 class AudioFlinger : public BnAudioFlinger, protected Thread
 {
 public:
@@ -69,13 +73,16 @@
                                 uint32_t sampleRate,
                                 int format,
                                 int channelCount,
-                                int bufferCount,
-                                uint32_t flags);
+                                int frameCount,
+                                uint32_t flags,
+                                const sp<IMemory>& sharedBuffer,
+                                status_t *status);
 
     virtual     uint32_t    sampleRate() const;
     virtual     int         channelCount() const;
     virtual     int         format() const;
     virtual     size_t      frameCount() const;
+    virtual     size_t      latency() const;
 
     virtual     status_t    setMasterVolume(float value);
     virtual     status_t    setMasterMute(bool muted);
@@ -128,8 +135,9 @@
                                 uint32_t sampleRate,
                                 int format,
                                 int channelCount,
-                                int bufferCount,
-                                uint32_t flags);
+                                int frameCount,
+                                uint32_t flags,
+                                status_t *status);
 
     virtual     status_t    onTransact(
                                 uint32_t code,
@@ -141,12 +149,15 @@
                             AudioFlinger();
     virtual                 ~AudioFlinger();
     
+    void                    setOutput(AudioStreamOut* output);
+    size_t                  getOutputFrameCount(AudioStreamOut* output);
+
     // Internal dump utilites.
     status_t dumpPermissionDenial(int fd, const Vector<String16>& args);
     status_t dumpClients(int fd, const Vector<String16>& args);
     status_t dumpTracks(int fd, const Vector<String16>& args);
     status_t dumpInternals(int fd, const Vector<String16>& args);
-    
+
     // --- Client ---
     class Client : public RefBase {
     public:
@@ -183,17 +194,17 @@
         };
 
         enum track_flags {
-            STEPSERVER_FAILED = 0x01   //  StepServer could not acquire cblk->lock mutex 
+            STEPSERVER_FAILED = 0x01   //  StepServer could not acquire cblk->lock mutex
         };
-        
+
                             TrackBase(  const sp<AudioFlinger>& audioFlinger,
                                     const sp<Client>& client,
                                     int streamType,
                                     uint32_t sampleRate,
                                     int format,
                                     int channelCount,
-                                    int bufferCount,
-                                    int bufferSize);
+                                    int frameCount,
+                                    const sp<IMemory>& sharedBuffer);
                             ~TrackBase();
 
         virtual status_t    start() = 0;
@@ -203,6 +214,7 @@
     protected:
         friend class AudioFlinger;
         friend class RecordHandle;
+        friend class AudioRecordThread;
 
                             TrackBase(const TrackBase&);
                             TrackBase& operator = (const TrackBase&);
@@ -222,19 +234,11 @@
             return mFormat;
         }
 
-        int channelCount() const {
-            return mChannelCount;
-        }
-
-        int bufferCount() const {
-            return mBufferCount;
-        }
+        int channelCount() const ;
 
         int sampleRate() const;
 
-        void* getBuffer(int n) const {
-            return (char*)mBuffers + n * mBufferSize;
-        }
+        void* getBuffer(uint32_t offset, uint32_t frames) const;
 
         int name() const {
             return mName;
@@ -256,16 +260,15 @@
         sp<IMemory>         mCblkMemory;
         audio_track_cblk_t* mCblk;
         int                 mStreamType;
-        uint8_t             mFormat;
-        uint8_t             mChannelCount;
-        uint8_t             mBufferCount;
-        uint8_t             mFlags;
-        void*               mBuffers;
-        size_t              mBufferSize;
+        void*               mBuffer;
+        void*               mBufferEnd;
+        uint32_t            mFrameCount;
         int                 mName;
         // we don't really need a lock for these
         int                 mState;
         int                 mClientTid;
+        uint8_t             mFormat;
+        uint8_t             mFlags;
     };
 
     // playback track
@@ -277,8 +280,8 @@
                                     uint32_t sampleRate,
                                     int format,
                                     int channelCount,
-                                    int bufferCount,
-                                    int bufferSize);
+                                    int frameCount,
+                                    const sp<IMemory>& sharedBuffer);
                             ~Track();
 
                 void        dump(char* buffer, size_t size);
@@ -312,7 +315,7 @@
             return mState == PAUSED;
         }
 
-        bool isReady(uint32_t u, int32_t s) const;
+        bool isReady() const;
 
         void setPaused() { mState = PAUSED; }
         void reset();
@@ -324,6 +327,8 @@
         enum {FS_FILLING, FS_FILLED, FS_ACTIVE};
         mutable uint8_t     mFillingUpStatus;
         int8_t              mRetryCount;
+        sp<IMemory>         mSharedBuffer;
+        bool                mResetDone;
     };  // end of Track
 
     friend class AudioBuffer;
@@ -366,8 +371,8 @@
                 void        remove_track_l(wp<Track> track, int name);
                 void        destroyTrack(const sp<Track>& track);
 
-                AudioMixer& audioMixer() {
-                    return *mAudioMixer;
+                AudioMixer* audioMixer() {
+                    return mAudioMixer;
                 }
 
     // record track
@@ -379,8 +384,7 @@
                                     uint32_t sampleRate,
                                     int format,
                                     int channelCount,
-                                    int bufferCount,
-                                    int bufferSize);
+                                    int frameCount);
                             ~RecordTrack();
 
         virtual status_t    start();
@@ -419,43 +423,34 @@
     class AudioRecordThread : public Thread
     {
     public:
-        AudioRecordThread(const sp<AudioFlinger>& audioFlinger);
+        AudioRecordThread(AudioHardwareInterface* audioHardware);
         virtual             ~AudioRecordThread();
         virtual bool        threadLoop();
         virtual status_t    readyToRun() { return NO_ERROR; }
         virtual void        onFirstRef() {}
 
-                status_t    open(const sp<RecordTrack>& recordTrack, AudioStreamIn *input);
-                status_t    start();
-                void        stop();
-                status_t    close();
+                status_t    start(RecordTrack* recordTrack);
+                void        stop(RecordTrack* recordTrack);
                 void        exit();
-                
-                bool        isOpen() { return bool(mRecordTrack != NULL); }
 
     private:
                 AudioRecordThread();
-                sp<AudioFlinger>                    mAudioFlinger;
-                wp<RecordTrack>                     mRecordTrack;
-                AudioStreamIn*                      mInput;
+                AudioHardwareInterface              *mAudioHardware;
+                sp<RecordTrack>                     mRecordTrack;
                 Mutex                               mLock;
                 Condition                           mWaitWorkCV;
-                AudioBufferProvider::Buffer         mBuffer;
                 volatile bool                       mActive;
+                status_t                            mStartStatus;
     };
 
     friend class AudioRecordThread;
 
-                sp<AudioRecordThread> audioRecordThread();
-                void        endRecord();
-                status_t    startRecord();
-                void        stopRecord();
-                void        exitRecord();
-                
-                AudioHardwareInterface* audioHardware() { return mAudioHardware; }
+                status_t    startRecord(RecordTrack* recordTrack);
+                void        stopRecord(RecordTrack* recordTrack);
 
     mutable     Mutex                                       mHardwareLock;
     mutable     Mutex                                       mLock;
+    mutable     Mutex                                       mOutputLock;
     mutable     Condition                                   mWaitWorkCV;
                 DefaultKeyedVector< pid_t, wp<Client> >     mClients;
                 SortedVector< wp<Track> >                   mActiveTracks;
@@ -465,15 +460,19 @@
                 bool                                mMasterMute;
                 stream_type_t                       mStreamTypes[AudioTrack::NUM_STREAM_TYPES];
 
+                AudioMixer*                         mHardwareAudioMixer;
+                AudioMixer*                         mA2dpAudioMixer;
                 AudioMixer*                         mAudioMixer;
                 AudioHardwareInterface*             mAudioHardware;
+                AudioHardwareInterface*             mA2dpAudioInterface;
+                AudioStreamOut*                     mHardwareOutput;
+                AudioStreamOut*                     mA2dpOutput;
                 AudioStreamOut*                     mOutput;
                 sp<AudioRecordThread>               mAudioRecordThread;
                 uint32_t                            mSampleRate;
                 size_t                              mFrameCount;
                 int                                 mChannelCount;
                 int                                 mFormat;
-                int                                 mMixBufferSize;
                 int16_t*                            mMixBuffer;
     mutable     int                                 mHardwareStatus;
                 nsecs_t                             mLastWriteTime;
diff --git a/libs/audioflinger/AudioHardwareGeneric.cpp b/libs/audioflinger/AudioHardwareGeneric.cpp
index b1e5b7f..e6a163b 100644
--- a/libs/audioflinger/AudioHardwareGeneric.cpp
+++ b/libs/audioflinger/AudioHardwareGeneric.cpp
@@ -2,16 +2,16 @@
 **
 ** Copyright 2007, The Android Open Source Project
 **
-** Licensed under the Apache License, Version 2.0 (the "License"); 
-** you may not use this file except in compliance with the License. 
-** You may obtain a copy of the License at 
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
 **
-**     http://www.apache.org/licenses/LICENSE-2.0 
+**     http://www.apache.org/licenses/LICENSE-2.0
 **
-** Unless required by applicable law or agreed to in writing, software 
-** distributed under the License is distributed on an "AS IS" BASIS, 
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
-** See the License for the specific language governing permissions and 
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
 ** limitations under the License.
 */
 
@@ -68,16 +68,25 @@
 }
 
 AudioStreamOut* AudioHardwareGeneric::openOutputStream(
-        int format, int channelCount, uint32_t sampleRate)
+        int format, int channelCount, uint32_t sampleRate, status_t *status)
 {
     AutoMutex lock(mLock);
 
     // only one output stream allowed
-    if (mOutput) return 0;
+    if (mOutput) {
+        if (status) {
+            *status = INVALID_OPERATION;
+        }
+        return 0;
+    }
 
     // create new output stream
     AudioStreamOutGeneric* out = new AudioStreamOutGeneric();
-    if (out->set(this, mFd, format, channelCount, sampleRate) == NO_ERROR) {
+    status_t lStatus = out->set(this, mFd, format, channelCount, sampleRate);
+    if (status) {
+        *status = lStatus;
+    }
+    if (lStatus == NO_ERROR) {
         mOutput = out;
     } else {
         delete out;
@@ -90,16 +99,25 @@
 }
 
 AudioStreamIn* AudioHardwareGeneric::openInputStream(
-        int format, int channelCount, uint32_t sampleRate)
+        int format, int channelCount, uint32_t sampleRate, status_t *status)
 {
     AutoMutex lock(mLock);
 
     // only one input stream allowed
-    if (mInput) return 0;
+    if (mInput) {
+        if (status) {
+            *status = INVALID_OPERATION;
+        }
+        return 0;
+    }
 
     // create new output stream
     AudioStreamInGeneric* in = new AudioStreamInGeneric();
-    if (in->set(this, mFd, format, channelCount, sampleRate) == NO_ERROR) {
+    status_t lStatus = in->set(this, mFd, format, channelCount, sampleRate);
+    if (status) {
+        *status = lStatus;
+    }
+    if (lStatus == NO_ERROR) {
         mInput = in;
     } else {
         delete in;
diff --git a/libs/audioflinger/AudioHardwareGeneric.h b/libs/audioflinger/AudioHardwareGeneric.h
index 10cc45d..a2342cd 100644
--- a/libs/audioflinger/AudioHardwareGeneric.h
+++ b/libs/audioflinger/AudioHardwareGeneric.h
@@ -2,16 +2,16 @@
 **
 ** Copyright 2007, The Android Open Source Project
 **
-** Licensed under the Apache License, Version 2.0 (the "License"); 
-** you may not use this file except in compliance with the License. 
-** You may obtain a copy of the License at 
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
 **
-**     http://www.apache.org/licenses/LICENSE-2.0 
+**     http://www.apache.org/licenses/LICENSE-2.0
 **
-** Unless required by applicable law or agreed to in writing, software 
-** distributed under the License is distributed on an "AS IS" BASIS, 
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
-** See the License for the specific language governing permissions and 
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
 ** limitations under the License.
 */
 
@@ -23,7 +23,7 @@
 
 #include <utils/threads.h>
 
-#include <hardware/AudioHardwareInterface.h>
+#include <hardware/AudioHardwareBase.h>
 
 namespace android {
 
@@ -47,6 +47,7 @@
     virtual size_t      bufferSize() const { return 4096; }
     virtual int         channelCount() const { return 2; }
     virtual int         format() const { return AudioSystem::PCM_16_BIT; }
+    virtual uint32_t    latency() const { return 0; }
     virtual status_t    setVolume(float volume) { return INVALID_OPERATION; }
     virtual ssize_t     write(const void* buffer, size_t bytes);
     virtual status_t    dump(int fd, const Vector<String16>& args);
@@ -76,6 +77,7 @@
     virtual status_t    setGain(float gain) { return INVALID_OPERATION; }
     virtual ssize_t     read(void* buffer, ssize_t bytes);
     virtual status_t    dump(int fd, const Vector<String16>& args);
+    virtual status_t    standby() { return NO_ERROR; }
 
 private:
     AudioHardwareGeneric *mAudioHardware;
@@ -84,7 +86,7 @@
 };
 
 
-class AudioHardwareGeneric : public  AudioHardwareInterface
+class AudioHardwareGeneric : public AudioHardwareBase
 {
 public:
                         AudioHardwareGeneric();
@@ -105,12 +107,14 @@
     virtual AudioStreamOut* openOutputStream(
             int format=0,
             int channelCount=0,
-            uint32_t sampleRate=0);
+            uint32_t sampleRate=0,
+            status_t *status=0);
 
     virtual AudioStreamIn* openInputStream(
             int format,
             int channelCount,
-            uint32_t sampleRate);
+            uint32_t sampleRate,
+            status_t *status);
 
             void            closeOutputStream(AudioStreamOutGeneric* out);
             void            closeInputStream(AudioStreamInGeneric* in);
@@ -120,7 +124,7 @@
 
 private:
     status_t                dumpInternals(int fd, const Vector<String16>& args);
-    
+
     Mutex                   mLock;
     AudioStreamOutGeneric   *mOutput;
     AudioStreamInGeneric    *mInput;
diff --git a/libs/audioflinger/AudioHardwareInterface.cpp b/libs/audioflinger/AudioHardwareInterface.cpp
index 7387b3d..ac76a19 100644
--- a/libs/audioflinger/AudioHardwareInterface.cpp
+++ b/libs/audioflinger/AudioHardwareInterface.cpp
@@ -26,7 +26,7 @@
 #include "AudioHardwareStub.h"
 #include "AudioHardwareGeneric.h"
 
-// #define DUMP_FLINGER_OUT        // if defined allows recording samples in a file
+//#define DUMP_FLINGER_OUT        // if defined allows recording samples in a file
 #ifdef DUMP_FLINGER_OUT
 #include "AudioDumpInterface.h"
 #endif
@@ -54,6 +54,7 @@
     "SPEAKER ",
     "BLUETOOTH ",
     "HEADSET "
+    "BLUETOOTH_A2DP "
 };
 static const char* routeNone = "NONE";
 
@@ -115,24 +116,10 @@
     // This code adds a record of buffers in a file to write calls made by AudioFlinger.
     // It replaces the current AudioHardwareInterface object by an intermediate one which
     // will record buffers in a file (after sending them to hardware) for testing purpose.
-    // This feature is enabled by defining symbol DUMP_FLINGER_OUT and setting environement
-    // "audioflinger.dump = 1". The output file is "tmp/FlingerOut.pcm". Pause are not recorded
-    // in the file.
+    // This feature is enabled by defining symbol DUMP_FLINGER_OUT.
+    // The output file is FLINGER_DUMP_NAME. Pause are not recorded in the file.
     
-    // read dump mode
-    property_get("audioflinger.dump", value, "0");
-    switch(value[0]) {
-    case '1':
-        LOGV("Dump mode");
-        hw = new AudioDumpInterface(hw);    // replace interface
-        return hw;
-        break;
-    case '0':
-    default:
-        LOGV("No Dump mode");
-        return hw;
-        break;
-    }
+    hw = new AudioDumpInterface(hw);    // replace interface
 #endif
     return hw;
 }
@@ -143,7 +130,7 @@
 
 AudioStreamIn::~AudioStreamIn() {}
 
-AudioHardwareInterface::AudioHardwareInterface()
+AudioHardwareBase::AudioHardwareBase()
 {
     // force a routing update on initialization
     memset(&mRoutes, 0, sizeof(mRoutes));
@@ -151,7 +138,7 @@
 }
 
 // generics for audio routing - the real work is done in doRouting
-status_t AudioHardwareInterface::setRouting(int mode, uint32_t routes)
+status_t AudioHardwareBase::setRouting(int mode, uint32_t routes)
 {
 #if LOG_ROUTING_CALLS
     LOGD("setRouting: mode=%s, routes=[%s]", displayMode(mode), displayRoutes(routes));
@@ -173,7 +160,7 @@
     return doRouting();
 }
 
-status_t AudioHardwareInterface::getRouting(int mode, uint32_t* routes)
+status_t AudioHardwareBase::getRouting(int mode, uint32_t* routes)
 {
     if (mode == AudioSystem::MODE_CURRENT)
         mode = mMode;
@@ -187,7 +174,7 @@
     return NO_ERROR;
 }
 
-status_t AudioHardwareInterface::setMode(int mode)
+status_t AudioHardwareBase::setMode(int mode)
 {
 #if LOG_ROUTING_CALLS
     LOGD("setMode(%s)", displayMode(mode));
@@ -204,25 +191,45 @@
     return doRouting();
 }
 
-status_t AudioHardwareInterface::getMode(int* mode)
+status_t AudioHardwareBase::getMode(int* mode)
 {
     // Implement: set audio routing
     *mode = mMode;
     return NO_ERROR;
 }
 
-status_t AudioHardwareInterface::setParameter(const char* key, const char* value)
+status_t AudioHardwareBase::setParameter(const char* key, const char* value)
 {
     // default implementation is to ignore
     return NO_ERROR;
 }
 
-status_t AudioHardwareInterface::dumpState(int fd, const Vector<String16>& args)
+
+// default implementation
+size_t AudioHardwareBase::getInputBufferSize(uint32_t sampleRate, int format, int channelCount)
+{
+    if (sampleRate != 8000) {
+        LOGW("getInputBufferSize bad sampling rate: %d", sampleRate);
+        return 0;
+    }
+    if (format != AudioSystem::PCM_16_BIT) {
+        LOGW("getInputBufferSize bad format: %d", format);
+        return 0;
+    }
+    if (channelCount != 1) {
+        LOGW("getInputBufferSize bad channel count: %d", channelCount);
+        return 0;
+    }
+
+    return 320;
+}
+
+status_t AudioHardwareBase::dumpState(int fd, const Vector<String16>& args)
 {
     const size_t SIZE = 256;
     char buffer[SIZE];
     String8 result;
-    snprintf(buffer, SIZE, "AudioHardwareInterface::dumpState\n");
+    snprintf(buffer, SIZE, "AudioHardwareBase::dumpState\n");
     result.append(buffer);
     snprintf(buffer, SIZE, "\tmMode: %d\n", mMode);
     result.append(buffer);
diff --git a/libs/audioflinger/AudioHardwareStub.cpp b/libs/audioflinger/AudioHardwareStub.cpp
index 0046db8..d309902 100644
--- a/libs/audioflinger/AudioHardwareStub.cpp
+++ b/libs/audioflinger/AudioHardwareStub.cpp
@@ -2,16 +2,16 @@
 **
 ** Copyright 2007, The Android Open Source Project
 **
-** Licensed under the Apache License, Version 2.0 (the "License"); 
-** you may not use this file except in compliance with the License. 
-** You may obtain a copy of the License at 
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
 **
-**     http://www.apache.org/licenses/LICENSE-2.0 
+**     http://www.apache.org/licenses/LICENSE-2.0
 **
-** Unless required by applicable law or agreed to in writing, software 
-** distributed under the License is distributed on an "AS IS" BASIS, 
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
-** See the License for the specific language governing permissions and 
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
 ** limitations under the License.
 */
 
@@ -47,20 +47,28 @@
 }
 
 AudioStreamOut* AudioHardwareStub::openOutputStream(
-        int format, int channelCount, uint32_t sampleRate)
+        int format, int channelCount, uint32_t sampleRate, status_t *status)
 {
     AudioStreamOutStub* out = new AudioStreamOutStub();
-    if (out->set(format, channelCount, sampleRate) == NO_ERROR)
+    status_t lStatus = out->set(format, channelCount, sampleRate);
+    if (status) {
+        *status = lStatus;
+    }
+    if (lStatus == NO_ERROR)
         return out;
     delete out;
     return 0;
 }
 
 AudioStreamIn* AudioHardwareStub::openInputStream(
-        int format, int channelCount, uint32_t sampleRate)
+        int format, int channelCount, uint32_t sampleRate, status_t *status)
 {
     AudioStreamInStub* in = new AudioStreamInStub();
-    if (in->set(format, channelCount, sampleRate) == NO_ERROR)
+    status_t lStatus = in->set(format, channelCount, sampleRate);
+    if (status) {
+        *status = lStatus;
+    }
+    if (lStatus == NO_ERROR)
         return in;
     delete in;
     return 0;
@@ -102,7 +110,7 @@
     if (format == 0) format = AudioSystem::PCM_16_BIT;
     if (channels == 0) channels = channelCount();
     if (rate == 0) rate = sampleRate();
-    
+
     if ((format == AudioSystem::PCM_16_BIT) &&
             (channels == channelCount()) &&
             (rate == sampleRate()))
@@ -129,7 +137,7 @@
     snprintf(buffer, SIZE, "\tformat: %d\n", format());
     result.append(buffer);
     ::write(fd, result.string(), result.size());
-    return NO_ERROR; 
+    return NO_ERROR;
 }
 
 // ----------------------------------------------------------------------------
diff --git a/libs/audioflinger/AudioHardwareStub.h b/libs/audioflinger/AudioHardwareStub.h
index 1a61552..5316d60 100644
--- a/libs/audioflinger/AudioHardwareStub.h
+++ b/libs/audioflinger/AudioHardwareStub.h
@@ -2,16 +2,16 @@
 **
 ** Copyright 2007, The Android Open Source Project
 **
-** Licensed under the Apache License, Version 2.0 (the "License"); 
-** you may not use this file except in compliance with the License. 
-** You may obtain a copy of the License at 
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
 **
-**     http://www.apache.org/licenses/LICENSE-2.0 
+**     http://www.apache.org/licenses/LICENSE-2.0
 **
-** Unless required by applicable law or agreed to in writing, software 
-** distributed under the License is distributed on an "AS IS" BASIS, 
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
-** See the License for the specific language governing permissions and 
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
 ** limitations under the License.
 */
 
@@ -21,7 +21,7 @@
 #include <stdint.h>
 #include <sys/types.h>
 
-#include <hardware/AudioHardwareInterface.h>
+#include <hardware/AudioHardwareBase.h>
 
 namespace android {
 
@@ -34,6 +34,7 @@
     virtual size_t      bufferSize() const { return 4096; }
     virtual int         channelCount() const { return 2; }
     virtual int         format() const { return AudioSystem::PCM_16_BIT; }
+    virtual uint32_t    latency() const { return 0; }
     virtual status_t    setVolume(float volume) { return NO_ERROR; }
     virtual ssize_t     write(const void* buffer, size_t bytes);
     virtual status_t    dump(int fd, const Vector<String16>& args);
@@ -49,9 +50,10 @@
     virtual status_t    setGain(float gain) { return NO_ERROR; }
     virtual ssize_t     read(void* buffer, ssize_t bytes);
     virtual status_t    dump(int fd, const Vector<String16>& args);
+    virtual status_t    standby() { return NO_ERROR; }
 };
 
-class AudioHardwareStub : public  AudioHardwareInterface
+class AudioHardwareStub : public  AudioHardwareBase
 {
 public:
                         AudioHardwareStub();
@@ -72,12 +74,14 @@
     virtual AudioStreamOut* openOutputStream(
                                 int format=0,
                                 int channelCount=0,
-                                uint32_t sampleRate=0);
+                                uint32_t sampleRate=0,
+                                status_t *status=0);
 
     virtual AudioStreamIn* openInputStream(
                                 int format,
                                 int channelCount,
-                                uint32_t sampleRate);
+                                uint32_t sampleRate,
+                                status_t *status);
 
 protected:
     virtual status_t    doRouting() { return NO_ERROR; }
diff --git a/libs/audioflinger/AudioMixer.cpp b/libs/audioflinger/AudioMixer.cpp
index 9f1b17f..b03467f 100644
--- a/libs/audioflinger/AudioMixer.cpp
+++ b/libs/audioflinger/AudioMixer.cpp
@@ -2,16 +2,16 @@
 **
 ** Copyright 2007, The Android Open Source Project
 **
-** Licensed under the Apache License, Version 2.0 (the "License"); 
-** you may not use this file except in compliance with the License. 
-** You may obtain a copy of the License at 
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
 **
-**     http://www.apache.org/licenses/LICENSE-2.0 
+**     http://www.apache.org/licenses/LICENSE-2.0
 **
-** Unless required by applicable law or agreed to in writing, software 
-** distributed under the License is distributed on an "AS IS" BASIS, 
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
-** See the License for the specific language governing permissions and 
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
 ** limitations under the License.
 */
 
@@ -247,8 +247,8 @@
 void AudioMixer::track_t::adjustVolumeRamp()
 {
     for (int i=0 ; i<2 ; i++) {
-        if (((volumeInc[i]>0) && ((prevVolume[i]>>16) >= volume[i])) ||
-            ((volumeInc[i]<0) && ((prevVolume[i]>>16) <= volume[i]))) {
+        if (((volumeInc[i]>0) && (((prevVolume[i]+volumeInc[i])>>16) >= volume[i])) ||
+            ((volumeInc[i]<0) && (((prevVolume[i]+volumeInc[i])>>16) <= volume[i]))) {
             volumeInc[i] = 0;
             prevVolume[i] = volume[i]<<16;
         }
@@ -307,7 +307,7 @@
         n |= NEEDS_CHANNEL_1 + t.channelCount - 1;
         n |= NEEDS_FORMAT_16;
         n |= t.doesResample() ? NEEDS_RESAMPLE_ENABLED : NEEDS_RESAMPLE_DISABLED;
-        
+       
         if (t.volumeInc[0]|t.volumeInc[1]) {
             volumeRamp = 1;
         } else if (!t.doesResample() && t.volumeRL == 0) {
@@ -370,7 +370,7 @@
 
    state->hook(state, output);
 
-   // Now that the volume ramp has been done, set optimal state and 
+   // Now that the volume ramp has been done, set optimal state and
    // track hooks for subsequent mixer process
    if (countActiveTracks) {
        int allMuted = 1;
@@ -397,7 +397,7 @@
    }
 }
 
-static inline 
+static inline
 int32_t mulAdd(int16_t in, int16_t v, int32_t a)
 {
 #if defined(__arm__) && !defined(__thumb__)
@@ -412,7 +412,7 @@
 #endif
 }
 
-static inline 
+static inline
 int32_t mul(int16_t in, int16_t v)
 {
 #if defined(__arm__) && !defined(__thumb__)
@@ -427,7 +427,7 @@
 #endif
 }
 
-static inline 
+static inline
 int32_t mulAddRL(int left, uint32_t inRL, uint32_t vRL, int32_t a)
 {
 #if defined(__arm__) && !defined(__thumb__)
@@ -453,7 +453,7 @@
 #endif
 }
 
-static inline 
+static inline
 int32_t mulRL(int left, uint32_t inRL, uint32_t vRL)
 {
 #if defined(__arm__) && !defined(__thumb__)
@@ -513,7 +513,7 @@
     //LOGD("[0] %p: inc=%f, v0=%f, v1=%d, final=%f, count=%d",
     //        t, vlInc/65536.0f, vl/65536.0f, t->volume[0],
     //       (vl + vlInc*frameCount)/65536.0f, frameCount);
-    
+   
     // ramp volume
     do {
         *out++ += (vl >> 16) * (*temp++ >> 12);
@@ -548,7 +548,7 @@
             vl += vlInc;
             vr += vrInc;
         } while (--frameCount);
-        
+       
         t->prevVolume[0] = vl;
         t->prevVolume[1] = vr;
         t->adjustVolumeRamp();
@@ -590,7 +590,7 @@
             vl += vlInc;
             vr += vrInc;
         } while (--frameCount);
-        
+       
         t->prevVolume[0] = vl;
         t->prevVolume[1] = vr;
         t->adjustVolumeRamp();
@@ -609,7 +609,7 @@
     t->in = in;
 }
 
-inline 
+inline
 void AudioMixer::ditherAndClamp(int32_t* out, int32_t const *sums, size_t c)
 {
     for (size_t i=0 ; i<c ; i++) {
@@ -633,8 +633,12 @@
         const int i = 31 - __builtin_clz(en);
         en &= ~(1<<i);
         track_t& t = state->tracks[i];
-        t.bufferProvider->getNextBuffer(&t.buffer);
-        if (t.buffer.raw) {
+        size_t outFrames = state->frameCount;
+        while (outFrames) {
+            t.buffer.frameCount = outFrames;
+            t.bufferProvider->getNextBuffer(&t.buffer);
+            if (!t.buffer.raw) break;
+            outFrames -= t.buffer.frameCount;
             t.bufferProvider->releaseBuffer(&t.buffer);
         }
     }
@@ -652,12 +656,14 @@
         const int i = 31 - __builtin_clz(en);
         en &= ~(1<<i);
         track_t& t = state->tracks[i];
+        t.buffer.frameCount = state->frameCount;
         t.bufferProvider->getNextBuffer(&t.buffer);
+        t.frameCount = t.buffer.frameCount;
         t.in = t.buffer.raw;
         // t.in == NULL can happen if the track was flushed just after having
         // been enabled for mixing.
         if (t.in == NULL)
-            enabledTracks &= ~(1<<i); 
+            enabledTracks &= ~(1<<i);
     }
 
     // this assumes output 16 bits stereo, no resampling
@@ -671,12 +677,31 @@
             const int i = 31 - __builtin_clz(en);
             en &= ~(1<<i);
             track_t& t = state->tracks[i];
-            (t.hook)(&t, outTemp, BLOCKSIZE, state->resampleTemp);
+            size_t outFrames = BLOCKSIZE;
+           
+            while (outFrames) {
+                size_t inFrames = (t.frameCount > outFrames)?outFrames:t.frameCount;
+                if (inFrames) {
+                    (t.hook)(&t, outTemp + (BLOCKSIZE-outFrames)*MAX_NUM_CHANNELS, inFrames, state->resampleTemp);
+                    t.frameCount -= inFrames;
+                    outFrames -= inFrames;
+                }
+                if (t.frameCount == 0 && outFrames) {
+                    t.bufferProvider->releaseBuffer(&t.buffer);
+                    t.buffer.frameCount = numFrames - (BLOCKSIZE - outFrames);
+                    t.bufferProvider->getNextBuffer(&t.buffer);
+                    t.in = t.buffer.raw;
+                    if (t.in == NULL) {
+                        enabledTracks &= ~(1<<i);
+                        break;
+                    }
+                    t.frameCount = t.buffer.frameCount;
+                 }
+            }
         }
 
         ditherAndClamp(out, outTemp, BLOCKSIZE);
         out += BLOCKSIZE;
-
         numFrames -= BLOCKSIZE;
     } while (numFrames);
 
@@ -713,12 +738,19 @@
         if ((t.needs & NEEDS_RESAMPLE__MASK) == NEEDS_RESAMPLE_ENABLED) {
             (t.hook)(&t, outTemp, numFrames, state->resampleTemp);
         } else {
-            t.bufferProvider->getNextBuffer(&t.buffer);
-            t.in = t.buffer.raw;
-            // t.in == NULL can happen if the track was flushed just after having
-            // been enabled for mixing.
-            if (t.in) {
-                (t.hook)(&t, outTemp, numFrames, state->resampleTemp);
+
+            size_t outFrames = numFrames;
+           
+            while (outFrames) {
+                t.buffer.frameCount = outFrames;
+                t.bufferProvider->getNextBuffer(&t.buffer);
+                t.in = t.buffer.raw;
+                // t.in == NULL can happen if the track was flushed just after having
+                // been enabled for mixing.
+                if (t.in == NULL) break;
+
+                (t.hook)(&t, outTemp + (numFrames-outFrames)*MAX_NUM_CHANNELS, t.buffer.frameCount, state->resampleTemp);
+                outFrames -= t.buffer.frameCount;
                 t.bufferProvider->releaseBuffer(&t.buffer);
             }
         }
@@ -734,45 +766,51 @@
     const track_t& t = state->tracks[i];
 
     AudioBufferProvider::Buffer& b(t.buffer);
-    t.bufferProvider->getNextBuffer(&b);
-    int16_t const *in = t.buffer.i16;
-
-    // in == NULL can happen if the track was flushed just after having
-    // been enabled for mixing.
-    if (in == NULL) {
-        memset(output, 0, state->frameCount*MAX_NUM_CHANNELS*sizeof(int16_t));
-        return;
-    }
-    
+   
     int32_t* out = static_cast<int32_t*>(output);
     size_t numFrames = state->frameCount;
+  
     const int16_t vl = t.volume[0];
     const int16_t vr = t.volume[1];
     const uint32_t vrl = t.volumeRL;
-    if (UNLIKELY(uint32_t(vl) > UNITY_GAIN || uint32_t(vr) > UNITY_GAIN)) {
-        // volume is boosted, so we might need to clamp even though
-        // we process only one track.
-        do {
-            uint32_t rl = *reinterpret_cast<uint32_t const *>(in);
-            in += 2;
-            int32_t l = mulRL(1, rl, vrl) >> 12;
-            int32_t r = mulRL(0, rl, vrl) >> 12;
-            // clamping...
-            l = clamp16(l);
-            r = clamp16(r);
-            *out++ = (r<<16) | (l & 0xFFFF);
-        } while (--numFrames);
-    } else {
-        do {
-            uint32_t rl = *reinterpret_cast<uint32_t const *>(in);
-            in += 2;
-            int32_t l = mulRL(1, rl, vrl) >> 12;
-            int32_t r = mulRL(0, rl, vrl) >> 12;
-            *out++ = (r<<16) | (l & 0xFFFF);
-        } while (--numFrames);
-    }
+    while (numFrames) {
+        b.frameCount = numFrames;
+        t.bufferProvider->getNextBuffer(&b);
+        int16_t const *in = b.i16;
 
-    t.bufferProvider->releaseBuffer(&b);
+        // in == NULL can happen if the track was flushed just after having
+        // been enabled for mixing.
+        if (in == NULL) {
+            memset(out, 0, numFrames*MAX_NUM_CHANNELS*sizeof(int16_t));
+            return;
+        }
+        size_t outFrames = b.frameCount;
+       
+        if (UNLIKELY(uint32_t(vl) > UNITY_GAIN || uint32_t(vr) > UNITY_GAIN)) {
+            // volume is boosted, so we might need to clamp even though
+            // we process only one track.
+            do {
+                uint32_t rl = *reinterpret_cast<uint32_t const *>(in);
+                in += 2;
+                int32_t l = mulRL(1, rl, vrl) >> 12;
+                int32_t r = mulRL(0, rl, vrl) >> 12;
+                // clamping...
+                l = clamp16(l);
+                r = clamp16(r);
+                *out++ = (r<<16) | (l & 0xFFFF);
+            } while (--outFrames);
+        } else {
+            do {
+                uint32_t rl = *reinterpret_cast<uint32_t const *>(in);
+                in += 2;
+                int32_t l = mulRL(1, rl, vrl) >> 12;
+                int32_t r = mulRL(0, rl, vrl) >> 12;
+                *out++ = (r<<16) | (l & 0xFFFF);
+            } while (--outFrames);
+        }
+        numFrames -= b.frameCount;
+        t.bufferProvider->releaseBuffer(&b);
+    }
 }
 
 // 2 tracks is also a common case
@@ -784,71 +822,89 @@
     i = 31 - __builtin_clz(en);
     const track_t& t0 = state->tracks[i];
     AudioBufferProvider::Buffer& b0(t0.buffer);
-    t0.bufferProvider->getNextBuffer(&b0);
 
     en &= ~(1<<i);
     i = 31 - __builtin_clz(en);
     const track_t& t1 = state->tracks[i];
     AudioBufferProvider::Buffer& b1(t1.buffer);
-    t1.bufferProvider->getNextBuffer(&b1);
-
+   
     int16_t const *in0;
     const int16_t vl0 = t0.volume[0];
     const int16_t vr0 = t0.volume[1];
+    size_t frameCount0 = 0;
+  
     int16_t const *in1;
     const int16_t vl1 = t1.volume[0];
     const int16_t vr1 = t1.volume[1];
-    size_t numFrames = state->frameCount;
+    size_t frameCount1 = 0;
+   
     int32_t* out = static_cast<int32_t*>(output);
+    size_t numFrames = state->frameCount;
+    int16_t const *buff = NULL;
 
-    // t0/1.buffer.i16 == NULL can happen if the track was flushed just after having
-    // been enabled for mixing.
-    if (t0.buffer.i16 != NULL) {
-        in0 = t0.buffer.i16;
-        if (t1.buffer.i16 != NULL) {
-            in1 = t1.buffer.i16;
-        } else {
-            in1 = new int16_t[MAX_NUM_CHANNELS * state->frameCount];
-            memset((void *)in1, 0, state->frameCount*MAX_NUM_CHANNELS*sizeof(int16_t));
+  
+    while (numFrames) {
+   
+        if (frameCount0 == 0) {
+            b0.frameCount = numFrames;
+            t0.bufferProvider->getNextBuffer(&b0);
+            if (b0.i16 == NULL) {
+                if (buff == NULL) {
+                    buff = new int16_t[MAX_NUM_CHANNELS * state->frameCount];
+                }
+                in0 = buff;
+                b0.frameCount = numFrames;
+            } else {
+                in0 = b0.i16;
+            }
+            frameCount0 = b0.frameCount;
         }
-    } else {
-        in0 = new int16_t[MAX_NUM_CHANNELS * state->frameCount];
-        memset((void *)in0, 0, state->frameCount*MAX_NUM_CHANNELS*sizeof(int16_t));
-        if (t1.buffer.i16 != NULL) {
-            in1 = t1.buffer.i16;
-        } else {
-            in1 = in0;
+        if (frameCount1 == 0) {
+            b1.frameCount = numFrames;
+            t1.bufferProvider->getNextBuffer(&b1);
+            if (b1.i16 == NULL) {
+                if (buff == NULL) {
+                    buff = new int16_t[MAX_NUM_CHANNELS * state->frameCount];
+                }
+                in1 = buff;
+                b1.frameCount = numFrames;
+               } else {
+                in1 = b1.i16;
+            }
+            frameCount1 = b1.frameCount;
         }
-    }
-    
-    do {
-        int32_t l0 = *in0++;
-        int32_t r0 = *in0++;
-        l0 = mul(l0, vl0);
-        r0 = mul(r0, vr0);
-        int32_t l = *in1++;
-        int32_t r = *in1++;
-        l = mulAdd(l, vl1, l0) >> 12;
-        r = mulAdd(r, vr1, r0) >> 12;
-        // clamping...
-        l = clamp16(l);
-        r = clamp16(r);
-        *out++ = (r<<16) | (l & 0xFFFF);
-    } while (--numFrames);
+       
+        size_t outFrames = frameCount0 < frameCount1?frameCount0:frameCount1;
 
-    
-    if (t0.buffer.i16 != NULL) {
-        t0.bufferProvider->releaseBuffer(&b0);
-        if (t1.buffer.i16 != NULL) {
-            t1.bufferProvider->releaseBuffer(&b1);
-        } else {
-            delete [] in1;
+        numFrames -= outFrames;
+        frameCount0 -= outFrames;
+        frameCount1 -= outFrames;
+       
+        do {
+            int32_t l0 = *in0++;
+            int32_t r0 = *in0++;
+            l0 = mul(l0, vl0);
+            r0 = mul(r0, vr0);
+            int32_t l = *in1++;
+            int32_t r = *in1++;
+            l = mulAdd(l, vl1, l0) >> 12;
+            r = mulAdd(r, vr1, r0) >> 12;
+            // clamping...
+            l = clamp16(l);
+            r = clamp16(r);
+            *out++ = (r<<16) | (l & 0xFFFF);
+        } while (--outFrames);
+       
+        if (frameCount0 == 0) {
+            t0.bufferProvider->releaseBuffer(&b0);
         }
-    } else {
-        delete [] in0;
-        if (t1.buffer.i16 != NULL) {
+        if (frameCount1 == 0) {
             t1.bufferProvider->releaseBuffer(&b1);
         }
+    }   
+       
+    if (buff != NULL) {
+        delete [] buff;       
     }
 }
 
diff --git a/libs/audioflinger/AudioMixer.h b/libs/audioflinger/AudioMixer.h
index 9ca109f..72ca28a 100644
--- a/libs/audioflinger/AudioMixer.h
+++ b/libs/audioflinger/AudioMixer.h
@@ -2,16 +2,16 @@
 **
 ** Copyright 2007, The Android Open Source Project
 **
-** Licensed under the Apache License, Version 2.0 (the "License"); 
-** you may not use this file except in compliance with the License. 
-** You may obtain a copy of the License at 
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
 **
-**     http://www.apache.org/licenses/LICENSE-2.0 
+**     http://www.apache.org/licenses/LICENSE-2.0
 **
-** Unless required by applicable law or agreed to in writing, software 
-** distributed under the License is distributed on an "AS IS" BASIS, 
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
-** See the License for the specific language governing permissions and 
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
 ** limitations under the License.
 */
 
@@ -130,7 +130,7 @@
 
         int32_t     volumeInc[2];
 
-        uint16_t    reserved;
+        uint16_t    frameCount;
 
         uint8_t     channelCount : 4;
         uint8_t     enabled      : 1;
diff --git a/libs/audioflinger/AudioResampler.cpp b/libs/audioflinger/AudioResampler.cpp
index c93ead3..5dabacb 100644
--- a/libs/audioflinger/AudioResampler.cpp
+++ b/libs/audioflinger/AudioResampler.cpp
@@ -14,17 +14,23 @@
  * limitations under the License.
  */
 
+#define LOG_TAG "AudioResampler"
+//#define LOG_NDEBUG 0
+
 #include <stdint.h>
 #include <stdlib.h>
 #include <sys/types.h>
 #include <cutils/log.h>
 #include <cutils/properties.h>
-
 #include "AudioResampler.h"
 #include "AudioResamplerSinc.h"
 #include "AudioResamplerCubic.h"
 
 namespace android {
+
+#ifdef __ARM_ARCH_5E__  // optimized asm option
+    #define ASM_ARM_RESAMP1 // enable asm optimisation for ResamplerOrder1
+#endif // __ARM_ARCH_5E__
 // ----------------------------------------------------------------------------
 
 class AudioResamplerOrder1 : public AudioResampler {
@@ -46,6 +52,15 @@
             AudioBufferProvider* provider);
     void resampleStereo16(int32_t* out, size_t outFrameCount,
             AudioBufferProvider* provider);
+#ifdef ASM_ARM_RESAMP1  // asm optimisation for ResamplerOrder1
+    void AsmMono16Loop(int16_t *in, int32_t* maxOutPt, int32_t maxInIdx,
+            size_t &outputIndex, int32_t* out, size_t &inputIndex, int32_t vl, int32_t vr,
+            uint32_t &phaseFraction, uint32_t phaseIncrement);
+    void AsmStereo16Loop(int16_t *in, int32_t* maxOutPt, int32_t maxInIdx,
+            size_t &outputIndex, int32_t* out, size_t &inputIndex, int32_t vl, int32_t vr,
+            uint32_t &phaseFraction, uint32_t phaseIncrement);
+#endif  // ASM_ARM_RESAMP1
+
     static inline int32_t Interp(int32_t x0, int32_t x1, uint32_t f) {
         return x0 + (((x1 - x0) * (int32_t)(f >> kPreInterpShift)) >> kNumInterpBits);
     }
@@ -73,20 +88,23 @@
 
     if (quality == DEFAULT)
         quality = LOW_QUALITY;
-    
+
     switch (quality) {
     default:
     case LOW_QUALITY:
+        LOGV("Create linear Resampler");
         resampler = new AudioResamplerOrder1(bitDepth, inChannelCount, sampleRate);
         break;
     case MED_QUALITY:
+        LOGV("Create cubic Resampler");
         resampler = new AudioResamplerCubic(bitDepth, inChannelCount, sampleRate);
         break;
     case HIGH_QUALITY:
+        LOGV("Create sinc Resampler");
         resampler = new AudioResamplerSinc(bitDepth, inChannelCount, sampleRate);
         break;
     }
-    
+
     // initialize resampler
     resampler->init();
     return resampler;
@@ -103,10 +121,10 @@
                 inChannelCount);
         // LOG_ASSERT(0);
     }
-    
+
     // initialize common members
     mVolume[0] = mVolume[1] = 0;
-    mBuffer.raw = NULL;
+    mBuffer.frameCount = 0;
 
     // save format for quick lookup
     if (inChannelCount == 1) {
@@ -160,19 +178,31 @@
     uint32_t phaseIncrement = mPhaseIncrement;
     size_t outputIndex = 0;
     size_t outputSampleCount = outFrameCount * 2;
+    size_t inFrameCount = (outFrameCount*mInSampleRate)/mSampleRate;
 
     // LOGE("starting resample %d frames, inputIndex=%d, phaseFraction=%d, phaseIncrement=%d\n",
-    //		outFrameCount, inputIndex, phaseFraction, phaseIncrement);
+    //      outFrameCount, inputIndex, phaseFraction, phaseIncrement);
 
     while (outputIndex < outputSampleCount) {
 
         // buffer is empty, fetch a new one
-        if (mBuffer.raw == NULL) {
+        while (mBuffer.frameCount == 0) {
+            mBuffer.frameCount = inFrameCount;
             provider->getNextBuffer(&mBuffer);
-            if (mBuffer.raw == NULL)
-                break;
+            if (mBuffer.raw == NULL) {
+                goto resampleStereo16_exit;
+            }
+
             // LOGE("New buffer fetched: %d frames\n", mBuffer.frameCount);
+            if (mBuffer.frameCount > inputIndex) break;
+
+            inputIndex -= mBuffer.frameCount;
+            mX0L = mBuffer.i16[mBuffer.frameCount*2-2];
+            mX0R = mBuffer.i16[mBuffer.frameCount*2-1];
+            provider->releaseBuffer(&mBuffer);
+             // mBuffer.frameCount == 0 now so we reload a new buffer
         }
+
         int16_t *in = mBuffer.i16;
 
         // handle boundary case
@@ -187,34 +217,47 @@
 
         // process input samples
         // LOGE("general case\n");
-        while (outputIndex < outputSampleCount) {
+
+#ifdef ASM_ARM_RESAMP1  // asm optimisation for ResamplerOrder1
+        if (inputIndex + 2 < mBuffer.frameCount) {
+            int32_t* maxOutPt;
+            int32_t maxInIdx;
+
+            maxOutPt = out + (outputSampleCount - 2);   // 2 because 2 frames per loop
+            maxInIdx = mBuffer.frameCount - 2;
+            AsmStereo16Loop(in, maxOutPt, maxInIdx, outputIndex, out, inputIndex, vl, vr,
+                    phaseFraction, phaseIncrement);
+        }
+#endif  // ASM_ARM_RESAMP1
+
+        while (outputIndex < outputSampleCount && inputIndex < mBuffer.frameCount) {
             out[outputIndex++] += vl * Interp(in[inputIndex*2-2],
                     in[inputIndex*2], phaseFraction);
             out[outputIndex++] += vr * Interp(in[inputIndex*2-1],
                     in[inputIndex*2+1], phaseFraction);
             Advance(&inputIndex, &phaseFraction, phaseIncrement);
-            if (inputIndex >= mBuffer.frameCount)
-                break;
         }
+
         // LOGE("loop done - outputIndex=%d, inputIndex=%d\n", outputIndex, inputIndex);
 
         // if done with buffer, save samples
         if (inputIndex >= mBuffer.frameCount) {
             inputIndex -= mBuffer.frameCount;
 
-            // LOGE("buffer done, new input index", inputIndex);
+            // LOGE("buffer done, new input index %d", inputIndex);
 
             mX0L = mBuffer.i16[mBuffer.frameCount*2-2];
             mX0R = mBuffer.i16[mBuffer.frameCount*2-1];
             provider->releaseBuffer(&mBuffer);
 
-            // verify that the releaseBuffer NULLS the buffer pointer 
-            // LOG_ASSERT(mBuffer.raw == NULL);
+            // verify that the releaseBuffer resets the buffer frameCount
+            // LOG_ASSERT(mBuffer.frameCount == 0);
         }
     }
 
     // LOGE("output buffer full - outputIndex=%d, inputIndex=%d\n", outputIndex, inputIndex);
 
+resampleStereo16_exit:
     // save state
     mInputIndex = inputIndex;
     mPhaseFraction = phaseFraction;
@@ -231,18 +274,27 @@
     uint32_t phaseIncrement = mPhaseIncrement;
     size_t outputIndex = 0;
     size_t outputSampleCount = outFrameCount * 2;
+    size_t inFrameCount = (outFrameCount*mInSampleRate)/mSampleRate;
 
     // LOGE("starting resample %d frames, inputIndex=%d, phaseFraction=%d, phaseIncrement=%d\n",
     //      outFrameCount, inputIndex, phaseFraction, phaseIncrement);
-
     while (outputIndex < outputSampleCount) {
-
         // buffer is empty, fetch a new one
-        if (mBuffer.raw == NULL) {
+        while (mBuffer.frameCount == 0) {
+            mBuffer.frameCount = inFrameCount;
             provider->getNextBuffer(&mBuffer);
-            if (mBuffer.raw == NULL)
-                break;
+            if (mBuffer.raw == NULL) {
+                mInputIndex = inputIndex;
+                mPhaseFraction = phaseFraction;
+                goto resampleMono16_exit;
+            }
             // LOGE("New buffer fetched: %d frames\n", mBuffer.frameCount);
+            if (mBuffer.frameCount >  inputIndex) break;
+
+            inputIndex -= mBuffer.frameCount;
+            mX0L = mBuffer.i16[mBuffer.frameCount-1];
+            provider->releaseBuffer(&mBuffer);
+            // mBuffer.frameCount == 0 now so we reload a new buffer
         }
         int16_t *in = mBuffer.i16;
 
@@ -259,38 +311,284 @@
 
         // process input samples
         // LOGE("general case\n");
-        while (outputIndex < outputSampleCount) {
+
+#ifdef ASM_ARM_RESAMP1  // asm optimisation for ResamplerOrder1
+        if (inputIndex + 2 < mBuffer.frameCount) {
+            int32_t* maxOutPt;
+            int32_t maxInIdx;
+
+            maxOutPt = out + (outputSampleCount - 2);
+            maxInIdx = (int32_t)mBuffer.frameCount - 2;
+                AsmMono16Loop(in, maxOutPt, maxInIdx, outputIndex, out, inputIndex, vl, vr,
+                        phaseFraction, phaseIncrement);
+        }
+#endif  // ASM_ARM_RESAMP1
+
+        while (outputIndex < outputSampleCount && inputIndex < mBuffer.frameCount) {
             int32_t sample = Interp(in[inputIndex-1], in[inputIndex],
                     phaseFraction);
             out[outputIndex++] += vl * sample;
             out[outputIndex++] += vr * sample;
             Advance(&inputIndex, &phaseFraction, phaseIncrement);
-            if (inputIndex >= mBuffer.frameCount)
-                break;
         }
+
+
         // LOGE("loop done - outputIndex=%d, inputIndex=%d\n", outputIndex, inputIndex);
 
         // if done with buffer, save samples
         if (inputIndex >= mBuffer.frameCount) {
             inputIndex -= mBuffer.frameCount;
 
-            // LOGE("buffer done, new input index", inputIndex);
+            // LOGE("buffer done, new input index %d", inputIndex);
 
             mX0L = mBuffer.i16[mBuffer.frameCount-1];
             provider->releaseBuffer(&mBuffer);
 
-            // verify that the releaseBuffer NULLS the buffer pointer 
-            // LOG_ASSERT(mBuffer.raw == NULL);
+            // verify that the releaseBuffer resets the buffer frameCount
+            // LOG_ASSERT(mBuffer.frameCount == 0);
         }
     }
 
     // LOGE("output buffer full - outputIndex=%d, inputIndex=%d\n", outputIndex, inputIndex);
 
+resampleMono16_exit:
     // save state
     mInputIndex = inputIndex;
     mPhaseFraction = phaseFraction;
 }
 
+#ifdef ASM_ARM_RESAMP1  // asm optimisation for ResamplerOrder1
+
+/*******************************************************************
+*
+*   AsmMono16Loop
+*   asm optimized monotonic loop version; one loop is 2 frames
+*   Input:
+*       in : pointer on input samples
+*       maxOutPt : pointer on first not filled
+*       maxInIdx : index on first not used
+*       outputIndex : pointer on current output index
+*       out : pointer on output buffer
+*       inputIndex : pointer on current input index
+*       vl, vr : left and right gain
+*       phaseFraction : pointer on current phase fraction
+*       phaseIncrement
+*   Ouput:
+*       outputIndex :
+*       out : updated buffer
+*       inputIndex : index of next to use
+*       phaseFraction : phase fraction for next interpolation
+*
+*******************************************************************/
+void AudioResamplerOrder1::AsmMono16Loop(int16_t *in, int32_t* maxOutPt, int32_t maxInIdx,
+            size_t &outputIndex, int32_t* out, size_t &inputIndex, int32_t vl, int32_t vr,
+            uint32_t &phaseFraction, uint32_t phaseIncrement)
+{
+#define MO_PARAM5   "36"        // offset of parameter 5 (outputIndex)
+
+    asm(
+        "stmfd  sp!, {r4, r5, r6, r7, r8, r9, r10, r11, lr}\n"
+        // get parameters
+        "   ldr r6, [sp, #" MO_PARAM5 " + 20]\n"    // &phaseFraction
+        "   ldr r6, [r6]\n"                         // phaseFraction
+        "   ldr r7, [sp, #" MO_PARAM5 " + 8]\n"     // &inputIndex
+        "   ldr r7, [r7]\n"                         // inputIndex
+        "   ldr r8, [sp, #" MO_PARAM5 " + 4]\n"     // out
+        "   ldr r0, [sp, #" MO_PARAM5 " + 0]\n"     // &outputIndex
+        "   ldr r0, [r0]\n"                         // outputIndex
+        "   add r8, r0, asl #2\n"                   // curOut
+        "   ldr r9, [sp, #" MO_PARAM5 " + 24]\n"    // phaseIncrement
+        "   ldr r10, [sp, #" MO_PARAM5 " + 12]\n"   // vl
+        "   ldr r11, [sp, #" MO_PARAM5 " + 16]\n"   // vr
+
+        // r0 pin, x0, Samp
+
+        // r1 in
+        // r2 maxOutPt
+        // r3 maxInIdx
+
+        // r4 x1, i1, i3, Out1
+        // r5 out0
+
+        // r6 frac
+        // r7 inputIndex
+        // r8 curOut
+
+        // r9 inc
+        // r10 vl
+        // r11 vr
+
+        // r12
+        // r13 sp
+        // r14
+
+        // the following loop works on 2 frames
+
+        ".Y4L01:\n"
+        "   cmp r8, r2\n"                   // curOut - maxCurOut
+        "   bcs .Y4L02\n"
+
+#define MO_ONE_FRAME \
+    "   add r0, r1, r7, asl #1\n"       /* in + inputIndex */\
+    "   ldrsh r4, [r0]\n"               /* in[inputIndex] */\
+    "   ldr r5, [r8]\n"                 /* out[outputIndex] */\
+    "   ldrsh r0, [r0, #-2]\n"          /* in[inputIndex-1] */\
+    "   bic r6, r6, #0xC0000000\n"      /* phaseFraction & ... */\
+    "   sub r4, r4, r0\n"               /* in[inputIndex] - in[inputIndex-1] */\
+    "   mov r4, r4, lsl #2\n"           /* <<2 */\
+    "   smulwt r4, r4, r6\n"            /* (x1-x0)*.. */\
+    "   add r6, r6, r9\n"               /* phaseFraction + phaseIncrement */\
+    "   add r0, r0, r4\n"               /* x0 - (..) */\
+    "   mla r5, r0, r10, r5\n"          /* vl*interp + out[] */\
+    "   ldr r4, [r8, #4]\n"             /* out[outputIndex+1] */\
+    "   str r5, [r8], #4\n"             /* out[outputIndex++] = ... */\
+    "   mla r4, r0, r11, r4\n"          /* vr*interp + out[] */\
+    "   add r7, r7, r6, lsr #30\n"      /* inputIndex + phaseFraction>>30 */\
+    "   str r4, [r8], #4\n"             /* out[outputIndex++] = ... */
+
+        MO_ONE_FRAME    // frame 1
+        MO_ONE_FRAME    // frame 2
+
+        "   cmp r7, r3\n"                   // inputIndex - maxInIdx
+        "   bcc .Y4L01\n"
+        ".Y4L02:\n"
+
+        "   bic r6, r6, #0xC0000000\n"             // phaseFraction & ...
+        // save modified values
+        "   ldr r0, [sp, #" MO_PARAM5 " + 20]\n"    // &phaseFraction
+        "   str r6, [r0]\n"                         // phaseFraction
+        "   ldr r0, [sp, #" MO_PARAM5 " + 8]\n"     // &inputIndex
+        "   str r7, [r0]\n"                         // inputIndex
+        "   ldr r0, [sp, #" MO_PARAM5 " + 4]\n"     // out
+        "   sub r8, r0\n"                           // curOut - out
+        "   asr r8, #2\n"                           // new outputIndex
+        "   ldr r0, [sp, #" MO_PARAM5 " + 0]\n"     // &outputIndex
+        "   str r8, [r0]\n"                         // save outputIndex
+
+        "   ldmfd   sp!, {r4, r5, r6, r7, r8, r9, r10, r11, pc}\n"
+    );
+}
+
+/*******************************************************************
+*
+*   AsmStereo16Loop
+*   asm optimized stereo loop version; one loop is 2 frames
+*   Input:
+*       in : pointer on input samples
+*       maxOutPt : pointer on first not filled
+*       maxInIdx : index on first not used
+*       outputIndex : pointer on current output index
+*       out : pointer on output buffer
+*       inputIndex : pointer on current input index
+*       vl, vr : left and right gain
+*       phaseFraction : pointer on current phase fraction
+*       phaseIncrement
+*   Ouput:
+*       outputIndex :
+*       out : updated buffer
+*       inputIndex : index of next to use
+*       phaseFraction : phase fraction for next interpolation
+*
+*******************************************************************/
+void AudioResamplerOrder1::AsmStereo16Loop(int16_t *in, int32_t* maxOutPt, int32_t maxInIdx,
+            size_t &outputIndex, int32_t* out, size_t &inputIndex, int32_t vl, int32_t vr,
+            uint32_t &phaseFraction, uint32_t phaseIncrement)
+{
+#define ST_PARAM5    "40"     // offset of parameter 5 (outputIndex)
+    asm(
+        "stmfd  sp!, {r4, r5, r6, r7, r8, r9, r10, r11, r12, lr}\n"
+        // get parameters
+        "   ldr r6, [sp, #" ST_PARAM5 " + 20]\n"    // &phaseFraction
+        "   ldr r6, [r6]\n"                         // phaseFraction
+        "   ldr r7, [sp, #" ST_PARAM5 " + 8]\n"     // &inputIndex
+        "   ldr r7, [r7]\n"                         // inputIndex
+        "   ldr r8, [sp, #" ST_PARAM5 " + 4]\n"     // out
+        "   ldr r0, [sp, #" ST_PARAM5 " + 0]\n"     // &outputIndex
+        "   ldr r0, [r0]\n"                         // outputIndex
+        "   add r8, r0, asl #2\n"                   // curOut
+        "   ldr r9, [sp, #" ST_PARAM5 " + 24]\n"    // phaseIncrement
+        "   ldr r10, [sp, #" ST_PARAM5 " + 12]\n"   // vl
+        "   ldr r11, [sp, #" ST_PARAM5 " + 16]\n"   // vr
+
+        // r0 pin, x0, Samp
+
+        // r1 in
+        // r2 maxOutPt
+        // r3 maxInIdx
+
+        // r4 x1, i1, i3, out1
+        // r5 out0
+
+        // r6 frac
+        // r7 inputIndex
+        // r8 curOut
+
+        // r9 inc
+        // r10 vl
+        // r11 vr
+
+        // r12 temporary
+        // r13 sp
+        // r14
+
+        ".Y5L01:\n"
+        "   cmp r8, r2\n"                   // curOut - maxCurOut
+        "   bcs .Y5L02\n"
+
+#define ST_ONE_FRAME \
+    "   bic r6, r6, #0xC0000000\n"      /* phaseFraction & ... */\
+\
+    "   add r0, r1, r7, asl #2\n"       /* in + 2*inputIndex */\
+\
+    "   ldrsh r4, [r0]\n"               /* in[2*inputIndex] */\
+    "   ldr r5, [r8]\n"                 /* out[outputIndex] */\
+    "   ldrsh r12, [r0, #-4]\n"         /* in[2*inputIndex-2] */\
+    "   sub r4, r4, r12\n"              /* in[2*InputIndex] - in[2*InputIndex-2] */\
+    "   mov r4, r4, lsl #2\n"           /* <<2 */\
+    "   smulwt r4, r4, r6\n"            /* (x1-x0)*.. */\
+    "   add r12, r12, r4\n"             /* x0 - (..) */\
+    "   mla r5, r12, r10, r5\n"         /* vl*interp + out[] */\
+    "   ldr r4, [r8, #4]\n"             /* out[outputIndex+1] */\
+    "   str r5, [r8], #4\n"             /* out[outputIndex++] = ... */\
+\
+    "   ldrsh r12, [r0, #+2]\n"         /* in[2*inputIndex+1] */\
+    "   ldrsh r0, [r0, #-2]\n"          /* in[2*inputIndex-1] */\
+    "   sub r12, r12, r0\n"             /* in[2*InputIndex] - in[2*InputIndex-2] */\
+    "   mov r12, r12, lsl #2\n"         /* <<2 */\
+    "   smulwt r12, r12, r6\n"          /* (x1-x0)*.. */\
+    "   add r12, r0, r12\n"             /* x0 - (..) */\
+    "   mla r4, r12, r11, r4\n"         /* vr*interp + out[] */\
+    "   str r4, [r8], #4\n"             /* out[outputIndex++] = ... */\
+\
+    "   add r6, r6, r9\n"               /* phaseFraction + phaseIncrement */\
+    "   add r7, r7, r6, lsr #30\n"      /* inputIndex + phaseFraction>>30 */
+
+    ST_ONE_FRAME    // frame 1
+    ST_ONE_FRAME    // frame 1
+
+        "   cmp r7, r3\n"                       // inputIndex - maxInIdx
+        "   bcc .Y5L01\n"
+        ".Y5L02:\n"
+
+        "   bic r6, r6, #0xC0000000\n"              // phaseFraction & ...
+        // save modified values
+        "   ldr r0, [sp, #" ST_PARAM5 " + 20]\n"    // &phaseFraction
+        "   str r6, [r0]\n"                         // phaseFraction
+        "   ldr r0, [sp, #" ST_PARAM5 " + 8]\n"     // &inputIndex
+        "   str r7, [r0]\n"                         // inputIndex
+        "   ldr r0, [sp, #" ST_PARAM5 " + 4]\n"     // out
+        "   sub r8, r0\n"                           // curOut - out
+        "   asr r8, #2\n"                           // new outputIndex
+        "   ldr r0, [sp, #" ST_PARAM5 " + 0]\n"     // &outputIndex
+        "   str r8, [r0]\n"                         // save outputIndex
+
+        "   ldmfd   sp!, {r4, r5, r6, r7, r8, r9, r10, r11, r12, pc}\n"
+    );
+}
+
+#endif  // ASM_ARM_RESAMP1
+
+
 // ----------------------------------------------------------------------------
 }
 ; // namespace android
diff --git a/libs/audioflinger/AudioResamplerCubic.cpp b/libs/audioflinger/AudioResamplerCubic.cpp
index 4f437bf..1d247bd 100644
--- a/libs/audioflinger/AudioResamplerCubic.cpp
+++ b/libs/audioflinger/AudioResamplerCubic.cpp
@@ -60,9 +60,11 @@
     uint32_t phaseIncrement = mPhaseIncrement;
     size_t outputIndex = 0;
     size_t outputSampleCount = outFrameCount * 2;
-    
+    size_t inFrameCount = (outFrameCount*mInSampleRate)/mSampleRate;
+
     // fetch first buffer
-    if (mBuffer.raw == NULL) {
+    if (mBuffer.frameCount == 0) {
+        mBuffer.frameCount = inFrameCount;
         provider->getNextBuffer(&mBuffer);
         if (mBuffer.raw == NULL)
             return;
@@ -79,7 +81,7 @@
         out[outputIndex++] += vl * interp(&left, x);
         out[outputIndex++] += vr * interp(&right, x);
         // out[outputIndex++] += vr * in[inputIndex*2];
-        
+
         // increment phase
         phaseFraction += phaseIncrement;
         uint32_t indexIncrement = (phaseFraction >> kNumPhaseBits);
@@ -92,6 +94,7 @@
             if (inputIndex == mBuffer.frameCount) {
                 inputIndex = 0;
                 provider->releaseBuffer(&mBuffer);
+                mBuffer.frameCount = inFrameCount;
                 provider->getNextBuffer(&mBuffer);
                 if (mBuffer.raw == NULL)
                     goto save_state;  // ugly, but efficient
@@ -122,9 +125,11 @@
     uint32_t phaseIncrement = mPhaseIncrement;
     size_t outputIndex = 0;
     size_t outputSampleCount = outFrameCount * 2;
-    
+    size_t inFrameCount = (outFrameCount*mInSampleRate)/mSampleRate;
+
     // fetch first buffer
-    if (mBuffer.raw == NULL) {
+    if (mBuffer.frameCount == 0) {
+        mBuffer.frameCount = inFrameCount;
         provider->getNextBuffer(&mBuffer);
         if (mBuffer.raw == NULL)
             return;
@@ -141,7 +146,7 @@
         sample = interp(&left, x);
         out[outputIndex++] += vl * sample;
         out[outputIndex++] += vr * sample;
-        
+
         // increment phase
         phaseFraction += phaseIncrement;
         uint32_t indexIncrement = (phaseFraction >> kNumPhaseBits);
@@ -154,6 +159,7 @@
             if (inputIndex == mBuffer.frameCount) {
                 inputIndex = 0;
                 provider->releaseBuffer(&mBuffer);
+                mBuffer.frameCount = inFrameCount;
                 provider->getNextBuffer(&mBuffer);
                 if (mBuffer.raw == NULL)
                     goto save_state;  // ugly, but efficient
diff --git a/libs/audioflinger/AudioResamplerSinc.cpp b/libs/audioflinger/AudioResamplerSinc.cpp
index e710d16..9e5e254 100644
--- a/libs/audioflinger/AudioResamplerSinc.cpp
+++ b/libs/audioflinger/AudioResamplerSinc.cpp
@@ -25,18 +25,18 @@
  * These coeficients are computed with the "fir" utility found in
  * tools/resampler_tools
  * TODO: A good optimization would be to transpose this matrix, to take
- * better advantage of the data-cache. 
+ * better advantage of the data-cache.
  */
 const int32_t AudioResamplerSinc::mFirCoefsUp[] = {
-		0x7fffffff, 0x7f15d078, 0x7c5e0da6, 0x77ecd867, 0x71e2e251, 0x6a6c304a, 0x61be7269, 0x58170412, 0x4db8ab05, 0x42e92ea6, 0x37eee214, 0x2d0e3bb1, 0x22879366, 0x18951e95, 0x0f693d0d, 0x072d2621, 
-	    0x00000000, 0xf9f66655, 0xf51a5fd7, 0xf16bbd84, 0xeee0d9ac, 0xed67a922, 0xece70de6, 0xed405897, 0xee50e505, 0xeff3be30, 0xf203370f, 0xf45a6741, 0xf6d67d53, 0xf957db66, 0xfbc2f647, 0xfe00f2b9, 
-	    0x00000000, 0x01b37218, 0x0313a0c6, 0x041d930d, 0x04d28057, 0x053731b0, 0x05534dff, 0x05309bfd, 0x04da440d, 0x045c1aee, 0x03c1fcdd, 0x03173ef5, 0x02663ae8, 0x01b7f736, 0x0113ec79, 0x007fe6a9, 
-	    0x00000000, 0xff96b229, 0xff44f99f, 0xff0a86be, 0xfee5f803, 0xfed518fd, 0xfed521fd, 0xfee2f4fd, 0xfefb54f8, 0xff1b159b, 0xff3f4203, 0xff6539e0, 0xff8ac502, 0xffae1ddd, 0xffcdf3f9, 0xffe96798, 
-	    0x00000000, 0x00119de6, 0x001e6b7e, 0x0026cb7a, 0x002b4830, 0x002c83d6, 0x002b2a82, 0x0027e67a, 0x002356f9, 0x001e098e, 0x001875e4, 0x0012fbbe, 0x000de2d1, 0x00095c10, 0x00058414, 0x00026636, 
-	    0x00000000, 0xfffe44a9, 0xfffd206d, 0xfffc7b7f, 0xfffc3c8f, 0xfffc4ac2, 0xfffc8f2b, 0xfffcf5c4, 0xfffd6df3, 0xfffdeab2, 0xfffe6275, 0xfffececf, 0xffff2c07, 0xffff788c, 0xffffb471, 0xffffe0f2, 
-	    0x00000000, 0x000013e6, 0x00001f03, 0x00002396, 0x00002399, 0x000020b6, 0x00001c3c, 0x00001722, 0x00001216, 0x00000d81, 0x0000099c, 0x0000067c, 0x00000419, 0x0000025f, 0x00000131, 0x00000070, 
-	    0x00000000, 0xffffffc7, 0xffffffb3, 0xffffffb3, 0xffffffbe, 0xffffffcd, 0xffffffdb, 0xffffffe7, 0xfffffff0, 0xfffffff7, 0xfffffffb, 0xfffffffe, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 
-	    0x00000000 // this one is needed for lerping the last coefficient
+        0x7fffffff, 0x7f15d078, 0x7c5e0da6, 0x77ecd867, 0x71e2e251, 0x6a6c304a, 0x61be7269, 0x58170412, 0x4db8ab05, 0x42e92ea6, 0x37eee214, 0x2d0e3bb1, 0x22879366, 0x18951e95, 0x0f693d0d, 0x072d2621,
+        0x00000000, 0xf9f66655, 0xf51a5fd7, 0xf16bbd84, 0xeee0d9ac, 0xed67a922, 0xece70de6, 0xed405897, 0xee50e505, 0xeff3be30, 0xf203370f, 0xf45a6741, 0xf6d67d53, 0xf957db66, 0xfbc2f647, 0xfe00f2b9,
+        0x00000000, 0x01b37218, 0x0313a0c6, 0x041d930d, 0x04d28057, 0x053731b0, 0x05534dff, 0x05309bfd, 0x04da440d, 0x045c1aee, 0x03c1fcdd, 0x03173ef5, 0x02663ae8, 0x01b7f736, 0x0113ec79, 0x007fe6a9,
+        0x00000000, 0xff96b229, 0xff44f99f, 0xff0a86be, 0xfee5f803, 0xfed518fd, 0xfed521fd, 0xfee2f4fd, 0xfefb54f8, 0xff1b159b, 0xff3f4203, 0xff6539e0, 0xff8ac502, 0xffae1ddd, 0xffcdf3f9, 0xffe96798,
+        0x00000000, 0x00119de6, 0x001e6b7e, 0x0026cb7a, 0x002b4830, 0x002c83d6, 0x002b2a82, 0x0027e67a, 0x002356f9, 0x001e098e, 0x001875e4, 0x0012fbbe, 0x000de2d1, 0x00095c10, 0x00058414, 0x00026636,
+        0x00000000, 0xfffe44a9, 0xfffd206d, 0xfffc7b7f, 0xfffc3c8f, 0xfffc4ac2, 0xfffc8f2b, 0xfffcf5c4, 0xfffd6df3, 0xfffdeab2, 0xfffe6275, 0xfffececf, 0xffff2c07, 0xffff788c, 0xffffb471, 0xffffe0f2,
+        0x00000000, 0x000013e6, 0x00001f03, 0x00002396, 0x00002399, 0x000020b6, 0x00001c3c, 0x00001722, 0x00001216, 0x00000d81, 0x0000099c, 0x0000067c, 0x00000419, 0x0000025f, 0x00000131, 0x00000070,
+        0x00000000, 0xffffffc7, 0xffffffb3, 0xffffffb3, 0xffffffbe, 0xffffffcd, 0xffffffdb, 0xffffffe7, 0xfffffff0, 0xfffffff7, 0xfffffffb, 0xfffffffe, 0xffffffff, 0x00000000, 0x00000000, 0x00000000,
+        0x00000000 // this one is needed for lerping the last coefficient
 };
 
 /*
@@ -46,20 +46,20 @@
  * these coefficient from the above by "Stretching" them in time).
  */
 const int32_t AudioResamplerSinc::mFirCoefsDown[] = {
-		0x7fffffff, 0x7f55e46d, 0x7d5b4c60, 0x7a1b4b98, 0x75a7fb14, 0x7019f0bd, 0x698f875a, 0x622bfd59, 0x5a167256, 0x5178cc54, 0x487e8e6c, 0x3f53aae8, 0x36235ad4, 0x2d17047b, 0x245539ab, 0x1c00d540, 
-	    0x14383e57, 0x0d14d5ca, 0x06aa910b, 0x0107c38b, 0xfc351654, 0xf835abae, 0xf5076b45, 0xf2a37202, 0xf0fe9faa, 0xf00a3bbd, 0xefb4aa81, 0xefea2b05, 0xf0959716, 0xf1a11e83, 0xf2f6f7a0, 0xf481fff4, 
-	    0xf62e48ce, 0xf7e98ca5, 0xf9a38b4c, 0xfb4e4bfa, 0xfcde456f, 0xfe4a6d30, 0xff8c2fdf, 0x009f5555, 0x0181d393, 0x0233940f, 0x02b62f06, 0x030ca07d, 0x033afa62, 0x03461725, 0x03334f83, 0x030835fa, 
-	    0x02ca59cc, 0x027f12d1, 0x022b570d, 0x01d39a49, 0x017bb78f, 0x0126e414, 0x00d7aaaf, 0x008feec7, 0x0050f584, 0x001b73e3, 0xffefa063, 0xffcd46ed, 0xffb3ddcd, 0xffa29aaa, 0xff988691, 0xff949066, 
-	    0xff959d24, 0xff9a959e, 0xffa27195, 0xffac4011, 0xffb72d2b, 0xffc28569, 0xffcdb706, 0xffd85171, 0xffe20364, 0xffea97e9, 0xfff1f2b2, 0xfff80c06, 0xfffcec92, 0x0000a955, 0x00035fd8, 0x000532cf, 
-	    0x00064735, 0x0006c1f9, 0x0006c62d, 0x000673ba, 0x0005e68f, 0x00053630, 0x000475a3, 0x0003b397, 0x0002fac1, 0x00025257, 0x0001be9e, 0x0001417a, 0x0000dafd, 0x000089eb, 0x00004c28, 0x00001f1d, 
-	    0x00000000, 0xffffec10, 0xffffe0be, 0xffffdbc5, 0xffffdb39, 0xffffdd8b, 0xffffe182, 0xffffe638, 0xffffeb0a, 0xffffef8f, 0xfffff38b, 0xfffff6e3, 0xfffff993, 0xfffffba6, 0xfffffd30, 0xfffffe4a, 
-	    0xffffff09, 0xffffff85, 0xffffffd1, 0xfffffffb, 0x0000000f, 0x00000016, 0x00000015, 0x00000012, 0x0000000d, 0x00000009, 0x00000006, 0x00000003, 0x00000002, 0x00000001, 0x00000000, 0x00000000, 
-	    0x00000000 // this one is needed for lerping the last coefficient
+        0x7fffffff, 0x7f55e46d, 0x7d5b4c60, 0x7a1b4b98, 0x75a7fb14, 0x7019f0bd, 0x698f875a, 0x622bfd59, 0x5a167256, 0x5178cc54, 0x487e8e6c, 0x3f53aae8, 0x36235ad4, 0x2d17047b, 0x245539ab, 0x1c00d540,
+        0x14383e57, 0x0d14d5ca, 0x06aa910b, 0x0107c38b, 0xfc351654, 0xf835abae, 0xf5076b45, 0xf2a37202, 0xf0fe9faa, 0xf00a3bbd, 0xefb4aa81, 0xefea2b05, 0xf0959716, 0xf1a11e83, 0xf2f6f7a0, 0xf481fff4,
+        0xf62e48ce, 0xf7e98ca5, 0xf9a38b4c, 0xfb4e4bfa, 0xfcde456f, 0xfe4a6d30, 0xff8c2fdf, 0x009f5555, 0x0181d393, 0x0233940f, 0x02b62f06, 0x030ca07d, 0x033afa62, 0x03461725, 0x03334f83, 0x030835fa,
+        0x02ca59cc, 0x027f12d1, 0x022b570d, 0x01d39a49, 0x017bb78f, 0x0126e414, 0x00d7aaaf, 0x008feec7, 0x0050f584, 0x001b73e3, 0xffefa063, 0xffcd46ed, 0xffb3ddcd, 0xffa29aaa, 0xff988691, 0xff949066,
+        0xff959d24, 0xff9a959e, 0xffa27195, 0xffac4011, 0xffb72d2b, 0xffc28569, 0xffcdb706, 0xffd85171, 0xffe20364, 0xffea97e9, 0xfff1f2b2, 0xfff80c06, 0xfffcec92, 0x0000a955, 0x00035fd8, 0x000532cf,
+        0x00064735, 0x0006c1f9, 0x0006c62d, 0x000673ba, 0x0005e68f, 0x00053630, 0x000475a3, 0x0003b397, 0x0002fac1, 0x00025257, 0x0001be9e, 0x0001417a, 0x0000dafd, 0x000089eb, 0x00004c28, 0x00001f1d,
+        0x00000000, 0xffffec10, 0xffffe0be, 0xffffdbc5, 0xffffdb39, 0xffffdd8b, 0xffffe182, 0xffffe638, 0xffffeb0a, 0xffffef8f, 0xfffff38b, 0xfffff6e3, 0xfffff993, 0xfffffba6, 0xfffffd30, 0xfffffe4a,
+        0xffffff09, 0xffffff85, 0xffffffd1, 0xfffffffb, 0x0000000f, 0x00000016, 0x00000015, 0x00000012, 0x0000000d, 0x00000009, 0x00000006, 0x00000003, 0x00000002, 0x00000001, 0x00000000, 0x00000000,
+        0x00000000 // this one is needed for lerping the last coefficient
 };
 
 // ----------------------------------------------------------------------------
 
-static inline 
+static inline
 int32_t mulRL(int left, int32_t in, uint32_t vRL)
 {
 #if defined(__arm__) && !defined(__thumb__)
@@ -85,7 +85,7 @@
 #endif
 }
 
-static inline 
+static inline
 int32_t mulAdd(int16_t in, int32_t v, int32_t a)
 {
 #if defined(__arm__) && !defined(__thumb__)
@@ -95,12 +95,14 @@
          : [in]"%r"(in), [v]"r"(v), [a]"r"(a)
          : );
     return out;
-#else    
-    return a + ((in * int32_t(v))>>16);
+#else
+    return a + in * (v>>16);
+    // improved precision
+    // return a + in * (v>>16) + ((in * (v & 0xffff)) >> 16);
 #endif
 }
 
-static inline 
+static inline
 int32_t mulAddRL(int left, uint32_t inRL, int32_t v, int32_t a)
 {
 #if defined(__arm__) && !defined(__thumb__)
@@ -119,9 +121,11 @@
     return out;
 #else
     if (left) {
-        return a + ((int16_t(inRL&0xFFFF) * int32_t(v))>>16);
+        return a + (int16_t(inRL&0xFFFF) * (v>>16));
+        //improved precision
+        // return a + (int16_t(inRL&0xFFFF) * (v>>16)) + ((int16_t(inRL&0xFFFF) * (v & 0xffff)) >> 16);
     } else {
-        return a + ((int16_t(inRL>>16) * int32_t(v))>>16);
+        return a + (int16_t(inRL>>16) * (v>>16));
     }
 #endif
 }
@@ -129,37 +133,37 @@
 // ----------------------------------------------------------------------------
 
 AudioResamplerSinc::AudioResamplerSinc(int bitDepth,
-		int inChannelCount, int32_t sampleRate)
-	: AudioResampler(bitDepth, inChannelCount, sampleRate),
-	mState(0)
+        int inChannelCount, int32_t sampleRate)
+    : AudioResampler(bitDepth, inChannelCount, sampleRate),
+    mState(0)
 {
-	/* 
-	 * Layout of the state buffer for 32 tap:
-	 * 
-	 * "present" sample            beginning of 2nd buffer
-	 *                 v                v
-	 *  0              01               2              23              3
-	 *  0              F0               0              F0              F
-	 * [pppppppppppppppInnnnnnnnnnnnnnnnpppppppppppppppInnnnnnnnnnnnnnnn]
-	 *                 ^               ^ head
-	 * 
-	 * p = past samples, convoluted with the (p)ositive side of sinc()
-	 * n = future samples, convoluted with the (n)egative side of sinc()
-	 * r = extra space for implementing the ring buffer
-	 * 
-	 */
+    /*
+     * Layout of the state buffer for 32 tap:
+     *
+     * "present" sample            beginning of 2nd buffer
+     *                 v                v
+     *  0              01               2              23              3
+     *  0              F0               0              F0              F
+     * [pppppppppppppppInnnnnnnnnnnnnnnnpppppppppppppppInnnnnnnnnnnnnnnn]
+     *                 ^               ^ head
+     *
+     * p = past samples, convoluted with the (p)ositive side of sinc()
+     * n = future samples, convoluted with the (n)egative side of sinc()
+     * r = extra space for implementing the ring buffer
+     *
+     */
 
-	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;
+    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;
 }
 
 AudioResamplerSinc::~AudioResamplerSinc()
 {
-	delete [] mState;
+    delete [] mState;
 }
 
 void AudioResamplerSinc::init() {
@@ -168,9 +172,9 @@
 void AudioResamplerSinc::resample(int32_t* out, size_t outFrameCount,
             AudioBufferProvider* provider)
 {
-	mFirCoefs = (mInSampleRate <= mSampleRate) ? mFirCoefsUp : mFirCoefsDown;
+    mFirCoefs = (mInSampleRate <= mSampleRate) ? mFirCoefsUp : mFirCoefsDown;
 
-	// select the appropriate resampler
+    // select the appropriate resampler
     switch (mChannelCount) {
     case 1:
         resample<1>(out, outFrameCount, provider);
@@ -193,43 +197,68 @@
     uint32_t phaseIncrement = mPhaseIncrement;
     size_t outputIndex = 0;
     size_t outputSampleCount = outFrameCount * 2;
+    size_t inFrameCount = (outFrameCount*mInSampleRate)/mSampleRate;
 
     AudioBufferProvider::Buffer& buffer(mBuffer);
     while (outputIndex < outputSampleCount) {
         // buffer is empty, fetch a new one
-        if (buffer.raw == NULL) {
+        while (buffer.frameCount == 0) {
+            buffer.frameCount = inFrameCount;
             provider->getNextBuffer(&buffer);
-            if (buffer.raw == NULL)
-                break;
-    		const uint32_t phaseIndex = phaseFraction >> kNumPhaseBits;
-        	if (phaseIndex) {
-        		read<CHANNELS>(impulse, phaseFraction, buffer.i16, inputIndex);
+            if (buffer.raw == NULL) {
+                goto resample_exit;
             }
+            const uint32_t phaseIndex = phaseFraction >> kNumPhaseBits;
+            if (phaseIndex == 1) {
+                // read one frame
+                read<CHANNELS>(impulse, phaseFraction, buffer.i16, inputIndex);
+            } else if (phaseIndex == 2) {
+                // read 2 frames
+                read<CHANNELS>(impulse, phaseFraction, buffer.i16, inputIndex);
+                inputIndex++;
+                if (inputIndex >= mBuffer.frameCount) {
+                    inputIndex -= mBuffer.frameCount;
+                    provider->releaseBuffer(&buffer);
+                } else {
+                    read<CHANNELS>(impulse, phaseFraction, buffer.i16, inputIndex);
+                }
+           }
         }
         int16_t *in = buffer.i16;
-    	const size_t frameCount = buffer.frameCount;
+        const size_t frameCount = buffer.frameCount;
 
-    	// Always read-in the first samples from the input buffer
-    	int16_t* head = impulse + halfNumCoefs*CHANNELS;
-		head[0] = in[inputIndex*CHANNELS + 0];
-		if (CHANNELS == 2)
-			head[1] = in[inputIndex*CHANNELS + 1];
+        // Always read-in the first samples from the input buffer
+        int16_t* head = impulse + halfNumCoefs*CHANNELS;
+        head[0] = in[inputIndex*CHANNELS + 0];
+        if (CHANNELS == 2)
+            head[1] = in[inputIndex*CHANNELS + 1];
 
         // handle boundary case
-    	int32_t l, r;
+        int32_t l, r;
         while (outputIndex < outputSampleCount) {
-        	filterCoefficient<CHANNELS>(l, r, phaseFraction, impulse);
-    		out[outputIndex++] = mulRL(1, l, vRL);
-    		out[outputIndex++] = mulRL(0, r, vRL);
+            filterCoefficient<CHANNELS>(l, r, phaseFraction, impulse);
+            out[outputIndex++] += 2 * mulRL(1, l, vRL);
+            out[outputIndex++] += 2 * mulRL(0, r, vRL);
 
-        	phaseFraction += phaseIncrement;
-    		const uint32_t phaseIndex = phaseFraction >> kNumPhaseBits;
-        	if (phaseIndex) {
-        		inputIndex += phaseIndex;
-        		if (inputIndex >= frameCount)
-        			break;
-        		read<CHANNELS>(impulse, phaseFraction, in, inputIndex);
-        	}
+            phaseFraction += phaseIncrement;
+            const uint32_t phaseIndex = phaseFraction >> kNumPhaseBits;
+            if (phaseIndex == 1) {
+                inputIndex++;
+                if (inputIndex >= frameCount)
+                    break;  // need a new buffer
+                read<CHANNELS>(impulse, phaseFraction, in, inputIndex);
+            } else if(phaseIndex == 2) {    // maximum value
+                inputIndex++;
+                if (inputIndex >= frameCount)
+                    break;  // 0 frame available, 2 frames needed
+                // read first frame
+                read<CHANNELS>(impulse, phaseFraction, in, inputIndex);
+                inputIndex++;
+                if (inputIndex >= frameCount)
+                    break;  // 0 frame available, 1 frame needed
+                // read second frame
+                read<CHANNELS>(impulse, phaseFraction, in, inputIndex);
+            }
         }
 
         // if done with buffer, save samples
@@ -239,80 +268,89 @@
         }
     }
 
+resample_exit:
     mImpulse = impulse;
     mInputIndex = inputIndex;
     mPhaseFraction = phaseFraction;
 }
 
 template<int CHANNELS>
+/***
+* read()
+*
+* This function reads only one frame from input buffer and writes it in
+* state buffer
+*
+**/
 void AudioResamplerSinc::read(
-		int16_t*& impulse, uint32_t& phaseFraction,
-		int16_t const* in, size_t inputIndex)
+        int16_t*& impulse, uint32_t& phaseFraction,
+        int16_t const* in, size_t inputIndex)
 {
-	// read new samples into the ring buffer
-	while (phaseFraction >> kNumPhaseBits) {
-		const uint32_t phaseIndex = phaseFraction >> kNumPhaseBits;
-		impulse += CHANNELS;
-		phaseFraction -= 1LU<<kNumPhaseBits;
-		if (impulse >= mRingFull) {
-			const size_t stateSize = (halfNumCoefs*2)*CHANNELS;
-			memcpy(mState, mState+stateSize, sizeof(int16_t)*stateSize);
-			impulse -= stateSize;
-		}
-		int16_t* head = impulse + halfNumCoefs*CHANNELS;
-		head[0] = in[inputIndex*CHANNELS + 0];
-		if (CHANNELS == 2)
-			head[1] = in[inputIndex*CHANNELS + 1];
-	}
+    const uint32_t phaseIndex = phaseFraction >> kNumPhaseBits;
+    impulse += CHANNELS;
+    phaseFraction -= 1LU<<kNumPhaseBits;
+    if (impulse >= mRingFull) {
+        const size_t stateSize = (halfNumCoefs*2)*CHANNELS;
+        memcpy(mState, mState+stateSize, sizeof(int16_t)*stateSize);
+        impulse -= stateSize;
+    }
+    int16_t* head = impulse + halfNumCoefs*CHANNELS;
+    head[0] = in[inputIndex*CHANNELS + 0];
+    if (CHANNELS == 2)
+        head[1] = in[inputIndex*CHANNELS + 1];
 }
 
 template<int CHANNELS>
 void AudioResamplerSinc::filterCoefficient(
-		int32_t& l, int32_t& r, uint32_t phase, int16_t const *samples)
-{	
-	// 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;
-	
-	l = 0;
-	r = 0;
-	int32_t const* coefs = mFirCoefs;
-	int16_t const *sP = samples;
-	int16_t const *sN = samples+CHANNELS;
-	for (unsigned int i=0 ; i<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;
+        int32_t& l, int32_t& r, uint32_t phase, int16_t const *samples)
+{
+    // 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;
+    if ((indexP == 0) && (lerpP == 0)) {
+        indexN = cMask >> cShift;
+        lerpN = pMask >> pShift;
+    }
+
+    l = 0;
+    r = 0;
+    int32_t const* coefs = mFirCoefs;
+    int16_t const *sP = samples;
+    int16_t const *sN = samples+CHANNELS;
+    for (unsigned int i=0 ; i<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<<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<<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<<coefsBits;
+        interpolate<CHANNELS>(l, r, coefs+indexP, lerpP, sP);
+        interpolate<CHANNELS>(l, r, coefs+indexN, lerpN, sN);
+        sP -= CHANNELS; sN += CHANNELS; coefs += 1<<coefsBits;
+    }
 }
 
 template<int CHANNELS>
 void AudioResamplerSinc::interpolate(
         int32_t& l, int32_t& r,
-		int32_t const* coefs, int16_t lerp, int16_t const* samples)
+        int32_t const* coefs, int16_t lerp, int16_t const* samples)
 {
-	int32_t c0 = coefs[0];
-	int32_t c1 = coefs[1];
-	int32_t sinc = mulAdd(lerp, (c1-c0)<<1, c0);
-	if (CHANNELS == 2) {
-		uint32_t rl = *reinterpret_cast<uint32_t const*>(samples);
-		l = mulAddRL(1, rl, sinc, l);
-		r = mulAddRL(0, rl, sinc, r);
-	} else {
-		r = l = mulAdd(samples[0], sinc, l);
-	}
+    int32_t c0 = coefs[0];
+    int32_t c1 = coefs[1];
+    int32_t sinc = mulAdd(lerp, (c1-c0)<<1, c0);
+    if (CHANNELS == 2) {
+        uint32_t rl = *reinterpret_cast<uint32_t const*>(samples);
+        l = mulAddRL(1, rl, sinc, l);
+        r = mulAddRL(0, rl, sinc, r);
+    } else {
+        r = l = mulAdd(samples[0], sinc, l);
+    }
 }
 
 // ----------------------------------------------------------------------------
diff --git a/libs/audioflinger/AudioResamplerSinc.h b/libs/audioflinger/AudioResamplerSinc.h
index 89b9577..e6cb90b 100644
--- a/libs/audioflinger/AudioResamplerSinc.h
+++ b/libs/audioflinger/AudioResamplerSinc.h
@@ -24,19 +24,20 @@
 #include "AudioResampler.h"
 
 namespace android {
+
 // ----------------------------------------------------------------------------
 
 class AudioResamplerSinc : public AudioResampler {
 public:
-	AudioResamplerSinc(int bitDepth, int inChannelCount, int32_t sampleRate);
+    AudioResamplerSinc(int bitDepth, int inChannelCount, int32_t sampleRate);
 
-	~AudioResamplerSinc();
-	
+    ~AudioResamplerSinc();
+
     virtual void resample(int32_t* out, size_t outFrameCount,
             AudioBufferProvider* provider);
 private:
     void init();
-    
+
     template<int CHANNELS>
     void resample(int32_t* out, size_t outFrameCount,
             AudioBufferProvider* provider);
@@ -52,12 +53,12 @@
 
     template<int CHANNELS>
     inline void read(int16_t*& impulse, uint32_t& phaseFraction,
-    		int16_t const* in, size_t inputIndex);
+            int16_t const* in, size_t inputIndex);
 
     int16_t *mState;
     int16_t *mImpulse;
     int16_t *mRingFull;
-    
+
     int32_t const * mFirCoefs;
     static const int32_t mFirCoefsDown[];
     static const int32_t mFirCoefsUp[];
@@ -67,15 +68,15 @@
     static const int32_t RESAMPLE_FIR_LERP_INT_BITS  = 4;
 
     // we have 16 coefs samples per zero-crossing
-    static const int coefsBits = RESAMPLE_FIR_LERP_INT_BITS;
-    static const int cShift = kNumPhaseBits - coefsBits;
-    static const uint32_t cMask  = ((1<<coefsBits)-1) << cShift;
+    static const int coefsBits = RESAMPLE_FIR_LERP_INT_BITS;        // 4
+    static const int cShift = kNumPhaseBits - coefsBits;            // 26
+    static const uint32_t cMask  = ((1<<coefsBits)-1) << cShift;    // 0xf<<26 = 3c00 0000
 
     // 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 const int pShift = kNumPhaseBits - coefsBits - pLerpBits;
-    static const uint32_t pMask  = ((1<<pLerpBits)-1) << pShift;
+    static const int pShift = kNumPhaseBits - coefsBits - pLerpBits;    // 11
+    static const uint32_t pMask  = ((1<<pLerpBits)-1) << pShift;    // 0x7fff << 11
 
     // number of zero-crossing on each side
     static const unsigned int halfNumCoefs = RESAMPLE_FIR_NUM_COEF;