Merge "AudioTrackShared cleanup"
diff --git a/camera/CameraParameters.cpp b/camera/CameraParameters.cpp
index d10f2e5..c51f265 100644
--- a/camera/CameraParameters.cpp
+++ b/camera/CameraParameters.cpp
@@ -242,7 +242,7 @@
         return;
     }
 
-    if (strchr(value, '=') || strchr(key, ';')) {
+    if (strchr(value, '=') || strchr(value, ';')) {
         //XXX ALOGE("Value \"%s\"contains invalid character (= or ;)", value);
         return;
     }
diff --git a/include/cpustats/CentralTendencyStatistics.h b/include/cpustats/CentralTendencyStatistics.h
new file mode 100644
index 0000000..21b6981
--- /dev/null
+++ b/include/cpustats/CentralTendencyStatistics.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _CENTRAL_TENDENCY_STATISTICS_H
+#define _CENTRAL_TENDENCY_STATISTICS_H
+
+#include <math.h>
+
+// Not multithread safe
+class CentralTendencyStatistics {
+
+public:
+
+    CentralTendencyStatistics() :
+            mMean(NAN), mMedian(NAN), mMinimum(INFINITY), mMaximum(-INFINITY), mN(0), mM2(0),
+            mVariance(NAN), mVarianceKnownForN(0), mStddev(NAN), mStddevKnownForN(0) { }
+
+    ~CentralTendencyStatistics() { }
+
+    // add x to the set of samples
+    void sample(double x);
+
+    // return the arithmetic mean of all samples so far
+    double mean() const { return mMean; }
+
+    // return the minimum of all samples so far
+    double minimum() const { return mMinimum; }
+
+    // return the maximum of all samples so far
+    double maximum() const { return mMaximum; }
+
+    // return the variance of all samples so far
+    double variance() const;
+
+    // return the standard deviation of all samples so far
+    double stddev() const;
+
+    // return the number of samples added so far
+    unsigned n() const { return mN; }
+
+    // reset the set of samples to be empty
+    void reset();
+
+private:
+    double mMean;
+    double mMedian;
+    double mMinimum;
+    double mMaximum;
+    unsigned mN;    // number of samples so far
+    double mM2;
+
+    // cached variance, and n at time of caching
+    mutable double mVariance;
+    mutable unsigned mVarianceKnownForN;
+
+    // cached standard deviation, and n at time of caching
+    mutable double mStddev;
+    mutable unsigned mStddevKnownForN;
+
+};
+
+#endif // _CENTRAL_TENDENCY_STATISTICS_H
diff --git a/include/cpustats/README.txt b/include/cpustats/README.txt
new file mode 100644
index 0000000..14439f0
--- /dev/null
+++ b/include/cpustats/README.txt
@@ -0,0 +1,6 @@
+This is a static library of CPU usage statistics, originally written
+for audio but most are not actually specific to audio.
+
+Requirements to be here:
+ * should be related to CPU usage statistics
+ * should be portable to host; avoid Android OS dependencies without a conditional
diff --git a/include/cpustats/ThreadCpuUsage.h b/include/cpustats/ThreadCpuUsage.h
new file mode 100644
index 0000000..9756844
--- /dev/null
+++ b/include/cpustats/ThreadCpuUsage.h
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _THREAD_CPU_USAGE_H
+#define _THREAD_CPU_USAGE_H
+
+#include <fcntl.h>
+#include <pthread.h>
+
+namespace android {
+
+// Track CPU usage for the current thread.
+// Units are in per-thread CPU ns, as reported by
+// clock_gettime(CLOCK_THREAD_CPUTIME_ID).  Simple usage: for cyclic
+// threads where you want to measure the execution time of the whole
+// cycle, just call sampleAndEnable() at the start of each cycle.
+// For acyclic threads, or for cyclic threads where you want to measure/track
+// only part of each cycle, call enable(), disable(), and/or setEnabled()
+// to demarcate the region(s) of interest, and then call sample() periodically.
+// This class is not thread-safe for concurrent calls from multiple threads;
+// the methods of this class may only be called by the current thread
+// which constructed the object.
+
+class ThreadCpuUsage
+{
+
+public:
+    ThreadCpuUsage() :
+        mIsEnabled(false),
+        mWasEverEnabled(false),
+        mAccumulator(0),
+        // mPreviousTs
+        // mMonotonicTs
+        mMonotonicKnown(false)
+        {
+            (void) pthread_once(&sOnceControl, &init);
+            for (int i = 0; i < sKernelMax; ++i) {
+                mCurrentkHz[i] = (uint32_t) ~0;   // unknown
+            }
+        }
+
+    ~ThreadCpuUsage() { }
+
+    // Return whether currently tracking CPU usage by current thread
+    bool isEnabled() const  { return mIsEnabled; }
+
+    // Enable tracking of CPU usage by current thread;
+    // any CPU used from this point forward will be tracked.
+    // Returns the previous enabled status.
+    bool enable()       { return setEnabled(true); }
+
+    // Disable tracking of CPU usage by current thread;
+    // any CPU used from this point forward will be ignored.
+    // Returns the previous enabled status.
+    bool disable()      { return setEnabled(false); }
+
+    // Set the enabled status and return the previous enabled status.
+    // This method is intended to be used for safe nested enable/disabling.
+    bool setEnabled(bool isEnabled);
+
+    // Add a sample point, and also enable tracking if needed.
+    // If tracking has never been enabled, then this call enables tracking but
+    // does _not_ add a sample -- it is not possible to add a sample the
+    // first time because there is no previous point to subtract from.
+    // Otherwise, if tracking is enabled,
+    // then adds a sample for tracked CPU ns since the previous
+    // sample, or since the first call to sampleAndEnable(), enable(), or
+    // setEnabled(true).  If there was a previous sample but tracking is
+    // now disabled, then adds a sample for the tracked CPU ns accumulated
+    // up until the most recent disable(), resets this accumulator, and then
+    // enables tracking.  Calling this method rather than enable() followed
+    // by sample() avoids a race condition for the first sample.
+    // Returns true if the sample 'ns' is valid, or false if invalid.
+    // Note that 'ns' is an output parameter passed by reference.
+    // The caller does not need to initialize this variable.
+    // The units are CPU nanoseconds consumed by current thread.
+    bool sampleAndEnable(double& ns);
+
+    // Add a sample point, but do not
+    // change the tracking enabled status.  If tracking has either never been
+    // enabled, or has never been enabled since the last sample, then log a warning
+    // and don't add sample.  Otherwise, adds a sample for tracked CPU ns since
+    // the previous sample or since the first call to sampleAndEnable(),
+    // enable(), or setEnabled(true) if no previous sample.
+    // Returns true if the sample is valid, or false if invalid.
+    // Note that 'ns' is an output parameter passed by reference.
+    // The caller does not need to initialize this variable.
+    // The units are CPU nanoseconds consumed by current thread.
+    bool sample(double& ns);
+
+    // Return the elapsed delta wall clock ns since initial enable or reset,
+    // as reported by clock_gettime(CLOCK_MONOTONIC).
+    long long elapsed() const;
+
+    // Reset elapsed wall clock.  Has no effect on tracking or accumulator.
+    void resetElapsed();
+
+    // Return current clock frequency for specified CPU, in kHz.
+    // You can get your CPU number using sched_getcpu(2).  Note that, unless CPU affinity
+    // has been configured appropriately, the CPU number can change.
+    // Also note that, unless the CPU governor has been configured appropriately,
+    // the CPU frequency can change.  And even if the CPU frequency is locked down
+    // to a particular value, that the frequency might still be adjusted
+    // to prevent thermal overload.  Therefore you should poll for your thread's
+    // current CPU number and clock frequency periodically.
+    uint32_t getCpukHz(int cpuNum);
+
+private:
+    bool mIsEnabled;                // whether tracking is currently enabled
+    bool mWasEverEnabled;           // whether tracking was ever enabled
+    long long mAccumulator;         // accumulated thread CPU time since last sample, in ns
+    struct timespec mPreviousTs;    // most recent thread CPU time, valid only if mIsEnabled is true
+    struct timespec mMonotonicTs;   // most recent monotonic time
+    bool mMonotonicKnown;           // whether mMonotonicTs has been set
+
+    static const int MAX_CPU = 8;
+    static int sScalingFds[MAX_CPU];// file descriptor per CPU for reading scaling_cur_freq
+    uint32_t mCurrentkHz[MAX_CPU];  // current CPU frequency in kHz, not static to avoid a race
+    static pthread_once_t sOnceControl;
+    static int sKernelMax;          // like MAX_CPU, but determined at runtime == cpu/kernel_max + 1
+    static void init();             // called once at first ThreadCpuUsage construction
+    static pthread_mutex_t sMutex;  // protects sScalingFds[] after initialization
+};
+
+}   // namespace android
+
+#endif //  _THREAD_CPU_USAGE_H
diff --git a/include/media/AudioSystem.h b/include/media/AudioSystem.h
index 09160cc..fb1d631 100644
--- a/include/media/AudioSystem.h
+++ b/include/media/AudioSystem.h
@@ -17,20 +17,18 @@
 #ifndef ANDROID_AUDIOSYSTEM_H_
 #define ANDROID_AUDIOSYSTEM_H_
 
-#include <utils/RefBase.h>
-#include <utils/threads.h>
-#include <media/IAudioFlinger.h>
-
+#include <hardware/audio_effect.h>
+#include <media/IAudioFlingerClient.h>
 #include <system/audio.h>
 #include <system/audio_policy.h>
-
-/* XXX: Should be include by all the users instead */
-#include <media/AudioParameter.h>
+#include <utils/Errors.h>
+#include <utils/Mutex.h>
 
 namespace android {
 
 typedef void (*audio_error_callback)(status_t err);
 
+class IAudioFlinger;
 class IAudioPolicyService;
 class String8;
 
diff --git a/include/media/Visualizer.h b/include/media/Visualizer.h
index aa58905..e429263 100644
--- a/include/media/Visualizer.h
+++ b/include/media/Visualizer.h
@@ -19,7 +19,7 @@
 
 #include <media/AudioEffect.h>
 #include <audio_effects/effect_visualizer.h>
-#include <string.h>
+#include <utils/Thread.h>
 
 /**
  * The Visualizer class enables application to retrieve part of the currently playing audio for
diff --git a/media/libcpustats/Android.mk b/media/libcpustats/Android.mk
new file mode 100644
index 0000000..b506353
--- /dev/null
+++ b/media/libcpustats/Android.mk
@@ -0,0 +1,11 @@
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES :=     \
+        CentralTendencyStatistics.cpp \
+        ThreadCpuUsage.cpp
+
+LOCAL_MODULE := libcpustats
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/media/libcpustats/CentralTendencyStatistics.cpp b/media/libcpustats/CentralTendencyStatistics.cpp
new file mode 100644
index 0000000..42ab62b
--- /dev/null
+++ b/media/libcpustats/CentralTendencyStatistics.cpp
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdlib.h>
+
+#include <cpustats/CentralTendencyStatistics.h>
+
+void CentralTendencyStatistics::sample(double x)
+{
+    // update min and max
+    if (x < mMinimum)
+        mMinimum = x;
+    if (x > mMaximum)
+        mMaximum = x;
+    // Knuth
+    if (mN == 0) {
+        mMean = 0;
+    }
+    ++mN;
+    double delta = x - mMean;
+    mMean += delta / mN;
+    mM2 += delta * (x - mMean);
+}
+
+void CentralTendencyStatistics::reset()
+{
+    mMean = NAN;
+    mMedian = NAN;
+    mMinimum = INFINITY;
+    mMaximum = -INFINITY;
+    mN = 0;
+    mM2 = 0;
+    mVariance = NAN;
+    mVarianceKnownForN = 0;
+    mStddev = NAN;
+    mStddevKnownForN = 0;
+}
+
+double CentralTendencyStatistics::variance() const
+{
+    double variance;
+    if (mVarianceKnownForN != mN) {
+        if (mN > 1) {
+            // double variance_n = M2/n;
+            variance = mM2 / (mN - 1);
+        } else {
+            variance = NAN;
+        }
+        mVariance = variance;
+        mVarianceKnownForN = mN;
+    } else {
+        variance = mVariance;
+    }
+    return variance;
+}
+
+double CentralTendencyStatistics::stddev() const
+{
+    double stddev;
+    if (mStddevKnownForN != mN) {
+        stddev = sqrt(variance());
+        mStddev = stddev;
+        mStddevKnownForN = mN;
+    } else {
+        stddev = mStddev;
+    }
+    return stddev;
+}
diff --git a/media/libcpustats/ThreadCpuUsage.cpp b/media/libcpustats/ThreadCpuUsage.cpp
new file mode 100644
index 0000000..637402a
--- /dev/null
+++ b/media/libcpustats/ThreadCpuUsage.cpp
@@ -0,0 +1,255 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "ThreadCpuUsage"
+//#define LOG_NDEBUG 0
+
+#include <errno.h>
+#include <stdlib.h>
+#include <time.h>
+
+#include <utils/Debug.h>
+#include <utils/Log.h>
+
+#include <cpustats/ThreadCpuUsage.h>
+
+namespace android {
+
+bool ThreadCpuUsage::setEnabled(bool isEnabled)
+{
+    bool wasEnabled = mIsEnabled;
+    // only do something if there is a change
+    if (isEnabled != wasEnabled) {
+        ALOGV("setEnabled(%d)", isEnabled);
+        int rc;
+        // enabling
+        if (isEnabled) {
+            rc = clock_gettime(CLOCK_THREAD_CPUTIME_ID, &mPreviousTs);
+            if (rc) {
+                ALOGE("clock_gettime(CLOCK_THREAD_CPUTIME_ID) errno=%d", errno);
+                isEnabled = false;
+            } else {
+                mWasEverEnabled = true;
+                // record wall clock time at first enable
+                if (!mMonotonicKnown) {
+                    rc = clock_gettime(CLOCK_MONOTONIC, &mMonotonicTs);
+                    if (rc) {
+                        ALOGE("clock_gettime(CLOCK_MONOTONIC) errno=%d", errno);
+                    } else {
+                        mMonotonicKnown = true;
+                    }
+                }
+            }
+        // disabling
+        } else {
+            struct timespec ts;
+            rc = clock_gettime(CLOCK_THREAD_CPUTIME_ID, &ts);
+            if (rc) {
+                ALOGE("clock_gettime(CLOCK_THREAD_CPUTIME_ID) errno=%d", errno);
+            } else {
+                long long delta = (ts.tv_sec - mPreviousTs.tv_sec) * 1000000000LL +
+                        (ts.tv_nsec - mPreviousTs.tv_nsec);
+                mAccumulator += delta;
+#if 0
+                mPreviousTs = ts;
+#endif
+            }
+        }
+        mIsEnabled = isEnabled;
+    }
+    return wasEnabled;
+}
+
+bool ThreadCpuUsage::sampleAndEnable(double& ns)
+{
+    bool ret;
+    bool wasEverEnabled = mWasEverEnabled;
+    if (enable()) {
+        // already enabled, so add a new sample relative to previous
+        return sample(ns);
+    } else if (wasEverEnabled) {
+        // was disabled, but add sample for accumulated time while enabled
+        ns = (double) mAccumulator;
+        mAccumulator = 0;
+        ALOGV("sampleAndEnable %.0f", ns);
+        return true;
+    } else {
+        // first time called
+        ns = 0.0;
+        ALOGV("sampleAndEnable false");
+        return false;
+    }
+}
+
+bool ThreadCpuUsage::sample(double &ns)
+{
+    if (mWasEverEnabled) {
+        if (mIsEnabled) {
+            struct timespec ts;
+            int rc;
+            rc = clock_gettime(CLOCK_THREAD_CPUTIME_ID, &ts);
+            if (rc) {
+                ALOGE("clock_gettime(CLOCK_THREAD_CPUTIME_ID) errno=%d", errno);
+                ns = 0.0;
+                return false;
+            } else {
+                long long delta = (ts.tv_sec - mPreviousTs.tv_sec) * 1000000000LL +
+                        (ts.tv_nsec - mPreviousTs.tv_nsec);
+                mAccumulator += delta;
+                mPreviousTs = ts;
+            }
+        } else {
+            mWasEverEnabled = false;
+        }
+        ns = (double) mAccumulator;
+        ALOGV("sample %.0f", ns);
+        mAccumulator = 0;
+        return true;
+    } else {
+        ALOGW("Can't add sample because measurements have never been enabled");
+        ns = 0.0;
+        return false;
+    }
+}
+
+long long ThreadCpuUsage::elapsed() const
+{
+    long long elapsed;
+    if (mMonotonicKnown) {
+        struct timespec ts;
+        int rc;
+        rc = clock_gettime(CLOCK_MONOTONIC, &ts);
+        if (rc) {
+            ALOGE("clock_gettime(CLOCK_MONOTONIC) errno=%d", errno);
+            elapsed = 0;
+        } else {
+            // mMonotonicTs is updated only at first enable and resetStatistics
+            elapsed = (ts.tv_sec - mMonotonicTs.tv_sec) * 1000000000LL +
+                    (ts.tv_nsec - mMonotonicTs.tv_nsec);
+        }
+    } else {
+        ALOGW("Can't compute elapsed time because measurements have never been enabled");
+        elapsed = 0;
+    }
+    ALOGV("elapsed %lld", elapsed);
+    return elapsed;
+}
+
+void ThreadCpuUsage::resetElapsed()
+{
+    ALOGV("resetElapsed");
+    if (mMonotonicKnown) {
+        int rc;
+        rc = clock_gettime(CLOCK_MONOTONIC, &mMonotonicTs);
+        if (rc) {
+            ALOGE("clock_gettime(CLOCK_MONOTONIC) errno=%d", errno);
+            mMonotonicKnown = false;
+        }
+    }
+}
+
+/*static*/
+int ThreadCpuUsage::sScalingFds[ThreadCpuUsage::MAX_CPU];
+pthread_once_t ThreadCpuUsage::sOnceControl = PTHREAD_ONCE_INIT;
+int ThreadCpuUsage::sKernelMax;
+pthread_mutex_t ThreadCpuUsage::sMutex = PTHREAD_MUTEX_INITIALIZER;
+
+/*static*/
+void ThreadCpuUsage::init()
+{
+    // read the number of CPUs
+    sKernelMax = 1;
+    int fd = open("/sys/devices/system/cpu/kernel_max", O_RDONLY);
+    if (fd >= 0) {
+#define KERNEL_MAX_SIZE 12
+        char kernelMax[KERNEL_MAX_SIZE];
+        ssize_t actual = read(fd, kernelMax, sizeof(kernelMax));
+        if (actual >= 2 && kernelMax[actual-1] == '\n') {
+            sKernelMax = atoi(kernelMax);
+            if (sKernelMax >= MAX_CPU - 1) {
+                ALOGW("kernel_max %d but MAX_CPU %d", sKernelMax, MAX_CPU);
+                sKernelMax = MAX_CPU;
+            } else if (sKernelMax < 0) {
+                ALOGW("kernel_max invalid %d", sKernelMax);
+                sKernelMax = 1;
+            } else {
+                ++sKernelMax;
+                ALOGV("number of CPUs %d", sKernelMax);
+            }
+        } else {
+            ALOGW("Can't read number of CPUs");
+        }
+        (void) close(fd);
+    } else {
+        ALOGW("Can't open number of CPUs");
+    }
+    int i;
+    for (i = 0; i < MAX_CPU; ++i) {
+        sScalingFds[i] = -1;
+    }
+}
+
+uint32_t ThreadCpuUsage::getCpukHz(int cpuNum)
+{
+    if (cpuNum < 0 || cpuNum >= MAX_CPU) {
+        ALOGW("getCpukHz called with invalid CPU %d", cpuNum);
+        return 0;
+    }
+    // double-checked locking idiom is not broken for atomic values such as fd
+    int fd = sScalingFds[cpuNum];
+    if (fd < 0) {
+        // some kernels can't open a scaling file until hot plug complete
+        pthread_mutex_lock(&sMutex);
+        fd = sScalingFds[cpuNum];
+        if (fd < 0) {
+#define FREQ_SIZE 64
+            char freq_path[FREQ_SIZE];
+#define FREQ_DIGIT 27
+            COMPILE_TIME_ASSERT_FUNCTION_SCOPE(MAX_CPU <= 10);
+#define FREQ_PATH "/sys/devices/system/cpu/cpu?/cpufreq/scaling_cur_freq"
+            strlcpy(freq_path, FREQ_PATH, sizeof(freq_path));
+            freq_path[FREQ_DIGIT] = cpuNum + '0';
+            fd = open(freq_path, O_RDONLY | O_CLOEXEC);
+            // keep this fd until process exit or exec
+            sScalingFds[cpuNum] = fd;
+        }
+        pthread_mutex_unlock(&sMutex);
+        if (fd < 0) {
+            ALOGW("getCpukHz can't open CPU %d", cpuNum);
+            return 0;
+        }
+    }
+#define KHZ_SIZE 12
+    char kHz[KHZ_SIZE];   // kHz base 10
+    ssize_t actual = pread(fd, kHz, sizeof(kHz), (off_t) 0);
+    uint32_t ret;
+    if (actual >= 2 && kHz[actual-1] == '\n') {
+        ret = atoi(kHz);
+    } else {
+        ret = 0;
+    }
+    if (ret != mCurrentkHz[cpuNum]) {
+        if (ret > 0) {
+            ALOGV("CPU %d frequency %u kHz", cpuNum, ret);
+        } else {
+            ALOGW("Can't read CPU %d frequency", cpuNum);
+        }
+        mCurrentkHz[cpuNum] = ret;
+    }
+    return ret;
+}
+
+}   // namespace android
diff --git a/media/libmedia/AudioRecord.cpp b/media/libmedia/AudioRecord.cpp
index 9faa497..8ae0908 100644
--- a/media/libmedia/AudioRecord.cpp
+++ b/media/libmedia/AudioRecord.cpp
@@ -23,6 +23,7 @@
 #include <media/AudioRecord.h>
 #include <utils/Log.h>
 #include <private/media/AudioTrackShared.h>
+#include <media/IAudioFlinger.h>
 
 #define WAIT_PERIOD_MS          10
 
diff --git a/media/libmedia/AudioSystem.cpp b/media/libmedia/AudioSystem.cpp
index a6dedec..22d6763 100644
--- a/media/libmedia/AudioSystem.cpp
+++ b/media/libmedia/AudioSystem.cpp
@@ -20,6 +20,7 @@
 #include <utils/Log.h>
 #include <binder/IServiceManager.h>
 #include <media/AudioSystem.h>
+#include <media/IAudioFlinger.h>
 #include <media/IAudioPolicyService.h>
 #include <math.h>
 
diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp
index 2af162c..00f4640 100644
--- a/media/libmedia/AudioTrack.cpp
+++ b/media/libmedia/AudioTrack.cpp
@@ -25,6 +25,7 @@
 #include <media/AudioTrack.h>
 #include <utils/Log.h>
 #include <private/media/AudioTrackShared.h>
+#include <media/IAudioFlinger.h>
 
 #define WAIT_PERIOD_MS          10
 
@@ -1237,7 +1238,8 @@
         if (tryCounter < 0) {
             ALOGE("did not receive expected priority boost on time");
         }
-        return true;
+        // Run again immediately
+        return 0;
     }
 
     // Can only reference mCblk while locked
