Merge "stagefright: prevent allocating stale buffers for OMX decoders" into mnc-dev
diff --git a/include/media/AudioSystem.h b/include/media/AudioSystem.h
index 26cffa6..06116a5 100644
--- a/include/media/AudioSystem.h
+++ b/include/media/AudioSystem.h
@@ -408,8 +408,8 @@
         AudioPolicyServiceClient() {
         }
 
-        status_t addAudioPortCallback(const sp<AudioPortCallback>& callback);
-        status_t removeAudioPortCallback(const sp<AudioPortCallback>& callback);
+        int addAudioPortCallback(const sp<AudioPortCallback>& callback);
+        int removeAudioPortCallback(const sp<AudioPortCallback>& callback);
 
         // DeathRecipient
         virtual void binderDied(const wp<IBinder>& who);
diff --git a/include/media/IAudioPolicyService.h b/include/media/IAudioPolicyService.h
index ee462a0..6b93f6f 100644
--- a/include/media/IAudioPolicyService.h
+++ b/include/media/IAudioPolicyService.h
@@ -149,6 +149,8 @@
 
     virtual void registerClient(const sp<IAudioPolicyServiceClient>& client) = 0;
 
+    virtual void setAudioPortCallbacksEnabled(bool enabled) = 0;
+
     virtual status_t acquireSoundTriggerSession(audio_session_t *session,
                                            audio_io_handle_t *ioHandle,
                                            audio_devices_t *device) = 0;
diff --git a/include/media/stagefright/MediaCodecSource.h b/include/media/stagefright/MediaCodecSource.h
index a991b02..71f58a9 100644
--- a/include/media/stagefright/MediaCodecSource.h
+++ b/include/media/stagefright/MediaCodecSource.h
@@ -108,6 +108,9 @@
     bool mStarted;
     bool mStopping;
     bool mDoMoreWorkPending;
+    bool mSetEncoderFormat;
+    int mEncoderFormat;
+    int mEncoderDataSpace;
     sp<AMessage> mEncoderActivityNotify;
     sp<IGraphicBufferProducer> mGraphicBufferProducer;
     sp<IGraphicBufferConsumer> mGraphicBufferConsumer;
diff --git a/include/media/stagefright/MetaData.h b/include/media/stagefright/MetaData.h
index ca80123..726b197 100644
--- a/include/media/stagefright/MetaData.h
+++ b/include/media/stagefright/MetaData.h
@@ -70,7 +70,9 @@
     kKeyDriftTime         = 'dftT',  // int64_t (usecs)
     kKeyAnchorTime        = 'ancT',  // int64_t (usecs)
     kKeyDuration          = 'dura',  // int64_t (usecs)
-    kKeyColorFormat       = 'colf',
+    kKeyPixelFormat       = 'pixf',  // int32_t
+    kKeyColorFormat       = 'colf',  // int32_t
+    kKeyColorSpace        = 'cols',  // int32_t
     kKeyPlatformPrivate   = 'priv',  // pointer
     kKeyDecoderComponent  = 'decC',  // cstring
     kKeyBufferID          = 'bfID',
diff --git a/media/libmedia/AudioSystem.cpp b/media/libmedia/AudioSystem.cpp
index 6c2c226..f13bcf3 100644
--- a/media/libmedia/AudioSystem.cpp
+++ b/media/libmedia/AudioSystem.cpp
@@ -1043,7 +1043,11 @@
     if (gAudioPolicyServiceClient == 0) {
         return NO_INIT;
     }
-    return gAudioPolicyServiceClient->addAudioPortCallback(callback);
+    int ret = gAudioPolicyServiceClient->addAudioPortCallback(callback);
+    if (ret == 1) {
+        aps->setAudioPortCallbacksEnabled(true);
+    }
+    return (ret < 0) ? INVALID_OPERATION : NO_ERROR;
 }
 
 /*static*/
@@ -1056,7 +1060,11 @@
     if (gAudioPolicyServiceClient == 0) {
         return NO_INIT;
     }
