Merge "Fix memory corruption if increaseSamplingN is not called"
diff --git a/camera/Android.mk b/camera/Android.mk
index 18800b4..5774b6f 100644
--- a/camera/Android.mk
+++ b/camera/Android.mk
@@ -52,11 +52,6 @@
 	system/media/camera/include \
 	system/media/private/camera/include
 
-## Enable asserts for 'eng' builds
-ifeq ($(TARGET_BUILD_VARIANT),eng)
-LOCAL_CFLAGS += -UNDEBUG
-endif
-
 LOCAL_MODULE:= libcamera_client
 
 include $(BUILD_SHARED_LIBRARY)
diff --git a/camera/VendorTagDescriptor.cpp b/camera/VendorTagDescriptor.cpp
index ba24fcb..59dce91 100644
--- a/camera/VendorTagDescriptor.cpp
+++ b/camera/VendorTagDescriptor.cpp
@@ -120,7 +120,7 @@
 
         // Set up tag to section index map
         ssize_t index = sections.indexOf(sectionString);
-        assert(index >= 0);
+        LOG_ALWAYS_FATAL_IF(index < 0, "index %zd must be non-negative", index);
         desc->mTagToSectionMap.add(tag, static_cast<uint32_t>(index));
 
         // Set up reverse mapping
@@ -217,7 +217,8 @@
                     __FUNCTION__, sectionCount, (maxSectionIndex + 1));
             return BAD_VALUE;
         }
-        assert(desc->mSections.setCapacity(sectionCount) > 0);
+        LOG_ALWAYS_FATAL_IF(desc->mSections.setCapacity(sectionCount) <= 0,
+                "Vector capacity must be positive");
         for (size_t i = 0; i < sectionCount; ++i) {
             String8 sectionName = parcel->readString8();
             if (sectionName.isEmpty()) {
@@ -228,7 +229,7 @@
         }
     }
 
-    assert(tagCount == allTags.size());
+    LOG_ALWAYS_FATAL_IF(tagCount != allTags.size(), "tagCount must be the same as allTags size");
     // Set up reverse mapping
     for (size_t i = 0; i < static_cast<size_t>(tagCount); ++i) {
         uint32_t tag = allTags[i];
diff --git a/include/ndk/NdkMediaCodec.h b/include/ndk/NdkMediaCodec.h
index 2af88d0b..5233fe3 100644
--- a/include/ndk/NdkMediaCodec.h
+++ b/include/ndk/NdkMediaCodec.h
@@ -29,6 +29,7 @@
 
 #include <android/native_window.h>
 
+#include "NdkMediaCrypto.h"
 #include "NdkMediaFormat.h"
 
 #ifdef __cplusplus
@@ -46,6 +47,7 @@
     uint32_t flags;
 };
 typedef struct AMediaCodecBufferInfo AMediaCodecBufferInfo;
+typedef struct AMediaCodecCryptoInfo AMediaCodecCryptoInfo;
 
 enum {
     AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM = 4,
@@ -55,7 +57,6 @@
     AMEDIACODEC_INFO_TRY_AGAIN_LATER = -1
 };
 
-
 /**
  * Create codec by name. Use this if you know the exact codec you want to use.
  * When configuring, you will need to specify whether to use the codec as an
@@ -82,8 +83,12 @@
 /**
  * Configure the codec. For decoding you would typically get the format from an extractor.
  */
-int AMediaCodec_configure(AMediaCodec*, const AMediaFormat* format,
-        ANativeWindow* surface, uint32_t flags);  // TODO: other args
+int AMediaCodec_configure(
+        AMediaCodec*,
+        const AMediaFormat* format,
+        ANativeWindow* surface,
+        AMediaCrypto *crypto,
+        uint32_t flags);
 
 /**
  * Start the codec. A codec must be configured before it can be started, and must be started
@@ -128,6 +133,12 @@
         size_t idx, off_t offset, size_t size, uint64_t time, uint32_t flags);
 
 /**
+ * Send the specified buffer to the codec for processing.
+ */
+int AMediaCodec_queueSecureInputBuffer(AMediaCodec*,
+        size_t idx, off_t offset, AMediaCodecCryptoInfo*, uint64_t time, uint32_t flags);
+
+/**
  * Get the index of the next available buffer of processed data.
  */
 ssize_t AMediaCodec_dequeueOutputBuffer(AMediaCodec*, AMediaCodecBufferInfo *info, int64_t timeoutUs);
@@ -139,6 +150,46 @@
 int AMediaCodec_releaseOutputBuffer(AMediaCodec*, size_t idx, bool render);
 
 
+typedef void (*OnCodecEvent)(AMediaCodec *codec, void *userdata);
+
+/**
+ * Set a callback to be called when a new buffer is available, or there was a format
+ * or buffer change.
+ * Note that you cannot perform any operations on the mediacodec from within the callback.
+ * If you need to perform mediacodec operations, you must do so on a different thread.
+ */
+int AMediaCodec_setNotificationCallback(AMediaCodec*, OnCodecEvent callback, void *userdata);
+
+
+enum {
+    AMEDIACODECRYPTOINFO_MODE_CLEAR = 0,
+    AMEDIACODECRYPTOINFO_MODE_AES_CTR = 1
+};
+
+/**
+ * create an AMediaCodecCryptoInfo from scratch. Use this if you need to use custom
+ * crypto info, rather than one obtained from AMediaExtractor.
+ */
+AMediaCodecCryptoInfo *AMediaCodecCryptoInfo_new(
+        int numsubsamples,
+        uint8_t key[16],
+        uint8_t iv[16],
+        uint32_t mode,
+        size_t *clearbytes,
+        size_t *encryptedbytes);
+
+/**
+ * delete an AMediaCodecCryptoInfo create previously with AMediaCodecCryptoInfo_new, or
+ * obtained from AMediaExtractor
+ */
+int AMediaCodecCryptoInfo_delete(AMediaCodecCryptoInfo*);
+
+size_t AMediaCodecCryptoInfo_getNumSubSamples(AMediaCodecCryptoInfo*);
+int AMediaCodecCryptoInfo_getKey(AMediaCodecCryptoInfo*, uint8_t *dst);
+int AMediaCodecCryptoInfo_getIV(AMediaCodecCryptoInfo*, uint8_t *dst);
+uint32_t AMediaCodecCryptoInfo_getMode(AMediaCodecCryptoInfo*);
+int AMediaCodecCryptoInfo_getClearBytes(AMediaCodecCryptoInfo*, size_t *dst);
+int AMediaCodecCryptoInfo_getEncryptedBytes(AMediaCodecCryptoInfo*, size_t *dst);
 
 #ifdef __cplusplus
 } // extern "C"
diff --git a/include/ndk/NdkMediaCrypto.h b/include/ndk/NdkMediaCrypto.h
new file mode 100644
index 0000000..0bcba9f
--- /dev/null
+++ b/include/ndk/NdkMediaCrypto.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2014 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.
+ */
+
+
+/*
+ * This file defines an NDK API.
+ * Do not remove methods.
+ * Do not change method signatures.
+ * Do not change the value of constants.
+ * Do not change the size of any of the classes defined in here.
+ * Do not reference types that are not part of the NDK.
+ * Do not #include files that aren't part of the NDK.
+ */
+
+#ifndef _NDK_MEDIA_CRYPTO_H
+#define _NDK_MEDIA_CRYPTO_H
+
+#include <sys/types.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct AMediaCrypto;
+typedef struct AMediaCrypto AMediaCrypto;
+
+typedef uint8_t AMediaUUID[16];
+
+bool AMediaCrypto_isCryptoSchemeSupport(const AMediaUUID uuid);
+
+bool AMediaCrypto_requiresSecureDecoderComponent(const char *mime);
+
+AMediaCrypto* AMediaCrypto_new(const AMediaUUID uuid, const void *initData, size_t initDataSize);
+
+void AMediaCrypto_delete(AMediaCrypto* crypto);
+
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // _NDK_MEDIA_CRYPTO_H
diff --git a/include/ndk/NdkMediaError.h b/include/ndk/NdkMediaError.h
new file mode 100644
index 0000000..b89a10e
--- /dev/null
+++ b/include/ndk/NdkMediaError.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2014 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.
+ */
+
+
+/*
+ * This file defines an NDK API.
+ * Do not remove methods.
+ * Do not change method signatures.
+ * Do not change the value of constants.
+ * Do not change the size of any of the classes defined in here.
+ * Do not reference types that are not part of the NDK.
+ * Do not #include files that aren't part of the NDK.
+ */
+
+#ifndef _NDK_MEDIA_ERROR_H
+#define _NDK_MEDIA_ERROR_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+enum {
+    AMEDIAERROR_BASE = -10000,
+
+    AMEDIAERROR_GENERIC     = AMEDIAERROR_BASE,
+    AMEDIAERROR_MALFORMED   = AMEDIAERROR_BASE - 1,
+    AMEDIAERROR_UNSUPPORTED = AMEDIAERROR_BASE - 2
+};
+
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // _NDK_MEDIA_ERROR_H
diff --git a/include/ndk/NdkMediaExtractor.h b/include/ndk/NdkMediaExtractor.h
index a7c32c4..9e50ec0 100644
--- a/include/ndk/NdkMediaExtractor.h
+++ b/include/ndk/NdkMediaExtractor.h
@@ -30,7 +30,9 @@
 
 #include <sys/types.h>
 
