blob: 0c6f8afcfa134300ea84cb0825dcc6398d88f4dd [file] [log] [blame]
/*
* 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