-    return gAudioPolicyServiceClient->removeAudioPortCallback(callback);
+    int ret = gAudioPolicyServiceClient->removeAudioPortCallback(callback);
+    if (ret == 0) {
+        aps->setAudioPortCallbacksEnabled(false);
+    }
+    return (ret < 0) ? INVALID_OPERATION : NO_ERROR;
 }
 
 status_t AudioSystem::addAudioDeviceCallback(
@@ -1138,20 +1146,20 @@
 
 // ---------------------------------------------------------------------------
 
-status_t AudioSystem::AudioPolicyServiceClient::addAudioPortCallback(
+int AudioSystem::AudioPolicyServiceClient::addAudioPortCallback(
         const sp<AudioPortCallback>& callback)
 {
     Mutex::Autolock _l(mLock);
     for (size_t i = 0; i < mAudioPortCallbacks.size(); i++) {
         if (mAudioPortCallbacks[i] == callback) {
-            return INVALID_OPERATION;
+            return -1;
         }
     }
     mAudioPortCallbacks.add(callback);
-    return NO_ERROR;
+    return mAudioPortCallbacks.size();
 }
 
-status_t AudioSystem::AudioPolicyServiceClient::removeAudioPortCallback(
+int AudioSystem::AudioPolicyServiceClient::removeAudioPortCallback(
         const sp<AudioPortCallback>& callback)
 {
     Mutex::Autolock _l(mLock);
@@ -1162,10 +1170,10 @@
         }
     }
     if (i == mAudioPortCallbacks.size()) {
-        return INVALID_OPERATION;
+        return -1;
     }
     mAudioPortCallbacks.removeAt(i);
-    return NO_ERROR;
+    return mAudioPortCallbacks.size();
 }
 
 
diff --git a/media/libmedia/IAudioPolicyService.cpp b/media/libmedia/IAudioPolicyService.cpp
index fd18f17..3348441 100644
--- a/media/libmedia/IAudioPolicyService.cpp
+++ b/media/libmedia/IAudioPolicyService.cpp
@@ -72,7 +72,8 @@
     GET_PHONE_STATE,
     REGISTER_POLICY_MIXES,
     START_AUDIO_SOURCE,
-    STOP_AUDIO_SOURCE
+    STOP_AUDIO_SOURCE,
+    SET_AUDIO_PORT_CALLBACK_ENABLED,
 };
 
 #define MAX_ITEMS_PER_LIST 1024
@@ -646,6 +647,14 @@
         remote()->transact(REGISTER_CLIENT, data, &reply);
     }
 
+    virtual void setAudioPortCallbacksEnabled(bool enabled)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
+        data.writeInt32(enabled ? 1 : 0);
+        remote()->transact(SET_AUDIO_PORT_CALLBACK_ENABLED, data, &reply);
+    }
+
     virtual status_t acquireSoundTriggerSession(audio_session_t *session,
                                             audio_io_handle_t *ioHandle,
                                             audio_devices_t *device)
@@ -1219,6 +1228,12 @@
             return NO_ERROR;
         } break;
 
+        case SET_AUDIO_PORT_CALLBACK_ENABLED: {
+            CHECK_INTERFACE(IAudioPolicyService, data, reply);
+            setAudioPortCallbacksEnabled(data.readInt32() == 1);
+            return NO_ERROR;
+        } break;
+
         case ACQUIRE_SOUNDTRIGGER_SESSION: {
             CHECK_INTERFACE(IAudioPolicyService, data, reply);
             sp<IAudioPolicyServiceClient> client = interface_cast<IAudioPolicyServiceClient>(
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index 383966f..7452e4b 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -1639,6 +1639,14 @@
         if (mInputMetadataType == kMetadataBufferTypeGrallocSource) {
             mInputMetadataType = kMetadataBufferTypeCameraSource;
         }
+
+        uint32_t usageBits;
+        if (mOMX->getParameter(
+                mNode, (OMX_INDEXTYPE)OMX_IndexParamConsumerUsageBits,
+                &usageBits, sizeof(usageBits)) == OK) {
+            inputFormat->setInt32(
+                    "using-sw-read-often", !!(usageBits & GRALLOC_USAGE_SW_READ_OFTEN));
+        }
     }
 
     int32_t prependSPSPPS = 0;
@@ -5749,6 +5757,14 @@
         }
     }
 
