Merge commit 'remotes/korg/cupcake' into merge

Conflicts:
	core/java/android/view/animation/TranslateAnimation.java
	core/jni/Android.mk
	core/res/res/values-en-rGB/strings.xml
	libs/audioflinger/AudioFlinger.cpp
	libs/surfaceflinger/LayerScreenshot.cpp
	packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
diff --git a/libs/audioflinger/AudioFlinger.cpp b/libs/audioflinger/AudioFlinger.cpp
index 918b01f..3c81a47 100644
--- a/libs/audioflinger/AudioFlinger.cpp
+++ b/libs/audioflinger/AudioFlinger.cpp
@@ -47,6 +47,15 @@
 #include "A2dpAudioInterface.h"
 #endif
 
+// ----------------------------------------------------------------------------
+// the sim build doesn't have gettid
+
+#ifndef HAVE_GETTID
+# define gettid getpid
+#endif
+
+// ----------------------------------------------------------------------------
+
 namespace android {
 
 //static const nsecs_t kStandbyTimeInNsecs = seconds(3);
@@ -59,6 +68,16 @@
 static const int8_t kMaxTrackRetries = 50;
 static const int8_t kMaxTrackStartupRetries = 50;
 
+static const int kStartSleepTime = 30000;
+static const int kStopSleepTime = 30000;
+
+static const int kDumpLockRetries = 50;
+static const int kDumpLockSleep = 20000;
+
+// Maximum number of pending buffers allocated by OutputTrack::write()
+static const uint8_t kMaxOutputTrackBuffers = 5;
+
+
 #define AUDIOFLINGER_SECURITY_ENABLED 1
 
 // ----------------------------------------------------------------------------
@@ -98,13 +117,10 @@
 // ----------------------------------------------------------------------------
 
 AudioFlinger::AudioFlinger()
-    : BnAudioFlinger(), Thread(false),
-        mMasterVolume(0), mMasterMute(true), mHardwareAudioMixer(0), mA2dpAudioMixer(0),
-        mAudioMixer(0), mAudioHardware(0), mA2dpAudioInterface(0), mHardwareOutput(0),
-        mA2dpOutput(0), mOutput(0), mRequestedOutput(0), mAudioRecordThread(0),
-        mSampleRate(0), mFrameCount(0), mChannelCount(0), mFormat(0), mMixBuffer(0),
-        mLastWriteTime(0), mNumWrites(0), mNumDelayedWrites(0), mStandby(false),
-        mInWrite(false), mA2dpDisableCount(0), mA2dpSuppressed(false)
+    : BnAudioFlinger(),
+        mAudioHardware(0), mA2dpAudioInterface(0), mA2dpEnabled(false), mNotifyA2dpChange(false),
+        mForcedSpeakerCount(0), mA2dpDisableCount(0), mA2dpSuppressed(false), mForcedRoute(0),
+        mRouteRestoreTime(0), mMusicMuteSaved(false)
 {
     mHardwareStatus = AUDIO_HW_IDLE;
     mAudioHardware = AudioHardwareInterface::create();
@@ -113,57 +129,51 @@
         // open 16-bit output stream for s/w mixer
         mHardwareStatus = AUDIO_HW_OUTPUT_OPEN;
         status_t status;
-        mHardwareOutput = mAudioHardware->openOutputStream(AudioSystem::PCM_16_BIT, 0, 0, &status);
+        AudioStreamOut *hwOutput = mAudioHardware->openOutputStream(AudioSystem::PCM_16_BIT, 0, 0, &status);
         mHardwareStatus = AUDIO_HW_IDLE;
-        if (mHardwareOutput) {
-            mHardwareAudioMixer = new AudioMixer(getOutputFrameCount(mHardwareOutput), mHardwareOutput->sampleRate());
-            mRequestedOutput = mHardwareOutput;
-            doSetOutput(mHardwareOutput);
-
-            // 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;
+        if (hwOutput) {
+            mHardwareMixerThread = new MixerThread(this, hwOutput, AudioSystem::AUDIO_OUTPUT_HARDWARE);
         } else {
-            LOGE("Failed to initialize output stream, status: %d", status);
+            LOGE("Failed to initialize hardware output stream, status: %d", status);
         }
         
 #ifdef WITH_A2DP
         // Create A2DP interface
         mA2dpAudioInterface = new A2dpAudioInterface();
-        mA2dpOutput = mA2dpAudioInterface->openOutputStream(AudioSystem::PCM_16_BIT, 0, 0, &status);       
-        mA2dpAudioMixer = new AudioMixer(getOutputFrameCount(mA2dpOutput), mA2dpOutput->sampleRate());
-
-        // create a buffer big enough for both hardware and A2DP audio output.
-        size_t hwFrameCount = getOutputFrameCount(mHardwareOutput);
-        size_t a2dpFrameCount = getOutputFrameCount(mA2dpOutput);
-        size_t frameCount = (hwFrameCount > a2dpFrameCount ? hwFrameCount : a2dpFrameCount);
-#else
-        size_t frameCount = getOutputFrameCount(mHardwareOutput);
+        AudioStreamOut *a2dpOutput = mA2dpAudioInterface->openOutputStream(AudioSystem::PCM_16_BIT, 0, 0, &status);
+        if (a2dpOutput) {
+            mA2dpMixerThread = new MixerThread(this, a2dpOutput, AudioSystem::AUDIO_OUTPUT_A2DP);
+            if (hwOutput) {  
+                uint32_t frameCount = ((a2dpOutput->bufferSize()/a2dpOutput->frameSize()) * hwOutput->sampleRate()) / a2dpOutput->sampleRate();
+                MixerThread::OutputTrack *a2dpOutTrack = new MixerThread::OutputTrack(mA2dpMixerThread,
+                                                            hwOutput->sampleRate(),
+                                                            AudioSystem::PCM_16_BIT,
+                                                            hwOutput->channelCount(),
+                                                            frameCount);
+                mHardwareMixerThread->setOuputTrack(a2dpOutTrack);                
+            }
+        } else {
+            LOGE("Failed to initialize A2DP output stream, status: %d", status);
+        }
 #endif
-        // FIXME - Current mixer implementation only supports stereo output: Always
-        // Allocate a stereo buffer even if HW output is mono.
-        mMixBuffer = new int16_t[frameCount * 2];
-        memset(mMixBuffer, 0, frameCount * 2 * sizeof(int16_t));
-        
+ 
+        // FIXME - this should come from settings
+        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);
+
+        setMasterVolume(1.0f);
+        setMasterMute(false);
+
         // Start record thread
-        mAudioRecordThread = new AudioRecordThread(mAudioHardware);
+        mAudioRecordThread = new AudioRecordThread(mAudioHardware, this);
         if (mAudioRecordThread != 0) {
             mAudioRecordThread->run("AudioRecordThread", PRIORITY_URGENT_AUDIO);            
         }
      } else {
         LOGE("Couldn't even initialize the stubbed audio hardware!");
     }
-
-    char value[PROPERTY_VALUE_MAX];
-    property_get("ro.audio.silent", value, "0");
-    if (atoi(value)) {
-        LOGD("Silence is golden");
-        mMasterMute = true;
-    }
 }
 
 AudioFlinger::~AudioFlinger()
@@ -172,60 +182,73 @@
         mAudioRecordThread->exit();
         mAudioRecordThread.clear();        
     }
+    mHardwareMixerThread.clear();
     delete mAudioHardware;
     // deleting mA2dpAudioInterface also deletes mA2dpOutput;
+#ifdef WITH_A2DP
+    mA2dpMixerThread.clear();
     delete mA2dpAudioInterface;
-    delete [] mMixBuffer;
-    delete mHardwareAudioMixer;
-    delete mA2dpAudioMixer;
-}
- 
-void AudioFlinger::setOutput(AudioStreamOut* output)
-{
-    mRequestedOutput = output;
+#endif
 }
 
-void AudioFlinger::doSetOutput(AudioStreamOut* output)
-{
-    mSampleRate = output->sampleRate();
-    mChannelCount = output->channelCount();
-
-    // FIXME - Current mixer implementation only supports stereo output
-    if (mChannelCount == 1) {
-        LOGE("Invalid audio hardware channel count");
-    }
-    mFormat = output->format();
-    mFrameCount = getOutputFrameCount(output);
-    mAudioMixer = (output == mA2dpOutput ? mA2dpAudioMixer : mHardwareAudioMixer);
-    mOutput = output;
-}
-
-size_t AudioFlinger::getOutputFrameCount(AudioStreamOut* output) 
-{
-    return output->bufferSize() / output->channelCount() / sizeof(int16_t);
-}
 
 #ifdef WITH_A2DP
-bool AudioFlinger::streamDisablesA2dp(int streamType)
+// setA2dpEnabled_l() must be called with AudioFlinger::mLock held
+void AudioFlinger::setA2dpEnabled_l(bool enable)
 {
-    return (streamType == AudioTrack::SYSTEM ||
-            streamType == AudioTrack::RING ||
-            streamType == AudioTrack::ALARM ||
-            streamType == AudioTrack::NOTIFICATION);
+    SortedVector < sp<MixerThread::Track> > tracks;
+    SortedVector < wp<MixerThread::Track> > activeTracks;
+    
+    LOGV_IF(enable, "set output to A2DP\n");
+    LOGV_IF(!enable, "set output to hardware audio\n");
+
+    // Transfer tracks playing on MUSIC stream from one mixer to the other
+    if (enable) {
+        mHardwareMixerThread->getTracks_l(tracks, activeTracks);
+        mA2dpMixerThread->putTracks_l(tracks, activeTracks);
+    } else {
+        mA2dpMixerThread->getTracks_l(tracks, activeTracks);
+        mHardwareMixerThread->putTracks_l(tracks, activeTracks);
+    }
+    mA2dpEnabled = enable;
+    mNotifyA2dpChange = true;
+    mWaitWorkCV.broadcast();
 }
 
