auto import from //branches/cupcake/...@130745
diff --git a/libs/audioflinger/A2dpAudioInterface.cpp b/libs/audioflinger/A2dpAudioInterface.cpp
index c8c8431..3c18036 100644
--- a/libs/audioflinger/A2dpAudioInterface.cpp
+++ b/libs/audioflinger/A2dpAudioInterface.cpp
@@ -99,6 +99,10 @@
     if (strcmp(key, "a2dp_sink_address") == 0) {        
         return mOutput->setAddress(value);
     }
+    if (strcmp(key, "bluetooth_enabled") == 0 &&
+        strcmp(value, "false") == 0) {
+        return mOutput->close();
+    }
 
     return 0;
 }
@@ -154,8 +158,7 @@
 
 A2dpAudioInterface::A2dpAudioStreamOut::~A2dpAudioStreamOut()
 {
-    if (mData)
-        a2dp_cleanup(mData);
+    close();
 }
 
 ssize_t A2dpAudioInterface::A2dpAudioStreamOut::write(const void* buffer, size_t bytes)
@@ -186,7 +189,8 @@
     
     return bytes;
 
-Error:   
+Error:
+    close();
     // Simulate audio output timing in case of error
     usleep(bytes * 1000000 / frameSize() / sampleRate());
 
@@ -213,17 +217,22 @@
 
     if (strcmp(address, mA2dpAddress)) {
         strcpy(mA2dpAddress, address);
-        
-        if (mInitialized) {
-            a2dp_cleanup(mData);
-            mData = NULL;
-            mInitialized = false;
-        }
+        close();
     }
     
     return NO_ERROR;
 }
 
+status_t A2dpAudioInterface::A2dpAudioStreamOut::close()
+{
+    if (mData) {
+        a2dp_cleanup(mData);
+        mData = NULL;
+        mInitialized = false;
+    }
+    return NO_ERROR;
+}
+
 status_t A2dpAudioInterface::A2dpAudioStreamOut::dump(int fd, const Vector<String16>& args)
 {
     return NO_ERROR;
diff --git a/libs/audioflinger/A2dpAudioInterface.h b/libs/audioflinger/A2dpAudioInterface.h
index 2197d0e..38ba684 100644
--- a/libs/audioflinger/A2dpAudioInterface.h
+++ b/libs/audioflinger/A2dpAudioInterface.h
@@ -77,10 +77,11 @@
         virtual size_t      bufferSize() const { return 512 * 20; }
         virtual int         channelCount() const { return 2; }
         virtual int         format() const { return AudioSystem::PCM_16_BIT; }
-        virtual uint32_t    latency() const { return ((1000*channelCount()*bufferSize())/frameSize())/sampleRate() + 200; }
+        virtual uint32_t    latency() const { return ((1000*bufferSize())/frameSize())/sampleRate() + 200; }
         virtual status_t    setVolume(float volume) { return INVALID_OPERATION; }
         virtual ssize_t     write(const void* buffer, size_t bytes);
                 status_t    standby();
+                status_t    close();
         virtual status_t    dump(int fd, const Vector<String16>& args);
 
     private:
diff --git a/libs/audioflinger/AudioFlinger.cpp b/libs/audioflinger/AudioFlinger.cpp
index c330bc8..017a298 100644
--- a/libs/audioflinger/AudioFlinger.cpp
+++ b/libs/audioflinger/AudioFlinger.cpp
@@ -183,6 +183,7 @@
 void AudioFlinger::setOutput(AudioStreamOut* output)
 {
     mRequestedOutput = output;
+    mWaitWorkCV.broadcast();
 }
 
 void AudioFlinger::doSetOutput(AudioStreamOut* output)
@@ -198,6 +199,7 @@
     mFrameCount = getOutputFrameCount(output);
     mAudioMixer = (output == mA2dpOutput ? mA2dpAudioMixer : mHardwareAudioMixer);
     mOutput = output;
+    notifyOutputChange_l();
 }
 
 size_t AudioFlinger::getOutputFrameCount(AudioStreamOut* output) 
@@ -211,6 +213,8 @@
     return (streamType == AudioTrack::SYSTEM ||
             streamType == AudioTrack::RING ||
             streamType == AudioTrack::ALARM ||
+            streamType == AudioTrack::VOICE_CALL ||
+            streamType == AudioTrack::BLUETOOTH_SCO ||
             streamType == AudioTrack::NOTIFICATION);
 }
 
