Merge "audioflinger: flush HAL when transitioning to next direct track" into mnc-dev
diff --git a/include/media/stagefright/foundation/ADebug.h b/include/media/stagefright/foundation/ADebug.h
index 24df85a..65f415a 100644
--- a/include/media/stagefright/foundation/ADebug.h
+++ b/include/media/stagefright/foundation/ADebug.h
@@ -117,7 +117,7 @@
 
     };
 
-    // parse the property or string to get the debug level for a component name
+    // parse the property or string to get a long-type level for a component name
     // string format is:
     // <level>[:<glob>][,<level>[:<glob>]...]
     // - <level> is 0-5 corresponding to ADebug::Level
@@ -125,10 +125,14 @@
     //   matches all components
     // - string is read left-to-right, and the last matching level is returned, or
     //   the def if no terms matched
+    static long GetLevelFromSettingsString(
+            const char *name, const char *value, long def);
+    static long GetLevelFromProperty(
+            const char *name, const char *value, long def);
+
+    // same for ADebug::Level - performs clamping to valid debug ranges
     static Level GetDebugLevelFromProperty(
             const char *name, const char *propertyName, Level def = kDebugNone);
-    static Level GetDebugLevelFromString(
-            const char *name, const char *value, Level def = kDebugNone);
 
     // remove redundant segments of a codec name, and return a newly allocated
     // string suitable for debugging