-void AudioFlinger::setA2dpEnabled(bool enable)
+// checkA2dpEnabledChange_l() must be called with AudioFlinger::mLock held
+void AudioFlinger::checkA2dpEnabledChange_l()
 {
-    if (enable) {
-        LOGD("set output to A2DP\n");
-        setOutput(mA2dpOutput);
-    } else {
-        LOGD("set output to hardware audio\n");
-        setOutput(mHardwareOutput);
+    if (mNotifyA2dpChange) {
+        // Notify AudioSystem of the A2DP activation/deactivation
+        size_t size = mNotificationClients.size();
+        for (size_t i = 0; i < size; i++) {
+            sp<IBinder> binder = mNotificationClients.itemAt(i).promote();
+            if (binder != NULL) {
+                LOGV("Notifying output change to client %p", binder.get());
+                sp<IAudioFlingerClient> client = interface_cast<IAudioFlingerClient> (binder);
+                client->a2dpEnabledChanged(mA2dpEnabled);
+            }
+        }
+        mNotifyA2dpChange = false;
     }
 }
 #endif // WITH_A2DP
 
+bool AudioFlinger::streamForcedToSpeaker(int streamType)
+{
+    // NOTE that streams listed here must not be routed to A2DP by default:
+    // AudioSystem::routedToA2dpOutput(streamType) == false
+    return (streamType == AudioSystem::RING ||
+            streamType == AudioSystem::ALARM ||
+            streamType == AudioSystem::NOTIFICATION);
+}
+
+bool AudioFlinger::streamDisablesA2dp(int streamType)
+{
+    return (streamType == AudioSystem::VOICE_CALL ||
+            streamType == AudioSystem::BLUETOOTH_SCO);
+}
+
 status_t AudioFlinger::dumpClients(int fd, const Vector<String16>& args)
 {
     const size_t SIZE = 256;
@@ -247,60 +270,18 @@
     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);
+    int hardwareStatus = mHardwareStatus;
+    
+    if (hardwareStatus == AUDIO_HW_IDLE && mHardwareMixerThread->mStandby) {
+        hardwareStatus = AUDIO_HW_STANDBY;
+    }
+    snprintf(buffer, SIZE, "Hardware status: %d\n", hardwareStatus);
     result.append(buffer);
     write(fd, result.string(), result.size());
     return NO_ERROR;
@@ -325,225 +306,36 @@
     if (checkCallingPermission(String16("android.permission.DUMP")) == false) {
         dumpPermissionDenial(fd, args);
     } else {
-        AutoMutex lock(&mLock);
+        bool locked = false;
+        for (int i = 0; i < kDumpLockRetries; ++i) {
+            if (mLock.tryLock() == NO_ERROR) {
+                locked = true;
+                break;
+            }
+            usleep(kDumpLockSleep);
+        }
 
         dumpClients(fd, args);
-        dumpTracks(fd, args);
         dumpInternals(fd, args);
+        mHardwareMixerThread->dump(fd, args);
+#ifdef WITH_A2DP
+        mA2dpMixerThread->dump(fd, args);
+#endif
+
+        // dump record client
+        if (mAudioRecordThread != 0) mAudioRecordThread->dump(fd, args);
+
         if (mAudioHardware) {
             mAudioHardware->dumpState(fd, args);
         }
+        if (locked) mLock.unlock();
     }
     return NO_ERROR;
 }
 
-// Thread virtuals
-bool AudioFlinger::threadLoop()
-{
-    unsigned long sleepTime = kBufferRecoveryInUsecs;
-    int16_t* curBuf = mMixBuffer;
-    Vector< sp<Track> > tracksToRemove;
-    size_t enabledTracks = 0;
-    nsecs_t standbyTime = systemTime();
-
-    do {
-        enabledTracks = 0;
-        { // scope for the mLock
-        
-            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) {
-                    mOutput->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;
-            }
-
-            // check for change in output
-            if (mRequestedOutput != mOutput) {
-
-                // put current output into standby mode
-                if (mOutput) mOutput->standby();
-
-                // change output
-                doSetOutput(mRequestedOutput);
-            }
-
-            // 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();
-
-                // The first time a track is added we wait
-                // for all its buffers to be filled before processing it
-                mAudioMixer->setActiveTrack(track->name());
-                if (cblk->framesReady() && (track->isReady() || 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
-                    mAudioMixer->setBufferProvider(track);
-                    mAudioMixer->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;
-                    }
-                    mAudioMixer->setParameter(param, AudioMixer::VOLUME0, left);
-                    mAudioMixer->setParameter(param, AudioMixer::VOLUME1, right);
-                    mAudioMixer->setParameter(
-                        AudioMixer::TRACK,
-                        AudioMixer::FORMAT, track->format());
-                    mAudioMixer->setParameter(
-                        AudioMixer::TRACK,
-                        AudioMixer::CHANNEL_COUNT, track->channelCount());
-                    mAudioMixer->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->reset();
-                    }
-                    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());
-                    mAudioMixer->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];
-                    removeActiveTrack(track);
-                    if (track->isTerminated()) {
-                        mTracks.remove(track);
-                        mAudioMixer->deleteTrackName(track->mName);
-                    }
-                }
-            }  
-       }
-        if (LIKELY(enabledTracks)) {
-            // mix buffers...
-            mAudioMixer->process(curBuf);
-
-            // output audio to hardware
-            mLastWriteTime = systemTime();
-            mInWrite = true;
-            size_t mixBufferSize = mFrameCount*mChannelCount*sizeof(int16_t);
-            mOutput->write(curBuf, mixBufferSize);
-            mNumWrites++;
-            mInWrite = false;
-            mStandby = false;
-            nsecs_t temp = systemTime();
-            standbyTime = temp + kStandbyTimeInNsecs;
-            nsecs_t delta = temp - mLastWriteTime;
-            nsecs_t maxPeriod = seconds(mFrameCount) / mSampleRate * 2;
-            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,
@@ -555,34 +347,21 @@
         const sp<IMemory>& sharedBuffer,
         status_t *status)
 {
-    sp<Track> track;
+    sp<MixerThread::Track> track;
     sp<TrackHandle> trackHandle;
     sp<Client> client;
     wp<Client> wclient;
     status_t lStatus;
 
-    if (streamType >= AudioTrack::NUM_STREAM_TYPES) {
+    if (streamType >= AudioSystem::NUM_STREAM_TYPES) {
         LOGE("invalid stream type");
         lStatus = BAD_VALUE;
         goto Exit;
     }
 
-    // Resampler implementation limits input sampling rate to 2 x output sampling rate.
-    if (sampleRate > MAX_SAMPLE_RATE || sampleRate > mSampleRate*2) {
-        LOGE("Sample rate out of range: %d", sampleRate);
-        lStatus = BAD_VALUE;
-        goto Exit;
-    }
-
     {
         Mutex::Autolock _l(mLock);
 
-        if (mSampleRate == 0) {
-            LOGE("Audio driver not initialized.");
-            lStatus = NO_INIT;
-            goto Exit;
-        }
-
         wclient = mClients.valueFor(pid);
 
         if (wclient != NULL) {
@@ -591,13 +370,21 @@
             client = new Client(this, pid);
             mClients.add(pid, client);
         }
-
-        track = new Track(this, client, streamType, sampleRate, format,
-                channelCount, frameCount, sharedBuffer);
-        mTracks.add(track);
+#ifdef WITH_A2DP
+        if (isA2dpEnabled() && AudioSystem::routedToA2dpOutput(streamType)) {
+            track = mA2dpMixerThread->createTrack_l(client, streamType, sampleRate, format,
+                    channelCount, frameCount, sharedBuffer, &lStatus);            
+        } else 
+#endif
+        {
+            track = mHardwareMixerThread->createTrack_l(client, streamType, sampleRate, format,
+                    channelCount, frameCount, sharedBuffer, &lStatus);            
+        }
+    }
+    if (lStatus == NO_ERROR) {
         trackHandle = new TrackHandle(track);
-
-        lStatus = NO_ERROR;
+    } else {
+        track.clear();
     }
 
 Exit:
@@ -607,34 +394,54 @@
     return trackHandle;
 }
 
-uint32_t AudioFlinger::sampleRate() const
+uint32_t AudioFlinger::sampleRate(int output) const
 {
-    return mSampleRate;
+#ifdef WITH_A2DP
+     if (output == AudioSystem::AUDIO_OUTPUT_A2DP) {
+         return mA2dpMixerThread->sampleRate();
+     }
+#endif
+     return mHardwareMixerThread->sampleRate();
 }
 
-int AudioFlinger::channelCount() const
+int AudioFlinger::channelCount(int output) const
 {
-    return mChannelCount;
+#ifdef WITH_A2DP
+     if (output == AudioSystem::AUDIO_OUTPUT_A2DP) {
+         return mA2dpMixerThread->channelCount();
+     }
+#endif
+     return mHardwareMixerThread->channelCount();
 }
 
-int AudioFlinger::format() const
+int AudioFlinger::format(int output) const
 {
-    return mFormat;
+#ifdef WITH_A2DP
+     if (output == AudioSystem::AUDIO_OUTPUT_A2DP) {
+         return mA2dpMixerThread->format();
+     }
+#endif
+     return mHardwareMixerThread->format();
 }
 
-size_t AudioFlinger::frameCount() const
+size_t AudioFlinger::frameCount(int output) const
 {
-    return mFrameCount;
+#ifdef WITH_A2DP
+     if (output == AudioSystem::AUDIO_OUTPUT_A2DP) {
+         return mA2dpMixerThread->frameCount();
+     }
+#endif
+     return mHardwareMixerThread->frameCount();
 }
 
-uint32_t AudioFlinger::latency() const
+uint32_t AudioFlinger::latency(int output) const
 {
-    if (mOutput) {
-        return mOutput->latency();
-    }
-    else {
-        return 0;
-    }
+#ifdef WITH_A2DP
+     if (output == AudioSystem::AUDIO_OUTPUT_A2DP) {
+         return mA2dpMixerThread->latency();
+     }
+#endif
+     return mHardwareMixerThread->latency();
 }
 
 status_t AudioFlinger::setMasterVolume(float value)
@@ -648,12 +455,14 @@
     AutoMutex lock(mHardwareLock);
     mHardwareStatus = AUDIO_HW_SET_MASTER_VOLUME;
     if (mAudioHardware->setMasterVolume(value) == NO_ERROR) {
-        mMasterVolume = 1.0f;
-    }
-    else {
-        mMasterVolume = value;
+        value = 1.0f;
     }
     mHardwareStatus = AUDIO_HW_IDLE;
+    mHardwareMixerThread->setMasterVolume(value);
+#ifdef WITH_A2DP
+    mA2dpMixerThread->setMasterVolume(value);
+#endif
+
     return NO_ERROR;
 }
 
@@ -671,20 +480,21 @@
     }
 
 #ifdef WITH_A2DP
-    LOGD("setRouting %d %d %d\n", mode, routes, mask);
+    LOGD("setRouting %d %d %d, tid %d, calling tid %d\n", mode, routes, mask, gettid(), IPCThreadState::self()->getCallingPid());
     if (mode == AudioSystem::MODE_NORMAL && 
             (mask & AudioSystem::ROUTE_BLUETOOTH_A2DP)) {
         AutoMutex lock(&mLock);
 
         bool enableA2dp = false;
         if (routes & AudioSystem::ROUTE_BLUETOOTH_A2DP) {
-            if (mA2dpDisableCount > 0)
-                mA2dpSuppressed = true;
-            else
-                enableA2dp = true;
+            enableA2dp = true;
         }
-        setA2dpEnabled(enableA2dp);
-        LOGD("setOutput done\n");
+        if (mA2dpDisableCount > 0) {
+            mA2dpSuppressed = enableA2dp;
+        } else {
+            setA2dpEnabled_l(enableA2dp);
+        }
+        LOGV("setOutput done\n");
     }
 #endif
 
@@ -697,6 +507,12 @@
         err = mAudioHardware->getRouting(mode, &r);
         if (err == NO_ERROR) {
             r = (r & ~mask) | (routes & mask);
+            if (mode == AudioSystem::MODE_NORMAL || 
+                (mode == AudioSystem::MODE_CURRENT && getMode() == AudioSystem::MODE_NORMAL)) {
+                mSavedRoute = r;
+                r |= mForcedRoute;
+                LOGV("setRouting mSavedRoute %08x mForcedRoute %08x\n", mSavedRoute, mForcedRoute);
+            }
             mHardwareStatus = AUDIO_HW_SET_ROUTING;
             err = mAudioHardware->setRouting(mode, r);
         }
