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