Merge "ACodec: process deferred messages when entering Loaded state." into lmp-dev
diff --git a/include/media/stagefright/ACodec.h b/include/media/stagefright/ACodec.h
index 28e5c56..d77ddaf 100644
--- a/include/media/stagefright/ACodec.h
+++ b/include/media/stagefright/ACodec.h
@@ -217,6 +217,8 @@
 
     bool mCreateInputBuffersSuspended;
 
+    bool mTunneled;
+
     status_t setCyclicIntraMacroblockRefresh(const sp<AMessage> &msg, int32_t mode);
     status_t allocateBuffersOnPort(OMX_U32 portIndex);
     status_t freeBuffersOnPort(OMX_U32 portIndex);
diff --git a/include/private/media/VideoFrame.h b/include/private/media/VideoFrame.h
index 5dd425b..5193d00 100644
--- a/include/private/media/VideoFrame.h
+++ b/include/private/media/VideoFrame.h
@@ -63,8 +63,11 @@
     uint32_t mDisplayWidth;
     uint32_t mDisplayHeight;
     uint32_t mSize;            // Number of bytes in mData
+    int32_t  mRotationAngle;   // rotation angle, clockwise, should be multiple of 90
+    // mData should be 64 bit aligned to prevent additional padding
     uint8_t* mData;            // Actual binary data
-    int32_t  mRotationAngle;   // rotation angle, clockwise
+    // pad structure so it's the same size on 64 bit and 32 bit
+    char     mPadding[8 - sizeof(mData)];
 };
 
 }; // namespace android
diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp
index e3beba5..8e0704f 100644
--- a/media/libmedia/AudioTrack.cpp
+++ b/media/libmedia/AudioTrack.cpp
@@ -2244,6 +2244,9 @@
             return true;
         }
     }
+    if (exitPending()) {
+        return false;
+    }
     nsecs_t ns = mReceiver.processAudioBuffer();
     switch (ns) {
     case 0:
diff --git a/media/libmediaplayerservice/StagefrightRecorder.cpp b/media/libmediaplayerservice/StagefrightRecorder.cpp
index 17190fb..cadd691 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.cpp
+++ b/media/libmediaplayerservice/StagefrightRecorder.cpp
@@ -1172,6 +1172,7 @@
             client.interface(),
             (mVideoEncoder == VIDEO_ENCODER_H263 ? MEDIA_MIMETYPE_VIDEO_H263 :
              mVideoEncoder == VIDEO_ENCODER_MPEG_4_SP ? MEDIA_MIMETYPE_VIDEO_MPEG4 :
+             mVideoEncoder == VIDEO_ENCODER_VP8 ? MEDIA_MIMETYPE_VIDEO_VP8 :
              mVideoEncoder == VIDEO_ENCODER_H264 ? MEDIA_MIMETYPE_VIDEO_AVC : ""),
             false /* decoder */, true /* hwCodec */, &codecs);
     *supportsCameraSourceMetaDataMode = codecs.size() > 0;
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
index 53eec91..1c73995 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
@@ -174,6 +174,7 @@
       mNumFramesDropped(0ll),
       mVideoScalingMode(NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW),
       mStarted(false) {
+    clearFlushComplete();
 }
 
 NuPlayer::~NuPlayer() {
@@ -333,25 +334,6 @@
     msg->post();
 }
 
-// static
-bool NuPlayer::IsFlushingState(FlushStatus state, bool *needShutdown) {
-    switch (state) {
-        case FLUSHING_DECODER:
-            if (needShutdown != NULL) {
-                *needShutdown = false;
-            }
-            return true;
-
-        case FLUSHING_DECODER_SHUTDOWN:
-            if (needShutdown != NULL) {
-                *needShutdown = true;
-            }
-            return true;
-
-        default:
-            return false;
-    }
-}
 
 void NuPlayer::writeTrackInfo(
         Parcel* reply, const sp<AMessage> format) const {
@@ -773,38 +755,9 @@
 
                 mRenderer->queueEOS(audio, err);
             } else if (what == Decoder::kWhatFlushCompleted) {
-                bool needShutdown;
-
-                if (audio) {
-                    CHECK(IsFlushingState(mFlushingAudio, &needShutdown));
-                    mFlushingAudio = FLUSHED;
-                } else {
-                    CHECK(IsFlushingState(mFlushingVideo, &needShutdown));
-                    mFlushingVideo = FLUSHED;
-
-                    mVideoLateByUs = 0;
-                }
-
                 ALOGV("decoder %s flush completed", audio ? "audio" : "video");
 
-                if (needShutdown) {
-                    ALOGV("initiating %s decoder shutdown",
-                         audio ? "audio" : "video");
-
-                    // Widevine source reads must stop before releasing the video decoder.
-                    if (!audio && mSource != NULL && mSourceFlags & Source::FLAG_SECURE) {
-                        mSource->stop();
-                    }
-
-                    getDecoder(audio)->initiateShutdown();
-
-                    if (audio) {
-                        mFlushingAudio = SHUTTING_DOWN_DECODER;
-                    } else {
-                        mFlushingVideo = SHUTTING_DOWN_DECODER;
-                    }
-                }
-
+                handleFlushComplete(audio, true /* isDecoder */);
                 finishFlushIfPossible();
             } else if (what == Decoder::kWhatOutputFormatChanged) {
                 sp<AMessage> format;
@@ -957,6 +910,8 @@
                 CHECK(msg->findInt32("audio", &audio));
 
                 ALOGV("renderer %s flush completed.", audio ? "audio" : "video");
+                handleFlushComplete(audio, false /* isDecoder */);
+                finishFlushIfPossible();
             } else if (what == Renderer::kWhatVideoRenderingStart) {
                 notifyListener(MEDIA_INFO, MEDIA_INFO_RENDERING_START, 0);
             } else if (what == Renderer::kWhatMediaRenderingStart) {
@@ -1084,6 +1039,50 @@
     return ((mFlushingAudio != SHUT_DOWN) && (mFlushingAudio != SHUTTING_DOWN_DECODER));
 }
 