+#include "NdkMediaCodec.h"
 #include "NdkMediaFormat.h"
+#include "NdkMediaCrypto.h"
 
 #ifdef __cplusplus
 extern "C" {
@@ -112,6 +114,33 @@
  */
 bool AMediaExtractor_advance(AMediaExtractor*);
 
+
+/**
+ * mapping of crypto scheme uuid to the scheme specific data for that scheme
+ */
+typedef struct PsshEntry {
+    AMediaUUID uuid;
+    size_t datalen;
+    void *data;
+} PsshEntry;
+
+/**
+ * list of crypto schemes and their data
+ */
+typedef struct PsshInfo {
+    size_t numentries;
+    PsshEntry entries[0];
+} PsshInfo;
+
+/**
+ * Get the PSSH info if present.
+ */
+PsshInfo* AMediaExtractor_getPsshInfo(AMediaExtractor*);
+
+
+AMediaCodecCryptoInfo *AMediaExtractor_getSampleCryptoInfo(AMediaExtractor *);
+
+
 enum {
     AMEDIAEXTRACTOR_SAMPLE_FLAG_SYNC = 1,
     AMEDIAEXTRACTOR_SAMPLE_FLAG_ENCRYPTED = 2,
diff --git a/media/ndk/Android.mk b/media/ndk/Android.mk
index b8dd19e..03f26a0 100644
--- a/media/ndk/Android.mk
+++ b/media/ndk/Android.mk
@@ -22,6 +22,7 @@
 
 LOCAL_SRC_FILES:=                                       \
                   NdkMediaCodec.cpp                     \
+                  NdkMediaCrypto.cpp                    \
                   NdkMediaExtractor.cpp                 \
                   NdkMediaFormat.cpp                    \
                   NdkMediaMuxer.cpp                     \
@@ -34,6 +35,7 @@
     frameworks/av/include/ndk
 
 LOCAL_SHARED_LIBRARIES := \
+    libbinder \
     libmedia \
     libstagefright \
     libstagefright_foundation \
diff --git a/media/ndk/NdkMediaCodec.cpp b/media/ndk/NdkMediaCodec.cpp
index 9592af8..1f62fa2 100644
--- a/media/ndk/NdkMediaCodec.cpp
+++ b/media/ndk/NdkMediaCodec.cpp
@@ -18,13 +18,14 @@
 #define LOG_TAG "NdkMediaCodec"
 
 #include "NdkMediaCodec.h"
+#include "NdkMediaError.h"
+#include "NdkMediaCryptoPriv.h"
 #include "NdkMediaFormatPriv.h"
 
 #include <utils/Log.h>
 #include <utils/StrongPointer.h>
 #include <gui/Surface.h>
 
-#include <media/ICrypto.h>
 #include <media/stagefright/foundation/ALooper.h>
 #include <media/stagefright/foundation/AMessage.h>
 #include <media/stagefright/foundation/ABuffer.h>
@@ -42,30 +43,98 @@
         return AMEDIACODEC_INFO_TRY_AGAIN_LATER;
     }
     ALOGE("sf error code: %d", err);
-    return -1000;
+    return AMEDIAERROR_GENERIC;
 }
 
+enum {
+    kWhatActivityNotify,
+    kWhatRequestActivityNotifications,
+    kWhatStopActivityNotifications,
+};
+
 
 class CodecHandler: public AHandler {
+private:
+    AMediaCodec* mCodec;
 public:
-    CodecHandler(sp<android::MediaCodec>);
+    CodecHandler(AMediaCodec *codec);
     virtual void onMessageReceived(const sp<AMessage> &msg);
 };
 
-CodecHandler::CodecHandler(sp<android::MediaCodec>) {
-
-}
-
-void CodecHandler::onMessageReceived(const sp<AMessage> &msg) {
-    ALOGI("handler got message %d", msg->what());
-}
-
 struct AMediaCodec {
     sp<android::MediaCodec> mCodec;
     sp<ALooper> mLooper;
     sp<CodecHandler> mHandler;
+    sp<AMessage> mActivityNotification;
+    int32_t mGeneration;
+    bool mRequestedActivityNotification;
+    OnCodecEvent mCallback;
+    void *mCallbackUserData;
 };
 
+CodecHandler::CodecHandler(AMediaCodec *codec) {
+    mCodec = codec;
+}
+
+void CodecHandler::onMessageReceived(const sp<AMessage> &msg) {
+
+    switch (msg->what()) {
+        case kWhatRequestActivityNotifications:
+        {
+            if (mCodec->mRequestedActivityNotification) {
+                break;
+            }
+
+            mCodec->mCodec->requestActivityNotification(mCodec->mActivityNotification);
+            mCodec->mRequestedActivityNotification = true;
+            break;
+        }
+
+        case kWhatActivityNotify:
+        {
+            {
+                int32_t generation;
+                msg->findInt32("generation", &generation);
+
+                if (generation != mCodec->mGeneration) {
+                    // stale
+                    break;
+                }
+
+                mCodec->mRequestedActivityNotification = false;
+            }
+
+            if (mCodec->mCallback) {
+                mCodec->mCallback(mCodec, mCodec->mCallbackUserData);
+            }
+            break;
+        }
+
+        case kWhatStopActivityNotifications:
+        {
+            uint32_t replyID;
+            msg->senderAwaitsResponse(&replyID);
+
+            mCodec->mGeneration++;
+            mCodec->mRequestedActivityNotification = false;
+
+            sp<AMessage> response = new AMessage;
+            response->postReply(replyID);
+            break;
+        }
+
+        default:
+            ALOGE("shouldn't be here");
+            break;
+    }
+
+}
+
+
+static void requestActivityNotification(AMediaCodec *codec) {
+    (new AMessage(kWhatRequestActivityNotifications, codec->mHandler->id()))->post();
+}
+
 extern "C" {
 
 static AMediaCodec * createAMediaCodec(const char *name, bool name_is_type, bool encoder) {
@@ -76,14 +145,17 @@
             false,      // runOnCallingThread
             true,       // canCallJava XXX
             PRIORITY_FOREGROUND);
-    ALOGV("looper start: %d", ret);
     if (name_is_type) {
         mData->mCodec = android::MediaCodec::CreateByType(mData->mLooper, name, encoder);
     } else {
         mData->mCodec = android::MediaCodec::CreateByComponentName(mData->mLooper, name);
     }
-    mData->mHandler = new CodecHandler(mData->mCodec);
+    mData->mHandler = new CodecHandler(mData);
     mData->mLooper->registerHandler(mData->mHandler);
+    mData->mGeneration = 1;
+    mData->mRequestedActivityNotification = false;
+    mData->mCallback = NULL;
+
     return mData;
 }
 
@@ -116,7 +188,11 @@
 }
 
 int AMediaCodec_configure(
-        AMediaCodec *mData, const AMediaFormat* format, ANativeWindow* window, uint32_t flags) {
+        AMediaCodec *mData,
+        const AMediaFormat* format,
+        ANativeWindow* window,
+        AMediaCrypto *crypto,
+        uint32_t flags) {
     sp<AMessage> nativeFormat;
     AMediaFormat_getFormat(format, &nativeFormat);
     ALOGV("configure with format: %s", nativeFormat->debugString(0).c_str());
@@ -125,15 +201,30 @@
         surface = (Surface*) window;
     }
 
