diff options
31 files changed, 719 insertions, 70 deletions
diff --git a/camera/ICameraService.cpp b/camera/ICameraService.cpp index 7bb24ee..7c9720f 100644 --- a/camera/ICameraService.cpp +++ b/camera/ICameraService.cpp @@ -285,6 +285,7 @@ public: } Parcel data, reply; + data.writeInterfaceToken(ICameraService::getInterfaceDescriptor()); data.writeInt32(cameraId); remote()->transact(BnCameraService::GET_LEGACY_PARAMETERS, data, &reply); @@ -304,6 +305,7 @@ public: virtual status_t supportsCameraApi(int cameraId, int apiVersion) { Parcel data, reply; + data.writeInterfaceToken(ICameraService::getInterfaceDescriptor()); data.writeInt32(cameraId); data.writeInt32(apiVersion); remote()->transact(BnCameraService::SUPPORTS_CAMERA_API, data, &reply); @@ -315,6 +317,7 @@ public: virtual void notifySystemEvent(int32_t eventId, const int32_t* args, size_t len) { Parcel data, reply; + data.writeInterfaceToken(ICameraService::getInterfaceDescriptor()); data.writeInt32(eventId); data.writeInt32Array(len, args); remote()->transact(BnCameraService::NOTIFY_SYSTEM_EVENT, data, &reply, diff --git a/camera/ICameraServiceListener.cpp b/camera/ICameraServiceListener.cpp index 90a8bc2..0010325 100644 --- a/camera/ICameraServiceListener.cpp +++ b/camera/ICameraServiceListener.cpp @@ -45,8 +45,7 @@ public: virtual void onStatusChanged(Status status, int32_t cameraId) { Parcel data, reply; - data.writeInterfaceToken( - ICameraServiceListener::getInterfaceDescriptor()); + data.writeInterfaceToken(ICameraServiceListener::getInterfaceDescriptor()); data.writeInt32(static_cast<int32_t>(status)); data.writeInt32(cameraId); @@ -60,8 +59,7 @@ public: virtual void onTorchStatusChanged(TorchStatus status, const String16 &cameraId) { Parcel data, reply; - data.writeInterfaceToken( - ICameraServiceListener::getInterfaceDescriptor()); + data.writeInterfaceToken(ICameraServiceListener::getInterfaceDescriptor()); data.writeInt32(static_cast<int32_t>(status)); data.writeString16(cameraId); @@ -73,14 +71,12 @@ public: } }; -IMPLEMENT_META_INTERFACE(CameraServiceListener, - "android.hardware.ICameraServiceListener"); +IMPLEMENT_META_INTERFACE(CameraServiceListener, "android.hardware.ICameraServiceListener"); // ---------------------------------------------------------------------- -status_t BnCameraServiceListener::onTransact( - uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) -{ +status_t BnCameraServiceListener::onTransact(uint32_t code, const Parcel& data, Parcel* reply, + uint32_t flags) { switch(code) { case STATUS_CHANGED: { CHECK_INTERFACE(ICameraServiceListener, data, reply); diff --git a/camera/camera2/ICameraDeviceUser.cpp b/camera/camera2/ICameraDeviceUser.cpp index a7549f2..ffe974b 100644 --- a/camera/camera2/ICameraDeviceUser.cpp +++ b/camera/camera2/ICameraDeviceUser.cpp @@ -82,7 +82,7 @@ public: reply.readExceptionCode(); } - virtual status_t submitRequest(sp<CaptureRequest> request, bool repeating, + virtual int submitRequest(sp<CaptureRequest> request, bool repeating, int64_t *lastFrameNumber) { Parcel data, reply; @@ -111,13 +111,13 @@ public: } } - if ((res < NO_ERROR) || (resFrameNumber != NO_ERROR)) { + if (res < 0 || (resFrameNumber != NO_ERROR)) { res = FAILED_TRANSACTION; } return res; } - virtual status_t submitRequestList(List<sp<CaptureRequest> > requestList, bool repeating, + virtual int submitRequestList(List<sp<CaptureRequest> > requestList, bool repeating, int64_t *lastFrameNumber) { Parcel data, reply; @@ -151,7 +151,7 @@ public: resFrameNumber = reply.readInt64(lastFrameNumber); } } - if ((res < NO_ERROR) || (resFrameNumber != NO_ERROR)) { + if (res < 0 || (resFrameNumber != NO_ERROR)) { res = FAILED_TRANSACTION; } return res; diff --git a/camera/camera2/OutputConfiguration.cpp b/camera/camera2/OutputConfiguration.cpp index 24acaa0..20a23e0 100644 --- a/camera/camera2/OutputConfiguration.cpp +++ b/camera/camera2/OutputConfiguration.cpp @@ -65,6 +65,11 @@ OutputConfiguration::OutputConfiguration(const Parcel& parcel) { gbp.get(), String8(name).string()); } +OutputConfiguration::OutputConfiguration(sp<IGraphicBufferProducer>& gbp, int rotation) { + mGbp = gbp; + mRotation = rotation; +} + status_t OutputConfiguration::writeToParcel(Parcel& parcel) const { parcel.writeInt32(mRotation); diff --git a/camera/tests/Android.mk b/camera/tests/Android.mk index 5d37f9e..3777d94 100644 --- a/camera/tests/Android.mk +++ b/camera/tests/Android.mk @@ -17,7 +17,8 @@ include $(CLEAR_VARS) LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk LOCAL_SRC_FILES:= \ - VendorTagDescriptorTests.cpp + VendorTagDescriptorTests.cpp \ + CameraBinderTests.cpp LOCAL_SHARED_LIBRARIES := \ libutils \ diff --git a/camera/tests/CameraBinderTests.cpp b/camera/tests/CameraBinderTests.cpp new file mode 100644 index 0000000..572fb72 --- /dev/null +++ b/camera/tests/CameraBinderTests.cpp @@ -0,0 +1,484 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_NDEBUG 0 +#define LOG_TAG "CameraBinderTests" + +#include <binder/IInterface.h> +#include <binder/IServiceManager.h> +#include <binder/Parcel.h> +#include <binder/ProcessState.h> +#include <utils/Errors.h> +#include <utils/Log.h> +#include <utils/List.h> +#include <utils/String8.h> +#include <utils/String16.h> +#include <utils/Condition.h> +#include <utils/Mutex.h> +#include <system/graphics.h> +#include <hardware/gralloc.h> + +#include <camera/CameraMetadata.h> +#include <camera/ICameraService.h> +#include <camera/ICameraServiceListener.h> +#include <camera/camera2/CaptureRequest.h> +#include <camera/camera2/ICameraDeviceUser.h> +#include <camera/camera2/ICameraDeviceCallbacks.h> +#include <camera/camera2/OutputConfiguration.h> + +#include <gui/BufferItemConsumer.h> +#include <gui/IGraphicBufferProducer.h> +#include <gui/Surface.h> + +#include <gtest/gtest.h> +#include <unistd.h> +#include <stdint.h> +#include <utility> +#include <vector> +#include <map> +#include <algorithm> + +using namespace android; + +#define ASSERT_NOT_NULL(x) \ + ASSERT_TRUE((x) != nullptr) + +#define SETUP_TIMEOUT 2000000000 // ns +#define IDLE_TIMEOUT 2000000000 // ns + +// Stub listener implementation +class TestCameraServiceListener : public BnCameraServiceListener { + std::map<String16, TorchStatus> mCameraTorchStatuses; + std::map<int32_t, Status> mCameraStatuses; + mutable Mutex mLock; + mutable Condition mCondition; + mutable Condition mTorchCondition; +public: + virtual ~TestCameraServiceListener() {}; + + virtual void onStatusChanged(Status status, int32_t cameraId) { + Mutex::Autolock l(mLock); + mCameraStatuses[cameraId] = status; + mCondition.broadcast(); + }; + + virtual void onTorchStatusChanged(TorchStatus status, const String16& cameraId) { + Mutex::Autolock l(mLock); + mCameraTorchStatuses[cameraId] = status; + mTorchCondition.broadcast(); + }; + + bool waitForNumCameras(size_t num) const { + Mutex::Autolock l(mLock); + + if (mCameraStatuses.size() == num) { + return true; + } + + while (mCameraStatuses.size() < num) { + if (mCondition.waitRelative(mLock, SETUP_TIMEOUT) != OK) { + return false; + } + } + return true; + }; + + bool waitForTorchState(TorchStatus status, int32_t cameraId) const { + Mutex::Autolock l(mLock); + + const auto& iter = mCameraTorchStatuses.find(String16(String8::format("%d", cameraId))); + if (iter != mCameraTorchStatuses.end() && iter->second == status) { + return true; + } + + bool foundStatus = false; + while (!foundStatus) { + if (mTorchCondition.waitRelative(mLock, SETUP_TIMEOUT) != OK) { + return false; + } + const auto& iter = + mCameraTorchStatuses.find(String16(String8::format("%d", cameraId))); + foundStatus = (iter != mCameraTorchStatuses.end() && iter->second == status); + } + return true; + }; + + TorchStatus getTorchStatus(int32_t cameraId) const { + Mutex::Autolock l(mLock); + const auto& iter = mCameraTorchStatuses.find(String16(String8::format("%d", cameraId))); + if (iter == mCameraTorchStatuses.end()) { + return ICameraServiceListener::TORCH_STATUS_UNKNOWN; + } + return iter->second; + }; + + Status getStatus(int32_t cameraId) const { + Mutex::Autolock l(mLock); + const auto& iter = mCameraStatuses.find(cameraId); + if (iter == mCameraStatuses.end()) { + return ICameraServiceListener::STATUS_UNKNOWN; + } + return iter->second; + }; +}; + +// Callback implementation +class TestCameraDeviceCallbacks : public BnCameraDeviceCallbacks { +public: + enum Status { + IDLE, + ERROR, + PREPARED, + RUNNING, + SENT_RESULT, + UNINITIALIZED + }; + +protected: + bool mError; + Status mLastStatus; + mutable std::vector<Status> mStatusesHit; + mutable Mutex mLock; + mutable Condition mStatusCondition; +public: + TestCameraDeviceCallbacks() : mError(false), mLastStatus(UNINITIALIZED) {} + + virtual ~TestCameraDeviceCallbacks() {} + + virtual void onDeviceError(CameraErrorCode errorCode, + const CaptureResultExtras& resultExtras) { + ALOGE("%s: onDeviceError occurred with: %d", __FUNCTION__, static_cast<int>(errorCode)); + Mutex::Autolock l(mLock); + mError = true; + mLastStatus = ERROR; + mStatusesHit.push_back(mLastStatus); + mStatusCondition.broadcast(); + } + + virtual void onDeviceIdle() { + Mutex::Autolock l(mLock); + mLastStatus = IDLE; + mStatusesHit.push_back(mLastStatus); + mStatusCondition.broadcast(); + } + + virtual void onCaptureStarted(const CaptureResultExtras& resultExtras, + int64_t timestamp) { + Mutex::Autolock l(mLock); + mLastStatus = RUNNING; + mStatusesHit.push_back(mLastStatus); + mStatusCondition.broadcast(); + } + + + virtual void onResultReceived(const CameraMetadata& metadata, + const CaptureResultExtras& resultExtras) { + Mutex::Autolock l(mLock); + mLastStatus = SENT_RESULT; + mStatusesHit.push_back(mLastStatus); + mStatusCondition.broadcast(); + } + + virtual void onPrepared(int streamId) { + Mutex::Autolock l(mLock); + mLastStatus = PREPARED; + mStatusesHit.push_back(mLastStatus); + mStatusCondition.broadcast(); + } + + // Test helper functions: + + bool hadError() const { + Mutex::Autolock l(mLock); + return mError; + } + + bool waitForStatus(Status status) const { + Mutex::Autolock l(mLock); + if (mLastStatus == status) { + return true; + } + + while (std::find(mStatusesHit.begin(), mStatusesHit.end(), status) + == mStatusesHit.end()) { + + if (mStatusCondition.waitRelative(mLock, IDLE_TIMEOUT) != OK) { + mStatusesHit.clear(); + return false; + } + } + mStatusesHit.clear(); + + return true; + + } + + void clearStatus() const { + Mutex::Autolock l(mLock); + mStatusesHit.clear(); + } + + bool waitForIdle() const { + return waitForStatus(IDLE); + } + +}; + +// Exercise basic binder calls for the camera service +TEST(CameraServiceBinderTest, CheckBinderCameraService) { + ProcessState::self()->startThreadPool(); + sp<IServiceManager> sm = defaultServiceManager(); + sp<IBinder> binder = sm->getService(String16("media.camera")); + ASSERT_NOT_NULL(binder); + sp<ICameraService> service = interface_cast<ICameraService>(binder); + + + int32_t numCameras = service->getNumberOfCameras(); + EXPECT_LE(0, numCameras); + + // Check listener binder calls + sp<TestCameraServiceListener> listener(new TestCameraServiceListener()); + EXPECT_EQ(OK, service->addListener(listener)); + + EXPECT_TRUE(listener->waitForNumCameras(numCameras)); + + for (int32_t i = 0; i < numCameras; i++) { + // We only care about binder calls for the Camera2 API. Camera1 is deprecated. + status_t camera2Support = service->supportsCameraApi(i, ICameraService::API_VERSION_2); + if (camera2Support != OK) { + EXPECT_EQ(-EOPNOTSUPP, camera2Support); + continue; + } + + // Check metadata binder call + CameraMetadata metadata; + EXPECT_EQ(OK, service->getCameraCharacteristics(i, &metadata)); + EXPECT_FALSE(metadata.isEmpty()); + + // Make sure we're available, or skip device tests otherwise + ICameraServiceListener::Status s = listener->getStatus(i); + EXPECT_EQ(ICameraServiceListener::STATUS_AVAILABLE, s); + if (s != ICameraServiceListener::STATUS_AVAILABLE) { + continue; + } + + // Check connect binder calls + sp<TestCameraDeviceCallbacks> callbacks(new TestCameraDeviceCallbacks()); + sp<ICameraDeviceUser> device; + EXPECT_EQ(OK, service->connectDevice(callbacks, i, String16("meeeeeeeee!"), + ICameraService::USE_CALLING_UID, /*out*/device)); + ASSERT_NE(nullptr, device.get()); + device->disconnect(); + EXPECT_FALSE(callbacks->hadError()); + + ICameraServiceListener::TorchStatus torchStatus = listener->getTorchStatus(i); + if (torchStatus == ICameraServiceListener::TORCH_STATUS_AVAILABLE_OFF) { + // Check torch calls + EXPECT_EQ(OK, service->setTorchMode(String16(String8::format("%d", i)), + /*enabled*/true, callbacks)); + EXPECT_TRUE(listener->waitForTorchState( + ICameraServiceListener::TORCH_STATUS_AVAILABLE_ON, i)); + EXPECT_EQ(OK, service->setTorchMode(String16(String8::format("%d", i)), + /*enabled*/false, callbacks)); + EXPECT_TRUE(listener->waitForTorchState( + ICameraServiceListener::TORCH_STATUS_AVAILABLE_OFF, i)); + } + } + + EXPECT_EQ(OK, service->removeListener(listener)); +} + +// Test fixture for client focused binder tests +class CameraClientBinderTest : public testing::Test { +protected: + sp<ICameraService> service; + int32_t numCameras; + std::vector<std::pair<sp<TestCameraDeviceCallbacks>, sp<ICameraDeviceUser>>> openDeviceList; + sp<TestCameraServiceListener> serviceListener; + + std::pair<sp<TestCameraDeviceCallbacks>, sp<ICameraDeviceUser>> openNewDevice(int deviceId) { + + sp<TestCameraDeviceCallbacks> callbacks(new TestCameraDeviceCallbacks()); + sp<ICameraDeviceUser> device; + { + SCOPED_TRACE("openNewDevice"); + EXPECT_EQ(OK, service->connectDevice(callbacks, deviceId, String16("meeeeeeeee!"), + ICameraService::USE_CALLING_UID, /*out*/device)); + } + auto p = std::make_pair(callbacks, device); + openDeviceList.push_back(p); + return p; + } + + void closeDevice(std::pair<sp<TestCameraDeviceCallbacks>, sp<ICameraDeviceUser>>& p) { + if (p.second.get() != nullptr) { + p.second->disconnect(); + { + SCOPED_TRACE("closeDevice"); + EXPECT_FALSE(p.first->hadError()); + } + } + auto iter = std::find(openDeviceList.begin(), openDeviceList.end(), p); + if (iter != openDeviceList.end()) { + openDeviceList.erase(iter); + } + } + + virtual void SetUp() { + ProcessState::self()->startThreadPool(); + sp<IServiceManager> sm = defaultServiceManager(); + sp<IBinder> binder = sm->getService(String16("media.camera")); + service = interface_cast<ICameraService>(binder); + serviceListener = new TestCameraServiceListener(); + service->addListener(serviceListener); + numCameras = service->getNumberOfCameras(); + } + + virtual void TearDown() { + service = nullptr; + numCameras = 0; + for (auto& p : openDeviceList) { + closeDevice(p); + } + } + +}; + +TEST_F(CameraClientBinderTest, CheckBinderCameraDeviceUser) { + ASSERT_NOT_NULL(service); + + EXPECT_TRUE(serviceListener->waitForNumCameras(numCameras)); + for (int32_t i = 0; i < numCameras; i++) { + // Make sure we're available, or skip device tests otherwise + ICameraServiceListener::Status s = serviceListener->getStatus(i); + EXPECT_EQ(ICameraServiceListener::STATUS_AVAILABLE, s); + if (s != ICameraServiceListener::STATUS_AVAILABLE) { + continue; + } + + auto p = openNewDevice(i); + sp<TestCameraDeviceCallbacks> callbacks = p.first; + sp<ICameraDeviceUser> device = p.second; + + // Setup a buffer queue; I'm just using the vendor opaque format here as that is + // guaranteed to be present + sp<IGraphicBufferProducer> gbProducer; + sp<IGraphicBufferConsumer> gbConsumer; + BufferQueue::createBufferQueue(&gbProducer, &gbConsumer); + sp<BufferItemConsumer> opaqueConsumer = new BufferItemConsumer(gbConsumer, + GRALLOC_USAGE_SW_READ_NEVER, /*maxImages*/2, /*controlledByApp*/true); + EXPECT_TRUE(opaqueConsumer.get() != nullptr); + opaqueConsumer->setName(String8("nom nom nom")); + + // Set to VGA dimens for default, as that is guaranteed to be present + EXPECT_EQ(OK, gbConsumer->setDefaultBufferSize(640, 480)); + EXPECT_EQ(OK, gbConsumer->setDefaultBufferFormat(HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED)); + + sp<Surface> surface(new Surface(gbProducer, /*controlledByApp*/false)); + + OutputConfiguration output(gbProducer, /*rotation*/0); + + // Can we configure? + EXPECT_EQ(OK, device->beginConfigure()); + status_t streamId = device->createStream(output); + EXPECT_LE(0, streamId); + EXPECT_EQ(OK, device->endConfigure()); + EXPECT_FALSE(callbacks->hadError()); + + // Can we make requests? + CameraMetadata requestTemplate; + EXPECT_EQ(OK, device->createDefaultRequest(/*preview template*/1, + /*out*/&requestTemplate)); + sp<CaptureRequest> request(new CaptureRequest()); + request->mMetadata = requestTemplate; + request->mSurfaceList.add(surface); + request->mIsReprocess = false; + int64_t lastFrameNumber = 0; + int64_t lastFrameNumberPrev = 0; + callbacks->clearStatus(); + int requestId = device->submitRequest(request, /*streaming*/true, /*out*/&lastFrameNumber); + EXPECT_TRUE(callbacks->waitForStatus(TestCameraDeviceCallbacks::SENT_RESULT)); + EXPECT_LE(0, requestId); + + // Can we stop requests? + EXPECT_EQ(OK, device->cancelRequest(requestId, /*out*/&lastFrameNumber)); + EXPECT_TRUE(callbacks->waitForIdle()); + EXPECT_FALSE(callbacks->hadError()); + + // Can we do it again? + lastFrameNumberPrev = lastFrameNumber; + lastFrameNumber = 0; + requestTemplate.clear(); + EXPECT_EQ(OK, device->createDefaultRequest(/*preview template*/1, + /*out*/&requestTemplate)); + sp<CaptureRequest> request2(new CaptureRequest()); + request2->mMetadata = requestTemplate; + request2->mSurfaceList.add(surface); + request2->mIsReprocess = false; + callbacks->clearStatus(); + int requestId2 = device->submitRequest(request2, /*streaming*/true, + /*out*/&lastFrameNumber); + EXPECT_EQ(-1, lastFrameNumber); + lastFrameNumber = 0; + EXPECT_TRUE(callbacks->waitForStatus(TestCameraDeviceCallbacks::SENT_RESULT)); + EXPECT_LE(0, requestId2); + EXPECT_EQ(OK, device->cancelRequest(requestId2, /*out*/&lastFrameNumber)); + EXPECT_TRUE(callbacks->waitForIdle()); + EXPECT_LE(lastFrameNumberPrev, lastFrameNumber); + sleep(/*second*/1); // allow some time for errors to show up, if any + EXPECT_FALSE(callbacks->hadError()); + + // Can we do it with a request list? + lastFrameNumberPrev = lastFrameNumber; + lastFrameNumber = 0; + requestTemplate.clear(); + CameraMetadata requestTemplate2; + EXPECT_EQ(OK, device->createDefaultRequest(/*preview template*/1, + /*out*/&requestTemplate)); + EXPECT_EQ(OK, device->createDefaultRequest(/*preview template*/1, + /*out*/&requestTemplate2)); + sp<CaptureRequest> request3(new CaptureRequest()); + sp<CaptureRequest> request4(new CaptureRequest()); + request3->mMetadata = requestTemplate; + request3->mSurfaceList.add(surface); + request3->mIsReprocess = false; + request4->mMetadata = requestTemplate2; + request4->mSurfaceList.add(surface); + request4->mIsReprocess = false; + List<sp<CaptureRequest>> requestList; + requestList.push_back(request3); + requestList.push_back(request4); + + callbacks->clearStatus(); + int requestId3 = device->submitRequestList(requestList, /*streaming*/false, + /*out*/&lastFrameNumber); + EXPECT_TRUE(callbacks->waitForStatus(TestCameraDeviceCallbacks::SENT_RESULT)); + EXPECT_TRUE(callbacks->waitForIdle()); + EXPECT_LE(lastFrameNumberPrev, lastFrameNumber); + sleep(/*second*/1); // allow some time for errors to show up, if any + EXPECT_FALSE(callbacks->hadError()); + + // Can we unconfigure? + EXPECT_EQ(OK, device->beginConfigure()); + EXPECT_EQ(OK, device->deleteStream(streamId)); + EXPECT_EQ(OK, device->endConfigure()); + sleep(/*second*/1); // allow some time for errors to show up, if any + EXPECT_FALSE(callbacks->hadError()); + + closeDevice(p); + } + +}; diff --git a/camera/tests/VendorTagDescriptorTests.cpp b/camera/tests/VendorTagDescriptorTests.cpp index 6624e79..9082dbf 100644 --- a/camera/tests/VendorTagDescriptorTests.cpp +++ b/camera/tests/VendorTagDescriptorTests.cpp @@ -53,6 +53,10 @@ static bool ContainsTag(uint32_t* tagArray, size_t size, uint32_t tag) { extern "C" { +static int zero_get_tag_count(const vendor_tag_ops_t* vOps) { + return 0; +} + static int default_get_tag_count(const vendor_tag_ops_t* vOps) { return VENDOR_TAG_COUNT_ERR; } @@ -173,10 +177,13 @@ TEST(VendorTagDescriptorTest, ErrorConditions) { vendor_tag_ops_t vOps; FillWithDefaults(&vOps); + // Make empty tag count + vOps.get_tag_count = zero_get_tag_count; + // Ensure create fails when using null vOps EXPECT_EQ(BAD_VALUE, VendorTagDescriptor::createDescriptorFromOps(/*vOps*/NULL, vDesc)); - // Ensure create works when there are no vtags defined in a well-formed vOps + // Ensure creat succeeds for empty vendor tag ops ASSERT_EQ(OK, VendorTagDescriptor::createDescriptorFromOps(&vOps, vDesc)); // Ensure defaults are returned when no vtags are defined, or tag is unknown diff --git a/include/camera/camera2/OutputConfiguration.h b/include/camera/camera2/OutputConfiguration.h index e6b679f..5bcbe15 100644 --- a/include/camera/camera2/OutputConfiguration.h +++ b/include/camera/camera2/OutputConfiguration.h @@ -39,6 +39,8 @@ public: // getRotation will be INVALID_ROTATION if error occurred OutputConfiguration(const Parcel& parcel); + OutputConfiguration(sp<IGraphicBufferProducer>& gbp, int rotation); + private: sp<IGraphicBufferProducer> mGbp; int mRotation; diff --git a/include/media/stagefright/MediaCodecSource.h b/include/media/stagefright/MediaCodecSource.h index a991b02..71f58a9 100644 --- a/include/media/stagefright/MediaCodecSource.h +++ b/include/media/stagefright/MediaCodecSource.h @@ -108,6 +108,9 @@ private: bool mStarted; bool mStopping; bool mDoMoreWorkPending; + bool mSetEncoderFormat; + int mEncoderFormat; + int mEncoderDataSpace; sp<AMessage> mEncoderActivityNotify; sp<IGraphicBufferProducer> mGraphicBufferProducer; sp<IGraphicBufferConsumer> mGraphicBufferConsumer; diff --git a/include/media/stagefright/MetaData.h b/include/media/stagefright/MetaData.h index ca80123..726b197 100644 --- a/include/media/stagefright/MetaData.h +++ b/include/media/stagefright/MetaData.h @@ -70,7 +70,9 @@ enum { kKeyDriftTime = 'dftT', // int64_t (usecs) kKeyAnchorTime = 'ancT', // int64_t (usecs) kKeyDuration = 'dura', // int64_t (usecs) - kKeyColorFormat = 'colf', + kKeyPixelFormat = 'pixf', // int32_t + kKeyColorFormat = 'colf', // int32_t + kKeyColorSpace = 'cols', // int32_t kKeyPlatformPrivate = 'priv', // pointer kKeyDecoderComponent = 'decC', // cstring kKeyBufferID = 'bfID', diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp index bb53ce6..7452e4b 100644 --- a/media/libstagefright/ACodec.cpp +++ b/media/libstagefright/ACodec.cpp @@ -1639,6 +1639,14 @@ status_t ACodec::configureCodec( if (mInputMetadataType == kMetadataBufferTypeGrallocSource) { mInputMetadataType = kMetadataBufferTypeCameraSource; } + + uint32_t usageBits; + if (mOMX->getParameter( + mNode, (OMX_INDEXTYPE)OMX_IndexParamConsumerUsageBits, + &usageBits, sizeof(usageBits)) == OK) { + inputFormat->setInt32( + "using-sw-read-often", !!(usageBits & GRALLOC_USAGE_SW_READ_OFTEN)); + } } int32_t prependSPSPPS = 0; @@ -5234,6 +5242,7 @@ void ACodec::BaseState::onOutputBufferDrained(const sp<AMessage> &msg) { if (err == OK) { info->mStatus = BufferInfo::OWNED_BY_NATIVE_WINDOW; } else { + ALOGE("queueBuffer failed in onOutputBufferDrained: %d", err); mCodec->signalError(OMX_ErrorUndefined, makeNoSideEffectStatus(err)); info->mStatus = BufferInfo::OWNED_BY_US; // keeping read fence as write fence to avoid clobbering @@ -5748,6 +5757,14 @@ status_t ACodec::LoadedState::setupInputSurface() { } } + uint32_t usageBits; + if (mCodec->mOMX->getParameter( + mCodec->mNode, (OMX_INDEXTYPE)OMX_IndexParamConsumerUsageBits, + &usageBits, sizeof(usageBits)) == OK) { + mCodec->mInputFormat->setInt32( + "using-sw-read-often", !!(usageBits & GRALLOC_USAGE_SW_READ_OFTEN)); + } + return OK; } diff --git a/media/libstagefright/CameraSource.cpp b/media/libstagefright/CameraSource.cpp index 2606e44..bc34bcf 100644 --- a/media/libstagefright/CameraSource.cpp +++ b/media/libstagefright/CameraSource.cpp @@ -670,9 +670,13 @@ status_t CameraSource::start(MetaData *meta) { mNumInputBuffers = nBuffers; } - // TODO: Read in format/dataspace from somewhere - // Uncomment to test SW encoders until TODO is resolved - // mEncoderFormat = HAL_PIXEL_FORMAT_YCbCr_420_888; + // apply encoder color format if specified + if (meta->findInt32(kKeyPixelFormat, &mEncoderFormat)) { + ALOGV("Using encoder format: %#x", mEncoderFormat); + } + if (meta->findInt32(kKeyColorSpace, &mEncoderDataSpace)) { + ALOGV("Using encoder data space: %#x", mEncoderDataSpace); + } } status_t err; diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp index b576cd9..69f44ed 100644 --- a/media/libstagefright/MediaCodec.cpp +++ b/media/libstagefright/MediaCodec.cpp @@ -2528,7 +2528,25 @@ status_t MediaCodec::connectToSurface(const sp<Surface> &surface) { err = native_window_api_connect(surface.get(), NATIVE_WINDOW_API_MEDIA); if (err == BAD_VALUE) { ALOGI("native window already connected. Assuming no change of surface"); - } else if (err != OK) { + } else if (err == OK) { + // Require a fresh set of buffers after each connect by using a unique generation + // number. Rely on the fact that max supported process id by Linux is 2^22. + // PID is never 0 so we don't have to worry that we use the default generation of 0. + // TODO: come up with a unique scheme if other producers also set the generation number. + static uint32_t mSurfaceGeneration = 0; + uint32_t generation = (getpid() << 10) | (++mSurfaceGeneration & ((1 << 10) - 1)); + surface->setGenerationNumber(generation); + ALOGI("[%s] setting surface generation to %u", mComponentName.c_str(), generation); + + // HACK: clear any free buffers. Remove when connect will automatically do this. + // This is needed as the consumer may be holding onto stale frames that it can reattach + // to this surface after disconnect/connect, and those free frames would inherit the new + // generation number. Disconnecting after setting a unique generation prevents this. + native_window_api_disconnect(surface.get(), NATIVE_WINDOW_API_MEDIA); + err = native_window_api_connect(surface.get(), NATIVE_WINDOW_API_MEDIA); + } + + if (err != OK) { ALOGE("native_window_api_connect returned an error: %s (%d)", strerror(-err), err); } } @@ -2538,6 +2556,8 @@ status_t MediaCodec::connectToSurface(const sp<Surface> &surface) { status_t MediaCodec::disconnectFromSurface() { status_t err = OK; if (mSurface != NULL) { + // Resetting generation is not technically needed, but there is no need to keep it either + mSurface->setGenerationNumber(0); err = native_window_api_disconnect(mSurface.get(), NATIVE_WINDOW_API_MEDIA); if (err != OK) { ALOGW("native_window_api_disconnect returned an error: %s (%d)", strerror(-err), err); diff --git a/media/libstagefright/MediaCodecList.cpp b/media/libstagefright/MediaCodecList.cpp index ab49c11..7ea5cbd 100644 --- a/media/libstagefright/MediaCodecList.cpp +++ b/media/libstagefright/MediaCodecList.cpp @@ -175,6 +175,7 @@ MediaCodecList::MediaCodecList() mUpdate(false), mGlobalSettings(new AMessage()) { parseTopLevelXMLFile("/etc/media_codecs.xml"); + parseTopLevelXMLFile("/etc/media_codecs_performance.xml", true/* ignore_errors */); parseTopLevelXMLFile(kProfilingResults, true/* ignore_errors */); } @@ -935,7 +936,7 @@ status_t MediaCodecList::addLimit(const char **attrs) { if (name == "aspect-ratio" || name == "bitrate" || name == "block-count" || name == "blocks-per-second" || name == "complexity" || name == "frame-rate" || name == "quality" || name == "size" - || name == "measured-blocks-per-second" || name == "measured-frame-rate") { + || name == "measured-blocks-per-second" || name.startsWith("measured-frame-rate-")) { AString min, max; if (msg->findString("min", &min) && msg->findString("max", &max)) { min.append("-"); diff --git a/media/libstagefright/MediaCodecSource.cpp b/media/libstagefright/MediaCodecSource.cpp index e089c46..7f9f824 100644 --- a/media/libstagefright/MediaCodecSource.cpp +++ b/media/libstagefright/MediaCodecSource.cpp @@ -39,6 +39,9 @@ namespace android { +const int kDefaultSwVideoEncoderFormat = HAL_PIXEL_FORMAT_YCbCr_420_888; +const int kDefaultSwVideoEncoderDataSpace = HAL_DATASPACE_BT709; + struct MediaCodecSource::Puller : public AHandler { Puller(const sp<MediaSource> &source); @@ -341,6 +344,9 @@ MediaCodecSource::MediaCodecSource( mStarted(false), mStopping(false), mDoMoreWorkPending(false), + mSetEncoderFormat(false), + mEncoderFormat(0), + mEncoderDataSpace(0), mGraphicBufferConsumer(consumer), mFirstSampleTimeUs(-1ll), mEncoderReachedEOS(false), @@ -438,6 +444,18 @@ status_t MediaCodecSource::initEncoder() { } } + sp<AMessage> inputFormat; + int32_t usingSwReadOften; + mSetEncoderFormat = false; + if (mEncoder->getInputFormat(&inputFormat) == OK + && inputFormat->findInt32("using-sw-read-often", &usingSwReadOften) + && usingSwReadOften) { + // this is a SW encoder; signal source to allocate SW readable buffers + mSetEncoderFormat = true; + mEncoderFormat = kDefaultSwVideoEncoderFormat; + mEncoderDataSpace = kDefaultSwVideoEncoderDataSpace; + } + err = mEncoder->start(); if (err != OK) { @@ -632,8 +650,17 @@ status_t MediaCodecSource::onStart(MetaData *params) { resume(startTimeUs); } else { CHECK(mPuller != NULL); + sp<MetaData> meta = params; + if (mSetEncoderFormat) { + if (meta == NULL) { + meta = new MetaData; + } + meta->setInt32(kKeyPixelFormat, mEncoderFormat); + meta->setInt32(kKeyColorSpace, mEncoderDataSpace); + } + sp<AMessage> notify = new AMessage(kWhatPullerNotify, mReflector); - err = mPuller->start(params, notify); + err = mPuller->start(meta.get(), notify); if (err != OK) { return err; } diff --git a/media/libstagefright/MediaSync.cpp b/media/libstagefright/MediaSync.cpp index b402e48..52077a7 100644 --- a/media/libstagefright/MediaSync.cpp +++ b/media/libstagefright/MediaSync.cpp @@ -558,7 +558,6 @@ void MediaSync::onFrameAvailableFromInput() { return; } } - ++mNumOutstandingBuffers; // Acquire and detach the buffer from the input. BufferItem bufferItem; @@ -567,6 +566,7 @@ void MediaSync::onFrameAvailableFromInput() { ALOGE("acquiring buffer from input failed (%d)", status); return; } + ++mNumOutstandingBuffers; ALOGV("acquired buffer %#llx from input", (long long)bufferItem.mGraphicBuffer->getId()); @@ -608,6 +608,7 @@ void MediaSync::renderOneBufferItem_l( const BufferItem &bufferItem) { // Attach and queue the buffer to the output. int slot; + mOutput->setGenerationNumber(bufferItem.mGraphicBuffer->getGenerationNumber()); status_t status = mOutput->attachBuffer(&slot, bufferItem.mGraphicBuffer); ALOGE_IF(status != NO_ERROR, "attaching buffer to output failed (%d)", status); if (status == NO_ERROR) { @@ -695,16 +696,13 @@ void MediaSync::returnBufferToInput_l( ALOGE_IF(status != NO_ERROR, "releasing buffer to input failed (%d)", status); } - if (status != NO_ERROR) { - // TODO: do we need to try to return this buffer later? - return; - } - - ALOGV("released buffer %#llx to input", (long long)oldBuffer->getId()); - // Notify any waiting onFrameAvailable calls. --mNumOutstandingBuffers; mReleaseCondition.signal(); + + if (status == NO_ERROR) { + ALOGV("released buffer %#llx to input", (long long)oldBuffer->getId()); + } } void MediaSync::onAbandoned_l(bool isInput) { diff --git a/media/libstagefright/codecs/mp3dec/SoftMP3.cpp b/media/libstagefright/codecs/mp3dec/SoftMP3.cpp index 5396022..f743b1c 100644 --- a/media/libstagefright/codecs/mp3dec/SoftMP3.cpp +++ b/media/libstagefright/codecs/mp3dec/SoftMP3.cpp @@ -283,6 +283,11 @@ void SoftMP3::onQueueFilled(OMX_U32 /* portIndex */) { } else { // This is recoverable, just ignore the current frame and // play silence instead. + + // TODO: should we skip silence (and consume input data) + // if mIsFirst is true as we may not have a valid + // mConfig->samplingRate and mConfig->num_channels? + ALOGV_IF(mIsFirst, "insufficient data for first frame, sending silence"); memset(outHeader->pBuffer, 0, mConfig->outputFrameSize * sizeof(int16_t)); @@ -317,8 +322,7 @@ void SoftMP3::onQueueFilled(OMX_U32 /* portIndex */) { } outHeader->nTimeStamp = - mAnchorTimeUs - + (mNumFramesOutput * 1000000ll) / mConfig->samplingRate; + mAnchorTimeUs + (mNumFramesOutput * 1000000ll) / mSamplingRate; if (inHeader) { CHECK_GE(inHeader->nFilledLen, mConfig->inputBufferUsedLength); diff --git a/media/libstagefright/omx/GraphicBufferSource.cpp b/media/libstagefright/omx/GraphicBufferSource.cpp index 31c6975..1a7dc9d 100644 --- a/media/libstagefright/omx/GraphicBufferSource.cpp +++ b/media/libstagefright/omx/GraphicBufferSource.cpp @@ -23,6 +23,7 @@ #include "GraphicBufferSource.h" #include <OMX_Core.h> +#include <OMX_IndexExt.h> #include <media/stagefright/foundation/ADebug.h> #include <media/stagefright/foundation/AMessage.h> @@ -110,6 +111,7 @@ GraphicBufferSource::GraphicBufferSource( uint32_t bufferWidth, uint32_t bufferHeight, uint32_t bufferCount, + uint32_t consumerUsage, const sp<IGraphicBufferConsumer> &consumer) : mInitCheck(UNKNOWN_ERROR), mNodeInstance(nodeInstance), @@ -152,7 +154,12 @@ GraphicBufferSource::GraphicBufferSource( BufferQueue::createBufferQueue(&mProducer, &mConsumer); mConsumer->setConsumerName(name); - mConsumer->setConsumerUsageBits(GRALLOC_USAGE_HW_VIDEO_ENCODER); + + // use consumer usage bits queried from encoder, but always add HW_VIDEO_ENCODER + // for backward compatibility. + consumerUsage |= GRALLOC_USAGE_HW_VIDEO_ENCODER; + mConsumer->setConsumerUsageBits(consumerUsage); + mInitCheck = mConsumer->setMaxAcquiredBufferCount(bufferCount); if (mInitCheck != NO_ERROR) { ALOGE("Unable to set BQ max acquired buffer count to %u: %d", @@ -836,13 +843,15 @@ void GraphicBufferSource::releaseBuffer( mConsumer->detachBuffer(id); mBufferSlot[id] = NULL; - mConsumer->attachBuffer(&id, buffer); - mConsumer->releaseBuffer( - id, 0, EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, fence); + if (mConsumer->attachBuffer(&id, buffer) == OK) { + mConsumer->releaseBuffer( + id, 0, EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, fence); + } } else { mConsumer->releaseBuffer( id, frameNum, EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, fence); } + id = -1; // invalidate id mNumBufferAcquired--; } diff --git a/media/libstagefright/omx/GraphicBufferSource.h b/media/libstagefright/omx/GraphicBufferSource.h index 3f64088..2f929d9 100644 --- a/media/libstagefright/omx/GraphicBufferSource.h +++ b/media/libstagefright/omx/GraphicBufferSource.h @@ -55,6 +55,7 @@ public: uint32_t bufferWidth, uint32_t bufferHeight, uint32_t bufferCount, + uint32_t consumerUsage, const sp<IGraphicBufferConsumer> &consumer = NULL ); diff --git a/media/libstagefright/omx/OMXNodeInstance.cpp b/media/libstagefright/omx/OMXNodeInstance.cpp index 147aae7..9f1c5d8 100644 --- a/media/libstagefright/omx/OMXNodeInstance.cpp +++ b/media/libstagefright/omx/OMXNodeInstance.cpp @@ -834,7 +834,8 @@ status_t OMXNodeInstance::updateGraphicBufferInMeta_l( } CLOG_BUFFER(updateGraphicBufferInMeta, "%s:%u, %#x := %p", - portString(portIndex), portIndex, buffer, graphicBuffer->handle); + portString(portIndex), portIndex, buffer, + graphicBuffer == NULL ? NULL : graphicBuffer->handle); return OK; } @@ -885,10 +886,18 @@ status_t OMXNodeInstance::createGraphicBufferSource( return INVALID_OPERATION; } + uint32_t usageBits; + oerr = OMX_GetParameter( + mHandle, (OMX_INDEXTYPE)OMX_IndexParamConsumerUsageBits, &usageBits); + if (oerr != OMX_ErrorNone) { + usageBits = 0; + } + sp<GraphicBufferSource> bufferSource = new GraphicBufferSource(this, def.format.video.nFrameWidth, def.format.video.nFrameHeight, def.nBufferCountActual, + usageBits, bufferConsumer); if ((err = bufferSource->initCheck()) != OK) { @@ -1607,7 +1616,12 @@ OMX_BUFFERHEADERTYPE *OMXNodeInstance::findBufferHeader(OMX::buffer_id buffer) { return NULL; } Mutex::Autolock autoLock(mBufferIDLock); - return mBufferIDToBufferHeader.valueFor(buffer); + ssize_t index = mBufferIDToBufferHeader.indexOfKey(buffer); + if (index < 0) { + CLOGW("findBufferHeader: buffer %u not found", buffer); + return NULL; + } + return mBufferIDToBufferHeader.valueAt(index); } OMX::buffer_id OMXNodeInstance::findBufferID(OMX_BUFFERHEADERTYPE *bufferHeader) { @@ -1615,7 +1629,12 @@ OMX::buffer_id OMXNodeInstance::findBufferID(OMX_BUFFERHEADERTYPE *bufferHeader) return 0; } Mutex::Autolock autoLock(mBufferIDLock); - return mBufferHeaderToBufferID.valueFor(bufferHeader); + ssize_t index = mBufferHeaderToBufferID.indexOfKey(bufferHeader); + if (index < 0) { + CLOGW("findBufferID: bufferHeader %p not found", bufferHeader); + return 0; + } + return mBufferHeaderToBufferID.valueAt(index); } void OMXNodeInstance::invalidateBufferID(OMX::buffer_id buffer) { @@ -1623,8 +1642,13 @@ void OMXNodeInstance::invalidateBufferID(OMX::buffer_id buffer) { return; } Mutex::Autolock autoLock(mBufferIDLock); - mBufferHeaderToBufferID.removeItem(mBufferIDToBufferHeader.valueFor(buffer)); - mBufferIDToBufferHeader.removeItem(buffer); + ssize_t index = mBufferIDToBufferHeader.indexOfKey(buffer); + if (index < 0) { + CLOGW("invalidateBufferID: buffer %u not found", buffer); + return; + } + mBufferHeaderToBufferID.removeItem(mBufferIDToBufferHeader.valueAt(index)); + mBufferIDToBufferHeader.removeItemsAt(index); } } // namespace android diff --git a/media/libstagefright/omx/SoftVideoEncoderOMXComponent.cpp b/media/libstagefright/omx/SoftVideoEncoderOMXComponent.cpp index 9dd26fb..8ea7a6e 100644 --- a/media/libstagefright/omx/SoftVideoEncoderOMXComponent.cpp +++ b/media/libstagefright/omx/SoftVideoEncoderOMXComponent.cpp @@ -34,6 +34,8 @@ #include <ui/GraphicBuffer.h> #include <ui/GraphicBufferMapper.h> +#include <OMX_IndexExt.h> + namespace android { const static OMX_COLOR_FORMATTYPE kSupportedColorFormats[] = { @@ -293,7 +295,7 @@ OMX_ERRORTYPE SoftVideoEncoderOMXComponent::internalSetParameter( OMX_ERRORTYPE SoftVideoEncoderOMXComponent::internalGetParameter( OMX_INDEXTYPE index, OMX_PTR param) { - switch (index) { + switch ((int)index) { case OMX_IndexParamVideoErrorCorrection: { return OMX_ErrorNotImplemented; @@ -343,6 +345,13 @@ OMX_ERRORTYPE SoftVideoEncoderOMXComponent::internalGetParameter( return OMX_ErrorNone; } + case OMX_IndexParamConsumerUsageBits: + { + OMX_U32 *usageBits = (OMX_U32 *)param; + *usageBits = GRALLOC_USAGE_SW_READ_OFTEN; + return OMX_ErrorNone; + } + default: return SimpleSoftOMXComponent::internalGetParameter(index, param); } diff --git a/services/audioflinger/PatchPanel.cpp b/services/audioflinger/PatchPanel.cpp index 9248bba..f6078a2 100644 --- a/services/audioflinger/PatchPanel.cpp +++ b/services/audioflinger/PatchPanel.cpp @@ -481,22 +481,31 @@ void AudioFlinger::PatchPanel::clearPatchConnections(Patch *patch) if (patch->mRecordThread != 0) { if (patch->mPatchRecord != 0) { patch->mRecordThread->deletePatchRecord(patch->mPatchRecord); - patch->mPatchRecord.clear(); } audioflinger->closeInputInternal_l(patch->mRecordThread); - patch->mRecordThread.clear(); } if (patch->mPlaybackThread != 0) { if (patch->mPatchTrack != 0) { patch->mPlaybackThread->deletePatchTrack(patch->mPatchTrack); - patch->mPatchTrack.clear(); } // if num sources == 2 we are reusing an existing playback thread so we do not close it if (patch->mAudioPatch.num_sources != 2) { audioflinger->closeOutputInternal_l(patch->mPlaybackThread); } + } + if (patch->mRecordThread != 0) { + if (patch->mPatchRecord != 0) { + patch->mPatchRecord.clear(); + } + patch->mRecordThread.clear(); + } + if (patch->mPlaybackThread != 0) { + if (patch->mPatchTrack != 0) { + patch->mPatchTrack.clear(); + } patch->mPlaybackThread.clear(); } + } /* Disconnect a patch */ diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp index c8f9be0..d3ea9d8 100644 --- a/services/audioflinger/Threads.cpp +++ b/services/audioflinger/Threads.cpp @@ -375,6 +375,7 @@ String8 devicesToString(audio_devices_t devices) AUDIO_DEVICE_OUT_FM, "FM", AUDIO_DEVICE_OUT_AUX_LINE, "AUX_LINE", AUDIO_DEVICE_OUT_SPEAKER_SAFE, "SPEAKER_SAFE", + AUDIO_DEVICE_OUT_IP, "IP", AUDIO_DEVICE_NONE, "NONE", // must be last }, mappingsIn[] = { AUDIO_DEVICE_IN_COMMUNICATION, "COMMUNICATION", @@ -397,6 +398,7 @@ String8 devicesToString(audio_devices_t devices) AUDIO_DEVICE_IN_SPDIF, "SPDIF", AUDIO_DEVICE_IN_BLUETOOTH_A2DP, "BLUETOOTH_A2DP", AUDIO_DEVICE_IN_LOOPBACK, "LOOPBACK", + AUDIO_DEVICE_IN_IP, "IP", AUDIO_DEVICE_NONE, "NONE", // must be last }; String8 result; diff --git a/services/audiopolicy/common/managerdefinitions/include/ConfigParsingUtils.h b/services/audiopolicy/common/managerdefinitions/include/ConfigParsingUtils.h index a39006e..78d2cdf 100644 --- a/services/audiopolicy/common/managerdefinitions/include/ConfigParsingUtils.h +++ b/services/audiopolicy/common/managerdefinitions/include/ConfigParsingUtils.h @@ -73,6 +73,7 @@ const StringToEnum sDeviceTypeToEnumTable[] = { STRING_TO_ENUM(AUDIO_DEVICE_OUT_SPDIF), STRING_TO_ENUM(AUDIO_DEVICE_OUT_FM), STRING_TO_ENUM(AUDIO_DEVICE_OUT_AUX_LINE), + STRING_TO_ENUM(AUDIO_DEVICE_OUT_IP), STRING_TO_ENUM(AUDIO_DEVICE_IN_AMBIENT), STRING_TO_ENUM(AUDIO_DEVICE_IN_BUILTIN_MIC), STRING_TO_ENUM(AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET), @@ -94,6 +95,7 @@ const StringToEnum sDeviceTypeToEnumTable[] = { STRING_TO_ENUM(AUDIO_DEVICE_IN_SPDIF), STRING_TO_ENUM(AUDIO_DEVICE_IN_BLUETOOTH_A2DP), STRING_TO_ENUM(AUDIO_DEVICE_IN_LOOPBACK), + STRING_TO_ENUM(AUDIO_DEVICE_IN_IP), }; const StringToEnum sDeviceNameToEnumTable[] = { @@ -124,6 +126,7 @@ const StringToEnum sDeviceNameToEnumTable[] = { NAME_TO_ENUM("S/PDIF Out", AUDIO_DEVICE_OUT_SPDIF), NAME_TO_ENUM("FM transceiver Out", AUDIO_DEVICE_OUT_FM), NAME_TO_ENUM("Aux Line Out", AUDIO_DEVICE_OUT_AUX_LINE), + NAME_TO_ENUM("IP Out", AUDIO_DEVICE_OUT_IP), NAME_TO_ENUM("Ambient Mic", AUDIO_DEVICE_IN_AMBIENT), NAME_TO_ENUM("Built-In Mic", AUDIO_DEVICE_IN_BUILTIN_MIC), NAME_TO_ENUM("BT SCO Headset Mic", AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET), @@ -145,6 +148,7 @@ const StringToEnum sDeviceNameToEnumTable[] = { NAME_TO_ENUM("S/PDIF In", AUDIO_DEVICE_IN_SPDIF), NAME_TO_ENUM("BT A2DP In", AUDIO_DEVICE_IN_BLUETOOTH_A2DP), NAME_TO_ENUM("Loopback In", AUDIO_DEVICE_IN_LOOPBACK), + NAME_TO_ENUM("IP In", AUDIO_DEVICE_IN_IP), }; const StringToEnum sOutputFlagNameToEnumTable[] = { @@ -156,11 +160,15 @@ const StringToEnum sOutputFlagNameToEnumTable[] = { STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_NON_BLOCKING), STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_HW_AV_SYNC), STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_TTS), + STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_RAW), + STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_SYNC), }; const StringToEnum sInputFlagNameToEnumTable[] = { STRING_TO_ENUM(AUDIO_INPUT_FLAG_FAST), STRING_TO_ENUM(AUDIO_INPUT_FLAG_HW_HOTWORD), + STRING_TO_ENUM(AUDIO_INPUT_FLAG_RAW), + STRING_TO_ENUM(AUDIO_INPUT_FLAG_SYNC), }; const StringToEnum sFormatNameToEnumTable[] = { diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp index ee25b71..6983b5c 100644 --- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp +++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp @@ -427,7 +427,7 @@ void AudioPolicyManager::setPhoneState(audio_mode_t state) /// Opens: can these line be executed after the switch of volume curves??? // if leaving call state, handle special case of active streams // pertaining to sonification strategy see handleIncallSonification() - if (isInCall()) { + if (isStateInCall(oldState)) { ALOGV("setPhoneState() in call state management: new state is %d", state); for (int stream = 0; stream < AUDIO_STREAM_CNT; stream++) { if (stream == AUDIO_STREAM_PATCH) { @@ -436,7 +436,7 @@ void AudioPolicyManager::setPhoneState(audio_mode_t state) handleIncallSonification((audio_stream_type_t)stream, false, true); } - // force reevaluating accessibility routing when call starts + // force reevaluating accessibility routing when call stops mpClientInterface->invalidateStream(AUDIO_STREAM_ACCESSIBILITY); } @@ -514,6 +514,9 @@ void AudioPolicyManager::setPhoneState(audio_mode_t state) } handleIncallSonification((audio_stream_type_t)stream, true, true); } + + // force reevaluating accessibility routing when call starts + mpClientInterface->invalidateStream(AUDIO_STREAM_ACCESSIBILITY); } // Flag that ringtone volume must be limited to music volume until we exit MODE_RINGTONE diff --git a/services/audiopolicy/service/AudioPolicyService.cpp b/services/audiopolicy/service/AudioPolicyService.cpp index fbe4f18..eefff3d 100644 --- a/services/audiopolicy/service/AudioPolicyService.cpp +++ b/services/audiopolicy/service/AudioPolicyService.cpp @@ -930,6 +930,7 @@ void AudioPolicyService::AudioCommandThread::insertCommand_l(sp<AudioCommand>& c patch2 = ((CreateAudioPatchData *)command2->mParam.get())->mPatch; } else { handle2 = ((ReleaseAudioPatchData *)command2->mParam.get())->mHandle; + memset(&patch2, 0, sizeof(patch2)); } if (handle != handle2) break; /* Filter CREATE_AUDIO_PATCH commands only when they are issued for diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp index f42fada..92df4e3 100644 --- a/services/camera/libcameraservice/CameraService.cpp +++ b/services/camera/libcameraservice/CameraService.cpp @@ -1292,7 +1292,7 @@ void CameraService::notifySystemEvent(int32_t eventId, const int32_t* args, size status_t CameraService::addListener(const sp<ICameraServiceListener>& listener) { ALOGV("%s: Add listener %p", __FUNCTION__, listener.get()); - if (listener == 0) { + if (listener == nullptr) { ALOGE("%s: Listener must not be null", __FUNCTION__); return BAD_VALUE; } diff --git a/services/camera/libcameraservice/common/CameraModule.cpp b/services/camera/libcameraservice/common/CameraModule.cpp index 85d4488..1ae01ae 100644 --- a/services/camera/libcameraservice/common/CameraModule.cpp +++ b/services/camera/libcameraservice/common/CameraModule.cpp @@ -154,6 +154,18 @@ CameraModule::CameraModule(camera_module_t *module) { mCameraInfoMap.setCapacity(getNumberOfCameras()); } +CameraModule::~CameraModule() +{ + while (mCameraInfoMap.size() > 0) { + camera_info cameraInfo = mCameraInfoMap.editValueAt(0); + if (cameraInfo.static_camera_characteristics != NULL) { + free_camera_metadata( + const_cast<camera_metadata_t*>(cameraInfo.static_camera_characteristics)); + } + mCameraInfoMap.removeItemsAt(0); + } +} + int CameraModule::init() { if (getModuleApiVersion() >= CAMERA_MODULE_API_VERSION_2_4 && mModule->init != NULL) { @@ -192,12 +204,9 @@ int CameraModule::getCameraInfo(int cameraId, struct camera_info *info) { CameraMetadata m; m = rawInfo.static_camera_characteristics; deriveCameraCharacteristicsKeys(rawInfo.device_version, m); - mCameraCharacteristicsMap.add(cameraId, m); cameraInfo = rawInfo; - cameraInfo.static_camera_characteristics = - mCameraCharacteristicsMap.valueFor(cameraId).getAndLock(); - mCameraInfoMap.add(cameraId, cameraInfo); - index = mCameraInfoMap.indexOfKey(cameraId); + cameraInfo.static_camera_characteristics = m.release(); + index = mCameraInfoMap.add(cameraId, cameraInfo); } assert(index != NAME_NOT_FOUND); diff --git a/services/camera/libcameraservice/common/CameraModule.h b/services/camera/libcameraservice/common/CameraModule.h index c21092e..36822c7 100644 --- a/services/camera/libcameraservice/common/CameraModule.h +++ b/services/camera/libcameraservice/common/CameraModule.h @@ -33,6 +33,7 @@ namespace android { class CameraModule { public: CameraModule(camera_module_t *module); + virtual ~CameraModule(); // Must be called after construction // Returns OK on success, NO_INIT on failure @@ -60,7 +61,6 @@ private: camera_module_t *mModule; KeyedVector<int, camera_info> mCameraInfoMap; - KeyedVector<int, CameraMetadata> mCameraCharacteristicsMap; Mutex mCameraInfoLock; }; diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp index 4b55dad..9e73b5c 100644 --- a/services/camera/libcameraservice/device3/Camera3Device.cpp +++ b/services/camera/libcameraservice/device3/Camera3Device.cpp @@ -164,9 +164,17 @@ status_t Camera3Device::initialize(CameraModule *module) return res; } - /** Start up request queue thread */ + bool aeLockAvailable = false; + camera_metadata_ro_entry aeLockAvailableEntry; + res = find_camera_metadata_ro_entry(info.static_camera_characteristics, + ANDROID_CONTROL_AE_LOCK_AVAILABLE, &aeLockAvailableEntry); + if (res == OK && aeLockAvailableEntry.count > 0) { + aeLockAvailable = (aeLockAvailableEntry.data.u8[0] == + ANDROID_CONTROL_AE_LOCK_AVAILABLE_TRUE); + } - mRequestThread = new RequestThread(this, mStatusTracker, device); + /** Start up request queue thread */ + mRequestThread = new RequestThread(this, mStatusTracker, device, aeLockAvailable); res = mRequestThread->run(String8::format("C3Dev-%d-ReqQueue", mId).string()); if (res != OK) { SET_ERR_L("Unable to start request queue thread: %s (%d)", @@ -2472,7 +2480,8 @@ CameraMetadata Camera3Device::getLatestRequestLocked() { Camera3Device::RequestThread::RequestThread(wp<Camera3Device> parent, sp<StatusTracker> statusTracker, - camera3_device_t *hal3Device) : + camera3_device_t *hal3Device, + bool aeLockAvailable) : Thread(/*canCallJava*/false), mParent(parent), mStatusTracker(statusTracker), @@ -2485,19 +2494,9 @@ Camera3Device::RequestThread::RequestThread(wp<Camera3Device> parent, mLatestRequestId(NAME_NOT_FOUND), mCurrentAfTriggerId(0), mCurrentPreCaptureTriggerId(0), - mRepeatingLastFrameNumber(NO_IN_FLIGHT_REPEATING_FRAMES) { + mRepeatingLastFrameNumber(NO_IN_FLIGHT_REPEATING_FRAMES), + mAeLockAvailable(aeLockAvailable) { mStatusId = statusTracker->addComponent(); - - mAeLockAvailable = false; - sp<Camera3Device> p = parent.promote(); - if (p != NULL) { - camera_metadata_ro_entry aeLockAvailable = - p->info().find(ANDROID_CONTROL_AE_LOCK_AVAILABLE); - if (aeLockAvailable.count > 0) { - mAeLockAvailable = (aeLockAvailable.data.u8[0] == - ANDROID_CONTROL_AE_LOCK_AVAILABLE_TRUE); - } - } } void Camera3Device::RequestThread::setNotificationListener( diff --git a/services/camera/libcameraservice/device3/Camera3Device.h b/services/camera/libcameraservice/device3/Camera3Device.h index bb4bcc4..31b6132 100644 --- a/services/camera/libcameraservice/device3/Camera3Device.h +++ b/services/camera/libcameraservice/device3/Camera3Device.h @@ -389,7 +389,8 @@ class Camera3Device : RequestThread(wp<Camera3Device> parent, sp<camera3::StatusTracker> statusTracker, - camera3_device_t *hal3Device); + camera3_device_t *hal3Device, + bool aeLockAvailable); void setNotificationListener(NotificationListener *listener); |