/* * 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. */ #ifndef HW_EMULATOR_CAMERA_QEMU_CLIENT_H #define HW_EMULATOR_CAMERA_QEMU_CLIENT_H /* * Contains declaration of classes that encapsulate connection to camera services * in the emulator via qemu pipe. */ #include <hardware/qemud.h> namespace android { /**************************************************************************** * Qemu query ***************************************************************************/ /* Encapsulates a query to the emulator. * Guest exchanges data with the emulator via queries sent over the qemu pipe. * The queries as well as replies to the queries are all strings (except for the * 'frame' query where reply is a framebuffer). * Each query is formatted as such: * * "<query name>[ <parameters>]", * * where <query name> is a string representing query name, and <parameters> are * optional parameters for the query. If parameters are present, they must be * separated from the query name with a single space, and they must be formatted * as such: * * "<name1>=<value1> <name2>=<value2> ... <nameN>=<valueN>" * * I.e.: * - Every parameter must have a name, and a value. * - Name and value must be separated with '='. * - No spaces are allowed around '=' separating name and value. * - Parameters must be separated with a single space character. * - No '=' character is allowed in name and in value. * * There are certain restrictions on strings used in the query: * - Spaces are allowed only as separators. * - '=' are allowed only to divide parameter names from parameter values. * * Emulator replies to each query in two chunks: * - 8 bytes encoding the payload size as a string containing hexadecimal * representation of the payload size value. This is done in order to simplify * dealing with different endianness on the host, and on the guest. * - Payload, whose size is defined by the first chunk. * * Every payload always begins with two characters, encoding the result of the * query: * - 'ok' Encoding the success * - 'ko' Encoding a failure. * After that payload may have optional data. If payload has more data following * the query result, there is a ':' character separating them. If payload carries * only the result, it always ends with a zero-terminator. So, payload 'ok'/'ko' * prefix is always 3 bytes long: it either includes a zero-terminator, if there * is no data, or a ':' separator. */ class QemuQuery { public: /* Constructs an uninitialized QemuQuery instance. */ QemuQuery(); /* Constructs and initializes QemuQuery instance for a query. * Param: * query_string - Query string. This constructor can also be used to * construct a query that doesn't have parameters. In this case query * name can be passed as a parameter here. */ explicit QemuQuery(const char* query_string); /* Constructs and initializes QemuQuery instance for a query with parameters. * Param: * query_name - Query name. * query_param - Query parameters. Can be NULL. */ QemuQuery(const char* query_name, const char* query_param); /* Destructs QemuQuery instance. */ ~QemuQuery(); /**************************************************************************** * Public API ***************************************************************************/ /* Creates new query. * Note: this method will reset this instance prior to creating a new query * in order to discard possible "leftovers" from the previous query. * Param: * query_name - Query name. * query_param - Query parameters. Can be NULL. * Return: * NO_ERROR on success, or an appropriate error status. */ status_t createQuery(const char* name, const char* param); /* Completes the query after a reply from the emulator. * This method will parse the reply buffer, and calculate the final query * status, which depends not only on the transport success / failure, but * also on 'ok' / 'ko' in the reply buffer. * Param: * status - Query delivery status. This status doesn't necessarily reflects * the final query status (which is defined by 'ok'/'ko' prefix in the * reply buffer). This status simply states whether or not the query has * been sent, and a reply has been received successfuly. However, if * this status indicates a failure, it means that the entire query has * failed. * Return: * NO_ERROR on success, or an appropriate error status on failure. Note that * status returned here just signals whether or not the method has succeeded. * Use isQuerySucceeded() / getCompletionStatus() methods of this class to * check the final query status. */ status_t completeQuery(status_t status); /* Resets the query from a previous use. */ void resetQuery(); /* Checks if query has succeeded. * Note that this method must be called after completeQuery() method of this * class has been executed. */ inline bool isQuerySucceeded() const { return mQueryDeliveryStatus == NO_ERROR && mReplyStatus != 0; } /* Gets final completion status of the query. * Note that this method must be called after completeQuery() method of this * class has been executed. * Return: * NO_ERROR if query has succeeded, or an appropriate error status on query * failure. */ inline status_t getCompletionStatus() const { if (mQueryDeliveryStatus == NO_ERROR) { if (mReplyStatus) { return NO_ERROR; } else { return EINVAL; } } else { return mQueryDeliveryStatus; } } /**************************************************************************** * Public data memebers ***************************************************************************/ public: /* Query string. */ char* mQuery; /* Query delivery status. */ status_t mQueryDeliveryStatus; /* Reply buffer */ char* mReplyBuffer; /* Reply data (past 'ok'/'ko'). If NULL, there were no data in reply. */ char* mReplyData; /* Reply buffer size. */ size_t mReplySize; /* Reply data size. */ size_t mReplyDataSize; /* Reply status: 1 - ok, 0 - ko. */ int mReplyStatus; /**************************************************************************** * Private data memebers ***************************************************************************/ protected: /* Preallocated buffer for small queries. */ char mQueryPrealloc[256]; }; /**************************************************************************** * Qemu client base ***************************************************************************/ /* Encapsulates a connection to the 'camera' service in the emulator via qemu * pipe. */ class QemuClient { public: /* Constructs QemuClient instance. */ QemuClient(); /* Destructs QemuClient instance. */ virtual ~QemuClient(); /**************************************************************************** * Qemu client API ***************************************************************************/ public: /* Connects to the 'camera' service in the emulator via qemu pipe. * Param: * param - Parameters to pass to the camera service. There are two types of * camera services implemented by the emulator. The first one is a * 'camera factory' type of service that provides list of cameras * connected to the host. Another one is an 'emulated camera' type of * service that provides interface to a camera connected to the host. At * the connection time emulator makes distinction between the two by * looking at connection parameters: no parameters means connection to * the 'factory' service, while connection with parameters means * connection to an 'emulated camera' service, where camera is identified * by one of the connection parameters. So, passing NULL, or an empty * string to this method will establish a connection with the 'factory' * service, while not empty string passed here will establish connection * with an 'emulated camera' service. Parameters defining the emulated * camera must be formatted as such: * * "name=<device name> [inp_channel=<input channel #>]", * * where 'device name' is a required parameter defining name of the * camera device, and 'input channel' is an optional parameter (positive * integer), defining the input channel to use on the camera device. * Note that device name passed here must have been previously obtained * from the factory service using 'list' query. * Return: * NO_ERROR on success, or an appropriate error status. */ virtual status_t connectClient(const char* param); /* Disconnects from the service. */ virtual void disconnectClient(); /* Sends data to the service. * Param: * data, data_size - Data to send. * Return: * NO_ERROR on success, or an appropriate error status on failure. */ virtual status_t sendMessage(const void* data, size_t data_size); /* Receives data from the service. * This method assumes that data to receive will come in two chunks: 8 * characters encoding the payload size in hexadecimal string, followed by * the paylod (if any). * This method will allocate data buffer where to receive the response. * Param: * data - Upon success contains address of the allocated data buffer with * the data received from the service. The caller is responsible for * freeing allocated data buffer. * data_size - Upon success contains size of the data received from the * service. * Return: * NO_ERROR on success, or an appropriate error status on failure. */ virtual status_t receiveMessage(void** data, size_t* data_size); /* Sends a query, and receives a response from the service. * Param: * query - Query to send to the service. When this method returns, the query * is completed, and all its relevant data members are properly initialized. * Return: * NO_ERROR on success, or an appropriate error status on failure. Note that * status returned here is not the final query status. Use isQuerySucceeded(), * or getCompletionStatus() method on the query object to see if it has * succeeded. However, if this method returns a failure, it means that the * query has failed, and there is no guarantee that its data members are * properly initialized (except for the 'mQueryDeliveryStatus', which is * always in the proper state). */ virtual status_t doQuery(QemuQuery* query); /**************************************************************************** * Data members ***************************************************************************/ protected: /* Qemu pipe handle. */ int mPipeFD; private: /* Camera service name. */ static const char mCameraServiceName[]; }; /**************************************************************************** * Qemu client for the 'factory' service. ***************************************************************************/ /* Encapsulates QemuClient for the 'factory' service. */ class FactoryQemuClient : public QemuClient { public: /* Constructs FactoryQemuClient instance. */ FactoryQemuClient(); /* Destructs FactoryQemuClient instance. */ ~FactoryQemuClient(); /**************************************************************************** * Public API ***************************************************************************/ public: /* Lists camera devices connected to the host. * Param: * list - Upon success contains a list of cameras connected to the host. The * list returned here is represented as a string, containing multiple * lines separated with '\n', where each line represents a camera. Each * camera line is formatted as such: * * "name=<device name> channel=<num> pix=<num> framedims=<dimensions>\n" * * Where: * - 'name' is the name of the camera device attached to the host. This * name must be used for subsequent connection to the 'emulated camera' * service for that camera. * - 'channel' - input channel number (positive int) to use to communicate * with the camera. * - 'pix' - pixel format (a "fourcc" uint), chosen for the video frames * by the camera service. * - 'framedims' contains a list of frame dimensions supported by the * camera for the chosen pixel format. Each etry in the list is in form * '<width>x<height>', where 'width' and 'height' are numeric values * for width and height of a supported frame dimension. Entries in * this list are separated with ',' with no spaces between the entries. * Return: * NO_ERROR on success, or an appropriate error status on failure. */ status_t listCameras(char** list); /**************************************************************************** * Names of the queries available for the emulated camera factory. ***************************************************************************/ private: /* List cameras connected to the host. */ static const char mQueryList[]; }; /**************************************************************************** * Qemu client for an 'emulated camera' service. ***************************************************************************/ /* Encapsulates QemuClient for an 'emulated camera' service. */ class CameraQemuClient : public QemuClient { public: /* Constructs CameraQemuClient instance. */ CameraQemuClient(); /* Destructs CameraQemuClient instance. */ ~CameraQemuClient(); /**************************************************************************** * Public API ***************************************************************************/ public: /* Queries camera connection. * Return: * NO_ERROR on success, or an appropriate error status on failure. */ status_t queryConnect(); /* Queries camera disconnection. * Return: * NO_ERROR on success, or an appropriate error status on failure. */ status_t queryDisconnect(); /* Queries camera to start capturing video. * Param: * pixel_format - Pixel format that is used by the client to push video * frames to the camera framework. * width, height - Frame dimensions, requested by the framework. * Return: * NO_ERROR on success, or an appropriate error status on failure. */ status_t queryStart(uint32_t pixel_format, int width, int height); /* Queries camera to stop capturing video. * Return: * NO_ERROR on success, or an appropriate error status on failure. */ status_t queryStop(); /* Queries camera for the next video frame. * Param: * vframe, vframe_size - Define buffer, allocated to receive a video frame. * Any of these parameters can be 0, indicating that the caller is * interested only in preview frame. * pframe, pframe_size - Define buffer, allocated to receive a preview frame. * Any of these parameters can be 0, indicating that the caller is * interested only in video frame. * Return: * NO_ERROR on success, or an appropriate error status on failure. */ status_t queryFrame(void* vframe, void* pframe, size_t vframe_size, size_t pframe_size); /**************************************************************************** * Names of the queries available for the emulated camera. ***************************************************************************/ private: /* Connect to the camera. */ static const char mQueryConnect[]; /* Disconnect from the camera. */ static const char mQueryDisconnect[]; /* Start video capturing. */ static const char mQueryStart[]; /* Stop video capturing. */ static const char mQueryStop[]; /* Query frame(s). */ static const char mQueryFrame[]; }; }; /* namespace android */ #endif /* HW_EMULATOR_CAMERA_QEMU_CLIENT_H */