Initial Contribution
diff --git a/libs/audioflinger/Android.mk b/libs/audioflinger/Android.mk
new file mode 100644
index 0000000..a9cb3037
--- /dev/null
+++ b/libs/audioflinger/Android.mk
@@ -0,0 +1,53 @@
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+    AudioHardwareGeneric.cpp \
+    AudioHardwareStub.cpp \
+    AudioDumpInterface.cpp \
+    AudioHardwareInterface.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+    libcutils \
+    libutils \
+    libmedia \
+    libhardware
+
+ifeq ($(strip $(BOARD_USES_GENERIC_AUDIO)),true)
+  LOCAL_CFLAGS += -DGENERIC_AUDIO
+endif
+
+LOCAL_MODULE:= libaudiointerface
+
+include $(BUILD_STATIC_LIBRARY)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:=               \
+    AudioFlinger.cpp            \
+    AudioMixer.cpp.arm          \
+    AudioResampler.cpp.arm      \
+    AudioResamplerSinc.cpp.arm  \
+    AudioResamplerCubic.cpp.arm
+
+LOCAL_SHARED_LIBRARIES := \
+    libcutils \
+    libutils \
+    libmedia \
+    libhardware
+
+ifeq ($(strip $(BOARD_USES_GENERIC_AUDIO)),true)
+  LOCAL_STATIC_LIBRARIES += libaudiointerface
+else
+  LOCAL_SHARED_LIBRARIES += libaudio
+endif
+
+LOCAL_MODULE:= libaudioflinger
+
+ifeq ($(TARGET_ARCH),arm)  # not simulator
+  LOCAL_CFLAGS += -DWITH_BLUETOOTH
+  LOCAL_C_INCLUDES += $(call include-path-for, bluez-libs)
+endif
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/libs/audioflinger/AudioBufferProvider.h b/libs/audioflinger/AudioBufferProvider.h
new file mode 100644
index 0000000..1a467c7
--- /dev/null
+++ b/libs/audioflinger/AudioBufferProvider.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 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
+ *
+ *      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 ANDROID_AUDIO_BUFFER_PROVIDER_H
+#define ANDROID_AUDIO_BUFFER_PROVIDER_H
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <utils/Errors.h>
+
+namespace android {
+// ----------------------------------------------------------------------------
+
+class AudioBufferProvider
+{
+public:
+
+    struct Buffer {
+        union {
+            void*       raw;
+            short*      i16;
+            int8_t*     i8;
+        };
+        size_t frameCount;
+    };
+    
+    virtual status_t getNextBuffer(Buffer* buffer) = 0;
+    virtual void releaseBuffer(Buffer* buffer) = 0;
+};
+
+// ----------------------------------------------------------------------------
+}; // namespace android
+
+#endif // ANDROID_AUDIO_BUFFER_PROVIDER_H
diff --git a/libs/audioflinger/AudioDumpInterface.cpp b/libs/audioflinger/AudioDumpInterface.cpp
new file mode 100644
index 0000000..5ff2f18
--- /dev/null
+++ b/libs/audioflinger/AudioDumpInterface.cpp
@@ -0,0 +1,94 @@
+/* //device/servers/AudioFlinger/AudioDumpInterface.cpp
+**
+** 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 
+**
+**     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.
+*/
+
+#define LOG_TAG "AudioFlingerDump"
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <utils/Log.h>
+
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "AudioDumpInterface.h"
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+
+AudioDumpInterface::AudioDumpInterface(AudioHardwareInterface* hw)
+{
+    if(hw == 0) {
+        LOGE("Dump construct hw = 0");
+    }
+    mFinalInterface = hw;
+    mStreamOut = 0;
+}
+
+
+status_t AudioDumpInterface::standby()
+{
+    if(mStreamOut)  mStreamOut->Close();
+    return mFinalInterface->standby();
+}
+
+
+AudioStreamOut* AudioDumpInterface::openOutputStream(
+        int format, int channelCount, uint32_t sampleRate)
+{
+    AudioStreamOut* outFinal = mFinalInterface->openOutputStream(format, channelCount, sampleRate);
+
+    if(outFinal) {
+        mStreamOut =  new AudioStreamOutDump(outFinal);
+        return mStreamOut;
+    } else {
+        LOGE("Dump outFinal=0");
+        return 0;
+    }
+}
+
+// ----------------------------------------------------------------------------
+
+AudioStreamOutDump::AudioStreamOutDump( AudioStreamOut* finalStream)
+{
+    mFinalStream = finalStream;
+    mOutFile = 0;
+}
+
+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) {
+        fwrite(buffer, bytes, 1, mOutFile);
+    }
+    return ret;
+}
+
+void AudioStreamOutDump::Close(void)
+{
+    if(mOutFile) {
+        fclose(mOutFile);
+        mOutFile = 0;
+    }
+}
+
+}; // namespace android
diff --git a/libs/audioflinger/AudioDumpInterface.h b/libs/audioflinger/AudioDumpInterface.h
new file mode 100644
index 0000000..732b97d
--- /dev/null
+++ b/libs/audioflinger/AudioDumpInterface.h
@@ -0,0 +1,101 @@
+/* //device/servers/AudioFlinger/AudioDumpInterface.h
+**
+** 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 
+**
+**     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 ANDROID_AUDIO_DUMP_INTERFACE_H
+#define ANDROID_AUDIO_DUMP_INTERFACE_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <hardware/AudioHardwareInterface.h>
+
+namespace android {
+
+#define FLINGER_DUMP_NAME "/tmp/FlingerOut.pcm" // name of file used for dump
+
+class AudioStreamOutDump : public AudioStreamOut {
+public:
+                        AudioStreamOutDump( AudioStreamOut* FinalStream);
+                        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 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
+};
+
+
+class AudioDumpInterface : public  AudioHardwareInterface
+{
+
+public:
+                        AudioDumpInterface(AudioHardwareInterface* hw);
+    virtual status_t    standby();
+    virtual AudioStreamOut* openOutputStream(
+                                int format=0,
+                                int channelCount=0,
+                                uint32_t sampleRate=0);
+
+    virtual             ~AudioDumpInterface()
+                            {delete mFinalInterface;}
+    virtual status_t    initCheck()
+                            {return mFinalInterface->initCheck();}
+    virtual status_t    setVoiceVolume(float volume)
+                            {return mFinalInterface->setVoiceVolume(volume);}
+    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);}
+    virtual status_t    getMicMute(bool* state)
+                            {return mFinalInterface->getMicMute(state);}
+
+    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 status_t    dump(int fd, const Vector<String16>& args) { return mFinalInterface->dumpState(fd, args); }
+
+protected:
+    virtual status_t    doRouting() {return 0;}
+    
+    AudioHardwareInterface  *mFinalInterface;
+    AudioStreamOutDump      *mStreamOut;
+    
+};
+
+}; // namespace android
+
+#endif // ANDROID_AUDIO_DUMP_INTERFACE_H
diff --git a/libs/audioflinger/AudioFlinger.cpp b/libs/audioflinger/AudioFlinger.cpp
new file mode 100644
index 0000000..fb21629
--- /dev/null
+++ b/libs/audioflinger/AudioFlinger.cpp
@@ -0,0 +1,1450 @@
+/* //device/include/server/AudioFlinger/AudioFlinger.cpp
+**
+** 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
+**
+**     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.
+*/
+
+
+#define LOG_TAG "AudioFlinger"
+//#define LOG_NDEBUG 0
+
+#include <math.h>
+#include <signal.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+
+#include <utils/IServiceManager.h>
+#include <utils/Log.h>
+#include <utils/Parcel.h>
+#include <utils/IPCThreadState.h>
+#include <utils/String16.h>
+#include <utils/threads.h>
+
+#include <media/AudioTrack.h>
+#include <media/AudioRecord.h>
+
+#include <private/media/AudioTrackShared.h>
+
+#include <hardware/AudioHardwareInterface.h>
+
+#include "AudioMixer.h"
+#include "AudioFlinger.h"
+
+namespace android {
+
+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;
+
+// retry counts for buffer fill timeout
+// 50 * ~20msecs = 1 second
+static const int8_t kMaxTrackRetries = 50;
+static const int8_t kMaxTrackStartupRetries = 50;
+
+#define AUDIOFLINGER_SECURITY_ENABLED 1
+
+// ----------------------------------------------------------------------------
+
+static bool recordingAllowed() {
+#ifndef HAVE_ANDROID_OS
+    return true;
+#endif
+#if AUDIOFLINGER_SECURITY_ENABLED
+    if (getpid() == IPCThreadState::self()->getCallingPid()) return true;
+    bool ok = checkCallingPermission(String16("android.permission.RECORD_AUDIO"));
+    if (!ok) LOGE("Request requires android.permission.RECORD_AUDIO");
+    return ok;
+#else
+    if (!checkCallingPermission(String16("android.permission.RECORD_AUDIO")))
+        LOGW("WARNING: Need to add android.permission.RECORD_AUDIO to manifest");
+    return true;
+#endif
+}
+
+static bool settingsAllowed() {
+#ifndef HAVE_ANDROID_OS
+    return true;
+#endif
+#if AUDIOFLINGER_SECURITY_ENABLED
+    if (getpid() == IPCThreadState::self()->getCallingPid()) return true;
+    bool ok = checkCallingPermission(String16("android.permission.MODIFY_AUDIO_SETTINGS"));
+    if (!ok) LOGE("Request requires android.permission.MODIFY_AUDIO_SETTINGS");
+    return ok;
+#else
+    if (!checkCallingPermission(String16("android.permission.MODIFY_AUDIO_SETTINGS")))
+        LOGW("WARNING: Need to add android.permission.MODIFY_AUDIO_SETTINGS to manifest");
+    return true;
+#endif
+}
+
+// ----------------------------------------------------------------------------
+
+AudioFlinger::AudioFlinger()
+    : BnAudioFlinger(), Thread(false),
+        mMasterVolume(0), mMasterMute(true),
+        mAudioMixer(0), mAudioHardware(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)
+{
+    mHardwareStatus = AUDIO_HW_IDLE;
+    mAudioHardware = AudioHardwareInterface::create();
+    mHardwareStatus = AUDIO_HW_INIT;
+    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);
+        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);
+            // FIXME - this should come from settings
+            setMasterVolume(1.0f);
+            setRouting(AudioSystem::MODE_NORMAL, AudioSystem::ROUTE_SPEAKER, AudioSystem::ROUTE_ALL);
+            setRouting(AudioSystem::MODE_RINGTONE, AudioSystem::ROUTE_SPEAKER, AudioSystem::ROUTE_ALL);
+            setRouting(AudioSystem::MODE_IN_CALL, AudioSystem::ROUTE_EARPIECE, AudioSystem::ROUTE_ALL);
+            setMode(AudioSystem::MODE_NORMAL);
+            mMasterMute = false;
+        } else {
+            LOGE("Failed to initialize output stream");
+        }
+    } else {
+        LOGE("Couldn't even initialize the stubbed audio hardware!");
+    }
+}
+
+AudioFlinger::~AudioFlinger()
+{
+    delete mOutput;
+    delete mAudioHardware;
+    delete [] mMixBuffer;
+    delete mAudioMixer;
+    mAudioRecordThread.clear();
+}
+
+status_t AudioFlinger::dumpClients(int fd, const Vector<String16>& args)
+{
+    const size_t SIZE = 256;
+    char buffer[SIZE];
+    String8 result;
+
+    result.append("Clients:\n");
+    for (size_t i = 0; i < mClients.size(); ++i) {
+        wp<Client> wClient = mClients.valueAt(i);
+        if (wClient != 0) {
+            sp<Client> client = wClient.promote();
+            if (client != 0) {
+                snprintf(buffer, SIZE, "  pid: %d\n", client->pid());
+                result.append(buffer);
+            }
+        }
+    }
+    write(fd, result.string(), result.size());
+    return NO_ERROR;
+}
+
+status_t AudioFlinger::dumpTracks(int fd, const Vector<String16>& args)
+{
+    const size_t SIZE = 256;
+    char buffer[SIZE];
+    String8 result;
+
+    result.append("Tracks:\n");
+    result.append("   Name Clien Typ Fmt Chn Buf S M F SRate LeftV RighV Serv User\n");
+    for (size_t i = 0; i < mTracks.size(); ++i) {
+        wp<Track> wTrack = mTracks[i];
+        if (wTrack != 0) {
+            sp<Track> track = wTrack.promote();
+            if (track != 0) {
+                track->dump(buffer, SIZE);
+                result.append(buffer);
+            }
+        }
+    }
+
+    result.append("Active Tracks:\n");
+    result.append("   Name Clien Typ Fmt Chn Buf S M F SRate LeftV RighV Serv User\n");
+    for (size_t i = 0; i < mActiveTracks.size(); ++i) {
+        wp<Track> wTrack = mTracks[i];
+        if (wTrack != 0) {
+            sp<Track> track = wTrack.promote();
+            if (track != 0) {
+                track->dump(buffer, SIZE);
+                result.append(buffer);
+            }
+        }
+    }
+    write(fd, result.string(), result.size());
+    return NO_ERROR;
+}
+
+status_t AudioFlinger::dumpInternals(int fd, const Vector<String16>& args)
+{
+    const size_t SIZE = 256;
+    char buffer[SIZE];
+    String8 result;
+    
+    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);
+    snprintf(buffer, SIZE, "total writes: %d\n", mNumWrites);
+    result.append(buffer);
+    snprintf(buffer, SIZE, "delayed writes: %d\n", mNumDelayedWrites);
+    result.append(buffer);
+    snprintf(buffer, SIZE, "blocked in write: %d\n", mInWrite);
+    result.append(buffer);
+    snprintf(buffer, SIZE, "standby: %d\n", mStandby);
+    result.append(buffer);
+    snprintf(buffer, SIZE, "Hardware status: %d\n", mHardwareStatus);
+    result.append(buffer);
+    write(fd, result.string(), result.size());
+    return NO_ERROR;
+}
+
+status_t AudioFlinger::dumpPermissionDenial(int fd, const Vector<String16>& args)
+{
+    const size_t SIZE = 256;
+    char buffer[SIZE];
+    String8 result;
+    snprintf(buffer, SIZE, "Permission Denial: "
+            "can't dump AudioFlinger from pid=%d, uid=%d\n",
+            IPCThreadState::self()->getCallingPid(),
+            IPCThreadState::self()->getCallingUid());
+    result.append(buffer);
+    write(fd, result.string(), result.size());
+    return NO_ERROR;
+}
+
+status_t AudioFlinger::dump(int fd, const Vector<String16>& args)
+{
+    if (checkCallingPermission(String16("android.permission.DUMP")) == false) {
+        dumpPermissionDenial(fd, args);
+    } else {
+        AutoMutex lock(&mLock);
+
+        dumpClients(fd, args);
+        dumpTracks(fd, args);
+        dumpInternals(fd, args);
+        if (mAudioHardware) {
+            mAudioHardware->dumpState(fd, args);
+        }
+    }
+    return NO_ERROR;
+}
+
+// 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;
+    nsecs_t standbyTime = systemTime();
+
+    do {
+        enabledTracks = 0;
+        { // scope for the lock
+            Mutex::Autolock _l(mLock);
+            const SortedVector< wp<Track> >& activeTracks = mActiveTracks;
+
+            // put audio hardware into standby after short delay
+            if UNLIKELY(!activeTracks.size() && systemTime() > standbyTime) {
+                // wait until we have something to do...
+                LOGV("Audio hardware entering standby\n");
+                mHardwareStatus = AUDIO_HW_STANDBY;
+                if (!mStandby) {
+                    mAudioHardware->standby();
+                    mStandby = true;
+                }
+                mHardwareStatus = AUDIO_HW_IDLE;
+                // we're about to wait, flush the binder command buffer
+                IPCThreadState::self()->flushCommands();
+                mWaitWorkCV.wait(mLock);
+                LOGV("Audio hardware exiting standby\n");
+                standbyTime = systemTime() + kStandbyTimeInNsecs;
+                continue;
+            }
+
+            // find out which tracks need to be processed
+            size_t count = activeTracks.size();
+            for (size_t i=0 ; i<count ; i++) {
+                sp<Track> t = activeTracks[i].promote();
+                if (t == 0) continue;
+
+                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()) &&
+                        !track->isPaused())
+                {
+                    //LOGD("u=%08x, s=%08x [OK]", u, s);
+
+                    // compute volume for this track
+                    int16_t left, right;
+                    if (track->isMuted() || mMasterMute || track->isPausing()) {
+                        left = right = 0;
+                        if (track->isPausing()) {
+                            LOGV("paused(%d)", track->name());
+                            track->setPaused();
+                        }
+                    } else {
+                        float typeVolume = mStreamTypes[track->type()].volume;
+                        float v = mMasterVolume * typeVolume;
+                        float v_clamped = v * cblk->volume[0];
+                        if (v_clamped > MAX_GAIN) v_clamped = MAX_GAIN;
+                        left = int16_t(v_clamped);
+                        v_clamped = v * cblk->volume[1];
+                        if (v_clamped > MAX_GAIN) v_clamped = MAX_GAIN;
+                        right = int16_t(v_clamped);
+                    }
+
+                    // XXX: these things DON'T need to be done each time
+                    AudioMixer& mixer(audioMixer());
+                    mixer.setBufferProvider(track);
+                    mixer.enable(AudioMixer::MIXING);
+
+                    int param;
+                    if ( track->mFillingUpStatus == Track::FS_FILLED) {
+                        // no ramp for the first volume setting
+                        track->mFillingUpStatus = Track::FS_ACTIVE;
+                        if (track->mState == TrackBase::RESUMING) {
+                            track->mState = TrackBase::ACTIVE;
+                            param = AudioMixer::RAMP_VOLUME;
+                        } else {
+                            param = AudioMixer::VOLUME;
+                        }
+                    } else {
+                        param = AudioMixer::RAMP_VOLUME;
+                    }
+                    mixer.setParameter(param, AudioMixer::VOLUME0, left);
+                    mixer.setParameter(param, AudioMixer::VOLUME1, right);
+                    mixer.setParameter(
+                        AudioMixer::TRACK,
+                        AudioMixer::FORMAT, track->format());
+                    mixer.setParameter(
+                        AudioMixer::TRACK,
+                        AudioMixer::CHANNEL_COUNT, track->channelCount());
+                    mixer.setParameter(
+                        AudioMixer::RESAMPLE,
+                        AudioMixer::SAMPLE_RATE,
+                        int(cblk->sampleRate));
+
+                    // reset retry count
+                    track->mRetryCount = kMaxTrackRetries;
+                    enabledTracks++;
+                } else {
+                    //LOGD("u=%08x, s=%08x [NOT READY]", u, s);
+                    if (track->isStopped()) {
+                        track->mFillingUpStatus = Track::FS_FILLING;
+                        track->mFlags = 0;    
+                    }
+                    if (track->isTerminated() || track->isStopped() || track->isPaused()) {
+                        // We have consumed all the buffers of this track.
+                        // Remove it from the list of active tracks.
+                        LOGV("remove(%d) from active list", track->name());
+                        tracksToRemove.add(track);
+                    } else {
+                        // No buffers for this track. Give it a few chances to
+                        // fill a buffer, then remove it from active list.
+                        if (--(track->mRetryCount) <= 0) {
+                            LOGV("BUFFER TIMEOUT: remove(%d) from active list", track->name());
+                            tracksToRemove.add(track);
+                        }
+                    }
+                    // LOGV("disable(%d)", track->name());
+                    audioMixer().disable(AudioMixer::MIXING);
+                }
+            }
+
+            // remove all the tracks that need to be...
+            count = tracksToRemove.size();
+            if (UNLIKELY(count)) {
+                for (size_t i=0 ; i<count ; i++) {
+                    const sp<Track>& track = tracksToRemove[i];
+                    mActiveTracks.remove(track);
+                    if (track->isTerminated()) {
+                        mTracks.remove(track);
+                        audioMixer().deleteTrackName(track->mName);
+                    }
+                }
+            }
+        }
+
+        if (LIKELY(enabledTracks)) {
+            // mix buffers...
+            audioMixer().process(curBuf);
+
+            // output audio to hardware
+            mLastWriteTime = systemTime();
+            mInWrite = true;
+            mOutput->write(curBuf, mixBufferSize);
+            mNumWrites++;
+            mInWrite = false;
+            mStandby = false;
+            nsecs_t temp = systemTime();
+            standbyTime = temp + kStandbyTimeInNsecs;
+            nsecs_t delta = temp - mLastWriteTime;
+            if (delta > maxPeriod) {
+                LOGW("write blocked for %llu msecs", ns2ms(delta));
+                mNumDelayedWrites++;
+            }
+            sleepTime = kBufferRecoveryInUsecs;
+        } else {
+            // There was nothing to mix this round, which means all
+            // active tracks were late. Sleep a little bit to give
+            // them another chance. If we're too late, the audio
+            // hardware will zero-fill for us.
+            LOGV("no buffers - usleep(%lu)", sleepTime);
+            usleep(sleepTime);
+            if (sleepTime < kMaxBufferRecoveryInUsecs) {
+                sleepTime += kBufferRecoveryInUsecs;
+            }
+        }
+
+        // finally let go of all our tracks, without the lock held
+        // since we can't guarantee the destructors won't acquire that
+        // same lock.
+        tracksToRemove.clear();
+    } while (true);
+
+    return false;
+}
+
+status_t AudioFlinger::readyToRun()
+{
+    if (mSampleRate == 0) {
+        LOGE("No working audio driver found.");
+        return NO_INIT;
+    }
+    LOGI("AudioFlinger's main thread ready to run.");
+    return NO_ERROR;
+}
+
+void AudioFlinger::onFirstRef()
+{
+    run("AudioFlinger", ANDROID_PRIORITY_URGENT_AUDIO);
+}
+
+// IAudioFlinger interface
+sp<IAudioTrack> AudioFlinger::createTrack(
+        pid_t pid,
+        int streamType,
+        uint32_t sampleRate,
+        int format,
+        int channelCount,
+        int bufferCount,
+        uint32_t flags)
+{
+    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);
+
+    if (wclient != NULL) {
+        client = wclient.promote();
+    } else {
+        client = new Client(this, pid);
+        mClients.add(pid, client);
+    }
+
+    // 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);
+    return trackHandle;
+}
+
+uint32_t AudioFlinger::sampleRate() const
+{
+    return mSampleRate;
+}
+
+int AudioFlinger::channelCount() const
+{
+    return mChannelCount;
+}
+
+int AudioFlinger::format() const
+{
+    return mFormat;
+}
+
+size_t AudioFlinger::frameCount() const
+{
+    return mFrameCount;
+}
+
+status_t AudioFlinger::setMasterVolume(float value)
+{
+    // check calling permissions
+    if (!settingsAllowed()) {
+        return PERMISSION_DENIED;
+    }
+
+    // when hw supports master volume, don't scale in sw mixer
+    AutoMutex lock(mHardwareLock);
+    mHardwareStatus = AUDIO_HW_SET_MASTER_VOLUME;
+    if (mAudioHardware->setMasterVolume(value) == NO_ERROR) {
+        mMasterVolume = 1.0f;
+    }
+    else {
+        mMasterVolume = value;
+    }
+    mHardwareStatus = AUDIO_HW_IDLE;
+    return NO_ERROR;
+}
+
+status_t AudioFlinger::setRouting(int mode, uint32_t routes, uint32_t mask)
+{
+    // check calling permissions
+    if (!settingsAllowed()) {
+        return PERMISSION_DENIED;
+    }
+    if ((mode < AudioSystem::MODE_CURRENT) || (mode >= AudioSystem::NUM_MODES)) {
+        LOGW("Illegal value: setRouting(%d, %u, %u)", mode, routes, mask);
+        return BAD_VALUE;
+    }
+
+    AutoMutex lock(mHardwareLock);
+    mHardwareStatus = AUDIO_HW_GET_ROUTING;
+    uint32_t r;
+    uint32_t err = mAudioHardware->getRouting(mode, &r);
+    if (err == NO_ERROR) {
+        r = (r & ~mask) | (routes & mask);
+        mHardwareStatus = AUDIO_HW_SET_ROUTING;
+        err = mAudioHardware->setRouting(mode, r);
+    }
+    mHardwareStatus = AUDIO_HW_IDLE;
+    return err;
+}
+
+uint32_t AudioFlinger::getRouting(int mode) const
+{
+    uint32_t routes = 0;
+    if ((mode >= AudioSystem::MODE_CURRENT) && (mode < AudioSystem::NUM_MODES)) {
+        mHardwareStatus = AUDIO_HW_GET_ROUTING;
+        mAudioHardware->getRouting(mode, &routes);
+        mHardwareStatus = AUDIO_HW_IDLE;
+    } else {
+        LOGW("Illegal value: getRouting(%d)", mode);
+    }
+    return routes;
+}
+
+status_t AudioFlinger::setMode(int mode)
+{
+    // check calling permissions
+    if (!settingsAllowed()) {
+        return PERMISSION_DENIED;
+    }
+    if ((mode < 0) || (mode >= AudioSystem::NUM_MODES)) {
+        LOGW("Illegal value: setMode(%d)", mode);
+        return BAD_VALUE;
+    }
+
+    AutoMutex lock(mHardwareLock);
+    mHardwareStatus = AUDIO_HW_SET_MODE;
+    status_t ret = mAudioHardware->setMode(mode);
+    mHardwareStatus = AUDIO_HW_IDLE;
+    return ret;
+}
+
+int AudioFlinger::getMode() const
+{
+    int mode = AudioSystem::MODE_INVALID;
+    mHardwareStatus = AUDIO_HW_SET_MODE;
+    mAudioHardware->getMode(&mode);
+    mHardwareStatus = AUDIO_HW_IDLE;
+    return mode;
+}
+
+status_t AudioFlinger::setMicMute(bool state)
+{
+    // check calling permissions
+    if (!settingsAllowed()) {
+        return PERMISSION_DENIED;
+    }
+
+    AutoMutex lock(mHardwareLock);
+    mHardwareStatus = AUDIO_HW_SET_MIC_MUTE;
+    status_t ret = mAudioHardware->setMicMute(state);
+    mHardwareStatus = AUDIO_HW_IDLE;
+    return ret;
+}
+
+bool AudioFlinger::getMicMute() const
+{
+    bool state = AudioSystem::MODE_INVALID;
+    mHardwareStatus = AUDIO_HW_GET_MIC_MUTE;
+    mAudioHardware->getMicMute(&state);
+    mHardwareStatus = AUDIO_HW_IDLE;
+    return state;
+}
+
+status_t AudioFlinger::setMasterMute(bool muted)
+{
+    // check calling permissions
+    if (!settingsAllowed()) {
+        return PERMISSION_DENIED;
+    }
+
+    mMasterMute = muted;
+    return NO_ERROR;
+}
+
+float AudioFlinger::masterVolume() const
+{
+    return mMasterVolume;
+}
+
+bool AudioFlinger::masterMute() const
+{
+    return mMasterMute;
+}
+
+status_t AudioFlinger::setStreamVolume(int stream, float value)
+{
+    // check calling permissions
+    if (!settingsAllowed()) {
+        return PERMISSION_DENIED;
+    }
+
+    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) {
+        AutoMutex lock(mHardwareLock);
+        mHardwareStatus = AUDIO_SET_VOICE_VOLUME;
+        ret = mAudioHardware->setVoiceVolume(value);
+        mHardwareStatus = AUDIO_HW_IDLE;
+    }
+    return ret;
+}
+
+status_t AudioFlinger::setStreamMute(int stream, bool muted)
+{
+    // check calling permissions
+    if (!settingsAllowed()) {
+        return PERMISSION_DENIED;
+    }
+
+    if (uint32_t(stream) >= AudioTrack::NUM_STREAM_TYPES) {
+        return BAD_VALUE;
+    }
+    mStreamTypes[stream].mute = muted;
+    return NO_ERROR;
+}
+
+float AudioFlinger::streamVolume(int stream) const
+{
+    if (uint32_t(stream) >= AudioTrack::NUM_STREAM_TYPES) {
+        return 0.0f;
+    }
+    return mStreamTypes[stream].volume;
+}
+
+bool AudioFlinger::streamMute(int stream) const
+{
+    if (uint32_t(stream) >= AudioTrack::NUM_STREAM_TYPES) {
+        return true;
+    }
+    return mStreamTypes[stream].mute;
+}
+
+bool AudioFlinger::isMusicActive() const
+{
+    size_t count = mActiveTracks.size();
+    for (size_t i = 0 ; i < count ; ++i) {
+        sp<Track> t = mActiveTracks[i].promote();
+        if (t == 0) continue;
+        Track* const track = t.get();
+        if (t->mStreamType == AudioTrack::MUSIC)
+            return true;
+    }
+    return false;
+}
+
+status_t AudioFlinger::setParameter(const char* key, const char* value)
+{
+    status_t result;
+    AutoMutex lock(mHardwareLock);
+    mHardwareStatus = AUDIO_SET_PARAMETER;
+    result = mAudioHardware->setParameter(key, value);
+    mHardwareStatus = AUDIO_HW_IDLE;
+    return result;
+}
+
+void AudioFlinger::removeClient(pid_t pid)
+{
+    Mutex::Autolock _l(mLock);
+    mClients.removeItem(pid);
+}
+
+status_t AudioFlinger::addTrack(const sp<Track>& track)
+{
+    Mutex::Autolock _l(mLock);
+
+    // here the track could be either new, or restarted
+    // in both cases "unstop" the track
+    if (track->isPaused()) {
+        track->mState = TrackBase::RESUMING;
+        LOGV("PAUSED => RESUMING (%d)", track->name());
+    } else {
+        track->mState = TrackBase::ACTIVE;
+        LOGV("? => ACTIVE (%d)", track->name());
+    }
+    // set retry count for buffer fill
+    track->mRetryCount = kMaxTrackStartupRetries;
+    LOGV("mWaitWorkCV.broadcast");
+    mWaitWorkCV.broadcast();
+
+    if (mActiveTracks.indexOf(track) < 0) {
+        // the track is newly added, make sure it fills up all its
+        // buffers before playing. This is to ensure the client will
+        // effectively get the latency it requested.
+        track->mFillingUpStatus = Track::FS_FILLING;
+        mActiveTracks.add(track);
+        return NO_ERROR;
+    }
+    return ALREADY_EXISTS;
+}
+
+void AudioFlinger::removeTrack(wp<Track> track, int name)
+{
+    Mutex::Autolock _l(mLock);
+    sp<Track> t = track.promote();
+    if (t!=NULL && (t->mState <= TrackBase::STOPPED)) {
+        remove_track_l(track, name);
+    }
+}
+
+void AudioFlinger::remove_track_l(wp<Track> track, int name)
+{
+    sp<Track> t = track.promote();
+    if (t!=NULL) {
+        t->reset();
+    }
+    audioMixer().deleteTrackName(name);
+    mActiveTracks.remove(track);
+    mWaitWorkCV.broadcast();
+}
+
+void AudioFlinger::destroyTrack(const sp<Track>& track)
+{
+    // NOTE: We're acquiring a strong reference on the track before
+    // acquiring the lock, this is to make sure removing it from
+    // mTracks won't cause the destructor to be called while the lock is
+    // held (note that technically, 'track' could be a reference to an item
+    // in mTracks, which is why we need to do this).
+    sp<Track> keep(track);
+    Mutex::Autolock _l(mLock);
+    track->mState = TrackBase::TERMINATED;
+    if (mActiveTracks.indexOf(track) < 0) {
+        LOGV("remove track (%d) and delete from mixer", track->name());
+        mTracks.remove(track);
+        audioMixer().deleteTrackName(keep->name());
+    }
+}
+
+// ----------------------------------------------------------------------------
+
+AudioFlinger::Client::Client(const sp<AudioFlinger>& audioFlinger, pid_t pid)
+    :   RefBase(),
+        mAudioFlinger(audioFlinger),
+        mMemoryDealer(new MemoryDealer(1024*1024)),
+        mPid(pid)
+{
+    // 1 MB of address space is good for 32 tracks, 8 buffers each, 4 KB/buffer
+}
+
+AudioFlinger::Client::~Client()
+{
+    mAudioFlinger->removeClient(mPid);
+}
+
+const sp<MemoryDealer>& AudioFlinger::Client::heap() const
+{
+    return mMemoryDealer;
+}
+
+// ----------------------------------------------------------------------------
+
+AudioFlinger::TrackBase::TrackBase(
+            const sp<AudioFlinger>& audioFlinger,
+            const sp<Client>& client,
+            int streamType,
+            uint32_t sampleRate,
+            int format,
+            int channelCount,
+            int bufferCount,
+            int bufferSize)
+    :   RefBase(),
+        mAudioFlinger(audioFlinger),
+        mClient(client),
+        mStreamType(streamType),
+        mFormat(format),
+        mChannelCount(channelCount),
+        mBufferCount(bufferCount),
+        mFlags(0),
+        mBufferSize(bufferSize),
+        mState(IDLE),
+        mClientTid(-1)
+{
+    mName = audioFlinger->audioMixer().getTrackName();
+    if (mName < 0) {
+        LOGE("no more track names availlable");
+        return;
+    }
+
+    // LOGD("Creating track with %d buffers @ %d bytes", bufferCount, bufferSize);
+    size_t size = sizeof(audio_track_cblk_t) + bufferCount * 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->sampleRate = sampleRate;
+            mBuffers = (char*)mCblk + sizeof(audio_track_cblk_t);
+            memset(mBuffers, 0, bufferCount * bufferSize);
+        }
+    } else {
+        LOGE("not enough memory for AudioTrack size=%u", size);
+        client->heap()->dump("AudioTrack");
+        return;
+    }
+}
+
+AudioFlinger::TrackBase::~TrackBase()
+{
+    mCblk->~audio_track_cblk_t();   // destroy our shared-structure.
+    mCblkMemory.clear();            // and free the shared memory
+    mClient.clear();
+}
+
+void AudioFlinger::TrackBase::releaseBuffer(AudioBufferProvider::Buffer* buffer)
+{
+    buffer->raw = 0;
+    buffer->frameCount = 0;
+    step();
+}
+
+bool AudioFlinger::TrackBase::step() {
+    bool result;
+    audio_track_cblk_t* cblk = this->cblk();
+    
+    result = cblk->stepServer(bufferCount()); 
+    if (!result) {
+        LOGV("stepServer failed acquiring cblk mutex");
+        mFlags |= STEPSERVER_FAILED;
+    }
+    return result;
+}
+
+void AudioFlinger::TrackBase::reset() {
+    audio_track_cblk_t* cblk = this->cblk();
+
+    cblk->user = 0;
+    cblk->server = 0;
+    mFlags = 0;    
+}
+
+sp<IMemory> AudioFlinger::TrackBase::getCblk() const
+{
+    return mCblkMemory;
+}
+
+int AudioFlinger::TrackBase::sampleRate() const {
+    return mCblk->sampleRate;
+}
+
+// ----------------------------------------------------------------------------
+
+AudioFlinger::Track::Track(
+            const sp<AudioFlinger>& audioFlinger,
+            const sp<Client>& client,
+            int streamType,
+            uint32_t sampleRate,
+            int format,
+            int channelCount,
+            int bufferCount,
+            int bufferSize)
+    :   TrackBase(audioFlinger, client, streamType, sampleRate, format, channelCount, bufferCount, bufferSize)
+{
+    mVolume[0] = 1.0f;
+    mVolume[1] = 1.0f;
+    mMute = false;
+}
+
+AudioFlinger::Track::~Track()
+{
+    wp<Track> weak(this); // never create a strong ref from the dtor
+    mState = TERMINATED;
+    mAudioFlinger->removeTrack(weak, mName);
+}
+
+void AudioFlinger::Track::destroy()
+{
+    mAudioFlinger->destroyTrack(this);
+}
+
+void AudioFlinger::Track::dump(char* buffer, size_t size)
+{
+    snprintf(buffer, size, "  %5d %5d %3u %3u %3u %3u %1d %1d %1d %5u %5u %5u %04x %04x\n",
+            mName - AudioMixer::TRACK0,
+            mClient->pid(),
+            mStreamType,
+            mFormat,
+            mChannelCount,
+            mBufferCount,
+            mState,
+            mMute,
+            mFillingUpStatus,
+            mCblk->sampleRate,
+            mCblk->volume[0],
+            mCblk->volume[1],
+            mCblk->server,
+            mCblk->user);
+}
+
+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 
+     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;
+     }
+getNextBuffer_exit:
+     buffer->raw = 0;
+     buffer->frameCount = 0;
+     return NOT_ENOUGH_DATA;
+}
+
+bool AudioFlinger::Track::isReady(uint32_t u, int32_t s) 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) {
+        mFillingUpStatus = FS_FILLED;
+        return true;
+    }
+    return false;
+}
+
+status_t AudioFlinger::Track::start()
+{
+    LOGV("start(%d)", mName);
+    mAudioFlinger->addTrack(this);
+    return NO_ERROR;
+}
+
+void AudioFlinger::Track::stop()
+{
+    LOGV("stop(%d)", mName);
+    Mutex::Autolock _l(mAudioFlinger->mLock);
+    if (mState > STOPPED) {
+        mState = STOPPED;
+        // If the track is not active (PAUSED and buffers full), flush buffers  
+        if (mAudioFlinger->mActiveTracks.indexOf(this) < 0) {
+            reset();
+        }
+        LOGV("(> STOPPED) => STOPPED (%d)", mName);
+    }
+}
+
+void AudioFlinger::Track::pause()
+{
+    LOGV("pause(%d)", mName);
+    Mutex::Autolock _l(mAudioFlinger->mLock);
+    if (mState == ACTIVE || mState == RESUMING) {
+        mState = PAUSING;
+        LOGV("ACTIVE/RESUMING => PAUSING (%d)", mName);
+    }
+}
+
+void AudioFlinger::Track::flush()
+{
+    LOGV("flush(%d)", mName);
+    Mutex::Autolock _l(mAudioFlinger->mLock);
+    if (mState != STOPPED && mState != PAUSED && mState != PAUSING) {
+        return;
+    }
+    // No point remaining in PAUSED state after a flush => go to
+    // STOPPED state
+    mState = STOPPED;
+
+    // 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! 
+    reset();
+}
+
+void AudioFlinger::Track::reset()
+{
+    TrackBase::reset();
+    mFillingUpStatus = FS_FILLING;
+}
+
+void AudioFlinger::Track::mute(bool muted)
+{
+    mMute = muted;
+}
+
+void AudioFlinger::Track::setVolume(float left, float right)
+{
+    mVolume[0] = left;
+    mVolume[1] = right;
+}
+
+// ----------------------------------------------------------------------------
+
+AudioFlinger::TrackHandle::TrackHandle(const sp<AudioFlinger::Track>& track)
+    : BnAudioTrack(),
+      mTrack(track)
+{
+}
+
+AudioFlinger::TrackHandle::~TrackHandle() {
+    // just stop the track on deletion, associated resources
+    // will be freed from the main thread once all pending buffers have
+    // been played. Unless it's not in the active track list, in which
+    // case we free everything now...
+    mTrack->destroy();
+}
+
+status_t AudioFlinger::TrackHandle::start() {
+    return mTrack->start();
+}
+
+void AudioFlinger::TrackHandle::stop() {
+    mTrack->stop();
+}
+
+void AudioFlinger::TrackHandle::flush() {
+    mTrack->flush();
+}
+
+void AudioFlinger::TrackHandle::mute(bool e) {
+    mTrack->mute(e);
+}
+
+void AudioFlinger::TrackHandle::pause() {
+    mTrack->pause();
+}
+
+void AudioFlinger::TrackHandle::setVolume(float left, float right) {
+    mTrack->setVolume(left, right);
+}
+
+sp<IMemory> AudioFlinger::TrackHandle::getCblk() const {
+    return mTrack->getCblk();
+}
+
+status_t AudioFlinger::TrackHandle::onTransact(
+    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+    return BnAudioTrack::onTransact(code, data, reply, flags);
+}
+
+// ----------------------------------------------------------------------------
+
+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)
+{
+    sp<AudioRecordThread> thread;
+    sp<RecordTrack> recordTrack;
+    sp<RecordHandle> recordHandle;
+    sp<Client> client;
+    wp<Client> wclient;
+    AudioStreamIn* input = 0;
+
+    // check calling permissions
+    if (!recordingAllowed()) {
+        goto Exit;
+    }
+
+    if (uint32_t(streamType) >= AudioRecord::NUM_STREAM_TYPES) {
+        LOGE("invalid stream type");
+        goto Exit;
+    }
+
+    if (sampleRate > MAX_SAMPLE_RATE) {
+        LOGE("Sample rate out of range");
+        goto Exit;
+    }
+
+    if (mSampleRate == 0) {
+        LOGE("Audio driver not initialized");
+        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;
+    }
+    // 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();
+        goto Exit;
+    }
+
+    // add client to list
+    {
+        Mutex::Autolock _l(mLock);
+        wclient = mClients.valueFor(pid);
+        if (wclient != NULL) {
+            client = wclient.promote();
+        } else {
+            client = new Client(this, pid);
+            mClients.add(pid, client);
+        }
+    }
+
+    // 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);
+
+    // return to handle to client
+    recordHandle = new RecordHandle(recordTrack);
+
+Exit:
+    return recordHandle;
+}
+
+status_t AudioFlinger::startRecord() {
+    sp<AudioRecordThread> t = audioRecordThread();
+    if (t == 0) return NO_INIT;
+    return t->start();
+}
+
+void AudioFlinger::stopRecord() {
+    sp<AudioRecordThread> t = audioRecordThread();
+    if (t != 0) t->stop();
+}
+
+void AudioFlinger::exitRecord()
+{
+    sp<AudioRecordThread> t = audioRecordThread();
+    if (t != 0) t->exit();
+}
+
+// ----------------------------------------------------------------------------
+
+AudioFlinger::RecordTrack::RecordTrack(
+            const sp<AudioFlinger>& audioFlinger,
+            const sp<Client>& client,
+            int streamType,
+            uint32_t sampleRate,
+            int format,
+            int channelCount,
+            int bufferCount,
+            int bufferSize)
+    :   TrackBase(audioFlinger, client, streamType, sampleRate, format,
+            channelCount, bufferCount, bufferSize),
+            mOverflow(false)
+{
+}
+
+AudioFlinger::RecordTrack::~RecordTrack()
+{
+    mAudioFlinger->audioMixer().deleteTrackName(mName);
+    mAudioFlinger->exitRecord();
+}
+
+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;
+     }
+
+     if (LIKELY(s_seq == u_seq || s_buf != u_buf)) {
+         buffer->raw = getBuffer(s_buf);
+         buffer->frameCount = mAudioFlinger->frameCount();
+         return NO_ERROR;
+     }
+
+getNextBuffer_exit:     
+     buffer->raw = 0;
+     buffer->frameCount = 0;
+     return NOT_ENOUGH_DATA;
+}
+
+status_t AudioFlinger::RecordTrack::start()
+{
+    return mAudioFlinger->startRecord();
+}
+
+void AudioFlinger::RecordTrack::stop()
+{
+    mAudioFlinger->stopRecord();
+}
+
+// ----------------------------------------------------------------------------
+
+AudioFlinger::RecordHandle::RecordHandle(const sp<AudioFlinger::RecordTrack>& recordTrack)
+    : BnAudioRecord(),
+    mRecordTrack(recordTrack)
+{
+}
+
+AudioFlinger::RecordHandle::~RecordHandle() {}
+
+status_t AudioFlinger::RecordHandle::start() {
+    LOGV("RecordHandle::start()");
+    return mRecordTrack->start();
+}
+
+void AudioFlinger::RecordHandle::stop() {
+    LOGV("RecordHandle::stop()");
+    mRecordTrack->stop();
+}
+
+sp<IMemory> AudioFlinger::RecordHandle::getCblk() const {
+    return mRecordTrack->getCblk();
+}
+
+status_t AudioFlinger::RecordHandle::onTransact(
+    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+    return BnAudioRecord::onTransact(code, data, reply, flags);
+}
+
+// ----------------------------------------------------------------------------
+
+AudioFlinger::AudioRecordThread::AudioRecordThread(const sp<AudioFlinger>& audioFlinger) :
+    mAudioFlinger(audioFlinger),
+    mRecordTrack(0),
+    mInput(0),
+    mActive(false)
+{
+}
+
+AudioFlinger::AudioRecordThread::~AudioRecordThread()
+{
+}
+
+bool AudioFlinger::AudioRecordThread::threadLoop()
+{
+    LOGV("AudioRecordThread: start record loop");
+
+    // start recording
+    while (!exitPending()) {
+        if (!mActive) {
+            mLock.lock();
+            if (!mActive && !exitPending()) {
+                LOGV("AudioRecordThread: loop stopping");
+                mWaitWorkCV.wait(mLock);
+                LOGV("AudioRecordThread: loop starting");
+            }
+            mLock.unlock();
+        } else {
+            // promote strong ref so track isn't deleted while we access it
+            sp<RecordTrack> t = mRecordTrack.promote();
+
+            // 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) {
+                    LOGE("Error reading audio input");
+                    sleep(1);
+                }
+                t->releaseBuffer(&mBuffer);
+            }
+
+            // client isn't retrieving buffers fast enough
+            else {
+                if (!t->setOverflow())
+                    LOGW("AudioRecordThread: buffer overflow");
+            }
+        }
+    };
+
+    // close hardware
+    close();
+
+    // delete this object - no more data references after this call
+    mAudioFlinger->endRecord();
+    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()
+{
+    LOGV("AudioRecordThread::start");
+    AutoMutex lock(&mLock);
+    if (mActive) return -EBUSY;
+
+    sp<RecordTrack> t = mRecordTrack.promote();
+    if (t == 0) return UNKNOWN_ERROR;
+
+    // signal thread to start
+    LOGV("Signal record thread");
+    mActive = true;
+    mWaitWorkCV.signal();
+    return NO_ERROR;
+}
+
+void AudioFlinger::AudioRecordThread::stop() {
+    LOGV("AudioRecordThread::stop");
+    AutoMutex lock(&mLock);
+    if (mActive) {
+        mActive = false;
+        mWaitWorkCV.signal();
+    }
+}
+
+void AudioFlinger::AudioRecordThread::exit()
+{
+    LOGV("AudioRecordThread::exit");
+    AutoMutex lock(&mLock);
+    requestExit();
+    mWaitWorkCV.signal();
+}
+
+
+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)
+{
+    return BnAudioFlinger::onTransact(code, data, reply, flags);
+}
+
+// ----------------------------------------------------------------------------
+void AudioFlinger::instantiate() {
+    defaultServiceManager()->addService(
+            String16("media.audio_flinger"), new AudioFlinger());
+}
+
+}; // namespace android
diff --git a/libs/audioflinger/AudioFlinger.h b/libs/audioflinger/AudioFlinger.h
new file mode 100644
index 0000000..8c02617
--- /dev/null
+++ b/libs/audioflinger/AudioFlinger.h
@@ -0,0 +1,490 @@
+/* //device/include/server/AudioFlinger/AudioFlinger.h
+**
+** 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
+**
+**     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 ANDROID_AUDIO_FLINGER_H
+#define ANDROID_AUDIO_FLINGER_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <media/IAudioFlinger.h>
+#include <media/IAudioTrack.h>
+#include <media/IAudioRecord.h>
+#include <media/AudioTrack.h>
+
+#include <utils/Atomic.h>
+#include <utils/Errors.h>
+#include <utils/threads.h>
+#include <utils/MemoryDealer.h>
+#include <utils/KeyedVector.h>
+#include <utils/SortedVector.h>
+
+#include <hardware/AudioHardwareInterface.h>
+
+#include "AudioBufferProvider.h"
+
+namespace android {
+
+class audio_track_cblk_t;
+class AudioMixer;
+class AudioBuffer;
+
+// ----------------------------------------------------------------------------
+
+#define LIKELY( exp )       (__builtin_expect( (exp) != 0, true  ))
+#define UNLIKELY( exp )     (__builtin_expect( (exp) != 0, false ))
+
+// ----------------------------------------------------------------------------
+
+class AudioFlinger : public BnAudioFlinger, protected Thread
+{
+public:
+    static void instantiate();
+
+    virtual     status_t    dump(int fd, const Vector<String16>& args);
+
+    // Thread virtuals
+    virtual     bool        threadLoop();
+    virtual     status_t    readyToRun();
+    virtual     void        onFirstRef();
+
+    // IAudioFlinger interface
+    virtual sp<IAudioTrack> createTrack(
+                                pid_t pid,
+                                int streamType,
+                                uint32_t sampleRate,
+                                int format,
+                                int channelCount,
+                                int bufferCount,
+                                uint32_t flags);
+
+    virtual     uint32_t    sampleRate() const;
+    virtual     int         channelCount() const;
+    virtual     int         format() const;
+    virtual     size_t      frameCount() const;
+
+    virtual     status_t    setMasterVolume(float value);
+    virtual     status_t    setMasterMute(bool muted);
+
+    virtual     float       masterVolume() const;
+    virtual     bool        masterMute() const;
+
+    virtual     status_t    setStreamVolume(int stream, float value);
+    virtual     status_t    setStreamMute(int stream, bool muted);
+
+    virtual     float       streamVolume(int stream) const;
+    virtual     bool        streamMute(int stream) const;
+
+    virtual     status_t    setRouting(int mode, uint32_t routes, uint32_t mask);
+    virtual     uint32_t    getRouting(int mode) const;
+
+    virtual     status_t    setMode(int mode);
+    virtual     int         getMode() const;
+
+    virtual     status_t    setMicMute(bool state);
+    virtual     bool        getMicMute() const;
+
+    virtual     bool        isMusicActive() const;
+
+    virtual     status_t    setParameter(const char* key, const char* value);
+
+    enum hardware_call_state {
+        AUDIO_HW_IDLE = 0,
+        AUDIO_HW_INIT,
+        AUDIO_HW_OUTPUT_OPEN,
+        AUDIO_HW_OUTPUT_CLOSE,
+        AUDIO_HW_INPUT_OPEN,
+        AUDIO_HW_INPUT_CLOSE,
+        AUDIO_HW_STANDBY,
+        AUDIO_HW_SET_MASTER_VOLUME,
+        AUDIO_HW_GET_ROUTING,
+        AUDIO_HW_SET_ROUTING,
+        AUDIO_HW_GET_MODE,
+        AUDIO_HW_SET_MODE,
+        AUDIO_HW_GET_MIC_MUTE,
+        AUDIO_HW_SET_MIC_MUTE,
+        AUDIO_SET_VOICE_VOLUME,
+        AUDIO_SET_PARAMETER,
+    };
+
+    // record interface
+    virtual sp<IAudioRecord> openRecord(
+                                pid_t pid,
+                                int streamType,
+                                uint32_t sampleRate,
+                                int format,
+                                int channelCount,
+                                int bufferCount,
+                                uint32_t flags);
+
+    virtual     status_t    onTransact(
+                                uint32_t code,
+                                const Parcel& data,
+                                Parcel* reply,
+                                uint32_t flags);
+
+private:
+                            AudioFlinger();
+    virtual                 ~AudioFlinger();
+    
+    // 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:
+                            Client(const sp<AudioFlinger>& audioFlinger, pid_t pid);
+        virtual             ~Client();
+        const sp<MemoryDealer>&     heap() const;
+        pid_t               pid() const { return mPid; }
+    private:
+                            Client(const Client&);
+                            Client& operator = (const Client&);
+        sp<AudioFlinger>    mAudioFlinger;
+        sp<MemoryDealer>    mMemoryDealer;
+        pid_t               mPid;
+    };
+
+
+    // --- Track ---
+    class TrackHandle;
+    class RecordHandle;
+    class AudioRecordThread;
+
+    // base for record and playback
+    class TrackBase : public AudioBufferProvider, public RefBase {
+
+    public:
+        enum track_state {
+            IDLE,
+            TERMINATED,
+            STOPPED,
+            RESUMING,
+            ACTIVE,
+            PAUSING,
+            PAUSED
+        };
+
+        enum track_flags {
+            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);
+                            ~TrackBase();
+
+        virtual status_t    start() = 0;
+        virtual void        stop() = 0;
+                sp<IMemory> getCblk() const;
+
+    protected:
+        friend class AudioFlinger;
+        friend class RecordHandle;
+
+                            TrackBase(const TrackBase&);
+                            TrackBase& operator = (const TrackBase&);
+
+        virtual status_t getNextBuffer(AudioBufferProvider::Buffer* buffer) = 0;
+        virtual void releaseBuffer(AudioBufferProvider::Buffer* buffer);
+
+        audio_track_cblk_t* cblk() const {
+            return mCblk;
+        }
+
+        int type() const {
+            return mStreamType;
+        }
+
+        int format() const {
+            return mFormat;
+        }
+
+        int channelCount() const {
+            return mChannelCount;
+        }
+
+        int bufferCount() const {
+            return mBufferCount;
+        }
+
+        int sampleRate() const;
+
+        void* getBuffer(int n) const {
+            return (char*)mBuffers + n * mBufferSize;
+        }
+
+        int name() const {
+            return mName;
+        }
+
+        bool isStopped() const {
+            return mState == STOPPED;
+        }
+
+        bool isTerminated() const {
+            return mState == TERMINATED;
+        }
+
+        bool step();
+        void reset();
+
+        sp<AudioFlinger>    mAudioFlinger;
+        sp<Client>          mClient;
+        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;
+        int                 mName;
+        // we don't really need a lock for these
+        int                 mState;
+        int                 mClientTid;
+    };
+
+    // playback track
+    class Track : public TrackBase {
+    public:
+                            Track(  const sp<AudioFlinger>& audioFlinger,
+                                    const sp<Client>& client,
+                                    int streamType,
+                                    uint32_t sampleRate,
+                                    int format,
+                                    int channelCount,
+                                    int bufferCount,
+                                    int bufferSize);
+                            ~Track();
+
+                void        dump(char* buffer, size_t size);
+        virtual status_t    start();
+        virtual void        stop();
+                void        pause();
+
+                void        flush();
+                void        destroy();
+                void        mute(bool);
+                void        setVolume(float left, float right);
+
+    private:
+        friend class AudioFlinger;
+        friend class TrackHandle;
+
+                            Track(const Track&);
+                            Track& operator = (const Track&);
+
+        virtual status_t getNextBuffer(AudioBufferProvider::Buffer* buffer);
+
+        bool isMuted() const {
+            return mMute;
+        }
+
+        bool isPausing() const {
+            return mState == PAUSING;
+        }
+
+        bool isPaused() const {
+            return mState == PAUSED;
+        }
+
+        bool isReady(uint32_t u, int32_t s) const;
+
+        void setPaused() { mState = PAUSED; }
+        void reset();
+
+        // we don't really need a lock for these
+        float               mVolume[2];
+        volatile bool       mMute;
+        // FILLED state is used for suppressing volume ramp at begin of playing
+        enum {FS_FILLING, FS_FILLED, FS_ACTIVE};
+        mutable uint8_t     mFillingUpStatus;
+        int8_t              mRetryCount;
+    };  // end of Track
+
+    friend class AudioBuffer;
+
+    class TrackHandle : public android::BnAudioTrack {
+    public:
+                            TrackHandle(const sp<Track>& track);
+        virtual             ~TrackHandle();
+        virtual status_t    start();
+        virtual void        stop();
+        virtual void        flush();
+        virtual void        mute(bool);
+        virtual void        pause();
+        virtual void        setVolume(float left, float right);
+        virtual sp<IMemory> getCblk() const;
+        virtual status_t onTransact(
+            uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags);
+    private:
+        sp<Track> mTrack;
+    };
+
+    struct  stream_type_t {
+        stream_type_t()
+            :   volume(1.0f),
+                mute(false)
+        {
+        }
+        float       volume;
+        bool        mute;
+    };
+
+    friend class Client;
+    friend class Track;
+
+
+                void        removeClient(pid_t pid);
+
+                status_t    addTrack(const sp<Track>& track);
+                void        removeTrack(wp<Track> track, int name);
+                void        remove_track_l(wp<Track> track, int name);
+                void        destroyTrack(const sp<Track>& track);
+
+                AudioMixer& audioMixer() {
+                    return *mAudioMixer;
+                }
+
+    // record track
+    class RecordTrack : public TrackBase {
+    public:
+                            RecordTrack(  const sp<AudioFlinger>& audioFlinger,
+                                    const sp<Client>& client,
+                                    int streamType,
+                                    uint32_t sampleRate,
+                                    int format,
+                                    int channelCount,
+                                    int bufferCount,
+                                    int bufferSize);
+                            ~RecordTrack();
+
+        virtual status_t    start();
+        virtual void        stop();
+
+                bool        overflow() { bool tmp = mOverflow; mOverflow = false; return tmp; }
+                bool        setOverflow() { bool tmp = mOverflow; mOverflow = true; return tmp; }
+
+    private:
+        friend class AudioFlinger;
+        friend class RecordHandle;
+        friend class AudioRecordThread;
+
+                            RecordTrack(const Track&);
+                            RecordTrack& operator = (const Track&);
+
+        virtual status_t getNextBuffer(AudioBufferProvider::Buffer* buffer);
+
+        bool                mOverflow;
+    };
+
+    class RecordHandle : public android::BnAudioRecord {
+    public:
+        RecordHandle(const sp<RecordTrack>& recordTrack);
+        virtual             ~RecordHandle();
+        virtual status_t    start();
+        virtual void        stop();
+        virtual sp<IMemory> getCblk() const;
+        virtual status_t onTransact(
+            uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags);
+    private:
+        sp<RecordTrack> mRecordTrack;
+    };
+
+    // record thread
+    class AudioRecordThread : public Thread
+    {
+    public:
+        AudioRecordThread(const sp<AudioFlinger>& audioFlinger);
+        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();
+                void        exit();
+                
+                bool        isOpen() { return bool(mRecordTrack != NULL); }
+
+    private:
+                AudioRecordThread();
+                sp<AudioFlinger>                    mAudioFlinger;
+                wp<RecordTrack>                     mRecordTrack;
+                AudioStreamIn*                      mInput;
+                Mutex                               mLock;
+                Condition                           mWaitWorkCV;
+                AudioBufferProvider::Buffer         mBuffer;
+                volatile bool                       mActive;
+    };
+
+    friend class AudioRecordThread;
+
+                sp<AudioRecordThread> audioRecordThread();
+                void        endRecord();
+                status_t    startRecord();
+                void        stopRecord();
+                void        exitRecord();
+                
+                AudioHardwareInterface* audioHardware() { return mAudioHardware; }
+
+    mutable     Mutex                                       mHardwareLock;
+    mutable     Mutex                                       mLock;
+    mutable     Condition                                   mWaitWorkCV;
+                DefaultKeyedVector< pid_t, wp<Client> >     mClients;
+                SortedVector< wp<Track> >                   mActiveTracks;
+                SortedVector< sp<Track> >                   mTracks;
+                float                               mMasterVolume;
+                uint32_t                            mMasterRouting;
+                bool                                mMasterMute;
+                stream_type_t                       mStreamTypes[AudioTrack::NUM_STREAM_TYPES];
+
+                AudioMixer*                         mAudioMixer;
+                AudioHardwareInterface*             mAudioHardware;
+                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;
+                int                                 mNumWrites;
+                int                                 mNumDelayedWrites;
+                bool                                mStandby;
+                bool                                mInWrite;
+};
+
+// ----------------------------------------------------------------------------
+
+}; // namespace android
+
+#endif // ANDROID_AUDIO_FLINGER_H
diff --git a/libs/audioflinger/AudioHardwareGeneric.cpp b/libs/audioflinger/AudioHardwareGeneric.cpp
new file mode 100644
index 0000000..b1e5b7f
--- /dev/null
+++ b/libs/audioflinger/AudioHardwareGeneric.cpp
@@ -0,0 +1,293 @@
+/*
+**
+** 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 
+**
+**     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 <stdint.h>
+#include <sys/types.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sched.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+
+#define LOG_TAG "AudioHardware"
+#include <utils/Log.h>
+#include <utils/String8.h>
+
+#include "AudioHardwareGeneric.h"
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+
+static char const * const kAudioDeviceName = "/dev/eac";
+
+// ----------------------------------------------------------------------------
+
+AudioHardwareGeneric::AudioHardwareGeneric()
+    : mOutput(0), mInput(0),  mFd(-1), mMicMute(false)
+{
+    mFd = ::open(kAudioDeviceName, O_RDWR);
+}
+
+AudioHardwareGeneric::~AudioHardwareGeneric()
+{
+    if (mFd >= 0) ::close(mFd);
+    delete mOutput;
+    delete mInput;
+}
+
+status_t AudioHardwareGeneric::initCheck()
+{
+    if (mFd >= 0) {
+        if (::access(kAudioDeviceName, O_RDWR) == NO_ERROR)
+            return NO_ERROR;
+    }
+    return NO_INIT;
+}
+
+status_t AudioHardwareGeneric::standby()
+{
+    // Implement: audio hardware to standby mode
+    return NO_ERROR;
+}
+
+AudioStreamOut* AudioHardwareGeneric::openOutputStream(
+        int format, int channelCount, uint32_t sampleRate)
+{
+    AutoMutex lock(mLock);
+
+    // only one output stream allowed
+    if (mOutput) return 0;
+
+    // create new output stream
+    AudioStreamOutGeneric* out = new AudioStreamOutGeneric();
+    if (out->set(this, mFd, format, channelCount, sampleRate) == NO_ERROR) {
+        mOutput = out;
+    } else {
+        delete out;
+    }
+    return mOutput;
+}
+
+void AudioHardwareGeneric::closeOutputStream(AudioStreamOutGeneric* out) {
+    if (out == mOutput) mOutput = 0;
+}
+
+AudioStreamIn* AudioHardwareGeneric::openInputStream(
+        int format, int channelCount, uint32_t sampleRate)
+{
+    AutoMutex lock(mLock);
+
+    // only one input stream allowed
+    if (mInput) return 0;
+
+    // create new output stream
+    AudioStreamInGeneric* in = new AudioStreamInGeneric();
+    if (in->set(this, mFd, format, channelCount, sampleRate) == NO_ERROR) {
+        mInput = in;
+    } else {
+        delete in;
+    }
+    return mInput;
+}
+
+void AudioHardwareGeneric::closeInputStream(AudioStreamInGeneric* in) {
+    if (in == mInput) mInput = 0;
+}
+
+status_t AudioHardwareGeneric::setVoiceVolume(float v)
+{
+    // Implement: set voice volume
+    return NO_ERROR;
+}
+
+status_t AudioHardwareGeneric::setMasterVolume(float v)
+{
+    // Implement: set master volume
+    // return error - software mixer will handle it
+    return INVALID_OPERATION;
+}
+
+status_t AudioHardwareGeneric::setMicMute(bool state)
+{
+    mMicMute = state;
+    return NO_ERROR;
+}
+
+status_t AudioHardwareGeneric::getMicMute(bool* state)
+{
+    *state = mMicMute;
+    return NO_ERROR;
+}
+
+status_t AudioHardwareGeneric::dumpInternals(int fd, const Vector<String16>& args)
+{
+    const size_t SIZE = 256;
+    char buffer[SIZE];
+    String8 result;
+    result.append("AudioHardwareGeneric::dumpInternals\n");
+    snprintf(buffer, SIZE, "\tmFd: %d mMicMute: %s\n",  mFd, mMicMute? "true": "false");
+    result.append(buffer);
+    ::write(fd, result.string(), result.size());
+    return NO_ERROR;
+}
+
+status_t AudioHardwareGeneric::dump(int fd, const Vector<String16>& args)
+{
+    dumpInternals(fd, args);
+    if (mInput) {
+        mInput->dump(fd, args);
+    }
+    if (mOutput) {
+        mOutput->dump(fd, args);
+    }
+    return NO_ERROR;
+}
+
+// ----------------------------------------------------------------------------
+
+status_t AudioStreamOutGeneric::set(
+        AudioHardwareGeneric *hw,
+        int fd,
+        int format,
+        int channels,
+        uint32_t 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;
+
+    mAudioHardware = hw;
+    mFd = fd;
+    return NO_ERROR;
+}
+
+AudioStreamOutGeneric::~AudioStreamOutGeneric()
+{
+    if (mAudioHardware)
+        mAudioHardware->closeOutputStream(this);
+}
+
+ssize_t AudioStreamOutGeneric::write(const void* buffer, size_t bytes)
+{
+    Mutex::Autolock _l(mLock);
+    return ssize_t(::write(mFd, buffer, bytes));
+}
+
+status_t AudioStreamOutGeneric::dump(int fd, const Vector<String16>& args)
+{
+    const size_t SIZE = 256;
+    char buffer[SIZE];
+    String8 result;
+    snprintf(buffer, SIZE, "AudioStreamOutGeneric::dump\n");
+    result.append(buffer);
+    snprintf(buffer, SIZE, "\tsample rate: %d\n", sampleRate());
+    result.append(buffer);
+    snprintf(buffer, SIZE, "\tbuffer size: %d\n", bufferSize());
+    result.append(buffer);
+    snprintf(buffer, SIZE, "\tchannel count: %d\n", channelCount());
+    result.append(buffer);
+    snprintf(buffer, SIZE, "\tformat: %d\n", format());
+    result.append(buffer);
+    snprintf(buffer, SIZE, "\tmAudioHardware: %p\n", mAudioHardware);
+    result.append(buffer);
+    snprintf(buffer, SIZE, "\tmFd: %d\n", mFd);
+    result.append(buffer);
+    ::write(fd, result.string(), result.size());
+    return NO_ERROR;
+}
+
+// ----------------------------------------------------------------------------
+
+// record functions
+status_t AudioStreamInGeneric::set(
+        AudioHardwareGeneric *hw,
+        int fd,
+        int format,
+        int channels,
+        uint32_t rate)
+{
+    // FIXME: remove logging
+    LOGD("AudioStreamInGeneric::set(%p, %d, %d, %d, %u)", hw, fd, format, channels, rate);
+    // check values
+    if ((format != AudioSystem::PCM_16_BIT) ||
+            (channels != channelCount()) ||
+            (rate != sampleRate())) {
+        LOGE("Error opening input channel");
+        return BAD_VALUE;
+    }
+
+    mAudioHardware = hw;
+    mFd = fd;
+    return NO_ERROR;
+}
+
+AudioStreamInGeneric::~AudioStreamInGeneric()
+{
+    // FIXME: remove logging
+    LOGD("AudioStreamInGeneric destructor");
+    if (mAudioHardware)
+        mAudioHardware->closeInputStream(this);
+}
+
+ssize_t AudioStreamInGeneric::read(void* buffer, ssize_t bytes)
+{
+    // FIXME: remove logging
+    LOGD("AudioStreamInGeneric::read(%p, %d) from fd %d", buffer, bytes, mFd);
+    AutoMutex lock(mLock);
+    if (mFd < 0) {
+        LOGE("Attempt to read from unopened device");
+        return NO_INIT;
+    }
+    return ::read(mFd, buffer, bytes);
+}
+
+status_t AudioStreamInGeneric::dump(int fd, const Vector<String16>& args)
+{
+    const size_t SIZE = 256;
+    char buffer[SIZE];
+    String8 result;
+    snprintf(buffer, SIZE, "AudioStreamInGeneric::dump\n");
+    result.append(buffer);
+    snprintf(buffer, SIZE, "\tsample rate: %d\n", sampleRate());
+    result.append(buffer);
+    snprintf(buffer, SIZE, "\tbuffer size: %d\n", bufferSize());
+    result.append(buffer);
+    snprintf(buffer, SIZE, "\tchannel count: %d\n", channelCount());
+    result.append(buffer);
+    snprintf(buffer, SIZE, "\tformat: %d\n", format());
+    result.append(buffer);
+    snprintf(buffer, SIZE, "\tmAudioHardware: %p\n", mAudioHardware);
+    result.append(buffer);
+    snprintf(buffer, SIZE, "\tmFd: %d\n", mFd);
+    result.append(buffer);
+    ::write(fd, result.string(), result.size());
+    return NO_ERROR;
+}
+
+// ----------------------------------------------------------------------------
+
+}; // namespace android
diff --git a/libs/audioflinger/AudioHardwareGeneric.h b/libs/audioflinger/AudioHardwareGeneric.h
new file mode 100644
index 0000000..10cc45d
--- /dev/null
+++ b/libs/audioflinger/AudioHardwareGeneric.h
@@ -0,0 +1,135 @@
+/*
+**
+** 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 
+**
+**     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 ANDROID_AUDIO_HARDWARE_GENERIC_H
+#define ANDROID_AUDIO_HARDWARE_GENERIC_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/threads.h>
+
+#include <hardware/AudioHardwareInterface.h>
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+
+class AudioHardwareGeneric;
+
+class AudioStreamOutGeneric : public AudioStreamOut {
+public:
+                        AudioStreamOutGeneric() : mAudioHardware(0), mFd(-1) {}
+    virtual             ~AudioStreamOutGeneric();
+
+    virtual status_t    set(
+            AudioHardwareGeneric *hw,
+            int mFd,
+            int format,
+            int channelCount,
+            uint32_t sampleRate);
+
+    virtual uint32_t    sampleRate() const { return 44100; }
+    virtual size_t      bufferSize() const { return 4096; }
+    virtual int         channelCount() const { return 2; }
+    virtual int         format() const { return AudioSystem::PCM_16_BIT; }
+    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);
+
+private:
+    AudioHardwareGeneric *mAudioHardware;
+    Mutex   mLock;
+    int     mFd;
+};
+
+class AudioStreamInGeneric : public AudioStreamIn {
+public:
+                        AudioStreamInGeneric() : mAudioHardware(0), mFd(-1) {}
+    virtual             ~AudioStreamInGeneric();
+
+    virtual status_t    set(
+            AudioHardwareGeneric *hw,
+            int mFd,
+            int format,
+            int channelCount,
+            uint32_t sampleRate);
+
+    uint32_t    sampleRate() const { return 8000; }
+    virtual size_t      bufferSize() const { return 320; }
+    virtual int         channelCount() const { return 1; }
+    virtual int         format() const { return AudioSystem::PCM_16_BIT; }
+    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);
+
+private:
+    AudioHardwareGeneric *mAudioHardware;
+    Mutex   mLock;
+    int     mFd;
+};
+
+
+class AudioHardwareGeneric : public  AudioHardwareInterface
+{
+public:
+                        AudioHardwareGeneric();
+    virtual             ~AudioHardwareGeneric();
+    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);
+
+    virtual status_t    setParameter(const char* key, const char* value)
+            { return NO_ERROR; }
+
+    // create I/O streams
+    virtual AudioStreamOut* openOutputStream(
+            int format=0,
+            int channelCount=0,
+            uint32_t sampleRate=0);
+
+    virtual AudioStreamIn* openInputStream(
+            int format,
+            int channelCount,
+            uint32_t sampleRate);
+
+            void            closeOutputStream(AudioStreamOutGeneric* out);
+            void            closeInputStream(AudioStreamInGeneric* in);
+protected:
+    virtual status_t        doRouting() { return NO_ERROR; }
+    virtual status_t        dump(int fd, const Vector<String16>& args);
+
+private:
+    status_t                dumpInternals(int fd, const Vector<String16>& args);
+    
+    Mutex                   mLock;
+    AudioStreamOutGeneric   *mOutput;
+    AudioStreamInGeneric    *mInput;
+    int                     mFd;
+    bool                    mMicMute;
+};
+
+// ----------------------------------------------------------------------------
+
+}; // namespace android
+
+#endif // ANDROID_AUDIO_HARDWARE_GENERIC_H
diff --git a/libs/audioflinger/AudioHardwareInterface.cpp b/libs/audioflinger/AudioHardwareInterface.cpp
new file mode 100644
index 0000000..7387b3d
--- /dev/null
+++ b/libs/audioflinger/AudioHardwareInterface.cpp
@@ -0,0 +1,240 @@
+/*
+**
+** 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 
+**
+**     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 <cutils/properties.h>
+#include <string.h>
+#include <unistd.h>
+
+#define LOG_TAG "AudioHardwareInterface"
+#include <utils/Log.h>
+#include <utils/String8.h>
+
+#include "AudioHardwareStub.h"
+#include "AudioHardwareGeneric.h"
+
+// #define DUMP_FLINGER_OUT        // if defined allows recording samples in a file
+#ifdef DUMP_FLINGER_OUT
+#include "AudioDumpInterface.h"
+#endif
+
+
+// change to 1 to log routing calls
+#define LOG_ROUTING_CALLS 0
+
+namespace android {
+
+#if LOG_ROUTING_CALLS
+static const char* routingModeStrings[] =
+{
+    "OUT OF RANGE",
+    "INVALID",
+    "CURRENT",
+    "NORMAL",
+    "RINGTONE",
+    "IN_CALL"
+};
+
+static const char* routeStrings[] =
+{
+    "EARPIECE ",
+    "SPEAKER ",
+    "BLUETOOTH ",
+    "HEADSET "
+};
+static const char* routeNone = "NONE";
+
+static const char* displayMode(int mode)
+{
+    if ((mode < -2) || (mode > 2))
+        return routingModeStrings[0];
+    return routingModeStrings[mode+3];
+}
+
+static const char* displayRoutes(uint32_t routes)
+{
+    static char routeStr[80];
+    if (routes == 0)
+        return routeNone;
+    routeStr[0] = 0;
+    int bitMask = 1;
+    for (int i = 0; i < 4; ++i, bitMask <<= 1) {
+        if (routes & bitMask) {
+            strcat(routeStr, routeStrings[i]);
+        }
+    }
+    routeStr[strlen(routeStr)-1] = 0;
+    return routeStr;
+}
+#endif
+
+// ----------------------------------------------------------------------------
+
+AudioHardwareInterface* AudioHardwareInterface::create()
+{
+    /*
+     * FIXME: This code needs to instantiate the correct audio device
+     * interface. For now - we use compile-time switches.
+     */
+    AudioHardwareInterface* hw = 0;
+    char value[PROPERTY_VALUE_MAX];
+
+#ifdef GENERIC_AUDIO
+    hw = new AudioHardwareGeneric();
+#else
+    // if running in emulation - use the emulator driver
+    if (property_get("ro.kernel.qemu", value, 0)) {
+        LOGD("Running in emulation - using generic audio driver");
+        hw = new AudioHardwareGeneric();
+    }
+    else {
+        LOGV("Creating Vendor Specific AudioHardware");
+        hw = createAudioHardware();
+    }
+#endif
+    if (hw->initCheck() != NO_ERROR) {
+        LOGW("Using stubbed audio hardware. No sound will be produced.");
+        delete hw;
+        hw = new AudioHardwareStub();
+    }
+    
+#ifdef DUMP_FLINGER_OUT
+    // 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.
+    
+    // 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;
+    }
+#endif
+    return hw;
+}
+
+AudioStreamOut::~AudioStreamOut()
+{
+}
+
+AudioStreamIn::~AudioStreamIn() {}
+
+AudioHardwareInterface::AudioHardwareInterface()
+{
+    // force a routing update on initialization
+    memset(&mRoutes, 0, sizeof(mRoutes));
+    mMode = 0;
+}
+
+// generics for audio routing - the real work is done in doRouting
+status_t AudioHardwareInterface::setRouting(int mode, uint32_t routes)
+{
+#if LOG_ROUTING_CALLS
+    LOGD("setRouting: mode=%s, routes=[%s]", displayMode(mode), displayRoutes(routes));
+#endif
+    if (mode == AudioSystem::MODE_CURRENT)
+        mode = mMode;
+    if ((mode < 0) || (mode >= AudioSystem::NUM_MODES))
+        return BAD_VALUE;
+    uint32_t old = mRoutes[mode];
+    mRoutes[mode] = routes;
+    if ((mode != mMode) || (old == routes))
+        return NO_ERROR;
+#if LOG_ROUTING_CALLS
+    const char* oldRouteStr = strdup(displayRoutes(old));
+    LOGD("doRouting: mode=%s, old route=[%s], new route=[%s]",
+           displayMode(mode), oldRouteStr, displayRoutes(routes));
+    delete oldRouteStr;
+#endif
+    return doRouting();
+}
+
+status_t AudioHardwareInterface::getRouting(int mode, uint32_t* routes)
+{
+    if (mode == AudioSystem::MODE_CURRENT)
+        mode = mMode;
+    if ((mode < 0) || (mode >= AudioSystem::NUM_MODES))
+        return BAD_VALUE;
+    *routes = mRoutes[mode];
+#if LOG_ROUTING_CALLS
+    LOGD("getRouting: mode=%s, routes=[%s]",
+           displayMode(mode), displayRoutes(*routes));
+#endif
+    return NO_ERROR;
+}
+
+status_t AudioHardwareInterface::setMode(int mode)
+{
+#if LOG_ROUTING_CALLS
+    LOGD("setMode(%s)", displayMode(mode));
+#endif
+    if ((mode < 0) || (mode >= AudioSystem::NUM_MODES))
+        return BAD_VALUE;
+    if (mMode == mode)
+        return NO_ERROR;
+#if LOG_ROUTING_CALLS
+    LOGD("doRouting: old mode=%s, new mode=%s route=[%s]",
+            displayMode(mMode), displayMode(mode), displayRoutes(mRoutes[mode]));
+#endif
+    mMode = mode;
+    return doRouting();
+}
+
+status_t AudioHardwareInterface::getMode(int* mode)
+{
+    // Implement: set audio routing
+    *mode = mMode;
+    return NO_ERROR;
+}
+
+status_t AudioHardwareInterface::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)
+{
+    const size_t SIZE = 256;
+    char buffer[SIZE];
+    String8 result;
+    snprintf(buffer, SIZE, "AudioHardwareInterface::dumpState\n");
+    result.append(buffer);
+    snprintf(buffer, SIZE, "\tmMode: %d\n", mMode);
+    result.append(buffer);
+    for (int i = 0, n = AudioSystem::NUM_MODES; i < n; ++i) {
+        snprintf(buffer, SIZE, "\tmRoutes[%d]: %d\n", i, mRoutes[i]);
+        result.append(buffer);
+    }
+    ::write(fd, result.string(), result.size());
+    dump(fd, args);  // Dump the state of the concrete child.
+    return NO_ERROR;
+}
+
+// ----------------------------------------------------------------------------
+
+}; // namespace android
diff --git a/libs/audioflinger/AudioHardwareStub.cpp b/libs/audioflinger/AudioHardwareStub.cpp
new file mode 100644
index 0000000..0046db8
--- /dev/null
+++ b/libs/audioflinger/AudioHardwareStub.cpp
@@ -0,0 +1,175 @@
+/* //device/servers/AudioFlinger/AudioHardwareStub.cpp
+**
+** 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 
+**
+**     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 <stdint.h>
+#include <sys/types.h>
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <utils/String8.h>
+
+#include "AudioHardwareStub.h"
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+
+AudioHardwareStub::AudioHardwareStub() : mMicMute(false)
+{
+}
+
+AudioHardwareStub::~AudioHardwareStub()
+{
+}
+
+status_t AudioHardwareStub::initCheck()
+{
+    return NO_ERROR;
+}
+
+status_t AudioHardwareStub::standby()
+{
+    return NO_ERROR;
+}
+
+AudioStreamOut* AudioHardwareStub::openOutputStream(
+        int format, int channelCount, uint32_t sampleRate)
+{
+    AudioStreamOutStub* out = new AudioStreamOutStub();
+    if (out->set(format, channelCount, sampleRate) == NO_ERROR)
+        return out;
+    delete out;
+    return 0;
+}
+
+AudioStreamIn* AudioHardwareStub::openInputStream(
+        int format, int channelCount, uint32_t sampleRate)
+{
+    AudioStreamInStub* in = new AudioStreamInStub();
+    if (in->set(format, channelCount, sampleRate) == NO_ERROR)
+        return in;
+    delete in;
+    return 0;
+}
+
+status_t AudioHardwareStub::setVoiceVolume(float volume)
+{
+    return NO_ERROR;
+}
+
+status_t AudioHardwareStub::setMasterVolume(float volume)
+{
+    return NO_ERROR;
+}
+
+status_t AudioHardwareStub::dumpInternals(int fd, const Vector<String16>& args)
+{
+    const size_t SIZE = 256;
+    char buffer[SIZE];
+    String8 result;
+    result.append("AudioHardwareStub::dumpInternals\n");
+    snprintf(buffer, SIZE, "\tmMicMute: %s\n", mMicMute? "true": "false");
+    result.append(buffer);
+    ::write(fd, result.string(), result.size());
+    return NO_ERROR;
+}
+
+status_t AudioHardwareStub::dump(int fd, const Vector<String16>& args)
+{
+    dumpInternals(fd, args);
+    return NO_ERROR;
+}
+
+// ----------------------------------------------------------------------------
+
+status_t AudioStreamOutStub::set(int format, int channels, uint32_t rate)
+{
+    // fix up defaults
+    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()))
+        return NO_ERROR;
+    return BAD_VALUE;
+}
+
+ssize_t AudioStreamOutStub::write(const void* buffer, size_t bytes)
+{
+    // fake timing for audio output
+    usleep(bytes * 1000000 / sizeof(int16_t) / channelCount() / sampleRate());
+    return bytes;
+}
+
+status_t AudioStreamOutStub::dump(int fd, const Vector<String16>& args)
+{
+    const size_t SIZE = 256;
+    char buffer[SIZE];
+    String8 result;
+    snprintf(buffer, SIZE, "AudioStreamOutStub::dump\n");
+    snprintf(buffer, SIZE, "\tsample rate: %d\n", sampleRate());
+    snprintf(buffer, SIZE, "\tbuffer size: %d\n", bufferSize());
+    snprintf(buffer, SIZE, "\tchannel count: %d\n", channelCount());
+    snprintf(buffer, SIZE, "\tformat: %d\n", format());
+    result.append(buffer);
+    ::write(fd, result.string(), result.size());
+    return NO_ERROR; 
+}
+
+// ----------------------------------------------------------------------------
+
+status_t AudioStreamInStub::set(int format, int channels, uint32_t rate)
+{
+    if ((format == AudioSystem::PCM_16_BIT) &&
+            (channels == channelCount()) &&
+            (rate == sampleRate()))
+        return NO_ERROR;
+    return BAD_VALUE;
+}
+
+ssize_t AudioStreamInStub::read(void* buffer, ssize_t bytes)
+{
+    // fake timing for audio input
+    usleep(bytes * 1000000 / sizeof(int16_t) / channelCount() / sampleRate());
+    memset(buffer, 0, bytes);
+    return bytes;
+}
+
+status_t AudioStreamInStub::dump(int fd, const Vector<String16>& args)
+{
+    const size_t SIZE = 256;
+    char buffer[SIZE];
+    String8 result;
+    snprintf(buffer, SIZE, "AudioStreamInStub::dump\n");
+    result.append(buffer);
+    snprintf(buffer, SIZE, "\tsample rate: %d\n", sampleRate());
+    result.append(buffer);
+    snprintf(buffer, SIZE, "\tbuffer size: %d\n", bufferSize());
+    result.append(buffer);
+    snprintf(buffer, SIZE, "\tchannel count: %d\n", channelCount());
+    result.append(buffer);
+    snprintf(buffer, SIZE, "\tformat: %d\n", format());
+    result.append(buffer);
+    ::write(fd, result.string(), result.size());
+    return NO_ERROR;
+}
+
+// ----------------------------------------------------------------------------
+
+}; // namespace android
diff --git a/libs/audioflinger/AudioHardwareStub.h b/libs/audioflinger/AudioHardwareStub.h
new file mode 100644
index 0000000..1a61552
--- /dev/null
+++ b/libs/audioflinger/AudioHardwareStub.h
@@ -0,0 +1,95 @@
+/* //device/servers/AudioFlinger/AudioHardwareStub.h
+**
+** 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 
+**
+**     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 ANDROID_AUDIO_HARDWARE_STUB_H
+#define ANDROID_AUDIO_HARDWARE_STUB_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <hardware/AudioHardwareInterface.h>
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+
+class AudioStreamOutStub : public AudioStreamOut {
+public:
+    virtual status_t    set(int format, int channelCount, uint32_t sampleRate);
+    virtual uint32_t    sampleRate() const { return 44100; }
+    virtual size_t      bufferSize() const { return 4096; }
+    virtual int         channelCount() const { return 2; }
+    virtual int         format() const { return AudioSystem::PCM_16_BIT; }
+    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);
+};
+
+class AudioStreamInStub : public AudioStreamIn {
+public:
+    virtual status_t    set(int format, int channelCount, uint32_t sampleRate);
+    virtual uint32_t    sampleRate() const { return 8000; }
+    virtual size_t      bufferSize() const { return 320; }
+    virtual int         channelCount() const { return 1; }
+    virtual int         format() const { return AudioSystem::PCM_16_BIT; }
+    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);
+};
+
+class AudioHardwareStub : public  AudioHardwareInterface
+{
+public:
+                        AudioHardwareStub();
+    virtual             ~AudioHardwareStub();
+    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) { mMicMute = state;  return  NO_ERROR; }
+    virtual status_t    getMicMute(bool* state) { *state = mMicMute ; return NO_ERROR; }
+
+    virtual status_t    setParameter(const char* key, const char* value)
+            { return NO_ERROR; }
+
+    // create I/O streams
+    virtual AudioStreamOut* openOutputStream(
+                                int format=0,
+                                int channelCount=0,
+                                uint32_t sampleRate=0);
+
+    virtual AudioStreamIn* openInputStream(
+                                int format,
+                                int channelCount,
+                                uint32_t sampleRate);
+
+protected:
+    virtual status_t    doRouting() { return NO_ERROR; }
+    virtual status_t    dump(int fd, const Vector<String16>& args);
+
+            bool        mMicMute;
+private:
+    status_t            dumpInternals(int fd, const Vector<String16>& args);
+};
+
+// ----------------------------------------------------------------------------
+
+}; // namespace android
+
+#endif // ANDROID_AUDIO_HARDWARE_STUB_H
diff --git a/libs/audioflinger/AudioMixer.cpp b/libs/audioflinger/AudioMixer.cpp
new file mode 100644
index 0000000..9f1b17f
--- /dev/null
+++ b/libs/audioflinger/AudioMixer.cpp
@@ -0,0 +1,857 @@
+/* //device/include/server/AudioFlinger/AudioMixer.cpp
+**
+** 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 
+**
+**     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.
+*/
+
+#define LOG_TAG "AudioMixer"
+
+#include <stdint.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/types.h>
+
+#include <utils/Errors.h>
+#include <utils/Log.h>
+
+#include "AudioMixer.h"
+
+namespace android {
+// ----------------------------------------------------------------------------
+
+static inline int16_t clamp16(int32_t sample)
+{
+    if ((sample>>15) ^ (sample>>31))
+        sample = 0x7FFF ^ (sample>>31);
+    return sample;
+}
+
+// ----------------------------------------------------------------------------
+
+AudioMixer::AudioMixer(size_t frameCount, uint32_t sampleRate)
+    :   mActiveTrack(0), mTrackNames(0), mSampleRate(sampleRate)
+{
+    mState.enabledTracks= 0;
+    mState.needsChanged = 0;
+    mState.frameCount   = frameCount;
+    mState.outputTemp   = 0;
+    mState.resampleTemp = 0;
+    mState.hook         = process__nop;
+    track_t* t = mState.tracks;
+    for (int i=0 ; i<32 ; i++) {
+        t->needs = 0;
+        t->volume[0] = UNITY_GAIN;
+        t->volume[1] = UNITY_GAIN;
+        t->volumeInc[0] = 0;
+        t->volumeInc[1] = 0;
+        t->channelCount = 2;
+        t->enabled = 0;
+        t->format = 16;
+        t->buffer.raw = 0;
+        t->bufferProvider = 0;
+        t->hook = 0;
+        t->resampler = 0;
+        t->sampleRate = mSampleRate;
+        t->in = 0;
+        t++;
+    }
+}
+
+ AudioMixer::~AudioMixer()
+ {
+     track_t* t = mState.tracks;
+     for (int i=0 ; i<32 ; i++) {
+         delete t->resampler;
+         t++;
+     }
+     delete [] mState.outputTemp;
+     delete [] mState.resampleTemp;
+ }
+
+ int AudioMixer::getTrackName()
+ {
+    uint32_t names = mTrackNames;
+    uint32_t mask = 1;
+    int n = 0;
+    while (names & mask) {
+        mask <<= 1;
+        n++;
+    }
+    if (mask) {
+        LOGV("add track (%d)", n);
+        mTrackNames |= mask;
+        return TRACK0 + n;
+    }
+    return -1;
+ }
+
+ void AudioMixer::invalidateState(uint32_t mask)
+ {
+    if (mask) {
+        mState.needsChanged |= mask;
+        mState.hook = process__validate;
+    }
+ }
+
+ void AudioMixer::deleteTrackName(int name)
+ {
+    name -= TRACK0;
+    if (uint32_t(name) < MAX_NUM_TRACKS) {
+        LOGV("deleteTrackName(%d)", name);
+        track_t& track(mState.tracks[ name ]);
+        if (track.enabled != 0) {
+            track.enabled = 0;
+            invalidateState(1<<name);
+        }
+        if (track.resampler) {
+            // delete  the resampler
+            delete track.resampler;
+            track.resampler = 0;
+            track.sampleRate = mSampleRate;
+            invalidateState(1<<name);
+        }
+        track.volumeInc[0] = 0;
+        track.volumeInc[1] = 0;
+        mTrackNames &= ~(1<<name);
+    }
+ }
+
+status_t AudioMixer::enable(int name)
+{
+    switch (name) {
+        case MIXING: {
+            if (mState.tracks[ mActiveTrack ].enabled != 1) {
+                mState.tracks[ mActiveTrack ].enabled = 1;
+                LOGV("enable(%d)", mActiveTrack);
+                invalidateState(1<<mActiveTrack);
+            }
+        } break;
+        default:
+            return NAME_NOT_FOUND;
+    }
+    return NO_ERROR;
+}
+
+status_t AudioMixer::disable(int name)
+{
+    switch (name) {
+        case MIXING: {
+            if (mState.tracks[ mActiveTrack ].enabled != 0) {
+                mState.tracks[ mActiveTrack ].enabled = 0;
+                LOGV("disable(%d)", mActiveTrack);
+                invalidateState(1<<mActiveTrack);
+            }
+        } break;
+        default:
+            return NAME_NOT_FOUND;
+    }
+    return NO_ERROR;
+}
+
+status_t AudioMixer::setActiveTrack(int track)
+{
+    if (uint32_t(track-TRACK0) >= MAX_NUM_TRACKS) {
+        return BAD_VALUE;
+    }
+    mActiveTrack = track - TRACK0;
+    return NO_ERROR;
+}
+
+status_t AudioMixer::setParameter(int target, int name, int value)
+{
+    switch (target) {
+    case TRACK:
+        if (name == CHANNEL_COUNT) {
+            if ((uint32_t(value) <= MAX_NUM_CHANNELS) && (value)) {
+                if (mState.tracks[ mActiveTrack ].channelCount != value) {
+                    mState.tracks[ mActiveTrack ].channelCount = value;
+                    LOGV("setParameter(TRACK, CHANNEL_COUNT, %d)", value);
+                    invalidateState(1<<mActiveTrack);
+                }
+                return NO_ERROR;
+            }
+        }
+        break;
+    case RESAMPLE:
+        if (name == SAMPLE_RATE) {
+            if (value > 0) {
+                track_t& track = mState.tracks[ mActiveTrack ];
+                if (track.setResampler(uint32_t(value), mSampleRate)) {
+                    LOGV("setParameter(RESAMPLE, SAMPLE_RATE, %u)",
+                            uint32_t(value));
+                    invalidateState(1<<mActiveTrack);
+                }
+                return NO_ERROR;
+            }
+        }
+        break;
+    case RAMP_VOLUME:
+    case VOLUME:
+        if ((uint32_t(name-VOLUME0) < MAX_NUM_CHANNELS)) {
+            track_t& track = mState.tracks[ mActiveTrack ];
+            if (track.volume[name-VOLUME0] != value) {
+                track.prevVolume[name-VOLUME0] = track.volume[name-VOLUME0] << 16;
+                track.volume[name-VOLUME0] = value;
+                if (target == VOLUME) {
+                    track.prevVolume[name-VOLUME0] = value << 16;
+                    track.volumeInc[name-VOLUME0] = 0;
+                } else {
+                    int32_t d = (value<<16) - track.prevVolume[name-VOLUME0];
+                    int32_t volInc = d / int32_t(mState.frameCount);
+                    track.volumeInc[name-VOLUME0] = volInc;
+                    if (volInc == 0) {
+                        track.prevVolume[name-VOLUME0] = value << 16;
+                    }
+                }
+                invalidateState(1<<mActiveTrack);
+            }
+            return NO_ERROR;
+        }
+        break;
+    }
+    return BAD_VALUE;
+}
+
+bool AudioMixer::track_t::setResampler(uint32_t value, uint32_t devSampleRate)
+{
+    if (value!=devSampleRate || resampler) {
+        if (sampleRate != value) {
+            sampleRate = value;
+            if (resampler == 0) {
+                resampler = AudioResampler::create(
+                        format, channelCount, devSampleRate);
+            }
+            return true;
+        }
+    }
+    return false;
+}
+
+bool AudioMixer::track_t::doesResample() const
+{
+    return resampler != 0;
+}
+
+inline
+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]))) {
+            volumeInc[i] = 0;
+            prevVolume[i] = volume[i]<<16;
+        }
+    }
+}
+
+
+status_t AudioMixer::setBufferProvider(AudioBufferProvider* buffer)
+{
+    mState.tracks[ mActiveTrack ].bufferProvider = buffer;
+    return NO_ERROR;
+}
+
+
+
+void AudioMixer::process(void* output)
+{
+    mState.hook(&mState, output);
+}
+
+
+void AudioMixer::process__validate(state_t* state, void* output)
+{
+    LOGW_IF(!state->needsChanged,
+        "in process__validate() but nothing's invalid");
+
+    uint32_t changed = state->needsChanged;
+    state->needsChanged = 0; // clear the validation flag
+
+    // recompute which tracks are enabled / disabled
+    uint32_t enabled = 0;
+    uint32_t disabled = 0;
+    while (changed) {
+        const int i = 31 - __builtin_clz(changed);
+        const uint32_t mask = 1<<i;
+        changed &= ~mask;
+        track_t& t = state->tracks[i];
+        (t.enabled ? enabled : disabled) |= mask;
+    }
+    state->enabledTracks &= ~disabled;
+    state->enabledTracks |=  enabled;
+
+    // compute everything we need...
+    int countActiveTracks = 0;
+    int all16BitsStereoNoResample = 1;
+    int resampling = 0;
+    int volumeRamp = 0;
+    uint32_t en = state->enabledTracks;
+    while (en) {
+        const int i = 31 - __builtin_clz(en);
+        en &= ~(1<<i);
+
+        countActiveTracks++;
+        track_t& t = state->tracks[i];
+        uint32_t n = 0;
+        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) {
+            n |= NEEDS_MUTE_ENABLED;
+        }
+        t.needs = n;
+
+        if ((n & NEEDS_MUTE__MASK) == NEEDS_MUTE_ENABLED) {
+            t.hook = track__nop;
+        } else {
+            if ((n & NEEDS_RESAMPLE__MASK) == NEEDS_RESAMPLE_ENABLED) {
+                all16BitsStereoNoResample = 0;
+                resampling = 1;
+                t.hook = track__genericResample;
+            } else {
+                if ((n & NEEDS_CHANNEL_COUNT__MASK) == NEEDS_CHANNEL_1){
+                    t.hook = track__16BitsMono;
+                    all16BitsStereoNoResample = 0;
+                }
+                if ((n & NEEDS_CHANNEL_COUNT__MASK) == NEEDS_CHANNEL_2){
+                    t.hook = track__16BitsStereo;
+                }
+            }
+        }
+    }
+
+    // select the processing hooks
+    state->hook = process__nop;
+    if (countActiveTracks) {
+        if (resampling) {
+            if (!state->outputTemp) {
+                state->outputTemp = new int32_t[MAX_NUM_CHANNELS * state->frameCount];
+            }
+            if (!state->resampleTemp) {
+                state->resampleTemp = new int32_t[MAX_NUM_CHANNELS * state->frameCount];
+            }
+            state->hook = process__genericResampling;
+        } else {
+            if (state->outputTemp) {
+                delete [] state->outputTemp;
+                state->outputTemp = 0;
+            }
+            if (state->resampleTemp) {
+                delete [] state->resampleTemp;
+                state->resampleTemp = 0;
+            }
+            state->hook = process__genericNoResampling;
+            if (all16BitsStereoNoResample && !volumeRamp) {
+                if (countActiveTracks == 1) {
+                    state->hook = process__OneTrack16BitsStereoNoResampling;
+                }
+            }
+        }
+    }
+
+    LOGV("mixer configuration change: %d activeTracks (%08x) "
+        "all16BitsStereoNoResample=%d, resampling=%d, volumeRamp=%d",
+        countActiveTracks, state->enabledTracks,
+        all16BitsStereoNoResample, resampling, volumeRamp);
+
+   state->hook(state, output);
+
+   // Now that the volume ramp has been done, set optimal state and 
+   // track hooks for subsequent mixer process
+   if (countActiveTracks) {
+       int allMuted = 1;
+       uint32_t en = state->enabledTracks;
+       while (en) {
+           const int i = 31 - __builtin_clz(en);
+           en &= ~(1<<i);
+           track_t& t = state->tracks[i];
+           if (!t.doesResample() && t.volumeRL == 0)
+           {
+               t.needs |= NEEDS_MUTE_ENABLED;
+               t.hook = track__nop;
+           } else {
+               allMuted = 0;
+           }
+       }
+       if (allMuted) {
+           state->hook = process__nop;
+       } else if (!resampling && all16BitsStereoNoResample) {
+           if (countActiveTracks == 1) {
+              state->hook = process__OneTrack16BitsStereoNoResampling;
+           }
+       }
+   }
+}
+
+static inline 
+int32_t mulAdd(int16_t in, int16_t v, int32_t a)
+{
+#if defined(__arm__) && !defined(__thumb__)
+    int32_t out;
+    asm( "smlabb %[out], %[in], %[v], %[a] \n"
+         : [out]"=r"(out)
+         : [in]"%r"(in), [v]"r"(v), [a]"r"(a)
+         : );
+    return out;
+#else
+    return a + in * int32_t(v);
+#endif
+}
+
+static inline 
+int32_t mul(int16_t in, int16_t v)
+{
+#if defined(__arm__) && !defined(__thumb__)
+    int32_t out;
+    asm( "smulbb %[out], %[in], %[v] \n"
+         : [out]"=r"(out)
+         : [in]"%r"(in), [v]"r"(v)
+         : );
+    return out;
+#else
+    return in * int32_t(v);
+#endif
+}
+
+static inline 
+int32_t mulAddRL(int left, uint32_t inRL, uint32_t vRL, int32_t a)
+{
+#if defined(__arm__) && !defined(__thumb__)
+    int32_t out;
+    if (left) {
+        asm( "smlabb %[out], %[inRL], %[vRL], %[a] \n"
+             : [out]"=r"(out)
+             : [inRL]"%r"(inRL), [vRL]"r"(vRL), [a]"r"(a)
+             : );
+    } else {
+        asm( "smlatt %[out], %[inRL], %[vRL], %[a] \n"
+             : [out]"=r"(out)
+             : [inRL]"%r"(inRL), [vRL]"r"(vRL), [a]"r"(a)
+             : );
+    }
+    return out;
+#else
+    if (left) {
+        return a + int16_t(inRL&0xFFFF) * int16_t(vRL&0xFFFF);
+    } else {
+        return a + int16_t(inRL>>16) * int16_t(vRL>>16);
+    }
+#endif
+}
+
+static inline 
+int32_t mulRL(int left, uint32_t inRL, uint32_t vRL)
+{
+#if defined(__arm__) && !defined(__thumb__)
+    int32_t out;
+    if (left) {
+        asm( "smulbb %[out], %[inRL], %[vRL] \n"
+             : [out]"=r"(out)
+             : [inRL]"%r"(inRL), [vRL]"r"(vRL)
+             : );
+    } else {
+        asm( "smultt %[out], %[inRL], %[vRL] \n"
+             : [out]"=r"(out)
+             : [inRL]"%r"(inRL), [vRL]"r"(vRL)
+             : );
+    }
+    return out;
+#else
+    if (left) {
+        return int16_t(inRL&0xFFFF) * int16_t(vRL&0xFFFF);
+    } else {
+        return int16_t(inRL>>16) * int16_t(vRL>>16);
+    }
+#endif
+}
+
+
+void AudioMixer::track__genericResample(track_t* t, int32_t* out, size_t outFrameCount, int32_t* temp)
+{
+    t->resampler->setSampleRate(t->sampleRate);
+
+    // ramp gain - resample to temp buffer and scale/mix in 2nd step
+    if UNLIKELY(t->volumeInc[0]|t->volumeInc[1]) {
+        t->resampler->setVolume(UNITY_GAIN, UNITY_GAIN);
+        memset(temp, 0, outFrameCount * MAX_NUM_CHANNELS * sizeof(int32_t));
+        t->resampler->resample(temp, outFrameCount, t->bufferProvider);
+        volumeRampStereo(t, out, outFrameCount, temp);
+    }
+
+    // constant gain
+    else {
+        t->resampler->setVolume(t->volume[0], t->volume[1]);
+        t->resampler->resample(out, outFrameCount, t->bufferProvider);
+    }
+}
+
+void AudioMixer::track__nop(track_t* t, int32_t* out, size_t outFrameCount, int32_t* temp)
+{
+}
+
+void AudioMixer::volumeRampStereo(track_t* t, int32_t* out, size_t frameCount, int32_t* temp)
+{
+    int32_t vl = t->prevVolume[0];
+    int32_t vr = t->prevVolume[1];
+    const int32_t vlInc = t->volumeInc[0];
+    const int32_t vrInc = t->volumeInc[1];
+
+    //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);
+        *out++ += (vr >> 16) * (*temp++ >> 12);
+        vl += vlInc;
+        vr += vrInc;
+    } while (--frameCount);
+
+    t->prevVolume[0] = vl;
+    t->prevVolume[1] = vr;
+    t->adjustVolumeRamp();
+}
+
+void AudioMixer::track__16BitsStereo(track_t* t, int32_t* out, size_t frameCount, int32_t* temp)
+{
+    int16_t const *in = static_cast<int16_t const *>(t->in);
+
+    // ramp gain
+    if UNLIKELY(t->volumeInc[0]|t->volumeInc[1]) {
+        int32_t vl = t->prevVolume[0];
+        int32_t vr = t->prevVolume[1];
+        const int32_t vlInc = t->volumeInc[0];
+        const int32_t vrInc = t->volumeInc[1];
+
+        // LOGD("[1] %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);
+
+        do {
+            *out++ += (vl >> 16) * (int32_t) *in++;
+            *out++ += (vr >> 16) * (int32_t) *in++;
+            vl += vlInc;
+            vr += vrInc;
+        } while (--frameCount);
+        
+        t->prevVolume[0] = vl;
+        t->prevVolume[1] = vr;
+        t->adjustVolumeRamp();
+    }
+
+    // constant gain
+    else {
+        const uint32_t vrl = t->volumeRL;
+        do {
+            uint32_t rl = *reinterpret_cast<uint32_t const *>(in);
+            in += 2;
+            out[0] = mulAddRL(1, rl, vrl, out[0]);
+            out[1] = mulAddRL(0, rl, vrl, out[1]);
+            out += 2;
+        } while (--frameCount);
+    }
+    t->in = in;
+}
+
+void AudioMixer::track__16BitsMono(track_t* t, int32_t* out, size_t frameCount, int32_t* temp)
+{
+    int16_t const *in = static_cast<int16_t const *>(t->in);
+
+    // ramp gain
+    if UNLIKELY(t->volumeInc[0]|t->volumeInc[1]) {
+        int32_t vl = t->prevVolume[0];
+        int32_t vr = t->prevVolume[1];
+        const int32_t vlInc = t->volumeInc[0];
+        const int32_t vrInc = t->volumeInc[1];
+
+        // LOGD("[2] %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);
+
+        do {
+            int32_t l = *in++;
+            *out++ += (vl >> 16) * l;
+            *out++ += (vr >> 16) * l;
+            vl += vlInc;
+            vr += vrInc;
+        } while (--frameCount);
+        
+        t->prevVolume[0] = vl;
+        t->prevVolume[1] = vr;
+        t->adjustVolumeRamp();
+    }
+    // constant gain
+    else {
+        const int16_t vl = t->volume[0];
+        const int16_t vr = t->volume[1];
+        do {
+            int16_t l = *in++;
+            out[0] = mulAdd(l, vl, out[0]);
+            out[1] = mulAdd(l, vr, out[1]);
+            out += 2;
+        } while (--frameCount);
+    }
+    t->in = in;
+}
+
+inline 
+void AudioMixer::ditherAndClamp(int32_t* out, int32_t const *sums, size_t c)
+{
+    for (size_t i=0 ; i<c ; i++) {
+        int32_t l = *sums++;
+        int32_t r = *sums++;
+        int32_t nl = l >> 12;
+        int32_t nr = r >> 12;
+        l = clamp16(nl);
+        r = clamp16(nr);
+        *out++ = (r<<16) | (l & 0xFFFF);
+    }
+}
+
+// no-op case
+void AudioMixer::process__nop(state_t* state, void* output)
+{
+    // this assumes output 16 bits stereo, no resampling
+    memset(output, 0, state->frameCount*4);
+    uint32_t en = state->enabledTracks;
+    while (en) {
+        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) {
+            t.bufferProvider->releaseBuffer(&t.buffer);
+        }
+    }
+}
+
+// generic code without resampling
+void AudioMixer::process__genericNoResampling(state_t* state, void* output)
+{
+    int32_t outTemp[BLOCKSIZE * MAX_NUM_CHANNELS] __attribute__((aligned(32)));
+
+    // acquire each track's buffer
+    uint32_t enabledTracks = state->enabledTracks;
+    uint32_t en = enabledTracks;
+    while (en) {
+        const int i = 31 - __builtin_clz(en);
+        en &= ~(1<<i);
+        track_t& t = state->tracks[i];
+        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)
+            enabledTracks &= ~(1<<i); 
+    }
+
+    // this assumes output 16 bits stereo, no resampling
+    int32_t* out = static_cast<int32_t*>(output);
+    size_t numFrames = state->frameCount;
+    do {
+        memset(outTemp, 0, sizeof(outTemp));
+
+        en = enabledTracks;
+        while (en) {
+            const int i = 31 - __builtin_clz(en);
+            en &= ~(1<<i);
+            track_t& t = state->tracks[i];
+            (t.hook)(&t, outTemp, BLOCKSIZE, state->resampleTemp);
+        }
+
+        ditherAndClamp(out, outTemp, BLOCKSIZE);
+        out += BLOCKSIZE;
+
+        numFrames -= BLOCKSIZE;
+    } while (numFrames);
+
+
+    // release each track's buffer
+    en = enabledTracks;
+    while (en) {
+        const int i = 31 - __builtin_clz(en);
+        en &= ~(1<<i);
+        track_t& t = state->tracks[i];
+        t.bufferProvider->releaseBuffer(&t.buffer);
+    }
+}
+
+// generic code with resampling
+void AudioMixer::process__genericResampling(state_t* state, void* output)
+{
+    int32_t* const outTemp = state->outputTemp;
+    const size_t size = sizeof(int32_t) * MAX_NUM_CHANNELS * state->frameCount;
+    memset(outTemp, 0, size);
+
+    int32_t* out = static_cast<int32_t*>(output);
+    size_t numFrames = state->frameCount;
+
+    uint32_t en = state->enabledTracks;
+    while (en) {
+        const int i = 31 - __builtin_clz(en);
+        en &= ~(1<<i);
+        track_t& t = state->tracks[i];
+
+        // this is a little goofy, on the resampling case we don't
+        // acquire/release the buffers because it's done by
+        // the resampler.
+        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);
+                t.bufferProvider->releaseBuffer(&t.buffer);
+            }
+        }
+    }
+
+    ditherAndClamp(out, outTemp, numFrames);
+}
+
+// one track, 16 bits stereo without resampling is the most common case
+void AudioMixer::process__OneTrack16BitsStereoNoResampling(state_t* state, void* output)
+{
+    const int i = 31 - __builtin_clz(state->enabledTracks);
+    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);
+    }
+
+    t.bufferProvider->releaseBuffer(&b);
+}
+
+// 2 tracks is also a common case
+void AudioMixer::process__TwoTracks16BitsStereoNoResampling(state_t* state, void* output)
+{
+    int i;
+    uint32_t en = state->enabledTracks;
+
+    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];
+    int16_t const *in1;
+    const int16_t vl1 = t1.volume[0];
+    const int16_t vr1 = t1.volume[1];
+    size_t numFrames = state->frameCount;
+    int32_t* out = static_cast<int32_t*>(output);
+
+    // 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));
+        }
+    } 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;
+        }
+    }
+    
+    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);
+
+    
+    if (t0.buffer.i16 != NULL) {
+        t0.bufferProvider->releaseBuffer(&b0);
+        if (t1.buffer.i16 != NULL) {
+            t1.bufferProvider->releaseBuffer(&b1);
+        } else {
+            delete [] in1;
+        }
+    } else {
+        delete [] in0;
+        if (t1.buffer.i16 != NULL) {
+            t1.bufferProvider->releaseBuffer(&b1);
+        }
+    }
+}
+
+// ----------------------------------------------------------------------------
+}; // namespace android
+
diff --git a/libs/audioflinger/AudioMixer.h b/libs/audioflinger/AudioMixer.h
new file mode 100644
index 0000000..9ca109f
--- /dev/null
+++ b/libs/audioflinger/AudioMixer.h
@@ -0,0 +1,192 @@
+/* //device/include/server/AudioFlinger/AudioMixer.h
+**
+** 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 
+**
+**     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 ANDROID_AUDIO_MIXER_H
+#define ANDROID_AUDIO_MIXER_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include "AudioBufferProvider.h"
+#include "AudioResampler.h"
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+
+#define LIKELY( exp )       (__builtin_expect( (exp) != 0, true  ))
+#define UNLIKELY( exp )     (__builtin_expect( (exp) != 0, false ))
+
+// ----------------------------------------------------------------------------
+
+class AudioMixer
+{
+public:
+                            AudioMixer(size_t frameCount, uint32_t sampleRate);
+
+                            ~AudioMixer();
+
+    static const uint32_t MAX_NUM_TRACKS = 32;
+    static const uint32_t MAX_NUM_CHANNELS = 2;
+
+    static const uint16_t UNITY_GAIN = 0x1000;
+
+    enum { // names
+
+        // track units (32 units)
+        TRACK0          = 0x1000,
+
+        // enable/disable
+        MIXING          = 0x2000,
+
+        // setParameter targets
+        TRACK           = 0x3000,
+        RESAMPLE        = 0x3001,
+        RAMP_VOLUME     = 0x3002, // ramp to new volume
+        VOLUME          = 0x3003, // don't ramp
+
+        // set Parameter names
+        // for target TRACK
+        CHANNEL_COUNT   = 0x4000,
+        FORMAT          = 0x4001,
+        // for TARGET RESAMPLE
+        SAMPLE_RATE     = 0x4100,
+        // for TARGET VOLUME (8 channels max)
+        VOLUME0         = 0x4200,
+        VOLUME1         = 0x4201,
+    };
+
+
+    int         getTrackName();
+    void        deleteTrackName(int name);
+
+    status_t    enable(int name);
+    status_t    disable(int name);
+
+    status_t    setActiveTrack(int track);
+    status_t    setParameter(int target, int name, int value);
+
+    status_t    setBufferProvider(AudioBufferProvider* bufferProvider);
+    void        process(void* output);
+
+    uint32_t    trackNames() const { return mTrackNames; }
+
+private:
+
+    enum {
+        NEEDS_CHANNEL_COUNT__MASK   = 0x00000003,
+        NEEDS_FORMAT__MASK          = 0x000000F0,
+        NEEDS_MUTE__MASK            = 0x00000100,
+        NEEDS_RESAMPLE__MASK        = 0x00001000,
+    };
+
+    enum {
+        NEEDS_CHANNEL_1             = 0x00000000,
+        NEEDS_CHANNEL_2             = 0x00000001,
+
+        NEEDS_FORMAT_16             = 0x00000010,
+
+        NEEDS_MUTE_DISABLED         = 0x00000000,
+        NEEDS_MUTE_ENABLED          = 0x00000100,
+
+        NEEDS_RESAMPLE_DISABLED     = 0x00000000,
+        NEEDS_RESAMPLE_ENABLED      = 0x00001000,
+    };
+
+    static inline int32_t applyVolume(int32_t in, int32_t v) {
+        return in * v;
+    }
+
+
+    struct state_t;
+
+    typedef void (*mix_t)(state_t* state, void* output);
+
+    static const int BLOCKSIZE = 16; // 4 cache lines
+
+    struct track_t {
+        uint32_t    needs;
+
+        union {
+        int16_t     volume[2];      // [0]3.12 fixed point
+        int32_t     volumeRL;
+        };
+
+        int32_t     prevVolume[2];
+
+        int32_t     volumeInc[2];
+
+        uint16_t    reserved;
+
+        uint8_t     channelCount : 4;
+        uint8_t     enabled      : 1;
+        uint8_t     reserved0    : 3;
+        uint8_t     format;
+
+        AudioBufferProvider*                bufferProvider;
+        mutable AudioBufferProvider::Buffer buffer;
+
+        void (*hook)(track_t* t, int32_t* output, size_t numOutFrames, int32_t* temp);
+        void const* in;             // current location in buffer
+
+        AudioResampler*     resampler;
+        uint32_t            sampleRate;
+
+        bool        setResampler(uint32_t sampleRate, uint32_t devSampleRate);
+        bool        doesResample() const;
+        void        adjustVolumeRamp();
+    };
+
+    // pad to 32-bytes to fill cache line
+    struct state_t {
+        uint32_t        enabledTracks;
+        uint32_t        needsChanged;
+        size_t          frameCount;
+        mix_t           hook;
+        int32_t         *outputTemp;
+        int32_t         *resampleTemp;
+        int32_t         reserved[2];
+        track_t         tracks[32]; __attribute__((aligned(32)));
+    };
+
+    int             mActiveTrack;
+    uint32_t        mTrackNames;
+    const uint32_t  mSampleRate;
+
+    state_t         mState __attribute__((aligned(32)));
+
+    void invalidateState(uint32_t mask);
+
+    static void track__genericResample(track_t* t, int32_t* out, size_t numFrames, int32_t* temp);
+    static void track__nop(track_t* t, int32_t* out, size_t numFrames, int32_t* temp);
+    static void volumeRampStereo(track_t* t, int32_t* out, size_t frameCount, int32_t* temp);
+    static void track__16BitsStereo(track_t* t, int32_t* out, size_t numFrames, int32_t* temp);
+    static void track__16BitsMono(track_t* t, int32_t* out, size_t numFrames, int32_t* temp);
+    static void ditherAndClamp(int32_t* out, int32_t const *sums, size_t c);
+
+    static void process__validate(state_t* state, void* output);
+    static void process__nop(state_t* state, void* output);
+    static void process__genericNoResampling(state_t* state, void* output);
+    static void process__genericResampling(state_t* state, void* output);
+    static void process__OneTrack16BitsStereoNoResampling(state_t* state, void* output);
+    static void process__TwoTracks16BitsStereoNoResampling(state_t* state, void* output);
+};
+
+// ----------------------------------------------------------------------------
+}; // namespace android
+
+#endif // ANDROID_AUDIO_MIXER_H
diff --git a/libs/audioflinger/AudioResampler.cpp b/libs/audioflinger/AudioResampler.cpp
new file mode 100644
index 0000000..c93ead3
--- /dev/null
+++ b/libs/audioflinger/AudioResampler.cpp
@@ -0,0 +1,297 @@
+/*
+ * Copyright (C) 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
+ *
+ *      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 <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 {
+// ----------------------------------------------------------------------------
+
+class AudioResamplerOrder1 : public AudioResampler {
+public:
+    AudioResamplerOrder1(int bitDepth, int inChannelCount, int32_t sampleRate) :
+        AudioResampler(bitDepth, inChannelCount, sampleRate), mX0L(0), mX0R(0) {
+    }
+    virtual void resample(int32_t* out, size_t outFrameCount,
+            AudioBufferProvider* provider);
+private:
+    // number of bits used in interpolation multiply - 15 bits avoids overflow
+    static const int kNumInterpBits = 15;
+
+    // bits to shift the phase fraction down to avoid overflow
+    static const int kPreInterpShift = kNumPhaseBits - kNumInterpBits;
+
+    void init() {}
+    void resampleMono16(int32_t* out, size_t outFrameCount,
+            AudioBufferProvider* provider);
+    void resampleStereo16(int32_t* out, size_t outFrameCount,
+            AudioBufferProvider* provider);
+    static inline int32_t Interp(int32_t x0, int32_t x1, uint32_t f) {
+        return x0 + (((x1 - x0) * (int32_t)(f >> kPreInterpShift)) >> kNumInterpBits);
+    }
+    static inline void Advance(size_t* index, uint32_t* frac, uint32_t inc) {
+        *frac += inc;
+        *index += (size_t)(*frac >> kNumPhaseBits);
+        *frac &= kPhaseMask;
+    }
+    int mX0L;
+    int mX0R;
+};
+
+// ----------------------------------------------------------------------------
+AudioResampler* AudioResampler::create(int bitDepth, int inChannelCount,
+        int32_t sampleRate, int quality) {
+
+    // can only create low quality resample now
+    AudioResampler* resampler;
+
+    char value[PROPERTY_VALUE_MAX];
+    if (property_get("af.resampler.quality", value, 0)) {
+        quality = atoi(value);
+        LOGD("forcing AudioResampler quality to %d", quality);
+    }
+
+    if (quality == DEFAULT)
+        quality = LOW_QUALITY;
+    
+    switch (quality) {
+    default:
+    case LOW_QUALITY:
+        resampler = new AudioResamplerOrder1(bitDepth, inChannelCount, sampleRate);
+        break;
+    case MED_QUALITY:
+        resampler = new AudioResamplerCubic(bitDepth, inChannelCount, sampleRate);
+        break;
+    case HIGH_QUALITY:
+        resampler = new AudioResamplerSinc(bitDepth, inChannelCount, sampleRate);
+        break;
+    }
+    
+    // initialize resampler
+    resampler->init();
+    return resampler;
+}
+
+AudioResampler::AudioResampler(int bitDepth, int inChannelCount,
+        int32_t sampleRate) :
+    mBitDepth(bitDepth), mChannelCount(inChannelCount),
+            mSampleRate(sampleRate), mInSampleRate(sampleRate), mInputIndex(0),
+            mPhaseFraction(0) {
+    // sanity check on format
+    if ((bitDepth != 16) ||(inChannelCount < 1) || (inChannelCount > 2)) {
+        LOGE("Unsupported sample format, %d bits, %d channels", bitDepth,
+                inChannelCount);
+        // LOG_ASSERT(0);
+    }
+    
+    // initialize common members
+    mVolume[0] = mVolume[1] = 0;
+    mBuffer.raw = NULL;
+
+    // save format for quick lookup
+    if (inChannelCount == 1) {
+        mFormat = MONO_16_BIT;
+    } else {
+        mFormat = STEREO_16_BIT;
+    }
+}
+
+AudioResampler::~AudioResampler() {
+}
+
+void AudioResampler::setSampleRate(int32_t inSampleRate) {
+    mInSampleRate = inSampleRate;
+    mPhaseIncrement = (uint32_t)((kPhaseMultiplier * inSampleRate) / mSampleRate);
+}
+
+void AudioResampler::setVolume(int16_t left, int16_t right) {
+    // TODO: Implement anti-zipper filter
+    mVolume[0] = left;
+    mVolume[1] = right;
+}
+
+// ----------------------------------------------------------------------------
+
+void AudioResamplerOrder1::resample(int32_t* out, size_t outFrameCount,
+        AudioBufferProvider* provider) {
+
+    // should never happen, but we overflow if it does
+    // LOG_ASSERT(outFrameCount < 32767);
+
+    // select the appropriate resampler
+    switch (mChannelCount) {
+    case 1:
+        resampleMono16(out, outFrameCount, provider);
+        break;
+    case 2:
+        resampleStereo16(out, outFrameCount, provider);
+        break;
+    }
+}
+
+void AudioResamplerOrder1::resampleStereo16(int32_t* out, size_t outFrameCount,
+        AudioBufferProvider* provider) {
+
+    int32_t vl = mVolume[0];
+    int32_t vr = mVolume[1];
+
+    size_t inputIndex = mInputIndex;
+    uint32_t phaseFraction = mPhaseFraction;
+    uint32_t phaseIncrement = mPhaseIncrement;
+    size_t outputIndex = 0;
+    size_t outputSampleCount = outFrameCount * 2;
+
+    // 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) {
+            provider->getNextBuffer(&mBuffer);
+            if (mBuffer.raw == NULL)
+                break;
+            // LOGE("New buffer fetched: %d frames\n", mBuffer.frameCount);
+        }
+        int16_t *in = mBuffer.i16;
+
+        // handle boundary case
+        while (inputIndex == 0) {
+            // LOGE("boundary case\n");
+            out[outputIndex++] += vl * Interp(mX0L, in[0], phaseFraction);
+            out[outputIndex++] += vr * Interp(mX0R, in[1], phaseFraction);
+            Advance(&inputIndex, &phaseFraction, phaseIncrement);
+            if (outputIndex == outputSampleCount)
+                break;
+        }
+
+        // process input samples
+        // LOGE("general case\n");
+        while (outputIndex < outputSampleCount) {
+            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);
+
+            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);
+        }
+    }
+
+    // LOGE("output buffer full - outputIndex=%d, inputIndex=%d\n", outputIndex, inputIndex);
+
+    // save state
+    mInputIndex = inputIndex;
+    mPhaseFraction = phaseFraction;
+}
+
+void AudioResamplerOrder1::resampleMono16(int32_t* out, size_t outFrameCount,
+        AudioBufferProvider* provider) {
+
+    int32_t vl = mVolume[0];
+    int32_t vr = mVolume[1];
+
+    size_t inputIndex = mInputIndex;
+    uint32_t phaseFraction = mPhaseFraction;
+    uint32_t phaseIncrement = mPhaseIncrement;
+    size_t outputIndex = 0;
+    size_t outputSampleCount = outFrameCount * 2;
+
+    // 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) {
+            provider->getNextBuffer(&mBuffer);
+            if (mBuffer.raw == NULL)
+                break;
+            // LOGE("New buffer fetched: %d frames\n", mBuffer.frameCount);
+        }
+        int16_t *in = mBuffer.i16;
+
+        // handle boundary case
+        while (inputIndex == 0) {
+            // LOGE("boundary case\n");
+            int32_t sample = Interp(mX0L, in[0], phaseFraction);
+            out[outputIndex++] += vl * sample;
+            out[outputIndex++] += vr * sample;
+            Advance(&inputIndex, &phaseFraction, phaseIncrement);
+            if (outputIndex == outputSampleCount)
+                break;
+        }
+
+        // process input samples
+        // LOGE("general case\n");
+        while (outputIndex < outputSampleCount) {
+            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);
+
+            mX0L = mBuffer.i16[mBuffer.frameCount-1];
+            provider->releaseBuffer(&mBuffer);
+
+            // verify that the releaseBuffer NULLS the buffer pointer 
+            // LOG_ASSERT(mBuffer.raw == NULL);
+        }
+    }
+
+    // LOGE("output buffer full - outputIndex=%d, inputIndex=%d\n", outputIndex, inputIndex);
+
+    // save state
+    mInputIndex = inputIndex;
+    mPhaseFraction = phaseFraction;
+}
+
+// ----------------------------------------------------------------------------
+}
+; // namespace android
+
diff --git a/libs/audioflinger/AudioResampler.h b/libs/audioflinger/AudioResampler.h
new file mode 100644
index 0000000..39656c0
--- /dev/null
+++ b/libs/audioflinger/AudioResampler.h
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 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
+ *
+ *      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 ANDROID_AUDIO_RESAMPLER_H
+#define ANDROID_AUDIO_RESAMPLER_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include "AudioBufferProvider.h"
+
+namespace android {
+// ----------------------------------------------------------------------------
+
+class AudioResampler {
+public:
+    // Determines quality of SRC.
+    //  LOW_QUALITY: linear interpolator (1st order)
+    //  MED_QUALITY: cubic interpolator (3rd order)
+    //  HIGH_QUALITY: fixed multi-tap FIR (e.g. 48KHz->44.1KHz)
+    // NOTE: high quality SRC will only be supported for
+    // certain fixed rate conversions. Sample rate cannot be
+    // changed dynamically. 
+    enum src_quality {
+        DEFAULT=0,
+        LOW_QUALITY=1,
+        MED_QUALITY=2,
+        HIGH_QUALITY=3
+    };
+
+    static AudioResampler* create(int bitDepth, int inChannelCount,
+            int32_t sampleRate, int quality=DEFAULT);
+
+    virtual ~AudioResampler();
+
+    virtual void init() = 0;
+    virtual void setSampleRate(int32_t inSampleRate);
+    virtual void setVolume(int16_t left, int16_t right);
+
+    virtual void resample(int32_t* out, size_t outFrameCount,
+            AudioBufferProvider* provider) = 0;
+
+protected:
+    // number of bits for phase fraction - 30 bits allows nearly 2x downsampling
+    static const int kNumPhaseBits = 30;
+
+    // phase mask for fraction
+    static const uint32_t kPhaseMask = (1LU<<kNumPhaseBits)-1;
+
+    // multiplier to calculate fixed point phase increment
+    static const double kPhaseMultiplier = 1L << kNumPhaseBits;
+
+    enum format {MONO_16_BIT, STEREO_16_BIT};
+    AudioResampler(int bitDepth, int inChannelCount, int32_t sampleRate);
+
+    // prevent copying
+    AudioResampler(const AudioResampler&);
+    AudioResampler& operator=(const AudioResampler&);
+
+    int32_t mBitDepth;
+    int32_t mChannelCount;
+    int32_t mSampleRate;
+    int32_t mInSampleRate;
+    AudioBufferProvider::Buffer mBuffer;
+    union {
+    	int16_t mVolume[2];
+    	uint32_t mVolumeRL;
+    };
+    int16_t mTargetVolume[2];
+    format mFormat;
+    size_t mInputIndex;
+    int32_t mPhaseIncrement;
+    uint32_t mPhaseFraction;
+};
+
+// ----------------------------------------------------------------------------
+}
+; // namespace android
+
+#endif // ANDROID_AUDIO_RESAMPLER_H
diff --git a/libs/audioflinger/AudioResamplerCubic.cpp b/libs/audioflinger/AudioResamplerCubic.cpp
new file mode 100644
index 0000000..4f437bf
--- /dev/null
+++ b/libs/audioflinger/AudioResamplerCubic.cpp
@@ -0,0 +1,178 @@
+/*
+ * Copyright (C) 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
+ *
+ *      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 <stdint.h>
+#include <string.h>
+#include <sys/types.h>
+#include <cutils/log.h>
+
+#include "AudioResampler.h"
+#include "AudioResamplerCubic.h"
+
+#define LOG_TAG "AudioSRC"
+
+namespace android {
+// ----------------------------------------------------------------------------
+
+void AudioResamplerCubic::init() {
+    memset(&left, 0, sizeof(state));
+    memset(&right, 0, sizeof(state));
+}
+
+void AudioResamplerCubic::resample(int32_t* out, size_t outFrameCount,
+        AudioBufferProvider* provider) {
+
+    // should never happen, but we overflow if it does
+    // LOG_ASSERT(outFrameCount < 32767);
+
+    // select the appropriate resampler
+    switch (mChannelCount) {
+    case 1:
+        resampleMono16(out, outFrameCount, provider);
+        break;
+    case 2:
+        resampleStereo16(out, outFrameCount, provider);
+        break;
+    }
+}
+
+void AudioResamplerCubic::resampleStereo16(int32_t* out, size_t outFrameCount,
+        AudioBufferProvider* provider) {
+
+    int32_t vl = mVolume[0];
+    int32_t vr = mVolume[1];
+
+    size_t inputIndex = mInputIndex;
+    uint32_t phaseFraction = mPhaseFraction;
+    uint32_t phaseIncrement = mPhaseIncrement;
+    size_t outputIndex = 0;
+    size_t outputSampleCount = outFrameCount * 2;
+    
+    // fetch first buffer
+    if (mBuffer.raw == NULL) {
+        provider->getNextBuffer(&mBuffer);
+        if (mBuffer.raw == NULL)
+            return;
+        // LOGW("New buffer: offset=%p, frames=%dn", mBuffer.raw, mBuffer.frameCount);
+    }
+    int16_t *in = mBuffer.i16;
+
+    while (outputIndex < outputSampleCount) {
+        int32_t sample;
+        int32_t x;
+
+        // calculate output sample
+        x = phaseFraction >> kPreInterpShift;
+        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);
+        phaseFraction &= kPhaseMask;
+
+        // time to fetch another sample
+        while (indexIncrement--) {
+
+            inputIndex++;
+            if (inputIndex == mBuffer.frameCount) {
+                inputIndex = 0;
+                provider->releaseBuffer(&mBuffer);
+                provider->getNextBuffer(&mBuffer);
+                if (mBuffer.raw == NULL)
+                    goto save_state;  // ugly, but efficient
+                in = mBuffer.i16;
+                // LOGW("New buffer: offset=%p, frames=%d\n", mBuffer.raw, mBuffer.frameCount);
+            }
+
+            // advance sample state
+            advance(&left, in[inputIndex*2]);
+            advance(&right, in[inputIndex*2+1]);
+        }
+    }
+
+save_state:
+    // LOGW("Done: index=%d, fraction=%u", inputIndex, phaseFraction);
+    mInputIndex = inputIndex;
+    mPhaseFraction = phaseFraction;
+}
+
+void AudioResamplerCubic::resampleMono16(int32_t* out, size_t outFrameCount,
+        AudioBufferProvider* provider) {
+
+    int32_t vl = mVolume[0];
+    int32_t vr = mVolume[1];
+
+    size_t inputIndex = mInputIndex;
+    uint32_t phaseFraction = mPhaseFraction;
+    uint32_t phaseIncrement = mPhaseIncrement;
+    size_t outputIndex = 0;
+    size_t outputSampleCount = outFrameCount * 2;
+    
+    // fetch first buffer
+    if (mBuffer.raw == NULL) {
+        provider->getNextBuffer(&mBuffer);
+        if (mBuffer.raw == NULL)
+            return;
+        // LOGW("New buffer: offset=%p, frames=%d\n", mBuffer.raw, mBuffer.frameCount);
+    }
+    int16_t *in = mBuffer.i16;
+
+    while (outputIndex < outputSampleCount) {
+        int32_t sample;
+        int32_t x;
+
+        // calculate output sample
+        x = phaseFraction >> kPreInterpShift;
+        sample = interp(&left, x);
+        out[outputIndex++] += vl * sample;
+        out[outputIndex++] += vr * sample;
+        
+        // increment phase
+        phaseFraction += phaseIncrement;
+        uint32_t indexIncrement = (phaseFraction >> kNumPhaseBits);
+        phaseFraction &= kPhaseMask;
+
+        // time to fetch another sample
+        while (indexIncrement--) {
+
+            inputIndex++;
+            if (inputIndex == mBuffer.frameCount) {
+                inputIndex = 0;
+                provider->releaseBuffer(&mBuffer);
+                provider->getNextBuffer(&mBuffer);
+                if (mBuffer.raw == NULL)
+                    goto save_state;  // ugly, but efficient
+                // LOGW("New buffer: offset=%p, frames=%dn", mBuffer.raw, mBuffer.frameCount);
+                in = mBuffer.i16;
+            }
+
+            // advance sample state
+            advance(&left, in[inputIndex]);
+        }
+    }
+
+save_state:
+    // LOGW("Done: index=%d, fraction=%u", inputIndex, phaseFraction);
+    mInputIndex = inputIndex;
+    mPhaseFraction = phaseFraction;
+}
+
+// ----------------------------------------------------------------------------
+}
+; // namespace android
+
diff --git a/libs/audioflinger/AudioResamplerCubic.h b/libs/audioflinger/AudioResamplerCubic.h
new file mode 100644
index 0000000..b72b62a
--- /dev/null
+++ b/libs/audioflinger/AudioResamplerCubic.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 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
+ *
+ *      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 ANDROID_AUDIO_RESAMPLER_CUBIC_H
+#define ANDROID_AUDIO_RESAMPLER_CUBIC_H
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <cutils/log.h>
+
+#include "AudioResampler.h"
+
+namespace android {
+// ----------------------------------------------------------------------------
+
+class AudioResamplerCubic : public AudioResampler {
+public:
+    AudioResamplerCubic(int bitDepth, int inChannelCount, int32_t sampleRate) :
+        AudioResampler(bitDepth, inChannelCount, sampleRate) {
+    }
+    virtual void resample(int32_t* out, size_t outFrameCount,
+            AudioBufferProvider* provider);
+private:
+    // number of bits used in interpolation multiply - 14 bits avoids overflow
+    static const int kNumInterpBits = 14;
+
+    // bits to shift the phase fraction down to avoid overflow
+    static const int kPreInterpShift = kNumPhaseBits - kNumInterpBits;
+    typedef struct {
+        int32_t a, b, c, y0, y1, y2, y3;
+    } state;
+    void init();
+    void resampleMono16(int32_t* out, size_t outFrameCount,
+            AudioBufferProvider* provider);
+    void resampleStereo16(int32_t* out, size_t outFrameCount,
+            AudioBufferProvider* provider);
+    static inline int32_t interp(state* p, int32_t x) {
+        return (((((p->a * x >> 14) + p->b) * x >> 14) + p->c) * x >> 14) + p->y1;
+    }
+    static inline void advance(state* p, int16_t in) {
+        p->y0 = p->y1;
+        p->y1 = p->y2;
+        p->y2 = p->y3;
+        p->y3 = in;
+        p->a = (3 * (p->y1 - p->y2) - p->y0 + p->y3) >> 1;            
+        p->b = (p->y2 << 1) + p->y0 - (((5 * p->y1 + p->y3)) >> 1);
+        p->c = (p->y2 - p->y0) >> 1;
+    }
+    state left, right;
+};
+
+// ----------------------------------------------------------------------------
+}; // namespace android
+
+#endif /*ANDROID_AUDIO_RESAMPLER_CUBIC_H*/
diff --git a/libs/audioflinger/AudioResamplerSinc.cpp b/libs/audioflinger/AudioResamplerSinc.cpp
new file mode 100644
index 0000000..e710d16
--- /dev/null
+++ b/libs/audioflinger/AudioResamplerSinc.cpp
@@ -0,0 +1,320 @@
+/*
+ * Copyright (C) 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
+ *
+ *      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 <string.h>
+#include "AudioResamplerSinc.h"
+
+namespace android {
+// ----------------------------------------------------------------------------
+
+
+/*
+ * 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. 
+ */
+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
+};
+
+/*
+ * These coefficients are optimized for 48KHz -> 44.1KHz (stop-band at 22.050KHz)
+ * It's possible to use the above coefficient for any down-sampling
+ * at the expense of a slower processing loop (we can interpolate
+ * 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
+};
+
+// ----------------------------------------------------------------------------
+
+static inline 
+int32_t mulRL(int left, int32_t in, uint32_t vRL)
+{
+#if defined(__arm__) && !defined(__thumb__)
+    int32_t out;
+    if (left) {
+        asm( "smultb %[out], %[in], %[vRL] \n"
+             : [out]"=r"(out)
+             : [in]"%r"(in), [vRL]"r"(vRL)
+             : );
+    } else {
+        asm( "smultt %[out], %[in], %[vRL] \n"
+             : [out]"=r"(out)
+             : [in]"%r"(in), [vRL]"r"(vRL)
+             : );
+    }
+    return out;
+#else
+    if (left) {
+        return int16_t(in>>16) * int16_t(vRL&0xFFFF);
+    } else {
+        return int16_t(in>>16) * int16_t(vRL>>16);
+    }
+#endif
+}
+
+static inline 
+int32_t mulAdd(int16_t in, int32_t v, int32_t a)
+{
+#if defined(__arm__) && !defined(__thumb__)
+    int32_t out;
+    asm( "smlawb %[out], %[v], %[in], %[a] \n"
+         : [out]"=r"(out)
+         : [in]"%r"(in), [v]"r"(v), [a]"r"(a)
+         : );
+    return out;
+#else    
+    return a + ((in * int32_t(v))>>16);
+#endif
+}
+
+static inline 
+int32_t mulAddRL(int left, uint32_t inRL, int32_t v, int32_t a)
+{
+#if defined(__arm__) && !defined(__thumb__)
+    int32_t out;
+    if (left) {
+        asm( "smlawb %[out], %[v], %[inRL], %[a] \n"
+             : [out]"=r"(out)
+             : [inRL]"%r"(inRL), [v]"r"(v), [a]"r"(a)
+             : );
+    } else {
+        asm( "smlawt %[out], %[v], %[inRL], %[a] \n"
+             : [out]"=r"(out)
+             : [inRL]"%r"(inRL), [v]"r"(v), [a]"r"(a)
+             : );
+    }
+    return out;
+#else
+    if (left) {
+        return a + ((int16_t(inRL&0xFFFF) * int32_t(v))>>16);
+    } else {
+        return a + ((int16_t(inRL>>16) * int32_t(v))>>16);
+    }
+#endif
+}
+
+// ----------------------------------------------------------------------------
+
+AudioResamplerSinc::AudioResamplerSinc(int bitDepth,
+		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
+	 * 
+	 */
+
+	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;
+}
+
+void AudioResamplerSinc::init() {
+}
+
+void AudioResamplerSinc::resample(int32_t* out, size_t outFrameCount,
+            AudioBufferProvider* provider)
+{
+	mFirCoefs = (mInSampleRate <= mSampleRate) ? mFirCoefsUp : mFirCoefsDown;
+
+	// select the appropriate resampler
+    switch (mChannelCount) {
+    case 1:
+        resample<1>(out, outFrameCount, provider);
+        break;
+    case 2:
+        resample<2>(out, outFrameCount, provider);
+        break;
+    }
+}
+
+
+template<int CHANNELS>
+void AudioResamplerSinc::resample(int32_t* out, size_t outFrameCount,
+        AudioBufferProvider* provider)
+{
+    int16_t* impulse = mImpulse;
+    uint32_t vRL = mVolumeRL;
+    size_t inputIndex = mInputIndex;
+    uint32_t phaseFraction = mPhaseFraction;
+    uint32_t phaseIncrement = mPhaseIncrement;
+    size_t outputIndex = 0;
+    size_t outputSampleCount = outFrameCount * 2;
+
+    AudioBufferProvider::Buffer& buffer(mBuffer);
+    while (outputIndex < outputSampleCount) {
+        // buffer is empty, fetch a new one
+        if (buffer.raw == NULL) {
+            provider->getNextBuffer(&buffer);
+            if (buffer.raw == NULL)
+                break;
+    		const uint32_t phaseIndex = phaseFraction >> kNumPhaseBits;
+        	if (phaseIndex) {
+        		read<CHANNELS>(impulse, phaseFraction, buffer.i16, inputIndex);
+            }
+        }
+        int16_t *in = buffer.i16;
+    	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];
+
+        // handle boundary case
+    	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);
+
+        	phaseFraction += phaseIncrement;
+    		const uint32_t phaseIndex = phaseFraction >> kNumPhaseBits;
+        	if (phaseIndex) {
+        		inputIndex += phaseIndex;
+        		if (inputIndex >= frameCount)
+        			break;
+        		read<CHANNELS>(impulse, phaseFraction, in, inputIndex);
+        	}
+        }
+
+        // if done with buffer, save samples
+        if (inputIndex >= frameCount) {
+            inputIndex -= frameCount;
+            provider->releaseBuffer(&buffer);
+        }
+    }
+
+    mImpulse = impulse;
+    mInputIndex = inputIndex;
+    mPhaseFraction = phaseFraction;
+}
+
+template<int CHANNELS>
+void AudioResamplerSinc::read(
+		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];
+	}
+}
+
+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;
+        interpolate<CHANNELS>(l, r, coefs+indexP, lerpP, sP);
+        interpolate<CHANNELS>(l, r, coefs+indexN, lerpN, sN);
+		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;
+        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 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);
+	}
+}
+
+// ----------------------------------------------------------------------------
+}; // namespace android
+
diff --git a/libs/audioflinger/AudioResamplerSinc.h b/libs/audioflinger/AudioResamplerSinc.h
new file mode 100644
index 0000000..89b9577
--- /dev/null
+++ b/libs/audioflinger/AudioResamplerSinc.h
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 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
+ *
+ *      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 ANDROID_AUDIO_RESAMPLER_SINC_H
+#define ANDROID_AUDIO_RESAMPLER_SINC_H
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <cutils/log.h>
+
+#include "AudioResampler.h"
+
+namespace android {
+// ----------------------------------------------------------------------------
+
+class AudioResamplerSinc : public AudioResampler {
+public:
+	AudioResamplerSinc(int bitDepth, int inChannelCount, int32_t sampleRate);
+
+	~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);
+
+    template<int CHANNELS>
+    inline void filterCoefficient(
+            int32_t& l, int32_t& r, uint32_t phase, int16_t const *samples);
+
+    template<int CHANNELS>
+    inline void interpolate(
+            int32_t& l, int32_t& r,
+            int32_t const* coefs, int16_t lerp, int16_t const* samples);
+
+    template<int CHANNELS>
+    inline void read(int16_t*& impulse, uint32_t& phaseFraction,
+    		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[];
+
+    // ----------------------------------------------------------------------------
+    static const int32_t RESAMPLE_FIR_NUM_COEF       = 8;
+    static const int32_t RESAMPLE_FIR_LERP_INT_BITS  = 4;
+
+    // we have 16 coefs samples per zero-crossing
+    static const int coefsBits = RESAMPLE_FIR_LERP_INT_BITS;
+    static const int cShift = kNumPhaseBits - coefsBits;
+    static const uint32_t cMask  = ((1<<coefsBits)-1) << cShift;
+
+    // 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;
+
+    // number of zero-crossing on each side
+    static const unsigned int halfNumCoefs = RESAMPLE_FIR_NUM_COEF;
+};
+
+// ----------------------------------------------------------------------------
+}; // namespace android
+
+#endif /*ANDROID_AUDIO_RESAMPLER_SINC_H*/