@@ -344,7 +348,8 @@
     int16_t* curBuf = mMixBuffer;
     Vector< sp<Track> > tracksToRemove;
     size_t enabledTracks = 0;
-    nsecs_t standbyTime = systemTime();
+    nsecs_t standbyTime = systemTime();    
+    nsecs_t outputSwitchStandbyTime = 0;
 
     do {
         enabledTracks = 0;
@@ -362,6 +367,11 @@
                     mOutput->standby();
                     mStandby = true;
                 }
+                if (outputSwitchStandbyTime) {
+                    AudioStreamOut *output = (mOutput == mHardwareOutput) ? mA2dpOutput : mHardwareOutput;
+                    output->standby();
+                    outputSwitchStandbyTime = 0;
+                }
                 mHardwareStatus = AUDIO_HW_IDLE;
                 // we're about to wait, flush the binder command buffer
                 IPCThreadState::self()->flushCommands();
@@ -375,11 +385,18 @@
             if (mRequestedOutput != mOutput) {
 
                 // put current output into standby mode
-                if (mOutput) mOutput->standby();
+                if (mOutput) {
+                    outputSwitchStandbyTime = systemTime() + milliseconds(mOutput->latency());
+                }
 
                 // change output
                 doSetOutput(mRequestedOutput);
             }
+            if (outputSwitchStandbyTime && systemTime() > outputSwitchStandbyTime) {
+                AudioStreamOut *output = (mOutput == mHardwareOutput) ? mA2dpOutput : mHardwareOutput;
+                output->standby();
+                outputSwitchStandbyTime = 0;
+            }
 
             // find out which tracks need to be processed
             size_t count = activeTracks.size();
@@ -481,7 +498,7 @@
                     removeActiveTrack(track);
                     if (track->isTerminated()) {
                         mTracks.remove(track);
-                        mAudioMixer->deleteTrackName(track->mName);
+                        deleteTrackName(track->mName);
                     }
                 }
             }  
@@ -512,7 +529,7 @@
             // 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);
+//            LOGV("no buffers - usleep(%lu)", sleepTime);
             usleep(sleepTime);
             if (sleepTime < kMaxBufferRecoveryInUsecs) {
                 sleepTime += kBufferRecoveryInUsecs;
@@ -802,12 +819,14 @@
 
     mStreamTypes[stream].volume = value;
     status_t ret = NO_ERROR;
-    if (stream == AudioTrack::VOICE_CALL) {
+    if (stream == AudioTrack::VOICE_CALL ||
+        stream == AudioTrack::BLUETOOTH_SCO) {
         AutoMutex lock(mHardwareLock);
         mHardwareStatus = AUDIO_SET_VOICE_VOLUME;
         ret = mAudioHardware->setVoiceVolume(value);
         mHardwareStatus = AUDIO_HW_IDLE;
     }
+
     return ret;
 }
 
@@ -821,7 +840,20 @@
     if (uint32_t(stream) >= AudioTrack::NUM_STREAM_TYPES) {
         return BAD_VALUE;
     }
+#ifdef WITH_A2DP
+    if (stream == AudioTrack::MUSIC) 
+    {
+        AutoMutex lock(&mLock);
+        if (mA2dpDisableCount > 0)
+            mMusicMuteSaved = muted;
+        else
+            mStreamTypes[stream].mute = muted;
+    } else {
+        mStreamTypes[stream].mute = muted;
+    }
+#else
     mStreamTypes[stream].mute = muted;
+#endif
     return NO_ERROR;
 }
 
@@ -838,6 +870,12 @@
     if (uint32_t(stream) >= AudioTrack::NUM_STREAM_TYPES) {
         return true;
     }
+#ifdef WITH_A2DP
+    if (stream == AudioTrack::MUSIC && mA2dpDisableCount > 0) 
+    {
+        return mMusicMuteSaved;
+    }
+#endif
     return mStreamTypes[stream].mute;
 }
 
@@ -869,6 +907,59 @@
     return result;
 }
 