-    return translate_error(mData->mCodec->configure(nativeFormat, surface, NULL, flags));
+    return translate_error(mData->mCodec->configure(nativeFormat, surface,
+            crypto ? crypto->mCrypto : NULL, flags));
 }
 
 int AMediaCodec_start(AMediaCodec *mData) {
-    return translate_error(mData->mCodec->start());
+    status_t ret =  mData->mCodec->start();
+    if (ret != OK) {
+        return translate_error(ret);
+    }
+    mData->mActivityNotification = new AMessage(kWhatActivityNotify, mData->mHandler->id());
+    mData->mActivityNotification->setInt32("generation", mData->mGeneration);
+    requestActivityNotification(mData);
+    return OK;
 }
 
 int AMediaCodec_stop(AMediaCodec *mData) {
-    return translate_error(mData->mCodec->stop());
+    int ret = translate_error(mData->mCodec->stop());
+
+    sp<AMessage> msg = new AMessage(kWhatStopActivityNotifications, mData->mHandler->id());
+    sp<AMessage> response;
+    msg->postAndAwaitResponse(&response);
+    mData->mActivityNotification.clear();
+
+    return ret;
 }
 
 int AMediaCodec_flush(AMediaCodec *mData) {
@@ -143,6 +234,7 @@
 ssize_t AMediaCodec_dequeueInputBuffer(AMediaCodec *mData, int64_t timeoutUs) {
     size_t idx;
     status_t ret = mData->mCodec->dequeueInputBuffer(&idx, timeoutUs);
+    requestActivityNotification(mData);
     if (ret == OK) {
         return idx;
     }
@@ -200,7 +292,7 @@
     int64_t presentationTimeUs;
     status_t ret = mData->mCodec->dequeueOutputBuffer(&idx, &offset, &size, &presentationTimeUs,
             &flags, timeoutUs);
-
+    requestActivityNotification(mData);
     switch (ret) {
         case OK:
             info->offset = offset;
@@ -234,5 +326,135 @@
     }
 }
 
+int AMediaCodec_setNotificationCallback(AMediaCodec *mData, OnCodecEvent callback, void *userdata) {
+    mData->mCallback = callback;
+    mData->mCallbackUserData = userdata;
+    return OK;
+}
+
+typedef struct AMediaCodecCryptoInfo {
+        int numsubsamples;
+        uint8_t key[16];
+        uint8_t iv[16];
+        uint32_t mode;
+        size_t *clearbytes;
+        size_t *encryptedbytes;
+} AMediaCodecCryptoInfo;
+
+int AMediaCodec_queueSecureInputBuffer(
+        AMediaCodec* codec,
+        size_t idx,
+        off_t offset,
+        AMediaCodecCryptoInfo* crypto,
+        uint64_t time,
+        uint32_t flags) {
+
+    CryptoPlugin::SubSample *subSamples = new CryptoPlugin::SubSample[crypto->numsubsamples];
+    for (int i = 0; i < crypto->numsubsamples; i++) {
+        subSamples[i].mNumBytesOfClearData = crypto->clearbytes[i];
+        subSamples[i].mNumBytesOfEncryptedData = crypto->encryptedbytes[i];
+    }
+
+    AString errormsg;
+    status_t err  = codec->mCodec->queueSecureInputBuffer(idx,
+            offset,
+            subSamples,
+            crypto->numsubsamples,
+            crypto->key,
+            crypto->iv,
+            (CryptoPlugin::Mode) crypto->mode,
+            time,
+            flags,
+            &errormsg);
+    if (err != 0) {
+        ALOGE("queSecureInputBuffer: %s", errormsg.c_str());
+    }
+    delete subSamples;
+    return translate_error(err);
+}
+
+
+
+AMediaCodecCryptoInfo *AMediaCodecCryptoInfo_new(
+        int numsubsamples,
+        uint8_t key[16],
+        uint8_t iv[16],
+        uint32_t mode,
+        size_t *clearbytes,
+        size_t *encryptedbytes) {
+
+    // size needed to store all the crypto data
+    size_t cryptosize = sizeof(AMediaCodecCryptoInfo) + sizeof(size_t) * numsubsamples * 2;
+    AMediaCodecCryptoInfo *ret = (AMediaCodecCryptoInfo*) malloc(cryptosize);
+    if (!ret) {
+        ALOGE("couldn't allocate %d bytes", cryptosize);
+        return NULL;
+    }
+    ret->numsubsamples = numsubsamples;
+    memcpy(ret->key, key, 16);
+    memcpy(ret->iv, iv, 16);
+    ret->mode = mode;
+
+    // clearbytes and encryptedbytes point at the actual data, which follows
+    ret->clearbytes = (size_t*) ((&ret->encryptedbytes) + sizeof(ret->encryptedbytes));
+    ret->encryptedbytes = (size_t*) (ret->clearbytes + (sizeof(size_t) * numsubsamples));
+
+    size_t *dst = ret->clearbytes;
+    memcpy(dst, clearbytes, numsubsamples * sizeof(size_t));
+    dst += numsubsamples * sizeof(size_t);
+    memcpy(dst, encryptedbytes, numsubsamples * sizeof(size_t));
+
+    return ret;
+}
+
+
+int AMediaCodecCryptoInfo_delete(AMediaCodecCryptoInfo* info) {
+    free(info);
+    return OK;
+}
+
+size_t AMediaCodecCryptoInfo_getNumSubSamples(AMediaCodecCryptoInfo* ci) {
+    return ci->numsubsamples;
+}
+
+int AMediaCodecCryptoInfo_getKey(AMediaCodecCryptoInfo* ci, uint8_t *dst) {
+    if (!dst || !ci) {
+        return AMEDIAERROR_UNSUPPORTED;
+    }
+    memcpy(dst, ci->key, 16);
+    return OK;
+}
+
+int AMediaCodecCryptoInfo_getIV(AMediaCodecCryptoInfo* ci, uint8_t *dst) {
+    if (!dst || !ci) {
+        return AMEDIAERROR_UNSUPPORTED;
+    }
+    memcpy(dst, ci->iv, 16);
+    return OK;
+}
+
+uint32_t AMediaCodecCryptoInfo_getMode(AMediaCodecCryptoInfo* ci) {
+    if (!ci) {
+        return AMEDIAERROR_UNSUPPORTED;
+    }
+    return ci->mode;
+}
+
+int AMediaCodecCryptoInfo_getClearBytes(AMediaCodecCryptoInfo* ci, size_t *dst) {
+    if (!dst || !ci) {
+        return AMEDIAERROR_UNSUPPORTED;
+    }
+    memcpy(dst, ci->clearbytes, sizeof(size_t) * ci->numsubsamples);
+    return OK;
+}
+
+int AMediaCodecCryptoInfo_getEncryptedBytes(AMediaCodecCryptoInfo* ci, size_t *dst) {
+    if (!dst || !ci) {
+        return AMEDIAERROR_UNSUPPORTED;
+    }
+    memcpy(dst, ci->encryptedbytes, sizeof(size_t) * ci->numsubsamples);
+    return OK;
+}
+
 } // extern "C"
 
diff --git a/media/ndk/NdkMediaCrypto.cpp b/media/ndk/NdkMediaCrypto.cpp
new file mode 100644
index 0000000..25dfe6a
--- /dev/null
+++ b/media/ndk/NdkMediaCrypto.cpp
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2014 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_NDEBUG 0
+#define LOG_TAG "NdkMediaCrypto"
+
+
+#include "NdkMediaCrypto.h"
+#include "NdkMediaCodec.h"
+#include "NdkMediaFormatPriv.h"
+
+
+#include <utils/Log.h>
+#include <utils/StrongPointer.h>
+#include <binder/IServiceManager.h>
+#include <media/ICrypto.h>
+#include <media/IMediaPlayerService.h>
+#include <android_runtime/AndroidRuntime.h>
+#include <android_util_Binder.h>
+
+#include <jni.h>
+
+using namespace android;
+
+static int translate_error(status_t err) {
+    if (err == OK) {
+        return OK;
+    }
+    ALOGE("sf error code: %d", err);
+    return -1000;
+}
+
+
+static sp<ICrypto> makeCrypto() {
+    sp<IServiceManager> sm = defaultServiceManager();
+
+    sp<IBinder> binder =
+        sm->getService(String16("media.player"));
+
+    sp<IMediaPlayerService> service =
+        interface_cast<IMediaPlayerService>(binder);
+
+    if (service == NULL) {
+        return NULL;
+    }
+
+    sp<ICrypto> crypto = service->makeCrypto();
+
+    if (crypto == NULL || (crypto->initCheck() != OK && crypto->initCheck() != NO_INIT)) {
+        return NULL;
+    }
+
+    return crypto;
+}
+
+struct AMediaCrypto {
+    sp<ICrypto> mCrypto;
+};
+
+
+extern "C" {
+
+
+bool AMediaCrypto_isCryptoSchemeSupport(const AMediaUUID uuid) {
+    sp<ICrypto> crypto = makeCrypto();
+    if (crypto == NULL) {
+        return false;
+    }
+    return crypto->isCryptoSchemeSupported(uuid);
+}
+
+bool AMediaCrypto_requiresSecureDecoderComponent(const char *mime) {
+    sp<ICrypto> crypto = makeCrypto();
+    if (crypto == NULL) {
+        return false;
+    }
+    return crypto->requiresSecureDecoderComponent(mime);
+}
+
+AMediaCrypto* AMediaCrypto_new(const AMediaUUID uuid, const void *data, size_t datasize) {
+
+    sp<ICrypto> tmp = makeCrypto();
+    if (tmp == NULL) {
+        return NULL;
+    }
+
+    if (tmp->createPlugin(uuid, data, datasize) != 0) {
+        return NULL;
+    }
+
+    AMediaCrypto *crypto = new AMediaCrypto();
+    crypto->mCrypto = tmp;
+
+    return crypto;
+}
+
+void AMediaCrypto_delete(AMediaCrypto* crypto) {
+    delete crypto;
+}
+
+
+
+} // extern "C"
+
diff --git a/media/ndk/NdkMediaCryptoPriv.h b/media/ndk/NdkMediaCryptoPriv.h
new file mode 100644
index 0000000..14ea928
--- /dev/null
+++ b/media/ndk/NdkMediaCryptoPriv.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2014 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.
+ */
+
+
+/*
+ * This file defines an NDK API.
+ * Do not remove methods.
+ * Do not change method signatures.
+ * Do not change the value of constants.
+ * Do not change the size of any of the classes defined in here.
+ * Do not reference types that are not part of the NDK.
+ * Do not #include files that aren't part of the NDK.
+ */
+
+#ifndef _NDK_MEDIA_CRYPTO_PRIV_H
+#define _NDK_MEDIA_CRYPTO_PRIV_H
+
+#include <sys/types.h>
+#include <utils/StrongPointer.h>
+#include <media/ICrypto.h>
+
+using namespace android;
+
+struct AMediaCrypto {
+    sp<ICrypto> mCrypto;
+};
+
+#endif // _NDK_MEDIA_CRYPTO_PRIV_H
diff --git a/media/ndk/NdkMediaExtractor.cpp b/media/ndk/NdkMediaExtractor.cpp
index 681633a..0a66988 100644
--- a/media/ndk/NdkMediaExtractor.cpp
+++ b/media/ndk/NdkMediaExtractor.cpp
@@ -18,12 +18,14 @@
 #define LOG_TAG "NdkMediaExtractor"
 
 