+    uint32_t usageBits;
+    if (mCodec->mOMX->getParameter(
+            mCodec->mNode, (OMX_INDEXTYPE)OMX_IndexParamConsumerUsageBits,
+            &usageBits, sizeof(usageBits)) == OK) {
+        mCodec->mInputFormat->setInt32(
+                "using-sw-read-often", !!(usageBits & GRALLOC_USAGE_SW_READ_OFTEN));
+    }
+
     return OK;
 }
 
diff --git a/media/libstagefright/CameraSource.cpp b/media/libstagefright/CameraSource.cpp
index 2606e44..bc34bcf 100644
--- a/media/libstagefright/CameraSource.cpp
+++ b/media/libstagefright/CameraSource.cpp
@@ -670,9 +670,13 @@
             mNumInputBuffers = nBuffers;
         }
 
-        // TODO: Read in format/dataspace from somewhere
-        // Uncomment to test SW encoders until TODO is resolved
-        // mEncoderFormat = HAL_PIXEL_FORMAT_YCbCr_420_888;
+        // apply encoder color format if specified
+        if (meta->findInt32(kKeyPixelFormat, &mEncoderFormat)) {
+            ALOGV("Using encoder format: %#x", mEncoderFormat);
+        }
+        if (meta->findInt32(kKeyColorSpace, &mEncoderDataSpace)) {
+            ALOGV("Using encoder data space: %#x", mEncoderDataSpace);
+        }
     }
 
     status_t err;
diff --git a/media/libstagefright/MediaCodecList.cpp b/media/libstagefright/MediaCodecList.cpp
index 8993403..7ea5cbd 100644
--- a/media/libstagefright/MediaCodecList.cpp
+++ b/media/libstagefright/MediaCodecList.cpp
@@ -38,6 +38,7 @@
 #include <sys/stat.h>
 #include <utils/threads.h>
 
