Code drop from //branches/cupcake/...@124589
diff --git a/libs/audioflinger/AudioFlinger.cpp b/libs/audioflinger/AudioFlinger.cpp
index fb21629..53b18ad 100644
--- a/libs/audioflinger/AudioFlinger.cpp
+++ b/libs/audioflinger/AudioFlinger.cpp
@@ -31,6 +31,8 @@
 #include <utils/String16.h>
 #include <utils/threads.h>
 
+#include <cutils/properties.h>
+
 #include <media/AudioTrack.h>
 #include <media/AudioRecord.h>
 
@@ -41,9 +43,13 @@
 #include "AudioMixer.h"
 #include "AudioFlinger.h"
 
+#ifdef WITH_A2DP
+#include "A2dpAudioInterface.h"
+#endif
+
 namespace android {
 
-static const nsecs_t kStandbyTimeInNsecs = seconds(3);
+//static const nsecs_t kStandbyTimeInNsecs = seconds(3);
 static const unsigned long kBufferRecoveryInUsecs = 2000;
 static const unsigned long kMaxBufferRecoveryInUsecs = 20000;
 static const float MAX_GAIN = 4096.0f;
@@ -93,8 +99,9 @@
 
 AudioFlinger::AudioFlinger()
     : BnAudioFlinger(), Thread(false),
-        mMasterVolume(0), mMasterMute(true),
-        mAudioMixer(0), mAudioHardware(0), mOutput(0), mAudioRecordThread(0),
+        mMasterVolume(0), mMasterMute(true), mHardwareAudioMixer(0), mA2dpAudioMixer(0),
+        mAudioMixer(0), mAudioHardware(0), mA2dpAudioInterface(0),
+        mHardwareOutput(0), mA2dpOutput(0), mOutput(0), mAudioRecordThread(0),
         mSampleRate(0), mFrameCount(0), mChannelCount(0), mFormat(0),
         mMixBuffer(0), mLastWriteTime(0), mNumWrites(0), mNumDelayedWrites(0),
         mStandby(false), mInWrite(false)
@@ -105,17 +112,14 @@
     if (mAudioHardware->initCheck() == NO_ERROR) {
         // open 16-bit output stream for s/w mixer
         mHardwareStatus = AUDIO_HW_OUTPUT_OPEN;
-        mOutput = mAudioHardware->openOutputStream(AudioSystem::PCM_16_BIT);
+        status_t status;
+        mHardwareOutput = mAudioHardware->openOutputStream(AudioSystem::PCM_16_BIT, 0, 0, &status);
         mHardwareStatus = AUDIO_HW_IDLE;
-        if (mOutput) {
-            mSampleRate = mOutput->sampleRate();
-            mChannelCount = mOutput->channelCount();
-            mFormat = mOutput->format();
-            mMixBufferSize = mOutput->bufferSize();
-            mFrameCount = mMixBufferSize / mChannelCount / sizeof(int16_t);
-            mMixBuffer = new int16_t[mFrameCount * mChannelCount];
-            memset(mMixBuffer, 0, mMixBufferSize);
-            mAudioMixer = new AudioMixer(mFrameCount, mSampleRate);
+        if (mHardwareOutput) {
+            mSampleRate = mHardwareOutput->sampleRate();
+            mHardwareAudioMixer = new AudioMixer(getOutputFrameCount(mHardwareOutput), mSampleRate);
+            setOutput(mHardwareOutput);
+
             // FIXME - this should come from settings
             setMasterVolume(1.0f);
             setRouting(AudioSystem::MODE_NORMAL, AudioSystem::ROUTE_SPEAKER, AudioSystem::ROUTE_ALL);
@@ -124,20 +128,87 @@
             setMode(AudioSystem::MODE_NORMAL);
             mMasterMute = false;
         } else {
-            LOGE("Failed to initialize output stream");
+            LOGE("Failed to initialize output stream, status: %d", status);
         }
-    } else {
+        
+#ifdef WITH_A2DP
+        // Create A2DP interface
+        mA2dpAudioInterface = new A2dpAudioInterface();
+        mA2dpOutput = mA2dpAudioInterface->openOutputStream(AudioSystem::PCM_16_BIT, 0, 0, &status);       
+        mA2dpAudioMixer = new AudioMixer(getOutputFrameCount(mA2dpOutput), mA2dpOutput->sampleRate());
+
+        // create a buffer big enough for both hardware and A2DP audio output.
+        size_t hwFrameCount = getOutputFrameCount(mHardwareOutput);
+        size_t a2dpFrameCount = getOutputFrameCount(mA2dpOutput);
+        size_t frameCount = (hwFrameCount > a2dpFrameCount ? hwFrameCount : a2dpFrameCount);
+#else
+        size_t frameCount = getOutputFrameCount(mHardwareOutput);
+#endif
+        // FIXME - Current mixer implementation only supports stereo output: Always
+        // Allocate a stereo buffer even if HW output is mono.
+        mMixBuffer = new int16_t[frameCount * 2];
+        memset(mMixBuffer, 0, frameCount * 2 * sizeof(int16_t));
+        
+        // Start record thread
+        mAudioRecordThread = new AudioRecordThread(mAudioHardware);
+        if (mAudioRecordThread != 0) {
+            mAudioRecordThread->run("AudioRecordThread", PRIORITY_URGENT_AUDIO);            
+        }
+     } else {
         LOGE("Couldn't even initialize the stubbed audio hardware!");
     }
+
+    char value[PROPERTY_VALUE_MAX];
+    // FIXME: What property should this be???
+    property_get("ro.audio.silent", value, "0");
+    if (atoi(value)) {
+        LOGD("Silence is golden");
+        mMasterMute = true;
+    }
 }
 
 AudioFlinger::~AudioFlinger()
 {
+    if (mAudioRecordThread != 0) {
+        mAudioRecordThread->exit();
+        mAudioRecordThread.clear();        
+    }
     delete mOutput;
+    delete mA2dpOutput;
     delete mAudioHardware;
+    delete mA2dpAudioInterface;
     delete [] mMixBuffer;
-    delete mAudioMixer;
-    mAudioRecordThread.clear();
+    delete mHardwareAudioMixer;
+    delete mA2dpAudioMixer;
+}
+ 
+void AudioFlinger::setOutput(AudioStreamOut* output)
+{
+    // lock on mOutputLock to prevent threadLoop() from starving us
+    Mutex::Autolock _l2(mOutputLock);
+    
+    // to synchronize with threadLoop()
+    Mutex::Autolock _l(mLock);
+
+    if (mOutput != output) {
+        mSampleRate = output->sampleRate();
+        mChannelCount = output->channelCount();
+    
+        // FIXME - Current mixer implementation only supports stereo output
+        if (mChannelCount == 1) {
+            LOGE("Invalid audio hardware channel count");
+        }
+        mFormat = output->format();
+        mFrameCount = getOutputFrameCount(output);
+                
+        mAudioMixer = (output == mA2dpOutput ? mA2dpAudioMixer : mHardwareAudioMixer);
+        mOutput = output;
+    }
+}
+
+size_t AudioFlinger::getOutputFrameCount(AudioStreamOut* output) 
+{
+    return output->bufferSize() / output->channelCount() / sizeof(int16_t);
 }
 
 status_t AudioFlinger::dumpClients(int fd, const Vector<String16>& args)
@@ -201,8 +272,8 @@
     const size_t SIZE = 256;
     char buffer[SIZE];
     String8 result;
-    
-    snprintf(buffer, SIZE, "AudioMixer tracks: %08x\n", audioMixer().trackNames());
+
+    snprintf(buffer, SIZE, "AudioMixer tracks: %08x\n", audioMixer()->trackNames());
     result.append(buffer);
     snprintf(buffer, SIZE, "last write occurred (msecs): %llu\n", ns2ms(systemTime() - mLastWriteTime));
     result.append(buffer);
@@ -254,17 +325,26 @@
 // Thread virtuals
 bool AudioFlinger::threadLoop()
 {
-    nsecs_t maxPeriod = seconds(mFrameCount) / mSampleRate * 2;
     unsigned long sleepTime = kBufferRecoveryInUsecs;
-    const size_t mixBufferSize = mFrameCount*mChannelCount*sizeof(int16_t);
     int16_t* curBuf = mMixBuffer;
     Vector< sp<Track> > tracksToRemove;
-    size_t enabledTracks;
+    size_t enabledTracks = 0;
     nsecs_t standbyTime = systemTime();
+    AudioMixer* mixer = 0;
+    size_t frameCount = 0;
+    int channelCount = 0;
+    uint32_t sampleRate = 0;
+    AudioStreamOut* output = 0;
 
     do {
         enabledTracks = 0;
-        { // scope for the lock
+        { // scope for the mLock
+        
+            // locking briefly on the secondary mOutputLock is necessary to avoid
+            // having this thread starve the thread that called setOutput()
+            mOutputLock.lock();
+            mOutputLock.unlock();
+
             Mutex::Autolock _l(mLock);
             const SortedVector< wp<Track> >& activeTracks = mActiveTracks;
 
@@ -286,6 +366,15 @@
                 continue;
             }
 
+            // get active mixer and output parameter while the lock is held and keep them
+            // consistent till the next loop.
+            
+            mixer = audioMixer();
+            frameCount = mFrameCount;
+            channelCount = mChannelCount;
+            sampleRate = mSampleRate;
+            output = mOutput;
+            
             // find out which tracks need to be processed
             size_t count = activeTracks.size();
             for (size_t i=0 ; i<count ; i++) {
@@ -294,13 +383,11 @@
 
                 Track* const track = t.get();
                 audio_track_cblk_t* cblk = track->cblk();
-                uint32_t u = cblk->user;
-                uint32_t s = cblk->server;
 
                 // The first time a track is added we wait
                 // for all its buffers to be filled before processing it
-                audioMixer().setActiveTrack(track->name());
-                if ((u > s) && (track->isReady(u, s) || track->isStopped()) &&
+                mixer->setActiveTrack(track->name());
+                if (cblk->framesReady() && (track->isReady() || track->isStopped()) &&
                         !track->isPaused())
                 {
                     //LOGD("u=%08x, s=%08x [OK]", u, s);
@@ -325,9 +412,8 @@
                     }
 
                     // XXX: these things DON'T need to be done each time
-                    AudioMixer& mixer(audioMixer());
-                    mixer.setBufferProvider(track);
-                    mixer.enable(AudioMixer::MIXING);
+                    mixer->setBufferProvider(track);
+                    mixer->enable(AudioMixer::MIXING);
 
                     int param;
                     if ( track->mFillingUpStatus == Track::FS_FILLED) {
@@ -342,15 +428,15 @@
                     } else {
                         param = AudioMixer::RAMP_VOLUME;
                     }
-                    mixer.setParameter(param, AudioMixer::VOLUME0, left);
-                    mixer.setParameter(param, AudioMixer::VOLUME1, right);
-                    mixer.setParameter(
+                    mixer->setParameter(param, AudioMixer::VOLUME0, left);
+                    mixer->setParameter(param, AudioMixer::VOLUME1, right);
+                    mixer->setParameter(
                         AudioMixer::TRACK,
                         AudioMixer::FORMAT, track->format());
-                    mixer.setParameter(
+                    mixer->setParameter(
                         AudioMixer::TRACK,
                         AudioMixer::CHANNEL_COUNT, track->channelCount());
-                    mixer.setParameter(
+                    mixer->setParameter(
                         AudioMixer::RESAMPLE,
                         AudioMixer::SAMPLE_RATE,
                         int(cblk->sampleRate));
@@ -361,8 +447,7 @@
                 } else {
                     //LOGD("u=%08x, s=%08x [NOT READY]", u, s);
                     if (track->isStopped()) {
-                        track->mFillingUpStatus = Track::FS_FILLING;
-                        track->mFlags = 0;    
+                        track->reset();
                     }
                     if (track->isTerminated() || track->isStopped() || track->isPaused()) {
                         // We have consumed all the buffers of this track.
@@ -378,7 +463,7 @@
                         }
                     }
                     // LOGV("disable(%d)", track->name());
-                    audioMixer().disable(AudioMixer::MIXING);
+                    mixer->disable(AudioMixer::MIXING);
                 }
             }
 
@@ -390,26 +475,27 @@
                     mActiveTracks.remove(track);
                     if (track->isTerminated()) {
                         mTracks.remove(track);
-                        audioMixer().deleteTrackName(track->mName);
+                        mixer->deleteTrackName(track->mName);
                     }
                 }
-            }
-        }
-
+            }  
+       }
         if (LIKELY(enabledTracks)) {
             // mix buffers...
-            audioMixer().process(curBuf);
+            mixer->process(curBuf);
 
             // output audio to hardware
             mLastWriteTime = systemTime();
             mInWrite = true;
-            mOutput->write(curBuf, mixBufferSize);
+            size_t mixBufferSize = frameCount*channelCount*sizeof(int16_t);
+            output->write(curBuf, mixBufferSize);
             mNumWrites++;
             mInWrite = false;
             mStandby = false;
             nsecs_t temp = systemTime();
             standbyTime = temp + kStandbyTimeInNsecs;
             nsecs_t delta = temp - mLastWriteTime;
+            nsecs_t maxPeriod = seconds(frameCount) / sampleRate * 2;
             if (delta > maxPeriod) {
                 LOGW("write blocked for %llu msecs", ns2ms(delta));
                 mNumDelayedWrites++;
@@ -458,43 +544,60 @@
         uint32_t sampleRate,
         int format,
         int channelCount,
-        int bufferCount,
-        uint32_t flags)
+        int frameCount,
+        uint32_t flags,
+        const sp<IMemory>& sharedBuffer,
+        status_t *status)
 {
-    if (streamType >= AudioTrack::NUM_STREAM_TYPES) {
-        LOGE("invalid stream type");
-        return NULL;
-    }
-
-    if (sampleRate > MAX_SAMPLE_RATE) {
-        LOGE("Sample rate out of range: %d", sampleRate);
-        return NULL;
-    }
-
     sp<Track> track;
     sp<TrackHandle> trackHandle;
-    Mutex::Autolock _l(mLock);
-
-    if (mSampleRate == 0) {
-        LOGE("Audio driver not initialized.");
-        return trackHandle;
-    }
-
     sp<Client> client;
-    wp<Client> wclient = mClients.valueFor(pid);
+    wp<Client> wclient;
+    status_t lStatus;
 
-    if (wclient != NULL) {
-        client = wclient.promote();
-    } else {
-        client = new Client(this, pid);
-        mClients.add(pid, client);
+    if (streamType >= AudioTrack::NUM_STREAM_TYPES) {
+        LOGE("invalid stream type");
+        lStatus = BAD_VALUE;
+        goto Exit;
     }
 
-    // FIXME: Buffer size should be based on sample rate for consistent latency
-    track = new Track(this, client, streamType, sampleRate, format,
-            channelCount, bufferCount, channelCount == 1 ? mMixBufferSize>>1 : mMixBufferSize);
-    mTracks.add(track);
-    trackHandle = new TrackHandle(track);
+    // Resampler implementation limits input sampling rate to 2 x output sampling rate.
+    if (sampleRate > MAX_SAMPLE_RATE || sampleRate > mSampleRate*2) {
+        LOGE("Sample rate out of range: %d", sampleRate);
+        lStatus = BAD_VALUE;
+        goto Exit;
+    }
+
+    {
+        Mutex::Autolock _l(mLock);
+
+        if (mSampleRate == 0) {
+            LOGE("Audio driver not initialized.");
+            lStatus = NO_INIT;
+            goto Exit;
+        }
+
+        wclient = mClients.valueFor(pid);
+
+        if (wclient != NULL) {
+            client = wclient.promote();
+        } else {
+            client = new Client(this, pid);
+            mClients.add(pid, client);
+        }
+
+        track = new Track(this, client, streamType, sampleRate, format,
+                channelCount, frameCount, sharedBuffer);
+        mTracks.add(track);
+        trackHandle = new TrackHandle(track);
+
+        lStatus = NO_ERROR;
+    }
+
+Exit:
+    if(status) {
+        *status = lStatus;
+    }
     return trackHandle;
 }
 
@@ -518,6 +621,16 @@
     return mFrameCount;
 }
 
+uint32_t AudioFlinger::latency() const
+{
+    if (mOutput) {
+        return mOutput->latency();
+    }
+    else {
+        return 0;
+    }
+}
+
 status_t AudioFlinger::setMasterVolume(float value)
 {
     // check calling permissions
@@ -549,6 +662,21 @@
         return BAD_VALUE;
     }
 
+#ifdef WITH_A2DP
+    LOGD("setRouting %d %d %d\n", mode, routes, mask);
+    if (mode == AudioSystem::MODE_NORMAL && 
+            (mask & AudioSystem::ROUTE_BLUETOOTH_A2DP)) {
+        if (routes & AudioSystem::ROUTE_BLUETOOTH_A2DP) {
+            LOGD("set output to A2DP\n");
+            setOutput(mA2dpOutput);
+        } else {
+            LOGD("set output to hardware audio\n");
+            setOutput(mHardwareOutput);
+        }
+        LOGD("setOutput done\n");
+    }
+#endif
+
     AutoMutex lock(mHardwareLock);
     mHardwareStatus = AUDIO_HW_GET_ROUTING;
     uint32_t r;
@@ -656,7 +784,7 @@
     if (uint32_t(stream) >= AudioTrack::NUM_STREAM_TYPES) {
         return BAD_VALUE;
     }
-    
+
     mStreamTypes[stream].volume = value;
     status_t ret = NO_ERROR;
     if (stream == AudioTrack::VOICE_CALL) {
@@ -750,6 +878,7 @@
         // buffers before playing. This is to ensure the client will
         // effectively get the latency it requested.
         track->mFillingUpStatus = Track::FS_FILLING;
+        track->mResetDone = false;
         mActiveTracks.add(track);
         return NO_ERROR;
     }
@@ -771,7 +900,7 @@
     if (t!=NULL) {
         t->reset();
     }
-    audioMixer().deleteTrackName(name);
+    audioMixer()->deleteTrackName(name);
     mActiveTracks.remove(track);
     mWaitWorkCV.broadcast();
 }