+void NuPlayer::handleFlushComplete(bool audio, bool isDecoder) {
+    // We wait for both the decoder flush and the renderer flush to complete
+    // before entering either the FLUSHED or the SHUTTING_DOWN_DECODER state.
+
+    mFlushComplete[audio][isDecoder] = true;
+    if (!mFlushComplete[audio][!isDecoder]) {
+        return;
+    }
+
+    FlushStatus *state = audio ? &mFlushingAudio : &mFlushingVideo;
+    switch (*state) {
+        case FLUSHING_DECODER:
+        {
+            *state = FLUSHED;
+
+            if (!audio) {
+                mVideoLateByUs = 0;
+            }
+            break;
+        }
+
+        case FLUSHING_DECODER_SHUTDOWN:
+        {
+            *state = SHUTTING_DOWN_DECODER;
+
+            ALOGV("initiating %s decoder shutdown", audio ? "audio" : "video");
+            if (!audio) {
+                mVideoLateByUs = 0;
+                // Widevine source reads must stop before releasing the video decoder.
+                if (mSource != NULL && mSourceFlags & Source::FLAG_SECURE) {
+                    mSource->stop();
+                }
+            }
+            getDecoder(audio)->initiateShutdown();
+            break;
+        }
+
+        default:
+            // decoder flush completes only occur in a flushing state.
+            LOG_ALWAYS_FATAL_IF(isDecoder, "decoder flush in invalid state %d", *state);
+            break;
+    }
+}
+
 void NuPlayer::finishFlushIfPossible() {
     if (mFlushingAudio != NONE && mFlushingAudio != FLUSHED
             && mFlushingAudio != SHUT_DOWN) {
@@ -1116,6 +1115,8 @@
     mFlushingAudio = NONE;
     mFlushingVideo = NONE;
 
+    clearFlushComplete();
+
     processDeferredActions();
 }
 
@@ -1720,6 +1721,8 @@
     FlushStatus newStatus =
         needShutdown ? FLUSHING_DECODER_SHUTDOWN : FLUSHING_DECODER;
 
+    mFlushComplete[audio][false /* isDecoder */] = false;
+    mFlushComplete[audio][true /* isDecoder */] = false;
     if (audio) {
         ALOGE_IF(mFlushingAudio != NONE,
                 "audio flushDecoder() is called in state %d", mFlushingAudio);
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.h b/media/libmediaplayerservice/nuplayer/NuPlayer.h
index 8157733..1b9a756 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.h
@@ -164,6 +164,9 @@
     // notion of time has changed.
     bool mTimeDiscontinuityPending;
 
+    // Status of flush responses from the decoder and renderer.
+    bool mFlushComplete[2][2];
+
     // Used by feedDecoderInputData to aggregate small buffers into
     // one large buffer.
     sp<ABuffer> mPendingAudioAccessUnit;
@@ -187,6 +190,13 @@
         return audio ? mAudioDecoder : mVideoDecoder;
     }
 
+    inline void clearFlushComplete() {
+        mFlushComplete[0][0] = false;
+        mFlushComplete[0][1] = false;
+        mFlushComplete[1][0] = false;
+        mFlushComplete[1][1] = false;
+    }
+
     void openAudioSink(const sp<AMessage> &format, bool offloadOnly);
     void closeAudioSink();
 
@@ -201,6 +211,7 @@
 
     void notifyListener(int msg, int ext1, int ext2, const Parcel *in = NULL);
 
+    void handleFlushComplete(bool audio, bool isDecoder);
     void finishFlushIfPossible();
 
     bool audioDecoderStillNeeded();
@@ -209,8 +220,6 @@
             bool audio, bool needShutdown, const sp<AMessage> &newFormat = NULL);
     void updateDecoderFormatWithoutFlush(bool audio, const sp<AMessage> &format);
 
-    static bool IsFlushingState(FlushStatus state, bool *needShutdown = NULL);
-
     void postScanSources();
 
     void schedulePollDuration();
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
index 1a01d52..c57955d 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
@@ -582,7 +582,7 @@
 }
 
 void NuPlayerDriver::notifyResetComplete() {
-    ALOGI("notifyResetComplete(%p)", this);
+    ALOGD("notifyResetComplete(%p)", this);
     Mutex::Autolock autoLock(mLock);
 
     CHECK_EQ(mState, STATE_RESET_IN_PROGRESS);
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
index d6bf1de..e5c64f6 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
@@ -72,6 +72,7 @@
       mHasVideo(false),
       mSyncQueues(false),
       mPaused(false),
+      mPauseStartedTimeRealUs(-1),
       mVideoSampleReceived(false),
       mVideoRenderingStarted(false),
       mVideoRenderingStartGeneration(0),
@@ -574,7 +575,9 @@
             if (!mHasAudio) {
                 mAnchorTimeMediaUs = mediaTimeUs;
                 mAnchorTimeRealUs = nowUs;
-                notifyPosition();
+                if (!mPaused || mVideoSampleReceived) {
+                    notifyPosition();
+                }
             }
             realTimeUs = nowUs;
         } else {
@@ -645,6 +648,10 @@
         }
     } else {
         mVideoLateByUs = 0ll;
+        if (!mHasAudio && !mVideoSampleReceived) {
+            mAnchorTimeMediaUs = -1;
+            mAnchorTimeRealUs = -1;
+        }
     }
 
     entry->mNotifyConsumed->setInt64("timestampNs", realTimeUs * 1000ll);
