TYPE3
[iec.git] / src / type3_AndroidCloud / anbox-master / android / camera / EmulatedCameraFactory.cpp
diff --git a/src/type3_AndroidCloud/anbox-master/android/camera/EmulatedCameraFactory.cpp b/src/type3_AndroidCloud/anbox-master/android/camera/EmulatedCameraFactory.cpp
new file mode 100644 (file)
index 0000000..137d8ab
--- /dev/null
@@ -0,0 +1,542 @@
+/*
+ * 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 <cutils/log.h>
+#include <cutils/properties.h>
+#include "EmulatedQemuCamera.h"
+#include "EmulatedFakeCamera.h"
+#include "EmulatedFakeCamera2.h"
+#include "EmulatedFakeCamera3.h"
+#include "EmulatedCameraHotplugThread.h"
+#include "EmulatedCameraFactory.h"
+
+extern camera_module_t HAL_MODULE_INFO_SYM;
+
+/* A global instance of EmulatedCameraFactory is statically instantiated and
+ * initialized when camera emulation HAL is loaded.
+ */
+android::EmulatedCameraFactory  gEmulatedCameraFactory;
+
+namespace android {
+
+EmulatedCameraFactory::EmulatedCameraFactory()
+        : mQemuClient(),
+          mEmulatedCameras(NULL),
+          mEmulatedCameraNum(0),
+          mFakeCameraNum(0),
+          mConstructedOK(false),
+          mCallbacks(NULL)
+{
+    status_t res;
+    /* Connect to the factory service in the emulator, and create Qemu cameras. */
+    if (mQemuClient.connectClient(NULL) == NO_ERROR) {
+        /* Connection has succeeded. Create emulated cameras for each camera
+         * device, reported by the service. */
+        createQemuCameras();
+    }
+
+    if (isBackFakeCameraEmulationOn()) {
+        /* Camera ID. */
+        const int camera_id = mEmulatedCameraNum;
+        /* Use fake camera to emulate back-facing camera. */
+        mEmulatedCameraNum++;
+
+        /* Make sure that array is allocated (in case there were no 'qemu'
+         * cameras created. Note that we preallocate the array so it may contain
+         * two fake cameras: one facing back, and another facing front. */
+        if (mEmulatedCameras == NULL) {
+            mEmulatedCameras = new EmulatedBaseCamera*[mEmulatedCameraNum + 1];
+            if (mEmulatedCameras == NULL) {
+                ALOGE("%s: Unable to allocate emulated camera array for %d entries",
+                     __FUNCTION__, mEmulatedCameraNum);
+                return;
+            }
+            memset(mEmulatedCameras, 0,
+                    (mEmulatedCameraNum + 1) * sizeof(EmulatedBaseCamera*));
+        }
+
+        /* Create, and initialize the fake camera */
+        switch (getBackCameraHalVersion()) {
+            case 1:
+                mEmulatedCameras[camera_id] =
+                        new EmulatedFakeCamera(camera_id, true,
+                                &HAL_MODULE_INFO_SYM.common);
+                break;
+            case 2:
+                mEmulatedCameras[camera_id] =
+                        new EmulatedFakeCamera2(camera_id, true,
+                                &HAL_MODULE_INFO_SYM.common);
+                break;
+            case 3:
+                mEmulatedCameras[camera_id] =
+                        new EmulatedFakeCamera3(camera_id, true,
+                                &HAL_MODULE_INFO_SYM.common);
+                break;
+            default:
+                ALOGE("%s: Unknown back camera hal version requested: %d", __FUNCTION__,
+                        getBackCameraHalVersion());
+        }
+        if (mEmulatedCameras[camera_id] != NULL) {
+            ALOGV("%s: Back camera device version is %d", __FUNCTION__,
+                    getBackCameraHalVersion());
+            res = mEmulatedCameras[camera_id]->Initialize();
+            if (res != NO_ERROR) {
+                ALOGE("%s: Unable to intialize back camera %d: %s (%d)",
+                        __FUNCTION__, camera_id, strerror(-res), res);
+                delete mEmulatedCameras[camera_id];
+                mEmulatedCameraNum--;
+            }
+        } else {
+            mEmulatedCameraNum--;
+            ALOGE("%s: Unable to instantiate fake camera class", __FUNCTION__);
+        }
+    }
+
+    if (isFrontFakeCameraEmulationOn()) {
+        /* Camera ID. */
+        const int camera_id = mEmulatedCameraNum;
+        /* Use fake camera to emulate front-facing camera. */
+        mEmulatedCameraNum++;
+
+        /* Make sure that array is allocated (in case there were no 'qemu'
+         * cameras created. */
+        if (mEmulatedCameras == NULL) {
+            mEmulatedCameras = new EmulatedBaseCamera*[mEmulatedCameraNum];
+            if (mEmulatedCameras == NULL) {
+                ALOGE("%s: Unable to allocate emulated camera array for %d entries",
+                     __FUNCTION__, mEmulatedCameraNum);
+                return;
+            }
+            memset(mEmulatedCameras, 0,
+                    mEmulatedCameraNum * sizeof(EmulatedBaseCamera*));
+        }
+
+        /* Create, and initialize the fake camera */
+        switch (getFrontCameraHalVersion()) {
+            case 1:
+                mEmulatedCameras[camera_id] =
+                        new EmulatedFakeCamera(camera_id, false,
+                                &HAL_MODULE_INFO_SYM.common);
+                break;
+            case 2:
+                mEmulatedCameras[camera_id] =
+                        new EmulatedFakeCamera2(camera_id, false,
+                                &HAL_MODULE_INFO_SYM.common);
+                break;
+            case 3:
+                mEmulatedCameras[camera_id] =
+                        new EmulatedFakeCamera3(camera_id, false,
+                                &HAL_MODULE_INFO_SYM.common);
+                break;
+            default:
+                ALOGE("%s: Unknown front camera hal version requested: %d",
+                        __FUNCTION__,
+                        getFrontCameraHalVersion());
+        }
+        if (mEmulatedCameras[camera_id] != NULL) {
+            ALOGV("%s: Front camera device version is %d", __FUNCTION__,
+                    getFrontCameraHalVersion());
+            res = mEmulatedCameras[camera_id]->Initialize();
+            if (res != NO_ERROR) {
+                ALOGE("%s: Unable to intialize front camera %d: %s (%d)",
+                        __FUNCTION__, camera_id, strerror(-res), res);
+                delete mEmulatedCameras[camera_id];
+                mEmulatedCameraNum--;
+            }
+        } else {
+            mEmulatedCameraNum--;
+            ALOGE("%s: Unable to instantiate fake camera class", __FUNCTION__);
+        }
+    }
+
+    ALOGV("%d cameras are being emulated. %d of them are fake cameras.",
+          mEmulatedCameraNum, mFakeCameraNum);
+
+    /* Create hotplug thread */
+    {
+        Vector<int> cameraIdVector;
+        for (int i = 0; i < mEmulatedCameraNum; ++i) {
+            cameraIdVector.push_back(i);
+        }
+        mHotplugThread = new EmulatedCameraHotplugThread(&cameraIdVector[0],
+                                                         mEmulatedCameraNum);
+        mHotplugThread->run("EmulatedCameraHotplugThread");
+    }
+
+    mConstructedOK = true;
+}
+
+EmulatedCameraFactory::~EmulatedCameraFactory()
+{
+    if (mEmulatedCameras != NULL) {
+        for (int n = 0; n < mEmulatedCameraNum; n++) {
+            if (mEmulatedCameras[n] != NULL) {
+                delete mEmulatedCameras[n];
+            }
+        }
+        delete[] mEmulatedCameras;
+    }
+
+    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;
+
+    if (!isConstructedOK()) {
+        ALOGE("%s: EmulatedCameraFactory has failed to initialize", __FUNCTION__);
+        return -EINVAL;
+    }
+
+    if (camera_id < 0 || camera_id >= getEmulatedCameraNum()) {
+        ALOGE("%s: Camera id %d is out of bounds (%d)",
+             __FUNCTION__, camera_id, getEmulatedCameraNum());
+        return -ENODEV;
+    }
+
+    return mEmulatedCameras[camera_id]->connectCamera(device);
+}
+
+int EmulatedCameraFactory::getCameraInfo(int camera_id, struct camera_info* info)
+{
+    ALOGV("%s: id = %d", __FUNCTION__, camera_id);
+
+    if (!isConstructedOK()) {
+        ALOGE("%s: EmulatedCameraFactory has failed to initialize", __FUNCTION__);
+        return -EINVAL;
+    }
+
+    if (camera_id < 0 || camera_id >= getEmulatedCameraNum()) {
+        ALOGE("%s: Camera id %d is out of bounds (%d)",
+             __FUNCTION__, camera_id, getEmulatedCameraNum());
+        return -ENODEV;
+    }
+
+    return mEmulatedCameras[camera_id]->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
+}
+
+/****************************************************************************
+ * 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 gEmulatedCameraFactory.cameraDeviceOpen(atoi(name), device);
+}
+
+int EmulatedCameraFactory::get_number_of_cameras(void)
+{
+    return gEmulatedCameraFactory.getEmulatedCameraNum();
+}
+
+int EmulatedCameraFactory::get_camera_info(int camera_id,
+                                           struct camera_info* info)
+{
+    return gEmulatedCameraFactory.getCameraInfo(camera_id, info);
+}
+
+int EmulatedCameraFactory::set_callbacks(
+        const camera_module_callbacks_t *callbacks)
+{
+    return gEmulatedCameraFactory.setCallbacks(callbacks);
+}
+
+void EmulatedCameraFactory::get_vendor_tag_ops(vendor_tag_ops_t* ops)
+{
+    gEmulatedCameraFactory.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;
+}
+
+/********************************************************************************
+ * Internal API
+ *******************************************************************************/
+
+/*
+ * Camera information tokens passed in response to the "list" factory query.
+ */
+
+/* Device name token. */
+static const char lListNameToken[]    = "name=";
+/* Frame dimensions token. */
+static const char lListDimsToken[]    = "framedims=";
+/* Facing direction token. */
+static const char lListDirToken[]     = "dir=";
+
+void EmulatedCameraFactory::createQemuCameras()
+{
+    /* Obtain camera list. */
+    char* camera_list = NULL;
+    status_t res = mQemuClient.listCameras(&camera_list);
+    /* Empty list, or list containing just an EOL means that there were no
+     * connected cameras found. */
+    if (res != NO_ERROR || camera_list == NULL || *camera_list == '\0' ||
+        *camera_list == '\n') {
+        if (camera_list != NULL) {
+            free(camera_list);
+        }
+        return;
+    }
+
+    /*
+     * Calculate number of connected cameras. Number of EOLs in the camera list
+     * is the number of the connected cameras.
+     */
+
+    int num = 0;
+    const char* eol = strchr(camera_list, '\n');
+    while (eol != NULL) {
+        num++;
+        eol = strchr(eol + 1, '\n');
+    }
+
+    /* Allocate the array for emulated camera instances. Note that we allocate
+     * two more entries for back and front fake camera emulation. */
+    mEmulatedCameras = new EmulatedBaseCamera*[num + 2];
+    if (mEmulatedCameras == NULL) {
+        ALOGE("%s: Unable to allocate emulated camera array for %d entries",
+             __FUNCTION__, num + 1);
+        free(camera_list);
+        return;
+    }
+    memset(mEmulatedCameras, 0, sizeof(EmulatedBaseCamera*) * (num + 1));
+
+    /*
+     * Iterate the list, creating, and initializin emulated qemu cameras for each
+     * entry (line) in the list.
+     */
+
+    int index = 0;
+    char* cur_entry = camera_list;
+    while (cur_entry != NULL && *cur_entry != '\0' && index < num) {
+        /* Find the end of the current camera entry, and terminate it with zero
+         * for simpler string manipulation. */
+        char* next_entry = strchr(cur_entry, '\n');
+        if (next_entry != NULL) {
+            *next_entry = '\0';
+            next_entry++;   // Start of the next entry.
+        }
+
+        /* Find 'name', 'framedims', and 'dir' tokens that are required here. */
+        char* name_start = strstr(cur_entry, lListNameToken);
+        char* dim_start = strstr(cur_entry, lListDimsToken);
+        char* dir_start = strstr(cur_entry, lListDirToken);
+        if (name_start != NULL && dim_start != NULL && dir_start != NULL) {
+            /* Advance to the token values. */
+            name_start += strlen(lListNameToken);
+            dim_start += strlen(lListDimsToken);
+            dir_start += strlen(lListDirToken);
+
+            /* Terminate token values with zero. */
+            char* s = strchr(name_start, ' ');
+            if (s != NULL) {
+                *s = '\0';
+            }
+            s = strchr(dim_start, ' ');
+            if (s != NULL) {
+                *s = '\0';
+            }
+            s = strchr(dir_start, ' ');
+            if (s != NULL) {
+                *s = '\0';
+            }
+
+            /* Create and initialize qemu camera. */
+            EmulatedQemuCamera* qemu_cam =
+                new EmulatedQemuCamera(index, &HAL_MODULE_INFO_SYM.common);
+            if (NULL != qemu_cam) {
+                res = qemu_cam->Initialize(name_start, dim_start, dir_start);
+                if (res == NO_ERROR) {
+                    mEmulatedCameras[index] = qemu_cam;
+                    index++;
+                } else {
+                    delete qemu_cam;
+                }
+            } else {
+                ALOGE("%s: Unable to instantiate EmulatedQemuCamera",
+                     __FUNCTION__);
+            }
+        } else {
+            ALOGW("%s: Bad camera information: %s", __FUNCTION__, cur_entry);
+        }
+
+        cur_entry = next_entry;
+    }
+
+    mEmulatedCameraNum = index;
+}
+
+bool EmulatedCameraFactory::isBackFakeCameraEmulationOn()
+{
+    /* Defined by 'qemu.sf.fake_camera' boot property: if property exist, and
+     * is set to 'both', or 'back', then fake camera is used to emulate back
+     * camera. */
+    char prop[PROPERTY_VALUE_MAX];
+    if ((property_get("qemu.sf.fake_camera", prop, NULL) > 0) &&
+        (!strcmp(prop, "both") || !strcmp(prop, "back"))) {
+        return true;
+    } else {
+        return false;
+    }
+}
+
+int EmulatedCameraFactory::getBackCameraHalVersion()
+{
+    /* Defined by 'qemu.sf.back_camera_hal_version' boot property: if the
+     * property doesn't exist, it is assumed to be 1. */
+    char prop[PROPERTY_VALUE_MAX];
+    if (property_get("qemu.sf.back_camera_hal", prop, NULL) > 0) {
+        char *prop_end = prop;
+        int val = strtol(prop, &prop_end, 10);
+        if (*prop_end == '\0') {
+            return val;
+        }
+        // Badly formatted property, should just be a number
+        ALOGE("qemu.sf.back_camera_hal is not a number: %s", prop);
+    }
+    return 1;
+}
+
+bool EmulatedCameraFactory::isFrontFakeCameraEmulationOn()
+{
+    /* Defined by 'qemu.sf.fake_camera' boot property: if property exist, and
+     * is set to 'both', or 'front', then fake camera is used to emulate front
+     * camera. */
+    char prop[PROPERTY_VALUE_MAX];
+    if ((property_get("qemu.sf.fake_camera", prop, NULL) > 0) &&
+        (!strcmp(prop, "both") || !strcmp(prop, "front"))) {
+        return true;
+    } else {
+        return false;
+    }
+}
+
+int EmulatedCameraFactory::getFrontCameraHalVersion()
+{
+    /* Defined by 'qemu.sf.front_camera_hal_version' boot property: if the
+     * property doesn't exist, it is assumed to be 1. */
+    char prop[PROPERTY_VALUE_MAX];
+    if (property_get("qemu.sf.front_camera_hal", prop, NULL) > 0) {
+        char *prop_end = prop;
+        int val = strtol(prop, &prop_end, 10);
+        if (*prop_end == '\0') {
+            return val;
+        }
+        // Badly formatted property, should just be a number
+        ALOGE("qemu.sf.front_camera_hal is not a number: %s", prop);
+    }
+    return 1;
+}
+
+void EmulatedCameraFactory::onStatusChanged(int cameraId, int newStatus) {
+
+    EmulatedBaseCamera *cam = mEmulatedCameras[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();
+    }
+
+}
+
+/********************************************************************************
+ * 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 */