@@ -709,9 +525,14 @@
 {
     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;
+        if (mode == AudioSystem::MODE_NORMAL || 
+            (mode == AudioSystem::MODE_CURRENT && getMode() == AudioSystem::MODE_NORMAL)) {
+            routes = mSavedRoute;                
+        } else {
+            mHardwareStatus = AUDIO_HW_GET_ROUTING;
+            mAudioHardware->getRouting(mode, &routes);
+            mHardwareStatus = AUDIO_HW_IDLE;
+        }
     } else {
         LOGW("Illegal value: getRouting(%d)", mode);
     }
@@ -774,19 +595,21 @@
     if (!settingsAllowed()) {
         return PERMISSION_DENIED;
     }
-
-    mMasterMute = muted;
+    mHardwareMixerThread->setMasterMute(muted);
+#ifdef WITH_A2DP
+    mA2dpMixerThread->setMasterMute(muted);
+#endif
     return NO_ERROR;
 }
 
 float AudioFlinger::masterVolume() const
 {
-    return mMasterVolume;
+    return mHardwareMixerThread->masterVolume();
 }
 
 bool AudioFlinger::masterMute() const
 {
-    return mMasterMute;
+    return mHardwareMixerThread->masterMute();
 }
 
 status_t AudioFlinger::setStreamVolume(int stream, float value)
@@ -796,26 +619,40 @@
         return PERMISSION_DENIED;
     }
 
-    if (uint32_t(stream) >= AudioTrack::NUM_STREAM_TYPES) {
+    if (uint32_t(stream) >= AudioSystem::NUM_STREAM_TYPES) {
         return BAD_VALUE;
     }
 
     status_t ret = NO_ERROR;
-    if (stream == AudioTrack::VOICE_CALL) {
+    
+    if (stream == AudioSystem::VOICE_CALL ||
+        stream == AudioSystem::BLUETOOTH_SCO) {
+        float hwValue = value;
+        if (stream == AudioSystem::VOICE_CALL) {
+            hwValue = (float)AudioSystem::logToLinear(value)/100.0f;
+            // FIXME: This is a temporary fix to re-base the internally
+            // generated in-call audio so that it is never muted, which is
+            // already the case for the hardware routed in-call audio.
+            // When audio stream handling is reworked, this should be
+            // addressed more cleanly.  Fixes #1324; see discussion at
+            // http://review.source.android.com/8224
+            value = value * 0.99 + 0.01;        
+        } else { // (type == AudioSystem::BLUETOOTH_SCO)
+            hwValue = 1.0f;
+        }
+
         AutoMutex lock(mHardwareLock);
         mHardwareStatus = AUDIO_SET_VOICE_VOLUME;
-        ret = mAudioHardware->setVoiceVolume(value);
+        ret = mAudioHardware->setVoiceVolume(hwValue);
         mHardwareStatus = AUDIO_HW_IDLE;
-        // FIXME: This is a temporary fix to re-base the internally
-        // generated in-call audio so that it is never muted, which is
-        // already the case for the hardware routed in-call audio.
-        // When audio stream handling is reworked, this should be
-        // addressed more cleanly.  Fixes #1324; see discussion at
-        // http://review.source.android.com/8224
-        mStreamTypes[stream].volume = value * (1.0 - 1.0 / 6.0) + (1.0 / 6.0);
-    } else {
-        mStreamTypes[stream].volume = value;
+        
     }
+    
+    mHardwareMixerThread->setStreamVolume(stream, value);
+#ifdef WITH_A2DP
+    mA2dpMixerThread->setStreamVolume(stream, value);
+#endif
+
     return ret;
 }
 
@@ -826,45 +663,66 @@
         return PERMISSION_DENIED;
     }
 
