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