+#include <cutils/properties.h>
 #include <libexpat/expat.h>
 
 namespace android {
@@ -56,6 +57,11 @@
 }
 
 static bool isProfilingNeeded() {
+    int8_t value = property_get_bool("debug.stagefright.profilecodec", 0);
+    if (value == 0) {
+        return false;
+    }
+
     bool profilingNeeded = true;
     FILE *resultsFile = fopen(kProfilingResults, "r");
     if (resultsFile) {
@@ -169,6 +175,7 @@
       mUpdate(false),
       mGlobalSettings(new AMessage()) {
     parseTopLevelXMLFile("/etc/media_codecs.xml");
+    parseTopLevelXMLFile("/etc/media_codecs_performance.xml", true/* ignore_errors */);
     parseTopLevelXMLFile(kProfilingResults, true/* ignore_errors */);
 }
 
@@ -929,7 +936,7 @@
     if (name == "aspect-ratio" || name == "bitrate" || name == "block-count"
             || name == "blocks-per-second" || name == "complexity"
             || name == "frame-rate" || name == "quality" || name == "size"
-            || name == "measured-blocks-per-second" || name == "measured-frame-rate") {
+            || name == "measured-blocks-per-second" || name.startsWith("measured-frame-rate-")) {
         AString min, max;
         if (msg->findString("min", &min) && msg->findString("max", &max)) {
             min.append("-");
@@ -1005,8 +1012,7 @@
             return limitFoundMissingAttr(name, "ranges", found);
         } else if (msg->contains("scale")) {
             return limitFoundMissingAttr(name, "scale");
-        } else if ((name == "alignment" || name == "block-size"
-                || name == "max-supported-instances") ^
+        } else if ((name == "alignment" || name == "block-size") ^
                 (found = msg->findString("value", &value))) {
             return limitFoundMissingAttr(name, "value", found);
         }
diff --git a/media/libstagefright/MediaCodecSource.cpp b/media/libstagefright/MediaCodecSource.cpp
index e089c46..7f9f824 100644
--- a/media/libstagefright/MediaCodecSource.cpp
+++ b/media/libstagefright/MediaCodecSource.cpp
@@ -39,6 +39,9 @@
 
 namespace android {
 
+const int kDefaultSwVideoEncoderFormat = HAL_PIXEL_FORMAT_YCbCr_420_888;
+const int kDefaultSwVideoEncoderDataSpace = HAL_DATASPACE_BT709;
+
 struct MediaCodecSource::Puller : public AHandler {
     Puller(const sp<MediaSource> &source);
 
@@ -341,6 +344,9 @@
       mStarted(false),
       mStopping(false),
       mDoMoreWorkPending(false),
+      mSetEncoderFormat(false),
+      mEncoderFormat(0),
+      mEncoderDataSpace(0),
       mGraphicBufferConsumer(consumer),
       mFirstSampleTimeUs(-1ll),
       mEncoderReachedEOS(false),
@@ -438,6 +444,18 @@
         }
     }
 
+    sp<AMessage> inputFormat;
+    int32_t usingSwReadOften;
+    mSetEncoderFormat = false;
+    if (mEncoder->getInputFormat(&inputFormat) == OK
+            && inputFormat->findInt32("using-sw-read-often", &usingSwReadOften)
+            && usingSwReadOften) {
+        // this is a SW encoder; signal source to allocate SW readable buffers
+        mSetEncoderFormat = true;
+        mEncoderFormat = kDefaultSwVideoEncoderFormat;
+        mEncoderDataSpace = kDefaultSwVideoEncoderDataSpace;
+    }
+
     err = mEncoder->start();
 
     if (err != OK) {
@@ -632,8 +650,17 @@
         resume(startTimeUs);
     } else {
         CHECK(mPuller != NULL);
+        sp<MetaData> meta = params;
+        if (mSetEncoderFormat) {
+            if (meta == NULL) {
+                meta = new MetaData;
+            }
+            meta->setInt32(kKeyPixelFormat, mEncoderFormat);
+            meta->setInt32(kKeyColorSpace, mEncoderDataSpace);
+        }
+
         sp<AMessage> notify = new AMessage(kWhatPullerNotify, mReflector);
-        err = mPuller->start(params, notify);
+        err = mPuller->start(meta.get(), notify);
         if (err != OK) {
             return err;
         }
diff --git a/media/libstagefright/codecs/mp3dec/SoftMP3.cpp b/media/libstagefright/codecs/mp3dec/SoftMP3.cpp
index 5396022..f743b1c 100644
--- a/media/libstagefright/codecs/mp3dec/SoftMP3.cpp
+++ b/media/libstagefright/codecs/mp3dec/SoftMP3.cpp
@@ -283,6 +283,11 @@
             } else {
                 // This is recoverable, just ignore the current frame and
                 // play silence instead.
+
+                // TODO: should we skip silence (and consume input data)
+                // if mIsFirst is true as we may not have a valid
+                // mConfig->samplingRate and mConfig->num_channels?
+                ALOGV_IF(mIsFirst, "insufficient data for first frame, sending silence");
                 memset(outHeader->pBuffer,
                        0,
                        mConfig->outputFrameSize * sizeof(int16_t));
@@ -317,8 +322,7 @@
         }
 
         outHeader->nTimeStamp =
-            mAnchorTimeUs
-                + (mNumFramesOutput * 1000000ll) / mConfig->samplingRate;
+            mAnchorTimeUs + (mNumFramesOutput * 1000000ll) / mSamplingRate;
 
         if (inHeader) {
             CHECK_GE(inHeader->nFilledLen, mConfig->inputBufferUsedLength);
diff --git a/media/libstagefright/omx/GraphicBufferSource.cpp b/media/libstagefright/omx/GraphicBufferSource.cpp
index ac64685..1a7dc9d 100644
--- a/media/libstagefright/omx/GraphicBufferSource.cpp
+++ b/media/libstagefright/omx/GraphicBufferSource.cpp
@@ -23,6 +23,7 @@
 #include "GraphicBufferSource.h"
 
 #include <OMX_Core.h>
+#include <OMX_IndexExt.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/AMessage.h>
 
@@ -110,6 +111,7 @@
         uint32_t bufferWidth,
         uint32_t bufferHeight,
         uint32_t bufferCount,
+        uint32_t consumerUsage,
         const sp<IGraphicBufferConsumer> &consumer) :
     mInitCheck(UNKNOWN_ERROR),
     mNodeInstance(nodeInstance),
@@ -152,7 +154,12 @@
 
         BufferQueue::createBufferQueue(&mProducer, &mConsumer);
         mConsumer->setConsumerName(name);
-        mConsumer->setConsumerUsageBits(GRALLOC_USAGE_HW_VIDEO_ENCODER);
+
+        // use consumer usage bits queried from encoder, but always add HW_VIDEO_ENCODER
+        // for backward compatibility.
+        consumerUsage |= GRALLOC_USAGE_HW_VIDEO_ENCODER;
+        mConsumer->setConsumerUsageBits(consumerUsage);
+
         mInitCheck = mConsumer->setMaxAcquiredBufferCount(bufferCount);
         if (mInitCheck != NO_ERROR) {
             ALOGE("Unable to set BQ max acquired buffer count to %u: %d",
diff --git a/media/libstagefright/omx/GraphicBufferSource.h b/media/libstagefright/omx/GraphicBufferSource.h
index 3f64088..2f929d9 100644
--- a/media/libstagefright/omx/GraphicBufferSource.h
+++ b/media/libstagefright/omx/GraphicBufferSource.h
@@ -55,6 +55,7 @@
             uint32_t bufferWidth,
             uint32_t bufferHeight,
             uint32_t bufferCount,
+            uint32_t consumerUsage,
             const sp<IGraphicBufferConsumer> &consumer = NULL
     );
 
diff --git a/media/libstagefright/omx/OMXNodeInstance.cpp b/media/libstagefright/omx/OMXNodeInstance.cpp
index 147aae7..9f1c5d8 100644
--- a/media/libstagefright/omx/OMXNodeInstance.cpp
+++ b/media/libstagefright/omx/OMXNodeInstance.cpp
@@ -834,7 +834,8 @@
     }
 
     CLOG_BUFFER(updateGraphicBufferInMeta, "%s:%u, %#x := %p",
-            portString(portIndex), portIndex, buffer, graphicBuffer->handle);
+            portString(portIndex), portIndex, buffer,
+            graphicBuffer == NULL ? NULL : graphicBuffer->handle);
     return OK;
 }
 
@@ -885,10 +886,18 @@
         return INVALID_OPERATION;
     }
 