+#include "NdkMediaError.h"
 #include "NdkMediaExtractor.h"
 #include "NdkMediaFormatPriv.h"
 
 
 #include <utils/Log.h>
 #include <utils/StrongPointer.h>
+#include <media/hardware/CryptoAPI.h>
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/AMessage.h>
 #include <media/stagefright/MetaData.h>
@@ -41,11 +43,12 @@
         return OK;
     }
     ALOGE("sf error code: %d", err);
-    return -1000;
+    return AMEDIAERROR_GENERIC;
 }
 
 struct AMediaExtractor {
     sp<NuMediaExtractor> mImpl;
+    sp<ABuffer> mPsshBuf;
 
 };
 
@@ -79,14 +82,14 @@
     if (env == NULL) {
         ALOGE("setDataSource(path) must be called from Java thread");
         env->ExceptionClear();
-        return -1;
+        return AMEDIAERROR_UNSUPPORTED;
     }
 
     jclass mediahttpclass = env->FindClass("android/media/MediaHTTPService");
     if (mediahttpclass == NULL) {
         ALOGE("can't find MediaHttpService");
         env->ExceptionClear();
-        return -1;
+        return AMEDIAERROR_UNSUPPORTED;
     }
 
     jmethodID mediaHttpCreateMethod = env->GetStaticMethodID(mediahttpclass,
@@ -94,7 +97,7 @@
     if (mediaHttpCreateMethod == NULL) {
         ALOGE("can't find method");
         env->ExceptionClear();
-        return -1;
+        return AMEDIAERROR_UNSUPPORTED;
     }
 
     jstring jloc = env->NewStringUTF(location);
@@ -110,7 +113,7 @@
 
     mData->mImpl->setDataSource(httpService, location, NULL);
     env->ExceptionClear();
-    return 0;
+    return OK;
 }
 
 int AMediaExtractor_getTrackCount(AMediaExtractor *mData) {
@@ -184,6 +187,141 @@
     return time;
 }
 
+PsshInfo* AMediaExtractor_getPsshInfo(AMediaExtractor *ex) {
+
+    if (ex->mPsshBuf != NULL) {
+        return (PsshInfo*) ex->mPsshBuf->data();
+    }
+
+    sp<AMessage> format;
+    ex->mImpl->getFileFormat(&format);
+    sp<ABuffer> buffer;
+    if(!format->findBuffer("pssh", &buffer)) {
+        return NULL;
+    }
+
+    // the format of the buffer is 1 or more of:
+    //    {
+    //        16 byte uuid
+    //        4 byte data length N
+    //        N bytes of data
+    //    }
+
+    // Determine the number of entries in the source data.
+    // Since we got the data from stagefright, we trust it is valid and properly formatted.
+    const uint8_t* data = buffer->data();
+    size_t len = buffer->size();
+    size_t numentries = 0;
+    while (len > 0) {
+        numentries++;
+
+        // skip uuid
+        data += 16;
+        len -= 16;
+
+        // get data length
+        uint32_t datalen = *((uint32_t*)data);
+        data += 4;
+        len -= 4;
+
+        // skip the data
+        data += datalen;
+        len -= datalen;
+    }
+
+    // there are <numentries> in the buffer, we need
+    // (source buffer size) + 4 + (4 * numentries) bytes for the PsshInfo structure
+    size_t newsize = buffer->size() + 4 + (4 * numentries);
+    ex->mPsshBuf = new ABuffer(newsize);
+    ex->mPsshBuf->setRange(0, newsize);
+
+    // copy data
+    const uint8_t* src = buffer->data();
+    uint8_t* dst = ex->mPsshBuf->data();
+    uint8_t* dstdata = dst + 4 + numentries * sizeof(PsshEntry);
+    *((uint32_t*)dst) = numentries;
+    dst += 4;
+    for (size_t i = 0; i < numentries; i++) {
+        // copy uuid
+        memcpy(dst, src, 16);
+        src += 16;
+        dst += 16;
+
+        // get/copy data length
+        uint32_t datalen = *((uint32_t*)src);
+        memcpy(dst, src, 4);
+        src += 4;
+        dst += 4;
+
+        // the next entry in the destination is a pointer to the actual data, which we store
+        // after the array of PsshEntry
+        memcpy(dst, &dstdata, sizeof(dstdata));
+        dst += 4;
+
+        // copy the actual data
+        memcpy(dstdata, src, datalen);
+        dstdata += datalen;
+        src += datalen;
+    }
+
+    return (PsshInfo*) ex->mPsshBuf->data();
+}
+
+AMediaCodecCryptoInfo *AMediaExtractor_getSampleCryptoInfo(AMediaExtractor *ex) {
+    sp<MetaData> meta;
+    if(ex->mImpl->getSampleMeta(&meta) != 0) {
+        return NULL;
+    }
+
+    uint32_t type;
+    const void *crypteddata;
+    size_t cryptedsize;
+    if (!meta->findData(kKeyEncryptedSizes, &type, &crypteddata, &cryptedsize)) {
+        return NULL;
+    }
+    size_t numSubSamples = cryptedsize / sizeof(size_t);
+
+    const void *cleardata;
+    size_t clearsize;
+    if (meta->findData(kKeyPlainSizes, &type, &cleardata, &clearsize)) {
+        if (clearsize != cryptedsize) {
+            // The two must be of the same length.
+            return NULL;
+        }
+    }
+
+    const void *key;
+    size_t keysize;
+    if (meta->findData(kKeyCryptoIV, &type, &key, &keysize)) {
+        if (keysize != 16) {
+            // IVs must be 16 bytes in length.
+            return NULL;
+        }
+    }
+
+    const void *iv;
+    size_t ivsize;
+    if (meta->findData(kKeyCryptoIV, &type, &iv, &ivsize)) {
+        if (ivsize != 16) {
+            // IVs must be 16 bytes in length.
+            return NULL;
+        }
+    }
+
+    int32_t mode;
+    if (!meta->findInt32(kKeyCryptoMode, &mode)) {
+        mode = CryptoPlugin::kMode_AES_CTR;
+    }
+
+    return AMediaCodecCryptoInfo_new(
+            numSubSamples,
+            (uint8_t*) key,
+            (uint8_t*) iv,
+            mode,
+            (size_t*) cleardata,
+            (size_t*) crypteddata);
+}
+
 
 } // extern "C"
 
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index e256f32..11170c2 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -82,6 +82,7 @@
 
 static const char kDeadlockedString[] = "AudioFlinger may be deadlocked\n";
 static const char kHardwareLockedString[] = "Hardware lock is taken\n";
+static const char kClientLockedString[] = "Client lock is taken\n";
 
 
 nsecs_t AudioFlinger::mStandbyTimeInNsecs = kDefaultStandbyTimeInNsecs;
@@ -382,7 +383,16 @@
             write(fd, result.string(), result.size());
         }
 
+        bool clientLocked = dumpTryLock(mClientLock);
+        if (!clientLocked) {
+            String8 result(kClientLockedString);
+            write(fd, result.string(), result.size());
+        }
         dumpClients(fd, args);
+        if (clientLocked) {
+            mClientLock.unlock();
+        }
+
         dumpInternals(fd, args);
 
         // dump playback threads
@@ -426,8 +436,9 @@
     return NO_ERROR;
 }
 
-sp<AudioFlinger::Client> AudioFlinger::registerPid_l(pid_t pid)
+sp<AudioFlinger::Client> AudioFlinger::registerPid(pid_t pid)
 {
+    Mutex::Autolock _cl(mClientLock);
     // If pid is already in the mClients wp<> map, then use that entry
     // (for which promote() is always != 0), otherwise create a new entry and Client.
     sp<Client> client = mClients.valueFor(pid).promote();
@@ -564,7 +575,7 @@
         }
 
         pid_t pid = IPCThreadState::self()->getCallingPid();