@@ -789,7 +918,7 @@
     if (mActiveTracks.indexOf(track) < 0) {
         LOGV("remove track (%d) and delete from mixer", track->name());
         mTracks.remove(track);
-        audioMixer().deleteTrackName(keep->name());
+        audioMixer()->deleteTrackName(keep->name());
     }
 }
 
@@ -823,38 +952,53 @@
             uint32_t sampleRate,
             int format,
             int channelCount,
-            int bufferCount,
-            int bufferSize)
+            int frameCount,
+            const sp<IMemory>& sharedBuffer)
     :   RefBase(),
         mAudioFlinger(audioFlinger),
         mClient(client),
         mStreamType(streamType),
-        mFormat(format),
-        mChannelCount(channelCount),
-        mBufferCount(bufferCount),
-        mFlags(0),
-        mBufferSize(bufferSize),
+        mFrameCount(0),
         mState(IDLE),
-        mClientTid(-1)
+        mClientTid(-1),
+        mFormat(format),
+        mFlags(0)
 {
-    mName = audioFlinger->audioMixer().getTrackName();
+    mName = audioFlinger->audioMixer()->getTrackName();
     if (mName < 0) {
         LOGE("no more track names availlable");
         return;
     }
 
+    LOGV_IF(sharedBuffer != 0, "sharedBuffer: %p, size: %d", sharedBuffer->pointer(), sharedBuffer->size());
+
+
     // LOGD("Creating track with %d buffers @ %d bytes", bufferCount, bufferSize);
-    size_t size = sizeof(audio_track_cblk_t) + bufferCount * bufferSize;
+   size_t size = sizeof(audio_track_cblk_t);
+   size_t bufferSize = frameCount*channelCount*sizeof(int16_t);
+   if (sharedBuffer == 0) {
+       size += bufferSize;
+   }
+
     mCblkMemory = client->heap()->allocate(size);
     if (mCblkMemory != 0) {
         mCblk = static_cast<audio_track_cblk_t *>(mCblkMemory->pointer());
         if (mCblk) { // construct the shared structure in-place.
             new(mCblk) audio_track_cblk_t();
             // clear all buffers
-            mCblk->size = bufferSize;
+            mCblk->frameCount = frameCount;
             mCblk->sampleRate = sampleRate;
-            mBuffers = (char*)mCblk + sizeof(audio_track_cblk_t);
-            memset(mBuffers, 0, bufferCount * bufferSize);
+            mCblk->channels = channelCount;
+            if (sharedBuffer == 0) {
+                mBuffer = (char*)mCblk + sizeof(audio_track_cblk_t);
+                memset(mBuffer, 0, frameCount*channelCount*sizeof(int16_t));
+                // Force underrun condition to avoid false underrun callback until first data is
+                // written to buffer
+                mCblk->flowControlFlag = 1;
+            } else {
+                mBuffer = sharedBuffer->pointer();
+            }
+            mBufferEnd = (uint8_t *)mBuffer + bufferSize;
         }
     } else {
         LOGE("not enough memory for AudioTrack size=%u", size);
@@ -873,15 +1017,16 @@
 void AudioFlinger::TrackBase::releaseBuffer(AudioBufferProvider::Buffer* buffer)
 {
     buffer->raw = 0;
-    buffer->frameCount = 0;
+    mFrameCount = buffer->frameCount;
     step();
+    buffer->frameCount = 0;
 }
 
 bool AudioFlinger::TrackBase::step() {
     bool result;
     audio_track_cblk_t* cblk = this->cblk();
-    
-    result = cblk->stepServer(bufferCount()); 
+
+    result = cblk->stepServer(mFrameCount);
     if (!result) {
         LOGV("stepServer failed acquiring cblk mutex");
         mFlags |= STEPSERVER_FAILED;
@@ -894,7 +1039,10 @@
 
     cblk->user = 0;
     cblk->server = 0;
-    mFlags = 0;    
+    cblk->userBase = 0;
+    cblk->serverBase = 0;
+    mFlags = 0;
+    LOGV("TrackBase::reset");
 }
 
 sp<IMemory> AudioFlinger::TrackBase::getCblk() const
@@ -906,6 +1054,27 @@
     return mCblk->sampleRate;
 }
 
+int AudioFlinger::TrackBase::channelCount() const {
+    return mCblk->channels;
+}
+
+void* AudioFlinger::TrackBase::getBuffer(uint32_t offset, uint32_t frames) const {
+    audio_track_cblk_t* cblk = this->cblk();
+    int16_t *bufferStart = (int16_t *)mBuffer + (offset-cblk->serverBase)*cblk->channels;
+    int16_t *bufferEnd = bufferStart + frames * cblk->channels;
+
+    // Check validity of returned pointer in case the track control block would have been corrupted.
+    if (bufferStart < mBuffer || bufferStart > bufferEnd || bufferEnd > mBufferEnd) {
+        LOGW("TrackBase::getBuffer buffer out of range:\n    start: %p, end %p , mBuffer %p mBufferEnd %p\n    \
+                server %d, serverBase %d, user %d, userBase %d",
+                bufferStart, bufferEnd, mBuffer, mBufferEnd,
+                cblk->server, cblk->serverBase, cblk->user, cblk->userBase);
+        return 0;
+    }
+
+    return bufferStart;
+}
+
 // ----------------------------------------------------------------------------
 
 AudioFlinger::Track::Track(
@@ -915,13 +1084,14 @@
             uint32_t sampleRate,
             int format,
             int channelCount,
-            int bufferCount,
-            int bufferSize)
-    :   TrackBase(audioFlinger, client, streamType, sampleRate, format, channelCount, bufferCount, bufferSize)
+            int frameCount,
+            const sp<IMemory>& sharedBuffer)
+    :   TrackBase(audioFlinger, client, streamType, sampleRate, format, channelCount, frameCount, sharedBuffer)
 {
     mVolume[0] = 1.0f;
     mVolume[1] = 1.0f;
     mMute = false;
+    mSharedBuffer = sharedBuffer;
 }
 
 AudioFlinger::Track::~Track()
@@ -943,8 +1113,8 @@
             mClient->pid(),
             mStreamType,
             mFormat,
-            mChannelCount,
-            mBufferCount,
+            mCblk->channels,
+            mFrameCount,
             mState,
             mMute,
             mFillingUpStatus,
@@ -958,36 +1128,50 @@
 status_t AudioFlinger::Track::getNextBuffer(AudioBufferProvider::Buffer* buffer)
 {
      audio_track_cblk_t* cblk = this->cblk();
-     uint32_t u = cblk->user;
-     uint32_t s = cblk->server;
-     
-     // Check if last stepServer failed, try to step now 
+     uint32_t framesReady;
+     uint32_t framesReq = buffer->frameCount;
+
+     // Check if last stepServer failed, try to step now
      if (mFlags & TrackBase::STEPSERVER_FAILED) {
          if (!step())  goto getNextBuffer_exit;
          LOGV("stepServer recovered");
          mFlags &= ~TrackBase::STEPSERVER_FAILED;
      }
 
-     if (LIKELY(u > s)) {
-         int index = s & audio_track_cblk_t::BUFFER_MASK;
-         buffer->raw = getBuffer(index);
-         buffer->frameCount = mAudioFlinger->frameCount();
-         return NO_ERROR;
+     framesReady = cblk->framesReady();
+
+     if (LIKELY(framesReady)) {
+        uint32_t s = cblk->server;
+        uint32_t bufferEnd = cblk->serverBase + cblk->frameCount;
+
+        bufferEnd = (cblk->loopEnd < bufferEnd) ? cblk->loopEnd : bufferEnd;
+        if (framesReq > framesReady) {
+            framesReq = framesReady;
+        }
+        if (s + framesReq > bufferEnd) {
+            framesReq = bufferEnd - s;
+        }
+
+         buffer->raw = getBuffer(s, framesReq);
+         if (buffer->raw == 0) goto getNextBuffer_exit;
+
+         buffer->frameCount = framesReq;
+        return NO_ERROR;
      }
+
 getNextBuffer_exit:
      buffer->raw = 0;
      buffer->frameCount = 0;
      return NOT_ENOUGH_DATA;
 }
 
-bool AudioFlinger::Track::isReady(uint32_t u, int32_t s) const {
+bool AudioFlinger::Track::isReady() const {
     if (mFillingUpStatus != FS_FILLING) return true;
-    const uint32_t u_seq = u & audio_track_cblk_t::SEQUENCE_MASK;
-    const uint32_t u_buf = u & audio_track_cblk_t::BUFFER_MASK;
-    const uint32_t s_seq = s & audio_track_cblk_t::SEQUENCE_MASK;
-    const uint32_t s_buf = s & audio_track_cblk_t::BUFFER_MASK;
-    if (u_seq > s_seq && u_buf == s_buf) {
+
+    if (mCblk->framesReady() >= mCblk->frameCount ||
+        mCblk->forceReady) {
         mFillingUpStatus = FS_FILLED;
+        mCblk->forceReady = 0;
         return true;
     }
     return false;
@@ -1006,7 +1190,7 @@
     Mutex::Autolock _l(mAudioFlinger->mLock);
     if (mState > STOPPED) {
         mState = STOPPED;
-        // If the track is not active (PAUSED and buffers full), flush buffers  
+        // If the track is not active (PAUSED and buffers full), flush buffers
         if (mAudioFlinger->mActiveTracks.indexOf(this) < 0) {
             reset();
         }
@@ -1038,15 +1222,24 @@
     // NOTE: reset() will reset cblk->user and cblk->server with
     // the risk that at the same time, the AudioMixer is trying to read
     // data. In this case, getNextBuffer() would return a NULL pointer
-    // as audio buffer => the AudioMixer code MUST always test that pointer 
-    // returned by getNextBuffer() is not NULL! 
+    // as audio buffer => the AudioMixer code MUST always test that pointer
+    // returned by getNextBuffer() is not NULL!
     reset();
 }
 
 void AudioFlinger::Track::reset()
 {
-    TrackBase::reset();
-    mFillingUpStatus = FS_FILLING;
+    // Do not reset twice to avoid discarding data written just after a flush and before
+    // the audioflinger thread detects the track is stopped.
+    if (!mResetDone) {
+        TrackBase::reset();
+        // Force underrun condition to avoid false underrun callback until first data is
+        // written to buffer
+        mCblk->flowControlFlag = 1;
+        mCblk->forceReady = 0;
+        mFillingUpStatus = FS_FILLING;        
+        mResetDone = true;
+    }
 }
 
 void AudioFlinger::Track::mute(bool muted)
@@ -1112,26 +1305,15 @@
 
 // ----------------------------------------------------------------------------
 
-sp<AudioFlinger::AudioRecordThread> AudioFlinger::audioRecordThread()
-{
-    Mutex::Autolock _l(mLock);
-    return mAudioRecordThread;
-}
-
-void AudioFlinger::endRecord()
-{
-    Mutex::Autolock _l(mLock);
-    mAudioRecordThread.clear();
-}
-
 sp<IAudioRecord> AudioFlinger::openRecord(
         pid_t pid,
         int streamType,
         uint32_t sampleRate,
         int format,
         int channelCount,
-        int bufferCount,
-        uint32_t flags)
+        int frameCount,
+        uint32_t flags,
+        status_t *status)
 {
     sp<AudioRecordThread> thread;
     sp<RecordTrack> recordTrack;
@@ -1139,46 +1321,46 @@
     sp<Client> client;
     wp<Client> wclient;
     AudioStreamIn* input = 0;
+    int inFrameCount;
+    size_t inputBufferSize;
+    status_t lStatus;
 
     // check calling permissions
     if (!recordingAllowed()) {
+        lStatus = PERMISSION_DENIED;
         goto Exit;
     }
 
     if (uint32_t(streamType) >= AudioRecord::NUM_STREAM_TYPES) {
         LOGE("invalid stream type");
+        lStatus = BAD_VALUE;
         goto Exit;
     }
 
     if (sampleRate > MAX_SAMPLE_RATE) {
         LOGE("Sample rate out of range");
+        lStatus = BAD_VALUE;
         goto Exit;
     }
 
     if (mSampleRate == 0) {
         LOGE("Audio driver not initialized");
+        lStatus = NO_INIT;
         goto Exit;
     }
 
-    // Create audio thread - take mutex to prevent race condition
-    {
-        Mutex::Autolock _l(mLock);
-        if (mAudioRecordThread != 0) {
-            LOGE("Record channel already open");
-            goto Exit;
-        }
-        thread = new AudioRecordThread(this);
-        mAudioRecordThread = thread;
+    if (mAudioRecordThread == 0) {
+        LOGE("Audio record thread not started");
+        lStatus = NO_INIT;
+        goto Exit;
     }
-    // It's safe to release the mutex here since the client doesn't get a
-    // handle until we return from this call
 
-    // open driver, initialize h/w
-    input = mAudioHardware->openInputStream(
-            AudioSystem::PCM_16_BIT, channelCount, sampleRate);
-    if (!input) {
-        LOGE("Error opening input stream");
-        mAudioRecordThread.clear();
+
+    // Check that audio input stream accepts requested audio parameters 
+    inputBufferSize = mAudioHardware->getInputBufferSize(sampleRate, format, channelCount);
+    if (inputBufferSize == 0) {
+        lStatus = BAD_VALUE;
+        LOGE("Bad audio input parameters: sampling rate %u, format %d, channels %d",  sampleRate, format, channelCount);
         goto Exit;
     }
 
@@ -1194,37 +1376,38 @@
         }
     }
 
+    // frameCount must be a multiple of input buffer size
+    inFrameCount = inputBufferSize/channelCount/sizeof(short);
+    frameCount = ((frameCount - 1)/inFrameCount + 1) * inFrameCount;
+
     // create new record track and pass to record thread
     recordTrack = new RecordTrack(this, client, streamType, sampleRate,
-            format, channelCount, bufferCount, input->bufferSize());
-
-    // spin up record thread
-    thread->open(recordTrack, input);
-    thread->run("AudioRecordThread", PRIORITY_URGENT_AUDIO);
+            format, channelCount, frameCount);
 
     // return to handle to client
     recordHandle = new RecordHandle(recordTrack);
+    lStatus = NO_ERROR;
 
 Exit:
+    if (status) {
+        *status = lStatus;
+    }
     return recordHandle;
 }
 
-status_t AudioFlinger::startRecord() {
-    sp<AudioRecordThread> t = audioRecordThread();
-    if (t == 0) return NO_INIT;
-    return t->start();
+status_t AudioFlinger::startRecord(RecordTrack* recordTrack) {
+    if (mAudioRecordThread != 0) {
+        return mAudioRecordThread->start(recordTrack);        
+    }
+    return NO_INIT;
 }
 
-void AudioFlinger::stopRecord() {
-    sp<AudioRecordThread> t = audioRecordThread();
-    if (t != 0) t->stop();
+void AudioFlinger::stopRecord(RecordTrack* recordTrack) {
+    if (mAudioRecordThread != 0) {
+        mAudioRecordThread->stop(recordTrack);
+    }
 }
 
-void AudioFlinger::exitRecord()
-{
-    sp<AudioRecordThread> t = audioRecordThread();
-    if (t != 0) t->exit();
-}
 
 // ----------------------------------------------------------------------------
 
@@ -1235,55 +1418,69 @@
             uint32_t sampleRate,
             int format,
             int channelCount,
-            int bufferCount,
-            int bufferSize)
+            int frameCount)
     :   TrackBase(audioFlinger, client, streamType, sampleRate, format,
-            channelCount, bufferCount, bufferSize),
+            channelCount, frameCount, 0),
             mOverflow(false)
 {
 }
 
 AudioFlinger::RecordTrack::~RecordTrack()
 {
-    mAudioFlinger->audioMixer().deleteTrackName(mName);
-    mAudioFlinger->exitRecord();
+    mAudioFlinger->audioMixer()->deleteTrackName(mName);
 }
 
 status_t AudioFlinger::RecordTrack::getNextBuffer(AudioBufferProvider::Buffer* buffer)
 {
-     audio_track_cblk_t* cblk = this->cblk();
-     const uint32_t u_seq = cblk->user & audio_track_cblk_t::SEQUENCE_MASK;
-     const uint32_t u_buf = cblk->user & audio_track_cblk_t::BUFFER_MASK;
-     const uint32_t s_seq = cblk->server & audio_track_cblk_t::SEQUENCE_MASK;
-     const uint32_t s_buf = cblk->server & audio_track_cblk_t::BUFFER_MASK;
-     
-     // Check if last stepServer failed, try to step now 
-     if (mFlags & TrackBase::STEPSERVER_FAILED) {
-         if (!step())  goto getNextBuffer_exit;
-         LOGV("stepServer recovered");
-         mFlags &= ~TrackBase::STEPSERVER_FAILED;
-     }
+    audio_track_cblk_t* cblk = this->cblk();
+    uint32_t framesAvail;
+    uint32_t framesReq = buffer->frameCount;
 
-     if (LIKELY(s_seq == u_seq || s_buf != u_buf)) {
-         buffer->raw = getBuffer(s_buf);
-         buffer->frameCount = mAudioFlinger->frameCount();
-         return NO_ERROR;
-     }
+     // Check if last stepServer failed, try to step now
+    if (mFlags & TrackBase::STEPSERVER_FAILED) {
+        if (!step()) goto getNextBuffer_exit;
+        LOGV("stepServer recovered");
+        mFlags &= ~TrackBase::STEPSERVER_FAILED;
+    }
 
-getNextBuffer_exit:     
-     buffer->raw = 0;
-     buffer->frameCount = 0;
-     return NOT_ENOUGH_DATA;
+    framesAvail = cblk->framesAvailable_l();
+
+    if (LIKELY(framesAvail)) {
+        uint32_t s = cblk->server;
+        uint32_t bufferEnd = cblk->serverBase + cblk->frameCount;
+
+        if (framesReq > framesAvail) {
+            framesReq = framesAvail;
+        }
+        if (s + framesReq > bufferEnd) {
+            framesReq = bufferEnd - s;
+        }
+
+        buffer->raw = getBuffer(s, framesReq);
+        if (buffer->raw == 0) goto getNextBuffer_exit;
+
+        buffer->frameCount = framesReq;
+        return NO_ERROR;
+    }
+
+getNextBuffer_exit:
+    buffer->raw = 0;
+    buffer->frameCount = 0;
+    return NOT_ENOUGH_DATA;
 }
 
 status_t AudioFlinger::RecordTrack::start()
 {
-    return mAudioFlinger->startRecord();
+    return mAudioFlinger->startRecord(this);
 }
 
 void AudioFlinger::RecordTrack::stop()
 {
-    mAudioFlinger->stopRecord();
+    mAudioFlinger->stopRecord(this);
+    TrackBase::reset();
+    // Force overerrun condition to avoid false overrun callback until first data is
+    // read from buffer
+    mCblk->flowControlFlag = 1;
 }
 
 // ----------------------------------------------------------------------------
@@ -1294,7 +1491,9 @@
 {
 }
 
-AudioFlinger::RecordHandle::~RecordHandle() {}
+AudioFlinger::RecordHandle::~RecordHandle() {
+    stop();
+}
 
 status_t AudioFlinger::RecordHandle::start() {
     LOGV("RecordHandle::start()");
@@ -1318,10 +1517,8 @@
 
 // ----------------------------------------------------------------------------
 
-AudioFlinger::AudioRecordThread::AudioRecordThread(const sp<AudioFlinger>& audioFlinger) :
-    mAudioFlinger(audioFlinger),
-    mRecordTrack(0),
-    mInput(0),
+AudioFlinger::AudioRecordThread::AudioRecordThread(AudioHardwareInterface* audioHardware) :
+    mAudioHardware(audioHardware),
     mActive(false)
 {
 }
@@ -1333,108 +1530,123 @@
 bool AudioFlinger::AudioRecordThread::threadLoop()
 {
     LOGV("AudioRecordThread: start record loop");
+    AudioBufferProvider::Buffer buffer;
+    int inBufferSize = 0;
+    int inFrameCount = 0;
+    AudioStreamIn* input = 0;
 
+    mActive = 0;
+    
     // start recording
     while (!exitPending()) {
         if (!mActive) {
             mLock.lock();
             if (!mActive && !exitPending()) {
                 LOGV("AudioRecordThread: loop stopping");
+                if (input) {
+                    delete input;
+                    input = 0;
+                }
+                mRecordTrack.clear();
+
                 mWaitWorkCV.wait(mLock);
+               
                 LOGV("AudioRecordThread: loop starting");
+                if (mRecordTrack != 0) {
+                    input = mAudioHardware->openInputStream(mRecordTrack->format(), 
+                                            mRecordTrack->channelCount(), 
+                                            mRecordTrack->sampleRate(), 
+                                            &mStartStatus);
+                    if (input != 0) {
+                        inBufferSize = input->bufferSize();
+                        inFrameCount = inBufferSize/input->frameSize();                        
+                    }
+                } else {
+                    mStartStatus = NO_INIT;
+                }
+                if (mStartStatus !=NO_ERROR) {
+                    LOGW("record start failed, status %d", mStartStatus);
+                    mActive = false;
+                    mRecordTrack.clear();                    
+                }
+                mWaitWorkCV.signal();
             }
             mLock.unlock();
-        } else {
-            // promote strong ref so track isn't deleted while we access it
-            sp<RecordTrack> t = mRecordTrack.promote();
+        } else if (mRecordTrack != 0){
 
-            // if we lose the weak reference, client is gone.
-            if (t == 0) {
-                LOGV("AudioRecordThread: client deleted track");
-                break;
-            }
-
-            if (LIKELY(t->getNextBuffer(&mBuffer) == NO_ERROR)) {
-                if (mInput->read(mBuffer.raw, t->mBufferSize) < 0) {
+            buffer.frameCount = inFrameCount;
+            if (LIKELY(mRecordTrack->getNextBuffer(&buffer) == NO_ERROR)) {
+                LOGV("AudioRecordThread read: %d frames", buffer.frameCount);
+                if (input->read(buffer.raw, inBufferSize) < 0) {
                     LOGE("Error reading audio input");
                     sleep(1);
                 }
-                t->releaseBuffer(&mBuffer);
+                mRecordTrack->releaseBuffer(&buffer);
+                mRecordTrack->overflow();
             }
 
             // client isn't retrieving buffers fast enough
             else {
-                if (!t->setOverflow())
+                if (!mRecordTrack->setOverflow())
                     LOGW("AudioRecordThread: buffer overflow");
+                // Release the processor for a while before asking for a new buffer.
+                // This will give the application more chance to read from the buffer and
+                // clear the overflow.
+                usleep(5000);
             }
         }
-    };
+    }
 
-    // close hardware
-    close();
 
-    // delete this object - no more data references after this call
-    mAudioFlinger->endRecord();
+    if (input) {
+        delete input;
+    }
+    mRecordTrack.clear();
+    
     return false;
 }
 
-status_t AudioFlinger::AudioRecordThread::open(const sp<RecordTrack>& recordTrack, AudioStreamIn *input) {
-    LOGV("AudioRecordThread::open");
-    // check for record channel already open
-    AutoMutex lock(&mLock);
-    if (mRecordTrack != NULL) {
-        LOGE("Record channel already open");
-        return ALREADY_EXISTS;
-    }
-    mRecordTrack = recordTrack;
-    mInput = input;
-    return NO_ERROR;
-}
-
-status_t AudioFlinger::AudioRecordThread::start()
+status_t AudioFlinger::AudioRecordThread::start(RecordTrack* recordTrack)
 {
     LOGV("AudioRecordThread::start");
     AutoMutex lock(&mLock);
-    if (mActive) return -EBUSY;
+    mActive = true;
+    // If starting the active track, just reset mActive in case a stop
+    // was pending and exit
+    if (recordTrack == mRecordTrack.get()) return NO_ERROR;
 
-    sp<RecordTrack> t = mRecordTrack.promote();
-    if (t == 0) return UNKNOWN_ERROR;
+    if (mRecordTrack != 0) return -EBUSY;
+
+    mRecordTrack = recordTrack;
 
     // signal thread to start
     LOGV("Signal record thread");
-    mActive = true;
     mWaitWorkCV.signal();
-    return NO_ERROR;
+    mWaitWorkCV.wait(mLock);
+    LOGV("Record started, status %d", mStartStatus);
+    return mStartStatus;
 }
 
-void AudioFlinger::AudioRecordThread::stop() {
+void AudioFlinger::AudioRecordThread::stop(RecordTrack* recordTrack) {
     LOGV("AudioRecordThread::stop");
     AutoMutex lock(&mLock);
-    if (mActive) {
+    if (mActive && (recordTrack == mRecordTrack.get())) {
         mActive = false;
-        mWaitWorkCV.signal();
     }
 }
 
 void AudioFlinger::AudioRecordThread::exit()
 {
     LOGV("AudioRecordThread::exit");
-    AutoMutex lock(&mLock);
-    requestExit();
-    mWaitWorkCV.signal();
+    {
+        AutoMutex lock(&mLock);
+        requestExit();
+        mWaitWorkCV.signal();
+    }
+    requestExitAndWait();
 }
 
 
-status_t AudioFlinger::AudioRecordThread::close()
-{
-    LOGV("AudioRecordThread::close");
-    AutoMutex lock(&mLock);
-    if (!mInput) return NO_INIT;
-    delete mInput;
-    mInput = 0;
-    return NO_ERROR;
-}
-
 status_t AudioFlinger::onTransact(
         uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
 {