+    uint32_t usageBits;
+    oerr = OMX_GetParameter(
+            mHandle, (OMX_INDEXTYPE)OMX_IndexParamConsumerUsageBits, &usageBits);
+    if (oerr != OMX_ErrorNone) {
+        usageBits = 0;
+    }
+
     sp<GraphicBufferSource> bufferSource = new GraphicBufferSource(this,
             def.format.video.nFrameWidth,
             def.format.video.nFrameHeight,
             def.nBufferCountActual,
+            usageBits,
             bufferConsumer);
 
     if ((err = bufferSource->initCheck()) != OK) {
@@ -1607,7 +1616,12 @@
         return NULL;
     }
     Mutex::Autolock autoLock(mBufferIDLock);
-    return mBufferIDToBufferHeader.valueFor(buffer);
+    ssize_t index = mBufferIDToBufferHeader.indexOfKey(buffer);
+    if (index < 0) {
+        CLOGW("findBufferHeader: buffer %u not found", buffer);
+        return NULL;
+    }
+    return mBufferIDToBufferHeader.valueAt(index);
 }
 
 OMX::buffer_id OMXNodeInstance::findBufferID(OMX_BUFFERHEADERTYPE *bufferHeader) {
@@ -1615,7 +1629,12 @@
         return 0;
     }
     Mutex::Autolock autoLock(mBufferIDLock);