-        client = registerPid_l(pid);
+        client = registerPid(pid);
 
         PlaybackThread *effectThread = NULL;
         if (sessionId != NULL && *sessionId != AUDIO_SESSION_ALLOCATE) {
@@ -623,7 +634,8 @@
 
     if (lStatus != NO_ERROR) {
         // remove local strong reference to Client before deleting the Track so that the
-        // Client destructor is called by the TrackBase destructor with mLock held
+        // Client destructor is called by the TrackBase destructor with mClientLock held
+        Mutex::Autolock _cl(mClientLock);
         client.clear();
         track.clear();
         goto Exit;
@@ -1140,21 +1152,29 @@
 
 void AudioFlinger::registerClient(const sp<IAudioFlingerClient>& client)
 {
-
     Mutex::Autolock _l(mLock);
+    bool clientAdded = false;
+    {
+        Mutex::Autolock _cl(mClientLock);
 
-    pid_t pid = IPCThreadState::self()->getCallingPid();
-    if (mNotificationClients.indexOfKey(pid) < 0) {
-        sp<NotificationClient> notificationClient = new NotificationClient(this,
-                                                                            client,
-                                                                            pid);
-        ALOGV("registerClient() client %p, pid %d", notificationClient.get(), pid);
+        pid_t pid = IPCThreadState::self()->getCallingPid();
+        if (mNotificationClients.indexOfKey(pid) < 0) {
+            sp<NotificationClient> notificationClient = new NotificationClient(this,
+                                                                                client,
+                                                                                pid);
+            ALOGV("registerClient() client %p, pid %d", notificationClient.get(), pid);
 
-        mNotificationClients.add(pid, notificationClient);
+            mNotificationClients.add(pid, notificationClient);
 
-        sp<IBinder> binder = client->asBinder();
-        binder->linkToDeath(notificationClient);
+            sp<IBinder> binder = client->asBinder();
+            binder->linkToDeath(notificationClient);
+            clientAdded = true;
+        }
+    }
 
+    // mClientLock should not be held here because ThreadBase::sendIoConfigEvent() will lock the
+    // ThreadBase mutex and teh locknig 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++) {
@@ -1170,8 +1190,10 @@
 void AudioFlinger::removeNotificationClient(pid_t pid)
 {
     Mutex::Autolock _l(mLock);
-
-    mNotificationClients.removeItem(pid);
+    {
+        Mutex::Autolock _cl(mClientLock);
+        mNotificationClients.removeItem(pid);
+    }
 
     ALOGV("%d died, releasing its sessions", pid);
     size_t num = mAudioSessionRefs.size();
@@ -1194,22 +1216,18 @@
     }
 }
 
-// audioConfigChanged_l() must be called with AudioFlinger::mLock held
-void AudioFlinger::audioConfigChanged_l(
-                    const DefaultKeyedVector< pid_t,sp<NotificationClient> >& notificationClients,
-                    int event,
-                    audio_io_handle_t ioHandle,
-                    const void *param2)
+void AudioFlinger::audioConfigChanged(int event, audio_io_handle_t ioHandle, const void *param2)
 {
-    size_t size = notificationClients.size();
+    Mutex::Autolock _l(mClientLock);
+    size_t size = mNotificationClients.size();
     for (size_t i = 0; i < size; i++) {
-        notificationClients.valueAt(i)->audioFlingerClient()->ioConfigChanged(event,
+        mNotificationClients.valueAt(i)->audioFlingerClient()->ioConfigChanged(event,
                                                                               ioHandle,
                                                                               param2);
     }
 }
 
-// removeClient_l() must be called with AudioFlinger::mLock held
+// removeClient_l() must be called with AudioFlinger::mClientLock held
 void AudioFlinger::removeClient_l(pid_t pid)
 {
     ALOGV("removeClient_l() pid %d, calling pid %d", pid,
@@ -1247,7 +1265,7 @@
     // 1 MB of address space is good for 32 tracks, 8 buffers each, 4 KB/buffer
 }
 
-// Client destructor must be called with AudioFlinger::mLock held
+// Client destructor must be called with AudioFlinger::mClientLock held
 AudioFlinger::Client::~Client()
 {
     mAudioFlinger->removeClient_l(mPid);
@@ -1377,7 +1395,7 @@
         }
 
         pid_t pid = IPCThreadState::self()->getCallingPid();
-        client = registerPid_l(pid);
+        client = registerPid(pid);
 
         if (sessionId != NULL && *sessionId != AUDIO_SESSION_ALLOCATE) {
             lSessionId = *sessionId;
@@ -1400,7 +1418,8 @@
 
     if (lStatus != NO_ERROR) {
         // remove local strong reference to Client before deleting the RecordTrack so that the
-        // Client destructor is called by the TrackBase destructor with mLock held
+        // Client destructor is called by the TrackBase destructor with mClientLock held
+        Mutex::Autolock _cl(mClientLock);
         client.clear();
         recordTrack.clear();
         goto Exit;
@@ -1638,7 +1657,7 @@
         }
 
         // notify client processes of the new output creation
-        thread->audioConfigChanged_l(mNotificationClients, AudioSystem::OUTPUT_OPENED);
+        thread->audioConfigChanged(AudioSystem::OUTPUT_OPENED);
 
         // the first primary output opened designates the primary hw device
         if ((mPrimaryHardwareDev == NULL) && (flags & AUDIO_OUTPUT_FLAG_PRIMARY)) {
@@ -1674,7 +1693,7 @@
     thread->addOutputTrack(thread2);
     mPlaybackThreads.add(id, thread);
     // notify client processes of the new output creation
-    thread->audioConfigChanged_l(mNotificationClients, AudioSystem::OUTPUT_OPENED);
+    thread->audioConfigChanged(AudioSystem::OUTPUT_OPENED);
     return id;
 }
 
@@ -1724,7 +1743,7 @@
                 }
             }
         }
-        audioConfigChanged_l(mNotificationClients, AudioSystem::OUTPUT_CLOSED, output, NULL);
+        audioConfigChanged(AudioSystem::OUTPUT_CLOSED, output, NULL);
     }
     thread->exit();
     // The thread entity (active unit of execution) is no longer running here,
@@ -1904,7 +1923,7 @@
         }
 
         // notify client processes of the new input creation
-        thread->audioConfigChanged_l(mNotificationClients, AudioSystem::INPUT_OPENED);
+        thread->audioConfigChanged(AudioSystem::INPUT_OPENED);
         return id;
     }
 
@@ -1929,7 +1948,7 @@
         }
 
         ALOGV("closeInput() %d", input);
-        audioConfigChanged_l(mNotificationClients, AudioSystem::INPUT_CLOSED, input, NULL);
+        audioConfigChanged(AudioSystem::INPUT_CLOSED, input, NULL);
         mRecordThreads.removeItem(input);
     }
     thread->exit();
@@ -1973,13 +1992,16 @@
         caller = pid;
     }
 
-    // Ignore requests received from processes not known as notification client. The request
-    // is likely proxied by mediaserver (e.g CameraService) and releaseAudioSessionId() can be
-    // called from a different pid leaving a stale session reference.  Also we don't know how
-    // to clear this reference if the client process dies.
-    if (mNotificationClients.indexOfKey(caller) < 0) {
-        ALOGW("acquireAudioSessionId() unknown client %d for session %d", caller, audioSession);
-        return;
+    {
+        Mutex::Autolock _cl(mClientLock);
+        // Ignore requests received from processes not known as notification client. The request
+        // is likely proxied by mediaserver (e.g CameraService) and releaseAudioSessionId() can be
+        // called from a different pid leaving a stale session reference.  Also we don't know how
+        // to clear this reference if the client process dies.
+        if (mNotificationClients.indexOfKey(caller) < 0) {
+            ALOGW("acquireAudioSessionId() unknown client %d for session %d", caller, audioSession);
+            return;
+        }
     }
 
     size_t num = mAudioSessionRefs.size();
@@ -2348,7 +2370,7 @@
             }
         }
 
-        sp<Client> client = registerPid_l(pid);
+        sp<Client> client = registerPid(pid);
 
         // create effect on selected output thread
         handle = thread->createEffect_l(client, effectClient, priority, sessionId,
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index 894bd35..c1d4c08 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -453,11 +453,7 @@
               // no range check, doesn't check per-thread stream volume, AudioFlinger::mLock held
               float streamVolume_l(audio_stream_type_t stream) const
                                 { return mStreamTypes[stream].volume; }
-              void audioConfigChanged_l(const DefaultKeyedVector< pid_t,sp<NotificationClient> >&
-                                           notificationClients,
-                                        int event,
-                                        audio_io_handle_t ioHandle,
-                                        const void *param2);
+              void audioConfigChanged(int event, audio_io_handle_t ioHandle, const void *param2);
 
               // 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
@@ -482,8 +478,6 @@
 
                 void        removeClient_l(pid_t pid);
                 void        removeNotificationClient(pid_t pid);
-                DefaultKeyedVector< pid_t,sp<NotificationClient> > notificationClients() {
-                                        Mutex::Autolock _l(mLock); return mNotificationClients; }
                 bool isNonOffloadableGlobalEffectEnabled_l();
                 void onNonOffloadableGlobalEffectEnable();
 
@@ -553,7 +547,11 @@
     };
 
     mutable     Mutex                               mLock;
-
+                // protects mClients and mNotificationClients.
+                // must be locked after mLock and ThreadBase::mLock if both must be locked
+                // avoids acquiring AudioFlinger::mLock from inside thread loop.
+    mutable     Mutex                               mClientLock;
+                // protected by mClientLock
                 DefaultKeyedVector< pid_t, wp<Client> >     mClients;   // see ~Client()
 
                 mutable     Mutex                   mHardwareLock;
@@ -602,6 +600,7 @@
 
                 DefaultKeyedVector< audio_io_handle_t, sp<RecordThread> >    mRecordThreads;
 
