diff options
49 files changed, 872 insertions, 158 deletions
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 @@ void CameraParameters::set(const char *key, const char *value) return; } - if (strchr(value, '=') || strchr(key, ';')) { + if (strchr(value, '=') || strchr(value, ';')) { //XXX ALOGE("Value \"%s\"contains invalid character (= or ;)", value); return; } diff --git a/camera/ProCamera.cpp b/camera/ProCamera.cpp index fec5461..190402e 100644 --- a/camera/ProCamera.cpp +++ b/camera/ProCamera.cpp @@ -247,7 +247,8 @@ status_t ProCamera::createStreamCpu(int width, int height, int format, sp <IProCameraUser> c = mCamera; if (c == 0) return NO_INIT; - sp<CpuConsumer> cc = new CpuConsumer(heapCount, synchronousMode); + sp<BufferQueue> bq = new BufferQueue(); + sp<CpuConsumer> cc = new CpuConsumer(bq, heapCount, synchronousMode); cc->setName(String8("ProCamera::mCpuConsumer")); sp<Surface> stc = new Surface( diff --git a/camera/photography/ICameraDeviceUser.cpp b/camera/photography/ICameraDeviceUser.cpp index 0515bd7..325f94d 100644 --- a/camera/photography/ICameraDeviceUser.cpp +++ b/camera/photography/ICameraDeviceUser.cpp @@ -151,21 +151,22 @@ public: } - virtual status_t getCameraInfo(int cameraId, camera_metadata** info) + virtual status_t getCameraInfo(CameraMetadata* info) { Parcel data, reply; data.writeInterfaceToken(ICameraDeviceUser::getInterfaceDescriptor()); - data.writeInt32(cameraId); remote()->transact(GET_CAMERA_INFO, data, &reply); - reply.readExceptionCode(); status_t result = reply.readInt32(); + CameraMetadata out; if (reply.readInt32() != 0) { - CameraMetadata::readFromParcel(reply, /*out*/info); - } else if (info) { - *info = NULL; + out.readFromParcel(&reply); + } + + if (info != NULL) { + info->swap(out); } return result; @@ -273,6 +274,7 @@ status_t BnCameraDeviceUser::onTransact( reply->writeNoException(); reply->writeInt32(ret); + // out-variables are after exception and return value reply->writeInt32(1); // to mark presence of metadata object request.writeToParcel(const_cast<Parcel*>(reply)); @@ -281,19 +283,16 @@ status_t BnCameraDeviceUser::onTransact( case GET_CAMERA_INFO: { CHECK_INTERFACE(ICameraDeviceUser, data, reply); - int cameraId = data.readInt32(); - - camera_metadata_t* info = NULL; + CameraMetadata info; status_t ret; - ret = getCameraInfo(cameraId, &info); - - reply->writeInt32(1); // to mark presence of metadata object - CameraMetadata::writeToParcel(*reply, info); + ret = getCameraInfo(&info); reply->writeNoException(); reply->writeInt32(ret); - free_camera_metadata(info); + // out-variables are after exception and return value + reply->writeInt32(1); // to mark presence of metadata object + info.writeToParcel(reply); return NO_ERROR; } break; diff --git a/cmds/stagefright/stagefright.cpp b/cmds/stagefright/stagefright.cpp index f8fc8ed..529b96c 100644 --- a/cmds/stagefright/stagefright.cpp +++ b/cmds/stagefright/stagefright.cpp @@ -937,7 +937,8 @@ int main(int argc, char **argv) { } else { CHECK(useSurfaceTexAlloc); - sp<GLConsumer> texture = new GLConsumer(0 /* tex */); + sp<BufferQueue> bq = new BufferQueue(); + sp<GLConsumer> texture = new GLConsumer(bq, 0 /* tex */); gSurface = new Surface(texture->getBufferQueue()); } diff --git a/include/camera/photography/ICameraDeviceUser.h b/include/camera/photography/ICameraDeviceUser.h index 1b8d666..3ea49f4 100644 --- a/include/camera/photography/ICameraDeviceUser.h +++ b/include/camera/photography/ICameraDeviceUser.h @@ -58,9 +58,8 @@ public: /*out*/ CameraMetadata* request) = 0; // Get static camera metadata - virtual status_t getCameraInfo(int cameraId, - /*out*/ - camera_metadata** info) = 0; + virtual status_t getCameraInfo(/*out*/ + CameraMetadata* info) = 0; }; 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/include/private/media/AudioTrackShared.h b/include/private/media/AudioTrackShared.h index b41684a..0592683 100644 --- a/include/private/media/AudioTrackShared.h +++ b/include/private/media/AudioTrackShared.h @@ -168,6 +168,7 @@ protected: const bool mIsOut; // true for AudioTrack, false for AudioRecord const bool mClientInServer; // true for OutputTrack, false for AudioTrack & AudioRecord bool mIsShutdown; // latch set to true when shared memory corruption detected + size_t mUnreleased; // unreleased frames remaining from most recent obtainBuffer }; // ---------------------------------------------------------------------------- @@ -213,7 +214,7 @@ public: // DEAD_OBJECT Server has died or invalidated, caller should destroy this proxy and re-create. // -EINTR Call has been interrupted. Look around to see why, and then perhaps try again. // NO_INIT Shared memory is corrupt. - // BAD_VALUE On entry buffer == NULL or buffer->mFrameCount == 0. + // Assertion failure on entry, if buffer == NULL or buffer->mFrameCount == 0. status_t obtainBuffer(Buffer* buffer, const struct timespec *requested = NULL, struct timespec *elapsed = NULL); @@ -372,7 +373,6 @@ public: virtual void releaseBuffer(Buffer* buffer); protected: - size_t mUnreleased; // unreleased frames remaining from most recent obtainBuffer() size_t mAvailToClient; // estimated frames available to client prior to releaseBuffer() private: int32_t mFlush; // our copy of cblk->u.mStreaming.mFlush, for streaming output only diff --git a/libvideoeditor/lvpp/NativeWindowRenderer.cpp b/libvideoeditor/lvpp/NativeWindowRenderer.cpp index 702900b..84a8e15 100755 --- a/libvideoeditor/lvpp/NativeWindowRenderer.cpp +++ b/libvideoeditor/lvpp/NativeWindowRenderer.cpp @@ -568,7 +568,8 @@ void NativeWindowRenderer::destroyRenderInput(RenderInput* input) { RenderInput::RenderInput(NativeWindowRenderer* renderer, GLuint textureId) : mRenderer(renderer) , mTextureId(textureId) { - mST = new GLConsumer(mTextureId); + sp<BufferQueue> bq = new BufferQueue(); + mST = new GLConsumer(bq, mTextureId); mSTC = new Surface(mST->getBufferQueue()); native_window_connect(mSTC.get(), NATIVE_WINDOW_API_MEDIA); } 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 fb19357..5de46bb 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 @@ nsecs_t AudioTrack::processAudioBuffer(const sp<AudioTrackThread>& thread) 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 5f8f292..55bf175 100644 --- a/media/libmedia/AudioTrackShared.cpp +++ b/media/libmedia/AudioTrackShared.cpp @@ -38,7 +38,7 @@ Proxy::Proxy(audio_track_cblk_t* cblk, void *buffers, size_t frameCount, size_t bool isOut, bool clientInServer) : mCblk(cblk), mBuffers(buffers), mFrameCount(frameCount), mFrameSize(frameSize), mFrameCountP2(roundup(frameCount)), mIsOut(isOut), mClientInServer(clientInServer), - mIsShutdown(false) + mIsShutdown(false), mUnreleased(0) { } @@ -64,10 +64,7 @@ const struct timespec ClientProxy::kNonBlocking = {0 /*tv_sec*/, 0 /*tv_nsec*/}; status_t ClientProxy::obtainBuffer(Buffer* buffer, const struct timespec *requested, struct timespec *elapsed) { - if (buffer == NULL || buffer->mFrameCount == 0) { - ALOGE("%s BAD_VALUE", __func__); - return BAD_VALUE; - } + LOG_ALWAYS_FATAL_IF(buffer == NULL || buffer->mFrameCount == 0); struct timespec total; // total elapsed time spent waiting total.tv_sec = 0; total.tv_nsec = 0; @@ -164,7 +161,7 @@ status_t ClientProxy::obtainBuffer(Buffer* buffer, const struct timespec *reques buffer->mRaw = part1 > 0 ? &((char *) mBuffers)[(mIsOut ? rear : front) * mFrameSize] : NULL; buffer->mNonContig = avail - part1; - // mUnreleased = part1; + mUnreleased = part1; status = NO_ERROR; break; } @@ -238,6 +235,7 @@ status_t ClientProxy::obtainBuffer(Buffer* buffer, const struct timespec *reques case -EWOULDBLOCK: // benign race condition with server case -EINTR: // wait was interrupted by signal or other spurious wakeup case -ETIMEDOUT: // time-out expired + // FIXME these error/non-0 status are being dropped break; default: ALOGE("%s unexpected error %d", __func__, ret); @@ -252,6 +250,7 @@ end: buffer->mFrameCount = 0; buffer->mRaw = NULL; buffer->mNonContig = 0; + mUnreleased = 0; } if (elapsed != NULL) { *elapsed = total; @@ -268,14 +267,17 @@ end: void ClientProxy::releaseBuffer(Buffer* buffer) { + LOG_ALWAYS_FATAL_IF(buffer == NULL); size_t stepCount = buffer->mFrameCount; - // FIXME - // check mUnreleased - // verify that stepCount <= frameCount returned by the last obtainBuffer() - // verify stepCount not > total frame count of pipe - if (stepCount == 0) { + if (stepCount == 0 || mIsShutdown) { + // prevent accidental re-use of buffer + buffer->mFrameCount = 0; + buffer->mRaw = NULL; + buffer->mNonContig = 0; return; } + LOG_ALWAYS_FATAL_IF(!(stepCount <= mUnreleased && mUnreleased <= mFrameCount)); + mUnreleased -= stepCount; audio_track_cblk_t* cblk = mCblk; // Both of these barriers are required if (mIsOut) { @@ -362,20 +364,18 @@ size_t StaticAudioTrackClientProxy::getBufferPosition() ServerProxy::ServerProxy(audio_track_cblk_t* cblk, void *buffers, size_t frameCount, size_t frameSize, bool isOut, bool clientInServer) - : Proxy(cblk, buffers, frameCount, frameSize, isOut, clientInServer), mUnreleased(0), + : Proxy(cblk, buffers, frameCount, frameSize, isOut, clientInServer), mAvailToClient(0), mFlush(0), mDeferWake(false) { } status_t ServerProxy::obtainBuffer(Buffer* buffer) { + LOG_ALWAYS_FATAL_IF(buffer == NULL || buffer->mFrameCount == 0); if (mIsShutdown) { - buffer->mFrameCount = 0; - buffer->mRaw = NULL; - buffer->mNonContig = 0; - mUnreleased = 0; - return NO_INIT; + goto no_init; } + { audio_track_cblk_t* cblk = mCblk; // compute number of frames available to write (AudioTrack) or read (AudioRecord), // or use previous cached value from framesReady(), with added barrier if it omits. @@ -388,6 +388,8 @@ status_t ServerProxy::obtainBuffer(Buffer* buffer) 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; } @@ -402,11 +404,7 @@ status_t ServerProxy::obtainBuffer(Buffer* buffer) mIsShutdown = true; } if (mIsShutdown) { - buffer->mFrameCount = 0; - buffer->mRaw = NULL; - buffer->mNonContig = 0; - mUnreleased = 0; - return NO_INIT; + goto no_init; } // don't allow filling pipe beyond the nominal size size_t availToServer; @@ -443,23 +441,27 @@ status_t ServerProxy::obtainBuffer(Buffer* buffer) // FIXME need to test for recording mDeferWake = part1 < ask && availToServer >= ask; return part1 > 0 ? NO_ERROR : WOULD_BLOCK; + } +no_init: + buffer->mFrameCount = 0; + buffer->mRaw = NULL; + buffer->mNonContig = 0; + mUnreleased = 0; + return NO_INIT; } void ServerProxy::releaseBuffer(Buffer* buffer) { - if (mIsShutdown) { - buffer->mFrameCount = 0; - buffer->mRaw = NULL; - buffer->mNonContig = 0; - return; - } + LOG_ALWAYS_FATAL_IF(buffer == NULL); size_t stepCount = buffer->mFrameCount; - LOG_ALWAYS_FATAL_IF(stepCount > mUnreleased); - if (stepCount == 0) { + if (stepCount == 0 || mIsShutdown) { + // prevent accidental re-use of buffer + buffer->mFrameCount = 0; buffer->mRaw = NULL; buffer->mNonContig = 0; return; } + LOG_ALWAYS_FATAL_IF(!(stepCount <= mUnreleased && mUnreleased <= mFrameCount)); mUnreleased -= stepCount; audio_track_cblk_t* cblk = mCblk; if (mIsOut) { @@ -637,8 +639,9 @@ status_t StaticAudioTrackServerProxy::obtainBuffer(Buffer* buffer) void StaticAudioTrackServerProxy::releaseBuffer(Buffer* buffer) { size_t stepCount = buffer->mFrameCount; - LOG_ALWAYS_FATAL_IF(stepCount > mUnreleased); + LOG_ALWAYS_FATAL_IF(!(stepCount <= mUnreleased)); if (stepCount == 0) { + // prevent accidental re-use of buffer buffer->mRaw = NULL; buffer->mNonContig = 0; return; 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 @@ public: 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 @@ public: 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 @@ public: 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 @@ public: 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::initCheck() const { 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 @@ status_t Drm::verify(Vector<uint8_t> const &sessionId, 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 @@ namespace android { 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 @@ struct Drm : public BnDrm, public DrmPluginListener { 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::onSDPLoaded(const sp<AMessage> &msg) { } 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::getBitrate(int64_t *bitrate) { 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 @@ status_t SurfaceMediaSource::read( MediaBuffer **buffer, // 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 @@ uint32 SfNetLog::NextID() { } 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 @@ bool GraphicBufferSource::fillCodecBuffer_l() { 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 @@ void GraphicBufferSource::onFrameAvailable() { 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 @@ struct MyHandler : public AHandler { 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 @@ struct MyHandler : public AHandler { } void parsePlayResponse(const sp<ARTSPResponse> &response) { + mPlayResponseParsed = true; if (mTracks.size() == 0) { ALOGV("parsePlayResponse: late packets ignored."); return; @@ -1524,6 +1526,8 @@ private: Vector<TrackInfo> mTracks; + bool mPlayResponseParsed; + void setupTrack(size_t index) { sp<APacketSource> source = new APacketSource(mSessionDesc, index); @@ -1728,6 +1732,13 @@ private: 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 @@ public: 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 @@ static Mutex sMutex; 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 @@ void Camera2Client::setPreviewCallbackFlagL(Parameters ¶ms, int flag) { 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/CallbackProcessor.cpp b/services/camera/libcameraservice/camera2/CallbackProcessor.cpp index aae2504..efbbe57 100644 --- a/services/camera/libcameraservice/camera2/CallbackProcessor.cpp +++ b/services/camera/libcameraservice/camera2/CallbackProcessor.cpp @@ -110,7 +110,8 @@ status_t CallbackProcessor::updateStream(const Parameters ¶ms) { if (!mCallbackToApp && mCallbackConsumer == 0) { // Create CPU buffer queue endpoint, since app hasn't given us one // Make it async to avoid disconnect deadlocks - mCallbackConsumer = new CpuConsumer(kCallbackHeapCount, + sp<BufferQueue> bq = new BufferQueue(); + mCallbackConsumer = new CpuConsumer(bq, kCallbackHeapCount, /*synchronized*/ false); mCallbackConsumer->setFrameAvailableListener(this); mCallbackConsumer->setName(String8("Camera2Client::CallbackConsumer")); diff --git a/services/camera/libcameraservice/camera2/JpegProcessor.cpp b/services/camera/libcameraservice/camera2/JpegProcessor.cpp index f0a13ca..1d739cd 100644 --- a/services/camera/libcameraservice/camera2/JpegProcessor.cpp +++ b/services/camera/libcameraservice/camera2/JpegProcessor.cpp @@ -82,7 +82,8 @@ status_t JpegProcessor::updateStream(const Parameters ¶ms) { if (mCaptureConsumer == 0) { // Create CPU buffer queue endpoint - mCaptureConsumer = new CpuConsumer(1); + sp<BufferQueue> bq = new BufferQueue(); + mCaptureConsumer = new CpuConsumer(bq, 1); mCaptureConsumer->setFrameAvailableListener(this); mCaptureConsumer->setName(String8("Camera2Client::CaptureConsumer")); mCaptureWindow = new Surface( diff --git a/services/camera/libcameraservice/camera2/StreamingProcessor.cpp b/services/camera/libcameraservice/camera2/StreamingProcessor.cpp index fed05a6..76fa46c 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 @@ StreamingProcessor::StreamingProcessor(sp<Camera2Client> client): mRecordingRequestId(Camera2Client::kRecordingRequestIdStart), mRecordingStreamId(NO_STREAM), mRecordingFrameAvailable(false), - mRecordingHeapCount(kDefaultRecordingHeapCount) + mRecordingHeapCount(kDefaultRecordingHeapCount), + mRecordingHeapFree(kDefaultRecordingHeapCount) { } @@ -215,22 +223,39 @@ int StreamingProcessor::getPreviewStreamId() const { 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,11 +312,15 @@ status_t StreamingProcessor::updateRecordingStream(const Parameters ¶ms) { 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. - mRecordingConsumer = new BufferItemConsumer( + sp<BufferQueue> bq = new BufferQueue(); + mRecordingConsumer = new BufferItemConsumer(bq, GRALLOC_USAGE_HW_VIDEO_ENCODER, mRecordingHeapCount + 1, true); @@ -299,6 +328,7 @@ status_t StreamingProcessor::updateRecordingStream(const Parameters ¶ms) { 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 +344,7 @@ status_t StreamingProcessor::updateRecordingStream(const Parameters ¶ms) { 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 +430,17 @@ status_t StreamingProcessor::startStream(StreamType type, 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 +469,7 @@ status_t StreamingProcessor::startStream(StreamType type, } mActiveRequest = type; mPaused = false; - + mActiveStreamIds = outputStreams; return OK; } @@ -500,6 +541,7 @@ status_t StreamingProcessor::stopStream() { } mActiveRequest = NONE; + mActiveStreamIds.clear(); mPaused = false; return OK; @@ -576,7 +618,7 @@ status_t StreamingProcessor::processRecordingFrame() { 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 +636,7 @@ status_t StreamingProcessor::processRecordingFrame() { 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 +647,7 @@ status_t StreamingProcessor::processRecordingFrame() { 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 +698,7 @@ status_t StreamingProcessor::processRecordingFrame() { 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 +711,7 @@ status_t StreamingProcessor::processRecordingFrame() { 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 +724,10 @@ status_t StreamingProcessor::processRecordingFrame() { 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 +775,7 @@ void StreamingProcessor::releaseRecordingFrame(const sp<IMemory>& mem) { 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 +788,58 @@ void StreamingProcessor::releaseRecordingFrame(const sp<IMemory>& mem) { 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 @@ class StreamingProcessor: StreamType mActiveRequest; bool mPaused; + Vector<uint8_t> mActiveStreamIds; + // Preview-related members int32_t mPreviewRequestId; int mPreviewStreamId; @@ -125,6 +127,13 @@ class StreamingProcessor: 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..3c575f6 100644 --- a/services/camera/libcameraservice/camera2/ZslProcessor.cpp +++ b/services/camera/libcameraservice/camera2/ZslProcessor.cpp @@ -128,7 +128,8 @@ status_t ZslProcessor::updateStream(const Parameters ¶ms) { if (mZslConsumer == 0) { // Create CPU buffer queue endpoint - mZslConsumer = new BufferItemConsumer( + sp<BufferQueue> bq = new BufferQueue(); + mZslConsumer = new BufferItemConsumer(bq, GRALLOC_USAGE_HW_CAMERA_ZSL, kZslBufferDepth, true); @@ -426,7 +427,7 @@ status_t ZslProcessor::processNewZslBuffer() { } 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/camera3/Camera3InputStream.cpp b/services/camera/libcameraservice/camera3/Camera3InputStream.cpp index 13e9c83..6d9acc3 100644 --- a/services/camera/libcameraservice/camera3/Camera3InputStream.cpp +++ b/services/camera/libcameraservice/camera3/Camera3InputStream.cpp @@ -211,7 +211,8 @@ status_t Camera3InputStream::configureQueueLocked() { mFrameCount = 0; if (mConsumer.get() == 0) { - mConsumer = new BufferItemConsumer(camera3_stream::usage, + sp<BufferQueue> bq = new BufferQueue(); + mConsumer = new BufferItemConsumer(bq, camera3_stream::usage, mTotalBufferCount, /*synchronousMode*/true); mConsumer->setName(String8::format("Camera3-InputStream-%d", mId)); 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 @@ void RingBufferConsumer::onFrameAvailable() { /** * 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); diff --git a/services/camera/libcameraservice/photography/CameraDeviceClient.cpp b/services/camera/libcameraservice/photography/CameraDeviceClient.cpp index bd6b60a..a6a2dc1 100644 --- a/services/camera/libcameraservice/photography/CameraDeviceClient.cpp +++ b/services/camera/libcameraservice/photography/CameraDeviceClient.cpp @@ -391,28 +391,23 @@ status_t CameraDeviceClient::createDefaultRequest(int templateId, return res; } -status_t CameraDeviceClient::getCameraInfo(int cameraId, - /*out*/ - camera_metadata** info) +status_t CameraDeviceClient::getCameraInfo(/*out*/CameraMetadata* info) { ATRACE_CALL(); ALOGV("%s", __FUNCTION__); status_t res = OK; - // TODO: remove cameraId. this should be device-specific info, not static. - if (cameraId != mCameraId) { - return INVALID_OPERATION; - } - if ( (res = checkPid(__FUNCTION__) ) != OK) return res; Mutex::Autolock icl(mBinderSerializationLock); if (!mDevice.get()) return DEAD_OBJECT; - CameraMetadata deviceInfo = mDevice->info(); - *info = deviceInfo.release(); + if (info != NULL) { + *info = mDevice->info(); // static camera metadata + // TODO: merge with device-specific camera metadata + } return res; } diff --git a/services/camera/libcameraservice/photography/CameraDeviceClient.h b/services/camera/libcameraservice/photography/CameraDeviceClient.h index 806aa15..c6c241a 100644 --- a/services/camera/libcameraservice/photography/CameraDeviceClient.h +++ b/services/camera/libcameraservice/photography/CameraDeviceClient.h @@ -85,9 +85,7 @@ public: // Get the static metadata for the camera // -- Caller owns the newly allocated metadata - virtual status_t getCameraInfo(int cameraId, - /*out*/ - camera_metadata** info); + virtual status_t getCameraInfo(/*out*/CameraMetadata* info); /** * Interface used by CameraService |