-    return mBufferHeaderToBufferID.valueFor(bufferHeader);
+    ssize_t index = mBufferHeaderToBufferID.indexOfKey(bufferHeader);
+    if (index < 0) {
+        CLOGW("findBufferID: bufferHeader %p not found", bufferHeader);
+        return 0;
+    }
+    return mBufferHeaderToBufferID.valueAt(index);
 }
 
 void OMXNodeInstance::invalidateBufferID(OMX::buffer_id buffer) {
@@ -1623,8 +1642,13 @@
         return;
     }
     Mutex::Autolock autoLock(mBufferIDLock);
-    mBufferHeaderToBufferID.removeItem(mBufferIDToBufferHeader.valueFor(buffer));
-    mBufferIDToBufferHeader.removeItem(buffer);
+    ssize_t index = mBufferIDToBufferHeader.indexOfKey(buffer);
+    if (index < 0) {
+        CLOGW("invalidateBufferID: buffer %u not found", buffer);
+        return;
+    }
+    mBufferHeaderToBufferID.removeItem(mBufferIDToBufferHeader.valueAt(index));
+    mBufferIDToBufferHeader.removeItemsAt(index);
 }
 
 }  // namespace android
diff --git a/media/libstagefright/omx/SoftVideoEncoderOMXComponent.cpp b/media/libstagefright/omx/SoftVideoEncoderOMXComponent.cpp
index 9dd26fb..8ea7a6e 100644
--- a/media/libstagefright/omx/SoftVideoEncoderOMXComponent.cpp
+++ b/media/libstagefright/omx/SoftVideoEncoderOMXComponent.cpp
@@ -34,6 +34,8 @@
 #include <ui/GraphicBuffer.h>
 #include <ui/GraphicBufferMapper.h>
 
+#include <OMX_IndexExt.h>
+
 namespace android {
 
 const static OMX_COLOR_FORMATTYPE kSupportedColorFormats[] = {
@@ -293,7 +295,7 @@
 
 OMX_ERRORTYPE SoftVideoEncoderOMXComponent::internalGetParameter(
         OMX_INDEXTYPE index, OMX_PTR param) {
-    switch (index) {
+    switch ((int)index) {
         case OMX_IndexParamVideoErrorCorrection:
         {
             return OMX_ErrorNotImplemented;
@@ -343,6 +345,13 @@
             return OMX_ErrorNone;
         }
 
+        case OMX_IndexParamConsumerUsageBits:
+        {
+            OMX_U32 *usageBits = (OMX_U32 *)param;
+            *usageBits = GRALLOC_USAGE_SW_READ_OFTEN;
+            return OMX_ErrorNone;
+        }
+
         default:
             return SimpleSoftOMXComponent::internalGetParameter(index, param);
     }
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index 410fff5..c8f9be0 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -530,7 +530,7 @@
         // RecordThread::readInputParameters_l()
         //FIXME: mStandby should be true here. Is this some kind of hack?
         mStandby(false), mOutDevice(outDevice), mInDevice(inDevice),
-        mAudioSource(AUDIO_SOURCE_DEFAULT), mId(id),
+        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)
@@ -3131,6 +3131,7 @@
     for (size_t i = 0; i < mEffectChains.size(); i++) {
         mEffectChains[i]->setDevice_l(type);
     }
+    bool configChanged = mOutDevice != type;
     mOutDevice = type;
     mPatch = *patch;
 
@@ -3159,7 +3160,9 @@
                 param.toString().string());
         *handle = AUDIO_PATCH_HANDLE_NONE;
     }
-    sendIoConfigEvent_l(AUDIO_OUTPUT_CONFIG_CHANGED);
+    if (configChanged) {
+        sendIoConfigEvent_l(AUDIO_OUTPUT_CONFIG_CHANGED);
+    }
     return status;
 }
 