+                // protected by mClientLock
                 DefaultKeyedVector< pid_t, sp<NotificationClient> >    mNotificationClients;
 
                 volatile int32_t                    mNextUniqueId;  // updated by android_atomic_inc
@@ -622,7 +621,7 @@
                                                              // to be created
 
 private:
-    sp<Client>  registerPid_l(pid_t pid);    // always returns non-0
+    sp<Client>  registerPid(pid_t pid);    // always returns non-0
 
     // for use from destructor
     status_t    closeOutput_nonvirtual(audio_io_handle_t output);
diff --git a/services/audioflinger/Effects.cpp b/services/audioflinger/Effects.cpp
index 29b56db..77aca00 100644
--- a/services/audioflinger/Effects.cpp
+++ b/services/audioflinger/Effects.cpp
@@ -1162,8 +1162,8 @@
             mCblk->~effect_param_cblk_t();   // destroy our shared-structure.
         }
         mCblkMemory.clear();    // free the shared memory before releasing the heap it belongs to
-        // Client destructor must run with AudioFlinger mutex locked
-        Mutex::Autolock _l(mClient->audioFlinger()->mLock);
+        // Client destructor must run with AudioFlinger client mutex locked
+        Mutex::Autolock _l(mClient->audioFlinger()->mClientLock);
         mClient.clear();
     }
 }
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index 470b018..8243a8b 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -401,8 +401,7 @@
 }
 
 // post condition: mConfigEvents.isEmpty()
-void AudioFlinger::ThreadBase::processConfigEvents_l(
-                    const DefaultKeyedVector< pid_t,sp<NotificationClient> >& notificationClients)
+void AudioFlinger::ThreadBase::processConfigEvents_l()
 {
     bool configChanged = false;
 
@@ -423,7 +422,7 @@
         } break;
         case CFG_EVENT_IO: {
             IoConfigEventData *data = (IoConfigEventData *)event->mData.get();
-            audioConfigChanged_l(notificationClients, data->mEvent, data->mParam);
+            audioConfigChanged(data->mEvent, data->mParam);
         } break;
         case CFG_EVENT_SET_PARAMETER: {
             SetParameterConfigEventData *data = (SetParameterConfigEventData *)event->mData.get();
@@ -1638,15 +1637,11 @@
     return out_s8;
 }
 
