blob: 857f2ed1188ed058c3a07ad3df9df8d6cd73391b [file] [log] [blame]
/*
* Copyright (C) 2011 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.
*/
/*
* Contains implementation of a class EmulatedCameraFactory that manages cameras
* available for emulation.
*/
#define LOG_NDEBUG 0
#define LOG_TAG "EmulatedCamera_Factory"
#include <log/log.h>
#include <cutils/properties.h>
#include "EmulatedFakeCamera.h"
#include "EmulatedCameraHotplugThread.h"
#include "EmulatedFakeCamera2.h"
#include "EmulatedFakeCamera3.h"
#include "EmulatedCameraFactory.h"
extern camera_module_t HAL_MODULE_INFO_SYM;
namespace android {
EmulatedCameraFactory& EmulatedCameraFactory::Instance() {
static EmulatedCameraFactory* factory = new EmulatedCameraFactory;
return *factory;
}
EmulatedCameraFactory::EmulatedCameraFactory()
: mCallbacks(NULL)
{
mCameraConfiguration.Init();
const std::vector<cvd::CameraDefinition>& cameras =
mCameraConfiguration.cameras();
for (size_t camera_index = 0; camera_index < cameras.size(); ++camera_index) {
mCameraDefinitions.push(cameras[camera_index]);
/* Reserve a spot for camera, but don't create just yet. */
mEmulatedCameras.push(NULL);
}
ALOGV("%zu cameras are being emulated.", getEmulatedCameraNum());
/* Create hotplug thread */
{
mHotplugThread = new EmulatedCameraHotplugThread(getEmulatedCameraNum());
mHotplugThread->run("EmulatedCameraHotplugThread");
}
}
EmulatedBaseCamera* EmulatedCameraFactory::getOrCreateFakeCamera(
size_t cameraId) {
::cvd::LockGuard< ::cvd::Mutex> lock(mEmulatedCamerasMutex);
if (cameraId >= getEmulatedCameraNum()) {
ALOGE("%s: Invalid camera ID: %zu", __FUNCTION__, cameraId);
return NULL;
}
if (mEmulatedCameras[cameraId] != NULL) {
return mEmulatedCameras[cameraId];
}
const cvd::CameraDefinition& definition = mCameraDefinitions[cameraId];
bool is_back_facing =
(definition.orientation == cvd::CameraDefinition::kBack);
EmulatedBaseCamera* camera;
/* Create, and initialize the fake camera */
switch (definition.hal_version) {
case cvd::CameraDefinition::kHalV1:
camera = new EmulatedFakeCamera(cameraId, is_back_facing,
&HAL_MODULE_INFO_SYM.common);
break;
case cvd::CameraDefinition::kHalV2:
camera = new EmulatedFakeCamera2(cameraId, is_back_facing,
&HAL_MODULE_INFO_SYM.common);
break;
case cvd::CameraDefinition::kHalV3:
camera = new EmulatedFakeCamera3(cameraId, is_back_facing,
&HAL_MODULE_INFO_SYM.common);
break;
default:
ALOGE("%s: Unsupported camera hal version requested: %d", __FUNCTION__,
definition.hal_version);
return NULL;
}
ALOGI("%s: Camera device %zu hal version is %d", __FUNCTION__, cameraId,
definition.hal_version);
int res = camera->Initialize(definition);
if (res != NO_ERROR) {
ALOGE("%s: Unable to intialize camera %zu: %s (%d)", __FUNCTION__, cameraId,
strerror(-res), res);
delete camera;
return NULL;
}
ALOGI("%s: Inserting camera", __FUNCTION__);
mEmulatedCameras.replaceAt(camera, cameraId);
ALOGI("%s: Done", __FUNCTION__);
return camera;
}
EmulatedCameraFactory::~EmulatedCameraFactory() {
for (size_t n = 0; n < mEmulatedCameras.size(); n++) {
if (mEmulatedCameras[n] != NULL) {
delete mEmulatedCameras[n];
}
}
if (mHotplugThread != NULL) {
mHotplugThread->requestExit();
mHotplugThread->join();
}
}
/****************************************************************************
* Camera HAL API handlers.
*
* Each handler simply verifies existence of an appropriate EmulatedBaseCamera
* instance, and dispatches the call to that instance.
*
***************************************************************************/
int EmulatedCameraFactory::cameraDeviceOpen(int camera_id,
hw_device_t** device) {
ALOGV("%s: id = %d", __FUNCTION__, camera_id);
*device = NULL;
EmulatedBaseCamera* camera = getOrCreateFakeCamera(camera_id);
if (camera == NULL) return -EINVAL;
return camera->connectCamera(device);
}
int EmulatedCameraFactory::getCameraInfo(int camera_id,
struct camera_info* info) {
ALOGV("%s: id = %d", __FUNCTION__, camera_id);
EmulatedBaseCamera* camera = getOrCreateFakeCamera(camera_id);
if (camera == NULL) return -EINVAL;
return camera->getCameraInfo(info);
}
int EmulatedCameraFactory::setCallbacks(
const camera_module_callbacks_t* callbacks) {
ALOGV("%s: callbacks = %p", __FUNCTION__, callbacks);
mCallbacks = callbacks;
return OK;
}
void EmulatedCameraFactory::getVendorTagOps(vendor_tag_ops_t* ops) {
ALOGV("%s: ops = %p", __FUNCTION__, ops);
// No vendor tags defined for emulator yet, so not touching ops
}
int EmulatedCameraFactory::setTorchMode(const char* camera_id, bool enabled) {
ALOGV("%s: camera_id = %s, enabled =%d", __FUNCTION__, camera_id, enabled);
EmulatedBaseCamera* camera = getOrCreateFakeCamera(atoi(camera_id));
if (camera == NULL) return -EINVAL;
return camera->setTorchMode(enabled);
}
/****************************************************************************
* Camera HAL API callbacks.
***************************************************************************/
int EmulatedCameraFactory::device_open(const hw_module_t* module,
const char* name, hw_device_t** device) {
/*
* Simply verify the parameters, and dispatch the call inside the
* EmulatedCameraFactory instance.
*/
if (module != &HAL_MODULE_INFO_SYM.common) {
ALOGE("%s: Invalid module %p expected %p", __FUNCTION__, module,
&HAL_MODULE_INFO_SYM.common);
return -EINVAL;
}
if (name == NULL) {
ALOGE("%s: NULL name is not expected here", __FUNCTION__);
return -EINVAL;
}
return EmulatedCameraFactory::Instance().cameraDeviceOpen(atoi(name), device);
}
int EmulatedCameraFactory::get_number_of_cameras(void) {
return EmulatedCameraFactory::Instance().getEmulatedCameraNum();
}
int EmulatedCameraFactory::get_camera_info(int camera_id,
struct camera_info* info) {
return EmulatedCameraFactory::Instance().getCameraInfo(camera_id, info);
}
int EmulatedCameraFactory::set_callbacks(
const camera_module_callbacks_t* callbacks) {
return EmulatedCameraFactory::Instance().setCallbacks(callbacks);
}
void EmulatedCameraFactory::get_vendor_tag_ops(vendor_tag_ops_t* ops) {
EmulatedCameraFactory::Instance().getVendorTagOps(ops);
}
int EmulatedCameraFactory::open_legacy(const struct hw_module_t* /*module*/,
const char* /*id*/,
uint32_t /*halVersion*/,
struct hw_device_t** /*device*/) {
// Not supporting legacy open
return -ENOSYS;
}
int EmulatedCameraFactory::set_torch_mode(const char* camera_id, bool enabled) {
return EmulatedCameraFactory::Instance().setTorchMode(camera_id, enabled);
}
/********************************************************************************
* Internal API
*******************************************************************************/
void EmulatedCameraFactory::onStatusChanged(int cameraId, int newStatus) {
EmulatedBaseCamera* cam = getOrCreateFakeCamera(cameraId);
if (!cam) {
ALOGE("%s: Invalid camera ID %d", __FUNCTION__, cameraId);
return;
}
/**
* (Order is important)
* Send the callback first to framework, THEN close the camera.
*/
if (newStatus == cam->getHotplugStatus()) {
ALOGW("%s: Ignoring transition to the same status", __FUNCTION__);
return;
}
const camera_module_callbacks_t* cb = mCallbacks;
if (cb != NULL && cb->camera_device_status_change != NULL) {
cb->camera_device_status_change(cb, cameraId, newStatus);
}
if (newStatus == CAMERA_DEVICE_STATUS_NOT_PRESENT) {
cam->unplugCamera();
} else if (newStatus == CAMERA_DEVICE_STATUS_PRESENT) {
cam->plugCamera();
}
}
void EmulatedCameraFactory::onTorchModeStatusChanged(int cameraId,
int newStatus) {
EmulatedBaseCamera* cam = getOrCreateFakeCamera(cameraId);
if (!cam) {
ALOGE("%s: Invalid camera ID %d", __FUNCTION__, cameraId);
return;
}
const camera_module_callbacks_t* cb = mCallbacks;
if (cb != NULL && cb->torch_mode_status_change != NULL) {
char id[10];
sprintf(id, "%d", cameraId);
cb->torch_mode_status_change(cb, id, newStatus);
}
}
/********************************************************************************
* Initializer for the static member structure.
*******************************************************************************/
/* Entry point for camera HAL API. */
struct hw_module_methods_t EmulatedCameraFactory::mCameraModuleMethods = {
.open = EmulatedCameraFactory::device_open};
}; /* namespace android */