diff options
Diffstat (limited to 'services')
-rw-r--r-- | services/camera/libcameraservice/CameraFlashlight.cpp | 330 | ||||
-rw-r--r-- | services/camera/libcameraservice/CameraFlashlight.h | 72 | ||||
-rw-r--r-- | services/camera/libcameraservice/CameraService.cpp | 201 | ||||
-rw-r--r-- | services/camera/libcameraservice/CameraService.h | 21 |
4 files changed, 423 insertions, 201 deletions
diff --git a/services/camera/libcameraservice/CameraFlashlight.cpp b/services/camera/libcameraservice/CameraFlashlight.cpp index 00a70eb..a00a49f 100644 --- a/services/camera/libcameraservice/CameraFlashlight.cpp +++ b/services/camera/libcameraservice/CameraFlashlight.cpp @@ -16,7 +16,7 @@ #define LOG_TAG "CameraFlashlight" #define ATRACE_TAG ATRACE_TAG_CAMERA -#define LOG_NDEBUG 0 +// #define LOG_NDEBUG 0 #include <utils/Log.h> #include <utils/Trace.h> @@ -32,16 +32,21 @@ namespace android { +///////////////////////////////////////////////////////////////////// +// CameraFlashlight implementation begins +// used by camera service to control flashflight. +///////////////////////////////////////////////////////////////////// CameraFlashlight::CameraFlashlight(CameraModule& cameraModule, const camera_module_callbacks_t& callbacks) : mCameraModule(&cameraModule), - mCallbacks(&callbacks) { + mCallbacks(&callbacks), + mFlashlightMapInitialized(false) { } CameraFlashlight::~CameraFlashlight() { } -status_t CameraFlashlight::createFlashlightControl(const String16& cameraId) { +status_t CameraFlashlight::createFlashlightControl(const String8& cameraId) { ALOGV("%s: creating a flash light control for camera %s", __FUNCTION__, cameraId.string()); if (mFlashControl != NULL) { @@ -52,7 +57,7 @@ status_t CameraFlashlight::createFlashlightControl(const String16& cameraId) { if (mCameraModule->getRawModule()->module_api_version >= CAMERA_MODULE_API_VERSION_2_4) { - mFlashControl = new FlashControl(*mCameraModule, *mCallbacks); + mFlashControl = new ModuleFlashControl(*mCameraModule, *mCallbacks); if (mFlashControl == NULL) { ALOGV("%s: cannot create flash control for module api v2.4+", __FUNCTION__); @@ -67,7 +72,7 @@ status_t CameraFlashlight::createFlashlightControl(const String16& cameraId) { res = mCameraModule->getCameraInfo( atoi(String8(cameraId).string()), &info); if (res) { - ALOGV("%s: failed to get camera info for camera %s", + ALOGE("%s: failed to get camera info for camera %s", __FUNCTION__, cameraId.string()); return res; } @@ -83,8 +88,7 @@ status_t CameraFlashlight::createFlashlightControl(const String16& cameraId) { } mFlashControl = flashControl; - } - else { + } else { // todo: implement for device api 1 return INVALID_OPERATION; } @@ -93,8 +97,9 @@ status_t CameraFlashlight::createFlashlightControl(const String16& cameraId) { return OK; } -status_t CameraFlashlight::setTorchMode(const String16& cameraId, bool enabled) { - if (!mCameraModule) { +status_t CameraFlashlight::setTorchMode(const String8& cameraId, bool enabled) { + if (!mFlashlightMapInitialized) { + ALOGE("%s: findFlashUnits() must be called before this method."); return NO_INIT; } @@ -105,6 +110,10 @@ status_t CameraFlashlight::setTorchMode(const String16& cameraId, bool enabled) Mutex::Autolock l(mLock); if (mFlashControl == NULL) { + if (enabled == false) { + return OK; + } + res = createFlashlightControl(cameraId); if (res) { return res; @@ -130,88 +139,169 @@ status_t CameraFlashlight::setTorchMode(const String16& cameraId, bool enabled) return res; } -bool CameraFlashlight::hasFlashUnit(const String16& cameraId) { +status_t CameraFlashlight::findFlashUnits() { + Mutex::Autolock l(mLock); status_t res; + int32_t numCameras = mCameraModule->getNumberOfCameras(); - Mutex::Autolock l(mLock); + mHasFlashlightMap.clear(); + mFlashlightMapInitialized = false; - if (mFlashControl == NULL) { - res = createFlashlightControl(cameraId); + for (int32_t i = 0; i < numCameras; i++) { + bool hasFlash = false; + String8 id = String8::format("%d", i); + + res = createFlashlightControl(id); if (res) { - ALOGE("%s: failed to create flash control for %s ", - __FUNCTION__, cameraId.string()); - return false; + ALOGE("%s: failed to create flash control for %s", __FUNCTION__, + id.string()); + } else { + res = mFlashControl->hasFlashUnit(id, &hasFlash); + if (res == -EUSERS || res == -EBUSY) { + ALOGE("%s: failed to check if camera %s has a flash unit. Some " + "camera devices may be opened", __FUNCTION__, + id.string()); + return res; + } else if (res) { + ALOGE("%s: failed to check if camera %s has a flash unit. %s" + " (%d)", __FUNCTION__, id.string(), strerror(-res), + res); + } + + mFlashControl.clear(); } + mHasFlashlightMap.add(id, hasFlash); } - bool flashUnit = false; + mFlashlightMapInitialized = true; + return OK; +} - // if flash control already exists, querying if a camera device has a flash - // unit may fail if it's module v1 - res = mFlashControl->hasFlashUnit(cameraId, &flashUnit); - if (res == BAD_INDEX) { - // need to close the flash control before query. - mFlashControl.clear(); - res = createFlashlightControl(cameraId); - if (res) { - ALOGE("%s: failed to create flash control for %s ", __FUNCTION__, - cameraId.string()); - return false; - } - res = mFlashControl->hasFlashUnit(cameraId, &flashUnit); - if (res) { - flashUnit = false; - } +bool CameraFlashlight::hasFlashUnit(const String8& cameraId) { + status_t res; + + Mutex::Autolock l(mLock); + return hasFlashUnitLocked(cameraId); +} + +bool CameraFlashlight::hasFlashUnitLocked(const String8& cameraId) { + if (!mFlashlightMapInitialized) { + ALOGE("%s: findFlashUnits() must be called before this method."); + return false; } - return flashUnit; + ssize_t index = mHasFlashlightMap.indexOfKey(cameraId); + if (index == NAME_NOT_FOUND) { + ALOGE("%s: camera %s not present when findFlashUnits() was called", + __FUNCTION__, cameraId.string()); + return false; + } + + return mHasFlashlightMap.valueAt(index); } -status_t CameraFlashlight::prepareDeviceOpen() { +status_t CameraFlashlight::prepareDeviceOpen(const String8& cameraId) { ALOGV("%s: prepare for device open", __FUNCTION__); Mutex::Autolock l(mLock); + if (!mFlashlightMapInitialized) { + ALOGE("%s: findFlashUnits() must be called before this method."); + return NO_INIT; + } - if (mCameraModule && mCameraModule->getRawModule()->module_api_version < + if (mCameraModule->getRawModule()->module_api_version < CAMERA_MODULE_API_VERSION_2_4) { // framework is going to open a camera device, all flash light control // should be closed for backward compatible support. - if (mFlashControl != NULL) { - mFlashControl.clear(); + mFlashControl.clear(); + + if (mOpenedCameraIds.size() == 0) { + // notify torch unavailable for all cameras with a flash + int numCameras = mCameraModule->getNumberOfCameras(); + for (int i = 0; i < numCameras; i++) { + if (hasFlashUnitLocked(String8::format("%d", i))) { + mCallbacks->torch_mode_status_change(mCallbacks, + String8::format("%d", i).string(), + TORCH_MODE_STATUS_NOT_AVAILABLE); + } + } } + + // close flash control that may be opened by calling hasFlashUnitLocked. + mFlashControl.clear(); + } + + if (mOpenedCameraIds.indexOf(cameraId) == NAME_NOT_FOUND) { + mOpenedCameraIds.add(cameraId); } return OK; } +status_t CameraFlashlight::deviceClosed(const String8& cameraId) { + ALOGV("%s: device %s is closed", __FUNCTION__, cameraId.string()); -FlashControlBase::~FlashControlBase() { + Mutex::Autolock l(mLock); + if (!mFlashlightMapInitialized) { + ALOGE("%s: findFlashUnits() must be called before this method."); + return NO_INIT; + } + + ssize_t index = mOpenedCameraIds.indexOf(cameraId); + if (index == NAME_NOT_FOUND) { + ALOGE("%s: couldn't find camera %s in the opened list", __FUNCTION__, + cameraId.string()); + } else { + mOpenedCameraIds.removeAt(index); + } + + // Cannot do anything until all cameras are closed. + if (mOpenedCameraIds.size() != 0) + return OK; + + if (mCameraModule->getRawModule()->module_api_version < + CAMERA_MODULE_API_VERSION_2_4) { + // notify torch available for all cameras with a flash + int numCameras = mCameraModule->getNumberOfCameras(); + for (int i = 0; i < numCameras; i++) { + if (hasFlashUnitLocked(String8::format("%d", i))) { + mCallbacks->torch_mode_status_change(mCallbacks, + String8::format("%d", i).string(), + TORCH_MODE_STATUS_AVAILABLE_OFF); + } + } + } + + return OK; } +// CameraFlashlight implementation ends -FlashControl::FlashControl(CameraModule& cameraModule, +FlashControlBase::~FlashControlBase() { +} + +///////////////////////////////////////////////////////////////////// +// ModuleFlashControl implementation begins +// Flash control for camera module v2.4 and above. +///////////////////////////////////////////////////////////////////// +ModuleFlashControl::ModuleFlashControl(CameraModule& cameraModule, const camera_module_callbacks_t& callbacks) : mCameraModule(&cameraModule) { } -FlashControl::~FlashControl() { +ModuleFlashControl::~ModuleFlashControl() { } -status_t FlashControl::hasFlashUnit(const String16& cameraId, bool *hasFlash) { +status_t ModuleFlashControl::hasFlashUnit(const String8& cameraId, bool *hasFlash) { if (!hasFlash) { return BAD_VALUE; } *hasFlash = false; - Mutex::Autolock l(mLock); - if (!mCameraModule) { - return NO_INIT; - } - camera_info info; - status_t res = mCameraModule->getCameraInfo(atoi(String8(cameraId).string()), + status_t res = mCameraModule->getCameraInfo(atoi(cameraId.string()), &info); if (res != 0) { return res; @@ -228,33 +318,31 @@ status_t FlashControl::hasFlashUnit(const String16& cameraId, bool *hasFlash) { return OK; } -status_t FlashControl::setTorchMode(const String16& cameraId, bool enabled) { +status_t ModuleFlashControl::setTorchMode(const String8& cameraId, bool enabled) { ALOGV("%s: set camera %s torch mode to %d", __FUNCTION__, cameraId.string(), enabled); Mutex::Autolock l(mLock); - if (!mCameraModule) { - return NO_INIT; - } - - return mCameraModule->setTorchMode(String8(cameraId).string(), enabled); + return mCameraModule->setTorchMode(cameraId.string(), enabled); } +// ModuleFlashControl implementation ends +///////////////////////////////////////////////////////////////////// +// CameraDeviceClientFlashControl implementation begins +// Flash control for camera module <= v2.3 and camera HAL v2-v3 +///////////////////////////////////////////////////////////////////// CameraDeviceClientFlashControl::CameraDeviceClientFlashControl( CameraModule& cameraModule, const camera_module_callbacks_t& callbacks) : mCameraModule(&cameraModule), mCallbacks(&callbacks), mTorchEnabled(false), - mMetadata(NULL) { + mMetadata(NULL), + mStreaming(false) { } CameraDeviceClientFlashControl::~CameraDeviceClientFlashControl() { - if (mDevice != NULL) { - mDevice->flush(); - mDevice->deleteStream(mStreamId); - mDevice.clear(); - } + disconnectCameraDevice(); if (mMetadata) { delete mMetadata; } @@ -269,13 +357,13 @@ CameraDeviceClientFlashControl::~CameraDeviceClientFlashControl() { ALOGV("%s: notify the framework that torch was turned off", __FUNCTION__); mCallbacks->torch_mode_status_change(mCallbacks, - String8(mCameraId).string(), TORCH_MODE_STATUS_OFF); + mCameraId.string(), TORCH_MODE_STATUS_AVAILABLE_OFF); } } } -status_t CameraDeviceClientFlashControl::initializeSurface(int32_t width, - int32_t height) { +status_t CameraDeviceClientFlashControl::initializeSurface( + sp<CameraDeviceBase> &device, int32_t width, int32_t height) { status_t res; BufferQueue::createBufferQueue(&mProducer, &mConsumer); @@ -295,27 +383,16 @@ status_t CameraDeviceClientFlashControl::initializeSurface(int32_t width, return res; } - bool useAsync = false; - int32_t consumerUsage; - res = mProducer->query(NATIVE_WINDOW_CONSUMER_USAGE_BITS, &consumerUsage); - if (res) { - return res; - } - - if (consumerUsage & GraphicBuffer::USAGE_HW_TEXTURE) { - useAsync = true; - } - - mAnw = new Surface(mProducer, useAsync); + mAnw = new Surface(mProducer, /*useAsync*/ true); if (mAnw == NULL) { return NO_MEMORY; } - res = mDevice->createStream(mAnw, width, height, format, &mStreamId); + res = device->createStream(mAnw, width, height, format, &mStreamId); if (res) { return res; } - res = mDevice->configureStreams(); + res = device->configureStreams(); if (res) { return res; } @@ -342,7 +419,21 @@ status_t CameraDeviceClientFlashControl::getSmallestSurfaceSize( int32_t ww = streamConfigs.data.i32[i + 1]; int32_t hh = streamConfigs.data.i32[i + 2]; - if (w* h > ww * hh) { + if (w * h > ww * hh) { + w = ww; + h = hh; + } + } + } + + // if stream configuration is not found, try available processed sizes. + if (streamConfigs.count == 0) { + camera_metadata_entry availableProcessedSizes = + metadata.find(ANDROID_SCALER_AVAILABLE_PROCESSED_SIZES); + for (size_t i = 0; i < availableProcessedSizes.count; i += 2) { + int32_t ww = availableProcessedSizes.data.i32[i]; + int32_t hh = availableProcessedSizes.data.i32[i + 1]; + if (w * h > ww * hh) { w = ww; h = hh; } @@ -360,24 +451,24 @@ status_t CameraDeviceClientFlashControl::getSmallestSurfaceSize( } status_t CameraDeviceClientFlashControl::connectCameraDevice( - const String16& cameraId) { - String8 id = String8(cameraId); + const String8& cameraId) { camera_info info; - status_t res = mCameraModule->getCameraInfo(atoi(id.string()), &info); + status_t res = mCameraModule->getCameraInfo(atoi(cameraId.string()), &info); if (res != 0) { ALOGE("%s: failed to get camera info for camera %s", __FUNCTION__, - mCameraId.string()); + cameraId.string()); return res; } - mDevice = CameraDeviceFactory::createDevice(atoi(id.string())); - if (mDevice == NULL) { + sp<CameraDeviceBase> device = + CameraDeviceFactory::createDevice(atoi(cameraId.string())); + if (device == NULL) { return NO_MEMORY; } - res = mDevice->initialize(mCameraModule); + res = device->initialize(mCameraModule); if (res) { - goto fail; + return res; } int32_t width, height; @@ -385,22 +476,30 @@ status_t CameraDeviceClientFlashControl::connectCameraDevice( if (res) { return res; } - res = initializeSurface(width, height); + res = initializeSurface(device, width, height); if (res) { - goto fail; + return res; } mCameraId = cameraId; + mStreaming = (info.device_version <= CAMERA_DEVICE_API_VERSION_3_1); + mDevice = device; return OK; +} -fail: - mDevice.clear(); - return res; +status_t CameraDeviceClientFlashControl::disconnectCameraDevice() { + if (mDevice != NULL) { + mDevice->disconnect(); + mDevice.clear(); + } + + return OK; } -status_t CameraDeviceClientFlashControl::hasFlashUnit(const String16& cameraId, + +status_t CameraDeviceClientFlashControl::hasFlashUnit(const String8& cameraId, bool *hasFlash) { ALOGV("%s: checking if camera %s has a flash unit", __FUNCTION__, cameraId.string()); @@ -411,19 +510,14 @@ status_t CameraDeviceClientFlashControl::hasFlashUnit(const String16& cameraId, } status_t CameraDeviceClientFlashControl::hasFlashUnitLocked( - const String16& cameraId, bool *hasFlash) { - if (!mCameraModule) { - ALOGE("%s: camera module is NULL", __FUNCTION__); - return NO_INIT; - } - + const String8& cameraId, bool *hasFlash) { if (!hasFlash) { return BAD_VALUE; } camera_info info; status_t res = mCameraModule->getCameraInfo( - atoi(String8(cameraId).string()), &info); + atoi(cameraId.string()), &info); if (res != 0) { ALOGE("%s: failed to get camera info for camera %s", __FUNCTION__, cameraId.string()); @@ -441,7 +535,7 @@ status_t CameraDeviceClientFlashControl::hasFlashUnitLocked( return OK; } -status_t CameraDeviceClientFlashControl::submitTorchRequest(bool enabled) { +status_t CameraDeviceClientFlashControl::submitTorchEnabledRequest() { status_t res; if (mMetadata == NULL) { @@ -456,27 +550,29 @@ status_t CameraDeviceClientFlashControl::submitTorchRequest(bool enabled) { } } - uint8_t torchOn = enabled ? ANDROID_FLASH_MODE_TORCH : - ANDROID_FLASH_MODE_OFF; - + uint8_t torchOn = ANDROID_FLASH_MODE_TORCH; mMetadata->update(ANDROID_FLASH_MODE, &torchOn, 1); mMetadata->update(ANDROID_REQUEST_OUTPUT_STREAMS, &mStreamId, 1); + uint8_t aeMode = ANDROID_CONTROL_AE_MODE_ON; + mMetadata->update(ANDROID_CONTROL_AE_MODE, &aeMode, 1); + int32_t requestId = 0; mMetadata->update(ANDROID_REQUEST_ID, &requestId, 1); - List<const CameraMetadata> metadataRequestList; - metadataRequestList.push_back(*mMetadata); - - int64_t lastFrameNumber = 0; - res = mDevice->captureList(metadataRequestList, &lastFrameNumber); - + if (mStreaming) { + res = mDevice->setStreamingRequest(*mMetadata); + } else { + res = mDevice->capture(*mMetadata); + } return res; } + + status_t CameraDeviceClientFlashControl::setTorchMode( - const String16& cameraId, bool enabled) { + const String8& cameraId, bool enabled) { bool hasFlash = false; Mutex::Autolock l(mLock); @@ -499,6 +595,13 @@ status_t CameraDeviceClientFlashControl::setTorchMode( } else if (mDevice == NULL || cameraId != mCameraId) { // disabling the torch mode of an un-opened or different device. return OK; + } else { + // disabling the torch mode of currently opened device + disconnectCameraDevice(); + mTorchEnabled = false; + mCallbacks->torch_mode_status_change(mCallbacks, + cameraId.string(), TORCH_MODE_STATUS_AVAILABLE_OFF); + return OK; } if (mDevice == NULL) { @@ -508,13 +611,16 @@ status_t CameraDeviceClientFlashControl::setTorchMode( } } - res = submitTorchRequest(enabled); + res = submitTorchEnabledRequest(); if (res) { return res; } - mTorchEnabled = enabled; + mTorchEnabled = true; + mCallbacks->torch_mode_status_change(mCallbacks, + cameraId.string(), TORCH_MODE_STATUS_AVAILABLE_ON); return OK; } +// CameraDeviceClientFlashControl implementation ends } diff --git a/services/camera/libcameraservice/CameraFlashlight.h b/services/camera/libcameraservice/CameraFlashlight.h index a0de0b0..ae502b9 100644 --- a/services/camera/libcameraservice/CameraFlashlight.h +++ b/services/camera/libcameraservice/CameraFlashlight.h @@ -19,6 +19,7 @@ #include "hardware/camera_common.h" #include "utils/KeyedVector.h" +#include "utils/SortedVector.h" #include "gui/GLConsumer.h" #include "gui/Surface.h" #include "common/CameraDeviceBase.h" @@ -37,11 +38,11 @@ class FlashControlBase : public virtual VirtualLightRefBase { // cause the torch mode to be turned off in HAL v1 devices. If // previously-on torch mode is turned off, // callbacks.torch_mode_status_change() should be invoked. - virtual status_t hasFlashUnit(const String16& cameraId, + virtual status_t hasFlashUnit(const String8& cameraId, bool *hasFlash) = 0; // set the torch mode to on or off. - virtual status_t setTorchMode(const String16& cameraId, + virtual status_t setTorchMode(const String8& cameraId, bool enabled) = 0; }; @@ -54,43 +55,61 @@ class CameraFlashlight : public virtual VirtualLightRefBase { const camera_module_callbacks_t& callbacks); virtual ~CameraFlashlight(); - // set the torch mode to on or off. - status_t setTorchMode(const String16& cameraId, bool enabled); + // Find all flash units. This must be called before other methods. All + // camera devices must be closed when it's called because HAL v1 devices + // need to be opened to query available flash modes. + status_t findFlashUnits(); - // Whether a camera device has a flash unit. Calling this function may - // cause the torch mode to be turned off in HAL v1 devices. - bool hasFlashUnit(const String16& cameraId); + // Whether a camera device has a flash unit. Before findFlashUnits() is + // called, this function always returns false. + bool hasFlashUnit(const String8& cameraId); + + // set the torch mode to on or off. + status_t setTorchMode(const String8& cameraId, bool enabled); // Notify CameraFlashlight that camera service is going to open a camera // device. CameraFlashlight will free the resources that may cause the // camera open to fail. Camera service must call this function before // opening a camera device. - status_t prepareDeviceOpen(); + status_t prepareDeviceOpen(const String8& cameraId); + + // Notify CameraFlashlight that camera service has closed a camera + // device. CameraFlashlight may invoke callbacks for torch mode + // available depending on the implementation. + status_t deviceClosed(const String8& cameraId); private: // create flashlight control based on camera module API and camera // device API versions. - status_t createFlashlightControl(const String16& cameraId); + status_t createFlashlightControl(const String8& cameraId); + + // mLock should be locked. + bool hasFlashUnitLocked(const String8& cameraId); sp<FlashControlBase> mFlashControl; CameraModule *mCameraModule; const camera_module_callbacks_t *mCallbacks; + SortedVector<String8> mOpenedCameraIds; - Mutex mLock; + // camera id -> if it has a flash unit + KeyedVector<String8, bool> mHasFlashlightMap; + bool mFlashlightMapInitialized; + + Mutex mLock; // protect CameraFlashlight API }; /** * Flash control for camera module v2.4 and above. */ -class FlashControl : public FlashControlBase { +class ModuleFlashControl : public FlashControlBase { public: - FlashControl(CameraModule& cameraModule, + ModuleFlashControl(CameraModule& cameraModule, const camera_module_callbacks_t& callbacks); - virtual ~FlashControl(); + virtual ~ModuleFlashControl(); // FlashControlBase - status_t hasFlashUnit(const String16& cameraId, bool *hasFlash); - status_t setTorchMode(const String16& cameraId, bool enabled); + status_t hasFlashUnit(const String8& cameraId, bool *hasFlash); + status_t setTorchMode(const String8& cameraId, bool enabled); private: CameraModule *mCameraModule; @@ -108,30 +127,37 @@ class CameraDeviceClientFlashControl : public FlashControlBase { virtual ~CameraDeviceClientFlashControl(); // FlashControlBase - status_t setTorchMode(const String16& cameraId, bool enabled); - status_t hasFlashUnit(const String16& cameraId, bool *hasFlash); + status_t setTorchMode(const String8& cameraId, bool enabled); + status_t hasFlashUnit(const String8& cameraId, bool *hasFlash); private: // connect to a camera device - status_t connectCameraDevice(const String16& cameraId); + status_t connectCameraDevice(const String8& cameraId); + // disconnect and free mDevice + status_t disconnectCameraDevice(); // initialize a surface - status_t initializeSurface(int32_t width, int32_t height); + status_t initializeSurface(sp<CameraDeviceBase>& device, int32_t width, + int32_t height); - // submit a request with the given torch mode - status_t submitTorchRequest(bool enabled); + // submit a request to enable the torch mode + status_t submitTorchEnabledRequest(); // get the smallest surface size of IMPLEMENTATION_DEFINED status_t getSmallestSurfaceSize(const camera_info& info, int32_t *width, int32_t *height); - status_t hasFlashUnitLocked(const String16& cameraId, bool *hasFlash); + status_t hasFlashUnitLocked(const String8& cameraId, bool *hasFlash); CameraModule *mCameraModule; const camera_module_callbacks_t *mCallbacks; - String16 mCameraId; + String8 mCameraId; bool mTorchEnabled; CameraMetadata *mMetadata; + // WORKAROUND: will be set to true for HAL v2 devices where + // setStreamingRequest() needs to be call for torch mode settings to + // take effect. + bool mStreaming; sp<CameraDeviceBase> mDevice; diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp index d65ac21..8fdfaa8 100644 --- a/services/camera/libcameraservice/CameraService.cpp +++ b/services/camera/libcameraservice/CameraService.cpp @@ -101,14 +101,14 @@ static void torch_mode_status_change( ICameraServiceListener::TorchStatus status; switch (new_status) { - case TORCH_MODE_STATUS_AVAILABLE: - status = ICameraServiceListener::TORCH_STATUS_AVAILABLE; - break; - case TORCH_MODE_STATUS_RESOURCE_BUSY: + case TORCH_MODE_STATUS_NOT_AVAILABLE: status = ICameraServiceListener::TORCH_STATUS_NOT_AVAILABLE; break; - case TORCH_MODE_STATUS_OFF: - status = ICameraServiceListener::TORCH_STATUS_OFF; + case TORCH_MODE_STATUS_AVAILABLE_OFF: + status = ICameraServiceListener::TORCH_STATUS_AVAILABLE_OFF; + break; + case TORCH_MODE_STATUS_AVAILABLE_ON: + status = ICameraServiceListener::TORCH_STATUS_AVAILABLE_ON; break; default: ALOGE("Unknown torch status %d", new_status); @@ -116,7 +116,7 @@ static void torch_mode_status_change( } cs->onTorchStatusChanged( - String16(camera_id), + String8(camera_id), status); } } // extern "C" @@ -156,23 +156,29 @@ void CameraService::onFirstRef() } else { mModule = new CameraModule(rawModule); - mFlashlight = new CameraFlashlight(*mModule, *this); - const hw_module_t *common = mModule->getRawModule(); - ALOGI("Loaded \"%s\" camera module", common->name); + ALOGI("Loaded \"%s\" cameraCa module", common->name); mNumberOfCameras = mModule->getNumberOfCameras(); if (mNumberOfCameras > MAX_CAMERAS) { ALOGE("Number of cameras(%d) > MAX_CAMERAS(%d).", mNumberOfCameras, MAX_CAMERAS); mNumberOfCameras = MAX_CAMERAS; } + + mFlashlight = new CameraFlashlight(*mModule, *this); + status_t res = mFlashlight->findFlashUnits(); + if (res) { + // impossible because we haven't open any camera devices. + ALOGE("failed to find flash units."); + } + for (int i = 0; i < mNumberOfCameras; i++) { setCameraFree(i); - String16 cameraName = String16(String8::format("%d", i)); + String8 cameraName = String8::format("%d", i); if (mFlashlight->hasFlashUnit(cameraName)) { mTorchStatusMap.add(cameraName, - ICameraServiceListener::TORCH_STATUS_AVAILABLE); + ICameraServiceListener::TORCH_STATUS_AVAILABLE_OFF); } } @@ -207,7 +213,7 @@ CameraService::~CameraService() { void CameraService::onDeviceStatusChanged(int cameraId, int newStatus) { - ALOGI("%s: Status changed for cameraId=%d, newStatus=%d", __FUNCTION__, + ALOGV("%s: Status changed for cameraId=%d, newStatus=%d", __FUNCTION__, cameraId, newStatus); if (cameraId < 0 || cameraId >= MAX_CAMERAS) { @@ -268,24 +274,30 @@ void CameraService::onDeviceStatusChanged(int cameraId, } -void CameraService::onTorchStatusChanged(const String16& cameraId, +void CameraService::onTorchStatusChanged(const String8& cameraId, ICameraServiceListener::TorchStatus newStatus) { Mutex::Autolock al(mTorchStatusMutex); onTorchStatusChangedLocked(cameraId, newStatus); } -void CameraService::onTorchStatusChangedLocked(const String16& cameraId, +void CameraService::onTorchStatusChangedLocked(const String8& cameraId, ICameraServiceListener::TorchStatus newStatus) { ALOGI("%s: Torch status changed for cameraId=%s, newStatus=%d", __FUNCTION__, cameraId.string(), newStatus); - if (getTorchStatusLocked(cameraId) == newStatus) { + ICameraServiceListener::TorchStatus status; + status_t res = getTorchStatusLocked(cameraId, &status); + if (res) { + ALOGE("%s: cannot get torch status of camera %s", cameraId.string()); + return; + } + if (status == newStatus) { ALOGE("%s: Torch state transition to the same status 0x%x not allowed", __FUNCTION__, (uint32_t)newStatus); return; } - status_t res = setTorchStatusLocked(cameraId, newStatus); + res = setTorchStatusLocked(cameraId, newStatus); if (res) { ALOGE("%s: Failed to set the torch status", __FUNCTION__, (uint32_t)newStatus); @@ -294,7 +306,7 @@ void CameraService::onTorchStatusChangedLocked(const String16& cameraId, Vector<sp<ICameraServiceListener> >::const_iterator it; for (it = mListenerList.begin(); it != mListenerList.end(); ++it) { - (*it)->onTorchStatusChanged(newStatus, cameraId); + (*it)->onTorchStatusChanged(newStatus, String16(cameraId.string())); } } @@ -754,7 +766,7 @@ status_t CameraService::connectHelperLocked( bool legacyMode) { // give flashlight a chance to close devices if necessary. - mFlashlight->prepareDeviceOpen(); + mFlashlight->prepareDeviceOpen(String8::format("%d", cameraId)); int facing = -1; int deviceVersion = getDeviceVersion(cameraId, &facing); @@ -932,44 +944,94 @@ status_t CameraService::connectLegacy( return OK; } +bool CameraService::validCameraIdForSetTorchMode(const String8& cameraId) { + // invalid string for int + if (cameraId.string() == NULL) { + return false; + } + errno = 0; + char *endptr; + long id = strtol(cameraId.string(), &endptr, 10); // base 10 + if (errno || id > INT_MAX || id < INT_MIN || *endptr != 0) { + return false; + } + + // id matches one of the plugged-in devices? + ICameraServiceListener::Status deviceStatus = getStatus(id); + if (deviceStatus != ICameraServiceListener::STATUS_PRESENT && + deviceStatus != ICameraServiceListener::STATUS_NOT_AVAILABLE) { + return false; + } + + return true; +} + status_t CameraService::setTorchMode(const String16& cameraId, bool enabled, const sp<IBinder>& clientBinder) { if (enabled && clientBinder == NULL) { ALOGE("%s: torch client binder is NULL", __FUNCTION__); - return -ENOSYS; + return -EINVAL; } - Mutex::Autolock al(mTorchStatusMutex); - status_t res = mFlashlight->setTorchMode(cameraId, enabled); + String8 id = String8(cameraId.string()); + + // verify id is valid. + if (validCameraIdForSetTorchMode(id) == false) { + ALOGE("%s: camera id is invalid %s", id.string()); + return -EINVAL; + } + + { + Mutex::Autolock al(mTorchStatusMutex); + ICameraServiceListener::TorchStatus status; + status_t res = getTorchStatusLocked(id, &status); + if (res) { + ALOGE("%s: getting current torch status failed for camera %s", + __FUNCTION__, id.string()); + return -EINVAL; + } + + if (status == ICameraServiceListener::TORCH_STATUS_NOT_AVAILABLE) { + if (getStatus(atoi(id.string())) == + ICameraServiceListener::STATUS_NOT_AVAILABLE) { + ALOGE("%s: torch mode of camera %s is not available because " + "camera is in use", __FUNCTION__, id.string()); + return -EBUSY; + } else { + ALOGE("%s: torch mode of camera %s is not available due to " + "insufficient resources", __FUNCTION__, id.string()); + return -EUSERS; + } + } + } + + status_t res = mFlashlight->setTorchMode(id, enabled); if (res) { - ALOGE("%s: setting torch mode of camera %s to %d failed", __FUNCTION__, - cameraId.string(), enabled); + ALOGE("%s: setting torch mode of camera %s to %d failed. %s (%d)", + __FUNCTION__, id.string(), enabled, strerror(-res), res); return res; } - // update the link to client's death - ssize_t index = mTorchClientMap.indexOfKey(cameraId); - if (enabled) { - if (index == NAME_NOT_FOUND) { - mTorchClientMap.add(cameraId, clientBinder); - } else { - const sp<IBinder> oldBinder = mTorchClientMap.valueAt(index); - oldBinder->unlinkToDeath(this); + { + // update the link to client's death + Mutex::Autolock al(mTorchClientMapMutex); + ssize_t index = mTorchClientMap.indexOfKey(id); + if (enabled) { + if (index == NAME_NOT_FOUND) { + mTorchClientMap.add(id, clientBinder); + } else { + const sp<IBinder> oldBinder = mTorchClientMap.valueAt(index); + oldBinder->unlinkToDeath(this); - mTorchClientMap.replaceValueAt(index, clientBinder); + mTorchClientMap.replaceValueAt(index, clientBinder); + } + clientBinder->linkToDeath(this); + } else if (index != NAME_NOT_FOUND) { + sp<IBinder> oldBinder = mTorchClientMap.valueAt(index); + oldBinder->unlinkToDeath(this); } - clientBinder->linkToDeath(this); - } else if (index != NAME_NOT_FOUND) { - sp<IBinder> oldBinder = mTorchClientMap.valueAt(index); - oldBinder->unlinkToDeath(this); } - // notify the listeners the change. - ICameraServiceListener::TorchStatus status = enabled ? - ICameraServiceListener::TORCH_STATUS_ON : - ICameraServiceListener::TORCH_STATUS_OFF; - onTorchStatusChangedLocked(cameraId, status); - return OK; } @@ -1099,7 +1161,7 @@ status_t CameraService::connectDevice( int deviceVersion = getDeviceVersion(cameraId, &facing); // give flashlight a chance to close devices if necessary. - mFlashlight->prepareDeviceOpen(); + mFlashlight->prepareDeviceOpen(String8::format("%d", cameraId)); switch(deviceVersion) { case CAMERA_DEVICE_API_VERSION_1_0: @@ -1176,8 +1238,8 @@ status_t CameraService::addListener( { Mutex::Autolock al(mTorchStatusMutex); for (size_t i = 0; i < mTorchStatusMap.size(); i++ ) { - listener->onTorchStatusChanged(mTorchStatusMap.valueAt(i), - mTorchStatusMap.keyAt(i)); + String16 id = String16(mTorchStatusMap.keyAt(i).string()); + listener->onTorchStatusChanged(mTorchStatusMap.valueAt(i), id); } } @@ -1616,6 +1678,9 @@ status_t CameraService::BasicClient::finishCameraOps() { mCameraId, &rejectSourceStates); + // Notify flashlight that a camera device is closed. + mCameraService->mFlashlight->deviceClosed( + String8::format("%d", mCameraId)); } // Always stop watching, even if no camera op is active if (mOpsCallback != NULL) { @@ -1862,17 +1927,18 @@ status_t CameraService::dump(int fd, const Vector<String16>& args) { } void CameraService::handleTorchClientBinderDied(const wp<IBinder> &who) { - Mutex::Autolock al(mTorchStatusMutex); + Mutex::Autolock al(mTorchClientMapMutex); for (size_t i = 0; i < mTorchClientMap.size(); i++) { if (mTorchClientMap[i] == who) { // turn off the torch mode that was turned on by dead client - String16 cameraId = mTorchClientMap.keyAt(i); - mFlashlight->setTorchMode(cameraId, false); + String8 cameraId = mTorchClientMap.keyAt(i); + status_t res = mFlashlight->setTorchMode(cameraId, false); + if (res) { + ALOGE("%s: torch client died but couldn't turn off torch: " + "%s (%d)", __FUNCTION__, strerror(-res), res); + return; + } mTorchClientMap.removeItemsAt(i); - - // notify torch mode was turned off - onTorchStatusChangedLocked(cameraId, - ICameraServiceListener::TORCH_STATUS_OFF); break; } } @@ -1968,6 +2034,19 @@ void CameraService::updateStatus(ICameraServiceListener::Status status, } } + if (status == ICameraServiceListener::STATUS_NOT_PRESENT || + status == ICameraServiceListener::STATUS_NOT_AVAILABLE) { + // update torch status to not available when the camera device + // becomes not present or not available. + onTorchStatusChanged(String8::format("%d", cameraId), + ICameraServiceListener::TORCH_STATUS_NOT_AVAILABLE); + } else if (status == ICameraServiceListener::STATUS_PRESENT) { + // update torch status to available when the camera device becomes + // present or available + onTorchStatusChanged(String8::format("%d", cameraId), + ICameraServiceListener::TORCH_STATUS_AVAILABLE_OFF); + } + Vector<sp<ICameraServiceListener> >::const_iterator it; for (it = mListenerList.begin(); it != mListenerList.end(); ++it) { (*it)->onStatusChanged(status, cameraId); @@ -1985,17 +2064,23 @@ ICameraServiceListener::Status CameraService::getStatus(int cameraId) const { return mStatusList[cameraId]; } -ICameraServiceListener::TorchStatus CameraService::getTorchStatusLocked( - const String16& cameraId) const { +status_t CameraService::getTorchStatusLocked( + const String8& cameraId, + ICameraServiceListener::TorchStatus *status) const { + if (!status) { + return BAD_VALUE; + } ssize_t index = mTorchStatusMap.indexOfKey(cameraId); if (index == NAME_NOT_FOUND) { - return ICameraServiceListener::TORCH_STATUS_NOT_AVAILABLE; + // invalid camera ID or the camera doesn't have a flash unit + return NAME_NOT_FOUND; } - return mTorchStatusMap.valueAt(index); + *status = mTorchStatusMap.valueAt(index); + return OK; } -status_t CameraService::setTorchStatusLocked(const String16& cameraId, +status_t CameraService::setTorchStatusLocked(const String8& cameraId, ICameraServiceListener::TorchStatus status) { ssize_t index = mTorchStatusMap.indexOfKey(cameraId); if (index == NAME_NOT_FOUND) { diff --git a/services/camera/libcameraservice/CameraService.h b/services/camera/libcameraservice/CameraService.h index 84bcdb8..74b3623 100644 --- a/services/camera/libcameraservice/CameraService.h +++ b/services/camera/libcameraservice/CameraService.h @@ -72,7 +72,7 @@ public: // HAL Callbacks virtual void onDeviceStatusChanged(int cameraId, int newStatus); - virtual void onTorchStatusChanged(const String16& cameraId, + virtual void onTorchStatusChanged(const String8& cameraId, ICameraServiceListener::TorchStatus newStatus); @@ -418,28 +418,33 @@ private: // flashlight control sp<CameraFlashlight> mFlashlight; - // guard mTorchStatusMap and mTorchClientMap + // guard mTorchStatusMap Mutex mTorchStatusMutex; + // guard mTorchClientMap + Mutex mTorchClientMapMutex; // camera id -> torch status - KeyedVector<String16, ICameraServiceListener::TorchStatus> mTorchStatusMap; + KeyedVector<String8, ICameraServiceListener::TorchStatus> mTorchStatusMap; // camera id -> torch client binder // only store the last client that turns on each camera's torch mode - KeyedVector<String16, sp<IBinder> > mTorchClientMap; + KeyedVector<String8, sp<IBinder> > mTorchClientMap; // check and handle if torch client's process has died void handleTorchClientBinderDied(const wp<IBinder> &who); // handle torch mode status change and invoke callbacks. mTorchStatusMutex // should be locked. - void onTorchStatusChangedLocked(const String16& cameraId, + void onTorchStatusChangedLocked(const String8& cameraId, ICameraServiceListener::TorchStatus newStatus); + // validate the camera id for use of setting a torch mode. + bool validCameraIdForSetTorchMode(const String8& cameraId); + // get a camera's torch status. mTorchStatusMutex should be locked. - ICameraServiceListener::TorchStatus getTorchStatusLocked( - const String16 &cameraId) const; + status_t getTorchStatusLocked(const String8 &cameraId, + ICameraServiceListener::TorchStatus *status) const; // set a camera's torch status. mTorchStatusMutex should be locked. - status_t setTorchStatusLocked(const String16 &cameraId, + status_t setTorchStatusLocked(const String8 &cameraId, ICameraServiceListener::TorchStatus status); // IBinder::DeathRecipient implementation |