diff --git a/media/libmedia/AudioTrackShared.cpp b/media/libmedia/AudioTrackShared.cpp
index 554802d..55bf175 100644
--- a/media/libmedia/AudioTrackShared.cpp
+++ b/media/libmedia/AudioTrackShared.cpp
@@ -388,6 +388,8 @@
         if (flush != mFlush) {
             front = rear;
             mFlush = flush;
+            // effectively obtain then release whatever is in the buffer
+            android_atomic_release_store(rear, &cblk->u.mStreaming.mFront);
         } else {
             front = cblk->u.mStreaming.mFront;
         }
diff --git a/media/libmedia/IAudioFlinger.cpp b/media/libmedia/IAudioFlinger.cpp
index e4df77d..6bb7df6 100644
--- a/media/libmedia/IAudioFlinger.cpp
+++ b/media/libmedia/IAudioFlinger.cpp
@@ -365,11 +365,12 @@
                                          const audio_offload_info_t *offloadInfo)
     {
         Parcel data, reply;
-        audio_devices_t devices = pDevices ? *pDevices : (audio_devices_t)0;
-        uint32_t samplingRate = pSamplingRate ? *pSamplingRate : 0;
-        audio_format_t format = pFormat ? *pFormat : AUDIO_FORMAT_DEFAULT;
-        audio_channel_mask_t channelMask = pChannelMask ? *pChannelMask : (audio_channel_mask_t)0;
-        uint32_t latency = pLatencyMs ? *pLatencyMs : 0;
+        audio_devices_t devices = pDevices != NULL ? *pDevices : (audio_devices_t)0;
+        uint32_t samplingRate = pSamplingRate != NULL ? *pSamplingRate : 0;
+        audio_format_t format = pFormat != NULL ? *pFormat : AUDIO_FORMAT_DEFAULT;
+        audio_channel_mask_t channelMask = pChannelMask != NULL ?
+                *pChannelMask : (audio_channel_mask_t)0;
+        uint32_t latency = pLatencyMs != NULL ? *pLatencyMs : 0;
 
         data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
         data.writeInt32(module);
@@ -383,15 +384,15 @@
         audio_io_handle_t output = (audio_io_handle_t) reply.readInt32();
         ALOGV("openOutput() returned output, %d", output);
         devices = (audio_devices_t)reply.readInt32();
-        if (pDevices) *pDevices = devices;
+        if (pDevices != NULL) *pDevices = devices;
         samplingRate = reply.readInt32();
-        if (pSamplingRate) *pSamplingRate = samplingRate;
+        if (pSamplingRate != NULL) *pSamplingRate = samplingRate;
         format = (audio_format_t) reply.readInt32();
-        if (pFormat) *pFormat = format;
+        if (pFormat != NULL) *pFormat = format;
         channelMask = (audio_channel_mask_t)reply.readInt32();
-        if (pChannelMask) *pChannelMask = channelMask;
+        if (pChannelMask != NULL) *pChannelMask = channelMask;
         latency = reply.readInt32();
-        if (pLatencyMs) *pLatencyMs = latency;
+        if (pLatencyMs != NULL) *pLatencyMs = latency;
         return output;
     }
 
