blob: 575b075cca7af602ee8011a0c93d5f9fde73b9d0 [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"
#include "CameraDeviceBase.h"
namespace android {
using namespace camera2;
// Interface used by CameraService
ProCamera2Client::ProCamera2Client(const sp<CameraService>& cameraService,
const sp<IProCameraCallbacks>& remoteCallback,
const String16& clientPackageName,
int cameraId,
int cameraFacing,
int clientPid,
uid_t clientUid,
int servicePid) :
Camera2ClientBase(cameraService, remoteCallback, clientPackageName,
cameraId, cameraFacing, clientPid, clientUid, servicePid)
{
ATRACE_CALL();
ALOGI("ProCamera %d: Opened", cameraId);
mExclusiveLock = false;
}
status_t ProCamera2Client::initialize(camera_module_t *module)
{
ATRACE_CALL();
status_t res;
res = Camera2ClientBase::initialize(module);
if (res != OK) {
return res;
}
String8 threadName;
mFrameProcessor = new ProFrameProcessor(mDevice);
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() {
}
status_t ProCamera2Client::exclusiveTryLock() {
ATRACE_CALL();
ALOGV("%s", __FUNCTION__);
Mutex::Autolock icl(mBinderSerializationLock);
SharedCameraCallbacks::Lock l(mSharedCameraCallbacks);
if (!mDevice.get()) return PERMISSION_DENIED;
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(mBinderSerializationLock);
SharedCameraCallbacks::Lock l(mSharedCameraCallbacks);
if (!mDevice.get()) return PERMISSION_DENIED;
/**
* 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(mBinderSerializationLock);
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() {
Mutex::Autolock icl(mBinderSerializationLock);
return mExclusiveLock;
}
void ProCamera2Client::onExclusiveLockStolen() {
ALOGV("%s: ProClient lost exclusivity (id %d)",
__FUNCTION__, mCameraId);
Mutex::Autolock icl(mBinderSerializationLock);
SharedCameraCallbacks::Lock l(mSharedCameraCallbacks);
if (mExclusiveLock && mRemoteCallback.get() != NULL) {
mRemoteCallback->onLockStatusChanged(
IProCameraCallbacks::LOCK_STOLEN);
}
mExclusiveLock = false;
//TODO: we should not need to detach the device, merely reset it.
detachDevice();
}
status_t ProCamera2Client::submitRequest(camera_metadata_t* request,
bool streaming) {
ATRACE_CALL();
ALOGV("%s", __FUNCTION__);
Mutex::Autolock icl(mBinderSerializationLock);
if (!mDevice.get()) return DEAD_OBJECT;
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(mBinderSerializationLock);
if (!mDevice.get()) return DEAD_OBJECT;
if (!mExclusiveLock) {
return PERMISSION_DENIED;
}
// TODO: implement
ALOGE("%s: not fully implemented yet", __FUNCTION__);
return INVALID_OPERATION;
}
status_t ProCamera2Client::deleteStream(int streamId) {
ATRACE_CALL();
ALOGV("%s (streamId = 0x%x)", __FUNCTION__, streamId);
status_t res;
if ( (res = checkPid(__FUNCTION__) ) != OK) return res;
Mutex::Autolock icl(mBinderSerializationLock);
if (!mDevice.get()) return DEAD_OBJECT;
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(mBinderSerializationLock);
if (!mDevice.get()) return DEAD_OBJECT;
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(mBinderSerializationLock);
if (!mDevice.get()) return DEAD_OBJECT;
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;
}
Mutex::Autolock icl(mBinderSerializationLock);
if (!mDevice.get()) return DEAD_OBJECT;
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);
return dumpDevice(fd, args);
}
// IProCameraUser interface
void ProCamera2Client::detachDevice() {
if (mDevice == 0) return;
ALOGV("Camera %d: Stopping processors", 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);
// WORKAROUND: HAL refuses to disconnect while there's streams in flight
{
mDevice->clearStreamingRequest();
status_t code;
if ((code = mDevice->waitUntilDrained()) != OK) {
ALOGE("%s: waitUntilDrained failed with code 0x%x", __FUNCTION__,
code);
}
}
Camera2ClientBase::detachDevice();
}
/** Device-related methods */
void ProCamera2Client::onFrameAvailable(int32_t frameId,
const CameraMetadata& frame) {
ATRACE_CALL();
ALOGV("%s", __FUNCTION__);
Mutex::Autolock icl(mBinderSerializationLock);
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