diff --git a/media/libmedia/AudioSystem.cpp b/media/libmedia/AudioSystem.cpp
index f13bcf3..3bfb09a 100644
--- a/media/libmedia/AudioSystem.cpp
+++ b/media/libmedia/AudioSystem.cpp
@@ -476,11 +476,13 @@
         switch (event) {
         case AUDIO_OUTPUT_OPENED:
         case AUDIO_INPUT_OPENED: {
-            if (getIoDescriptor(ioDesc->mIoHandle) != 0) {
-                ALOGV("ioConfigChanged() opening already existing output! %d", ioDesc->mIoHandle);
-                break;
+            sp<AudioIoDescriptor> oldDesc = getIoDescriptor(ioDesc->mIoHandle);
+            if (oldDesc == 0) {
+                mIoDescriptors.add(ioDesc->mIoHandle, ioDesc);
+            } else {
+                deviceId = oldDesc->getDeviceId();
+                mIoDescriptors.replaceValueFor(ioDesc->mIoHandle, ioDesc);
             }
-            mIoDescriptors.add(ioDesc->mIoHandle, ioDesc);
 
             if (ioDesc->getDeviceId() != AUDIO_PORT_HANDLE_NONE) {
                 deviceId = ioDesc->getDeviceId();
@@ -1074,7 +1076,14 @@
     if (afc == 0) {
         return NO_INIT;
     }
-    return afc->addAudioDeviceCallback(callback, audioIo);
+    status_t status = afc->addAudioDeviceCallback(callback, audioIo);
+    if (status == NO_ERROR) {
+        const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
+        if (af != 0) {
+            af->registerClient(afc);
+        }
+    }
+    return status;
 }
 
 status_t AudioSystem::removeAudioDeviceCallback(
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index ae869d6..0ecfb1e 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -1335,21 +1335,23 @@
       mCallbackCookie(NULL),
       mCallbackData(NULL),
       mBytesWritten(0),
+      mStreamType(AUDIO_STREAM_MUSIC),
+      mAttributes(attr),
+      mLeftVolume(1.0),
+      mRightVolume(1.0),
+      mPlaybackRate(AUDIO_PLAYBACK_RATE_DEFAULT),
+      mSampleRateHz(0),
+      mMsecsPerFrame(0),
+      mFrameSize(0),
       mSessionId(sessionId),
       mUid(uid),
       mPid(pid),
-      mFlags(AUDIO_OUTPUT_FLAG_NONE) {
+      mSendLevel(0.0),
+      mAuxEffectId(0),
+      mFlags(AUDIO_OUTPUT_FLAG_NONE)
+{
     ALOGV("AudioOutput(%d)", sessionId);
-    mStreamType = AUDIO_STREAM_MUSIC;
-    mLeftVolume = 1.0;
-    mRightVolume = 1.0;
-    mPlaybackRate = AUDIO_PLAYBACK_RATE_DEFAULT;
-    mSampleRateHz = 0;
-    mMsecsPerFrame = 0;
-    mAuxEffectId = 0;
-    mSendLevel = 0.0;
     setMinBufferCount();
-    mAttributes = attr;
 }
 
 MediaPlayerService::AudioOutput::~AudioOutput()
@@ -1358,6 +1360,7 @@
     delete mCallbackData;
 }
 
+//static
 void MediaPlayerService::AudioOutput::setMinBufferCount()
 {
     char value[PROPERTY_VALUE_MAX];
@@ -1367,92 +1370,105 @@
     }
 }
 
+// static
 bool MediaPlayerService::AudioOutput::isOnEmulator()
 {
-    setMinBufferCount();
+    setMinBufferCount(); // benign race wrt other threads
     return mIsOnEmulator;
 }
 
+// static
 int MediaPlayerService::AudioOutput::getMinBufferCount()
 {
-    setMinBufferCount();
+    setMinBufferCount(); // benign race wrt other threads
     return mMinBufferCount;
 }
 
 ssize_t MediaPlayerService::AudioOutput::bufferSize() const
 {
+    Mutex::Autolock lock(mLock);
     if (mTrack == 0) return NO_INIT;
-    return mTrack->frameCount() * frameSize();
+    return mTrack->frameCount() * mFrameSize;
 }
 
 ssize_t MediaPlayerService::AudioOutput::frameCount() const
 {
+    Mutex::Autolock lock(mLock);
     if (mTrack == 0) return NO_INIT;
     return mTrack->frameCount();
 }
 
 ssize_t MediaPlayerService::AudioOutput::channelCount() const
 {
+    Mutex::Autolock lock(mLock);
     if (mTrack == 0) return NO_INIT;
     return mTrack->channelCount();
 }
 
 ssize_t MediaPlayerService::AudioOutput::frameSize() const
 {
+    Mutex::Autolock lock(mLock);
     if (mTrack == 0) return NO_INIT;
-    return mTrack->frameSize();
+    return mFrameSize;
 }
 
 uint32_t MediaPlayerService::AudioOutput::latency () const
 {
+    Mutex::Autolock lock(mLock);
     if (mTrack == 0) return 0;
     return mTrack->latency();
 }
 
 float MediaPlayerService::AudioOutput::msecsPerFrame() const
 {
+    Mutex::Autolock lock(mLock);
     return mMsecsPerFrame;
 }
 
 status_t MediaPlayerService::AudioOutput::getPosition(uint32_t *position) const
 {
+    Mutex::Autolock lock(mLock);
     if (mTrack == 0) return NO_INIT;
     return mTrack->getPosition(position);
 }
 
 status_t MediaPlayerService::AudioOutput::getTimestamp(AudioTimestamp &ts) const
 {
+    Mutex::Autolock lock(mLock);
     if (mTrack == 0) return NO_INIT;
     return mTrack->getTimestamp(ts);
 }
 
 status_t MediaPlayerService::AudioOutput::getFramesWritten(uint32_t *frameswritten) const
 {
+    Mutex::Autolock lock(mLock);
     if (mTrack == 0) return NO_INIT;
-    *frameswritten = mBytesWritten / frameSize();
+    *frameswritten = mBytesWritten / mFrameSize;
     return OK;
 }
 
 status_t MediaPlayerService::AudioOutput::setParameters(const String8& keyValuePairs)
 {
+    Mutex::Autolock lock(mLock);
     if (mTrack == 0) return NO_INIT;
     return mTrack->setParameters(keyValuePairs);
 }
 
 String8  MediaPlayerService::AudioOutput::getParameters(const String8& keys)
 {
+    Mutex::Autolock lock(mLock);
     if (mTrack == 0) return String8::empty();
     return mTrack->getParameters(keys);
 }
 
 void MediaPlayerService::AudioOutput::setAudioAttributes(const audio_attributes_t * attributes) {
+    Mutex::Autolock lock(mLock);
     mAttributes = attributes;
 }
 
-void MediaPlayerService::AudioOutput::deleteRecycledTrack()
+void MediaPlayerService::AudioOutput::deleteRecycledTrack_l()
 {
-    ALOGV("deleteRecycledTrack");
-
+    ALOGV("deleteRecycledTrack_l");
     if (mRecycledTrack != 0) {
 
         if (mCallbackData != NULL) {
@@ -1470,12 +1486,17 @@
         // AudioFlinger to drain the track.
 
         mRecycledTrack.clear();
+        close_l();
         delete mCallbackData;
         mCallbackData = NULL;
-        close();
     }
 }
 
+void MediaPlayerService::AudioOutput::close_l()
+{
+    mTrack.clear();
+}
+
 status_t MediaPlayerService::AudioOutput::open(
         uint32_t sampleRate, int channelCount, audio_channel_mask_t channelMask,
         audio_format_t format, int bufferCount,
@@ -1535,6 +1556,7 @@
         }
     }
 
+    Mutex::Autolock lock(mLock);
     mCallback = cb;
     mCallbackCookie = cookie;
 
@@ -1577,7 +1599,7 @@
     // we must close the previous output before opening a new one
     if (bothOffloaded && !reuse) {
         ALOGV("both offloaded and not recycling");
-        deleteRecycledTrack();
+        deleteRecycledTrack_l();
     }
 
     sp<AudioTrack> t;
@@ -1655,7 +1677,7 @@
 
         if (reuse) {
             ALOGV("chaining to next output and recycling track");
-            close();
+            close_l();
             mTrack = mRecycledTrack;
             mRecycledTrack.clear();
             if (mCallbackData != NULL) {
@@ -1669,7 +1691,7 @@
     // we're not going to reuse the track, unblock and flush it
     // this was done earlier if both tracks are offloaded
     if (!bothOffloaded) {
-        deleteRecycledTrack();
+        deleteRecycledTrack_l();
     }
 
     CHECK((t != NULL) && ((mCallback == NULL) || (newcbd != NULL)));
@@ -1681,9 +1703,10 @@
     mSampleRateHz = sampleRate;
     mFlags = t->getFlags(); // we suggest the flags above, but new AudioTrack() may not grant it.
     mMsecsPerFrame = 1E3f / (mPlaybackRate.mSpeed * sampleRate);
+    mFrameSize = t->frameSize();
     uint32_t pos;
     if (t->getPosition(&pos) == OK) {
-        mBytesWritten = uint64_t(pos) * t->frameSize();
+        mBytesWritten = uint64_t(pos) * mFrameSize;
     }
     mTrack = t;
 
@@ -1704,6 +1727,7 @@
 status_t MediaPlayerService::AudioOutput::start()
 {
     ALOGV("start");
+    Mutex::Autolock lock(mLock);
     if (mCallbackData != NULL) {
         mCallbackData->endTrackSwitch();
     }
@@ -1716,30 +1740,88 @@
 }
 
 void MediaPlayerService::AudioOutput::setNextOutput(const sp<AudioOutput>& nextOutput) {
+    Mutex::Autolock lock(mLock);
     mNextOutput = nextOutput;
 }
 
-
 void MediaPlayerService::AudioOutput::switchToNextOutput() {
     ALOGV("switchToNextOutput");
-    if (mNextOutput != NULL) {
-        if (mCallbackData != NULL) {
-            mCallbackData->beginTrackSwitch();
+
+    // Try to acquire the callback lock before moving track (without incurring deadlock).
+    const unsigned kMaxSwitchTries = 100;
+    Mutex::Autolock lock(mLock);
+    for (unsigned tries = 0;;) {
+        if (mTrack == 0) {
+            return;
         }
-        delete mNextOutput->mCallbackData;
-        mNextOutput->mCallbackData = mCallbackData;
-        mCallbackData = NULL;
-        mNextOutput->mRecycledTrack = mTrack;
-        mTrack.clear();
-        mNextOutput->mSampleRateHz = mSampleRateHz;
-        mNextOutput->mMsecsPerFrame = mMsecsPerFrame;
-        mNextOutput->mBytesWritten = mBytesWritten;
-        mNextOutput->mFlags = mFlags;
+        if (mNextOutput != NULL && mNextOutput != this) {
+            if (mCallbackData != NULL) {
+                // two alternative approaches
+#if 1
+                CallbackData *callbackData = mCallbackData;
+                mLock.unlock();
+                // proper acquisition sequence
+                callbackData->lock();
+                mLock.lock();
+                // Caution: it is unlikely that someone deleted our callback or changed our target
+                if (callbackData != mCallbackData || mNextOutput == NULL || mNextOutput == this) {
+                    // fatal if we are starved out.
+                    LOG_ALWAYS_FATAL_IF(++tries > kMaxSwitchTries,
+                            "switchToNextOutput() cannot obtain correct lock sequence");
+                    callbackData->unlock();
+                    continue;
+                }
+                callbackData->mSwitching = true; // begin track switch
+#else
+                // tryBeginTrackSwitch() returns false if the callback has the lock.
+                if (!mCallbackData->tryBeginTrackSwitch()) {
+                    // fatal if we are starved out.
+                    LOG_ALWAYS_FATAL_IF(++tries > kMaxSwitchTries,
+                            "switchToNextOutput() cannot obtain callback lock");
+                    mLock.unlock();
+                    usleep(5 * 1000 /* usec */); // allow callback to use AudioOutput
+                    mLock.lock();
+                    continue;
+                }
+#endif
+            }
+
+            Mutex::Autolock nextLock(mNextOutput->mLock);
+
+            // If the next output track is not NULL, then it has been
+            // opened already for playback.
+            // This is possible even without the next player being started,
+            // for example, the next player could be prepared and seeked.
+            //
+            // Presuming it isn't advisable to force the track over.
+             if (mNextOutput->mTrack == NULL) {
+                ALOGD("Recycling track for gapless playback");
+                delete mNextOutput->mCallbackData;
+                mNextOutput->mCallbackData = mCallbackData;
+                mNextOutput->mRecycledTrack = mTrack;
+                mNextOutput->mSampleRateHz = mSampleRateHz;
+                mNextOutput->mMsecsPerFrame = mMsecsPerFrame;
+                mNextOutput->mBytesWritten = mBytesWritten;
+                mNextOutput->mFlags = mFlags;
+                mNextOutput->mFrameSize = mFrameSize;
+                close_l();
+                mCallbackData = NULL;  // destruction handled by mNextOutput
+            } else {
+                ALOGW("Ignoring gapless playback because next player has already started");
+                // remove track in case resource needed for future players.
+                if (mCallbackData != NULL) {
+                    mCallbackData->endTrackSwitch();  // release lock for callbacks before close.
+                }
+                close_l();
+            }
+        }
+        break;
     }
 }
 
 ssize_t MediaPlayerService::AudioOutput::write(const void* buffer, size_t size, bool blocking)
 {
+    Mutex::Autolock lock(mLock);
     LOG_ALWAYS_FATAL_IF(mCallback != NULL, "Don't call write if supplying a callback.");
 
     //ALOGV("write(%p, %u)", buffer, size);
@@ -1756,6 +1838,7 @@
 void MediaPlayerService::AudioOutput::stop()
 {
     ALOGV("stop");
+    Mutex::Autolock lock(mLock);
     mBytesWritten = 0;
     if (mTrack != 0) mTrack->stop();
 }
@@ -1763,6 +1846,7 @@
 void MediaPlayerService::AudioOutput::flush()
 {
     ALOGV("flush");
+    Mutex::Autolock lock(mLock);
     mBytesWritten = 0;
     if (mTrack != 0) mTrack->flush();
 }
@@ -1770,18 +1854,21 @@
 void MediaPlayerService::AudioOutput::pause()
 {
     ALOGV("pause");
+    Mutex::Autolock lock(mLock);
     if (mTrack != 0) mTrack->pause();
 }
 
 void MediaPlayerService::AudioOutput::close()
 {
     ALOGV("close");
-    mTrack.clear();
+    Mutex::Autolock lock(mLock);
+    close_l();
 }
 
 void MediaPlayerService::AudioOutput::setVolume(float left, float right)
 {
     ALOGV("setVolume(%f, %f)", left, right);
+    Mutex::Autolock lock(mLock);
     mLeftVolume = left;
     mRightVolume = right;
     if (mTrack != 0) {
@@ -1793,6 +1880,7 @@
 {
     ALOGV("setPlaybackRate(%f %f %d %d)",
                 rate.mSpeed, rate.mPitch, rate.mFallbackMode, rate.mStretchMode);
+    Mutex::Autolock lock(mLock);
     if (mTrack == 0) {
         // remember rate so that we can set it when the track is opened
         mPlaybackRate = rate;
@@ -1814,6 +1902,7 @@
 status_t MediaPlayerService::AudioOutput::getPlaybackRate(AudioPlaybackRate *rate)
 {
     ALOGV("setPlaybackRate");
+    Mutex::Autolock lock(mLock);
     if (mTrack == 0) {
         return NO_INIT;
     }
@@ -1824,6 +1913,7 @@
 status_t MediaPlayerService::AudioOutput::setAuxEffectSendLevel(float level)
 {
     ALOGV("setAuxEffectSendLevel(%f)", level);
+    Mutex::Autolock lock(mLock);
     mSendLevel = level;
     if (mTrack != 0) {
         return mTrack->setAuxEffectSendLevel(level);
@@ -1834,6 +1924,7 @@
 status_t MediaPlayerService::AudioOutput::attachAuxEffect(int effectId)
 {
     ALOGV("attachAuxEffect(%d)", effectId);
+    Mutex::Autolock lock(mLock);
     mAuxEffectId = effectId;
     if (mTrack != 0) {
         return mTrack->attachAuxEffect(effectId);
@@ -1846,6 +1937,7 @@
         int event, void *cookie, void *info) {
     //ALOGV("callbackwrapper");
     CallbackData *data = (CallbackData*)cookie;
+    // lock to ensure we aren't caught in the middle of a track switch.
     data->lock();
     AudioOutput *me = data->getOutput();
     AudioTrack::Buffer *buffer = (AudioTrack::Buffer *)info;
@@ -1915,11 +2007,13 @@
 
 int MediaPlayerService::AudioOutput::getSessionId() const
 {
+    Mutex::Autolock lock(mLock);
     return mSessionId;
 }
 
 uint32_t MediaPlayerService::AudioOutput::getSampleRate() const
 {
+    Mutex::Autolock lock(mLock);
     if (mTrack == 0) return 0;
     return mTrack->getSampleRate();
 }
diff --git a/media/libmediaplayerservice/MediaPlayerService.h b/media/libmediaplayerservice/MediaPlayerService.h
index 7527506..9e6ca52 100644
--- a/media/libmediaplayerservice/MediaPlayerService.h
+++ b/media/libmediaplayerservice/MediaPlayerService.h
@@ -132,7 +132,8 @@
         static void             setMinBufferCount();
         static void             CallbackWrapper(
                 int event, void *me, void *info);
-               void             deleteRecycledTrack();
+               void             deleteRecycledTrack_l();
+               void             close_l();
 
         sp<AudioTrack>          mTrack;
         sp<AudioTrack>          mRecycledTrack;
@@ -148,32 +149,47 @@
         AudioPlaybackRate       mPlaybackRate;
         uint32_t                mSampleRateHz; // sample rate of the content, as set in open()
         float                   mMsecsPerFrame;
+        size_t                  mFrameSize;
         int                     mSessionId;
         int                     mUid;
         int                     mPid;
         float                   mSendLevel;
         int                     mAuxEffectId;
+        audio_output_flags_t    mFlags;
+        mutable Mutex           mLock;
+
+        // static variables below not protected by mutex
         static bool             mIsOnEmulator;
         static int              mMinBufferCount;  // 12 for emulator; otherwise 4
-        audio_output_flags_t    mFlags;
 
         // CallbackData is what is passed to the AudioTrack as the "user" data.
         // We need to be able to target this to a different Output on the fly,
         // so we can't use the Output itself for this.
         class CallbackData {
+            friend AudioOutput;
         public:
             CallbackData(AudioOutput *cookie) {
                 mData = cookie;
                 mSwitching = false;
             }
-            AudioOutput *   getOutput() { return mData;}
+            AudioOutput *   getOutput() const { return mData; }
             void            setOutput(AudioOutput* newcookie) { mData = newcookie; }
             // lock/unlock are used by the callback before accessing the payload of this object
-            void            lock() { mLock.lock(); }
-            void            unlock() { mLock.unlock(); }
-            // beginTrackSwitch/endTrackSwitch are used when this object is being handed over
+            void            lock() const { mLock.lock(); }
+            void            unlock() const { mLock.unlock(); }
+
+            // tryBeginTrackSwitch/endTrackSwitch are used when the CallbackData is handed over
             // to the next sink.
-            void            beginTrackSwitch() { mLock.lock(); mSwitching = true; }
+
+            // tryBeginTrackSwitch() returns true only if it obtains the lock.
+            bool            tryBeginTrackSwitch() {
+                LOG_ALWAYS_FATAL_IF(mSwitching, "tryBeginTrackSwitch() already called");
+                if (mLock.tryLock() != OK) {
+                    return false;
+                }
+                mSwitching = true;
+                return true;
+            }
             void            endTrackSwitch() {
                 if (mSwitching) {
                     mLock.unlock();
@@ -182,7 +198,7 @@
             }
         private:
             AudioOutput *   mData;
-            mutable Mutex   mLock;
+            mutable Mutex   mLock; // a recursive mutex might make this unnecessary.
             bool            mSwitching;
             DISALLOW_EVIL_CONSTRUCTORS(CallbackData);
         };
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
index a9d8904..4a1a34d 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
@@ -639,7 +639,7 @@
 
             mDeferredActions.push_back(new SetSurfaceAction(surface));
 
-            if (obj != NULL) {
+            if (obj != NULL || mAudioDecoder != NULL) {
                 if (mStarted) {
                     // Issue a seek to refresh the video screen only if started otherwise
                     // the extractor may not yet be started and will assert.
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index 7452e4b..9206b5c 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -1063,9 +1063,11 @@
 
     for (OMX_U32 i = cancelStart; i < cancelEnd; i++) {
         BufferInfo *info = &mBuffers[kPortIndexOutput].editItemAt(i);
-        status_t error = cancelBufferToNativeWindow(info);
-        if (err == 0) {
-            err = error;
+        if (info->mStatus == BufferInfo::OWNED_BY_US) {
+            status_t error = cancelBufferToNativeWindow(info);
+            if (err == 0) {
+                err = error;
+            }
         }
     }
 
@@ -1152,9 +1154,11 @@
 
         for (OMX_U32 i = 0; i < mBuffers[kPortIndexOutput].size(); i++) {
             BufferInfo *info = &mBuffers[kPortIndexOutput].editItemAt(i);
-            status_t error = cancelBufferToNativeWindow(info);
-            if (err == OK) {
-                err = error;
+            if (info->mStatus == BufferInfo::OWNED_BY_US) {
+                status_t error = cancelBufferToNativeWindow(info);
+                if (err == OK) {
+                    err = error;
+                }
             }
         }
 
@@ -4864,6 +4868,12 @@
         case RESUBMIT_BUFFERS:
         {
             if (buffer != NULL && !mCodec->mPortEOS[kPortIndexInput]) {
+                // Do not send empty input buffer w/o EOS to the component.
+                if (buffer->size() == 0 && !eos) {
+                    postFillThisBuffer(info);
+                    break;
+                }
+
                 int64_t timeUs;
                 CHECK(buffer->meta()->findInt64("timeUs", &timeUs));
 
diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp
index 8bf47b1..b696746 100755
--- a/media/libstagefright/MPEG4Extractor.cpp
+++ b/media/libstagefright/MPEG4Extractor.cpp
@@ -4313,6 +4313,14 @@
 
     if ((!mIsAVC && !mIsHEVC)|| mWantsNALFragments) {
         if (newBuffer) {
+            if (!isInRange((size_t)0u, mBuffer->size(), size)) {
+                mBuffer->release();
+                mBuffer = NULL;
+
+                ALOGE("fragmentedRead ERROR_MALFORMED size %zu", size);
+                return ERROR_MALFORMED;
+            }
+
             ssize_t num_bytes_read =
                 mDataSource->readAt(offset, (uint8_t *)mBuffer->data(), size);
 
@@ -4320,7 +4328,7 @@
                 mBuffer->release();
                 mBuffer = NULL;
 
-                ALOGV("i/o error");
+                ALOGE("i/o error");
                 return ERROR_IO;
             }
 
@@ -4392,18 +4400,40 @@
         ssize_t num_bytes_read = 0;
         int32_t drm = 0;
         bool usesDRM = (mFormat->findInt32(kKeyIsDRM, &drm) && drm != 0);
+        void *data = NULL;
+        bool isMalFormed = false;
         if (usesDRM) {
-            num_bytes_read =
-                mDataSource->readAt(offset, (uint8_t*)mBuffer->data(), size);
+            if (mBuffer == NULL || !isInRange((size_t)0u, mBuffer->size(), size)) {
+                isMalFormed = true;
+            } else {
+                data = mBuffer->data();
+            }
         } else {
-            num_bytes_read = mDataSource->readAt(offset, mSrcBuffer, size);
+            int32_t max_size;
+            if (mFormat == NULL
+                    || !mFormat->findInt32(kKeyMaxInputSize, &max_size)
+                    || !isInRange((size_t)0u, (size_t)max_size, size)) {
+                isMalFormed = true;
+            } else {
+                data = mSrcBuffer;
+            }
         }
 
+        if (isMalFormed || data == NULL) {
+            ALOGE("isMalFormed size %zu", size);
+            if (mBuffer != NULL) {
+                mBuffer->release();
+                mBuffer = NULL;
+            }
+            return ERROR_MALFORMED;
+        }
+        num_bytes_read = mDataSource->readAt(offset, data, size);
+
         if (num_bytes_read < (ssize_t)size) {
             mBuffer->release();
             mBuffer = NULL;
 
-            ALOGV("i/o error");
+            ALOGE("i/o error");
             return ERROR_IO;
         }
 
@@ -4417,16 +4447,18 @@
             size_t dstOffset = 0;
 
             while (srcOffset < size) {
-                bool isMalFormed = !isInRange((size_t)0u, size, srcOffset, mNALLengthSize);
+                isMalFormed = !isInRange((size_t)0u, size, srcOffset, mNALLengthSize);
                 size_t nalLength = 0;
                 if (!isMalFormed) {
                     nalLength = parseNALSize(&mSrcBuffer[srcOffset]);
                     srcOffset += mNALLengthSize;
-                    isMalFormed = !isInRange((size_t)0u, size, srcOffset, nalLength);
+                    isMalFormed = !isInRange((size_t)0u, size, srcOffset, nalLength)
+                            || !isInRange((size_t)0u, mBuffer->size(), dstOffset, (size_t)4u)
+                            || !isInRange((size_t)0u, mBuffer->size(), dstOffset + 4, nalLength);
                 }
 
                 if (isMalFormed) {
-                    ALOGE("Video is malformed");
+                    ALOGE("Video is malformed; nalLength %zu", nalLength);
                     mBuffer->release();
                     mBuffer = NULL;
                     return ERROR_MALFORMED;
diff --git a/media/libstagefright/codecs/avcdec/SoftAVCDec.cpp b/media/libstagefright/codecs/avcdec/SoftAVCDec.cpp
index f3af777..aab3af7 100644
--- a/media/libstagefright/codecs/avcdec/SoftAVCDec.cpp
+++ b/media/libstagefright/codecs/avcdec/SoftAVCDec.cpp
@@ -115,6 +115,7 @@
             kProfileLevels, ARRAY_SIZE(kProfileLevels),
             320 /* width */, 240 /* height */, callbacks,
             appData, component),
+      mCodecCtx(NULL),
       mMemRecords(NULL),
       mFlushOutBuffer(NULL),
       mOmxColorFormat(OMX_COLOR_FormatYUV420Planar),
@@ -122,7 +123,8 @@
       mNewWidth(mWidth),
       mNewHeight(mHeight),
       mNewLevel(0),
-      mChangingResolution(false) {
+      mChangingResolution(false),
+      mSignalledError(false) {
     initPorts(
             kNumBuffers, INPUT_BUF_SIZE, kNumBuffers, CODEC_MIME_TYPE);
 
@@ -132,7 +134,7 @@
     GENERATE_FILE_NAMES();
     CREATE_DUMP_FILE(mInFile);
 
-    CHECK_EQ(initDecoder(), (status_t)OK);
+    CHECK_EQ(initDecoder(mWidth, mHeight), (status_t)OK);
 }
 
 SoftAVC::~SoftAVC() {
@@ -232,6 +234,7 @@
         ALOGE("Error in reset: 0x%x", s_ctl_op.u4_error_code);
         return UNKNOWN_ERROR;
     }
+    mSignalledError = false;
 
     /* Set the run-time (dynamic) parameters */
     setParams(outputBufferWidth());
@@ -285,7 +288,7 @@
     return OK;
 }
 
-status_t SoftAVC::initDecoder() {
+status_t SoftAVC::initDecoder(uint32_t width, uint32_t height) {
     IV_API_CALL_STATUS_T status;
 
     UWORD32 u4_num_reorder_frames;
@@ -294,14 +297,15 @@
     WORD32 i4_level;
 
     mNumCores = GetCPUCoreCount();
+    mCodecCtx = NULL;
 
     /* Initialize number of ref and reorder modes (for H264) */
     u4_num_reorder_frames = 16;
     u4_num_ref_frames = 16;
     u4_share_disp_buf = 0;
 
-    uint32_t displayStride = outputBufferWidth();
-    uint32_t displayHeight = outputBufferHeight();
+    uint32_t displayStride = mIsAdaptive ? mAdaptiveMaxWidth : width;
+    uint32_t displayHeight = mIsAdaptive ? mAdaptiveMaxHeight : height;
     uint32_t displaySizeY = displayStride * displayHeight;
 
     if(mNewLevel == 0){
@@ -435,6 +439,7 @@
 
         status = ivdec_api_function(mCodecCtx, (void *)&s_init_ip, (void *)&s_init_op);
         if (status != IV_SUCCESS) {
+            mCodecCtx = NULL;
             ALOGE("Error in init: 0x%x",
                     s_init_op.s_ivd_init_op_t.u4_error_code);
             return UNKNOWN_ERROR;
@@ -494,12 +499,12 @@
     return OK;
 }
 
-status_t SoftAVC::reInitDecoder() {
+status_t SoftAVC::reInitDecoder(uint32_t width, uint32_t height) {
     status_t ret;
 
     deInitDecoder();
 
-    ret = initDecoder();
+    ret = initDecoder(width, height);
     if (OK != ret) {
         ALOGE("Create failure");
         deInitDecoder();
@@ -511,6 +516,7 @@
 void SoftAVC::onReset() {
     SoftVideoDecoderOMXComponent::onReset();
 
+    mSignalledError = false;
     resetDecoder();
     resetPlugin();
 }
@@ -520,7 +526,12 @@
     const uint32_t oldHeight = mHeight;
     OMX_ERRORTYPE ret = SoftVideoDecoderOMXComponent::internalSetParameter(index, params);
     if (mWidth != oldWidth || mHeight != oldHeight) {
-        reInitDecoder();
+        status_t err = reInitDecoder(mNewWidth, mNewHeight);
+        if (err != OK) {
+            notify(OMX_EventError, OMX_ErrorUnsupportedSetting, err, NULL);
+            mSignalledError = true;
+            return OMX_ErrorUnsupportedSetting;
+        }
     }
     return ret;
 }
@@ -595,6 +606,9 @@
 void SoftAVC::onQueueFilled(OMX_U32 portIndex) {
     UNUSED(portIndex);
 
+    if (mSignalledError) {
+        return;
+    }
     if (mOutputPortSettingsChange != NONE) {
         return;
     }
@@ -627,6 +641,11 @@
             if (!inQueue.empty()) {
                 inInfo = *inQueue.begin();
                 inHeader = inInfo->mHeader;
+                if (inHeader == NULL) {
+                    inQueue.erase(inQueue.begin());
+                    inInfo->mOwnedByUs = false;
+                    continue;
+                }
             } else {
                 break;
             }
@@ -638,14 +657,21 @@
         outHeader->nTimeStamp = 0;
         outHeader->nOffset = 0;
 
-        if (inHeader != NULL && (inHeader->nFlags & OMX_BUFFERFLAG_EOS)) {
-            mReceivedEOS = true;
+        if (inHeader != NULL) {
             if (inHeader->nFilledLen == 0) {
                 inQueue.erase(inQueue.begin());
                 inInfo->mOwnedByUs = false;
                 notifyEmptyBufferDone(inHeader);
+
+                if (!(inHeader->nFlags & OMX_BUFFERFLAG_EOS)) {
+                    continue;
+                }
+
+                mReceivedEOS = true;
                 inHeader = NULL;
                 setFlushMode();
+            } else if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) {
+                mReceivedEOS = true;
             }
         }
 
@@ -653,9 +679,15 @@
         // update output port's definition and reinitialize decoder.
         if (mInitNeeded && !mIsInFlush) {
             bool portWillReset = false;
-            handlePortSettingsChange(&portWillReset, mNewWidth, mNewHeight);
 
-            CHECK_EQ(reInitDecoder(), (status_t)OK);
+            status_t err = reInitDecoder(mNewWidth, mNewHeight);
+            if (err != OK) {
+                notify(OMX_EventError, OMX_ErrorUnsupportedSetting, err, NULL);
+                mSignalledError = true;
+                return;
+            }
+
+            handlePortSettingsChange(&portWillReset, mNewWidth, mNewHeight);
             return;
         }
 
@@ -714,13 +746,22 @@
                 mTimeStampsValid[timeStampIx] = false;
             }
 
+
             // This is needed to handle CTS DecoderTest testCodecResetsH264WithoutSurface,
             // which is not sending SPS/PPS after port reconfiguration and flush to the codec.
             if (unsupportedDimensions && !mFlushNeeded) {
                 bool portWillReset = false;
-                handlePortSettingsChange(&portWillReset, s_dec_op.u4_pic_wd, s_dec_op.u4_pic_ht);
+                mNewWidth = s_dec_op.u4_pic_wd;
+                mNewHeight = s_dec_op.u4_pic_ht;
 
-                CHECK_EQ(reInitDecoder(), (status_t)OK);
+                status_t err = reInitDecoder(mNewWidth, mNewHeight);
+                if (err != OK) {
+                    notify(OMX_EventError, OMX_ErrorUnsupportedSetting, err, NULL);
+                    mSignalledError = true;
+                    return;
+                }
+
+                handlePortSettingsChange(&portWillReset, mNewWidth, mNewHeight);
 
                 setDecodeArgs(&s_dec_ip, &s_dec_op, inHeader, outHeader, timeStampIx);
 
@@ -732,7 +773,12 @@
 
                 mNewLevel = 51;
 
-                CHECK_EQ(reInitDecoder(), (status_t)OK);
+                status_t err = reInitDecoder(mNewWidth, mNewHeight);
+                if (err != OK) {
+                    notify(OMX_EventError, OMX_ErrorUnsupportedSetting, err, NULL);
+                    mSignalledError = true;
+                    return;
+                }
 
                 setDecodeArgs(&s_dec_ip, &s_dec_op, inHeader, outHeader, timeStampIx);
 
diff --git a/media/libstagefright/codecs/avcdec/SoftAVCDec.h b/media/libstagefright/codecs/avcdec/SoftAVCDec.h
index 2067810..1ec8991 100644
--- a/media/libstagefright/codecs/avcdec/SoftAVCDec.h
+++ b/media/libstagefright/codecs/avcdec/SoftAVCDec.h
@@ -105,8 +105,9 @@
     // codec. So the codec is switching to decode the new resolution.
     bool mChangingResolution;
     bool mFlushNeeded;
+    bool mSignalledError;
 
-    status_t initDecoder();
+    status_t initDecoder(uint32_t width, uint32_t height);
     status_t deInitDecoder();
     status_t setFlushMode();
     status_t setParams(size_t stride);
@@ -114,7 +115,7 @@
     status_t setNumCores();
     status_t resetDecoder();
     status_t resetPlugin();
-    status_t reInitDecoder();
+    status_t reInitDecoder(uint32_t width, uint32_t height);
 
     void setDecodeArgs(
             ivd_video_decode_ip_t *ps_dec_ip,
diff --git a/media/libstagefright/codecs/m4v_h263/dec/SoftMPEG4.cpp b/media/libstagefright/codecs/m4v_h263/dec/SoftMPEG4.cpp
index ede645c..0c1a149 100644
--- a/media/libstagefright/codecs/m4v_h263/dec/SoftMPEG4.cpp
+++ b/media/libstagefright/codecs/m4v_h263/dec/SoftMPEG4.cpp
@@ -103,34 +103,41 @@
     while (!inQueue.empty() && outQueue.size() == kNumOutputBuffers) {
         BufferInfo *inInfo = *inQueue.begin();
         OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader;
+        if (inHeader == NULL) {
+            inQueue.erase(inQueue.begin());
+            inInfo->mOwnedByUs = false;
+            continue;
+        }
 
         PortInfo *port = editPortInfo(1);
 
         OMX_BUFFERHEADERTYPE *outHeader =
             port->mBuffers.editItemAt(mNumSamplesOutput & 1).mHeader;
 
-        if ((inHeader->nFlags & OMX_BUFFERFLAG_EOS) && inHeader->nFilledLen == 0) {
+        if (inHeader->nFilledLen == 0) {
             inQueue.erase(inQueue.begin());
             inInfo->mOwnedByUs = false;
             notifyEmptyBufferDone(inHeader);
 
             ++mInputBufferCount;
 
-            outHeader->nFilledLen = 0;
-            outHeader->nFlags = OMX_BUFFERFLAG_EOS;
+            if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) {
+                outHeader->nFilledLen = 0;
+                outHeader->nFlags = OMX_BUFFERFLAG_EOS;
 
-            List<BufferInfo *>::iterator it = outQueue.begin();
-            while ((*it)->mHeader != outHeader) {
-                ++it;
+                List<BufferInfo *>::iterator it = outQueue.begin();
+                while ((*it)->mHeader != outHeader) {
+                    ++it;
+                }
+
+                BufferInfo *outInfo = *it;
+                outInfo->mOwnedByUs = false;
+                outQueue.erase(it);
+                outInfo = NULL;
+
+                notifyFillBufferDone(outHeader);
+                outHeader = NULL;
             }
-
-            BufferInfo *outInfo = *it;
-            outInfo->mOwnedByUs = false;
-            outQueue.erase(it);
-            outInfo = NULL;
-
-            notifyFillBufferDone(outHeader);
-            outHeader = NULL;
             return;
         }
 
diff --git a/media/libstagefright/foundation/ADebug.cpp b/media/libstagefright/foundation/ADebug.cpp
index 0d1cea4..24fa561 100644
--- a/media/libstagefright/foundation/ADebug.cpp
+++ b/media/libstagefright/foundation/ADebug.cpp
@@ -32,11 +32,10 @@
 namespace android {
 
 //static
-ADebug::Level ADebug::GetDebugLevelFromString(
-        const char *name, const char *value, ADebug::Level def) {
+long ADebug::GetLevelFromSettingsString(
+        const char *name, const char *value, long def) {
     // split on ,
     const char *next = value, *current;
-    const unsigned long maxLevel = (unsigned long)kDebugMax;
     while (next != NULL) {
         current = next;
         next = strchr(current, ',');
@@ -52,8 +51,8 @@
 
         // get level
         char *end;
-        errno = 0;  // strtoul does not clear errno, but it can be set for any return value
-        unsigned long level = strtoul(current, &end, 10);
+        errno = 0;  // strtol does not clear errno, but it can be set for any return value
+        long level = strtol(current, &end, 10);
         while (isspace(*end)) {
             ++end;
         }
@@ -77,8 +76,18 @@
             }
         }
 
-        // update debug level
-        def = (Level)min(level, maxLevel);
+        // update value
+        def = level;
+    }
+    return def;
+}
+
+//static
+long ADebug::GetLevelFromProperty(
+        const char *name, const char *propertyName, long def) {
+    char value[PROPERTY_VALUE_MAX];
+    if (property_get(propertyName, value, NULL)) {
+        def = GetLevelFromSettingsString(name, value, def);
     }
     return def;
 }
@@ -86,11 +95,8 @@
 //static
 ADebug::Level ADebug::GetDebugLevelFromProperty(
         const char *name, const char *propertyName, ADebug::Level def) {
-    char value[PROPERTY_VALUE_MAX];
-    if (property_get(propertyName, value, NULL)) {
-        return GetDebugLevelFromString(name, value, def);
-    }
-    return def;
+    long level = GetLevelFromProperty(name, propertyName, (long)def);
+    return (Level)min(max(level, (long)kDebugNone), (long)kDebugMax);
 }
 
 //static
@@ -118,6 +124,15 @@
 bool ADebug::getExperimentFlag(
         bool allow, const char *name, uint64_t modulo,
         uint64_t limit, uint64_t plus, uint64_t timeDivisor) {
+    // see if this experiment should be disabled/enabled based on properties.
+    // default to 2 to allow 0/1 specification
+    const int undefined = 2;
+    long level = GetLevelFromProperty(name, "debug.stagefright.experiments", undefined);
+    if (level != undefined) {
+        ALOGI("experiment '%s': %s from property", name, level ? "ENABLED" : "disabled");
+        return level != 0;
+    }
+
     static volatile int32_t haveSerial = 0;
     static uint64_t serialNum;
     if (!android_atomic_acquire_load(&haveSerial)) {
@@ -138,11 +153,10 @@
                 num = num * 256 + c;
             }
         }
-        ALOGI("got serial");
         serialNum = num;
         android_atomic_release_store(1, &haveSerial);
     }
-    ALOGI("serial: %llu, time: %llu", (long long)serialNum, (long long)time(NULL));
+    ALOGD("serial: %llu, time: %lld", (long long unsigned)serialNum, (long long)time(NULL));
     // MINOR: use modulo for counter and time, so that their sum does not
     // roll over, and mess up the correlation between related experiments.
     // e.g. keep (a mod 2N) = 0 impl (a mod N) = 0
diff --git a/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp b/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp
index aae3e9f..cbe9673 100644
--- a/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp
+++ b/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp
@@ -264,8 +264,19 @@
     if (event.isInit()) {
         for (size_t i = 0; i < mSourceImpls.size(); ++i) {
             if (mSourceImpls[i].get() == event.getMediaSource().get()) {
-                mSyncPoints.editItemAt(i).add(
-                        event.getTimeUs(), event.getOffset());
+                KeyedVector<int64_t, off64_t> *syncPoints = &mSyncPoints.editItemAt(i);
+                syncPoints->add(event.getTimeUs(), event.getOffset());
+                // We're keeping the size of the sync points at most 5mb per a track.
+                size_t size = syncPoints->size();
+                if (size >= 327680) {
+                    int64_t firstTimeUs = syncPoints->keyAt(0);
+                    int64_t lastTimeUs = syncPoints->keyAt(size - 1);
+                    if (event.getTimeUs() - firstTimeUs > lastTimeUs - event.getTimeUs()) {
+                        syncPoints->removeItemsAt(0, 4096);
+                    } else {
+                        syncPoints->removeItemsAt(size - 4096, 4096);
+                    }
+                }
                 break;
             }
         }
diff --git a/media/libstagefright/omx/SimpleSoftOMXComponent.cpp b/media/libstagefright/omx/SimpleSoftOMXComponent.cpp
index 04303c4..e6a0c49 100644
--- a/media/libstagefright/omx/SimpleSoftOMXComponent.cpp
+++ b/media/libstagefright/omx/SimpleSoftOMXComponent.cpp
@@ -505,7 +505,15 @@
     CHECK_LT(portIndex, mPorts.size());
 
     PortInfo *port = &mPorts.editItemAt(portIndex);
-    CHECK_EQ((int)port->mTransition, (int)PortInfo::NONE);
+    // Ideally, the port should not in transitioning state when flushing.
+    // However, in error handling case, e.g., the client can't allocate buffers
+    // when it tries to re-enable the port, the port will be stuck in ENABLING.
+    // The client will then transition the component from Executing to Idle,
+    // which leads to flushing ports. At this time, it should be ok to notify
+    // the client of the error and still clear all buffers on the port.
+    if (port->mTransition != PortInfo::NONE) {
+        notify(OMX_EventError, OMX_ErrorUndefined, 0, 0);
+    }
 
     for (size_t i = 0; i < port->mBuffers.size(); ++i) {
         BufferInfo *buffer = &port->mBuffers.editItemAt(i);
diff --git a/media/libstagefright/tests/Utils_test.cpp b/media/libstagefright/tests/Utils_test.cpp
index c1e663c..d736501 100644
--- a/media/libstagefright/tests/Utils_test.cpp
+++ b/media/libstagefright/tests/Utils_test.cpp
@@ -109,21 +109,21 @@
 
 TEST_F(UtilsTest, TestDebug) {
 #define LVL(x) (ADebug::Level)(x)
-    ASSERT_EQ(ADebug::GetDebugLevelFromString("video", "", LVL(5)), LVL(5));
-    ASSERT_EQ(ADebug::GetDebugLevelFromString("video", "   \t  \n ", LVL(2)), LVL(2));
-    ASSERT_EQ(ADebug::GetDebugLevelFromString("video", "3", LVL(5)), LVL(3));
-    ASSERT_EQ(ADebug::GetDebugLevelFromString("video", "3:*deo", LVL(5)), LVL(3));
-    ASSERT_EQ(ADebug::GetDebugLevelFromString(
+    ASSERT_EQ(ADebug::GetLevelFromSettingsString("video", "", LVL(5)), LVL(5));
+    ASSERT_EQ(ADebug::GetLevelFromSettingsString("video", "   \t  \n ", LVL(2)), LVL(2));
+    ASSERT_EQ(ADebug::GetLevelFromSettingsString("video", "3", LVL(5)), LVL(3));
+    ASSERT_EQ(ADebug::GetLevelFromSettingsString("video", "3:*deo", LVL(5)), LVL(3));
+    ASSERT_EQ(ADebug::GetLevelFromSettingsString(
             "video", "\t\n 3 \t\n:\t\n video \t\n", LVL(5)), LVL(3));
-    ASSERT_EQ(ADebug::GetDebugLevelFromString("video", "3:*deo,2:vid*", LVL(5)), LVL(2));
-    ASSERT_EQ(ADebug::GetDebugLevelFromString(
+    ASSERT_EQ(ADebug::GetLevelFromSettingsString("video", "3:*deo,2:vid*", LVL(5)), LVL(2));
+    ASSERT_EQ(ADebug::GetLevelFromSettingsString(
             "avideo", "\t\n 3 \t\n:\t\n avideo \t\n,\t\n 2 \t\n:\t\n video \t\n", LVL(5)), LVL(3));
-    ASSERT_EQ(ADebug::GetDebugLevelFromString(
+    ASSERT_EQ(ADebug::GetLevelFromSettingsString(
             "audio.omx", "4:*omx,3:*d*o*,2:audio*", LVL(5)), LVL(2));
-    ASSERT_EQ(ADebug::GetDebugLevelFromString(
+    ASSERT_EQ(ADebug::GetLevelFromSettingsString(
             "video.omx", "4:*omx,3:*d*o*,2:audio*", LVL(5)), LVL(3));
-    ASSERT_EQ(ADebug::GetDebugLevelFromString("video", "4:*omx,3:*d*o*,2:audio*", LVL(5)), LVL(3));
-    ASSERT_EQ(ADebug::GetDebugLevelFromString("omx", "4:*omx,3:*d*o*,2:audio*", LVL(5)), LVL(4));
+    ASSERT_EQ(ADebug::GetLevelFromSettingsString("video", "4:*omx,3:*d*o*,2:audio*", LVL(5)), LVL(3));
+    ASSERT_EQ(ADebug::GetLevelFromSettingsString("omx", "4:*omx,3:*d*o*,2:audio*", LVL(5)), LVL(4));
 #undef LVL
 }
 
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 52fce34..8f1e050 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -1252,11 +1252,9 @@
     if (client == 0) {
         return;
     }
-    bool clientAdded = false;
+    pid_t pid = IPCThreadState::self()->getCallingPid();
     {
         Mutex::Autolock _cl(mClientLock);
-
-        pid_t pid = IPCThreadState::self()->getCallingPid();
         if (mNotificationClients.indexOfKey(pid) < 0) {
             sp<NotificationClient> notificationClient = new NotificationClient(this,
                                                                                 client,
@@ -1267,22 +1265,19 @@
 
             sp<IBinder> binder = IInterface::asBinder(client);
             binder->linkToDeath(notificationClient);
-            clientAdded = true;
         }
     }
 
     // mClientLock should not be held here because ThreadBase::sendIoConfigEvent() will lock the
     // ThreadBase mutex and the locking order is ThreadBase::mLock then AudioFlinger::mClientLock.
-    if (clientAdded) {
-        // the config change is always sent from playback or record threads to avoid deadlock
-        // with AudioSystem::gLock
-        for (size_t i = 0; i < mPlaybackThreads.size(); i++) {
-            mPlaybackThreads.valueAt(i)->sendIoConfigEvent(AUDIO_OUTPUT_OPENED);
-        }
+    // the config change is always sent from playback or record threads to avoid deadlock
+    // with AudioSystem::gLock
+    for (size_t i = 0; i < mPlaybackThreads.size(); i++) {
+        mPlaybackThreads.valueAt(i)->sendIoConfigEvent(AUDIO_OUTPUT_OPENED, pid);
+    }
 
-        for (size_t i = 0; i < mRecordThreads.size(); i++) {
-            mRecordThreads.valueAt(i)->sendIoConfigEvent(AUDIO_INPUT_OPENED);
-        }
+    for (size_t i = 0; i < mRecordThreads.size(); i++) {
+        mRecordThreads.valueAt(i)->sendIoConfigEvent(AUDIO_INPUT_OPENED, pid);
     }
 }
 
@@ -1316,12 +1311,15 @@
 }
 
 void AudioFlinger::ioConfigChanged(audio_io_config_event event,
-                                   const sp<AudioIoDescriptor>& ioDesc)
+                                   const sp<AudioIoDescriptor>& ioDesc,
+                                   pid_t pid)
 {
     Mutex::Autolock _l(mClientLock);
     size_t size = mNotificationClients.size();
     for (size_t i = 0; i < size; i++) {
-        mNotificationClients.valueAt(i)->audioFlingerClient()->ioConfigChanged(event, ioDesc);
+        if ((pid == 0) || (mNotificationClients.keyAt(i) == pid)) {
+            mNotificationClients.valueAt(i)->audioFlingerClient()->ioConfigChanged(event, ioDesc);
+        }
     }
 }
 
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index d087ced..4f7e27d 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -559,7 +559,8 @@
               float streamVolume_l(audio_stream_type_t stream) const
                                 { return mStreamTypes[stream].volume; }
               void ioConfigChanged(audio_io_config_event event,
-                                   const sp<AudioIoDescriptor>& ioDesc);
+                                   const sp<AudioIoDescriptor>& ioDesc,
+                                   pid_t pid = 0);
 
               // Allocate an audio_io_handle_t, session ID, effect ID, or audio_module_handle_t.
               // They all share the same ID space, but the namespaces are actually independent
diff --git a/services/audioflinger/AudioStreamOut.cpp b/services/audioflinger/AudioStreamOut.cpp
index e6d8f09..f953cc8 100644
--- a/services/audioflinger/AudioStreamOut.cpp
+++ b/services/audioflinger/AudioStreamOut.cpp
@@ -27,25 +27,59 @@
 namespace android {
 
 // ----------------------------------------------------------------------------
-
 AudioStreamOut::AudioStreamOut(AudioHwDevice *dev, audio_output_flags_t flags)
         : audioHwDev(dev)
         , stream(NULL)
         , flags(flags)
+        , mFramesWritten(0)
+        , mFramesWrittenAtStandby(0)
+        , mRenderPosition(0)
+        , mRateMultiplier(1)
+        , mHalFormatIsLinearPcm(false)
+        , mHalFrameSize(0)
 {
 }
 
-audio_hw_device_t* AudioStreamOut::hwDev() const
+audio_hw_device_t *AudioStreamOut::hwDev() const
 {
     return audioHwDev->hwDevice();
 }
 
-status_t AudioStreamOut::getRenderPosition(uint32_t *frames)
+status_t AudioStreamOut::getRenderPosition(uint64_t *frames)
 {
     if (stream == NULL) {
         return NO_INIT;
     }
-    return stream->get_render_position(stream, frames);
+
+    uint32_t halPosition = 0;
+    status_t status = stream->get_render_position(stream, &halPosition);
+    if (status != NO_ERROR) {
+        return status;
+    }
+
+    // Maintain a 64-bit render position using the 32-bit result from the HAL.
+    // This delta calculation relies on the arithmetic overflow behavior
+    // of integers. For example (100 - 0xFFFFFFF0) = 116.
+    uint32_t truncatedPosition = (uint32_t)mRenderPosition;
+    int32_t deltaHalPosition = (int32_t)(halPosition - truncatedPosition);
+    if (deltaHalPosition > 0) {
+        mRenderPosition += deltaHalPosition;
+    }
+    // Scale from HAL sample rate to application rate.
+    *frames = mRenderPosition / mRateMultiplier;
+
+    return status;
+}
+
+// return bottom 32-bits of the render position
+status_t AudioStreamOut::getRenderPosition(uint32_t *frames)
+{
+    uint64_t position64 = 0;
+    status_t status = getRenderPosition(&position64);
+    if (status == NO_ERROR) {
+        *frames = (uint32_t)position64;
+    }
+    return status;
 }
 
 status_t AudioStreamOut::getPresentationPosition(uint64_t *frames, struct timespec *timestamp)
@@ -53,7 +87,26 @@
     if (stream == NULL) {
         return NO_INIT;
     }
-    return stream->get_presentation_position(stream, frames, timestamp);
+
+    uint64_t halPosition = 0;
+    status_t status = stream->get_presentation_position(stream, &halPosition, timestamp);
+    if (status != NO_ERROR) {
+        return status;
+    }
+
+    // Adjust for standby using HAL rate frames.
+    // Only apply this correction if the HAL is getting PCM frames.
+    if (mHalFormatIsLinearPcm) {
+        uint64_t adjustedPosition = (halPosition <= mFramesWrittenAtStandby) ?
+                0 : (halPosition - mFramesWrittenAtStandby);
+        // Scale from HAL sample rate to application rate.
+        *frames = adjustedPosition / mRateMultiplier;
+    } else {
+        // For offloaded MP3 and other compressed formats.
+        *frames = halPosition;
+    }
+
+    return status;
 }
 
 status_t AudioStreamOut::open(
@@ -62,7 +115,7 @@
         struct audio_config *config,
         const char *address)
 {
-    audio_stream_out_t* outStream;
+    audio_stream_out_t *outStream;
     int status = hwDev()->open_output_stream(
             hwDev(),
             handle,
@@ -82,6 +135,9 @@
 
     if (status == NO_ERROR) {
         stream = outStream;
+        mHalFormatIsLinearPcm = audio_is_linear_pcm(config->format);
+        ALOGI("AudioStreamOut::open(), mHalFormatIsLinearPcm = %d", (int)mHalFormatIsLinearPcm);
+        mHalFrameSize = audio_stream_out_frame_size(stream);
     }
 
     return status;
@@ -89,13 +145,15 @@
 
 size_t AudioStreamOut::getFrameSize()
 {
-    ALOG_ASSERT(stream != NULL);
-    return audio_stream_out_frame_size(stream);
+    return mHalFrameSize;
 }
 
 int AudioStreamOut::flush()
 {
     ALOG_ASSERT(stream != NULL);
+    mRenderPosition = 0;
+    mFramesWritten = 0;
+    mFramesWrittenAtStandby = 0;
     if (stream->flush != NULL) {
         return stream->flush(stream);
     }
@@ -105,13 +163,20 @@
 int AudioStreamOut::standby()
 {
     ALOG_ASSERT(stream != NULL);
+    mRenderPosition = 0;
+    mFramesWrittenAtStandby = mFramesWritten;
+    ALOGI("AudioStreamOut::standby(), mFramesWrittenAtStandby = %llu", mFramesWrittenAtStandby);
     return stream->common.standby(&stream->common);
 }
 
-ssize_t AudioStreamOut::write(const void* buffer, size_t bytes)
+ssize_t AudioStreamOut::write(const void *buffer, size_t numBytes)
 {
     ALOG_ASSERT(stream != NULL);
-    return stream->write(stream, buffer, bytes);
+    ssize_t bytesWritten = stream->write(stream, buffer, numBytes);
+    if (bytesWritten > 0 && mHalFrameSize > 0) {
+        mFramesWritten += bytesWritten / mHalFrameSize;
+    }
+    return bytesWritten;
 }
 
 } // namespace android
diff --git a/services/audioflinger/AudioStreamOut.h b/services/audioflinger/AudioStreamOut.h
index e91ca9c..761e771 100644
--- a/services/audioflinger/AudioStreamOut.h
+++ b/services/audioflinger/AudioStreamOut.h
@@ -53,7 +53,10 @@
 
     virtual ~AudioStreamOut() { }
 
-    virtual status_t getRenderPosition(uint32_t *frames);
+    // Get the bottom 32-bits of the 64-bit render position.
+    status_t getRenderPosition(uint32_t *frames);
+
+    virtual status_t getRenderPosition(uint64_t *frames);
 
     virtual status_t getPresentationPosition(uint64_t *frames, struct timespec *timestamp);
 
@@ -76,6 +79,14 @@
 
     virtual status_t flush();
     virtual status_t standby();
+
+protected:
+    uint64_t             mFramesWritten; // reset by flush
+    uint64_t             mFramesWrittenAtStandby;
+    uint64_t             mRenderPosition; // reset by flush or standby
+    int                  mRateMultiplier;
+    bool                 mHalFormatIsLinearPcm;
+    size_t               mHalFrameSize;
 };
 
 } // namespace android
diff --git a/services/audioflinger/SpdifStreamOut.cpp b/services/audioflinger/SpdifStreamOut.cpp
index ac637ef..6af7bce 100644
--- a/services/audioflinger/SpdifStreamOut.cpp
+++ b/services/audioflinger/SpdifStreamOut.cpp
@@ -36,10 +36,7 @@
             audio_output_flags_t flags,
             audio_format_t format)
         : AudioStreamOut(dev,flags)
-        , mRateMultiplier(1)
         , mSpdifEncoder(this, format)
-        , mRenderPositionHal(0)
-        , mPreviousHalPosition32(0)
 {
 }
 
@@ -97,62 +94,18 @@
     return status;
 }
 
-// Account for possibly higher sample rate.
-status_t SpdifStreamOut::getRenderPosition(uint32_t *frames)
-{
-    uint32_t halPosition = 0;
-    status_t status = AudioStreamOut::getRenderPosition(&halPosition);
-    if (status != NO_ERROR) {
-        return status;
-    }
-
-    // Accumulate a 64-bit position so that we wrap at the right place.
-    if (mRateMultiplier != 1) {
-        // Maintain a 64-bit render position.
-        int32_t deltaHalPosition = (int32_t)(halPosition - mPreviousHalPosition32);
-        mPreviousHalPosition32 = halPosition;
-        mRenderPositionHal += deltaHalPosition;
-
-        // Scale from device sample rate to application rate.
-        uint64_t renderPositionApp = mRenderPositionHal / mRateMultiplier;
-        ALOGV("SpdifStreamOut::getRenderPosition() "
-            "renderPositionAppRate = %llu = %llu / %u\n",
-            renderPositionApp, mRenderPositionHal, mRateMultiplier);
-
-        *frames = (uint32_t)renderPositionApp;
-    } else {
-        *frames = halPosition;
-    }
-    return status;
-}
-
 int SpdifStreamOut::flush()
 {
     mSpdifEncoder.reset();
-    mRenderPositionHal = 0;
-    mPreviousHalPosition32 = 0;
     return AudioStreamOut::flush();
 }
 
 int SpdifStreamOut::standby()
 {
     mSpdifEncoder.reset();
-    mRenderPositionHal = 0;
-    mPreviousHalPosition32 = 0;
     return AudioStreamOut::standby();
 }
 
-// Account for possibly higher sample rate.
-// This is much easier when all the values are 64-bit.
-status_t SpdifStreamOut::getPresentationPosition(uint64_t *frames,
-        struct timespec *timestamp)
-{
-    uint64_t halFrames = 0;
-    status_t status = AudioStreamOut::getPresentationPosition(&halFrames, timestamp);
-    *frames = halFrames / mRateMultiplier;
-    return status;
-}
-
 size_t SpdifStreamOut::getFrameSize()
 {
     return sizeof(int8_t);
diff --git a/services/audioflinger/SpdifStreamOut.h b/services/audioflinger/SpdifStreamOut.h
index d81c064..a61a7bd 100644
--- a/services/audioflinger/SpdifStreamOut.h
+++ b/services/audioflinger/SpdifStreamOut.h
@@ -49,10 +49,6 @@
             struct audio_config *config,
             const char *address);
 
-    virtual status_t getRenderPosition(uint32_t *frames);
-
-    virtual status_t getPresentationPosition(uint64_t *frames, struct timespec *timestamp);
-
     /**
     * Write audio buffer to driver. Returns number of bytes written, or a
     * negative status_t. If at least one frame was written successfully prior to the error,
@@ -92,13 +88,8 @@
         SpdifStreamOut * const mSpdifStreamOut;
     };
 
-    int                  mRateMultiplier;
     MySPDIFEncoder       mSpdifEncoder;
 
-    // Used to implement getRenderPosition()
-    int64_t              mRenderPositionHal;
-    uint32_t             mPreviousHalPosition32;
-
     ssize_t  writeDataBurst(const void* data, size_t bytes);
     ssize_t  writeInternal(const void* buffer, size_t bytes);
 
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index 966fb5c..d9f1a83 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -532,7 +532,8 @@
         // RecordThread::readInputParameters_l()
         //FIXME: mStandby should be true here. Is this some kind of hack?
         mStandby(false), mOutDevice(outDevice), mInDevice(inDevice),
-        mPrevInDevice(AUDIO_DEVICE_NONE), mAudioSource(AUDIO_SOURCE_DEFAULT), mId(id),
+        mPrevOutDevice(AUDIO_DEVICE_NONE), mPrevInDevice(AUDIO_DEVICE_NONE),
+        mAudioSource(AUDIO_SOURCE_DEFAULT), mId(id),
         // mName will be set by concrete (non-virtual) subclass
         mDeathRecipient(new PMDeathRecipient(this)),
         mSystemReady(systemReady)
@@ -627,16 +628,16 @@
     return status;
 }
 
-void AudioFlinger::ThreadBase::sendIoConfigEvent(audio_io_config_event event)
+void AudioFlinger::ThreadBase::sendIoConfigEvent(audio_io_config_event event, pid_t pid)
 {
     Mutex::Autolock _l(mLock);
-    sendIoConfigEvent_l(event);
+    sendIoConfigEvent_l(event, pid);
 }
 
 // sendIoConfigEvent_l() must be called with ThreadBase::mLock held
-void AudioFlinger::ThreadBase::sendIoConfigEvent_l(audio_io_config_event event)
+void AudioFlinger::ThreadBase::sendIoConfigEvent_l(audio_io_config_event event, pid_t pid)
 {
-    sp<ConfigEvent> configEvent = (ConfigEvent *)new IoConfigEvent(event);
+    sp<ConfigEvent> configEvent = (ConfigEvent *)new IoConfigEvent(event, pid);
     sendConfigEvent_l(configEvent);
 }
 
@@ -706,7 +707,7 @@
         } break;
         case CFG_EVENT_IO: {
             IoConfigEventData *data = (IoConfigEventData *)event->mData.get();
-            ioConfigChanged(data->mEvent);
+            ioConfigChanged(data->mEvent, data->mPid);
         } break;
         case CFG_EVENT_SET_PARAMETER: {
             SetParameterConfigEventData *data = (SetParameterConfigEventData *)event->mData.get();
@@ -1999,7 +2000,7 @@
     return out_s8;
 }
 
-void AudioFlinger::PlaybackThread::ioConfigChanged(audio_io_config_event event) {
+void AudioFlinger::PlaybackThread::ioConfigChanged(audio_io_config_event event, pid_t pid) {
     sp<AudioIoDescriptor> desc = new AudioIoDescriptor();
     ALOGV("PlaybackThread::ioConfigChanged, thread %p, event %d", this, event);
 
@@ -2021,7 +2022,7 @@
     default:
         break;
     }
-    mAudioFlinger->ioConfigChanged(event, desc);
+    mAudioFlinger->ioConfigChanged(event, desc, pid);
 }
 
 void AudioFlinger::PlaybackThread::writeCallback()
@@ -3133,7 +3134,10 @@
     for (size_t i = 0; i < mEffectChains.size(); i++) {
         mEffectChains[i]->setDevice_l(type);
     }
-    bool configChanged = mOutDevice != type;
+
+    // mPrevOutDevice is the latest device set by createAudioPatch_l(). It is not set when
+    // the thread is created so that the first patch creation triggers an ioConfigChanged callback
+    bool configChanged = mPrevOutDevice != type;
     mOutDevice = type;
     mPatch = *patch;
 
@@ -3163,6 +3167,7 @@
         *handle = AUDIO_PATCH_HANDLE_NONE;
     }
     if (configChanged) {
+        mPrevOutDevice = type;
         sendIoConfigEvent_l(AUDIO_OUTPUT_CONFIG_CHANGED);
     }
     return status;
@@ -6871,7 +6876,7 @@
     return out_s8;
 }
 
-void AudioFlinger::RecordThread::ioConfigChanged(audio_io_config_event event) {
+void AudioFlinger::RecordThread::ioConfigChanged(audio_io_config_event event, pid_t pid) {
     sp<AudioIoDescriptor> desc = new AudioIoDescriptor();
 
     desc->mIoHandle = mId;
@@ -6891,7 +6896,7 @@
     default:
         break;
     }
-    mAudioFlinger->ioConfigChanged(event, desc);
+    mAudioFlinger->ioConfigChanged(event, desc, pid);
 }
 
 void AudioFlinger::RecordThread::readInputParameters_l()
diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h
index 0783371..46ac300 100644
--- a/services/audioflinger/Threads.h
+++ b/services/audioflinger/Threads.h
@@ -104,21 +104,22 @@
 
     class IoConfigEventData : public ConfigEventData {
     public:
-        IoConfigEventData(audio_io_config_event event) :
-            mEvent(event) {}
+        IoConfigEventData(audio_io_config_event event, pid_t pid) :
+            mEvent(event), mPid(pid) {}
 
         virtual  void dump(char *buffer, size_t size) {
             snprintf(buffer, size, "IO event: event %d\n", mEvent);
         }
 
         const audio_io_config_event mEvent;
+        const pid_t                 mPid;
     };
 
     class IoConfigEvent : public ConfigEvent {
     public:
-        IoConfigEvent(audio_io_config_event event) :
+        IoConfigEvent(audio_io_config_event event, pid_t pid) :
             ConfigEvent(CFG_EVENT_IO) {
-            mData = new IoConfigEventData(event);
+            mData = new IoConfigEventData(event, pid);
         }
         virtual ~IoConfigEvent() {}
     };
@@ -255,13 +256,13 @@
                                                     status_t& status) = 0;
     virtual     status_t    setParameters(const String8& keyValuePairs);
     virtual     String8     getParameters(const String8& keys) = 0;
-    virtual     void        ioConfigChanged(audio_io_config_event event) = 0;
+    virtual     void        ioConfigChanged(audio_io_config_event event, pid_t pid = 0) = 0;
                 // sendConfigEvent_l() must be called with ThreadBase::mLock held
                 // Can temporarily release the lock if waiting for a reply from
                 // processConfigEvents_l().
                 status_t    sendConfigEvent_l(sp<ConfigEvent>& event);
-                void        sendIoConfigEvent(audio_io_config_event event);
-                void        sendIoConfigEvent_l(audio_io_config_event event);
+                void        sendIoConfigEvent(audio_io_config_event event, pid_t pid = 0);
+                void        sendIoConfigEvent_l(audio_io_config_event event, pid_t pid = 0);
                 void        sendPrioConfigEvent(pid_t pid, pid_t tid, int32_t prio);
                 void        sendPrioConfigEvent_l(pid_t pid, pid_t tid, int32_t prio);
                 status_t    sendSetParameterConfigEvent_l(const String8& keyValuePair);
@@ -436,6 +437,7 @@
                 bool                    mStandby;     // Whether thread is currently in standby.
                 audio_devices_t         mOutDevice;   // output device
                 audio_devices_t         mInDevice;    // input device
+                audio_devices_t         mPrevOutDevice;   // previous output device
                 audio_devices_t         mPrevInDevice;    // previous input device
                 struct audio_patch      mPatch;
                 audio_source_t          mAudioSource;
@@ -572,7 +574,7 @@
                                 { return android_atomic_acquire_load(&mSuspended) > 0; }
 
     virtual     String8     getParameters(const String8& keys);
-    virtual     void        ioConfigChanged(audio_io_config_event event);
+    virtual     void        ioConfigChanged(audio_io_config_event event, pid_t pid = 0);
                 status_t    getRenderPosition(uint32_t *halFrames, uint32_t *dspFrames);
                 // FIXME rename mixBuffer() to sinkBuffer() and remove int16_t* dependency.
                 // Consider also removing and passing an explicit mMainBuffer initialization
@@ -1254,7 +1256,7 @@
                                                status_t& status);
     virtual void        cacheParameters_l() {}
     virtual String8     getParameters(const String8& keys);
-    virtual void        ioConfigChanged(audio_io_config_event event);
+    virtual void        ioConfigChanged(audio_io_config_event event, pid_t pid = 0);
     virtual status_t    createAudioPatch_l(const struct audio_patch *patch,
                                            audio_patch_handle_t *handle);
     virtual status_t    releaseAudioPatch_l(const audio_patch_handle_t handle);
diff --git a/services/audiopolicy/common/include/Volume.h b/services/audiopolicy/common/include/Volume.h
index 4205589..712f7a7 100755
--- a/services/audiopolicy/common/include/Volume.h
+++ b/services/audiopolicy/common/include/Volume.h
@@ -82,6 +82,8 @@
             //  - HDMI-CEC system audio mode only output: give priority to available item in order.
             if (device & AUDIO_DEVICE_OUT_SPEAKER) {
                 device = AUDIO_DEVICE_OUT_SPEAKER;
+            } else if (device & AUDIO_DEVICE_OUT_SPEAKER_SAFE) {
+                device = AUDIO_DEVICE_OUT_SPEAKER_SAFE;
             } else if (device & AUDIO_DEVICE_OUT_HDMI_ARC) {
                 device = AUDIO_DEVICE_OUT_HDMI_ARC;
             } else if (device & AUDIO_DEVICE_OUT_AUX_LINE) {
diff --git a/services/audiopolicy/common/include/policy.h b/services/audiopolicy/common/include/policy.h
index 4eef02f2..4b73e3c 100755
--- a/services/audiopolicy/common/include/policy.h
+++ b/services/audiopolicy/common/include/policy.h
@@ -37,8 +37,9 @@
  * A device mask for all audio input and output devices where matching inputs/outputs on device
  * type alone is not enough: the address must match too
  */
-#define APM_AUDIO_DEVICE_MATCH_ADDRESS_ALL (AUDIO_DEVICE_IN_REMOTE_SUBMIX | \
-                                            AUDIO_DEVICE_OUT_REMOTE_SUBMIX)
+#define APM_AUDIO_DEVICE_OUT_MATCH_ADDRESS_ALL (AUDIO_DEVICE_OUT_REMOTE_SUBMIX)
+
+#define APM_AUDIO_DEVICE_IN_MATCH_ADDRESS_ALL (AUDIO_DEVICE_IN_REMOTE_SUBMIX)
 
 /**
  * Check if the state given correspond to an in call state.
@@ -80,5 +81,8 @@
  */
 static inline bool device_distinguishes_on_address(audio_devices_t device)
 {
-    return ((device & APM_AUDIO_DEVICE_MATCH_ADDRESS_ALL & ~AUDIO_DEVICE_BIT_IN) != 0);
+    return (((device & AUDIO_DEVICE_BIT_IN) != 0) &&
+            ((~AUDIO_DEVICE_BIT_IN & device & APM_AUDIO_DEVICE_IN_MATCH_ADDRESS_ALL) != 0)) ||
+           (((device & AUDIO_DEVICE_BIT_IN) == 0) &&
+            ((device & APM_AUDIO_DEVICE_OUT_MATCH_ADDRESS_ALL) != 0));
 }
diff --git a/services/audiopolicy/common/managerdefinitions/Android.mk b/services/audiopolicy/common/managerdefinitions/Android.mk
index 7c265aa..8728ff3 100644
--- a/services/audiopolicy/common/managerdefinitions/Android.mk
+++ b/services/audiopolicy/common/managerdefinitions/Android.mk
@@ -16,6 +16,7 @@
     src/EffectDescriptor.cpp \
     src/ConfigParsingUtils.cpp \
     src/SoundTriggerSession.cpp \
+    src/SessionRoute.cpp \
 
 LOCAL_SHARED_LIBRARIES := \
     libcutils \
diff --git a/services/audiopolicy/common/managerdefinitions/include/SessionRoute.h b/services/audiopolicy/common/managerdefinitions/include/SessionRoute.h
new file mode 100644
index 0000000..b4feaf0
--- /dev/null
+++ b/services/audiopolicy/common/managerdefinitions/include/SessionRoute.h
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <system/audio.h>
+#include <utils/KeyedVector.h>
+#include <utils/RefBase.h>
+#include <utils/Errors.h>
+
+namespace android {
+
+class DeviceDescriptor;
+
+class SessionRoute : public RefBase
+{
+public:
+    // For Input (Source) routes, use STREAM_TYPE_NA ("NA" = "not applicable)for the
+    // streamType argument
+    static const audio_stream_type_t STREAM_TYPE_NA = AUDIO_STREAM_DEFAULT;
+
+    // For Output (Sink) routes, use SOURCE_TYPE_NA ("NA" = "not applicable") for the
+    // source argument
+
+    static const audio_source_t SOURCE_TYPE_NA = AUDIO_SOURCE_DEFAULT;
+
+    SessionRoute(audio_session_t session,
+                 audio_stream_type_t streamType,
+                 audio_source_t source,
+                 sp<DeviceDescriptor> deviceDescriptor,
+                 uid_t uid)
+        : mUid(uid),
+          mSession(session),
+          mDeviceDescriptor(deviceDescriptor),
+          mRefCount(0),
+          mActivityCount(0),
+          mChanged(false),
+          mStreamType(streamType),
+          mSource(source)
+    {}
+
+    void log(const char* prefix);
+
+    bool isActive() {
+        return (mDeviceDescriptor != 0) && (mChanged || (mActivityCount > 0));
+    }
+
+    uid_t                       mUid;
+    audio_session_t             mSession;
+    sp<DeviceDescriptor>        mDeviceDescriptor;
+
+    // "reference" counting
+    int                         mRefCount;      // +/- on references
+    int                         mActivityCount; // +/- on start/stop
+    bool                        mChanged;
+    // for outputs
+    const audio_stream_type_t   mStreamType;
+    // for inputs
+    const audio_source_t        mSource;
+};
+
+class SessionRouteMap: public KeyedVector<audio_session_t, sp<SessionRoute> >
+{
+public:
+    // These constants identify the SessionRoutMap as holding EITHER input routes,
+    // or output routes.  An error will occur if an attempt is made to add a SessionRoute
+    // object with mStreamType == STREAM_TYPE_NA (i.e. an input SessionRoute) to a
+    // SessionRoutMap that is marked for output (i.e. mMapType == SESSION_ROUTE_MAP_OUTPUT)
+    // and similarly  for output SessionRoutes and Input SessionRouteMaps.
+    typedef enum
+    {
+        MAPTYPE_INPUT = 0,
+        MAPTYPE_OUTPUT = 1
+    } session_route_map_type_t;
+
+    SessionRouteMap(session_route_map_type_t mapType) :
+        mMapType(mapType)
+    {}
+
+    bool hasRoute(audio_session_t session);
+
+    void removeRoute(audio_session_t session);
+
+    int incRouteActivity(audio_session_t session);
+    int decRouteActivity(audio_session_t session);
+    bool hasRouteChanged(audio_session_t session); // also clears the changed flag
+    void log(const char* caption);
+
+    // Specify an Output(Sink) route by passing SessionRoute::SOURCE_TYPE_NA in the
+    // source argument.
+    // Specify an Input(Source) rout by passing SessionRoute::AUDIO_STREAM_DEFAULT
+    // in the streamType argument.
+    void addRoute(audio_session_t session,
+                  audio_stream_type_t streamType,
+                  audio_source_t source,
+                  sp<DeviceDescriptor> deviceDescriptor,
+                  uid_t uid);
+
+private:
+    // Used to mark a SessionRoute as for either inputs (mMapType == kSessionRouteMap_Input)
+    // or outputs (mMapType == kSessionRouteMap_Output)
+    const session_route_map_type_t mMapType;
+};
+
+}; // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/src/SessionRoute.cpp b/services/audiopolicy/common/managerdefinitions/src/SessionRoute.cpp
new file mode 100644
index 0000000..7ecfa44
--- /dev/null
+++ b/services/audiopolicy/common/managerdefinitions/src/SessionRoute.cpp
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "APM::SessionRoute"
+//#define LOG_NDEBUG 0
+
+#include "SessionRoute.h"
+#include "HwModule.h"
+#include "AudioGain.h"
+#include "DeviceDescriptor.h"
+#include <utils/Log.h>
+
+namespace android {
+
+// --- SessionRoute class implementation
+void SessionRoute::log(const char* prefix)
+{
+    ALOGI("%s[SessionRoute strm:0x%X, src:%d, sess:0x%X, dev:0x%X refs:%d act:%d",
+          prefix, mStreamType, mSource, mSession,
+          mDeviceDescriptor != 0 ? mDeviceDescriptor->type() : AUDIO_DEVICE_NONE,
+          mRefCount, mActivityCount);
+}
+
+// --- SessionRouteMap class implementation
+bool SessionRouteMap::hasRoute(audio_session_t session)
+{
+    return indexOfKey(session) >= 0 && valueFor(session)->mDeviceDescriptor != 0;
+}
+
+bool SessionRouteMap::hasRouteChanged(audio_session_t session)
+{
+    if (indexOfKey(session) >= 0) {
+        if (valueFor(session)->mChanged) {
+            valueFor(session)->mChanged = false;
+            return true;
+        }
+    }
+    return false;
+}
+
+void SessionRouteMap::removeRoute(audio_session_t session)
+{
+    sp<SessionRoute> route = indexOfKey(session) >= 0 ? valueFor(session) : 0;
+    if (route != 0) {
+        ALOG_ASSERT(route->mRefCount > 0);
+        --route->mRefCount;
+        if (route->mRefCount <= 0) {
+            removeItem(session);
+        }
+    }
+}
+
+int SessionRouteMap::incRouteActivity(audio_session_t session)
+{
+    sp<SessionRoute> route = indexOfKey(session) >= 0 ? valueFor(session) : 0;
+    return route != 0 ? ++(route->mActivityCount) : -1;
+}
+
+int SessionRouteMap::decRouteActivity(audio_session_t session)
+{
+    sp<SessionRoute> route = indexOfKey(session) >= 0 ? valueFor(session) : 0;
+    if (route != 0 && route->mActivityCount > 0) {
+        return --(route->mActivityCount);
+    } else {
+        return -1;
+    }
+}
+
+void SessionRouteMap::log(const char* caption)
+{
+    ALOGI("%s ----", caption);
+    for(size_t index = 0; index < size(); index++) {
+        valueAt(index)->log("  ");
+    }
+}
+
+void SessionRouteMap::addRoute(audio_session_t session,
+                               audio_stream_type_t streamType,
+                               audio_source_t source,
+                               sp<DeviceDescriptor> descriptor,
+                               uid_t uid)
+{
+    if (mMapType == MAPTYPE_INPUT && streamType != SessionRoute::STREAM_TYPE_NA) {
+        ALOGE("Adding Output Route to InputRouteMap");
+        return;
+    } else if (mMapType == MAPTYPE_OUTPUT && source != SessionRoute::SOURCE_TYPE_NA) {
+        ALOGE("Adding Input Route to OutputRouteMap");
+        return;
+    }
+
+    sp<SessionRoute> route = indexOfKey(session) >= 0 ? valueFor(session) : 0;
+
+    if (route != 0) {
+        if (((route->mDeviceDescriptor == 0) && (descriptor != 0)) ||
+                ((route->mDeviceDescriptor != 0) &&
+                 ((descriptor == 0) || (!route->mDeviceDescriptor->equals(descriptor))))) {
+            route->mChanged = true;
+        }
+        route->mRefCount++;
+        route->mDeviceDescriptor = descriptor;
+    } else {
+        route = new SessionRoute(session, streamType, source, descriptor, uid);
+        route->mRefCount++;
+        add(session, route);
+        if (descriptor != 0) {
+            route->mChanged = true;
+        }
+    }
+}
+
+} // namespace android
diff --git a/services/audiopolicy/enginedefault/src/Engine.cpp b/services/audiopolicy/enginedefault/src/Engine.cpp
index 7a785eb..0686414 100755
--- a/services/audiopolicy/enginedefault/src/Engine.cpp
+++ b/services/audiopolicy/enginedefault/src/Engine.cpp
@@ -319,8 +319,11 @@
             device = getDeviceForStrategy(STRATEGY_SONIFICATION);
             //user "safe" speaker if available instead of normal speaker to avoid triggering
             //other acoustic safety mechanisms for notification
-            if (device == AUDIO_DEVICE_OUT_SPEAKER && (availableOutputDevicesType & AUDIO_DEVICE_OUT_SPEAKER_SAFE))
-                device = AUDIO_DEVICE_OUT_SPEAKER_SAFE;
+            if ((device & AUDIO_DEVICE_OUT_SPEAKER) &&
+                    (availableOutputDevicesType & AUDIO_DEVICE_OUT_SPEAKER_SAFE)) {
+                device |= AUDIO_DEVICE_OUT_SPEAKER_SAFE;
+                device &= ~AUDIO_DEVICE_OUT_SPEAKER;
+            }
         } else if (outputs.isStreamActive(AUDIO_STREAM_MUSIC, SONIFICATION_RESPECTFUL_AFTER_MUSIC_DELAY)) {
             // while media is playing (or has recently played), use the same device
             device = getDeviceForStrategy(STRATEGY_MEDIA);
@@ -329,8 +332,11 @@
             device = getDeviceForStrategy(STRATEGY_SONIFICATION);
             //user "safe" speaker if available instead of normal speaker to avoid triggering
             //other acoustic safety mechanisms for notification
-            if (device == AUDIO_DEVICE_OUT_SPEAKER && (availableOutputDevicesType & AUDIO_DEVICE_OUT_SPEAKER_SAFE))
-                device = AUDIO_DEVICE_OUT_SPEAKER_SAFE;
+            if ((device & AUDIO_DEVICE_OUT_SPEAKER) &&
+                    (availableOutputDevicesType & AUDIO_DEVICE_OUT_SPEAKER_SAFE)) {
+                device |= AUDIO_DEVICE_OUT_SPEAKER_SAFE;
+                device &= ~AUDIO_DEVICE_OUT_SPEAKER;
+            }
         }
         break;
 
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index 6983b5c..6d99640 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -1076,6 +1076,9 @@
         beaconMuteLatency = handleEventForBeacon(STARTING_OUTPUT);
     }
 
+    // check active before incrementing usage count
+    bool force = !outputDesc->isActive();
+
     // increment usage count for this stream on the requested output:
     // NOTE that the usage count is the same for duplicated output and hardware output which is
     // necessary for a correct control of hardware output routing by startOutput() and stopOutput()
@@ -1091,7 +1094,6 @@
                             (strategy == STRATEGY_SONIFICATION_RESPECTFUL) ||
                             (beaconMuteLatency > 0);
         uint32_t waitMs = beaconMuteLatency;
-        bool force = false;
         for (size_t i = 0; i < mOutputs.size(); i++) {
             sp<AudioOutputDescriptor> desc = mOutputs.valueAt(i);
             if (desc != outputDesc) {
@@ -4721,99 +4723,7 @@
     }
 }
 
-// --- SessionRoute class implementation
-void AudioPolicyManager::SessionRoute::log(const char* prefix) {
-    ALOGI("%s[SessionRoute strm:0x%X, src:%d, sess:0x%X, dev:0x%X refs:%d act:%d",
-          prefix, mStreamType, mSource, mSession,
-          mDeviceDescriptor != 0 ? mDeviceDescriptor->type() : AUDIO_DEVICE_NONE,
-          mRefCount, mActivityCount);
-}
 
-// --- SessionRouteMap class implementation
-bool AudioPolicyManager::SessionRouteMap::hasRoute(audio_session_t session)
-{
-    return indexOfKey(session) >= 0 && valueFor(session)->mDeviceDescriptor != 0;
-}
-
-bool AudioPolicyManager::SessionRouteMap::hasRouteChanged(audio_session_t session)
-{
-    if (indexOfKey(session) >= 0) {
-        if (valueFor(session)->mChanged) {
-            valueFor(session)->mChanged = false;
-            return true;
-        }
-    }
-    return false;
-}
-
-void AudioPolicyManager::SessionRouteMap::removeRoute(audio_session_t session)
-{
-    sp<SessionRoute> route = indexOfKey(session) >= 0 ? valueFor(session) : 0;
-    if (route != 0) {
-        ALOG_ASSERT(route->mRefCount > 0);
-        --route->mRefCount;
-        if (route->mRefCount <= 0) {
-            removeItem(session);
-        }
-    }
-}
-
-int AudioPolicyManager::SessionRouteMap::incRouteActivity(audio_session_t session)
-{
-    sp<SessionRoute> route = indexOfKey(session) >= 0 ? valueFor(session) : 0;
-    return route != 0 ? ++(route->mActivityCount) : -1;
-}
-
-int AudioPolicyManager::SessionRouteMap::decRouteActivity(audio_session_t session)
-{
-    sp<SessionRoute> route = indexOfKey(session) >= 0 ? valueFor(session) : 0;
-    if (route != 0 && route->mActivityCount > 0) {
-        return --(route->mActivityCount);
-    } else {
-        return -1;
-    }
-}
-
-void AudioPolicyManager::SessionRouteMap::log(const char* caption) {
-    ALOGI("%s ----", caption);
-    for(size_t index = 0; index < size(); index++) {
-        valueAt(index)->log("  ");
-    }
-}
-
-void AudioPolicyManager::SessionRouteMap::addRoute(audio_session_t session,
-                                                   audio_stream_type_t streamType,
-                                                   audio_source_t source,
-                                                   sp<DeviceDescriptor> descriptor,
-                                                   uid_t uid)
-{
-    if (mMapType == MAPTYPE_INPUT && streamType != SessionRoute::STREAM_TYPE_NA) {
-        ALOGE("Adding Output Route to InputRouteMap");
-        return;
-    } else if (mMapType == MAPTYPE_OUTPUT && source != SessionRoute::SOURCE_TYPE_NA) {
-        ALOGE("Adding Input Route to OutputRouteMap");
-        return;
-    }
-
-    sp<SessionRoute> route = indexOfKey(session) >= 0 ? valueFor(session) : 0;
-
-    if (route != 0) {
-        if (((route->mDeviceDescriptor == 0) && (descriptor != 0)) ||
-                ((route->mDeviceDescriptor != 0) &&
-                 ((descriptor == 0) || (!route->mDeviceDescriptor->equals(descriptor))))) {
-            route->mChanged = true;
-        }
-        route->mRefCount++;
-        route->mDeviceDescriptor = descriptor;
-    } else {
-        route = new AudioPolicyManager::SessionRoute(session, streamType, source, descriptor, uid);
-        route->mRefCount++;
-        add(session, route);
-        if (descriptor != 0) {
-            route->mChanged = true;
-        }
-    }
-}
 
 void AudioPolicyManager::defaultAudioPolicyConfig(void)
 {
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.h b/services/audiopolicy/managerdefault/AudioPolicyManager.h
index cf64154..bf3ae4a 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.h
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.h
@@ -42,6 +42,7 @@
 #include <EffectDescriptor.h>
 #include <SoundTriggerSession.h>
 #include <StreamDescriptor.h>
+#include <SessionRoute.h>
 
 namespace android {
 
@@ -237,93 +238,6 @@
         routing_strategy getStrategy(audio_stream_type_t stream) const;
 
 protected:
-        class SessionRoute : public RefBase {
-        public:
-            // For Input (Source) routes, use STREAM_TYPE_NA ("NA" = "not applicable)for the
-            // streamType argument
-            static const audio_stream_type_t STREAM_TYPE_NA = AUDIO_STREAM_DEFAULT;
-
-            // For Output (Sink) routes, use SOURCE_TYPE_NA ("NA" = "not applicable") for the
-            // source argument
-
-            static const audio_source_t SOURCE_TYPE_NA = AUDIO_SOURCE_DEFAULT;
-
-            SessionRoute(audio_session_t session,
-                         audio_stream_type_t streamType,
-                         audio_source_t source,
-                         sp<DeviceDescriptor> deviceDescriptor,
-                         uid_t uid)
-               : mUid(uid),
-                 mSession(session),
-                 mDeviceDescriptor(deviceDescriptor),
-                 mRefCount(0),
-                 mActivityCount(0),
-                 mChanged(false),
-                 mStreamType(streamType),
-                 mSource(source)
-                  {}
-
-            void log(const char* prefix);
-
-            bool isActive() {
-                return (mDeviceDescriptor != 0) && (mChanged || (mActivityCount > 0));
-            }
-
-            uid_t                       mUid;
-            audio_session_t             mSession;
-            sp<DeviceDescriptor>        mDeviceDescriptor;
-
-            // "reference" counting
-            int                         mRefCount;      // +/- on references
-            int                         mActivityCount; // +/- on start/stop
-            bool                        mChanged;
-            // for outputs
-            const audio_stream_type_t   mStreamType;
-            // for inputs
-            const audio_source_t        mSource;
-        };
-
-        class SessionRouteMap: public KeyedVector<audio_session_t, sp<SessionRoute>> {
-        public:
-            // These constants identify the SessionRoutMap as holding EITHER input routes,
-            // or output routes.  An error will occur if an attempt is made to add a SessionRoute
-            // object with mStreamType == STREAM_TYPE_NA (i.e. an input SessionRoute) to a
-            // SessionRoutMap that is marked for output (i.e. mMapType == SESSION_ROUTE_MAP_OUTPUT)
-            // and similarly  for output SessionRoutes and Input SessionRouteMaps.
-            typedef enum {
-              MAPTYPE_INPUT = 0,
-              MAPTYPE_OUTPUT = 1
-            } session_route_map_type_t;
-
-            SessionRouteMap(session_route_map_type_t mapType) :
-                mMapType(mapType) {
-            }
-
-            bool hasRoute(audio_session_t session);
-
-            void removeRoute(audio_session_t session);
-
-            int incRouteActivity(audio_session_t session);
-            int decRouteActivity(audio_session_t session);
-            bool hasRouteChanged(audio_session_t session); // also clears the changed flag
-            void log(const char* caption);
-
-            // Specify an Output(Sink) route by passing SessionRoute::SOURCE_TYPE_NA in the
-            // source argument.
-            // Specify an Input(Source) rout by passing SessionRoute::AUDIO_STREAM_DEFAULT
-            // in the streamType argument.
-            void addRoute(audio_session_t session,
-                          audio_stream_type_t streamType,
-                          audio_source_t source,
-                          sp<DeviceDescriptor> deviceDescriptor,
-                          uid_t uid);
-
-        private:
-            // Used to mark a SessionRoute as for either inputs (mMapType == kSessionRouteMap_Input)
-            // or outputs (mMapType == kSessionRouteMap_Output)
-            const session_route_map_type_t mMapType;
-        };
-
         // From AudioPolicyManagerObserver
         virtual const AudioPatchCollection &getAudioPatches() const
         {