1/*
2 * Copyright (C) 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#define LOG_TAG "CameraFlashlight"
18#define ATRACE_TAG ATRACE_TAG_CAMERA
19// #define LOG_NDEBUG 0
20
21#include <utils/Log.h>
22#include <utils/Trace.h>
23#include <cutils/properties.h>
24
25#include "camera/CameraMetadata.h"
26#include "CameraFlashlight.h"
27#include "gui/IGraphicBufferConsumer.h"
28#include "gui/BufferQueue.h"
29#include "camera/camera2/CaptureRequest.h"
30#include "device3/Camera3Device.h"
31
32
33namespace android {
34
35/////////////////////////////////////////////////////////////////////
36// CameraFlashlight implementation begins
37// used by camera service to control flashflight.
38/////////////////////////////////////////////////////////////////////
39
40CameraFlashlight::CameraFlashlight(sp<CameraProviderManager> providerManager,
41        camera_module_callbacks_t* callbacks) :
42        mProviderManager(providerManager),
43        mCallbacks(callbacks),
44        mFlashlightMapInitialized(false) {
45}
46
47CameraFlashlight::~CameraFlashlight() {
48}
49
50status_t CameraFlashlight::createFlashlightControl(const String8& cameraId) {
51    ALOGV("%s: creating a flash light control for camera %s", __FUNCTION__,
52            cameraId.string());
53    if (mFlashControl != NULL) {
54        return INVALID_OPERATION;
55    }
56
57    if (mProviderManager->supportSetTorchMode(cameraId.string())) {
58        mFlashControl = new ProviderFlashControl(mProviderManager);
59    } else {
60        // Only HAL1 devices do not support setTorchMode
61        mFlashControl =
62                new CameraHardwareInterfaceFlashControl(mProviderManager, *mCallbacks);
63    }
64
65    return OK;
66}
67
68status_t CameraFlashlight::setTorchMode(const String8& cameraId, bool enabled) {
69    if (!mFlashlightMapInitialized) {
70        ALOGE("%s: findFlashUnits() must be called before this method.",
71               __FUNCTION__);
72        return NO_INIT;
73    }
74
75    ALOGV("%s: set torch mode of camera %s to %d", __FUNCTION__,
76            cameraId.string(), enabled);
77
78    status_t res = OK;
79    Mutex::Autolock l(mLock);
80
81    if (mOpenedCameraIds.indexOf(cameraId) != NAME_NOT_FOUND) {
82        // This case is needed to avoid state corruption during the following call sequence:
83        // CameraService::setTorchMode for camera ID 0 begins, does torch status checks
84        // CameraService::connect for camera ID 0 begins, calls prepareDeviceOpen, ends
85        // CameraService::setTorchMode for camera ID 0 continues, calls
86        //        CameraFlashlight::setTorchMode
87
88        // TODO: Move torch status checks and state updates behind this CameraFlashlight lock
89        // to avoid other similar race conditions.
90        ALOGE("%s: Camera device %s is in use, cannot set torch mode.",
91                __FUNCTION__, cameraId.string());
92        return -EBUSY;
93    }
94
95    if (mFlashControl == NULL) {
96        res = createFlashlightControl(cameraId);
97        if (res) {
98            return res;
99        }
100        res =  mFlashControl->setTorchMode(cameraId, enabled);
101        return res;
102    }
103
104    // if flash control already exists, turning on torch mode may fail if it's
105    // tied to another camera device for module v2.3 and below.
106    res = mFlashControl->setTorchMode(cameraId, enabled);
107    if (res == BAD_INDEX) {
108        // flash control is tied to another camera device, need to close it and
109        // try again.
110        mFlashControl.clear();
111        res = createFlashlightControl(cameraId);
112        if (res) {
113            return res;
114        }
115        res = mFlashControl->setTorchMode(cameraId, enabled);
116    }
117
118    return res;
119}
120
121int CameraFlashlight::getNumberOfCameras() {
122    return mProviderManager->getAPI1CompatibleCameraCount();
123}
124
125status_t CameraFlashlight::findFlashUnits() {
126    Mutex::Autolock l(mLock);
127    status_t res;
128
129    std::vector<String8> cameraIds;
130    int numberOfCameras = getNumberOfCameras();
131    cameraIds.resize(numberOfCameras);
132    // No module, must be provider
133    std::vector<std::string> ids = mProviderManager->getAPI1CompatibleCameraDeviceIds();
134    for (size_t i = 0; i < cameraIds.size(); i++) {
135        cameraIds[i] = String8(ids[i].c_str());
136    }
137
138    mFlashControl.clear();
139
140    for (auto &id : cameraIds) {
141        ssize_t index = mHasFlashlightMap.indexOfKey(id);
142        if (0 <= index) {
143            continue;
144        }
145
146        bool hasFlash = false;
147        res = createFlashlightControl(id);
148        if (res) {
149            ALOGE("%s: failed to create flash control for %s", __FUNCTION__,
150                    id.string());
151        } else {
152            res = mFlashControl->hasFlashUnit(id, &hasFlash);
153            if (res == -EUSERS || res == -EBUSY) {
154                ALOGE("%s: failed to check if camera %s has a flash unit. Some "
155                        "camera devices may be opened", __FUNCTION__,
156                        id.string());
157                return res;
158            } else if (res) {
159                ALOGE("%s: failed to check if camera %s has a flash unit. %s"
160                        " (%d)", __FUNCTION__, id.string(), strerror(-res),
161                        res);
162            }
163
164            mFlashControl.clear();
165        }
166        mHasFlashlightMap.add(id, hasFlash);
167    }
168
169    mFlashlightMapInitialized = true;
170    return OK;
171}
172
173bool CameraFlashlight::hasFlashUnit(const String8& cameraId) {
174    Mutex::Autolock l(mLock);
175    return hasFlashUnitLocked(cameraId);
176}
177
178bool CameraFlashlight::hasFlashUnitLocked(const String8& cameraId) {
179    if (!mFlashlightMapInitialized) {
180        ALOGE("%s: findFlashUnits() must be called before this method.",
181               __FUNCTION__);
182        return false;
183    }
184
185    ssize_t index = mHasFlashlightMap.indexOfKey(cameraId);
186    if (index == NAME_NOT_FOUND) {
187        ALOGE("%s: camera %s not present when findFlashUnits() was called",
188                __FUNCTION__, cameraId.string());
189        return false;
190    }
191
192    return mHasFlashlightMap.valueAt(index);
193}
194
195bool CameraFlashlight::isBackwardCompatibleMode(const String8& cameraId) {
196    bool backwardCompatibleMode = false;
197    if (mProviderManager != nullptr &&
198            !mProviderManager->supportSetTorchMode(cameraId.string())) {
199        backwardCompatibleMode = true;
200    }
201    return backwardCompatibleMode;
202}
203
204status_t CameraFlashlight::prepareDeviceOpen(const String8& cameraId) {
205    ALOGV("%s: prepare for device open", __FUNCTION__);
206
207    Mutex::Autolock l(mLock);
208    if (!mFlashlightMapInitialized) {
209        ALOGE("%s: findFlashUnits() must be called before this method.",
210               __FUNCTION__);
211        return NO_INIT;
212    }
213
214    if (isBackwardCompatibleMode(cameraId)) {
215        // framework is going to open a camera device, all flash light control
216        // should be closed for backward compatible support.
217        mFlashControl.clear();
218
219        if (mOpenedCameraIds.size() == 0) {
220            // notify torch unavailable for all cameras with a flash
221            int numCameras = getNumberOfCameras();
222            for (int i = 0; i < numCameras; i++) {
223                if (hasFlashUnitLocked(String8::format("%d", i))) {
224                    mCallbacks->torch_mode_status_change(mCallbacks,
225                            String8::format("%d", i).string(),
226                            TORCH_MODE_STATUS_NOT_AVAILABLE);
227                }
228            }
229        }
230
231        // close flash control that may be opened by calling hasFlashUnitLocked.
232        mFlashControl.clear();
233    }
234
235    if (mOpenedCameraIds.indexOf(cameraId) == NAME_NOT_FOUND) {
236        mOpenedCameraIds.add(cameraId);
237    }
238
239    return OK;
240}
241
242status_t CameraFlashlight::deviceClosed(const String8& cameraId) {
243    ALOGV("%s: device %s is closed", __FUNCTION__, cameraId.string());
244
245    Mutex::Autolock l(mLock);
246    if (!mFlashlightMapInitialized) {
247        ALOGE("%s: findFlashUnits() must be called before this method.",
248               __FUNCTION__);
249        return NO_INIT;
250    }
251
252    ssize_t index = mOpenedCameraIds.indexOf(cameraId);
253    if (index == NAME_NOT_FOUND) {
254        ALOGE("%s: couldn't find camera %s in the opened list", __FUNCTION__,
255                cameraId.string());
256    } else {
257        mOpenedCameraIds.removeAt(index);
258    }
259
260    // Cannot do anything until all cameras are closed.
261    if (mOpenedCameraIds.size() != 0)
262        return OK;
263
264    if (isBackwardCompatibleMode(cameraId)) {
265        // notify torch available for all cameras with a flash
266        int numCameras = getNumberOfCameras();
267        for (int i = 0; i < numCameras; i++) {
268            if (hasFlashUnitLocked(String8::format("%d", i))) {
269                mCallbacks->torch_mode_status_change(mCallbacks,
270                        String8::format("%d", i).string(),
271                        TORCH_MODE_STATUS_AVAILABLE_OFF);
272            }
273        }
274    }
275
276    return OK;
277}
278// CameraFlashlight implementation ends
279
280
281FlashControlBase::~FlashControlBase() {
282}
283
284/////////////////////////////////////////////////////////////////////
285// ModuleFlashControl implementation begins
286// Flash control for camera module v2.4 and above.
287/////////////////////////////////////////////////////////////////////
288ProviderFlashControl::ProviderFlashControl(sp<CameraProviderManager> providerManager) :
289        mProviderManager(providerManager) {
290}
291
292ProviderFlashControl::~ProviderFlashControl() {
293}
294
295status_t ProviderFlashControl::hasFlashUnit(const String8& cameraId, bool *hasFlash) {
296    if (!hasFlash) {
297        return BAD_VALUE;
298    }
299    *hasFlash = mProviderManager->hasFlashUnit(cameraId.string());
300    return OK;
301}
302
303status_t ProviderFlashControl::setTorchMode(const String8& cameraId, bool enabled) {
304    ALOGV("%s: set camera %s torch mode to %d", __FUNCTION__,
305            cameraId.string(), enabled);
306
307    return mProviderManager->setTorchMode(cameraId.string(), enabled);
308}
309// ProviderFlashControl implementation ends
310
311/////////////////////////////////////////////////////////////////////
312// CameraHardwareInterfaceFlashControl implementation begins
313// Flash control for camera module <= v2.3 and camera HAL v1
314/////////////////////////////////////////////////////////////////////
315
316CameraHardwareInterfaceFlashControl::CameraHardwareInterfaceFlashControl(
317        sp<CameraProviderManager> manager,
318        const camera_module_callbacks_t& callbacks) :
319        mProviderManager(manager),
320        mCallbacks(&callbacks),
321        mTorchEnabled(false) {
322}
323
324CameraHardwareInterfaceFlashControl::~CameraHardwareInterfaceFlashControl() {
325    disconnectCameraDevice();
326
327    mSurface.clear();
328    mSurfaceTexture.clear();
329    mProducer.clear();
330    mConsumer.clear();
331
332    if (mTorchEnabled) {
333        if (mCallbacks) {
334            ALOGV("%s: notify the framework that torch was turned off",
335                    __FUNCTION__);
336            mCallbacks->torch_mode_status_change(mCallbacks,
337                    mCameraId.string(), TORCH_MODE_STATUS_AVAILABLE_OFF);
338        }
339    }
340}
341
342status_t CameraHardwareInterfaceFlashControl::setTorchMode(
343        const String8& cameraId, bool enabled) {
344    Mutex::Autolock l(mLock);
345
346    // pre-check
347    status_t res;
348    if (enabled) {
349        bool hasFlash = false;
350        // Check if it has a flash unit and leave camera device open.
351        res = hasFlashUnitLocked(cameraId, &hasFlash, /*keepDeviceOpen*/true);
352        // invalid camera?
353        if (res) {
354            // hasFlashUnitLocked() returns BAD_INDEX if mDevice is connected to
355            // another camera device.
356            return res == BAD_INDEX ? BAD_INDEX : -EINVAL;
357        }
358        // no flash unit?
359        if (!hasFlash) {
360            // Disconnect camera device if it has no flash.
361            disconnectCameraDevice();
362            return -ENOSYS;
363        }
364    } else if (mDevice == NULL || cameraId != mCameraId) {
365        // disabling the torch mode of an un-opened or different device.
366        return OK;
367    } else {
368        // disabling the torch mode of currently opened device
369        disconnectCameraDevice();
370        mTorchEnabled = false;
371        mCallbacks->torch_mode_status_change(mCallbacks,
372            cameraId.string(), TORCH_MODE_STATUS_AVAILABLE_OFF);
373        return OK;
374    }
375
376    res = startPreviewAndTorch();
377    if (res) {
378        return res;
379    }
380
381    mTorchEnabled = true;
382    mCallbacks->torch_mode_status_change(mCallbacks,
383            cameraId.string(), TORCH_MODE_STATUS_AVAILABLE_ON);
384    return OK;
385}
386
387status_t CameraHardwareInterfaceFlashControl::hasFlashUnit(
388        const String8& cameraId, bool *hasFlash) {
389    Mutex::Autolock l(mLock);
390    // Close device after checking if it has a flash unit.
391    return hasFlashUnitLocked(cameraId, hasFlash, /*keepDeviceOpen*/false);
392}
393
394status_t CameraHardwareInterfaceFlashControl::hasFlashUnitLocked(
395        const String8& cameraId, bool *hasFlash, bool keepDeviceOpen) {
396    bool closeCameraDevice = false;
397
398    if (!hasFlash) {
399        return BAD_VALUE;
400    }
401
402    status_t res;
403    if (mDevice == NULL) {
404        // Connect to camera device to query if it has a flash unit.
405        res = connectCameraDevice(cameraId);
406        if (res) {
407            return res;
408        }
409        // Close camera device only when it is just opened and the caller doesn't want to keep
410        // the camera device open.
411        closeCameraDevice = !keepDeviceOpen;
412    }
413
414    if (cameraId != mCameraId) {
415        return BAD_INDEX;
416    }
417
418    const char *flashMode =
419            mParameters.get(CameraParameters::KEY_SUPPORTED_FLASH_MODES);
420    if (flashMode && strstr(flashMode, CameraParameters::FLASH_MODE_TORCH)) {
421        *hasFlash = true;
422    } else {
423        *hasFlash = false;
424    }
425
426    if (closeCameraDevice) {
427        res = disconnectCameraDevice();
428        if (res != OK) {
429            ALOGE("%s: Failed to disconnect camera device. %s (%d)", __FUNCTION__,
430                    strerror(-res), res);
431            return res;
432        }
433    }
434
435    return OK;
436}
437
438status_t CameraHardwareInterfaceFlashControl::startPreviewAndTorch() {
439    status_t res = OK;
440    res = mDevice->startPreview();
441    if (res) {
442        ALOGE("%s: start preview failed. %s (%d)", __FUNCTION__,
443                strerror(-res), res);
444        return res;
445    }
446
447    mParameters.set(CameraParameters::KEY_FLASH_MODE,
448            CameraParameters::FLASH_MODE_TORCH);
449
450    return mDevice->setParameters(mParameters);
451}
452
453status_t CameraHardwareInterfaceFlashControl::getSmallestSurfaceSize(
454        int32_t *width, int32_t *height) {
455    if (!width || !height) {
456        return BAD_VALUE;
457    }
458
459    int32_t w = INT32_MAX;
460    int32_t h = 1;
461    Vector<Size> sizes;
462
463    mParameters.getSupportedPreviewSizes(sizes);
464    for (size_t i = 0; i < sizes.size(); i++) {
465        Size s = sizes[i];
466        if (w * h > s.width * s.height) {
467            w = s.width;
468            h = s.height;
469        }
470    }
471
472    if (w == INT32_MAX) {
473        return NAME_NOT_FOUND;
474    }
475
476    *width = w;
477    *height = h;
478
479    return OK;
480}
481
482status_t CameraHardwareInterfaceFlashControl::initializePreviewWindow(
483        const sp<CameraHardwareInterface>& device, int32_t width, int32_t height) {
484    status_t res;
485    BufferQueue::createBufferQueue(&mProducer, &mConsumer);
486
487    mSurfaceTexture = new GLConsumer(mConsumer, 0, GLConsumer::TEXTURE_EXTERNAL,
488            true, true);
489    if (mSurfaceTexture == NULL) {
490        return NO_MEMORY;
491    }
492
493    int32_t format = HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED;
494    res = mSurfaceTexture->setDefaultBufferSize(width, height);
495    if (res) {
496        return res;
497    }
498    res = mSurfaceTexture->setDefaultBufferFormat(format);
499    if (res) {
500        return res;
501    }
502
503    mSurface = new Surface(mProducer, /*useAsync*/ true);
504    if (mSurface == NULL) {
505        return NO_MEMORY;
506    }
507
508    res = native_window_api_connect(mSurface.get(), NATIVE_WINDOW_API_CAMERA);
509    if (res) {
510        ALOGE("%s: Unable to connect to native window", __FUNCTION__);
511        return res;
512    }
513
514    return device->setPreviewWindow(mSurface);
515}
516
517status_t CameraHardwareInterfaceFlashControl::connectCameraDevice(
518        const String8& cameraId) {
519    sp<CameraHardwareInterface> device =
520            new CameraHardwareInterface(cameraId.string());
521
522    status_t res = device->initialize(mProviderManager);
523    if (res) {
524        ALOGE("%s: initializing camera %s failed", __FUNCTION__,
525                cameraId.string());
526        return res;
527    }
528
529    // need to set __get_memory in set_callbacks().
530    device->setCallbacks(NULL, NULL, NULL, NULL, NULL);
531
532    mParameters = device->getParameters();
533
534    int32_t width, height;
535    res = getSmallestSurfaceSize(&width, &height);
536    if (res) {
537        ALOGE("%s: failed to get smallest surface size for camera %s",
538                __FUNCTION__, cameraId.string());
539        return res;
540    }
541
542    res = initializePreviewWindow(device, width, height);
543    if (res) {
544        ALOGE("%s: failed to initialize preview window for camera %s",
545                __FUNCTION__, cameraId.string());
546        return res;
547    }
548
549    mCameraId = cameraId;
550    mDevice = device;
551    return OK;
552}
553
554status_t CameraHardwareInterfaceFlashControl::disconnectCameraDevice() {
555    if (mDevice == NULL) {
556        return OK;
557    }
558
559    if (mParameters.get(CameraParameters::KEY_FLASH_MODE)) {
560        // There is a flash, turn if off.
561        // (If there isn't one, leave the parameter null)
562        mParameters.set(CameraParameters::KEY_FLASH_MODE,
563                CameraParameters::FLASH_MODE_OFF);
564        mDevice->setParameters(mParameters);
565    }
566    mDevice->stopPreview();
567    status_t res = native_window_api_disconnect(mSurface.get(),
568            NATIVE_WINDOW_API_CAMERA);
569    if (res) {
570        ALOGW("%s: native_window_api_disconnect failed: %s (%d)",
571                __FUNCTION__, strerror(-res), res);
572    }
573    mDevice->setPreviewWindow(NULL);
574    mDevice->release();
575    mDevice = NULL;
576
577    return OK;
578}
579// CameraHardwareInterfaceFlashControl implementation ends
580
581}
582