@@ -830,6 +837,9 @@
     {
          Mutex::Autolock autoLock(mLock);
          syncQueuesDone_l();
+         if (!mHasAudio) {
+             mPauseStartedTimeRealUs = -1;
+         }
     }
 
     ALOGV("flushing %s", audio ? "audio" : "video");
@@ -980,6 +990,9 @@
         ++mVideoQueueGeneration;
         prepareForMediaRenderingStart();
         mPaused = true;
+        if (!mHasAudio) {
+            mPauseStartedTimeRealUs = ALooper::GetNowUs();
+        }
     }
 
     mDrainAudioQueuePending = false;
@@ -1008,6 +1021,10 @@
 
     Mutex::Autolock autoLock(mLock);
     mPaused = false;
+    if (!mHasAudio && mPauseStartedTimeRealUs != -1) {
+        mAnchorTimeRealUs += ALooper::GetNowUs() - mPauseStartedTimeRealUs;
+        mPauseStartedTimeRealUs = -1;
+    }
 
     if (!mAudioQueue.empty()) {
         postDrainAudioQueue_l();
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h
index 4237902..d27c238 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h
@@ -130,6 +130,7 @@
     bool mSyncQueues;
 
     bool mPaused;
+    int64_t mPauseStartedTimeRealUs;
     bool mVideoSampleReceived;
     bool mVideoRenderingStarted;
     int32_t mVideoRenderingStartGeneration;
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index b14efd7..b8d5c7b 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -421,7 +421,8 @@
       mMaxPtsGapUs(-1ll),
       mTimePerFrameUs(-1ll),
       mTimePerCaptureUs(-1ll),
-      mCreateInputBuffersSuspended(false) {
+      mCreateInputBuffersSuspended(false),
+      mTunneled(false) {
     mUninitializedState = new UninitializedState(this);
     mLoadedState = new LoadedState(this);
     mLoadedToIdleState = new LoadedToIdleState(this);
@@ -697,6 +698,21 @@
         return err;
     }
 
+    // Exits here for tunneled video playback codecs -- i.e. skips native window
+    // buffer allocation step as this is managed by the tunneled OMX omponent
+    // itself and explicitly sets def.nBufferCountActual to 0.
+    if (mTunneled) {
+        ALOGV("Tunneled Playback: skipping native window buffer allocation.");
+        def.nBufferCountActual = 0;
+        err = mOMX->setParameter(
+                mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
+
+        *minUndequeuedBuffers = 0;
+        *bufferCount = 0;
+        *bufferSize = 0;
+        return err;
+    }
+
     *minUndequeuedBuffers = 0;
     err = mNativeWindow->query(
             mNativeWindow.get(), NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS,
@@ -904,6 +920,13 @@
     ANativeWindowBuffer *buf;
     int fenceFd = -1;
     CHECK(mNativeWindow.get() != NULL);
+
+    if (mTunneled) {
+        ALOGW("dequeueBufferFromNativeWindow() should not be called in tunnel"
+              " video playback mode mode!");
+        return NULL;
+    }
+
     if (native_window_dequeue_buffer_and_wait(mNativeWindow.get(), &buf) != 0) {
         ALOGE("dequeueBuffer failed.");
         return NULL;
@@ -1245,6 +1268,7 @@
         if (msg->findInt32("feature-tunneled-playback", &tunneled) &&
             tunneled != 0) {
             ALOGI("Configuring TUNNELED video playback.");
+            mTunneled = true;
 
             int32_t audioHwSync = 0;
             if (!msg->findInt32("audio-hw-sync", &audioHwSync)) {
@@ -1259,6 +1283,9 @@
 
             inputFormat->setInt32("adaptive-playback", true);
         } else {
+            ALOGV("Configuring CPU controlled video playback.");
+            mTunneled = false;
+
             // Always try to enable dynamic output buffers on native surface
             err = mOMX->storeMetaDataInBuffers(
                     mNode, kPortIndexOutput, OMX_TRUE);
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index b568063..5f55484 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -780,7 +780,9 @@
                                 // STOPPING->UNINITIALIZED, instead of the
                                 // usual STOPPING->INITIALIZED state.
                                 setState(UNINITIALIZED);
-
+                                if (mState == RELEASING) {
+                                    mComponentName.clear();
+                                }
                                 (new AMessage)->postReply(mReplyID);
                             }
                             break;
@@ -1046,7 +1048,9 @@
                     }
 
                     if (mFlags & kFlagIsAsync) {
-                        onInputBufferAvailable();
+                        if (!mHaveInputSurface) {
+                            onInputBufferAvailable();
+                        }
                     } else if (mFlags & kFlagDequeueInputPending) {
                         CHECK(handleDequeueInputBuffer(mDequeueInputReplyID));
 
@@ -1130,6 +1134,7 @@
                     } else {
                         CHECK_EQ(mState, RELEASING);
                         setState(UNINITIALIZED);
+                        mComponentName.clear();
                     }
 
                     (new AMessage)->postReply(mReplyID);
@@ -1339,12 +1344,12 @@
                 // after stop() returned, it would be safe to call release()
                 // and it should be in this case, no harm to allow a release()
                 // if we're already uninitialized.
-                // Similarly stopping a stopped MediaCodec should be benign.
                 sp<AMessage> response = new AMessage;
-                response->setInt32(
-                        "err",
-                        mState == targetState ? OK : INVALID_OPERATION);
-
+                status_t err = mState == targetState ? OK : INVALID_OPERATION;
+                response->setInt32("err", err);
+                if (err == OK && targetState == UNINITIALIZED) {
+                    mComponentName.clear();
+                }
                 response->postReply(replyID);
                 break;
             }
@@ -1353,6 +1358,9 @@
                 // It's dead, Jim. Don't expect initiateShutdown to yield
                 // any useful results now...
                 setState(UNINITIALIZED);
+                if (targetState == UNINITIALIZED) {
+                    mComponentName.clear();
+                }
                 (new AMessage)->postReply(replyID);
                 break;
             }
@@ -1745,8 +1753,6 @@
         // return any straggling buffers, e.g. if we got here on an error
         returnBuffersToCodec();
 
-        mComponentName.clear();
-
         // The component is gone, mediaserver's probably back up already
         // but should definitely be back up should we try to instantiate
         // another component.. and the cycle continues.
diff --git a/media/libstagefright/codecs/aacdec/SoftAAC2.cpp b/media/libstagefright/codecs/aacdec/SoftAAC2.cpp
index 1b6eac4..40925fd 100644
--- a/media/libstagefright/codecs/aacdec/SoftAAC2.cpp
+++ b/media/libstagefright/codecs/aacdec/SoftAAC2.cpp
@@ -654,6 +654,7 @@
             inHeader->nOffset += inBufferUsedLength;
 
             AAC_DECODER_ERROR decoderErr;
+            int numLoops = 0;
             do {
                 if (outputDelayRingBufferSpaceLeft() <
                         (mStreamInfo->frameSize * mStreamInfo->numChannels)) {
@@ -661,20 +662,19 @@
                     break;
                 }
 
-                int numconsumed = mStreamInfo->numTotalBytes + mStreamInfo->numBadBytes;
+                int numConsumed = mStreamInfo->numTotalBytes;
                 decoderErr = aacDecoder_DecodeFrame(mAACDecoder,
                                            tmpOutBuffer,
                                            2048 * MAX_CHANNEL_COUNT,
                                            0 /* flags */);
 
-                numconsumed = (mStreamInfo->numTotalBytes + mStreamInfo->numBadBytes) - numconsumed;
-                if (numconsumed != 0) {
-                    mDecodedSizes.add(numconsumed);
-                }
+                numConsumed = mStreamInfo->numTotalBytes - numConsumed;
+                numLoops++;
 
                 if (decoderErr == AAC_DEC_NOT_ENOUGH_BITS) {
                     break;
                 }
+                mDecodedSizes.add(numConsumed);
 
                 if (decoderErr != AAC_DEC_OK) {
                     ALOGW("aacDecoder_DecodeFrame decoderErr = 0x%4.4x", decoderErr);
@@ -716,6 +716,15 @@
 
                     aacDecoder_SetParam(mAACDecoder, AAC_TPDEC_CLEAR_BUFFER, 1);
 
+                    // After an error, replace the last entry in mBufferSizes with the sum of the
+                    // last <numLoops> entries from mDecodedSizes to resynchronize the in/out lists.
+                    mBufferSizes.pop();
+                    int n = 0;
+                    for (int i = 0; i < numLoops; i++) {
+                        n += mDecodedSizes.itemAt(mDecodedSizes.size() - numLoops + i);
+                    }
+                    mBufferSizes.add(n);
+
                     // fall through
                 }
 
diff --git a/services/audiopolicy/AudioPolicyClientImplLegacy.cpp b/services/audiopolicy/AudioPolicyClientImplLegacy.cpp
index 9639096..97719da 100644
--- a/services/audiopolicy/AudioPolicyClientImplLegacy.cpp
+++ b/services/audiopolicy/AudioPolicyClientImplLegacy.cpp
@@ -96,7 +96,7 @@
         *pFormat = config.format;
         *pChannelMask = config.channel_mask;
         if (offloadInfo != NULL) {
-            *offloadInfo = config.offload_info;
+            *((audio_offload_info_t *)offloadInfo) = config.offload_info;
         }
     }
     return output;
diff --git a/services/audiopolicy/AudioPolicyEffects.cpp b/services/audiopolicy/AudioPolicyEffects.cpp
index c45acd0..3c1c042 100644
--- a/services/audiopolicy/AudioPolicyEffects.cpp
+++ b/services/audiopolicy/AudioPolicyEffects.cpp
@@ -87,6 +87,7 @@
     audio_source_t aliasSource = (inputSource == AUDIO_SOURCE_HOTWORD) ?
                                     AUDIO_SOURCE_VOICE_RECOGNITION : inputSource;
 
+    Mutex::Autolock _l(mLock);
     ssize_t index = mInputSources.indexOfKey(aliasSource);
     if (index < 0) {
         ALOGV("addInputEffects(): no processing needs to be attached to this source");
@@ -122,7 +123,7 @@
         ALOGV("addInputEffects(): added Fx %s on source: %d", effect->mName, (int32_t)aliasSource);
         inputDesc->mEffects.add(fx);
     }
-    setProcessorEnabled(inputDesc, true);
+    inputDesc->setProcessorEnabled(true);
 
     return status;
 }
@@ -132,6 +133,7 @@
 {
     status_t status = NO_ERROR;
 
+    Mutex::Autolock _l(mLock);
     ssize_t index = mInputs.indexOfKey(input);
     if (index < 0) {
         return status;
@@ -140,7 +142,7 @@
     inputDesc->mRefCount--;
     ALOGV("releaseInputEffects(): input: %d, refCount: %d", input, inputDesc->mRefCount);
     if (inputDesc->mRefCount == 0) {
-        setProcessorEnabled(inputDesc, false);
+        inputDesc->setProcessorEnabled(false);
         delete inputDesc;
         mInputs.removeItemsAt(index);
         ALOGV("releaseInputEffects(): all effects released");
@@ -154,6 +156,7 @@
 {
     status_t status = NO_ERROR;
 
+    Mutex::Autolock _l(mLock);
     size_t index;
     for (index = 0; index < mInputs.size(); index++) {
         if (mInputs.valueAt(index)->mSessionId == audioSession) {
@@ -186,6 +189,7 @@
 {
     status_t status = NO_ERROR;
 
+    Mutex::Autolock _l(mLock);
     size_t index;
     for (index = 0; index < mOutputSessions.size(); index++) {
         if (mOutputSessions.valueAt(index)->mSessionId == audioSession) {
@@ -218,6 +222,7 @@
 {
     status_t status = NO_ERROR;
 
+    Mutex::Autolock _l(mLock);
     // create audio processors according to stream
     ssize_t index = mOutputStreams.indexOfKey(stream);
     if (index < 0) {
@@ -254,7 +259,7 @@
         procDesc->mEffects.add(fx);
     }
 
-    setProcessorEnabled(procDesc, true);
+    procDesc->setProcessorEnabled(true);
 
     return status;
 }
@@ -267,6 +272,7 @@
     (void) output; // argument not used for now
     (void) stream; // argument not used for now
 
+    Mutex::Autolock _l(mLock);
     ssize_t index = mOutputSessions.indexOfKey(audioSession);
     if (index < 0) {
         ALOGV("releaseOutputSessionEffects: no output processing was attached to this stream");
@@ -277,7 +283,7 @@
     procDesc->mRefCount--;
     ALOGV("releaseOutputSessionEffects(): session: %d, refCount: %d", audioSession, procDesc->mRefCount);
     if (procDesc->mRefCount == 0) {
-        setProcessorEnabled(procDesc, false);
+        procDesc->setProcessorEnabled(false);
         procDesc->mEffects.clear();
         delete procDesc;
         mOutputSessions.removeItemsAt(index);
@@ -288,11 +294,10 @@
 }
 
 
-void AudioPolicyEffects::setProcessorEnabled(const EffectVector *effectVector, bool enabled)
+void AudioPolicyEffects::EffectVector::setProcessorEnabled(bool enabled)
 {
-    const Vector<sp<AudioEffect> > &fxVector = effectVector->mEffects;
-    for (size_t i = 0; i < fxVector.size(); i++) {
-        fxVector.itemAt(i)->setEnabled(enabled);
+    for (size_t i = 0; i < mEffects.size(); i++) {
+        mEffects.itemAt(i)->setEnabled(enabled);
     }
 }
 
@@ -313,7 +318,7 @@
 
 // returns the audio_source_t enum corresponding to the input source name or
 // AUDIO_SOURCE_CNT is no match found
-audio_source_t AudioPolicyEffects::inputSourceNameToEnum(const char *name)
+/*static*/ audio_source_t AudioPolicyEffects::inputSourceNameToEnum(const char *name)
 {
     int i;
     for (i = AUDIO_SOURCE_MIC; i < AUDIO_SOURCE_CNT; i++) {
diff --git a/services/audiopolicy/AudioPolicyEffects.h b/services/audiopolicy/AudioPolicyEffects.h
index dbe0d0e..6b0d538 100644
--- a/services/audiopolicy/AudioPolicyEffects.h
+++ b/services/audiopolicy/AudioPolicyEffects.h
@@ -45,6 +45,10 @@
 	         AudioPolicyEffects();
     virtual ~AudioPolicyEffects();
 
+    // NOTE: methods on AudioPolicyEffects should never be called with the AudioPolicyService
+    // main mutex (mLock) held as they will indirectly call back into AudioPolicyService when
+    // managing audio effects.
+
     // Return a list of effect descriptors for default input effects
     // associated with audioSession
     status_t queryDefaultInputEffects(int audioSession,
@@ -133,6 +137,10 @@
     public:
         EffectVector(int session) : mSessionId(session), mRefCount(0) {}
         /*virtual*/ ~EffectVector() {}
+
+        // Enable or disable all effects in effect vector
+        void setProcessorEnabled(bool enabled);
+
         const int mSessionId;
         // AudioPolicyManager keeps mLock, no need for lock on reference count here
         int mRefCount;
@@ -141,14 +149,11 @@
 
 
     static const char * const kInputSourceNames[AUDIO_SOURCE_CNT -1];
-    audio_source_t inputSourceNameToEnum(const char *name);
+    static audio_source_t inputSourceNameToEnum(const char *name);
 
     static const char *kStreamNames[AUDIO_STREAM_CNT+1]; //+1 required as streams start from -1
     audio_stream_type_t streamNameToEnum(const char *name);
 
-    // Enable or disable all effects in effect vector
-    void setProcessorEnabled(const EffectVector *effectVector, bool enabled);
-
     // Parse audio_effects.conf
     status_t loadAudioEffectConfig(const char *path);
 
@@ -173,6 +178,8 @@
                          size_t *curSize,
                          size_t *totSize);
 
+    // protects access to mInputSources, mInputs, mOutputStreams, mOutputSessions
+    Mutex mLock;
     // Automatic input effects are configured per audio_source_t
     KeyedVector< audio_source_t, EffectDescVector* > mInputSources;
     // Automatic input effects are unique for audio_io_handle_t
diff --git a/services/audiopolicy/AudioPolicyInterfaceImpl.cpp b/services/audiopolicy/AudioPolicyInterfaceImpl.cpp
index b212ca6..6cd0ac8 100644
--- a/services/audiopolicy/AudioPolicyInterfaceImpl.cpp
+++ b/services/audiopolicy/AudioPolicyInterfaceImpl.cpp
@@ -162,14 +162,19 @@
         return NO_INIT;
     }
     ALOGV("startOutput()");
-    Mutex::Autolock _l(mLock);
-
-    // create audio processors according to stream
-    status_t status = mAudioPolicyEffects->addOutputSessionEffects(output, stream, session);
-    if (status != NO_ERROR && status != ALREADY_EXISTS) {
-        ALOGW("Failed to add effects on session %d", session);
+    sp<AudioPolicyEffects>audioPolicyEffects;
+    {
+        Mutex::Autolock _l(mLock);
+        audioPolicyEffects = mAudioPolicyEffects;
     }
-
+    if (audioPolicyEffects != 0) {
+        // create audio processors according to stream
+        status_t status = audioPolicyEffects->addOutputSessionEffects(output, stream, session);
+        if (status != NO_ERROR && status != ALREADY_EXISTS) {
+            ALOGW("Failed to add effects on session %d", session);
+        }
+    }
+    Mutex::Autolock _l(mLock);
     return mAudioPolicyManager->startOutput(output, stream, session);
 }
 
@@ -190,14 +195,19 @@
                                       int session)
 {
     ALOGV("doStopOutput from tid %d", gettid());
-    Mutex::Autolock _l(mLock);
-
-    // release audio processors from the stream
-    status_t status = mAudioPolicyEffects->releaseOutputSessionEffects(output, stream, session);
-    if (status != NO_ERROR && status != ALREADY_EXISTS) {
-        ALOGW("Failed to release effects on session %d", session);
+    sp<AudioPolicyEffects>audioPolicyEffects;
+    {
+        Mutex::Autolock _l(mLock);
+        audioPolicyEffects = mAudioPolicyEffects;
     }
-
+    if (audioPolicyEffects != 0) {
+        // release audio processors from the stream
+        status_t status = audioPolicyEffects->releaseOutputSessionEffects(output, stream, session);
+        if (status != NO_ERROR && status != ALREADY_EXISTS) {
+            ALOGW("Failed to release effects on session %d", session);
+        }
+    }
+    Mutex::Autolock _l(mLock);
     return mAudioPolicyManager->stopOutput(output, stream, session);
 }
 
@@ -235,23 +245,26 @@
     if ((inputSource == AUDIO_SOURCE_HOTWORD) && !captureHotwordAllowed()) {
         return 0;
     }
-
-    Mutex::Autolock _l(mLock);
-    // the audio_in_acoustics_t parameter is ignored by get_input()
-    audio_io_handle_t input = mAudioPolicyManager->getInput(inputSource, samplingRate,
-                                                   format, channelMask,
-                                                   (audio_session_t)audioSession, flags);
-
+    audio_io_handle_t input;
+    sp<AudioPolicyEffects>audioPolicyEffects;
+    {
+        Mutex::Autolock _l(mLock);
+        // the audio_in_acoustics_t parameter is ignored by get_input()
+        input = mAudioPolicyManager->getInput(inputSource, samplingRate,
+                                                       format, channelMask,
+                                                       (audio_session_t)audioSession, flags);
+        audioPolicyEffects = mAudioPolicyEffects;
+    }
     if (input == 0) {
         return input;
     }
-
-    // create audio pre processors according to input source
-    status_t status = mAudioPolicyEffects->addInputEffects(input, inputSource, audioSession);
-    if (status != NO_ERROR && status != ALREADY_EXISTS) {
-        ALOGW("Failed to add effects on input %d", input);
+    if (audioPolicyEffects != 0) {
+        // create audio pre processors according to input source
+        status_t status = audioPolicyEffects->addInputEffects(input, inputSource, audioSession);
+        if (status != NO_ERROR && status != ALREADY_EXISTS) {
+            ALOGW("Failed to add effects on input %d", input);
+        }
     }
-
     return input;
 }
 
@@ -283,13 +296,18 @@
     if (mAudioPolicyManager == NULL) {
         return;
     }
-    Mutex::Autolock _l(mLock);
-    mAudioPolicyManager->releaseInput(input, session);
-
-    // release audio processors from the input
-    status_t status = mAudioPolicyEffects->releaseInputEffects(input);
-    if(status != NO_ERROR) {
-        ALOGW("Failed to release effects on input %d", input);
+    sp<AudioPolicyEffects>audioPolicyEffects;
+    {
+        Mutex::Autolock _l(mLock);
+        mAudioPolicyManager->releaseInput(input, session);
+        audioPolicyEffects = mAudioPolicyEffects;
+    }
+    if (audioPolicyEffects != 0) {
+        // release audio processors from the input
+        status_t status = audioPolicyEffects->releaseInputEffects(input);
+        if(status != NO_ERROR) {
+            ALOGW("Failed to release effects on input %d", input);
+        }
     }
 }
 
@@ -437,9 +455,16 @@
         *count = 0;
         return NO_INIT;
     }
-    Mutex::Autolock _l(mLock);
-
-    return mAudioPolicyEffects->queryDefaultInputEffects(audioSession, descriptors, count);
+    sp<AudioPolicyEffects>audioPolicyEffects;
+    {
+        Mutex::Autolock _l(mLock);
+        audioPolicyEffects = mAudioPolicyEffects;
+    }
+    if (audioPolicyEffects == 0) {
+        *count = 0;
+        return NO_INIT;
+    }
+    return audioPolicyEffects->queryDefaultInputEffects(audioSession, descriptors, count);
 }
 
 bool AudioPolicyService::isOffloadSupported(const audio_offload_info_t& info)
diff --git a/services/audiopolicy/AudioPolicyInterfaceImplLegacy.cpp b/services/audiopolicy/AudioPolicyInterfaceImplLegacy.cpp
index 1e40bc3..e1e81e1 100644
--- a/services/audiopolicy/AudioPolicyInterfaceImplLegacy.cpp
+++ b/services/audiopolicy/AudioPolicyInterfaceImplLegacy.cpp
@@ -24,6 +24,7 @@
 #include <system/audio.h>
 #include <system/audio_policy.h>
 #include <hardware/audio_policy.h>
+#include <media/AudioPolicyHelper.h>
 
 namespace android {
 
@@ -150,14 +151,20 @@
         return NO_INIT;
     }
     ALOGV("startOutput()");
-    Mutex::Autolock _l(mLock);
-
     // create audio processors according to stream
-    status_t status = mAudioPolicyEffects->addOutputSessionEffects(output, stream, session);
-    if (status != NO_ERROR && status != ALREADY_EXISTS) {
-        ALOGW("Failed to add effects on session %d", session);
+    sp<AudioPolicyEffects>audioPolicyEffects;
+    {
+        Mutex::Autolock _l(mLock);
+        audioPolicyEffects = mAudioPolicyEffects;
+    }
+    if (audioPolicyEffects != 0) {
+        status_t status = audioPolicyEffects->addOutputSessionEffects(output, stream, session);
+        if (status != NO_ERROR && status != ALREADY_EXISTS) {
+            ALOGW("Failed to add effects on session %d", session);
+        }
     }
 
+    Mutex::Autolock _l(mLock);
     return mpAudioPolicy->start_output(mpAudioPolicy, output, stream, session);
 }
 
@@ -178,14 +185,19 @@
                                       int session)
 {
     ALOGV("doStopOutput from tid %d", gettid());
-    Mutex::Autolock _l(mLock);
-
     // release audio processors from the stream
-    status_t status = mAudioPolicyEffects->releaseOutputSessionEffects(output, stream, session);
-    if (status != NO_ERROR && status != ALREADY_EXISTS) {
-        ALOGW("Failed to release effects on session %d", session);
+    sp<AudioPolicyEffects>audioPolicyEffects;
+    {
+        Mutex::Autolock _l(mLock);
+        audioPolicyEffects = mAudioPolicyEffects;
     }
-
+    if (audioPolicyEffects != 0) {
+        status_t status = audioPolicyEffects->releaseOutputSessionEffects(output, stream, session);
+        if (status != NO_ERROR && status != ALREADY_EXISTS) {
+            ALOGW("Failed to release effects on session %d", session);
+        }
+    }
+    Mutex::Autolock _l(mLock);
     return mpAudioPolicy->stop_output(mpAudioPolicy, output, stream, session);
 }
 
@@ -224,21 +236,26 @@
         return 0;
     }
 
-    Mutex::Autolock _l(mLock);
-    // the audio_in_acoustics_t parameter is ignored by get_input()
-    audio_io_handle_t input = mpAudioPolicy->get_input(mpAudioPolicy, inputSource, samplingRate,
-                                                   format, channelMask, (audio_in_acoustics_t) 0);
-
+    audio_io_handle_t input;
+    sp<AudioPolicyEffects>audioPolicyEffects;
+    {
+        Mutex::Autolock _l(mLock);
+        // the audio_in_acoustics_t parameter is ignored by get_input()
+        input = mpAudioPolicy->get_input(mpAudioPolicy, inputSource, samplingRate,
+                                             format, channelMask, (audio_in_acoustics_t) 0);
+        audioPolicyEffects = mAudioPolicyEffects;
+    }
     if (input == 0) {
         return input;
     }
 
-    // create audio pre processors according to input source
-    status_t status = mAudioPolicyEffects->addInputEffects(input, inputSource, audioSession);
-    if (status != NO_ERROR && status != ALREADY_EXISTS) {
-        ALOGW("Failed to add effects on input %d", input);
+    if (audioPolicyEffects != 0) {
+        // create audio pre processors according to input source
+        status_t status = audioPolicyEffects->addInputEffects(input, inputSource, audioSession);
+        if (status != NO_ERROR && status != ALREADY_EXISTS) {
+            ALOGW("Failed to add effects on input %d", input);
+        }
     }
-
     return input;
 }
 
@@ -270,13 +287,19 @@
     if (mpAudioPolicy == NULL) {
         return;
     }
-    Mutex::Autolock _l(mLock);
-    mpAudioPolicy->release_input(mpAudioPolicy, input);
 
-    // release audio processors from the input
-    status_t status = mAudioPolicyEffects->releaseInputEffects(input);
-    if(status != NO_ERROR) {
-        ALOGW("Failed to release effects on input %d", input);
+    sp<AudioPolicyEffects>audioPolicyEffects;
+    {
+        Mutex::Autolock _l(mLock);
+        mpAudioPolicy->release_input(mpAudioPolicy, input);
+        audioPolicyEffects = mAudioPolicyEffects;
+    }
+    if (audioPolicyEffects != 0) {
+        // release audio processors from the input
+        status_t status = audioPolicyEffects->releaseInputEffects(input);
+        if(status != NO_ERROR) {
+            ALOGW("Failed to release effects on input %d", input);
+        }
     }
 }
 
@@ -437,9 +460,16 @@
         *count = 0;
         return NO_INIT;
     }
-    Mutex::Autolock _l(mLock);
-
-    return mAudioPolicyEffects->queryDefaultInputEffects(audioSession, descriptors, count);
+    sp<AudioPolicyEffects>audioPolicyEffects;
+    {
+        Mutex::Autolock _l(mLock);
+        audioPolicyEffects = mAudioPolicyEffects;
+    }
+    if (audioPolicyEffects == 0) {
+        *count = 0;
+        return NO_INIT;
+    }
+    return audioPolicyEffects->queryDefaultInputEffects(audioSession, descriptors, count);
 }
 
 bool AudioPolicyService::isOffloadSupported(const audio_offload_info_t& info)
@@ -496,7 +526,7 @@
     return INVALID_OPERATION;
 }
 
-audio_io_handle_t AudioPolicyService::getOutputForAttr(const audio_attributes_t *attr __unused,
+audio_io_handle_t AudioPolicyService::getOutputForAttr(const audio_attributes_t *attr,
                                     uint32_t samplingRate,
                                     audio_format_t format,
                                     audio_channel_mask_t channelMask,
diff --git a/services/audiopolicy/AudioPolicyService.cpp b/services/audiopolicy/AudioPolicyService.cpp
index 647cda4..06a7e84 100644
--- a/services/audiopolicy/AudioPolicyService.cpp
+++ b/services/audiopolicy/AudioPolicyService.cpp
@@ -61,56 +61,65 @@
     : BnAudioPolicyService(), mpAudioPolicyDev(NULL), mpAudioPolicy(NULL),
       mAudioPolicyManager(NULL), mAudioPolicyClient(NULL), mPhoneState(AUDIO_MODE_INVALID)
 {
+}
+
+void AudioPolicyService::onFirstRef()
+{
     char value[PROPERTY_VALUE_MAX];
     const struct hw_module_t *module;
     int forced_val;
     int rc;
 
-    Mutex::Autolock _l(mLock);
+    {
+        Mutex::Autolock _l(mLock);
 
-    // start tone playback thread
-    mTonePlaybackThread = new AudioCommandThread(String8("ApmTone"), this);
-    // start audio commands thread
-    mAudioCommandThread = new AudioCommandThread(String8("ApmAudio"), this);
-    // start output activity command thread
-    mOutputCommandThread = new AudioCommandThread(String8("ApmOutput"), this);
+        // start tone playback thread
+        mTonePlaybackThread = new AudioCommandThread(String8("ApmTone"), this);
+        // start audio commands thread
+        mAudioCommandThread = new AudioCommandThread(String8("ApmAudio"), this);
+        // start output activity command thread
+        mOutputCommandThread = new AudioCommandThread(String8("ApmOutput"), this);
 
 #ifdef USE_LEGACY_AUDIO_POLICY
-    ALOGI("AudioPolicyService CSTOR in legacy mode");
+        ALOGI("AudioPolicyService CSTOR in legacy mode");
 
-    /* instantiate the audio policy manager */
-    rc = hw_get_module(AUDIO_POLICY_HARDWARE_MODULE_ID, &module);
-    if (rc) {
-        return;
-    }
-    rc = audio_policy_dev_open(module, &mpAudioPolicyDev);
-    ALOGE_IF(rc, "couldn't open audio policy device (%s)", strerror(-rc));
-    if (rc) {
-        return;
-    }
+        /* instantiate the audio policy manager */
+        rc = hw_get_module(AUDIO_POLICY_HARDWARE_MODULE_ID, &module);
+        if (rc) {
+            return;
+        }
+        rc = audio_policy_dev_open(module, &mpAudioPolicyDev);
+        ALOGE_IF(rc, "couldn't open audio policy device (%s)", strerror(-rc));
+        if (rc) {
+            return;
+        }
 
-    rc = mpAudioPolicyDev->create_audio_policy(mpAudioPolicyDev, &aps_ops, this,
-                                               &mpAudioPolicy);
-    ALOGE_IF(rc, "couldn't create audio policy (%s)", strerror(-rc));
-    if (rc) {
-        return;
-    }
+        rc = mpAudioPolicyDev->create_audio_policy(mpAudioPolicyDev, &aps_ops, this,
+                                                   &mpAudioPolicy);
+        ALOGE_IF(rc, "couldn't create audio policy (%s)", strerror(-rc));
+        if (rc) {
+            return;
+        }
 
-    rc = mpAudioPolicy->init_check(mpAudioPolicy);
-    ALOGE_IF(rc, "couldn't init_check the audio policy (%s)", strerror(-rc));
-    if (rc) {
-        return;
-    }
-    ALOGI("Loaded audio policy from %s (%s)", module->name, module->id);
+        rc = mpAudioPolicy->init_check(mpAudioPolicy);
+        ALOGE_IF(rc, "couldn't init_check the audio policy (%s)", strerror(-rc));
+        if (rc) {
+            return;
+        }
+        ALOGI("Loaded audio policy from %s (%s)", module->name, module->id);
 #else
-    ALOGI("AudioPolicyService CSTOR in new mode");
+        ALOGI("AudioPolicyService CSTOR in new mode");
 
-    mAudioPolicyClient = new AudioPolicyClient(this);
-    mAudioPolicyManager = createAudioPolicyManager(mAudioPolicyClient);
+        mAudioPolicyClient = new AudioPolicyClient(this);
+        mAudioPolicyManager = createAudioPolicyManager(mAudioPolicyClient);
 #endif
-
+    }
     // load audio processing modules
-    mAudioPolicyEffects = new AudioPolicyEffects();
+    sp<AudioPolicyEffects>audioPolicyEffects = new AudioPolicyEffects();
+    {
+        Mutex::Autolock _l(mLock);
+        mAudioPolicyEffects = audioPolicyEffects;
+    }
 }
 
 AudioPolicyService::~AudioPolicyService()
diff --git a/services/audiopolicy/AudioPolicyService.h b/services/audiopolicy/AudioPolicyService.h
index 2cea40b..4e68ab1 100644
--- a/services/audiopolicy/AudioPolicyService.h
+++ b/services/audiopolicy/AudioPolicyService.h
@@ -134,6 +134,9 @@
     // IBinder::DeathRecipient
     virtual     void        binderDied(const wp<IBinder>& who);
 
+    // RefBase
+    virtual     void        onFirstRef();
+
     //
     // Helpers for the struct audio_policy_service_ops implementation.
     // This is used by the audio policy manager for certain operations that