-    if (uint32_t(stream) >= AudioTrack::NUM_STREAM_TYPES) {
+    if (uint32_t(stream) >= AudioSystem::NUM_STREAM_TYPES) {
         return BAD_VALUE;
     }
-    mStreamTypes[stream].mute = muted;
+    
+#ifdef WITH_A2DP
+    mA2dpMixerThread->setStreamMute(stream, muted);
+#endif
+    if (stream == AudioSystem::MUSIC) 
+    {
+        AutoMutex lock(&mHardwareLock);
+        if (mForcedRoute != 0)
+            mMusicMuteSaved = muted;
+        else
+            mHardwareMixerThread->setStreamMute(stream, muted);
+    } else {
+        mHardwareMixerThread->setStreamMute(stream, muted);
+    }
+
+    
+
     return NO_ERROR;
 }
 
 float AudioFlinger::streamVolume(int stream) const
 {
-    if (uint32_t(stream) >= AudioTrack::NUM_STREAM_TYPES) {
+    if (uint32_t(stream) >= AudioSystem::NUM_STREAM_TYPES) {
         return 0.0f;
     }
-    if (stream == AudioTrack::VOICE_CALL) {
+    float value = mHardwareMixerThread->streamVolume(stream);
+    
+    if (stream == AudioSystem::VOICE_CALL) {
         // FIXME: Re-base internally generated in-call audio,
         // reverse of above in setStreamVolume.
-        return (mStreamTypes[stream].volume - (1.0 / 6.0)) / (1.0 - 1.0 / 6.0);
+        value = (value - 0.01) / 0.99;
     }
-    return mStreamTypes[stream].volume;
+    
+    return value;
 }
 
 bool AudioFlinger::streamMute(int stream) const
 {
-    if (uint32_t(stream) >= AudioTrack::NUM_STREAM_TYPES) {
+    if (uint32_t(stream) >= AudioSystem::NUM_STREAM_TYPES) {
         return true;
     }
-    return mStreamTypes[stream].mute;
+    
+    if (stream == AudioSystem::MUSIC && mForcedRoute != 0) 
+    {
+        return mMusicMuteSaved;
+    }
+    return mHardwareMixerThread->streamMute(stream);
 }
 
 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;
+ #ifdef WITH_A2DP
+     if (isA2dpEnabled()) {
+         return mA2dpMixerThread->isMusicActive();
+     }
+ #endif
+    return mHardwareMixerThread->isMusicActive();
 }
 
 status_t AudioFlinger::setParameter(const char* key, const char* value)
@@ -872,6 +730,8 @@
     status_t result, result2;
     AutoMutex lock(mHardwareLock);
     mHardwareStatus = AUDIO_SET_PARAMETER;
+    
+    LOGV("setParameter() key %s, value %s, tid %d, calling tid %d", key, value, gettid(), IPCThreadState::self()->getCallingPid());
     result = mAudioHardware->setParameter(key, value);
     if (mA2dpAudioInterface) {
         result2 = mA2dpAudioInterface->setParameter(key, value);
@@ -882,15 +742,716 @@
     return result;
 }
 
+size_t AudioFlinger::getInputBufferSize(uint32_t sampleRate, int format, int channelCount)
+{
+    return mAudioHardware->getInputBufferSize(sampleRate, format, channelCount);
+}
+
+void AudioFlinger::registerClient(const sp<IAudioFlingerClient>& client)
+{
+    
+    LOGV("registerClient() %p, tid %d, calling tid %d", client.get(), gettid(), IPCThreadState::self()->getCallingPid());
+    Mutex::Autolock _l(mLock);
+
+    sp<IBinder> binder = client->asBinder();
+    if (mNotificationClients.indexOf(binder) < 0) {
+        LOGV("Adding notification client %p", binder.get());
+        binder->linkToDeath(this);
+        mNotificationClients.add(binder);
+        client->a2dpEnabledChanged(isA2dpEnabled());
+    }
+}
+
+void AudioFlinger::binderDied(const wp<IBinder>& who) {
+    
+    LOGV("binderDied() %p, tid %d, calling tid %d", who.unsafe_get(), gettid(), IPCThreadState::self()->getCallingPid());
+    Mutex::Autolock _l(mLock);
+
+    IBinder *binder = who.unsafe_get();
+
+    if (binder != NULL) {
+        int index = mNotificationClients.indexOf(binder);
+        if (index >= 0) {
+            LOGV("Removing notification client %p", binder);
+            mNotificationClients.removeAt(index);
+        }
+    }
+}
+
 void AudioFlinger::removeClient(pid_t pid)
 {
+    LOGV("removeClient() pid %d, tid %d, calling tid %d", pid, gettid(), IPCThreadState::self()->getCallingPid());
     Mutex::Autolock _l(mLock);
     mClients.removeItem(pid);
 }
 
-status_t AudioFlinger::addTrack(const sp<Track>& track)
+bool AudioFlinger::isA2dpEnabled() const
 {
-    Mutex::Autolock _l(mLock);
+    return mA2dpEnabled;
+}
+
+void AudioFlinger::handleForcedSpeakerRoute(int command)
+{
+    switch(command) {
+    case ACTIVE_TRACK_ADDED:
+        {
+            AutoMutex lock(mHardwareLock);
+            if (mForcedSpeakerCount++ == 0) {
+                mRouteRestoreTime = 0;
+                mMusicMuteSaved = mHardwareMixerThread->streamMute(AudioSystem::MUSIC);
+                if (mForcedRoute == 0 && !(mSavedRoute & AudioSystem::ROUTE_SPEAKER)) {
+                    LOGV("Route forced to Speaker ON %08x", mSavedRoute | AudioSystem::ROUTE_SPEAKER);
+                    mHardwareMixerThread->setStreamMute(AudioSystem::MUSIC, true);
+                    mHardwareStatus = AUDIO_HW_SET_MASTER_VOLUME;
+                    mAudioHardware->setMasterVolume(0);
+                    usleep(mHardwareMixerThread->latency()*1000);
+                    mHardwareStatus = AUDIO_HW_SET_ROUTING;
+                    mAudioHardware->setRouting(AudioSystem::MODE_NORMAL, mSavedRoute | AudioSystem::ROUTE_SPEAKER);
+                    mHardwareStatus = AUDIO_HW_IDLE;
+                    // delay track start so that audio hardware has time to siwtch routes
+                    usleep(kStartSleepTime);
+                    mHardwareStatus = AUDIO_HW_SET_MASTER_VOLUME;
+                    mAudioHardware->setMasterVolume(mHardwareMixerThread->masterVolume());
+                    mHardwareStatus = AUDIO_HW_IDLE;
+                }
+                mForcedRoute = AudioSystem::ROUTE_SPEAKER;
+            }
+            LOGV("mForcedSpeakerCount incremented to %d", mForcedSpeakerCount);
+        }
+        break;
+    case ACTIVE_TRACK_REMOVED:
+        {
+            AutoMutex lock(mHardwareLock);
+            if (mForcedSpeakerCount > 0){
+                if (--mForcedSpeakerCount == 0) {
+                    mRouteRestoreTime = systemTime() + milliseconds(kStopSleepTime/1000);
+                }
+                LOGV("mForcedSpeakerCount decremented to %d", mForcedSpeakerCount);
+            } else {
+                LOGE("mForcedSpeakerCount is already zero");
+            }
+        }
+        break;
+    case CHECK_ROUTE_RESTORE_TIME:
+    case FORCE_ROUTE_RESTORE:
+        if (mRouteRestoreTime) {
+            AutoMutex lock(mHardwareLock);
+            if (mRouteRestoreTime && 
+               (systemTime() > mRouteRestoreTime || command == FORCE_ROUTE_RESTORE)) {
+                mHardwareMixerThread->setStreamMute(AudioSystem::MUSIC, mMusicMuteSaved);
+                mForcedRoute = 0;
+                if (!(mSavedRoute & AudioSystem::ROUTE_SPEAKER)) {
+                    mHardwareStatus = AUDIO_HW_SET_ROUTING;
+                    mAudioHardware->setRouting(AudioSystem::MODE_NORMAL, mSavedRoute);
+                    mHardwareStatus = AUDIO_HW_IDLE;
+                    LOGV("Route forced to Speaker OFF %08x", mSavedRoute);
+                }
+                mRouteRestoreTime = 0;
+            }
+        }
+        break;
+    }
+}
+
+#ifdef WITH_A2DP
+// handleStreamDisablesA2dp_l() must be called with AudioFlinger::mLock held
+void AudioFlinger::handleStreamDisablesA2dp_l(int command)
+{
+    switch(command) {
+    case ACTIVE_TRACK_ADDED:
+        {
+            if (mA2dpDisableCount++ == 0) {
+                if (mA2dpEnabled) {
+                    setA2dpEnabled_l(false);
+                    mA2dpSuppressed = true;
+                }
+            }
+            LOGV("mA2dpDisableCount incremented to %d", mA2dpDisableCount);
+        }
+        break;
+    case ACTIVE_TRACK_REMOVED:
+        {
+            if (mA2dpDisableCount > 0) {
+                if (--mA2dpDisableCount == 0) {
+                    if (mA2dpSuppressed) {
+                        setA2dpEnabled_l(true);
+                        mA2dpSuppressed = false;
+                    }
+                }
+                LOGV("mA2dpDisableCount decremented to %d", mA2dpDisableCount);
+            } else {
+                LOGE("mA2dpDisableCount is already zero");
+            }
+        }
+        break;
+    }
+}
+#endif
+
+// ----------------------------------------------------------------------------
+
+AudioFlinger::MixerThread::MixerThread(const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output, int outputType)
+    :   Thread(false),
+        mAudioFlinger(audioFlinger), mAudioMixer(0), mOutput(output), mOutputType(outputType), 
+        mSampleRate(0), mFrameCount(0), mChannelCount(0), mFormat(0), mMixBuffer(0),
+        mLastWriteTime(0), mNumWrites(0), mNumDelayedWrites(0), mStandby(false),
+        mInWrite(false)
+{
+    mSampleRate = output->sampleRate();
+    mChannelCount = output->channelCount();
+
+    // FIXME - Current mixer implementation only supports stereo output
+    if (mChannelCount == 1) {
+        LOGE("Invalid audio hardware channel count");
+    }
+
+    mFormat = output->format();
+    mFrameCount = output->bufferSize() / output->channelCount() / sizeof(int16_t);
+    mAudioMixer = new AudioMixer(mFrameCount, output->sampleRate());
+
+    // FIXME - Current mixer implementation only supports stereo output: Always
+    // Allocate a stereo buffer even if HW output is mono.
+    mMixBuffer = new int16_t[mFrameCount * 2];
+    memset(mMixBuffer, 0, mFrameCount * 2 * sizeof(int16_t));
+}
+
+AudioFlinger::MixerThread::~MixerThread()
+{
+    delete [] mMixBuffer;
+    delete mAudioMixer;
+}
+
+status_t AudioFlinger::MixerThread::dump(int fd, const Vector<String16>& args)
+{
+    dumpInternals(fd, args);
+    dumpTracks(fd, args);
+    return NO_ERROR;
+}
+
+status_t AudioFlinger::MixerThread::dumpTracks(int fd, const Vector<String16>& args)
+{
+    const size_t SIZE = 256;
+    char buffer[SIZE];
+    String8 result;
+
+    snprintf(buffer, SIZE, "Output %d mixer thread tracks\n", mOutputType);
+    result.append(buffer);
+    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);
+            }
+        }
+    }
+
+    snprintf(buffer, SIZE, "Output %d mixer thread active tracks\n", mOutputType);
+    result.append(buffer);
+    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::MixerThread::dumpInternals(int fd, const Vector<String16>& args)
+{
+    const size_t SIZE = 256;
+    char buffer[SIZE];
+    String8 result;
+
+    snprintf(buffer, SIZE, "Output %d mixer thread internals\n", mOutputType);
+    result.append(buffer);
+    snprintf(buffer, SIZE, "AudioMixer tracks: %08x\n", mAudioMixer->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);
+    write(fd, result.string(), result.size());
+    return NO_ERROR;
+}
+
+// Thread virtuals
+bool AudioFlinger::MixerThread::threadLoop()
+{
+    unsigned long sleepTime = kBufferRecoveryInUsecs;
+    int16_t* curBuf = mMixBuffer;
+    Vector< sp<Track> > tracksToRemove;
+    size_t enabledTracks = 0;
+    nsecs_t standbyTime = systemTime();   
+    size_t mixBufferSize = mFrameCount*mChannelCount*sizeof(int16_t);
+    nsecs_t maxPeriod = seconds(mFrameCount) / mSampleRate * 2;
+
+#ifdef WITH_A2DP
+    bool outputTrackActive = false;
+#endif
+
+    do {
+        enabledTracks = 0;
+        { // scope for the AudioFlinger::mLock
+        
+            Mutex::Autolock _l(mAudioFlinger->mLock);
+
+#ifdef WITH_A2DP
+            if (mOutputTrack != NULL && !mAudioFlinger->isA2dpEnabled()) {
+                if (outputTrackActive) {
+                    mAudioFlinger->mLock.unlock();
+                    mOutputTrack->stop();
+                    mAudioFlinger->mLock.lock();
+                    outputTrackActive = false;
+                }
+            }
+            mAudioFlinger->checkA2dpEnabledChange_l();
+#endif
+
+            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, output %d\n", mOutputType);
+                if (!mStandby) {
+                    mOutput->standby();
+                    mStandby = true;
+                }
+                
+#ifdef WITH_A2DP
+                if (outputTrackActive) {
+                    mAudioFlinger->mLock.unlock();
+                    mOutputTrack->stop();
+                    mAudioFlinger->mLock.lock();
+                    outputTrackActive = false;
+                }
+#endif
+                if (mOutputType == AudioSystem::AUDIO_OUTPUT_HARDWARE) {
+                    mAudioFlinger->handleForcedSpeakerRoute(FORCE_ROUTE_RESTORE);
+                }                
+                // we're about to wait, flush the binder command buffer
+                IPCThreadState::self()->flushCommands();
+                mAudioFlinger->mWaitWorkCV.wait(mAudioFlinger->mLock);
+                LOGV("Audio hardware exiting standby, output %d\n", mOutputType);
+                
+                if (mMasterMute == false) {
+                    char value[PROPERTY_VALUE_MAX];
+                    property_get("ro.audio.silent", value, "0");
+                    if (atoi(value)) {
+                        LOGD("Silence is golden");
+                        setMasterMute(true);
+                    }                    
+                }
+                
+                standbyTime = systemTime() + kStandbyTimeInNsecs;
+                continue;
+            }
+
+            // Forced route to speaker is handled by hardware mixer thread
+            if (mOutputType == AudioSystem::AUDIO_OUTPUT_HARDWARE) {
+                mAudioFlinger->handleForcedSpeakerRoute(CHECK_ROUTE_RESTORE_TIME);
+            }
+
+            // 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();
+
+                // The first time a track is added we wait
+                // for all its buffers to be filled before processing it
+                mAudioMixer->setActiveTrack(track->name());
+                if (cblk->framesReady() && (track->isReady() || track->isStopped()) &&
+                        !track->isPaused())
+                {
+                    //LOGV("track %d u=%08x, s=%08x [OK]", track->name(), cblk->user, cblk->server);
+
+                    // 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
+                    mAudioMixer->setBufferProvider(track);
+                    mAudioMixer->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;
+                    }
+                    mAudioMixer->setParameter(param, AudioMixer::VOLUME0, left);
+                    mAudioMixer->setParameter(param, AudioMixer::VOLUME1, right);
+                    mAudioMixer->setParameter(
+                        AudioMixer::TRACK,
+                        AudioMixer::FORMAT, track->format());
+                    mAudioMixer->setParameter(
+                        AudioMixer::TRACK,
+                        AudioMixer::CHANNEL_COUNT, track->channelCount());
+                    mAudioMixer->setParameter(
+                        AudioMixer::RESAMPLE,
+                        AudioMixer::SAMPLE_RATE,
+                        int(cblk->sampleRate));
+
+                    // reset retry count
+                    track->mRetryCount = kMaxTrackRetries;
+                    enabledTracks++;
+                } else {
+                    //LOGV("track %d u=%08x, s=%08x [NOT READY]", track->name(), cblk->user, cblk->server);
+                    if (track->isStopped()) {
+                        track->reset();
+                    }
+                    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());
+                    mAudioMixer->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];
+                    removeActiveTrack_l(track);
+                    if (track->isTerminated()) {
+                        mTracks.remove(track);
+                        deleteTrackName_l(track->mName);
+                    }
+                }
+            }
+       }
+        
+        if (LIKELY(enabledTracks)) {
+            // mix buffers...
+            mAudioMixer->process(curBuf);
+
+#ifdef WITH_A2DP
+            if (mOutputTrack != NULL && mAudioFlinger->isA2dpEnabled()) {
+                if (!outputTrackActive) {
+                    LOGV("starting output track in mixer for output %d", mOutputType);
+                    mOutputTrack->start();
+                    outputTrackActive = true;
+                }
+                mOutputTrack->write(curBuf, mFrameCount);
+            }
+#endif
+
+            // 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 {         
+#ifdef WITH_A2DP
+            if (mOutputTrack != NULL && mAudioFlinger->isA2dpEnabled()) {
+                if (outputTrackActive) {
+                    mOutputTrack->write(curBuf, 0);
+                    if (mOutputTrack->bufferQueueEmpty()) {
+                        mOutputTrack->stop();
+                        outputTrackActive = false;
+                    } else {
+                        standbyTime = systemTime() + kStandbyTimeInNsecs;
+                    }
+                }
+            }
+#endif
+            // 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::MixerThread::readyToRun()
+{
+    if (mSampleRate == 0) {
+        LOGE("No working audio driver found.");
+        return NO_INIT;
+    }
+    LOGI("AudioFlinger's thread ready to run for output %d", mOutputType);
+    return NO_ERROR;
+}
+
+void AudioFlinger::MixerThread::onFirstRef()
+{
+    const size_t SIZE = 256;
+    char buffer[SIZE];
+
+    snprintf(buffer, SIZE, "Mixer Thread for output %d", mOutputType);
+
+    run(buffer, ANDROID_PRIORITY_URGENT_AUDIO);
+}
+
+// MixerThread::createTrack_l() must be called with AudioFlinger::mLock held
+sp<AudioFlinger::MixerThread::Track>  AudioFlinger::MixerThread::createTrack_l(
+        const sp<AudioFlinger::Client>& client,
+        int streamType,
+        uint32_t sampleRate,
+        int format,
+        int channelCount,
+        int frameCount,
+        const sp<IMemory>& sharedBuffer,
+        status_t *status)
+{
+    sp<Track> track;
+    status_t lStatus;
+    
+    // Resampler implementation limits input sampling rate to 2 x output sampling rate.
+    if (sampleRate > MAX_SAMPLE_RATE || sampleRate > mSampleRate*2) {
+        LOGE("Sample rate out of range: %d mSampleRate %d", sampleRate, mSampleRate);
+        lStatus = BAD_VALUE;
+        goto Exit;
+    }
+
+
+    if (mSampleRate == 0) {
+        LOGE("Audio driver not initialized.");
+        lStatus = NO_INIT;
+        goto Exit;
+    }
+
+    track = new Track(this, client, streamType, sampleRate, format,
+            channelCount, frameCount, sharedBuffer);
+    if (track->getCblk() == NULL) {
+        lStatus = NO_MEMORY;
+        goto Exit;
+    }
+    mTracks.add(track);
+    lStatus = NO_ERROR;
+
+Exit:
+    if(status) {
+        *status = lStatus;
+    }
+    return track;
+}
+
+// getTracks_l() must be called with AudioFlinger::mLock held
+void AudioFlinger::MixerThread::getTracks_l(
+        SortedVector < sp<Track> >& tracks,
+        SortedVector < wp<Track> >& activeTracks)
+{
+    size_t size = mTracks.size();
+    LOGV ("MixerThread::getTracks_l() for output %d, mTracks.size %d, mActiveTracks.size %d", mOutputType,  mTracks.size(), mActiveTracks.size());
+    for (size_t i = 0; i < size; i++) {
+        sp<Track> t = mTracks[i];
+        if (AudioSystem::routedToA2dpOutput(t->mStreamType)) {
+            tracks.add(t);
+            int j = mActiveTracks.indexOf(t);
+            if (j >= 0) {
+                t = mActiveTracks[j].promote();
+                if (t != NULL) {
+                    activeTracks.add(t);                                    
+                }                            
+            }
+        }
+    }
+
+    size = activeTracks.size();
+    for (size_t i = 0; i < size; i++) {
+        removeActiveTrack_l(activeTracks[i]);
+    }
+    
+    size = tracks.size();
+    for (size_t i = 0; i < size; i++) {
+        sp<Track> t = tracks[i];
+        mTracks.remove(t);
+        deleteTrackName_l(t->name());
+    }
+}
+
+// putTracks_l() must be called with AudioFlinger::mLock held
+void AudioFlinger::MixerThread::putTracks_l(
+        SortedVector < sp<Track> >& tracks,
+        SortedVector < wp<Track> >& activeTracks)
+{
+
+    LOGV ("MixerThread::putTracks_l() for output %d, tracks.size %d, activeTracks.size %d", mOutputType,  tracks.size(), activeTracks.size());
+
+    size_t size = tracks.size();
+    for (size_t i = 0; i < size ; i++) {
+        sp<Track> t = tracks[i];
+        int name = getTrackName_l();
+
+        if (name < 0) return;
+        
+        t->mName = name;
+        t->mMixerThread = this;
+        mTracks.add(t);
+
+        int j = activeTracks.indexOf(t);
+        if (j >= 0) {
+            addActiveTrack_l(t);
+        }            
+    }
+}
+
+uint32_t AudioFlinger::MixerThread::sampleRate() const
+{
+    return mSampleRate;
+}
+
+int AudioFlinger::MixerThread::channelCount() const
+{
+    return mChannelCount;
+}
+
+int AudioFlinger::MixerThread::format() const
+{
+    return mFormat;
+}
+
+size_t AudioFlinger::MixerThread::frameCount() const
+{
+    return mFrameCount;
+}
+
+uint32_t AudioFlinger::MixerThread::latency() const
+{
+    if (mOutput) {
+        return mOutput->latency();
+    }
+    else {
+        return 0;
+    }
+}
+
+status_t AudioFlinger::MixerThread::setMasterVolume(float value)
+{
+    mMasterVolume = value;
+    return NO_ERROR;
+}
+
+status_t AudioFlinger::MixerThread::setMasterMute(bool muted)
+{
+    mMasterMute = muted;
+    return NO_ERROR;
+}
+
+float AudioFlinger::MixerThread::masterVolume() const
+{
+    return mMasterVolume;
+}
+
+bool AudioFlinger::MixerThread::masterMute() const
+{
+    return mMasterMute;
+}
+
+status_t AudioFlinger::MixerThread::setStreamVolume(int stream, float value)
+{
+    mStreamTypes[stream].volume = value;
+    return NO_ERROR;
+}
+
+status_t AudioFlinger::MixerThread::setStreamMute(int stream, bool muted)
+{
+    mStreamTypes[stream].mute = muted;
+    return NO_ERROR;
+}
+
+float AudioFlinger::MixerThread::streamVolume(int stream) const
+{
+    return mStreamTypes[stream].volume;
+}
+
+bool AudioFlinger::MixerThread::streamMute(int stream) const
+{
+    return mStreamTypes[stream].mute;
+}
+
+bool AudioFlinger::MixerThread::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 == AudioSystem::MUSIC)
+            return true;
+    }
+    return false;
+}
+
+// addTrack_l() must be called with AudioFlinger::mLock held
+status_t AudioFlinger::MixerThread::addTrack_l(const sp<Track>& track)
+{
+    status_t status = ALREADY_EXISTS;
 
     // here the track could be either new, or restarted
     // in both cases "unstop" the track
@@ -903,139 +1464,135 @@
     }
     // 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;
         track->mResetDone = false;