@@ -440,10 +441,11 @@
                                         audio_channel_mask_t *pChannelMask)
     {
         Parcel data, reply;
-        audio_devices_t devices = pDevices ? *pDevices : (audio_devices_t)0;
-        uint32_t samplingRate = pSamplingRate ? *pSamplingRate : 0;
-        audio_format_t format = pFormat ? *pFormat : AUDIO_FORMAT_DEFAULT;
-        audio_channel_mask_t channelMask = pChannelMask ? *pChannelMask : (audio_channel_mask_t)0;
+        audio_devices_t devices = pDevices != NULL ? *pDevices : (audio_devices_t)0;
+        uint32_t samplingRate = pSamplingRate != NULL ? *pSamplingRate : 0;
+        audio_format_t format = pFormat != NULL ? *pFormat : AUDIO_FORMAT_DEFAULT;
+        audio_channel_mask_t channelMask = pChannelMask != NULL ?
+                *pChannelMask : (audio_channel_mask_t)0;
 
         data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
         data.writeInt32(module);
@@ -454,13 +456,13 @@
         remote()->transact(OPEN_INPUT, data, &reply);
         audio_io_handle_t input = (audio_io_handle_t) reply.readInt32();
         devices = (audio_devices_t)reply.readInt32();
-        if (pDevices) *pDevices = devices;
+        if (pDevices != NULL) *pDevices = devices;
         samplingRate = reply.readInt32();
-        if (pSamplingRate) *pSamplingRate = samplingRate;
+        if (pSamplingRate != NULL) *pSamplingRate = samplingRate;
         format = (audio_format_t) reply.readInt32();
-        if (pFormat) *pFormat = format;
+        if (pFormat != NULL) *pFormat = format;
         channelMask = (audio_channel_mask_t)reply.readInt32();
-        if (pChannelMask) *pChannelMask = channelMask;
+        if (pChannelMask != NULL) *pChannelMask = channelMask;
         return input;
     }
 
