Camera NDK library: first draft
Bug: 23012001
Change-Id: I06d834421289d4dead1c87301a6ee94487ccf023
diff --git a/camera/ndk/impl/ACameraDevice.cpp b/camera/ndk/impl/ACameraDevice.cpp
new file mode 100644
index 0000000..0c6f8af
--- /dev/null
+++ b/camera/ndk/impl/ACameraDevice.cpp
@@ -0,0 +1,300 @@
+/*
+ * 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 "ACameraDevice"
+
+#include <inttypes.h>
+#include "ACameraDevice.h"
+#include "ACameraMetadata.h"
+#include "ACaptureRequest.h"
+
+using namespace android;
+
+namespace android {
+// Static member definitions
+const char* CameraDevice::kContextKey = "Context";
+const char* CameraDevice::kDeviceKey = "Device";
+const char* CameraDevice::kErrorCodeKey = "ErrorCode";
+const char* CameraDevice::kCallbackKey = "Callback";
+
+/**
+ * CameraDevice Implementation
+ */
+CameraDevice::CameraDevice(
+ const char* id,
+ ACameraDevice_StateCallbacks* cb,
+ std::unique_ptr<ACameraMetadata> chars,
+ ACameraDevice* wrapper) :
+ mCameraId(id),
+ mAppCallbacks(*cb),
+ mChars(std::move(chars)),
+ mServiceCallback(new ServiceCallback(this)),
+ mWrapper(wrapper),
+ mInError(false),
+ mError(ACAMERA_OK),
+ mIdle(true) {
+ mClosing = false;
+ // Setup looper thread to perfrom device callbacks to app
+ mCbLooper = new ALooper;
+ mCbLooper->setName("C2N-dev-looper");
+ status_t ret = mCbLooper->start(
+ /*runOnCallingThread*/false,
+ /*canCallJava*/ true,
+ PRIORITY_FOREGROUND);
+ mHandler = new CallbackHandler();
+ mCbLooper->registerHandler(mHandler);
+}
+
+CameraDevice::~CameraDevice() {
+ Mutex::Autolock _l(mDeviceLock);
+ if (mCbLooper != nullptr) {
+ mCbLooper->unregisterHandler(mHandler->id());
+ mCbLooper->stop();
+ }
+ mCbLooper.clear();
+ mHandler.clear();
+ if (!isClosed()) {
+ disconnectLocked();
+ }
+}
+
+// TODO: cached created request?
+camera_status_t
+CameraDevice::createCaptureRequest(
+ ACameraDevice_request_template templateId,
+ ACaptureRequest** request) const {
+ Mutex::Autolock _l(mDeviceLock);
+ camera_status_t ret = checkCameraClosedOrErrorLocked();
+ if (ret != ACAMERA_OK) {
+ return ret;
+ }
+ if (mRemote == nullptr) {
+ return ACAMERA_ERROR_CAMERA_DISCONNECTED;
+ }
+ CameraMetadata rawRequest;
+ status_t remoteRet = mRemote->createDefaultRequest(templateId, &rawRequest);
+ if (remoteRet == BAD_VALUE) {
+ ALOGW("Create capture request failed! template %d is not supported on this device",
+ templateId);
+ return ACAMERA_ERROR_UNSUPPORTED;
+ } else if (remoteRet != OK) {
+ ALOGE("Create capture request failed! error %d", remoteRet);
+ return ACAMERA_ERROR_UNKNOWN;
+ }
+ ACaptureRequest* outReq = new ACaptureRequest();
+ outReq->settings = new ACameraMetadata(rawRequest.release(), ACameraMetadata::ACM_REQUEST);
+ outReq->targets = new ACameraOutputTargets();
+ *request = outReq;
+ return ACAMERA_OK;
+}
+
+void
+CameraDevice::disconnectLocked() {
+ if (mClosing.exchange(true)) {
+ // Already closing, just return
+ ALOGW("Camera device %s is already closing.", getId());
+ return;
+ }
+
+ if (mRemote != nullptr) {
+ mRemote->disconnect();
+ }
+ mRemote = nullptr;
+}
+
+void
+CameraDevice::setRemoteDevice(sp<ICameraDeviceUser> remote) {
+ Mutex::Autolock _l(mDeviceLock);
+ mRemote = remote;
+}
+
+camera_status_t
+CameraDevice::checkCameraClosedOrErrorLocked() const {
+ if (mRemote == nullptr) {
+ ALOGE("%s: camera device already closed", __FUNCTION__);
+ return ACAMERA_ERROR_CAMERA_DISCONNECTED;
+ }
+ if (mInError) {// triggered by onDeviceError
+ ALOGE("%s: camera device has encountered a serious error", __FUNCTION__);
+ return mError;
+ }
+ return ACAMERA_OK;
+}
+
+void
+CameraDevice::onCaptureErrorLocked(
+ ICameraDeviceCallbacks::CameraErrorCode errorCode,
+ const CaptureResultExtras& resultExtras) {
+ // TODO: implement!
+}
+
+void CameraDevice::CallbackHandler::onMessageReceived(
+ const sp<AMessage> &msg) {
+ switch (msg->what()) {
+ case kWhatOnDisconnected:
+ case kWhatOnError:
+ break;
+ default:
+ ALOGE("%s:Error: unknown device callback %d", __FUNCTION__, msg->what());
+ return;
+ }
+ // Check the common part of all message
+ void* context;
+ bool found = msg->findPointer(kContextKey, &context);
+ if (!found) {
+ ALOGE("%s: Cannot find callback context!", __FUNCTION__);
+ return;
+ }
+ ACameraDevice* dev;
+ found = msg->findPointer(kDeviceKey, (void**) &dev);
+ if (!found) {
+ ALOGE("%s: Cannot find device pointer!", __FUNCTION__);
+ return;
+ }
+ switch (msg->what()) {
+ case kWhatOnDisconnected:
+ {
+ ACameraDevice_StateCallback onDisconnected;
+ found = msg->findPointer(kCallbackKey, (void**) &onDisconnected);
+ if (!found) {
+ ALOGE("%s: Cannot find onDisconnected!", __FUNCTION__);
+ return;
+ }
+ (*onDisconnected)(context, dev);
+ break;
+ }
+ case kWhatOnError:
+ {
+ ACameraDevice_ErrorStateCallback onError;
+ found = msg->findPointer(kCallbackKey, (void**) &onError);
+ if (!found) {
+ ALOGE("%s: Cannot find onError!", __FUNCTION__);
+ return;
+ }
+ int errorCode;
+ found = msg->findInt32(kErrorCodeKey, &errorCode);
+ if (!found) {
+ ALOGE("%s: Cannot find error code!", __FUNCTION__);
+ return;
+ }
+ (*onError)(context, dev, errorCode);
+ }
+ }
+}
+
+/**
+ * Camera service callback implementation
+ */
+void
+CameraDevice::ServiceCallback::onDeviceError(
+ CameraErrorCode errorCode,
+ const CaptureResultExtras& resultExtras) {
+ ALOGD("Device error received, code %d, frame number %" PRId64 ", request ID %d, subseq ID %d",
+ errorCode, resultExtras.frameNumber, resultExtras.requestId, resultExtras.burstId);
+
+ sp<CameraDevice> dev = mDevice.promote();
+ if (dev == nullptr) {
+ return; // device has been closed
+ }
+
+ Mutex::Autolock _l(dev->mDeviceLock);
+ if (dev->mRemote == nullptr) {
+ return; // device has been disconnected
+ }
+ switch (errorCode) {
+ case ERROR_CAMERA_DISCONNECTED:
+ {
+ // should be clear mRemote here?
+ // TODO: close current session
+ sp<AMessage> msg = new AMessage(kWhatOnDisconnected, dev->mHandler);
+ msg->setPointer(kContextKey, dev->mAppCallbacks.context);
+ msg->setPointer(kDeviceKey, (void*) dev->getWrapper());
+ msg->setPointer(kCallbackKey, (void*) dev->mAppCallbacks.onDisconnected);
+ msg->post();
+ break;
+ }
+ default:
+ ALOGE("Unknown error from camera device: %d", errorCode);
+ // no break
+ case ERROR_CAMERA_DEVICE:
+ case ERROR_CAMERA_SERVICE:
+ {
+ dev->mInError = true;
+ switch (errorCode) {
+ case ERROR_CAMERA_DEVICE:
+ dev->mError = ACAMERA_ERROR_CAMERA_DEVICE;
+ break;
+ case ERROR_CAMERA_SERVICE:
+ dev->mError = ACAMERA_ERROR_CAMERA_SERVICE;
+ break;
+ default:
+ dev->mError = ACAMERA_ERROR_UNKNOWN;
+ break;
+ }
+ sp<AMessage> msg = new AMessage(kWhatOnError, dev->mHandler);
+ msg->setPointer(kContextKey, dev->mAppCallbacks.context);
+ msg->setPointer(kDeviceKey, (void*) dev->getWrapper());
+ msg->setPointer(kCallbackKey, (void*) dev->mAppCallbacks.onError);
+ msg->setInt32(kErrorCodeKey, errorCode);
+ msg->post();
+ break;
+ }
+ case ERROR_CAMERA_REQUEST:
+ case ERROR_CAMERA_RESULT:
+ case ERROR_CAMERA_BUFFER:
+ dev->onCaptureErrorLocked(errorCode, resultExtras);
+ break;
+ }
+}
+
+void
+CameraDevice::ServiceCallback::onDeviceIdle() {
+ ALOGV("Camera is now idle");
+ sp<CameraDevice> dev = mDevice.promote();
+ if (dev == nullptr) {
+ return; // device has been closed
+ }
+
+ Mutex::Autolock _l(dev->mDeviceLock);
+ if (dev->mRemote == nullptr) {
+ return; // device has been disconnected
+ }
+ if (!dev->mIdle) {
+ // TODO: send idle callback to current session
+ }
+ dev->mIdle = true;
+}
+
+void
+CameraDevice::ServiceCallback::onCaptureStarted(
+ const CaptureResultExtras& resultExtras,
+ int64_t timestamp) {
+}
+
+void
+CameraDevice::ServiceCallback::onResultReceived(
+ const CameraMetadata& metadata,
+ const CaptureResultExtras& resultExtras) {
+}
+
+void
+CameraDevice::ServiceCallback::onPrepared(int) {
+ // Prepare not yet implemented in NDK
+ return;
+}
+
+} // namespace android