+
+void AudioFlinger::registerClient(const sp<IAudioFlingerClient>& client)
+{
+    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);
+    }
+}
+
+
+size_t AudioFlinger::getInputBufferSize(uint32_t sampleRate, int format, int channelCount)
+{
+    return mAudioHardware->getInputBufferSize(sampleRate, format, channelCount);
+}
+
+void AudioFlinger::wakeUp()
+{
+    mWaitWorkCV.broadcast();
+}
+
+void AudioFlinger::binderDied(const wp<IBinder>& who) {
+    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);
+        }
+    }
+}
+
+// must be called with mLock held
+void AudioFlinger::notifyOutputChange_l()
+{
+    size_t size = mNotificationClients.size();
+    uint32_t latency = mOutput->latency();
+    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->audioOutputChanged(mFrameCount, mSampleRate, latency);
+        }
+    }
+}
+
 void AudioFlinger::removeClient(pid_t pid)
 {
     Mutex::Autolock _l(mLock);
@@ -920,7 +1011,7 @@
     if (t!=NULL) {
         t->reset();
     }
-    audioMixer()->deleteTrackName(name);
+    deleteTrackName(name);
     removeActiveTrack(track);
     mWaitWorkCV.broadcast();
 }
@@ -938,7 +1029,7 @@
     if (mActiveTracks.indexOf(track) < 0) {
         LOGV("remove track (%d) and delete from mixer", track->name());
         mTracks.remove(track);
-        audioMixer()->deleteTrackName(keep->name());
+        deleteTrackName(keep->name());
     }
 }
 
@@ -953,9 +1044,11 @@
         if (mA2dpDisableCount++ == 0 && isA2dpEnabled()) {
             setA2dpEnabled(false);
             mA2dpSuppressed = true;
-            LOGD("mA2dpSuppressed = true\n");
+            mMusicMuteSaved = mStreamTypes[AudioTrack::MUSIC].mute;
+            mStreamTypes[AudioTrack::MUSIC].mute = true;
+            LOGV("mA2dpSuppressed = true, track %d\n", track->name());
         }
-        LOGD("mA2dpDisableCount incremented to %d\n", mA2dpDisableCount);
+        LOGV("mA2dpDisableCount incremented to %d, track %d\n", mA2dpDisableCount, track->name());
     }
 #endif
 }
@@ -969,17 +1062,45 @@
     if (streamDisablesA2dp(track->type())) {
         if (mA2dpDisableCount > 0) {
             mA2dpDisableCount--;
+            LOGV("mA2dpDisableCount decremented to %d, track %d\n", mA2dpDisableCount, track->name());
             if (mA2dpDisableCount == 0 && mA2dpSuppressed) {
                 setA2dpEnabled(true);
                 mA2dpSuppressed = false;
-            }
-            LOGD("mA2dpDisableCount decremented to %d\n", mA2dpDisableCount);
+                mStreamTypes[AudioTrack::MUSIC].mute = mMusicMuteSaved;
+                LOGV("mA2dpSuppressed = false, track %d\n", track->name());
+            }   
         } else
             LOGE("mA2dpDisableCount is already zero");
     }
 #endif
 }
 
+int AudioFlinger::getTrackName()
+{
+    // Both mixers must have the same set of track used to avoid mismatches when
+    // switching from A2DP output to hardware output
+    int a2DpName;
+    int hwName;
+#ifdef WITH_A2DP
+    a2DpName = mA2dpAudioMixer->getTrackName();
+#endif
+    hwName = mHardwareAudioMixer->getTrackName();
+    
+    LOGW_IF((a2DpName != hwName), "getTrackName track name mismatch! A2DP %d, HW %d", a2DpName, hwName);
+    
+    return hwName;
+}
+
+void AudioFlinger::deleteTrackName(int name)
+{
+    // Both mixers must have the same set of track used to avoid mismatches when
+    // switching from A2DP output to hardware output
+    mHardwareAudioMixer->deleteTrackName(name);
+#ifdef WITH_A2DP
+    mA2dpAudioMixer->deleteTrackName(name);
+#endif
+}
+
 // ----------------------------------------------------------------------------
 
 AudioFlinger::Client::Client(const sp<AudioFlinger>& audioFlinger, pid_t pid)