@@ -6796,6 +6799,9 @@
             status = BAD_VALUE;
         } else {
             mInDevice = value;
+            if (value != AUDIO_DEVICE_NONE) {
+                mPrevInDevice = value;
+            }
             // disable AEC and NS if the device is a BT SCO headset supporting those
             // pre processings
             if (mTracks.size() > 0) {
@@ -7079,7 +7085,10 @@
         *handle = AUDIO_PATCH_HANDLE_NONE;
     }
 
-    sendIoConfigEvent_l(AUDIO_INPUT_CONFIG_CHANGED);
+    if (mInDevice != mPrevInDevice) {
+        sendIoConfigEvent_l(AUDIO_INPUT_CONFIG_CHANGED);
+        mPrevInDevice = mInDevice;
+    }
 
     return status;
 }
diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h
index b12b091..0783371 100644
--- a/services/audioflinger/Threads.h
+++ b/services/audioflinger/Threads.h
@@ -436,6 +436,7 @@
                 bool                    mStandby;     // Whether thread is currently in standby.
                 audio_devices_t         mOutDevice;   // output device
                 audio_devices_t         mInDevice;    // input device
+                audio_devices_t         mPrevInDevice;    // previous input device
                 struct audio_patch      mPatch;
                 audio_source_t          mAudioSource;
 
diff --git a/services/audiopolicy/service/AudioPolicyService.cpp b/services/audiopolicy/service/AudioPolicyService.cpp
index c5f4fb7..fbe4f18 100644
--- a/services/audiopolicy/service/AudioPolicyService.cpp
+++ b/services/audiopolicy/service/AudioPolicyService.cpp
@@ -166,6 +166,17 @@
     }
 }
 
+void AudioPolicyService::setAudioPortCallbacksEnabled(bool enabled)
+{
+    Mutex::Autolock _l(mNotificationClientsLock);
+
+    uid_t uid = IPCThreadState::self()->getCallingUid();
+    if (mNotificationClients.indexOfKey(uid) < 0) {
+        return;
+    }
+    mNotificationClients.valueFor(uid)->setAudioPortCallbacksEnabled(enabled);
+}
+
 // removeNotificationClient() is called when the client process dies.
 void AudioPolicyService::removeNotificationClient(uid_t uid)
 {
@@ -246,7 +257,8 @@
 AudioPolicyService::NotificationClient::NotificationClient(const sp<AudioPolicyService>& service,
                                                      const sp<IAudioPolicyServiceClient>& client,
                                                      uid_t uid)
-    : mService(service), mUid(uid), mAudioPolicyServiceClient(client)
+    : mService(service), mUid(uid), mAudioPolicyServiceClient(client),
+      mAudioPortCallbacksEnabled(false)
 {
 }
 
@@ -265,14 +277,14 @@
 
 void AudioPolicyService::NotificationClient::onAudioPortListUpdate()
 {
-    if (mAudioPolicyServiceClient != 0) {
+    if (mAudioPolicyServiceClient != 0 && mAudioPortCallbacksEnabled) {
         mAudioPolicyServiceClient->onAudioPortListUpdate();
     }
 }
 
 void AudioPolicyService::NotificationClient::onAudioPatchListUpdate()
 {
-    if (mAudioPolicyServiceClient != 0) {
+    if (mAudioPolicyServiceClient != 0 && mAudioPortCallbacksEnabled) {
         mAudioPolicyServiceClient->onAudioPatchListUpdate();
     }
 }
@@ -285,6 +297,12 @@
     }
 }
 
+void AudioPolicyService::NotificationClient::setAudioPortCallbacksEnabled(bool enabled)
+{
+    mAudioPortCallbacksEnabled = enabled;
+}
+
+
 void AudioPolicyService::binderDied(const wp<IBinder>& who) {
     ALOGW("binderDied() %p, calling pid %d", who.unsafe_get(),
             IPCThreadState::self()->getCallingPid());
diff --git a/services/audiopolicy/service/AudioPolicyService.h b/services/audiopolicy/service/AudioPolicyService.h
index eb50cdd..a0d5aa2 100644
--- a/services/audiopolicy/service/AudioPolicyService.h
+++ b/services/audiopolicy/service/AudioPolicyService.h
@@ -185,6 +185,8 @@
 
     virtual void registerClient(const sp<IAudioPolicyServiceClient>& client);
 
+    virtual void setAudioPortCallbacksEnabled(bool enabled);
+
     virtual status_t acquireSoundTriggerSession(audio_session_t *session,
                                            audio_io_handle_t *ioHandle,
                                            audio_devices_t *device);
@@ -507,6 +509,7 @@
                             void      onAudioPortListUpdate();
                             void      onAudioPatchListUpdate();
                             void      onDynamicPolicyMixStateUpdate(String8 regId, int32_t state);
+                            void      setAudioPortCallbacksEnabled(bool enabled);
 
                 // IBinder::DeathRecipient
                 virtual     void        binderDied(const wp<IBinder>& who);
@@ -518,6 +521,7 @@
         const wp<AudioPolicyService>        mService;
         const uid_t                         mUid;
         const sp<IAudioPolicyServiceClient> mAudioPolicyServiceClient;
+              bool                          mAudioPortCallbacksEnabled;
     };
 
     // Internal dump utilities.
diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp
index 4b55dad..9e73b5c 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Device.cpp
@@ -164,9 +164,17 @@
         return res;
     }
 