diff --git a/media/libmedia/JetPlayer.cpp b/media/libmedia/JetPlayer.cpp
index 8fe5bb3..e914b34 100644
--- a/media/libmedia/JetPlayer.cpp
+++ b/media/libmedia/JetPlayer.cpp
@@ -18,8 +18,6 @@
 #define LOG_TAG "JetPlayer-C"
 
 #include <utils/Log.h>
-#include <utils/threads.h>
-
 #include <media/JetPlayer.h>
 
 
diff --git a/media/libmedia/SoundPool.cpp b/media/libmedia/SoundPool.cpp
index e1e88ec..7f10e05 100644
--- a/media/libmedia/SoundPool.cpp
+++ b/media/libmedia/SoundPool.cpp
@@ -20,14 +20,8 @@
 
 //#define USE_SHARED_MEM_BUFFER
 
-// XXX needed for timing latency
-#include <utils/Timers.h>
-
 #include <media/AudioTrack.h>
 #include <media/mediaplayer.h>
-
-#include <system/audio.h>
-
 #include <media/SoundPool.h>
 #include "SoundPoolThread.h"
 
diff --git a/media/libmedia/ToneGenerator.cpp b/media/libmedia/ToneGenerator.cpp
index f9ad31d..adef3be 100644
--- a/media/libmedia/ToneGenerator.cpp
+++ b/media/libmedia/ToneGenerator.cpp
@@ -16,13 +16,9 @@
 
 //#define LOG_NDEBUG 0
 #define LOG_TAG "ToneGenerator"