-// audioConfigChanged_l() must be called with AudioFlinger::mLock held
-void AudioFlinger::PlaybackThread::audioConfigChanged_l(
-                    const DefaultKeyedVector< pid_t,sp<NotificationClient> >& notificationClients,
-                    int event,
-                    int param) {
+void AudioFlinger::PlaybackThread::audioConfigChanged(int event, int param) {
     AudioSystem::OutputDescriptor desc;
     void *param2 = NULL;
 
-    ALOGV("PlaybackThread::audioConfigChanged_l, thread %p, event %d, param %d", this, event,
+    ALOGV("PlaybackThread::audioConfigChanged, thread %p, event %d, param %d", this, event,
             param);
 
     switch (event) {
@@ -1667,7 +1662,7 @@
     default:
         break;
     }
-    mAudioFlinger->audioConfigChanged_l(notificationClients, event, mId, param2);
+    mAudioFlinger->audioConfigChanged(event, mId, param2);
 }
 
 void AudioFlinger::PlaybackThread::writeCallback()
@@ -2317,15 +2312,11 @@
 
         Vector< sp<EffectChain> > effectChains;
 
-        DefaultKeyedVector< pid_t,sp<NotificationClient> > notificationClients =
-                mAudioFlinger->notificationClients();
-
         { // scope for mLock
 
             Mutex::Autolock _l(mLock);
 
-            processConfigEvents_l(notificationClients);
-            notificationClients.clear();
+            processConfigEvents_l();
 
             if (logString != NULL) {
                 mNBLogWriter->logTimestamp();
@@ -4695,14 +4686,11 @@
         // activeTracks accumulates a copy of a subset of mActiveTracks
         Vector< sp<RecordTrack> > activeTracks;
 
-        DefaultKeyedVector< pid_t,sp<NotificationClient> > notificationClients =
-                mAudioFlinger->notificationClients();
 
         { // scope for mLock
             Mutex::Autolock _l(mLock);
 
-            processConfigEvents_l(notificationClients);
-            notificationClients.clear();
+            processConfigEvents_l();
 
             // check exitPending here because checkForNewParameters_l() and
             // checkForNewParameters_l() can temporarily release mLock
@@ -5605,10 +5593,7 @@
     return out_s8;
 }
 
-void AudioFlinger::RecordThread::audioConfigChanged_l(
-                    const DefaultKeyedVector< pid_t,sp<NotificationClient> >& notificationClients,
-                    int event,
-                    int param __unused) {
+void AudioFlinger::RecordThread::audioConfigChanged(int event, int param __unused) {
     AudioSystem::OutputDescriptor desc;
     const void *param2 = NULL;
 
@@ -5627,7 +5612,7 @@
     default:
         break;
     }
-    mAudioFlinger->audioConfigChanged_l(notificationClients, event, mId, param2);
+    mAudioFlinger->audioConfigChanged(event, mId, param2);
 }
 
 void AudioFlinger::RecordThread::readInputParameters_l()
diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h
index 9578993..cc2b246 100644
--- a/services/audioflinger/Threads.h
+++ b/services/audioflinger/Threads.h
@@ -200,10 +200,7 @@
                                                     status_t& status) = 0;
     virtual     status_t    setParameters(const String8& keyValuePairs);
     virtual     String8     getParameters(const String8& keys) = 0;
-    virtual     void        audioConfigChanged_l(
-                      const DefaultKeyedVector< pid_t,sp<NotificationClient> >& notificationClients,
-                      int event,
-                      int param = 0) = 0;
+    virtual     void        audioConfigChanged(int event, int param = 0) = 0;
                 // sendConfigEvent_l() must be called with ThreadBase::mLock held
                 // Can temporarily release the lock if waiting for a reply from
                 // processConfigEvents_l().
@@ -212,8 +209,7 @@
                 void        sendIoConfigEvent_l(int event, int param = 0);
                 void        sendPrioConfigEvent_l(pid_t pid, pid_t tid, int32_t prio);
                 status_t    sendSetParameterConfigEvent_l(const String8& keyValuePair);
-                void        processConfigEvents_l(
-                    const DefaultKeyedVector< pid_t,sp<NotificationClient> >& notificationClients);
+                void        processConfigEvents_l();
     virtual     void        cacheParameters_l() = 0;
 
                 // see note at declaration of mStandby, mOutDevice and mInDevice
@@ -502,10 +498,7 @@
                                 { return android_atomic_acquire_load(&mSuspended) > 0; }
 
     virtual     String8     getParameters(const String8& keys);
-    virtual     void        audioConfigChanged_l(
-                    const DefaultKeyedVector< pid_t,sp<NotificationClient> >& notificationClients,
-                    int event,
-                    int param = 0);
+    virtual     void        audioConfigChanged(int event, int param = 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
@@ -652,7 +645,6 @@
 
     friend class AudioFlinger;      // for numerous
 
-    PlaybackThread(const Client&);
     PlaybackThread& operator = (const PlaybackThread&);
 
     status_t    addTrack_l(const sp<Track>& track);
@@ -1037,10 +1029,7 @@
                                                status_t& status);
     virtual void        cacheParameters_l() {}
     virtual String8     getParameters(const String8& keys);
-    virtual void        audioConfigChanged_l(
-                    const DefaultKeyedVector< pid_t,sp<NotificationClient> >& notificationClients,
-                    int event,
-                    int param = 0);
+    virtual void        audioConfigChanged(int event, int param = 0);
             void        readInputParameters_l();
     virtual uint32_t    getInputFramesLost();
 
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index d8f3423..88ead74 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -198,8 +198,8 @@
     }
     mCblkMemory.clear();    // free the shared memory before releasing the heap it belongs to
     if (mClient != 0) {
-        // Client destructor must run with AudioFlinger mutex locked
-        Mutex::Autolock _l(mClient->audioFlinger()->mLock);
+        // Client destructor must run with AudioFlinger client mutex locked
+        Mutex::Autolock _l(mClient->audioFlinger()->mClientLock);
         // If the client's reference count drops to zero, the associated destructor
         // must run with AudioFlinger lock held. Thus the explicit clear() rather than
         // relying on the automatic clear() at end of scope.
diff --git a/services/audiopolicy/AudioPolicyService.cpp b/services/audiopolicy/AudioPolicyService.cpp
index 2811475..4e9a2f0 100644
--- a/services/audiopolicy/AudioPolicyService.cpp
+++ b/services/audiopolicy/AudioPolicyService.cpp
@@ -51,7 +51,7 @@
 static const int kDumpLockRetries = 50;
 static const int kDumpLockSleepUs = 20000;
 
-static const nsecs_t kAudioCommandTimeout = 3000000000LL; // 3 seconds
+static const nsecs_t kAudioCommandTimeoutNs = seconds(3); // 3 seconds
 
 namespace {
     extern struct audio_policy_service_ops aps_ops;
@@ -268,10 +268,6 @@
     if (!mAudioCommands.isEmpty()) {
         release_wake_lock(mName.string());
     }
-    for (size_t k=0; k < mAudioCommands.size(); k++) {
-        delete mAudioCommands[k]->mParam;
-        delete mAudioCommands[k];
-    }
     mAudioCommands.clear();
     delete mpToneGenerator;
 }
@@ -292,20 +288,19 @@
             nsecs_t curTime = systemTime();
             // commands are sorted by increasing time stamp: execute them from index 0 and up
             if (mAudioCommands[0]->mTime <= curTime) {
-                AudioCommand *command = mAudioCommands[0];
+                sp<AudioCommand> command = mAudioCommands[0];
                 mAudioCommands.removeAt(0);
-                mLastCommand = *command;
+                mLastCommand = command;
 
                 switch (command->mCommand) {
                 case START_TONE: {
                     mLock.unlock();
-                    ToneData *data = (ToneData *)command->mParam;
+                    ToneData *data = (ToneData *)command->mParam.get();
                     ALOGV("AudioCommandThread() processing start tone %d on stream %d",
                             data->mType, data->mStream);
                     delete mpToneGenerator;
                     mpToneGenerator = new ToneGenerator(data->mStream, 1.0);
                     mpToneGenerator->startTone(data->mType);
-                    delete data;
                     mLock.lock();
                     }break;
                 case STOP_TONE: {
@@ -319,42 +314,27 @@
                     mLock.lock();
                     }break;
                 case SET_VOLUME: {
-                    VolumeData *data = (VolumeData *)command->mParam;
+                    VolumeData *data = (VolumeData *)command->mParam.get();
                     ALOGV("AudioCommandThread() processing set volume stream %d, \
                             volume %f, output %d", data->mStream, data->mVolume, data->mIO);
                     command->mStatus = AudioSystem::setStreamVolume(data->mStream,
                                                                     data->mVolume,
                                                                     data->mIO);
-                    if (command->mWaitStatus) {
-                        command->mCond.signal();
-                        command->mCond.waitRelative(mLock, kAudioCommandTimeout);
-                    }
-                    delete data;
                     }break;
                 case SET_PARAMETERS: {
-                    ParametersData *data = (ParametersData *)command->mParam;
+                    ParametersData *data = (ParametersData *)command->mParam.get();
                     ALOGV("AudioCommandThread() processing set parameters string %s, io %d",
                             data->mKeyValuePairs.string(), data->mIO);
                     command->mStatus = AudioSystem::setParameters(data->mIO, data->mKeyValuePairs);
-                    if (command->mWaitStatus) {
-                        command->mCond.signal();
-                        command->mCond.waitRelative(mLock, kAudioCommandTimeout);
-                    }
-                    delete data;
                     }break;
                 case SET_VOICE_VOLUME: {
-                    VoiceVolumeData *data = (VoiceVolumeData *)command->mParam;
+                    VoiceVolumeData *data = (VoiceVolumeData *)command->mParam.get();
                     ALOGV("AudioCommandThread() processing set voice volume volume %f",
                             data->mVolume);
                     command->mStatus = AudioSystem::setVoiceVolume(data->mVolume);
-                    if (command->mWaitStatus) {
-                        command->mCond.signal();
-                        command->mCond.waitRelative(mLock, kAudioCommandTimeout);
-                    }
-                    delete data;
                     }break;
                 case STOP_OUTPUT: {
-                    StopOutputData *data = (StopOutputData *)command->mParam;
+                    StopOutputData *data = (StopOutputData *)command->mParam.get();
                     ALOGV("AudioCommandThread() processing stop output %d",
                             data->mIO);
                     sp<AudioPolicyService> svc = mService.promote();
@@ -364,10 +344,9 @@
                     mLock.unlock();
                     svc->doStopOutput(data->mIO, data->mStream, data->mSession);
                     mLock.lock();
-                    delete data;
                     }break;
                 case RELEASE_OUTPUT: {
-                    ReleaseOutputData *data = (ReleaseOutputData *)command->mParam;
+                    ReleaseOutputData *data = (ReleaseOutputData *)command->mParam.get();
                     ALOGV("AudioCommandThread() processing release output %d",
                             data->mIO);
                     sp<AudioPolicyService> svc = mService.promote();
@@ -377,12 +356,17 @@
                     mLock.unlock();
                     svc->doReleaseOutput(data->mIO);
                     mLock.lock();
-                    delete data;
                     }break;
                 default:
                     ALOGW("AudioCommandThread() unknown command %d", command->mCommand);
                 }
-                delete command;
+                {
+                    Mutex::Autolock _l(command->mLock);
+                    if (command->mWaitStatus) {
+                        command->mWaitStatus = false;
+                        command->mCond.signal();
+                    }
+                }
                 waitTime = INT64_MAX;
             } else {
                 waitTime = mAudioCommands[0]->mTime - curTime;
@@ -425,8 +409,12 @@
         result.append(buffer);
     }
     result.append("  Last Command\n");
-    mLastCommand.dump(buffer, SIZE);
-    result.append(buffer);
+    if (mLastCommand != 0) {
+        mLastCommand->dump(buffer, SIZE);
+        result.append(buffer);
+    } else {
+        result.append("     none\n");
+    }
 
     write(fd, result.string(), result.size());
 
@@ -438,27 +426,22 @@
 void AudioPolicyService::AudioCommandThread::startToneCommand(ToneGenerator::tone_type type,
         audio_stream_type_t stream)
 {
-    AudioCommand *command = new AudioCommand();
+    sp<AudioCommand> command = new AudioCommand();
     command->mCommand = START_TONE;
-    ToneData *data = new ToneData();
+    sp<ToneData> data = new ToneData();
     data->mType = type;
     data->mStream = stream;
     command->mParam = data;
-    Mutex::Autolock _l(mLock);
-    insertCommand_l(command);
     ALOGV("AudioCommandThread() adding tone start type %d, stream %d", type, stream);
-    mWaitWorkCV.signal();
+    sendCommand(command);
 }
 
 void AudioPolicyService::AudioCommandThread::stopToneCommand()
 {
-    AudioCommand *command = new AudioCommand();
+    sp<AudioCommand> command = new AudioCommand();
     command->mCommand = STOP_TONE;
-    command->mParam = NULL;
-    Mutex::Autolock _l(mLock);
-    insertCommand_l(command);
     ALOGV("AudioCommandThread() adding tone stop");
-    mWaitWorkCV.signal();
+    sendCommand(command);
 }
 
 status_t AudioPolicyService::AudioCommandThread::volumeCommand(audio_stream_type_t stream,
@@ -466,109 +449,96 @@
                                                                audio_io_handle_t output,
                                                                int delayMs)
 {
-    status_t status = NO_ERROR;
-
-    AudioCommand *command = new AudioCommand();
+    sp<AudioCommand> command = new AudioCommand();
     command->mCommand = SET_VOLUME;
-    VolumeData *data = new VolumeData();
+    sp<VolumeData> data = new VolumeData();
     data->mStream = stream;
     data->mVolume = volume;
     data->mIO = output;
     command->mParam = data;
-    Mutex::Autolock _l(mLock);
-    insertCommand_l(command, delayMs);
+    command->mWaitStatus = true;
     ALOGV("AudioCommandThread() adding set volume stream %d, volume %f, output %d",
             stream, volume, output);
-    mWaitWorkCV.signal();
-    if (command->mWaitStatus) {
-        command->mCond.wait(mLock);
-        status =  command->mStatus;
-        command->mCond.signal();
-    }
-    return status;
+    return sendCommand(command, delayMs);
 }
 
 status_t AudioPolicyService::AudioCommandThread::parametersCommand(audio_io_handle_t ioHandle,
                                                                    const char *keyValuePairs,
                                                                    int delayMs)
 {
-    status_t status = NO_ERROR;
-
-    AudioCommand *command = new AudioCommand();
+    sp<AudioCommand> command = new AudioCommand();
     command->mCommand = SET_PARAMETERS;
-    ParametersData *data = new ParametersData();
+    sp<ParametersData> data = new ParametersData();
     data->mIO = ioHandle;
     data->mKeyValuePairs = String8(keyValuePairs);
     command->mParam = data;
-    Mutex::Autolock _l(mLock);
-    insertCommand_l(command, delayMs);
+    command->mWaitStatus = true;
     ALOGV("AudioCommandThread() adding set parameter string %s, io %d ,delay %d",
             keyValuePairs, ioHandle, delayMs);
-    mWaitWorkCV.signal();
-    if (command->mWaitStatus) {
-        command->mCond.wait(mLock);
-        status =  command->mStatus;
-        command->mCond.signal();
-    }
-    return status;
+    return sendCommand(command, delayMs);
 }
 
 status_t AudioPolicyService::AudioCommandThread::voiceVolumeCommand(float volume, int delayMs)
 {
-    status_t status = NO_ERROR;
-
-    AudioCommand *command = new AudioCommand();
+    sp<AudioCommand> command = new AudioCommand();
     command->mCommand = SET_VOICE_VOLUME;
-    VoiceVolumeData *data = new VoiceVolumeData();
+    sp<VoiceVolumeData> data = new VoiceVolumeData();
     data->mVolume = volume;
     command->mParam = data;
-    Mutex::Autolock _l(mLock);
-    insertCommand_l(command, delayMs);
+    command->mWaitStatus = true;
     ALOGV("AudioCommandThread() adding set voice volume volume %f", volume);
-    mWaitWorkCV.signal();
-    if (command->mWaitStatus) {
-        command->mCond.wait(mLock);
-        status =  command->mStatus;
-        command->mCond.signal();
-    }
-    return status;
+    return sendCommand(command, delayMs);
 }
 
 void AudioPolicyService::AudioCommandThread::stopOutputCommand(audio_io_handle_t output,
                                                                audio_stream_type_t stream,
                                                                int session)
 {
-    AudioCommand *command = new AudioCommand();
+    sp<AudioCommand> command = new AudioCommand();
     command->mCommand = STOP_OUTPUT;
-    StopOutputData *data = new StopOutputData();
+    sp<StopOutputData> data = new StopOutputData();
     data->mIO = output;
     data->mStream = stream;
     data->mSession = session;
     command->mParam = data;
-    Mutex::Autolock _l(mLock);
-    insertCommand_l(command);
     ALOGV("AudioCommandThread() adding stop output %d", output);
-    mWaitWorkCV.signal();
+    sendCommand(command);
 }
 
 void AudioPolicyService::AudioCommandThread::releaseOutputCommand(audio_io_handle_t output)
 {
-    AudioCommand *command = new AudioCommand();
+    sp<AudioCommand> command = new AudioCommand();
     command->mCommand = RELEASE_OUTPUT;
-    ReleaseOutputData *data = new ReleaseOutputData();
+    sp<ReleaseOutputData> data = new ReleaseOutputData();
     data->mIO = output;
     command->mParam = data;
-    Mutex::Autolock _l(mLock);
-    insertCommand_l(command);
     ALOGV("AudioCommandThread() adding release output %d", output);
-    mWaitWorkCV.signal();
+    sendCommand(command);
+}
+
+status_t AudioPolicyService::AudioCommandThread::sendCommand(sp<AudioCommand>& command, int delayMs)
+{
+    {
+        Mutex::Autolock _l(mLock);
+        insertCommand_l(command, delayMs);
+        mWaitWorkCV.signal();
+    }
+    Mutex::Autolock _l(command->mLock);
+    while (command->mWaitStatus) {
+        nsecs_t timeOutNs = kAudioCommandTimeoutNs + milliseconds(delayMs);
+        if (command->mCond.waitRelative(command->mLock, timeOutNs) != NO_ERROR) {
+            command->mStatus = TIMED_OUT;
+            command->mWaitStatus = false;
+        }
+    }
+    return command->mStatus;
 }
 
 // insertCommand_l() must be called with mLock held
-void AudioPolicyService::AudioCommandThread::insertCommand_l(AudioCommand *command, int delayMs)
+void AudioPolicyService::AudioCommandThread::insertCommand_l(sp<AudioCommand>& command, int delayMs)
 {
     ssize_t i;  // not size_t because i will count down to -1
-    Vector <AudioCommand *> removedCommands;
+    Vector < sp<AudioCommand> > removedCommands;
     command->mTime = systemTime() + milliseconds(delayMs);
 
     // acquire wake lock to make sure delayed commands are processed
@@ -578,15 +548,15 @@
 
     // check same pending commands with later time stamps and eliminate them
     for (i = mAudioCommands.size()-1; i >= 0; i--) {
-        AudioCommand *command2 = mAudioCommands[i];
+        sp<AudioCommand> command2 = mAudioCommands[i];
         // commands are sorted by increasing time stamp: no need to scan the rest of mAudioCommands
         if (command2->mTime <= command->mTime) break;
         if (command2->mCommand != command->mCommand) continue;
 
         switch (command->mCommand) {
         case SET_PARAMETERS: {
-            ParametersData *data = (ParametersData *)command->mParam;
-            ParametersData *data2 = (ParametersData *)command2->mParam;
+            ParametersData *data = (ParametersData *)command->mParam.get();
+            ParametersData *data2 = (ParametersData *)command2->mParam.get();
             if (data->mIO != data2->mIO) break;
             ALOGV("Comparing parameter command %s to new command %s",
                     data2->mKeyValuePairs.string(), data->mKeyValuePairs.string());
@@ -621,8 +591,8 @@
         } break;
 
         case SET_VOLUME: {
-            VolumeData *data = (VolumeData *)command->mParam;
-            VolumeData *data2 = (VolumeData *)command2->mParam;
+            VolumeData *data = (VolumeData *)command->mParam.get();
+            VolumeData *data2 = (VolumeData *)command2->mParam.get();
             if (data->mIO != data2->mIO) break;
             if (data->mStream != data2->mStream) break;
             ALOGV("Filtering out volume command on output %d for stream %d",
@@ -644,12 +614,8 @@
     for (size_t j = 0; j < removedCommands.size(); j++) {
         // removed commands always have time stamps greater than current command
         for (size_t k = i + 1; k < mAudioCommands.size(); k++) {
-            if (mAudioCommands[k] == removedCommands[j]) {
+            if (mAudioCommands[k].get() == removedCommands[j].get()) {
                 ALOGV("suppressing command: %d", mAudioCommands[k]->mCommand);
-                // for commands that are not filtered,
-                // command->mParam is deleted in threadLoop
-                delete mAudioCommands[k]->mParam;
-                delete mAudioCommands[k];
                 mAudioCommands.removeAt(k);
                 break;
             }
@@ -657,10 +623,8 @@
     }
     removedCommands.clear();
 
-    // wait for status only if delay is 0
-    if (delayMs == 0) {
-        command->mWaitStatus = true;
-    } else {
+    // Disable wait for status if delay is not 0
+    if (delayMs != 0) {
         command->mWaitStatus = false;
     }
 
@@ -688,7 +652,7 @@
             (int)ns2s(mTime),
             (int)ns2ms(mTime)%1000,
             mWaitStatus,
-            mParam);
+            mParam.get());
 }
 
 /******* helpers for the service_ops callbacks defined below *********/
diff --git a/services/audiopolicy/AudioPolicyService.h b/services/audiopolicy/AudioPolicyService.h
index 28e3a4b..26037e4 100644
--- a/services/audiopolicy/AudioPolicyService.h
+++ b/services/audiopolicy/AudioPolicyService.h
@@ -194,30 +194,31 @@
                                                   audio_stream_type_t stream,
                                                   int session);
                     void        releaseOutputCommand(audio_io_handle_t output);
-
-                    void        insertCommand_l(AudioCommand *command, int delayMs = 0);
+                    status_t    sendCommand(sp<AudioCommand>& command, int delayMs = 0);
+                    void        insertCommand_l(sp<AudioCommand>& command, int delayMs = 0);
 
     private:
         class AudioCommandData;
 
         // descriptor for requested tone playback event
-        class AudioCommand {
+        class AudioCommand: public RefBase {
 
         public:
             AudioCommand()
-            : mCommand(-1) {}
+            : mCommand(-1), mStatus(NO_ERROR), mWaitStatus(false) {}
 
             void dump(char* buffer, size_t size);
 
             int mCommand;   // START_TONE, STOP_TONE ...
             nsecs_t mTime;  // time stamp
+            Mutex mLock;    // mutex associated to mCond
             Condition mCond; // condition for status return
             status_t mStatus; // command status
             bool mWaitStatus; // true if caller is waiting for status
-            AudioCommandData *mParam;     // command specific parameter data
+            sp<AudioCommandData> mParam;     // command specific parameter data
         };
 
-        class AudioCommandData {
+        class AudioCommandData: public RefBase {
         public:
             virtual ~AudioCommandData() {}
         protected:
@@ -262,9 +263,9 @@
 
         Mutex   mLock;
         Condition mWaitWorkCV;
-        Vector <AudioCommand *> mAudioCommands; // list of pending commands
+        Vector < sp<AudioCommand> > mAudioCommands; // list of pending commands
         ToneGenerator *mpToneGenerator;     // the tone generator
-        AudioCommand mLastCommand;          // last processed command (used by dump)
+        sp<AudioCommand> mLastCommand;      // last processed command (used by dump)
         String8 mName;                      // string used by wake lock fo delayed commands
         wp<AudioPolicyService> mService;
     };
diff --git a/services/camera/libcameraservice/api1/client2/Parameters.cpp b/services/camera/libcameraservice/api1/client2/Parameters.cpp
index 5bfb969..65592d3 100644
--- a/services/camera/libcameraservice/api1/client2/Parameters.cpp
+++ b/services/camera/libcameraservice/api1/client2/Parameters.cpp
@@ -1754,6 +1754,9 @@
 
     camera_metadata_entry_t intent =
             request->find(ANDROID_CONTROL_CAPTURE_INTENT);
+
+    if (intent.count == 0) return BAD_VALUE;
+
     if (intent.data.u8[0] == ANDROID_CONTROL_CAPTURE_INTENT_STILL_CAPTURE) {
         res = request->update(ANDROID_CONTROL_AE_TARGET_FPS_RANGE,
                 fastInfo.bestStillCaptureFpsRange, 2);