Merge "Add AMediaCodec callback"
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/media/AudioRecord.h b/include/media/AudioRecord.h
index b3c44a8..6a68c94 100644
--- a/include/media/AudioRecord.h
+++ b/include/media/AudioRecord.h
@@ -490,10 +490,12 @@
     int                     mSessionId;
     transfer_type           mTransfer;
 
-    // Next 4 fields may be changed if IAudioRecord is re-created, but always != 0
+    // Next 5 fields may be changed if IAudioRecord is re-created, but always != 0
+    // provided the initial set() was successful
     sp<IAudioRecord>        mAudioRecord;
     sp<IMemory>             mCblkMemory;
     audio_track_cblk_t*     mCblk;              // re-load after mLock.unlock()
+    sp<IMemory>             mBufferMemory;
     audio_io_handle_t       mInput;             // returned by AudioSystem::getInput()
 
     int                     mPreviousPriority;  // before start()
diff --git a/include/media/AudioTrack.h b/include/media/AudioTrack.h
index 2c48bbf..79db323 100644
--- a/include/media/AudioTrack.h
+++ b/include/media/AudioTrack.h
@@ -154,8 +154,9 @@
      * streamType:         Select the type of audio stream this track is attached to
      *                     (e.g. AUDIO_STREAM_MUSIC).
      * sampleRate:         Data source sampling rate in Hz.
-     * format:             Audio format (e.g AUDIO_FORMAT_PCM_16_BIT for signed
-     *                     16 bits per sample).
+     * format:             Audio format.  For mixed tracks, any PCM format supported by server is OK
+     *                     or AUDIO_FORMAT_PCM_8_BIT which is handled on client side.  For direct
+     *                     and offloaded tracks, the possible format(s) depends on the output sink.
      * channelMask:        Channel mask, such that audio_is_output_channel(channelMask) is true.
      * frameCount:         Minimum size of track PCM buffer in frames. This defines the
      *                     application's contribution to the
diff --git a/include/media/IAudioFlinger.h b/include/media/IAudioFlinger.h
index 9101f06..7db6a48 100644
--- a/include/media/IAudioFlinger.h
+++ b/include/media/IAudioFlinger.h
@@ -88,6 +88,8 @@
                                 track_flags_t *flags,
                                 pid_t tid,  // -1 means unused, otherwise must be valid non-0
                                 int *sessionId,
+                                sp<IMemory>& cblk,
+                                sp<IMemory>& buffers,   // return value 0 means it follows cblk
                                 status_t *status) = 0;
 
     /* query the audio hardware state. This state never changes,
diff --git a/include/media/IAudioRecord.h b/include/media/IAudioRecord.h
index eccc2ca..2003985 100644
--- a/include/media/IAudioRecord.h
+++ b/include/media/IAudioRecord.h
@@ -34,9 +34,6 @@
 public:
     DECLARE_META_INTERFACE(AudioRecord);
 
-    /* get this tracks control block */
-    virtual sp<IMemory> getCblk() const = 0;
-
     /* After it's created the track is not active. Call start() to
      * make it active.
      */
diff --git a/include/media/nbaio/AudioStreamInSource.h b/include/media/nbaio/AudioStreamInSource.h
index eaea63c..5169f1e 100644
--- a/include/media/nbaio/AudioStreamInSource.h
+++ b/include/media/nbaio/AudioStreamInSource.h
@@ -45,7 +45,7 @@
     // FIXME Use an audio HAL API to query the buffer filling status when it's available.
     virtual ssize_t availableToRead() { return mStreamBufferSizeBytes / mFrameSize; }
 
-    virtual ssize_t read(void *buffer, size_t count);
+    virtual ssize_t read(void *buffer, size_t count, int64_t readPTS);
 
     // NBAIO_Sink end
 
diff --git a/include/media/nbaio/Pipe.h b/include/media/nbaio/Pipe.h
index c784129..eba37bc 100644
--- a/include/media/nbaio/Pipe.h
+++ b/include/media/nbaio/Pipe.h
@@ -30,7 +30,11 @@
 
 public:
     // maxFrames will be rounded up to a power of 2, and all slots are available. Must be >= 2.
-    Pipe(size_t maxFrames, const NBAIO_Format& format);
+    // buffer is an optional parameter specifying the virtual address of the pipe buffer,
+    // which must be of size roundup(maxFrames) * Format_frameSize(format) bytes.
+    Pipe(size_t maxFrames, const NBAIO_Format& format, void *buffer = NULL);
+
+    // If a buffer was specified in the constructor, it is not automatically freed by destructor.
     virtual ~Pipe();
 
     // NBAIO_Port interface
@@ -57,6 +61,7 @@
     void * const    mBuffer;
     volatile int32_t mRear;         // written by android_atomic_release_store
     volatile int32_t mReaders;      // number of PipeReader clients currently attached to this Pipe
+    const bool      mFreeBufferInDestructor;
 };
 
 }   // namespace android
diff --git a/include/media/stagefright/MediaCodec.h b/include/media/stagefright/MediaCodec.h
index 276543b..39e57de 100644
--- a/include/media/stagefright/MediaCodec.h
+++ b/include/media/stagefright/MediaCodec.h
@@ -100,6 +100,7 @@
             uint32_t *flags,
             int64_t timeoutUs = 0ll);
 
+    status_t renderOutputBufferAndRelease(size_t index, int64_t timestampNs);
     status_t renderOutputBufferAndRelease(size_t index);
     status_t releaseOutputBuffer(size_t index);
 
diff --git a/media/libeffects/downmix/Android.mk b/media/libeffects/downmix/Android.mk
index 2bb6dbe..e0ca8af 100644
--- a/media/libeffects/downmix/Android.mk
+++ b/media/libeffects/downmix/Android.mk
@@ -15,16 +15,10 @@
 
 LOCAL_MODULE_RELATIVE_PATH := soundfx
 
-ifeq ($(TARGET_OS)-$(TARGET_SIMULATOR),linux-true)
-LOCAL_LDLIBS += -ldl
-endif
-
 LOCAL_C_INCLUDES := \
 	$(call include-path-for, audio-effects) \
 	$(call include-path-for, audio-utils)
 
-LOCAL_PRELINK_MODULE := false
-
 LOCAL_CFLAGS += -fvisibility=hidden
 
 include $(BUILD_SHARED_LIBRARY)
diff --git a/media/libeffects/preprocessing/Android.mk b/media/libeffects/preprocessing/Android.mk
index 9e8cb83..ea3c59d 100644
--- a/media/libeffects/preprocessing/Android.mk
+++ b/media/libeffects/preprocessing/Android.mk
@@ -24,12 +24,7 @@
     libutils \
     liblog
 
-ifeq ($(TARGET_SIMULATOR),true)
-LOCAL_LDLIBS += -ldl
-else
 LOCAL_SHARED_LIBRARIES += libdl
-endif
-
 LOCAL_CFLAGS += -fvisibility=hidden
 
 include $(BUILD_SHARED_LIBRARY)
diff --git a/media/libmedia/AudioRecord.cpp b/media/libmedia/AudioRecord.cpp
index 2c8605c..97ab8f8 100644
--- a/media/libmedia/AudioRecord.cpp
+++ b/media/libmedia/AudioRecord.cpp
@@ -484,6 +484,8 @@
     size_t temp = frameCount;   // temp may be replaced by a revised value of frameCount,
                                 // but we will still need the original value also
     int originalSessionId = mSessionId;
+    sp<IMemory> iMem;           // for cblk
+    sp<IMemory> bufferMem;
     sp<IAudioRecord> record = audioFlinger->openRecord(input,
                                                        mSampleRate, mFormat,
                                                        mChannelMask,
@@ -491,6 +493,8 @@
                                                        &trackFlags,
                                                        tid,
                                                        &mSessionId,
+                                                       iMem,
+                                                       bufferMem,
                                                        &status);
     ALOGE_IF(originalSessionId != AUDIO_SESSION_ALLOCATE && mSessionId != originalSessionId,
             "session ID changed from %d to %d", originalSessionId, mSessionId);
@@ -504,7 +508,6 @@
     // AudioFlinger now owns the reference to the I/O handle,
     // so we are no longer responsible for releasing it.
 
-    sp<IMemory> iMem = record->getCblk();
     if (iMem == 0) {
         ALOGE("Could not get control block");
         return NO_INIT;
@@ -514,6 +517,22 @@
         ALOGE("Could not get control block pointer");
         return NO_INIT;
     }
