1c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine/* 2c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine * Copyright (C) 2011 The Android Open Source Project 3c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine * 4c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine * Licensed under the Apache License, Version 2.0 (the "License"); 5c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine * you may not use this file except in compliance with the License. 6c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine * You may obtain a copy of the License at 7c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine * 8c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine * http://www.apache.org/licenses/LICENSE-2.0 9c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine * 10c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine * Unless required by applicable law or agreed to in writing, software 11c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine * distributed under the License is distributed on an "AS IS" BASIS, 12c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine * See the License for the specific language governing permissions and 14c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine * limitations under the License. 15c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine */ 16c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine 17c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine/* 18c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine * Contains emulated camera service implementation. 19c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine */ 20c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine 21c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine#include "qemu-common.h" 22b8dcaffaf7dcb0c795d2776abf3bb75196f8527cVladimir Chtchetkine#include "android/globals.h" /* for android_hw */ 23c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine#include "android/hw-qemud.h" 24c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine#include "android/utils/misc.h" 25c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine#include "android/utils/system.h" 26c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine#include "android/utils/debug.h" 27c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine#include "android/camera/camera-capture.h" 28c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine#include "android/camera/camera-format-converters.h" 29c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine#include "android/camera/camera-service.h" 30c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine 31c68dbbef0118eab4256acfc0d9430f0e557a82a1Vladimir Chtchetkine#define E(...) derror(__VA_ARGS__) 32c68dbbef0118eab4256acfc0d9430f0e557a82a1Vladimir Chtchetkine#define W(...) dwarning(__VA_ARGS__) 33c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine#define D(...) VERBOSE_PRINT(camera,__VA_ARGS__) 34c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine#define D_ACTIVE VERBOSE_CHECK(camera) 35c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine 36cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine/* the T(...) macro is used to dump traffic */ 37cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine#define T_ACTIVE 0 38cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine 39cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine#if T_ACTIVE 40cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine#define T(...) VERBOSE_PRINT(camera,__VA_ARGS__) 41cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine#else 42cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine#define T(...) ((void)0) 43cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine#endif 44cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine 45cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine/* Defines name of the camera service. */ 46cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine#define SERVICE_NAME "camera" 47cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine 48cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine/* Maximum number of supported emulated cameras. */ 49cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine#define MAX_CAMERA 8 50c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine 51c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine/* Camera sevice descriptor. */ 52c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkinetypedef struct CameraServiceDesc CameraServiceDesc; 53c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkinestruct CameraServiceDesc { 54cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine /* Information about camera devices connected to the host. 55cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * Note that once initialized, entries in this array are considered to be 56cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * constant. */ 57cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine CameraInfo camera_info[MAX_CAMERA]; 58c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine /* Number of camera devices connected to the host. */ 59cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine int camera_count; 60c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine}; 61c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine 62c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine/* One and only one camera service. */ 63c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkinestatic CameraServiceDesc _camera_service_desc; 64c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine 65c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine/******************************************************************************** 66cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * Helper routines 67cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine *******************************************************************************/ 68cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine 69cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine/* Extracts query name, and (optionally) query parameters from the query string. 70cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * Param: 71cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * query - Query string. Query string in the camera service are formatted as such: 72cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * "<query name>[ <parameters>]", 73cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * where parameters are optional, and if present, must be separated from the 742ae501556f90647e40466b6a1948f6f7f51cf251Vladimir Chtchetkine * query name with a single ' '. See comments to get_token_value routine 75cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * for the format of the parameters string. 76cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * query_name - Upon success contains query name extracted from the query 77cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * string. 78cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * query_name_size - Buffer size for 'query_name' string. 79cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * query_param - Upon success contains a pointer to the beginning of the query 80cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * parameters. If query has no parameters, NULL will be passed back with 81cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * this parameter. This parameter is optional and can be NULL. 82cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * Return: 83cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * 0 on success, or number of bytes required for query name if 'query_name' 84cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * string buffer was too small to contain it. 85cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine */ 86cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkinestatic int 87cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine_parse_query(const char* query, 88cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine char* query_name, 89cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine int query_name_size, 90cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine const char** query_param) 91cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine{ 92cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine /* Extract query name. */ 93cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine const char* qend = strchr(query, ' '); 94cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine if (qend == NULL) { 95cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine qend = query + strlen(query); 96cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine } 97cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine if ((qend - query) >= query_name_size) { 98cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine return qend - query + 1; 99cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine } 100cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine memcpy(query_name, query, qend - query); 101cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine query_name[qend - query] = '\0'; 102cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine 103cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine /* Calculate query parameters pointer (if needed) */ 104cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine if (query_param != NULL) { 105cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine if (*qend == ' ') { 106cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine qend++; 107cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine } 108cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine *query_param = (*qend == '\0') ? NULL : qend; 109cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine } 110cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine 111cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine return 0; 112cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine} 113cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine 114cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine/* Appends one string to another, growing the destination string buffer if 115cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * needed. 116cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * Param: 117cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * str_buffer - Contains pointer to the destination string buffer. Content of 118cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * this parameter can be NULL. Note that content of this parameter will 119cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * change if string buffer has been reallocated. 120cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * str_buf_size - Contains current buffer size of the string, addressed by 121cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * 'str_buffer' parameter. Note that content of this parameter will change 122cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * if string buffer has been reallocated. 123cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * str - String to append. 124cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * Return: 125cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * 0 on success, or -1 on failure (memory allocation). 126cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine */ 127cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkinestatic int 128cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine_append_string(char** str_buf, size_t* str_buf_size, const char* str) 129cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine{ 130cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine const size_t offset = (*str_buf != NULL) ? strlen(*str_buf) : 0; 131cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine const size_t append_bytes = strlen(str) + 1; 132cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine 133cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine /* Make sure these two match. */ 134cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine if (*str_buf == NULL) { 135cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine *str_buf_size = 0; 136cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine } 137cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine 138cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine if ((offset + append_bytes) > *str_buf_size) { 139cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine /* Reallocate string, so it can fit what's being append to it. Note that 140cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * we reallocate a bit bigger buffer than is needed in order to minimize 141cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * number of memory allocation calls in case there are more "appends" 142cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * coming. */ 143cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine const size_t required_mem = offset + append_bytes + 256; 144cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine char* new_buf = (char*)realloc(*str_buf, required_mem); 145cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine if (new_buf == NULL) { 146cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine E("%s: Unable to allocate %d bytes for a string", 147cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine __FUNCTION__, required_mem); 148cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine return -1; 149cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine } 150cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine *str_buf = new_buf; 151cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine *str_buf_size = required_mem; 152cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine } 153cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine memcpy(*str_buf + offset, str, append_bytes); 154cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine 155cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine return 0; 156cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine} 157cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine 158cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine/* Represents camera information as a string formatted as follows: 159b8dcaffaf7dcb0c795d2776abf3bb75196f8527cVladimir Chtchetkine * 'name=<devname> channel=<num> pix=<format> facing=<direction> framedims=<widh1xheight1,...>\n' 160cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * Param: 161cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * ci - Camera information descriptor to convert into a string. 162cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * str - Pointer to the string buffer where to save the converted camera 163cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * information descriptor. On entry, content of this parameter can be NULL. 164cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * Note that string buffer addressed with this parameter may be reallocated 165cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * in this routine, so (if not NULL) it must contain a buffer allocated with 166cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * malloc. The caller is responsible for freeing string buffer returned in 167cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * this parameter. 168cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * str_size - Contains byte size of the buffer addressed by 'str' parameter. 169cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * Return: 170cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * 0 on success, or != 0 on failure. 171cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine */ 172cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkinestatic int 173cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine_camera_info_to_string(const CameraInfo* ci, char** str, size_t* str_size) { 174cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine int res; 175cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine int n; 176cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine char tmp[128]; 177cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine 178cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine /* Append device name. */ 179cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine snprintf(tmp, sizeof(tmp), "name=%s ", ci->device_name); 180cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine res = _append_string(str, str_size, tmp); 181cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine if (res) { 182cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine return res; 183cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine } 184cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine /* Append input channel. */ 185cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine snprintf(tmp, sizeof(tmp), "channel=%d ", ci->inp_channel); 186cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine res = _append_string(str, str_size, tmp); 187cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine if (res) { 188cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine return res; 189cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine } 190cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine /* Append pixel format. */ 191cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine snprintf(tmp, sizeof(tmp), "pix=%d ", ci->pixel_format); 192cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine res = _append_string(str, str_size, tmp); 193cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine if (res) { 194cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine return res; 195cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine } 196b8dcaffaf7dcb0c795d2776abf3bb75196f8527cVladimir Chtchetkine /* Append direction. */ 197b8dcaffaf7dcb0c795d2776abf3bb75196f8527cVladimir Chtchetkine snprintf(tmp, sizeof(tmp), "dir=%s ", ci->direction); 198b8dcaffaf7dcb0c795d2776abf3bb75196f8527cVladimir Chtchetkine res = _append_string(str, str_size, tmp); 199b8dcaffaf7dcb0c795d2776abf3bb75196f8527cVladimir Chtchetkine if (res) { 200b8dcaffaf7dcb0c795d2776abf3bb75196f8527cVladimir Chtchetkine return res; 201b8dcaffaf7dcb0c795d2776abf3bb75196f8527cVladimir Chtchetkine } 202cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine /* Append supported frame sizes. */ 203cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine snprintf(tmp, sizeof(tmp), "framedims=%dx%d", 204cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine ci->frame_sizes[0].width, ci->frame_sizes[0].height); 205cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine res = _append_string(str, str_size, tmp); 206cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine if (res) { 207cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine return res; 208cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine } 209cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine for (n = 1; n < ci->frame_sizes_num; n++) { 210cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine snprintf(tmp, sizeof(tmp), ",%dx%d", 211cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine ci->frame_sizes[n].width, ci->frame_sizes[n].height); 212cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine res = _append_string(str, str_size, tmp); 213cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine if (res) { 214cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine return res; 215cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine } 216cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine } 217cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine 218cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine /* Stringified camera properties should end with EOL. */ 219cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine return _append_string(str, str_size, "\n"); 220cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine} 221cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine 222b8dcaffaf7dcb0c795d2776abf3bb75196f8527cVladimir Chtchetkine/* Gets camera information matching a display name. 223b8dcaffaf7dcb0c795d2776abf3bb75196f8527cVladimir Chtchetkine * Param: 224b8dcaffaf7dcb0c795d2776abf3bb75196f8527cVladimir Chtchetkine * disp_name - Display name to match. 225b8dcaffaf7dcb0c795d2776abf3bb75196f8527cVladimir Chtchetkine * arr - Array of camera informations. 226b8dcaffaf7dcb0c795d2776abf3bb75196f8527cVladimir Chtchetkine * num - Number of elements in the array. 227b8dcaffaf7dcb0c795d2776abf3bb75196f8527cVladimir Chtchetkine * Return: 228b8dcaffaf7dcb0c795d2776abf3bb75196f8527cVladimir Chtchetkine * Matching camera information, or NULL if matching camera information for the 229b8dcaffaf7dcb0c795d2776abf3bb75196f8527cVladimir Chtchetkine * given display name has not been found in the array. 230b8dcaffaf7dcb0c795d2776abf3bb75196f8527cVladimir Chtchetkine */ 231b8dcaffaf7dcb0c795d2776abf3bb75196f8527cVladimir Chtchetkinestatic CameraInfo* 232b8dcaffaf7dcb0c795d2776abf3bb75196f8527cVladimir Chtchetkine_camera_info_get_by_display_name(const char* disp_name, CameraInfo* arr, int num) 233b8dcaffaf7dcb0c795d2776abf3bb75196f8527cVladimir Chtchetkine{ 234b8dcaffaf7dcb0c795d2776abf3bb75196f8527cVladimir Chtchetkine int n; 235b8dcaffaf7dcb0c795d2776abf3bb75196f8527cVladimir Chtchetkine for (n = 0; n < num; n++) { 2367485c2989d727a1d0c14a66fb75e140f885a1583Vladimir Chtchetkine if (!arr[n].in_use && arr[n].display_name != NULL && 2377485c2989d727a1d0c14a66fb75e140f885a1583Vladimir Chtchetkine !strcmp(arr[n].display_name, disp_name)) { 238b8dcaffaf7dcb0c795d2776abf3bb75196f8527cVladimir Chtchetkine return &arr[n]; 239b8dcaffaf7dcb0c795d2776abf3bb75196f8527cVladimir Chtchetkine } 240b8dcaffaf7dcb0c795d2776abf3bb75196f8527cVladimir Chtchetkine } 241b8dcaffaf7dcb0c795d2776abf3bb75196f8527cVladimir Chtchetkine return NULL; 242b8dcaffaf7dcb0c795d2776abf3bb75196f8527cVladimir Chtchetkine} 243b8dcaffaf7dcb0c795d2776abf3bb75196f8527cVladimir Chtchetkine 244b8dcaffaf7dcb0c795d2776abf3bb75196f8527cVladimir Chtchetkine/* Gets camera information matching a device name. 245b8dcaffaf7dcb0c795d2776abf3bb75196f8527cVladimir Chtchetkine * Param: 246b8dcaffaf7dcb0c795d2776abf3bb75196f8527cVladimir Chtchetkine * device_name - Device name to match. 247b8dcaffaf7dcb0c795d2776abf3bb75196f8527cVladimir Chtchetkine * arr - Array of camera informations. 248b8dcaffaf7dcb0c795d2776abf3bb75196f8527cVladimir Chtchetkine * num - Number of elements in the array. 249b8dcaffaf7dcb0c795d2776abf3bb75196f8527cVladimir Chtchetkine * Return: 250b8dcaffaf7dcb0c795d2776abf3bb75196f8527cVladimir Chtchetkine * Matching camera information, or NULL if matching camera information for the 251b8dcaffaf7dcb0c795d2776abf3bb75196f8527cVladimir Chtchetkine * given device name has not been found in the array. 252b8dcaffaf7dcb0c795d2776abf3bb75196f8527cVladimir Chtchetkine */ 253b8dcaffaf7dcb0c795d2776abf3bb75196f8527cVladimir Chtchetkinestatic CameraInfo* 254b8dcaffaf7dcb0c795d2776abf3bb75196f8527cVladimir Chtchetkine_camera_info_get_by_device_name(const char* device_name, CameraInfo* arr, int num) 255b8dcaffaf7dcb0c795d2776abf3bb75196f8527cVladimir Chtchetkine{ 256b8dcaffaf7dcb0c795d2776abf3bb75196f8527cVladimir Chtchetkine int n; 257b8dcaffaf7dcb0c795d2776abf3bb75196f8527cVladimir Chtchetkine for (n = 0; n < num; n++) { 258b8dcaffaf7dcb0c795d2776abf3bb75196f8527cVladimir Chtchetkine if (arr[n].device_name != NULL && !strcmp(arr[n].device_name, device_name)) { 259b8dcaffaf7dcb0c795d2776abf3bb75196f8527cVladimir Chtchetkine return &arr[n]; 260b8dcaffaf7dcb0c795d2776abf3bb75196f8527cVladimir Chtchetkine } 261b8dcaffaf7dcb0c795d2776abf3bb75196f8527cVladimir Chtchetkine } 262b8dcaffaf7dcb0c795d2776abf3bb75196f8527cVladimir Chtchetkine return NULL; 263b8dcaffaf7dcb0c795d2776abf3bb75196f8527cVladimir Chtchetkine} 264b8dcaffaf7dcb0c795d2776abf3bb75196f8527cVladimir Chtchetkine 265b8dcaffaf7dcb0c795d2776abf3bb75196f8527cVladimir Chtchetkine/******************************************************************************** 266b8dcaffaf7dcb0c795d2776abf3bb75196f8527cVladimir Chtchetkine * CameraServiceDesc API 267b8dcaffaf7dcb0c795d2776abf3bb75196f8527cVladimir Chtchetkine *******************************************************************************/ 268b8dcaffaf7dcb0c795d2776abf3bb75196f8527cVladimir Chtchetkine 2697485c2989d727a1d0c14a66fb75e140f885a1583Vladimir Chtchetkine/* Initialized webcam emulation record in camera service descriptor. 2707485c2989d727a1d0c14a66fb75e140f885a1583Vladimir Chtchetkine * Param: 2717485c2989d727a1d0c14a66fb75e140f885a1583Vladimir Chtchetkine * csd - Camera service descriptor to initialize a record in. 2727485c2989d727a1d0c14a66fb75e140f885a1583Vladimir Chtchetkine * disp_name - Display name of a web camera ('webcam<N>') to use for emulation. 2737485c2989d727a1d0c14a66fb75e140f885a1583Vladimir Chtchetkine * dir - Direction ('back', or 'front') that emulated camera is facing. 2747485c2989d727a1d0c14a66fb75e140f885a1583Vladimir Chtchetkine * ci, ci_cnt - Array of webcam information for enumerated web cameras connected 2757485c2989d727a1d0c14a66fb75e140f885a1583Vladimir Chtchetkine * to the host. 2767485c2989d727a1d0c14a66fb75e140f885a1583Vladimir Chtchetkine */ 2777485c2989d727a1d0c14a66fb75e140f885a1583Vladimir Chtchetkinestatic void 2787485c2989d727a1d0c14a66fb75e140f885a1583Vladimir Chtchetkine_wecam_setup(CameraServiceDesc* csd, 2797485c2989d727a1d0c14a66fb75e140f885a1583Vladimir Chtchetkine const char* disp_name, 2807485c2989d727a1d0c14a66fb75e140f885a1583Vladimir Chtchetkine const char* dir, 2817485c2989d727a1d0c14a66fb75e140f885a1583Vladimir Chtchetkine CameraInfo* ci, 2827485c2989d727a1d0c14a66fb75e140f885a1583Vladimir Chtchetkine int ci_cnt) 2837485c2989d727a1d0c14a66fb75e140f885a1583Vladimir Chtchetkine{ 2847485c2989d727a1d0c14a66fb75e140f885a1583Vladimir Chtchetkine /* Find webcam record in the list of enumerated web cameras. */ 2857485c2989d727a1d0c14a66fb75e140f885a1583Vladimir Chtchetkine CameraInfo* found = _camera_info_get_by_display_name(disp_name, ci, ci_cnt); 2867485c2989d727a1d0c14a66fb75e140f885a1583Vladimir Chtchetkine if (found == NULL) { 2877485c2989d727a1d0c14a66fb75e140f885a1583Vladimir Chtchetkine W("Camera name '%s' is not found in the list of connected cameras.\n" 2887485c2989d727a1d0c14a66fb75e140f885a1583Vladimir Chtchetkine "Use '-webcam-list' emulator option to obtain the list of connected camera names.\n", 2897485c2989d727a1d0c14a66fb75e140f885a1583Vladimir Chtchetkine disp_name); 2907485c2989d727a1d0c14a66fb75e140f885a1583Vladimir Chtchetkine return; 2917485c2989d727a1d0c14a66fb75e140f885a1583Vladimir Chtchetkine } 2927485c2989d727a1d0c14a66fb75e140f885a1583Vladimir Chtchetkine 2937485c2989d727a1d0c14a66fb75e140f885a1583Vladimir Chtchetkine /* Save to the camera info array that will be used by the service. */ 2947485c2989d727a1d0c14a66fb75e140f885a1583Vladimir Chtchetkine memcpy(csd->camera_info + csd->camera_count, found, sizeof(CameraInfo)); 2957485c2989d727a1d0c14a66fb75e140f885a1583Vladimir Chtchetkine /* This camera is taken. */ 2967485c2989d727a1d0c14a66fb75e140f885a1583Vladimir Chtchetkine found->in_use = 1; 2977485c2989d727a1d0c14a66fb75e140f885a1583Vladimir Chtchetkine /* Update direction parameter. */ 2987485c2989d727a1d0c14a66fb75e140f885a1583Vladimir Chtchetkine if (csd->camera_info[csd->camera_count].direction != NULL) { 2997485c2989d727a1d0c14a66fb75e140f885a1583Vladimir Chtchetkine free(csd->camera_info[csd->camera_count].direction); 3007485c2989d727a1d0c14a66fb75e140f885a1583Vladimir Chtchetkine } 3017485c2989d727a1d0c14a66fb75e140f885a1583Vladimir Chtchetkine csd->camera_info[csd->camera_count].direction = ASTRDUP(dir); 3027485c2989d727a1d0c14a66fb75e140f885a1583Vladimir Chtchetkine D("Camera %d '%s' connected to '%s' facing %s using %.4s pixel format", 3037485c2989d727a1d0c14a66fb75e140f885a1583Vladimir Chtchetkine csd->camera_count, csd->camera_info[csd->camera_count].display_name, 3047485c2989d727a1d0c14a66fb75e140f885a1583Vladimir Chtchetkine csd->camera_info[csd->camera_count].device_name, 3057485c2989d727a1d0c14a66fb75e140f885a1583Vladimir Chtchetkine csd->camera_info[csd->camera_count].direction, 3067485c2989d727a1d0c14a66fb75e140f885a1583Vladimir Chtchetkine (const char*)(&csd->camera_info[csd->camera_count].pixel_format)); 3077485c2989d727a1d0c14a66fb75e140f885a1583Vladimir Chtchetkine csd->camera_count++; 3087485c2989d727a1d0c14a66fb75e140f885a1583Vladimir Chtchetkine} 3097485c2989d727a1d0c14a66fb75e140f885a1583Vladimir Chtchetkine 310b8dcaffaf7dcb0c795d2776abf3bb75196f8527cVladimir Chtchetkine/* Initializes camera service descriptor. 311b8dcaffaf7dcb0c795d2776abf3bb75196f8527cVladimir Chtchetkine */ 312b8dcaffaf7dcb0c795d2776abf3bb75196f8527cVladimir Chtchetkinestatic void 313b8dcaffaf7dcb0c795d2776abf3bb75196f8527cVladimir Chtchetkine_camera_service_init(CameraServiceDesc* csd) 314b8dcaffaf7dcb0c795d2776abf3bb75196f8527cVladimir Chtchetkine{ 315b8dcaffaf7dcb0c795d2776abf3bb75196f8527cVladimir Chtchetkine CameraInfo ci[MAX_CAMERA]; 316b8dcaffaf7dcb0c795d2776abf3bb75196f8527cVladimir Chtchetkine int connected_cnt; 317b8dcaffaf7dcb0c795d2776abf3bb75196f8527cVladimir Chtchetkine 318b8dcaffaf7dcb0c795d2776abf3bb75196f8527cVladimir Chtchetkine /* Enumerate camera devices connected to the host. */ 319b8dcaffaf7dcb0c795d2776abf3bb75196f8527cVladimir Chtchetkine memset(ci, 0, sizeof(CameraInfo) * MAX_CAMERA); 320b8dcaffaf7dcb0c795d2776abf3bb75196f8527cVladimir Chtchetkine memset(csd->camera_info, 0, sizeof(CameraInfo) * MAX_CAMERA); 321b8dcaffaf7dcb0c795d2776abf3bb75196f8527cVladimir Chtchetkine csd->camera_count = 0; 322f8675c20db7625adc69800ca4ac54e72846ac9a8Vladimir Chtchetkine 3237485c2989d727a1d0c14a66fb75e140f885a1583Vladimir Chtchetkine /* Lets see if HW config uses web cameras. */ 3247485c2989d727a1d0c14a66fb75e140f885a1583Vladimir Chtchetkine if (memcmp(android_hw->hw_camera_back, "webcam", 6) && 3257485c2989d727a1d0c14a66fb75e140f885a1583Vladimir Chtchetkine memcmp(android_hw->hw_camera_front, "webcam", 6)) { 3267485c2989d727a1d0c14a66fb75e140f885a1583Vladimir Chtchetkine /* Web camera emulation is disabled. Skip enumeration of webcameras. */ 327f8675c20db7625adc69800ca4ac54e72846ac9a8Vladimir Chtchetkine return; 328f8675c20db7625adc69800ca4ac54e72846ac9a8Vladimir Chtchetkine } 329f8675c20db7625adc69800ca4ac54e72846ac9a8Vladimir Chtchetkine 3307485c2989d727a1d0c14a66fb75e140f885a1583Vladimir Chtchetkine /* Enumerate web cameras connected to the host. */ 331b8dcaffaf7dcb0c795d2776abf3bb75196f8527cVladimir Chtchetkine connected_cnt = enumerate_camera_devices(ci, MAX_CAMERA); 332b8dcaffaf7dcb0c795d2776abf3bb75196f8527cVladimir Chtchetkine if (connected_cnt <= 0) { 333b8dcaffaf7dcb0c795d2776abf3bb75196f8527cVladimir Chtchetkine /* Nothing is connected - nothing to emulate. */ 334b8dcaffaf7dcb0c795d2776abf3bb75196f8527cVladimir Chtchetkine return; 335b8dcaffaf7dcb0c795d2776abf3bb75196f8527cVladimir Chtchetkine } 336b8dcaffaf7dcb0c795d2776abf3bb75196f8527cVladimir Chtchetkine 3377485c2989d727a1d0c14a66fb75e140f885a1583Vladimir Chtchetkine /* Set up back camera emulation. */ 3387485c2989d727a1d0c14a66fb75e140f885a1583Vladimir Chtchetkine if (!memcmp(android_hw->hw_camera_back, "webcam", 6)) { 3397485c2989d727a1d0c14a66fb75e140f885a1583Vladimir Chtchetkine _wecam_setup(csd, android_hw->hw_camera_back, "back", ci, connected_cnt); 340b8dcaffaf7dcb0c795d2776abf3bb75196f8527cVladimir Chtchetkine } 3415f8faaeb1fc4aa1bc875ebc6ab6ad70867ab5321Vladimir Chtchetkine 3427485c2989d727a1d0c14a66fb75e140f885a1583Vladimir Chtchetkine /* Set up front camera emulation. */ 3437485c2989d727a1d0c14a66fb75e140f885a1583Vladimir Chtchetkine if (!memcmp(android_hw->hw_camera_front, "webcam", 6)) { 3447485c2989d727a1d0c14a66fb75e140f885a1583Vladimir Chtchetkine _wecam_setup(csd, android_hw->hw_camera_front, "front", ci, connected_cnt); 3455f8faaeb1fc4aa1bc875ebc6ab6ad70867ab5321Vladimir Chtchetkine } 346b8dcaffaf7dcb0c795d2776abf3bb75196f8527cVladimir Chtchetkine} 347b8dcaffaf7dcb0c795d2776abf3bb75196f8527cVladimir Chtchetkine 348b8dcaffaf7dcb0c795d2776abf3bb75196f8527cVladimir Chtchetkine/* Gets camera information for the given camera device name. 349b8dcaffaf7dcb0c795d2776abf3bb75196f8527cVladimir Chtchetkine * Param: 350b8dcaffaf7dcb0c795d2776abf3bb75196f8527cVladimir Chtchetkine * cs - Initialized camera service descriptor. 351b8dcaffaf7dcb0c795d2776abf3bb75196f8527cVladimir Chtchetkine * device_name - Camera's device name to look up the information for. 352b8dcaffaf7dcb0c795d2776abf3bb75196f8527cVladimir Chtchetkine * Return: 353b8dcaffaf7dcb0c795d2776abf3bb75196f8527cVladimir Chtchetkine * Camera information pointer on success, or NULL if no camera information has 354b8dcaffaf7dcb0c795d2776abf3bb75196f8527cVladimir Chtchetkine * been found for the given device name. 355b8dcaffaf7dcb0c795d2776abf3bb75196f8527cVladimir Chtchetkine */ 356b8dcaffaf7dcb0c795d2776abf3bb75196f8527cVladimir Chtchetkinestatic CameraInfo* 357b8dcaffaf7dcb0c795d2776abf3bb75196f8527cVladimir Chtchetkine_camera_service_get_camera_info_by_device_name(CameraServiceDesc* cs, 358b8dcaffaf7dcb0c795d2776abf3bb75196f8527cVladimir Chtchetkine const char* device_name) 359b8dcaffaf7dcb0c795d2776abf3bb75196f8527cVladimir Chtchetkine{ 360b8dcaffaf7dcb0c795d2776abf3bb75196f8527cVladimir Chtchetkine return _camera_info_get_by_device_name(device_name, cs->camera_info, 361b8dcaffaf7dcb0c795d2776abf3bb75196f8527cVladimir Chtchetkine cs->camera_count); 362b8dcaffaf7dcb0c795d2776abf3bb75196f8527cVladimir Chtchetkine} 363b8dcaffaf7dcb0c795d2776abf3bb75196f8527cVladimir Chtchetkine 364cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine/******************************************************************************** 365cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * Helpers for handling camera client queries 366cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine *******************************************************************************/ 367cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine 368cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine/* Formats paload size according to the protocol, and sends it to the client. 369cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * To simplify endianess handling we convert payload size to an eight characters 370cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * string, representing payload size value in hexadecimal format. 371cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * Param: 372cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * qc - Qemu client to send the payload size to. 373cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * payload_size - Payload size to report to the client. 374cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine */ 375cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkinestatic void 376cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine_qemu_client_reply_payload(QemudClient* qc, size_t payload_size) 377cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine{ 378cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine char payload_size_str[9]; 379c7389bd69e570a2c8432b37399aff1976b021f0fAndrew Hsieh snprintf(payload_size_str, sizeof(payload_size_str), "%08zx", payload_size); 380cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine qemud_client_send(qc, (const uint8_t*)payload_size_str, 8); 381cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine} 382cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine 383cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine/* 384cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * Prefixes for replies to camera client queries. 385cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine */ 386cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine 387cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine/* Success, no data to send in reply. */ 388cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine#define OK_REPLY "ok" 389cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine/* Failure, no data to send in reply. */ 390cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine#define KO_REPLY "ko" 391cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine/* Success, there are data to send in reply. */ 392cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine#define OK_REPLY_DATA OK_REPLY ":" 393cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine/* Failure, there are data to send in reply. */ 394cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine#define KO_REPLY_DATA KO_REPLY ":" 395cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine 396cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine/* Builds and sends a reply to a query. 397cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * All replies to a query in camera service have a prefix indicating whether the 398cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * query has succeeded ("ok"), or failed ("ko"). The prefix can be followed by 399cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * extra data, containing response to the query. In case there are extra data, 400cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * they are separated from the prefix with a ':' character. 401cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * Param: 402cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * qc - Qemu client to send the reply to. 403cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * ok_ko - An "ok", or "ko" selector, where 0 is for "ko", and !0 is for "ok". 404cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * extra - Optional extra query data. Can be NULL. 405cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * extra_size - Extra data size. 406cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine */ 407cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkinestatic void 408cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine_qemu_client_query_reply(QemudClient* qc, 409cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine int ok_ko, 410cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine const void* extra, 411cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine size_t extra_size) 412cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine{ 413cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine const char* ok_ko_str; 414cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine size_t payload_size; 415cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine 416cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine /* Make sure extra_size is 0 if extra is NULL. */ 417cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine if (extra == NULL && extra_size != 0) { 418cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine W("%s: 'extra' = NULL, while 'extra_size' = %d", 419cdd8d78b202e005691467296b9be98816ed4d4a9Vladimir Chtchetkine __FUNCTION__, (int)extra_size); 420cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine extra_size = 0; 421cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine } 422cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine 423cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine /* Calculate total payload size, and select appropriate 'ok'/'ko' prefix */ 424cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine if (extra_size) { 425cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine /* 'extra' size + 2 'ok'/'ko' bytes + 1 ':' separator byte. */ 426cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine payload_size = extra_size + 3; 427cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine ok_ko_str = ok_ko ? OK_REPLY_DATA : KO_REPLY_DATA; 428cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine } else { 429cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine /* No extra data: just zero-terminated 'ok'/'ko'. */ 430cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine payload_size = 3; 431cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine ok_ko_str = ok_ko ? OK_REPLY : KO_REPLY; 432cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine } 433cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine 434cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine /* Send payload size first. */ 435cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine _qemu_client_reply_payload(qc, payload_size); 436cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine /* Send 'ok[:]'/'ko[:]' next. Note that if there is no extra data, we still 437cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * need to send a zero-terminator for 'ok'/'ko' string instead of the ':' 438cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * separator. So, one way or another, the prefix is always 3 bytes. */ 439cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine qemud_client_send(qc, (const uint8_t*)ok_ko_str, 3); 440cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine /* Send extra data (if present). */ 441cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine if (extra != NULL) { 442cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine qemud_client_send(qc, (const uint8_t*)extra, extra_size); 443cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine } 444cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine} 445cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine 446cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine/* Replies query success ("OK") back to the client. 447cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * Param: 448cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * qc - Qemu client to send the reply to. 449cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * ok_str - An optional string containing query results. Can be NULL. 450cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine */ 451cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkinestatic void 452cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine_qemu_client_reply_ok(QemudClient* qc, const char* ok_str) 453cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine{ 454cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine _qemu_client_query_reply(qc, 1, ok_str, 455cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine (ok_str != NULL) ? (strlen(ok_str) + 1) : 0); 456cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine} 457cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine 458cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine/* Replies query failure ("KO") back to the client. 459cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * Param: 460cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * qc - Qemu client to send the reply to. 461cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * ko_str - An optional string containing reason for failure. Can be NULL. 462cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine */ 463cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkinestatic void 464cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine_qemu_client_reply_ko(QemudClient* qc, const char* ko_str) 465cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine{ 466cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine _qemu_client_query_reply(qc, 0, ko_str, 467cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine (ko_str != NULL) ? (strlen(ko_str) + 1) : 0); 468c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine} 469c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine 470c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine/******************************************************************************** 471c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine * Camera Factory API 472c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine *******************************************************************************/ 473c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine 474cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine/* Handles 'list' query received from the Factory client. 475cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * Response to this query is a string that represents each connected camera in 476cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * this format: 'name=devname framedims=widh1xheight1,widh2xheight2,widhNxheightN\n' 477cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * Strings, representing each camera are separated with EOL symbol. 478cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * Param: 479cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * csd, client - Factory serivice, and client. 480cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * Return: 481cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * 0 on success, or != 0 on failure. 482cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine */ 483cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkinestatic int 484cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine_factory_client_list_cameras(CameraServiceDesc* csd, QemudClient* client) 485cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine{ 486cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine int n; 487cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine size_t reply_size = 0; 488cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine char* reply = NULL; 489cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine 490cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine /* Lets see if there was anything found... */ 491cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine if (csd->camera_count == 0) { 492cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine /* No cameras connected to the host. Reply with "\n" */ 493cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine _qemu_client_reply_ok(client, "\n"); 494cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine return 0; 495cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine } 496cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine 497cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine /* "Stringify" each camera information into the reply string. */ 498cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine for (n = 0; n < csd->camera_count; n++) { 499cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine const int res = 500cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine _camera_info_to_string(csd->camera_info + n, &reply, &reply_size); 501cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine if (res) { 502cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine if (reply != NULL) { 503cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine free(reply); 504cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine } 505cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine _qemu_client_reply_ko(client, "Memory allocation error"); 506cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine return res; 507cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine } 508cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine } 509cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine 510cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine D("%s Replied: %s", __FUNCTION__, reply); 511cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine _qemu_client_reply_ok(client, reply); 512cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine free(reply); 513cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine 514cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine return 0; 515cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine} 516cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine 517c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine/* Handles a message received from the emulated camera factory client. 518cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * Queries received here are represented as strings: 519cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * 'list' - Queries list of cameras connected to the host. 520cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * Param: 521cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * opaque - Camera service descriptor. 522cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * msg, msglen - Message received from the camera factory client. 523cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * client - Camera factory client pipe. 524c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine */ 525c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkinestatic void 526c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine_factory_client_recv(void* opaque, 527c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine uint8_t* msg, 528c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine int msglen, 529c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine QemudClient* client) 530c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine{ 531cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine /* 532cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * Emulated camera factory client queries. 533cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine */ 534cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine 535cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine /* List cameras connected to the host. */ 536cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine static const char _query_list[] = "list"; 537cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine 538cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine CameraServiceDesc* csd = (CameraServiceDesc*)opaque; 539cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine char query_name[64]; 540cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine const char* query_param = NULL; 541cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine 542cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine /* Parse the query, extracting query name and parameters. */ 543cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine if (_parse_query((const char*)msg, query_name, sizeof(query_name), 544cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine &query_param)) { 545cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine E("%s: Invalid format in query '%s'", __FUNCTION__, (const char*)msg); 546cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine _qemu_client_reply_ko(client, "Invalid query format"); 547cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine return; 548cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine } 549cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine 550cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine D("%s Camera factory query '%s'", __FUNCTION__, query_name); 551cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine 552cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine /* Dispatch the query to an appropriate handler. */ 553cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine if (!strcmp(query_name, _query_list)) { 554cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine /* This is a "list" query. */ 555cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine _factory_client_list_cameras(csd, client); 556cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine } else { 557cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine E("%s: Unknown camera factory query name in '%s'", 558cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine __FUNCTION__, (const char*)msg); 559cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine _qemu_client_reply_ko(client, "Unknown query name"); 560cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine } 561c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine} 562c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine 563cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine/* Emulated camera factory client has been disconnected from the service. */ 564c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkinestatic void 565c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine_factory_client_close(void* opaque) 566c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine{ 567cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine /* There is nothing to clean up here: factory service is just an alias for 568cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * the "root" camera service, that doesn't require anything more, than camera 569cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * dervice descriptor already provides. */ 570c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine} 571c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine 572c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine/******************************************************************************** 573c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine * Camera client API 574c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine *******************************************************************************/ 575c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine 576c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine/* Describes an emulated camera client. 577c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine */ 578c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkinetypedef struct CameraClient CameraClient; 579c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkinestruct CameraClient 580c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine{ 581c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine /* Client name. 582c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine * On Linux this is the name of the camera device. 583c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine * On Windows this is the name of capturing window. 584c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine */ 585cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine char* device_name; 586c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine /* Input channel to use to connect to the camera. */ 587cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine int inp_channel; 588cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine /* Camera information. */ 589cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine const CameraInfo* camera_info; 590cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine /* Emulated camera device descriptor. */ 591cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine CameraDevice* camera; 592cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine /* Buffer allocated for video frames. 593cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * Note that memory allocated for this buffer 594cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * also contains preview framebuffer. */ 595cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine uint8_t* video_frame; 596cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine /* Preview frame buffer. 597cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * This address points inside the 'video_frame' buffer. */ 598cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine uint16_t* preview_frame; 599cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine /* Byte size of the videoframe buffer. */ 600cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine size_t video_frame_size; 601cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine /* Byte size of the preview frame buffer. */ 602cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine size_t preview_frame_size; 603cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine /* Pixel format required by the guest. */ 604cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine uint32_t pixel_format; 605cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine /* Frame width. */ 606cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine int width; 607cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine /* Frame height. */ 608cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine int height; 609cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine /* Number of pixels in a frame buffer. */ 610cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine int pixel_num; 611cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine /* Status of video and preview frame cache. */ 612cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine int frames_cached; 613c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine}; 614c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine 615cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine/* Frees emulated camera client descriptor. */ 616c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkinestatic void 617c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine_camera_client_free(CameraClient* cc) 618c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine{ 619cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine /* The only exception to the "read only" rule: we have to mark the camera 620cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * as being not used when we destroy a service for it. */ 621cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine if (cc->camera_info != NULL) { 622cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine ((CameraInfo*)cc->camera_info)->in_use = 0; 623cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine } 624cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine if (cc->camera != NULL) { 625cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine camera_device_close(cc->camera); 626cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine } 627cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine if (cc->video_frame != NULL) { 628cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine free(cc->video_frame); 629c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine } 630cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine if (cc->device_name != NULL) { 631cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine free(cc->device_name); 632c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine } 633c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine 634c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine AFREE(cc); 635c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine} 636c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine 637cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine/* Creates descriptor for a connecting emulated camera client. 638c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine * Param: 639cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * csd - Camera service descriptor. 640cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * param - Client parameters. Must be formatted as described in comments to 6412ae501556f90647e40466b6a1948f6f7f51cf251Vladimir Chtchetkine * get_token_value routine, and must contain at least 'name' parameter, 642cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * identifiying the camera device to create the service for. Also parameters 643cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * may contain a decimal 'inp_channel' parameter, selecting the input 644cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * channel to use when communicating with the camera device. 645c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine * Return: 646cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * Emulated camera client descriptor on success, or NULL on failure. 647c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine */ 648cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkinestatic CameraClient* 649cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine_camera_client_create(CameraServiceDesc* csd, const char* param) 650cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine{ 651cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine CameraClient* cc; 652cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine CameraInfo* ci; 653cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine int res; 654cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine ANEW0(cc); 655cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine 656cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine /* 657cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * Parse parameter string, containing camera client properties. 658cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine */ 659cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine 660cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine /* Pull required device name. */ 6612ae501556f90647e40466b6a1948f6f7f51cf251Vladimir Chtchetkine if (get_token_value_alloc(param, "name", &cc->device_name)) { 662cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine E("%s: Allocation failure, or required 'name' parameter is missing, or misformed in '%s'", 663cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine __FUNCTION__, param); 664cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine return NULL; 665cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine } 666cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine 667cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine /* Pull optional input channel. */ 6682ae501556f90647e40466b6a1948f6f7f51cf251Vladimir Chtchetkine res = get_token_value_int(param, "inp_channel", &cc->inp_channel); 669cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine if (res != 0) { 670cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine if (res == -1) { 671cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine /* 'inp_channel' parameter has been ommited. Use default input 672cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * channel, which is zero. */ 673cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine cc->inp_channel = 0; 674cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine } else { 675cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine E("%s: 'inp_channel' parameter is misformed in '%s'", 676cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine __FUNCTION__, param); 677cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine return NULL; 678cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine } 679cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine } 680cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine 681cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine /* Get camera info for the emulated camera represented with this service. 682cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * Array of camera information records has been created when the camera 683cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * service was enumerating camera devices during the service initialization. 684cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * By the camera service protocol, camera service clients must first obtain 685cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * list of enumerated cameras via the 'list' query to the camera service, and 686cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * then use device name reported in the list to connect to an emulated camera 687cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * service. So, if camera information for the given device name is not found 688cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * in the array, we fail this connection due to protocol violation. */ 689b8dcaffaf7dcb0c795d2776abf3bb75196f8527cVladimir Chtchetkine ci = _camera_service_get_camera_info_by_device_name(csd, cc->device_name); 690cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine if (ci == NULL) { 691cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine E("%s: Cannot find camera info for device '%s'", 692cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine __FUNCTION__, cc->device_name); 693cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine _camera_client_free(cc); 694cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine return NULL; 695cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine } 696cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine 697cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine /* We can't allow multiple camera services for a single camera device, Lets 698cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * make sure that there is no client created for this camera. */ 699cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine if (ci->in_use) { 700cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine E("%s: Camera device '%s' is in use", __FUNCTION__, cc->device_name); 701cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine _camera_client_free(cc); 702cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine return NULL; 703cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine } 704cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine 705cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine /* We're done. Set camera in use, and succeed the connection. */ 706cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine ci->in_use = 1; 707cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine cc->camera_info = ci; 708cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine 709cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine D("%s: Camera service is created for device '%s' using input channel %d", 710cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine __FUNCTION__, cc->device_name, cc->inp_channel); 711cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine 712cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine return cc; 713cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine} 714cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine 715cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine/******************************************************************************** 716cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * Camera client queries 717cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine *******************************************************************************/ 718cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine 719cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine/* Client has queried conection to the camera. 720cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * Param: 721cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * cc - Queried camera client descriptor. 722cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * qc - Qemu client for the emulated camera. 723cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * param - Query parameters. There are no parameters expected for this query. 724cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine */ 725cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkinestatic void 726cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine_camera_client_query_connect(CameraClient* cc, QemudClient* qc, const char* param) 727cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine{ 728cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine if (cc->camera != NULL) { 729cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine /* Already connected. */ 730cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine W("%s: Camera '%s' is already connected", __FUNCTION__, cc->device_name); 731cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine _qemu_client_reply_ok(qc, "Camera is already connected"); 732cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine return; 733cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine } 734cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine 735cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine /* Open camera device. */ 736cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine cc->camera = camera_device_open(cc->device_name, cc->inp_channel); 737cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine if (cc->camera == NULL) { 738cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine E("%s: Unable to open camera device '%s'", __FUNCTION__, cc->device_name); 739cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine _qemu_client_reply_ko(qc, "Unable to open camera device."); 740cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine return; 741cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine } 742cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine 743cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine D("%s: Camera device '%s' is now connected", __FUNCTION__, cc->device_name); 744cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine 745cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine _qemu_client_reply_ok(qc, NULL); 746cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine} 747cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine 748cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine/* Client has queried disconection from the camera. 749cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * Param: 750cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * cc - Queried camera client descriptor. 751cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * qc - Qemu client for the emulated camera. 752cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * param - Query parameters. There are no parameters expected for this query. 753cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine */ 754cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkinestatic void 755cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine_camera_client_query_disconnect(CameraClient* cc, 756cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine QemudClient* qc, 757cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine const char* param) 758c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine{ 759cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine if (cc->camera == NULL) { 760cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine /* Already disconnected. */ 761cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine W("%s: Camera '%s' is already disconnected", __FUNCTION__, cc->device_name); 762cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine _qemu_client_reply_ok(qc, "Camera is not connected"); 763cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine return; 764cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine } 765cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine 766cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine /* Before we can go ahead and disconnect, we must make sure that camera is 767cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * not capturing frames. */ 768cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine if (cc->video_frame != NULL) { 769cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine E("%s: Cannot disconnect camera '%s' while it is not stopped", 770cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine __FUNCTION__, cc->device_name); 771cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine _qemu_client_reply_ko(qc, "Camera is not stopped"); 772cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine return; 773cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine } 774c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine 775cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine /* Close camera device. */ 776cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine camera_device_close(cc->camera); 777cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine cc->camera = NULL; 778cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine 779cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine D("Camera device '%s' is now disconnected", cc->device_name); 780cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine 781cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine _qemu_client_reply_ok(qc, NULL); 782cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine} 783cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine 784cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine/* Client has queried the client to start capturing video. 785cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * Param: 786cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * cc - Queried camera client descriptor. 787cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * qc - Qemu client for the emulated camera. 788cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * param - Query parameters. Parameters for this query must contain a 'dim', and 789cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * a 'pix' parameters, where 'dim' must be "dim=<width>x<height>", and 'pix' 790cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * must be "pix=<format>", where 'width' and 'height' must be numerical 791cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * values for the capturing video frame width, and height, and 'format' must 792cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * be a numerical value for the pixel format of the video frames expected by 793cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * the client. 'format' must be one of the V4L2_PIX_FMT_XXX values. 794cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine */ 795cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkinestatic void 796cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine_camera_client_query_start(CameraClient* cc, QemudClient* qc, const char* param) 797cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine{ 798cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine char* w; 799cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine char dim[64]; 800cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine int width, height, pix_format; 801c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine 802c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine /* Sanity check. */ 803cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine if (cc->camera == NULL) { 804cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine /* Not connected. */ 805cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine E("%s: Camera '%s' is not connected", __FUNCTION__, cc->device_name); 806cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine _qemu_client_reply_ko(qc, "Camera is not connected"); 807cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine return; 808c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine } 809c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine 810cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine /* 811cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * Parse parameters. 812cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine */ 813cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine 814cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine if (param == NULL) { 815cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine E("%s: Missing parameters for the query", __FUNCTION__); 816cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine _qemu_client_reply_ko(qc, "Missing parameters for the query"); 817cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine return; 818c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine } 819c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine 820cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine /* Pull required 'dim' parameter. */ 8212ae501556f90647e40466b6a1948f6f7f51cf251Vladimir Chtchetkine if (get_token_value(param, "dim", dim, sizeof(dim))) { 822cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine E("%s: Invalid or missing 'dim' parameter in '%s'", __FUNCTION__, param); 823cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine _qemu_client_reply_ko(qc, "Invalid or missing 'dim' parameter"); 824cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine return; 825c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine } 826c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine 827cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine /* Pull required 'pix' parameter. */ 8282ae501556f90647e40466b6a1948f6f7f51cf251Vladimir Chtchetkine if (get_token_value_int(param, "pix", &pix_format)) { 829cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine E("%s: Invalid or missing 'pix' parameter in '%s'", __FUNCTION__, param); 830cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine _qemu_client_reply_ko(qc, "Invalid or missing 'pix' parameter"); 831cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine return; 832c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine } 833cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine 834cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine /* Parse 'dim' parameter, and get requested frame width and height. */ 835cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine w = strchr(dim, 'x'); 836cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine if (w == NULL || w[1] == '\0') { 837cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine E("%s: Invalid 'dim' parameter in '%s'", __FUNCTION__, param); 838cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine _qemu_client_reply_ko(qc, "Invalid 'dim' parameter"); 839cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine return; 840c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine } 841cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine *w = '\0'; w++; 842cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine errno = 0; 843cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine width = strtoi(dim, NULL, 10); 844cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine height = strtoi(w, NULL, 10); 845cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine if (errno) { 846cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine E("%s: Invalid 'dim' parameter in '%s'", __FUNCTION__, param); 847cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine _qemu_client_reply_ko(qc, "Invalid 'dim' parameter"); 848cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine return; 849c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine } 850cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine 851cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine /* After collecting capture parameters lets see if camera has already 852cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * started, and if so, lets see if parameters match. */ 853cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine if (cc->video_frame != NULL) { 854cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine /* Already started. Match capture parameters. */ 855cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine if (cc->pixel_format != pix_format ||cc->width != width || 856cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine cc->height != height) { 857cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine /* Parameters match. Succeed the query. */ 858cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine W("%s: Camera '%s' is already started", __FUNCTION__, cc->device_name); 859cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine _qemu_client_reply_ok(qc, "Camera is already started"); 860cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine } else { 861cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine /* Parameters don't match. Fail the query. */ 862cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine E("%s: Camera '%s' is already started, and parameters don't match:\n" 863cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine "Current %.4s[%dx%d] != requested %.4s[%dx%d]", 864cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine __FUNCTION__, cc->device_name, (const char*)&cc->pixel_format, 865cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine cc->width, cc->height, (const char*)&pix_format, width, height); 866cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine _qemu_client_reply_ko(qc, 867cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine "Camera is already started with different capturing parameters"); 868cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine } 869cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine return; 870c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine } 871c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine 872cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine /* 873cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * Start the camera. 874cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine */ 875cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine 876cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine /* Save capturing parameters. */ 877cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine cc->pixel_format = pix_format; 878cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine cc->width = width; 879cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine cc->height = height; 880cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine cc->pixel_num = cc->width * cc->height; 881cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine cc->frames_cached = 0; 882cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine 883cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine /* Make sure that pixel format is known, and calculate video framebuffer size 884cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * along the lines. */ 885cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine switch (cc->pixel_format) { 886ddd59b14583126d6282d2fab3142171934981e85Vladimir Chtchetkine case V4L2_PIX_FMT_YUV420: 887cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine case V4L2_PIX_FMT_YVU420: 888916106df33bcbceceb81b582a331915f487ea21eVladimir Chtchetkine case V4L2_PIX_FMT_NV12: 889916106df33bcbceceb81b582a331915f487ea21eVladimir Chtchetkine case V4L2_PIX_FMT_NV21: 890cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine cc->video_frame_size = (cc->pixel_num * 12) / 8; 891cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine break; 892cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine 893cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine default: 894cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine E("%s: Unknown pixel format %.4s", 895cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine __FUNCTION__, (char*)&cc->pixel_format); 896cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine _qemu_client_reply_ko(qc, "Pixel format is unknown"); 897cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine return; 898c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine } 899c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine 900cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine /* Make sure that we have a converters between the original camera pixel 901cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * format and the one that the client expects. Also a converter must exist 902cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * for the preview window pixel format (RGB32) */ 903cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine if (!has_converter(cc->camera_info->pixel_format, cc->pixel_format) || 904cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine !has_converter(cc->camera_info->pixel_format, V4L2_PIX_FMT_RGB32)) { 905cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine E("%s: No conversion exist between %.4s and %.4s (or RGB32) pixel formats", 906cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine __FUNCTION__, (char*)&cc->camera_info->pixel_format, (char*)&cc->pixel_format); 907cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine _qemu_client_reply_ko(qc, "No conversion exist for the requested pixel format"); 908cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine return; 909cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine } 910cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine 911cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine /* TODO: At the moment camera framework in the emulator requires RGB32 pixel 912cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * format for preview window. So, we need to keep two framebuffers here: one 913cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * for the video, and another for the preview window. Watch out when this 914cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * changes (if changes). */ 915cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine cc->preview_frame_size = cc->pixel_num * 4; 916cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine 917cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine /* Allocate buffer large enough to contain both, video and preview 918cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * framebuffers. */ 919cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine cc->video_frame = 920cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine (uint8_t*)malloc(cc->video_frame_size + cc->preview_frame_size); 921cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine if (cc->video_frame == NULL) { 922cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine E("%s: Not enough memory for framebuffers %d + %d", 923cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine __FUNCTION__, cc->video_frame_size, cc->preview_frame_size); 924cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine _qemu_client_reply_ko(qc, "Out of memory"); 925cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine return; 926cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine } 927cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine 928cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine /* Set framebuffer pointers. */ 929cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine cc->preview_frame = (uint16_t*)(cc->video_frame + cc->video_frame_size); 930cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine 931cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine /* Start the camera. */ 932cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine if (camera_device_start_capturing(cc->camera, cc->camera_info->pixel_format, 933cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine cc->width, cc->height)) { 934cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine E("%s: Cannot start camera '%s' for %.4s[%dx%d]: %s", 935cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine __FUNCTION__, cc->device_name, (const char*)&cc->pixel_format, 936cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine cc->width, cc->height, strerror(errno)); 937cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine free(cc->video_frame); 938cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine cc->video_frame = NULL; 939cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine _qemu_client_reply_ko(qc, "Cannot start the camera"); 940cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine return; 941cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine } 942cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine 943cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine D("%s: Camera '%s' is now started for %.4s[%dx%d]", 944cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine __FUNCTION__, cc->device_name, (char*)&cc->pixel_format, cc->width, 945cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine cc->height); 946cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine 947cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine _qemu_client_reply_ok(qc, NULL); 948c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine} 949c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine 950cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine/* Client has queried the client to stop capturing video. 951c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine * Param: 952cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * cc - Queried camera client descriptor. 953cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * qc - Qemu client for the emulated camera. 954cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * param - Query parameters. There are no parameters expected for this query. 955c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine */ 956cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkinestatic void 957cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine_camera_client_query_stop(CameraClient* cc, QemudClient* qc, const char* param) 958c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine{ 959cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine if (cc->video_frame == NULL) { 960cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine /* Not started. */ 961cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine W("%s: Camera '%s' is not started", __FUNCTION__, cc->device_name); 962cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine _qemu_client_reply_ok(qc, "Camera is not started"); 963cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine return; 964cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine } 965c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine 966cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine /* Stop the camera. */ 967cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine if (camera_device_stop_capturing(cc->camera)) { 968cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine E("%s: Cannot stop camera device '%s': %s", 969cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine __FUNCTION__, cc->device_name, strerror(errno)); 970cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine _qemu_client_reply_ko(qc, "Cannot stop camera device"); 971cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine return; 972cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine } 973c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine 974cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine free(cc->video_frame); 975cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine cc->video_frame = NULL; 976cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine 977cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine D("%s: Camera device '%s' is now stopped.", __FUNCTION__, cc->device_name); 978cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine _qemu_client_reply_ok(qc, NULL); 979cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine} 980cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine 981cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine/* Client has queried next frame. 982cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * Param: 983cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * cc - Queried camera client descriptor. 984cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * qc - Qemu client for the emulated camera. 98537fb84f8b26e3061c1ccb404bf4c962eed5e6057Vladimir Chtchetkine * param - Query parameters. Parameters for this query are formatted as such: 98637fb84f8b26e3061c1ccb404bf4c962eed5e6057Vladimir Chtchetkine * video=<size> preview=<size> whiteb=<red>,<green>,<blue> expcomp=<comp> 98737fb84f8b26e3061c1ccb404bf4c962eed5e6057Vladimir Chtchetkine * where: 98837fb84f8b26e3061c1ccb404bf4c962eed5e6057Vladimir Chtchetkine * - 'video', and 'preview' both must be decimal values, defining size of 98937fb84f8b26e3061c1ccb404bf4c962eed5e6057Vladimir Chtchetkine * requested video, and preview frames respectively. Zero value for any 99037fb84f8b26e3061c1ccb404bf4c962eed5e6057Vladimir Chtchetkine * of these parameters means that this particular frame is not requested. 99137fb84f8b26e3061c1ccb404bf4c962eed5e6057Vladimir Chtchetkine * - whiteb contains float values required to calculate whilte balance. 99237fb84f8b26e3061c1ccb404bf4c962eed5e6057Vladimir Chtchetkine * - expcomp contains a float value required to calculate exposure 99337fb84f8b26e3061c1ccb404bf4c962eed5e6057Vladimir Chtchetkine * compensation. 994cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine */ 995cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkinestatic void 996cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine_camera_client_query_frame(CameraClient* cc, QemudClient* qc, const char* param) 997cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine{ 998cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine int video_size = 0; 999cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine int preview_size = 0; 1000cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine int repeat; 1001cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine ClientFrameBuffer fbs[2]; 1002cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine int fbs_num = 0; 1003cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine size_t payload_size; 1004c68dbbef0118eab4256acfc0d9430f0e557a82a1Vladimir Chtchetkine uint64_t tick; 100537fb84f8b26e3061c1ccb404bf4c962eed5e6057Vladimir Chtchetkine float r_scale = 1.0f, g_scale = 1.0f, b_scale = 1.0f, exp_comp = 1.0f; 100637fb84f8b26e3061c1ccb404bf4c962eed5e6057Vladimir Chtchetkine char tmp[256]; 1007cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine 1008cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine /* Sanity check. */ 1009cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine if (cc->video_frame == NULL) { 1010cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine /* Not started. */ 1011cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine E("%s: Camera '%s' is not started", __FUNCTION__, cc->device_name); 1012cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine _qemu_client_reply_ko(qc, "Camera is not started"); 1013cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine return; 1014c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine } 1015c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine 1016cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine /* Pull required parameters. */ 10172ae501556f90647e40466b6a1948f6f7f51cf251Vladimir Chtchetkine if (get_token_value_int(param, "video", &video_size) || 10182ae501556f90647e40466b6a1948f6f7f51cf251Vladimir Chtchetkine get_token_value_int(param, "preview", &preview_size)) { 1019cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine E("%s: Invalid or missing 'video', or 'preview' parameter in '%s'", 1020cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine __FUNCTION__, param); 1021cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine _qemu_client_reply_ko(qc, 1022cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine "Invalid or missing 'video', or 'preview' parameter"); 1023cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine return; 1024cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine } 1025cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine 102637fb84f8b26e3061c1ccb404bf4c962eed5e6057Vladimir Chtchetkine /* Pull white balance values. */ 10272ae501556f90647e40466b6a1948f6f7f51cf251Vladimir Chtchetkine if (!get_token_value(param, "whiteb", tmp, sizeof(tmp))) { 102837fb84f8b26e3061c1ccb404bf4c962eed5e6057Vladimir Chtchetkine if (sscanf(tmp, "%g,%g,%g", &r_scale, &g_scale, &b_scale) != 3) { 102937fb84f8b26e3061c1ccb404bf4c962eed5e6057Vladimir Chtchetkine D("Invalid value '%s' for parameter 'whiteb'", tmp); 103037fb84f8b26e3061c1ccb404bf4c962eed5e6057Vladimir Chtchetkine r_scale = g_scale = b_scale = 1.0f; 103137fb84f8b26e3061c1ccb404bf4c962eed5e6057Vladimir Chtchetkine } 103237fb84f8b26e3061c1ccb404bf4c962eed5e6057Vladimir Chtchetkine } 103337fb84f8b26e3061c1ccb404bf4c962eed5e6057Vladimir Chtchetkine 103437fb84f8b26e3061c1ccb404bf4c962eed5e6057Vladimir Chtchetkine /* Pull exposure compensation. */ 10352ae501556f90647e40466b6a1948f6f7f51cf251Vladimir Chtchetkine if (!get_token_value(param, "expcomp", tmp, sizeof(tmp))) { 103637fb84f8b26e3061c1ccb404bf4c962eed5e6057Vladimir Chtchetkine if (sscanf(tmp, "%g", &exp_comp) != 1) { 103737fb84f8b26e3061c1ccb404bf4c962eed5e6057Vladimir Chtchetkine D("Invalid value '%s' for parameter 'whiteb'", tmp); 103837fb84f8b26e3061c1ccb404bf4c962eed5e6057Vladimir Chtchetkine exp_comp = 1.0f; 103937fb84f8b26e3061c1ccb404bf4c962eed5e6057Vladimir Chtchetkine } 104037fb84f8b26e3061c1ccb404bf4c962eed5e6057Vladimir Chtchetkine } 104137fb84f8b26e3061c1ccb404bf4c962eed5e6057Vladimir Chtchetkine 1042cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine /* Verify that framebuffer sizes match the ones that the started camera 1043cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * operates with. */ 1044cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine if ((video_size != 0 && cc->video_frame_size != video_size) || 1045cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine (preview_size != 0 && cc->preview_frame_size != preview_size)) { 1046cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine E("%s: Frame sizes don't match for camera '%s':\n" 1047cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine "Expected %d for video, and %d for preview. Requested %d, and %d", 1048cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine __FUNCTION__, cc->device_name, cc->video_frame_size, 1049cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine cc->preview_frame_size, video_size, preview_size); 1050cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine _qemu_client_reply_ko(qc, "Frame size mismatch"); 1051cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine return; 1052cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine } 1053cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine 1054cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine /* 1055cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * Initialize framebuffer array for frame read. 1056cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine */ 1057cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine 1058cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine if (video_size) { 1059cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine fbs[fbs_num].pixel_format = cc->pixel_format; 1060cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine fbs[fbs_num].framebuffer = cc->video_frame; 1061cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine fbs_num++; 1062cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine } 1063cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine if (preview_size) { 1064cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine /* TODO: Watch out for preview format changes! */ 1065cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine fbs[fbs_num].pixel_format = V4L2_PIX_FMT_RGB32; 1066cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine fbs[fbs_num].framebuffer = cc->preview_frame; 1067cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine fbs_num++; 1068cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine } 1069cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine 1070cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine /* Capture new frame. */ 1071c68dbbef0118eab4256acfc0d9430f0e557a82a1Vladimir Chtchetkine tick = _get_timestamp(); 107237fb84f8b26e3061c1ccb404bf4c962eed5e6057Vladimir Chtchetkine repeat = camera_device_read_frame(cc->camera, fbs, fbs_num, 107337fb84f8b26e3061c1ccb404bf4c962eed5e6057Vladimir Chtchetkine r_scale, g_scale, b_scale, exp_comp); 1074cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine 1075cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine /* Note that there is no (known) way how to wait on next frame being 1076c68dbbef0118eab4256acfc0d9430f0e557a82a1Vladimir Chtchetkine * available, so we could dequeue frame buffer from the device only when we 1077c68dbbef0118eab4256acfc0d9430f0e557a82a1Vladimir Chtchetkine * know it's available. Instead we're shooting in the dark, and quite often 1078cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * device will response with EAGAIN, indicating that it doesn't have frame 1079cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * ready. In turn, it means that the last frame we have obtained from the 1080cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * device is still good, and we can reply with the cached frames. The only 1081cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * case when we need to keep trying to obtain a new frame is when frame cache 1082c68dbbef0118eab4256acfc0d9430f0e557a82a1Vladimir Chtchetkine * is empty. To prevent ourselves from an indefinite loop in case device got 1083c68dbbef0118eab4256acfc0d9430f0e557a82a1Vladimir Chtchetkine * stuck on something (observed with some Microsoft devices) we will limit 1084c68dbbef0118eab4256acfc0d9430f0e557a82a1Vladimir Chtchetkine * the loop by 2 second time period (which is more than enough to obtain 1085c68dbbef0118eab4256acfc0d9430f0e557a82a1Vladimir Chtchetkine * something from the device) */ 1086c68dbbef0118eab4256acfc0d9430f0e557a82a1Vladimir Chtchetkine while (repeat == 1 && !cc->frames_cached && 1087c68dbbef0118eab4256acfc0d9430f0e557a82a1Vladimir Chtchetkine (_get_timestamp() - tick) < 2000000LL) { 1088c68dbbef0118eab4256acfc0d9430f0e557a82a1Vladimir Chtchetkine /* Sleep for 10 millisec before repeating the attempt. */ 10893d3fea0627b4dfb6119ee8173a40640ea8a401f2Vladimir Chtchetkine _camera_sleep(10); 109037fb84f8b26e3061c1ccb404bf4c962eed5e6057Vladimir Chtchetkine repeat = camera_device_read_frame(cc->camera, fbs, fbs_num, 109137fb84f8b26e3061c1ccb404bf4c962eed5e6057Vladimir Chtchetkine r_scale, g_scale, b_scale, exp_comp); 1092cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine } 1093c68dbbef0118eab4256acfc0d9430f0e557a82a1Vladimir Chtchetkine if (repeat == 1 && !cc->frames_cached) { 1094c68dbbef0118eab4256acfc0d9430f0e557a82a1Vladimir Chtchetkine /* Waited too long for the first frame. */ 1095c68dbbef0118eab4256acfc0d9430f0e557a82a1Vladimir Chtchetkine E("%s: Unable to obtain first video frame from the camera '%s' in %d milliseconds: %s.", 1096c68dbbef0118eab4256acfc0d9430f0e557a82a1Vladimir Chtchetkine __FUNCTION__, cc->device_name, 1097c68dbbef0118eab4256acfc0d9430f0e557a82a1Vladimir Chtchetkine (uint32_t)(_get_timestamp() - tick) / 1000, strerror(errno)); 1098cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine _qemu_client_reply_ko(qc, "Unable to obtain video frame from the camera"); 1099cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine return; 1100c68dbbef0118eab4256acfc0d9430f0e557a82a1Vladimir Chtchetkine } else if (repeat < 0) { 1101c68dbbef0118eab4256acfc0d9430f0e557a82a1Vladimir Chtchetkine /* An I/O error. */ 1102c68dbbef0118eab4256acfc0d9430f0e557a82a1Vladimir Chtchetkine E("%s: Unable to obtain video frame from the camera '%s': %s.", 1103c68dbbef0118eab4256acfc0d9430f0e557a82a1Vladimir Chtchetkine __FUNCTION__, cc->device_name, strerror(errno)); 1104c68dbbef0118eab4256acfc0d9430f0e557a82a1Vladimir Chtchetkine _qemu_client_reply_ko(qc, strerror(errno)); 1105c68dbbef0118eab4256acfc0d9430f0e557a82a1Vladimir Chtchetkine return; 1106cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine } 1107c68dbbef0118eab4256acfc0d9430f0e557a82a1Vladimir Chtchetkine 1108cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine /* We have cached something... */ 1109cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine cc->frames_cached = 1; 1110cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine 1111cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine /* 1112cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * Build the reply. 1113cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine */ 1114cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine 1115cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine /* Payload includes "ok:" + requested video and preview frames. */ 1116cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine payload_size = 3 + video_size + preview_size; 1117cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine 1118cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine /* Send payload size first. */ 1119cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine _qemu_client_reply_payload(qc, payload_size); 1120cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine 1121cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine /* After that send the 'ok:'. Note that if there is no frames sent, we should 1122cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * use prefix "ok" instead of "ok:" */ 1123cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine if (video_size || preview_size) { 1124cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine qemud_client_send(qc, (const uint8_t*)"ok:", 3); 1125cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine } else { 1126cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine /* Still 3 bytes: zero terminator is required in this case. */ 1127cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine qemud_client_send(qc, (const uint8_t*)"ok", 3); 1128cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine } 1129cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine 1130cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine /* After that send video frame (if requested). */ 1131cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine if (video_size) { 1132cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine qemud_client_send(qc, cc->video_frame, video_size); 1133cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine } 1134cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine 1135cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine /* After that send preview frame (if requested). */ 1136cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine if (preview_size) { 1137cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine qemud_client_send(qc, (const uint8_t*)cc->preview_frame, preview_size); 1138cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine } 1139c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine} 1140c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine 1141c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine/* Handles a message received from the emulated camera client. 1142cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * Queries received here are represented as strings: 1143cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * - 'connect' - Connects to the camera device (opens it). 1144cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * - 'disconnect' - Disconnexts from the camera device (closes it). 1145cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * - 'start' - Starts capturing video from the connected camera device. 1146cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * - 'stop' - Stop capturing video from the connected camera device. 1147cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * - 'frame' - Queries video and preview frames captured from the camera. 1148cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * Param: 1149cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * opaque - Camera service descriptor. 1150cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * msg, msglen - Message received from the camera factory client. 1151cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * client - Camera factory client pipe. 1152c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine */ 1153c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkinestatic void 1154c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine_camera_client_recv(void* opaque, 1155c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine uint8_t* msg, 1156c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine int msglen, 1157c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine QemudClient* client) 1158c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine{ 1159cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine /* 1160cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * Emulated camera client queries. 1161cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine */ 1162cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine 1163cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine /* Connect to the camera. */ 1164cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine static const char _query_connect[] = "connect"; 1165cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine /* Disconnect from the camera. */ 1166cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine static const char _query_disconnect[] = "disconnect"; 1167cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine /* Start video capturing. */ 1168cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine static const char _query_start[] = "start"; 1169cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine /* Stop video capturing. */ 1170cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine static const char _query_stop[] = "stop"; 1171cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine /* Query frame(s). */ 1172cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine static const char _query_frame[] = "frame"; 1173cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine 1174cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine char query_name[64]; 1175c7389bd69e570a2c8432b37399aff1976b021f0fAndrew Hsieh const char* query_param = NULL; 1176c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine CameraClient* cc = (CameraClient*)opaque; 1177c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine 1178cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine /* 1179cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * Emulated camera queries are formatted as such: 1180cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * "<query name> [<parameters>]" 1181cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine */ 1182cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine 1183cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine T("%s: Camera client query: '%s'", __FUNCTION__, (char*)msg); 1184cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine if (_parse_query((const char*)msg, query_name, sizeof(query_name), 1185cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine &query_param)) { 1186cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine E("%s: Invalid query '%s'", __FUNCTION__, (char*)msg); 1187cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine _qemu_client_reply_ko(client, "Invalid query"); 1188cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine return; 1189cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine } 1190cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine 1191cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine /* Dispatch the query to an appropriate handler. */ 1192cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine if (!strcmp(query_name, _query_frame)) { 1193cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine /* A frame is queried. */ 1194cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine _camera_client_query_frame(cc, client, query_param); 1195cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine } else if (!strcmp(query_name, _query_connect)) { 1196cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine /* Camera connection is queried. */ 1197cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine _camera_client_query_connect(cc, client, query_param); 1198cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine } else if (!strcmp(query_name, _query_disconnect)) { 1199cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine /* Camera disnection is queried. */ 1200cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine _camera_client_query_disconnect(cc, client, query_param); 1201cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine } else if (!strcmp(query_name, _query_start)) { 1202cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine /* Start capturing is queried. */ 1203cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine _camera_client_query_start(cc, client, query_param); 1204cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine } else if (!strcmp(query_name, _query_stop)) { 1205cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine /* Stop capturing is queried. */ 1206cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine _camera_client_query_stop(cc, client, query_param); 1207cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine } else { 1208cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine E("%s: Unknown query '%s'", __FUNCTION__, (char*)msg); 1209cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine _qemu_client_reply_ko(client, "Unknown query"); 1210cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine } 1211c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine} 1212c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine 1213cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine/* Emulated camera client has been disconnected from the service. */ 1214c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkinestatic void 1215cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine_camera_client_close(void* opaque) 1216c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine{ 1217c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine CameraClient* cc = (CameraClient*)opaque; 1218c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine 1219cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine D("%s: Camera client for device '%s' on input channel %d is now closed", 1220cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine __FUNCTION__, cc->device_name, cc->inp_channel); 1221c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine 1222c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine _camera_client_free(cc); 1223c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine} 1224c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine 1225c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine/******************************************************************************** 1226c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine * Camera service API 1227c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine *******************************************************************************/ 1228c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine 1229c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine/* Connects a client to the camera service. 1230c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine * There are two classes of the client that can connect to the service: 1231c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine * - Camera factory that is insterested only in listing camera devices attached 1232c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine * to the host. 1233c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine * - Camera device emulators that attach to the actual camera devices. 1234c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine * The distinction between these two classes is made by looking at extra 1235c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine * parameters passed in client_param variable. If it's NULL, or empty, the client 1236c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine * connects to a camera factory. Otherwise, parameters describe the camera device 1237c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine * the client wants to connect to. 1238c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine */ 1239c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkinestatic QemudClient* 1240c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine_camera_service_connect(void* opaque, 1241c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine QemudService* serv, 1242c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine int channel, 1243c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine const char* client_param) 1244c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine{ 1245c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine QemudClient* client = NULL; 1246c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine CameraServiceDesc* csd = (CameraServiceDesc*)opaque; 1247c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine 1248cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine D("%s: Connecting camera client '%s'", 1249cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine __FUNCTION__, client_param ? client_param : "Factory"); 1250c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine if (client_param == NULL || *client_param == '\0') { 1251c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine /* This is an emulated camera factory client. */ 1252c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine client = qemud_client_new(serv, channel, client_param, csd, 1253c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine _factory_client_recv, _factory_client_close, 1254c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine NULL, NULL); 1255c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine } else { 1256c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine /* This is an emulated camera client. */ 1257c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine CameraClient* cc = _camera_client_create(csd, client_param); 1258c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine if (cc != NULL) { 1259c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine client = qemud_client_new(serv, channel, client_param, cc, 1260c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine _camera_client_recv, _camera_client_close, 1261c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine NULL, NULL); 1262c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine } 1263c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine } 1264c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine 1265c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine return client; 1266c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine} 1267c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine 1268c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkinevoid 1269c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkineandroid_camera_service_init(void) 1270c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine{ 1271c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine static int _inited = 0; 1272c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine 1273c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine if (!_inited) { 1274cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine _camera_service_init(&_camera_service_desc); 1275c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine QemudService* serv = qemud_service_register( SERVICE_NAME, 0, 1276c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine &_camera_service_desc, 1277c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine _camera_service_connect, 1278c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine NULL, NULL); 1279c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine if (serv == NULL) { 1280cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine derror("%s: Could not register '%s' service", 1281cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine __FUNCTION__, SERVICE_NAME); 1282c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine return; 1283c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine } 1284cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine D("%s: Registered '%s' qemud service", __FUNCTION__, SERVICE_NAME); 1285c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine } 1286c646f5e40ddda3d49b581ac0c78cf748b5dee74cVladimir Chtchetkine} 1287b8dcaffaf7dcb0c795d2776abf3bb75196f8527cVladimir Chtchetkine 1288b8dcaffaf7dcb0c795d2776abf3bb75196f8527cVladimir Chtchetkinevoid 1289b8dcaffaf7dcb0c795d2776abf3bb75196f8527cVladimir Chtchetkineandroid_list_web_cameras(void) 1290b8dcaffaf7dcb0c795d2776abf3bb75196f8527cVladimir Chtchetkine{ 1291b8dcaffaf7dcb0c795d2776abf3bb75196f8527cVladimir Chtchetkine CameraInfo ci[MAX_CAMERA]; 1292b8dcaffaf7dcb0c795d2776abf3bb75196f8527cVladimir Chtchetkine int connected_cnt; 1293b8dcaffaf7dcb0c795d2776abf3bb75196f8527cVladimir Chtchetkine int i; 1294b8dcaffaf7dcb0c795d2776abf3bb75196f8527cVladimir Chtchetkine 1295b8dcaffaf7dcb0c795d2776abf3bb75196f8527cVladimir Chtchetkine /* Enumerate camera devices connected to the host. */ 1296b8dcaffaf7dcb0c795d2776abf3bb75196f8527cVladimir Chtchetkine connected_cnt = enumerate_camera_devices(ci, MAX_CAMERA); 1297b8dcaffaf7dcb0c795d2776abf3bb75196f8527cVladimir Chtchetkine if (connected_cnt <= 0) { 1298b8dcaffaf7dcb0c795d2776abf3bb75196f8527cVladimir Chtchetkine return; 1299b8dcaffaf7dcb0c795d2776abf3bb75196f8527cVladimir Chtchetkine } 1300b8dcaffaf7dcb0c795d2776abf3bb75196f8527cVladimir Chtchetkine 1301b8dcaffaf7dcb0c795d2776abf3bb75196f8527cVladimir Chtchetkine printf("List of web cameras connected to the computer:\n"); 1302b8dcaffaf7dcb0c795d2776abf3bb75196f8527cVladimir Chtchetkine for (i = 0; i < connected_cnt; i++) { 1303b8dcaffaf7dcb0c795d2776abf3bb75196f8527cVladimir Chtchetkine printf(" Camera '%s' is connected to device '%s' on channel %d using pixel format '%.4s'\n", 1304b8dcaffaf7dcb0c795d2776abf3bb75196f8527cVladimir Chtchetkine ci[i].display_name, ci[i].device_name, ci[i].inp_channel, 1305b8dcaffaf7dcb0c795d2776abf3bb75196f8527cVladimir Chtchetkine (const char*)&ci[i].pixel_format); 1306b8dcaffaf7dcb0c795d2776abf3bb75196f8527cVladimir Chtchetkine } 1307b8dcaffaf7dcb0c795d2776abf3bb75196f8527cVladimir Chtchetkine printf("\n"); 1308b8dcaffaf7dcb0c795d2776abf3bb75196f8527cVladimir Chtchetkine} 1309