-#include <utils/threads.h>
 
-#include <stdio.h>
 #include <math.h>
 #include <utils/Log.h>
-#include <utils/RefBase.h>
-#include <utils/Timers.h>
 #include <cutils/properties.h>
 #include "media/ToneGenerator.h"
 
diff --git a/media/libmedia/Visualizer.cpp b/media/libmedia/Visualizer.cpp
index 5b4071b..e519f13 100644
--- a/media/libmedia/Visualizer.cpp
+++ b/media/libmedia/Visualizer.cpp
@@ -28,6 +28,7 @@
 
 #include <media/Visualizer.h>
 #include <audio_utils/fixedfft.h>
+#include <utils/Thread.h>
 
 namespace android {
 
diff --git a/media/libmediaplayerservice/Drm.cpp b/media/libmediaplayerservice/Drm.cpp
index 1e6cd94..f00f488 100644
--- a/media/libmediaplayerservice/Drm.cpp
+++ b/media/libmediaplayerservice/Drm.cpp
@@ -71,6 +71,12 @@
 status_t Drm::setListener(const sp<IDrmClient>& listener)
 {
     Mutex::Autolock lock(mEventLock);
+    if (mListener != NULL){
+        mListener->asBinder()->unlinkToDeath(this);
+    }
+    if (listener != NULL) {
+        listener->asBinder()->linkToDeath(this);
+    }
     mListener = listener;
     return NO_ERROR;
 }
@@ -576,4 +582,12 @@
     return mPlugin->verify(sessionId, keyId, message, signature, match);
 }
 
+void Drm::binderDied(const wp<IBinder> &the_late_who)
+{
+    delete mPlugin;
+    mPlugin = NULL;
+    closeFactory();
+    mListener.clear();
+}
+
 }  // namespace android
diff --git a/media/libmediaplayerservice/Drm.h b/media/libmediaplayerservice/Drm.h
index 3da8ad4..3f460f1 100644
--- a/media/libmediaplayerservice/Drm.h
+++ b/media/libmediaplayerservice/Drm.h
@@ -29,7 +29,9 @@
 struct DrmFactory;
 struct DrmPlugin;
 
