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);