From 985fd30a10f6fec4293f071fd258c4726cff5a3d Mon Sep 17 00:00:00 2001 From: Igor Murashkin Date: Wed, 20 Feb 2013 18:24:43 -0800 Subject: Camera: ProCamera2Client - add createStream (service is stubbed) and unit test Change-Id: I1ae7ba9b24f5883c214c19a7ed0eaf0c802d69c1 --- camera/IProCameraUser.cpp | 178 +++++++-- camera/ProCamera.cpp | 25 +- camera/tests/ProCameraTests.cpp | 20 +- include/camera/IProCameraUser.h | 10 + include/camera/ProCamera.h | 2 +- services/camera/libcameraservice/Android.mk | 1 + services/camera/libcameraservice/CameraService.cpp | 4 +- .../camera/libcameraservice/ProCamera2Client.cpp | 396 +++++++++++++++++++++ .../camera/libcameraservice/ProCamera2Client.h | 156 ++++++++ 9 files changed, 736 insertions(+), 56 deletions(-) create mode 100644 services/camera/libcameraservice/ProCamera2Client.cpp create mode 100644 services/camera/libcameraservice/ProCamera2Client.h diff --git a/camera/IProCameraUser.cpp b/camera/IProCameraUser.cpp index 76c2dcd..cd7bf5c 100644 --- a/camera/IProCameraUser.cpp +++ b/camera/IProCameraUser.cpp @@ -42,8 +42,78 @@ enum { CANCEL_REQUEST, REQUEST_STREAM, CANCEL_STREAM, + CREATE_STREAM, + CREATE_DEFAULT_REQUEST, }; +/** + * Caller becomes the owner of the new metadata + * 'const Parcel' doesnt prevent us from calling the read functions. + * which is interesting since it changes the internal state + */ +void readMetadata(const Parcel& data, camera_metadata_t** out) { + camera_metadata_t* metadata; + + // arg0 = metadataSize (int32) + size_t metadataSize = static_cast(data.readInt32()); + + if (metadataSize == 0) { + if (out) { + *out = NULL; + } + return; + } + + // NOTE: this doesn't make sense to me. shouldnt the blob + // know how big it is? why do we have to specify the size + // to Parcel::readBlob ? + + ReadableBlob blob; + // arg1 = metadata (blob) + { + data.readBlob(metadataSize, &blob); + const camera_metadata_t* tmp = + reinterpret_cast(blob.data()); + size_t entry_capacity = get_camera_metadata_entry_capacity(tmp); + size_t data_capacity = get_camera_metadata_data_capacity(tmp); + + metadata = allocate_camera_metadata(entry_capacity, data_capacity); + copy_camera_metadata(metadata, metadataSize, tmp); + } + blob.release(); + + if (out) { + *out = metadata; + } else { + free_camera_metadata(metadata); + } +} + +/** + * Caller retains ownership of metadata + * - Write 2 (int32 + blob) args in the current position + */ +void writeMetadata(Parcel& data, camera_metadata_t* metadata) { + // arg0 = metadataSize (int32) + size_t metadataSize; + + if (metadata == NULL) { + data.writeInt32(0); + return; + } + + metadataSize = get_camera_metadata_compact_size(metadata); + data.writeInt32(static_cast(metadataSize)); + + // arg1 = metadata (blob) + WritableBlob blob; + { + data.writeBlob(metadataSize, &blob); + copy_camera_metadata(blob.data(), metadataSize, metadata); + } + blob.release(); +} + class BpProCameraUser: public BpInterface { public: @@ -109,17 +179,8 @@ public: Parcel data, reply; data.writeInterfaceToken(IProCameraUser::getInterfaceDescriptor()); - // arg0 = metadataSize (int32) - size_t metadataSize = get_camera_metadata_compact_size(metadata); - data.writeInt32(static_cast(metadataSize)); - - // arg1 = metadata (blob) - WritableBlob blob; - { - data.writeBlob(metadataSize, &blob); - copy_camera_metadata(blob.data(), metadataSize, metadata); - } - blob.release(); + // arg0+arg1 + writeMetadata(data, metadata); // arg2 = streaming (bool) data.writeInt32(streaming); @@ -157,6 +218,44 @@ public: return reply.readInt32(); } + virtual status_t createStream(int width, int height, int format, + const sp& surface, + /*out*/ + int* streamId) + { + Parcel data, reply; + data.writeInterfaceToken(IProCameraUser::getInterfaceDescriptor()); + data.writeInt32(width); + data.writeInt32(height); + data.writeInt32(format); + + Surface::writeToParcel(surface, &data); + remote()->transact(CREATE_STREAM, data, &reply); + + int sId = reply.readInt32(); + if (streamId) { + *streamId = sId; + } + return reply.readInt32(); + } + + // Create a request object from a template. + virtual status_t createDefaultRequest(int templateId, + /*out*/ + camera_metadata** request) + { + Parcel data, reply; + data.writeInterfaceToken(IProCameraUser::getInterfaceDescriptor()); + data.writeInt32(templateId); + remote()->transact(CREATE_DEFAULT_REQUEST, data, &reply); + readMetadata(reply, /*out*/request); + return reply.readInt32(); + } + + +private: + + }; IMPLEMENT_META_INTERFACE(ProCameraUser, "android.hardware.IProCameraUser"); @@ -205,28 +304,7 @@ status_t BnProCameraUser::onTransact( case SUBMIT_REQUEST: { CHECK_INTERFACE(IProCameraUser, data, reply); camera_metadata_t* metadata; - - // arg0 = metadataSize (int32) - size_t metadataSize = static_cast(data.readInt32()); - - // NOTE: this doesn't make sense to me. shouldnt the blob - // know how big it is? why do we have to specify the size - // to Parcel::readBlob ? - - ReadableBlob blob; - // arg1 = metadata (blob) - { - data.readBlob(metadataSize, &blob); - const camera_metadata_t* tmp = - reinterpret_cast(blob.data()); - size_t entry_capacity = get_camera_metadata_entry_capacity(tmp); - size_t data_capacity = get_camera_metadata_data_capacity(tmp); - - metadata = allocate_camera_metadata(entry_capacity, - data_capacity); - copy_camera_metadata(metadata, metadataSize, tmp); - } - blob.release(); + readMetadata(data, /*out*/&metadata); // arg2 = streaming (bool) bool streaming = data.readInt32(); @@ -254,6 +332,40 @@ status_t BnProCameraUser::onTransact( reply->writeInt32(cancelStream(streamId)); return NO_ERROR; } break; + case CREATE_STREAM: { + CHECK_INTERFACE(IProCameraUser, data, reply); + int width, height, format; + + width = data.readInt32(); + height = data.readInt32(); + format = data.readInt32(); + + sp surface = Surface::readFromParcel(data); + + int streamId = -1; + status_t ret; + ret = createStream(width, height, format, surface, &streamId); + + reply->writeInt32(streamId); + reply->writeInt32(ret); + + return NO_ERROR; + } break; + + case CREATE_DEFAULT_REQUEST: { + CHECK_INTERFACE(IProCameraUser, data, reply); + + int templateId = data.readInt32(); + + camera_metadata_t* request = NULL; + status_t ret; + ret = createDefaultRequest(templateId, &request); + + writeMetadata(*reply, request); + reply->writeInt32(ret); + + return NO_ERROR; + } break; default: return BBinder::onTransact(code, data, reply, flags); } diff --git a/camera/ProCamera.cpp b/camera/ProCamera.cpp index 26e4de9..92ec9d6 100644 --- a/camera/ProCamera.cpp +++ b/camera/ProCamera.cpp @@ -262,7 +262,7 @@ status_t ProCamera::cancelStream(int streamId) } status_t ProCamera::createStream(int width, int height, int format, - const sp& window, + const sp& surface, /*out*/ int* streamId) { @@ -271,12 +271,14 @@ status_t ProCamera::createStream(int width, int height, int format, ALOGV("%s: createStreamW %dx%d (fmt=0x%x)", __FUNCTION__, width, height, format); - if (window == 0) { + if (surface == 0) { return BAD_VALUE; } - // TODO: actually implement this in IProCamera - return INVALID_OPERATION; + sp c = mCamera; + if (c == 0) return NO_INIT; + + return c->createStream(width, height, format, surface, streamId); } status_t ProCamera::createStream(int width, int height, int format, @@ -288,13 +290,10 @@ status_t ProCamera::createStream(int width, int height, int format, format); sp binder; - sp window; + status_t stat = INVALID_OPERATION; if (bufferProducer != 0) { binder = bufferProducer->asBinder(); - window = new Surface(bufferProducer); - - status_t stat = createStream(width, height, format, window, streamId); ALOGV("%s: createStreamT END (%d), StreamID = %d", __FUNCTION__, stat, *streamId); @@ -304,7 +303,7 @@ status_t ProCamera::createStream(int width, int height, int format, return BAD_VALUE; } - return BAD_VALUE; + return stat; } int ProCamera::getNumberOfCameras() { @@ -321,12 +320,12 @@ camera_metadata* ProCamera::getCameraInfo(int cameraId) { status_t ProCamera::createDefaultRequest(int templateId, camera_metadata** request) const { - ALOGE("%s: not implemented yet", __FUNCTION__); - ALOGV("%s: templateId = %d", __FUNCTION__, templateId); - *request = NULL; - return INVALID_OPERATION; + sp c = mCamera; + if (c == 0) return NO_INIT; + + return c->createDefaultRequest(templateId, request); } }; // namespace android diff --git a/camera/tests/ProCameraTests.cpp b/camera/tests/ProCameraTests.cpp index d632b7e..230e160 100644 --- a/camera/tests/ProCameraTests.cpp +++ b/camera/tests/ProCameraTests.cpp @@ -317,14 +317,12 @@ TEST_F(ProCameraTest, StreamingImage) { } sp surface; - sp window; if (mDisplaySecs > 0) { createOnScreenSurface(/*out*/surface); - window = surface; } int streamId = -1; EXPECT_OK(mCamera->createStream(/*width*/640, /*height*/480, TEST_FORMAT, - window, &streamId)); + surface, &streamId)); EXPECT_NE(-1, streamId); EXPECT_OK(mCamera->exclusiveTryLock()); @@ -351,8 +349,16 @@ TEST_F(ProCameraTest, StreamingImage) { uint32_t tag = static_cast(ANDROID_REQUEST_OUTPUT_STREAMS); int find = find_camera_metadata_entry(request, tag, &entry); if (find == -ENOENT) { - ASSERT_OK(add_camera_metadata_entry(request, tag, &streamId, - /*data_count*/1)); + if (add_camera_metadata_entry(request, tag, &streamId, /*data_count*/1) + != OK) { + camera_metadata_t *tmp = allocate_camera_metadata(1000, 10000); + ASSERT_OK(append_camera_metadata(tmp, request)); + free_camera_metadata(request); + request = tmp; + + ASSERT_OK(add_camera_metadata_entry(request, tag, &streamId, + /*data_count*/1)); + } } else { ASSERT_OK(update_camera_metadata_entry(request, entry.index, &streamId, /*data_count*/1, &entry)); @@ -360,10 +366,8 @@ TEST_F(ProCameraTest, StreamingImage) { EXPECT_OK(mCamera->submitRequest(request, /*streaming*/true)); + dout << "will sleep now for " << mDisplaySecs << std::endl; sleep(mDisplaySecs); - //should the window be empty until the buffer is flipped? - // that would certainly make sense - free_camera_metadata(request); EXPECT_OK(mCamera->cancelStream(streamId)); diff --git a/include/camera/IProCameraUser.h b/include/camera/IProCameraUser.h index 6170410..3ef4676 100644 --- a/include/camera/IProCameraUser.h +++ b/include/camera/IProCameraUser.h @@ -63,6 +63,16 @@ public: virtual status_t requestStream(int streamId) = 0; virtual status_t cancelStream(int streamId) = 0; + virtual status_t createStream(int width, int height, int format, + const sp& surface, + /*out*/ + int* streamId) = 0; + + // Create a request object from a template. + virtual status_t createDefaultRequest(int templateId, + /*out*/ + camera_metadata** request) + = 0; }; diff --git a/include/camera/ProCamera.h b/include/camera/ProCamera.h index 7191b07..9b763a3 100644 --- a/include/camera/ProCamera.h +++ b/include/camera/ProCamera.h @@ -132,7 +132,7 @@ public: * Errors: -EBUSY if too many streams created */ status_t createStream(int width, int height, int format, - const sp& window, + const sp& surface, /*out*/ int* streamId); diff --git a/services/camera/libcameraservice/Android.mk b/services/camera/libcameraservice/Android.mk index b6ebd02..c7a8e4a 100644 --- a/services/camera/libcameraservice/Android.mk +++ b/services/camera/libcameraservice/Android.mk @@ -10,6 +10,7 @@ LOCAL_SRC_FILES:= \ CameraService.cpp \ CameraClient.cpp \ Camera2Client.cpp \ + ProCamera2Client.cpp \ Camera2Device.cpp \ camera2/Parameters.cpp \ camera2/FrameProcessor.cpp \ diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp index 4941965..eb8bc05 100644 --- a/services/camera/libcameraservice/CameraService.cpp +++ b/services/camera/libcameraservice/CameraService.cpp @@ -39,6 +39,7 @@ #include "CameraService.h" #include "CameraClient.h" #include "Camera2Client.h" +#include "ProCamera2Client.h" namespace android { @@ -281,7 +282,8 @@ sp CameraService::connect( return NULL; break; case CAMERA_DEVICE_API_VERSION_2_0: - client = new ProClient(this, cameraCb, cameraId, + case CAMERA_DEVICE_API_VERSION_2_1: + client = new ProCamera2Client(this, cameraCb, cameraId, facing, callingPid, getpid()); break; case -1: diff --git a/services/camera/libcameraservice/ProCamera2Client.cpp b/services/camera/libcameraservice/ProCamera2Client.cpp new file mode 100644 index 0000000..d6389a1 --- /dev/null +++ b/services/camera/libcameraservice/ProCamera2Client.cpp @@ -0,0 +1,396 @@ +/* + * Copyright (C) 2013 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 "ProCamera2Client" +#define ATRACE_TAG ATRACE_TAG_CAMERA +//#define LOG_NDEBUG 0 + +#include +#include + +#include +#include +#include +#include "camera2/Parameters.h" +#include "ProCamera2Client.h" + +namespace android { +using namespace camera2; + +static int getCallingPid() { + return IPCThreadState::self()->getCallingPid(); +} + +static int getCallingUid() { + return IPCThreadState::self()->getCallingUid(); +} + +// Interface used by CameraService + +ProCamera2Client::ProCamera2Client(const sp& cameraService, + const sp& remoteCallback, + int cameraId, + int cameraFacing, + int clientPid, + int servicePid): + ProClient(cameraService, remoteCallback, + cameraId, cameraFacing, clientPid, servicePid), + mSharedCameraCallbacks(remoteCallback) +{ + ATRACE_CALL(); + ALOGI("ProCamera %d: Opened", cameraId); + + mDevice = new Camera2Device(cameraId); + + mExclusiveLock = false; +} + +status_t ProCamera2Client::checkPid(const char* checkLocation) const { + int callingPid = getCallingPid(); + if (callingPid == mClientPid) return NO_ERROR; + + ALOGE("%s: attempt to use a locked camera from a different process" + " (old pid %d, new pid %d)", checkLocation, mClientPid, callingPid); + return PERMISSION_DENIED; +} + +status_t ProCamera2Client::initialize(camera_module_t *module) +{ + ATRACE_CALL(); + ALOGV("%s: Initializing client for camera %d", __FUNCTION__, mCameraId); + status_t res; + + res = mDevice->initialize(module); + if (res != OK) { + ALOGE("%s: Camera %d: unable to initialize device: %s (%d)", + __FUNCTION__, mCameraId, strerror(-res), res); + return NO_INIT; + } + + res = mDevice->setNotifyCallback(this); + + return OK; +} + +ProCamera2Client::~ProCamera2Client() { + ATRACE_CALL(); + + mDestructionStarted = true; + + disconnect(); + + ALOGI("ProCamera %d: Closed", mCameraId); +} + +status_t ProCamera2Client::exclusiveTryLock() { + ATRACE_CALL(); + ALOGV("%s", __FUNCTION__); + + Mutex::Autolock icl(mIProCameraUserLock); + SharedCameraCallbacks::Lock l(mSharedCameraCallbacks); + + if (!mExclusiveLock) { + mExclusiveLock = true; + + if (mRemoteCallback != NULL) { + mRemoteCallback->onLockStatusChanged( + IProCameraCallbacks::LOCK_ACQUIRED); + } + + ALOGV("%s: exclusive lock acquired", __FUNCTION__); + + return OK; + } + + // TODO: have a PERMISSION_DENIED case for when someone else owns the lock + + // don't allow recursive locking + ALOGW("%s: exclusive lock already exists - recursive locking is not" + "allowed", __FUNCTION__); + + return ALREADY_EXISTS; +} + +status_t ProCamera2Client::exclusiveLock() { + ATRACE_CALL(); + ALOGV("%s", __FUNCTION__); + + Mutex::Autolock icl(mIProCameraUserLock); + SharedCameraCallbacks::Lock l(mSharedCameraCallbacks); + + /** + * TODO: this should asynchronously 'wait' until the lock becomes available + * if another client already has an exclusive lock. + * + * once we have proper sharing support this will need to do + * more than just return immediately + */ + if (!mExclusiveLock) { + mExclusiveLock = true; + + if (mRemoteCallback != NULL) { + mRemoteCallback->onLockStatusChanged(IProCameraCallbacks::LOCK_ACQUIRED); + } + + ALOGV("%s: exclusive lock acquired", __FUNCTION__); + + return OK; + } + + // don't allow recursive locking + ALOGW("%s: exclusive lock already exists - recursive locking is not allowed" + , __FUNCTION__); + return ALREADY_EXISTS; +} + +status_t ProCamera2Client::exclusiveUnlock() { + ATRACE_CALL(); + ALOGV("%s", __FUNCTION__); + + Mutex::Autolock icl(mIProCameraUserLock); + SharedCameraCallbacks::Lock l(mSharedCameraCallbacks); + + // don't allow unlocking if we have no lock + if (!mExclusiveLock) { + ALOGW("%s: cannot unlock, no lock was held in the first place", + __FUNCTION__); + return BAD_VALUE; + } + + mExclusiveLock = false; + if (mRemoteCallback != NULL ) { + mRemoteCallback->onLockStatusChanged( + IProCameraCallbacks::LOCK_RELEASED); + } + ALOGV("%s: exclusive lock released", __FUNCTION__); + + return OK; +} + +bool ProCamera2Client::hasExclusiveLock() { + return mExclusiveLock; +} + +status_t ProCamera2Client::submitRequest(camera_metadata_t* request, + bool streaming) { + ATRACE_CALL(); + ALOGV("%s", __FUNCTION__); + + Mutex::Autolock icl(mIProCameraUserLock); + if (!mExclusiveLock) { + return PERMISSION_DENIED; + } + + ALOGE("%s: not fully implemented yet", __FUNCTION__); + free_camera_metadata(request); + return OK; +} + +status_t ProCamera2Client::cancelRequest(int requestId) { + ATRACE_CALL(); + ALOGV("%s", __FUNCTION__); + + Mutex::Autolock icl(mIProCameraUserLock); + if (!mExclusiveLock) { + return PERMISSION_DENIED; + } + + ALOGE("%s: not fully implemented yet", __FUNCTION__); + return OK; +} + +status_t ProCamera2Client::requestStream(int streamId) { + ALOGE("%s: not implemented yet", __FUNCTION__); + + return INVALID_OPERATION; +} + +status_t ProCamera2Client::cancelStream(int streamId) { + ALOGE("%s: not implemented yet", __FUNCTION__); + + return INVALID_OPERATION; +} + +status_t ProCamera2Client::createStream(int width, int height, int format, + const sp& surface, + /*out*/ + int* streamId) { + ALOGE("%s: not implemented yet", __FUNCTION__); + + return INVALID_OPERATION; +} + +status_t ProCamera2Client::createDefaultRequest(int templateId, + /*out*/ + camera_metadata** request) { + ALOGE("%s: not implemented yet", __FUNCTION__); + + return INVALID_OPERATION; +} + + + + + +status_t ProCamera2Client::dump(int fd, const Vector& args) { + String8 result; + result.appendFormat("ProCamera2Client[%d] (%p) PID: %d, dump:\n", + mCameraId, + getRemoteCallback()->asBinder().get(), + mClientPid); + result.append(" State: "); + + // TODO: print dynamic/request section from most recent requests + +#define CASE_APPEND_ENUM(x) case x: result.append(#x "\n"); break; + + result = " Device dump:\n"; + write(fd, result.string(), result.size()); + + status_t res = mDevice->dump(fd, args); + if (res != OK) { + result = String8::format(" Error dumping device: %s (%d)", + strerror(-res), res); + write(fd, result.string(), result.size()); + } + +#undef CASE_APPEND_ENUM + return NO_ERROR; +} + +// IProCameraUser interface + +void ProCamera2Client::disconnect() { + ATRACE_CALL(); + Mutex::Autolock icl(mIProCameraUserLock); + status_t res; + + // Allow both client and the media server to disconnect at all times + int callingPid = getCallingPid(); + if (callingPid != mClientPid && callingPid != mServicePid) return; + + if (mDevice == 0) return; + + ALOGV("Camera %d: Shutting down", mCameraId); + ALOGV("Camera %d: Waiting for threads", mCameraId); + ALOGV("Camera %d: Disconnecting device", mCameraId); + + mDevice->disconnect(); + + mDevice.clear(); + + ProClient::disconnect(); +} + +status_t ProCamera2Client::connect(const sp& client) { + ATRACE_CALL(); + ALOGV("%s: E", __FUNCTION__); + Mutex::Autolock icl(mIProCameraUserLock); + + if (mClientPid != 0 && getCallingPid() != mClientPid) { + ALOGE("%s: Camera %d: Connection attempt from pid %d; " + "current locked to pid %d", __FUNCTION__, + mCameraId, getCallingPid(), mClientPid); + return BAD_VALUE; + } + + mClientPid = getCallingPid(); + + mRemoteCallback = client; + mSharedCameraCallbacks = client; + + return OK; +} + +/** Device-related methods */ + +void ProCamera2Client::notifyError(int errorCode, int arg1, int arg2) { + ALOGE("Error condition %d reported by HAL, arguments %d, %d", errorCode, + arg1, arg2); +} + +void ProCamera2Client::notifyShutter(int frameNumber, nsecs_t timestamp) { + ALOGV("%s: Shutter notification for frame %d at time %lld", __FUNCTION__, + frameNumber, timestamp); +} + +void ProCamera2Client::notifyAutoFocus(uint8_t newState, int triggerId) { + ALOGV("%s: Autofocus state now %d, last trigger %d", + __FUNCTION__, newState, triggerId); + + SharedCameraCallbacks::Lock l(mSharedCameraCallbacks); + if (l.mRemoteCallback != 0) { + l.mRemoteCallback->notifyCallback(CAMERA_MSG_FOCUS_MOVE, + 1, 0); + } + if (l.mRemoteCallback != 0) { + l.mRemoteCallback->notifyCallback(CAMERA_MSG_FOCUS, + 1, 0); + } +} + +void ProCamera2Client::notifyAutoExposure(uint8_t newState, int triggerId) { + ALOGV("%s: Autoexposure state now %d, last trigger %d", + __FUNCTION__, newState, triggerId); +} + +void ProCamera2Client::notifyAutoWhitebalance(uint8_t newState, int triggerId) { + ALOGV("%s: Auto-whitebalance state now %d, last trigger %d", + __FUNCTION__, newState, triggerId); +} + +int ProCamera2Client::getCameraId() const { + return mCameraId; +} + +const sp& ProCamera2Client::getCameraDevice() { + return mDevice; +} + +const sp& ProCamera2Client::getCameraService() { + return mCameraService; +} + +ProCamera2Client::SharedCameraCallbacks::Lock::Lock( + SharedCameraCallbacks &client): + mRemoteCallback(client.mRemoteCallback), + mSharedClient(client) { + mSharedClient.mRemoteCallbackLock.lock(); +} + +ProCamera2Client::SharedCameraCallbacks::Lock::~Lock() { + mSharedClient.mRemoteCallbackLock.unlock(); +} + +ProCamera2Client::SharedCameraCallbacks::SharedCameraCallbacks + (const sp&client): + mRemoteCallback(client) { +} + +ProCamera2Client::SharedCameraCallbacks& + ProCamera2Client::SharedCameraCallbacks::operator=( + const sp&client) { + Mutex::Autolock l(mRemoteCallbackLock); + mRemoteCallback = client; + return *this; +} + +void ProCamera2Client::SharedCameraCallbacks::clear() { + Mutex::Autolock l(mRemoteCallbackLock); + mRemoteCallback.clear(); +} + +} // namespace android diff --git a/services/camera/libcameraservice/ProCamera2Client.h b/services/camera/libcameraservice/ProCamera2Client.h new file mode 100644 index 0000000..8f76819 --- /dev/null +++ b/services/camera/libcameraservice/ProCamera2Client.h @@ -0,0 +1,156 @@ +/* + * Copyright (C) 2013 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 ANDROID_SERVERS_CAMERA_PROCAMERA2CLIENT_H +#define ANDROID_SERVERS_CAMERA_PROCAMERA2CLIENT_H + +#include "Camera2Device.h" +#include "CameraService.h" + +namespace android { + +class IMemory; +/** + * Implements the binder IProCameraUser API, + * meant for HAL2-level private API access. + */ +class ProCamera2Client : + public CameraService::ProClient, + public Camera2Device::NotificationListener +{ +public: + /** + * IProCameraUser interface (see IProCameraUser for details) + */ + virtual status_t connect(const sp& callbacks); + virtual void disconnect(); + + virtual status_t exclusiveTryLock(); + virtual status_t exclusiveLock(); + virtual status_t exclusiveUnlock(); + + virtual bool hasExclusiveLock(); + + // Note that the callee gets a copy of the metadata. + virtual int submitRequest(camera_metadata_t* metadata, + bool streaming = false); + virtual status_t cancelRequest(int requestId); + + virtual status_t requestStream(int streamId); + virtual status_t cancelStream(int streamId); + + virtual status_t createStream(int width, int height, int format, + const sp& surface, + /*out*/ + int* streamId); + + // Create a request object from a template. + virtual status_t createDefaultRequest(int templateId, + /*out*/ + camera_metadata** request); + + + /** + * Interface used by CameraService + */ + + ProCamera2Client(const sp& cameraService, + const sp& remoteCallback, + int cameraId, + int cameraFacing, + int clientPid, + int servicePid); + virtual ~ProCamera2Client(); + + status_t initialize(camera_module_t *module); + + virtual status_t dump(int fd, const Vector& args); + + /** + * Interface used by Camera2Device + */ + + virtual void notifyError(int errorCode, int arg1, int arg2); + virtual void notifyShutter(int frameNumber, nsecs_t timestamp); + virtual void notifyAutoFocus(uint8_t newState, int triggerId); + virtual void notifyAutoExposure(uint8_t newState, int triggerId); + virtual void notifyAutoWhitebalance(uint8_t newState, int triggerId); + + + int getCameraId() const; + const sp& getCameraDevice(); + const sp& getCameraService(); + + /** + * Interface used by independent components of ProCamera2Client. + */ + + // Simple class to ensure that access to IProCameraCallbacks is serialized + // by requiring mRemoteCallbackLock to be locked before access to + // mCameraClient is possible. + class SharedCameraCallbacks { + public: + class Lock { + public: + Lock(SharedCameraCallbacks &client); + ~Lock(); + sp &mRemoteCallback; + private: + SharedCameraCallbacks &mSharedClient; + }; + SharedCameraCallbacks(const sp& client); + SharedCameraCallbacks& operator=(const sp& client); + void clear(); + private: + sp mRemoteCallback; + mutable Mutex mRemoteCallbackLock; + } mSharedCameraCallbacks; + +private: + /** IProCameraUser interface-related private members */ + + // Mutex that must be locked by methods implementing the IProCameraUser + // interface. Ensures serialization between incoming IProCameraUser calls. + // All methods below that append 'L' to the name assume that + // mIProCameraUserLock is locked when they're called + mutable Mutex mIProCameraUserLock; + + // Used with stream IDs + static const int NO_STREAM = -1; + + /* Preview/Recording related members */ + + sp mPreviewSurface; + + /** Preview callback related members */ + /** Camera2Device instance wrapping HAL2 entry */ + + sp mDevice; + + /** Utility members */ + + // Verify that caller is the owner of the camera + status_t checkPid(const char *checkLocation) const; + + // Whether or not we have an exclusive lock on the device + // - if no we can't modify the request queue. + // note that creating/deleting streams we own is still OK + bool mExclusiveLock; +}; + +}; // namespace android + +#endif -- cgit v1.1