+    audio_track_cblk_t* cblk = static_cast<audio_track_cblk_t*>(iMemPointer);
+
+    // Starting address of buffers in shared memory.
+    // The buffers are either immediately after the control block,
+    // or in a separate area at discretion of server.
+    void *buffers;
+    if (bufferMem == 0) {
+        buffers = cblk + 1;
+    } else {
+        buffers = bufferMem->pointer();
+        if (buffers == NULL) {
+            ALOGE("Could not get buffer pointer");
+            return NO_INIT;
+        }
+    }
+
     // invariant that mAudioRecord != 0 is true only after set() returns successfully
     if (mAudioRecord != 0) {
         mAudioRecord->asBinder()->unlinkToDeath(mDeathNotifier, this);
@@ -522,7 +541,7 @@
     mAudioRecord = record;
 
     mCblkMemory = iMem;
-    audio_track_cblk_t* cblk = static_cast<audio_track_cblk_t*>(iMemPointer);
+    mBufferMemory = bufferMem;
     mCblk = cblk;
     // note that temp is the (possibly revised) value of frameCount
     if (temp < frameCount || (frameCount == 0 && temp == 0)) {
@@ -552,11 +571,6 @@
     mInput = input;
     mRefreshRemaining = true;
 
-    // Starting address of buffers in shared memory, immediately after the control block.  This
-    // address is for the mapping within client address space.  AudioFlinger::TrackBase::mBuffer
-    // is for the server address space.
-    void *buffers = (char*)cblk + sizeof(audio_track_cblk_t);
-
     mFrameCount = frameCount;
     // If IAudioRecord is re-created, don't let the requested frameCount
     // decrease.  This can confuse clients that cache frameCount().
@@ -631,6 +645,7 @@
         // keep them from going away if another thread re-creates the track during obtainBuffer()
         sp<AudioRecordClientProxy> proxy;
         sp<IMemory> iMem;
+        sp<IMemory> bufferMem;
         {
             // start of lock scope
             AutoMutex lock(mLock);
@@ -654,6 +669,7 @@
             // Keep the extra references
             proxy = mProxy;
             iMem = mCblkMemory;
+            bufferMem = mBufferMemory;
 
             // Non-blocking if track is stopped
             if (!mActive) {
@@ -986,7 +1002,7 @@
     status_t result;
 
     // if the new IAudioRecord is created, openRecord_l() will modify the
-    // following member variables: mAudioRecord, mCblkMemory and mCblk.
+    // following member variables: mAudioRecord, mCblkMemory, mCblk, mBufferMemory.
     // It will also delete the strong references on previous IAudioRecord and IMemory
     size_t position = mProxy->getPosition();
     mNewPosition = position + mUpdatePeriod;
diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp
index dc4f90e..aaaa3f1 100644
--- a/media/libmedia/AudioTrack.cpp
+++ b/media/libmedia/AudioTrack.cpp
@@ -315,12 +315,20 @@
         flags = (audio_output_flags_t)(flags &~AUDIO_OUTPUT_FLAG_DEEP_BUFFER);
     }
 
-    if (audio_is_linear_pcm(format)) {
-        mFrameSize = channelCount * audio_bytes_per_sample(format);
-        mFrameSizeAF = channelCount * sizeof(int16_t);
+    if (flags & AUDIO_OUTPUT_FLAG_DIRECT) {
+        if (audio_is_linear_pcm(format)) {
+            mFrameSize = channelCount * audio_bytes_per_sample(format);
+        } else {
+            mFrameSize = sizeof(uint8_t);
+        }
+        mFrameSizeAF = mFrameSize;
     } else {
-        mFrameSize = sizeof(uint8_t);
-        mFrameSizeAF = sizeof(uint8_t);
+        ALOG_ASSERT(audio_is_linear_pcm(format));
+        mFrameSize = channelCount * audio_bytes_per_sample(format);
+        mFrameSizeAF = channelCount * audio_bytes_per_sample(
+                format == AUDIO_FORMAT_PCM_8_BIT ? AUDIO_FORMAT_PCM_16_BIT : format);
+        // createTrack will return an error if PCM format is not supported by server,
+        // so no need to check for specific PCM formats here
     }
 
     // Make copy of input parameter offloadInfo so that in the future:
@@ -931,7 +939,11 @@
 
         // Ensure that buffer alignment matches channel count
         // 8-bit data in shared memory is not currently supported by AudioFlinger
-        size_t alignment = /* mFormat == AUDIO_FORMAT_PCM_8_BIT ? 1 : */ 2;
+        size_t alignment = audio_bytes_per_sample(
+                mFormat == AUDIO_FORMAT_PCM_8_BIT ? AUDIO_FORMAT_PCM_16_BIT : mFormat);
+        if (alignment & 1) {
+            alignment = 1;
+        }
         if (mChannelCount > 1) {
             // More than 2 channels does not require stronger alignment than stereo
             alignment <<= 1;
@@ -947,7 +959,7 @@
         // there's no frameCount parameter.
         // But when initializing a shared buffer AudioTrack via set(),
         // there _is_ a frameCount parameter.  We silently ignore it.
-        frameCount = mSharedBuffer->size()/mChannelCount/sizeof(int16_t);
+        frameCount = mSharedBuffer->size() / mFrameSizeAF;
 
     } else if (!(mFlags & AUDIO_OUTPUT_FLAG_FAST)) {
 
diff --git a/media/libmedia/AudioTrackShared.cpp b/media/libmedia/AudioTrackShared.cpp
index 58c9fc1..323b675 100644
--- a/media/libmedia/AudioTrackShared.cpp
+++ b/media/libmedia/AudioTrackShared.cpp
@@ -621,7 +621,7 @@
         android_atomic_release_store(stepCount + rear, &cblk->u.mStreaming.mRear);
     }
 
-    mCblk->mServer += stepCount;
+    cblk->mServer += stepCount;
 
     size_t half = mFrameCount / 2;
     if (half == 0) {
@@ -679,10 +679,11 @@
 }
 
 bool  AudioTrackServerProxy::setStreamEndDone() {
+    audio_track_cblk_t* cblk = mCblk;
     bool old =
-            (android_atomic_or(CBLK_STREAM_END_DONE, &mCblk->mFlags) & CBLK_STREAM_END_DONE) != 0;
+            (android_atomic_or(CBLK_STREAM_END_DONE, &cblk->mFlags) & CBLK_STREAM_END_DONE) != 0;
     if (!old) {
-        (void) __futex_syscall3(&mCblk->mFutex, mClientInServer ? FUTEX_WAKE_PRIVATE : FUTEX_WAKE,
+        (void) __futex_syscall3(&cblk->mFutex, mClientInServer ? FUTEX_WAKE_PRIVATE : FUTEX_WAKE,
                 1);
     }
     return old;
@@ -690,10 +691,11 @@
 
 void AudioTrackServerProxy::tallyUnderrunFrames(uint32_t frameCount)
 {
-    mCblk->u.mStreaming.mUnderrunFrames += frameCount;
+    audio_track_cblk_t* cblk = mCblk;
+    cblk->u.mStreaming.mUnderrunFrames += frameCount;
 
     // FIXME also wake futex so that underrun is noticed more quickly
-    (void) android_atomic_or(CBLK_UNDERRUN, &mCblk->mFlags);
+    (void) android_atomic_or(CBLK_UNDERRUN, &cblk->mFlags);
 }
 
 // ---------------------------------------------------------------------------
diff --git a/media/libmedia/IAudioFlinger.cpp b/media/libmedia/IAudioFlinger.cpp
index 1940fe7..0e2463e 100644
--- a/media/libmedia/IAudioFlinger.cpp
+++ b/media/libmedia/IAudioFlinger.cpp
@@ -169,6 +169,8 @@
                                 track_flags_t *flags,
                                 pid_t tid,
                                 int *sessionId,
+                                sp<IMemory>& cblk,
+                                sp<IMemory>& buffers,
                                 status_t *status)
     {
         Parcel data, reply;
@@ -188,6 +190,8 @@
             lSessionId = *sessionId;
         }
         data.writeInt32(lSessionId);
+        cblk.clear();
+        buffers.clear();
         status_t lStatus = remote()->transact(OPEN_RECORD, data, &reply);
         if (lStatus != NO_ERROR) {
             ALOGE("openRecord error: %s", strerror(-lStatus));
@@ -206,17 +210,34 @@
             }
             lStatus = reply.readInt32();
             record = interface_cast<IAudioRecord>(reply.readStrongBinder());
+            cblk = interface_cast<IMemory>(reply.readStrongBinder());
+            if (cblk != 0 && cblk->pointer() == NULL) {
+                cblk.clear();
+            }
+            buffers = interface_cast<IMemory>(reply.readStrongBinder());
+            if (buffers != 0 && buffers->pointer() == NULL) {
+                buffers.clear();
+            }
             if (lStatus == NO_ERROR) {
                 if (record == 0) {
                     ALOGE("openRecord should have returned an IAudioRecord");
                     lStatus = UNKNOWN_ERROR;
+                } else if (cblk == 0) {
+                    ALOGE("openRecord should have returned a cblk");
+                    lStatus = NO_MEMORY;
                 }
+                // buffers is permitted to be 0
             } else {
-                if (record != 0) {
-                    ALOGE("openRecord returned an IAudioRecord but with status %d", lStatus);
-                    record.clear();
+                if (record != 0 || cblk != 0 || buffers != 0) {
+                    ALOGE("openRecord returned an IAudioRecord, cblk, "
+                          "or buffers but with status %d", lStatus);
                 }
             }
+            if (lStatus != NO_ERROR) {
+                record.clear();
+                cblk.clear();
+                buffers.clear();
+            }
         }
         if (status != NULL) {
             *status = lStatus;
@@ -838,15 +859,20 @@
             track_flags_t flags = (track_flags_t) data.readInt32();
             pid_t tid = (pid_t) data.readInt32();
             int sessionId = data.readInt32();
+            sp<IMemory> cblk;
+            sp<IMemory> buffers;
             status_t status;
             sp<IAudioRecord> record = openRecord(input,
-                    sampleRate, format, channelMask, &frameCount, &flags, tid, &sessionId, &status);
+                    sampleRate, format, channelMask, &frameCount, &flags, tid, &sessionId,
+                    cblk, buffers, &status);
             LOG_ALWAYS_FATAL_IF((record != 0) != (status == NO_ERROR));
             reply->writeInt64(frameCount);
             reply->writeInt32(flags);
             reply->writeInt32(sessionId);
             reply->writeInt32(status);
             reply->writeStrongBinder(record->asBinder());
+            reply->writeStrongBinder(cblk->asBinder());
+            reply->writeStrongBinder(buffers->asBinder());
             return NO_ERROR;
         } break;
         case SAMPLE_RATE: {
diff --git a/media/libmedia/IAudioRecord.cpp b/media/libmedia/IAudioRecord.cpp
index 9866d70..8a4a383 100644
--- a/media/libmedia/IAudioRecord.cpp
+++ b/media/libmedia/IAudioRecord.cpp
@@ -29,7 +29,7 @@
 namespace android {
 
 enum {
-    GET_CBLK = IBinder::FIRST_CALL_TRANSACTION,
+    UNUSED_WAS_GET_CBLK = IBinder::FIRST_CALL_TRANSACTION,
     START,
     STOP
 };
@@ -42,21 +42,6 @@
     {
     }
 
-    virtual sp<IMemory> getCblk() const
-    {
-        Parcel data, reply;
-        sp<IMemory> cblk;
-        data.writeInterfaceToken(IAudioRecord::getInterfaceDescriptor());
-        status_t status = remote()->transact(GET_CBLK, data, &reply);
-        if (status == NO_ERROR) {
-            cblk = interface_cast<IMemory>(reply.readStrongBinder());
-            if (cblk != 0 && cblk->pointer() == NULL) {
-                cblk.clear();
-            }
-        }
-        return cblk;
-    }
-
     virtual status_t start(int /*AudioSystem::sync_event_t*/ event, int triggerSession)
     {
         Parcel data, reply;
@@ -89,11 +74,6 @@
     uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
 {
     switch (code) {
-        case GET_CBLK: {
-            CHECK_INTERFACE(IAudioRecord, data, reply);
-            reply->writeStrongBinder(getCblk()->asBinder());
-            return NO_ERROR;
-        } break;
         case START: {
             CHECK_INTERFACE(IAudioRecord, data, reply);
             int /*AudioSystem::sync_event_t*/ event = data.readInt32();
diff --git a/media/libnbaio/AudioStreamInSource.cpp b/media/libnbaio/AudioStreamInSource.cpp
index 80bf61a..af8f365 100644
--- a/media/libnbaio/AudioStreamInSource.cpp
+++ b/media/libnbaio/AudioStreamInSource.cpp
@@ -63,7 +63,7 @@
     return mFramesOverrun;
 }
 
-ssize_t AudioStreamInSource::read(void *buffer, size_t count)
+ssize_t AudioStreamInSource::read(void *buffer, size_t count, int64_t readPTS __unused)
 {
     if (CC_UNLIKELY(!Format_isValid(mFormat))) {
         return NEGOTIATE;
diff --git a/media/libnbaio/Pipe.cpp b/media/libnbaio/Pipe.cpp
index 28a034c..6e0ec8c 100644
--- a/media/libnbaio/Pipe.cpp
+++ b/media/libnbaio/Pipe.cpp
@@ -25,19 +25,22 @@
 
 namespace android {
 
-Pipe::Pipe(size_t maxFrames, const NBAIO_Format& format) :
+Pipe::Pipe(size_t maxFrames, const NBAIO_Format& format, void *buffer) :
         NBAIO_Sink(format),
         mMaxFrames(roundup(maxFrames)),
-        mBuffer(malloc(mMaxFrames * Format_frameSize(format))),
+        mBuffer(buffer == NULL ? malloc(mMaxFrames * Format_frameSize(format)) : buffer),
         mRear(0),
-        mReaders(0)
+        mReaders(0),
+        mFreeBufferInDestructor(buffer == NULL)
 {
 }
 
 Pipe::~Pipe()
 {
     ALOG_ASSERT(android_atomic_acquire_load(&mReaders) == 0);
-    free(mBuffer);
+    if (mFreeBufferInDestructor) {
+        free(mBuffer);
+    }
 }
 
 ssize_t Pipe::write(const void *buffer, size_t count)
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index 537d9de..0a3a3b6 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -3670,7 +3670,28 @@
         ATRACE_NAME("render");
         // The client wants this buffer to be rendered.
 
+        int64_t timestampNs = 0;
+        if (!msg->findInt64("timestampNs", &timestampNs)) {
+            // TODO: it seems like we should use the timestamp
+            // in the (media)buffer as it potentially came from
+            // an input surface, but we did not propagate it prior to
+            // API 20.  Perhaps check for target SDK version.
+#if 0
+            if (info->mData->meta()->findInt64("timeUs", &timestampNs)) {
+                ALOGI("using buffer PTS of %" PRId64, timestampNs);
+                timestampNs *= 1000;
+            }
+#endif
+        }
+
         status_t err;
+        err = native_window_set_buffers_timestamp(mCodec->mNativeWindow.get(), timestampNs);
+        if (err != OK) {
+            ALOGW("failed to set buffer timestamp: %d", err);
+        } else {
+            ALOGI("set PTS to %" PRId64, timestampNs);
+        }
+
         if ((err = mCodec->mNativeWindow->queueBuffer(
                     mCodec->mNativeWindow.get(),
                     info->mGraphicBuffer.get(), -1)) == OK) {
diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp
index 8d3032b..d679be1 100644
--- a/media/libstagefright/AwesomePlayer.cpp
+++ b/media/libstagefright/AwesomePlayer.cpp
@@ -106,12 +106,15 @@
     }
 
     virtual void render(MediaBuffer *buffer) {
+        int64_t timeUs;
+        CHECK(buffer->meta_data()->findInt64(kKeyTime, &timeUs));
+
         render((const uint8_t *)buffer->data() + buffer->range_offset(),
-               buffer->range_length());
+               buffer->range_length(), timeUs * 1000);
     }
 
-    void render(const void *data, size_t size) {
-        mTarget->render(data, size, NULL);
+    void render(const void *data, size_t size, int64_t timestampNs) {
+        mTarget->render(data, size, timestampNs, NULL);
     }
 
 protected:
diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp
index 2a3fa04..e07b6aa 100644
--- a/media/libstagefright/MPEG4Extractor.cpp
+++ b/media/libstagefright/MPEG4Extractor.cpp
@@ -3540,7 +3540,7 @@
 
     off64_t offset;
     size_t size;
-    uint32_t cts;
+    uint32_t cts, stts;
     bool isSyncSample;
     bool newBuffer = false;
     if (mBuffer == NULL) {
@@ -3548,7 +3548,7 @@
 
         status_t err =
             mSampleTable->getMetaDataForSample(
-                    mCurrentSampleIndex, &offset, &size, &cts, &isSyncSample);
+                    mCurrentSampleIndex, &offset, &size, &cts, &isSyncSample, &stts);
 
         if (err != OK) {
             return err;
@@ -3579,6 +3579,8 @@
             mBuffer->meta_data()->clear();
             mBuffer->meta_data()->setInt64(
                     kKeyTime, ((int64_t)cts * 1000000) / mTimescale);
+            mBuffer->meta_data()->setInt64(
+                    kKeyDuration, ((int64_t)stts * 1000000) / mTimescale);
 
             if (targetSampleTimeUs >= 0) {
                 mBuffer->meta_data()->setInt64(
@@ -3701,6 +3703,8 @@
         mBuffer->meta_data()->clear();
         mBuffer->meta_data()->setInt64(
                 kKeyTime, ((int64_t)cts * 1000000) / mTimescale);
+        mBuffer->meta_data()->setInt64(
+                kKeyDuration, ((int64_t)stts * 1000000) / mTimescale);
 
         if (targetSampleTimeUs >= 0) {
             mBuffer->meta_data()->setInt64(
@@ -3850,6 +3854,8 @@
             mBuffer->set_range(0, size);
             mBuffer->meta_data()->setInt64(
                     kKeyTime, ((int64_t)cts * 1000000) / mTimescale);
+            mBuffer->meta_data()->setInt64(
+                    kKeyDuration, ((int64_t)smpl->duration * 1000000) / mTimescale);
 
             if (targetSampleTimeUs >= 0) {
                 mBuffer->meta_data()->setInt64(
@@ -3973,6 +3979,8 @@
 
         mBuffer->meta_data()->setInt64(
                 kKeyTime, ((int64_t)cts * 1000000) / mTimescale);
+        mBuffer->meta_data()->setInt64(
+                kKeyDuration, ((int64_t)smpl->duration * 1000000) / mTimescale);
 
         if (targetSampleTimeUs >= 0) {
             mBuffer->meta_data()->setInt64(
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index 601dccf..5b525f2 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -17,6 +17,7 @@
 //#define LOG_NDEBUG 0
 #define LOG_TAG "MediaCodec"
 #include <utils/Log.h>
+#include <inttypes.h>
 
 #include <media/stagefright/MediaCodec.h>
 
@@ -323,6 +324,16 @@
     return PostAndAwaitResponse(msg, &response);
 }
 
+status_t MediaCodec::renderOutputBufferAndRelease(size_t index, int64_t timestampNs) {
+    sp<AMessage> msg = new AMessage(kWhatReleaseOutputBuffer, id());
+    msg->setSize("index", index);
+    msg->setInt32("render", true);
+    msg->setInt64("timestampNs", timestampNs);
+
+    sp<AMessage> response;
+    return PostAndAwaitResponse(msg, &response);
+}
+
 status_t MediaCodec::releaseOutputBuffer(size_t index) {
     sp<AMessage> msg = new AMessage(kWhatReleaseOutputBuffer, id());
     msg->setSize("index", index);
@@ -1707,9 +1718,25 @@
     if (render && info->mData != NULL && info->mData->size() != 0) {
         info->mNotify->setInt32("render", true);
 
+        int64_t timestampNs = 0;
+        if (msg->findInt64("timestampNs", &timestampNs)) {
+            info->mNotify->setInt64("timestampNs", timestampNs);
+        } else {
+            // TODO: it seems like we should use the timestamp
+            // in the (media)buffer as it potentially came from
+            // an input surface, but we did not propagate it prior to
+            // API 20.  Perhaps check for target SDK version.
+#if 0
+            if (info->mData->meta()->findInt64("timeUs", &timestampNs)) {
+                ALOGI("using buffer PTS of %" PRId64, timestampNs);
+                timestampNs *= 1000;
+            }
+#endif
+        }
+
         if (mSoftRenderer != NULL) {
             mSoftRenderer->render(
-                    info->mData->data(), info->mData->size(), NULL);
+                    info->mData->data(), info->mData->size(), timestampNs, NULL);
         }
     }
 
diff --git a/media/libstagefright/SampleIterator.cpp b/media/libstagefright/SampleIterator.cpp
index eae721b..2748349 100644
--- a/media/libstagefright/SampleIterator.cpp
+++ b/media/libstagefright/SampleIterator.cpp
@@ -133,7 +133,8 @@
     }
 
     status_t err;
-    if ((err = findSampleTime(sampleIndex, &mCurrentSampleTime)) != OK) {
+    if ((err = findSampleTimeAndDuration(
+            sampleIndex, &mCurrentSampleTime, &mCurrentSampleDuration)) != OK) {
         ALOGE("findSampleTime return error");
         return err;
     }
@@ -285,8 +286,8 @@
     return OK;
 }
 
-status_t SampleIterator::findSampleTime(
-        uint32_t sampleIndex, uint32_t *time) {
+status_t SampleIterator::findSampleTimeAndDuration(
+        uint32_t sampleIndex, uint32_t *time, uint32_t *duration) {
     if (sampleIndex >= mTable->mNumSampleSizes) {
         return ERROR_OUT_OF_RANGE;
     }
@@ -309,6 +310,8 @@
 
     *time += mTable->getCompositionTimeOffset(sampleIndex);
 
+    *duration = mTTSDuration;
+
     return OK;
 }
 
diff --git a/media/libstagefright/SampleTable.cpp b/media/libstagefright/SampleTable.cpp
index d9858d7..9a92805 100644
--- a/media/libstagefright/SampleTable.cpp
+++ b/media/libstagefright/SampleTable.cpp
@@ -778,7 +778,8 @@
         off64_t *offset,
         size_t *size,
         uint32_t *compositionTime,
-        bool *isSyncSample) {
+        bool *isSyncSample,
+        uint32_t *sampleDuration) {
     Mutex::Autolock autoLock(mLock);
 
     status_t err;
@@ -820,6 +821,10 @@
         }
     }
 
+    if (sampleDuration) {
+        *sampleDuration = mSampleIterator->getSampleDuration();
+    }
+
     return OK;
 }
 
diff --git a/media/libstagefright/colorconversion/SoftwareRenderer.cpp b/media/libstagefright/colorconversion/SoftwareRenderer.cpp
index 77f21b7..67dfcd2 100644
--- a/media/libstagefright/colorconversion/SoftwareRenderer.cpp
+++ b/media/libstagefright/colorconversion/SoftwareRenderer.cpp
@@ -138,7 +138,7 @@
 }
 
 void SoftwareRenderer::render(
-        const void *data, size_t size, void *platformPrivate) {
+        const void *data, size_t size, int64_t timestampNs, void *platformPrivate) {
     ANativeWindowBuffer *buf;
     int err;
     if ((err = native_window_dequeue_buffer_and_wait(mNativeWindow.get(),
@@ -230,6 +230,11 @@
 
     CHECK_EQ(0, mapper.unlock(buf->handle));
 
+    if ((err = native_window_set_buffers_timestamp(mNativeWindow.get(),
+            timestampNs)) != 0) {
+        ALOGW("Surface::set_buffers_timestamp returned error %d", err);
+    }
+
     if ((err = mNativeWindow->queueBuffer(mNativeWindow.get(), buf,
             -1)) != 0) {
         ALOGW("Surface::queueBuffer returned error %d", err);
diff --git a/media/libstagefright/httplive/PlaylistFetcher.cpp b/media/libstagefright/httplive/PlaylistFetcher.cpp
index c34f3cb..326d85b 100644
--- a/media/libstagefright/httplive/PlaylistFetcher.cpp
+++ b/media/libstagefright/httplive/PlaylistFetcher.cpp
@@ -69,6 +69,7 @@
       mNumRetries(0),
       mStartup(true),
       mPrepared(false),
+      mSkipToFirstIDRAfterConnect(false),
       mNextPTSTimeUs(-1ll),
       mMonitorQueueGeneration(0),
       mRefreshState(INITIAL_MINIMUM_RELOAD_DELAY),
@@ -1097,12 +1098,30 @@
             continue;
         }
 
+        if (stream == LiveSession::STREAMTYPE_VIDEO && mVideoMime.empty()) {
+            const char *mime;
+            if (source->getFormat()->findCString(kKeyMIMEType, &mime)) {
+                mVideoMime.setTo(mime);
+                if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC)) {
+                    mSkipToFirstIDRAfterConnect = true;
+                }
+            }
+        }
+
         int64_t timeUs;
         sp<ABuffer> accessUnit;
         status_t finalResult;
         while (source->hasBufferAvailable(&finalResult)
                 && source->dequeueAccessUnit(&accessUnit) == OK) {
 
+            if (stream == LiveSession::STREAMTYPE_VIDEO && mSkipToFirstIDRAfterConnect) {
+                if (!IsIDR(accessUnit)) {
+                    continue;
+                } else {
+                    mSkipToFirstIDRAfterConnect = false;
+                }
+            }
+
             CHECK(accessUnit->meta()->findInt64("timeUs", &timeUs));
             if (mMinStartTimeUs > 0) {
                 if (timeUs < mMinStartTimeUs) {
@@ -1183,9 +1202,35 @@
     return OK;
 }
 
+/* static */
+bool PlaylistFetcher::bufferStartsWithWebVTTMagicSequence(
+        const sp<ABuffer> &buffer) {
+    size_t pos = 0;
+
+    // skip possible BOM
+    if (buffer->size() >= pos + 3 &&
+            !memcmp("\xef\xbb\xbf", buffer->data() + pos, 3)) {
+        pos += 3;
+    }
+
+    // accept WEBVTT followed by SPACE, TAB or (CR) LF
+    if (buffer->size() < pos + 6 ||
+            memcmp("WEBVTT", buffer->data() + pos, 6)) {
+        return false;
+    }
+    pos += 6;
+
+    if (buffer->size() == pos) {
+        return true;
+    }
+
+    uint8_t sep = buffer->data()[pos];
+    return sep == ' ' || sep == '\t' || sep == '\n' || sep == '\r';
+}
+
 status_t PlaylistFetcher::extractAndQueueAccessUnits(
         const sp<ABuffer> &buffer, const sp<AMessage> &itemMeta) {
-    if (buffer->size() >= 7 && !memcmp("WEBVTT\n", buffer->data(), 7)) {
+    if (bufferStartsWithWebVTTMagicSequence(buffer)) {
         if (mStreamTypeMask != LiveSession::STREAMTYPE_SUBTITLES) {
             ALOGE("This stream only contains subtitles.");
             return ERROR_MALFORMED;
diff --git a/media/libstagefright/httplive/PlaylistFetcher.h b/media/libstagefright/httplive/PlaylistFetcher.h
index 7e21523..e4fdbff 100644
--- a/media/libstagefright/httplive/PlaylistFetcher.h
+++ b/media/libstagefright/httplive/PlaylistFetcher.h
@@ -91,6 +91,7 @@
     static const int32_t kNumSkipFrames;
 
     static bool bufferStartsWithTsSyncByte(const sp<ABuffer>& buffer);
+    static bool bufferStartsWithWebVTTMagicSequence(const sp<ABuffer>& buffer);
 
     // notifications to mSession
     sp<AMessage> mNotify;
@@ -98,6 +99,7 @@
 
     sp<LiveSession> mSession;
     AString mURI;
+    AString mVideoMime;
 
     uint32_t mStreamTypeMask;
     int64_t mStartTimeUs;
@@ -115,6 +117,7 @@
     int32_t mNumRetries;
     bool mStartup;
     bool mPrepared;
+    bool mSkipToFirstIDRAfterConnect;
     int64_t mNextPTSTimeUs;
 
     int32_t mMonitorQueueGeneration;
diff --git a/media/libstagefright/include/SampleIterator.h b/media/libstagefright/include/SampleIterator.h
index b5a043c..60c9e7e 100644
--- a/media/libstagefright/include/SampleIterator.h
+++ b/media/libstagefright/include/SampleIterator.h
@@ -30,6 +30,7 @@
     off64_t getSampleOffset() const { return mCurrentSampleOffset; }
     size_t getSampleSize() const { return mCurrentSampleSize; }
     uint32_t getSampleTime() const { return mCurrentSampleTime; }
+    uint32_t getSampleDuration() const { return mCurrentSampleDuration; }
 
     status_t getSampleSizeDirect(
             uint32_t sampleIndex, size_t *size);
@@ -61,11 +62,12 @@
     off64_t mCurrentSampleOffset;
     size_t mCurrentSampleSize;
     uint32_t mCurrentSampleTime;
+    uint32_t mCurrentSampleDuration;
 
     void reset();
     status_t findChunkRange(uint32_t sampleIndex);
     status_t getChunkOffset(uint32_t chunk, off64_t *offset);
-    status_t findSampleTime(uint32_t sampleIndex, uint32_t *time);
+    status_t findSampleTimeAndDuration(uint32_t sampleIndex, uint32_t *time, uint32_t *duration);
 
     SampleIterator(const SampleIterator &);
     SampleIterator &operator=(const SampleIterator &);
diff --git a/media/libstagefright/include/SampleTable.h b/media/libstagefright/include/SampleTable.h
index 847dff7..fe146f2 100644
--- a/media/libstagefright/include/SampleTable.h
+++ b/media/libstagefright/include/SampleTable.h
@@ -66,7 +66,8 @@
             off64_t *offset,
             size_t *size,
             uint32_t *compositionTime,
-            bool *isSyncSample = NULL);
+            bool *isSyncSample = NULL,
+            uint32_t *sampleDuration = NULL);
 
     enum {
         kFlagBefore,
diff --git a/media/libstagefright/include/SoftwareRenderer.h b/media/libstagefright/include/SoftwareRenderer.h
index 7ab0042..0ba670c 100644
--- a/media/libstagefright/include/SoftwareRenderer.h
+++ b/media/libstagefright/include/SoftwareRenderer.h
@@ -34,7 +34,7 @@
     ~SoftwareRenderer();
 
     void render(
-            const void *data, size_t size, void *platformPrivate);
+            const void *data, size_t size, int64_t timestampNs, void *platformPrivate);
 
 private:
     enum YUVMode {
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index eb00c82..e256f32 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -1195,12 +1195,17 @@
 }
 
 // audioConfigChanged_l() must be called with AudioFlinger::mLock held
-void AudioFlinger::audioConfigChanged_l(int event, audio_io_handle_t ioHandle, const void *param2)
+void AudioFlinger::audioConfigChanged_l(
+                    const DefaultKeyedVector< pid_t,sp<NotificationClient> >& notificationClients,
+                    int event,
+                    audio_io_handle_t ioHandle,
+                    const void *param2)
 {
-    size_t size = mNotificationClients.size();
+    size_t size = notificationClients.size();
     for (size_t i = 0; i < size; i++) {
-        mNotificationClients.valueAt(i)->audioFlingerClient()->ioConfigChanged(event, ioHandle,
-                                                                               param2);
+        notificationClients.valueAt(i)->audioFlingerClient()->ioConfigChanged(event,
+                                                                              ioHandle,
+                                                                              param2);
     }
 }
 
@@ -1313,6 +1318,8 @@
         IAudioFlinger::track_flags_t *flags,
         pid_t tid,
         int *sessionId,
+        sp<IMemory>& cblk,
+        sp<IMemory>& buffers,
         status_t *status)
 {
     sp<RecordThread::RecordTrack> recordTrack;
@@ -1321,6 +1328,9 @@
     status_t lStatus;
     int lSessionId;
 
+    cblk.clear();
+    buffers.clear();
+
     // check calling permissions
     if (!recordingAllowed()) {
         ALOGE("openRecord() permission denied: recording not allowed");
@@ -1396,6 +1406,9 @@
         goto Exit;
     }
 
+    cblk = recordTrack->getCblk();
+    buffers = recordTrack->getBuffers();
+
     // return handle to client
     recordHandle = new RecordHandle(recordTrack);
 
@@ -1625,7 +1638,7 @@
         }
 
         // notify client processes of the new output creation
-        thread->audioConfigChanged_l(AudioSystem::OUTPUT_OPENED);
+        thread->audioConfigChanged_l(mNotificationClients, AudioSystem::OUTPUT_OPENED);
 
         // the first primary output opened designates the primary hw device
         if ((mPrimaryHardwareDev == NULL) && (flags & AUDIO_OUTPUT_FLAG_PRIMARY)) {
@@ -1661,7 +1674,7 @@
     thread->addOutputTrack(thread2);
     mPlaybackThreads.add(id, thread);
     // notify client processes of the new output creation
-    thread->audioConfigChanged_l(AudioSystem::OUTPUT_OPENED);
+    thread->audioConfigChanged_l(mNotificationClients, AudioSystem::OUTPUT_OPENED);
     return id;
 }
 
@@ -1711,7 +1724,7 @@
                 }
             }
         }
-        audioConfigChanged_l(AudioSystem::OUTPUT_CLOSED, output, NULL);
+        audioConfigChanged_l(mNotificationClients, AudioSystem::OUTPUT_CLOSED, output, NULL);
     }
     thread->exit();
     // The thread entity (active unit of execution) is no longer running here,
@@ -1891,7 +1904,7 @@
         }
 
         // notify client processes of the new input creation
-        thread->audioConfigChanged_l(AudioSystem::INPUT_OPENED);
+        thread->audioConfigChanged_l(mNotificationClients, AudioSystem::INPUT_OPENED);
         return id;
     }
 
@@ -1916,7 +1929,7 @@
         }
 
         ALOGV("closeInput() %d", input);
-        audioConfigChanged_l(AudioSystem::INPUT_CLOSED, input, NULL);
+        audioConfigChanged_l(mNotificationClients, AudioSystem::INPUT_CLOSED, input, NULL);
         mRecordThreads.removeItem(input);
     }
     thread->exit();
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index ec32edd..894bd35 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -120,6 +120,8 @@
                                 IAudioFlinger::track_flags_t *flags,
                                 pid_t tid,
                                 int *sessionId,
+                                sp<IMemory>& cblk,
+                                sp<IMemory>& buffers,
                                 status_t *status /*non-NULL*/);
 
     virtual     uint32_t    sampleRate(audio_io_handle_t output) const;
@@ -430,7 +432,6 @@
     public:
         RecordHandle(const sp<RecordThread::RecordTrack>& recordTrack);
         virtual             ~RecordHandle();
-        virtual sp<IMemory> getCblk() const;
         virtual status_t    start(int /*AudioSystem::sync_event_t*/ event, int triggerSession);
         virtual void        stop();
         virtual status_t onTransact(
@@ -452,7 +453,11 @@
               // 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(int event, audio_io_handle_t ioHandle, const void *param2);
+              void audioConfigChanged_l(const DefaultKeyedVector< pid_t,sp<NotificationClient> >&
+                                           notificationClients,
+                                        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
@@ -477,7 +482,8 @@
 
                 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();
 
diff --git a/services/audioflinger/RecordTracks.h b/services/audioflinger/RecordTracks.h
index 6fc06d8..4ca2ad4 100644
--- a/services/audioflinger/RecordTracks.h
+++ b/services/audioflinger/RecordTracks.h
@@ -29,7 +29,8 @@
                                 audio_channel_mask_t channelMask,
                                 size_t frameCount,
                                 int sessionId,
-                                int uid);
+                                int uid,
+                                bool isFast);
     virtual             ~RecordTrack();
 
     virtual status_t    start(AudioSystem::sync_event_t event, int triggerSession);
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index a916b32..470b018 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -97,8 +97,8 @@
 // RecordThread loop sleep time upon application overrun or audio HAL read error
 static const int kRecordThreadSleepUs = 5000;
 
-// maximum time to wait for setParameters to complete
-static const nsecs_t kSetParametersTimeoutNs = seconds(2);
+// maximum time to wait in sendConfigEvent_l() for a status to be received
+static const nsecs_t kConfigEventTimeoutNs = seconds(2);
 
 // minimum sleep time for the mixer thread loop when tracks are active but in underrun
 static const uint32_t kMinThreadSleepTimeUs = 5000;
@@ -143,6 +143,12 @@
 // See the client's minBufCount and mNotificationFramesAct calculations for details.
 static const int kFastTrackMultiplier = 2;
 
+// See Thread::readOnlyHeap().
+// Initially this heap is used to allocate client buffers for "fast" AudioRecord.
+// Eventually it will be the single buffer that FastCapture writes into via HAL read(),
+// and that all "fast" AudioRecord clients read from.  In either case, the size can be small.
+static const size_t kRecordThreadReadOnlyHeapSize = 0x1000;
+
 // ----------------------------------------------------------------------------
 
 #ifdef ADD_BATTERY_DATA
@@ -277,7 +283,6 @@
         // mSampleRate, mFrameCount, mChannelMask, mChannelCount, mFrameSize, mFormat, mBufferSize
         // are set by PlaybackThread::readOutputParameters_l() or
         // RecordThread::readInputParameters_l()
-        mParamStatus(NO_ERROR),
         //FIXME: mStandby should be true here. Is this some kind of hack?
         mStandby(false), mOutDevice(outDevice), mInDevice(inDevice),
         mAudioSource(AUDIO_SOURCE_DEFAULT), mId(id),
@@ -289,12 +294,8 @@
 AudioFlinger::ThreadBase::~ThreadBase()
 {
     // mConfigEvents should be empty, but just in case it isn't, free the memory it owns
-    for (size_t i = 0; i < mConfigEvents.size(); i++) {
-        delete mConfigEvents[i];
-    }
     mConfigEvents.clear();
 
-    mParamCond.broadcast();
     // do not lock the mutex in destructor
     releaseWakeLock_l();
     if (mPowerManager != 0) {
@@ -345,16 +346,30 @@
     ALOGV("ThreadBase::setParameters() %s", keyValuePairs.string());
     Mutex::Autolock _l(mLock);
 
-    mNewParameters.add(keyValuePairs);
+    return sendSetParameterConfigEvent_l(keyValuePairs);
+}
+
+// sendConfigEvent_l() must be called with ThreadBase::mLock held
+// Can temporarily release the lock if waiting for a reply from processConfigEvents_l().
+status_t AudioFlinger::ThreadBase::sendConfigEvent_l(sp<ConfigEvent>& event)
+{
+    status_t status = NO_ERROR;
+
+    mConfigEvents.add(event);
+    ALOGV("sendConfigEvent_l() num events %d event %d", mConfigEvents.size(), event->mType);
     mWaitWorkCV.signal();
-    // wait condition with timeout in case the thread loop has exited
-    // before the request could be processed
-    if (mParamCond.waitRelative(mLock, kSetParametersTimeoutNs) == NO_ERROR) {
-        status = mParamStatus;
-        mWaitWorkCV.signal();
-    } else {
-        status = TIMED_OUT;
+    mLock.unlock();
+    {
+        Mutex::Autolock _l(event->mLock);
+        while (event->mWaitStatus) {
+            if (event->mCond.waitRelative(event->mLock, kConfigEventTimeoutNs) != NO_ERROR) {
+                event->mStatus = TIMED_OUT;
+                event->mWaitStatus = false;
+            }
+        }
+        status = event->mStatus;
     }
+    mLock.lock();
     return status;
 }
 
@@ -367,63 +382,71 @@
 // sendIoConfigEvent_l() must be called with ThreadBase::mLock held
 void AudioFlinger::ThreadBase::sendIoConfigEvent_l(int event, int param)
 {
-    IoConfigEvent *ioEvent = new IoConfigEvent(event, param);
-    mConfigEvents.add(static_cast<ConfigEvent *>(ioEvent));
-    ALOGV("sendIoConfigEvent() num events %d event %d, param %d", mConfigEvents.size(), event,
-            param);
-    mWaitWorkCV.signal();
+    sp<ConfigEvent> configEvent = (ConfigEvent *)new IoConfigEvent(event, param);
+    sendConfigEvent_l(configEvent);
 }
 
 // sendPrioConfigEvent_l() must be called with ThreadBase::mLock held
 void AudioFlinger::ThreadBase::sendPrioConfigEvent_l(pid_t pid, pid_t tid, int32_t prio)
 {
-    PrioConfigEvent *prioEvent = new PrioConfigEvent(pid, tid, prio);
-    mConfigEvents.add(static_cast<ConfigEvent *>(prioEvent));
-    ALOGV("sendPrioConfigEvent_l() num events %d pid %d, tid %d prio %d",
-          mConfigEvents.size(), pid, tid, prio);
-    mWaitWorkCV.signal();
+    sp<ConfigEvent> configEvent = (ConfigEvent *)new PrioConfigEvent(pid, tid, prio);
+    sendConfigEvent_l(configEvent);
 }
 
-void AudioFlinger::ThreadBase::processConfigEvents()
+// sendSetParameterConfigEvent_l() must be called with ThreadBase::mLock held
+status_t AudioFlinger::ThreadBase::sendSetParameterConfigEvent_l(const String8& keyValuePair)
 {
-    Mutex::Autolock _l(mLock);
-    processConfigEvents_l();
+    sp<ConfigEvent> configEvent = (ConfigEvent *)new SetParameterConfigEvent(keyValuePair);
+    return sendConfigEvent_l(configEvent);
 }
 
 // post condition: mConfigEvents.isEmpty()
-void AudioFlinger::ThreadBase::processConfigEvents_l()
+void AudioFlinger::ThreadBase::processConfigEvents_l(
+                    const DefaultKeyedVector< pid_t,sp<NotificationClient> >& notificationClients)
 {
+    bool configChanged = false;
+
     while (!mConfigEvents.isEmpty()) {
-        ALOGV("processConfigEvents() remaining events %d", mConfigEvents.size());
-        ConfigEvent *event = mConfigEvents[0];
+        ALOGV("processConfigEvents_l() remaining events %d", mConfigEvents.size());
+        sp<ConfigEvent> event = mConfigEvents[0];
         mConfigEvents.removeAt(0);
-        // release mLock before locking AudioFlinger mLock: lock order is always
-        // AudioFlinger then ThreadBase to avoid cross deadlock
-        mLock.unlock();
-        switch (event->type()) {
+        switch (event->mType) {
         case CFG_EVENT_PRIO: {
-            PrioConfigEvent *prioEvent = static_cast<PrioConfigEvent *>(event);
-            // FIXME Need to understand why this has be done asynchronously
-            int err = requestPriority(prioEvent->pid(), prioEvent->tid(), prioEvent->prio(),
+            PrioConfigEventData *data = (PrioConfigEventData *)event->mData.get();
+            // FIXME Need to understand why this has to be done asynchronously
+            int err = requestPriority(data->mPid, data->mTid, data->mPrio,
                     true /*asynchronous*/);
             if (err != 0) {
                 ALOGW("Policy SCHED_FIFO priority %d is unavailable for pid %d tid %d; error %d",
-                      prioEvent->prio(), prioEvent->pid(), prioEvent->tid(), err);
+                      data->mPrio, data->mPid, data->mTid, err);
             }
         } break;
         case CFG_EVENT_IO: {
-            IoConfigEvent *ioEvent = static_cast<IoConfigEvent *>(event);
-            {
-                Mutex::Autolock _l(mAudioFlinger->mLock);
-                audioConfigChanged_l(ioEvent->event(), ioEvent->param());
+            IoConfigEventData *data = (IoConfigEventData *)event->mData.get();
+            audioConfigChanged_l(notificationClients, data->mEvent, data->mParam);
+        } break;
+        case CFG_EVENT_SET_PARAMETER: {
+            SetParameterConfigEventData *data = (SetParameterConfigEventData *)event->mData.get();
+            if (checkForNewParameter_l(data->mKeyValuePairs, event->mStatus)) {
+                configChanged = true;
             }
         } break;
         default:
-            ALOGE("processConfigEvents() unknown event type %d", event->type());
+            ALOG_ASSERT(false, "processConfigEvents_l() unknown event type %d", event->mType);
             break;
         }
-        delete event;
-        mLock.lock();
+        {
+            Mutex::Autolock _l(event->mLock);
+            if (event->mWaitStatus) {
+                event->mWaitStatus = false;
+                event->mCond.signal();
+            }
+        }
+        ALOGV_IF(mConfigEvents.isEmpty(), "processConfigEvents_l() DONE thread %p", this);
+    }
+
+    if (configChanged) {
+        cacheParameters_l();
     }
 }
 
@@ -496,18 +519,6 @@
             channelMaskToString(mChannelMask, mType != RECORD).string());
     fdprintf(fd, "  Format: 0x%x (%s)\n", mFormat, formatToString(mFormat));
     fdprintf(fd, "  Frame size: %zu\n", mFrameSize);
-    fdprintf(fd, "  Pending setParameters commands:");
-    size_t numParams = mNewParameters.size();
-    if (numParams) {
-        fdprintf(fd, "\n   Index Command");
-        for (size_t i = 0; i < numParams; ++i) {
-            fdprintf(fd, "\n   %02zu    ", i);
-            fdprintf(fd, mNewParameters[i]);
-        }
-        fdprintf(fd, "\n");
-    } else {
-        fdprintf(fd, " none\n");
-    }
     fdprintf(fd, "  Pending config events:");
     size_t numConfig = mConfigEvents.size();
     if (numConfig) {
@@ -1628,7 +1639,10 @@
 }
 
 // audioConfigChanged_l() must be called with AudioFlinger::mLock held
-void AudioFlinger::PlaybackThread::audioConfigChanged_l(int event, int param) {
+void AudioFlinger::PlaybackThread::audioConfigChanged_l(
+                    const DefaultKeyedVector< pid_t,sp<NotificationClient> >& notificationClients,
+                    int event,
+                    int param) {
     AudioSystem::OutputDescriptor desc;
     void *param2 = NULL;
 
@@ -1643,7 +1657,7 @@
         desc.format = mFormat;
         desc.frameCount = mNormalFrameCount; // FIXME see
                                              // AudioFlinger::frameCount(audio_io_handle_t)
-        desc.latency = latency();
+        desc.latency = latency_l();
         param2 = &desc;
         break;
 
@@ -1653,7 +1667,7 @@
     default:
         break;
     }
-    mAudioFlinger->audioConfigChanged_l(event, mId, param2);
+    mAudioFlinger->audioConfigChanged_l(notificationClients, event, mId, param2);
 }
 
 void AudioFlinger::PlaybackThread::writeCallback()
@@ -2303,12 +2317,16 @@
 
         Vector< sp<EffectChain> > effectChains;
 
-        processConfigEvents();
+        DefaultKeyedVector< pid_t,sp<NotificationClient> > notificationClients =
+                mAudioFlinger->notificationClients();
 
         { // scope for mLock
 
             Mutex::Autolock _l(mLock);
 
+            processConfigEvents_l(notificationClients);
+            notificationClients.clear();
+
             if (logString != NULL) {
                 mNBLogWriter->logTimestamp();
                 mNBLogWriter->log(logString);
@@ -2321,10 +2339,6 @@
                 mLatchQValid = true;
             }
 
-            if (checkForNewParameters_l()) {
-                cacheParameters_l();
-            }
-
             saveOutputTracks();
             if (mSignalPending) {
                 // A signal was raised while we were unlocked
@@ -2746,7 +2760,7 @@
         if (state->mCommand == FastMixerState::COLD_IDLE) {
             int32_t old = android_atomic_inc(&mFastMixerFutex);
             if (old == -1) {
-                __futex_syscall3(&mFastMixerFutex, FUTEX_WAKE_PRIVATE, 1);
+                (void) __futex_syscall3(&mFastMixerFutex, FUTEX_WAKE_PRIVATE, 1);
             }
         }
         state->mCommand = FastMixerState::EXIT;
@@ -2803,7 +2817,7 @@
             if (state->mCommand == FastMixerState::COLD_IDLE) {
                 int32_t old = android_atomic_inc(&mFastMixerFutex);
                 if (old == -1) {
-                    __futex_syscall3(&mFastMixerFutex, FUTEX_WAKE_PRIVATE, 1);
+                    (void) __futex_syscall3(&mFastMixerFutex, FUTEX_WAKE_PRIVATE, 1);
                 }
 #ifdef AUDIO_WATCHDOG
                 if (mAudioWatchdog != 0) {
@@ -3529,128 +3543,117 @@
     mAudioMixer->deleteTrackName(name);
 }
 
-// checkForNewParameters_l() must be called with ThreadBase::mLock held
-bool AudioFlinger::MixerThread::checkForNewParameters_l()
+// checkForNewParameter_l() must be called with ThreadBase::mLock held
+bool AudioFlinger::MixerThread::checkForNewParameter_l(const String8& keyValuePair,
+                                                       status_t& status)
 {
-    // if !&IDLE, holds the FastMixer state to restore after new parameters processed
-    FastMixerState::Command previousCommand = FastMixerState::HOT_IDLE;
     bool reconfig = false;
 
-    while (!mNewParameters.isEmpty()) {
+    status = NO_ERROR;
 
-        if (mFastMixer != NULL) {
-            FastMixerStateQueue *sq = mFastMixer->sq();
-            FastMixerState *state = sq->begin();
-            if (!(state->mCommand & FastMixerState::IDLE)) {
-                previousCommand = state->mCommand;
-                state->mCommand = FastMixerState::HOT_IDLE;
-                sq->end();
-                sq->push(FastMixerStateQueue::BLOCK_UNTIL_ACKED);
-            } else {
-                sq->end(false /*didModify*/);
-            }
+    // if !&IDLE, holds the FastMixer state to restore after new parameters processed
+    FastMixerState::Command previousCommand = FastMixerState::HOT_IDLE;
+    if (mFastMixer != NULL) {
+        FastMixerStateQueue *sq = mFastMixer->sq();
+        FastMixerState *state = sq->begin();
+        if (!(state->mCommand & FastMixerState::IDLE)) {
+            previousCommand = state->mCommand;
+            state->mCommand = FastMixerState::HOT_IDLE;
+            sq->end();
+            sq->push(FastMixerStateQueue::BLOCK_UNTIL_ACKED);
+        } else {
+            sq->end(false /*didModify*/);
         }
+    }
 
-        status_t status = NO_ERROR;
-        String8 keyValuePair = mNewParameters[0];
-        AudioParameter param = AudioParameter(keyValuePair);
-        int value;
-
-        if (param.getInt(String8(AudioParameter::keySamplingRate), value) == NO_ERROR) {
+    AudioParameter param = AudioParameter(keyValuePair);
+    int value;
+    if (param.getInt(String8(AudioParameter::keySamplingRate), value) == NO_ERROR) {
+        reconfig = true;
+    }
+    if (param.getInt(String8(AudioParameter::keyFormat), value) == NO_ERROR) {
+        if ((audio_format_t) value != AUDIO_FORMAT_PCM_16_BIT) {
+            status = BAD_VALUE;
+        } else {
+            // no need to save value, since it's constant
             reconfig = true;
         }
-        if (param.getInt(String8(AudioParameter::keyFormat), value) == NO_ERROR) {
-            if ((audio_format_t) value != AUDIO_FORMAT_PCM_16_BIT) {
-                status = BAD_VALUE;
-            } else {
-                // no need to save value, since it's constant
-                reconfig = true;
-            }
+    }
+    if (param.getInt(String8(AudioParameter::keyChannels), value) == NO_ERROR) {
+        if ((audio_channel_mask_t) value != AUDIO_CHANNEL_OUT_STEREO) {
+            status = BAD_VALUE;
+        } else {
+            // no need to save value, since it's constant
+            reconfig = true;
         }
-        if (param.getInt(String8(AudioParameter::keyChannels), value) == NO_ERROR) {
-            if ((audio_channel_mask_t) value != AUDIO_CHANNEL_OUT_STEREO) {
-                status = BAD_VALUE;
-            } else {
-                // no need to save value, since it's constant
-                reconfig = true;
-            }
+    }
+    if (param.getInt(String8(AudioParameter::keyFrameCount), value) == NO_ERROR) {
+        // do not accept frame count changes if tracks are open as the track buffer
+        // size depends on frame count and correct behavior would not be guaranteed
+        // if frame count is changed after track creation
+        if (!mTracks.isEmpty()) {
+            status = INVALID_OPERATION;
+        } else {
+            reconfig = true;
         }
-        if (param.getInt(String8(AudioParameter::keyFrameCount), value) == NO_ERROR) {
-            // do not accept frame count changes if tracks are open as the track buffer
-            // size depends on frame count and correct behavior would not be guaranteed
-            // if frame count is changed after track creation
-            if (!mTracks.isEmpty()) {
-                status = INVALID_OPERATION;
-            } else {
-                reconfig = true;
-            }
-        }
-        if (param.getInt(String8(AudioParameter::keyRouting), value) == NO_ERROR) {
+    }
+    if (param.getInt(String8(AudioParameter::keyRouting), value) == NO_ERROR) {
 #ifdef ADD_BATTERY_DATA
-            // when changing the audio output device, call addBatteryData to notify
-            // the change
-            if (mOutDevice != value) {
-                uint32_t params = 0;
-                // check whether speaker is on
-                if (value & AUDIO_DEVICE_OUT_SPEAKER) {
-                    params |= IMediaPlayerService::kBatteryDataSpeakerOn;
-                }
-
-                audio_devices_t deviceWithoutSpeaker
-                    = AUDIO_DEVICE_OUT_ALL & ~AUDIO_DEVICE_OUT_SPEAKER;
-                // check if any other device (except speaker) is on
-                if (value & deviceWithoutSpeaker ) {
-                    params |= IMediaPlayerService::kBatteryDataOtherAudioDeviceOn;
-                }
-
-                if (params != 0) {
-                    addBatteryData(params);
-                }
+        // when changing the audio output device, call addBatteryData to notify
+        // the change
+        if (mOutDevice != value) {
+            uint32_t params = 0;
+            // check whether speaker is on
+            if (value & AUDIO_DEVICE_OUT_SPEAKER) {
+                params |= IMediaPlayerService::kBatteryDataSpeakerOn;
             }
+
+            audio_devices_t deviceWithoutSpeaker
+                = AUDIO_DEVICE_OUT_ALL & ~AUDIO_DEVICE_OUT_SPEAKER;
+            // check if any other device (except speaker) is on
+            if (value & deviceWithoutSpeaker ) {
+                params |= IMediaPlayerService::kBatteryDataOtherAudioDeviceOn;
+            }
+
+            if (params != 0) {
+                addBatteryData(params);
+            }
+        }
 #endif
 
-            // forward device change to effects that have requested to be
-            // aware of attached audio device.
-            if (value != AUDIO_DEVICE_NONE) {
-                mOutDevice = value;
-                for (size_t i = 0; i < mEffectChains.size(); i++) {
-                    mEffectChains[i]->setDevice_l(mOutDevice);
-                }
+        // forward device change to effects that have requested to be
+        // aware of attached audio device.
+        if (value != AUDIO_DEVICE_NONE) {
+            mOutDevice = value;
+            for (size_t i = 0; i < mEffectChains.size(); i++) {
+                mEffectChains[i]->setDevice_l(mOutDevice);
             }
         }
+    }
 
-        if (status == NO_ERROR) {
+    if (status == NO_ERROR) {
+        status = mOutput->stream->common.set_parameters(&mOutput->stream->common,
+                                                keyValuePair.string());
+        if (!mStandby && status == INVALID_OPERATION) {
+            mOutput->stream->common.standby(&mOutput->stream->common);
+            mStandby = true;
+            mBytesWritten = 0;
             status = mOutput->stream->common.set_parameters(&mOutput->stream->common,
-                                                    keyValuePair.string());
-            if (!mStandby && status == INVALID_OPERATION) {
-                mOutput->stream->common.standby(&mOutput->stream->common);
-                mStandby = true;
-                mBytesWritten = 0;
-                status = mOutput->stream->common.set_parameters(&mOutput->stream->common,
-                                                       keyValuePair.string());
-            }
-            if (status == NO_ERROR && reconfig) {
-                readOutputParameters_l();
-                delete mAudioMixer;
-                mAudioMixer = new AudioMixer(mNormalFrameCount, mSampleRate);
-                for (size_t i = 0; i < mTracks.size() ; i++) {
-                    int name = getTrackName_l(mTracks[i]->mChannelMask, mTracks[i]->mSessionId);
-                    if (name < 0) {
-                        break;
-                    }
-                    mTracks[i]->mName = name;
-                }
-                sendIoConfigEvent_l(AudioSystem::OUTPUT_CONFIG_CHANGED);
-            }
+                                                   keyValuePair.string());
         }
-
-        mNewParameters.removeAt(0);
-
-        mParamStatus = status;
-        mParamCond.signal();
-        // wait for condition with time out in case the thread calling ThreadBase::setParameters()
-        // already timed out waiting for the status and will never signal the condition.
-        mWaitWorkCV.waitRelative(mLock, kSetParametersTimeoutNs);
+        if (status == NO_ERROR && reconfig) {
+            readOutputParameters_l();
+            delete mAudioMixer;
+            mAudioMixer = new AudioMixer(mNormalFrameCount, mSampleRate);
+            for (size_t i = 0; i < mTracks.size() ; i++) {
+                int name = getTrackName_l(mTracks[i]->mChannelMask, mTracks[i]->mSessionId);
+                if (name < 0) {
+                    break;
+                }
+                mTracks[i]->mName = name;
+            }
+            sendIoConfigEvent_l(AudioSystem::OUTPUT_CONFIG_CHANGED);
+        }
     }
 
     if (!(previousCommand & FastMixerState::IDLE)) {
@@ -3940,61 +3943,52 @@
 {
 }
 
-// checkForNewParameters_l() must be called with ThreadBase::mLock held
-bool AudioFlinger::DirectOutputThread::checkForNewParameters_l()
+// checkForNewParameter_l() must be called with ThreadBase::mLock held
+bool AudioFlinger::DirectOutputThread::checkForNewParameter_l(const String8& keyValuePair,
+                                                              status_t& status)
 {
     bool reconfig = false;
 
-    while (!mNewParameters.isEmpty()) {
-        status_t status = NO_ERROR;
-        String8 keyValuePair = mNewParameters[0];
-        AudioParameter param = AudioParameter(keyValuePair);
-        int value;
+    status = NO_ERROR;
 
-        if (param.getInt(String8(AudioParameter::keyRouting), value) == NO_ERROR) {
-            // forward device change to effects that have requested to be
-            // aware of attached audio device.
-            if (value != AUDIO_DEVICE_NONE) {
-                mOutDevice = value;
-                for (size_t i = 0; i < mEffectChains.size(); i++) {
-                    mEffectChains[i]->setDevice_l(mOutDevice);
-                }
+    AudioParameter param = AudioParameter(keyValuePair);
+    int value;
+    if (param.getInt(String8(AudioParameter::keyRouting), value) == NO_ERROR) {
+        // forward device change to effects that have requested to be
+        // aware of attached audio device.
+        if (value != AUDIO_DEVICE_NONE) {
+            mOutDevice = value;
+            for (size_t i = 0; i < mEffectChains.size(); i++) {
+                mEffectChains[i]->setDevice_l(mOutDevice);
             }
         }
-        if (param.getInt(String8(AudioParameter::keyFrameCount), value) == NO_ERROR) {
-            // do not accept frame count changes if tracks are open as the track buffer
-            // size depends on frame count and correct behavior would not be garantied
-            // if frame count is changed after track creation
-            if (!mTracks.isEmpty()) {
-                status = INVALID_OPERATION;
-            } else {
-                reconfig = true;
-            }
-        }
-        if (status == NO_ERROR) {
-            status = mOutput->stream->common.set_parameters(&mOutput->stream->common,
-                                                    keyValuePair.string());
-            if (!mStandby && status == INVALID_OPERATION) {
-                mOutput->stream->common.standby(&mOutput->stream->common);
-                mStandby = true;
-                mBytesWritten = 0;
-                status = mOutput->stream->common.set_parameters(&mOutput->stream->common,
-                                                       keyValuePair.string());
-            }
-            if (status == NO_ERROR && reconfig) {
-                readOutputParameters_l();
-                sendIoConfigEvent_l(AudioSystem::OUTPUT_CONFIG_CHANGED);
-            }
-        }
-
-        mNewParameters.removeAt(0);
-
-        mParamStatus = status;
-        mParamCond.signal();
-        // wait for condition with time out in case the thread calling ThreadBase::setParameters()
-        // already timed out waiting for the status and will never signal the condition.
-        mWaitWorkCV.waitRelative(mLock, kSetParametersTimeoutNs);
     }
+    if (param.getInt(String8(AudioParameter::keyFrameCount), value) == NO_ERROR) {
+        // do not accept frame count changes if tracks are open as the track buffer
+        // size depends on frame count and correct behavior would not be garantied
+        // if frame count is changed after track creation
+        if (!mTracks.isEmpty()) {
+            status = INVALID_OPERATION;
+        } else {
+            reconfig = true;
+        }
+    }
+    if (status == NO_ERROR) {
+        status = mOutput->stream->common.set_parameters(&mOutput->stream->common,
+                                                keyValuePair.string());
+        if (!mStandby && status == INVALID_OPERATION) {
+            mOutput->stream->common.standby(&mOutput->stream->common);
+            mStandby = true;
+            mBytesWritten = 0;
+            status = mOutput->stream->common.set_parameters(&mOutput->stream->common,
+                                                   keyValuePair.string());
+        }
+        if (status == NO_ERROR && reconfig) {
+            readOutputParameters_l();
+            sendIoConfigEvent_l(AudioSystem::OUTPUT_CONFIG_CHANGED);
+        }
+    }
+
     return reconfig;
 }
 
@@ -4635,6 +4629,8 @@
 #ifdef TEE_SINK
     , mTeeSink(teeSink)
 #endif
+    , mReadOnlyHeap(new MemoryDealer(kRecordThreadReadOnlyHeapSize,
+            "RecordThreadRO", MemoryHeapBase::READ_ONLY))
 {
     snprintf(mName, kNameLength, "AudioIn_%X", id);
     mNBLogWriter = audioFlinger->newWriter_l(kLogSize, mName);
@@ -4699,12 +4695,14 @@
         // 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();
-            // return value 'reconfig' is currently unused
-            bool reconfig = checkForNewParameters_l();
+            processConfigEvents_l(notificationClients);
+            notificationClients.clear();
 
             // check exitPending here because checkForNewParameters_l() and
             // checkForNewParameters_l() can temporarily release mLock
@@ -5155,7 +5153,8 @@
         Mutex::Autolock _l(mLock);
 
         track = new RecordTrack(this, client, sampleRate,
-                      format, channelMask, frameCount, sessionId, uid);
+                      format, channelMask, frameCount, sessionId, uid,
+                      (*flags & IAudioFlinger::TRACK_FAST) != 0);
 
         lStatus = track->initCheck();
         if (lStatus != NO_ERROR) {
@@ -5478,126 +5477,118 @@
     buffer->frameCount = 0;
 }
 
-bool AudioFlinger::RecordThread::checkForNewParameters_l()
+bool AudioFlinger::RecordThread::checkForNewParameter_l(const String8& keyValuePair,
+                                                        status_t& status)
 {
     bool reconfig = false;
 
-    while (!mNewParameters.isEmpty()) {
-        status_t status = NO_ERROR;
-        String8 keyValuePair = mNewParameters[0];
-        AudioParameter param = AudioParameter(keyValuePair);
-        int value;
-        audio_format_t reqFormat = mFormat;
-        uint32_t samplingRate = mSampleRate;
-        audio_channel_mask_t channelMask = audio_channel_in_mask_from_count(mChannelCount);
+    status = NO_ERROR;
 
-        // TODO Investigate when this code runs. Check with audio policy when a sample rate and
-        //      channel count change can be requested. Do we mandate the first client defines the
-        //      HAL sampling rate and channel count or do we allow changes on the fly?
-        if (param.getInt(String8(AudioParameter::keySamplingRate), value) == NO_ERROR) {
-            samplingRate = value;
+    audio_format_t reqFormat = mFormat;
+    uint32_t samplingRate = mSampleRate;
+    audio_channel_mask_t channelMask = audio_channel_in_mask_from_count(mChannelCount);
+
+    AudioParameter param = AudioParameter(keyValuePair);
+    int value;
+    // TODO Investigate when this code runs. Check with audio policy when a sample rate and
+    //      channel count change can be requested. Do we mandate the first client defines the
+    //      HAL sampling rate and channel count or do we allow changes on the fly?
+    if (param.getInt(String8(AudioParameter::keySamplingRate), value) == NO_ERROR) {
+        samplingRate = value;
+        reconfig = true;
+    }
+    if (param.getInt(String8(AudioParameter::keyFormat), value) == NO_ERROR) {
+        if ((audio_format_t) value != AUDIO_FORMAT_PCM_16_BIT) {
+            status = BAD_VALUE;
+        } else {
+            reqFormat = (audio_format_t) value;
             reconfig = true;
         }
-        if (param.getInt(String8(AudioParameter::keyFormat), value) == NO_ERROR) {
-            if ((audio_format_t) value != AUDIO_FORMAT_PCM_16_BIT) {
-                status = BAD_VALUE;
-            } else {
-                reqFormat = (audio_format_t) value;
-                reconfig = true;
-            }
+    }
+    if (param.getInt(String8(AudioParameter::keyChannels), value) == NO_ERROR) {
+        audio_channel_mask_t mask = (audio_channel_mask_t) value;
+        if (mask != AUDIO_CHANNEL_IN_MONO && mask != AUDIO_CHANNEL_IN_STEREO) {
+            status = BAD_VALUE;
+        } else {
+            channelMask = mask;
+            reconfig = true;
         }
-        if (param.getInt(String8(AudioParameter::keyChannels), value) == NO_ERROR) {
-            audio_channel_mask_t mask = (audio_channel_mask_t) value;
-            if (mask != AUDIO_CHANNEL_IN_MONO && mask != AUDIO_CHANNEL_IN_STEREO) {
-                status = BAD_VALUE;
-            } else {
-                channelMask = mask;
-                reconfig = true;
-            }
+    }
+    if (param.getInt(String8(AudioParameter::keyFrameCount), value) == NO_ERROR) {
+        // do not accept frame count changes if tracks are open as the track buffer
+        // size depends on frame count and correct behavior would not be guaranteed
+        // if frame count is changed after track creation
+        if (mActiveTracks.size() > 0) {
+            status = INVALID_OPERATION;
+        } else {
+            reconfig = true;
         }
-        if (param.getInt(String8(AudioParameter::keyFrameCount), value) == NO_ERROR) {
-            // do not accept frame count changes if tracks are open as the track buffer
-            // size depends on frame count and correct behavior would not be guaranteed
-            // if frame count is changed after track creation
-            if (mActiveTracks.size() > 0) {
-                status = INVALID_OPERATION;
-            } else {
-                reconfig = true;
-            }
+    }
+    if (param.getInt(String8(AudioParameter::keyRouting), value) == NO_ERROR) {
+        // forward device change to effects that have requested to be
+        // aware of attached audio device.
+        for (size_t i = 0; i < mEffectChains.size(); i++) {
+            mEffectChains[i]->setDevice_l(value);
         }
-        if (param.getInt(String8(AudioParameter::keyRouting), value) == NO_ERROR) {
-            // forward device change to effects that have requested to be
-            // aware of attached audio device.
-            for (size_t i = 0; i < mEffectChains.size(); i++) {
-                mEffectChains[i]->setDevice_l(value);
-            }
 
-            // store input device and output device but do not forward output device to audio HAL.
-            // Note that status is ignored by the caller for output device
-            // (see AudioFlinger::setParameters()
-            if (audio_is_output_devices(value)) {
-                mOutDevice = value;
-                status = BAD_VALUE;
-            } else {
-                mInDevice = value;
-                // disable AEC and NS if the device is a BT SCO headset supporting those
-                // pre processings
-                if (mTracks.size() > 0) {
-                    bool suspend = audio_is_bluetooth_sco_device(mInDevice) &&
-                                        mAudioFlinger->btNrecIsOff();
-                    for (size_t i = 0; i < mTracks.size(); i++) {
-                        sp<RecordTrack> track = mTracks[i];
-                        setEffectSuspended_l(FX_IID_AEC, suspend, track->sessionId());
-                        setEffectSuspended_l(FX_IID_NS, suspend, track->sessionId());
-                    }
+        // store input device and output device but do not forward output device to audio HAL.
+        // Note that status is ignored by the caller for output device
+        // (see AudioFlinger::setParameters()
+        if (audio_is_output_devices(value)) {
+            mOutDevice = value;
+            status = BAD_VALUE;
+        } else {
+            mInDevice = value;
+            // disable AEC and NS if the device is a BT SCO headset supporting those
+            // pre processings
+            if (mTracks.size() > 0) {
+                bool suspend = audio_is_bluetooth_sco_device(mInDevice) &&
+                                    mAudioFlinger->btNrecIsOff();
+                for (size_t i = 0; i < mTracks.size(); i++) {
+                    sp<RecordTrack> track = mTracks[i];
+                    setEffectSuspended_l(FX_IID_AEC, suspend, track->sessionId());
+                    setEffectSuspended_l(FX_IID_NS, suspend, track->sessionId());
                 }
             }
         }
-        if (param.getInt(String8(AudioParameter::keyInputSource), value) == NO_ERROR &&
-                mAudioSource != (audio_source_t)value) {
-            // forward device change to effects that have requested to be
-            // aware of attached audio device.
-            for (size_t i = 0; i < mEffectChains.size(); i++) {
-                mEffectChains[i]->setAudioSource_l((audio_source_t)value);
-            }
-            mAudioSource = (audio_source_t)value;
+    }
+    if (param.getInt(String8(AudioParameter::keyInputSource), value) == NO_ERROR &&
+            mAudioSource != (audio_source_t)value) {
+        // forward device change to effects that have requested to be
+        // aware of attached audio device.
+        for (size_t i = 0; i < mEffectChains.size(); i++) {
+            mEffectChains[i]->setAudioSource_l((audio_source_t)value);
         }
+        mAudioSource = (audio_source_t)value;
+    }
 
-        if (status == NO_ERROR) {
+    if (status == NO_ERROR) {
+        status = mInput->stream->common.set_parameters(&mInput->stream->common,
+                keyValuePair.string());
+        if (status == INVALID_OPERATION) {
+            inputStandBy();
             status = mInput->stream->common.set_parameters(&mInput->stream->common,
                     keyValuePair.string());
-            if (status == INVALID_OPERATION) {
-                inputStandBy();
-                status = mInput->stream->common.set_parameters(&mInput->stream->common,
-                        keyValuePair.string());
+        }
+        if (reconfig) {
+            if (status == BAD_VALUE &&
+                reqFormat == mInput->stream->common.get_format(&mInput->stream->common) &&
+                reqFormat == AUDIO_FORMAT_PCM_16_BIT &&
+                (mInput->stream->common.get_sample_rate(&mInput->stream->common)
+                        <= (2 * samplingRate)) &&
+                popcount(mInput->stream->common.get_channels(&mInput->stream->common))
+                        <= FCC_2 &&
+                (channelMask == AUDIO_CHANNEL_IN_MONO ||
+                        channelMask == AUDIO_CHANNEL_IN_STEREO)) {
+                status = NO_ERROR;
             }
-            if (reconfig) {
-                if (status == BAD_VALUE &&
-                    reqFormat == mInput->stream->common.get_format(&mInput->stream->common) &&
-                    reqFormat == AUDIO_FORMAT_PCM_16_BIT &&
-                    (mInput->stream->common.get_sample_rate(&mInput->stream->common)
-                            <= (2 * samplingRate)) &&
-                    popcount(mInput->stream->common.get_channels(&mInput->stream->common))
-                            <= FCC_2 &&
-                    (channelMask == AUDIO_CHANNEL_IN_MONO ||
-                            channelMask == AUDIO_CHANNEL_IN_STEREO)) {
-                    status = NO_ERROR;
-                }
-                if (status == NO_ERROR) {
-                    readInputParameters_l();
-                    sendIoConfigEvent_l(AudioSystem::INPUT_CONFIG_CHANGED);
-                }
+            if (status == NO_ERROR) {
+                readInputParameters_l();
+                sendIoConfigEvent_l(AudioSystem::INPUT_CONFIG_CHANGED);
             }
         }
-
-        mNewParameters.removeAt(0);
-
-        mParamStatus = status;
-        mParamCond.signal();
-        // wait for condition with time out in case the thread calling ThreadBase::setParameters()
-        // already timed out waiting for the status and will never signal the condition.
-        mWaitWorkCV.waitRelative(mLock, kSetParametersTimeoutNs);
     }
+
     return reconfig;
 }
 
@@ -5614,7 +5605,10 @@
     return out_s8;
 }
 
-void AudioFlinger::RecordThread::audioConfigChanged_l(int event, int param __unused) {
+void AudioFlinger::RecordThread::audioConfigChanged_l(
+                    const DefaultKeyedVector< pid_t,sp<NotificationClient> >& notificationClients,
+                    int event,
+                    int param __unused) {
     AudioSystem::OutputDescriptor desc;
     const void *param2 = NULL;
 
@@ -5633,7 +5627,7 @@
     default:
         break;
     }
-    mAudioFlinger->audioConfigChanged_l(event, mId, param2);
+    mAudioFlinger->audioConfigChanged_l(notificationClients, event, mId, param2);
 }
 
 void AudioFlinger::RecordThread::readInputParameters_l()
diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h
index 5617c0c..9578993 100644
--- a/services/audioflinger/Threads.h
+++ b/services/audioflinger/Threads.h
@@ -46,60 +46,121 @@
     // base for record and playback
     enum {
         CFG_EVENT_IO,
-        CFG_EVENT_PRIO
+        CFG_EVENT_PRIO,
+        CFG_EVENT_SET_PARAMETER,
     };
 
-    class ConfigEvent {
+    class ConfigEventData: public RefBase {
     public:
-        ConfigEvent(int type) : mType(type) {}
-        virtual ~ConfigEvent() {}
-
-                 int type() const { return mType; }
+        virtual ~ConfigEventData() {}
 
         virtual  void dump(char *buffer, size_t size) = 0;
-
-    private:
-        const int mType;
+    protected:
+        ConfigEventData() {}
     };
 
-    class IoConfigEvent : public ConfigEvent {
-    public:
-        IoConfigEvent(int event, int param) :
-            ConfigEvent(CFG_EVENT_IO), mEvent(event), mParam(param) {}
-        virtual ~IoConfigEvent() {}
+    // Config event sequence by client if status needed (e.g binder thread calling setParameters()):
+    //  1. create SetParameterConfigEvent. This sets mWaitStatus in config event
+    //  2. Lock mLock
+    //  3. Call sendConfigEvent_l(): Append to mConfigEvents and mWaitWorkCV.signal
+    //  4. sendConfigEvent_l() reads status from event->mStatus;
+    //  5. sendConfigEvent_l() returns status
+    //  6. Unlock
+    //
+    // Parameter sequence by server: threadLoop calling processConfigEvents_l():
+    // 1. Lock mLock
+    // 2. If there is an entry in mConfigEvents proceed ...
+    // 3. Read first entry in mConfigEvents
+    // 4. Remove first entry from mConfigEvents
+    // 5. Process
+    // 6. Set event->mStatus
+    // 7. event->mCond.signal
+    // 8. Unlock
 
-                int event() const { return mEvent; }
-                int param() const { return mParam; }
+    class ConfigEvent: public RefBase {
+    public:
+        virtual ~ConfigEvent() {}
+
+        void dump(char *buffer, size_t size) { mData->dump(buffer, size); }
+
+        const int mType; // event type e.g. CFG_EVENT_IO
+        Mutex mLock;     // mutex associated with mCond
+        Condition mCond; // condition for status return
+        status_t mStatus; // status communicated to sender
+        bool mWaitStatus; // true if sender is waiting for status
+        sp<ConfigEventData> mData;     // event specific parameter data
+
+    protected:
+        ConfigEvent(int type) : mType(type), mStatus(NO_ERROR), mWaitStatus(false), mData(NULL) {}
+    };
+
+    class IoConfigEventData : public ConfigEventData {
+    public:
+        IoConfigEventData(int event, int param) :
+            mEvent(event), mParam(param) {}
 
         virtual  void dump(char *buffer, size_t size) {
             snprintf(buffer, size, "IO event: event %d, param %d\n", mEvent, mParam);
         }
 
-    private:
         const int mEvent;
         const int mParam;
     };
 
-    class PrioConfigEvent : public ConfigEvent {
+    class IoConfigEvent : public ConfigEvent {
     public:
-        PrioConfigEvent(pid_t pid, pid_t tid, int32_t prio) :
-            ConfigEvent(CFG_EVENT_PRIO), mPid(pid), mTid(tid), mPrio(prio) {}
-        virtual ~PrioConfigEvent() {}
+        IoConfigEvent(int event, int param) :
+            ConfigEvent(CFG_EVENT_IO) {
+            mData = new IoConfigEventData(event, param);
+        }
+        virtual ~IoConfigEvent() {}
+    };
 
-                pid_t pid() const { return mPid; }
-                pid_t tid() const { return mTid; }
-                int32_t prio() const { return mPrio; }
+    class PrioConfigEventData : public ConfigEventData {
+    public:
+        PrioConfigEventData(pid_t pid, pid_t tid, int32_t prio) :
+            mPid(pid), mTid(tid), mPrio(prio) {}
 
         virtual  void dump(char *buffer, size_t size) {
             snprintf(buffer, size, "Prio event: pid %d, tid %d, prio %d\n", mPid, mTid, mPrio);
         }
 
-    private:
         const pid_t mPid;
         const pid_t mTid;
         const int32_t mPrio;
     };
 
+    class PrioConfigEvent : public ConfigEvent {
+    public:
+        PrioConfigEvent(pid_t pid, pid_t tid, int32_t prio) :
+            ConfigEvent(CFG_EVENT_PRIO) {
+            mData = new PrioConfigEventData(pid, tid, prio);
+        }
+        virtual ~PrioConfigEvent() {}
+    };
+
+    class SetParameterConfigEventData : public ConfigEventData {
+    public:
+        SetParameterConfigEventData(String8 keyValuePairs) :
+            mKeyValuePairs(keyValuePairs) {}
+
+        virtual  void dump(char *buffer, size_t size) {
+            snprintf(buffer, size, "KeyValue: %s\n", mKeyValuePairs.string());
+        }
+
+        const String8 mKeyValuePairs;
+    };
+
+    class SetParameterConfigEvent : public ConfigEvent {
+    public:
+        SetParameterConfigEvent(String8 keyValuePairs) :
+            ConfigEvent(CFG_EVENT_SET_PARAMETER) {
+            mData = new SetParameterConfigEventData(keyValuePairs);
+            mWaitStatus = true;
+        }
+        virtual ~SetParameterConfigEvent() {}
+    };
+
 
     class PMDeathRecipient : public IBinder::DeathRecipient {
     public:
@@ -135,15 +196,25 @@
     // Should be "virtual status_t requestExitAndWait()" and override same
     // method in Thread, but Thread::requestExitAndWait() is not yet virtual.
                 void        exit();
-    virtual     bool        checkForNewParameters_l() = 0;
+    virtual     bool        checkForNewParameter_l(const String8& keyValuePair,
+                                                    status_t& status) = 0;
     virtual     status_t    setParameters(const String8& keyValuePairs);
     virtual     String8     getParameters(const String8& keys) = 0;
-    virtual     void        audioConfigChanged_l(int event, int param = 0) = 0;
+    virtual     void        audioConfigChanged_l(
+                      const DefaultKeyedVector< pid_t,sp<NotificationClient> >& notificationClients,
+                      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().
+                status_t    sendConfigEvent_l(sp<ConfigEvent>& event);
                 void        sendIoConfigEvent(int event, int param = 0);
                 void        sendIoConfigEvent_l(int event, int param = 0);
                 void        sendPrioConfigEvent_l(pid_t pid, pid_t tid, int32_t prio);
-                void        processConfigEvents();
-                void        processConfigEvents_l();
+                status_t    sendSetParameterConfigEvent_l(const String8& keyValuePair);
+                void        processConfigEvents_l(
+                    const DefaultKeyedVector< pid_t,sp<NotificationClient> >& notificationClients);
+    virtual     void        cacheParameters_l() = 0;
 
                 // see note at declaration of mStandby, mOutDevice and mInDevice
                 bool        standby() const { return mStandby; }
@@ -226,6 +297,13 @@
                 virtual status_t    setSyncEvent(const sp<SyncEvent>& event) = 0;
                 virtual bool        isValidSyncEvent(const sp<SyncEvent>& event) const = 0;
 
+                // Return a reference to a per-thread heap which can be used to allocate IMemory
+                // objects that will be read-only to client processes, read/write to mediaserver,
+                // and shared by all client processes of the thread.
+                // The heap is per-thread rather than common across all threads, because
+                // clients can't be trusted not to modify the offset of the IMemory they receive.
+                // If a thread does not have such a heap, this method returns 0.
+                virtual sp<MemoryDealer>    readOnlyHeap() const { return 0; }
 
     mutable     Mutex                   mLock;
 
@@ -280,31 +358,7 @@
                 audio_format_t          mFormat;
                 size_t                  mBufferSize;       // HAL buffer size for read() or write()
 
-                // Parameter sequence by client: binder thread calling setParameters():
-                //  1. Lock mLock
-                //  2. Append to mNewParameters
-                //  3. mWaitWorkCV.signal
-                //  4. mParamCond.waitRelative with timeout
-                //  5. read mParamStatus
-                //  6. mWaitWorkCV.signal
-                //  7. Unlock
-                //
-                // Parameter sequence by server: threadLoop calling checkForNewParameters_l():
-                // 1. Lock mLock
-                // 2. If there is an entry in mNewParameters proceed ...
-                // 2. Read first entry in mNewParameters
-                // 3. Process
-                // 4. Remove first entry from mNewParameters
-                // 5. Set mParamStatus
-                // 6. mParamCond.signal
-                // 7. mWaitWorkCV.wait with timeout (this is to avoid overwriting mParamStatus)
-                // 8. Unlock
-                Condition               mParamCond;
-                Vector<String8>         mNewParameters;
-                status_t                mParamStatus;
-
-                // vector owns each ConfigEvent *, so must delete after removing
-                Vector<ConfigEvent *>     mConfigEvents;
+                Vector< sp<ConfigEvent> >     mConfigEvents;
 
                 // These fields are written and read by thread itself without lock or barrier,
                 // and read by other threads without lock or barrier via standby(), outDevice()
@@ -448,7 +502,10 @@
                                 { return android_atomic_acquire_load(&mSuspended) > 0; }
 
     virtual     String8     getParameters(const String8& keys);
-    virtual     void        audioConfigChanged_l(int event, int param = 0);
+    virtual     void        audioConfigChanged_l(
+                    const DefaultKeyedVector< pid_t,sp<NotificationClient> >& notificationClients,
+                    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
@@ -717,7 +774,8 @@
 
     // Thread virtuals
 
-    virtual     bool        checkForNewParameters_l();
+    virtual     bool        checkForNewParameter_l(const String8& keyValuePair,
+                                                   status_t& status);
     virtual     void        dumpInternals(int fd, const Vector<String16>& args);
 
 protected:
@@ -771,7 +829,8 @@
 
     // Thread virtuals
 
-    virtual     bool        checkForNewParameters_l();
+    virtual     bool        checkForNewParameter_l(const String8& keyValuePair,
+                                                   status_t& status);
 
 protected:
     virtual     int         getTrackName_l(audio_channel_mask_t channelMask, int sessionId);
@@ -947,6 +1006,8 @@
 
     virtual status_t    initCheck() const { return (mInput == NULL) ? NO_INIT : NO_ERROR; }
 
+    virtual sp<MemoryDealer>    readOnlyHeap() const { return mReadOnlyHeap; }
+
             sp<AudioFlinger::RecordThread::RecordTrack>  createRecordTrack_l(
                     const sp<AudioFlinger::Client>& client,
                     uint32_t sampleRate,
@@ -972,9 +1033,14 @@
             virtual audio_stream_t* stream() const;
 
 
-    virtual bool        checkForNewParameters_l();
+    virtual bool        checkForNewParameter_l(const String8& keyValuePair,
+                                               status_t& status);
+    virtual void        cacheParameters_l() {}
     virtual String8     getParameters(const String8& keys);
-    virtual void        audioConfigChanged_l(int event, int param = 0);
+    virtual void        audioConfigChanged_l(
+                    const DefaultKeyedVector< pid_t,sp<NotificationClient> >& notificationClients,
+                    int event,
+                    int param = 0);
             void        readInputParameters_l();
     virtual uint32_t    getInputFramesLost();
 
@@ -1021,4 +1087,6 @@
 
             // For dumpsys
             const sp<NBAIO_Sink>                mTeeSink;
+
+            const sp<MemoryDealer>              mReadOnlyHeap;
 };
diff --git a/services/audioflinger/TrackBase.h b/services/audioflinger/TrackBase.h
index 58705c4..06023fd 100644
--- a/services/audioflinger/TrackBase.h
+++ b/services/audioflinger/TrackBase.h
@@ -48,7 +48,8 @@
                                 const sp<IMemory>& sharedBuffer,
                                 int sessionId,
                                 int uid,
-                                bool isOut);
+                                bool isOut,
+                                bool useReadOnlyHeap = false);
     virtual             ~TrackBase();
     virtual status_t    initCheck() const { return getCblk() != 0 ? NO_ERROR : NO_MEMORY; }
 
@@ -61,6 +62,8 @@
             int         uid() const { return mUid; }
     virtual status_t    setSyncEvent(const sp<SyncEvent>& event);
 
+            sp<IMemory> getBuffers() const { return mBufferMemory; }
+
 protected:
                         TrackBase(const TrackBase&);
                         TrackBase& operator = (const TrackBase&);
@@ -112,6 +115,7 @@
     /*const*/ sp<Client> mClient;   // see explanation at ~TrackBase() why not const
     sp<IMemory>         mCblkMemory;
     audio_track_cblk_t* mCblk;
+    sp<IMemory>         mBufferMemory;  // currently non-0 for fast RecordTrack only
     void*               mBuffer;    // start of track buffer, typically in shared memory
                                     // except for OutputTrack when it is in local memory
     // we don't really need a lock for these
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index 1064fd1..d8f3423 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -69,7 +69,8 @@
             const sp<IMemory>& sharedBuffer,
             int sessionId,
             int clientUid,
-            bool isOut)
+            bool isOut,
+            bool useReadOnlyHeap)
     :   RefBase(),
         mThread(thread),
         mClient(client),
@@ -110,7 +111,7 @@
     // ALOGD("Creating track with %d buffers @ %d bytes", bufferCount, bufferSize);
     size_t size = sizeof(audio_track_cblk_t);
     size_t bufferSize = (sharedBuffer == 0 ? roundup(frameCount) : frameCount) * mFrameSize;
-    if (sharedBuffer == 0) {
+    if (sharedBuffer == 0 && !useReadOnlyHeap) {
         size += bufferSize;
     }
 
@@ -132,15 +133,31 @@
     // construct the shared structure in-place.
     if (mCblk != NULL) {
         new(mCblk) audio_track_cblk_t();
-        // clear all buffers
-        if (sharedBuffer == 0) {
-            mBuffer = (char*)mCblk + sizeof(audio_track_cblk_t);
+        if (useReadOnlyHeap) {
+            const sp<MemoryDealer> roHeap(thread->readOnlyHeap());
+            if (roHeap == 0 ||
+                    (mBufferMemory = roHeap->allocate(bufferSize)) == 0 ||
+                    (mBuffer = mBufferMemory->pointer()) == NULL) {
+                ALOGE("not enough memory for read-only buffer size=%zu", bufferSize);
+                if (roHeap != 0) {
+                    roHeap->dump("buffer");
+                }
+                mCblkMemory.clear();
+                mBufferMemory.clear();
+                return;
+            }
             memset(mBuffer, 0, bufferSize);
         } else {
-            mBuffer = sharedBuffer->pointer();
+            // clear all buffers
+            if (sharedBuffer == 0) {
+                mBuffer = (char*)mCblk + sizeof(audio_track_cblk_t);
+                memset(mBuffer, 0, bufferSize);
+            } else {
+                mBuffer = sharedBuffer->pointer();
 #if 0
-            mCblk->mFlags = CBLK_FORCEREADY;    // FIXME hack, need to fix the track ready logic
+                mCblk->mFlags = CBLK_FORCEREADY;    // FIXME hack, need to fix the track ready logic
 #endif
+            }
         }
 
 #ifdef TEE_SINK
@@ -1783,10 +1800,6 @@
     mRecordTrack->destroy();
 }
 
-sp<IMemory> AudioFlinger::RecordHandle::getCblk() const {
-    return mRecordTrack->getCblk();
-}
-
 status_t AudioFlinger::RecordHandle::start(int /*AudioSystem::sync_event_t*/ event,
         int triggerSession) {
     ALOGV("RecordHandle::start()");
@@ -1819,9 +1832,11 @@
             audio_channel_mask_t channelMask,
             size_t frameCount,
             int sessionId,
-            int uid)
+            int uid,
+            bool isFast)
     :   TrackBase(thread, client, sampleRate, format,
-                  channelMask, frameCount, 0 /*sharedBuffer*/, sessionId, uid, false /*isOut*/),
+                  channelMask, frameCount, 0 /*sharedBuffer*/, sessionId, uid, false /*isOut*/,
+                  isFast /*useReadOnlyHeap*/),
         mOverflow(false), mResampler(NULL), mRsmpOutBuffer(NULL), mRsmpOutFrameCount(0),
         // See real initialization of mRsmpInFront at RecordThread::start()
         mRsmpInUnrel(0), mRsmpInFront(0), mFramesToDrop(0), mResamplerBufferProvider(NULL)
diff --git a/services/audiopolicy/AudioPolicyManager.cpp b/services/audiopolicy/AudioPolicyManager.cpp
index fc9b81a..62a44ee 100644
--- a/services/audiopolicy/AudioPolicyManager.cpp
+++ b/services/audiopolicy/AudioPolicyManager.cpp
@@ -2920,9 +2920,6 @@
     uint32_t muteWaitMs = 0;
     audio_devices_t device = outputDesc->device();
     bool shouldMute = outputDesc->isActive() && (popcount(device) >= 2);
-    // temporary mute output if device selection changes to avoid volume bursts due to
-    // different per device volumes
-    bool tempMute = outputDesc->isActive() && (device != prevDevice);
 
     for (size_t i = 0; i < NUM_STRATEGIES; i++) {
         audio_devices_t curDevice = getDeviceForStrategy((routing_strategy)i, false /*fromCache*/);
@@ -2936,7 +2933,7 @@
             doMute = true;
             outputDesc->mStrategyMutedByDevice[i] = false;
         }
-        if (doMute || tempMute) {
+        if (doMute) {
             for (size_t j = 0; j < mOutputs.size(); j++) {
                 AudioOutputDescriptor *desc = mOutputs.valueAt(j);
                 // skip output if it does not share any device with current output
@@ -2949,15 +2946,14 @@
                       mute ? "muting" : "unmuting", i, curDevice, curOutput);
                 setStrategyMute((routing_strategy)i, mute, curOutput, mute ? 0 : delayMs);
                 if (desc->isStrategyActive((routing_strategy)i)) {
-                    // do tempMute only for current output
-                    if (tempMute && (desc == outputDesc)) {
-                        setStrategyMute((routing_strategy)i, true, curOutput);
-                        setStrategyMute((routing_strategy)i, false, curOutput,
-                                            desc->latency() * 2, device);
-                    }
-                    if ((tempMute && (desc == outputDesc)) || mute) {
-                        if (muteWaitMs < desc->latency()) {
-                            muteWaitMs = desc->latency();
+                    if (mute) {
+                        // FIXME: should not need to double latency if volume could be applied
+                        // immediately by the audioflinger mixer. We must account for the delay
+                        // between now and the next time the audioflinger thread for this output
+                        // will process a buffer (which corresponds to one buffer size,
+                        // usually 1/2 or 1/4 of the latency).
+                        if (muteWaitMs < desc->latency() * 2) {
+                            muteWaitMs = desc->latency() * 2;
                         }
                     }
                 }
@@ -2965,11 +2961,22 @@
         }
     }
 
-    // FIXME: should not need to double latency if volume could be applied immediately by the
-    // audioflinger mixer. We must account for the delay between now and the next time
-    // the audioflinger thread for this output will process a buffer (which corresponds to
-    // one buffer size, usually 1/2 or 1/4 of the latency).
-    muteWaitMs *= 2;
+    // temporary mute output if device selection changes to avoid volume bursts due to
+    // different per device volumes
+    if (outputDesc->isActive() && (device != prevDevice)) {
+        if (muteWaitMs < outputDesc->latency() * 2) {
+            muteWaitMs = outputDesc->latency() * 2;
+        }
+        for (size_t i = 0; i < NUM_STRATEGIES; i++) {
+            if (outputDesc->isStrategyActive((routing_strategy)i)) {
+                setStrategyMute((routing_strategy)i, true, outputDesc->mId);
+                // do tempMute unmute after twice the mute wait time
+                setStrategyMute((routing_strategy)i, false, outputDesc->mId,
+                                muteWaitMs *2, device);
+            }
+        }
+    }
+
     // wait for the PCM output buffers to empty before proceeding with the rest of the command
     if (muteWaitMs > delayMs) {
         muteWaitMs -= delayMs;
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);