-struct Drm : public BnDrm, public DrmPluginListener {
+struct Drm : public BnDrm,
+             public IBinder::DeathRecipient,
+             public DrmPluginListener {
     Drm();
     virtual ~Drm();
 
@@ -115,6 +117,8 @@
                            Vector<uint8_t> const *sessionId,
                            Vector<uint8_t> const *data);
 
+    virtual void binderDied(const wp<IBinder> &the_late_who);
+
 private:
     mutable Mutex mLock;
 
diff --git a/media/libmediaplayerservice/MediaPlayerService.h b/media/libmediaplayerservice/MediaPlayerService.h
index 1f8bcc7..f7076cc 100644
--- a/media/libmediaplayerservice/MediaPlayerService.h
+++ b/media/libmediaplayerservice/MediaPlayerService.h
@@ -20,15 +20,12 @@
 
 #include <arpa/inet.h>
 
-#include <utils/Log.h>
 #include <utils/threads.h>
-#include <utils/List.h>
 #include <utils/Errors.h>
 #include <utils/KeyedVector.h>
 #include <utils/String8.h>
 #include <utils/Vector.h>
 
-#include <media/IMediaPlayerService.h>
 #include <media/MediaPlayerInterface.h>
 #include <media/Metadata.h>
 #include <media/stagefright/foundation/ABase.h>
diff --git a/media/libmediaplayerservice/nuplayer/RTSPSource.cpp b/media/libmediaplayerservice/nuplayer/RTSPSource.cpp
index 50ebf9c..3385a19 100644
--- a/media/libmediaplayerservice/nuplayer/RTSPSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/RTSPSource.cpp
@@ -634,6 +634,10 @@
 }
 
 void NuPlayer::RTSPSource::onDisconnected(const sp<AMessage> &msg) {
+    if (mState == DISCONNECTED) {
+        return;
+    }
+
     status_t err;
     CHECK(msg->findInt32("result", &err));
     CHECK_NE(err, (status_t)OK);
diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp
index 6c197e2..b505518 100644
--- a/media/libstagefright/AwesomePlayer.cpp
+++ b/media/libstagefright/AwesomePlayer.cpp
@@ -617,7 +617,7 @@
 bool AwesomePlayer::getCachedDuration_l(int64_t *durationUs, bool *eos) {
     int64_t bitrate;
 
-    if (mCachedSource != NULL && getBitrate(&bitrate)) {
+    if (mCachedSource != NULL && getBitrate(&bitrate) && (bitrate > 0)) {
         status_t finalStatus;
         size_t cachedDataRemaining = mCachedSource->approxDataRemaining(&finalStatus);
         *durationUs = cachedDataRemaining * 8000000ll / bitrate;
diff --git a/media/libstagefright/SurfaceMediaSource.cpp b/media/libstagefright/SurfaceMediaSource.cpp
index 71b6569..305e7e0 100644
--- a/media/libstagefright/SurfaceMediaSource.cpp
+++ b/media/libstagefright/SurfaceMediaSource.cpp
@@ -293,7 +293,7 @@
     // wait here till the frames come in from the client side
     while (mStarted) {
 
-        status_t err = mBufferQueue->acquireBuffer(&item);
+        status_t err = mBufferQueue->acquireBuffer(&item, 0);
         if (err == BufferQueue::NO_BUFFER_AVAILABLE) {
             // wait for a buffer to be queued
             mFrameAvailableCondition.wait(mMutex);
diff --git a/media/libstagefright/chromium_http/support.cpp b/media/libstagefright/chromium_http/support.cpp
index 741cb1d..0a8e3e3 100644
--- a/media/libstagefright/chromium_http/support.cpp
+++ b/media/libstagefright/chromium_http/support.cpp
@@ -150,7 +150,7 @@
 }
 
 net::NetLog::LogLevel SfNetLog::GetLogLevel() const {
-    return LOG_ALL;
+    return LOG_BASIC;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
diff --git a/media/libstagefright/omx/GraphicBufferSource.cpp b/media/libstagefright/omx/GraphicBufferSource.cpp
index b3a8463..b3167b5 100644
--- a/media/libstagefright/omx/GraphicBufferSource.cpp
+++ b/media/libstagefright/omx/GraphicBufferSource.cpp
@@ -251,7 +251,7 @@
     ALOGV("fillCodecBuffer_l: acquiring buffer, avail=%d",
             mNumFramesAvailable);
     BufferQueue::BufferItem item;
-    status_t err = mBufferQueue->acquireBuffer(&item);
+    status_t err = mBufferQueue->acquireBuffer(&item, 0);
     if (err == BufferQueue::NO_BUFFER_AVAILABLE) {
         // shouldn't happen
         ALOGW("fillCodecBuffer_l: frame was not available");
@@ -422,7 +422,7 @@
         ALOGW("onFrameAvailable: EOS is set, ignoring frame");
 
         BufferQueue::BufferItem item;
-        status_t err = mBufferQueue->acquireBuffer(&item);
+        status_t err = mBufferQueue->acquireBuffer(&item, 0);
         if (err == OK) {
             mBufferQueue->releaseBuffer(item.mBuf, item.mFrameNumber,
                     EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, item.mFence);
diff --git a/media/libstagefright/rtsp/MyHandler.h b/media/libstagefright/rtsp/MyHandler.h
index e067e20..e51d9e3 100644
--- a/media/libstagefright/rtsp/MyHandler.h
+++ b/media/libstagefright/rtsp/MyHandler.h
@@ -127,7 +127,8 @@
           mKeepAliveTimeoutUs(kDefaultKeepAliveTimeoutUs),
           mKeepAliveGeneration(0),
           mPausing(false),
-          mPauseGeneration(0) {
+          mPauseGeneration(0),
+          mPlayResponseParsed(false) {
         mNetLooper->setName("rtsp net");
         mNetLooper->start(false /* runOnCallingThread */,
                           false /* canCallJava */,
@@ -1371,6 +1372,7 @@
     }
 
     void parsePlayResponse(const sp<ARTSPResponse> &response) {
+        mPlayResponseParsed = true;
         if (mTracks.size() == 0) {
             ALOGV("parsePlayResponse: late packets ignored.");
             return;
@@ -1524,6 +1526,8 @@
 
     Vector<TrackInfo> mTracks;
 
+    bool mPlayResponseParsed;
+
     void setupTrack(size_t index) {
         sp<APacketSource> source =
             new APacketSource(mSessionDesc, index);
@@ -1728,6 +1732,13 @@
             int32_t trackIndex, const sp<ABuffer> &accessUnit) {
         ALOGV("onAccessUnitComplete track %d", trackIndex);
 
+        if(!mPlayResponseParsed){
+            ALOGI("play response is not parsed, storing accessunit");
+            TrackInfo *track = &mTracks.editItemAt(trackIndex);
+            track->mPackets.push_back(accessUnit);
+            return;
+        }
+
         if (mFirstAccessUnit) {
             sp<AMessage> msg = mNotify->dup();
             msg->setInt32("what", kWhatConnected);
diff --git a/media/libstagefright/wifi-display/sink/DirectRenderer.h b/media/libstagefright/wifi-display/sink/DirectRenderer.h
index c5a4a83..1e7dc34 100644
--- a/media/libstagefright/wifi-display/sink/DirectRenderer.h
+++ b/media/libstagefright/wifi-display/sink/DirectRenderer.h
@@ -23,9 +23,7 @@
 namespace android {
 
 struct ABuffer;
-struct AudioTrack;
 struct IGraphicBufferProducer;
-struct MediaCodec;
 
 // Renders audio and video data queued by calls to "queueAccessUnit".
 struct DirectRenderer : public AHandler {
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index c8e8aba..17a69fa 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -38,9 +38,6 @@
 #include <cutils/properties.h>
 #include <cutils/compiler.h>
 
-//#include <private/media/AudioTrackShared.h>
-//#include <private/media/AudioEffectShared.h>
-
 #include <system/audio.h>
 #include <hardware/audio.h>
 
@@ -58,12 +55,12 @@
 #include <powermanager/PowerManager.h>
 
 #include <common_time/cc_helper.h>
-//#include <common_time/local_clock.h>
 
 #include <media/IMediaLogService.h>
 
 #include <media/nbaio/Pipe.h>
 #include <media/nbaio/PipeReader.h>
+#include <media/AudioParameter.h>
 
 // ----------------------------------------------------------------------------
 
diff --git a/services/audioflinger/AudioPolicyService.cpp b/services/audioflinger/AudioPolicyService.cpp
index fd4431c..eacecf0 100644
--- a/services/audioflinger/AudioPolicyService.cpp
+++ b/services/audioflinger/AudioPolicyService.cpp
@@ -40,6 +40,7 @@
 #include <system/audio_policy.h>
 #include <hardware/audio_policy.h>
 #include <audio_effects/audio_effects_conf.h>
+#include <media/AudioParameter.h>
 
 namespace android {
 
diff --git a/services/audioflinger/ISchedulingPolicyService.cpp b/services/audioflinger/ISchedulingPolicyService.cpp
index 0079968..f55bc02 100644
--- a/services/audioflinger/ISchedulingPolicyService.cpp
+++ b/services/audioflinger/ISchedulingPolicyService.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#define LOG_TAG "SchedulingPolicyService"
+#define LOG_TAG "ISchedulingPolicyService"
 //#define LOG_NDEBUG 0
 
 #include <binder/Parcel.h>
@@ -45,9 +45,17 @@
         data.writeInt32(tid);
         data.writeInt32(prio);
         uint32_t flags = asynchronous ? IBinder::FLAG_ONEWAY : 0;
-        remote()->transact(REQUEST_PRIORITY_TRANSACTION, data, &reply, flags);
-        // fail on exception
-        if (reply.readExceptionCode() != 0) return -1;
+        status_t status = remote()->transact(REQUEST_PRIORITY_TRANSACTION, data, &reply, flags);
+        if (status != NO_ERROR) {
+            return status;
+        }
+        if (asynchronous) {
+            return NO_ERROR;
+        }
+        // fail on exception: force binder reconnection
+        if (reply.readExceptionCode() != 0) {
+            return DEAD_OBJECT;
+        }
         return reply.readInt32();
     }
 };
diff --git a/services/audioflinger/SchedulingPolicyService.cpp b/services/audioflinger/SchedulingPolicyService.cpp
index 36e62e9..70a3f1a 100644
--- a/services/audioflinger/SchedulingPolicyService.cpp
+++ b/services/audioflinger/SchedulingPolicyService.cpp
@@ -14,6 +14,9 @@
  * limitations under the License.
  */
 
+#define LOG_TAG "SchedulingPolicyService"
+//#define LOG_NDEBUG 0
+
 #include <binder/IServiceManager.h>
 #include <utils/Mutex.h>
 #include "ISchedulingPolicyService.h"
@@ -28,25 +31,32 @@
 int requestPriority(pid_t pid, pid_t tid, int32_t prio, bool asynchronous)
 {
     // FIXME merge duplicated code related to service lookup, caching, and error recovery
-    sp<ISchedulingPolicyService> sps;
+    int ret;
     for (;;) {
         sMutex.lock();
-        sps = sSchedulingPolicyService;
+        sp<ISchedulingPolicyService> sps = sSchedulingPolicyService;
         sMutex.unlock();
-        if (sps != 0) {
-            break;
-        }
-        sp<IBinder> binder = defaultServiceManager()->checkService(_scheduling_policy);
-        if (binder != 0) {
+        if (sps == 0) {
+            sp<IBinder> binder = defaultServiceManager()->checkService(_scheduling_policy);
+            if (binder == 0) {
+                sleep(1);
+                continue;
+            }
             sps = interface_cast<ISchedulingPolicyService>(binder);
             sMutex.lock();
             sSchedulingPolicyService = sps;
             sMutex.unlock();
+        }
+        ret = sps->requestPriority(pid, tid, prio, asynchronous);
+        if (ret != DEAD_OBJECT) {
             break;
         }
-        sleep(1);
+        ALOGW("SchedulingPolicyService died");
+        sMutex.lock();
+        sSchedulingPolicyService.clear();
+        sMutex.unlock();
     }
-    return sps->requestPriority(pid, tid, prio, asynchronous);
+    return ret;
 }
 
 }   // namespace android
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index 0773534..ef109af 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -25,6 +25,7 @@
 #include <sys/stat.h>
 #include <cutils/properties.h>
 #include <cutils/compiler.h>
+#include <media/AudioParameter.h>
 #include <utils/Log.h>
 #include <utils/Trace.h>
 
diff --git a/services/camera/libcameraservice/Camera2Client.cpp b/services/camera/libcameraservice/Camera2Client.cpp
index 96bde90..203d7c0 100644
--- a/services/camera/libcameraservice/Camera2Client.cpp
+++ b/services/camera/libcameraservice/Camera2Client.cpp
@@ -600,6 +600,7 @@
         case Parameters::STOPPED:
         case Parameters::WAITING_FOR_PREVIEW_WINDOW:
         case Parameters::PREVIEW:
+        case Parameters::STILL_CAPTURE:
             // OK
             break;
         default:
diff --git a/services/camera/libcameraservice/camera2/StreamingProcessor.cpp b/services/camera/libcameraservice/camera2/StreamingProcessor.cpp
index fed05a6..35eb433 100644
--- a/services/camera/libcameraservice/camera2/StreamingProcessor.cpp
+++ b/services/camera/libcameraservice/camera2/StreamingProcessor.cpp
@@ -17,6 +17,13 @@
 #define LOG_TAG "Camera2-StreamingProcessor"
 #define ATRACE_TAG ATRACE_TAG_CAMERA
 //#define LOG_NDEBUG 0
+//#define LOG_NNDEBUG 0 // Per-frame verbose logging
+
+#ifdef LOG_NNDEBUG
+#define ALOGVV(...) ALOGV(__VA_ARGS__)
+#else
+#define ALOGVV(...) ((void)0)
+#endif
 
 #include <utils/Log.h>
 #include <utils/Trace.h>
@@ -42,7 +49,8 @@
         mRecordingRequestId(Camera2Client::kRecordingRequestIdStart),
         mRecordingStreamId(NO_STREAM),
         mRecordingFrameAvailable(false),
-        mRecordingHeapCount(kDefaultRecordingHeapCount)
+        mRecordingHeapCount(kDefaultRecordingHeapCount),
+        mRecordingHeapFree(kDefaultRecordingHeapCount)
 {
 }
 
@@ -215,22 +223,39 @@
 
 status_t StreamingProcessor::setRecordingBufferCount(size_t count) {
     ATRACE_CALL();
-    // 32 is the current upper limit on the video buffer count for BufferQueue
-    if (count > 32) {
-        ALOGE("%s: Camera %d: Error setting %d as video buffer count value",
-                __FUNCTION__, mId, count);
+    // Make sure we can support this many buffer slots
+    if (count > BufferQueue::NUM_BUFFER_SLOTS) {
+        ALOGE("%s: Camera %d: Too many recording buffers requested: %d, max %d",
+                __FUNCTION__, mId, count, BufferQueue::NUM_BUFFER_SLOTS);
         return BAD_VALUE;
     }
 
     Mutex::Autolock m(mMutex);
 
-    // Need to reallocate memory for heap
+    ALOGV("%s: Camera %d: New recording buffer count from encoder: %d",
+            __FUNCTION__, mId, count);
+
+    // Need to re-size consumer and heap
     if (mRecordingHeapCount != count) {
-        if  (mRecordingHeap != 0) {
+        ALOGV("%s: Camera %d: Resetting recording heap and consumer",
+            __FUNCTION__, mId);
+
+        if (isStreamActive(mActiveStreamIds, mRecordingStreamId)) {
+            ALOGE("%s: Camera %d: Setting recording buffer count when "
+                    "recording stream is already active!", __FUNCTION__,
+                    mId);
+            return INVALID_OPERATION;
+        }
+
+        releaseAllRecordingFramesLocked();
+
+        if (mRecordingHeap != 0) {
             mRecordingHeap.clear();
-            mRecordingHeap = NULL;
         }
         mRecordingHeapCount = count;
+        mRecordingHeapFree = count;
+
+        mRecordingConsumer.clear();
     }
 
     return OK;
@@ -287,7 +312,10 @@
         return INVALID_OPERATION;
     }
 
+    bool newConsumer = false;
     if (mRecordingConsumer == 0) {
+        ALOGV("%s: Camera %d: Creating recording consumer with %d + 1 "
+                "consumer-side buffers", __FUNCTION__, mId, mRecordingHeapCount);
         // Create CPU buffer queue endpoint. We need one more buffer here so that we can
         // always acquire and free a buffer when the heap is full; otherwise the consumer
         // will have buffers in flight we'll never clear out.
@@ -299,6 +327,7 @@
         mRecordingConsumer->setName(String8("Camera2-RecordingConsumer"));
         mRecordingWindow = new Surface(
             mRecordingConsumer->getProducerInterface());
+        newConsumer = true;
         // Allocate memory later, since we don't know buffer size until receipt
     }
 
@@ -314,7 +343,7 @@
             return res;
         }
         if (currentWidth != (uint32_t)params.videoWidth ||
-                currentHeight != (uint32_t)params.videoHeight) {
+                currentHeight != (uint32_t)params.videoHeight || newConsumer) {
             // TODO: Should wait to be sure previous recording has finished
             res = device->deleteStream(mRecordingStreamId);
 
@@ -400,6 +429,17 @@
 
     Mutex::Autolock m(mMutex);
 
+    // If a recording stream is being started up, free up any
+    // outstanding buffers left from the previous recording session.
+    // There should never be any, so if there are, warn about it.
+    if (isStreamActive(outputStreams, mRecordingStreamId)) {
+        releaseAllRecordingFramesLocked();
+    }
+
+    ALOGV("%s: Camera %d: %s started, recording heap has %d free of %d",
+            __FUNCTION__, mId, (type == PREVIEW) ? "preview" : "recording",
+            mRecordingHeapFree, mRecordingHeapCount);
+
     CameraMetadata &request = (type == PREVIEW) ?
             mPreviewRequest : mRecordingRequest;
 
@@ -428,7 +468,7 @@
     }
     mActiveRequest = type;
     mPaused = false;
-
+    mActiveStreamIds = outputStreams;
     return OK;
 }
 
@@ -500,6 +540,7 @@
     }
 
     mActiveRequest = NONE;
+    mActiveStreamIds.clear();
     mPaused = false;
 
     return OK;
@@ -576,7 +617,7 @@
     if (client == 0) {
         // Discard frames during shutdown
         BufferItemConsumer::BufferItem imgBuffer;
-        res = mRecordingConsumer->acquireBuffer(&imgBuffer);
+        res = mRecordingConsumer->acquireBuffer(&imgBuffer, 0);
         if (res != OK) {
             if (res != BufferItemConsumer::NO_BUFFER_AVAILABLE) {
                 ALOGE("%s: Camera %d: Can't acquire recording buffer: %s (%d)",
@@ -594,7 +635,7 @@
         SharedParameters::Lock l(client->getParameters());
         Mutex::Autolock m(mMutex);
         BufferItemConsumer::BufferItem imgBuffer;
-        res = mRecordingConsumer->acquireBuffer(&imgBuffer);
+        res = mRecordingConsumer->acquireBuffer(&imgBuffer, 0);
         if (res != OK) {
             if (res != BufferItemConsumer::NO_BUFFER_AVAILABLE) {
                 ALOGE("%s: Camera %d: Can't acquire recording buffer: %s (%d)",
@@ -605,7 +646,7 @@
         timestamp = imgBuffer.mTimestamp;
 
         mRecordingFrameCount++;
-        ALOGV("OnRecordingFrame: Frame %d", mRecordingFrameCount);
+        ALOGVV("OnRecordingFrame: Frame %d", mRecordingFrameCount);
 
         if (l.mParameters.state != Parameters::RECORD &&
                 l.mParameters.state != Parameters::VIDEO_SNAPSHOT) {
@@ -656,7 +697,7 @@
         mRecordingHeapHead = (mRecordingHeapHead + 1) % mRecordingHeapCount;
         mRecordingHeapFree--;
 
-        ALOGV("%s: Camera %d: Timestamp %lld",
+        ALOGVV("%s: Camera %d: Timestamp %lld",
                 __FUNCTION__, mId, timestamp);
 
         ssize_t offset;
@@ -669,7 +710,7 @@
         uint32_t type = kMetadataBufferTypeGrallocSource;
         *((uint32_t*)data) = type;
         *((buffer_handle_t*)(data + 4)) = imgBuffer.mGraphicBuffer->handle;
-        ALOGV("%s: Camera %d: Sending out buffer_handle_t %p",
+        ALOGVV("%s: Camera %d: Sending out buffer_handle_t %p",
                 __FUNCTION__, mId,
                 imgBuffer.mGraphicBuffer->handle);
         mRecordingBuffers.replaceAt(imgBuffer, heapIdx);
@@ -682,7 +723,10 @@
         l.mRemoteCallback->dataCallbackTimestamp(timestamp,
                 CAMERA_MSG_VIDEO_FRAME,
                 recordingHeap->mBuffers[heapIdx]);
+    } else {
+        ALOGW("%s: Camera %d: Remote callback gone", __FUNCTION__, mId);
     }
+
     return OK;
 }
 
@@ -730,7 +774,7 @@
         return;
     }
 
-    ALOGV("%s: Camera %d: Freeing buffer_handle_t %p", __FUNCTION__,
+    ALOGVV("%s: Camera %d: Freeing buffer_handle_t %p", __FUNCTION__,
             mId, imgHandle);
 
     res = mRecordingConsumer->releaseBuffer(mRecordingBuffers[itemIndex]);
@@ -743,6 +787,58 @@
     mRecordingBuffers.replaceAt(itemIndex);
 
     mRecordingHeapFree++;
+    ALOGV_IF(mRecordingHeapFree == mRecordingHeapCount,
+            "%s: Camera %d: All %d recording buffers returned",
+            __FUNCTION__, mId, mRecordingHeapCount);
+}
+
+void StreamingProcessor::releaseAllRecordingFramesLocked() {
+    ATRACE_CALL();
+    status_t res;
+
+    if (mRecordingConsumer == 0) {
+        return;
+    }
+
+    ALOGV("%s: Camera %d: Releasing all recording buffers", __FUNCTION__,
+            mId);
+
+    size_t releasedCount = 0;
+    for (size_t itemIndex = 0; itemIndex < mRecordingBuffers.size(); itemIndex++) {
+        const BufferItemConsumer::BufferItem item =
+                mRecordingBuffers[itemIndex];
+        if (item.mBuf != BufferItemConsumer::INVALID_BUFFER_SLOT) {
+            res = mRecordingConsumer->releaseBuffer(mRecordingBuffers[itemIndex]);
+            if (res != OK) {
+                ALOGE("%s: Camera %d: Unable to free recording frame "
+                        "(buffer_handle_t: %p): %s (%d)", __FUNCTION__,
+                        mId, item.mGraphicBuffer->handle, strerror(-res), res);
+            }
+            mRecordingBuffers.replaceAt(itemIndex);
+            releasedCount++;
+        }
+    }
+
+    if (releasedCount > 0) {
+        ALOGW("%s: Camera %d: Force-freed %d outstanding buffers "
+                "from previous recording session", __FUNCTION__, mId, releasedCount);
+        ALOGE_IF(releasedCount != mRecordingHeapCount - mRecordingHeapFree,
+            "%s: Camera %d: Force-freed %d buffers, but expected %d",
+            __FUNCTION__, mId, releasedCount, mRecordingHeapCount - mRecordingHeapFree);
+    }
+
+    mRecordingHeapHead = 0;
+    mRecordingHeapFree = mRecordingHeapCount;
+}
+
+bool StreamingProcessor::isStreamActive(const Vector<uint8_t> &streams,
+        uint8_t recordingStreamId) {
+    for (size_t i = 0; i < streams.size(); i++) {
+        if (streams[i] == recordingStreamId) {
+            return true;
+        }
+    }
+    return false;
 }
 
 
diff --git a/services/camera/libcameraservice/camera2/StreamingProcessor.h b/services/camera/libcameraservice/camera2/StreamingProcessor.h
index 9f71fa0..3ec2df7 100644
--- a/services/camera/libcameraservice/camera2/StreamingProcessor.h
+++ b/services/camera/libcameraservice/camera2/StreamingProcessor.h
@@ -97,6 +97,8 @@
     StreamType mActiveRequest;
     bool mPaused;
 
+    Vector<uint8_t> mActiveStreamIds;
+
     // Preview-related members
     int32_t mPreviewRequestId;
     int mPreviewStreamId;
@@ -125,6 +127,13 @@
     virtual bool threadLoop();
 
     status_t processRecordingFrame();
+
+    // Unilaterally free any buffers still outstanding to stagefright
+    void releaseAllRecordingFramesLocked();
+
+    // Determine if the specified stream is currently in use
+    static bool isStreamActive(const Vector<uint8_t> &streams,
+            uint8_t recordingStreamId);
 };
 
 
diff --git a/services/camera/libcameraservice/camera2/ZslProcessor.cpp b/services/camera/libcameraservice/camera2/ZslProcessor.cpp
index 94059cd..8af8276 100644
--- a/services/camera/libcameraservice/camera2/ZslProcessor.cpp
+++ b/services/camera/libcameraservice/camera2/ZslProcessor.cpp
@@ -426,7 +426,7 @@
     }
     ALOGVV("Trying to get next buffer");
     BufferItemConsumer::BufferItem item;
-    res = zslConsumer->acquireBuffer(&item);
+    res = zslConsumer->acquireBuffer(&item, 0);
     if (res != OK) {
         if (res != BufferItemConsumer::NO_BUFFER_AVAILABLE) {
             ALOGE("%s: Camera %d: Error receiving ZSL image buffer: "
diff --git a/services/camera/libcameraservice/gui/RingBufferConsumer.cpp b/services/camera/libcameraservice/gui/RingBufferConsumer.cpp
index dfa1066..7625735 100644
--- a/services/camera/libcameraservice/gui/RingBufferConsumer.cpp
+++ b/services/camera/libcameraservice/gui/RingBufferConsumer.cpp
@@ -284,7 +284,7 @@
         /**
          * Acquire new frame
          */
-        err = acquireBufferLocked(&item);
+        err = acquireBufferLocked(&item, 0);
         if (err != OK) {
             if (err != NO_BUFFER_AVAILABLE) {
                 BI_LOGE("Error acquiring buffer: %s (%d)", strerror(err), err);