@@ -1022,7 +1143,8 @@
         mFormat(format),
         mFlags(0)
 {
-    mName = audioFlinger->audioMixer()->getTrackName();
+    mName = audioFlinger->getTrackName();
+    LOGV("TrackBase contructor name %d, calling thread %d", mName, IPCThreadState::self()->getCallingPid());
     if (mName < 0) {
         LOGE("no more track names availlable");
         return;
@@ -1237,14 +1359,14 @@
 
 status_t AudioFlinger::Track::start()
 {
-    LOGV("start(%d)", mName);
+    LOGV("start(%d), calling thread %d", mName, IPCThreadState::self()->getCallingPid());
     mAudioFlinger->addTrack(this);
     return NO_ERROR;
 }
 
 void AudioFlinger::Track::stop()
 {
-    LOGV("stop(%d)", mName);
+    LOGV("stop(%d), calling thread %d", mName, IPCThreadState::self()->getCallingPid());
     Mutex::Autolock _l(mAudioFlinger->mLock);
     if (mState > STOPPED) {
         mState = STOPPED;
@@ -1258,7 +1380,7 @@
 
 void AudioFlinger::Track::pause()
 {
-    LOGV("pause(%d)", mName);
+    LOGV("pause(%d), calling thread %d", mName, IPCThreadState::self()->getCallingPid());
     Mutex::Autolock _l(mAudioFlinger->mLock);
     if (mState == ACTIVE || mState == RESUMING) {
         mState = PAUSING;
@@ -1485,7 +1607,7 @@
 
 AudioFlinger::RecordTrack::~RecordTrack()
 {
-    mAudioFlinger->audioMixer()->deleteTrackName(mName);
+    mAudioFlinger->deleteTrackName(mName);
 }
 
 status_t AudioFlinger::RecordTrack::getNextBuffer(AudioBufferProvider::Buffer* buffer)
diff --git a/libs/audioflinger/AudioFlinger.h b/libs/audioflinger/AudioFlinger.h
index 9ab362a..38fa001 100644
--- a/libs/audioflinger/AudioFlinger.h
+++ b/libs/audioflinger/AudioFlinger.h
@@ -22,6 +22,7 @@
 #include <sys/types.h>
 
 #include <media/IAudioFlinger.h>
+#include <media/IAudioFlingerClient.h>
 #include <media/IAudioTrack.h>
 #include <media/IAudioRecord.h>
 #include <media/AudioTrack.h>
@@ -54,7 +55,7 @@
 
 static const nsecs_t kStandbyTimeInNsecs = seconds(3);
 
-class AudioFlinger : public BnAudioFlinger, protected Thread
+class AudioFlinger : public BnAudioFlinger, protected Thread, public IBinder::DeathRecipient 
 {
 public:
     static void instantiate();
@@ -109,6 +110,15 @@
 
     virtual     status_t    setParameter(const char* key, const char* value);
 
+    virtual     void        registerClient(const sp<IAudioFlingerClient>& client);
+    
+    virtual     size_t      getInputBufferSize(uint32_t sampleRate, int format, int channelCount);
+    
+    virtual     void        wakeUp();
+    
+    // IBinder::DeathRecipient
+    virtual     void        binderDied(const wp<IBinder>& who);
+
     enum hardware_call_state {
         AUDIO_HW_IDLE = 0,
         AUDIO_HW_INIT,
@@ -314,7 +324,7 @@
         virtual status_t getNextBuffer(AudioBufferProvider::Buffer* buffer);
 
         bool isMuted() const {
-            return mMute;
+            return (mMute || mAudioFlinger->mStreamTypes[mStreamType].mute);
         }
 
         bool isPausing() const {
@@ -382,6 +392,8 @@
                 void        destroyTrack(const sp<Track>& track);
                 void        addActiveTrack(const wp<Track>& track);
                 void        removeActiveTrack(const wp<Track>& track);
+                int         getTrackName();
+                void        deleteTrackName(int name);
 
                 AudioMixer* audioMixer() {
                     return mAudioMixer;
@@ -460,6 +472,8 @@
                 status_t    startRecord(RecordTrack* recordTrack);
                 void        stopRecord(RecordTrack* recordTrack);
 
+                void notifyOutputChange_l();
+
     mutable     Mutex                                       mHardwareLock;
     mutable     Mutex                                       mLock;
     mutable     Condition                                   mWaitWorkCV;
@@ -494,6 +508,8 @@
                 bool                                mInWrite;
                 int                                 mA2dpDisableCount;
                 bool                                mA2dpSuppressed;
+                bool                                mMusicMuteSaved;
+                SortedVector< wp<IBinder> >         mNotificationClients;
 };
 
 // ----------------------------------------------------------------------------