-        addActiveTrack(track);
-        return NO_ERROR;
+        addActiveTrack_l(track);
+        status = NO_ERROR;
     }
-    return ALREADY_EXISTS;
+    
+    LOGV("mWaitWorkCV.broadcast");
+    mAudioFlinger->mWaitWorkCV.broadcast();
+
+    return status;
 }
 
-void AudioFlinger::removeTrack(wp<Track> track, int name)
+// removeTrack_l() must be called with AudioFlinger::mLock held
+void AudioFlinger::MixerThread::removeTrack_l(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();
+        deleteTrackName_l(name);
+        removeActiveTrack_l(track);
+        mAudioFlinger->mWaitWorkCV.broadcast();
     }
-    audioMixer()->deleteTrackName(name);
-    removeActiveTrack(track);
-    mWaitWorkCV.broadcast();
 }
 
-void AudioFlinger::destroyTrack(const sp<Track>& track)
+// destroyTrack_l() must be called with AudioFlinger::mLock held
+void AudioFlinger::MixerThread::destroyTrack_l(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());
+        deleteTrackName_l(track->name());
     }
 }
 
-void AudioFlinger::addActiveTrack(const wp<Track>& t)
+// addActiveTrack_l() must be called with AudioFlinger::mLock held
+void AudioFlinger::MixerThread::addActiveTrack_l(const wp<Track>& t)
 {
     mActiveTracks.add(t);
 
+    // Force routing to speaker for certain stream types
+    // The forced routing to speaker is managed by hardware mixer
+    if (mOutputType == AudioSystem::AUDIO_OUTPUT_HARDWARE) {
+        sp<Track> track = t.promote();
+        if (track == NULL) return;
+   
+        if (streamForcedToSpeaker(track->type())) {
+            mAudioFlinger->handleForcedSpeakerRoute(ACTIVE_TRACK_ADDED);
+        }        
 #ifdef WITH_A2DP
-    // disable A2DP for certain stream types
-    sp<Track> track = t.promote();
-    if (streamDisablesA2dp(track->type())) {
-        if (mA2dpDisableCount++ == 0 && isA2dpEnabled()) {
-            setA2dpEnabled(false);
-            mA2dpSuppressed = true;
-            LOGD("mA2dpSuppressed = true\n");
+        // AudioFlinger::mLock must be locked before calling
+        // handleStreamDisablesA2dp_l because it calls setA2dpEnabled_l().
+        if (streamDisablesA2dp(track->type())) {
+            mAudioFlinger->handleStreamDisablesA2dp_l(ACTIVE_TRACK_ADDED);
         }
-        LOGD("mA2dpDisableCount incremented to %d\n", mA2dpDisableCount);
-    }
 #endif
+    }
 }
 
-void AudioFlinger::removeActiveTrack(const wp<Track>& t)
+// removeActiveTrack_l() must be called with AudioFlinger::mLock held
+void AudioFlinger::MixerThread::removeActiveTrack_l(const wp<Track>& t)
 {
     mActiveTracks.remove(t);
+
+    // Force routing to speaker for certain stream types
+    // The forced routing to speaker is managed by hardware mixer
+    if (mOutputType == AudioSystem::AUDIO_OUTPUT_HARDWARE) {
+        sp<Track> track = t.promote();
+        if (track == NULL) return;
+
+        if (streamForcedToSpeaker(track->type())) {
+            mAudioFlinger->handleForcedSpeakerRoute(ACTIVE_TRACK_REMOVED);
+        }
 #ifdef WITH_A2DP
-    // disable A2DP for certain stream types
-    sp<Track> track = t.promote();
-    if (streamDisablesA2dp(track->type())) {
-        if (mA2dpDisableCount > 0) {
-            mA2dpDisableCount--;
-            if (mA2dpDisableCount == 0 && mA2dpSuppressed) {
-                setA2dpEnabled(true);
-                mA2dpSuppressed = false;
-            }
-            LOGD("mA2dpDisableCount decremented to %d\n", mA2dpDisableCount);
-        } else
-            LOGE("mA2dpDisableCount is already zero");
-    }
+        // AudioFlinger::mLock must be locked before calling
+        // handleStreamDisablesA2dp_l because it calls setA2dpEnabled_l().
+        if (streamDisablesA2dp(track->type())) {
+            mAudioFlinger->handleStreamDisablesA2dp_l(ACTIVE_TRACK_REMOVED);
+        }
 #endif
+    }
+}
+
+// getTrackName_l() must be called with AudioFlinger::mLock held
+int AudioFlinger::MixerThread::getTrackName_l()
+{
+    return mAudioMixer->getTrackName();
+}
+
+// deleteTrackName_l() must be called with AudioFlinger::mLock held
+void AudioFlinger::MixerThread::deleteTrackName_l(int name)
+{
+    mAudioMixer->deleteTrackName(name);
+}
+
+size_t AudioFlinger::MixerThread::getOutputFrameCount() 
+{
+    return mOutput->bufferSize() / mOutput->channelCount() / sizeof(int16_t);
 }
 
 // ----------------------------------------------------------------------------
 
-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,
+// TrackBase constructor must be called with AudioFlinger::mLock held
+AudioFlinger::MixerThread::TrackBase::TrackBase(
+            const sp<MixerThread>& mixerThread,
             const sp<Client>& client,
             int streamType,
             uint32_t sampleRate,
             int format,
             int channelCount,
             int frameCount,
+            uint32_t flags,
             const sp<IMemory>& sharedBuffer)
     :   RefBase(),
-        mAudioFlinger(audioFlinger),
+        mMixerThread(mixerThread),
         mClient(client),
         mStreamType(streamType),
         mFrameCount(0),
         mState(IDLE),
         mClientTid(-1),
         mFormat(format),
-        mFlags(0)
+        mFlags(flags & ~SYSTEM_FLAGS_MASK)
 {
-    mName = audioFlinger->audioMixer()->getTrackName();
+    mName = mixerThread->getTrackName_l();
+    LOGV("TrackBase contructor name %d, calling thread %d", mName, IPCThreadState::self()->getCallingPid());
     if (mName < 0) {
         LOGE("no more track names availlable");
         return;
@@ -1043,7 +1600,6 @@
 
     LOGV_IF(sharedBuffer != 0, "sharedBuffer: %p, size: %d", sharedBuffer->pointer(), sharedBuffer->size());
 
-
     // LOGD("Creating track with %d buffers @ %d bytes", bufferCount, bufferSize);
    size_t size = sizeof(audio_track_cblk_t);
    size_t bufferSize = frameCount*channelCount*sizeof(int16_t);
@@ -1051,41 +1607,60 @@
        size += bufferSize;
    }
 
-    mCblkMemory = client->heap()->allocate(size);
-    if (mCblkMemory != 0) {
-        mCblk = static_cast<audio_track_cblk_t *>(mCblkMemory->pointer());
-        if (mCblk) { // construct the shared structure in-place.
-            new(mCblk) audio_track_cblk_t();
-            // clear all buffers
-            mCblk->frameCount = frameCount;
-            mCblk->sampleRate = sampleRate;
-            mCblk->channels = channelCount;
-            if (sharedBuffer == 0) {
-                mBuffer = (char*)mCblk + sizeof(audio_track_cblk_t);
-                memset(mBuffer, 0, frameCount*channelCount*sizeof(int16_t));
-                // Force underrun condition to avoid false underrun callback until first data is
-                // written to buffer
-                mCblk->flowControlFlag = 1;
-            } else {
-                mBuffer = sharedBuffer->pointer();
+   if (client != NULL) {
+        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->frameCount = frameCount;
+                mCblk->sampleRate = sampleRate;
+                mCblk->channels = channelCount;
+                if (sharedBuffer == 0) {
+                    mBuffer = (char*)mCblk + sizeof(audio_track_cblk_t);
+                    memset(mBuffer, 0, frameCount*channelCount*sizeof(int16_t));
+                    // Force underrun condition to avoid false underrun callback until first data is
+                    // written to buffer
+                    mCblk->flowControlFlag = 1;
+                } else {
+                    mBuffer = sharedBuffer->pointer();
+                }
+                mBufferEnd = (uint8_t *)mBuffer + bufferSize;
             }
-            mBufferEnd = (uint8_t *)mBuffer + bufferSize;
+        } else {
+            LOGE("not enough memory for AudioTrack size=%u", size);
+            client->heap()->dump("AudioTrack");
+            return;
         }
-    } else {
-        LOGE("not enough memory for AudioTrack size=%u", size);
-        client->heap()->dump("AudioTrack");
-        return;
-    }
+   } else {
+       mCblk = (audio_track_cblk_t *)(new uint8_t[size]);
+       if (mCblk) { // construct the shared structure in-place.
+           new(mCblk) audio_track_cblk_t();
+           // clear all buffers
+           mCblk->frameCount = frameCount;
+           mCblk->sampleRate = sampleRate;
+           mCblk->channels = channelCount;
+           mBuffer = (char*)mCblk + sizeof(audio_track_cblk_t);
+           memset(mBuffer, 0, frameCount*channelCount*sizeof(int16_t));
+           // Force underrun condition to avoid false underrun callback until first data is
+           // written to buffer
+           mCblk->flowControlFlag = 1;
+           mBufferEnd = (uint8_t *)mBuffer + bufferSize;
+       }
+   }
 }
 
-AudioFlinger::TrackBase::~TrackBase()
+AudioFlinger::MixerThread::TrackBase::~TrackBase()
 {
-    mCblk->~audio_track_cblk_t();   // destroy our shared-structure.
+    if (mCblk) {
+        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)
+void AudioFlinger::MixerThread::TrackBase::releaseBuffer(AudioBufferProvider::Buffer* buffer)
 {
     buffer->raw = 0;
     mFrameCount = buffer->frameCount;
@@ -1093,7 +1668,7 @@
     buffer->frameCount = 0;
 }
 
-bool AudioFlinger::TrackBase::step() {
+bool AudioFlinger::MixerThread::TrackBase::step() {
     bool result;
     audio_track_cblk_t* cblk = this->cblk();
 
@@ -1105,31 +1680,31 @@
     return result;
 }
 
-void AudioFlinger::TrackBase::reset() {
+void AudioFlinger::MixerThread::TrackBase::reset() {
     audio_track_cblk_t* cblk = this->cblk();
 
     cblk->user = 0;
     cblk->server = 0;
     cblk->userBase = 0;
     cblk->serverBase = 0;
-    mFlags = 0;
+    mFlags &= (uint32_t)(~SYSTEM_FLAGS_MASK);
     LOGV("TrackBase::reset");
 }
 
-sp<IMemory> AudioFlinger::TrackBase::getCblk() const
+sp<IMemory> AudioFlinger::MixerThread::TrackBase::getCblk() const
 {
     return mCblkMemory;
 }
 
-int AudioFlinger::TrackBase::sampleRate() const {
+int AudioFlinger::MixerThread::TrackBase::sampleRate() const {
     return mCblk->sampleRate;
 }
 
-int AudioFlinger::TrackBase::channelCount() const {
+int AudioFlinger::MixerThread::TrackBase::channelCount() const {
     return mCblk->channels;
 }
 
-void* AudioFlinger::TrackBase::getBuffer(uint32_t offset, uint32_t frames) const {
+void* AudioFlinger::MixerThread::TrackBase::getBuffer(uint32_t offset, uint32_t frames) const {
     audio_track_cblk_t* cblk = this->cblk();
     int16_t *bufferStart = (int16_t *)mBuffer + (offset-cblk->serverBase)*cblk->channels;
     int16_t *bufferEnd = bufferStart + frames * cblk->channels;
@@ -1148,8 +1723,9 @@
 
 // ----------------------------------------------------------------------------
 
-AudioFlinger::Track::Track(
-            const sp<AudioFlinger>& audioFlinger,
+// Track constructor must be called with AudioFlinger::mLock held
+AudioFlinger::MixerThread::Track::Track(
+            const sp<MixerThread>& mixerThread,
             const sp<Client>& client,
             int streamType,
             uint32_t sampleRate,
@@ -1157,7 +1733,7 @@
             int channelCount,
             int frameCount,
             const sp<IMemory>& sharedBuffer)
-    :   TrackBase(audioFlinger, client, streamType, sampleRate, format, channelCount, frameCount, sharedBuffer)
+    :   TrackBase(mixerThread, client, streamType, sampleRate, format, channelCount, frameCount, 0, sharedBuffer)
 {
     mVolume[0] = 1.0f;
     mVolume[1] = 1.0f;
@@ -1165,23 +1741,36 @@
     mSharedBuffer = sharedBuffer;
 }
 
-AudioFlinger::Track::~Track()
+AudioFlinger::MixerThread::Track::~Track()
 {
     wp<Track> weak(this); // never create a strong ref from the dtor
+    Mutex::Autolock _l(mMixerThread->mAudioFlinger->mLock);
     mState = TERMINATED;
-    mAudioFlinger->removeTrack(weak, mName);
+    mMixerThread->removeTrack_l(weak, mName);
 }
 
-void AudioFlinger::Track::destroy()
+void AudioFlinger::MixerThread::Track::destroy()
 {
-    mAudioFlinger->destroyTrack(this);
+    // NOTE: destroyTrack_l() can remove a strong reference to this Track 
+    // by removing it from mTracks vector, so there is a risk that this Tracks's
+    // desctructor is called. As the destructor needs to lock AudioFlinger::mLock,
+    // we must acquire a strong reference on this Track before locking AudioFlinger::mLock
+    // here so that the destructor is called only when exiting this function.
+    // On the other hand, as long as Track::destroy() is only called by 
+    // TrackHandle destructor, the TrackHandle still holds a strong ref on 
+    // this Track with its member mTrack.
+    sp<Track> keep(this);
+    { // scope for AudioFlinger::mLock
+        Mutex::Autolock _l(mMixerThread->mAudioFlinger->mLock);
+        mMixerThread->destroyTrack_l(this);
+    }
 }
 
-void AudioFlinger::Track::dump(char* buffer, size_t size)
+void AudioFlinger::MixerThread::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(),
+            (mClient == NULL) ? getpid() : mClient->pid(),
             mStreamType,
             mFormat,
             mCblk->channels,
@@ -1196,7 +1785,7 @@
             mCblk->user);
 }
 
-status_t AudioFlinger::Track::getNextBuffer(AudioBufferProvider::Buffer* buffer)
+status_t AudioFlinger::MixerThread::Track::getNextBuffer(AudioBufferProvider::Buffer* buffer)
 {
      audio_track_cblk_t* cblk = this->cblk();
      uint32_t framesReady;
@@ -1236,53 +1825,55 @@
      return NOT_ENOUGH_DATA;
 }
 
-bool AudioFlinger::Track::isReady() const {
+bool AudioFlinger::MixerThread::Track::isReady() const {
     if (mFillingUpStatus != FS_FILLING) return true;
 
     if (mCblk->framesReady() >= mCblk->frameCount ||
         mCblk->forceReady) {
         mFillingUpStatus = FS_FILLED;
         mCblk->forceReady = 0;
+        LOGV("Track::isReady() track %d for output %d", mName, mMixerThread->mOutputType);
         return true;
     }
     return false;
 }
 
-status_t AudioFlinger::Track::start()
+status_t AudioFlinger::MixerThread::Track::start()
 {
-    LOGV("start(%d)", mName);
-    mAudioFlinger->addTrack(this);
+    LOGV("start(%d), calling thread %d for output %d", mName, IPCThreadState::self()->getCallingPid(), mMixerThread->mOutputType);
+    Mutex::Autolock _l(mMixerThread->mAudioFlinger->mLock);
+    mMixerThread->addTrack_l(this);
     return NO_ERROR;
 }
 
-void AudioFlinger::Track::stop()
+void AudioFlinger::MixerThread::Track::stop()
 {
-    LOGV("stop(%d)", mName);
-    Mutex::Autolock _l(mAudioFlinger->mLock);
+    LOGV("stop(%d), calling thread %d for output %d", mName, IPCThreadState::self()->getCallingPid(), mMixerThread->mOutputType);
+    Mutex::Autolock _l(mMixerThread->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) {
+        if (mMixerThread->mActiveTracks.indexOf(this) < 0) {
             reset();
         }
         LOGV("(> STOPPED) => STOPPED (%d)", mName);
     }
 }
 
-void AudioFlinger::Track::pause()
+void AudioFlinger::MixerThread::Track::pause()
 {
-    LOGV("pause(%d)", mName);
-    Mutex::Autolock _l(mAudioFlinger->mLock);
+    LOGV("pause(%d), calling thread %d", mName, IPCThreadState::self()->getCallingPid());
+    Mutex::Autolock _l(mMixerThread->mAudioFlinger->mLock);
     if (mState == ACTIVE || mState == RESUMING) {
         mState = PAUSING;
         LOGV("ACTIVE/RESUMING => PAUSING (%d)", mName);
     }
 }
 
-void AudioFlinger::Track::flush()
+void AudioFlinger::MixerThread::Track::flush()
 {
     LOGV("flush(%d)", mName);
-    Mutex::Autolock _l(mAudioFlinger->mLock);
+    Mutex::Autolock _l(mMixerThread->mAudioFlinger->mLock);
     if (mState != STOPPED && mState != PAUSED && mState != PAUSING) {
         return;
     }
@@ -1298,7 +1889,7 @@
     reset();
 }
 
-void AudioFlinger::Track::reset()
+void AudioFlinger::MixerThread::Track::reset()
 {
     // Do not reset twice to avoid discarding data written just after a flush and before
     // the audioflinger thread detects the track is stopped.
@@ -1313,12 +1904,12 @@
     }
 }
 
-void AudioFlinger::Track::mute(bool muted)
+void AudioFlinger::MixerThread::Track::mute(bool muted)
 {
     mMute = muted;
 }
 
-void AudioFlinger::Track::setVolume(float left, float right)
+void AudioFlinger::MixerThread::Track::setVolume(float left, float right)
 {
     mVolume[0] = left;
     mVolume[1] = right;
@@ -1326,7 +1917,292 @@
 
 // ----------------------------------------------------------------------------
 
-AudioFlinger::TrackHandle::TrackHandle(const sp<AudioFlinger::Track>& track)
+// RecordTrack constructor must be called with AudioFlinger::mLock held
+AudioFlinger::MixerThread::RecordTrack::RecordTrack(
+            const sp<MixerThread>& mixerThread,
+            const sp<Client>& client,
+            int streamType,
+            uint32_t sampleRate,
+            int format,
+            int channelCount,
+            int frameCount,
+            uint32_t flags)
+    :   TrackBase(mixerThread, client, streamType, sampleRate, format,
+                  channelCount, frameCount, flags, 0),
+        mOverflow(false)
+{
+}
+
+AudioFlinger::MixerThread::RecordTrack::~RecordTrack()
+{
+    Mutex::Autolock _l(mMixerThread->mAudioFlinger->mLock);
+    mMixerThread->deleteTrackName_l(mName);
+}
+
+status_t AudioFlinger::MixerThread::RecordTrack::getNextBuffer(AudioBufferProvider::Buffer* buffer)
+{
+    audio_track_cblk_t* cblk = this->cblk();
+    uint32_t framesAvail;
+    uint32_t framesReq = buffer->frameCount;
+
+     // Check if last stepServer failed, try to step now
+    if (mFlags & TrackBase::STEPSERVER_FAILED) {
+        if (!step()) goto getNextBuffer_exit;
+        LOGV("stepServer recovered");
+        mFlags &= ~TrackBase::STEPSERVER_FAILED;
+    }
+
+    framesAvail = cblk->framesAvailable_l();
+
+    if (LIKELY(framesAvail)) {
+        uint32_t s = cblk->server;
+        uint32_t bufferEnd = cblk->serverBase + cblk->frameCount;
+
+        if (framesReq > framesAvail) {
+            framesReq = framesAvail;
+        }
+        if (s + framesReq > bufferEnd) {
+            framesReq = bufferEnd - s;
+        }
+
+        buffer->raw = getBuffer(s, framesReq);
+        if (buffer->raw == 0) goto getNextBuffer_exit;
+
+        buffer->frameCount = framesReq;
+        return NO_ERROR;
+    }
+
+getNextBuffer_exit:
+    buffer->raw = 0;
+    buffer->frameCount = 0;
+    return NOT_ENOUGH_DATA;
+}
+
+status_t AudioFlinger::MixerThread::RecordTrack::start()
+{
+    return mMixerThread->mAudioFlinger->startRecord(this);
+}
+
+void AudioFlinger::MixerThread::RecordTrack::stop()
+{
+    mMixerThread->mAudioFlinger->stopRecord(this);
+    TrackBase::reset();
+    // Force overerrun condition to avoid false overrun callback until first data is
+    // read from buffer
+    mCblk->flowControlFlag = 1;
+}
+
+
+// ----------------------------------------------------------------------------
+
+AudioFlinger::MixerThread::OutputTrack::OutputTrack(
+            const sp<MixerThread>& mixerThread,
+            uint32_t sampleRate,
+            int format,
+            int channelCount,
+            int frameCount)
+    :   Track(mixerThread, NULL, AudioSystem::SYSTEM, sampleRate, format, channelCount, frameCount, NULL),
+    mOutputMixerThread(mixerThread)
+{
+                
+    mCblk->out = 1;
+    mCblk->buffers = (char*)mCblk + sizeof(audio_track_cblk_t);
+    mCblk->volume[0] = mCblk->volume[1] = 0x1000;
+    mOutBuffer.frameCount = 0;
+    mCblk->bufferTimeoutMs = 10;
+    
+    LOGV("OutputTrack constructor mCblk %p, mBuffer %p, mCblk->buffers %p, mCblk->frameCount %d, mCblk->sampleRate %d, mCblk->channels %d mBufferEnd %p", 
+            mCblk, mBuffer, mCblk->buffers, mCblk->frameCount, mCblk->sampleRate, mCblk->channels, mBufferEnd);
+    
+}
+
+AudioFlinger::MixerThread::OutputTrack::~OutputTrack()
+{
+    stop();
+}
+
+status_t AudioFlinger::MixerThread::OutputTrack::start()
+{
+    status_t status = Track::start();
+    
+    mRetryCount = 127;
+    return status;
+}
+
+void AudioFlinger::MixerThread::OutputTrack::stop()
+{
+    Track::stop();
+    clearBufferQueue();
+    mOutBuffer.frameCount = 0;
+}
+
+void AudioFlinger::MixerThread::OutputTrack::write(int16_t* data, uint32_t frames)
+{
+    Buffer *pInBuffer;
+    Buffer inBuffer;
+    uint32_t channels = mCblk->channels;
+        
+    inBuffer.frameCount = frames;
+    inBuffer.i16 = data;
+    
+    if (mCblk->user == 0) {
+        if (mOutputMixerThread->isMusicActive()) {
+            mCblk->forceReady = 1;
+            LOGV("OutputTrack::start() force ready");
+        } else if (mCblk->frameCount > frames){
+            if (mBufferQueue.size() < kMaxOutputTrackBuffers) {
+                uint32_t startFrames = (mCblk->frameCount - frames);
+                LOGV("OutputTrack::start() write %d frames", startFrames);
+                pInBuffer = new Buffer;
+                pInBuffer->mBuffer = new int16_t[startFrames * channels];
+                pInBuffer->frameCount = startFrames;
+                pInBuffer->i16 = pInBuffer->mBuffer;
+                memset(pInBuffer->raw, 0, startFrames * channels * sizeof(int16_t));
+                mBufferQueue.add(pInBuffer);                
+            } else {
+                LOGW ("OutputTrack::write() no more buffers");
+            }
+        }        
+    }
+
+    while (1) { 
+        // First write pending buffers, then new data
+        if (mBufferQueue.size()) {
+            pInBuffer = mBufferQueue.itemAt(0);
+        } else {
+            pInBuffer = &inBuffer;
+        }
+ 
+        if (pInBuffer->frameCount == 0) {
+            break;
+        }
+        
+        if (mOutBuffer.frameCount == 0) {
+            mOutBuffer.frameCount = pInBuffer->frameCount;
+            if (obtainBuffer(&mOutBuffer) == (status_t)AudioTrack::NO_MORE_BUFFERS) {
+                break;
+            }
+        }
+            
+        uint32_t outFrames = pInBuffer->frameCount > mOutBuffer.frameCount ? mOutBuffer.frameCount : pInBuffer->frameCount;
+        memcpy(mOutBuffer.raw, pInBuffer->raw, outFrames * channels * sizeof(int16_t));
+        mCblk->stepUser(outFrames);
+        pInBuffer->frameCount -= outFrames;
+        pInBuffer->i16 += outFrames * channels;
+        mOutBuffer.frameCount -= outFrames;
+        mOutBuffer.i16 += outFrames * channels;            
+        
+        if (pInBuffer->frameCount == 0) {
+            if (mBufferQueue.size()) {
+                mBufferQueue.removeAt(0);
+                delete [] pInBuffer->mBuffer;
+                delete pInBuffer;
+            } else {
+                break;
+            }
+        }
+    }
+ 
+    // If we could not write all frames, allocate a buffer and queue it for next time.
+    if (inBuffer.frameCount) {
+        if (mBufferQueue.size() < kMaxOutputTrackBuffers) {
+            pInBuffer = new Buffer;
+            pInBuffer->mBuffer = new int16_t[inBuffer.frameCount * channels];
+            pInBuffer->frameCount = inBuffer.frameCount;
+            pInBuffer->i16 = pInBuffer->mBuffer;
+            memcpy(pInBuffer->raw, inBuffer.raw, inBuffer.frameCount * channels * sizeof(int16_t));
+            mBufferQueue.add(pInBuffer);
+        } else {
+            LOGW("OutputTrack::write() no more buffers");
+        }
+    }
+    
+    // Calling write() with a 0 length buffer, means that no more data will be written:
+    // If no more buffers are pending, fill output track buffer to make sure it is started 
+    // by output mixer.
+    if (frames == 0 && mBufferQueue.size() == 0 && mCblk->user < mCblk->frameCount) {
+        frames = mCblk->frameCount - mCblk->user;
+        pInBuffer = new Buffer;
+        pInBuffer->mBuffer = new int16_t[frames * channels];
+        pInBuffer->frameCount = frames;
+        pInBuffer->i16 = pInBuffer->mBuffer;
+        memset(pInBuffer->raw, 0, frames * channels * sizeof(int16_t));
+        mBufferQueue.add(pInBuffer);
+    }
+
+}
+
+status_t AudioFlinger::MixerThread::OutputTrack::obtainBuffer(AudioBufferProvider::Buffer* buffer)
+{
+    int active;
+    int timeout = 0;
+    status_t result;
+    audio_track_cblk_t* cblk = mCblk;
+    uint32_t framesReq = buffer->frameCount;
+
+    LOGV("OutputTrack::obtainBuffer user %d, server %d", cblk->user, cblk->server);
+    buffer->frameCount  = 0;
+    
+    uint32_t framesAvail = cblk->framesAvailable();
+
+    if (framesAvail == 0) {
+        return AudioTrack::NO_MORE_BUFFERS;
+    }
+
+    if (framesReq > framesAvail) {
+        framesReq = framesAvail;
+    }
+
+    uint32_t u = cblk->user;
+    uint32_t bufferEnd = cblk->userBase + cblk->frameCount;
+
+    if (u + framesReq > bufferEnd) {
+        framesReq = bufferEnd - u;
+    }
+
+    buffer->frameCount  = framesReq;
+    buffer->raw         = (void *)cblk->buffer(u);
+    return NO_ERROR;
+}
+
+
+void AudioFlinger::MixerThread::OutputTrack::clearBufferQueue()
+{
+    size_t size = mBufferQueue.size();
+    Buffer *pBuffer;
+    
+    for (size_t i = 0; i < size; i++) {
+        pBuffer = mBufferQueue.itemAt(i);
+        delete [] pBuffer->mBuffer;
+        delete pBuffer;
+    }
+    mBufferQueue.clear();
+}
+
+// ----------------------------------------------------------------------------
+
+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::TrackHandle::TrackHandle(const sp<AudioFlinger::MixerThread::Track>& track)
     : BnAudioTrack(),
       mTrack(track)
 {
@@ -1386,8 +2262,7 @@
         uint32_t flags,
         status_t *status)
 {
-    sp<AudioRecordThread> thread;
-    sp<RecordTrack> recordTrack;
+    sp<MixerThread::RecordTrack> recordTrack;
     sp<RecordHandle> recordHandle;
     sp<Client> client;
     wp<Client> wclient;
@@ -1414,12 +2289,6 @@
         goto Exit;
     }
 
-    if (mSampleRate == 0) {
-        LOGE("Audio driver not initialized");
-        lStatus = NO_INIT;
-        goto Exit;
-    }
-
     if (mAudioRecordThread == 0) {
         LOGE("Audio record thread not started");
         lStatus = NO_INIT;
@@ -1436,7 +2305,7 @@
     }
 
     // add client to list
-    {
+    { // scope for mLock
         Mutex::Autolock _l(mLock);
         wclient = mClients.valueFor(pid);
         if (wclient != NULL) {
@@ -1445,15 +2314,20 @@
             client = new Client(this, pid);
             mClients.add(pid, client);
         }
+
+        // frameCount must be a multiple of input buffer size
+        inFrameCount = inputBufferSize/channelCount/sizeof(short);
+        frameCount = ((frameCount - 1)/inFrameCount + 1) * inFrameCount;
+    
+        // create new record track. The record track uses one track in mHardwareMixerThread by convention.
+        recordTrack = new MixerThread::RecordTrack(mHardwareMixerThread, client, streamType, sampleRate,
+                                                   format, channelCount, frameCount, flags);
     }
-
-    // frameCount must be a multiple of input buffer size
-    inFrameCount = inputBufferSize/channelCount/sizeof(short);
-    frameCount = ((frameCount - 1)/inFrameCount + 1) * inFrameCount;
-
-    // create new record track and pass to record thread
-    recordTrack = new RecordTrack(this, client, streamType, sampleRate,
-            format, channelCount, frameCount);
+    if (recordTrack->getCblk() == NULL) {
+        recordTrack.clear();
+        lStatus = NO_MEMORY;
+        goto Exit;
+    }
 
     // return to handle to client
     recordHandle = new RecordHandle(recordTrack);
@@ -1466,97 +2340,22 @@
     return recordHandle;
 }
 
-status_t AudioFlinger::startRecord(RecordTrack* recordTrack) {
+status_t AudioFlinger::startRecord(MixerThread::RecordTrack* recordTrack) {
     if (mAudioRecordThread != 0) {
         return mAudioRecordThread->start(recordTrack);        
     }
     return NO_INIT;
 }
 
-void AudioFlinger::stopRecord(RecordTrack* recordTrack) {
+void AudioFlinger::stopRecord(MixerThread::RecordTrack* recordTrack) {
     if (mAudioRecordThread != 0) {
         mAudioRecordThread->stop(recordTrack);
     }
 }
 
-
 // ----------------------------------------------------------------------------
 
-AudioFlinger::RecordTrack::RecordTrack(
-            const sp<AudioFlinger>& audioFlinger,
-            const sp<Client>& client,
-            int streamType,
-            uint32_t sampleRate,
-            int format,
-            int channelCount,
-            int frameCount)
-    :   TrackBase(audioFlinger, client, streamType, sampleRate, format,
-            channelCount, frameCount, 0),
-            mOverflow(false)
-{
-}
-
-AudioFlinger::RecordTrack::~RecordTrack()
-{
-    mAudioFlinger->audioMixer()->deleteTrackName(mName);
-}
-
-status_t AudioFlinger::RecordTrack::getNextBuffer(AudioBufferProvider::Buffer* buffer)
-{
-    audio_track_cblk_t* cblk = this->cblk();
-    uint32_t framesAvail;
-    uint32_t framesReq = buffer->frameCount;
-
-     // Check if last stepServer failed, try to step now
-    if (mFlags & TrackBase::STEPSERVER_FAILED) {
-        if (!step()) goto getNextBuffer_exit;
-        LOGV("stepServer recovered");
-        mFlags &= ~TrackBase::STEPSERVER_FAILED;
-    }
-
-    framesAvail = cblk->framesAvailable_l();
-
-    if (LIKELY(framesAvail)) {
-        uint32_t s = cblk->server;
-        uint32_t bufferEnd = cblk->serverBase + cblk->frameCount;
-
-        if (framesReq > framesAvail) {
-            framesReq = framesAvail;
-        }
-        if (s + framesReq > bufferEnd) {
-            framesReq = bufferEnd - s;
-        }
-
-        buffer->raw = getBuffer(s, framesReq);
-        if (buffer->raw == 0) goto getNextBuffer_exit;
-
-        buffer->frameCount = framesReq;
-        return NO_ERROR;
-    }
-
-getNextBuffer_exit:
-    buffer->raw = 0;
-    buffer->frameCount = 0;
-    return NOT_ENOUGH_DATA;
-}
-
-status_t AudioFlinger::RecordTrack::start()
-{
-    return mAudioFlinger->startRecord(this);
-}
-
-void AudioFlinger::RecordTrack::stop()
-{
-    mAudioFlinger->stopRecord(this);
-    TrackBase::reset();
-    // Force overerrun condition to avoid false overrun callback until first data is
-    // read from buffer
-    mCblk->flowControlFlag = 1;
-}
-
-// ----------------------------------------------------------------------------
-
-AudioFlinger::RecordHandle::RecordHandle(const sp<AudioFlinger::RecordTrack>& recordTrack)
+AudioFlinger::RecordHandle::RecordHandle(const sp<AudioFlinger::MixerThread::RecordTrack>& recordTrack)
     : BnAudioRecord(),
     mRecordTrack(recordTrack)
 {
@@ -1588,8 +2387,10 @@
 
 // ----------------------------------------------------------------------------
 
-AudioFlinger::AudioRecordThread::AudioRecordThread(AudioHardwareInterface* audioHardware) :
+AudioFlinger::AudioRecordThread::AudioRecordThread(AudioHardwareInterface* audioHardware,
+            const sp<AudioFlinger>& audioFlinger) :
     mAudioHardware(audioHardware),
+    mAudioFlinger(audioFlinger),
     mActive(false)
 {
 }
@@ -1619,15 +2420,17 @@
                     input = 0;
                 }
                 mRecordTrack.clear();
+                mStopped.signal();
 
                 mWaitWorkCV.wait(mLock);
                
                 LOGV("AudioRecordThread: loop starting");
                 if (mRecordTrack != 0) {
                     input = mAudioHardware->openInputStream(mRecordTrack->format(), 
-                                            mRecordTrack->channelCount(), 
-                                            mRecordTrack->sampleRate(), 
-                                            &mStartStatus);
+                                    mRecordTrack->channelCount(), 
+                                    mRecordTrack->sampleRate(), 
+                                    &mStartStatus,
+                                    (AudioSystem::audio_in_acoustics)(mRecordTrack->mFlags >> 16));
                     if (input != 0) {
                         inBufferSize = input->bufferSize();
                         inFrameCount = inBufferSize/input->frameSize();                        
@@ -1643,12 +2446,14 @@
                 mWaitWorkCV.signal();
             }
             mLock.unlock();
-        } else if (mRecordTrack != 0){
+        } else if (mRecordTrack != 0) {
 
             buffer.frameCount = inFrameCount;
-            if (LIKELY(mRecordTrack->getNextBuffer(&buffer) == NO_ERROR)) {
+            if (LIKELY(mRecordTrack->getNextBuffer(&buffer) == NO_ERROR &&
+                       (int)buffer.frameCount == inFrameCount)) {
                 LOGV("AudioRecordThread read: %d frames", buffer.frameCount);
-                if (input->read(buffer.raw, inBufferSize) < 0) {
+                ssize_t bytesRead = input->read(buffer.raw, inBufferSize);
+                if (bytesRead < 0) {
                     LOGE("Error reading audio input");
                     sleep(1);
                 }
@@ -1677,7 +2482,7 @@
     return false;
 }
 
-status_t AudioFlinger::AudioRecordThread::start(RecordTrack* recordTrack)
+status_t AudioFlinger::AudioRecordThread::start(MixerThread::RecordTrack* recordTrack)
 {
     LOGV("AudioRecordThread::start");
     AutoMutex lock(&mLock);
@@ -1690,6 +2495,19 @@
 
     mRecordTrack = recordTrack;
 
+#ifdef WITH_A2DP
+    { // scope for lock2
+
+        // AudioFlinger::mLock must be locked before calling
+        // handleStreamDisablesA2dp_l because it calls setA2dpEnabled_l().
+        AutoMutex lock2(&mAudioFlinger->mLock);
+
+        // Currently there is no way to detect if we are recording over SCO,
+        // so we disable A2DP during any recording.
+        mAudioFlinger->handleStreamDisablesA2dp_l(ACTIVE_TRACK_ADDED);
+    }
+#endif
+
     // signal thread to start
     LOGV("Signal record thread");
     mWaitWorkCV.signal();
@@ -1698,11 +2516,24 @@
     return mStartStatus;
 }
 
-void AudioFlinger::AudioRecordThread::stop(RecordTrack* recordTrack) {
+void AudioFlinger::AudioRecordThread::stop(MixerThread::RecordTrack* recordTrack) {
     LOGV("AudioRecordThread::stop");
     AutoMutex lock(&mLock);
     if (mActive && (recordTrack == mRecordTrack.get())) {
+#ifdef WITH_A2DP
+        { // scope for lock2
+    
+            // AudioFlinger::mLock must be locked before calling
+            // handleStreamDisablesA2dp_l because it calls setA2dpEnabled_l().
+            AutoMutex lock2(&mAudioFlinger->mLock);
+
+            // Currently there is no way to detect if we are recording over SCO,
+            // so we disable A2DP during any recording.
+            mAudioFlinger->handleStreamDisablesA2dp_l(ACTIVE_TRACK_REMOVED);
+        }
+#endif
         mActive = false;
+        mStopped.wait(mLock);
     }
 }
 
@@ -1717,6 +2548,22 @@
     requestExitAndWait();
 }
 
+status_t AudioFlinger::AudioRecordThread::dump(int fd, const Vector<String16>& args)
+{
+    const size_t SIZE = 256;
+    char buffer[SIZE];
+    String8 result;
+    pid_t pid = 0;
+
+    if (mRecordTrack != 0 && mRecordTrack->mClient != 0) {
+        snprintf(buffer, SIZE, "Record client pid: %d\n", mRecordTrack->mClient->pid());
+        result.append(buffer);
+    } else {
+        result.append("No record client\n");
+    }
+    write(fd, result.string(), result.size());
+    return NO_ERROR;
+}
 
 status_t AudioFlinger::onTransact(
         uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)