-    /** Start up request queue thread */
+    bool aeLockAvailable = false;
+    camera_metadata_ro_entry aeLockAvailableEntry;
+    res = find_camera_metadata_ro_entry(info.static_camera_characteristics,
+            ANDROID_CONTROL_AE_LOCK_AVAILABLE, &aeLockAvailableEntry);
+    if (res == OK && aeLockAvailableEntry.count > 0) {
+        aeLockAvailable = (aeLockAvailableEntry.data.u8[0] ==
+                ANDROID_CONTROL_AE_LOCK_AVAILABLE_TRUE);
+    }
 
-    mRequestThread = new RequestThread(this, mStatusTracker, device);
+    /** Start up request queue thread */
+    mRequestThread = new RequestThread(this, mStatusTracker, device, aeLockAvailable);
     res = mRequestThread->run(String8::format("C3Dev-%d-ReqQueue", mId).string());
     if (res != OK) {
         SET_ERR_L("Unable to start request queue thread: %s (%d)",
@@ -2472,7 +2480,8 @@
 
 Camera3Device::RequestThread::RequestThread(wp<Camera3Device> parent,
         sp<StatusTracker> statusTracker,
-        camera3_device_t *hal3Device) :
+        camera3_device_t *hal3Device,
+        bool aeLockAvailable) :
         Thread(/*canCallJava*/false),
         mParent(parent),
         mStatusTracker(statusTracker),
@@ -2485,19 +2494,9 @@
         mLatestRequestId(NAME_NOT_FOUND),
         mCurrentAfTriggerId(0),
         mCurrentPreCaptureTriggerId(0),
-        mRepeatingLastFrameNumber(NO_IN_FLIGHT_REPEATING_FRAMES) {
+        mRepeatingLastFrameNumber(NO_IN_FLIGHT_REPEATING_FRAMES),
+        mAeLockAvailable(aeLockAvailable) {
     mStatusId = statusTracker->addComponent();
-
-    mAeLockAvailable = false;
-    sp<Camera3Device> p = parent.promote();
-    if (p != NULL) {
-        camera_metadata_ro_entry aeLockAvailable =
-                p->info().find(ANDROID_CONTROL_AE_LOCK_AVAILABLE);
-        if (aeLockAvailable.count > 0) {
-            mAeLockAvailable = (aeLockAvailable.data.u8[0] ==
-                    ANDROID_CONTROL_AE_LOCK_AVAILABLE_TRUE);
-        }
-    }
 }
 
 void Camera3Device::RequestThread::setNotificationListener(
diff --git a/services/camera/libcameraservice/device3/Camera3Device.h b/services/camera/libcameraservice/device3/Camera3Device.h
index bb4bcc4..31b6132 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.h
+++ b/services/camera/libcameraservice/device3/Camera3Device.h
@@ -389,7 +389,8 @@
 
         RequestThread(wp<Camera3Device> parent,
                 sp<camera3::StatusTracker> statusTracker,
-                camera3_device_t *hal3Device);
+                camera3_device_t *hal3Device,
+                bool aeLockAvailable);
 
         void     setNotificationListener(NotificationListener *listener);