blob: c264e2adbbdfec103d9393b65d1d950fcd6bd539 [file] [log] [blame]
/*
* 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 <utils/Log.h>
#include <utils/Trace.h>
#include <cutils/properties.h>
#include <gui/Surface.h>
#include <gui/Surface.h>
#include "camera2/Parameters.h"
#include "ProCamera2Client.h"
#include "camera2/ProFrameProcessor.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>& cameraService,
const sp<IProCameraCallbacks>& 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);
String8 threadName;
mFrameProcessor = new ProFrameProcessor(this);
threadName = String8::format("PC2-%d-FrameProc",
mCameraId);
mFrameProcessor->run(threadName.string());
mFrameProcessor->registerListener(FRAME_PROCESSOR_LISTENER_MIN_ID,
FRAME_PROCESSOR_LISTENER_MAX_ID,
/*listener*/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;
}
CameraMetadata metadata(request);
if (streaming) {
return mDevice->setStreamingRequest(metadata);
} else {
return mDevice->capture(metadata);
}
// unreachable. thx gcc for a useless warning
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 INVALID_OPERATION;
}
status_t ProCamera2Client::requestStream(int streamId) {
ALOGE("%s: not implemented yet", __FUNCTION__);
return INVALID_OPERATION;
}
status_t ProCamera2Client::cancelStream(int streamId) {
ATRACE_CALL();
ALOGV("%s (streamId = 0x%x)", __FUNCTION__, streamId);
status_t res;
if ( (res = checkPid(__FUNCTION__) ) != OK) return res;
Mutex::Autolock icl(mIProCameraUserLock);
mDevice->clearStreamingRequest();
status_t code;
if ((code = mDevice->waitUntilDrained()) != OK) {
ALOGE("%s: waitUntilDrained failed with code 0x%x", __FUNCTION__, code);
}
return mDevice->deleteStream(streamId);
}
status_t ProCamera2Client::createStream(int width, int height, int format,
const sp<IGraphicBufferProducer>& bufferProducer,
/*out*/
int* streamId)
{
if (streamId) {
*streamId = -1;
}
ATRACE_CALL();
ALOGV("%s (w = %d, h = %d, f = 0x%x)", __FUNCTION__, width, height, format);
status_t res;
if ( (res = checkPid(__FUNCTION__) ) != OK) return res;
Mutex::Autolock icl(mIProCameraUserLock);
sp<IBinder> binder;
sp<ANativeWindow> window;
if (bufferProducer != 0) {
binder = bufferProducer->asBinder();
window = new Surface(bufferProducer);
}
return mDevice->createStream(window, width, height, format, /*size*/1,
streamId);
}
// Create a request object from a template.
// -- Caller owns the newly allocated metadata
status_t ProCamera2Client::createDefaultRequest(int templateId,
/*out*/
camera_metadata** request)
{
ATRACE_CALL();
ALOGV("%s (templateId = 0x%x)", __FUNCTION__, templateId);
if (request) {
*request = NULL;
}
status_t res;
if ( (res = checkPid(__FUNCTION__) ) != OK) return res;
Mutex::Autolock icl(mIProCameraUserLock);
CameraMetadata metadata;
if ( (res = mDevice->createDefaultRequest(templateId, &metadata) ) == OK) {
*request = metadata.release();
}
return res;
}
status_t ProCamera2Client::getCameraInfo(int cameraId,
/*out*/
camera_metadata** info)
{
if (cameraId != mCameraId) {
return INVALID_OPERATION;
}
CameraMetadata deviceInfo = mDevice->info();
*info = deviceInfo.release();
return OK;
}
status_t ProCamera2Client::dump(int fd, const Vector<String16>& 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
mFrameProcessor->dump(fd, args);
#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);
mFrameProcessor->removeListener(FRAME_PROCESSOR_LISTENER_MIN_ID,
FRAME_PROCESSOR_LISTENER_MAX_ID,
/*listener*/this);
mFrameProcessor->requestExit();
ALOGV("Camera %d: Waiting for threads", mCameraId);
mFrameProcessor->join();
ALOGV("Camera %d: Disconnecting device", mCameraId);
mDevice->disconnect();
mDevice.clear();
ProClient::disconnect();
}
status_t ProCamera2Client::connect(const sp<IProCameraCallbacks>& 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<Camera2Device>& ProCamera2Client::getCameraDevice() {
return mDevice;
}
const sp<CameraService>& 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<IProCameraCallbacks>&client):
mRemoteCallback(client) {
}
ProCamera2Client::SharedCameraCallbacks&
ProCamera2Client::SharedCameraCallbacks::operator=(
const sp<IProCameraCallbacks>&client) {
Mutex::Autolock l(mRemoteCallbackLock);
mRemoteCallback = client;
return *this;
}
void ProCamera2Client::SharedCameraCallbacks::clear() {
Mutex::Autolock l(mRemoteCallbackLock);
mRemoteCallback.clear();
}
void ProCamera2Client::onFrameAvailable(int32_t frameId,
const CameraMetadata& frame) {
ATRACE_CALL();
ALOGV("%s", __FUNCTION__);
Mutex::Autolock icl(mIProCameraUserLock);
SharedCameraCallbacks::Lock l(mSharedCameraCallbacks);
if (mRemoteCallback != NULL) {
CameraMetadata tmp(frame);
camera_metadata_t* meta = tmp.release();
ALOGV("%s: meta = %p ", __FUNCTION__, meta);
mRemoteCallback->onResultReceived(frameId, meta);
tmp.acquire(meta);
}
}
} // namespace android